mixdog 1.3.5 → 1.4.1

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 (515) hide show
  1. package/NOTICE.md +2 -2
  2. package/README.md +2 -2
  3. package/package.json +2 -11
  4. package/scripts/check-voice-runtime-inputs.mjs +25 -0
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/gate-local.mjs +16 -5
  7. package/scripts/latest-guard.mjs +21 -9
  8. package/scripts/lib/isolated-test-env.mjs +10 -5
  9. package/scripts/lib/run-node-tests.mjs +37 -37
  10. package/scripts/lib/scoped-temp.d.mts +16 -0
  11. package/scripts/lib/scoped-temp.mjs +123 -0
  12. package/scripts/lib/stale-temp.mjs +44 -0
  13. package/scripts/native-release-status.mjs +2 -2
  14. package/scripts/post-release-check.mjs +1 -6
  15. package/scripts/pptx-kit-index.mjs +17 -4
  16. package/scripts/recall-history-cases.json +1 -1
  17. package/scripts/suite-health.mjs +20 -2
  18. package/scripts/test-data-dir.mjs +10 -7
  19. package/scripts/test.mjs +7 -11
  20. package/src/agents/reviewer/AGENT.md +7 -11
  21. package/src/agents/reviewer/agent.json +1 -1
  22. package/src/app.mjs +4 -0
  23. package/src/defaults/shipped-history.json +22 -1
  24. package/src/defaults/skills/browser-use/SKILL.md +62 -12
  25. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  26. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  27. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  28. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  29. package/src/defaults/skills/computer-use/SKILL.md +35 -9
  30. package/src/defaults/skills/setup/SKILL.md +22 -0
  31. package/src/defaults/skills/setup/references/actions.md +39 -5
  32. package/src/defaults/skills/setup/references/surfaces.md +11 -2
  33. package/src/defaults/skills/visualize/SKILL.md +2 -1
  34. package/src/lib/rules-builder.cjs +39 -20
  35. package/src/output-styles/common.md +2 -2
  36. package/src/output-styles/simple.md +1 -1
  37. package/src/rules/agent/AGENT.md +11 -10
  38. package/src/rules/lead/LEAD.md +23 -20
  39. package/src/rules/shared/05-tool-calls.md +5 -6
  40. package/src/rules/shared/10-tool-workflow.md +4 -0
  41. package/src/rules/shared/45-destructive.md +0 -2
  42. package/src/rules/shared/50-execution.md +2 -0
  43. package/src/rules/shared/60-verification.md +7 -5
  44. package/src/rules/shared/70-delivery.md +7 -9
  45. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
  46. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  47. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  48. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  49. package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
  50. package/src/runtime/agent/orchestrator/config.mjs +17 -1
  51. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  52. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
  53. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
  54. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  55. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
  56. package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
  57. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
  58. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
  59. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
  60. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
  63. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
  66. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  67. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
  70. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
  71. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  72. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
  73. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
  74. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  75. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
  76. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  77. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
  78. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  79. package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
  82. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
  83. package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
  84. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
  85. package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
  87. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  88. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  89. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
  90. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  91. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  92. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  93. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
  106. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
  107. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
  109. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  113. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
  115. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
  116. package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
  117. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  118. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  119. package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
  120. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  121. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  122. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
  127. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
  128. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
  131. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
  132. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
  133. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
  134. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
  135. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
  136. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
  137. package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
  138. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
  139. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  140. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  141. package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
  142. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
  143. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
  144. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
  145. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
  146. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
  147. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
  148. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
  149. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
  150. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  151. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
  153. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
  154. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
  155. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
  157. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
  158. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
  159. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
  162. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  163. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  164. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
  165. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  166. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
  167. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  168. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
  172. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  173. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  174. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
  175. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  176. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  177. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
  178. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
  179. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  181. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
  182. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
  183. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
  185. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  187. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
  188. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
  189. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  191. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
  192. package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
  193. package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
  203. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
  207. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
  208. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
  209. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
  214. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  216. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  217. package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
  218. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
  225. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
  226. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
  227. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
  228. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
  229. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
  230. package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
  231. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
  232. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
  233. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
  234. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
  235. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
  236. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
  237. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  238. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
  239. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
  240. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  241. package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
  242. package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
  243. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  244. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  245. package/src/runtime/browser-bridge/client.mjs +73 -8
  246. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  247. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  248. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  249. package/src/runtime/channels/lib/config.mjs +6 -61
  250. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  251. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  252. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  253. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  254. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  255. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  256. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  257. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  258. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  259. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  260. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  261. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  262. package/src/runtime/channels/lib/scheduler.mjs +33 -147
  263. package/src/runtime/channels/lib/schedules-db.mjs +34 -11
  264. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  265. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
  266. package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
  267. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  268. package/src/runtime/channels/lib/whisper-port.mjs +10 -1
  269. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  270. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  271. package/src/runtime/channels/lib/worker-main.mjs +10 -34
  272. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  273. package/src/runtime/computer-bridge/actions.mjs +9 -1
  274. package/src/runtime/computer-bridge/client.mjs +180 -8
  275. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  276. package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
  277. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
  278. package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
  279. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  280. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  281. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  282. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  283. package/src/runtime/connectors/google-mcp.mjs +10 -12
  284. package/src/runtime/local-provider/server-process.mjs +2 -1
  285. package/src/runtime/media/adapters/gemini-video.mjs +4 -1
  286. package/src/runtime/media/adapters/xai-media.mjs +2 -1
  287. package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
  288. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
  289. package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
  290. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  291. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  292. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  293. package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
  294. package/src/runtime/office/design/design-art-direction.mjs +29 -27
  295. package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
  296. package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
  297. package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
  298. package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
  299. package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
  300. package/src/runtime/office/quality/design-review.mjs +1 -5
  301. package/src/runtime/office/quality/document-brief.mjs +1 -5
  302. package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
  303. package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
  304. package/src/runtime/session-search/session-search-db.mjs +73 -9
  305. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  306. package/src/runtime/shared/abort-race.mjs +89 -0
  307. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  308. package/src/runtime/shared/agent-kind.mjs +4 -3
  309. package/src/runtime/shared/bot-owned-work.mjs +56 -0
  310. package/src/runtime/shared/bounded-download.mjs +8 -3
  311. package/src/runtime/shared/config.mjs +2 -13
  312. package/src/runtime/shared/connector-accounts.mjs +20 -10
  313. package/src/runtime/shared/connector-catalog.d.mts +29 -0
  314. package/src/runtime/shared/connector-catalog.mjs +150 -0
  315. package/src/runtime/shared/connector-triggers.mjs +22 -19
  316. package/src/runtime/shared/defaults-separation.mjs +2 -17
  317. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  318. package/src/runtime/shared/err-text.mjs +24 -15
  319. package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
  320. package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
  321. package/src/runtime/shared/file-permissions.d.mts +0 -8
  322. package/src/runtime/shared/file-permissions.mjs +0 -11
  323. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  324. package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
  325. package/src/runtime/shared/handoff-artifacts.mjs +18 -8
  326. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  327. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  328. package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
  329. package/src/runtime/shared/llm/cost.mjs +5 -1
  330. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  331. package/src/runtime/shared/loopback-listener.mjs +25 -2
  332. package/src/runtime/shared/mixy-presence.mjs +22 -0
  333. package/src/runtime/shared/model-route-chain.d.mts +7 -2
  334. package/src/runtime/shared/model-route-chain.mjs +22 -4
  335. package/src/runtime/shared/open-url.mjs +10 -0
  336. package/src/runtime/shared/orchestration.d.mts +2 -0
  337. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  338. package/src/runtime/shared/profile-config.cjs +1 -1
  339. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  340. package/src/runtime/shared/prompt-origin.mjs +21 -0
  341. package/src/runtime/shared/provider-accounts.mjs +7 -1
  342. package/src/runtime/shared/provider-display-name.mjs +29 -0
  343. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  344. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  345. package/src/runtime/shared/routine-trigger.mjs +10 -0
  346. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  347. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  348. package/src/runtime/shared/session-activity-signal.mjs +48 -1
  349. package/src/runtime/shared/session-scratch.mjs +37 -0
  350. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  351. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  352. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  353. package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
  354. package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
  355. package/src/runtime/shared/tool-result-summary.mjs +2 -15
  356. package/src/runtime/shared/tool-surface.mjs +3 -0
  357. package/src/runtime/shared/tool-work-units.mjs +2 -0
  358. package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
  359. package/src/runtime/shared/worktrees/contract.mjs +4 -1
  360. package/src/runtime/shared/worktrees/git.mjs +15 -0
  361. package/src/runtime/shared/worktrees/manager.mjs +87 -38
  362. package/src/runtime/shared/worktrees/test-support.mjs +14 -13
  363. package/src/runtime/terminal-bridge/client.mjs +10 -1
  364. package/src/runtime/visualize-bridge/client.mjs +29 -8
  365. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  366. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  367. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  368. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  369. package/src/session-runtime/agent-home-delivery.mjs +489 -185
  370. package/src/session-runtime/agent-task-sessions.mjs +467 -229
  371. package/src/session-runtime/agent-tool-routing.mjs +8 -41
  372. package/src/session-runtime/boot/apis.mjs +9 -0
  373. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  374. package/src/session-runtime/boot/providers.mjs +3 -0
  375. package/src/session-runtime/boot/tools.mjs +11 -2
  376. package/src/session-runtime/bot-status.mjs +12 -6
  377. package/src/session-runtime/bot-target.mjs +38 -0
  378. package/src/session-runtime/channel-config-api.mjs +6 -1
  379. package/src/session-runtime/config-lifecycle.mjs +6 -0
  380. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  381. package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
  382. package/src/session-runtime/conversation-import/discovery.mjs +271 -25
  383. package/src/session-runtime/conversation-import/service.mjs +26 -5
  384. package/src/session-runtime/handoff-attachments.mjs +82 -31
  385. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
  386. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
  387. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
  388. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
  389. package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
  390. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  391. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
  392. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  393. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  394. package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
  395. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  396. package/src/session-runtime/mixy-heartbeat.mjs +153 -33
  397. package/src/session-runtime/model-route/set-route.mjs +11 -2
  398. package/src/session-runtime/notification-bus.mjs +31 -117
  399. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  400. package/src/session-runtime/notification-listeners.mjs +76 -0
  401. package/src/session-runtime/owned-automation-run.mjs +2 -1
  402. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  403. package/src/session-runtime/provider-catalog-cache.mjs +82 -36
  404. package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
  405. package/src/session-runtime/provider-models.mjs +4 -2
  406. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  407. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  408. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  409. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  410. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  411. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  412. package/src/session-runtime/resource-recall-api.mjs +6 -1
  413. package/src/session-runtime/routine-owner.mjs +40 -9
  414. package/src/session-runtime/runtime-feature-gates.mjs +5 -1
  415. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  416. package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
  417. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
  418. package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
  419. package/src/session-runtime/services/agent-tool/render.mjs +71 -17
  420. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  422. package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
  423. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  424. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  425. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  426. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  427. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  428. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  429. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  430. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  431. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  432. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  433. package/src/session-runtime/services/channel-admin.mjs +7 -13
  434. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  435. package/src/session-runtime/services/provider-admin.mjs +2 -1
  436. package/src/session-runtime/services/seeds.mjs +0 -28
  437. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  438. package/src/session-runtime/session-create/session-options.mjs +1 -0
  439. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  440. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  441. package/src/session-runtime/settings-system-api.mjs +13 -1
  442. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  443. package/src/session-runtime/setup-tool/executor.mjs +145 -22
  444. package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
  445. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  446. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
  447. package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
  448. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  449. package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
  450. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  451. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
  452. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
  453. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
  454. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  455. package/src/session-runtime/workspace/transitions.mjs +25 -0
  456. package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
  457. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  458. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  459. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  460. package/src/standalone/channel-transport.mjs +1 -1
  461. package/src/standalone/daemon-channels-loader.mjs +10 -8
  462. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  463. package/src/standalone/daemon-session-control/request.mjs +51 -0
  464. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  465. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  466. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  467. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  468. package/src/standalone/daemon-session-control.mjs +142 -190
  469. package/src/standalone/daemon.mjs +26 -3
  470. package/src/standalone/session-client.mjs +7 -3
  471. package/src/standalone/session-protocol.mjs +5 -0
  472. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  473. package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
  474. package/src/standalone/session-service/quota-resume.mjs +3 -0
  475. package/src/standalone/session-service/retention/busy.mjs +65 -1
  476. package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
  477. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  478. package/src/standalone/session-tool-output.mjs +15 -7
  479. package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
  480. package/src/tui/app/app-view/floating-panel.jsx +7 -4
  481. package/src/tui/app/model-options.mjs +3 -28
  482. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
  483. package/src/tui/app/model-picker/route-selection.mjs +5 -6
  484. package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
  485. package/src/tui/app/provider-setup/provider-items.mjs +8 -2
  486. package/src/tui/app/provider-setup-picker.mjs +9 -5
  487. package/src/tui/components/QuestionPanel.jsx +13 -4
  488. package/src/tui/dist/index.mjs +133 -92
  489. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  490. package/src/tui/session/initial-state.mjs +3 -0
  491. package/src/tui/session/notice-surface.mjs +7 -1
  492. package/src/tui/session/queue-helpers.mjs +3 -42
  493. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  494. package/src/tui/session/session-api/routes-write.mjs +5 -1
  495. package/src/tui/session/session-api/routes.mjs +1 -0
  496. package/src/tui/session/session-api/settings.mjs +17 -1
  497. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  498. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  499. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  500. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  501. package/src/tui/session/session-flow/drain.mjs +118 -149
  502. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  503. package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
  504. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  505. package/src/tui/session/tool-approval-request.mjs +39 -0
  506. package/src/tui/session/tool-approval-settle.mjs +62 -0
  507. package/src/tui/session/tool-approval.mjs +69 -115
  508. package/src/tui/session/tui-steering-persist.mjs +8 -1
  509. package/src/tui/session/turn-stream.mjs +19 -2
  510. package/src/tui/session/turn.mjs +1 -0
  511. package/src/ui/statusline-agents.mjs +1 -3
  512. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  513. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  514. package/scripts/code-graph-description-contract.mjs +0 -188
  515. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -0,0 +1,217 @@
