create-walle 0.10.2 → 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 (488) hide show
  1. package/README.md +3 -1
  2. package/lib/release-schema.json +2 -2
  3. package/lib/runtime-closure-policy.json +8 -7
  4. package/package.json +1 -1
  5. package/template/coding-task-manager/api-prompts.js +45 -7
  6. package/template/coding-task-manager/bin/claude-hook.js +55 -1
  7. package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
  8. package/template/coding-task-manager/bin/land.js +2069 -0
  9. package/template/coding-task-manager/bin/memory-census.js +4 -2
  10. package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
  11. package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
  12. package/template/coding-task-manager/db.js +156 -32
  13. package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
  14. package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
  15. package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
  16. package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
  17. package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
  18. package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
  19. package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
  20. package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
  21. package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
  22. package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
  23. package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
  24. package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
  25. package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
  26. package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
  27. package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
  28. package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
  29. package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
  30. package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
  31. package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
  32. package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
  33. package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
  34. package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
  35. package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
  36. package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
  37. package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
  38. package/template/coding-task-manager/lib/agent-definitions.js +19 -0
  39. package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
  40. package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
  41. package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
  42. package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
  43. package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
  44. package/template/coding-task-manager/lib/agent-presets.js +84 -1
  45. package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
  46. package/template/coding-task-manager/lib/agent-version-service.js +74 -11
  47. package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
  48. package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
  49. package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
  50. package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
  51. package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
  52. package/template/coding-task-manager/lib/api/fleet.js +118 -0
  53. package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
  54. package/template/coding-task-manager/lib/api/ingress.js +9 -1
  55. package/template/coding-task-manager/lib/api/landing.js +403 -0
  56. package/template/coding-task-manager/lib/api/machines.js +691 -2
  57. package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
  58. package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
  59. package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
  60. package/template/coding-task-manager/lib/api/session-attach.js +623 -0
  61. package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
  62. package/template/coding-task-manager/lib/api/sessions.js +77 -51
  63. package/template/coding-task-manager/lib/api/setup-network.js +544 -16
  64. package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
  65. package/template/coding-task-manager/lib/api/setup.js +829 -10
  66. package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
  67. package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
  68. package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
  69. package/template/coding-task-manager/lib/auth-rules.js +292 -21
  70. package/template/coding-task-manager/lib/background-stop.js +369 -0
  71. package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
  72. package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
  73. package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
  74. package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
  75. package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
  76. package/template/coding-task-manager/lib/build-info.js +4 -2
  77. package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
  78. package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
  79. package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
  80. package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
  81. package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
  82. package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
  83. package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
  84. package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
  85. package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
  86. package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
  87. package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
  88. package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
  89. package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
  90. package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
  91. package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
  92. package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
  93. package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
  94. package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
  95. package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
  96. package/template/coding-task-manager/lib/conversation-sync.js +355 -0
  97. package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
  98. package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
  99. package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
  100. package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
  101. package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
  102. package/template/coding-task-manager/lib/db-domains.js +1 -0
  103. package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
  104. package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
  105. package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
  106. package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
  107. package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
  108. package/template/coding-task-manager/lib/feature-manifest.js +4 -0
  109. package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
  110. package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
  111. package/template/coding-task-manager/lib/fleet-hub.js +762 -0
  112. package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
  113. package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
  114. package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
  115. package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
  116. package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
  117. package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
  118. package/template/coding-task-manager/lib/fleet-update.js +798 -0
  119. package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
  120. package/template/coding-task-manager/lib/fs-watcher.js +58 -42
  121. package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
  122. package/template/coding-task-manager/lib/headless-term-service.js +84 -8
  123. package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
  124. package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
  125. package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
  126. package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
  127. package/template/coding-task-manager/lib/host-handoff.js +16 -19
  128. package/template/coding-task-manager/lib/host-stats.js +150 -3
  129. package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
  130. package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
  131. package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
  132. package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
  133. package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
  134. package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
  135. package/template/coding-task-manager/lib/hub-bridge.js +398 -0
  136. package/template/coding-task-manager/lib/idle-notify.js +491 -0
  137. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
  138. package/template/coding-task-manager/lib/instance-manifest.js +5 -1
  139. package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
  140. package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
  141. package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
  142. package/template/coding-task-manager/lib/landing/config.js +536 -0
  143. package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
  144. package/template/coding-task-manager/lib/landing/gate.js +360 -0
  145. package/template/coding-task-manager/lib/landing/git.js +344 -0
  146. package/template/coding-task-manager/lib/landing/lease.js +247 -0
  147. package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
  148. package/template/coding-task-manager/lib/landing/proof.js +223 -0
  149. package/template/coding-task-manager/lib/landing/queue.js +998 -0
  150. package/template/coding-task-manager/lib/landing/radar.js +489 -0
  151. package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
  152. package/template/coding-task-manager/lib/landing/state.js +263 -0
  153. package/template/coding-task-manager/lib/landing/stop.js +49 -0
  154. package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
  155. package/template/coding-task-manager/lib/landing/sync.js +456 -0
  156. package/template/coding-task-manager/lib/landing/train.js +885 -0
  157. package/template/coding-task-manager/lib/landing/window.js +57 -0
  158. package/template/coding-task-manager/lib/launch-environment.js +121 -0
  159. package/template/coding-task-manager/lib/launch-model-override.js +36 -10
  160. package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
  161. package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
  162. package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
  163. package/template/coding-task-manager/lib/lead-model-options.js +160 -3
  164. package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
  165. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
  166. package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
  167. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
  168. package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
  169. package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
  170. package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
  171. package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
  172. package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
  173. package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
  174. package/template/coding-task-manager/lib/machine-registry.js +750 -5
  175. package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
  176. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
  177. package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
  178. package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
  179. package/template/coding-task-manager/lib/memory-join.js +337 -0
  180. package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
  181. package/template/coding-task-manager/lib/memory-sync.js +565 -0
  182. package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
  183. package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
  184. package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
  185. package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
  186. package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
  187. package/template/coding-task-manager/lib/model-availability.js +727 -0
  188. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
  189. package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
  190. package/template/coding-task-manager/lib/model-id-rule.js +19 -0
  191. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  192. package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
  193. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  194. package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
  195. package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
  196. package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
  197. package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
  198. package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
  199. package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
  200. package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
  201. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  202. package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
  203. package/template/coding-task-manager/lib/native-history-control.js +6 -4
  204. package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
  205. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
  206. package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
  207. package/template/coding-task-manager/lib/opencode-cli.js +480 -0
  208. package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
  209. package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
  210. package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
  211. package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
  212. package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
  213. package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
  214. package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
  215. package/template/coding-task-manager/lib/perf-summary.js +7 -0
  216. package/template/coding-task-manager/lib/perf-tracker.js +63 -2
  217. package/template/coding-task-manager/lib/project-config.js +7 -0
  218. package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
  219. package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
  220. package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
  221. package/template/coding-task-manager/lib/read-pool-client.js +89 -2
  222. package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
  223. package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
  224. package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
  225. package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
  226. package/template/coding-task-manager/lib/relay-client.js +57 -3
  227. package/template/coding-task-manager/lib/relink-audit.js +34 -5
  228. package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
  229. package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
  230. package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
  231. package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
  232. package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
  233. package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
  234. package/template/coding-task-manager/lib/restart-guard.js +18 -6
  235. package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
  236. package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
  237. package/template/coding-task-manager/lib/resume-admission.js +17 -3
  238. package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
  239. package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
  240. package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
  241. package/template/coding-task-manager/lib/runtime-contract.js +3 -1
  242. package/template/coding-task-manager/lib/schema-indexes.js +1 -0
  243. package/template/coding-task-manager/lib/session-context-locator.js +742 -0
  244. package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
  245. package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
  246. package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
  247. package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
  248. package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
  249. package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
  250. package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
  251. package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
  252. package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
  253. package/template/coding-task-manager/lib/session-create/response.js +7 -7
  254. package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
  255. package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
  256. package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
  257. package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
  258. package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
  259. package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
  260. package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
  261. package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
  262. package/template/coding-task-manager/lib/session-empty.js +13 -10
  263. package/template/coding-task-manager/lib/session-host-manager.js +60 -0
  264. package/template/coding-task-manager/lib/session-jobs.js +3 -1
  265. package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
  266. package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
  267. package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
  268. package/template/coding-task-manager/lib/session-park.js +738 -0
  269. package/template/coding-task-manager/lib/session-path-grant.js +13 -4
  270. package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
  271. package/template/coding-task-manager/lib/session-transport.js +17 -0
  272. package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
  273. package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
  274. package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
  275. package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
  276. package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
  277. package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
  278. package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
  279. package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
  280. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
  281. package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
  282. package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
  283. package/template/coding-task-manager/lib/submission-ack.js +90 -2
  284. package/template/coding-task-manager/lib/systemd-scope.js +115 -0
  285. package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
  286. package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
  287. package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
  288. package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
  289. package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
  290. package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
  291. package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
  292. package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
  293. package/template/coding-task-manager/lib/transcript-source.js +36 -4
  294. package/template/coding-task-manager/lib/transcript-store.js +9 -0
  295. package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
  296. package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
  297. package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
  298. package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
  299. package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
  300. package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
  301. package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
  302. package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
  303. package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
  304. package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
  305. package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
  306. package/template/coding-task-manager/lib/walle/turn.js +1 -1
  307. package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
  308. package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
  309. package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
  310. package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
  311. package/template/coding-task-manager/lib/walle-row-history.js +495 -0
  312. package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
  313. package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
  314. package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
  315. package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
  316. package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
  317. package/template/coding-task-manager/lib/ws/misc.js +1 -1
  318. package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
  319. package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
  320. package/template/coding-task-manager/oauth-proxy.js +112 -115
  321. package/template/coding-task-manager/package-lock.json +10 -94
  322. package/template/coding-task-manager/package.json +4 -3
  323. package/template/coding-task-manager/protocol/message-table.json +10 -0
  324. package/template/coding-task-manager/protocol/messages.js +10 -0
  325. package/template/coding-task-manager/protocol/ws-schema.json +20 -0
  326. package/template/coding-task-manager/protocol/ws-schema.md +2 -0
  327. package/template/coding-task-manager/public/css/app.css +170 -0
  328. package/template/coding-task-manager/public/css/walle-session.css +4 -0
  329. package/template/coding-task-manager/public/index.html +473 -243
  330. package/template/coding-task-manager/public/js/agent-command.js +86 -0
  331. package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
  332. package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
  333. package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
  334. package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
  335. package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
  336. package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
  337. package/template/coding-task-manager/public/js/background-work.js +196 -27
  338. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
  339. package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
  340. package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
  341. package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
  342. package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
  343. package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
  344. package/template/coding-task-manager/public/js/document-review-links.js +9 -1
  345. package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
  346. package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
  347. package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
  348. package/template/coding-task-manager/public/js/message-renderer.js +4 -3
  349. package/template/coding-task-manager/public/js/model-picker.js +3 -1
  350. package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
  351. package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
  352. package/template/coding-task-manager/public/js/pasted-content.js +236 -0
  353. package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
  354. package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
  355. package/template/coding-task-manager/public/js/prompts.js +11 -10
  356. package/template/coding-task-manager/public/js/protocol.js +10 -0
  357. package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
  358. package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
  359. package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
  360. package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
  361. package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
  362. package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
  363. package/template/coding-task-manager/public/js/stream-view.js +6 -5
  364. package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
  365. package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
  366. package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
  367. package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
  368. package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
  369. package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
  370. package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
  371. package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
  372. package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
  373. package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
  374. package/template/coding-task-manager/public/js/walle.js +6 -0
  375. package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
  376. package/template/coding-task-manager/public/m/app.css +140 -0
  377. package/template/coding-task-manager/public/m/app.js +507 -68
  378. package/template/coding-task-manager/public/m/index.html +17 -0
  379. package/template/coding-task-manager/public/m/machines.js +838 -4
  380. package/template/coding-task-manager/public/m/private-api.js +31 -1
  381. package/template/coding-task-manager/public/usage.html +1 -0
  382. package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
  383. package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
  384. package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
  385. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
  386. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
  387. package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
  388. package/template/coding-task-manager/server.js +1950 -11679
  389. package/template/coding-task-manager/session-integrity.js +64 -4
  390. package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
  391. package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
  392. package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
  393. package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
  394. package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
  395. package/template/coding-task-manager/workers/session-host-process.js +5 -5
  396. package/template/coding-task-manager/workers/watch-worker.js +105 -0
  397. package/template/coding-task-manager/workers/worktree-worker.js +168 -33
  398. package/template/ctm-relay/lib/protocol.js +14 -1
  399. package/template/package-lock.json +2 -2
  400. package/template/package.json +1 -1
  401. package/template/shared/backup-retention.js +82 -0
  402. package/template/shared/conversation-admission.js +2 -0
  403. package/template/shared/conversation-provenance.js +3 -7
  404. package/template/shared/conversation-storage-v2-contract.js +5 -0
  405. package/template/shared/linked-worktree.js +51 -0
  406. package/template/shared/macos-fda-target.js +57 -0
  407. package/template/shared/orphan-parents.js +55 -0
  408. package/template/shared/release-schema.json +2 -2
  409. package/template/shared/storage/contract.js +3 -0
  410. package/template/wall-e/adapters/imessage.js +12 -0
  411. package/template/wall-e/agent.js +71 -4
  412. package/template/wall-e/api-walle.js +21 -1
  413. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
  414. package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
  415. package/template/wall-e/brain/brain-join.js +859 -0
  416. package/template/wall-e/brain/brain-sync-membership.js +20 -0
  417. package/template/wall-e/brain/brain-sync-store.js +131 -77
  418. package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
  419. package/template/wall-e/brain/brain-sync-v2.js +578 -0
  420. package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
  421. package/template/wall-e/brain/deterministic-id.js +51 -0
  422. package/template/wall-e/brain/memories.js +2 -2
  423. package/template/wall-e/brain/migrations.js +40 -6
  424. package/template/wall-e/brain/model-identity-migration.js +1 -1
  425. package/template/wall-e/brain/owner-call-whitelist.js +23 -7
  426. package/template/wall-e/brain/schema.js +45 -85
  427. package/template/wall-e/brain.js +171 -35
  428. package/template/wall-e/chat.js +3 -3
  429. package/template/wall-e/coding/agent-shell-env.js +7 -2
  430. package/template/wall-e/coding/prompt-bundle.js +66 -21
  431. package/template/wall-e/config/main-loop-exemptions.json +2 -2
  432. package/template/wall-e/http/admin-api.js +37 -0
  433. package/template/wall-e/http/gws-api.js +4 -0
  434. package/template/wall-e/http/helper-rules-api.js +7 -1
  435. package/template/wall-e/http/model-admin.js +8 -1
  436. package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
  437. package/template/wall-e/http/model-proxy-providers.js +174 -1
  438. package/template/wall-e/http/model-route-health.js +157 -0
  439. package/template/wall-e/http/sync-api.js +278 -464
  440. package/template/wall-e/jobs/job-runner.js +28 -1
  441. package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
  442. package/template/wall-e/lib/ctm-data-dir.js +26 -0
  443. package/template/wall-e/lib/derivation-home.js +147 -0
  444. package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
  445. package/template/wall-e/lib/helper-rules/grade.js +51 -8
  446. package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
  447. package/template/wall-e/lib/helper-rules/store.js +4 -2
  448. package/template/wall-e/lib/landing-mcp-tools.js +170 -0
  449. package/template/wall-e/lib/mcp-client-config.js +133 -14
  450. package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
  451. package/template/wall-e/lib/mcp-integration.js +58 -13
  452. package/template/wall-e/lib/parent-death.js +7 -1
  453. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
  454. package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
  455. package/template/wall-e/llm/delegate-vendor-default.js +12 -5
  456. package/template/wall-e/llm/model-roles.js +1 -1
  457. package/template/wall-e/llm/native-delegate-selection.js +56 -8
  458. package/template/wall-e/llm/worker-delegate-args.js +72 -7
  459. package/template/wall-e/llm/worker-mcp-routing.js +66 -17
  460. package/template/wall-e/loops/brain-custom-writes.js +19 -0
  461. package/template/wall-e/loops/ingest.js +17 -1
  462. package/template/wall-e/loops/think.js +19 -4
  463. package/template/wall-e/mcp-contract.js +222 -6
  464. package/template/wall-e/mcp-protocol-contract.js +40 -5
  465. package/template/wall-e/mcp-server.js +128 -29
  466. package/template/wall-e/mcp-worker-schemas.js +5 -5
  467. package/template/wall-e/memory/ctm-context-client.js +85 -0
  468. package/template/wall-e/memory/ctm-session-context.js +9 -3
  469. package/template/wall-e/memory/hub-bridge-client.js +388 -0
  470. package/template/wall-e/memory/replica-origin.js +56 -0
  471. package/template/wall-e/memory/session-pool.js +135 -0
  472. package/template/wall-e/runtime/live-capabilities.js +8 -3
  473. package/template/wall-e/server.js +4 -2
  474. package/template/wall-e/shared/release-schema.json +2 -2
  475. package/template/wall-e/shared/sqlite-file-set.js +39 -0
  476. package/template/wall-e/shared/storage/contract.js +3 -0
  477. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  478. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
  479. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
  480. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
  481. package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
  482. package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
  483. package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
  484. package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
  485. package/template/wall-e/tools/chrome-automation.js +6 -0
  486. package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
  487. package/template/wall-e/workers/brain-owner-worker.js +18 -4
  488. package/template/wall-e/workers/mcp-gateway-process.js +5 -5
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // Delegate model preferences (lead-and-delegate-model-picker-ux-2026-10-08.html §6.4):
4
- // GET /api/models/delegate-prefs?ctm_session_id=&agent=claude|codex
4
+ // GET /api/models/delegate-prefs?ctm_session_id=&agent=claude|codex|opencode
5
5
  // -> { effective:{lane,model,route_id,identity_id,display,effort,source}, ladder:[...] }
