aicodeman 1.2.1 → 1.3.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 (232) hide show
  1. package/README.md +264 -90
  2. package/dist/attachment-magic.d.ts +13 -0
  3. package/dist/attachment-magic.d.ts.map +1 -1
  4. package/dist/attachment-magic.js +47 -0
  5. package/dist/attachment-magic.js.map +1 -1
  6. package/dist/attachment-registry.d.ts.map +1 -1
  7. package/dist/attachment-registry.js +13 -2
  8. package/dist/attachment-registry.js.map +1 -1
  9. package/dist/config/buffer-limits.d.ts +2 -3
  10. package/dist/config/buffer-limits.d.ts.map +1 -1
  11. package/dist/config/buffer-limits.js +5 -5
  12. package/dist/config/buffer-limits.js.map +1 -1
  13. package/dist/config/map-limits.d.ts +11 -0
  14. package/dist/config/map-limits.d.ts.map +1 -1
  15. package/dist/config/map-limits.js +11 -0
  16. package/dist/config/map-limits.js.map +1 -1
  17. package/dist/config/server-timing.d.ts +6 -0
  18. package/dist/config/server-timing.d.ts.map +1 -1
  19. package/dist/config/server-timing.js +9 -0
  20. package/dist/config/server-timing.js.map +1 -1
  21. package/dist/config/terminal-history.d.ts +30 -0
  22. package/dist/config/terminal-history.d.ts.map +1 -0
  23. package/dist/config/terminal-history.js +43 -0
  24. package/dist/config/terminal-history.js.map +1 -0
  25. package/dist/cron/cron-input.d.ts +30 -0
  26. package/dist/cron/cron-input.d.ts.map +1 -0
  27. package/dist/cron/cron-input.js +7 -0
  28. package/dist/cron/cron-input.js.map +1 -0
  29. package/dist/cron/cron-service.d.ts +92 -0
  30. package/dist/cron/cron-service.d.ts.map +1 -0
  31. package/dist/cron/cron-service.js +606 -0
  32. package/dist/cron/cron-service.js.map +1 -0
  33. package/dist/cron/cron-time.d.ts +29 -0
  34. package/dist/cron/cron-time.d.ts.map +1 -0
  35. package/dist/cron/cron-time.js +87 -0
  36. package/dist/cron/cron-time.js.map +1 -0
  37. package/dist/document-thumbnailer.d.ts +1 -1
  38. package/dist/document-thumbnailer.d.ts.map +1 -1
  39. package/dist/document-thumbnailer.js +11 -2
  40. package/dist/document-thumbnailer.js.map +1 -1
  41. package/dist/generated-artifact-attachments.d.ts +26 -0
  42. package/dist/generated-artifact-attachments.d.ts.map +1 -0
  43. package/dist/generated-artifact-attachments.js +61 -0
  44. package/dist/generated-artifact-attachments.js.map +1 -0
  45. package/dist/index.js +11 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/mux-interface.d.ts +37 -5
  48. package/dist/mux-interface.d.ts.map +1 -1
  49. package/dist/remote-hosts.d.ts +66 -0
  50. package/dist/remote-hosts.d.ts.map +1 -0
  51. package/dist/remote-hosts.js +198 -0
  52. package/dist/remote-hosts.js.map +1 -0
  53. package/dist/services/unified-session-service.d.ts +115 -0
  54. package/dist/services/unified-session-service.d.ts.map +1 -0
  55. package/dist/services/unified-session-service.js +173 -0
  56. package/dist/services/unified-session-service.js.map +1 -0
  57. package/dist/session-cli-builder.d.ts +3 -1
  58. package/dist/session-cli-builder.d.ts.map +1 -1
  59. package/dist/session-cli-builder.js +26 -7
  60. package/dist/session-cli-builder.js.map +1 -1
  61. package/dist/session-pty-exit-breaker.d.ts +66 -0
  62. package/dist/session-pty-exit-breaker.d.ts.map +1 -0
  63. package/dist/session-pty-exit-breaker.js +77 -0
  64. package/dist/session-pty-exit-breaker.js.map +1 -0
  65. package/dist/session.d.ts +27 -1
  66. package/dist/session.d.ts.map +1 -1
  67. package/dist/session.js +102 -11
  68. package/dist/session.js.map +1 -1
  69. package/dist/state-store.d.ts +14 -0
  70. package/dist/state-store.d.ts.map +1 -1
  71. package/dist/state-store.js +49 -0
  72. package/dist/state-store.js.map +1 -1
  73. package/dist/tmux-manager.d.ts +100 -8
  74. package/dist/tmux-manager.d.ts.map +1 -1
  75. package/dist/tmux-manager.js +249 -26
  76. package/dist/tmux-manager.js.map +1 -1
  77. package/dist/types/api.d.ts +11 -0
  78. package/dist/types/api.d.ts.map +1 -1
  79. package/dist/types/api.js.map +1 -1
  80. package/dist/types/app-state.d.ts +5 -0
  81. package/dist/types/app-state.d.ts.map +1 -1
  82. package/dist/types/app-state.js.map +1 -1
  83. package/dist/types/cron.d.ts +88 -0
  84. package/dist/types/cron.d.ts.map +1 -0
  85. package/dist/types/cron.js +13 -0
  86. package/dist/types/cron.js.map +1 -0
  87. package/dist/types/session.d.ts +57 -0
  88. package/dist/types/session.d.ts.map +1 -1
  89. package/dist/types/session.js.map +1 -1
  90. package/dist/web/heic-jpeg-converter.d.ts +24 -0
  91. package/dist/web/heic-jpeg-converter.d.ts.map +1 -0
  92. package/dist/web/heic-jpeg-converter.js +76 -0
  93. package/dist/web/heic-jpeg-converter.js.map +1 -0
  94. package/dist/web/heic-jpeg-worker.d.ts +44 -0
  95. package/dist/web/heic-jpeg-worker.d.ts.map +1 -0
  96. package/dist/web/heic-jpeg-worker.js +78 -0
  97. package/dist/web/heic-jpeg-worker.js.map +1 -0
  98. package/dist/web/ports/config-port.d.ts +2 -0
  99. package/dist/web/ports/config-port.d.ts.map +1 -1
  100. package/dist/web/ports/cron-port.d.ts +9 -0
  101. package/dist/web/ports/cron-port.d.ts.map +1 -0
  102. package/dist/web/ports/cron-port.js +6 -0
  103. package/dist/web/ports/cron-port.js.map +1 -0
  104. package/dist/web/ports/index.d.ts +1 -0
  105. package/dist/web/ports/index.d.ts.map +1 -1
  106. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  107. package/dist/web/public/app.b0534652.js +38 -0
  108. package/dist/web/public/app.b0534652.js.br +0 -0
  109. package/dist/web/public/app.b0534652.js.gz +0 -0
  110. package/dist/web/public/{constants.1c779517.js → constants.5b18ed64.js} +65 -0
  111. package/dist/web/public/constants.5b18ed64.js.br +0 -0
  112. package/dist/web/public/constants.5b18ed64.js.gz +0 -0
  113. package/dist/web/public/cron-ui.js +328 -0
  114. package/dist/web/public/cron-ui.js.br +0 -0
  115. package/dist/web/public/cron-ui.js.gz +0 -0
  116. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  117. package/dist/web/public/index.html +296 -25
  118. package/dist/web/public/index.html.br +0 -0
  119. package/dist/web/public/index.html.gz +0 -0
  120. package/dist/web/public/input-cjk.63794d0b.js +1 -0
  121. package/dist/web/public/input-cjk.63794d0b.js.br +0 -0
  122. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  123. package/dist/web/public/keyboard-accessory.3f91acef.js.gz +0 -0
  124. package/dist/web/public/mobile-handlers.b5a667ef.js.gz +0 -0
  125. package/dist/web/public/mobile.0644e3ac.css +1 -0
  126. package/dist/web/public/mobile.0644e3ac.css.br +0 -0
  127. package/dist/web/public/mobile.0644e3ac.css.gz +0 -0
  128. package/dist/web/public/notification-manager.ca9dc40d.js.gz +0 -0
  129. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  130. package/dist/web/public/{panels-ui.772e92c9.js → panels-ui.ca03853f.js} +25 -17
  131. package/dist/web/public/panels-ui.ca03853f.js.br +0 -0
  132. package/dist/web/public/panels-ui.ca03853f.js.gz +0 -0
  133. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  134. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  135. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  136. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  137. package/dist/web/public/session-ui.b51814ef.js +49 -0
  138. package/dist/web/public/session-ui.b51814ef.js.br +0 -0
  139. package/dist/web/public/session-ui.b51814ef.js.gz +0 -0
  140. package/dist/web/public/settings-ui.6c67c125.js +67 -0
  141. package/dist/web/public/settings-ui.6c67c125.js.br +0 -0
  142. package/dist/web/public/settings-ui.6c67c125.js.gz +0 -0
  143. package/dist/web/public/styles.e1ba7849.css +1 -0
  144. package/dist/web/public/styles.e1ba7849.css.br +0 -0
  145. package/dist/web/public/styles.e1ba7849.css.gz +0 -0
  146. package/dist/web/public/subagent-windows.69b60c35.js.gz +0 -0
  147. package/dist/web/public/sw.js.gz +0 -0
  148. package/dist/web/public/terminal-ui.dbf141fa.js +3 -0
  149. package/dist/web/public/terminal-ui.dbf141fa.js.br +0 -0
  150. package/dist/web/public/terminal-ui.dbf141fa.js.gz +0 -0
  151. package/dist/web/public/ultracode-panel.js.gz +0 -0
  152. package/dist/web/public/ultracode-windows.js.gz +0 -0
  153. package/dist/web/public/upload.html.gz +0 -0
  154. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  155. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  156. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  157. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  158. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  159. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  160. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  161. package/dist/web/public/vendor/xterm.css.gz +0 -0
  162. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  163. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  164. package/dist/web/routes/case-routes.d.ts.map +1 -1
  165. package/dist/web/routes/case-routes.js +115 -1
  166. package/dist/web/routes/case-routes.js.map +1 -1
  167. package/dist/web/routes/cron-routes.d.ts +11 -0
  168. package/dist/web/routes/cron-routes.d.ts.map +1 -0
  169. package/dist/web/routes/cron-routes.js +70 -0
  170. package/dist/web/routes/cron-routes.js.map +1 -0
  171. package/dist/web/routes/index.d.ts +1 -0
  172. package/dist/web/routes/index.d.ts.map +1 -1
  173. package/dist/web/routes/index.js +1 -0
  174. package/dist/web/routes/index.js.map +1 -1
  175. package/dist/web/routes/respawn-routes.d.ts.map +1 -1
  176. package/dist/web/routes/respawn-routes.js +3 -0
  177. package/dist/web/routes/respawn-routes.js.map +1 -1
  178. package/dist/web/routes/session-routes.d.ts.map +1 -1
  179. package/dist/web/routes/session-routes.js +614 -68
  180. package/dist/web/routes/session-routes.js.map +1 -1
  181. package/dist/web/routes/system-routes.d.ts.map +1 -1
  182. package/dist/web/routes/system-routes.js +5 -0
  183. package/dist/web/routes/system-routes.js.map +1 -1
  184. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  185. package/dist/web/routes/ws-routes.js +56 -17
  186. package/dist/web/routes/ws-routes.js.map +1 -1
  187. package/dist/web/schemas.d.ts +117 -0
  188. package/dist/web/schemas.d.ts.map +1 -1
  189. package/dist/web/schemas.js +168 -1
  190. package/dist/web/schemas.js.map +1 -1
  191. package/dist/web/server.d.ts +9 -2
  192. package/dist/web/server.d.ts.map +1 -1
  193. package/dist/web/server.js +82 -13
  194. package/dist/web/server.js.map +1 -1
  195. package/dist/web/session-listener-wiring.d.ts +5 -1
  196. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  197. package/dist/web/session-listener-wiring.js +23 -1
  198. package/dist/web/session-listener-wiring.js.map +1 -1
  199. package/dist/web/sse-events.d.ts +15 -0
  200. package/dist/web/sse-events.d.ts.map +1 -1
  201. package/dist/web/sse-events.js +17 -0
  202. package/dist/web/sse-events.js.map +1 -1
  203. package/dist/web/ws-connection-registry.d.ts +77 -0
  204. package/dist/web/ws-connection-registry.d.ts.map +1 -0
  205. package/dist/web/ws-connection-registry.js +99 -0
  206. package/dist/web/ws-connection-registry.js.map +1 -0
  207. package/package.json +3 -1
  208. package/dist/web/public/app.a8d73c32.js +0 -38
  209. package/dist/web/public/app.a8d73c32.js.br +0 -0
  210. package/dist/web/public/app.a8d73c32.js.gz +0 -0
  211. package/dist/web/public/constants.1c779517.js.br +0 -0
  212. package/dist/web/public/constants.1c779517.js.gz +0 -0
  213. package/dist/web/public/input-cjk.4e950e0a.js +0 -1
  214. package/dist/web/public/input-cjk.4e950e0a.js.br +0 -0
  215. package/dist/web/public/input-cjk.4e950e0a.js.gz +0 -0
  216. package/dist/web/public/mobile.8a9aff7a.css +0 -1
  217. package/dist/web/public/mobile.8a9aff7a.css.br +0 -0
  218. package/dist/web/public/mobile.8a9aff7a.css.gz +0 -0
  219. package/dist/web/public/panels-ui.772e92c9.js.br +0 -0
  220. package/dist/web/public/panels-ui.772e92c9.js.gz +0 -0
  221. package/dist/web/public/session-ui.da3e53f2.js +0 -36
  222. package/dist/web/public/session-ui.da3e53f2.js.br +0 -0
  223. package/dist/web/public/session-ui.da3e53f2.js.gz +0 -0
  224. package/dist/web/public/settings-ui.38feb956.js +0 -61
  225. package/dist/web/public/settings-ui.38feb956.js.br +0 -0
  226. package/dist/web/public/settings-ui.38feb956.js.gz +0 -0
  227. package/dist/web/public/styles.1b3e6147.css +0 -1
  228. package/dist/web/public/styles.1b3e6147.css.br +0 -0
  229. package/dist/web/public/styles.1b3e6147.css.gz +0 -0
  230. package/dist/web/public/terminal-ui.865f21f6.js +0 -3
  231. package/dist/web/public/terminal-ui.865f21f6.js.br +0 -0
  232. package/dist/web/public/terminal-ui.865f21f6.js.gz +0 -0
