mixdog 1.3.5 → 1.4.1

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 (515) hide show
  1. package/NOTICE.md +2 -2
  2. package/README.md +2 -2
  3. package/package.json +2 -11
  4. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/gate-local.mjs +16 -5
  7. package/scripts/latest-guard.mjs +21 -9
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +37 -37
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +123 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/native-release-status.mjs +2 -2
  14. package/scripts/post-release-check.mjs +1 -6
  15. package/scripts/pptx-kit-index.mjs +17 -4
  16. package/scripts/recall-history-cases.json +1 -1
  17. package/scripts/suite-health.mjs +20 -2
  18. package/scripts/test-data-dir.mjs +10 -7
  19. package/scripts/test.mjs +7 -11
  20. package/src/agents/reviewer/AGENT.md +7 -11
  21. package/src/agents/reviewer/agent.json +1 -1
  22. package/src/app.mjs +4 -0
  23. package/src/defaults/shipped-history.json +22 -1
  24. package/src/defaults/skills/browser-use/SKILL.md +62 -12
  25. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  26. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  27. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  28. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  29. package/src/defaults/skills/computer-use/SKILL.md +35 -9
  30. package/src/defaults/skills/setup/SKILL.md +22 -0
  31. package/src/defaults/skills/setup/references/actions.md +39 -5
  32. package/src/defaults/skills/setup/references/surfaces.md +11 -2
  33. package/src/defaults/skills/visualize/SKILL.md +2 -1
  34. package/src/lib/rules-builder.cjs +39 -20
  35. package/src/output-styles/common.md +2 -2
  36. package/src/output-styles/simple.md +1 -1
  37. package/src/rules/agent/AGENT.md +11 -10
  38. package/src/rules/lead/LEAD.md +23 -20
  39. package/src/rules/shared/05-tool-calls.md +5 -6
  40. package/src/rules/shared/10-tool-workflow.md +4 -0
  41. package/src/rules/shared/45-destructive.md +0 -2
  42. package/src/rules/shared/50-execution.md +2 -0
  43. package/src/rules/shared/60-verification.md +7 -5
  44. package/src/rules/shared/70-delivery.md +7 -9
  45. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
  46. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  47. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  49. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  50. package/src/runtime/agent/orchestrator/config.mjs +17 -1
  51. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  52. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
  53. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
  54. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  55. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
  56. package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
  57. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
  58. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
  59. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
  60. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  63. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  66. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
  71. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  72. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
  73. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  74. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  75. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
  76. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  77. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  78. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  79. package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
  83. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  84. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  85. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  87. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  88. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  89. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  90. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  91. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  92. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  93. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  106. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  107. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
  109. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  113. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
  117. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  118. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  119. package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
  120. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  121. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  122. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
  131. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  132. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  133. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
  134. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  136. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  137. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  138. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
  139. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  140. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  141. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  142. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
  143. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
  144. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  145. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  146. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
  147. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
  148. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
  149. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
  150. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  151. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
  153. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
  154. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
  155. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  158. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
  159. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
  162. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  163. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  164. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
  165. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  166. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
  167. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  168. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  172. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  173. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  174. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
  175. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  176. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  177. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
  178. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
  179. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
  182. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
  183. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
  185. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  187. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
  188. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
  189. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  191. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
  192. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  193. package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  203. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
  209. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
  214. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  217. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  218. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  225. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
  226. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
  227. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  228. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
  229. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  231. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  232. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  233. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  234. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  235. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  236. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  237. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  238. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  239. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  240. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  241. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
  243. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  244. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  245. package/src/runtime/browser-bridge/client.mjs +73 -8
  246. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  247. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  248. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  249. package/src/runtime/channels/lib/config.mjs +6 -61
  250. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  251. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  252. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  253. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  254. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  255. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  256. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  257. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  258. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  259. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  260. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  261. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  262. package/src/runtime/channels/lib/scheduler.mjs +33 -147
  263. package/src/runtime/channels/lib/schedules-db.mjs +34 -11
  264. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  265. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
  266. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  267. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  268. package/src/runtime/channels/lib/whisper-port.mjs +10 -1
  269. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  270. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  271. package/src/runtime/channels/lib/worker-main.mjs +10 -34
  272. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  273. package/src/runtime/computer-bridge/actions.mjs +9 -1
  274. package/src/runtime/computer-bridge/client.mjs +180 -8
  275. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  276. package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
  277. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  278. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  279. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  280. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  281. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  282. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  283. package/src/runtime/connectors/google-mcp.mjs +10 -12
  284. package/src/runtime/local-provider/server-process.mjs +2 -1
  285. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  286. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  287. package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
  288. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  289. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  290. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  291. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  292. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  293. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  294. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  295. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  296. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  297. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  298. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  299. package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
  300. package/src/runtime/office/quality/design-review.mjs +1 -5
  301. package/src/runtime/office/quality/document-brief.mjs +1 -5
  302. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  303. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  304. package/src/runtime/session-search/session-search-db.mjs +73 -9
  305. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  306. package/src/runtime/shared/abort-race.mjs +89 -0
  307. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  308. package/src/runtime/shared/agent-kind.mjs +4 -3
  309. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  310. package/src/runtime/shared/bounded-download.mjs +8 -3
  311. package/src/runtime/shared/config.mjs +2 -13
  312. package/src/runtime/shared/connector-accounts.mjs +20 -10
  313. package/src/runtime/shared/connector-catalog.d.mts +29 -0
  314. package/src/runtime/shared/connector-catalog.mjs +150 -0
  315. package/src/runtime/shared/connector-triggers.mjs +22 -19
  316. package/src/runtime/shared/defaults-separation.mjs +2 -17
  317. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  318. package/src/runtime/shared/err-text.mjs +24 -15
  319. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  320. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  321. package/src/runtime/shared/file-permissions.d.mts +0 -8
  322. package/src/runtime/shared/file-permissions.mjs +0 -11
  323. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  324. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  325. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  326. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  327. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  328. package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
  329. package/src/runtime/shared/llm/cost.mjs +5 -1
  330. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  331. package/src/runtime/shared/loopback-listener.mjs +25 -2
  332. package/src/runtime/shared/mixy-presence.mjs +22 -0
  333. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  334. package/src/runtime/shared/model-route-chain.mjs +22 -4
  335. package/src/runtime/shared/open-url.mjs +10 -0
  336. package/src/runtime/shared/orchestration.d.mts +2 -0
  337. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  338. package/src/runtime/shared/profile-config.cjs +1 -1
  339. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  340. package/src/runtime/shared/prompt-origin.mjs +21 -0
  341. package/src/runtime/shared/provider-accounts.mjs +7 -1
  342. package/src/runtime/shared/provider-display-name.mjs +29 -0
  343. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  344. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  345. package/src/runtime/shared/routine-trigger.mjs +10 -0
  346. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  347. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  348. package/src/runtime/shared/session-activity-signal.mjs +48 -1
  349. package/src/runtime/shared/session-scratch.mjs +37 -0
  350. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  351. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  352. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  353. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  354. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  355. package/src/runtime/shared/tool-result-summary.mjs +2 -15
  356. package/src/runtime/shared/tool-surface.mjs +3 -0
  357. package/src/runtime/shared/tool-work-units.mjs +2 -0
  358. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  359. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  360. package/src/runtime/shared/worktrees/git.mjs +15 -0
  361. package/src/runtime/shared/worktrees/manager.mjs +87 -38
  362. package/src/runtime/shared/worktrees/test-support.mjs +14 -13
  363. package/src/runtime/terminal-bridge/client.mjs +10 -1
  364. package/src/runtime/visualize-bridge/client.mjs +29 -8
  365. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  366. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  367. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  368. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  369. package/src/session-runtime/agent-home-delivery.mjs +489 -185
  370. package/src/session-runtime/agent-task-sessions.mjs +467 -229
  371. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  372. package/src/session-runtime/boot/apis.mjs +9 -0
  373. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  374. package/src/session-runtime/boot/providers.mjs +3 -0
  375. package/src/session-runtime/boot/tools.mjs +11 -2
  376. package/src/session-runtime/bot-status.mjs +12 -6
  377. package/src/session-runtime/bot-target.mjs +38 -0
  378. package/src/session-runtime/channel-config-api.mjs +6 -1
  379. package/src/session-runtime/config-lifecycle.mjs +6 -0
  380. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  381. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  382. package/src/session-runtime/conversation-import/discovery.mjs +271 -25
  383. package/src/session-runtime/conversation-import/service.mjs +26 -5
  384. package/src/session-runtime/handoff-attachments.mjs +82 -31
  385. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
  386. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
  387. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  388. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
  389. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  390. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  391. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  392. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  393. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  394. package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
  395. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  396. package/src/session-runtime/mixy-heartbeat.mjs +153 -33
  397. package/src/session-runtime/model-route/set-route.mjs +11 -2
  398. package/src/session-runtime/notification-bus.mjs +31 -117
  399. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  400. package/src/session-runtime/notification-listeners.mjs +76 -0
  401. package/src/session-runtime/owned-automation-run.mjs +2 -1
  402. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  403. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  404. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  405. package/src/session-runtime/provider-models.mjs +4 -2
  406. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  407. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  408. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  409. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  410. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  411. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  412. package/src/session-runtime/resource-recall-api.mjs +6 -1
  413. package/src/session-runtime/routine-owner.mjs +40 -9
  414. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  415. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  416. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  417. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  418. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  419. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  420. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  422. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  423. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  424. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  425. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  426. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  427. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  428. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  429. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  430. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  431. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  432. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  433. package/src/session-runtime/services/channel-admin.mjs +7 -13
  434. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  435. package/src/session-runtime/services/provider-admin.mjs +2 -1
  436. package/src/session-runtime/services/seeds.mjs +0 -28
  437. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  438. package/src/session-runtime/session-create/session-options.mjs +1 -0
  439. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  440. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  441. package/src/session-runtime/settings-system-api.mjs +13 -1
  442. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  443. package/src/session-runtime/setup-tool/executor.mjs +145 -22
  444. package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
  445. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  446. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
  447. package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
  448. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  449. package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
  450. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  451. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  452. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
  453. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  454. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  455. package/src/session-runtime/workspace/transitions.mjs +25 -0
  456. package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
  457. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  458. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  459. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  460. package/src/standalone/channel-transport.mjs +1 -1
  461. package/src/standalone/daemon-channels-loader.mjs +10 -8
  462. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  463. package/src/standalone/daemon-session-control/request.mjs +51 -0
  464. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  465. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  466. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  467. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  468. package/src/standalone/daemon-session-control.mjs +142 -190
  469. package/src/standalone/daemon.mjs +26 -3
  470. package/src/standalone/session-client.mjs +7 -3
  471. package/src/standalone/session-protocol.mjs +5 -0
  472. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  473. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  474. package/src/standalone/session-service/quota-resume.mjs +3 -0
  475. package/src/standalone/session-service/retention/busy.mjs +65 -1
  476. package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
  477. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  478. package/src/standalone/session-tool-output.mjs +15 -7
  479. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  480. package/src/tui/app/app-view/floating-panel.jsx +7 -4
  481. package/src/tui/app/model-options.mjs +3 -28
  482. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  483. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  484. package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
  485. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  486. package/src/tui/app/provider-setup-picker.mjs +9 -5
  487. package/src/tui/components/QuestionPanel.jsx +13 -4
  488. package/src/tui/dist/index.mjs +133 -92
  489. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  490. package/src/tui/session/initial-state.mjs +3 -0
  491. package/src/tui/session/notice-surface.mjs +7 -1
  492. package/src/tui/session/queue-helpers.mjs +3 -42
  493. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  494. package/src/tui/session/session-api/routes-write.mjs +5 -1
  495. package/src/tui/session/session-api/routes.mjs +1 -0
  496. package/src/tui/session/session-api/settings.mjs +17 -1
  497. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  498. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  499. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  500. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  501. package/src/tui/session/session-flow/drain.mjs +118 -149
  502. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  503. package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
  504. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  505. package/src/tui/session/tool-approval-request.mjs +39 -0
  506. package/src/tui/session/tool-approval-settle.mjs +62 -0
  507. package/src/tui/session/tool-approval.mjs +69 -115
  508. package/src/tui/session/tui-steering-persist.mjs +8 -1
  509. package/src/tui/session/turn-stream.mjs +19 -2
  510. package/src/tui/session/turn.mjs +1 -0
  511. package/src/ui/statusline-agents.mjs +1 -3
  512. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  513. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  514. package/scripts/code-graph-description-contract.mjs +0 -188
  515. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -0,0 +1,18 @@
