mixdog 1.3.4 → 1.4.0

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 (472) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +17 -2
  3. package/README.md +11 -0
  4. package/package.json +3 -11
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/embed-google-oauth-client.mjs +49 -0
  7. package/scripts/gate-local.mjs +4 -2
  8. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  9. package/scripts/native-release-status.mjs +2 -2
  10. package/scripts/recall-history-cases.json +1 -1
  11. package/scripts/suite-health.mjs +10 -1
  12. package/scripts/test.mjs +12 -11
  13. package/src/agents/reviewer/AGENT.md +7 -11
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/defaults/shipped-history.json +25 -1
  16. package/src/defaults/skills/browser-use/SKILL.md +77 -17
  17. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  18. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  19. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  20. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  21. package/src/defaults/skills/computer-use/SKILL.md +33 -9
  22. package/src/defaults/skills/setup/SKILL.md +29 -2
  23. package/src/defaults/skills/setup/references/actions.md +117 -28
  24. package/src/defaults/skills/setup/references/surfaces.md +77 -35
  25. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  26. package/src/defaults/skills/visualize/SKILL.md +2 -1
  27. package/src/lib/keychain-cjs.cjs +359 -29
  28. package/src/lib/rules-builder.cjs +10 -8
  29. package/src/rules/agent/AGENT.md +6 -6
  30. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  31. package/src/rules/agent-mode/MIXY.md +12 -0
  32. package/src/rules/lead/LEAD.md +18 -20
  33. package/src/rules/shared/05-tool-calls.md +5 -6
  34. package/src/rules/shared/10-tool-workflow.md +2 -0
  35. package/src/rules/shared/60-verification.md +7 -5
  36. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  37. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  38. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  39. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/config.mjs +34 -0
  41. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  42. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
  43. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
  44. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  45. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
  46. package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  49. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  50. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  51. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  53. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
  54. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
  55. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  56. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  60. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +160 -69
  61. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
  63. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  65. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  66. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  67. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  68. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  69. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
  70. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  78. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  79. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  81. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  82. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  83. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  84. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  85. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  86. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  87. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  88. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  89. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  90. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  91. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  92. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  93. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  94. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  95. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  97. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  98. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  99. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  100. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  101. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  103. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +19 -1
  104. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  109. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  113. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  114. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  115. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  116. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  117. package/src/runtime/agent/orchestrator/providers/registry.mjs +43 -3
  118. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  119. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  120. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  121. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
  122. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  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 +1 -1
  127. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  128. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  131. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  132. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  133. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  134. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  135. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  136. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  137. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  138. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  139. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  140. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
  141. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
  142. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  143. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  144. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +8 -0
  145. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
  146. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
  147. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  148. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
  149. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
  151. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
  152. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
  153. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  154. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
  155. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
  156. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
  157. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  158. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +14 -4
  159. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  163. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
  164. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  165. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  166. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  167. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  168. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  172. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  173. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
  174. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  175. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  176. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
  177. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
  178. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  179. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
  180. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  182. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
  183. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  184. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
  185. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  186. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  187. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  188. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
  189. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
  191. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  192. package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
  193. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  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-persistence-events.mjs +29 -0
  203. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
  207. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
  208. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  209. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  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/tool-batch/state.mjs +4 -0
  214. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
  216. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  217. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  218. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  219. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  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.mjs +25 -5
  225. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
  226. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  227. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  228. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  229. package/src/runtime/browser-bridge/client.mjs +73 -8
  230. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  231. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  232. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  233. package/src/runtime/channels/lib/config.mjs +6 -61
  234. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  235. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  236. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  237. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  238. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  239. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  240. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  241. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  242. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  243. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  244. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  245. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  246. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  247. package/src/runtime/channels/lib/scheduler.mjs +135 -154
  248. package/src/runtime/channels/lib/schedules-db.mjs +83 -11
  249. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  250. package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
  251. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  252. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  253. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  254. package/src/runtime/channels/lib/worker-main.mjs +19 -34
  255. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  256. package/src/runtime/computer-bridge/actions.mjs +9 -1
  257. package/src/runtime/computer-bridge/client.mjs +180 -8
  258. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  259. package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
  260. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  261. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  262. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  263. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  264. package/src/runtime/connectors/google-mcp.mjs +10 -12
  265. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  266. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  268. package/src/runtime/office/com/com-adapter.mjs +17 -1
  269. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  270. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  271. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  272. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  273. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  274. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  275. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  276. package/src/runtime/session-search/session-search-db.mjs +73 -9
  277. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  278. package/src/runtime/shared/abort-race.mjs +89 -0
  279. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  280. package/src/runtime/shared/agent-kind.mjs +4 -3
  281. package/src/runtime/shared/bot-hops.mjs +62 -2
  282. package/src/runtime/shared/bounded-download.mjs +8 -3
  283. package/src/runtime/shared/config.mjs +51 -35
  284. package/src/runtime/shared/connector-accounts.mjs +20 -10
  285. package/src/runtime/shared/connector-catalog.d.mts +33 -2
  286. package/src/runtime/shared/connector-catalog.mjs +166 -8
  287. package/src/runtime/shared/connector-triggers.mjs +22 -19
  288. package/src/runtime/shared/defaults-separation.mjs +2 -14
  289. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  290. package/src/runtime/shared/developer-options.mjs +32 -1
  291. package/src/runtime/shared/err-text.mjs +24 -15
  292. package/src/runtime/shared/file-permissions.d.mts +0 -8
  293. package/src/runtime/shared/file-permissions.mjs +0 -11
  294. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  295. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  296. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  297. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  298. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  299. package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
  300. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  301. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  302. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  303. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  304. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  305. package/src/runtime/shared/mixy-presence.mjs +22 -0
  306. package/src/runtime/shared/orchestration.d.mts +2 -0
  307. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  308. package/src/runtime/shared/profile-config.cjs +1 -1
  309. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  310. package/src/runtime/shared/prompt-origin.mjs +21 -0
  311. package/src/runtime/shared/provider-accounts.mjs +231 -59
  312. package/src/runtime/shared/provider-api-key.mjs +19 -8
  313. package/src/runtime/shared/provider-display-name.mjs +29 -0
  314. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  315. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  316. package/src/runtime/shared/routine-trigger.mjs +52 -0
  317. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  318. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  319. package/src/runtime/shared/session-activity-signal.mjs +34 -1
  320. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  321. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  322. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  323. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  324. package/src/runtime/shared/tool-result-summary.mjs +1 -14
  325. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  326. package/src/runtime/shared/user-data-guard.mjs +30 -2
  327. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  328. package/src/runtime/shared/worktrees/test-support.mjs +9 -4
  329. package/src/runtime/terminal-bridge/client.mjs +10 -1
  330. package/src/runtime/visualize-bridge/client.mjs +27 -8
  331. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  332. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  333. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  334. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  335. package/src/session-runtime/agent-home-delivery.mjs +486 -179
  336. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  337. package/src/session-runtime/agent-task-sessions.mjs +561 -199
  338. package/src/session-runtime/boot/apis.mjs +9 -0
  339. package/src/session-runtime/boot/begin.mjs +3 -2
  340. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  341. package/src/session-runtime/boot/providers.mjs +3 -0
  342. package/src/session-runtime/boot/tools.mjs +8 -1
  343. package/src/session-runtime/bot-chain.mjs +32 -0
  344. package/src/session-runtime/bot-status.mjs +7 -4
  345. package/src/session-runtime/channel-config-api.mjs +63 -17
  346. package/src/session-runtime/config-lifecycle.mjs +6 -0
  347. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  348. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
  349. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
  350. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  351. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  352. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  353. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  354. package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
  355. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  356. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  357. package/src/session-runtime/mcp-glue/server-catalog.mjs +61 -3
  358. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  359. package/src/session-runtime/mixy-heartbeat.mjs +927 -0
  360. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  361. package/src/session-runtime/notification-bus.mjs +31 -117
  362. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  363. package/src/session-runtime/notification-listeners.mjs +76 -0
  364. package/src/session-runtime/owned-automation-run.mjs +35 -13
  365. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  366. package/src/session-runtime/provider-auth/login.mjs +7 -0
  367. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  368. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  369. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  370. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  371. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  372. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  373. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  374. package/src/session-runtime/routine-home-turn.mjs +33 -6
  375. package/src/session-runtime/routine-owner.mjs +40 -9
  376. package/src/session-runtime/schedule-session-run.mjs +7 -3
  377. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  378. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  379. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
  380. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  381. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  382. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  383. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  384. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  385. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  386. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  387. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  388. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  389. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  390. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  391. package/src/session-runtime/services/channel-admin.mjs +73 -31
  392. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  393. package/src/session-runtime/services/channel-worker.mjs +1 -1
  394. package/src/session-runtime/services/provider-admin.mjs +128 -25
  395. package/src/session-runtime/services/schedule-access.mjs +14 -0
  396. package/src/session-runtime/services/seeds.mjs +0 -28
  397. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  398. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  399. package/src/session-runtime/session-create/session-options.mjs +8 -4
  400. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  401. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  402. package/src/session-runtime/settings-system-api.mjs +28 -1
  403. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  404. package/src/session-runtime/setup-tool/executor.mjs +187 -29
  405. package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
  406. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  407. package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
  408. package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
  409. package/src/session-runtime/task-session-route.mjs +99 -0
  410. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  411. package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
  412. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  413. package/src/session-runtime/tool-surface.mjs +4 -0
  414. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  415. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  416. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  417. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  418. package/src/session-runtime/workspace/transitions.mjs +10 -2
  419. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  420. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  421. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  422. package/src/standalone/channel-transport.mjs +1 -1
  423. package/src/standalone/daemon-channels-loader.mjs +10 -8
  424. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  425. package/src/standalone/daemon-session-control/request.mjs +51 -0
  426. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  427. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  428. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  429. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  430. package/src/standalone/daemon-session-control.mjs +161 -157
  431. package/src/standalone/daemon.mjs +33 -2
  432. package/src/standalone/session-client.mjs +7 -3
  433. package/src/standalone/session-protocol.mjs +10 -0
  434. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  435. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  436. package/src/standalone/session-service/quota-resume.mjs +3 -0
  437. package/src/standalone/session-service/retention/busy.mjs +65 -1
  438. package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
  439. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  440. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  441. package/src/standalone/session-service.mjs +13 -0
  442. package/src/standalone/session-tool-output.mjs +21 -10
  443. package/src/tui/app/model-options.mjs +4 -27
  444. package/src/tui/dist/index.mjs +81 -65
  445. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  446. package/src/tui/session/initial-state.mjs +3 -0
  447. package/src/tui/session/notice-surface.mjs +23 -1
  448. package/src/tui/session/queue-helpers.mjs +3 -42
  449. package/src/tui/session/session-api/integrations.mjs +1 -0
  450. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  451. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  452. package/src/tui/session/session-api/routes-write.mjs +5 -1
  453. package/src/tui/session/session-api/routes.mjs +1 -0
  454. package/src/tui/session/session-api/settings.mjs +30 -2
  455. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  456. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  457. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  458. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  459. package/src/tui/session/session-flow/drain.mjs +118 -149
  460. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  461. package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
  462. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  463. package/src/tui/session/tool-approval-request.mjs +39 -0
  464. package/src/tui/session/tool-approval-settle.mjs +62 -0
  465. package/src/tui/session/tool-approval.mjs +69 -115
  466. package/src/tui/session/tui-steering-persist.mjs +8 -1
  467. package/src/tui/session/turn-stream.mjs +36 -3
  468. package/src/tui/session/turn.mjs +23 -2
  469. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  470. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  471. package/scripts/code-graph-description-contract.mjs +0 -188
  472. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -13,20 +13,14 @@
