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,436 @@
1
+ 'use strict';
2
+
3
+ // WP-2 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-1/D-2/D-5, §6.2, §6.3): the BOX-side
4
+ // bundle ingress — the three routes a hub calls with its peer bearer to hand this machine the skills
5
+ // and plugins it must run a forwarded session with.
6
+ //
7
+ // POST /api/agent-bundles/missing { blobs: [hex…] } -> 200 { missing }
8
+ // POST /api/agent-bundles/blobs { blobs: [{hash, data(base64)}] }
9
+ // -> 200 { stored, present } (WP-4/§6.2, D-6)
10
+ // PUT /api/agent-bundles/blobs/<hex> raw bytes -> 201 { stored:true } | 200 { stored:false }
11
+ // PUT /api/agent-bundles/manifests/<treeHash> JSON -> 201 { treeHash, materialized:true }
12
+ // | 200 { treeHash, materialized:false }
13
+ // GET /api/agent-skills/inventory the hub's read -> 200 { platform, checkedAt, roots,
14
+ // skills, base } (WP-7/§6.2, D-11)
15
+ // GET /api/agent-skills/export ?agent&name -> 200 { agent, name, itemHash, files }
16
+ // POST /api/agent-skills/retire { agent, name, expectHash } -> 200 { retiredTo }
17
+ // (WP-8/§6.2, D-12/D-13)
18
+ //
19
+ // Storage and verification are lib/agent-bundle/store.js's (blob re-hash, manifest tree-hash check,
20
+ // materialization); this module owns only the wire: body limits, the status table, and the peer
21
+ // identity read.
22
+ //
23
+ // Like lib/api/host-stats.js and lib/api/machines.js (and unlike the lib/api/*.js extraction slices)
24
+ // this is NEW surface: the handler bodies live here, so there is no legacy handleApi branch to delete
25
+ // and tests-integration/api-router-parity.test.js's no-dual-dispatch rule is satisfied by
26
+ // construction. Auth is NOT evaluated here: lib/auth-rules.js carries the three `admin` +
27
+ // `peerControl: true` rows, and a route with no rule is 403 auth_rule_missing by design — so the rule
28
+ // rows and these registrations must land together.
29
+ //
30
+ // IDENTITY: every route refuses a caller with no authenticated peer identity (403
31
+ // `agent_bundle_peer_unidentified`) before it reads a body. The peer is `req.ctmAuth.peerInstanceId`
32
+ // (the same read server.js's sync routes use) — never a field from the request — so a bundle can
33
+ // only ever be written under the identity that actually authenticated.
34
+ const os = require('os');
35
+ const { registerApiRoutes } = require('../api-router');
36
+ const store = require('../agent-bundle/store');
37
+ // WP-5 (docs/remote-agent-skills-bundles-2026-10-25.html §8 WP-5 row): a manifest PUT that
38
+ // MATERIALIZED a tree is one of exactly two moments the box store grows, so it is one of exactly
39
+ // two moments a sweep is scheduled (the other is boot, in server.js). Event-driven, never a timer.
40
+ const bundleGc = require('../agent-bundle/gc');
41
+ // WP-6 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-14, §8 WP-6 row): the same PUT is also
42
+ // the moment the box's `$HOME/.agents/skills` copies are brought in line with the tree it just
43
+ // pointed at — on EVERY successful PUT, because the hub pointer moves on a re-PUT too.
44
+ const bundleCodexInstall = require('../agent-bundle/codex-install');
45
+ // WP-7 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-11, §6.2): the RETURN path — the box
46
+ // reports the skills it already holds so the hub can classify them instead of copying anything.
47
+ const bundleInventory = require('../agent-bundle/inventory');
48
+ // WP-8 (docs/remote-agent-skills-bundles-2026-10-25.html §5 D-12/D-13, §6.2): the ONE-SKILL
49
+ // exchange — `export` ships one box item's bytes to the hub, `retire` MOVES that item aside on the box
50
+ // when the hub now owns the copy. Policy lives in the lib; this module owns only the wire.
51
+ const skillTransfer = require('../agent-bundle/skill-transfer');
52
+ const { MAX_ENTRIES } = require('../agent-bundle/build');
53
+
54
+ const { AgentBundleError } = store;
55
+
56
+ // §6.2 body limits. MAX_ENTRIES mirrors build.js: the hub cannot produce a longer list, so the box
57
+ // answers the same way it would to an unparseable body rather than reading unbounded input.
58
+ const MAX_MISSING_BODY_BYTES = 1024 * 1024;
59
+ // WP-4/§6.2/D-6: the batch body is JSON + base64, so it is capped at its own limit rather than
60
+ // MAX_BLOB_BYTES. A 4 MiB raw batch (D-7) base64-grows to ~5.4 MiB, under this cap.
61
+ const MAX_BATCH_BODY_BYTES = 8 * 1024 * 1024;
62
+ const MAX_BLOB_BYTES = 25 * 1024 * 1024;
63
+ const MAX_MANIFEST_BODY_BYTES = 4 * 1024 * 1024;
64
+
65
+ const ROUTE_MISSING = 'POST /api/agent-bundles/missing';
66
+ const ROUTE_BLOB_BATCH = 'POST /api/agent-bundles/blobs';
67
+ const ROUTE_BLOB = 'PUT /api/agent-bundles/blobs/:sha256';
68
+ const ROUTE_MANIFEST = 'PUT /api/agent-bundles/manifests/:treeHash';
69
+ const ROUTE_INVENTORY = 'GET /api/agent-skills/inventory';
70
+ const ROUTE_SKILL_EXPORT = 'GET /api/agent-skills/export';
71
+ const ROUTE_SKILL_RETIRE = 'POST /api/agent-skills/retire';
72
+
73
+ // One table: the store's error codes are the wire's codes (D-5 wording), and nothing else maps to a
74
+ // 4xx. An unrecognized error is a 500 `internal_error`, server.js's own global shape.
75
+ const STATUS_BY_CODE = {
76
+ agent_bundle_path_invalid: 422,
77
+ agent_bundle_blob_hash_mismatch: 422,
78
+ agent_bundle_tree_hash_mismatch: 422,
79
+ agent_bundle_blobs_missing: 409,
80
+ agent_bundle_peer_unidentified: 403,
81
+ };
82
+
83
+ let _deps = null;
84
+
85
+ function configure({
86
+ dataDir,
87
+ // WP-8: the box user's home, injected rather than `os.homedir()`-at-call-site so a route test can
88
+ // point the export/retire legs at a temp HOME. In production it is the process home, which the
89
+ // spawner already sets to the box user's.
90
+ homeDir = null,
91
+ readJsonRequestBody,
92
+ sendJsonResponse,
93
+ errorSink = null,
94
+ // WP-5: both are injected rather than required at call time so the route test can observe the
95
+ // trigger without a timer, a flag, or a spy on the store.
96
+ scheduleGc = null, // (dataDir, deps) => Promise<result>; defaults to the real single-flight sweep
97
+ sessionExists = null, // (ctmSessionId) => Promise<boolean>; server.js wires the box's DB read
98
+ // WP-6: same seam shape as scheduleGc — the route test observes the trigger without a timer.
99
+ scheduleCodexInstall = null, // (dataDir, deps) => Promise<result>; defaults to the real single-flight run
100
+ // WP-3 (agent-bundle-darwin-readonly-rename-2026-10-27.html §16 D-8 T1): the hub pointer for this
101
+ // peer just moved (or a tree materialized), so any live session still running the OLD tree is now
102
+ // drifted. Injected, never required at call time — the module stays wire-only and testable.
103
+ onBundlePointerMoved = null, // (peerInstanceId) => void
104
+ } = {}) {
105
+ _deps = { dataDir, homeDir, readJsonRequestBody, sendJsonResponse, errorSink, scheduleGc, sessionExists, scheduleCodexInstall, onBundlePointerMoved };
106
+ }
107
+
108
+ /** The box user's home, for the WP-8 export/retire legs. */
109
+ function _homeDir() {
110
+ if (_deps && _deps.homeDir) return _deps.homeDir;
111
+ return os.homedir();
112
+ }
113
+
114
+ function _send(res, status, payload) {
115
+ if (_deps && typeof _deps.sendJsonResponse === 'function') return _deps.sendJsonResponse(res, status, payload);
116
+ const body = JSON.stringify(payload || {});
117
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
118
+ res.end(body);
119
+ }
120
+
121
+ function _dataDir() {
122
+ if (_deps && _deps.dataDir) return _deps.dataDir;
123
+ return require('../data-dir').getDataDir();
124
+ }
125
+
126
+ /** The authenticated hub, or '' — the same read server.js:52696 does for its sync routes. */
127
+ function _peerInstanceId(req) {
128
+ return String((req && req.ctmAuth && req.ctmAuth.peerInstanceId) || '').trim();
129
+ }
130
+
131
+ function _payloadTooLarge(res) {
132
+ return _send(res, 413, { error: 'payload_too_large', code: 'PAYLOAD_TOO_LARGE' });
133
+ }
134
+
135
+ /**
136
+ * WP-5: fire-and-forget sweep after the response is out. The scheduler is single-flight and never
137
+ * rejects, so `void` here cannot produce an unhandled rejection; a sweep fault reaches the error sink
138
+ * through the `report` this passes in.
139
+ */
140
+ function _scheduleGc() {
141
+ const schedule = (_deps && _deps.scheduleGc) || bundleGc.scheduleCollectGarbage;
142
+ const report = (error) => {
143
+ if (_deps && _deps.errorSink && typeof _deps.errorSink.report === 'function') {
144
+ _deps.errorSink.report('agent-bundle-gc', error);
145
+ }
146
+ };
147
+ schedule(_dataDir(), { sessionExists: (_deps && _deps.sessionExists) || null, report });
148
+ }
149
+
150
+ /**
151
+ * WP-6/D-14: fire-and-forget Codex install after the response is out — the box's `$HOME/.agents/skills`
152
+ * copies are brought in line with the tree this PUT just pointed at. The scheduler is single-flight and
153
+ * never rejects, so `void` here cannot produce an unhandled rejection; a fault reaches the error sink
154
+ * through the `report` this passes in. The hub identity is the AUTHENTICATED one, never a body field.
155
+ */
156
+ function _scheduleCodexInstall(hubPeerId) {
157
+ const schedule = (_deps && _deps.scheduleCodexInstall) || bundleCodexInstall.scheduleBundleCodexInstall;
158
+ const report = (error) => {
159
+ if (_deps && _deps.errorSink && typeof _deps.errorSink.report === 'function') {
160
+ _deps.errorSink.report('agent-bundle-codex-install', error);
161
+ }
162
+ };
163
+ schedule(_dataDir(), { hubPeerId, report });
164
+ }
165
+
166
+ /**
167
+ * WP-3/D-8 T1: tell the server the hub pointer just moved, so it can reconcile bundle drift for the
168
+ * sessions that are still running an older tree. Void by construction — the reconciler is
169
+ * single-flight and reports its own faults through `errorSink`; a manifest PUT never waits on it.
170
+ */
171
+ function _onBundlePointerMoved(hubPeerId) {
172
+ if (_deps && typeof _deps.onBundlePointerMoved === 'function') _deps.onBundlePointerMoved(hubPeerId);
173
+ }
174
+
175
+ /**
176
+ * The bounded raw-body reader. api-prompts.js:684 has the same shape for image uploads but does not
177
+ * export it, and its 499/abort bookkeeping is image-specific; this is the ~20-line subset the blob
178
+ * PUT needs (accumulate to a hard cap, reject with the tagged 413 the readers share).
179
+ */
180
+ function _readRawBody(req, limit) {
181
+ return new Promise((resolve, reject) => {
182
+ const chunks = [];
183
+ let size = 0;
184
+ let settled = false;
185
+ const fail = (error) => {
186
+ if (settled) return;
187
+ settled = true;
188
+ reject(error);
189
+ };
190
+ req.on('data', (chunk) => {
191
+ if (settled) return;
192
+ size += chunk.length;
193
+ if (size > limit) {
194
+ const error = new Error('Body too large');
195
+ error.code = 'PAYLOAD_TOO_LARGE';
196
+ error.error = 'payload_too_large';
197
+ error.status = 413;
198
+ fail(error);
199
+ return;
200
+ }
201
+ chunks.push(chunk);
202
+ });
203
+ req.on('end', () => {
204
+ if (settled) return;
205
+ settled = true;
206
+ resolve(Buffer.concat(chunks));
207
+ });
208
+ req.on('aborted', () => {
209
+ const error = new Error('Client aborted agent-bundle upload');
210
+ error.code = 'CTM_UPLOAD_ABORTED';
211
+ error.status = 499;
212
+ fail(error);
213
+ });
214
+ req.on('error', fail);
215
+ });
216
+ }
217
+
218
+ /** Every route's failure path: store codes → their status, an over-cap body → 413, else 500. */
219
+ function _fail(res, error, route) {
220
+ if (error instanceof AgentBundleError) {
221
+ const status = STATUS_BY_CODE[error.code] || 500;
222
+ const payload = { code: error.code };
223
+ if (Array.isArray(error.missing)) payload.missing = error.missing;
224
+ return _send(res, status, payload);
225
+ }
226
+ // WP-8: the skill transfer's own typed failure already carries its wire status (404/409/413/422/502),
227
+ // so the box's answer and the hub's relay of it are the same shape for the same fault.
228
+ if (error instanceof skillTransfer.AgentSkillError) {
229
+ const payload = { code: error.code };
230
+ if (error.detail) payload.detail = error.detail;
231
+ return _send(res, error.status, payload);
232
+ }
233
+ const code = String((error && error.code) || '');
234
+ const message = String((error && error.message) || '');
235
+ if (code === 'PAYLOAD_TOO_LARGE' || message === 'request_body_too_large') return _payloadTooLarge(res);
236
+ if (code === 'CTM_UPLOAD_ABORTED') return _send(res, 499, { error: 'client_aborted' });
237
+ if (_deps && _deps.errorSink && typeof _deps.errorSink.report === 'function') {
238
+ // REPORT: an unexpected failure is a real fault, not a client mistake — surface it before the 500.
239
+ _deps.errorSink.report(`agent-bundles:${route}`, error);
240
+ }
241
+ return _send(res, 500, { error: 'internal_error' });
242
+ }
243
+
244
+ async function handleMissing(req, res) {
245
+ const peerInstanceId = _peerInstanceId(req);
246
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
247
+ try {
248
+ const body = await _deps.readJsonRequestBody(req, { limitBytes: MAX_MISSING_BODY_BYTES });
249
+ const blobs = body && !Array.isArray(body) ? body.blobs : null;
250
+ if (!Array.isArray(blobs)) return _send(res, 400, { error: 'invalid_body' });
251
+ if (blobs.length > MAX_ENTRIES) return _payloadTooLarge(res);
252
+ return _send(res, 200, { missing: await store.missingBlobs(_dataDir(), blobs) });
253
+ } catch (error) {
254
+ return _fail(res, error, ROUTE_MISSING);
255
+ }
256
+ }
257
+
258
+ async function handleBlobPut(req, res, url, params) {
259
+ const peerInstanceId = _peerInstanceId(req);
260
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
261
+ try {
262
+ const hex = String((params && params['1']) || '');
263
+ const body = await _readRawBody(req, MAX_BLOB_BYTES);
264
+ const result = await store.putBlob(_dataDir(), hex, body);
265
+ return _send(res, result.stored ? 201 : 200, { stored: result.stored });
266
+ } catch (error) {
267
+ return _fail(res, error, ROUTE_BLOB);
268
+ }
269
+ }
270
+
271
+ /**
272
+ * WP-4/§6.2/D-6 (docs/remote-skills-hub-peer-identity-2026-10-26.html rev 2): the BATCH blob leg —
273
+ * many blobs in one request, so a first push costs a constant number of requests instead of one per
274
+ * blob (the box's `peer` rate bucket is per-hub and shared with the live relay; §1.3). Body:
275
+ * `{ blobs: [{ hash: <64 hex>, data: <base64> }] }`, at most MAX_BATCH_BODY_BYTES of JSON and
276
+ * MAX_ENTRIES items. Items go through the SAME `store.putBlob` (re-hash + atomic write) IN ORDER, so
277
+ * a bad hash is the store's own 422 and an already-present blob is left untouched. Content-addressed,
278
+ * so a stop mid-list is exactly a partial per-blob run. Same identity rule as the per-blob PUT: the
279
+ * peer refusal comes first, before the body is read.
280
+ */
281
+ async function handleBlobBatch(req, res) {
282
+ const peerInstanceId = _peerInstanceId(req);
283
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
284
+ try {
285
+ const body = await _deps.readJsonRequestBody(req, { limitBytes: MAX_BATCH_BODY_BYTES });
286
+ const blobs = body && !Array.isArray(body) ? body.blobs : null;
287
+ if (!Array.isArray(blobs)) return _send(res, 400, { error: 'invalid_body' });
288
+ if (blobs.length > MAX_ENTRIES) return _payloadTooLarge(res);
289
+ let stored = 0;
290
+ let present = 0;
291
+ for (const item of blobs) {
292
+ const hash = item && typeof item.hash === 'string' ? item.hash : '';
293
+ const data = item && typeof item.data === 'string' ? item.data : null;
294
+ if (data === null) return _send(res, 400, { error: 'invalid_body' });
295
+ // A bad hash (or bytes that do not match it) is the store's own code; it stops the batch, and
296
+ // every item already written stays — content-addressed, so that is a partial per-blob run.
297
+ const result = await store.putBlob(_dataDir(), hash, Buffer.from(data, 'base64'));
298
+ if (result.stored) stored += 1; else present += 1;
299
+ }
300
+ return _send(res, 200, { stored, present });
301
+ } catch (error) {
302
+ return _fail(res, error, ROUTE_BLOB_BATCH);
303
+ }
304
+ }
305
+
306
+ async function handleManifestPut(req, res, url, params) {
307
+ const peerInstanceId = _peerInstanceId(req);
308
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
309
+ try {
310
+ const treeHash = String((params && params['1']) || '');
311
+ const manifest = await _deps.readJsonRequestBody(req, { limitBytes: MAX_MANIFEST_BODY_BYTES });
312
+ const result = await store.putManifest(_dataDir(), treeHash, manifest, { peerInstanceId });
313
+ _send(res, result.materialized ? 201 : 200, {
314
+ treeHash: result.treeHash,
315
+ materialized: result.materialized,
316
+ });
317
+ // WP-6/D-14: on EVERY successful PUT — the hub pointer moves on a re-PUT too, and re-applying an
318
+ // unchanged tree is a cheap `noop` sweep. The install resolves the tree through the hub pointer
319
+ // this PUT just wrote, and the GC keeps a hub-pointer tree (gc.js's `_referencedTrees` reads
320
+ // `hubs/*.json`), so scheduling the sweep for a re-PUT cannot delete what the install needs.
321
+ void _scheduleCodexInstall(peerInstanceId);
322
+ // WP-3/D-8 T1: on EVERY 2xx PUT — the pointer moves on a re-PUT too, so a live session on the
323
+ // old tree is drifted either way. Distinct from the GC below, which only a NEW tree can feed.
324
+ void _onBundlePointerMoved(peerInstanceId);
325
+ // Only a NEW tree can have added blobs/trees worth sweeping: a re-PUT changed nothing on disk.
326
+ if (result.materialized) void _scheduleGc();
327
+ return undefined;
328
+ } catch (error) {
329
+ return _fail(res, error, ROUTE_MANIFEST);
330
+ }
331
+ }
332
+
333
+ /**
334
+ * WP-7/§6.2/AC-7a: `GET /api/agent-skills/inventory` — the box's own skill truth for the CALLING hub.
335
+ *
336
+ * Read-only and side-effect free: it enumerates the box user's skill roots and hashes them, and it
337
+ * never writes anything (D-1: the bundle only ever lives under the box's data dir). The peer check
338
+ * comes first, exactly like the three ingress routes, so an unidentified caller cannot even learn the
339
+ * shape of this machine's skill roots.
340
+ *
341
+ * The `base` in the answer is the tree THIS hub last handed the box (`store.currentHubTree` keyed by
342
+ * the AUTHENTICATED peer id), which is what makes classification survive a hub restart — the hub's
343
+ * own push bookkeeping is in-process only.
344
+ */
345
+ async function handleSkillsInventory(req, res) {
346
+ const peerInstanceId = _peerInstanceId(req);
347
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
348
+ try {
349
+ const inventory = await bundleInventory.readBoxInventory({ dataDir: _dataDir(), peerInstanceId });
350
+ return _send(res, 200, inventory);
351
+ } catch (error) {
352
+ return _fail(res, error, ROUTE_INVENTORY);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * WP-8/§6.2: `GET /api/agent-skills/export?agent=claude|codex&name=<name>` — the bytes of ONE box item.
358
+ *
359
+ * A `ctm-managed` copy (the managed-skill installer's own `delegate`) is a 404, never a 409: this
360
+ * release's copy is simply not an item that can be proposed for import, and "not found" keeps the hub
361
+ * from ever rendering it as one. The ref is validated first (a name that could escape a root is a 422
362
+ * before any path is built), then the item is located exactly as the WP-7 inventory locates it.
363
+ */
364
+ async function handleSkillExport(req, res, url) {
365
+ const peerInstanceId = _peerInstanceId(req);
366
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
367
+ try {
368
+ const agent = url && url.searchParams ? url.searchParams.get('agent') : '';
369
+ const name = url && url.searchParams ? url.searchParams.get('name') : '';
370
+ const exported = await skillTransfer.exportBoxSkill({ agent, name, homeDir: _homeDir(), env: process.env });
371
+ return _send(res, 200, exported);
372
+ } catch (error) {
373
+ return _fail(res, error, ROUTE_SKILL_EXPORT);
374
+ }
375
+ }
376
+
377
+ /**
378
+ * WP-8/§6.5: `POST /api/agent-skills/retire { agent, name, expectHash }` — D-13's "moves, never
379
+ * deletes". The box re-hashes the copy NOW and refuses one that changed since review, then MOVES it
380
+ * under `<data dir>/agent-bundles/retired/`. Both failures are the human's to see, so both carry a code.
381
+ */
382
+ async function handleSkillRetire(req, res) {
383
+ const peerInstanceId = _peerInstanceId(req);
384
+ if (!peerInstanceId) return _send(res, 403, { code: 'agent_bundle_peer_unidentified' });
385
+ try {
386
+ const body = await _deps.readJsonRequestBody(req, { limitBytes: MAX_MISSING_BODY_BYTES });
387
+ const ref = body && !Array.isArray(body) ? body : {};
388
+ const result = await skillTransfer.retireBoxSkill({
389
+ agent: ref.agent,
390
+ name: ref.name,
391
+ expectHash: ref.expectHash,
392
+ dataDir: _dataDir(),
393
+ homeDir: _homeDir(),
394
+ env: process.env,
395
+ });
396
+ return _send(res, 200, result);
397
+ } catch (error) {
398
+ return _fail(res, error, ROUTE_SKILL_RETIRE);
399
+ }
400
+ }
401
+
402
+ function register() {
403
+ registerApiRoutes('agent-bundles', [
404
+ { method: 'POST', path: '/api/agent-bundles/missing', handler: handleMissing },
405
+ // WP-4/§6.2/D-6: the batch leg, so a first push is a constant number of requests. Same auth row
406
+ // tuple as the per-blob PUT (lib/auth-rules.js), same peer-identity refusal first.
407
+ { method: 'POST', path: '/api/agent-bundles/blobs', handler: handleBlobBatch },
408
+ // The regex is byte-identical to lib/auth-rules.js's blob row on purpose: routing and auth must
409
+ // agree on what "this route" is, or a malformed hash would be answered by the auth wall with a
410
+ // different code than the handler's own 422.
411
+ { method: 'PUT', regex: /^\/api\/agent-bundles\/blobs\/([0-9a-f]{64})$/, handler: handleBlobPut },
412
+ // `[^/]+` (not a hash pattern): the tree hash is URL-encoded in the URL, and store.js decodes
413
+ // and validates it into the one canonical `sha256:<hex>` form — a bad one is its 422, not a 404.
414
+ { method: 'PUT', regex: /^\/api\/agent-bundles\/manifests\/([^/]+)$/, handler: handleManifestPut },
415
+ // WP-7/§6.2: the return path. Same identity rule as the three above (an unauthenticated caller is
416
+ // 403 agent_bundle_peer_unidentified), same group; the base it reports is the caller's own.
417
+ { method: 'GET', path: '/api/agent-skills/inventory', handler: handleSkillsInventory },
418
+ // WP-8/§6.2: the one-skill exchange. `export` is a GET with query ref fields (a name is not
419
+ // path-safe in general); `retire` is a POST whose only body field that matters is the reviewed
420
+ // hash — the box identity is the authenticated peer, never a field, exactly as above.
421
+ { method: 'GET', path: '/api/agent-skills/export', handler: handleSkillExport },
422
+ { method: 'POST', path: '/api/agent-skills/retire', handler: handleSkillRetire },
423
+ ]);
424
+ }
425
+
426
+ module.exports = {
427
+ configure,
428
+ register,
429
+ handleMissing,
430
+ handleBlobBatch,
431
+ handleBlobPut,
432
+ handleManifestPut,
433
+ handleSkillsInventory,
434
+ handleSkillExport,
435
+ handleSkillRetire,
436
+ };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ // Backup retention setting (design: docs/backup-retention-days-setting-2026-10-31.html §6/WP-1).
4
+ // GET /api/storage/backup-retention -> the effective value, where it came from, and the
5
+ // backup names the next prune will remove.
6
+ // PUT /api/storage/backup-retention -> validate + persist `backup_retention_days`.
7
+ //
8
+ // Neither handler deletes anything: pruning still runs only at the end of a successful backup
9
+ // (db.js cleanOldBackups). A PUT just changes the number the next prune reads.
10
+
11
+ const { registerApiRoutes } = require('../api-router');
12
+ const backupRetention = require('../../../shared/backup-retention');
13
+
14
+ let _deps = null;
15
+
16
+ function configure(deps = {}) {
17
+ _deps = deps;
18
+ }
19
+
20
+ async function _statusPayload() {
21
+ const db = _deps.db;
22
+ const retentionDays = db.getBackupRetentionDays();
23
+ let source = 'default';
24
+ try {
25
+ // Production main thread: the published control snapshot (direct sync DB reads are refused
26
+ // in the request zone). Tests and worker-local callers fall back to db.getSetting.
27
+ const read = typeof _deps.getSetting === 'function' ? _deps.getSetting : db.getSetting.bind(db);
28
+ const stored = await read(backupRetention.BACKUP_RETENTION_SETTING_KEY, null);
29
+ if (stored !== null && stored !== undefined) source = 'settings';
30
+ } catch (e) {
31
+ // A read failure must never break the page: report and answer with the default source.
32
+ console.error('[api] Backup retention setting read failed:', e.message);
33
+ source = 'default';
34
+ }
35
+ const expiring = backupRetention
36
+ .selectExpiredBackups(await db.listBackupsAsync(), retentionDays)
37
+ .map((b) => b.name);
38
+ return {
39
+ retention_days: retentionDays,
40
+ default_retention_days: backupRetention.DEFAULT_BACKUP_RETENTION_DAYS,
41
+ min: backupRetention.MIN_BACKUP_RETENTION_DAYS,
42
+ max: backupRetention.MAX_BACKUP_RETENTION_DAYS,
43
+ source,
44
+ expiring,
45
+ };
46
+ }
47
+
48
+ async function handleGet(req, res) {
49
+ void req;
50
+ _deps.sendJsonResponse(res, 200, await _statusPayload());
51
+ }
52
+
53
+ async function handlePut(req, res) {
54
+ let body;
55
+ try {
56
+ body = await _deps.readBody(req);
57
+ } catch {
58
+ // Malformed JSON, empty body, or an over-limit body: nothing is written.
59
+ _deps.sendJsonResponse(res, 400, { error: 'invalid_body' });
60
+ return;
61
+ }
62
+ const parsed = backupRetention.parseRetentionDaysInput(body && body.retention_days);
63
+ if (!parsed.ok) {
64
+ _deps.sendJsonResponse(res, 400, {
65
+ error: parsed.error,
66
+ min: parsed.min,
67
+ max: parsed.max,
68
+ });
69
+ return;
70
+ }
71
+ _deps.db.setBackupRetentionDays(parsed.days);
72
+ await _deps.db.setSetting(backupRetention.BACKUP_RETENTION_SETTING_KEY, parsed.days);
73
+ _deps.sendJsonResponse(res, 200, await _statusPayload());
74
+ }
75
+
76
+ function register() {
77
+ registerApiRoutes('backup-retention', [
78
+ { method: 'GET', path: '/api/storage/backup-retention', handler: handleGet },
79
+ { method: 'PUT', path: '/api/storage/backup-retention', handler: handlePut },
80
+ ]);
81
+ }
82
+
83
+ module.exports = { configure, handleGet, handlePut, register };
@@ -0,0 +1,124 @@
1
+ 'use strict';
2
+
3
+ // WP-5 (docs/shared-memory-every-machine-2026-10-31.html §5 D-3, D-12, §6.8): the CTM-served
4
+ // conversation-history feed. Unlike the brain/v2 family (lib/api/memory-sync-routes.js), these
5
+ // three routes are NOT proxies: transcription history lives in CTM's own task-manager.db, so the
6
+ // hub speaks to a member's CTM directly and no Wall-E hop is involved.
7
+ //
8
+ // GET /api/sync/conversation/v2/vector -> { ok, instanceId, vector, seedDone }
9
+ // POST /api/sync/conversation/v2/changes { since, limit } -> { ok, entries, more, seedDone }
10
+ // POST /api/sync/conversation/v2/apply { sourceInstanceId, entries } -> { ok, applied, skipped, vector }
11
+ //
12
+ // Auth is NOT evaluated here — lib/auth-rules.js carries the three rows (scope `sync`, no step-up,
13
+ // NOT peerControl: the pool credential the hub already dials `/api/sync/brain/v2/*` with authorizes
14
+ // them), and a route with no rule is 403 auth_rule_missing by design, so the rule rows and these
15
+ // registrations land together. A body over the 8 MiB cap is 413 before any DB work.
16
+ //
17
+ // The clock seed (D-3 / §6.8) is driven from here rather than at boot: each `/vector` and
18
+ // `/changes` call advances THIS node's seed by one bounded page, so a member with pre-existing
19
+ // history finishes seeding over the first few hub ticks and boot stays free of the work.
20
+ //
21
+ // WP-3 (docs/join-sync-followups-2-2026-11-01.html §5 R-10/R-11, §8 WP-3): that seed page, the
22
+ // store DDL and every read/write below run in the DB-OWNER WORKER, never on this thread. Each
23
+ // handler awaits one closed owner action through the injected `runMutation`
24
+ // (`runMutation -> server.js _runCtmDbWorkerOp('runDbMutation', …) -> db.js
25
+ // DB_OWNER_MUTATION_ACTIONS -> lib/conversation-sync.js owner*`). Doing this work here is what
26
+ // made every member's /vector answer 500: the main-thread request-zone guard refuses a main-DB
27
+ // op inside a request (lib/main-db-census.js, CTM_MAIN_DB_REQUEST_FORBIDDEN). The three reply
28
+ // shapes are unchanged (R-11) — only where the work runs changed.
29
+
30
+ const { registerApiRoutes } = require('../api-router');
31
+
32
+ const MAX_BODY_BYTES = 8 * 1024 * 1024;
33
+ const BODY_TOO_LARGE = 'request_body_too_large';
34
+ const OWNER_UNAVAILABLE = 'conversation_sync_owner_unavailable';
35
+
36
+ let _deps = null;
37
+
38
+ function configure({ dbModule, readJsonRequestBody, sendJsonResponse, seedPageLimit, runMutation } = {}) {
39
+ _deps = { dbModule, readJsonRequestBody, sendJsonResponse, seedPageLimit, runMutation };
40
+ }
41
+
42
+ // The one seam to the DB-owner worker. Unconfigured (or configured with a non-function) means the
43
+ // feed cannot run at all, so every route answers 503 rather than doing the work in-zone.
44
+ function _ownerRun() {
45
+ const run = _deps && _deps.runMutation;
46
+ return typeof run === 'function' ? run : null;
47
+ }
48
+
49
+ function _send(res, status, payload) {
50
+ if (_deps && typeof _deps.sendJsonResponse === 'function') return _deps.sendJsonResponse(res, status, payload || {});
51
+ const body = JSON.stringify(payload || {});
52
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
53
+ res.end(body);
54
+ }
55
+
56
+ async function _readBody(req) {
57
+ const reader = _deps && _deps.readJsonRequestBody;
58
+ if (typeof reader !== 'function') return { ok: true, body: undefined };
59
+ try {
60
+ return { ok: true, body: await reader(req, { limitBytes: MAX_BODY_BYTES }) };
61
+ } catch (err) {
62
+ return { ok: false, tooLarge: !!(err && err.message === BODY_TOO_LARGE) };
63
+ }
64
+ }
65
+
66
+ async function _handleVector(req, res) {
67
+ const run = _ownerRun();
68
+ if (!run) return _send(res, 503, { ok: false, error: OWNER_UNAVAILABLE });
69
+ try {
70
+ const vector = await run('conversationSyncVector', [{ seedPageLimit: _deps.seedPageLimit }]);
71
+ return _send(res, 200, { ok: true, ...vector });
72
+ } catch (err) {
73
+ return _send(res, 500, { ok: false, error: 'conversation_vector_failed', detail: String(err?.message || err).slice(0, 200) });
74
+ }
75
+ }
76
+
77
+ async function _handleChanges(req, res) {
78
+ const run = _ownerRun();
79
+ if (!run) return _send(res, 503, { ok: false, error: OWNER_UNAVAILABLE });
80
+ const read = await _readBody(req);
81
+ if (!read.ok) return _send(res, 413, { ok: false, error: 'payload_too_large' });
82
+ const body = (read.body && typeof read.body === 'object') ? read.body : {};
83
+ try {
84
+ const page = await run('conversationSyncChanges', [{
85
+ since: body.since,
86
+ limit: body.limit,
87
+ seedPageLimit: _deps.seedPageLimit,
88
+ }]);
89
+ return _send(res, 200, { ok: true, entries: page.entries, more: page.more, seedDone: page.seedDone });
90
+ } catch (err) {
91
+ return _send(res, 500, { ok: false, error: 'conversation_changes_failed', detail: String(err?.message || err).slice(0, 200) });
92
+ }
93
+ }
94
+
95
+ async function _handleApply(req, res) {
96
+ const run = _ownerRun();
97
+ if (!run) return _send(res, 503, { ok: false, error: OWNER_UNAVAILABLE });
98
+ const read = await _readBody(req);
99
+ if (!read.ok) return _send(res, 413, { ok: false, error: 'payload_too_large' });
100
+ const body = (read.body && typeof read.body === 'object') ? read.body : {};
101
+ const sourceInstanceId = String(body.sourceInstanceId || '').trim();
102
+ if (!sourceInstanceId) return _send(res, 400, { ok: false, error: 'source_instance_required' });
103
+ try {
104
+ const result = await run('conversationSyncApply', [{
105
+ sourceInstanceId,
106
+ entries: Array.isArray(body.entries) ? body.entries : [],
107
+ }]);
108
+ return _send(res, 200, { ok: true, applied: result.applied, skipped: result.skipped, vector: result.vector });
109
+ } catch (err) {
110
+ const code = err && err.code;
111
+ if (code === 'CONVERSATION_SYNC_ENTRIES_TOO_LARGE') return _send(res, 413, { ok: false, error: 'too_many_entries' });
112
+ return _send(res, 500, { ok: false, error: 'conversation_apply_failed', detail: String(err?.message || err).slice(0, 200) });
113
+ }
114
+ }
115
+
116
+ function register() {
117
+ registerApiRoutes('conversation-sync', [
118
+ { method: 'GET', path: '/api/sync/conversation/v2/vector', handler: (req, res, url) => _handleVector(req, res, url) },
119
+ { method: 'POST', path: '/api/sync/conversation/v2/changes', handler: (req, res, url) => _handleChanges(req, res, url) },
120
+ { method: 'POST', path: '/api/sync/conversation/v2/apply', handler: (req, res, url) => _handleApply(req, res, url) },
121
+ ]);
122
+ }
123
+
124
+ module.exports = { configure, register };