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,657 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * WP-1 — hub-side agent bundle builder (design §6.1, rules D-2/D-3/D-9/D-10).
5
+ *
6
+ * Pure except filesystem reads: no network, no persistence, no server wiring.
7
+ * Later work packages (push, box store, spawn injection) consume this module.
8
+ *
9
+ * The bundle is content addressed: `treeHash` is sha256 over the canonical JSON
10
+ * of the sorted entry list, so identical content yields an identical hash on any
11
+ * hub, regardless of mtime or directory order (D-2).
12
+ */
13
+
14
+ const crypto = require('crypto');
15
+ const os = require('os');
16
+ const path = require('path');
17
+ const fsp = require('fs/promises');
18
+
19
+ /** = box readRawBody cap (api-prompts.js) — larger files cannot be uploaded. */
20
+ const MAX_FILE_BYTES = 25 * 1024 * 1024;
21
+ /** Measured hub total is ≈ 9.7 MB; 13× headroom. */
22
+ const MAX_BUNDLE_BYTES = 128 * 1024 * 1024;
23
+ const MAX_ENTRIES = 20000;
24
+
25
+ /** A file is "text" for the D-10 home-path lint when no NUL byte appears here. */
26
+ const TEXT_PROBE_BYTES = 8192;
27
+
28
+ /** Claude user skills are never shipped: the account syncs them itself. */
29
+ const SKIPPED_SKILL_DIRS = new Set(['synced']);
30
+
31
+ /**
32
+ * Module-scope hash cache, keyed `${realpath}\0${size}\0${mtimeMs}` → sha256 hex.
33
+ * No disk cache (D-2 keeps identity cheap without a second source of truth).
34
+ */
35
+ const sha256Cache = new Map();
36
+
37
+ function sha256Hex(buffer) {
38
+ return crypto.createHash('sha256').update(buffer).digest('hex');
39
+ }
40
+
41
+ function comparePaths(a, b) {
42
+ if (a < b) return -1;
43
+ if (a > b) return 1;
44
+ return 0;
45
+ }
46
+
47
+ /**
48
+ * Canonical tree hash: sort by path (byte order), keep exactly
49
+ * {path, mode, sha256, size} in that key order, JSON.stringify, sha256.
50
+ *
51
+ * @param {Array<{path: string, mode: number, sha256: string, size: number}>} entries
52
+ * @returns {string} `sha256:<64 hex>`
53
+ */
54
+ function computeTreeHash(entries) {
55
+ const normalized = (Array.isArray(entries) ? entries : [])
56
+ .map((entry) => ({
57
+ path: entry.path,
58
+ mode: entry.mode,
59
+ sha256: entry.sha256,
60
+ size: entry.size,
61
+ }))
62
+ .sort((a, b) => comparePaths(a.path, b.path));
63
+ return `sha256:${sha256Hex(JSON.stringify(normalized))}`;
64
+ }
65
+
66
+ function isInside(root, candidate) {
67
+ if (candidate === root) return true;
68
+ return candidate.startsWith(root.endsWith(path.sep) ? root : `${root}${path.sep}`);
69
+ }
70
+
71
+ function isTextBuffer(buffer) {
72
+ const probe = buffer.length > TEXT_PROBE_BYTES ? buffer.subarray(0, TEXT_PROBE_BYTES) : buffer;
73
+ return probe.indexOf(0) === -1;
74
+ }
75
+
76
+ function stripQuotes(value) {
77
+ const text = String(value == null ? '' : value).trim();
78
+ if (text.length >= 2) {
79
+ const first = text[0];
80
+ const last = text[text.length - 1];
81
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
82
+ return text.slice(1, -1);
83
+ }
84
+ }
85
+ return text;
86
+ }
87
+
88
+ /**
89
+ * Narrow YAML reader for `metadata.platforms` only (D-9).
90
+ *
91
+ * Deliberately not lib/skill-autocomplete.js's parser: that one flattens nested
92
+ * keys, so `metadata:` / ` platforms:` would collapse into a bogus top-level
93
+ * key. Recognizes:
94
+ * metadata:
95
+ * platforms: [darwin, linux]
96
+ * metadata:
97
+ * platforms:
98
+ * - darwin
99
+ *
100
+ * @param {string} text SKILL.md / plugin.json frontmatter source
101
+ * @returns {string[]|null} platform list, or null when absent
102
+ */
103
+ function parseFrontmatterPlatforms(text) {
104
+ const lines = String(text == null ? '' : text).split(/\r?\n/);
105
+ if (lines.length < 2 || lines[0].trim() !== '---') return null;
106
+ let end = -1;
107
+ for (let i = 1; i < lines.length; i += 1) {
108
+ if (lines[i].trim() === '---') {
109
+ end = i;
110
+ break;
111
+ }
112
+ }
113
+ if (end === -1) return null;
114
+ const frontmatter = lines.slice(1, end);
115
+
116
+ let metaIndex = -1;
117
+ for (let i = 0; i < frontmatter.length; i += 1) {
118
+ if (/^metadata\s*:\s*$/.test(frontmatter[i])) {
119
+ metaIndex = i;
120
+ break;
121
+ }
122
+ }
123
+ if (metaIndex === -1) return null;
124
+
125
+ for (let i = metaIndex + 1; i < frontmatter.length; i += 1) {
126
+ const line = frontmatter[i];
127
+ if (!line.trim() || /^\s*#/.test(line)) continue;
128
+ const indent = line.match(/^\s*/)[0].length;
129
+ if (indent === 0) return null; // left the metadata block
130
+ const match = line.match(/^\s+platforms\s*:\s*(.*)$/);
131
+ if (!match) continue;
132
+ const inline = match[1].trim();
133
+ if (inline) {
134
+ if (inline.startsWith('[') && inline.endsWith(']')) {
135
+ return inline
136
+ .slice(1, -1)
137
+ .split(',')
138
+ .map((item) => stripQuotes(item))
139
+ .filter((item) => item.length > 0);
140
+ }
141
+ const scalar = stripQuotes(inline);
142
+ return scalar ? [scalar] : null;
143
+ }
144
+ const list = [];
145
+ for (let j = i + 1; j < frontmatter.length; j += 1) {
146
+ const item = frontmatter[j];
147
+ if (!item.trim()) continue;
148
+ const itemIndent = item.match(/^\s*/)[0].length;
149
+ const itemMatch = item.match(/^\s*-\s*(.+?)\s*$/);
150
+ // YAML permits a block sequence either deeper than, or level with, its key.
151
+ if (!itemMatch || itemIndent < indent) break;
152
+ list.push(stripQuotes(itemMatch[1]));
153
+ }
154
+ return list.length ? list : null;
155
+ }
156
+ return null;
157
+ }
158
+
159
+ /** Platforms declared by a plugin's `.claude-plugin/plugin.json` (`metadata.platforms`). */
160
+ function parsePluginJsonPlatforms(text) {
161
+ let parsed;
162
+ try {
163
+ parsed = JSON.parse(String(text));
164
+ } catch (err) {
165
+ /* expected: a malformed third-party plugin.json only means "no platform filter" */
166
+ return null;
167
+ }
168
+ const metadata = parsed && typeof parsed === 'object' ? parsed.metadata : null;
169
+ const platforms = metadata && typeof metadata === 'object' ? metadata.platforms : null;
170
+ if (!Array.isArray(platforms)) return null;
171
+ const list = platforms.map((item) => stripQuotes(item)).filter((item) => item.length > 0);
172
+ return list.length ? list : null;
173
+ }
174
+
175
+ async function statOrNull(target) {
176
+ try {
177
+ return await fsp.stat(target);
178
+ } catch (err) {
179
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) return null;
180
+ throw err;
181
+ }
182
+ }
183
+
184
+ async function readTextOrNull(target) {
185
+ try {
186
+ return await fsp.readFile(target, 'utf8');
187
+ } catch (err) {
188
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR' || err.code === 'EISDIR')) return null;
189
+ throw err;
190
+ }
191
+ }
192
+
193
+ async function readJsonObjectOrNull(target) {
194
+ const text = await readTextOrNull(target);
195
+ if (text == null) return null;
196
+ try {
197
+ const parsed = JSON.parse(text);
198
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
199
+ } catch (err) {
200
+ /* expected: an unreadable/garbled hub config means "no plugins", not a build failure */
201
+ return null;
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Claude user skills: every directory directly under realpath(<config>/skills)
207
+ * that contains SKILL.md, minus `synced`. Entries may be symlinks to dirs — they
208
+ * are followed. Top-level non-directories are ignored.
209
+ */
210
+ async function listClaudeSkillItems(configDir) {
211
+ const skillsDir = path.join(configDir, 'skills');
212
+ let dirents;
213
+ try {
214
+ dirents = await fsp.readdir(skillsDir, { withFileTypes: true });
215
+ } catch (err) {
216
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) return [];
217
+ throw err;
218
+ }
219
+ const items = [];
220
+ for (const dirent of dirents.slice().sort((a, b) => comparePaths(a.name, b.name))) {
221
+ const name = dirent.name;
222
+ if (name.startsWith('.')) continue;
223
+ if (SKIPPED_SKILL_DIRS.has(name)) continue;
224
+ const dir = path.join(skillsDir, name);
225
+ const stat = await statOrNull(dir);
226
+ if (!stat || !stat.isDirectory()) continue; // stray files (e.g. foo.skill) are ignored
227
+ const skillMd = await statOrNull(path.join(dir, 'SKILL.md'));
228
+ if (!skillMd || !skillMd.isFile()) continue;
229
+ items.push({ agent: 'claude', kind: 'skill', name, dirName: name, rootDir: dir });
230
+ }
231
+ return items;
232
+ }
233
+
234
+ /**
235
+ * Claude plugins: enabled === true in settings.json `enabledPlugins`, minus the
236
+ * per-machine exclude list, using the first installed_plugins.json record's
237
+ * installPath. Missing config files mean "no plugins" (not an error).
238
+ */
239
+ async function listPluginItems(configDir, excludePlugins) {
240
+ const installed = await readJsonObjectOrNull(path.join(configDir, 'plugins', 'installed_plugins.json'));
241
+ const settings = await readJsonObjectOrNull(path.join(configDir, 'settings.json'));
242
+ if (!installed || !settings) return [];
243
+ const enabled = settings.enabledPlugins;
244
+ if (!enabled || typeof enabled !== 'object' || Array.isArray(enabled)) return [];
245
+ const records = installed.plugins;
246
+ const recordMap = records && typeof records === 'object' && !Array.isArray(records) ? records : {};
247
+ const excluded = new Set(Array.isArray(excludePlugins) ? excludePlugins.map(String) : []);
248
+ const items = [];
249
+ const dirNames = new Set();
250
+ for (const id of Object.keys(enabled).sort(comparePaths)) {
251
+ if (enabled[id] !== true) continue;
252
+ if (excluded.has(id)) continue;
253
+ const list = recordMap[id];
254
+ const first = Array.isArray(list) ? list[0] : null;
255
+ const installPath = first && typeof first === 'object' && typeof first.installPath === 'string'
256
+ ? first.installPath
257
+ : null;
258
+ const dirName = id.split('@')[0];
259
+ // Two enabled plugins differing only after '@' would share plugins/<dirName>/; the first
260
+ // (sorted id) ships, the other is held back rather than producing colliding entry paths.
261
+ const collides = dirNames.has(dirName);
262
+ dirNames.add(dirName);
263
+ items.push({
264
+ agent: 'claude',
265
+ kind: 'plugin',
266
+ name: id,
267
+ dirName,
268
+ rootDir: installPath,
269
+ collides,
270
+ });
271
+ }
272
+ return items;
273
+ }
274
+
275
+ async function listCodexRoot(rootDir, out, seen) {
276
+ let dirents;
277
+ try {
278
+ dirents = await fsp.readdir(rootDir, { withFileTypes: true });
279
+ } catch (err) {
280
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) return;
281
+ throw err;
282
+ }
283
+ for (const dirent of dirents.slice().sort((a, b) => comparePaths(a.name, b.name))) {
284
+ const name = dirent.name;
285
+ if (name.startsWith('.') || name === '.system') continue;
286
+ if (seen.has(name)) continue; // first root wins (`.agents` before `$CODEX_HOME`)
287
+ const dir = path.join(rootDir, name);
288
+ const stat = await statOrNull(dir);
289
+ if (!stat || !stat.isDirectory()) continue;
290
+ const skillMd = await statOrNull(path.join(dir, 'SKILL.md'));
291
+ if (!skillMd || !skillMd.isFile()) continue;
292
+ seen.add(name);
293
+ out.push({ agent: 'codex', kind: 'skill', name, dirName: name, rootDir: dir });
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Codex skills: directories under `<homeDir>/.agents/skills` and
299
+ * `(env.CODEX_HOME || <homeDir>/.codex)/skills`, minus `.system`. On a name
300
+ * collision the first root (`.agents`) wins.
301
+ */
302
+ async function listCodexSkillItems(homeDir, env) {
303
+ const roots = [path.join(homeDir, '.agents', 'skills')];
304
+ const codexHome = typeof env.CODEX_HOME === 'string' && env.CODEX_HOME.trim()
305
+ ? env.CODEX_HOME.trim()
306
+ : path.join(homeDir, '.codex');
307
+ const codexSkills = path.join(codexHome, 'skills');
308
+ if (codexSkills !== roots[0]) roots.push(codexSkills);
309
+ const items = [];
310
+ const seen = new Set();
311
+ for (const root of roots) {
312
+ await listCodexRoot(root, items, seen);
313
+ }
314
+ items.sort((a, b) => comparePaths(a.name, b.name));
315
+ return items;
316
+ }
317
+
318
+ /**
319
+ * Recursive walk of one item, sorted by relative POSIX path.
320
+ * Skips dot-names, sockets/FIFOs/devices, and symlinks whose realpath leaves the
321
+ * item's realpath root (in-root symlinks are followed and stored as files).
322
+ *
323
+ * @returns {Promise<{files?: Array<object>, error?: {reason: string, file: string}}>}
324
+ */
325
+ async function walkItem(realRoot) {
326
+ const files = [];
327
+ const stack = [{ abs: realRoot, rel: '' }];
328
+ // Real paths of directories already queued: an in-root symlink to an ancestor (a/loop -> ..)
329
+ // passes the containment check, so without this the walk would never end.
330
+ const visitedDirs = new Set([realRoot]);
331
+ while (stack.length) {
332
+ const current = stack.pop();
333
+ let dirents;
334
+ try {
335
+ dirents = await fsp.readdir(current.abs, { withFileTypes: true });
336
+ } catch (err) {
337
+ if (err && err.code === 'ENOENT') continue; // vanished mid-walk
338
+ return { error: { reason: 'unreadable', file: current.rel } };
339
+ }
340
+ const dirs = [];
341
+ for (const dirent of dirents.slice().sort((a, b) => comparePaths(a.name, b.name))) {
342
+ const name = dirent.name;
343
+ if (name.startsWith('.')) continue;
344
+ const abs = path.join(current.abs, name);
345
+ const rel = current.rel ? `${current.rel}/${name}` : name;
346
+ let realAbs = abs;
347
+ if (dirent.isSymbolicLink()) {
348
+ try {
349
+ realAbs = await fsp.realpath(abs);
350
+ } catch (err) {
351
+ if (err && err.code === 'ENOENT') continue; // dangling symlink
352
+ return { error: { reason: 'unreadable', file: rel } };
353
+ }
354
+ if (!isInside(realRoot, realAbs)) continue; // escapes the item folder
355
+ }
356
+ let stat;
357
+ try {
358
+ stat = await fsp.stat(abs);
359
+ } catch (err) {
360
+ if (err && err.code === 'ENOENT') continue;
361
+ return { error: { reason: 'unreadable', file: rel } };
362
+ }
363
+ if (stat.isDirectory()) {
364
+ if (visitedDirs.has(realAbs)) continue;
365
+ visitedDirs.add(realAbs);
366
+ dirs.push({ abs, rel });
367
+ continue;
368
+ }
369
+ if (!stat.isFile()) continue; // sockets, FIFOs, devices
370
+ files.push({
371
+ rel,
372
+ abs,
373
+ realAbs,
374
+ size: stat.size,
375
+ mtimeMs: stat.mtimeMs,
376
+ mode: (stat.mode & 0o111) !== 0 ? 0o555 : 0o444,
377
+ });
378
+ }
379
+ for (let i = dirs.length - 1; i >= 0; i -= 1) stack.push(dirs[i]);
380
+ }
381
+ files.sort((a, b) => comparePaths(a.rel, b.rel));
382
+ return { files };
383
+ }
384
+
385
+ /**
386
+ * D-10: first text file (sorted order) whose lines contain the hub home prefix.
387
+ * @returns {{file: string, line: number}|null}
388
+ */
389
+ function findHomePathHit(files, textByRel, needle) {
390
+ for (const file of files) {
391
+ const text = textByRel.get(file.rel);
392
+ if (text == null) continue;
393
+ const lines = text.split('\n');
394
+ for (let i = 0; i < lines.length; i += 1) {
395
+ if (lines[i].includes(needle)) return { file: file.rel, line: i + 1 };
396
+ }
397
+ }
398
+ return null;
399
+ }
400
+
401
+ function heldBackEntry(item, reason, extra) {
402
+ return Object.assign(
403
+ { agent: item.agent, kind: item.kind, name: item.name, reason },
404
+ extra || {},
405
+ );
406
+ }
407
+
408
+ async function platformsForItem(item, realRoot) {
409
+ if (item.kind === 'plugin') {
410
+ const text = await readTextOrNull(path.join(realRoot, '.claude-plugin', 'plugin.json'));
411
+ return text == null ? null : parsePluginJsonPlatforms(text);
412
+ }
413
+ const text = await readTextOrNull(path.join(realRoot, 'SKILL.md'));
414
+ return text == null ? null : parseFrontmatterPlatforms(text);
415
+ }
416
+
417
+ function entryPrefix(item) {
418
+ if (item.kind === 'plugin') return `plugins/${item.dirName}/`;
419
+ if (item.agent === 'codex') return `codex/${item.name}/`;
420
+ return `claude/.claude/skills/${item.name}/`;
421
+ }
422
+
423
+ /**
424
+ * Build the content-addressed bundle description of the hub's agent skills.
425
+ *
426
+ * @param {object} opts
427
+ * @param {'darwin'|'linux'|'win32'} opts.targetPlatform box platform (from its sync manifest probe)
428
+ * @param {string[]} [opts.excludePlugins] plugin ids excluded for this machine
429
+ * @param {NodeJS.ProcessEnv} [opts.env]
430
+ * @param {string} [opts.homeDir]
431
+ * @returns {Promise<object>} BundleBuild (see design §6.1)
432
+ */
433
+ async function buildAgentBundle({
434
+ targetPlatform,
435
+ excludePlugins = [],
436
+ env = process.env,
437
+ homeDir = os.homedir(),
438
+ }) {
439
+ const resolvedHome = String(homeDir).replace(/\/+$/, '') || '/';
440
+ const configDir = typeof env.CLAUDE_CONFIG_DIR === 'string' && env.CLAUDE_CONFIG_DIR.trim()
441
+ ? env.CLAUDE_CONFIG_DIR.trim()
442
+ : path.join(resolvedHome, '.claude');
443
+ const needle = `${resolvedHome}/`;
444
+
445
+ const items = [
446
+ ...(await listClaudeSkillItems(configDir)),
447
+ ...(await listPluginItems(configDir, excludePlugins)),
448
+ ...(await listCodexSkillItems(resolvedHome, env)),
449
+ ];
450
+
451
+ const entries = [];
452
+ const acceptedItems = [];
453
+ const heldBack = [];
454
+ const warnings = [];
455
+ const blobsByHash = new Map();
456
+ let totalBytes = 0;
457
+ let overLimit = false;
458
+
459
+ for (const item of items) {
460
+ if (overLimit) {
461
+ heldBack.push(heldBackEntry(item, 'too_large'));
462
+ continue;
463
+ }
464
+ if (item.collides) {
465
+ heldBack.push(heldBackEntry(item, 'name_collision'));
466
+ continue;
467
+ }
468
+ if (!item.rootDir) {
469
+ heldBack.push(heldBackEntry(item, 'unreadable'));
470
+ continue;
471
+ }
472
+ let realRoot;
473
+ try {
474
+ realRoot = await fsp.realpath(item.rootDir);
475
+ } catch (err) {
476
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) {
477
+ heldBack.push(heldBackEntry(item, 'unreadable'));
478
+ continue;
479
+ }
480
+ throw err;
481
+ }
482
+ const rootStat = await statOrNull(realRoot);
483
+ if (!rootStat || !rootStat.isDirectory()) {
484
+ heldBack.push(heldBackEntry(item, 'unreadable'));
485
+ continue;
486
+ }
487
+
488
+ // D-9 platform filter — skipped entirely when the author declared another platform.
489
+ const platforms = await platformsForItem(item, realRoot);
490
+ if (Array.isArray(platforms) && platforms.length > 0 && !platforms.includes(targetPlatform)) {
491
+ heldBack.push(heldBackEntry(item, 'platform', { file: platformFile(item) }));
492
+ continue;
493
+ }
494
+
495
+ const walked = await walkItem(realRoot);
496
+ if (walked.error) {
497
+ heldBack.push(heldBackEntry(item, walked.error.reason, { file: walked.error.file }));
498
+ continue;
499
+ }
500
+ const files = walked.files;
501
+
502
+ const oversized = files.find((file) => file.size > MAX_FILE_BYTES);
503
+ if (oversized) {
504
+ heldBack.push(heldBackEntry(item, 'too_large', { file: oversized.rel }));
505
+ continue;
506
+ }
507
+
508
+ const itemBytes = files.reduce((sum, file) => sum + file.size, 0);
509
+ if (totalBytes + itemBytes > MAX_BUNDLE_BYTES || entries.length + files.length > MAX_ENTRIES) {
510
+ overLimit = true;
511
+ heldBack.push(heldBackEntry(item, 'too_large'));
512
+ continue;
513
+ }
514
+
515
+ const hashed = [];
516
+ let unreadable = null;
517
+ const textByRel = new Map();
518
+ for (const file of files) {
519
+ let buffer;
520
+ try {
521
+ buffer = await fsp.readFile(file.abs);
522
+ } catch (err) {
523
+ unreadable = { reason: 'unreadable', file: file.rel };
524
+ break;
525
+ }
526
+ const hash = sha256Cache.get(`${file.realAbs}\0${file.size}\0${file.mtimeMs}`) || sha256Hex(buffer);
527
+ sha256Cache.set(`${file.realAbs}\0${file.size}\0${file.mtimeMs}`, hash);
528
+ if (isTextBuffer(buffer)) textByRel.set(file.rel, buffer.toString('utf8'));
529
+ hashed.push({ rel: file.rel, abs: file.abs, mode: file.mode, size: file.size, sha256: hash });
530
+ }
531
+ if (unreadable) {
532
+ heldBack.push(heldBackEntry(item, unreadable.reason, { file: unreadable.file }));
533
+ continue;
534
+ }
535
+
536
+ const prefix = entryPrefix(item);
537
+ const hit = findHomePathHit(hashed, textByRel, needle);
538
+ if (hit) {
539
+ if (item.kind === 'plugin') {
540
+ // D-10: we do not own third-party plugin text — warn, still ship it.
541
+ warnings.push({
542
+ kind: 'plugin',
543
+ name: item.name,
544
+ reason: 'hub_home_path',
545
+ file: hit.file,
546
+ line: hit.line,
547
+ });
548
+ } else {
549
+ heldBack.push(heldBackEntry(item, 'hub_home_path', { file: hit.file, line: hit.line }));
550
+ continue;
551
+ }
552
+ }
553
+
554
+ const itemEntries = hashed.map((file) => ({
555
+ path: `${prefix}${file.rel}`,
556
+ mode: file.mode,
557
+ sha256: file.sha256,
558
+ size: file.size,
559
+ }));
560
+ entries.push(...itemEntries);
561
+ for (const file of hashed) {
562
+ if (!blobsByHash.has(file.sha256)) blobsByHash.set(file.sha256, file.abs);
563
+ }
564
+ totalBytes += itemBytes;
565
+ acceptedItems.push({
566
+ agent: item.agent,
567
+ kind: item.kind,
568
+ name: item.name,
569
+ itemHash: computeTreeHash(hashed.map((file) => ({
570
+ path: file.rel,
571
+ mode: file.mode,
572
+ sha256: file.sha256,
573
+ size: file.size,
574
+ }))),
575
+ });
576
+ }
577
+
578
+ entries.sort((a, b) => comparePaths(a.path, b.path));
579
+
580
+ return {
581
+ schema: 1,
582
+ treeHash: computeTreeHash(entries),
583
+ entries,
584
+ items: acceptedItems,
585
+ heldBack,
586
+ warnings,
587
+ blobsByHash,
588
+ };
589
+ }
590
+
591
+ function platformFile(item) {
592
+ return item.kind === 'plugin' ? '.claude-plugin/plugin.json' : 'SKILL.md';
593
+ }
594
+
595
+ /**
596
+ * WP-7 (docs/remote-agent-skills-bundles-2026-10-25.html §6.2/§6.5): the build-IDENTICAL
597
+ * `items[].itemHash` of ONE item folder, for the box's own skill roots.
598
+ *
599
+ * This is the same walk (`walkItem`'s dot-name / symlink / mode rules) and the same canonical
600
+ * entry list `buildAgentBundle` folds into `items[].itemHash` — deliberately NOT
601
+ * lib/agent-bundle/codex-install.js's `dirHash`, which is a different hash of a different entry
602
+ * shape (WP-6's marker `sha256`, never comparable with an item hash). The box and the hub
603
+ * therefore agree on an item hash for identical bytes, which is what the classification rules
604
+ * compare (`tests/agent-bundle-inventory.test.js`).
605
+ *
606
+ * @param {string} rootDir the item folder (an item root, symlinks inside it are followed in-root)
607
+ * @returns {Promise<string|null>} `sha256:<64 hex>`, or null when the folder has vanished
608
+ * (ENOENT/ENOTDIR mid-walk) — an item that is not there is not an item, and a hash for it
609
+ * would be a lie. A genuine read fault is RETHROWN for the caller to REPORT.
610
+ */
611
+ async function itemHashOfDir(rootDir) {
612
+ let realRoot;
613
+ try {
614
+ realRoot = await fsp.realpath(String(rootDir == null ? '' : rootDir));
615
+ } catch (err) {
616
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) return null;
617
+ throw err;
618
+ }
619
+ const walked = await walkItem(realRoot);
620
+ if (walked.error) return null;
621
+ const hashed = [];
622
+ for (const file of walked.files) {
623
+ let buffer;
624
+ try {
625
+ buffer = await fsp.readFile(file.abs);
626
+ } catch (err) {
627
+ if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) return null; // vanished mid-walk
628
+ throw err; // RETHROW: a real read fault is the caller's to REPORT
629
+ }
630
+ const key = `${file.realAbs}\0${file.size}\0${file.mtimeMs}`;
631
+ const hash = sha256Cache.get(key) || sha256Hex(buffer);
632
+ sha256Cache.set(key, hash);
633
+ hashed.push({ path: file.rel, mode: file.mode, sha256: hash, size: file.size });
634
+ }
635
+ return computeTreeHash(hashed);
636
+ }
637
+
638
+ module.exports = {
639
+ buildAgentBundle,
640
+ computeTreeHash,
641
+ // WP-7: the box inventory hashes one item folder with the SAME walk and the SAME canonical entry
642
+ // list the builder uses — this export is the one hasher, so the two can never drift.
643
+ itemHashOfDir,
644
+ // WP-7: the box enumerates ITS skill roots with the SAME listers the hub enumerates its own
645
+ // (`synced/` skipped for Claude, `.system` skipped for Codex, `.agents` before `$CODEX_HOME`), so
646
+ // "the same skill" means the same folder on both sides.
647
+ listClaudeSkillItems,
648
+ listCodexSkillItems,
649
+ // WP-8: the export leg (`lib/agent-bundle/skill-transfer.js`) ships ONE item's bytes, and it walks
650
+ // that folder with THIS walk — the same dot-name/symlink/`isFile` rules the hub's own builder uses —
651
+ // so an exported item and a hub-built item of identical bytes carry the same entry list by
652
+ // construction, never by a second implementation of the same rules.
653
+ walkItem,
654
+ MAX_FILE_BYTES,
655
+ MAX_BUNDLE_BYTES,
656
+ MAX_ENTRIES,
657
+ };