mixdog 0.9.1 → 0.9.3

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 (301) hide show
  1. package/package.json +9 -1
  2. package/scripts/_bench-cwc.json +20 -0
  3. package/scripts/agent-loop-policy-test.mjs +37 -0
  4. package/scripts/agent-parallel-smoke.mjs +54 -10
  5. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  6. package/scripts/background-task-meta-smoke.mjs +1 -1
  7. package/scripts/bench-run.mjs +262 -0
  8. package/scripts/build-tui.mjs +13 -1
  9. package/scripts/compact-smoke.mjs +12 -0
  10. package/scripts/compact-trigger-migration-smoke.mjs +67 -1
  11. package/scripts/explore-bench.mjs +124 -0
  12. package/scripts/hook-bus-test.mjs +191 -0
  13. package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
  14. package/scripts/internal-comms-bench.mjs +727 -0
  15. package/scripts/internal-comms-smoke.mjs +75 -0
  16. package/scripts/lead-workflow-smoke.mjs +4 -4
  17. package/scripts/live-worker-smoke.mjs +9 -9
  18. package/scripts/output-style-bench.mjs +285 -0
  19. package/scripts/output-style-smoke.mjs +13 -10
  20. package/scripts/patch-replay.mjs +90 -0
  21. package/scripts/path-suffix-test.mjs +57 -0
  22. package/scripts/provider-stream-stall-test.mjs +276 -0
  23. package/scripts/provider-toolcall-test.mjs +599 -1
  24. package/scripts/recall-bench.mjs +207 -0
  25. package/scripts/routing-corpus.mjs +281 -0
  26. package/scripts/session-bench.mjs +1526 -0
  27. package/scripts/session-diag.mjs +595 -0
  28. package/scripts/task-bench.mjs +207 -0
  29. package/scripts/tool-failures.mjs +6 -6
  30. package/scripts/tool-smoke.mjs +310 -67
  31. package/scripts/toolcall-args-test.mjs +81 -0
  32. package/src/agents/debugger/AGENT.md +4 -4
  33. package/src/agents/heavy-worker/AGENT.md +20 -9
  34. package/src/agents/reviewer/AGENT.md +4 -4
  35. package/src/agents/worker/AGENT.md +17 -9
  36. package/src/app.mjs +10 -6
  37. package/src/defaults/{hidden-roles.json → agents.json} +7 -7
  38. package/src/examples/schedules/SCHEDULE.example.md +32 -0
  39. package/src/examples/webhooks/WEBHOOK.example.md +40 -0
  40. package/src/headless-role.mjs +14 -14
  41. package/src/help.mjs +1 -0
  42. package/src/lib/rules-builder.cjs +32 -54
  43. package/src/mixdog-session-runtime.mjs +1040 -2036
  44. package/src/output-styles/default.md +12 -7
  45. package/src/output-styles/minimal.md +25 -0
  46. package/src/output-styles/oneline.md +21 -0
  47. package/src/output-styles/simple.md +10 -9
  48. package/src/repl.mjs +17 -7
  49. package/src/rules/agent/00-common.md +7 -5
  50. package/src/rules/agent/30-explorer.md +8 -12
  51. package/src/rules/lead/01-general.md +3 -1
  52. package/src/rules/lead/lead-tool.md +13 -2
  53. package/src/rules/shared/01-tool.md +23 -12
  54. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
  55. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
  59. package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
  60. package/src/runtime/agent/orchestrator/config.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/context/collect.mjs +182 -67
  62. package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
  63. package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +100 -18
  65. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
  66. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +313 -84
  70. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +104 -38
  71. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +28 -33
  72. package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
  73. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
  74. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  75. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
  76. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +227 -31
  78. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +83 -6
  79. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +229 -115
  80. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +213 -33
  81. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
  82. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +49 -17
  83. package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +22 -17
  85. package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
  86. package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
  87. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  88. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +262 -0
  89. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  90. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  91. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  92. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +49 -0
  93. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  94. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  95. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  96. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  97. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  98. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  99. package/src/runtime/agent/orchestrator/session/loop.mjs +513 -1000
  100. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +227 -0
  101. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  102. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +137 -0
  103. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  104. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  105. package/src/runtime/agent/orchestrator/session/manager.mjs +232 -1152
  106. package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
  107. package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
  108. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
  109. package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
  110. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -24
  111. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
  113. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +162 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  116. package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
  118. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  119. package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
  120. package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
  121. package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
  122. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +14 -5
  123. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  124. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
  125. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +23 -2
  126. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +50 -39
  127. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
  128. package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
  129. package/src/runtime/agent/orchestrator/tools/builtin.mjs +70 -1
  130. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  131. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  132. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  133. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +497 -0
  134. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  135. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  136. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  137. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  138. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  139. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1192 -0
  140. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  141. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  142. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  143. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  144. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
  145. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +39 -4189
  146. package/src/runtime/agent/orchestrator/tools/patch.mjs +119 -5
  147. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -2
  148. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +1 -2
  149. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  150. package/src/runtime/channels/backends/discord.mjs +99 -9
  151. package/src/runtime/channels/backends/telegram.mjs +501 -0
  152. package/src/runtime/channels/index.mjs +437 -1439
  153. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  154. package/src/runtime/channels/lib/config.mjs +54 -2
  155. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  156. package/src/runtime/channels/lib/format.mjs +4 -2
  157. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  158. package/src/runtime/channels/lib/output-forwarder.mjs +88 -67
  159. package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
  160. package/src/runtime/channels/lib/scheduler.mjs +1 -1
  161. package/src/runtime/channels/lib/telegram-format.mjs +280 -0
  162. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  163. package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
  164. package/src/runtime/channels/lib/webhook.mjs +59 -31
  165. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  166. package/src/runtime/channels/tool-defs.mjs +1 -1
  167. package/src/runtime/memory/index.mjs +465 -345
  168. package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
  169. package/src/runtime/memory/lib/core-memory-store.mjs +352 -2
  170. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  171. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  172. package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
  173. package/src/runtime/memory/lib/memory-cycle2.mjs +65 -9
  174. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
  175. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  176. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  177. package/src/runtime/memory/lib/memory.mjs +121 -4
  178. package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
  179. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  180. package/src/runtime/memory/lib/recall-format.mjs +183 -0
  181. package/src/runtime/memory/lib/session-ingest.mjs +107 -0
  182. package/src/runtime/memory/lib/trace-store.mjs +69 -22
  183. package/src/runtime/memory/tool-defs.mjs +10 -7
  184. package/src/runtime/shared/abort-controller.mjs +1 -1
  185. package/src/runtime/shared/background-tasks.mjs +2 -3
  186. package/src/runtime/shared/buffered-appender.mjs +149 -0
  187. package/src/runtime/shared/channel-notification-routing.mjs +12 -0
  188. package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
  189. package/src/runtime/shared/config.mjs +9 -0
  190. package/src/runtime/shared/llm/http-agent.mjs +12 -5
  191. package/src/runtime/shared/schedules-store.mjs +21 -19
  192. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  193. package/src/runtime/shared/task-notification-envelope.test.mjs +107 -0
  194. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  195. package/src/runtime/shared/tool-surface.mjs +98 -13
  196. package/src/runtime/shared/transcript-writer.mjs +156 -0
  197. package/src/runtime/shared/update-checker.mjs +214 -0
  198. package/src/session-runtime/config-helpers.mjs +209 -0
  199. package/src/session-runtime/effort.mjs +128 -0
  200. package/src/session-runtime/fs-utils.mjs +10 -0
  201. package/src/session-runtime/model-capabilities.mjs +130 -0
  202. package/src/session-runtime/output-styles.mjs +124 -0
  203. package/src/session-runtime/plugin-mcp.mjs +114 -0
  204. package/src/session-runtime/session-text.mjs +100 -0
  205. package/src/session-runtime/statusline-route.mjs +35 -0
  206. package/src/session-runtime/tool-catalog.mjs +720 -0
  207. package/src/session-runtime/workflow.mjs +358 -0
  208. package/src/standalone/agent-tool.mjs +302 -117
  209. package/src/standalone/channel-admin.mjs +133 -40
  210. package/src/standalone/channel-worker.mjs +10 -292
  211. package/src/standalone/explore-tool.mjs +12 -5
  212. package/src/standalone/hook-bus.mjs +165 -8
  213. package/src/standalone/memory-runtime-proxy.mjs +3 -1
  214. package/src/standalone/opencode-go-login.mjs +121 -0
  215. package/src/standalone/provider-admin.mjs +25 -3
  216. package/src/standalone/usage-dashboard.mjs +1 -1
  217. package/src/tui/App.jsx +2883 -778
  218. package/src/tui/components/ConfirmBar.jsx +47 -0
  219. package/src/tui/components/ContextPanel.jsx +5 -3
  220. package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
  221. package/src/tui/components/Markdown.jsx +22 -98
  222. package/src/tui/components/Message.jsx +14 -35
  223. package/src/tui/components/Picker.jsx +87 -12
  224. package/src/tui/components/PromptInput.jsx +355 -22
  225. package/src/tui/components/QueuedCommands.jsx +1 -1
  226. package/src/tui/components/SlashCommandPalette.jsx +8 -5
  227. package/src/tui/components/Spinner.jsx +7 -7
  228. package/src/tui/components/StatusLine.jsx +40 -21
  229. package/src/tui/components/TextEntryPanel.jsx +51 -7
  230. package/src/tui/components/ToolExecution.jsx +183 -101
  231. package/src/tui/components/TurnDone.jsx +4 -4
  232. package/src/tui/components/UsagePanel.jsx +1 -1
  233. package/src/tui/components/tool-output-format.mjs +161 -23
  234. package/src/tui/components/tool-output-format.test.mjs +87 -0
  235. package/src/tui/display-width.mjs +69 -0
  236. package/src/tui/display-width.test.mjs +35 -0
  237. package/src/tui/dist/index.mjs +6731 -2333
  238. package/src/tui/engine/agent-envelope.mjs +296 -0
  239. package/src/tui/engine/boot-profile.mjs +21 -0
  240. package/src/tui/engine/labels.mjs +67 -0
  241. package/src/tui/engine/notice-text.mjs +112 -0
  242. package/src/tui/engine/queue-helpers.mjs +161 -0
  243. package/src/tui/engine/session-stats.mjs +46 -0
  244. package/src/tui/engine/tool-call-fields.mjs +23 -0
  245. package/src/tui/engine/tool-result-text.mjs +126 -0
  246. package/src/tui/engine.mjs +569 -948
  247. package/src/tui/index.jsx +117 -7
  248. package/src/tui/input-editing.mjs +58 -8
  249. package/src/tui/input-editing.selection.test.mjs +75 -0
  250. package/src/tui/keyboard-protocol.mjs +42 -0
  251. package/src/tui/lib/voice-recorder.mjs +469 -0
  252. package/src/tui/markdown/format-token.mjs +128 -76
  253. package/src/tui/markdown/format-token.test.mjs +61 -19
  254. package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
  255. package/src/tui/markdown/render-ansi.test.mjs +1 -1
  256. package/src/tui/markdown/streaming-markdown.mjs +167 -0
  257. package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
  258. package/src/tui/markdown/table-layout.mjs +9 -9
  259. package/src/tui/paste-attachments.mjs +36 -9
  260. package/src/tui/paste-fix.test.mjs +119 -0
  261. package/src/tui/prompt-history-store.mjs +129 -0
  262. package/src/tui/prompt-history-store.test.mjs +52 -0
  263. package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
  264. package/src/tui/theme.mjs +41 -657
  265. package/src/tui/themes/base.mjs +86 -0
  266. package/src/tui/themes/basic.mjs +85 -0
  267. package/src/tui/themes/catppuccin.mjs +72 -0
  268. package/src/tui/themes/dracula.mjs +70 -0
  269. package/src/tui/themes/everforest.mjs +71 -0
  270. package/src/tui/themes/gruvbox.mjs +71 -0
  271. package/src/tui/themes/index.mjs +71 -0
  272. package/src/tui/themes/indigo.mjs +78 -0
  273. package/src/tui/themes/kanagawa.mjs +80 -0
  274. package/src/tui/themes/light.mjs +81 -0
  275. package/src/tui/themes/nord.mjs +72 -0
  276. package/src/tui/themes/onedark.mjs +16 -0
  277. package/src/tui/themes/rosepine.mjs +70 -0
  278. package/src/tui/themes/teal.mjs +80 -0
  279. package/src/tui/themes/tokyonight.mjs +79 -0
  280. package/src/tui/themes/utils.mjs +106 -0
  281. package/src/tui/themes/warm.mjs +79 -0
  282. package/src/tui/transcript-tool-failures.mjs +13 -2
  283. package/src/ui/markdown.mjs +1 -1
  284. package/src/ui/model-display.mjs +2 -2
  285. package/src/ui/statusline.mjs +75 -27
  286. package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
  287. package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
  288. package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
  289. package/src/workflows/default/WORKFLOW.md +46 -12
  290. package/src/workflows/sequential/WORKFLOW.md +51 -0
  291. package/src/workflows/solo/WORKFLOW.md +12 -1
  292. package/vendor/ink/build/display-width.js +62 -0
  293. package/vendor/ink/build/ink.js +100 -12
  294. package/vendor/ink/build/measure-text.js +4 -1
  295. package/vendor/ink/build/output.js +115 -9
  296. package/vendor/ink/build/render-node-to-output.js +4 -1
  297. package/vendor/ink/build/render.js +4 -0
  298. package/src/output-styles/extreme-simple.md +0 -20
  299. package/src/rules/lead/04-workflow.md +0 -51
  300. package/src/workflows/default/workflow.json +0 -13
  301. package/src/workflows/solo/workflow.json +0 -7
