create-walle 0.10.1 → 0.10.3

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 (681) hide show
  1. package/README.md +7 -1
  2. package/lib/owner-write-safety.js +135 -0
  3. package/lib/public-runtime.js +13 -5
  4. package/lib/release-schema.json +3 -2
  5. package/lib/runtime-closure-policy.json +11 -8
  6. package/package.json +1 -1
  7. package/template/bin/deps-doctor.js +1 -1
  8. package/template/bin/node-bin.sh +11 -0
  9. package/template/coding-task-manager/api-prompts.js +55 -29
  10. package/template/coding-task-manager/bin/claude-hook.js +62 -4
  11. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  12. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  13. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  14. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  16. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  17. package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
  18. package/template/coding-task-manager/bin/land.js +2069 -0
  19. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  20. package/template/coding-task-manager/bin/memory-census.js +4 -2
  21. package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
  22. package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
  23. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  24. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  25. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  26. package/template/coding-task-manager/db.js +860 -317
  27. package/template/coding-task-manager/git-utils.js +44 -0
  28. package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
  29. package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
  30. package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
  31. package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
  32. package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
  33. package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
  34. package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
  35. package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
  36. package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
  37. package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
  38. package/template/coding-task-manager/lib/adopted-host-redial.js +47 -7
  39. package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
  40. package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
  41. package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
  42. package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
  43. package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
  44. package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
  45. package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
  46. package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
  47. package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
  48. package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
  49. package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
  50. package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
  51. package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
  52. package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
  53. package/template/coding-task-manager/lib/agent-definitions.js +19 -0
  54. package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
  55. package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
  56. package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
  57. package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
  58. package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
  59. package/template/coding-task-manager/lib/agent-presets.js +99 -1
  60. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  61. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  62. package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
  63. package/template/coding-task-manager/lib/agent-version-service.js +74 -11
  64. package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
  65. package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
  66. package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
  67. package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
  68. package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
  69. package/template/coding-task-manager/lib/api/fleet.js +118 -0
  70. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  71. package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
  72. package/template/coding-task-manager/lib/api/ingress.js +43 -12
  73. package/template/coding-task-manager/lib/api/landing.js +403 -0
  74. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  75. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  76. package/template/coding-task-manager/lib/api/machines.js +1150 -0
  77. package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
  78. package/template/coding-task-manager/lib/api/misc-ops.js +25 -5
  79. package/template/coding-task-manager/lib/api/providers.js +53 -6
  80. package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
  81. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  82. package/template/coding-task-manager/lib/api/session-attach.js +623 -0
  83. package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
  84. package/template/coding-task-manager/lib/api/sessions.js +237 -59
  85. package/template/coding-task-manager/lib/api/setup-network.js +544 -16
  86. package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
  87. package/template/coding-task-manager/lib/api/setup.js +829 -10
  88. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  89. package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
  90. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  91. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  92. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  93. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  94. package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
  95. package/template/coding-task-manager/lib/auth-context.js +32 -2
  96. package/template/coding-task-manager/lib/auth-rate-limit.js +64 -1
  97. package/template/coding-task-manager/lib/auth-rules.js +474 -62
  98. package/template/coding-task-manager/lib/background-stop.js +369 -0
  99. package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
  100. package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
  101. package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
  102. package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
  103. package/template/coding-task-manager/lib/broadcast-serialize.js +7 -1
  104. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  105. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  106. package/template/coding-task-manager/lib/build-info.js +4 -2
  107. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  108. package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
  109. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  110. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  111. package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
  112. package/template/coding-task-manager/lib/client-diag-handler.js +69 -2
  113. package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
  114. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  115. package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
  116. package/template/coding-task-manager/lib/codex-harness-qualification.js +55 -20
  117. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  118. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  119. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  120. package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
  121. package/template/coding-task-manager/lib/coding-agent-models.js +48 -42
  122. package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
  123. package/template/coding-task-manager/lib/coding-session-model-adapters.js +70 -4
  124. package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
  125. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  126. package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
  127. package/template/coding-task-manager/lib/coding-session-model-runtime.js +24 -6
  128. package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
  129. package/template/coding-task-manager/lib/coding-session-model-state.js +17 -0
  130. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  131. package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
  132. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  133. package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
  134. package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
  135. package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
  136. package/template/coding-task-manager/lib/conversation-sync.js +355 -0
  137. package/template/coding-task-manager/lib/create/resolve-launch-params.js +104 -13
  138. package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
  139. package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
  140. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  141. package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
  142. package/template/coding-task-manager/lib/db-domain-tables.js +8 -0
  143. package/template/coding-task-manager/lib/db-domains.js +22 -2
  144. package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
  145. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  146. package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
  147. package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
  148. package/template/coding-task-manager/lib/db-schema-source-files.js +6 -0
  149. package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
  150. package/template/coding-task-manager/lib/feature-manifest.js +5 -1
  151. package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
  152. package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
  153. package/template/coding-task-manager/lib/fleet-hub.js +762 -0
  154. package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
  155. package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
  156. package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
  157. package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
  158. package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
  159. package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
  160. package/template/coding-task-manager/lib/fleet-update.js +798 -0
  161. package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
  162. package/template/coding-task-manager/lib/fs-watcher.js +61 -44
  163. package/template/coding-task-manager/lib/harness-history-transition.js +52 -11
  164. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  165. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  166. package/template/coding-task-manager/lib/headless-term-service.js +139 -25
  167. package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
  168. package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
  169. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  170. package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
  171. package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
  172. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  173. package/template/coding-task-manager/lib/host-handoff.js +50 -15
  174. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  175. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  176. package/template/coding-task-manager/lib/host-stats.js +475 -0
  177. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  178. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  179. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  180. package/template/coding-task-manager/lib/hosted-sync-worker.js +141 -310
  181. package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
  182. package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
  183. package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
  184. package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
  185. package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
  186. package/template/coding-task-manager/lib/hub-bridge.js +398 -0
  187. package/template/coding-task-manager/lib/idle-notify.js +491 -0
  188. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +12 -0
  189. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  190. package/template/coding-task-manager/lib/instance-manifest.js +18 -2
  191. package/template/coding-task-manager/lib/instance-sync-status.js +33 -8
  192. package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
  193. package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
  194. package/template/coding-task-manager/lib/landing/config.js +536 -0
  195. package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
  196. package/template/coding-task-manager/lib/landing/gate.js +360 -0
  197. package/template/coding-task-manager/lib/landing/git.js +344 -0
  198. package/template/coding-task-manager/lib/landing/lease.js +247 -0
  199. package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
  200. package/template/coding-task-manager/lib/landing/proof.js +223 -0
  201. package/template/coding-task-manager/lib/landing/queue.js +998 -0
  202. package/template/coding-task-manager/lib/landing/radar.js +489 -0
  203. package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
  204. package/template/coding-task-manager/lib/landing/state.js +263 -0
  205. package/template/coding-task-manager/lib/landing/stop.js +49 -0
  206. package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
  207. package/template/coding-task-manager/lib/landing/sync.js +456 -0
  208. package/template/coding-task-manager/lib/landing/train.js +885 -0
  209. package/template/coding-task-manager/lib/landing/window.js +57 -0
  210. package/template/coding-task-manager/lib/launch-environment.js +121 -0
  211. package/template/coding-task-manager/lib/launch-model-override.js +193 -8
  212. package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
  213. package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
  214. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  215. package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
  216. package/template/coding-task-manager/lib/lead-model-options.js +160 -3
  217. package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
  218. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +409 -72
  219. package/template/coding-task-manager/lib/lead-model-switch.js +115 -10
  220. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
  221. package/template/coding-task-manager/lib/lead-model-transition-store.js +85 -9
  222. package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
  223. package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
  224. package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
  225. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  226. package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
  227. package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
  228. package/template/coding-task-manager/lib/login-tripwire.js +1 -0
  229. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  230. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  231. package/template/coding-task-manager/lib/machine-registry.js +1494 -0
  232. package/template/coding-task-manager/lib/machine-self.js +66 -0
  233. package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
  234. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +485 -57
  235. package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
  236. package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
  237. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  238. package/template/coding-task-manager/lib/media-journal.js +84 -27
  239. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  240. package/template/coding-task-manager/lib/memory-join.js +337 -0
  241. package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
  242. package/template/coding-task-manager/lib/memory-sync.js +565 -0
  243. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  244. package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
  245. package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
  246. package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
  247. package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
  248. package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
  249. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  250. package/template/coding-task-manager/lib/model-availability.js +727 -0
  251. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
  252. package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
  253. package/template/coding-task-manager/lib/model-id-rule.js +19 -0
  254. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +8 -0
  255. package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
  256. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +6 -0
  257. package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
  258. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  259. package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
  260. package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
  261. package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
  262. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  263. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  264. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  265. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  266. package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
  267. package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
  268. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  269. package/template/coding-task-manager/lib/model-proxy/tokens.js +147 -5
  270. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +18 -0
  271. package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
  272. package/template/coding-task-manager/lib/native-history-control.js +7 -5
  273. package/template/coding-task-manager/lib/native-lead-settings-client.js +46 -5
  274. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  275. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +776 -75
  276. package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
  277. package/template/coding-task-manager/lib/opencode-cli.js +480 -0
  278. package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
  279. package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
  280. package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
  281. package/template/coding-task-manager/lib/owner-action-manifest-data.json +15 -1
  282. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  283. package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
  284. package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
  285. package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
  286. package/template/coding-task-manager/lib/perf-summary.js +7 -0
  287. package/template/coding-task-manager/lib/perf-tracker.js +63 -2
  288. package/template/coding-task-manager/lib/project-config.js +7 -0
  289. package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
  290. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  291. package/template/coding-task-manager/lib/provider-login-broker.js +264 -24
  292. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  293. package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
  294. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  295. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  296. package/template/coding-task-manager/lib/read-pool-client.js +94 -4
  297. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  298. package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
  299. package/template/coding-task-manager/lib/recent-catalog-query.js +41 -0
  300. package/template/coding-task-manager/lib/recent-session-catalog-response.js +76 -10
  301. package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
  302. package/template/coding-task-manager/lib/relay-client.js +57 -3
  303. package/template/coding-task-manager/lib/relink-audit.js +34 -5
  304. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  305. package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
  306. package/template/coding-task-manager/lib/remote-machine-catalog.js +1357 -0
  307. package/template/coding-task-manager/lib/remote-machine-create.js +1233 -0
  308. package/template/coding-task-manager/lib/remote-machine-link.js +1426 -0
  309. package/template/coding-task-manager/lib/remote-machine-proxy.js +654 -0
  310. package/template/coding-task-manager/lib/remote-session-forward.js +364 -0
  311. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  312. package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
  313. package/template/coding-task-manager/lib/restart-guard.js +18 -6
  314. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  315. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  316. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  317. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  318. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  319. package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
  320. package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
  321. package/template/coding-task-manager/lib/resume-admission.js +17 -3
  322. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  323. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  324. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  325. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  326. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  327. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  328. package/template/coding-task-manager/lib/review-repo-registry.js +74 -18
  329. package/template/coding-task-manager/lib/root-delivery-runtime.js +74 -17
  330. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  331. package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
  332. package/template/coding-task-manager/lib/root-prompt-flow.js +168 -34
  333. package/template/coding-task-manager/lib/runtime-contract.js +3 -1
  334. package/template/coding-task-manager/lib/schema-indexes.js +1 -0
  335. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  336. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  337. package/template/coding-task-manager/lib/session-context-locator.js +742 -0
  338. package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
  339. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  340. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  341. package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
  342. package/template/coding-task-manager/lib/session-create/delegate-worker.js +179 -20
  343. package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
  344. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  345. package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
  346. package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
  347. package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
  348. package/template/coding-task-manager/lib/session-create/prepared.js +201 -9
  349. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  350. package/template/coding-task-manager/lib/session-create/provider-process.js +193 -64
  351. package/template/coding-task-manager/lib/session-create/response.js +37 -19
  352. package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
  353. package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
  354. package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
  355. package/template/coding-task-manager/lib/session-create/transcript.js +14 -5
  356. package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
  357. package/template/coding-task-manager/lib/session-create/worker-continuation.js +50 -2
  358. package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
  359. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  360. package/template/coding-task-manager/lib/session-create/worker-observability.js +101 -9
  361. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  362. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  363. package/template/coding-task-manager/lib/session-empty.js +13 -10
  364. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  365. package/template/coding-task-manager/lib/session-host-manager.js +212 -206
  366. package/template/coding-task-manager/lib/session-jobs.js +20 -10
  367. package/template/coding-task-manager/lib/session-lifecycle.js +28 -4
  368. package/template/coding-task-manager/lib/session-model-action-preconditions.js +15 -2
  369. package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
  370. package/template/coding-task-manager/lib/session-park.js +738 -0
  371. package/template/coding-task-manager/lib/session-path-grant.js +13 -4
  372. package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
  373. package/template/coding-task-manager/lib/session-standup.js +67 -4
  374. package/template/coding-task-manager/lib/session-status-ledger.js +147 -6
  375. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  376. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  377. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  378. package/template/coding-task-manager/lib/session-transport.js +17 -0
  379. package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
  380. package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
  381. package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
  382. package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
  383. package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
  384. package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
  385. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  386. package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
  387. package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
  388. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  389. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +25 -23
  390. package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
  391. package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
  392. package/template/coding-task-manager/lib/submission-ack.js +90 -2
  393. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  394. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  395. package/template/coding-task-manager/lib/systemd-scope.js +115 -0
  396. package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
  397. package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
  398. package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
  399. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  400. package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
  401. package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
  402. package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
  403. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  404. package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
  405. package/template/coding-task-manager/lib/transcript-frame-cache.js +20 -5
  406. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  407. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  408. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  409. package/template/coding-task-manager/lib/transcript-source.js +44 -7
  410. package/template/coding-task-manager/lib/transcript-store.js +49 -0
  411. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  412. package/template/coding-task-manager/lib/typing-interaction-trace.js +198 -3
  413. package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
  414. package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
  415. package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
  416. package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
  417. package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
  418. package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
  419. package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
  420. package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
  421. package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
  422. package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
  423. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  424. package/template/coding-task-manager/lib/wake-skip-reasons.js +47 -0
  425. package/template/coding-task-manager/lib/walle/turn.js +1 -1
  426. package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
  427. package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
  428. package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
  429. package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
  430. package/template/coding-task-manager/lib/walle-row-history.js +495 -0
  431. package/template/coding-task-manager/lib/walle-supervisor.js +130 -27
  432. package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
  433. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  434. package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
  435. package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
  436. package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
  437. package/template/coding-task-manager/lib/ws/misc.js +1 -1
  438. package/template/coding-task-manager/lib/ws/state-sync.js +125 -6
  439. package/template/coding-task-manager/lib/ws/terminal-attach.js +123 -1
  440. package/template/coding-task-manager/lib/ws-router.js +68 -1
  441. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  442. package/template/coding-task-manager/oauth-proxy.js +211 -170
  443. package/template/coding-task-manager/package-lock.json +34 -94
  444. package/template/coding-task-manager/package.json +7 -3
  445. package/template/coding-task-manager/protocol/message-table.json +10 -0
  446. package/template/coding-task-manager/protocol/messages.js +10 -0
  447. package/template/coding-task-manager/protocol/ws-schema.json +20 -0
  448. package/template/coding-task-manager/protocol/ws-schema.md +2 -0
  449. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  450. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  451. package/template/coding-task-manager/public/css/app.css +449 -1
  452. package/template/coding-task-manager/public/css/reviews.css +4 -0
  453. package/template/coding-task-manager/public/css/walle-session.css +4 -0
  454. package/template/coding-task-manager/public/index.html +766 -465
  455. package/template/coding-task-manager/public/js/agent-command.js +86 -0
  456. package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
  457. package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
  458. package/template/coding-task-manager/public/js/app/machines-page.js +2572 -0
  459. package/template/coding-task-manager/public/js/app/models-tab.js +658 -73
  460. package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
  461. package/template/coding-task-manager/public/js/app/worktrees-panel.js +191 -7
  462. package/template/coding-task-manager/public/js/background-work.js +203 -28
  463. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +181 -13
  464. package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
  465. package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
  466. package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
  467. package/template/coding-task-manager/public/js/core/session-commands.js +847 -5
  468. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  469. package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
  470. package/template/coding-task-manager/public/js/document-review-links.js +9 -1
  471. package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
  472. package/template/coding-task-manager/public/js/history-app-seam.js +48 -4
  473. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  474. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  475. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  476. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  477. package/template/coding-task-manager/public/js/machine-pool-shared.js +991 -0
  478. package/template/coding-task-manager/public/js/message-renderer.js +4 -3
  479. package/template/coding-task-manager/public/js/model-picker.js +3 -1
  480. package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
  481. package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
  482. package/template/coding-task-manager/public/js/pasted-content.js +236 -0
  483. package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
  484. package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
  485. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  486. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
  487. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  488. package/template/coding-task-manager/public/js/prompts.js +11 -10
  489. package/template/coding-task-manager/public/js/protocol.js +10 -0
  490. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  491. package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
  492. package/template/coding-task-manager/public/js/reviews.js +7 -3
  493. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  494. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  495. package/template/coding-task-manager/public/js/row-join.js +4 -2
  496. package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
  497. package/template/coding-task-manager/public/js/session-search-utils.js +64 -21
  498. package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
  499. package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
  500. package/template/coding-task-manager/public/js/state-sync-client.js +14 -1
  501. package/template/coding-task-manager/public/js/stream-view.js +6 -5
  502. package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
  503. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  504. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  505. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  506. package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
  507. package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
  508. package/template/coding-task-manager/public/js/terminal/runtime-12.js +60 -3
  509. package/template/coding-task-manager/public/js/terminal/runtime-16.js +16 -12
  510. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  511. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  512. package/template/coding-task-manager/public/js/terminal/runtime-20.js +211 -74
  513. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  514. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  515. package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
  516. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
  517. package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
  518. package/template/coding-task-manager/public/js/terminal-wheel.js +62 -5
  519. package/template/coding-task-manager/public/js/walle/chat-conversation.js +15 -7
  520. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  521. package/template/coding-task-manager/public/js/walle.js +6 -0
  522. package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
  523. package/template/coding-task-manager/public/m/app.css +366 -8
  524. package/template/coding-task-manager/public/m/app.js +1006 -74
  525. package/template/coding-task-manager/public/m/index.html +55 -1
  526. package/template/coding-task-manager/public/m/machines.js +2147 -0
  527. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  528. package/template/coding-task-manager/public/m/private-api.js +31 -1
  529. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  530. package/template/coding-task-manager/public/m/sw.js +5 -0
  531. package/template/coding-task-manager/public/usage.html +1 -0
  532. package/template/coding-task-manager/queue-engine.js +13 -0
  533. package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
  534. package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
  535. package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
  536. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
  537. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
  538. package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
  539. package/template/coding-task-manager/server/approvals.js +5 -6
  540. package/template/coding-task-manager/server/boot.js +136 -17
  541. package/template/coding-task-manager/server.js +2819 -11885
  542. package/template/coding-task-manager/session-integrity.js +71 -13
  543. package/template/coding-task-manager/workers/db-owner-worker.js +72 -9
  544. package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
  545. package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
  546. package/template/coding-task-manager/workers/read-pool-worker.js +93 -12
  547. package/template/coding-task-manager/workers/session-host-pool-process.js +24 -10
  548. package/template/coding-task-manager/workers/session-host-process.js +19 -8
  549. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  550. package/template/coding-task-manager/workers/watch-worker.js +105 -0
  551. package/template/coding-task-manager/workers/worktree-worker.js +202 -33
  552. package/template/ctm-relay/lib/protocol.js +14 -1
  553. package/template/package-lock.json +2 -2
  554. package/template/package.json +1 -1
  555. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  556. package/template/shared/backup-retention.js +82 -0
  557. package/template/shared/conversation-admission.js +2 -0
  558. package/template/shared/conversation-provenance.js +3 -7
  559. package/template/shared/conversation-storage-v2-contract.js +47 -6
  560. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  561. package/template/shared/git-remote-key.js +83 -0
  562. package/template/shared/host-identity.js +98 -2
  563. package/template/shared/linked-worktree.js +51 -0
  564. package/template/shared/macos-fda-target.js +57 -0
  565. package/template/shared/orphan-parents.js +55 -0
  566. package/template/shared/owner-write-safety.js +135 -0
  567. package/template/shared/public-runtime.js +13 -5
  568. package/template/shared/release-schema.json +3 -2
  569. package/template/shared/report-citations.js +14 -0
  570. package/template/shared/sqlite-write-lock.js +361 -223
  571. package/template/shared/storage/contract.js +38 -3
  572. package/template/wall-e/adapters/imessage.js +12 -0
  573. package/template/wall-e/agent.js +92 -4
  574. package/template/wall-e/api-walle.js +26 -1
  575. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  576. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
  577. package/template/wall-e/bin/walle-mcp-stdio.js +14 -8
  578. package/template/wall-e/brain/brain-join.js +859 -0
  579. package/template/wall-e/brain/brain-sync-membership.js +20 -0
  580. package/template/wall-e/brain/brain-sync-store.js +131 -77
  581. package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
  582. package/template/wall-e/brain/brain-sync-v2.js +578 -0
  583. package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
  584. package/template/wall-e/brain/deterministic-id.js +51 -0
  585. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  586. package/template/wall-e/brain/memories.js +2 -2
  587. package/template/wall-e/brain/migrations.js +91 -28
  588. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  589. package/template/wall-e/brain/model-identity-migration.js +1 -1
  590. package/template/wall-e/brain/owner-call-whitelist.js +39 -7
  591. package/template/wall-e/brain/schema-ensures.js +22 -0
  592. package/template/wall-e/brain/schema.js +45 -85
  593. package/template/wall-e/brain.js +172 -36
  594. package/template/wall-e/chat.js +3 -3
  595. package/template/wall-e/coding/agent-shell-env.js +7 -2
  596. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  597. package/template/wall-e/coding/prompt-bundle.js +66 -21
  598. package/template/wall-e/coding/session-journal.js +28 -40
  599. package/template/wall-e/coding-orchestrator.js +23 -26
  600. package/template/wall-e/config/main-loop-exemptions.json +2 -2
  601. package/template/wall-e/http/admin-api.js +37 -0
  602. package/template/wall-e/http/auth.js +18 -1
  603. package/template/wall-e/http/blog-views-api.js +318 -0
  604. package/template/wall-e/http/gws-api.js +4 -0
  605. package/template/wall-e/http/helper-rules-api.js +327 -0
  606. package/template/wall-e/http/model-admin.js +8 -1
  607. package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
  608. package/template/wall-e/http/model-proxy-providers.js +177 -2
  609. package/template/wall-e/http/model-route-health.js +157 -0
  610. package/template/wall-e/http/sync-api.js +278 -464
  611. package/template/wall-e/http/telemetry-api.js +12 -0
  612. package/template/wall-e/jobs/job-runner.js +28 -1
  613. package/template/wall-e/lib/blog-view-policy.js +88 -0
  614. package/template/wall-e/lib/blog-view-store.js +169 -0
  615. package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
  616. package/template/wall-e/lib/client-config-lock.js +2 -1
  617. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  618. package/template/wall-e/lib/ctm-data-dir.js +26 -0
  619. package/template/wall-e/lib/derivation-home.js +147 -0
  620. package/template/wall-e/lib/error-kinds.js +10 -1
  621. package/template/wall-e/lib/feature-manifest.js +1 -1
  622. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  623. package/template/wall-e/lib/helper-rules/evaluate.js +398 -0
  624. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  625. package/template/wall-e/lib/helper-rules/grade.js +320 -0
  626. package/template/wall-e/lib/helper-rules/label.js +247 -0
  627. package/template/wall-e/lib/helper-rules/lead-call-hook.js +555 -0
  628. package/template/wall-e/lib/helper-rules/store.js +669 -0
  629. package/template/wall-e/lib/landing-mcp-tools.js +170 -0
  630. package/template/wall-e/lib/mcp-client-config.js +133 -14
  631. package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
  632. package/template/wall-e/lib/mcp-integration.js +63 -19
  633. package/template/wall-e/lib/parent-death.js +7 -1
  634. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  635. package/template/wall-e/lib/scheduler-worker-jobs.js +12 -4
  636. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  637. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  638. package/template/wall-e/llm/default-fallback.js +4 -0
  639. package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
  640. package/template/wall-e/llm/delegate-vendor-default.js +12 -5
  641. package/template/wall-e/llm/model-catalog.js +13 -4
  642. package/template/wall-e/llm/model-roles.js +7 -1
  643. package/template/wall-e/llm/native-delegate-selection.js +56 -8
  644. package/template/wall-e/llm/portkey-http.js +150 -0
  645. package/template/wall-e/llm/portkey-sync.js +15 -145
  646. package/template/wall-e/llm/worker-delegate-args.js +72 -7
  647. package/template/wall-e/llm/worker-mcp-routing.js +117 -7
  648. package/template/wall-e/llm/worker-route.js +43 -1
  649. package/template/wall-e/loops/brain-custom-writes.js +64 -0
  650. package/template/wall-e/loops/ingest.js +17 -1
  651. package/template/wall-e/loops/think.js +19 -4
  652. package/template/wall-e/mcp-contract.js +222 -6
  653. package/template/wall-e/mcp-protocol-contract.js +77 -2
  654. package/template/wall-e/mcp-server.js +141 -31
  655. package/template/wall-e/mcp-worker-schemas.js +25 -7
  656. package/template/wall-e/memory/ctm-context-client.js +110 -5
  657. package/template/wall-e/memory/ctm-session-context.js +9 -3
  658. package/template/wall-e/memory/hub-bridge-client.js +388 -0
  659. package/template/wall-e/memory/replica-origin.js +56 -0
  660. package/template/wall-e/memory/session-pool.js +135 -0
  661. package/template/wall-e/runtime/live-capabilities.js +8 -3
  662. package/template/wall-e/server.js +4 -2
  663. package/template/wall-e/shared/release-schema.json +3 -2
  664. package/template/wall-e/shared/sqlite-file-set.js +39 -0
  665. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  666. package/template/wall-e/shared/storage/contract.js +38 -3
  667. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  668. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +13 -1
  669. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +11 -6
  670. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +13 -8
  671. package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
  672. package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
  673. package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
  674. package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
  675. package/template/wall-e/tools/chrome-automation.js +6 -0
  676. package/template/wall-e/tools/local-tools.js +6 -4
  677. package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
  678. package/template/wall-e/workers/brain-owner-worker.js +27 -4
  679. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  680. package/template/wall-e/workers/mcp-gateway-process.js +5 -5
  681. package/template/wall-e/workers/telemetry-worker.js +8 -0
