mixdog 1.4.0 → 1.4.2

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 (493) hide show
  1. package/package.json +3 -2
  2. package/scripts/build-shipped-history.mjs +115 -33
  3. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  4. package/scripts/gate-local.mjs +183 -63
  5. package/scripts/latest-guard.mjs +21 -9
  6. package/scripts/lib/gate-scheduler.mjs +138 -32
  7. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +91 -66
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +124 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/lib/test-failure-records.mjs +14 -1
  14. package/scripts/lib/test-failure-summary.mjs +16 -4
  15. package/scripts/lib/test-spawn-ledger.mjs +12 -3
  16. package/scripts/post-release-check.mjs +1 -6
  17. package/scripts/pptx-kit-index.mjs +17 -5
  18. package/scripts/suite-health.mjs +115 -24
  19. package/scripts/test-data-dir.mjs +10 -7
  20. package/scripts/test.mjs +9 -14
  21. package/src/agents/advisor/AGENT.md +4 -4
  22. package/src/agents/advisor/agent.json +1 -1
  23. package/src/agents/explore/AGENT.md +22 -0
  24. package/src/agents/explore/agent.json +6 -0
  25. package/src/app.mjs +4 -0
  26. package/src/cli.mjs +7 -0
  27. package/src/defaults/agents.json +7 -0
  28. package/src/defaults/shipped-history.json +23 -2
  29. package/src/defaults/skills/browser-use/SKILL.md +10 -5
  30. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  31. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  32. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  33. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  34. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  35. package/src/defaults/skills/computer-use/SKILL.md +16 -4
  36. package/src/defaults/skills/goal-management/SKILL.md +1 -1
  37. package/src/defaults/skills/setup/references/actions.md +12 -6
  38. package/src/defaults/skills/setup/references/surfaces.md +2 -2
  39. package/src/defaults/skills/setup-guide/SKILL.md +5 -2
  40. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  41. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  42. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  43. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  44. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  45. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  46. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  47. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  48. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  49. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  50. package/src/defaults/skills/visualize/SKILL.md +6 -2
  51. package/src/lib/rules-builder.cjs +35 -42
  52. package/src/output-styles/common.md +2 -2
  53. package/src/output-styles/simple.md +1 -1
  54. package/src/rules/agent/AGENT.md +5 -4
  55. package/src/rules/lead/LEAD.md +12 -7
  56. package/src/rules/shared/10-tool-workflow.md +3 -1
  57. package/src/rules/shared/20-research.md +3 -6
  58. package/src/rules/shared/40-editing.md +1 -0
  59. package/src/rules/shared/45-destructive.md +0 -2
  60. package/src/rules/shared/50-execution.md +2 -0
  61. package/src/rules/shared/60-verification.md +10 -9
  62. package/src/rules/shared/70-delivery.md +8 -9
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
  65. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
  66. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  69. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  70. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
  71. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
  72. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
  79. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
  80. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
  81. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
  82. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
  84. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  85. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  86. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  87. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
  89. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  90. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
  91. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
  92. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  93. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  94. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  95. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  97. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
  99. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  100. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  101. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  102. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  103. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  104. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  105. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  106. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  107. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
  108. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  109. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  110. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  113. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  114. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  115. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  116. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  117. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  129. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  130. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  131. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  132. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  133. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
  135. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  136. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
  137. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  138. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  139. package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
  140. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  141. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  142. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  143. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
  145. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
  147. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
  148. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
  150. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
  151. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  152. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  153. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  154. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  155. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  156. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
  157. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  158. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  159. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  160. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  161. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
  162. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  163. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
  164. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
  165. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  166. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  167. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
  168. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  169. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
  170. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
  171. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
  172. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  174. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
  175. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  179. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
  180. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  181. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  184. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
  185. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
  186. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
  187. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
  188. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
  189. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
  190. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
  192. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
  193. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  194. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  195. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
  196. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  197. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
  198. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
  199. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  200. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
  201. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
  202. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
  203. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  204. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
  209. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  210. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
  211. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  212. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
  213. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  214. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  215. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  217. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
  218. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
  219. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
  221. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  223. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  224. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  225. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  226. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  227. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  228. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  229. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  231. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
  232. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  233. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  234. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  235. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  236. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  237. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  238. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  239. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
  240. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  241. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  243. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
  244. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
  245. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  246. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  248. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  249. package/src/runtime/channels/lib/whisper-port.mjs +29 -11
  250. package/src/runtime/channels/lib/whisper-server.mjs +10 -1
  251. package/src/runtime/computer-bridge/action-schema.mjs +2 -2
  252. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  253. package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
  254. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  255. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  256. package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
  257. package/src/runtime/connectors/gmail-app-password.mjs +3 -3
  258. package/src/runtime/explore/explorer.mjs +93 -0
  259. package/src/runtime/explore/tool-defs.mjs +35 -0
  260. package/src/runtime/explore/tool.mjs +123 -0
  261. package/src/runtime/local-provider/server-process.mjs +2 -1
  262. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  263. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  264. package/src/runtime/memory/index.mjs +4 -0
  265. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  266. package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
  267. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  268. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  269. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  270. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  271. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  272. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  273. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  274. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  275. package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
  276. package/src/runtime/office/quality/design-review.mjs +1 -5
  277. package/src/runtime/office/quality/document-brief.mjs +1 -5
  278. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  279. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  280. package/src/runtime/shared/agent-route-config.mjs +17 -2
  281. package/src/runtime/shared/atomic-file.mjs +103 -2
  282. package/src/runtime/shared/background-tasks.mjs +15 -6
  283. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  284. package/src/runtime/shared/connector-accounts.mjs +5 -5
  285. package/src/runtime/shared/connector-catalog.d.mts +11 -4
  286. package/src/runtime/shared/connector-catalog.mjs +60 -52
  287. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  288. package/src/runtime/shared/defaults-separation.mjs +1 -4
  289. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  290. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  291. package/src/runtime/shared/file-has-data.mjs +26 -2
  292. package/src/runtime/shared/file-lock.mjs +13 -15
  293. package/src/runtime/shared/git-launch.d.mts +9 -0
  294. package/src/runtime/shared/git-launch.mjs +213 -0
  295. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  296. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  297. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  298. package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
  299. package/src/runtime/shared/llm/cost.mjs +11 -2
  300. package/src/runtime/shared/llm/http-agent.mjs +313 -29
  301. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  302. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  303. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  304. package/src/runtime/shared/llm/system-proxy.mjs +452 -0
  305. package/src/runtime/shared/loopback-listener.mjs +25 -2
  306. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  307. package/src/runtime/shared/model-route-chain.mjs +22 -4
  308. package/src/runtime/shared/open-url.mjs +10 -0
  309. package/src/runtime/shared/provider-accounts.mjs +52 -2
  310. package/src/runtime/shared/session-activity-signal.mjs +14 -0
  311. package/src/runtime/shared/session-scratch.mjs +37 -0
  312. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  313. package/src/runtime/shared/staged-update.mjs +47 -2
  314. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  315. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  316. package/src/runtime/shared/tool-result-summary.mjs +1 -1
  317. package/src/runtime/shared/tool-surface.mjs +113 -36
  318. package/src/runtime/shared/tool-work-units.mjs +6 -0
  319. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  320. package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
  321. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  322. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  323. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  324. package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
  325. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  326. package/src/runtime/shared/worktrees/git.mjs +72 -0
  327. package/src/runtime/shared/worktrees/manager.mjs +285 -168
  328. package/src/runtime/shared/worktrees/test-support.mjs +6 -10
  329. package/src/runtime/tidy/install.mjs +95 -15
  330. package/src/runtime/tidy/languages.mjs +17 -15
  331. package/src/runtime/tidy/process.mjs +7 -4
  332. package/src/runtime/tidy/resolve.mjs +19 -16
  333. package/src/runtime/tidy/runners/biome.mjs +3 -3
  334. package/src/runtime/tidy/tool.mjs +1 -1
  335. package/src/runtime/tidy/worktree.mjs +10 -6
  336. package/src/runtime/visualize-bridge/client.mjs +6 -1
  337. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  338. package/src/runtime/web-search/index.mjs +1 -1
  339. package/src/session-runtime/agent-home-delivery.mjs +41 -0
  340. package/src/session-runtime/agent-task-sessions.mjs +458 -312
  341. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  342. package/src/session-runtime/boot/tools.mjs +7 -1
  343. package/src/session-runtime/bot-status.mjs +107 -101
  344. package/src/session-runtime/bot-target.mjs +38 -0
  345. package/src/session-runtime/channel-config-api.mjs +6 -1
  346. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  347. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  348. package/src/session-runtime/conversation-import/discovery.mjs +401 -36
  349. package/src/session-runtime/conversation-import/service.mjs +35 -8
  350. package/src/session-runtime/handoff-attachments.mjs +82 -31
  351. package/src/session-runtime/held-requests.mjs +3 -1
  352. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
  353. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
  354. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
  355. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  356. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  357. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
  358. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  359. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
  360. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
  361. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  362. package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
  363. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  364. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  365. package/src/session-runtime/model-route/set-route.mjs +11 -2
  366. package/src/session-runtime/provider-auth/login.mjs +2 -2
  367. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  368. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  369. package/src/session-runtime/provider-models.mjs +4 -2
  370. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  371. package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
  372. package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
  373. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  374. package/src/session-runtime/resource-recall-api.mjs +6 -1
  375. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  376. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  377. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  378. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  379. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  380. package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
  381. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  382. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
  383. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
  384. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  385. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  386. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  387. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  388. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  389. package/src/session-runtime/services/plugin-admin.mjs +10 -6
  390. package/src/session-runtime/services/provider-admin.mjs +283 -11
  391. package/src/session-runtime/session-turn-api.mjs +2 -0
  392. package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
  393. package/src/session-runtime/settings-system-api.mjs +1 -1
  394. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  395. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  396. package/src/session-runtime/setup-tool/executor.mjs +6 -2
  397. package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
  398. package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
  399. package/src/session-runtime/turn/agent-ops.mjs +23 -0
  400. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
  401. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  402. package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
  403. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  404. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  405. package/src/session-runtime/workspace/session-view.mjs +149 -0
  406. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  407. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  408. package/src/session-runtime/workspace/transitions.mjs +108 -1041
  409. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  410. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  411. package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
  412. package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
  413. package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
  414. package/src/standalone/daemon-desktop-runtime.mjs +2 -0
  415. package/src/standalone/daemon-session-control.mjs +169 -138
  416. package/src/standalone/daemon.mjs +7 -0
  417. package/src/standalone/desktop-service-registry.mjs +9 -0
  418. package/src/standalone/local-session-runtime.mjs +5 -1
  419. package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
  420. package/src/standalone/session-client.mjs +5 -1
  421. package/src/standalone/session-frame-stream.mjs +83 -11
  422. package/src/standalone/session-protocol.mjs +4 -0
  423. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  424. package/src/standalone/session-service/agent-tree.mjs +45 -9
  425. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  426. package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
  427. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  428. package/src/standalone/session-service/stored-reader.mjs +127 -40
  429. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  430. package/src/tui/App.jsx +154 -164
  431. package/src/tui/app/app-view/floating-panel.jsx +10 -4
  432. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  433. package/src/tui/app/clipboard.mjs +21 -10
  434. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  435. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  436. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  437. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  438. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  439. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  440. package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
  441. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  442. package/src/tui/app/provider-setup-picker.mjs +29 -18
  443. package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
  444. package/src/tui/app/slash-commands.mjs +1 -0
  445. package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
  446. package/src/tui/app/slash-dispatch.mjs +1 -1
  447. package/src/tui/app/use-btw-panel.mjs +29 -0
  448. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  449. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  450. package/src/tui/app/use-mouse-input.mjs +11 -0
  451. package/src/tui/app/use-onboarding-start.mjs +8 -3
  452. package/src/tui/app/use-panel-transition.mjs +10 -1
  453. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  454. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  455. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  456. package/src/tui/app/use-prompt-queue-history.mjs +3 -2
  457. package/src/tui/app/use-selection-focus.mjs +11 -2
  458. package/src/tui/app/use-selection-geometry.mjs +18 -9
  459. package/src/tui/app/use-selection-paint.mjs +4 -4
  460. package/src/tui/app/use-selection-stitch.mjs +3 -3
  461. package/src/tui/app/use-slash-palette.mjs +62 -0
  462. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  463. package/src/tui/app/use-transcript-activity.mjs +47 -32
  464. package/src/tui/app/use-transcript-follow.mjs +12 -4
  465. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  466. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  467. package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
  468. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  469. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  470. package/src/tui/app/use-transcript-window.mjs +21 -11
  471. package/src/tui/app/use-tui-ready.mjs +18 -0
  472. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  473. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  474. package/src/tui/components/Picker.jsx +27 -3
  475. package/src/tui/components/QuestionPanel.jsx +13 -4
  476. package/src/tui/components/SignInUrl.jsx +68 -0
  477. package/src/tui/components/TextEntryPanel.jsx +76 -46
  478. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  479. package/src/tui/dist/index.mjs +1963 -1361
  480. package/src/tui/session/goal-turn-state.mjs +6 -2
  481. package/src/tui/session/session-api/controls.mjs +4 -0
  482. package/src/tui/session/session-api/extensions.mjs +8 -0
  483. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  484. package/src/tui/session/session-api/intake.mjs +2 -0
  485. package/src/tui/session/session-api/integrations.mjs +2 -2
  486. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  487. package/src/tui/session/session-api/settings.mjs +2 -2
  488. package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
  489. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  490. package/src/tui/session/transcript-spill.mjs +92 -4
  491. package/src/tui/session/transcript-store.mjs +2 -0
  492. package/src/ui/statusline-agents.mjs +1 -3
  493. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
