mixdog 1.3.4 → 1.4.0

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 (472) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +17 -2
  3. package/README.md +11 -0
  4. package/package.json +3 -11
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/embed-google-oauth-client.mjs +49 -0
  7. package/scripts/gate-local.mjs +4 -2
  8. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  9. package/scripts/native-release-status.mjs +2 -2
  10. package/scripts/recall-history-cases.json +1 -1
  11. package/scripts/suite-health.mjs +10 -1
  12. package/scripts/test.mjs +12 -11
  13. package/src/agents/reviewer/AGENT.md +7 -11
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/defaults/shipped-history.json +25 -1
  16. package/src/defaults/skills/browser-use/SKILL.md +77 -17
  17. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  18. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  19. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  20. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  21. package/src/defaults/skills/computer-use/SKILL.md +33 -9
  22. package/src/defaults/skills/setup/SKILL.md +29 -2
  23. package/src/defaults/skills/setup/references/actions.md +117 -28
  24. package/src/defaults/skills/setup/references/surfaces.md +77 -35
  25. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  26. package/src/defaults/skills/visualize/SKILL.md +2 -1
  27. package/src/lib/keychain-cjs.cjs +359 -29
  28. package/src/lib/rules-builder.cjs +10 -8
  29. package/src/rules/agent/AGENT.md +6 -6
  30. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  31. package/src/rules/agent-mode/MIXY.md +12 -0
  32. package/src/rules/lead/LEAD.md +18 -20
  33. package/src/rules/shared/05-tool-calls.md +5 -6
  34. package/src/rules/shared/10-tool-workflow.md +2 -0
  35. package/src/rules/shared/60-verification.md +7 -5
  36. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  37. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  38. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  39. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/config.mjs +34 -0
  41. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  42. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
  43. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
  44. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  45. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
  46. package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  49. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  50. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  51. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  53. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
  54. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
  55. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  56. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  60. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +160 -69
  61. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
  63. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  65. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  66. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  67. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  68. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  69. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
  70. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  78. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  79. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  81. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  82. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  83. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  84. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  85. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  86. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  87. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  88. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  89. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  90. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  91. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  92. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  93. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  94. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  95. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  97. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  98. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  99. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  100. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  101. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  103. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +19 -1
  104. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  109. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  113. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  114. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  115. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  116. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  117. package/src/runtime/agent/orchestrator/providers/registry.mjs +43 -3
  118. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  119. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  120. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  121. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
  122. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  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 +1 -1
  127. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  128. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  131. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  132. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  133. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  134. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  135. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  136. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  137. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  138. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  139. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  140. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
  141. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
  142. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  143. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  144. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +8 -0
  145. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
  146. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
  147. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  148. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
  149. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
  151. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
  152. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
  153. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  154. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
  155. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
  156. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
  157. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  158. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +14 -4
  159. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  163. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
  164. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  165. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  166. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  167. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  168. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  172. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  173. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
  174. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  175. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  176. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
  177. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
  178. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  179. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
  180. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  182. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
  183. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  184. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
  185. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  186. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  187. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  188. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
  189. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
  191. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  192. package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
  193. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  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-persistence-events.mjs +29 -0
  203. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
  207. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
  208. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  209. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  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/tool-batch/state.mjs +4 -0
  214. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
  216. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  217. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  218. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  219. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  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.mjs +25 -5
  225. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
  226. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  227. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  228. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  229. package/src/runtime/browser-bridge/client.mjs +73 -8
  230. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  231. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  232. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  233. package/src/runtime/channels/lib/config.mjs +6 -61
  234. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  235. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  236. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  237. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  238. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  239. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  240. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  241. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  242. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  243. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  244. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  245. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  246. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  247. package/src/runtime/channels/lib/scheduler.mjs +135 -154
  248. package/src/runtime/channels/lib/schedules-db.mjs +83 -11
  249. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  250. package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
  251. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  252. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  253. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  254. package/src/runtime/channels/lib/worker-main.mjs +19 -34
  255. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  256. package/src/runtime/computer-bridge/actions.mjs +9 -1
  257. package/src/runtime/computer-bridge/client.mjs +180 -8
  258. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  259. package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
  260. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  261. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  262. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  263. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  264. package/src/runtime/connectors/google-mcp.mjs +10 -12
  265. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  266. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  268. package/src/runtime/office/com/com-adapter.mjs +17 -1
  269. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  270. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  271. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  272. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  273. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  274. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  275. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  276. package/src/runtime/session-search/session-search-db.mjs +73 -9
  277. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  278. package/src/runtime/shared/abort-race.mjs +89 -0
  279. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  280. package/src/runtime/shared/agent-kind.mjs +4 -3
  281. package/src/runtime/shared/bot-hops.mjs +62 -2
  282. package/src/runtime/shared/bounded-download.mjs +8 -3
  283. package/src/runtime/shared/config.mjs +51 -35
  284. package/src/runtime/shared/connector-accounts.mjs +20 -10
  285. package/src/runtime/shared/connector-catalog.d.mts +33 -2
  286. package/src/runtime/shared/connector-catalog.mjs +166 -8
  287. package/src/runtime/shared/connector-triggers.mjs +22 -19
  288. package/src/runtime/shared/defaults-separation.mjs +2 -14
  289. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  290. package/src/runtime/shared/developer-options.mjs +32 -1
  291. package/src/runtime/shared/err-text.mjs +24 -15
  292. package/src/runtime/shared/file-permissions.d.mts +0 -8
  293. package/src/runtime/shared/file-permissions.mjs +0 -11
  294. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  295. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  296. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  297. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  298. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  299. package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
  300. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  301. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  302. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  303. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  304. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  305. package/src/runtime/shared/mixy-presence.mjs +22 -0
  306. package/src/runtime/shared/orchestration.d.mts +2 -0
  307. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  308. package/src/runtime/shared/profile-config.cjs +1 -1
  309. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  310. package/src/runtime/shared/prompt-origin.mjs +21 -0
  311. package/src/runtime/shared/provider-accounts.mjs +231 -59
  312. package/src/runtime/shared/provider-api-key.mjs +19 -8
  313. package/src/runtime/shared/provider-display-name.mjs +29 -0
  314. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  315. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  316. package/src/runtime/shared/routine-trigger.mjs +52 -0
  317. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  318. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  319. package/src/runtime/shared/session-activity-signal.mjs +34 -1
  320. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  321. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  322. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  323. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  324. package/src/runtime/shared/tool-result-summary.mjs +1 -14
  325. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  326. package/src/runtime/shared/user-data-guard.mjs +30 -2
  327. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  328. package/src/runtime/shared/worktrees/test-support.mjs +9 -4
  329. package/src/runtime/terminal-bridge/client.mjs +10 -1
  330. package/src/runtime/visualize-bridge/client.mjs +27 -8
  331. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  332. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  333. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  334. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  335. package/src/session-runtime/agent-home-delivery.mjs +486 -179
  336. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  337. package/src/session-runtime/agent-task-sessions.mjs +561 -199
  338. package/src/session-runtime/boot/apis.mjs +9 -0
  339. package/src/session-runtime/boot/begin.mjs +3 -2
  340. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  341. package/src/session-runtime/boot/providers.mjs +3 -0
  342. package/src/session-runtime/boot/tools.mjs +8 -1
  343. package/src/session-runtime/bot-chain.mjs +32 -0
  344. package/src/session-runtime/bot-status.mjs +7 -4
  345. package/src/session-runtime/channel-config-api.mjs +63 -17
  346. package/src/session-runtime/config-lifecycle.mjs +6 -0
  347. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  348. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
  349. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
  350. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  351. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  352. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  353. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  354. package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
  355. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  356. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  357. package/src/session-runtime/mcp-glue/server-catalog.mjs +61 -3
  358. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  359. package/src/session-runtime/mixy-heartbeat.mjs +927 -0
  360. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  361. package/src/session-runtime/notification-bus.mjs +31 -117
  362. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  363. package/src/session-runtime/notification-listeners.mjs +76 -0
  364. package/src/session-runtime/owned-automation-run.mjs +35 -13
  365. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  366. package/src/session-runtime/provider-auth/login.mjs +7 -0
  367. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  368. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  369. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  370. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  371. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  372. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  373. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  374. package/src/session-runtime/routine-home-turn.mjs +33 -6
  375. package/src/session-runtime/routine-owner.mjs +40 -9
  376. package/src/session-runtime/schedule-session-run.mjs +7 -3
  377. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  378. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  379. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
  380. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  381. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  382. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  383. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  384. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  385. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  386. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  387. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  388. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  389. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  390. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  391. package/src/session-runtime/services/channel-admin.mjs +73 -31
  392. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  393. package/src/session-runtime/services/channel-worker.mjs +1 -1
  394. package/src/session-runtime/services/provider-admin.mjs +128 -25
  395. package/src/session-runtime/services/schedule-access.mjs +14 -0
  396. package/src/session-runtime/services/seeds.mjs +0 -28
  397. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  398. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  399. package/src/session-runtime/session-create/session-options.mjs +8 -4
  400. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  401. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  402. package/src/session-runtime/settings-system-api.mjs +28 -1
  403. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  404. package/src/session-runtime/setup-tool/executor.mjs +187 -29
  405. package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
  406. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  407. package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
  408. package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
  409. package/src/session-runtime/task-session-route.mjs +99 -0
  410. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  411. package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
  412. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  413. package/src/session-runtime/tool-surface.mjs +4 -0
  414. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  415. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  416. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  417. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  418. package/src/session-runtime/workspace/transitions.mjs +10 -2
  419. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  420. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  421. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  422. package/src/standalone/channel-transport.mjs +1 -1
  423. package/src/standalone/daemon-channels-loader.mjs +10 -8
  424. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  425. package/src/standalone/daemon-session-control/request.mjs +51 -0
  426. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  427. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  428. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  429. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  430. package/src/standalone/daemon-session-control.mjs +161 -157
  431. package/src/standalone/daemon.mjs +33 -2
  432. package/src/standalone/session-client.mjs +7 -3
  433. package/src/standalone/session-protocol.mjs +10 -0
  434. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  435. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  436. package/src/standalone/session-service/quota-resume.mjs +3 -0
  437. package/src/standalone/session-service/retention/busy.mjs +65 -1
  438. package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
  439. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  440. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  441. package/src/standalone/session-service.mjs +13 -0
  442. package/src/standalone/session-tool-output.mjs +21 -10
  443. package/src/tui/app/model-options.mjs +4 -27
  444. package/src/tui/dist/index.mjs +81 -65
  445. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  446. package/src/tui/session/initial-state.mjs +3 -0
  447. package/src/tui/session/notice-surface.mjs +23 -1
  448. package/src/tui/session/queue-helpers.mjs +3 -42
  449. package/src/tui/session/session-api/integrations.mjs +1 -0
  450. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  451. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  452. package/src/tui/session/session-api/routes-write.mjs +5 -1
  453. package/src/tui/session/session-api/routes.mjs +1 -0
  454. package/src/tui/session/session-api/settings.mjs +30 -2
  455. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  456. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  457. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  458. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  459. package/src/tui/session/session-flow/drain.mjs +118 -149
  460. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  461. package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
  462. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  463. package/src/tui/session/tool-approval-request.mjs +39 -0
  464. package/src/tui/session/tool-approval-settle.mjs +62 -0
  465. package/src/tui/session/tool-approval.mjs +69 -115
  466. package/src/tui/session/tui-steering-persist.mjs +8 -1
  467. package/src/tui/session/turn-stream.mjs +36 -3
  468. package/src/tui/session/turn.mjs +23 -2
  469. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  470. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  471. package/scripts/code-graph-description-contract.mjs +0 -188
  472. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -17,10 +17,14 @@ export function createRouteTuning(deps, persist) {
17
17
  * is already the Main model (persistAdoptedModelSettings: tunesNonMainModel),
18
18
  * so the lead preset's model is rewritten with itself and never changes. A
19
19
  * live route without a model normalizes to nothing and writes no preset. */
20
- async function commitRouteTuning(fastCapable, modelMeta) {
21
- persist.saveRouteModelSettings(getRoute(), fastCapable);
22
- const leadRoute = persist.persistAdoptedModelSettings(getRoute());
23
- if (leadRoute) setRouteState(resolveRoute(getConfig(), { model: workflowPresetId('lead') }));
20
+ async function commitRouteTuning(fastCapable, modelMeta, { sessionOnly = false } = {}) {
21
+ // sessionOnly: the live route and session change; the saved model
22
+ // settings and the config stay as the user left them.
23
+ if (!sessionOnly) {
24
+ persist.saveRouteModelSettings(getRoute(), fastCapable);
25
+ const leadRoute = persist.persistAdoptedModelSettings(getRoute());
26
+ if (leadRoute) setRouteState(resolveRoute(getConfig(), { model: workflowPresetId('lead') }));
27
+ }
24
28
  await refreshRouteEffort(modelMeta);
25
29
  persist.applySessionTuning();
26
30
  }
@@ -65,7 +69,7 @@ export function createRouteTuning(deps, persist) {
65
69
  async toggleFast() {
66
70
  return await setFast(!(getRoute().fast === true));
67
71
  },
68
- async setEffort(value) {
72
+ async setEffort(value, { sessionOnly = false } = {}) {
69
73
  const normalized = normalizeEffortInput(value);
70
74
  // An explicit level is the user's choice for this route: Auto effort
71
75
  // would replace it on the next turn (its base is fixed), so the pick
@@ -73,7 +77,7 @@ export function createRouteTuning(deps, persist) {
73
77
  setRouteState({ ...getRoute(), effort: normalized, ...(normalized ? { autoEffort: false } : {}) });
74
78
  const modelMeta = await lookupModelMeta(getRoute().provider, getRoute().model);
75
79
  const fastCapable = selectionFastCapable(getRoute().provider, modelMeta, normalized, getRoute().modelParameters);
76
- await commitRouteTuning(fastCapable, modelMeta);
80
+ await commitRouteTuning(fastCapable, modelMeta, { sessionOnly });
77
81
  return getRoute();
78
82
  },
79
83
  };
@@ -3,27 +3,17 @@
3
3
  // pending queue so the model sees it next turn. The delivered registry keeps
4
4
  // those two paths from double-injecting the same completion.
5
5
  import { modelVisibleToolCompletionMessage } from '../runtime/shared/tool-execution-contract.mjs';
6
- import {
7
- PENDING_MODE_TASK_NOTIFICATION,
8
- markCompletionEntry,
9
- } from '../runtime/agent/orchestrator/session/manager/pending-messages.mjs';
10
- import {
11
- isDeliveredCompletion,
12
- logDuplicateSkip,
13
- recordDeliveredCompletion,
14
- } from '../runtime/agent/orchestrator/session/manager/delivered-completions.mjs';
6
+ import { PENDING_MODE_TASK_NOTIFICATION } from '../runtime/agent/orchestrator/session/manager/pending-messages.mjs';
7
+ import { recordDeliveredCompletion } from '../runtime/agent/orchestrator/session/manager/delivered-completions.mjs';
15
8
  import { shouldMirrorCompletionToPendingQueue } from './runtime-tool-routing.mjs';
16
9
  import { notifyTrace } from '../runtime/shared/notify-trace.mjs';
10
+ import { cleanSessionId, createListenerBindings, sessionListenersOf } from './notification-listeners.mjs';
11
+ import { createCompletionQueue } from './notification-completion-queue.mjs';
17
12
 
18
- const sessionNotificationListeners = new Map();
19
13
  // A completion that waits this long between enqueue and wake is reported: the
20
14
  // queue is durable, so the delay is a scheduling symptom, not a lost message.
21
15
  const WAKE_DELAY_REPORT_MS = 1_000;
22
16
 
23
- function cleanSessionId(value) {
24
- return String(value || '').trim();
25
- }
26
-
27
17
  // A queued completion only reaches the model on the next turn, so a session
28
18
  // with no user input pending is woken with an empty turn. One wake per session
29
19
  // runs at a time, and a completion suppressed by that in-flight wake is
@@ -63,7 +53,9 @@ export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi,
63
53
  if (typeof beforeWake === 'function') {
64
54
  try {
65
55
  await beforeWake(ownerSessionId);
66
- } catch {}
56
+ } catch {
57
+ // The pre-wake hook is best-effort; the wake proceeds without it.
58
+ }
67
59
  if (cleanSessionId(getCurrentSessionId()) !== ownerSessionId || !ownerOpen(ownerSessionId)) return;
68
60
  }
69
61
  // The wake continues the user turn that launched the worker, so its
@@ -102,10 +94,15 @@ export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi,
102
94
  };
103
95
  }
104
96
 
105
- function emitToListeners(source, content, meta = {}) {
97
+ function emitToListeners(source, content, meta = {}, origin = null) {
106
98
  const text = String(content || '').trim();
107
99
  if (!text) return { handled: false, modelVisibleDelivered: false };
108
- const event = { content: text, meta: meta && typeof meta === 'object' ? meta : {} };
100
+ const event = {
101
+ content: text,
102
+ meta: meta && typeof meta === 'object' ? meta : {},
103
+ // The notification's provenance apart from its meta (PROMPT_ORIGIN_CHANNEL).
104
+ ...(origin ? { origin } : {}),
105
+ };
109
106
  let handled = false;
110
107
  for (const listener of [...source]) {
111
108
  try {
@@ -118,8 +115,9 @@ function emitToListeners(source, content, meta = {}) {
118
115
  }
119
116
 
120
117
  export function createNotificationBus({ listeners, mgr, onCompletionQueued, getOwnerLifecycle }) {
121
- const boundSessionListeners = new Map();
122
- const queuedCompletionIds = new Map();
118
+ const { subscribeRuntimeNotification, bindRuntimeNotificationSession, clearRuntimeNotifications } =
119
+ createListenerBindings({ listeners });
120
+ const enqueueCompletion = createCompletionQueue({ mgr, onCompletionQueued });
123
121
 
124
122
  // Owner identity + lifecycle generation. A closing/terminal owner (or a
125
123
  // callback captured under an earlier generation) keeps its result for
@@ -137,12 +135,14 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued, getO
137
135
  return emitToListeners(listeners, content, meta);
138
136
  }
139
137
 
140
- function notifySession(sessionId, content, meta = {}) {
138
+ // `origin`: the notification's provenance (PROMPT_ORIGIN_CHANNEL for an
139
+ // inbound channel message), carried to the queue beside its mode.
140
+ function notifySession(sessionId, content, meta = {}, { origin = null } = {}) {
141
141
  const targetSessionId = cleanSessionId(sessionId);
142
142
  if (!targetSessionId) return false;
143
- const targetListeners = sessionNotificationListeners.get(targetSessionId) || [];
143
+ const targetListeners = sessionListenersOf(targetSessionId);
144
144
  const open = ownerOpen(targetSessionId);
145
- const { handled } = emitToListeners(targetListeners, content, open ? meta : closedMeta(meta));
145
+ const { handled } = emitToListeners(targetListeners, content, open ? meta : closedMeta(meta), origin);
146
146
  if (handled) return true;
147
147
  if (!open) return false;
148
148
  if (typeof mgr.enqueuePendingMessage !== 'function') return false;
@@ -151,7 +151,13 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued, getO
151
151
  // is the runtime reporting, exactly as an attached TUI queues it: a
152
152
  // task notification, so text inside it — fenced external webhook values
153
153
  // included — never drives explicit skill selection.
154
- return mgr.enqueuePendingMessage(targetSessionId, { content, mode: PENDING_MODE_TASK_NOTIFICATION }) > 0;
154
+ return (
155
+ mgr.enqueuePendingMessage(targetSessionId, {
156
+ content,
157
+ mode: PENDING_MODE_TASK_NOTIFICATION,
158
+ ...(origin ? { origin } : {}),
159
+ }) > 0
160
+ );
155
161
  } catch {
156
162
  return false;
157
163
  }
@@ -164,50 +170,14 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued, getO
164
170
  function notifySessionUi(sessionId, content, meta = {}) {
165
171
  const targetSessionId = cleanSessionId(sessionId);
166
172
  if (!targetSessionId) return false;
167
- const targetListeners = sessionNotificationListeners.get(targetSessionId) || [];
173
+ const targetListeners = sessionListenersOf(targetSessionId);
168
174
  return emitToListeners(targetListeners, content, meta).handled;
169
175
  }
170
176
 
171
- // Enqueue the model-visible twin unless it was already delivered; returns
172
- // true when the caller may treat the completion as delivered.
173
- function enqueueCompletion(callerSessionId, text, meta, path) {
174
- const visible = modelVisibleToolCompletionMessage(text, meta);
175
- // Non-completion notifications yield '' here and are never queued.
176
- if (!visible) return false;
177
- if (isDeliveredCompletion({ executionId: meta?.execution_id, text: visible })) {
178
- // Delivered + ACKed on the TUI path: suppress the duplicate but report
179
- // DELIVERED so the caller stops retrying.
180
- logDuplicateSkip(path, { executionId: meta?.execution_id, text: visible });
181
- return true;
182
- }
183
- const entry = markCompletionEntry(visible, { executionId: meta?.execution_id, meta });
184
- const queueKey = `${callerSessionId}:${entry.id}`;
185
- if (queuedCompletionIds.has(queueKey)) {
186
- logDuplicateSkip(`${path}-queued`, { executionId: meta?.execution_id, text: visible });
187
- return true;
188
- }
189
- const enqueued = mgr.enqueuePendingMessage(callerSessionId, entry) > 0;
190
- if (!enqueued) return false;
191
- queuedCompletionIds.set(queueKey, Date.now());
192
- while (queuedCompletionIds.size > 512) queuedCompletionIds.delete(queuedCompletionIds.keys().next().value);
193
- if (typeof onCompletionQueued === 'function') {
194
- try {
195
- onCompletionQueued({
196
- sessionId: callerSessionId,
197
- executionId: meta?.execution_id || null,
198
- enqueuedAt: entry.enqueuedAt,
199
- });
200
- } catch {
201
- /* wake-up is best-effort; the durable queue remains authoritative */
202
- }
203
- }
204
- return true;
205
- }
206
-
207
177
  function notifySessionCompletion(sessionId, text, meta = {}, capturedGeneration = undefined) {
208
178
  const targetSessionId = cleanSessionId(sessionId);
209
179
  if (!targetSessionId) return false;
210
- const targetListeners = sessionNotificationListeners.get(targetSessionId) || [];
180
+ const targetListeners = sessionListenersOf(targetSessionId);
211
181
  const open = ownerOpen(targetSessionId, capturedGeneration);
212
182
  const ownerMeta = {
213
183
  ...(meta && typeof meta === 'object' ? meta : {}),
@@ -262,62 +232,6 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued, getO
262
232
  return (text, meta = {}) => notifySessionCompletion(ownerSessionId, text, meta, generation);
263
233
  }
264
234
 
265
- function bindListenerToSession(sessionId, listener) {
266
- const ownerSessionId = cleanSessionId(sessionId);
267
- if (!ownerSessionId || typeof listener !== 'function') return;
268
- let bucket = sessionNotificationListeners.get(ownerSessionId);
269
- if (!bucket) {
270
- bucket = new Set();
271
- sessionNotificationListeners.set(ownerSessionId, bucket);
272
- }
273
- bucket.add(listener);
274
- let ownedBucket = boundSessionListeners.get(ownerSessionId);
275
- if (!ownedBucket) {
276
- ownedBucket = new Set();
277
- boundSessionListeners.set(ownerSessionId, ownedBucket);
278
- }
279
- ownedBucket.add(listener);
280
- }
281
-
282
- function unbindListener(listener) {
283
- for (const [sessionId, ownedBucket] of boundSessionListeners) {
284
- if (!ownedBucket.delete(listener)) continue;
285
- const bucket = sessionNotificationListeners.get(sessionId);
286
- bucket?.delete(listener);
287
- if (bucket?.size === 0) sessionNotificationListeners.delete(sessionId);
288
- if (ownedBucket.size === 0) boundSessionListeners.delete(sessionId);
289
- }
290
- }
291
-
292
- function subscribeRuntimeNotification(sessionId, listener) {
293
- const ownerSessionId = cleanSessionId(sessionId);
294
- if (typeof listener !== 'function') return () => {};
295
- listeners.add(listener);
296
- bindListenerToSession(ownerSessionId, listener);
297
- return () => {
298
- listeners.delete(listener);
299
- unbindListener(listener);
300
- };
301
- }
302
-
303
- function bindRuntimeNotificationSession(sessionId) {
304
- const ownerSessionId = cleanSessionId(sessionId);
305
- if (!ownerSessionId) return false;
306
- for (const listener of listeners) bindListenerToSession(ownerSessionId, listener);
307
- return true;
308
- }
309
-
310
- function clearRuntimeNotifications() {
311
- for (const [sessionId, ownedBucket] of boundSessionListeners) {
312
- const bucket = sessionNotificationListeners.get(sessionId);
313
- if (!bucket) continue;
314
- for (const listener of ownedBucket) bucket.delete(listener);
315
- if (bucket.size === 0) sessionNotificationListeners.delete(sessionId);
316
- }
317
- boundSessionListeners.clear();
318
- listeners.clear();
319
- }
320
-
321
235
  return {
322
236
  emitRuntimeNotification,
323
237
  notifySession,
@@ -0,0 +1,54 @@
1
+ // The model-visible queue path of a terminal tool completion
2
+ // (notification-bus.mjs): enqueue its twin once, skipping a completion the TUI
3
+ // path already delivered or this bus already queued.
4
+ import { modelVisibleToolCompletionMessage } from '../runtime/shared/tool-execution-contract.mjs';
5
+ import { markCompletionEntry } from '../runtime/agent/orchestrator/session/manager/pending-messages.mjs';
6
+ import {
7
+ isDeliveredCompletion,
8
+ logDuplicateSkip,
9
+ } from '../runtime/agent/orchestrator/session/manager/delivered-completions.mjs';
10
+
11
+ // Bounded memory of `${session}:${entry id}` keys this bus queued.
12
+ const QUEUED_COMPLETION_IDS_MAX = 512;
13
+
14
+ export function createCompletionQueue({ mgr, onCompletionQueued }) {
15
+ const queuedCompletionIds = new Map();
16
+
17
+ // Enqueue the model-visible twin unless it was already delivered; returns
18
+ // true when the caller may treat the completion as delivered.
19
+ return function enqueueCompletion(callerSessionId, text, meta, path) {
20
+ const visible = modelVisibleToolCompletionMessage(text, meta);
21
+ // Non-completion notifications yield '' here and are never queued.
22
+ if (!visible) return false;
23
+ if (isDeliveredCompletion({ executionId: meta?.execution_id, text: visible })) {
24
+ // Delivered + ACKed on the TUI path: suppress the duplicate but report
25
+ // DELIVERED so the caller stops retrying.
26
+ logDuplicateSkip(path, { executionId: meta?.execution_id, text: visible });
27
+ return true;
28
+ }
29
+ const entry = markCompletionEntry(visible, { executionId: meta?.execution_id, meta });
30
+ const queueKey = `${callerSessionId}:${entry.id}`;
31
+ if (queuedCompletionIds.has(queueKey)) {
32
+ logDuplicateSkip(`${path}-queued`, { executionId: meta?.execution_id, text: visible });
33
+ return true;
34
+ }
35
+ const enqueued = mgr.enqueuePendingMessage(callerSessionId, entry) > 0;
36
+ if (!enqueued) return false;
37
+ queuedCompletionIds.set(queueKey, Date.now());
38
+ while (queuedCompletionIds.size > QUEUED_COMPLETION_IDS_MAX) {
39
+ queuedCompletionIds.delete(queuedCompletionIds.keys().next().value);
40
+ }
41
+ if (typeof onCompletionQueued === 'function') {
42
+ try {
43
+ onCompletionQueued({
44
+ sessionId: callerSessionId,
45
+ executionId: meta?.execution_id || null,
46
+ enqueuedAt: entry.enqueuedAt,
47
+ });
48
+ } catch {
49
+ /* wake-up is best-effort; the durable queue remains authoritative */
50
+ }
51
+ }
52
+ return true;
53
+ };
54
+ }
@@ -0,0 +1,76 @@
1
+ // Session-bound runtime notification listeners (notification-bus.mjs). The
2
+ // per-session listener sets are process-wide; each bus owns which of its
3
+ // listeners it bound to which session, and unbinds only those.
4
+
5
+ const sessionNotificationListeners = new Map();
6
+
7
+ export function cleanSessionId(value) {
8
+ return String(value || '').trim();
9
+ }
10
+
11
+ /** The listeners bound to one session (an empty array when none). */
12
+ export function sessionListenersOf(sessionId) {
13
+ return sessionNotificationListeners.get(sessionId) || [];
14
+ }
15
+
16
+ export function createListenerBindings({ listeners }) {
17
+ const boundSessionListeners = new Map();
18
+
19
+ function bindListenerToSession(sessionId, listener) {
20
+ const ownerSessionId = cleanSessionId(sessionId);
21
+ if (!ownerSessionId || typeof listener !== 'function') return;
22
+ let bucket = sessionNotificationListeners.get(ownerSessionId);
23
+ if (!bucket) {
24
+ bucket = new Set();
25
+ sessionNotificationListeners.set(ownerSessionId, bucket);
26
+ }
27
+ bucket.add(listener);
28
+ let ownedBucket = boundSessionListeners.get(ownerSessionId);
29
+ if (!ownedBucket) {
30
+ ownedBucket = new Set();
31
+ boundSessionListeners.set(ownerSessionId, ownedBucket);
32
+ }
33
+ ownedBucket.add(listener);
34
+ }
35
+
36
+ function unbindListener(listener) {
37
+ for (const [sessionId, ownedBucket] of boundSessionListeners) {
38
+ if (!ownedBucket.delete(listener)) continue;
39
+ const bucket = sessionNotificationListeners.get(sessionId);
40
+ bucket?.delete(listener);
41
+ if (bucket?.size === 0) sessionNotificationListeners.delete(sessionId);
42
+ if (ownedBucket.size === 0) boundSessionListeners.delete(sessionId);
43
+ }
44
+ }
45
+
46
+ function subscribeRuntimeNotification(sessionId, listener) {
47
+ const ownerSessionId = cleanSessionId(sessionId);
48
+ if (typeof listener !== 'function') return () => {};
49
+ listeners.add(listener);
50
+ bindListenerToSession(ownerSessionId, listener);
51
+ return () => {
52
+ listeners.delete(listener);
53
+ unbindListener(listener);
54
+ };
55
+ }
56
+
57
+ function bindRuntimeNotificationSession(sessionId) {
58
+ const ownerSessionId = cleanSessionId(sessionId);
59
+ if (!ownerSessionId) return false;
60
+ for (const listener of listeners) bindListenerToSession(ownerSessionId, listener);
61
+ return true;
62
+ }
63
+
64
+ function clearRuntimeNotifications() {
65
+ for (const [sessionId, ownedBucket] of boundSessionListeners) {
66
+ const bucket = sessionNotificationListeners.get(sessionId);
67
+ if (!bucket) continue;
68
+ for (const listener of ownedBucket) bucket.delete(listener);
69
+ if (bucket.size === 0) sessionNotificationListeners.delete(sessionId);
70
+ }
71
+ boundSessionListeners.clear();
72
+ listeners.clear();
73
+ }
74
+
75
+ return { subscribeRuntimeNotification, bindRuntimeNotificationSession, clearRuntimeNotifications };
76
+ }
@@ -27,6 +27,21 @@ const defaultLog = (line) => process.stderr.write(`mixdog routines: ${line}\n`);
27
27
  // received webhooks and the app's "Run now" all come through here.
28
28
  const activeRuns = new Set();
29
29
 
30
+ /**
31
+ * Reserve `kind:name` against runs in this process for a rename. Null when a
32
+ * run is in flight; otherwise a release function. The check and the reservation
33
+ * are one synchronous step, and a run that finds the reservation is skipped as
34
+ * an overlap (runOwnedAutomation), so none can start under the name meanwhile.
35
+ * "Run now" takes the same reservation to hold the name from its read of the
36
+ * row through its outcome stamps (runOwnedAutomation `reserved`).
37
+ */
38
+ export function beginAutomationRename(kind, name, active = activeRuns) {
39
+ const key = `${kind}:${name}`;
40
+ if (active.has(key)) return null;
41
+ active.add(key);
42
+ return () => active.delete(key);
43
+ }
44
+
30
45
  // The PG record of each kind, imported on first use.
31
46
  const RECORDS = {
32
47
  schedule: () =>
@@ -103,7 +118,8 @@ async function queueResult(row, item, entry, { deliver, recordDelivery, onDelive
103
118
  * result }` (`signal` is the caller's cancellation, if any). Resolves the
104
119
  * outcome, or `{ skipped: true, reason: 'owner' | 'overlap' | 'backoff' | 'paused' }`
105
120
  * (an owner skip also names `ownerProblem` and its `message`); a failed run
106
- * rejects.
121
+ * rejects. `reserved`: the caller already holds `kind:name` (beginAutomationRename)
122
+ * and releases it itself, so this run neither checks for nor releases it.
107
123
  */
108
124
  export async function runOwnedAutomation(kind, row, run, deps = {}) {
109
125
  if (!row?.name) throw new Error(`${kind} run: a ${kind} row is required`);
@@ -112,9 +128,11 @@ export async function runOwnedAutomation(kind, row, run, deps = {}) {
112
128
  active = activeRuns,
113
129
  limits = ROUTINE_LIMITS,
114
130
  attended = false,
131
+ reserved = false,
115
132
  signal = null,
116
133
  now = Date.now,
117
- ownerProblem = routineOwnerProblem,
134
+ // `row` is stored: for Mixy, itself evidence of her (routine-owner.mjs).
135
+ ownerProblem = (ownerAgentId) => routineOwnerProblem(ownerAgentId, null, { stored: true }),
118
136
  log = defaultLog,
119
137
  } = deps;
120
138
  const name = row.name;
@@ -125,17 +143,21 @@ export async function runOwnedAutomation(kind, row, run, deps = {}) {
125
143
  .catch((error) => log(`${kind} "${name}": skip record failed: ${errorText(error)}`));
126
144
  return { name, skipped: true, reason, sessionId: null, result: '', ...extra };
127
145
  };
128
- // A routine runs only in its own bot's thread: without that bot it waits.
129
- const problem = await Promise.resolve()
130
- .then(() => ownerProblem(row.ownerAgentId))
131
- .catch(() => '');
132
- if (problem) {
133
- log(`${kind} "${name}": paused, ${ROUTINE_OWNER_PROBLEMS[problem]}`);
134
- return skip('owner', { ownerProblem: problem, message: ROUTINE_OWNER_PROBLEMS[problem] });
135
- }
136
- if (active.has(key)) return skip('overlap');
137
- active.add(key);
146
+ // The name is reserved before the owner check, so a rename can neither
147
+ // complete while it waits nor leave this run to start under the old name.
148
+ const overlap = !reserved && active.has(key);
149
+ const holds = !reserved && !overlap;
150
+ if (holds) active.add(key);
138
151
  try {
152
+ // A routine runs only in its own bot's thread: without that bot it waits.
153
+ const problem = await Promise.resolve()
154
+ .then(() => ownerProblem(row.ownerAgentId))
155
+ .catch(() => '');
156
+ if (problem) {
157
+ log(`${kind} "${name}": paused, ${ROUTINE_OWNER_PROBLEMS[problem]}`);
158
+ return await skip('owner', { ownerProblem: problem, message: ROUTINE_OWNER_PROBLEMS[problem] });
159
+ }
160
+ if (overlap) return await skip('overlap');
139
161
  if (!attended) {
140
162
  const record = await withRecord(kind, deps);
141
163
  const state = await Promise.resolve()
@@ -156,7 +178,7 @@ export async function runOwnedAutomation(kind, row, run, deps = {}) {
156
178
  }
157
179
  return await run({ signal });
158
180
  } finally {
159
- active.delete(key);
181
+ if (holds) active.delete(key);
160
182
  }
161
183
  }
162
184
 
@@ -39,9 +39,7 @@ export function createChannelStart({
39
39
  async function onChannelStartTimer() {
40
40
  timers.channelStartTimer = null;
41
41
  if (isCloseRequested()) return;
42
- // Channels-module and remote toggles gate MESSAGING; automation
43
- // (enabled schedules/webhooks) keeps the worker boot alive — its
44
- // channel worker runs headless: only active automation boots it.
42
+ // Only active automation (enabled schedules/webhooks) boots the worker.
45
43
  const automation = await hasActiveAutomation().catch(() => false);
46
44
  if (!automation) {
47
45
  bootProfile('channels:start-disabled');
@@ -69,10 +67,8 @@ export function createChannelStart({
69
67
  timers.channelStartTimer.unref?.();
70
68
  }
71
69
 
72
- // Boot-time automation autostart. Automation decoupling (user decision):
73
- // enabled schedules/webhooks boot the worker on their own — no messaging
74
- // provider. The worker runs headless (scheduler/webhooks/voice only).
75
- // Unlike scheduleChannelStart this probes once at the boot delay and never
70
+ // Boot-time automation autostart: enabled schedules/webhooks boot the worker
71
+ // on their own (scheduler/webhooks/voice only). Unlike scheduleChannelStart this probes once at the boot delay and never
76
72
  // re-arms. The probe itself is shared process-wide (channel-admin
77
73
  // hasActiveAutomation), so N runtimes booting together check once.
78
74
  function scheduleAutomationAutostart(delayMs) {
@@ -8,6 +8,7 @@ import {
8
8
  saveOpenAIUsageSessionKey,
9
9
  saveProviderApiKey,
10
10
  saveCustomProvider,
11
+ saveCustomProviderKey,
11
12
  removeCustomProvider,
12
13
  updateCustomProviderModel,
13
14
  saveModelPreferences,
@@ -76,6 +77,12 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
76
77
  refresh.afterCredentialChange();
77
78
  return result;
78
79
  },
80
+ async saveCustomProviderKey(providerId, secret) {
81
+ await awaitKeychainPrewarm();
82
+ const result = await saveCustomProviderKey(cfgMod, providerId, secret);
83
+ refresh.afterCredentialChange();
84
+ return result;
85
+ },
79
86
  async updateCustomProviderModel(providerId, modelId, patch) {
80
87
  const result = await updateCustomProviderModel(cfgMod, providerId, modelId, patch);
81
88
  refresh.afterCredentialChange();
@@ -14,6 +14,7 @@ import {
14
14
  effortConfigurationMode,
15
15
  } from '../../runtime/agent/orchestrator/providers/effort-configuration.mjs';
16
16
  import { getProvider } from '../../runtime/agent/orchestrator/providers/registry.mjs';
17
+ import { providerAvailable } from '../../runtime/agent/orchestrator/providers/provider-availability.mjs';
17
18
  import {
18
19
  DAYBREAK_PARAMETER_OPTION,
19
20
  DAYBREAK_PROVIDER,
@@ -96,7 +97,17 @@ export function createRowHydration({
96
97
  hydrateProviderModelRow: (row) => hydrateProviderModelRow(config(), row),
97
98
  sortProviderModels,
98
99
  providerModelCacheRow,
99
- providerModelsFromCacheRows: (rows) =>
100
- sortProviderModels((rows || []).map((row) => hydrateProviderModelRow(config(), row))),
100
+ // Cached rows outlive a Developer option switch, so availability is
101
+ // applied at read time, once per provider per call.
102
+ providerModelsFromCacheRows: (rows) => {
103
+ const availability = new Map();
104
+ const available = (provider) => {
105
+ if (!availability.has(provider)) availability.set(provider, providerAvailable(provider));
106
+ return availability.get(provider);
107
+ };
108
+ return sortProviderModels(
109
+ (rows || []).filter((row) => available(row.provider)).map((row) => hydrateProviderModelRow(config(), row))
110
+ );
111
+ },
101
112
  };
102
113
  }