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,82 @@
1
+ // Message classification, protected-context splitting, and summary-message
2
+ // construction helpers. Extracted verbatim from compact.mjs
3
+ // (behavior-preserving).
4
+ import { SUMMARY_PREFIX } from './constants.mjs';
5
+ import { sha16, roleCounts } from './text-utils.mjs';
6
+
7
+ export function compactHeader(oldHistory) {
8
+ const encoded = JSON.stringify(oldHistory ?? []);
9
+ return [
10
+ SUMMARY_PREFIX,
11
+ `messages=${oldHistory.length} sha256=${sha16(encoded)} roles=${roleCounts(oldHistory) || 'none'}`,
12
+ ];
13
+ }
14
+
15
+ export function makeSummaryMessage(content) {
16
+ return { role: 'user', content };
17
+ }
18
+
19
+ // A compact summary message is a synthetic role:'user' message carrying the
20
+ // SUMMARY_PREFIX anchor. It is NOT a real user turn: it must be excluded from
21
+ // real user-turn boundary calculations and treated as merge input, otherwise
22
+ // an old summary can sit in the preserved tail as a live user message,
23
+ // duplicate, or fail to merge across repeated compaction.
24
+ export function isSummaryMessage(m) {
25
+ return m?.role === 'user'
26
+ && typeof m.content === 'string'
27
+ && m.content.startsWith(SUMMARY_PREFIX);
28
+ }
29
+
30
+ export function isProtectedContextUserMessage(m) {
31
+ if (m?.role !== 'user' || typeof m.content !== 'string') return false;
32
+ return m.content.trimStart().startsWith('<system-reminder>');
33
+ }
34
+
35
+ // An injected Skill-body user message (the general newMessages channel carries
36
+ // the full SKILL.md body as a role:'user' message after the Skill tool_result).
37
+ // Like isSummaryMessage / isProtectedContextUserMessage, it is detected by
38
+ // content prefix (the `<skill>` envelope from buildSkillResultEnvelope) so the
39
+ // check survives even if the synthetic `meta` field is dropped during a tail
40
+ // rebuild. It is NOT the human's latest prompt and must be excluded from
41
+ // "latest human request" selection (deriveCurrentRequest /
42
+ // buildRecallFastTrackQuery). The `meta:'skill'` marker is also honoured.
43
+ export function isInjectedSkillBodyMessage(m) {
44
+ if (m?.role !== 'user') return false;
45
+ if (m.meta === 'skill') return true;
46
+ return typeof m.content === 'string' && m.content.trimStart().startsWith('<skill>');
47
+ }
48
+
49
+ export function isProtectedContextAckMessage(m) {
50
+ return m?.role === 'assistant'
51
+ && typeof m.content === 'string'
52
+ && m.content.trim() === '.'
53
+ && !Array.isArray(m.toolCalls);
54
+ }
55
+
56
+ export function splitProtectedContext(messages) {
57
+ const protectedPrefix = [];
58
+ const conversation = [];
59
+ let prefixMode = true;
60
+ let previousWasProtectedContext = false;
61
+ for (const m of messages || []) {
62
+ if (m?.role === 'system') {
63
+ protectedPrefix.push(m);
64
+ previousWasProtectedContext = false;
65
+ continue;
66
+ }
67
+ if (prefixMode && isProtectedContextUserMessage(m)) {
68
+ protectedPrefix.push(m);
69
+ previousWasProtectedContext = true;
70
+ continue;
71
+ }
72
+ if (prefixMode && previousWasProtectedContext && isProtectedContextAckMessage(m)) {
73
+ protectedPrefix.push(m);
74
+ previousWasProtectedContext = false;
75
+ continue;
76
+ }
77
+ prefixMode = false;
78
+ previousWasProtectedContext = false;
79
+ conversation.push(m);
80
+ }
81
+ return { protectedPrefix, conversation };
82
+ }
@@ -0,0 +1,315 @@
1
+ // Semantic-summary schema machinery: required-section anchors, heading
2
+ // matching, schema validation, deterministic repair/backfill, minimal
3
+ // schema-valid scaffold, and section-aware truncation. Extracted verbatim
4
+ // from summary.mjs (behavior-preserving) — summary.mjs re-exports the
5
+ // public entry points so the compact/ facade surface is unchanged.
6
+ import {
7
+ extractText,
8
+ truncateMiddle,
9
+ } from './text-utils.mjs';
10
+ import {
11
+ isProtectedContextUserMessage,
12
+ isInjectedSkillBodyMessage,
13
+ } from './messages.mjs';
14
+
15
+ // Canonical section anchors the semantic summary template (SUMMARY_TEMPLATE)
16
+ // must contain. Used for lightweight schema validation of provider output.
17
+ const REQUIRED_SUMMARY_SECTIONS = Object.freeze([
18
+ '## Goal',
19
+ '## Constraints',
20
+ '## Progress',
21
+ '## Key Decisions',
22
+ '## Next Steps',
23
+ '## Critical Context',
24
+ '## Relevant Files',
25
+ ]);
26
+
27
+ // Collect actual top-level (`## `, not `### `) heading lines from a summary.
28
+ // Validation is heading-anchor based (not substring includes) so prose or code
29
+ // that merely mentions "## Relevant Files" inside a bullet body cannot satisfy
30
+ // a section anchor.
31
+ function summaryHeadingLines(summary) {
32
+ const out = [];
33
+ let inFence = false;
34
+ for (const rawLine of String(summary || '').split('\n')) {
35
+ const line = rawLine.trim();
36
+ if (/^(?:```|~~~)/.test(line)) { inFence = !inFence; continue; }
37
+ if (inFence) continue;
38
+ if (/^##\s+\S/.test(line) && !/^###\s+/.test(line)) out.push(line);
39
+ }
40
+ return out;
41
+ }
42
+
43
+ // An anchor matches a heading when the heading title equals the anchor title or
44
+ // extends it at a word/punctuation boundary. This lets `## Constraints &
45
+ // Preferences` satisfy the `## Constraints` anchor while NOT letting an
46
+ // unrelated `## Goalkeeper` heading satisfy `## Goal`. Requires a real `## `
47
+ // heading line (not a substring buried in prose).
48
+ export function headingMatchesAnchor(heading, anchor) {
49
+ const anchorTitle = anchor.replace(/^##\s+/, '').trim().toLowerCase();
50
+ const headingTitle = heading.replace(/^##\s+/, '').trim().toLowerCase();
51
+ if (headingTitle === anchorTitle) return true;
52
+ if (!headingTitle.startsWith(anchorTitle)) return false;
53
+ // Next char after the anchor title must be a boundary (space or &/punct),
54
+ // not a continuation letter/digit.
55
+ const nextChar = headingTitle.charAt(anchorTitle.length);
56
+ return /[\s&:(-]/.test(nextChar);
57
+ }
58
+
59
+ function summarySchemaScore(summary) {
60
+ const headings = summaryHeadingLines(summary);
61
+ let hits = 0;
62
+ for (const anchor of REQUIRED_SUMMARY_SECTIONS) {
63
+ if (headings.some((h) => headingMatchesAnchor(h, anchor))) hits += 1;
64
+ }
65
+ return hits;
66
+ }
67
+
68
+ // A summary is schema-valid only when EVERY required section anchor is present
69
+ // as a real heading. A partial summary (e.g. missing Critical Context /
70
+ // Relevant Files) must be repaired rather than injected unchanged.
71
+ export function summaryIsSchemaValid(summary) {
72
+ if (summarySchemaScore(summary) !== REQUIRED_SUMMARY_SECTIONS.length) return false;
73
+ return !summaryHasUnrecognizedHeadings(summary);
74
+ }
75
+
76
+ function deriveRelevantFilesBullets(head) {
77
+ const seen = new Set();
78
+ const out = [];
79
+ const fileRe = /(?:[A-Za-z]:[\\/]|\.{1,2}[\\/]|[\w$.-]+[\\/])?[\w$.-]+\.(?:mjs|cjs|js|jsx|ts|tsx|json|md|rs|go|py|java|kt|cs|cpp|c|h|hpp|css|html|yml|yaml|toml|lock|sh|ps1)\b/gi;
80
+ for (const m of Array.isArray(head) ? head : []) {
81
+ const text = extractText(m);
82
+ if (!text) continue;
83
+ let match;
84
+ while ((match = fileRe.exec(text)) && out.length < 8) {
85
+ const file = match[0];
86
+ const key = file.toLowerCase();
87
+ if (seen.has(key)) continue;
88
+ seen.add(key);
89
+ out.push(`- ${file}`);
90
+ }
91
+ if (out.length >= 8) break;
92
+ }
93
+ return out;
94
+ }
95
+
96
+ function deriveCurrentRequest(messages) {
97
+ for (let i = (Array.isArray(messages) ? messages.length : 0) - 1; i >= 0; i -= 1) {
98
+ const m = messages[i];
99
+ if (m?.role === 'user' && !isProtectedContextUserMessage(m) && !isInjectedSkillBodyMessage(m)) {
100
+ const text = truncateMiddle(extractText(m).trim(), 400);
101
+ if (text) return text;
102
+ }
103
+ }
104
+ return '';
105
+ }
106
+
107
+ // Canonical ordered section headings the structured summary scaffold emits.
108
+ // Each `## ` heading maps to one REQUIRED_SUMMARY_SECTIONS anchor; Progress
109
+ // additionally carries its three `### ` sub-headings.
110
+ const SUMMARY_SECTION_LAYOUT = Object.freeze([
111
+ { heading: '## Goal', anchor: '## Goal' },
112
+ { heading: '## Constraints & Preferences', anchor: '## Constraints' },
113
+ { heading: '## Progress', anchor: '## Progress', sub: ['### Done', '### In Progress', '### Blocked'] },
114
+ { heading: '## Key Decisions', anchor: '## Key Decisions' },
115
+ { heading: '## Next Steps', anchor: '## Next Steps' },
116
+ { heading: '## Critical Context', anchor: '## Critical Context' },
117
+ { heading: '## Relevant Files', anchor: '## Relevant Files' },
118
+ ]);
119
+
120
+ // Split a markdown summary into a map of top-level `## ` heading -> body lines.
121
+ function parseSummarySections(text) {
122
+ const map = new Map();
123
+ let current = null;
124
+ let inFence = false;
125
+ for (const rawLine of String(text || '').split('\n')) {
126
+ const trimmed = rawLine.trim();
127
+ const line = rawLine.replace(/\s+$/, '');
128
+ if (/^(?:```|~~~)/.test(trimmed)) {
129
+ inFence = !inFence;
130
+ if (current) map.get(current).push(line);
131
+ continue;
132
+ }
133
+ if (!inFence && /^##\s+/.test(trimmed) && !/^###\s+/.test(trimmed)) {
134
+ current = trimmed;
135
+ if (!map.has(current)) map.set(current, []);
136
+ continue;
137
+ }
138
+ if (current) map.get(current).push(line);
139
+ }
140
+ return map;
141
+ }
142
+
143
+ function summarySectionIsRecognized(heading) {
144
+ for (const section of SUMMARY_SECTION_LAYOUT) {
145
+ if (headingMatchesAnchor(heading, section.anchor)) return true;
146
+ }
147
+ return false;
148
+ }
149
+
150
+ export function summaryHasUnrecognizedHeadings(summary) {
151
+ for (const heading of parseSummarySections(summary).keys()) {
152
+ if (!summarySectionIsRecognized(heading)) return true;
153
+ }
154
+ return false;
155
+ }
156
+
157
+ function summaryLinesToBullets(text) {
158
+ return String(text || '')
159
+ .split('\n')
160
+ .map((l) => l.trim())
161
+ .filter(Boolean)
162
+ .map((l) => (l.startsWith('-') ? l : `- ${l}`));
163
+ }
164
+
165
+ function unrecognizedSummarySectionText(present) {
166
+ const chunks = [];
167
+ for (const [heading, body] of present) {
168
+ if (summarySectionIsRecognized(heading)) continue;
169
+ const lines = [heading];
170
+ for (const line of body || []) {
171
+ const trimmed = String(line).trim();
172
+ if (trimmed) lines.push(line);
173
+ }
174
+ chunks.push(lines.join('\n'));
175
+ }
176
+ return chunks.join('\n\n').trim();
177
+ }
178
+
179
+ // Deterministic schema repair for a non-empty but malformed/partial semantic
180
+ // summary. Preserve every section the provider DID supply (matched by anchor),
181
+ // and scaffold the missing required sections so downstream consumers always
182
+ // receive the full structured anchored shape. Content that lives outside any
183
+ // recognized section is routed into Critical Context so nothing is dropped.
184
+ // Lightly backfill Goal / Relevant Files from the transcript when empty.
185
+ export function repairSemanticSummary(summary, { head = [], tail = [] } = {}) {
186
+ const raw = String(summary || '').trim();
187
+ const present = parseSummarySections(raw);
188
+ // Capture any leading content before the first recognized `## ` heading so
189
+ // an entirely unstructured blob is preserved rather than silently dropped.
190
+ let preamble = '';
191
+ if (raw) {
192
+ const firstHeading = raw.search(/(^|\n)\s*##\s+/);
193
+ preamble = firstHeading === -1 ? raw : raw.slice(0, firstHeading);
194
+ preamble = preamble.trim();
195
+ }
196
+ const orphanText = unrecognizedSummarySectionText(present);
197
+ const extraContextParts = [];
198
+ if (preamble) extraContextParts.push(preamble);
199
+ if (orphanText) extraContextParts.push(orphanText);
200
+ const extraContext = extraContextParts.join('\n\n').trim();
201
+ const bulletize = (lines) => {
202
+ const cleaned = (Array.isArray(lines) ? lines : [])
203
+ .map((l) => String(l).trim())
204
+ .filter(Boolean);
205
+ return cleaned.length ? cleaned : null;
206
+ };
207
+ const findPresent = (anchor) => {
208
+ let found = null;
209
+ for (const [heading, body] of present) {
210
+ if (headingMatchesAnchor(heading, anchor)) {
211
+ if (!found) found = [];
212
+ found.push(...(body || []));
213
+ }
214
+ }
215
+ return found;
216
+ };
217
+ const goal = deriveCurrentRequest(tail) || deriveCurrentRequest(head);
218
+ const files = deriveRelevantFilesBullets(head);
219
+ const out = [];
220
+ for (const section of SUMMARY_SECTION_LAYOUT) {
221
+ if (out.length) out.push('');
222
+ out.push(section.heading);
223
+ const body = bulletize(findPresent(section.anchor));
224
+ if (section.sub) {
225
+ // Progress: keep provider sub-bodies when present, else scaffold.
226
+ if (body) {
227
+ out.push(...body);
228
+ } else {
229
+ for (const sub of section.sub) {
230
+ out.push(sub, '- (none)');
231
+ }
232
+ }
233
+ continue;
234
+ }
235
+ if (section.anchor === '## Critical Context') {
236
+ const ccLines = [];
237
+ if (body) ccLines.push(...body);
238
+ for (const line of summaryLinesToBullets(extraContext)) {
239
+ if (!ccLines.some((existing) => existing.trim() === line.trim())) ccLines.push(line);
240
+ }
241
+ if (ccLines.some((line) => line.trim() !== '- (none)')) {
242
+ const withoutPlaceholder = ccLines.filter((line) => line.trim() !== '- (none)');
243
+ out.push(...(withoutPlaceholder.length ? withoutPlaceholder : ccLines));
244
+ } else {
245
+ out.push(...(ccLines.length ? ccLines : ['- (none)']));
246
+ }
247
+ continue;
248
+ }
249
+ if (body) {
250
+ out.push(...body);
251
+ continue;
252
+ }
253
+ if (section.anchor === '## Goal') {
254
+ out.push(goal ? `- ${goal}` : '- (none)');
255
+ } else if (section.anchor === '## Relevant Files') {
256
+ out.push(...(files.length ? files : ['- (none)']));
257
+ } else {
258
+ out.push('- (none)');
259
+ }
260
+ }
261
+ return out.join('\n');
262
+ }
263
+
264
+ // A headings-only structured summary: every required `## ` (and Progress `### `)
265
+ // anchor present with `- (none)` bodies. This is the minimal schema-valid shape
266
+ // the fitter can fall back to when token pressure cannot hold real section
267
+ // bodies — it still passes summaryIsSchemaValid so the injected message is
268
+ // never partial.
269
+ export function minimalSchemaSummary() {
270
+ const out = [];
271
+ for (const section of SUMMARY_SECTION_LAYOUT) {
272
+ if (out.length) out.push('');
273
+ out.push(section.heading);
274
+ if (section.sub) {
275
+ for (const sub of section.sub) out.push(sub, '- (none)');
276
+ } else {
277
+ out.push('- (none)');
278
+ }
279
+ }
280
+ return out.join('\n');
281
+ }
282
+
283
+ // Section-aware truncation: keep EVERY `## ` heading and Progress `### `
284
+ // sub-heading intact, trimming only section bodies to `perSectionChars`. Unlike
285
+ // a raw text.slice(0, n) this never drops a trailing required section, so the
286
+ // result stays schema-valid (all anchors present) at any budget.
287
+ export function truncateSummaryBySections(summary, perSectionChars) {
288
+ const sections = parseSummarySections(summary);
289
+ const out = [];
290
+ for (const section of SUMMARY_SECTION_LAYOUT) {
291
+ if (out.length) out.push('');
292
+ out.push(section.heading);
293
+ let body = null;
294
+ for (const [heading, lines] of sections) {
295
+ if (headingMatchesAnchor(heading, section.anchor)) {
296
+ if (!body) body = [];
297
+ body.push(...(lines || []));
298
+ }
299
+ }
300
+ const bodyText = (Array.isArray(body) ? body : [])
301
+ .map((l) => String(l).trim())
302
+ .filter(Boolean)
303
+ .join('\n');
304
+ if (!bodyText) {
305
+ if (section.sub) for (const sub of section.sub) out.push(sub, '- (none)');
306
+ else out.push('- (none)');
307
+ continue;
308
+ }
309
+ const trimmed = perSectionChars > 0 ? truncateMiddle(bodyText, perSectionChars) : '';
310
+ if (trimmed) out.push(trimmed);
311
+ else if (section.sub) for (const sub of section.sub) out.push(sub, '- (none)');
312
+ else out.push('- (none)');
313
+ }
314
+ return out.join('\n');
315
+ }