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
@@ -378,5 +378,35 @@
378
378
  }
379
379
  }
380
380
 
381
- return { createMobilePrivateApi, runPhoneModelRequest, createIdentityCache, createConditionalIdentityFetch, CONDITIONAL_PATHS };
381
+ // The phone transcript page's one normalization: an array, `{messages}`, `{data}` or `{items}` all become
382
+ // the same page shape. Moved verbatim out of app.js (which is at its line ceiling) — one call site there.
383
+ function normalizeSessionMessagesPayload(data) {
384
+ if (Array.isArray(data)) {
385
+ return {
386
+ messages: data,
387
+ hasMore: false,
388
+ nextOffset: data.length,
389
+ total: data.length,
390
+ pageKind: 'messages',
391
+ conversationBudget: null,
392
+ };
393
+ }
394
+ const messages = Array.isArray(data?.messages)
395
+ ? data.messages
396
+ : (Array.isArray(data?.data) ? data.data : (Array.isArray(data?.items) ? data.items : []));
397
+ return {
398
+ messages,
399
+ hasMore: !!(data?.has_more || data?.hasMore),
400
+ nextOffset: Number.isFinite(Number(data?.next_offset ?? data?.nextOffset))
401
+ ? Number(data?.next_offset ?? data?.nextOffset)
402
+ : messages.length,
403
+ total: Number.isFinite(Number(data?.total)) ? Number(data.total) : messages.length,
404
+ pageKind: String(data?.page_kind || data?.pageKind || ''),
405
+ conversationBudget: data?.conversationBudget && typeof data.conversationBudget === 'object'
406
+ ? data.conversationBudget
407
+ : null,
408
+ };
409
+ }
410
+
411
+ return { createMobilePrivateApi, runPhoneModelRequest, createIdentityCache, createConditionalIdentityFetch, CONDITIONAL_PATHS, normalizeSessionMessagesPayload };
382
412
  });
@@ -55,6 +55,7 @@
55
55
  <details class="reporting-panel"><summary>Reports and observational budgets</summary><div id="usage-reporting-host"></div></details>
56
56
  </main>
57
57
  <script src="/js/usage-format.js"></script>
58
+ <script src="/js/pasted-content.js"></script>
58
59
  <script src="/js/session-usage-view.js"></script>
59
60
  <script src="/js/usage-reporting-view.js"></script>