@@ -0,0 +1,198 @@
1
+ import { existsSync, mkdirSync } from 'node:fs';
2
+ import fs from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { exec } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ const execAsync = promisify(exec);
8
+ const REMOTE_HOSTS_FILE = 'remote-hosts.json';
9
+ const REMOTE_CASES_FILE = 'remote-cases.json';
10
+ export function remoteHostsPath(configDir) {
11
+ return join(configDir, REMOTE_HOSTS_FILE);
12
+ }
13
+ export function remoteCasesPath(configDir) {
14
+ return join(configDir, REMOTE_CASES_FILE);
15
+ }
16
+ async function readJsonArray(path) {
17
+ try {
18
+ const raw = await fs.readFile(path, 'utf-8');
19
+ const parsed = JSON.parse(raw);
20
+ return Array.isArray(parsed) ? parsed : [];
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ }
26
+ async function writeJsonArray(configDir, path, value) {
27
+ if (!existsSync(configDir))
28
+ mkdirSync(configDir, { recursive: true });
29
+ await fs.writeFile(path, JSON.stringify(value, null, 2));
30
+ }
31
+ export async function readRemoteHosts(configDir) {
32
+ return readJsonArray(remoteHostsPath(configDir));
33
+ }
34
+ export async function writeRemoteHosts(configDir, hosts) {
35
+ await writeJsonArray(configDir, remoteHostsPath(configDir), hosts);
36
+ }
37
+ export async function readRemoteCases(configDir) {
38
+ return readJsonArray(remoteCasesPath(configDir));
39
+ }
40
+ export async function writeRemoteCases(configDir, cases) {
41
+ await writeJsonArray(configDir, remoteCasesPath(configDir), cases);
42
+ }
43
+ export function defaultRemoteCommandForMode(mode) {
44
+ const commands = {
45
+ shell: 'exec bash -l',
46
+ // Mirror the LOCAL claude default so the remote agent runs non-interactively
47
+ // (no trust-folder/permission prompt that nothing on the remote answers). The
48
+ // per-host `commands.claude` override stays the escape hatch.
49
+ claude: 'exec claude --dangerously-skip-permissions',
50
+ opencode: 'exec opencode',
51
+ codex: 'exec codex',
52
+ gemini: 'exec gemini',
53
+ };
54
+ return commands[mode] || commands.shell;
55
+ }
56
+ export function remoteSshTarget(host) {
57
+ return `${host.username}@${host.host}`;
58
+ }
59
+ /**
60
+ * POSIX single-quote shell-escaping (end-quote, escaped-quote, restart-quote).
61
+ * Mirrors the helper in tmux-manager.ts so a value with spaces/metachars stays a
62
+ * single shell token. Used here for identity paths and `-o KEY=VALUE` options.
63
+ */
64
+ function shellescape(str) {
65
+ return "'" + str.replace(/'/g, "'\\''") + "'";
66
+ }
67
+ /**
68
+ * Expand a leading `~` or `$HOME` in an identity path to an absolute path.
69
+ *
70
+ * ssh does NOT expand `~` inside `-i` (the shell would, but we shellescape the
71
+ * value into a single quoted token so the shell never sees it). So we expand at
72
+ * build time, before escaping. Non-`~`/`$HOME` paths are returned unchanged.
73
+ */
74
+ function expandIdentityPath(identityFile) {
75
+ if (identityFile === '~')
76
+ return homedir();
77
+ if (identityFile.startsWith('~/'))
78
+ return join(homedir(), identityFile.slice(2));
79
+ if (identityFile === '$HOME')
80
+ return homedir();
81
+ if (identityFile.startsWith('$HOME/'))
82
+ return join(homedir(), identityFile.slice('$HOME/'.length));
83
+ return identityFile;
84
+ }
85
+ /**
86
+ * COD-107 — build the ordered, shell-safe ssh CONNECTION tokens shared by both
87
+ * the durable-launch command (`buildRemoteLaunchCommand`) and the tmux
88
+ * prerequisite probe (`buildRemoteTmuxCheckCommand`), so the prereq check and
89
+ * the real launch connect with IDENTICAL options (they can't drift).
90
+ *
91
+ * Returns the leading tokens of an ssh command line (NOT including `-t`, the
92
+ * target, or any remote command). Order:
93
+ * ssh -o BatchMode=yes
94
+ * [-o ConnectTimeout=10] (default; suppressed if extraSshOptions sets it)
95
+ * [-p <port>]
96
+ * [-i <abs-identity>] (~/$HOME expanded, then shellescaped)
97
+ * [-J <jumpHost>] (shellescaped, single token)
98
+ * [-o ProxyCommand=nc -X 5 -x <socks> %h %p] (ONE shellescaped -o token)
99
+ * [-o <KEY=VALUE>] … (each extra option, shellescaped)
100
+ *
101
+ * Escaping notes (the risky part):
102
+ * - The ProxyCommand is emitted as a single shellescaped `-o KEY=VALUE`, so the
103
+ * whole value (spaces + `%h`/`%p`) reaches ssh as one argument and `%h %p`
104
+ * survive verbatim — ssh expands them to the real host/port, not the shell.
105
+ * - A default `-o ConnectTimeout=10` bounds the wait on an unreachable/blackholed
106
+ * host (else the pane hangs on the OS TCP timeout). It is omitted when the
107
+ * operator already set ConnectTimeout via extraSshOptions, so their value wins.
108
+ */
109
+ export function buildSshConnectionArgs(remote) {
110
+ const parts = ['ssh', '-o BatchMode=yes'];
111
+ const hasConnectTimeout = (remote.extraSshOptions ?? []).some((opt) => /^ConnectTimeout=/i.test(opt));
112
+ if (!hasConnectTimeout)
113
+ parts.push('-o ConnectTimeout=10');
114
+ if (remote.port)
115
+ parts.push(`-p ${remote.port}`);
116
+ if (remote.identityFile)
117
+ parts.push(`-i ${shellescape(expandIdentityPath(remote.identityFile))}`);
118
+ if (remote.jumpHost)
119
+ parts.push(`-J ${shellescape(remote.jumpHost)}`);
120
+ if (remote.socksProxy) {
121
+ parts.push(`-o ${shellescape(`ProxyCommand=nc -X 5 -x ${remote.socksProxy} %h %p`)}`);
122
+ }
123
+ for (const opt of remote.extraSshOptions ?? []) {
124
+ parts.push(`-o ${shellescape(opt)}`);
125
+ }
126
+ return parts;
127
+ }
128
+ /**
129
+ * COD-104 — build the SSH command that checks the remote host has tmux.
130
+ *
131
+ * Durable remote sessions run the agent inside a tmux server ON the remote host
132
+ * (`tmux -L codeman new-session -A …`), so tmux is now a hard prerequisite there.
133
+ * `command -v tmux` exits 0 (and prints the path) when tmux is installed.
134
+ *
135
+ * COD-107 — connects with the SAME options as the real launch
136
+ * (`buildSshConnectionArgs`) so a proxied/custom-port/identity host that the
137
+ * launch can reach also passes the prereq probe (and vice-versa).
138
+ */
139
+ export function buildRemoteTmuxCheckCommand(host) {
140
+ // ConnectTimeout is now a default of buildSshConnectionArgs (shared with the launch).
141
+ return [...buildSshConnectionArgs(host), remoteSshTarget(host), "'command -v tmux'"].join(' ');
142
+ }
143
+ /**
144
+ * COD-104 — verify the remote host has tmux installed (required for durable
145
+ * remote sessions). Returns a structured result with a clear, user-facing error
146
+ * when tmux is missing or the host is unreachable. Never throws.
147
+ */
148
+ export async function checkRemoteTmuxAvailable(host) {
149
+ const command = buildRemoteTmuxCheckCommand(host);
150
+ try {
151
+ const { stdout } = await execAsync(command, { timeout: 15_000 });
152
+ const tmuxPath = stdout.trim();
153
+ if (!tmuxPath) {
154
+ return {
155
+ ok: false,
156
+ error: `remote host ${host.host} needs tmux installed for durable remote sessions`,
157
+ };
158
+ }
159
+ return { ok: true, tmuxPath };
160
+ }
161
+ catch (err) {
162
+ const stderr = err && typeof err === 'object' && 'stderr' in err ? String(err.stderr ?? '') : '';
163
+ // `command -v tmux` exits non-zero when tmux is absent (no stderr); a real
164
+ // connection failure surfaces ssh diagnostics on stderr.
165
+ if (stderr.trim()) {
166
+ return {
167
+ ok: false,
168
+ error: `could not verify tmux on remote host ${host.host}: ${stderr.trim()}`,
169
+ };
170
+ }
171
+ return {
172
+ ok: false,
173
+ error: `remote host ${host.host} needs tmux installed for durable remote sessions`,
174
+ };
175
+ }
176
+ }
177
+ export function remoteDisplayPath(remote) {
178
+ const path = 'remotePath' in remote ? remote.remotePath : remote.path;
179
+ return `${remote.username}@${remote.host}:${path}`;
180
+ }
181
+ export function toSessionRemote(host, remoteCase) {
182
+ return {
183
+ hostId: host.id,
184
+ label: host.label,
185
+ host: host.host,
186
+ username: host.username,
187
+ port: host.port,
188
+ remotePath: remoteCase.remotePath,
189
+ commands: host.commands,
190
+ // COD-107 — carry the advanced SSH options from host config into the session
191
+ // so the launch/prereq commands connect the same way the operator configured.
192
+ identityFile: host.identityFile,
193
+ socksProxy: host.socksProxy,
194
+ jumpHost: host.jumpHost,
195
+ extraSshOptions: host.extraSshOptions,
196
+ };
197
+ }
198
+ //# sourceMappingURL=remote-hosts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-hosts.js","sourceRoot":"","sources":["../src/remote-hosts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @fileoverview Pure merge/filter logic for the unified session list (COD-121).
3
+ *
4
+ * Combines four read-only views of a session — live (in-memory `Session`),
5
+ * persisted (`state.json`), transcript history (`~/.claude/projects`), and the
6
+ * lifecycle audit log — plus mux process stats, into one de-duplicated list
7
+ * keyed by sessionId. Transcript-history rows are keyed by the Claude
8
+ * conversation UUID (the `.jsonl` filename stem), which diverges from the
9
+ * Codeman id for resumed sessions — an alias map (claudeSessionId → Codeman id,
10
+ * built from the live/persisted views) folds them into the owning session item.
11
+ * Higher-precedence sources overwrite scalar fields when present
12
+ * (history < lifecycle < persisted < live), while the `sources` array
13
+ * always accumulates every contributing view. A "meaningfulness floor" drops
14
+ * noise (bare lifecycle/mux-only rows with no name and no first prompt).
15
+ *
16
+ * PURE: no fs/IO and no node imports. All IO happens in the route that feeds
17
+ * this module its inputs, which keeps the merge/sort/filter behavior unit-testable.
18
+ */
19
+ export type UnifiedSessionItem = {
20
+ sessionId: string;
21
+ name?: string;
22
+ mode?: string;
23
+ status?: string;
24
+ isWorking?: boolean;
25
+ workingDir?: string;
26
+ createdAt?: number;
27
+ lastActivityAt?: number;
28
+ claudeSessionId?: string;
29
+ firstPrompt?: string;
30
+ sizeBytes?: number;
31
+ projectKey?: string;
32
+ remote?: boolean;
33
+ sources: string[];
34
+ stats?: {
35
+ memoryMB: number;
36
+ cpuPercent: number;
37
+ };
38
+ };
39
+ /** Live in-memory session view (subset of `Session.toState()`). */
40
+ export type LiveSessionInput = {
41
+ id: string;
42
+ name?: string;
43
+ mode?: string;
44
+ status?: string;
45
+ isWorking?: boolean;
46
+ workingDir?: string;
47
+ createdAt?: number;
48
+ lastActivityAt?: number;
49
+ claudeSessionId?: string;
50
+ };
51
+ /** Persisted session view (subset of `SessionState`). */
52
+ export type PersistedSessionInput = {
53
+ id: string;
54
+ name?: string;
55
+ mode?: string;
56
+ status?: string;
57
+ workingDir?: string;
58
+ createdAt?: number;
59
+ lastActivityAt?: number;
60
+ /** Claude conversation ID this session resumes (`SessionState.resumeSessionId`). */
61
+ claudeSessionId?: string;
62
+ };
63
+ /** Lifecycle audit-log view. Entries are expected NEWEST-first (the order `SessionLifecycleLog.query()` returns). */
64
+ export type LifecycleInput = {
65
+ sessionId: string;
66
+ name?: string;
67
+ mode?: string;
68
+ ts: number;
69
+ event?: string;
70
+ };
71
+ /** Transcript-history view (one `.jsonl` per session). */
72
+ export type HistoryInput = {
73
+ sessionId: string;
74
+ workingDir: string;
75
+ sizeBytes: number;
76
+ lastModified: string;
77
+ firstPrompt?: string;
78
+ projectKey?: string;
79
+ };
80
+ /** Mux process-stat view. */
81
+ export type MuxStatInput = {
82
+ sessionId: string;
83
+ muxName?: string;
84
+ mode?: string;
85
+ stats?: {
86
+ memoryMB: number;
87
+ cpuPercent: number;
88
+ };
89
+ remote?: boolean;
90
+ };
91
+ export type UnifiedSources = {
92
+ live?: LiveSessionInput[];
93
+ persisted?: PersistedSessionInput[];
94
+ lifecycle?: LifecycleInput[];
95
+ history?: HistoryInput[];
96
+ mux?: MuxStatInput[];
97
+ };
98
+ /**
99
+ * Merge all source views into one list, applying precedence
100
+ * (history → lifecycle → persisted → live) and the meaningfulness floor.
101
+ */
102
+ export declare function mergeUnifiedSessions(sources: UnifiedSources): UnifiedSessionItem[];
103
+ /**
104
+ * Case-insensitive substring filter (name + firstPrompt + workingDir + sessionId)
105
+ * with offset/limit paging. `total` is the filtered count BEFORE paging.
106
+ */
107
+ export declare function filterAndPaginate(items: UnifiedSessionItem[], opts: {
108
+ q?: string;
109
+ offset?: number;
110
+ limit?: number;
111
+ }): {
112
+ sessions: UnifiedSessionItem[];
113
+ total: number;
114
+ };
115
+ //# sourceMappingURL=unified-session-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-session-service.d.ts","sourceRoot":"","sources":["../../src/services/unified-session-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * @fileoverview Pure merge/filter logic for the unified session list (COD-121).
3
+ *
4
+ * Combines four read-only views of a session — live (in-memory `Session`),
5
+ * persisted (`state.json`), transcript history (`~/.claude/projects`), and the
6
+ * lifecycle audit log — plus mux process stats, into one de-duplicated list
7
+ * keyed by sessionId. Transcript-history rows are keyed by the Claude
8
+ * conversation UUID (the `.jsonl` filename stem), which diverges from the
9
+ * Codeman id for resumed sessions — an alias map (claudeSessionId → Codeman id,
10
+ * built from the live/persisted views) folds them into the owning session item.
11
+ * Higher-precedence sources overwrite scalar fields when present
12
+ * (history < lifecycle < persisted < live), while the `sources` array
13
+ * always accumulates every contributing view. A "meaningfulness floor" drops
14
+ * noise (bare lifecycle/mux-only rows with no name and no first prompt).
15
+ *
16
+ * PURE: no fs/IO and no node imports. All IO happens in the route that feeds
17
+ * this module its inputs, which keeps the merge/sort/filter behavior unit-testable.
18
+ */
19
+ /** Push a source tag onto an item exactly once. */
20
+ function addSource(item, source) {
21
+ if (!item.sources.includes(source))
22
+ item.sources.push(source);
23
+ }
24
+ /** Get-or-create the accumulator item for a sessionId. */
25
+ function ensureItem(map, sessionId) {
26
+ let item = map.get(sessionId);
27
+ if (!item) {
28
+ item = { sessionId, sources: [] };
29
+ map.set(sessionId, item);
30
+ }
31
+ return item;
32
+ }
33
+ /** Overwrite a scalar field only when the incoming value is defined. */
34
+ function overwrite(item, key, value) {
35
+ if (value !== undefined)
36
+ item[key] = value;
37
+ }
38
+ /**
39
+ * Merge all source views into one list, applying precedence
40
+ * (history → lifecycle → persisted → live) and the meaningfulness floor.
41
+ */
42
+ export function mergeUnifiedSessions(sources) {
43
+ const map = new Map();
44
+ // Alias map: Claude conversation UUID → owning Codeman session id. Resumed
45
+ // (claudeSessionId = resumeSessionId != id) and /clear-respawned sessions
46
+ // would otherwise surface twice — once as a live/persisted row and once as a
47
+ // separate history-only row keyed by the conversation UUID. Live wins over
48
+ // persisted on conflicting entries (registered last).
49
+ const aliasToOwner = new Map();
50
+ for (const p of sources.persisted ?? []) {
51
+ if (p.claudeSessionId !== undefined && p.claudeSessionId !== p.id)
52
+ aliasToOwner.set(p.claudeSessionId, p.id);
53
+ }
54
+ for (const v of sources.live ?? []) {
55
+ if (v.claudeSessionId !== undefined && v.claudeSessionId !== v.id)
56
+ aliasToOwner.set(v.claudeSessionId, v.id);
57
+ }
58
+ const resolveId = (sessionId) => aliasToOwner.get(sessionId) ?? sessionId;
59
+ // 1) history (lowest precedence; keys resolve through the alias map)
60
+ for (const h of sources.history ?? []) {
61
+ const item = ensureItem(map, resolveId(h.sessionId));
62
+ addSource(item, 'history');
63
+ overwrite(item, 'workingDir', h.workingDir);
64
+ overwrite(item, 'sizeBytes', h.sizeBytes);
65
+ overwrite(item, 'firstPrompt', h.firstPrompt);
66
+ overwrite(item, 'projectKey', h.projectKey);
67
+ const ms = Date.parse(h.lastModified);
68
+ if (!Number.isNaN(ms) && item.lastActivityAt === undefined)
69
+ item.lastActivityAt = ms;
70
+ }
71
+ // 2) lifecycle — entries arrive NEWEST-first, so first-seen wins for
72
+ // name/mode (mirrors the lastActivityAt guard); unconditional overwrites
73
+ // would leave the OLDEST entry in the window (stale name/mode) standing.
74
+ for (const l of sources.lifecycle ?? []) {
75
+ const item = ensureItem(map, resolveId(l.sessionId));
76
+ addSource(item, 'lifecycle');
77
+ if (item.name === undefined)
78
+ overwrite(item, 'name', l.name);
79
+ if (item.mode === undefined)
80
+ overwrite(item, 'mode', l.mode);
81
+ if (item.lastActivityAt === undefined && typeof l.ts === 'number')
82
+ item.lastActivityAt = l.ts;
83
+ }
84
+ // 3) persisted
85
+ for (const p of sources.persisted ?? []) {
86
+ const item = ensureItem(map, p.id);
87
+ addSource(item, 'persisted');
88
+ overwrite(item, 'name', p.name);
89
+ overwrite(item, 'mode', p.mode);
90
+ overwrite(item, 'status', p.status);
91
+ overwrite(item, 'workingDir', p.workingDir);
92
+ overwrite(item, 'createdAt', p.createdAt);
93
+ overwrite(item, 'lastActivityAt', p.lastActivityAt);
94
+ }
95
+ // 4) live (highest precedence)
96
+ for (const v of sources.live ?? []) {
97
+ const item = ensureItem(map, v.id);
98
+ addSource(item, 'live');
99
+ overwrite(item, 'name', v.name);
100
+ overwrite(item, 'mode', v.mode);
101
+ overwrite(item, 'status', v.status);
102
+ overwrite(item, 'isWorking', v.isWorking);
103
+ overwrite(item, 'workingDir', v.workingDir);
104
+ overwrite(item, 'createdAt', v.createdAt);
105
+ overwrite(item, 'lastActivityAt', v.lastActivityAt);
106
+ overwrite(item, 'claudeSessionId', v.claudeSessionId);
107
+ }
108
+ // 5) mux stats + remote flag (create item if mux-only)
109
+ for (const m of sources.mux ?? []) {
110
+ const item = ensureItem(map, m.sessionId);
111
+ addSource(item, 'mux');
112
+ overwrite(item, 'mode', m.mode);
113
+ if (m.stats)
114
+ item.stats = m.stats;
115
+ if (m.remote !== undefined)
116
+ item.remote = m.remote;
117
+ }
118
+ // Meaningfulness floor: keep real rows, drop bare lifecycle/mux-only noise.
119
+ const kept = [];
120
+ for (const item of map.values()) {
121
+ const isReal = item.sources.includes('live') ||
122
+ item.sources.includes('persisted') ||
123
+ item.sources.includes('history') ||
124
+ (item.firstPrompt !== undefined && item.firstPrompt !== '');
125
+ if (isReal)
126
+ kept.push(item);
127
+ }
128
+ // Stable sort: lastActivityAt desc (undefined last), createdAt desc, sessionId asc.
129
+ kept.sort((a, b) => {
130
+ const la = a.lastActivityAt;
131
+ const lb = b.lastActivityAt;
132
+ if (la !== lb) {
133
+ if (la === undefined)
134
+ return 1;
135
+ if (lb === undefined)
136
+ return -1;
137
+ return lb - la;
138
+ }
139
+ const ca = a.createdAt;
140
+ const cb = b.createdAt;
141
+ if (ca !== cb) {
142
+ if (ca === undefined)
143
+ return 1;
144
+ if (cb === undefined)
145
+ return -1;
146
+ return cb - ca;
147
+ }
148
+ return a.sessionId < b.sessionId ? -1 : a.sessionId > b.sessionId ? 1 : 0;
149
+ });
150
+ return kept;
151
+ }
152
+ /**
153
+ * Case-insensitive substring filter (name + firstPrompt + workingDir + sessionId)
154
+ * with offset/limit paging. `total` is the filtered count BEFORE paging.
155
+ */
156
+ export function filterAndPaginate(items, opts) {
157
+ const q = (opts.q ?? '').trim().toLowerCase();
158
+ const filtered = q
159
+ ? items.filter((it) => {
160
+ const hay = [it.name, it.firstPrompt, it.workingDir, it.sessionId]
161
+ .filter((v) => typeof v === 'string')
162
+ .join(' ')
163
+ .toLowerCase();
164
+ return hay.includes(q);
165
+ })
166
+ : items;
167
+ const total = filtered.length;
168
+ const offset = Math.max(0, Math.floor(opts.offset ?? 0));
169
+ const limit = Math.min(500, Math.max(1, Math.floor(opts.limit ?? 100)));
170
+ const sessions = filtered.slice(offset, offset + limit);
171
+ return { sessions, total };
172
+ }
173
+ //# sourceMappingURL=unified-session-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-session-service.js","sourceRoot":"","sources":["../../src/services/unified-session-service.ts"],"names":[],"mappings":"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"}
@@ -58,9 +58,11 @@ export declare function buildClaudeEnv(sessionId: string): Record<string, string
58
58
  * Lighter than buildClaudeEnv — no PATH augmentation or Codeman vars needed
59
59
  * since the mux session already has those set.
60
60
  *
61
+ * @param truecolorEnabled - When true, set COLORTERM=truecolor (COD-75 opt-in);
62
+ * otherwise leave COLORTERM unset. Mirrors buildEnvExports() so both paths agree.
61
63
  * @returns Environment variables object for pty.spawn
62
64
  */
63
- export declare function buildMuxAttachEnv(): Record<string, string | undefined>;
65
+ export declare function buildMuxAttachEnv(truecolorEnabled?: boolean): Record<string, string | undefined>;
64
66
  /**
65
67
  * Build environment variables for a direct shell session (non-mux fallback).
66
68
  *
@@ -1 +1 @@
1
- {"version":3,"file":"session-cli-builder.d.ts","sourceRoot":"","sources":["../src/session-cli-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyB1D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,CAGjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,MAAM,EAAE,CAKV;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAOxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAgBpF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAStE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAYnF"}
1
+ {"version":3,"file":"session-cli-builder.d.ts","sourceRoot":"","sources":["../src/session-cli-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyB1D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,CAGjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,MAAM,EAAE,CAKV;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAOxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAmBpF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAsBhG;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAYnF"}
@@ -91,14 +91,12 @@ export function buildPromptArgs(prompt, model) {
91
91
  * @returns Environment variables object for pty.spawn
92
92
  */
93
93
  export function buildClaudeEnv(sessionId) {
94
- return {
94
+ const env = {
95
95
  ...process.env,
96
96
  LANG: 'en_US.UTF-8',
97
97
  LC_ALL: 'en_US.UTF-8',
98
98
  PATH: getAugmentedPath(),
99
99
  TERM: 'xterm-256color',
100
- COLORTERM: undefined,
101
- CLAUDECODE: undefined,
102
100
  // Inform Claude it's running within Codeman (helps prevent self-termination)
103
101
  CODEMAN_MUX: '1',
104
102
  CODEMAN_SESSION_ID: sessionId,
@@ -106,23 +104,44 @@ export function buildClaudeEnv(sessionId) {
106
104
  // Path only (not the secret value) — hook curls cat it at execution time (COD-54)
107
105
  CODEMAN_HOOK_SECRET_FILE: dataPath('hook-secret'),
108
106
  };
107
+ // COD-115: `delete`, not `= undefined` — node-pty serializes a present-with-undefined
108
+ // key as the literal string "KEY=undefined" (see buildMuxAttachEnv below).
109
+ delete env.COLORTERM;
110
+ delete env.CLAUDECODE;
111
+ return env;
109
112
  }
110
113
  /**
111
114
  * Build environment variables for mux-attached PTY sessions (tmux attach).
112
115
  * Lighter than buildClaudeEnv — no PATH augmentation or Codeman vars needed
113
116
  * since the mux session already has those set.
114
117
  *
118
+ * @param truecolorEnabled - When true, set COLORTERM=truecolor (COD-75 opt-in);
119
+ * otherwise leave COLORTERM unset. Mirrors buildEnvExports() so both paths agree.
115
120
  * @returns Environment variables object for pty.spawn
116
121
  */
117
- export function buildMuxAttachEnv() {
118
- return {
122
+ export function buildMuxAttachEnv(truecolorEnabled) {
123
+ const env = {
119
124
  ...process.env,
120
125
  LANG: 'en_US.UTF-8',
121
126
  LC_ALL: 'en_US.UTF-8',
122
127
  TERM: 'xterm-256color',
123
- COLORTERM: undefined,
124
- CLAUDECODE: undefined,
125
128
  };
129
+ // COD-115: keys to UNSET must be `delete`d, NOT set to `undefined`. On a
130
+ // `{...process.env}` spread the key stays present with value undefined, and node-pty
131
+ // serializes it as the literal string "TMUX=undefined" — a non-empty value that still
132
+ // trips tmux's nesting guard, killing the attach-bridge PTY (exit 1 → respawn loop).
133
+ // The server can be launched from inside tmux; attach clients must never inherit that
134
+ // parent tmux context. (Same fix the working create path uses in tmux-manager.ts.)
135
+ delete env.TMUX;
136
+ delete env.TMUX_PANE;
137
+ delete env.CLAUDECODE;
138
+ if (truecolorEnabled) {
139
+ env.COLORTERM = 'truecolor';
140
+ }
141
+ else {
142
+ delete env.COLORTERM; // COD-75: unset for non-truecolor (was `: undefined`, same node-pty quirk)
143
+ }
144
+ return env;
126
145
  }
127
146
  /**
128
147
  * Build environment variables for a direct shell session (non-mux fallback).
@@ -1 +1 @@
1
- {"version":3,"file":"session-cli-builder.js","sourceRoot":"","sources":["../src/session-cli-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-cli-builder.js","sourceRoot":"","sources":["../src/session-cli-builder.ts"],"names":[],"mappings":"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"}