mixdog 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. package/README.md +8 -4
  2. package/package.json +8 -8
  3. package/scripts/native-release-status.mjs +238 -0
  4. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  5. package/src/agents/reviewer/AGENT.md +5 -7
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +9 -1
  8. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  9. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  10. package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
  11. package/src/defaults/skills/setup/SKILL.md +23 -1
  12. package/src/defaults/skills/setup/references/actions.md +50 -3
  13. package/src/defaults/skills/setup/references/surfaces.md +23 -3
  14. package/src/defaults/skills/setup-guide/SKILL.md +7 -3
  15. package/src/defaults/skills/visualize/SKILL.md +9 -6
  16. package/src/defaults/skills/visualize/references/craft.md +8 -1
  17. package/src/help.mjs +1 -1
  18. package/src/lib/keychain-cjs.cjs +4 -1
  19. package/src/lib/rules-builder.cjs +14 -7
  20. package/src/rules/agent-mode/AGENT_MODE.md +8 -5
  21. package/src/rules/agent-mode/MIXY.md +6 -8
  22. package/src/rules/lead/LEAD.md +7 -10
  23. package/src/rules/shared/10-tool-workflow.md +4 -0
  24. package/src/rules/shared/20-research.md +2 -0
  25. package/src/rules/shared/45-destructive.md +5 -1
  26. package/src/rules/shared/60-verification.md +6 -4
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
  29. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
  31. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
  32. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
  33. package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
  35. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
  37. package/src/runtime/agent/orchestrator/config.mjs +11 -0
  38. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
  39. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
  40. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
  41. package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  45. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
  46. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
  48. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
  49. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  50. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
  51. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
  52. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
  54. package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
  55. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  56. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
  57. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
  59. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
  60. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
  62. package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
  64. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
  67. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
  69. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
  70. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
  72. package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
  73. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  74. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
  75. package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  81. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
  82. package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
  83. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
  86. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
  90. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
  92. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
  93. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
  94. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
  95. package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
  96. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
  97. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  99. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
  100. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
  101. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  102. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
  103. package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
  107. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
  108. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  109. package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
  110. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
  111. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
  112. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
  113. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
  114. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
  115. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
  116. package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
  117. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
  118. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
  119. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  120. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  121. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  123. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  124. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
  125. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
  126. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
  127. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
  128. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
  129. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  130. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
  131. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
  132. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
  133. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
  134. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  135. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  136. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  137. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
  138. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
  139. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
  143. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  144. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
  145. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
  146. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
  148. package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
  150. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  151. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  155. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
  156. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
  157. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
  158. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
  160. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
  161. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
  163. package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
  166. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  167. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
  168. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
  169. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
  170. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
  171. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
  172. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
  178. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
  179. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
  180. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
  181. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  182. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  183. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  184. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  185. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
  186. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
  189. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
  190. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
  191. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
  196. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
  200. package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
  201. package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
  202. package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
  203. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
  204. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
  206. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
  207. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
  208. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
  209. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
  210. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
  211. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
  212. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
  213. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
  214. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
  215. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
  216. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
  217. package/src/runtime/attachments/attachment-reference.mjs +155 -0
  218. package/src/runtime/attachments/legacy-office.mjs +110 -0
  219. package/src/runtime/attachments/limits.mjs +5 -1
  220. package/src/runtime/attachments/office-extract.mjs +3 -6
  221. package/src/runtime/attachments/pdf-extract.mjs +84 -10
  222. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  223. package/src/runtime/attachments/store.mjs +109 -33
  224. package/src/runtime/browser-bridge/client.mjs +73 -20
  225. package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
  226. package/src/runtime/channels/lib/scheduler.mjs +14 -7
  227. package/src/runtime/channels/lib/state-file.mjs +15 -15
  228. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
  229. package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
  230. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
  231. package/src/runtime/channels/lib/worker-main.mjs +3 -2
  232. package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
  233. package/src/runtime/effort-judge/judge-client.mjs +66 -16
  234. package/src/runtime/effort-judge/model-install.mjs +47 -7
  235. package/src/runtime/local-provider/asset-installer.mjs +10 -4
  236. package/src/runtime/local-provider/catalog.mjs +5 -2
  237. package/src/runtime/local-provider/registered-models.mjs +64 -27
  238. package/src/runtime/local-provider/server.mjs +2 -3
  239. package/src/runtime/media/adapters/image-api.mjs +89 -0
  240. package/src/runtime/media/auth.mjs +64 -1
  241. package/src/runtime/media/catalog.mjs +66 -4
  242. package/src/runtime/media/jobs.mjs +4 -0
  243. package/src/runtime/media/lanes.mjs +46 -5
  244. package/src/runtime/media/media-usage.mjs +17 -0
  245. package/src/runtime/media/renditions.mjs +15 -15
  246. package/src/runtime/media/store.mjs +36 -35
  247. package/src/runtime/media/tool.mjs +8 -1
  248. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
  249. package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
  250. package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
  251. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  252. package/src/runtime/memory/lib/pg/process.mjs +8 -4
  253. package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
  254. package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
  255. package/src/runtime/office/core/journal.mjs +7 -14
  256. package/src/runtime/office/design/library/design-library-core.mjs +4 -16
  257. package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
  258. package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
  259. package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
  260. package/src/runtime/office/pdf/pdf-render.mjs +30 -18
  261. package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
  262. package/src/runtime/office/portable/portable-soffice.mjs +135 -29
  263. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  264. package/src/runtime/shared/agent-avatar.mjs +3 -2
  265. package/src/runtime/shared/agent-kind-migration.mjs +200 -0
  266. package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
  267. package/src/runtime/shared/agent-message-envelope.mjs +44 -0
  268. package/src/runtime/shared/agent-reap-state.d.mts +4 -0
  269. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  270. package/src/runtime/shared/agent-room-host.mjs +58 -0
  271. package/src/runtime/shared/agent-store.mjs +24 -7
  272. package/src/runtime/shared/agent-task-starts.mjs +27 -0
  273. package/src/runtime/shared/atomic-file.d.mts +50 -0
  274. package/src/runtime/shared/atomic-file.mjs +394 -132
  275. package/src/runtime/shared/background-tasks.mjs +7 -4
  276. package/src/runtime/shared/bot-hops.mjs +35 -0
  277. package/src/runtime/shared/bot-split-migration.mjs +1 -1
  278. package/src/runtime/shared/bounded-download.mjs +4 -2
  279. package/src/runtime/shared/config.mjs +39 -9
  280. package/src/runtime/shared/defaults-separation.mjs +6 -2
  281. package/src/runtime/shared/delegated-approval-host.mjs +74 -0
  282. package/src/runtime/shared/err-text.mjs +4 -0
  283. package/src/runtime/shared/error-presentation.mjs +22 -4
  284. package/src/runtime/shared/file-has-data.mjs +28 -0
  285. package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
  286. package/src/runtime/shared/pending-agent-work.mjs +54 -0
  287. package/src/runtime/shared/process-lifecycle.mjs +8 -12
  288. package/src/runtime/shared/projects.mjs +50 -41
  289. package/src/runtime/shared/provider-accounts.mjs +17 -12
  290. package/src/runtime/shared/redact-directories.mjs +18 -0
  291. package/src/runtime/shared/remove-directory.mjs +28 -0
  292. package/src/runtime/shared/routine-trigger.d.mts +6 -1
  293. package/src/runtime/shared/routine-trigger.mjs +14 -6
  294. package/src/runtime/shared/run-child.d.mts +3 -0
  295. package/src/runtime/shared/run-child.mjs +24 -3
  296. package/src/runtime/shared/session-baseline-store.mjs +8 -2
  297. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  298. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  299. package/src/runtime/shared/singleton-owner.mjs +7 -6
  300. package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
  301. package/src/runtime/shared/staged-update.mjs +4 -2
  302. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
  303. package/src/runtime/shared/tool-execution-contract.mjs +10 -0
  304. package/src/runtime/shared/tool-work-units.mjs +12 -9
  305. package/src/runtime/shared/transcript-metadata.mjs +28 -3
  306. package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
  307. package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
  308. package/src/runtime/shared/turn-snapshot.mjs +277 -124
  309. package/src/runtime/shared/user-cwd.mjs +9 -4
  310. package/src/runtime/shared/user-data-guard.mjs +92 -61
  311. package/src/runtime/shared/utf8-cut.mjs +10 -0
  312. package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
  313. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  314. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  315. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  316. package/src/runtime/shared/worktrees/registry.mjs +29 -27
  317. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  318. package/src/runtime/tidy/core-install.mjs +26 -4
  319. package/src/runtime/tidy/install.mjs +91 -23
  320. package/src/runtime/tidy/process.mjs +41 -8
  321. package/src/runtime/tidy/resolve.mjs +10 -7
  322. package/src/runtime/web-search/lib/config.mjs +4 -16
  323. package/src/session-runtime/agent-home-delivery.mjs +542 -204
  324. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  325. package/src/session-runtime/agent-room-delivery.mjs +81 -35
  326. package/src/session-runtime/agent-task-sessions.mjs +811 -179
  327. package/src/session-runtime/agent-tool-routing.mjs +1 -0
  328. package/src/session-runtime/boot/apis.mjs +48 -24
  329. package/src/session-runtime/boot/config.mjs +1 -0
  330. package/src/session-runtime/boot/facade.mjs +16 -7
  331. package/src/session-runtime/boot/infrastructure.mjs +14 -2
  332. package/src/session-runtime/boot/providers.mjs +2 -2
  333. package/src/session-runtime/boot/shared.mjs +12 -6
  334. package/src/session-runtime/boot/tools.mjs +23 -3
  335. package/src/session-runtime/bot-status.mjs +432 -0
  336. package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
  337. package/src/session-runtime/config-lifecycle.mjs +60 -55
  338. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
  339. package/src/session-runtime/held-requests.mjs +31 -33
  340. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
  341. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
  342. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
  343. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  344. package/src/session-runtime/lifecycle/teardown.mjs +11 -3
  345. package/src/session-runtime/mcp-glue/connect.mjs +100 -186
  346. package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
  347. package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
  348. package/src/session-runtime/media-api.mjs +5 -2
  349. package/src/session-runtime/model-recency.mjs +1 -0
  350. package/src/session-runtime/model-route/route-tuning.mjs +4 -1
  351. package/src/session-runtime/model-route/set-route.mjs +61 -1
  352. package/src/session-runtime/owned-automation-run.mjs +8 -1
  353. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  354. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  355. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  356. package/src/session-runtime/route-resolution.mjs +16 -8
  357. package/src/session-runtime/route-state.mjs +1 -59
  358. package/src/session-runtime/routine-home-turn.mjs +5 -3
  359. package/src/session-runtime/runtime-bootstrap.mjs +5 -3
  360. package/src/session-runtime/runtime-paths.mjs +11 -5
  361. package/src/session-runtime/runtime-review-api.mjs +4 -1
  362. package/src/session-runtime/runtime-tunables.mjs +6 -0
  363. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
  364. package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
  365. package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
  366. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
  367. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  368. package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
  369. package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
  370. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
  371. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
  372. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
  373. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
  374. package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
  375. package/src/session-runtime/services/agent-tool.mjs +6 -0
  376. package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
  377. package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
  378. package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
  379. package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
  380. package/src/session-runtime/services/plugin-admin.mjs +26 -26
  381. package/src/session-runtime/services/provider-admin.mjs +26 -6
  382. package/src/session-runtime/services/schedule-access.mjs +33 -4
  383. package/src/session-runtime/services/seeds.mjs +4 -3
  384. package/src/session-runtime/services/usage-dashboard.mjs +1 -1
  385. package/src/session-runtime/services/usage-stats-model.mjs +2 -1
  386. package/src/session-runtime/services/worktree-access.mjs +27 -0
  387. package/src/session-runtime/session-create/materialize.mjs +2 -3
  388. package/src/session-runtime/session-create/session-options.mjs +15 -2
  389. package/src/session-runtime/session-hooks.mjs +9 -17
  390. package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
  391. package/src/session-runtime/settings-compaction-api.mjs +86 -39
  392. package/src/session-runtime/setup-tool/executor.mjs +12 -2
  393. package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
  394. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
  395. package/src/session-runtime/skills-api.mjs +12 -5
  396. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
  397. package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
  398. package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
  399. package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
  400. package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
  401. package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
  402. package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
  403. package/src/session-runtime/tool-policy-refresh.mjs +48 -369
  404. package/src/session-runtime/tool-surface.mjs +10 -4
  405. package/src/session-runtime/turn/session-ops.mjs +8 -0
  406. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
  407. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  408. package/src/session-runtime/turn/turn-run.mjs +7 -2
  409. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
  410. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
  411. package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
  412. package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
  413. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
  414. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
  415. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  416. package/src/session-runtime/workspace/transitions.mjs +279 -67
  417. package/src/session-runtime/workspace/workspace-state.mjs +7 -6
  418. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  419. package/src/standalone/daemon-agent-control.mjs +4 -1
  420. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  421. package/src/standalone/daemon-session-control.mjs +173 -15
  422. package/src/standalone/daemon-telemetry.mjs +9 -0
  423. package/src/standalone/daemon.mjs +33 -10
  424. package/src/standalone/local-session-runtime.mjs +33 -16
  425. package/src/standalone/session-client.mjs +7 -2
  426. package/src/standalone/session-protocol.mjs +8 -0
  427. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  428. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  429. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  430. package/src/standalone/session-service.mjs +21 -0
  431. package/src/standalone/session-state-projection.mjs +19 -9
  432. package/src/standalone/session-tool-output.mjs +36 -9
  433. package/src/standalone/staged-import.mjs +47 -0
  434. package/src/tui/App.jsx +2 -0
  435. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
  436. package/src/tui/app/message-selector.mjs +15 -2
  437. package/src/tui/app/model-options.mjs +16 -2
  438. package/src/tui/app/model-picker.mjs +2 -1
  439. package/src/tui/app/route-pickers.mjs +3 -1
  440. package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
  441. package/src/tui/app/slash-commands.mjs +1 -1
  442. package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
  443. package/src/tui/dist/index.mjs +617 -369
  444. package/src/tui/paste-attachments.mjs +0 -1
  445. package/src/tui/paste-text-policy.mjs +4 -5
  446. package/src/tui/prompt-history-store.mjs +16 -21
  447. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  448. package/src/tui/session/context-state.mjs +4 -0
  449. package/src/tui/session/notice-surface.mjs +3 -0
  450. package/src/tui/session/session-api/intake/abort.mjs +52 -18
  451. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  452. package/src/tui/session/session-api/media.mjs +2 -1
  453. package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
  454. package/src/tui/session/session-api/routes-write.mjs +203 -0
  455. package/src/tui/session/session-api/routes.mjs +23 -247
  456. package/src/tui/session/session-api/settings.mjs +14 -1
  457. package/src/tui/session/session-flow/drain.mjs +28 -3
  458. package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
  459. package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
  460. package/src/tui/session/session-flow/steering.mjs +8 -3
  461. package/src/tui/session/tool-approval.mjs +142 -14
  462. package/src/tui/session/transcript-intake.mjs +2 -0
  463. package/src/tui/session/turn.mjs +23 -14
  464. package/src/tui/transcript-tool-failures.mjs +8 -2
  465. package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
  466. package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
  467. package/src/rules/agent-mode/ROUTINE.md +0 -6
  468. package/src/session-runtime/room-member-gate.mjs +0 -48
