@@ -19,7 +19,7 @@ import {
1919} from '../shared/workflows/index.js' ;
2020import { StepIndexManager } from './indexing/index.js' ;
2121import { registry } from '../infra/engines/index.js' ;
22- import { MonitoringCleanup } from '../agents/monitoring/index.js' ;
22+ import { MonitoringCleanup , AgentMonitorService } from '../agents/monitoring/index.js' ;
2323import { WorkflowEventBus , WorkflowEventEmitter } from './events/index.js' ;
2424import { validateSpecification } from '../runtime/services/index.js' ;
2525import { WorkflowRunner } from './runner/index.js' ;
@@ -54,8 +54,33 @@ export async function runWorkflow(options: RunWorkflowOptions = {}): Promise<voi
5454 // Set up cleanup handlers
5555 MonitoringCleanup . setup ( ) ;
5656
57- // Load template
57+ // Load template (needed before we can set up the before-cleanup handler)
5858 const cmRoot = path . join ( cwd , '.codemachine' ) ;
59+ const indexManager = new StepIndexManager ( cmRoot ) ;
60+
61+ // Register callback to save session state before cleanup on Ctrl+C
62+ // This ensures session/monitoring IDs are persisted even if the first turn hasn't completed
63+ MonitoringCleanup . registerWorkflowHandlers ( {
64+ onBeforeCleanup : async ( ) => {
65+ const monitor = AgentMonitorService . getInstance ( ) ;
66+ const activeAgents = monitor . getActiveAgents ( ) ;
67+
68+ // Find root agents (no parentId) - these are the main step agents
69+ const rootAgents = activeAgents . filter ( ( agent ) => ! agent . parentId ) ;
70+
71+ for ( const agent of rootAgents ) {
72+ // Only save if agent has a sessionId (needed for resume)
73+ if ( agent . sessionId ) {
74+ const stepIndex = indexManager . currentStepIndex ;
75+ debug ( '[Workflow] Saving session state on Ctrl+C: step=%d, sessionId=%s, monitoringId=%d' ,
76+ stepIndex , agent . sessionId , agent . id ) ;
77+ await indexManager . stepSessionInitialized ( stepIndex , agent . sessionId , agent . id ) ;
78+ }
79+ }
80+ } ,
81+ } ) ;
82+
83+ // Load template
5984 const templatePath = options . templatePath || ( await getTemplatePathFromTracking ( cmRoot ) ) ;
6085 const { template } = await loadTemplateWithPath ( cwd , templatePath ) ;
6186
@@ -108,9 +133,6 @@ export async function runWorkflow(options: RunWorkflowOptions = {}): Promise<voi
108133 globalThis . __workflowEventBus = eventBus ;
109134 }
110135
111- // Create step index manager
112- const indexManager = new StepIndexManager ( cmRoot ) ;
113-
114136 // Get resume info
115137 const resumeInfo = await indexManager . getResumeInfo ( ) ;
116138 const startIndex = resumeInfo . startIndex ;
0 commit comments