1
+ // What must land in a session's transcript right before its next turn's
2
+ // prompt, whoever starts that turn: the daemon registers one prelude
3
+ // (agent-home-delivery.mjs postBeforeAgentTurn) and the prompt queue's drain
4
+ // (tui/session/session-flow/drain.mjs) awaits it before presenting a batch.
5
+
6
+ let prelude = null;
7
+
8
+ /** Register `fn(sessionId)` (null or a promise per turn); a non-function clears it. */
9
+ export function setSessionTurnPrelude(fn) {
10
+ prelude = typeof fn === 'function' ? fn : null;
11
+ }
12
+
13
+ /** The prelude's work before a turn of `sessionId`: a promise, or null when
14
+ * there is none (no await, so a turn with nothing owed starts as before). */
15
+ export function sessionTurnPrelude(sessionId) {
16
+ if (!prelude || !sessionId) return null;
17
+ return prelude(String(sessionId)) || null;
18
+ }
@@ -38,9 +38,7 @@ function agentNameFromResult(resultText) {
38
38
  // The agent identity a card shows: the call's own fields, else the result
39
39
  // envelope when the call only carried a tag/task id.
40
40
  function agentDisplayName(args, resultText = '') {
41
- return (
42
- titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText)
43
- );
41
+ return titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText);
44
42
  }