@@ -18,6 +18,31 @@
18
18
  // all three move here VERBATIM (misc-ops.js's workspace handlers are the
19
19
  // precedent for a verbatim body living alongside dispatch-only wiring in the
20
20
  // same module).
21
+ //
22
+ // Landing-throughput WP-5 shard S2 (design doc §5 D-10 "move-only", §6 "Shard
23
+ // module seam", §8 WP-5, §9 S-21..S-27): three more setup handlers move out of
24
+ // server.js VERBATIM -- apiSetupTestKey (GET /api/setup/test-key),
25
+ // apiSetupDetectKey (GET /api/setup/detect-key) and apiSetupSave
26
+ // (POST /api/setup/save). Each body is identical to server.js's declaration
27
+ // except for the `_deps.` prefix on every identifier that used to resolve to a
28
+ // server.js top-level binding (D-10 rule 1), proven by
29
+ // `node bin/move-only-check.js`. Injected deps, per function:
30
+ // apiSetupTestKey: CONFIG_DIR, MODEL_PROBE_ORDER, codexPaths, fs,
31
+ // getWalleStatusData, hostIdentityAccessAllowed, missingBinaryChild,
32
+ // oauthProxySupervisor, probeModel, resolveAgentCliCommand,
33
+ // sanitizeSetupProviderType, serverConfig, walleClient
34
+ // apiSetupDetectKey: CONFIG_DIR, codexPaths, execFileSync, fs,
35
+ // hostIdentityAccessAllowed, path, probeModel, readUserShellEnv,
36
+ // resolveAgentCliCommand, sanitizeSetupProviderType, serverConfig
37
+ // apiSetupSave: CONFIG_DIR, SETUP_PROVIDER_TYPES, __dirname,
38
+ // atomicWriteFileSync, fs, path, resolveEnvFilePath,
39
+ // sanitizeSetupProviderType, serverConfig, setup, setupProviderTypeList,
40
+ // telemetry, walleClient, walleSupervisor
41
+ // `__dirname` is injected although it is NOT a server.js top-level binding: it
42
+ // is the CommonJS wrapper parameter, so left bare in this file it would resolve
43
+ // to lib/api/ instead of server.js's own directory and silently change
44
+ // resolveEnvFilePath's repoRoot (D-10 rule 9, "behaviour: none changes"). It is
45
+ // passed by value, same as every immutable binding.
21
46
 
