mixdog 0.9.3 → 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 (329) hide show
  1. package/package.json +7 -3
  2. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  3. package/scripts/bench/lead-review-tasks.json +20 -0
  4. package/scripts/bench/r4-mixed-tasks.json +20 -0
  5. package/scripts/bench/review-tasks.json +20 -0
  6. package/scripts/bench/round-codex.json +114 -0
  7. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  8. package/scripts/bench/round-mixdog-lead.json +269 -0
  9. package/scripts/bench/round-mixdog.json +126 -0
  10. package/scripts/bench/round-r10-bigsample.json +679 -0
  11. package/scripts/bench/round-r11-codexalign.json +257 -0
  12. package/scripts/bench/round-r4-codex.json +114 -0
  13. package/scripts/bench/round-r4-mixed.json +225 -0
  14. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  15. package/scripts/bench/round-r6-codex.json +114 -0
  16. package/scripts/bench/round-r6-solo.json +257 -0
  17. package/scripts/bench/round-r7-full.json +254 -0
  18. package/scripts/bench/round-r8-fulldefault.json +255 -0
  19. package/scripts/bench-run.mjs +215 -29
  20. package/scripts/freevar-smoke.mjs +95 -0
  21. package/scripts/internal-comms-bench.mjs +1 -0
  22. package/scripts/internal-comms-smoke.mjs +10 -9
  23. package/scripts/mouse-probe.mjs +45 -0
  24. package/scripts/output-style-bench.mjs +13 -6
  25. package/scripts/output-style-smoke.mjs +4 -4
  26. package/scripts/provider-toolcall-test.mjs +7 -3
  27. package/scripts/recall-usecase-cases.json +18 -0
  28. package/scripts/recall-usecase-probe.json +6 -0
  29. package/scripts/session-bench.mjs +152 -6
  30. package/scripts/tool-smoke.mjs +23 -63
  31. package/scripts/tui-render-smoke.mjs +90 -0
  32. package/scripts/webhook-smoke.mjs +208 -0
  33. package/src/agents/debugger/AGENT.md +4 -1
  34. package/src/agents/heavy-worker/AGENT.md +6 -5
  35. package/src/agents/maintainer/AGENT.md +4 -0
  36. package/src/agents/reviewer/AGENT.md +2 -1
  37. package/src/agents/worker/AGENT.md +8 -4
  38. package/src/lib/rules-builder.cjs +4 -0
  39. package/src/mixdog-session-runtime.mjs +632 -2042
  40. package/src/output-styles/default.md +34 -9
  41. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  42. package/src/output-styles/minimal.md +4 -1
  43. package/src/output-styles/simple.md +22 -7
  44. package/src/rules/agent/00-common.md +2 -0
  45. package/src/rules/lead/lead-brief.md +12 -0
  46. package/src/rules/lead/lead-tool.md +0 -11
  47. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  48. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  49. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  50. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  51. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  52. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  53. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  54. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +62 -20
  55. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +81 -1281
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  59. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -3
  60. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  61. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  62. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  63. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  64. package/src/runtime/agent/orchestrator/providers/gemini.mjs +43 -1013
  65. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +17 -3
  66. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  67. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  68. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +40 -1143
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +297 -2123
  76. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +130 -1002
  77. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  78. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  79. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  80. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  82. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  83. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  84. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  85. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  86. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  87. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  88. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  89. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  90. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +14 -2
  91. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  92. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -3
  93. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  94. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  95. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  96. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  97. package/src/runtime/agent/orchestrator/session/loop.mjs +251 -397
  98. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  99. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +7 -4
  100. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +12 -0
  101. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  102. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  103. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  104. package/src/runtime/agent/orchestrator/session/manager.mjs +166 -1087
  105. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  106. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  107. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  108. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  109. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +32 -41
  110. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -92
  115. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +28 -265
  118. package/src/runtime/agent/orchestrator/tools/builtin.mjs +0 -6
  119. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +57 -3
  120. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  121. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +10 -122
  122. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  123. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  124. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  125. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  126. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  127. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  128. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  129. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  130. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  131. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  132. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  133. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  134. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +0 -21
  135. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -72
  136. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  137. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  138. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  139. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  140. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  141. package/src/runtime/channels/backends/discord.mjs +12 -292
  142. package/src/runtime/channels/index.mjs +229 -663
  143. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  144. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  145. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  146. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  147. package/src/runtime/channels/lib/output-forwarder.mjs +1 -1
  148. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  149. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  150. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  151. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  152. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  153. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  154. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  155. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  156. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  157. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  158. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  159. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  160. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  161. package/src/runtime/channels/lib/webhook.mjs +36 -570
  162. package/src/runtime/channels/tool-defs.mjs +11 -130
  163. package/src/runtime/memory/index.mjs +201 -1948
  164. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  165. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  166. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  167. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  168. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  169. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  170. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  171. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  172. package/src/runtime/memory/lib/memory-cycle2.mjs +24 -842
  173. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  174. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  175. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  176. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  177. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  178. package/src/runtime/memory/lib/recall-format.mjs +55 -0
  179. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  180. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  181. package/src/runtime/memory/tool-defs.mjs +5 -13
  182. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  183. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  184. package/src/runtime/search/lib/web-tools.mjs +24 -602
  185. package/src/runtime/shared/atomic-file.mjs +26 -1
  186. package/src/runtime/shared/launcher-control.mjs +2 -2
  187. package/src/runtime/shared/tool-primitives.mjs +308 -0
  188. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  189. package/src/runtime/shared/tool-surface.mjs +80 -898
  190. package/src/runtime/shared/transcript-writer.mjs +23 -0
  191. package/src/runtime/shared/update-checker.mjs +7 -4
  192. package/src/session-runtime/config-helpers.mjs +84 -2
  193. package/src/session-runtime/config-lifecycle.mjs +232 -0
  194. package/src/session-runtime/cwd-plugins.mjs +226 -0
  195. package/src/session-runtime/mcp-glue.mjs +177 -0
  196. package/src/session-runtime/model-recency.mjs +111 -0
  197. package/src/session-runtime/native-search.mjs +247 -0
  198. package/src/session-runtime/output-styles.mjs +11 -9
  199. package/src/session-runtime/prewarm.mjs +142 -0
  200. package/src/session-runtime/provider-models.mjs +278 -0
  201. package/src/session-runtime/provider-usage.mjs +120 -0
  202. package/src/session-runtime/quick-model-rows.mjs +170 -0
  203. package/src/session-runtime/quick-search-models.mjs +46 -0
  204. package/src/session-runtime/session-hooks.mjs +93 -0
  205. package/src/session-runtime/settings-api.mjs +319 -0
  206. package/src/session-runtime/tool-catalog.mjs +29 -29
  207. package/src/session-runtime/tool-defs.mjs +84 -0
  208. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  209. package/src/standalone/agent-tool/helpers.mjs +237 -0
  210. package/src/standalone/agent-tool/notify.mjs +107 -0
  211. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  212. package/src/standalone/agent-tool/render.mjs +152 -0
  213. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  214. package/src/standalone/agent-tool.mjs +110 -671
  215. package/src/standalone/channel-worker.mjs +4 -7
  216. package/src/standalone/explore-tool.mjs +30 -9
  217. package/src/standalone/hook-bus/config.mjs +207 -0
  218. package/src/standalone/hook-bus/constants.mjs +90 -0
  219. package/src/standalone/hook-bus/handlers.mjs +481 -0
  220. package/src/standalone/hook-bus/payload.mjs +31 -0
  221. package/src/standalone/hook-bus/rules.mjs +77 -0
  222. package/src/standalone/hook-bus.mjs +77 -870
  223. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  224. package/src/standalone/opencode-go-login.mjs +5 -1
  225. package/src/standalone/provider-admin.mjs +1 -16
  226. package/src/standalone/usage-dashboard.mjs +3 -1
  227. package/src/tui/App.jsx +945 -8094
  228. package/src/tui/app/app-format.mjs +206 -0
  229. package/src/tui/app/channel-pickers.mjs +510 -0
  230. package/src/tui/app/clipboard.mjs +67 -0
  231. package/src/tui/app/core-memory-picker.mjs +210 -0
  232. package/src/tui/app/extension-pickers.mjs +506 -0
  233. package/src/tui/app/input-parsers.mjs +193 -0
  234. package/src/tui/app/maintenance-pickers.mjs +324 -0
  235. package/src/tui/app/model-options.mjs +330 -0
  236. package/src/tui/app/model-picker.mjs +365 -0
  237. package/src/tui/app/onboarding-steps.mjs +400 -0
  238. package/src/tui/app/project-picker.mjs +247 -0
  239. package/src/tui/app/provider-setup-picker.mjs +580 -0
  240. package/src/tui/app/resume-picker.mjs +55 -0
  241. package/src/tui/app/route-pickers.mjs +419 -0
  242. package/src/tui/app/settings-picker.mjs +490 -0
  243. package/src/tui/app/slash-commands.mjs +101 -0
  244. package/src/tui/app/slash-dispatch.mjs +427 -0
  245. package/src/tui/app/text-layout.mjs +46 -0
  246. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  247. package/src/tui/app/transcript-window.mjs +671 -0
  248. package/src/tui/app/use-mouse-input.mjs +460 -0
  249. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  250. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  251. package/src/tui/app/use-transcript-window.mjs +589 -0
  252. package/src/tui/components/ConfirmBar.jsx +1 -1
  253. package/src/tui/components/Picker.jsx +32 -4
  254. package/src/tui/components/PromptInput.jsx +23 -101
  255. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  256. package/src/tui/components/StatusLine.jsx +63 -12
  257. package/src/tui/components/TextEntryPanel.jsx +11 -0
  258. package/src/tui/components/ToolExecution.jsx +52 -594
  259. package/src/tui/components/TranscriptItem.jsx +105 -0
  260. package/src/tui/components/UsagePanel.jsx +18 -4
  261. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  262. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  263. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  264. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  265. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  266. package/src/tui/display-width.mjs +20 -3
  267. package/src/tui/dist/index.mjs +19652 -18630
  268. package/src/tui/engine/agent-job-feed.mjs +133 -0
  269. package/src/tui/engine/notification-plan.mjs +76 -0
  270. package/src/tui/engine/render-timing.mjs +17 -0
  271. package/src/tui/engine/tool-approval.mjs +94 -0
  272. package/src/tui/engine/tool-card-results.mjs +234 -0
  273. package/src/tui/engine/tool-result-status.mjs +135 -0
  274. package/src/tui/engine.mjs +122 -562
  275. package/src/tui/figures.mjs +5 -0
  276. package/src/tui/index.jsx +105 -0
  277. package/src/tui/input-editing.mjs +2 -2
  278. package/src/tui/markdown/format-token.mjs +4 -1
  279. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  280. package/src/tui/theme.mjs +6 -0
  281. package/src/ui/statusline-agents.mjs +213 -0
  282. package/src/ui/statusline-format.mjs +146 -0
  283. package/src/ui/statusline-segments.mjs +148 -0
  284. package/src/ui/statusline.mjs +67 -501
  285. package/src/ui/tool-card.mjs +0 -1
  286. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  287. package/src/workflows/default/WORKFLOW.md +1 -1
  288. package/src/workflows/sequential/WORKFLOW.md +1 -1
  289. package/vendor/ink/build/display-width.js +19 -3
  290. package/vendor/ink/build/ink.js +103 -6
  291. package/vendor/ink/build/log-update.js +17 -3
  292. package/vendor/ink/build/wrap-text.js +125 -0
  293. package/scripts/_test-folder-dialog.mjs +0 -30
  294. package/scripts/fix-brief-fn.mjs +0 -35
  295. package/scripts/fix-format-tool-surface.mjs +0 -24
  296. package/scripts/fix-tool-exec-visible.mjs +0 -42
  297. package/scripts/patch-agent-brief.mjs +0 -48
  298. package/scripts/patch-app.mjs +0 -21
  299. package/scripts/patch-app2.mjs +0 -18
  300. package/scripts/patch-dist-brief.mjs +0 -96
  301. package/scripts/patch-tool-exec.mjs +0 -70
  302. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  303. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  304. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  305. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  306. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  307. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +0 -162
  308. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  309. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  310. package/src/runtime/shared/task-notification-envelope.test.mjs +0 -107
  311. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  312. package/src/standalone/agent-task-status.test.mjs +0 -76
  313. package/src/tui/components/tool-output-format.test.mjs +0 -399
  314. package/src/tui/display-width.test.mjs +0 -35
  315. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  316. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  317. package/src/tui/input-editing.selection.test.mjs +0 -75
  318. package/src/tui/markdown/format-token.test.mjs +0 -354
  319. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  320. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  321. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  322. package/src/tui/paste-fix.test.mjs +0 -119
  323. package/src/tui/prompt-history-store.test.mjs +0 -52
  324. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  325. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  326. package/src/ui/markdown.test.mjs +0 -70
  327. package/src/ui/statusline-context-label.test.mjs +0 -15
  328. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  329. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -9,15 +9,12 @@ import { appendBuffered } from '../runtime/shared/buffered-appender.mjs';