45
43
 
46
44
  function agentModelLabel(args) {
@@ -7,13 +7,26 @@ import { backgroundTaskFailureStatusLabel } from '../err-text.mjs';
7
7
  import { agentTerminalDetail, isAgentTool } from './agent-surface.mjs';
8
8
  import { backgroundTaskElapsed, backgroundTaskFailureDetail, isBackgroundTaskTool } from './background-task.mjs';
9
9
  import { shellDisplayStatus } from './shell-surface.mjs';
10
- import { normalizeTerminalStatus, resultControlStatus, resultEnvelopeStatus, shellResultElapsed } from './terminal-status.mjs';
10
+ import {
11
+ normalizeTerminalStatus,
12
+ resultControlStatus,
13
+ resultEnvelopeStatus,
14
+ shellResultElapsed,
15
+ } from './terminal-status.mjs';
11
16
  import { mediaTerminalStatus } from './media-result.mjs';
12
17
  import { gitTerminalStatus } from './git-result.mjs';
13
18
  import { isUserControlCancellation } from '../tool-status.mjs';
14
19
 
15
20
  // Tools whose result opens with a task/bridge envelope that reports the call's status.
16
- const ENVELOPE_STATUS_TOOLS = new Set(['agent', 'bridge', 'task', 'web_search', 'search_query', 'image_query', 'web_search_call']);
21
+ const ENVELOPE_STATUS_TOOLS = new Set([
22
+ 'agent',
23
+ 'bridge',
24
+ 'task',
25
+ 'web_search',
26
+ 'search_query',
27
+ 'image_query',
28
+ 'web_search_call',
29
+ ]);
17
30
 
18
31
  function shellFragments(base, display, isShellSurface) {
19
32
  if (!isShellSurface) return { shellStatus: '', shellElapsed: '' };
@@ -526,20 +526,7 @@ function summarizeCodeGraphResult({ text, translate }) {
526
526
  return null;
527
527
  }
528
528
 
529
- function summarizeFetchResult({ text, trimmed, args, normalized, translate }) {
530
- // Channel `fetch` (Discord message fetch — args carry channel/messageId/limit,
531
- // never url/uri) is not a WEB fetch: the status/size probes would miss and
532
- // the result fall to raw JSON, so it takes the generic JSON/text summarizer.
533
- if (normalized === 'fetch') {
534
- const a = parseToolArgs(args);
535
- const isChannelFetch =
536
- !firstText(a.url, a.uri) && Boolean(firstText(a.channel, a.channelId, a.chatId, a.messageId) || a.limit != null);
537
- if (isChannelFetch) {
538
- const n = countNonEmptyLines(text);
539
- if (trimmed && looksLineOriented(text) && n > 0) return countLabel(translate, n, 'message');
540
- return summarizeGenericResult(text, translate);
541
- }
542
- }
529
+ function summarizeFetchResult({ text }) {
543
530
  // Status: require a status-like context (HTTP NNN, "Status: NNN",
544
531
  // or "NNN OK"/"NNN Not Found") rather than any bare 3-digit number.
545
532
  const status =
@@ -661,7 +648,7 @@ const summarizeAskUserResult = ({ text, translate }) => {
661
648
 
662
649
  const TOOL_RESULT_SUMMARIZERS = new Map(
663
650
  [
664
- [['ask_user'], summarizeAskUserResult],
651
+ [['ask_user', 'handoff_user'], summarizeAskUserResult],
665
652
  [['read', 'view_image', 'read_mcp_resource'], summarizeReadResult],
666
653
  [['apply_patch'], summarizePatchResult],
667
654
  [['grep'], summarizeGrepResult],
@@ -151,6 +151,7 @@ export function displayToolName(name, args = {}) {
151
151
  case 'request_user_input':
152
152
  return 'Ask User';
153
153
  case 'ask_user':
154
+ case 'handoff_user':
154
155
  return 'Question';
155
156
  case 'update_plan':
156
157
  return 'Plan';
@@ -239,6 +240,8 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
239
240
  return summarizeGithub(a, max);
240
241
  case 'goal':
241
242
  return compactParts([String(a.action || ''), truncateToolText(a.objective, max)]);
243
+ case 'handoff_user':
244
+ return '';
242
245
  case 'ask_user':
243
246
  return truncateToolText(
244
247
  (Array.isArray(a.questions) ? a.questions : [])
@@ -91,6 +91,7 @@ const TOOL_CATEGORY = new Map([
91
91
  ['goal', 'Setup'],
92
92
  ['request_user_input', 'Setup'],
93
93
  ['ask_user', 'Setup'],
94
+ ['handoff_user', 'Setup'],
94
95
  ['update_plan', 'Setup'],
95
96
  ['skill', 'Skill'],
96
97
  ['skill_execute', 'Skill'],
@@ -734,6 +735,7 @@ const TOOL_UNITS = new Map([
734
735
  ['code_graph', codeGraphUnit],
735
736
  ['request_user_input', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
736
737
  ['ask_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
738
+ ['handoff_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
737
739
  ['update_plan', () => unitDescriptor('Setup', { active: 'Updating', done: 'Updated', noun: 'plan' })],
738
740
  ['list_mcp_resources', () => unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'MCP resource' })],
739
741
  [
@@ -117,16 +117,23 @@ function recordPath(sessionId) {
117
117
  function chain(sessionId, task) {
118
118
  const previous = writeChains.get(sessionId) || Promise.resolve();
119
119
  const next = previous.then(task, task);
120
- writeChains.set(
121
- sessionId,
122
- next.then(
123
- () => undefined,
124
- () => undefined
125
- )
120
+ const settled = next.then(
121
+ () => undefined,
122
+ () => undefined
126
123
  );
124
+ writeChains.set(sessionId, settled);
125
+ // A settled chain with nothing queued behind it holds no order to keep.
126
+ void settled.then(() => {
127
+ if (writeChains.get(sessionId) === settled) writeChains.delete(sessionId);
128
+ });
127
129
  return next;
128
130
  }
129
131
 
132
+ /** Sessions with a write chain still held (tests). */
133
+ export function _turnSnapshotWriteChainCountForTest() {
134
+ return writeChains.size;
135
+ }
136
+
130
137
  async function readRecordFile(path) {
131
138
  try {
132
139
  const parsed = JSON.parse(await readFile(path, 'utf8'));
@@ -27,6 +27,7 @@ const WORKTREE_ENTRY_STATES = Object.freeze(['creating', 'ready', 'deleting', 'r
27
27
  export const WORKTREE_ERROR_CODES = Object.freeze({
28
28
  WORKTREE_BUSY_JOBS: 'WORKTREE_BUSY_JOBS',
29
29
  WORKTREE_BRANCH_OCCUPIED: 'WORKTREE_BRANCH_OCCUPIED',
30
+ WORKTREE_DEFAULT_BRANCH: 'WORKTREE_DEFAULT_BRANCH',
30
31
  WORKTREE_DISK_INSUFFICIENT: 'WORKTREE_DISK_INSUFFICIENT',
31
32
  WORKTREE_LARGE_REPO_CONFIRM: 'WORKTREE_LARGE_REPO_CONFIRM',
32
33
  WORKTREE_DIRTY: 'WORKTREE_DIRTY',
@@ -54,6 +55,8 @@ export const WORKTREE_ERROR_CODES = Object.freeze({
54
55
  const DEFAULT_ERROR_MESSAGES = Object.freeze({
55
56
  WORKTREE_BUSY_JOBS: 'The session has running jobs; wait for them or stop them before changing its workspace.',
56
57
  WORKTREE_BRANCH_OCCUPIED: 'The branch is checked out in another worktree.',
58
+ WORKTREE_DEFAULT_BRANCH:
59
+ "The repository's default branch can't be opened in a worktree: the project folder could not switch to it while the worktree exists. Check it out in the project folder, or create a new branch for the worktree.",
57
60
  WORKTREE_DISK_INSUFFICIENT: 'Not enough free disk space to create the worktree.',
58
61
  WORKTREE_LARGE_REPO_CONFIRM: 'The repository is large; confirm before creating a worktree.',
59
62
  WORKTREE_DIRTY: 'The worktree has uncommitted changes.',
@@ -193,7 +196,7 @@ function record(value, name) {
193
196
  * @property {string|null} worktreeId Managed worktree id; null when running in the project folder.
194
197
  * @property {string|null} branch Checked-out branch at `cwd`; null when detached or not a repository.
195
198
  * @property {string|null} baseCommit Commit the worktree branch was created from.
196
- * @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch).
199
+ * @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch); null for an existing branch until a merge records it.
197
200
  * @property {number} revision Monotonic; advances on every committed workspace change.
198
201
  * @property {WorkspaceTransition} transition In-flight transition marker.
199
202
  */
@@ -186,6 +186,21 @@ export async function localBranches(cwd, { signal, prefix = '' } = {}) {
186
186
  return lines(result.stdout);
187
187
  }
188
188
 
189
+ /** The local branch names the repository's remotes declare as their default (`refs/remotes/<remote>/HEAD`). */
190
+ export async function remoteDefaultBranches(cwd) {
191
+ const result = await runGit(cwd, ['for-each-ref', '--format=%(refname) %(symref)', 'refs/remotes'], {
192
+ readOnly: true,
193
+ });
194
+ const names = [];
195
+ for (const line of lines(result.stdout)) {
196
+ const [ref, target] = line.split(' ');
197
+ if (!ref.endsWith('/HEAD') || !target) continue;
198
+ const remote = ref.slice(0, -'HEAD'.length);
199
+ if (target.startsWith(remote)) names.push(target.slice(remote.length));
200
+ }
201
+ return names;
202
+ }
203
+
189
204
  export async function validBranchName(cwd, branch) {
190
205
  if (typeof branch !== 'string' || !branch.trim() || branch.startsWith('-')) return false;
191
206
  const result = await runGit(cwd, ['check-ref-format', '--branch', branch], { allowFailure: true });
@@ -49,6 +49,7 @@ import {
49
49
  WORKTREE_SNAPSHOT_KIND,
50
50
  worktreeBranchName,
51
51
  worktreeError,
52
+ worktreeRefusal,
52
53
  } from './contract.mjs';
53
54
  import {
54
55
  assertCarryable,
@@ -68,6 +69,7 @@ import {
68
69
  listWorktrees,
69
70
  localBranches,
70
71
  parseStatusPaths,
72
+ remoteDefaultBranches,
71
73
  runGit,
72
74
  throwIfAborted,
73
75
  validBranchName,
@@ -757,6 +759,11 @@ export async function resolveBranchWorkspace({
757
759
  repoCommonDir: repo.repoCommonDir,
758
760
  };
759
761
  }
762
+ // Checked out in a managed worktree, the branch a remote declares its
763
+ // default would stay locked away from the project folder.
764
+ if (!create && (await remoteDefaultBranches(repo.projectPath)).includes(branch)) {
765
+ throw worktreeError('WORKTREE_DEFAULT_BRANCH', undefined, { branch });
766
+ }
760
767
  const entry = await createManagedWorktree({
761
768
  projectPath,
762
769
  sessionId,
@@ -770,10 +777,6 @@ export async function resolveBranchWorkspace({
770
777
  confirmLarge,
771
778
  signal,
772
779
  });
773
- const record = await getRecord(entry.id);
774
- record.mergeTarget = repo.currentBranch;
775
- await putRecord(record);
776
- entry.mergeTarget = repo.currentBranch;
777
780
  return { path: entry.path, branch, entry, created: true, repoCommonDir: repo.repoCommonDir };
778
781
  });
779
782
  }
@@ -1219,7 +1222,10 @@ export async function createManagedWorktree({
1219
1222
  path: managedWorktreePath(repo.repoCommonDir, slug),
1220
1223
  branch,
1221
1224
  baseCommit,
1222
- mergeTarget,
1225
+ // An existing branch has no base it branched from: it merges where a
1226
+ // merge first takes it (recorded then), and until that its own work is
1227
+ // what it gained here since baseCommit.
1228
+ mergeTarget: existingBranch ? null : mergeTarget,
1223
1229
  createdAt: Date.now(),
1224
1230
  ownerSessionId: owner.sessionId,
1225
1231
  existingBranch,
@@ -1400,9 +1406,7 @@ export async function removeSessionSnapshots(sessionId, { txIds = null } = {}) {
1400
1406
  const only = txIds ? new Set(txIds) : null;
1401
1407
  const held = Object.values((await readRegistry()).entries).filter(
1402
1408
  (record) =>
1403
- record.kind === WORKTREE_SNAPSHOT_KIND &&
1404
- record.holderSessionId === sessionId &&
1405
- (!only || only.has(record.txId))
1409
+ record.kind === WORKTREE_SNAPSHOT_KIND && record.holderSessionId === sessionId && (!only || only.has(record.txId))
1406
1410
  );
1407
1411
  for (const record of held) {
1408
1412
  const row = { id: record.id, txId: record.txId };
@@ -1854,19 +1858,59 @@ export async function removeManagedWorktree({
1854
1858
  if (!current && !expected) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1855
1859
  return skipped;
1856
1860
  }
1857
- assertNotShared(current, sessionId);
1858
- if (current.state === 'creating' || current.state === 'recovery') {
1859
- const rollback = await rollbackCreation(current);
1860
- return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
1861
+ return removeLocked(current, { force, sessionId, preserveBranch, safeOnly });
1862
+ });
1863
+ }
1864
+
1865
+ /** The removal of `current`, under its repository lock. */
1866
+ async function removeLocked(current, { force, sessionId, preserveBranch = false, safeOnly = false }) {
1867
+ assertNotShared(current, sessionId);
1868
+ if (current.state === 'creating' || current.state === 'recovery') {
1869
+ const rollback = await rollbackCreation(current);
1870
+ return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
1871
+ }
1872
+ // Every deletion attempt of a snapshot, a resumed one included, waits
1873
+ // for (refuses on) its consumers.
1874
+ const release = current.kind === WORKTREE_SNAPSHOT_KIND ? holdSnapshotFolder(current) : () => {};
1875
+ try {
1876
+ return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
1877
+ } finally {
1878
+ release();
1879
+ }
1880
+ }
1881
+
1882
+ /**
1883
+ * Remove a worktree whose owner is gone, on an explicit request: under the
1884
+ * repository lock its retention is read again right before anything moves,
1885
+ * so an owner that came back (a live session, a running lease holder) or a
1886
+ * session the store still keeps it for refuses (WORKTREE_BUSY_JOBS). Then
1887
+ * the ordinary removal guards apply (dirty or unmerged work needs `force`).
1888
+ * @param {{ entryId: string, force?: boolean, liveSessionIds?: string[], retainedSessionIds?: string[] }} input
1889
+ */
1890
+ export async function removeOrphanedWorktree({
1891
+ entryId,
1892
+ force = false,
1893
+ liveSessionIds = [],
1894
+ retainedSessionIds = [],
1895
+ } = {}) {
1896
+ const record = await getRecord(entryId);
1897
+ if (!record) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1898
+ return withRepoLock(record.repoCommonDir, async () => {
1899
+ const current = await getRecord(entryId);
1900
+ if (!current || current.kind === WORKTREE_SNAPSHOT_KIND) {
1901
+ throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
1861
1902
  }
1862
- // Every deletion attempt of a snapshot, a resumed one included, waits
1863
- // for (refuses on) its consumers.
1864
- const release = current.kind === WORKTREE_SNAPSHOT_KIND ? holdSnapshotFolder(current) : () => {};
1865
- try {
1866
- return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
1867
- } finally {
1868
- release();
1903
+ const { ownerLive, removable } = await retentionOf(current, new Set(liveSessionIds), new Set(retainedSessionIds));
1904
+ if (ownerLive) throw worktreeRefusal('workspace-lease', { entryId });
1905
+ if (!removable) {
1906
+ // Retained recovery data names itself; otherwise sessions still keep it.
1907
+ await assertRecoveryStoresClear(current);
1908
+ throw worktreeRefusal('workspace-retained', {
1909
+ entryId,
1910
+ sessions: [current.ownerSessionId, ...(current.sharedSessionIds ?? [])].filter(Boolean),
1911
+ });
1869
1912
  }
1913
+ return removeLocked(current, { force });
1870
1914
  });
1871
1915
  }
1872
1916
 
@@ -1900,25 +1944,7 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
1900
1944
  const retained = new Set(retainedSessionIds);
1901
1945
  const rows = [];
1902
1946
  for (const record of Object.values((await readRegistry()).entries)) {
1903
- const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
1904
- const ownerLive = snapshot
1905
- ? await snapshotHolderLive(record, live)
1906
- : (!!record.ownerSessionId && live.has(record.ownerSessionId)) ||
1907
- leaseProcessAlive(await readOwnerLease(record));
1908
- const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
1909
- // A snapshot outlives no holder: the prune removes it, changes and all.
1910
- let removable = snapshot
1911
- ? !ownerLive
1912
- : !record.sharedSessionIds?.length &&
1913
- (record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
1914
- if (removable) {
1915
- try {
1916
- await assertRecoveryStoresClear(record);
1917
- } catch (error) {
1918
- if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
1919
- removable = false;
1920
- }
1921
- }
1947
+ const { ownerLive, retained: isRetained, removable } = await retentionOf(record, live, retained);
1922
1948
  rows.push({
1923
1949
  ...entryView(record),
1924
1950
  projectPath: record.projectPath,
@@ -1930,6 +1956,29 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
1930
1956
  return rows;
1931
1957
  }
1932
1958
 
1959
+ /** Who keeps `record` (listManagedWorktrees): `live` and `retained` are session id sets. */
1960
+ async function retentionOf(record, live, retained) {
1961
+ const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
1962
+ const ownerLive = snapshot
1963
+ ? await snapshotHolderLive(record, live)
1964
+ : (!!record.ownerSessionId && live.has(record.ownerSessionId)) || leaseProcessAlive(await readOwnerLease(record));
1965
+ const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
1966
+ // A snapshot outlives no holder: the prune removes it, changes and all.
1967
+ let removable = snapshot
1968
+ ? !ownerLive
1969
+ : !record.sharedSessionIds?.length &&
1970
+ (record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
1971
+ if (removable) {
1972
+ try {
1973
+ await assertRecoveryStoresClear(record);
1974
+ } catch (error) {
1975
+ if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
1976
+ removable = false;
1977
+ }
1978
+ }
1979
+ return { ownerLive, retained: isRetained, removable };
1980
+ }
1981
+
1933
1982
  /**
1934
1983
  * Conservative reconcile (daemon startup, and the manual prune). Always:
1935
1984
  * resumes interrupted deletions, rolls back interrupted creations of no
@@ -1,25 +1,22 @@
1
1
  // Temporary git repositories and data dirs for the worktree suites.
2
+ import '../git-direct.test-support.mjs';
2
3
  import { execFileSync } from 'node:child_process';
3
- import { chmodSync, cpSync, existsSync, mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
4
- import { tmpdir } from 'node:os';
4
+ import { appendFileSync, chmodSync, cpSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
5
5
  import { dirname, join } from 'node:path';
6
+ import { makeTempDirSync, removeTempDirSync } from '../../../../scripts/lib/scoped-temp.mjs';
6
7
 
7
8
  const created = [];
8
9
 
10
+ // A suite that never calls cleanupTempDirs still has its directories removed
11
+ // when the process exits.
9
12
  export function tempDir(prefix = 'mixdog-wt-') {
10
- const dir = mkdtempSync(join(tmpdir(), prefix));
13
+ const dir = makeTempDirSync(prefix);
11
14
  created.push(dir);
12
15
  return dir;
13
16
  }
14
17
 
15
18
  export function cleanupTempDirs() {
16
- for (const dir of created.splice(0)) {
17
- try {
18
- rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
19
- } catch {
20
- /* best effort */
21
- }
22
- }
19
+ for (const dir of created.splice(0)) removeTempDirSync(dir);
23
20
  }
24
21
 
25
22
  const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' };
@@ -67,9 +64,13 @@ function repoTemplate(commit) {
67
64
  if (existing && existsSync(existing)) return existing;
68
65
  const dir = tempDir('mixdog-wt-template-');
69
66
  git(dir, 'init', '-q', '-b', 'main');
70
- git(dir, 'config', 'user.name', 'Mixdog Test');
71
- git(dir, 'config', 'user.email', 'mixdog@example.com');
72
- git(dir, 'config', 'core.autocrlf', 'false');
67
+ // One config write instead of a `git config` process per key. Auto
68
+ // maintenance is off, so no commit (the test's or a merge's) starts a
69
+ // `git maintenance run` child.
70
+ appendFileSync(
71
+ join(dir, '.git', 'config'),
72
+ '[user]\n\tname = Mixdog Test\n\temail = mixdog@example.com\n[core]\n\tautocrlf = false\n[maintenance]\n\tauto = false\n'
73
+ );
73
74
  if (commit) commitFile(dir, 'README.md', 'hello\n', 'initial');
74
75
  templates.set(commit, dir);
75
76
  return dir;
@@ -262,10 +262,19 @@ function oldestRowsOverCap(rows) {
262
262
  function formatRun(value) {
263
263
  const cursor = Number.isSafeInteger(value?.cursor) ? value.cursor : 0;
264
264
  const tab = value?.tab !== undefined ? ` tab=${value.tab}` : '';
265
+ let where = '';
266
+ if (value?.shown === true) where = 'The terminal is shown in the desktop window.';
267
+ else if (value?.shown === false) {
268
+ where =
269
+ 'The terminal is not shown in the desktop window right now (a paired phone may still show it); it keeps running.';
270
+ }
265
271
  return [
266
272
  `Terminal run: ${value?.id || `tab ${value?.tab}`} · ${tabLabel(value)} · cursor=${cursor}`,
267
273
  `Command sent to the side terminal. Read its output with action=read${tab} since=${cursor}.`,
268
- ].join('\n');
274
+ where,
275
+ ]
276
+ .filter(Boolean)
277
+ .join('\n');
269
278
  }
270
279
 
271
280
  async function readJson(response) {
@@ -6,6 +6,7 @@
6
6
  * Response: { ok:true, text, tabs?, path? } | { ok:false, error }.
7
7
  */
8
8
  import { bridgeDiscoveryChanged, readBridgeDiscovery, readBridgeDiscoveryDetail } from '../bridge-discovery.mjs';
9
+ import { visualizeOwnerToolMeta } from './tool-meta.mjs';
9
10
 
10
11
  const DISCOVERY_FILE = 'visualize-bridge.json';
11
12
  const REQUEST_TIMEOUT_MS = 30_000;
@@ -38,12 +39,14 @@ export function validateVisualizeArgs(args) {
38
39
  if (!args || typeof args !== 'object' || Array.isArray(args)) {
39
40
  return { ok: false, error: 'visualize arguments must be an object' };
40
41
  }
41
- if (!ACTIONS.has(args.action)) return { ok: false, error: 'action must be open, close, annotate, capture, export, check, or inspect' };
42
+ if (!ACTIONS.has(args.action))
43
+ return { ok: false, error: 'action must be open, close, annotate, capture, export, check, or inspect' };
42
44
  const input = args.input ?? {};
43
45
  if (typeof input !== 'object' || Array.isArray(input)) return { ok: false, error: 'input must be an object' };
44
46
  if (args.action === 'open' && input.content != null) {
45
47
  const content = input.content;
46
- if (input.targets != null) return { ok: false, error: 'open takes either input.targets or input.content, not both' };
48
+ if (input.targets != null)
49
+ return { ok: false, error: 'open takes either input.targets or input.content, not both' };
47
50
  if (typeof content !== 'object' || Array.isArray(content)) {
48
51
  return { ok: false, error: 'open input.content must be { kind, source, title? }' };
49
52
  }
@@ -79,7 +82,10 @@ export function validateVisualizeArgs(args) {
79
82
  return { ok: false, error: 'open input.version must be a positive integer (a kept version number)' };
80
83
  }
81
84
  }
82
- if (['annotate', 'capture', 'export', 'check', 'inspect'].includes(args.action) && (typeof input.tab !== 'string' || !input.tab)) {
85
+ if (
86
+ ['annotate', 'capture', 'export', 'check', 'inspect'].includes(args.action) &&
87
+ (typeof input.tab !== 'string' || !input.tab)
88
+ ) {
83
89
  return { ok: false, error: `${args.action} requires input.tab` };
84
90
  }
85
91
  if (args.action === 'inspect') {
@@ -92,7 +98,10 @@ export function validateVisualizeArgs(args) {
92
98
  !sized(viewport.width, 200, 3000) ||
93
99
  (viewport.height != null && !sized(viewport.height, 200, 4000))
94
100
  ) {
95
- return { ok: false, error: 'inspect input.viewport must be { width: 200-3000, height?: 200-4000 } in whole pixels' };
101
+ return {
102
+ ok: false,
103
+ error: 'inspect input.viewport must be { width: 200-3000, height?: 200-4000 } in whole pixels',
104
+ };
96
105
  }
97
106
  }
98
107
  if (selector != null && (typeof selector !== 'string' || !selector.trim() || selector.length > 500)) {
@@ -103,7 +112,8 @@ export function validateVisualizeArgs(args) {
103
112
  return { ok: false, error: 'capture requires input.output ending in .png' };
104
113
  }
105
114
  if (args.action === 'export') {
106
- if (input.format !== 'png' && input.format !== 'pdf') return { ok: false, error: 'export requires input.format png or pdf' };
115
+ if (input.format !== 'png' && input.format !== 'pdf')
116
+ return { ok: false, error: 'export requires input.format png or pdf' };
107
117
  if (typeof input.output !== 'string' || !new RegExp('\\.' + input.format + '$', 'i').test(input.output.trim())) {
108
118
  return { ok: false, error: `export requires input.output ending in .${input.format}` };
109
119
  }
@@ -153,6 +163,8 @@ export async function executeVisualizeTool(args, options = {}) {
153
163
  cwd: options.cwd || process.cwd(),
154
164
  action: validated.action,
155
165
  input: validated.input,
166
+ // The call's id: the host names it in its turn-end record of opens whose tab is gone.
167
+ ...(options.callId ? { callId: String(options.callId) } : {}),
156
168
  };
157
169
  let discovery = readBridgeDiscovery(DISCOVERY_FILE);
158
170
  if (!discovery) return toolError(unavailableMessage());
@@ -160,7 +172,11 @@ export async function executeVisualizeTool(args, options = {}) {
160
172
  for (let attempt = 0; attempt < 2; attempt += 1) {
161
173
  const timeout = AbortSignal.timeout(validated.action === 'export' ? EXPORT_REQUEST_TIMEOUT_MS : REQUEST_TIMEOUT_MS);
162
174
  try {
163
- result = await requestBridge(discovery, payload, options.signal ? AbortSignal.any([timeout, options.signal]) : timeout);
175
+ result = await requestBridge(
176
+ discovery,
177
+ payload,
178
+ options.signal ? AbortSignal.any([timeout, options.signal]) : timeout
179
+ );
164
180
  break;
165
181
  } catch (error) {
166
182
  if (error?.name === 'TimeoutError') return toolError('visualize bridge timed out');
@@ -175,7 +191,12 @@ export async function executeVisualizeTool(args, options = {}) {
175
191
  }
176
192
  const { body, status } = result;
177
193
  if (!body?.ok) {
178
- return toolError(String(body?.error || `visualize bridge request failed (HTTP ${status})`).replace(/^Error:\s*/, ''));
194
+ return toolError(
195
+ String(body?.error || `visualize bridge request failed (HTTP ${status})`).replace(/^Error:\s*/, '')
196
+ );
179
197
  }
180
- return { content: [{ type: 'text', text: formatSuccess(body) }] };
198
+ // The host ran it for another session's panel: the owner rides as a field
199
+ // (toolMeta, kept with the stored result), never only as prose.
200
+ const toolMeta = visualizeOwnerToolMeta(body.ownerSessionId);
201
+ return { content: [{ type: 'text', text: formatSuccess(body) }], ...(toolMeta ? { toolMeta } : {}) };
181
202
  }
@@ -10,8 +10,8 @@ export const TOOL_DEFS = [
10
10
  name: 'visualize',
11
11
  title: 'Mixdog Visualize',
12
12
  description:
13
- "Show the user any artifact you produced or changed (mockups, docs, decks, sheets, PDFs, images, video, local dev pages) in the desktop side panel beside the chat. Panel tabs auto-reload when a file changes, so re-opening after edits is unnecessary. " +
14
- 'open: input.targets (1-3 file paths, 2-3 = side-by-side comparison; or a single http(s) URL alone, never mixed with files or other URLs), optional label, optional version (show that kept version of a file tab read-only; each open/reload that changes the files keeps a version). close: optional tab (omit = all). ' +
13
+ 'Show the user any artifact you produced or changed (mockups, docs, decks, sheets, PDFs, images, video, local dev pages) in the desktop side panel beside the chat. Panel tabs auto-reload when a file changes, so re-opening after edits is unnecessary. ' +
14
+ 'open: input.targets (1-3 file paths, relative to the working directory or absolute anywhere on this machine; 2-3 = side-by-side comparison; or a single http(s) URL alone, never mixed with files or other URLs), optional label, optional version (show that kept version of a file tab read-only; each open/reload that changes the files keeps a version). close: optional tab (omit = all). ' +
15
15
  'annotate: tab + add [{selector,label?}] | remove [selector] | clear; HTML pages only, never edits the file. capture: tab + output (.png path). ' +
16
16
  'export: tab + format (png|pdf) + output (project-relative path ending .png/.pdf) + optional version (a kept version of the tab) + optional overwrite (true replaces an existing file, only under design/; otherwise an existing file is refused). Writes a record of the approved page inside the project and returns its project-relative path, size/dimensions and the page problems seen while rendering. A single HTML page (file, or inline html/chart) is rendered whole in a hidden window, so the tab need not be on screen (PDF: HTML pages only; PNG has a pixel cap, over it export pdf or shorten the page); any other tab exports as capture does (the displayed tab, PNG only). Same project containment as capture: links and paths outside the working directory are refused. ' +
17
17
  'check: tab; HTML pages only; waits briefly for the page to settle and returns only its runtime problems (uncaught errors, unhandled rejections, CSP violations, console errors/warnings, missing local assets). ' +
@@ -36,7 +36,8 @@ export const TOOL_DEFS = [
36
36
  items: { type: 'string' },
37
37
  minItems: 1,
38
38
  maxItems: 3,
39
- description: 'open: 1-3 project-relative/absolute file paths (side by side), or exactly one http(s) URL as the only target.',
39
+ description:
40
+ 'open: 1-3 file paths (side by side), relative to the working directory or absolute in any folder, or exactly one http(s) URL as the only target.',
40
41
  },
41
42
  content: {
42
43
  type: 'object',
@@ -57,7 +58,8 @@ export const TOOL_DEFS = [
57
58
  version: {
58
59
  type: 'integer',
59
60
  minimum: 1,
60
- description: 'open (file tabs): kept version number to show read-only instead of the live files. export: kept version number to render instead of the live page.',
61
+ description:
62
+ 'open (file tabs): kept version number to show read-only instead of the live files. export: kept version number to render instead of the live page.',
61
63
  },
62
64
  tab: { type: 'string', description: 'Tab id from open (close: omit for all).' },
63
65
  add: {
@@ -72,9 +74,16 @@ export const TOOL_DEFS = [
72
74
  },
73
75
  remove: { type: 'array', items: { type: 'string' }, description: 'annotate: selectors to un-outline.' },
74
76
  clear: { type: 'boolean', description: 'annotate: remove all outlines.' },
75
- output: { type: 'string', description: 'capture: project path ending .png. export: project path ending .png or .pdf (matching format).' },
77
+ output: {
78
+ type: 'string',
79
+ description:
80
+ 'capture: project path ending .png. export: project path ending .png or .pdf (matching format).',
81
+ },
76
82
  format: { type: 'string', enum: ['png', 'pdf'], description: 'export: file format.' },
77
- overwrite: { type: 'boolean', description: 'export: replace an existing output file; honored only for paths under design/.' },
83
+ overwrite: {
84
+ type: 'boolean',
85
+ description: 'export: replace an existing output file; honored only for paths under design/.',
86
+ },
78
87
  viewport: {
79
88
  type: 'object',
80
89
  properties: {
@@ -83,9 +92,14 @@ export const TOOL_DEFS = [
83
92
  },
84
93
  required: ['width'],
85
94
  additionalProperties: false,
86
- description: 'inspect: size to lay the page out at (height defaults to 800); omit for the panel\'s current size.',
95
+ description:
96
+ "inspect: size to lay the page out at (height defaults to 800); omit for the panel's current size.",
97
+ },
98
+ selector: {
99
+ type: 'string',
100
+ maxLength: 500,
101
+ description: 'inspect: CSS selector scoping the read-out to one subtree.',
87
102
  },
88
- selector: { type: 'string', maxLength: 500, description: 'inspect: CSS selector scoping the read-out to one subtree.' },
89
103
  },
90
104
  additionalProperties: false,
91
105
  },
@@ -0,0 +1,5 @@
1
+ export declare const VISUALIZE_OWNER_META_CODE: 'visualize_owner';
2
+ export declare function visualizeOwnerMetaSessionId(value: unknown): string;
3
+ export declare function visualizeOwnerToolMeta(
4
+ ownerSessionId: unknown
5
+ ): { code: typeof VISUALIZE_OWNER_META_CODE; missing: string[]; ownerSessionId: string } | undefined;