@@ -5,26 +5,65 @@
5
5
  * active one into store state (state.toolApproval). They need live session
6
6
  * state, so the closure identifiers (state/set/nextId/disposed/timeout) are
7
7
  * threaded through the factory argument via getters — never stale snapshots.
8
+ *
9
+ * Delegation (`surfaceOf`, human-gate/gate.mjs approvalSurface): a sub-agent's
10
+ * approval is also offered to the top-level conversation the user watches
11
+ * (runtime/shared/delegated-approval-host.mjs), labelled with the agent chain.
12
+ * That session's queue holds a copy (`mirror`): it never times out, survives
13
+ * that session's own turn ending, and its answer is forwarded to the owning
14
+ * queue, so either place settles the one request once.
8
15
  */
9
16
  import {
10
17
  humanRequestFields,
11
18
  normalizeHumanResponse,
12
19
  } from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
20
+ import {
21
+ delegateApproval,
22
+ delegatedApprovalsFor,
23
+ registerApprovalQueue,
24
+ withdrawDelegatedApproval,
25
+ } 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']);
30
+
31
+ /** The wait limit an approval has when its request names none, from
32
+ * MIXDOG_TOOL_APPROVAL_TIMEOUT_MS (milliseconds, one second at least): null —
33
+ * no limit — unless the variable sets one, which tests and ops use. An
34
+ * approval waits until the user answers, Stop/turn abort denies it, or its
35
+ * runtime closes. */
36
+ export function resolveToolApprovalTimeoutMs(env = process.env) {
37
+ const value = Number(env.MIXDOG_TOOL_APPROVAL_TIMEOUT_MS);
38
+ return Number.isFinite(value) && value > 0 ? Math.max(1000, Math.round(value)) : null;
39
+ }
13
40
 
