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
@@ -0,0 +1,296 @@
1
+ /**
2
+ * src/tui/engine/agent-envelope.mjs - parse agent/background-task/shell
3
+ * notification envelopes into synthetic tool-item shapes, and derive
4
+ * status/result text. Extracted from engine.mjs; parseBackgroundTaskEnvelope
5
+ * remains part of engine.mjs's public surface.
6
+ */
7
+ import { isBackgroundErrorOnlyBody } from '../../runtime/shared/err-text.mjs';
8
+
9
+ export function textBetweenTag(text, tag) {
10
+ const re = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, 'i');
11
+ const match = re.exec(String(text ?? ''));
12
+ return match ? match[1].trim() : '';
13
+ }
14
+
15
+ export function stripSyntheticAgentTags(text) {
16
+ const value = String(text ?? '').trim();
17
+ const finalAnswer = textBetweenTag(value, 'final-answer');
18
+ if (finalAnswer) return finalAnswer;
19
+ const taskResult = textBetweenTag(value, 'result');
20
+ if (taskResult) return taskResult;
21
+ return value
22
+ .replace(/^agent result[^\n]*(?:\n|$)/i, '')
23
+ .replace(/<\/?(?:final-answer|task-notification|task-id|tool-use-id|output-file|result|status|summary|usage|total_tokens|tool_uses|duration_ms|worktree|worktreePath|worktreeBranch)[^>]*>/gi, '')
24
+ .trim();
25
+ }
26
+
27
+ export function splitBridgeEnvelope(text) {
28
+ const value = String(text ?? '').trim();
29
+ if (!value) return { head: '', body: '' };
30
+ const match = /\n\s*\n/.exec(value);
31
+ if (!match) return { head: value, body: '' };
32
+ return {
33
+ head: value.slice(0, match.index).trim(),
34
+ body: value.slice(match.index + match[0].length).trim(),
35
+ };
36
+ }
37
+
38
+ export function agentJobStatusText(parsed) {
39
+ if (!parsed) return '';
40
+ const parts = [];
41
+ if (parsed.status) parts.push(`status: ${parsed.status}`);
42
+ if (parsed.taskId) parts.push(`task_id: ${parsed.taskId}`);
43
+ return parts.join(' · ');
44
+ }
45
+
46
+ export function agentJobResultText(text, parsed = parseAgentJob(text)) {
47
+ const value = String(text ?? '').trim();
48
+ if (!value) return '';
49
+ if (parsed?.taskId) {
50
+ const { body } = splitBridgeEnvelope(value);
51
+ const cleanBody = stripSyntheticAgentTags(body);
52
+ if (cleanBody) return cleanBody;
53
+ return agentJobStatusText(parsed);
54
+ }
55
+ return stripSyntheticAgentTags(value) || value;
56
+ }
57
+
58
+ export function parseAgentResultEnvelope(text, fallback = {}) {
59
+ const value = String(text ?? '').trim();
60
+ if (!/^agent result\b/i.test(value)) return null;
61
+ const [head = '', ...restLines] = value.split('\n');
62
+ const body = stripSyntheticAgentTags(restLines.join('\n'));
63
+ const attrs = {};
64
+ const attrRe = /([a-zA-Z][\w-]*)=("[^"]*"|'[^']*'|\S+)/g;
65
+ let match;
66
+ while ((match = attrRe.exec(head))) {
67
+ attrs[match[1].toLowerCase()] = String(match[2] || '').replace(/^["']|["']$/g, '');
68
+ }
69
+ const providerModel = /\s([a-zA-Z0-9_.-]+)\/([^\s]+)\s*$/i.exec(head);
70
+ const agent = attrs.agent || fallback.agent || '';
71
+ return {
72
+ name: 'agent',
73
+ label: String(fallback.status || attrs.status || 'completed').toLowerCase(),
74
+ args: {
75
+ type: 'result',
76
+ status: fallback.status || attrs.status || 'completed',
77
+ task_id: fallback.taskId || attrs.task_id || attrs.taskid || undefined,
78
+ tag: fallback.tag || attrs.tag || undefined,
79
+ agent: agent || undefined,
80
+ provider: fallback.provider || attrs.provider || providerModel?.[1] || undefined,
81
+ model: fallback.model || attrs.model || providerModel?.[2] || undefined,
82
+ preset: fallback.preset || attrs.preset || undefined,
83
+ effort: fallback.effort || attrs.effort || undefined,
84
+ fast: fallback.fast ?? attrs.fast,
85
+ },
86
+ result: body || agentJobStatusText({ status: fallback.status || attrs.status || 'completed', taskId: fallback.taskId || attrs.task_id || attrs.taskid || '' }),
87
+ isError: /^(failed|error|timeout|cancelled|canceled|killed)$/i.test(fallback.status || attrs.status || ''),
88
+ };
89
+ }
90
+
91
+ export function parseBackgroundTaskEnvelope(text) {
92
+ const value = String(text ?? '').trim();
93
+ if (!/^background task\b/i.test(value)) return null;
94
+ const allLines = value.split('\n');
95
+ const rest = allLines.slice(1);
96
+ const blank = rest.findIndex((line) => !line.trim());
97
+ const headLines = blank >= 0 ? rest.slice(0, blank) : rest;
98
+ const body = blank >= 0 ? rest.slice(blank + 1).join('\n').trim() : '';
99
+ const fields = {};
100
+ for (const line of headLines) {
101
+ const match = /^([a-zA-Z][\w-]*):\s*(.*)$/.exec(line.trim());
102
+ if (match) fields[match[1].toLowerCase()] = match[2].trim();
103
+ }
104
+ const surface = String(fields.surface || fields.operation || 'task').toLowerCase();
105
+ const name = surface === 'explore' || surface === 'search' || surface === 'shell' || surface === 'agent' ? surface : 'task';
106
+ const status = String(fields.status || '').toLowerCase();
107
+ const taskId = fields.task_id || fields.taskid || '';
108
+ const errorText = fields.error || '';
109
+ const agentResult = parseAgentResultEnvelope(body, {
110
+ status,
111
+ taskId,
112
+ tag: fields.tag || fields.label || '',
113
+ agent: fields.agent || '',
114
+ provider: fields.provider || '',
115
+ model: fields.model || '',
116
+ preset: fields.preset || '',
117
+ effort: fields.effort || '',
118
+ fast: fields.fast,
119
+ });
120
+ if (agentResult) return { ...agentResult, rawResult: value };
121
+ const errorOnlyBody = isBackgroundErrorOnlyBody(body, errorText);
122
+ const resultBody = body && !errorOnlyBody ? body : '';
123
+ return {
124
+ name,
125
+ label: status || 'notification',
126
+ args: {
127
+ type: body ? 'result' : (fields.operation || 'status'),
128
+ status,
129
+ task_id: taskId || undefined,
130
+ surface,
131
+ operation: fields.operation || undefined,
132
+ label: fields.label || undefined,
133
+ tag: fields.tag || undefined,
134
+ agent: fields.agent || undefined,
135
+ provider: fields.provider || undefined,
136
+ model: fields.model || undefined,
137
+ preset: fields.preset || undefined,
138
+ effort: fields.effort || undefined,
139
+ fast: fields.fast || undefined,
140
+ error: errorText || undefined,
141
+ startedAt: fields.started || fields.startedat || undefined,
142
+ finishedAt: fields.finished || fields.finishedat || undefined,
143
+ },
144
+ result: resultBody || (!errorText ? [status ? `status: ${status}` : '', taskId ? `task_id: ${taskId}` : ''].filter(Boolean).join(' · ') : ''),
145
+ rawResult: value,
146
+ isError: /^(failed|error|timeout|cancelled|canceled|killed)$/i.test(status) || /^error:/i.test(body) || Boolean(errorText),
147
+ };
148
+ }
149
+
150
+ export function isStatusOnlyAgentCompletionNotification(text) {
151
+ const background = parseBackgroundTaskEnvelope(text);
152
+ if (background?.name === 'agent' && /^(completed|cancelled|canceled)$/i.test(background.label || '')) {
153
+ return !(hasAgentResponseResultText(background.result) || hasAgentResponseResultText(text));
154
+ }
155
+ const parsed = parseAgentJob(text);
156
+ const result = agentJobResultText(text, parsed);
157
+ if (!parsed?.taskId || !/^(completed|cancelled|canceled)$/i.test(parsed.status || '')) return false;
158
+ return !(hasAgentResponseResultText(result) || hasAgentResponseResultText(text));
159
+ }
160
+
161
+ export function hasAgentResponseResultText(text) {
162
+ const value = String(text || '').trim();
163
+ if (!value) return false;
164
+ if (/^status:\s*(?:running|pending|queued|completed|failed|cancelled|canceled)(?:\s*·\s*task_id:\s*\S+)?$/i.test(value)) return false;
165
+ if (/^(?:background task\b|agent task:|task_id:)/i.test(value) && !/\n\s*\n[\s\S]*\S/.test(value)) return false;
166
+ return true;
167
+ }
168
+
169
+ export function bracketField(text, name) {
170
+ const re = new RegExp(`^\\[${name}:\\s*([^\\]]*)\\]`, 'mi');
171
+ return re.exec(String(text ?? ''))?.[1]?.trim() || '';
172
+ }
173
+
174
+ export function toolResultStatus(text) {
175
+ const value = String(text ?? '');
176
+ const tagged = textBetweenTag(value, 'status');
177
+ if (tagged) return tagged.trim();
178
+ const bracketed = bracketField(value, 'status');
179
+ if (bracketed) return bracketed.trim();
180
+ const inline = /^(?:status|state):\s*([^\s·,;]+)/mi.exec(value);
181
+ return inline ? inline[1].trim() : '';
182
+ }
183
+
184
+ export function isErrorToolStatus(status) {
185
+ return /^(failed|error|timeout|cancelled|canceled|killed)$/i.test(String(status || '').trim());
186
+ }
187
+
188
+ export function parseSyntheticAgentMessage(text) {
189
+ const value = String(text ?? '').trim();
190
+ if (!value) return null;
191
+ const finalAnswer = textBetweenTag(value, 'final-answer');
192
+ if (finalAnswer) {
193
+ return {
194
+ name: 'agent',
195
+ label: 'final',
196
+ args: { type: 'read', description: 'agent result' },
197
+ result: finalAnswer,
198
+ };
199
+ }
200
+ const agentResult = parseAgentResultEnvelope(value);
201
+ if (agentResult) return agentResult;
202
+ const backgroundTask = parseBackgroundTaskEnvelope(value);
203
+ if (backgroundTask) return backgroundTask;
204
+ const shellTaskId = bracketField(value, 'task_id');
205
+ if (shellTaskId) {
206
+ const status = bracketField(value, 'status') || 'done';
207
+ const exit = bracketField(value, 'exit');
208
+ const command = bracketField(value, 'command');
209
+ return {
210
+ name: 'shell',
211
+ label: status,
212
+ args: { type: 'result', task_id: shellTaskId, command },
213
+ result: value,
214
+ isError: /^(failed|error|timeout|cancelled|killed)$/i.test(status) || (exit && exit !== '0' && exit !== 'n/a'),
215
+ };
216
+ }
217
+ const agentJob = parseAgentJob(value);
218
+ if (agentJob?.taskId) {
219
+ const label = agentJob.status || 'notification';
220
+ const result = agentJobResultText(value, agentJob);
221
+ return {
222
+ name: 'agent',
223
+ label,
224
+ args: agentArgsWithResultMetadata({ type: agentJob.type || 'notification', description: 'agent notification' }, agentJob),
225
+ result: result || agentJobStatusText(agentJob) || 'agent notification',
226
+ isError: /^(failed|error|timeout|cancelled|killed)$/i.test(label),
227
+ };
228
+ }
229
+ if (/<task-notification\b/i.test(value)) {
230
+ const status = textBetweenTag(value, 'status') || 'completed';
231
+ const summary = textBetweenTag(value, 'summary') || `Agent ${status}`;
232
+ const taskId = textBetweenTag(value, 'task-id');
233
+ const result = stripSyntheticAgentTags(value);
234
+ return {
235
+ name: 'agent',
236
+ label: status,
237
+ taskId,
238
+ summary,
239
+ result: result || summary,
240
+ };
241
+ }
242
+ return null;
243
+ }
244
+
245
+ export function parseAgentJob(text) {
246
+ const value = String(text || '');
247
+ const idMatch = /^agent task:\s*([^\s]+)/m.exec(value) || /^task_id:\s*([^\s]+)/m.exec(value);
248
+ if (!idMatch) return null;
249
+ const statusMatch = /^status:\s*([^\s(]+)/m.exec(value);
250
+ const typeMatch = /^type:\s*(.+)$/m.exec(value);
251
+ const targetMatch = /^target:\s*(.+)$/m.exec(value);
252
+ const agentMatch = /^agent:\s*(.+)$/m.exec(value);
253
+ const presetMatch = /^preset:\s*(.+)$/m.exec(value);
254
+ const modelMatch = /^model:\s*([^/\s]+)\/(.+)$/m.exec(value);
255
+ const effortMatch = /^effort:\s*(.+)$/m.exec(value);
256
+ const fastMatch = /^fast:\s*(on|off|true|false)$/m.exec(value);
257
+ return {
258
+ taskId: idMatch[1],
259
+ status: (statusMatch?.[1] || '').toLowerCase(),
260
+ type: (typeMatch?.[1] || '').trim(),
261
+ target: (targetMatch?.[1] || '').trim(),
262
+ agent: (agentMatch?.[1] || '').trim(),
263
+ preset: (presetMatch?.[1] || '').trim(),
264
+ provider: (modelMatch?.[1] || '').trim(),
265
+ model: (modelMatch?.[2] || '').trim(),
266
+ effort: (effortMatch?.[1] || '').trim(),
267
+ fast: fastMatch ? /^(on|true)$/i.test(fastMatch[1]) : undefined,
268
+ };
269
+ }
270
+
271
+ export function agentArgsWithResultMetadata(args, parsed) {
272
+ if (!parsed) return args;
273
+ const next = { ...(args && typeof args === 'object' ? args : {}) };
274
+ const requestedAction = String(next.type || next.action || next.mode || '').trim().toLowerCase();
275
+ if (parsed.type) {
276
+ // Job status envelopes report the original job type (usually "spawn").
277
+ // Preserve the user's current agent tool action ("status", "read", …) so
278
+ // manual checks render as "Reviewer status" instead of another
279
+ // "Spawning Reviewer" card. Keep the job type as metadata for detail.
280
+ if (!requestedAction || /^(notification|result|completion)$/i.test(requestedAction)) next.type = parsed.type;
281
+ else next.jobType = parsed.type;
282
+ }
283
+ if (parsed.status) next.status = parsed.status;
284
+ if (parsed.taskId) next.task_id = parsed.taskId;
285
+ if (parsed.agent) next.agent = parsed.agent;
286
+ if (parsed.preset) next.preset = parsed.preset;
287
+ if (parsed.provider) next.provider = parsed.provider;
288
+ if (parsed.model) next.model = parsed.model;
289
+ if (parsed.effort) next.effort = parsed.effort;
290
+ if (parsed.fast !== undefined) next.fast = parsed.fast;
291
+ if (!next.tag && parsed.target) {
292
+ const target = parsed.target.split(/\s+/)[0];
293
+ if (target && !target.startsWith('sess_')) next.tag = target;
294
+ }
295
+ return next;
296
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * src/tui/engine/agent-job-feed.mjs — agent-job / runtime-notification plumbing
3
+ * extracted from createEngineSession (engine.mjs) as a dependency-injection
4
+ * factory.
5
+ *
6
+ * Owns: the agent-job card result patch (updateAgentJobCard), the
7
+ * execution-pending-resume kick trio (kick / flushDeferred / schedule), and the
8
+ * runtime.onNotification subscription that routes runtime notifications into the
9
+ * store (status refresh, execution-ui synthetic items, model-visible enqueue).
10
+ *
11
+ * These handlers mutate live session state and drive the queue, so
12
+ * state/set/enqueue/drain/pushUserOrSyntheticItem/patchItem/etc are threaded via
13
+ * the factory argument (getters/callbacks) — never stale snapshots. Every body
14
+ * is the original engine.mjs logic verbatim.
15
+ */
16
+ import {
17
+ parseAgentJob,
18
+ agentJobResultText,
19
+ agentArgsWithResultMetadata,
20
+ } from './agent-envelope.mjs';
21
+ import { toolErrorDisplay } from './tool-result-text.mjs';
22
+ import {
23
+ notificationQueueKey,
24
+ resolveTuiRuntimeNotificationDelivery,
25
+ } from './notification-plan.mjs';
26
+
27
+ export function createAgentJobFeed({
28
+ runtime,
29
+ getState,
30
+ set,
31
+ nextId,
32
+ getDisposed,
33
+ patchItem,
34
+ enqueue,
35
+ drain,
36
+ pushUserOrSyntheticItem,
37
+ makeQueueEntry,
38
+ getPending,
39
+ agentStatusState,
40
+ displayedExecutionNotificationKeys,
41
+ }) {
42
+ let executionResumeKickDeferred = false;
43
+
44
+ function kickExecutionPendingResume() {
45
+ if (getDisposed()) return;
46
+ if (getState().busy) {
47
+ executionResumeKickDeferred = true;
48
+ return;
49
+ }
50
+ const pending = getPending();
51
+ if (pending.some((entry) => entry.mode === 'pending-resume')) {
52
+ executionResumeKickDeferred = true;
53
+ return;
54
+ }
55
+ executionResumeKickDeferred = false;
56
+ pending.push(makeQueueEntry('', { mode: 'pending-resume', priority: 'next' }));
57
+ void drain();
58
+ }
59
+
60
+ function flushDeferredExecutionPendingResumeKick() {
61
+ if (!executionResumeKickDeferred || getDisposed() || getState().busy) return;
62
+ kickExecutionPendingResume();
63
+ }
64
+
65
+ function scheduleExecutionPendingResumeKick() {
66
+ // notifyFnForSession enqueues the model-visible body after onNotification
67
+ // returns; defer the kick so askSession pre-drain sees session pending.
68
+ queueMicrotask(() => kickExecutionPendingResume());
69
+ }
70
+
71
+ function updateAgentJobCard(itemId, text, isError = false) {
72
+ const parsed = parseAgentJob(text);
73
+ const current = getState().items.find((it) => it.id === itemId);
74
+ const rawDisplayText = agentJobResultText(text, parsed) || String(text ?? '').trim();
75
+ const displayText = isError ? toolErrorDisplay(rawDisplayText, 'agent') : rawDisplayText;
76
+ patchItem(itemId, {
77
+ result: displayText,
78
+ text: displayText,
79
+ isError,
80
+ errorCount: isError ? 1 : 0,
81
+ ...(parsed ? { args: agentArgsWithResultMetadata(current?.args, parsed) } : {}),
82
+ });
83
+ }
84
+
85
+ function subscribeRuntimeNotifications() {
86
+ if (typeof runtime.onNotification !== 'function') return null;
87
+ return runtime.onNotification((event) => {
88
+ if (getDisposed()) return;
89
+ const text = String(event?.content ?? event?.text ?? event ?? '').trim();
90
+ if (!text) return;
91
+ const parsed = parseAgentJob(text);
92
+ const notificationKey = notificationQueueKey(event, text, parsed);
93
+ const delivery = resolveTuiRuntimeNotificationDelivery(event, text);
94
+ if (delivery.action === 'ignore') return;
95
+ if (delivery.action === 'status-only') {
96
+ if (parsed?.taskId) set(agentStatusState({ force: true }));
97
+ return true;
98
+ }
99
+ if (delivery.action === 'execution-ui') {
100
+ const firstDelivery = !notificationKey || !displayedExecutionNotificationKeys.has(notificationKey);
101
+ if (firstDelivery) {
102
+ if (notificationKey) displayedExecutionNotificationKeys.add(notificationKey);
103
+ pushUserOrSyntheticItem(delivery.displayText, nextId());
104
+ }
105
+ if (parsed?.taskId) set(agentStatusState({ force: true }));
106
+ if (String(delivery.modelContent || '').trim()) {
107
+ scheduleExecutionPendingResumeKick();
108
+ }
109
+ return true;
110
+ }
111
+ if (parsed?.taskId) {
112
+ set(agentStatusState({ force: true }));
113
+ }
114
+ const modelContent = String(delivery.modelContent ?? delivery.displayText ?? text).trim();
115
+ if (!modelContent) return true;
116
+ enqueue(modelContent, {
117
+ mode: 'task-notification',
118
+ priority: 'next',
119
+ key: notificationKey || undefined,
120
+ displayText: delivery.displayText || text,
121
+ });
122
+ return true;
123
+ });
124
+ }
125
+
126
+ return {
127
+ kickExecutionPendingResume,
128
+ flushDeferredExecutionPendingResumeKick,
129
+ scheduleExecutionPendingResumeKick,
130
+ updateAgentJobCard,
131
+ subscribeRuntimeNotifications,
132
+ };
133
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * src/tui/engine/boot-profile.mjs - opt-in boot timing trace.
3
+ *
4
+ * Extracted from engine.mjs. Emits `[mixdog-boot]` stderr lines when
5
+ * MIXDOG_BOOT_PROFILE is truthy; a no-op otherwise.
6
+ */
7
+ import { performance } from 'node:perf_hooks';
8
+
9
+ const BOOT_PROFILE_ENABLED = /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_BOOT_PROFILE || ''));
10
+ const BOOT_PROFILE_START = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance.now());
11
+
12
+ export function bootProfile(event, fields = {}) {
13
+ if (!BOOT_PROFILE_ENABLED) return;
14
+ const elapsedMs = performance.now() - BOOT_PROFILE_START;
15
+ const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, `tui:${event}`];
16
+ for (const [key, value] of Object.entries(fields || {})) {
17
+ if (value === undefined || value === null || value === '') continue;
18
+ parts.push(`${key}=${String(value).replace(/\s+/g, '_')}`);
19
+ }
20
+ try { process.stderr.write(`${parts.join(' ')}\n`); } catch {}
21
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * src/tui/engine/labels.mjs - spinner verbs, elapsed formatting, and compact
3
+ * event label/detail helpers. Extracted from engine.mjs.
4
+ */
5
+ import { SPINNER_VERBS } from '../spinner-verbs.mjs';
6
+
7
+ export function pickVerb(turn) {
8
+ return SPINNER_VERBS[(turn * 7 + 3) % SPINNER_VERBS.length];
9
+ }
10
+
11
+ const TURN_DONE_VERBS = [
12
+ 'Thought',
13
+ 'Reasoned',
14
+ 'Mapped',
15
+ 'Checked',
16
+ 'Solved',
17
+ 'Composed',
18
+ 'Synthesized',
19
+ 'Wrapped',
20
+ ];
21
+
22
+ export function pickDoneVerb(turn) {
23
+ return TURN_DONE_VERBS[(turn * 5 + 2) % TURN_DONE_VERBS.length];
24
+ }
25
+
26
+ export function formatElapsedSeconds(ms) {
27
+ const value = Math.max(0, Number(ms) || 0);
28
+ if (value <= 0) return '0s';
29
+ return `${Math.max(1, Math.ceil(value / 1000))}s`;
30
+ }
31
+
32
+ export function compactEventLabel(event = {}) {
33
+ const status = String(event.status || '').toLowerCase();
34
+ const reactive = String(event.trigger || '').toLowerCase() === 'reactive';
35
+ if (status === 'failed') return reactive ? 'Compact failed (overflow retry)' : 'Compact failed';
36
+ if (status === 'skipped') return 'Compact skipped';
37
+ if (status === 'no_change') return 'Compact checked';
38
+ return reactive ? 'Compact complete (overflow recovery)' : 'Compact complete';
39
+ }
40
+
41
+ export function compactEventDetail(event = {}) {
42
+ // Keep the elapsed time as the lead detail, but no longer discard the rest of
43
+ // the compact metadata. Surface type/trigger and the boundary/pressure so the
44
+ // statusdone marker reflects what actually fired.
45
+ const parts = [];
46
+ const elapsed = formatElapsedSeconds(Number(event.durationMs ?? event.elapsedMs ?? 0));
47
+ if (elapsed) parts.push(elapsed);
48
+ const type = String(event.compactType || event.type || '').trim();
49
+ if (type && type !== 'semantic') parts.push(type);
50
+ const trigger = String(event.trigger || '').toLowerCase();
51
+ if (trigger === 'reactive') parts.push('reactive');
52
+ else if (trigger === 'manual') parts.push('manual');
53
+ const before = Number(event.beforeTokens ?? event.pressureTokens ?? 0);
54
+ const after = Number(event.afterTokens ?? 0);
55
+ const fmtTok = (n) => {
56
+ const v = Number(n) || 0;
57
+ if (v >= 1000) return `${(v / 1000).toFixed(v >= 10_000 ? 0 : 1)}k`;
58
+ return `${Math.round(v)}`;
59
+ };
60
+ if (before > 0 && after > 0 && after !== before) parts.push(`${fmtTok(before)}→${fmtTok(after)}`);
61
+ return parts.join(' · ');
62
+ }
63
+
64
+ export function projectNameFromPath(value) {
65
+ const text = String(value || '').replace(/[\\/]+$/, '');
66
+ return text.split(/[\\/]/).pop() || text || '(current)';
67
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * src/tui/engine/notice-text.mjs - polish user-facing failure/notice text.
3
+ * Extracted from engine.mjs.
4
+ */
5
+ const FAILED_NOTICE_ACTIONS = new Map([
6
+ ['api key save', 'save API key'],
7
+ ['auth-forget', 'forget auth'],
8
+ ['auto-clear', 'update auto-clear'],
9
+ ['autoclear', 'update auto-clear'],
10
+ ['agent', 'run agent command'],
11
+ ['channels', 'load channels'],
12
+ ['channels update', 'update channels'],
13
+ ['clear', 'clear chat'],
14
+ ['compact', 'compact context'],
15
+ ['copy', 'copy'],
16
+ ['core memory', 'load core memory'],
17
+ ['cwd', 'update working directory'],
18
+ ['effort switch', 'switch effort'],
19
+ ['fast', 'update fast mode'],
20
+ ['hook rule update', 'update hook rule'],
21
+ ['hook toggle', 'toggle hook'],
22
+ ['hook update', 'update hook'],
23
+ ['hooks status', 'load hooks'],
24
+ ['local provider update', 'update local provider'],
25
+ ['mcp add', 'add MCP server'],
26
+ ['mcp reconnect', 'reconnect MCP server'],
27
+ ['mcp status', 'load MCP status'],
28
+ ['mcp toggle', 'toggle MCP server'],
29
+ ['memory', 'run memory command'],
30
+ ['memory status', 'load memory status'],
31
+ ['model save', 'save model'],
32
+ ['model switch', 'switch model'],
33
+ ['oauth code', 'finish OAuth login'],
34
+ ['oauth login', 'start OAuth login'],
35
+ ['output style switch', 'switch output style'],
36
+ ['OpenAI usage auth save', 'save OpenAI usage auth'],
37
+ ['OpenCode Go usage auth save', 'save OpenCode Go usage auth'],
38
+ ['plugin add', 'add plugin'],
39
+ ['plugin MCP enable', 'enable plugin MCP'],
40
+ ['plugin uninstall', 'uninstall plugin'],
41
+ ['plugin update', 'update plugin'],
42
+ ['plugins status', 'load plugins'],
43
+ ['providers', 'load providers'],
44
+ ['recall', 'run recall'],
45
+ ['resume', 'resume chat'],
46
+ ['schedule toggle', 'toggle schedule'],
47
+ ['setup save', 'save setup'],
48
+ ['settings update', 'update settings'],
49
+ ['skill add', 'add skill'],
50
+ ['skills status', 'load skills'],
51
+ ['tools status', 'load tool status'],
52
+ ['usage', 'load usage'],
53
+ ['webhook toggle', 'toggle webhook'],
54
+ ['workflow switch', 'switch workflow'],
55
+ ]);
56
+
57
+ function polishNoticeAction(action) {
58
+ const value = String(action || '').trim();
59
+ if (!value) return 'finish';
60
+ const key = value.toLowerCase();
61
+ for (const [candidate, replacement] of FAILED_NOTICE_ACTIONS.entries()) {
62
+ if (candidate.toLowerCase() === key) return replacement;
63
+ }
64
+ const suffixes = [
65
+ [' save', 'save'],
66
+ [' switch', 'switch'],
67
+ [' update', 'update'],
68
+ [' toggle', 'toggle'],
69
+ [' reconnect', 'reconnect'],
70
+ [' enable', 'enable'],
71
+ [' uninstall', 'uninstall'],
72
+ [' add', 'add'],
73
+ ];
74
+ for (const [suffix, verb] of suffixes) {
75
+ if (!key.endsWith(suffix)) continue;
76
+ const subject = value.slice(0, -suffix.length).trim();
77
+ return subject ? `${verb} ${subject}` : verb;
78
+ }
79
+ return value;
80
+ }
81
+
82
+ function sentenceStart(text) {
83
+ const value = String(text || '').trim();
84
+ return value ? `${value[0].toUpperCase()}${value.slice(1)}` : value;
85
+ }
86
+
87
+ export function polishNoticeText(text) {
88
+ let value = String(text ?? '').trim().replace(/^✓\s*/, '');
89
+ if (!value) return '';
90
+ const error = /^error\s*:\s*(.+)$/i.exec(value);
91
+ if (error?.[1]) value = error[1].trim();
92
+ const couldNot = /^could not\s+(.+?)(?::\s*(.+))?$/i.exec(value);
93
+ if (couldNot) {
94
+ return couldNot[2]
95
+ ? `Couldn’t ${couldNot[1]}: ${couldNot[2]}`
96
+ : `Couldn’t ${couldNot[1]}.`;
97
+ }
98
+ const failed = /^(.+?)\s+failed(?::\s*(.+))?$/i.exec(value);
99
+ if (failed) {
100
+ const action = polishNoticeAction(failed[1]);
101
+ return failed[2] ? `Couldn’t ${action}: ${failed[2]}` : `Couldn’t ${action}.`;
102
+ }
103
+ const busy = /^(.+?)\s+already in progress\.?$/i.exec(value);
104
+ if (busy) return `${sentenceStart(polishNoticeAction(busy[1]))} is already running.`;
105
+ const required = /^(.+?)\s+is required(?:\s+for\s+(.+))?\.?$/i.exec(value);
106
+ if (required) {
107
+ const subject = required[1].trim();
108
+ const target = required[2]?.trim();
109
+ return `${subject}${target ? ` required for ${target}` : ' required'}.`;
110
+ }
111
+ return value;
112
+ }