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
@@ -0,0 +1,324 @@
1
+ // Entry-mutation + phase_merge cluster extracted from memory-cycle2.mjs.
2
+ // DB status/update/merge writers plus the cosine-similarity dedup pass.
3
+ // Facade (memory-cycle2.mjs) re-exports the public members unchanged.
4
+ import { deleteRootEmbedding, syncRootEmbedding } from './memory-embed.mjs'
5
+ import { callAgentDispatch } from './agent-ipc.mjs'
6
+ import { __mixdogMemoryLog, throwIfAborted } from './memory-cycle2-shared.mjs'
7
+
8
+ const TIER1_THRESHOLD = 0.78
9
+ const TIER2_LOW = 0.65
10
+ const LLM_JUDGE_CAP = 20
11
+
12
+ // Batch CTE UPDATE for status-only verdicts (active/archived from pending or active rows).
13
+ // Trigger handles score recompute automatically — no app-side score writes.
14
+ export async function applyBatchStatusVerdicts(db, batch, nowMs) {
15
+ if (!batch || batch.length === 0) return { promoted: 0, archived: 0 }
16
+ const valueRows = batch.map((item, i) => {
17
+ const base = i * 3
18
+ return `($${base + 1}::bigint, $${base + 2}::text, $${base + 3}::boolean)`
19
+ })
20
+ const params = []
21
+ for (const item of batch) {
22
+ params.push(item.entry_id, item.new_status, item.was_pending)
23
+ }
24
+ params.push(nowMs)
25
+ const lastParam = `$${params.length}`
26
+ const res = await db.query(
27
+ `WITH actions(entry_id, new_status, was_pending) AS (
28
+ VALUES ${valueRows.join(', ')}
29
+ )
30
+ UPDATE entries
31
+ SET status = a.new_status::entry_status,
32
+ last_seen_at = ${lastParam},
33
+ promoted_at = CASE
34
+ WHEN a.was_pending AND a.new_status = 'active' THEN ${lastParam}
35
+ ELSE promoted_at
36
+ END
37
+ FROM actions a
38
+ WHERE entries.id = a.entry_id AND entries.is_root = 1
39
+ RETURNING entries.id, entries.status, a.was_pending, a.new_status`,
40
+ params,
41
+ )
42
+ let promoted = 0
43
+ let archived = 0
44
+ for (const r of (res.rows ?? [])) {
45
+ if (r.was_pending && r.new_status === 'active') promoted += 1
46
+ else if (r.new_status === 'archived') archived += 1
47
+ }
48
+ return { promoted, archived }
49
+ }
50
+
51
+ // Generic status update for archived/active terminal transitions.
52
+ export async function applySimpleStatus(db, entryId, nextStatus) {
53
+ const res = await db.query(
54
+ `UPDATE entries SET status = $1 WHERE id = $2 AND is_root = 1`,
55
+ [nextStatus, entryId],
56
+ )
57
+ return Number(res.rowCount ?? res.affectedRows ?? 0) > 0
58
+ }
59
+
60
+ export async function applyUpdate(db, entryId, element, summary, options = {}) {
61
+ const setClauses = []
62
+ const params = []
63
+ let paramIdx = 1
64
+ const newElement = (typeof element === 'string' && element.trim()) ? element.trim() : null
65
+ const newSummary = (typeof summary === 'string' && summary.trim()) ? summary.trim() : null
66
+ if (newElement) {
67
+ setClauses.push(`element = $${paramIdx++}`); params.push(newElement)
68
+ }
69
+ if (newSummary) {
70
+ setClauses.push(`summary = $${paramIdx++}`); params.push(newSummary)
71
+ setClauses.push('summary_hash = NULL')
72
+ }
73
+ if (setClauses.length === 0) return false
74
+ params.push(entryId)
75
+ const res = await db.query(
76
+ `UPDATE entries SET ${setClauses.join(', ')} WHERE id = $${paramIdx} AND is_root = 1`,
77
+ params,
78
+ )
79
+ if (Number(res.rowCount ?? res.affectedRows ?? 0) === 0) return false
80
+ await syncRootEmbedding(db, entryId, options)
81
+ return true
82
+ }
83
+
84
+ export async function applyMerge(db, targetId, sourceIds, options = {}) {
85
+ const signal = options?.signal
86
+ throwIfAborted(signal)
87
+ if (!Number.isFinite(targetId)) return 0
88
+ const targetRes = await db.query(
89
+ `SELECT id, project_id FROM entries WHERE id = $1 AND is_root = 1`,
90
+ [targetId],
91
+ )
92
+ throwIfAborted(signal)
93
+ const target = targetRes.rows[0]
94
+ if (!target) return 0
95
+ let moved = 0
96
+ for (const src of sourceIds) {
97
+ throwIfAborted(signal)
98
+ const sid = Number(src)
99
+ if (!Number.isFinite(sid) || sid === targetId) continue
100
+ const srcRes = await db.query(
101
+ `SELECT id, project_id, status FROM entries WHERE id = $1 AND is_root = 1`,
102
+ [sid],
103
+ )
104
+ throwIfAborted(signal)
105
+ const srcRow = srcRes.rows[0]
106
+ if (!srcRow) continue
107
+ if (target.project_id !== srcRow.project_id) {
108
+ __mixdogMemoryLog(
109
+ `[cycle2] merge rejected: cross-pool (target=${targetId} project_id=${target.project_id ?? 'COMMON'} src=${sid} project_id=${srcRow.project_id ?? 'COMMON'})\n`,
110
+ )
111
+ continue
112
+ }
113
+ try {
114
+ // One source merge is the mutation unit: DB reassignment/archive plus
115
+ // embedding cleanup. The next abort checkpoint is before the next source.
116
+ await db.transaction(async (tx) => {
117
+ await tx.query(
118
+ `UPDATE entries SET chunk_root = $1, project_id = $2 WHERE chunk_root = $3 AND id != $4 AND is_root = 0`,
119
+ [targetId, target.project_id, sid, sid],
120
+ )
121
+ await tx.query(
122
+ `UPDATE entries SET status = 'archived' WHERE id = $1 AND is_root = 1`,
123
+ [sid],
124
+ )
125
+ })
126
+ await deleteRootEmbedding(db, sid)
127
+ moved += 1
128
+ } catch (err) {
129
+ __mixdogMemoryLog(`[cycle2] merge failed (target=${targetId} src=${sid}): ${err.message}\n`)
130
+ }
131
+ }
132
+ return moved
133
+ }
134
+
135
+ // ─── phase_merge: cosine-similarity dedup pass ───────────────────────────────
136
+
137
+ function _pickKeeper(a, b) {
138
+ if ((a.score ?? 0) !== (b.score ?? 0)) return (a.score ?? 0) > (b.score ?? 0) ? a : b
139
+ if ((a.last_seen_at ?? 0) !== (b.last_seen_at ?? 0)) return (a.last_seen_at ?? 0) > (b.last_seen_at ?? 0) ? a : b
140
+ return a.id < b.id ? a : b
141
+ }
142
+
143
+ async function _llmJudgePair(summaryA, summaryB, siblingContext = [], options = {}) {
144
+ const signal = options?.signal
145
+ throwIfAborted(signal)
146
+ const llmCall = typeof options?.callLlm === 'function' ? options.callLlm : callAgentDispatch
147
+ const siblings = Array.isArray(siblingContext) && siblingContext.length > 0
148
+ ? `\n\nSibling near-matches (recall context only — do not absorb these into the verdict):\n${siblingContext.slice(0, 5).map((p, i) => `${i + 1}. ${String(p.a?.summary ?? '')} ↔ ${String(p.b?.summary ?? '')}`).join('\n')}`
149
+ : ''
150
+ const prompt =
151
+ `Two memory entries below. Are they restating the same principle? Reply ONE WORD: merge or distinct.\n\nA: ${summaryA}\nB: ${summaryB}${siblings}`
152
+ try {
153
+ const raw = await llmCall({
154
+ agent: 'cycle2-agent',
155
+ taskType: 'maintenance',
156
+ mode: 'cycle2-phase_merge_judge',
157
+ preset: 'HAIKU',
158
+ timeout: 30000,
159
+ cwd: null,
160
+ }, prompt)
161
+ throwIfAborted(signal)
162
+ return String(raw ?? '').trim().toLowerCase().startsWith('merge')
163
+ } catch (err) {
164
+ if (signal?.aborted) throw signal.reason ?? err
165
+ __mixdogMemoryLog(`[cycle2] phase_merge llm-judge error: ${err.message}\n`)
166
+ return false
167
+ }
168
+ }
169
+
170
+ export async function runPhaseMerge(db, options = {}) {
171
+ const signal = options?.signal
172
+ throwIfAborted(signal)
173
+ // PG-side lateral nearest-neighbor via HNSW index — replaces JS O(n²) double loop.
174
+ const pairRes = await db.query(
175
+ `WITH active AS (
176
+ SELECT id, category, summary, score, last_seen_at, status, embedding, project_id
177
+ FROM entries
178
+ WHERE is_root = 1 AND status = 'active' AND embedding IS NOT NULL
179
+ )
180
+ SELECT a.id AS a_id, a.category AS a_category, a.summary AS a_summary, a.score AS a_score, a.last_seen_at AS a_last_seen_at, a.status AS a_status,
181
+ b.id AS b_id, b.category AS b_category, b.summary AS b_summary, b.score AS b_score, b.last_seen_at AS b_last_seen_at, b.status AS b_status,
182
+ 1 - (a.embedding <=> b.embedding)::float8 AS sim
183
+ FROM active a
184
+ CROSS JOIN LATERAL (
185
+ SELECT id, category, summary, score, last_seen_at, status, embedding
186
+ FROM active inner_b
187
+ WHERE inner_b.id != a.id AND inner_b.category = a.category
188
+ AND inner_b.project_id IS NOT DISTINCT FROM a.project_id
189
+ ORDER BY inner_b.embedding <=> a.embedding
190
+ LIMIT 8
191
+ ) b
192
+ WHERE a.id < b.id
193
+ AND 1 - (a.embedding <=> b.embedding) >= $1
194
+ ORDER BY sim DESC`,
195
+ [TIER2_LOW],
196
+ )
197
+ throwIfAborted(signal)
198
+
199
+ const tier1Pairs = []
200
+ const tier2Pairs = []
201
+ for (const row of pairRes.rows) {
202
+ throwIfAborted(signal)
203
+ const a = { id: row.a_id, category: row.a_category, summary: row.a_summary, score: row.a_score, last_seen_at: row.a_last_seen_at, status: row.a_status }
204
+ const b = { id: row.b_id, category: row.b_category, summary: row.b_summary, score: row.b_score, last_seen_at: row.b_last_seen_at, status: row.b_status }
205
+ if (row.sim >= TIER1_THRESHOLD) tier1Pairs.push({ a, b, sim: row.sim })
206
+ else tier2Pairs.push({ a, b, sim: row.sim })
207
+ }
208
+
209
+ // No active/active similarity pairs is NOT a reason to skip the
210
+ // core_entries overlap sweep below — that pass archives active entries
211
+ // that restate a user-curated core row and is independent of intra-
212
+ // entry pairing. Falling through with merged=0 keeps the cross-table
213
+ // sweep running and the per-phase log shape intact.
214
+ let merged = 0
215
+ let llmCalls = 0
216
+ const mergedIds = new Set()
217
+
218
+ const doMerge = async (a, b, sim) => {
219
+ throwIfAborted(signal)
220
+ if (mergedIds.has(a.id) || mergedIds.has(b.id)) return
221
+ const keeper = _pickKeeper(a, b)
222
+ const loser = keeper.id === a.id ? b : a
223
+ const moved = await applyMerge(db, keeper.id, [loser.id], { signal })
224
+ if (moved > 0) {
225
+ merged += moved
226
+ mergedIds.add(loser.id)
227
+ __mixdogMemoryLog(
228
+ `[cycle2] phase_merge merged id=${loser.id} -> keeper=${keeper.id} category=${keeper.category} sim=${typeof sim === 'number' ? sim.toFixed(3) : '?'}\n`,
229
+ )
230
+ }
231
+ }
232
+
233
+ // Only tier1 pairs enter the LLM judge. Tier2 pairs (0.65 ≤ sim < 0.78)
234
+ // are recall context only — passed as sibling examples to the judge, never
235
+ // as judge input themselves, and never archived here.
236
+ for (const pair of tier1Pairs) {
237
+ throwIfAborted(signal)
238
+ if (llmCalls >= LLM_JUDGE_CAP) break
239
+ if (mergedIds.has(pair.a.id) || mergedIds.has(pair.b.id)) continue
240
+ llmCalls++
241
+ const shouldMerge = await _llmJudgePair(
242
+ String(pair.a.summary ?? ''),
243
+ String(pair.b.summary ?? ''),
244
+ tier2Pairs,
245
+ { signal },
246
+ )
247
+ throwIfAborted(signal)
248
+ if (shouldMerge) await doMerge(pair.a, pair.b, pair.sim)
249
+ }
250
+
251
+ // Cross-table sweep: surface every active entry whose embedding sits near
252
+ // a user-curated core_entries row (sim ≥ TIER2_LOW for broad recall) and
253
+ // ask the LLM whether the entry is a restatement of that user rule. Only
254
+ // the LLM verdict moves the entry to archived — embedding sim alone is
255
+ // never authoritative. Project-scoped core only matches the same pool;
256
+ // COMMON core is global and may absorb duplicate generated project memory.
257
+ throwIfAborted(signal)
258
+ const coreOverlapRes = await db.query(
259
+ `WITH active_e AS (
260
+ SELECT id, project_id, summary, embedding
261
+ FROM entries
262
+ WHERE is_root = 1 AND status = 'active' AND embedding IS NOT NULL
263
+ )
264
+ SELECT e.id AS entry_id, e.summary AS entry_summary, c.core_id, c.core_summary, c.sim
265
+ FROM active_e e
266
+ CROSS JOIN LATERAL (
267
+ SELECT inner_c.id AS core_id, inner_c.summary AS core_summary,
268
+ 1 - (e.embedding <=> inner_c.embedding)::float8 AS sim
269
+ FROM core_entries inner_c
270
+ WHERE inner_c.embedding IS NOT NULL
271
+ AND (inner_c.project_id IS NULL OR inner_c.project_id IS NOT DISTINCT FROM e.project_id)
272
+ ORDER BY
273
+ CASE WHEN inner_c.project_id IS NOT DISTINCT FROM e.project_id THEN 0 ELSE 1 END,
274
+ inner_c.embedding <=> e.embedding
275
+ LIMIT 1
276
+ ) c
277
+ WHERE c.sim >= $1`,
278
+ [TIER1_THRESHOLD],
279
+ )
280
+ throwIfAborted(signal)
281
+ let coreOverlap = 0
282
+ for (const row of coreOverlapRes.rows) {
283
+ throwIfAborted(signal)
284
+ if (llmCalls >= LLM_JUDGE_CAP) break
285
+ llmCalls++
286
+ const verdictMerge = await _llmJudgePair(
287
+ String(row.entry_summary ?? ''),
288
+ String(row.core_summary ?? ''),
289
+ [],
290
+ { signal },
291
+ )
292
+ throwIfAborted(signal)
293
+ if (!verdictMerge) continue
294
+ // Archiving one overlap and deleting its embedding is one mutation unit;
295
+ // cancellation resumes at the next row boundary.
296
+ const r = await db.query(
297
+ // Clear a live core-candidate flag on the same UPDATE: an archived root
298
+ // must not stay listed as a candidate or keep eating CANDIDATE_CAP. Set
299
+ // it to 'dismissed' (terminal) since the fact already restates a core row.
300
+ `UPDATE entries
301
+ SET status = 'archived',
302
+ core_candidate_status = CASE WHEN core_candidate_status = 'candidate' THEN 'dismissed' ELSE core_candidate_status END
303
+ WHERE id = $1 AND is_root = 1 AND status = 'active'`,
304
+ [Number(row.entry_id)],
305
+ )
306
+ if (Number(r.rowCount ?? r.affectedRows ?? 0) > 0) {
307
+ coreOverlap++
308
+ await deleteRootEmbedding(db, Number(row.entry_id))
309
+ }
310
+ }
311
+ throwIfAborted(signal)
312
+ if (coreOverlap > 0) {
313
+ __mixdogMemoryLog(
314
+ `[cycle2] phase_merge core_overlap archived=${coreOverlap} (LLM-judged restatements of user-curated core_entries)\n`,
315
+ )
316
+ }
317
+
318
+ __mixdogMemoryLog(
319
+ `[cycle2] phase_merge tier1_pairs=${tier1Pairs.length} tier2_pairs=${tier2Pairs.length}` +
320
+ ` llm_calls=${llmCalls} merged=${merged} core_overlap=${coreOverlap}\n`,
321
+ )
322
+
323
+ return { merged, llm_calls: llmCalls, tier1_pairs: tier1Pairs.length, tier2_pairs: tier2Pairs.length, core_overlap: coreOverlap }
324
+ }
@@ -0,0 +1,18 @@
1
+ // Shared low-level helpers for the cycle2 cluster (extracted from
2
+ // memory-cycle2.mjs). Logging shim, abort check, and resource-dir resolution.
3
+ // No cycle2 business logic; safe to import from any cycle2 sub-module.
4
+ import { fileURLToPath } from 'url'
5
+
6
+ const __mixdogMemoryStderrWrite = process.stderr.write.bind(process.stderr)
7
+ export function __mixdogMemoryLog(...args) {
8
+ if (process.env.MIXDOG_QUIET_MEMORY_LOG) return true
9
+ return __mixdogMemoryStderrWrite(...args)
10
+ }
11
+
12
+ export function throwIfAborted(signal) {
13
+ if (signal?.aborted) throw signal.reason ?? new Error('aborted')
14
+ }
15
+
16
+ export function resourceDir() {
17
+ return process.env.MIXDOG_ROOT || fileURLToPath(new URL('../../../..', import.meta.url))
18
+ }