mixdog 1.2.1 → 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 (557) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +19 -3
  4. package/scripts/model-catalog-audit.mjs +1 -15
  5. package/scripts/provider-pingpong-live.mjs +509 -0
  6. package/src/agents/advisor/AGENT.md +1 -1
  7. package/src/agents/advisor/agent.json +1 -1
  8. package/src/agents/reviewer/AGENT.md +3 -3
  9. package/src/agents/reviewer/agent.json +1 -1
  10. package/src/defaults/shipped-history.json +6 -0
  11. package/src/defaults/skills/setup/SKILL.md +6 -1
  12. package/src/defaults/skills/setup/references/actions.md +44 -22
  13. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  14. package/src/headless-exec.mjs +15 -8
  15. package/src/lib/keychain-cjs.cjs +7 -4
  16. package/src/output-styles/common.md +11 -10
  17. package/src/repl/slash-commands.mjs +16 -1
  18. package/src/rules/agent/AGENT.md +5 -5
  19. package/src/rules/lead/LEAD.md +5 -5
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
  22. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  23. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
  33. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
  34. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
  35. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
  36. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
  37. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
  38. package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
  39. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
  40. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
  41. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
  42. package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  44. package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
  45. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
  46. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
  47. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
  48. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
  49. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
  50. package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
  51. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
  52. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
  54. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
  58. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  63. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  65. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
  68. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
  70. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
  71. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
  72. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
  73. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
  74. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
  75. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
  76. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
  77. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  79. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  80. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
  81. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
  83. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
  84. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
  85. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
  86. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
  87. package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
  88. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
  89. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
  90. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  91. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  92. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  93. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
  94. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
  96. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
  97. package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
  98. package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
  99. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  100. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
  101. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
  102. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
  103. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
  105. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
  106. package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
  107. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  108. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  109. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
  110. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  111. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  112. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
  113. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  114. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  115. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
  116. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  117. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  118. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  120. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
  121. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
  122. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  123. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
  124. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
  125. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  126. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  127. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
  128. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
  129. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
  138. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  140. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  141. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
  142. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
  143. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
  144. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  145. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
  147. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
  148. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
  150. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
  151. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  152. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
  153. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
  154. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
  155. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
  156. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
  157. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
  158. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
  159. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  160. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
  161. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  163. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
  164. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
  165. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
  166. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  167. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
  168. package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
  169. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  170. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
  171. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
  172. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
  173. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
  174. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
  175. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  176. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
  177. package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
  178. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
  179. package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
  180. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  181. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
  182. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  183. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
  184. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
  185. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  186. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  187. package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
  188. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
  189. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
  190. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
  191. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
  192. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
  193. package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
  194. package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
  195. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
  196. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
  197. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
  198. package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
  199. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  200. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  201. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
  202. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
  203. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  204. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
  205. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
  206. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
  207. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
  208. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  209. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
  210. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
  211. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
  212. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
  213. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  214. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  215. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
  216. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  217. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  218. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  219. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
  220. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
  221. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  222. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
  223. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  224. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
  225. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  226. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
  227. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  228. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  229. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
  230. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  231. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
  232. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  233. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  234. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  235. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
  236. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
  237. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
  238. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
  239. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  240. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
  241. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  242. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  243. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
  244. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  245. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
  246. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
  247. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
  248. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
  249. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
  250. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  251. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
  252. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  253. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  254. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
  255. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  256. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
  257. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
  258. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
  259. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
  260. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  261. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
  262. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  263. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  264. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
  265. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
  266. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  267. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
  268. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  269. package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
  270. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
  271. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  272. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
  273. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
  274. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
  275. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  276. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
  277. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
  278. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
  279. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
  280. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  281. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
  282. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
  283. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
  284. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
  285. package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
  286. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
  287. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
  288. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  289. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  290. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  291. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
  292. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
  293. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  294. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  295. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  296. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
  297. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  298. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
  299. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
  300. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
  301. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  302. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  303. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  304. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  305. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  306. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  307. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  308. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  309. package/src/runtime/computer-bridge/action-schema.mjs +44 -21
  310. package/src/runtime/github/tool.mjs +92 -2
  311. package/src/runtime/memory/index.mjs +1 -0
  312. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  313. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  314. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  315. package/src/runtime/memory/lib/pg/process.mjs +65 -50
  316. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  317. package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
  318. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  319. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  320. package/src/runtime/office/README.md +2 -2
  321. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  322. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  323. package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
  324. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  325. package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
  326. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  327. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  328. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  329. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  330. package/src/runtime/office/core/office-sessions.mjs +5 -0
  331. package/src/runtime/office/core/office-transactions.mjs +3 -0
  332. package/src/runtime/office/core/office-write-ledger.mjs +98 -0
  333. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  334. package/src/runtime/office/index.mjs +30 -0
  335. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  336. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  337. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  338. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  339. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  340. package/src/runtime/office/shared/values.mjs +0 -5
  341. package/src/runtime/shared/background-tasks.mjs +92 -14
  342. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  343. package/src/runtime/shared/bounded-line-diff.mjs +182 -0
  344. package/src/runtime/shared/buffered-appender.mjs +18 -0
  345. package/src/runtime/shared/config.mjs +78 -18
  346. package/src/runtime/shared/err-text.mjs +31 -0
  347. package/src/runtime/shared/error-presentation.mjs +159 -19
  348. package/src/runtime/shared/file-permissions.d.mts +6 -1
  349. package/src/runtime/shared/file-permissions.mjs +54 -6
  350. package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
  351. package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
  352. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
  353. package/src/runtime/shared/llm/model-catalog.mjs +53 -40
  354. package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
  355. package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
  356. package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
  357. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  358. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  359. package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
  360. package/src/runtime/shared/loopback-listener.mjs +9 -0
  361. package/src/runtime/shared/model-display.mjs +13 -0
  362. package/src/runtime/shared/provider-api-key.mjs +2 -0
  363. package/src/runtime/shared/quota-resume-store.mjs +11 -0
  364. package/src/runtime/shared/review-diff.mjs +52 -0
  365. package/src/runtime/shared/session-baseline-store.mjs +960 -0
  366. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  367. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  368. package/src/runtime/shared/slow-span.mjs +114 -0
  369. package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
  370. package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
  371. package/src/runtime/shared/task-notification-envelope.mjs +2 -2
  372. package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
  373. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  374. package/src/runtime/shared/tool-card-model.mjs +5 -2
  375. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  376. package/src/runtime/shared/tool-primitives.mjs +13 -0
  377. package/src/runtime/shared/tool-result-summary.mjs +8 -1
  378. package/src/runtime/shared/tool-surface.mjs +18 -3
  379. package/src/runtime/shared/tool-work-units.mjs +40 -4
  380. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  381. package/src/runtime/shared/transcript-writer.mjs +10 -2
  382. package/src/runtime/shared/turn-changes.mjs +670 -274
  383. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  384. package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
  385. package/src/runtime/shared/turn-snapshot.mjs +986 -690
  386. package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
  387. package/src/runtime/shared/user-data-guard.mjs +262 -49
  388. package/src/runtime/shared/worktrees/carry.mjs +531 -0
  389. package/src/runtime/shared/worktrees/contract.mjs +34 -24
  390. package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
  391. package/src/runtime/shared/worktrees/git-head.mjs +205 -0
  392. package/src/runtime/shared/worktrees/git.mjs +8 -3
  393. package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
  394. package/src/runtime/shared/worktrees/manager.mjs +156 -8
  395. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  396. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  397. package/src/runtime/shared/worktrees/test-support.mjs +19 -4
  398. package/src/runtime/terminal-bridge/client.mjs +44 -11
  399. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  400. package/src/runtime/tidy/apply.mjs +47 -2
  401. package/src/runtime/tidy/run-engines.mjs +11 -5
  402. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  403. package/src/session-runtime/boot/apis.mjs +19 -5
  404. package/src/session-runtime/boot/facade.mjs +1 -0
  405. package/src/session-runtime/boot/infrastructure.mjs +12 -1
  406. package/src/session-runtime/boot/session.mjs +0 -1
  407. package/src/session-runtime/boot/tools.mjs +4 -1
  408. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  409. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
  410. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  411. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
  412. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
  413. package/src/session-runtime/internal-tool-executor.mjs +6 -2
  414. package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
  415. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  416. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
  417. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  418. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
  419. package/src/session-runtime/lifecycle/teardown.mjs +73 -8
  420. package/src/session-runtime/lifecycle-api.mjs +1 -0
  421. package/src/session-runtime/mcp-glue/connect.mjs +46 -14
  422. package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
  423. package/src/session-runtime/mcp-glue.mjs +3 -0
  424. package/src/session-runtime/mcp-oauth-login.mjs +174 -0
  425. package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
  426. package/src/session-runtime/model-route/set-route.mjs +85 -17
  427. package/src/session-runtime/model-route/web-search-route.mjs +1 -1
  428. package/src/session-runtime/native-web-search/routes.mjs +22 -3
  429. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  430. package/src/session-runtime/native-web-search.mjs +10 -1
  431. package/src/session-runtime/new-session-config.mjs +4 -2
  432. package/src/session-runtime/provider-auth/login.mjs +4 -0
  433. package/src/session-runtime/provider-models/model-meta.mjs +12 -3
  434. package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
  435. package/src/session-runtime/quick-web-search-models.mjs +13 -38
  436. package/src/session-runtime/resource-extension-sync.mjs +4 -0
  437. package/src/session-runtime/resource-mcp-api.mjs +98 -2
  438. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  439. package/src/session-runtime/runtime-review-api.mjs +21 -2
  440. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  441. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
  442. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
  443. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  444. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  445. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
  446. package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
  447. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
  448. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
  449. package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
  450. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
  451. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
  452. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  453. package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
  454. package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
  455. package/src/session-runtime/services/agent-tool.mjs +3 -0
  456. package/src/session-runtime/services/channel-admin.mjs +19 -3
  457. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  458. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  459. package/src/session-runtime/services/provider-admin.mjs +81 -15
  460. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  461. package/src/session-runtime/session-turn-api.mjs +14 -5
  462. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
  463. package/src/session-runtime/settings-compaction-api.mjs +1 -0
  464. package/src/session-runtime/setup-tool/executor.mjs +36 -6
  465. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  466. package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
  467. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
  468. package/src/session-runtime/skills-api.mjs +3 -5
  469. package/src/session-runtime/tool-surface.mjs +5 -1
  470. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  471. package/src/session-runtime/turn/session-ops.mjs +7 -5
  472. package/src/session-runtime/turn/side-question-ops.mjs +22 -0
  473. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
  474. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
  475. package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
  476. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  477. package/src/session-runtime/turn/turn-run.mjs +25 -9
  478. package/src/session-runtime/usage-stats-api.mjs +43 -11
  479. package/src/session-runtime/workspace/project-branches.mjs +7 -5
  480. package/src/session-runtime/workspace/transition-steps.mjs +129 -31
  481. package/src/session-runtime/workspace/transitions.mjs +190 -15
  482. package/src/standalone/daemon-agent-control.mjs +9 -1
  483. package/src/standalone/daemon-drain-policy.mjs +8 -0
  484. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  485. package/src/standalone/daemon-owner.mjs +17 -4
  486. package/src/standalone/daemon-pg-stop.mjs +51 -0
  487. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  488. package/src/standalone/daemon-stop-budget.mjs +18 -0
  489. package/src/standalone/daemon-stored-session-views.mjs +2 -0
  490. package/src/standalone/daemon-telemetry.mjs +74 -0
  491. package/src/standalone/daemon.mjs +64 -8
  492. package/src/standalone/desktop-service-registry.mjs +5 -0
  493. package/src/standalone/local-session-runtime.mjs +70 -19
  494. package/src/standalone/session-client.mjs +42 -0
  495. package/src/standalone/session-protocol.mjs +14 -0
  496. package/src/standalone/session-proxy/projection.mjs +41 -4
  497. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  498. package/src/standalone/session-runtime-inline-host.mjs +1 -0
  499. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
  500. package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
  501. package/src/standalone/session-service/agent-tree.mjs +12 -0
  502. package/src/standalone/session-service/quota-resume.mjs +8 -0
  503. package/src/standalone/session-service/retention/busy.mjs +15 -1
  504. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  505. package/src/standalone/session-service-api.mjs +11 -1
  506. package/src/standalone/session-service.mjs +1 -0
  507. package/src/standalone/session-state-patch.d.mts +2 -1
  508. package/src/standalone/session-state-patch.mjs +41 -1
  509. package/src/tui/App.jsx +25 -0
  510. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  511. package/src/tui/app/app-view.jsx +1 -0
  512. package/src/tui/app/btw-controller.mjs +118 -0
  513. package/src/tui/app/create-app-pickers.mjs +6 -0
  514. package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
  515. package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
  516. package/src/tui/app/extension-pickers.mjs +2 -1
  517. package/src/tui/app/model-options.mjs +11 -16
  518. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  519. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  520. package/src/tui/app/slash-commands.mjs +20 -5
  521. package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
  522. package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
  523. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  524. package/src/tui/app/use-global-key-input.mjs +5 -12
  525. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  526. package/src/tui/components/BtwPanel.jsx +53 -0
  527. package/src/tui/components/QuestionPanel.jsx +275 -0
  528. package/src/tui/components/StatusLine.jsx +2 -0
  529. package/src/tui/components/question-panel-model.mjs +156 -0
  530. package/src/tui/components/status-line/local-line.mjs +5 -2
  531. package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
  532. package/src/tui/dist/index.mjs +3221 -1500
  533. package/src/tui/session/context-state.mjs +4 -2
  534. package/src/tui/session/quota-resume.mjs +46 -14
  535. package/src/tui/session/session-api/commands.mjs +43 -24
  536. package/src/tui/session/session-api/controls.mjs +2 -2
  537. package/src/tui/session/session-api/extensions.mjs +22 -0
  538. package/src/tui/session/session-api/integrations.mjs +16 -2
  539. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  540. package/src/tui/session/session-api/lifecycle.mjs +7 -2
  541. package/src/tui/session/session-api/routes.mjs +71 -7
  542. package/src/tui/session/session-api/settings.mjs +11 -14
  543. package/src/tui/session/session-api.mjs +1 -0
  544. package/src/tui/session/session-flow/drain.mjs +7 -1
  545. package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
  546. package/src/tui/session/tool-approval.mjs +10 -7
  547. package/src/tui/session/transcript-spill.mjs +14 -7
  548. package/src/tui/session/turn-stream.mjs +174 -31
  549. package/src/tui/session/turn.mjs +46 -16
  550. package/src/tui/statusline-ansi-bridge.mjs +1 -1
  551. package/src/ui/statusline-agents.mjs +15 -4
  552. package/src/ui/statusline.mjs +7 -3
  553. package/src/ui/streaming-markdown-heal.mjs +34 -3
  554. package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
  555. package/src/workflows/default/WORKFLOW.md +3 -1
  556. package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
  557. package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
