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
@@ -1,20 +1,32 @@
1
- // The one MCP server of a multi-account connector (connector-catalog.mjs
2
- // connectorAccountsOf): Gmail, Google Calendar or Google Drive with every
3
- // connected account behind one tool set. Answered in-process like the
4
- // one-account servers it fronts (google-mcp.mjs, gmail-app-password.mjs):
5
- // each tool takes `account` (the account's address), and the call goes to
6
- // that account's own endpoint with that account's own credentials (its OAuth
7
- // tokens, or its app password from the keychain). With one account
8
- // `account` may be left out; with several, a call naming none is refused
9
- // with the list, so the model asks the user. An account that fails stays
10
- // listed with why (connectorAccountHealth); the server only fails to start
11
- // when no account can be used.
1
+ // The one MCP server of a catalog connector (connector-catalog.mjs
2
+ // connectorAccountsOf): every connected account of Gmail, Notion, Postgres…
3
+ // behind one tool set, answered in-process. Underneath, each account is its
4
+ // own ordinary MCP connection with its own credentials (client-transport.mjs
5
+ // connectorAccountClient), and its tools are the ones its backend lists. This
6
+ // server lists their union (a tool whose schema differs between accounts is
7
+ // left out), each with one more optional argument, `account` (an account's
8
+ // address or name), which never reaches the account.
9
+ //
10
+ // The account a call uses: the one it names; else the one last used in its
11
+ // conversation, else the connector's last-used account (connectorAccountInUse),
12
+ // else the topmost connected account. A named or remembered account that is
13
+ // switched off, removed or needs a sign-in fails the call with the usable
14
+ // accounts listed; no other account ever stands in for it. A conversation's
15
+ // call (`_meta[CONVERSATION_META]`) makes its account the last used, for the
16
+ // conversation and the connector. Every result of a call made on an account,
17
+ // errors included, says which account answered. A name binds a call to one
18
+ // account; an address or label two accounts share binds none.
19
+ // An account that fails stays listed with why (connectorAccountHealth); the
20
+ // server only fails to start when no account can be used.
21
+ import { join } from 'node:path';
22
+ import { readJsonStateSync, updateJsonAtomicSync } from '../shared/atomic-file.mjs';
12
23
  import { accountsOfInstructions, connectorAccountsInstructions } from '../shared/connector-accounts.mjs';
13
24
  import { connectorById } from '../shared/connector-catalog.mjs';
14
- import { gmailAppPasswordTools } from './gmail-app-password.mjs';
15
- import { googleMcpTools } from './google-mcp.mjs';
25
+ import { resolvePluginData } from '../shared/plugin-paths.mjs';
16
26
 
17
27
  const PROTOCOL_VERSION = '2025-06-18';
28
+ /** The `_meta` key of a tools/call that names the conversation it is made in. */
29
+ export const CONVERSATION_META = 'mixdog/conversation';
18
30
 
19
31
  const json = (status, body) =>
20
32
  new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
@@ -36,66 +48,158 @@ export function forgetConnectorAccountHealth(name) {
36
48
  health.delete(name);
37
49
  }
38
50
 
39
- const ACCOUNT_PROPERTY = Object.freeze({
40
- type: 'string',
41
- description:
42
- 'The account to act as (its email address). May be left out when one account is connected; required when several are.',
43
- });
51
+ // ── The last-used account ───────────────────────────────────────────────────
52
+ // Per connector, in the data dir (every runtime reads the same one); per
53
+ // conversation, in memory (the newest conversations kept).
54
+ const ACCOUNTS_IN_USE_FILE = 'connector-accounts-in-use.json';
55
+ const inUseFile = () => join(resolvePluginData(), ACCOUNTS_IN_USE_FILE);
56
+ const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
57
+ const validInUse = (value) => {
58
+ if (!isRecord(value)) throw new Error('the accounts in use must be an object');
59
+ return value;
60
+ };
44
61
 
