aicodeman 1.16.2 → 1.16.4

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 (158) hide show
  1. package/README.md +11 -10
  2. package/dist/claude-credentials.d.ts +50 -0
  3. package/dist/claude-credentials.d.ts.map +1 -0
  4. package/dist/claude-credentials.js +102 -0
  5. package/dist/claude-credentials.js.map +1 -0
  6. package/dist/config/voice.d.ts +43 -0
  7. package/dist/config/voice.d.ts.map +1 -0
  8. package/dist/config/voice.js +48 -0
  9. package/dist/config/voice.js.map +1 -0
  10. package/dist/search-service.d.ts +9 -1
  11. package/dist/search-service.d.ts.map +1 -1
  12. package/dist/search-service.js +13 -3
  13. package/dist/search-service.js.map +1 -1
  14. package/dist/services/unified-session-service.d.ts +9 -0
  15. package/dist/services/unified-session-service.d.ts.map +1 -1
  16. package/dist/services/unified-session-service.js +4 -1
  17. package/dist/services/unified-session-service.js.map +1 -1
  18. package/dist/types/search.d.ts +17 -3
  19. package/dist/types/search.d.ts.map +1 -1
  20. package/dist/web/ports/config-port.d.ts +2 -0
  21. package/dist/web/ports/config-port.d.ts.map +1 -1
  22. package/dist/web/public/admin-ui.js +35 -20
  23. package/dist/web/public/admin-ui.js.br +0 -0
  24. package/dist/web/public/admin-ui.js.gz +0 -0
  25. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  26. package/dist/web/public/{app.4d006245.js → app.f9c6aadd.js} +18 -18
  27. package/dist/web/public/app.f9c6aadd.js.br +0 -0
  28. package/dist/web/public/app.f9c6aadd.js.gz +0 -0
  29. package/dist/web/public/approvals-ui.js.gz +0 -0
  30. package/dist/web/public/{constants.7d0f4047.js → constants.53dc0fa1.js} +43 -0
  31. package/dist/web/public/constants.53dc0fa1.js.br +0 -0
  32. package/dist/web/public/constants.53dc0fa1.js.gz +0 -0
  33. package/dist/web/public/cron-ui.js.gz +0 -0
  34. package/dist/web/public/entrance-animations.js.gz +0 -0
  35. package/dist/web/public/home-sessions.js +132 -10
  36. package/dist/web/public/home-sessions.js.br +0 -0
  37. package/dist/web/public/home-sessions.js.gz +0 -0
  38. package/dist/web/public/i18n.89097ff5.js +1 -0
  39. package/dist/web/public/i18n.89097ff5.js.br +0 -0
  40. package/dist/web/public/i18n.89097ff5.js.gz +0 -0
  41. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  42. package/dist/web/public/index.html +1335 -1000
  43. package/dist/web/public/index.html.br +0 -0
  44. package/dist/web/public/index.html.gz +0 -0
  45. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  46. package/dist/web/public/{keyboard-accessory.1f35b482.js → keyboard-accessory.0f524637.js} +207 -5
  47. package/dist/web/public/keyboard-accessory.0f524637.js.br +0 -0
  48. package/dist/web/public/keyboard-accessory.0f524637.js.gz +0 -0
  49. package/dist/web/public/mobile-handlers.32fdd57f.js.gz +0 -0
  50. package/dist/web/public/mobile-overview.js.gz +0 -0
  51. package/dist/web/public/mobile.4f875962.css +1 -0
  52. package/dist/web/public/mobile.4f875962.css.br +0 -0
  53. package/dist/web/public/mobile.4f875962.css.gz +0 -0
  54. package/dist/web/public/notification-manager.5d229063.js.gz +0 -0
  55. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  56. package/dist/web/public/{panels-ui.3df9cd95.js → panels-ui.54b0d004.js} +1 -1
  57. package/dist/web/public/panels-ui.54b0d004.js.br +0 -0
  58. package/dist/web/public/panels-ui.54b0d004.js.gz +0 -0
  59. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  60. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  61. package/dist/web/public/readmymind-ui.js +98 -18
  62. package/dist/web/public/readmymind-ui.js.br +0 -0
  63. package/dist/web/public/readmymind-ui.js.gz +0 -0
  64. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  65. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  66. package/dist/web/public/{session-ui.f4fed187.js → session-ui.46a0993c.js} +5 -5
  67. package/dist/web/public/session-ui.46a0993c.js.br +0 -0
  68. package/dist/web/public/session-ui.46a0993c.js.gz +0 -0
  69. package/dist/web/public/settings-ui.63be4178.js +67 -0
  70. package/dist/web/public/settings-ui.63be4178.js.br +0 -0
  71. package/dist/web/public/settings-ui.63be4178.js.gz +0 -0
  72. package/dist/web/public/styles.9e04378d.css +1 -0
  73. package/dist/web/public/styles.9e04378d.css.br +0 -0
  74. package/dist/web/public/styles.9e04378d.css.gz +0 -0
  75. package/dist/web/public/subagent-windows.4cc8b005.js.gz +0 -0
  76. package/dist/web/public/sw.js.gz +0 -0
  77. package/dist/web/public/terminal-ui.ae776405.js +4 -0
  78. package/dist/web/public/terminal-ui.ae776405.js.br +0 -0
  79. package/dist/web/public/terminal-ui.ae776405.js.gz +0 -0
  80. package/dist/web/public/ultracode-panel.js.gz +0 -0
  81. package/dist/web/public/ultracode-windows.js.gz +0 -0
  82. package/dist/web/public/upload.html.gz +0 -0
  83. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  84. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  85. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  86. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  87. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  88. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  89. package/dist/web/public/vendor/xterm-predictive-echo.6cec0fba.js.gz +0 -0
  90. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  91. package/dist/web/public/vendor/xterm.css.gz +0 -0
  92. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  93. package/dist/web/public/{voice-input.e5461859.js → voice-input.4ec670b0.js} +421 -13
  94. package/dist/web/public/voice-input.4ec670b0.js.br +0 -0
  95. package/dist/web/public/voice-input.4ec670b0.js.gz +0 -0
  96. package/dist/web/public/voice-pcm-worklet.js +57 -0
  97. package/dist/web/public/voice-pcm-worklet.js.br +0 -0
  98. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  99. package/dist/web/public/webview-tabs.js.gz +0 -0
  100. package/dist/web/routes/index.d.ts +1 -0
  101. package/dist/web/routes/index.d.ts.map +1 -1
  102. package/dist/web/routes/index.js +1 -0
  103. package/dist/web/routes/index.js.map +1 -1
  104. package/dist/web/routes/search-routes.d.ts +3 -1
  105. package/dist/web/routes/search-routes.d.ts.map +1 -1
  106. package/dist/web/routes/search-routes.js +34 -1
  107. package/dist/web/routes/search-routes.js.map +1 -1
  108. package/dist/web/routes/session-routes.d.ts.map +1 -1
  109. package/dist/web/routes/session-routes.js +151 -9
  110. package/dist/web/routes/session-routes.js.map +1 -1
  111. package/dist/web/routes/voice-routes.d.ts +45 -0
  112. package/dist/web/routes/voice-routes.d.ts.map +1 -0
  113. package/dist/web/routes/voice-routes.js +172 -0
  114. package/dist/web/routes/voice-routes.js.map +1 -0
  115. package/dist/web/schemas.d.ts +2 -0
  116. package/dist/web/schemas.d.ts.map +1 -1
  117. package/dist/web/schemas.js +12 -0
  118. package/dist/web/schemas.js.map +1 -1
  119. package/dist/web/server.d.ts +1 -0
  120. package/dist/web/server.d.ts.map +1 -1
  121. package/dist/web/server.js +11 -1
  122. package/dist/web/server.js.map +1 -1
  123. package/dist/web/session-history-index.d.ts +108 -0
  124. package/dist/web/session-history-index.d.ts.map +1 -0
  125. package/dist/web/session-history-index.js +118 -0
  126. package/dist/web/session-history-index.js.map +1 -0
  127. package/dist/web/voice-stream.d.ts +96 -0
  128. package/dist/web/voice-stream.d.ts.map +1 -0
  129. package/dist/web/voice-stream.js +268 -0
  130. package/dist/web/voice-stream.js.map +1 -0
  131. package/package.json +1 -1
  132. package/dist/web/public/app.4d006245.js.br +0 -0
  133. package/dist/web/public/app.4d006245.js.gz +0 -0
  134. package/dist/web/public/constants.7d0f4047.js.br +0 -0
  135. package/dist/web/public/constants.7d0f4047.js.gz +0 -0
  136. package/dist/web/public/i18n.ef50083f.js +0 -1
  137. package/dist/web/public/i18n.ef50083f.js.br +0 -0
  138. package/dist/web/public/i18n.ef50083f.js.gz +0 -0
  139. package/dist/web/public/keyboard-accessory.1f35b482.js.br +0 -0
  140. package/dist/web/public/keyboard-accessory.1f35b482.js.gz +0 -0
  141. package/dist/web/public/mobile.5d8c896c.css +0 -1
  142. package/dist/web/public/mobile.5d8c896c.css.br +0 -0
  143. package/dist/web/public/mobile.5d8c896c.css.gz +0 -0
  144. package/dist/web/public/panels-ui.3df9cd95.js.br +0 -0
  145. package/dist/web/public/panels-ui.3df9cd95.js.gz +0 -0
  146. package/dist/web/public/session-ui.f4fed187.js.br +0 -0
  147. package/dist/web/public/session-ui.f4fed187.js.gz +0 -0
  148. package/dist/web/public/settings-ui.1c15649c.js +0 -67
  149. package/dist/web/public/settings-ui.1c15649c.js.br +0 -0
  150. package/dist/web/public/settings-ui.1c15649c.js.gz +0 -0
  151. package/dist/web/public/styles.0024c22e.css +0 -1
  152. package/dist/web/public/styles.0024c22e.css.br +0 -0
  153. package/dist/web/public/styles.0024c22e.css.gz +0 -0
  154. package/dist/web/public/terminal-ui.e7c5d233.js +0 -4
  155. package/dist/web/public/terminal-ui.e7c5d233.js.br +0 -0
  156. package/dist/web/public/terminal-ui.e7c5d233.js.gz +0 -0
  157. package/dist/web/public/voice-input.e5461859.js.br +0 -0
  158. package/dist/web/public/voice-input.e5461859.js.gz +0 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @fileoverview Bounded in-memory index of PAST sessions, harvested by `GET /api/search`.
