create-walle 0.10.0 → 0.10.2

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 (381) hide show
  1. package/README.md +88 -41
  2. package/lib/owner-write-safety.js +135 -0
  3. package/lib/public-runtime.js +13 -5
  4. package/lib/release-schema.json +3 -2
  5. package/lib/runtime-closure-policy.json +7 -5
  6. package/package.json +10 -4
  7. package/template/bin/deps-doctor.js +1 -1
  8. package/template/bin/node-bin.sh +11 -0
  9. package/template/coding-task-manager/api-prompts.js +10 -22
  10. package/template/coding-task-manager/bin/capture-codex-rollout-records.js +417 -0
  11. package/template/coding-task-manager/bin/census-codex-lead-history.js +325 -0
  12. package/template/coding-task-manager/bin/claude-hook.js +7 -3
  13. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  14. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  16. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  17. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  18. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  19. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  20. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  21. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  22. package/template/coding-task-manager/bin/seam-replay-codex.js +301 -0
  23. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  24. package/template/coding-task-manager/db.js +705 -286
  25. package/template/coding-task-manager/git-utils.js +44 -0
  26. package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
  27. package/template/coding-task-manager/lib/agent-presets.js +15 -0
  28. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  29. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  30. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  31. package/template/coding-task-manager/lib/api/ingress.js +35 -12
  32. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  33. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  34. package/template/coding-task-manager/lib/api/machines.js +461 -0
  35. package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
  36. package/template/coding-task-manager/lib/api/providers.js +53 -6
  37. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  38. package/template/coding-task-manager/lib/api/sessions.js +160 -8
  39. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  40. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  41. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  42. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  43. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  44. package/template/coding-task-manager/lib/auth-context.js +32 -2
  45. package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
  46. package/template/coding-task-manager/lib/auth-rules.js +186 -45
  47. package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
  48. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  49. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  50. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  51. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  52. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  53. package/template/coding-task-manager/lib/client-diag-handler.js +25 -0
  54. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  55. package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
  56. package/template/coding-task-manager/lib/codex-history-terminal-renderer.js +33 -33
  57. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  58. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  59. package/template/coding-task-manager/lib/codex-local-links.js +267 -0
  60. package/template/coding-task-manager/lib/codex-markdown-lists.js +160 -0
  61. package/template/coding-task-manager/lib/codex-native-history-prefix.js +4 -0
  62. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  63. package/template/coding-task-manager/lib/codex-source-handoff.js +186 -0
  64. package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
  65. package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
  66. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  67. package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
  68. package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
  69. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  70. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  71. package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
  72. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  73. package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
  74. package/template/coding-task-manager/lib/db-domains.js +21 -2
  75. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  76. package/template/coding-task-manager/lib/db-owner-worker-client.js +22 -0
  77. package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
  78. package/template/coding-task-manager/lib/feature-manifest.js +1 -3
  79. package/template/coding-task-manager/lib/fs-watcher.js +3 -2
  80. package/template/coding-task-manager/lib/harness-history-transition.js +41 -14
  81. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  82. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  83. package/template/coding-task-manager/lib/headless-term-service.js +60 -23
  84. package/template/coding-task-manager/lib/history-transition-read-op.js +179 -23
  85. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  86. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  87. package/template/coding-task-manager/lib/host-handoff.js +51 -13
  88. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  89. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  90. package/template/coding-task-manager/lib/host-stats.js +328 -0
  91. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  92. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  93. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  94. package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
  95. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
  96. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  97. package/template/coding-task-manager/lib/instance-manifest.js +13 -1
  98. package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
  99. package/template/coding-task-manager/lib/kernel/diag-log.js +12 -0
  100. package/template/coding-task-manager/lib/launch-model-override.js +160 -1
  101. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  102. package/template/coding-task-manager/lib/lead-model-observer.js +17 -2
  103. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
  104. package/template/coding-task-manager/lib/lead-model-switch.js +11 -2
  105. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +42 -4
  106. package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
  107. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  108. package/template/coding-task-manager/lib/login-tripwire.js +18 -0
  109. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  110. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  111. package/template/coding-task-manager/lib/machine-registry.js +749 -0
  112. package/template/coding-task-manager/lib/machine-self.js +66 -0
  113. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +56 -4
  114. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  115. package/template/coding-task-manager/lib/media-journal.js +84 -27
  116. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  117. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  118. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  119. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +16 -3
  120. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  121. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  122. package/template/coding-task-manager/lib/model-proxy/collaboration-codec.js +94 -0
  123. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  124. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  125. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  126. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  127. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  128. package/template/coding-task-manager/lib/model-proxy/responses-face.js +24 -2
  129. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  130. package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
  131. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  132. package/template/coding-task-manager/lib/native-history-control.js +62 -14
  133. package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
  134. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  135. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
  136. package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
  137. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  138. package/template/coding-task-manager/lib/prompt-admission-trace.js +69 -0
  139. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  140. package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
  141. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  142. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  143. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  144. package/template/coding-task-manager/lib/raw-history-block.js +3 -1
  145. package/template/coding-task-manager/lib/read-pool-client.js +36 -24
  146. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  147. package/template/coding-task-manager/lib/read-pool-telemetry.js +14 -5
  148. package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
  149. package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
  150. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  151. package/template/coding-task-manager/lib/remote-command-runtime.js +18 -5
  152. package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
  153. package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
  154. package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
  155. package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
  156. package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
  157. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  158. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  159. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  160. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  161. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  162. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  163. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  164. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  165. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  166. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  167. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  168. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  169. package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
  170. package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
  171. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  172. package/template/coding-task-manager/lib/root-prompt-admission.js +43 -11
  173. package/template/coding-task-manager/lib/root-prompt-flow.js +175 -38
  174. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  175. package/template/coding-task-manager/lib/server-memory-sampler-runtime.js +10 -0
  176. package/template/coding-task-manager/lib/server-memory-sampler.js +41 -2
  177. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  178. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  179. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  180. package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
  181. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  182. package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
  183. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  184. package/template/coding-task-manager/lib/session-create/provider-process.js +38 -39
  185. package/template/coding-task-manager/lib/session-create/response.js +30 -12
  186. package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
  187. package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
  188. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  189. package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
  190. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  191. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  192. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  193. package/template/coding-task-manager/lib/session-host-manager.js +152 -206
  194. package/template/coding-task-manager/lib/session-jobs.js +17 -9
  195. package/template/coding-task-manager/lib/session-lifecycle.js +20 -50
  196. package/template/coding-task-manager/lib/session-model-action-preconditions.js +68 -3
  197. package/template/coding-task-manager/lib/session-resource-sampler.js +67 -9
  198. package/template/coding-task-manager/lib/session-standup.js +67 -4
  199. package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
  200. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  201. package/template/coding-task-manager/lib/session-status.js +2 -2
  202. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  203. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  204. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  205. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  206. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
  207. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  208. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  209. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  210. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  211. package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
  212. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  213. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  214. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  215. package/template/coding-task-manager/lib/transcript-source.js +8 -3
  216. package/template/coding-task-manager/lib/transcript-store.js +40 -0
  217. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  218. package/template/coding-task-manager/lib/typing-interaction-trace.js +136 -2
  219. package/template/coding-task-manager/lib/typing-worker-stages.js +208 -1
  220. package/template/coding-task-manager/lib/usage-ledger/claude-parse.js +53 -2
  221. package/template/coding-task-manager/lib/usage-ledger/ingest.js +13 -4
  222. package/template/coding-task-manager/lib/usage-ledger/read.js +14 -0
  223. package/template/coding-task-manager/lib/usage-ledger/schema.js +49 -1
  224. package/template/coding-task-manager/lib/usage-ledger/store.js +337 -6
  225. package/template/coding-task-manager/lib/usage-ledger/task-read.js +123 -5
  226. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  227. package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
  228. package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
  229. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  230. package/template/coding-task-manager/lib/ws/input.js +1 -0
  231. package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
  232. package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
  233. package/template/coding-task-manager/lib/ws-router.js +68 -1
  234. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  235. package/template/coding-task-manager/oauth-proxy.js +99 -55
  236. package/template/coding-task-manager/package-lock.json +24 -0
  237. package/template/coding-task-manager/package.json +3 -0
  238. package/template/coding-task-manager/protocol/message-table.json +0 -10
  239. package/template/coding-task-manager/protocol/messages.js +0 -10
  240. package/template/coding-task-manager/protocol/ws-schema.json +0 -20
  241. package/template/coding-task-manager/protocol/ws-schema.md +0 -2
  242. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  243. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  244. package/template/coding-task-manager/public/css/app.css +279 -2
  245. package/template/coding-task-manager/public/css/reviews.css +4 -0
  246. package/template/coding-task-manager/public/index.html +297 -240
  247. package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
  248. package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
  249. package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
  250. package/template/coding-task-manager/public/js/background-work.js +13 -7
  251. package/template/coding-task-manager/public/js/client-health-core.js +81 -0
  252. package/template/coding-task-manager/public/js/client-health-main.js +61 -0
  253. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
  254. package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
  255. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  256. package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
  257. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  258. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  259. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  260. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  261. package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
  262. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  263. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -4
  264. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  265. package/template/coding-task-manager/public/js/protocol.js +0 -10
  266. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  267. package/template/coding-task-manager/public/js/reviews.js +7 -3
  268. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  269. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  270. package/template/coding-task-manager/public/js/row-join.js +18 -3
  271. package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
  272. package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
  273. package/template/coding-task-manager/public/js/session-usage-view.js +1 -0
  274. package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
  275. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  276. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  277. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  278. package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
  279. package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
  280. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  281. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  282. package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
  283. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  284. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  285. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -3
  286. package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
  287. package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
  288. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  289. package/template/coding-task-manager/public/m/app.css +226 -8
  290. package/template/coding-task-manager/public/m/app.js +502 -9
  291. package/template/coding-task-manager/public/m/index.html +38 -1
  292. package/template/coding-task-manager/public/m/machines.js +1313 -0
  293. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  294. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  295. package/template/coding-task-manager/public/m/sw.js +5 -0
  296. package/template/coding-task-manager/queue-engine.js +13 -0
  297. package/template/coding-task-manager/server/approvals.js +5 -6
  298. package/template/coding-task-manager/server/boot.js +136 -17
  299. package/template/coding-task-manager/server.js +964 -425
  300. package/template/coding-task-manager/session-integrity.js +7 -9
  301. package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
  302. package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
  303. package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
  304. package/template/coding-task-manager/workers/session-host-process.js +14 -3
  305. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  306. package/template/coding-task-manager/workers/worktree-worker.js +34 -0
  307. package/template/package-lock.json +2 -2
  308. package/template/package.json +1 -1
  309. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  310. package/template/shared/conversation-storage-v2-contract.js +42 -6
  311. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  312. package/template/shared/git-remote-key.js +83 -0
  313. package/template/shared/host-identity.js +98 -2
  314. package/template/shared/owner-write-safety.js +135 -0
  315. package/template/shared/public-runtime.js +13 -5
  316. package/template/shared/release-schema.json +3 -2
  317. package/template/shared/report-citations.js +14 -0
  318. package/template/shared/sqlite-write-lock.js +361 -223
  319. package/template/shared/storage/contract.js +35 -3
  320. package/template/wall-e/agent.js +21 -0
  321. package/template/wall-e/api-walle.js +5 -0
  322. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  323. package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
  324. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  325. package/template/wall-e/brain/migrations.js +51 -22
  326. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  327. package/template/wall-e/brain/owner-call-whitelist.js +16 -0
  328. package/template/wall-e/brain/schema-ensures.js +22 -0
  329. package/template/wall-e/brain.js +1 -1
  330. package/template/wall-e/coding/host-capabilities.js +2 -2
  331. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  332. package/template/wall-e/coding/session-journal.js +28 -40
  333. package/template/wall-e/coding-orchestrator.js +23 -26
  334. package/template/wall-e/fly.toml +1 -1
  335. package/template/wall-e/http/auth.js +18 -1
  336. package/template/wall-e/http/blog-views-api.js +318 -0
  337. package/template/wall-e/http/helper-rules-api.js +321 -0
  338. package/template/wall-e/http/model-proxy-providers.js +3 -1
  339. package/template/wall-e/http/telemetry-api.js +12 -0
  340. package/template/wall-e/lib/blog-view-policy.js +88 -0
  341. package/template/wall-e/lib/blog-view-store.js +169 -0
  342. package/template/wall-e/lib/client-config-lock.js +2 -1
  343. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  344. package/template/wall-e/lib/error-kinds.js +10 -1
  345. package/template/wall-e/lib/feature-manifest.js +1 -1
  346. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  347. package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
  348. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  349. package/template/wall-e/lib/helper-rules/grade.js +277 -0
  350. package/template/wall-e/lib/helper-rules/label.js +247 -0
  351. package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
  352. package/template/wall-e/lib/helper-rules/store.js +667 -0
  353. package/template/wall-e/lib/mcp-integration.js +5 -6
  354. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  355. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
  356. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  357. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  358. package/template/wall-e/llm/default-fallback.js +4 -0
  359. package/template/wall-e/llm/model-catalog.js +13 -4
  360. package/template/wall-e/llm/model-roles.js +6 -0
  361. package/template/wall-e/llm/portkey-http.js +150 -0
  362. package/template/wall-e/llm/portkey-sync.js +15 -145
  363. package/template/wall-e/llm/worker-mcp-routing.js +61 -0
  364. package/template/wall-e/llm/worker-route.js +43 -1
  365. package/template/wall-e/loops/brain-custom-writes.js +45 -0
  366. package/template/wall-e/mcp-protocol-contract.js +41 -1
  367. package/template/wall-e/mcp-server.js +13 -2
  368. package/template/wall-e/mcp-worker-schemas.js +20 -2
  369. package/template/wall-e/memory/ctm-context-client.js +25 -5
  370. package/template/wall-e/shared/release-schema.json +3 -2
  371. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  372. package/template/wall-e/shared/storage/contract.js +35 -3
  373. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  374. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
  375. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
  376. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
  377. package/template/wall-e/tools/local-tools.js +12 -5
  378. package/template/wall-e/workers/brain-owner-worker.js +9 -0
  379. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  380. package/template/wall-e/workers/telemetry-worker.js +8 -0
  381. package/template/coding-task-manager/lib/giant-freeze-park.js +0 -31
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ // native-same-thread-model-switch / §6.5: the PRIVATE launch capture a rollback recovery replays.
4
+ // It is recorded for EVERY native harness whose `recoverSource` can resume the same canonical
5
+ // thread -- Codex AND Claude -- because this capture is the only proof of THIS spawn's
6
+ // executable/argv/cwd/home/generation. It is taken from the prepared launch plan at the REAL
7
+ // spawn (never synthesized later from mutable session fields), and every field is a copy: the
8
+ // argv array is cloned, so a later `session.args` rewrite cannot edit the receipt.
9
+ // WP-0b: extracted verbatim from provider-process.js (same spawn point) so that file stays under
10
+ // the file-size ceiling; behavior is unchanged. The existing Codex receipt dependency is called
11
+ // once as before; this adds no reader, state, or credential copy.
12
+
13
+ const path = require('node:path');
14
+ const { strFlag } = require('../env-flags');
15
+
16
+ // Explicit launch inputs (never the whole process env): the prepared plan, the caller's argv/cwd,
17
+ // the ACTUAL spawn env, the recipe/generation the launch was prepared with, the Codex config
18
+ // receipt already read for this spawn, and the existing codex-paths dependency (no extra read).
19
+ // Returns `null` for a harness with no same-canonical-thread rollout to resume.
20
+ function buildModelTransitionLaunchContext({ agentType, preparedLaunchPlan, cmd, args, cwd, spawnEnv,
21
+ serverHome, executionRecipe, processGeneration, nativeConfigReceipt = null, codexPaths = null }) {
22
+ if (agentType !== 'codex' && agentType !== 'claude') return null;
23
+ const capturedHome = spawnEnv.HOME || serverHome || null;
24
+ const capturedTmpDir = typeof spawnEnv.TMPDIR === 'string' && path.isAbsolute(spawnEnv.TMPDIR)
25
+ ? spawnEnv.TMPDIR : null;
26
+ if (agentType === 'claude') {
27
+ // A native Claude launch claims NO Codex receipt/config: `codexHome`, `nativeStorageRootReceipt`
28
+ // and `nativeConfigReceipt` (read from the Codex `config.toml`) are explicitly null, so a
29
+ // rollback can never mistake this capture for a Codex one. The configured storage root is the
30
+ // Claude `projects/` dir under the ACTUAL `CLAUDE_CONFIG_DIR` (else `HOME/.claude`) and stays
31
+ // null when neither is known. The canonical thread is this launch's OWN recipe thread --
32
+ // computed by `launchProviderThreadId` from the resume plan, an injected/explicit
33
+ // `--session-id` and the caller's argv -- never inferred from the CTM session id, and left
34
+ // null (a fail-closed refusal in `recoverSource`) when the identity is unknown.
35
+ // A blank child CLAUDE_CONFIG_DIR falls back to that child's HOME/.claude, never the parent's
36
+ // config root. Codex keeps its CTM_CODEX_SESSIONS_DIR fallback below, unchanged.
37
+ const claudeConfigDir = spawnEnv.CLAUDE_CONFIG_DIR
38
+ || (capturedHome ? path.join(capturedHome, '.claude') : null);
39
+ return {
40
+ executablePath: preparedLaunchPlan?.cmd || cmd,
41
+ args: Array.isArray(preparedLaunchPlan?.args) ? [...preparedLaunchPlan.args] : [...args],
42
+ workingDirectory: preparedLaunchPlan?.cwd || cwd,
43
+ providerThreadId: executionRecipe?.providerThreadId || null,
44
+ processGeneration,
45
+ homeDir: capturedHome,
46
+ codexHome: null,
47
+ nativeStorageRootConfiguredPath: claudeConfigDir ? path.join(claudeConfigDir, 'projects') : null,
48
+ nativeStorageRootReceipt: null,
49
+ tmpDir: capturedTmpDir,
50
+ nativeConfigReceipt: null,
51
+ };
52
+ }
53
+ const sessionsDir = spawnEnv.CTM_CODEX_SESSIONS_DIR || strFlag('CTM_CODEX_SESSIONS_DIR', '');
54
+ return {
55
+ executablePath: preparedLaunchPlan?.cmd || cmd,
56
+ args: Array.isArray(preparedLaunchPlan?.args) ? [...preparedLaunchPlan.args] : [...args],
57
+ workingDirectory: preparedLaunchPlan?.cwd || cwd,
58
+ providerThreadId: preparedLaunchPlan?.resume?.providerResumeId || preparedLaunchPlan?.resume?.sessionId
59
+ || preparedLaunchPlan?.resume?.agentSessionId || null,
60
+ processGeneration,
61
+ homeDir: capturedHome,
62
+ codexHome: spawnEnv.CODEX_HOME || (capturedHome ? path.join(capturedHome, '.codex') : null),
63
+ nativeStorageRootConfiguredPath: spawnEnv.CTM_CODEX_SESSIONS_DIR
64
+ || sessionsDir
65
+ || ((spawnEnv.CODEX_HOME || capturedHome)
66
+ ? path.join(spawnEnv.CODEX_HOME || path.join(capturedHome, '.codex'), 'sessions') : null),
67
+ nativeStorageRootReceipt: codexPaths?.codexSessionsRootReceipt?.({
68
+ homeDir: capturedHome,
69
+ codexHomePath: spawnEnv.CODEX_HOME || (capturedHome ? path.join(capturedHome, '.codex') : null),
70
+ sessionsDir: sessionsDir || undefined,
71
+ }) || null,
72
+ tmpDir: capturedTmpDir,
73
+ nativeConfigReceipt: nativeConfigReceipt || { state: 'unknown' },
74
+ };
75
+ }
76
+
77
+ module.exports = { buildModelTransitionLaunchContext };
@@ -20,8 +20,11 @@ const { RECIPE_ENV_KEY, MAX_RECIPE_BYTES, modelExecutionRecipeMetadata } = requi
20
20
  const { validateDeferredRestoreAttempt } = require('../deferred-restore-attempt');
