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
@@ -5,55 +5,22 @@
5
5
  */
6
6
 
7
7
  import { clean } from '../runtime/shared/clean.mjs';
8
-
9
- const lower = (value) => clean(value).toLowerCase();
10
-
11
- // A pinned model named by its catalog display name ("GPT-6.1-Sol") is not a
12
- // wire id. Canonicalize it only on an unambiguous EXACT match: the id itself,
13
- // or a display name / label, case-insensitively, within the requested provider
14
- // (or across providers when none is given and exactly one row matches).
15
- // Anything else — no match, several matches, an empty or partial catalog —
16
- // returns the args unchanged: the catalog never refuses a model and never
17
- // substitutes a near one.
18
- export function canonicalizePinnedModel(args, rows) {
19
- const model = clean(args?.model);
20
- if (!model || !Array.isArray(rows)) return args;
21
- const provider = lower(args.provider);
22
- const pool = rows.filter((row) => row && (!provider || lower(row.provider) === provider));
23
- const wanted = model.toLowerCase();
24
- const exactId = pool.filter((row) => row.id === model);
25
- // A partial catalog may lack the real id a display name collides with, so
26
- // only an exact id can pass there; aliases wait for a complete catalog.
27
- const partial = pool.some((row) => row.catalogPartial === true);
28
- const hits = exactId.length
29
- ? exactId
30
- : partial
31
- ? []
32
- : pool.filter((row) => lower(row.id) === wanted || lower(row.display) === wanted || lower(row.label) === wanted);
33
- const distinct = [...new Map(hits.map((row) => [`${row.provider}\n${row.id}`, row])).values()];
34
- if (distinct.length !== 1) return args;
35
- const [hit] = distinct;
36
- if (hit.id === model && hit.provider === args.provider) return args;
37
- return { ...args, provider: hit.provider, model: hit.id };
38
- }
8
+ import { resolveRequestedModel } from './services/agent-tool/model-select.mjs';
39
9
 
40
10
  // `listProviderModels` is this runtime's provider catalog. The agent control
41
11
  // behind `executeAgentControl` (the daemon's canonical agent) has none, so a
