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,49 @@
1
+ 'use strict';
2
+ // WP-1 (docs/landing-train-member-withdraw-and-gate-fail-fast-2026-10-31.html §5 D-2/D-6, §6, §9
3
+ // S-1/S-2): the two predicates the member-withdraw move needs. They live here rather than in
4
+ // bin/land.js, which sits exactly at its file-size ceiling (lint/file-size-baseline.json), beside the
5
+ // record they read (`stopRequest`, lib/landing/queue.js requestStop — §4 "Stop requests").
6
+
7
+ // D-2: should the heartbeat abort this train's controller NOW?
8
+ //
9
+ // `members` are the job records of the train in flight, as read from disk (bin/land.js reads them
10
+ // through `queue.readJob`). A null entry — a job file that vanished, or a read that failed — is not a
11
+ // member and is ignored, so one unreadable file can neither make a train look stopped nor keep a
12
+ // stopped one running.
13
+ //
14
+ // * >= 2 members, at least one of them carrying a `kind: 'cancel'` request: the train's verdict is
15
+ // already void — a PASS would land code its owner has withdrawn (I-4: the chain was built from
16
+ // every member, lib/landing/train.js) and a FAIL would bisect the innocent — so the gate is
17
+ // aborted at once (P-1: a group's result is void once its content changes).
18
+ // * every member carries a request of some kind: today's rule, kept for the all-preempt case. A
19
+ // singleton's one member satisfies it trivially, so the serial runner behaves exactly as before.
20
+ //
21
+ // Only members still `in_progress` are in flight. batch-runner.runTrain bisects INSIDE one take, so the
22
+ // runner's jobIds keep the whole original train while the requeued half sits `queued`; counting that
23
+ // half kept a singleton half's own cancel from ever aborting it (observed 2026-10-31, attempt 2 of
24
+ // batch b-01m697xcw391a8j042f3d5xvp1: `land cancel --force` recorded, gate ran on).
25
+ function shouldAbortTrain(members) {
26
+ const present = (Array.isArray(members) ? members : []).filter((job) => Boolean(job) && job.state === 'in_progress');
27
+ if (!present.length) return false;
28
+ if (present.length >= 2 && present.some((job) => job.stopRequest && job.stopRequest.kind === 'cancel')) return true;
29
+ return present.every((job) => Boolean(job.stopRequest));
30
+ }
31
+
32
+ // D-6: is `job` in flight as a member of a RUNNING train of two or more? The lease record is what
33
+ // says a train is running — the runner refreshes its `jobIds` on every heartbeat (§9 S-6) — so
34
+ // `land cancel` may take the withdraw path only while the runner advertises this job as one of its
35
+ // members. A singleton job (no batch, or a batch of one) is never a batch member, and the refusal it
36
+ // keeps is the one that protects a running gate of its own (`--force`).
37
+ //
38
+ // R-3: `jobIds` is additive. A lease written by an older runner has no `jobIds`, and this answers
39
+ // false for it — that runner predates batch members, would not honour the request, and would clobber
40
+ // whatever state we wrote, which is exactly the refusal `cmdCancel` keeps for it.
41
+ function isBatchMemberInFlight(job, leaseRecord) {
42
+ if (!job || !leaseRecord) return false;
43
+ const members = job.batch && Array.isArray(job.batch.members) ? job.batch.members : null;
44
+ if (!members || members.length < 2) return false;
45
+ const jobIds = Array.isArray(leaseRecord.jobIds) ? leaseRecord.jobIds : null;
46
+ return Boolean(jobIds) && jobIds.includes(job.id);
47
+ }
48
+
49
+ module.exports = { shouldAbortTrain, isBatchMemberInFlight };
@@ -0,0 +1,475 @@
1
+ 'use strict';
2
+ // WP-0/WP-1, the CLI half (docs/fleet-origin-main-sync-skill-2026-10-31.html §6.1-§6.3, §7, §8
3
+ // WP-0/WP-1): `land sync`, the queue side of a sync job, and the four origin doctor checks.
4
+ //
5
+ // This is a PURE MOVE out of bin/land.js (that file is under a frozen size ceiling). land.js keeps
6
+ // owning the process-level helpers — `progress`/`emit*`, the detached runner spawn, the guard
7
+ // renderer/reader, and the git wrappers — and hands them over ONCE through `configure()`. Nothing in
8
+ // here is a second implementation of any of them, and no behaviour changed with the move.
9
+ //
10
+ // §5 R-3 keeps its shape across the move: the ONE publish site is `sync.pushMain` in
11
+ // lib/landing/sync.js; the only other `git push` reachable from this module is doctor's
12
+ // `--dry-run --porcelain` credential probe (AC-0c), which never transfers a ref.
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ const { runGitRaw, revParseOrNull } = require('./git');
18
+ const { strFlag } = require('../env-flags');
19
+ const lease = require('./lease');
20
+ const queue = require('./queue');
21
+ const train = require('./train');
22
+ const sync = require('./sync');
23
+ const { loadLandingConfig, loadTargetLandingConfig } = require('./config');
24
+
25
+ // Injected by bin/land.js at load time (see the `syncCli.configure({...})` call there). Held as plain
26
+ // bindings rather than a `deps.` prefix so the moved function bodies stay byte-comparable with the
27
+ // file they came from — which is the whole point of a pure move.
28
+ let progress = () => {};
29
+ let emitLine = () => {};
30
+ let emitJson = () => {};
31
+ let emitJsonOrLine = () => {};
32
+ let delay = () => Promise.resolve();
33
+ let context = null;
34
+ let branchRef = null;
35
+ let spawnRunner = null;
36
+ let readGuardState = null;
37
+ let CONTRACT = 1;
38
+ let WAIT_TIMEOUT_MS = 4 * 60 * 60 * 1000;
39
+ let POLL_MS = 200;
40
+
41
+ // §6.2: `land sync [--wait] [--pull-only] [--json]`. The publish policy is read from the TARGET tree
42
+ // (`loadTargetLandingConfig`), exactly like the gate policy, so a branch cannot weaken it. `--wait`
43
+ // is accepted and implied: the verb is already synchronous.
44
+ async function cmdSync(opts, cwd) {
45
+ const ctx = context(cwd);
46
+ const config = loadTargetLandingConfig(cwd);
47
+ const payload = await sync.syncOnce({
48
+ cwd,
49
+ common: ctx.common,
50
+ config,
51
+ pullOnly: opts.flags.has('pull-only'),
52
+ runGit: sync.gitRunner(cwd),
53
+ runTrain: (args) => runSyncTrain(ctx, config, args),
54
+ followRetry: (jobId) => waitForSyncJob(ctx, jobId),
55
+ });
56
+ sync.recordSyncVerdict(ctx.common, payload.verdict, {
57
+ jobId: payload.jobId || null,
58
+ attempts: payload.attempts || 1,
59
+ restart: payload.restart || null,
60
+ });
61
+ emitJsonOrLine(opts, payload, syncHumanLine(payload));
62
+ return sync.exitCodeForVerdict(payload.verdict);
63
+ }
64
+
65
+ // §6.2: the human line says the verdict, what origin holds, and — for the two contested verdicts —
66
+ // the one thing a reader needs (retry later, or read `land inspect`).
67
+ function syncHumanLine(payload) {
68
+ const where = payload.remote && payload.branch ? ` (${payload.remote}/${payload.branch})` : '';
69
+ const attempts = payload.attempts > 1 ? ` after ${payload.attempts} attempts` : '';
70
+ const hint = payload.hint ? `; run: ${payload.hint}` : '';
71
+ const id = payload.jobId ? ` [job ${payload.jobId}]` : '';
72
+ return `sync: ${payload.verdict}${where}${attempts}${id}${hint}`;
73
+ }
74
+
75
+ // §6.3 step 5 (CLI side): the sync job's train runs in the queue like any other job; this process
76
+ // waits for its terminal state and reads the push verdict `finishSyncJob` wrote on the record.
77
+ async function runSyncTrain(ctx, config, { tip, attempt }) {
78
+ const job = syncJobRecord(ctx, config, { tip, attempt });
79
+ queue.enqueue(ctx.root, job);
80
+ ensureRunner(ctx);
81
+ return waitForSyncJob(ctx, job.id);
82
+ }
83
+
84
+ // A sync job settles in TWO steps: the train lands (the queue record flips to `landed`) and only then
85
+ // does the runner push and write `job.sync` (`finishSyncJob`). Waiting on the terminal state alone
86
+ // would read the record inside that window and report a missing verdict, so this waits for the verdict
87
+ // itself. A terminal state is only trusted once the runner that was going to write it is gone — that
88
+ // case really is `sync_verdict_missing` and is reported, not waited out.
89
+ const SYNC_ORPHAN_GRACE_MS = 120000;
90
+
91
+ async function waitForSyncJob(ctx, jobId) {
92
+ const deadline = Date.now() + WAIT_TIMEOUT_MS;
93
+ let orphanedSince = null;
94
+ for (;;) {
95
+ const job = queue.readJob(ctx.root, jobId);
96
+ if (job && job.sync) return { jobId, state: job.state, reason: job.reason || null, sync: job.sync, waited: true };
97
+ const holder = lease.read(ctx.root);
98
+ const live = Boolean(holder) && !lease.isDead(holder);
99
+ if (job && queue.TERMINAL_STATES.includes(job.state) && !(job.state === 'landed' && live)) {
100
+ // Settled without a verdict and nobody is left to write one: a real `sync_verdict_missing`.
101
+ return { jobId, state: job.state, reason: job.reason || null, sync: null, waited: true };
102
+ }
103
+ if (live) orphanedSince = null;
104
+ else {
105
+ if (orphanedSince === null) orphanedSince = Date.now();
106
+ // Nothing is draining the queue (the runner died, or never started): report rather than hang.
107
+ if (Date.now() - orphanedSince > SYNC_ORPHAN_GRACE_MS) {
108
+ return { jobId, state: job ? job.state : 'queued', reason: job ? job.reason || null : null, sync: null, waited: true };
109
+ }
110
+ }
111
+ const remaining = deadline - Date.now();
112
+ if (remaining <= 0) return { jobId, state: job ? job.state : 'queued', reason: null, sync: null, waited: true };
113
+ await delay(Math.min(POLL_MS, remaining)); // eslint-disable-line no-await-in-loop
114
+ }
115
+ }
116
+
117
+ // D-2: a sync job is an ordinary queue job (R-3: it is the job that publishes), so it is submitted
118
+ // exactly like one — enqueued under the mutex, then a detached runner started if none is live.
119
+ function syncJobRecord(ctx, config, { tip, attempt }) {
120
+ const publish = config.publish;
121
+ return {
122
+ contract: CONTRACT,
123
+ id: queue.newJobId(),
124
+ // WP-1: the one marker that says "this job publishes origin" — `afterTrainLanded` reads it, and
125
+ // it is what stops a sync job from triggering another sync (R-9).
126
+ kind: 'sync',
127
+ syncAttempt: attempt,
128
+ repo: ctx.common,
129
+ branch: sync.ORIGIN_BRANCH,
130
+ tip,
131
+ title: `origin/${publish.branch} sync (attempt ${attempt})`,
132
+ submittedBy: { session: strFlag('CTM_SESSION_ID') || null, pid: process.pid, cwd: ctx.cwd },
133
+ state: 'queued',
134
+ reason: null,
135
+ priority: 'normal',
136
+ priorityHistory: [],
137
+ preemptions: 0,
138
+ base: null,
139
+ train: null,
140
+ tree: null,
141
+ verdict: null,
142
+ conflictPaths: [],
143
+ conflictPreview: null,
144
+ overlapWithTarget: [],
145
+ policySource: config.policySource || null,
146
+ runnerPid: null,
147
+ timestamps: { queued: queue.nowIso() },
148
+ gateLog: null,
149
+ };
150
+ }
151
+
152
+ function ensureRunner(ctx) {
153
+ const holder = lease.read(ctx.root);
154
+ if (holder && !lease.isDead(holder)) return { runner: 'other', pid: holder.pid };
155
+ const started = spawnRunner(ctx);
156
+ return { runner: 'self', pid: started ? started.pid : null };
157
+ }
158
+
159
+ // §6.3 step 5, second half (R-3): the push of the exact commit the train gated, run once the sync
160
+ // job has landed. A rejected push is a CAS miss (R-4): fetch, materialise the new origin tip and
161
+ // enqueue ONE retry train, bounded by `publish.maxRetrains` extra trains; any other failure is
162
+ // `publish_failed` with git's stderr and is never retried.
163
+ async function finishSyncJob(ctx, job) {
164
+ const config = loadTargetLandingConfig(ctx.cwd);
165
+ const publish = config.publish;
166
+ if (!publish) return null;
167
+ const runGit = sync.gitRunner(ctx.cwd);
168
+ const attempt = Number.isInteger(job.syncAttempt) ? job.syncAttempt : 1;
169
+ const sha = revParseOrNull(ctx.cwd, branchRef(config.target));
170
+ if (!sha) {
171
+ queue.updateJob(ctx.root, job.id, { sync: { verdict: 'publish_failed', at: queue.nowIso(), attempt, stderr: `${config.target} has no tip` } });
172
+ sync.recordSyncVerdict(ctx.common, 'publish_failed', { jobId: job.id, attempts: attempt });
173
+ return null;
174
+ }
175
+ const push = sync.pushMain(runGit, { remote: publish.remote, branch: publish.branch, sha });
176
+ const record = (verdict, extra = {}) => {
177
+ queue.updateJob(ctx.root, job.id, { sync: { verdict, at: queue.nowIso(), attempt, tip: sha, ...extra } });
178
+ sync.recordSyncVerdict(ctx.common, verdict, { jobId: job.id, attempts: attempt, restart: extra.restart || null });
179
+ return verdict;
180
+ };
181
+ if (push.outcome === 'ok') {
182
+ // §8 WP-2b: the train moved main and origin now holds it — this box converges onto its own build.
183
+ const restart = await sync.scheduleRestartForTip({ from: job.tip || null, to: sha, common: ctx.common });
184
+ progress(`sync: published ${sha.slice(0, 12)} to ${publish.remote}/${publish.branch}`);
185
+ return record('published', { restart });
186
+ }
187
+ if (push.outcome === 'up_to_date') { progress(`sync: ${publish.remote}/${publish.branch} already at ${sha.slice(0, 12)}`); return record('in_sync'); }
188
+ if (push.outcome === 'rejected' && attempt <= publish.maxRetrains) {
189
+ // R-4: origin moved between the fetch that built this train and the push. One more train.
190
+ const fetched = sync.fetchOrigin(runGit, publish);
191
+ const originTip = fetched.ok ? sync.revParseVia(runGit, sync.remoteRef(publish.remote, publish.branch)) : null;
192
+ if (originTip) {
193
+ sync.materializeOrigin(runGit, publish);
194
+ const retry = syncJobRecord(ctx, config, { tip: originTip, attempt: attempt + 1 });
195
+ queue.enqueue(ctx.root, retry);
196
+ progress(`sync: push rejected (origin moved); retraining as job ${retry.id} (attempt ${attempt + 1})`);
197
+ return record('retraining', { retryJobId: retry.id, stderr: push.stderr });
198
+ }
199
+ return record('publish_failed', { stderr: push.stderr || `cannot re-read ${sync.remoteRef(publish.remote, publish.branch)}` });
200
+ }
201
+ if (push.outcome === 'rejected') {
202
+ progress(`sync: publish contended after ${attempt} attempt(s)`);
203
+ return record('publish_contended', { stderr: push.stderr });
204
+ }
205
+ progress(`sync: push failed: ${push.stderr || `git push exited ${push.status}`}`);
206
+ return record('publish_failed', { stderr: push.stderr });
207
+ }
208
+
209
+ // §5 R-9 (S-7): the runner-side hook after a train lands. A landed `kind:"sync"` job publishes
210
+ // itself; an ordinary landing runs the §6.3 step-1..5 logic once when `publish.auto` is on, and a
211
+ // sync job never triggers another (`auto` is what stops `land sync` from recursing). Errors are
212
+ // reported, never thrown: a publish failure must not turn a landed job into a crashed runner.
213
+ async function afterTrainLanded(ctx, jobs) {
214
+ const landed = (Array.isArray(jobs) ? jobs : []).filter((job) => job && job.state === 'landed');
215
+ if (!landed.length) return null;
216
+ const syncJob = landed.find((job) => job.kind === 'sync');
217
+ if (syncJob) return finishSyncJob(ctx, syncJob);
218
+ let config;
219
+ try {
220
+ config = loadTargetLandingConfig(ctx.cwd);
221
+ } catch (error) {
222
+ /* REPORT: an unreadable policy is the job's own refusal to make; the landing stands */
223
+ return null;
224
+ }
225
+ if (!config.publish) return null;
226
+ // §5 R-7: every move of main schedules an idle restart — an ordinary landing moves main too, and
227
+ // auto-publish only PUSHES it (`pushed` never moves main, so it schedules nothing). Observed
228
+ // 2026-10-31: job 01m69v5chb9nngfe landed and published 5ad132e4d4 while the hub kept running
229
+ // ae6b643adf with sync-state restart:null. The outcome rides on each landed job's record.
230
+ const landedTip = revParseOrNull(ctx.cwd, branchRef(config.target));
231
+ if (landedTip) {
232
+ const restart = await sync.scheduleRestartForTip({ from: null, to: landedTip, common: ctx.common });
233
+ for (const job of landed) queue.updateJob(ctx.root, job.id, { restart: { tip: landedTip, ...(restart || { spawned: false, reason: 'none' }) } });
234
+ }
235
+ if (!config.publish.auto) return null;
236
+ try {
237
+ const payload = await sync.syncOnce({
238
+ cwd: ctx.cwd,
239
+ common: ctx.common,
240
+ config,
241
+ pullOnly: false,
242
+ runGit: sync.gitRunner(ctx.cwd),
243
+ // The runner cannot block on its own queue: enqueue the train and let the next drain
244
+ // iteration run it (its landing calls this function again for the push).
245
+ runTrain: async ({ tip, attempt }) => {
246
+ const job = syncJobRecord(ctx, config, { tip, attempt });
247
+ queue.enqueue(ctx.root, job);
248
+ progress(`sync: enqueued ${config.publish.remote}/${config.publish.branch} publish job ${job.id} (attempt ${attempt})`);
249
+ return { jobId: job.id, state: 'queued', reason: null, waited: false };
250
+ },
251
+ });
252
+ if (payload.verdict !== 'publishing' && payload.verdict !== 'in_sync') {
253
+ sync.recordSyncVerdict(ctx.common, payload.verdict, { attempts: payload.attempts || 1, restart: payload.restart || null });
254
+ }
255
+ return payload;
256
+ } catch (error) {
257
+ progress(`sync: auto-publish skipped (${typeof error.code === 'string' ? error.code : 'error'}: ${error.message})`);
258
+ return null;
259
+ }
260
+ }
261
+
262
+ // --- WP-1 §6.2: the origin half of `land status` --------------------------------------------------
263
+
264
+ // Ahead/behind against the LOCAL tracking ref (no fetch: `land status` stays a read verb) plus the
265
+ // last sync verdict from `landing/sync-state.json`.
266
+ function statusOrigin(dir, common, config) {
267
+ return sync.originStatus({
268
+ runGit: sync.gitRunner(dir),
269
+ target: config ? config.target : null,
270
+ config,
271
+ common,
272
+ });
273
+ }
274
+
275
+ // The human line, printed only for a repository that opted in — an unconfigured repo's status stays
276
+ // byte-identical to what it printed before this change.
277
+ function originStatusLine(config, origin) {
278
+ if (!config || !config.publish) return null;
279
+ const ahead = origin.ahead === null ? '?' : origin.ahead;
280
+ const behind = origin.behind === null ? '?' : origin.behind;
281
+ const last = origin.lastSync ? `, last sync ${origin.lastSync.verdict}` : '';
282
+ return `origin: ${config.publish.remote}/${config.publish.branch} ahead ${ahead} behind ${behind}${last}`;
283
+ }
284
+
285
+ // --- WP-0: the origin doctor checks (§7, §8 WP-0, §9 S-3) ----------------------------------------
286
+
287
+ const REQUIRED_HOOKS = Object.freeze(['pre-commit', 'commit-msg']);
288
+
289
+ function hooksState(cwd) {
290
+ const res = runGitRaw(cwd, ['rev-parse', '--path-format=absolute', '--git-path', 'hooks']);
291
+ if (res.status !== 0) return { ok: false, detail: 'cannot resolve the hooks dir' };
292
+ const dir = res.stdout.trim();
293
+ const missing = REQUIRED_HOOKS.filter((name) => {
294
+ try {
295
+ fs.accessSync(path.join(dir, name), fs.constants.X_OK);
296
+ return false;
297
+ } catch (error) {
298
+ /* expected: the hook is absent or not executable — both are "this box runs no gate" */
299
+ return true;
300
+ }
301
+ });
302
+ return { ok: missing.length === 0, detail: missing.length ? `missing ${missing.join(', ')} in ${dir}` : dir };
303
+ }
304
+
305
+ function remoteState(cwd, remote) {
306
+ const res = runGitRaw(cwd, ['remote']);
307
+ const remotes = res.status === 0 ? res.stdout.split('\n').map((line) => line.trim()).filter(Boolean) : [];
308
+ return { ok: remotes.includes(remote), detail: remotes.includes(remote) ? remote : `remote ${JSON.stringify(remote)} is not configured (have: ${remotes.join(', ') || 'none'})` };
309
+ }
310
+
311
+ // AC-0c: `git push --dry-run` with the §6.3 no-prompt env, so a box with no credentials reports
312
+ // `push-auth: FAILED` instead of opening a browser or blocking on a prompt.
313
+ function pushAuthState(cwd, publish, target) {
314
+ const sha = revParseOrNull(cwd, branchRef(target));
315
+ if (!sha) return { ok: false, detail: `cannot resolve ${target}` };
316
+ const res = runGitRaw(cwd, ['push', '--dry-run', '--porcelain', publish.remote, `${sha}:refs/heads/${publish.branch}`], { env: sync.NO_PROMPT_ENV });
317
+ if (res.status === 0) return { ok: true, detail: `${publish.remote}/${publish.branch}` };
318
+ // A `[rejected]` ref line means git reached the remote, authenticated and read its refs; only the
319
+ // ref STATE refused the update (local main is behind or diverged from origin — exactly what
320
+ // `land sync` resolves). Observed 2026-10-31 on the hub and the MacBook Pro: a diverged main made
321
+ // this probe print "push-auth: FAILED" while a dry-run push of origin's own tip was "up to date".
322
+ const refLine = String(res.stdout || '').split('\n').find((line) => line.startsWith('!\t'));
323
+ if (refLine && /\[rejected\]/.test(refLine)) {
324
+ const why = (refLine.match(/\[rejected\]\s*\(([^)]*)\)/) || [])[1] || 'rejected';
325
+ return { ok: true, detail: `${publish.remote}/${publish.branch} (credentials ok; local ${target} is not a fast-forward: ${why} — land sync resolves it)` };
326
+ }
327
+ const first = String(res.stderr || res.stdout || '').trim().split('\n')[0];
328
+ return { ok: false, detail: first || `git push --dry-run exited ${res.status}` };
329
+ }
330
+
331
+ // Only reported when the repository opted in: a repo with no `landing.publish` has no origin contract
332
+ // to prove, and four FAILED lines on every other user's install would be noise, not signal.
333
+ function originChecks(ctx, config) {
334
+ let publish = null;
335
+ try {
336
+ publish = loadTargetLandingConfig(ctx.cwd).publish;
337
+ } catch (error) {
338
+ /* expected: an unreadable target policy is already a doctor finding above (or the repository
339
+ never opted into publishing) — the origin half then reports "not configured", never a throw */
340
+ }
341
+ if (!publish) return { lines: [], problems: 0, payload: { configured: false, checks: null } };
342
+ const lines = [];
343
+ const checks = {};
344
+ let problems = 0;
345
+ const record = (name, state) => {
346
+ checks[name] = { ok: state.ok, detail: state.detail || null };
347
+ lines.push(`origin ${name}: ${state.ok ? 'ok' : `FAILED (${state.detail})`}`);
348
+ if (!state.ok) problems += 1;
349
+ };
350
+ record('hooks', hooksState(ctx.cwd));
351
+ const guard = readGuardState(ctx.common, config ? config.target : null);
352
+ record('guard', { ok: guard === 'present', detail: guard });
353
+ record('remote', remoteState(ctx.cwd, publish.remote));
354
+ record('push-auth', pushAuthState(ctx.cwd, publish, config ? config.target : null));
355
+ return { lines, problems, payload: { configured: true, remote: publish.remote, branch: publish.branch, checks } };
356
+ }
357
+
358
+ function cmdDoctor(opts, cwd) {
359
+ // WP-0 (AC-0a): `--json` emits the findings as ONE payload; the prose lines are the human form.
360
+ const jsonMode = opts.flags.has('json');
361
+ const say = jsonMode ? () => {} : emitLine;
362
+ const ctx = context(cwd);
363
+ let problems = 0;
364
+ say(`repo: ${ctx.common}`);
365
+ say(`state: ${ctx.root}`);
366
+ try {
367
+ fs.accessSync(ctx.root, fs.constants.W_OK);
368
+ say('state dir: writable');
369
+ } catch (error) {
370
+ /* expected: the state directory has not been created yet (nothing has been submitted) or is
371
+ not writable — both are reported below as a doctor finding, never thrown */
372
+ if (fs.existsSync(ctx.root)) {
373
+ say(`state dir: NOT writable (${error.code})`);
374
+ problems += 1;
375
+ } else {
376
+ say('state dir: not created yet (nothing queued)');
377
+ }
378
+ }
379
+ let config = null;
380
+ try {
381
+ config = loadLandingConfig(cwd);
382
+ say(`config: ok (target ${config.target}, mode ${config.mode}, ${config.gates.length} gate(s) from ${config.gatesSource})`);
383
+ } catch (error) {
384
+ say(`config: ${typeof error.code === 'string' ? error.code : 'invalid'}: ${error.message}`);
385
+ problems += 1;
386
+ }
387
+ // WP-6 E-1: the reference-transaction fence. `present` (ours, for the configured target) is never
388
+ // a problem; `missing` / `foreign` are one only where the repository asked for the fence
389
+ // (`.ctm.json` `landing.guard: true`).
390
+ const guardState = readGuardState(ctx.common, config ? config.target : null);
391
+ say(`guard: ${guardState}`);
392
+ // A repository that requires the fence is unhealthy without OUR hook on the target: absent and
393
+ // foreign (someone else's hook, or ours baked for another branch) both leave it unfenced.
394
+ if (guardState !== 'present' && config !== null && config.guard === true) problems += 1;
395
+ // WP-4 (§7 "Guard"): a config that leaves the fence off can have main moved by hand (I-2), which
396
+ // discards whatever the queue gated. A warning line only — doctor has no warning channel, so the
397
+ // exit code is unchanged; only `problems` moves it.
398
+ if (config !== null && config.guard !== true) say('guard: disabled in .ctm.json (landing.guard: false) — main can be moved outside the queue');
399
+ const holder = lease.read(ctx.root);
400
+ if (!holder) {
401
+ say('lease: none');
402
+ } else {
403
+ const dead = lease.isDead(holder);
404
+ say(`lease: pid ${holder.pid} ${dead ? 'dead (the next submit reaps it)' : 'alive'}${holder.jobId ? ` job ${holder.jobId}` : ''}`);
405
+ }
406
+ // D-8: the revisit trigger for a floor, measured rather than guessed — a normal job that waited
407
+ // more than 180 min while a higher-ranked job started inside that window. Informational: it is not
408
+ // a finding, so it never counts toward `problems`.
409
+ try {
410
+ say(`priority: ${queue.priorityStarvationCount(ctx.root)} normal job(s) waited > 180 min behind a higher-ranked job (14 days)`);
411
+ } catch (error) {
412
+ /* expected: the job files are the only input, and an unreadable one (which readJob already
413
+ treats as "no job") is not a doctor failure — report the count as unknown rather than
414
+ failing the whole check */
415
+ say(`priority: unreadable (${error.message})`);
416
+ }
417
+ try {
418
+ const trainsRoot = train.trainsRoot(cwd, ctx.common);
419
+ say(`trains: ${trainsRoot.dir} (${trainsRoot.source})`);
420
+ } catch (error) {
421
+ /* expected: `git check-ignore` could not answer for the repository root — doctor reports the
422
+ fallback it would use rather than failing the whole check */
423
+ say(`trains: ${path.join(ctx.common, 'landing', 'trains')} (common-dir, probe failed: ${error.message})`);
424
+ }
425
+ // WP-0: the four origin checks. `--json` emits the same findings as a payload (AC-0a), so the
426
+ // Machines card can render a box's doctor verdict without parsing prose.
427
+ const origin = originChecks(ctx, config);
428
+ for (const line of origin.lines) say(line);
429
+ problems += origin.problems;
430
+ if (opts.flags.has('json')) {
431
+ emitJson({ contract: CONTRACT, repo: ctx.common, state: ctx.root, problems, origin: origin.payload });
432
+ }
433
+ return problems ? 1 : 0;
434
+ }
435
+
436
+ // bin/land.js calls this once, at load, with its own process-level helpers. Required — a caller that
437
+ // forgets it gets a module whose emitter is a no-op rather than a thrown TypeError mid-command.
438
+ function configure(injected) {
439
+ ({
440
+ progress,
441
+ emitLine,
442
+ emitJson,
443
+ emitJsonOrLine,
444
+ delay,
445
+ context,
446
+ branchRef,
447
+ spawnRunner,
448
+ readGuardState,
449
+ CONTRACT,
450
+ WAIT_TIMEOUT_MS,
451
+ POLL_MS,
452
+ } = injected);
453
+ return module.exports;
454
+ }
455
+
456
+ module.exports = {
457
+ configure,
458
+ cmdSync,
459
+ cmdDoctor,
460
+ syncHumanLine,
461
+ runSyncTrain,
462
+ waitForSyncJob,
463
+ syncJobRecord,
464
+ ensureRunner,
465
+ finishSyncJob,
466
+ afterTrainLanded,
467
+ statusOrigin,
468
+ originStatusLine,
469
+ hooksState,
470
+ remoteState,
471
+ pushAuthState,
472
+ originChecks,
473
+ SYNC_ORPHAN_GRACE_MS,
474
+ REQUIRED_HOOKS,
475
+ };