aicodeman 1.28.1 → 1.29.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 (234) hide show
  1. package/README.md +2 -1
  2. package/README.zh-CN.md +1 -0
  3. package/dist/attachment-registry.d.ts +20 -0
  4. package/dist/attachment-registry.d.ts.map +1 -1
  5. package/dist/attachment-registry.js +75 -10
  6. package/dist/attachment-registry.js.map +1 -1
  7. package/dist/config/cli-registry/schema.d.ts +29 -0
  8. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  9. package/dist/config/cli-registry/schema.js +50 -0
  10. package/dist/config/cli-registry/schema.js.map +1 -1
  11. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  12. package/dist/config/cli-registry/stock.js +165 -2
  13. package/dist/config/cli-registry/stock.js.map +1 -1
  14. package/dist/config/cli-registry/types.d.ts +79 -0
  15. package/dist/config/cli-registry/types.d.ts.map +1 -1
  16. package/dist/custom-model-hosts.d.ts +39 -0
  17. package/dist/custom-model-hosts.d.ts.map +1 -0
  18. package/dist/custom-model-hosts.js +35 -0
  19. package/dist/custom-model-hosts.js.map +1 -0
  20. package/dist/custom-model-injection-apply.d.ts +49 -0
  21. package/dist/custom-model-injection-apply.d.ts.map +1 -0
  22. package/dist/custom-model-injection-apply.js +77 -0
  23. package/dist/custom-model-injection-apply.js.map +1 -0
  24. package/dist/custom-model-injection.d.ts +79 -0
  25. package/dist/custom-model-injection.d.ts.map +1 -0
  26. package/dist/custom-model-injection.js +169 -0
  27. package/dist/custom-model-injection.js.map +1 -0
  28. package/dist/docker-hosts.d.ts +64 -1
  29. package/dist/docker-hosts.d.ts.map +1 -1
  30. package/dist/docker-hosts.js +75 -3
  31. package/dist/docker-hosts.js.map +1 -1
  32. package/dist/generated-artifact-attachments.d.ts +3 -0
  33. package/dist/generated-artifact-attachments.d.ts.map +1 -1
  34. package/dist/generated-artifact-attachments.js +18 -8
  35. package/dist/generated-artifact-attachments.js.map +1 -1
  36. package/dist/hooks-config.d.ts +93 -0
  37. package/dist/hooks-config.d.ts.map +1 -1
  38. package/dist/hooks-config.js +211 -6
  39. package/dist/hooks-config.js.map +1 -1
  40. package/dist/mux-interface.d.ts +7 -0
  41. package/dist/mux-interface.d.ts.map +1 -1
  42. package/dist/remote-files.d.ts +145 -0
  43. package/dist/remote-files.d.ts.map +1 -0
  44. package/dist/remote-files.js +347 -0
  45. package/dist/remote-files.js.map +1 -0
  46. package/dist/remote-hosts.d.ts +12 -0
  47. package/dist/remote-hosts.d.ts.map +1 -1
  48. package/dist/remote-hosts.js +7 -1
  49. package/dist/remote-hosts.js.map +1 -1
  50. package/dist/remote-ssh-limiter.d.ts +42 -0
  51. package/dist/remote-ssh-limiter.d.ts.map +1 -0
  52. package/dist/remote-ssh-limiter.js +84 -0
  53. package/dist/remote-ssh-limiter.js.map +1 -0
  54. package/dist/session-cli-registry-bridge.d.ts +8 -0
  55. package/dist/session-cli-registry-bridge.d.ts.map +1 -1
  56. package/dist/session-cli-registry-bridge.js +14 -3
  57. package/dist/session-cli-registry-bridge.js.map +1 -1
  58. package/dist/session-manager.d.ts.map +1 -1
  59. package/dist/session-manager.js +8 -1
  60. package/dist/session-manager.js.map +1 -1
  61. package/dist/session.d.ts +79 -2
  62. package/dist/session.d.ts.map +1 -1
  63. package/dist/session.js +169 -3
  64. package/dist/session.js.map +1 -1
  65. package/dist/tmux-manager.d.ts +21 -0
  66. package/dist/tmux-manager.d.ts.map +1 -1
  67. package/dist/tmux-manager.js +80 -13
  68. package/dist/tmux-manager.js.map +1 -1
  69. package/dist/types/api.d.ts +6 -0
  70. package/dist/types/api.d.ts.map +1 -1
  71. package/dist/types/api.js.map +1 -1
  72. package/dist/types/session.d.ts +30 -0
  73. package/dist/types/session.d.ts.map +1 -1
  74. package/dist/types/session.js.map +1 -1
  75. package/dist/usage-telemetry.d.ts +4 -1
  76. package/dist/usage-telemetry.d.ts.map +1 -1
  77. package/dist/usage-telemetry.js +6 -3
  78. package/dist/usage-telemetry.js.map +1 -1
  79. package/dist/web/middleware/auth.d.ts +11 -1
  80. package/dist/web/middleware/auth.d.ts.map +1 -1
  81. package/dist/web/middleware/auth.js +69 -1
  82. package/dist/web/middleware/auth.js.map +1 -1
  83. package/dist/web/public/admin-ui.js.gz +0 -0
  84. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  85. package/dist/web/public/{app.78bf0bf8.js → app.556be563.js} +7 -7
  86. package/dist/web/public/app.556be563.js.br +0 -0
  87. package/dist/web/public/app.556be563.js.gz +0 -0
  88. package/dist/web/public/approvals-ui.js.gz +0 -0
  89. package/dist/web/public/{constants.9cd8ed69.js → constants.258b140f.js} +50 -0
  90. package/dist/web/public/constants.258b140f.js.br +0 -0
  91. package/dist/web/public/constants.258b140f.js.gz +0 -0
  92. package/dist/web/public/cron-ui.js.gz +0 -0
  93. package/dist/web/public/entrance-animations.js.gz +0 -0
  94. package/dist/web/public/home-sessions.js.gz +0 -0
  95. package/dist/web/public/i18n.561ca09c.js +1 -0
  96. package/dist/web/public/i18n.561ca09c.js.br +0 -0
  97. package/dist/web/public/i18n.561ca09c.js.gz +0 -0
  98. package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
  99. package/dist/web/public/index.html +59 -16
  100. package/dist/web/public/index.html.br +0 -0
  101. package/dist/web/public/index.html.gz +0 -0
  102. package/dist/web/public/input-cjk.8bc46081.js +1 -0
  103. package/dist/web/public/input-cjk.8bc46081.js.br +0 -0
  104. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  105. package/dist/web/public/{keyboard-accessory.1d0dda9b.js → keyboard-accessory.2cf04f17.js} +38 -3
  106. package/dist/web/public/keyboard-accessory.2cf04f17.js.br +0 -0
  107. package/dist/web/public/keyboard-accessory.2cf04f17.js.gz +0 -0
  108. package/dist/web/public/{mobile-handlers.2e9c214a.js → mobile-handlers.6f354a87.js} +61 -13
  109. package/dist/web/public/mobile-handlers.6f354a87.js.br +0 -0
  110. package/dist/web/public/mobile-handlers.6f354a87.js.gz +0 -0
  111. package/dist/web/public/mobile-overview.js +2 -2
  112. package/dist/web/public/mobile-overview.js.br +0 -0
  113. package/dist/web/public/mobile-overview.js.gz +0 -0
  114. package/dist/web/public/{mobile.65176832.css → mobile.e9d0b53e.css} +1 -1
  115. package/dist/web/public/mobile.e9d0b53e.css.br +0 -0
  116. package/dist/web/public/mobile.e9d0b53e.css.gz +0 -0
  117. package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
  118. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  119. package/dist/web/public/{panels-ui.4e9ea307.js → panels-ui.5b07ad14.js} +77 -77
  120. package/dist/web/public/panels-ui.5b07ad14.js.br +0 -0
  121. package/dist/web/public/panels-ui.5b07ad14.js.gz +0 -0
  122. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  123. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  124. package/dist/web/public/readmymind-ui.js.gz +0 -0
  125. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  126. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  127. package/dist/web/public/session-lineage.js.gz +0 -0
  128. package/dist/web/public/session-ui.42b81477.js +77 -0
  129. package/dist/web/public/session-ui.42b81477.js.br +0 -0
  130. package/dist/web/public/session-ui.42b81477.js.gz +0 -0
  131. package/dist/web/public/settings-ui.e0c7f6b4.js +67 -0
  132. package/dist/web/public/settings-ui.e0c7f6b4.js.br +0 -0
  133. package/dist/web/public/settings-ui.e0c7f6b4.js.gz +0 -0
  134. package/dist/web/public/{styles.8ecf20cf.css → styles.6add175d.css} +1 -1
  135. package/dist/web/public/styles.6add175d.css.br +0 -0
  136. package/dist/web/public/styles.6add175d.css.gz +0 -0
  137. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  138. package/dist/web/public/sw.js.gz +0 -0
  139. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  140. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
  141. package/dist/web/public/terminal-ui.38c49244.js +2 -0
  142. package/dist/web/public/terminal-ui.38c49244.js.br +0 -0
  143. package/dist/web/public/terminal-ui.38c49244.js.gz +0 -0
  144. package/dist/web/public/ultracode-panel.js.gz +0 -0
  145. package/dist/web/public/ultracode-windows.js.gz +0 -0
  146. package/dist/web/public/upload.html.gz +0 -0
  147. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  148. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  149. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  150. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  151. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  152. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  153. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  154. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  155. package/dist/web/public/vendor/xterm.css.gz +0 -0
  156. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  157. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
  158. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  159. package/dist/web/public/webview-tabs.js +56 -4
  160. package/dist/web/public/webview-tabs.js.br +0 -0
  161. package/dist/web/public/webview-tabs.js.gz +0 -0
  162. package/dist/web/route-helpers.d.ts +20 -0
  163. package/dist/web/route-helpers.d.ts.map +1 -1
  164. package/dist/web/route-helpers.js +29 -2
  165. package/dist/web/route-helpers.js.map +1 -1
  166. package/dist/web/routes/case-routes.d.ts.map +1 -1
  167. package/dist/web/routes/case-routes.js +23 -6
  168. package/dist/web/routes/case-routes.js.map +1 -1
  169. package/dist/web/routes/custom-model-routes.d.ts +18 -0
  170. package/dist/web/routes/custom-model-routes.d.ts.map +1 -0
  171. package/dist/web/routes/custom-model-routes.js +136 -0
  172. package/dist/web/routes/custom-model-routes.js.map +1 -0
  173. package/dist/web/routes/file-routes.d.ts.map +1 -1
  174. package/dist/web/routes/file-routes.js +484 -100
  175. package/dist/web/routes/file-routes.js.map +1 -1
  176. package/dist/web/routes/index.d.ts +1 -0
  177. package/dist/web/routes/index.d.ts.map +1 -1
  178. package/dist/web/routes/index.js +1 -0
  179. package/dist/web/routes/index.js.map +1 -1
  180. package/dist/web/routes/session-routes.d.ts.map +1 -1
  181. package/dist/web/routes/session-routes.js +95 -23
  182. package/dist/web/routes/session-routes.js.map +1 -1
  183. package/dist/web/routes/status-telemetry-routes.d.ts +3 -2
  184. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  185. package/dist/web/routes/status-telemetry-routes.js +6 -4
  186. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  187. package/dist/web/routes/system-routes.d.ts.map +1 -1
  188. package/dist/web/routes/system-routes.js +32 -22
  189. package/dist/web/routes/system-routes.js.map +1 -1
  190. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  191. package/dist/web/routes/ws-routes.js +26 -2
  192. package/dist/web/routes/ws-routes.js.map +1 -1
  193. package/dist/web/schemas.d.ts +20 -2
  194. package/dist/web/schemas.d.ts.map +1 -1
  195. package/dist/web/schemas.js +37 -8
  196. package/dist/web/schemas.js.map +1 -1
  197. package/dist/web/server.d.ts +8 -0
  198. package/dist/web/server.d.ts.map +1 -1
  199. package/dist/web/server.js +69 -4
  200. package/dist/web/server.js.map +1 -1
  201. package/dist/web/webview-proxy.d.ts +41 -0
  202. package/dist/web/webview-proxy.d.ts.map +1 -1
  203. package/dist/web/webview-proxy.js +102 -1
  204. package/dist/web/webview-proxy.js.map +1 -1
  205. package/package.json +10 -9
  206. package/dist/web/public/app.78bf0bf8.js.br +0 -0
  207. package/dist/web/public/app.78bf0bf8.js.gz +0 -0
  208. package/dist/web/public/constants.9cd8ed69.js.br +0 -0
  209. package/dist/web/public/constants.9cd8ed69.js.gz +0 -0
  210. package/dist/web/public/i18n.9db8c4e0.js +0 -1
  211. package/dist/web/public/i18n.9db8c4e0.js.br +0 -0
  212. package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
  213. package/dist/web/public/input-cjk.87f14251.js +0 -1
  214. package/dist/web/public/input-cjk.87f14251.js.br +0 -0
  215. package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
  216. package/dist/web/public/keyboard-accessory.1d0dda9b.js.br +0 -0
  217. package/dist/web/public/keyboard-accessory.1d0dda9b.js.gz +0 -0
  218. package/dist/web/public/mobile-handlers.2e9c214a.js.br +0 -0
  219. package/dist/web/public/mobile-handlers.2e9c214a.js.gz +0 -0
  220. package/dist/web/public/mobile.65176832.css.br +0 -0
  221. package/dist/web/public/mobile.65176832.css.gz +0 -0
  222. package/dist/web/public/panels-ui.4e9ea307.js.br +0 -0
  223. package/dist/web/public/panels-ui.4e9ea307.js.gz +0 -0
  224. package/dist/web/public/session-ui.cd222710.js +0 -77
  225. package/dist/web/public/session-ui.cd222710.js.br +0 -0
  226. package/dist/web/public/session-ui.cd222710.js.gz +0 -0
  227. package/dist/web/public/settings-ui.c175db9a.js +0 -67
  228. package/dist/web/public/settings-ui.c175db9a.js.br +0 -0
  229. package/dist/web/public/settings-ui.c175db9a.js.gz +0 -0
  230. package/dist/web/public/styles.8ecf20cf.css.br +0 -0
  231. package/dist/web/public/styles.8ecf20cf.css.gz +0 -0
  232. package/dist/web/public/terminal-ui.89e4eb1a.js +0 -2
  233. package/dist/web/public/terminal-ui.89e4eb1a.js.br +0 -0
  234. package/dist/web/public/terminal-ui.89e4eb1a.js.gz +0 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @fileoverview The one IO wrapper around `custom-model-injection.ts`'s pure