9
9
  const CHANNEL_TOOLS = new Set([
10
10
  'reply',
11
11
  'fetch',
12
- 'react',
13
- 'edit_message',
14
- 'download_attachment',
15
- 'schedule_status',
16
- 'trigger_schedule',
17
- 'schedule_control',
12
+ // activate_channel_bridge/reload_config are NOT model-facing tools (no
13
+ // TOOL_DEFS entry) but stay in the allow-set: mixdog-session-runtime.mjs
14
+ // calls channels.execute() with these names directly as internal
15
+ // Lead-only runtime plumbing (bridge-claim on start, config hot-reload).
18
16
  'activate_channel_bridge',
19
17
  'reload_config',
20
- 'inject_command',
21
18
  ]);
22
19
 
23
20
  const WORKER_PRELOAD = fileURLToPath(new URL('./channel-worker-preload.cjs', import.meta.url));
@@ -1,4 +1,5 @@
1
1
  import { isAbsolute, resolve } from 'node:path';
2
+ import { existsSync } from 'node:fs';
2
3
  import { homedir } from 'node:os';
3
4
  import { makeAgentDispatch } from '../runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs';
4
5
  import { loadConfig } from '../runtime/agent/orchestrator/config.mjs';
@@ -80,11 +81,11 @@ function resolveExploreCwd(input, callerCwd) {
80
81
  return base;
81
82
  }
