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
@@ -15,6 +15,7 @@
15
15
 
16
16
  const fs = require('fs');
17
17
  const path = require('path');
18
+ const { NOOP_LAP, createPerfTrace, perfPhasesJson } = require('./lib/perf-phase-trace');
18
19
  const { writeStartupPointerGuarded, readStartupTaskProjectDir } = require('./lib/startup-pointer-write');
19
20
  const crypto = require('crypto');
20
21
  const claudeDesktopSessions = require('./lib/claude-desktop-sessions');
@@ -65,6 +66,17 @@ function resolveWalleLiveTranscriptPath(ctmSessionId, chatSessionId) {
65
66
  // stale-metadata check (2) still run.
66
67
  const INTEGRITY_CONTENT_CHECK_MAX_BYTES = 256 * 1024 * 1024;
67
68
 
69
+ // --- Perf attribution (WP-0 / M-3, measurement only; see lib/perf-phase-trace.js) ---
70
+ // The trace of the detectMismatches run in flight — lets the findCodexSessionFiles wrapper
71
+ // below count calls made from helpers that do not receive the trace. detectMismatches is
72
+ // synchronous and never re-entrant, so one slot is enough.
73
+ let _activeDetectPerfTrace = null;
74
+
75
+ function findCodexSessionFilesCounted(sessionId) {
76
+ const trace = _activeDetectPerfTrace;
77
+ return trace ? trace.timed('findCodexSessionFiles', () => findCodexSessionFiles(sessionId)) : findCodexSessionFiles(sessionId);
78
+ }
79
+
68
80
  // --- Detection ---
69
81
 
70
82
  function sessionFileIdFromPath(filePath) {
@@ -358,7 +370,8 @@ function codexAgentRowHasTranscript(row) {
358
370
  * Run a full integrity check between the sessions DB and JSONL files on disk.
359
371
  * Returns an array of issue objects, each with { type, severity, sessionId, details, suggestion }.
360
372
  */
361
- function detectMismatches(db, getAllSessionFiles) {
373
+ function _detectMismatchesInner(db, getAllSessionFiles, trace) {
374
+ const lap = trace ? trace.lap : NOOP_LAP;
362
375
  const issues = [];
363
376
  // 1. Load all DB sessions (v1 schema: ctm_sessions + agent_sessions)
364
377
  let allSessions;
@@ -397,10 +410,12 @@ function detectMismatches(db, getAllSessionFiles) {
397
410
  LEFT JOIN agent_sessions a ON a.ctm_session_id = c.id
398
411
  `).all();
399
412
  } catch (e) {
413
+ lap('load_sessions', 0);
400
414
  issues.push({ type: 'db_error', severity: 'critical', sessionId: null,
401
415
  details: { error: e.message }, suggestion: 'Check DB connectivity' });
402
416
  return issues;
403
417
  }
418
+ lap('load_sessions', 1);
404
419
 
405
420
  // 2. Build file index from disk
406
421
  const fileIndex = {}; // uuid -> { filePath, stat, projectEntry }
@@ -412,6 +427,7 @@ function detectMismatches(db, getAllSessionFiles) {
412
427
  issues.push({ type: 'scan_error', severity: 'warning', sessionId: null,
413
428
  details: { error: e.message }, suggestion: 'JSONL directory may be inaccessible' });
414
429
  }
430
+ lap('build_file_index', Object.keys(fileIndex).length);
415
431
 
416
432
  const timestampStartBySession = new Map();
417
433
  for (const row of allSessions) {
@@ -434,6 +450,7 @@ function detectMismatches(db, getAllSessionFiles) {
434
450
  });
435
451
  }
436
452
  }
453
+ lap('timestamp_start_pass', allSessions.length);
437
454
 
438
455
  // 3. Track claims to detect duplicates
439
456
  const agentIdClaims = {}; // agent_session_id -> [session ids that claim it]
@@ -457,6 +474,7 @@ function detectMismatches(db, getAllSessionFiles) {
457
474
  const expectedFileId = (agentId && agentId !== sid) ? agentId : sid;
458
475
  const file = resolveDbSessionFile(row, expectedFileId, fileIndex);
459
476
  let reportedCodexAgentJsonlMismatch = false;
477
+ lap('check0_row_prep', 1);
460
478
 
461
479
  if (isCodexSessionRow(row) && agentId) {
462
480
  const providerResumeId = String(row.provider_resume_id || '').trim();
@@ -502,6 +520,7 @@ function detectMismatches(db, getAllSessionFiles) {
502
520
  reportedCodexAgentJsonlMismatch = true;
503
521
  }
504
522
  }
523
+ lap('check0_codex_alias', (isCodexSessionRow(row) && agentId) ? 1 : 0);
505
524
 
506
525
  // Check 1: Missing file
507
526
  if (!file && row.file_size > 0 && !reportedCodexAgentJsonlMismatch) {
@@ -531,10 +550,15 @@ function detectMismatches(db, getAllSessionFiles) {
531
550
  suggestion: 'File may have been deleted or moved. Check .jsonl.bak variant.',
532
551
  });
533
552
  }
553
+ lap('check1_missing_file', 1);
534
554
  continue;
535
555
  }
536
556
 
537
- if (!file) continue; // No file expected or found — OK for legacy entries
557
+ if (!file) {
558
+ lap('check1_missing_file', 1);
559
+ continue; // No file expected or found — OK for legacy entries
560
+ }
561
+ lap('check1_missing_file', 1);
538
562
 
539
563
  // Check 2: Stale metadata (file_size mismatch)
540
564
  if (row.file_size > 0 && file.stat.size > 0) {
@@ -557,6 +581,7 @@ function detectMismatches(db, getAllSessionFiles) {
557
581
  });
558
582
  }
559
583
  }
584
+ lap('check2_stale_metadata', 1);
560
585
 
561
586
  // Check 3: Timestamp drift (created_at vs JSONL timestamp)
562
587
  // Filesystem birthtime is not reliable for Claude JSONL sessions: Dropbox,
@@ -586,6 +611,7 @@ function detectMismatches(db, getAllSessionFiles) {
586
611
  });
587
612
  }
588
613
  }
614
+ lap('check3_timestamp_drift', 1);
589
615
 
590
616
  // Check 4a: Wrong mapping via slug mismatch (primary, slug-based detector).
591
617
  // Flags rows whose slug differs from the tab's canonical slug AND whose
@@ -651,6 +677,7 @@ function detectMismatches(db, getAllSessionFiles) {
651
677
  }
652
678
  }
653
679
  } catch (e) { /* lineage helpers unavailable — fall through to content check */ }
680
+ lap('check4a_slug_mapping', 1);
654
681
 
655
682
  // Check 4b: Wrong mapping detection via content fingerprint (legacy).
656
683
  // Kept for pre-slug JSONLs and as a defense-in-depth check.
@@ -689,6 +716,7 @@ function detectMismatches(db, getAllSessionFiles) {
689
716
  }
690
717
  } catch {}
691
718
  }
719
+ lap('check4b_content_mapping', 1);
692
720
  }
693
721
 
694
722
  // Check 5: Duplicate claims
@@ -705,6 +733,7 @@ function detectMismatches(db, getAllSessionFiles) {
705
733
  });
706
734
  }
707
735
  }
736
+ lap('check5_duplicate_claims', Object.keys(agentIdClaims).length);
708
737
 
709
738
  // Check 6: Orphan files (on disk but not in DB)
710
739
  const dbFileIds = new Set();
@@ -712,13 +741,15 @@ function detectMismatches(db, getAllSessionFiles) {
712
741
  addAgentRowFileIds(dbFileIds, row);
713
742
  if (isCodexSessionRow(row) && row.agent_session_id) {
714
743
  try {
715
- for (const filePath of findCodexSessionFiles(row.agent_session_id)) {
744
+ for (const filePath of findCodexSessionFilesCounted(row.agent_session_id)) {
716
745
  const rolloutFileId = sessionFileIdFromPath(filePath);
717
746
  if (rolloutFileId) dbFileIds.add(rolloutFileId);
718
747
  }
719
748
  } catch {}
720
749
  }
721
750
  }
751
+ lap('check6_pass1', allSessions.length);
752
+ let agentRowCount = 0;
722
753
  try {
723
754
  const agentCols = new Set(db.prepare('PRAGMA table_info(agent_sessions)').all().map(c => c.name));
724
755
  const threadSourceCol = agentCols.has('thread_source') ? 'thread_source' : "'' AS thread_source";
@@ -728,11 +759,12 @@ function detectMismatches(db, getAllSessionFiles) {
728
759
  ${threadSourceCol}, ${parentAgentSessionCol}
729
760
  FROM agent_sessions
730
761
  `).all();
762
+ agentRowCount = allAgentRows.length;
731
763
  for (const row of allAgentRows) {
732
764
  addAgentRowFileIds(dbFileIds, row);
733
765
  if (isCodexSessionRow(row) && row.agent_session_id) {
734
766
  try {
735
- for (const filePath of findCodexSessionFiles(row.agent_session_id)) {
767
+ for (const filePath of findCodexSessionFilesCounted(row.agent_session_id)) {
736
768
  const rolloutFileId = sessionFileIdFromPath(filePath);
737
769
  if (rolloutFileId) dbFileIds.add(rolloutFileId);
738
770
  }
@@ -740,6 +772,7 @@ function detectMismatches(db, getAllSessionFiles) {
740
772
  }
741
773
  }
742
774
  } catch {}
775
+ lap('check6_pass2', agentRowCount);
743
776
  for (const issue of issues) {
744
777
  if (issue.type === 'codex_agent_jsonl_mismatch' && issue.details?.file_agent_session_id) {
745
778
  dbFileIds.add(issue.details.file_agent_session_id);
@@ -770,6 +803,7 @@ function detectMismatches(db, getAllSessionFiles) {
770
803
  suggestion: `${orphanCount} orphan files total. Only first 10 reported.`,
771
804
  });
772
805
  }
806
+ lap('check6_orphan_count', orphanCount);
773
807
 
774
808
  // Check 6b: Codex startup_tasks must contain provider-native resume args.
775
809
  // A CTM tab UUID is a lifecycle id, not a Codex resume id. If a crash restart
@@ -834,6 +868,7 @@ function detectMismatches(db, getAllSessionFiles) {
834
868
  suggestion: 'Startup task integrity scan failed; check startup_tasks schema.',
835
869
  });
836
870
  }
871
+ lap('check6b_startup_resume', 1);
837
872
 
838
873
  // Check 7: Orphan top-level agent_sessions (no valid ctm_session parent).
839
874
  // Provider-native child threads (Codex subagents, etc.) are deliberately
@@ -875,7 +910,32 @@ function detectMismatches(db, getAllSessionFiles) {
875
910
  } catch (e) {
876
911
  console.error('[session-integrity] Error checking orphan agent_sessions:', e.message);
877
912
  }
913
+ lap('check7_orphan_agents', 1);
914
+
915
+ return issues;
916
+ }
878
917
 
918
+ /**
919
+ * Perf-attribution wrapper (WP-0 / M-3): runs the detection scan with a phase trace,
920
+ * attaches it as `issues.phases` (additive; a property on the array, so consumers that
921
+ * iterate/filter it and JSON serialization of an array are both unaffected) and logs one
922
+ * `[session-integrity] phases {...}` line for this run. Measurement only — the trace is
923
+ * null when CTM_PERF_ATTRIBUTION is off, in which case nothing is attached or logged.
924
+ */
925
+ function detectMismatches(db, getAllSessionFiles) {
926
+ const trace = createPerfTrace();
927
+ _activeDetectPerfTrace = trace;
928
+ let issues;
929
+ try {
930
+ issues = _detectMismatchesInner(db, getAllSessionFiles, trace);
931
+ } finally {
932
+ _activeDetectPerfTrace = null;
933
+ }
934
+ if (trace) {
935
+ trace.lap('finalize', 1);
936
+ issues.phases = trace.phases;
937
+ console.log(`[session-integrity] phases ${perfPhasesJson('detect', trace)}`);
938
+ }
879
939
  return issues;
880
940
  }
881
941
 
@@ -163,6 +163,9 @@ function _interactiveRequestPending() {
163
163
  });
164
164
  }
165
165
 
166
+ // WP-0c (§6.5 D-13, AC-0e): names a `low` dispatch while signalled high/urgent work is not yet queued.
167
+ const observeLowDispatch = require('../lib/db-owner-dispatch-probe').createLowOverSignalledProbe();
168
+
166
169
  // Background writer: transient write-lock contention with the main thread should
167
170
  // retry rather than surface (e.g. a pasted image failing). Safe because a busy
168
171
  // error means the write never started. This worker thread may async-wait freely.
@@ -1778,6 +1781,11 @@ async function _runOpWithCursorPublication(op, payload = {}, rowCursorBases = []
1778
1781
  };
1779
1782
  }
1780
1783
 
1784
+ // D-12 (S-17): dispatch on the NEXT turn, never inline from a delivery or a completion. Inline,
1785
+ // every delivered request ran at once on an empty queue, so the MessagePort's FIFO decided the order
1786
+ // and a high request posted behind three lows ran fourth (tests-integration/db-owner-repump-starvation.test.js).
1787
+ let _pumpScheduled = false;
1788
+ function _schedulePump() { if (_pumpScheduled) return; _pumpScheduled = true; setImmediate(() => { _pumpScheduled = false; _pump(); }); }
1781
1789
  function _pump() {
1782
1790
  if (active || closing) return;
1783
1791
  const dispatchNow = Date.now();
@@ -1786,6 +1794,15 @@ function _pump() {
1786
1794
  _postStatus();
1787
1795
  return;
1788
1796
  }
1797
+ if (task.priority === 'low') {
1798
+ observeLowDispatch({
1799
+ op: task.op,
1800
+ snapshot: workSignal?.snapshot(),
1801
+ queuedUrgent: queue.pendingUrgent(),
1802
+ queuedHigh: queue.pendingHigh(),
1803
+ at: dispatchNow,
1804
+ });
1805
+ }
1789
1806
  try {
1790
1807
  activeDecl = getDbOwnerDispatchDeclaration(task.op, task.payload);
1791
1808
  assertDbOwnerOpDispatch(activeDecl, {
@@ -1929,7 +1946,7 @@ function _pump() {
1929
1946
  activeWedgeDumped = false;
1930
1947
  activeBudgetLogged = false;
1931
1948
  try { dbOwnerHeartbeat?.clear(); } catch { /* expected: same best-effort observability rationale as the beat() call above */ }
1932
- _pump();
1949
+ _schedulePump(); // D-12 (S-17), see _schedulePump
1933
1950
  });
1934
1951
  }
1935
1952
 
@@ -1978,7 +1995,7 @@ function _enqueue(msg) {
1978
1995
  return;
1979
1996
  }
1980
1997
  enqueued += 1;
1981
- _pump();
1998
+ _schedulePump();
1982
1999
  }
1983
2000
 
1984
2001
  function _postCancelledResponse(task, reason = '') {
@@ -13,6 +13,7 @@ function serializeError(error) {
13
13
 
14
14
  db.createBackupFromPath(workerData.dbPath, workerData.label, {
15
15
  backupDir: workerData.backupDir,
16
+ retentionDays: workerData.retentionDays,
16
17
  }).then(
17
18
  (result) => parentPort.postMessage({ ok: true, result }),
18
19
  (error) => parentPort.postMessage({ ok: false, error: serializeError(error) }),
@@ -139,7 +139,7 @@ function collectNativeModelObservations(items, options = {}) {
139
139
  try {
140
140
  for (const item of items) {
141
141
  activeResultIndex = out.length;
142
- if (!item || typeof item !== 'object' || typeof item.id !== 'string' || safeText(item.id) !== item.id || !['claude', 'codex', 'gemini', 'opencode'].includes(item.agentType) || ownerRejection(item.owner, item.agentType) !== null) {
142
+ if (!item || typeof item !== 'object' || typeof item.id !== 'string' || safeText(item.id) !== item.id || !['claude', 'codex', 'gemini', 'opencode', 'dsh'].includes(item.agentType) || ownerRejection(item.owner, item.agentType) !== null) {
143
143
  out.push(identityResult(item, 'invalid_or_unbound_owner'));
144
144
  continue;
145
145
  }
@@ -149,7 +149,9 @@ function collectNativeModelObservations(items, options = {}) {
149
149
  }
150
150
  const env = envFor(item, options);
151
151
  try {
152
- if (item.agentType === 'claude') out.push(collectClaude(item, env, options));
152
+ // dsh (ACP) has no native file to scan: its model facts arrive live from the bridge's configOptions.
153
+ if (item.agentType === 'dsh') out.push(identityResult(item, null));
154
+ else if (item.agentType === 'claude') out.push(collectClaude(item, env, options));
153
155
  else if (item.agentType === 'gemini') out.push(collectGemini(item, env, options));
154
156
  else if (item.agentType === 'codex') out.push(collectCodex(item, env, options, getDb));
155
157
  else out.push(collectOpencode(item, env, options, getDb));
@@ -450,8 +452,18 @@ function collectOpencode(item, env, options, getDb) {
450
452
  const handle = getDb(dbPath);
451
453
  if (!handle.db) return identityResult(item, 'database_error', { ...errorFields(handle.error), sourceRevision: statSignature(dbPath) });
452
454
  try {
455
+ /*
456
+ * WP-3 (OpenCode 2.x): 2.2.x keeps sessions in `session_v2`/`session_message` in the same db file
457
+ * and drops `session`/`message`. Detect the 2.x schema first; the 1.x branch below is unchanged.
458
+ */
459
+ const v2Cols = sqliteColumns(handle.db, 'session_v2', handle.columns);
460
+ // A db holding both schemas (a 1.x install sharing the file) falls through to 1.x when the id is not a 2.x session.
461
+ if (v2Cols.has('id') && v2Cols.has('model') && v2Cols.has('time_updated')) {
462
+ const v2 = collectOpencodeV2(item, handle, dbPath);
463
+ if (v2.reason !== 'session_missing' || !sqliteColumns(handle.db, 'session', handle.columns).has('id')) return v2;
464
+ }
453
465
  const sessionCols = sqliteColumns(handle.db, 'session', handle.columns);
454
- const session = selectColumns(handle.db, 'session', sessionCols, ['id', 'parent_id', 'model', 'time_updated'], 'id', item.owner.providerSessionId);
466
+ const session = selectColumns(handle.db, 'session', sessionCols, ['id', 'parent_id', 'model', 'time_created', 'time_updated'], 'id', item.owner.providerSessionId);
455
467
  if (!session) return identityResult(item, 'session_missing', { sourceRevision: statSignature(dbPath) });
456
468
  if (session.parent_id) return identityResult(item, 'child_session', { sourceRevision: digest([statSignature(dbPath), session.id, session.parent_id]) });
457
469
  const messageCols = sqliteColumns(handle.db, 'message', handle.columns);
@@ -472,4 +484,40 @@ function collectOpencode(item, env, options, getDb) {
472
484
  }
473
485
  }
474
486
 
487
+ /*
488
+ * WP-3: map a 2.x `session_message` assistant row onto the 1.x `message.data` shape the unchanged
489
+ * `opencodeModelObservations` adapter already decodes. A `finish:"error"` (or a present `error`) row
490
+ * is mapped to have `data.error` so the adapter refuses it -- no `completed-turn` fact. Unparseable
491
+ * `data` yields null and the caller drops the row.
492
+ */
493
+ function v2AssistantRow(row) {
494
+ if (!row || typeof row.data !== 'string') return null;
495
+ let parsed;
496
+ try { parsed = JSON.parse(row.data); } catch { return null; }
497
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
498
+ const data = { role: 'assistant', modelID: parsed.model?.id, providerID: parsed.model?.providerID, time: parsed.time };
499
+ if (parsed.error || parsed.finish === 'error') data.error = parsed.error || { type: 'finish_error' };
500
+ return { id: row.id, session_id: row.session_id, data: JSON.stringify(data) };
501
+ }
502
+ function collectOpencodeV2(item, handle, dbPath) {
503
+ const sessionCols = sqliteColumns(handle.db, 'session_v2', handle.columns);
504
+ // `time_created` too: the adapter stamps the session-store facts with it (I-5). 2.x bumps `time_updated` to
505
+ // the last turn's completion, so a fact stamped with it ties the newest opencode:message turn and wins.
506
+ const session = selectColumns(handle.db, 'session_v2', sessionCols, ['id', 'parent_id', 'model', 'time_created', 'time_updated'], 'id', item.owner.providerSessionId);
507
+ if (!session) return identityResult(item, 'session_missing', { sourceRevision: statSignature(dbPath) });
508
+ if (session.parent_id) return identityResult(item, 'child_session', { sourceRevision: digest([statSignature(dbPath), session.id, session.parent_id]) });
509
+ const messageCols = sqliteColumns(handle.db, 'session_message', handle.columns);
510
+ if (!messageCols.has('session_id') || !messageCols.has('data') || !messageCols.has('time_created')) throw Object.assign(new Error('missing session_message columns'), { code: 'SCHEMA' });
511
+ const selected = ['id', 'session_id', 'type', 'data', 'time_created'].filter((name) => messageCols.has(name));
512
+ const orderId = messageCols.has('id') ? ', "id" DESC' : '';
513
+ const rows = handle.db.prepare(`SELECT ${selected.map((name) => `"${name}"`).join(', ')} FROM "session_message" WHERE "session_id" = ? AND "type" = 'assistant' ORDER BY "time_created" DESC${orderId} LIMIT 128`).all(item.owner.providerSessionId).reverse();
514
+ const assistantRows = rows.map((row) => v2AssistantRow(row)).filter(Boolean);
515
+ const observations = opencodeModelObservations(item.owner, { sessionRow: session, assistantRows });
516
+ const revision = digest([statSignature(dbPath), session, rows.map((row) => [row.id, row.time_created, row.data])]);
517
+ for (const fact of observations) if (fact.source === 'opencode:session-store') {
518
+ fact.sourceRevision = digest([session.id, fact.value, fact.providerId, fact.effort, session.time_updated]);
519
+ }
520
+ return { id: item.id, owner: item.owner, observations, reason: observations.length ? null : 'unknown', sourceRevision: revision };
521
+ }
522
+
475
523
  module.exports = { collectNativeModelObservations, MAX_ITEMS, TAIL_BYTES, GEMINI_MAX_BYTES };
@@ -19,6 +19,8 @@ require('../../shared/network/external-network-guard').armExternalNetworkGuardFr
19
19
  // request / response / status / close) so it can share the client transport.
20
20
 
21
21
  const { parentPort, workerData } = require('node:worker_threads');
22
+ const v8 = require('node:v8');
23
+ const { boolFlag } = require('../lib/env-flags');
22
24
  const fs = require('node:fs'), path = require('node:path');
23
25
  const transcriptSource = require('../lib/transcript-source');
24
26
  const { readAgentTitleBackfillPage } = require('../lib/agent-title-backfill-read');
@@ -56,6 +58,9 @@ let enqueued = 0;
56
58
  let completed = 0;
57
59
  let failed = 0;
58
60
  const queue = [];
61
+ // WP-0 M-1/M-4 AC-0d: test-only retained allocations (see the `ping` allocMb hook). Bounded to
62
+ // 4 entries; unused unless CTM_READ_POOL_TEST_OPS=1.
63
+ const _perfTestHoldings = [];
59
64
  const JSON_FRAME_MAX_BYTES = 60 * 1024;
60
65
  const JSON_STRING_PART_BYTES = 24 * 1024;
61
66
  // readCanonicalAgentEvents blast-radius bound. This was 10000 events/session with
@@ -1124,6 +1129,48 @@ function _telemetry(currentOpBytes = 0) {
1124
1129
  };
1125
1130
  }
1126
1131
 
1132
+ // WP-0 M-1 + M-4 (docs/hub-local-cpu-memory-burn-2026-10-31.html §7): attribute CPU and heap to
1133
+ // the op that actually cost them, inside the worker that runs it.
1134
+ //
1135
+ // M-1 CPU: process.threadCpuUsage() -- THIS worker thread's own CPU, not the process's, so a
1136
+ // sibling worker's burn can never be charged to this op.
1137
+ // M-4 heap: v8.getHeapStatistics() rather than process.memoryUsage(). It exposes exactly the
1138
+ // two fields wanted (used_heap_size, external_memory) and skips memoryUsage()'s extra
1139
+ // uv_resident_set_memory() syscall -- measured 176 ns vs 545 ns per call on the
1140
+ // pinned node (v25.2.1); threadCpuUsage() is 728 ns. Two samples per op ≈ 1.8 µs,
1141
+ // negligible against any op that reaches a worker.
1142
+ // Nothing is sampled or attached when CTM_PERF_ATTRIBUTION=0.
1143
+ const _perfAttributionOn = () => boolFlag('CTM_PERF_ATTRIBUTION', true);
1144
+ const _threadCpu = typeof process.threadCpuUsage === 'function'
1145
+ ? () => process.threadCpuUsage()
1146
+ : () => ({ user: 0, system: 0 });
1147
+
1148
+ function _perfSample() {
1149
+ return { cpu: _threadCpu(), heap: v8.getHeapStatistics() };
1150
+ }
1151
+
1152
+ // null when attribution is off -- _perfDelta() then returns null and the response carries no
1153
+ // `perf` field at all.
1154
+ function _perfStart() {
1155
+ return _perfAttributionOn() ? _perfSample() : null;
1156
+ }
1157
+
1158
+ // `op` rides along so the client can attribute the delta without re-deriving the op from a
1159
+ // requestId the worker handle may already have released (late responses).
1160
+ function _perfDelta(start, op) {
1161
+ if (!start) return null;
1162
+ const cpu = _threadCpu();
1163
+ const heap = v8.getHeapStatistics();
1164
+ return {
1165
+ op,
1166
+ cpuUserUs: cpu.user - start.cpu.user,
1167
+ cpuSystemUs: cpu.system - start.cpu.system,
1168
+ // Signed on purpose: a delta may be negative (GC ran, or a transferred buffer was neutered).
1169
+ heapDeltaBytes: heap.used_heap_size - start.heap.used_heap_size,
1170
+ externalDeltaBytes: heap.external_memory - start.heap.external_memory,
1171
+ };
1172
+ }
1173
+
1127
1174
  function _postStatus() {
1128
1175
  try { parentPort.postMessage({ type: 'status', status: _status() }); } catch {}
1129
1176
  }
@@ -1185,6 +1232,9 @@ async function _runOp(op, payload = {}, task = null) {
1185
1232
  // that switch must not be reachable on a production instance even though `ping`
1186
1233
  // has no production caller today.
1187
1234
  const _testHooks = process.env.CTM_READPOOL_TEST_HOOKS === '1';
1235
+ // WP-0 M-1/M-4: default OFF, like _testHooks above -- an allocation this size is a test
1236
+ // affordance, never something a production caller may ask for.
1237
+ const _testOps = boolFlag('CTM_READ_POOL_TEST_OPS', false);
1188
1238
  const rawSleepMs = _testHooks ? Math.min(5000, Math.max(0, Number(payload.rawSleepMs) || 0)) : 0;
1189
1239
  if (rawSleepMs > 0) await new Promise((r) => setTimeout(r, rawSleepMs));
1190
1240
  // Test hook (WP-2): throw OUTSIDE the awaited task chain entirely — a genuinely
@@ -1194,6 +1244,18 @@ async function _runOp(op, payload = {}, task = null) {
1194
1244
  setImmediate(() => { throw new Error('WP-2 test: forced uncaughtException'); });
1195
1245
  await new Promise(() => {}); // this task never resolves; the fault kills the worker instead.
1196
1246
  }
1247
+ // WP-0 M-1/M-4 AC-0d: an op that allocates and RETAINS `allocMb` MB until it returns, so
1248
+ // the heap-delta attribution has a real allocation to attribute (a declared op's own output
1249
+ // caps top out well under 50 MB, and a transferred response is neutered before the delta is
1250
+ // read). Inert unless CTM_READ_POOL_TEST_OPS=1 -- production must not be able to allocate
1251
+ // on demand through `ping`. Retained in a bounded ring (4 buffers) so a long-lived test
1252
+ // process cannot grow without limit.
1253
+ const allocMb = _testOps ? Math.min(256, Math.max(0, Number(payload.allocMb) || 0)) : 0;
1254
+ if (allocMb > 0) {
1255
+ const held = Buffer.alloc(allocMb * 1024 * 1024, 1);
1256
+ _perfTestHoldings.push(held);
1257
+ if (_perfTestHoldings.length > 4) _perfTestHoldings.shift();
1258
+ }
1197
1259
  return { pong: true, ts: Number(payload.ts) || 0 };
1198
1260
  }
1199
1261
 
@@ -2909,7 +2971,7 @@ async function _runOp(op, payload = {}, task = null) {
2909
2971
  // connection makes it side-effect-free (better-sqlite3 readonly + fs only).
2910
2972
  const ctx = require('../../wall-e/memory/ctm-session-context');
2911
2973
  const args = (payload && payload.args) || {};
2912
- const conn = _readonlyDb(payload.dbPath);
2974
+ const conn = _readonlyRoutedDb(payload.dbPath); // ROUTED: ctm_sessions is domain core (core.db after the flip); base-only gave title/cwd "" (cross-machine-session-context C-4)
2913
2975
  if (op === 'ctmSessionMemorySearch') return _transferJson(ctx.searchCtmSessions({ ...args, db: conn }));
2914
2976
  if (op === 'ctmSessionMemoryContext') return _transferJson(ctx.getCtmSessionContext({ ...args, db: conn }));
2915
2977
  if (op === 'ctmSessionMemoryHealth') return _transferJson(ctx.getCtmDbHealth({ ...args, db: conn }));
@@ -3007,6 +3069,14 @@ function _pump() {
3007
3069
  }
3008
3070
  active = task;
3009
3071
  _postStatus();
3072
+ // WP-0 M-1/M-4: one start sample per executed op; the delta is attached to whichever response
3073
+ // (success, size refusal, or error) ends it. Cancelled/never-dispatched requests take the
3074
+ // _postCancelledResponse path above and are not ops, so they carry no perf.
3075
+ const perfStart = _perfStart();
3076
+ const postResponse = (message, transferList) => {
3077
+ const perf = _perfDelta(perfStart, task.op);
3078
+ parentPort.postMessage(perf ? { ...message, perf } : message, transferList);
3079
+ };
3010
3080
  Promise.resolve()
3011
3081
  .then(() => _runOp(task.op, task.payload, task))
3012
3082
  .then((result) => {
@@ -3016,7 +3086,7 @@ function _pump() {
3016
3086
  const error = new Error(`read-pool output exceeds declared byte bound: ${task.op}`);
3017
3087
  error.code = 'CTM_READ_POOL_OUTPUT_TOO_LARGE';
3018
3088
  failed += 1;
3019
- parentPort.postMessage({
3089
+ postResponse({
3020
3090
  type: 'response', requestId: task.requestId, error: _serializeError(error), telemetry: _telemetry(),
3021
3091
  });
3022
3092
  return;
@@ -3025,7 +3095,7 @@ function _pump() {
3025
3095
  // multi-MB object. transferList moves ownership + neuters our copy (race-free).
3026
3096
  const buf = _toTransferBuffer(result.buffer);
3027
3097
  completed += 1;
3028
- parentPort.postMessage(
3098
+ postResponse(
3029
3099
  {
3030
3100
  type: 'response', requestId: task.requestId,
3031
3101
  resultBuffer: buf.buffer, byteOffset: buf.byteOffset, byteLength: buf.byteLength,
@@ -3041,13 +3111,13 @@ function _pump() {
3041
3111
  const error = new Error(`read-pool output exceeds declared byte bound: ${task.op}`);
3042
3112
  error.code = 'CTM_READ_POOL_OUTPUT_TOO_LARGE';
3043
3113
  failed += 1;
3044
- parentPort.postMessage({
3114
+ postResponse({
3045
3115
  type: 'response', requestId: task.requestId, error: _serializeError(error), telemetry: _telemetry(),
3046
3116
  });
3047
3117
  return;
3048
3118
  }
3049
3119
  completed += 1;
3050
- parentPort.postMessage({
3120
+ postResponse({
3051
3121
  type: 'response', requestId: task.requestId, result, serializedBytes,
3052
3122
  telemetry: _telemetry(serializedBytes),
3053
3123
  });
@@ -3064,7 +3134,7 @@ function _pump() {
3064
3134
  // catches BOTH: a rejection from _runOp, and a throw from the onFulfilled
3065
3135
  // handler above.
3066
3136
  failed += 1;
3067
- parentPort.postMessage({
3137
+ postResponse({
3068
3138
  type: 'response', requestId: task.requestId, error: _serializeError(err), telemetry: _telemetry(),
3069
3139
  });
3070
3140
  })
@@ -30,7 +30,7 @@ const {
30
30
  MAX_FRAME_BYTES,
31
31
  PROTOCOL_VERSION, FLOOR_VERSION,
32
32
  } = require('../lib/host-control-protocol');
33
- const { createHandoff, handoffManifestFromArgv, modelProcessGenerationFromEnv, modelProcessGenerationMetadata, modelStorageRootsFromEnv, modelStorageRootsMetadata } = require('../lib/host-handoff'); const { modelExecutionRecipeFromEnv, modelExecutionRecipeMetadata } = require('../lib/model-execution-recipe-metadata'); const { createProbeFrameHold } = require('../lib/probe-frame-hold');
33
+ const { createHandoff, handoffManifestFromArgv, modelProcessGenerationFromEnv, modelProcessGenerationMetadata, modelStorageRootsFromEnv, modelStorageRootsMetadata, launchEnvironmentMetadata } = require('../lib/host-handoff'); const { modelExecutionRecipeFromEnv, modelExecutionRecipeMetadata } = require('../lib/model-execution-recipe-metadata'); const { createProbeFrameHold } = require('../lib/probe-frame-hold');
34
34
  const { computeClosure } = require('../lib/host-closure-hash'), { createScrollbackSnapshotStore } = require('../lib/scrollback-snapshot-store'); // hoisted: loaded set frozen at startup
35
35
 
36
36
  const POST_EXIT_HEADLESS_TTL_MS = 60000;
@@ -199,7 +199,7 @@ function createSessionState(sessionId, o) {
199
199
  seq: 0, // WP-0: monotonic per-session data counter, socket-protocol-only (see buildSessionsState)
200
200
  ...modelProcessGenerationMetadata(o.modelProcessGeneration),
201
201
  ...modelStorageRootsMetadata(o.modelStorageRoots),
202
- ...modelExecutionRecipeMetadata(o.modelExecutionRecipe),
202
+ ...modelExecutionRecipeMetadata(o.modelExecutionRecipe), ...launchEnvironmentMetadata(o.launchEnvironment),
203
203
  cmd: String(o.cmd || ''),
204
204
  cwd: o.cwd || '',
205
205
  name: o.name || '',
@@ -268,7 +268,7 @@ async function startSession(msg) {
268
268
  const state = createSessionState(sessionId, {
269
269
  cols, rows, suppress: msg.suppressPtyHeadlessUntilInput, cmd: msg.cmd, cwd: msg.cwd, name: msg.name, outputEpoch: msg.outputEpoch,
270
270
  modelProcessGeneration: modelProcessGenerationFromEnv(msg.env),
271
- modelStorageRoots: modelStorageRootsFromEnv(msg.env),
271
+ modelStorageRoots: modelStorageRootsFromEnv(msg.env), launchEnvironment: msg.launchEnvironment,
272
272
  displayContext: isWorkerDisplaySession({ env: msg.env }) ? { agentRole: 'worker', _workerAgent: workerAgentOf({ env: msg.env }), cwd: msg.cwd || '' } : null,
273
273
  });
274
274
  try {
@@ -293,7 +293,7 @@ async function startSession(msg) {
293
293
  attachSessionProcess(state, proc);
294
294
  // D-3/S-7: fresh spawns only; a no-op unless msg.env came from buildSandboxCliEnv (non-primary, D-5).
295
295
  armSessionLoginTripwire({ proc, env: childEnv, onBlocked: (record) => { state.loginBlocked = record; send({ type: 'host-diagnostic', sessionId, event: 'login-attempt-blocked', details: { id: record.id, excerpt: record.excerpt } }); } });
296
- send({ type: 'started', sessionId, pid: proc.pid, cols, rows, ...modelProcessGenerationMetadata(state.modelProcessGeneration), ...modelStorageRootsMetadata(state.modelStorageRoots), ...modelExecutionRecipeMetadata(state.modelExecutionRecipe) });
296
+ send({ type: 'started', sessionId, pid: proc.pid, cols, rows, ...modelProcessGenerationMetadata(state.modelProcessGeneration), ...modelStorageRootsMetadata(state.modelStorageRoots), ...modelExecutionRecipeMetadata(state.modelExecutionRecipe), ...launchEnvironmentMetadata(state.launchEnvironment) });
297
297
  } catch (err) {
298
298
  hostError(sessionId, err, { code: 'spawn_failed' });
299
299
  send({ type: 'exit', sessionId, exitCode: 1, signal: null, spawnFailed: true });
@@ -379,7 +379,7 @@ function buildSessionsState() {
379
379
  headlessReady: headless.hasTerminal(sessionId),
380
380
  ...modelProcessGenerationMetadata(state.modelProcessGeneration),
381
381
  ...modelStorageRootsMetadata(state.modelStorageRoots),
382
- ...modelExecutionRecipeMetadata(state.modelExecutionRecipe),
382
+ ...modelExecutionRecipeMetadata(state.modelExecutionRecipe), ...launchEnvironmentMetadata(state.launchEnvironment),
383
383
  ...(state.exitSource ? { exitSource: state.exitSource } : {}),
384
384
  });
385
385
  }
@@ -414,7 +414,7 @@ const handoff = createHandoff({
414
414
  });
415
415
  const stateFromEntry = (e) => createSessionState(e.sessionId, {
416
416
  cols: e.cols, rows: e.rows, suppress: e.suppressPtyHeadlessUntilInput, displayContext: e.workerDisplayContext, cmd: e.cmd, cwd: e.cwd, name: e.name, outputEpoch: e.outputEpoch,
417
- modelProcessGeneration: e.modelProcessGeneration, ...modelStorageRootsMetadata(e.modelStorageRoots), ...modelExecutionRecipeMetadata(e.modelExecutionRecipe, { sessionId: e.sessionId, processGeneration: e.modelProcessGeneration }),
417
+ modelProcessGeneration: e.modelProcessGeneration, ...modelStorageRootsMetadata(e.modelStorageRoots), ...modelExecutionRecipeMetadata(e.modelExecutionRecipe, { sessionId: e.sessionId, processGeneration: e.modelProcessGeneration }), launchEnvironment: e.launchEnvironment,
418
418
  });
419
419
  // WP-3: a successor host rebuilds its sessions from the manifest BEFORE its control socket listens.
420
420
  const handoffRestored = !handoffManifestFromArgv() ? Promise.resolve() : handoff.restore(handoffManifestFromArgv(), {
@@ -26,7 +26,7 @@ const {
26
26
  MAX_FRAME_BYTES,
27
27
  PROTOCOL_VERSION, FLOOR_VERSION,
28
28
  } = require('../lib/host-control-protocol');
29
- const { createHandoff, handoffManifestFromArgv, modelProcessGenerationFromEnv, modelProcessGenerationMetadata, modelStorageRootsFromEnv, modelStorageRootsMetadata } = require('../lib/host-handoff'); const { modelExecutionRecipeFromEnv, modelExecutionRecipeMetadata } = require('../lib/model-execution-recipe-metadata'); const { createProbeFrameHold } = require('../lib/probe-frame-hold');
29
+ const { createHandoff, handoffManifestFromArgv, modelProcessGenerationFromEnv, modelProcessGenerationMetadata, modelStorageRootsFromEnv, modelStorageRootsMetadata, launchEnvironmentMetadata } = require('../lib/host-handoff'); const { modelExecutionRecipeFromEnv, modelExecutionRecipeMetadata } = require('../lib/model-execution-recipe-metadata'); const { createProbeFrameHold } = require('../lib/probe-frame-hold');
30
30
  const { computeClosure } = require('../lib/host-closure-hash'), { createScrollbackSnapshotStore } = require('../lib/scrollback-snapshot-store'); // hoisted: loaded set frozen at startup
31
31
  let sessionId = '';
32
32
  let ptyProcess = null;
@@ -255,7 +255,7 @@ async function startSession(msg) {
255
255
  const rows = Number(msg.rows || 30) || 30;
256
256
  sessionCols = cols;
257
257
  sessionRows = rows;
258
- sessionMeta = { cwd: msg.cwd || '', name: msg.name || '', outputEpoch: String(msg.outputEpoch || ''), ...modelProcessGenerationMetadata(modelProcessGenerationFromEnv(msg.env)), modelStorageRoots: modelStorageRootsFromEnv(msg.env) };
258
+ sessionMeta = { cwd: msg.cwd || '', name: msg.name || '', outputEpoch: String(msg.outputEpoch || ''), ...modelProcessGenerationMetadata(modelProcessGenerationFromEnv(msg.env)), modelStorageRoots: modelStorageRootsFromEnv(msg.env), launchEnvironment: msg.launchEnvironment };
259
259
  workerDisplayContext = isWorkerDisplaySession({ env: msg.env }) ? { agentRole: 'worker', _workerAgent: workerAgentOf({ env: msg.env }), cwd: msg.cwd || '' } : null;
260
260
  try {
261
261
  const createMessage = { type: 'create', sessionId, cols, rows, outputEpoch: String(msg.outputEpoch || '') };
@@ -280,7 +280,7 @@ async function startSession(msg) {
280
280
  attachSessionProcess(proc);
281
281
  // D-3/S-7: fresh spawns only; a no-op unless msg.env came from buildSandboxCliEnv (non-primary, D-5).
282
282
  armSessionLoginTripwire({ proc, env: childEnv, onBlocked: (record) => { loginBlocked = record; send({ type: 'host-diagnostic', sessionId, event: 'login-attempt-blocked', details: { id: record.id, excerpt: record.excerpt } }); } });
283
- send({ type: 'started', sessionId, pid: proc.pid, cols, rows, ...modelProcessGenerationMetadata(sessionMeta.modelProcessGeneration), ...modelStorageRootsMetadata(sessionMeta.modelStorageRoots), ...modelExecutionRecipeMetadata(sessionMeta.modelExecutionRecipe) });
283
+ send({ type: 'started', sessionId, pid: proc.pid, cols, rows, ...modelProcessGenerationMetadata(sessionMeta.modelProcessGeneration), ...modelStorageRootsMetadata(sessionMeta.modelStorageRoots), ...modelExecutionRecipeMetadata(sessionMeta.modelExecutionRecipe), ...launchEnvironmentMetadata(sessionMeta.launchEnvironment) });
284
284
  } catch (err) {
285
285
  hostError(err, { code: 'spawn_failed' });
286
286
  send({ type: 'exit', sessionId, exitCode: 1, signal: null, spawnFailed: true });
@@ -301,7 +301,7 @@ function buildSessionsState() {
301
301
  headlessReady: headless.hasTerminal(sessionId),
302
302
  ...modelProcessGenerationMetadata(sessionMeta.modelProcessGeneration),
303
303
  ...modelStorageRootsMetadata(sessionMeta.modelStorageRoots),
304
- ...modelExecutionRecipeMetadata(sessionMeta.modelExecutionRecipe),
304
+ ...modelExecutionRecipeMetadata(sessionMeta.modelExecutionRecipe), ...launchEnvironmentMetadata(sessionMeta.launchEnvironment),
305
305
  ...(exitSource ? { exitSource } : {}),
306
306
  }];
307
307
  }
@@ -335,7 +335,7 @@ const handoffRestored = !handoffManifestFromArgv() ? Promise.resolve() : handoff
335
335
  adopt: (e, proc) => {
336
336
  if (ptyProcess) throw new Error('a dedicated host holds exactly one session');
337
337
  sessionId = e.sessionId; sessionCmd = e.cmd || ''; sessionCols = e.cols; sessionRows = e.rows; sessionSeq = e.seq || 0;
338
- sessionMeta = { cwd: e.cwd || '', name: e.name || '', outputEpoch: e.outputEpoch || '', ...modelProcessGenerationMetadata(e.modelProcessGeneration), ...modelStorageRootsMetadata(e.modelStorageRoots), ...modelExecutionRecipeMetadata(e.modelExecutionRecipe, { sessionId: e.sessionId, processGeneration: e.modelProcessGeneration }) };
338
+ sessionMeta = { cwd: e.cwd || '', name: e.name || '', outputEpoch: e.outputEpoch || '', ...modelProcessGenerationMetadata(e.modelProcessGeneration), ...modelStorageRootsMetadata(e.modelStorageRoots), ...modelExecutionRecipeMetadata(e.modelExecutionRecipe, { sessionId: e.sessionId, processGeneration: e.modelProcessGeneration }), launchEnvironment: e.launchEnvironment };
339
339
  workerDisplayContext = e.workerDisplayContext || null; suppressPtyHeadlessUntilInput = !!e.suppressPtyHeadlessUntilInput;
340
340
  attachSessionProcess(proc);
341
341
  },