13
13
  * that session's own turn ending, and its answer is forwarded to the owning
14
14
  * queue, so either place settles the one request once.
15
15
  */
16
- import {
17
- humanRequestFields,
18
- normalizeHumanResponse,
19
- } from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
20
16
  import {
21
17
  delegateApproval,
22
18
  delegatedApprovalsFor,
23
19
  registerApprovalQueue,
24
- withdrawDelegatedApproval,
25
20
  } from '../../runtime/shared/delegated-approval-host.mjs';
26
-
27
- /** Approvals a sub-agent shows in the top-level chat too; a question, a secret
28
- * or a takeover stays in its own session (its answer or window is there). */
29
- const DELEGATED_KINDS = new Set(['', 'approval', 'outbound', 'permission']);
21
+ import { defaultApprovalTimeoutMs, normalizeToolApprovalRequest } from './tool-approval-request.mjs';
22
+ import { copyOutcome, finishedOutcome, forwardToOwner, settleToolApproval } from './tool-approval-settle.mjs';
23
+ import { createApprovalDelegation } from './tool-approval-delegation.mjs';
30
24
 
31
25
  /** The wait limit an approval has when its request names none, from
32
26
  * MIXDOG_TOOL_APPROVAL_TIMEOUT_MS (milliseconds, one second at least): null —
@@ -39,10 +33,18 @@ export function resolveToolApprovalTimeoutMs(env = process.env) {
39
33
  }
40
34
 
41
35
  export function createToolApproval({ getState, set, nextId, getDisposed, timeoutMs = null, surfaceOf = null }) {
42
- const defaultTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Number(timeoutMs) : null;
36
+ const defaultTimeoutMs = defaultApprovalTimeoutMs(timeoutMs);
43
37
  const toolApprovalQueue = [];
44
38
  let activeToolApproval = null;
39
+ // Copies of the ask_user questions of sessions this chat handed work to
40
+ // (`{ id, request, mirror }`): published as `handoffQuestions`, each shown
41
+ // at its hand-off line for the user alone (no transcript row), outside the
42
+ // queue so they never hold this chat's own requests back and several show
43
+ // at once. Answered here, the answer goes to the asking session's queue.
44
+ const handoffQuestions = [];
45
+ const publishHandoffQuestions = () => set({ handoffQuestions: handoffQuestions.map((entry) => entry.request) });
45
46
  const ownSessionId = () => String(getState()?.sessionId || '');
47
+ const { delegationSurface, handsOff, offerToHandoffs } = createApprovalDelegation({ surfaceOf, ownSessionId });
46
48
  const unregister =
47
49
  typeof surfaceOf === 'function'
48
50
  ? registerApprovalQueue({
@@ -53,33 +55,6 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
53
55
  })
54
56
  : () => {};
55
57
 
56
- function normalizeToolApprovalRequest(input = {}, id = nextId()) {
57
- const now = Date.now();
58
- // An explicit `timeoutMs: null` means no wait limit (no timer, no expiry);
59
- // any other missing/invalid value falls back to the session default,
60
- // which is itself no limit unless the runtime configures one.
61
- const requestTimeoutMs =
62
- input?.timeoutMs === null
63
- ? null
64
- : Number.isFinite(Number(input?.timeoutMs)) && Number(input.timeoutMs) > 0
65
- ? Number(input.timeoutMs)
66
- : defaultTimeoutMs;
67
- return {
68
- id,
69
- name: String(input?.name || input?.tool_name || 'tool'),
70
- kind: typeof input?.kind === 'string' ? input.kind : '',
71
- args: input?.args ?? input?.tool_input ?? null,
72
- cwd: input?.cwd || null,
73
- sessionId: input?.sessionId || input?.session_id || null,
74
- toolCallId: input?.toolCallId || input?.tool_use_id || null,
75
- reason: String(input?.reason || input?.message || 'approval requested by hook').trim(),
76
- requestedAt: now,
77
- timeoutMs: requestTimeoutMs,
78
- expiresAt: requestTimeoutMs === null ? null : now + requestTimeoutMs,
79
- // outbound / secret / takeover / permission fields (human-gate/requests.mjs).
80
- ...humanRequestFields(input),
81
- };
82
- }
83
58
  // A request that has a limit expires from ITS OWN requestedAt, queued or
84
59
  // active. Arming the timer only on presentation let a queued request sit past
85
60
  // expiresAt (retaining its promise and surfacing an obsolete approval later).
@@ -93,54 +68,35 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
93
68
  }, remainingMs);
94
69
  entry.timer.unref?.();
95
70
  }
96
- // Settle one entry: drop its timeout, then hand the waiter its answer. The
97
- // resolve stays guarded — a waiter whose caller already went away must never
98
- // take the rest of the queue down with it.
99
- function settleToolApproval(entry, approved, reason, answers, reply, extra, device = '') {
100
- if (entry?.timer) clearTimeout(entry.timer);
101
- const result = { approved, reason };
102
- if (answers !== undefined) result.answers = answers;
103
- if (reply !== undefined) result.reply = reply;
104
- // A human-kind request answers with its canonical response (never a value).
105
- if (entry?.request?.remember) {
106
- Object.assign(result, normalizeHumanResponse(entry.request, approved, extra));
107
- if (device) result.device = device;
108
- }
109
- if (extra?.timedOut === true) result.timedOut = true;
110
- // Settled here: its copy in the top-level chat goes away.
111
- if (entry?.delegated) withdrawDelegatedApproval(entry.id, { approved, device });
112
- try {
113
- entry.resolve(result);
114
- } catch {}
115
- }
116
- /** Hand a copy's answer to the queue that owns the request; false when the
117
- * owner had already settled it. */
118
- function forwardToOwner(entry, approved, reason, device, answers, reply, extra) {
119
- try {
120
- return entry.mirror.answer(approved, reason, device, answers, reply, extra) === true;
121
- } catch {
122
- return false;
123
- }
124
- }
125
71
  function offerDelegatedApproval(delegated) {
126
72
  if (getDisposed() || delegated.sessionId !== ownSessionId()) return;
73
+ if (delegated.request?.kind === 'question') {
74
+ if (handoffQuestions.some((entry) => entry.id === delegated.id)) return;
75
+ handoffQuestions.push({ id: delegated.id, request: delegated.request, mirror: delegated });
76
+ publishHandoffQuestions();
77
+ return;
78
+ }
127
79
  if (activeToolApproval?.id === delegated.id || toolApprovalQueue.some((entry) => entry.id === delegated.id)) return;
128
80
  toolApprovalQueue.push({ id: delegated.id, request: delegated.request, mirror: delegated, timer: null });
129
81
  presentNextToolApproval();
130
82
  }