@@ -72,6 +72,27 @@ export function createAgentOps(deps) {
72
72
  });
73
73
  }
74
74
 
75
+ // `/stop`: the background shells this session would stop, then stopping all
76
+ // of them through the same per-task cancel.
77
+ async function listStoppableShellJobs() {
78
+ const session = getSession();
79
+ const { listStoppableShellJobs: list } = await import(
80
+ '../../runtime/agent/orchestrator/tools/builtin/task-tool.mjs'
81
+ );
82
+ return {
83
+ jobs: list({ callerSessionId: session?.id || null, clientHostPid: session?.clientHostPid || process.pid }),
84
+ };
85
+ }
86
+
87
+ async function stopShellJobs() {
88
+ const session = getSession();
89
+ const { stopBackgroundShellJobs } = await import('../../runtime/agent/orchestrator/tools/builtin/task-tool.mjs');
90
+ return stopBackgroundShellJobs({
91
+ callerSessionId: session?.id || null,
92
+ clientHostPid: session?.clientHostPid || process.pid,
93
+ });
94
+ }
95
+
75
96
  // Explicit user force-release ("Release anyway") of a shell job whose
76
97
  // termination is unconfirmed: drops its workspace hold. The surface has
77
98
  // already asked the user to confirm. The caller session's own holds, and