6
6
  // PUT /api/models/delegate-prefs { scope_key, lane, model, identity_id, route_id, display, effort } -> { row }
7
7
  // DELETE /api/models/delegate-prefs/:scope_key -> { ok, deleted }
@@ -30,14 +30,14 @@ async function handleDelegatePrefAdminRoute({ req, res, p, m, url, brainApi } =
30
30
  const db = brainApi.getDb();
31
31
  if (m === 'GET') {
32
32
  const agent = url && url.searchParams ? url.searchParams.get('agent') : '';
33
- if (!store.AGENTS.includes(agent)) return invalid(res, 'agent: must be claude or codex');
33
+ if (!store.AGENTS.includes(agent)) return invalid(res, 'agent: must be claude, codex or opencode');
34
34
  const ctmSessionId = (url.searchParams.get('ctm_session_id') || '').trim();
35
35
  if (ctmSessionId && !store.isValidScopeKey(`session:${ctmSessionId}`)) return invalid(res, 'ctm_session_id: not a valid session id');
36
36
  return jsonResponse(res, 200, store.effectiveDelegatePref(db, { ctmSessionId, agent }));
37
37
  }
38
38
  if (m === 'DELETE') {
39
39
  const scopeKey = decodeOnce(item[1]);
40
- if (!store.isValidScopeKey(scopeKey)) return invalid(res, 'scope_key: must be session:<ctm_session_id>, default:claude or default:codex');
40
+ if (!store.isValidScopeKey(scopeKey)) return invalid(res, 'scope_key: must be session:<ctm_session_id>, default:claude, default:codex or default:opencode');
41
41
  return jsonResponse(res, 200, store.deleteDelegatePref(db, scopeKey));
42
42
  }
43
43
  let body;
@@ -85,4 +85,177 @@ function handleModelProxyProvidersFeed(req, res, url, {
85
85
  return true;
86
86
  }
87
87
 
88
- module.exports = { handleModelProxyProvidersFeed };
88
+ // WP-1 (docs/remote-box-model-access-2026-10-26.html §6.1, §9): `GET /api/wall-e/internal/
89
+ // delegate-defaults` — the box's own /delegate picks, for the hub that is asking what the box can
90
+ // serve. Loopback-only under the SAME guard as the provider feed above (the values are not secrets —
91
+ // CTM asks for them over its own loopback Wall-E client — but a row here names a route on this
92
+ // machine, and the feed's rule is that this surface is never reachable from off-box).
93
+ //
94
+ // It answers ONLY the two `default:*` rows (§6.1: "the two default:* rows of delegate_model_prefs
95
+ // and nothing for session:*"): a `session:<ctm_session_id>` row is another user's in-flight pick and
96
+ // is never part of "what can this box serve".
97
+ const DELEGATE_DEFAULT_AGENTS = Object.freeze(['claude', 'codex']);
98
+
99
+ /** The two default rows, in `{ agent, lane, model, routeId }` shape. Absent rows are omitted. */
100
+ function _readDelegateDefaults() {
101
+ const store = require('../brain/delegate-model-prefs-store');
102
+ const db = require('../brain').getDb();
103
+ const rows = [];
104
+ for (const agent of DELEGATE_DEFAULT_AGENTS) {
105
+ const row = store.getDelegatePref(db, `default:${agent}`);
106
+ if (!row) continue;
107
+ rows.push({
108
+ agent,
109
+ lane: String(row.lane || ''),
110
+ model: String(row.model || ''),
111
+ routeId: String(row.route_id || ''),
112
+ });
113
+ }
114
+ return rows;
115
+ }
116
+
117
+ function handleDelegateDefaultsFeed(req, res, url, {
118
+ isLoopbackRequest,
119
+ brainAvailable,
120
+ readDefaults,
121
+ errorStatus,
122
+ } = {}) {
123
+ if (url.pathname !== '/api/wall-e/internal/delegate-defaults' || req.method !== 'GET') return false;
124
+ if (typeof isLoopbackRequest !== 'function' || !isLoopbackRequest(req)) {
125
+ jsonResponse(res, { error: 'loopback_only' }, 403);
126
+ return true;
127
+ }
128
+ if (!brainAvailable) {
129
+ jsonResponse(res, { error: 'Brain not available' }, 503);
130
+ return true;
131
+ }
132
+ try {
133
+ const defaults = (typeof readDefaults === 'function' ? readDefaults : _readDelegateDefaults)();
134
+ jsonResponse(res, { ok: true, defaults: Array.isArray(defaults) ? defaults : [] }, 200);
135
+ } catch (error) {
136
+ errorSink.report('api-walle', 'delegate_defaults_feed', new Error('Delegate default read failed'));
137
+ jsonResponse(res, { error: 'Failed to read delegate defaults' }, typeof errorStatus === 'function' ? errorStatus(error) : 500);
138
+ }
139
+ return true;
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------------------------
143
+ // WP-5 (docs/remote-box-model-access-2026-10-26.html §5.1 R-5/R-6, §6.4): the ONE place a
144
+ // provider credential leaves Wall-E, and only to loopback.
145
+ //
146
+ // "Use on <box>" copies ONE hub route (with its key) onto a machine the user paired, on an explicit
147
+ // click. The key lives only in `model_providers.api_key_encrypted`, and the hub's CTM reads it
148
+ // through this leaf — never through a browser-facing route — then hands it to the box over the
149
+ // hub's own peer credential. R-5/R-6: the copy is per-route and user-initiated, never a bulk
150
+ // export, never a sync.
151
+ //
152
+ // The row is an ALLOWLIST, not a copy of the DB row: exactly the fields the raw upsert route
153
+ // accepts (http/model-admin.js's `POST /api/models/providers` → brain/models.js's
154
+ // `upsertModelProvider`, whose destructuring is id/name/type/baseUrl/apiKeyEncrypted/customHeaders/
155
+ // enabled/caCertPem/maxOutputTokens/reasoningField/reasoningEffortDefault, with the route accepting
156
+ // the snake_case aliases for the three config columns and `caCert` for the PEM). Custom headers,
157
+ // usage/health counters and every derived column stay behind. Nothing here is logged: the error
158
+ // paths write fixed strings, and the response is the only carrier of the key, to a loopback socket.
159
+ // ---------------------------------------------------------------------------------------------
160
+
161
+ const PROVIDER_EXPORT_PATH = '/api/wall-e/internal/provider-export';
162
+ /** Longest accepted `id` query value. A longer one cannot name a row, so it is the same 404. */
163
+ const MAX_EXPORT_ID_CHARS = 200;
164
+ /** Per-field bound for the exported strings — mirrors the shapes the admin routes accept. */
165
+ const EXPORT_FIELD_CHARS = Object.freeze({
166
+ id: 200, name: 200, type: 60, base_url: 500, auth_method: 60, api_key: 512, ca_cert_pem: 70000,
167
+ });
168
+
169
+ /** `value` as a bounded string, or null when absent/not a string. Never throws, never logs. */
170
+ function _exportString(value, max) {
171
+ if (typeof value !== 'string') return null;
172
+ const trimmed = value.trim();
173
+ if (!trimmed) return null;
174
+ return trimmed.slice(0, max);
175
+ }
176
+
177
+ /**
178
+ * The exported row for `id`: an allowlist of the raw upsert's own field names (the snake_case
179
+ * spellings `POST /api/models/providers` maps explicitly), plus the credential under `api_key` — the
180
+ * §6.4 wire name the box's `POST /api/models/import` validates and maps onto its own upsert call.
181
+ * The key is the ONLY secret here; `ca_cert_pem` is trust material the route's sibling write also
182
+ * carries, and it is omitted when the row has none.
183
+ *
184
+ * @returns {object|null} null when the row does not exist
185
+ */
186
+ function _exportRowFor(row) {
187
+ if (!row || typeof row !== 'object') return null;
188
+ const id = _exportString(row.id, EXPORT_FIELD_CHARS.id);
189
+ if (!id) return null;
190
+ const exported = { id };
191
+ for (const [key, column] of [
192
+ ['name', 'name'],
193
+ ['type', 'type'],
194
+ ['base_url', 'base_url'],
195
+ ['auth_method', 'auth_method'],
196
+ ]) {
197
+ const value = _exportString(row[column], EXPORT_FIELD_CHARS[key]);
198
+ if (value !== null) exported[key] = value;
199
+ }
200
+ const apiKey = _exportString(row.api_key_encrypted, EXPORT_FIELD_CHARS.api_key);
201
+ if (apiKey !== null) exported.api_key = apiKey;
202
+ // `enabled` is an INTEGER column (0/1) in the brain; the import row speaks the same boolean the
203
+ // upsert takes, so a 0 is forwarded as false rather than as a truthy number.
204
+ exported.enabled = !(row.enabled === 0 || row.enabled === false);
205
+ if (Number.isInteger(row.max_output_tokens) && row.max_output_tokens > 0) {
206
+ exported.max_output_tokens = row.max_output_tokens;
207
+ }
208
+ const reasoningField = _exportString(row.reasoning_field, 60);
209
+ if (reasoningField !== null) exported.reasoning_field = reasoningField;
210
+ const reasoningEffort = _exportString(row.reasoning_effort_default, 40);
211
+ if (reasoningEffort !== null) exported.reasoning_effort_default = reasoningEffort;
212
+ const caCertPem = _exportString(row.ca_cert_pem, EXPORT_FIELD_CHARS.ca_cert_pem);
213
+ if (caCertPem !== null) exported.ca_cert_pem = caCertPem;
214
+ return exported;
215
+ }
216
+
217
+ /**
218
+ * §6.4: `GET /api/wall-e/internal/provider-export?id=<id>` — the hub's CTM reads ONE row WITH its
219
+ * key through this leaf, so the copy leg never has to reach into the brain itself. Loopback only,
220
+ * with the same guard and the same refusals as the two leaves above; an unknown id is a 404 that
221
+ * carries no row, and every failure reply is a constant (a DB error must not become a message or a
222
+ * leaked row).
223
+ */
224
+ function handleProviderExport(req, res, url, {
225
+ readBrain,
226
+ isLoopbackRequest,
227
+ brainAvailable,
228
+ errorStatus,
229
+ } = {}) {
230
+ if (url.pathname !== PROVIDER_EXPORT_PATH || req.method !== 'GET') return false;
231
+ if (typeof isLoopbackRequest !== 'function' || !isLoopbackRequest(req)) {
232
+ jsonResponse(res, { error: 'loopback_only' }, 403);
233
+ return true;
234
+ }
235
+ if (!brainAvailable) {
236
+ jsonResponse(res, { error: 'Brain not available' }, 503);
237
+ return true;
238
+ }
239
+ const id = String(url.searchParams.get('id') || '');
240
+ if (!id || id.length > MAX_EXPORT_ID_CHARS) {
241
+ jsonResponse(res, { error: 'Provider not found' }, 404);
242
+ return true;
243
+ }
244
+ void (async () => {
245
+ try {
246
+ const row = await readBrain('getModelProviderWithKey', [id]);
247
+ const exported = _exportRowFor(row);
248
+ if (!exported) {
249
+ jsonResponse(res, { error: 'Provider not found' }, 404);
250
+ return;
251
+ }
252
+ jsonResponse(res, { ok: true, row: exported }, 200);
253
+ } catch (error) {
254
+ errorSink.report('api-walle', 'provider_export', new Error('Provider export read failed'));
255
+ jsonResponse(res, { error: 'Failed to read provider' }, typeof errorStatus === 'function' ? errorStatus(error) : 500);
256
+ }
257
+ })();
258
+ return true;
259
+ }
260
+
261
+ module.exports = { handleModelProxyProvidersFeed, handleDelegateDefaultsFeed, handleProviderExport };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ // WP-2 (lead-route-model-invocability-preflight, D-3/D-4/D-6): CTM probes a
4
+ // (route, model) pair before it parks a routed Lead and POSTs the verdict here.
5
+ // The verdict is written into the EXISTING per-route+model circuit breaker
6
+ // (`provider_model_circuit_breakers`, key `${route_id}:${model}` lower-cased —
7
+ // llm/provider-health-state.js's providerModelKey) and then read back by
8
+ // `GET /api/models/coding-catalog`, which annotates every route with the
9
+ // circuit. No new state, no new constant, no new flag: D-8's "nothing else
10
+ // changes" rule.
11
+ const { jsonResponse, readSmallJsonBody } = require('./model-admin-shared');
12
+ const errorSink = require('../lib/error-sink');
13
+ // Read off the module object (not destructured) so the catalog annotation's
14
+ // one-build-per-call property stays observable to callers/tests that spy on the
15
+ // factory; the lookup itself is built once per annotateCatalogRouteCircuits call.
16
+ const providerHealthState = require('../llm/provider-health-state');
17
+
18
+ const ROUTE_HEALTH_PATH = '/api/models/route-health';
19
+
20
+ // D-2: only the non-retryable, pair-class outcomes are recorded. A retryable
21
+ // condition (rate limit, overload, 5xx) or an unknown/absent outcome is a
22
+ // property of the moment, not of the pair — CTM refuses to spend a circuit on
23
+ // it, and so does this endpoint (400, nothing written).
24
+ const NON_RETRYABLE_OUTCOMES = new Set([
25
+ 'model_not_invocable',
26
+ 'model_access_denied',
27
+ // §12a rule 4: the route does not serve this model id at all. Recorded like the other pair-class
28
+ // outcomes (error_type `model_unavailable`), and only ever sent for a single-wire route.
29
+ 'model_not_found',
30
+ 'invalid_prompt',
31
+ 'context_length_exceeded',
32
+ 'insufficient_quota',
33
+ ]);
34
+
35
+ function isNonEmptyString(value, maxLength) {
36
+ if (typeof value !== 'string') return false;
37
+ const trimmed = value.trim();
38
+ return trimmed.length >= 1 && trimmed.length <= maxLength;
39
+ }
40
+
41
+ function isValidOptionalHttpStatus(value) {
42
+ if (value == null) return true;
43
+ return Number.isInteger(value) && value >= 100 && value <= 599;
44
+ }
45
+
46
+ function isValidOutcome(body) {
47
+ if (body.ok === true) return body.outcome == null;
48
+ return typeof body.outcome === 'string' && NON_RETRYABLE_OUTCOMES.has(body.outcome);
49
+ }
50
+
51
+ // Validates CTM's probe verdict; null means "acceptable", otherwise the reason
52
+ // is unused today but kept for the 400 body and future diagnostics.
53
+ function invalidRouteHealthReason(body) {
54
+ if (!body || typeof body !== 'object' || Array.isArray(body)) return 'body';
55
+ if (!isNonEmptyString(body.route_id, 120)) return 'route_id';
56
+ if (!isNonEmptyString(body.model, 200)) return 'model';
57
+ if (typeof body.ok !== 'boolean') return 'ok';
58
+ if (!isValidOutcome(body)) return 'outcome';
59
+ if (!isValidOptionalHttpStatus(body.http_status)) return 'http_status';
60
+ return null;
61
+ }
62
+
63
+ function routeHealthStatusFor(row, body) {
64
+ const routeId = body.route_id.trim();
65
+ const model = body.model.trim();
66
+ const ok = body.ok === true;
67
+ return {
68
+ provider: row.type,
69
+ provider_id: routeId,
70
+ provider_type: row.type,
71
+ runtime_type: row.type,
72
+ model,
73
+ ok,
74
+ source: 'ctm-lead-preflight',
75
+ error_type: ok ? '' : (body.outcome === 'model_access_denied' ? 'auth_error' : 'model_unavailable'),
76
+ error: ok ? '' : body.outcome,
77
+ checked_at: new Date().toISOString(),
78
+ };
79
+ }
80
+
81
+ // POST /api/models/route-health — see §5 D-3/D-4 and §6.3. Returns a truthy
82
+ // response value when it handled the request, null otherwise (the caller's
83
+ // one-line dispatch convention).
84
+ async function handleModelRouteHealthRoute({ req, res, p, m, brainApi, deps = {} } = {}) {
85
+ if (p !== ROUTE_HEALTH_PATH || m !== 'POST') return null;
86
+ let body;
87
+ try {
88
+ body = await readSmallJsonBody(req);
89
+ } catch {
90
+ // an unparseable / oversized body is a caller error, not a brain error
91
+ return jsonResponse(res, 400, { error: 'invalid_route_health' });
92
+ }
93
+ try {
94
+ if (invalidRouteHealthReason(body)) return jsonResponse(res, 400, { error: 'invalid_route_health' });
95
+ if (!brainApi) return jsonResponse(res, 500, { error: 'Wall-E brain not available' });
96
+ const routeId = body.route_id.trim();
97
+ const model = body.model.trim();
98
+ const row = (brainApi.listModelProviders() || []).find((r) => r && r.id === routeId);
99
+ if (!row) return jsonResponse(res, 404, { error: 'route_not_found' });
100
+ const brain = deps.brain || require('../lib/brain-events').getBrainCapabilities();
101
+ providerHealthState.recordProviderHealthStatus(routeHealthStatusFor(row, body), { brain, recoverySuccesses: 1 });
102
+ const circuit = providerHealthState.getProviderModelCircuit(routeId, model, { brain });
103
+ return jsonResponse(res, 200, { recorded: true, circuit });
104
+ } catch (e) {
105
+ return jsonResponse(res, 500, { error: e.message });
106
+ }
107
+ }
108
+
109
+ // D-6: annotate every OPEN route of a coding-catalog page with the pair's
110
+ // circuit; absent = closed (keeps the page byte-identical when nothing is
111
+ // open). The catalog payload is a PINNED SNAPSHOT reused across pages, so this
112
+ // never mutates its input — it returns a fresh body. The lookup is built ONCE
113
+ // per call (one parse/prune of the circuit KV map for the whole page), never
114
+ // per route; model-identity-routes.js uses the same lookup call shape.
115
+ function annotateCatalogRouteCircuits(body, { lookup } = {}) {
116
+ if (!body || typeof body !== 'object' || Array.isArray(body) || !Array.isArray(body.models)) {
117
+ return { ...body };
118
+ }
119
+ let lookupFn = lookup;
120
+ if (typeof lookupFn !== 'function') {
121
+ try {
122
+ const brain = require('../lib/brain-events').getBrainCapabilities();
123
+ lookupFn = providerHealthState.buildProviderModelCircuitLookup({ brain });
124
+ } catch (e) {
125
+ // expected: the catalog is a read path — a brain/circuit read failure must
126
+ // never fail the page; it ships without the circuit fields (the clients
127
+ // treat a missing circuit as 'closed', AC-3d).
128
+ errorSink.report('model-route-health', 'catalog-circuit-lookup', e);
129
+ return { ...body };
130
+ }
131
+ }
132
+ return {
133
+ ...body,
134
+ models: body.models.map((item) => {
135
+ if (!item || typeof item !== 'object') return item;
136
+ if (!Array.isArray(item.routes)) return { ...item };
137
+ return {
138
+ ...item,
139
+ routes: item.routes.map((route) => {
140
+ if (!route || typeof route !== 'object') return route;
141
+ const circuit = lookupFn([route.provider_id], route.model_id);
142
+ // A closed pair carries NO circuit fields at all: the page stays
143
+ // byte-identical when nothing is open (clients read absent as closed).
144
+ if (!circuit) return { ...route };
145
+ return {
146
+ ...route,
147
+ circuit: 'open',
148
+ circuit_retry_after_ms: Number.isFinite(circuit.next_probe_in_ms) ? circuit.next_probe_in_ms : 0,
149
+ circuit_error_type: circuit.error_type || null,
150
+ };
151
+ }),
152
+ };
153
+ }),
154
+ };
155
+ }
156
+
157
+ module.exports = { handleModelRouteHealthRoute, annotateCatalogRouteCircuits };