60
61
  <script>window.CTMSessionUsage.boot(document);</script>
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ // WP-5 (coding-task-manager/docs/opencode-followups-agent-word-v2-waiting-dev-route-2026-10-31.html
4
+ // §4 "Synthetic route upstream", §6.5): the ONE loopback synthetic model upstream, extracted
5
+ // verbatim from tests/rendering/helpers/claude-routed-provider.js so that the render harness's
6
+ // routed-provider fixture and scripts/dev-route-fixture.js serve the same bytes from the same code.
7
+ //
8
+ // It is a synthetic upstream, never a provider: no credentials, no real vendor, no private source.
9
+ // GET /v1/models (or /models) -> the reachability answer a route probe reads
10
+ // POST /v1/chat/completions (or /chat/completions) -> a canned assistant turn (SSE when the
11
+ // request body says stream: true)
12
+ // anything else -> a bounded JSON 404
13
+ // `requests` records every request it answers (`{ method, url, body, model }`) so a caller can
14
+ // assert what a routed target actually sent. The canned turn is the constant SYNTHETIC_ROUTED_TURN
15
+ // under both the streaming and the non-streaming shape, so a routed turn can never hang here.
16
+
17
+ const http = require('node:http');
18
+
19
+ /** The one canned assistant turn; both the SSE delta and the JSON message carry it verbatim. */
20
+ const SYNTHETIC_ROUTED_TURN = 'SYNTHETIC_ROUTED_TURN';
21
+
22
+ function sendJson(res, status, body) {
23
+ const payload = JSON.stringify(body);
24
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) });
25
+ res.end(payload);
26
+ }
27
+
28
+ function listen(server, host = '127.0.0.1') {
29
+ return new Promise((resolve, reject) => {
30
+ server.once('error', reject);
31
+ server.listen(0, host, () => resolve(server.address().port));
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Start the synthetic upstream on 127.0.0.1 (an OS-assigned port, never a fixed one -- a fixture
37
+ * that pinned a port would need a probe-close-rebind, which H-8 forbids).
38
+ *
39
+ * @param {{ wireModelId?: string }} [options] the model id this upstream lists and answers as.
40
+ * @returns {Promise<{ server: import('node:http').Server, port: number,
41
+ * requests: Array<{ method: string|undefined, url: string|undefined, body: string, model: string|null }>,
42
+ * close: () => Promise<void> }>}
43
+ */
44
+ async function startSyntheticUpstream(options = {}) {
45
+ // Every caller names its wire model (the render fixture its WIRE_MODEL_ID, the dev fixture --model);
46
+ // shipped scripts carry no model id literal (model-roles lint R-4).
47
+ const wireModelId = String(options.wireModelId || '').trim();
48
+ if (!wireModelId) throw new TypeError('startSyntheticUpstream: wireModelId required');
49
+ const requests = [];
50
+ const server = http.createServer((req, res) => {
51
+ const chunks = [];
52
+ req.on('data', (chunk) => chunks.push(chunk));
53
+ req.on('end', () => {
54
+ const raw = Buffer.concat(chunks).toString('utf8');
55
+ let parsed = {};
56
+ // expected: a body that is not JSON (an empty GET body, a probe) is recorded raw and still
57
+ // served the canned reply -- this upstream never fails on shape.
58
+ try { parsed = JSON.parse(raw); } catch { parsed = {}; }
59
+ requests.push({ method: req.method, url: req.url, body: raw, model: parsed?.model ?? null });
60
+ if (req.url === '/v1/models' || req.url === '/models') {
61
+ return sendJson(res, 200, { object: 'list', data: [{ id: wireModelId, object: 'model' }] });
62
+ }
63
+ if (req.url === '/v1/chat/completions' || req.url === '/chat/completions') {
64
+ if (parsed.stream) {
65
+ res.writeHead(200, { 'Content-Type': 'text/event-stream' });
66
+ res.write(`data: ${JSON.stringify({ id: 'chatcmpl-synthetic', object: 'chat.completion.chunk',
67
+ model: wireModelId, choices: [{ index: 0, delta: { role: 'assistant', content: SYNTHETIC_ROUTED_TURN } }] })}\n\n`);
68
+ res.write(`data: ${JSON.stringify({ id: 'chatcmpl-synthetic', object: 'chat.completion.chunk',
69
+ model: wireModelId, choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] })}\n\n`);
70
+ return res.end('data: [DONE]\n\n');
71
+ }
72
+ return sendJson(res, 200, { id: 'chatcmpl-synthetic', object: 'chat.completion', model: wireModelId,
73
+ choices: [{ index: 0, message: { role: 'assistant', content: SYNTHETIC_ROUTED_TURN }, finish_reason: 'stop' }],
74
+ usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 } });
75
+ }
76
+ return sendJson(res, 404, { error: 'not_found', path: req.url });
77
+ });
78
+ });
79
+
80
+ function close() {
81
+ return new Promise((resolve, reject) => {
82
+ // Idempotent: a caller may close explicitly and again from its own finally (or after a
83
+ // signal handler already ran).
84
+ if (!server.listening) {
85
+ if (typeof server.closeAllConnections === 'function') server.closeAllConnections();
86
+ resolve();
87
+ return;
88
+ }
89
+ // A keep-alive socket from a routed turn would otherwise hold close() open forever.
90
+ if (typeof server.closeAllConnections === 'function') server.closeAllConnections();
91
+ server.close((error) => (error ? reject(error) : resolve()));
92
+ });
93
+ }
94
+
95
+ const port = await listen(server);
96
+ return { server, port, requests, close };
97
+ }
98
+
99
+ module.exports = {
100
+ startSyntheticUpstream,
101
+ sendJson,
102
+ listen,
103
+ SYNTHETIC_ROUTED_TURN,
104
+ };
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // WP-5 (coding-task-manager/docs/opencode-followups-agent-word-v2-waiting-dev-route-2026-10-31.html
5
+ // §4 "Synthetic route upstream" / "Provider + registry write endpoints" / "Coding-catalog build",
6
+ // §5 D-9/D-10, §6.5): seed ONE synthetic routed model into a /ctm-dev instance and serve a loopback
7
+ // synthetic upstream for it, so routed model switching can be checked live on a fresh dev DB
8
+ // (bin/dev.sh --fresh deletes the dev databases, so a fresh instance has no routes at all).
9
+ //
10
+ // node scripts/dev-route-fixture.js --ctm-port <devPort> [--walle-port <n>]
11
+ // [--route-id dev-synthetic] [--model fixture/m-route]
12
+ // [--deadline-ms 7200000]
13
+ //
14
+ // Endpoint choice (§6.5 steps 3-4): CTM's lib/api/walle-bridge.js register() mounts
15
+ // { method: '*', prefix: '/api/models', handler: handleProxy }
16
+ // whose handleProxy pipes every /api/models* request straight to the instance's own WALL_E_PORT
17
+ // (proxyHttp, CTM never parses the body). Both writes -- and the coding-catalog read, and the
18
+ // teardown DELETE -- therefore go to --ctm-port; --walle-port is accepted, refused when it names the
19
+ // primary pair, and never used for a request.
20
+ //
21
+ // Field names come from the endpoints' own code, never from convenience:
22
+ // POST /api/models/providers spreads its body into the Wall-E brain upsertModelProvider
23
+ // upsertModelProvider({ id, name, type, baseUrl, apiKeyEncrypted, customHeaders, enabled,
24
+ // caCertPem, maxOutputTokens, reasoningField, reasoningEffortDefault }) -- CAMELCASE; the
25
+ // snake_case aliases (base_url/api_key/custom_headers) belong to /api/wall-e/setup/provider,
26
+ // not to this raw upsert route, and would be silently dropped here.
27
+ // POST /api/models/registry rejects any key outside MODEL_REGISTRY_POST_ALLOWED_FIELDS
28
+ // (wall-e/http/model-admin.js:77) with 400 `unknown field: <key>`, so this script sends that
29
+ // allowlist's spellings only.
30
+ // type 'openai-compatible' is what wall-e/llm/worker-route.js upstreamApisForRow() treats as
31
+ // routable on the openai-chat wire (the everything-else branch) -- the same type the render
32
+ // fixture's routeRow() uses.
33
+ //
34
+ // Exit codes: 0 clean shutdown (SIGTERM/SIGINT/--deadline-ms) after the teardown DELETE;
35
+ // 2 refused with NOT ONE request sent (missing --ctm-port, a primary --ctm-port/--walle-port, a
36
+ // port that is not a reachable dev CTM); 3 the coding catalog never listed a route for
37
+ // --route-id within 30 s (the catalog warnings are printed); 4 a write/read handshake failed.
38
+ //
39
+ // This script performs no filesystem I/O at all: it never reads or writes ~/.walle/data or any path
40
+ // outside the OS temp dir (the dev instance owns its own data dir).
41
+
42
+ const { startSyntheticUpstream } = require('./dev-route-fixture/synthetic-route-upstream');
43
+
44
+ // D-10: the user's live primary pair. Refused before any request, by either flag.
45
+ const PRIMARY_PORTS = new Set([3456, 3457]);
46
+
47
+ const POLL_INTERVAL_MS = 1000;
48
+ const POLL_DEADLINE_MS = 30_000;
49
+ const REQUEST_TIMEOUT_MS = 10_000;
50
+ const STATUS_TIMEOUT_MS = 5_000;
51
+ const PAGE_SIZE = 500;
52
+ const MAX_CATALOG_PAGES = 50;
53
+ const API_KEY = 'dev-synthetic-not-a-secret';
54
+
55
+ const DEFAULTS = Object.freeze({
56
+ routeId: 'dev-synthetic',
57
+ model: 'fixture/m-route',
58
+ deadlineMs: 7_200_000,
59
+ });
60
+
61
+ const FLAG_FIELDS = new Map([
62
+ ['--ctm-port', 'ctmPort'],
63
+ ['--walle-port', 'wallePort'],
64
+ ['--route-id', 'routeId'],
65
+ ['--model', 'model'],
66
+ ['--deadline-ms', 'deadlineMs'],
67
+ ]);
68
+
69
+ /** A refusal (exit 2) or a handshake failure (exit 4) carrying the exit code its caller must use. */
70
+ class FixtureFailure extends Error {
71
+ constructor(exitCode, message) {
72
+ super(message);
73
+ this.name = 'FixtureFailure';
74
+ this.exitCode = exitCode;
75
+ }
76
+ }
77
+
78
+ function usageLine() {
79
+ return 'usage: node scripts/dev-route-fixture.js --ctm-port <devPort> [--walle-port <n>] '
80
+ + '[--route-id dev-synthetic] [--model fixture/m-route] [--deadline-ms 7200000]';
81
+ }
82
+
83
+ function messageOf(error) {
84
+ return String(error?.message || error);
85
+ }
86
+
87
+ // REPORT + EXIT: every refusal is printed with the usage line and ends the process before the first
88
+ // network request (D-10). Never a throw the caller could swallow into a later request.
89
+ function refuse(message) {
90
+ process.stderr.write(`dev-route-fixture: refusing: ${message}\n${usageLine()}\n`);
91
+ process.exit(2);
92
+ }
93
+
94
+ function parsePort(raw, flag) {
95
+ if (raw === null || raw === undefined || raw === '') refuse(`${flag} needs a port number`);
96
+ const port = Number(raw);
97
+ if (!Number.isInteger(port) || port < 1 || port > 65535) refuse(`${flag} must be a port number (got ${JSON.stringify(raw)})`);
98
+ if (PRIMARY_PORTS.has(port)) refuse(`${flag} ${port} is the user's PRIMARY instance -- this fixture is dev-only (D-10)`);
99
+ return port;
100
+ }
101
+
102
+ // Accepts `--flag value` and `--flag=value`; an unknown flag or a missing value refuses (a typo
103
+ // silently changing which instance is seeded would be worse than a refusal).
104
+ function parseArgs(argv) {
105
+ const args = { ...DEFAULTS, ctmPort: null, wallePort: null };
106
+ for (let index = 0; index < argv.length; index += 1) {
107
+ const token = argv[index];
108
+ const eq = token.indexOf('=');
109
+ const flag = eq === -1 ? token : token.slice(0, eq);
110
+ const field = FLAG_FIELDS.get(flag);
111
+ if (!field) refuse(`unknown argument ${JSON.stringify(token)}`);
112
+ let value = eq === -1 ? null : token.slice(eq + 1);
113
+ if (value === null) {
114
+ index += 1;
115
+ value = index < argv.length ? argv[index] : null;
116
+ if (value === null || value.startsWith('--')) refuse(`${flag} needs a value`);
117
+ }
118
+ args[field] = value;
119
+ }
120
+ args.ctmPort = parsePort(args.ctmPort, '--ctm-port');
121
+ args.wallePort = args.wallePort === null ? null : parsePort(args.wallePort, '--walle-port');
122
+ const deadlineMs = Number(args.deadlineMs);
123
+ if (!Number.isInteger(deadlineMs) || deadlineMs < 1_000) refuse(`--deadline-ms must be an integer >= 1000 (got ${JSON.stringify(args.deadlineMs)})`);
124
+ args.deadlineMs = deadlineMs;
125
+ args.model = String(args.model ?? '').trim();
126
+ if (!args.model) refuse('--model must not be empty');
127
+ args.routeId = String(args.routeId ?? '').trim();
128
+ if (!/^[A-Za-z0-9._:-]{1,80}$/.test(args.routeId)) refuse(`--route-id must match [A-Za-z0-9._:-]{1,80} (got ${JSON.stringify(args.routeId)})`);
129
+ return args;
130
+ }
131
+
132
+ function ctmBase(ctmPort) {
133
+ return `http://127.0.0.1:${ctmPort}`;
134
+ }
135
+
136
+ // D-10 step 1: the port must really be a running CTM instance. Anything else refuses with no write.
137
+ async function requireDevInstance(ctmPort) {
138
+ const base = ctmBase(ctmPort);
139
+ let res = null;
140
+ let body = null;
141
+ try {
142
+ res = await fetch(`${base}/api/services/status`, { signal: AbortSignal.timeout(STATUS_TIMEOUT_MS) });
143
+ // expected: a non-JSON body is not a CTM status payload -- handled as `body = null` below, and
144
+ // read as a refusal rather than used.
145
+ try { body = await res.json(); } catch { body = null; }
146
+ } catch (error) {
147
+ // REPORT + EXIT 2: nothing answered, so there is nothing to seed and nothing was sent.
148
+ refuse(`GET ${base}/api/services/status failed: ${messageOf(error)}`);
149
+ }
150
+ if (!res.ok) refuse(`GET ${base}/api/services/status -> HTTP ${res.status}`);
151
+ if (!body || body.ctm?.running !== true) refuse(`GET ${base}/api/services/status did not answer as a running CTM instance`);
152
+ }
153
+
154
+ async function postJson(url, body, what) {
155
+ let res = null;
156
+ try {
157
+ res = await fetch(url, {
158
+ method: 'POST',
159
+ headers: { 'Content-Type': 'application/json' },
160
+ body: JSON.stringify(body),
161
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
162
+ });
163
+ } catch (error) {
164
+ throw new FixtureFailure(4, `${what}: POST ${url} failed: ${messageOf(error)}`);
165
+ }
166
+ const text = await res.text();
167
+ if (!res.ok) throw new FixtureFailure(4, `${what}: POST ${url} -> HTTP ${res.status} ${text.slice(0, 400)}`);
168
+ return text;
169
+ }
170
+
171
+ async function getJson(url) {
172
+ let res = null;
173
+ let body = null;
174
+ try {
175
+ res = await fetch(url, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
176
+ // expected: an error body that is not JSON is reported as the raw status line, never parsed.
177
+ try { body = await res.json(); } catch { body = null; }
178
+ } catch (error) {
179
+ throw new FixtureFailure(4, `GET ${url} failed: ${messageOf(error)}`);
180
+ }
181
+ if (!res.ok) throw new FixtureFailure(4, `GET ${url} -> HTTP ${res.status} ${body ? JSON.stringify(body).slice(0, 300) : ''}`);
182
+ return body;
183
+ }
184
+
185
+ // The provider row as the raw upsert route reads it (see the field-name note in the header).
186
+ function providerBody(args, upstreamPort) {
187
+ return {
188
+ id: args.routeId,
189
+ name: 'Dev synthetic',
190
+ type: 'openai-compatible',
191
+ baseUrl: `http://127.0.0.1:${upstreamPort}/v1`,
192
+ apiKeyEncrypted: API_KEY,
193
+ enabled: 1,
194
+ };
195
+ }
196
+
197
+ // The registry entry: MODEL_REGISTRY_POST_ALLOWED_FIELDS spellings only (id, providerId, modelId,
198
+ // displayName, capabilities, enabled, maxContextTokens, maxOutputTokens, source, verificationStatus).
199
+ function registryBody(args) {
200
+ return {
201
+ id: `${args.routeId}:${args.model}`,
202
+ providerId: args.routeId,
203
+ modelId: args.model,
204
+ displayName: `${args.model} (dev synthetic)`,
205
+ capabilities: ['chat', 'tools'],
206
+ enabled: 1,
207
+ maxContextTokens: 131072,
208
+ maxOutputTokens: 8192,
209
+ source: 'manual',
210
+ verificationStatus: 'verified',
211
+ };
212
+ }
213
+
214
+ function itemHasRoute(item, routeId) {
215
+ return Array.isArray(item?.routes) && item.routes.some((route) => route?.provider_id === routeId);
216
+ }
217
+
218
+ // One full paged walk of GET /api/models/coding-catalog, following next_page_token to the end the
219
+ // same way lib/walle-paged-read.js requestWalleAllPages does (a partial walk is never a verdict).
220
+ async function readCatalog(base) {
221
+ const items = [];
222
+ const warnings = [];
223
+ const seenTokens = new Set();
224
+ let token = '';
225
+ for (let page = 0; page < MAX_CATALOG_PAGES; page += 1) {
226
+ const query = new URLSearchParams({ page_size: String(PAGE_SIZE) });
227
+ if (token) query.set('page_token', token);
228
+ const body = await getJson(`${base}/api/models/coding-catalog?${query.toString()}`);
229
+ if (!Array.isArray(body?.models)) throw new FixtureFailure(4, 'GET /api/models/coding-catalog answered without a models array');
230
+ items.push(...body.models);
231
+ for (const warning of Array.isArray(body.catalog_warnings) ? body.catalog_warnings : []) warnings.push(warning);
232
+ if (typeof body.next_page_token !== 'string' || !body.next_page_token) return { items, warnings };
233
+ if (seenTokens.has(body.next_page_token)) throw new FixtureFailure(4, 'GET /api/models/coding-catalog repeated a next_page_token');
234
+ seenTokens.add(body.next_page_token);
235
+ token = body.next_page_token;
236
+ }
237
+ throw new FixtureFailure(4, `GET /api/models/coding-catalog did not finish within ${MAX_CATALOG_PAGES} pages`);
238
+ }
239
+
240
+ function sleep(ms) {
241
+ return new Promise((resolve) => { setTimeout(resolve, ms); });
242
+ }
243
+
244
+ // §6.5 step 4: poll every second for up to 30 s; the deadline is the loop's own bound, never a set
245
+ // number of attempts.
246
+ async function waitForCatalogRoute(base, routeId) {
247
+ const deadline = Date.now() + POLL_DEADLINE_MS;
248
+ for (;;) {
249
+ const catalog = await readCatalog(base);
250
+ if (catalog.items.some((item) => itemHasRoute(item, routeId))) return { ...catalog, found: true };
251
+ if (Date.now() >= deadline) return { ...catalog, found: false };
252
+ await sleep(POLL_INTERVAL_MS);
253
+ }
254
+ }
255
+
256
+ // §6.5 step 5: undo the provider row, then release the upstream. REPORT-only -- a cleanup that
257
+ // cannot reach a dev instance must never turn into a hang or hide the port release.
258
+ async function teardown({ base, routeId, upstream, deleteProvider }) {
259
+ if (deleteProvider) {
260
+ try {
261
+ const res = await fetch(`${base}/api/models/providers/${encodeURIComponent(routeId)}`, {
262
+ method: 'DELETE',
263
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
264
+ });
265
+ if (!res.ok) process.stderr.write(`dev-route-fixture: DELETE provider ${routeId} -> HTTP ${res.status}\n`);
266
+ } catch (error) {
267
+ // REPORT: the dev instance may already be gone; the row dies with its database.
268
+ process.stderr.write(`dev-route-fixture: DELETE provider ${routeId} failed: ${messageOf(error)}\n`);
269
+ }
270
+ }
271
+ try {
272
+ await upstream.close();
273
+ } catch (error) {
274
+ // REPORT: a port that will not close is worth the line; there is nothing left to release it with.
275
+ process.stderr.write(`dev-route-fixture: closing the synthetic upstream failed: ${messageOf(error)}\n`);
276
+ }
277
+ }
278
+
279
+ function waitForShutdown(deadlineMs) {
280
+ return new Promise((resolve) => {
281
+ const timer = setTimeout(() => resolve(`deadline ${deadlineMs}ms reached`), deadlineMs);
282
+ const stop = (signal) => {
283
+ clearTimeout(timer);
284
+ resolve(`received ${signal}`);
285
+ };
286
+ process.once('SIGTERM', () => stop('SIGTERM'));
287
+ process.once('SIGINT', () => stop('SIGINT'));
288
+ });
289
+ }
290
+
291
+ async function main() {
292
+ const args = parseArgs(process.argv.slice(2));
293
+ const base = ctmBase(args.ctmPort);
294
+ await requireDevInstance(args.ctmPort);
295
+ const upstream = await startSyntheticUpstream({ wireModelId: args.model });
296
+ let providerWritten = false;
297
+ try {
298
+ await postJson(`${base}/api/models/providers`, providerBody(args, upstream.port), 'provider write');
299
+ providerWritten = true;
300
+ await postJson(`${base}/api/models/registry`, registryBody(args), 'registry write');
301
+ const catalog = await waitForCatalogRoute(base, args.routeId);
302
+ if (!catalog.found) {
303
+ for (const warning of catalog.warnings) {
304
+ process.stderr.write(`dev-route-fixture: catalog warning ${JSON.stringify(warning)}\n`);
305
+ }
306
+ process.stdout.write(`${JSON.stringify({
307
+ error: 'catalog_route_missing', ctm_port: args.ctmPort, route_id: args.routeId, warnings: catalog.warnings,
308
+ })}\n`);
309
+ await teardown({ base, routeId: args.routeId, upstream, deleteProvider: true });
310
+ process.exit(3);
311
+ }
312
+ } catch (error) {
313
+ // HANDLE + REPORT: undo the partial seed, then exit non-zero -- a half-seeded route must never
314
+ // be reported as success.
315
+ process.stderr.write(`dev-route-fixture: ${messageOf(error)}\n`);
316
+ await teardown({ base, routeId: args.routeId, upstream, deleteProvider: providerWritten });
317
+ process.exit(error?.exitCode || 4);
318
+ }
319
+ // `requests_log` is the synthetic upstream's live request log at print time (empty on a fresh
320
+ // start; the upstream itself records what a routed turn actually sent).
321
+ process.stdout.write(`${JSON.stringify({
322
+ ctm_port: args.ctmPort,
323
+ route_id: args.routeId,
324
+ model: args.model,
325
+ upstream_port: upstream.port,
326
+ requests_log: upstream.requests,
327
+ })}\n`);
328
+ const stopped = await waitForShutdown(args.deadlineMs);
329
+ await teardown({ base, routeId: args.routeId, upstream, deleteProvider: true });
330
+ process.stderr.write(`dev-route-fixture: ${stopped}; provider ${args.routeId} deleted\n`);
331
+ process.exit(0);
332
+ }
333
+
334
+ main().catch((error) => {
335
+ // REPORT: anything reaching here is a bug in this script (a refusal already called process.exit),
336
+ // never a dev-instance state the caller can act on.
337
+ process.stderr.write(`dev-route-fixture: unexpected failure: ${error?.stack || error}\n`);
338
+ process.exit(4);
339
+ });