3
+ * `ConfigDirInjection` output — deliberately split out so that file, the
4
+ * discovery routes, and `scripts/test-local-llm-harnesses.ts` (via tsx) can
5
+ * all share EXACTLY one "write these files, merge this env" implementation.
6
+ * Before this existed, the route and the standalone script each carried
7
+ * their own copy of this logic, which is exactly the kind of drift the CLI
8
+ * registry's "declare once, consume everywhere" design exists to prevent —
9
+ * see docs/custom-model-endpoints-plan.md and the "dynamic to support
10
+ * cli-registry changes" requirement it was written against.
11
+ */
12
+ import type { CliEntry } from './config/cli-registry/types.js';
13
+ import { type ConfigDirInjection, type CustomModelEndpoint } from './custom-model-injection.js';
14
+ /** Where a session's isolated `configDir`-kind files live: never the user's real CLI config path. */
15
+ export declare function customModelConfigDir(sessionId: string): string;
16
+ /**
17
+ * Writes a `ConfigDirInjection`'s files under `baseDir` and returns the full
18
+ * envOverrides object a caller should merge into the session/process env
19
+ * (the dir-redirect var plus any `extraEnv` the config file references by
20
+ * name). Never touches anything outside `baseDir` — the caller is
21
+ * responsible for choosing an isolated directory (never the user's real
22
+ * `~/.codex`, `~/.pi`, etc.).
23
+ *
24
+ * pi and omp embed the API key literally in the file, so the tree is written
25
+ * 0700/0600 like every other secret-bearing file under `~/.codeman`; the chmod
26
+ * covers a re-apply onto a file that already exists (`mode` only applies at
27
+ * creation).
28
+ */
29
+ export declare function applyConfigDirInjection(baseDir: string, injection: ConfigDirInjection): Record<string, string>;
30
+ /** Best-effort recursive removal of a previously-written configDir. Never throws. */
31
+ export declare function removeConfigDir(dir: string | undefined): void;
32
+ /** What applying an endpoint to a session yields, ready for `Session.setCustomModel()`. */
33
+ export interface AppliedCustomModel {
34
+ envOverrides: Record<string, string>;
35
+ envKeys: string[];
36
+ configDir?: string;
37
+ launchModel?: string;
38
+ }
39
+ /**
40
+ * Compute (and for the `configDir` kind, write) everything a session needs to run
41
+ * against `endpoint`/`modelId`. Returns undefined for a CLI with no mechanism.
42
+ *
43
+ * Idempotent on purpose: the boot-recovery path calls it again for a session that
44
+ * was already pointed at an endpoint, so the config files are rewritten in place
45
+ * (same content) and the env values, which are never persisted because they carry
46
+ * the API key, are re-derived from the endpoint store instead.
47
+ */
48
+ export declare function applyCustomModelInjection(entry: Pick<CliEntry, 'capabilities'>, endpoint: CustomModelEndpoint, modelId: string, sessionId: string): AppliedCustomModel | undefined;
49
+ //# sourceMappingURL=custom-model-injection-apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-model-injection-apply.d.ts","sourceRoot":"","sources":["../src/custom-model-injection-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,6BAA6B,CAAC;AAErC,qGAAqG;AACrG,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ9G;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAO7D;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,EACrC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,kBAAkB,GAAG,SAAS,CAahC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview The one IO wrapper around `custom-model-injection.ts`'s pure
3
+ * `ConfigDirInjection` output — deliberately split out so that file, the
4
+ * discovery routes, and `scripts/test-local-llm-harnesses.ts` (via tsx) can
5
+ * all share EXACTLY one "write these files, merge this env" implementation.
6
+ * Before this existed, the route and the standalone script each carried
7
+ * their own copy of this logic, which is exactly the kind of drift the CLI
8
+ * registry's "declare once, consume everywhere" design exists to prevent —
9
+ * see docs/custom-model-endpoints-plan.md and the "dynamic to support
10
+ * cli-registry changes" requirement it was written against.
11
+ */
12
+ import { chmodSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
13
+ import { join, dirname } from 'node:path';
14
+ import { dataPath } from './config/instance.js';
15
+ import { buildCustomModelInjection, } from './custom-model-injection.js';
16
+ /** Where a session's isolated `configDir`-kind files live: never the user's real CLI config path. */
17
+ export function customModelConfigDir(sessionId) {
18
+ return join(dataPath('custom-model-configs'), sessionId);
19
+ }
20
+ /**
21
+ * Writes a `ConfigDirInjection`'s files under `baseDir` and returns the full
22
+ * envOverrides object a caller should merge into the session/process env
23
+ * (the dir-redirect var plus any `extraEnv` the config file references by
24
+ * name). Never touches anything outside `baseDir` — the caller is
25
+ * responsible for choosing an isolated directory (never the user's real
26
+ * `~/.codex`, `~/.pi`, etc.).
27
+ *
28
+ * pi and omp embed the API key literally in the file, so the tree is written
29
+ * 0700/0600 like every other secret-bearing file under `~/.codeman`; the chmod
30
+ * covers a re-apply onto a file that already exists (`mode` only applies at
31
+ * creation).
32
+ */
33
+ export function applyConfigDirInjection(baseDir, injection) {
34
+ for (const file of injection.files) {
35
+ const filePath = join(baseDir, file.relPath);
36
+ mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });
37
+ writeFileSync(filePath, file.content, { encoding: 'utf8', mode: 0o600 });
38
+ chmodSync(filePath, 0o600);
39
+ }
40
+ return { [injection.dirEnvVar]: baseDir, ...injection.extraEnv };
41
+ }
42
+ /** Best-effort recursive removal of a previously-written configDir. Never throws. */
43
+ export function removeConfigDir(dir) {
44
+ if (!dir)
45
+ return;
46
+ try {
47
+ rmSync(dir, { recursive: true, force: true });
48
+ }
49
+ catch {
50
+ // best-effort cleanup only
51
+ }
52
+ }
53
+ /**
54
+ * Compute (and for the `configDir` kind, write) everything a session needs to run
55
+ * against `endpoint`/`modelId`. Returns undefined for a CLI with no mechanism.
56
+ *
57
+ * Idempotent on purpose: the boot-recovery path calls it again for a session that
58
+ * was already pointed at an endpoint, so the config files are rewritten in place
59
+ * (same content) and the env values, which are never persisted because they carry
60
+ * the API key, are re-derived from the endpoint store instead.
61
+ */
62
+ export function applyCustomModelInjection(entry, endpoint, modelId, sessionId) {
63
+ const injection = buildCustomModelInjection(entry, endpoint, modelId);
64
+ if (injection.kind === 'unsupported')
65
+ return undefined;
66
+ if (injection.kind === 'env') {
67
+ return {
68
+ envOverrides: injection.envOverrides,
69
+ envKeys: Object.keys(injection.envOverrides),
70
+ launchModel: injection.launchModel,
71
+ };
72
+ }
73
+ const configDir = customModelConfigDir(sessionId);
74
+ const envOverrides = applyConfigDirInjection(configDir, injection);
75
+ return { envOverrides, envKeys: Object.keys(envOverrides), configDir, launchModel: injection.launchModel };
76
+ }
77
+ //# sourceMappingURL=custom-model-injection-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-model-injection-apply.js","sourceRoot":"","sources":["../src/custom-model-injection-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EACL,yBAAyB,GAG1B,MAAM,6BAA6B,CAAC;AAErC,qGAAqG;AACrG,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,SAA6B;IACpF,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/D,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;AACnE,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,GAAuB;IACrD,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;AACH,CAAC;AAUD;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAqC,EACrC,QAA6B,EAC7B,OAAe,EACf,SAAiB;IAEjB,MAAM,SAAS,GAAG,yBAAyB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtE,IAAI,SAAS,CAAC,IAAI,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IACvD,IAAI,SAAS,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7B,OAAO;YACL,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;YAC5C,WAAW,EAAE,SAAS,CAAC,WAAW;SACnC,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,uBAAuB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @fileoverview Pure builder for the Custom Model Endpoint Profiles feature
3
+ * (docs/custom-model-endpoints-plan.md): turns a CLI registry entry's
4
+ * `capabilities.customModelInjection` declaration, a configured endpoint,
5
+ * and a chosen model id into the concrete env vars / config-file content
6
+ * that would redirect that CLI's session at the endpoint.
7
+ *
8
+ * No IO here on purpose (mirrors `session-cli-builder.ts`) — a caller
9
+ * writes `ConfigDirInjection.files` to disk under an isolated per-session
10
+ * directory and points `dirEnvVar` at it; this module only computes what
11
+ * those files/env vars should contain.
12
+ *
13
+ * Confidence: `claude` and `opencode` are verified end-to-end against a real
14
+ * llama-swap server (a real "hello world" reply came back). `codex`'s
15
+ * config.toml STRUCTURE is now verified (an earlier `[model].default` table
16
+ * shape was rejected by a real codex binary with "invalid type: map,
17
+ * expected a string" — caught by `scripts/test-local-llm-harnesses.ts`),
18
+ * but `wire_api = "responses"` is the only value codex still accepts
19
+ * (support for `"chat"` was dropped in Feb 2026), and a plain OpenAI
20
+ * Chat-Completions server (llama.cpp, llama-swap, most local setups) does
21
+ * NOT implement the Responses API — so codex may still fail at the
22
+ * PROTOCOL level even with a correctly-shaped config file. That gap is
23
+ * real and current, not a stale warning; see docs/custom-model-endpoints-plan.md. The rest
24
+ * (gemini/pi/grok/deepseek/omp) have their ONE-SHOT INVOCATION flags
25
+ * confirmed against real installed binaries' own `--help` output, but
26
+ * their custom-endpoint env/config conventions remain web-researched,
27
+ * unverified.
28
+ */
29
+ import type { CliEntry } from './config/cli-registry/types.js';
30
+ export interface CustomModelEndpoint {
31
+ id: string;
32
+ label: string;
33
+ /** Root URL, no trailing slash required — e.g. "http://192.168.1.50:8080" or an Azure AI Foundry URL. */
34
+ baseUrl: string;
35
+ /** Falls back to a harmless placeholder for endpoints (llama.cpp) that don't check it. */
36
+ apiKey?: string;
37
+ }
38
+ export interface EnvInjection {
39
+ kind: 'env';
40
+ /** Ready to merge into a session's envOverrides. */
41
+ envOverrides: Record<string, string>;
42
+ /** See {@link ConfigDirInjection.launchModel}. */
43
+ launchModel?: string;
44
+ }
45
+ export interface ConfigDirInjection {
46
+ kind: 'configDir';
47
+ /** Env var that must be set to the directory the caller writes `files` under. */
48
+ dirEnvVar: string;
49
+ files: Array<{
50
+ relPath: string;
51
+ content: string;
52
+ }>;
53
+ /**
54
+ * Env vars the written config file REFERENCES by name rather than embedding a
55
+ * literal value (codex's `env_key = "..."` convention: config.toml never carries
56
+ * the API key itself, only the name of an env var codex reads it from). Merge
57
+ * these into the session's envOverrides alongside `dirEnvVar` — never skip them,
58
+ * or the config points at a credential that was never actually set.
59
+ */
60
+ extraEnv?: Record<string, string>;
61
+ /**
62
+ * The value the CLI's `model` launch param must carry for it to SELECT the injected
63
+ * provider (pi/omp: `custom/<modelId>`; grok: the `[model.<name>]` block name). Absent
64
+ * when the config alone selects the model. Rendered from the registry entry's
65
+ * `customModelInjection.launchModel` template, never hand-built per CLI.
66
+ */
67
+ launchModel?: string;
68
+ }
69
+ export interface UnsupportedInjection {
70
+ kind: 'unsupported';
71
+ }
72
+ export type CustomModelInjectionResult = EnvInjection | ConfigDirInjection | UnsupportedInjection;
73
+ /** Normalizes a base URL to end in exactly one trailing `/v1`, for CLIs whose config expects the OpenAI-style suffix. */
74
+ export declare function withV1Suffix(baseUrl: string): string;
75
+ export declare function buildCustomModelInjection(entry: Pick<CliEntry, 'capabilities'>, endpoint: CustomModelEndpoint, modelId: string): CustomModelInjectionResult;
76
+ /** The `[model.<name>]` block name grok's config.toml uses for the injected model — also
77
+ * what `-m <name>` in the standalone script's ONE_SHOT argv must reference to select it. */
78
+ export declare const GROK_CUSTOM_MODEL_NAME = "codeman-custom";
79
+ //# sourceMappingURL=custom-model-injection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-model-injection.d.ts","sourceRoot":"","sources":["../src/custom-model-injection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,yGAAyG;IACzG,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,KAAK,CAAC;IACZ,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,MAAM,0BAA0B,GAAG,YAAY,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAIlG,yHAAyH;AACzH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD;AAOD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,EACrC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,MAAM,GACd,0BAA0B,CA+B5B;AAmCD;6FAC6F;AAC7F,eAAO,MAAM,sBAAsB,mBAAmB,CAAC"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @fileoverview Pure builder for the Custom Model Endpoint Profiles feature
3
+ * (docs/custom-model-endpoints-plan.md): turns a CLI registry entry's
4
+ * `capabilities.customModelInjection` declaration, a configured endpoint,
5
+ * and a chosen model id into the concrete env vars / config-file content
6
+ * that would redirect that CLI's session at the endpoint.
7
+ *
8
+ * No IO here on purpose (mirrors `session-cli-builder.ts`) — a caller
9
+ * writes `ConfigDirInjection.files` to disk under an isolated per-session
10
+ * directory and points `dirEnvVar` at it; this module only computes what
11
+ * those files/env vars should contain.
12
+ *
13
+ * Confidence: `claude` and `opencode` are verified end-to-end against a real
14
+ * llama-swap server (a real "hello world" reply came back). `codex`'s
15
+ * config.toml STRUCTURE is now verified (an earlier `[model].default` table
16
+ * shape was rejected by a real codex binary with "invalid type: map,
17
+ * expected a string" — caught by `scripts/test-local-llm-harnesses.ts`),
18
+ * but `wire_api = "responses"` is the only value codex still accepts
19
+ * (support for `"chat"` was dropped in Feb 2026), and a plain OpenAI
20
+ * Chat-Completions server (llama.cpp, llama-swap, most local setups) does
21
+ * NOT implement the Responses API — so codex may still fail at the
22
+ * PROTOCOL level even with a correctly-shaped config file. That gap is
23
+ * real and current, not a stale warning; see docs/custom-model-endpoints-plan.md. The rest
24
+ * (gemini/pi/grok/deepseek/omp) have their ONE-SHOT INVOCATION flags
25
+ * confirmed against real installed binaries' own `--help` output, but
26
+ * their custom-endpoint env/config conventions remain web-researched,
27
+ * unverified.
28
+ */
29
+ const DEFAULT_API_KEY = 'local-dummy-key';
30
+ /** Normalizes a base URL to end in exactly one trailing `/v1`, for CLIs whose config expects the OpenAI-style suffix. */
31
+ export function withV1Suffix(baseUrl) {
32
+ const trimmed = baseUrl.replace(/\/+$/, '');
33
+ return /\/v1$/.test(trimmed) ? trimmed : `${trimmed}/v1`;
34
+ }
35
+ /** JSON-escapes a string for embedding in a TOML/YAML double-quoted scalar — a safe superset of both grammars' basic escapes. */
36
+ function quoted(value) {
37
+ return JSON.stringify(value);
38
+ }
39
+ export function buildCustomModelInjection(entry, endpoint, modelId) {
40
+ const cap = entry.capabilities.customModelInjection;
41
+ const apiKey = endpoint.apiKey?.trim() || DEFAULT_API_KEY;
42
+ switch (cap.kind) {
43
+ case 'env': {
44
+ const envOverrides = {
45
+ [cap.baseUrlVar]: endpoint.baseUrl,
46
+ [cap.apiKeyVar]: apiKey,
47
+ };
48
+ for (const modelVar of cap.modelVars)
49
+ envOverrides[modelVar] = modelId;
50
+ return withLaunchModel({ kind: 'env', envOverrides }, cap.launchModel, modelId);
51
+ }
52
+ case 'configContentEnv': {
53
+ const content = renderConfigContent(cap.template, endpoint, modelId, apiKey);
54
+ return withLaunchModel({ kind: 'env', envOverrides: { [cap.envVar]: content } }, cap.launchModel, modelId);
55
+ }
56
+ case 'configDir': {
57
+ const { content, extraEnv } = renderConfigFile(cap.template, endpoint, modelId, apiKey);
58
+ return withLaunchModel({ kind: 'configDir', dirEnvVar: cap.dirEnvVar, files: [{ relPath: cap.fileName, content }], extraEnv }, cap.launchModel, modelId);
59
+ }
60
+ case 'unsupported':
61
+ return { kind: 'unsupported' };
62
+ }
63
+ }
64
+ /** Render a `launchModel` template (`{modelId}` = the chosen id) onto an injection result. */
65
+ function withLaunchModel(result, template, modelId) {
66
+ if (!template)
67
+ return result;
68
+ return { ...result, launchModel: template.split('{modelId}').join(modelId) };
69
+ }
70
+ function renderConfigContent(template, endpoint, modelId, apiKey) {
71
+ switch (template) {
72
+ case 'opencode-json':
73
+ return JSON.stringify({
74
+ $schema: 'https://opencode.ai/config.json',
75
+ provider: {
76
+ custom: {
77
+ options: { baseURL: withV1Suffix(endpoint.baseUrl), apiKey },
78
+ models: { [modelId]: {} },
79
+ },
80
+ },
81
+ model: `custom/${modelId}`,
82
+ });
83
+ }
84
+ }
85
+ const CODEX_API_KEY_ENV_VAR = 'CODEMAN_CUSTOM_MODEL_API_KEY';
86
+ /** The `[model.<name>]` block name grok's config.toml uses for the injected model — also
87
+ * what `-m <name>` in the standalone script's ONE_SHOT argv must reference to select it. */
88
+ export const GROK_CUSTOM_MODEL_NAME = 'codeman-custom';
89
+ function renderConfigFile(template, endpoint, modelId, apiKey) {
90
+ const baseUrl = withV1Suffix(endpoint.baseUrl);
91
+ switch (template) {
92
+ case 'codex-toml': {
93
+ // Verified against real codex (>= Feb 2026): `model` is a top-level STRING, never
94
+ // a `[model].default` table — codex rejects that with "invalid type: map, expected
95
+ // a string" (caught by scripts/test-local-llm-harnesses.ts against a real llama-swap
96
+ // server). The API key is NEVER a literal TOML field: codex's schema only supports
97
+ // `env_key`, the NAME of an env var it reads the credential from at runtime, so the
98
+ // actual value must ride along as an extra env var, never embedded in the file.
99
+ // ⚠️ `wire_api = "responses"` is the only value codex still accepts (it dropped
100
+ // `"chat"` support in Feb 2026) — a plain OpenAI Chat-Completions server (llama.cpp,
101
+ // llama-swap, most local setups) does NOT implement the Responses API, so this
102
+ // recipe may still fail at the PROTOCOL level even though the file now parses
103
+ // correctly. That is a real, currently-unresolved compatibility gap, not a syntax
104
+ // bug — track it before calling codex support done.
105
+ const content = [
106
+ `model = ${quoted(modelId)}`,
107
+ `model_provider = "custom"`,
108
+ '',
109
+ '[model_providers.custom]',
110
+ `name = "Custom Endpoint"`,
111
+ `base_url = ${quoted(baseUrl)}`,
112
+ `env_key = ${quoted(CODEX_API_KEY_ENV_VAR)}`,
113
+ `wire_api = "responses"`,
114
+ '',
115
+ ].join('\n');
116
+ return { content, extraEnv: { [CODEX_API_KEY_ENV_VAR]: apiKey } };
117
+ }
118
+ case 'pi-models-json':
119
+ // Verified against pi's OWN bundled docs (models.md): `models` is an ARRAY of
120
+ // `{id: "..."}` objects, NOT an object keyed by model id — the earlier shape here
121
+ // silently loaded zero models ("No models available"), confirmed live. `authHeader:
122
+ // true` is required too: pi does not automatically send `Authorization: Bearer
123
+ // <apiKey>` just because `apiKey` is set (per the same doc) — without it, a real
124
+ // (non-llama.cpp) endpoint that actually checks the key would reject every request.
125
+ return {
126
+ content: JSON.stringify({
127
+ providers: {
128
+ custom: {
129
+ baseUrl,
130
+ apiKey,
131
+ api: 'openai-completions',
132
+ authHeader: true,
133
+ models: [{ id: modelId }],
134
+ },
135
+ },
136
+ }, null, 2),
137
+ };
138
+ case 'omp-models-yml':
139
+ // Mirrors the pi-models-json fix above (omp shares pi's config lineage per
140
+ // CLAUDE.md — it reads several of pi's own env vars): a flat list of bare model
141
+ // name strings under `models` is UNCONFIRMED against real omp docs (none are
142
+ // bundled with the binary) — this now matches pi's `{id: "..."}` object-list
143
+ // shape and adds `authHeader: true` on the same reasoning, but has not itself
144
+ // been live-tested the way pi's fix was. Verify before raising its confidence.
145
+ return {
146
+ content: `providers:\n custom:\n baseUrl: ${quoted(baseUrl)}\n apiKey: ${quoted(apiKey)}\n api: openai-completions\n authHeader: true\n models:\n - id: ${quoted(modelId)}\n`,
147
+ };
148
+ case 'grok-toml': {
149
+ // Verified against xAI's own docs (docs.x.ai/build/settings/reference): a
150
+ // `[model.<name>]` block, NOT plain env vars — an earlier `env`-kind recipe for
151
+ // grok was wrong, not just unverified (see the customModelInjection doc comment
152
+ // in cli-registry/types.ts). `api_backend = "chat_completions"` is explicitly
153
+ // supported (unlike codex, which dropped it after Feb 2026), so this one CAN
154
+ // talk to a plain OpenAI-compatible server directly. `env_key` reuses grok's own
155
+ // documented fallback var name (XAI_API_KEY) rather than inventing a new one.
156
+ const content = [
157
+ `[model.${GROK_CUSTOM_MODEL_NAME}]`,
158
+ `model = ${quoted(modelId)}`,
159
+ `base_url = ${quoted(baseUrl)}`,
160
+ `name = "Custom Endpoint"`,
161
+ `env_key = "XAI_API_KEY"`,
162
+ `api_backend = "chat_completions"`,
163
+ '',
164
+ ].join('\n');
165
+ return { content, extraEnv: { XAI_API_KEY: apiKey } };
166
+ }
167
+ }
168
+ }
169
+ //# sourceMappingURL=custom-model-injection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-model-injection.js","sourceRoot":"","sources":["../src/custom-model-injection.ts"],"names":[],"mappings":"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"}
@@ -100,6 +100,48 @@ export declare function dockerConfigHash(docker: Pick<SessionDocker, 'engine' |
100
100
  * computed last over the resolved values.
101
101
  */
102
102
  export declare function toSessionDocker(host: DockerHost, dockerCase: DockerCase): SessionDocker;
103
+ /**
104
+ * Which existing case, if any, blocks adopting `container` at `containerWorkdir`.
105
+ *
106
+ * One container may back SEVERAL adopted cases, each pointing at a different
107
+ * directory inside it — that is the whole reason to adopt the same container
108
+ * twice, and it is safe because the in-container tmux session is named per
109
+ * SESSION (`dockerTmuxSessionName`, `codeman-dkr-<id8>`) and not per case, so a
110
+ * session teardown kills exactly one session and its siblings on the shared
111
+ * in-container tmux server are untouched. Nothing else reaches an adopted
112
+ * container's lifecycle either: stop/remove throw at the builder, recreate
113
+ * refuses `owned === false`, and the orphan reaper filters on the
114
+ * `codeman.managed=1` label that only Codeman-created containers carry.
115
+ *
116
+ * So the conflicts that remain are NOT about the tmux server:
117
+ * - `owned-case` the container backs a case Codeman CREATED, whose lifecycle
118
+ * it owns; a recreate or delete there would destroy the
119
+ * adopted case's container out from under it.
120
+ * - `other-owner` already adopted by a different user. Adoption hands out a
121
+ * shell inside someone else's container, so it stays scoped.
122
+ * - `duplicate` same container AND same directory: the second case would
123
+ * behave identically to the first, so name the first instead
124
+ * of silently creating a twin. A DIFFERENT directory is the
125
+ * supported case and returns null.
126
+ */
127
+ export type AdoptContainerConflict = {
128
+ kind: 'owned-case';
129
+ caseName: string;
130
+ } | {
131
+ kind: 'other-owner';
132
+ caseName: string;
133
+ } | {
134
+ kind: 'duplicate';
135
+ caseName: string;
136
+ } | null;
137
+ export declare function classifyAdoptContainerConflict(params: {
138
+ container: string;
139
+ /** Directory inside the container this adoption targets (already defaulted). */
140
+ containerWorkdir: string;
141
+ existing: ReadonlyArray<Pick<DockerCase, 'name' | 'container' | 'containerWorkdir' | 'hostWorkspacePath' | 'owned' | 'owner'>>;
142
+ /** Owner visibility test (canAccessOwned bound to the caller). */
143
+ canAccess: (owner?: string) => boolean;
144
+ }): AdoptContainerConflict;
103
145
  /**
104
146
  * An ADOPTED container is one the user built and runs themselves. Codeman may
105
147
  * only exec into it; it must never create, start, stop, restart or remove it.
@@ -176,7 +218,28 @@ export declare function buildDockerCreateArgs(ctx: DockerCreateContext): string[
176
218
  * scripts/build-agent-image.mjs): `build -f <dockerfile> -t <image> [--no-cache]
177
219
  * <contextDir>`. Kept pure + unit-testable; the caller prepends the engine binary.
178
220
  */
179
- export declare function agentImageBuildArgs(dockerfile: string, image: string, contextDir: string, noCache?: boolean): string[];
221
+ export declare function agentImageBuildArgs(dockerfile: string, image: string, contextDir: string, noCache?: boolean, buildArgs?: Array<[string, string]>): string[];
222
+ /**
223
+ * npm packages the agent image installs in its shared layer, from the STOCK catalogue.
224
+ *
225
+ * ⚠️ Stock, deliberately, NOT the merged registry. A user's `~/.codeman/clis.json` must not
226
+ * change what lands inside an image tagged `codeman/agent:base`, or two machines holding that
227
+ * same tag hold different images and every cache-hit decision downstream is a lie.
228
+ *
229
+ * ⚠️ An entry carrying `discovery.install.agentImageLayer` is excluded here — see that field's
230
+ * doc comment in `types.ts` for why some CLIs need their own hand-written Dockerfile layer
231
+ * instead of the shared one, and `test/docker-agent-image-coverage.test.ts` for the guard that
232
+ * an exclusion here still lands in the Dockerfile somewhere.
233
+ *
234
+ * ⚠️ This mirrors `agentImageNpmPackages()` in `scripts/lib/cli-catalog.mjs`, which the CLI
235
+ * build path uses because a `.mjs` cannot import TypeScript. Two producers of one command
236
+ * line drift; `test/agent-image-build-args-parity.test.ts` is what stops them — including the
237
+ * SAFE_PACKAGE regex below, which is duplicated (not imported) in that file for the same
238
+ * reason and must stay byte-identical to it.
239
+ */
240
+ export declare function agentImageNpmPackages(): string[];
241
+ /** The `--build-arg` pairs the agent image takes. */
242
+ export declare function agentImageBuildArgPairs(): Array<[string, string]>;
180
243
  /** Container Claude config dir (created gid-0 writable in the image). */
181
244
  export declare const CONTAINER_CLAUDE_DIR = "/home/agent/.claude";
182
245
  /** In-container path of the seeded (writable) `~/.claude.json`. */
@@ -1 +1 @@
1
- {"version":3,"file":"docker-hosts.d.ts","sourceRoot":"","sources":["../src/docker-hosts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"docker-hosts.d.ts","sourceRoot":"","sources":["../src/docker-hosts.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
24
24
  import fs from 'node:fs/promises';
25
25
  import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
26
26
  import { enabledCliIds, getCli } from './config/cli-registry/registry.js';
27
+ import { STOCK_CLIS } from './config/cli-registry/stock.js';
27
28
  import { fileURLToPath } from 'node:url';
28
29
  import { homedir } from 'node:os';
29
30
  import { createHash } from 'node:crypto';
@@ -243,6 +244,24 @@ export function toSessionDocker(host, dockerCase) {
243
244
  session.owned = false;
244
245
  return session;
245
246
  }
247
+ export function classifyAdoptContainerConflict(params) {
248
+ const { container, containerWorkdir, existing, canAccess } = params;
249
+ const sharing = existing.filter((item) => (item.container ?? dockerContainerName(item.name)) === container);
250
+ if (sharing.length === 0)
251
+ return null;
252
+ // `owned` is optional and an ABSENT flag means owned (legacy cases predate the
253
+ // field), so this must test `!== false` rather than truthiness.
254
+ const owned = sharing.find((item) => item.owned !== false);
255
+ if (owned)
256
+ return { kind: 'owned-case', caseName: owned.name };
257
+ const foreign = sharing.find((item) => !canAccess(item.owner));
258
+ if (foreign)
259
+ return { kind: 'other-owner', caseName: foreign.name };
260
+ const twin = sharing.find((item) => (item.containerWorkdir ?? item.hostWorkspacePath) === containerWorkdir);
261
+ if (twin)
262
+ return { kind: 'duplicate', caseName: twin.name };
263
+ return null;
264
+ }
246
265
  /**
247
266
  * An ADOPTED container is one the user built and runs themselves. Codeman may
248
267
  * only exec into it; it must never create, start, stop, restart or remove it.
@@ -381,8 +400,61 @@ export function buildDockerCreateArgs(ctx) {
381
400
  * scripts/build-agent-image.mjs): `build -f <dockerfile> -t <image> [--no-cache]
382
401
  * <contextDir>`. Kept pure + unit-testable; the caller prepends the engine binary.
383
402
  */
384
- export function agentImageBuildArgs(dockerfile, image, contextDir, noCache = false) {
385
- return ['build', '-f', dockerfile, '-t', image, ...(noCache ? ['--no-cache'] : []), contextDir];
403
+ export function agentImageBuildArgs(dockerfile, image, contextDir, noCache = false, buildArgs = []) {
404
+ return [
405
+ 'build',
406
+ '-f',
407
+ dockerfile,
408
+ '-t',
409
+ image,
410
+ ...(noCache ? ['--no-cache'] : []),
411
+ ...buildArgs.flatMap(([name, value]) => ['--build-arg', `${name}=${value}`]),
412
+ contextDir,
413
+ ];
414
+ }
415
+ /** Tokens allowed in an npm package name reaching a Dockerfile build arg unquoted. */
416
+ const SAFE_PACKAGE = /^[@A-Za-z0-9][@A-Za-z0-9/._-]*$/;
417
+ /**
418
+ * npm packages the agent image installs in its shared layer, from the STOCK catalogue.
419
+ *
420
+ * ⚠️ Stock, deliberately, NOT the merged registry. A user's `~/.codeman/clis.json` must not
421
+ * change what lands inside an image tagged `codeman/agent:base`, or two machines holding that
422
+ * same tag hold different images and every cache-hit decision downstream is a lie.
423
+ *
424
+ * ⚠️ An entry carrying `discovery.install.agentImageLayer` is excluded here — see that field's
425
+ * doc comment in `types.ts` for why some CLIs need their own hand-written Dockerfile layer
426
+ * instead of the shared one, and `test/docker-agent-image-coverage.test.ts` for the guard that
427
+ * an exclusion here still lands in the Dockerfile somewhere.
428
+ *
429
+ * ⚠️ This mirrors `agentImageNpmPackages()` in `scripts/lib/cli-catalog.mjs`, which the CLI
430
+ * build path uses because a `.mjs` cannot import TypeScript. Two producers of one command
431
+ * line drift; `test/agent-image-build-args-parity.test.ts` is what stops them — including the
432
+ * SAFE_PACKAGE regex below, which is duplicated (not imported) in that file for the same
433
+ * reason and must stay byte-identical to it.
434
+ */
435
+ export function agentImageNpmPackages() {
436
+ const packages = [];
437
+ for (const entry of STOCK_CLIS) {
438
+ if (!entry.enabled || entry.discovery.install.agentImageLayer)
439
+ continue;
440
+ const pkg = entry.discovery.install.npmPackage;
441
+ if (!pkg)
442
+ continue;
443
+ // The value is interpolated into a Dockerfile ARG expanded UNQUOTED (word splitting is
444
+ // how the list becomes several arguments), so a token with whitespace or shell
445
+ // metacharacters would change what the RUN line means. The source is `stock.ts`, so the
446
+ // practical risk is nil, but this is the in-app auto-build path and the only one of the
447
+ // two producers where that had gone unchecked.
448
+ if (!SAFE_PACKAGE.test(pkg)) {
449
+ throw new Error(`Refusing unsafe npm package name for "${String(entry.id)}": ${JSON.stringify(pkg)}`);
450
+ }
451
+ packages.push(pkg);
452
+ }
453
+ return packages;
454
+ }
455
+ /** The `--build-arg` pairs the agent image takes. */
456
+ export function agentImageBuildArgPairs() {
457
+ return [['CLI_NPM_PACKAGES', agentImageNpmPackages().join(' ')]];
386
458
  }
387
459
  // ========== Credential mount resolution (IO) ==========
388
460
  /** Container Claude config dir (created gid-0 writable in the image). */
@@ -802,7 +874,7 @@ function buildAgentImage(docker, image, opts) {
802
874
  const argv = dockerEngineArgv(docker);
803
875
  const args = [
804
876
  ...argv.slice(1),
805
- ...agentImageBuildArgs(resolved.dockerfile, image, resolved.contextDir, opts.noCache),
877
+ ...agentImageBuildArgs(resolved.dockerfile, image, resolved.contextDir, opts.noCache, agentImageBuildArgPairs()),
806
878
  ];
807
879
  return new Promise((resolve) => {
808
880
  // async spawn (NEVER spawnSync) so a multi-minute build never wedges the event loop.