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
@@ -11,9 +11,7 @@
11
11
  import React, { useEffect, useState } from 'react';
12
12
  import { Box, Text } from 'ink';
13
13
  import stringWidth from 'string-width';
14
- import stripAnsi from 'strip-ansi';
15
- import { displayWidth } from '../display-width.mjs';
16
- import { theme, TURN_MARKER, RESULT_GUTTER, RESULT_GUTTER_CONT } from '../theme.mjs';
14
+ import { theme, TURN_MARKER, AGENT_CALL_MARKER, AGENT_RESPONSE_MARKER } from '../theme.mjs';
17
15
  import { formatElapsed } from '../time-format.mjs';
18
16
  import { BULLET_OPERATOR } from '../figures.mjs';
19
17
  import {
@@ -22,23 +20,52 @@ import {
22
20
  summarizeToolResult as surfaceSummarizeToolResult,
23
21
  formatAggregateHeader,
24
22
  formatToolActionHeader,
25
- displayModelName,
26
23
  summarizeAgentSurfaceBrief,
27
24
  AGENT_SURFACE_BRIEF_MAX,
28
25
  } from '../../runtime/shared/tool-surface.mjs';
29
- import { backgroundTaskFailureStatusLabel, isBackgroundErrorOnlyBody } from '../../runtime/shared/err-text.mjs';
30
- import { formatExpandedResult, wrapExpandedResultLines } from './tool-output-format.mjs';
31
-
32
- const MIN_RESULT_LINE_CHARS = 24;
33
- // Hard cap for the collapsed result detail row (the second line under the ⎿
34
- // gutter). Independent of terminal width so a wide terminal never lets a long
35
- // line (e.g. an agent response brief) stretch the whole row — anything past
36
- // this is truncated with an ellipsis. ctrl+o expand still shows the full body.
37
- const RESULT_LINE_HARD_MAX = 80;
38
- // Hard cap for the parenthesized header arg summary so a long path/query does
39
- // not eat the whole header line; anything longer is truncated with an ellipsis.
40
- const SUMMARY_MAX_CHARS = 48;
41
- const HEADER_FAILURE_STATUS_MAX = 32;
26
+ import { isBackgroundErrorOnlyBody, backgroundTaskFailureStatusLabel } from '../../runtime/shared/err-text.mjs';
27
+ import {
28
+ MIN_RESULT_LINE_CHARS,
29
+ RESULT_LINE_HARD_MAX,
30
+ SUMMARY_MAX_CHARS,
31
+ HEADER_FAILURE_STATUS_MAX,
32
+ safeInlineText,
33
+ normalizeCountMap,
34
+ truncateToWidth,
35
+ shellResultElapsed,
36
+ normalizeTerminalStatus,
37
+ resultTerminalStatus,
38
+ stripLeadingStatusMarkerLines,
39
+ stripLeadingStatusMarkerFromText,
40
+ } from './tool-execution/text-format.mjs';
41
+ import {
42
+ SKILL_SURFACE_NAMES,
43
+ isShellTool,
44
+ shellDisplayStatus,
45
+ shellHeader,
46
+ isAgentTool,
47
+ isBackgroundTaskTool,
48
+ agentResponseTitle,
49
+ agentActionTitle,
50
+ agentActionSummary,
51
+ hasAgentResponseResult,
52
+ resolveBackgroundTaskMeta,
53
+ backgroundTaskElapsed,
54
+ prefixElapsed,
55
+ mergeTerminalDetail,
56
+ shouldPrefixSyncElapsed,
57
+ backgroundTaskResultTitle,
58
+ backgroundTaskActionTitle,
59
+ backgroundTaskFailureDetail,
60
+ backgroundTaskDetail,
61
+ isBackgroundTaskResponseArgs,
62
+ genericCompletedDetail,
63
+ toolSearchLoadedSummary,
64
+ agentTerminalDetail,
65
+ clampFailureCount,
66
+ toolStatusColor,
67
+ } from './tool-execution/surface-detail.mjs';
68
+ import { ResultBody } from './tool-execution/ResultBody.jsx';
42
69
 
43
70
  export function displayToolName(name, args) {
44
71
  return surfaceDisplayToolName(name, args);
@@ -47,193 +74,6 @@ export function displayToolName(name, args) {
47
74
  const TOOL_BLINK_MS = 500;
48
75
  const TOOL_BLINK_LIMIT_MS = 3000;
49
76
  const TOOL_PENDING_SHOW_DELAY_MS = 1000;
50
- // Read `theme.subtle` at use-time (not captured here) so a live `/theme`
51
- // switch re-tones the tool hints. `theme` is mutated in-place on switch.
52
- // Collapsed tool headers/details are laid out as single terminal rows. Never let
53
- // raw C0/control bytes (CR, tabs, cursor escapes, etc.) reach those rows: a
54
- // terminal can apply them after Ink has already clipped/measured the row, which
55
- // makes a scrolled tool card appear to write through the prompt/statusline.
56
- const INLINE_CONTROL_RE = /[\u0000-\u001F\u007F]/g;
57
-
58
- function safeInlineText(value) {
59
- return stripAnsi(String(value ?? ''))
60
- .replace(/\r\n?/g, '\n')
61
- .replace(/\t/g, ' ')
62
- .replace(/\n+/g, ' ')
63
- .replace(INLINE_CONTROL_RE, ' ')
64
- .replace(/\s+/g, ' ')
65
- .trim();
66
- }
67
-
68
- function normalizeCount(value) {
69
- const n = Number(value || 0);
70
- return Number.isFinite(n) ? Math.max(0, Math.floor(n)) : 0;
71
- }
72
-
73
- function normalizeCountMap(value = {}) {
74
- const out = {};
75
- for (const [key, raw] of Object.entries(value || {})) {
76
- if (raw && typeof raw === 'object') {
77
- out[key] = { ...raw, count: normalizeCount(raw.count) };
78
- } else {
79
- out[key] = normalizeCount(raw);
80
- }
81
- }
82
- return out;
83
- }
84
-
85
- function deltaColor(token) {
86
- return String(token || '').startsWith('+') ? theme.success : theme.error;
87
- }
88
-
89
- function deltaTextParts(text) {
90
- const value = String(text ?? '');
91
- const parts = [];
92
- const re = /(^|[\s([,{·])([+-]\s*\d+)(?=\s+Lines?\b)/gi;
93
- let last = 0;
94
- let match;
95
- while ((match = re.exec(value))) {
96
- const prefix = match[1] || '';
97
- const token = (match[2] || '').replace(/\s+/g, '');
98
- const tokenStart = match.index + prefix.length;
99
- if (match.index > last) parts.push({ text: value.slice(last, match.index) });
100
- if (prefix) parts.push({ text: prefix });
101
- if (token) parts.push({ text: token, color: deltaColor(token) });
102
- last = tokenStart + (match[2] || '').length;
103
- }
104
- if (last < value.length) parts.push({ text: value.slice(last) });
105
- return parts;
106
- }
107
-
108
- function renderDeltaText(text) {
109
- return deltaTextParts(text).map((part, index) => (
110
- part.color ? <Text key={index} color={part.color}>{part.text}</Text> : part.text
111
- ));
112
- }
113
-
114
- // Shared multi-line result body: `└` on the first row, `│` continuation rail on
115
- // every following row, body text in one flex column so wrapping stays aligned
116
- // under the head gutter.
117
- //
118
- // Two render paths:
119
- // - COLLAPSED (raw=false): a single fitted summary line, diff(+/-) colored via
120
- // renderDeltaText.
121
- // - EXPANDED (raw=true): formatExpandedResult then wrapExpandedResultLines so
122
- // each physical row fits the body width before render (rail rows stay 1:1;
123
- // ink does not re-wrap). Physical row mount cap: MIXDOG_TUI_TOOL_OUTPUT_MAX_RENDER_LINES
124
- // (default 600; 0 disables). Shell/script bodies keep the newest tail when capped.
125
- function ResultBody({ lines, rawText, pathArg = '', isShell = false, columns, color, raw }) {
126
- const renderLines = raw
127
- ? wrapExpandedResultLines(
128
- formatExpandedResult(rawText, { pathArg, isShell }),
129
- columns,
130
- { isShell },
131
- )
132
- : (lines || []);
133
- if (!renderLines || renderLines.length === 0) return null;
134
- return (
135
- <Box flexDirection="row">
136
- <Box flexShrink={0} flexDirection="column">
137
- {renderLines.map((_, i) => (
138
- <Text key={i} color={theme.subtle}>{i === 0 ? RESULT_GUTTER : RESULT_GUTTER_CONT}</Text>
139
- ))}
140
- </Box>
141
- <Box flexDirection="column" flexShrink={1} flexGrow={1}>
142
- {renderLines.map((line, i) => (
143
- <Text key={i} color={raw ? undefined : color} wrap="truncate">
144
- {raw
145
- ? (line || ' ')
146
- : renderDeltaText(fitResultLine(line || ' ', columns))}
147
- </Text>
148
- ))}
149
- </Box>
150
- </Box>
151
- );
152
- }
153
-
154
- function plural(count, singular, pluralText = `${singular}s`) {
155
- return count === 1 ? singular : pluralText;
156
- }
157
-
158
- function isShellTool(normalizedName, label = '') {
159
- const n = String(normalizedName || '').toLowerCase();
160
- const l = String(label || '').toLowerCase();
161
- return n === 'shell' || n === 'bash' || n === 'bash_session' || n === 'shell_command' || n === 'job_wait' || l === 'run';
162
- }
163
-
164
- function shellResultStatus(value) {
165
- const match = String(value || '').match(/(?:^|\b)status:\s*(running|pending|queued|completed|failed|cancelled|canceled)\b/im);
166
- return match ? String(match[1] || '').toLowerCase() : '';
167
- }
168
-
169
- function normalizeTerminalStatus(value) {
170
- const raw = String(value || '').trim().toLowerCase();
171
- if (!raw) return '';
172
- if (/^(running|pending|queued|in_progress|in-progress)$/.test(raw)) return 'running';
173
- if (/^(completed|complete|done|success|succeeded|ok)$/.test(raw)) return 'completed';
174
- if (/^(failed|fail|error|errored|timeout|timed_out|killed)$/.test(raw)) return 'failed';
175
- if (/^(cancelled|canceled|cancel)$/.test(raw)) return 'cancelled';
176
- return '';
177
- }
178
-
179
- function displayTerminalStatus(value) {
180
- const status = normalizeTerminalStatus(value);
181
- if (status === 'running') return 'Running';
182
- if (status === 'completed') return 'Finished';
183
- if (status === 'failed') return 'Failed';
184
- if (status === 'cancelled') return 'Cancelled';
185
- return '';
186
- }
187
-
188
- function resultTerminalStatus(value) {
189
- const text = String(value || '');
190
- const tagged = text.match(/<status[^>]*>([\s\S]*?)<\/status>/i)?.[1]?.trim();
191
- if (tagged) return normalizeTerminalStatus(tagged);
192
- const bracketed = text.match(/^\[status:\s*([^\]]*)\]/mi)?.[1]?.trim();
193
- if (bracketed) return normalizeTerminalStatus(bracketed);
194
- // Loose inline `status: x` / `state: x` matches are a last-resort fallback —
195
- // prefer the engine-controlled `<status>` tag or `[status: …]` marker above.
196
- // A loose match can false-positive on prose that happens to start with
197
- // "status:" (rare, but shellResultStatus below already owns real shell
198
- // output parsing; this fallback stays narrow and unchanged in behavior).
199
- const inline = text.match(/^(?:status|state):\s*([^\s·,;]+)/mi)?.[1]?.trim();
200
- return normalizeTerminalStatus(inline);
201
- }
202
-
203
- const LEADING_STATUS_MARKER_LINE_RE = /^\[status:\s*[^\]]*\]\s*$/i;
204
-
205
- function stripLeadingStatusMarkerLines(lines) {
206
- const out = Array.isArray(lines) ? lines.slice() : [];
207
- if (out.length > 0 && LEADING_STATUS_MARKER_LINE_RE.test(String(out[0] ?? '').trim())) out.shift();
208
- return out;
209
- }
210
-
211
- function stripLeadingStatusMarkerFromText(text) {
212
- return stripLeadingStatusMarkerLines(String(text || '').split('\n')).join('\n');
213
- }
214
-
215
- function shellDisplayStatus({ pending = false, failedCount = 0, isError = false, result = '' } = {}) {
216
- const status = shellResultStatus(result);
217
- if (pending || /^(running|pending|queued)$/.test(status)) return 'running';
218
- if (/^cancel/.test(status)) return 'cancelled';
219
- if (/^(failed|error|killed|timeout)$/.test(status) || isError || failedCount > 0) return 'failed';
220
- return 'completed';
221
- }
222
-
223
- function shellHeader(status, count = 1) {
224
- const n = Math.max(1, Number(count) || 1);
225
- const object = `${n} ${plural(n, 'command')}`;
226
- if (status === 'running') return `Running ${object}`;
227
- return `Ran ${object}`;
228
- }
229
-
230
- function shellResultElapsed(value) {
231
- const match = String(value || '').match(/^\[elapsed:\s*(\d+)\s*ms\]/mi);
232
- if (!match) return '';
233
- const elapsedMs = Number(match[1]);
234
- return Number.isFinite(elapsedMs) && elapsedMs >= 1000 ? formatElapsed(elapsedMs) : '';
235
- }
236
-
237
77
  function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
238
78
  // No stableVerbWidth padding: it padded the done verb to the active ("-ing")
239
79
  // width, which Ink trims at the line END (vendor output trimEnd) so it never
@@ -243,388 +83,6 @@ function statusCopy(name, label, count, doneCount, pending, isError, args = {})
243
83
  // dropping the pad just normalizes the spacing.
244
84
  return formatToolActionHeader(name, args, { pending, count });
245
85
  }
246
-
247
- function fitResultLine(line, columns) {
248
- const max = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
249
- const text = safeInlineText(line);
250
- return displayWidth(text) > max ? truncateToWidth(text, max) : text;
251
- }
252
-
253
- /** Trim text from the end (by display width) so it fits maxWidth, appending '…'. */
254
- function truncateToWidth(text, maxWidth) {
255
- const str = safeInlineText(text);
256
- if (maxWidth < 1) return '';
257
- if (displayWidth(str) <= maxWidth) return str;
258
- const chars = Array.from(str);
259
- let out = '';
260
- for (const ch of chars) {
261
- if (displayWidth(out + ch + '…') > maxWidth) break;
262
- out += ch;
263
- }
264
- return `${out}…`;
265
- }
266
-
267
- function isAgentTool(normalizedName) {
268
- return normalizedName === 'agent';
269
- }
270
-
271
- const SKILL_SURFACE_NAMES = new Set([
272
- 'skill', 'skill_execute', 'skill_view', 'skills_list', 'use_skill',
273
- ]);
274
-
275
- function isBackgroundTaskTool(normalizedName) {
276
- return new Set(['explore', 'search', 'shell', 'bash', 'bash_session', 'shell_command', 'task']).has(String(normalizedName || '').toLowerCase());
277
- }
278
-
279
- const AGENT_DISPLAY_NAMES = new Map([
280
- ['explore', 'Explore'],
281
- ['maintainer', 'Maintainer'],
282
- ['worker', 'Worker'],
283
- ['heavy-worker', 'Heavy Worker'],
284
- ['reviewer', 'Reviewer'],
285
- ['debugger', 'Debugger'],
286
- ]);
287
-
288
- function titleizeAgentName(value) {
289
- const text = String(value || '').trim();
290
- if (!text) return '';
291
- const key = text.toLowerCase().replace(/[\s_]+/g, '-');
292
- if (AGENT_DISPLAY_NAMES.has(key)) return AGENT_DISPLAY_NAMES.get(key);
293
- return text
294
- .replace(/[_-]+/g, ' ')
295
- .split(/\s+/)
296
- .filter(Boolean)
297
- .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1).toLowerCase()}`)
298
- .join(' ');
299
- }
300
-
301
- function agentModelLabel(args) {
302
- const a = args && typeof args === 'object' ? args : {};
303
- const provider = String(a.provider || a.providerId || a.provider_id || '').trim();
304
- const model = String(a.model || '').trim();
305
- const displayHint = String(a.modelDisplay || a.model_display || a.displayModel || '').trim();
306
- return displayModelName(model, provider, displayHint);
307
- }
308
-
309
- function agentTagLabel(args) {
310
- // The real spawn tag (engine fills parsedArgs.tag from the envelope target).
311
- // Never fall back to task_id — only the human-meaningful spawn tag belongs in
312
- // the header parentheses.
313
- return String(args?.tag || '').trim();
314
- }
315
-
316
- function withModelAndTag(label, args) {
317
- const model = agentModelLabel(args);
318
- const tag = agentTagLabel(args);
319
- const inner = [model, tag].filter(Boolean).join(', ');
320
- return inner ? `${label} (${inner})` : label;
321
- }
322
-
323
- // Append an agent name to a base action word without leaving a trailing space
324
- // when the agent is unknown (no generic "Agent" fallback).
325
- function joinActionAgent(action, agent) {
326
- return agent ? `${action} ${agent}` : action;
327
- }
328
-
329
- function agentResponseTitle(args) {
330
- const name = titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '');
331
- // The agent + model identify the responder; the response summary itself
332
- // is hidden in the collapsed card (ctrl+o expand still shows the full body).
333
- // No generic "Agent" fallback — render just "Response" when the agent is empty.
334
- return withModelAndTag(joinActionAgent('Response', name), args);
335
- }
336
-
337
- function agentActionTitle(args) {
338
- const name = titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '');
339
- // Runtime treats an omitted type/action as "spawn" (see agent-tool.mjs default),
340
- // so mirror that contract here instead of falling through to the generic
341
- // "Called agent" status copy.
342
- const action = String(args?.type || args?.action || 'spawn').toLowerCase();
343
- // Fixed action verbs regardless of running/completed status. No generic
344
- // "Agent" fallback for the agent: when the agent is unknown render the action
345
- // word alone ("Spawn") instead of "Spawn Agent".
346
- if (action === 'spawn') return withModelAndTag(joinActionAgent('Spawn', name), args);
347
- if (action === 'send') return withModelAndTag(joinActionAgent('Send', name), args);
348
- if (action === 'list') return 'Agent status';
349
- if (action === 'cancel') return withModelAndTag(joinActionAgent('Cancel', name), args);
350
- if (action === 'close') return withModelAndTag(joinActionAgent('Close', name), args);
351
- if (action === 'cleanup') return withModelAndTag(joinActionAgent('Cleanup', name), args);
352
- if (action === 'read' || action === 'status') return withModelAndTag(joinActionAgent('Status', name), args);
353
- return '';
354
- }
355
-
356
- function agentActionSummary(args, summary) {
357
- const text = String(summary || '').trim();
358
- if (!text) return '';
359
- const name = titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '');
360
- if (name && text === name) return '';
361
- let rest = name && text.startsWith(`${name} · `) ? text.slice(name.length + 3).trim() : text;
362
- // The agent/model/tag surface summary ("Heavy Worker · Opus 4.8") is now folded
363
- // into the header label itself ("Spawn Heavy Worker (Opus 4.8, tag)"), so drop
364
- // the model and tag tokens from the parenthesized summary to avoid showing
365
- // them twice.
366
- const model = agentModelLabel(args);
367
- if (model && rest === model) return '';
368
- const tag = agentTagLabel(args);
369
- if (tag && rest === tag) return '';
370
- return rest;
371
- }
372
-
373
- function hasAgentResponseResult(value) {
374
- const text = String(value || '').trim();
375
- if (!text) return false;
376
- if (/^(?:undefined|null)$/i.test(text)) return false;
377
- if (/^status:\s*(?:running|pending|queued|completed|failed|cancelled|canceled)(?:\s*·\s*task_id:\s*\S+)?$/i.test(text)) return false;
378
- const isBridgeEnvelope = /^(?:agent task:|background task\b|agent message queued\b|agent close:)/i.test(text)
379
- || /^(?:agents|tasks):\s*\d/i.test(text)
380
- || /^\(no agents or tasks\)$/i.test(text)
381
- || (/^task_id:\s*\S+/mi.test(text) && /^(?:surface|operation|status):\s*/mi.test(text));
382
- if (!isBridgeEnvelope) return true;
383
- let sawBlank = false;
384
- for (const line of text.split('\n')) {
385
- const trimmed = line.trim();
386
- if (!trimmed) {
387
- sawBlank = true;
388
- continue;
389
- }
390
- if (/^agent result\b/i.test(trimmed)) continue;
391
- if (/^(?:undefined|null)$/i.test(trimmed)) continue;
392
- if (/^<\/?(?:final-answer|task-notification|task-id|tool-use-id|output-file|result|status|summary|usage|total_tokens|tool_uses|duration_ms|worktree|worktreePath|worktreeBranch)[^>]*>$/i.test(trimmed)) continue;
393
- if (!sawBlank && /^(?:agent task|background task|agent message queued\b|agent close:|task_id|surface|operation|label|status|type|target|agent|preset|model|effort|fast|limits|started|finished|error|notification|queueDepth):?\s*/i.test(trimmed)) continue;
394
- if (!sawBlank && /^(?:agents|tasks):\s*/i.test(trimmed)) continue;
395
- if (/^\(no agents or tasks\)$/i.test(trimmed)) continue;
396
- if (!sawBlank && /^-\s+\S+/i.test(trimmed)) continue;
397
- return true;
398
- }
399
- return false;
400
- }
401
-
402
- function parseBackgroundTaskResult(value) {
403
- const text = String(value || '').trim();
404
- if (!text) return null;
405
- const allLines = text.split('\n');
406
- const start = allLines.findIndex((line) => line.trim() === 'background task');
407
- if (start < 0) return null;
408
- const rest = allLines.slice(start + 1);
409
- const blank = rest.findIndex((line) => !line.trim());
410
- const headLines = blank >= 0 ? rest.slice(0, blank) : rest;
411
- const body = blank >= 0 ? rest.slice(blank + 1).join('\n').trim() : '';
412
- const fields = {};
413
- for (const line of headLines) {
414
- const match = /^([a-zA-Z][\w-]*):\s*(.*)$/.exec(line.trim());
415
- if (match) fields[match[1].toLowerCase()] = match[2].trim();
416
- }
417
- const status = String(fields.status || '').toLowerCase();
418
- const error = fields.error || '';
419
- return {
420
- taskId: fields.task_id || fields.taskid || '',
421
- surface: fields.surface || '',
422
- operation: fields.operation || '',
423
- label: fields.label || '',
424
- status,
425
- startedAt: fields.started || fields.startedat || '',
426
- finishedAt: fields.finished || fields.finishedat || '',
427
- body,
428
- error,
429
- hasResponse: Boolean(body) && !isBackgroundErrorOnlyBody(body, error) && !/^(running|pending|queued)$/i.test(status),
430
- };
431
- }
432
-
433
- function backgroundTaskMetaFromArgs(args = {}) {
434
- const taskId = String(args.task_id || args.taskId || '').trim();
435
- if (!taskId) return null;
436
- return {
437
- taskId,
438
- surface: args.surface || '',
439
- operation: args.operation || '',
440
- label: args.label || '',
441
- status: String(args.status || '').toLowerCase(),
442
- startedAt: args.startedAt || args.started || '',
443
- finishedAt: args.finishedAt || args.finished || '',
444
- error: args.error || '',
445
- body: '',
446
- hasResponse: false,
447
- };
448
- }
449
-
450
- function resolveBackgroundTaskMeta(parsedArgs = {}, resultText = '') {
451
- const parsed = parseBackgroundTaskResult(resultText);
452
- if (parsed) {
453
- if (!parsed.error && parsedArgs?.error) parsed.error = parsedArgs.error;
454
- if (!parsed.status && parsedArgs?.status) parsed.status = String(parsedArgs.status).toLowerCase();
455
- if (!parsed.surface && parsedArgs?.surface) parsed.surface = parsedArgs.surface;
456
- return parsed;
457
- }
458
- return backgroundTaskMetaFromArgs(parsedArgs);
459
- }
460
-
461
- function backgroundTaskElapsed(meta = {}, fallback = '') {
462
- const startedMs = Date.parse(meta.startedAt || '');
463
- const finishedMs = Date.parse(meta.finishedAt || '');
464
- if (Number.isFinite(startedMs) && Number.isFinite(finishedMs) && finishedMs >= startedMs) {
465
- const elapsedMs = finishedMs - startedMs;
466
- return elapsedMs >= 1000 ? formatElapsed(elapsedMs) : '';
467
- }
468
- return fallback || '';
469
- }
470
-
471
- function prefixElapsed(detail, elapsed = '') {
472
- const text = String(detail || '').trim();
473
- const time = String(elapsed || '').trim();
474
- if (!time) return text;
475
- // Unified convention: the elapsed time ALWAYS goes at the END, ` · ` separated.
476
- // Guard against a double-append when the text already ends with the same time.
477
- if (text && text.endsWith(`· ${time}`)) return text;
478
- return text ? `${text} · ${time}` : time;
479
- }
480
-
481
- function mergeTerminalDetail(status, detail = '') {
482
- const label = displayTerminalStatus(status);
483
- const text = String(detail || '').trim();
484
- if (!label) return text;
485
- if (label === 'Finished' && text) return text;
486
- if (!text) return label;
487
- if (text.toLowerCase().startsWith(label.toLowerCase())) return text;
488
- return `${label} · ${text}`;
489
- }
490
-
491
- function shouldPrefixSyncElapsed(normalizedName, label) {
492
- const n = String(normalizedName || '').toLowerCase();
493
- const l = String(label || '').toLowerCase();
494
- return n === 'explore' || l === 'explore' || n === 'search' || l === 'search' || l === 'web search';
495
- }
496
-
497
- function backgroundTaskDisplayName(normalizedName, meta = {}) {
498
- const surface = String(meta.surface || normalizedName || '').toLowerCase();
499
- if (surface === 'explore') return 'Explore';
500
- if (surface === 'search') return 'Search';
501
- if (surface === 'shell' || surface === 'bash' || surface === 'bash_session' || surface === 'shell_command' || surface === 'task') return 'Shell';
502
- return titleizeAgentName(surface || normalizedName || 'Task');
503
- }
504
-
505
- function backgroundTaskResultTitle(normalizedName, meta = {}) {
506
- const display = backgroundTaskDisplayName(normalizedName, meta);
507
- if (display === 'Shell') return 'Shell output';
508
- if (display === 'Search') return 'Search results';
509
- return `${display} response`;
510
- }
511
-
512
- function backgroundTaskActionTitle(normalizedName, meta = {}) {
513
- const display = backgroundTaskDisplayName(normalizedName, meta);
514
- if (/^(running|pending|queued)$/i.test(meta.status || '')) return `Started ${display}`;
515
- if (meta.hasResponse) return backgroundTaskResultTitle(normalizedName, meta);
516
- return `${display} status`;
517
- }
518
-
519
- function backgroundTaskFailureDetail(meta = {}, parsedArgs = {}) {
520
- const status = meta.status || parsedArgs?.status;
521
- const error = meta.error || parsedArgs?.error;
522
- if (!error) return '';
523
- const surface = meta.surface || parsedArgs?.surface || '';
524
- return backgroundTaskFailureStatusLabel(status, error, { surface });
525
- }
526
-
527
- function backgroundTaskDetail(meta = {}, elapsed = '', parsedArgs = {}) {
528
- const parts = [];
529
- const status = displayTerminalStatus(meta.status);
530
- if (status) parts.push(status);
531
- if (meta.taskId) parts.push(`task_id: ${meta.taskId}`);
532
- const firstBodyLine = String(meta.body || '').split('\n').map((line) => line.trim()).find(Boolean) || '';
533
- if (firstBodyLine && /^(running|pending|queued)$/i.test(meta.status || '')) parts.push(firstBodyLine);
534
- return prefixElapsed(parts.join(' · '), elapsed);
535
- }
536
-
537
- function isBackgroundTaskResponseArgs(normalizedName, args = {}) {
538
- if (!isBackgroundTaskTool(normalizedName)) return false;
539
- const type = String(args?.type || args?.action || '').toLowerCase();
540
- const status = String(args?.status || '').toLowerCase();
541
- return type === 'result' || type === 'completion' || (/^(completed|cancelled|canceled)$/i.test(status) && Boolean(args?.task_id));
542
- }
543
-
544
- function isOutputDetailTool(normalizedName, label) {
545
- const n = String(normalizedName || '').toLowerCase();
546
- const l = String(label || '').toLowerCase();
547
- return new Set([
548
- 'shell', 'bash', 'bash_session', 'shell_command', 'job_wait',
549
- 'read', 'view_image', 'read_mcp_resource',
550
- 'grep', 'glob', 'search', 'search_query', 'image_query', 'web_search', 'web_search_call', 'explore', 'web_fetch', 'fetch', 'download_attachment',
551
- 'list', 'ls', 'code_graph',
552
- 'recall', 'recall_memory', 'search_memories', 'remember', 'save_memory', 'update_memory',
553
- ]).has(n) || l === 'read' || l === 'search' || l === 'web search' || l === 'run';
554
- }
555
-
556
- function genericCompletedDetail({ normalizedName, label, hasResult, firstResultLine, isError }) {
557
- const n = String(normalizedName || '').toLowerCase();
558
- const l = String(label || '').toLowerCase();
559
- if (isError) return hasResult ? firstResultLine : 'Failed';
560
- if (n === 'shell' || n === 'bash' || n === 'bash_session' || n === 'shell_command' || n === 'job_wait') {
561
- return '';
562
- }
563
- if (isOutputDetailTool(n, l)) {
564
- return hasResult ? firstResultLine : '';
565
- }
566
- return '';
567
- }
568
-
569
- function toolSearchLoadedSummary(resultText) {
570
- let parsed;
571
- try {
572
- parsed = JSON.parse(String(resultText || ''));
573
- } catch {
574
- return '';
575
- }
576
- const tools = parsed?.selected?.tools;
577
- if (!tools || typeof tools !== 'object') return '';
578
- const names = [
579
- ...(Array.isArray(tools.added) ? tools.added : []),
580
- ...(Array.isArray(tools.already) ? tools.already : []),
581
- ]
582
- .map((name) => String(name || '').trim())
583
- .filter(Boolean);
584
- return [...new Set(names)].join(', ');
585
- }
586
-
587
- function agentTerminalDetail(status, isError, elapsed, error = '') {
588
- const failureDetail = isError && error
589
- ? backgroundTaskFailureStatusLabel(status, error, { surface: 'agent' })
590
- : '';
591
- if (failureDetail) return failureDetail;
592
- const s = String(status || '').toLowerCase();
593
- const word = /cancel/.test(s)
594
- ? 'Cancelled'
595
- : /error|fail|killed|timeout/.test(s) || isError
596
- ? 'Failed'
597
- : /done|success|complete|closed/.test(s)
598
- ? 'Finished'
599
- : '';
600
- // Unified ` · <time>` convention (previously "Finished after 12s").
601
- return word ? `${word}${elapsed ? ` · ${elapsed}` : ''}` : '';
602
- }
603
-
604
- function clampFailureCount(errorCount, groupCount, isError) {
605
- const explicit = Number(errorCount);
606
- if (Number.isFinite(explicit)) return Math.max(0, Math.min(groupCount, Math.floor(explicit)));
607
- return isError ? groupCount : 0;
608
- }
609
-
610
- // Single source of truth for the tool-card dot (●) color. Both the aggregate
611
- // and normal (single-tool) render paths must call this with a resolved
612
- // `terminalStatus` — do not recompute color inline elsewhere.
613
- // running/pending -> mixdogOrange || warning (blink handled by caller)
614
- // success -> theme.success
615
- // partial failure -> mixdogOrange (some, not all, of the group failed)
616
- // all failed -> theme.error
617
- // cancelled -> theme.warning
618
- function toolStatusColor({ pending, groupCount, failedCount, terminalStatus = '' }) {
619
- if (pending) return theme.mixdogOrange || theme.warning;
620
- const status = normalizeTerminalStatus(terminalStatus);
621
- if (status === 'cancelled') return theme.warning;
622
- if (status === 'failed') return theme.error;
623
- if (failedCount <= 0) return theme.success;
624
- if (groupCount > 1 && failedCount < groupCount) return theme.mixdogOrange || theme.warning;
625
- return theme.error;
626
- }
627
-
628
86
  export function ToolExecution({ name, args, result, rawResult, isError, errorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, headerFinalized = true, deferredDisplayReady = false }) {
629
87
  const rowWidth = Math.max(1, Number(columns || 80));
630
88
  const [blinkOn, setBlinkOn] = useState(true);
@@ -809,7 +267,10 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
809
267
  // Aggregate cards intentionally omit elapsed time once grouped. A brief
810
268
  // `Running · 1s` tick during the grouped→finished handoff reads as visual
811
269
  // noise, and the grouped header already communicates that work is active.
812
- const pendingPlaceholder = headerPending
270
+ // The placeholder tracks `pending` (real completion), NOT headerPending:
271
+ // the header verb stays active until the block seals, but the detail row
272
+ // must not keep saying "Running" after every call already resolved.
273
+ const pendingPlaceholder = pending
813
274
  ? 'Running'
814
275
  : 'Finished';
815
276
  const detailLines = showRawAggregate
@@ -978,7 +439,14 @@ export function ToolExecution({ name, args, result, rawResult, isError, errorCou
978
439
  }
979
440
  const finalStatusColor = toolStatusColor({ pending, groupCount, failedCount, terminalStatus });
980
441
  const dotColor = finalStatusColor;
981
- const dotText = pending && !blinkExpired && !blinkOn ? ' ' : TURN_MARKER;
442
+ // Agent surface cards use directional markers: `←` for requests going OUT
443
+ // (spawn/send/etc.) and `→` for the response coming back IN. Background
444
+ // task cards (shell async / explore / search / task) and every other tool
445
+ // keep the BLACK_CIRCLE turn marker. Blink behavior is shared.
446
+ const markerGlyph = isAgentResponse
447
+ ? AGENT_RESPONSE_MARKER
448
+ : (isAgentSurfaceCard ? AGENT_CALL_MARKER : TURN_MARKER);
449
+ const dotText = pending && !blinkExpired && !blinkOn ? ' ' : markerGlyph;
982
450
  let labelText;
983
451
  if (isAgentResponse) labelText = agentResponseTitle(parsedArgs);
984
452
  else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);