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
@@ -10,6 +10,10 @@
10
10
  // a <script src="porter-stemmer.js"> tag (see public/index.html and
11
11
  // public/m/index.html) and hangs off `root.PorterStemmer`.
12
12
  const PorterStemmer = typeof require === 'function' ? require('./porter-stemmer') : root.PorterStemmer;
13
+ // The one command-to-agent rule (WP-2, S-8): the same UMD module the server re-exports. Under
14
+ // Node it is `require`d; in the browser it is loaded first via <script src="js/agent-command.js">
15
+ // (see public/index.html and public/m/index.html) and hangs off `root.CtmAgentCommand`.
16
+ const AgentCommand = typeof require === 'function' ? require('./agent-command') : root.CtmAgentCommand;
13
17
 
14
18
  const SESSION_ID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/ig;
15
19
  const SEARCH_WRAP_RE = /^[\s"'`“”‘’]+|[\s"'`“”‘’,.;:!?)}\]]+$/g;
@@ -809,10 +813,11 @@
809
813
  opencode: 'OpenCode',
810
814
  cursor: 'Cursor',
811
815
  'claude-desktop': 'Claude Desktop',
816
+ dsh: 'DeepSeek Harness',
812
817
  shell: 'Shell / Other',
813
818
  };
814
819
 
815
- const AGENT_FILTER_ORDER = ['codex', 'claude', 'walle', 'cursor', 'gemini', 'opencode', 'claude-desktop', 'shell'];
820
+ const AGENT_FILTER_ORDER = ['codex', 'claude', 'walle', 'cursor', 'gemini', 'opencode', 'dsh', 'claude-desktop', 'shell'];
816
821
 
817
822
  function normalizeRecentAgentType(value) {
818
823
  if (!value) return '';
@@ -826,6 +831,8 @@
826
831
  if (v === 'gemini-cli') return 'gemini';
827
832
  if (v === 'open-code' || v === 'opencode-cli') return 'opencode';
828
833
  if (v === 'cursor-agent' || v === 'cursor-cli') return 'cursor';
834
+ // WP-7 (S-54): the dsh aliases the server normalizes to `dsh` (lib/agent-capabilities.js).
835
+ if (v === 'deepseek-harness' || v === 'deepseek' || v === 'dsh') return 'dsh';
829
836
  if (v === 'terminal' || v === 'unknown' || v === 'other') return 'shell';
830
837
  return '';
831
838
  }
@@ -833,6 +840,11 @@
833
840
  function detectRecentAgentTypeFromText(value) {
834
841
  if (!value) return '';
835
842
  const v = String(value).toLowerCase();
843
+ // WP-7 (S-54): D-3 command-word match — `/x/dshell` must not read as dsh.
844
+ if (/^(?:\S*\/)?dsh(?:\s|$)/.test(v)) return 'dsh';
845
+ // WP-2 (S-8, D-4): the command word wins — `/x/codex/bin/claude` is `claude`, not `codex`.
846
+ // The substring fallbacks below stay for commands whose word names no agent.
847
+ const w = AgentCommand.agentTypeFromCommandWord(v); if (w) return w;
836
848
  if (v.includes('opencode') || v.includes('open-code')) return 'opencode';
837
849
  if (v.includes('cursor')) return 'cursor';
838
850
  if (v.includes('wall-e') || v.includes('walle')) return 'walle';
@@ -914,13 +926,17 @@
914
926
 
915
927
  const emptyMode = f.emptyMode || (f.showEmptyOnly ? 'only' : 'exclude');
916
928
  if (emptyMode === 'only' && !s.isEmpty) return false;
917
- if (emptyMode === 'exclude' && s.isEmpty) return false;
929
+ // D-7: a starred row stays visible even when empty — the default 'exclude' mode
930
+ // hides only UNstarred empty rows. Recent rows carry `starred` (lib/recent-catalog-query.js).
931
+ if (emptyMode === 'exclude' && s.isEmpty && !s.starred) return false;
918
932
 
919
933
  const project = stripWorktreePath(f.project || '');
920
934
  if (project && stripWorktreePath(s.project || s.cwd || '') !== project) return false;
921
935
 
922
936
  const agent = normalizeRecentAgentType(f.agent || '');
923
937
  if (agent && !getRecentSessionAgentTypes(s).includes(agent)) return false;
938
+ // G-1: computer filter. null/undefined = all; '' = Local (no machine key); else an instanceId.
939
+ if (typeof f.machine === 'string' && String(s.machine || '').trim() !== f.machine) return false;
924
940
  return true;
925
941
  }
926
942
 
