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
@@ -537,6 +537,32 @@ function catalogSessionIds(machineInstanceId) {
537
537
  return entry ? new Set(entry.byId.keys()) : new Set();
538
538
  }
539
539
 
540
+ /** WP-5: is this a multi-machine install at all? The sessions frame carries `machinesPending` ONLY
541
+ * then — zero registered machines keeps the payload byte-identical to the single-machine one. */
542
+ function hasEnabledMachines(deps = {}) {
543
+ return _enabledMachines(_d(deps)).length > 0;
544
+ }
545
+
546
+ /**
547
+ * WP-5 (§5.4/§8 AC-5a, docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html):
548
+ * how many ENABLED machines have delivered NO session list since this hub booted.
549
+ *
550
+ * Their ids CAN still arrive (the machine sweep + catalog fetch land seconds to a minute after a hub
551
+ * restart), so a client restoring a `tab_order` that names one must not treat the id as dropped. A
552
+ * machine that delivered ONCE is settled — its ids were classified — even if it later drops, and
553
+ * health is deliberately irrelevant: an unreachable or still-'unknown' box that has never answered
554
+ * is exactly the pending case (its ids are the ones the client is waiting for).
555
+ */
556
+ function catalogPendingCount(deps = {}) {
557
+ const d = _d(deps);
558
+ let pending = 0;
559
+ for (const machine of _enabledMachines(d)) {
560
+ const id = _string(machine.instanceId, 160);
561
+ if (id && !_catalogs.has(id)) pending += 1;
562
+ }
563
+ return pending;
564
+ }
565
+
540
566
  /**
541
567
  * S-3/AC-6a: fetch one machine's LIVE session list over the WP-3 machine link.
542
568
  *
@@ -859,7 +885,13 @@ function mergeSessionRows(localRows, deps = {}) {
859
885
  seen.add(id);
860
886
  out.push(remote);
861
887
  }
862
- _lastMergeSignature = JSON.stringify([machines.map((m) => `${m.instanceId}:${m.health}`), out.slice(rows.length)]);
888
+ // WP-5: the pending count joins the signature so a pending->settled flip (a machine that finally
889
+ // delivered its first list) is never elided as a no-op broadcast with identical remote rows.
890
+ _lastMergeSignature = JSON.stringify([
891
+ machines.map((m) => `${m.instanceId}:${m.health}`),
892
+ catalogPendingCount(d),
893
+ out.slice(rows.length),
894
+ ]);
863
895
  return out;
864
896
  }
865
897
 
@@ -883,19 +915,13 @@ function _machineRowForMirror(mirror, d) {
883
915
  }
884
916
 
885
917
  /**
886
- * §7 ownership routing (AC-6b), HTTP half: `POST /api/sessions/:id/(park|revive|pin|wake)` for a
887
- * MIRROR session must be acted on the BOX, never locally — the hub's `parkSession`/`getSession`
888
- * would otherwise be asked about a session it does not have (OQ-4: mirror sessions are deliberately
889
- * NOT in the hub's sessions Map).
918
+ * The shared middle of every mirror forwarder (lifecycle + WP-2's lead-model): resolve the mirror to
919
+ * the registry row that owns it and write the ONE refusal shape when the box cannot be reached. The
920
+ * three bodies below are byte-identical to what each forwarder used to write inline.
890
921
  *
891
- * @returns {Promise<boolean>} true = the request was answered here (do NOT run the local handler)
922
+ * @returns {{machine: object, machineName: string, proxy: object}|null} null = already refused here
892
923
  */
893
- async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
894
- const d = _d(deps);
895
- const verb = _string(action, 20);
896
- if (!['park', 'revive', 'pin', 'wake'].includes(verb)) return false;
897
- const mirror = getMirrorSessionMachine(sessionId, d);
898
- if (!mirror) return false; // a LOCAL session takes the byte-identical existing path
924
+ function _forwardTarget(res, mirror, d) {
899
925
  const machine = _machineRowForMirror(mirror, d);
900
926
  const machineName = _string(machine ? machine.displayName : mirror.machineName, 200);
901
927
  if (!machine) {
@@ -903,16 +929,16 @@ async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
903
929
  ok: false, code: 'machine_unreachable', error: `Machine ${machineName || mirror.machineInstanceId} is not available`,
904
930
  machine: mirror.machineInstanceId, machineName,
905
931
  });
