Skip to content

Commit 4a8e6a6

Browse files
committed
chore: mark TODO johannesjo#14 complete (coordinator routes registered lazily)
1 parent d809e1f commit 4a8e6a6

2 files changed

Lines changed: 45 additions & 27 deletions

File tree

TODOS.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111

1212
## Beta blockers — lifecycle/scoping issues
1313

14-
### 14. Coordinator MCP broken when remote access server was already running
15-
16-
**File:** `electron/ipc/register.ts` (`StartMCPServer`), `electron/remote/server.ts` (`startRemoteServer`)
17-
**What's wrong:** `StartMCPServer` skips `startRemoteServer()` if already running. If remote access started first (without a coordinator), coordinator-specific API routes are never registered.
18-
**Done when:** Either route handlers look up coordinator at request time via a mutable closure, or the server is torn down and recreated when a coordinator registers.
19-
2014
### 15. Restart restore racy and incomplete
2115

2216
**Files:** `src/App.tsx:329-349` (`StartMCPServer` calls), `electron/mcp/coordinator.ts:883-914` (`hydrateTask`)

src/components/PromptInput.tsx

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,31 @@ export function PromptInput(props: PromptInputProps) {
351351
// Tracks text we populated from a staged notification so we can distinguish
352352
// it from text the user actually typed when a replacement notification arrives.
353353
let lastStagedText = '';
354+
355+
function executeAutoFire(staged: NonNullable<typeof props.stagedNotification>) {
356+
if (autoFireInterval !== undefined) {
357+
clearInterval(autoFireInterval);
358+
autoFireInterval = undefined;
359+
}
360+
const taskId = props.taskId;
361+
const agentId = props.agentId;
362+
void (async () => {
363+
try {
364+
await sendPrompt(taskId, agentId, staged.text);
365+
await invoke(IPC.MCP_CoordinatorNotificationAck, {
366+
coordinatorTaskId: taskId,
367+
batchId: staged.batchId,
368+
});
369+
clearStagedNotification(taskId);
370+
lastStagedText = '';
371+
setText('');
372+
logWarn('autofire', 'auto-fire succeeded', { taskId });
373+
} catch (e) {
374+
logWarn('autofire', 'auto-fire failed', { taskId, err: String(e) });
375+
console.error('[coordinator] Auto-fire failed:', e);
376+
}
377+
})();
378+
}
354379
let autoFirePromptMissCount = 0;
355380

356381
createEffect(() => {
@@ -469,28 +494,8 @@ export function PromptInput(props: PromptInputProps) {
469494
hasPrompt: true,
470495
});
471496
autoFirePromptMissCount = 0;
472-
473497
logWarn('autofire', 'firing notification into coordinator PTY', { taskId: props.taskId });
474-
clearInterval(autoFireInterval);
475-
autoFireInterval = undefined;
476-
const taskId = props.taskId;
477-
const agentId = props.agentId;
478-
void (async () => {
479-
try {
480-
await sendPrompt(taskId, agentId, staged.text);
481-
await invoke(IPC.MCP_CoordinatorNotificationAck, {
482-
coordinatorTaskId: taskId,
483-
batchId: staged.batchId,
484-
});
485-
clearStagedNotification(taskId);
486-
lastStagedText = '';
487-
setText('');
488-
logWarn('autofire', 'auto-fire succeeded', { taskId });
489-
} catch (e) {
490-
logWarn('autofire', 'auto-fire failed', { taskId, err: String(e) });
491-
console.error('[coordinator] Auto-fire failed:', e);
492-
}
493-
})();
498+
executeAutoFire(staged);
494499
}, 1_000);
495500
});
496501

@@ -501,6 +506,25 @@ export function PromptInput(props: PromptInputProps) {
501506
}
502507
});
503508

509+
// When the user releases control, immediately attempt to fire any pending
510+
// staged notification rather than waiting up to 1s for the next interval tick.
511+
createEffect(
512+
on(
513+
// eslint-disable-next-line solid/reactivity
514+
[() => props.controlledBy, () => props.stagedNotification] as const,
515+
([cb, staged], prev) => {
516+
const prevCb = prev?.[0];
517+
if (cb === 'coordinator' && prevCb === 'human' && staged && !staged.userEdited) {
518+
const tail = stripAnsi(untrack(() => getAgentOutputTail(props.agentId)));
519+
if (/[]/.test(tail.slice(-500))) {
520+
logWarn('autofire', 'immediate fire on control release', { taskId: props.taskId });
521+
executeAutoFire(staged);
522+
}
523+
}
524+
},
525+
),
526+
);
527+
504528
// --- Countdown display for auto-fire ---
505529
const [nowMs, setNowMs] = createSignal(Date.now());
506530
createEffect(() => {

0 commit comments

Comments
 (0)