21
21
  const { getPrivateSourceRecoveryEnvironment, capturePrivateSourceEnvironment,
22
22
  hasCapturedEmptySourceEnvironmentRestore } = require('../lead-model-restore-reconciliation');
23
- const { modelStorageRootsFromEnv } = require('../host-handoff');
24
- const { strFlag } = require('../env-flags');
23
+ const { modelStorageRootsFromEnv, privateOverridesFromEnv } = require('../host-handoff');
24
+ // WP-0b: the rollback launch capture (moved out of this file, same spawn point) -- see
25
+ // lib/session-create/provider-launch-context.js for the field-by-field contract.
26
+ const { buildModelTransitionLaunchContext } = require('./provider-launch-context');
27
+ const codexNativeProviderGate = require('./codex-native-provider-gate');
25
28
  const MAX_CODEX_CONFIG_BYTES = 1024 * 1024;
26
29
 
27
30
  async function readCodexConfigReceipt(codexHome, onCleanupError = () => {}) {
@@ -76,7 +79,7 @@ function applyModelExecutionRecipeToSpawnEnv(env, recipe, expected = {}) {
76
79
  }
77
80
 
78
81
  function modelExecutionRecipeForSpawn({ sessionId, processGeneration, agent, launchPlan, leadRoute, transition,
79
- sourceEnvironmentReference, providerThreadId: explicitProviderThreadId }) {
82
+ sourceEnvironmentReference, providerThreadId: explicitProviderThreadId, nativeConfigReceipt }) {
80
83
  const routeId = leadRoute ? String(leadRoute.routeId || leadRoute.alias || '') : null;
81
84
  const profile = leadRoute?.profile || leadRoute?.preparedPlan?.profile || null;
82
85
  const ownership = leadRoute?.ownership || leadRoute?.preparedPlan?.ownership || null;
@@ -93,6 +96,8 @@ function modelExecutionRecipeForSpawn({ sessionId, processGeneration, agent, lau
93
96
  factsRevision: routeId ? (profile.factsRevision || ownership?.factsRevision || null) : null,
94
97
  transitionId: transition?.transitionId || leadRoute?.transitionId || ownership?.transitionId || null,
95
98
  ...(sourceEnvironmentReference ? { sourceEnvironmentReference } : {}),
99
+ ...(nativeConfigReceipt && ['present', 'missing'].includes(nativeConfigReceipt.state)
100
+ ? { nativeConfigReceipt: { state: nativeConfigReceipt.state, sha256: nativeConfigReceipt.sha256 ?? null } } : {}),
96
101
  };
97
102
  }
98
103
 
@@ -193,6 +198,7 @@ async function prepareProviderSession(state) {
193
198
  _wsSend,
194
199
  recordSessionDiagnostic,
195
200
  harnessModelProfileLoader,
201
+ markSessionResumeBlocked, // WP-1: the deterministic refusal hook (server.js)
196
202
  } = _getDeps();
197
203
  const { args, cmd, createAgentType, cwd, env, id, msg, preparedLaunchPlan, restoreSeedSnapshot, ws, signal,
198
204
  claudeResumeId, _injectedSessionId } = state;
@@ -322,6 +328,14 @@ async function prepareProviderSession(state) {
322
328
  if (typeof recordSessionDiagnostic === 'function') recordSessionDiagnostic(id, 'lead-route-read-failed', { message: String(error && error.message || error).slice(0, 200) });
323
329
  }
324
330
  }