131
83
  function withdrawDelegatedCopy(id, result) {
84
+ const question = handoffQuestions.findIndex((entry) => entry.id === id);
85
+ if (question >= 0) {
86
+ handoffQuestions.splice(question, 1);
87
+ if (!getDisposed()) publishHandoffQuestions();
88
+ return;
89
+ }
132
90
  if (activeToolApproval?.mirror && activeToolApproval.id === id) {
133
91
  activeToolApproval = null;
134
- const device = String(result?.device || '');
135
- set({
136
- toolApproval: null,
137
- toolApprovalResult: device ? { id, approved: result.approved === true, device, at: Date.now() } : null,
138
- });
92
+ set({ toolApproval: null, toolApprovalResult: copyOutcome(id, result) });
139
93
  presentNextToolApproval();
140
94
  return;
141
95
  }
142
96
  const index = toolApprovalQueue.findIndex((entry) => entry.mirror && entry.id === id);
143
- if (index >= 0) toolApprovalQueue.splice(index, 1);
97
+ if (index < 0) return;
98
+ toolApprovalQueue.splice(index, 1);
99
+ presentNextToolApproval();
144
100
  }
145
101
  /** Show the delegated approvals waiting for this session (it loaded, or its
146
102
  * session id became the top-level one after the request was made). */
