mixdog 0.9.2 → 0.9.4

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 (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,436 @@
1
+ // Native mixdog-patch engine transport: persistent stdio server, env-driven
2
+ // mode gating, binary resolution, prewarm/idle lifecycle, and the char-indexed
3
+ // EDIT client. Split out of patch.mjs; behavior is identical.
4
+ //
5
+ // Backend: NATIVE-ONLY. Every supported apply/edit case is dispatched to the
6
+ // mixdog-patch Rust engine via the persistent stdio server. There is NO JS
7
+ // apply fallback: unsupported / unsafe input returns a clean Error string.
8
+
9
+ import { existsSync } from 'node:fs';
10
+ import { spawn } from 'node:child_process';
11
+ import { createInterface } from 'node:readline';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { resolve as pathResolve, dirname as pathDirname, join as pathJoin } from 'node:path';
14
+ import { performance } from 'node:perf_hooks';
15
+ import { startChildGuardian } from '../../../../shared/child-guardian.mjs';
16
+ import { getPluginData } from '../../config.mjs';
17
+ import { ensurePatchBinary, findCachedPatchBinary } from '../patch-binary-fetcher.mjs';
18
+
19
+ const PLUGIN_ROOT = process.env.MIXDOG_ROOT
20
+ || pathResolve(pathDirname(fileURLToPath(import.meta.url)), '../../../../..');
21
+ const NATIVE_PATCH_DEFAULT_BIN = pathJoin(
22
+ PLUGIN_ROOT,
23
+ 'native/mixdog-patch/target/release',
24
+ process.platform === 'win32' ? 'mixdog-patch.exe' : 'mixdog-patch',
25
+ );
26
+ let _nativePatchServer = null;
27
+ let _nativePatchPrewarmTimer = null;
28
+ let _nativeEditServer = null;
29
+
30
+ function markNativePatchRuntimeTouched() {
31
+ try { globalThis.__mixdogNativePatchRuntimeTouched = true; } catch {}
32
+ }
33
+
34
+ function nativePatchMode() {
35
+ return String(process.env.MIXDOG_PATCH_NATIVE || 'auto').toLowerCase();
36
+ }
37
+
38
+ export function nativePatchEnabled() {
39
+ return !/^(0|false|no|off|js|legacy)$/i.test(nativePatchMode());
40
+ }
41
+
42
+ export function nativePatchTraceEnabled() {
43
+ return /^(1|true|yes)$/i.test(process.env.MIXDOG_PATCH_NATIVE_TRACE || '');
44
+ }
45
+
46
+ function ioTraceEnabled() {
47
+ return /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_IO_TRACE || ''));
48
+ }
49
+
50
+ export function ioTrace(event, fields = {}) {
51
+ if (!ioTraceEnabled()) return;
52
+ try {
53
+ process.stderr.write(`[io-trace] ${JSON.stringify({ event, ts: Date.now(), ...fields })}\n`);
54
+ } catch {}
55
+ }
56
+
57
+ export function patchTraceEnabled() {
58
+ return ioTraceEnabled()
59
+ || nativePatchTraceEnabled()
60
+ || /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_PATCH_TRACE || ''));
61
+ }
62
+
63
+ function nativePatchPrewarmEnabled() {
64
+ if (!nativePatchEnabled()) return false;
65
+ if (process.env.MIXDOG_PATCH_NATIVE_BIN && !existsSync(nativePatchBinPath())) return false;
66
+ return !/^(0|false|no)$/i.test(process.env.MIXDOG_PATCH_NATIVE_PREWARM || '');
67
+ }
68
+
69
+ function nativePatchPersistent() {
70
+ return /^(1|true|yes|server|persistent)$/i.test(nativePatchMode());
71
+ }
72
+
73
+ export function nativePatchBinPath() {
74
+ if (process.env.MIXDOG_PATCH_NATIVE_BIN) return process.env.MIXDOG_PATCH_NATIVE_BIN;
75
+ // Local cargo build first, then a fetched/cached prebuilt; absence is
76
+ // a hard error at dispatch (no JS fallback in native-only mode).
77
+ if (existsSync(NATIVE_PATCH_DEFAULT_BIN)) return NATIVE_PATCH_DEFAULT_BIN;
78
+ return findCachedPatchBinary(getPluginData()) || NATIVE_PATCH_DEFAULT_BIN;
79
+ }
80
+
81
+ export async function ensureNativePatchBinaryAvailable() {
82
+ if (!nativePatchEnabled()) {
83
+ throw new Error('apply_patch: native engine disabled via MIXDOG_PATCH_NATIVE; set it to "auto" or "1" to apply patches.');
84
+ }
85
+ const current = nativePatchBinPath();
86
+ if (existsSync(current)) return current;
87
+ if (process.env.MIXDOG_PATCH_NATIVE_BIN) {
88
+ throw new Error(`apply_patch: native patch binary not found at MIXDOG_PATCH_NATIVE_BIN=${current}.`);
89
+ }
90
+ try {
91
+ const fetched = await ensurePatchBinary(getPluginData());
92
+ if (fetched && existsSync(fetched)) return fetched;
93
+ } catch (err) {
94
+ throw new Error(`apply_patch: native patch binary unavailable — ${err?.message || String(err)}`);
95
+ }
96
+ const resolved = nativePatchBinPath();
97
+ if (existsSync(resolved)) return resolved;
98
+ throw new Error(`apply_patch: native patch binary not found at ${resolved}.`);
99
+ }
100
+
101
+ // Decode the hex-encoded failures payload that accompanies OK_PARTIAL:
102
+ // the Rust side emits utf-8 bytes (`<path>\t<reason>` records joined by
103
+ // `\n`) hex-encoded so they can ride the tab-separated response line
104
+ // without escaping. An empty / unparseable payload becomes an empty list
105
+ // so a missing field never crashes the caller.
106
+ function decodeNativeFailures(hexPayload) {
107
+ if (typeof hexPayload !== 'string' || hexPayload.length === 0) return [];
108
+ if (!/^[0-9a-fA-F]+$/.test(hexPayload) || hexPayload.length % 2 !== 0) return [];
109
+ let text = '';
110
+ try { text = Buffer.from(hexPayload, 'hex').toString('utf-8'); }
111
+ catch { return []; }
112
+ const out = [];
113
+ for (const raw of text.split('\n')) {
114
+ if (!raw) continue;
115
+ const tab = raw.indexOf('\t');
116
+ if (tab === -1) out.push({ path: '', reason: raw });
117
+ else out.push({ path: raw.slice(0, tab), reason: raw.slice(tab + 1) });
118
+ }
119
+ return out;
120
+ }
121
+
122
+ class NativePatchServer {
123
+ constructor(binPath) {
124
+ this.binPath = binPath;
125
+ // windowsHide: mixdog-patch.exe is a console binary; without this each spawn
126
+ // flashes an empty console window on Windows. Especially visible now that the
127
+ // idle watchdog exits the server and it respawns on the next request.
128
+ this.child = spawn(binPath, ['--server'], { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
129
+ startChildGuardian({ childPid: this.child.pid, label: 'native-patch-server', orphanGraceMs: 5000, forceGraceMs: 2000 });
130
+ this.stderr = '';
131
+ this.lines = [];
132
+ this.waiters = [];
133
+ this.exited = false;
134
+ this.child.stderr.setEncoding('utf8');
135
+ this.child.stderr.on('data', (chunk) => { this.stderr += chunk; });
136
+ this.rl = createInterface({ input: this.child.stdout });
137
+ this.rl.on('line', (line) => {
138
+ const waiter = this.waiters.shift();
139
+ if (waiter) waiter.resolve(line);
140
+ else this.lines.push(line);
141
+ });
142
+ this.child.on('exit', (code, signal) => {
143
+ this.exited = true;
144
+ const err = new Error(`native patch server exited code=${code} signal=${signal} stderr=${this.stderr}`);
145
+ for (const waiter of this.waiters.splice(0)) waiter.reject(err);
146
+ try { this.rl.close(); } catch {}
147
+ });
148
+ }
149
+
150
+ abort(signal) {
151
+ const err = new Error(signal?.reason?.message || signal?.reason || 'native patch aborted');
152
+ err.name = 'AbortError';
153
+ if (_nativePatchServer === this) _nativePatchServer = null;
154
+ for (const waiter of this.waiters.splice(0)) waiter.reject(err);
155
+ try { this.child.kill('SIGTERM'); } catch {}
156
+ return err;
157
+ }
158
+
159
+ nextLine() {
160
+ if (this.lines.length > 0) return Promise.resolve(this.lines.shift());
161
+ if (this.exited) return Promise.reject(new Error(`native patch server already exited: ${this.stderr}`));
162
+ return new Promise((resolve, reject) => this.waiters.push({ resolve, reject }));
163
+ }
164
+
165
+ ref() {
166
+ try { this.child.ref(); } catch {}
167
+ try { this.child.stdin.ref?.(); } catch {}
168
+ try { this.child.stdout.ref?.(); } catch {}
169
+ try { this.child.stderr.ref?.(); } catch {}
170
+ }
171
+
172
+ unref() {
173
+ try { this.child.unref(); } catch {}
174
+ try { this.child.stdin.unref?.(); } catch {}
175
+ try { this.child.stdout.unref?.(); } catch {}
176
+ try { this.child.stderr.unref?.(); } catch {}
177
+ }
178
+
179
+ async ping() {
180
+ this.ref();
181
+ const linePromise = this.nextLine();
182
+ this.child.stdin.write('PING\n');
183
+ const line = await linePromise;
184
+ if (line !== 'OK\tPONG') {
185
+ throw new Error(`native patch server ping failed: ${line || 'no native response'}`);
186
+ }
187
+ }
188
+
189
+ async apply(basePath, patchText, { fuzz = 2, rejectPartial = true, dryRun = false, signal = null } = {}) {
190
+ this.ref();
191
+ if (signal?.aborted) {
192
+ const err = new Error(signal.reason?.message || signal.reason || 'native patch aborted');
193
+ err.name = 'AbortError';
194
+ throw err;
195
+ }
196
+ const started = performance.now();
197
+ const baseBuf = Buffer.from(basePath, 'utf8');
198
+ const patchBuf = Buffer.from(patchText, 'utf8');
199
+ const linePromise = this.nextLine();
200
+ if (signal) linePromise.catch(() => {});
201
+ let abortListener = null;
202
+ const abortPromise = signal ? new Promise((_, reject) => {
203
+ abortListener = () => {
204
+ reject(this.abort(signal));
205
+ };
206
+ signal.addEventListener('abort', abortListener, { once: true });
207
+ }) : null;
208
+ // 7-token APPLY protocol: APPLY <base_len> <patch_len> <timing> <dry_run> <fuzz> <reject_partial>
209
+ // - timing=1 keeps the server emitting per-phase ms fields
210
+ // - dry_run=1 validates without writing; useful for tests and explicit callers
211
+ // - fuzz=0 means strict context match; fuzz=2 absorbs minor outer-context drift and context trailing spaces/tabs
212
+ // - reject_partial=0 unlocks file-level isolation (OK_PARTIAL response)
213
+ const fuzzTok = Number.isFinite(fuzz) && fuzz >= 0 ? Math.floor(fuzz) : 2;
214
+ const rpTok = rejectPartial ? 1 : 0;
215
+ const dryTok = dryRun ? 1 : 0;
216
+ this.child.stdin.write(`APPLY ${baseBuf.length} ${patchBuf.length} 1 ${dryTok} ${fuzzTok} ${rpTok}\n`);
217
+ this.child.stdin.write(baseBuf);
218
+ this.child.stdin.write(patchBuf);
219
+ let line;
220
+ try {
221
+ line = abortPromise ? await Promise.race([linePromise, abortPromise]) : await linePromise;
222
+ } finally {
223
+ if (abortListener) {
224
+ try { signal.removeEventListener('abort', abortListener); } catch {}
225
+ }
226
+ }
227
+ if (!line) throw new Error('no native response');
228
+ if (line.startsWith('ERR\t')) throw new Error(line.slice(4));
229
+ const okFull = line.startsWith('OK\t');
230
+ const okPartial = line.startsWith('OK_PARTIAL\t');
231
+ if (!okFull && !okPartial) throw new Error(line);
232
+ const fields = line.split('\t');
233
+ // fields[0] = "OK" | "OK_PARTIAL".
234
+ // OK layout: <files> <readMs> <applyMs> <writeMs> <totalMs> <hashMs> <contentHashes>
235
+ // OK_PARTIAL layout: <files> <failed> <readMs> <applyMs> <writeMs> <totalMs> <hashMs> <contentHashes> <hexFailures>
236
+ // The OK_PARTIAL line carries an extra <failed> count between <files>
237
+ // and the timing block, plus a trailing <hexFailures> column — keep
238
+ // the two decodes separate so SKIP failure counts stay accurate.
239
+ let files; let readMs; let applyMs; let writeMs; let totalMs; let hashMs;
240
+ let contentHashesRaw; let hexFailures;
241
+ if (okPartial) {
242
+ files = fields[1];
243
+ // fields[2] = <failed> count; the JS layer already derives a failure
244
+ // count from decodeNativeFailures(hexFailures), so skip the raw cell.
245
+ readMs = fields[3];
246
+ applyMs = fields[4];
247
+ writeMs = fields[5];
248
+ totalMs = fields[6];
249
+ hashMs = fields[7];
250
+ contentHashesRaw = fields[8];
251
+ hexFailures = fields[9];
252
+ } else {
253
+ files = fields[1];
254
+ readMs = fields[2];
255
+ applyMs = fields[3];
256
+ writeMs = fields[4];
257
+ totalMs = fields[5];
258
+ hashMs = fields[6];
259
+ contentHashesRaw = fields[7];
260
+ }
261
+ const contentHashes = String(contentHashesRaw || '')
262
+ .split(',')
263
+ .filter((value) => value.length > 0)
264
+ .map((value) => (/^[a-f0-9]{64}$/i.test(value) ? value.toLowerCase() : null));
265
+ const failures = okPartial ? decodeNativeFailures(hexFailures) : [];
266
+ return {
267
+ partial: okPartial,
268
+ files: Number(files) || 0,
269
+ readMs: Number(readMs) || 0,
270
+ applyMs: Number(applyMs) || 0,
271
+ writeMs: Number(writeMs) || 0,
272
+ hashMs: Number(hashMs) || 0,
273
+ totalMs: Number(totalMs) || 0,
274
+ contentHashes,
275
+ contentHash: contentHashes.length === 1 ? contentHashes[0] : null,
276
+ failures,
277
+ roundtripMs: performance.now() - started,
278
+ };
279
+ }
280
+
281
+ // EDIT protocol client: invariant-safe char-indexed edit. Mirrors apply()'s
282
+ // abort/await-line handling. EDIT <path_len> <old_len> <new_len> <replace_all>
283
+ // <dry_run> then path+old+new bytes; response is the 8-field OK line with the
284
+ // matched tier.
285
+ async edit(fullPath, oldBuf, newBuf, { replaceAll = false, dryRun = false, signal = null } = {}) {
286
+ this.ref();
287
+ if (signal?.aborted) {
288
+ const err = new Error(signal.reason?.message || signal.reason || 'native edit aborted');
289
+ err.name = 'AbortError';
290
+ throw err;
291
+ }
292
+ const started = performance.now();
293
+ const pathBuf = Buffer.from(fullPath, 'utf8');
294
+ const linePromise = this.nextLine();
295
+ if (signal) linePromise.catch(() => {});
296
+ let abortListener = null;
297
+ const abortPromise = signal ? new Promise((_, reject) => {
298
+ abortListener = () => { reject(this.abort(signal)); };
299
+ signal.addEventListener('abort', abortListener, { once: true });
300
+ }) : null;
301
+ this.child.stdin.write(
302
+ `EDIT ${pathBuf.length} ${oldBuf.length} ${newBuf.length} ${replaceAll ? 1 : 0} ${dryRun ? 1 : 0}\n`,
303
+ );
304
+ this.child.stdin.write(pathBuf);
305
+ this.child.stdin.write(oldBuf);
306
+ this.child.stdin.write(newBuf);
307
+ let line;
308
+ try {
309
+ line = abortPromise ? await Promise.race([linePromise, abortPromise]) : await linePromise;
310
+ } finally {
311
+ if (abortListener) {
312
+ try { signal.removeEventListener('abort', abortListener); } catch {}
313
+ }
314
+ }
315
+ if (!line) throw new Error('no native response');
316
+ if (line.startsWith('ERR\t')) throw new Error(line.slice(4));
317
+ if (!line.startsWith('OK\t')) throw new Error(line);
318
+ const f = line.split('\t');
319
+ // OK \t replacements \t readMs \t applyMs \t writeMs \t totalMs \t tier \t hash
320
+ return {
321
+ replacements: Number(f[1]) || 0,
322
+ readMs: Number(f[2]) || 0,
323
+ applyMs: Number(f[3]) || 0,
324
+ writeMs: Number(f[4]) || 0,
325
+ totalMs: Number(f[5]) || 0,
326
+ tier: f[6] || 'exact',
327
+ contentHash: /^[a-f0-9]{64}$/i.test(f[7] || '') ? f[7].toLowerCase() : null,
328
+ roundtripMs: performance.now() - started,
329
+ };
330
+ }
331
+
332
+ async close(options = {}) {
333
+ if (this.exited) return;
334
+ const waitForExit = options?.waitForExit !== false;
335
+ if (!waitForExit) {
336
+ try { this.child.stdin.end('QUIT\n'); } catch {}
337
+ this.unref();
338
+ return;
339
+ }
340
+ this.ref();
341
+ try { this.child.stdin.end('QUIT\n'); } catch {}
342
+ await new Promise((resolve) => this.child.once('exit', resolve));
343
+ try { this.rl.close(); } catch {}
344
+ }
345
+ }
346
+
347
+ export function getNativePatchServer() {
348
+ markNativePatchRuntimeTouched();
349
+ const binPath = nativePatchBinPath();
350
+ if (!existsSync(binPath)) {
351
+ throw new Error(`native patch binary not found: ${binPath}`);
352
+ }
353
+ if (!_nativePatchServer || _nativePatchServer.exited || _nativePatchServer.binPath !== binPath) {
354
+ _nativePatchServer = new NativePatchServer(binPath);
355
+ }
356
+ return _nativePatchServer;
357
+ }
358
+
359
+ function getNativeEditServer() {
360
+ markNativePatchRuntimeTouched();
361
+ // Honor MIXDOG_EDIT_NATIVE_BIN (the same override the edit gating checks) so
362
+ // the gated binary and the spawned server binary cannot diverge.
363
+ const binPath = process.env.MIXDOG_EDIT_NATIVE_BIN || nativePatchBinPath();
364
+ if (!existsSync(binPath)) {
365
+ throw new Error(`native patch binary not found: ${binPath}`);
366
+ }
367
+ if (!_nativeEditServer || _nativeEditServer.exited || _nativeEditServer.binPath !== binPath) {
368
+ _nativeEditServer = new NativePatchServer(binPath);
369
+ }
370
+ return _nativeEditServer;
371
+ }
372
+
373
+ // Invariant-safe char-indexed edit over the persistent server (B2). Shares the
374
+ // NativePatchServer transport but runs on a DEDICATED instance so edit and
375
+ // patch requests never interleave their stdin framing on one stdout stream.
376
+ export async function runServerEdit({ fullPath, oldBuf, newBuf, replaceAll = false, dryRun = false, signal = null }) {
377
+ const server = getNativeEditServer();
378
+ return server.edit(fullPath, oldBuf, newBuf, { replaceAll, dryRun, signal });
379
+ }
380
+
381
+ export function scheduleNativePatchPrewarm() {
382
+ if (!nativePatchPrewarmEnabled() || _nativePatchPrewarmTimer || _nativePatchServer) return;
383
+ _nativePatchPrewarmTimer = setImmediate(() => {
384
+ void (async () => {
385
+ _nativePatchPrewarmTimer = null;
386
+ const started = performance.now();
387
+ try {
388
+ // Ensure the native binary is present (local build or fetched
389
+ // prebuilt) before starting the server. Best-effort: failures
390
+ // surface as a hard error at dispatch (no JS fallback in the
391
+ // native-only path).
392
+ if (!existsSync(nativePatchBinPath())) {
393
+ try { await ensurePatchBinary(getPluginData()); } catch { /* surfaces at dispatch */ }
394
+ }
395
+ await getNativePatchServer().ping();
396
+ if (!nativePatchPersistent() && (_nativePatchServer?.waiters?.length || 0) === 0) {
397
+ _nativePatchServer?.unref();
398
+ }
399
+ if (nativePatchTraceEnabled()) {
400
+ process.stderr.write(`[patch-native-trace] prewarm_ms=${(performance.now() - started).toFixed(3)}\n`);
401
+ }
402
+ } catch (err) {
403
+ if (nativePatchTraceEnabled()) {
404
+ process.stderr.write(`[patch-native-trace] prewarm_failed=${err?.message || String(err)}\n`);
405
+ }
406
+ }
407
+ })();
408
+ });
409
+ if (_nativePatchPrewarmTimer?.unref) _nativePatchPrewarmTimer.unref();
410
+ }
411
+
412
+ export function scheduleNativePatchIdleClose() {
413
+ if (nativePatchPersistent() || !_nativePatchServer) return;
414
+ if (process.versions?.bun) {
415
+ const server = _nativePatchServer;
416
+ _nativePatchServer = null;
417
+ void server?.close().catch(() => {});
418
+ return;
419
+ }
420
+ _nativePatchServer.unref();
421
+ }
422
+
423
+ export async function closeNativePatchServerForTests(options = {}) {
424
+ if (_nativePatchPrewarmTimer) {
425
+ try { clearImmediate(_nativePatchPrewarmTimer); } catch {}
426
+ _nativePatchPrewarmTimer = null;
427
+ }
428
+ const server = _nativePatchServer;
429
+ _nativePatchServer = null;
430
+ const editServer = _nativeEditServer;
431
+ _nativeEditServer = null;
432
+ await server?.close(options);
433
+ await editServer?.close(options);
434
+ }
435
+
436
+ try { globalThis.__mixdogCloseNativePatchServers = closeNativePatchServerForTests; } catch {}