mixdog 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -5,7 +5,7 @@ import {
5
5
  normalizeToolNotifyContext,
6
6
  notifyToolCompletion,
7
7
  } from './tool-execution-contract.mjs';
8
- import { presentErrorText } from './err-text.mjs';
8
+ import { presentErrorText, errorLine } from './err-text.mjs';
9
9
 
10
10
  export {
11
11
  TOOL_ASYNC_EXECUTION_CONTRACT,
@@ -465,8 +465,7 @@ export function renderBackgroundTask(taskOrId, { includeResult = false } = {}) {
465
465
  if (body) {
466
466
  lines.push('', body);
467
467
  } else if (TERMINAL_STATUSES.has(task.status) && task.error) {
468
- const errorText = String(task.error || '').trim();
469
- lines.push('', /^error\s*:/i.test(errorText) ? errorText : `Error: ${errorText}`);
468
+ lines.push('', errorLine(task.error, { surface: task.surface }));
470
469
  } else if (TERMINAL_STATUSES.has(task.status) && task.status === 'completed') {
471
470
  // Terminal-completed task with no extractable body: surface a placeholder
472
471
  // instead of silently omitting the result so the owner isn't left with a
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Per-file buffered append queue.
3
+ *
4
+ * Hot paths (transcript writer, channel worker stderr log, etc.) previously
5
+ * called appendFileSync per entry/chunk, which blocks the event loop on
6
+ * every write. This module coalesces writes per path into an in-memory
7
+ * buffer and flushes asynchronously via fs.promises.appendFile once the
8
+ * buffer reaches BUFFER_FLUSH_BYTES or after DEBOUNCE_MS of inactivity.
9
+ * Flushes are serialized per path so ordering is preserved. On process
10
+ * exit, any remaining buffered bytes for every path are drained with one
11
+ * synchronous appendFileSync call each (best-effort, matching the
12
+ * agent-trace.mjs local spool exit-drain pattern).
13
+ */
14
+ import { appendFileSync } from 'node:fs';
15
+ import { appendFile } from 'node:fs/promises';
16
+
17
+ const BUFFER_FLUSH_BYTES = 32 * 1024;
18
+ const DEBOUNCE_MS = 50;
19
+
20
+ // path -> { chunks: string[], bytes: number, timer, flushing, inFlight, failCount }
21
+ const queues = new Map();
22
+
23
+ function getQueue(path) {
24
+ let q = queues.get(path);
25
+ if (!q) {
26
+ q = { chunks: [], bytes: 0, timer: null, flushing: false, inFlight: null, failCount: 0 };
27
+ queues.set(path, q);
28
+ }
29
+ return q;
30
+ }
31
+
32
+ function scheduleFlush(path, q) {
33
+ if (q.timer) return;
34
+ q.timer = setTimeout(() => {
35
+ q.timer = null;
36
+ _flush(path, q);
37
+ }, DEBOUNCE_MS);
38
+ q.timer.unref?.();
39
+ }
40
+
41
+ function _flush(path, q) {
42
+ if (q.flushing) return;
43
+ if (q.chunks.length === 0) return;
44
+ const data = q.chunks.join('');
45
+ q.chunks = [];
46
+ q.bytes = 0;
47
+ // Hold the in-flight payload until the write settles so an exit-time
48
+ // sync drain can still recover it if it fires mid-write (fix: exit
49
+ // drain must not miss data that was dequeued but not yet persisted).
50
+ q.inFlight = data;
51
+ q.flushing = true;
52
+ appendFile(path, data, 'utf8')
53
+ .then(() => {
54
+ q.failCount = 0;
55
+ })
56
+ .catch(() => {
57
+ // Requeue the failed data so a later flush/exit-drain retries
58
+ // once, instead of silently dropping. Cap retries so a
59
+ // permanently broken path (e.g. deleted dir) cannot loop
60
+ // forever accumulating the same failing chunk.
61
+ q.failCount += 1;
62
+ if (q.failCount <= 3) {
63
+ q.chunks.unshift(data);
64
+ q.bytes += Buffer.byteLength(data, 'utf8');
65
+ }
66
+ })
67
+ .finally(() => {
68
+ q.inFlight = null;
69
+ q.flushing = false;
70
+ if (q.chunks.length > 0) {
71
+ if (q.bytes >= BUFFER_FLUSH_BYTES) _flush(path, q);
72
+ else scheduleFlush(path, q);
73
+ }
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Queue text for buffered append to `path`. Flushes async once the buffer
79
+ * for that path crosses BUFFER_FLUSH_BYTES, or after DEBOUNCE_MS of
80
+ * inactivity, whichever comes first.
81
+ */
82
+ export function appendBuffered(path, text) {
83
+ if (!path || !text) return;
84
+ const q = getQueue(path);
85
+ q.chunks.push(text);
86
+ q.bytes += Buffer.byteLength(text, 'utf8');
87
+ if (q.bytes >= BUFFER_FLUSH_BYTES) {
88
+ if (q.timer) { clearTimeout(q.timer); q.timer = null; }
89
+ _flush(path, q);
90
+ } else {
91
+ scheduleFlush(path, q);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Synchronously drain any remaining buffered bytes for every known path.
97
+ * Intended for process exit hooks only — best-effort, never throws.
98
+ */
99
+ export function drainAllSync() {
100
+ for (const [path, q] of queues) {
101
+ drainPathSync(path);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Synchronously drain the queue for a single path. Writes any in-flight
107
+ * (already-dequeued but not yet persisted) payload FIRST, then any
108
+ * still-queued chunks, so nothing buffered is lost. Best-effort, never
109
+ * throws.
110
+ */
111
+ export function drainPathSync(path) {
112
+ const q = queues.get(path);
113
+ if (!q) return;
114
+ if (q.timer) { clearTimeout(q.timer); q.timer = null; }
115
+ if (q.inFlight) {
116
+ try {
117
+ appendFileSync(path, q.inFlight, 'utf8');
118
+ } catch {
119
+ // Best-effort; nothing to recover from here.
120
+ }
121
+ q.inFlight = null;
122
+ }
123
+ if (q.chunks.length === 0) return;
124
+ const data = q.chunks.join('');
125
+ q.chunks = [];
126
+ q.bytes = 0;
127
+ try {
128
+ appendFileSync(path, data, 'utf8');
129
+ } catch {
130
+ // Best-effort exit drain; nothing to recover from here.
131
+ }
132
+ }
133
+
134
+ /**
135
+ * True if a path currently has an async write in flight. Callers that need
136
+ * to rename/rotate the underlying file (which would race a concurrent
137
+ * appendFile on some platforms, notably Windows) should check this and
138
+ * defer the rename to a later tick rather than racing it.
139
+ */
140
+ export function hasInFlightWrite(path) {
141
+ const q = queues.get(path);
142
+ return Boolean(q && q.inFlight);
143
+ }
144
+
145
+ try {
146
+ process.on('exit', drainAllSync);
147
+ } catch {
148
+ // Ignore lifecycle hook failures in embedded runtimes.
149
+ }
@@ -4,7 +4,7 @@
4
4
  // path. A `mixdog`-launched session can be "managed": the launcher
5
5
  // (setup/mixdog.mjs) owns the child process and exposes a file-based
6
6
  // command queue under the runtime root. Internal commands (/clear,
7
- // /reload-plugins) are enqueued by the MCP server (inject_command / inject_input)
7
+ // /reload-plugins) are enqueued by the MCP server (inject_input)
8
8
  // and the launcher delivers them to the child's stdin — no terminal keystroke
9
9
  // injection, no new window. Works on Windows / macOS / Linux.
10
10
  //
@@ -166,7 +166,7 @@ export function managedLaunchId() {
166
166
 
167
167
  let enqueueSequence = 0;
168
168
 
169
- // Writer side (inject_command / inject_input): publish one command for the
169
+ // Writer side (inject_input): publish one command for the
170
170
  // launcher to deliver. Prefers the canonical Rust backend; the JS writer (temp
171
171
  // name + rename so the watcher never sees a partial file) is the fallback.
172
172
  // Returns the published path.
@@ -0,0 +1,98 @@
1
+ // Shared production of background-task notification envelopes.
2
+ //
3
+ // Producers (shell-jobs fire()/prompt-stall) and consumers (session
4
+ // ingest/manager detection, TUI parsers reading stored sessions) must agree
5
+ // byte-for-byte on the emitted wire format: bracket header fields, the blank
6
+ // line body separator, and the completion instruction wording. To keep one
7
+ // source of truth, the render helpers and the detection regexes live here.
8
+
9
+ import {
10
+ toolCompletionInstruction,
11
+ isInternalRuntimeNotificationText,
12
+ isBracketedShellNotificationEnvelope,
13
+ backgroundTaskHeaderStatus,
14
+ } from './tool-execution-contract.mjs';
15
+
16
+ // Re-export the envelope *detection* predicate so producers and consumers can
17
+ // pull render + detect from one module. Detection primitives live in
18
+ // tool-execution-contract.mjs (shouldPersistModelVisibleToolCompletion et al.
19
+ // depend on them there); this keeps a single import surface without forking
20
+ // the regexes.
21
+ export {
22
+ isInternalRuntimeNotificationText,
23
+ isBracketedShellNotificationEnvelope,
24
+ backgroundTaskHeaderStatus,
25
+ };
26
+
27
+ // Render the bracketed shell *completion* envelope body.
28
+ // Byte-compatible with the historical inline assembly in shell-jobs.fire().
29
+ export function renderShellCompletionEnvelope({
30
+ jobId,
31
+ status,
32
+ exitCode = null,
33
+ elapsedMs = null,
34
+ command = null,
35
+ summary = null,
36
+ stdoutPreview = null,
37
+ stderrPreview = null,
38
+ mergeStderr = false,
39
+ } = {}) {
40
+ const header = [
41
+ `[task_id: ${jobId}]`,
42
+ `[status: ${status}]`,
43
+ `[exit: ${exitCode === null ? 'n/a' : exitCode}]`,
44
+ elapsedMs !== null ? `[elapsed: ${elapsedMs} ms]` : null,
45
+ command ? `[command: ${command}]` : null,
46
+ ].filter((l) => l !== null);
47
+ const bodySections = [
48
+ summary ? `Summary: ${summary}` : null,
49
+ stdoutPreview ? `\n[stdout preview]\n${stdoutPreview}` : null,
50
+ (mergeStderr !== true && stderrPreview) ? `\n[stderr preview]\n${stderrPreview}` : null,
51
+ ].filter((l) => l !== null);
52
+ // Exactly one blank line separates the bracket header block from the body
53
+ // when any body section exists; no trailing blank line when there is none.
54
+ // (Previously the '' separator was filtered out by the value filter, so a
55
+ // summary-only envelope glued headers straight onto `Summary:` and read as
56
+ // bodyless to the `\n\s*\n` body detector.)
57
+ const lines = bodySections.length > 0
58
+ ? [...header, '', ...bodySections]
59
+ : header;
60
+ return lines.join('\n');
61
+ }
62
+
63
+ // Build the shell completion instruction via the shared wording so all async
64
+ // surfaces read identically ("The async shell task … has finished …"). The
65
+ // exit detail is folded into the shared detail slot.
66
+ export function shellCompletionInstruction({ jobId, status, exitCode = null } = {}) {
67
+ return toolCompletionInstruction({
68
+ surface: 'shell',
69
+ id: jobId,
70
+ status,
71
+ detail: `exit ${exitCode === null ? 'n/a' : exitCode}`,
72
+ });
73
+ }
74
+
75
+ // Render the bracketed shell *prompt-stall* progress envelope body.
76
+ // Byte-compatible with the historical inline assembly in maybeNotifyPromptStall.
77
+ export function renderShellPromptStallEnvelope({
78
+ jobId,
79
+ stalledMs,
80
+ elapsedMs = null,
81
+ command = null,
82
+ tailText = null,
83
+ } = {}) {
84
+ return [
85
+ `[task_id: ${jobId}]`,
86
+ '[status: running]',
87
+ `[stalled: no output growth for ${stalledMs} ms]`,
88
+ (elapsedMs !== null && elapsedMs >= 0) ? `[elapsed: ${elapsedMs} ms]` : null,
89
+ command ? `[command: ${command}]` : null,
90
+ '',
91
+ 'This background shell task appears to be waiting for interactive input. Background tasks cannot answer prompts automatically; cancel it or rerun with non-interactive flags/input.',
92
+ tailText ? `\n${tailText}` : null,
93
+ ].filter((line) => line !== null && line !== '').join('\n');
94
+ }
95
+
96
+ export function shellPromptStallInstruction({ jobId } = {}) {
97
+ return `The background shell task ${jobId} appears to be waiting for interactive input; inspect the prompt, then cancel or rerun it non-interactively.`;
98
+ }
@@ -33,7 +33,7 @@ function notificationResultBody(text) {
33
33
  return match ? String(match[1] || '').trim() : '';
34
34
  }
35
35
 
36
- function backgroundTaskHeaderStatus(text) {
36
+ export function backgroundTaskHeaderStatus(text) {
37
37
  const match = /^status:\s*(\S+)/mi.exec(String(text || ''));
38
38
  return clean(match?.[1]).toLowerCase();
39
39
  }
@@ -86,7 +86,7 @@ export function shouldPersistModelVisibleToolCompletion(text, meta = {}) {
86
86
 
87
87
  const BRACKETED_SHELL_STATUS_RE = /^\[status:\s*(?:running|pending|queued|completed|failed|cancelled|canceled|error|timeout|done|success)\]/im;
88
88
 
89
- function isBracketedShellNotificationEnvelope(text) {
89
+ export function isBracketedShellNotificationEnvelope(text) {
90
90
  const value = String(text ?? '').trim();
91
91
  if (!value) return false;
92
92
  if (!/^\[task_id:\s*\S+\]/im.test(value)) return false;
@@ -0,0 +1,308 @@
1
+ import { displayModelName as sharedDisplayModelName } from '../../ui/model-display.mjs';
2
+
3
+ // Default cap for tool-arg summaries (header parenthetical, channel tool lines).
4
+ // Unified at 80 so every tool surface line — header arg summary and collapsed
5
+ // detail alike — shares one width ceiling; per-call sites still clamp lower
6
+ // (header 48, channel 50) where a tighter line is wanted.
7
+ export const DEFAULT_SUMMARY_MAX = 80;
8
+ // Semantic cap for collapsed tool/agent/task card one-liners — the second row
9
+ // under the ⎿ gutter (spawn, send, response, generic/shell result summaries).
10
+ // Kept at 80 so every collapsed detail line is truncated to the same width
11
+ // regardless of terminal columns; ctrl+o expand still shows the full body.
12
+ export const AGENT_SURFACE_BRIEF_MAX = 80;
13
+ export const STATUS_SEPARATOR = ' · ';
14
+
15
+ export function stripToolPrefix(name) {
16
+ const text = rawToolName(name);
17
+ const mcp = parseMcpToolName(text);
18
+ return mcp ? mcp.tool : text;
19
+ }
20
+
21
+ function rawToolName(name) {
22
+ return String(name || 'tool').replace(/^functions\./, '');
23
+ }
24
+
25
+ export function parseMcpToolName(name) {
26
+ const text = rawToolName(name);
27
+ const match = /^mcp__(.+?)__(.+)$/.exec(text);
28
+ if (!match) return null;
29
+ return { server: match[1], tool: match[2] };
30
+ }
31
+
32
+ export function isMcpToolName(name) {
33
+ return Boolean(parseMcpToolName(name));
34
+ }
35
+
36
+ export function normalizeToolName(name) {
37
+ return stripToolPrefix(name).replace(/-/g, '_').toLowerCase();
38
+ }
39
+
40
+ export function truncateToolText(value, max = DEFAULT_SUMMARY_MAX) {
41
+ const text = String(value ?? '').trim();
42
+ return text.length > max ? `${text.slice(0, max)}...` : text;
43
+ }
44
+
45
+ export function truncateSingleLine(value, max = DEFAULT_SUMMARY_MAX) {
46
+ return truncateToolText(String(value ?? '').replace(/\s+/g, ' '), max);
47
+ }
48
+
49
+ export function truncateCommand(value, max = DEFAULT_SUMMARY_MAX) {
50
+ const text = String(value ?? '').trim();
51
+ if (!text) return '';
52
+ const lines = text.split('\n');
53
+ let out = lines.length > 2 ? `${lines.slice(0, 2).join(' ')}...` : lines.join(' ');
54
+ out = out.replace(/\s+/g, ' ').trim();
55
+ return out.length > max ? `${out.slice(0, Math.max(1, max - 3))}...` : out;
56
+ }
57
+
58
+ export function parseToolArgs(args) {
59
+ if (!args) return {};
60
+ if (typeof args === 'string') {
61
+ try {
62
+ const parsed = JSON.parse(args);
63
+ return parsed && typeof parsed === 'object' ? parsed : { value: args };
64
+ } catch {
65
+ return { value: args };
66
+ }
67
+ }
68
+ if (typeof args === 'object') {
69
+ if (args.input && typeof args.input === 'object') return args.input;
70
+ return args;
71
+ }
72
+ return { value: args };
73
+ }
74
+
75
+ export function displayToolPath(path) {
76
+ const text = String(path ?? '');
77
+ return text.replace(/\\/g, '/').split('/').filter(Boolean).at(-1) || text;
78
+ }
79
+
80
+ export function compactParts(parts) {
81
+ return parts.filter((part) => part != null && String(part).trim()).map((part) => String(part).trim()).join(STATUS_SEPARATOR);
82
+ }
83
+
84
+ export function compactSlash(left, right) {
85
+ const a = String(left ?? '').trim();
86
+ const b = String(right ?? '').trim();
87
+ return a && b ? `${a}/${b}` : a || b;
88
+ }
89
+
90
+ export function mcpToolTarget(name, max = DEFAULT_SUMMARY_MAX) {
91
+ const mcp = parseMcpToolName(name);
92
+ if (!mcp) return '';
93
+ return truncateToolText(compactSlash(mcp.server, mcp.tool), max);
94
+ }
95
+
96
+ export function quoted(value, max) {
97
+ const text = truncateToolText(value || '', max);
98
+ return text ? `"${text}"` : '';
99
+ }
100
+
101
+ export function firstText(...values) {
102
+ for (const value of values) {
103
+ if (value != null && String(value).trim()) return String(value).trim();
104
+ }
105
+ return '';
106
+ }
107
+
108
+ export function splitToolSearchSelection(value) {
109
+ if (Array.isArray(value)) return value.map((item) => String(item || '').trim()).filter(Boolean);
110
+ return String(value || '')
111
+ .split(/[,\s]+/)
112
+ .map((item) => item.trim())
113
+ .filter(Boolean);
114
+ }
115
+
116
+ function toolSearchTargetKind(value) {
117
+ const lower = String(value || '').trim().toLowerCase();
118
+ if (!lower) return '';
119
+ if (lower.startsWith('mcp__') || lower.includes('_mcp_') || lower.includes('mcp')) return 'MCP';
120
+ if (lower === 'skill' || lower.startsWith('skill:') || lower.startsWith('skill_') || lower.startsWith('skills_') || lower.includes('skill')) return 'Skills';
121
+ return 'Tools';
122
+ }
123
+
124
+ function orderedToolSearchKinds(kinds) {
125
+ const set = new Set((kinds || []).filter(Boolean));
126
+ const order = ['Tools', 'MCP', 'Skills'];
127
+ const out = order.filter((kind) => set.has(kind));
128
+ return out.length ? out : ['Tools'];
129
+ }
130
+
131
+ function inferToolSearchKinds(args = {}) {
132
+ const selected = splitToolSearchSelection(args.select);
133
+ if (selected.length) return orderedToolSearchKinds(selected.map(toolSearchTargetKind));
134
+
135
+ const query = firstText(args.query, args.q, args.text).toLowerCase();
136
+ const kinds = [];
137
+ if (/\bmcp\b|mcp__|mcp[-_\s]?server/.test(query)) kinds.push('MCP');
138
+ if (/\bskills?\b|skill_|use[-_\s]?skill/.test(query)) kinds.push('Skills');
139
+ return orderedToolSearchKinds(kinds);
140
+ }
141
+
142
+ export function toolSearchDisplayLabel(args = {}) {
143
+ return `Load ${inferToolSearchKinds(args).join('/')}`;
144
+ }
145
+
146
+ export function displayToolSearchTarget(value) {
147
+ const text = String(value || '').trim();
148
+ if (/^skill:/i.test(text)) return text.slice('skill:'.length);
149
+ const mcp = /^mcp__(.*?)__(.+)$/.exec(text);
150
+ if (mcp) return `${mcp[1]}.${mcp[2]}`;
151
+ return stripToolPrefix(text);
152
+ }
153
+
154
+ export function titleizeToolName(name) {
155
+ return stripToolPrefix(name)
156
+ .split(/[_\s-]+/)
157
+ .filter(Boolean)
158
+ .map((part) => {
159
+ const lower = part.toLowerCase();
160
+ if (lower === 'ui') return 'UI';
161
+ if (lower === 'mcp') return 'MCP';
162
+ if (lower === 'id') return 'ID';
163
+ return `${lower.slice(0, 1).toUpperCase()}${lower.slice(1)}`;
164
+ })
165
+ .join(' ') || 'Tool';
166
+ }
167
+
168
+ const AGENT_DISPLAY_NAMES = new Map([
169
+ ['explore', 'Explore'],
170
+ ['maintainer', 'Maintainer'],
171
+ ['worker', 'Worker'],
172
+ ['heavy-worker', 'Heavy Worker'],
173
+ ['reviewer', 'Reviewer'],
174
+ ['debugger', 'Debugger'],
175
+ ]);
176
+
177
+ function titleizeDisplayName(value) {
178
+ const text = String(value || '').trim();
179
+ if (!text) return '';
180
+ return text
181
+ .replace(/[_-]+/g, ' ')
182
+ .split(/\s+/)
183
+ .filter(Boolean)
184
+ .map((part) => {
185
+ const lower = part.toLowerCase();
186
+ if (lower === 'ui') return 'UI';
187
+ if (lower === 'mcp') return 'MCP';
188
+ if (lower === 'id') return 'ID';
189
+ return `${lower.slice(0, 1).toUpperCase()}${lower.slice(1)}`;
190
+ })
191
+ .join(' ');
192
+ }
193
+
194
+ export function displayAgentName(value) {
195
+ const text = String(value || '').trim();
196
+ if (!text) return '';
197
+ const key = text.toLowerCase().replace(/[\s_]+/g, '-');
198
+ return AGENT_DISPLAY_NAMES.get(key) || titleizeDisplayName(text);
199
+ }
200
+
201
+ export function displayModelName(model, provider, displayHint) {
202
+ const text = String(model ?? '').trim();
203
+ const modelId = text
204
+ ? (text.includes('/') ? (text.split('/').filter(Boolean).at(-1) || text) : text)
205
+ : '';
206
+ const shown = sharedDisplayModelName(modelId, provider, displayHint);
207
+ return shown || modelId;
208
+ }
209
+
210
+ export function bridgeAgentModelSummary(args) {
211
+ const provider = firstText(args.provider, args.providerId, args.provider_id);
212
+ const modelId = firstText(args.model);
213
+ const displayHint = firstText(args.modelDisplay, args.model_display, args.displayModel);
214
+ return compactParts([
215
+ displayAgentName(firstText(args.agent, args.name, args.subagent_type)),
216
+ displayModelName(modelId, provider, displayHint),
217
+ ]);
218
+ }
219
+
220
+ export function summarizeLineWindow(a) {
221
+ const offset = a.offset ?? a.start_line ?? a.startLine ?? a.line;
222
+ const limit = a.limit ?? a.line_count ?? a.lineCount ?? a.lines;
223
+ if (offset == null && limit == null) return '';
224
+ const start = Number(offset);
225
+ const count = Number(limit);
226
+ if (Number.isFinite(start) && Number.isFinite(count) && count > 0) {
227
+ return `lines ${start}-${Math.max(start, start + count - 1)}`;
228
+ }
229
+ if (Number.isFinite(start)) return `from line ${start}`;
230
+ if (Number.isFinite(count)) return `${count} lines`;
231
+ return '';
232
+ }
233
+
234
+ export function summarizePatch(patch, basePath) {
235
+ const text = String(patch ?? '');
236
+ const files = [];
237
+ for (const line of text.split('\n')) {
238
+ const match = /^\*\*\*\s+(?:Update|Add|Delete) File:\s+(.+)\s*$/.exec(line);
239
+ if (match) files.push(displayToolPath(match[1]));
240
+ }
241
+ if (files.length === 1) return files[0];
242
+ if (files.length > 1) return `${files.length} files`;
243
+ if (basePath) return displayToolPath(basePath);
244
+ return text ? 'patch' : '';
245
+ }
246
+
247
+ export function collectionCount(...values) {
248
+ for (const value of values) {
249
+ if (Array.isArray(value)) {
250
+ const count = value.filter((item) => item != null && String(item).trim()).length;
251
+ return count || value.length || 0;
252
+ }
253
+ if (value && typeof value === 'object') return 1;
254
+ if (value != null && String(value).trim()) return 1;
255
+ }
256
+ return 0;
257
+ }
258
+
259
+ export function formatCountedUnit(count, singular, pluralText = `${singular}s`) {
260
+ const n = Math.max(0, Number(count || 0));
261
+ return n > 0 ? `${n} ${pluralize(n, singular, pluralText)}` : '';
262
+ }
263
+
264
+ export function patchFileCount(args = {}) {
265
+ const patchText = String(args.patch ?? '');
266
+ if (patchText) {
267
+ const files = new Set();
268
+ for (const line of patchText.split('\n')) {
269
+ const match = /^\*\*\*\s+(?:Update|Add|Delete) File:\s+(.+)\s*$/.exec(line);
270
+ if (match) files.add(match[1].trim());
271
+ }
272
+ if (files.size > 0) return files.size;
273
+ }
274
+ return collectionCount(args.path, args.file, args.file_path, args.base_path);
275
+ }
276
+
277
+ export function codeGraphLabel(args) {
278
+ const mode = String(args.mode || args.action || '').toLowerCase();
279
+ if (mode === 'prewarm' || mode === 'index' || mode === 'build' || mode === 'refresh') return 'Setup';
280
+ if (mode === 'search' || mode === 'find_symbol' || mode === 'references' || mode === 'callers' || mode === 'callees') return 'Search';
281
+ return 'Read';
282
+ }
283
+
284
+ export function codeGraphSummary(args, max) {
285
+ return compactParts([
286
+ args.mode || args.action || '',
287
+ truncateToolText(firstText(args.symbol, Array.isArray(args.symbols) ? args.symbols.join(', ') : '', args.file, args.path, args.query), max),
288
+ ]);
289
+ }
290
+
291
+ export function pluralize(count, singular, pluralText = `${singular}s`) {
292
+ return count === 1 ? singular : pluralText;
293
+ }
294
+
295
+ export function titleWord(value) {
296
+ const text = String(value || '');
297
+ return text ? `${text.charAt(0).toUpperCase()}${text.slice(1).toLowerCase()}` : '';
298
+ }
299
+
300
+ export function titleStatus(value) {
301
+ const text = String(value || '').trim();
302
+ if (!text) return '';
303
+ if (/^ok$/i.test(text)) return 'Ok';
304
+ if (/^(done|success|completed)$/i.test(text)) return 'Finished';
305
+ if (/^(error|failed|fail|killed|timeout)$/i.test(text)) return 'Failed';
306
+ if (/^(cancelled|canceled|cancel)$/i.test(text)) return 'Cancelled';
307
+ return titleWord(text);
308
+ }