@@ -149,16 +105,23 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
149
105
  if (!sessionId || typeof surfaceOf !== 'function') return;
150
106
  for (const delegated of delegatedApprovalsFor(sessionId)) offerDelegatedApproval(delegated);
151
107
  }
108
+ /** Show the next request when none is shown, and publish how many wait
109
+ * behind the shown one (`toolApprovalsWaiting`: the dock's "1/N"). */
152
110
  function presentNextToolApproval() {
153
- if (activeToolApproval || getDisposed()) return;
154
- const entry = toolApprovalQueue.shift();
155
- if (!entry) {
156
- if (getState().toolApproval) set({ toolApproval: null });
157
- return;
111
+ if (getDisposed()) return;
112
+ const patch = {};
113
+ if (!activeToolApproval) {
114
+ const entry = toolApprovalQueue.shift();
115
+ if (entry) {
116
+ activeToolApproval = entry;
117
+ armToolApprovalTimeout(entry);
118
+ patch.toolApproval = entry.request;
119
+ } else if (getState().toolApproval) patch.toolApproval = null;
120
+ }
121
+ if ((getState().toolApprovalsWaiting ?? 0) !== toolApprovalQueue.length) {
122
+ patch.toolApprovalsWaiting = toolApprovalQueue.length;
158
123
  }
159
- activeToolApproval = entry;
160
- armToolApprovalTimeout(entry);
161
- set({ toolApproval: entry.request });
124
+ if (Object.keys(patch).length > 0) set(patch);
162
125
  }
163
126
  function finishToolApproval(
164
127
  id,
@@ -173,12 +136,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
173
136
  if (activeToolApproval && activeToolApproval.id === targetId) {
174
137
  const entry = activeToolApproval;
175
138
  activeToolApproval = null;
176
- // Only an answer from a known device is attributed; a timeout or an
177
- // interrupt names nobody.
178
- const toolApprovalResult = device
179
- ? { id: targetId, approved: approved === true, device: String(device), at: Date.now() }
180
- : null;
181
- set({ toolApproval: null, toolApprovalResult });
139
+ set({ toolApproval: null, toolApprovalResult: finishedOutcome(targetId, approved, device, extra) });
182
140
  let accepted = true;
183
141
  if (entry.mirror) {
184
142
  accepted = forwardToOwner(entry, approved, reason, device, answers, reply, extra);
@@ -191,10 +149,17 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
191
149
  const index = toolApprovalQueue.findIndex((entry) => entry.id === targetId);
192
150
  if (index >= 0) {
193
151
  const [entry] = toolApprovalQueue.splice(index, 1);
152
+ presentNextToolApproval();
194
153
  if (entry.mirror) return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
195
154
  settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
196
155
  return true;
197
156
  }
157
+ const question = handoffQuestions.findIndex((entry) => entry.id === targetId);
158
+ if (question >= 0) {
159
+ const [entry] = handoffQuestions.splice(question, 1);
160
+ publishHandoffQuestions();
161
+ return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
162
+ }
198
163
  return false;
199
164
  }
200
165
  /** Deny this session's own requests. A copy of a sub-agent's request stays
@@ -202,11 +167,19 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
202
167
  * unanswered: the next runtime of this session adopts it again. */
203
168
  function denyAllToolApprovals(reason = 'approval cancelled') {
204
169
  const closing = getDisposed();
205
- if (closing) unregister();
170
+ if (closing) {
171
+ unregister();
172
+ // Dropped unanswered with this runtime: the next one adopts them again.
173
+ handoffQuestions.length = 0;
174
+ }
206
175
  if (activeToolApproval && !(activeToolApproval.mirror && !closing)) {
207
176
  const entry = activeToolApproval;
208
177
  activeToolApproval = null;
209
- if (!entry.mirror) settleToolApproval(entry, false, reason);
178
+ if (!entry.mirror) {
179
+ settleToolApproval(entry, false, reason);
180
+ // Stop/turn abort ended it: not a timeout, nobody answered.
181
+ set({ toolApprovalResult: { id: entry.id, approved: false, device: '', interrupted: true, at: Date.now() } });
182
+ }
210
183
  }
211
184
  const kept = [];
212
185
  while (toolApprovalQueue.length > 0) {
@@ -215,7 +188,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
215
188
  else if (!closing) kept.push(entry);
216
189
  }
217
190
  toolApprovalQueue.push(...kept);
218
- if (activeToolApproval) return;
191
+ if (activeToolApproval) return presentNextToolApproval();
219
192
  if (getState().toolApproval) set({ toolApproval: null });
220
193
  presentNextToolApproval();
221
194
  }
@@ -223,43 +196,24 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
223
196
  if (getDisposed()) return Promise.resolve({ approved: false, reason: 'runtime disposed' });
224
197
  return new Promise((resolve) => {
225
198
  const id = nextId();
226
- const full = normalizeToolApprovalRequest(input, id);
199
+ const full = normalizeToolApprovalRequest(input, id, defaultTimeoutMs);
227
200
  const surface = delegationSurface(full);
228
201
  if (surface) {
229
202
  // Who asks, from the top-level chat down ("사무관 › Worker"), and where the copy is.
230
203
  full.chain = surface.chain;
231
204
  full.surfaceSessionId = surface.sessionId;
232
205
  }
233
- const entry = { id, request: full, resolve, timer: null, delegated: Boolean(surface) };
206
+ const handoffs = !surface && handsOff(full);
207
+ const entry = { id, request: full, resolve, timer: null, delegated: Boolean(surface || handoffs) };
234
208
  toolApprovalQueue.push(entry);
235
209
  armToolApprovalTimeout(entry);
236
210
  presentNextToolApproval();
237
- if (surface) {
238
- delegateApproval({
239
- id,
240
- sessionId: surface.sessionId,
241
- request: full,
242
- answer: (approved, reason, device, answers, reply, extra) =>
243
- finishToolApproval(id, approved, reason, device, answers, reply, extra),
244
- });
245
- }
211
+ const answer = (approved, reason, device, answers, reply, extra) =>
212
+ finishToolApproval(id, approved, reason, device, answers, reply, extra);
213
+ if (surface) delegateApproval({ id, sessionId: surface.sessionId, request: full, answer });
214
+ if (handoffs) offerToHandoffs(id, full, answer);
246
215
  });
247
216
  }
248
- /** `{ sessionId, chain }` of the top-level chat a sub-agent's request also
249
- * shows in, or null (no delegation, another kind, or this is the top). */
250
- function delegationSurface(request) {
251
- if (typeof surfaceOf !== 'function' || !DELEGATED_KINDS.has(request.kind)) return null;
252
- const own = String(request.sessionId || ownSessionId());
253
- let surface = null;
254
- try {
255
- surface = surfaceOf(own);
256
- } catch {
257
- return null;
258
- }
259
- const sessionId = String(surface?.sessionId || '');
260
- if (!sessionId || sessionId === own || sessionId === ownSessionId()) return null;
261
- return { sessionId, chain: Array.isArray(surface.chain) ? surface.chain.map(String) : [] };
262
- }
263
217
 
264
218
  return {
265
219
  presentNextToolApproval,
@@ -70,10 +70,17 @@ function persistedQueuePayload(entry) {
70
70
  const value = entry[field];
71
71
  if (value && typeof value === 'object' && !Array.isArray(value)) out[field] = value;
72
72
  }
73
- for (const field of ['mode', 'priority', 'context']) {
73
+ for (const field of ['mode', 'priority', 'context', 'origin']) {
74
74
  if (typeof entry[field] === 'string' && entry[field]) out[field] = entry[field];
75
75
  }
76
76
  if (entry.skipSlashCommands === true) out.skipSlashCommands = true;
77
+ // Retry of a failed turn: the drain rewinds the failed prompt by these.
78
+ if (typeof entry.skillSelection === 'string') out.skillSelection = entry.skillSelection;
79
+ if (entry.suppressDisplay === true) out.suppressDisplay = true;
80
+ if (entry.retryFailedTurn === true) out.retryFailedTurn = true;
81
+ for (const field of ['retryTurnId', 'retryAttemptId']) {
82
+ if (typeof entry[field] === 'string' && entry[field]) out[field] = entry[field];
83
+ }
77
84
  return out;
78
85
  }
79
86
 
@@ -40,6 +40,9 @@ export function createTurnStream(deps) {
40
40
  // (`commentary` / `final_answer`), or null; the desktop row carries it.
41
41
  phase: null,
42
42
  thinkingText: '',
43
+ // Length of thinkingText when the current provider send began: a
44
+ // `reasoning` retraction drops only what that send added.
45
+ thinkingSendMark: 0,
43
46
  thinkingStartedAt: 0,
44
47
  thinkingSegmentStartedAt: 0,
45
48
  accumulatedThinkingMs: 0,
@@ -492,9 +495,20 @@ export function appendReasoningDelta(stream, chunk) {
492
495
  scheduleStreamFlush(stream);
493
496
  }
494
497
 
498
+ // A provider send (one model request of the turn) begins: the thinking so far
499
+ // belongs to earlier sends and survives a retraction of this one.
500
+ export function markThinkingSendStart(stream) {
501
+ stream.thinkingSendMark = stream.thinkingText.length;
502
+ }
503
+
495
504
  export function resetStreamedText(stream, { chars, reasoning } = {}) {
496
505
  const count = Math.max(0, Number(chars) || 0);
497
- if (reasoning) endThinkingForText(stream);
506
+ if (reasoning) {
507
+ endThinkingForText(stream);
508
+ // The discarded attempt's thinking must not prefix the next attempt's;
509
+ // earlier sends' thinking stays.
510
+ stream.thinkingText = stream.thinkingText.slice(0, stream.thinkingSendMark);
511
+ }
498
512
  if (!count) return reasoning === true;
499
513
  flushStreamBatch(stream);
500
514
  stream.assistantText = stream.assistantText.slice(0, Math.max(0, stream.assistantText.length - count));
@@ -529,6 +543,8 @@ export function resetStreamedText(stream, { chars, reasoning } = {}) {
529
543
  // tool phase (`spinnerMode`: 'task-wait' or 'tool-use').
530
544
  export function closeThinkingForToolBatch(stream, spinnerMode) {
531
545
  const { getState, set } = stream;
546
+ // The send that produced this batch is complete; its thinking is kept.
547
+ markThinkingSendStart(stream);
532
548
  if (stream.thinkingText && getState().thinking) {
533
549
  const thinkingLastEndedAt = closeThinkingSegment(stream);
534
550
  set({
@@ -572,6 +588,12 @@ function stopReconnectCountdown(stream) {
572
588
  stream.reconnectTimer = null;
573
589
  }
574
590
 
591
+ // The spinner's wait fields for a reconnect stage (see applyStageChange).
592
+ function reconnectWait(detail, now = Date.now()) {
593
+ const retryAt = Number(detail?.retryAt) || 0;
594
+ return { retryAt, retryInMs: retryAt > 0 ? Math.max(0, retryAt - now) : 0 };
595
+ }
596
+
575
597
  // Re-renders the reconnect verb once a second until the wait ends, the stage
576
598
  // moves on, or the turn is gone. The desktop reads the same spinner state.
577
599
  function startReconnectCountdown(stream, detail) {
@@ -583,7 +605,7 @@ function startReconnectCountdown(stream, detail) {
583
605
  stopReconnectCountdown(stream);
584
606
  return;
585
607
  }
586
- stream.set({ spinner: { ...spinner, verb: reconnectVerb(detail) } });
608
+ stream.set({ spinner: { ...spinner, verb: reconnectVerb(detail), ...reconnectWait(detail) } });
587
609
  }, 1_000);
588
610
  stream.reconnectTimer.unref?.();
589
611
  }
@@ -619,7 +641,18 @@ export async function applyStageChange(stream, stage, detail = null) {
619
641
  }
620
642
  if (value === 'reconnecting') {
621
643
  stream.compactingActive = false;
622
- set({ spinner: { ...getState().spinner, mode: 'reconnecting', verb: reconnectVerb(detail) } });
644
+ // The wait rides on the spinner so a surface that repaints on its own
645
+ // clock (the desktop status line) counts it down itself: `retryInMs` is
646
+ // the remaining wait at publish (relative, so a remote client's clock skew
647
+ // cannot distort it) and `retryAt` only identifies this retry.
648
+ set({
649
+ spinner: {
650
+ ...getState().spinner,
651
+ mode: 'reconnecting',
652
+ verb: reconnectVerb(detail),
653
+ ...reconnectWait(detail),
654
+ },
655
+ });
623
656
  startReconnectCountdown(stream, detail);
624
657
  await yieldToRenderer();
625
658
  return;
@@ -23,6 +23,10 @@ import { isRejected429 } from '../../runtime/shared/error-presentation.mjs';
23
23
  import { QUOTA_KINDS, providerErrorKind } from '../../runtime/agent/orchestrator/providers/provider-error-kind.mjs';
24
24
  import { turnFailureRecord } from '../../runtime/agent/orchestrator/session/turn-failure.mjs';
25
25
  import { registerTaskWaitSteeringCheck } from '../../runtime/agent/orchestrator/session/task-wait-control.mjs';
26
+ import {
27
+ isReactionSuccess,
28
+ reactionCallIds,
29
+ } from '../../runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs';
26
30
  import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
27
31
  import { yieldToRenderer } from './render-timing.mjs';
28
32
  import { archiveItemsForCompaction, compactionArchivedRows } from './compaction-view.mjs';
@@ -35,6 +39,7 @@ import {
35
39
  appendTextDelta,
36
40
  appendAssistantText,
37
41
  appendReasoningDelta,
42
+ markThinkingSendStart,
38
43
  noteAssistantPhase,
39
44
  resetStreamedText,
40
45
  applyStageChange,
@@ -152,6 +157,9 @@ function beginTurn({ flags, getState, transcriptRouteMetadata }, options) {
152
157
  askResult: null,
153
158
  finishedNormally: false,
154
159
  transcriptCompacted: false,
160
+ // Ids of this turn's react calls; `reacted` is set once one succeeds.
161
+ reactionCallIds: new Set(),
162
+ reacted: false,
155
163
  };
156
164
  }
157
165
 
@@ -403,10 +411,15 @@ export function toolHandlers(ctx) {
403
411
  if (isCurrentTurn()) settleSegmentBeforeToolCall(ctx);
404
412
  },
405
413
  onToolCall: async (_iter, calls) => {
406
- if (isCurrentTurn()) await openToolCalls(ctx, calls);
414
+ if (!isCurrentTurn()) return;
415
+ for (const id of reactionCallIds(calls)) ctx.turn.reactionCallIds.add(id);
416
+ await openToolCalls(ctx, calls);
407
417
  },
408
418
  onToolResult: (message) => {
409
419
  if (!isCurrentTurn()) return;
420
+ // A reaction that landed on the user's message is this turn's output
421
+ // even with no reply text; a rejected or failed react call is not.
422
+ if (isReactionSuccess(message, ctx.turn.reactionCallIds)) ctx.turn.reacted = true;
410
423
  try {
411
424
  options.onToolResult?.(message);
412
425
  } catch {}
@@ -440,7 +453,9 @@ export function streamHandlers(ctx) {
440
453
  const { isCurrentTurn, stream } = ctx;
441
454
  return {
442
455
  onProviderSendStarted: () => {
443
- if (isCurrentTurn()) markLiveCallRequestStart(stream);
456
+ if (!isCurrentTurn()) return;
457
+ markThinkingSendStart(stream);
458
+ markLiveCallRequestStart(stream);
444
459
  },
445
460
  onStageChange: async (stage, detail = null) => {
446
461
  if (!isCurrentTurn()) return;
@@ -554,6 +569,9 @@ export function turnDoneItem({ turn, stream, cards, getState, nextId }) {
554
569
  outputTokens: finalOutputTokens(stream, getState().spinner?.outputTokens),
555
570
  thinkingElapsedMs: stream.thinkingStartedAt ? stream.accumulatedThinkingMs : 0,
556
571
  toolCount: cards.toolCards.length,
572
+ // Its answer may be a reaction alone: readers of the turn's final answer
573
+ // take it as done with nothing to say (session-final-answer.ts).
574
+ ...(turn.reacted ? { reacted: true } : {}),
557
575
  verb: turn.completionVerb,
558
576
  at: Date.now(),
559
577
  ...(turn.failureDetail ? { detail: turn.failureDetail } : {}),
@@ -577,9 +595,11 @@ function publishTurnClose(ctx, closingItems) {
577
595
  const assistantOutput = (stream.currentAssistantText || stream.assistantText || '').trim();
578
596
  // Suppress only true pending-resume no-ops: no transcript items added and
579
597
  // no model output; cancelled/error turns and any visible turn stay marked.
598
+ // A turn whose only output was a reaction ends with its turndone row too.
580
599
  const isNoOpTurn =
581
600
  turn.finishedNormally &&
582
601
  !turn.cancelled &&
602
+ !turn.reacted &&
583
603
  cards.toolCards.length === 0 &&
584
604
  !resultContent &&
585
605
  !assistantOutput &&
@@ -757,6 +777,7 @@ export function createRunTurn(bag) {
757
777
  submissionIds: turn.submittedIds,
758
778
  submittedAt: options.submittedAt,
759
779
  promptSource: options.promptSource,
780
+ ...(options.promptOrigin ? { promptOrigin: options.promptOrigin } : {}),
760
781
  retryFailedTurn: options.retryFailedTurn === true,
761
782
  retryTurnId: options.retryTurnId,
762
783
  retryAttemptId: options.retryAttemptId,