mixdog 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/package.json +4 -3
  2. package/scripts/build-shipped-history.mjs +125 -33
  3. package/scripts/gate-local.mjs +220 -63
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +139 -32
  6. package/scripts/lib/gate-timing-reporter.mjs +16 -0
  7. package/scripts/lib/run-node-tests.mjs +71 -34
  8. package/scripts/lib/scoped-temp.mjs +1 -0
  9. package/scripts/lib/test-failure-records.mjs +14 -1
  10. package/scripts/lib/test-failure-summary.mjs +9 -4
  11. package/scripts/lib/test-spawn-ledger.mjs +43 -3
  12. package/scripts/post-release-check.mjs +26 -16
  13. package/scripts/pptx-kit-index.mjs +5 -6
  14. package/scripts/provider-pingpong-live.mjs +1 -1
  15. package/scripts/prune-embedding-runtime.mjs +3 -1
  16. package/scripts/release-paths.mjs +7 -1
  17. package/scripts/suite-health.mjs +110 -28
  18. package/scripts/test.mjs +9 -14
  19. package/src/agents/advisor/AGENT.md +4 -4
  20. package/src/agents/advisor/agent.json +1 -1
  21. package/src/agents/explore/AGENT.md +22 -0
  22. package/src/agents/explore/agent.json +6 -0
  23. package/src/cli.mjs +7 -0
  24. package/src/defaults/agents.json +7 -0
  25. package/src/defaults/shipped-history.json +38 -2
  26. package/src/defaults/skills/browser-use/SKILL.md +4 -1
  27. package/src/defaults/skills/code-tidy/SKILL.md +71 -102
  28. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
  29. package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
  30. package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
  31. package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
  32. package/src/defaults/skills/computer-use/SKILL.md +12 -2
  33. package/src/defaults/skills/setup/SKILL.md +2 -2
  34. package/src/defaults/skills/setup/references/actions.md +28 -9
  35. package/src/defaults/skills/setup/references/surfaces.md +5 -2
  36. package/src/defaults/skills/setup-guide/SKILL.md +11 -3
  37. package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
  38. package/src/defaults/skills/skill-creator/SKILL.md +85 -190
  39. package/src/defaults/skills/skill-creator/references/design.md +70 -162
  40. package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
  41. package/src/defaults/skills/test-suite/SKILL.md +194 -0
  42. package/src/defaults/skills/test-suite/references/case-management.md +51 -0
  43. package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
  44. package/src/defaults/skills/test-suite/references/reliability.md +49 -0
  45. package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
  46. package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
  47. package/src/defaults/skills/visualize/SKILL.md +6 -2
  48. package/src/lib/instruction-text.cjs +36 -0
  49. package/src/lib/rules-builder.cjs +40 -50
  50. package/src/orchestration/balanced.md +23 -0
  51. package/src/orchestration/focused.md +22 -0
  52. package/src/orchestration/none.md +5 -0
  53. package/src/orchestration/swarm.md +24 -0
  54. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  55. package/src/rules/agent-mode/MIXY.md +2 -2
  56. package/src/rules/lead/LEAD.md +3 -3
  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/60-verification.md +10 -9
  60. package/src/rules/shared/70-delivery.md +4 -3
  61. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
  62. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  63. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -2
  64. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +132 -21
  65. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -9
  66. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  67. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  69. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/config.mjs +12 -7
  71. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
  72. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -30
  73. package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
  74. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +124 -12
  75. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +204 -49
  76. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +16 -7
  77. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +157 -57
  78. package/src/runtime/agent/orchestrator/mcp/client.mjs +54 -23
  79. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  81. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +83 -52
  82. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  83. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  84. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +43 -27
  85. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
  86. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
  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-sse-turn/turn-events/content-block-stop.mjs +3 -3
  90. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
  91. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
  92. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
  95. package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
  96. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
  97. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
  98. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
  99. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
  100. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  102. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +48 -31
  103. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
  104. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
  105. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
  106. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
  107. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  112. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +26 -28
  113. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
  116. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
  118. package/src/runtime/agent/orchestrator/providers/registry.mjs +33 -2
  119. package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
  120. package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
  121. package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
  122. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +576 -0
  123. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  124. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +32 -0
  125. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  126. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  127. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  129. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  130. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  131. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  132. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  133. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  134. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  136. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  137. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  138. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  139. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  140. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -47
  141. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  142. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +12 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  146. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +4 -1
  147. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +15 -6
  148. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
  149. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  150. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  151. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
  152. package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
  153. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +94 -10
  155. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  156. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  158. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  159. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  160. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  161. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +4 -4
  162. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +11 -6
  163. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +6 -6
  164. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  165. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
  166. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
  167. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +37 -8
  169. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  172. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +5 -3
  174. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  175. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  176. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  177. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  178. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  179. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  181. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  182. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +27 -3
  183. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +18 -2
  184. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
  185. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
  186. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  187. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  188. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +103 -50
  189. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  190. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  191. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  192. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  193. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  194. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  195. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  196. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  197. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  198. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  199. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  200. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  201. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  202. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  203. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  204. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +20 -0
  205. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -14
  206. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
  207. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +12 -0
  208. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  210. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +56 -14
  211. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  212. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +59 -20
  213. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  214. package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
  215. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
  216. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +18 -4
  217. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  218. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  219. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  220. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  221. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  222. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +48 -30
  223. package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
  224. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  225. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  226. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +12 -6
  227. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  228. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +1 -1
  229. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  230. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  231. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  232. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  233. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  234. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  235. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  236. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  237. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
  238. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
  239. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +177 -8
  240. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
  241. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  242. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  243. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  244. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  245. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  246. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  247. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  248. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  249. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
  250. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  251. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  252. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  253. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  254. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +42 -28
  255. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +30 -14
  256. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  257. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
  258. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  259. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  260. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
  261. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  262. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +95 -20
  263. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
  264. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  265. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  266. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  267. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  269. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  270. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  271. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  272. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  273. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
  274. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
  275. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +105 -15
  276. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
  277. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
  278. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
  279. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +35 -11
  280. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +2 -0
  281. package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
  282. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -6
  283. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  284. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  285. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  286. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  287. package/src/runtime/attachments/store.d.mts +1 -0
  288. package/src/runtime/attachments/store.mjs +2 -2
  289. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  290. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  291. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  292. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  293. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  294. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  295. package/src/runtime/channels/lib/whisper-port.mjs +19 -10
  296. package/src/runtime/channels/lib/whisper-server.mjs +22 -13
  297. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  298. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  299. package/src/runtime/connectors/connector-accounts-mcp.mjs +372 -103
  300. package/src/runtime/connectors/gmail-app-password.mjs +4 -4
  301. package/src/runtime/connectors/google-mcp.mjs +1 -1
  302. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  303. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  304. package/src/runtime/explore/explorer.mjs +88 -0
  305. package/src/runtime/explore/tool-defs.mjs +35 -0
  306. package/src/runtime/explore/tool.mjs +123 -0
  307. package/src/runtime/local-provider/hardware.mjs +1 -1
  308. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  309. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  310. package/src/runtime/media/media-usage.mjs +1 -1
  311. package/src/runtime/media/store.mjs +1 -1
  312. package/src/runtime/memory/index.mjs +15 -1
  313. package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
  314. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  315. package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
  316. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  317. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  318. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  319. package/src/runtime/memory/lib/memory.mjs +17 -0
  320. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  321. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  322. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  323. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  324. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  325. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  326. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  327. package/src/runtime/office/capabilities.mjs +1 -1
  328. package/src/runtime/office/core/office-core.mjs +1 -1
  329. package/src/runtime/office/design/content-model.mjs +3 -3
  330. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  331. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  332. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  333. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  334. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  335. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  336. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  337. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  338. package/src/runtime/office/quality/assurance-structure-docx.mjs +1 -1
  339. package/src/runtime/shared/agent-route-config.mjs +17 -2
  340. package/src/runtime/shared/atomic-file.d.mts +8 -0
  341. package/src/runtime/shared/atomic-file.mjs +103 -2
  342. package/src/runtime/shared/background-tasks.mjs +37 -10
  343. package/src/runtime/shared/background-wait.mjs +66 -0
  344. package/src/runtime/shared/child-guardian.mjs +17 -7
  345. package/src/runtime/shared/config.mjs +313 -16
  346. package/src/runtime/shared/connector-accounts.mjs +5 -5
  347. package/src/runtime/shared/connector-catalog.d.mts +14 -8
  348. package/src/runtime/shared/connector-catalog.mjs +70 -52
  349. package/src/runtime/shared/custom-provider-keys.mjs +20 -0
  350. package/src/runtime/shared/file-has-data.mjs +26 -2
  351. package/src/runtime/shared/file-lock.mjs +21 -18
  352. package/src/runtime/shared/git-launch.d.mts +9 -0
  353. package/src/runtime/shared/git-launch.mjs +213 -0
  354. package/src/runtime/shared/git-runner-worker.mjs +2 -1
  355. package/src/runtime/shared/git-runner.mjs +7 -2
  356. package/src/runtime/shared/idle-gc.mjs +30 -7
  357. package/src/runtime/shared/llm/cost.mjs +6 -1
  358. package/src/runtime/shared/llm/http-agent.mjs +316 -29
  359. package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
  360. package/src/runtime/shared/llm/model-catalog.mjs +46 -6
  361. package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
  362. package/src/runtime/shared/llm/system-proxy.mjs +453 -0
  363. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  364. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  365. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  366. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  367. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  368. package/src/runtime/shared/process-runner.mjs +8 -4
  369. package/src/runtime/shared/provider-accounts.mjs +52 -2
  370. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  371. package/src/runtime/shared/routine-trigger.mjs +34 -0
  372. package/src/runtime/shared/run-child.d.mts +2 -1
  373. package/src/runtime/shared/run-child.mjs +70 -18
  374. package/src/runtime/shared/session-scratch.mjs +14 -2
  375. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  376. package/src/runtime/shared/staged-install-worker.mjs +5 -0
  377. package/src/runtime/shared/staged-update.mjs +47 -2
  378. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  379. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  380. package/src/runtime/shared/tool-surface.mjs +110 -36
  381. package/src/runtime/shared/tool-work-units.mjs +35 -6
  382. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  383. package/src/runtime/shared/turn-worktree-snapshot.mjs +409 -54
  384. package/src/runtime/shared/worker-requests.mjs +17 -3
  385. package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
  386. package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
  387. package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
  388. package/src/runtime/shared/worktrees/branch-management.mjs +5 -3
  389. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  390. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  391. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  392. package/src/runtime/shared/worktrees/git.mjs +97 -7
  393. package/src/runtime/shared/worktrees/include.mjs +6 -4
  394. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  395. package/src/runtime/shared/worktrees/manager.mjs +962 -197
  396. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  397. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  398. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  399. package/src/runtime/tidy/install.mjs +95 -15
  400. package/src/runtime/tidy/languages.mjs +17 -15
  401. package/src/runtime/tidy/process.mjs +9 -5
  402. package/src/runtime/tidy/resolve.mjs +19 -16
  403. package/src/runtime/tidy/runners/biome.mjs +3 -3
  404. package/src/runtime/tidy/tool.mjs +1 -1
  405. package/src/runtime/tidy/worktree.mjs +10 -6
  406. package/src/runtime/visualize-bridge/client.mjs +4 -1
  407. package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
  408. package/src/runtime/web-search/index.mjs +4 -23
  409. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  410. package/src/runtime/web-search/tool-defs.mjs +17 -26
  411. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  412. package/src/session-runtime/agent-task-sessions.mjs +410 -353
  413. package/src/session-runtime/boot/apis.mjs +27 -4
  414. package/src/session-runtime/boot/begin.mjs +2 -0
  415. package/src/session-runtime/boot/config.mjs +10 -1
  416. package/src/session-runtime/boot/facade.mjs +1 -0
  417. package/src/session-runtime/boot/providers.mjs +70 -3
  418. package/src/session-runtime/boot/session.mjs +2 -0
  419. package/src/session-runtime/boot/tools.mjs +71 -25
  420. package/src/session-runtime/bot-status.mjs +103 -103
  421. package/src/session-runtime/channel-config-api.mjs +1 -0
  422. package/src/session-runtime/config-change-effects.mjs +179 -0
  423. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  424. package/src/session-runtime/config-lifecycle.mjs +160 -24
  425. package/src/session-runtime/connector-merge-migration.mjs +18 -15
  426. package/src/session-runtime/conversation-import/discovery.mjs +245 -47
  427. package/src/session-runtime/conversation-import/service.mjs +12 -5
  428. package/src/session-runtime/goal-facade-api.mjs +49 -3
  429. package/src/session-runtime/handoff-attachments.mjs +1 -1
  430. package/src/session-runtime/held-requests.mjs +3 -1
  431. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  432. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  433. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -11
  434. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
  435. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +161 -120
  436. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  437. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  438. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  439. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  440. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  441. package/src/session-runtime/lifecycle/teardown/session-close.mjs +10 -5
  442. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  443. package/src/session-runtime/lifecycle-api.mjs +1 -0
  444. package/src/session-runtime/mcp-glue/server-catalog.mjs +27 -10
  445. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  446. package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
  447. package/src/session-runtime/mixy-heartbeat.mjs +1 -1
  448. package/src/session-runtime/model-route/set-route.mjs +40 -7
  449. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  450. package/src/session-runtime/provider-auth/login.mjs +2 -2
  451. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  452. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  453. package/src/session-runtime/provider-readiness.mjs +53 -4
  454. package/src/session-runtime/resource-api.mjs +1 -1
  455. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  456. package/src/session-runtime/resource-mcp-api.mjs +98 -35
  457. package/src/session-runtime/resource-mcp-connector-accounts.mjs +49 -32
  458. package/src/session-runtime/resource-mcp-secrets.mjs +27 -10
  459. package/src/session-runtime/resource-mcp-servers.mjs +5 -4
  460. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  461. package/src/session-runtime/routine-executor.mjs +152 -0
  462. package/src/session-runtime/routine-home-turn.mjs +46 -5
  463. package/src/session-runtime/runtime-facade.mjs +5 -0
  464. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  465. package/src/session-runtime/schedule-session-run.mjs +1 -0
  466. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  467. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  468. package/src/session-runtime/services/agent-tool/send-flow.mjs +120 -8
  469. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  470. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  471. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
  472. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +28 -7
  473. package/src/session-runtime/services/agent-tool.mjs +51 -1
  474. package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
  475. package/src/session-runtime/services/channel-admin.mjs +18 -0
  476. package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
  477. package/src/session-runtime/services/daemon-candidate.mjs +4 -1
  478. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  479. package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
  480. package/src/session-runtime/services/plugin-admin.mjs +14 -6
  481. package/src/session-runtime/services/provider-admin.mjs +281 -10
  482. package/src/session-runtime/services/seeds.mjs +7 -0
  483. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  484. package/src/session-runtime/session-create/materialize.mjs +4 -2
  485. package/src/session-runtime/session-create/session-options.mjs +2 -0
  486. package/src/session-runtime/session-turn-api.mjs +2 -0
  487. package/src/session-runtime/settings-builtin-tools-api.mjs +5 -10
  488. package/src/session-runtime/settings-system-api.mjs +1 -1
  489. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
  490. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
  491. package/src/session-runtime/setup-tool/executor.mjs +14 -3
  492. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  493. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  494. package/src/session-runtime/setup-tool/tool-defs.mjs +28 -2
  495. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  496. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  497. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  498. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  499. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  500. package/src/session-runtime/tool-surface.mjs +38 -1
  501. package/src/session-runtime/turn/agent-ops.mjs +33 -2
  502. package/src/session-runtime/turn/session-ops.mjs +2 -0
  503. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  504. package/src/session-runtime/turn/turn-run.mjs +1 -1
  505. package/src/session-runtime/webhook-session-run.mjs +2 -0
  506. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +46 -11
  507. package/src/session-runtime/workflow-agents-api/agent-route.mjs +2 -0
  508. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  509. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  510. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  511. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  512. package/src/session-runtime/workspace/activity-guards.mjs +176 -0
  513. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  514. package/src/session-runtime/workspace/session-view.mjs +149 -0
  515. package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
  516. package/src/session-runtime/workspace/transition-runner.mjs +188 -0
  517. package/src/session-runtime/workspace/transitions.mjs +128 -1070
  518. package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
  519. package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
  520. package/src/session-runtime/workspace/worktree-maintenance.mjs +200 -0
  521. package/src/session-runtime/workspace/worktree-setup.mjs +97 -0
  522. package/src/session-runtime/workspace/worktree-tool.mjs +70 -54
  523. package/src/standalone/daemon-agent-control.mjs +25 -8
  524. package/src/standalone/daemon-desktop-runtime.mjs +8 -2
  525. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  526. package/src/standalone/daemon-session-control.mjs +151 -136
  527. package/src/standalone/daemon.mjs +61 -2
  528. package/src/standalone/desktop-service-registry.mjs +9 -0
  529. package/src/standalone/local-session-runtime.mjs +21 -1
  530. package/src/standalone/session-client/daemon-unavailable.mjs +4 -1
  531. package/src/standalone/session-client.mjs +5 -1
  532. package/src/standalone/session-frame-stream.mjs +83 -11
  533. package/src/standalone/session-protocol.mjs +15 -0
  534. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  535. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  536. package/src/standalone/session-service/agent-tree.mjs +45 -9
  537. package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
  538. package/src/standalone/session-service/quota-resume.mjs +9 -0
  539. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  540. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  541. package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
  542. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  543. package/src/standalone/session-service/session-calls.mjs +2 -1
  544. package/src/standalone/session-service/stored-reader.mjs +127 -40
  545. package/src/tui/App.jsx +162 -164
  546. package/src/tui/app/app-view/floating-panel.jsx +3 -0
  547. package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
  548. package/src/tui/app/clipboard.mjs +22 -11
  549. package/src/tui/app/create-app-pickers.mjs +2 -0
  550. package/src/tui/app/doctor.mjs +2 -2
  551. package/src/tui/app/panel-signature.mjs +1 -1
  552. package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
  553. package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
  554. package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
  555. package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
  556. package/src/tui/app/provider-setup/oauth-actions.mjs +25 -6
  557. package/src/tui/app/provider-setup-picker.mjs +20 -13
  558. package/src/tui/app/settings-picker.mjs +53 -8
  559. package/src/tui/app/shell-layout/row-budgets.mjs +14 -12
  560. package/src/tui/app/slash-commands.mjs +2 -1
  561. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  562. package/src/tui/app/slash-dispatch/session-commands.mjs +47 -1
  563. package/src/tui/app/slash-dispatch.mjs +1 -1
  564. package/src/tui/app/use-btw-panel.mjs +29 -0
  565. package/src/tui/app/use-context-panel-refresh.mjs +31 -0
  566. package/src/tui/app/use-model-catalog-cache.mjs +13 -10
  567. package/src/tui/app/use-mouse-input.mjs +11 -0
  568. package/src/tui/app/use-onboarding-start.mjs +8 -3
  569. package/src/tui/app/use-panel-transition.mjs +10 -1
  570. package/src/tui/app/use-pasted-buffers.mjs +28 -20
  571. package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
  572. package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
  573. package/src/tui/app/use-prompt-queue-history.mjs +5 -4
  574. package/src/tui/app/use-selection-focus.mjs +11 -2
  575. package/src/tui/app/use-selection-geometry.mjs +18 -9
  576. package/src/tui/app/use-selection-paint.mjs +4 -4
  577. package/src/tui/app/use-selection-stitch.mjs +3 -3
  578. package/src/tui/app/use-slash-palette.mjs +62 -0
  579. package/src/tui/app/use-terminal-chrome.mjs +2 -2
  580. package/src/tui/app/use-transcript-activity.mjs +48 -33
  581. package/src/tui/app/use-transcript-follow.mjs +12 -4
  582. package/src/tui/app/use-transcript-scroll.mjs +46 -17
  583. package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
  584. package/src/tui/app/use-transcript-window/geometry.mjs +20 -6
  585. package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
  586. package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
  587. package/src/tui/app/use-transcript-window.mjs +21 -11
  588. package/src/tui/app/use-tui-ready.mjs +18 -0
  589. package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
  590. package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
  591. package/src/tui/components/Picker.jsx +27 -3
  592. package/src/tui/components/SignInUrl.jsx +68 -0
  593. package/src/tui/components/TextEntryPanel.jsx +76 -46
  594. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  595. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  596. package/src/tui/components/question-panel-model.mjs +4 -4
  597. package/src/tui/components/sign-in-url-layout.mjs +24 -0
  598. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  599. package/src/tui/components/user-message-skills.mjs +1 -1
  600. package/src/tui/dist/index.mjs +2205 -1371
  601. package/src/tui/markdown/render-ansi.mjs +1 -1
  602. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  603. package/src/tui/session/agent-job-feed.mjs +2 -0
  604. package/src/tui/session/context-state.mjs +3 -0
  605. package/src/tui/session/goal-turn-state.mjs +6 -2
  606. package/src/tui/session/quota-resume.mjs +1 -1
  607. package/src/tui/session/session-api/controls.mjs +4 -0
  608. package/src/tui/session/session-api/extensions.mjs +8 -0
  609. package/src/tui/session/session-api/intake/abort.mjs +2 -1
  610. package/src/tui/session/session-api/intake.mjs +2 -0
  611. package/src/tui/session/session-api/integrations.mjs +2 -2
  612. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  613. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  614. package/src/tui/session/session-api/routes-agent-definitions.mjs +6 -0
  615. package/src/tui/session/session-api/settings.mjs +2 -2
  616. package/src/tui/session/session-api/worktree.mjs +13 -1
  617. package/src/tui/session/session-flow/drain.mjs +11 -14
  618. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  619. package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
  620. package/src/tui/session/transcript-spill.mjs +92 -4
  621. package/src/tui/session/transcript-store.mjs +2 -0
  622. package/src/tui/session/turn-quiet.mjs +1 -1
  623. package/src/tui/session/turn.mjs +3 -0
  624. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  625. package/src/tui/spinner-meta.mjs +3 -3
  626. package/src/tui/spinner-verbs.mjs +2 -2
  627. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  628. package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
  629. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  630. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -1,20 +1,36 @@
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 new account
15
+ // given a removed one's name included (a remembered account is bound to its
16
+ // identity, not its name). A conversation's
17
+ // call (`_meta[CONVERSATION_META]`) makes its account the last used, for the
18
+ // conversation and the connector. Every result of a call made on an account,
19
+ // errors included, says which account answered. A name binds a call to one
20
+ // account; an address or label two accounts share binds none.
21
+ // An account that fails stays listed with why (connectorAccountHealth); the
22
+ // server only fails to start when no account can be used.
23
+ import { randomUUID } from 'node:crypto';
24
+ import { join } from 'node:path';
25
+ import { readJsonStateSync, updateJsonAtomicSync } from '../shared/atomic-file.mjs';
26
+ import { readSection, updateSection } from '../shared/config.mjs';
12
27
  import { accountsOfInstructions, connectorAccountsInstructions } from '../shared/connector-accounts.mjs';