22
47
  const { registerApiRoutes } = require('../api-router');
23
48
 
@@ -25,15 +50,12 @@ let _deps = null;
25
50
 
26
51
  function configure({
27
52
  apiSetupStatus,
28
- apiSetupTestKey,
29
53
  apiSetupDetectCodexCli,
30
- apiSetupDetectKey,
31
54
  apiSetupDetectGeminiCli,
32
55
  apiSetupDetectClaudeCli,
33
56
  apiSetupOauthProxyStart,
34
57
  apiSetupOauthProxyStop,
35
58
  apiSetupOauthProxyStatus,
36
- apiSetupSave,
37
59
  apiSetupProviders,
38
60
  apiSetupSaveProvider,
39
61
  apiSetupTestProvider,
@@ -49,18 +71,40 @@ function configure({
49
71
  listWalleModelsViaOwner,
50
72
  walleOwnerWrite,
51
73
  serverConfig,
74
+ // WP-5 shard S2 move-only deps (see this file's header): the top-level
75
+ // server.js bindings apiSetupTestKey/apiSetupDetectKey/apiSetupSave used to
76
+ // close over. Immutable bindings, passed by value; `__dirname` is
77
+ // server.js's own module-wrapper directory (see header).
78
+ CONFIG_DIR,
79
+ MODEL_PROBE_ORDER,
80
+ codexPaths,
81
+ execFileSync,
82
+ fs,
83
+ path,
84
+ getWalleStatusData,
85
+ hostIdentityAccessAllowed,
86
+ missingBinaryChild,
87
+ oauthProxySupervisor,
88
+ probeModel,
89
+ readUserShellEnv,
90
+ resolveAgentCliCommand,
91
+ atomicWriteFileSync,
92
+ resolveEnvFilePath,
93
+ setup,
94
+ setupProviderTypeList,
95
+ telemetry,
96
+ walleClient,
97
+ walleSupervisor,
98
+ __dirname,
52
99
  } = {}) {
53
100
  _deps = {
54
101
  apiSetupStatus,
55
- apiSetupTestKey,
56
102
  apiSetupDetectCodexCli,
57
- apiSetupDetectKey,
58
103
  apiSetupDetectGeminiCli,
59
104
  apiSetupDetectClaudeCli,
60
105
  apiSetupOauthProxyStart,
61
106
  apiSetupOauthProxyStop,
62
107
  apiSetupOauthProxyStatus,
63
- apiSetupSave,
64
108
  apiSetupProviders,
65
109
  apiSetupSaveProvider,
66
110
  apiSetupTestProvider,
@@ -76,6 +120,27 @@ function configure({
76
120
  listWalleModelsViaOwner,
77
121
  walleOwnerWrite,
78
122
  serverConfig,
123
+ CONFIG_DIR,
124
+ MODEL_PROBE_ORDER,
125
+ codexPaths,
126
+ execFileSync,
127
+ fs,
128
+ path,
129
+ getWalleStatusData,
130
+ hostIdentityAccessAllowed,
131
+ missingBinaryChild,
132
+ oauthProxySupervisor,
133
+ probeModel,
134
+ readUserShellEnv,
135
+ resolveAgentCliCommand,
136
+ atomicWriteFileSync,
137
+ resolveEnvFilePath,
138
+ setup,
139
+ setupProviderTypeList,
140
+ telemetry,
141
+ walleClient,
142
+ walleSupervisor,
143
+ __dirname,
79
144
  };
80
145
  }
81
146
 
@@ -226,15 +291,15 @@ async function handleSetupModelsByType(req, res, type) {
226
291
  function register() {
227
292
  registerApiRoutes('setup', [
228
293
  { method: 'GET', path: '/api/setup/status', handler: (req, res, url) => _deps.apiSetupStatus(req, res, url) },
229
- { method: 'GET', path: '/api/setup/test-key', handler: (req, res, url) => _deps.apiSetupTestKey(req, res, url) },
294
+ { method: 'GET', path: '/api/setup/test-key', handler: (req, res, url) => apiSetupTestKey(req, res, url) },
230
295
  { method: 'GET', path: '/api/setup/detect-codex-cli', handler: (req, res, url) => _deps.apiSetupDetectCodexCli(req, res, url) },
231
- { method: 'GET', path: '/api/setup/detect-key', handler: (req, res, url) => _deps.apiSetupDetectKey(req, res, url) },
296
+ { method: 'GET', path: '/api/setup/detect-key', handler: (req, res, url) => apiSetupDetectKey(req, res, url) },
232
297
  { method: 'GET', path: '/api/setup/detect-gemini-cli', handler: (req, res, url) => _deps.apiSetupDetectGeminiCli(req, res, url) },
233
298
  { method: 'GET', path: '/api/setup/detect-claude-cli', handler: (req, res, url) => _deps.apiSetupDetectClaudeCli(req, res, url) },
234
299
  { method: 'POST', path: '/api/setup/oauth-proxy/start', handler: (req, res, url) => _deps.apiSetupOauthProxyStart(req, res, url) },
235
300
  { method: 'POST', path: '/api/setup/oauth-proxy/stop', handler: (req, res, url) => _deps.apiSetupOauthProxyStop(req, res, url) },
236
301
  { method: 'GET', path: '/api/setup/oauth-proxy/status', handler: (req, res, url) => _deps.apiSetupOauthProxyStatus(req, res, url) },
237
- { method: 'POST', path: '/api/setup/save', handler: (req, res, url) => _deps.apiSetupSave(req, res, url) },
302
+ { method: 'POST', path: '/api/setup/save', handler: (req, res, url) => apiSetupSave(req, res, url) },
238
303
  { method: 'GET', path: '/api/setup/providers', handler: (req, res, url) => _deps.apiSetupProviders(req, res, url) },
239
304
  { method: 'POST', path: '/api/setup/save-provider', handler: (req, res, url) => _deps.apiSetupSaveProvider(req, res, url) },
240
305
  { method: 'POST', path: '/api/setup/test-provider', handler: (req, res, url) => _deps.apiSetupTestProvider(req, res, url) },
@@ -267,4 +332,758 @@ function register() {
267
332
  ]);
268
333
  }
269
334
 
270
- module.exports = { configure, register };
335
+ async function apiSetupTestKey(req, res, url) {
336
+ const providerParam = _deps.sanitizeSetupProviderType(url.searchParams.get('provider') || '');
337
+ const authMethodParam = url.searchParams.get('auth_method') || '';
338
+ const walleStatus = await _deps.getWalleStatusData().catch(() => ({}));
339
+ const walleProvider = walleStatus.walle_provider || 'anthropic';
340
+ const walleModel = walleStatus.walle_model || '';
341
+
342
+ // ── auth_method=claude_cli: shell out to `claude auth status` (JSON
343
+ // output, no API call, no tokens burned). Tells us whether the CLI
344
+ // is installed AND authenticated, plus the user's email + plan.
345
+ if (providerParam === 'anthropic' && authMethodParam === 'claude_cli') {
346
+ const respond = (data) => {
347
+ res.writeHead(200, { 'Content-Type': 'application/json' });
348
+ res.end(JSON.stringify(data));
349
+ };
350
+ const { spawn } = require('child_process');
351
+ // Scrub ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN so the CLI reports the
352
+ // subscription auth (claude.ai login) we actually want to validate
353
+ // here — otherwise it just echoes back "apiKeySource": "ANTHROPIC_API_KEY"
354
+ // and we'd be testing the wrong path.
355
+ const childEnv = { ...process.env };
356
+ delete childEnv.ANTHROPIC_API_KEY;
357
+ delete childEnv.ANTHROPIC_AUTH_TOKEN;
358
+ let proc;
359
+ try {
360
+ proc = spawn(_deps.resolveAgentCliCommand('claude'), ['auth', 'status'], {
361
+ stdio: ['ignore', 'pipe', 'pipe'],
362
+ timeout: 15000,
363
+ env: childEnv,
364
+ });
365
+ } catch (err) {
366
+ return respond({ ok: false, error: 'Could not spawn claude: ' + err.message });
367
+ }
368
+ let stdout = '';
369
+ let stderr = '';
370
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
371
+ proc.stderr.on('data', (d) => { stderr += d.toString(); });
372
+ proc.on('error', (err) => {
373
+ respond({
374
+ ok: false,
375
+ error: err.code === 'ENOENT'
376
+ ? 'claude CLI not on PATH. Install Claude Code from claude.com/claude-code.'
377
+ : 'spawn failed: ' + err.message,
378
+ });
379
+ });
380
+ proc.on('close', (code) => {
381
+ if (code !== 0) {
382
+ return respond({ ok: false, error: 'claude auth status exited ' + code + ': ' + (stderr || stdout).slice(0, 300) });
383
+ }
384
+ let parsed;
385
+ try {
386
+ parsed = JSON.parse(stdout);
387
+ } catch (parseErr) {
388
+ return respond({ ok: false, error: 'claude auth status stdout not JSON: ' + stdout.slice(0, 200) });
389
+ }
390
+ if (!parsed.loggedIn) {
391
+ return respond({ ok: false, error: 'CLI installed but not signed in. Run `claude auth login`.' });
392
+ }
393
+ // Display "email · subscription" e.g. "user@example.com · pro"
394
+ const label = [parsed.email, parsed.subscriptionType].filter(Boolean).join(' · ');
395
+ respond({ ok: true, model: label || 'claude.ai', reply: parsed.authMethod || 'subscription' });
396
+ });
397
+ return;
398
+ }
399
+
400
+ // ── auth_method=oauth_proxy: probe the running proxy on its loopback
401
+ // port, then send a minimal /v1/messages request through it. Flips
402
+ // `running=false` to a clear error so the user knows to enable it.
403
+ if (providerParam === 'anthropic' && authMethodParam === 'oauth_proxy') {
404
+ const respond = (data) => {
405
+ res.writeHead(200, { 'Content-Type': 'application/json' });
406
+ res.end(JSON.stringify(data));
407
+ };
408
+ const proxyStatus = await _deps.oauthProxySupervisor.status();
409
+ if (!proxyStatus.running) {
410
+ return respond({ ok: false, error: 'OAuth proxy is not running yet. Save the Anthropic card to start it, then test again.', proxy_status: proxyStatus, remediation: 'save_provider' });
411
+ }
412
+ const port = proxyStatus.port;
413
+ try {
414
+ const r = await fetch(`http://127.0.0.1:${port}/v1/messages`, {
415
+ method: 'POST',
416
+ headers: {
417
+ 'Content-Type': 'application/json',
418
+ 'anthropic-version': '2023-06-01',
419
+ },
420
+ body: JSON.stringify({
421
+ model: 'claude-haiku-4-5-20251001',
422
+ max_tokens: 20,
423
+ messages: [{ role: 'user', content: 'reply with the literal string OK and nothing else' }],
424
+ }),
425
+ signal: AbortSignal.timeout(20000),
426
+ });
427
+ if (!r.ok) {
428
+ const txt = await r.text().catch(() => '');
429
+ return respond({ ok: false, error: `Proxy returned ${r.status}: ${txt.slice(0, 250)}` });
430
+ }
431
+ const d = await r.json();
432
+ const reply = (d.content || []).filter((b) => b.type === 'text').map((b) => b.text).join('').trim();
433
+ return respond({
434
+ ok: reply.length > 0,
435
+ model: d.model || 'claude-haiku-4-5',
436
+ reply: reply.slice(0, 50),
437
+ });
438
+ } catch (err) {
439
+ return respond({ ok: false, error: 'Proxy probe failed: ' + err.message });
440
+ }
441
+ }
442
+
443
+ const _testStoredProvider = async (type, fallbackModel, extraBody = {}) => {
444
+ try {
445
+ const providersResp = await _deps.walleClient.requestJson('/api/models/providers');
446
+ const providers = Array.isArray(providersResp.json?.providers) ? providersResp.json.providers : [];
447
+ const keylessProvider = type === 'ollama' || type === 'mlx';
448
+ const provider = providers.find((item) => item.type === type && item.enabled !== 0 && (keylessProvider || item.has_key));
449
+ if (!provider) return null;
450
+ const testResp = await _deps.walleClient.requestJson('/api/models/test-connection', {
451
+ method: 'POST',
452
+ body: { type, instance_id: provider.id, ...extraBody },
453
+ });
454
+ if (testResp.status >= 200 && testResp.status < 300 && testResp.json?.ok) {
455
+ const firstModel = Array.isArray(testResp.json.models) && testResp.json.models[0]?.id;
456
+ return { ok: true, model: testResp.json.probe?.model || firstModel || fallbackModel, probe: testResp.json.probe || null };
457
+ }
458
+ return { ok: false, error: testResp.json?.error || 'Provider not available', probe: testResp.json?.probe || null };
459
+ } catch {
460
+ return null;
461
+ }
462
+ };
463
+
464
+ // ── Ollama test (local runtime, no API key) ──
465
+ if (providerParam === 'ollama') {
466
+ const ollamaModel = (walleProvider === 'ollama' && walleModel) ? walleModel : (url.searchParams.get('model') || process.env.OLLAMA_MODEL || 'gemma4:e4b');
467
+ const stored = await _testStoredProvider('ollama', ollamaModel, { model: ollamaModel });
468
+ if (stored) {
469
+ res.writeHead(200, { 'Content-Type': 'application/json' });
470
+ res.end(JSON.stringify(stored));
471
+ return;
472
+ }
473
+ try {
474
+ const testResp = await _deps.walleClient.requestJson('/api/models/test-connection', {
475
+ method: 'POST',
476
+ body: {
477
+ type: 'ollama',
478
+ model: ollamaModel,
479
+ baseUrl: process.env.OLLAMA_BASE_URL || 'http://127.0.0.1:11434',
480
+ },
481
+ });
482
+ res.writeHead(200, { 'Content-Type': 'application/json' });
483
+ if (testResp.status >= 200 && testResp.status < 300 && testResp.json?.ok) {
484
+ res.end(JSON.stringify({
485
+ ok: true,
486
+ model: testResp.json.probe?.model || ollamaModel,
487
+ probe: testResp.json.probe || null,
488
+ }));
489
+ } else {
490
+ res.end(JSON.stringify({
491
+ ok: false,
492
+ error: testResp.json?.error || `Ollama probe failed with HTTP ${testResp.status}`,
493
+ probe: testResp.json?.probe || null,
494
+ }));
495
+ }
496
+ } catch (e) {
497
+ res.writeHead(200, { 'Content-Type': 'application/json' });
498
+ res.end(JSON.stringify({ ok: false, error: e.message }));
499
+ }
500
+ return;
501
+ }
502
+
503
+ // ── Google key test ──
504
+ if (providerParam === 'google') {
505
+ const googleKey = _deps.serverConfig.GOOGLE_API_KEY || '';
506
+ if (!googleKey) {
507
+ const stored = await _testStoredProvider('google', 'gemini-2.5-flash');
508
+ res.writeHead(200, { 'Content-Type': 'application/json' });
509
+ res.end(JSON.stringify(stored || { ok: false, error: 'No Google API key configured.' }));
510
+ return;
511
+ }
512
+ // Detect stale ya29 access tokens — these are short-lived and can't be refreshed without GOOGLE_AUTH_MODE=oauth
513
+ if (googleKey.startsWith('ya29.') && _deps.serverConfig.GOOGLE_AUTH_MODE !== 'oauth') {
514
+ res.writeHead(200, { 'Content-Type': 'application/json' });
515
+ res.end(JSON.stringify({ ok: false, error: 'Stored key is a stale Gemini CLI OAuth token (ya29.*). Get an API key from aistudio.google.com/apikey or use "Use Gemini CLI Credentials" on the setup page.' }));
516
+ return;
517
+ }
518
+ const isOAuth = _deps.serverConfig.GOOGLE_AUTH_MODE === 'oauth';
519
+ const testUrl = isOAuth
520
+ ? 'https://generativelanguage.googleapis.com/v1beta/models?pageSize=1'
521
+ : `https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(googleKey)}&pageSize=1`;
522
+ const headers = isOAuth ? { 'Authorization': `Bearer ${googleKey}` } : {};
523
+ const googleModel = (walleProvider === 'google' && walleModel && walleModel.startsWith('gemini')) ? walleModel : 'gemini-2.5-flash';
524
+ fetch(testUrl, { headers }).then(async (resp) => {
525
+ res.writeHead(200, { 'Content-Type': 'application/json' });
526
+ if (resp.ok) { res.end(JSON.stringify({ ok: true, model: googleModel })); }
527
+ else { const body = await resp.json().catch(() => ({})); res.end(JSON.stringify({ ok: false, error: body?.error?.message || `HTTP ${resp.status}` })); }
528
+ }).catch(e => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); });
529
+ return;
530
+ }
531
+
532
+ // ── OpenAI codex_cli test: shell out to `codex login status` (free, no
533
+ // API call, no tokens). Mirrors anthropic's claude_cli test pattern.
534
+ if (providerParam === 'openai' && authMethodParam === 'codex_cli') {
535
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
536
+ const spawn = _deps.hostIdentityAccessAllowed({ configDir: _deps.CONFIG_DIR }) ? require('child_process').spawn : _deps.missingBinaryChild;
537
+ const childEnv = { ...process.env };
538
+ delete childEnv.OPENAI_API_KEY; // force ChatGPT subscription path
539
+ let proc;
540
+ try {
541
+ proc = spawn(_deps.resolveAgentCliCommand('codex'), ['login', 'status'], { stdio: ['ignore', 'pipe', 'pipe'], timeout: 10000, env: childEnv });
542
+ } catch (err) {
543
+ return respond({ ok: false, error: 'Could not spawn codex: ' + err.message });
544
+ }
545
+ let stdout = '';
546
+ let stderr = '';
547
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
548
+ proc.stderr.on('data', (d) => { stderr += d.toString(); });
549
+ proc.on('error', (err) => {
550
+ respond({
551
+ ok: false,
552
+ error: err.code === 'ENOENT'
553
+ ? 'codex CLI not on PATH. Install Codex from chatgpt.com/codex.'
554
+ : 'spawn failed: ' + err.message,
555
+ });
556
+ });
557
+ proc.on('close', (code) => {
558
+ if (code !== 0) {
559
+ return respond({ ok: false, error: 'codex login status exited ' + code + ': ' + (stderr || stdout).slice(0, 300) });
560
+ }
561
+ // codex login status prints to stderr; combine streams for the match.
562
+ const combined = stdout + '\n' + stderr;
563
+ const loggedIn = /logged in/i.test(combined);
564
+ if (!loggedIn) {
565
+ return respond({ ok: false, error: 'Codex installed but not logged in. Run `codex login`.' });
566
+ }
567
+ // Parse plan from auth.json JWT (best-effort, same as detect)
568
+ let plan = null;
569
+ try {
570
+ const auth = JSON.parse(_deps.fs.readFileSync(_deps.codexPaths.codexAuthPath(), 'utf8'));
571
+ const accessToken = auth?.tokens?.access_token;
572
+ if (accessToken) {
573
+ const parts = accessToken.split('.');
574
+ if (parts.length >= 2) {
575
+ const pad = '='.repeat((-parts[1].length) & 3);
576
+ const payload = JSON.parse(Buffer.from(parts[1] + pad, 'base64url').toString('utf8'));
577
+ plan = payload?.['https://api.openai.com/auth']?.chatgpt_plan_type || null;
578
+ }
579
+ }
580
+ } catch { /* best-effort */ }
581
+ const emailMatch = combined.match(/[\w.+-]+@[\w-]+\.[\w.-]+/);
582
+ const label = [emailMatch ? emailMatch[0] : null, plan].filter(Boolean).join(' · ');
583
+ respond({ ok: true, model: label || 'ChatGPT subscription', reply: 'codex' });
584
+ });
585
+ return;
586
+ }
587
+
588
+ // ── DeepSeek key test (api_key — direct API, OpenAI-compatible) ──
589
+ if (providerParam === 'deepseek') {
590
+ const deepseekKey = _deps.serverConfig.DEEPSEEK_API_KEY || '';
591
+ if (!deepseekKey) {
592
+ const stored = await _testStoredProvider('deepseek', 'deepseek-v4-flash');
593
+ res.writeHead(200, { 'Content-Type': 'application/json' });
594
+ res.end(JSON.stringify(stored || { ok: false, error: 'No DeepSeek API key configured.' }));
595
+ return;
596
+ }
597
+ const dsModel = (walleProvider === 'deepseek' && walleModel && /^deepseek-/.test(walleModel)) ? walleModel : 'deepseek-v4-flash';
598
+ // /models is OpenAI-compatible at api.deepseek.com — single GET, no token burn.
599
+ fetch('https://api.deepseek.com/v1/models', { headers: { 'Authorization': `Bearer ${deepseekKey}` } }).then(async (resp) => {
600
+ res.writeHead(200, { 'Content-Type': 'application/json' });
601
+ if (resp.ok) { res.end(JSON.stringify({ ok: true, model: dsModel })); }
602
+ else { const body = await resp.json().catch(() => ({})); res.end(JSON.stringify({ ok: false, error: body?.error?.message || `HTTP ${resp.status}` })); }
603
+ }).catch(e => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); });
604
+ return;
605
+ }
606
+
607
+ // ── Moonshot / Kimi key test (api_key — direct API, OpenAI-compatible) ──
608
+ if (providerParam === 'moonshot') {
609
+ const moonshotKey = _deps.serverConfig.MOONSHOT_API_KEY || '';
610
+ if (!moonshotKey) {
611
+ const stored = await _testStoredProvider('moonshot', 'kimi-k2.6');
612
+ res.writeHead(200, { 'Content-Type': 'application/json' });
613
+ res.end(JSON.stringify(stored || { ok: false, error: 'No Moonshot API key configured.' }));
614
+ return;
615
+ }
616
+ const moonshotModel = (walleProvider === 'moonshot' && walleModel && /^(kimi-|moonshot-)/.test(walleModel)) ? walleModel : 'kimi-k2.6';
617
+ const base = process.env.MOONSHOT_BASE_URL || 'https://api.moonshot.ai/v1';
618
+ fetch(base.replace(/\/+$/, '') + '/models', { headers: { 'Authorization': `Bearer ${moonshotKey}` } }).then(async (resp) => {
619
+ res.writeHead(200, { 'Content-Type': 'application/json' });
620
+ if (resp.ok) { res.end(JSON.stringify({ ok: true, model: moonshotModel })); }
621
+ else { const body = await resp.json().catch(() => ({})); res.end(JSON.stringify({ ok: false, error: body?.error?.message || `HTTP ${resp.status}` })); }
622
+ }).catch(e => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); });
623
+ return;
624
+ }
625
+
626
+ // ── Z.AI key test (api_key — direct API, OpenAI-compatible) ──
627
+ if (providerParam === 'zai') {
628
+ const zaiKey = _deps.serverConfig.ZAI_API_KEY || '';
629
+ if (!zaiKey) {
630
+ const stored = await _testStoredProvider('zai', 'glm-5.2');
631
+ res.writeHead(200, { 'Content-Type': 'application/json' });
632
+ res.end(JSON.stringify(stored || { ok: false, error: 'No Z.AI API key configured.' }));
633
+ return;
634
+ }
635
+ const zaiModel = (walleProvider === 'zai' && walleModel && /^glm-/.test(walleModel)) ? walleModel : 'glm-5.2';
636
+ const base = process.env.ZAI_BASE_URL || 'https://api.z.ai/api/paas/v4/';
637
+ fetch(base.replace(/\/+$/, '') + '/models', { headers: { 'Authorization': `Bearer ${zaiKey}` } }).then(async (resp) => {
638
+ res.writeHead(200, { 'Content-Type': 'application/json' });
639
+ if (resp.ok) { res.end(JSON.stringify({ ok: true, model: zaiModel })); }
640
+ else { const body = await resp.json().catch(() => ({})); res.end(JSON.stringify({ ok: false, error: body?.error?.message || `HTTP ${resp.status}` })); }
641
+ }).catch(e => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); });
642
+ return;
643
+ }
644
+
645
+ // ── OpenAI key test (api_key — direct API) ──
646
+ if (providerParam === 'openai') {
647
+ const openaiKey = _deps.serverConfig.OPENAI_API_KEY || '';
648
+ if (!openaiKey) {
649
+ const stored = await _testStoredProvider('openai', 'gpt-4o-mini');
650
+ res.writeHead(200, { 'Content-Type': 'application/json' });
651
+ res.end(JSON.stringify(stored || { ok: false, error: 'No OpenAI API key configured.' }));
652
+ return;
653
+ }
654
+ const openaiModel = (walleProvider === 'openai' && walleModel && /^(gpt|o[1-9])/.test(walleModel)) ? walleModel : 'gpt-4o-mini';
655
+ fetch('https://api.openai.com/v1/models?limit=1', { headers: { 'Authorization': `Bearer ${openaiKey}` } }).then(async (resp) => {
656
+ res.writeHead(200, { 'Content-Type': 'application/json' });
657
+ if (resp.ok) { res.end(JSON.stringify({ ok: true, model: openaiModel })); }
658
+ else { const body = await resp.json().catch(() => ({})); res.end(JSON.stringify({ ok: false, error: body?.error?.message || `HTTP ${resp.status}` })); }
659
+ }).catch(e => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); });
660
+ return;
661
+ }
662
+
663
+ // ── Anthropic key test (default) ──
664
+ const apiKey = _deps.serverConfig.ANTHROPIC_API_KEY || _deps.serverConfig.ANTHROPIC_AUTH_TOKEN || '';
665
+ const baseUrl = _deps.serverConfig.ANTHROPIC_BASE_URL || 'https://api.anthropic.com';
666
+ const customHeadersB64 = _deps.serverConfig.ANTHROPIC_CUSTOM_HEADERS_B64 || '';
667
+ const configuredModel = _deps.MODEL_PROBE_ORDER[0];
668
+ if (!apiKey) {
669
+ const stored = await _testStoredProvider('anthropic', configuredModel);
670
+ if (stored) {
671
+ res.writeHead(200, { 'Content-Type': 'application/json' });
672
+ res.end(JSON.stringify(stored));
673
+ return;
674
+ }
675
+ res.writeHead(200, { 'Content-Type': 'application/json' });
676
+ res.end(JSON.stringify({ ok: false, error: 'No API key configured.' }));
677
+ return;
678
+ }
679
+ // Try the configured model first; only probe for an alternative if it fails.
680
+ // Build probe order with configured model at the front (deduplicated)
681
+ const probeOrder = [configuredModel, ..._deps.MODEL_PROBE_ORDER.filter(m => m !== configuredModel)];
682
+ _deps.probeModel(apiKey, baseUrl, customHeadersB64, probeOrder).then(({ model, authError }) => {
683
+ if (model) {
684
+ res.writeHead(200, { 'Content-Type': 'application/json' });
685
+ res.end(JSON.stringify({ ok: true, model }));
686
+ } else if (authError) {
687
+ res.writeHead(200, { 'Content-Type': 'application/json' });
688
+ res.end(JSON.stringify({ ok: false, error: 'Invalid API key — double-check the key and try again.' }));
689
+ } else {
690
+ res.writeHead(200, { 'Content-Type': 'application/json' });
691
+ res.end(JSON.stringify({ ok: false, error: 'No accessible model found for this key. Check that your key has inference permissions.' }));
692
+ }
693
+ }).catch(e => {
694
+ res.writeHead(200, { 'Content-Type': 'application/json' });
695
+ res.end(JSON.stringify({ ok: false, error: e.message }));
696
+ });
697
+ return;
698
+ }
699
+
700
+ async function apiSetupDetectKey(req, res, url) {
701
+ // Detect API credentials from external sources (NOT .env — that's what we're trying to populate).
702
+ // Provider-aware: ?provider=openai|google|anthropic. Defaults to anthropic for back-compat.
703
+ const detectProvider = _deps.sanitizeSetupProviderType(url.searchParams.get('provider') || 'anthropic') || 'anthropic';
704
+
705
+ // Helper: read a shell env var via the user's login shell so we get values
706
+ // sourced from .zshrc / .bashrc / etc., not just our parent process.
707
+ const readShellEnv = (varName) => {
708
+ return _deps.readUserShellEnv(varName, 6);
709
+ };
710
+
711
+ // ── OpenAI branch: shell env OPENAI_API_KEY → fallback to codex CLI suggestion
712
+ if (detectProvider === 'openai') {
713
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
714
+ const openaiKey = readShellEnv('OPENAI_API_KEY');
715
+ if (openaiKey && openaiKey.startsWith('sk-')) {
716
+ return respond({ found: true, key: openaiKey, source: 'shell environment (OPENAI_API_KEY)', provider: 'openai' });
717
+ }
718
+ // No API key — probe codex CLI as a Strategy-2 (subscription) suggestion.
719
+ try {
720
+ if (!_deps.hostIdentityAccessAllowed({ configDir: _deps.CONFIG_DIR })) throw new Error('host identity access not allowed');
721
+ const proc = require('child_process').spawnSync(_deps.resolveAgentCliCommand('codex'), ['login', 'status'], { encoding: 'utf8', timeout: 8000 });
722
+ if (proc.status === 0) {
723
+ const stdout = (proc.stdout || '').trim();
724
+ // Output is freeform like "Logged in using ChatGPT". Surface presence + try to parse account email.
725
+ const emailMatch = stdout.match(/[\w.+-]+@[\w-]+\.[\w.-]+/);
726
+ let plan = null;
727
+ try {
728
+ const auth = JSON.parse(require('fs').readFileSync(_deps.codexPaths.codexAuthPath(), 'utf8'));
729
+ const accessToken = auth?.tokens?.access_token;
730
+ if (accessToken) {
731
+ const parts = accessToken.split('.');
732
+ if (parts.length >= 2) {
733
+ const pad = '='.repeat((-parts[1].length) & 3);
734
+ const payload = JSON.parse(Buffer.from(parts[1] + pad, 'base64url').toString('utf8'));
735
+ plan = payload?.['https://api.openai.com/auth']?.chatgpt_plan_type || null;
736
+ }
737
+ }
738
+ } catch { /* best-effort */ }
739
+ return respond({
740
+ found: false,
741
+ provider: 'openai',
742
+ codex_available: true,
743
+ codex_status: stdout,
744
+ codex_email: emailMatch ? emailMatch[0] : null,
745
+ codex_plan: plan,
746
+ hint: 'No OPENAI_API_KEY in shell env. Codex CLI is logged in — use it for subscription billing instead.',
747
+ });
748
+ }
749
+ } catch { /* codex not on PATH — fine */ }
750
+ return respond({ found: false, provider: 'openai', hint: 'No OPENAI_API_KEY in shell env. Get a key at platform.openai.com OR install Codex CLI from chatgpt.com/codex' });
751
+ }
752
+
753
+ // ── DeepSeek branch: shell env DEEPSEEK_API_KEY only (no CLI subscription path).
754
+ if (detectProvider === 'deepseek') {
755
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
756
+ const dsKey = readShellEnv('DEEPSEEK_API_KEY');
757
+ if (dsKey && dsKey.startsWith('sk-')) {
758
+ return respond({ found: true, key: dsKey, source: 'shell environment (DEEPSEEK_API_KEY)', provider: 'deepseek' });
759
+ }
760
+ return respond({ found: false, provider: 'deepseek', hint: 'No DEEPSEEK_API_KEY in shell env. Get a key at platform.deepseek.com (prepaid — top up first).' });
761
+ }
762
+
763
+ // ── Moonshot / Kimi branch: shell env MOONSHOT_API_KEY only.
764
+ if (detectProvider === 'moonshot') {
765
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
766
+ const moonshotKey = readShellEnv('MOONSHOT_API_KEY');
767
+ if (moonshotKey) {
768
+ return respond({ found: true, key: moonshotKey, source: 'shell environment (MOONSHOT_API_KEY)', provider: 'moonshot' });
769
+ }
770
+ return respond({ found: false, provider: 'moonshot', hint: 'No MOONSHOT_API_KEY in shell env. Get a key from the Kimi Open Platform console.' });
771
+ }
772
+
773
+ // ── Z.AI branch: shell env ZAI_API_KEY only.
774
+ if (detectProvider === 'zai') {
775
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
776
+ const zaiKey = readShellEnv('ZAI_API_KEY');
777
+ if (zaiKey) {
778
+ return respond({ found: true, key: zaiKey, source: 'shell environment (ZAI_API_KEY)', provider: 'zai' });
779
+ }
780
+ return respond({ found: false, provider: 'zai', hint: 'No ZAI_API_KEY in shell env. Get a key from the Z.AI Open Platform.' });
781
+ }
782
+
783
+ // ── Google branch: shell env GOOGLE_API_KEY / GEMINI_API_KEY → fallback to Gemini CLI OAuth
784
+ if (detectProvider === 'google') {
785
+ const respond = (data) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); };
786
+ const googleKey = readShellEnv('GOOGLE_API_KEY') || readShellEnv('GEMINI_API_KEY');
787
+ if (googleKey && !googleKey.startsWith('ya29.')) {
788
+ const which = readShellEnv('GOOGLE_API_KEY') ? 'GOOGLE_API_KEY' : 'GEMINI_API_KEY';
789
+ return respond({ found: true, key: googleKey, source: `shell environment (${which})`, provider: 'google' });
790
+ }
791
+ // Fallback to Gemini CLI's OAuth file (existing /api/setup/detect-gemini-cli handles this richly).
792
+ return respond({ found: false, provider: 'google', hint: 'No GOOGLE_API_KEY/GEMINI_API_KEY in shell env. Use the Gemini CLI auto-detection if installed, or get a key at aistudio.google.com/apikey' });
793
+ }
794
+
795
+ // ── Anthropic branch: existing logic (devbox / Keychain / shell env). Falls through.
796
+ let key = '';
797
+ let source = '';
798
+ let gateway = null;
799
+
800
+ // 1. Devbox corporate gateway (reads auth headers file directly)
801
+ if (process.platform === 'darwin') {
802
+ try {
803
+ const authFile = _deps.path.join(_deps.serverConfig.HOME, '.devbox', 'secrets', 'claude', 'auth_headers');
804
+ const headers = _deps.fs.readFileSync(authFile, 'utf8').trim();
805
+ if (headers) {
806
+ let baseUrl = '';
807
+ try {
808
+ const claudeScript = _deps.fs.readFileSync(_deps.path.join(_deps.serverConfig.HOME, '.devbox', 'ai', 'claude', 'claude'), 'utf8');
809
+ const m = claudeScript.match(/VPN_CHECK_URL="(https?:\/\/[^"]+)"/);
810
+ if (m) baseUrl = m[1] + '/v1';
811
+ } catch {}
812
+ if (baseUrl) {
813
+ gateway = {
814
+ base_url: baseUrl,
815
+ auth_token: 'sk-ant-api03-unused',
816
+ custom_headers_b64: Buffer.from(headers).toString('base64'),
817
+ };
818
+ source = 'Claude Code devbox (' + baseUrl.replace(/https?:\/\//, '').split('/')[0] + ')';
819
+ }
820
+ }
821
+ } catch {}
822
+ }
823
+
824
+ // 2. Claude Code OAuth token from macOS Keychain (checked before shell env — always freshest)
825
+ if (!gateway && !key && process.platform === 'darwin' && _deps.hostIdentityAccessAllowed({ configDir: _deps.CONFIG_DIR })) {
826
+ try {
827
+ const credJson = _deps.execFileSync('security', ['find-generic-password', '-s', 'Claude Code-credentials', '-w'], { encoding: 'utf8', timeout: 3000 }).trim();
828
+ if (credJson) {
829
+ const cred = JSON.parse(credJson);
830
+ const oauth = cred.claudeAiOauth;
831
+ if (oauth && oauth.accessToken) {
832
+ const expired = oauth.expiresAt && oauth.expiresAt < Date.now();
833
+ if (!expired) {
834
+ key = oauth.accessToken;
835
+ source = 'Claude Code (OAuth)';
836
+ } else {
837
+ res.writeHead(200, { 'Content-Type': 'application/json' });
838
+ res.end(JSON.stringify({ found: false, claude_code_expired: true, hint: 'Found Claude Code, but the OAuth token has expired. Run "claude" in your terminal once to refresh it, then click Detect again.' }));
839
+ return;
840
+ }
841
+ }
842
+ }
843
+ } catch {}
844
+ }
845
+
846
+ // 3. Shell environment (fallback — may be stale if sourced from a previous .env)
847
+ if (!gateway && !key) {
848
+ try {
849
+ const result = _deps.readUserShellEnv('ANTHROPIC_API_KEY', 6);
850
+ if (result && result.length > 5 && result !== 'sk-ant-api03-unused') {
851
+ key = result;
852
+ source = 'shell environment';
853
+ }
854
+ } catch {}
855
+ }
856
+
857
+ if (!gateway && !key) {
858
+ res.writeHead(200, { 'Content-Type': 'application/json' });
859
+ res.end(JSON.stringify({ found: false, hint: 'No API key found. Checked: Claude Code keychain, shell environment, devbox auth. Enter your key manually or get one at console.anthropic.com' }));
860
+ return;
861
+ }
862
+
863
+ // Probe API to discover the best model accessible with this key
864
+ const probeKey = key || (gateway ? gateway.auth_token : '');
865
+ const probeBase = gateway ? gateway.base_url : 'https://api.anthropic.com';
866
+ const probeHeaders = gateway ? gateway.custom_headers_b64 : null;
867
+ _deps.probeModel(probeKey, probeBase, probeHeaders).then(({ model: detectedModel }) => {
868
+ res.writeHead(200, { 'Content-Type': 'application/json' });
869
+ if (gateway) {
870
+ res.end(JSON.stringify({ found: true, gateway, source, ...(detectedModel ? { model: detectedModel } : {}) }));
871
+ } else {
872
+ res.end(JSON.stringify({ found: true, key, source, ...(detectedModel ? { model: detectedModel } : {}) }));
873
+ }
874
+ }).catch(() => {
875
+ res.writeHead(200, { 'Content-Type': 'application/json' });
876
+ if (gateway) {
877
+ res.end(JSON.stringify({ found: true, gateway, source }));
878
+ } else {
879
+ res.end(JSON.stringify({ found: true, key, source }));
880
+ }
881
+ });
882
+ return;
883
+ }
884
+
885
+ async function apiSetupSave(req, res, url) {
886
+ let body = '';
887
+ let bodyLen = 0;
888
+ req.on('data', c => {
889
+ bodyLen += c.length;
890
+ if (bodyLen > 8192) { req.destroy(); return; } // 8KB limit
891
+ body += c;
892
+ });
893
+ req.on('end', async () => {
894
+ try {
895
+ const data = JSON.parse(body);
896
+ // Validate and sanitize inputs
897
+ const ownerName = typeof data.owner_name === 'string'
898
+ ? data.owner_name.replace(/[\r\n=]/g, '').trim().slice(0, 200)
899
+ : '';
900
+ const apiKey = typeof data.api_key === 'string'
901
+ ? data.api_key.replace(/[\r\n\s]/g, '').slice(0, 200)
902
+ : '';
903
+ // Gateway config (corporate Portkey/cybertron setups) — sanitize values
904
+ let gw = null;
905
+ if (data.gateway && data.gateway.base_url) {
906
+ gw = {
907
+ base_url: String(data.gateway.base_url).replace(/[\r\n]/g, '').slice(0, 500),
908
+ auth_token: String(data.gateway.auth_token || 'sk-ant-api03-unused').replace(/[\r\n]/g, '').slice(0, 500),
909
+ custom_headers_b64: String(data.gateway.custom_headers_b64 || '').replace(/[\r\n\s]/g, '').slice(0, 2000),
910
+ };
911
+ }
912
+ const walleModel = typeof data.model === 'string'
913
+ ? data.model.replace(/[\r\n\s]/g, '').slice(0, 100)
914
+ : '';
915
+ const walleProvider = _deps.sanitizeSetupProviderType(data.provider);
916
+ if (walleProvider && !_deps.SETUP_PROVIDER_TYPES.includes(walleProvider)) {
917
+ res.writeHead(400, { 'Content-Type': 'application/json' });
918
+ res.end(JSON.stringify({ error: 'Invalid provider type. Must be one of: ' + _deps.setupProviderTypeList() }));
919
+ return;
920
+ }
921
+ const providerForApiKey = walleProvider || 'anthropic';
922
+ // Anthropic auth_method picker: 'api_key' (default), 'claude_cli', or
923
+ // 'oauth_proxy'. Anything else gets normalized to '' (= cleared).
924
+ // OpenAI auth_method picker: 'api_key' (default) or 'codex_cli'.
925
+ const anthropicAuthMethods = new Set(['api_key', 'claude_cli', 'oauth_proxy']);
926
+ const openaiAuthMethods = new Set(['api_key', 'codex_cli']);
927
+ const validForProvider = walleProvider === 'anthropic'
928
+ ? anthropicAuthMethods
929
+ : walleProvider === 'openai'
930
+ ? openaiAuthMethods
931
+ : new Set();
932
+ const authMethod = validForProvider.has(data.auth_method) ? data.auth_method : '';
933
+ // coding_via_cli: route the coding agent through `claude -p` (subscription
934
+ // billing) even when the primary auth is api_key. Stored as
935
+ // WALLE_CODING_USE_CLI=true|false to match what coding-orchestrator reads.
936
+ const codingViaCli = walleProvider === 'anthropic' && data.coding_via_cli === true;
937
+ // Accept any non-empty key (Anthropic, Portkey, or other providers)
938
+ const envPath = _deps.resolveEnvFilePath({ repoRoot: _deps.path.resolve(_deps.__dirname, '..'), dataDir: _deps.CONFIG_DIR });
939
+ const lines = [];
940
+ // Build set of keys to strip
941
+ const keysToReplace = new Set();
942
+ if (ownerName) keysToReplace.add('WALLE_OWNER_NAME');
943
+ // WALLE_AUTH_METHOD applies to anthropic (api_key/claude_cli/oauth_proxy)
944
+ // AND openai (api_key/codex_cli). WALLE_CODING_USE_CLI is anthropic-only.
945
+ if (walleProvider === 'anthropic' || walleProvider === 'openai') {
946
+ keysToReplace.add('WALLE_AUTH_METHOD');
947
+ }
948
+ if (walleProvider === 'anthropic') {
949
+ keysToReplace.add('WALLE_CODING_USE_CLI');
950
+ }
951
+ if (gw) {
952
+ // Gateway: strip Anthropic direct key vars
953
+ keysToReplace.add('ANTHROPIC_API_KEY');
954
+ keysToReplace.add('ANTHROPIC_BASE_URL');
955
+ keysToReplace.add('ANTHROPIC_AUTH_TOKEN');
956
+ keysToReplace.add('ANTHROPIC_CUSTOM_HEADERS_B64');
957
+ } else if (apiKey) {
958
+ // Only strip the key for the provider being configured — preserve others
959
+ if (providerForApiKey === 'openai') { keysToReplace.add('OPENAI_API_KEY'); }
960
+ else if (providerForApiKey === 'google') { keysToReplace.add('GOOGLE_API_KEY'); keysToReplace.add('GEMINI_API_KEY'); keysToReplace.add('GOOGLE_AUTH_MODE'); keysToReplace.add('GOOGLE_REFRESH_TOKEN'); }
961
+ else if (providerForApiKey === 'deepseek') { keysToReplace.add('DEEPSEEK_API_KEY'); }
962
+ else if (providerForApiKey === 'moonshot') { keysToReplace.add('MOONSHOT_API_KEY'); }
963
+ else if (providerForApiKey === 'zai') { keysToReplace.add('ZAI_API_KEY'); }
964
+ else if (providerForApiKey === 'anthropic') { keysToReplace.add('ANTHROPIC_API_KEY'); keysToReplace.add('ANTHROPIC_BASE_URL'); keysToReplace.add('ANTHROPIC_AUTH_TOKEN'); keysToReplace.add('ANTHROPIC_CUSTOM_HEADERS_B64'); }
965
+ }
966
+ // Read existing .env, keep lines that aren't being replaced
967
+ try {
968
+ const existing = _deps.fs.readFileSync(envPath, 'utf8');
969
+ for (const line of existing.split('\n')) {
970
+ const m = line.match(/^\s*#?\s*([A-Z0-9_]+)\s*=/);
971
+ if (m && keysToReplace.has(m[1])) continue; // skip — will re-add below
972
+ lines.push(line);
973
+ }
974
+ } catch { lines.push('# Wall-E configuration'); lines.push(''); }
975
+ // Strip trailing blank lines
976
+ while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();
977
+ lines.push('');
978
+ // Add new values
979
+ if (ownerName) {
980
+ lines.push(`WALLE_OWNER_NAME=${ownerName}`);
981
+ _deps.serverConfig.override("WALLE_OWNER_NAME", ownerName, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
982
+ }
983
+ // WALLE_AUTH_METHOD persistence — applies to anthropic AND openai.
984
+ if (walleProvider === 'anthropic' || walleProvider === 'openai') {
985
+ if (authMethod) {
986
+ lines.push(`WALLE_AUTH_METHOD=${authMethod}`);
987
+ _deps.serverConfig.override("WALLE_AUTH_METHOD", authMethod, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
988
+ } else {
989
+ delete _deps.serverConfig.WALLE_AUTH_METHOD;
990
+ }
991
+ }
992
+ // WALLE_CODING_USE_CLI is anthropic-only (claude -p override for the
993
+ // coding agent). Codex's equivalent path is auth_method=codex_cli itself.
994
+ if (walleProvider === 'anthropic') {
995
+ if (codingViaCli) {
996
+ lines.push(`WALLE_CODING_USE_CLI=true`);
997
+ _deps.serverConfig.override("WALLE_CODING_USE_CLI", 'true', 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
998
+ } else {
999
+ delete _deps.serverConfig.WALLE_CODING_USE_CLI;
1000
+ }
1001
+ }
1002
+ if (gw) {
1003
+ // Gateway setup: save gateway vars, clear direct API key
1004
+ lines.push(`ANTHROPIC_BASE_URL=${gw.base_url}`);
1005
+ lines.push(`ANTHROPIC_AUTH_TOKEN=${gw.auth_token}`);
1006
+ lines.push(`ANTHROPIC_CUSTOM_HEADERS_B64=${gw.custom_headers_b64}`);
1007
+ _deps.serverConfig.override("ANTHROPIC_BASE_URL", gw.base_url, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1008
+ _deps.serverConfig.override("ANTHROPIC_AUTH_TOKEN", gw.auth_token, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1009
+ _deps.serverConfig.override("ANTHROPIC_CUSTOM_HEADERS_B64", gw.custom_headers_b64, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1010
+ delete _deps.serverConfig.ANTHROPIC_API_KEY;
1011
+ } else if (apiKey) {
1012
+ // Save key under the correct provider env var
1013
+ if (providerForApiKey === 'openai') {
1014
+ lines.push(`OPENAI_API_KEY=${apiKey}`);
1015
+ _deps.serverConfig.override("OPENAI_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1016
+ } else if (providerForApiKey === 'google') {
1017
+ const googleAuthMode = typeof data.google_auth_mode === 'string' ? data.google_auth_mode.replace(/[^a-z]/g, '') : '';
1018
+ const googleRefreshToken = typeof data.google_refresh_token === 'string' ? data.google_refresh_token.replace(/[\r\n]/g, '').slice(0, 2000) : '';
1019
+ lines.push(`GOOGLE_API_KEY=${apiKey}`);
1020
+ _deps.serverConfig.override("GOOGLE_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1021
+ if (googleAuthMode === 'oauth' && googleRefreshToken) {
1022
+ lines.push(`GOOGLE_AUTH_MODE=oauth`);
1023
+ lines.push(`GOOGLE_REFRESH_TOKEN=${googleRefreshToken}`);
1024
+ _deps.serverConfig.override("GOOGLE_AUTH_MODE", 'oauth', 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1025
+ _deps.serverConfig.override("GOOGLE_REFRESH_TOKEN", googleRefreshToken, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1026
+ } else {
1027
+ delete _deps.serverConfig.GOOGLE_AUTH_MODE;
1028
+ delete _deps.serverConfig.GOOGLE_REFRESH_TOKEN;
1029
+ }
1030
+ } else if (providerForApiKey === 'deepseek') {
1031
+ lines.push(`DEEPSEEK_API_KEY=${apiKey}`);
1032
+ _deps.serverConfig.override("DEEPSEEK_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1033
+ } else if (providerForApiKey === 'moonshot') {
1034
+ lines.push(`MOONSHOT_API_KEY=${apiKey}`);
1035
+ _deps.serverConfig.override("MOONSHOT_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1036
+ } else if (providerForApiKey === 'zai') {
1037
+ lines.push(`ZAI_API_KEY=${apiKey}`);
1038
+ _deps.serverConfig.override("ZAI_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1039
+ } else if (providerForApiKey === 'anthropic') {
1040
+ // Default: Anthropic
1041
+ lines.push(`ANTHROPIC_API_KEY=${apiKey}`);
1042
+ _deps.serverConfig.override("ANTHROPIC_API_KEY", apiKey, 'ctm-config-seam: migrated write site (WP-4 AC-4c)');
1043
+ delete _deps.serverConfig.ANTHROPIC_BASE_URL;
1044
+ delete _deps.serverConfig.ANTHROPIC_AUTH_TOKEN;
1045
+ delete _deps.serverConfig.ANTHROPIC_CUSTOM_HEADERS_B64;
1046
+ }
1047
+ }
1048
+ _deps.atomicWriteFileSync(envPath, lines.join('\n') + '\n', { mode: 0o600 });
1049
+ _deps.setup.clearSetupCache(); // so next / request goes to dashboard
1050
+ _deps.telemetry.track('ctm_setup_save', { has_key: !!(apiKey || gw), has_model: !!walleModel });
1051
+
1052
+ // Persist provider config through Wall-E, which owns its brain DB.
1053
+ try {
1054
+ await _deps.walleClient.requestJson('/api/wall-e/setup/config', {
1055
+ method: 'POST',
1056
+ body: {
1057
+ provider: walleProvider,
1058
+ model: walleModel,
1059
+ ownerName,
1060
+ providerConfig: walleProvider ? {
1061
+ id: `${walleProvider}-default`,
1062
+ baseUrl: gw ? gw.base_url : null,
1063
+ apiKeyEncrypted: gw ? gw.auth_token : (apiKey || null),
1064
+ customHeaders: gw ? gw.custom_headers_b64 : null,
1065
+ } : null,
1066
+ },
1067
+ });
1068
+ } catch (dbErr) {
1069
+ console.error('[setup] Failed to persist Wall-E config:', dbErr.message);
1070
+ }
1071
+
1072
+ // Restart Wall-E so it picks up new config
1073
+ if (apiKey || gw || walleModel || walleProvider) {
1074
+ _deps.walleSupervisor.restartQuiet();
1075
+ }
1076
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1077
+ res.end(JSON.stringify({ ok: true }));
1078
+ } catch (e) {
1079
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1080
+ res.end(JSON.stringify({ error: e.message }));
1081
+ }
1082
+ });
1083
+ return;
1084
+ }
1085
+
1086
+ // WP-5 shard S2: the three verbatim bodies above are appended here by
1087
+ // bin/move-only-check.js's proof (identical to server.js's declarations up to
1088
+ // the `_deps.` prefix).
1089
+ module.exports = { configure, register, apiSetupTestKey, apiSetupDetectKey, apiSetupSave };