14
- export function createToolApproval({ getState, set, nextId, getDisposed, timeoutMs }) {
41
+ export function createToolApproval({ getState, set, nextId, getDisposed, timeoutMs = null, surfaceOf = null }) {
42
+ const defaultTimeoutMs = Number.isFinite(Number(timeoutMs)) && Number(timeoutMs) > 0 ? Number(timeoutMs) : null;
15
43
  const toolApprovalQueue = [];
16
44
  let activeToolApproval = null;
45
+ const ownSessionId = () => String(getState()?.sessionId || '');
46
+ const unregister =
47
+ typeof surfaceOf === 'function'
48
+ ? registerApprovalQueue({
49
+ sessionId: ownSessionId,
50
+ disposed: () => getDisposed(),
51
+ offer: offerDelegatedApproval,
52
+ withdraw: withdrawDelegatedCopy,
53
+ })
54
+ : () => {};
17
55
 
18
56
  function normalizeToolApprovalRequest(input = {}, id = nextId()) {
19
57
  const now = Date.now();
20
58
  // An explicit `timeoutMs: null` means no wait limit (no timer, no expiry);
21
- // any other missing/invalid value falls back to the session default.
59
+ // any other missing/invalid value falls back to the session default,
60
+ // which is itself no limit unless the runtime configures one.
22
61
  const requestTimeoutMs =
23
62
  input?.timeoutMs === null
24
63
  ? null
25
64
  : Number.isFinite(Number(input?.timeoutMs)) && Number(input.timeoutMs) > 0
26
65
  ? Number(input.timeoutMs)
27
- : timeoutMs;
66
+ : defaultTimeoutMs;
28
67
  return {
29
68
  id,
30
69
  name: String(input?.name || input?.tool_name || 'tool'),
@@ -41,12 +80,14 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
41
80
  ...humanRequestFields(input),
42
81
  };
43
82
  }
44
- // Every request expires from ITS OWN requestedAt, queued or active. Arming
45
- // the timer only on presentation let a queued request sit past expiresAt
46
- // (retaining its promise and surfacing an obsolete approval later).
83
+ // A request that has a limit expires from ITS OWN requestedAt, queued or
84
+ // active. Arming the timer only on presentation let a queued request sit past
85
+ // expiresAt (retaining its promise and surfacing an obsolete approval later).
86
+ // One without a limit (expiresAt null — the default) arms nothing.
47
87
  function armToolApprovalTimeout(entry) {
48
- if (!entry || entry.timer || entry.request?.expiresAt === null) return;
49
- const remainingMs = Math.max(0, Number(entry.request?.expiresAt || 0) - Date.now());
88
+ // A copy expires with its owner, which withdraws it.
89
+ if (!entry || entry.mirror || entry.timer || !Number.isFinite(entry.request?.expiresAt)) return;
90
+ const remainingMs = Math.max(0, entry.request.expiresAt - Date.now());
50
91
  entry.timer = setTimeout(() => {
51
92
  finishToolApproval(entry.id, false, 'approval timed out', '', undefined, undefined, { timedOut: true });
52
93
  }, remainingMs);
@@ -66,10 +107,48 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
66
107
  if (device) result.device = device;
67
108
  }
68
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 });
69
112
  try {
70
113
  entry.resolve(result);
71
114
  } catch {}