13
- import { connectorById } from '../shared/connector-catalog.mjs';
14
- import { gmailAppPasswordTools } from './gmail-app-password.mjs';
15
- import { googleMcpTools } from './google-mcp.mjs';
28
+ import { connectorAccountsOf, connectorById, connectorOfServer } from '../shared/connector-catalog.mjs';
29
+ import { resolvePluginData } from '../shared/plugin-paths.mjs';
16
30
 
17
31
  const PROTOCOL_VERSION = '2025-06-18';
32
+ /** The `_meta` key of a tools/call that names the conversation it is made in. */
33
+ export const CONVERSATION_META = 'mixdog/conversation';
18
34
 
19
35
  const json = (status, body) =>
20
36
  new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });
@@ -36,66 +52,289 @@ export function forgetConnectorAccountHealth(name) {
36
52
  health.delete(name);
37
53
  }
38
54
 
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
- });
55
+ // ── The last-used account ───────────────────────────────────────────────────
56
+ // Per connector and per conversation, in the data dir (every runtime and every
57
+ // restart reads the same ones).
58
+ const ACCOUNTS_IN_USE_FILE = 'connector-accounts-in-use.json';
59
+ const inUseFile = () => join(resolvePluginData(), ACCOUNTS_IN_USE_FILE);
60
+ const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
61
+ const validInUse = (value) => {
62
+ if (!isRecord(value)) throw new Error('the accounts in use must be an object');
63
+ return value;
64
+ };
44
65
 
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
- },
66
+ // A remembered account is `{ name, id }`: the name it was called by and its
67
+ // identity (connector-catalog.mjs connectorAccountId: the random id stored
68
+ // with it). A name can be given to a new account once the old one is
69
+ // removed; the identity cannot, so it binds the choice to the account.
70
+ const readInUse = () => readJsonStateSync(inUseFile(), { validate: validInUse, fallback: {} });
71
+
72
+ // Set in the accounts-in-use file once its name-only records (from before
73
+ // identities) were bound to the accounts then under those names.
74
+ const IDS_MIGRATED = '#ids';
75
+
76
+ const hasId = (account) => typeof account?.id === 'string' && account.id !== '';
77
+ const missingIds = (servers) =>
78
+ Object.values(isRecord(servers) ? servers : {}).some((cfg) => connectorAccountsOf(cfg).some((one) => !hasId(one)));
79
+
80
+ /** Test seam: runs once the config lock that gave the ids is released, before
81
+ * the binding (where another process's write may land). */
82
+ export const accountIdsDeps = { afterIdsGiven: () => {} };
83
+
84
+ /** `servers` with a random id given to every connector account stored
85
+ * without one; null when every account has one. */
86
+ function withAccountIds(servers) {
87
+ if (!missingIds(servers)) return null;
88
+ return Object.fromEntries(
89
+ Object.entries(servers).map(([name, cfg]) => {
90
+ if (!connectorAccountsOf(cfg).some((one) => !hasId(one))) return [name, cfg];
91
+ const accounts = cfg.accounts.map((account) =>
92
+ isRecord(account) && !hasId(account) ? { ...account, id: randomUUID() } : account
93
+ );
94
+ return [name, { ...cfg, accounts }];
95
+ })
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Every stored connector account gets an identity, once, at every start and
101
+ * after a config change (an account written by hand has none). All under the
102
+ * accounts-in-use file's lock, so concurrent runs (processes, runtimes) and
103
+ * choices serialize: the config is changed only where an id is missing (an id
104
+ * once given is never replaced), and the first run also binds each name-only
105
+ * record (from before identities) to the account then under that name, which
106
+ * is where such a record routed until now, and marks that done. A name-only
107
+ * record found afterwards stays unbound (it fails closed). Records already
108
+ * holding an identity are never touched. True when it changed the config.
109
+ *
110
+ * The binding uses the accounts exactly as the ids were given or confirmed:
111
+ * the config is re-read nowhere after that, so an account replaced under the
112
+ * same name meanwhile (by another process) is never the one bound; it fails
113
+ * the identity check instead.
114
+ */
115
+ export function ensureConnectorAccountIds() {
116
+ let changed = false;
117
+ updateJsonAtomicSync(inUseFile(), (current) => {
118
+ const stored = isRecord(current) ? current : {};
119
+ // The stored servers whose ids the binding below uses.
120
+ let snapshot = readSection('agent')?.mcpServers;
121
+ if (missingIds(snapshot)) {
122
+ updateSection('agent', (agent) => {
123
+ const servers = withAccountIds(agent.mcpServers);
124
+ snapshot = servers ?? agent.mcpServers;
125
+ if (!servers) return agent;
126
+ changed = true;
127
+ return { ...agent, mcpServers: servers };
128
+ });
129
+ accountIdsDeps.afterIdsGiven();
130
+ }
131
+ if (stored[IDS_MIGRATED]) return undefined;
132
+ const servers = Object.values(isRecord(snapshot) ? snapshot : {});
133
+ const next = { ...stored, [IDS_MIGRATED]: true };
134
+ for (const [connector, name] of Object.entries(stored)) {
135
+ if (typeof name !== 'string' || !name) continue;
136
+ const cfg = servers.find((one) => connectorOfServer(one) === connector && connectorAccountsOf(one).length);
137
+ const account = cfg && connectorAccountsOf(cfg).find((one) => one.name === name);
138
+ if (hasId(account)) next[connector] = { name, id: account.id };
139
+ }
140
+ return next;
141
+ });
142
+ return changed;
143
+ }
144
+
145
+ /** The account catalog connector `connector` used last, null when none was
146
+ * recorded. A name-only record (from before identities, unbound) has an
147
+ * empty `id`. */
148
+ export function connectorAccountInUseRecord(connector) {
149
+ const value = readInUse()[connector];
150
+ if (typeof value === 'string') return value ? { name: value, id: '' } : null;
151
+ if (!isRecord(value) || typeof value.name !== 'string' || !value.name) return null;
152
+ return { name: value.name, id: typeof value.id === 'string' ? value.id : '' };
153
+ }
154
+
155
+ /** The name of the account catalog connector `connector` used last, '' when
156
+ * none was recorded. */
157
+ export function connectorAccountInUse(connector) {
158
+ return connectorAccountInUseRecord(connector)?.name || '';
159
+ }
160
+
161
+ function rememberAccountInUse(connector, account) {
162
+ const current = connectorAccountInUseRecord(connector);
163
+ if (current?.name === account.name && current.id === account.id) return;
164
+ updateJsonAtomicSync(inUseFile(), (stored) => ({
165
+ ...(isRecord(stored) ? stored : {}),
166
+ [connector]: { name: account.name, id: account.id },
61
167
  }));
62
168
  }
63
169
 
64
- class AccountChoiceError extends Error {}
170
+ // Per conversation, in the data dir too, so a conversation resumed after a
171
+ // restart keeps its own account: conversation (its session id) → { accounts:
172
+ // (connector → { name, id }) }. A binding lives as long as its session: it is
173
+ // dropped only when the session is deleted (forgetConversationConnectorAccounts,
174
+ // a session purge hook), never to make room, so no live conversation falls
175
+ // back to another conversation's choice.
176
+ const CONVERSATION_ACCOUNTS_FILE = 'connector-accounts-by-conversation.json';
177
+ const conversationsFile = () => join(resolvePluginData(), CONVERSATION_ACCOUNTS_FILE);
65
178
 
66
- const labelOf = (account) => account.email || account.name;
179
+ /** Drop the connector accounts conversation `conversation` used (its session
180
+ * was deleted). */
181
+ export function forgetConversationConnectorAccounts(conversation) {
182
+ const id = text(conversation);
183
+ if (!id || !Object.hasOwn(readJsonStateSync(conversationsFile(), { validate: validInUse, fallback: {} }), id)) return;
184
+ updateJsonAtomicSync(conversationsFile(), (stored) => {
185
+ const { [id]: _gone, ...rest } = isRecord(stored) ? stored : {};
186
+ return rest;
187
+ });
188
+ }
67
189
 
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;
190
+ /** The account conversation `conversation` used last on `connector`, or null. */
191
+ function conversationAccount(conversation, connector) {
192
+ const own = readJsonStateSync(conversationsFile(), { validate: validInUse, fallback: {} })[conversation];
193
+ const value = isRecord(own?.accounts) ? own.accounts[connector] : null;
194
+ if (!isRecord(value) || typeof value.name !== 'string' || !value.name) return null;
195
+ return { name: value.name, id: typeof value.id === 'string' ? value.id : '' };
196
+ }
197
+
198
+ function rememberConversationAccount(conversation, connector, account) {
199
+ const current = conversationAccount(conversation, connector);
200
+ if (current?.name === account.name && current.id === account.id) return;
201
+ updateJsonAtomicSync(conversationsFile(), (stored) => {
202
+ const all = isRecord(stored) ? stored : {};
203
+ const accounts = isRecord(all[conversation]?.accounts) ? all[conversation].accounts : {};
204
+ return {
205
+ ...all,
206
+ [conversation]: { accounts: { ...accounts, [connector]: { name: account.name, id: account.id } } },
207
+ };
208
+ });
209
+ }
210
+
211
+ const ACCOUNT_PROPERTY = Object.freeze({
212
+ type: 'string',
213
+ description: 'The account to use (its email address or account name). Left out: the account used last.',
214
+ });
215
+
216
+ /** `value` as JSON with every object's keys sorted, so equal schemas compare
217
+ * equal whatever order their keys were written in. */
218
+ const canonical = (value) => {
219
+ if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;
220
+ if (isRecord(value)) {
221
+ const keys = Object.keys(value)
222
+ .filter((key) => value[key] !== undefined)
223
+ .sort();
224
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(',')}}`;
79
225
  }
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
- );
226
+ return JSON.stringify(value) ?? 'null';
227
+ };
228
+
229
+ /** The tools every account lists, once each, with `account` added; a tool
230
+ * two accounts list with different schemas is left out. */
231
+ function unionTools(states) {
232
+ const first = new Map();
233
+ const differs = new Set();
234
+ for (const { tools = [] } of states) {
235
+ for (const tool of tools) {
236
+ const seen = first.get(tool.name);
237
+ if (!seen) first.set(tool.name, tool);
238
+ else if (canonical(seen.inputSchema) !== canonical(tool.inputSchema)) differs.add(tool.name);
239
+ }
240
+ }
241
+ return [...first.values()]
242
+ .filter((tool) => !differs.has(tool.name))
243
+ .map((tool) => ({
244
+ ...tool,
245
+ inputSchema: {
246
+ type: 'object',
247
+ ...tool.inputSchema,
248
+ properties: { ...(tool.inputSchema?.properties || {}), account: ACCOUNT_PROPERTY },
249
+ },
250
+ }));
84
251
  }
85
252
 
86
253
  const noteOf = (state) => (state.authRequired ? 'needs sign-in' : 'unavailable');
254
+ const usable = (account) => health.get(account.name)?.authRequired !== true;
255
+
256
+ /** `result` saying which account answered it (`label`). */
257
+ const withAccountNote = (result, service, label) => ({
258
+ ...result,
259
+ content: [
260
+ ...(Array.isArray(result?.content) ? result.content : []),
261
+ { type: 'text', text: `(${service} account: ${label})` },
262
+ ],
263
+ });
87
264
 
88
265
  /**
89
266
  * 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).
267
+ * `accounts` is `{ name, id, email, connect(signal), callTool(params, { signal, onprogress }) }`
268
+ * (`id`: its identity, connector-catalog.mjs connectorAccountId):
269
+ * `connect` resolves `{ instructions, tools }` of that account's own MCP
270
+ * connection, `callTool` sends it one tools/call (reporting its progress to
271
+ * `onprogress`, when given) and resolves the result; both
272
+ * throw when the account cannot be reached (an `authRequired` error when it
273
+ * needs a sign-in). The fetch carries `connectorAccounts`: `{ connector,
274
+ * choose({ tool, wanted, conversation }) }`, `{ name, label }` of the account
275
+ * such a call would use (it throws the refusal otherwise), for binding a call
276
+ * to its account (by its unique name) before it is approved.
94
277
  */
95
278
  export function withConnectorAccountsMcp({ connector, accounts }) {
96
279
  const service = connectorById(connector)?.name || connector;
97
- const listed = connectorTools(connector, accounts);
98
- const callable = connectorTools(connector, accounts, { hidden: true });
280
+ // account name → the names of the tools it lists (set once it answered).
281
+ const toolsOf = new Map();
282
+ let listed = [];
283
+ const same = (a, b) => Boolean(a) && a.toLowerCase() === b.toLowerCase();
284
+ /** What an account is called to the model: its address, with its name when
285
+ * another account shares that address. */
286
+ const labelOf = (account) => {
287
+ if (!account.email) return account.name;
288
+ const shared = accounts.some((other) => other !== account && same(other.email, account.email));
289
+ return shared ? `${account.email} (${account.name})` : account.email;
290
+ };
291
+ /** The account a call uses (see the header); throws the refusal. */
292
+ const choose = ({ tool, wanted, conversation }) => {
293
+ const refuse = (why) => {
294
+ const list = accounts.filter(usable).map(labelOf).join(', ') || 'none';
295
+ return new Error(`${why} Usable ${service} accounts: ${list}. Pass one as \`account\`.`);
296
+ };
297
+ const named = text(wanted);
298
+ let account;
299
+ if (named) {
300
+ // Its unique name, else the one account its address or label is.
301
+ let matches = accounts.filter((one) => same(one.name, named));
302
+ if (!matches.length) matches = accounts.filter((one) => same(one.email, named) || same(labelOf(one), named));
303
+ if (!matches.length) throw refuse(`No connected ${service} account is "${named}".`);
304
+ if (matches.length > 1) {
305
+ const names = matches.map((one) => one.name).join(', ');
306
+ throw refuse(`"${named}" is more than one ${service} account (${names}); name one.`);
307
+ }
308
+ [account] = matches;
309
+ } else {
310
+ const remembered =
311
+ (conversation && conversationAccount(conversation, connector)) || connectorAccountInUseRecord(connector);
312
+ if (remembered) {
313
+ account = accounts.find((one) => one.name === remembered.name);
314
+ // The name must still be the account it named: one removed and its
315
+ // name given to a new account, or a record without an identity (one
316
+ // ensureConnectorAccountIds did not bind, or an account picked before
317
+ // it had an id), fails closed until an account is picked again.
318
+ if (account && !remembered.id) {
319
+ throw refuse(
320
+ `The ${service} account used last (${remembered.name}) cannot be confirmed as the same account.`
321
+ );
322
+ }
323
+ if (account && account.id !== remembered.id) {
324
+ throw refuse(`The ${service} account used last (${remembered.name} (removed)) is not connected now.`);
325
+ }
326
+ if (!account) throw refuse(`The ${service} account used last (${remembered.name}) is not connected now.`);
327
+ } else {
328
+ account = accounts[0];
329
+ }
330
+ }
331
+ if (!usable(account)) throw refuse(`${labelOf(account)} needs a sign-in in Connectors.`);
332
+ const has = toolsOf.get(account.name);
333
+ if (has && !has.has(tool) && listed.some((one) => one.name === tool)) {
334
+ throw refuse(`${labelOf(account)} has no ${tool} tool.`);
335
+ }
336
+ return account;
337
+ };
99
338
  const record = (account, state) => {
100
339
  if (state.email) account.email = state.email;
101
340
  health.set(account.name, {
@@ -109,13 +348,13 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
109
348
  record(account, state);
110
349
  return state;
111
350
  };
112
- // Each account's own initialize: whether it can be used, and its address.
351
+ // Each account's own connection: whether it can be used, its address and tools.
113
352
  const probe = async (account, signal) => {
114
353
  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 };
354
+ const { instructions, tools } = await account.connect(signal);
355
+ toolsOf.set(account.name, new Set(tools.map((tool) => tool.name)));
356
+ const [email = ''] = accountsOfInstructions(instructions);
357
+ const state = { email: account.email || email, instructions, tools };
119
358
  record(account, state);
120
359
  return state;
121
360
  } catch (error) {
@@ -125,7 +364,9 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
125
364
  // The calls in flight by JSON-RPC id, so a `notifications/cancelled` for one
126
365
  // aborts its downstream request.
127
366
  const inflight = new Map();
128
- async function rpc(message, transportSignal) {
367
+ /** One JSON-RPC request's reply; `notify` sends a notification ahead of it
368
+ * (a tools/call's progress). */
369
+ async function rpc(message, transportSignal, notify = null) {
129
370
  const { id, method, params } = message || {};
130
371
  const reply = (result) => ({ jsonrpc: '2.0', id, result });
131
372
  if (method === 'initialize') {
@@ -138,55 +379,70 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
138
379
  error: { code: -32001, message: first?.error || `No ${service} account is connected` },
139
380
  };
140
381
  }
382
+ listed = unionTools(states);
383
+ // What the accounts' own servers tell the model (an in-process Google
384
+ // account's only names its address, which the account list says).
385
+ const own = [
386
+ ...new Set(
387
+ states.map((state) => text(state.instructions)).filter((one) => one && !accountsOfInstructions(one).length)
388
+ ),
389
+ ];
390
+ const accountsLine = connectorAccountsInstructions(
391
+ accounts.map((account, index) => ({
392
+ email: labelOf(account),
393
+ ...(states[index].error ? { note: noteOf(states[index]) } : {}),
394
+ }))
395
+ );
141
396
  return reply({
142
397
  protocolVersion: text(params?.protocolVersion) || PROTOCOL_VERSION,
143
398
  capabilities: { tools: { listChanged: false } },
144
399
  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
- ),
400
+ instructions: [accountsLine, ...own].filter(Boolean).join('\n\n') || undefined,
151
401
  });
152
402
  }
153
403
  if (method === 'ping') return reply({});
154
404
  if (method === 'tools/list') return reply({ tools: listed });
155
405
  if (method === 'tools/call') {
156
406
  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 || {};
407
+ const { account: wanted, ...args } = params?.arguments || {};
408
+ const conversation = text(params?._meta?.[CONVERSATION_META]);
161
409
  let account;
162
410
  try {
163
- account = pickAccount(accounts, chosen, service);
411
+ account = choose({ tool: name, wanted, conversation });
412
+ if (conversation) {
413
+ rememberConversationAccount(conversation, connector, account);
414
+ rememberAccountInUse(connector, account);
415
+ }
164
416
  } catch (error) {
165
- return reply(errorResult(error.message));
417
+ return reply(errorResult(error?.message || String(error)));
166
418
  }
167
419
  const cancel = new AbortController();
168
420
  const signal = transportSignal ? AbortSignal.any([transportSignal, cancel.signal]) : cancel.signal;
169
421
  inflight.set(id, cancel);
422
+ // The account's progress reaches the caller under the caller's own token,
423
+ // so it resets the call's deadline as a direct server's progress does.
424
+ const progressToken = params?._meta?.progressToken;
425
+ const onprogress =
426
+ notify && progressToken !== undefined
427
+ ? (progress) =>
428
+ notify({ jsonrpc: '2.0', method: 'notifications/progress', params: { ...progress, progressToken } })
429
+ : undefined;
170
430
  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}`));
431
+ // An unlisted tool (one only the approval gate calls) is the account's to answer.
432
+ const result = await account.callTool({ name, arguments: args }, { signal, onprogress });
176
433
  if (health.get(account.name)?.error) record(account, {});
177
- return reply(answer?.result ?? errorResult(`${labelOf(account)}: no answer`));
434
+ return reply(withAccountNote(result, service, labelOf(account)));
178
435
  } catch (error) {
179
436
  // 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}`));
