mixdog 1.2.2 → 1.2.3

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 (415) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/provider-pingpong-live.mjs +509 -0
  4. package/src/agents/advisor/AGENT.md +1 -1
  5. package/src/agents/advisor/agent.json +1 -1
  6. package/src/defaults/shipped-history.json +5 -0
  7. package/src/defaults/skills/setup/SKILL.md +6 -1
  8. package/src/defaults/skills/setup/references/actions.md +44 -22
  9. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  10. package/src/headless-exec.mjs +15 -8
  11. package/src/lib/keychain-cjs.cjs +7 -4
  12. package/src/output-styles/common.md +11 -10
  13. package/src/rules/agent/AGENT.md +5 -5
  14. package/src/rules/lead/LEAD.md +5 -5
  15. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  16. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  17. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  18. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  19. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  21. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  22. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  23. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +2 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +7 -6
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +29 -10
  28. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  30. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  31. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  32. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +58 -7
  39. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  40. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +16 -3
  41. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  42. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +12 -6
  43. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +114 -72
  45. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +37 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +1 -0
  49. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  50. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +3 -0
  51. package/src/runtime/agent/orchestrator/providers/cursor.mjs +9 -2
  52. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  53. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  54. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  55. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  56. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  57. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  59. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +25 -8
  60. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +87 -5
  61. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  62. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +13 -13
  63. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +355 -37
  64. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  65. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +93 -47
  66. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +55 -10
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +26 -8
  68. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  70. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  71. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  72. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  73. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  74. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  75. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  76. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  77. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  78. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  80. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  81. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  82. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  83. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  84. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  85. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  86. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +121 -61
  89. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  90. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  91. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  92. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  93. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  95. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  96. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  97. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  98. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +42 -24
  99. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  100. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  101. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  102. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +53 -5
  103. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  104. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  107. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  108. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  109. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  110. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  111. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +25 -4
  112. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  113. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  114. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  115. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  117. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  118. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  119. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  120. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  121. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +71 -24
  122. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  123. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  124. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  125. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  126. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  127. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  128. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  129. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  130. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +11 -3
  131. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  132. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  133. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  134. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +147 -8
  135. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  136. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +5 -0
  137. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  138. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  139. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  140. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  141. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  142. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  143. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  144. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  145. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  146. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  147. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  148. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  149. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  150. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  151. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  152. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  153. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  154. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  155. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -1
  156. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  157. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  158. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  159. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  160. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  161. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  162. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  163. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  164. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  165. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  167. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  168. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  169. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  170. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  171. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  172. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +63 -20
  173. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +2 -1
  174. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  175. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  176. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  177. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  178. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  179. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +4 -1
  180. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  181. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  182. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +16 -0
  183. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  184. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  186. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  187. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  188. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +15 -3
  189. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  190. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  191. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  192. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  193. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  195. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  196. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +13 -0
  197. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  198. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  199. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  200. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  201. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  202. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  203. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  204. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  205. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  206. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  207. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
  208. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  209. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  210. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  211. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  212. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  213. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  215. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  216. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  217. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  218. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  219. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  222. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  223. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  224. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  225. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  226. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  227. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  228. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  229. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  230. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  231. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  232. package/src/runtime/github/tool.mjs +92 -2
  233. package/src/runtime/memory/index.mjs +1 -0
  234. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  235. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  236. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  237. package/src/runtime/memory/lib/pg/process.mjs +31 -26
  238. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +108 -3
  240. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  241. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  242. package/src/runtime/office/README.md +1 -1
  243. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  244. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  245. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  246. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  247. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  248. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  249. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  250. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  251. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  252. package/src/runtime/office/core/office-sessions.mjs +5 -0
  253. package/src/runtime/office/core/office-transactions.mjs +3 -0
  254. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  255. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  256. package/src/runtime/office/index.mjs +30 -0
  257. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  258. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  259. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  260. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  261. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  262. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  263. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  264. package/src/runtime/shared/buffered-appender.mjs +18 -0
  265. package/src/runtime/shared/config.mjs +78 -18
  266. package/src/runtime/shared/err-text.mjs +6 -0
  267. package/src/runtime/shared/file-permissions.d.mts +6 -1
  268. package/src/runtime/shared/file-permissions.mjs +54 -6
  269. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  270. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  271. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  272. package/src/runtime/shared/loopback-listener.mjs +9 -0
  273. package/src/runtime/shared/provider-api-key.mjs +2 -0
  274. package/src/runtime/shared/review-diff.mjs +52 -0
  275. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  276. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  277. package/src/runtime/shared/slow-span.mjs +114 -0
  278. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  279. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  280. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  281. package/src/runtime/shared/tool-card-model.mjs +5 -2
  282. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  283. package/src/runtime/shared/tool-primitives.mjs +13 -0
  284. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  285. package/src/runtime/shared/tool-surface.mjs +18 -3
  286. package/src/runtime/shared/tool-work-units.mjs +40 -4
  287. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  288. package/src/runtime/shared/transcript-writer.mjs +10 -2
  289. package/src/runtime/shared/turn-changes.mjs +268 -100
  290. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  291. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  292. package/src/runtime/shared/turn-snapshot.mjs +857 -683
  293. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  294. package/src/runtime/shared/user-data-guard.mjs +262 -49
  295. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  296. package/src/runtime/shared/worktrees/contract.mjs +34 -0
  297. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  298. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  299. package/src/runtime/shared/worktrees/git.mjs +8 -3
  300. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  301. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  302. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  303. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  304. package/src/runtime/terminal-bridge/client.mjs +44 -11
  305. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  306. package/src/runtime/tidy/apply.mjs +47 -2
  307. package/src/runtime/tidy/run-engines.mjs +11 -5
  308. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  309. package/src/session-runtime/boot/apis.mjs +13 -5
  310. package/src/session-runtime/boot/facade.mjs +1 -0
  311. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  312. package/src/session-runtime/boot/session.mjs +0 -1
  313. package/src/session-runtime/boot/tools.mjs +4 -1
  314. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  315. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  316. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  317. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  318. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  319. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  320. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  321. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  322. package/src/session-runtime/lifecycle/session-catalog.mjs +12 -3
  323. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  324. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  325. package/src/session-runtime/lifecycle/teardown.mjs +72 -7
  326. package/src/session-runtime/lifecycle-api.mjs +1 -0
  327. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  328. package/src/session-runtime/model-route/set-route.mjs +2 -2
  329. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  330. package/src/session-runtime/native-web-search.mjs +10 -1
  331. package/src/session-runtime/new-session-config.mjs +4 -2
  332. package/src/session-runtime/provider-auth/login.mjs +4 -0
  333. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  334. package/src/session-runtime/runtime-review-api.mjs +8 -2
  335. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  336. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  337. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  338. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  339. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  340. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  341. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  342. package/src/session-runtime/services/agent-tool.mjs +3 -0
  343. package/src/session-runtime/services/channel-admin.mjs +19 -3
  344. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  345. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  346. package/src/session-runtime/services/provider-admin.mjs +81 -15
  347. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  348. package/src/session-runtime/session-turn-api.mjs +14 -5
  349. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  350. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  351. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  352. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  353. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  354. package/src/session-runtime/skills-api.mjs +3 -5
  355. package/src/session-runtime/tool-surface.mjs +5 -1
  356. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  357. package/src/session-runtime/turn/session-ops.mjs +7 -5
  358. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  359. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  360. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  361. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  362. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  363. package/src/session-runtime/turn/turn-run.mjs +25 -9
  364. package/src/session-runtime/usage-stats-api.mjs +43 -11
  365. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  366. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  367. package/src/session-runtime/workspace/transitions.mjs +190 -15
  368. package/src/standalone/daemon-agent-control.mjs +9 -1
  369. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  370. package/src/standalone/daemon-owner.mjs +17 -4
  371. package/src/standalone/daemon-pg-stop.mjs +51 -0
  372. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  373. package/src/standalone/daemon-stop-budget.mjs +18 -0
  374. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  375. package/src/standalone/daemon-telemetry.mjs +19 -0
  376. package/src/standalone/daemon.mjs +61 -1
  377. package/src/standalone/desktop-service-registry.mjs +5 -0
  378. package/src/standalone/local-session-runtime.mjs +70 -19
  379. package/src/standalone/session-client.mjs +42 -0
  380. package/src/standalone/session-protocol.mjs +7 -0
  381. package/src/standalone/session-proxy/projection.mjs +41 -4
  382. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  383. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  384. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  385. package/src/standalone/session-service-api.mjs +6 -1
  386. package/src/standalone/session-state-patch.d.mts +2 -1
  387. package/src/standalone/session-state-patch.mjs +41 -1
  388. package/src/tui/App.jsx +25 -0
  389. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  390. package/src/tui/app/btw-controller.mjs +118 -0
  391. package/src/tui/app/create-app-pickers.mjs +2 -0
  392. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  393. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  394. package/src/tui/app/slash-commands.mjs +13 -3
  395. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  396. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  397. package/src/tui/app/use-global-key-input.mjs +5 -12
  398. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  399. package/src/tui/components/BtwPanel.jsx +53 -0
  400. package/src/tui/components/QuestionPanel.jsx +275 -0
  401. package/src/tui/components/question-panel-model.mjs +156 -0
  402. package/src/tui/dist/index.mjs +2413 -1465
  403. package/src/tui/session/context-state.mjs +4 -2
  404. package/src/tui/session/session-api/commands.mjs +10 -0
  405. package/src/tui/session/session-api/controls.mjs +2 -2
  406. package/src/tui/session/session-api/integrations.mjs +9 -2
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  408. package/src/tui/session/session-api/lifecycle.mjs +2 -1
  409. package/src/tui/session/session-api/settings.mjs +6 -0
  410. package/src/tui/session/session-api.mjs +1 -0
  411. package/src/tui/session/tool-approval.mjs +10 -7
  412. package/src/tui/session/transcript-spill.mjs +14 -7
  413. package/src/tui/session/turn-stream.mjs +174 -31
  414. package/src/tui/session/turn.mjs +12 -5
  415. package/src/workflows/default/WORKFLOW.md +3 -1
