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,251 @@
1
+ // Daemon-side stand-in for a provider in remote mode (MIXDOG_MODEL_PROXY=client).
2
+ // It holds no credentials and opens no model connection: every call is handed
3
+ // to the desktop client through the model proxy channel and executed by the
4
+ // PC's own provider of the same name. The registry still wraps it with
5
+ // admission scheduling and usage accounting, which then see the PC's result.
6
+ import {
7
+ getModelProxyChannel,
8
+ ModelProxyUnavailableError,
9
+ splitModelProxySendOptions,
10
+ stripModelProxySecrets,
11
+ } from './model-proxy-channel.mjs';
12
+ import {
13
+ isFinalizedProviderRequestTools,
14
+ providerNativeToolPrefixCount,
15
+ } from '../runtime-core/provider-request-tools.mjs';
16
+ import {
17
+ attachmentTextForPart,
18
+ isAttachmentReference,
19
+ isPermanentAttachmentError,
20
+ readAttachmentBuffer,
21
+ } from '../../../attachments/store.mjs';
22
+ import { MAX_ATTACHMENT_BLOB_BYTES } from '../../../attachments/limits.mjs';
23
+
24
+ /** Stored-attachment bytes one proxied call may carry inline: the store's own
25
+ * single-blob ceiling. Newer messages are inlined first; a reference past the
26
+ * budget stays a reference, which the PC lowers to its "unavailable" text. */
27
+ export const MODEL_PROXY_INLINE_MAX_BYTES = MAX_ATTACHMENT_BLOB_BYTES;
28
+
29
+ // A stored reference names a blob in THIS daemon's attachment store, which the
30
+ // PC running the call cannot read. Each one travels as the inline part it was
31
+ // stored from (image/file → base64 `data`, text → its text), so the PC lowers
32
+ // exactly what a local daemon would.
33
+ function inlineReference(part, budget) {
34
+ let buffer;
35
+ try {
36
+ buffer = readAttachmentBuffer(part);
37
+ } catch (error) {
38
+ if (isPermanentAttachmentError(error)) return part;
39
+ throw error;
40
+ }
41
+ if (buffer.length > budget.remaining) return part;
42
+ budget.remaining -= buffer.length;
43
+ const { attachmentRef: _ref, sizeBytes: _size, ...rest } = part;
44
+ if (part.type === 'text') {
45
+ const { textKind: _kind, filename: _name, mimeType: _mime, ...textRest } = rest;
46
+ return { ...textRest, type: 'text', text: attachmentTextForPart(part) };
47
+ }
48
+ return { ...rest, data: buffer.toString('base64') };
49
+ }
50
+
51
+ function inlinePart(part, budget) {
52
+ if (!part || typeof part !== 'object' || Array.isArray(part)) return part;
53
+ if (isAttachmentReference(part)) return inlineReference(part, budget);
54
+ if (Array.isArray(part.content)) {
55
+ const content = inlineParts(part.content, budget);
56
+ return content === part.content ? part : { ...part, content };
57
+ }
58
+ return part;
59
+ }
60
+
61
+ /** Newest last in a content list, so it is walked backwards for the budget. */
62
+ function inlineParts(parts, budget) {
63
+ let out = null;
64
+ for (let index = parts.length - 1; index >= 0; index -= 1) {
65
+ const next = inlinePart(parts[index], budget);
66
+ if (next === parts[index]) continue;
67
+ out ??= [...parts];
68
+ out[index] = next;
69
+ }
70
+ return out ?? parts;
71
+ }
72
+
73
+ /** `messages` with every stored attachment reference replaced by its bytes. */
74
+ export function inlineModelProxyAttachments(messages, { maxBytes = MODEL_PROXY_INLINE_MAX_BYTES } = {}) {
75
+ if (!Array.isArray(messages)) return messages;
76
+ const budget = { remaining: maxBytes };
77
+ let out = null;
78
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
79
+ const message = messages[index];
80
+ if (!message || typeof message !== 'object' || message.content == null || typeof message.content === 'string') {
81
+ continue;
82
+ }
83
+ const content = Array.isArray(message.content)
84
+ ? inlineParts(message.content, budget)
85
+ : inlinePart(message.content, budget);
86
+ if (content === message.content) continue;
87
+ out ??= [...messages];
88
+ out[index] = { ...message, content };
89
+ }
90
+ return out ?? messages;
91
+ }
92
+
93
+ export class ModelProxyProvider {
94
+ #channel;
95
+ #modelInfo = new Map();
96
+
97
+ constructor(name, config = {}, channel = getModelProxyChannel()) {
98
+ this.name = name;
99
+ this.config = config || {};
100
+ this.#channel = channel;
101
+ // Adapter traits are reported by the PC's real instance.
102
+ if (typeof this.config.modelProxy?.nativePdf === 'boolean') this.nativePdf = this.config.modelProxy.nativePdf;
103
+ }
104
+
105
+ #call(method, fields = {}, options = {}) {
106
+ return this.#channel.request({ provider: this.name, method, ...fields }, options);
107
+ }
108
+
109
+ async send(messages, model, tools, sendOpts) {
110
+ const { options, callbacks } = splitModelProxySendOptions(sendOpts);
111
+ const finalized = isFinalizedProviderRequestTools(tools);
112
+ return this.#call(
113
+ 'send',
114
+ {
115
+ model: model ?? null,
116
+ messages: inlineModelProxyAttachments(messages),
117
+ tools: Array.isArray(tools) ? tools : null,
118
+ toolsFinalized: finalized,
119
+ nativePrefixCount: finalized ? providerNativeToolPrefixCount(tools) : 0,
120
+ options,
121
+ },
122
+ { signal: sendOpts?.signal || null, callbacks }
123
+ );
124
+ }
125
+
126
+ #adoptCatalog(catalog) {
127
+ const models = Array.isArray(catalog?.models) ? catalog.models : [];
128
+ const info = catalog?.modelInfo && typeof catalog.modelInfo === 'object' ? catalog.modelInfo : {};
129
+ this.#modelInfo = new Map(Object.entries(info));
130
+ return models;
131
+ }
132
+
133
+ async listModels() {
134
+ return this.#adoptCatalog(await this.#call('listModels'));
135
+ }
136
+
137
+ async _refreshModelCache() {
138
+ return this.#adoptCatalog(await this.#call('refreshModels'));
139
+ }
140
+
141
+ async isAvailable() {
142
+ return (await this.#call('isAvailable')) === true;
143
+ }
144
+
145
+ getCachedModelInfo(model) {
146
+ return this.#modelInfo.get(String(model ?? '')) ?? null;
147
+ }
148
+ }
149
+
150
+ /** A proxy instance whose class carries the PC adapter's usage convention. */
151
+ export function createModelProxyProvider(name, config = {}, channel = getModelProxyChannel()) {
152
+ const inputExcludesCache = config?.modelProxy?.inputExcludesCache;
153
+ if (typeof inputExcludesCache !== 'boolean') return new ModelProxyProvider(name, config, channel);
154
+ class BoundModelProxyProvider extends ModelProxyProvider {
155
+ static inputExcludesCache = inputExcludesCache;
156
+ }
157
+ return new BoundModelProxyProvider(name, config, channel);
158
+ }
159
+
160
+ // The PC's provider set (availability + non-secret config) changes only on a
161
+ // PC-side sign-in or settings edit; a short cache keeps registry re-inits from
162
+ // paying a client round trip each. The cache belongs to one client generation:
163
+ // a reconnect (possibly from another PC) always asks again.
164
+ const PROVIDER_CONFIG_TTL_MS = 15_000;
165
+ /** How long a registry init waits for a client to connect and for its PC to
166
+ * answer with a loaded provider registry. */
167
+ export const MODEL_PROXY_CONFIG_WAIT_MS = 15_000;
168
+ const CONFIG_RETRY_FIRST_MS = 250;
169
+ const CONFIG_RETRY_MAX_MS = 2_000;
170
+ let _providerConfigCache = null;
171
+ let _providerConfigInFlight = null;
172
+
173
+ /** A reply the registry may act on: the PC says its registry is loaded, or it
174
+ * already names an enabled provider (a client that predates `ready`). An
175
+ * empty or unready answer is never read as "everything disabled". */
176
+ function providerConfigReady(reply, providers) {
177
+ // A loaded PC registry is authoritative, even when it has nothing enabled.
178
+ if (reply?.ready === true) return true;
179
+ if (reply?.ready === false) return false;
180
+ return Object.keys(providers).some((name) => providers[name]?.enabled === true);
181
+ }
182
+
183
+ const pause = (ms) =>
184
+ new Promise((resolve) => {
185
+ const timer = setTimeout(resolve, ms);
186
+ timer.unref?.();
187
+ });
188
+
189
+ export function loadModelProxyProviderConfig({
190
+ channel = getModelProxyChannel(),
191
+ now = Date.now,
192
+ waitMs = MODEL_PROXY_CONFIG_WAIT_MS,
193
+ } = {}) {
194
+ const generation = channel.generation;
195
+ const cached = _providerConfigCache;
196
+ if (
197
+ cached &&
198
+ cached.channel === channel &&
199
+ cached.generation === generation &&
200
+ now() - cached.at < PROVIDER_CONFIG_TTL_MS
201
+ ) {
202
+ return Promise.resolve(cached.value);
203
+ }
204
+ const inFlight = _providerConfigInFlight;
205
+ if (inFlight && inFlight.channel === channel && inFlight.generation === generation) return inFlight.promise;
206
+ const promise = (async () => {
207
+ const deadline = Date.now() + waitMs;
208
+ let delay = CONFIG_RETRY_FIRST_MS;
209
+ let lastError = null;
210
+ for (;;) {
211
+ if (!channel.connected) {
212
+ const remaining = deadline - Date.now();
213
+ if (remaining <= 0 || !(await channel.whenConnected(remaining))) {
214
+ throw lastError ?? new ModelProxyUnavailableError('no desktop client is connected to run model calls');
215
+ }
216
+ }
217
+ try {
218
+ const reply = await channel.request({ provider: '', method: 'providerConfig' });
219
+ const raw = reply?.providers && typeof reply.providers === 'object' ? reply.providers : {};
220
+ // Defense in depth: the PC already strips secrets before sending.
221
+ const value = stripModelProxySecrets(raw);
222
+ if (providerConfigReady(reply, value)) {
223
+ if (channel.generation === generation) {
224
+ _providerConfigCache = { at: now(), value, channel, generation };
225
+ }
226
+ return value;
227
+ }
228
+ lastError = new ModelProxyUnavailableError('the desktop client has not loaded its model providers yet');
229
+ } catch (error) {
230
+ // Only "no client / no answer yet" is worth waiting out.
231
+ if (error?.code !== 'MODEL_PROXY_UNAVAILABLE') throw error;
232
+ lastError = error;
233
+ }
234
+ if (Date.now() + delay > deadline) throw lastError;
235
+ await pause(delay);
236
+ delay = Math.min(delay * 2, CONFIG_RETRY_MAX_MS);
237
+ }
238
+ })();
239
+ const entry = { channel, generation, promise };
240
+ _providerConfigInFlight = entry;
241
+ const clear = () => {
242
+ if (_providerConfigInFlight === entry) _providerConfigInFlight = null;
243
+ };
244
+ promise.then(clear, clear);
245
+ return promise;
246
+ }
247
+
248
+ export function _resetModelProxyProviderConfigForTest() {
249
+ _providerConfigCache = null;
250
+ _providerConfigInFlight = null;
251
+ }
@@ -10,6 +10,7 @@ import { writeJsonAtomicSync } from '../../../shared/atomic-file.mjs';
10
10
  import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
