aicodeman 1.14.2 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/README.zh-CN.md +91 -21
  2. package/dist/cli.d.ts +32 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +19 -8
  5. package/dist/cli.js.map +1 -1
  6. package/dist/hooks-config.d.ts +23 -2
  7. package/dist/hooks-config.d.ts.map +1 -1
  8. package/dist/hooks-config.js +118 -52
  9. package/dist/hooks-config.js.map +1 -1
  10. package/dist/mux-interface.d.ts +10 -0
  11. package/dist/mux-interface.d.ts.map +1 -1
  12. package/dist/respawn-patterns.d.ts.map +1 -1
  13. package/dist/respawn-patterns.js +7 -2
  14. package/dist/respawn-patterns.js.map +1 -1
  15. package/dist/session-activity.d.ts +73 -0
  16. package/dist/session-activity.d.ts.map +1 -0
  17. package/dist/session-activity.js +74 -0
  18. package/dist/session-activity.js.map +1 -0
  19. package/dist/session-cli-builder.d.ts +33 -1
  20. package/dist/session-cli-builder.d.ts.map +1 -1
  21. package/dist/session-cli-builder.js +51 -1
  22. package/dist/session-cli-builder.js.map +1 -1
  23. package/dist/session-trust-dialog.d.ts +62 -0
  24. package/dist/session-trust-dialog.d.ts.map +1 -0
  25. package/dist/session-trust-dialog.js +83 -0
  26. package/dist/session-trust-dialog.js.map +1 -0
  27. package/dist/session.d.ts +67 -0
  28. package/dist/session.d.ts.map +1 -1
  29. package/dist/session.js +199 -60
  30. package/dist/session.js.map +1 -1
  31. package/dist/tmux-manager.d.ts +18 -0
  32. package/dist/tmux-manager.d.ts.map +1 -1
  33. package/dist/tmux-manager.js +48 -6
  34. package/dist/tmux-manager.js.map +1 -1
  35. package/dist/types/api.d.ts +1 -1
  36. package/dist/types/api.d.ts.map +1 -1
  37. package/dist/types/api.js.map +1 -1
  38. package/dist/utils/index.d.ts +1 -1
  39. package/dist/utils/index.d.ts.map +1 -1
  40. package/dist/utils/index.js +1 -1
  41. package/dist/utils/index.js.map +1 -1
  42. package/dist/utils/regex-patterns.d.ts +17 -0
  43. package/dist/utils/regex-patterns.d.ts.map +1 -1
  44. package/dist/utils/regex-patterns.js +17 -0
  45. package/dist/utils/regex-patterns.js.map +1 -1
  46. package/dist/web/approval-inbox.d.ts +159 -0
  47. package/dist/web/approval-inbox.d.ts.map +1 -0
  48. package/dist/web/approval-inbox.js +322 -0
  49. package/dist/web/approval-inbox.js.map +1 -0
  50. package/dist/web/public/admin-ui.js.gz +0 -0
  51. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  52. package/dist/web/public/app.c8e6e44e.js +36 -0
  53. package/dist/web/public/app.c8e6e44e.js.br +0 -0
  54. package/dist/web/public/app.c8e6e44e.js.gz +0 -0
  55. package/dist/web/public/approvals-ui.js +242 -0
  56. package/dist/web/public/approvals-ui.js.br +0 -0
  57. package/dist/web/public/approvals-ui.js.gz +0 -0
  58. package/dist/web/public/{constants.e7175b95.js → constants.7d0f4047.js} +86 -0
  59. package/dist/web/public/constants.7d0f4047.js.br +0 -0
  60. package/dist/web/public/constants.7d0f4047.js.gz +0 -0
  61. package/dist/web/public/cron-ui.js.gz +0 -0
  62. package/dist/web/public/entrance-animations.js.gz +0 -0
  63. package/dist/web/public/i18n.75cf29d4.js +1 -0
  64. package/dist/web/public/i18n.75cf29d4.js.br +0 -0
  65. package/dist/web/public/i18n.75cf29d4.js.gz +0 -0
  66. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  67. package/dist/web/public/index.html +81 -12
  68. package/dist/web/public/index.html.br +0 -0
  69. package/dist/web/public/index.html.gz +0 -0
  70. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  71. package/dist/web/public/{keyboard-accessory.9936227d.js → keyboard-accessory.d6c3ad11.js} +50 -0
  72. package/dist/web/public/keyboard-accessory.d6c3ad11.js.br +0 -0
  73. package/dist/web/public/keyboard-accessory.d6c3ad11.js.gz +0 -0
  74. package/dist/web/public/mobile-handlers.32fdd57f.js.gz +0 -0
  75. package/dist/web/public/mobile-overview.js +49 -0
  76. package/dist/web/public/mobile-overview.js.br +0 -0
  77. package/dist/web/public/mobile-overview.js.gz +0 -0
  78. package/dist/web/public/mobile.8a2651ba.css +1 -0
  79. package/dist/web/public/mobile.8a2651ba.css.br +0 -0
  80. package/dist/web/public/mobile.8a2651ba.css.gz +0 -0
  81. package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
  82. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  83. package/dist/web/public/{panels-ui.1d4203e0.js → panels-ui.3df9cd95.js} +5 -5
  84. package/dist/web/public/panels-ui.3df9cd95.js.br +0 -0
  85. package/dist/web/public/panels-ui.3df9cd95.js.gz +0 -0
  86. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  87. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  88. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  89. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  90. package/dist/web/public/session-ui.1356a4f4.js.gz +0 -0
  91. package/dist/web/public/{settings-ui.b41d33a5.js → settings-ui.20f9c723.js} +10 -10
  92. package/dist/web/public/settings-ui.20f9c723.js.br +0 -0
  93. package/dist/web/public/settings-ui.20f9c723.js.gz +0 -0
  94. package/dist/web/public/{styles.c4e58e13.css → styles.e33fc754.css} +1 -1
  95. package/dist/web/public/styles.e33fc754.css.br +0 -0
  96. package/dist/web/public/styles.e33fc754.css.gz +0 -0
  97. package/dist/web/public/subagent-windows.4cc8b005.js.gz +0 -0
  98. package/dist/web/public/sw.js +45 -20
  99. package/dist/web/public/sw.js.br +0 -0
  100. package/dist/web/public/sw.js.gz +0 -0
  101. package/dist/web/public/terminal-ui.430395be.js +4 -0
  102. package/dist/web/public/terminal-ui.430395be.js.br +0 -0
  103. package/dist/web/public/terminal-ui.430395be.js.gz +0 -0
  104. package/dist/web/public/ultracode-panel.js.gz +0 -0
  105. package/dist/web/public/ultracode-windows.js.gz +0 -0
  106. package/dist/web/public/upload.html.gz +0 -0
  107. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  108. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  109. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  110. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  111. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  112. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  113. package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js +4 -0
  114. package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.br +0 -0
  115. package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.gz +0 -0
  116. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  117. package/dist/web/public/vendor/xterm.css.gz +0 -0
  118. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  119. package/dist/web/public/{voice-input.085e9e73.js → voice-input.e5461859.js} +3 -0
  120. package/dist/web/public/voice-input.e5461859.js.br +0 -0
  121. package/dist/web/public/{voice-input.085e9e73.js.gz → voice-input.e5461859.js.gz} +0 -0
  122. package/dist/web/public/webview-tabs.js.gz +0 -0
  123. package/dist/web/route-helpers.d.ts.map +1 -1
  124. package/dist/web/route-helpers.js +10 -0
  125. package/dist/web/route-helpers.js.map +1 -1
  126. package/dist/web/routes/approval-routes.d.ts +19 -0
  127. package/dist/web/routes/approval-routes.d.ts.map +1 -0
  128. package/dist/web/routes/approval-routes.js +119 -0
  129. package/dist/web/routes/approval-routes.js.map +1 -0
  130. package/dist/web/routes/file-routes.d.ts.map +1 -1
  131. package/dist/web/routes/file-routes.js +24 -8
  132. package/dist/web/routes/file-routes.js.map +1 -1
  133. package/dist/web/routes/hook-event-routes.d.ts +3 -0
  134. package/dist/web/routes/hook-event-routes.d.ts.map +1 -1
  135. package/dist/web/routes/hook-event-routes.js +61 -3
  136. package/dist/web/routes/hook-event-routes.js.map +1 -1
  137. package/dist/web/routes/index.d.ts +1 -0
  138. package/dist/web/routes/index.d.ts.map +1 -1
  139. package/dist/web/routes/index.js +1 -0
  140. package/dist/web/routes/index.js.map +1 -1
  141. package/dist/web/routes/session-routes.d.ts.map +1 -1
  142. package/dist/web/routes/session-routes.js +30 -2
  143. package/dist/web/routes/session-routes.js.map +1 -1
  144. package/dist/web/schemas.d.ts +26 -0
  145. package/dist/web/schemas.d.ts.map +1 -1
  146. package/dist/web/schemas.js +40 -1
  147. package/dist/web/schemas.js.map +1 -1
  148. package/dist/web/sensitive-path.d.ts +12 -0
  149. package/dist/web/sensitive-path.d.ts.map +1 -1
  150. package/dist/web/sensitive-path.js +49 -4
  151. package/dist/web/sensitive-path.js.map +1 -1
  152. package/dist/web/server.d.ts.map +1 -1
  153. package/dist/web/server.js +31 -3
  154. package/dist/web/server.js.map +1 -1
  155. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  156. package/dist/web/session-listener-wiring.js +9 -0
  157. package/dist/web/session-listener-wiring.js.map +1 -1
  158. package/dist/web/sse-events.d.ts +18 -2
  159. package/dist/web/sse-events.d.ts.map +1 -1
  160. package/dist/web/sse-events.js +20 -2
  161. package/dist/web/sse-events.js.map +1 -1
  162. package/package.json +3 -1
  163. package/scripts/postinstall.js +29 -0
  164. package/skills/codeman/SKILL.md +109 -15
  165. package/skills/codeman/reference/endpoints.md +66 -8
  166. package/skills/codeman/reference/messaging.md +216 -0
  167. package/skills/codeman/reference/recipes.md +59 -5
  168. package/dist/web/public/app.94825d85.js +0 -36
  169. package/dist/web/public/app.94825d85.js.br +0 -0
  170. package/dist/web/public/app.94825d85.js.gz +0 -0
  171. package/dist/web/public/constants.e7175b95.js.br +0 -0
  172. package/dist/web/public/constants.e7175b95.js.gz +0 -0
  173. package/dist/web/public/i18n.da34cfaf.js +0 -1
  174. package/dist/web/public/i18n.da34cfaf.js.br +0 -0
  175. package/dist/web/public/i18n.da34cfaf.js.gz +0 -0
  176. package/dist/web/public/keyboard-accessory.9936227d.js.br +0 -0
  177. package/dist/web/public/keyboard-accessory.9936227d.js.gz +0 -0
  178. package/dist/web/public/mobile.32cacde5.css +0 -1
  179. package/dist/web/public/mobile.32cacde5.css.br +0 -0
  180. package/dist/web/public/mobile.32cacde5.css.gz +0 -0
  181. package/dist/web/public/panels-ui.1d4203e0.js.br +0 -0
  182. package/dist/web/public/panels-ui.1d4203e0.js.gz +0 -0
  183. package/dist/web/public/settings-ui.b41d33a5.js.br +0 -0
  184. package/dist/web/public/settings-ui.b41d33a5.js.gz +0 -0
  185. package/dist/web/public/styles.c4e58e13.css.br +0 -0
  186. package/dist/web/public/styles.c4e58e13.css.gz +0 -0
  187. package/dist/web/public/terminal-ui.bc6819a9.js +0 -4
  188. package/dist/web/public/terminal-ui.bc6819a9.js.br +0 -0
  189. package/dist/web/public/terminal-ui.bc6819a9.js.gz +0 -0
  190. package/dist/web/public/voice-input.085e9e73.js.br +0 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * @fileoverview Approvals Inbox: server-side registry of prompts waiting on a human.