@@ -7,6 +7,7 @@
7
7
  })(function() {
8
8
  'use strict';
9
9
  var fmt = (typeof window !== 'undefined' && window.CTMUsageFormat) || (typeof require === 'function' ? require('./usage-format.js') : null);
10
+ var pasted = (typeof window !== 'undefined' && window.PastedContent) || (typeof require === 'function' ? require('./pasted-content.js') : null);
10
11
  var RESTART_NOTICE = 'This server answers an older usage format — restart CTM.';
11
12
  var TABS = [['tasks', 'Tasks'], ['prompts', 'Prompts'], ['agents', 'Agents'], ['models', 'Models']];
12
13
  var CALLS_PAGE = 100;
@@ -511,7 +512,7 @@
511
512
  return '<div class="table-wrap"><table class="attribution"><thead>' + head + '</thead><tbody>' + body + '</tbody></table></div>';
512
513
  }
513
514
  function previewLabel(text) {
514
- var label = String(text || '').replace(/^\s*<pasted_content(?:\s[^>]*)?>\s*/i, '').replace(/\s*<\/pasted_content>\s*$/i, '');
515
+ var label = pasted ? pasted.previewText(String(text || '')) : String(text || '');
515
516
  var command = /^\s*<command-name>\s*([^<]+)\s*<\/command-name>\s*$/i.exec(label);
516
517
  return (command ? command[1].trim() : label) || '(no text)';
517
518
  }
@@ -10,6 +10,8 @@
10
10
  const GIT_STATES = ['checking', 'known', 'unknown', 'unavailable'];
11
11
  const PROVENANCE = ['current-snapshot', 'last-observed', 'configured', 'unavailable'];
12
12
  const UNAVAILABLE_CODES = ['WORKSPACE_IDENTITY_CHANGED', 'WORKSPACE_IDENTITY_UNAVAILABLE'];
13
+ // The radar's closed level set (§6.3). `unknown` is not a level; anything outside render nothing.
14
+ const LANDING_LEVELS = ['L0', 'L1', 'L1*', 'L2', 'L3'];
13
15
  // What the existing details panel calls each provenance — never "current" for a branch that
14
16
  // did not come from a matching fresh snapshot (D-6/AC-3c).
15
17
  const PROVENANCE_LABELS = {
@@ -124,6 +126,46 @@
124
126
  }
125
127
  return { kind: 'unknown', ref: '', display: 'unknown', label: 'Workspace context unavailable' };
126
128
  }
129
+ // WP-3b (§6.3): the landing-queue sub-view the same freshness gate publishes. Normalised here so
130
+ // a hand-built or older payload can never invent a position or a radar level, and `detailRows`
131
+ // never has to guess — an absent/`null` landing stays `null` (nothing to show).
132
+ function normaliseLanding(raw) {
133
+ if (!raw || typeof raw !== 'object') return null;
134
+ const radarRaw = raw.radar && typeof raw.radar === 'object' ? raw.radar : {};
135
+ const max = LANDING_LEVELS.includes(text(radarRaw.max)) ? text(radarRaw.max) : null;
136
+ const peers = (Array.isArray(radarRaw.with) ? radarRaw.with : [])
137
+ .filter((entry) => entry && typeof entry === 'object')
138
+ .map((entry) => ({ session: text(entry.session), branch: text(entry.branch), level: text(entry.level) }))
139
+ // A level outside the closed set is not a level, and a pair without a branch is not a pair.
140
+ .filter((entry) => entry.branch && LANDING_LEVELS.includes(entry.level));
141
+ return {
142
+ jobId: typeof raw.jobId === 'string' && raw.jobId ? raw.jobId : null,
143
+ // Only a string is a state word: a number/object would print as "[object Object]" in a row.
144
+ state: typeof raw.state === 'string' && raw.state.trim() ? raw.state.trim() : null,
145
+ position: typeof raw.position === 'number' && Number.isFinite(raw.position) ? raw.position : null,
146
+ total: typeof raw.total === 'number' && Number.isFinite(raw.total) ? raw.total : 0,
147
+ eta_s: typeof raw.eta_s === 'number' && Number.isFinite(raw.eta_s) ? raw.eta_s : null,
148
+ radar: { max, with: peers },
149
+ };
150
+ }
151
+ function landingEtaLabel(etaSeconds) {
152
+ return typeof etaSeconds === 'number' && Number.isFinite(etaSeconds)
153
+ ? `${Math.round(etaSeconds / 60)}m` : '';
154
+ }
155
+ // '#2 of 3 · queued · ETA 23m' — each clause is dropped when the payload does not carry it.
156
+ function landingJobLine(landing) {
157
+ const parts = [];
158
+ if (landing.position !== null) parts.push(`#${landing.position} of ${landing.total}`);
159
+ if (landing.state) parts.push(landing.state);
160
+ const eta = landingEtaLabel(landing.eta_s);
161
+ if (eta) parts.push(`ETA ${eta}`);
162
+ return parts.join(' · ');
163
+ }
164
+ // 'L3 with feat/x, L2 with feat/y' — the server sorts `with` strongest-first.
165
+ function landingRadarLine(radar) {
166
+ const peers = radar && Array.isArray(radar.with) ? radar.with : [];
167
+ return peers.map((entry) => `${entry.level} with ${entry.branch}`).join(', ');
168
+ }
127
169
  function present(tracking) {
128
170
  tracking = tracking || {};
129
171
  const selection = tracking.selection || {};
@@ -166,7 +208,7 @@
166
208
  && text(entry.workspaceIncarnation) === text(tracking.workspaceIncarnation)))
