mixdog 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/src/agents/reviewer/AGENT.md +3 -3
  6. package/src/agents/reviewer/agent.json +1 -1
  7. package/src/defaults/shipped-history.json +5 -0
  8. package/src/defaults/skills/pptx/SKILL.md +6 -6
  9. package/src/defaults/skills/pptx/references/review.md +6 -4
  10. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  11. package/src/defaults/skills/setup/references/actions.md +13 -3
  12. package/src/defaults/skills/visualize/SKILL.md +12 -9
  13. package/src/repl/slash-commands.mjs +16 -1
  14. package/src/rules/shared/60-verification.md +3 -1
  15. package/src/rules/shared/70-delivery.md +4 -2
  16. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  17. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  18. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  19. package/src/runtime/agent/orchestrator/config.mjs +10 -4
  20. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  21. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  22. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  23. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
  24. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
  25. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
  27. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  28. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  29. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  30. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  31. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  32. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  33. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  36. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
  41. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  42. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  43. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
  44. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  46. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  49. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  50. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  51. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
  53. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  58. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  59. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
  60. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
  61. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
  63. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  65. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  66. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
  68. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
  73. package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
  74. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  75. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
  76. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
  78. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
  79. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  80. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  81. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  82. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  83. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
  84. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
  85. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
  86. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
  87. package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
  88. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  89. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
  90. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  91. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  92. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  93. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  94. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
  95. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
  96. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  97. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  108. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
  109. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  110. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  111. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
  114. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
  115. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
  116. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
  117. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  119. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
  120. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
  121. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  122. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
  123. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  125. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
  126. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
  127. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  128. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
  130. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  132. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  133. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  134. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  135. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
  136. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
  137. package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
  138. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  139. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
  140. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  141. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  142. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  143. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  146. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  147. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  148. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  149. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  150. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
  151. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  154. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
  156. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  157. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  158. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
  159. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  160. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  161. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  162. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  163. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  164. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  165. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  166. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  167. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
  169. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
  170. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
  171. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
  172. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  173. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
  174. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
  175. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
  176. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
  177. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
  178. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
  179. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
  180. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  182. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  183. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
  184. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
  185. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  186. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  187. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  188. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  189. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  190. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
  191. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
  192. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
  193. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  194. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
  195. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  196. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  197. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
  198. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
  199. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  200. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  201. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  202. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  203. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  205. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  206. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  208. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
  209. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
  210. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  211. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  212. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  213. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  214. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  216. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  217. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  219. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  220. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  221. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  222. package/src/runtime/attachments/store.d.mts +3 -0
  223. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  224. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  225. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  226. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  227. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  228. package/src/runtime/memory/lib/memory.mjs +1 -1
  229. package/src/runtime/memory/lib/pg/process.mjs +34 -24
  230. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
  231. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  232. package/src/runtime/office/README.md +1 -1
  233. package/src/runtime/office/shared/values.mjs +0 -5
  234. package/src/runtime/shared/atomic-file.mjs +25 -4
  235. package/src/runtime/shared/background-tasks.mjs +92 -14
  236. package/src/runtime/shared/err-text.mjs +25 -0
  237. package/src/runtime/shared/error-presentation.mjs +159 -19
  238. package/src/runtime/shared/extension-scopes.mjs +5 -3
  239. package/src/runtime/shared/file-lock.mjs +37 -11
  240. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  241. package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
  242. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  243. package/src/runtime/shared/llm/model-catalog.mjs +53 -52
  244. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  245. package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
  246. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  247. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  248. package/src/runtime/shared/model-display.mjs +13 -0
  249. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  250. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  251. package/src/runtime/shared/pristine-execution.mjs +28 -4
  252. package/src/runtime/shared/provider-accounts.mjs +124 -20
  253. package/src/runtime/shared/provider-api-key.mjs +12 -0
  254. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  255. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  256. package/src/runtime/shared/shell-display.mjs +9 -3
  257. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  258. package/src/runtime/shared/skill-mentions.mjs +133 -0
  259. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  260. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  261. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  262. package/src/runtime/shared/tool-primitives.mjs +35 -2
  263. package/src/runtime/shared/turn-changes.mjs +447 -219
  264. package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
  265. package/src/runtime/shared/turn-snapshot.mjs +170 -48
  266. package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
  267. package/src/runtime/shared/worker-requests.mjs +15 -2
  268. package/src/runtime/shared/worktrees/contract.mjs +0 -24
  269. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  270. package/src/session-runtime/automation-agents.mjs +8 -2
  271. package/src/session-runtime/boot/apis.mjs +61 -0
  272. package/src/session-runtime/boot/config.mjs +5 -2
  273. package/src/session-runtime/boot/facade.mjs +1 -0
  274. package/src/session-runtime/boot/infrastructure.mjs +35 -18
  275. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  276. package/src/session-runtime/conversation-import/service.mjs +369 -0
  277. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
  278. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  279. package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
  280. package/src/session-runtime/lifecycle/teardown.mjs +1 -1
  281. package/src/session-runtime/mcp-glue/connect.mjs +83 -16
  282. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  283. package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
  284. package/src/session-runtime/mcp-glue.mjs +25 -2
  285. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  286. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  287. package/src/session-runtime/model-route/set-route.mjs +83 -15
  288. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  289. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  290. package/src/session-runtime/new-session-config.mjs +3 -2
  291. package/src/session-runtime/notification-bus.mjs +9 -2
  292. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  293. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  294. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  295. package/src/session-runtime/provider-readiness.mjs +16 -10
  296. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  297. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  298. package/src/session-runtime/resource-extension-sync.mjs +24 -5
  299. package/src/session-runtime/resource-mcp-api.mjs +198 -78
  300. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  301. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  302. package/src/session-runtime/resource-skills-api.mjs +23 -2
  303. package/src/session-runtime/runtime-review-api.mjs +13 -0
  304. package/src/session-runtime/schedule-session-run.mjs +1 -1
  305. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  306. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  307. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  308. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  310. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  311. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  312. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  313. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  314. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  315. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  316. package/src/session-runtime/services/provider-admin.mjs +64 -18
  317. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  318. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  319. package/src/session-runtime/setup-tool/executor.mjs +12 -1
  320. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  321. package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
  322. package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
  323. package/src/session-runtime/skills-api.mjs +7 -3
  324. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  325. package/src/session-runtime/webhook-session-run.mjs +16 -4
  326. package/src/skill-script-entry.mjs +36 -0
  327. package/src/standalone/daemon-drain-policy.mjs +8 -0
  328. package/src/standalone/daemon-stored-session-views.mjs +11 -3
  329. package/src/standalone/daemon-telemetry.mjs +55 -0
  330. package/src/standalone/daemon.mjs +44 -11
  331. package/src/standalone/session-protocol.mjs +12 -0
  332. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  333. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  334. package/src/standalone/session-service/agent-tree.mjs +12 -0
  335. package/src/standalone/session-service/quota-resume.mjs +8 -0
  336. package/src/standalone/session-service/retention/busy.mjs +15 -1
  337. package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
  338. package/src/standalone/session-service-api.mjs +5 -0
  339. package/src/standalone/session-service.mjs +1 -0
  340. package/src/tui/App.jsx +9 -1
  341. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  342. package/src/tui/app/app-view.jsx +7 -0
  343. package/src/tui/app/create-app-pickers.mjs +4 -0
  344. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  345. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  346. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  347. package/src/tui/app/extension-pickers.mjs +2 -1
  348. package/src/tui/app/model-options.mjs +13 -16
  349. package/src/tui/app/skill-mention-palette.mjs +88 -0
  350. package/src/tui/app/slash-commands.mjs +7 -2
  351. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  352. package/src/tui/app/slash-palette.mjs +23 -7
  353. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  354. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  355. package/src/tui/app/use-prompt-state.mjs +5 -0
  356. package/src/tui/components/Message.jsx +22 -1
  357. package/src/tui/components/PromptInput.jsx +21 -3
  358. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  359. package/src/tui/components/StatusLine.jsx +2 -0
  360. package/src/tui/components/TranscriptItem.jsx +9 -1
  361. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  362. package/src/tui/components/status-line/local-line.mjs +5 -2
  363. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  364. package/src/tui/components/user-message-skills.mjs +38 -0
  365. package/src/tui/dist/index.mjs +1323 -214
  366. package/src/tui/session/queue-helpers.mjs +7 -2
  367. package/src/tui/session/quota-resume.mjs +46 -14
  368. package/src/tui/session/session-api/commands.mjs +33 -24
  369. package/src/tui/session/session-api/extensions.mjs +26 -2
  370. package/src/tui/session/session-api/integrations.mjs +7 -0
  371. package/src/tui/session/session-api/lifecycle.mjs +5 -1
  372. package/src/tui/session/session-api/routes.mjs +71 -7
  373. package/src/tui/session/session-api/settings.mjs +12 -14
  374. package/src/tui/session/session-flow/drain.mjs +21 -5
  375. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  376. package/src/tui/session/tui-steering-persist.mjs +25 -9
  377. package/src/tui/session/turn.mjs +55 -15
  378. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  379. package/src/ui/statusline-agents.mjs +15 -4
  380. package/src/ui/statusline.mjs +7 -3
  381. package/src/ui/streaming-markdown-heal.mjs +34 -3
  382. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  383. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  384. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
  385. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  386. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
