mixdog 1.1.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (424) hide show
  1. package/README.md +8 -5
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +10 -0
  7. package/src/defaults/skills/pptx/SKILL.md +6 -6
  8. package/src/defaults/skills/pptx/references/review.md +6 -4
  9. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  10. package/src/defaults/skills/setup/references/actions.md +18 -5
  11. package/src/defaults/skills/visualize/SKILL.md +160 -0
  12. package/src/defaults/skills/visualize/references/craft.md +88 -0
  13. package/src/headless-command.mjs +56 -3
  14. package/src/headless-exec.mjs +17 -1
  15. package/src/help.mjs +2 -0
  16. package/src/rules/shared/60-verification.md +3 -1
  17. package/src/rules/shared/70-delivery.md +4 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  22. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  24. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +19 -5
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
  33. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  34. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  35. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  36. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  43. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  45. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  50. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
  51. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  52. package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
  53. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  56. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  57. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  58. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  59. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  60. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  61. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
  62. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  64. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  66. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
  67. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
  77. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
  78. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  79. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  80. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
  81. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  83. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
  85. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  87. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  88. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  90. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  91. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  92. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  93. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
  94. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  95. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  96. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  97. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
  98. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  99. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  100. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  101. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  102. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  103. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  104. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  105. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  106. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  107. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  108. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  109. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  112. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  114. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
  115. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
  116. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
  124. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  125. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  126. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
  128. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  131. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  133. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  136. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  137. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  138. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
  139. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  140. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  141. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  142. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  143. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  144. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
  145. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
  146. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
  147. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  148. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
  149. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  150. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  151. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
  153. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  155. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  157. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  158. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  159. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  160. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  161. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  162. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
  163. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  164. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  165. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  166. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  167. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
  168. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  169. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  175. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  176. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  177. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  179. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  180. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  181. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  182. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  184. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  185. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  186. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  187. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  188. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  189. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  190. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  191. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  192. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  193. package/src/runtime/attachments/store.d.mts +3 -0
  194. package/src/runtime/attachments/store.mjs +38 -0
  195. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  196. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  197. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  199. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  200. package/src/runtime/memory/lib/memory.mjs +1 -1
  201. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  202. package/src/runtime/shared/atomic-file.mjs +33 -6
  203. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  204. package/src/runtime/shared/code-graph-state.mjs +12 -0
  205. package/src/runtime/shared/defaults-separation.mjs +2 -0
  206. package/src/runtime/shared/extension-scopes.mjs +5 -3
  207. package/src/runtime/shared/file-lock.mjs +37 -11
  208. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  209. package/src/runtime/shared/git-runner.mjs +4 -3
  210. package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
  211. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  212. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  213. package/src/runtime/shared/llm/model-catalog.mjs +240 -130
  214. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  215. package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
  216. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  217. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  218. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  219. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  220. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  221. package/src/runtime/shared/pristine-execution.mjs +28 -4
  222. package/src/runtime/shared/provider-accounts.mjs +125 -21
  223. package/src/runtime/shared/provider-api-key.mjs +33 -1
  224. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  225. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  226. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  227. package/src/runtime/shared/shell-display.mjs +9 -3
  228. package/src/runtime/shared/singleton-owner.mjs +36 -6
  229. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  230. package/src/runtime/shared/skill-mentions.mjs +133 -0
  231. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  232. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  233. package/src/runtime/shared/tool-primitives.mjs +35 -2
  234. package/src/runtime/shared/tool-surface.mjs +7 -0
  235. package/src/runtime/shared/tool-work-units.mjs +14 -0
  236. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  237. package/src/runtime/shared/turn-changes.mjs +791 -0
  238. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  239. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  240. package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
  241. package/src/runtime/shared/worker-requests.mjs +15 -2
  242. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  243. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  244. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  245. package/src/runtime/shared/worktrees/git.mjs +247 -0
  246. package/src/runtime/shared/worktrees/include.mjs +480 -0
  247. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  248. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  249. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  250. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  251. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  252. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  253. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  254. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  255. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  256. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  257. package/src/runtime/visualize-bridge/client.mjs +181 -0
  258. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  259. package/src/session-runtime/automation-agents.mjs +8 -2
  260. package/src/session-runtime/boot/apis.mjs +90 -0
  261. package/src/session-runtime/boot/config.mjs +7 -2
  262. package/src/session-runtime/boot/facade.mjs +21 -0
  263. package/src/session-runtime/boot/infrastructure.mjs +30 -18
  264. package/src/session-runtime/boot/session.mjs +1 -0
  265. package/src/session-runtime/boot/tools.mjs +4 -0
  266. package/src/session-runtime/config-lifecycle.mjs +10 -1
  267. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  268. package/src/session-runtime/conversation-import/service.mjs +369 -0
  269. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
  270. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  271. package/src/session-runtime/global-extensions.mjs +2 -2
  272. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  273. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  274. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  275. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  276. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  277. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  278. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  279. package/src/session-runtime/mcp-glue/connect.mjs +68 -16
  280. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  281. package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
  282. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  283. package/src/session-runtime/mcp-glue.mjs +22 -2
  284. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  285. package/src/session-runtime/model-route/set-route.mjs +15 -2
  286. package/src/session-runtime/new-session-config.mjs +3 -2
  287. package/src/session-runtime/notification-bus.mjs +18 -3
  288. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  289. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  290. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  291. package/src/session-runtime/provider-readiness.mjs +16 -10
  292. package/src/session-runtime/resource-extension-sync.mjs +45 -7
  293. package/src/session-runtime/resource-mcp-api.mjs +121 -84
  294. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  295. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  296. package/src/session-runtime/resource-skills-api.mjs +23 -2
  297. package/src/session-runtime/route-resolution.mjs +10 -1
  298. package/src/session-runtime/route-state.mjs +16 -2
  299. package/src/session-runtime/runtime-core.mjs +5 -0
  300. package/src/session-runtime/runtime-facade.mjs +8 -0
  301. package/src/session-runtime/runtime-review-api.mjs +9 -0
  302. package/src/session-runtime/schedule-session-run.mjs +1 -1
  303. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  304. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  305. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  306. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  307. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  308. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  310. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  311. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  312. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  313. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  314. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  315. package/src/session-runtime/services/agent-tool.mjs +1 -0
  316. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  317. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  318. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  319. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  320. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  321. package/src/session-runtime/services/provider-admin.mjs +64 -18
  322. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  323. package/src/session-runtime/session-create/session-options.mjs +10 -1
  324. package/src/session-runtime/session-turn-api.mjs +1 -0
  325. package/src/session-runtime/settings-api.mjs +4 -2
  326. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  327. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  328. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  329. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  330. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
  331. package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
  332. package/src/session-runtime/skills-api.mjs +7 -3
  333. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  334. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
  335. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  336. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  337. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  338. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  339. package/src/session-runtime/turn/turn-run.mjs +6 -7
  340. package/src/session-runtime/webhook-session-run.mjs +16 -4
  341. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  342. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  343. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  344. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  345. package/src/session-runtime/workspace/transitions.mjs +651 -0
  346. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  347. package/src/skill-script-entry.mjs +36 -0
  348. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  349. package/src/standalone/channel-transport.mjs +13 -1
  350. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  351. package/src/standalone/daemon-owner.mjs +372 -0
  352. package/src/standalone/daemon-stored-session-views.mjs +15 -4
  353. package/src/standalone/daemon.mjs +179 -8
  354. package/src/standalone/desktop-service-registry.mjs +20 -0
  355. package/src/standalone/local-session-runtime.mjs +11 -0
  356. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  357. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  358. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  359. package/src/standalone/session-client.mjs +104 -13
  360. package/src/standalone/session-protocol.mjs +21 -0
  361. package/src/standalone/session-proxy.mjs +3 -0
  362. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  363. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  364. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  365. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  366. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  367. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  368. package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
  369. package/src/standalone/session-transport/call-route.mjs +13 -0
  370. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  371. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  372. package/src/standalone/session-transport/client-registry.mjs +20 -3
  373. package/src/standalone/session-transport/routes.mjs +79 -2
  374. package/src/standalone/session-transport/stack.mjs +2 -0
  375. package/src/standalone/session-transport.mjs +24 -1
  376. package/src/tui/App.jsx +9 -1
  377. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  378. package/src/tui/app/app-view.jsx +6 -0
  379. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  380. package/src/tui/app/message-selector.mjs +2 -1
  381. package/src/tui/app/model-options.mjs +37 -5
  382. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  383. package/src/tui/app/model-picker.mjs +4 -2
  384. package/src/tui/app/skill-mention-palette.mjs +88 -0
  385. package/src/tui/app/slash-palette.mjs +23 -7
  386. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  387. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  388. package/src/tui/app/use-prompt-state.mjs +5 -0
  389. package/src/tui/components/Message.jsx +22 -1
  390. package/src/tui/components/PromptInput.jsx +21 -3
  391. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  392. package/src/tui/components/TranscriptItem.jsx +9 -1
  393. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  394. package/src/tui/components/user-message-skills.mjs +38 -0
  395. package/src/tui/dist/index.mjs +839 -207
  396. package/src/tui/index.jsx +10 -2
  397. package/src/tui/session/compaction-view.mjs +147 -0
  398. package/src/tui/session/context-state.mjs +6 -0
  399. package/src/tui/session/initial-state.mjs +3 -0
  400. package/src/tui/session/queue-helpers.mjs +7 -2
  401. package/src/tui/session/quota-resume.mjs +2 -1
  402. package/src/tui/session/session-api/commands.mjs +10 -2
  403. package/src/tui/session/session-api/controls.mjs +4 -0
  404. package/src/tui/session/session-api/extensions.mjs +4 -2
  405. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  406. package/src/tui/session/session-api/integrations.mjs +17 -0
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  408. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  409. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  410. package/src/tui/session/session-api/routes.mjs +10 -1
  411. package/src/tui/session/session-api/settings.mjs +9 -0
  412. package/src/tui/session/session-api/worktree.mjs +60 -0
  413. package/src/tui/session/session-api.mjs +2 -0
  414. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  415. package/src/tui/session/session-flow/drain.mjs +27 -3
  416. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  417. package/src/tui/session/session-flow.mjs +2 -0
  418. package/src/tui/session/transcript-intake.mjs +14 -5
  419. package/src/tui/session/tui-steering-persist.mjs +25 -9
  420. package/src/tui/session/turn-stream.mjs +32 -4
  421. package/src/tui/session/turn-tool-cards.mjs +10 -2
  422. package/src/tui/session/turn.mjs +56 -10
  423. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  424. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
