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
@@ -22,6 +22,7 @@ import {
22
22
  scanSessionFiles,
23
23
  scanSessionFilesAsync,
24
24
  stampedDerivation,
25
+ storedSessionCatalogRow,
25
26
  } from './store-summary-catalog.mjs';
26
27
  import { createStoredTranscriptCache, nextProjectionStamp } from './store-transcript-cache.mjs';
27
28
  import {
@@ -34,10 +35,21 @@ import { projectStoredTranscript } from './store-transcript-projection.mjs';
34
35
  import { dataDir } from './store-summary-locations.mjs';
35
36
  import { isStoredSessionId, workspaceSummary } from './store-summary-fields.mjs';
36
37
  import { readArchivedAgentResult } from './store-summary-archived-agent.mjs';
37
- import { compactionArchivePath, readCompactionArchivePage } from './compaction-archive.mjs';
38
+ import {
39
+ compactionArchivePath,
40
+ compactionArchiveRange,
41
+ readCompactionArchivePage,
42
+ visitCompactionArchive,
43
+ } from './compaction-archive.mjs';
44
+ import { attachmentHistoryRows } from './stored-attachment-history.mjs';
38
45
  import { currentSessionCatalogDb, onSessionCatalogDbChange, sessionCatalogDb } from './catalog-db/index.mjs';
39
46
  import { decodeCatalogCursor, encodeCatalogCursor, isAfterCursor } from './catalog-db/schema.mjs';
40
- import { onSessionActivityChange } from '../../../shared/session-activity-signal.mjs';
47
+ import {
48
+ onSessionActivityChange,
49
+ onSessionApprovalCardChange,
50
+ onSessionBotWorkChange,
51
+ } from '../../../shared/session-activity-signal.mjs';
52
+ import { inFlightSessionActivity } from './manager/runtime-state.mjs';
41
53
  import {
42
54
  readCanonicalSessionRecord as readCanonicalLifecycle,
43
55
  offerStrictSessionRecord,
@@ -59,6 +71,11 @@ export { storedAgentWorkerIndexPath } from './store-summary-locations.mjs';
59
71
  // the desktop service worker keeps its own for the deep-history prefetch.
60
72
  const storedTranscriptCache = createStoredTranscriptCache();
61
73
 
74
+ // The attachment rows of whole stored conversations: the same cache mechanism
75
+ // and byte budget as the windows above, as an instance of its own, which a
76
+ // lookup can neither fill nor evict.
77
+ const attachmentHistoryCache = createStoredTranscriptCache();
78
+
62
79
  /** Test seam: forget every cached projection. */
63
80
  export function clearStoredTranscriptCache() {
64
81
  storedTranscriptCache.clear();
@@ -106,7 +123,27 @@ onSessionCatalogDbChange(() => notifyCatalogListeners());
106
123
  // Runtime activity transitions (turn start/settle, task wait, background
107
124
  // hand-off/finish) change only the Agents pool projection: `agent-activity`
108
125
  // lets the reader refresh just that, at once.
109
- onSessionActivityChange(() => notifyCatalogListeners('agent-activity'));
126
+ // A transition that starts or settles a turn also changes the catalog rows'
127
+ // `working` / `agentWorking` overlay. The listing that a turn's final save
128
+ // triggers can run before the turn leaves the runtime map, and nothing else
129
+ // re-lists: a bot home (no title write after its turn) kept `working` — a
130
+ // spinner and no completion dot — until its next file change.
131
+ let catalogActivity = '';
132
+ onSessionActivityChange(() => {
133
+ notifyCatalogListeners('agent-activity');
134
+ const { working, agentWorking } = inFlightSessionActivity();
135
+ const next = `${[...working].sort().join(',')}|${[...agentWorking].sort().join(',')}`;
136
+ if (next === catalogActivity) return;
137
+ catalogActivity = next;
138
+ notifyCatalogListeners('turn-activity');
139
+ });
140
+ // A session started or stopped waiting on the user's approval: its catalog row
141
+ // (`awaitingApproval`) changed, though no store file did.
142
+ onSessionApprovalCardChange(() => notifyCatalogListeners('approval'));
143
+ // A bot started or stopped having a send in flight in a session: its catalog
144
+ // row (`handedBy`) changed, though neither a file nor the set of working
145
+ // sessions did (the work may already be running, or continue past the end).
146
+ onSessionBotWorkChange(() => notifyCatalogListeners('bot-work'));
110
147
 
111
148
  /** `listener()` runs when a background pass finds a session file that changed
112
149
  * without a directory or index change, i.e. when an ordinary listing would
@@ -232,6 +269,12 @@ export async function listStoredSessionSummaryPage(options = {}) {
232
269
  };
233
270
  }
234
271
 
272
+ /** One session's catalog row by id, read off its record (not the paged
273
+ * listing): null when the catalog would not list it. */
274
+ export function readStoredSessionCatalogRow(id) {
275
+ return storedSessionCatalogRow(join(dataDir(), 'sessions'), String(id || '').trim());
276
+ }
277
+
235
278
  /** Exact, fail-closed existence check for a durable session address.
236
279
  * Summary indexes and desktop metadata are presentation caches; neither may
237
280
  * make a missing sessions/<id>.json record addressable again. */
@@ -269,6 +312,7 @@ function storedSessionMetadata(sessionId, session) {
269
312
  ownerSessionId: session.ownerSessionId || session.parentSessionId || null,
270
313
  visibility: sessionVisibility(session),
271
314
  agentTag: session.agentTag || null,
315
+ title: session.title || null,
272
316
  cwd: session.cwd || '',
273
317
  ...(workspaceSummary(session.workspace) ? { workspace: workspaceSummary(session.workspace) } : {}),
274
318
  provider: session.provider || null,
@@ -405,6 +449,49 @@ async function produceStoredTranscript(text, stamp, context) {
405
449
  }
406
450
  }
407
451
 
452
+ /** The rows of one session's whole stored conversation that name attachments
453
+ * (see attachmentHistoryRows): its record's messages and every visible
454
+ * segment of its compaction archive (a cleared or capped archive stays
455
+ * excluded, as for a window). Read from the files alone, under the same
456
+ * strict record authority as a transcript read, and cached by content
457
+ * identity in a cache of its own: the transcript windows are untouched.
458
+ * Null when the record is absent, unreadable or not this session's. */
459
+ async function readStoredAttachmentHistory(sessionId, recordPath, archivePath) {
460
+ const recordStat = probePath(recordPath);
461
+ if (recordStat.state !== PROBE_PRESENT) return null;
462
+ const archive = probePath(archivePath);
463
+ const key = `${sessionId}|attachments`;
464
+ let complete = true;
465
+ const { value } = await attachmentHistoryCache.read({
466
+ key,
467
+ fingerprint: [archive.state, archive.mtimeMs, archive.ctimeMs, archive.size, archive.ino, archive.dev].join(':'),
468
+ fileStat: recordStat,
469
+ loadText: () => {
470
+ const body = readTextFile(recordPath);
471
+ return body.state === PROBE_PRESENT ? body.text : null;
472
+ },
473
+ produce: async (text) => {
474
+ const record = readTopLevelLifecycleRecord(text);
475
+ if (isLifecycleUnreadable(record) || record.id !== sessionId) return null;
476
+ const { restoreTranscriptItems } = await import('./transcript-restore/restore.mjs');
477
+ const items = [];
478
+ const range = compactionArchiveRange(record.doc);
479
+ // An archive that exists but could not be walked is a transient miss,
480
+ // not a state worth keeping.
481
+ const walked = range
482
+ ? await visitCompactionArchive(join(dataDir(), 'sessions'), sessionId, range, (segment) =>
483
+ items.push(...attachmentHistoryRows(segment))
484
+ )
485
+ : true;
486
+ complete = walked || archive.state !== PROBE_PRESENT;
487
+ items.push(...attachmentHistoryRows(restoreTranscriptItems(record.doc.messages, { sessionId })));
488
+ return { sessionId, items };
489
+ },
490
+ });
491
+ if (!complete) attachmentHistoryCache.forget(key);
492
+ return value ?? null;
493
+ }
494
+
408
495
  /** Read exactly one persisted session for a visible desktop pane. This never
409
496
  * enumerates siblings. Normal reads stay independent of runtime ownership;
410
497
  * interrupted turns conditionally use the same durable reconnect recovery as
@@ -416,6 +503,8 @@ export async function readStoredSessionTranscript(id, options = {}) {
416
503
  // absent, unreadable, ambiguous or foreign record yields no transcript.
417
504
  const { recordPath, checkpointPath, archivePath } = storedTranscriptInputPaths(sessionId);
418
505
  if (options.metadataOnly === true) return readStoredSessionMetadata(recordPath, sessionId);
506
+ // The attachments the whole conversation names, apart from any window.
507
+ if (options.attachmentHistory === true) return readStoredAttachmentHistory(sessionId, recordPath, archivePath);
419
508
  // One page of the display-only compaction archive (the live head loader
420
509
  // pages it once a runtime's in-memory rows are exhausted).
421
510
  if (options.compactionArchive && typeof options.compactionArchive === 'object') {
@@ -0,0 +1,32 @@
1
+ // The attachments a session's whole stored conversation names (its record and
2
+ // its compaction archive), reduced to the metadata that says which rows name
3
+ // which attachment. Whether an attachment id belongs to a session is decided
4
+ // against this, not against a transcript window (a tail plus the pages paged
5
+ // in), which no longer holds rows a compaction moved into the archive.
6
+
7
+ const pick = (entry, keys) =>
8
+ Object.fromEntries(keys.filter((key) => entry?.[key] != null).map((key) => [key, entry[key]]));
9
+ const picked = (list, keys) => (Array.isArray(list) ? list.map((entry) => pick(entry, keys)) : []);
10
+
11
+ /** The rows of `items` that name attachments, reduced to the fields the
12
+ * desktop reads to attribute an id to its row: the row kind (and a notice's
13
+ * routine / room kind) and each attachment's id, name, type and size. No
14
+ * text, tool output or other row content is kept. */
15
+ export function attachmentHistoryRows(items) {
16
+ const rows = [];
17
+ for (const item of Array.isArray(items) ? items : []) {
18
+ const attachments = picked(item?.attachments, ['id', 'name', 'mimeType', 'kind', 'size']);
19
+ const images = picked(item?.images, ['attachmentRef', 'name', 'mimeType', 'bytes']);
20
+ const imageRefs = picked(item?.imageRefs, ['ref']);
21
+ if (!attachments.length && !images.length && !imageRefs.length) continue;
22
+ rows.push({
23
+ kind: item.kind,
24
+ ...(item.routine?.kind ? { routine: { kind: item.routine.kind } } : {}),
25
+ ...(item.room?.kind ? { room: { kind: item.room.kind } } : {}),
26
+ ...(attachments.length ? { attachments } : {}),
27
+ ...(images.length ? { images } : {}),
28
+ ...(imageRefs.length ? { imageRefs } : {}),
29
+ });
30
+ }
31
+ return rows;
32
+ }
@@ -0,0 +1,108 @@
1
+ // Thinking replay is bound to the request prefix that produced it.
2
+ //
3
+ // An Anthropic thinking block's signature records the conversation prefix it
4
+ // was generated under: the top-level system prompt, the tool set, and every
5
+ // earlier message. A request whose system or tools changed since then carries
6
+ // blocks the API drops before the model sees them (unbilled, so the provider's
7
+ // count no longer includes them) or, where the check is enforced, refuses with
8
+ // a 400. The drop also takes every LATER thinking block, so a transcript that
9
+ // keeps the stale blocks loses the reasoning of every turn that follows them.
10
+ //
11
+ // Where the runtime itself changes that prefix — a heir carrying a conversation
12
+ // into a prompt built for it, a folded or migrated prompt — the stored thinking
13
+ // can never be replayed again. It is stripped once, at that boundary, the
14
+ // documented recovery: each turn keeps its text and tool calls, and the next
15
+ // turns' thinking binds to the new prefix and is replayed normally. Leaving it
16
+ // in place also kept charging every signature to the local context estimate,
17
+ // which then ran far above what the provider actually counted.
18
+ //
19
+ // One round is never stripped: a trailing tool round whose next request still
20
+ // continues it (the latest assistant turn called tools and no final reply
21
+ // followed — an idle session can stop there after a provider error). Its
22
+ // latest assistant turn must go back starting with its thinking, so removing
23
+ // that thinking is a refused request too. When the prefix changed under such a
24
+ // round, the round is ended explicitly instead (`rebindToChangedPrefix`).
25
+ import { contextAckMessage } from './compact/user-message-kind.mjs';
26
+ import { collectAssistantToolCallIds } from './context-tool-pairs.mjs';
27
+ import { assistantMessageWithoutThinkingReplay } from './thinking-replay-recovery.mjs';
28
+
29
+ /** The runtime turn that ends an open tool round: a context ack, so the
30
+ * transcript never shows it and Compact never reads it as a reply. */
31
+ function toolRoundClosure() {
32
+ const ack = contextAckMessage();
33
+ return { ...ack, meta: { ...ack.meta, synthetic: true } };
34
+ }
35
+
36
+ const callsTools = (message) =>
37
+ collectAssistantToolCallIds(message).length > 0 ||
38
+ (Array.isArray(message?.providerReplay?.items) &&
39
+ message.providerReplay.items.some((item) => item?.type === 'tool_use'));
40
+
41
+ /**
42
+ * Index where the trailing open tool round starts (the assistant/tool run that
43
+ * ends with the latest assistant turn's results; later user or notification
44
+ * input may follow), or -1 when the latest assistant turn is a final reply.
45
+ * Read from the persisted transcript alone.
46
+ */
47
+ export function openToolRoundStart(messages) {
48
+ if (!Array.isArray(messages)) return -1;
49
+ const latest = messages.findLastIndex((message) => message?.role === 'assistant');
50
+ if (latest < 0 || !callsTools(messages[latest])) return -1;
51
+ let start = latest;
52
+ while (start > 0 && ['assistant', 'tool'].includes(messages[start - 1]?.role)) start -= 1;
53
+ return start;
54
+ }
55
+
56
+ /** What the next request sends ahead of the conversation: the system blocks and tools. */
57
+ export function requestPrefixIdentity(session) {
58
+ return JSON.stringify([
59
+ (Array.isArray(session?.messages) ? session.messages : [])
60
+ .filter((message) => message?.role === 'system')
61
+ .map((message) => message.content),
62
+ session?.tools,
63
+ ]);
64
+ }
65
+
66
+ /**
67
+ * `messages` without Anthropic thinking replay (thinking / redacted_thinking
68
+ * blocks, wherever an assistant turn stores them); text and tool calls stay.
69
+ * The trailing open tool round keeps its thinking: everything stripped is a
70
+ * leading run, which leaves the round's own blocks valid.
71
+ * Replaces changed messages, never mutates; the same array when none changed.
72
+ */
73
+ export function withoutThinkingReplay(messages) {
74
+ if (!Array.isArray(messages)) return messages;
75
+ const open = openToolRoundStart(messages);
76
+ const end = open < 0 ? messages.length : open;
77
+ let changed = false;
78
+ const out = messages.map((message, index) => {
79
+ const stripped = index < end ? assistantMessageWithoutThinkingReplay(message) : null;
80
+ if (!stripped) return message;
81
+ changed = true;
82
+ return stripped;
83
+ });
84
+ return changed ? out : messages;
85
+ }
86
+
87
+ /**
88
+ * `messages` for a request prefix that changed under them: no thinking replay
89
+ * at all. An open tool round that carries thinking can neither keep it (bound
90
+ * to the old prefix) nor lose it (its continuation must start with it), so it
91
+ * is ended first by a runtime turn right after its last tool result, ahead of
92
+ * any later input (a task notification stays pending after it); the next
93
+ * request then starts a new turn. Never mutates; the same array when nothing
94
+ * changed.
95
+ */
96
+ export function rebindToChangedPrefix(messages) {
97
+ if (!Array.isArray(messages)) return messages;
98
+ const open = openToolRoundStart(messages);
99
+ if (open < 0) return withoutThinkingReplay(messages);
100
+ let end = messages.findLastIndex((message) => message?.role === 'assistant') + 1;
101
+ while (messages[end]?.role === 'tool') end += 1;
102
+ const roundThinks = messages
103
+ .slice(open, end)
104
+ .some((message) => assistantMessageWithoutThinkingReplay(message) !== null);
105
+ return withoutThinkingReplay(
106
+ roundThinks ? [...messages.slice(0, end), toolRoundClosure(), ...messages.slice(end)] : messages
107
+ );
108
+ }
@@ -103,8 +103,8 @@ function crossTurnStub(batch, call, ctSig) {
103
103
  // (which spans ONE assistant turn): when the model re-issues an IDENTICAL
104
104
  // normalized call that has already failed repeatFailLimit times in a row
105
105
  // across iterations, stop re-executing — the result will not change, and
106
- // each retry burns a full LLM round-trip with no iteration cap to end it. The
107
- // call stays unresolved; the guard only skips re-execution.
106
+ // each retry burns a full LLM round-trip. The call stays unresolved; the
107
+ // guard only skips re-execution.
108
108
  function repeatFailureSkip(batch, call, sigs) {
109
109
  const { sessionRef, repeatFailLimit } = batch;
110
110
  const rfg = sessionRef?._repeatFailGuard;
@@ -4,6 +4,7 @@
4
4
  // consumes.
5
5
  import { resolve as resolvePath, isAbsolute } from 'node:path';
6
6
  import { normalizeToolEnvelope } from '../tool-envelope.mjs';
7
+ import { effectiveToolCwd } from '../../tools/builtin/bash-tool/shell-cwd.mjs';
7
8
  import {
8
9
  invalidatePathForSession,
9
10
  clearReadDedupSession,
@@ -85,7 +86,7 @@ async function fireToolFailureHook(batch, call, result) {
85
86
  await hook({
86
87
  name: call.name,
87
88
  args: call.arguments,
88
- cwd: batch.cwd,
89
+ cwd: effectiveToolCwd(call.name, call.arguments, batch.cwd),
89
90
  sessionId: batch.sessionId,
90
91
  toolCallId: call.id,
91
92
  result: typeof result === 'string' ? result : String(result ?? ''),
@@ -44,6 +44,7 @@ import {
44
44
  } from '../../../../shared/transcript-metadata.mjs';
45
45
  import { routineTriggerField } from '../../../../shared/routine-trigger.mjs';
46
46
  import { isImportedMessage } from '../imported-message.mjs';
47
+ import { toolRunLine } from '../conversation-import/turns.mjs';
47
48
  import { isContextAckMessage } from '../compact/user-message-kind.mjs';
48
49
  import { isRoutineResultMessage, routineResultNotice } from '../routine-result.mjs';
49
50
  import { heldRequestNotice, isHeldRequestMessage } from '../human-gate/held-message.mjs';
@@ -64,6 +65,20 @@ function restoredFailureFields(value) {
64
65
  };
65
66
  }
66
67
 
68
+ /** Whether `message` was posted into the thread outside any turn: it says so
69
+ * (`transcript.posted`, stamped by agent-home-delivery.mjs), or it is a row
70
+ * stored before that marker existed. Those carry the id agent-home-delivery
71
+ * mints for every posted row (`messageIdOf`: `routine_<runId>`) and are not
72
+ * prompts: an agent's own message (assistant role) or a result/held-request
73
+ * notice (stored under the user role, but not a prompt). The `routine_` scheme
74
+ * alone is not enough: routine-home-turn.mjs:144 gives the prompt of a routine
75
+ * fire (user role) the same prefix, and that prompt opens a real turn. */
76
+ function isPostedMessage(message, transcript) {
77
+ if (transcript.posted === true) return true;
78
+ if (typeof transcript.messageId !== 'string' || !transcript.messageId.startsWith('routine_')) return false;
79
+ return message?.role !== 'user' || isRoutineResultMessage(message) || isHeldRequestMessage(message);
80
+ }
81
+
67
82
  function restoredTranscriptMetadata(message) {
68
83
  const value = message?.meta?.transcript;
69
84
  if (!value || typeof value !== 'object') return {};
@@ -87,6 +102,8 @@ function restoredTranscriptMetadata(message) {
87
102
  // messages back to these rows.
88
103
  ...(typeof value.messageId === 'string' && value.messageId ? { messageId: value.messageId } : {}),
89
104
  ...(Number.isFinite(Number(value.at)) ? { at: Number(value.at) } : {}),
105
+ // Delivered into the thread outside any turn (agent-home-delivery.mjs).
106
+ ...(isPostedMessage(message, value) ? { posted: true } : {}),
90
107
  ...transcriptRouteMetadataFields(value),
91
108
  ...(typeof value.sender === 'string' && value.sender ? { sender: value.sender } : {}),
92
109
  ...(typeof value.device === 'string' && value.device ? { device: value.device } : {}),
@@ -124,7 +141,64 @@ function restoredContentText(message) {
124
141
  return typeof message?.content === 'string' ? message.content : toolResultText(message?.content);
125
142
  }
126
143
 
144
+ // The runs of tool use an imported assistant message recorded (conversation-import
145
+ // turns.mjs), kept only where the text still holds exactly their canonical line.
146
+ function importedToolRuns(message) {
147
+ const runs = message?.meta?.importedToolRuns;
148
+ if (!isImportedMessage(message) || typeof message.content !== 'string' || !Array.isArray(runs)) return [];
149
+ let cursor = 0;
150
+ return runs.filter((run) => {
151
+ const valid =
152
+ Number.isInteger(run?.start) &&
153
+ Number.isInteger(run?.end) &&
154
+ run.start >= cursor &&
155
+ run.end > run.start &&
156
+ run.end <= message.content.length &&
157
+ Array.isArray(run.tools) &&
158
+ run.tools.length > 0 &&
159
+ run.tools.every((tool) => typeof tool?.name === 'string' && Number.isInteger(tool.count) && tool.count > 0) &&
160
+ message.content.slice(run.start, run.end) === toolRunLine(run.tools);
161
+ if (valid) cursor = run.end;
162
+ return valid;
163
+ });
164
+ }
165
+
166
+ // An imported reply with tool use: its text around each run as assistant rows,
167
+ // each run as tool rows (one per tool, counted). The calls' results were never
168
+ // imported; the `imported` mark lets the row say so.
169
+ function restoredImportedAssistantItems(message, runs, nextId) {
170
+ const { completion: _completion, ...metadata } = restoredTranscriptMetadata(message);
171
+ const at = Number(message?.meta?.transcript?.at);
172
+ const items = [];
173
+ const pushText = (raw) => {
174
+ const text = raw.trim();
175
+ if (text) items.push({ kind: 'assistant', id: nextId(), text, ...metadata });
176
+ };
177
+ let cursor = 0;
178
+ for (const run of runs) {
179
+ pushText(message.content.slice(cursor, run.start));
180
+ for (const { name, count } of run.tools) {
181
+ if (isTranscriptHiddenControlToolName(name)) continue;
182
+ items.push({
183
+ kind: 'tool',
184
+ id: nextId(),
185
+ name,
186
+ imported: true,
187
+ expanded: false,
188
+ count,
189
+ completedCount: count,
190
+ ...(Number.isFinite(at) ? { at, startedAt: at, completedAt: at } : {}),
191
+ });
192
+ }
193
+ cursor = run.end;
194
+ }
195
+ pushText(message.content.slice(cursor));
196
+ return items;
197
+ }
198
+
127
199
  function restoredAssistantTranscriptItems(message, nextId) {
200
+ const runs = importedToolRuns(message);
201
+ if (runs.length) return restoredImportedAssistantItems(message, runs, nextId);
128
202
  const text = restoredContentText(message).trim();
129
203
  if (!text) return [];
130
204
  const { completion, ...metadata } = restoredTranscriptMetadata(message);
@@ -323,7 +397,7 @@ function mergeRestoredToolItems(items) {
323
397
  // Result-dependent hiding (built-in skill loads) resolves here, after
324
398
  // every role:'tool' result has been attached to its restored call.
325
399
  if (item?.kind === 'tool' && isTranscriptHiddenToolItem(item)) continue;
326
- const mergeable = item?.kind === 'tool' && item.aggregate !== true;
400
+ const mergeable = item?.kind === 'tool' && item.aggregate !== true && item.imported !== true;
327
401
  if (!mergeable) {
328
402
  flushRun();
329
403
  merged.push(item);
@@ -363,7 +437,8 @@ function restoredMessageItemUpperBound(message) {
363
437
  const calls = restoredMessageToolCalls(message);
364
438
  const content = message?.content;
365
439
  const hasContent = typeof content === 'string' ? content.length > 0 : Array.isArray(content) && content.length > 0;
366
- return Number(hasContent) + completionCount + calls.length + boundaries;
440
+ const importedRows = importedToolRuns(message).reduce((total, run) => total + run.tools.length + 1, 0);
441
+ return Number(hasContent) + completionCount + calls.length + importedRows + boundaries;
367
442
  }
368
443
 
369
444
  // One restored tool card for a parsed notification/completion envelope.
@@ -400,7 +475,7 @@ function restoredUserTranscriptItems(message, nextId, userText) {
400
475
  // A schedule's result in its owner's home thread: a notice row.
401
476
  // A held request of an unattended run (human-gate/held-message.mjs) likewise.
402
477
  if (isRoutineResultMessage(message) || isHeldRequestMessage(message)) {
403
- const { messageId, at } = restoredTranscriptMetadata(message);
478
+ const { messageId, at, posted } = restoredTranscriptMetadata(message);
404
479
  return [
405
480
  {
406
481
  kind: 'notice',
@@ -408,6 +483,7 @@ function restoredUserTranscriptItems(message, nextId, userText) {
408
483
  ...(isHeldRequestMessage(message) ? heldRequestNotice(message) : routineResultNotice(message)),
409
484
  ...(messageId ? { messageId } : {}),
410
485
  ...(at ? { at } : {}),
486
+ ...(posted ? { posted } : {}),
411
487
  },
412
488
  ];
413
489
  }
@@ -13,6 +13,7 @@ import { formatAggregateDetail, summarizeToolResult, toolLoadingTargets } from '
13
13
  import { normalizeToolName } from '../../../../shared/tool-primitives.mjs';
14
14
  import { gitResultError, gitResultExitCode } from '../../../../shared/tool-card-model/git-result.mjs';
15
15
  import { readRowsForDisplay } from '../../../../shared/read-row-numbers.mjs';
16
+ import { visualizeOwnerMetaSessionId } from '../../../../visualize-bridge/tool-meta.mjs';
16
17
 
17
18
  const CANCELLED_RESULT_STATUS_LINE = '[status: cancelled]';
18
19
 
@@ -292,15 +293,16 @@ export function assignUiDiffFromMessage(target, source) {
292
293
  }
293
294
 
294
295
  /** Structured side channel a tool result may carry next to its text (the
295
- * Computer Use capability refusal): a stable code plus the capability names.
296
- * Anything else is dropped so stored history stays small and predictable. */
297
- export function toolMetaFromMessage(source) {
296
+ * Computer Use capability refusal): a stable code plus the capability names,
297
+ * and the owner conversation of a `visualize` call run for another session's
298
+ * work (visualize-bridge/tool-meta.mjs). Anything else is dropped so stored
299
+ * history stays small and predictable. */
300
+ function toolMetaFromMessage(source) {
298
301
  const meta = source?.toolMeta ?? source?.content?.toolMeta;
299
302
  if (!meta || typeof meta !== 'object' || typeof meta.code !== 'string' || !meta.code) return undefined;
300
- const missing = Array.isArray(meta.missing)
301
- ? meta.missing.filter((name) => typeof name === 'string' && name)
302
- : [];
303
- return { code: meta.code, missing };
303
+ const missing = Array.isArray(meta.missing) ? meta.missing.filter((name) => typeof name === 'string' && name) : [];
304
+ const ownerSessionId = visualizeOwnerMetaSessionId(meta.ownerSessionId);
305
+ return { code: meta.code, missing, ...(ownerSessionId ? { ownerSessionId } : {}) };
304
306
  }
305
307
 
306
308
  export function toolMetaPatchFromMessage(source) {
@@ -132,8 +132,8 @@ export function toolGroupedDisplayFallback(resultText, text, rawText) {
132
132
  return resultText;
133
133
  }
134
134
 
135
- export function toolErrorDisplay(value, surface = 'tool') {
136
- const text = presentErrorText(value, { surface });
135
+ export function toolErrorDisplay(value, surface = 'tool', { providerLabel } = {}) {
136
+ const text = presentErrorText(value, { surface, providerLabel });
137
137
  if (
138
138
  /^(?:Search failed|Fetch failed|No first response|No progress|Cancelled|The .+ went stale|(?:Web search agent|Agent|Tool|Request) (?:stopped|was cancelled))/i.test(
139
139
  text
@@ -3,6 +3,7 @@
3
3
  // session shows the same failure, reason and quota stop as the live one.
4
4
  import { errText } from '../../../shared/err-text.mjs';
5
5
  import { safeErrorDetails } from '../../../shared/error-presentation.mjs';
6
+ import { providerDisplayName } from '../../../shared/provider-display-name.mjs';
6
7
  import { providerErrorKind } from '../providers/provider-error-kind.mjs';
7
8
  import { toolErrorDisplay } from './transcript-restore/tool-result-text.mjs';
8
9
 
@@ -39,7 +40,10 @@ export function turnFailureRecord(error, route = {}) {
39
40
  providerKind,
40
41
  errorKind,
41
42
  quota,
42
- detail: toolErrorDisplay(error, 'turn').replace(/^Error:\s*/i, ''),
43
+ // The provider is named from the turn's own route, never from the error.
44
+ detail: toolErrorDisplay(error, 'turn', {
45
+ providerLabel: route.provider ? providerDisplayName(route.provider) : undefined,
46
+ }).replace(/^Error:\s*/i, ''),
43
47
  errorDetails: safeErrorDetails(errText(error)),
44
48
  };
45
49
  }
@@ -259,6 +259,29 @@ export const PROVIDER_WS_SEMANTIC_IDLE_TIMEOUT_MS = resolveTimeoutMs(
259
259
  { minMs: 10_000, maxMs: Math.max(10_000, STALL_ABORT_MS - STALL_TICK_MS) }
260
260
  );
261
261
 
262
+ // First-OUTPUT window of one provider stream: from the stream opening until
263
+ // the model's first semantic output (reasoning, text or a tool call). Server
264
+ // metadata and keepalives (response.created / in_progress, an empty reasoning
265
+ // or message item, a role-only chunk, pings) neither end this phase nor start
266
+ // the semantic-idle clock, so a reasoning model may think silently past the
267
+ // idle window (issue #244: 4–6 min on a large post-tool-result prompt). The
268
+ // window sits one tick under the stall abort — the same ceiling the semantic
269
+ // idle uses — so the provider still fails (and may retry or fall back) before
270
+ // the agent watchdog's first-output deadline (600s default), and it is never
271
+ // shorter than the idle window it replaces. Not separately tunable: it
272
+ // follows STALL_TIMEOUT_S.
273
+ export const PROVIDER_FIRST_OUTPUT_TIMEOUT_MS = Math.max(
274
+ PROVIDER_SEMANTIC_IDLE_TIMEOUT_MS,
275
+ PROVIDER_WS_SEMANTIC_IDLE_TIMEOUT_MS,
276
+ STALL_ABORT_MS - STALL_TICK_MS
277
+ );
278
+
279
+ /** The first-output window of a stream whose semantic idle is `idleMs`: a
280
+ * longer idle window (a provider profile) is never cut short by it. */
281
+ export function providerFirstOutputTimeoutMs(idleMs) {
282
+ return Math.max(idleMs, PROVIDER_FIRST_OUTPUT_TIMEOUT_MS);
283
+ }
284
+
262
285
  /**
263
286
  * The longest a provider's own first-byte handling may legitimately run
264
287
  * before it gives up, over every attempt it permits: `windowMs(n)` is the wait
@@ -780,10 +780,13 @@ function guardRead(a) {
780
780
  }
781
781
 
782
782
  function guardShell(a) {
783
- const allowed = new Set(['command', 'timeout_ms', 'wait_ms', 'background']);
783
+ const allowed = new Set(['command', 'cwd', 'timeout_ms', 'wait_ms', 'background']);
784
784
  const unsupported = Object.keys(a).find((key) => !allowed.has(key));
785
785
  if (unsupported) {
786
- return `Error: shell arg "${unsupported}" is unsupported; use only command, timeout_ms, wait_ms, and background`;
786
+ return `Error: shell arg "${unsupported}" is unsupported; use only command, cwd, timeout_ms, wait_ms, and background`;
787
+ }
788
+ if (hasOwn(a, 'cwd') && (typeof a.cwd !== 'string' || a.cwd.trim().length === 0)) {
789
+ return `Error: shell arg "cwd" must be a non-empty string (got ${describeType(a.cwd)})`;
787
790
  }
788
791
  if (hasOwn(a, 'background') && typeof a.background !== 'boolean') {
789
792
  return `Error: shell arg "background" must be a boolean (got ${describeType(a.background)})`;
@@ -52,7 +52,17 @@ function registerPromotedTask({ result, command, cwd, options, startedAtMs }) {
52
52
  // running, now promoted as a tracked shell-job. Surface the task_id + partial
53
53
  // output for manual task control instead of keeping the tool call open until
54
54
  // the hard timeout.
55
- export function renderBackgroundedResult({ result, command, cwd, options, startedAtMs, teePlan, stdout, stderr }) {
55
+ export function renderBackgroundedResult({
56
+ result,
57
+ command,
58
+ cwd,
59
+ options,
60
+ startedAtMs,
61
+ teePlan,
62
+ stdout,
63
+ stderr,
64
+ notes = '',
65
+ }) {
56
66
  let task = null;
57
67
  if (result.jobId) {
58
68
  task = registerPromotedTask({ result, command, cwd, options, startedAtMs });
@@ -91,6 +101,7 @@ export function renderBackgroundedResult({ result, command, cwd, options, starte
91
101
  )
92
102
  : renderBackgroundPartialOutput(stdout, stderr);
93
103
  const lines = _backgroundResultLines({
104
+ warning: notes,
94
105
  taskBlock,
95
106
  message: result.backgroundMessage || DEFAULT_BACKGROUND_MESSAGE,
96
107
  partialOutput,
@@ -28,9 +28,9 @@ function prefixPowerShellUtf8(command) {
28
28
  // UTF-8 prefix (+ optional filter-tee rescue), or a POSIX bash/zsh snapshot
29
29
  // wrapper delivered through the environment. Returns `{ failure }` when the
30
30
  // snapshot wrapper cannot be built.
31
- export async function planShellInvocation({ command, resolvedSpec, cwd }) {
31
+ export async function planShellInvocation({ command, resolvedSpec, cwd, sessionId = null }) {
32
32
  const { shell, shellArg, shellArgs, shellType } = resolvedSpec;
33
- const spawnEnv = buildShellSpawnEnv(cwd);
33
+ const spawnEnv = buildShellSpawnEnv(cwd, process.env, sessionId);
34
34
  const plan = {
35
35
  execShell: shell,
36
36
  execShellArg: shellArg,