82
83
 
83
- function settledExplorerResult(result) {
84
+ function settledExplorerResult(result, cwd = null) {
84
85
  if (result?.status !== 'fulfilled') {
85
86
  return { ok: false, text: `[explorer error] ${result?.reason?.message || String(result?.reason)}` };
86
87
  }
87
- const text = cleanExplorerText(typeof result.value === 'string' ? result.value : responseText(result.value));
88
+ const text = cleanExplorerText(typeof result.value === 'string' ? result.value : responseText(result.value), cwd);
88
89
  if (!text) return { ok: false, text: '[explorer error] empty response' };
89
90
  return { ok: true, text };
90
91
  }
@@ -106,10 +107,10 @@ function fatalExploreError(settled) {
106
107
  return (settled || []).find((r) => r?.status === 'rejected' && isFatalExploreError(r.reason))?.reason || null;
107
108
  }
108
109
 
109
- function mergeSettled(settled, queries) {
110
+ function mergeSettled(settled, queries, cwd = null) {
110
111
  const single = queries.length === 1;
111
112
  if (single) {
112
- const { text: body } = settledExplorerResult(settled[0]);
113
+ const { text: body } = settledExplorerResult(settled[0], cwd);
113
114
  return body.length > EXPLORE_OUTPUT_CHAR_CAP
114
115
  ? body.slice(0, EXPLORE_OUTPUT_CHAR_CAP) + EXPLORE_TRUNCATION_MARKER
115
116
  : body;
@@ -120,7 +121,7 @@ function mergeSettled(settled, queries) {
120
121
  let truncated = false;
121
122
  for (let i = 0; i < settled.length; i++) {
122
123
  const header = `Q${i + 1}: ${String(queries[i] ?? '').replace(/\s+/g, ' ').slice(0, 60)}`;
123
- const { text: body } = settledExplorerResult(settled[i]);
124
+ const { text: body } = settledExplorerResult(settled[i], cwd);
124
125
  const piece = `${header}\n${body}`;
125
126
  const addLen = (parts.length === 0 ? 0 : sep.length) + piece.length;
126
127
  if (total + addLen > EXPLORE_OUTPUT_CHAR_CAP) {
@@ -247,6 +248,7 @@ function responseText(response) {
247
248
  }
248
249
 
249
250
  const ANCHOR_LINE_RE = /(?:^|\s)(?:[A-Za-z]:[\\/][^:\n]+|\.{0,2}[\\/][^:\n]+|src[\\/][^:\n]+|[\w.-]+[\\/][^:\n]+):\d+\b/;
251
+ const ANCHOR_PATH_CAPTURE_RE = /(?:^|\s)((?:[A-Za-z]:[\\/][^:\n]+|\.{0,2}[\\/][^:\n]+|src[\\/][^:\n]+|[\w.-]+[\\/][^:\n]+)):\d+\b/;
250
252
  const FAILED_RE = /\b(?:EXPLORATION_FAILED|exploration failed|no credible (?:anchor|location)|no relevant (?:anchor|location)|not found|could(?: not|n't) find)\b/i;
251
253
 
252
254
  function normalizeExplorerLine(line) {
@@ -260,7 +262,16 @@ function normalizeExplorerLine(line) {
260
262
  .trim();
261
263
  }
262
264
 
263
- function cleanExplorerText(text) {
265
+ // Anchor existence filter: a locator answer citing a file that does not exist
266
+ // is a hallucination — drop the line. Only enforced when cwd is known.
267
+ function anchorLineExists(line, cwd) {
268
+ const m = line.match(ANCHOR_PATH_CAPTURE_RE);
269
+ if (!m) return true;
270
+ const p = m[1].trim();
271
+ try { return existsSync(isAbsolute(p) ? p : resolve(cwd, p)); } catch { return true; }
272
+ }
273
+
274
+ function cleanExplorerText(text, cwd = null) {
264
275
  const raw = String(text || '').trim();
265
276
  if (!raw) return '';
266
277
  const anchors = [];
@@ -270,7 +281,12 @@ function cleanExplorerText(text) {
270
281
  if (/^EXPLORATION_FAILED\b/i.test(line)) return 'EXPLORATION_FAILED';
271
282
  if (ANCHOR_LINE_RE.test(line)) anchors.push(line);
272
283
  }
273
- if (anchors.length) return anchors.join('\n');
284
+ if (anchors.length) {
285
+ const real = cwd ? anchors.filter((l) => anchorLineExists(l, cwd)) : anchors;
286
+ // All anchors pointed at nonexistent paths: fail harmlessly instead of
287
+ // forwarding hallucinated locations.
288
+ return real.length ? real.join('\n') : 'EXPLORATION_FAILED';
289
+ }
274
290
  if (FAILED_RE.test(raw)) return 'EXPLORATION_FAILED';
275
291
  return raw;
276
292
  }
@@ -311,10 +327,15 @@ async function runExploreSync(args = {}, ctx = {}) {
311
327
  const presetName = (route && typeof route === 'object')
312
328
  ? `${clean(route.provider)}/${clean(route.model)}`
313
329
  : (route || '');
330
+ // Explorer is a one-shot locator (one grep+code_graph turn, answer, stop —
331
+ // rules/agent/30-explorer.md). Pin a low hard cap so a drifting explorer
332
+ // cannot run an 11-call research loop; 3 leaves room for one lookup turn,
333
+ // one recovery turn, and the answer.
314
334
  const llm = makeAgentDispatch({
315
335
  agent: 'explorer',
316
336
  cwd: resolvedCwd,
317
337
  brief: true,
338
+ maxLoopIterations: 3,
318
339
  parentSessionId: ctx.callerSessionId || null,
319
340
  clientHostPid: ctx.clientHostPid || null,
320
341
  config,
@@ -328,8 +349,8 @@ async function runExploreSync(args = {}, ctx = {}) {
328
349
  const fatal = fatalExploreError(settled);
329
350
  if (fatal) return fail(presentErrorText(fatal, { surface: 'explore' }));
330
351
 
331
- const merged = mergeSettled(settled, working);
332
- const allFailed = settled.every((r) => !settledExplorerResult(r).ok);
352
+ const merged = mergeSettled(settled, working, resolvedCwd);
353
+ const allFailed = settled.every((r) => !settledExplorerResult(r, resolvedCwd).ok);
333
354
  const out = capNotice + merged;
334
355
  return allFailed ? fail(out) : ok(out);
335
356
  }
@@ -0,0 +1,207 @@
1
+ import { existsSync, readFileSync, statSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { listRegisteredPlugins } from '../plugin-admin.mjs';
4
+ import { NO_MATCHER_EVENTS } from './constants.mjs';
5
+
6
+ export function hookRulesPath(dataDir) {
7
+ if (process.env.MIXDOG_HOOKS_FILE) return resolve(process.env.MIXDOG_HOOKS_FILE);
8
+ return dataDir ? join(dataDir, 'hooks.json') : null;
9
+ }
10
+
11
+ export function normalizeRules(raw) {
12
+ if (Array.isArray(raw)) return raw;
13
+ if (Array.isArray(raw?.toolBefore)) return raw.toolBefore;
14
+ if (Array.isArray(raw?.beforeTool)) return raw.beforeTool;
15
+ if (Array.isArray(raw?.hooks?.toolBefore)) return raw.hooks.toolBefore;
16
+ return [];
17
+ }
18
+
19
+ function uniqueHookEntries(entries) {
20
+ const seen = new Set();
21
+ const out = [];
22
+ for (const entry of entries) {
23
+ if (!entry?.path) continue;
24
+ const resolved = resolve(entry.path);
25
+ const key = process.platform === 'win32' ? resolved.toLowerCase() : resolved;
26
+ if (seen.has(key)) continue;
27
+ seen.add(key);
28
+ out.push({ ...entry, path: resolved });
29
+ }
30
+ return out;
31
+ }
32
+
33
+ function cleanHookId(value) {
34
+ return String(value ?? '').trim()
35
+ .toLowerCase()
36
+ .replace(/[^a-z0-9_.-]+/g, '-')
37
+ .replace(/^-+|-+$/g, '');
38
+ }
39
+
40
+ function pluginHookConfigEntries(dataDir) {
41
+ if (!dataDir) return [];
42
+ let plugins = [];
43
+ try {
44
+ plugins = listRegisteredPlugins({ dataDir });
45
+ } catch {
46
+ return [];
47
+ }
48
+ const entries = [];
49
+ for (const plugin of plugins || []) {
50
+ const root = String(plugin?.root || '').trim();
51
+ if (!root || !existsSync(root)) continue;
52
+ const id = cleanHookId(plugin.id || plugin.name || plugin.title || root.split(/[\\/]/).pop());
53
+ const pluginData = join(dataDir, 'plugins', 'data', id || 'plugin');
54
+ entries.push({
55
+ path: join(root, 'hooks', 'hooks.json'),
56
+ pluginRoot: root,
57
+ pluginData,
58
+ sourceType: 'plugin',
59
+ });
60
+ entries.push({
61
+ path: join(root, '.mixdog', 'hooks.json'),
62
+ pluginRoot: root,
63
+ pluginData,
64
+ sourceType: 'plugin',
65
+ });
66
+ }
67
+ return entries;
68
+ }
69
+
70
+ export function hookConfigEntries(dataDir, cwd) {
71
+ if (process.env.MIXDOG_HOOKS_FILE) {
72
+ return uniqueHookEntries([{ path: process.env.MIXDOG_HOOKS_FILE, sourceType: 'env' }]);
73
+ }
74
+ const projectDir = cwd ? resolve(cwd) : process.cwd();
75
+ return uniqueHookEntries([
76
+ projectDir ? { path: join(projectDir, '.mixdog', 'hooks.json'), sourceType: 'project' } : null,
77
+ projectDir ? { path: join(projectDir, '.mixdog', 'hooks', 'hooks.json'), sourceType: 'project' } : null,
78
+ dataDir ? { path: join(dataDir, 'hooks.json'), sourceType: 'data' } : null,
79
+ dataDir ? { path: join(dataDir, 'hooks', 'hooks.json'), sourceType: 'data' } : null,
80
+ ...pluginHookConfigEntries(dataDir),
81
+ ]);
82
+ }
83
+
84
+ export function isStandardConfig(parsed) {
85
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return false;
86
+ const hooks = parsed.hooks;
87
+ if (!hooks || typeof hooks !== 'object' || Array.isArray(hooks)) return false;
88
+ const values = Object.values(hooks);
89
+ if (values.length === 0) return false;
90
+ return values.every((groups) => (
91
+ Array.isArray(groups)
92
+ && groups.every((g) => g && typeof g === 'object' && Array.isArray(g.hooks))
93
+ ));
94
+ }
95
+
96
+ const SIMPLE_MATCHER_RE = /^[A-Za-z0-9_ ,|]*$/;
97
+ export function matcherFires(matcher, field) {
98
+ if (matcher == null) return true;
99
+ const text = String(matcher).trim();
100
+ if (text === '' || text === '*') return true;
101
+ const value = String(field ?? '');
102
+ if (SIMPLE_MATCHER_RE.test(text)) {
103
+ const items = text.split(/[|,]/).map((s) => s.trim()).filter(Boolean);
104
+ if (items.length === 0) return true;
105
+ return items.includes(value);
106
+ }
107
+ try {
108
+ return new RegExp(text).test(value);
109
+ } catch {
110
+ return true;
111
+ }
112
+ }
113
+
114
+ export function parseStandardConfig(parsed, source, meta = {}) {
115
+ const events = {};
116
+ const hooks = parsed.hooks || {};
117
+ for (const [eventName, groups] of Object.entries(hooks)) {
118
+ if (!Array.isArray(groups)) continue;
119
+ const cleanGroups = [];
120
+ for (const group of groups) {
121
+ if (!group || typeof group !== 'object') continue;
122
+ const handlers = Array.isArray(group.hooks)
123
+ ? group.hooks
124
+ .filter((h) => h && typeof h === 'object' && h.type)
125
+ .map((h) => ({
126
+ ...h,
127
+ _source: source,
128
+ ...(meta.pluginRoot ? { _pluginRoot: meta.pluginRoot } : {}),
129
+ ...(meta.pluginData ? { _pluginData: meta.pluginData } : {}),
130
+ }))
131
+ : [];
132
+ if (handlers.length === 0) continue;
133
+ cleanGroups.push({ matcher: group.matcher, hooks: handlers, _source: source });
134
+ }
135
+ if (cleanGroups.length > 0) events[eventName] = cleanGroups;
136
+ }
137
+ return events;
138
+ }
139
+
140
+ export function mergeEvents(target, source) {
141
+ for (const [eventName, groups] of Object.entries(source || {})) {
142
+ if (!Array.isArray(target[eventName])) target[eventName] = [];
143
+ target[eventName].push(...groups);
144
+ }
145
+ }
146
+
147
+ export function buildEventPayload(eventName, input = {}) {
148
+ const payload = {
149
+ session_id: input.sessionId ?? input.session_id ?? null,
150
+ cwd: input.cwd ?? null,
151
+ hook_event_name: eventName,
152
+ };
153
+ if (input.transcriptPath != null || input.transcript_path != null) {
154
+ payload.transcript_path = input.transcriptPath ?? input.transcript_path;
155
+ }
156
+ if (input.permissionMode != null || input.permission_mode != null) {
157
+ payload.permission_mode = input.permissionMode ?? input.permission_mode;
158
+ }
159
+ if (input.effort != null) payload.effort = input.effort;
160
+ const toolName = input.name ?? input.tool_name;
161
+ if (toolName != null) payload.tool_name = toolName;
162
+ const toolInput = input.args ?? input.tool_input;
163
+ if (toolInput != null) payload.tool_input = toolInput;
164
+ if (input.toolCallId != null || input.tool_use_id != null) {
165
+ payload.tool_use_id = input.toolCallId ?? input.tool_use_id;
166
+ }
167
+ if (input.toolResponse != null || input.tool_response != null || input.result != null) {
168
+ payload.tool_response = input.toolResponse ?? input.tool_response ?? input.result;
169
+ }
170
+ for (const key of [
171
+ 'prompt',
172
+ 'source',
173
+ 'model',
174
+ 'session_title',
175
+ 'message',
176
+ 'notification_type',
177
+ 'trigger',
178
+ 'load_reason',
179
+ 'file_path',
180
+ 'memory_type',
181
+ 'command_name',
182
+ 'command_args',
183
+ 'command_source',
184
+ 'expansion_type',
185
+ 'stop_reason',
186
+ 'error_type',
187
+ 'agent_type',
188
+ ]) {
189
+ if (input[key] != null) payload[key] = input[key];
190
+ }
191
+ return payload;
192
+ }
193
+
194
+ export function matchFieldFor(eventName, payload) {
195
+ if (NO_MATCHER_EVENTS.has(eventName)) return null;
196
+ if (eventName === 'SessionStart') return payload.source ?? '';
197
+ if (eventName === 'Setup') return payload.trigger ?? '';
198
+ if (eventName === 'SessionEnd') return payload.reason ?? '';
199
+ if (eventName === 'Notification') return payload.notification_type ?? payload.type ?? '';
200
+ if (eventName === 'SubagentStart' || eventName === 'SubagentStop') return payload.agent_type ?? '';
201
+ if (eventName === 'PreCompact' || eventName === 'PostCompact') return payload.trigger ?? '';
202
+ if (eventName === 'ConfigChange') return payload.source ?? '';
203
+ if (eventName === 'InstructionsLoaded') return payload.load_reason ?? '';
204
+ if (eventName === 'UserPromptExpansion') return payload.command_name ?? '';
205
+ if (eventName === 'StopFailure') return payload.error_type ?? '';
206
+ return payload.tool_name ?? '';
207
+ }
@@ -0,0 +1,90 @@
1
+ export const DEFAULT_EVENTS = Object.freeze([
2
+ 'runtime:start',
3
+ 'session:create',
4
+ 'turn:start',
5
+ 'turn:end',
6
+ 'turn:error',
7
+ 'tool:planned',
8
+ 'tool:before',
9
+ 'tool:ask',
10
+ 'tool:deny',
11
+ 'tool:modify',
12
+ 'hook:error',
13
+ 'SessionStart',
14
+ 'UserPromptSubmit',
15
+ 'PreToolUse',
16
+ 'PostToolUse',
17
+ 'Stop',
18
+ ]);
19
+
20
+ export const DEFAULT_COMMAND_TIMEOUT_S = 600;
21
+ export const USER_PROMPT_TIMEOUT_S = 30;
22
+ export const MESSAGE_DISPLAY_TIMEOUT_S = 10;
23
+ export const DEFAULT_PROMPT_TIMEOUT_S = 30;
24
+ export const DEFAULT_AGENT_TIMEOUT_S = 60;
25
+ export const MAX_OUTPUT_CHARS = 10_000;
26
+ export const MAX_BUFFER_BYTES = 10 * 1024 * 1024;
27
+
28
+ export const TOOL_IF_EVENTS = new Set([
29
+ 'PreToolUse',
30
+ 'PostToolUse',
31
+ 'PostToolUseFailure',
32
+ 'PermissionRequest',
33
+ 'PermissionDenied',
34
+ ]);
35
+
36
+ export const NO_MATCHER_EVENTS = new Set([
37
+ 'UserPromptSubmit',
38
+ 'PostToolBatch',
39
+ 'Stop',
40
+ 'TeammateIdle',
41
+ 'TaskCreated',
42
+ 'TaskCompleted',
43
+ 'WorktreeCreate',
44
+ 'WorktreeRemove',
45
+ 'CwdChanged',
46
+ 'MessageDisplay',
47
+ ]);
48
+
49
+ export const EXIT2_BLOCK_EVENTS = new Set([
50
+ 'PreToolUse',
51
+ 'PermissionRequest',
52
+ 'UserPromptSubmit',
53
+ 'UserPromptExpansion',
54
+ 'Stop',
55
+ 'SubagentStop',
56
+ 'TeammateIdle',
57
+ 'TaskCreated',
58
+ 'TaskCompleted',
59
+ 'ConfigChange',
60
+ 'PostToolBatch',
61
+ 'PreCompact',
62
+ 'Elicitation',
63
+ 'ElicitationResult',
64
+ ]);
65
+
66
+ export const TOP_LEVEL_DECISION_EVENTS = new Set([
67
+ 'UserPromptSubmit',
68
+ 'UserPromptExpansion',
69
+ 'PostToolUse',
70
+ 'PostToolUseFailure',
71
+ 'PostToolBatch',
72
+ 'Stop',
73
+ 'SubagentStop',
74
+ 'ConfigChange',
75
+ 'PreCompact',
76
+ ]);
77
+
78
+ export const PLAIN_STDOUT_CONTEXT_EVENTS = new Set([
79
+ 'SessionStart',
80
+ 'UserPromptSubmit',
81
+ 'UserPromptExpansion',
82
+ ]);
83
+
84
+ export const SUPPORTED_HANDLER_TYPES = new Set(['command', 'http', 'mcp_tool', 'prompt']);
85
+
86
+ export function limitText(text) {
87
+ const value = String(text || '');
88
+ if (value.length <= MAX_OUTPUT_CHARS) return value;
89
+ return `${value.slice(0, MAX_OUTPUT_CHARS)}\n... [hook output truncated; original ${value.length} chars]`;
90
+ }