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,28 @@
1
+ // Compaction debug/diagnostic helpers extracted from loop.mjs.
2
+ import { estimateMessagesTokens } from '../context-utils.mjs';
3
+
4
+ export function estimateMessagesTokensSafe(messages) {
5
+ try { return estimateMessagesTokens(messages); }
6
+ catch { return null; }
7
+ }
8
+
9
+ export function compactDebugEnabled() {
10
+ return String(process.env.MIXDOG_COMPACT_DEBUG || '').trim() === '1';
11
+ }
12
+
13
+ export function compactDiagnosticError(err) {
14
+ if (!err) return null;
15
+ const text = String(err?.message || err);
16
+ return text.length > 500 ? `${text.slice(0, 499)}…` : text;
17
+ }
18
+
19
+ export function compactByteLength(text) {
20
+ try { return Buffer.byteLength(String(text || ''), 'utf8'); }
21
+ catch { return String(text || '').length; }
22
+ }
23
+
24
+ export function compactDebugLog(scope, details = {}) {
25
+ if (!compactDebugEnabled()) return;
26
+ try { process.stderr.write(`[compact] ${scope} ${JSON.stringify(details)}\n`); }
27
+ catch { /* best-effort diagnostics only */ }
28
+ }
@@ -0,0 +1,274 @@
1
+ // Compaction policy resolution, pressure/target budgeting, telemetry
2
+ // persistence, and event emission — extracted from loop.mjs.
3
+ // runRecallFastTrackCompact stays in the loop (it drives the recall pipeline
4
+ // against live session state).
5
+ import {
6
+ estimateRequestReserveTokens,
7
+ resolveCompactBufferRatio,
8
+ resolveCompactBufferTokens,
9
+ } from '../context-utils.mjs';
10
+ import {
11
+ compactTypeIsRecallFastTrack,
12
+ compactTypeIsSemantic,
13
+ normalizeCompactType,
14
+ DEFAULT_COMPACT_TYPE,
15
+ DEFAULT_COMPACTION_KEEP_TOKENS,
16
+ CONTEXT_SHARE_RATIO,
17
+ } from '../compact.mjs';
18
+ import { positiveTokenInt, envFlag, envTokenInt } from './env.mjs';
19
+ import { isAgentOwner } from '../../agent-owner.mjs';
20
+
21
+ const COMPACT_SAFETY_PERCENT = 1.00;
22
+ // Unified context-share rule (compact/constants.mjs CONTEXT_SHARE_RATIO): the
23
+ // post-compaction target is 5% of the boundary/context window — the same 5%
24
+ // the recall-fasttrack injection cap uses (loop.mjs recallTokenCap). One
25
+ // number governs every "share of model context" budget.
26
+ const COMPACT_TARGET_RATIO = CONTEXT_SHARE_RATIO;
27
+ const COMPACT_TARGET_MIN_TOKENS = 4_000;
28
+ const COMPACT_TARGET_MAX_TOKENS = 16_000;
29
+
30
+ function resolveSemanticCompactSetting(sessionRef, cfg = {}) {
31
+ if (process.env.MIXDOG_AGENT_COMPACT_SEMANTIC !== undefined) return envFlag('MIXDOG_AGENT_COMPACT_SEMANTIC', true);
32
+ if (cfg.semantic === false || cfg.semantic === 'false' || cfg.semantic === 'off') return false;
33
+ if (cfg.semantic === true || cfg.semantic === 'true' || cfg.semantic === 'on') return true;
34
+ // The compact type is already explicit (`semantic` by default). Honor it
35
+ // directly instead of substituting another compaction path.
36
+ return true;
37
+ }
38
+
39
+ function resolveCompactTypeSetting(sessionRef, cfg = {}) {
40
+ // Agent-owned sessions are ALWAYS semantic. recall-fasttrack rebuilds
41
+ // context from Memory recall, which is scoped to the user's main-session
42
+ // history — an agent's tool-loop history is not in the recall pool, so a
43
+ // fasttrack compact would inject unrelated main-session memories and drop
44
+ // the agent's own working context. Env/config overrides do not apply.
45
+ if (isAgentOwner(sessionRef)) return DEFAULT_COMPACT_TYPE;
46
+ const configured = process.env.MIXDOG_AGENT_COMPACT_TYPE
47
+ ?? process.env.MIXDOG_COMPACT_TYPE
48
+ ?? cfg.type
49
+ ?? cfg.compactType
50
+ ?? cfg.compact_type;
51
+ return normalizeCompactType(configured, DEFAULT_COMPACT_TYPE);
52
+ }
53
+
54
+ function resolveCompactTargetRatio(cfg = {}) {
55
+ const raw = cfg.targetPercent
56
+ ?? cfg.targetPct
57
+ ?? cfg.targetRatio
58
+ ?? cfg.targetFraction
59
+ ?? process.env.MIXDOG_AGENT_COMPACT_TARGET_PERCENT
60
+ ?? process.env.MIXDOG_COMPACT_TARGET_PERCENT
61
+ ?? COMPACT_TARGET_RATIO;
62
+ const n = Number(raw);
63
+ if (!Number.isFinite(n) || n <= 0) return COMPACT_TARGET_RATIO;
64
+ return n > 1 ? n / 100 : n;
65
+ }
66
+ function resolveCompactTargetTokens(boundaryTokens, cfg = {}) {
67
+ const boundary = positiveTokenInt(boundaryTokens);
68
+ if (!boundary) return null;
69
+ const explicit = positiveTokenInt(cfg.targetTokens ?? cfg.target)
70
+ || envTokenInt('MIXDOG_AGENT_COMPACT_TARGET_TOKENS')
71
+ || envTokenInt('MIXDOG_COMPACT_TARGET_TOKENS');
72
+ if (explicit) return Math.max(1, Math.min(boundary, explicit));
73
+ const minTarget = Math.min(boundary, positiveTokenInt(cfg.targetMinTokens ?? cfg.minTargetTokens)
74
+ || envTokenInt('MIXDOG_AGENT_COMPACT_TARGET_MIN_TOKENS')
75
+ || envTokenInt('MIXDOG_COMPACT_TARGET_MIN_TOKENS')
76
+ || COMPACT_TARGET_MIN_TOKENS);
77
+ const maxTarget = Math.min(boundary, positiveTokenInt(cfg.targetMaxTokens ?? cfg.maxTargetTokens)
78
+ || envTokenInt('MIXDOG_AGENT_COMPACT_TARGET_MAX_TOKENS')
79
+ || envTokenInt('MIXDOG_COMPACT_TARGET_MAX_TOKENS')
80
+ || COMPACT_TARGET_MAX_TOKENS);
81
+ const byRatio = Math.max(1, Math.floor(boundary * resolveCompactTargetRatio(cfg)));
82
+ return Math.max(1, Math.min(boundary, maxTarget, Math.max(minTarget, byRatio)));
83
+ }
84
+ function resolveCompactKeepTokens(cfg = {}) {
85
+ return positiveTokenInt(cfg.keepTokens ?? cfg.keep?.tokens ?? cfg.preserveRecentTokens)
86
+ || envTokenInt('MIXDOG_AGENT_COMPACT_KEEP_TOKENS')
87
+ || DEFAULT_COMPACTION_KEEP_TOKENS;
88
+ }
89
+ export function resolveWorkerCompactPolicy(sessionRef, tools) {
90
+ if (!sessionRef) return null;
91
+ const cfg = sessionRef.compaction || {};
92
+ const auto = cfg.auto !== false && envFlag('MIXDOG_AGENT_COMPACT_AUTO', true);
93
+ if (!auto) return { auto: false };
94
+ const contextWindow = positiveTokenInt(sessionRef.contextWindow ?? cfg.contextWindow);
95
+ const explicitBoundary = positiveTokenInt(sessionRef.compactBoundaryTokens ?? cfg.boundaryTokens);
96
+ const autoLimit = positiveTokenInt(sessionRef.autoCompactTokenLimit ?? cfg.autoCompactTokenLimit);
97
+ const boundaryTokens = explicitBoundary && contextWindow
98
+ ? Math.min(explicitBoundary, contextWindow)
99
+ : (explicitBoundary || contextWindow || autoLimit);
100
+ if (!boundaryTokens) return null;
101
+ const compactBoundaryTokens = Math.max(1, Math.floor(boundaryTokens * COMPACT_SAFETY_PERCENT));
102
+ // Only an explicit auto-compact limit STRICTLY BELOW the boundary acts as
103
+ // the trigger. A persisted value == boundary (legacy derived full-window
104
+ // autoCompactTokenLimit) would set autoTriggerTokens == boundary and
105
+ // collapse/override the default trigger, so it is ignored in favor of the
106
+ // default boundary trigger.
107
+ const autoTriggerTokens = autoLimit && autoLimit < compactBoundaryTokens ? Math.max(1, autoLimit) : null;
108
+ // Sanitized explicit limit: only a sub-boundary value is a real auto-compact
109
+ // limit. Anything >= boundary is a legacy derived full-window artifact and
110
+ // is reported as null so rememberCompactTelemetry does not re-persist it
111
+ // back onto the session and re-collapse the buffer on the next turn.
112
+ const explicitAutoCompactTokenLimit = autoTriggerTokens;
113
+ const bufferTokens = autoTriggerTokens
114
+ ? Math.max(0, compactBoundaryTokens - autoTriggerTokens)
115
+ : resolveCompactBufferTokens(compactBoundaryTokens, cfg);
116
+ const bufferRatio = compactBoundaryTokens ? (bufferTokens / compactBoundaryTokens) : resolveCompactBufferRatio(cfg);
117
+ const triggerTokens = autoTriggerTokens || Math.max(1, compactBoundaryTokens - bufferTokens);
118
+ const configuredReserve = positiveTokenInt(cfg.reservedTokens)
119
+ || envTokenInt('MIXDOG_AGENT_COMPACT_RESERVED_TOKENS')
120
+ || 0;
121
+ const requestReserve = estimateRequestReserveTokens(tools);
122
+ const keepTokens = resolveCompactKeepTokens(cfg);
123
+ const compactType = resolveCompactTypeSetting(sessionRef, cfg);
124
+ return {
125
+ auto: true,
126
+ type: compactType,
127
+ compactType,
128
+ prune: cfg.prune === true || envFlag('MIXDOG_AGENT_COMPACT_PRUNE', false),
129
+ boundaryTokens: compactBoundaryTokens,
130
+ triggerTokens,
131
+ bufferTokens,
132
+ bufferRatio,
133
+ contextWindow,
134
+ rawContextWindow: positiveTokenInt(sessionRef.rawContextWindow ?? cfg.rawContextWindow) || contextWindow,
135
+ effectiveContextWindowPercent: Number.isFinite(Number(sessionRef.effectiveContextWindowPercent ?? cfg.effectiveContextWindowPercent))
136
+ ? Number(sessionRef.effectiveContextWindowPercent ?? cfg.effectiveContextWindowPercent)
137
+ : null,
138
+ autoCompactTokenLimit: explicitAutoCompactTokenLimit,
139
+ semantic: compactTypeIsSemantic(compactType) && resolveSemanticCompactSetting(sessionRef, cfg),
140
+ recallFastTrack: compactTypeIsRecallFastTrack(compactType),
141
+ semanticTimeoutMs: positiveTokenInt(cfg.timeoutMs) || envTokenInt('MIXDOG_AGENT_COMPACT_TIMEOUT_MS') || 30_000,
142
+ tailTurns: positiveTokenInt(cfg.tailTurns) || envTokenInt('MIXDOG_AGENT_COMPACT_TAIL_TURNS') || 2,
143
+ keepTokens,
144
+ preserveRecentTokens: positiveTokenInt(cfg.preserveRecentTokens) || envTokenInt('MIXDOG_AGENT_COMPACT_PRESERVE_RECENT_TOKENS') || keepTokens,
145
+ reserveTokens: requestReserve + configuredReserve,
146
+ requestReserveTokens: requestReserve,
147
+ configuredReserveTokens: configuredReserve,
148
+ };
149
+ }
150
+ /** Transcript + request reserve only (never provider lastContextTokens). */
151
+ function compactPressureTokens(messageTokensEst, policy) {
152
+ if (messageTokensEst === null) return 0;
153
+ return Math.max(0, messageTokensEst + (policy?.reserveTokens || 0));
154
+ }
155
+
156
+ /** Telemetry pressure when a reactive overflow retry forces the next compact. */
157
+ export function compactionTelemetryPressureTokens(messageTokensEst, policy, { reactivePending = false } = {}) {
158
+ const base = compactPressureTokens(messageTokensEst, policy);
159
+ if (!reactivePending) return base;
160
+ const floor = positiveTokenInt(policy?.triggerTokens) || positiveTokenInt(policy?.boundaryTokens) || 0;
161
+ return floor ? Math.max(base, floor) : base;
162
+ }
163
+ export function compactTargetBudget(policy) {
164
+ const boundary = positiveTokenInt(policy?.boundaryTokens);
165
+ if (!boundary) return null;
166
+ const reserve = Math.max(0, Number(policy?.reserveTokens) || 0);
167
+ const targetEffective = resolveCompactTargetTokens(boundary, policy) || boundary;
168
+ return Math.max(1, Math.min(boundary, targetEffective + reserve));
169
+ }
170
+ export function shouldCompactForSession(messageTokensEst, policy, { forceReactive = false } = {}) {
171
+ if (!policy?.auto || !policy.boundaryTokens) return false;
172
+ if (forceReactive) return true;
173
+ if (messageTokensEst === null) return true;
174
+ return compactPressureTokens(messageTokensEst, policy) >= (policy.triggerTokens || policy.boundaryTokens);
175
+ }
176
+ export function countPrunedToolOutputs(before, after) {
177
+ if (!Array.isArray(before) || !Array.isArray(after)) return 0;
178
+ let count = 0;
179
+ const n = Math.min(before.length, after.length);
180
+ for (let i = 0; i < n; i += 1) {
181
+ if (before[i]?.role !== 'tool' || after[i]?.role !== 'tool') continue;
182
+ if (before[i]?.content !== after[i]?.content && after[i]?.compactedKind === 'tool_output_prune') count += 1;
183
+ }
184
+ return count;
185
+ }
186
+ export function rememberCompactTelemetry(sessionRef, policy, meta = {}) {
187
+ if (!sessionRef || !policy) return;
188
+ const prev = sessionRef.compaction && typeof sessionRef.compaction === 'object'
189
+ ? sessionRef.compaction
190
+ : {};
191
+ const changed = meta.compactChanged === true || meta.pruneCount > 0;
192
+ sessionRef.compaction = {
193
+ ...prev,
194
+ auto: policy.auto !== false,
195
+ prune: policy.prune === true,
196
+ reservedTokens: policy.configuredReserveTokens || prev.reservedTokens || null,
197
+ requestReserveTokens: policy.requestReserveTokens || 0,
198
+ reserveTokens: policy.reserveTokens || 0,
199
+ boundaryTokens: policy.boundaryTokens || null,
200
+ triggerTokens: policy.triggerTokens || null,
201
+ bufferTokens: policy.bufferTokens || 0,
202
+ bufferRatio: policy.bufferRatio ?? prev.bufferRatio ?? null,
203
+ contextWindow: policy.contextWindow || null,
204
+ rawContextWindow: policy.rawContextWindow || null,
205
+ effectiveContextWindowPercent: policy.effectiveContextWindowPercent ?? null,
206
+ autoCompactTokenLimit: policy.autoCompactTokenLimit || null,
207
+ type: policy.compactType || policy.type || DEFAULT_COMPACT_TYPE,
208
+ compactType: policy.compactType || policy.type || DEFAULT_COMPACT_TYPE,
209
+ semantic: policy.semantic === true ? 'auto' : false,
210
+ recallFastTrack: policy.recallFastTrack === true,
211
+ semanticModel: policy.semanticModel || null,
212
+ semanticTimeoutMs: policy.semanticTimeoutMs || null,
213
+ tailTurns: policy.tailTurns || null,
214
+ keepTokens: policy.keepTokens || null,
215
+ preserveRecentTokens: policy.preserveRecentTokens || null,
216
+ lastCheckedAt: Date.now(),
217
+ lastBeforeTokens: meta.beforeTokens ?? null,
218
+ lastAfterTokens: meta.afterTokens ?? null,
219
+ lastPressureTokens: meta.pressureTokens ?? null,
220
+ currentEstimatedTokens: meta.pressureTokens ?? prev.currentEstimatedTokens ?? null,
221
+ lastApiRequestTokens: positiveTokenInt(sessionRef?.lastContextTokens) || prev.lastApiRequestTokens || null,
222
+ lastStage: meta.stage || prev.lastStage || null,
223
+ lastChanged: changed,
224
+ lastTrigger: meta.trigger || prev.lastTrigger || null,
225
+ lastSemantic: meta.semanticCompact === true,
226
+ lastSemanticError: Object.hasOwn(meta, 'semanticError')
227
+ ? (meta.semanticError ?? null)
228
+ : (prev.lastSemanticError ?? null),
229
+ lastRecallFastTrack: meta.recallFastTrack === true,
230
+ lastRecallFastTrackError: Object.hasOwn(meta, 'recallFastTrackError')
231
+ ? (meta.recallFastTrackError ?? null)
232
+ : (prev.lastRecallFastTrackError ?? null),
233
+ lastError: Object.hasOwn(meta, 'compactError') || Object.hasOwn(meta, 'lastError')
234
+ ? (meta.compactError ?? meta.lastError ?? null)
235
+ : (prev.lastError ?? null),
236
+ lastPruneCount: meta.pruneCount || 0,
237
+ lastDurationMs: meta.durationMs != null && Number.isFinite(Number(meta.durationMs))
238
+ ? Math.max(0, Math.round(Number(meta.durationMs)))
239
+ : null,
240
+ compactCount: (prev.compactCount || 0) + (changed ? 1 : 0),
241
+ };
242
+ if (changed) {
243
+ const changedAt = Date.now();
244
+ sessionRef.compaction.lastChangedAt = changedAt;
245
+ sessionRef.compaction.lastCompactAt = changedAt;
246
+ sessionRef.lastContextTokensStaleAfterCompact = true;
247
+ }
248
+ sessionRef.contextWindow = policy.contextWindow || sessionRef.contextWindow;
249
+ sessionRef.rawContextWindow = policy.rawContextWindow || sessionRef.rawContextWindow;
250
+ sessionRef.compactBoundaryTokens = policy.boundaryTokens || sessionRef.compactBoundaryTokens || null;
251
+ // Persist only the sanitized (sub-boundary) explicit limit. policy.autoCompactTokenLimit
252
+ // is already null for legacy derived full-window values, so a stale
253
+ // boundary-sized autoCompactTokenLimit on the session is cleared here rather
254
+ // than carried forward to re-collapse the buffer next turn.
255
+ {
256
+ const _boundary = positiveTokenInt(sessionRef.compactBoundaryTokens);
257
+ const _prevLimit = positiveTokenInt(sessionRef.autoCompactTokenLimit);
258
+ const _keepPrev = _prevLimit && (!_boundary || _prevLimit < _boundary) ? _prevLimit : null;
259
+ sessionRef.autoCompactTokenLimit = policy.autoCompactTokenLimit || _keepPrev || null;
260
+ }
261
+ if (policy.effectiveContextWindowPercent !== null) {
262
+ sessionRef.effectiveContextWindowPercent = policy.effectiveContextWindowPercent;
263
+ }
264
+ }
265
+
266
+ export function emitCompactEvent(opts, event = {}) {
267
+ if (!opts || typeof opts.onCompactEvent !== 'function') return;
268
+ try { opts.onCompactEvent({ ts: Date.now(), ...event }); }
269
+ catch { /* best-effort UI/log hook */ }
270
+ }
271
+
272
+ export function compactEventType(policy, fallback = DEFAULT_COMPACT_TYPE) {
273
+ return policy?.compactType || policy?.type || fallback;
274
+ }
@@ -0,0 +1,61 @@
1
+ // Completion-first loop guards: escalation ladder (level-2 steering),
2
+ // cross-turn identical read-only call dedup, and worker soft-cap wrap-up.
3
+ // Pure string/signature helpers extracted from loop.mjs so the loop body only
4
+ // wires state + messages. No provider/manager coupling.
5
+
6
+ // Deterministic, key-sorted stringify for cross-turn call signatures. Mirrors
7
+ // _canonicalArgs but exposed by name for the dedup signature contract.
8
+ export function stableStringify(value) {
9
+ if (value == null || typeof value !== 'object') {
10
+ try { return JSON.stringify(value); } catch { return String(value); }
11
+ }
12
+ if (Array.isArray(value)) {
13
+ try { return `[${value.map(stableStringify).join(',')}]`; } catch { return String(value); }
14
+ }
15
+ try {
16
+ const keys = Object.keys(value).sort();
17
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(',')}}`;
18
+ } catch { return String(value); }
19
+ }
20
+
21
+ export function crossTurnSignature(name, args) {
22
+ return `${name}:${stableStringify(args)}`;
23
+ }
24
+
25
+ // Tool names that are non-eager (no readOnlyHint) but are NOT edits/progress —
26
+ // they must not reset the escalation ladder's "zero edit" condition. Skill /
27
+ // recall / agent / task / cwd / tool_search are exploration/meta plumbing.
28
+ const NON_PROGRESS_TOOLS = new Set(['Skill', 'recall', 'agent', 'task', 'cwd', 'tool_search']);
29
+
30
+ // True when a successfully-executed tool represents real edit/progress. A tool
31
+ // counts as progress only if its def lacks readOnlyHint (not eager) AND it is
32
+ // not in the meta/non-progress set. apply_patch and shell/bash always count.
33
+ export function isEditProgressTool(name, isEager) {
34
+ if (isEager) return false;
35
+ const bare = name && name.startsWith('mcp__') ? name.split('__').pop() : name;
36
+ if (bare === 'apply_patch' || bare === 'shell' || bare === 'bash' || bare === 'bash_session') return true;
37
+ return !NON_PROGRESS_TOOLS.has(bare);
38
+ }
39
+
40
+ // Step 1 — level-2 escalation steering. N = cumulative level-1 fires.
41
+ // `readOnlyRole` swaps the edit-oriented directive for a report-oriented one:
42
+ // read-permission sessions (reviewer-style) cannot apply_patch, so telling
43
+ // them to edit is self-contradictory and pushes premature termination.
44
+ export function level2SteerMessage(n, readOnlyRole = false) {
45
+ if (readOnlyRole) {
46
+ return `<system-reminder>\nYou have received this batching reminder ${n} times. Converge now: report your findings from what you have already read, or state exactly what information is missing for a verdict. A partial report with named gaps is a valid, successful completion — continued exploration is not.\n</system-reminder>`;
47
+ }
48
+ return `<system-reminder>\nYou have received this batching reminder ${n} times without making any edit. Stop exploring now: either apply_patch with what you already know, or return a blocked report stating exactly what is missing. A blocked report is a valid, successful completion — continued exploration is not.\n</system-reminder>`;
49
+ }
50
+
51
+ // Step 2 — cross-turn dedup stub. `stuck` appends the escalation tail at the
52
+ // 5th+ dedup stub in the session.
53
+ export function crossTurnDedupStub(name, firstIteration, stuck) {
54
+ let s = `[cross-turn-dedup] identical read-only \`${name}\` call already executed in iteration ${firstIteration}; its result is unchanged and already in context. Use it, or change path/offset/pattern for new information.`;
55
+ if (stuck) s += ` Repeated identical calls indicate you are stuck — apply what you know or return blocked.`;
56
+ return s;
57
+ }
58
+
59
+ // Step 3 — worker soft-cap wrap-up assistant-visible directive + refusal stub.
60
+ export const SOFT_CAP_WRAPUP_MESSAGE = `MAXIMUM EXPLORATION BUDGET REACHED. Tools are now disabled. Respond with text only: summarize work completed so far, list remaining/incomplete items, and state what is blocking or what should be done next. This overrides all other instructions.`;
61
+ export const SOFT_CAP_REFUSAL_STUB = `Tools are disabled: exploration budget reached. Provide your final text summary.`;
@@ -0,0 +1,38 @@
1
+ // Agent context-overflow error, extracted from loop.mjs. Raised when the latest
2
+ // turn cannot fit the target context budget even after compaction.
3
+
4
+ export class AgentContextOverflowError extends Error {
5
+ constructor({ stage, sessionId, provider, model, contextWindow, budgetTokens, reserveTokens, messageTokensEst }, cause) {
6
+ const target = [provider, model].filter(Boolean).join('/') || 'target model';
7
+ const causeMsg = cause && cause.message ? `: ${cause.message}` : '';
8
+ super(
9
+ `agent context overflow (${target}, stage=${stage || 'compact'}): ` +
10
+ `latest turn cannot fit target context budget=${budgetTokens ?? 'unknown'} ` +
11
+ `reserve=${reserveTokens ?? 'unknown'} contextWindow=${contextWindow ?? 'unknown'} ` +
12
+ `messageTokensEst=${messageTokensEst ?? 'unknown'}${causeMsg}`,
13
+ );
14
+ this.name = 'AgentContextOverflowError';
15
+ this.code = 'AGENT_CONTEXT_OVERFLOW';
16
+ this.sessionId = sessionId || null;
17
+ this.provider = provider || null;
18
+ this.model = model || null;
19
+ this.contextWindow = contextWindow ?? null;
20
+ this.budgetTokens = budgetTokens ?? null;
21
+ this.reserveTokens = reserveTokens ?? null;
22
+ this.messageTokensEst = messageTokensEst ?? null;
23
+ if (cause) this.cause = cause;
24
+ }
25
+ }
26
+
27
+ export function agentContextOverflowError({ stage, sessionId, sessionRef, model, budgetTokens, reserveTokens, messageTokensEst }, cause) {
28
+ return new AgentContextOverflowError({
29
+ stage,
30
+ sessionId,
31
+ provider: sessionRef?.provider || null,
32
+ model: sessionRef?.model || model || null,
33
+ contextWindow: sessionRef?.contextWindow ?? null,
34
+ budgetTokens,
35
+ reserveTokens,
36
+ messageTokensEst,
37
+ }, cause);
38
+ }
@@ -0,0 +1,14 @@
1
+ // Env-var / token parsing helpers extracted from loop.mjs.
2
+
3
+ export function positiveTokenInt(value) {
4
+ const n = Number(value);
5
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
6
+ }
7
+ export function envFlag(name, fallback = false) {
8
+ const v = process.env[name];
9
+ if (v === undefined) return fallback;
10
+ return !['0', 'false', 'off', 'no'].includes(String(v).trim().toLowerCase());
11
+ }
12
+ export function envTokenInt(name) {
13
+ return positiveTokenInt(process.env[name]);
14
+ }
@@ -0,0 +1,21 @@
1
+ // Hidden (sub-agent) role registry, extracted from loop.mjs.
2
+ // Source of truth: defaults/agents.json — read once and cached. HIDDEN_AGENT_NAMES
3
+ // is built eagerly so it stays in sync with the declarative registry (no
4
+ // hardcoded duplicate).
5
+ import { readFileSync as _readFileSync } from 'fs';
6
+ import { fileURLToPath } from 'url';
7
+ import { dirname, resolve as resolvePath } from 'path';
8
+
9
+ const _AGENTS_JSON = resolvePath(dirname(fileURLToPath(import.meta.url)), '../../../../../defaults/agents.json');
10
+ let _hiddenAgentsCache = null;
11
+ function _getHiddenAgents() {
12
+ if (_hiddenAgentsCache) return _hiddenAgentsCache;
13
+ try {
14
+ _hiddenAgentsCache = JSON.parse(_readFileSync(_AGENTS_JSON, 'utf8'));
15
+ } catch { _hiddenAgentsCache = { agents: [] }; }
16
+ return _hiddenAgentsCache;
17
+ }
18
+
19
+ export const HIDDEN_AGENT_NAMES = new Set(
20
+ (_getHiddenAgents().agents || []).map((r) => r && r.agent).filter((n) => typeof n === 'string' && n.length > 0)
21
+ );
@@ -0,0 +1,47 @@
1
+ // Shared pre-dispatch deny — single source of truth for the remaining
2
+ // control-plane / role scoping rejects. Called by BOTH the eager dispatch
3
+ // path (startEagerTool) and the serial dispatch path (executeTool body).
4
+ // Returns null when the call is allowed to proceed; otherwise returns the
5
+ // Error string the serial path would emit. The eager caller ignores the
6
+ // message body and just treats non-null as "do not start eager".
7
+ //
8
+ // This is NOT a permission gate — runtime permission enforcement was removed
9
+ // (every tool call is trusted). What remains is architectural scoping:
10
+ // agent workers are sandboxed to code/research tools. They must never reach
11
+ // owner/host control surfaces: session management, the ENTIRE channels module
12
+ // (Discord messaging, schedules, webhook/config, channel-bridge toggle,
13
+ // command injection), or host input injection. Explicit name list (no imports)
14
+ // keeps this hot-path gate dependency-free; add new owner/channel tools here.
15
+ import { isAgentOwner } from '../../agent-owner.mjs';
16
+
17
+ const WORKER_DENIED_TOOLS = new Set([
18
+ // session control-plane — unified into the single `agent` tool
19
+ // (type=spawn|send|close|list). Denying the one name blocks all worker
20
+ // session control.
21
+ 'agent',
22
+ // channels module (owner/Discord-facing)
23
+ 'reply', 'fetch',
24
+ // host input injection
25
+ 'inject_input',
26
+ ]);
27
+
28
+ function _preDispatchDeny(call, toolKind, sessionRef) {
29
+ const name = call?.name;
30
+ if (typeof name !== 'string' || !name) return null;
31
+ const _agentOwned = sessionRef?.scope?.startsWith?.('agent:')
32
+ || isAgentOwner(sessionRef);
33
+ const _controlPlaneTool = WORKER_DENIED_TOOLS.has(name);
34
+ if (_agentOwned && _controlPlaneTool) {
35
+ return `Error: control-plane tool "${name}" is Lead-only and not available to agent workers.`;
36
+ }
37
+ const noToolAgent = sessionRef?.agent === 'cycle1-agent' || sessionRef?.agent === 'cycle2-agent';
38
+ if (noToolAgent) {
39
+ return `Error: tool "${name}" is not available in agent "${sessionRef.agent}". Re-emit the answer as pipe-separated text per the agent's output format (first character a digit, NO tool_use blocks, NO JSON, NO prose, NO apology).`;
40
+ }
41
+ return null;
42
+ }
43
+
44
+ /** Exported for smoke tests — same runtime deny as the agent loop. */
45
+ export function preDispatchDenyForSession(sessionRef, call, toolKind = 'builtin') {
46
+ return _preDispatchDeny(call, toolKind, sessionRef);
47
+ }