45
- const SERVICE_OF = { gmail: 'gmail', 'google-calendar': 'calendar', 'google-drive': 'drive' };
46
-
47
- /** The tools of `connector` over `accounts`, each taking `account`. Gmail on
48
- * an app password has the larger set (IMAP); a Google sign-in Gmail account
49
- * answers the tools it has and refuses the others. */
50
- function connectorTools(connector, accounts, { hidden = false } = {}) {
51
- const tools =
52
- connector === 'gmail' && accounts.some((account) => account.appPassword)
53
- ? gmailAppPasswordTools({ hidden })
54
- : googleMcpTools(SERVICE_OF[connector]);
55
- return tools.map((tool) => ({
56
- ...tool,
57
- inputSchema: {
58
- ...tool.inputSchema,
59
- properties: { ...(tool.inputSchema?.properties || {}), account: ACCOUNT_PROPERTY },
60
- },
61
- }));
62
+ /** The name of the account catalog connector `connector` used last, '' when
63
+ * none was recorded. */
64
+ export function connectorAccountInUse(connector) {
65
+ const stored = readJsonStateSync(inUseFile(), { validate: validInUse, fallback: {} });
66
+ return typeof stored[connector] === 'string' ? stored[connector] : '';
62
67
  }
63
68
 
64
- class AccountChoiceError extends Error {}
69
+ function rememberAccountInUse(connector, name) {
70
+ if (connectorAccountInUse(connector) === name) return;
71
+ updateJsonAtomicSync(inUseFile(), (current) => ({ ...(isRecord(current) ? current : {}), [connector]: name }));
72
+ }
65
73
 
66
- const labelOf = (account) => account.email || account.name;
74
+ const CONVERSATIONS_KEPT = 500;
75
+ // conversation → (connector → account name), oldest first.
76
+ const conversations = new Map();
67
77
 
68
- /** The account a call names (by address, or by its account name), or its
69
- * only account; throws the account list otherwise. */
70
- function pickAccount(accounts, value, service) {
71
- const list = accounts.map(labelOf).join(', ');
72
- const wanted = text(value).toLowerCase();
73
- if (wanted) {
74
- const found = accounts.find(
75
- (account) => account.email.toLowerCase() === wanted || account.name.toLowerCase() === wanted
76
- );
77
- if (!found) throw new AccountChoiceError(`Unknown ${service} account "${text(value)}". Accounts: ${list}.`);
78
- return found;
78
+ /** Account `name` of `connector` was removed: wherever it is the last used it
79
+ * stays a removed account, so a call that would default to it keeps failing
80
+ * closed, even once a new account is given the same name. */
81
+ export function retireConnectorAccount(connector, name) {
82
+ const removed = `${name} (removed)`;
83
+ for (const own of conversations.values()) if (own.get(connector) === name) own.set(connector, removed);
84
+ if (connectorAccountInUse(connector) === name) rememberAccountInUse(connector, removed);
85
+ }
86
+
87
+ function rememberConversationAccount(conversation, connector, name) {
88
+ const own = conversations.get(conversation) || new Map();
89
+ conversations.delete(conversation);
90
+ own.set(connector, name);
91
+ conversations.set(conversation, own);
92
+ if (conversations.size > CONVERSATIONS_KEPT) conversations.delete(conversations.keys().next().value);
93
+ }
94
+
95
+ const ACCOUNT_PROPERTY = Object.freeze({
96
+ type: 'string',
97
+ description: 'The account to use (its email address or account name). Left out: the account used last.',
98
+ });
99
+
100
+ /** `value` as JSON with every object's keys sorted, so equal schemas compare
101
+ * equal whatever order their keys were written in. */
102
+ const canonical = (value) => {
103
+ if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;
104
+ if (isRecord(value)) {
105
+ const keys = Object.keys(value).filter((key) => value[key] !== undefined).sort();
106
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(',')}}`;
107
+ }
108
+ return JSON.stringify(value) ?? 'null';
109
+ };
110
+
111
+ /** The tools every account lists, once each, with `account` added; a tool
112
+ * two accounts list with different schemas is left out. */
113
+ function unionTools(states) {
114
+ const first = new Map();
115
+ const differs = new Set();
116
+ for (const { tools = [] } of states) {
117
+ for (const tool of tools) {
118
+ const seen = first.get(tool.name);
119
+ if (!seen) first.set(tool.name, tool);
120
+ else if (canonical(seen.inputSchema) !== canonical(tool.inputSchema)) differs.add(tool.name);
121
+ }
79
122
  }
80
- if (accounts.length === 1) return accounts[0];
81
- throw new AccountChoiceError(
82
- `Several ${service} accounts are connected: ${list}. Ask the user which one, then pass it as \`account\`.`
83
- );
123
+ return [...first.values()]
124
+ .filter((tool) => !differs.has(tool.name))
125
+ .map((tool) => ({
126
+ ...tool,
127
+ inputSchema: {
128
+ type: 'object',
129
+ ...tool.inputSchema,
130
+ properties: { ...(tool.inputSchema?.properties || {}), account: ACCOUNT_PROPERTY },
131
+ },
132
+ }));
84
133
  }
85
134
 
86
135
  const noteOf = (state) => (state.authRequired ? 'needs sign-in' : 'unavailable');
136
+ const usable = (account) => health.get(account.name)?.authRequired !== true;
137
+
138
+ /** `result` saying which account answered it (`label`). */
139
+ const withAccountNote = (result, service, label) => ({
140
+ ...result,
141
+ content: [
142
+ ...(Array.isArray(result?.content) ? result.content : []),
143
+ { type: 'text', text: `(${service} account: ${label})` },
144
+ ],
145
+ });
87
146
 
88
147
  /**
89
148
  * A `fetch` answering the accounts server of `connector` in-process. Each of
90
- * `accounts` is `{ name, email, appPassword, request(message, { signal }) }`:
91
- * `request` sends one JSON-RPC message to that account's own endpoint with its own
92
- * credentials and resolves the JSON-RPC reply; it throws when the account
93
- * cannot be reached (an `authRequired` error when it needs a sign-in).
149
+ * `accounts` is `{ name, email, connect(signal), callTool(params, { signal, onprogress }) }`:
150
+ * `connect` resolves `{ instructions, tools }` of that account's own MCP
151
+ * connection, `callTool` sends it one tools/call (reporting its progress to
152
+ * `onprogress`, when given) and resolves the result; both
153
+ * throw when the account cannot be reached (an `authRequired` error when it
154
+ * needs a sign-in). The fetch carries `connectorAccounts`: `{ connector,
155
+ * choose({ tool, wanted, conversation }) }`, `{ name, label }` of the account
156
+ * such a call would use (it throws the refusal otherwise), for binding a call
157
+ * to its account (by its unique name) before it is approved.
94
158
  */
95
159
  export function withConnectorAccountsMcp({ connector, accounts }) {
96
160
  const service = connectorById(connector)?.name || connector;
97
- const listed = connectorTools(connector, accounts);
98
- const callable = connectorTools(connector, accounts, { hidden: true });
161
+ // account name → the names of the tools it lists (set once it answered).
162
+ const toolsOf = new Map();
163
+ let listed = [];
164
+ const same = (a, b) => Boolean(a) && a.toLowerCase() === b.toLowerCase();
165
+ /** What an account is called to the model: its address, with its name when
166
+ * another account shares that address. */
167
+ const labelOf = (account) => {
168
+ if (!account.email) return account.name;
169
+ const shared = accounts.some((other) => other !== account && same(other.email, account.email));
170
+ return shared ? `${account.email} (${account.name})` : account.email;
171
+ };
172
+ /** The account a call uses (see the header); throws the refusal. */
173
+ const choose = ({ tool, wanted, conversation }) => {
174
+ const refuse = (why) => {
175
+ const list = accounts.filter(usable).map(labelOf).join(', ') || 'none';
176
+ return new Error(`${why} Usable ${service} accounts: ${list}. Pass one as \`account\`.`);
177
+ };
178
+ const named = text(wanted);
179
+ let account;
180
+ if (named) {
181
+ // Its unique name, else the one account its address or label is.
182
+ let matches = accounts.filter((one) => same(one.name, named));
183
+ if (!matches.length) matches = accounts.filter((one) => same(one.email, named) || same(labelOf(one), named));
184
+ if (!matches.length) throw refuse(`No connected ${service} account is "${named}".`);
185
+ if (matches.length > 1) {
186
+ const names = matches.map((one) => one.name).join(', ');
187
+ throw refuse(`"${named}" is more than one ${service} account (${names}); name one.`);
188
+ }
189
+ [account] = matches;
190
+ } else {
191
+ const remembered =
192
+ (conversation && conversations.get(conversation)?.get(connector)) || connectorAccountInUse(connector);
193
+ account = remembered ? accounts.find((one) => one.name === remembered) : accounts[0];
194
+ if (!account) throw refuse(`The ${service} account used last (${remembered}) is not connected now.`);
195
+ }
196
+ if (!usable(account)) throw refuse(`${labelOf(account)} needs a sign-in in Connectors.`);
197
+ const has = toolsOf.get(account.name);
198
+ if (has && !has.has(tool) && listed.some((one) => one.name === tool)) {
199
+ throw refuse(`${labelOf(account)} has no ${tool} tool.`);
200
+ }
201
+ return account;
202
+ };
99
203
  const record = (account, state) => {
100
204
  if (state.email) account.email = state.email;
101
205
  health.set(account.name, {
@@ -109,13 +213,13 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
109
213
  record(account, state);
110
214
  return state;
111
215
  };
112
- // Each account's own initialize: whether it can be used, and its address.
216
+ // Each account's own connection: whether it can be used, its address and tools.
113
217
  const probe = async (account, signal) => {
114
218
  try {
115
- const reply = await account.request({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }, { signal });
116
- if (reply?.error) return failure(account, new Error(reply.error.message || 'The account did not start'));
117
- const [email = ''] = accountsOfInstructions(reply?.result?.instructions);
118
- const state = { email: account.email || email };
219
+ const { instructions, tools } = await account.connect(signal);
220
+ toolsOf.set(account.name, new Set(tools.map((tool) => tool.name)));
221
+ const [email = ''] = accountsOfInstructions(instructions);
222
+ const state = { email: account.email || email, instructions, tools };
119
223
  record(account, state);
120
224
  return state;
121
225
  } catch (error) {
@@ -125,7 +229,9 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
125
229
  // The calls in flight by JSON-RPC id, so a `notifications/cancelled` for one
126
230
  // aborts its downstream request.
127
231
  const inflight = new Map();
128
- async function rpc(message, transportSignal) {
232
+ /** One JSON-RPC request's reply; `notify` sends a notification ahead of it
233
+ * (a tools/call's progress). */
234
+ async function rpc(message, transportSignal, notify = null) {
129
235
  const { id, method, params } = message || {};
130
236
  const reply = (result) => ({ jsonrpc: '2.0', id, result });
131
237
  if (method === 'initialize') {
@@ -138,55 +244,69 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
138
244
  error: { code: -32001, message: first?.error || `No ${service} account is connected` },
139
245
  };
140
246
  }
247
+ listed = unionTools(states);
248
+ // What the accounts' own servers tell the model (an in-process Google
249
+ // account's only names its address, which the account list says).
250
+ const own = [
251
+ ...new Set(
252
+ states.map((state) => text(state.instructions)).filter((one) => one && !accountsOfInstructions(one).length)
253
+ ),
254
+ ];
255
+ const accountsLine = connectorAccountsInstructions(
256
+ accounts.map((account, index) => ({
257
+ email: labelOf(account),
258
+ ...(states[index].error ? { note: noteOf(states[index]) } : {}),
259
+ }))
260
+ );
141
261
  return reply({
142
262
  protocolVersion: text(params?.protocolVersion) || PROTOCOL_VERSION,
143
263
  capabilities: { tools: { listChanged: false } },
144
264
  serverInfo: { name: `mixdog-${connector}`, version: '1.0.0' },
145
- instructions: connectorAccountsInstructions(
146
- accounts.map((account, index) => ({
147
- email: labelOf(account),
148
- ...(states[index].error ? { note: noteOf(states[index]) } : {}),
149
- }))
150
- ),
265
+ instructions: [accountsLine, ...own].filter(Boolean).join('\n\n') || undefined,
151
266
  });
152
267
  }
153
268
  if (method === 'ping') return reply({});
154
269
  if (method === 'tools/list') return reply({ tools: listed });
155
270
  if (method === 'tools/call') {
156
271
  const name = params?.name;
157
- if (!callable.some((tool) => tool.name === name)) {
158
- return { jsonrpc: '2.0', id, error: { code: -32602, message: `Unknown tool: ${name}` } };
159
- }
160
- const { account: chosen, ...args } = params?.arguments || {};
272
+ const { account: wanted, ...args } = params?.arguments || {};
273
+ const conversation = text(params?._meta?.[CONVERSATION_META]);
161
274
  let account;
162
275
  try {
163
- account = pickAccount(accounts, chosen, service);
276
+ account = choose({ tool: name, wanted, conversation });
277
+ if (conversation) {
278
+ rememberConversationAccount(conversation, connector, account.name);
279
+ rememberAccountInUse(connector, account.name);
280
+ }
164
281
  } catch (error) {
165
- return reply(errorResult(error.message));
282
+ return reply(errorResult(error?.message || String(error)));
166
283
  }
167
284
  const cancel = new AbortController();
168
285
  const signal = transportSignal ? AbortSignal.any([transportSignal, cancel.signal]) : cancel.signal;
169
286
  inflight.set(id, cancel);
287
+ // The account's progress reaches the caller under the caller's own token,
288
+ // so it resets the call's deadline as a direct server's progress does.
289
+ const progressToken = params?._meta?.progressToken;
290
+ const onprogress =
291
+ notify && progressToken !== undefined
292
+ ? (progress) => notify({ jsonrpc: '2.0', method: 'notifications/progress', params: { ...progress, progressToken } })
293
+ : undefined;
170
294
  try {
171
- const answer = await account.request(
172
- { jsonrpc: '2.0', id, method, params: { name, arguments: args } },
173
- { signal }
174
- );
175
- if (answer?.error) return reply(errorResult(`${labelOf(account)}: ${answer.error.message}`));
295
+ // An unlisted tool (one only the approval gate calls) is the account's to answer.
296
+ const result = await account.callTool({ name, arguments: args }, { signal, onprogress });
176
297
  if (health.get(account.name)?.error) record(account, {});
177
- return reply(answer?.result ?? errorResult(`${labelOf(account)}: no answer`));
298
+ return reply(withAccountNote(result, service, labelOf(account)));
178
299
  } catch (error) {
179
300
  // A cancelled call says nothing about the account's health.
180
- if (signal.aborted) return reply(errorResult(`${labelOf(account)}: cancelled`));
181
- const state = failure(account, error);
182
- return reply(errorResult(`${labelOf(account)}: ${state.error}`));
301
+ const why = signal.aborted ? 'cancelled' : failure(account, error).error;
302
+ return reply(withAccountNote(errorResult(why), service, labelOf(account)));
183
303
  } finally {
184
304
  inflight.delete(id);
185
305
  }
186
306
  }
187
307
  return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
188
308
  }
189
- return async (input, init) => {
309
+ const fetchImpl = async (input, init) => {
190
310
  const request = input instanceof Request ? input : null;
191
311
  if (String(request?.method || init?.method || 'GET').toUpperCase() !== 'POST') {
192
312
  return new Response(null, { status: 405, headers: { allow: 'POST' } });
@@ -203,28 +323,41 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
203
323
  for (const one of batch) {
204
324
  if (one?.method === 'notifications/cancelled') inflight.get(one.params?.requestId)?.abort();
205
325
  }
326
+ // A call asking for progress is answered as an event stream: its progress
327
+ // notifications, then its reply.
328
+ if (!Array.isArray(message) && message?.id !== undefined && message.params?._meta?.progressToken !== undefined) {
329
+ const encoder = new TextEncoder();
330
+ let open = true;
331
+ const stream = new ReadableStream({
332
+ start(controller) {
333
+ const send = (payload) => {
334
+ if (open) controller.enqueue(encoder.encode(`event: message\ndata: ${JSON.stringify(payload)}\n\n`));
335
+ };
336
+ void rpc(message, signal, send).then((answer) => {
337
+ send(answer);
338
+ if (open) controller.close();
339
+ open = false;
340
+ });
341
+ },
342
+ // The caller stopped reading (its call was aborted).
343
+ cancel() {
344
+ open = false;
345
+ },
346
+ });
347
+ return new Response(stream, { status: 200, headers: { 'content-type': 'text/event-stream' } });
348
+ }
206
349
  const replies = (await Promise.all(batch.map((one) => (one?.id === undefined ? null : rpc(one, signal))))).filter(
207
350
  Boolean
208
351
  );
209
352
  if (!replies.length) return new Response(null, { status: 202 });
210
353
  return json(200, Array.isArray(message) ? replies : replies[0]);
211
354
  };
212
- }
213
-
214
- /** `request` for an account answered at `url` through `fetchImpl` (its
215
- * credentials applied there) with `headers`: one JSON-RPC POST, its reply. */
216
- export function connectorAccountRequest(url, fetchImpl, headers = {}) {
217
- return async (message, { signal } = {}) => {
218
- const response = await fetchImpl(url, {
219
- method: 'POST',
220
- headers: { 'content-type': 'application/json', accept: 'application/json, text/event-stream', ...headers },
221
- body: JSON.stringify(message),
222
- signal,
223
- });
224
- if (!response.ok) {
225
- await response.body?.cancel();
226
- throw new Error(`The account's server answered ${response.status}`);
227
- }
228
- return response.json();
355
+ fetchImpl.connectorAccounts = {
356
+ connector,
357
+ choose: (call) => {
358
+ const account = choose(call);
359
+ return { name: account.name, label: labelOf(account) };
360
+ },
229
361
  };
362
+ return fetchImpl;
230
363
  }
@@ -723,9 +723,9 @@ const TOOLS = [
723
723
  ];
724
724
 
725
725
  /** The tool definitions (name, description, schema, annotations) the server
726
- * lists; with `hidden`, also the ones only the approval gate calls. */
727
- export function gmailAppPasswordTools({ hidden = false } = {}) {
728
- return TOOLS.filter((tool) => hidden || !tool.hidden).map(({ run, hidden: _hidden, ...tool }) => tool);
726
+ * lists: never the ones only the approval gate calls. */
727
+ export function gmailAppPasswordTools() {
728
+ return TOOLS.filter((tool) => !tool.hidden).map(({ run, hidden: _hidden, ...tool }) => tool);
729
729
  }
730
730
 
731
731
  // ── The MCP server at the reserved address ──────────────────────────────────
@@ -0,0 +1,93 @@
1
+ // One explorer: the agent loop driven directly with one fixed system prompt
2
+ // and the read-only filesystem tools — no session record, rules, skills,
3
+ // profile context or persistence.
4
+ import { agentLoop } from '../agent/orchestrator/session/agent-loop.mjs';
5
+ import { readOnlyFilesystemTools } from '../agent/orchestrator/session/manager/tool-resolution.mjs';
6
+ import { sharedPrefixProviderCacheOpts } from '../agent/orchestrator/agent-runtime/cache-strategy.mjs';
7
+ import { partialHandoffTextFromSession } from '../agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs';
8
+
9
+ // Tool-calling responses before the explorer must answer from what it has.
10
+ export const EXPLORER_MAX_TOOL_ROUNDS = 10;
11
+
12
+ export const EXPLORER_SYSTEM_PROMPT = [
13
+ 'You explore the working directory read-only to answer one question. You cannot edit, run commands or delegate.',
14
+ '',
15
+ 'Search:',
16
+ `- You have ${EXPLORER_MAX_TOOL_ROUNDS} tool rounds: batch independent searches in one turn (parallel calls or array arguments).`,
17
+ "- Search the question's own nouns, and match the subsystem it names, not a similarly named one.",
18
+ '- Locate first, then read only that window.',
19
+ '- A location a tool returned is final; never reconfirm it.',
20
+ '- Before answering, list the parts the question asks about; each needs its own tool-returned `path:line`.',
21
+ '- Cite implementation, not tests, docs or changelogs, unless asked.',
22
+ '- A part without a `path:line`: search again with different terms, or use `code_graph` on a found symbol (definition, callers, writers). Call it missing only after that search, and name what you searched.',
23
+ '- Stop once every part has its location.',
24
+ '',
25
+ 'Answer shape, hard limit 1,500 characters, nothing else:',
26
+ '- One short answer line.',
27
+ '- One evidence line per hop of each part (entry, callee, writer, reader), at most 10 lines: `path:line` from tool output, the exact function or symbol name there, a few words.',
28
+ '- No intro, summary, extra locations, notes about unread code or "Open:" lines.',
29
+ ].join('\n');
30
+
31
+ // One list for the process: identical schema bytes for every explorer.
32
+ const EXPLORER_TOOLS = readOnlyFilesystemTools();
33
+ export const EXPLORER_TOOL_NAMES = Object.freeze(EXPLORER_TOOLS.map((tool) => tool.name));
34
+
35
+ /** Exact provider prefix inputs, for cache-stability checks. */
36
+ export function explorerPrefix() {
37
+ return { system: EXPLORER_SYSTEM_PROMPT, tools: EXPLORER_TOOLS };
38
+ }
39
+
40
+ /**
41
+ * Answer `query` on `route` with `provider`. Resolves the answer text (on a
42
+ * salvage-flagged abort, the text written so far); rejects on failure.
43
+ */
44
+ export async function runExplorer({ query, route, provider, cwd = null, signal, ownerSessionId = null }) {
45
+ const tools = EXPLORER_TOOLS.slice();
46
+ const messages = [
47
+ { role: 'system', content: EXPLORER_SYSTEM_PROMPT },
48
+ { role: 'user', content: query },
49
+ ];
50
+ // In-memory policy only: the schema allowlist is also the execution
51
+ // allowlist (pre-dispatch-deny.mjs), and the owner ids attribute spend in
52
+ // the usage ledger. No session id, so nothing session-keyed is created.
53
+ const policy = {
54
+ provider: route.provider,
55
+ model: route.model,
56
+ cwd,
57
+ tools,
58
+ schemaAllowedTools: EXPLORER_TOOL_NAMES,
59
+ compaction: { auto: false },
60
+ ownerSessionId,
61
+ parentSessionId: ownerSessionId,
62
+ };
63
+ // Text of the request in flight, for salvage when the deadline cuts it.
64
+ let streamed = '';
65
+ try {
66
+ const response = await agentLoop(provider, messages, route.model, tools, null, cwd, {
67
+ signal,
68
+ session: policy,
69
+ ...(route.effort ? { effort: route.effort } : {}),
70
+ fast: route.fast === true,
71
+ modelParameters: route.modelParameters || {},
72
+ turnLimits: { maxToolRounds: EXPLORER_MAX_TOOL_ROUNDS },
73
+ ...sharedPrefixProviderCacheOpts(route.provider),
74
+ onProviderSendStarted: () => {
75
+ streamed = '';
76
+ },
77
+ onTextDelta: (chunk) => {
78
+ streamed += typeof chunk === 'string' ? chunk : '';
79
+ },
80
+ onTextReset: ({ chars } = {}) => {
81
+ streamed = streamed.slice(0, Math.max(0, streamed.length - (Number(chars) || 0)));
82
+ return true;
83
+ },
84
+ });
85
+ return String(response?.content || '').trim();
86
+ } catch (error) {
87
+ if (signal?.reason?.salvagePartial === true) {
88
+ const partial = [partialHandoffTextFromSession({ messages }, 2), streamed.trim()].filter(Boolean).join('\n\n');
89
+ if (partial) return partial;
90
+ }
91
+ throw error;
92
+ }
93
+ }
@@ -0,0 +1,35 @@
1
+ import { TOOL_SYNC_EXECUTION_CONTRACT } from '../shared/tool-execution-contract.mjs';
2
+
3
+ export const EXPLORE_MAX_QUERIES = 8;
4
+
5
+ export const TOOL_DEFS = [
6
+ {
7
+ name: 'explore',
8
+ title: 'Explore',
9
+ annotations: {
10
+ title: 'Explore',
11
+ readOnlyHint: true,
12
+ destructiveHint: false,
13
+ idempotentHint: true,
14
+ openWorldHint: false,
15
+ },
16
+ description:
17
+ 'Read-only code search in parallel explorers outside your context; returns one merged answer with path:line evidence. ' +
18
+ 'Use when locating needs 3+ searches, spans 2+ files or areas, or covers independent questions; a known file or one lookup: read/grep. ' +
19
+ TOOL_SYNC_EXECUTION_CONTRACT,
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ query: {
24
+ anyOf: [
25
+ { type: 'string', minLength: 1 },
26
+ { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1, maxItems: EXPLORE_MAX_QUERIES },
27
+ ],
28
+ description: 'One self-contained question, or an array of independent ones (one explorer each).',
29
+ },
30
+ },
31
+ required: ['query'],
32
+ additionalProperties: false,
33
+ },
34
+ },
35
+ ];