@@ -0,0 +1,155 @@
1
+ // Prompt-layer rules builders + mtime-invalidated caches, extracted verbatim
2
+ // from manager.mjs. Behavior-preserving: same createRequire lookup, same cache
3
+ // semantics, same error messages.
4
+ import { createRequire } from 'module';
5
+ import { join } from 'path';
6
+ import { resolvePluginData, mixdogRoot } from '../../../../shared/plugin-paths.mjs';
7
+ import { maxMtimeRecursive } from '../../cache-mtime.mjs';
8
+ import { getAgentInstructionDir } from '../../internal-agents.mjs';
9
+
10
+ // Phase B: Pool B Tier 2 content builder (common rules only).
11
+ // Loaded once per process via createRequire so the CJS module reaches us.
12
+ const _require = createRequire(import.meta.url);
13
+ const _rulesBuilder = (() => {
14
+ const candidates = [
15
+ join(mixdogRoot(), 'lib', 'rules-builder.cjs'),
16
+ ].filter(Boolean);
17
+ for (const p of candidates) {
18
+ try { return _require(p); } catch { /* fall through */ }
19
+ }
20
+ // Fallback: walk up from this file's location to find lib/rules-builder.cjs.
21
+ try { return _require('../../../../../lib/rules-builder.cjs'); } catch { return null; }
22
+ })();
23
+
24
+ // BP1/BP2/BP3 prompt-layer caches — invalidated by source file mtime, not a
25
+ // timer. Cheap: O(sentinel-count) stat calls on each session creation, no file
26
+ // I/O when warm.
27
+ let _sharedRulesCache = null;
28
+ let _sharedRulesMtime = 0;
29
+ const _agentRulesCacheByProfile = new Map();
30
+ let _leadRulesCache = null;
31
+ let _leadRulesMtime = 0;
32
+ let _leadMetaCache = null;
33
+ let _leadMetaMtime = 0;
34
+
35
+ export function _buildSharedRules() {
36
+ if (!_rulesBuilder || typeof _rulesBuilder.buildSharedToolContent !== 'function') return '';
37
+ const PLUGIN_ROOT = mixdogRoot();
38
+ const RULES_DIR = join(PLUGIN_ROOT, 'rules');
39
+ const mtime = maxMtimeRecursive([
40
+ join(RULES_DIR, 'shared'),
41
+ ]);
42
+ if (_sharedRulesCache !== null && mtime <= _sharedRulesMtime) {
43
+ return _sharedRulesCache;
44
+ }
45
+ try {
46
+ const built = _rulesBuilder.buildSharedToolContent({ PLUGIN_ROOT, DATA_DIR: resolvePluginData() });
47
+ _sharedRulesCache = built;
48
+ _sharedRulesMtime = mtime;
49
+ return built;
50
+ } catch (e) {
51
+ throw new Error(`[session] shared tool rules build failed: ${e.message}`);
52
+ }
53
+ }
54
+
55
+ export function _buildAgentRules(profile = 'full') {
56
+ if (!_rulesBuilder || typeof _rulesBuilder.buildAgentRoleContent !== 'function') return '';
57
+ const key = String(profile || 'full');
58
+ const PLUGIN_ROOT = mixdogRoot();
59
+ const DATA_DIR = resolvePluginData();
60
+ const RULES_DIR = join(PLUGIN_ROOT, 'rules');
61
+ const mtime = maxMtimeRecursive([
62
+ join(RULES_DIR, 'agent'),
63
+ join(DATA_DIR, 'mixdog-config.json'),
64
+ ]);
65
+ const cached = _agentRulesCacheByProfile.get(key);
66
+ if (cached && mtime <= cached.mtime) {
67
+ return cached.value;
68
+ }
69
+ try {
70
+ const built = _rulesBuilder.buildAgentRoleContent({ PLUGIN_ROOT, DATA_DIR, profile: key });
71
+ _agentRulesCacheByProfile.set(key, { mtime, value: built });
72
+ return built;
73
+ } catch (e) {
74
+ throw new Error(`[session] agent role rules build failed: ${e.message}`);
75
+ }
76
+ }
77
+
78
+ export function _buildLeadRules() {
79
+ if (!_rulesBuilder || typeof _rulesBuilder.buildLeadRoleContent !== 'function') return '';
80
+ const PLUGIN_ROOT = mixdogRoot();
81
+ const DATA_DIR = resolvePluginData();
82
+ const RULES_DIR = join(PLUGIN_ROOT, 'rules');
83
+ const mtime = maxMtimeRecursive([
84
+ join(RULES_DIR, 'lead'),
85
+ join(DATA_DIR, 'mixdog-config.json'),
86
+ ]);
87
+ if (_leadRulesCache !== null && mtime <= _leadRulesMtime) {
88
+ return _leadRulesCache;
89
+ }
90
+ try {
91
+ const built = _rulesBuilder.buildLeadRoleContent({ PLUGIN_ROOT, DATA_DIR });
92
+ _leadRulesCache = built;
93
+ _leadRulesMtime = mtime;
94
+ return built;
95
+ } catch (e) {
96
+ throw new Error(`[session] lead role rules build failed: ${e.message}`);
97
+ }
98
+ }
99
+
100
+ export function _buildLeadMetaContext() {
101
+ if (!_rulesBuilder || typeof _rulesBuilder.buildLeadMetaContent !== 'function') return '';
102
+ const PLUGIN_ROOT = mixdogRoot();
103
+ const DATA_DIR = resolvePluginData();
104
+ const RULES_DIR = join(PLUGIN_ROOT, 'rules');
105
+ const mtime = maxMtimeRecursive([
106
+ join(RULES_DIR, 'lead'),
107
+ join(DATA_DIR, 'history'),
108
+ join(DATA_DIR, 'mixdog-config.json'),
109
+ join(DATA_DIR, 'user-workflow.md'),
110
+ join(PLUGIN_ROOT, 'output-styles'),
111
+ join(DATA_DIR, 'output-styles'),
112
+ ]);
113
+ if (_leadMetaCache !== null && mtime <= _leadMetaMtime) {
114
+ return _leadMetaCache;
115
+ }
116
+ try {
117
+ const built = _rulesBuilder.buildLeadMetaContent({ PLUGIN_ROOT, DATA_DIR });
118
+ _leadMetaCache = built;
119
+ _leadMetaMtime = mtime;
120
+ return built;
121
+ } catch (e) {
122
+ throw new Error(`[session] lead meta context build failed: ${e.message}`);
123
+ }
124
+ }
125
+
126
+ // BP4-adjacent agent-specific data cache — keyed by agent. webhook / schedule
127
+ // agents each have their own scoped instruction set; other agents return ''.
128
+ const _roleSpecificCache = new Map(); // agent → { value, mtime }
129
+ export function _buildAgentSpecific(currentAgent) {
130
+ if (!_rulesBuilder || typeof _rulesBuilder.buildAgentRoleSpecificContent !== 'function') return '';
131
+ if (!currentAgent) return '';
132
+ const PLUGIN_ROOT = mixdogRoot();
133
+ const DATA_DIR = resolvePluginData();
134
+ const RULES_DIR = join(PLUGIN_ROOT, 'rules');
135
+ const roleInstructionDir = getAgentInstructionDir(currentAgent);
136
+ const mtime = maxMtimeRecursive([
137
+ join(RULES_DIR, 'shared'),
138
+ join(DATA_DIR, 'mixdog-config.json'),
139
+ join(DATA_DIR, 'webhooks'),
140
+ join(DATA_DIR, 'schedules'),
141
+ ...(roleInstructionDir ? [join(DATA_DIR, roleInstructionDir)] : []),
142
+ join(PLUGIN_ROOT, 'defaults', 'agents.json'),
143
+ ]);
144
+ const entry = _roleSpecificCache.get(currentAgent);
145
+ if (entry && mtime <= entry.mtime) {
146
+ return entry.value;
147
+ }
148
+ try {
149
+ const built = _rulesBuilder.buildAgentRoleSpecificContent({ PLUGIN_ROOT, DATA_DIR, currentAgent });
150
+ _roleSpecificCache.set(currentAgent, { mtime, value: built });
151
+ return built;
152
+ } catch (e) {
153
+ throw new Error(`[session] agent-specific rules build failed (agent: ${currentAgent}): ${e.message}`);
154
+ }
155
+ }
@@ -0,0 +1,303 @@
1
+ // Session tool schema resolution + permission narrowing, extracted verbatim
2
+ // from manager.mjs. Behavior-preserving: same toolset ids, same ordering,
3
+ // same dedup, same fail-closed permission intersection.
4
+ import { getMcpTools } from '../../mcp/client.mjs';
5
+ import { getInternalTools } from '../../internal-tools.mjs';
6
+ import { BUILTIN_TOOLS } from '../../tools/builtin/builtin-tools.mjs';
7
+ import { PATCH_TOOL_DEFS } from '../../tools/patch-tool-defs.mjs';
8
+ import { CODE_GRAPH_TOOL_DEFS } from '../../tools/code-graph-tool-defs.mjs';
9
+ import { buildSkillToolDefs } from '../../context/collect.mjs';
10
+ import { getHiddenAgent, listHiddenAgentNames } from '../../internal-agents.mjs';
11
+
12
+ // Merge externally-connected MCP tools with the plugin's in-process tools
13
+ // (registered by agent's toolExecutor adapter). Internal tools are exposed
14
+ // under their bare names — no mcp__ prefix, since the dispatcher in
15
+ // server.mjs handles them directly without a transport.
16
+ // Sorted deterministically by name — protects BP_1 hash stability from
17
+ // listTools() ordering churn. Anthropic / OpenAI / Gemini all hash the
18
+ // tools array verbatim, so any reorder rewrites the prefix.
19
+ // No cache: getMcpTools() and getInternalTools() are O(n) in-memory reads;
20
+ // the sort overhead on ~30 tools is negligible.
21
+ function _getMcpTools() {
22
+ const mcp = getMcpTools() || [];
23
+ const internalRaw = getInternalTools() || [];
24
+ const internal = internalRaw.map(t => ({
25
+ name: t.name,
26
+ description: typeof t.description === 'string' ? t.description : '',
27
+ inputSchema: t.inputSchema || { type: 'object', properties: {} },
28
+ // Keep annotations so the permission filter / role invariants can
29
+ // tell read-only from write-capable internal tools, and so
30
+ // agentHidden can be read during deny filtering.
31
+ annotations: t.annotations || {},
32
+ }));
33
+ return [...mcp, ...internal].sort((a, b) => {
34
+ const an = a?.name || '';
35
+ const bn = b?.name || '';
36
+ return an < bn ? -1 : an > bn ? 1 : 0;
37
+ });
38
+ }
39
+
40
+ const SESSION_ROUTE_TOOL_ORDER = [
41
+ 'code_graph',
42
+ 'find',
43
+ 'glob',
44
+ 'list',
45
+ 'grep',
46
+ 'read',
47
+ 'apply_patch',
48
+ 'shell',
49
+ 'task',
50
+ ];
51
+ const SESSION_ROUTE_TOOL_RANK = new Map(SESSION_ROUTE_TOOL_ORDER.map((name, index) => [name, index]));
52
+ const FILESYSTEM_TOOL_NAMES = new Set([
53
+ 'code_graph',
54
+ 'find',
55
+ 'glob',
56
+ 'list',
57
+ 'grep',
58
+ 'read',
59
+ 'apply_patch',
60
+ ]);
61
+ const READONLY_TOOL_NAMES = new Set([
62
+ 'code_graph',
63
+ 'find',
64
+ 'glob',
65
+ 'list',
66
+ 'grep',
67
+ 'read',
68
+ ]);
69
+
70
+ const AGENT_STRING_PERMISSION_READ_ALLOW = Object.freeze([
71
+ 'code_graph',
72
+ 'find',
73
+ 'glob',
74
+ 'list',
75
+ 'grep',
76
+ 'read',
77
+ 'explore',
78
+ 'search',
79
+ 'web_fetch',
80
+ 'Skill',
81
+ ]);
82
+
83
+ function stringToolPermissionAllowList(toolPermission) {
84
+ if (toolPermission === 'read') return AGENT_STRING_PERMISSION_READ_ALLOW;
85
+ if (toolPermission === 'read-write') return AGENT_STRING_PERMISSION_READ_WRITE_ALLOW;
86
+ if (toolPermission === 'none') return [];
87
+ return null;
88
+ }
89
+
90
+ const AGENT_STRING_PERMISSION_READ_WRITE_ALLOW = Object.freeze([
91
+ 'code_graph',
92
+ 'find',
93
+ 'glob',
94
+ 'list',
95
+ 'grep',
96
+ 'read',
97
+ 'apply_patch',
98
+ 'explore',
99
+ 'search',
100
+ 'web_fetch',
101
+ 'Skill',
102
+ ]);
103
+
104
+ export function applyToolPermissionNarrowing(tools, toolPermission, warnRole = null) {
105
+ if (toolPermission === 'none') return [];
106
+ const allowList = stringToolPermissionAllowList(toolPermission);
107
+ if (allowList) {
108
+ const allowSet = new Set(allowList.map((n) => String(n).toLowerCase()));
109
+ return tools.filter((t) => allowSet.has(String(t?.name || '').toLowerCase()));
110
+ }
111
+ if (toolPermission && typeof toolPermission === 'object') {
112
+ const allowSet = Array.isArray(toolPermission.allow) && toolPermission.allow.length > 0
113
+ ? new Set(toolPermission.allow.map(n => String(n).toLowerCase()))
114
+ : null;
115
+ const denySet = Array.isArray(toolPermission.deny) && toolPermission.deny.length > 0
116
+ ? new Set(toolPermission.deny.map(n => String(n).toLowerCase()))
117
+ : null;
118
+ if (allowSet || denySet) {
119
+ const filtered = tools.filter(t => {
120
+ const name = String(t?.name || '').toLowerCase();
121
+ if (denySet && denySet.has(name)) return false;
122
+ if (allowSet && !allowSet.has(name)) return false;
123
+ return true;
124
+ });
125
+ if (filtered.length === 0) {
126
+ process.stderr.write(`[session] WARN: role permission intersection produced 0 tools — failing closed (role=${warnRole || 'unknown'})\n`);
127
+ }
128
+ return filtered;
129
+ }
130
+ }
131
+ return tools;
132
+ }
133
+
134
+ function recursiveWrapperToolNameForPublicAgent(agent) {
135
+ if (!agent) return null;
136
+ const key = String(agent).trim();
137
+ if (key === 'explore') return 'explore';
138
+ for (const hiddenName of listHiddenAgentNames()) {
139
+ const def = getHiddenAgent(hiddenName);
140
+ const invokedBy = typeof def?.invokedBy === 'string' ? def.invokedBy.trim() : '';
141
+ if (hiddenName === key && invokedBy) return invokedBy;
142
+ if (invokedBy && invokedBy === key) return invokedBy;
143
+ }
144
+ return null;
145
+ }
146
+
147
+ export function finalizeSessionToolList(tools, {
148
+ schemaAllowedTools = null,
149
+ disallowedTools = null,
150
+ ownerIsAgent = false,
151
+ resolvedAgent = null,
152
+ } = {}) {
153
+ let out = Array.isArray(tools) ? tools : [];
154
+ const hasCallerAllow = Array.isArray(schemaAllowedTools);
155
+ if (hasCallerAllow) {
156
+ const allowSet = new Set(schemaAllowedTools.map(n => String(n).toLowerCase()));
157
+ out = out.filter(t => allowSet.has(String(t?.name || '').toLowerCase()));
158
+ }
159
+ const callerDeny = Array.isArray(disallowedTools) ? disallowedTools.map(n => String(n)) : [];
160
+ if (callerDeny.length) {
161
+ const denySet = new Set(callerDeny.map(n => n.toLowerCase()));
162
+ out = out.filter(t => !denySet.has(String(t?.name || '').toLowerCase()));
163
+ }
164
+ const recursiveDeny = ownerIsAgent ? recursiveWrapperToolNameForPublicAgent(resolvedAgent) : null;
165
+ if (recursiveDeny) {
166
+ const deny = recursiveDeny.toLowerCase();
167
+ out = out.filter(t => String(t?.name || '').toLowerCase() !== deny);
168
+ }
169
+ if (ownerIsAgent) {
170
+ out = out.filter(t => !t?.annotations?.agentHidden);
171
+ out = orderSessionTools(out);
172
+ }
173
+ return out;
174
+ }
175
+
176
+ function orderSessionTools(tools) {
177
+ return tools.map((tool, index) => ({ tool, index }))
178
+ .sort((a, b) => {
179
+ const ar = SESSION_ROUTE_TOOL_RANK.get(a.tool?.name) ?? 10_000;
180
+ const br = SESSION_ROUTE_TOOL_RANK.get(b.tool?.name) ?? 10_000;
181
+ if (ar !== br) return ar - br;
182
+ return a.index - b.index;
183
+ })
184
+ .map((entry) => entry.tool);
185
+ }
186
+
187
+ const ALL_BUILTIN_SESSION_TOOLS = orderSessionTools(_dedupByName([
188
+ ...BUILTIN_TOOLS,
189
+ ...PATCH_TOOL_DEFS,
190
+ ...CODE_GRAPH_TOOL_DEFS,
191
+ ]));
192
+
193
+ export function resolveSessionTools(toolSpec, skills, { ownerIsAgentSession = false } = {}) {
194
+ const mcp = _getMcpTools();
195
+ // Agent sessions freeze the skill meta-tool into the schema
196
+ // unconditionally — concrete skill resolution is cwd-scoped at tool-call
197
+ // time (loop.mjs), so the schema bytes stay bit-identical across roles /
198
+ // cwds and the provider cache shard does not fragment.
199
+ const skillTools = buildSkillToolDefs(skills, { ownerIsAgentSession });
200
+ return _computeBaseTools(toolSpec, mcp, skillTools);
201
+ }
202
+
203
+ export function previewSessionTools(toolSpec, skills = [], options = {}) {
204
+ return resolveSessionTools(toolSpec, skills, options);
205
+ }
206
+
207
+ // Dedup by name, first occurrence wins. BUILTIN_TOOLS is passed in ahead
208
+ // of the MCP-registered internal tools so plugin-side definitions take
209
+ // precedence when both surfaces declare the same name (e.g. read / grep / glob).
210
+ // Without this merge, Anthropic rejected the request with
211
+ // "tools: Tool names must be unique" and the orchestrator burned up to
212
+ // 20 iterations retrying before the final answer landed.
213
+ function _dedupByName(tools) {
214
+ const seen = new Map();
215
+ for (const t of tools) {
216
+ const n = t?.name;
217
+ if (!n || seen.has(n)) continue;
218
+ seen.set(n, t);
219
+ }
220
+ return [...seen.values()];
221
+ }
222
+
223
+ // Agent visibility is declared per-tool via annotations.agentHidden.
224
+ // Tools with agentHidden:true are stripped from agent sessions at schema
225
+ // build time (see deny filtering below). No code-level name list needed.
226
+
227
+ function _computeBaseTools(toolSpec, mcp, skillTools) {
228
+ if (Array.isArray(toolSpec)) {
229
+ if (toolSpec.length === 0) {
230
+ // Explicit "no tools" — skill meta tools still travel so the model
231
+ // can at least discover and invoke skills if that is the one
232
+ // dynamic surface the profile retains.
233
+ return _dedupByName([...skillTools]);
234
+ }
235
+ if (toolSpec.includes('full')) {
236
+ return _dedupByName([...ALL_BUILTIN_SESSION_TOOLS, ...mcp, ...skillTools]);
237
+ }
238
+ const byName = new Map();
239
+ const add = (tool) => { if (tool?.name && !byName.has(tool.name)) byName.set(tool.name, tool); };
240
+ const addMany = (arr) => { for (const t of arr) add(t); };
241
+ for (const tagRaw of toolSpec) {
242
+ const tag = String(tagRaw || '').trim();
243
+ switch (tag) {
244
+ case 'tools:filesystem':
245
+ addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => FILESYSTEM_TOOL_NAMES.has(t.name)));
246
+ break;
247
+ case 'tools:readonly':
248
+ addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => READONLY_TOOL_NAMES.has(t.name)));
249
+ break;
250
+ case 'tools:shell':
251
+ case 'tools:git':
252
+ case 'tools:analysis':
253
+ // Shell-class toolset. `tools:git` / `tools:analysis` exist so
254
+ // profile authors can name the intent (git workflows / data
255
+ // analysis) without inventing new toolset ids.
256
+ addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => t.name === 'shell' || t.name === 'task'));
257
+ break;
258
+ case 'tools:mcp':
259
+ addMany(mcp);
260
+ break;
261
+ case 'tools:search':
262
+ // Name-pattern match: picks up `search` and any future tool
263
+ // whose name contains `search`. `recall` and `explore` deliberately do NOT match
264
+ // — they need `tools:mcp` (full mcp surface) or their own
265
+ // toolset id if a role wants targeted retrieval. Public agent
266
+ // roles never reach the wrapper bodies regardless: see the
267
+ // isBlockedPublicWrapperCall guard in session/loop.mjs.
268
+ addMany(mcp.filter(t => /search/i.test(t?.name || '')));
269
+ break;
270
+ default:
271
+ process.stderr.write(`[session] unknown toolset id "${tag}" (profile.tools); skipping\n`);
272
+ }
273
+ }
274
+ return _dedupByName([...byName.values(), ...skillTools]);
275
+ }
276
+
277
+ switch (toolSpec) {
278
+ case 'mcp':
279
+ return _dedupByName([...mcp, ...skillTools]);
280
+ case 'readonly': {
281
+ const readTools = ALL_BUILTIN_SESSION_TOOLS.filter(t => READONLY_TOOL_NAMES.has(t.name));
282
+ return _dedupByName([...readTools, ...mcp, ...skillTools]);
283
+ }
284
+ case 'full':
285
+ default:
286
+ return _dedupByName([...ALL_BUILTIN_SESSION_TOOLS, ...mcp, ...skillTools]);
287
+ }
288
+ }
289
+
290
+ export function permissionFromToolSpec(toolSpec) {
291
+ if (toolSpec === 'readonly') return 'read';
292
+ if (toolSpec === 'mcp') return 'mcp';
293
+ if (Array.isArray(toolSpec)) {
294
+ const tags = new Set(toolSpec.map(t => String(t || '').trim()));
295
+ const hasWriteOrShell = tags.has('full')
296
+ || tags.has('tools:filesystem')
297
+ || tags.has('tools:shell')
298
+ || tags.has('tools:git')
299
+ || tags.has('tools:analysis');
300
+ if (tags.has('tools:readonly') && !hasWriteOrShell) return 'read';
301
+ }
302
+ return null;
303
+ }