@@ -2,23 +2,25 @@
2
2
  * Command Code provider (commandcode.ai Provider API).
3
3
  *
4
4
  * Credentials are a Studio-issued API key (command-code-oauth-tokens.mjs).
5
- * Each model is served on the endpoint its /models row declares: Chat
6
- * Completions through the OpenAI-compatible engine, Messages-only models
7
- * (Claude) through the Anthropic engine. Both clients are pinned to the
8
- * Command Code API host. The key never expires and has no refresh grant: a
9
- * 401 means the user must sign in again.
5
+ * Each model is served on a wire its /models row declares (wire-route.mjs
6
+ * picks among them): Chat Completions and Responses through the
7
+ * OpenAI-compatible engine, Messages through the Anthropic engine. Both
8
+ * clients are pinned to the Command Code API host. The key never expires and
9
+ * has no refresh grant: a 401 means the user must sign in again.
10
10
  */
11
11
  import { noteErrorUsage } from './lib/note-error-usage.mjs';
12
12
  import { fileMtimeMs, normalizeExpiresAtMs, scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
13
+ import { originBoundFetch } from './lib/origin-bound-fetch.mjs';
14
+ import { withInclusiveUsage } from './lib/inclusive-usage.mjs';
13
15
  import { OpenAICompatProvider, preloadOpenAICompatRuntime } from './openai-compat.mjs';
14
16
  import { COMPAT_RETRY_POLICY } from './openai-compat-retry-profile.mjs';
15
17
  import { listCompatModels } from './openai-compat-models.mjs';
16
18
  import { AnthropicProvider } from './anthropic.mjs';
17
- import { toInclusiveOpenCodeGoUsage as toInclusiveUsage } from './opencode-go.mjs';
18
19
  import { sanitizeToolPairs } from '../session/context-utils.mjs';
19
20
  import { preparePdfTextForProvider } from './media-normalization.mjs';
20
- import { currentUsageContext } from '../../../shared/llm/usage-context.mjs';
21
21
  import { makeModelCache } from './model-cache.mjs';
22
+ import { resolveWireRoute, sendOnRoute } from './wire-route.mjs';
23
+ import { gatewayMessagesOpts } from './wire-gateway.mjs';
22
24
  import {
23
25
  API_ORIGIN,
24
26
  CREDITS_URL,
@@ -38,8 +40,11 @@ export {
38
40
  export { beginOAuthLogin, loginOAuth } from './command-code-oauth-login.mjs';
39
41
 
40
42
  export const DEFAULT_MODEL = 'deepseek/deepseek-v4-flash';
41
- const CHAT_ENDPOINT = '/chat/completions';
42
- const MESSAGES_ENDPOINT = '/messages';
43
+ const ENDPOINT_WIRES = Object.freeze({
44
+ '/chat/completions': 'chat',
45
+ '/messages': 'messages',
46
+ '/responses': 'responses',
47
+ });
43
48
  // The Anthropic SDK appends /v1/messages itself.
44
49
  const MESSAGES_BASE_URL = `${API_ORIGIN}/provider`;
45
50
  const FIVE_HOURS_MS = 5 * 60 * 60 * 1000;
@@ -56,35 +61,42 @@ const commandCodeModelCache = makeModelCache({
56
61
  });
57
62
 
58
63
  /**
59
- * The wire a /models row is served on: 'chat' when it declares Chat
60
- * Completions or declares no endpoints at all, 'messages' when it declares
61
- * only Messages, null when it declares neither.
64
+ * The wires a /models row declares (`supported_endpoints`), or null when it
65
+ * declares none — such a row is served on Chat Completions by convention.
66
+ */
67
+ export function modelEndpoints(item) {
68
+ const declared = item?.supported_endpoints;
69
+ if (!Array.isArray(declared)) return null;
70
+ const wires = [];
71
+ for (const endpoint of declared) {
72
+ const path = String(endpoint).replace(/^\/?(?:provider\/)?(?:v1\/)?/, '/');
73
+ const wire = Object.hasOwn(ENDPOINT_WIRES, path) ? ENDPOINT_WIRES[path] : null;
74
+ if (wire && !wires.includes(wire)) wires.push(wire);
75
+ }
76
+ return wires;
77
+ }
78
+
79
+ // The route for a model with these declared endpoints (null: undeclared, Chat).
80
+ // `undefined`: nothing describes the model, so no wire is ruled out.
81
+ function commandCodeRoute(model, endpoints, ctx = {}) {
82
+ return resolveWireRoute(PROVIDER_ID, model, { ...ctx, endpoints: endpoints === undefined ? null : (endpoints ?? ['chat']) });
83
+ }
84
+
85
+ /**
86
+ * The wire a /models row is served on (wire-route.mjs over its declared
87
+ * endpoints): Responses for GPT / Muse / Grok when advertised, otherwise Chat
88
+ * when declared or undeclared, Messages when it is the only one, Responses
89
+ * for a Responses-only row; null when it declares none of them.
62
90
  */
63
91
  export function modelWire(item) {
64
92
  if (typeof item?.id !== 'string' || !item.id) return null;
65
- const endpoints = item.supported_endpoints;
66
- if (!Array.isArray(endpoints)) return 'chat';
67
- const declared = endpoints.map((endpoint) => String(endpoint).replace(/^\/?(?:provider\/)?(?:v1\/)?/, '/'));
68
- if (declared.includes(CHAT_ENDPOINT)) return 'chat';
69
- if (declared.includes(MESSAGES_ENDPOINT)) return 'messages';
70
- return null;
93
+ return commandCodeRoute(item.id, modelEndpoints(item))?.wire || null;
71
94
  }
72
95
 
73
- // Every request either engine makes goes through this fetch: anything outside
74
- // the Command Code API origin is refused before the key leaves the process,
75
- // and redirects are never followed (any 3xx is an error).
96
+ // Every request either engine makes goes through this fetch: only the Command
97
+ // Code API origin, never a redirect.
76
98
  function apiOnlyFetch(fetchImpl) {
77
- return async (input, init) => {
78
- const url = new URL(String(input?.url ?? input));
79
- if (url.origin !== API_ORIGIN) {
80
- throw new Error(`[command-code-oauth] refusing to send the API key to ${url.host}`);
81
- }
82
- const res = await (fetchImpl || globalThis.fetch)(input, { ...init, redirect: 'manual' });
83
- if (res.status >= 300 && res.status < 400) {
84
- throw new Error(`[command-code-oauth] refusing to follow a redirect from ${url.host}`);
85
- }
86
- return res;
87
- };
99
+ return originBoundFetch(API_ORIGIN, fetchImpl, PROVIDER_ID);
88
100
  }
89
101
 
90
102
  // Anthropic engine bound to this credential: only the Command Code key is
@@ -98,15 +110,11 @@ class CommandCodeMessagesEngine extends AnthropicProvider {
98
110
  client.fetch = apiOnlyFetch(this.config.fetchImpl);
99
111
  return client;
100
112
  }
101
- }
102
-
103
- const normalizeUsageError = (err) => {
104
- if (err && typeof err === 'object') {
105
- if (err.usage) err.usage = toInclusiveUsage(err.usage);
106
- if (err.partialUsage) err.partialUsage = toInclusiveUsage(err.partialUsage);
113
+ // The roster's output ceiling reaches the shared request builder.
114
+ _sendOnce(messages, model, tools, opts) {
115
+ return super._sendOnce(messages, model, tools, gatewayMessagesOpts(this.config, model, messages, opts));
107
116
  }
108
- return err;
109
- };
117
+ }
110
118
 
111
119
  function rosterRow(item) {
112
120
  const contextWindow = Number(item.context_window ?? item.max_context_window ?? item.context_length ?? 0);
@@ -118,6 +126,11 @@ function rosterRow(item) {
118
126
  ...(name ? { name: name.trim() } : {}),
119
127
  ...(contextWindow > 0 ? { contextWindow } : {}),
120
128
  ...(outputTokens > 0 ? { outputTokens } : {}),
129
+ // The full declared endpoint set: the cached route metadata a later
130
+ // send falls back on when the live roster cannot be read.
131
+ ...(Array.isArray(item.supported_endpoints)
132
+ ? { supportedEndpoints: item.supported_endpoints.map((endpoint) => String(endpoint)) }
133
+ : {}),
121
134
  };
122
135
  }
123
136
 
@@ -147,11 +160,16 @@ function scrubErrorSecrets(err, apiKey) {
147
160
  }
148
161
 
149
162
  // Redact where the transport first surfaces errors (request open and stream
150
- // iteration), so the shared retry reporter never logs the key.
163
+ // iteration) on the Chat and Responses endpoints, so the shared retry
164
+ // reporter never logs the key.
151
165
  function redactClientErrors(client, apiKey) {
152
- const completions = client?.chat?.completions;
153
- if (!completions || !apiKey || completions.create?.commandCodeRedacting === apiKey) return;
154
- const create = completions.create.bind(completions);
166
+ redactCreateErrors(client?.chat?.completions, apiKey);
167
+ redactCreateErrors(client?.responses, apiKey);
168
+ }
169
+
170
+ function redactCreateErrors(endpoint, apiKey) {
171
+ if (!endpoint || !apiKey || endpoint.create?.commandCodeRedacting === apiKey) return;
172
+ const create = endpoint.create.bind(endpoint);
155
173
  const wrapped = async (...args) => {
156
174
  try {
157
175
  const stream = await create(...args);
@@ -177,7 +195,7 @@ function redactClientErrors(client, apiKey) {
177
195
  }
178
196
  };
179
197
  wrapped.commandCodeRedacting = apiKey;
180
- completions.create = wrapped;
198
+ endpoint.create = wrapped;
181
199
  }
182
200
 
183
201
  // Same for the Anthropic client's streaming request (read through
@@ -253,8 +271,9 @@ export class CommandCodeOAuthProvider {
253
271
  _defaultModelKey = null;
254
272
  _messages = null;
255
273
  _messagesKey = null;
256
- // Model id → wire ('chat' | 'messages') from the roster fetched with `_wiresKey`.
257
- _wires = new Map();
274
+ // Model id → declared endpoint wires (null: undeclared) from the roster
275
+ // fetched with `_wiresKey`.
276
+ _endpoints = new Map();
258
277
  _wiresKey = null;
259
278
 
260
279
  constructor(config) {
@@ -315,6 +334,8 @@ export class CommandCodeOAuthProvider {
315
334
  apiKey,
316
335
  baseURL: MESSAGES_BASE_URL,
317
336
  disableBetaHeaders: true,
337
+ modelMaxOutputTokens: (model) =>
338
+ commandCodeModelCache.loadSync({ allowStale: true })?.find((row) => row?.id === model)?.outputTokens,
318
339
  // x-api-key from the SDK plus the bearer form of the same key.
319
340
  extraHeaders: { Authorization: `Bearer ${apiKey}` },
320
341
  });
@@ -324,8 +345,9 @@ export class CommandCodeOAuthProvider {
324
345
  return engine;
325
346
  }
326
347
 
327
- // Servable rows from /models; only the latest fetch with the still-active
328
- // key publishes the roster and the per-model wire map.
348
+ // Servable rows from /models (any declared Chat, Messages or Responses
349
+ // endpoint, or none declared); only the latest fetch with the still-active
350
+ // key publishes the roster and the per-model endpoint map.
329
351
  async _fetchRoster(apiKey, signal = null) {
330
352
  const publish = commandCodeModelCache.beginSave(() => loadTokens()?.apiKey === apiKey);
331
353
  const body = await requestCommandCodeJson(`${PROVIDER_BASE_URL}/models`, apiKey, {
@@ -338,16 +360,30 @@ export class CommandCodeOAuthProvider {
338
360
  const items = list.filter((item) => modelWire(item));
339
361
  publish(items.map(rosterRow));
340
362
  if (this.tokens?.apiKey === apiKey) {
341
- this._wires = new Map(items.map((item) => [item.id, modelWire(item)]));
363
+ // Rows accumulate for one key: a later roster that misses a model
364
+ // leaves the endpoints it was last listed with.
365
+ const known = this._wiresKey === apiKey ? this._endpoints : new Map();
366
+ for (const item of items) known.set(item.id, modelEndpoints(item));
367
+ this._endpoints = known;
342
368
  this._wiresKey = apiKey;
343
369
  }
344
370
  return items;
345
371
  }
346
372
 
347
- // The wire for a model, from this credential's roster (fetched once when
348
- // missing). A model the roster does not know, or a roster that cannot be
349
- // read right now, stays on Chat Completions; a rejected key is surfaced.
350
- async _wireFor(inner, model) {
373
+ // A model's declared endpoints: what this credential's rosters listed,
374
+ // then the persisted roster (a roster miss or a roster that cannot be read
375
+ // right now must not move a known Messages-only model to Chat). null is a
376
+ // row declaring none (Chat); undefined is a model nothing describes.
377
+ _endpointsFor(apiKey, model) {
378
+ if (this._wiresKey === apiKey && this._endpoints.has(model)) return this._endpoints.get(model);
379
+ const cached = commandCodeModelCache.loadSync({ allowStale: true })?.find((row) => row?.id === model);
380
+ return cached ? modelEndpoints({ supported_endpoints: cached.supportedEndpoints }) : undefined;
381
+ }
382
+
383
+ // This credential's route for a model (the roster is fetched once when
384
+ // missing; a roster that cannot be read falls back on the persisted rows);
385
+ // a rejected key is surfaced.
386
+ async _routeFor(inner, model, ctx = {}) {
351
387
  if (this._wiresKey !== inner.apiKey) {
352
388
  try {
353
389
  await listCompatModels(inner, { throwOnError: true });
@@ -355,7 +391,16 @@ export class CommandCodeOAuthProvider {
355
391
  if (isUnauthorized(err)) throw err;
356
392
  }
357
393
  }
358
- return (this._wiresKey === inner.apiKey && this._wires.get(model)) || 'chat';
394
+ const endpoints = this._endpointsFor(inner.apiKey, model);
395
+ return commandCodeRoute(model, endpoints, {
396
+ ...ctx,
397
+ override: this.config?.modelWires?.[model] ?? null,
398
+ known: endpoints !== undefined,
399
+ });
400
+ }
401
+
402
+ resolveWireRoute(model, ctx = {}) {
403
+ return this._routeFor(this._ensureInner(), model, ctx);
359
404
  }
360
405
 
361
406
  // A rejected key needs a fresh sign-in; the gateway's own detail stays attached.
@@ -382,17 +427,21 @@ export class CommandCodeOAuthProvider {
382
427
  throw this._shapeError(err, this.tokens?.apiKey);
383
428
  }
384
429
  const apiKey = this._innerKey;
385
- // The model's declared endpoint picks the wire; a caller cannot move a
386
- // model to Responses.
387
- const { compatWireApi: _wire, responsesTransport: _transport, ...opts } = sendOpts || {};
430
+ // The model's route (the session's pinned one, else its declared
431
+ // endpoints) picks the wire; a caller's compat wire flag cannot move it.
432
+ const { compatWireApi: _wire, responsesTransport: _transport, ...callerOpts } = sendOpts || {};
388
433
  try {
389
434
  const useModel = model || (await this._pickDefaultModel(inner));
390
- if ((await this._wireFor(inner, useModel)) === 'messages') {
391
- return await this._sendMessages(apiKey, messages, useModel, tools, opts);
392
- }
393
- // _doSend directly: the compat wrapper's 401 handler reloads a static
394
- // config key, which does not apply to this credential.
395
- return await inner._doSend(messages, useModel, tools, opts);
435
+ // One clear "unsupported" refusal moves the send to the next wire once.
436
+ return await sendOnRoute(this, useModel, tools, callerOpts, messages, (wire, history, opts) => {
437
+ if (wire === 'messages') return this._sendMessages(apiKey, history, useModel, tools, opts);
438
+ // _doSend directly: the compat wrapper's 401 handler reloads a static
439
+ // config key, which does not apply to this credential.
440
+ if (wire === 'responses') {
441
+ return inner._doSend(history, useModel, tools, { ...opts, compatWireApi: 'responses' });
442
+ }
443
+ return inner._doSend(history, useModel, tools, opts);
444
+ });
396
445
  } catch (err) {
397
446
  throw this._shapeError(err, apiKey);
398
447
  }
@@ -405,14 +454,7 @@ export class CommandCodeOAuthProvider {
405
454
  async _sendMessages(apiKey, messages, model, tools, opts) {
406
455
  const engine = this._ensureMessages(apiKey);
407
456
  const prepared = await preparePdfTextForProvider(sanitizeToolPairs(messages), engine);
408
- const identity = currentUsageContext();
409
- if (identity) identity.normalizeAbandonedUsage = toInclusiveUsage;
410
- try {
411
- const result = await engine._doSend(prepared, model, tools, opts);
412
- return result?.usage ? { ...result, usage: toInclusiveUsage(result.usage) } : result;
413
- } catch (err) {
414
- throw normalizeUsageError(err);
415
- }
457
+ return withInclusiveUsage(() => engine._doSend(prepared, model, tools, opts));
416
458
  }
417
459
 
418
460
  async listModels() {
@@ -1,5 +1,6 @@
1
1
  // Shared request controls for Chat Completions and Responses gateways.
2
2
  import { emitProviderRetryStage, retryDelayLabel } from './retry-classifier.mjs';
3
+ import { isTogetherBaseURL } from './openai-compat-reasoning-field.mjs';
3
4
 
4
5
  // withRetry onRetry for the compat stream sends: one stderr line plus a
5
6
  // display-only 'reconnecting' stage for the UI.
@@ -13,8 +14,83 @@ export function compatStreamRetryReporter(label, opts) {
13
14
  };
14
15
  }
15
16
 
16
- export function applyCompatToolChoice(body, opts = {}) {
17
- if (body.tools?.length && opts.toolChoice === 'none') body.tool_choice = 'none';
17
+ // Providers whose docs accept `required` / named tool_choice, and the subset
18
+ // that also documents `parallel_tool_calls`. DeepSeek documents no
19
+ // parallel_tool_calls, and rejects forced choices in thinking mode.
20
+ const FORCED_CHOICE_PROVIDERS = new Set([
21
+ 'xai',
22
+ 'deepseek',
23
+ 'openrouter',
24
+ 'mistral',
25
+ 'groq',
26
+ 'fireworks',
27
+ 'together',
28
+ 'command-code-oauth',
29
+ ]);
30
+ const PARALLEL_CALLS_PROVIDERS = new Set([
31
+ 'xai',
32
+ 'openrouter',
33
+ 'mistral',
34
+ 'groq',
35
+ 'fireworks',
36
+ 'together',
37
+ 'command-code-oauth',
38
+ ]);
39
+
40
+ function hostMatches(baseURL, domain) {
41
+ try {
42
+ const host = new URL(String(baseURL || '')).hostname.toLowerCase();
43
+ return host === domain || host.endsWith(`.${domain}`);
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ function compatToolFamily(provider, baseURL) {
50
+ if (FORCED_CHOICE_PROVIDERS.has(provider)) return provider;
51
+ if (isTogetherBaseURL(baseURL)) return 'together';
52
+ if (hostMatches(baseURL, 'fireworks.ai')) return 'fireworks';
53
+ if (hostMatches(baseURL, 'mistral.ai')) return 'mistral';
54
+ if (hostMatches(baseURL, 'groq.com')) return 'groq';
55
+ return null;
56
+ }
57
+
58
+ function forcedToolChoice(choice, wire) {
59
+ if (choice === 'required') return 'required';
60
+ if (!choice || typeof choice !== 'object') return null;
61
+ const name = choice.function?.name || choice.name;
62
+ if (typeof name !== 'string' || !name) return null;
63
+ return wire === 'responses' ? { type: 'function', name } : { type: 'function', function: { name } };
64
+ }
65
+
66
+ /**
67
+ * Tool-choice controls. `none` is universal. With `ctx` ({ provider, baseURL,
68
+ * wire: 'chat'|'responses', thinking: 'enabled'|'disabled'|null }) the
69
+ * documented providers also get explicit `required` / named tool_choice and an
70
+ * explicit boolean `opts.parallelToolCalls`; without it only `none` applies.
71
+ * DeepSeek rejects forced choices while thinking is explicitly enabled and
72
+ * keeps omitting them when thinking is left to the server default.
73
+ */
74
+ export function applyCompatToolChoice(body, opts = {}, ctx = null) {
75
+ if (!(body.tools?.length > 0)) return body;
76
+ if (opts.toolChoice === 'none') body.tool_choice = 'none';
77
+ const family = ctx?.provider ? compatToolFamily(ctx.provider, ctx.baseURL) : null;
78
+ if (!family) return body;
79
+ const forced = forcedToolChoice(opts.toolChoice, ctx.wire);
80
+ if (forced) {
81
+ if (family === 'deepseek' && ctx.thinking === 'enabled') {
82
+ throw Object.assign(
83
+ new Error(
84
+ '[deepseek] tool_choice "required" or a named tool is not supported in thinking mode; disable thinking (effort none) to force a tool call'
85
+ ),
86
+ { code: 'unsupported_tool_choice' }
87
+ );
88
+ }
89
+ if (family !== 'deepseek' || ctx.thinking === 'disabled') body.tool_choice = forced;
90
+ }
91
+ if (typeof opts.parallelToolCalls === 'boolean' && PARALLEL_CALLS_PROVIDERS.has(family)) {
92
+ body.parallel_tool_calls = opts.parallelToolCalls;
93
+ }
18
94
  return body;
19
95
  }
20
96
 
@@ -130,7 +130,7 @@ function saveCredentials(tokens) {
130
130
 
131
131
  export function hasCursorOAuthCredentials() {
132
132
  const tokens = loadStoredCredentials();
133
- if (!tokens?.access_token) return false;
133
+ if (!tokens?.access_token || tokens.reauth_required === true) return false;
134
134
  const expiresAt = Number(tokens.expires_at) || 0;
135
135
  return expiresAt === 0 || expiresAt > Date.now() || Boolean(tokens.refresh_token);
136
136
  }
@@ -147,6 +147,18 @@ export function describeCursorOAuthCredentials() {
147
147
  detail: 'Mixdog token store or CURSOR_ACCESS_TOKEN',
148
148
  };
149
149
  }
150
+ if (tokens.reauth_required === true) {
151
+ return {
152
+ authenticated: false,
153
+ usable: false,
154
+ refreshable: false,
155
+ reauthRequired: true,
156
+ status: 'Reauth Required',
157
+ detail: tokens.source || 'Cursor OAuth',
158
+ expiresAt: Number(tokens.expires_at) || null,
159
+ ...accountIdentityFields(tokens.identity),
160
+ };
161
+ }
150
162
  const expiresAt = Number(tokens.expires_at) || 0;
151
163
  const expired = expiresAt > 0 && expiresAt <= Date.now();
152
164
  const expiring = expiresAt > 0 && expiresAt <= Date.now() + REFRESH_SKEW_MS;
@@ -336,10 +348,30 @@ export async function resolveCursorOAuthAccessToken({ forceRefresh = false, fetc
336
348
  // (turn cancel / session close) kill it would fail the refresh for
337
349
  // all of them and leave the process without a usable token. Its own
338
350
  // timeout bounds the request instead.
339
- const next = await exchangeCursorToken(latest.refresh_token, {
340
- fetchFn,
341
- signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
342
- });
351
+ let next;
352
+ try {
353
+ next = await exchangeCursorToken(latest.refresh_token, {
354
+ fetchFn,
355
+ signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
356
+ });
357
+ } catch (error) {
358
+ if (error?.reauthRequired !== true) throw error;
359
+ // Mark the account dead only if no other process replaced the
360
+ // refresh token meanwhile. Non-destructive: tokens stay intact and
361
+ // a new sign-in rewrites the file without this marker.
362
+ if (!process.env.CURSOR_ACCESS_TOKEN || boundProviderAuthPath('cursor-oauth')) {
363
+ const current = loadStoredCredentials();
364
+ if (current?.refresh_token && current.refresh_token === latest.refresh_token) {
365
+ const { source: _source, ...persisted } = current;
366
+ try {
367
+ saveCredentials({ ...persisted, reauth_required: true });
368
+ } catch (saveError) {
369
+ process.stderr.write(`[cursor-oauth] dead-account mark failed: ${String(saveError?.message || saveError).slice(0, 200)}\n`);
370
+ }
371
+ }
372
+ }
373
+ throw error;
374
+ }
343
375
  if (!process.env.CURSOR_ACCESS_TOKEN || boundProviderAuthPath('cursor-oauth')) {
344
376
  saveCredentials(next);
345
377
  }
@@ -4,7 +4,7 @@ import { createRemoteVersionSource } from './npm-cli-version.mjs';
4
4
  // documented version endpoint; the official installer script embeds the
5
5
  // current build (…/lab/<build>/…), parsed best-effort. Any format change or
6
6
  // failure falls back to the floor.
7
- export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.14-0f9edde';
7
+ export const CURSOR_CLIENT_VERSION_FLOOR = 'cli-2026.10.14-941492e';
8
8
  const BUILD_PATTERN = /downloads\.cursor\.com\/lab\/(\d{4}\.\d{2}\.\d{2}-[0-9a-f]{6,40})\//;
9
9
  export const CURSOR_INSTALL_URL = 'https://cursor.com/install';
10
10
 
@@ -207,6 +207,7 @@ export function createBridgeController(ctx) {
207
207
  conversation: run.conversation,
208
208
  tools: run.tools,
209
209
  cloudRule: run.cloudRule,
210
+ sessionId: run.sessionId,
210
211
  };
211
212
  const frameParser = createFrameParser(
212
213
  // Server requests answer on whichever bridge is live when they arrive.
@@ -3,12 +3,46 @@
3
3
  * to the shared stream state and relayed to the SSE sink. Returns the
4
4
  * message's forward-progress kind for the watchdog.
5
5
  */
6
+ import { appendAgentTrace } from '../agent-trace.mjs';
6
7
  import { decodeMessage } from './cursor-wire-protobuf.mjs';
7
8
  import { MAX_CHECKPOINT_BYTES, cursorInteractionProgress } from './cursor-wire-guards.mjs';
8
9
  import { buildCursorInteractionResponse } from './cursor-wire-interactions.mjs';
9
10
  import { cursorError } from './cursor-wire-transport.mjs';
10
11
  import { handleExecMessage, handleKvMessage, sendClientMessage } from './cursor-wire-exec.mjs';
11
12
 
13
+ // Unknown fields seen on every live frame: AgentServerMessage field 8 (timing
14
+ // doubles) and InteractionUpdate field 25 (epoch-ms timestamp). Never traced.
15
+ const NOISE_SERVER_FIELDS = new Set([8]);
16
+ const NOISE_UPDATE_FIELDS = new Set([25]);
17
+ const TRACE_MAX_FIELDS = 8;
18
+ const TRACE_PREVIEW_BYTES = 48;
19
+
20
+ // Records undecoded fields (number, wire type, bounded hex of the raw field)
21
+ // so a new server event such as a mid-turn model fallback can be inspected.
22
+ function traceUnknownFields(trace, sessionId, scope, unknown, noise) {
23
+ const fields = unknown?.filter((field) => !noise.has(field.no));
24
+ if (!fields?.length) return;
25
+ try {
26
+ trace({
27
+ sessionId,
28
+ kind: 'cursor_unknown_field',
29
+ provider: 'cursor',
30
+ payload: {
31
+ scope,
32
+ count: fields.length,
33
+ fields: fields.slice(0, TRACE_MAX_FIELDS).map((field) => ({
34
+ no: field.no,
35
+ wire_type: field.wireType,
36
+ bytes: field.data.byteLength,
37
+ preview_hex: Buffer.from(field.data.subarray(0, TRACE_PREVIEW_BYTES)).toString('hex'),
38
+ })),
39
+ },
40
+ });
41
+ } catch {
42
+ /* best-effort */
43
+ }
44
+ }
45
+
12
46
  // Relays one interaction update to the SSE stream and returns its progress.
13
47
  function applyInteractionUpdate(update, state, filter, emit) {
14
48
  if (update.textDelta?.text) {
@@ -62,11 +96,18 @@ function announcePendingToolCall(state, pending, emit) {
62
96
 
63
97
  /**
64
98
  * @param {Uint8Array} bytes one Connect frame payload
65
- * @param {object} ctx { state, filter, emit, conversation, tools, cloudRule, bridge }
99
+ * @param {object} ctx { state, filter, emit, conversation, tools, cloudRule, bridge, sessionId?, trace? }
66
100
  * @returns {'work'|'park'|'none'|string} progress kind for the watchdog
67
101
  */
68
- export function processServerMessage(bytes, { state, filter, emit, conversation, tools, cloudRule, bridge }) {
102
+ export function processServerMessage(
103
+ bytes,
104
+ { state, filter, emit, conversation, tools, cloudRule, bridge, sessionId = '', trace = appendAgentTrace }
105
+ ) {
69
106
  const message = decodeMessage('AgentServerMessage', bytes);
107
+ traceUnknownFields(trace, sessionId, 'agent_server_message', message.$unknown, NOISE_SERVER_FIELDS);
108
+ if (message.interactionUpdate) {
109
+ traceUnknownFields(trace, sessionId, 'interaction_update', message.interactionUpdate.$unknown, NOISE_UPDATE_FIELDS);
110
+ }
70
111
  if (message.interactionUpdate) return applyInteractionUpdate(message.interactionUpdate, state, filter, emit);
71
112
  if (message.kvServerMessage) {
72
113
  handleKvMessage(bridge, message.kvServerMessage, conversation);
@@ -42,6 +42,7 @@ import {
42
42
  import { handleExecMessage, heartbeatFrame, sendToolResult } from './cursor-wire-exec.mjs';
43
43
  import { completionChunk, createStreamSink } from './cursor-wire-stream-sink.mjs';
44
44
  import { createBridgeController } from './cursor-wire-stream-bridge.mjs';
45
+ import { TRANSPORT_SCOPE_DISPOSED } from './transport-scope.mjs';
45
46
 
46
47
  export { clearModelCache, getCursorModels, getCursorUsage } from './cursor-wire-models.mjs';
47
48
 
@@ -117,6 +118,8 @@ globalThis.__mixdogCloseProviderConnectionsForSession = (sessionId, reason) => {
117
118
  _priorCursorSessionCloseHook?.(sessionId, reason);
118
119
  } finally {
119
120
  closeCursorRunsForSession(sessionId, reason);
121
+ // A disposed transport scope never sends again: drop its conversation.
122
+ if (reason === TRANSPORT_SCOPE_DISPOSED && sessionId) conversations.delete(conversationKey([], sessionId));
120
123
  }
121
124
  };
122
125
  const _priorCursorDrainHook = globalThis.__mixdogDrainProviderConnections;
@@ -12,6 +12,7 @@ import { preparePdfTextForProvider } from './media-normalization.mjs';
12
12
  import { consumeCompatChatCompletionStream } from './openai-compat-stream.mjs';
13
13
  import { retryAfterMsFromError } from './retry-classifier.mjs';
14
14
  import { ensureChatToolPairs } from './lib/wire-pairing.mjs';
15
+ import { acceptedWireTools } from './lib/claude-bridge-schema.mjs';
15
16
  import { cursorTokenExpiry, exchangeCursorToken, resolveCursorOAuthAccessToken } from './cursor-auth.mjs';
16
17
  import {
17
18
  canonicalCursorModelId,
@@ -693,10 +694,16 @@ class CursorProviderBase {
693
694
  const runtime = await this._runtime();
694
695
  let accessToken = await this._accessToken({ signal });
695
696
  let cursorSelection = await this._resolveCursorModel(model, sendOpts, runtime, accessToken);
697
+ // The Cursor run and conversation (checkpoint, pending tool batch) live
698
+ // under this scope; a forked request keeps its own (transport-scope.mjs).
696
699
  const sessionScope = String(
697
- sendOpts.sessionId || sendOpts.providerCacheKey || sendOpts.promptCacheKey || `cursor-call:${randomUUID()}`
700
+ sendOpts.transportScope ||
701
+ sendOpts.sessionId ||
702
+ sendOpts.providerCacheKey || sendOpts.promptCacheKey || `cursor-call:${randomUUID()}`
698
703
  );
699
- const openAiTools = tools?.length ? toOpenAITools(tools) : undefined;
704
+ const openAiTools = tools?.length
705
+ ? toOpenAITools(acceptedWireTools(tools, 'openai', sendOpts.onToolExcluded, '[cursor] tool'))
706
+ : undefined;
700
707
  const dispatch = async () => {
701
708
  noteRequestServiceTier(cursorSelectionIsFast(cursorSelection) ? 'fast' : '');
702
709
  // Every attempt (retries included) prepares right before it lowers.