@@ -35,6 +35,10 @@ export async function runWebhookSession({
35
35
  workflow = null,
36
36
  attachments = null,
37
37
  signal = null,
38
+ // Endpoint-authored instructions: the run's ONLY skill-selection input.
39
+ // `prompt` also carries the fenced external payload, which must never
40
+ // select a skill; absent means nothing selects.
41
+ skillSelection = '',
38
42
  }) {
39
43
  const endpoint = String(name || '').trim();
40
44
  const body = String(prompt || '').trim();
@@ -63,9 +67,17 @@ export async function runWebhookSession({
63
67
  // askOpts.signal is the parent-abort link: it is cascaded onto the turn
64
68
  // controller, so aborting it stops the in-flight provider/tool work instead
65
69
  // of leaving a timed-out delivery's session running with live side effects.
66
- const ask = (turnContent) =>
67
- askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, signal ? { signal } : {});
68
- // Agents the run delegates to report back; each result is the next turn.
69
- const result = await runAutomationTurns(session.id, () => ask(content), ask);
70
+ const ask = (turnContent, askOpts) =>
71
+ askSession(session.id, turnContent, null, null, projectCwd || undefined, undefined, {
72
+ ...askOpts,
73
+ ...(signal ? { signal } : {}),
74
+ });
75
+ // Agents the run delegates to report back; each result is the next turn
76
+ // (runAutomationTurns marks those turns as task notifications).
77
+ const result = await runAutomationTurns(
78
+ session.id,
79
+ () => ask(content, { skillSelection: String(skillSelection ?? '') }),
80
+ ask
81
+ );
70
82
  return { sessionId: session.id, result: String(result?.content || '') };
71
83
  }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ // Entry the skill-script launcher runs (src/runtime/shared/skill-script-runtime.mjs):
3
+ // <runtime executable> skill-script-entry.mjs <script.mjs> [args...]
4
+ // The script then sees itself as the main module, exactly as under
5
+ // `node <script.mjs> [args...]`, and its exit code is the process's.
6
+
7
+ // Before anything can import sharp: Electron on Linux must use its wasm build.
8
+ await import('./runtime/shared/sharp-electron-linux.mjs');
9
+ // Node mode belongs to this process only; whatever the script starts is a
10
+ // normal child again.
11
+ delete process.env.ELECTRON_RUN_AS_NODE;
12
+
13
+ const { pathToFileURL } = await import('node:url');
14
+ const { canonicalSkillScriptPath, decodeSkillArgv, SKILL_ARGV_ENV } = await import(
15
+ './runtime/shared/skill-script-runtime.mjs'
16
+ );
17
+
18
+ // The PowerShell `mixdog-skill-node` function passes its arguments in the
19
+ // environment (see renderPowerShellSkillFunction); the script never sees them.
20
+ const envArgv = process.argv.length === 2 ? decodeSkillArgv(process.env[SKILL_ARGV_ENV]) : null;
21
+ delete process.env[SKILL_ARGV_ENV];
22
+ const [execPath, , target, ...args] = envArgv ? [process.argv[0], process.argv[1], ...envArgv] : process.argv;
23
+ if (!target) {
24
+ console.error('Usage: <skill launcher> <script.mjs> [args...]');
25
+ process.exitCode = 2;
26
+ } else {
27
+ const script = canonicalSkillScriptPath(target);
28
+ // The scripts' main check compares import.meta.url with argv[1].
29
+ process.argv = [execPath, script, ...args];
30
+ try {
31
+ await import(pathToFileURL(script).href);
32
+ } catch (error) {
33
+ console.error(error?.stack || String(error));
34
+ process.exitCode = 1;
35
+ }
36
+ }
@@ -1,3 +1,11 @@
1
+ /** Whether an idle GC sweep may start: no service call and no running turn
2
+ * (provider stream / tool call). Background-task-only sessions and memory
3
+ * agents do not block it — unlike drainDeferral, which guards shutdown. */
4
+ export function idleGcEligible(work) {
5
+ const { activeCalls = 0, queuedCalls = 0, turnBusySessions = 0 } = work || {};
6
+ return !(activeCalls > 0 || queuedCalls > 0 || turnBusySessions > 0);
7
+ }
8
+
1
9
  /** Whether self-shutdown must wait for in-flight work. A forced replacement
2
10
  * never waits: shutdown() aborts busy sessions, service calls and agent runs. */
3
11
  export function drainDeferral(work, { force = false } = {}) {
@@ -78,9 +78,17 @@ export function createStoredSessionViews({ desktopRuntime, dataDir }) {
78
78
  });
79
79
  }