167
209
  .slice(0, 12);
168
210
  return {
169
- tracking, selection, git, matching, freshness, branch, provenance,
211
+ tracking, selection, git, matching, freshness, branch, provenance, landing: normaliseLanding(tracking.landing),
170
212
  // Mirrors the projection's own derivation for payloads that predate `git.state`: a fresh
171
213
  // snapshot is only "known" when its tracked state is — an unmeasured snapshot is unknown,
172
214
  // never a clean 0-file reading.
@@ -243,6 +285,14 @@
243
285
  const activityCheckout = checkoutLabel(view.selection.lastActivityCheckout);
244
286
  const currentCheckout = checkoutLabel(view.git.checkout);
245
287
  if (activityCheckout && activityCheckout !== currentCheckout) rows.push(['Last activity checkout', activityCheckout]);
288
+ // WP-3b: the landing-queue rows. Each is omitted when the payload carries nothing to show, so a
289
+ // repo with no queue renders exactly the rows it always did.
290
+ if (view.landing) {
291
+ const job = landingJobLine(view.landing);
292
+ if (job) rows.push(['Landing job', job]);
293
+ const radar = landingRadarLine(view.landing.radar);
294
+ if (radar) rows.push(['Radar', radar]);
295
+ }
246
296
  return rows;
247
297
  }
248
298
  function checkoutLabel(checkout) {
@@ -1083,7 +1083,16 @@
1083
1083
  const action = stateSyncFrameAction(baseline, frame);
1084
1084
  if (action === 'ignore') return action;
1085
1085
  if (action === 'request-keyframe') {
1086
- if (deps.requestKeyframe) deps.requestKeyframe('desync:base=' + frame.baseSeq + ',have=' + Number(baseline?.seq || 0));
1086
+ // WP-2 (D-6, §6/S-14): ONE desync request per (session, committed baseline seq). A pipelined
1087
+ // window can leave several base-mismatched deltas in flight after one desync, and every one
1088
+ // of them lands here -- only the first asks, and it tells the server the baseline it holds.
1089
+ // No timer and no reset hook: the answering keyframe moves baseline.seq, so the next desync
1090
+ // carries a different haveSeq and requests on its own. deps.onSkipped still fires per frame.
1091
+ const haveSeq = Number(baseline?.seq || 0);
1092
+ if (!session || session._stateSyncDesyncReqHaveSeq !== haveSeq) {
1093
+ if (session) session._stateSyncDesyncReqHaveSeq = haveSeq;
1094
+ if (deps.requestKeyframe) deps.requestKeyframe('desync:base=' + frame.baseSeq + ',have=' + haveSeq, { haveSeq });
1095
+ }
1087
1096
  if (typeof deps.onSkipped === 'function') deps.onSkipped('request-keyframe', frame);
1088
1097
  return action;
1089
1098
  }
@@ -589,9 +589,10 @@ function _tooltipAgentLabel(session, anchorEl) {
589
589
  return { walle: 'Wall-E', codex: 'Codex', gemini: 'Gemini', claude: 'Claude Code', shell: 'Shell' }[agent] || _tooltipStatusLabel(agent);
590
590
  }
591
591
  const cmd = _tooltipText(session?.meta?.cmd).toLowerCase();
592
- if (cmd.includes('codex')) return 'Codex';
593
- if (cmd.includes('gemini')) return 'Gemini';
594
- if (cmd.includes('claude')) return 'Claude Code';
592
+ // WP-2 (S-9, D-4): one command-word decision for every agent label.
593
+ const detected = window.CtmAgentCommand.detectAgentType(cmd);
594
+ const label = { claude: 'Claude Code', codex: 'Codex', gemini: 'Gemini', opencode: 'OpenCode', cursor: 'Cursor', dsh: 'DeepSeek Harness' }[detected];
595
+ if (label) return label;
595
596
  if (session?.meta?.type === 'walle') return 'Wall-E';
596
597
  return 'Session';
597
598
  }
@@ -794,7 +795,7 @@ function _syncStreamTooltipStatus() {
794
795
  const fresh = _tooltipStatusPill(session);
795
796
  if (pill.textContent !== fresh.textContent || pill.className !== fresh.className || pill.title !== fresh.title) pill.replaceWith(fresh);
796
797
  }
797
- if (typeof BackgroundWork !== 'undefined') BackgroundWork.syncTooltip(tooltip, session._statusRow?.backgroundWork, { cap: _tooltipCap, age: _tooltipAge }, (body) => _tooltipSection('Background work', body));
798
+ if (typeof BackgroundWork !== 'undefined') BackgroundWork.syncTooltip(tooltip, session._statusRow?.backgroundWork, { cap: _tooltipCap, age: _tooltipAge, sessionId: session.id }, (body) => _tooltipSection('Background work', body));
798
799
  const footer = tooltip.querySelector('[data-tooltip-footer]');