3
+ *
4
+ * One cross-session queue of pending Claude prompts (permission dialogs,
5
+ * AskUserQuestion/elicitation questions, idle prompts), fed by `/api/hook-event`
6
+ * and answered via `POST /api/approvals/:id/answer`. Before this store existed,
7
+ * pending prompts lived only in `app.js` memory (SSE-transient, lost on reload)
8
+ * and the push notification Approve/Deny buttons had nothing to act on.
9
+ * Design: `docs/approvals-inbox-plan.md`.
10
+ *
11
+ * Invariants:
12
+ * - At most ONE active item per session: the Claude TUI shows one dialog at a
13
+ * time, so a new prompt supersedes the session's previous item.
14
+ * - Module-level singleton in the style of `session-wait-registry.ts`: no
15
+ * `Session` import, no IO; the server injects emit callbacks (`onPending`/
16
+ * `onUpdated`/`onResolved`), which keeps this unit-testable and cycle-free.
17
+ * - Items are in-memory only. A server restart drops them; the next prompt
18
+ * re-fires the hook. Claude-mode sessions only (hooks fire for nothing else).
19
+ * - Answer flow is take-then-write: `take()` removes the item BEFORE keystrokes
20
+ * are sent so a double-tap cannot double-send; `restore()` re-inserts on a
21
+ * failed write unless a newer prompt arrived meanwhile.
22
+ *
23
+ * @dependencies utils (stripAnsi)
24
+ * @consumedby web/routes/hook-event-routes (notePrompt/resolve), web/routes/approval-routes,
25
+ * web/session-listener-wiring (working/exit resolution), web/server (emit callbacks + stop)
26
+ *
27
+ * @module web/approval-inbox
28
+ */
29
+ export type ApprovalKind = 'permission' | 'question' | 'idle';
30
+ export type ApprovalResolution = 'answered' | 'resolved_in_terminal' | 'superseded' | 'session_ended' | 'dismissed' | 'expired';
31
+ /** A numbered choice parsed from the captured dialog frame. */
32
+ export interface ApprovalOption {
33
+ n: number;
34
+ label: string;
35
+ }
36
+ export interface ApprovalItem {
37
+ /** `${sessionId}:${seq}`, stable across re-captures, unique per prompt. */
38
+ id: string;
39
+ sessionId: string;
40
+ sessionName: string;
41
+ kind: ApprovalKind;
42
+ createdAt: number;
43
+ /** Sanitized hook fields (already bounded by sanitizeHookData). */
44
+ toolName?: string;
45
+ toolSummary?: string;
46
+ message?: string;
47
+ cwd?: string;
48
+ /** ANSI-stripped tail of the visible pane frame at capture time. */
49
+ context?: string;
50
+ /**
51
+ * Present only when the frame parsed confidently. Gates which digits the
52
+ * answer endpoint accepts; absent → only approve('1')/deny(Esc) are allowed.
53
+ */
54
+ options?: ApprovalOption[];
55
+ }
56
+ export interface ApprovalResolvedInfo {
57
+ id: string;
58
+ sessionId: string;
59
+ kind: ApprovalKind;
60
+ resolution: ApprovalResolution;
61
+ }
62
+ interface NotePromptArgs {
63
+ sessionId: string;
64
+ sessionName: string;
65
+ kind: ApprovalKind;
66
+ toolName?: string;
67
+ toolSummary?: string;
68
+ message?: string;
69
+ cwd?: string;
70
+ /** Returns the raw (ANSI-bearing) pane frame, or null when unavailable. */
71
+ capture?: () => string | null;
72
+ }
73
+ /**
74
+ * Normalize a raw pane capture into card context: convert row repaints to
75
+ * lines, strip ANSI, right-trim lines, drop trailing blanks, keep the last
76
+ * MAX_CONTEXT_LINES lines.
77
+ */
78
+ export declare function normalizeCapturedFrame(raw: string | null | undefined): string | undefined;
79
+ /**
80
+ * Parse the numbered options of a Claude dialog out of a normalized frame.
81
+ *
82
+ * Matches the shapes Ink renders for permission prompts and AskUserQuestion:
83
+ *
84
+ * ❯ 1. Yes ❯ 1. Red
85
+ * 2. Yes, allow all edits (shift+tab) Prefer red
86
+ * 3. No, tell Claude what to do (esc) 2. Blue
87
+ * Prefer blue
88
+ *
89
+ * Options must be consecutively numbered from 1 (2..6 of them); description /
90
+ * wrap / separator lines between options are tolerated up to a small gap
91
+ * (AskUserQuestion puts a description under every option and a ─ separator
92
+ * before its "Chat about this" entry, measured against the live dialog). The
93
+ * LAST complete block in the frame wins (dialogs render at the bottom).
94
+ * Returns undefined when nothing parses; callers then fall back to
95
+ * approve/deny only, so a mis-parse can never route a digit at a dialog that
96
+ * does not have it.
97
+ */
98
+ export declare function parseDialogOptions(context: string | undefined): ApprovalOption[] | undefined;
99
+ export declare class ApprovalInbox {
100
+ /** Keyed by sessionId; the one-active-item-per-session invariant lives here. */
101
+ private items;
102
+ private recaptureTimers;
103
+ /** Capture callbacks kept for answer-time re-verification; dropped on remove. */
104
+ private captures;
105
+ private seq;
106
+ private stopped;
107
+ /** Emit callbacks, injected by the server (SSE broadcast + push). */
108
+ onPending?: (item: ApprovalItem) => void;
109
+ onUpdated?: (item: ApprovalItem) => void;
110
+ onResolved?: (info: ApprovalResolvedInfo) => void;
111
+ /**
112
+ * Record a prompt for a session, superseding any previous item, and return
113
+ * the new item. Captures context immediately and once more after a short
114
+ * delay (see RECAPTURE_DELAY_MS).
115
+ */
116
+ notePrompt(args: NotePromptArgs): ApprovalItem;
117
+ /**
118
+ * Answer-time guard: re-capture the pane and check the dialog is still on
119
+ * screen before keystrokes are sent at it. Only conclusive when the ORIGINAL
120
+ * frame parsed options: if a fresh capture then parses none, the dialog is
121
+ * gone (answered in the terminal moments ago), so the item resolves and the
122
+ * answer must be refused, because the digit would land in whatever now has
123
+ * focus. Unparseable-from-the-start items stay answerable (approve/deny
124
+ * only), same risk the terminal user already carries.
125
+ */
126
+ verifyStillAnswerable(id: string): boolean;
127
+ /** Pending item for a session, TTL-checked. */
128
+ getForSession(sessionId: string): ApprovalItem | undefined;
129
+ /** Pending item by id, TTL-checked. */
130
+ getById(id: string): ApprovalItem | undefined;
131
+ /** All pending items, TTL-swept, oldest first. */
132
+ listPending(): ApprovalItem[];
133
+ /**
134
+ * Remove the item as `answered` and return it, or undefined if it is no
135
+ * longer pending. Callers send keystrokes AFTER a successful take, and
136
+ * `restore()` on a failed write.
137
+ */
138
+ take(id: string): ApprovalItem | undefined;
139
+ /** Re-insert a taken item after a failed write, unless superseded meanwhile. */
140
+ restore(item: ApprovalItem): void;
141
+ /** Remove an item without keystrokes (user chose Dismiss). */
142
+ dismiss(id: string): boolean;
143
+ /**
144
+ * Resolve a session's pending item, if any (stop hook, exit, ...). `kinds`
145
+ * restricts which item kinds the signal may clear: the heuristic `working`
146
+ * transition passes `['idle']` so a mid-turn flap cannot false-clear a
147
+ * pending permission/question dialog.
148
+ */
149
+ resolveForSession(sessionId: string, resolution: ApprovalResolution, kinds?: ApprovalKind[]): void;
150
+ /** Clear all timers (shutdown/tests). Items become inert; no events fire after this. */
151
+ stop(): void;
152
+ private applyCapture;
153
+ private remove;
154
+ private isExpired;
155
+ }
156
+ /** Process-wide singleton, mirroring `sessionWaits`. */
157
+ export declare const approvalInbox: ApprovalInbox;
158
+ export {};
159
+ //# sourceMappingURL=approval-inbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-inbox.d.ts","sourceRoot":"","sources":["../../src/web/approval-inbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,322 @@
1
+ /**
2
+ * @fileoverview Approvals Inbox: server-side registry of prompts waiting on a human.
3
+ *
4
+ * One cross-session queue of pending Claude prompts (permission dialogs,
5
+ * AskUserQuestion/elicitation questions, idle prompts), fed by `/api/hook-event`
6
+ * and answered via `POST /api/approvals/:id/answer`. Before this store existed,
7
+ * pending prompts lived only in `app.js` memory (SSE-transient, lost on reload)
8
+ * and the push notification Approve/Deny buttons had nothing to act on.
9
+ * Design: `docs/approvals-inbox-plan.md`.
10
+ *
11
+ * Invariants:
12
+ * - At most ONE active item per session: the Claude TUI shows one dialog at a
13
+ * time, so a new prompt supersedes the session's previous item.
14
+ * - Module-level singleton in the style of `session-wait-registry.ts`: no
15
+ * `Session` import, no IO; the server injects emit callbacks (`onPending`/
16
+ * `onUpdated`/`onResolved`), which keeps this unit-testable and cycle-free.
17
+ * - Items are in-memory only. A server restart drops them; the next prompt
18
+ * re-fires the hook. Claude-mode sessions only (hooks fire for nothing else).
19
+ * - Answer flow is take-then-write: `take()` removes the item BEFORE keystrokes
20
+ * are sent so a double-tap cannot double-send; `restore()` re-inserts on a
21
+ * failed write unless a newer prompt arrived meanwhile.
22
+ *
23
+ * @dependencies utils (stripAnsi)
24
+ * @consumedby web/routes/hook-event-routes (notePrompt/resolve), web/routes/approval-routes,
25
+ * web/session-listener-wiring (working/exit resolution), web/server (emit callbacks + stop)
26
+ *
27
+ * @module web/approval-inbox
28
+ */
29
+ import { stripAnsi } from '../utils/index.js';
30
+ // ─── Tunables ────────────────────────────────────────────────────────────────
31
+ /** Items older than this are dropped on read: a 12h-old dialog is stale by any measure. */
32
+ const ITEM_TTL_MS = 12 * 60 * 60 * 1000;
33
+ /**
34
+ * The Notification hook can fire before Ink finishes painting the dialog, so a
35
+ * single delayed re-capture picks up the frame the immediate capture missed.
36
+ */
37
+ const RECAPTURE_DELAY_MS = 600;
38
+ /** Context kept per item: enough for a dialog plus a few lines above it. */
39
+ const MAX_CONTEXT_CHARS = 4000;
40
+ const MAX_CONTEXT_LINES = 30;
41
+ const MAX_OPTION_LABEL_CHARS = 120;
42
+ // ─── Pure helpers ────────────────────────────────────────────────────────────
43
+ /**
44
+ * The visible-frame tmux capture (`formatPaneSnapshot`) carries NO newlines: it
45
+ * repaints every row at its absolute position via `ESC[<row>;<col>H`. Verified
46
+ * against a live dialog: without this conversion the whole frame collapses to
47
+ * one line and no dialog ever parses. Column 1 (or omitted) means a fresh row →
48
+ * newline; a mid-row jump becomes a space so adjacent words don't merge.
49
+ */
50
+ // eslint-disable-next-line no-control-regex
51
+ const CURSOR_POSITION_PATTERN = /\x1b\[(?:(\d+)(?:;(\d+))?)?[Hf]/g;
52
+ /**
53
+ * Normalize a raw pane capture into card context: convert row repaints to
54
+ * lines, strip ANSI, right-trim lines, drop trailing blanks, keep the last
55
+ * MAX_CONTEXT_LINES lines.
56
+ */
57
+ export function normalizeCapturedFrame(raw) {
58
+ if (!raw)
59
+ return undefined;
60
+ const rowed = raw.replace(CURSOR_POSITION_PATTERN, (_m, _row, col) => (!col || col === '1' ? '\n' : ' '));
61
+ const lines = stripAnsi(rowed)
62
+ .split('\n')
63
+ .map((line) => line.replace(/\s+$/, ''));
64
+ while (lines.length > 0 && lines[lines.length - 1] === '')
65
+ lines.pop();
66
+ while (lines.length > 0 && lines[0] === '')
67
+ lines.shift();
68
+ if (lines.length === 0)
69
+ return undefined;
70
+ const text = lines.slice(-MAX_CONTEXT_LINES).join('\n');
71
+ return text.length > MAX_CONTEXT_CHARS ? text.slice(-MAX_CONTEXT_CHARS) : text;
72
+ }
73
+ /**
74
+ * Parse the numbered options of a Claude dialog out of a normalized frame.
75
+ *
76
+ * Matches the shapes Ink renders for permission prompts and AskUserQuestion:
77
+ *
78
+ * ❯ 1. Yes ❯ 1. Red
79
+ * 2. Yes, allow all edits (shift+tab) Prefer red
80
+ * 3. No, tell Claude what to do (esc) 2. Blue
81
+ * Prefer blue
82
+ *
83
+ * Options must be consecutively numbered from 1 (2..6 of them); description /
84
+ * wrap / separator lines between options are tolerated up to a small gap
85
+ * (AskUserQuestion puts a description under every option and a ─ separator
86
+ * before its "Chat about this" entry, measured against the live dialog). The
87
+ * LAST complete block in the frame wins (dialogs render at the bottom).
88
+ * Returns undefined when nothing parses; callers then fall back to
89
+ * approve/deny only, so a mis-parse can never route a digit at a dialog that
90
+ * does not have it.
91
+ */
92
+ export function parseDialogOptions(context) {
93
+ if (!context)
94
+ return undefined;
95
+ const lines = context.split('\n');
96
+ let lastComplete;
97
+ let run = [];
98
+ let gap = 0;
99
+ const commit = () => {
100
+ if (run.length >= 2 && run.length <= 6)
101
+ lastComplete = run;
102
+ run = [];
103
+ gap = 0;
104
+ };
105
+ for (const line of lines) {
106
+ const m = line.match(/^\s*(?:❯\s*)?(\d)[.)]\s+(.+)$/);
107
+ const n = m ? Number(m[1]) : NaN;
108
+ if (m && n === run.length + 1) {
109
+ run.push({ n, label: m[2].trim().slice(0, MAX_OPTION_LABEL_CHARS) });
110
+ gap = 0;
111
+ }
112
+ else if (m && n === 1) {
113
+ commit();
114
+ run = [{ n: 1, label: m[2].trim().slice(0, MAX_OPTION_LABEL_CHARS) }];
115
+ }
116
+ else if (run.length > 0 && ++gap > 3) {
117
+ // Too far past the last option for this to still be its description:
118
+ // the block is over.
119
+ commit();
120
+ }
121
+ }
122
+ commit();
123
+ return lastComplete;
124
+ }
125
+ // ─── Registry ────────────────────────────────────────────────────────────────
126
+ export class ApprovalInbox {
127
+ /** Keyed by sessionId; the one-active-item-per-session invariant lives here. */
128
+ items = new Map();
129
+ recaptureTimers = new Map();
130
+ /** Capture callbacks kept for answer-time re-verification; dropped on remove. */
131
+ captures = new Map();
132
+ seq = 0;
133
+ stopped = false;
134
+ /** Emit callbacks, injected by the server (SSE broadcast + push). */
135
+ onPending;
136
+ onUpdated;
137
+ onResolved;
138
+ /**
139
+ * Record a prompt for a session, superseding any previous item, and return
140
+ * the new item. Captures context immediately and once more after a short
141
+ * delay (see RECAPTURE_DELAY_MS).
142
+ */
143
+ notePrompt(args) {
144
+ this.resolveForSession(args.sessionId, 'superseded');
145
+ const item = {
146
+ id: `${args.sessionId}:${++this.seq}`,
147
+ sessionId: args.sessionId,
148
+ sessionName: args.sessionName,
149
+ kind: args.kind,
150
+ createdAt: Date.now(),
151
+ toolName: args.toolName,
152
+ toolSummary: args.toolSummary,
153
+ message: args.message,
154
+ cwd: args.cwd,
155
+ };
156
+ this.applyCapture(item, args.capture);
157
+ this.items.set(args.sessionId, item);
158
+ if (args.capture)
159
+ this.captures.set(args.sessionId, args.capture);
160
+ this.onPending?.(item);
161
+ if (args.capture && !this.stopped) {
162
+ const timer = setTimeout(() => {
163
+ this.recaptureTimers.delete(item.id);
164
+ // Only update the item if it is still the live one for the session.
165
+ if (this.items.get(args.sessionId)?.id !== item.id)
166
+ return;
167
+ this.applyCapture(item, args.capture);
168
+ this.onUpdated?.(item);
169
+ }, RECAPTURE_DELAY_MS);
170
+ this.recaptureTimers.set(item.id, timer);
171
+ }
172
+ return item;
173
+ }
174
+ /**
175
+ * Answer-time guard: re-capture the pane and check the dialog is still on
176
+ * screen before keystrokes are sent at it. Only conclusive when the ORIGINAL
177
+ * frame parsed options: if a fresh capture then parses none, the dialog is
178
+ * gone (answered in the terminal moments ago), so the item resolves and the
179
+ * answer must be refused, because the digit would land in whatever now has
180
+ * focus. Unparseable-from-the-start items stay answerable (approve/deny
181
+ * only), same risk the terminal user already carries.
182
+ */
183
+ verifyStillAnswerable(id) {
184
+ const item = this.getById(id);
185
+ if (!item)
186
+ return false;
187
+ if (item.kind === 'idle' || !item.options)
188
+ return true;
189
+ const capture = this.captures.get(item.sessionId);
190
+ if (!capture)
191
+ return true;
192
+ let raw = null;
193
+ try {
194
+ raw = capture();
195
+ }
196
+ catch {
197
+ return true; // capture hiccup: inconclusive, keep the item answerable
198
+ }
199
+ const context = normalizeCapturedFrame(raw);
200
+ if (!context)
201
+ return true;
202
+ const options = parseDialogOptions(context);
203
+ if (!options) {
204
+ this.remove(item, 'resolved_in_terminal');
205
+ return false;
206
+ }
207
+ item.context = context;
208
+ item.options = options;
209
+ return true;
210
+ }
211
+ /** Pending item for a session, TTL-checked. */
212
+ getForSession(sessionId) {
213
+ const item = this.items.get(sessionId);
214
+ if (!item)
215
+ return undefined;
216
+ if (this.isExpired(item)) {
217
+ this.resolveForSession(sessionId, 'expired');
218
+ return undefined;
219
+ }
220
+ return item;
221
+ }
222
+ /** Pending item by id, TTL-checked. */
223
+ getById(id) {
224
+ const item = this.getForSession(sessionIdOf(id));
225
+ return item?.id === id ? item : undefined;
226
+ }
227
+ /** All pending items, TTL-swept, oldest first. */
228
+ listPending() {
229
+ for (const sessionId of [...this.items.keys()])
230
+ this.getForSession(sessionId);
231
+ return [...this.items.values()].sort((a, b) => a.createdAt - b.createdAt);
232
+ }
233
+ /**
234
+ * Remove the item as `answered` and return it, or undefined if it is no
235
+ * longer pending. Callers send keystrokes AFTER a successful take, and
236
+ * `restore()` on a failed write.
237
+ */
238
+ take(id) {
239
+ const item = this.getById(id);
240
+ if (!item)
241
+ return undefined;
242
+ this.remove(item, 'answered');
243
+ return item;
244
+ }
245
+ /** Re-insert a taken item after a failed write, unless superseded meanwhile. */
246
+ restore(item) {
247
+ if (this.stopped || this.items.has(item.sessionId))
248
+ return;
249
+ this.items.set(item.sessionId, item);
250
+ this.onPending?.(item);
251
+ }
252
+ /** Remove an item without keystrokes (user chose Dismiss). */
253
+ dismiss(id) {
254
+ const item = this.getById(id);
255
+ if (!item)
256
+ return false;
257
+ this.remove(item, 'dismissed');
258
+ return true;
259
+ }
260
+ /**
261
+ * Resolve a session's pending item, if any (stop hook, exit, ...). `kinds`
262
+ * restricts which item kinds the signal may clear: the heuristic `working`
263
+ * transition passes `['idle']` so a mid-turn flap cannot false-clear a
264
+ * pending permission/question dialog.
265
+ */
266
+ resolveForSession(sessionId, resolution, kinds) {
267
+ const item = this.items.get(sessionId);
268
+ if (!item)
269
+ return;
270
+ if (kinds && !kinds.includes(item.kind))
271
+ return;
272
+ this.remove(item, resolution);
273
+ }
274
+ /** Clear all timers (shutdown/tests). Items become inert; no events fire after this. */
275
+ stop() {
276
+ this.stopped = true;
277
+ for (const timer of this.recaptureTimers.values())
278
+ clearTimeout(timer);
279
+ this.recaptureTimers.clear();
280
+ this.items.clear();
281
+ this.captures.clear();
282
+ }
283
+ applyCapture(item, capture) {
284
+ if (!capture)
285
+ return;
286
+ let raw = null;
287
+ try {
288
+ raw = capture();
289
+ }
290
+ catch {
291
+ // Capture is best-effort; the card still renders from hook fields.
292
+ }
293
+ const context = normalizeCapturedFrame(raw);
294
+ if (!context)
295
+ return;
296
+ item.context = context;
297
+ // Idle prompts are not dialogs; never offer digit answers for them.
298
+ if (item.kind !== 'idle')
299
+ item.options = parseDialogOptions(context);
300
+ }
301
+ remove(item, resolution) {
302
+ this.items.delete(item.sessionId);
303
+ this.captures.delete(item.sessionId);
304
+ const timer = this.recaptureTimers.get(item.id);
305
+ if (timer) {
306
+ clearTimeout(timer);
307
+ this.recaptureTimers.delete(item.id);
308
+ }
309
+ if (!this.stopped) {
310
+ this.onResolved?.({ id: item.id, sessionId: item.sessionId, kind: item.kind, resolution });
311
+ }
312
+ }
313
+ isExpired(item) {
314
+ return Date.now() - item.createdAt > ITEM_TTL_MS;
315
+ }
316
+ }
317
+ function sessionIdOf(itemId) {
318
+ return itemId.slice(0, itemId.lastIndexOf(':'));
319
+ }
320
+ /** Process-wide singleton, mirroring `sessionWaits`. */
321
+ export const approvalInbox = new ApprovalInbox();
322
+ //# sourceMappingURL=approval-inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-inbox.js","sourceRoot":"","sources":["../../src/web/approval-inbox.ts"],"names":[],"mappings":"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"}
Binary file