80
80
  const store = await desktopRuntime.loadSessionStore();
81
- return store.listStoredSessionSummaries({
82
- refreshFromStorage: options.refreshFromStorage === true,
83
- });
81
+ const refreshFromStorage = options.refreshFromStorage === true;
82
+ // Paged ordinary catalog ({ sessions, nextCursor }) only on the explicit
83
+ // `page: { limit, cursor }` option (`limit` alone keeps its old meaning:
84
+ // ignored, full array). An authoritative refresh is never paged.
85
+ const page = options.page && typeof options.page === 'object' ? options.page : null;
86
+ if (page && !refreshFromStorage && store.listStoredSessionSummaryPage) {
87
+ return store.listStoredSessionSummaryPage({ limit: page.limit, cursor: page.cursor });
88
+ }
89
+ // The async listing may answer from the session catalog DB.
90
+ if (store.listStoredSessionSummariesAsync) return store.listStoredSessionSummariesAsync({ refreshFromStorage });
91
+ return store.listStoredSessionSummaries({ refreshFromStorage });
84
92
  },
85
93
  };
86
94
  }
@@ -93,6 +93,52 @@ export function collectDaemonTelemetry({
93
93
  };
94
94
  }
95
95
 
96
+ /**
97
+ * Tracks the smallest heapUsed observed right after a major GC (mark-sweep-
98
+ * compact) — the retained-set size, which heapUsed at an arbitrary instant
99
+ * hides. Sampled per telemetry interval; no per-GC logging. Returns null when
100
+ * PerformanceObserver is unavailable.
101
+ */
102
+ export function createPostGcHeapTracker({
103
+ heapUsed = () => v8.getHeapStatistics().used_heap_size,
104
+ observe = (onGc) => {
105
+ const obs = new PerformanceObserver((list) => {
106
+ for (const entry of list.getEntries()) onGc(entry);
107
+ });
108
+ obs.observe({ entryTypes: ['gc'] });
109
+ return () => obs.disconnect();
110
+ },
111
+ } = {}) {
112
+ let min = -1;
113
+ let disconnect = null;
114
+ try {
115
+ disconnect = observe((entry) => {
116
+ // NODE_PERFORMANCE_GC_MAJOR = 4 (older Node: entry.kind); newer: entry.detail.kind.
117
+ const kind = entry?.detail?.kind ?? entry?.kind;
118
+ if (kind !== 4) return;
119
+ const used = byteCount(heapUsed());
120
+ if (used >= 0 && (min < 0 || used < min)) min = used;
121
+ });
122
+ } catch {
123
+ return null;
124
+ }
125
+ return {
126
+ /** Min post-major-GC heap since the last take; -1 when none ran. */
127
+ take() {
128
+ const value = min;
129
+ min = -1;
130
+ return value;
131
+ },
132
+ stop() {
133
+ try {
134
+ disconnect?.();
135
+ } catch {
136
+ /* already gone */
137
+ }
138
+ },
139
+ };
140
+ }
141
+
96
142
  export function formatDaemonTelemetry(record, reason = 'periodic') {
97
143
  const row = record && typeof record === 'object' ? record : collectDaemonTelemetry();
98
144
  return [
@@ -110,6 +156,8 @@ export function formatDaemonTelemetry(record, reason = 'periodic') {
110
156
  `queuedCalls=${row.queuedCalls}`,
111
157
  `busySessions=${row.busySessions}`,
112
158
  `busyMemoryAgents=${row.busyMemoryAgents}`,
159
+ // Present only when a major GC ran since the previous line.
160
+ ...(byteCount(row.postGcHeapMinBytes) >= 0 ? [`postGcHeapMinBytes=${row.postGcHeapMinBytes}`] : []),
113
161
  ].join(' ');
114
162
  }
115
163
 
@@ -123,8 +171,10 @@ export function createDaemonTelemetry({
123
171
  heapStatistics,
124
172
  setIntervalFn = setInterval,
125
173
  clearIntervalFn = clearInterval,
174
+ createGcTracker = createPostGcHeapTracker,
126
175
  } = {}) {
127
176
  let timer = null;
177
+ let gcTracker = null;
128
178
 
129
179
  function emit(reason = 'periodic') {
130
180
  try {
@@ -141,6 +191,8 @@ export function createDaemonTelemetry({
141
191
  heapStatistics,
142
192
  work,
143
193
  });
194
+ const postGc = gcTracker?.take() ?? -1;
195
+ if (postGc >= 0) record.postGcHeapMinBytes = postGc;
144
196
  log(formatDaemonTelemetry(record, reason));
145
197
  return record;
146
198
  } catch {
@@ -159,6 +211,7 @@ export function createDaemonTelemetry({
159
211
 
160
212
  function start(intervalMs = DAEMON_TELEMETRY_INTERVAL_MS) {
161
213
  if (timer) return timer;
214
+ gcTracker ??= createGcTracker();
162
215
  const delay = Number(intervalMs);
163
216
  const ms = Number.isFinite(delay) && delay > 0 ? delay : DAEMON_TELEMETRY_INTERVAL_MS;
164
217
  const handle = setIntervalFn(() => {
@@ -174,6 +227,8 @@ export function createDaemonTelemetry({
174
227
  if (!timer) return;
175
228
  clearIntervalFn(timer);
176
229
  timer = null;
230
+ gcTracker?.stop();
231
+ gcTracker = null;
177
232
  }
178
233
 
179
234
  return { emit, start, stop };
@@ -49,6 +49,7 @@ import {
49
49
  startOwnerLivenessListener,
50
50
  } from './daemon-owner.mjs';
51
51
  import { remoteIntentPath } from '../runtime/shared/remote-intent.mjs';
52
+ import { modelProxyClientMode } from '../runtime/shared/model-proxy-mode.mjs';
52
53
  import { setChannelNotifySink } from '../runtime/channels/lib/parent-bridge.mjs';
53
54
  import { setOwnerContext } from '../runtime/channels/lib/runtime-paths.mjs';
54
55
  import { safeIpcSend } from '../runtime/shared/safe-ipc-send.mjs';
@@ -64,7 +65,7 @@ import {
64
65
  } from '../runtime/agent/orchestrator/providers/stream-json-pool.mjs';
65
66
  import { createAgentDispatchBroker } from './agent-dispatch-broker.mjs';
66
67
  import { createChannelTransport } from './channel-transport.mjs';
67
- import { drainDeferral } from './daemon-drain-policy.mjs';
68
+ import { drainDeferral, idleGcEligible } from './daemon-drain-policy.mjs';
68
69
  import { createChannelSessionRouter } from '../session-runtime/services/channel-session-router.mjs';
69
70
  import { createSessionTransport } from './session-transport.mjs';
70
71
  import { createSessionService } from './session-service.mjs';
@@ -144,6 +145,11 @@ let ownerLiveness = null;
144
145
  // The endpoints daemon.json carries once published; a heartbeat re-publishes
145
146
  // them when the file goes missing (TEMP cleanup).
146
147
  let publishedEndpoints = null;
148
+ // Remote mode only: the loopback relay that lets headless runs started from
149
+ // model shells (skill scripts) reach the PC behind this daemon's model proxy
150
+ // channel (providers/model-proxy-bridge.mjs), and its running-call count.
151
+ let modelProxyBridge = null;
152
+ let modelProxyBridgeActive = 0;
147
153
  const eventLoopDelay = monitorEventLoopDelay({ resolution: 20 });
148
154
  eventLoopDelay.enable();
149
155
  let idleGc = null;
@@ -218,6 +224,13 @@ async function shutdown(reason, code = 0) {
218
224
  try {
219
225
  setChannelNotifySink(null);
220
226
  } catch {}
227
+ // Abort every relayed model call, close the bridge sockets and wait for the
228
+ // calls to settle before anything they depend on goes away.
229
+ try {
230
+ await modelProxyBridge?.close(`daemon shutdown: ${reason}`);
231
+ } catch (e) {
232
+ log(`model proxy bridge stop failed: ${e?.message || e}`);
233
+ }
221
234
  try {
222
235
  await sessionService?.stop?.(reason);
223
236
  } catch (e) {
@@ -292,10 +305,11 @@ async function shutdown(reason, code = 0) {
292
305
  * asks whether this process may exit; idle GC asks whether a pause is safe. */
293
306
  function inFlightWork() {
294
307
  return {
295
- activeCalls: (transport?.activeCount ?? 0) + (sessionTransport?.activeCount ?? 0),
308
+ activeCalls: (transport?.activeCount ?? 0) + (sessionTransport?.activeCount ?? 0) + modelProxyBridgeActive,
296
309
  queuedCalls: (transport?.queuedCount ?? 0) + (sessionTransport?.queuedCount ?? 0),
297
310
  busySessions: sessionService?.busyCount ?? 0,
298
311
  busyMemoryAgents: agentDispatchBroker?.snapshot?.().inFlight ?? 0,
312
+ turnBusySessions: sessionService?.turnBusyCount ?? 0,
299
313
  };
300
314
  }
301
315
 
@@ -340,11 +354,6 @@ daemonTelemetry = createDaemonTelemetry({
340
354
  },
341
355
  });
342
356
 
343
- function daemonHasWorkInFlight() {
344
- const work = inFlightWork();
345
- return work.activeCalls > 0 || work.queuedCalls > 0 || work.busySessions > 0 || work.busyMemoryAgents > 0;
346
- }
347
-
348
357
  /** One process, two front doors (channels + sessions): an idle side must never
349
358
  * evict a busy one, so every self-shutdown trigger checks BOTH registries. */
350
359
  let _lastDeferredLog = { key: '', at: 0, suppressed: 0 };
@@ -562,9 +571,9 @@ function daemonStatusSnapshot() {
562
571
 
563
572
  /** The file every attacher reads to find this daemon: wire identity plus both
564
573
  * loopback endpoints and their privileged tokens. */
565
- function publishDaemonDiscovery({ channel, session }) {
574
+ function publishDaemonDiscovery({ channel, session, modelProxy = null }) {
566
575
  // A re-publish keeps the first publication's startedAt.
567
- publishedEndpoints = { channel, session, startedAt: publishedEndpoints?.startedAt ?? Date.now() };
576
+ publishedEndpoints = { channel, session, modelProxy, startedAt: publishedEndpoints?.startedAt ?? Date.now() };
568
577
  writeJsonAtomicSync(
569
578
  DAEMON_DISCOVERY_PATH,
570
579
  {
@@ -577,12 +586,34 @@ function publishDaemonDiscovery({ channel, session }) {
577
586
  endpoints: {
578
587
  channel: { port: channel.port, token: channel.token },
579
588
  session: { port: session.port, token: session.token },
589
+ ...(modelProxy ? { modelProxy: { port: modelProxy.port, token: modelProxy.token } } : {}),
580
590
  },
581
591
  },
582
592
  { compact: true, secret: true }
583
593
  );
584
594
  }
585
595
 
596
+ /** Remote mode only: the model proxy bridge endpoint to publish, or null. */
597
+ async function startModelProxyBridge(bootPhases) {
598
+ if (!modelProxyClientMode()) return null;
599
+ const [{ createModelProxyBridgeServer }, { getModelProxyChannel }] = await Promise.all([
600
+ import('../runtime/agent/orchestrator/providers/model-proxy-bridge.mjs'),
601
+ import('../runtime/agent/orchestrator/providers/model-proxy-channel.mjs'),
602
+ ]);
603
+ modelProxyBridge = createModelProxyBridgeServer({
604
+ channel: getModelProxyChannel(),
605
+ // Fenced or shutting down: no new relayed call.
606
+ admit: () => !shuttingDown && admitOwnerWork(),
607
+ trackWork: (active) => {
608
+ modelProxyBridgeActive = active;
609
+ },
610
+ log,
611
+ });
612
+ const endpoint = await bootPhases.measure('model-proxy-bridge-start', () => modelProxyBridge.start());
613
+ log(`model proxy bridge on 127.0.0.1:${endpoint.port}`);
614
+ return endpoint;
615
+ }
616
+
586
617
  /** Asked by both front doors before every register/call: an expired lease
587
618
  * fences here (answered 503), and after an event-loop stall nothing is
588
619
  * served until the record is re-verified as ours. */
@@ -598,6 +629,7 @@ function fenceDaemon(reason) {
598
629
  log(`${reason} — refusing new work and stopping so only one daemon serves`);
599
630
  sessionTransport?.commitDrain?.(reason);
600
631
  transport?.commitDrain?.(reason);
632
+ modelProxyBridge?.abortAll(reason);
601
633
  try {
602
634
  if (discoveryPid(DAEMON_DISCOVERY_PATH) === process.pid) rmSync(DAEMON_DISCOVERY_PATH, { force: true });
603
635
  } catch (e) {
@@ -787,7 +819,7 @@ async function main() {
787
819
  // Reclaim deferred garbage while nothing is in flight. V8 keeps a long-lived
788
820
  // daemon's dead transcripts resident for as long as the heap limit stays out
789
821
  // of sight; a measured sweep on this daemon returned 140MB in 98ms.
790
- idleGc = createIdleGc({ isBusy: daemonHasWorkInFlight, log });
822
+ idleGc = createIdleGc({ isBusy: () => !idleGcEligible(inFlightWork()), log });
791
823
  if (idleGc.arm()) log('idle gc armed');
792
824
 
793
825
  const channelsRuntime = createChannelsRuntimeLoader({
@@ -890,6 +922,7 @@ async function main() {
890
922
  admitWork: admitOwnerWork,
891
923
  });
892
924
  const sessionEndpoint = await bootPhases.measure('session-transport-start', () => sessionTransport.start());
925
+ const modelProxyEndpoint = await startModelProxyBridge(bootPhases);
893
926
  // A boot whose holder stopped answering may have been superseded by a
894
927
  // contender between beats; never publish over the winner's endpoint. An
895
928
  // unreadable record (an antivirus lock) is not a takeover.
@@ -900,7 +933,7 @@ async function main() {
900
933
  exitRecorder.setReason(`owner claim superseded by pid=${ownerPid} before publish`, 0);
901
934
  process.exit(0);
902
935
  }
903
- publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint });
936
+ publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint, modelProxy: modelProxyEndpoint });
904
937
  bootPhases.mark('discovery-published');
905
938
  log(`session front door on 127.0.0.1:${sessionEndpoint.port}`);
906
939
 
@@ -13,11 +13,13 @@ export const SESSION_READ_ACTIONS = Object.freeze([
13
13
  'getChannelSetup',
14
14
  'getChannelWorkerStatus',
15
15
  'getCompactionSettings',
16
+ 'getConversationImportJobs',
16
17
  'getDeveloperSettings',
17
18
  'getDisabledSkills',
18
19
  'getMediaDefault',
19
20
  'getMediaJob',
20
21
  'getMcpServerConfig',
22
+ 'getMcpOAuthLoginStatus',
21
23
  'getOnboardingStatus',
22
24
  'getOAuthProviderLoginStatus',
23
25
  'getOutputStyle',
@@ -57,6 +59,7 @@ export const SESSION_READ_ACTIONS = Object.freeze([
57
59
  'hooksStatus',
58
60
  'inheritancePreflight',
59
61
  'listAgents',
62
+ 'listImportableConversations',
60
63
  'listMediaAssets',
61
64
  'listMediaLanes',
62
65
  'listOutputStyles',
@@ -83,15 +86,19 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
83
86
  'agentControl',
84
87
  'authenticateProvider',
85
88
  'beginOAuthProviderLogin',
89
+ 'beginMcpOAuthLogin',
86
90
  'updateProviderAccounts',
87
91
  'cacheMediaThumbnail',
88
92
  'cancelMediaJob',
89
93
  'cancelOAuthProviderLogin',
94
+ 'cancelMcpOAuthLogin',
95
+ 'cancelConversationImport',
90
96
  'checkForUpdate',
91
97
  'clear',
92
98
  'compact',
93
99
  'completeOnboarding',
94
100
  'completeOAuthProviderLogin',
101
+ 'completeMcpOAuthLogin',
95
102
  'consumeCodexRateLimitResetCredit',
96
103
  'createWorkflow',
97
104
  'deleteAgentDefinition',
@@ -115,9 +122,11 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
115
122
  'memoryControl',
116
123
  'openMediaAsset',
117
124
  'openMediaFolder',
125
+ 'probeMcpServerAuth',
118
126
  'pushNotice',
119
127
  'recall',
120
128
  'reconnectMcp',
129
+ 'registerConversationImportFile',
121
130
  'reloadPlugins',
122
131
  'reloadSkills',
123
132
  'rememberPromptHistory',
@@ -139,6 +148,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
139
148
  'revertTurnReviewFile',
140
149
  'revertTurnChanges',
141
150
  'reapplyTurnChanges',
151
+ 'clearSessionChangeHistory',
142
152
  'rewindToItem',
143
153
  'runDoctor',
144
154
  'runScheduleNow',
@@ -196,8 +206,10 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
196
206
  'setWebhookEnabled',
197
207
  'setWorkflow',
198
208
  'setOrchestrationMode',
209
+ 'signOutMcpServer',
199
210
  'saveStarterGuideState',
200
211
  'skipOnboarding',
212
+ 'startConversationImport',
201
213
  'startMediaJob',
202
214
  'stopShellJob',
203
215
  'switchContext',
@@ -1,9 +1,29 @@
1
1
  // agent-tree/agent-cancel.mjs
2
2
  // Cancelling an agent subtree: descendants first, then a durable canonical
3
3
  // close of the session itself. Concurrent cancels of one id share a run.
4
- import { cancelBackgroundTasks } from '../../../runtime/shared/background-tasks.mjs';
4
+ import {
5
+ cancelBackgroundTask,
6
+ cancelBackgroundTasks,
7
+ listBackgroundTasks,
8
+ } from '../../../runtime/shared/background-tasks.mjs';
5
9
 
6
- export function createAgentCancellation({ registry, rehydrateAgentSessions, sessionOwner, entryForSession, log }) {
10
+ // Cancel the running Agent task(s) bound to this session itself (owned by its
11
+ // parent) BEFORE the session closes, so the owner hears `cancelled` with the
12
+ // turn's partial output instead of the closed turn failing the task.
13
+ function cancelOwnAgentTasks(sessionId, reason) {
14
+ for (const row of listBackgroundTasks({ surface: 'agent' })) {
15
+ if (row.status === 'running' && row.sessionId === sessionId) cancelBackgroundTask(row.task_id, reason);
16
+ }
17
+ }
18
+
19
+ export function createAgentCancellation({
20
+ registry,
21
+ rehydrateAgentSessions,
22
+ sessionOwner,
23
+ entryForSession,
24
+ log,
25
+ rememberCancelTranscript,
26
+ }) {
7
27
  const agentCancelRuns = new Map();
8
28
 
9
29
  /** The runtime entry that can close this descriptor: the live owner, else a
@@ -39,6 +59,7 @@ export function createAgentCancellation({ registry, rehydrateAgentSessions, sess
39
59
  });
40
60
  const children = registry.childrenOf(id);
41
61
  await Promise.all(children.map((childId) => cancelAgentTree(childId, reason)));
62
+ cancelOwnAgentTasks(id, reason);
42
63
  const descriptor = registry.get(id);
43
64
  if (!descriptor) return children.length > 0;
44
65
  if (descriptor.closed) return true;
@@ -47,6 +68,16 @@ export function createAgentCancellation({ registry, rehydrateAgentSessions, sess
47
68
  if (typeof closeCanonical !== 'function') {
48
69
  throw new TypeError('session runtime must implement closeCanonicalSession');
49
70
  }
71
+ // The close clears the transcript: capture a running turn's transcript
72
+ // first so the cancelled turn still hands off its partial output.
73
+ if (descriptor.status === 'running') {
74
+ try {
75
+ const { messages } = await entry.runtime.readModelMessages(0);
76
+ rememberCancelTranscript(id, messages);
77
+ } catch (error) {
78
+ log(`agent cancel transcript read failed session=${id}: ${error?.message || error}`);
79
+ }
80
+ }
50
81
  const closed = await closeCanonical.call(entry.runtime, reason);
51
82
  if (closed !== true) throw new Error(`agent session ${id} could not be durably closed`);
52
83
  descriptor.closed = true;
@@ -12,16 +12,23 @@ export function createAgentTurns({
12
12
  retainUnwatched,
13
13
  createSession,
14
14
  takeWatchdogStop,
15
+ takeCancelTranscript,
15
16
  }) {
16
17
  const createAgentChild = createAgentChildFactory({ registry, rehydrateAgentSessions, createSession });
17
18
 
18
- // The progress watchdog stopped the turn: rethrow its stall error carrying
19
- // the assistant text the turn produced, so the owner still gets a partial
20
- // result.
21
- async function watchdogStopError(runtime, error, messageStart) {
22
- const { messages } = await runtime.readModelMessages(messageStart);
23
- const partial = partialHandoffTextFromSession({ messages });
24
- if (partial) error.partialHandoff = partial;
19
+ // The turn was stopped (progress watchdog or cancellation): rethrow its error
20
+ // carrying the assistant text the turn produced, so the owner still gets a
21
+ // partial result. A cancel that closed the session captured the transcript
22
+ // before the close cleared it.
23
+ async function withPartialHandoff(runtime, sessionId, error, messageStart) {
24
+ try {
25
+ const captured = takeCancelTranscript(sessionId);
26
+ const messages = captured
27
+ ? captured.slice(messageStart)
28
+ : (await runtime.readModelMessages(messageStart)).messages;
29
+ const partial = partialHandoffTextFromSession({ messages });
30
+ if (partial) error.partialHandoff = partial;
31
+ } catch {}
25
32
  return error;
26
33
  }
27
34
 
@@ -44,6 +51,7 @@ export function createAgentTurns({
44
51
  }
45
52
  // A stop left over from an earlier turn must not relabel this one.
46
53
  takeWatchdogStop(sessionId);
54
+ takeCancelTranscript(sessionId);
47
55
  // Transcript length before this turn: where a watchdog stop's partial
48
56
  // output starts.
49
57
  const { messageCount: messageStart } = await entry.runtime.readModelMessages(Number.MAX_SAFE_INTEGER);
@@ -64,9 +72,16 @@ export function createAgentTurns({
64
72
  throw new Error(String(detail.error || 'agent session turn failed'));
65
73
  }
66
74
  if (detail?.status === 'cancelled') {
67
- const watchdogStop = takeWatchdogStop(sessionId);
68
- if (watchdogStop) throw await watchdogStopError(entry.runtime, watchdogStop, messageStart);
69
- throw new Error('agent session turn cancelled');
75
+ const stop = takeWatchdogStop(sessionId) || new Error('agent session turn cancelled');
76
+ throw await withPartialHandoff(entry.runtime, sessionId, stop, messageStart);
77
+ }
78
+ // Only a completed turn has a result; a rejected submission (session
79
+ // closing/terminal, steering persist failure) or any unknown status is a
80
+ // failure, never an empty completion.
81
+ if (detail?.status !== 'done' && detail?.status !== 'completed') {
82
+ const status = String(detail?.status || 'unknown');
83
+ const reason = String(detail?.reason || detail?.error || '').trim();
84
+ throw new Error(`agent turn ${status}${reason ? `: ${reason}` : ''}`);
70
85
  }
71
86
  const result = detail?.result || { content: '' };
72
87
  descriptor.status = 'idle';
@@ -81,6 +96,7 @@ export function createAgentTurns({
81
96
  descriptor.stage = descriptor.status;
82
97
  throw error;
83
98
  } finally {
99
+ takeCancelTranscript(sessionId);
84
100
  descriptor.updatedAt = Date.now();
85
101
  retainUnwatched(entry, 'agent child idle');
86
102
  }
@@ -37,6 +37,16 @@ export function createAgentTree({
37
37
  watchdogStops.delete(sessionId);
38
38
  return error;
39
39
  };
40
+ // Transcripts of running turns captured by a cancel just before it closes
41
+ // (and clears) the session, so the cancelled turn still reports the output
42
+ // it produced.
43
+ const cancelTranscripts = new Map();
44
+ const rememberCancelTranscript = (sessionId, messages) => cancelTranscripts.set(sessionId, messages);
45
+ const takeCancelTranscript = (sessionId) => {
46
+ const messages = cancelTranscripts.get(sessionId) || null;
47
+ cancelTranscripts.delete(sessionId);
48
+ return messages;
49
+ };
40
50
  function getSessionProgressSnapshot(sessionId) {
41
51
  const runtime = sessionOwner(sessionId)?.runtime;
42
52
  if (typeof runtime?.getTurnLiveness !== 'function') return null;
@@ -58,6 +68,7 @@ export function createAgentTree({
58
68
  retainUnwatched,
59
69
  createSession,
60
70
  takeWatchdogStop,
71
+ takeCancelTranscript,
61
72
  });
62
73
  const { cancelAgentTree, cancelAgentDescendants } = createAgentCancellation({
63
74
  registry,
@@ -65,6 +76,7 @@ export function createAgentTree({
65
76
  sessionOwner,
66
77
  entryForSession,
67
78
  log,
79
+ rememberCancelTranscript,
68
80
  });
69
81
 
70
82
  /** The descriptor as callers see it: status from the live runtime when one
@@ -8,6 +8,8 @@
8
8
  // again, and the session's own lane runs the retry under the entry's
9
9
  // generation. Overdue entries run as soon as the scheduler starts.
10
10
 
11
+ import { isAgentOnlySession } from '../../runtime/shared/quota-resume-store.mjs';
12
+
11
13
  /** A still-exhausted reading is re-taken once, this much later. */
12
14
  export const QUOTA_RESUME_RETRY_MS = 5 * 60_000;
13
15
  /** A busy session is re-checked this much later, without spending an attempt. */
@@ -30,6 +32,12 @@ async function resumeDueEntry(entry, { store, materializeSession, readQuotaUsabl
30
32
  return 'unavailable';
31
33
  }
32
34
  if (!isCurrent(store, entry)) return 'cancelled';
35
+ // A delegated agent child never owns a resume (the Lead decides retries), so
36
+ // an entry persisted for one never fires, whatever wrote it.
37
+ if (isAgentOnlySession({ id: sessionId, ...runtime?.session })) {
38
+ store.cancelQuotaResumeEntry(sessionId, { generation });
39
+ return 'agent-session';
40
+ }
33
41
  let usable = false;
34
42
  try {
35
43
  usable = await readQuotaUsable(entry.provider, entry.model);
@@ -28,6 +28,12 @@ export function createBusyTracker({ sessions, currentSessionId }) {
28
28
  // reaches a terminal state and its completion can be delivered back into
29
29
  // this session.
30
30
  if (sessionId && hasActiveBackgroundTasks({ callerSessionId: sessionId })) return true;
31
+ return sessionTurnBusy(entry);
32
+ }
33
+
34
+ // A turn is running (provider stream / tool call / queued input). Background
35
+ // tasks are deliberately not counted: they run outside the heap-churning turn.
36
+ function sessionTurnBusy(entry) {
31
37
  if (typeof entry?.busy === 'boolean') return entry.busy;
32
38
  try {
33
39
  return updateEntryBusy(entry, entry.runtime.getState?.() || {});
@@ -46,5 +52,13 @@ export function createBusyTracker({ sessions, currentSessionId }) {
46
52
  return count;
47
53
  }
48
54
 
49
- return { stateBusy, updateEntryBusy, sessionBusy, liveBusyCount };
55
+ function liveTurnBusyCount() {
56
+ let count = 0;
57
+ for (const entry of sessions) {
58
+ if (sessionTurnBusy(entry)) count += 1;
59
+ }
60
+ return count;
61
+ }
62
+
63
+ return { stateBusy, updateEntryBusy, sessionBusy, liveBusyCount, liveTurnBusyCount };
50
64
  }
@@ -101,15 +101,20 @@ export function createSessionActionCalls(ctx) {
101
101
  if (typeof listSessions !== 'function') {
102
102
  throw new Error('session catalog is unavailable');
103
103
  }
104
- const sessions = await listSessions({
104
+ const listed = await listSessions({
105
105
  ...(options || {}),
106
106
  // Agent-only records are an internal ancestry/reuse source, never part
107
107
  // of the ordinary session catalog returned over the public transport.
108
108
  includeAgentOnly: false,
109
109
  });
110
+ // A `page: { limit, cursor }` request answers one page: { sessions, nextCursor }.
111
+ const page = listed && !Array.isArray(listed) && Array.isArray(listed.sessions) ? listed : null;
112
+ const sessions = page ? page.sessions : listed;
110
113
  const remoteSession = typeof getRemoteSessionState === 'function' ? await getRemoteSessionState() : null;
114
+ const nextCursor = typeof page?.nextCursor === 'string' ? page.nextCursor : null;
111
115
  return {
112
116
  sessions: sanitizeForWire(Array.isArray(sessions) ? sessions : []),
117
+ ...(page ? { nextCursor } : {}),
113
118
  remoteSession: sanitizeForWire(remoteSession) ?? null,
114
119
  };
115
120
  }
@@ -29,6 +29,7 @@ export function createSessionServiceApi({
29
29
  methods,
30
30
  getSize,
31
31
  getBusyCount,
32
+ getTurnBusyCount,
32
33
  getStatus,
33
34
  getExternalClientCount,
34
35
  }) {
@@ -46,6 +47,10 @@ export function createSessionServiceApi({
46
47
  get busyCount() {
47
48
  return getBusyCount();
48
49
  },
50
+ /** Sessions with a running turn; background-task-only sessions excluded. */
51
+ get turnBusyCount() {
52
+ return getTurnBusyCount();
53
+ },
49
54
  get status() {
50
55
  return getStatus();
51
56
  },