package/README.md CHANGED
@@ -134,6 +134,24 @@ is published in [`benchmarks/terminal-bench-2.1/`](benchmarks/terminal-bench-2.1
134
134
  and [Context efficiency](docs/context-efficiency.md) explains where the
135
135
  savings come from.
136
136
 
137
+ <details>
138
+ <summary><b>Benchmark history</b></summary>
139
+
140
+ Newest first. Each run links to its details, records, and caveats.
141
+
142
+ | Run | Model · trials | vs | Score | Cost | Final context | Time / trial |
143
+ |---|---|---|---|---|---|---|
144
+ | [2026-10-15](benchmarks/terminal-bench-2.1/#bench-log) | GPT-6.1 Sol xhigh · `k=1` | Codex CLI | 77 vs 78 /89 | **−55%** | **−68%** (10.8K vs 33.6K) | 344s vs 380s |
145
+ | [2026-08-25](benchmarks/terminal-bench-2.1/#gpt-56-sol-xhigh-vs-codex-cli) | GPT-5.6 Sol xhigh · `k=5` | Codex CLI | 385 vs 383 /445 | **−39%** | **−46%** (18.5K vs 34.3K) | 415s vs 437s |
146
+ | [2026-08-25](benchmarks/terminal-bench-2.1/#claude-opus-5-vs-claude-code) | Claude Opus 5 · `k=1` | Claude Code | 79 vs 77 /89 | **−19%** | **−28%** (27.6K vs 38.2K) | 610s vs 708s |
147
+
148
+ The 2026-10-15 run is the first full run with the
149
+ [effort judge](docs/auto-reasoning-effort.md) active on OpenAI routes, with web
150
+ search on for both sides. It is a single pass, so the `k=5` chart above stays
151
+ the reference.
152
+
153
+ </details>
154
+
137
155
  ## Documentation
138
156
 
139
157
  - [Context efficiency](docs/context-efficiency.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Open-source coding agent that matches Codex on Terminal-Bench 2.1 with 63% fewer tokens.",
@@ -161,6 +161,7 @@
161
161
  "@mozilla/readability": "^0.6.0",
162
162
  "@napi-rs/canvas": "^1.0.8",
163
163
  "@pdf-lib/fontkit": "^1.1.1",
164
+ "ajv": "^8.20.0",
164
165
  "chalk": "^5.6.2",
165
166
  "cli-highlight": "^2.1.11",
166
167
  "diff": "^9.0.0",
@@ -2,10 +2,17 @@
2
2
  // Local pre-push check. Mirrors the test legs of .github/workflows/release-gate.yml
3
3
  // (jobs: runtime, runtime-slow, desktop, desktop-tests fast/slow). It MUST be
4
4
  // updated together with that workflow whenever those commands change.
5
+ // Up front, before any build or leg, it runs two fast source checks and stops
6
+ // if either fails: the gate's shipped-history job (build-shipped-history.mjs
7
+ // --check; needs a full clone, a shallow one keeps the committed file), and the
8
+ // released-section changelog check the desktop fast lane asserts
9
+ // (changelog-locales.test.mjs; Deploy's plan adds the Unreleased section).
5
10
  // Not covered locally: runtime-macos, computer-backend (cargo + Linux X11),
6
11
  // desktop-tests `computer` lane (windows-latest, src/main/computer/ only),
7
- // relay (apps/relay tests), graph (cargo test). The gate's path filtering is
8
- // not applied: every leg always runs. Run `npm ci` (root and apps/desktop) first.
12
+ // relay (apps/relay tests), graph (cargo test), patch (cargo test of the
13
+ // checked-out engine), mobile-scripts (Python unittest). The gate's path
14
+ // filtering is not applied: every check and leg always runs. Run `npm ci`
15
+ // (root and apps/desktop) first.
9
16
  import { spawn, spawnSync } from 'node:child_process';
10
17
  import fs from 'node:fs';
11
18
  import os from 'node:os';
@@ -16,6 +23,15 @@ import { gateTestBudget, runGateLegs } from './lib/gate-scheduler.mjs';
16
23
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
17
24
  const started = Date.now();
18
25
 
26
+ const preChecks = ['node scripts/build-shipped-history.mjs --check', 'node scripts/check-changelog-locales.mjs'];
27
+ const failedPreChecks = preChecks.filter(
28
+ (cmd) => spawnSync(cmd, { cwd: root, stdio: 'inherit', shell: true }).status !== 0
29
+ );
30
+ if (failedPreChecks.length) {
31
+ console.error(`[gate:local] pre-check failed: ${failedPreChecks.join('; ')}`);
32
+ process.exit(1);
33
+ }
34
+
19
35
  const build = spawnSync('npm run build:spawn:test', { cwd: root, stdio: 'inherit', shell: true });
20
36
  if (build.status !== 0) {
21
37
  console.error('[gate:local] build:spawn:test failed');
@@ -87,7 +103,7 @@ for (const leg of legs) {
87
103
  }
88
104
  }
89
105
  console.log(
90
- 'Not covered locally: runtime-macos, computer-backend, desktop-tests computer lane (Windows-only), relay, graph'
106
+ 'Not covered locally: runtime-macos, computer-backend, desktop-tests computer lane (Windows-only), relay, graph, patch, mobile-scripts'
91
107
  );
92
108
  console.log(`Total: ${((Date.now() - started) / 1000).toFixed(1)}s`);
93
109
  process.exit(legs.every((l) => l.ok) ? 0 : 1);
@@ -6,7 +6,6 @@ import {
6
6
  warmModelMetadataCatalogs,
7
7
  auditModelPricing,
8
8
  } from '../src/runtime/agent/orchestrator/providers/model-catalog.mjs';
9
- import { QUICK_WEB_SEARCH_MODELS } from '../src/session-runtime/quick-web-search-models.mjs';
10
9
 
11
10
  const args = new Set(process.argv.slice(2));
12
11
  const json = args.has('--json');
@@ -154,21 +153,8 @@ for (const [name, provider] of getAllProviders()) {
154
153
  });
155
154
  }
156
155
 
156
+ // Quick web-search rows carry no static windows any more (they come from the catalogs).
157
157
  const quickRows = [];
158
- for (const [provider, models] of Object.entries(QUICK_WEB_SEARCH_MODELS)) {
159
- for (const model of models) {
160
- if (model?.contextWindow == null) continue;
161
- const external = externalMeta(modelsDev, litellm, provider, model.id);
162
- const externalContext = external.modelsDevContext ?? external.litellmContext;
163
- quickRows.push({
164
- provider,
165
- id: model.id,
166
- staticContext: n(model.contextWindow),
167
- externalContext,
168
- mismatch: n(model.contextWindow) != null && externalContext != null && n(model.contextWindow) !== externalContext,
169
- });
170
- }
171
- }
172
158
 
173
159
  const mismatches = providerResults.flatMap((p) => p.rows.filter((r) => r.contextMismatch || r.outputMismatch));
174
160
  const exactOneM = providerResults.flatMap((p) => p.rows.filter((r) => r.liveContext === 1_000_000));
@@ -0,0 +1,509 @@
1
+ // Live ping-pong across providers.
2
+ // Basic suite (default): three turns - a forced read, a no-tool replay of that history,
3
+ // and two parallel reads.
4
+ // Extended suite (`--suite extended`): after those, tool error, file write, shell, a
5
+ // 3-step tool chain, image input, mid-stream cancel + follow-up. Per-turn usage is
6
+ // captured to report prompt-cache reads on turns 2+.
7
+ //
8
+ // Isolation (default): the runs use a fresh temp MIXDOG_HOME/MIXDOG_DATA_DIR, never the
9
+ // installed app's ~/.mixdog data, so no session, catalog or worker rows reach the real
10
+ // stores. Only the API-key secrets (`secrets/agent.<provider>.apiKey.dpapi`) and the
11
+ // `agent` section of mixdog-config.json are copied in. OAuth providers (`*-oauth`, whose
12
+ // refresh tokens could be rotated) are skipped unless `--real-data` is passed, which
13
+ // restores the old behaviour of running against the real data dir. The isolated dir is
14
+ // deleted at the end, after stopping only processes whose executable lives inside it.
15
+ // Usage: node scripts/provider-pingpong-live.mjs [--suite extended] [--real-data] [case-name ...]
16
+ import fs from 'node:fs';
17
+ import os from 'node:os';
18
+ import path from 'node:path';
19
+ import zlib from 'node:zlib';
20
+ import { fileURLToPath } from 'node:url';
21
+ import { spawn, spawnSync } from 'node:child_process';
22
+
23
+ const self = fileURLToPath(import.meta.url);
24
+ const TURN_TIMEOUT_MS = 150_000;
25
+
26
+ const textOf = (response) => {
27
+ const content = response?.result?.content ?? response?.text ?? '';
28
+ if (Array.isArray(content)) return content.map((p) => (typeof p === 'string' ? p : p?.text || '')).join('');
29
+ return String(content);
30
+ };
31
+
32
+ // Solid-colour PNG (8-bit RGB) built from scratch so no image dependency is needed.
33
+ function solidPng(width, height, [r, g, b]) {
34
+ const crcTable = Array.from({ length: 256 }, (_, n) => {
35
+ let c = n;
36
+ for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
37
+ return c >>> 0;
38
+ });
39
+ const crc32 = (buf) => {
40
+ let c = 0xffffffff;
41
+ for (const byte of buf) c = crcTable[(c ^ byte) & 0xff] ^ (c >>> 8);
42
+ return (c ^ 0xffffffff) >>> 0;
43
+ };
44
+ const chunk = (type, data) => {
45
+ const body = Buffer.concat([Buffer.from(type, 'ascii'), data]);
46
+ const out = Buffer.alloc(body.length + 8);
47
+ out.writeUInt32BE(data.length, 0);
48
+ body.copy(out, 4);
49
+ out.writeUInt32BE(crc32(body), body.length + 4);
50
+ return out;
51
+ };
52
+ const ihdr = Buffer.alloc(13);
53
+ ihdr.writeUInt32BE(width, 0);
54
+ ihdr.writeUInt32BE(height, 4);
55
+ ihdr[8] = 8; // bit depth
56
+ ihdr[9] = 2; // RGB
57
+ const row = Buffer.concat([Buffer.from([0]), Buffer.from(Array.from({ length: width }, () => [r, g, b]).flat())]);
58
+ const raw = Buffer.concat(Array.from({ length: height }, () => row));
59
+ return Buffer.concat([
60
+ Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
61
+ chunk('IHDR', ihdr),
62
+ chunk('IDAT', zlib.deflateSync(raw)),
63
+ chunk('IEND', Buffer.alloc(0)),
64
+ ]);
65
+ }
66
+
67
+ const withTimeout = (promise, ms, onTimeout) =>
68
+ new Promise((resolve, reject) => {
69
+ const timer = setTimeout(() => {
70
+ onTimeout?.();
71
+ reject(new Error(`timeout after ${ms}ms`));
72
+ }, ms);
73
+ promise.then(
74
+ (v) => (clearTimeout(timer), resolve(v)),
75
+ (e) => (clearTimeout(timer), reject(e))
76
+ );
77
+ });
78
+
79
+ // Failures caused by the account (limits, billing, entitlement) rather than the provider code.
80
+ const ACCOUNT_RE =
81
+ /quota|billing|\b(?:402|403|429)\b|rate.?limit|usage limit|insufficient|payment|credit|too many requests|exhaust|subscription|plan limit|not entitled|resource_exhausted/i;
82
+
83
+ if (process.argv[2] === '--child') {
84
+ const spec = JSON.parse(process.argv[3]);
85
+ const extended = spec.suite === 'extended';
86
+ const { resolvePluginData } = await import('../src/runtime/shared/plugin-paths.mjs');
87
+ if (spec.dataDir && path.resolve(resolvePluginData()) !== path.resolve(spec.dataDir)) {
88
+ console.log(`RESULT ${JSON.stringify({ name: spec.name, error: `refusing to run: data dir ${resolvePluginData()} is not the isolated ${spec.dataDir}` })}`);
89
+ process.exit(0);
90
+ }
91
+ const { createMixdogSessionRuntime } = await import('../src/session-runtime/runtime-core.mjs');
92
+ const { materializePromptSubmission } = await import('../src/runtime/attachments/store.mjs');
93
+ const { getModelMetadataSync } = await import('../src/runtime/shared/llm/model-catalog.mjs');
94
+ let runtime;
95
+ const out = { name: spec.name, provider: spec.provider, model: spec.model, effort: spec.effort, turns: {}, order: [] };
96
+ const readDisk = (file) => {
97
+ try {
98
+ return fs.readFileSync(path.join(spec.cwd, file), 'utf8');
99
+ } catch {
100
+ return null;
101
+ }
102
+ };
103
+
104
+ // Runs one ask() and records calls/text/usage under `key`. Errors are recorded, not thrown,
105
+ // so later scenarios still run; an ACCOUNT error stops the case (everything after would fail alike).
106
+ const turn = async (key, prompt, options = {}) => {
107
+ const rec = { calls: [], text: '', usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, events: 0 }, models: [] };
108
+ out.turns[key] = rec;
109
+ out.order.push(key);
110
+ const startedAt = Date.now();
111
+ try {
112
+ const response = await withTimeout(
113
+ runtime.ask(prompt, {
114
+ ...options,
115
+ onAssistantToolCallObserved: (call) => rec.calls.push(call.name || call.tool),
116
+ onUsageDelta: (d) => {
117
+ rec.usage.events++;
118
+ rec.usage.input += d.deltaInput || 0;
119
+ rec.usage.output += d.deltaOutput || 0;
120
+ rec.usage.cacheRead += d.deltaCachedRead || 0;
121
+ rec.usage.cacheWrite += d.deltaCacheWrite || 0;
122
+ if (d.model && !rec.models.includes(d.model)) rec.models.push(d.model);
123
+ },
124
+ }),
125
+ TURN_TIMEOUT_MS,
126
+ () => runtime.abort('pingpong-timeout')
127
+ );
128
+ rec.text = textOf(response).trim().slice(0, 300);
129
+ } catch (error) {
130
+ rec.error = String(error?.message || error).slice(0, 400);
131
+ if (ACCOUNT_RE.test(rec.error)) out.stopped = 'account';
132
+ }
133
+ rec.ms = Date.now() - startedAt;
134
+ return rec;
135
+ };
136
+
137
+ try {
138
+ runtime = await createMixdogSessionRuntime({
139
+ provider: spec.provider,
140
+ model: spec.model,
141
+ ...(spec.effort ? { effort: spec.effort } : {}),
142
+ cwd: spec.cwd,
143
+ toolMode: 'full',
144
+ autoWakeCompletions: false,
145
+ });
146
+ const steps = [
147
+ ['t1', 'Use the read tool on package.json, then reply with only the value of "name".'],
148
+ ['t2', 'Without using tools, reply with only that same name in uppercase.'],
149
+ ['t3', 'Read a.txt and b.txt with two read calls issued together in one step, then reply with only their two contents joined by "+".'],
150
+ ];
151
+ for (const [key, prompt] of steps) {
152
+ await turn(key, prompt);
153
+ if (out.stopped) break;
154
+ }
155
+
156
+ if (extended && !out.stopped) {
157
+ await turn(
158
+ 'er',
159
+ 'Use the read tool on does-not-exist.txt. Whatever happens, then tell me in one short sentence whether that file exists.'
160
+ );
161
+ }
162
+ if (extended && !out.stopped) {
163
+ const rec = await turn(
164
+ 'wr',
165
+ 'Using the file edit/write tool (not the shell), create a new file c.txt in the working directory containing exactly the text gamma. Reply "done" when finished.'
166
+ );
167
+ rec.disk = readDisk('c.txt');
168
+ }
169
+ if (extended && !out.stopped) {
170
+ await turn('sh', 'Use the shell tool to run exactly: node -e "console.log(6*7)" and reply with only its output.');
171
+ }
172
+ if (extended && !out.stopped) {
173
+ const rec = await turn(
174
+ 'ml',
175
+ 'Do these in order, each as its own tool call, one after another: (1) read a.txt, (2) create a new file d.txt using the file edit/write tool containing the contents of a.txt with its characters reversed and no trailing newline, (3) read d.txt. Then reply with only the text in d.txt.'
176
+ );
177
+ rec.disk = readDisk('d.txt');
178
+ }
179
+ if (extended && !out.stopped) {
180
+ const vision = getModelMetadataSync(spec.model, spec.provider)?.supportsVision;
181
+ if (vision === false) {
182
+ out.turns.im = { skipped: 'catalog says no vision', calls: [], text: '' };
183
+ out.order.push('im');
184
+ } else {
185
+ const png = solidPng(64, 64, [255, 0, 0]).toString('base64');
186
+ // Same intake the session service applies before runtime.ask: inline image
187
+ // parts become content-addressed attachment references.
188
+ const intake = materializePromptSubmission([
189
+ { type: 'text', text: 'What single colour fills this image? Reply with only the colour name in English.' },
190
+ { type: 'image', data: png, mimeType: 'image/png' },
191
+ ]);
192
+ const rec = await turn('im', intake.prompt, intake.options);
193
+ rec.visionFlag = vision === undefined ? 'unknown' : 'true';
194
+ }
195
+ }
196
+ if (extended && !out.stopped) {
197
+ // Real cancel path: runtime.abort() -> abortRuntime -> turn controller + mgr.abortSessionTurn.
198
+ const rec = { calls: [], text: '', usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, events: 0 }, models: [] };
199
+ out.turns.ca = rec;
200
+ out.order.push('ca');
201
+ let deltas = 0;
202
+ let abortResult;
203
+ let aborted = false;
204
+ const doAbort = () => {
205
+ if (aborted) return;
206
+ aborted = true;
207
+ abortResult = runtime.abort('user-cancel');
208
+ };
209
+ const fallback = setTimeout(doAbort, 30_000);
210
+ const onDelta = () => {
211
+ if (++deltas >= 5) doAbort();
212
+ };
213
+ const startedAt = Date.now();
214
+ const pending = runtime
215
+ .ask('Write a very long numbered list from 1 to 300, one item per line, each item a full sentence about a different animal. Do not use tools.', {
216
+ onTextDelta: onDelta,
217
+ onUsageDelta: (d) => {
218
+ rec.usage.events++;
219
+ rec.usage.input += d.deltaInput || 0;
220
+ rec.usage.output += d.deltaOutput || 0;
221
+ rec.usage.cacheRead += d.deltaCachedRead || 0;
222
+ rec.usage.cacheWrite += d.deltaCacheWrite || 0;
223
+ },
224
+ })
225
+ .then(
226
+ (r) => ({ ok: true, text: textOf(r).trim() }),
227
+ (e) => ({ ok: false, error: String(e?.message || e) })
228
+ );
229
+ const settled = await Promise.race([pending, new Promise((r) => setTimeout(() => r({ hang: true }), 120_000))]);
230
+ clearTimeout(fallback);
231
+ rec.ms = Date.now() - startedAt;
232
+ rec.deltas = deltas;
233
+ rec.abortResult = abortResult;
234
+ rec.abortedAfterMs = rec.ms;
235
+ rec.settle = settled.hang ? 'hang' : settled.ok ? 'resolved' : 'rejected';
236
+ rec.text = String(settled.text || '').slice(0, 120);
237
+ rec.error = settled.error ? settled.error.slice(0, 300) : undefined;
238
+ rec.chars = String(settled.text || '').length;
239
+ if (settled.hang) out.stopped = 'hang';
240
+ else if (rec.error && ACCOUNT_RE.test(rec.error) && !aborted) out.stopped = 'account';
241
+ if (!out.stopped) await turn('fu', 'Reply with only the word READY.');
242
+ }
243
+ } catch (error) {
244
+ out.error = String(error?.message || error).slice(0, 400);
245
+ } finally {
246
+ await runtime?.close('provider-pingpong-live').catch(() => {});
247
+ }
248
+ console.log(`RESULT ${JSON.stringify(out)}`);
249
+ process.exit(0);
250
+ }
251
+
252
+ // [name, provider, model, effort]; each route runs at a low and a high reasoning setting.
253
+ const routes = [
254
+ ['openrouter-claude', 'openrouter', 'anthropic/claude-haiku-5.5', ['low', 'max']],
255
+ ['openrouter-gpt', 'openrouter', 'openai/gpt-6-luna', ['none', 'xhigh']],
256
+ ['openrouter-gemini', 'openrouter', 'google/gemini-3.5-flash-lite', ['minimal', 'high']],
257
+ ['openrouter-deepseek', 'openrouter', 'deepseek/deepseek-v4.1-flash', ['low', 'max']],
258
+ ['deepseek', 'deepseek', 'deepseek-flash', ['low', 'max']],
259
+ ['deepseek-pro', 'deepseek', 'deepseek-v4-pro', ['high']],
260
+ ['opencode-go-gemini', 'opencode-go', 'gemini-4-argon-contributor', ['low', 'high']],
261
+ ['opencode-go-deepseek', 'opencode-go', 'deepseek-v4.1-flash', ['low', 'max']],
262
+ ['opencode-go-claude', 'opencode-go', 'claude-haiku-5-5', ['low', 'max']],
263
+ ['opencode-go-gpt', 'opencode-go', 'gpt-6-luna', ['none', 'xhigh']],
264
+ ['opencode-go-glm', 'opencode-go', 'glm-5.3-flash', ['low', 'max']],
265
+ ['opencode-go-qwen', 'opencode-go', 'qwen3.8-flash', ['low', 'xhigh']],
266
+ ['opencode-go-kimi', 'opencode-go', 'kimi-k3', ['max']],
267
+ ['opencode-go-minimax', 'opencode-go', 'minimax-m3', [null]],
268
+ ['opencode-go-grok', 'opencode-go', 'grok-4.7', ['low']],
269
+ ['anthropic-api', 'anthropic', 'claude-haiku-5-5', ['low', 'max']],
270
+ ['gemini-api', 'gemini', 'gemini-3.5-flash-lite', ['minimal', 'high']],
271
+ ['grok-oauth', 'grok-oauth', 'grok-4.7', ['low', 'xhigh']],
272
+ ['openai-oauth', 'openai-oauth', 'gpt-6-luna', ['none', 'xhigh']],
273
+ ['anthropic-oauth', 'anthropic-oauth', 'claude-haiku-5-5', ['low', 'max']],
274
+ ['antigravity-oauth', 'antigravity-oauth', 'gemini-3.8-flash', ['low', 'high']],
275
+ ['cursor-auto', 'cursor-oauth', 'auto', [null]],
276
+ ['cursor-composer', 'cursor-oauth', 'composer-2.5', [null]],
277
+ ['cursor-claude', 'cursor-oauth', 'claude-opus-5-5', [null]],
278
+ ['cursor-grok', 'cursor-oauth', 'grok-4.7', [null]],
279
+ ];
280
+ const cases = routes.flatMap(([name, provider, model, efforts]) =>
281
+ efforts.map((effort) => [`${name}${effort ? `@${effort}` : ''}`, provider, model, effort])
282
+ );
283
+ const args = process.argv.slice(2);
284
+ const suiteAt = args.findIndex((a) => a === '--suite' || a.startsWith('--suite='));
285
+ const suite = suiteAt < 0 ? 'basic' : args[suiteAt].includes('=') ? args[suiteAt].split('=')[1] : args[suiteAt + 1];
286
+ const extended = suite === 'extended';
287
+ const realData = args.includes('--real-data');
288
+ const only = args.filter(
289
+ (a, i) => a !== '--real-data' && !a.startsWith('--suite') && !(suiteAt >= 0 && i === suiteAt + 1 && args[suiteAt] === '--suite')
290
+ );
291
+ const chosen = only.length ? cases.filter(([name]) => only.includes(name)) : cases;
292
+ // Refresh-capable OAuth logins are never exercised from an isolated copy.
293
+ const isOauth = ([, provider]) => /-oauth$/.test(provider);
294
+ const selected = realData ? chosen : chosen.filter((c) => !isOauth(c));
295
+ for (const c of chosen) if (!selected.includes(c)) console.log(`SKIP ${c[0]} (OAuth provider; pass --real-data to run against the real data dir)`);
296
+ if (!selected.length) {
297
+ console.log('nothing to run');
298
+ process.exit(0);
299
+ }
300
+
301
+ // Isolated MIXDOG_HOME for the child runtimes: a fresh temp dir holding only the API-key
302
+ // secrets of the selected providers and the `agent` section of the real config.
303
+ let isolated = null;
304
+ if (!realData) {
305
+ const realDataDir = process.env.MIXDOG_DATA_DIR || path.join(process.env.MIXDOG_HOME || path.join(os.homedir(), '.mixdog'), 'data');
306
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'mixdog-pp-home-'));
307
+ const dataDir = path.join(home, 'data');
308
+ fs.mkdirSync(path.join(dataDir, 'secrets'), { recursive: true });
309
+ const config = JSON.parse(fs.readFileSync(path.join(realDataDir, 'mixdog-config.json'), 'utf8'));
310
+ fs.writeFileSync(path.join(dataDir, 'mixdog-config.json'), JSON.stringify({ agent: config.agent ?? {} }, null, 2));
311
+ for (const provider of new Set(selected.map(([, p]) => p))) {
312
+ const secret = `agent.${provider}.apiKey.dpapi`;
313
+ const from = path.join(realDataDir, 'secrets', secret);
314
+ if (fs.existsSync(from)) fs.copyFileSync(from, path.join(dataDir, 'secrets', secret));
315
+ else console.log(`WARN no ${secret} in the real data dir; ${provider} cases will fail to authenticate`);
316
+ }
317
+ isolated = {
318
+ home,
319
+ dataDir,
320
+ env: { MIXDOG_HOME: home, MIXDOG_DATA_DIR: dataDir, MIXDOG_RUNTIME_ROOT: path.join(home, 'runtime-root') },
321
+ };
322
+ }
323
+
324
+ // Stops only processes whose executable path is inside `root` (e.g. the isolated memory
325
+ // postgres), then removes the dir. Windows-only lookup, like the DPAPI secrets.
326
+ const removeIsolated = () => {
327
+ if (!isolated) return;
328
+ const { home } = isolated;
329
+ isolated = null;
330
+ if (process.platform === 'win32') {
331
+ const root = home.replace(/'/g, "''");
332
+ spawnSync(
333
+ 'powershell.exe',
334
+ [
335
+ '-NoProfile',
336
+ '-Command',
337
+ `$root='${root}\\'; Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($root, [StringComparison]::OrdinalIgnoreCase) } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }`,
338
+ ],
339
+ { stdio: 'ignore' }
340
+ );
341
+ }
342
+ fs.rmSync(home, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
343
+ };
344
+
345
+ // One fixture dir per case: concurrent children write c.txt/d.txt and must not collide.
346
+ const tempDirs = new Set();
347
+ const removeTemp = () => {
348
+ for (const dir of tempDirs) fs.rmSync(dir, { recursive: true, force: true });
349
+ tempDirs.clear();
350
+ removeIsolated();
351
+ };
352
+ process.on('exit', removeTemp);
353
+ const makeCwd = (name) => {
354
+ const cwd = fs.mkdtempSync(path.join(os.tmpdir(), `mixdog-pingpong-${name.replace(/[^a-z0-9]+/gi, '-')}-`));
355
+ tempDirs.add(cwd);
356
+ fs.writeFileSync(path.join(cwd, 'package.json'), JSON.stringify({ name: 'pingpong-probe', version: '1.0.0' }, null, 2));
357
+ fs.writeFileSync(path.join(cwd, 'a.txt'), 'alpha\n');
358
+ fs.writeFileSync(path.join(cwd, 'b.txt'), 'beta\n');
359
+ return cwd;
360
+ };
361
+
362
+ const runOne = ([name, provider, model, effort]) =>
363
+ new Promise((resolve) => {
364
+ const cwd = makeCwd(name);
365
+ const child = spawn(
366
+ process.execPath,
367
+ [self, '--child', JSON.stringify({ name, provider, model, effort, cwd, dataDir: isolated?.dataDir, suite: extended ? 'extended' : 'basic' })],
368
+ { stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env, ...isolated?.env } }
369
+ );
370
+ let stdout = '';
371
+ let stderr = '';
372
+ child.stdout.on('data', (d) => (stdout += d));
373
+ child.stderr.on('data', (d) => (stderr += d));
374
+ const timer = setTimeout(() => child.kill(), extended ? 900_000 : 240_000);
375
+ child.on('close', () => {
376
+ clearTimeout(timer);
377
+ fs.rmSync(cwd, { recursive: true, force: true });
378
+ tempDirs.delete(cwd);
379
+ const line = stdout.split('\n').find((l) => l.startsWith('RESULT '));
380
+ resolve(line ? JSON.parse(line.slice(7)) : { name, provider, model, effort, error: `no result: ${stderr.slice(-300)}` });
381
+ });
382
+ });
383
+
384
+ // Bounded concurrency keeps per-provider rate limits from masking real failures.
385
+ const results = [];
386
+ const queue = [...selected];
387
+ await Promise.all(
388
+ Array.from({ length: 8 }, async () => {
389
+ while (queue.length) results.push(await runOne(queue.shift()));
390
+ })
391
+ );
392
+ results.sort((a, b) => a.name.localeCompare(b.name));
393
+
394
+ const has = (t, re) => re.test(t?.text || '');
395
+ const called = (t, name) => (t?.calls || []).includes(name);
396
+ const wroteVia = (t) => (t?.calls || []).some((c) => /edit|write|patch/i.test(c));
397
+ // [key, label, check(turn, result)] ; check returns true/false.
398
+ const scenarios = [
399
+ ['t1', 't1', (t) => called(t, 'read') && has(t, /pingpong-probe/i)],
400
+ ['t2', 't2', (t) => has(t, /PINGPONG-PROBE/)],
401
+ ['t3', 't3', (t) => (t.calls || []).filter((c) => c === 'read').length >= 1 && has(t, /alpha/i) && has(t, /beta/i)],
402
+ // The reply language follows the user's profile (may be Korean), so the wording check is bilingual.
403
+ ['er', 'err', (t) => called(t, 'read') && has(t, /missing|not exist|doesn.?t exist|does not|no such|not found|nonexistent|isn.?t|cannot|can.?t|존재하지|없|찾을 수|않/i)],
404
+ ['wr', 'wr', (t) => wroteVia(t) && String(t.disk ?? '').trim() === 'gamma'],
405
+ ['sh', 'sh', (t) => called(t, 'shell') && has(t, /42/)],
406
+ [
407
+ 'ml',
408
+ 'ml',
409
+ (t) => {
410
+ const c = t.calls || [];
411
+ const firstRead = c.indexOf('read');
412
+ const write = c.findIndex((n, i) => i > firstRead && /edit|write|patch/i.test(n));
413
+ const lastRead = c.lastIndexOf('read');
414
+ return firstRead >= 0 && write > firstRead && lastRead > write && String(t.disk ?? '').trim() === 'ahpla' && has(t, /ahpla/);
415
+ },
416
+ ],
417
+ ['im', 'img', (t) => has(t, /red/i)],
418
+ ['ca', 'can', (t) => t.settle && t.settle !== 'hang' && t.abortResult === true],
419
+ ['fu', 'fu', (t) => has(t, /READY/i)],
420
+ ];
421
+
422
+ const short = (s, n = 60) => String(s || '').replace(/\s+/g, ' ').slice(0, n);
423
+ const evidence = (key, t) => {
424
+ if (!t) return 'no turn';
425
+ if (t.error && key !== 'ca') return `error: ${short(t.error, 90)}`;
426
+ const base = `[${(t.calls || []).join(',')}] "${short(t.text)}"`;
427
+ if (key === 'wr' || key === 'ml') return `${base} disk=${JSON.stringify(short(t.disk ?? null, 20))}`;
428
+ if (key === 'ca') return `abort=${t.abortResult} settle=${t.settle} deltas=${t.deltas} chars=${t.chars} ${t.error ? `err="${short(t.error, 70)}"` : ''}`;
429
+ return base;
430
+ };
431
+
432
+ const details = [];
433
+ for (const r of results) {
434
+ const marks = [];
435
+ const evid = [];
436
+ let anyFail = false;
437
+ let anyAccount = false;
438
+ for (const [key, label, check] of scenarios) {
439
+ if (!extended && !['t1', 't2', 't3'].includes(key)) continue;
440
+ const t = r.turns?.[key];
441
+ // A cancelled turn is expected to reject, so only 'ca' tolerates an error.
442
+ const ok = t && (key === 'ca' || !t.error) && check(t, r);
443
+ const accountish = t
444
+ ? ACCOUNT_RE.test(t.error || t.text || '')
445
+ : r.stopped === 'account' || ACCOUNT_RE.test(r.error || '');
446
+ let mark;
447
+ if (t?.skipped) mark = '-';
448
+ else if (ok) mark = '✓';
449
+ else if (accountish) mark = 'A';
450
+ // The catalog is silent on vision for this model: a wrong answer may just be a text-only
451
+ // model, so it is flagged for manual review instead of counted as a failure.
452
+ else if (key === 'im' && t?.visionFlag === 'unknown') mark = '?';
453
+ else mark = '✗';
454
+ marks.push(`${label}${mark}`);
455
+ if (mark === '✗') anyFail = true;
456
+ if (mark === 'A') anyAccount = true;
457
+ if (mark !== '✓' && mark !== '-') {
458
+ evid.push(`${label}${mark}: ${evidence(key, t)}`);
459
+ details.push({ r, key, label, mark, t });
460
+ }
461
+ }
462
+ const turns = Object.entries(r.turns || {});
463
+ const later = (r.order || []).slice(1).map((k) => r.turns[k]).filter((t) => t?.usage);
464
+ const sum = (f) => later.reduce((n, t) => n + f(t.usage), 0);
465
+ const events = (r.order || []).reduce((n, k) => n + (r.turns[k]?.usage?.events || 0), 0);
466
+ const cache = !turns.length || !events
467
+ ? 'cache=NO-USAGE'
468
+ : `cache r=${sum((u) => u.cacheRead)} w=${sum((u) => u.cacheWrite)} in=${sum((u) => u.input)} cr/turn=[${later.map((t) => t.usage.cacheRead).join(',')}]`;
469
+ const verdict = r.error && !turns.length ? (ACCOUNT_RE.test(r.error) ? 'ACCOUNT' : 'FAIL') : anyFail ? 'FAIL' : anyAccount ? 'ACCOUNT' : 'PASS';
470
+ if (extended) {
471
+ console.log(`${verdict.padEnd(7)} ${r.name.padEnd(30)} ${marks.join(' ')} ${cache}`);
472
+ if (r.error) console.log(` error=${r.error}`);
473
+ for (const e of evid) console.log(` ${e}`);
474
+ } else {
475
+ const turn = (key, label) => {
476
+ const t = r.turns?.[key];
477
+ const ok = t && !t.error && scenarios.find((s) => s[0] === key)[2](t, r);
478
+ return `${label}${ok ? '✓' : '✗'} ${t?.ms}ms [${t?.calls}] "${short(t?.text)}"`;
479
+ };
480
+ const pass = !r.error && verdict === 'PASS';
481
+ console.log(
482
+ `${pass ? 'PASS' : verdict === 'ACCOUNT' ? 'ACCOUNT' : 'FAIL'} ${r.name.padEnd(30)} ` +
483
+ (r.error ? `error=${r.error}` : `${turn('t1', 't1')} | ${turn('t2', 't2')} | ${turn('t3', 't3')}`)
484
+ );
485
+ }
486
+ }
487
+
488
+ if (extended) {
489
+ // Oddities worth a manual look: model identity, usage presence, notices mixed into answers.
490
+ console.log('\n--- NON-PASS DETAILS (raw) ---');
491
+ for (const { r, label, mark, t } of details) {
492
+ console.log(
493
+ `[${mark === 'A' ? 'ACCOUNT' : mark === '?' ? 'UNVERIFIED' : 'FAIL'}] ${r.provider}/${r.model} effort=${r.effort ?? '-'} ${label}: ` +
494
+ `error=${JSON.stringify(t?.error ?? null)} text=${JSON.stringify(t?.text ?? null)} calls=${JSON.stringify(t?.calls ?? null)} disk=${JSON.stringify(t?.disk ?? null)}`
495
+ );
496
+ }
497
+ console.log('\n--- ODDITIES ---');
498
+ for (const r of results) {
499
+ for (const key of r.order || []) {
500
+ const t = r.turns[key];
501
+ if (t?.models?.length && !t.models.some((m) => m === r.model || m.endsWith(`/${r.model}`) || m.includes(r.model) || r.model.includes(m)))
502
+ console.log(`${r.name} ${key}: served model ${JSON.stringify(t.models)} != requested ${r.model}`);
503
+ if (/notice|overloaded|retrying|fallback|server error|temporarily/i.test(t?.text || ''))
504
+ console.log(`${r.name} ${key}: notice-like text ${JSON.stringify(t.text)}`);
505
+ if (t && !t.skipped && !t.error && t.usage && t.usage.events === 0) console.log(`${r.name} ${key}: no usage events`);
506
+ }
507
+ }
508
+ }
509
+ removeTemp();
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Advisor
3
- description: Use on non-trivial work after orientation and before committing to an approach, when stuck or results do not converge, before changing approach, and for requested second opinions. Skip for low-difficulty work. Advisory analysis only; the final check belongs to Reviewer.
3
+ description: "Use by difficulty: on any work beyond a simple one- or two-step change, after orientation and before committing to an approach, when errors recur or results stop converging, before changing approach, and for requested second opinions."
4
4
  ---
5
5
 
6
6
  Independent technical advisor.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "advisor",
3
3
  "name": "Advisor",
4
- "description": "Use on non-trivial work after orientation and before committing to an approach, when stuck or results do not converge, before changing approach, and for requested second opinions. Skip for low-difficulty work. Advisory analysis only; the final check belongs to Reviewer.",
4
+ "description": "Use by difficulty: on any work beyond a simple one- or two-step change, after orientation and before committing to an approach, when errors recur or results stop converging, before changing approach, and for requested second opinions.",
5
5
  "entry": "AGENT.md"
6
6
  }
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: Reviewer
3
- description: Use once at the final check of non-trivial work: after the implementation is written and verified, before reporting completion, to independently verify correctness, regressions, risks, and acceptance criteria. Skip for low-difficulty work.
3
+ description: Use only at the end, as the final check of non-trivial work: after the implementation is written and verified, before reporting completion, to independently verify correctness, regressions, risks, and acceptance criteria. Skip for low-difficulty work.
4
4
  ---
5
5
 
6
6
  Independent final-check review agent.
7
7
 
8
- You are called once, after the deliverable is written and the Lead's own
9
- verification has run, before completion is reported.
8
+ You are called only at the end, after the deliverable is written and the
9
+ Lead's own verification has run, before completion is reported.
10
10
 
11
11
  Inspect the diff, affected boundaries, existing tests, and stated acceptance
12
12
  criteria with independent judgment. Run the necessary builds, tests, lint, or