72
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
+ function offerDelegatedApproval(delegated) {
126
+ if (getDisposed() || delegated.sessionId !== ownSessionId()) return;
127
+ if (activeToolApproval?.id === delegated.id || toolApprovalQueue.some((entry) => entry.id === delegated.id)) return;
128
+ toolApprovalQueue.push({ id: delegated.id, request: delegated.request, mirror: delegated, timer: null });
129
+ presentNextToolApproval();
130
+ }
131
+ function withdrawDelegatedCopy(id, result) {
132
+ if (activeToolApproval?.mirror && activeToolApproval.id === id) {
133
+ 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
+ });
139
+ presentNextToolApproval();
140
+ return;
141
+ }
142
+ const index = toolApprovalQueue.findIndex((entry) => entry.mirror && entry.id === id);
143
+ if (index >= 0) toolApprovalQueue.splice(index, 1);
144
+ }
145
+ /** Show the delegated approvals waiting for this session (it loaded, or its
146
+ * session id became the top-level one after the request was made). */
147
+ function adoptDelegatedApprovals() {
148
+ const sessionId = ownSessionId();
149
+ if (!sessionId || typeof surfaceOf !== 'function') return;
150
+ for (const delegated of delegatedApprovalsFor(sessionId)) offerDelegatedApproval(delegated);
151
+ }
73
152
  function presentNextToolApproval() {
74
153
  if (activeToolApproval || getDisposed()) return;
75
154
  const entry = toolApprovalQueue.shift();
@@ -100,44 +179,93 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
100
179
  ? { id: targetId, approved: approved === true, device: String(device), at: Date.now() }
101
180
  : null;
102
181
  set({ toolApproval: null, toolApprovalResult });
103
- settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
182
+ let accepted = true;
183
+ if (entry.mirror) {
184
+ accepted = forwardToOwner(entry, approved, reason, device, answers, reply, extra);
185
+ } else {
186
+ settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
187
+ }
104
188
  presentNextToolApproval();
105
- return true;
189
+ return accepted;
106
190
  }
