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,7 +11,7 @@ import { buildHeadlessSpawnArgs } from '../src/headless-role.mjs';
11
11
  import { createStandaloneChannelWorker } from '../src/standalone/channel-worker.mjs';
12
12
  import { OpenAIOAuthProvider, buildRequestBody, sendViaHttpSse } from '../src/runtime/agent/orchestrator/providers/openai-oauth.mjs';
13
13
  import { _test as _anthropicOAuthTest } from '../src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs';
14
- import { _logicalResponseItemMatch, _resolveOpenAiPromptCacheRatePolicy } from '../src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs';
14
+ import { _logicalResponseItemMatch } from '../src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs';
15
15
  import { _mergePendingMessageEntries, applyAskTerminalUsageTotals, closeSession, createSession, drainPendingMessages, enqueuePendingMessage, resumeSession } from '../src/runtime/agent/orchestrator/session/manager.mjs';
16
16
  import {
17
17
  contentHasImage,
@@ -137,46 +137,6 @@ function assertOk(name, result, pattern = null) {
137
137
  }
138
138
 
139
139
  {
140
- const fullPolicy = _resolveOpenAiPromptCacheRatePolicy({}, {
141
- mode: 'full',
142
- frameInputItems: 40,
143
- deltaTokens: 9000,
144
- hasPreviousResponseId: false,
145
- });
146
- assert(fullPolicy.policy === 'full_guard' && fullPolicy.limitPerMin === 12, `full cache lane should keep 12rpm guard: ${JSON.stringify(fullPolicy)}`);
147
-
148
- const deltaPolicy = _resolveOpenAiPromptCacheRatePolicy({}, {
149
- mode: 'delta',
150
- frameInputItems: 1,
151
- deltaTokens: 9000,
152
- hasPreviousResponseId: true,
153
- });
154
- assert(deltaPolicy.policy === 'delta_relaxed' && deltaPolicy.limitPerMin === 60, `small delta should use relaxed cache lane rpm: ${JSON.stringify(deltaPolicy)}`);
155
-
156
- const largeDeltaPolicy = _resolveOpenAiPromptCacheRatePolicy({}, {
157
- mode: 'delta',
158
- frameInputItems: 20,
159
- deltaTokens: 9000,
160
- hasPreviousResponseId: true,
161
- });
162
- assert(largeDeltaPolicy.policy === 'delta_guarded' && largeDeltaPolicy.limitPerMin === 12, `large delta should fall back to full guard: ${JSON.stringify(largeDeltaPolicy)}`);
163
-
164
- const customDeltaPolicy = _resolveOpenAiPromptCacheRatePolicy({ openaiCacheLaneDeltaRateLimitPerMin: 90 }, {
165
- mode: 'delta',
166
- frameInputItems: 1,
167
- deltaTokens: 9000,
168
- hasPreviousResponseId: true,
169
- });
170
- assert(customDeltaPolicy.limitPerMin === 90, `custom delta rpm should be honored: ${JSON.stringify(customDeltaPolicy)}`);
171
-
172
- const unlimitedDeltaPolicy = _resolveOpenAiPromptCacheRatePolicy({ openaiCacheLaneDeltaRateLimitPerMin: 0 }, {
173
- mode: 'delta',
174
- frameInputItems: 1,
175
- deltaTokens: 9000,
176
- hasPreviousResponseId: true,
177
- });
178
- assert(unlimitedDeltaPolicy.policy === 'delta_unlimited' && unlimitedDeltaPolicy.limitPerMin === 0, `delta rpm=0 should disable delta rate wait: ${JSON.stringify(unlimitedDeltaPolicy)}`);
179
-
180
140
  const originalFunctionCall = {
181
141
  type: 'function_call',
182
142
  call_id: 'call_tool_1',
@@ -589,20 +549,28 @@ if (grepContextPolicyArgs['-C'] !== GREP_CONTEXT_MAX || Object.prototype.hasOwnP
589
549
  throw new Error(`grep context policy must canonicalize and clamp explicit context: ${JSON.stringify(grepContextPolicyArgs)}`);
590
550
  }
591
551
 
592
- const invalidGrepPath = validateBuiltinArgs('grep', {
552
+ // Multiple absolute paths in one string are now auto-split into a path array
553
+ // (arg-guard splitMultipleAbsoluteWindowsPaths) instead of rejected.
554
+ const multiGrepPathArgs = {
593
555
  pattern: 'providerStatus',
594
556
  path: 'C:\\Project\\mixdog\\src\\tui C:\\Project\\mixdog\\src\\mixdog-session-runtime.mjs',
595
- });
596
- if (!/multiple absolute paths/i.test(invalidGrepPath || '')) {
597
- throw new Error(`grep multi-path guard failed: ${invalidGrepPath}`);
557
+ };
558
+ const multiGrepPathErr = validateBuiltinArgs('grep', multiGrepPathArgs);
559
+ if (multiGrepPathErr) {
560
+ throw new Error(`grep multi-path auto-split should pass validation: ${multiGrepPathErr}`);
561
+ }
562
+ if (!Array.isArray(multiGrepPathArgs.path) || multiGrepPathArgs.path.length !== 2) {
563
+ throw new Error(`grep multi-path auto-split should coerce to 2-element array: ${JSON.stringify(multiGrepPathArgs.path)}`);
598
564
  }
599
565
 
600
- const invalidGrepLookaround = validateBuiltinArgs('grep', {
566
+ // Lookaround/backrefs are no longer rejected at validation time: search-tool
567
+ // routes them to rg --pcre2 at runtime (arg-guard.mjs comment near globKeys).
568
+ const lookaroundGrepErr = validateBuiltinArgs('grep', {
601
569
  pattern: 'C:\\\\Project(?!\\\\mixdog)',
602
570
  path: root,
603
571
  });
604
- if (!/lookaround\/backrefs/i.test(invalidGrepLookaround || '')) {
605
- throw new Error(`grep unsupported-regex guard failed: ${invalidGrepLookaround}`);
572
+ if (lookaroundGrepErr) {
573
+ throw new Error(`grep lookaround pattern should pass validation (PCRE2 runtime routing): ${lookaroundGrepErr}`);
606
574
  }
607
575
 
608
576
  // Windows drive path + no explicit shell used to be rejected with a retry hint;
@@ -747,7 +715,7 @@ if (agentProps.mode || agentProps.wait) throw new Error('agent schema should not
747
715
  agentRules: '# Tool Use',
748
716
  skillManifest: '',
749
717
  });
750
- if (!heavyPrompt.stableSystemContext.includes('## heavy-worker') || !heavyPrompt.stableSystemContext.includes('Handoff fragments only')) {
718
+ if (!heavyPrompt.stableSystemContext.includes('## heavy-worker')) {
751
719
  throw new Error(`heavy-worker AGENT.md must be included in scoped role instructions: ${heavyPrompt.stableSystemContext}`);
752
720
  }
753
721
  const workerPrompt = composeSystemPrompt({
@@ -756,7 +724,7 @@ if (agentProps.mode || agentProps.wait) throw new Error('agent schema should not
756
724
  agentRules: '# Tool Use',
757
725
  skillManifest: '',
758
726
  });
759
- if (!workerPrompt.stableSystemContext.includes('## worker') || !workerPrompt.stableSystemContext.includes('Handoff fragments only')) {
727
+ if (!workerPrompt.stableSystemContext.includes('## worker')) {
760
728
  throw new Error(`worker AGENT.md must be included in scoped role instructions: ${workerPrompt.stableSystemContext}`);
761
729
  }
762
730
  }
@@ -991,10 +959,7 @@ setInternalToolsProvider({
991
959
  { name: 'recall', description: 'Memory recall surface.', inputSchema: { type: 'object', properties: {} }, annotations: { readOnlyHint: true } },
992
960
  { name: 'search', description: 'Web search surface.', inputSchema: { type: 'object', properties: {} }, annotations: { readOnlyHint: true, openWorldHint: true } },
993
961
  { name: 'reply', description: 'Channel reply surface.', inputSchema: { type: 'object', properties: {} }, annotations: { destructiveHint: true } },
994
- { name: 'edit_message', description: 'Channel edit surface.', inputSchema: { type: 'object', properties: {} }, annotations: { destructiveHint: true } },
995
962
  { name: 'web_fetch', description: 'Web fetch surface.', inputSchema: { type: 'object', properties: {} }, annotations: { readOnlyHint: true, openWorldHint: true } },
996
- { name: 'reload_config', description: 'Config reload surface.', inputSchema: { type: 'object', properties: {} }, annotations: { destructiveHint: true } },
997
- { name: 'inject_command', description: 'Command injection surface.', inputSchema: { type: 'object', properties: {} }, annotations: { destructiveHint: true } },
998
963
  ],
999
964
  });
1000
965
  {
@@ -1091,7 +1056,7 @@ setInternalToolsProvider({
1091
1056
  if (!/Read-only retrieval role/i.test(visible) || /# environment/i.test(visible) || /git operations deferred to Lead/i.test(visible)) {
1092
1057
  throw new Error(`explorer hidden retrieval context should stay slim: ${visible.slice(0, 1200)}`);
1093
1058
  }
1094
- if (!/# Role: explorer/i.test(systemVisible) || /# Role: explorer/i.test(userReminderVisible) || !/Locator only/i.test(systemVisible)) {
1059
+ if (!/# Role: explorer/i.test(systemVisible) || /# Role: explorer/i.test(userReminderVisible) || !/one-shot locator/i.test(systemVisible)) {
1095
1060
  throw new Error(`explorer role md must ride BP2 system, not BP3 user reminder: system=${systemVisible.slice(0, 600)} user=${userReminderVisible.slice(0, 600)}`);
1096
1061
  }
1097
1062
  const visibleBytes = Buffer.byteLength(visible, 'utf8');
@@ -1197,12 +1162,12 @@ setInternalToolsProvider({
1197
1162
  if (readTools.includes('shell') || writeTools.includes('shell')) {
1198
1163
  throw new Error(`read/read-write agent schemas must omit shell: read=${readTools.join(', ')} write=${writeTools.join(', ')}`);
1199
1164
  }
1200
- for (const name of ['shell', 'apply_patch', 'task', 'diagnostics', 'open_config']) {
1165
+ for (const name of ['shell', 'apply_patch', 'task']) {
1201
1166
  if (readTools.includes(name)) {
1202
1167
  throw new Error(`read agent schema must omit non-read tool ${name}: read=${readTools.join(', ')}`);
1203
1168
  }
1204
1169
  }
1205
- for (const name of ['apply_patch', 'task', 'diagnostics']) {
1170
+ for (const name of ['apply_patch', 'task']) {
1206
1171
  if (name === 'apply_patch' && !writeTools.includes(name)) {
1207
1172
  throw new Error(`read-write agent schema must preserve apply_patch: write=${writeTools.join(', ')}`);
1208
1173
  }
@@ -1210,12 +1175,7 @@ setInternalToolsProvider({
1210
1175
  throw new Error(`read-write agent schema must omit non-edit tool ${name}: write=${writeTools.join(', ')}`);
1211
1176
  }
1212
1177
  }
1213
- for (const name of ['open_config']) {
1214
- if (writeTools.includes(name)) {
1215
- throw new Error(`read-write agent schema must omit config/skill tool ${name}: write=${writeTools.join(', ')}`);
1216
- }
1217
- }
1218
- for (const name of ['memory', 'recall', 'reply', 'edit_message', 'reload_config', 'inject_command']) {
1178
+ for (const name of ['memory', 'recall', 'reply']) {
1219
1179
  if (readTools.includes(name) || writeTools.includes(name)) {
1220
1180
  throw new Error(`read/read-write agent schema must not expose full-runtime internal tool ${name}: read=${readTools.join(', ')} write=${writeTools.join(', ')}`);
1221
1181
  }
@@ -1293,7 +1253,7 @@ setInternalToolsProvider({
1293
1253
  const hiddenAgents = JSON.parse(readFileSync(join(root, 'src', 'defaults', 'agents.json'), 'utf8')).agents || [];
1294
1254
  const hiddenPreset = { id: 'hidden-smoke', name: 'hidden-smoke', type: 'agent', provider: 'openai-oauth', model: 'tool-smoke-model', tools: 'full' };
1295
1255
  const hiddenRuntimeSpec = { scopeKey: 'hidden-role-smoke', lane: 'agent' };
1296
- const hiddenBadTools = new Set(['shell', 'task', 'diagnostics', 'open_config', 'Skill', 'memory', 'reply', 'edit_message', 'recall', 'reload_config', 'inject_command']);
1256
+ const hiddenBadTools = new Set(['shell', 'task', 'Skill', 'memory', 'reply', 'recall']);
1297
1257
  const expectedForHiddenAgent = (permission, schemaAllowedTools) => {
1298
1258
  if (Array.isArray(schemaAllowedTools)) return schemaAllowedTools.slice();
1299
1259
  if (permission === 'none') return [];
@@ -1434,9 +1394,12 @@ for (const requiredGrammarLine of [
1434
1394
  }
1435
1395
  const readPathSchema = BUILTIN_TOOLS.find((tool) => tool.name === 'read')?.inputSchema?.properties?.path || {};
1436
1396
  const readPathDescription = readPathSchema.description || '';
1437
- if (!/File path/i.test(readPathDescription) || !/\{path,offset,limit\}\[\]/i.test(readPathDescription) || !/Pass arrays directly/i.test(readPathDescription) || !/legacy recovery only/i.test(readPathDescription) || !/Dirs use list/i.test(readPathDescription)) {
1397
+ if (!/File path/i.test(readPathDescription) || !/\{path,offset,limit\}\[\]/i.test(readPathDescription) || !/Pass arrays directly/i.test(readPathDescription) || !/legacy recovery only/i.test(readPathDescription)) {
1438
1398
  throw new Error('read schema must keep directory-vs-file guidance');
1439
1399
  }
1400
+ if (!/Dirs use list/i.test((BUILTIN_TOOLS.find((tool) => tool.name === 'read')?.description) || '')) {
1401
+ throw new Error('read description must keep directory-vs-file guidance');
1402
+ }
1440
1403
  const readTool = BUILTIN_TOOLS.find((tool) => tool.name === 'read');
1441
1404
  const readDescription = readTool?.description || '';
1442
1405
  const readProps = readTool?.inputSchema?.properties || {};
@@ -1514,7 +1477,7 @@ if (!/before text grep/i.test(codeGraphDescription)) {
1514
1477
  if (!/repo-local/i.test(codeGraphDescription) || !/NOT web search|not web/i.test(codeGraphDescription)) {
1515
1478
  throw new Error('code_graph description must mark itself repo-local (not web search)');
1516
1479
  }
1517
- if (!/repo-local|not web/i.test(codeGraphProps.mode?.description || '') || !/source file/i.test(codeGraphProps.file?.description || '')) {
1480
+ if (!/repo-local|not web/i.test(codeGraphProps.mode?.description || '') || !/source file/i.test(codeGraphProps.files?.description || '')) {
1518
1481
  throw new Error('code_graph schema must keep compact, repo-local field descriptions');
1519
1482
  }
1520
1483
  const recallTool = MEMORY_TOOL_DEFS.find((tool) => tool.name === 'recall');
@@ -1585,7 +1548,7 @@ if (!recallProps.sessionOnly || !/session only/i.test(recallProps.sessionOnly?.d
1585
1548
  }
1586
1549
  const memoryTool = MEMORY_TOOL_DEFS.find((tool) => tool.name === 'memory');
1587
1550
  const memoryProps = memoryTool?.inputSchema?.properties || {};
1588
- if (!/explicit mutation/i.test(memoryTool?.description || '') || !/Destructive jobs require exact confirm/i.test(memoryTool?.description || '') || !/Exact confirmation phrase/i.test(memoryProps.confirm?.description || '')) {
1551
+ if (!/mutation/i.test(memoryTool?.description || '') || !/Exact confirmation phrase/i.test(memoryProps.confirm?.description || '')) {
1589
1552
  throw new Error('memory schema must preserve mutation/destructive confirmation guidance');
1590
1553
  }
1591
1554
  const searchTool = SEARCH_TOOL_DEFS.find((tool) => tool.name === 'search');
@@ -1780,7 +1743,7 @@ if (grepTool?.inputSchema?.properties?.head_limit?.minimum !== 0 || !/keep small
1780
1743
  if (grepTool?.inputSchema?.properties?.type) {
1781
1744
  throw new Error('grep type schema must stay hidden; prefer glob for extension narrowing');
1782
1745
  }
1783
- if (!/code flow before text search/i.test(codeGraphProps.mode?.description || '') || !/one anchor is enough/i.test(codeGraphProps.symbol?.description || '') || !/one call/i.test(codeGraphProps.symbols?.description || '')) {
1746
+ if (!/code flow before text search/i.test(codeGraphProps.mode?.description || '') || !/one anchor is enough/i.test(codeGraphProps.symbols?.description || '') || !/one call/i.test(codeGraphProps.symbols?.description || '')) {
1784
1747
  throw new Error('code_graph schema fields must steer away from repeated lookup loops');
1785
1748
  }
1786
1749
 
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/tui-render-smoke.mjs — undeclared-identifier gate for the TUI bundle.
4
+ *
5
+ * Why: esbuild does not flag free (undeclared) identifiers in JSX modules —
6
+ * they may legitimately be runtime globals — and no smoke actually renders
7
+ * App. That gap shipped two ReferenceErrors (promptContentRows,
8
+ * TRANSCRIPT_WINDOW_OVERSCAN_ROWS) during the App.jsx split.
9
+ *
10
+ * How: parse src/tui/dist/index.mjs with acorn, run eslint-scope, and fail on
11
+ * any reference that resolves to no binding and is not a known JS/Node/DOM
12
+ * global. Static, deterministic, no terminal or engine session needed.
13
+ *
14
+ * Run: node scripts/tui-render-smoke.mjs (or `npm run smoke:tui`)
15
+ * Exit: 0 = clean, 1 = undeclared identifiers found or bundle missing.
16
+ */
17
+ import { readFileSync, existsSync } from 'node:fs';
18
+ import { dirname, join } from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { parse } from 'acorn';
21
+ import { analyze } from 'eslint-scope';
22
+
23
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
24
+ const BUNDLE = join(ROOT, 'src', 'tui', 'dist', 'index.mjs');
25
+
26
+ // Globals that are legal free identifiers in the bundle. Anything outside
27
+ // this set that resolves to no binding is a guaranteed ReferenceError at
28
+ // runtime (module scope is strict; there is no window fallback in node ESM).
29
+ const KNOWN_GLOBALS = new Set([
30
+ // ECMAScript builtins
31
+ 'Array', 'ArrayBuffer', 'Atomics', 'BigInt', 'BigInt64Array', 'BigUint64Array', 'Boolean',
32
+ 'DataView', 'Date', 'Error', 'EvalError', 'FinalizationRegistry', 'Float32Array',
33
+ 'Float64Array', 'Function', 'Infinity', 'Int8Array', 'Int16Array', 'Int32Array',
34
+ 'Intl', 'JSON', 'Map', 'Math', 'NaN', 'Number', 'Object', 'Promise', 'Proxy',
35
+ 'RangeError', 'ReferenceError', 'Reflect', 'RegExp', 'Set', 'SharedArrayBuffer',
36
+ 'String', 'Symbol', 'SyntaxError', 'TypeError', 'URIError', 'Uint8Array',
37
+ 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', 'WeakRef', 'WeakSet',
38
+ 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'eval',
39
+ 'globalThis', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined',
40
+ // Node.js globals
41
+ 'AbortController', 'AbortSignal', 'Blob', 'Buffer', 'ByteLengthQueuingStrategy',
42
+ 'CompressionStream', 'CountQueuingStrategy', 'Crypto', 'CryptoKey', 'CustomEvent',
43
+ 'DecompressionStream', 'Event', 'EventTarget', 'File', 'FormData', 'Headers',
44
+ 'MessageChannel', 'MessageEvent', 'MessagePort', 'Navigator', 'PerformanceEntry',
45
+ 'PerformanceObserver', 'ReadableStream', 'ReadableStreamDefaultReader', 'Request',
46
+ 'Response', 'SubtleCrypto', 'TextDecoder', 'TextDecoderStream', 'TextEncoder',
47
+ 'TextEncoderStream', 'TransformStream', 'URL', 'URLSearchParams', 'WebAssembly',
48
+ 'WebSocket', 'WritableStream', 'atob', 'btoa', 'clearImmediate', 'clearInterval',
49
+ 'clearTimeout', 'console', 'crypto', 'fetch', 'navigator', 'performance',
50
+ 'process', 'queueMicrotask', 'require', 'setImmediate', 'setInterval',
51
+ 'setTimeout', 'structuredClone',
52
+ // Bundler/runtime artifacts occasionally referenced defensively
53
+ 'window', 'document', 'reportError',
54
+ ]);
55
+
56
+ if (!existsSync(BUNDLE)) {
57
+ console.error(`tui-render-smoke: FAIL — bundle not found at ${BUNDLE}; run \`npm run build:tui\` first`);
58
+ process.exit(1);
59
+ }
60
+
61
+ const source = readFileSync(BUNDLE, 'utf8');
62
+
63
+ let ast;
64
+ try {
65
+ ast = parse(source, { ecmaVersion: 'latest', sourceType: 'module', locations: true, ranges: true });
66
+ } catch (err) {
67
+ console.error(`tui-render-smoke: FAIL — bundle does not parse: ${err.message}`);
68
+ process.exit(1);
69
+ }
70
+
71
+ const scopeManager = analyze(ast, { ecmaVersion: 2022, sourceType: 'module' });
72
+ const unresolved = scopeManager.globalScope.through.filter(
73
+ (ref) => !KNOWN_GLOBALS.has(ref.identifier.name),
74
+ );
75
+
76
+ if (unresolved.length > 0) {
77
+ const seen = new Map();
78
+ for (const ref of unresolved) {
79
+ const { name } = ref.identifier;
80
+ if (!seen.has(name)) seen.set(name, ref.identifier.loc?.start);
81
+ }
82
+ console.error(`tui-render-smoke: FAIL — ${seen.size} undeclared identifier(s) in src/tui/dist/index.mjs:`);
83
+ for (const [name, loc] of seen) {
84
+ console.error(` ${name} (dist/index.mjs:${loc ? `${loc.line}:${loc.column}` : '?'})`);
85
+ }
86
+ console.error('These throw ReferenceError when the TUI renders. Fix missing imports in src/tui/ and rebuild.');
87
+ process.exit(1);
88
+ }
89
+
90
+ console.log('tui-render-smoke: ok — no undeclared identifiers in TUI bundle');
@@ -0,0 +1,208 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import * as crypto from 'node:crypto';
4
+ import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { readMarkdownDocument } from '../src/runtime/shared/markdown-frontmatter.mjs';
8
+
9
+ // DATA_DIR resolves from MIXDOG_DATA_DIR at module import time (via
10
+ // ./config.mjs -> resolvePluginData), so the env var MUST be set before
11
+ // the first dynamic import of webhook.mjs.
12
+ const dataDir = mkdtempSync(join(tmpdir(), 'mixdog-webhook-test-'));
13
+ process.env.MIXDOG_DATA_DIR = dataDir;
14
+
15
+ const {
16
+ extractSignature,
17
+ verifySignature,
18
+ loadEndpointConfig,
19
+ STRIPE_TOLERANCE_MS,
20
+ } = await import('../src/runtime/channels/lib/webhook.mjs');
21
+
22
+ function hmacHex(secret, payload) {
23
+ return crypto.createHmac('sha256', secret).update(payload).digest('hex');
24
+ }
25
+
26
+ // ── verifySignature: github/generic hex HMAC ──────────────────────────
27
+
28
+ test('verifySignature: github parser accepts a valid sha256 hex signature', () => {
29
+ const secret = 'shh';
30
+ const body = '{"hello":"world"}';
31
+ const sig = hmacHex(secret, body);
32
+ assert.equal(verifySignature(secret, body, sig, 'github'), true);
33
+ });
34
+
35
+ test('verifySignature: generic parser accepts a valid sha256 hex signature', () => {
36
+ const secret = 'shh';
37
+ const body = '{"hello":"world"}';
38
+ const sig = hmacHex(secret, body);
39
+ assert.equal(verifySignature(secret, body, sig, 'generic'), true);
40
+ });
41
+
42
+ test('verifySignature: github/generic reject a wrong signature', () => {
43
+ const secret = 'shh';
44
+ const body = '{"hello":"world"}';
45
+ const wrong = hmacHex('other-secret', body);
46
+ assert.equal(verifySignature(secret, body, wrong, 'github'), false);
47
+ });
48
+
49
+ test('verifySignature: length-mismatch hex signature returns false without throwing', () => {
50
+ const secret = 'shh';
51
+ const body = 'payload';
52
+ // Valid hex, wrong byte length vs the 32-byte sha256 digest.
53
+ assert.doesNotThrow(() => {
54
+ assert.equal(verifySignature(secret, body, 'ab', 'github'), false);
55
+ });
56
+ });
57
+
58
+ test('verifySignature: malformed (non-hex) signature returns false without throwing', () => {
59
+ const secret = 'shh';
60
+ const body = 'payload';
61
+ assert.doesNotThrow(() => {
62
+ assert.equal(verifySignature(secret, body, 'not-hex-zzzz', 'github'), false);
63
+ });
64
+ });
65
+
66
+ // ── verifySignature: stripe t= / v1= scheme ───────────────────────────
67
+
68
+ test('verifySignature: stripe accepts a valid t+v1 pair', () => {
69
+ const secret = 'stripe-secret';
70
+ const body = '{"id":"evt_1"}';
71
+ const t = Math.floor(Date.now() / 1000);
72
+ const v1 = hmacHex(secret, `${t}.${body}`);
73
+ assert.equal(verifySignature(secret, body, `t=${t},v1=${v1}`, 'stripe'), true);
74
+ });
75
+
76
+ test('verifySignature: stripe rejects a header missing t=', () => {
77
+ const secret = 'stripe-secret';
78
+ const body = '{"id":"evt_1"}';
79
+ const t = Math.floor(Date.now() / 1000);
80
+ const v1 = hmacHex(secret, `${t}.${body}`);
81
+ assert.equal(verifySignature(secret, body, `v1=${v1}`, 'stripe'), false);
82
+ });
83
+
84
+ test('verifySignature: stripe rejects a header missing v1=', () => {
85
+ const secret = 'stripe-secret';
86
+ const body = '{"id":"evt_1"}';
87
+ const t = Math.floor(Date.now() / 1000);
88
+ assert.equal(verifySignature(secret, body, `t=${t}`, 'stripe'), false);
89
+ });
90
+
91
+ test('verifySignature: stripe rejects a stale timestamp beyond the tolerance window (replay)', () => {
92
+ const secret = 'stripe-secret';
93
+ const body = '{"id":"evt_1"}';
94
+ const staleT = Math.floor((Date.now() - STRIPE_TOLERANCE_MS - 60_000) / 1000);
95
+ const v1 = hmacHex(secret, `${staleT}.${body}`);
96
+ assert.equal(verifySignature(secret, body, `t=${staleT},v1=${v1}`, 'stripe'), false);
97
+ });
98
+
99
+ test('verifySignature: stripe rejects a tampered v1 (HMAC mismatch) with a fresh t', () => {
100
+ const secret = 'stripe-secret';
101
+ const body = '{"id":"evt_1"}';
102
+ const t = Math.floor(Date.now() / 1000);
103
+ const tamperedV1 = hmacHex('wrong-secret', `${t}.${body}`);
104
+ assert.equal(verifySignature(secret, body, `t=${t},v1=${tamperedV1}`, 'stripe'), false);
105
+ });
106
+
107
+ // ── extractSignature: parser mapping + fallback scan ──────────────────
108
+
109
+ test('extractSignature: github parser strips the sha256= prefix from x-hub-signature-256', () => {
110
+ const headers = { 'x-hub-signature-256': 'sha256=deadbeef' };
111
+ assert.equal(extractSignature(headers, 'github'), 'deadbeef');
112
+ });
113
+
114
+ test('extractSignature: generic parser strips the sha256= prefix from x-signature-256', () => {
115
+ const headers = { 'x-signature-256': 'sha256=cafebabe' };
116
+ assert.equal(extractSignature(headers, 'generic'), 'cafebabe');
117
+ });
118
+
119
+ test('extractSignature: stripe parser returns the raw stripe-signature value (no prefix)', () => {
120
+ const headers = { 'stripe-signature': 't=1,v1=abc123' };
121
+ assert.equal(extractSignature(headers, 'stripe'), 't=1,v1=abc123');
122
+ });
123
+
124
+ test('extractSignature: sentry parser returns the raw sentry-hook-signature value', () => {
125
+ const headers = { 'sentry-hook-signature': 'raw-sig-value' };
126
+ assert.equal(extractSignature(headers, 'sentry'), 'raw-sig-value');
127
+ });
128
+
129
+ test('extractSignature: unknown parser name falls back to scanning all known headers', () => {
130
+ const headers = { 'x-signature-256': 'sha256=fallback-hit' };
131
+ assert.equal(extractSignature(headers, 'no-such-parser'), 'fallback-hit');
132
+ });
133
+
134
+ test('extractSignature: no parser given scans known headers in declaration order', () => {
135
+ const headers = { 'x-hub-signature-256': 'sha256=github-hit' };
136
+ assert.equal(extractSignature(headers, undefined), 'github-hit');
137
+ });
138
+
139
+ test('extractSignature: returns null when no known signature header is present', () => {
140
+ const headers = { 'x-some-other-header': 'value' };
141
+ assert.equal(extractSignature(headers, 'github'), null);
142
+ });
143
+
144
+ // ── endpoint config loader: WEBHOOK.md frontmatter + secret side file ─
145
+
146
+ test('loadEndpointConfig: loads frontmatter + reads secret from side file', () => {
147
+ const name = 'my-endpoint';
148
+ const dir = join(dataDir, 'webhooks', name);
149
+ mkdirSync(dir, { recursive: true });
150
+ writeFileSync(
151
+ join(dir, 'WEBHOOK.md'),
152
+ [
153
+ '---',
154
+ 'channel: main',
155
+ 'parser: github',
156
+ 'enabled: true',
157
+ '---',
158
+ '',
159
+ 'Handle this webhook by summarizing the payload.',
160
+ '',
161
+ ].join('\n'),
162
+ 'utf8',
163
+ );
164
+ writeFileSync(join(dir, 'secret'), 'my-webhook-secret\n', 'utf8');
165
+
166
+ const cfg = loadEndpointConfig(name);
167
+ assert.equal(cfg.channel, 'main');
168
+ assert.equal(cfg.parser, 'github');
169
+ assert.equal(cfg.enabled, true);
170
+ });
171
+
172
+ test('loadEndpointConfig: enabled: false frontmatter casts to boolean false', () => {
173
+ const name = 'disabled-endpoint';
174
+ const dir = join(dataDir, 'webhooks', name);
175
+ mkdirSync(dir, { recursive: true });
176
+ writeFileSync(
177
+ join(dir, 'WEBHOOK.md'),
178
+ ['---', 'channel: main', 'enabled: false', '---', '', 'body text', ''].join('\n'),
179
+ 'utf8',
180
+ );
181
+ const cfg = loadEndpointConfig(name);
182
+ assert.equal(cfg.enabled, false);
183
+ });
184
+
185
+ test('loadEndpointConfig: returns null for a name with no WEBHOOK.md', () => {
186
+ assert.equal(loadEndpointConfig('never-registered'), null);
187
+ });
188
+
189
+ // loadEndpointConfig only surfaces the frontmatter (by design — see
190
+ // webhook.mjs comment above loadEndpointConfig); confirm the underlying
191
+ // shared parser it delegates to also recovers the markdown body, since
192
+ // the loader's frontmatter/body split is not independently exercised
193
+ // through the exported loadEndpointConfig surface.
194
+ test('readMarkdownDocument: WEBHOOK.md-shaped input yields frontmatter + body', () => {
195
+ const raw = [
196
+ '---',
197
+ 'channel: main',
198
+ 'parser: github',
199
+ '---',
200
+ '',
201
+ 'Handle this webhook by summarizing the payload.',
202
+ '',
203
+ ].join('\n');
204
+ const { frontmatter, body } = readMarkdownDocument(raw);
205
+ assert.equal(frontmatter.channel, 'main');
206
+ assert.equal(frontmatter.parser, 'github');
207
+ assert.equal(body, 'Handle this webhook by summarizing the payload.');
208
+ });
@@ -7,5 +7,8 @@ permission: read
7
7
  Root-cause analysis agent.
8
8
 
9
9
  Smallest confirmed cause chain before fixes. Return likely cause, evidence
10
- (`file:line`), smallest next check/fix. Fragments only, no narration. Mark
11
- confirmed facts vs inferences; avoid broad speculation.
10
+ (`file:line`), smallest next check/fix. Mark confirmed facts vs inferences;
11
+ avoid broad speculation. Fragments only; no narration, no report bloat.
12
+
13
+ Converge, don't sweep: when new reads stop adding evidence, report the best
14
+ cause chain so far — a partial/blocked report is a valid completion.
@@ -1,11 +1,21 @@
1
- ---
2
- permission: read-write
3
- ---
4
-
5
- # Heavy Worker
6
- Broad implementation agent.
7
-
8
- Bounded slices; smallest coherent change, not rewrite. Stop: unclear scope,
9
- growing blast radius, or Lead-only verification. Minimal checks + how-to-verify.
10
- Handoff fragments only, no report bloat: changed `file:line`, verification, risks.
11
-
1
+ ---
2
+ permission: read-write
3
+ ---
4
+
5
+ # Heavy Worker
6
+ Broad implementation agent.
7
+
8
+ Bounded slices; smallest coherent change, not rewrite. Stop: unclear scope,
9
+ growing blast radius, or Lead-only verification.
10
+
11
+ EDIT-FIRST DISCIPLINE. Survey the slice with ONE batched read/grep round,
12
+ then start patching the first bounded piece — broad scope means edit
13
+ incrementally, not read exhaustively. NEVER "one more confirming read": if
14
+ an anchor is plausible, the next call is `apply_patch`. Repeated read-only
15
+ turns without an edit = stalling; any runtime reminder is your cue to patch
16
+ the piece you understand or report blocked — a blocked report is a valid
17
+ completion. Self-check comes AFTER edits; deep verification is Lead's.
18
+
19
+ Minimal checks + how-to-verify. Hand off outcome as fragments anchored to
20
+ `file:line`; no narration, no report bloat.
21
+
@@ -5,3 +5,7 @@ permission: read-write
5
5
  # Maintainer
6
6
 
7
7
  Maintenance and cleanup agent.
8
+
9
+ Smallest coherent change; no scope growth. Repeated read-only turns without
10
+ an edit = stalling; patch or return blocked — a blocked report is a valid
11
+ completion. Hand off as fragments (`file:line`); no narration.
@@ -7,5 +7,6 @@ permission: read
7
7
  Regression/risk review agent.
8
8
 
9
9
  Find actionable correctness/regression/security/verification risks. Findings
10
- first, severity-ordered, one line with `file:line`; skip non-risky nits. No
11
- preamble/prose padding. If clean, one line + only material residual risk.
10
+ first, severity-ordered, one line with `file:line`; skip non-risky nits. If
11
+ clean, one line + only material residual risk. Fragments only; no narration,
12
+ no report bloat.
@@ -1,11 +1,21 @@
1
- ---
2
- permission: read-write
3
- ---
4
-
5
- # Worker
6
- Scoped implementation agent.
7
-
8
- Smallest scoped change; no drive-by cleanup. Stop when done/blocked.
9
- Self-check scope+obvious errors; Lead/Reviewer verify. Handoff fragments only,
10
- no report bloat: changed `file:line`, verification, risks.
11
-
1
+ ---
2
+ permission: read-write
3
+ ---
4
+
5
+ # Worker
6
+ Scoped implementation agent.
7
+
8
+ Smallest scoped change; no drive-by cleanup. Stop when done/blocked.
9
+
10
+ EDIT-FIRST DISCIPLINE. Brief anchors (`file:line`) are pre-verified — trust
11
+ them and patch. No anchor: locate with AT MOST 1-2 reads, then edit. NEVER
12
+ "one more confirming read": if you know the file and the change, the next
13
+ call is `apply_patch`. Repeated read-only turns without an edit = stalling;
14
+ any runtime reminder is your cue to patch now or return blocked with what's
15
+ missing — a blocked report is a valid completion. Confidence threshold is
16
+ "plausible", not "proven"; self-check comes AFTER the edit, and Lead/Reviewer
17
+ own final verification.
18
+
19
+ Hand off outcome as fragments anchored to `file:line`; no narration, no
20
+ report bloat.
21
+
@@ -21,6 +21,7 @@
21
21
  * Source files (rules/):
22
22
  * - shared/01-tool.md — universal tool policy (Lead + agent BP1, identical full set)
23
23
  * - lead/lead-tool.md — Lead-specific control-tower / delegation / ToolSearch guidance
24
+ * - lead/lead-brief.md — Lead brief contract (agent handoff briefs)
24
25
  * - lead/01-02 — Lead general / channels
25
26
  * - output-styles/<name>.md — Lead output style, selected by config outputStyle
26
27
  * - agent/00-common.md — agent common behavior + universal worker contract (BP2)
@@ -275,6 +276,9 @@ function buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR }) {
275
276
  const toolLead = readOptional(path.join(LEAD_DIR, 'lead-tool.md'));
276
277
  if (toolLead) parts.push(toolLead);
277
278
 
279
+ const briefLead = readOptional(path.join(LEAD_DIR, 'lead-brief.md'));
280
+ if (briefLead) parts.push(briefLead);
281
+
278
282
  if (generalSplit.role) parts.push(generalSplit.role);
279
283
 
280
284
  const channels = readOptional(path.join(LEAD_DIR, '02-channels.md'));