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:
@@ -335,6 +335,7 @@ export function sanitizeHookData(data: Record<string, unknown> | null | undefine
|
||||
'permission_mode',
|
||||
'stop_hook_active',
|
||||
'transcript_path',
|
||||
'message',
|
||||
];
|
||||
|
||||
for (const key of allowedKeys) {
|
||||
@@ -343,6 +344,15 @@ export function sanitizeHookData(data: Record<string, unknown> | null | undefine
|
||||
}
|
||||
}
|
||||
|
||||
// Notification hooks carry the human-readable prompt text in `message`
|
||||
// ("Claude needs your permission to use Bash"). Bound it like the
|
||||
// tool_input summaries; the frontend and the Approvals Inbox both read it.
|
||||
if (typeof safeFields.message === 'string') {
|
||||
safeFields.message = safeFields.message.slice(0, 500);
|
||||
} else if ('message' in safeFields) {
|
||||
delete safeFields.message;
|
||||
}
|
||||
|
||||
// For tool_input, extract only summary fields (not full file content)
|
||||
if (safeFields.tool_input && typeof safeFields.tool_input === 'object') {
|
||||
const input = safeFields.tool_input as Record<string, unknown>;
|
||||
|
||||
Reference in New Issue
Block a user