107
191
  const index = toolApprovalQueue.findIndex((entry) => entry.id === targetId);
108
192
  if (index >= 0) {
109
193
  const [entry] = toolApprovalQueue.splice(index, 1);
194
+ if (entry.mirror) return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
110
195
  settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
111
196
  return true;
112
197
  }
113
198
  return false;
114
199
  }
200
+ /** Deny this session's own requests. A copy of a sub-agent's request stays
201
+ * (that agent still waits) until this runtime closes, which drops it
202
+ * unanswered: the next runtime of this session adopts it again. */
115
203
  function denyAllToolApprovals(reason = 'approval cancelled') {
116
- if (activeToolApproval) {
204
+ const closing = getDisposed();
205
+ if (closing) unregister();
206
+ if (activeToolApproval && !(activeToolApproval.mirror && !closing)) {
117
207
  const entry = activeToolApproval;
118
208
  activeToolApproval = null;
119
- settleToolApproval(entry, false, reason);
209
+ if (!entry.mirror) settleToolApproval(entry, false, reason);
120
210
  }
211
+ const kept = [];
121
212
  while (toolApprovalQueue.length > 0) {
122
- settleToolApproval(toolApprovalQueue.shift(), false, reason);
213
+ const entry = toolApprovalQueue.shift();
214
+ if (!entry.mirror) settleToolApproval(entry, false, reason);
215
+ else if (!closing) kept.push(entry);
123
216
  }
217
+ toolApprovalQueue.push(...kept);
218
+ if (activeToolApproval) return;
124
219
  if (getState().toolApproval) set({ toolApproval: null });
220
+ presentNextToolApproval();
125
221
  }
126
222
  function requestToolApproval(input = {}) {
127
223
  if (getDisposed()) return Promise.resolve({ approved: false, reason: 'runtime disposed' });
128
224
  return new Promise((resolve) => {
129
225
  const id = nextId();
130
- const entry = { id, request: normalizeToolApprovalRequest(input, id), resolve, timer: null };
226
+ const full = normalizeToolApprovalRequest(input, id);
227
+ const surface = delegationSurface(full);
228
+ if (surface) {
229
+ // Who asks, from the top-level chat down ("사무관 › Worker"), and where the copy is.
230
+ full.chain = surface.chain;
231
+ full.surfaceSessionId = surface.sessionId;
232
+ }
233
+ const entry = { id, request: full, resolve, timer: null, delegated: Boolean(surface) };
131
234
  toolApprovalQueue.push(entry);
132
235
  armToolApprovalTimeout(entry);
133
236
  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
+ }
134
246
  });
135
247
  }
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
+ }
136
263
 
137
264
  return {
138
265
  presentNextToolApproval,
139
266
  finishToolApproval,
140
267
  denyAllToolApprovals,
141
268
  requestToolApproval,
269
+ adoptDelegatedApprovals,
142
270
  };
143
271
  }