@@ -147,6 +168,8 @@ export function createAgentOps(deps) {
147
168
  agentControl,
148
169
  taskControl,
149
170
  stopShellJob,
171
+ listStoppableShellJobs,
172
+ stopShellJobs,
150
173
  releaseShellJob,
151
174
  listShellJobs,
152
175
  onNotification,
@@ -4,6 +4,9 @@ import {
4
4
  assertConnectorPolicyNotWidened,
5
5
  CONNECTOR_PERMISSIONS,
6
6
  connectorEnabled,
7
+ connectorGroupId,
8
+ connectorToolEntries,
9
+ connectorToolPermission,
7
10
  DENY_ALL_CONNECTORS,
8
11
  migrateLegacyConnectorPolicy,
9
12
  NO_WIDEN_MESSAGE,
@@ -108,8 +111,8 @@ export function createAgentConnectorsApi(deps, editor) {
108
111
  return getAgentConnectors(agentId);
109
112
  }
110
113
 
111
- // Older per-tool overrides keep working (the profile no longer shows them):
112
- // `permission` null drops the tool's entry, so the tool is auto again.
114
+ // One tool's permission (the profile's tool list, getAgentConnectorTools):
115
+ // `permission` null drops the tool's entry, so the tool is on its default again.
113
116
  async function setAgentConnectorToolPermission(agentId, connectorId, toolName, permission, options) {
114
117
  if (permission != null && !CONNECTOR_PERMISSIONS.includes(permission)) {
115
118
  throw new Error(`permission must be one of ${CONNECTOR_PERMISSIONS.join(', ')}`);
@@ -117,19 +120,25 @@ export function createAgentConnectorsApi(deps, editor) {
117
120
  const server = requireId(connectorId, 'connector id');
118
121
  const tool = requireId(toolName, 'tool name');
119
122
  const policy = editablePolicy(agentId);
120
- const own = { ...policy.tools[server] };
123
+ // The accounts of one connector (`gmail`, `gmail-2`…) share the permission,
124
+ // stored once under the connector's id; an entry an account kept of its own
125
+ // for this tool goes in the same write.
126
+ const group = connectorGroupId(server);
127
+ const tools = Object.fromEntries(
128
+ Object.entries(policy.tools).map(([id, entries]) => {
129
+ if (id === group || connectorGroupId(id) !== group) return [id, entries];
130
+ const { [tool]: _dropped, ...rest } = entries;
131
+ return [id, rest];
132
+ })
133
+ );
134
+ const own = { ...tools[group] };
121
135
  if (permission == null) delete own[tool];
122
136
  else own[tool] = permission;
137
+ tools[group] = own;
123
138
  if (options?.noWiden) {
124
- assertConnectorPolicyNotWidened(editor.getAgentConnectorPolicy(agentId), {
125
- off: policy.off,
126
- tools: { ...policy.tools, [server]: own },
127
- });
139
+ assertConnectorPolicyNotWidened(editor.getAgentConnectorPolicy(agentId), { off: policy.off, tools });
128
140
  }
129
- return editor.setAgentConnectorPolicy(
130
- agentId,
131
- storedConnectorPolicy({ off: policy.off, tools: { ...policy.tools, [server]: own } })
132
- );
141
+ return editor.setAgentConnectorPolicy(agentId, storedConnectorPolicy({ off: policy.off, tools }));
133
142
  }
134
143
 
135
144
  // A card's "항상 허용" for a connector tool saves through this same writer.
@@ -149,6 +158,34 @@ export function createAgentConnectorsApi(deps, editor) {
149
158
  .sort((a, b) => a.connector.localeCompare(b.connector) || a.tool.localeCompare(b.tool));
150
159
  }
151
160
 
161
+ /** `[{ connector, tool, permission, explicit }]`: each installed connector's
162
+ * tools (the connected server's own, and any the agent's policy names) with
163
+ * the permission the agent has for the tool itself, so a connector switched
164
+ * off does not change it, and whether that is an entry of its own policy
165
+ * rather than the tool's default. The profile's per-tool editor reads it. */
166
+ function getAgentConnectorTools(agentId) {
167
+ const { tools } = editablePolicy(agentId);
168
+ return installedIds().flatMap((connector) => {
169
+ const group = connectorGroupId(connector);
170
+ const accounts = Object.entries(tools).filter(([id]) => connectorGroupId(id) === group);
171
+ const names = new Set([
172
+ ...listConnectorTools(connector).map(({ name }) => name),
173
+ ...accounts.flatMap(([, entries]) => Object.keys(entries)),
174
+ ]);
175
+ // Accounts share one permission (stored under the connector); entries an
176
+ // account kept of its own follow the topmost.
177
+ return [...names].map((tool) => ({
178
+ connector,
179
+ tool,
180
+ permission: connectorToolPermission(
181
+ { off: [], tools },
182
+ { mcpServerName: connector, mcpToolName: tool }
183
+ ),
184
+ explicit: connectorToolEntries(tools, group, tool).length > 0,
185
+ }));
186
+ });
187
+ }
188
+
152
189
  /** Replace the agent's connector policy (null removes it). With `options.noWiden`
153
190
  * the replacement may not give any tool more authority than the stored policy. */
154
191
  async function setAgentConnectors(agentId, connectors, options) {
@@ -279,6 +316,7 @@ export function createAgentConnectorsApi(deps, editor) {
279
316
  setAgentConnectorEnabled,
280
317
  setAgentConnectorToolPermission,
281
318
  getAgentAlwaysAllowedTools,
319
+ getAgentConnectorTools,
282
320
  getProjectConnectors,
283
321
  setProjectConnectorEnabled,
284
322
  migrateConnectorPolicies,
@@ -19,7 +19,11 @@ import {
19
19
  writeJsonAtomicSync,
20
20
  } from '../../runtime/shared/atomic-file.mjs';
21
21
  import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
22
- import { agentEntryFile, agentEntryPath, parseManifestText } from '../../runtime/agent/orchestrator/runtime-core/workflow/agents.mjs';
22
+ import {
23
+ agentEntryFile,
24
+ agentEntryPath,
25
+ parseManifestText,
26
+ } from '../../runtime/agent/orchestrator/runtime-core/workflow/agents.mjs';
23
27
  import { hasOwn } from '../../runtime/shared/object.mjs';
24
28
  import { serializeFrontmatterDoc } from '../../runtime/shared/markdown-frontmatter.mjs';
25
29
  import { isHiddenAgent } from '../../runtime/agent/orchestrator/internal-agents.mjs';
@@ -7,6 +7,7 @@ import { ensureProviderEnabled } from '../../runtime/agent/orchestrator/runtime-
7
7
  import { resolveRouteContextState, selectionFastCapable } from '../route-state.mjs';
8
8
  import {
9
9
  canonicalizeAgentRouteStorage,
10
+ EXPLORE_AGENT_ID,
10
11
  isAgentDisabled,
11
12
  withAgentDisabled,
12
13
  } from '../../runtime/shared/agent-route-config.mjs';
@@ -22,7 +23,11 @@ import {
22
23
 
23
24
  /** Mixy's runtime id (agent-home.mjs MIXY_AGENT_ID). */
24
25
  const MIXY_RUNTIME_ID = 'lead';
25
- import { routeChain, validateRouteChainProviders } from '../../runtime/shared/model-route-chain.mjs';
26
+ import {
27
+ canonicalRouteProvider,
28
+ routeChain,
29
+ validateRouteChainProviders,
30
+ } from '../../runtime/shared/model-route-chain.mjs';
26
31
 
27
32
  // Agent route persistence. Route-scope isolation: an agent route owns its
28
33
  // model AND its effort/fast, stored in config.agents[<id>]. The shared
@@ -183,18 +188,25 @@ export function createAgentRouteApi(deps) {
183
188
  }
184
189
  if (!clean(requested.provider)) return clearOverride(id);
185
190
  if (!clean(requested.model)) throw new Error('agent route requires provider and model');
191
+ // An explicit list is validated; the stored one may hold a fallback on the
192
+ // picked model's provider, which stays saved untouched and inactive.
193
+ const explicitFallbacks = hasOwn(requested, 'fallbacks');
186
194
  const chain = routeChain({
187
195
  ...requested,
188
- fallbacks: hasOwn(requested, 'fallbacks') ? requested.fallbacks : stored.fallbacks,
196
+ fallbacks: explicitFallbacks ? requested.fallbacks : stored.fallbacks,
189
197
  });
190
- validateRouteChainProviders(chain);
198
+ validateRouteChainProviders(chain, { allowDuplicates: !explicitFallbacks });
191
199
  const storedChain = routeChain(stored);
192
200
  const resolved = [];
201
+ const usedProviders = new Set();
193
202
  for (const entry of chain) {
203
+ const provider = canonicalRouteProvider(entry.provider);
204
+ const inactive = usedProviders.has(provider);
205
+ usedProviders.add(provider);
194
206
  const previous = storedChain.find(
195
207
  (candidate) => candidate.provider === entry.provider && candidate.model === entry.model
196
208
  );
197
- resolved.push(await resolveChainEntry(deps, entry, previous || {}));
209
+ resolved.push(inactive ? entry : await resolveChainEntry(deps, entry, previous || {}));
198
210
  }
199
211
  const [primary, ...fallbacks] = resolved;
200
212
  const routeToSave = normalizeWorkflowRoute({ ...primary, fallbacks });
@@ -215,5 +227,13 @@ export function createAgentRouteApi(deps) {
215
227
  return stayOff ? { ...routeToSave, id, disabled: true } : routeToSave;
216
228
  }
217
229
 
218
- return { setAgentRoute };
230
+ // Explore's route decides whether the explore tool exists, so the empty
231
+ // session rebuilds its tool surface on any change of it.
232
+ async function setAgentRouteAndRefresh(agentId, next) {
233
+ const saved = await setAgentRoute(agentId, next);
234
+ if (agentEditorId(agentId) === EXPLORE_AGENT_ID) await deps.refreshEmptySessionToolPolicy?.();
235
+ return saved;
236
+ }
237
+
238
+ return { setAgentRoute: setAgentRouteAndRefresh };
219
239
  }
@@ -20,7 +20,7 @@ import { resolveDataDir } from './shared.mjs';
20
20
  function applyWorkflowSlots(workflowInput, draft) {
21
21
  for (const slot of WORKFLOW_ROUTE_SLOTS) {
22
22
  if (!hasOwn(workflowInput, slot)) continue;
23
- const normalized = normalizeWorkflowRoute(workflowInput[slot]);
23
+ const normalized = normalizeWorkflowRoute(workflowInput[slot], {}, { strict: true });
24
24
  if (slot === 'lead') {
25
25
  if (!normalized) continue;
26
26
  draft.presets = upsertWorkflowPreset(draft.presets, 'lead', normalized);
@@ -40,7 +40,7 @@ function applyAgentRouteInput(agentInput, agentRoutes, configurableIds) {
40
40
  const nextAgents = { ...agentRoutes };
41
41
  for (const id of configurableIds) {
42
42
  if (!hasOwn(agentInput, id)) continue;
43
- const routeToSave = normalizeWorkflowRoute(agentInput[id]);
43
+ const routeToSave = normalizeWorkflowRoute(agentInput[id], {}, { strict: true });
44
44
  if (routeToSave) nextAgents[id] = routeToSave;
45
45
  else delete nextAgents[id];
46
46
  }
@@ -67,7 +67,7 @@ export function createOnboardingApi(deps) {
67
67
  const config = getConfig();
68
68
  const nextConfig = { ...config };
69
69
  const defaultRoute = hasOwn(payload, 'defaultRoute')
70
- ? normalizeWorkflowRoute(payload.defaultRoute, getRoute())
70
+ ? normalizeWorkflowRoute(payload.defaultRoute, getRoute(), { strict: true })
71
71
  : null;
72
72
  const draft = {
73
73
  presets: Array.isArray(nextConfig.presets) ? nextConfig.presets.slice() : [],
@@ -0,0 +1,176 @@
1
+ /**
2
+ * The activity checks every workspace change runs first: whether the hosted
3
+ * Lead (its turn, workers and background shells) is idle, and whether other
4
+ * sessions work in a shared checkout — then holding that checkout so new
5
+ * turns there wait until the change settles (admission gate).
6
+ */
7
+ import { worktreeError, worktreeRefusal } from '../../runtime/shared/worktrees/contract.mjs';
8
+ import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
9
+ import {
10
+ holdWorkspaceActivity,
11
+ isExternalCheckout,
12
+ releaseAll,
13
+ } from '../../runtime/shared/worktrees/activity-gate.mjs';
14
+ import { AGENT_OWNER } from '../../runtime/agent/orchestrator/agent-owner.mjs';
15
+ import { holdCheckoutFolder } from './admission-gate.mjs';
16
+
17
+ const ACTIVE_STAGES = new Set(['connecting', 'requesting', 'streaming', 'tool_running', 'running', 'cancelling']);
18
+ const BUSY_WORKER_STATES = new Set([...ACTIVE_STAGES, 'starting', 'spawning', 'queued', 'pending']);
19
+ const BUSY_JOB_STATES = new Set(['starting', 'spawning', 'queued', 'pending', 'running']);
20
+
21
+ const lower = (value) => String(value || '').toLowerCase();
22
+
23
+ /** @param {object} deps The activity sources of createWorkspaceTransitions. */
24
+ export function createActivityGuards({
25
+ getActiveTurnCount,
26
+ agentStatusState,
27
+ countOwnShellJobs,
28
+ listLiveSessions,
29
+ sessionManager,
30
+ listWorkspaceConsumers,
31
+ listWorkspaceJobs,
32
+ }) {
33
+ function isSessionActive(session) {
34
+ const runtime = sessionManager?.getSessionRuntime?.(session.id);
35
+ if (runtime?.controller?.signal && !runtime.controller.signal.aborted) return true;
36
+ return ACTIVE_STAGES.has(lower(runtime?.stage || session.status));
37
+ }
38
+
39
+ const workersOf = (session) =>
40
+ listLiveSessions().filter(
41
+ (candidate) =>
42
+ candidate?.id &&
43
+ candidate.id !== session.id &&
44
+ candidate.owner === AGENT_OWNER &&
45
+ candidate.closed !== true &&
46
+ (candidate.ownerSessionId === session.id || candidate.parentSessionId === session.id)
47
+ );
48
+
49
+ /**
50
+ * WORKTREE_BUSY_JOBS while this Lead has a turn, workers or background
51
+ * shells running (`shellJobs: false` tolerates background shells).
52
+ */
53
+ async function assertLeadIdle(session, { ownTurn = false, shellJobs: checkShellJobs = true } = {}) {
54
+ if (!ownTurn && getActiveTurnCount() > 0) {
55
+ throw worktreeError('WORKTREE_BUSY_JOBS', 'The session is running a turn; wait for it to finish.', {
56
+ reason: 'turn',
57
+ });
58
+ }
59
+ const status = agentStatusState?.() || {};
60
+ const workers = Array.isArray(status.agentWorkers) ? status.agentWorkers : [];
61
+ const jobs = Array.isArray(status.agentJobs) ? status.agentJobs : [];
62
+ const busyWorkers = workers.filter(
63
+ (row) => BUSY_WORKER_STATES.has(lower(row?.status)) || BUSY_WORKER_STATES.has(lower(row?.stage))
64
+ ).length;
65
+ const busyJobs = jobs.filter((row) => BUSY_JOB_STATES.has(lower(row?.status))).length;
66
+ if (busyWorkers || busyJobs) {
67
+ throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'workers', workers: busyWorkers, jobs: busyJobs });
68
+ }
69
+ if (!checkShellJobs) return;
70
+ const ids = new Set([session.id, ...workers.map((row) => row?.sessionId).filter(Boolean)]);
71
+ for (const worker of workersOf(session)) ids.add(worker.id);
72
+ const shellJobs = await countOwnShellJobs([...ids]);
73
+ if (shellJobs > 0) throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'shell-jobs', shellJobs });
74
+ }
75
+
76
+ /**
77
+ * A checkout or merge in the shared checkout `folder` refuses while another
78
+ * session (not this Lead's own workers) works there, then holds the folder
79
+ * until the returned release: other sessions' turns that arrive meanwhile
80
+ * wait (admission gate). `sessionId` null: a session-less (draft) change.
81
+ * @returns {() => void}
82
+ */
83
+ function holdProjectFolder(sessionId, folder, { hold = true } = {}) {
84
+ const users = listLiveSessions().filter(
85
+ (candidate) =>
86
+ candidate?.id &&
87
+ candidate.id !== sessionId &&
88
+ candidate.closed !== true &&
89
+ (!sessionId || (candidate.ownerSessionId !== sessionId && candidate.parentSessionId !== sessionId)) &&
90
+ typeof candidate.cwd === 'string' &&
91
+ isWithin(folder, candidate.cwd) &&
92
+ isSessionActive(candidate)
93
+ );
94
+ if (users.length) throw worktreeRefusal('folder-in-use', { sessions: users.map((candidate) => candidate.id) });
95
+ return holdCheckoutFolder(sessionId, folder, { hold });
96
+ }
97
+
98
+ /** Run `fn` holding the checkout `folder` (holdProjectFolder); released when it settles. */
99
+ async function withProjectFolder(sessionId, folder, fn) {
100
+ const release = holdProjectFolder(sessionId, folder);
101
+ try {
102
+ return await fn();
103
+ } finally {
104
+ release();
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Before a carry clears the shared checkout `folder` (held by the caller,
110
+ * so no new turn starts there): WORKTREE_BUSY_JOBS while any other session
111
+ * working in it — idle or not, this Lead's workers included — owns a
112
+ * running background shell (holdProjectFolder already refused running
113
+ * turns and agents there, assertLeadIdle this Lead's own). Processes
114
+ * outside Mixdog (editors, watchers) cannot be excluded.
115
+ */
116
+ async function assertCheckoutQuiet(session, folder) {
117
+ const sharing = listLiveSessions()
118
+ .filter(
119
+ (candidate) =>
120
+ candidate?.id &&
121
+ candidate.id !== session.id &&
122
+ candidate.closed !== true &&
123
+ typeof candidate.cwd === 'string' &&
124
+ isWithin(folder, candidate.cwd)
125
+ )
126
+ .map((candidate) => candidate.id);
127
+ if (!sharing.length) return;
128
+ const shellJobs = await countOwnShellJobs(sharing);
129
+ if (shellJobs > 0) throw worktreeRefusal('folder-shell-jobs', { shellJobs });
130
+ }
131
+
132
+ /**
133
+ * The shared admission of every merge and folder cleanup (manageProjectBranch):
134
+ * refuses while a session or worker runs in an affected folder, or a
135
+ * background command does; `removing` refuses while any session still uses
136
+ * one. Then holds the folders — Mixdog checkouts only; an external checkout
137
+ * takes no lease from this profile — so new Mixdog work there waits until `run`
138
+ * settles. `actor`: the session acting on its own checkout, whose own turn
139
+ * and workers its caller already checked (assertLeadIdle).
140
+ */
141
+ async function withManagementFolders(folders, removing, run, { actor = null } = {}) {
142
+ const release = [];
143
+ try {
144
+ for (const folder of [...new Set(folders)].sort()) {
145
+ release.push(holdProjectFolder(actor, folder, { hold: !isExternalCheckout(folder) }));
146
+ }
147
+ release.push(holdWorkspaceActivity(folders, { sessionId: actor }));
148
+ const stored = await listWorkspaceConsumers();
149
+ const consumers = new Map(stored.map((session) => [session.id, session]));
150
+ for (const session of listLiveSessions()) if (session?.closed !== true) consumers.set(session.id, session);
151
+ const affected = [...consumers.values()].filter((session) =>
152
+ folders.some((folder) => session.cwd && isWithin(folder, session.cwd))
153
+ );
154
+ const blocking = removing
155
+ ? affected
156
+ : affected.filter(
157
+ (session) =>
158
+ !(actor && [session.id, session.ownerSessionId, session.parentSessionId].includes(actor)) &&
159
+ isSessionActive(session)
160
+ );
161
+ if (blocking.length) throw worktreeRefusal('folder-in-use', { sessions: blocking.map((session) => session.id) });
162
+ const jobs = await listWorkspaceJobs();
163
+ if (jobs.some((job) => !job.terminal && folders.some((folder) => isWithin(folder, job.cwd)))) {
164
+ throw worktreeRefusal('folder-shell-jobs');
165
+ }
166
+ if ((await countOwnShellJobs(affected.map((session) => session.id))) > 0) {
167
+ throw worktreeRefusal('folder-shell-jobs');
168
+ }
169
+ return await run([...consumers.keys()]);
170
+ } finally {
171
+ releaseAll(release);
172
+ }
173
+ }
174
+
175
+ return { workersOf, assertLeadIdle, withProjectFolder, assertCheckoutQuiet, withManagementFolders };
176
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * The hosted Lead's workspace as the transitions read it: the session this
3
+ * runtime hosts, its stored (or project-folder) workspace record, the live
4
+ * view the session snapshot publishes and the branch menu.
5
+ */
6
+ import { isDeepStrictEqual } from 'node:util';
7
+ import {
8
+ branchMenuEntries,
9
+ isWorktreeBound,
10
+ normalizeSessionWorkspace,
11
+ worktreeError,
12
+ } from '../../runtime/shared/worktrees/contract.mjs';
13
+ import { samePath } from '../../runtime/shared/worktrees/paths.mjs';
14
+ import { readGitHead } from '../../runtime/shared/worktrees/git-head.mjs';
15
+ import { readSessionWorkspace } from './workspace-state.mjs';
16
+
17
+ /**
18
+ * @param {object} deps The host hooks of createWorkspaceTransitions plus its
19
+ * `backend()` loader and `pendingWorktree()` (the armed worktree intent).
20
+ */
21
+ export function createSessionWorkspaceView({
22
+ getSession,
23
+ getCurrentCwd,
24
+ getDesktopSession,
25
+ createCurrentSession,
26
+ inspectProject,
27
+ backend,
28
+ pendingWorktree,
29
+ }) {
30
+ function hostedSession(sessionRef) {
31
+ const session = getSession();
32
+ const requested = String(sessionRef?.sessionId || '').trim();
33
+ if (!session?.id || (requested && requested !== session.id)) {
34
+ throw new Error(`workspace: session ${requested || '(none)'} is not hosted by this runtime.`);
35
+ }
36
+ return session;
37
+ }
38
+
39
+ async function ensureSession() {
40
+ if (!getSession()?.id && typeof createCurrentSession === 'function') await createCurrentSession('workspace');
41
+ return hostedSession(null);
42
+ }
43
+
44
+ function projectPathOf(session) {
45
+ const desktop = getDesktopSession?.() || session?.desktopSession;
46
+ if (desktop?.classification === 'project' && desktop.projectPath) return desktop.projectPath;
47
+ return session?.cwd || getCurrentCwd();
48
+ }
49
+
50
+ /** The stored record, or the project-folder workspace (revision 0) of a session that never moved. */
51
+ function currentWorkspace(session) {
52
+ const stored = readSessionWorkspace(session);
53
+ if (stored) return stored;
54
+ const projectPath = projectPathOf(session);
55
+ return normalizeSessionWorkspace({ projectPath, cwd: getCurrentCwd() || projectPath, revision: 0 });
56
+ }
57
+
58
+ let liveWorkspace = null;
59
+
60
+ /**
61
+ * The workspace the session publishes: a worktree-bound record as stored; a
62
+ * project-folder session (never moved, back from a worktree, or carrying a
63
+ * transition stub) with the folder's checked-out branch / detached commit and
64
+ * repoCommonDir read straight from HEAD — no git process. Null outside a git
65
+ * repository for a session without a record. Identity-stable while equal.
66
+ */
67
+ function getLiveWorkspace() {
68
+ const session = getSession();
69
+ const stored = readSessionWorkspace(session);
70
+ if (isWorktreeBound(stored)) return session.workspace;
71
+ let base;
72
+ try {
73
+ base = stored ?? currentWorkspace(session);
74
+ } catch {
75
+ return session?.workspace ?? null;
76
+ }
77
+ const head = readGitHead(base.cwd);
78
+ if (!head) return session?.workspace ?? null;
79
+ const next = {
80
+ ...base,
81
+ repoCommonDir: head.repoCommonDir,
82
+ branch: head.branch,
83
+ baseCommit: head.branch ? base.baseCommit : head.commit,
84
+ };
85
+ if (!liveWorkspace || !isDeepStrictEqual(liveWorkspace, next)) liveWorkspace = next;
86
+ return liveWorkspace;
87
+ }
88
+
89
+ /** WORKTREE_PROJECT_MISMATCH unless `repoCommonDir` (when given) is the session Project's repository. */
90
+ async function sessionProject(session, repoCommonDir) {
91
+ const workspace = currentWorkspace(session);
92
+ const project = await inspectProject(workspace.projectPath);
93
+ if (repoCommonDir && !samePath(repoCommonDir, project.repoCommonDir)) {
94
+ throw worktreeError(
95
+ 'WORKTREE_PROJECT_MISMATCH',
96
+ "Managed worktrees belong to this session's Project repository; run the command there.",
97
+ { projectPath: workspace.projectPath, repoCommonDir }
98
+ );
99
+ }
100
+ return { workspace, project };
101
+ }
102
+
103
+ async function getBranchMenu() {
104
+ const session = getSession();
105
+ const workspace = session?.id
106
+ ? currentWorkspace(session)
107
+ : normalizeSessionWorkspace({ projectPath: projectPathOf(null), cwd: getCurrentCwd(), revision: 0 });
108
+ const menu = await (await backend()).listBranchOccupancy({
109
+ projectPath: workspace.projectPath,
110
+ sessionId: session?.id || null,
111
+ });
112
+ const selectedEntry = workspace.worktreeId ? await (await backend()).findWorktreeContaining(workspace.cwd) : null;
113
+ // A session outside a managed worktree (the project folder — never moved,
114
+ // or back from a worktree — or a linked checkout of the selected branch)
115
+ // is on whatever that folder has checked out now.
116
+ // Its repository is the project's (a never-moved session has no stored
117
+ // record), and a detached checkout shows branch null with the commit in
118
+ // baseCommit — never mistaken for "not a repository".
119
+ let view = workspace;
120
+ if (!isWorktreeBound(workspace)) {
121
+ const project = await inspectProject(workspace.cwd);
122
+ const checkedOut = project.currentBranch ?? null;
123
+ view = {
124
+ ...workspace,
125
+ repoCommonDir: project.repoCommonDir ?? workspace.repoCommonDir,
126
+ branch: checkedOut,
127
+ baseCommit: checkedOut ? workspace.baseCommit : (project.headCommit ?? null),
128
+ };
129
+ }
130
+ return {
131
+ workspace: view,
132
+ pendingWorktree: pendingWorktree(),
133
+ branches: branchMenuEntries(menu.branches, menu.occupancy),
134
+ occupancy: menu.occupancy,
135
+ retainedWorktree: selectedEntry ?? menu.retainedWorktree ?? null,
136
+ // Creation notes of the retained worktree (submodules, include entries).
137
+ warnings: Array.isArray(menu.retainedWorktree?.warnings) ? [...menu.retainedWorktree.warnings] : [],
138
+ };
139
+ }
140
+
141
+ return {
142
+ hostedSession,
143
+ ensureSession,
144
+ currentWorkspace,
145
+ getLiveWorkspace,
146
+ sessionProject,
147
+ getBranchMenu,
148
+ };
149
+ }