799
800
  if (footer) {
800
801
  const text = _tooltipFooterBits(session).join(' | ');
@@ -941,7 +942,7 @@ async function showStreamTooltip(sessionId, anchorEl, opts = {}) {
941
942
  _tooltipAppendAiSummary(content, summary.aiSummary, currentTask);
942
943
 
943
944
  _tooltipAppendProgress(content, summary.progress);
944
- if (typeof BackgroundWork !== 'undefined') BackgroundWork.syncTooltip(content, session?._statusRow?.backgroundWork, { cap: _tooltipCap, age: _tooltipAge }, (body) => _tooltipSection('Background work', body));
945
+ if (typeof BackgroundWork !== 'undefined') BackgroundWork.syncTooltip(content, session?._statusRow?.backgroundWork, { cap: _tooltipCap, age: _tooltipAge, sessionId: session?.id }, (body) => _tooltipSection('Background work', body));
945
946
 
946
947
  _streamState._tooltipFooterTail = [];
947
948
  if (summary.turnCount) _streamState._tooltipFooterTail.push(String(summary.turnCount) + ' turns');
@@ -0,0 +1,287 @@
1
+ 'use strict';
2
+
3
+ // WP-7 (S-52/S-57, AC-7b): the client capability table (CLIENT_AGENT_CAPABILITIES in index.html,
4
+ // reached through _ctmAgentCapsForSession / _clientAgentCaps) is the single source of truth for
5
+ // "does this session have a CLI (PTY/xterm) surface at all". dsh is conv-only, so its tab never
6
+ // builds an xterm — the rule is capability-driven, never agent-name-driven.
7
+ function _sessionClientCapsFor(id) {
8
+ const s = id && state.sessions.get(id);
9
+ if (!s && !id) return null;
10
+ if (typeof _ctmAgentCapsForSession === 'function') {
11
+ try {
12
+ const caps = _ctmAgentCapsForSession(id);
13
+ if (caps) return caps;
14
+ } catch (e) { /* expected: fall through to the session meta */ }
15
+ }
16
+ const meta = (s && s.meta) || {};
17
+ const at = meta.agentType || meta.agent_type || meta.type;
18
+ if (typeof _clientAgentCaps === 'function' && at) return _clientAgentCaps(at);
19
+ return null;
20
+ }
21
+
22
+ function _sessionCliUnavailable(id) {
23
+ const caps = _sessionClientCapsFor(id);
24
+ return !!(caps && caps.surfaces && caps.surfaces.cli && caps.surfaces.cli.available === false);
25
+ }
26
+
27
+ // The conv-only client shape: a `.term-container` (what setSessionView/activateTab expect) with no
28
+ // xterm, no PTY bootstrap and no pending attach. `createConversationView`/`setSessionView` mount the
29
+ // only surface such a session has.
30
+ function _ensureConvOnlySessionClientShape(id, meta) {
31
+ if (!id) return null;
32
+ const existing = state.sessions.get(id);
33
+ if (existing && existing._convOnly === true && existing.container
34
+ && existing.container.classList && existing.container.classList.contains('term-container')) {
35
+ existing.meta = { ...(existing.meta || {}), ...(meta || {}) };
36
+ return existing;
37
+ }
38
+ if (existing) {
39
+ _terminalReleaseSessionAttachmentSources(existing);
40
+ _disposeSessionClientSurface(existing);
41
+ }
42
+ let container = document.getElementById('term-' + id);
43
+ if (!container) {
44
+ container = document.createElement('div');
45
+ document.getElementById('terminal-area').appendChild(container);
46
+ }
47
+ container.className = 'term-container';
48
+ container.id = 'term-' + id;
49
+ container.dataset.sessionId = id;
50
+ setPaneVisible(container, _sessionSurfaceShouldBeVisible(id));
51
+ // The same conversation view createTerminal() mounts inside every terminal container — the only
52
+ // surface a conv-only session has.
53
+ if (typeof createConversationView === 'function' && !container.querySelector('.conversation-view')) {
54
+ const view = createConversationView(id);
55
+ // The composer sits under the view in the container's flex column: the view takes the rest.
56
+ Object.assign(view.style, { height: 'auto', flex: '1 1 auto', minHeight: '0' });
57
+ container.appendChild(view);
58
+ }
59
+ _ensureConvOnlyComposer(id, container);
60
+ const s = {
61
+ ...(existing || {}),
62
+ _id: id,
63
+ meta: { ...((existing && existing.meta) || {}), ...(meta || {}) },
64
+ container,
65
+ term: null,
66
+ fitAddon: null,
67
+ needsTerminal: false,
68
+ needsAttach: false,
69
+ _convOnly: true,
70
+ };
71
+ state.sessions.set(id, s);
72
+ _ensureConvOnlyModelControl(id, container);
73
+ if (typeof setSessionView === 'function') {
74
+ // expected: setSessionView needs a mounted conv view factory; the session surface falls back to
75
+ // the next frame's render, so a throw here is not a lost session.
76
+ try { setSessionView(id, 'conv'); } catch (e) { /* expected: conv surface mounts on the next frame */ }
77
+ }
78
+ return s;
79
+ }
80
+
81
+ // WP-7b: a conv-only tab gets the shared agent composer (AgentUIPrimitives.createComposer, the same
82
+ // primitive Wall-E's composer wraps). Send rides the generic submit-prompt path (window.submitPrompt,
83
+ // as the Queue Builder does); Stop is the generic interrupt-session the server maps to ACP cancel.
84
+ const CONV_ONLY_TERMINAL_STATUSES = new Set(['completed', 'failed', 'blocked', 'cancelled', 'rejected']);
85
+
86
+ function _convOnlyCaps(id) {
87
+ const caps = _sessionClientCapsFor(id);
88
+ return (caps && caps.input) || {};
89
+ }
90
+
91
+ // WP-11 (D-20): attach is a CAPABILITY, not a preference. `_convOnlyCaps(id).attachments` is true
92
+ // exactly when the session's LIVE child advertised `promptCapabilities.image` — the server row
93
+ // carries that as `imageInput` (lib/acp/dsh-session-runtime.js → lib/session-create/dsh-session.js
94
+ // → server.js `_sessionPayload.agentCapabilities.input`), which _ctmAgentCapsForSession merges over
95
+ // the static table. Until that projection lands the static `dsh` row's `attachments:false` wins, so
96
+ // the button hides and SAYS WHY (AC-11b/AC-11e).
97
+ const CONV_ONLY_ATTACH_DISABLED_TITLE =
98
+ 'Images are unavailable: this DeepSeek Harness agent did not advertise image prompt support.';
99
+ const CONV_ONLY_ATTACH_TITLE = 'Attach images';
100
+ // id → the images uploaded for that session's NEXT prompt. Cleared once the prompt is accepted, so a
101
+ // refused prompt keeps them for a retry.
102
+ const _convOnlyImages = new Map();
103
+
104
+ function _convOnlyAttachAllowed(id) {
105
+ return _convOnlyCaps(id).attachments === true;
106
+ }
107
+
108
+ function _convOnlyImageExtension(type) {
109
+ const t = String(type || '').toLowerCase();
110
+ if (t === 'image/jpeg' || t === 'image/jpg') return '.jpg';
111
+ if (t === 'image/webp') return '.webp';
112
+ if (t === 'image/gif') return '.gif';
113
+ return '.png';
114
+ }
115
+
116
+ // The desktop terminal composer's own upload, through the SAME two shared client modules it uses
117
+ // (public/index.html `_terminalUploadPastedImage`): window.CTMImage.normalizeForProvider, then
118
+ // window.CTMUploader against CTM's one upload store with the terminal path's `defer_row=1` row.
119
+ // Neither the normalizer nor the uploader is re-implemented here, and the ref list this returns is
120
+ // the shape lib/session-image-refs.js already resolves (`filename` is the served basename).
121
+ async function _convOnlyUploadImage(file, ordinal) {
122
+ const source = 'conv-image-' + Date.now() + '-' + ordinal + _convOnlyImageExtension(file && file.type);
123
+ const normalized = window.CTMImage && typeof window.CTMImage.normalizeForProvider === 'function'
124
+ ? await window.CTMImage.normalizeForProvider(file, { filename: source, useWorker: window.CTM_IMAGE_WORKER_NORMALIZE === true })
125
+ : { blob: file, filename: source, mimeType: (file && file.type) || 'image/png' };
126
+ const filename = normalized.filename || source;
127
+ const data = await window.CTMUploader.upload({
128
+ url: '/api/images/upload?prompt_id=0&defer_row=1&source=terminal-path&filename=' +
129
+ encodeURIComponent(filename) + '&token=' + encodeURIComponent(state.token || ''),
130
+ method: 'POST',
131
+ headers: { 'Content-Type': normalized.mimeType || (file && file.type) || 'image/png' },
132
+ body: normalized.blob || file,
133
+ });
134
+ if (!data || !data.filename) throw new Error((data && data.error) || 'Image upload failed');
135
+ return {
136
+ id: data.id || null,
137
+ filename: data.filename,
138
+ path: data.path || '',
139
+ url: '/api/images/file/' + encodeURIComponent(data.filename),
140
+ mimeType: normalized.mimeType || (file && file.type) || 'image/png',
141
+ kind: 'image',
142
+ status: 'ready',
143
+ };
144
+ }
145
+
146
+ // The manifest the desktop composer writes when a prompt with images is accepted: the SAME route and
147
+ // the same body (`_terminalRecordSessionImageRefs`, index.html). The join in lib/session-image-refs.js
148
+ // matches a manifest to the user row that names its `[Image #N]` token within five minutes.
149
+ async function _convOnlyRecordImageRefs(id, images, promptText) {
150
+ const response = await fetch('/api/sessions/' + encodeURIComponent(id) + '/image-refs?token=' + encodeURIComponent(state.token || ''), {
151
+ method: 'POST',
152
+ headers: { 'Content-Type': 'application/json' },
153
+ keepalive: true,
154
+ body: JSON.stringify({
155
+ sessionId: id,
156
+ submissionId: '',
157
+ submittedAt: Date.now(),
158
+ promptText: String(promptText || '').slice(0, 4096),
159
+ images: images.map((att) => ({
160
+ id: att.id || null, attachmentId: att.attachmentId || null, revision: null,
161
+ label: att.label || '', filename: att.filename || '', path: att.path || '', url: att.url || '',
162
+ confirmation: 'confirmed',
163
+ })),
164
+ }),
165
+ });
166
+ const data = await response.json().catch(() => ({}));
167
+ if (!response.ok || data.ok === false) throw new Error(data.error || 'Could not record session image references');
168
+ return data;
169
+ }
170
+
171
+ function _convOnlyUpdateAttachTitle(id, composer) {
172
+ const attach = composer && composer.querySelector('.agent-ui-button.subtle');
173
+ if (!attach) return;
174
+ const count = (_convOnlyImages.get(id) || []).length;
175
+ attach.title = count ? CONV_ONLY_ATTACH_TITLE + ' (' + count + ' attached)' : CONV_ONLY_ATTACH_TITLE;
176
+ }
177
+
178
+ async function _convOnlyAttachImages(id, files, composer) {
179
+ if (!_convOnlyAttachAllowed(id)) return false;
180
+ const incoming = Array.from(files || []).filter((file) => file && /^image\//i.test(String(file.type || '')));
181
+ if (!incoming.length) return false;
182
+ const images = _convOnlyImages.get(id) || [];
183
+ for (let index = 0; index < incoming.length; index += 1) {
184
+ try {
185
+ const uploaded = await _convOnlyUploadImage(incoming[index], images.length + 1);
186
+ uploaded.label = '[Image #' + (images.length + 1) + ']';
187
+ images.push(uploaded);
188
+ _convOnlyImages.set(id, images);
189
+ } catch (error) {
190
+ // HANDLE: one unreadable/failed file never blocks the composer or the other files.
191
+ console.warn('[conv-only] image upload failed:', error && error.message ? error.message : error);
192
+ }
193
+ }
194
+ _convOnlyUpdateAttachTitle(id, composer);
195
+ return images.length > 0;
196
+ }
197
+
198
+ function _ensureConvOnlyComposer(id, container) {
199
+ const primitives = typeof AgentUIPrimitives !== 'undefined' ? AgentUIPrimitives : null;
200
+ if (!primitives || typeof primitives.createComposer !== 'function') return null;
201
+ const existing = container.querySelector(':scope > .conv-only-composer');
202
+ if (existing) return existing;
203
+ const composer = primitives.createComposer({
204
+ className: 'conv-only-composer',
205
+ placeholder: 'Message the agent…',
206
+ accept: 'image/*',
207
+ // WP-11 (D-20): the Attach button opens the primitive's own hidden file input; the files go
208
+ // through CTM's upload store (see _convOnlyUploadImage) and ride the next prompt's
209
+ // `attachments`, exactly like the desktop composer's.
210
+ onFiles: (files) => { void _convOnlyAttachImages(id, files, composer); },
211
+ onSubmit: (_mode, text) => _convOnlySubmit(id, composer, text),
212
+ // Escape also calls onStop; only a running turn has anything to interrupt.
213
+ onStop: () => { if (_convOnlyRunning(composer) && typeof send === 'function') send({ type: 'interrupt-session', id }); },
214
+ });
215
+ const attach = composer.querySelector('.agent-ui-button.subtle');
216
+ if (attach) {
217
+ const allowed = _convOnlyAttachAllowed(id);
218
+ attach.hidden = !allowed;
219
+ attach.title = allowed ? CONV_ONLY_ATTACH_TITLE : CONV_ONLY_ATTACH_DISABLED_TITLE;
220
+ attach.setAttribute('aria-label', attach.title);
221
+ }
222
+ container.appendChild(composer);
223
+ return composer;
224
+ }
225
+
226
+ // WP-8 step 4: a conv-only tab has no `.session-toolbar`, so the shared model chip (the one every
227
+ // terminal tab gets) leads the composer's action row; the chip refresh paths find it inside the
228
+ // session container (_findSessionModelChip). It needs the registered session, so it mounts after
229
+ // state.sessions.set.
230
+ function _ensureConvOnlyModelControl(id, container) {
231
+ const actions = container.querySelector(':scope > .conv-only-composer .agent-ui-composer-actions');
232
+ if (!actions || actions.querySelector('.model-switch-control') || typeof createSessionModelControl !== 'function') return;
233
+ const control = createSessionModelControl(id);
234
+ if (control) actions.insertBefore(control, actions.firstChild);
235
+ }
236
+
237
+ function _convOnlyRunning(composer) {
238
+ return !!composer && composer.primaryButton.dataset.sendMode !== 'send';
239
+ }
240
+
241
+ // The text the provider AND the transcript see. The `[Image #N]` labels lead it exactly the way the
242
+ // desktop composer's canonical prompt carries them: lib/session-image-refs.js attaches a recorded
243
+ // manifest to the user row that NAMES the token, so an image prompt whose text omits it would
244
+ // reload without thumbnails even though the bytes reached the agent.
245
+ function _convOnlyWireText(value, images) {
246
+ const labels = images.map((att, index) => att.label || ('[Image #' + (index + 1) + ']'));
247
+ return labels.length ? labels.join(' ') + ' ' + value : value;
248
+ }
249
+
250
+ function _convOnlyAfterSubmit(id, composer, images, wireText, draft, record) {
251
+ if (!images.length) return;
252
+ const refused = !!(record && record.ok === false) || String((record && record.status) || '') === 'failed';
253
+ if (refused) return; // HANDLE: the server refused it; keep the images and the draft for a retry.
254
+ _convOnlyImages.delete(id);
255
+ _convOnlyUpdateAttachTitle(id, composer);
256
+ void _convOnlyRecordImageRefs(id, images, wireText).catch((error) => {
257
+ // REPORT: the prompt is already delivered; a manifest write only costs the reload thumbnail.
258
+ console.warn('[conv-only] session image ref recording failed:', error && error.message ? error.message : error);
259
+ });
260
+ }
261
+
262
+ function _convOnlySubmit(id, composer, text) {
263
+ const value = String(text || '').trim();
264
+ if (!value || typeof window.submitPrompt !== 'function') return;
265
+ // No queue capability (dsh: input.queue false): a second prompt waits for the turn to end.
266
+ if (_convOnlyRunning(composer) && _convOnlyCaps(id).queue !== true) return;
267
+ const images = (_convOnlyImages.get(id) || []).slice();
268
+ const wireText = _convOnlyWireText(value, images);
269
+ composer.input.value = '';
270
+ composer.setRunningState(true, 'queue', false);
271
+ Promise.resolve(window.submitPrompt(id, wireText, { source: 'web', attachments: images })).then(
272
+ (record) => _convOnlyAfterSubmit(id, composer, images, wireText, value, record),
273
+ () => {
274
+ // HANDLE: the prompt never left the client; give the text back and drop the running state.
275
+ composer.input.value = value;
276
+ composer.setRunningState(false, 'queue', false);
277
+ },
278
+ );
279
+ }
280
+
281
+ function _convOnlyHandleSubmitStatus(msg) {
282
+ const id = msg && msg.id;
283
+ const s = id && state.sessions.get(id);
284
+ if (!s || s._convOnly !== true || !CONV_ONLY_TERMINAL_STATUSES.has(String(msg.status || ''))) return;
285
+ const composer = s.container && s.container.querySelector(':scope > .conv-only-composer');
286
+ if (composer) composer.setRunningState(false, 'queue', false);
287
+ }
@@ -982,6 +982,8 @@ function _terminalSkillAutocompletePath(id, trigger) {
982
982
  if (agentType && agentType !== 'shell') params.set('agent', agentType);
983
983
  const cwd = s?.meta?.cwd || s?.cwd || s?.meta?.project || s?.project || '';
984
984
  if (cwd) params.set('cwd', cwd);
985
+ // remote-agent-skills WP-9 (S-9): a session on another machine gets that machine's skill list.
986
+ if (id) params.set('sessionId', String(id));
985
987
  return `/skills/autocomplete?${params.toString()}`;
986
988
  }
987
989
 
@@ -1431,20 +1431,20 @@ async function _terminalRaceAttachmentFreeze(id, draft, Draft, started, attachme
1431
1431
  }
1432
1432
  }
1433
1433
 
1434
- // The deadline-outcome handler for _terminalRaceAttachmentFreeze's 'deadline' result: flips
1435
- // the draft to indeterminate (some attachments already froze) or aborts it (none did),
1434
+ // The deadline-outcome handler for _terminalRaceAttachmentFreeze's 'deadline' result: aborts
1435
+ // the submission (R-2: Enter is never forwarded on this path, so nothing was committed to the
1436
+ // provider and the draft is presumed aborted -- the chips return to attached/unconfirmed),
1436
1437
  // renders, records the metric, flushes any input queued during the freeze wait, and toasts.
1437
1438
  // Top-level for the same size-ratchet reason as its caller.
1438
1439
  function _terminalHandleAttachmentSubmissionDeadline(id, draft, Draft, frozenCount, attachmentCount, deps) {
1439
- if (frozenCount > 0) Draft.markIndeterminate(draft, 'Image send timed out before Enter');
1440
- else Draft.abortSubmission(draft, 'deadline');
1440
+ const outcome = Draft.failSubmission(draft, 'Image send timed out before Enter');
1441
1441
  // F-E (review fix wave): this used to be a bare flush AFTER deps.renderDraft, whose own first
1442
1442
  // statement already settled -- so it saw an empty buffer and outcome:'deadline' was
1443
1443
  // unreachable. Settle with the outcome BEFORE the render (Enter is NOT forwarded here, so
1444
1444
  // this is also where the Enter boundary ends).
1445
1445
  _terminalSettleAttachmentDeferredInput(id, 'submission-deadline', 'deadline');
1446
1446
  deps.renderDraft(id);
1447
- deps.metric(id, 'submission_deadline', { attachmentCount, frozen: frozenCount });
1447
+ deps.metric(id, 'submission_deadline', { attachmentCount, frozen: frozenCount, outcome });
1448
1448
  if (typeof toast === 'function') {
1449
1449
  toast('Image send timed out — press Enter to try again', {
1450
1450
  type: 'warning', duration: 4000, key: 'terminal-attachment-submission-deadline',
@@ -569,6 +569,12 @@ function _pruneTerminalHotCache(activeId, opts) {
569
569
  }
570
570
  const protectedIds = new Set();
571
571
  if (activeId) protectedIds.add(activeId);
572
+ // WP-2 (docs/box-session-client-diag-and-reader-jump-2026-11-01.html): `activeId` is NOT always
573
+ // the tab on screen -- createTerminal (index.html:14908) prunes with the id of a BACKGROUND
574
+ // terminal it just built on a sessions-list update, which parked the on-screen reader (view
575
+ // snapped to bottom). The on-screen tab is skipped in the park and eviction loops below (its
576
+ // reader and WebGL renderer survive); it is NOT added to `protectedIds`, so the budget is unchanged.
577
+ const activeTabId = state.activeTab || null;
572
578
  if (state.splitRoot) {
573
579
  try {
574
580
  allLeaves(state.splitRoot).forEach(leaf => {
@@ -592,6 +598,7 @@ function _pruneTerminalHotCache(activeId, opts) {
592
598
  // split-teardown) as the rest of this function.
593
599
  for (const sid of liveIds) {
594
600
  if (protectedIds.has(sid)) continue; // R-3: never park activeTab or a split-visible pane by visibility/prune alone
601
+ if (activeTabId && sid === activeTabId) continue; // WP-2: the tab on screen keeps its reader no matter which id this pass was called with
595
602
  try { window.TerminalHistoryViewport?.park(sid, 'prune'); } catch { /* expected: best-effort -- a park failure here must never block the prune pass itself */ }
596
603
  }
597
604
 
@@ -600,7 +607,7 @@ function _pruneTerminalHotCache(activeId, opts) {
600
607
  let disposedCount = 0;
601
608
  for (const sid of [...state.terminalHotOrder]) {
602
609
  if (nonProtectedLiveCount <= liveBudget) break;
603
- if (protectedIds.has(sid)) continue;
610
+ if (protectedIds.has(sid) || (activeTabId && sid === activeTabId)) continue; // WP-2: the on-screen tab keeps its renderer too
604
611
  const s = state.sessions.get(sid);
605
612
  if (s && !s._exited) {
606
613
  _releaseWarmTerminalRenderer(s, 'hot-cache-live');
@@ -42,6 +42,10 @@ function _requestStateSyncKeyframe(id, options) {
42
42
  requestToken,
43
43
  priority: opts.priority === true,
44
44
  reason: String(opts.reason || '').slice(0, 48), // report-only
45
+ // WP-2 (D-6, §6/S-7): the client's own committed baseline seq, so the server can recognise a
46
+ // request its already-in-flight keyframe answers. Sent only when valid -- an omitted haveSeq
47
+ // means "old client" and is served exactly as today, while an explicit 0 means "no baseline".
48
+ ...(Number.isSafeInteger(opts.haveSeq) && opts.haveSeq >= 0 ? { haveSeq: opts.haveSeq } : {}),
45
49
  }) === true;
46
50
  }
47
51
 
@@ -1463,7 +1463,7 @@ function _ensureTerminalSessionClientShape(id, meta) {
1463
1463
  _disposeWalleSessionController(id, 'surface-replaced');
1464
1464
  state.sessions.delete(id);
1465
1465
  _presentationStore.removeSession(id);
1466
- if (warmLive) createTerminal(id, { active: false });
1466
+ if (warmLive) createTerminal(id, { active: false, agentType: meta?.agentType || meta?.type || '', agentCapabilities: meta?.agentCapabilities || null });
1467
1467
  else _createTerminalStub(id);
1468
1468
  existing = state.sessions.get(id);
1469
1469
  }