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,480 @@
1
+ 'use strict';
2
+
3
+ // WP-0 of docs/opencode-lead-and-delegate-model-selection-2026-10-28.html (§6.1):
4
+ // the OpenCode CLI adapter. Dependency-free. It asks the installed `opencode`
5
+ // binary exactly two questions — its version, and its model catalog
6
+ // (`models --verbose`) — through an injectable `execFile`, so tests never spawn a
7
+ // real process and no caller has to know the output shapes.
8
+ //
9
+ // Everything here is deliberately total: `opencodeVersion` never rejects
10
+ // (a missing/timed-out binary is `null`); `opencodeCatalog` rejects only with
11
+ // `.code === 'opencode_catalog_unavailable'`.
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+ const { execFile: nodeExecFile } = require('node:child_process');
16
+
17
+ const VERSION_TIMEOUT_MS = 5000;
18
+ const CATALOG_TIMEOUT_MS = 15000;
19
+ const CATALOG_CACHE_MS = 60000;
20
+ const MAX_BUFFER = 8 * 1024 * 1024;
21
+ // How far up from the binary's own directory `opencodeLine` looks for a
22
+ // package.json: the binary sits at `<pkg>/bin/opencode(.exe)` (1) or, for the
23
+ // scoped npm layout, `<pkg>/node_modules/@opencode/cli/bin/opencode.exe` — one
24
+ // level is enough, three leaves room for a wrapping shim.
25
+ const PACKAGE_LOOKUP_LEVELS = 3;
26
+
27
+ /** @typedef {{ major:number, minor:number, patch:number, raw:string, line:'v1'|'v2' }} OpencodeVersion */
28
+ /** @typedef {{ value:string, label:string, sublabel:string, kind:'model', provider:string,
29
+ * status:string, variants:string[], efforts:{ values:[], model_default:null } }} OpencodeLeadRow */
30
+
31
+ // Cache state, keyed by the resolved-bin key from _binCacheKey(). Version entries
32
+ // never expire (a binary's version only changes when its mtime changes); catalog
33
+ // entries carry the `now()` at which they were stored.
34
+ const versionCache = new Map();
35
+ const catalogCache = new Map();
36
+ // Last non-null async line detection (opencodeLine), keyed by the `bin` STRING as
37
+ // given (e.g. 'opencode') so the sync peekOpencodeLine() can answer the launch
38
+ // path without any fs. Only positive ('v1'/'v2') findings are stored: a `null` is
39
+ // never recorded, so a later opencodeVersion() can still supply the fallback.
40
+ const lineByBin = new Map();
41
+ // One in-flight child per (kind, bin key): concurrent callers await the same promise.
42
+ const inflight = new Map();
43
+
44
+ async function _isFile(candidate, fsImpl) {
45
+ try {
46
+ return (await fsImpl.stat(candidate)).isFile();
47
+ } catch {
48
+ /* expected: a missing or unreadable PATH candidate is simply not a match */
49
+ return false;
50
+ }
51
+ }
52
+
53
+ // A bare name is resolved by walking env.PATH; a resolved file is keyed by
54
+ // realpath + mtimeMs so an upgrade (or a differently-installed copy) misses the
55
+ // cache. Anything unresolvable falls back to the raw bin string, which is what
56
+ // tests pass (a non-existent name) so their cache keys stay plain.
57
+ async function _binCacheKey(bin, env) {
58
+ const raw = String(bin == null ? '' : bin);
59
+ try {
60
+ let resolved = null;
61
+ if (raw.includes('/')) {
62
+ resolved = raw;
63
+ } else {
64
+ const pathEnv = (env && env.PATH) || '';
65
+ for (const dir of String(pathEnv).split(path.delimiter)) {
66
+ if (!dir) continue;
67
+ const candidate = path.join(dir, raw);
68
+ if (await _isFile(candidate, fs.promises)) { resolved = candidate; break; }
69
+ }
70
+ }
71
+ if (resolved && await _isFile(resolved, fs.promises)) {
72
+ const real = await fs.promises.realpath(resolved);
73
+ const stat = await fs.promises.stat(real);
74
+ return `${real}:${stat.mtimeMs}`;
75
+ }
76
+ } catch {
77
+ /* expected: an unresolvable bin falls back to the raw name as its cache key */
78
+ }
79
+ return raw;
80
+ }
81
+
82
+ // The callback contract, deliberately not `promisify(execFile)`: an AbortSignal
83
+ // deadline is enforced here, around the callback, so an injected fake that never
84
+ // calls back still settles. The signal is also handed to execFile, which kills a
85
+ // real child on abort; the listener settles the injected-fake case the same way.
86
+ function _run(execFileImpl, bin, argv, env, timeoutMs) {
87
+ return new Promise((resolve, reject) => {
88
+ let settled = false;
89
+ const signal = AbortSignal.timeout(timeoutMs);
90
+ const finish = (fn, value) => {
91
+ if (settled) return;
92
+ settled = true;
93
+ signal.removeEventListener('abort', onAbort);
94
+ fn(value);
95
+ };
96
+ const onAbort = () => {
97
+ const err = new Error(`opencode "${argv[0]}" timed out after ${timeoutMs} ms`);
98
+ err.code = 'opencode_timeout';
99
+ finish(reject, err);
100
+ };
101
+ signal.addEventListener('abort', onAbort, { once: true });
102
+ try {
103
+ execFileImpl(bin, argv, {
104
+ env,
105
+ timeout: timeoutMs,
106
+ maxBuffer: MAX_BUFFER,
107
+ windowsHide: true,
108
+ signal,
109
+ }, (err, stdout) => {
110
+ if (err) finish(reject, err);
111
+ else finish(resolve, String(stdout == null ? '' : stdout));
112
+ });
113
+ } catch (err) {
114
+ finish(reject, err);
115
+ }
116
+ });
117
+ }
118
+
119
+ function _parseVersion(stdout) {
120
+ const match = String(stdout == null ? '' : stdout).match(/(\d+)\.(\d+)\.(\d+)/);
121
+ if (!match) return null;
122
+ const major = Number(match[1]);
123
+ return {
124
+ major,
125
+ minor: Number(match[2]),
126
+ patch: Number(match[3]),
127
+ raw: match[0],
128
+ line: major >= 2 ? 'v2' : 'v1',
129
+ };
130
+ }
131
+
132
+ function _catalogUnavailable(cause) {
133
+ const detail = cause && cause.message ? `: ${cause.message}` : '';
134
+ const err = new Error(`opencode_catalog_unavailable${detail}`);
135
+ err.code = 'opencode_catalog_unavailable';
136
+ if (cause !== undefined) err.cause = cause;
137
+ return err;
138
+ }
139
+
140
+ // Index just past the JSON object starting at `start` (which must be '{'), or -1
141
+ // when it never closes. Brace depth is tracked with string/escape awareness so a
142
+ // `{` or `}` inside a model description cannot truncate the slice.
143
+ function _matchJsonObject(text, start) {
144
+ let depth = 0;
145
+ let inString = false;
146
+ let escaped = false;
147
+ for (let i = start; i < text.length; i += 1) {
148
+ const ch = text[i];
149
+ if (inString) {
150
+ if (escaped) escaped = false;
151
+ else if (ch === '\\') escaped = true;
152
+ else if (ch === '"') inString = false;
153
+ continue;
154
+ }
155
+ if (ch === '"') { inString = true; continue; }
156
+ if (ch === '{') depth += 1;
157
+ else if (ch === '}') {
158
+ depth -= 1;
159
+ if (depth === 0) return i + 1;
160
+ if (depth < 0) return -1;
161
+ }
162
+ }
163
+ return -1;
164
+ }
165
+
166
+ /**
167
+ * Parses `<bin> models --verbose` stdout: repeated blocks of one `provider/model`
168
+ * line (it may carry extra slashes and `@`, e.g.
169
+ * `doordash/@fireworks/accounts/fireworks/models/glm-5p2`) followed by exactly one
170
+ * pretty-printed JSON object. Garbage between blocks is skipped.
171
+ * @param {string} stdout
172
+ * @returns {Array<{ value: string, row: object }>}
173
+ */
174
+ function parseModelsVerbose(stdout) {
175
+ const text = String(stdout == null ? '' : stdout);
176
+ const out = [];
177
+ let i = 0;
178
+ while (i < text.length) {
179
+ let lineEnd = text.indexOf('\n', i);
180
+ if (lineEnd < 0) lineEnd = text.length;
181
+ const value = text.slice(i, lineEnd).trim();
182
+ i = lineEnd + 1;
183
+ if (!value || value.includes('{') || !value.includes('/')) continue;
184
+ let j = i;
185
+ while (j < text.length && /\s/.test(text[j])) j += 1;
186
+ if (text[j] !== '{') continue;
187
+ const end = _matchJsonObject(text, j);
188
+ if (end < 0) continue;
189
+ let row = null;
190
+ try {
191
+ row = JSON.parse(text.slice(j, end));
192
+ } catch {
193
+ /* expected: a truncated or non-JSON block is skipped, not fatal */
194
+ continue;
195
+ }
196
+ if (!row || typeof row !== 'object' || Array.isArray(row)) continue;
197
+ out.push({ value, row });
198
+ i = end;
199
+ }
200
+ return out;
201
+ }
202
+
203
+ /**
204
+ * Pure. One catalog entry → one picker row.
205
+ * @param {string} value the `provider/model` id printed by the CLI
206
+ * @param {object} row the decoded JSON object
207
+ * @returns {OpencodeLeadRow}
208
+ */
209
+ function opencodeRow(value, row) {
210
+ const r = row && typeof row === 'object' && !Array.isArray(row) ? row : {};
211
+ return {
212
+ value,
213
+ label: r.name || value,
214
+ sublabel: value,
215
+ kind: 'model',
216
+ provider: r.providerID || String(value).split('/')[0],
217
+ status: r.status || 'active',
218
+ variants: Object.keys(r.variants || {}),
219
+ efforts: { values: [], model_default: null },
220
+ };
221
+ }
222
+
223
+ /**
224
+ * `<bin> --version` (timeout VERSION_TIMEOUT_MS), cached per bin key forever.
225
+ * Resolves `null` — never rejects — when the binary is missing, times out, or
226
+ * prints no `x.y.z`. A failed call is not cached.
227
+ * @param {{ bin?:string, env?:object, execFile?:Function, now?:Function, timeoutMs?:number }} [opts]
228
+ * @returns {Promise<OpencodeVersion|null>}
229
+ */
230
+ async function opencodeVersion(opts = {}) {
231
+ const {
232
+ bin = 'opencode',
233
+ env = process.env,
234
+ execFile = nodeExecFile,
235
+ now = Date.now, // eslint-disable-line no-unused-vars -- accepted for API symmetry
236
+ timeoutMs = VERSION_TIMEOUT_MS,
237
+ } = opts;
238
+ const key = await _binCacheKey(bin, env);
239
+ if (versionCache.has(key)) return versionCache.get(key);
240
+
241
+ const flightKey = `version:${key}`;
242
+ if (inflight.has(flightKey)) return inflight.get(flightKey);
243
+
244
+ const promise = (async () => {
245
+ try {
246
+ const stdout = await _run(execFile, bin, ['--version'], env, timeoutMs);
247
+ return { ok: true, value: _parseVersion(stdout) };
248
+ } catch {
249
+ /* expected: missing/timed-out/denied binary -> null, and not cached */
250
+ return { ok: false, value: null };
251
+ }
252
+ })();
253
+ inflight.set(flightKey, promise);
254
+ try {
255
+ const result = await promise;
256
+ if (result.ok) versionCache.set(key, result.value);
257
+ return result.value;
258
+ } finally {
259
+ inflight.delete(flightKey);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Pure. OpenCode 2.x `models` output → entries: one trimmed `provider/model` id per line (the id
265
+ * may hold more `/` and `@` after the provider); lines with spaces or no `/` are skipped, and a
266
+ * repeated id keeps its first entry. 2.x prints no metadata, so every `row` is `{}`.
267
+ * @param {string} stdout
268
+ * @returns {Array<{ value: string, row: object }>}
269
+ */
270
+ function parseModelsList(stdout) {
271
+ const seen = new Set();
272
+ const out = [];
273
+ for (const raw of String(stdout == null ? '' : stdout).split('\n')) {
274
+ const value = raw.trim();
275
+ if (!/^[^\s/]+\/\S+$/.test(value) || seen.has(value)) continue;
276
+ seen.add(value);
277
+ out.push({ value, row: {} });
278
+ }
279
+ return out;
280
+ }
281
+
282
+ /**
283
+ * The catalog of the INSTALLED line (timeout CATALOG_TIMEOUT_MS): 1.x runs `<bin> models --verbose`;
284
+ * 2.x has no `--verbose` (it exits "Unrecognized flag") and runs `<bin> models --standalone`, a
285
+ * private server, so the providers of this process's own inline config are listed too (the shared
286
+ * background service ignores that config, docs/opencode-v2-model-switch-standalone-plugin-2026-10-30.html
287
+ * P-S4). `opts.line` is a test seam; by default the line comes from opencodeLine(). Deprecated rows are
288
+ * dropped and the rest sorted by label; the result is cached for
289
+ * CATALOG_CACHE_MS. Rejects with `.code === 'opencode_catalog_unavailable'`
290
+ * (cause preserved on `.cause`) on error, timeout, or zero parsed rows.
291
+ * @param {{ bin?:string, env?:object, execFile?:Function, now?:Function, timeoutMs?:number, line?:'v1'|'v2'|null }} [opts]
292
+ * @returns {Promise<OpencodeLeadRow[]>}
293
+ */
294
+ async function opencodeCatalog(opts = {}) {
295
+ const {
296
+ bin = 'opencode',
297
+ env = process.env,
298
+ execFile = nodeExecFile,
299
+ now = Date.now,
300
+ timeoutMs = CATALOG_TIMEOUT_MS,
301
+ } = opts;
302
+ // One bin key (realpath + mtime) is one install, so it is one line: the cache needs no line in its key.
303
+ const key = await _binCacheKey(bin, env);
304
+ const cached = catalogCache.get(key);
305
+ if (cached && now() - cached.at < CATALOG_CACHE_MS) return cached.rows;
306
+
307
+ const flightKey = `catalog:${key}`;
308
+ if (inflight.has(flightKey)) return inflight.get(flightKey);
309
+
310
+ const promise = (async () => {
311
+ const line = opts.line !== undefined ? opts.line : await opencodeLine({ bin, env });
312
+ const argv = line === 'v2' ? ['models', '--standalone'] : ['models', '--verbose'];
313
+ let stdout;
314
+ try {
315
+ stdout = await _run(execFile, bin, argv, env, timeoutMs);
316
+ } catch (err) {
317
+ throw _catalogUnavailable(err);
318
+ }
319
+ const parsed = line === 'v2' ? parseModelsList(stdout) : parseModelsVerbose(stdout);
320
+ if (!parsed.length) {
321
+ throw _catalogUnavailable(new Error(`no model rows parsed from \`${argv.join(' ')}\``));
322
+ }
323
+ const rows = parsed
324
+ .map(({ value, row }) => opencodeRow(value, row))
325
+ .filter((row) => row.status !== 'deprecated')
326
+ .sort((a, b) => a.label.localeCompare(b.label));
327
+ catalogCache.set(key, { at: now(), rows });
328
+ return rows;
329
+ })();
330
+ inflight.set(flightKey, promise);
331
+ try {
332
+ return await promise;
333
+ } finally {
334
+ inflight.delete(flightKey);
335
+ }
336
+ }
337
+
338
+ // A bare name is resolved by walking env.PATH; a path is used as-is. Either way
339
+ // the realpath is returned so the package.json walk starts at the real install
340
+ // location (a `bin/opencode` symlink is the common shape). Unresolvable → null.
341
+ async function _resolveBinFile(bin, env, fsImpl) {
342
+ const raw = String(bin == null ? '' : bin);
343
+ try {
344
+ if (raw.includes('/')) {
345
+ return (await _isFile(raw, fsImpl)) ? await fsImpl.realpath(raw) : null;
346
+ }
347
+ const pathEnv = (env && env.PATH) || '';
348
+ for (const dir of String(pathEnv).split(path.delimiter)) {
349
+ if (!dir) continue;
350
+ const candidate = path.join(dir, raw);
351
+ if (await _isFile(candidate, fsImpl)) return await fsImpl.realpath(candidate);
352
+ }
353
+ } catch {
354
+ /* expected: an unresolvable or broken bin has no line to report */
355
+ return null;
356
+ }
357
+ return null;
358
+ }
359
+
360
+ async function _readPackageJson(dir, fsImpl) {
361
+ try {
362
+ const parsed = JSON.parse(await fsImpl.readFile(path.join(dir, 'package.json'), 'utf8'));
363
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
364
+ } catch {
365
+ /* expected: a missing/invalid package.json is simply not a match */
366
+ return null;
367
+ }
368
+ }
369
+
370
+ // Only the two package names CTM has measured mean anything here; a version
371
+ // without a parseable major is treated as v1 (`opencode-ai` has always been 1.x
372
+ // where it accepted `--model`).
373
+ function _lineFromPackageJson(pkg) {
374
+ const name = String(pkg && pkg.name ? pkg.name : '').trim();
375
+ if (name === '@opencode/cli') return 'v2';
376
+ if (name === 'opencode-ai') {
377
+ const major = Number.parseInt(String(pkg.version || '').split('.')[0], 10);
378
+ return Number.isFinite(major) && major >= 2 ? 'v2' : 'v1';
379
+ }
380
+ return null;
381
+ }
382
+
383
+ /**
384
+ * Async, no spawn. Resolves `bin` (bare name → walk env.PATH; a path → as is),
385
+ * realpath, then walks up at most PACKAGE_LOOKUP_LEVELS directories from the
386
+ * binary's directory for a package.json. name '@opencode/cli' → 'v2'; name
387
+ * 'opencode-ai' → 'v2' if version major >= 2 else 'v1'. Otherwise falls back to
388
+ * the cached result of a previous opencodeVersion() for the same cache key, else
389
+ * null. A non-null result is recorded in `lineByBin` under the `bin` string as
390
+ * given, so the sync peekOpencodeLine() can answer later without any fs. Never
391
+ * rejects.
392
+ * @param {{ bin?:string, env?:object, fsImpl?:object }} [opts]
393
+ * @returns {Promise<'v1'|'v2'|null>}
394
+ */
395
+ async function opencodeLine({ bin = 'opencode', env = process.env, fsImpl = fs.promises } = {}) {
396
+ const binKey = String(bin == null ? '' : bin);
397
+ const key = await _binCacheKey(bin, env);
398
+ let line = null;
399
+ try {
400
+ const resolved = await _resolveBinFile(bin, env, fsImpl);
401
+ if (resolved) {
402
+ let dir = path.dirname(resolved);
403
+ for (let i = 0; i <= PACKAGE_LOOKUP_LEVELS && dir; i += 1) {
404
+ const pkg = await _readPackageJson(dir, fsImpl);
405
+ if (pkg) {
406
+ line = _lineFromPackageJson(pkg);
407
+ break;
408
+ }
409
+ const parent = path.dirname(dir);
410
+ if (parent === dir) break;
411
+ dir = parent;
412
+ }
413
+ }
414
+ } catch {
415
+ /* expected: any fs surprise degrades to the cached-version fallback */
416
+ line = null;
417
+ }
418
+
419
+ if (!line) {
420
+ const cachedVersion = versionCache.get(key);
421
+ line = (cachedVersion && cachedVersion.line) || null;
422
+ }
423
+ if (line) lineByBin.set(binKey, line);
424
+ return line;
425
+ }
426
+
427
+ /**
428
+ * R-6 (docs/opencode-v2-model-switch-standalone-plugin-2026-10-30.html §5.1/§6.1): prime the line
429
+ * for `bin` ASYNCHRONOUSLY, before any OpenCode launch argv is built. server.js's handleCreate
430
+ * awaits this once, at the top of an OpenCode create/restore, so the sync argv path can then read
431
+ * the answer with no fs at all (peekOpencodeLine). Returns the peeked line when one is already
432
+ * known, else the result of opencodeLine() — which memoises into `lineByBin` and, by its own
433
+ * contract, never rejects (a missing/unreadable bin is `null`). Never rejects here either.
434
+ * @param {{ bin?:string, env?:object }} [opts]
435
+ * @returns {Promise<'v1'|'v2'|null>}
436
+ */
437
+ async function primeOpencodeLine({ bin = 'opencode', env = process.env } = {}) {
438
+ const known = peekOpencodeLine({ bin });
439
+ if (known) return known;
440
+ try {
441
+ return await opencodeLine({ bin, env });
442
+ } catch {
443
+ /* expected: opencodeLine never rejects, but a prime must not be able to fail a launch */
444
+ return null;
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Sync, NO fs, NO spawn: the last non-null opencodeLine() result for this `bin`
450
+ * string, else null. The launch path calls this so it never blocks on the fs.
451
+ * @param {{ bin?:string }} [opts]
452
+ * @returns {'v1'|'v2'|null}
453
+ */
454
+ function peekOpencodeLine({ bin = 'opencode' } = {}) {
455
+ const binKey = String(bin == null ? '' : bin);
456
+ return lineByBin.get(binKey) || null;
457
+ }
458
+
459
+ /** Tests only: drop every cached version, catalog, line, and in-flight entry. */
460
+ function _resetOpencodeCliCache() {
461
+ versionCache.clear();
462
+ catalogCache.clear();
463
+ lineByBin.clear();
464
+ inflight.clear();
465
+ }
466
+
467
+ module.exports = {
468
+ opencodeVersion,
469
+ opencodeCatalog,
470
+ opencodeLine,
471
+ primeOpencodeLine,
472
+ peekOpencodeLine,
473
+ opencodeRow,
474
+ parseModelsVerbose,
475
+ parseModelsList,
476
+ _resetOpencodeCliCache,
477
+ VERSION_TIMEOUT_MS,
478
+ CATALOG_TIMEOUT_MS,
479
+ CATALOG_CACHE_MS,
480
+ };