@@ -123,6 +123,8 @@ export function createTranscriptIntake({ getState, flags, pushItem, patchItem, t
123
123
  ...routineTriggerField(extra),
124
124
  ...(extra && typeof extra.sender === 'string' && extra.sender ? { sender: extra.sender } : {}),
125
125
  ...(extra && typeof extra.device === 'string' && extra.device ? { device: extra.device } : {}),
126
+ // The bot that sent this message (a bot's `session send`).
127
+ ...(extra && typeof extra.fromAgent === 'string' && extra.fromAgent ? { fromAgent: extra.fromAgent } : {}),
126
128
  // Delivered into the running turn (steering): the desktop row's read mark.
127
129
  ...(extra?.steered === true ? { steered: true } : {}),
128
130
  // Byte-free attachment metadata (name/mime/size) from the queue entry —
@@ -10,8 +10,9 @@ import { applyUsageDelta } from './session-stats.mjs';
10
10
  import {
11
11
  createTranscriptRouteMetadata,
12
12
  transcriptRouteMetadataFields,
13
+ transcriptSourceFields,
13
14
  } from '../../runtime/shared/transcript-metadata.mjs';
14
- import { publishModelSwitch } from './session-api/routes.mjs';
15
+ import { publishModelSwitch, publishSessionSwitches } from './session-api/routes.mjs';
15
16
  import { compactEventLabel } from '../../runtime/shared/compact-event-label.mjs';
16
17
  import { pickVerb, pickDoneVerb, compactEventDetail } from './labels.mjs';
17
18
  import { isCancelLikeError } from '../../runtime/shared/err-text.mjs';
@@ -172,6 +173,7 @@ function promptRestoreFor(displayText, options, submittedIds, content = null) {
172
173
  pastedImages: options.pastedImages && typeof options.pastedImages === 'object' ? options.pastedImages : null,
173
174
  pastedTexts: options.pastedTexts && typeof options.pastedTexts === 'object' ? options.pastedTexts : null,
174
175
  onCommitted: typeof options.onCommitted === 'function' ? options.onCommitted : null,
176
+ onAborted: typeof options.onAborted === 'function' ? options.onAborted : null,
175
177
  restorable: options.restorable !== false,
176
178
  submittedIds,
177
179
  // Which device submitted the prompt: only that device may get it back.
@@ -202,7 +204,7 @@ export function commitPromptRestore(flags, turn) {
202
204
  restore.content = null;
203
205
  }
204
206
 
205
- function steeringItemExtras(steeringMeta) {
207
+ export function steeringItemExtras(steeringMeta) {
206
208
  return {
207
209
  // The steered message's stable id, so a compaction that drops it greys
208
210
  // this row.
@@ -217,12 +219,7 @@ function steeringItemExtras(steeringMeta) {
217
219
  ? { execution: steeringMeta.execution }
218
220
  : {}),
219
221
  ...(Array.isArray(steeringMeta?.images) && steeringMeta.images.length ? { images: steeringMeta.images } : {}),
220
- ...(typeof steeringMeta?.transcriptMeta?.sender === 'string' && steeringMeta.transcriptMeta.sender
221
- ? { sender: steeringMeta.transcriptMeta.sender }
222
- : {}),
223
- ...(typeof steeringMeta?.transcriptMeta?.device === 'string' && steeringMeta.transcriptMeta.device
224
- ? { device: steeringMeta.transcriptMeta.device }
225
- : {}),
222
+ ...transcriptSourceFields(steeringMeta?.transcriptMeta),
226
223
  };
227
224
  }
228
225
 
@@ -231,7 +228,7 @@ function steeringItemExtras(steeringMeta) {
231
228
  // first (including a streamed tail that never got a trailing '\n') so the
232
229
  // steered user turn and the next assistant response do not merge into one
233
230
  // bubble and the tail is not dropped when the injection races finalization.
234
- function injectSteerMessage({ stream, cards, pushUserOrSyntheticItem }, text, steeringMeta = {}) {
231
+ export function injectSteerMessage({ stream, cards, pushUserOrSyntheticItem }, text, steeringMeta = {}) {
235
232
  // A suppressed live-completion twin is model-visible only; its Response
236
233
  // card was already pushed at delivery time.
237
234
  if (text === STEERING_SUPPRESSED_DISPLAY) return;
@@ -294,7 +291,7 @@ async function approveToolRequest(ctx, request) {
294
291
  // contextStatus path instead of competing with its provider-aligned value.
295
292
  function publishContextPressure({ syncContextStats, getState, set }, info) {
296
293
  if (info?.willCompact !== true) return;
297
- const used = Math.max(0, Number(info?.usedTokens) || 0);
294
+ const used = Math.max(0, Number(info.usedTokens) || 0);
298
295
  if (!used) return;
299
296
  syncContextStats({ allowEstimated: true });
300
297
  set({ stats: { ...getState().stats } });
@@ -424,10 +421,18 @@ export function toolHandlers(ctx) {
424
421
  // state parked on screen until the next model event arrives.
425
422
  set({ spinner: { ...spinner, mode: 'requesting' } });
426
423
  },
427
- onToolApproval: async (request) => {
428
- if (!isCurrentTurn()) return { approved: false, reason: 'turn no longer active' };
429
- return approveToolRequest(ctx, request);
430
- },
424
+ onToolApproval: Object.assign(
425
+ async (request) => {
426
+ if (!isCurrentTurn()) return { approved: false, reason: 'turn no longer active' };
427
+ return approveToolRequest(ctx, request);
428
+ },
429
+ {
430
+ // A word to the person after their answer (e.g. an always-allow that could not be saved).
431
+ // A transcript notice of THIS session: the desktop's toast region draws only the
432
+ // host-level snapshot's toasts, while the pane that asked reads its own session lane.
433
+ notice: (text, tone = 'warn') => ctx.pushNotice?.(text, tone, { transcript: true }),
434
+ }
435
+ ),
431
436
  };
432
437
  }
433
438
 
@@ -768,6 +773,10 @@ export function createRunTurn(bag) {
768
773
  if (!isCurrentTurn()) return;
769
774
  publishModelSwitch(bag, boundary);
770
775
  },
776
+ onSessionSwitches: (switches) => {
777
+ if (!isCurrentTurn()) return;
778
+ publishSessionSwitches(bag, switches);
779
+ },
771
780
  });
772
781
  if (!isCurrentTurn()) turn.cancelled = true;
773
782
  else completeTurn(ctx, result, session);
@@ -8,11 +8,14 @@ import { parseToolArgs } from '../runtime/shared/tool-surface.mjs';
8
8
  // Anchor to the orchestrator's actual denial envelope:
9
9
  // `Error: tool "<name>" denied by hook[: ...]`
10
10
  // `Error: tool "<name>" denied by hook: approval required but no approval UI is available`
11
+ // `Error: tool "<name>" was not approved: <reason>. Do not retry it …` (a person said no)
11
12
  // Matching the bare phrase anywhere in the body produced FALSE POSITIVES when a
12
13
  // normal (successful) tool result merely CONTAINED the text — e.g. a read/grep
13
14
  // over this very file or the hook source. The denial is always an Error
14
15
  // envelope emitted at the START of the result, so anchor on that prefix.
15
- const HOOK_DENIAL_RE = /^Error:\s*tool\s*"[^"]*"\s*denied by hook\b/im;
16
+ const HOOK_DENIAL_RE = /^Error:\s*tool\s*"[^"]*"\s*(?:denied by hook|was not approved)\b/im;
17
+ // The not-approved denial's instruction to the model, not shown to the user.
18
+ const NOT_APPROVED_INSTRUCTION_RE = /\s*Do not retry it or reach the same result another way; report it\.\s*$/;
16
19
  const APPROVAL_UNAVAILABLE_RE = /denied by hook:\s*approval required but no approval UI is available/i;
17
20
 
18
21
  export function toolItemResultText(item) {
@@ -44,7 +47,10 @@ export function isHookApprovalDenialToolItem(item) {
44
47
  export function formatHookDenialDetail(text) {
45
48
  const raw = String(text ?? '').trim();
46
49
  if (!raw) return '';
47
- const stripped = raw.replace(/^Error:\s*tool\s*"[^"]*"\s*/i, '').trim();
50
+ const stripped = raw
51
+ .replace(/^Error:\s*tool\s*"[^"]*"\s*/i, '')
52
+ .replace(NOT_APPROVED_INSTRUCTION_RE, '')
53
+ .trim();
48
54
  return stripped || raw;
49
55
  }
50
56
 
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync,
3
- renameSync, statSync, fstatSync, writeFileSync,
3
+ renameSync, statSync, fstatSync,
4
4
  } from 'fs';
5
- import { appendFile, mkdir, readFile, rename, writeFile } from 'fs/promises';
5
+ import { appendFile, mkdir, readFile } from 'fs/promises';
6
+ import { writeFileAtomicAsync, writeFileAtomicSync } from '../../../../runtime/shared/atomic-file.mjs';
6
7
  import { dirname, join } from 'path';
7
8
  import { resolvePluginData } from '../../../../runtime/shared/plugin-paths.mjs';
8
9
  import { readSection } from '../../../../runtime/shared/config.mjs';
@@ -586,9 +587,9 @@ function ensureUsageStoreMigrated() {
586
587
  if (!existsSync(store)) {
587
588
  const raw = readJsonFile(legacy);
588
589
  const events = (Array.isArray(raw?.events) ? raw.events : []).slice(-MAX_USAGE_EVENTS);
589
- const tmp = `${store}.migrating.${process.pid}`;
590
- writeFileSync(tmp, events.map(e => JSON.stringify(e) + '\n').join(''));
591
- renameSync(tmp, store);
590
+ // Flushed before it is published: the store would otherwise be NUL
591
+ // after a crash, losing the migrated history.
592
+ writeFileAtomicSync(store, events.map(e => JSON.stringify(e) + '\n').join(''));
592
593
  }
593
594
  let backup = legacy + LEGACY_BACKUP_SUFFIX;
594
595
  if (existsSync(backup)) backup = `${legacy}.${Date.now()}${LEGACY_BACKUP_SUFFIX}`;
@@ -645,9 +646,7 @@ async function compactUsageStore(store) {
645
646
  await withFileLock(usageLockPath(store), async () => {
646
647
  const lines = (await readFile(store, 'utf8')).split('\n').filter(l => l.trim());
647
648
  if (lines.length <= MAX_USAGE_EVENTS * 1.5) return;
648
- const tmp = `${store}.compact.${process.pid}`;
649
- await writeFile(tmp, lines.slice(-MAX_USAGE_EVENTS).join('\n') + '\n');
650
- await rename(tmp, store);
649
+ await writeFileAtomicAsync(store, lines.slice(-MAX_USAGE_EVENTS).join('\n') + '\n');
651
650
  });
652
651
  } catch {
653
652
  // Compaction is best effort; the next flush retries.
@@ -1,7 +1,6 @@
1
- import { existsSync, readFileSync } from 'fs';
2
1
  import { join } from 'path';
3
2
  import { resolvePluginData } from '../../../../runtime/shared/plugin-paths.mjs';
4
- import { updateJsonAtomicSync } from '../../../../runtime/shared/atomic-file.mjs';
3
+ import { readJsonStateSync, updateJsonAtomicSync } from '../../../../runtime/shared/atomic-file.mjs';
5
4
  import { CLAUDE_CURRENT_MODE } from './claude-current.mjs';
6
5
 
7
6
  const STORE_FILE = 'gateway-session-routes.json';
@@ -68,9 +67,9 @@ export function gatewaySessionRoutesPath() {
68
67
 
69
68
  function readStore() {
70
69
  try {
71
- const file = gatewaySessionRoutesPath();
72
- if (!existsSync(file)) return {};
73
- const parsed = JSON.parse(readFileSync(file, 'utf8'));
70
+ // A damaged store (NUL, truncated) is kept aside as *.corrupt-<ts> and its
71
+ // last good copy restored, so a session never loses its route pin to it.
72
+ const parsed = readJsonStateSync(gatewaySessionRoutesPath(), { fallback: {} });
74
73
  return parsed && typeof parsed === 'object' ? parsed : {};
75
74
  } catch {
76
75
  return {};
@@ -187,7 +186,7 @@ export function writeGatewaySessionRoutes(entries = []) {
187
186
  sessions: pruneRouteMap(sessions, updatedAt, MAX_SESSION_ROUTES),
188
187
  sessionHosts: pruneRouteMap(sessionHosts, updatedAt, MAX_HOST_ROUTES),
189
188
  };
190
- }, { compact: true, fsync: false, fsyncDir: false });
189
+ }, { compact: true, backup: true });
191
190
  return true;
192
191
  } catch {
193
192
  return false;
@@ -216,7 +215,7 @@ export function clearGatewaySessionRoute(sessionId, options = {}) {
216
215
  delete sessions[sid];
217
216
  }
218
217
  return { version: 2, updatedAt: Date.now(), sessions, sessionHosts };
219
- }, { compact: true, fsync: false, fsyncDir: false });
218
+ }, { compact: true, backup: true });
220
219
  return true;
221
220
  } catch {
222
221
  return false;
@@ -1,6 +0,0 @@
1
- - No user is present in this run. Do not wait for clarification; when
2
- approval is required, follow the approval-hold path. Hand the result to the
3
- configured delivery and do not send a duplicate message.
4
- - Report the outcome in plain words for the user; never name internal tools,
5
- actions or parameters. If a sign-in, code or CAPTCHA blocks the task, stop
6
- and say which site needs the user to sign in.
@@ -1,48 +0,0 @@
1
- // A group-room member's tool calls (session/agent-room.mjs). Reads run freely;
2
- // anything that can change files or state asks the user through the ordinary
3
- // approval flow, whatever the agent's own permission or hook rules say — even
4
- // an agent that normally runs auto-approved. A hook's deny still wins.
5
- import { analyzeShellCommandEffects } from '../runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs';
6
-
7
- const READ_ONLY_TOOLS = new Set([
8
- 'read',
9
- 'grep',
10
- 'glob',
11
- 'find',
12
- 'list',
13
- 'code_graph',
14
- 'load_tool',
15
- 'skill',
16
- 'Skill',
17
- 'recall',
18
- 'search_memories',
19
- 'web_search',
20
- 'web_fetch',
21
- 'local_fetch',
22
- 'image_fetch',
23
- 'ask_user',
24
- ]);
25
-
26
- export const ROOM_APPROVAL_REASON = 'Group-room members need your approval before changing anything.';
27
-
28
- /** Whether `name(args)` only reads: a read-only tool, or a shell command whose
29
- * every stage the shell analysis classifies as non-mutating. */
30
- export async function isReadOnlyRoomCall({ name, args, cwd }, analyze = analyzeShellCommandEffects) {
31
- if (READ_ONLY_TOOLS.has(name)) return true;
32
- if (name !== 'shell' || typeof args?.command !== 'string') return false;
33
- try {
34
- return (await analyze(args.command, cwd))?.mutationMode === 'none';
35
- } catch {
36
- return false;
37
- }
38
- }
39
-
40
- /** The PreToolUse decision for a room member's call: the hook's own `decision`
41
- * when it denies or the call only reads; otherwise an approval ask that keeps
42
- * any rewrite the hook made. */
43
- export async function roomMemberToolDecision(call, decision, analyze) {
44
- const action = String(decision?.action || decision?.decision || '').toLowerCase();
45
- if (action === 'deny' || action === 'block') return decision;
46
- if (await isReadOnlyRoomCall(call, analyze)) return decision;
47
- return { ...(decision && typeof decision === 'object' ? decision : {}), action: 'ask', reason: ROOM_APPROVAL_REASON };
48
- }