mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 23:49:41 +02:00
feat: Approvals Inbox, one cross-session queue for prompts waiting on a human
Permission dialogs, AskUserQuestion questions and idle prompts from every session now land in a server-side inbox (web/approval-inbox.ts, one item per session, claude-mode only) and are answerable in place: a header bell + drawer on desktop, inline answer strips on the phone overview's NEEDS YOU rows, and working push Approve/Deny buttons (previously dead ends, now answered straight from sw.js with no tab open). Pending alerts survive reloads because the frontend seeds from GET /api/approvals on init. Answering sends the digit / Esc / prompt text through the existing tmux input path; option digits are accepted only when they match options parsed from the captured pane frame, and the answer path re-captures the pane first so a dialog that already left the screen refuses with 409 instead of typing into the composer. New elicitation_complete / elicitation_response hook matchers resolve question items the moment they are answered in the terminal; refreshStaleCodemanHooks heals existing cases. Verified end-to-end against a live claude session: a real AskUserQuestion dialog parsed into 5 option buttons and was answered from the drawer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -237,10 +237,17 @@ const _SSE_HANDLER_MAP = [
|
||||
[SSE_EVENTS.HOOK_IDLE_PROMPT, '_onHookIdlePrompt'],
|
||||
[SSE_EVENTS.HOOK_PERMISSION_PROMPT, '_onHookPermissionPrompt'],
|
||||
[SSE_EVENTS.HOOK_ELICITATION_DIALOG, '_onHookElicitationDialog'],
|
||||
[SSE_EVENTS.HOOK_ELICITATION_COMPLETE, '_onHookElicitationComplete'],
|
||||
[SSE_EVENTS.HOOK_ELICITATION_RESPONSE, '_onHookElicitationResponse'],
|
||||
[SSE_EVENTS.HOOK_STOP, '_onHookStop'],
|
||||
[SSE_EVENTS.HOOK_TEAMMATE_IDLE, '_onHookTeammateIdle'],
|
||||
[SSE_EVENTS.HOOK_TASK_COMPLETED, '_onHookTaskCompleted'],
|
||||
|
||||
// Approvals Inbox (handlers in approvals-ui.js)
|
||||
[SSE_EVENTS.APPROVAL_PENDING, '_onApprovalPending'],
|
||||
[SSE_EVENTS.APPROVAL_UPDATED, '_onApprovalUpdated'],
|
||||
[SSE_EVENTS.APPROVAL_RESOLVED, '_onApprovalResolved'],
|
||||
|
||||
// Subagents (Claude Code background agents)
|
||||
[SSE_EVENTS.SUBAGENT_DISCOVERED, '_onSubagentDiscovered'],
|
||||
[SSE_EVENTS.SUBAGENT_UPDATED, '_onSubagentUpdated'],
|
||||
@@ -630,6 +637,9 @@ class CodemanApp {
|
||||
// Tracks pending hook events that need resolution (permission_prompt, elicitation_dialog, idle_prompt)
|
||||
this.pendingHooks = new Map();
|
||||
|
||||
// Approvals Inbox: Map<approvalId, ApprovalItem> (methods in approvals-ui.js)
|
||||
this.approvals = new Map();
|
||||
|
||||
// WebSocket terminal I/O (low-latency bypass of HTTP POST + SSE)
|
||||
this._ws = null; // WebSocket instance for active session
|
||||
this._wsSessionId = null; // Session ID the WS is connected to
|
||||
@@ -3030,6 +3040,8 @@ class CodemanApp {
|
||||
this._predictiveEcho?.clearPredictions();
|
||||
// Clear pending hooks
|
||||
this.pendingHooks.clear();
|
||||
// Clear approvals (re-seeded from GET /api/approvals right after init)
|
||||
this.approvals?.clear();
|
||||
// Clear parent name cache (prevents stale session name entries accumulating)
|
||||
if (this._parentNameCache) this._parentNameCache.clear();
|
||||
// Clear subagent activity/results maps (prevents leaks if data.subagents is missing)
|
||||
@@ -3170,6 +3182,10 @@ class CodemanApp {
|
||||
this.updateCost();
|
||||
this.renderSessionTabs();
|
||||
|
||||
// Approvals Inbox: re-seed pending prompts from the server so alerts
|
||||
// survive reloads and SSE reconnects (methods in approvals-ui.js).
|
||||
this.seedApprovals?.();
|
||||
|
||||
// Start/stop system stats polling based on session count
|
||||
if (this.sessions.size > 0) {
|
||||
this.startSystemStatsPolling();
|
||||
|
||||
Reference in New Issue
Block a user