Skip to content

Commit c2a82f4

Browse files
committed
fix(controller): preserve state across workflow reset and improve signal handling
- Preserve controller state when resetting workflow to maintain continuity - Emit controller info after workflow:started to prevent state clearing - Add debug logs for better visibility into return-to-controller signal flow
1 parent c61c449 commit c2a82f4

3 files changed

Lines changed: 21 additions & 0 deletions

File tree

‎src/cli/tui/routes/workflow/context/ui-state/store.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ function createStoreInternal(workflowName: string): UIActions & { reset: (workfl
5151
// Reset function to reinitialize state for a new workflow
5252
const reset = (newWorkflowName: string) => {
5353
debug('[UI-STORE] Resetting store for new workflow: %s', newWorkflowName)
54+
// Preserve controller state across workflow reset
55+
const preservedControllerState = state.controllerState
5456
state = createInitialState(newWorkflowName)
57+
if (preservedControllerState) {
58+
debug('[UI-STORE] Preserving controller state: %s', preservedControllerState.id)
59+
state.controllerState = preservedControllerState
60+
}
5561
notifyImmediate()
5662
}
5763

‎src/workflows/run.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,13 @@ export async function runWorkflow(options: RunWorkflowOptions = {}): Promise<voi
245245
// This ensures timeline only appears when switching to executing view
246246
emitter.workflowStarted(template.name, moduleSteps.length);
247247

248+
// Emit controller info AFTER workflow:started to prevent reset() from clearing it
249+
// This enables the 'c' key to return to controller even while step agent executes
250+
if (controllerResult.controllerInfo) {
251+
const info = controllerResult.controllerInfo;
252+
emitter.setControllerInfo(info.id, info.name, info.engine, info.model);
253+
}
254+
248255
// Pre-populate timeline
249256
debug('[Workflow] ========== TIMELINE POPULATION ==========');
250257
debug('[Workflow] startIndex=%d, actualStartIndex=%d, total moduleSteps=%d', startIndex, actualStartIndex, moduleSteps.length);

‎src/workflows/signals/handlers/return.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,30 @@ export async function handleReturnToControllerSignal(ctx: SignalContext): Promis
4646
ctx.machine.send({ type: 'PAUSE' })
4747
ctx.mode.pause()
4848

49+
debug('[ReturnToControllerSignal] After pause, machine state=%s', ctx.machine.state)
50+
4951
// Abort current step if running
5052
const abortController = ctx.getAbortController()
5153
if (abortController && !abortController.signal.aborted) {
5254
debug('[ReturnToControllerSignal] Aborting current step')
5355
abortController.abort()
5456
}
57+
debug('[ReturnToControllerSignal] After abort check')
5558

5659
// CRITICAL: Emit mode-change event to abort ControllerInputProvider
5760
// This must be done BEFORE switching views to ensure the controller's executeWithActions aborts
5861
debug('[ReturnToControllerSignal] Emitting mode-change with autonomousMode=false to abort controller')
5962
;(process as NodeJS.EventEmitter).emit('workflow:mode-change', { autonomousMode: 'false' })
63+
debug('[ReturnToControllerSignal] After mode-change emit')
6064

6165
// Switch to controller view
66+
debug('[ReturnToControllerSignal] About to call setControllerView')
6267
await setControllerView(ctx.cmRoot, true)
68+
debug('[ReturnToControllerSignal] After setControllerView, about to emit workflow:view')
6369
ctx.emitter.setWorkflowView('controller')
70+
debug('[ReturnToControllerSignal] After setWorkflowView')
6471
ctx.emitter.updateControllerStatus('awaiting')
72+
debug('[ReturnToControllerSignal] After updateControllerStatus')
6573

6674
// Set autonomous mode to never for conversation (file persistence)
6775
await setAutonomousMode(ctx.cmRoot, 'never')

0 commit comments

Comments
 (0)