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
@@ -0,0 +1,536 @@
1
+ 'use strict';
2
+ // WP-0 (docs/local-landing-queue-multi-session-integration-2026-10-26.html §6.1, §5 D-1/D-6, §8
3
+ // WP-0): the landing queue's configuration, read from `.ctm.json#landing` through the SAME walker
4
+ // CTM already uses (lib/project-config.js) — one file, one walker, one schema, no flags (D-1).
5
+ //
6
+ // Validation is strict on purpose (§6.1): unknown keys are rejected, `mode` is `"serial"` only
7
+ // until WP-8, `cachePaths` must be git-ignored, and every `regenerate.paths` glob must match at
8
+ // least one tracked path. Every failure is a typed Error (`.code`).
9
+ //
10
+ // A repo without `.ctm.json` is normal (autodetect is the whole point of §6.1), so the loader
11
+ // works from the repository TOPLEVEL: an unconfigured repo still gets gates from autodetect, and
12
+ // a submit from a subdirectory behaves exactly like one from the root. A `.ctm.json` found above
13
+ // the toplevel (`~/ws/.ctm.json` for a repo in `~/ws/x`) is somebody else's config and is
14
+ // ignored, never inherited. Outside a repository there is nothing to land into: `not_a_repo`.
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const crypto = require('crypto');
19
+ const { findProjectConfig } = require('../project-config');
20
+ const { landingError, revParseOrNull, runGitRaw, toplevel } = require('./git');
21
+
22
+ const ALLOWED_KEYS = Object.freeze(['target', 'mode', 'gates', 'regenerate', 'refresh', 'registries', 'cachePaths', 'guard', 'triage', 'batch', 'publish']);
23
+ const DEFAULT_GATE_TIMEOUT_SECONDS = 3600;
24
+ // Off unless the repo asks for it (§7 E-1 / `land init --guard`).
25
+ const DEFAULT_GUARD = false;
26
+ // §5 D-7: at most this many failed test files are rerun on the base commit (WP-2).
27
+ const DEFAULT_TRIAGE_MAX_FILES = 8;
28
+ // The only key `landing.triage` understands today.
29
+ const TRIAGE_KEYS = Object.freeze(['maxFiles']);
30
+ // §5 D-3 / §6 (WP-1): the batch window's ceiling and how long a lone job waits for company. Both are
31
+ // defaults in code, never flags — batching is default-ON with a ceiling of 8 and no waiting, so a
32
+ // repository with no `landing.batch` key behaves exactly as it did before this change (`max: 1` is the
33
+ // serial queue; `waitSeconds: 0` means a ready train never waits).
34
+ const DEFAULT_BATCH_MAX = 8;
35
+ const DEFAULT_BATCH_WAIT_SECONDS = 0;
36
+ // The only keys `landing.batch` understands today.
37
+ const BATCH_KEYS = Object.freeze(['max', 'waitSeconds']);
38
+
39
+ // WP-0/WP-1 (docs/fleet-origin-main-sync-skill-2026-10-31.html §6.1): `landing.publish` — the origin
40
+ // half of the landing policy. Absent = `land sync` is off for that repository (other users' repos are
41
+ // unaffected, and there is no env flag). Present = on, with the §6.1 defaults below.
42
+ const PUBLISH_KEYS = Object.freeze([
43
+ 'remote', 'branch', 'auto', 'follow', 'followIntervalMs', 'maxRetrains',
44
+ // WP-6 (docs/fleet-origin-main-sync-skill-2026-10-31.html §13.4 R-R3/R-R4, §13.7): the resolver
45
+ // half of the publish policy. `resolve` says whether CTM opens a resolver session at all, the
46
+ // three others describe that session and the FAST gate its resolution runs.
47
+ 'resolve', 'resolveAgent', 'resolveMaxMinutes', 'resolveFastGate',
48
+ ]);
49
+ const DEFAULT_PUBLISH_REMOTE = 'origin';
50
+ const DEFAULT_PUBLISH_BRANCH = 'main';
51
+ // §5 R-9 (auto-publish after a landing) and R-8 (the CTM follower) are both default-ON.
52
+ const DEFAULT_PUBLISH_AUTO = true;
53
+ const DEFAULT_PUBLISH_FOLLOW = true;
54
+ // §5 R-8: fetch origin every 15 minutes.
55
+ const DEFAULT_PUBLISH_FOLLOW_INTERVAL_MS = 900000;
56
+ // §5 R-4: at most this many extra trains on a rejected push.
57
+ const DEFAULT_PUBLISH_MAX_RETRAINS = 3;
58
+ // §13.4 R-R1/R-R2: `session` = a blocked conflict (or a failed gate) becomes a visible resolver
59
+ // session; `off` = rev-2 behaviour (the follower keeps `--pull-only`).
60
+ const DEFAULT_PUBLISH_RESOLVE = 'session';
61
+ // §13.4 D-R2: which agent harness the resolver session runs on.
62
+ const DEFAULT_PUBLISH_RESOLVE_AGENT = 'claude';
63
+ // §13.4 R-R8: the resolver's wall-clock budget, in minutes (10 min .. 24 h).
64
+ const DEFAULT_PUBLISH_RESOLVE_MAX_MINUTES = 120;
65
+ const RESOLVE_MODES = Object.freeze(['session', 'off']);
66
+ const RESOLVE_AGENTS = Object.freeze(['claude', 'codex']);
67
+ const RESOLVE_MAX_MINUTES_MIN = 10;
68
+ const RESOLVE_MAX_MINUTES_MAX = 1440;
69
+ // §13.4 R-R4: the FAST gate a `kind:"resolve"` job runs instead of `landing.gates`. It is a gate
70
+ // entry in every respect (`{name, run, timeoutSeconds}`, run in the train worktree), so it is
71
+ // validated by the very same `normalizeGate`.
72
+ const DEFAULT_PUBLISH_RESOLVE_FAST_GATE = Object.freeze({
73
+ name: 'resolve-fast-gate',
74
+ run: 'bash bin/resolve-fast-gate.sh',
75
+ timeoutSeconds: 2400,
76
+ });
77
+
78
+ function isPlainObject(value) {
79
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
80
+ }
81
+
82
+ function isNonEmptyString(value) {
83
+ return typeof value === 'string' && value.trim() !== '';
84
+ }
85
+
86
+ function realpathOr(dir) {
87
+ try {
88
+ return fs.realpathSync(dir);
89
+ } catch (error) {
90
+ /* expected: the directory vanished between the walk and this call; the resolved-path form is
91
+ still a usable answer for the containment test */
92
+ return path.resolve(dir);
93
+ }
94
+ }
95
+
96
+ // True when `child` is `parent` itself or lies underneath it. Both sides must be resolved paths.
97
+ function isInside(parent, child) {
98
+ const rel = path.relative(parent, child);
99
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
100
+ }
101
+
102
+ // §6.1: `landing.target` defaults to the repo's main branch. This mirrors
103
+ // coding-task-manager/git-utils.js `resolveMainBranch` (origin/HEAD -> main -> master) for the
104
+ // local-branch part only; the local form is used because git-utils.js is async and pulls two
105
+ // extra modules (../shared/git-remote-key, ./lib/async-semaphore) into a library that must stay
106
+ // dependency-free and synchronous.
107
+ function resolveMainBranch(cwd) {
108
+ if (revParseOrNull(cwd, 'refs/heads/main')) return 'main';
109
+ if (revParseOrNull(cwd, 'refs/heads/master')) return 'master';
110
+ return 'main';
111
+ }
112
+
113
+ function readFileSafe(file) {
114
+ try {
115
+ return fs.readFileSync(file, 'utf8');
116
+ } catch (error) {
117
+ /* expected: the ecosystem probe file is absent or unreadable -> not this ecosystem */
118
+ return null;
119
+ }
120
+ }
121
+
122
+ // §6.1 autodetect, first match in the documented order. A repo that matches nothing gates
123
+ // nothing, which is a refusal at `land submit` time (config_gates_missing), never a silent pass.
124
+ // `readRel(rel)` returns a file's text or null; it defaults to the working tree at `cwd`, and the
125
+ // target-policy loader passes a reader over the target commit instead.
126
+ function autodetectGates(cwd, readRel = (rel) => readFileSafe(path.join(cwd, rel))) {
127
+ const gate = (name, run) => [{ name, run, timeoutSeconds: DEFAULT_GATE_TIMEOUT_SECONDS }];
128
+ const pkgRaw = readRel('package.json');
129
+ if (pkgRaw !== null) {
130
+ try {
131
+ const pkg = JSON.parse(pkgRaw);
132
+ if (pkg && isPlainObject(pkg.scripts) && isNonEmptyString(pkg.scripts.test)) {
133
+ return { gates: gate('npm-test', 'npm test'), gatesSource: 'autodetect' };
134
+ }
135
+ } catch (error) {
136
+ /* expected: an unparseable package.json is not a test command; fall through to the next
137
+ ecosystem probe (and `land doctor` reports the parse failure separately) */
138
+ }
139
+ }
140
+ const makefile = readRel('Makefile');
141
+ if (makefile !== null && /^test\s*:/m.test(makefile)) {
142
+ return { gates: gate('make-test', 'make test'), gatesSource: 'autodetect' };
143
+ }
144
+ if (readRel('pyproject.toml') !== null) {
145
+ return { gates: gate('pytest', 'python -m pytest'), gatesSource: 'autodetect' };
146
+ }
147
+ if (readRel('Cargo.toml') !== null) {
148
+ return { gates: gate('cargo-test', 'cargo test'), gatesSource: 'autodetect' };
149
+ }
150
+ if (readRel('go.mod') !== null) {
151
+ return { gates: gate('go-test', 'go test ./...'), gatesSource: 'autodetect' };
152
+ }
153
+ return { gates: [], gatesSource: 'none' };
154
+ }
155
+
156
+ function normalizeGate(cwd, entry, index, label) {
157
+ const where = label || `landing.gates[${index}]`;
158
+ if (!isPlainObject(entry)) {
159
+ throw landingError('config_invalid', `${where} must be an object`, { index, configDir: cwd });
160
+ }
161
+ if (!isNonEmptyString(entry.name)) {
162
+ throw landingError('config_invalid', `${where}.name must be a non-empty string`, { index, configDir: cwd });
163
+ }
164
+ if (!isNonEmptyString(entry.run)) {
165
+ throw landingError('config_invalid', `${where}.run must be a non-empty string`, { index, configDir: cwd });
166
+ }
167
+ const timeoutSeconds = entry.timeoutSeconds === undefined ? DEFAULT_GATE_TIMEOUT_SECONDS : entry.timeoutSeconds;
168
+ if (!Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0) {
169
+ throw landingError('config_invalid', `${where}.timeoutSeconds must be a positive number`, { index, configDir: cwd });
170
+ }
171
+ return { name: entry.name, run: entry.run, timeoutSeconds };
172
+ }
173
+
174
+ function isIgnoredByGit(cwd, relPath) {
175
+ const res = runGitRaw(cwd, ['check-ignore', '-q', '--', relPath]);
176
+ if (res.status === 0) return true;
177
+ if (res.status === 1) return false;
178
+ throw landingError('git_failed', `git check-ignore failed for ${relPath}`, { path: relPath, cwd, status: res.status, stderr: res.stderr });
179
+ }
180
+
181
+ // §6.1 calls the entry a glob, so it is matched with git's `:(glob)` magic: `**` then means
182
+ // "zero or more directories" (`src/**/*.js` matches `src/index.js` as well as `src/a/b.js`),
183
+ // whereas a bare pathspec would exclude the zero-directory case. A literal path is unaffected.
184
+ function matchesTrackedFile(cwd, pattern) {
185
+ const res = runGitRaw(cwd, ['ls-files', '--', `:(glob)${pattern}`]);
186
+ if (res.status !== 0) {
187
+ throw landingError('git_failed', `git ls-files failed for ${pattern}`, { path: pattern, cwd, status: res.status, stderr: res.stderr });
188
+ }
189
+ return res.stdout.trim() !== '';
190
+ }
191
+
192
+ // sha256 of the gate array — the second half of the verdict cache key (D-4).
193
+ function gatesHash(gates) {
194
+ return crypto.createHash('sha256').update(JSON.stringify(gates)).digest('hex');
195
+ }
196
+
197
+ // The validated landing config for `cwd` (which may be any directory inside the repo, including
198
+ // a subdirectory or a linked worktree). `configDir` is the directory the answers are relative to:
199
+ // the `.ctm.json` directory when the repo is configured, otherwise the repository toplevel.
200
+ function loadLandingConfig(cwd) {
201
+ const top = toplevel(cwd);
202
+ const found = findProjectConfig(cwd);
203
+ const foundDir = found ? realpathOr(found.dir) : null;
204
+ // A config above the repo is not this repo's config.
205
+ const usable = foundDir && isInside(top, foundDir) ? { dir: foundDir, data: found.data } : null;
206
+ const configDir = usable ? usable.dir : top;
207
+ const raw = usable && usable.data ? usable.data.landing : undefined;
208
+ return validateLanding(raw, {
209
+ configDir,
210
+ readRel: (rel) => readFileSafe(path.join(configDir, rel)),
211
+ matchesTracked: (pattern) => matchesTrackedFile(configDir, pattern),
212
+ targetDefault: () => resolveMainBranch(configDir),
213
+ });
214
+ }
215
+
216
+ // The landing policy the queue enforces: the `landing` object of the `.ctm.json` COMMITTED at the
217
+ // tip of the target branch (repository root), with gate autodetect read from that same commit. A
218
+ // branch can therefore never weaken the gate it is landed under by editing its own `.ctm.json`;
219
+ // a policy change takes effect only once it has itself landed. The submitter's working tree
220
+ // supplies only the target branch name. `cwd` is any directory inside the repository.
221
+ function loadTargetLandingConfig(cwd) {
222
+ const local = loadLandingConfig(cwd);
223
+ const top = toplevel(cwd);
224
+ const rev = `refs/heads/${local.target}`;
225
+ if (!revParseOrNull(top, rev)) {
226
+ throw landingError('target_missing', `target branch ${JSON.stringify(local.target)} does not exist`, { target: local.target });
227
+ }
228
+ const readRel = (rel) => {
229
+ const res = runGitRaw(top, ['show', `${rev}:${rel}`]);
230
+ return res.status === 0 ? res.stdout : null;
231
+ };
232
+ let data = null;
233
+ const text = readRel('.ctm.json');
234
+ if (text !== null) {
235
+ try {
236
+ data = JSON.parse(text);
237
+ } catch (error) {
238
+ throw landingError('config_invalid', `.ctm.json on ${local.target} is not valid JSON: ${error.message}`, { target: local.target, cause: error });
239
+ }
240
+ }
241
+ const raw = data && typeof data === 'object' ? data.landing : undefined;
242
+ const config = validateLanding(raw, {
243
+ configDir: top,
244
+ readRel,
245
+ // Authoring-time check only (land init / doctor validate the working tree); a committed policy
246
+ // is not re-validated against the tree it was committed with.
247
+ matchesTracked: () => true,
248
+ targetDefault: () => local.target,
249
+ });
250
+ // The target named by the committed policy wins only when it agrees; a disagreement means the
251
+ // submitter and the target disagree about where work lands, which is a refusal, not a guess.
252
+ if (config.target !== local.target) {
253
+ throw landingError('config_target_mismatch', `.ctm.json on ${local.target} names target ${JSON.stringify(config.target)}`, {
254
+ local: local.target, committed: config.target,
255
+ });
256
+ }
257
+ return { ...config, policySource: rev };
258
+ }
259
+
260
+ function validateLanding(raw, { configDir, readRel, matchesTracked, targetDefault }) {
261
+ if (raw !== undefined && raw !== null && !isPlainObject(raw)) {
262
+ throw landingError('config_invalid', `landing must be a JSON object in ${configDir}/.ctm.json`, { configDir });
263
+ }
264
+ const landing = raw || {};
265
+ for (const key of Object.keys(landing)) {
266
+ if (!ALLOWED_KEYS.includes(key)) {
267
+ throw landingError('config_unknown_key', `unknown landing key ${JSON.stringify(key)}`, {
268
+ key, configDir, allowed: [...ALLOWED_KEYS],
269
+ });
270
+ }
271
+ }
272
+ const mode = landing.mode === undefined ? 'serial' : landing.mode;
273
+ if (mode !== 'serial') {
274
+ throw landingError('config_mode_unsupported', `landing.mode ${JSON.stringify(mode)} is not supported (only "serial" until WP-8)`, {
275
+ mode, configDir,
276
+ });
277
+ }
278
+ let gates;
279
+ let gatesSource;
280
+ if (landing.gates === undefined) {
281
+ const detected = autodetectGates(configDir, readRel);
282
+ gates = detected.gates;
283
+ gatesSource = detected.gatesSource;
284
+ } else {
285
+ if (!Array.isArray(landing.gates)) {
286
+ throw landingError('config_invalid', 'landing.gates must be an array', { configDir });
287
+ }
288
+ gates = landing.gates.map((entry, index) => normalizeGate(configDir, entry, index));
289
+ gatesSource = 'config';
290
+ }
291
+ const regenerate = normalizePathEntries(landing.regenerate, 'regenerate', { configDir, matchesTracked });
292
+ // WP-0 (design §5 D-2, §9 S-4): `refresh` runs like `regenerate` but on EVERY train — it is how a
293
+ // tree-derived pin (the closure policy's digests) is rebuilt from the merged tree rather than
294
+ // merged as a scalar. Validated identically, so a glob that owns nothing is a config error.
295
+ const refresh = normalizePathEntries(landing.refresh, 'refresh', { configDir, matchesTracked });
296
+ const registries = [];
297
+ if (landing.registries !== undefined) {
298
+ if (!Array.isArray(landing.registries) || !landing.registries.every(isNonEmptyString)) {
299
+ throw landingError('config_invalid', 'landing.registries must be an array of strings', { configDir });
300
+ }
301
+ registries.push(...landing.registries);
302
+ }
303
+ const cachePaths = [];
304
+ if (landing.cachePaths !== undefined) {
305
+ if (!Array.isArray(landing.cachePaths) || !landing.cachePaths.every(isNonEmptyString)) {
306
+ throw landingError('config_invalid', 'landing.cachePaths must be an array of strings', { configDir });
307
+ }
308
+ for (const cachePath of landing.cachePaths) {
309
+ if (!isIgnoredByGit(configDir, cachePath)) {
310
+ throw landingError('config_cache_path_not_ignored', `landing.cachePaths entry ${JSON.stringify(cachePath)} is not git-ignored`, {
311
+ path: cachePath, configDir,
312
+ });
313
+ }
314
+ cachePaths.push(cachePath);
315
+ }
316
+ }
317
+ let guard = DEFAULT_GUARD;
318
+ if (landing.guard !== undefined) {
319
+ if (typeof landing.guard !== 'boolean') {
320
+ throw landingError('config_invalid', 'landing.guard must be a boolean', { configDir });
321
+ }
322
+ guard = landing.guard;
323
+ }
324
+ const triage = normalizeTriage(landing.triage, configDir);
325
+ const batch = normalizeBatch(landing.batch, configDir);
326
+ const publish = normalizePublish(landing.publish, configDir);
327
+ let target;
328
+ if (landing.target !== undefined) {
329
+ if (!isNonEmptyString(landing.target)) {
330
+ throw landingError('config_invalid', 'landing.target must be a non-empty branch name', { configDir });
331
+ }
332
+ target = landing.target;
333
+ } else {
334
+ target = targetDefault();
335
+ }
336
+ return {
337
+ target,
338
+ mode,
339
+ gates,
340
+ gatesSource,
341
+ regenerate,
342
+ refresh,
343
+ registries,
344
+ cachePaths,
345
+ guard,
346
+ triage,
347
+ batch,
348
+ publish,
349
+ configDir,
350
+ };
351
+ }
352
+
353
+ // §6.1: `landing.publish = { remote: str, branch: str, auto: bool, follow: bool, followIntervalMs:
354
+ // int > 0, maxRetrains: int ≥ 0 }`. Absent means "off" and the normalized form is then `null`, which
355
+ // is the one truth every caller (land sync, land doctor, land status, the runner's R-9 hook) reads —
356
+ // there is no second `publishEnabled` boolean to keep in sync. A bad shape is `config_invalid` with
357
+ // the offending `field`, like every other landing field, never a silent clamp.
358
+ //
359
+ // §13.4 R-R1/R-R4 (§13.7 WP-6) adds the resolver half: `resolve` ∈ {session, off}, `resolveAgent` ∈
360
+ // {claude, codex}, `resolveMaxMinutes` ∈ [10, 1440] and `resolveFastGate` — one `landing.gates`
361
+ // entry (`{name, run, timeoutSeconds}`) validated by the very same normalizer. All four have SOURCE
362
+ // defaults (this file), so the normalized form is ALWAYS complete and no caller has to re-derive one.
363
+ function normalizePublish(raw, configDir) {
364
+ if (raw === undefined || raw === null) return null;
365
+ if (!isPlainObject(raw)) {
366
+ throw landingError('config_invalid', 'landing.publish must be an object', { configDir, field: 'publish' });
367
+ }
368
+ for (const key of Object.keys(raw)) {
369
+ if (!PUBLISH_KEYS.includes(key)) {
370
+ throw landingError('config_unknown_key', `unknown landing.publish key ${JSON.stringify(key)}`, {
371
+ key, configDir, field: `publish.${key}`, allowed: [...PUBLISH_KEYS],
372
+ });
373
+ }
374
+ }
375
+ const remote = raw.remote === undefined ? DEFAULT_PUBLISH_REMOTE : raw.remote;
376
+ if (!isNonEmptyString(remote)) {
377
+ throw landingError('config_invalid', 'landing.publish.remote must be a non-empty string', { configDir, field: 'publish.remote', remote });
378
+ }
379
+ const branch = raw.branch === undefined ? DEFAULT_PUBLISH_BRANCH : raw.branch;
380
+ if (!isNonEmptyString(branch)) {
381
+ throw landingError('config_invalid', 'landing.publish.branch must be a non-empty string', { configDir, field: 'publish.branch', branch });
382
+ }
383
+ const bool = (key, fallback) => {
384
+ const value = raw[key] === undefined ? fallback : raw[key];
385
+ if (typeof value !== 'boolean') {
386
+ throw landingError('config_invalid', `landing.publish.${key} must be a boolean`, { configDir, field: `publish.${key}`, value });
387
+ }
388
+ return value;
389
+ };
390
+ const followIntervalMs = raw.followIntervalMs === undefined ? DEFAULT_PUBLISH_FOLLOW_INTERVAL_MS : raw.followIntervalMs;
391
+ if (!Number.isInteger(followIntervalMs) || followIntervalMs <= 0) {
392
+ throw landingError('config_invalid', 'landing.publish.followIntervalMs must be an integer > 0', { configDir, field: 'publish.followIntervalMs', followIntervalMs });
393
+ }
394
+ const maxRetrains = raw.maxRetrains === undefined ? DEFAULT_PUBLISH_MAX_RETRAINS : raw.maxRetrains;
395
+ if (!Number.isInteger(maxRetrains) || maxRetrains < 0) {
396
+ throw landingError('config_invalid', 'landing.publish.maxRetrains must be an integer ≥ 0', { configDir, field: 'publish.maxRetrains', maxRetrains });
397
+ }
398
+ // WP-6 §13.4 R-R1/R-R2 (§13.7 WP-6): the resolver policy. `resolve` and `resolveAgent` are closed
399
+ // enums, `resolveMaxMinutes` is bounded on both sides, and `resolveFastGate` is a gate entry —
400
+ // every default lives in SOURCE (here), so a repository that never mentions them gets the §13
401
+ // behaviour with no `.ctm.json` edit at all.
402
+ const resolveMode = raw.resolve === undefined ? DEFAULT_PUBLISH_RESOLVE : raw.resolve;
403
+ if (!RESOLVE_MODES.includes(resolveMode)) {
404
+ throw landingError('config_invalid', `landing.publish.resolve must be one of ${RESOLVE_MODES.join(', ')}`, { configDir, field: 'publish.resolve', resolve: resolveMode });
405
+ }
406
+ const resolveAgent = raw.resolveAgent === undefined ? DEFAULT_PUBLISH_RESOLVE_AGENT : raw.resolveAgent;
407
+ if (!RESOLVE_AGENTS.includes(resolveAgent)) {
408
+ throw landingError('config_invalid', `landing.publish.resolveAgent must be one of ${RESOLVE_AGENTS.join(', ')}`, { configDir, field: 'publish.resolveAgent', resolveAgent });
409
+ }
410
+ const resolveMaxMinutes = raw.resolveMaxMinutes === undefined ? DEFAULT_PUBLISH_RESOLVE_MAX_MINUTES : raw.resolveMaxMinutes;
411
+ if (!Number.isInteger(resolveMaxMinutes) || resolveMaxMinutes < RESOLVE_MAX_MINUTES_MIN || resolveMaxMinutes > RESOLVE_MAX_MINUTES_MAX) {
412
+ throw landingError('config_invalid', `landing.publish.resolveMaxMinutes must be an integer between ${RESOLVE_MAX_MINUTES_MIN} and ${RESOLVE_MAX_MINUTES_MAX}`, { configDir, field: 'publish.resolveMaxMinutes', resolveMaxMinutes });
413
+ }
414
+ const resolveFastGate = raw.resolveFastGate === undefined
415
+ ? { ...DEFAULT_PUBLISH_RESOLVE_FAST_GATE }
416
+ : normalizeGate(configDir, raw.resolveFastGate, null, 'landing.publish.resolveFastGate');
417
+ return {
418
+ remote,
419
+ branch,
420
+ auto: bool('auto', DEFAULT_PUBLISH_AUTO),
421
+ follow: bool('follow', DEFAULT_PUBLISH_FOLLOW),
422
+ followIntervalMs,
423
+ maxRetrains,
424
+ resolve: resolveMode,
425
+ resolveAgent,
426
+ resolveMaxMinutes,
427
+ resolveFastGate,
428
+ };
429
+ }
430
+
431
+ // §5 D-3 / §6 (WP-1): `landing.batch = { max: int ≥ 1 (8), waitSeconds: int ≥ 0 (0) }`. Absent means
432
+ // the defaults; the normalized form is ALWAYS an object, so the runner never has to ask whether
433
+ // batching is configured. A bad shape is `config_invalid` with the offending `field`, like every other
434
+ // landing field — never a silent clamp, because a window the operator did not ask for is worse than a
435
+ // refusal they can read.
436
+ function normalizeBatch(raw, configDir) {
437
+ if (raw === undefined) return { max: DEFAULT_BATCH_MAX, waitSeconds: DEFAULT_BATCH_WAIT_SECONDS };
438
+ if (!isPlainObject(raw)) {
439
+ throw landingError('config_invalid', 'landing.batch must be an object', { configDir, field: 'batch' });
440
+ }
441
+ for (const key of Object.keys(raw)) {
442
+ if (!BATCH_KEYS.includes(key)) {
443
+ throw landingError('config_unknown_key', `unknown landing.batch key ${JSON.stringify(key)}`, {
444
+ key, configDir, field: `batch.${key}`, allowed: [...BATCH_KEYS],
445
+ });
446
+ }
447
+ }
448
+ const max = raw.max === undefined ? DEFAULT_BATCH_MAX : raw.max;
449
+ if (!Number.isInteger(max) || max < 1) {
450
+ throw landingError('config_invalid', 'landing.batch.max must be an integer ≥ 1', { configDir, field: 'batch.max', max });
451
+ }
452
+ const waitSeconds = raw.waitSeconds === undefined ? DEFAULT_BATCH_WAIT_SECONDS : raw.waitSeconds;
453
+ if (!Number.isInteger(waitSeconds) || waitSeconds < 0) {
454
+ throw landingError('config_invalid', 'landing.batch.waitSeconds must be an integer ≥ 0', { configDir, field: 'batch.waitSeconds', waitSeconds });
455
+ }
456
+ return { max, waitSeconds };
457
+ }
458
+
459
+ // §5 D-7 / §9 S-4 (WP-2): the base-rerun budget. Absent means the default; `false` is the documented
460
+ // way to turn the pass off entirely (`maxFiles: 0`, which the runner reads as "never rerun"), so a
461
+ // repository can opt out without knowing the default. The normalized form is ALWAYS an object, so
462
+ // the runner never has to ask whether triage is configured.
463
+ function normalizeTriage(raw, configDir) {
464
+ if (raw === undefined) return { maxFiles: DEFAULT_TRIAGE_MAX_FILES };
465
+ if (raw === false) return { maxFiles: 0 };
466
+ if (!isPlainObject(raw)) {
467
+ throw landingError('config_invalid', 'landing.triage must be an object or false', { configDir });
468
+ }
469
+ for (const key of Object.keys(raw)) {
470
+ if (!TRIAGE_KEYS.includes(key)) {
471
+ throw landingError('config_unknown_key', `unknown landing.triage key ${JSON.stringify(key)}`, {
472
+ key, configDir, allowed: [...TRIAGE_KEYS],
473
+ });
474
+ }
475
+ }
476
+ const maxFiles = raw.maxFiles === undefined ? DEFAULT_TRIAGE_MAX_FILES : raw.maxFiles;
477
+ if (!Number.isInteger(maxFiles) || maxFiles < 0) {
478
+ throw landingError('config_invalid', 'landing.triage.maxFiles must be an integer ≥ 0', { configDir, maxFiles });
479
+ }
480
+ return { maxFiles };
481
+ }
482
+
483
+ // `landing.regenerate` and `landing.refresh` share one shape — an array of { paths, run } entries in
484
+ // which every glob must match at least one tracked path. `label` names the key in the error, so a
485
+ // refusal says exactly which block is wrong.
486
+ function normalizePathEntries(raw, label, { configDir, matchesTracked }) {
487
+ const entries = [];
488
+ if (raw === undefined) return entries;
489
+ if (!Array.isArray(raw)) {
490
+ throw landingError('config_invalid', `landing.${label} must be an array`, { configDir });
491
+ }
492
+ raw.forEach((entry, index) => {
493
+ if (!isPlainObject(entry) || !Array.isArray(entry.paths) || !entry.paths.length || !entry.paths.every(isNonEmptyString)) {
494
+ throw landingError('config_invalid', `landing.${label}[${index}].paths must be a non-empty array of strings`, { index, configDir });
495
+ }
496
+ if (!isNonEmptyString(entry.run)) {
497
+ throw landingError('config_invalid', `landing.${label}[${index}].run must be a non-empty string`, { index, configDir });
498
+ }
499
+ for (const pattern of entry.paths) {
500
+ if (!matchesTracked(pattern)) {
501
+ throw landingError(`config_${label}_unmatched`, `landing.${label}[${index}].paths entry ${JSON.stringify(pattern)} matches no tracked file`, {
502
+ path: pattern, index, configDir,
503
+ });
504
+ }
505
+ }
506
+ entries.push({ paths: entry.paths.slice(), run: entry.run });
507
+ });
508
+ return entries;
509
+ }
510
+
511
+ module.exports = {
512
+ ALLOWED_KEYS,
513
+ DEFAULT_GATE_TIMEOUT_SECONDS,
514
+ DEFAULT_GUARD,
515
+ DEFAULT_TRIAGE_MAX_FILES,
516
+ DEFAULT_BATCH_MAX,
517
+ DEFAULT_BATCH_WAIT_SECONDS,
518
+ PUBLISH_KEYS,
519
+ DEFAULT_PUBLISH_REMOTE,
520
+ DEFAULT_PUBLISH_BRANCH,
521
+ DEFAULT_PUBLISH_AUTO,
522
+ DEFAULT_PUBLISH_FOLLOW,
523
+ DEFAULT_PUBLISH_FOLLOW_INTERVAL_MS,
524
+ DEFAULT_PUBLISH_MAX_RETRAINS,
525
+ DEFAULT_PUBLISH_RESOLVE,
526
+ DEFAULT_PUBLISH_RESOLVE_AGENT,
527
+ DEFAULT_PUBLISH_RESOLVE_MAX_MINUTES,
528
+ DEFAULT_PUBLISH_RESOLVE_FAST_GATE,
529
+ RESOLVE_MODES,
530
+ RESOLVE_AGENTS,
531
+ loadLandingConfig,
532
+ loadTargetLandingConfig,
533
+ gatesHash,
534
+ autodetectGates,
535
+ resolveMainBranch,
536
+ };