437
+ const why = signal.aborted ? 'cancelled' : failure(account, error).error;
438
+ return reply(withAccountNote(errorResult(why), service, labelOf(account)));
183
439
  } finally {
184
440
  inflight.delete(id);
185
441
  }
186
442
  }
187
443
  return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } };
188
444
  }
189
- return async (input, init) => {
445
+ const fetchImpl = async (input, init) => {
190
446
  const request = input instanceof Request ? input : null;
191
447
  if (String(request?.method || init?.method || 'GET').toUpperCase() !== 'POST') {
192
448
  return new Response(null, { status: 405, headers: { allow: 'POST' } });
@@ -203,28 +459,41 @@ export function withConnectorAccountsMcp({ connector, accounts }) {
203
459
  for (const one of batch) {
204
460
  if (one?.method === 'notifications/cancelled') inflight.get(one.params?.requestId)?.abort();
205
461
  }
462
+ // A call asking for progress is answered as an event stream: its progress
463
+ // notifications, then its reply.
464
+ if (!Array.isArray(message) && message?.id !== undefined && message.params?._meta?.progressToken !== undefined) {
465
+ const encoder = new TextEncoder();
466
+ let open = true;
467
+ const stream = new ReadableStream({
468
+ start(controller) {
469
+ const send = (payload) => {
470
+ if (open) controller.enqueue(encoder.encode(`event: message\ndata: ${JSON.stringify(payload)}\n\n`));
471
+ };
472
+ void rpc(message, signal, send).then((answer) => {
473
+ send(answer);
474
+ if (open) controller.close();
475
+ open = false;
476
+ });
477
+ },
478
+ // The caller stopped reading (its call was aborted).
479
+ cancel() {
480
+ open = false;
481
+ },
482
+ });
483
+ return new Response(stream, { status: 200, headers: { 'content-type': 'text/event-stream' } });
484
+ }
206
485
  const replies = (await Promise.all(batch.map((one) => (one?.id === undefined ? null : rpc(one, signal))))).filter(
207
486
  Boolean
208
487
  );
209
488
  if (!replies.length) return new Response(null, { status: 202 });
210
489
  return json(200, Array.isArray(message) ? replies : replies[0]);
211
490
  };
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();
491
+ fetchImpl.connectorAccounts = {
492
+ connector,
493
+ choose: (call) => {
494
+ const account = choose(call);
495
+ return { name: account.name, label: labelOf(account) };
496
+ },
229
497
  };
498
+ return fetchImpl;
230
499
  }
@@ -7,7 +7,7 @@
7
7
  // for each call. The password is checked with Gmail before it is saved, and
8
8
  // never appears in a config, log, error or tool result.
9
9
  import { createHash } from 'node:crypto';
10
- import keychain from '../../lib/keychain-cjs.cjs';
10
+ import { keychainSecretStore as keychain } from '../shared/config.mjs';
11
11
  import { GMAIL_APP_PASSWORD, gmailAddress } from '../shared/connector-catalog.mjs';
12
12
  import { connectorAccountsInstructions } from '../shared/connector-accounts.mjs';
13
13
 
@@ -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
+ 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 ──────────────────────────────────
@@ -331,7 +331,7 @@ const SERVICES = {
331
331
 
332
332
  /** The tool definitions (name, description, schema, annotations) of built-in
333
333
  * Google service `service` (`gmail`, `calendar`, `drive`). */
334
- export function googleMcpTools(service) {
334
+ function googleMcpTools(service) {
335
335
  return (SERVICES[service]?.tools || []).map(({ run, ...tool }) => tool);
336
336
  }
337
337
 
@@ -83,7 +83,7 @@ function waitReady(ms) {
83
83
  });
84
84
  }
85
85
 
86
- export function effortJudgeModelDir() {
86
+ function effortJudgeModelDir() {
87
87
  return process.env.MIXDOG_EFFORT_JUDGE_DIR || join(resolvePluginData(), 'models', 'effort-judge');
88
88
  }
89
89
 
@@ -280,7 +280,7 @@ async function runInstall() {
280
280
  * background. Runs on the first judged turn of the process, never at runtime
281
281
  * creation, so booting touches no network.
282
282
  */
283
- export function refreshEffortJudge() {
283
+ function refreshEffortJudge() {
284
284
  if (!onnxRuntimeSupported()) return;
285
285
  installEffortJudge().catch((error) => {
286
286
  // An older complete install still works.
@@ -17,7 +17,7 @@ const HEX = /(?<![0-9A-Za-z])[0-9a-fA-F]{12,}(?![0-9A-Za-z])/g;
17
17
  const SPACES = /[ \t]+/g;
18
18
  const BLANK_LINES = /\n[ \t]*\n[\n \t]*/g;
19
19
 
20
- export function cleanJudgeText(text) {
20
+ function cleanJudgeText(text) {
21
21
  return String(text || '')
22
22
  .replace(/\r\n?/g, '\n')
23
23
  .replace(ANSI, '')
@@ -49,10 +49,10 @@ export function judgeInputClean(request, prev) {
49
49
  // continues), the previous reply's first line (its topic), then as much of the
50
50
  // reply's END (what a short approval answers) as remains. Training builds the
51
51
  // same id sequence (clean_text.pack_ids) with the identical tokenizer.
52
- export const PACK_BUDGET = Object.freeze({ request: 64, prevRequest: 24, replyHead: 16 });
52
+ const PACK_BUDGET = Object.freeze({ request: 64, prevRequest: 24, replyHead: 16 });
53
53
 
54
54
  /** Split the cleaned previous reply into its first line and the remaining text. */
55
- export function splitReply(reply) {
55
+ function splitReply(reply) {
56
56
  const at = reply.indexOf('\n');
57
57
  return at < 0 ? [reply, ''] : [reply.slice(0, at), reply.slice(at + 1)];
58
58
  }
@@ -63,7 +63,7 @@ export function splitReply(reply) {
63
63
  // A result keeps its start and end (where errors and summaries sit); the
64
64
  // stored window (2000 + 1000 code points) bounds the cleaning work on huge
65
65
  // outputs. Training builds the same text (clean_text.step_judge_text).
66
- export const STEP_CALLS = 3;
66
+ const STEP_CALLS = 3;
67
67
 
68
68
  export function stepResultWindow(text) {
69
69
  const cps = Array.from(String(text ?? ''));