1
+ // MCP OAuth sign-in and sign-out of a configured server or of one account of a
2
+ // multi-account connector server: the interactive login flows
3
+ // (mcp-oauth-login.mjs), the transactional account switch, and the
4
+ // credential-free auth probe.
5
+ import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
6
+ import { createMcpOAuthLogins } from './mcp-oauth-login.mjs';
7
+ import { connectorAccountServers, connectorAccountsOf } from '../runtime/shared/connector-catalog.mjs';
8
+ import { forgetConnectorAccountHealth } from '../runtime/connectors/connector-accounts-mcp.mjs';
9
+ import { accountTarget } from './resource-mcp-servers.mjs';
10
+
11
+ export function createMcpOAuthApi({
12
+ sync,
13
+ mcpStatus,
14
+ connectConfiguredMcp,
15
+ clearMcpServerOAuth,
16
+ reloadFullConfig,
17
+ awaitKeychainPrewarm,
18
+ resolveMcpCatalog,
19
+ cancelMcpLogin,
20
+ completeMcpLogin,
21
+ getMcpServerOAuthState,
22
+ probeMcpServerAuth,
23
+ startMcpServerOAuthSwitch,
24
+ commitMcpServerOAuthSwitch,
25
+ }) {
26
+ const reconnectOne = async (name) => {
27
+ const status = await connectConfiguredMcp({ only: name, enabled: true });
28
+ const row = status?.servers?.find((server) => server.name === name);
29
+ return { connected: row?.connected === true, error: row?.error || null };
30
+ };
31
+ // Explicit OAuth sign-in: the one interactive MCP connect. On success the
32
+ // other runtimes reconnect the server non-interactively with the new tokens.
33
+ const oauthLogins = createMcpOAuthLogins({
34
+ async connect(name, openBrowser) {
35
+ const status = await connectConfiguredMcp({ only: name, enabled: true, login: { openBrowser } });
36
+ const row = status?.servers?.find((server) => server.name === name);
37
+ return { connected: row?.connected === true, error: row?.error || null };
38
+ },
39
+ cancel: (name) => cancelMcpLogin(name),
40
+ completeCallback: completeMcpLogin,
41
+ // 계정 바꾸기, transactionally: the working connection stays until the new
42
+ // sign-in succeeded and connects; a cancel or failure changes nothing, and
43
+ // a new sign-in that cannot connect is rolled back.
44
+ // An account of a multi-account connector signs in the same way, any
45
+ // mode: beside its stored sign-in (if any), then its server reconnects.
46
+ async switchAccount(name, launch, attempt) {
47
+ const servers = resolveMcpCatalog().servers;
48
+ const target = accountTarget(servers, name);
49
+ const cfg = target ? target.accountCfg : servers[name];
50
+ const serverName = target ? target.serverName : name;
51
+ // 연결 / 다시 인증 of a signed-in account: its stored sign-in (refreshed
52
+ // as needed) is tried first; the browser opens only when that fails.
53
+ if (target && launch.accountMode !== 'switch' && getMcpServerOAuthState(cfg)?.signedIn === true) {
54
+ const repaired = await reconnectOne(serverName);
55
+ if (repaired.connected && !connectorAccountError(name)) return repaired;
56
+ }
57
+ const switching = startMcpServerOAuthSwitch(cfg, launch, name);
58
+ attempt.abort = () => switching.cancel();
59
+ attempt.answer = (callbackUrl) => switching.answer(callbackUrl);
60
+ const signIn = await switching.done;
61
+ // The same account twice would leave `account` ambiguous.
62
+ const address = String(signIn?.identity?.account || '').toLowerCase();
63
+ if (target && address) {
64
+ const twin = connectorAccountServers(target.cfg).find(
65
+ (other) =>
66
+ other.name !== name && String(getMcpServerOAuthState(other)?.account || '').toLowerCase() === address
67
+ );
68
+ if (twin) return { connected: false, error: `${signIn.identity.account} is already connected` };
69
+ }
70
+ const rollback = await commitMcpServerOAuthSwitch(cfg, signIn);
71
+ const outcome = await reconnectOne(serverName);
72
+ const accountError = target ? connectorAccountError(name) : '';
73
+ if (outcome.connected && !accountError) return outcome;
74
+ await rollback();
75
+ await reconnectOne(serverName);
76
+ return { connected: false, error: accountError || outcome.error || 'The new sign-in could not connect' };
77
+ },
78
+ onComplete: (name) =>
79
+ sync.announce('mcp', {
80
+ detail: {
81
+ mcpChanges: [{ name: accountTarget(resolveMcpCatalog().servers, name)?.serverName || name, enabled: true }],
82
+ },
83
+ }),
84
+ });
85
+ /** The effective config of a server that signs in with MCP OAuth (HTTP/SSE
86
+ * without configured authentication). */
87
+ const oauthServerConfig = async (name) => {
88
+ const serverName = clean(name);
89
+ if (!serverName) throw new Error('MCP server name is required');
90
+ await awaitKeychainPrewarm();
91
+ reloadFullConfig();
92
+ const cfg = resolveMcpCatalog().servers[serverName];
93
+ if (!cfg) throw new Error(`MCP server not configured: ${serverName}`);
94
+ if (!getMcpServerOAuthState(cfg)) throw new Error(`MCP server "${serverName}" does not use OAuth sign-in`);
95
+ return { serverName, cfg };
96
+ };
97
+
98
+ /** The sign-in account `name` addresses on a multi-account connector
99
+ * server — an account's name, or the server's name when it has exactly one
100
+ * sign-in account (`every`: all of them, for a sign-out) — as
101
+ * `{ serverName, cfg, account, accountCfg, signOut: [accountCfg…] }`;
102
+ * null for any other server. */
103
+ const signInAccount = async (name, { every = false } = {}) => {
104
+ const wanted = clean(name);
105
+ if (!wanted) throw new Error('MCP server name is required');
106
+ await awaitKeychainPrewarm();
107
+ reloadFullConfig();
108
+ const servers = resolveMcpCatalog().servers;
109
+ const target = accountTarget(servers, wanted);
110
+ if (target) {
111
+ if (!getMcpServerOAuthState(target.accountCfg)) {
112
+ throw new Error(`MCP server "${wanted}" does not use OAuth sign-in`);
113
+ }
114
+ return { ...target, signOut: [target.accountCfg] };
115
+ }
116
+ const cfg = servers[wanted];
117
+ if (!connectorAccountsOf(cfg).length) return null;
118
+ const signIns = connectorAccountServers(cfg).filter((accountCfg) => getMcpServerOAuthState(accountCfg));
119
+ if (every && signIns.length) return { serverName: wanted, cfg, account: null, accountCfg: null, signOut: signIns };
120
+ if (signIns.length === 1) {
121
+ const account = connectorAccountsOf(cfg).find((entry) => entry.name === signIns[0].name);
122
+ return { serverName: wanted, cfg, account, accountCfg: signIns[0], signOut: signIns };
123
+ }
124
+ throw new Error(
125
+ signIns.length
126
+ ? `MCP server "${wanted}" has several accounts; name the account to sign in`
127
+ : `MCP server "${wanted}" does not use OAuth sign-in`
128
+ );
129
+ };
130
+
131
+ /** What account `name` of a multi-account connector currently fails with ('' when fine). */
132
+ function connectorAccountError(name) {
133
+ for (const row of mcpStatus()?.servers || []) {
134
+ const account = (Array.isArray(row.accounts) ? row.accounts : []).find((entry) => entry.name === name);
135
+ if (account) return account.error || (account.authRequired ? 'Sign-in required' : '');
136
+ }
137
+ return '';
138
+ }
139
+
140
+ return {
141
+ /** `{ flowId, state: 'pending', url }` once the browser login starts
142
+ * (`options.openBrowser === false` leaves opening `url` to the caller), or
143
+ * `{ flowId, state: 'complete' }` when stored credentials sufficed. */
144
+ async beginMcpOAuthLogin(name, options = {}) {
145
+ const account = await signInAccount(name);
146
+ if (account) {
147
+ if (account.cfg.enabled === false) throw new Error(`MCP server is disabled: ${account.serverName}`);
148
+ // Beside the stored sign-in, whatever the mode: the account's server keeps running meanwhile.
149
+ return oauthLogins.begin(account.account.name, { ...(options || {}), beside: true });
150
+ }
151
+ const { beside: _beside, ...ownOptions } = options || {};
152
+ options = ownOptions;
153
+ const { serverName, cfg } = await oauthServerConfig(name);
154
+ if (cfg.enabled === false) throw new Error(`MCP server is disabled: ${serverName}`);
155
+ // `mode`: `connect` (a normal authorization), `reauth` (repair the same
156
+ // connection; a refresh is tried first) or `switch` (계정 바꾸기).
157
+ if (options?.mode === 'switch' && !getMcpServerOAuthState(cfg)?.signedIn) {
158
+ throw new Error(`MCP server "${serverName}" is not signed in`);
159
+ }
160
+ return oauthLogins.begin(serverName, options);
161
+ },
162
+ /** `{ flowId, state: 'pending' | 'complete' | 'failed' | 'cancelled',
163
+ * step?, error?, reason? }`; with `{ since, waitMs }` it resolves on the
164
+ * flow's next change (mcp-oauth-login.mjs). */
165
+ getMcpOAuthLoginStatus(flowId, options) {
166
+ return oauthLogins.status(flowId, options);
167
+ },
168
+ cancelMcpOAuthLogin(flowId) {
169
+ return oauthLogins.cancel(flowId);
170
+ },
171
+ /** Remote / headless sign-in: complete the pending flow with the redirect
172
+ * URL pasted from the browser. `{ flowId, state: 'complete' | 'failed',
173
+ * error? }`; an invalid paste throws a fixed message and stays pending. */
174
+ completeMcpOAuthLogin(flowId, callbackUrl) {
175
+ return oauthLogins.complete(flowId, callbackUrl);
176
+ },
177
+ /** Forget the server's stored OAuth credentials (shared by every server
178
+ * with the same exact URL) and reconnect without a login, here and on
179
+ * peers, so it reports sign-in required. */
180
+ async signOutMcpServer(name) {
181
+ const account = await signInAccount(name, { every: true });
182
+ if (account) {
183
+ const accountName = account.account?.name || clean(name);
184
+ return oauthLogins.cancelServer(accountName, async () => {
185
+ let revoked = true;
186
+ for (const accountCfg of account.signOut) {
187
+ forgetConnectorAccountHealth(accountCfg.name);
188
+ revoked = (await clearMcpServerOAuth(accountCfg, { revoke: true }))?.revoked === true && revoked;
189
+ }
190
+ const status = await sync.reconnectMcpAndAnnounce({
191
+ only: account.serverName,
192
+ enabled: account.cfg.enabled !== false,
193
+ });
194
+ return { ...status, revoked };
195
+ });
196
+ }
197
+ const { serverName, cfg } = await oauthServerConfig(name);
198
+ // A begin issued meanwhile waits until the credentials are gone.
199
+ return oauthLogins.cancelServer(serverName, async () => {
200
+ const { revoked = false } = (await clearMcpServerOAuth(cfg, { revoke: true })) || {};
201
+ const status = await sync.reconnectMcpAndAnnounce({ only: serverName, enabled: cfg.enabled !== false });
202
+ return { ...status, revoked };
203
+ });
204
+ },
205
+ /** `{ auth: 'oauth' | 'none' | 'configured' | 'unreachable', error? }` for an
206
+ * HTTP/SSE config, without credentials or a browser. */
207
+ probeMcpServerAuth(cfg) {
208
+ if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) throw new TypeError('MCP server config is required');
209
+ const probe = {};
210
+ for (const key of ['type', 'url', 'headers', 'bearer_token_env_var', 'env_http_headers']) {
211
+ if (cfg[key] !== undefined) probe[key] = cfg[key];
212
+ }
213
+ if (probe.type !== 'http' && probe.type !== 'sse') throw new TypeError("type must be 'http' or 'sse'");
214
+ return probeMcpServerAuth(probe);
215
+ },
216
+ };
217
+ }
@@ -0,0 +1,82 @@
1
+ // The keychain side of MCP server edits: storing a server's OAuth client
2
+ // secret or Gmail app password, and releasing a removed server's or account's
3
+ // sign-in once no other configured server shares it.
4
+ import {
5
+ gmailAppPasswordAccount,
6
+ gmailAppPasswordValue,
7
+ connectorAccountServers,
8
+ } from '../runtime/shared/connector-catalog.mjs';
9
+ import { forgetConnectorAccountHealth } from '../runtime/connectors/connector-accounts-mcp.mjs';
10
+ import { oauthUrlOf } from './resource-mcp-servers.mjs';
11
+
12
+ /** Every config `servers` connects with, a multi-account server's accounts
13
+ * as the one-account configs they are. */
14
+ const expandedConfigs = (servers) =>
15
+ Object.values(servers || {}).flatMap((cfg) => {
16
+ const accounts = connectorAccountServers(cfg);
17
+ return accounts.length ? accounts : [cfg];
18
+ });
19
+
20
+ export function createMcpServerSecrets({
21
+ gmailAppPassword,
22
+ saveOAuthClientSecret,
23
+ clearMcpServerOAuth,
24
+ resolveConfiguredMcpCatalog,
25
+ }) {
26
+ // The user's OAuth client secret (custom connector → 고급 설정 → 비밀값)
27
+ // goes to the keychain only; clearing the client id forgets it.
28
+ const storeOAuthClientSecret = async (input, cfg, previous = {}) => {
29
+ if (!cfg?.url) return;
30
+ const secret = typeof input.oauthClientSecret === 'string' ? input.oauthClientSecret.trim() : '';
31
+ if (cfg.oauthClientId && secret) await saveOAuthClientSecret(cfg.url, secret);
32
+ else if (!cfg.oauthClientId && previous.oauthClientId) await saveOAuthClientSecret(previous.url || cfg.url, '');
33
+ };
34
+ // Gmail with an app password (connector-catalog.mjs GMAIL_APP_PASSWORD): the
35
+ // password is checked with Gmail before anything is saved and goes to the
36
+ // keychain only. A new connection needs one; an edit without one keeps it.
37
+ const storeGmailAppPassword = async (input, cfg, required) => {
38
+ const account = gmailAppPasswordAccount(cfg);
39
+ if (!account) return;
40
+ const password = gmailAppPasswordValue(input.appPassword);
41
+ if (password) await gmailAppPassword.save(account, password);
42
+ else if (required || input.appPassword !== undefined) {
43
+ throw new Error('GMAIL_APP_PASSWORD_FORMAT: An app password has 16 characters.');
44
+ }
45
+ };
46
+ // A server's OAuth tokens and client registration go with it, unless another
47
+ // configured server (plugin or disabled ones included, even with MCP
48
+ // disabled for this runtime) still uses them through the same exact URL.
49
+ // `signIn` tells the caller what happened to the sign-in: `removed` (local
50
+ // secrets deleted, `revoked` when the provider confirmed the revocation
51
+ // too), `shared` (another server still uses it), or none (null).
52
+ const releaseOAuth = async (cfg) => {
53
+ const url = oauthUrlOf(cfg);
54
+ if (!url) return null;
55
+ if (expandedConfigs(resolveConfiguredMcpCatalog().servers).some((other) => oauthUrlOf(other) === url)) {
56
+ return { signIn: 'shared', revoked: false };
57
+ }
58
+ const { revoked = false } = (await clearMcpServerOAuth(cfg, { revoke: true })) || {};
59
+ return { signIn: 'removed', revoked };
60
+ };
61
+ // An app password is deleted once no configured server uses its account.
62
+ const forgetUnusedGmailAppPassword = async (account) => {
63
+ if (!account) return false;
64
+ const servers = expandedConfigs(resolveConfiguredMcpCatalog().servers);
65
+ if (servers.some((cfg) => gmailAppPasswordAccount(cfg) === account)) return false;
66
+ await gmailAppPassword.forget(account);
67
+ return true;
68
+ };
69
+ // A removed account keeps no sign-in another configured server or account
70
+ // does not share: `{ signIn, revoked }` as removeMcpServer reports it.
71
+ const releaseAccount = async (accountCfg) => {
72
+ forgetConnectorAccountHealth(accountCfg.name);
73
+ const address = gmailAppPasswordAccount(accountCfg);
74
+ if (address) {
75
+ const forgotten = await forgetUnusedGmailAppPassword(address);
76
+ return { signIn: forgotten ? 'removed' : 'shared', revoked: false };
77
+ }
78
+ return releaseOAuth(accountCfg);
79
+ };
80
+
81
+ return { storeOAuthClientSecret, storeGmailAppPassword, releaseOAuth, forgetUnusedGmailAppPassword, releaseAccount };
82
+ }
@@ -0,0 +1,78 @@
1
+ // Pure reads of an `mcpServers` map shared by the MCP server API units
2
+ // (resource-mcp-api.mjs): OAuth URLs, multi-account connector account lookup,
3
+ // name refusals and the merge of a partial server edit.
4
+ import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
5
+ import { MCP_TIMEOUT_FIELD_GROUPS } from '../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
6
+ import { resolveMcpOAuthUrl } from '../runtime/agent/orchestrator/mcp/client-config.mjs';
7
+ import {
8
+ connectorAccountServer,
9
+ connectorAccountsOf,
10
+ connectorById,
11
+ connectorOfServer,
12
+ } from '../runtime/shared/connector-catalog.mjs';
13
+
14
+ /** The URL a server's OAuth credentials are stored under, or null. */
15
+ export function oauthUrlOf(cfg) {
16
+ try {
17
+ return resolveMcpOAuthUrl(cfg);
18
+ } catch {
19
+ // No valid remote URL: such a server never logged in.
20
+ return null;
21
+ }
22
+ }
23
+
24
+ /** The `mcpServers` map of a config as a fresh object (never the live one). */
25
+ export function mcpServersOf(config) {
26
+ return config.mcpServers && typeof config.mcpServers === 'object' ? { ...config.mcpServers } : {};
27
+ }
28
+
29
+ /** The multi-account connector account `name` names in `servers`:
30
+ * `{ serverName, cfg, account, accountCfg }`, or null. */
31
+ export function accountTarget(servers, name) {
32
+ for (const [serverName, cfg] of Object.entries(servers || {})) {
33
+ const account = connectorAccountsOf(cfg).find((entry) => entry.name === name);
34
+ if (account) return { serverName, cfg, account, accountCfg: connectorAccountServer(cfg, account) };
35
+ }
36
+ return null;
37
+ }
38
+
39
+ /** The refusal of a new server name that is taken. A name a connector account
40
+ * holds is an account to the user (never a server), so it says so. */
41
+ export function nameTakenError(servers, name) {
42
+ const holder = accountTarget(servers, name);
43
+ const connector = holder && connectorById(connectorOfServer(holder.cfg));
44
+ return new Error(
45
+ connector
46
+ ? `The name "${name}" is used by a ${connector.name} account. Choose another name.`
47
+ : `MCP server already exists: ${name}`
48
+ );
49
+ }
50
+
51
+ const transportType = (type) => (type === 'streamable-http' ? 'http' : type);
52
+
53
+ /** UI editors send complete transports; setup may send a partial patch. Merge
54
+ * the patch over the existing entry, keeping omitted fields (including
55
+ * credentials) unless the transport itself changed. */
56
+ export function mergedServerInput(input, existing, originalName) {
57
+ const transportChanged =
58
+ (input.type && transportType(input.type) !== transportType(existing.type || (existing.url ? 'http' : 'stdio'))) ||
59
+ (input.command && existing.url) ||
60
+ (input.url && !existing.url);
61
+ const maps = {};
62
+ if (!transportChanged) {
63
+ for (const key of ['env', 'headers', 'env_http_headers']) {
64
+ if (Object.hasOwn(input, key)) maps[key] = { ...(existing[key] || {}), ...input[key] };
65
+ }
66
+ }
67
+ // Existing timeouts are kept by mergeMcpServerConfig; the normalizer must only
68
+ // see (and validate) newly supplied ones, so a stored 0/'off' never blocks
69
+ // an unrelated save.
70
+ const { ...base } = transportChanged ? {} : existing;
71
+ for (const field of MCP_TIMEOUT_FIELD_GROUPS.flat()) delete base[field];
72
+ return {
73
+ ...base,
74
+ ...input,
75
+ ...maps,
76
+ name: clean(input.name) || originalName,
77
+ };
78
+ }
@@ -0,0 +1,49 @@
1
+ // The user's `mcpServers` as the MCP server API reads and writes it: every
2
+ // read already merged (one server per multi-account connector) and with
3
+ // adoptable plugin copies adopted; every write persisted with collision names
4
+ // pinned. Also the free-name and plugin-ownership checks over that registry.
5
+ import { withAdoptedCopies, withPinnedCollisionNames } from './mcp-glue/plugin-servers.mjs';
6
+ import { connectorAccountsOf, mergeConnectorAccountServers } from '../runtime/shared/connector-catalog.mjs';
7
+ import { mcpServersOf } from './resource-mcp-servers.mjs';
8
+
9
+ function pluginOwnedError(name, owner) {
10
+ return new Error(
11
+ `MCP server "${name}" is provided by plugin "${owner.id}" (server "${owner.key}"); ` +
12
+ 'enable or disable it with set_mcp_enabled, or manage the plugin instead'
13
+ );
14
+ }
15
+
16
+ export function createMcpServerStore({ getConfig, saveConfigAndAdopt, resolveMcpCatalog, pluginMcpServer }) {
17
+ /** The config with any adoptable plugin server copies already adopted, so
18
+ * every write also persists the adoption and never re-adds a copy. */
19
+ const adoptedConfig = () => withAdoptedCopies(getConfig(), resolveMcpCatalog().adoption);
20
+
21
+ /** Persist a new `mcpServers` map; project overrides never survive a global
22
+ * edit. A plugin server pushed off its name by the edit keeps the collision
23
+ * name it gets, so it does not flip again later. */
24
+ const saveServers = (servers) => {
25
+ const nextConfig = { ...adoptedConfig() };
26
+ delete nextConfig.mcpProjectOverrides;
27
+ saveConfigAndAdopt({ ...nextConfig, mcpServers: servers });
28
+ const saved = getConfig();
29
+ const pinned = withPinnedCollisionNames(saved, resolveMcpCatalog());
30
+ if (pinned !== saved) saveConfigAndAdopt(pinned);
31
+ };
32
+ // Every write starts from the merged form: one server per multi-account connector.
33
+ const userServers = () => mergeConnectorAccountServers(mcpServersOf(adoptedConfig())).servers;
34
+ /** A name no server, plugin server or account has yet: `base`, else `base-2`… */
35
+ const freeName = (servers, base) => {
36
+ const taken = new Set(
37
+ Object.entries(servers).flatMap(([name, cfg]) => [name, ...connectorAccountsOf(cfg).map((a) => a.name)])
38
+ );
39
+ const free = (name) => !taken.has(name) && !pluginMcpServer(name);
40
+ if (free(base)) return base;
41
+ for (let n = 2; ; n += 1) if (free(`${base}-${n}`)) return `${base}-${n}`;
42
+ };
43
+ const refusePluginServer = (name) => {
44
+ const owned = name ? pluginMcpServer(name) : null;
45
+ if (owned) throw pluginOwnedError(name, owned.owner);
46
+ };
47
+
48
+ return { adoptedConfig, saveServers, userServers, freeName, refusePluginServer };
49
+ }
@@ -1,6 +1,11 @@
1
1
  // Memory control and recall: the current session's own rows first, then the