331
+ // WP-1 (codex-routed-fork-cold-restore-guard §5 D-2..D-4): a native `codex resume T` loads the provider
332
+ // STORED IN T; the gate refuses (D-4) or repairs the route from the journal (D-3) before any spawn.
333
+ if (!target && !readFailed && createAgentType === 'codex' && resolvedProviderThreadId) {
334
+ const gated = await codexNativeProviderGate.gateNativeCodexLaunch({ sessionId: id, threadId: resolvedProviderThreadId,
335
+ env, preparedLaunchPlan, dbModule, recordSessionDiagnostic, markSessionResumeBlocked, ws, wsSend: _wsSend });
336
+ if (gated.refused) { if (runtime) await runtime.close(); return { handled: true, providerState: null }; }
337
+ if (gated.target) target = gated.target;
338
+ }
325
339
  if (target && !readFailed) {
326
340
  let lr;
327
341
  if (target.preparedPlan) {
@@ -861,13 +875,17 @@ function createProviderSession(state) {
861
875
  const leadApplied = _applyLeadRouteToSpawn({ launchArgs, env, leadRoute });
862
876
  launchArgs = leadApplied.launchArgs;
863
877
  // The host receipt carries only whether the original per-session overrides were empty or
864
- // require a surviving private owner. Storage roots projected for this restore remain in the
865
- // launch context and do not turn an otherwise empty override set into a private environment.
878
+ // require a surviving private owner. Storage roots and TMPDIR projected into the launch context
879
+ // (`launchEnvironmentOverrides`) are launch context, not private overrides: for EVERY spawn, not
880
+ // only a host restore, they are dropped before the receipt is computed, so a projected HOME/TMPDIR
881
+ // never turns an otherwise empty override set into a private environment. The spawned child still
882
+ // receives them (`launchEnvOverrides` below).
866
883
  const trustedCapturedEmptySourceEnvironment = msg._isRestore === true
867
884
  && hasCapturedEmptySourceEnvironmentRestore(msg);
868
885
  const sourceOverrideCapture = capturePrivateSourceEnvironment(sourceRecoveryEnvironment
869
- ? sourceRecoveryEnvironment.environment : trustedCapturedEmptySourceEnvironment ? {}
870
- : (msg.env && typeof msg.env === 'object' ? msg.env : {}));
886
+ ? privateOverridesFromEnv(sourceRecoveryEnvironment.environment)
887
+ : trustedCapturedEmptySourceEnvironment ? {}
888
+ : privateOverridesFromEnv(msg.env && typeof msg.env === 'object' ? msg.env : {}));
871
889
  const sourceEnvironmentReference = trustedCapturedEmptySourceEnvironment ? 'captured-empty'
872
890
  : sourceOverrideCapture.state === 'captured'
873
891
  ? (Object.keys(sourceOverrideCapture.values || {}).length === 0 ? 'captured-empty' : 'private-owner-required')
@@ -890,7 +908,7 @@ function createProviderSession(state) {
890
908
  const modelProcessGeneration = capturedModelProcessGeneration;
891
909
  const executionRecipe = modelExecutionRecipeForSpawn({ sessionId: id, processGeneration: modelProcessGeneration,
892
910
  agent: createAgentType, launchPlan: preparedLaunchPlan, leadRoute, transition: msg._leadModelTransition || null,
893
- sourceEnvironmentReference, providerThreadId: launchProviderThreadId({ agent: createAgentType,
911
+ sourceEnvironmentReference, nativeConfigReceipt, providerThreadId: launchProviderThreadId({ agent: createAgentType,
894
912
  launchPlan: preparedLaunchPlan, claudeResumeId, injectedSessionId: _injectedSessionId, args: launchArgs }) });
895
913
  let spawnEnv = { ...applyModelExecutionRecipeToSpawnEnv(leadApplied.spawnEnv, executionRecipe,
896
914
  { sessionId: id, processGeneration: modelProcessGeneration }), CTM_MODEL_PROCESS_GENERATION: String(modelProcessGeneration) };
@@ -1063,32 +1081,14 @@ function createProviderSession(state) {
1063
1081
  _modelProcessGeneration: modelProcessGeneration,
1064
1082
  _modelExecutionRecipe: modelExecutionRecipeMetadata(executionRecipe,
1065
1083
  { sessionId: id, processGeneration: modelProcessGeneration }).modelExecutionRecipe || null,
1066
- ...(createAgentType === 'codex' ? { _modelTransitionLaunchContext: (() => {
1067
- const capturedHome = leadApplied.spawnEnv.HOME || serverConfig.HOME || null;
1068
- const sessionsDir = leadApplied.spawnEnv.CTM_CODEX_SESSIONS_DIR || strFlag('CTM_CODEX_SESSIONS_DIR', '');
1069
- return {
1070
- executablePath: preparedLaunchPlan?.cmd || cmd,
1071
- args: Array.isArray(preparedLaunchPlan?.args) ? [...preparedLaunchPlan.args] : [...args],
1072
- workingDirectory: preparedLaunchPlan?.cwd || cwd,
1073
- providerThreadId: preparedLaunchPlan?.resume?.providerResumeId || preparedLaunchPlan?.resume?.sessionId
1074
- || preparedLaunchPlan?.resume?.agentSessionId || null,
1075
- processGeneration: modelProcessGeneration,
1076
- homeDir: capturedHome,
1077
- codexHome: leadApplied.spawnEnv.CODEX_HOME || (capturedHome ? path.join(capturedHome, '.codex') : null),
1078
- nativeStorageRootConfiguredPath: leadApplied.spawnEnv.CTM_CODEX_SESSIONS_DIR
1079
- || sessionsDir
1080
- || ((leadApplied.spawnEnv.CODEX_HOME || capturedHome)
1081
- ? path.join(leadApplied.spawnEnv.CODEX_HOME || path.join(capturedHome, '.codex'), 'sessions') : null),
1082
- nativeStorageRootReceipt: codexPaths?.codexSessionsRootReceipt?.({
1083
- homeDir: capturedHome,
1084
- codexHomePath: leadApplied.spawnEnv.CODEX_HOME || (capturedHome ? path.join(capturedHome, '.codex') : null),
1085
- sessionsDir: sessionsDir || undefined,
1086
- }) || null,
1087
- tmpDir: typeof leadApplied.spawnEnv.TMPDIR === 'string' && path.isAbsolute(leadApplied.spawnEnv.TMPDIR)
1088
- ? leadApplied.spawnEnv.TMPDIR : null,
1089
- nativeConfigReceipt: nativeConfigReceipt || { state: 'unknown' },
1090
- };
1091
- })() } : {}),
1084
+ // native-same-thread-model-switch / §6.5, WP-0b: the PRIVATE launch capture a rollback recovery
1085
+ // replays, built at THIS REAL spawn point by the sibling module (see
1086
+ // lib/session-create/provider-launch-context.js for the field-by-field contract).
1087
+ ...((createAgentType === 'codex' || createAgentType === 'claude') ? { _modelTransitionLaunchContext: buildModelTransitionLaunchContext({
1088
+ agentType: createAgentType, preparedLaunchPlan, cmd, args, cwd,
1089
+ spawnEnv: leadApplied.spawnEnv, serverHome: serverConfig.HOME,
1090
+ executionRecipe, processGeneration: modelProcessGeneration, nativeConfigReceipt, codexPaths,
1091
+ }) } : {}),
1092
1092
  clients: sessionClients,
1093
1093
  _primaryWs: null,
1094
1094
  // scrollback removed — headless terminal is source of truth (Phase 3D)
@@ -1453,11 +1453,10 @@ function createProviderSession(state) {
1453
1453
  provider: sessionAgentType,
1454
1454
  providerResumeId: sessionAgentType === 'codex' ? (claudeResumeId || '') : '',
1455
1455
  cwd,
1456
- title: session.title || session.label,
1457
- userRenamed: !!session.userRenamed,
1458
- titleSource: session.userRenamed ? 'user' : '',
1459
- titleStatus: session.userRenamed ? 'user_named' : '',
1460
- titleStatusReason: session.userRenamed ? 'new_session_title' : '',
1456
+ // D-2 (session-name design 2026-10-23): a resume of a titled row keeps its title + provenance (upsertSession keeps omitted keys).
1457
+ ...(isResumeLaunch && existingTitle?.title ? {} : { title: session.title || session.label, userRenamed: !!session.userRenamed,
1458
+ titleSource: session.userRenamed ? 'user' : '', titleStatus: session.userRenamed ? 'user_named' : '',
1459
+ titleStatusReason: session.userRenamed ? 'new_session_title' : '' }),
1461
1460
  projectEntry: sessionAgentType === 'claude' ? encodeClaudeProjectEntry(cwd) : encodeProjectEntry(cwd),
1462
1461
  projectPath: cwd,
1463
1462
  },
@@ -9,6 +9,12 @@ const { releaseAdmissionOnExit, retireWorkerOnExit, scheduleWorkerObservation }
9
9
  // whole frame is built by the SAME bounded pure transport leaf (it copies the fixed typed whitelist out
10
10
  // of the payload `_sessionPayload` already produced).
11
11
  const { buildCreatedSessionPayload } = require('../coding-session-model-public');
12
+ // WP-2 (docs/codex-routed-fork-cold-restore-guard-2026-10-22.html §5 D-5): the module carries the
13
+ // rationale — a Codex config-load failure is a precondition failure, never a restart-budget consumer.
14
+ const { classifyCodexResumeExit } = require('./codex-resume-exit-classify');
15
+ const { codexProviderMissingMessage } = require('./codex-native-provider-gate'); // WP-1 owns the one block sentence
16
+ // WP-1 (D-1/D-2, S-11): the pure chooser for the block a deferred exit carries (a direct require, like the two leaves above: the injected `runtime` is built in server.js, which this WP does not own).
17
+ const { deferBlockForExit } = require('../resume-blocked-wire');
12
18
 
13
19
  // D-9 (delegated-worker-lifecycle-identity-observability-2026-09-27.html §5 D-9, §9 S-15):
14
20
  // best-effort proxy-token revoke for a worker session exiting on the CREATE path (never
@@ -887,7 +893,7 @@ function installResponseRuntime(runtime) {
887
893
  // classification BEFORE this handler is installed; the handler then passes its FULL event through it.
888
894
  const leadRouteCleanup = runtime.session.agentRole === 'worker' ? null : require('./lead-route-launch').createLeadRouteLifetimeCleanup({ sessionId: runtime.session.id, ownership: runtime.session._leadRouteTokenOwnership, hosted: _useSessionHostProcessForPty() === true });
889
895
  const onPtyExit = async (exitEvent) => {
890
- const { exitCode, signal } = exitEvent || {};
896
+ const { exitCode, signal, exitSource } = exitEvent || {};
891
897
  runtime.sessionInputAuthority.observeProvider({ sessionId: runtime.id, status: 'exited' });
892
898
  runtime.session._ptyExitLifecycle = {
893
899
  stage: 'capturing-viewport',
@@ -1064,6 +1070,20 @@ function installResponseRuntime(runtime) {
1064
1070
  // retry path as an exit 1 rather than being mistaken for a completed terminal lifecycle.
1065
1071
  const maxAutoRestarts = 3;
1066
1072
  const restartCount = runtime.session._autoRestartCount || 0;
1073
+ // WP-2 (§5 D-5, §9 S-9/S-10): classify THIS attempt's buffer — never scrollback — before the
1074
+ // auto-restart decision, and block a Codex config-load failure instead of spending the budget.
1075
+ const codexProviderMissingExit = (agentType === 'codex' && exitedBeforeResumeReady) ? classifyCodexResumeExit(runtime.session._resumeAttemptOutput || '') : null;
1076
+ if (codexProviderMissingExit) {
1077
+ runtime.recordSessionDiagnostic(runtime.id, 'codex-provider-missing-exit', { provider: codexProviderMissingExit.provider, exitCode });
1078
+ // Marked ONCE. This is what makes the auto-restart decision below false
1079
+ // (`resumeBlocked: isSessionResumeBlocked(runtime.id)`), so `handleCreatePrepared` is never
1080
+ // scheduled for this exit; the flow then falls through to the ordinary exit-persistence path,
1081
+ // which sees the session already blocked and keeps the placeholder + startup recipe as is.
1082
+ markSessionResumeBlocked(runtime.id, {
1083
+ code: 'codex_provider_missing', detail: codexProviderMissingExit.line, agentType: 'codex', deterministic: true,
1084
+ message: codexProviderMissingMessage(codexProviderMissingExit.provider),
1085
+ }, 'codex-provider-exit');
1086
+ }
1067
1087
  // A worker continuation does launch `-p --resume` / `exec resume`, but its exit is terminal and
1068
1088
  // never an interactive auto-restart (that would relaunch it as a TUI under the worker's identity,
1069
1089
  // stuck at worker-status 'starting'). lib/session-class.js declares that: relaunchFromRestore=false.
@@ -1208,25 +1228,22 @@ function installResponseRuntime(runtime) {
1208
1228
  const exitPersistence = sessionExitPersistenceDecision({
1209
1229
  intentionalKill: !!runtime.session._intentionalKill,
1210
1230
  exitCode,
1211
- signal,
1231
+ signal, exitSource,
1212
1232
  isResumable,
1213
1233
  resumeContext: resumeExitContext(runtime.session), deferOnAbnormalExit: sessionPolicy(runtime.session).deferOnAbnormalExit,
1214
1234
  });
1215
1235
  runtime.session._ptyExitLifecycle.stage = `persistence-${String(exitPersistence.action || 'unknown')}`;
1216
1236
  if (exitPersistence.action === 'defer') {
1217
1237
  const latestResumeExit = resumeExitContext(runtime.session);
1218
- if (!isSessionResumeBlocked(runtime.id)) {
1219
- const label = getAgentCapabilities(agentType).label || 'The agent';
1238
+ const label = getAgentCapabilities(agentType).label || 'The agent';
1239
+ // WP-1 (D-1/D-2): the block comes from the exit EVIDENCE -- an unknown exit yields null (defer with no block: exited, and the next input resumes it).
1240
+ const block = deferBlockForExit({ exitPersistence, latestResumeExit, exitCode, signal, autoRestartCount: runtime.session._autoRestartCount || 0, label });
1241
+ if (block && !isSessionResumeBlocked(runtime.id)) {
1220
1242
  markSessionResumeBlocked(runtime.id, {
1221
- code: latestResumeExit.failedBeforeReady
1222
- ? (latestResumeExit.code || 'resume_failed')
1223
- : 'session_crash_loop',
1224
- message: latestResumeExit.failedBeforeReady
1225
- ? `${label} did not become ready while resuming.`
1226
- : `${label} exited unexpectedly and automatic recovery was exhausted.`,
1243
+ ...block,
1227
1244
  detail: resumeFailureDetail(agentType, runtime.session._resumeAttemptOutput || ''),
1228
1245
  agentType,
1229
- });
1246
+ }, 'response-defer');
1230
1247
  }
1231
1248
  // Keep the CTM identity and startup recipe as a deferred placeholder. Retiring the startup
1232
1249
  // task here would make retry impossible. Failed resume mirrors also stay provisional so they
@@ -1243,7 +1260,8 @@ function installResponseRuntime(runtime) {
1243
1260
  runtime.session._restoreStarting = false;
1244
1261
  runtime.session._lifecycleState = 'deferred';
1245
1262
  runtime._markServerSessionTurnClosed(runtime.session, Date.now(), 'session-exit'); // R-15: PROCESS_EXIT, never a dead wait
1246
- runtime.session._resumeBlocked = true;
1263
+ // WP-1 (D-1): read the flag, never assert it -- a defer with no block is "exited, resumes on input", not "resuming".
1264
+ runtime.session._resumeBlocked = isSessionResumeBlocked(runtime.id);
1247
1265
  runtime.session._exitPersistenceReason = exitPersistence.reason;
1248
1266
  runtime.session._restoreTask = {
1249
1267
  session_id: runtime.id,
@@ -120,12 +120,21 @@ async function createWalleSession(state) {
120
120
  if (createResult) deps.recordWalleTranscriptAppend(session, createResult);
121
121
  for (const record of seeded.records) deps.recordWalleTranscriptAppend(session, record);
122
122
  try {
123
+ // WP-0 (session-name-agent-title-precedence-2026-10-23.html §5 D-2): reusing an existing
124
+ // Wall-E transcript must not rewrite the row's title or its provenance — the client echoes
125
+ // the displayed name back (D-1), and upsertSession keeps the stored value for any omitted
126
+ // title key (or empty titleSource/titleStatus/titleStatusReason), so omit them on a resume
127
+ // of a row that already has a title.
128
+ const preserveTitleProvenance = !msg._isRestore
129
+ && (launch.walleResumeRequest || launch.isResumeLaunch) && !!existingTitle?.title;
123
130
  void deps.detachOwnerMutation('walle-session-created', () => deps.dbModule.upsertSession(id, {
124
131
  agentSessionId: chatSessionId, provider: 'walle', cwd, projectPath: cwd,
125
- title: session.title, userRenamed: !!session.userRenamed,
126
- titleSource: session.userRenamed ? 'user' : '',
127
- titleStatus: session.userRenamed ? 'user_named' : '',
128
- titleStatusReason: session.userRenamed ? 'new_session_title' : '',
132
+ ...(preserveTitleProvenance ? {} : {
133
+ title: session.title, userRenamed: !!session.userRenamed,
134
+ titleSource: session.userRenamed ? 'user' : '',
135
+ titleStatus: session.userRenamed ? 'user_named' : '',
136
+ titleStatusReason: session.userRenamed ? 'new_session_title' : '',
137
+ }),
129
138
  jsonlPath, fileSize: 0, modifiedAt: '', model: modelId || '', hostname: deps.hostname,
130
139
  }));
131
140
  } catch (error) {
@@ -7,6 +7,12 @@ const admissionDefault = require('../worker-admission');
7
7
  const { restoreSucceeded } = require('../resume-rung-enrich');
8
8
  const transcriptRetention = require('../transcript-retention-check');
9
9
  const transcriptSource = require('../transcript-source');
10
+ // WP-2 (D-4/D-7): the derived-transcript-path helper and its verifier (see the preflight at the
11
+ // transcript link below). serverConfig is the same live-read env seam production uses for the
12
+ // Claude config dir (server.js:6743 getClaudeConfigDir).
13
+ const serverConfig = require('../server-config');
14
+ const { deriveClaudeTranscriptPath } = require('../resume-cwd');
15
+ const { verifyClaudeTranscriptAt } = require('../transcript-link');
10
16
  const { isColdDeferredSession, notifyWorkerGeneration } = require('./worker-observability');
11
17
  const { budgetSentence } = require('./worker-brief');
12
18
  const { attachProgressGuard } = require('./worker-progress-guard');
@@ -533,7 +539,43 @@ function createWorkerContinuation({ getDeps, admission = admissionDefault, helpe
533
539
  catch {
534
540
  return failReceipt('worker_transcript_unavailable', 'The provider transcript link could not be read.', { retryable: true });
535
541
  }
536
- const transcriptPath = String(agentRow && agentRow.jsonl_path || '').trim();
542
+ // WP-2 (D-4, worker-transcript-link-derived-not-discovered-2026-10-25.html §5 D-4/D-7): an
543
+ // empty jsonl_path is "we never recorded the link", not "the transcript is gone". Claude Code
544
+ // writes a session's transcript at a path derivable from (cwd, session id) alone, so derive
545
+ // it, VERIFY it through the one transcript reader (lib/transcript-link.js -- the file's own
546
+ // first line must name this session), link it, and continue. A derived path that verifies
547
+ // false, or a row with no cwd to derive from, refuses exactly as before -- now naming what
548
+ // was checked. Codex rows never enter this branch (their resume identity is the rollout
549
+ // thread, and a missing link there is a different failure).
550
+ let transcriptPath = String(agentRow && agentRow.jsonl_path || '').trim();
551
+ if (!transcriptPath && agentRow && recipe.agent === 'claude') {
552
+ const cwd = String(recipe.cwd || agentRow.project_path || agentRow.cwd || '').trim();
553
+ const providerSessionId = String(agentRow.agent_session_id || id);
554
+ let derived = '';
555
+ try {
556
+ derived = deriveClaudeTranscriptPath({
557
+ cwd,
558
+ agentSessionId: providerSessionId,
559
+ // The house coercion for this dep (lib/session-create/worker-mcp-servers.js:45): production's
560
+ // deps carries no `homedir` at all, and the test corpus injects both a getter and a string.
561
+ homeDir: typeof deps.homedir === 'function' ? deps.homedir() : deps.homedir,
562
+ claudeConfigDir: deps.claudeConfigDir || serverConfig.CLAUDE_CONFIG_DIR || '',
563
+ });
564
+ } catch { /* expected: a row with no cwd (or no agent_session_id) has nothing to derive -- fall through to the unchanged refusal */ }
565
+ if (derived) {
566
+ const verified = await verifyClaudeTranscriptAt(derived, providerSessionId, {
567
+ ...(typeof deps.resolveTranscriptSource === 'function' ? { resolveTranscriptSource: deps.resolveTranscriptSource } : {}),
568
+ ...(typeof deps.readTranscriptHead === 'function' ? { readTranscriptHead: deps.readTranscriptHead } : {}),
569
+ });
570
+ if (!verified.ok) {
571
+ return failReceipt('worker_transcript_missing', 'The provider transcript is not linked to this worker.', {
572
+ extra: { derived_path: derived, derived_state: verified.state },
573
+ });
574
+ }
575
+ if (typeof db.updateAgentSessionTranscriptLink === 'function') db.updateAgentSessionTranscriptLink(providerSessionId, derived);
576
+ transcriptPath = derived;
577
+ }
578
+ }
537
579
  if (!transcriptPath) return failReceipt('worker_transcript_missing', 'The provider transcript is not linked to this worker.');
538
580
 
539
581
  let providerId = '';
@@ -1,9 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  // A lead hears that its delegated worker stopped through its next PostToolUse / UserPromptSubmit
4
- // hook (lib/api/ingress.js -> bin/claude-hook.js). The queue lives here; the durable truth is the
5
- // terminal receipt's `delivered_at_ms` in worker_sessions.runtime_json, so a CTM restart rebuilds
6
- // the undelivered notices once per parent. Never types into the lead's terminal.
4
+ // hook, and -- RC-1, docs/session-stops-mid-job-2026-10-24.html D-1..D-3 -- through its Stop hook
5
+ // too, which is answered synchronously by CTM with the drained notices plus, when the lead still
6
+ // owns a live worker and nothing pending will wake it, a nudge naming walle_worker_wait /
7
+ // walle_stop_worker. The queue lives here; the durable truth is the terminal receipt's
8
+ // `delivered_at_ms` in worker_sessions.runtime_json, so a CTM restart rebuilds the undelivered
9
+ // notices once per parent. Never types into the lead's terminal (D-5).
7
10
 
8
11
  const mainDbCensus = require('../main-db-census');
9
12
  const { nextStepFor } = require('../worker-failure-classify');
@@ -13,6 +16,88 @@ const MAX_TEXT = 400;
13
16
 
14
17
  const _queues = new Map(); // parent ctm id -> [{ receipt_id, worker_id, parent, text, at_ms }]
15
18
 
19
+ // WP-0 (D-2/D-7): the live-worker index, maintained from the receipts CTM already publishes.
20
+ // Memory only -- the hook path touches no DB, and a CTM restart retires every live worker, so the
21
+ // index starts empty and needs no rebuild.
22
+ const _live = new Map(); // parent ctm id -> Map(worker id -> { generation, at_ms })
23
+
24
+ // WP-1 (D-4): one nudge per tool epoch. `nudgedAtEpoch` starts at `null` so the first Stop
25
+ // (toolEpoch 0) nudges; a second Stop with no PostToolUse between sees toolEpoch === nudgedAtEpoch.
26
+ const _epochs = new Map(); // parent ctm id -> { toolEpoch, nudgedAtEpoch }
27
+
28
+ function _epochFor(parent) {
29
+ let epoch = _epochs.get(parent);
30
+ if (!epoch) { epoch = { toolEpoch: 0, nudgedAtEpoch: null }; _epochs.set(parent, epoch); }
31
+ return epoch;
32
+ }
33
+
34
+ // D-2: a `started` receipt says this worker is live for its parent until a terminal receipt for the
35
+ // same or a newer generation arrives. No parent or no worker id -> nothing to index.
36
+ function markWorkerLive(receipt) {
37
+ if (!receipt || receipt.kind !== 'started') return null;
38
+ const parent = String(receipt.parent_ctm_session_id || '');
39
+ const workerId = String(receipt.worker_id || '');
40
+ if (!parent || !workerId) return null;
41
+ const generation = Number(receipt.generation) || 1;
42
+ const atMs = Number(receipt.at_ms) || Date.now();
43
+ const map = _live.get(parent) || new Map();
44
+ map.set(workerId, { generation, at_ms: atMs });
45
+ _live.set(parent, map);
46
+ return { worker_id: workerId, generation, at_ms: atMs };
47
+ }
48
+
49
+ // The terminal receipt retires the worker, but an OLDER generation's terminal must never erase a
50
+ // newer generation's `started` (AC-0c): the remove happens only while stored generation <= receipt
51
+ // generation.
52
+ function markWorkerGone(receipt) {
53
+ const parent = String(receipt?.parent_ctm_session_id || '');
54
+ const workerId = String(receipt?.worker_id || '');
55
+ if (!parent || !workerId) return false;
56
+ const map = _live.get(parent);
57
+ if (!map) return false;
58
+ const entry = map.get(workerId);
59
+ if (entry && Number(entry.generation) > (Number(receipt.generation) || 1)) return false;
60
+ map.delete(workerId);
61
+ if (!map.size) _live.delete(parent);
62
+ return true;
63
+ }
64
+
65
+ function liveWorkers(parentCtmSessionId) {
66
+ const parent = String(parentCtmSessionId || '');
67
+ const map = _live.get(parent);
68
+ if (!map || !map.size) return [];
69
+ return [...map.entries()]
70
+ .map(([worker_id, entry]) => ({ worker_id, generation: entry.generation, at_ms: entry.at_ms }))
71
+ .sort((a, b) => a.at_ms - b.at_ms);
72
+ }
73
+
74
+ function noteLeadToolUse(parentCtmSessionId) {
75
+ const parent = String(parentCtmSessionId || '');
76
+ if (!parent) return null;
77
+ const epoch = _epochFor(parent);
78
+ epoch.toolEpoch += 1;
79
+ return epoch.toolEpoch;
80
+ }
81
+
82
+ // D-3/D-4: the Stop nudge. Returns null when no worker is live, when a pending background task or
83
+ // session cron will wake the lead anyway, when the field is absent (Claude did not send it --
84
+ // unknown state fails open, never a nudge), or when this tool epoch was already nudged.
85
+ function stopNudge(parentCtmSessionId, { backgroundTasks = null, sessionCrons = null } = {}) {
86
+ const parent = String(parentCtmSessionId || '');
87
+ if (!parent) return null;
88
+ const workers = liveWorkers(parent);
89
+ if (!workers.length) return null;
90
+ if (Array.isArray(backgroundTasks) && backgroundTasks.some((task) => task && task.status === 'running')) return null;
91
+ if (Array.isArray(sessionCrons) && sessionCrons.length) return null;
92
+ if (!Array.isArray(backgroundTasks)) return null;
93
+ const epoch = _epochFor(parent);
94
+ if (epoch.toolEpoch === epoch.nudgedAtEpoch) return null;
95
+ epoch.nudgedAtEpoch = epoch.toolEpoch;
96
+ const firstId = workers[0].worker_id;
97
+ const text = `Delegated worker ${firstId} is still working (${workers.length} live) and nothing pending will wake you when it finishes. Call walle_worker_wait to keep waiting, or walle_stop_worker if you no longer need it. If you are deliberately handing back to your user with the worker still running, say so and end your turn again.`;
98
+ return { text, workers: workers.map((worker) => worker.worker_id) };
99
+ }
100
+
16
101
  // D-25: the notice ends with the failure's next_step. The evidence carries it when the
17
102
  // publisher stamped it; a receipt stored before that (or filtered by the evidence
18
103
  // whitelist) still names the code/class/reason, so the SAME table derives the identical
@@ -51,6 +136,7 @@ function noticeText(receipt) {
51
136
  function enqueueNotice(receipt) {
52
137
  const parent = String(receipt?.parent_ctm_session_id || '');
53
138
  if (!parent || receipt.kind !== 'terminal' || !receipt.receipt_id) return null;
139
+ markWorkerGone(receipt);
54
140
  const notice = { receipt_id: receipt.receipt_id, worker_id: String(receipt.worker_id || ''), parent, text: noticeText(receipt), at_ms: Number(receipt.at_ms) || Date.now() };
55
141
  const queue = _queues.get(parent) || [];
56
142
  if (!queue.some((n) => n.receipt_id === notice.receipt_id)) queue.push(notice);
@@ -132,6 +218,9 @@ function drainNotices(parentCtmSessionId, { now = Date.now(), dbModule = null, d
132
218
  };
133
219
  }
134
220
 
135
- function _resetForTest() { _queues.clear(); }
221
+ function _resetForTest() { _queues.clear(); _live.clear(); _epochs.clear(); }
136
222
 
137
- module.exports = { enqueueNotice, rebuildFromDb, drainNotices, noticeText, _resetForTest };
223
+ module.exports = {
224
+ enqueueNotice, rebuildFromDb, drainNotices, noticeText,
225
+ markWorkerLive, liveWorkers, noteLeadToolUse, stopNudge, _resetForTest,
226
+ };