3
+ *
4
+ * `GET /api/search` used to build its session corpus from the live in-memory
5
+ * session map alone, so a folder sitting in the home screen's "Resume
6
+ * Conversation" list matched nothing (issue #261). The corpus that list renders
7
+ * comes from `GET /api/sessions/unified`, which reads the lifecycle log and every
8
+ * Claude transcript file: disk I/O the search path deliberately does not do (its
9
+ * no-fs property is what keeps a per-keystroke query cheap and traversal-free).
10
+ *
11
+ * This module is the seam between the two: a capped snapshot of the unified list
12
+ * that the search route reads synchronously, refreshed OUT of the request path.
13
+ * Two things fill it:
14
+ * 1. `/api/sessions/unified` writes it as a side effect (free, it just merged
15
+ * that list). The home screen calls that endpoint whenever it opens, which
16
+ * is the same screen the search box lives on, so it is warm in practice.
17
+ * 2. `ensureHistorySessionIndexFresh()`, fire-and-forget, single-flight,
18
+ * TTL-guarded, kicks the registered refresher when a search finds the
19
+ * snapshot stale. The caller never awaits it: the current query answers from
20
+ * the existing snapshot and the next one sees fresh data.
21
+ *
22
+ * OWNERSHIP: each item carries the `owner` of the session it came from, and rows
23
+ * not tied to any live/persisted session (host-wide transcript history) carry
24
+ * `owner: undefined`. `canAccessOwned()` then reproduces the unified route's rule
25
+ * exactly, in multi-user mode a non-admin sees neither other users' sessions nor
26
+ * unowned host-wide history, and in single-user mode every check short-circuits
27
+ * true. The snapshot is written UNSCOPED, so it must never be returned unfiltered.
28
+ *
29
+ * Key exports:
30
+ * - setHistorySessionIndex / getHistorySessionIndex: the snapshot accessors.
31
+ * - buildHistorySessionIndexItems: pure merged-list → index-item projection.
32
+ * - setHistoryIndexRefresher / ensureHistorySessionIndexFresh: the refresh hook.
33
+ */
34
+ /** Hard cap on snapshot size, so a host with thousands of transcripts stays bounded. */
35
+ export const HISTORY_INDEX_MAX_ITEMS = 400;
36
+ /** How long a snapshot is considered fresh before a search triggers a background refresh. */
37
+ export const HISTORY_INDEX_TTL_MS = 60_000;
38
+ let snapshot = { items: [], updatedAt: 0 };
39
+ let refresher = null;
40
+ let refreshInFlight = false;
41
+ /**
42
+ * Project a merged unified list into index items. PURE, the caller supplies the
43
+ * owner lookup and the live-id set it already has in hand.
44
+ *
45
+ * Rows with no working directory AND no name are dropped: they can never match a
46
+ * query in a useful way and would only consume the cap.
47
+ *
48
+ * @param merged unified-list items, newest-first (the order the merge returns)
49
+ * @param ownerById owner of a session id, for rows tied to a live/persisted session
50
+ * @param liveIds session ids currently in the live map
51
+ */
52
+ export function buildHistorySessionIndexItems(merged, ownerById, liveIds) {
53
+ const items = [];
54
+ for (const m of merged) {
55
+ if (items.length >= HISTORY_INDEX_MAX_ITEMS)
56
+ break;
57
+ const name = m.name ?? '';
58
+ const workingDir = m.workingDir ?? '';
59
+ if (!name && !workingDir)
60
+ continue;
61
+ items.push({
62
+ sessionId: m.sessionId,
63
+ name,
64
+ workingDir,
65
+ claudeSessionId: m.claudeSessionId,
66
+ timestamp: m.lastActivityAt ?? m.createdAt ?? 0,
67
+ owner: ownerById.get(m.sessionId),
68
+ live: liveIds.has(m.sessionId),
69
+ });
70
+ }
71
+ return items;
72
+ }
73
+ /** Replace the snapshot. Items are capped defensively even if the caller already did. */
74
+ export function setHistorySessionIndex(items, now = Date.now()) {
75
+ snapshot = { items: items.slice(0, HISTORY_INDEX_MAX_ITEMS), updatedAt: now };
76
+ }
77
+ /**
78
+ * Read the snapshot. The returned array is UNSCOPED, callers must apply the
79
+ * per-item ownership check before exposing any of it.
80
+ */
81
+ export function getHistorySessionIndex() {
82
+ return snapshot;
83
+ }
84
+ /** True when the snapshot has never been written, or is older than the TTL. */
85
+ export function isHistorySessionIndexStale(now = Date.now(), ttlMs = HISTORY_INDEX_TTL_MS) {
86
+ return snapshot.updatedAt === 0 || now - snapshot.updatedAt > ttlMs;
87
+ }
88
+ /**
89
+ * Register the rebuild function. Called once by the session routes, which own the
90
+ * transcript scanner and the stores the unified list is merged from.
91
+ */
92
+ export function setHistoryIndexRefresher(fn) {
93
+ refresher = fn;
94
+ }
95
+ /**
96
+ * Kick a background rebuild if the snapshot is stale. Returns immediately,
97
+ * NEVER await this from a request handler, that is the whole point: the search
98
+ * path answers from the current snapshot and stays free of disk I/O.
99
+ */
100
+ export function ensureHistorySessionIndexFresh(now = Date.now()) {
101
+ if (refreshInFlight || !refresher || !isHistorySessionIndexStale(now))
102
+ return;
103
+ refreshInFlight = true;
104
+ void refresher()
105
+ .catch(() => {
106
+ // A failed rebuild leaves the previous snapshot in place; the next search retries.
107
+ })
108
+ .finally(() => {
109
+ refreshInFlight = false;
110
+ });
111
+ }
112
+ /** Test hook: drop the snapshot and any registered refresher. */
113
+ export function resetHistorySessionIndex() {
114
+ snapshot = { items: [], updatedAt: 0 };
115
+ refresher = null;
116
+ refreshInFlight = false;
117
+ }
118
+ //# sourceMappingURL=session-history-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-history-index.js","sourceRoot":"","sources":["../../src/web/session-history-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAwBH,wFAAwF;AACxF,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAQ3C,IAAI,QAAQ,GAAgC,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;AACxE,IAAI,SAAS,GAAiC,IAAI,CAAC;AACnD,IAAI,eAAe,GAAG,KAAK,CAAC;AAY5B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,6BAA6B,CAC3C,MAA2B,EAC3B,SAA0C,EAC1C,OAAoB;IAEpB,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,KAAK,CAAC,MAAM,IAAI,uBAAuB;YAAE,MAAM;QACnD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU;YAAE,SAAS;QACnC,KAAK,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI;YACJ,UAAU;YACV,eAAe,EAAE,CAAC,CAAC,eAAe;YAClC,SAAS,EAAE,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC;YAC/C,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YACjC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,sBAAsB,CAAC,KAAgC,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACvF,QAAQ,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,uBAAuB,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,0BAA0B,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,GAAG,oBAAoB;IACvF,OAAO,QAAQ,CAAC,SAAS,KAAK,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,SAAS,GAAG,KAAK,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,EAAgC;IACvE,SAAS,GAAG,EAAE,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7D,IAAI,eAAe,IAAI,CAAC,SAAS,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC;QAAE,OAAO;IAC9E,eAAe,GAAG,IAAI,CAAC;IACvB,KAAK,SAAS,EAAE;SACb,KAAK,CAAC,GAAG,EAAE;QACV,mFAAmF;IACrF,CAAC,CAAC;SACD,OAAO,CAAC,GAAG,EAAE;QACZ,eAAe,GAAG,KAAK,CAAC;IAC1B,CAAC,CAAC,CAAC;AACP,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,wBAAwB;IACtC,QAAQ,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IACvC,SAAS,GAAG,IAAI,CAAC;IACjB,eAAe,GAAG,KAAK,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @fileoverview Upstream half of Claude voice dictation: one browser recording
3
+ * relayed to the speech-to-text service Claude Code's own `/voice` mode uses.
4
+ *
5
+ * The browser cannot talk to that service directly — it would need the Claude
6
+ * OAuth bearer token in page JavaScript, and the endpoint is not CORS-open — so
7
+ * Codeman sits in the middle and is the only thing that ever holds the token.
8
+ * See `docs/claude-voice-plan.md` for the protocol table this implements.
9
+ *
10
+ * Wire contract (mirrors the CLI's `connectVoiceStream`):
11
+ * - Query pins the audio format: linear16 PCM, 16 kHz, mono. The browser worklet
12
+ * produces exactly that; a mismatch transcribes as silence or noise, never an error.
13
+ * - `{"type":"KeepAlive"}` on open and every 8s, or upstream drops the socket
14
+ * between utterances.
15
+ * - Audio frames go up as raw binary.
16
+ * - Downstream, `TranscriptText`/`TranscriptInterim` carry the RUNNING transcript
17
+ * (each frame supersedes the previous one — they are not deltas to concatenate),
18
+ * and `TranscriptEndpoint` promotes the pending interim to final.
19
+ * - `{"type":"CloseStream"}` finalizes; the endpoint frame that follows is the
20
+ * last transcript, so `finalize()` waits briefly for it rather than closing.
21
+ *
22
+ * The pure builders at the top are unit-tested; `VoiceStreamRelay` owns the socket,
23
+ * the keepalive timer and the lifetime cap.
24
+ */
25
+ export interface VoiceStreamParams {
26
+ /** BCP-47-ish language hint. Anything unusable falls back to 'en'. */
27
+ language?: string;
28
+ /** Domain vocabulary sent as a recognition hint. */
29
+ keyterms?: string[];
30
+ }
31
+ /**
32
+ * Collapse keyterms into the single ASCII header value upstream accepts.
33
+ *
34
+ * Commas separate terms, so a comma INSIDE a term would silently split it; it is
35
+ * replaced with a space rather than dropped. Non-ASCII is stripped because the
36
+ * value travels as an HTTP header, where anything outside the visible ASCII range
37
+ * is not portable. Deduped and truncated on a term boundary so a long list degrades
38
+ * to a shorter list instead of a mangled final term.
39
+ */
40
+ export declare function sanitizeKeyterms(terms: string[]): string;
41
+ /** Normalize a language hint to what the endpoint expects, defaulting to English. */
42
+ export declare function normalizeVoiceLanguage(language: string | undefined): string;
43
+ /** Full upstream URL with the audio format pinned. */
44
+ export declare function buildVoiceStreamUrl(params?: VoiceStreamParams, env?: NodeJS.ProcessEnv): string;
45
+ /**
46
+ * Upstream headers. Codeman identifies itself honestly (it is not the CLI), which
47
+ * the endpoint accepts; the bearer token is the only thing that authenticates.
48
+ */
49
+ export declare function buildVoiceStreamHeaders(accessToken: string, appVersion: string, keyterms?: string[]): Record<string, string>;
50
+ export interface VoiceStreamRelayOptions extends VoiceStreamParams {
51
+ accessToken: string;
52
+ appVersion: string;
53
+ /** Called once the upstream socket is open and audio may flow. */
54
+ onReady: () => void;
55
+ /** Running transcript. `final` marks the utterance as complete. */
56
+ onTranscript: (text: string, final: boolean) => void;
57
+ /** Human-readable failure. The relay is dead (or dying) by the time this fires. */
58
+ onError: (message: string) => void;
59
+ /** Terminal: the relay released its socket and timers. Fires exactly once. */
60
+ onClose: () => void;
61
+ }
62
+ /**
63
+ * One dictation, upstream. Owns exactly one WebSocket and dies with it: every
64
+ * exit path (error, upstream close, lifetime cap, caller close) funnels through
65
+ * `_teardown()`, which fires `onClose` once and clears both timers.
66
+ */
67
+ export declare class VoiceStreamRelay {
68
+ private readonly opts;
69
+ private ws;
70
+ private keepAlive;
71
+ private lifetimeTimer;
72
+ private finalizeTimer;
73
+ private closed;
74
+ private finalizing;
75
+ /** Latest interim, held so a close/finalize can promote it to final. */
76
+ private pendingTranscript;
77
+ constructor(opts: VoiceStreamRelayOptions);
78
+ /** Open the upstream socket. Safe to call once; a second call is a no-op. */
79
+ connect(): void;
80
+ /** Relay one raw PCM16 frame upstream. Dropped after finalize, as upstream ignores it. */
81
+ sendAudio(chunk: Buffer): void;
82
+ /**
83
+ * Ask upstream for the final transcript. The endpoint frame usually follows
84
+ * within a few hundred ms; the timer is the backstop so a silent upstream still
85
+ * yields whatever interim we already have instead of hanging the caller.
86
+ */
87
+ finalize(): void;
88
+ /** Terminal shutdown. Idempotent. */
89
+ close(): void;
90
+ private handleMessage;
91
+ /** Emit the held interim as final, exactly once per utterance. */
92
+ private promotePending;
93
+ private safeSend;
94
+ private teardown;
95
+ }
96
+ //# sourceMappingURL=voice-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-stream.d.ts","sourceRoot":"","sources":["../../src/web/voice-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAiBH,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAkBxD;AAED,qFAAqF;AACrF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI3E;AAED,sDAAsD;AACtD,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,iBAAsB,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAYhH;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAM,EAAO,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxB;AAED,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mEAAmE;IACnE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,mFAAmF;IACnF,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,gBAAgB;IAUf,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,wEAAwE;IACxE,OAAO,CAAC,iBAAiB,CAAM;gBAEF,IAAI,EAAE,uBAAuB;IAE1D,6EAA6E;IAC7E,OAAO,IAAI,IAAI;IA8Cf,0FAA0F;IAC1F,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM9B;;;;OAIG;IACH,QAAQ,IAAI,IAAI;IAehB,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAab,OAAO,CAAC,aAAa;IAmCrB,kEAAkE;IAClE,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,QAAQ;CAWjB"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * @fileoverview Upstream half of Claude voice dictation: one browser recording
3
+ * relayed to the speech-to-text service Claude Code's own `/voice` mode uses.
4
+ *
5
+ * The browser cannot talk to that service directly — it would need the Claude
6
+ * OAuth bearer token in page JavaScript, and the endpoint is not CORS-open — so
7
+ * Codeman sits in the middle and is the only thing that ever holds the token.
8
+ * See `docs/claude-voice-plan.md` for the protocol table this implements.
9
+ *
10
+ * Wire contract (mirrors the CLI's `connectVoiceStream`):
11
+ * - Query pins the audio format: linear16 PCM, 16 kHz, mono. The browser worklet
12
+ * produces exactly that; a mismatch transcribes as silence or noise, never an error.
13
+ * - `{"type":"KeepAlive"}` on open and every 8s, or upstream drops the socket
14
+ * between utterances.
15
+ * - Audio frames go up as raw binary.
16
+ * - Downstream, `TranscriptText`/`TranscriptInterim` carry the RUNNING transcript
17
+ * (each frame supersedes the previous one — they are not deltas to concatenate),
18
+ * and `TranscriptEndpoint` promotes the pending interim to final.
19
+ * - `{"type":"CloseStream"}` finalizes; the endpoint frame that follows is the
20
+ * last transcript, so `finalize()` waits briefly for it rather than closing.
21
+ *
22
+ * The pure builders at the top are unit-tested; `VoiceStreamRelay` owns the socket,
23
+ * the keepalive timer and the lifetime cap.
24
+ */
25
+ import WebSocket from 'ws';
26
+ import { AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, FINALIZE_TIMEOUT_MS, KEEPALIVE_INTERVAL_MS, MAX_KEYTERMS_HEADER_CHARS, MAX_STREAM_MS, VOICE_STREAM_PATH, voiceStreamBase, } from '../config/voice.js';
27
+ const KEEPALIVE_FRAME = '{"type":"KeepAlive"}';
28
+ const CLOSE_STREAM_FRAME = '{"type":"CloseStream"}';
29
+ /**
30
+ * Collapse keyterms into the single ASCII header value upstream accepts.
31
+ *
32
+ * Commas separate terms, so a comma INSIDE a term would silently split it; it is
33
+ * replaced with a space rather than dropped. Non-ASCII is stripped because the
34
+ * value travels as an HTTP header, where anything outside the visible ASCII range
35
+ * is not portable. Deduped and truncated on a term boundary so a long list degrades
36
+ * to a shorter list instead of a mangled final term.
37
+ */
38
+ export function sanitizeKeyterms(terms) {
39
+ const seen = new Set();
40
+ const out = [];
41
+ let length = 0;
42
+ for (const term of terms) {
43
+ const cleaned = term
44
+ .replace(/,/g, ' ')
45
+ .replace(/[^\x20-\x7E]/g, '')
46
+ .replace(/\s+/g, ' ')
47
+ .trim();
48
+ if (!cleaned || seen.has(cleaned))
49
+ continue;
50
+ const cost = cleaned.length + (out.length > 0 ? 1 : 0);
51
+ if (length + cost > MAX_KEYTERMS_HEADER_CHARS)
52
+ break;
53
+ seen.add(cleaned);
54
+ out.push(cleaned);
55
+ length += cost;
56
+ }
57
+ return out.join(',');
58
+ }
59
+ /** Normalize a language hint to what the endpoint expects, defaulting to English. */
60
+ export function normalizeVoiceLanguage(language) {
61
+ const trimmed = (language ?? '').trim();
62
+ if (!trimmed || !/^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?$|^multi$/.test(trimmed))
63
+ return 'en';
64
+ return trimmed;
65
+ }
66
+ /** Full upstream URL with the audio format pinned. */
67
+ export function buildVoiceStreamUrl(params = {}, env = process.env) {
68
+ const query = new URLSearchParams({
69
+ encoding: 'linear16',
70
+ sample_rate: String(AUDIO_SAMPLE_RATE),
71
+ channels: String(AUDIO_CHANNELS),
72
+ endpointing_ms: '300',
73
+ utterance_end_ms: '1000',
74
+ language: normalizeVoiceLanguage(params.language),
75
+ use_conversation_engine: 'true',
76
+ stt_provider: 'deepgram-nova3',
77
+ });
78
+ return `${voiceStreamBase(env)}${VOICE_STREAM_PATH}?${query.toString()}`;
79
+ }
80
+ /**
81
+ * Upstream headers. Codeman identifies itself honestly (it is not the CLI), which
82
+ * the endpoint accepts; the bearer token is the only thing that authenticates.
83
+ */
84
+ export function buildVoiceStreamHeaders(accessToken, appVersion, keyterms = []) {
85
+ const headers = {
86
+ Authorization: `Bearer ${accessToken}`,
87
+ 'User-Agent': `codeman/${appVersion} (voice-bridge)`,
88
+ 'x-app': 'codeman',
89
+ 'anthropic-client-platform': 'codeman_web',
90
+ };
91
+ const sanitized = sanitizeKeyterms(keyterms);
92
+ if (sanitized)
93
+ headers['x-config-keyterms'] = sanitized;
94
+ return headers;
95
+ }
96
+ /**
97
+ * One dictation, upstream. Owns exactly one WebSocket and dies with it: every
98
+ * exit path (error, upstream close, lifetime cap, caller close) funnels through
99
+ * `_teardown()`, which fires `onClose` once and clears both timers.
100
+ */
101
+ export class VoiceStreamRelay {
102
+ opts;
103
+ ws = null;
104
+ keepAlive = null;
105
+ lifetimeTimer = null;
106
+ finalizeTimer = null;
107
+ closed = false;
108
+ finalizing = false;
109
+ /** Latest interim, held so a close/finalize can promote it to final. */
110
+ pendingTranscript = '';
111
+ constructor(opts) {
112
+ this.opts = opts;
113
+ }
114
+ /** Open the upstream socket. Safe to call once; a second call is a no-op. */
115
+ connect() {
116
+ if (this.ws || this.closed)
117
+ return;
118
+ const url = buildVoiceStreamUrl({ language: this.opts.language, keyterms: this.opts.keyterms });
119
+ const ws = new WebSocket(url, {
120
+ headers: buildVoiceStreamHeaders(this.opts.accessToken, this.opts.appVersion, this.opts.keyterms ?? []),
121
+ });
122
+ this.ws = ws;
123
+ ws.on('open', () => {
124
+ // Ping immediately: the gap between upgrade and the browser's first audio
125
+ // frame is long enough (mic permission, worklet boot) for upstream to drop us.
126
+ this.safeSend(KEEPALIVE_FRAME);
127
+ this.keepAlive = setInterval(() => this.safeSend(KEEPALIVE_FRAME), KEEPALIVE_INTERVAL_MS);
128
+ this.lifetimeTimer = setTimeout(() => {
129
+ this.opts.onError('Voice stream reached its maximum length');
130
+ this.close();
131
+ }, MAX_STREAM_MS);
132
+ this.opts.onReady();
133
+ });
134
+ ws.on('message', (raw) => this.handleMessage(String(raw)));
135
+ // An upgrade rejection never reaches 'open', so its status is the only signal
136
+ // that the token was refused rather than the network being down.
137
+ ws.on('unexpected-response', (_req, res) => {
138
+ const status = res.statusCode ?? 0;
139
+ res.resume();
140
+ this.opts.onError(status === 401 || status === 403
141
+ ? 'Claude rejected the voice credentials. Run a Claude session to refresh your login.'
142
+ : `Voice service refused the connection (HTTP ${status})`);
143
+ this.teardown();
144
+ });
145
+ ws.on('error', (err) => {
146
+ if (this.closed)
147
+ return;
148
+ this.opts.onError(`Voice stream error: ${err.message}`);
149
+ });
150
+ ws.on('close', () => {
151
+ this.promotePending();
152
+ this.teardown();
153
+ });
154
+ }
155
+ /** Relay one raw PCM16 frame upstream. Dropped after finalize, as upstream ignores it. */
156
+ sendAudio(chunk) {
157
+ if (this.finalizing || this.closed)
158
+ return;
159
+ if (this.ws?.readyState !== WebSocket.OPEN)
160
+ return;
161
+ this.ws.send(chunk);
162
+ }
163
+ /**
164
+ * Ask upstream for the final transcript. The endpoint frame usually follows
165
+ * within a few hundred ms; the timer is the backstop so a silent upstream still
166
+ * yields whatever interim we already have instead of hanging the caller.
167
+ */
168
+ finalize() {
169
+ if (this.finalizing || this.closed)
170
+ return;
171
+ this.finalizing = true;
172
+ if (this.ws?.readyState !== WebSocket.OPEN) {
173
+ this.promotePending();
174
+ this.close();
175
+ return;
176
+ }
177
+ this.safeSend(CLOSE_STREAM_FRAME);
178
+ this.finalizeTimer = setTimeout(() => {
179
+ this.promotePending();
180
+ this.close();
181
+ }, FINALIZE_TIMEOUT_MS);
182
+ }
183
+ /** Terminal shutdown. Idempotent. */
184
+ close() {
185
+ if (this.closed)
186
+ return;
187
+ const ws = this.ws;
188
+ this.teardown();
189
+ if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
190
+ try {
191
+ ws.close();
192
+ }
193
+ catch {
194
+ /* already closing */
195
+ }
196
+ }
197
+ }
198
+ handleMessage(raw) {
199
+ let msg;
200
+ try {
201
+ msg = JSON.parse(raw);
202
+ }
203
+ catch {
204
+ return;
205
+ }
206
+ switch (msg.type) {
207
+ case 'TranscriptText':
208
+ case 'TranscriptInterim': {
209
+ // Each frame is the whole running transcript, not a delta.
210
+ if (typeof msg.data === 'string' && msg.data) {
211
+ this.pendingTranscript = msg.data;
212
+ this.opts.onTranscript(msg.data, false);
213
+ }
214
+ break;
215
+ }
216
+ case 'TranscriptEndpoint': {
217
+ this.promotePending();
218
+ if (this.finalizing)
219
+ this.close();
220
+ break;
221
+ }
222
+ case 'TranscriptError': {
223
+ this.opts.onError(msg.description || msg.error_code || 'Transcription failed');
224
+ break;
225
+ }
226
+ case 'error': {
227
+ this.opts.onError(msg.message || 'Voice service error');
228
+ break;
229
+ }
230
+ default:
231
+ break;
232
+ }
233
+ }
234
+ /** Emit the held interim as final, exactly once per utterance. */
235
+ promotePending() {
236
+ if (!this.pendingTranscript)
237
+ return;
238
+ const text = this.pendingTranscript;
239
+ this.pendingTranscript = '';
240
+ this.opts.onTranscript(text, true);
241
+ }
242
+ safeSend(frame) {
243
+ if (this.ws?.readyState !== WebSocket.OPEN)
244
+ return;
245
+ try {
246
+ this.ws.send(frame);
247
+ }
248
+ catch {
249
+ /* socket died between the check and the send */
250
+ }
251
+ }
252
+ teardown() {
253
+ if (this.closed)
254
+ return;
255
+ this.closed = true;
256
+ if (this.keepAlive)
257
+ clearInterval(this.keepAlive);
258
+ if (this.lifetimeTimer)
259
+ clearTimeout(this.lifetimeTimer);
260
+ if (this.finalizeTimer)
261
+ clearTimeout(this.finalizeTimer);
262
+ this.keepAlive = null;
263
+ this.lifetimeTimer = null;
264
+ this.finalizeTimer = null;
265
+ this.opts.onClose();
266
+ }
267
+ }
268
+ //# sourceMappingURL=voice-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-stream.js","sourceRoot":"","sources":["../../src/web/voice-stream.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicodeman",
3
- "version": "1.16.2",
3
+ "version": "1.16.4",
4
4
  "description": "Mission control for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
Binary file
Binary file