906
- return true;
932
+ return null;
907
933
  }
908
934
  if (_string(machine.health, 40) === 'unreachable') {
909
- // Never a local act: a lifecycle action on a session the hub does not own is refused, not
910
- // silently applied to a same-id session on this host (which does not exist anyway).
935
+ // Never a local act: an action on a session the hub does not own is refused, not silently
936
+ // applied to a same-id session on this host (which does not exist anyway).
911
937
  _sendJson(res, 503, {
912
938
  ok: false, code: 'machine_unreachable', error: `Machine ${machineName} is unreachable`,
913
939
  machine: mirror.machineInstanceId, machineName,
914
940
  });
915
- return true;
941
+ return null;
916
942
  }
917
943
  const proxy = _peer('proxy', d);
918
944
  if (!proxy || typeof proxy.forwardMachineHttp !== 'function') {
@@ -920,15 +946,18 @@ async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
920
946
  ok: false, code: 'machine_unreachable', error: `Machine ${machineName} could not be reached`,
921
947
  machine: mirror.machineInstanceId, machineName,
922
948
  });
923
- return true;
949
+ return null;
924
950
  }
925
- const result = await proxy.forwardMachineHttp({
926
- machine: machine,
927
- pathname: `/api/sessions/${encodeURIComponent(mirror && sessionId)}/${verb}`,
928
- method: 'POST',
929
- body: '',
930
- deps: d,
931
- });
951
+ return { machine, machineName, proxy };
952
+ }
953
+
954
+ /**
955
+ * The shared tail: a failed dial is the one refusal shape, and the box's own status + body are
956
+ * returned VERBATIM (§6.5) — the client parses the box's answer exactly as it parses the local one.
957
+ *
958
+ * @returns {true} always — the request was answered here.
959
+ */
960
+ function _relayBoxAnswer(res, result, mirror, machineName) {
932
961
  if (!result || !result.ok) {
933
962
  _sendJson(res, 503, {
934
963
  ok: false, code: (result && result.code) || 'machine_unreachable',
@@ -937,8 +966,6 @@ async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
937
966
  });
938
967
  return true;
939
968
  }
940
- // The box's own status and body are returned VERBATIM (§6.5): the client parses the box's answer
941
- // exactly as it parses the local one.
942
969
  if (!res.headersSent) {
943
970
  res.writeHead(Number(result.status) || 502, { 'Content-Type': result.contentType || 'application/json' });
944
971
  res.end(result.text || '');
@@ -946,6 +973,260 @@ async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
946
973
  return true;
947
974
  }
948
975
 
976
+ /**
977
+ * §7 ownership routing (AC-6b), HTTP half: `POST /api/sessions/:id/(park|revive|pin|wake)` for a
978
+ * MIRROR session must be acted on the BOX, never locally — the hub's `parkSession`/`getSession`
979
+ * would otherwise be asked about a session it does not have (OQ-4: mirror sessions are deliberately
980
+ * NOT in the hub's sessions Map).
981
+ *
982
+ * @returns {Promise<boolean>} true = the request was answered here (do NOT run the local handler)
983
+ */
984
+ async function forwardLifecycleRequest(req, res, sessionId, action, deps = {}) {
985
+ const d = _d(deps);
986
+ const verb = _string(action, 20);
987
+ if (!['park', 'revive', 'pin', 'wake'].includes(verb)) return false;
988
+ const mirror = getMirrorSessionMachine(sessionId, d);
989
+ if (!mirror) return false; // a LOCAL session takes the byte-identical existing path
990
+ const target = _forwardTarget(res, mirror, d);
991
+ if (!target) return true;
992
+ const result = await target.proxy.forwardMachineHttp({
993
+ machine: target.machine,
994
+ pathname: `/api/sessions/${encodeURIComponent(mirror && sessionId)}/${verb}`,
995
+ method: 'POST',
996
+ body: '',
997
+ deps: d,
998
+ });
999
+ return _relayBoxAnswer(res, result, mirror, target.machineName);
1000
+ }
1001
+
1002
+ // ---------------------------------------------------------------------------------------------
1003
+ // WP-2 (docs/remote-box-model-access-2026-10-26.html §1.3 C-6, §5.1 R-4/R-8, §5.3 D-4, §6.3) —
1004
+ // the model picker's four calls for a MIRROR session
1005
+ // ---------------------------------------------------------------------------------------------
1006
+ //
1007
+ // `GET .../lead-model/options`, `POST .../lead-model`, `GET .../lead-model/request` and
1008
+ // `DELETE .../lead-model/request` are answered hub-locally today, and for a mirror id that is a
1009
+ // `404 session_not_found` (the id is deliberately NOT in the hub's sessions Map, so
1010
+ // lib/lead-model-options.js can never serve it). The BOX owns the session, its CLI and its
1011
+ // servability rules (D-4), so the four calls are forwarded there exactly like the lifecycle verbs
1012
+ // above: a local id takes the byte-identical existing path, an unknown/down box is the shared 503
1013
+ // `machine_unreachable`, and otherwise the box's status + body come back VERBATIM.
1014
+
1015
+ /** kind → the BOX route it belongs to. `switch` is the only kind that carries a body. */
1016
+ const LEAD_MODEL_FORWARDS = Object.freeze({
1017
+ options: { method: 'GET', suffix: '/lead-model/options' },
1018
+ switch: { method: 'POST', suffix: '/lead-model' },
1019
+ request: { method: 'GET', suffix: '/lead-model/request' },
1020
+ 'request-cancel': { method: 'DELETE', suffix: '/lead-model/request' },
1021
+ });
1022
+
1023
+ // The local POST handler's own bound (lib/api/sessions.js handleLeadModelSwitch: 4 KiB), so a body
1024
+ // the hub itself would refuse is never dialled out. The bytes forwarded are the caller's, as-is.
1025
+ const LEAD_MODEL_BODY_LIMIT_BYTES = 4 * 1024;
1026
+
1027
+ /** The request's query string, unchanged ('' when there is none). */
1028
+ function _searchOf(req) {
1029
+ const raw = String((req && req.url) || '');
1030
+ const at = raw.indexOf('?');
1031
+ return at < 0 ? '' : raw.slice(at);
1032
+ }
1033
+
1034
+ /** The request's own path — the part of `req.url` before `?`, never decoded/re-encoded. */
1035
+ function _pathOf(req) {
1036
+ const raw = String((req && req.url) || '');
1037
+ const at = raw.indexOf('?');
1038
+ return at < 0 ? raw : raw.slice(0, at);
1039
+ }
1040
+
1041
+ // D-4 (lib/remote-session-forward.js:58-61): the hub's OWN device token and the picker's routing
1042
+ // param belong to the first hop and must never be dialled to the box — the box's own `getAuthToken`
1043
+ // prefers `?token=` over the peer Bearer, so a forwarded `token` would shadow the peer credential.
1044
+ const DELEGATE_PREFS_STRIPPED_PARAMS = Object.freeze(['token', 'machine']);
1045
+
1046
+ // WP-1 (docs/remote-session-delegate-pick-write-forward-2026-10-30.html D-1/D-2): the delegate-prefs
1047
+ // READ plus the two WRITES that set a rung of the box's own ladder cross the same peer leg. Any other
1048
+ // verb is not a delegate-prefs forward at all (the caller keeps its unchanged local path).
1049
+ const DELEGATE_PREFS_FORWARD_METHODS = Object.freeze(['GET', 'PUT', 'DELETE']);
1050
+
1051
+ /**
1052
+ * The delegate-prefs read's query string with the hub's protocol params removed ('' when nothing is
1053
+ * left). `ctm_session_id` and `agent` — everything that is the box's business — cross unchanged.
1054
+ */
1055
+ function _delegatePrefsSearch(req) {
1056
+ const raw = _searchOf(req);
1057
+ if (!raw) return '';
1058
+ const params = new URLSearchParams(raw);
1059
+ for (const key of DELEGATE_PREFS_STRIPPED_PARAMS) params.delete(key);
1060
+ const rest = params.toString();
1061
+ return rest ? `?${rest}` : '';
1062
+ }
1063
+
1064
+ /** The request body as the caller wrote it, bounded like the local handler. */
1065
+ function _readLeadModelBody(req) {
1066
+ return new Promise((resolve, reject) => {
1067
+ let raw = '';
1068
+ let size = 0;
1069
+ let done = false;
1070
+ const finish = (fn, value) => { if (done) return; done = true; fn(value); };
1071
+ req.on('data', (chunk) => {
1072
+ if (done) return;
1073
+ size += chunk.length;
1074
+ if (size > LEAD_MODEL_BODY_LIMIT_BYTES) { finish(reject, new Error('request_body_too_large')); return; }
1075
+ raw += chunk;
1076
+ });
1077
+ req.on('end', () => finish(resolve, raw));
1078
+ req.on('error', (error) => finish(reject, error));
1079
+ });
1080
+ }
1081
+
1082
+ /**
1083
+ * Like forwardLifecycleRequest: true = the request was answered here (do NOT run the local handler).
1084
+ *
1085
+ * @param {'options'|'switch'|'request'|'request-cancel'} kind
1086
+ * @returns {Promise<boolean>}
1087
+ */
1088
+ async function forwardLeadModelRequest(req, res, sessionId, kind, deps = {}) {
1089
+ const d = _d(deps);
1090
+ const spec = LEAD_MODEL_FORWARDS[_string(kind, 20)];
1091
+ if (!spec) return false;
1092
+ const mirror = getMirrorSessionMachine(sessionId, d);
1093
+ if (!mirror) return false; // a LOCAL session takes the byte-identical existing path
1094
+ const target = _forwardTarget(res, mirror, d);
1095
+ if (!target) return true;
1096
+ let body = '';
1097
+ if (spec.method === 'POST') {
1098
+ // Mirrors lib/api/sessions.js handleLeadModelSwitch's own admission (413 too large / 400
1099
+ // otherwise, same body) so the two agreement points cannot drift.
1100
+ try { body = await _readLeadModelBody(req); }
1101
+ catch (error) { return _sendJson(res, error && error.message === 'request_body_too_large' ? 413 : 400, { ok: false, code: 'invalid_request', message: error && error.message || 'Invalid request.' }); }
1102
+ }
1103
+ const result = await target.proxy.forwardMachineHttp({
1104
+ machine: target.machine,
1105
+ pathname: `/api/sessions/${encodeURIComponent(sessionId)}${spec.suffix}`,
1106
+ search: _searchOf(req),
1107
+ method: spec.method,
1108
+ body,
1109
+ deps: d,
1110
+ });
1111
+ return _relayBoxAnswer(res, result, mirror, target.machineName);
1112
+ }
1113
+
1114
+ /**
1115
+ * WP-3 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html §5 D-4) GET,
1116
+ * and WP-1 (docs/remote-session-delegate-pick-write-forward-2026-10-30.html D-1/D-2/D-7) PUT/DELETE:
1117
+ * /api/models/delegate-prefs[?ctm_session_id=<id>&agent=<a>] for a BOX-owned session is answered by
1118
+ * the box's own Wall-E ladder (session pick > per-agent default > vendor), not the hub's — the READ,
1119
+ * and the per-session / per-agent WRITES that set those rungs, take the same peer leg. Returns true
1120
+ * when the response was written (forwarded or refused); false for a local/unclaimed id or an
1121
+ * unsupported verb (the caller takes the unchanged proxyHttp path).
1122
+ *
1123
+ * @returns {Promise<boolean>}
1124
+ */
1125
+ async function forwardDelegatePrefsRequest(req, res, sessionId, deps = {}) {
1126
+ const d = _d(deps);
1127
+ const method = String((req && req.method) || '').toUpperCase();
1128
+ if (!DELEGATE_PREFS_FORWARD_METHODS.includes(method)) return false;
1129
+ const mirror = getMirrorSessionMachine(sessionId, d);
1130
+ if (!mirror) return false; // a LOCAL session takes the byte-identical existing path
1131
+ const target = _forwardTarget(res, mirror, d);
1132
+ if (!target) return true;
1133
+ let body = '';
1134
+ if (method === 'PUT') {
1135
+ // Mirrors lib/api/sessions.js handleLeadModelSwitch's own admission (413 too large / 400
1136
+ // otherwise, same body) so the two agreement points cannot drift.
1137
+ try { body = await _readLeadModelBody(req); }
1138
+ catch (error) { return _sendJson(res, error && error.message === 'request_body_too_large' ? 413 : 400, { ok: false, code: 'invalid_request', message: error && error.message || 'Invalid request.' }); }
1139
+ }
1140
+ const result = await target.proxy.forwardMachineHttp({
1141
+ machine: target.machine,
1142
+ pathname: _pathOf(req),
1143
+ search: _delegatePrefsSearch(req),
1144
+ method,
1145
+ body,
1146
+ deps: d,
1147
+ });
1148
+ return _relayBoxAnswer(res, result, mirror, target.machineName);
1149
+ }
1150
+
1151
+ /**
1152
+ * WP-1/AC-1h (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html): the
1153
+ * sidebar's "Clear N finished" retires a lead's finished workers by POSTing { lead } (or { ids }) to
1154
+ * /api/sessions/workers/retire. For a BOX-owned lead those rows live in the box's worker_sessions,
1155
+ * so the call is forwarded to the owning machine by looking the ids up in the mirror union.
1156
+ * Returns true when the response was written (forwarded, or refused); false when every id is local
1157
+ * or unclaimed (the caller runs the byte-identical local path).
1158
+ *
1159
+ * Unlike the per-session forwards above, this route carries the ids in its BODY, not in the path — so
1160
+ * the ownership decision is made here, after the caller has parsed and validated the JSON, and the
1161
+ * body is re-serialized byte-for-byte to the one machine that owns every id.
1162
+ *
1163
+ * @param {object} body the already-parsed, already-validated request body ({ ids?: string[], lead?: string })
1164
+ * @returns {Promise<boolean>}
1165
+ */
1166
+ async function forwardWorkersRetireRequest(req, res, body, deps = {}) {
1167
+ const d = _d(deps);
1168
+ const raw = body && typeof body === 'object' ? body : {};
1169
+ const candidates = [];
1170
+ if (typeof raw.lead === 'string' && raw.lead.trim()) candidates.push(raw.lead.trim());
1171
+ if (Array.isArray(raw.ids)) {
1172
+ for (const entry of raw.ids) {
1173
+ const id = _string(entry, 200);
1174
+ if (id) candidates.push(id);
1175
+ }
1176
+ }
1177
+ if (!candidates.length) return false;
1178
+ const mirrors = candidates.map((id) => getMirrorSessionMachine(id, d));
1179
+ const claimed = mirrors.filter(Boolean);
1180
+ if (!claimed.length) return false; // every id is local or unclaimed: the byte-identical local path
1181
+ const machineInstanceId = claimed[0].machineInstanceId;
1182
+ // A mix of local and mirror ids, or mirrors of two different machines, has no single owner to send
1183
+ // the one POST to — never split the call, never apply half of it here.
1184
+ if (claimed.length !== candidates.length || claimed.some((m) => m.machineInstanceId !== machineInstanceId)) {
1185
+ _sendJson(res, 400, { ok: false, code: 'mixed_owners', message: 'Retire ids must all belong to one machine.' });
1186
+ return true;
1187
+ }
1188
+ const mirror = claimed[0];
1189
+ const target = _forwardTarget(res, mirror, d);
1190
+ if (!target) return true; // a refusal was already written
1191
+ const result = await target.proxy.forwardMachineHttp({
1192
+ machine: target.machine,
1193
+ pathname: '/api/sessions/workers/retire',
1194
+ search: '',
1195
+ method: 'POST',
1196
+ // forwardMachineHttp sets `Content-Type: application/json` itself for a non-GET/HEAD verb; the
1197
+ // caller's own JSON body crosses unmodified.
1198
+ body: JSON.stringify(raw),
1199
+ deps: d,
1200
+ });
1201
+ return _relayBoxAnswer(res, result, mirror, target.machineName);
1202
+ }
1203
+
1204
+ /**
1205
+ * WP-1 (docs/remote-session-rename-forward-and-empty-rows-2026-10-30.html §5 D-1/D-2): a rename or
1206
+ * star of a BOX-owned session is the box's write. Body-keyed like forwardWorkersRetireRequest: the
1207
+ * caller has parsed and validated the JSON; the body is re-serialized to the owning box's same route.
1208
+ * Returns true when the response was written (forwarded or refused); false for a local/unclaimed id
1209
+ * (the caller runs the byte-identical local path).
1210
+ *
1211
+ * @param {object} body the already-parsed request body ({ sessionId?: string, id?: string, ... })
1212
+ * @returns {Promise<boolean>}
1213
+ */
1214
+ async function forwardSessionTitleWrite(req, res, body, deps = {}) {
1215
+ const d = _d(deps);
1216
+ const raw = body && typeof body === 'object' ? body : {};
1217
+ const id = _string(raw.sessionId || raw.id, 200);
1218
+ if (!id) return false;
1219
+ const mirror = getMirrorSessionMachine(id, d);
1220
+ if (!mirror) return false;
1221
+ const target = _forwardTarget(res, mirror, d);
1222
+ if (!target) return true;
1223
+ const result = await target.proxy.forwardMachineHttp({
1224
+ machine: target.machine, pathname: _pathOf(req), search: '', method: 'POST',
1225
+ body: JSON.stringify(raw), deps: d,
1226
+ });
1227
+ return _relayBoxAnswer(res, result, mirror, target.machineName);
1228
+ }
1229
+
949
1230
  function _sendJson(res, status, payload) {
950
1231
  const body = JSON.stringify(payload);
951
1232
  if (res.headersSent) return true;
@@ -1045,6 +1326,9 @@ module.exports = {
1045
1326
  ingestFenceCounters,
1046
1327
  catalogFor,
1047
1328
  catalogSessionIds,
1329
+ // WP-5 (§5.4): the hub's own truth for "a box tab may still be on its way" + the multi-machine gate.
1330
+ catalogPendingCount,
1331
+ hasEnabledMachines,
1048
1332
  fetchCatalog,
1049
1333
  refreshAll,
1050
1334
  onLinkReady,
@@ -1056,6 +1340,17 @@ module.exports = {
1056
1340
  mergeSessionRows,
1057
1341
  lastMergeSignature,
1058
1342
  forwardLifecycleRequest,
1343
+ // WP-2 (§6.3): the picker's four lead-model calls for a MIRROR session go to the box that owns it.
1344
+ forwardLeadModelRequest,
1345
+ // WP-3 (§5 D-4): the Delegate pane's ladder read for a BOX-owned session is answered by the box.
1346
+ forwardDelegatePrefsRequest,
1347
+ // WP-1 (docs/remote-session-child-transcript-model-truth-and-restart-2026-10-27.html AC-1h): the
1348
+ // body-keyed sibling — "Clear N finished" for a BOX-owned lead retires on the box that owns it.
1349
+ forwardWorkersRetireRequest,
1350
+ // WP-1 (docs/remote-session-rename-forward-and-empty-rows-2026-10-30.html §5 D-1/D-2, §8 WP-1): a
1351
+ // rename or star of a BOX-owned session is the box's write — the body-keyed sibling that forwards it
1352
+ // to the owning machine's same route instead of writing the hub's ledger for an id it does not own.
1353
+ forwardSessionTitleWrite,
1059
1354
  resumeMachineFor,
1060
1355
  forwardResumeOnMachine,
1061
1356
  _resetForTests,