@@ -0,0 +1,25 @@
1
+ // The MCP SDK Client compiles every tool's outputSchema with Ajv inside
2
+ // listTools(), synchronously: a server listing ~180 tools held the daemon's
3
+ // event loop for 1-2 s on every connect. This validator compiles each schema
4
+ // on the tool's first structured result instead, and creates the SDK's Ajv
5
+ // validator (same options and error text) on first use too.
6
+ // A schema declaring an `$id` anywhere registers it in the client's Ajv, and a
7
+ // schema referencing anything outside itself resolves against what is
8
+ // registered by then (failing the listing when it is not); both still compile
9
+ // when listed, in listing order, exactly as the SDK does.
10
+ const LISTING_ORDER_SCHEMA = /"\$id"|"\$ref":"(?!#)/;
11
+
12
+ export function createLazyOutputValidator(AjvJsonSchemaValidator) {
13
+ let provider = null;
14
+ const shared = () => (provider ??= new AjvJsonSchemaValidator());
15
+ return {
16
+ getValidator(schema) {
17
+ if (LISTING_ORDER_SCHEMA.test(JSON.stringify(schema))) return shared().getValidator(schema);
18
+ let validate = null;
19
+ return (input) => {
20
+ validate ??= shared().getValidator(schema);
21
+ return validate(input);
22
+ };
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * mcp/plugin-placeholders.mjs — plugin root/data placeholders in an MCP server
3
+ * config. Pure: no filesystem access; the caller supplies the directories.
4
+ */
5
+
6
+ const ROOT_NAMES = ['CLAUDE_PLUGIN_ROOT', 'CODEX_PLUGIN_ROOT', 'PLUGIN_ROOT', 'MIXDOG_PLUGIN_ROOT'];
7
+ const DATA_NAMES = ['CLAUDE_PLUGIN_DATA', 'PLUGIN_DATA', 'MIXDOG_PLUGIN_DATA'];
8
+ const PLACEHOLDER_RE = new RegExp(`\\$\\{(${[...ROOT_NAMES, ...DATA_NAMES].join('|')})\\}`, 'g');
9
+ const CONFIG_FIELDS = ['command', 'args', 'env', 'url', 'headers', 'cwd'];
10
+
11
+ // Substituted paths use forward slashes on Windows so a path that lands in a
12
+ // command line or argument is not read as backslash escapes; Windows accepts
13
+ // them everywhere.
14
+ function normalizePath(path, platform) {
15
+ return platform === 'win32' ? path.replace(/\\/g, '/') : path;
16
+ }
17
+
18
+ function substitute(value, replacements) {
19
+ if (typeof value === 'string') {
20
+ // Function replacement: `$` sequences in paths are inserted literally.
21
+ return value.replace(PLACEHOLDER_RE, (match, name) => replacements.get(name) ?? match);
22
+ }
23
+ if (Array.isArray(value)) return value.map((v) => substitute(v, replacements));
24
+ if (value && typeof value === 'object') {
25
+ const out = {};
26
+ for (const [k, v] of Object.entries(value)) out[k] = substitute(v, replacements);
27
+ return out;
28
+ }
29
+ return value;
30
+ }
31
+
32
+ /**
33
+ * Returns a copy of `config` with plugin root/data placeholders replaced in
34
+ * command, args, env, url, headers and cwd. A placeholder whose directory is
35
+ * not supplied is left as written. Run before ordinary env expansion.
36
+ */
37
+ export function resolvePluginPlaceholders(config, { root, data, platform = process.platform } = {}) {
38
+ const replacements = new Map();
39
+ if (root) for (const name of ROOT_NAMES) replacements.set(name, normalizePath(String(root), platform));
40
+ if (data) for (const name of DATA_NAMES) replacements.set(name, normalizePath(String(data), platform));
41
+ const out = { ...config };
42
+ for (const field of CONFIG_FIELDS) {
43
+ if (out[field] !== undefined) out[field] = substitute(out[field], replacements);
44
+ }
45
+ return out;
46
+ }
47
+
48
+ /** Environment variables a plugin-owned server process receives (raw paths). */
49
+ export function pluginServerEnv({ root, data } = {}) {
50
+ const env = {};
51
+ if (root) for (const name of ['CLAUDE_PLUGIN_ROOT', 'MIXDOG_PLUGIN_ROOT', 'PLUGIN_ROOT']) env[name] = String(root);
52
+ if (data) for (const name of ['CLAUDE_PLUGIN_DATA', 'MIXDOG_PLUGIN_DATA', 'PLUGIN_DATA']) env[name] = String(data);
53
+ return env;
54
+ }
@@ -13,6 +13,10 @@ export function createKeyedSingleflight() {
13
13
  pending.set(lane, tracked);
14
14
  return tracked;
15
15
  },
16
+ /** The in-flight task promise for `key`, or undefined. */
17
+ wait(key) {
18
+ return pending.get(String(key || ''));
19
+ },
16
20
  has(key) {
17
21
  return pending.has(String(key || ''));
18
22
  },
@@ -3,9 +3,11 @@ import {
3
3
  accountScopedSessionId,
4
4
  readProviderAccountPool,
5
5
  chooseProviderAccount,
6
- changeProviderAccounts,
6
+ selectProviderAccountIf,
7
7
  blockProviderAccount,
8
8
  providerAccountExhausted,
9
+ providerAccountExhaustedForModelOnly,
10
+ providerAccountPolicy,
9
11
  providerAccountsResetAt,
10
12
  } from '../../../shared/provider-accounts.mjs';
11
13
  import { withProviderAccount, hasExplicitProviderAuthBinding } from '../../../shared/provider-auth-binding.mjs';
@@ -116,13 +118,82 @@ function boundAccountSend(providerName, row, messages, options) {
116
118
  return { opts, history, emitted: () => emitted };
117
119
  }
118
120
 
119
- // Commit only a successful fallback, without overwriting a newer selection.
120
- function commitFallbackAccount(providerName, pool, row) {
121
- if (row.id === pool.selectedId) return;
122
- const current = readProviderAccountPool(providerName);
123
- if (current.selectedId === pool.selectedId && current.accounts.some((entry) => entry.id === row.id)) {
124
- return changeProviderAccounts(providerName, { selectedId: row.id });
121
+ // Commit only a successful fallback, without overwriting a newer selection:
122
+ // the selection is compared under the write's lock, not before it. A fallback
123
+ // forced by a model-scoped limit ("7D Fable" full, or a block attributed to
124
+ // one family) serves this request only: the selected account still serves
125
+ // every other model, so it stays the provider's account of record.
126
+ async function commitFallbackAccount(providerName, pool, row, model, refusalScoped, policy) {
127
+ if (row.id === pool.selectedId || refusalScoped) return null;
128
+ if (accountExhaustedForModelOnly(providerName, pool.selectedId, model)) return null;
129
+ return selectProviderAccountIf(providerName, pool.selectedId, row.id, policy);
130
+ }
131
+
132
+ // The account each session runs on under the headroom policy. Every answer
133
+ // records its provider and account in the assistant message's
134
+ // `providerMetadata` (and in provider state when the adapter keeps one), so
135
+ // the binding survives a restart and eviction from this map, which only
136
+ // spares the history walk. Bounded, oldest binding first out.
137
+ const SESSION_ACCOUNT_LIMIT = 1000;
138
+ const ROUTING_METADATA_KEY = 'accountRouting';
139
+ const sessionAccounts = new Map();
140
+
141
+ // Forget every in-memory binding, as a restart does (tests).
142
+ export function resetSessionAccountBindings() {
143
+ sessionAccounts.clear();
144
+ }
145
+
146
+ function rememberSessionAccount(key, id) {
147
+ sessionAccounts.delete(key);
148
+ sessionAccounts.set(key, id);
149
+ if (sessionAccounts.size > SESSION_ACCOUNT_LIMIT) sessionAccounts.delete(sessionAccounts.keys().next().value);
150
+ }
151
+
152
+ function accountExhaustedForModelOnly(providerName, id, model) {
153
+ const pool = readProviderAccountPool(providerName);
154
+ const row = pool.accounts.find((entry) => entry.id === id);
155
+ return (
156
+ Boolean(row) &&
157
+ providerAccountExhaustedForModelOnly(row, Date.now(), model, { useCredits: pool.useCredits === true })
158
+ );
159
+ }
160
+
161
+ // Only a binding recorded for THIS provider counts: a session that switched
162
+ // providers carries another roster's account ids (every roster has a `default`).
163
+ // The session's binding is read before the serving account, which differs
164
+ // when a model-scoped limit lent this one answer to another account.
165
+ function sessionAccountId(providerName, key, messages, options) {
166
+ if (key && sessionAccounts.has(key)) return sessionAccounts.get(key);
167
+ const state = options.providerState;
168
+ if (state?.providerAccountId && state.providerAccountProvider === providerName) {
169
+ return state.providerSessionAccountId || state.providerAccountId;
170
+ }
171
+ for (let index = (messages?.length || 0) - 1; index >= 0; index -= 1) {
172
+ const routing = messages[index]?.providerMetadata?.[ROUTING_METADATA_KEY];
173
+ if (routing?.accountId && routing.provider === providerName) return routing.sessionAccountId || routing.accountId;
174
+ }
175
+ return null;
176
+ }
177
+
178
+ // Stamp the serving account on the answer, independent of transport state,
179
+ // with the account the session stays bound to (`bindingId`).
180
+ function recordServingAccount(providerName, result, id, bindingId) {
181
+ if (!result || typeof result !== 'object') return;
182
+ if (result.providerReplay) result.providerReplay = { ...result.providerReplay, accountId: id };
183
+ if (result.providerState) {
184
+ result.providerState = {
185
+ ...result.providerState,
186
+ providerAccountId: id,
187
+ providerSessionAccountId: bindingId,
188
+ providerAccountProvider: providerName,
189
+ };
125
190
  }
191
+ const metadata =
192
+ result.providerMetadata && typeof result.providerMetadata === 'object' ? result.providerMetadata : {};
193
+ result.providerMetadata = {
194
+ ...metadata,
195
+ [ROUTING_METADATA_KEY]: { provider: providerName, accountId: id, sessionAccountId: bindingId },
196
+ };
126
197
  }
127
198
 
128
199
  // Whether the failed account's quota window is exhausted, plus the server's
@@ -158,12 +229,18 @@ function poolSend(providerName, account) {
158
229
  let lastError;
159
230
  let probed = false;
160
231
  const evidenced = new Set();
232
+ const sessionKey = options.sessionId ? `${providerName}:${options.sessionId}` : null;
233
+ const boundId = sessionAccountId(providerName, sessionKey, messages, options);
234
+ // Whether this send already left an account, and whether the latest quota
235
+ // refusal held only for this model's family.
236
+ let switched = false;
237
+ let refusalScoped = false;
161
238
  // Mark `error` only when every account in `ids` (default: the roster) is
162
239
  // exhausted with quota evidence: observed in this send, or a full window.
163
240
  const markExhausted = (error, ids) => {
164
241
  const pool = readProviderAccountPool(providerName);
165
- // Auto switching off: the eligible set is the selected account alone.
166
- const scope = ids || (pool.auto === false ? [pool.selectedId] : null);
242
+ // Manual policy: the eligible set is the selected account alone.
243
+ const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
167
244
  const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
168
245
  const opts = { useCredits: pool.useCredits === true };
169
246
  const now = Date.now();
@@ -194,7 +271,8 @@ function poolSend(providerName, account) {
194
271
  }
195
272
  return account('default').send(messages, model, tools, options);
196
273
  }
197
- const row = chooseProviderAccount(pool, attempted, Date.now(), model);
274
+ const policy = providerAccountPolicy(pool);
275
+ const row = chooseProviderAccount(pool, attempted, Date.now(), model, { sessionAccountId: boundId });
198
276
  if (!row) {
199
277
  // Once per send: a refusal built on a stale meter must not outlive the
200
278
  // meter. Re-measuring can only widen the roster, so it is tried before
@@ -209,9 +287,18 @@ function poolSend(providerName, account) {
209
287
  const bound = boundAccountSend(providerName, row, messages, options);
210
288
  try {
211
289
  const result = await account(row.id).send(bound.history, model, tools, bound.opts);
212
- if (result?.providerReplay) result.providerReplay = { ...result.providerReplay, accountId: row.id };
213
- if (result?.providerState) result.providerState = { ...result.providerState, providerAccountId: row.id };
214
- if (commitFallbackAccount(providerName, pool, row)) {
290
+ // Headroom policy: a session's first pick, or its move off its account
291
+ // on a limit, becomes the selection; continuing on its account does
292
+ // not, so concurrent sessions never flip the selection back and forth.
293
+ // A move forced by a model-scoped limit serves this request only.
294
+ const leftBound = Boolean(boundId) && row.id !== boundId;
295
+ const scoped = switched
296
+ ? refusalScoped
297
+ : policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
298
+ recordServingAccount(providerName, result, row.id, scoped && boundId ? boundId : row.id);
299
+ if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, row.id);
300
+ const commit = policy !== 'headroom' || !boundId || leftBound;
301
+ if (commit && (await commitFallbackAccount(providerName, pool, row, model, scoped, policy))) {
215
302
  // Publish only a committed selection, never a speculative retry or
216
303
  // one superseded by a manual switch. The existing progress channel
217
304
  // carries this across runtime shards to the attached UI.
@@ -230,7 +317,7 @@ function poolSend(providerName, account) {
230
317
  if (options.signal?.aborted) throw error;
231
318
  if (error?.reauthRequired === true) {
232
319
  if (
233
- pool.auto === false ||
320
+ policy === 'manual' ||
234
321
  bound.emitted() ||
235
322
  error.unsafeToRetry ||
236
323
  error.liveTextEmitted ||
@@ -238,13 +325,15 @@ function poolSend(providerName, account) {
238
325
  )
239
326
  throw error;
240
327
  lastError = error;
328
+ switched = true;
329
+ refusalScoped = false;
241
330
  options.onStageChange?.('reconnecting', { message: 'Sign-in expired — switching to the next account' });
242
331
  continue;
243
332
  }
244
333
  const { exhausted, delay, evidence } = await accountQuotaExhausted(providerName, row, model, error, account);
245
334
  if (options.signal?.aborted || !exhausted) throw error;
246
335
  if (evidence) evidenced.add(row.id);
247
- blockProviderAccount(
336
+ await blockProviderAccount(
248
337
  providerName,
249
338
  row.id,
250
339
  Date.now() + (delay > 0 ? delay : 5 * 60_000),
@@ -253,9 +342,11 @@ function poolSend(providerName, account) {
253
342
  { quota: evidence === true }
254
343
  );
255
344
  if (bound.emitted() || error.unsafeToRetry || error.liveTextEmitted || error.emittedToolCall) throw error;
256
- // Auto switching off: the eligible set is the selected account alone.
257
- if (pool.auto === false) throw markExhausted(error, [row.id]);
345
+ // Manual policy: the eligible set is the selected account alone.
346
+ if (policy === 'manual') throw markExhausted(error, [row.id]);
258
347
  lastError = error;
348
+ switched = true;
349
+ refusalScoped = accountExhaustedForModelOnly(providerName, row.id, model);
259
350
  options.onStageChange?.('reconnecting', { message: 'Quota exhausted — switching to the next account' });
260
351
  }
261
352
  }
@@ -10,7 +10,7 @@ import { createNpmVersionSource, maxSemver } from './npm-cli-version.mjs';
10
10
  // source release just to advance the user-agent version.
11
11
  // Claude Opus 5.5 requires 2.1.280 or newer. The release workflow raises this
12
12
  // to the published CLI version (scripts/sync-client-version-floors.mjs).
13
- export const DEFAULT_CLI_VERSION = '2.1.296';
13
+ export const DEFAULT_CLI_VERSION = '2.1.299';
14
14
  export const CLAUDE_CLI_NPM_PACKAGE = '@anthropic-ai/claude-code';
15
15
 
16
16
  const CACHE_SCHEMA_VERSION = 1;
@@ -13,6 +13,7 @@ import { randomBytes } from 'node:crypto';
13
13
  import { updateJsonAtomicSync, writeJsonAtomicSync, withFileLock } from '../../../shared/atomic-file.mjs';
14
14
  import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
15
15
  import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
16
+ import { modelProxyClientMode, serverModelCredentialsDisabledError } from '../../../shared/model-proxy-mode.mjs';
16
17
  import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
17
18
  import { claudeCliUserAgent, resolveCliVersion } from './anthropic-oauth-client-version.mjs';
18
19
  import {
@@ -148,6 +149,7 @@ export function _credentialsMaxMtime() {
148
149
  }
149
150
 
150
151
  export function loadCredentials() {
152
+ if (modelProxyClientMode()) return null;
151
153
  const loaded = credentialCandidates().map(_loadCredentialsFile).filter(Boolean);
152
154
  if (!loaded.length) return null;
153
155
  loaded.sort((a, b) => (Number(b.expiresAt) || 0) - (Number(a.expiresAt) || 0));
@@ -382,6 +384,7 @@ async function _refreshOAuthCredentialsUnlocked(creds) {
382
384
  }
383
385
 
384
386
  export async function refreshOAuthCredentials(creds) {
387
+ if (modelProxyClientMode()) throw serverModelCredentialsDisabledError('Anthropic OAuth credentials');
385
388
  if (isAnthropicOAuthRefreshDisabled()) {
386
389
  throw new Error(
387
390
  'Anthropic OAuth refresh is disabled in this process; ' +
@@ -48,6 +48,7 @@ import { createAnthropicOAuthRecovery } from './anthropic-oauth-recovery.mjs';
48
48
  import { createMidState, createMidstreamRecovery } from './anthropic-oauth-midstream.mjs';
49
49
  import { assertAnthropicStreamNotEmpty } from './anthropic-midstream-recovery.mjs';
50
50
  import { applyAnthropicEffortToBody, shouldIncludeEffortBeta } from './anthropic-effort.mjs';
51
+ import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-rejection.mjs';
51
52
  import { getLlmDispatcher, preconnect } from '../../../shared/llm/http-agent.mjs';
52
53
  import {
53
54
  applyAnthropicCacheMarkers,
@@ -408,6 +409,17 @@ export class AnthropicOAuthProvider {
408
409
  }
409
410
 
410
411
  async send(messages, model, tools, sendOpts) {
412
+ return withEffortRejectionFallback(
413
+ 'anthropic-oauth',
414
+ model,
415
+ sendOpts || {},
416
+ undefined,
417
+ (opts) => this._sendOnce(messages, model, tools, opts),
418
+ { levels: ANTHROPIC_EFFORT_LEVELS }
419
+ );
420
+ }
421
+
422
+ async _sendOnce(messages, model, tools, sendOpts) {
411
423
  await warmCliVersion();
412
424
  // Re-warm the kept-alive socket before the turn. preconnect() is a
413
425
  // best-effort no-op while a socket is still hot (TTL gate), but after an
@@ -625,7 +637,9 @@ export class AnthropicOAuthProvider {
625
637
  // without them (the request keeps its turn effort).
626
638
  if (isEffortConfigurationRejection(response.status, scrubbedText) && !opts._effortConfigurationRetry) {
627
639
  markEffortConfigurationUnsupported('anthropic-oauth', useModel);
628
- process.stderr.write(`[anthropic-oauth] ${useModel} rejected the mid-conversation effort update; retrying once without it\n`);
640
+ process.stderr.write(
641
+ `[anthropic-oauth] ${useModel} rejected the mid-conversation effort update; retrying once without it\n`
642
+ );
629
643
  return this.send(messages, useModel, tools, {
630
644
  ...opts,
631
645
  effortConfigurationEnabled: false,
@@ -1,4 +1,4 @@
1
- import { getAgentApiKey } from '../../../shared/provider-api-key.mjs';
1
+ import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
2
2
  import { sanitizeToolPairs } from '../session/context-utils.mjs';
3
3
  import { AnthropicFallbackTriggeredError } from './retry-classifier.mjs';
4
4
  import { readStreamOutcome } from './lib/stream-outcome.mjs';
@@ -8,6 +8,7 @@ import { ANTHROPIC_MAX_MIDSTREAM_RETRIES, parseSSEStream } from './anthropic-sse
8
8
  import { buildAnthropicBetaHeaders } from './anthropic-betas.mjs';
9
9
  import { buildAnthropicApiRequest } from './anthropic-api-request.mjs';
10
10
  import { isCustomProviderName } from './custom-reasoning.mjs';
11
+ import { ANTHROPIC_EFFORT_LEVELS, withEffortRejectionFallback } from './effort-rejection.mjs';
11
12
  import { armFirstByteWatchdog, createAnthropicApiTransport } from './anthropic-api-transport.mjs';
12
13
  import { createAnthropicApiRecovery } from './anthropic-api-recovery.mjs';
13
14
  import { buildAnthropicTurnResult } from './anthropic-turn-result.mjs';
@@ -41,9 +42,19 @@ export class AnthropicProvider {
41
42
  constructor(config) {
42
43
  this.config = config || {};
43
44
  this.name = this.config.name || 'anthropic';
44
- this.apiKey = this.config.apiKey || (this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
45
+ this.apiKey = resolveProviderApiKey(this.name, this.config) || null;
45
46
  this.client = this._createClient(this.apiKey);
46
47
  }
48
+ // Client for the currently resolved key; rebuilt when the key changed since
49
+ // it was built (e.g. a keyless-constructed instance).
50
+ _currentClient() {
51
+ const key = resolveProviderApiKey(this.name, this.config) || null;
52
+ if (key && key !== this.apiKey) {
53
+ this.apiKey = key;
54
+ this.client = this._createClient(key);
55
+ }
56
+ return this.client;
57
+ }
47
58
  // Tool-search is a request capability, not an account capability. Keep it
48
59
  // off the client defaults and add it only on turns that actually serialize
49
60
  // defer_loading tools.
@@ -54,8 +65,10 @@ export class AnthropicProvider {
54
65
  const custom = isCustomProviderName(this.name);
55
66
  const keyless = custom && this.config.keyless === true;
56
67
  const betaHeaders = this.config.disableBetaHeaders || custom ? null : buildAnthropicBetaHeaders();
68
+ let credentials = { apiKey };
69
+ if (custom) credentials = { apiKey: keyless ? '' : apiKey || '', authToken: null };
57
70
  return new (loadAnthropic())({
58
- ...(custom ? { apiKey: keyless ? '' : apiKey || '', authToken: null } : { apiKey }),
71
+ ...credentials,
59
72
  ...(this.config.baseURL ? { baseURL: this.config.baseURL } : {}),
60
73
  defaultHeaders: {
61
74
  ...(betaHeaders ? { 'anthropic-beta': betaHeaders } : {}),
@@ -67,10 +80,7 @@ export class AnthropicProvider {
67
80
  }
68
81
  reloadApiKey() {
69
82
  try {
70
- const newKey =
71
- getAgentApiKey(this.name) ||
72
- this.config.apiKey ||
73
- (this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
83
+ const newKey = reloadProviderApiKey(this.name, this.config);
74
84
  if (newKey) {
75
85
  this.config = { ...(this.config || {}), apiKey: newKey };
76
86
  this.apiKey = newKey;
@@ -106,10 +116,21 @@ export class AnthropicProvider {
106
116
  throw err;
107
117
  }
108
118
  }
119
+ // The `anthropic` API-key provider and every custom `anthropic`-protocol
120
+ // provider (a subclass of this one) share this send path.
109
121
  async _doSend(messages, model, tools, sendOpts) {
122
+ return withEffortRejectionFallback(
123
+ this.name,
124
+ model,
125
+ sendOpts || {},
126
+ this.config?.reasoningEffort,
127
+ (opts) => this._sendOnce(messages, model, tools, opts),
128
+ { levels: ANTHROPIC_EFFORT_LEVELS }
129
+ );
130
+ }
131
+ async _sendOnce(messages, model, tools, opts) {
110
132
  if (!model) throw new Error(`[${this.name}] model is required — pass it from the caller preset`);
111
133
  const useModel = model;
112
- const opts = sendOpts || {};
113
134
  // Wire request (system/cache layout, tools, effort, fast mode, images)
114
135
  // and the per-request beta headers derived from that final body —
115
136
  // anthropic-api-request.mjs. Fast mode latches on the provider instance.
@@ -148,7 +169,7 @@ export class AnthropicProvider {
148
169
  // The SDK calls and their initial-response retry policy
149
170
  // (anthropic-api-transport.mjs).
150
171
  const transport = createAnthropicApiTransport({
151
- client: this.client,
172
+ client: this._currentClient(),
152
173
  label: this.name,
153
174
  opts,
154
175
  useModel,
@@ -284,8 +305,7 @@ export class AnthropicProvider {
284
305
  }
285
306
  }
286
307
  async listModels() {
287
- const apiKey =
288
- this.apiKey || this.config?.apiKey || (this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
308
+ const apiKey = resolveProviderApiKey(this.name, this.config);
289
309
  if (!apiKey) return MODELS;
290
310
  try {
291
311
  const base = String(this.config?.baseURL || 'https://api.anthropic.com').replace(/\/+$/, '');
@@ -317,6 +337,6 @@ export class AnthropicProvider {
317
337
  async isAvailable() {
318
338
  // Availability probes must not spend tokens or depend on a live
319
339
  // network. Dispatch owns authentication validation and 401 reload.
320
- return !!(this.apiKey || this.config?.apiKey || (this.name === 'anthropic' && process.env.ANTHROPIC_API_KEY));
340
+ return !!resolveProviderApiKey(this.name, this.config);
321
341
  }
322
342
  }
@@ -18,6 +18,7 @@ import { join, resolve } from 'node:path';
18
18
  import { getPluginData } from '../config.mjs';
19
19
  import { writeJsonAtomicSync } from '../../../shared/atomic-file.mjs';
20
20
  import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
21
+ import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
21
22
  import {
22
23
  accountIdentityFields,
23
24
  normalizeExpiresAtMs as _normalizeExpiresAt,
@@ -192,6 +193,7 @@ function mtimeMs(path) {
192
193
  export { _normalizeExpiresAt };
193
194
 
194
195
  export function loadTokens() {
196
+ if (modelProxyClientMode()) return null;
195
197
  const path = getOwnTokenPath();
196
198
  if (!existsSync(path)) return null;
197
199
  try {
@@ -89,6 +89,15 @@ export function resolveAutoEffort({ base, options, probs }) {
89
89
  const ladder = autoEffortLadder(options);
90
90
  const at = ladder.indexOf(String(base ?? '').toLowerCase());
91
91
  if (at < 0) return null;
92
+ return resolveOnLadder(ladder, at, probs);
93
+ }
94
+
95
+ /** True when some judged outcome could apply: the base lies on the model's ladder. */
96
+ export function autoEffortApplicable({ base, options }) {
97
+ return autoEffortLadder(options).includes(String(base ?? '').toLowerCase());
98
+ }
99
+
100
+ function resolveOnLadder(ladder, at, probs) {
92
101
  const { step, level, confidence } = judgedStep(probs);
93
102
  const effort = ladder[Math.max(0, Math.min(ladder.length - 1, at + step))];
94
103
  return { base: ladder[at], effort, step, level, confidence: Number(confidence.toFixed(3)) };