11
11
  import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
12
12
  import { accountIdentityFields, scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
13
+ import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
13
14
 
14
15
  export const CLIENT_ID = '1031625952748946';
15
16
  export const DEVICE_AUTH_URL = 'https://auth.meta.com/oidc/device/authorization/';
@@ -44,6 +45,7 @@ const nonEmptyString = (value) => typeof value === 'string' && value.trim() !==
44
45
  export const isValidMuseCredentialDocument = (doc) => nonEmptyString(doc?.accessToken) && nonEmptyString(doc?.apiKey);
45
46
 
46
47
  export function loadTokens() {
48
+ if (modelProxyClientMode()) return null;
47
49
  const path = getOwnTokenPath();
48
50
  if (!existsSync(path)) return null;
49
51
  try {
@@ -10,6 +10,15 @@ import { createHash } from 'node:crypto';
10
10
  import { noteErrorUsage } from './lib/note-error-usage.mjs';
11
11
  import { fileMtimeMs } from './lib/oauth-token-utils.mjs';
12
12
  import { OpenAICompatProvider, preloadOpenAICompatRuntime } from './openai-compat.mjs';
13
+ import { getModelMetadataSync } from './model-catalog.mjs';
14
+ import { makeModelCache } from './model-cache.mjs';
15
+ import { PRICING_RATE_KEYS } from '../../../shared/llm/model-pricing-rates.mjs';
16
+ import {
17
+ MUSE_DEFAULT_EFFORT_LEVELS as FIVE_LEVELS,
18
+ MUSE_SEED_IDS as SEED_MODELS,
19
+ MUSE_SPARK_MAX_OUTPUT as SPARK_MAX_OUTPUT,
20
+ museSeedRow,
21
+ } from '../../../shared/llm/provider-seed-rosters.mjs';
13
22
  import {
14
23
  API_VERSION,
15
24
  MODEL_API_BASE_URL,
@@ -27,108 +36,63 @@ export {
27
36
  export { beginOAuthLogin, loginOAuth } from './muse-code-oauth-login.mjs';
28
37
 
29
38
  export const DEFAULT_MODEL = 'muse-spark-1.3';
30
- const FIVE_LEVELS = Object.freeze(['minimal', 'low', 'medium', 'high', 'xhigh']);
31
- const SIX_LEVELS = Object.freeze([...FIVE_LEVELS, 'max']);
32
39
  const effortOptions = (levels) => [{ type: 'effort', values: [...levels] }];
33
40
  // Image and voice generation ids are served by the same catalog but are not chat models.
34
41
  const NON_CHAT_MODEL_RE = /^muse-(image|voice)-/i;
35
- const SPARK_CONTEXT = 1_048_576;
36
- const SPARK_MAX_OUTPUT = 131_072;
37
- const STANDARD_COST = { inputCostPerM: 1.25, outputCostPerM: 4.25, cacheReadCostPerM: 0.15, cacheWriteCostPerM: 0 };
38
- const CONTRIBUTOR_COST = { inputCostPerM: 0.1, outputCostPerM: 0.2, cacheReadCostPerM: 0.002, cacheWriteCostPerM: 0 };
39
-
40
- // Seeded roster: the discovery endpoint lists bare ids, so limits, pricing and
41
- // the effort ladder come from here. Only the 1.3 revisions accept `max`.
42
- const SEEDS = Object.freeze({
43
- 'muse-spark-1.1': { name: 'Muse Spark 1.1', levels: FIVE_LEVELS, cost: STANDARD_COST },
44
- 'muse-spark-1.2': { name: 'Muse Spark 1.2', levels: FIVE_LEVELS, cost: STANDARD_COST },
45
- 'muse-spark-1.2-contributor': { name: 'Muse Spark 1.2 (C)', levels: FIVE_LEVELS, cost: CONTRIBUTOR_COST },
46
- 'muse-spark-1.3': { name: 'Muse Spark 1.3', levels: SIX_LEVELS, cost: STANDARD_COST },
47
- 'muse-spark-1.3-contributor': { name: 'Muse Spark 1.3 (C)', levels: SIX_LEVELS, cost: CONTRIBUTOR_COST },
48
- });
49
- const SEED_MODELS = Object.freeze(Object.keys(SEEDS));
50
-
51
- function seedRow(id) {
52
- const seed = SEEDS[id];
53
- return {
54
- id,
55
- name: seed.name,
56
- provider: 'muse-code-oauth',
57
- family: 'muse-spark',
58
- contextWindow: SPARK_CONTEXT,
59
- outputTokens: SPARK_MAX_OUTPUT,
60
- supportsReasoning: true,
61
- supportsVision: true,
62
- supportsFunctionCalling: true,
63
- reasoningLevels: [...seed.levels],
64
- reasoningOptions: effortOptions(seed.levels),
65
- ...seed.cost,
66
- };
67
- }
68
-
69
- // Revisioned Spark ids the seed does not list inherit the newest seeded
70
- // revision of their tier (limits, vision, pricing) but take the five-level
71
- // ladder: only reviewed seeds advertise `max`.
72
- const SPARK_ID_RE = /^muse-spark-(\d+)\.(\d+)(?:\.(\d+))?(-contributor)?$/i;
73
42
 
74
- function revisionOf(id) {
75
- const m = SPARK_ID_RE.exec(id);
76
- return m ? [Number(m[1]), Number(m[2]), Number(m[3] || 0)] : null;
77
- }
43
+ // The discovered roster (fields /models returned, never seed values) is
44
+ // persisted so the shared sync lookup sees what listModels found.
45
+ const museModelCache = makeModelCache({
46
+ fileName: 'muse-code-oauth-models.json',
47
+ ttlMs: 24 * 60 * 60 * 1000,
48
+ version: 1,
49
+ });
78
50
 
79
- function compareRevision(a, b) {
80
- for (let i = 0; i < 3; i += 1) if (a[i] !== b[i]) return a[i] - b[i];
81
- return 0;
51
+ // Row fields the shared metadata lookup resolves: live roster, models.dev
52
+ // `meta`, verified corrections, then the offline seed (provider-seed-rosters).
53
+ const LOOKUP_FIELDS = Object.freeze([
54
+ 'contextWindow',
55
+ 'outputTokens',
56
+ ...PRICING_RATE_KEYS,
57
+ 'supportsReasoning',
58
+ 'supportsVision',
59
+ 'supportsFunctionCalling',
60
+ 'reasoningOptions',
61
+ ]);
62
+
63
+ // Labels compare without the trailing "(C)" tier marker, case or punctuation.
64
+ const nameKey = (name) =>
65
+ String(name || '')
66
+ .replace(/\s*\(c\)\s*$/i, '')
67
+ .toLowerCase()
68
+ .replace(/[^a-z0-9]+/g, '');
69
+
70
+ // A discovered or catalog label naming the seeded model keeps the seed's "(C)" marker.
71
+ function tierName(candidate, seedName) {
72
+ if (!candidate) return '';
73
+ return seedName && nameKey(candidate) === nameKey(seedName) ? seedName : candidate;
82
74
  }
83
75
 
84
- function lineageRow(id) {
85
- if (SEEDS[id]) return null;
86
- const match = SPARK_ID_RE.exec(id);
87
- if (!match) return null;
88
- const contributor = Boolean(match[4]);
89
- let template = null;
90
- let templateRevision = null;
91
- for (const seedId of SEED_MODELS) {
92
- if (SPARK_ID_RE.exec(seedId)[4] ? !contributor : contributor) continue;
93
- const candidate = revisionOf(seedId);
94
- if (!templateRevision || compareRevision(candidate, templateRevision) > 0) {
95
- template = seedId;
96
- templateRevision = candidate;
97
- }
76
+ // Discovered fields win, then the shared lookup (fetched catalogs before
77
+ // seeds). Rows that report no effort ladder gain the default five levels
78
+ // unless a source declares the model non-reasoning.
79
+ function museRow(id, discovered = null) {
80
+ const meta = getModelMetadataSync(id, 'muse-code-oauth');
81
+ if (!meta && !discovered) return null;
82
+ const row = { id, provider: 'muse-code-oauth', family: 'muse-spark' };
83
+ for (const key of LOOKUP_FIELDS) {
84
+ const value = meta?.[key];
85
+ if (value != null && !(Array.isArray(value) && !value.length)) row[key] = value;
98
86
  }
99
- if (!template) return null;
100
- const revision =
101
- match[3] && Number(match[3]) !== 0 ? `${match[1]}.${match[2]}.${match[3]}` : `${match[1]}.${match[2]}`;
102
- return {
103
- ...seedRow(template),
104
- id,
105
- name: `Muse Spark ${revision}${contributor ? ' (C)' : ''}`,
106
- reasoningLevels: [...FIVE_LEVELS],
107
- reasoningOptions: effortOptions(FIVE_LEVELS),
108
- };
109
- }
110
-
111
- // Seeds win for the ids they cover; lineage rows yield to discovered metadata.
112
- // A name supplied by discovery is always kept. Other discovered rows keep
113
- // their own metadata and only gain the default effort ladder when they report none.
114
- function museRow(id, discovered) {
87
+ Object.assign(row, discovered || {});
115
88
  const discoveredName =
116
89
  typeof discovered?.name === 'string' && discovered.name && discovered.name !== id ? discovered.name : '';
117
- if (SEEDS[id]) return { ...(discovered || {}), ...seedRow(id), ...(discoveredName ? { name: discoveredName } : {}) };
118
- const lineage = lineageRow(id);
119
- const row = {
120
- id,
121
- name: id,
122
- provider: 'muse-code-oauth',
123
- family: 'muse-spark',
124
- ...(lineage || {}),
125
- ...(discovered || {}),
126
- };
127
- if (discoveredName) row.name = discoveredName;
128
- else if (lineage) row.name = lineage.name;
129
- if (!row.reasoningOptions?.length) {
130
- row.reasoningOptions = effortOptions(FIVE_LEVELS);
131
- row.reasoningLevels = [...FIVE_LEVELS];
90
+ row.name = tierName(discoveredName || meta?.displayName, museSeedRow(id)?.name) || id;
91
+ // A model declared non-reasoning gets no default ladder.
92
+ if (!row.reasoningOptions?.length)
93
+ row.reasoningOptions = row.supportsReasoning === false ? [] : effortOptions(FIVE_LEVELS);
94
+ if (!row.reasoningLevels?.length) {
95
+ row.reasoningLevels = [...(row.reasoningOptions.find((o) => o?.type === 'effort')?.values || [])];
132
96
  }
133
97
  return row;
134
98
  }
@@ -414,12 +378,9 @@ export class MuseCodeOAuthProvider {
414
378
  });
415
379
  this._innerKey = apiKey;
416
380
  // The Responses builder reads limits and the effort ladder from the inner
417
- // provider's cached model row; seeds fill in what discovery omits.
381
+ // provider's cached model row; the shared lookup fills what discovery omits.
418
382
  const innerRow = this._inner.getCachedModelInfo.bind(this._inner);
419
- this._inner.getCachedModelInfo = (model) => {
420
- const discovered = innerRow(model);
421
- return discovered || SEEDS[model] || lineageRow(model) ? museRow(model, discovered) : null;
422
- };
383
+ this._inner.getCachedModelInfo = (model) => museRow(model, innerRow(model));
423
384
  return this._inner;
424
385
  }
425
386
 
@@ -452,6 +413,8 @@ export class MuseCodeOAuthProvider {
452
413
  async listModels() {
453
414
  const { apiKey } = await this.ensureAuth();
454
415
  const inner = this._ensureInner(apiKey);
416
+ // Only the latest request, fetched with the still-active key, publishes.
417
+ const publish = museModelCache.beginSave(() => loadTokens()?.apiKey === apiKey);
455
418
  let items;
456
419
  try {
457
420
  items = await inner._fetchModelItems();
@@ -460,25 +423,29 @@ export class MuseCodeOAuthProvider {
460
423
  return SEED_MODELS.map((id) => museRow(id));
461
424
  }
462
425
  // A successful roster is authoritative, even when it holds no chat models.
463
- const rows = (Array.isArray(items) ? items : [])
426
+ const discovered = (Array.isArray(items) ? items : [])
464
427
  .filter((m) => typeof m?.id === 'string' && m.id && !NON_CHAT_MODEL_RE.test(m.id))
465
428
  .map((m) => {
466
429
  const contextWindow = Number(m.context_window ?? m.max_context_window ?? m.context_length ?? 0);
467
430
  const outputTokens = Number(m.max_output_tokens ?? m.output_tokens ?? 0);
468
431
  const name = [m.name, m.display_name].find((v) => typeof v === 'string' && v.trim());
469
- return museRow(m.id, {
432
+ return {
433
+ id: m.id,
434
+ provider: 'muse-code-oauth',
470
435
  ...(name ? { name: name.trim() } : {}),
471
436
  ...(contextWindow > 0 ? { contextWindow } : {}),
472
437
  ...(outputTokens > 0 ? { outputTokens } : {}),
473
438
  ...(typeof m.created === 'number' ? { created: m.created } : {}),
474
- });
439
+ };
475
440
  });
476
- inner._enrichedModels = rows;
441
+ const rows = discovered.map((row) => museRow(row.id, row));
442
+ // A superseded or other-credential response never replaces the live roster either.
443
+ if (publish(discovered)) inner._enrichedModels = rows;
477
444
  return rows;
478
445
  }
479
446
 
480
447
  getCachedModelInfo(model) {
481
- return this._inner?.getCachedModelInfo?.(model) || (SEEDS[model] || lineageRow(model) ? museRow(model) : null);
448
+ return this._inner?.getCachedModelInfo?.(model) || museRow(model);
482
449
  }
483
450
 
484
451
  /** Subscription window/weekly usage, read from the key endpoint without onboarding. */
@@ -6,6 +6,7 @@ import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs
6
6
  import { cursorTokenExpiry } from './cursor-auth.mjs';
7
7
  import { isValidMuseCredentialDocument } from './muse-code-oauth-tokens.mjs';
8
8
  import { developerOptionEnabled, developerOptionForProvider } from '../../../shared/developer-options.mjs';
9
+ import { modelProxyClientMode } from '../../../shared/model-proxy-mode.mjs';
9
10
 
10
11
  const ANTHROPIC_DEFAULT_CREDENTIALS_PATH = join(resolvePluginData(), 'anthropic-oauth-credentials.json');
11
12
 
@@ -100,6 +101,8 @@ function credentialPathsSignature(paths, extra = '') {
100
101
  }
101
102
 
102
103
  function memoProbe(key, paths, compute, extraSignature = '') {
104
+ // Remote mode: no credential file on this server is ever read.
105
+ if (modelProxyClientMode()) return 'absent';
103
106
  const signature = credentialPathsSignature(paths, extraSignature);
104
107
  const hit = _probeCache.get(key);
105
108
  const now = Date.now();
@@ -178,6 +181,17 @@ function mimoOAuthState() {
178
181
  );
179
182
  }
180
183
 
184
+ function commandCodeOAuthState() {
185
+ const paths = [
186
+ boundProviderAuthPath('command-code-oauth') ||
187
+ process.env.COMMAND_CODE_OAUTH_CREDENTIALS_PATH ||
188
+ join(resolvePluginData(), 'command-code-oauth.json'),
189
+ ];
190
+ return memoProbe('command-code-oauth', paths, () =>
191
+ resolveProbeState(paths, (docs) => docs.some((own) => typeof own?.apiKey === 'string' && !!own.apiKey.trim()))
192
+ );
193
+ }
194
+
181
195
  function museCodeOAuthState() {
182
196
  const paths = [
183
197
  boundProviderAuthPath('muse-code-oauth') ||
@@ -252,6 +266,7 @@ const OAUTH_PROBE_STATES = new Map([
252
266
  ['openai-oauth', openAIOAuthState],
253
267
  ['grok-oauth', grokOAuthState],
254
268
  ['muse-code-oauth', museCodeOAuthState],
269
+ ['command-code-oauth', commandCodeOAuthState],
255
270
  ['mimo-oauth', mimoOAuthState],
256
271
  ['cursor-oauth', cursorOAuthState],
257
272
  ['antigravity-oauth', antigravityOAuthState],
@@ -868,7 +868,8 @@ async function measureUsage(provider, providerObj, routeInfo) {
868
868
  (provider === 'cursor-oauth' ||
869
869
  provider === 'cursor-api' ||
870
870
  provider === 'antigravity-oauth' ||
871
- provider === 'muse-code-oauth') &&
871
+ provider === 'muse-code-oauth' ||
872
+ provider === 'command-code-oauth') &&
872
873
  typeof providerObj?.getUsageSnapshot === 'function'
873
874
  ) {
874
875
  return await providerObj.getUsageSnapshot();
@@ -893,12 +894,12 @@ async function measureUsageWithAuthRetry(provider, providerObj, routeInfo) {
893
894
  // refresh cannot vouch for the reading it last produced: keeping a 100% meter
894
895
  // earned by a dead token would hold the account out of the roster until its
895
896
  // reset time, so the recorded quota goes with the credential.
896
- function usageAfterFailure(err, provider, accountId, log) {
897
+ async function usageAfterFailure(err, provider, accountId, log) {
897
898
  const snapshot = provider === 'anthropic-oauth' && accountId === 'default' ? latestClaudeStatuslineUsage() : null;
898
899
  if (snapshot) return snapshot;
899
900
  if (isUsageAuthRejection(err) && ACCOUNT_PROVIDERS.includes(provider)) {
900
901
  try {
901
- clearProviderAccountQuotaState(provider, accountId);
902
+ await clearProviderAccountQuotaState(provider, accountId);
902
903
  } catch (error) {
903
904
  log(`Account usage could not be cleared: ${error.message}`);
904
905
  }
@@ -952,7 +953,7 @@ export async function fetchOAuthUsageSnapshot(routeInfo, providerObj, log = () =
952
953
  try {
953
954
  snapshot = await measureUsageWithAuthRetry(provider, providerObj, routeInfo);
954
955
  } catch (err) {
955
- snapshot = usageAfterFailure(err, provider, accountId, log);
956
+ snapshot = await usageAfterFailure(err, provider, accountId, log);
956
957
  }
957
958
  if (!isContentfulSnapshot(snapshot)) {
958
959
  cacheNegative(key, 'empty');
@@ -961,7 +962,7 @@ export async function fetchOAuthUsageSnapshot(routeInfo, providerObj, log = () =
961
962
  }
962
963
  if (ACCOUNT_PROVIDERS.includes(provider)) {
963
964
  try {
964
- recordProviderAccountUsage(provider, accountId, snapshot);
965
+ await recordProviderAccountUsage(provider, accountId, snapshot);
965
966
  } catch (error) {
966
967
  log(`Account usage could not be saved: ${error.message}`);
967
968
  }
@@ -38,7 +38,7 @@ export async function sendCompatChat(provider, messages, useModel, tools, opts)
38
38
  // global catalog must not shape a user-defined endpoint's request.
39
39
  let modelInfo = null;
40
40
  if (isCustom) modelInfo = provider.getCachedModelInfo(useModel) || null;
41
- else if (provider.name === 'opencode-go')
41
+ else if (provider.name === 'opencode-go' || provider.name === 'command-code-oauth')
42
42
  modelInfo = provider.getCachedModelInfo(useModel) || getModelMetadataSync(useModel, provider.name);
43
43
  else if (profile?.resolveModelInfo) modelInfo = profile.resolveModelInfo(provider, useModel) || null;
44
44
  // Resolved before lowering: replay eligibility depends on the snapped level
@@ -1,3 +1,4 @@
1
+ import { resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
1
2
  import { enrichModels } from './model-catalog.mjs';
2
3
  import { sanitizeModelList } from './model-list-sanitize.mjs';
3
4
  import { PROVIDER_GENERATE_TOTAL_TIMEOUT_MS, createTimeoutSignal, resolveTimeoutMs } from '../stall-policy.mjs';
@@ -10,12 +11,15 @@ const MODEL_LIST_TIMEOUT_MS = resolveTimeoutMs('MIXDOG_COMPAT_MODEL_LIST_TIMEOUT
10
11
  // `keyless` omits the Authorization header entirely (keyless endpoints);
11
12
  // `signal` aborts the request together with the list timeout.
12
13
  export async function fetchCompatModelItems(provider, { signal = null, keyless = false } = {}) {
13
- const timeout = createTimeoutSignal(signal, MODEL_LIST_TIMEOUT_MS, `${provider.name} model list`);
14
+ const name = provider.name;
15
+ const timeout = createTimeoutSignal(signal, MODEL_LIST_TIMEOUT_MS, `${name} model list`);
14
16
  try {
15
17
  const res = await fetch(`${String(provider.baseURL || '').replace(/\/+$/, '')}/models`, {
16
18
  method: 'GET',
17
19
  headers: {
18
- ...(keyless ? {} : { Authorization: `Bearer ${provider.apiKey || 'no-key'}` }),
20
+ ...(keyless
21
+ ? {}
22
+ : { Authorization: `Bearer ${resolveProviderApiKey(name, provider.config || provider) || 'no-key'}` }),
19
23
  ...(provider.defaultHeaders || {}),
20
24
  },
21
25
  signal: timeout.signal,
@@ -74,6 +74,17 @@ export function applyCompatProviderChatOptions(params, providerName, opts = {},
74
74
  }
75
75
  return params;
76
76
  }
77
+ if (providerName === 'command-code-oauth') {
78
+ // The API's field is undocumented; mirror the common `reasoning_effort`
79
+ // (levels the catalog row declares, else low/medium/high).
80
+ const rawEffort = opts.effort ?? config?.reasoningEffort;
81
+ const declared = modelInfo?.reasoningOptions?.some((option) => option?.type === 'effort');
82
+ const effort = declared
83
+ ? normalizeOpencodeGoReasoningEffort(rawEffort, modelInfo)
84
+ : normalizeReasoningEffort(rawEffort, ['low', 'medium', 'high']);
85
+ if (effort) params.reasoning_effort = effort;
86
+ return params;
87
+ }
77
88
  if (providerName === 'opencode-go') {
78
89
  const reasoningEffort = normalizeOpencodeGoReasoningEffort(opts.effort ?? config?.reasoningEffort, modelInfo);
79
90
  // OpenCode Go's OpenAI-compatible contract exposes reasoning_effort,
@@ -1,3 +1,4 @@
1
+ import { resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
1
2
  import { markProviderRecoveryExhausted, withRetry } from './retry-classifier.mjs';
2
3
  import { consumeCompatResponsesStream } from './openai-compat-stream.mjs';
3
4
  import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createPassthroughSignal } from '../stall-policy.mjs';
@@ -158,7 +159,7 @@ export async function sendXaiResponsesWebSocket(provider, messages, useModel, to
158
159
  const reason = signal.reason;
159
160
  throw reason instanceof Error ? reason : new Error('xAI Responses WebSocket request aborted by session close');
160
161
  }
161
- const apiKey = provider.config?.apiKey || process.env.XAI_API_KEY;
162
+ const apiKey = resolveProviderApiKey('xai', provider.config);
162
163
  if (!apiKey) throw new Error('xAI API key not configured');
163
164
  messages = await preparePdfTextForProvider(messages, provider);
164
165
  const chatMessagesForTrace = toOpenAIMessages(messages, provider.name, { nativePdf: provider.nativePdf });