42
- // display-name model is canonicalized here before it is forwarded. Only the
43
- // cached/quick catalog is read, so a spawn never waits on provider listings.
12
+ // pinned model is resolved here, by the same rule the in-process agent tool
13
+ // applies (exact id, display name, then every query word; ambiguous or
14
+ // unknown names fail with candidates), and forwarded as the exact route.
44
15
  export function createRoutedAgentTool({ rt, agentTool, executeAgentControl = null, listProviderModels = null }) {
45
16
  const routedAgentTool = {
46
17
  ...agentTool,
47
18
  async execute(args, context = {}) {
48
19
  if (typeof executeAgentControl !== 'function') return agentTool.execute(args, context);
49
- let routedArgs = args;
50
- if (typeof listProviderModels === 'function' && clean(args?.model) && (clean(args.type) || 'spawn') === 'spawn') {
51
- try {
52
- routedArgs = canonicalizePinnedModel(args, await listProviderModels({ quick: true }));
53
- } catch {
54
- routedArgs = args;
55
- }
56
- }
20
+ const routedArgs =
21
+ typeof listProviderModels === 'function' && clean(args?.model) && (clean(args.type) || 'spawn') === 'spawn'
22
+ ? await resolveRequestedModel(args, listProviderModels)
23
+ : args;
57
24
  return executeAgentControl(routedArgs, context);
58
25
  },
59
26
  closeAll(reason, scope = {}) {
@@ -107,8 +107,17 @@ export function wireApis(boot) {
107
107
  try {
108
108
  boot.resourceApi.migratePluginMcpCopies();
109
109
  } catch (error) {
110
+ console.warn(`[mcp] adopting plugin MCP copies failed: ${error?.message || error}`);
110
111
  bootProfile('plugin-mcp:adopt-failed', { error: error?.message || String(error) });
111
112
  }
113
+ // One server per multi-account connector: `gmail`, `gmail-2`… merge into
114
+ // `gmail` holding the accounts (their sign-ins and app passwords stay).
115
+ try {
116
+ boot.resourceApi.migrateConnectorAccounts();
117
+ } catch (error) {
118
+ console.warn(`[connectors] merging connector accounts failed: ${error?.message || error}`);
119
+ bootProfile('connector-accounts:merge-failed', { error: error?.message || String(error) });
120
+ }
112
121
  }
113
122
  boot.disposeGlobalExtensionSubscription = () => {
114
123
  boot.disposeConfigSync?.();
@@ -20,6 +20,7 @@ import { listProjectsStrict } from '../../runtime/shared/projects.mjs';
20
20
  import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
21
21
  import { standaloneDataDir } from '../runtime-paths.mjs';
22
22
  import { SessionAddressError, isAdmissionOpen, ownerLifecycle } from '../session-address.mjs';
23
+ import { syncSessionCompaction, usesInjectedConfig } from '../session-compaction-sync.mjs';
23
24
  import { dataDirOf } from './shared.mjs';
24
25
 
25
26
  export function wireInfrastructure(boot) {
@@ -187,6 +188,9 @@ export function sessionAdopter(boot) {
187
188
  }
188
189
  }
189
190
  rt.session = v;
191
+ // A resumed or swapped-in session keeps the compaction it was saved with
192
+ // unless it follows the current global settings (not on an injected config).
193
+ if (v?.id && !usesInjectedConfig(boot.params)) syncSessionCompaction(v, rt.config);
190
194
  // The PreToolUse/PostToolUse bridge is a non-enumerable property that
191
195
  // neither the store nor a resumed record carries: every session installed
192
196
  // here (create, resume, route swap, clear, the manager's copy) gets it, so
@@ -31,6 +31,7 @@ import {
31
31
  } from '../model-recency.mjs';
32
32
  import { createNativeWebSearch } from '../native-web-search.mjs';
33
33
  import { createConfigLifecycle } from '../config-lifecycle.mjs';
34
+ import { usesInjectedConfig } from '../session-compaction-sync.mjs';
34
35
  import { createQuickModelRows } from '../quick-model-rows.mjs';
35
36
  import { createProviderModels } from '../provider-models.mjs';
36
37
  import { createProviderUsage } from '../provider-usage.mjs';
@@ -66,6 +67,8 @@ function wireConfigLifecycle(boot) {
66
67
  rt.configHasSecrets = next;
67
68
  },
68
69
  getRoute: () => rt.route,
70
+ getSession: () => rt.session,
71
+ fixedSessionCompaction: usesInjectedConfig(boot.params),
69
72
  setRouteState: (next) => {
70
73
  rt.route = next;
71
74
  },
@@ -9,6 +9,7 @@ import {
9
9
  channelNotificationSessionId,
10
10
  } from '../../runtime/shared/channel-notification-routing.mjs';
11
11
  import { CHANNEL_NOTIFICATION_METHOD } from '../services/channel-session-router.mjs';
12
+ import { PROMPT_ORIGIN_CHANNEL } from '../../runtime/agent/orchestrator/session/manager/pending-message-entry.mjs';
12
13
  import { envFlag } from '../../runtime/shared/env.mjs';
13
14
  // Desktop-app bridges: tiny fs/fetch clients, so a static import adds no
14
15
  // meaningful boot cost. The tools themselves are gated per session by the
@@ -21,7 +22,10 @@ import { TOOL_DEFS as OFFICE_TOOL_DEFS } from '../../runtime/office/tool-defs.mj
21
22
  import { TOOL_DEFS as MEDIA_TOOL_DEFS } from '../../runtime/media/tool-defs.mjs';
22
23
  import { TOOL_DEFS as TIDY_TOOL_DEFS } from '../../runtime/tidy/tool-defs.mjs';
23
24
  import { TOOL_DEFS as VISUALIZE_BRIDGE_TOOL_DEFS } from '../../runtime/visualize-bridge/tool-defs.mjs';
24
- import { ASK_USER_TOOL_DEFS } from '../../runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs';
25
+ import {
26
+ ASK_USER_TOOL_DEFS,
27
+ HANDOFF_USER_TOOL_DEFS,
28
+ } from '../../runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs';
25
29
  import { REACTION_TOOL_DEFS } from '../../runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs';
26
30
  import { SETUP_TOOL_DEFS } from '../setup-tool/tool-defs.mjs';
27
31
  import { createSetupToolExecutor } from '../setup-tool/executor.mjs';
@@ -144,7 +148,9 @@ function wireChannels(boot) {
144
148
  const meta = p.meta && typeof p.meta === 'object' ? p.meta : {};
145
149
  const content = channelNotificationModelContent(p);
146
150
  if (!content) return;
147
- notifySession(channelNotificationSessionId(rt.session, rt.reservedSessionId), content, meta);
151
+ notifySession(channelNotificationSessionId(rt.session, rt.reservedSessionId), content, meta, {
152
+ origin: PROMPT_ORIGIN_CHANNEL,
153
+ });
148
154
  },
149
155
  });
150
156
  bootProfile('channels:worker-ready', { ms: (performance.now() - channelsStartedAt).toFixed(1) });
@@ -168,6 +174,7 @@ function wireToolSurface(boot) {
168
174
  visualizeToolDefs: VISUALIZE_BRIDGE_TOOL_DEFS,
169
175
  setupToolDefs: SETUP_TOOL_DEFS,
170
176
  askUserToolDefs: ASK_USER_TOOL_DEFS,
177
+ handoffUserToolDefs: HANDOFF_USER_TOOL_DEFS,
171
178
  reactionToolDefs: REACTION_TOOL_DEFS,
172
179
  goalTools: goalRuntime.tools,
173
180
  agentTools: agentTool.tools,
@@ -234,6 +241,8 @@ function wireInternalTools(boot) {
234
241
  getCallerSession: (sessionId) =>
235
242
  sessionId === rt.session?.id ? rt.session : boot.mgr?.getSession?.(sessionId) || null,
236
243
  flushSettings: () => boot.flushAllConfigSavesAsync({ requireSaved: true }),
244
+ // Another session's route and quota actions (daemon-session-control.mjs); null without a daemon.
245
+ executeSessionControl: boot.params.executeSessionControl || null,
237
246
  });
238
247
  const disposeInternalTools = internalTools.setInternalToolsProvider({
239
248
  scopeId: rt.mcpScopeId,
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * `session bots`: the state of the user's bots, read on demand (never injected
3
3
  * into a turn). One line per bot: its home chat (`sess_home_<id>`), the last
4
- * activity there and its latest line, whether it works now (its chat, or a
5
- * task session it runs), approvals waiting on the user, its routines and what
4
+ * activity there and its latest line, whether it works now (its chat, or work
5
+ * it sent running in a task session; a turn the user typed there is the
6
+ * user's), approvals waiting on the user, its routines and what
6
7
  * needs attention. With one bot (`session_id`: its id or chat id): its
7
8
  * routines, its held requests and its recent sessions.
8
9
  *
@@ -143,7 +144,7 @@ function span(ms) {
143
144
  const ago = (at, now) => `${span(now - at)} ago`;
144
145
  const until = (at, now) => (at <= now ? 'due now' : `in ${span(at - now)}`);
145
146
 
146
- async function defaultListBots() {
147
+ export async function defaultListBots() {
147
148
  const [{ workflowHelpers }, { getPluginData, loadConfig }, { isAgentDisabled, isContactAgentId }] = await Promise.all(
148
149
  [
149
150
  import('./boot/shared.mjs'),
@@ -264,7 +265,12 @@ export function createBotStatus({
264
265
  const homeId = agentHomeSessionId(bot.id);
265
266
  const owned = ctx.owned.get(bot.id) || [];
266
267
  const home = ctx.rows.get(homeId) || null;
267
- // Running task sessions: a turn whose report is still owed, or one working now.
268
+ // Work this bot sent that is running now: a session working with the bot's
269
+ // send in flight (`handedBy`, bot-owned-work.mjs). A turn the user typed
270
+ // in the bot's task session is the user's, not the bot working.
271
+ const sentWork = (row) => isWorking(row) && row.handedBy?.includes(bot.id) === true;
272
+ // Running task sessions: a turn whose report is still owed, or the bot's
273
+ // work running now.
268
274
  const tasks = new Map();
269
275
  const addTask = (id, title, at) => {
270
276
  const known = tasks.get(id);
@@ -276,7 +282,7 @@ export function createBotStatus({
276
282
  addTask(watch.taskSessionId, watch.title, Number(watch.at) || 0);
277
283
  }
278
284
  for (const row of owned) {
279
- if (row.id === homeId || roomMemberOfSession(row.id) || !isWorking(row)) continue;
285
+ if (row.id === homeId || roomMemberOfSession(row.id) || !sentWork(row)) continue;
280
286
  addTask(row.id, row.title, Number(row.createdAt) || 0);
281
287
  }
282
288
  const running = [...tasks.values()].sort((left, right) => left.at - right.at || (left.id < right.id ? -1 : 1));
@@ -302,7 +308,7 @@ export function createBotStatus({
302
308
  approvals,
303
309
  routines,
304
310
  flags,
305
- working: isWorking(home) || running.some((task) => isWorking(ctx.rows.get(task.id))),
311
+ working: isWorking(home) || running.some((task) => sentWork(ctx.rows.get(task.id))),
306
312
  lastAt: activityOf(home),
307
313
  };
308
314
  }
@@ -0,0 +1,38 @@
1
+ // A bot id as the `session_id` of read, send and status: a bot's chat is a
2
+ // session of its own (`sess_home_<id>`), but the schema also lets a model name
3
+ // the bot (`bots` takes either), so the id resolves to that home chat — before
4
+ // any check of the target, so the bot-chain, hop and task-origin checks see
5
+ // the chat they would for `sess_home_<id>`. A minted session id always has an
6
+ // underscore, a normalized bot id never does (agent-home.mjs), so only ids
7
+ // shaped like a bot id are looked up.
8
+ import { MIXY_AGENT_ID, agentHomeSessionId } from '../runtime/agent/orchestrator/session/agent-home.mjs';
9
+ import { defaultListBots, quotedText } from './bot-status.mjs';
10
+
11
+ const MAX_NAMED_BOTS = 30;
12
+ /** The actions whose `session_id` may be a bot id. */
13
+ export const BOT_TARGET_ACTIONS = new Set(['read', 'send', 'status']);
14
+
15
+ /** The ids of the bots a send can reach: Mixy and every contact agent. */
16
+ async function botIds(listBots) {
17
+ return [MIXY_AGENT_ID, ...(await listBots()).map((bot) => bot.id)];
18
+ }
19
+
20
+ /** `target`'s home chat when it is a known bot id, else `target` unchanged. */
21
+ export async function resolveBotTarget(target, listBots = defaultListBots) {
22
+ const home = agentHomeSessionId(target);
23
+ return home && (await botIds(listBots)).includes(target) ? home : target;
24
+ }
25
+
26
+ /** Whether `target` is shaped like a bot id (so, with no session, a mistyped one). */
27
+ export const isBotShaped = (target) => agentHomeSessionId(target) !== '';
28
+
29
+ /** The error for a bot-shaped `target` that is neither a known bot nor a session. */
30
+ export async function unknownBotError(target, listBots = defaultListBots, cause) {
31
+ const ids = await botIds(listBots);
32
+ const named = ids.slice(0, MAX_NAMED_BOTS).join(', ');
33
+ const more = ids.length > MAX_NAMED_BOTS ? `, … (${ids.length - MAX_NAMED_BOTS} more)` : '';
34
+ return new Error(
35
+ `session: "${quotedText(target, 64)}" is neither a session nor a known bot id; bot ids: ${named}${more}; session action=list finds session ids`,
36
+ cause ? { cause } : undefined
37
+ );
38
+ }
@@ -12,7 +12,12 @@ import {
12
12
  testWebhook,
13
13
  withScheduleRenameReserved,
14
14
  } from './services/channel-admin.mjs';
15
- import { getSchedule, markScheduleFailure, markScheduleSkipped, markScheduleSuccess } from '../runtime/channels/lib/schedules-db.mjs';
15
+ import {
16
+ getSchedule,
17
+ markScheduleFailure,
18
+ markScheduleSkipped,
19
+ markScheduleSuccess,
20
+ } from '../runtime/channels/lib/schedules-db.mjs';
16
21
  import { scheduleRenameUncertainError } from '../runtime/channels/lib/schedule-errors.mjs';
17
22
  import { loadEndpointConfig, readEndpointLastPayload } from '../runtime/channels/lib/webhooks-db.mjs';
18
23
  import { webhookEventSummary, webhookRunPrompt } from '../runtime/channels/lib/webhook/session-dispatch.mjs';
@@ -17,6 +17,7 @@ import {
17
17
  stripStoredRouteDefaults,
18
18
  withDefaultPresets,
19
19
  } from '../runtime/agent/orchestrator/config-presets.mjs';
20
+ import { syncSessionCompaction } from './session-compaction-sync.mjs';
20
21
  import { createConfigWriters } from './config-lifecycle/config-writers.mjs';
21
22
  import { createLeadRouteSync } from './config-lifecycle/lead-route-sync.mjs';
22
23
  import { createOutputStyleStatusCache } from './config-lifecycle/output-style-cache.mjs';
@@ -134,6 +135,10 @@ export function createConfigLifecycle({
134
135
  getConfigHasSecrets,
135
136
  setConfigHasSecrets,
136
137
  getRoute,
138
+ // The live session follows the reloaded global compaction settings, unless
139
+ // the runtime runs on an injected (headless) config.
140
+ getSession,
141
+ fixedSessionCompaction = false,
137
142
  // Main route sync on reload (both optional: a lifecycle without them never syncs)
138
143
  setRouteState,
139
144
  resolveRoute,
@@ -222,6 +227,7 @@ export function createConfigLifecycle({
222
227
  const adopted = adoptConfig(next, { hasSecrets: true });
223
228
  configSaveBaseline = structuredClone(adopted);
224
229
  leadRoute.syncEmptyMainRoute(adopted);
230
+ if (!fixedSessionCompaction) syncSessionCompaction(getSession?.(), adopted);
225
231
  return adopted;
226
232
  }
227
233
 
@@ -0,0 +1,305 @@
1
+ // After the multi-account connector merge (connector-catalog.mjs
2
+ // mergeConnectorAccountServers) `gmail-2`, `google-calendar-2`… are accounts of
3
+ // one server, no longer servers. Every store of ours that keys a setting by
4
+ // MCP server name must name the surviving server instead:
5
+ // agents/<id>/agent.json, bots/<id>/agent.json connectors.off / connectors.tools
6
+ // (a legacy allow list too)
7
+ // <data>/project-connectors.json projects.<root>.off
8
+ // <data>/hooks.json, <data>/hooks/hooks.json mcp_tool `server`, tool matchers
9
+ // (extension scopes are the config's and are dropped by migrateConnectorAccounts;
10
+ // an approval's "always allow" is the agent's connectors.tools; agent routes
11
+ // name models, not servers.) Project and plugin hook files are the user's or
12
+ // the plugin's own and are never rewritten here.
13
+ //
14
+ // Rule: the merged connector is OFF for an agent/project only when EVERY
15
+ // merged server was off (the same rule as the merged server's `enabled`: one
16
+ // working account keeps the connector usable). Per-tool permissions move to
17
+ // the surviving name; where two merged servers disagree on a tool the MORE
18
+ // PERMISSIVE permission wins, as "on beats off" does at server level. Entries
19
+ // of a server that was off are dormant and are dropped when the connector
20
+ // stays on, so they never become live. A setting that names no merged-away
21
+ // server is never touched, which makes every run after the first a no-op.
22
+ //
23
+ // The merge is saved to the config once, so the rename mapping outlives it:
24
+ // `<data>/connector-merge-pending.json` ({ merged: [{ name, from }] }) is
25
+ // written before any store is touched and deleted only when every store
26
+ // migrated. A store that fails (unreadable, malformed, not writable) is
27
+ // reported and the others still go on; the next start retries them all.
28
+ //
29
+ // Hooks: only tool identifiers are rewritten — an `mcp_tool` handler's
30
+ // `server`, and a matcher / tool-name field (or the tool part of an `if`
31
+ // before its `(`) that is an `mcp__<server>__…` identifier or an
32
+ // alternative of a pattern. Argument conditions such as `Bash(mcp__x__*)`
33
+ // and any other data are never touched.
34
+ import { readdirSync, readFileSync, rmSync } from 'node:fs';
35
+ import { join } from 'node:path';
36
+ import { normalizeRules, standardConfigReport } from './services/hook-bus/config.mjs';
37
+ import {
38
+ PERMISSION_RANK,
39
+ PROJECT_CONNECTORS_FILE,
40
+ connectorEnabled,
41
+ parseConnectorPolicy,
42
+ storedConnectorPolicy,
43
+ } from '../runtime/agent/orchestrator/mcp/agent-connectors.mjs';
44
+ import { parseJsonText, withFileLockSync, writeJsonAtomicSync } from '../runtime/shared/atomic-file.mjs';
45
+
46
+ const unique = (list) => [...new Set(list)].sort();
47
+
48
+ /** The policy `{ off, tools }` (or a legacy `{ allow, off, tools }`) with every
49
+ * merged-away server of `merged` mapped onto its surviving one; null when it
50
+ * names none. `merged` is mergeConnectorAccountServers' `merged`. */
51
+ function mapMergedConnectorPolicy(policy, merged) {
52
+ let current = policy;
53
+ for (const { name, from } of merged) {
54
+ const gone = from.filter((server) => server !== name);
55
+ const named = (server) =>
56
+ current.off.includes(server) || current.allow?.includes(server) || Object.hasOwn(current.tools, server);
57
+ if (!gone.some(named)) continue;
58
+ const live = from.filter((server) => connectorEnabled(current, server));
59
+ const on = live.length > 0;
60
+ const off = current.off.filter((server) => !from.includes(server));
61
+ const allow = current.allow?.filter((server) => !from.includes(server));
62
+ if (allow && on) allow.push(name);
63
+ if (!allow && !on) off.push(name);
64
+ const tools = { ...current.tools };
65
+ for (const server of from) delete tools[server];
66
+ const moved = {};
67
+ for (const server of on ? live : from) {
68
+ for (const [tool, permission] of Object.entries(current.tools[server] || {})) {
69
+ if (!(tool in moved) || PERMISSION_RANK[permission] > PERMISSION_RANK[moved[tool]]) moved[tool] = permission;
70
+ }
71
+ }
72
+ if (Object.keys(moved).length) tools[name] = moved;
73
+ current = { ...(allow ? { allow: unique(allow) } : {}), off: unique(off), tools };
74
+ }
75
+ return current === policy ? null : current;
76
+ }
77
+
78
+ /** A mapped policy as the value the agent.json `connectors` field stores
79
+ * (undefined: the field goes). */
80
+ function storedValue(policy) {
81
+ if (!policy.allow) return storedConnectorPolicy(policy) ?? undefined;
82
+ const ids = unique([...policy.allow, ...Object.keys(policy.tools)]);
83
+ return ids.map((id) => ({
84
+ id,
85
+ enabled: policy.allow.includes(id),
86
+ ...(policy.tools[id] ? { tools: policy.tools[id] } : {}),
87
+ }));
88
+ }
89
+
90
+ export const PENDING_MERGE_FILE = 'connector-merge-pending.json';
91
+
92
+ const warn = (file, error) => process.stderr.write(`[connectors] ${file} not migrated (${error?.message || error})\n`);
93
+
94
+ /** The JSON at `file`; null when it does not exist. Any other failure throws. */
95
+ function readJsonFile(file) {
96
+ try {
97
+ return parseJsonText(readFileSync(file, 'utf8'));
98
+ } catch (error) {
99
+ if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR') return null;
100
+ throw error;
101
+ }
102
+ }
103
+
104
+ const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
105
+
106
+ /** Runs `step` for one store; a failure is reported and returned, never thrown. */
107
+ function attempt(file, step, outcome) {
108
+ try {
109
+ step();
110
+ } catch (error) {
111
+ warn(file, error);
112
+ outcome.failed.push(file);
113
+ }
114
+ }
115
+
116
+ function migrateAgentFiles(dataDir, merged, outcome, readdir) {
117
+ for (const store of ['agents', 'bots']) {
118
+ const dir = join(dataDir, store);
119
+ let entries;
120
+ try {
121
+ entries = readdir(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory());
122
+ } catch (error) {
123
+ // A store that does not exist has nothing to migrate; any other failure
124
+ // leaves its agents unprocessed, so the mapping must stay pending.
125
+ if (error?.code !== 'ENOENT') {
126
+ warn(dir, error);
127
+ outcome.failed.push(dir);
128
+ }
129
+ continue;
130
+ }
131
+ for (const entry of entries) {
132
+ const file = join(dataDir, store, entry.name, 'agent.json');
133
+ attempt(
134
+ file,
135
+ () => {
136
+ const manifest = readJsonFile(file);
137
+ if (!isRecord(manifest) || manifest.connectors == null) return;
138
+ const next = mapMergedConnectorPolicy(parseConnectorPolicy(manifest.connectors), merged);
139
+ if (!next) return;
140
+ const value = storedValue(next);
141
+ if (value) manifest.connectors = value;
142
+ else delete manifest.connectors;
143
+ writeJsonAtomicSync(file, manifest, { backup: true });
144
+ outcome.agents.push(`${store}/${entry.name}`);
145
+ },
146
+ outcome
147
+ );
148
+ }
149
+ }
150
+ }
151
+
152
+ function migrateProjectFile(dataDir, merged, outcome) {
153
+ const file = join(dataDir, PROJECT_CONNECTORS_FILE);
154
+ attempt(
155
+ file,
156
+ () => {
157
+ withFileLockSync(`${file}.lock`, () => {
158
+ const document = readJsonFile(file);
159
+ const projects = document?.projects;
160
+ if (!isRecord(projects)) return;
161
+ const changed = [];
162
+ for (const [root, entry] of Object.entries(projects)) {
163
+ if (!isRecord(entry) || !Array.isArray(entry.off)) continue;
164
+ const next = mapMergedConnectorPolicy({ off: entry.off.map(String), tools: {} }, merged);
165
+ if (!next) continue;
166
+ if (next.off.length) projects[root] = { ...entry, off: next.off };
167
+ else delete projects[root];
168
+ changed.push(root);
169
+ }
170
+ if (!changed.length) return;
171
+ writeJsonAtomicSync(file, document, { lock: false, backup: true });
172
+ outcome.projects.push(...changed);
173
+ });
174
+ },
175
+ outcome
176
+ );
177
+ }
178
+
179
+ const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
180
+
181
+ /** A tool identifier or pattern (`mcp__a__x`, `^mcp__a__.*$`, `Bash|mcp__a__x`)
182
+ * with each `mcp__<merged-away>` alternative renamed. */
183
+ function renameToolPattern(value, renames) {
184
+ let next = value;
185
+ for (const [gone, name] of renames) {
186
+ const identifier = new RegExp(`(^|\\|)(\\^?)mcp__${escapeRegExp(gone)}(?=__|(?![A-Za-z0-9_-]))`, 'g');
187
+ next = next.replace(identifier, (_all, lead, anchor) => `${lead}${anchor}mcp__${name}`);
188
+ }
189
+ return next;
190
+ }
191
+
192
+ /** A condition `Tool(arguments)`: only the tool part is an identifier. */
193
+ function renameCondition(value, renames) {
194
+ const open = value.indexOf('(');
195
+ return open < 0
196
+ ? renameToolPattern(value, renames)
197
+ : renameToolPattern(value.slice(0, open), renames) + value.slice(open);
198
+ }
199
+
200
+ /** Renames in the hook structures of `document` (in place); true when any changed. */
201
+ function renameInHooks(document, renames) {
202
+ let changed = false;
203
+ const set = (owner, key, rename) => {
204
+ if (typeof owner[key] !== 'string') return;
205
+ const next = rename(owner[key], renames);
206
+ if (next === owner[key]) return;
207
+ owner[key] = next;
208
+ changed = true;
209
+ };
210
+ const handler = (hook) => {
211
+ if (!isRecord(hook)) return;
212
+ if (hook.type === 'mcp_tool') {
213
+ if (typeof hook.server === 'string' && renames.has(hook.server.trim())) {
214
+ hook.server = renames.get(hook.server.trim());
215
+ changed = true;
216
+ }
217
+ set(hook, 'tool', renameToolPattern);
218
+ }
219
+ set(hook, 'if', renameCondition);
220
+ };
221
+ if (standardConfigReport(document).standard) {
222
+ for (const groups of Object.values(document.hooks)) {
223
+ for (const group of Array.isArray(groups) ? groups : []) {
224
+ if (!isRecord(group)) continue;
225
+ set(group, 'matcher', renameToolPattern);
226
+ set(group, 'if', renameCondition);
227
+ for (const hook of Array.isArray(group.hooks) ? group.hooks : []) handler(hook);
228
+ }
229
+ }
230
+ } else {
231
+ for (const rule of normalizeRules(document)) {
232
+ if (!isRecord(rule)) continue;
233
+ set(rule, 'tool', renameToolPattern);
234
+ set(rule, 'name', renameToolPattern);
235
+ set(rule, 'if', renameCondition);
236
+ }
237
+ }
238
+ return changed;
239
+ }
240
+
241
+ function migrateHookFiles(dataDir, merged, outcome) {
242
+ const renames = new Map(
243
+ merged.flatMap(({ name, from }) => from.filter((server) => server !== name).map((gone) => [gone, name]))
244
+ );
245
+ for (const file of [join(dataDir, 'hooks.json'), join(dataDir, 'hooks', 'hooks.json')]) {
246
+ attempt(
247
+ file,
248
+ () => {
249
+ const document = readJsonFile(file);
250
+ if (!isRecord(document) && !Array.isArray(document)) return;
251
+ if (!renameInHooks(document, renames)) return;
252
+ writeJsonAtomicSync(file, document, { backup: true });
253
+ outcome.hooks.push(file);
254
+ },
255
+ outcome
256
+ );
257
+ }
258
+ }
259
+
260
+ const validGroup = (group) =>
261
+ isRecord(group) &&
262
+ typeof group.name === 'string' &&
263
+ Array.isArray(group.from) &&
264
+ group.from.every((n) => typeof n === 'string');
265
+
266
+ /** Maps every per-server setting of `dataDir` onto the surviving servers of
267
+ * `merged` (this start's merge, [] to only retry) plus any still pending from
268
+ * an earlier start. Returns what it rewrote and the files that failed:
269
+ * `{ agents, projects, hooks, failed, unrecorded? }`. The pending record is
270
+ * removed only when `failed` is empty; `unrecorded` says it could not be
271
+ * written, so the caller must not save the merge. `readdir` lists the agent
272
+ * and bot directories. */
273
+ export function migrateMergedConnectorServers(dataDir, merged, { readdir = readdirSync } = {}) {
274
+ const outcome = { agents: [], projects: [], hooks: [], failed: [] };
275
+ if (!dataDir) return outcome;
276
+ const pendingFile = join(dataDir, PENDING_MERGE_FILE);
277
+ let pending = [];
278
+ try {
279
+ const stored = readJsonFile(pendingFile)?.merged;
280
+ pending = Array.isArray(stored) ? stored.filter(validGroup).map(({ name, from }) => ({ name, from })) : [];
281
+ } catch (error) {
282
+ warn(pendingFile, error);
283
+ }
284
+ const groups = [...pending];
285
+ for (const { name, from } of merged) {
286
+ if (!groups.some((group) => group.name === name && JSON.stringify(group.from) === JSON.stringify(from))) {
287
+ groups.push({ name, from });
288
+ }
289
+ }
290
+ if (!groups.length) return outcome;
291
+ if (groups.length !== pending.length) {
292
+ try {
293
+ writeJsonAtomicSync(pendingFile, { merged: groups }, { backup: false });
294
+ } catch (error) {
295
+ warn(pendingFile, error);
296
+ // Nothing records the mapping: a failed store must keep the merge unsaved.
297
+ outcome.unrecorded = true;
298
+ }
299
+ }
300
+ migrateAgentFiles(dataDir, groups, outcome, readdir);
301
+ migrateProjectFile(dataDir, groups, outcome);
302
+ migrateHookFiles(dataDir, groups, outcome);
303
+ if (!outcome.failed.length) rmSync(pendingFile, { force: true });
304
+ return outcome;
305
+ }