2
2
  // memory runtime (with a forced ingest of the live session when it is empty).
3
- import { clean, toolResponseText, isEmptyRecallText, currentSessionRecallRows } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
3
+ import {
4
+ clean,
5
+ toolResponseText,
6
+ isEmptyRecallText,
7
+ currentSessionRecallRows,
8
+ } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
4
9
 
5
10
  function isIdentityRecallQuery(query) {
6
11
  const q = clean(query).toLowerCase().replace(/\s+/g, '');
@@ -6,6 +6,7 @@
6
6
  * and a new routine cannot name it.
7
7
  */
8
8
  import { MIXY_AGENT_ID } from '../runtime/agent/orchestrator/session/agent-home.mjs';
9
+ import { mixyExists } from '../runtime/shared/mixy-presence.mjs';
9
10
  import { scheduleOwnerAgentId } from './agent-home-delivery.mjs';
10
11
 
11
12
  /** `ownerProblem` codes and the error each one raises. */
@@ -15,7 +16,7 @@ export const ROUTINE_OWNER_PROBLEMS = Object.freeze({
15
16
  });
16
17
 
17
18
  let editor = null;
18
- async function defaultProbe() {
19
+ async function editorApi() {
19
20
  if (!editor) {
20
21
  const [{ getPluginData }, { createAgentEditorApi }] = await Promise.all([
21
22
  import('../runtime/agent/orchestrator/config.mjs'),
@@ -23,21 +24,51 @@ async function defaultProbe() {
23
24
  ]);
24
25
  editor = createAgentEditorApi({ cfgMod: { getPluginData } });
25
26
  }
27
+ return editor;
28
+ }
29
+
30
+ /** Whether a stored schedule or webhook belongs to Mixy (ownerless rows do).
31
+ * Without a PostgreSQL cluster none exists, and none is started for this. */
32
+ export async function mixyOwnsRoutines() {
33
+ const [{ pgClusterExists }, { resolvePluginData }] = await Promise.all([
34
+ import('../runtime/memory/lib/pg/adapter.mjs'),
35
+ import('../runtime/shared/plugin-paths.mjs'),
36
+ ]);
37
+ if (!pgClusterExists(resolvePluginData())) return false;
38
+ const [{ listSchedules }, { listEndpoints }] = await Promise.all([
39
+ import('../runtime/channels/lib/schedules-db.mjs'),
40
+ import('../runtime/channels/lib/webhooks-db.mjs'),
41
+ ]);
42
+ const [schedules, webhooks] = await Promise.all([listSchedules(), listEndpoints()]);
43
+ return [...schedules, ...webhooks].some((row) => scheduleOwnerAgentId(row) === MIXY_AGENT_ID);
44
+ }
45
+
46
+ /** Whether Mixy exists (mixy-presence.mjs, the one rule), from `status`
47
+ * (getLeadStatus) or a fresh read of it. `ownsRoutine`: the caller holds a
48
+ * stored routine of hers, so her routines need no read. Rejects when they
49
+ * cannot be read and nothing else decides. */
50
+ export async function readMixyExists(status = null, { ownsRoutine = false } = {}) {
51
+ return mixyExists(status ?? (await editorApi()).getLeadStatus(), ownsRoutine ? async () => true : mixyOwnsRoutines);
52
+ }
53
+
54
+ async function defaultProbe() {
55
+ const api = await editorApi();
26
56
  return {
27
- // An undecided profile (null) counts as having Mixy: nobody is blocked by
28
- // a flag the host has not written yet.
29
- mixyExists: () => editor.getLeadStatus().created !== false,
30
- presence: (agentId) => editor.agentDefinitionPresence([agentId])[agentId],
57
+ mixyExists: (ownsRoutine) => readMixyExists(null, { ownsRoutine }),
58
+ presence: (agentId) => api.agentDefinitionPresence([agentId])[agentId],
31
59
  };
32
60
  }
33
61
 
34
62
  /** Why `ownerAgentId` (none = Mixy) cannot own or run a routine: a
35
- * ROUTINE_OWNER_PROBLEMS code, '' when it can. Only a proven deletion
36
- * counts for a bot; a read fault never pauses anything. */
37
- export async function routineOwnerProblem(ownerAgentId, probe = null) {
63
+ * ROUTINE_OWNER_PROBLEMS code, '' when it can. `stored`: asked for a stored
64
+ * routine of that owner (a run, a list row). A routine Mixy owns is itself
65
+ * evidence of her, so only `created: false` pauses one; a new one needs her
66
+ * to exist. Only a proven deletion counts for a bot; a read fault never
67
+ * pauses anything (callers take a rejection as no problem). */
68
+ export async function routineOwnerProblem(ownerAgentId, probe = null, { stored = false } = {}) {
38
69
  const owner = scheduleOwnerAgentId({ ownerAgentId });
39
70
  const check = probe || (await defaultProbe());
40
- if (owner === MIXY_AGENT_ID) return check.mixyExists() ? '' : 'no-mixy';
71
+ if (owner === MIXY_AGENT_ID) return (await check.mixyExists(stored)) ? '' : 'no-mixy';
41
72
  return check.presence(owner) === 'deleted' ? 'owner-deleted' : '';
42
73
  }
43
74
 
@@ -4,7 +4,11 @@
4
4
  //
5
5
  // Key names mirror the dependency names of settings-api.mjs / the session-build
6
6
  // deps, so the runtime can hand them straight through.
7
- import { builtinFeatureActive, featureDisallowedToolsFor, localGitToolsActive } from '../runtime/agent/orchestrator/runtime-core/builtin-features.mjs';
7
+ import {
8
+ builtinFeatureActive,
9
+ featureDisallowedToolsFor,
10
+ localGitToolsActive,
11
+ } from '../runtime/agent/orchestrator/runtime-core/builtin-features.mjs';
8
12
  import { recapEnabled } from '../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
9
13
  import { browserBridgeAvailableSync } from '../runtime/browser-bridge/client.mjs';
10
14
  import { computerBridgeAvailableSync } from '../runtime/computer-bridge/client.mjs';
@@ -92,6 +92,9 @@ export function createCloseFlow({ mgr, registry, views }) {
92
92
  for (const descendantSessionId of descendantSessionIds) {
93
93
  registry.removeWorkerRow({ sessionId: descendantSessionId });
94
94
  }
95
+ // The sessions stay open (a send reuses them), so a later scan, even
96
+ // after a restart, would list them again: remember the owner closed them.
97
+ registry.markReleased([sessionId, ...descendantSessionIds]);
95
98
  }
96
99
  return { closed: ok, tag, sessionId, task_id: task?.taskId || null };
97
100
  }
@@ -66,15 +66,20 @@ export function createAgentExecute({
66
66
  });
67
67
  }
68
68
  // Targetless status is the same compact overview as list.
69
- return renderResult({
70
- // Idle workers stay open for follow-ups; the model must see them to close them.
71
- workers: views.list({
72
- scanSessions: registry.wantsSessionScan(args),
73
- context: scopedContext,
74
- includeIdle: true,
75
- }),
76
- jobs: views.listJobs(scopedContext),
77
- });
69
+ return renderResult(
70
+ {
71
+ // Idle workers stay open for follow-ups; the roster counts them and
72
+ // lists a bounded tail (or the `tag` matches) so they can be closed.
73
+ workers: views.list({
74
+ scanSessions: registry.wantsSessionScan(args),
75
+ context: scopedContext,
76
+ includeIdle: true,
77
+ includeClosed: true,
78
+ }),
79
+ jobs: views.listJobs(scopedContext),
80
+ },
81
+ { listFilter: clean(args.tag) }
82
+ );
78
83
  case 'read':
79
84
  return await readJob(args, scopedContext);
80
85
  case 'cleanup':
@@ -27,8 +27,12 @@ export function isActiveWorkerRow(row = {}) {
27
27
 
28
28
  // A finished worker that is still open: it takes follow-ups and can be closed.
29
29
  function isOpenIdleRow(row = {}) {
30
- const status = String(row.status ?? '').trim().toLowerCase();
31
- const stage = String(row.stage ?? '').trim().toLowerCase();
30
+ const status = String(row.status ?? '')
31
+ .trim()
32
+ .toLowerCase();
33
+ const stage = String(row.stage ?? '')
34
+ .trim()
35
+ .toLowerCase();
32
36
  if (CANCELLED_WORKER_STATUS.test(stage) || CANCELLED_WORKER_STATUS.test(status)) return false;
33
37
  return (status || stage) === 'idle';
34
38
  }
@@ -86,7 +90,13 @@ function agentRow({ tag, session, runtime, progress, now, indexRow = null }) {
86
90
  }
87
91
 
88
92
  export function createAgentList({ mgr, refreshTagsFromSessions, agentSessionEntries, progress }) {
89
- return function list({ scanSessions = false, context = {}, includeTerminal = false, includeIdle = false } = {}) {
93
+ return function list({
94
+ scanSessions = false,
95
+ context = {},
96
+ includeTerminal = false,
97
+ includeIdle = false,
98
+ includeClosed = false,
99
+ } = {}) {
90
100
  refreshTagsFromSessions({ scanSessions, context });
91
101
  const now = Date.now();
92
102
  const rows = [];
@@ -98,7 +108,13 @@ export function createAgentList({ mgr, refreshTagsFromSessions, agentSessionEntr
98
108
  // 2 s) would otherwise read every worker it ever ran, whole transcripts
99
109
  // on first sight, synchronously on the daemon loop.
100
110
  const state = rowState(session, runtime);
101
- if (!includeTerminal && !isActiveWorkerRow(state) && !(includeIdle && isOpenIdleRow(state))) continue;
111
+ if (
112
+ !includeTerminal &&
113
+ !isActiveWorkerRow(state) &&
114
+ !(includeIdle && isOpenIdleRow(state)) &&
115
+ !(includeClosed && state.status === 'closed')
116
+ )
117
+ continue;
102
118
  rows.push(
103
119
  agentRow({
104
120
  tag,