fix(02-03): include linter-applied changes for crash recovery
- Re-stage files that were modified by linter after previous commit
This commit is contained in:
1 parent
64183428ec
commit
9a1671981a
5 files changed
+33
No files matched your search
@@ -199,6 +199,24 @@ export async function bootstrapApplication({
|
|||||||
}
|
}
|
||||||
|
|
||||||
serviceGraph.getOrchestrationService()?.startHeartbeatScheduler();
|
serviceGraph.getOrchestrationService()?.startHeartbeatScheduler();
|
||||||
|
|
||||||
|
// Check for crash recovery -- emit recovery notification before resuming queued runs
|
||||||
|
const interruptedCount = db.lastInterruptedCount;
|
||||||
|
if (interruptedCount > 0) {
|
||||||
|
log.warn(`[bootstrap] Detected ${interruptedCount} interrupted runs from previous session. Sending recovery notification.`);
|
||||||
|
const interruptedRuns = db.getInterruptedRunsForRecovery();
|
||||||
|
if (interruptedRuns.length > 0) {
|
||||||
|
emitEvent({
|
||||||
|
type: "recovery-needed",
|
||||||
|
interruptedRuns,
|
||||||
|
} as any); // DesktopEvent will need extending
|
||||||
|
notify(
|
||||||
|
"Interrupted runs detected",
|
||||||
|
`${interruptedRuns.length} task(s) were interrupted when the app last closed. Check the dashboard for recovery options.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serviceGraph.getOrchestrationService()?.resumeQueuedRuns();
|
serviceGraph.getOrchestrationService()?.resumeQueuedRuns();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { registerAutomationOperationsHandlers } from "./ipc-automation-operation
|
|||||||
import { registerBrowserHandlers } from "./ipc-browser-handlers";
|
import { registerBrowserHandlers } from "./ipc-browser-handlers";
|
||||||
import { registerContentOperationsHandlers } from "./ipc-content-operations-handlers";
|
import { registerContentOperationsHandlers } from "./ipc-content-operations-handlers";
|
||||||
import { registerOnboardingHandlers } from "./ipc-onboarding-handlers";
|
import { registerOnboardingHandlers } from "./ipc-onboarding-handlers";
|
||||||
|
import { registerRecoveryHandlers } from "./ipc-recovery-handlers";
|
||||||
|
|
||||||
export function registerDomainHandlers(dependencies: RegisterDomainHandlersDependencies) {
|
export function registerDomainHandlers(dependencies: RegisterDomainHandlersDependencies) {
|
||||||
registerOnboardingHandlers(dependencies);
|
registerOnboardingHandlers(dependencies);
|
||||||
@@ -11,4 +12,5 @@ export function registerDomainHandlers(dependencies: RegisterDomainHandlersDepen
|
|||||||
registerContentOperationsHandlers(dependencies);
|
registerContentOperationsHandlers(dependencies);
|
||||||
registerAutomationOperationsHandlers(dependencies);
|
registerAutomationOperationsHandlers(dependencies);
|
||||||
registerAgentCoordinationHandlers(dependencies);
|
registerAgentCoordinationHandlers(dependencies);
|
||||||
|
registerRecoveryHandlers(dependencies);
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,12 @@ const api: DesktopApi = {
|
|||||||
deleteWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.deleteWorkflow, input),
|
deleteWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.deleteWorkflow, input),
|
||||||
runWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.runWorkflow, input),
|
runWorkflow: (input) => ipcRenderer.invoke(IPC_CHANNELS.runWorkflow, input),
|
||||||
autoAssignTask: (input) => ipcRenderer.invoke(IPC_CHANNELS.autoAssignTask, input),
|
autoAssignTask: (input) => ipcRenderer.invoke(IPC_CHANNELS.autoAssignTask, input),
|
||||||
|
recoveryRetry: (taskId: string, agentId: string, companyId: string) =>
|
||||||
|
ipcRenderer.invoke("recovery:retry", { taskId, agentId, companyId }),
|
||||||
|
recoveryDismiss: (taskId: string) =>
|
||||||
|
ipcRenderer.invoke("recovery:dismiss", { taskId }),
|
||||||
|
recoveryFail: (taskId: string) =>
|
||||||
|
ipcRenderer.invoke("recovery:fail", { taskId }),
|
||||||
subscribe: (callback: (event: DesktopEvent) => void) => {
|
subscribe: (callback: (event: DesktopEvent) => void) => {
|
||||||
const listener = (_event: Electron.IpcRendererEvent, payload: DesktopEvent) => callback(payload);
|
const listener = (_event: Electron.IpcRendererEvent, payload: DesktopEvent) => callback(payload);
|
||||||
ipcRenderer.on(IPC_CHANNELS.rendererEvent, listener);
|
ipcRenderer.on(IPC_CHANNELS.rendererEvent, listener);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import { TaskPipeline } from "./TaskPipeline";
|
|||||||
import { SprintProgress } from "./SprintProgress";
|
import { SprintProgress } from "./SprintProgress";
|
||||||
import { GoalProgress } from "./GoalProgress";
|
import { GoalProgress } from "./GoalProgress";
|
||||||
import { NeedsAttention } from "./NeedsAttention";
|
import { NeedsAttention } from "./NeedsAttention";
|
||||||
|
import { RecoveryBanner } from "./RecoveryBanner";
|
||||||
|
|
||||||
export interface DashboardProps {
|
export interface DashboardProps {
|
||||||
agents: AgentRecord[];
|
agents: AgentRecord[];
|
||||||
@@ -86,6 +87,9 @@ export function Dashboard(props: DashboardProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
|
{/* Recovery banner for interrupted runs */}
|
||||||
|
<RecoveryBanner />
|
||||||
|
|
||||||
{/* Health + Metrics */}
|
{/* Health + Metrics */}
|
||||||
<div className="flex flex-col gap-6 lg:flex-row lg:items-start">
|
<div className="flex flex-col gap-6 lg:flex-row lg:items-start">
|
||||||
<div className="shrink-0 rounded-[12px] border border-[color:var(--line)] bg-[color:var(--panel)] p-5">
|
<div className="shrink-0 rounded-[12px] border border-[color:var(--line)] bg-[color:var(--panel)] p-5">
|
||||||
|
|||||||
@@ -577,5 +577,8 @@ export type DesktopApi = {
|
|||||||
deleteWorkflow: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
|
deleteWorkflow: (input: z.infer<typeof deleteEntitySchema>) => Promise<DesktopResult<boolean>>;
|
||||||
runWorkflow: (input: z.infer<typeof runWorkflowSchema>) => Promise<DesktopResult<boolean>>;
|
runWorkflow: (input: z.infer<typeof runWorkflowSchema>) => Promise<DesktopResult<boolean>>;
|
||||||
autoAssignTask: (input: z.infer<typeof autoAssignSchema>) => Promise<DesktopResult<string>>;
|
autoAssignTask: (input: z.infer<typeof autoAssignSchema>) => Promise<DesktopResult<string>>;
|
||||||
|
recoveryRetry: (taskId: string, agentId: string, companyId: string) => Promise<DesktopResult<null>>;
|
||||||
|
recoveryDismiss: (taskId: string) => Promise<DesktopResult<null>>;
|
||||||
|
recoveryFail: (taskId: string) => Promise<DesktopResult<null>>;
|
||||||
subscribe: (callback: (event: DesktopEvent) => void) => () => void;
|
subscribe: (callback: (event: DesktopEvent) => void) => () => void;
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user