mixdog 0.7.18 → 0.8.0

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 (844) hide show
  1. package/README.md +37 -331
  2. package/package.json +67 -99
  3. package/scripts/boot-smoke.mjs +94 -0
  4. package/scripts/build-tui.mjs +52 -0
  5. package/scripts/compact-smoke.mjs +199 -0
  6. package/scripts/lead-workflow-smoke.mjs +598 -0
  7. package/scripts/live-worker-smoke.mjs +239 -0
  8. package/scripts/output-style-smoke.mjs +101 -0
  9. package/scripts/smoke-loop-report.mjs +221 -0
  10. package/scripts/smoke-loop.mjs +201 -0
  11. package/scripts/smoke.mjs +113 -0
  12. package/scripts/tool-failures.mjs +143 -0
  13. package/scripts/tool-smoke.mjs +456 -0
  14. package/src/agents/debugger/AGENT.md +3 -0
  15. package/src/agents/debugger/agent.json +6 -0
  16. package/src/agents/explore/AGENT.md +4 -0
  17. package/src/agents/explore/agent.json +6 -0
  18. package/src/agents/heavy-worker/AGENT.md +3 -0
  19. package/src/agents/heavy-worker/agent.json +6 -0
  20. package/src/agents/maintainer/AGENT.md +3 -0
  21. package/src/agents/maintainer/agent.json +6 -0
  22. package/src/agents/reviewer/AGENT.md +3 -0
  23. package/src/agents/reviewer/agent.json +6 -0
  24. package/src/agents/scheduler-task.md +3 -0
  25. package/src/agents/web-researcher/AGENT.md +3 -0
  26. package/src/agents/web-researcher/agent.json +6 -0
  27. package/src/agents/webhook-handler.md +3 -0
  28. package/src/agents/worker/AGENT.md +3 -0
  29. package/src/agents/worker/agent.json +6 -0
  30. package/src/app.mjs +90 -0
  31. package/src/cli.mjs +11 -0
  32. package/src/defaults/hidden-roles.json +72 -0
  33. package/src/defaults/mixdog-config.template.json +15 -0
  34. package/src/hooks/lib/permission-evaluator.cjs +488 -0
  35. package/src/hooks/lib/settings-loader.cjs +112 -0
  36. package/src/lib/keychain-cjs.cjs +332 -0
  37. package/src/lib/plugin-paths.cjs +28 -0
  38. package/src/lib/rules-builder.cjs +315 -0
  39. package/src/mixdog-session-runtime.mjs +3704 -0
  40. package/src/output-styles/default.md +38 -0
  41. package/src/output-styles/extreme-simple.md +17 -0
  42. package/src/output-styles/simple.md +17 -0
  43. package/src/repl.mjs +322 -0
  44. package/src/rules/bridge/00-common.md +5 -0
  45. package/src/rules/bridge/20-skip-protocol.md +11 -0
  46. package/src/rules/bridge/30-explorer.md +4 -0
  47. package/src/rules/bridge/40-cycle1-agent.md +28 -0
  48. package/src/rules/bridge/41-cycle2-agent.md +59 -0
  49. package/src/rules/lead/00-tool-lead.md +5 -0
  50. package/src/rules/lead/01-general.md +5 -0
  51. package/src/rules/lead/02-channels.md +3 -0
  52. package/src/rules/lead/04-workflow.md +12 -0
  53. package/src/rules/shared/00-language.md +3 -0
  54. package/src/rules/shared/01-tool.md +3 -0
  55. package/src/runtime/agent/orchestrator/bridge-trace.mjs +814 -0
  56. package/src/runtime/agent/orchestrator/cache-mtime.mjs +60 -0
  57. package/src/runtime/agent/orchestrator/config.mjs +446 -0
  58. package/src/runtime/agent/orchestrator/context/collect.mjs +796 -0
  59. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +417 -0
  60. package/src/runtime/agent/orchestrator/internal-roles.mjs +188 -0
  61. package/src/runtime/agent/orchestrator/internal-tools.mjs +88 -0
  62. package/src/runtime/agent/orchestrator/mcp/client.mjs +345 -0
  63. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2104 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +784 -0
  65. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +341 -0
  66. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1679 -0
  67. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +959 -0
  68. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +213 -0
  69. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +38 -0
  70. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +471 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +615 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +808 -0
  73. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +1719 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2587 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1953 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +136 -0
  77. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +317 -0
  78. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +109 -0
  79. package/src/runtime/agent/orchestrator/providers/registry.mjs +247 -0
  80. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +332 -0
  81. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +11 -0
  82. package/src/runtime/agent/orchestrator/providers/trace-utils.mjs +50 -0
  83. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  84. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +318 -0
  85. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +367 -0
  86. package/src/runtime/agent/orchestrator/session/compact.mjs +882 -0
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +233 -0
  88. package/src/runtime/agent/orchestrator/session/loop.mjs +2320 -0
  89. package/src/runtime/agent/orchestrator/session/manager.mjs +2960 -0
  90. package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
  91. package/src/runtime/agent/orchestrator/session/store.mjs +663 -0
  92. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  93. package/src/runtime/agent/orchestrator/smart-bridge/bridge-llm.mjs +339 -0
  94. package/src/runtime/agent/orchestrator/smart-bridge/cache-strategy.mjs +419 -0
  95. package/src/runtime/agent/orchestrator/stall-policy.mjs +227 -0
  96. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +235 -0
  97. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +723 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +389 -0
  99. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +637 -0
  100. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +165 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +104 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +194 -0
  103. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +596 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +110 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +153 -0
  106. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  107. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +189 -0
  108. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +731 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +168 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +465 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +160 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +982 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1087 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +231 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +223 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin.mjs +478 -0
  118. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  119. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4102 -0
  120. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  121. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +154 -0
  122. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +26 -0
  123. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +143 -0
  124. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +18 -0
  125. package/src/runtime/agent/orchestrator/tools/patch.mjs +2772 -0
  126. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +114 -0
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +880 -0
  128. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +312 -0
  129. package/src/runtime/channels/backends/discord.mjs +781 -0
  130. package/src/runtime/channels/data/voice-runtime-manifest.json +138 -0
  131. package/src/runtime/channels/index.mjs +3309 -0
  132. package/src/runtime/channels/lib/config.mjs +285 -0
  133. package/src/runtime/channels/lib/drop-trace.mjs +71 -0
  134. package/src/runtime/channels/lib/event-pipeline.mjs +81 -0
  135. package/src/runtime/channels/lib/holidays.mjs +138 -0
  136. package/src/runtime/channels/lib/hook-pipe-server.mjs +671 -0
  137. package/src/runtime/channels/lib/output-forwarder.mjs +765 -0
  138. package/src/runtime/channels/lib/runtime-paths.mjs +497 -0
  139. package/src/runtime/channels/lib/scheduler.mjs +710 -0
  140. package/src/runtime/channels/lib/session-discovery.mjs +102 -0
  141. package/src/runtime/channels/lib/state-file.mjs +68 -0
  142. package/src/runtime/channels/lib/status-snapshot.mjs +224 -0
  143. package/src/runtime/channels/lib/tool-format.mjs +124 -0
  144. package/src/runtime/channels/lib/transcript-discovery.mjs +195 -0
  145. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +734 -0
  146. package/src/runtime/channels/lib/webhook.mjs +1288 -0
  147. package/src/runtime/channels/tool-defs.mjs +177 -0
  148. package/src/runtime/lib/keychain-cjs.cjs +289 -0
  149. package/src/runtime/memory/data/runtime-manifest.json +40 -0
  150. package/src/runtime/memory/index.mjs +3600 -0
  151. package/src/runtime/memory/lib/core-memory-store.mjs +336 -0
  152. package/src/runtime/memory/lib/embedding-provider.mjs +275 -0
  153. package/src/runtime/memory/lib/embedding-worker.mjs +331 -0
  154. package/src/runtime/memory/lib/memory-cycle-requests.mjs +276 -0
  155. package/src/runtime/memory/lib/memory-cycle1.mjs +783 -0
  156. package/src/runtime/memory/lib/memory-cycle2.mjs +1389 -0
  157. package/src/runtime/memory/lib/memory-cycle3.mjs +646 -0
  158. package/src/runtime/memory/lib/memory-embed.mjs +300 -0
  159. package/src/runtime/memory/lib/memory-ops-policy.mjs +149 -0
  160. package/src/runtime/memory/lib/memory-recall-store.mjs +644 -0
  161. package/src/runtime/memory/lib/memory.mjs +418 -0
  162. package/src/runtime/memory/lib/pg/adapter.mjs +314 -0
  163. package/src/runtime/memory/lib/pg/process.mjs +366 -0
  164. package/src/runtime/memory/lib/pg/supervisor.mjs +495 -0
  165. package/src/runtime/memory/lib/runtime-fetcher.mjs +464 -0
  166. package/src/runtime/memory/lib/trace-store.mjs +734 -0
  167. package/src/runtime/memory/tool-defs.mjs +79 -0
  168. package/src/runtime/search/index.mjs +925 -0
  169. package/src/runtime/search/lib/config.mjs +61 -0
  170. package/src/runtime/search/lib/web-tools.mjs +1278 -0
  171. package/src/runtime/search/tool-defs.mjs +64 -0
  172. package/src/runtime/shared/atomic-file.mjs +435 -0
  173. package/src/runtime/shared/background-tasks.mjs +376 -0
  174. package/src/runtime/shared/child-guardian.mjs +98 -0
  175. package/src/runtime/shared/config.mjs +393 -0
  176. package/src/runtime/shared/err-text.mjs +121 -0
  177. package/src/runtime/shared/launcher-control.mjs +259 -0
  178. package/src/runtime/shared/llm/http-agent.mjs +129 -0
  179. package/src/runtime/shared/open-url.mjs +37 -0
  180. package/src/runtime/shared/plugin-paths.mjs +25 -0
  181. package/src/runtime/shared/process-shutdown.mjs +147 -0
  182. package/src/runtime/shared/schedules-store.mjs +70 -0
  183. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  184. package/src/runtime/shared/tool-surface.mjs +950 -0
  185. package/src/runtime/shared/user-cwd.mjs +221 -0
  186. package/src/runtime/shared/user-data-guard.mjs +232 -0
  187. package/src/runtime/shared/workspace-router.mjs +259 -0
  188. package/src/standalone/bridge-tool.mjs +1414 -0
  189. package/src/standalone/channel-admin.mjs +366 -0
  190. package/src/standalone/channel-worker-preload.cjs +3 -0
  191. package/src/standalone/channel-worker.mjs +353 -0
  192. package/src/standalone/explore-tool.mjs +233 -0
  193. package/src/standalone/hook-bus.mjs +246 -0
  194. package/src/standalone/plugin-admin.mjs +247 -0
  195. package/src/standalone/provider-admin.mjs +338 -0
  196. package/src/standalone/seeds.mjs +94 -0
  197. package/src/standalone/usage-dashboard.mjs +510 -0
  198. package/src/tui/App.jsx +5438 -0
  199. package/src/tui/components/AnsiText.jsx +199 -0
  200. package/src/tui/components/ContextPanel.jsx +217 -0
  201. package/src/tui/components/Markdown.jsx +205 -0
  202. package/src/tui/components/MarkdownTable.jsx +204 -0
  203. package/src/tui/components/Message.jsx +103 -0
  204. package/src/tui/components/Picker.jsx +317 -0
  205. package/src/tui/components/PromptInput.jsx +584 -0
  206. package/src/tui/components/QueuedCommands.jsx +47 -0
  207. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  208. package/src/tui/components/Spinner.jsx +317 -0
  209. package/src/tui/components/StatusLine.jsx +87 -0
  210. package/src/tui/components/TextEntryPanel.jsx +323 -0
  211. package/src/tui/components/ToolExecution.jsx +772 -0
  212. package/src/tui/components/TurnDone.jsx +78 -0
  213. package/src/tui/components/UsagePanel.jsx +331 -0
  214. package/src/tui/dist/index.mjs +12359 -0
  215. package/src/tui/engine.mjs +2410 -0
  216. package/src/tui/figures.mjs +50 -0
  217. package/src/tui/hooks/useEngine.mjs +16 -0
  218. package/src/tui/index.jsx +254 -0
  219. package/src/tui/input-editing.mjs +242 -0
  220. package/src/tui/markdown/format-token.mjs +194 -0
  221. package/src/tui/paste-attachments.mjs +198 -0
  222. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  223. package/src/tui/spinner-verbs.mjs +45 -0
  224. package/src/tui/theme.mjs +67 -0
  225. package/src/tui/time-format.mjs +53 -0
  226. package/src/ui/ansi.mjs +115 -0
  227. package/src/ui/markdown.mjs +195 -0
  228. package/src/ui/statusline.mjs +730 -0
  229. package/src/ui/tool-card.mjs +101 -0
  230. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  231. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  232. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  233. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  234. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  235. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  236. package/src/workflows/default/WORKFLOW.md +7 -0
  237. package/src/workflows/default/workflow.json +14 -0
  238. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  239. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  240. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  241. package/vendor/ink/build/colorize.d.ts +3 -0
  242. package/vendor/ink/build/colorize.js +48 -0
  243. package/vendor/ink/build/colorize.js.map +1 -0
  244. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  245. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  246. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  247. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  248. package/vendor/ink/build/components/AnimationContext.js +13 -0
  249. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  250. package/vendor/ink/build/components/App.d.ts +24 -0
  251. package/vendor/ink/build/components/App.js +554 -0
  252. package/vendor/ink/build/components/App.js.map +1 -0
  253. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  254. package/vendor/ink/build/components/AppContext.js +25 -0
  255. package/vendor/ink/build/components/AppContext.js.map +1 -0
  256. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  257. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  258. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  259. package/vendor/ink/build/components/Box.d.ts +130 -0
  260. package/vendor/ink/build/components/Box.js +34 -0
  261. package/vendor/ink/build/components/Box.js.map +1 -0
  262. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  263. package/vendor/ink/build/components/CursorContext.js +8 -0
  264. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  265. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  266. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  267. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  268. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  269. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  270. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  271. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  272. package/vendor/ink/build/components/FocusContext.js +17 -0
  273. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  274. package/vendor/ink/build/components/Newline.d.ts +13 -0
  275. package/vendor/ink/build/components/Newline.js +8 -0
  276. package/vendor/ink/build/components/Newline.js.map +1 -0
  277. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  278. package/vendor/ink/build/components/Spacer.js +11 -0
  279. package/vendor/ink/build/components/Spacer.js.map +1 -0
  280. package/vendor/ink/build/components/Static.d.ts +24 -0
  281. package/vendor/ink/build/components/Static.js +28 -0
  282. package/vendor/ink/build/components/Static.js.map +1 -0
  283. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  284. package/vendor/ink/build/components/StderrContext.js +13 -0
  285. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  286. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  287. package/vendor/ink/build/components/StdinContext.js +20 -0
  288. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  289. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  290. package/vendor/ink/build/components/StdoutContext.js +13 -0
  291. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  292. package/vendor/ink/build/components/Text.d.ts +55 -0
  293. package/vendor/ink/build/components/Text.js +50 -0
  294. package/vendor/ink/build/components/Text.js.map +1 -0
  295. package/vendor/ink/build/components/Transform.d.ts +16 -0
  296. package/vendor/ink/build/components/Transform.js +15 -0
  297. package/vendor/ink/build/components/Transform.js.map +1 -0
  298. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  299. package/vendor/ink/build/cursor-helpers.js +62 -0
  300. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  301. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  302. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  303. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  304. package/vendor/ink/build/devtools.d.ts +1 -0
  305. package/vendor/ink/build/devtools.js +36 -0
  306. package/vendor/ink/build/devtools.js.map +1 -0
  307. package/vendor/ink/build/dom.d.ts +62 -0
  308. package/vendor/ink/build/dom.js +143 -0
  309. package/vendor/ink/build/dom.js.map +1 -0
  310. package/vendor/ink/build/get-max-width.d.ts +3 -0
  311. package/vendor/ink/build/get-max-width.js +10 -0
  312. package/vendor/ink/build/get-max-width.js.map +1 -0
  313. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  314. package/vendor/ink/build/hooks/use-animation.js +87 -0
  315. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  316. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  317. package/vendor/ink/build/hooks/use-app.js +8 -0
  318. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  319. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  320. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  321. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  322. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  323. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  324. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  325. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  326. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  327. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  328. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  329. package/vendor/ink/build/hooks/use-focus.js +43 -0
  330. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  331. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  332. package/vendor/ink/build/hooks/use-input.js +126 -0
  333. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  334. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  335. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  336. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  337. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  338. package/vendor/ink/build/hooks/use-paste.js +62 -0
  339. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  340. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  341. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  342. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  343. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  344. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  345. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  346. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  347. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  348. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  349. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  350. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  351. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  352. package/vendor/ink/build/index.d.ts +42 -0
  353. package/vendor/ink/build/index.js +24 -0
  354. package/vendor/ink/build/index.js.map +1 -0
  355. package/vendor/ink/build/ink.d.ts +146 -0
  356. package/vendor/ink/build/ink.js +1022 -0
  357. package/vendor/ink/build/ink.js.map +1 -0
  358. package/vendor/ink/build/input-parser.d.ts +10 -0
  359. package/vendor/ink/build/input-parser.js +194 -0
  360. package/vendor/ink/build/input-parser.js.map +1 -0
  361. package/vendor/ink/build/instances.d.ts +3 -0
  362. package/vendor/ink/build/instances.js +8 -0
  363. package/vendor/ink/build/instances.js.map +1 -0
  364. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  365. package/vendor/ink/build/kitty-keyboard.js +32 -0
  366. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  367. package/vendor/ink/build/log-update.d.ts +20 -0
  368. package/vendor/ink/build/log-update.js +261 -0
  369. package/vendor/ink/build/log-update.js.map +1 -0
  370. package/vendor/ink/build/measure-element.d.ts +20 -0
  371. package/vendor/ink/build/measure-element.js +13 -0
  372. package/vendor/ink/build/measure-element.js.map +1 -0
  373. package/vendor/ink/build/measure-text.d.ts +6 -0
  374. package/vendor/ink/build/measure-text.js +21 -0
  375. package/vendor/ink/build/measure-text.js.map +1 -0
  376. package/vendor/ink/build/output.d.ts +35 -0
  377. package/vendor/ink/build/output.js +328 -0
  378. package/vendor/ink/build/output.js.map +1 -0
  379. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  380. package/vendor/ink/build/parse-keypress.js +495 -0
  381. package/vendor/ink/build/parse-keypress.js.map +1 -0
  382. package/vendor/ink/build/reconciler.d.ts +4 -0
  383. package/vendor/ink/build/reconciler.js +306 -0
  384. package/vendor/ink/build/reconciler.js.map +1 -0
  385. package/vendor/ink/build/render-background.d.ts +4 -0
  386. package/vendor/ink/build/render-background.js +25 -0
  387. package/vendor/ink/build/render-background.js.map +1 -0
  388. package/vendor/ink/build/render-border.d.ts +4 -0
  389. package/vendor/ink/build/render-border.js +84 -0
  390. package/vendor/ink/build/render-border.js.map +1 -0
  391. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  392. package/vendor/ink/build/render-node-to-output.js +162 -0
  393. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  394. package/vendor/ink/build/render-to-string.d.ts +38 -0
  395. package/vendor/ink/build/render-to-string.js +116 -0
  396. package/vendor/ink/build/render-to-string.js.map +1 -0
  397. package/vendor/ink/build/render.d.ts +176 -0
  398. package/vendor/ink/build/render.js +71 -0
  399. package/vendor/ink/build/render.js.map +1 -0
  400. package/vendor/ink/build/renderer.d.ts +8 -0
  401. package/vendor/ink/build/renderer.js +64 -0
  402. package/vendor/ink/build/renderer.js.map +1 -0
  403. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  404. package/vendor/ink/build/sanitize-ansi.js +27 -0
  405. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  406. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  407. package/vendor/ink/build/squash-text-nodes.js +36 -0
  408. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  409. package/vendor/ink/build/styles.d.ts +302 -0
  410. package/vendor/ink/build/styles.js +303 -0
  411. package/vendor/ink/build/styles.js.map +1 -0
  412. package/vendor/ink/build/utils.d.ts +9 -0
  413. package/vendor/ink/build/utils.js +19 -0
  414. package/vendor/ink/build/utils.js.map +1 -0
  415. package/vendor/ink/build/wrap-text.d.ts +3 -0
  416. package/vendor/ink/build/wrap-text.js +38 -0
  417. package/vendor/ink/build/wrap-text.js.map +1 -0
  418. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  419. package/vendor/ink/build/write-synchronized.js +9 -0
  420. package/vendor/ink/build/write-synchronized.js.map +1 -0
  421. package/vendor/ink/license +10 -0
  422. package/vendor/ink/package.json +137 -0
  423. package/.claude-plugin/marketplace.json +0 -34
  424. package/.claude-plugin/plugin.json +0 -20
  425. package/.gitattributes +0 -34
  426. package/.mcp.json +0 -14
  427. package/ARCHITECTURE.md +0 -77
  428. package/CHANGELOG.md +0 -30
  429. package/CONTRIBUTING.md +0 -45
  430. package/DATA-FLOW.md +0 -79
  431. package/LICENSE +0 -21
  432. package/SECURITY.md +0 -138
  433. package/UNINSTALL.md +0 -115
  434. package/agents/maintenance.md +0 -5
  435. package/agents/memory-classification.md +0 -30
  436. package/agents/scheduler-task.md +0 -18
  437. package/agents/webhook-handler.md +0 -27
  438. package/agents/worker.md +0 -24
  439. package/bin/bridge +0 -133
  440. package/bin/statusline-launcher.mjs +0 -82
  441. package/bin/statusline-lib.mjs +0 -581
  442. package/bin/statusline-route.mjs +0 -273
  443. package/bin/statusline.mjs +0 -638
  444. package/bun.lock +0 -927
  445. package/commands/config.md +0 -16
  446. package/commands/doctor.md +0 -13
  447. package/commands/model.md +0 -61
  448. package/commands/setup.md +0 -17
  449. package/defaults/hidden-roles.json +0 -68
  450. package/defaults/memory-chunk-prompt.md +0 -63
  451. package/defaults/mixdog-config.template.json +0 -27
  452. package/defaults/user-workflow.json +0 -8
  453. package/defaults/user-workflow.md +0 -17
  454. package/hooks/hooks.json +0 -73
  455. package/hooks/lib/active-instance.cjs +0 -77
  456. package/hooks/lib/permission-evaluator.cjs +0 -411
  457. package/hooks/lib/permission-route.cjs +0 -63
  458. package/hooks/lib/settings-loader.cjs +0 -117
  459. package/hooks/post-tool-use.cjs +0 -84
  460. package/hooks/pre-mcp-sandbox.cjs +0 -158
  461. package/hooks/pre-tool-subagent.cjs +0 -258
  462. package/hooks/session-start.cjs +0 -1493
  463. package/hooks/shim-launcher.cjs +0 -65
  464. package/hooks/turn-timer.cjs +0 -82
  465. package/lib/claude-md-writer.cjs +0 -386
  466. package/lib/keychain-cjs.cjs +0 -290
  467. package/lib/plugin-paths.cjs +0 -69
  468. package/lib/rules-builder.cjs +0 -241
  469. package/native/README.md +0 -117
  470. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  471. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  472. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  473. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  474. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  475. package/prompts/code-review.txt +0 -16
  476. package/prompts/security-audit.txt +0 -17
  477. package/rules/bridge/00-common.md +0 -39
  478. package/rules/bridge/20-skip-protocol.md +0 -18
  479. package/rules/bridge/30-explorer.md +0 -33
  480. package/rules/bridge/40-cycle1-agent.md +0 -52
  481. package/rules/bridge/41-cycle2-agent.md +0 -62
  482. package/rules/lead/00-tool-lead.md +0 -61
  483. package/rules/lead/01-general.md +0 -26
  484. package/rules/lead/02-channels.md +0 -49
  485. package/rules/lead/03-team.md +0 -27
  486. package/rules/lead/04-workflow.md +0 -20
  487. package/rules/shared/00-language.md +0 -14
  488. package/rules/shared/01-tool.md +0 -138
  489. package/scripts/bootstrap.mjs +0 -130
  490. package/scripts/bridge-unify-smoke.mjs +0 -308
  491. package/scripts/build-runtime-linux.sh +0 -348
  492. package/scripts/build-runtime-macos.sh +0 -217
  493. package/scripts/build-runtime-windows.ps1 +0 -242
  494. package/scripts/builtin-utils-smoke.mjs +0 -398
  495. package/scripts/bump.mjs +0 -80
  496. package/scripts/check-json.mjs +0 -45
  497. package/scripts/check-syntax-changed.mjs +0 -102
  498. package/scripts/check-syntax.mjs +0 -58
  499. package/scripts/code-graph-batch.test.mjs +0 -33
  500. package/scripts/config-preserve-smoke.mjs +0 -180
  501. package/scripts/doctor.mjs +0 -489
  502. package/scripts/edit-normalize-fuzz.mjs +0 -130
  503. package/scripts/edit-normalize-smoke.mjs +0 -401
  504. package/scripts/edit-operation-smoke.mjs +0 -369
  505. package/scripts/edit2-smoke.mjs +0 -63
  506. package/scripts/ensure-deps.mjs +0 -259
  507. package/scripts/fuzzy-e2e.mjs +0 -28
  508. package/scripts/fuzzy-smoke.mjs +0 -26
  509. package/scripts/gateway-model.mjs +0 -596
  510. package/scripts/generate-runtime-manifest.mjs +0 -166
  511. package/scripts/guard-smoke.mjs +0 -66
  512. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  513. package/scripts/hook-routing-smoke.mjs +0 -29
  514. package/scripts/inject-input.ps1 +0 -204
  515. package/scripts/io-complex-smoke.mjs +0 -667
  516. package/scripts/io-explore-bench.mjs +0 -424
  517. package/scripts/io-guardrails-smoke.mjs +0 -205
  518. package/scripts/io-mini-bench-baseline.json +0 -11
  519. package/scripts/io-mini-bench.mjs +0 -216
  520. package/scripts/io-route-harness.mjs +0 -933
  521. package/scripts/io-telemetry-report.mjs +0 -691
  522. package/scripts/lib/gateway-inventory.mjs +0 -178
  523. package/scripts/lib/gateway-settings.mjs +0 -78
  524. package/scripts/mutation-bench.mjs +0 -564
  525. package/scripts/mutation-io-smoke.mjs +0 -1097
  526. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  527. package/scripts/native-patch-smoke.mjs +0 -304
  528. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  529. package/scripts/patch-interior-context-smoke.mjs +0 -49
  530. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  531. package/scripts/perf-hook-smoke.mjs +0 -71
  532. package/scripts/permission-eval-smoke.mjs +0 -443
  533. package/scripts/prep-patch.mjs +0 -53
  534. package/scripts/prep-shim.mjs +0 -96
  535. package/scripts/provider-cache-smoke.mjs +0 -687
  536. package/scripts/report-runtime-health.mjs +0 -132
  537. package/scripts/resolve-bun.mjs +0 -60
  538. package/scripts/run-mcp.mjs +0 -1473
  539. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  540. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  541. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  542. package/scripts/smoke-runtime-negative.ps1 +0 -100
  543. package/scripts/smoke-runtime-negative.sh +0 -95
  544. package/scripts/stall-policy-smoke.mjs +0 -50
  545. package/scripts/start-memory-worker.mjs +0 -23
  546. package/scripts/statusline-launcher-smoke.mjs +0 -235
  547. package/scripts/stress-atomic-write.mjs +0 -1028
  548. package/scripts/test-fault-inject.mjs +0 -164
  549. package/scripts/test-large-file.mjs +0 -174
  550. package/scripts/tool-edge-smoke.mjs +0 -209
  551. package/scripts/uninstall.mjs +0 -238
  552. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  553. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  554. package/server-main.mjs +0 -3350
  555. package/server.mjs +0 -468
  556. package/setup/config-merge.mjs +0 -246
  557. package/setup/install.mjs +0 -574
  558. package/setup/launch-core.mjs +0 -617
  559. package/setup/launch.mjs +0 -101
  560. package/setup/locate-claude.mjs +0 -56
  561. package/setup/mixdog-cli.mjs +0 -122
  562. package/setup/setup-server.mjs +0 -3305
  563. package/setup/setup.html +0 -3740
  564. package/setup/tui.mjs +0 -325
  565. package/skills/retro-skill-proposer/SKILL.md +0 -92
  566. package/skills/schedule-add/SKILL.md +0 -77
  567. package/skills/setup/SKILL.md +0 -356
  568. package/skills/webhook-add/SKILL.md +0 -81
  569. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  570. package/src/agent/index.mjs +0 -2229
  571. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  572. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  573. package/src/agent/orchestrator/bridge-trace.mjs +0 -601
  574. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  575. package/src/agent/orchestrator/config.mjs +0 -405
  576. package/src/agent/orchestrator/context/collect.mjs +0 -651
  577. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  578. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  579. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  580. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  581. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  582. package/src/agent/orchestrator/jobs.mjs +0 -116
  583. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  584. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1884
  585. package/src/agent/orchestrator/providers/anthropic.mjs +0 -598
  586. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  587. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  588. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  589. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  590. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  591. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  592. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  593. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  594. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  595. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  596. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  597. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  598. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  599. package/src/agent/orchestrator/session/loop.mjs +0 -1619
  600. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  601. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  602. package/src/agent/orchestrator/session/store.mjs +0 -632
  603. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  604. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  605. package/src/agent/orchestrator/session/trim.mjs +0 -491
  606. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  607. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  608. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  609. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  610. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  611. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  612. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  613. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  614. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  615. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  616. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -511
  617. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  618. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  619. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  620. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  621. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  622. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  623. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  624. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  625. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  626. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  627. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  628. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  629. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  630. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  631. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  632. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  633. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  634. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  635. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  636. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  637. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  638. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  639. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  640. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  641. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  642. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  643. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  644. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  645. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  646. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  647. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  648. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  649. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  650. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  651. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  652. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  653. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  654. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  655. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  656. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  657. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  658. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  659. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  660. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  661. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  662. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  663. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  664. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  665. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  666. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  667. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  668. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  669. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  670. package/src/agent/tool-defs.mjs +0 -110
  671. package/src/channels/backends/discord.mjs +0 -784
  672. package/src/channels/data/voice-runtime-manifest.json +0 -138
  673. package/src/channels/index.mjs +0 -3268
  674. package/src/channels/lib/config.mjs +0 -292
  675. package/src/channels/lib/drop-trace.mjs +0 -71
  676. package/src/channels/lib/event-pipeline.mjs +0 -81
  677. package/src/channels/lib/holidays.mjs +0 -138
  678. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  679. package/src/channels/lib/output-forwarder.mjs +0 -765
  680. package/src/channels/lib/runtime-paths.mjs +0 -552
  681. package/src/channels/lib/scheduler.mjs +0 -723
  682. package/src/channels/lib/session-discovery.mjs +0 -103
  683. package/src/channels/lib/state-file.mjs +0 -68
  684. package/src/channels/lib/status-snapshot.mjs +0 -219
  685. package/src/channels/lib/tool-format.mjs +0 -140
  686. package/src/channels/lib/transcript-discovery.mjs +0 -195
  687. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  688. package/src/channels/lib/webhook.mjs +0 -1318
  689. package/src/channels/tool-defs.mjs +0 -170
  690. package/src/daemon/host.mjs +0 -118
  691. package/src/daemon/mcp-transport.mjs +0 -47
  692. package/src/daemon/session.mjs +0 -100
  693. package/src/daemon/thin-client.mjs +0 -71
  694. package/src/daemon/transport.mjs +0 -163
  695. package/src/gateway/claude-current.mjs +0 -255
  696. package/src/gateway/oauth-usage.mjs +0 -598
  697. package/src/gateway/route-meta.mjs +0 -629
  698. package/src/gateway/server.mjs +0 -713
  699. package/src/memory/data/runtime-manifest.json +0 -40
  700. package/src/memory/index.mjs +0 -3332
  701. package/src/memory/lib/core-memory-store.mjs +0 -330
  702. package/src/memory/lib/embedding-provider.mjs +0 -269
  703. package/src/memory/lib/embedding-worker.mjs +0 -323
  704. package/src/memory/lib/memory-cycle1.mjs +0 -645
  705. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  706. package/src/memory/lib/memory-cycle3.mjs +0 -540
  707. package/src/memory/lib/memory-embed.mjs +0 -299
  708. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  709. package/src/memory/lib/memory-recall-store.mjs +0 -638
  710. package/src/memory/lib/memory.mjs +0 -412
  711. package/src/memory/lib/pg/adapter.mjs +0 -308
  712. package/src/memory/lib/pg/process.mjs +0 -360
  713. package/src/memory/lib/pg/supervisor.mjs +0 -396
  714. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  715. package/src/memory/lib/trace-store.mjs +0 -728
  716. package/src/memory/tool-defs.mjs +0 -79
  717. package/src/search/index.mjs +0 -1173
  718. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  719. package/src/search/lib/backends/exa.mjs +0 -50
  720. package/src/search/lib/backends/firecrawl.mjs +0 -61
  721. package/src/search/lib/backends/gemini-api.mjs +0 -83
  722. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  723. package/src/search/lib/backends/index.mjs +0 -150
  724. package/src/search/lib/backends/openai-api.mjs +0 -144
  725. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  726. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  727. package/src/search/lib/backends/tavily.mjs +0 -55
  728. package/src/search/lib/backends/xai-api.mjs +0 -113
  729. package/src/search/lib/config.mjs +0 -192
  730. package/src/search/lib/provider-usage.mjs +0 -67
  731. package/src/search/lib/providers.mjs +0 -47
  732. package/src/search/lib/search-intent.mjs +0 -109
  733. package/src/search/lib/setup-handler.mjs +0 -261
  734. package/src/search/lib/web-tools.mjs +0 -1219
  735. package/src/search/tool-defs.mjs +0 -83
  736. package/src/setup/defender-exclusion.mjs +0 -183
  737. package/src/shared/atomic-file.mjs +0 -436
  738. package/src/shared/config.mjs +0 -372
  739. package/src/shared/daemon-recycle.mjs +0 -108
  740. package/src/shared/disable-claude-builtins.mjs +0 -91
  741. package/src/shared/err-text.mjs +0 -12
  742. package/src/shared/llm/http-agent.mjs +0 -123
  743. package/src/shared/open-url.mjs +0 -62
  744. package/src/shared/plugin-paths.mjs +0 -58
  745. package/src/shared/schedules-store.mjs +0 -70
  746. package/src/shared/seed.mjs +0 -161
  747. package/src/shared/user-cwd.mjs +0 -225
  748. package/src/shared/user-data-guard.mjs +0 -244
  749. package/src/status/aggregator.mjs +0 -584
  750. package/src/status/server.mjs +0 -413
  751. package/tools.json +0 -1671
  752. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  753. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  754. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  755. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  756. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  757. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  758. /package/{lib → src/lib}/text-utils.cjs +0 -0
  759. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  760. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  761. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  762. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  763. /package/src/{agent → runtime/agent}/orchestrator/session/cache/post-edit-marks.mjs +0 -0
  764. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/advisory-lock.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  805. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  806. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  807. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  808. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  809. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  810. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  811. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  812. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  813. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  814. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  815. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  816. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  817. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  818. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  819. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  820. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  821. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  822. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  823. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  824. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  829. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  830. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  831. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  832. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  833. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  834. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  835. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  836. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  837. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  838. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  839. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  840. /package/src/{shared → runtime/shared}/llm/cost.mjs +0 -0
  841. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  842. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  843. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  844. /package/src/{shared → runtime/shared}/wsl.mjs +0 -0
@@ -0,0 +1,3704 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { basename, dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { performance } from 'node:perf_hooks';
6
+ import { ensureProjectMixdogMd, ensureStandaloneEnvironment } from './standalone/seeds.mjs';
7
+ import { createStandaloneBridge } from './standalone/bridge-tool.mjs';
8
+ import { EXPLORE_TOOL, runExplore } from './standalone/explore-tool.mjs';
9
+ import { createStandaloneChannelWorker } from './standalone/channel-worker.mjs';
10
+ import { createStandaloneHookBus } from './standalone/hook-bus.mjs';
11
+ import { writeLastSessionCwd } from './runtime/shared/user-cwd.mjs';
12
+ import { cancelBackgroundTasks } from './runtime/shared/background-tasks.mjs';
13
+ import { createWorkspaceRouter, formatWorkspaceSessionContext } from './runtime/shared/workspace-router.mjs';
14
+ import { setConfiguredShell } from './runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs';
15
+ import {
16
+ PROVIDER_STATUS_TOOL,
17
+ beginOAuthProviderLogin,
18
+ forgetProviderAuth,
19
+ loginOAuthProvider,
20
+ providerSetup,
21
+ renderProviderStatus,
22
+ saveOpenAIUsageSessionKey,
23
+ saveOpenCodeGoUsageAuth,
24
+ saveProviderApiKey,
25
+ setLocalProvider,
26
+ } from './standalone/provider-admin.mjs';
27
+ import { createUsageDashboard } from './standalone/usage-dashboard.mjs';
28
+ import {
29
+ channelSetup,
30
+ deleteChannel,
31
+ deleteSchedule,
32
+ deleteWebhook,
33
+ forgetDiscordToken,
34
+ forgetWebhookAuthtoken,
35
+ renderChannelStatus,
36
+ saveChannel,
37
+ saveDiscordToken,
38
+ saveSchedule,
39
+ saveWebhook,
40
+ saveWebhookAuthtoken,
41
+ setScheduleEnabled,
42
+ setWebhookEnabled,
43
+ setWebhookConfig,
44
+ } from './standalone/channel-admin.mjs';
45
+ import {
46
+ addPlugin as registryAddPlugin,
47
+ listRegisteredPlugins,
48
+ pluginAdminStatus,
49
+ removePlugin as registryRemovePlugin,
50
+ updatePlugin as registryUpdatePlugin,
51
+ } from './standalone/plugin-admin.mjs';
52
+ import {
53
+ estimateMessagesTokens,
54
+ estimateRequestReserveTokens,
55
+ estimateToolSchemaTokens,
56
+ } from './runtime/agent/orchestrator/session/context-utils.mjs';
57
+
58
+ function sessionMessageText(content) {
59
+ if (content == null) return '';
60
+ if (typeof content === 'string') return content;
61
+ const parts = Array.isArray(content)
62
+ ? content
63
+ : (content && typeof content === 'object' && Array.isArray(content.content) ? content.content : null);
64
+ if (parts) {
65
+ return parts.map((part) => {
66
+ if (typeof part === 'string') return part;
67
+ return part?.text ?? '';
68
+ }).filter(Boolean).join('\n');
69
+ }
70
+ if (typeof content === 'object' && typeof content.text === 'string') return content.text;
71
+ try { return JSON.stringify(content); } catch { return String(content); }
72
+ }
73
+
74
+ function roughTokenCount(text) {
75
+ return Math.ceil(String(text ?? '').length / 4);
76
+ }
77
+
78
+ function messageContextText(message) {
79
+ if (!message || typeof message !== 'object') return '';
80
+ let text = sessionMessageText(message.content);
81
+ if (message.role === 'assistant' && Array.isArray(message.toolCalls) && message.toolCalls.length) {
82
+ try { text += `\n${JSON.stringify(message.toolCalls)}`; }
83
+ catch { text += `\n[${message.toolCalls.length} tool calls]`; }
84
+ }
85
+ if (message.role === 'tool' && message.toolCallId) text += `\n${message.toolCallId}`;
86
+ return text;
87
+ }
88
+
89
+ function summarizeContextMessages(messages) {
90
+ const rows = {
91
+ system: { count: 0, tokens: 0 },
92
+ user: { count: 0, tokens: 0 },
93
+ assistant: { count: 0, tokens: 0 },
94
+ tool: { count: 0, tokens: 0 },
95
+ other: { count: 0, tokens: 0 },
96
+ };
97
+ let toolCallCount = 0;
98
+ let toolCallTokens = 0;
99
+ let toolResultCount = 0;
100
+ let toolResultTokens = 0;
101
+ for (const message of messages || []) {
102
+ const role = rows[message?.role] ? message.role : 'other';
103
+ const tokens = roughTokenCount(messageContextText(message)) + 4;
104
+ rows[role].count += 1;
105
+ rows[role].tokens += tokens;
106
+ if (message?.role === 'assistant' && Array.isArray(message.toolCalls) && message.toolCalls.length) {
107
+ toolCallCount += message.toolCalls.length;
108
+ try { toolCallTokens += roughTokenCount(JSON.stringify(message.toolCalls)); }
109
+ catch { toolCallTokens += roughTokenCount(`[${message.toolCalls.length} tool calls]`); }
110
+ }
111
+ if (message?.role === 'tool') {
112
+ toolResultCount += 1;
113
+ toolResultTokens += tokens;
114
+ }
115
+ }
116
+ return {
117
+ count: Array.isArray(messages) ? messages.length : 0,
118
+ estimatedTokens: Array.isArray(messages) ? estimateMessagesTokens(messages) : 0,
119
+ roles: rows,
120
+ toolCallCount,
121
+ toolCallTokens,
122
+ toolResultCount,
123
+ toolResultTokens,
124
+ };
125
+ }
126
+
127
+ function isSessionPreviewNoise(text) {
128
+ const value = String(text || '').trim();
129
+ return !value
130
+ || value.startsWith('<system-reminder>')
131
+ || value.startsWith('</system-reminder>')
132
+ || /^#\s*permission\b/i.test(value)
133
+ || /^permission:\s*/i.test(value)
134
+ || /^cwd:\s*/i.test(value);
135
+ }
136
+
137
+ function cleanSessionPreview(text) {
138
+ return String(text || '')
139
+ .replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, ' ')
140
+ .replace(/\s+/g, ' ')
141
+ .trim()
142
+ .slice(0, 160);
143
+ }
144
+
145
+ const RUNTIME = './runtime/agent/orchestrator';
146
+ const SEARCH_RUNTIME = './runtime/search/index.mjs';
147
+ const SEARCH_TOOL_DEFS = './runtime/search/tool-defs.mjs';
148
+ const MEMORY_TOOL_DEFS = './runtime/memory/tool-defs.mjs';
149
+ const MEMORY_RUNTIME = './runtime/memory/index.mjs';
150
+ const CHANNEL_TOOL_DEFS = './runtime/channels/tool-defs.mjs';
151
+ const CHANNEL_WORKER_ENTRY = './runtime/channels/index.mjs';
152
+ const CODE_GRAPH_TOOL_DEFS = './runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs';
153
+ const CODE_GRAPH_RUNTIME = './runtime/agent/orchestrator/tools/code-graph.mjs';
154
+ const STATUSLINE_SESSION_ROUTES = './vendor/statusline/src/gateway/session-routes.mjs';
155
+ const __dirname = dirname(fileURLToPath(import.meta.url));
156
+ const STANDALONE_SOURCE_ROOT = __dirname;
157
+ // Resource root stays at src/ because defaults/, rules/, runtime/, vendor/ live
158
+ // there. User-owned standalone state lives under MIXDOG_HOME (~/.mixdog).
159
+ const STANDALONE_ROOT = STANDALONE_SOURCE_ROOT;
160
+ const MIXDOG_HOME = process.env.MIXDOG_HOME || join(homedir(), '.mixdog');
161
+ const STANDALONE_DATA_DIR = process.env.MIXDOG_DATA_DIR || join(MIXDOG_HOME, 'data');
162
+
163
+ const DEFAULT_PROVIDER = 'anthropic-oauth';
164
+ const DEFAULT_MODEL = '';
165
+ const TOOL_MODES = new Set(['full', 'readonly', 'lead']);
166
+ const ALL_EFFORT_LEVELS = new Set(['none', 'low', 'medium', 'high', 'xhigh', 'max']);
167
+ const EFFORT_LABELS = {
168
+ none: 'None',
169
+ low: 'Low',
170
+ medium: 'Medium',
171
+ high: 'High',
172
+ xhigh: 'Extra High',
173
+ max: 'Max',
174
+ };
175
+
176
+ function envFlag(name) {
177
+ return /^(1|true|yes|on)$/i.test(String(process.env[name] || ''));
178
+ }
179
+
180
+ function envDelayMs(name, fallback, { min = 0, max = 60_000 } = {}) {
181
+ const raw = process.env[name];
182
+ if (raw === undefined || raw === '') return fallback;
183
+ const n = Number(raw);
184
+ if (!Number.isFinite(n)) return fallback;
185
+ return Math.min(max, Math.max(min, Math.floor(n)));
186
+ }
187
+
188
+ const BOOT_PROFILE_ENABLED = envFlag('MIXDOG_BOOT_PROFILE');
189
+ const BOOT_PROFILE_START = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance.now());
190
+
191
+ function bootProfile(event, fields = {}) {
192
+ if (!BOOT_PROFILE_ENABLED) return;
193
+ const elapsedMs = performance.now() - BOOT_PROFILE_START;
194
+ const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, event];
195
+ for (const [key, value] of Object.entries(fields || {})) {
196
+ if (value === undefined || value === null || value === '') continue;
197
+ parts.push(`${key}=${String(value).replace(/\s+/g, '_')}`);
198
+ }
199
+ try { process.stderr.write(`${parts.join(' ')}\n`); } catch {}
200
+ }
201
+
202
+ async function profiledImport(label, spec, { optional = false } = {}) {
203
+ const startedAt = performance.now();
204
+ try {
205
+ const mod = await import(spec);
206
+ bootProfile(`import:${label}`, { ms: (performance.now() - startedAt).toFixed(1) });
207
+ return mod;
208
+ } catch (error) {
209
+ bootProfile(`import:${label}:failed`, {
210
+ ms: (performance.now() - startedAt).toFixed(1),
211
+ error: error?.message || String(error),
212
+ });
213
+ if (optional) return null;
214
+ throw error;
215
+ }
216
+ }
217
+ const EFFORT_OPTIONS_BY_PROVIDER = {
218
+ openai: ['none', 'low', 'medium', 'high', 'xhigh'],
219
+ 'openai-oauth': ['none', 'low', 'medium', 'high', 'xhigh'],
220
+ anthropic: ['low', 'medium', 'high', 'max'],
221
+ 'anthropic-oauth': ['low', 'medium', 'high', 'xhigh', 'max'],
222
+ xai: ['none', 'low', 'medium', 'high'],
223
+ 'grok-oauth': ['none', 'low', 'medium', 'high'],
224
+ 'opencode-go': ['high', 'max'],
225
+ };
226
+ const EFFORT_BY_FAMILY = {
227
+ opus: ['low', 'medium', 'high', 'xhigh', 'max'],
228
+ sonnet: ['low', 'medium', 'high'],
229
+ haiku: [],
230
+ 'gpt-5.5': ['none', 'low', 'medium', 'high', 'xhigh'],
231
+ 'gpt-5.4': ['none', 'low', 'medium', 'high', 'xhigh'],
232
+ 'gpt-5.2': ['none', 'low', 'medium', 'high', 'xhigh'],
233
+ 'gpt-5': ['none', 'low', 'medium', 'high', 'xhigh'],
234
+ 'gpt-mini': ['none', 'low', 'medium', 'high', 'xhigh'],
235
+ 'gpt-nano': ['none', 'low', 'medium', 'high'],
236
+ 'gpt-codex': ['none', 'low', 'medium', 'high'],
237
+ grok: ['none', 'low', 'medium', 'high'],
238
+ };
239
+ const EFFORT_FALLBACKS = {
240
+ max: ['max', 'xhigh', 'high', 'medium', 'low'],
241
+ xhigh: ['xhigh', 'high', 'medium', 'low'],
242
+ high: ['high', 'medium', 'low'],
243
+ medium: ['medium', 'low'],
244
+ low: ['low'],
245
+ none: ['none'],
246
+ };
247
+
248
+ export const TOOL_SEARCH_TOOL = {
249
+ name: 'tool_search',
250
+ title: 'Tool Search',
251
+ annotations: {
252
+ title: 'Tool Search',
253
+ readOnlyHint: true,
254
+ destructiveHint: false,
255
+ idempotentHint: true,
256
+ openWorldHint: false,
257
+ },
258
+ description: 'Search the current standalone tool surface and select deferred tools/skills for the task. Use before unfamiliar or currently inactive tools.',
259
+ inputSchema: {
260
+ type: 'object',
261
+ properties: {
262
+ query: { type: 'string', description: 'Optional search text, e.g. edit, bridge, memory, skill, mcp.' },
263
+ select: { anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], description: 'Tool/skill names to activate, as comma-separated text or an array.' },
264
+ limit: { type: 'number', description: 'Maximum matches to return.' },
265
+ },
266
+ additionalProperties: false,
267
+ },
268
+ };
269
+
270
+ const CHANNEL_STATUS_TOOL = {
271
+ name: 'channel_status',
272
+ title: 'Channel Status',
273
+ annotations: {
274
+ title: 'Channel Status',
275
+ readOnlyHint: true,
276
+ destructiveHint: false,
277
+ idempotentHint: true,
278
+ openWorldHint: false,
279
+ bridgeHidden: true,
280
+ },
281
+ description: 'List standalone Discord/channel/schedule/webhook configuration status. Read-only and never returns secrets.',
282
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
283
+ };
284
+
285
+ const CWD_TOOL = {
286
+ name: 'cwd',
287
+ title: 'Current Working Directory',
288
+ annotations: {
289
+ title: 'Current Working Directory',
290
+ readOnlyHint: false,
291
+ destructiveHint: false,
292
+ idempotentHint: false,
293
+ openWorldHint: false,
294
+ bridgeHidden: true,
295
+ },
296
+ description: 'Show or set the standalone session working directory. Default get; action=set requires path.',
297
+ inputSchema: {
298
+ type: 'object',
299
+ properties: {
300
+ action: { type: 'string', enum: ['get', 'set'], description: 'Default get, or set when path is provided.' },
301
+ path: { type: 'string', description: 'Directory path for action=set. Relative paths resolve from the current cwd.' },
302
+ },
303
+ additionalProperties: false,
304
+ },
305
+ };
306
+
307
+ const MEASURED_TOOL_USAGE = Object.freeze({
308
+ read: 710,
309
+ code_graph: 520,
310
+ grep: 500,
311
+ glob: 460,
312
+ list: 430,
313
+ apply_patch: 400,
314
+ explore: 360,
315
+ bridge: 330,
316
+ shell: 81,
317
+ cwd: 2,
318
+ diagnostics: 2,
319
+ recall: 2,
320
+ search: 2,
321
+ web_fetch: 2,
322
+ provider_status: 2,
323
+ channel_status: 2,
324
+ });
325
+ const MEASURED_TOOL_ORDER = Object.freeze(Object.keys(MEASURED_TOOL_USAGE));
326
+ const DEFERRED_ALWAYS_ACTIVE_TOOLS = new Set([
327
+ 'tool_search',
328
+ 'recall',
329
+ 'search',
330
+ 'web_fetch',
331
+ ]);
332
+ const LEAD_DISALLOWED_TOOLS = Object.freeze(['diagnostics', 'open_config']);
333
+ const DEFERRED_DEFAULT_FULL_LIMIT = 8;
334
+ const DEFERRED_DEFAULT_READONLY_TOOLS = Object.freeze([
335
+ 'read',
336
+ 'code_graph',
337
+ 'grep',
338
+ 'glob',
339
+ 'list',
340
+ 'explore',
341
+ 'tool_search',
342
+ ]);
343
+ const DEFERRED_DEFAULT_LEAD_TOOLS = Object.freeze([
344
+ 'read',
345
+ 'code_graph',
346
+ 'grep',
347
+ 'glob',
348
+ 'list',
349
+ 'shell',
350
+ 'task',
351
+ 'explore',
352
+ 'apply_patch',
353
+ 'bridge',
354
+ 'recall',
355
+ 'search',
356
+ 'web_fetch',
357
+ 'cwd',
358
+ 'tool_search',
359
+ ]);
360
+ const READONLY_TOOL_NAMES = new Set([
361
+ 'read',
362
+ 'list',
363
+ 'grep',
364
+ 'glob',
365
+ 'code_graph',
366
+ 'search',
367
+ 'web_fetch',
368
+ 'recall',
369
+ 'memory',
370
+ 'provider_status',
371
+ 'channel_status',
372
+ 'schedule_status',
373
+ 'fetch',
374
+ ]);
375
+ const BRIDGE_HIDDEN_WRAPPER_TOOLS = new Set(['explore', 'search']);
376
+
377
+ function applyStandaloneToolDefaults(tool) {
378
+ if (!tool || !BRIDGE_HIDDEN_WRAPPER_TOOLS.has(tool.name)) return tool;
379
+ return {
380
+ ...tool,
381
+ annotations: {
382
+ ...(tool.annotations || {}),
383
+ bridgeHidden: true,
384
+ },
385
+ };
386
+ }
387
+ const DEFERRED_SELECT_ALIASES = {
388
+ filesystem: ['read', 'list', 'grep', 'glob'],
389
+ search: ['search', 'web_fetch'],
390
+ web: ['web_fetch', 'search'],
391
+ memory: ['memory', 'recall'],
392
+ channels: ['reply', 'fetch', 'react', 'edit_message', 'download_attachment', 'schedule_status', 'trigger_schedule', 'schedule_control', 'reload_config'],
393
+ discord: ['reply', 'fetch', 'react', 'edit_message', 'download_attachment'],
394
+ providers: ['provider_status'],
395
+ provider: ['provider_status'],
396
+ status: ['provider_status', 'channel_status', 'schedule_status'],
397
+ schedule: ['schedule_status', 'trigger_schedule', 'schedule_control'],
398
+ channel: ['channel_status'],
399
+ explore: ['explore'],
400
+ discovery: ['explore'],
401
+ bridge: ['bridge'],
402
+ graph: ['code_graph'],
403
+ code: ['code_graph'],
404
+ shell: ['shell', 'task'],
405
+ };
406
+
407
+ function normalizeToolMode(mode) {
408
+ const value = String(mode || '').trim().toLowerCase();
409
+ return TOOL_MODES.has(value) ? value : 'full';
410
+ }
411
+
412
+ function normalizeEffortInput(value) {
413
+ const v = clean(value).toLowerCase();
414
+ if (!v || v === 'auto') return null;
415
+ if (!ALL_EFFORT_LEVELS.has(v)) {
416
+ throw new Error(`effort must be one of auto, ${[...ALL_EFFORT_LEVELS].join(', ')}`);
417
+ }
418
+ return v;
419
+ }
420
+
421
+ function effortOptionsFor(provider, model) {
422
+ const providerAllowed = EFFORT_OPTIONS_BY_PROVIDER[provider] || null;
423
+ const filterProvider = (values) => {
424
+ const unique = [...new Set((values || []).map(clean).filter(Boolean))];
425
+ return providerAllowed ? unique.filter((v) => providerAllowed.includes(v)) : unique;
426
+ };
427
+ const declared = Array.isArray(model?.reasoningLevels)
428
+ ? model.reasoningLevels.map(clean).filter(Boolean)
429
+ : [];
430
+ if (Array.isArray(model?.reasoningLevels)) return filterProvider(declared);
431
+ const family = clean(model?.family).toLowerCase();
432
+ if (Object.prototype.hasOwnProperty.call(EFFORT_BY_FAMILY, family)) {
433
+ return filterProvider(EFFORT_BY_FAMILY[family]);
434
+ }
435
+ return providerAllowed || [];
436
+ }
437
+
438
+ function coerceEffortFor(provider, model, effort) {
439
+ if (!effort) return null;
440
+ const allowed = effortOptionsFor(provider, model);
441
+ if (!allowed || allowed.length === 0) return null;
442
+ if (allowed.includes(effort)) return effort;
443
+ for (const candidate of EFFORT_FALLBACKS[effort] || []) {
444
+ if (allowed.includes(candidate)) return candidate;
445
+ }
446
+ return null;
447
+ }
448
+
449
+ function hasOwn(obj, key) {
450
+ return Object.prototype.hasOwnProperty.call(obj || {}, key);
451
+ }
452
+
453
+ function modelSettingsFor(config, provider, model) {
454
+ const key = routeFastKey(provider, model);
455
+ const value = key ? config?.modelSettings?.[key] : null;
456
+ return value && typeof value === 'object' ? value : {};
457
+ }
458
+
459
+ function normalizeSavedEffort(value) {
460
+ try {
461
+ return normalizeEffortInput(value);
462
+ } catch {
463
+ return null;
464
+ }
465
+ }
466
+
467
+ function effortItemsFor(provider, model, activeEffort) {
468
+ const allowed = effortOptionsFor(provider, model);
469
+ const items = [];
470
+ for (const value of allowed || []) {
471
+ items.push({
472
+ value,
473
+ label: EFFORT_LABELS[value] || value,
474
+ description: value === activeEffort ? 'current' : '',
475
+ });
476
+ }
477
+ return items;
478
+ }
479
+
480
+ function toolSpecForMode(mode) {
481
+ return mode === 'readonly' ? ['tools:readonly'] : 'full';
482
+ }
483
+
484
+ function clean(value) {
485
+ return String(value ?? '').trim();
486
+ }
487
+
488
+ const OUTPUT_STYLE_ORDER = ['default', 'simple', 'extreme-simple'];
489
+ const OUTPUT_STYLE_ALIASES = new Map([
490
+ ['compact', 'default'],
491
+ ['normal', 'default'],
492
+ ['extreme', 'extreme-simple'],
493
+ ['extremesimple', 'extreme-simple'],
494
+ ['extreme-simple', 'extreme-simple'],
495
+ ['extreme_simple', 'extreme-simple'],
496
+ ]);
497
+
498
+ function normalizeOutputStyleId(value) {
499
+ const raw = clean(value).toLowerCase();
500
+ if (!raw) return '';
501
+ const slug = raw.replace(/[_\s]+/g, '-').replace(/^-+|-+$/g, '');
502
+ const compact = slug.replace(/[_.-]+/g, '');
503
+ if (OUTPUT_STYLE_ALIASES.has(slug)) return OUTPUT_STYLE_ALIASES.get(slug);
504
+ if (OUTPUT_STYLE_ALIASES.has(compact)) return OUTPUT_STYLE_ALIASES.get(compact);
505
+ return /^[a-z0-9.-]+$/.test(slug) ? slug : '';
506
+ }
507
+
508
+ function outputStyleCompactKey(value) {
509
+ return normalizeOutputStyleId(value).replace(/[_.-]+/g, '');
510
+ }
511
+
512
+ function titleCaseOutputStyle(id) {
513
+ return clean(id)
514
+ .split(/[_.-]+/)
515
+ .filter(Boolean)
516
+ .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
517
+ .join(' ') || 'Default';
518
+ }
519
+
520
+ function parseOutputStyleFrontmatter(markdown) {
521
+ const match = String(markdown || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
522
+ const meta = {};
523
+ if (!match) return meta;
524
+ for (const line of match[1].split(/\r?\n/)) {
525
+ const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*?)\s*$/);
526
+ if (!kv) continue;
527
+ meta[kv[1]] = kv[2].replace(/^['"]|['"]$/g, '').trim();
528
+ }
529
+ return meta;
530
+ }
531
+
532
+ function readOutputStyleMetadata(filePath, source) {
533
+ let raw = '';
534
+ try { raw = readFileSync(filePath, 'utf8'); } catch { return null; }
535
+ const meta = parseOutputStyleFrontmatter(raw);
536
+ const fileId = normalizeOutputStyleId(basename(filePath).replace(/\.md$/i, ''));
537
+ const id = normalizeOutputStyleId(meta.name) || fileId;
538
+ if (!id) return null;
539
+ const aliases = clean(meta.aliases)
540
+ .split(',')
541
+ .map((value) => normalizeOutputStyleId(value))
542
+ .filter(Boolean);
543
+ const label = clean(meta.title || meta.label) || titleCaseOutputStyle(id);
544
+ return {
545
+ id,
546
+ label,
547
+ description: clean(meta.description),
548
+ aliases,
549
+ source,
550
+ };
551
+ }
552
+
553
+ function listOutputStyleCatalog(dataDir = STANDALONE_DATA_DIR) {
554
+ const byId = new Map();
555
+ const dirs = [
556
+ { dir: join(STANDALONE_ROOT, 'output-styles'), source: 'builtin' },
557
+ { dir: join(dataDir || STANDALONE_DATA_DIR, 'output-styles'), source: 'user' },
558
+ ];
559
+ for (const { dir, source } of dirs) {
560
+ let entries = [];
561
+ try { entries = readdirSync(dir, { withFileTypes: true }); } catch { continue; }
562
+ for (const entry of entries) {
563
+ if (!entry.isFile() || !entry.name.toLowerCase().endsWith('.md')) continue;
564
+ const style = readOutputStyleMetadata(join(dir, entry.name), source);
565
+ if (style) byId.set(style.id, style);
566
+ }
567
+ }
568
+ return [...byId.values()].sort((a, b) => {
569
+ const ai = OUTPUT_STYLE_ORDER.indexOf(a.id);
570
+ const bi = OUTPUT_STYLE_ORDER.indexOf(b.id);
571
+ if (ai !== bi) return (ai < 0 ? 999 : ai) - (bi < 0 ? 999 : bi);
572
+ return a.label.localeCompare(b.label, 'en', { sensitivity: 'base' });
573
+ });
574
+ }
575
+
576
+ function findOutputStyle(value, styles) {
577
+ const id = normalizeOutputStyleId(value);
578
+ const compact = outputStyleCompactKey(value);
579
+ if (!id && !compact) return null;
580
+ return (styles || []).find((style) => {
581
+ if (style.id === id || outputStyleCompactKey(style.id) === compact) return true;
582
+ if (outputStyleCompactKey(style.label) === compact) return true;
583
+ return (style.aliases || []).some((alias) => alias === id || outputStyleCompactKey(alias) === compact);
584
+ }) || null;
585
+ }
586
+
587
+ function configuredOutputStyleValue(dataDir = STANDALONE_DATA_DIR) {
588
+ const unified = readJsonSafe(join(dataDir || STANDALONE_DATA_DIR, 'mixdog-config.json')) || {};
589
+ return clean(unified.outputStyle || (unified.agent && unified.agent.outputStyle) || 'default') || 'default';
590
+ }
591
+
592
+ function outputStyleStatus(dataDir = STANDALONE_DATA_DIR) {
593
+ const styles = listOutputStyleCatalog(dataDir);
594
+ const configured = configuredOutputStyleValue(dataDir);
595
+ const current = findOutputStyle(configured, styles)
596
+ || findOutputStyle('default', styles)
597
+ || styles[0]
598
+ || { id: 'default', label: 'Default', description: '', aliases: [], source: 'builtin' };
599
+ return { configured, current, styles };
600
+ }
601
+
602
+ function sessionHasConversationMessages(activeSession) {
603
+ const messages = Array.isArray(activeSession?.messages) ? activeSession.messages : [];
604
+ return messages.some((message) => {
605
+ const role = message?.role;
606
+ if (role !== 'user' && role !== 'assistant' && role !== 'tool') return false;
607
+ const text = sessionMessageText(message.content).trim();
608
+ if (!text && role !== 'assistant') return false;
609
+ if (role === 'user' && isSessionPreviewNoise(text)) return false;
610
+ return true;
611
+ });
612
+ }
613
+
614
+ function readJsonSafe(path) {
615
+ try { return JSON.parse(readFileSync(path, 'utf8')); } catch { return null; }
616
+ }
617
+
618
+ function countSkillFiles(root) {
619
+ const skillsDir = join(root, 'skills');
620
+ if (!existsSync(skillsDir)) return 0;
621
+ let count = 0;
622
+ const walk = (dir) => {
623
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
624
+ const full = join(dir, entry.name);
625
+ if (entry.isDirectory()) walk(full);
626
+ else if (/^(SKILL|skill)\.md$/i.test(entry.name) || entry.name.toLowerCase().endsWith('.md')) count += 1;
627
+ }
628
+ };
629
+ try { walk(skillsDir); } catch { return count; }
630
+ return count;
631
+ }
632
+
633
+ function mcpScriptForPlugin(root) {
634
+ const candidates = [
635
+ 'scripts/run-mcp.mjs',
636
+ 'mcp/server.mjs',
637
+ 'server.mjs',
638
+ ];
639
+ return candidates.find((rel) => existsSync(join(root, rel))) || null;
640
+ }
641
+
642
+ function pluginManifest(root) {
643
+ return readJsonSafe(join(root, '.codex-plugin', 'plugin.json'))
644
+ || readJsonSafe(join(root, 'plugin.json'))
645
+ || {};
646
+ }
647
+
648
+ function pluginMcpServerName(plugin = {}) {
649
+ const base = clean(plugin.name || plugin.title || 'plugin')
650
+ .toLowerCase()
651
+ .replace(/[^a-z0-9_.-]+/g, '-')
652
+ .replace(/^-+|-+$/g, '');
653
+ return base ? `plugin-${base}` : 'plugin-mcp';
654
+ }
655
+
656
+ function findPreset(config, key) {
657
+ const wanted = clean(key).toLowerCase();
658
+ if (!wanted) return null;
659
+ const presets = Array.isArray(config?.presets) ? config.presets : [];
660
+ return presets.find((p) => {
661
+ const id = clean(p?.id).toLowerCase();
662
+ const name = clean(p?.name).toLowerCase();
663
+ return id === wanted || name === wanted;
664
+ }) || null;
665
+ }
666
+
667
+ function resolveRoute(config, { provider, model, effort, fast } = {}) {
668
+ const explicitProvider = clean(provider);
669
+ const explicitModel = clean(model);
670
+ const hasExplicitEffort = effort !== undefined;
671
+ const explicitEffort = hasExplicitEffort ? normalizeEffortInput(effort) : undefined;
672
+ const hasExplicitFast = fast !== undefined;
673
+ const explicitFast = fast === true;
674
+
675
+ if (explicitModel && !explicitProvider) {
676
+ const preset = findPreset(config, explicitModel);
677
+ if (preset) {
678
+ const p = clean(preset.provider) || DEFAULT_PROVIDER;
679
+ const m = clean(preset.model) || DEFAULT_MODEL;
680
+ const saved = modelSettingsFor(config, p, m);
681
+ return {
682
+ provider: p,
683
+ model: m,
684
+ preset,
685
+ effort: hasExplicitEffort ? explicitEffort : normalizeSavedEffort(saved.effort ?? preset.effort),
686
+ fast: hasExplicitFast ? explicitFast : (hasOwn(saved, 'fast') ? saved.fast === true : (preset.fast === true || fastPreferenceFor(config, p, m))),
687
+ };
688
+ }
689
+ }
690
+
691
+ if (!explicitProvider && !explicitModel) {
692
+ const defaultKey = config?.default;
693
+ const preset = findPreset(config, defaultKey);
694
+ if (preset) {
695
+ const p = clean(preset.provider) || DEFAULT_PROVIDER;
696
+ const m = clean(preset.model) || DEFAULT_MODEL;
697
+ const saved = modelSettingsFor(config, p, m);
698
+ return {
699
+ provider: p,
700
+ model: m,
701
+ preset,
702
+ effort: hasExplicitEffort ? explicitEffort : normalizeSavedEffort(saved.effort ?? preset.effort),
703
+ fast: hasExplicitFast ? explicitFast : (hasOwn(saved, 'fast') ? saved.fast === true : (preset.fast === true || fastPreferenceFor(config, p, m))),
704
+ };
705
+ }
706
+ }
707
+
708
+ const p = explicitProvider || DEFAULT_PROVIDER;
709
+ const m = explicitModel || DEFAULT_MODEL;
710
+ const saved = modelSettingsFor(config, p, m);
711
+ return {
712
+ provider: p,
713
+ model: m,
714
+ preset: null,
715
+ effort: hasExplicitEffort ? explicitEffort : normalizeSavedEffort(saved.effort),
716
+ fast: hasExplicitFast ? explicitFast : (hasOwn(saved, 'fast') ? saved.fast === true : fastPreferenceFor(config, p, m)),
717
+ };
718
+ }
719
+
720
+ function ensureProviderEnabled(config, provider) {
721
+ const providers = { ...(config?.providers || {}) };
722
+ providers[provider] = { ...(providers[provider] || {}), enabled: true };
723
+ return providers;
724
+ }
725
+
726
+ const AUTO_CLEAR_DEFAULT_IDLE_MS = 60 * 60 * 1000;
727
+
728
+ function normalizeSystemShellConfig(value = {}) {
729
+ const raw = value && typeof value === 'object' ? value : {};
730
+ const command = clean(raw.command ?? raw.path ?? raw.executable ?? raw.shell);
731
+ const envCommand = clean(process.env.MIXDOG_SHELL);
732
+ return {
733
+ command,
734
+ effective: command || envCommand || '',
735
+ source: command ? 'config' : (envCommand ? 'env' : 'auto'),
736
+ };
737
+ }
738
+
739
+ function normalizeSystemShellCommand(value) {
740
+ const command = clean(value).replace(/^auto$/i, '').replace(/^['"](.+)['"]$/, '$1').trim();
741
+ if (!command) return '';
742
+ if (process.platform === 'win32') {
743
+ const stem = command.split(/[\\/]/).pop().toLowerCase().replace(/\.exe$/, '');
744
+ if (stem !== 'powershell' && stem !== 'pwsh') {
745
+ throw new Error('system shell command must be powershell.exe or pwsh on Windows');
746
+ }
747
+ }
748
+ return command;
749
+ }
750
+
751
+ function normalizeAutoClearConfig(value = {}) {
752
+ const raw = value && typeof value === 'object' ? value : {};
753
+ const idleMs = Number(raw.idleMs ?? raw.thresholdMs ?? raw.idleMillis);
754
+ return {
755
+ enabled: raw.enabled !== false,
756
+ idleMs: Number.isFinite(idleMs) && idleMs > 0 ? Math.max(60_000, Math.round(idleMs)) : AUTO_CLEAR_DEFAULT_IDLE_MS,
757
+ };
758
+ }
759
+
760
+ function formatDurationMs(ms) {
761
+ const value = Math.max(0, Number(ms) || 0);
762
+ if (value % 3_600_000 === 0) return `${value / 3_600_000}h`;
763
+ if (value % 60_000 === 0) return `${value / 60_000}m`;
764
+ return `${Math.round(value / 1000)}s`;
765
+ }
766
+
767
+ function parseDurationMs(input) {
768
+ const text = clean(input).toLowerCase();
769
+ if (!text) return null;
770
+ const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(text);
771
+ if (!match) return null;
772
+ const n = Number(match[1]);
773
+ if (!Number.isFinite(n) || n <= 0) return null;
774
+ const unit = match[2] || 'm';
775
+ const mult = unit === 'h' ? 3_600_000 : unit === 'm' ? 60_000 : unit === 's' ? 1000 : 1;
776
+ return Math.max(60_000, Math.round(n * mult));
777
+ }
778
+
779
+ const FAST_CAPABLE_PROVIDERS = new Set(['anthropic', 'anthropic-oauth', 'openai', 'openai-oauth']);
780
+ const LAZY_SECRET_PROVIDERS = new Set(['openai-oauth', 'anthropic-oauth', 'grok-oauth', 'ollama', 'lmstudio']);
781
+
782
+ function routeFastKey(provider, model) {
783
+ const p = clean(provider);
784
+ const m = clean(model);
785
+ return p && m ? `${p}/${m}` : '';
786
+ }
787
+
788
+ function openAiModelMetaSupportsFast(model) {
789
+ const tiers = Array.isArray(model?.serviceTiers) ? model.serviceTiers : [];
790
+ const speedTiers = Array.isArray(model?.additionalSpeedTiers) ? model.additionalSpeedTiers : [];
791
+ if (tiers.length || speedTiers.length || model?.defaultServiceTier) {
792
+ return tiers.some((tier) => tier?.id === 'priority')
793
+ || speedTiers.includes('priority')
794
+ || model?.defaultServiceTier === 'priority';
795
+ }
796
+ const id = clean(model?.id || model).toLowerCase();
797
+ if (id.includes('mini') || id.includes('nano') || id.includes('codex')) return false;
798
+ return /^gpt-5(\.|-|$)/.test(id);
799
+ }
800
+
801
+ function openAiDirectModelSupportsFast(model) {
802
+ const id = clean(model?.id || model);
803
+ return /^gpt-5\.5(?:-\d{4}|$)/.test(id)
804
+ || /^gpt-5\.4(?:-\d{4}|$)/.test(id)
805
+ || /^gpt-5\.4-mini(?:-\d{4}|$)/.test(id);
806
+ }
807
+
808
+ function anthropicModelMetaSupportsFast(model) {
809
+ const id = clean(model?.id || model).toLowerCase();
810
+ return /^claude-(opus|sonnet)/.test(id);
811
+ }
812
+
813
+ function fastCapableFor(provider, model) {
814
+ const p = clean(provider);
815
+ if (!FAST_CAPABLE_PROVIDERS.has(p)) return false;
816
+ if (p === 'openai') return openAiDirectModelSupportsFast(model);
817
+ if (p === 'openai-oauth') return openAiModelMetaSupportsFast(model);
818
+ if (p === 'anthropic' || p === 'anthropic-oauth') return anthropicModelMetaSupportsFast(model);
819
+ return false;
820
+ }
821
+
822
+ function fastPreferenceFor(config, provider, model) {
823
+ const key = routeFastKey(provider, model);
824
+ if (!key) return false;
825
+ const saved = config?.modelSettings?.[key];
826
+ if (saved && typeof saved === 'object' && hasOwn(saved, 'fast')) return saved.fast === true;
827
+ return config?.fastModels?.[key] === true;
828
+ }
829
+
830
+ function saveModelSettings(cfgMod, route, { fastCapable = true } = {}) {
831
+ const key = routeFastKey(route?.provider, route?.model);
832
+ if (!key) return cfgMod.loadConfig();
833
+ const nextConfig = cfgMod.loadConfig();
834
+ const modelSettings = { ...(nextConfig.modelSettings || {}) };
835
+ const nextSetting = { ...(modelSettings[key] || {}) };
836
+ if (hasOwn(route, 'effort') && route.effort) nextSetting.effort = route.effort;
837
+ else delete nextSetting.effort;
838
+ if (fastCapable) nextSetting.fast = route.fast === true;
839
+ else nextSetting.fast = false;
840
+ modelSettings[key] = nextSetting;
841
+
842
+ // Legacy compatibility: keep fastModels true entries for old readers, but
843
+ // let modelSettings.fast=false override them in new readers.
844
+ const fastModels = { ...(nextConfig.fastModels || {}) };
845
+ if (nextSetting.fast === true) fastModels[key] = true;
846
+ else delete fastModels[key];
847
+
848
+ const savedConfig = { ...nextConfig, modelSettings, fastModels };
849
+ cfgMod.saveConfig(savedConfig);
850
+ return savedConfig;
851
+ }
852
+
853
+ function routeForStatusline(route) {
854
+ const out = {
855
+ mode: 'fixed',
856
+ defaultProvider: route.provider,
857
+ defaultModel: route.model,
858
+ };
859
+ const preset = route.preset || {};
860
+ if (preset.id) out.presetId = preset.id;
861
+ if (preset.name) out.presetName = preset.name;
862
+ if (preset.modelDisplay) out.modelDisplay = preset.modelDisplay;
863
+ if (route.fast === true || route.fast === false) out.fast = route.fast;
864
+ else if (preset.fast === true || preset.fast === false) out.fast = preset.fast;
865
+ if (route.effectiveEffort) {
866
+ out.effort = route.effectiveEffort;
867
+ out.displayEffort = route.effectiveEffort;
868
+ } else if (hasOwn(route, 'effort')) {
869
+ delete out.effort;
870
+ delete out.displayEffort;
871
+ }
872
+ return out;
873
+ }
874
+
875
+ const ONBOARDING_VERSION = 1;
876
+ const WORKFLOW_ROUTE_SLOTS = ['lead', 'bridge', 'explorer', 'memory'];
877
+ const FIXED_AGENT_SLOTS = Object.freeze([
878
+ { id: 'explore', label: 'Explore', description: 'Broad repository exploration', workflowSlot: 'explorer' },
879
+ { id: 'web-researcher', label: 'Web Researcher', description: 'External current-info research' },
880
+ { id: 'maintainer', label: 'Maintainer', description: 'Background memory and upkeep', workflowSlot: 'memory' },
881
+ { id: 'worker', label: 'Worker', description: 'Scoped implementation' },
882
+ { id: 'heavy-worker', label: 'Heavy Worker', description: 'Broad or multi-file implementation' },
883
+ { id: 'reviewer', label: 'Reviewer', description: 'Diff review and risk checks' },
884
+ { id: 'debugger', label: 'Debugger', description: 'Root-cause analysis and failure tracing' },
885
+ ]);
886
+ const AGENT_ROLE_IDS = new Set(FIXED_AGENT_SLOTS.map((agent) => agent.id));
887
+ const agentDefinitionCache = new Map();
888
+ const DEFAULT_WORKFLOW_ID = 'default';
889
+
890
+ function workflowPresetId(slot) {
891
+ return `workflow-${slot}`;
892
+ }
893
+
894
+ function workflowPresetName(slot) {
895
+ return `WORKFLOW ${String(slot || '').toUpperCase()}`;
896
+ }
897
+
898
+ function agentPresetSlot(agentId) {
899
+ return `agent-${String(agentId || '').replace(/[^a-z0-9_.-]+/gi, '-').toLowerCase()}`;
900
+ }
901
+
902
+ function normalizeAgentId(value) {
903
+ const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
904
+ if (id === 'explorer') return 'explore';
905
+ if (id === 'maint' || id === 'maintenance' || id === 'memory') return 'maintainer';
906
+ if (id === 'heavy' || id === 'heavyworker') return 'heavy-worker';
907
+ if (id === 'review') return 'reviewer';
908
+ if (id === 'debug') return 'debugger';
909
+ return AGENT_ROLE_IDS.has(id) ? id : '';
910
+ }
911
+
912
+ function normalizeWorkflowId(value, fallback = '') {
913
+ const id = clean(value).toLowerCase().replace(/[\s_]+/g, '-');
914
+ return /^[a-z0-9][a-z0-9_.-]*$/.test(id) ? id : fallback;
915
+ }
916
+
917
+ function readTextSafe(path) {
918
+ try { return readFileSync(path, 'utf8').trim(); } catch { return ''; }
919
+ }
920
+
921
+ function workflowSourceDirs(dataDir) {
922
+ return [
923
+ { root: join(STANDALONE_ROOT, 'workflows'), source: 'built-in' },
924
+ { root: join(dataDir || STANDALONE_DATA_DIR, 'workflows'), source: 'user' },
925
+ ];
926
+ }
927
+
928
+ function agentSourceDirs(dataDir, id) {
929
+ return [
930
+ join(dataDir || STANDALONE_DATA_DIR, 'agents', id),
931
+ join(STANDALONE_ROOT, 'agents', id),
932
+ ];
933
+ }
934
+
935
+ function readWorkflowPackFromDir(dir, source = 'built-in') {
936
+ const manifest = readJsonSafe(join(dir, 'workflow.json'));
937
+ if (!manifest || typeof manifest !== 'object') return null;
938
+ const id = normalizeWorkflowId(manifest.id || manifest.name);
939
+ if (!id) return null;
940
+ const entry = clean(manifest.entry) || 'WORKFLOW.md';
941
+ const body = readTextSafe(join(dir, entry));
942
+ if (!body) return null;
943
+ return {
944
+ id,
945
+ name: clean(manifest.name) || id,
946
+ description: clean(manifest.description),
947
+ entry,
948
+ agents: Array.isArray(manifest.agents) ? manifest.agents.map((agent) => normalizeAgentId(agent) || normalizeWorkflowId(agent)).filter(Boolean) : [],
949
+ body,
950
+ source,
951
+ };
952
+ }
953
+
954
+ function listWorkflowPacks(dataDir) {
955
+ const byId = new Map();
956
+ for (const { root, source } of workflowSourceDirs(dataDir)) {
957
+ if (!existsSync(root)) continue;
958
+ let entries = [];
959
+ try { entries = readdirSync(root, { withFileTypes: true }); } catch { entries = []; }
960
+ for (const entry of entries) {
961
+ if (!entry.isDirectory()) continue;
962
+ const pack = readWorkflowPackFromDir(join(root, entry.name), source);
963
+ if (pack) byId.set(pack.id, pack);
964
+ }
965
+ }
966
+ return [...byId.values()].sort((a, b) => {
967
+ if (a.id === DEFAULT_WORKFLOW_ID) return -1;
968
+ if (b.id === DEFAULT_WORKFLOW_ID) return 1;
969
+ return a.name.localeCompare(b.name);
970
+ });
971
+ }
972
+
973
+ function activeWorkflowId(config) {
974
+ return normalizeWorkflowId(config?.workflow?.active, DEFAULT_WORKFLOW_ID);
975
+ }
976
+
977
+ function loadWorkflowPack(dataDir, id) {
978
+ const wanted = normalizeWorkflowId(id, DEFAULT_WORKFLOW_ID);
979
+ for (const { root, source } of workflowSourceDirs(dataDir).reverse()) {
980
+ const pack = readWorkflowPackFromDir(join(root, wanted), source);
981
+ if (pack) return pack;
982
+ }
983
+ return readWorkflowPackFromDir(join(STANDALONE_ROOT, 'workflows', DEFAULT_WORKFLOW_ID), 'built-in');
984
+ }
985
+
986
+ function loadAgentDefinition(dataDir, id) {
987
+ const agentId = normalizeAgentId(id) || normalizeWorkflowId(id);
988
+ if (!agentId) return null;
989
+ const cacheKey = `${dataDir || STANDALONE_DATA_DIR}\n${agentId}`;
990
+ if (agentDefinitionCache.has(cacheKey)) return agentDefinitionCache.get(cacheKey);
991
+ for (const dir of agentSourceDirs(dataDir, agentId)) {
992
+ const manifest = readJsonSafe(join(dir, 'agent.json')) || {};
993
+ const entry = clean(manifest.entry) || 'AGENT.md';
994
+ const body = readTextSafe(join(dir, entry));
995
+ if (!body) continue;
996
+ const definition = {
997
+ id: agentId,
998
+ name: clean(manifest.name) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
999
+ description: clean(manifest.description) || FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.description || '',
1000
+ body,
1001
+ };
1002
+ agentDefinitionCache.set(cacheKey, definition);
1003
+ return definition;
1004
+ }
1005
+ const legacyBody = readTextSafe(join(dataDir || STANDALONE_DATA_DIR, 'roles', `${agentId}.md`))
1006
+ || readTextSafe(join(STANDALONE_ROOT, 'agents', `${agentId}.md`));
1007
+ if (!legacyBody) {
1008
+ agentDefinitionCache.set(cacheKey, null);
1009
+ return null;
1010
+ }
1011
+ const definition = {
1012
+ id: agentId,
1013
+ name: FIXED_AGENT_SLOTS.find((agent) => agent.id === agentId)?.label || agentId,
1014
+ description: '',
1015
+ body: legacyBody,
1016
+ };
1017
+ agentDefinitionCache.set(cacheKey, definition);
1018
+ return definition;
1019
+ }
1020
+
1021
+ function workflowContextBlock(config, dataDir) {
1022
+ const pack = loadWorkflowPack(dataDir, activeWorkflowId(config));
1023
+ if (!pack) return '';
1024
+ const lines = [
1025
+ `# Active Workflow: ${pack.name}`,
1026
+ ];
1027
+ if (pack.description) lines.push(pack.description);
1028
+ lines.push(pack.body);
1029
+
1030
+ const agentIds = pack.agents.length ? pack.agents : FIXED_AGENT_SLOTS.map((agent) => agent.id);
1031
+ const agentBlocks = agentIds
1032
+ .map((id) => loadAgentDefinition(dataDir, id))
1033
+ .filter(Boolean);
1034
+ if (agentBlocks.length) {
1035
+ lines.push('# Available Agents');
1036
+ for (const agent of agentBlocks) {
1037
+ lines.push(`## ${agent.name} (${agent.id})`);
1038
+ if (agent.description) lines.push(agent.description);
1039
+ lines.push(agent.body);
1040
+ }
1041
+ }
1042
+ return lines.join('\n\n');
1043
+ }
1044
+
1045
+ function normalizeWorkflowRoute(routeLike, fallback = {}) {
1046
+ const provider = clean(routeLike?.provider) || clean(fallback.provider);
1047
+ const model = clean(routeLike?.model) || clean(fallback.model);
1048
+ if (!provider || !model) return null;
1049
+ const effort = normalizeEffortInput(routeLike?.effort ?? fallback.effort);
1050
+ const fast = routeLike?.fast ?? fallback.fast;
1051
+ return {
1052
+ provider,
1053
+ model,
1054
+ ...(effort ? { effort } : {}),
1055
+ ...(fast === true ? { fast: true } : {}),
1056
+ };
1057
+ }
1058
+
1059
+ function upsertWorkflowPreset(presets, slot, routeLike) {
1060
+ const route = normalizeWorkflowRoute(routeLike);
1061
+ if (!route) return presets;
1062
+ const id = workflowPresetId(slot);
1063
+ const preset = {
1064
+ id,
1065
+ name: workflowPresetName(slot),
1066
+ type: 'bridge',
1067
+ provider: route.provider,
1068
+ model: route.model,
1069
+ ...(route.effort ? { effort: route.effort } : {}),
1070
+ ...(route.fast === true ? { fast: true } : {}),
1071
+ tools: 'full',
1072
+ };
1073
+ const next = (Array.isArray(presets) ? presets : []).filter((p) => clean(p?.id) !== id && clean(p?.name) !== preset.name);
1074
+ next.push(preset);
1075
+ return next;
1076
+ }
1077
+
1078
+ function summarizeWorkflowRoutes(config) {
1079
+ const routes = config?.workflowRoutes && typeof config.workflowRoutes === 'object' ? config.workflowRoutes : {};
1080
+ const out = {};
1081
+ for (const slot of WORKFLOW_ROUTE_SLOTS) {
1082
+ const route = routes[slot];
1083
+ if (route?.provider && route?.model) out[slot] = normalizeWorkflowRoute(route);
1084
+ }
1085
+ return out;
1086
+ }
1087
+
1088
+ function legacyWorkflowRolePreset(dataDir, role) {
1089
+ try {
1090
+ const file = join(dataDir, 'user-workflow.json');
1091
+ if (!existsSync(file)) return '';
1092
+ const raw = JSON.parse(readFileSync(file, 'utf8'));
1093
+ const found = (raw?.roles || []).find((item) => clean(item?.name) === role);
1094
+ return clean(found?.preset);
1095
+ } catch {
1096
+ return '';
1097
+ }
1098
+ }
1099
+
1100
+ function routeFromPreset(config, presetName) {
1101
+ const preset = findPreset(config, presetName);
1102
+ return preset ? normalizeWorkflowRoute(preset) : null;
1103
+ }
1104
+
1105
+ function agentRouteFromConfig(config, agentId, dataDir) {
1106
+ const id = normalizeAgentId(agentId);
1107
+ if (!id) return null;
1108
+ const explicit = normalizeWorkflowRoute(config?.agents?.[id])
1109
+ || (id === 'maintainer' ? normalizeWorkflowRoute(config?.agents?.maintenance) : null);
1110
+ if (explicit) return explicit;
1111
+
1112
+ const agent = FIXED_AGENT_SLOTS.find((item) => item.id === id);
1113
+ if (agent?.workflowSlot) {
1114
+ const workflowRoute = normalizeWorkflowRoute(config?.workflowRoutes?.[agent.workflowSlot]);
1115
+ if (workflowRoute) return workflowRoute;
1116
+ }
1117
+
1118
+ if (id === 'explore') return routeFromPreset(config, config?.maintenance?.explore);
1119
+ if (id === 'maintainer') return routeFromPreset(config, config?.maintenance?.memory);
1120
+
1121
+ return routeFromPreset(config, legacyWorkflowRolePreset(dataDir, id));
1122
+ }
1123
+
1124
+ function toolResponseText(result) {
1125
+ if (result && typeof result === 'object' && Array.isArray(result.content)) {
1126
+ return result.content
1127
+ .map((part) => (part?.type === 'text' ? part.text || '' : JSON.stringify(part)))
1128
+ .join('\n');
1129
+ }
1130
+ if (typeof result === 'string') return result;
1131
+ return JSON.stringify(result, null, 2);
1132
+ }
1133
+
1134
+ function isEmptyRecallText(value) {
1135
+ const text = String(value || '').trim();
1136
+ return !text || /^\(?no results\)?$/i.test(text) || /^\(?empty memory result\)?$/i.test(text);
1137
+ }
1138
+
1139
+ function currentSessionRecallRows(session, query, { limit = 10 } = {}) {
1140
+ const messages = Array.isArray(session?.messages) ? session.messages : [];
1141
+ if (!messages.length) return '(no results)';
1142
+ const terms = [...new Set(String(query || '').toLowerCase().match(/[\p{L}\p{N}_./:-]{2,}/gu) || [])]
1143
+ .filter(Boolean)
1144
+ .slice(0, 16);
1145
+ const max = Math.max(1, Math.min(100, Number(limit) || 10));
1146
+ const rows = [];
1147
+ for (let i = messages.length - 1; i >= 0 && rows.length < max; i -= 1) {
1148
+ const m = messages[i];
1149
+ if (!m || (m.role !== 'user' && m.role !== 'assistant' && m.role !== 'tool')) continue;
1150
+ const text = messageContextText(m).replace(/\s+/g, ' ').trim();
1151
+ if (!text) continue;
1152
+ if (terms.length && !terms.some((term) => text.toLowerCase().includes(term))) continue;
1153
+ rows.push(`[session:${i + 1}] ${m.role}: ${text.slice(0, 1000)}`);
1154
+ }
1155
+ return rows.length ? rows.join('\n') : '(no results)';
1156
+ }
1157
+
1158
+ function parseToolSelection(value) {
1159
+ if (Array.isArray(value)) return value.map(clean).filter(Boolean);
1160
+ return String(value || '')
1161
+ .split(/[,\s]+/)
1162
+ .map(clean)
1163
+ .filter(Boolean);
1164
+ }
1165
+
1166
+ function toolKind(tool) {
1167
+ const name = clean(tool?.name);
1168
+ if (name.startsWith('mcp__')) return 'mcp';
1169
+ if (name.startsWith('skill_') || name === 'skills_list') return 'skill';
1170
+ if (tool?.annotations?.bridgeHidden) return 'control';
1171
+ if (['edit', 'write', 'apply_patch', 'shell'].includes(name)) return 'write';
1172
+ return 'tool';
1173
+ }
1174
+
1175
+ function measuredToolUsage(name) {
1176
+ return MEASURED_TOOL_USAGE[clean(name)] || 0;
1177
+ }
1178
+
1179
+ function measuredToolRank(name) {
1180
+ const index = MEASURED_TOOL_ORDER.indexOf(clean(name));
1181
+ return index === -1 ? Number.MAX_SAFE_INTEGER : index;
1182
+ }
1183
+
1184
+ function sortedCatalogByMeasuredUsage(catalog) {
1185
+ return (catalog || [])
1186
+ .map((tool, index) => ({ tool, index }))
1187
+ .sort((a, b) => {
1188
+ const au = measuredToolUsage(a.tool?.name);
1189
+ const bu = measuredToolUsage(b.tool?.name);
1190
+ if (bu !== au) return bu - au;
1191
+ const ar = measuredToolRank(a.tool?.name);
1192
+ const br = measuredToolRank(b.tool?.name);
1193
+ if (ar !== br) return ar - br;
1194
+ return a.index - b.index;
1195
+ })
1196
+ .map((entry) => entry.tool);
1197
+ }
1198
+
1199
+ function activeToolForSurface(tool) {
1200
+ if (!tool || typeof tool !== 'object') return tool;
1201
+ return JSON.parse(JSON.stringify(tool));
1202
+ }
1203
+
1204
+ function filterDisallowedTools(tools, disallowed = []) {
1205
+ if (!Array.isArray(disallowed) || disallowed.length === 0) return tools;
1206
+ const deny = new Set(disallowed.map((name) => clean(name)).filter(Boolean));
1207
+ if (deny.size === 0) return tools;
1208
+ return (tools || []).filter((tool) => !deny.has(clean(tool?.name)));
1209
+ }
1210
+
1211
+ function sortedNamesByMeasuredUsage(names) {
1212
+ return [...(names || [])].sort((a, b) => {
1213
+ const au = measuredToolUsage(a);
1214
+ const bu = measuredToolUsage(b);
1215
+ if (bu !== au) return bu - au;
1216
+ const ar = measuredToolRank(a);
1217
+ const br = measuredToolRank(b);
1218
+ if (ar !== br) return ar - br;
1219
+ return String(a).localeCompare(String(b));
1220
+ });
1221
+ }
1222
+
1223
+ export function defaultDeferredToolNames(catalog, mode) {
1224
+ if (mode === 'lead') {
1225
+ const available = new Set((catalog || []).map((tool) => clean(tool?.name)).filter(Boolean));
1226
+ return new Set(DEFERRED_DEFAULT_LEAD_TOOLS.filter((name) => available.has(name)));
1227
+ }
1228
+ if (mode === 'readonly') {
1229
+ const available = new Set((catalog || []).map((tool) => clean(tool?.name)).filter(Boolean));
1230
+ return new Set(DEFERRED_DEFAULT_READONLY_TOOLS.filter((name) => available.has(name)));
1231
+ }
1232
+ const names = new Set(DEFERRED_ALWAYS_ACTIVE_TOOLS);
1233
+ const limit = DEFERRED_DEFAULT_FULL_LIMIT;
1234
+ for (const tool of sortedCatalogByMeasuredUsage(catalog)) {
1235
+ const name = clean(tool?.name);
1236
+ if (!name || names.has(name)) continue;
1237
+ if (mode === 'readonly' && !isReadonlySelectable(tool)) continue;
1238
+ names.add(name);
1239
+ if (names.size >= DEFERRED_ALWAYS_ACTIVE_TOOLS.size + limit) break;
1240
+ }
1241
+ return names;
1242
+ }
1243
+
1244
+ export function compactToolSearchDescription(value, max = 220) {
1245
+ const text = clean(value).replace(/\s+/g, ' ');
1246
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
1247
+ }
1248
+
1249
+ function toolRow(tool, activeNames = new Set()) {
1250
+ const name = clean(tool?.name);
1251
+ return {
1252
+ name,
1253
+ kind: toolKind(tool),
1254
+ usage: measuredToolUsage(name),
1255
+ active: activeNames.has(name),
1256
+ description: compactToolSearchDescription(tool?.description),
1257
+ };
1258
+ }
1259
+
1260
+ function toolSearchTokens(value) {
1261
+ return (clean(value).toLowerCase().match(/[a-z0-9_.-]+/g) || [])
1262
+ .map((token) => token.replace(/[-.]+/g, '_'))
1263
+ .filter(Boolean);
1264
+ }
1265
+
1266
+ function toolSearchText(row) {
1267
+ const text = `${row.name} ${String(row.name || '').replace(/_/g, ' ')} ${row.kind} ${row.description} ${row.active ? 'active' : 'deferred'}`;
1268
+ return `${text} ${text.replace(/[-.]+/g, '_')}`.toLowerCase();
1269
+ }
1270
+
1271
+ function toolSearchMatches(row, query) {
1272
+ const raw = clean(query).toLowerCase();
1273
+ if (!raw) return true;
1274
+ const haystack = toolSearchText(row);
1275
+ if (haystack.includes(raw)) return true;
1276
+ const tokens = toolSearchTokens(raw);
1277
+ if (tokens.length === 0) return haystack.includes(raw);
1278
+ return tokens.some((token) => haystack.includes(token));
1279
+ }
1280
+
1281
+ function expandSelectionNames(names) {
1282
+ const out = [];
1283
+ for (const raw of names || []) {
1284
+ const key = clean(raw);
1285
+ if (!key) continue;
1286
+ const alias = DEFERRED_SELECT_ALIASES[key.toLowerCase()];
1287
+ if (alias) out.push(...alias);
1288
+ else out.push(key);
1289
+ }
1290
+ return [...new Set(out)];
1291
+ }
1292
+
1293
+ function isReadonlySelectable(tool) {
1294
+ const name = clean(tool?.name);
1295
+ if (READONLY_TOOL_NAMES.has(name)) return true;
1296
+ const annotations = tool?.annotations || {};
1297
+ if (annotations.destructiveHint === true) return false;
1298
+ if (annotations.readOnlyHint === true) return true;
1299
+ return false;
1300
+ }
1301
+
1302
+ function applyDeferredToolSurface(session, mode, extraTools = []) {
1303
+ if (!session || !Array.isArray(session.tools)) return session;
1304
+ const byName = new Map();
1305
+ for (const tool of [...session.tools, ...(extraTools || [])]) {
1306
+ const name = clean(tool?.name);
1307
+ if (!name || byName.has(name)) continue;
1308
+ byName.set(name, activeToolForSurface(tool));
1309
+ }
1310
+ const catalog = sortedCatalogByMeasuredUsage([...byName.values()]);
1311
+ const defaultNames = defaultDeferredToolNames(catalog, mode);
1312
+ session.deferredToolCatalog = catalog;
1313
+ session.deferredToolUsage = MEASURED_TOOL_USAGE;
1314
+ session.deferredSelectedTools = sortedNamesByMeasuredUsage(defaultNames);
1315
+ session.tools.length = 0;
1316
+ for (const tool of catalog) {
1317
+ if (!defaultNames.has(clean(tool?.name))) continue;
1318
+ if (mode === 'readonly' && !isReadonlySelectable(tool)) continue;
1319
+ session.tools.push(tool);
1320
+ }
1321
+ return session;
1322
+ }
1323
+
1324
+ function selectDeferredTools(session, names, mode) {
1325
+ const catalog = Array.isArray(session?.deferredToolCatalog)
1326
+ ? session.deferredToolCatalog
1327
+ : (Array.isArray(session?.tools) ? session.tools : []);
1328
+ const active = new Set((session?.tools || []).map((tool) => tool?.name).filter(Boolean));
1329
+ const byName = new Map(catalog.map((tool) => [tool?.name, tool]).filter(([name]) => name));
1330
+ const added = [];
1331
+ const already = [];
1332
+ const blocked = [];
1333
+ const missing = [];
1334
+ for (const name of expandSelectionNames(names)) {
1335
+ const tool = byName.get(name);
1336
+ if (!tool) {
1337
+ missing.push(name);
1338
+ continue;
1339
+ }
1340
+ if (mode === 'readonly' && !isReadonlySelectable(tool)) {
1341
+ blocked.push({ name, reason: 'readonly mode' });
1342
+ continue;
1343
+ }
1344
+ if (active.has(name)) {
1345
+ already.push(name);
1346
+ continue;
1347
+ }
1348
+ session.tools.push(tool);
1349
+ active.add(name);
1350
+ added.push(name);
1351
+ }
1352
+ session.deferredSelectedTools = sortedNamesByMeasuredUsage(active);
1353
+ return { added, already, blocked, missing };
1354
+ }
1355
+
1356
+ function renderToolSearch(args = {}, session, mode = 'full') {
1357
+ const catalog = Array.isArray(session?.deferredToolCatalog)
1358
+ ? session.deferredToolCatalog
1359
+ : (Array.isArray(session?.tools) ? session.tools : []);
1360
+ const activeNames = new Set((session?.tools || []).map((tool) => tool?.name).filter(Boolean));
1361
+ const query = clean(args.query).toLowerCase();
1362
+ const selectedNames = parseToolSelection(args.select);
1363
+ const limit = Math.max(1, Math.min(50, Number(args.limit) || 20));
1364
+ const selection = selectedNames.length ? selectDeferredTools(session, selectedNames, mode) : null;
1365
+ const nextActiveNames = new Set((session?.tools || []).map((tool) => tool?.name).filter(Boolean));
1366
+ const rows = catalog.map((tool) => toolRow(tool, nextActiveNames)).filter((row) => row.name);
1367
+ const matches = query
1368
+ ? rows.filter((row) => toolSearchMatches(row, query))
1369
+ : rows;
1370
+ return JSON.stringify({
1371
+ selected: selection,
1372
+ totalMatches: matches.length,
1373
+ matches: matches.slice(0, limit),
1374
+ activeTools: sortedNamesByMeasuredUsage(nextActiveNames),
1375
+ note: 'standalone: tool_search adds deferred tools to the current session schema for the next model iteration.',
1376
+ }, null, 2);
1377
+ }
1378
+
1379
+ function resolveCwdPath(currentCwd, value) {
1380
+ const raw = clean(value);
1381
+ if (!raw) throw new Error('cwd: path is required for action=set');
1382
+ const next = resolve(currentCwd || process.cwd(), raw);
1383
+ const stat = statSync(next);
1384
+ if (!stat.isDirectory()) throw new Error(`cwd: not a directory: ${next}`);
1385
+ return next;
1386
+ }
1387
+
1388
+ export async function createMixdogSessionRuntime({
1389
+ provider,
1390
+ model,
1391
+ cwd = process.cwd(),
1392
+ toolMode = 'full',
1393
+ } = {}) {
1394
+ bootProfile('session-runtime:start', { provider, model, toolMode, cwd });
1395
+ process.env.MIXDOG_QUIET_SESSION_LOG ??= '1';
1396
+ const standaloneStartedAt = performance.now();
1397
+ ensureStandaloneEnvironment({
1398
+ rootDir: STANDALONE_ROOT,
1399
+ dataDir: STANDALONE_DATA_DIR,
1400
+ });
1401
+ ensureProjectMixdogMd({ cwd });
1402
+ bootProfile('standalone-env:ready', { ms: (performance.now() - standaloneStartedAt).toFixed(1) });
1403
+
1404
+ const importsStartedAt = performance.now();
1405
+ const [
1406
+ cfgMod,
1407
+ sharedCfgMod,
1408
+ reg,
1409
+ mcpClient,
1410
+ mgr,
1411
+ contextMod,
1412
+ internalTools,
1413
+ statusRoutes,
1414
+ searchToolDefs,
1415
+ memoryToolDefs,
1416
+ channelToolDefs,
1417
+ codeGraphToolDefs,
1418
+ ] = await Promise.all([
1419
+ profiledImport('config', `${RUNTIME}/config.mjs`),
1420
+ profiledImport('shared-config', `${RUNTIME}/../../shared/config.mjs`),
1421
+ profiledImport('providers-registry', `${RUNTIME}/providers/registry.mjs`),
1422
+ profiledImport('mcp-client', `${RUNTIME}/mcp/client.mjs`),
1423
+ profiledImport('session-manager', `${RUNTIME}/session/manager.mjs`),
1424
+ profiledImport('context-collect', `${RUNTIME}/context/collect.mjs`),
1425
+ profiledImport('internal-tools', `${RUNTIME}/internal-tools.mjs`),
1426
+ profiledImport('status-routes', STATUSLINE_SESSION_ROUTES, { optional: true }),
1427
+ profiledImport('search-tool-defs', SEARCH_TOOL_DEFS, { optional: true }),
1428
+ profiledImport('memory-tool-defs', MEMORY_TOOL_DEFS, { optional: true }),
1429
+ profiledImport('channel-tool-defs', CHANNEL_TOOL_DEFS, { optional: true }),
1430
+ profiledImport('code-graph-tool-defs', CODE_GRAPH_TOOL_DEFS, { optional: true }),
1431
+ ]);
1432
+ bootProfile('imports:ready', { ms: (performance.now() - importsStartedAt).toFixed(1) });
1433
+ let memoryModPromise = null;
1434
+ let memoryInitPromise = null;
1435
+ let searchModPromise = null;
1436
+ let codeGraphModPromise = null;
1437
+
1438
+ async function getMemoryModule() {
1439
+ const startedAt = performance.now();
1440
+ memoryModPromise ??= import(MEMORY_RUNTIME);
1441
+ const mod = await memoryModPromise;
1442
+ if (typeof mod?.init === 'function') {
1443
+ memoryInitPromise ??= mod.init();
1444
+ await memoryInitPromise;
1445
+ }
1446
+ bootProfile('memory-runtime:ready', { ms: (performance.now() - startedAt).toFixed(1) });
1447
+ return mod;
1448
+ }
1449
+
1450
+ async function getSearchModule() {
1451
+ const startedAt = performance.now();
1452
+ searchModPromise ??= import(SEARCH_RUNTIME);
1453
+ const mod = await searchModPromise;
1454
+ bootProfile('search-runtime:ready', { ms: (performance.now() - startedAt).toFixed(1) });
1455
+ return mod;
1456
+ }
1457
+
1458
+ async function getCodeGraphModule() {
1459
+ const startedAt = performance.now();
1460
+ codeGraphModPromise ??= import(CODE_GRAPH_RUNTIME);
1461
+ const mod = await codeGraphModPromise;
1462
+ bootProfile('code-graph-runtime:ready', { ms: (performance.now() - startedAt).toFixed(1) });
1463
+ return mod;
1464
+ }
1465
+
1466
+ function persistLeadRoute(routeLike) {
1467
+ const leadRoute = normalizeWorkflowRoute(routeLike);
1468
+ if (!leadRoute) return null;
1469
+
1470
+ const nextConfig = { ...(config || {}) };
1471
+ nextConfig.presets = upsertWorkflowPreset(nextConfig.presets, 'lead', leadRoute);
1472
+ nextConfig.workflowRoutes = {
1473
+ ...(nextConfig.workflowRoutes || {}),
1474
+ lead: leadRoute,
1475
+ };
1476
+ nextConfig.default = workflowPresetId('lead');
1477
+
1478
+ cfgMod.saveConfig(nextConfig);
1479
+ config = nextConfig;
1480
+ return leadRoute;
1481
+ }
1482
+
1483
+ async function closePatchRuntimeIfLoaded(options = {}) {
1484
+ const closer = globalThis.__mixdogCloseNativePatchServers;
1485
+ if (typeof closer !== 'function' || globalThis.__mixdogNativePatchRuntimeTouched !== true) return;
1486
+ bootProfile('patch-runtime:close:start');
1487
+ const startedAt = performance.now();
1488
+ try {
1489
+ await closer(options);
1490
+ } catch {
1491
+ // Best-effort shutdown only; terminal restore must continue.
1492
+ } finally {
1493
+ bootProfile('patch-runtime:close:done', { ms: (performance.now() - startedAt).toFixed(1) });
1494
+ }
1495
+ }
1496
+
1497
+ function formatCoreMemoryLines(payload = {}) {
1498
+ const seen = new Set();
1499
+ const lines = [];
1500
+ for (const value of [
1501
+ ...(Array.isArray(payload.userLines) ? payload.userLines : []),
1502
+ ...(Array.isArray(payload.dbLines) ? payload.dbLines : []),
1503
+ ]) {
1504
+ const text = clean(value).replace(/\s+/g, ' ');
1505
+ if (!text) continue;
1506
+ const key = text.toLowerCase();
1507
+ if (seen.has(key)) continue;
1508
+ seen.add(key);
1509
+ lines.push(`- ${text}`);
1510
+ if (lines.length >= 40) break;
1511
+ }
1512
+ const out = lines.join('\n');
1513
+ const maxChars = 6000;
1514
+ return out.length > maxChars ? `${out.slice(0, maxChars).replace(/\s+\S*$/, '')}\n- ...` : out;
1515
+ }
1516
+
1517
+ async function loadCoreMemoryContext() {
1518
+ // Boot should not pay for memory/PG startup unless explicitly requested.
1519
+ // Recall and memory tools still initialize the memory service on first use.
1520
+ if (process.env.MIXDOG_BOOT_CORE_MEMORY !== '1') {
1521
+ bootProfile('core-memory:skipped');
1522
+ return '';
1523
+ }
1524
+ const startedAt = performance.now();
1525
+ let timer = null;
1526
+ const timeout = new Promise((resolve) => {
1527
+ timer = setTimeout(() => resolve(''), 2000);
1528
+ timer.unref?.();
1529
+ });
1530
+ try {
1531
+ return await Promise.race([
1532
+ (async () => {
1533
+ const memoryMod = await getMemoryModule();
1534
+ if (typeof memoryMod?.buildSessionCoreMemoryPayload !== 'function') return '';
1535
+ return formatCoreMemoryLines(await memoryMod.buildSessionCoreMemoryPayload(currentCwd));
1536
+ })(),
1537
+ timeout,
1538
+ ]);
1539
+ } catch {
1540
+ return '';
1541
+ } finally {
1542
+ if (timer) clearTimeout(timer);
1543
+ bootProfile('core-memory:done', { ms: (performance.now() - startedAt).toFixed(1) });
1544
+ }
1545
+ }
1546
+
1547
+ const configStartedAt = performance.now();
1548
+ let config = cfgMod.loadConfig({ secrets: false });
1549
+ setConfiguredShell(normalizeSystemShellConfig(config.shell).command);
1550
+ let configHasSecrets = false;
1551
+ let route = resolveRoute(config, { provider, model });
1552
+ bootProfile('config:ready', { ms: (performance.now() - configStartedAt).toFixed(1) });
1553
+ let mode = normalizeToolMode(toolMode);
1554
+ let session = null;
1555
+ let sessionCreatePromise = null;
1556
+ let currentCwd = cwd;
1557
+ let sessionNeedsCwdRefresh = false;
1558
+ const workspaceRouter = createWorkspaceRouter({ entryCwd: cwd });
1559
+ let closeRequested = false;
1560
+ let channelStartTimer = null;
1561
+ let providerWarmupTimer = null;
1562
+ let providerModelWarmupTimer = null;
1563
+ let activeTurnCount = 0;
1564
+ let firstTurnCompleted = false;
1565
+ const sessionPrewarmDelayMs = envDelayMs('MIXDOG_SESSION_PREWARM_DELAY_MS', 50, { min: 0, max: 10_000 });
1566
+ const providerWarmupDelayMs = envDelayMs('MIXDOG_PROVIDER_WARMUP_DELAY_MS', 1_500, { min: 0, max: 60_000 });
1567
+ const providerModelWarmupDelayMs = envDelayMs('MIXDOG_PROVIDER_MODEL_WARMUP_DELAY_MS', 15_000, { min: 0, max: 120_000 });
1568
+ const channelStartDelayMs = envDelayMs('MIXDOG_CHANNEL_START_DELAY_MS', 10_000, { min: 0, max: 120_000 });
1569
+ const backgroundBusyRetryMs = envDelayMs('MIXDOG_BACKGROUND_BUSY_RETRY_MS', 1_000, { min: 50, max: 10_000 });
1570
+ const modelMetaByRoute = new Map();
1571
+ const notificationListeners = new Set();
1572
+ let providerModelsCache = { models: null, at: 0 };
1573
+ let providerModelsPromise = null;
1574
+ let providerSetupCache = { setup: null, at: 0 };
1575
+ let providerSetupPromise = null;
1576
+ let providerInitPromise = null;
1577
+ const PROVIDER_SETUP_CACHE_TTL_MS = 10_000;
1578
+ let mcpFailures = [];
1579
+ let preSessionToolSurface = null;
1580
+ let contextStatusCacheKey = null;
1581
+ let contextStatusCacheValue = null;
1582
+ const hooksStartedAt = performance.now();
1583
+ const hooks = createStandaloneHookBus({ dataDir: cfgMod.getPluginData() });
1584
+ hooks.emit('runtime:start', { cwd: currentCwd, provider: route.provider, model: route.model, toolMode: mode });
1585
+ bootProfile('hooks:ready', { ms: (performance.now() - hooksStartedAt).toFixed(1) });
1586
+
1587
+ function contextContentLength(content) {
1588
+ if (typeof content === 'string') return content.length;
1589
+ if (!Array.isArray(content)) {
1590
+ try { return JSON.stringify(content ?? '').length; } catch { return String(content ?? '').length; }
1591
+ }
1592
+ let length = 0;
1593
+ for (const part of content) {
1594
+ if (typeof part === 'string') length += part.length;
1595
+ else if (typeof part?.text === 'string') length += part.text.length;
1596
+ else {
1597
+ try { length += JSON.stringify(part ?? '').length; } catch { length += String(part ?? '').length; }
1598
+ }
1599
+ }
1600
+ return length;
1601
+ }
1602
+
1603
+ function sameContextStatusKey(a, b) {
1604
+ if (!a || !b || a.length !== b.length) return false;
1605
+ for (let i = 0; i < a.length; i++) {
1606
+ if (!Object.is(a[i], b[i])) return false;
1607
+ }
1608
+ return true;
1609
+ }
1610
+
1611
+ function buildContextStatusCacheKey(messages, tools, bridgeMode) {
1612
+ const lastMessage = messages[messages.length - 1] || null;
1613
+ const compaction = session?.compaction || null;
1614
+ return [
1615
+ session?.id || null,
1616
+ route.provider,
1617
+ route.model,
1618
+ currentCwd,
1619
+ mode,
1620
+ bridgeMode,
1621
+ messages,
1622
+ messages.length,
1623
+ lastMessage,
1624
+ lastMessage?.role || null,
1625
+ lastMessage?.content || null,
1626
+ contextContentLength(lastMessage?.content),
1627
+ Array.isArray(lastMessage?.toolCalls) ? lastMessage.toolCalls.length : 0,
1628
+ tools,
1629
+ tools.length,
1630
+ session?.contextWindow || null,
1631
+ session?.rawContextWindow || null,
1632
+ session?.effectiveContextWindowPercent || null,
1633
+ session?.lastContextTokens || 0,
1634
+ session?.lastContextTokensUpdatedAt || 0,
1635
+ session?.lastContextTokensStaleAfterCompact === true,
1636
+ session?.lastInputTokens || 0,
1637
+ session?.lastOutputTokens || 0,
1638
+ session?.lastCachedReadTokens || 0,
1639
+ session?.lastCacheWriteTokens || 0,
1640
+ session?.totalInputTokens || 0,
1641
+ session?.totalOutputTokens || 0,
1642
+ session?.totalCachedReadTokens || 0,
1643
+ session?.totalCacheWriteTokens || 0,
1644
+ session?.compactBoundaryTokens || 0,
1645
+ compaction,
1646
+ compaction?.lastChangedAt || 0,
1647
+ compaction?.lastCompactAt || 0,
1648
+ compaction?.boundaryTokens || 0,
1649
+ compaction?.triggerTokens || 0,
1650
+ ];
1651
+ }
1652
+
1653
+ function mcpTransportLabel(cfg = {}) {
1654
+ if (cfg.autoDetect) return `autoDetect:${cfg.autoDetect}`;
1655
+ if (cfg.transport === 'http' || cfg.url) return 'http';
1656
+ if (cfg.command) return 'stdio';
1657
+ return 'unknown';
1658
+ }
1659
+
1660
+ function emitRuntimeNotification(content, meta = {}) {
1661
+ const text = String(content || '').trim();
1662
+ if (!text) return;
1663
+ const event = { content: text, meta: meta && typeof meta === 'object' ? meta : {} };
1664
+ for (const listener of [...notificationListeners]) {
1665
+ try { listener(event); } catch {}
1666
+ }
1667
+ }
1668
+
1669
+ function notifyFnForSession(callerSessionId) {
1670
+ return (text, meta = {}) => {
1671
+ const hadRuntimeListener = notificationListeners.size > 0;
1672
+ emitRuntimeNotification(text, meta);
1673
+ // TUI sessions keep their own Claude-Code-style command queue via
1674
+ // onNotification. Headless/model-tool callers have no listener, so fall
1675
+ // back to the session manager pending-message queue.
1676
+ if (!hadRuntimeListener && callerSessionId && typeof mgr.enqueuePendingMessage === 'function') {
1677
+ try { mgr.enqueuePendingMessage(callerSessionId, String(text || '')); } catch {}
1678
+ }
1679
+ };
1680
+ }
1681
+
1682
+ function mcpStatus() {
1683
+ const configured = config?.mcpServers && typeof config.mcpServers === 'object'
1684
+ ? config.mcpServers
1685
+ : {};
1686
+ const connected = new Map((mcpClient.getMcpServerStatus?.() || []).map((row) => [row.name, row]));
1687
+ const failures = new Map((mcpFailures || []).map((row) => [row.name, row]));
1688
+ const servers = [];
1689
+ for (const [name, cfg] of Object.entries(configured)) {
1690
+ const live = connected.get(name);
1691
+ const fail = failures.get(name);
1692
+ servers.push({
1693
+ name,
1694
+ configured: true,
1695
+ enabled: cfg?.enabled !== false,
1696
+ connected: Boolean(live),
1697
+ status: cfg?.enabled === false ? 'disabled' : live ? 'connected' : fail ? 'failed' : 'disconnected',
1698
+ transport: mcpTransportLabel(cfg),
1699
+ toolCount: live?.toolCount || 0,
1700
+ tools: live?.tools || [],
1701
+ error: fail?.msg || null,
1702
+ });
1703
+ connected.delete(name);
1704
+ }
1705
+ for (const live of connected.values()) {
1706
+ servers.push({ ...live, configured: false, status: 'connected' });
1707
+ }
1708
+ servers.sort((a, b) => String(a.name).localeCompare(String(b.name)));
1709
+ return {
1710
+ servers,
1711
+ configuredCount: Object.keys(configured).length,
1712
+ connectedCount: servers.filter((row) => row.connected).length,
1713
+ failedCount: servers.filter((row) => row.status === 'failed').length,
1714
+ };
1715
+ }
1716
+
1717
+ function skillsStatus() {
1718
+ const skills = typeof contextMod.collectSkillsCached === 'function'
1719
+ ? contextMod.collectSkillsCached(currentCwd)
1720
+ : [];
1721
+ const norm = (value) => String(value || '').replace(/\\/g, '/').toLowerCase();
1722
+ const cwdNorm = norm(currentCwd);
1723
+ const sourceForSkill = (filePath) => {
1724
+ const path = norm(filePath);
1725
+ if (cwdNorm && path.startsWith(`${cwdNorm}/.mixdog/skills/`)) return 'project';
1726
+ return 'skill';
1727
+ };
1728
+ return {
1729
+ cwd: currentCwd,
1730
+ count: skills.length,
1731
+ skills: skills.map((skill) => ({
1732
+ name: skill.name,
1733
+ description: skill.description || '',
1734
+ filePath: skill.filePath || null,
1735
+ source: sourceForSkill(skill.filePath),
1736
+ })),
1737
+ };
1738
+ }
1739
+
1740
+ function applyResolvedCwd(nextCwd, { markRefresh = true } = {}) {
1741
+ const resolved = resolve(nextCwd);
1742
+ const stat = statSync(resolved);
1743
+ if (!stat.isDirectory()) throw new Error(`cwd: not a directory: ${resolved}`);
1744
+ const changed = resolve(currentCwd) !== resolved;
1745
+ currentCwd = resolved;
1746
+ ensureProjectMixdogMd({ cwd: currentCwd });
1747
+ process.env.MIXDOG_SESSION_CWD = currentCwd;
1748
+ writeLastSessionCwd(currentCwd);
1749
+ if (session) session.cwd = currentCwd;
1750
+ if (changed && markRefresh && session?.id) sessionNeedsCwdRefresh = true;
1751
+ return currentCwd;
1752
+ }
1753
+
1754
+ async function refreshSessionForCwdIfNeeded(reason = 'cwd-change') {
1755
+ if (!session?.id || !sessionNeedsCwdRefresh) return session;
1756
+ const previousId = session.id;
1757
+ statusRoutes?.clearGatewaySessionRoute?.(previousId);
1758
+ mgr.closeSession(previousId, reason);
1759
+ session = null;
1760
+ sessionNeedsCwdRefresh = false;
1761
+ return await createCurrentSession();
1762
+ }
1763
+
1764
+ function buildWorkspaceContext() {
1765
+ try {
1766
+ return formatWorkspaceSessionContext(workspaceRouter.snapshot(currentCwd));
1767
+ } catch (error) {
1768
+ return [
1769
+ '# Workspace',
1770
+ `current cwd: ${currentCwd}`,
1771
+ `project candidates: unavailable (${error?.message || String(error)})`,
1772
+ ].join('\n');
1773
+ }
1774
+ }
1775
+
1776
+ function skillContent(name) {
1777
+ const content = typeof contextMod.loadSkillContent === 'function'
1778
+ ? contextMod.loadSkillContent(name, currentCwd)
1779
+ : null;
1780
+ if (!content) throw new Error(`skill not found: ${name}`);
1781
+ return { name, content };
1782
+ }
1783
+
1784
+ function addProjectSkill(input = {}) {
1785
+ const name = clean(input.name).replace(/[^a-zA-Z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '');
1786
+ if (!name) throw new Error('skill name is required');
1787
+ const dir = join(currentCwd, '.mixdog', 'skills', name);
1788
+ const filePath = join(dir, 'SKILL.md');
1789
+ if (existsSync(filePath)) throw new Error(`skill already exists: ${name}`);
1790
+ const description = clean(input.description) || 'Project skill.';
1791
+ mkdirSync(dir, { recursive: true });
1792
+ writeFileSync(filePath, [
1793
+ '---',
1794
+ `name: ${name}`,
1795
+ `description: ${description}`,
1796
+ '---',
1797
+ '',
1798
+ '# Instructions',
1799
+ '',
1800
+ 'Describe when and how to use this skill.',
1801
+ '',
1802
+ ].join('\n'), 'utf8');
1803
+ return { name, filePath };
1804
+ }
1805
+
1806
+ function pluginsStatus() {
1807
+ const dataDir = cfgMod.getPluginData?.();
1808
+ const configuredMcp = config?.mcpServers && typeof config.mcpServers === 'object'
1809
+ ? config.mcpServers
1810
+ : {};
1811
+ const plugins = [];
1812
+ const addRegisteredPlugin = (entry) => {
1813
+ const root = clean(entry.root);
1814
+ if (!root || !existsSync(root)) return;
1815
+ const manifest = pluginManifest(root);
1816
+ const name = clean(manifest.name) || clean(manifest.id) || clean(entry.name) || root.split(/[\\/]/).pop() || root;
1817
+ const plugin = {
1818
+ id: clean(entry.id) || name,
1819
+ name,
1820
+ title: clean(manifest.title) || clean(manifest.displayName) || clean(entry.title) || name,
1821
+ version: clean(manifest.version) || clean(entry.version) || null,
1822
+ description: clean(manifest.description) || clean(entry.description),
1823
+ marketplace: null,
1824
+ source: clean(entry.sourceType) === 'local' ? 'local' : 'registry',
1825
+ sourceUrl: clean(entry.source),
1826
+ sourceType: clean(entry.sourceType) || 'git',
1827
+ managed: entry.managed !== false,
1828
+ root,
1829
+ installedAt: entry.installedAt || null,
1830
+ updatedAt: entry.updatedAt || null,
1831
+ skillCount: countSkillFiles(root),
1832
+ mcpScript: mcpScriptForPlugin(root),
1833
+ };
1834
+ plugin.mcpServerName = pluginMcpServerName(plugin);
1835
+ plugin.mcpEnabled = Object.prototype.hasOwnProperty.call(configuredMcp, plugin.mcpServerName);
1836
+ plugins.push(plugin);
1837
+ };
1838
+
1839
+ for (const entry of listRegisteredPlugins({ dataDir })) addRegisteredPlugin(entry);
1840
+
1841
+ plugins.sort((a, b) => {
1842
+ if (a.source !== b.source) return a.source.localeCompare(b.source);
1843
+ return a.name.localeCompare(b.name);
1844
+ });
1845
+ const admin = pluginAdminStatus({ dataDir });
1846
+ return {
1847
+ count: plugins.length,
1848
+ plugins,
1849
+ roots: {
1850
+ registry: admin.registryPath,
1851
+ installed: admin.installRoot,
1852
+ },
1853
+ };
1854
+ }
1855
+
1856
+ async function connectConfiguredMcp({ reset = false } = {}) {
1857
+ if (reset) await mcpClient.disconnectAll?.();
1858
+ mcpFailures = [];
1859
+ const servers = config?.mcpServers && typeof config.mcpServers === 'object'
1860
+ ? config.mcpServers
1861
+ : {};
1862
+ if (Object.keys(servers).length === 0) return mcpStatus();
1863
+ try {
1864
+ await mcpClient.connectMcpServers(servers);
1865
+ } catch (error) {
1866
+ mcpFailures = Array.isArray(error?.failures)
1867
+ ? error.failures
1868
+ : [{ name: 'mcp', msg: error?.message || String(error) }];
1869
+ }
1870
+ return mcpStatus();
1871
+ }
1872
+
1873
+ function normalizeMcpServerInput(input = {}) {
1874
+ const name = clean(input.name).toLowerCase().replace(/[^a-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '');
1875
+ if (!name) throw new Error('MCP server name is required');
1876
+ const url = clean(input.url);
1877
+ if (url) {
1878
+ if (!/^https?:\/\//i.test(url)) throw new Error('MCP URL must start with http:// or https://');
1879
+ return { name, config: { transport: 'http', url } };
1880
+ }
1881
+ const command = clean(input.command);
1882
+ if (!command) throw new Error('MCP server command or URL is required');
1883
+ const args = Array.isArray(input.args)
1884
+ ? input.args.map((v) => String(v)).filter(Boolean)
1885
+ : clean(input.args).split(/\s+/).filter(Boolean);
1886
+ const requestedCwd = clean(input.cwd);
1887
+ const cwdForServer = requestedCwd ? resolve(currentCwd, requestedCwd) : currentCwd;
1888
+ const root = resolve(currentCwd);
1889
+ const resolvedCwd = resolve(cwdForServer);
1890
+ if (resolvedCwd !== root && !resolvedCwd.startsWith(`${root}\\`) && !resolvedCwd.startsWith(`${root}/`)) {
1891
+ throw new Error('MCP server cwd must stay under the current project');
1892
+ }
1893
+ return { name, config: { command, args, cwd: resolvedCwd } };
1894
+ }
1895
+
1896
+ const persistedBridgeMode = (() => {
1897
+ try { return (sharedCfgMod.readSection('agent') || {}).bridgeMode; } catch { return undefined; }
1898
+ })();
1899
+ const bridgeStartedAt = performance.now();
1900
+ const bridge = createStandaloneBridge({
1901
+ cfgMod,
1902
+ reg,
1903
+ mgr,
1904
+ dataDir: cfgMod.getPluginData(),
1905
+ cwd,
1906
+ defaultMode: persistedBridgeMode ?? 'async',
1907
+ });
1908
+ bootProfile('bridge:ready', { ms: (performance.now() - bridgeStartedAt).toFixed(1) });
1909
+ const bridgeStatusState = () => {
1910
+ try {
1911
+ const status = bridge.getStatus?.({ clientHostPid: session?.clientHostPid || process.pid }) || {};
1912
+ return {
1913
+ bridgeMode: bridge.getDefaultMode?.() || status.bridgeMode || 'async',
1914
+ bridgeWorkers: Array.isArray(status.workers) ? status.workers : [],
1915
+ bridgeJobs: Array.isArray(status.jobs) ? status.jobs : [],
1916
+ bridgeScope: status.scope || null,
1917
+ };
1918
+ } catch {
1919
+ return { bridgeMode: bridge.getDefaultMode?.() || 'async', bridgeWorkers: [], bridgeJobs: [], bridgeScope: null };
1920
+ }
1921
+ };
1922
+ const channelsStartedAt = performance.now();
1923
+ const channels = createStandaloneChannelWorker({
1924
+ entry: join(STANDALONE_ROOT, CHANNEL_WORKER_ENTRY.replace(/^\.\//, '')),
1925
+ rootDir: STANDALONE_ROOT,
1926
+ dataDir: cfgMod.getPluginData(),
1927
+ cwd,
1928
+ });
1929
+ bootProfile('channels:worker-ready', { ms: (performance.now() - channelsStartedAt).toFixed(1) });
1930
+ const toolsStartedAt = performance.now();
1931
+ const standaloneTools = [
1932
+ TOOL_SEARCH_TOOL,
1933
+ CWD_TOOL,
1934
+ EXPLORE_TOOL,
1935
+ ...(searchToolDefs?.TOOL_DEFS || []).filter((tool) => tool?.name === 'search' || tool?.name === 'web_fetch'),
1936
+ ...(memoryToolDefs?.TOOL_DEFS || []).filter((tool) => tool?.name === 'recall' || tool?.name === 'memory'),
1937
+ ...(channelToolDefs?.TOOL_DEFS || []).filter((tool) => channels.isChannelTool(tool?.name)),
1938
+ ...(codeGraphToolDefs?.CODE_GRAPH_TOOL_DEFS || []).filter((tool) => tool?.name === 'code_graph'),
1939
+ ...bridge.tools,
1940
+ PROVIDER_STATUS_TOOL,
1941
+ CHANNEL_STATUS_TOOL,
1942
+ ].map(applyStandaloneToolDefaults);
1943
+ bootProfile('tools:ready', { ms: (performance.now() - toolsStartedAt).toFixed(1), count: standaloneTools.length });
1944
+
1945
+ function invalidatePreSessionToolSurface() {
1946
+ preSessionToolSurface = null;
1947
+ }
1948
+
1949
+ function invalidateContextStatusCache() {
1950
+ contextStatusCacheKey = null;
1951
+ contextStatusCacheValue = null;
1952
+ }
1953
+
1954
+ function buildPreSessionToolSurface() {
1955
+ const previewTools = typeof mgr.previewSessionTools === 'function'
1956
+ ? mgr.previewSessionTools(toolSpecForMode(mode), [])
1957
+ : [];
1958
+ const tools = filterDisallowedTools(previewTools, LEAD_DISALLOWED_TOOLS);
1959
+ const surface = { tools: Array.isArray(tools) ? tools.slice() : [] };
1960
+ applyDeferredToolSurface(surface, mode, standaloneTools);
1961
+ return surface;
1962
+ }
1963
+
1964
+ function activeToolSurface() {
1965
+ if (session) return session;
1966
+ preSessionToolSurface ??= buildPreSessionToolSurface();
1967
+ return preSessionToolSurface;
1968
+ }
1969
+
1970
+ function applyPreSessionToolSelection() {
1971
+ if (!session || !preSessionToolSurface) return;
1972
+ const selected = Array.isArray(preSessionToolSurface.deferredSelectedTools)
1973
+ ? preSessionToolSurface.deferredSelectedTools
1974
+ : [];
1975
+ if (selected.length) selectDeferredTools(session, selected, mode);
1976
+ }
1977
+ internalTools.setInternalToolsProvider({
1978
+ tools: standaloneTools,
1979
+ executor: async (name, args, callerCtx = {}) => {
1980
+ const callerCwd = callerCtx?.callerCwd || currentCwd;
1981
+ if (name === 'search' || name === 'web_fetch') {
1982
+ const callerSessionId = callerCtx?.callerSessionId || session?.id || null;
1983
+ const searchMod = await getSearchModule();
1984
+ if (!searchMod?.handleToolCall) throw new Error('search runtime is not available');
1985
+ return await searchMod.handleToolCall(name, args || {}, {
1986
+ callerCwd,
1987
+ callerSessionId,
1988
+ routingSessionId: callerSessionId,
1989
+ clientHostPid: callerCtx?.clientHostPid || session?.clientHostPid || process.pid,
1990
+ notifyFn: notifyFnForSession(callerSessionId),
1991
+ agentSearch: name === 'search'
1992
+ ? async (searchArgs) => {
1993
+ const query = Array.isArray(searchArgs.keywords)
1994
+ ? searchArgs.keywords.join('\n')
1995
+ : String(searchArgs.keywords || searchArgs.query || '');
1996
+ const prompt = searchArgs.prompt || [
1997
+ 'Perform a concise web research task for Mixdog search.',
1998
+ '',
1999
+ `Query: ${query}`,
2000
+ searchArgs.site ? `Site/domain restriction: ${searchArgs.site}` : null,
2001
+ searchArgs.type ? `Search type: ${searchArgs.type}` : null,
2002
+ searchArgs.locale ? `Locale: ${typeof searchArgs.locale === 'string' ? searchArgs.locale : JSON.stringify(searchArgs.locale)}` : null,
2003
+ `Max results: ${Math.max(1, Math.min(20, Number(searchArgs.maxResults) || 10))}`,
2004
+ '',
2005
+ 'Return a short answer first, then cite useful results as title + URL + one-line snippet.',
2006
+ 'Do not edit files.',
2007
+ ].filter(Boolean).join('\n');
2008
+ const rendered = await bridge.execute({
2009
+ type: 'spawn',
2010
+ agent: 'web-researcher',
2011
+ tag: `search_${Date.now().toString(36)}`,
2012
+ prompt,
2013
+ cwd: callerCwd,
2014
+ wait: true,
2015
+ firstResponseTimeoutMs: Number.isFinite(Number(searchArgs.firstResponseTimeoutMs)) ? Number(searchArgs.firstResponseTimeoutMs) : 120_000,
2016
+ idleTimeoutMs: Number.isFinite(Number(searchArgs.idleTimeoutMs)) ? Number(searchArgs.idleTimeoutMs) : 30 * 60_000,
2017
+ }, { invocationSource: 'user-command', callerCwd });
2018
+ return String(rendered || '').replace(/^bridge result[^\n]*\n/i, '').trim();
2019
+ }
2020
+ : undefined,
2021
+ });
2022
+ }
2023
+ if (name === 'recall' || name === 'memory' || name === 'search_memories') {
2024
+ const memoryMod = await getMemoryModule();
2025
+ if (!memoryMod?.handleToolCall) throw new Error('memory runtime is not available');
2026
+ return await memoryMod.handleToolCall(name, args || {});
2027
+ }
2028
+ if (name === 'code_graph') {
2029
+ const codeGraphMod = await getCodeGraphModule();
2030
+ if (!codeGraphMod?.executeCodeGraphTool) throw new Error('code_graph runtime is not available');
2031
+ return await codeGraphMod.executeCodeGraphTool(name, args || {}, args?.cwd || callerCwd);
2032
+ }
2033
+ if (name === 'tool_search') return renderToolSearch(args, session, mode);
2034
+ if (name === 'explore') {
2035
+ const callerSessionId = callerCtx?.callerSessionId || session?.id || null;
2036
+ return await runExplore(args || {}, {
2037
+ callerCwd: args?.cwd ? resolveCwdPath(currentCwd, args.cwd) : callerCwd,
2038
+ callerSessionId,
2039
+ routingSessionId: callerSessionId,
2040
+ clientHostPid: callerCtx?.clientHostPid || session?.clientHostPid || process.pid,
2041
+ notifyFn: notifyFnForSession(callerSessionId),
2042
+ });
2043
+ }
2044
+ if (name === 'cwd') {
2045
+ const action = clean(args?.action || (args?.path ? 'set' : 'get')).toLowerCase();
2046
+ if (action === 'set') {
2047
+ applyResolvedCwd(resolveCwdPath(currentCwd, args?.path));
2048
+ } else if (action !== 'get') {
2049
+ throw new Error(`cwd: unknown action "${action}"`);
2050
+ }
2051
+ return JSON.stringify({ cwd: currentCwd, sessionId: session?.id || null }, null, 2);
2052
+ }
2053
+ if (name === 'bridge') {
2054
+ const callerSessionId = callerCtx?.callerSessionId || session?.id || null;
2055
+ return await bridge.execute(args, {
2056
+ callerCwd,
2057
+ invocationSource: 'model-tool',
2058
+ callerSessionId,
2059
+ clientHostPid: callerCtx?.clientHostPid || session?.clientHostPid || process.pid,
2060
+ signal: callerCtx?.signal,
2061
+ notifyFn: notifyFnForSession(callerSessionId),
2062
+ });
2063
+ }
2064
+ if (name === 'provider_status') return renderProviderStatus(cfgMod.loadConfig());
2065
+ if (name === 'channel_status') return renderChannelStatus();
2066
+ if (channels.isChannelTool(name)) return await channels.execute(name, args || {});
2067
+ throw new Error(`unknown standalone internal tool: ${name}`);
2068
+ },
2069
+ });
2070
+ internalTools.markBootReady?.();
2071
+ void connectConfiguredMcp()
2072
+ .then((status) => bootProfile('mcp:ready', {
2073
+ connected: Number(status?.connectedCount || 0),
2074
+ failed: Number(status?.failedCount || 0),
2075
+ }))
2076
+ .catch((error) => bootProfile('mcp:failed', { error: error?.message || String(error) }));
2077
+
2078
+ function reloadChannelsSoon() {
2079
+ channels.execute('reload_config', {}).catch(() => {});
2080
+ }
2081
+
2082
+ function invalidateProviderCaches() {
2083
+ providerModelsCache = { models: null, at: 0 };
2084
+ providerModelsPromise = null;
2085
+ providerSetupCache = { setup: null, at: 0 };
2086
+ providerSetupPromise = null;
2087
+ providerInitPromise = null;
2088
+ modelMetaByRoute.clear();
2089
+ }
2090
+
2091
+ function ensureFullConfig() {
2092
+ if (configHasSecrets) return config;
2093
+ config = cfgMod.loadConfig();
2094
+ configHasSecrets = true;
2095
+ return config;
2096
+ }
2097
+
2098
+ function ensureConfigForRouteProvider() {
2099
+ const providerId = clean(route.provider);
2100
+ const providerCfg = config?.providers?.[providerId];
2101
+ if (configHasSecrets || LAZY_SECRET_PROVIDERS.has(providerId) || providerCfg?.apiKey) {
2102
+ return config;
2103
+ }
2104
+ return ensureFullConfig();
2105
+ }
2106
+
2107
+ async function ensureProvidersReady(providerConfig = config.providers || {}) {
2108
+ if (providerInitPromise) return await providerInitPromise;
2109
+ providerInitPromise = reg.initProviders(providerConfig)
2110
+ .finally(() => {
2111
+ providerInitPromise = null;
2112
+ });
2113
+ return await providerInitPromise;
2114
+ }
2115
+
2116
+ async function cachedProviderSetup({ force = false } = {}) {
2117
+ const now = Date.now();
2118
+ if (!force && providerSetupCache.setup && now - providerSetupCache.at < PROVIDER_SETUP_CACHE_TTL_MS) {
2119
+ return providerSetupCache.setup;
2120
+ }
2121
+ if (!force && providerSetupPromise) return await providerSetupPromise;
2122
+ providerSetupPromise = providerSetup(cfgMod.loadConfig())
2123
+ .then((setup) => {
2124
+ providerSetupCache = { setup, at: Date.now() };
2125
+ return setup;
2126
+ })
2127
+ .finally(() => {
2128
+ providerSetupPromise = null;
2129
+ });
2130
+ return await providerSetupPromise;
2131
+ }
2132
+
2133
+ function modelMetaKey(providerId, modelId) {
2134
+ return `${clean(providerId)}\n${clean(modelId)}`;
2135
+ }
2136
+
2137
+ async function lookupModelMeta(providerId, modelId, { allowFetch = false } = {}) {
2138
+ const key = modelMetaKey(providerId, modelId);
2139
+ if (modelMetaByRoute.has(key)) return modelMetaByRoute.get(key);
2140
+ const providerImpl = reg.getProvider(providerId);
2141
+ if (!providerImpl || typeof providerImpl.listModels !== 'function') {
2142
+ const fallback = { id: modelId, provider: providerId };
2143
+ modelMetaByRoute.set(key, fallback);
2144
+ return fallback;
2145
+ }
2146
+ if (typeof providerImpl.getCachedModelInfo === 'function') {
2147
+ const cached = providerImpl.getCachedModelInfo(modelId);
2148
+ if (cached) {
2149
+ const meta = { ...cached, id: cached.id || modelId, provider: providerId };
2150
+ modelMetaByRoute.set(key, meta);
2151
+ return meta;
2152
+ }
2153
+ }
2154
+ if (!allowFetch) {
2155
+ const fallback = { id: modelId, provider: providerId };
2156
+ modelMetaByRoute.set(key, fallback);
2157
+ scheduleProviderModelWarmup();
2158
+ return fallback;
2159
+ }
2160
+ try {
2161
+ const models = await providerImpl.listModels();
2162
+ const found = Array.isArray(models) ? models.find((m) => m?.id === modelId) : null;
2163
+ const meta = found || { id: modelId, provider: providerId };
2164
+ modelMetaByRoute.set(key, meta);
2165
+ return meta;
2166
+ } catch {
2167
+ const fallback = { id: modelId, provider: providerId };
2168
+ modelMetaByRoute.set(key, fallback);
2169
+ return fallback;
2170
+ }
2171
+ }
2172
+
2173
+ function parsedProviderModelVersion(id) {
2174
+ const text = clean(id).toLowerCase();
2175
+ const claude = text.match(/^claude-[a-z]+-(\d+)(?:[-.](\d+))?/);
2176
+ if (claude) return [Number(claude[1]) || 0, Number(claude[2]) || 0];
2177
+ const compact = text.match(/(?:^|[-_])(?:o|gpt|grok|qwen|llama|mistral|gemma|phi|glm)(\d+)(?:\.(\d+))?(?:\.(\d{1,3}))?/);
2178
+ if (compact) return compact.slice(1).filter((v) => v != null).map((v) => Number(v) || 0);
2179
+ const generic = text.match(/(?:^|[-_v])(\d+)(?:\.(\d+))?(?:\.(\d{1,3}))?/);
2180
+ return generic ? generic.slice(1).filter((v) => v != null).map((v) => Number(v) || 0) : [];
2181
+ }
2182
+
2183
+ function compareProviderModelVersion(a, b) {
2184
+ const va = parsedProviderModelVersion(a.id || a.display || a.name);
2185
+ const vb = parsedProviderModelVersion(b.id || b.display || b.name);
2186
+ if (va.length === 0 && vb.length === 0) return 0;
2187
+ if (va.length === 0) return 1;
2188
+ if (vb.length === 0) return -1;
2189
+ for (let i = 0; i < Math.max(va.length, vb.length); i += 1) {
2190
+ const delta = (vb[i] || 0) - (va[i] || 0);
2191
+ if (delta) return delta;
2192
+ }
2193
+ return 0;
2194
+ }
2195
+
2196
+ function providerModelReleaseTime(model) {
2197
+ if (model?.releaseDate) {
2198
+ const t = Date.parse(model.releaseDate);
2199
+ if (Number.isFinite(t)) return t;
2200
+ }
2201
+ const created = Number(model?.created);
2202
+ if (Number.isFinite(created) && created > 0) {
2203
+ return created < 1_000_000_000_000 ? created * 1000 : created;
2204
+ }
2205
+ const dated = clean(model?.id).match(/(?:^|-)(\d{4})(\d{2})(\d{2})(?:$|-)/);
2206
+ return dated ? (Date.parse(`${dated[1]}-${dated[2]}-${dated[3]}`) || 0) : 0;
2207
+ }
2208
+
2209
+ function isClaudeProviderModel(model) {
2210
+ return clean(model?.provider).toLowerCase().includes('anthropic')
2211
+ && /^claude-[a-z]+-/.test(clean(model?.id).toLowerCase());
2212
+ }
2213
+
2214
+ function compareProviderModelRecency(a, b) {
2215
+ if (isClaudeProviderModel(a) && isClaudeProviderModel(b)) {
2216
+ if (a.latest !== b.latest) return a.latest ? -1 : 1;
2217
+ const versionDelta = compareProviderModelVersion(a, b);
2218
+ if (versionDelta) return versionDelta;
2219
+ const ta = providerModelReleaseTime(a);
2220
+ const tb = providerModelReleaseTime(b);
2221
+ if (ta !== tb) return tb - ta;
2222
+ return clean(a.display || a.id).localeCompare(clean(b.display || b.id));
2223
+ }
2224
+ const ta = providerModelReleaseTime(a);
2225
+ const tb = providerModelReleaseTime(b);
2226
+ if (ta !== tb) return tb - ta;
2227
+ if (a.latest !== b.latest) return a.latest ? -1 : 1;
2228
+ const versionDelta = compareProviderModelVersion(a, b);
2229
+ if (versionDelta) return versionDelta;
2230
+ return clean(a.display || a.id).localeCompare(clean(b.display || b.id));
2231
+ }
2232
+
2233
+ function sortProviderModels(models) {
2234
+ return (models || []).sort((a, b) => {
2235
+ const ar = a.provider === route.provider ? 0 : 1;
2236
+ const br = b.provider === route.provider ? 0 : 1;
2237
+ if (ar !== br) return ar - br;
2238
+ if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
2239
+ return compareProviderModelRecency(a, b);
2240
+ });
2241
+ }
2242
+
2243
+ function isSelectableLlmModel(model) {
2244
+ const id = clean(model?.id).toLowerCase();
2245
+ const display = clean(model?.display || model?.name).toLowerCase();
2246
+ const mode = clean(model?.mode).toLowerCase();
2247
+ const text = `${id} ${display}`;
2248
+ if (!id) return false;
2249
+ if (mode && !['chat', 'completion', 'responses', 'messages'].includes(mode)) return false;
2250
+ if (/(^|[-_\s])(image|images|video|videos|audio|tts|stt|speech|embedding|embeddings|rerank|moderation|imagine)([-_\s]|$)/i.test(text)) return false;
2251
+ if (/(^|[-_\s])(dall[-_\s]?e|sora|imagen)([-_\s]|$)/i.test(text)) return false;
2252
+ return true;
2253
+ }
2254
+
2255
+ function providerModelCacheRow(name, m) {
2256
+ return {
2257
+ id: m.id,
2258
+ provider: name,
2259
+ display: m.display || m.name || m.id,
2260
+ created: typeof m.created === 'number' ? m.created : null,
2261
+ releaseDate: m.releaseDate || null,
2262
+ contextWindow: m.contextWindow,
2263
+ outputTokens: m.outputTokens || null,
2264
+ family: m.family || null,
2265
+ tier: m.tier || null,
2266
+ latest: m.latest === true,
2267
+ description: m.description || '',
2268
+ supportsVision: m.supportsVision === true,
2269
+ supportsFunctionCalling: m.supportsFunctionCalling === true,
2270
+ supportsPromptCaching: m.supportsPromptCaching === true,
2271
+ supportsReasoning: m.supportsReasoning === true,
2272
+ reasoningLevels: Array.isArray(m.reasoningLevels) ? m.reasoningLevels : [],
2273
+ reasoningOptions: Array.isArray(m.reasoningOptions) ? m.reasoningOptions : [],
2274
+ reasoningContentField: m.reasoningContentField || null,
2275
+ mode: m.mode || null,
2276
+ };
2277
+ }
2278
+
2279
+ function hydrateProviderModelRow(row) {
2280
+ return {
2281
+ ...row,
2282
+ effortOptions: effortItemsFor(row.provider, row, null),
2283
+ fastCapable: fastCapableFor(row.provider, row),
2284
+ fastPreferred: fastPreferenceFor(config, row.provider, row.id),
2285
+ savedEffort: modelSettingsFor(config, row.provider, row.id).effort || null,
2286
+ savedFast: modelSettingsFor(config, row.provider, row.id).fast === true,
2287
+ };
2288
+ }
2289
+
2290
+ function providerModelsFromCacheRows(rows) {
2291
+ return sortProviderModels((rows || []).map(hydrateProviderModelRow));
2292
+ }
2293
+
2294
+ async function loadProviderModelsFresh() {
2295
+ ensureFullConfig();
2296
+ await ensureProvidersReady(config.providers || {});
2297
+ const allProviders = reg.getAllProviders();
2298
+ const results = [];
2299
+ const seen = new Set();
2300
+ for (const [name, provider] of allProviders) {
2301
+ if (typeof provider?.listModels !== 'function') continue;
2302
+ try {
2303
+ const models = await provider.listModels();
2304
+ if (Array.isArray(models)) {
2305
+ for (const m of models) {
2306
+ if (!m?.id) continue;
2307
+ if (!isSelectableLlmModel(m)) continue;
2308
+ const key = `${name}:${m.id}`;
2309
+ if (seen.has(key)) continue;
2310
+ seen.add(key);
2311
+ const row = providerModelCacheRow(name, m);
2312
+ results.push(row);
2313
+ modelMetaByRoute.set(modelMetaKey(name, m.id), row);
2314
+ }
2315
+ }
2316
+ } catch {
2317
+ // Ignore per-provider catalog failures so one bad credential or
2318
+ // transient /models error does not hide other authenticated models.
2319
+ }
2320
+ }
2321
+ return results;
2322
+ }
2323
+
2324
+ async function collectProviderModels({ force = false } = {}) {
2325
+ if (!force && Array.isArray(providerModelsCache.models)) {
2326
+ return providerModelsFromCacheRows(providerModelsCache.models);
2327
+ }
2328
+ if (!providerModelsPromise) {
2329
+ providerModelsPromise = loadProviderModelsFresh()
2330
+ .then((models) => {
2331
+ providerModelsCache = { models, at: Date.now() };
2332
+ return models;
2333
+ })
2334
+ .finally(() => {
2335
+ providerModelsPromise = null;
2336
+ });
2337
+ }
2338
+ return providerModelsFromCacheRows(await providerModelsPromise);
2339
+ }
2340
+
2341
+ function warmProviderModelCache() {
2342
+ if (Array.isArray(providerModelsCache.models) || providerModelsPromise) return providerModelsPromise;
2343
+ providerModelsPromise = loadProviderModelsFresh()
2344
+ .then((models) => {
2345
+ providerModelsCache = { models, at: Date.now() };
2346
+ bootProfile('provider-models:warm-ready', { count: models.length });
2347
+ return models;
2348
+ })
2349
+ .catch((err) => {
2350
+ const msg = err instanceof Error ? err.message : String(err);
2351
+ bootProfile('provider-models:warm-failed', { error: msg });
2352
+ return [];
2353
+ })
2354
+ .finally(() => {
2355
+ providerModelsPromise = null;
2356
+ });
2357
+ return providerModelsPromise;
2358
+ }
2359
+
2360
+ async function resolveMissingRouteModelForFirstTurn() {
2361
+ if (routeHasModel()) return route;
2362
+ const models = await collectProviderModels();
2363
+ const picked = models[0] || null;
2364
+ if (!picked) {
2365
+ throw new Error('No provider models available. Run /providers to authenticate, then /model to choose a model.');
2366
+ }
2367
+ route = {
2368
+ ...route,
2369
+ provider: picked.provider,
2370
+ model: picked.id,
2371
+ preset: null,
2372
+ };
2373
+ return route;
2374
+ }
2375
+
2376
+ async function refreshRouteEffort(modelMetaOverride = null) {
2377
+ await ensureProvidersReady(ensureProviderEnabled(config, route.provider));
2378
+ const modelMeta = modelMetaOverride || await lookupModelMeta(route.provider, route.model);
2379
+ const requested = hasOwn(route, 'effort') ? route.effort : (route.preset?.effort || null);
2380
+ const effectiveEffort = coerceEffortFor(route.provider, modelMeta, requested);
2381
+ const fastCapable = fastCapableFor(route.provider, modelMeta);
2382
+ route = {
2383
+ ...route,
2384
+ fast: fastCapable ? route.fast === true : false,
2385
+ fastCapable,
2386
+ effectiveEffort,
2387
+ effortOptions: effortItemsFor(route.provider, modelMeta, effectiveEffort),
2388
+ };
2389
+ return route;
2390
+ }
2391
+
2392
+ function routeHasModel() {
2393
+ return !!clean(route?.model);
2394
+ }
2395
+
2396
+ function requireModelRoute() {
2397
+ if (routeHasModel()) return;
2398
+ throw new Error('No model configured. Run /providers to authenticate, then /model to choose a model.');
2399
+ }
2400
+
2401
+ async function recreateCurrentSessionIfReady() {
2402
+ if (!routeHasModel()) {
2403
+ session = null;
2404
+ return null;
2405
+ }
2406
+ return await createCurrentSession();
2407
+ }
2408
+
2409
+ async function createCurrentSession(reason = 'demand') {
2410
+ if (sessionCreatePromise) return await sessionCreatePromise;
2411
+ if (session?.id && !sessionNeedsCwdRefresh) {
2412
+ const liveSession = mgr.getSession(session.id);
2413
+ if (liveSession && liveSession.closed !== true && liveSession.status !== 'closed') {
2414
+ session = liveSession;
2415
+ return session;
2416
+ }
2417
+ session = null;
2418
+ }
2419
+
2420
+ const startedAt = performance.now();
2421
+ bootProfile('session:create:start', { mode, reason });
2422
+ const promise = (async () => {
2423
+ ensureConfigForRouteProvider();
2424
+ await resolveMissingRouteModelForFirstTurn();
2425
+ requireModelRoute();
2426
+ bootProfile('session:create:route-ready', { ms: (performance.now() - startedAt).toFixed(1) });
2427
+ await refreshRouteEffort();
2428
+ bootProfile('session:create:effort-ready', { ms: (performance.now() - startedAt).toFixed(1) });
2429
+ const providerImpl = reg.getProvider(route.provider);
2430
+ if (!providerImpl) {
2431
+ throw new Error(`Provider "${route.provider}" is not configured.`);
2432
+ }
2433
+ bootProfile('session:create:provider-ready', { ms: (performance.now() - startedAt).toFixed(1) });
2434
+ const coreMemoryContext = await loadCoreMemoryContext();
2435
+ if (closeRequested) throw new Error('runtime is closing');
2436
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
2437
+ const workflowContext = workflowContextBlock(config, dataDir);
2438
+ const workspaceContext = buildWorkspaceContext();
2439
+ const sessionOpts = {
2440
+ provider: route.provider,
2441
+ model: route.model,
2442
+ preset: route.preset || undefined,
2443
+ tools: toolSpecForMode(mode),
2444
+ owner: 'cli',
2445
+ role: 'lead',
2446
+ lane: 'cli',
2447
+ sourceType: 'lead',
2448
+ sourceName: 'main',
2449
+ clientHostPid: process.pid,
2450
+ disallowedTools: LEAD_DISALLOWED_TOOLS,
2451
+ cwd: currentCwd,
2452
+ coreMemoryContext,
2453
+ workflowContext,
2454
+ workspaceContext,
2455
+ fast: route.fast === true,
2456
+ };
2457
+ if (hasOwn(route, 'effort') || route.effectiveEffort) {
2458
+ sessionOpts.effort = route.effectiveEffort || null;
2459
+ }
2460
+ session = mgr.createSession(sessionOpts);
2461
+ sessionNeedsCwdRefresh = false;
2462
+ Object.defineProperty(session, 'beforeToolHook', {
2463
+ value: (input) => hooks.beforeTool(input),
2464
+ enumerable: false,
2465
+ configurable: true,
2466
+ writable: true,
2467
+ });
2468
+ applyDeferredToolSurface(session, mode, standaloneTools);
2469
+ applyPreSessionToolSelection();
2470
+ statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route));
2471
+ hooks.emit('session:create', { sessionId: session.id, provider: route.provider, model: route.model, toolMode: mode, cwd: currentCwd });
2472
+ bootProfile('session:create:ready', {
2473
+ ms: (performance.now() - startedAt).toFixed(1),
2474
+ reason,
2475
+ tools: Array.isArray(session.tools) ? session.tools.length : 0,
2476
+ catalog: Array.isArray(session.deferredToolCatalog) ? session.deferredToolCatalog.length : 0,
2477
+ });
2478
+ return session;
2479
+ })();
2480
+
2481
+ sessionCreatePromise = promise;
2482
+ try {
2483
+ return await promise;
2484
+ } finally {
2485
+ if (sessionCreatePromise === promise) sessionCreatePromise = null;
2486
+ }
2487
+ }
2488
+
2489
+ function scheduleLeadSessionPrewarm() {
2490
+ if (envFlag('MIXDOG_DISABLE_SESSION_PREWARM')) return;
2491
+ const timer = setTimeout(() => {
2492
+ if (closeRequested || session?.id || sessionCreatePromise || activeTurnCount > 0) return;
2493
+ void createCurrentSession('prewarm')
2494
+ .then(() => bootProfile('session:prewarm:ready'))
2495
+ .catch((error) => bootProfile('session:prewarm:failed', { error: error?.message || String(error) }));
2496
+ }, sessionPrewarmDelayMs);
2497
+ timer.unref?.();
2498
+ }
2499
+
2500
+ function scheduleProviderWarmup(delayMs = providerWarmupDelayMs) {
2501
+ if (envFlag('MIXDOG_DISABLE_PROVIDER_WARMUP')) {
2502
+ bootProfile('providers:warm-skipped');
2503
+ return;
2504
+ }
2505
+ if (providerWarmupTimer || closeRequested) return;
2506
+ providerWarmupTimer = setTimeout(() => {
2507
+ providerWarmupTimer = null;
2508
+ if (closeRequested) return;
2509
+ if (activeTurnCount > 0 || sessionCreatePromise) {
2510
+ bootProfile('providers:warm-deferred', { reason: activeTurnCount > 0 ? 'turn-active' : 'session-create' });
2511
+ scheduleProviderWarmup(backgroundBusyRetryMs);
2512
+ return;
2513
+ }
2514
+ const providersStartedAt = performance.now();
2515
+ try {
2516
+ config = cfgMod.loadConfig();
2517
+ configHasSecrets = true;
2518
+ } catch (error) {
2519
+ bootProfile('config:full-failed', { error: error?.message || String(error) });
2520
+ }
2521
+ void ensureProvidersReady(config.providers || {})
2522
+ .then(() => {
2523
+ bootProfile('providers:init:ready', { ms: (performance.now() - providersStartedAt).toFixed(1) });
2524
+ if (closeRequested) return null;
2525
+ if (activeTurnCount > 0 || sessionCreatePromise) {
2526
+ bootProfile('providers:optional-warm-deferred', { reason: activeTurnCount > 0 ? 'turn-active' : 'session-create' });
2527
+ scheduleProviderWarmup(backgroundBusyRetryMs);
2528
+ return null;
2529
+ }
2530
+ return cachedProviderSetup();
2531
+ })
2532
+ .then((setup) => {
2533
+ if (!setup) return;
2534
+ bootProfile('provider-setup:warm-ready', {
2535
+ api: Array.isArray(setup?.api) ? setup.api.length : 0,
2536
+ oauth: Array.isArray(setup?.oauth) ? setup.oauth.length : 0,
2537
+ local: Array.isArray(setup?.local) ? setup.local.length : 0,
2538
+ });
2539
+ })
2540
+ .catch((error) => bootProfile('providers:warm-failed', { error: error?.message || String(error) }));
2541
+ }, delayMs);
2542
+ providerWarmupTimer.unref?.();
2543
+ }
2544
+
2545
+ function scheduleProviderModelWarmup(delayMs = providerModelWarmupDelayMs) {
2546
+ if (envFlag('MIXDOG_DISABLE_PROVIDER_WARMUP')) return;
2547
+ if (providerModelWarmupTimer || closeRequested) return;
2548
+ providerModelWarmupTimer = setTimeout(() => {
2549
+ providerModelWarmupTimer = null;
2550
+ if (closeRequested || Array.isArray(providerModelsCache.models) || providerModelsPromise) return;
2551
+ if (activeTurnCount > 0 || sessionCreatePromise) {
2552
+ bootProfile('provider-models:warm-deferred', { reason: activeTurnCount > 0 ? 'turn-active' : 'session-create' });
2553
+ scheduleProviderModelWarmup(backgroundBusyRetryMs);
2554
+ return;
2555
+ }
2556
+ warmProviderModelCache();
2557
+ }, delayMs);
2558
+ providerModelWarmupTimer.unref?.();
2559
+ }
2560
+
2561
+ function scheduleChannelStart(delayMs = channelStartDelayMs) {
2562
+ if (envFlag('MIXDOG_DISABLE_CHANNEL_START')) {
2563
+ bootProfile('channels:start-skipped');
2564
+ return;
2565
+ }
2566
+ if (channelStartTimer || closeRequested) return;
2567
+ bootProfile('channels:start-scheduled', { delayMs });
2568
+ channelStartTimer = setTimeout(() => {
2569
+ channelStartTimer = null;
2570
+ if (closeRequested) return;
2571
+ if (activeTurnCount > 0 || sessionCreatePromise) {
2572
+ bootProfile('channels:start-deferred', { reason: activeTurnCount > 0 ? 'turn-active' : 'session-create' });
2573
+ scheduleChannelStart(backgroundBusyRetryMs);
2574
+ return;
2575
+ }
2576
+ const startedAt = performance.now();
2577
+ bootProfile('channels:start:begin');
2578
+ channels.start()
2579
+ .then(() => bootProfile('channels:start:ready', { ms: (performance.now() - startedAt).toFixed(1) }))
2580
+ .catch((error) => bootProfile('channels:start:failed', {
2581
+ ms: (performance.now() - startedAt).toFixed(1),
2582
+ error: error?.message || String(error),
2583
+ }));
2584
+ }, delayMs);
2585
+ channelStartTimer.unref?.();
2586
+ }
2587
+
2588
+ function withTeardownDeadline(promise, ms, fallback = false) {
2589
+ let timer = null;
2590
+ return Promise.race([
2591
+ Promise.resolve(promise),
2592
+ new Promise((resolve) => {
2593
+ timer = setTimeout(() => resolve(fallback), ms);
2594
+ }),
2595
+ ]).finally(() => {
2596
+ if (timer) clearTimeout(timer);
2597
+ });
2598
+ }
2599
+
2600
+ bootProfile('session-runtime:ready', { lazySession: true, prewarmSession: true });
2601
+ scheduleLeadSessionPrewarm();
2602
+ scheduleProviderWarmup();
2603
+ scheduleChannelStart();
2604
+
2605
+ function contextStatusCacheKeyFor({ messages, tools, bridgeMode }) {
2606
+ const compaction = session?.compaction || {};
2607
+ const lastMessage = messages[messages.length - 1] || null;
2608
+ return {
2609
+ session,
2610
+ sessionId: session?.id || null,
2611
+ provider: route.provider,
2612
+ model: route.model,
2613
+ cwd: currentCwd,
2614
+ mode,
2615
+ bridgeMode,
2616
+ messages,
2617
+ messageCount: messages.length,
2618
+ lastMessage,
2619
+ lastMessageRole: lastMessage?.role || null,
2620
+ lastMessageContent: lastMessage?.content || null,
2621
+ tools,
2622
+ toolCount: tools.length,
2623
+ contextWindow: session?.contextWindow || null,
2624
+ rawContextWindow: session?.rawContextWindow || null,
2625
+ effectiveContextWindowPercent: session?.effectiveContextWindowPercent || null,
2626
+ autoCompactTokenLimit: Number(session?.autoCompactTokenLimit || 0),
2627
+ lastContextTokens: Number(session?.lastContextTokens || 0),
2628
+ lastContextTokensUpdatedAt: Number(session?.lastContextTokensUpdatedAt || 0),
2629
+ lastContextTokensStaleAfterCompact: session?.lastContextTokensStaleAfterCompact === true,
2630
+ lastInputTokens: Number(session?.lastInputTokens || 0),
2631
+ lastOutputTokens: Number(session?.lastOutputTokens || 0),
2632
+ lastCachedReadTokens: Number(session?.lastCachedReadTokens || 0),
2633
+ lastCacheWriteTokens: Number(session?.lastCacheWriteTokens || 0),
2634
+ totalInputTokens: Number(session?.totalInputTokens || 0),
2635
+ totalOutputTokens: Number(session?.totalOutputTokens || 0),
2636
+ totalCachedReadTokens: Number(session?.totalCachedReadTokens || 0),
2637
+ totalCacheWriteTokens: Number(session?.totalCacheWriteTokens || 0),
2638
+ compactBoundaryTokens: Number(session?.compactBoundaryTokens || 0),
2639
+ compactionBoundaryTokens: Number(compaction.boundaryTokens || 0),
2640
+ compactionTriggerTokens: Number(compaction.triggerTokens || 0),
2641
+ compactionLastChangedAt: Number(compaction.lastChangedAt || 0),
2642
+ compactionLastCompactAt: Number(compaction.lastCompactAt || 0),
2643
+ };
2644
+ }
2645
+
2646
+ function sameContextStatusCacheKey(a, b) {
2647
+ if (!a || !b) return false;
2648
+ for (const key of Object.keys(a)) {
2649
+ if (!Object.is(a[key], b[key])) return false;
2650
+ }
2651
+ return true;
2652
+ }
2653
+
2654
+ return {
2655
+ get id() {
2656
+ return session?.id || null;
2657
+ },
2658
+ get provider() {
2659
+ return route.provider;
2660
+ },
2661
+ get model() {
2662
+ return route.model;
2663
+ },
2664
+ get effort() {
2665
+ return route.effectiveEffort || route.effort || route.preset?.effort || null;
2666
+ },
2667
+ get fast() {
2668
+ return route.fast === true;
2669
+ },
2670
+ get fastCapable() {
2671
+ return route.fastCapable === true;
2672
+ },
2673
+ get effortOptions() {
2674
+ return route.effortOptions || [];
2675
+ },
2676
+ get contextWindow() {
2677
+ return session?.contextWindow || null;
2678
+ },
2679
+ get rawContextWindow() {
2680
+ return session?.rawContextWindow || session?.contextWindow || null;
2681
+ },
2682
+ get effectiveContextWindowPercent() {
2683
+ return session?.effectiveContextWindowPercent || null;
2684
+ },
2685
+ get toolMode() {
2686
+ return mode;
2687
+ },
2688
+ get bridgeMode() {
2689
+ return bridge.getDefaultMode();
2690
+ },
2691
+ get autoClear() {
2692
+ return normalizeAutoClearConfig(config.autoClear);
2693
+ },
2694
+ get systemShell() {
2695
+ return normalizeSystemShellConfig(config.shell);
2696
+ },
2697
+ get workflow() {
2698
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
2699
+ const pack = loadWorkflowPack(dataDir, activeWorkflowId(config));
2700
+ return pack ? { id: pack.id, name: pack.name, description: pack.description, source: pack.source } : { id: DEFAULT_WORKFLOW_ID, name: 'Default' };
2701
+ },
2702
+ get outputStyle() {
2703
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
2704
+ return outputStyleStatus(dataDir).current;
2705
+ },
2706
+ get cwd() {
2707
+ return currentCwd;
2708
+ },
2709
+ get session() {
2710
+ return session;
2711
+ },
2712
+ contextStatus() {
2713
+ const messages = Array.isArray(session?.messages) ? session.messages : [];
2714
+ const tools = Array.isArray(session?.tools) ? session.tools : [];
2715
+ const bridgeMode = bridge.getDefaultMode();
2716
+ const cacheKey = contextStatusCacheKeyFor({ messages, tools, bridgeMode });
2717
+ if (contextStatusCacheValue && sameContextStatusCacheKey(cacheKey, contextStatusCacheKey)) {
2718
+ return contextStatusCacheValue;
2719
+ }
2720
+
2721
+ const messageSummary = summarizeContextMessages(messages);
2722
+ const toolSchemaTokens = estimateToolSchemaTokens(tools);
2723
+ const requestReserveTokens = estimateRequestReserveTokens(tools);
2724
+ const requestOverheadTokens = Math.max(0, requestReserveTokens - toolSchemaTokens);
2725
+ const rawWindow = Number(session?.rawContextWindow || session?.contextWindow || 0);
2726
+ const effectiveWindow = Number(session?.contextWindow || rawWindow || 0);
2727
+ const lastContextTokens = Number(session?.lastContextTokens || 0);
2728
+ const estimatedContextTokens = messageSummary.estimatedTokens + requestReserveTokens;
2729
+ const compactAt = Number(session?.compaction?.lastChangedAt || session?.compaction?.lastCompactAt || 0);
2730
+ const usageAt = Number(session?.lastContextTokensUpdatedAt || 0);
2731
+ const lastUsageStale = !!lastContextTokens && (
2732
+ session?.lastContextTokensStaleAfterCompact === true
2733
+ || (compactAt > 0 && usageAt > 0 && usageAt <= compactAt)
2734
+ || (compactAt > 0 && usageAt <= 0)
2735
+ );
2736
+ const compactBoundaryTokens = Number(session?.compactBoundaryTokens || session?.compaction?.boundaryTokens || 0);
2737
+ const displayWindow = compactBoundaryTokens || effectiveWindow;
2738
+ const usedTokens = lastUsageStale
2739
+ ? estimatedContextTokens
2740
+ : Math.max(estimatedContextTokens, lastContextTokens || 0);
2741
+ const freeTokens = displayWindow ? Math.max(0, displayWindow - usedTokens) : 0;
2742
+ const autoCompactTokenLimit = Number(session?.autoCompactTokenLimit || 0);
2743
+ const defaultCompactTriggerTokens = compactBoundaryTokens ? Math.max(1, compactBoundaryTokens) : 0;
2744
+ const compactTriggerTokens = autoCompactTokenLimit && compactBoundaryTokens && autoCompactTokenLimit <= compactBoundaryTokens
2745
+ ? autoCompactTokenLimit
2746
+ : Number(session?.compaction?.triggerTokens || defaultCompactTriggerTokens || 0);
2747
+ const compactBufferTokens = Number(session?.compaction?.bufferTokens || (compactBoundaryTokens && compactTriggerTokens ? Math.max(0, compactBoundaryTokens - compactTriggerTokens) : 0));
2748
+ const value = {
2749
+ sessionId: session?.id || null,
2750
+ provider: route.provider,
2751
+ model: route.model,
2752
+ cwd: currentCwd,
2753
+ toolMode: mode,
2754
+ bridgeMode,
2755
+ contextWindow: displayWindow || effectiveWindow || null,
2756
+ effectiveContextWindow: effectiveWindow || null,
2757
+ rawContextWindow: rawWindow || null,
2758
+ effectiveContextWindowPercent: session?.effectiveContextWindowPercent || null,
2759
+ usedTokens,
2760
+ usedSource: lastContextTokens && !lastUsageStale && lastContextTokens >= estimatedContextTokens
2761
+ ? 'last_api_request'
2762
+ : 'estimated',
2763
+ currentEstimatedTokens: estimatedContextTokens,
2764
+ lastApiRequestTokens: lastContextTokens || 0,
2765
+ lastApiRequestStale: lastUsageStale,
2766
+ freeTokens,
2767
+ compaction: {
2768
+ ...(session?.compaction || {}),
2769
+ boundaryTokens: compactBoundaryTokens || null,
2770
+ triggerTokens: compactTriggerTokens || null,
2771
+ bufferTokens: compactBufferTokens || null,
2772
+ currentEstimatedTokens: estimatedContextTokens,
2773
+ lastApiRequestTokens: lastContextTokens || 0,
2774
+ lastApiRequestStale: lastUsageStale,
2775
+ },
2776
+ messages: messageSummary,
2777
+ request: {
2778
+ toolSchemaTokens,
2779
+ requestOverheadTokens,
2780
+ reserveTokens: requestReserveTokens,
2781
+ },
2782
+ usage: {
2783
+ lastInputTokens: Number(session?.lastInputTokens || 0),
2784
+ lastOutputTokens: Number(session?.lastOutputTokens || 0),
2785
+ lastCachedReadTokens: Number(session?.lastCachedReadTokens || 0),
2786
+ lastCacheWriteTokens: Number(session?.lastCacheWriteTokens || 0),
2787
+ lastContextTokens,
2788
+ totalInputTokens: Number(session?.totalInputTokens || 0),
2789
+ totalOutputTokens: Number(session?.totalOutputTokens || 0),
2790
+ totalCachedReadTokens: Number(session?.totalCachedReadTokens || 0),
2791
+ totalCacheWriteTokens: Number(session?.totalCacheWriteTokens || 0),
2792
+ },
2793
+ };
2794
+ contextStatusCacheKey = cacheKey;
2795
+ contextStatusCacheValue = value;
2796
+ return value;
2797
+ },
2798
+ listProviders() {
2799
+ return renderProviderStatus(cfgMod.loadConfig());
2800
+ },
2801
+ async getProviderSetup() {
2802
+ return await cachedProviderSetup();
2803
+ },
2804
+ async getUsageDashboard(options = {}) {
2805
+ const nextConfig = cfgMod.loadConfig();
2806
+ return await createUsageDashboard(nextConfig, {
2807
+ ...(options || {}),
2808
+ setup: await cachedProviderSetup(),
2809
+ getProvider: (providerId) => reg.getProvider(providerId),
2810
+ log: (message) => {
2811
+ if (process.env.MIXDOG_USAGE_TRACE) {
2812
+ try { process.stderr.write(`[usage] ${message}\n`); } catch {}
2813
+ }
2814
+ },
2815
+ });
2816
+ },
2817
+ getOnboardingStatus() {
2818
+ const nextConfig = cfgMod.loadConfig();
2819
+ return {
2820
+ completed: nextConfig?.onboarding?.completed === true,
2821
+ version: nextConfig?.onboarding?.version || 0,
2822
+ default: nextConfig?.default || null,
2823
+ workflowRoutes: summarizeWorkflowRoutes(nextConfig),
2824
+ };
2825
+ },
2826
+ getAutoClear() {
2827
+ return normalizeAutoClearConfig(config.autoClear);
2828
+ },
2829
+ getSystemShell() {
2830
+ return normalizeSystemShellConfig(config.shell);
2831
+ },
2832
+ setSystemShell(input = {}) {
2833
+ const command = normalizeSystemShellCommand(typeof input === 'string' ? input : input?.command);
2834
+ const nextConfig = cfgMod.loadConfig();
2835
+ cfgMod.saveConfig({
2836
+ ...nextConfig,
2837
+ shell: command ? { ...(nextConfig.shell || {}), command } : {},
2838
+ });
2839
+ config = cfgMod.loadConfig();
2840
+ setConfiguredShell(command);
2841
+ return normalizeSystemShellConfig(config.shell);
2842
+ },
2843
+ setAutoClear(input = {}) {
2844
+ const current = normalizeAutoClearConfig(config.autoClear);
2845
+ const next = { ...current };
2846
+ if (hasOwn(input, 'enabled')) next.enabled = input.enabled !== false;
2847
+ if (hasOwn(input, 'idleMs')) {
2848
+ const idleMs = Number(input.idleMs);
2849
+ if (!Number.isFinite(idleMs) || idleMs <= 0) throw new Error('autoclear idleMs must be a positive number');
2850
+ next.idleMs = Math.max(60_000, Math.round(idleMs));
2851
+ }
2852
+ if (hasOwn(input, 'duration')) {
2853
+ const idleMs = parseDurationMs(input.duration);
2854
+ if (!idleMs) throw new Error('usage: /autoclear [on|off|status|<minutes|1h|90m>]');
2855
+ next.idleMs = idleMs;
2856
+ if (!hasOwn(input, 'enabled')) next.enabled = true;
2857
+ }
2858
+ const nextConfig = cfgMod.loadConfig();
2859
+ cfgMod.saveConfig({ ...nextConfig, autoClear: next });
2860
+ config = cfgMod.loadConfig();
2861
+ return { ...normalizeAutoClearConfig(config.autoClear), label: formatDurationMs(normalizeAutoClearConfig(config.autoClear).idleMs) };
2862
+ },
2863
+ async completeOnboarding(payload = {}) {
2864
+ const defaultRoute = normalizeWorkflowRoute(payload.defaultRoute, route);
2865
+ const workflowInput = payload.workflowRoutes && typeof payload.workflowRoutes === 'object'
2866
+ ? payload.workflowRoutes
2867
+ : {};
2868
+ const nextConfig = cfgMod.loadConfig();
2869
+ let presets = Array.isArray(nextConfig.presets) ? nextConfig.presets.slice() : [];
2870
+ const workflowRoutes = { ...(nextConfig.workflowRoutes || {}) };
2871
+
2872
+ if (defaultRoute) {
2873
+ presets = upsertWorkflowPreset(presets, 'lead', defaultRoute);
2874
+ workflowRoutes.lead = defaultRoute;
2875
+ nextConfig.default = workflowPresetId('lead');
2876
+ }
2877
+
2878
+ for (const slot of WORKFLOW_ROUTE_SLOTS) {
2879
+ const normalized = normalizeWorkflowRoute(workflowInput[slot]);
2880
+ if (!normalized) continue;
2881
+ workflowRoutes[slot] = normalized;
2882
+ presets = upsertWorkflowPreset(presets, slot, normalized);
2883
+ }
2884
+
2885
+ nextConfig.presets = presets;
2886
+ nextConfig.workflowRoutes = workflowRoutes;
2887
+ nextConfig.maintenance = {
2888
+ ...(nextConfig.maintenance || {}),
2889
+ explore: workflowRoutes.explorer ? workflowPresetId('explorer') : (nextConfig.maintenance?.explore || 'haiku'),
2890
+ memory: workflowRoutes.memory ? workflowPresetId('memory') : (nextConfig.maintenance?.memory || 'haiku'),
2891
+ };
2892
+ nextConfig.onboarding = {
2893
+ ...(nextConfig.onboarding || {}),
2894
+ completed: true,
2895
+ version: ONBOARDING_VERSION,
2896
+ completedAt: new Date().toISOString(),
2897
+ };
2898
+
2899
+ cfgMod.saveConfig(nextConfig);
2900
+ config = cfgMod.loadConfig();
2901
+ if (defaultRoute) {
2902
+ route = resolveRoute(config, { provider: defaultRoute.provider, model: defaultRoute.model, effort: defaultRoute.effort });
2903
+ if (session?.id) mgr.closeSession(session.id, 'cli-onboarding-complete');
2904
+ await recreateCurrentSessionIfReady();
2905
+ }
2906
+ return this.getOnboardingStatus();
2907
+ },
2908
+ getChannelSetup() {
2909
+ return channelSetup();
2910
+ },
2911
+ getChannelWorkerStatus() {
2912
+ return channels.status();
2913
+ },
2914
+ saveDiscordToken(token) {
2915
+ const result = saveDiscordToken(token);
2916
+ reloadChannelsSoon();
2917
+ return result;
2918
+ },
2919
+ forgetDiscordToken() {
2920
+ const result = forgetDiscordToken();
2921
+ reloadChannelsSoon();
2922
+ return result;
2923
+ },
2924
+ saveWebhookAuthtoken(token) {
2925
+ const result = saveWebhookAuthtoken(token);
2926
+ reloadChannelsSoon();
2927
+ return result;
2928
+ },
2929
+ forgetWebhookAuthtoken() {
2930
+ const result = forgetWebhookAuthtoken();
2931
+ reloadChannelsSoon();
2932
+ return result;
2933
+ },
2934
+ saveChannel(entry) {
2935
+ const result = saveChannel(entry);
2936
+ reloadChannelsSoon();
2937
+ return result;
2938
+ },
2939
+ deleteChannel(name) {
2940
+ const result = deleteChannel(name);
2941
+ reloadChannelsSoon();
2942
+ return result;
2943
+ },
2944
+ setWebhookConfig(patch) {
2945
+ const result = setWebhookConfig(patch);
2946
+ reloadChannelsSoon();
2947
+ return result;
2948
+ },
2949
+ saveSchedule(entry) {
2950
+ const result = saveSchedule(entry);
2951
+ reloadChannelsSoon();
2952
+ return result;
2953
+ },
2954
+ deleteSchedule(name) {
2955
+ const result = deleteSchedule(name);
2956
+ reloadChannelsSoon();
2957
+ return result;
2958
+ },
2959
+ setScheduleEnabled(name, enabled) {
2960
+ const result = setScheduleEnabled(name, enabled);
2961
+ reloadChannelsSoon();
2962
+ return result;
2963
+ },
2964
+ saveWebhook(entry) {
2965
+ const result = saveWebhook(entry);
2966
+ reloadChannelsSoon();
2967
+ return result;
2968
+ },
2969
+ deleteWebhook(name) {
2970
+ const result = deleteWebhook(name);
2971
+ reloadChannelsSoon();
2972
+ return result;
2973
+ },
2974
+ setWebhookEnabled(name, enabled) {
2975
+ const result = setWebhookEnabled(name, enabled);
2976
+ reloadChannelsSoon();
2977
+ return result;
2978
+ },
2979
+ async authenticateProvider(providerId, secret) {
2980
+ const result = String(secret || '').trim()
2981
+ ? saveProviderApiKey(cfgMod, providerId, secret)
2982
+ : await loginOAuthProvider(cfgMod, providerId);
2983
+ config = cfgMod.loadConfig();
2984
+ invalidateProviderCaches();
2985
+ warmProviderModelCache();
2986
+ return result;
2987
+ },
2988
+ async loginOAuthProvider(providerId) {
2989
+ const result = await loginOAuthProvider(cfgMod, providerId);
2990
+ config = cfgMod.loadConfig();
2991
+ invalidateProviderCaches();
2992
+ warmProviderModelCache();
2993
+ return result;
2994
+ },
2995
+ async beginOAuthProviderLogin(providerId) {
2996
+ const result = await beginOAuthProviderLogin(cfgMod, providerId);
2997
+ config = cfgMod.loadConfig();
2998
+ return {
2999
+ ...result,
3000
+ completeCode: async (code) => {
3001
+ const completed = await result.completeCode(code);
3002
+ config = cfgMod.loadConfig();
3003
+ invalidateProviderCaches();
3004
+ warmProviderModelCache();
3005
+ return completed;
3006
+ },
3007
+ };
3008
+ },
3009
+ saveProviderApiKey(providerId, secret) {
3010
+ const result = saveProviderApiKey(cfgMod, providerId, secret);
3011
+ config = cfgMod.loadConfig();
3012
+ invalidateProviderCaches();
3013
+ warmProviderModelCache();
3014
+ return result;
3015
+ },
3016
+ saveOpenAIUsageSessionKey(secret) {
3017
+ const result = saveOpenAIUsageSessionKey(cfgMod, secret);
3018
+ config = cfgMod.loadConfig();
3019
+ invalidateProviderCaches();
3020
+ return result;
3021
+ },
3022
+ saveOpenCodeGoUsageAuth(opts) {
3023
+ const result = saveOpenCodeGoUsageAuth(cfgMod, opts);
3024
+ config = cfgMod.loadConfig();
3025
+ invalidateProviderCaches();
3026
+ return result;
3027
+ },
3028
+ setLocalProvider(providerId, opts) {
3029
+ const result = setLocalProvider(cfgMod, providerId, opts);
3030
+ config = cfgMod.loadConfig();
3031
+ invalidateProviderCaches();
3032
+ warmProviderModelCache();
3033
+ return result;
3034
+ },
3035
+ forgetProviderAuth(providerId) {
3036
+ const result = forgetProviderAuth(providerId);
3037
+ config = cfgMod.loadConfig();
3038
+ invalidateProviderCaches();
3039
+ warmProviderModelCache();
3040
+ return result;
3041
+ },
3042
+ listPresets() {
3043
+ return cfgMod.listPresets(cfgMod.loadConfig());
3044
+ },
3045
+ async listProviderModels(options = {}) {
3046
+ return await collectProviderModels({ force: options.force === true || options.refresh === true });
3047
+ },
3048
+ listAgents() {
3049
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3050
+ return FIXED_AGENT_SLOTS.map((agent) => ({
3051
+ ...agent,
3052
+ locked: true,
3053
+ route: agentRouteFromConfig(config, agent.id, dataDir),
3054
+ definition: loadAgentDefinition(dataDir, agent.id),
3055
+ }));
3056
+ },
3057
+ listWorkflows() {
3058
+ const currentConfig = cfgMod.loadConfig();
3059
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3060
+ const active = activeWorkflowId(currentConfig);
3061
+ return listWorkflowPacks(dataDir).map((workflow) => ({
3062
+ id: workflow.id,
3063
+ name: workflow.name,
3064
+ description: workflow.description,
3065
+ source: workflow.source,
3066
+ active: workflow.id === active,
3067
+ agents: workflow.agents,
3068
+ }));
3069
+ },
3070
+ getOutputStyle() {
3071
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3072
+ return outputStyleStatus(dataDir);
3073
+ },
3074
+ listOutputStyles() {
3075
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3076
+ return outputStyleStatus(dataDir);
3077
+ },
3078
+ async setOutputStyle(value) {
3079
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3080
+ const before = outputStyleStatus(dataDir);
3081
+ const selected = findOutputStyle(value, before.styles);
3082
+ if (!selected) {
3083
+ const names = before.styles.map((style) => style.label || style.id).join(', ') || 'Default';
3084
+ throw new Error(`output style must be one of ${names}`);
3085
+ }
3086
+ if (typeof sharedCfgMod.updateConfig !== 'function') throw new Error('output style config writer unavailable');
3087
+ sharedCfgMod.updateConfig((root) => {
3088
+ const next = { ...(root || {}), outputStyle: selected.id };
3089
+ if (next.agent && typeof next.agent === 'object' && !Array.isArray(next.agent)) {
3090
+ const agent = { ...next.agent };
3091
+ delete agent.outputStyle;
3092
+ next.agent = agent;
3093
+ }
3094
+ return next;
3095
+ });
3096
+ const hasConversation = sessionHasConversationMessages(session);
3097
+ let appliedToCurrentSession = !hasConversation;
3098
+ if (session?.id && !hasConversation) {
3099
+ mgr.closeSession(session.id, 'cli-output-style-switch');
3100
+ session = null;
3101
+ await recreateCurrentSessionIfReady();
3102
+ }
3103
+ invalidateContextStatusCache();
3104
+ return { ...outputStyleStatus(dataDir), appliedToCurrentSession };
3105
+ },
3106
+ async setWorkflow(workflowId) {
3107
+ const id = normalizeWorkflowId(workflowId, DEFAULT_WORKFLOW_ID);
3108
+ const dataDir = cfgMod.getPluginData?.() || STANDALONE_DATA_DIR;
3109
+ const pack = loadWorkflowPack(dataDir, id);
3110
+ if (!pack || pack.id !== id) throw new Error(`workflow "${workflowId}" not found`);
3111
+ const nextConfig = cfgMod.loadConfig();
3112
+ nextConfig.workflow = { ...(nextConfig.workflow || {}), active: id };
3113
+ cfgMod.saveConfig(nextConfig);
3114
+ config = cfgMod.loadConfig();
3115
+ if (session?.id) {
3116
+ mgr.closeSession(session.id, 'cli-workflow-switch');
3117
+ session = null;
3118
+ }
3119
+ await recreateCurrentSessionIfReady();
3120
+ return { id: pack.id, name: pack.name, description: pack.description, source: pack.source };
3121
+ },
3122
+ async setAgentRoute(agentId, next) {
3123
+ const id = normalizeAgentId(agentId);
3124
+ if (!id) throw new Error(`unknown agent "${agentId}"`);
3125
+ let selectedRoute = resolveRoute(config, { ...(next || {}) });
3126
+ await reg.initProviders(ensureProviderEnabled(config, selectedRoute.provider));
3127
+ const modelMeta = await lookupModelMeta(selectedRoute.provider, selectedRoute.model);
3128
+ const fastCapable = fastCapableFor(selectedRoute.provider, modelMeta);
3129
+ selectedRoute = { ...selectedRoute, fast: fastCapable ? selectedRoute.fast === true : false };
3130
+ config = saveModelSettings(cfgMod, selectedRoute, { fastCapable });
3131
+
3132
+ const routeToSave = normalizeWorkflowRoute(selectedRoute);
3133
+ if (!routeToSave) throw new Error('agent route requires provider and model');
3134
+ const agent = FIXED_AGENT_SLOTS.find((item) => item.id === id);
3135
+ const nextConfig = cfgMod.loadConfig();
3136
+ nextConfig.agents = {
3137
+ ...(nextConfig.agents || {}),
3138
+ [id]: routeToSave,
3139
+ };
3140
+ nextConfig.presets = upsertWorkflowPreset(nextConfig.presets, agentPresetSlot(id), routeToSave);
3141
+ if (agent?.workflowSlot) {
3142
+ nextConfig.workflowRoutes = {
3143
+ ...(nextConfig.workflowRoutes || {}),
3144
+ [agent.workflowSlot]: routeToSave,
3145
+ };
3146
+ nextConfig.presets = upsertWorkflowPreset(nextConfig.presets, agent.workflowSlot, routeToSave);
3147
+ nextConfig.maintenance = {
3148
+ ...(nextConfig.maintenance || {}),
3149
+ ...(id === 'explore' ? { explore: workflowPresetId('explorer') } : {}),
3150
+ ...(id === 'maintainer' ? { memory: workflowPresetId('memory') } : {}),
3151
+ };
3152
+ }
3153
+ cfgMod.saveConfig(nextConfig);
3154
+ config = cfgMod.loadConfig();
3155
+ return routeToSave;
3156
+ },
3157
+ async ask(prompt, options = {}) {
3158
+ activeTurnCount += 1;
3159
+ const startedAt = Date.now();
3160
+ try {
3161
+ await refreshSessionForCwdIfNeeded('cwd-change');
3162
+ if (!session?.id) await createCurrentSession('turn');
3163
+ hooks.emit('turn:start', { sessionId: session.id, prompt, cwd: currentCwd });
3164
+ const turnContext = [options.context || ''].map((part) => String(part || '').trim()).filter(Boolean).join('\n\n');
3165
+ const result = await mgr.askSession(
3166
+ session.id,
3167
+ prompt,
3168
+ turnContext || null,
3169
+ async (iter, calls) => {
3170
+ for (const call of calls || []) {
3171
+ hooks.emit('tool:planned', {
3172
+ sessionId: session.id,
3173
+ name: call?.name || 'tool',
3174
+ callId: call?.id || null,
3175
+ });
3176
+ }
3177
+ if (typeof options.onToolCall === 'function') {
3178
+ return await options.onToolCall(iter, calls);
3179
+ }
3180
+ return undefined;
3181
+ },
3182
+ currentCwd,
3183
+ options.prefetch || null,
3184
+ {
3185
+ onTextDelta: options.onTextDelta,
3186
+ onReasoningDelta: options.onReasoningDelta,
3187
+ onUsageDelta: options.onUsageDelta,
3188
+ onToolResult: options.onToolResult,
3189
+ onStageChange: options.onStageChange,
3190
+ onStreamDelta: options.onStreamDelta,
3191
+ drainSteering: options.drainSteering,
3192
+ onSteerMessage: options.onSteerMessage,
3193
+ },
3194
+ );
3195
+ session = mgr.getSession(session.id) || session;
3196
+ hooks.emit('turn:end', { sessionId: session.id, elapsedMs: Date.now() - startedAt });
3197
+ return { result, session };
3198
+ } catch (error) {
3199
+ hooks.emit('turn:error', { sessionId: session?.id || null, elapsedMs: Date.now() - startedAt, error: error?.message || String(error) });
3200
+ throw error;
3201
+ } finally {
3202
+ activeTurnCount = Math.max(0, activeTurnCount - 1);
3203
+ if (!firstTurnCompleted) {
3204
+ firstTurnCompleted = true;
3205
+ scheduleProviderModelWarmup();
3206
+ }
3207
+ }
3208
+ },
3209
+ async clear(options = {}) {
3210
+ if (!session?.id) return false;
3211
+ const cleared = await mgr.clearSessionMessages(session.id);
3212
+ if (!cleared) return false;
3213
+ session = typeof cleared === 'object' ? cleared : (mgr.getSession(session.id) || session);
3214
+ if (options.recoverBridge === true) {
3215
+ try { bridge.recoverWorkers?.({ clientHostPid: session?.clientHostPid || process.pid }); } catch {}
3216
+ }
3217
+ invalidateContextStatusCache();
3218
+ return true;
3219
+ },
3220
+ async compact(options = {}) {
3221
+ if (!session?.id) return null;
3222
+ const result = await mgr.compactSessionMessages(session.id);
3223
+ session = mgr.getSession(session.id) || session;
3224
+ if (options.recoverBridge === true) {
3225
+ try { bridge.recoverWorkers?.({ clientHostPid: session?.clientHostPid || process.pid }); } catch {}
3226
+ }
3227
+ invalidateContextStatusCache();
3228
+ return result;
3229
+ },
3230
+ async setToolMode(nextMode) {
3231
+ mode = normalizeToolMode(nextMode);
3232
+ invalidatePreSessionToolSurface();
3233
+ if (session?.id) mgr.closeSession(session.id, 'cli-mode-switch');
3234
+ await recreateCurrentSessionIfReady();
3235
+ return mode;
3236
+ },
3237
+ setBridgeMode(nextMode) {
3238
+ const applied = bridge.setDefaultMode(nextMode);
3239
+ try { sharedCfgMod.updateSection('agent', (s) => ({ ...(s || {}), bridgeMode: applied })); } catch {}
3240
+ return applied;
3241
+ },
3242
+ toggleBridgeMode() {
3243
+ const applied = bridge.toggleDefaultMode();
3244
+ try { sharedCfgMod.updateSection('agent', (s) => ({ ...(s || {}), bridgeMode: applied })); } catch {}
3245
+ return applied;
3246
+ },
3247
+ bridgeStatus() {
3248
+ return bridgeStatusState();
3249
+ },
3250
+ get clientHostPid() {
3251
+ return session?.clientHostPid || process.pid;
3252
+ },
3253
+ bridgeControl(args = {}) {
3254
+ const callerSessionId = session?.id || null;
3255
+ return bridge.execute(args, {
3256
+ callerCwd: currentCwd,
3257
+ invocationSource: 'user-command',
3258
+ callerSessionId,
3259
+ clientHostPid: session?.clientHostPid || process.pid,
3260
+ notifyFn: notifyFnForSession(callerSessionId),
3261
+ });
3262
+ },
3263
+ onNotification(listener) {
3264
+ if (typeof listener !== 'function') return () => {};
3265
+ notificationListeners.add(listener);
3266
+ return () => notificationListeners.delete(listener);
3267
+ },
3268
+ toolsStatus(query = '') {
3269
+ const surface = activeToolSurface();
3270
+ const catalog = Array.isArray(surface?.deferredToolCatalog)
3271
+ ? surface.deferredToolCatalog
3272
+ : (Array.isArray(surface?.tools) ? surface.tools : []);
3273
+ const activeNames = new Set((surface?.tools || []).map((tool) => tool?.name).filter(Boolean));
3274
+ const needle = clean(query).toLowerCase();
3275
+ const rows = catalog.map((tool) => toolRow(tool, activeNames)).filter((row) => row.name);
3276
+ const tools = needle
3277
+ ? rows.filter((row) => toolSearchMatches(row, needle))
3278
+ : rows;
3279
+ return {
3280
+ mode,
3281
+ count: rows.length,
3282
+ activeCount: rows.filter((row) => row.active).length,
3283
+ tools,
3284
+ activeTools: sortedNamesByMeasuredUsage(activeNames),
3285
+ };
3286
+ },
3287
+ selectTools(names) {
3288
+ const list = Array.isArray(names) ? names : String(names || '').split(/[,\s]+/);
3289
+ const result = selectDeferredTools(activeToolSurface(), list, mode);
3290
+ return { ...result, status: this.toolsStatus() };
3291
+ },
3292
+ setCwd(path) {
3293
+ applyResolvedCwd(resolveCwdPath(currentCwd, path));
3294
+ return currentCwd;
3295
+ },
3296
+ mcpStatus() {
3297
+ return mcpStatus();
3298
+ },
3299
+ async reconnectMcp() {
3300
+ config = cfgMod.loadConfig();
3301
+ const status = await connectConfiguredMcp({ reset: true });
3302
+ invalidatePreSessionToolSurface();
3303
+ if (session?.id) mgr.closeSession(session.id, 'cli-mcp-reconnect');
3304
+ await recreateCurrentSessionIfReady();
3305
+ return status;
3306
+ },
3307
+ async addMcpServer(input = {}) {
3308
+ const { name, config: serverConfig } = normalizeMcpServerInput(input);
3309
+ const nextConfig = cfgMod.loadConfig();
3310
+ nextConfig.mcpServers = {
3311
+ ...(nextConfig.mcpServers || {}),
3312
+ [name]: serverConfig,
3313
+ };
3314
+ cfgMod.saveConfig(nextConfig);
3315
+ config = cfgMod.loadConfig();
3316
+ const status = await connectConfiguredMcp({ reset: true });
3317
+ invalidatePreSessionToolSurface();
3318
+ if (session?.id) mgr.closeSession(session.id, 'cli-mcp-add');
3319
+ await recreateCurrentSessionIfReady();
3320
+ return { name, status };
3321
+ },
3322
+ async removeMcpServer(name) {
3323
+ const serverName = clean(name);
3324
+ if (!serverName) throw new Error('MCP server name is required');
3325
+ const nextConfig = cfgMod.loadConfig();
3326
+ const current = nextConfig.mcpServers && typeof nextConfig.mcpServers === 'object'
3327
+ ? { ...nextConfig.mcpServers }
3328
+ : {};
3329
+ if (!Object.prototype.hasOwnProperty.call(current, serverName)) {
3330
+ throw new Error(`MCP server not configured: ${serverName}`);
3331
+ }
3332
+ delete current[serverName];
3333
+ cfgMod.saveConfig({ ...nextConfig, mcpServers: current });
3334
+ config = cfgMod.loadConfig();
3335
+ const status = await connectConfiguredMcp({ reset: true });
3336
+ invalidatePreSessionToolSurface();
3337
+ if (session?.id) mgr.closeSession(session.id, 'cli-mcp-remove');
3338
+ await recreateCurrentSessionIfReady();
3339
+ return status;
3340
+ },
3341
+ async setMcpServerEnabled(name, enabled) {
3342
+ const serverName = clean(name);
3343
+ if (!serverName) throw new Error('MCP server name is required');
3344
+ const nextConfig = cfgMod.loadConfig();
3345
+ const current = nextConfig.mcpServers && typeof nextConfig.mcpServers === 'object'
3346
+ ? { ...nextConfig.mcpServers }
3347
+ : {};
3348
+ if (!Object.prototype.hasOwnProperty.call(current, serverName)) {
3349
+ throw new Error(`MCP server not configured: ${serverName}`);
3350
+ }
3351
+ current[serverName] = { ...(current[serverName] || {}), enabled: enabled !== false };
3352
+ cfgMod.saveConfig({ ...nextConfig, mcpServers: current });
3353
+ config = cfgMod.loadConfig();
3354
+ const status = await connectConfiguredMcp({ reset: true });
3355
+ invalidatePreSessionToolSurface();
3356
+ if (session?.id) mgr.closeSession(session.id, 'cli-mcp-toggle');
3357
+ await recreateCurrentSessionIfReady();
3358
+ return status;
3359
+ },
3360
+ skillsStatus() {
3361
+ return skillsStatus();
3362
+ },
3363
+ skillContent(name) {
3364
+ return skillContent(name);
3365
+ },
3366
+ async addSkill(input = {}) {
3367
+ const skill = addProjectSkill(input);
3368
+ if (session?.id) mgr.closeSession(session.id, 'cli-skill-add');
3369
+ await recreateCurrentSessionIfReady();
3370
+ return { skill, status: skillsStatus() };
3371
+ },
3372
+ async reloadSkills() {
3373
+ if (session?.id) mgr.closeSession(session.id, 'cli-skills-reload');
3374
+ await recreateCurrentSessionIfReady();
3375
+ return skillsStatus();
3376
+ },
3377
+ pluginsStatus() {
3378
+ return pluginsStatus();
3379
+ },
3380
+ async reloadPlugins() {
3381
+ if (session?.id) mgr.closeSession(session.id, 'cli-plugins-reload');
3382
+ await recreateCurrentSessionIfReady();
3383
+ return pluginsStatus();
3384
+ },
3385
+ async addPlugin(source) {
3386
+ const dataDir = cfgMod.getPluginData?.();
3387
+ const plugin = registryAddPlugin(source, { dataDir });
3388
+ if (session?.id) mgr.closeSession(session.id, 'cli-plugin-add');
3389
+ await recreateCurrentSessionIfReady();
3390
+ return { plugin, status: pluginsStatus() };
3391
+ },
3392
+ async updatePlugin(plugin = {}) {
3393
+ const key = clean(plugin.id || plugin.name || plugin);
3394
+ const dataDir = cfgMod.getPluginData?.();
3395
+ const updated = registryUpdatePlugin(key, { dataDir });
3396
+ if (session?.id) mgr.closeSession(session.id, 'cli-plugin-update');
3397
+ await recreateCurrentSessionIfReady();
3398
+ return { plugin: updated, status: pluginsStatus() };
3399
+ },
3400
+ async removePlugin(plugin = {}) {
3401
+ const key = clean(plugin.id || plugin.name || plugin);
3402
+ const dataDir = cfgMod.getPluginData?.();
3403
+ const removed = registryRemovePlugin(key, { dataDir });
3404
+ const nextConfig = cfgMod.loadConfig();
3405
+ const serverName = pluginMcpServerName(plugin);
3406
+ if (nextConfig.mcpServers && Object.prototype.hasOwnProperty.call(nextConfig.mcpServers, serverName)) {
3407
+ const current = { ...nextConfig.mcpServers };
3408
+ delete current[serverName];
3409
+ cfgMod.saveConfig({ ...nextConfig, mcpServers: current });
3410
+ config = cfgMod.loadConfig();
3411
+ await connectConfiguredMcp({ reset: true });
3412
+ invalidatePreSessionToolSurface();
3413
+ }
3414
+ if (session?.id) mgr.closeSession(session.id, 'cli-plugin-remove');
3415
+ await recreateCurrentSessionIfReady();
3416
+ return { plugin: removed, status: pluginsStatus() };
3417
+ },
3418
+ async enablePluginMcp(plugin = {}) {
3419
+ const root = clean(plugin.root);
3420
+ const script = clean(plugin.mcpScript);
3421
+ if (!root || !script) throw new Error('plugin has no MCP script');
3422
+ const scriptPath = join(root, script);
3423
+ if (!existsSync(scriptPath)) throw new Error(`plugin MCP script not found: ${scriptPath}`);
3424
+ const serverName = pluginMcpServerName(plugin);
3425
+ const nextConfig = cfgMod.loadConfig();
3426
+ nextConfig.mcpServers = {
3427
+ ...(nextConfig.mcpServers || {}),
3428
+ [serverName]: {
3429
+ command: 'node',
3430
+ args: [scriptPath],
3431
+ cwd: root,
3432
+ env: {
3433
+ MIXDOG_PLUGIN_ROOT: root,
3434
+ MIXDOG_PLUGIN_DATA: join(cfgMod.getPluginData?.() || STANDALONE_DATA_DIR, 'plugins', 'data', clean(plugin.id || plugin.name || serverName)),
3435
+ },
3436
+ },
3437
+ };
3438
+ cfgMod.saveConfig(nextConfig);
3439
+ config = cfgMod.loadConfig();
3440
+ const status = await connectConfiguredMcp({ reset: true });
3441
+ invalidatePreSessionToolSurface();
3442
+ if (session?.id) mgr.closeSession(session.id, 'cli-plugin-mcp-enable');
3443
+ await recreateCurrentSessionIfReady();
3444
+ return { serverName, status };
3445
+ },
3446
+ hooksStatus() {
3447
+ return hooks.status();
3448
+ },
3449
+ addHookRule(rule) {
3450
+ return hooks.addRule(rule);
3451
+ },
3452
+ setHookRuleEnabled(index, enabled) {
3453
+ return hooks.setRuleEnabled(index, enabled);
3454
+ },
3455
+ deleteHookRule(index) {
3456
+ return hooks.deleteRule(index);
3457
+ },
3458
+ async memoryControl(args = {}) {
3459
+ const memoryMod = await getMemoryModule();
3460
+ if (!memoryMod?.handleToolCall) throw new Error('memory runtime is not available');
3461
+ return toolResponseText(await memoryMod.handleToolCall('memory', args || {}));
3462
+ },
3463
+ async recall(query, args = {}) {
3464
+ const baseQuery = query || args?.query || '';
3465
+ if (args?.currentSession !== false && session?.id) {
3466
+ const currentText = currentSessionRecallRows(session, baseQuery, { limit: args?.limit });
3467
+ if (!isEmptyRecallText(currentText)) return currentText;
3468
+ }
3469
+ const memoryMod = await getMemoryModule();
3470
+ if (!memoryMod?.handleToolCall) throw new Error('memory runtime is not available');
3471
+ const baseArgs = {
3472
+ ...(args || {}),
3473
+ query: baseQuery,
3474
+ cwd: args?.cwd || currentCwd,
3475
+ };
3476
+ let result = '(no results)';
3477
+ if (session?.id && args?.currentSession !== false && args?.forceCycleOnEmpty !== false) {
3478
+ const messages = Array.isArray(session.messages) ? session.messages : [];
3479
+ if (messages.length > 0) {
3480
+ await memoryMod.handleToolCall('memory', {
3481
+ action: 'ingest_session',
3482
+ sessionId: session.id,
3483
+ cwd: currentCwd,
3484
+ messages,
3485
+ });
3486
+ await memoryMod.handleToolCall('memory', {
3487
+ action: 'cycle1',
3488
+ min_batch: 1,
3489
+ session_cap: 1,
3490
+ batch_size: Math.max(1, Math.min(100, messages.length)),
3491
+ });
3492
+ result = toolResponseText(await memoryMod.handleToolCall('recall', {
3493
+ ...baseArgs,
3494
+ sessionId: session.id,
3495
+ currentSession: true,
3496
+ projectScope: baseArgs.projectScope || 'all',
3497
+ includeRaw: baseArgs.includeRaw !== false,
3498
+ includeArchived: baseArgs.includeArchived !== false,
3499
+ }));
3500
+ }
3501
+ }
3502
+ if (isEmptyRecallText(result)) {
3503
+ result = toolResponseText(await memoryMod.handleToolCall('recall', baseArgs));
3504
+ }
3505
+ return result;
3506
+ },
3507
+ async setRoute(next) {
3508
+ const requested = { ...(next || {}) };
3509
+ if (requested.effort === undefined && !requested.provider && !requested.model && hasOwn(route, 'effort')) {
3510
+ requested.effort = route.effort;
3511
+ }
3512
+ if (!requested.provider && requested.model && !findPreset(config, requested.model)) {
3513
+ requested.provider = route.provider;
3514
+ }
3515
+ let selectedRoute = resolveRoute(config, requested);
3516
+ await reg.initProviders(ensureProviderEnabled(config, selectedRoute.provider));
3517
+ const modelMeta = await lookupModelMeta(selectedRoute.provider, selectedRoute.model);
3518
+ const fastCapable = fastCapableFor(selectedRoute.provider, modelMeta);
3519
+ selectedRoute = { ...selectedRoute, fast: fastCapable ? selectedRoute.fast === true : false };
3520
+ config = saveModelSettings(cfgMod, selectedRoute, { fastCapable });
3521
+ const leadRoute = persistLeadRoute(selectedRoute);
3522
+ route = resolveRoute(config, leadRoute
3523
+ ? { model: workflowPresetId('lead') }
3524
+ : selectedRoute);
3525
+ await refreshRouteEffort(modelMeta);
3526
+ if (session) {
3527
+ const updated = mgr.updateSessionRoute?.(session.id, {
3528
+ provider: route.provider,
3529
+ model: route.model,
3530
+ fast: route.fast === true,
3531
+ effort: route.effectiveEffort || null,
3532
+ });
3533
+ if (updated) session = updated;
3534
+ else {
3535
+ session.provider = route.provider;
3536
+ session.model = route.model;
3537
+ session.fast = route.fast === true;
3538
+ session.effort = route.effectiveEffort || null;
3539
+ }
3540
+ statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route));
3541
+ invalidateContextStatusCache();
3542
+ }
3543
+ return route;
3544
+ },
3545
+
3546
+ async setFast(value) {
3547
+ const enabled = value === true;
3548
+ const modelMeta = await lookupModelMeta(route.provider, route.model);
3549
+ const fastCapable = fastCapableFor(route.provider, modelMeta);
3550
+ if (enabled && !fastCapable) {
3551
+ throw new Error(`fast mode is not available for ${route.provider}/${route.model}`);
3552
+ }
3553
+ route = resolveRoute(config, { provider: route.provider, model: route.model, effort: route.effort, fast: fastCapable ? enabled : false });
3554
+ config = saveModelSettings(cfgMod, route, { fastCapable });
3555
+ const leadRoute = persistLeadRoute(route);
3556
+ if (leadRoute) route = resolveRoute(config, { model: workflowPresetId('lead') });
3557
+ await refreshRouteEffort(modelMeta);
3558
+ if (session) {
3559
+ session.fast = route.fast === true;
3560
+ session.effort = route.effectiveEffort || null;
3561
+ statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route));
3562
+ invalidateContextStatusCache();
3563
+ }
3564
+ return route.fast === true;
3565
+ },
3566
+
3567
+ async toggleFast() {
3568
+ return await this.setFast(!(route.fast === true));
3569
+ },
3570
+
3571
+ async setEffort(value) {
3572
+ const normalized = normalizeEffortInput(value);
3573
+ route = { ...route, effort: normalized };
3574
+ config = saveModelSettings(cfgMod, route, { fastCapable: route.fastCapable !== false });
3575
+ const leadRoute = persistLeadRoute(route);
3576
+ if (leadRoute) {
3577
+ route = resolveRoute(config, { model: workflowPresetId('lead') });
3578
+ }
3579
+ await refreshRouteEffort();
3580
+ if (session) {
3581
+ session.effort = route.effectiveEffort || null;
3582
+ statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route));
3583
+ invalidateContextStatusCache();
3584
+ }
3585
+ return route;
3586
+ },
3587
+ async close(reason = 'cli-exit', options = {}) {
3588
+ const detach = options?.detach === true || options?.wait === false || options?.waitForExit === false;
3589
+ closeRequested = true;
3590
+ if (channelStartTimer) {
3591
+ clearTimeout(channelStartTimer);
3592
+ channelStartTimer = null;
3593
+ }
3594
+ if (providerWarmupTimer) {
3595
+ clearTimeout(providerWarmupTimer);
3596
+ providerWarmupTimer = null;
3597
+ }
3598
+ if (providerModelWarmupTimer) {
3599
+ clearTimeout(providerModelWarmupTimer);
3600
+ providerModelWarmupTimer = null;
3601
+ }
3602
+ try { cancelBackgroundTasks({ reason, notify: false }); } catch {}
3603
+ const channelStop = channels.stop(reason, detach ? { waitForExit: false } : undefined);
3604
+ try { bridge.closeAll(reason); } catch {}
3605
+ let mcpStop = null;
3606
+ try { mcpStop = mcpClient.disconnectAll?.(); } catch {}
3607
+ const openaiWsStop = globalThis.__mixdogOpenaiWsRuntimeLoaded === true
3608
+ ? import('./runtime/agent/orchestrator/providers/openai-oauth-ws.mjs')
3609
+ .then((mod) => mod?.drainOpenaiWsPool?.(reason))
3610
+ .catch(() => {})
3611
+ : null;
3612
+ const patchStop = closePatchRuntimeIfLoaded(detach ? { waitForExit: false } : undefined);
3613
+ let ok = false;
3614
+ if (session?.id) {
3615
+ statusRoutes?.clearGatewaySessionRoute?.(session.id);
3616
+ ok = mgr.closeSession(session.id, reason);
3617
+ session = null;
3618
+ }
3619
+ if (detach) {
3620
+ try { await withTeardownDeadline(channelStop, 300, false); } catch {}
3621
+ for (const stop of [mcpStop, openaiWsStop, patchStop]) {
3622
+ Promise.resolve(stop).catch(() => {});
3623
+ }
3624
+ return ok;
3625
+ }
3626
+ await Promise.allSettled([
3627
+ withTeardownDeadline(channelStop, 5500, false),
3628
+ withTeardownDeadline(mcpStop, 1500, false),
3629
+ withTeardownDeadline(openaiWsStop, 1500, false),
3630
+ withTeardownDeadline(patchStop, 1500, false),
3631
+ ]);
3632
+ return ok;
3633
+ },
3634
+ abort(reason = 'cli-abort') {
3635
+ if (!session?.id) return false;
3636
+ return mgr.abortSessionTurn(session.id, reason);
3637
+ },
3638
+ listSessions() {
3639
+ return mgr.listSessions({}).map(s => {
3640
+ const owner = clean(s.owner || 'user').toLowerCase();
3641
+ if (owner && !['cli', 'user', 'mixdog', 'legacy'].includes(owner)) return null;
3642
+ const sourceType = clean(s.sourceType || '').toLowerCase();
3643
+ const sourceName = clean(s.sourceName || '').toLowerCase();
3644
+ const role = clean(s.role || '').toLowerCase();
3645
+ const leadish = role === 'lead'
3646
+ || sourceType === 'lead'
3647
+ || (sourceType === 'cli' && (!sourceName || sourceName === 'main'))
3648
+ || (!sourceType && !sourceName && owner !== 'bridge');
3649
+ if (!leadish) return null;
3650
+ const msgs = s.messages || [];
3651
+ const userPreviews = msgs
3652
+ .filter(m => m && m.role === 'user')
3653
+ .map(m => cleanSessionPreview(sessionMessageText(m.content)))
3654
+ .filter(text => !isSessionPreviewNoise(text));
3655
+ const preview = userPreviews[userPreviews.length - 1] || userPreviews[0] || '';
3656
+ if (!preview) return null;
3657
+ const userAsst = msgs.filter(m => m && (m.role === 'user' || m.role === 'assistant'));
3658
+ return {
3659
+ id: s.id,
3660
+ updatedAt: s.updatedAt,
3661
+ cwd: s.cwd || '',
3662
+ model: s.model,
3663
+ provider: s.provider,
3664
+ messageCount: userAsst.length,
3665
+ preview,
3666
+ };
3667
+ }).filter(Boolean);
3668
+ },
3669
+ async newSession() {
3670
+ if (session?.id) mgr.closeSession(session.id, 'cli-new');
3671
+ await createCurrentSession();
3672
+ return session.id;
3673
+ },
3674
+ async resume(id) {
3675
+ const previousId = session?.id || null;
3676
+ const resumed = await mgr.resumeSession(id, toolSpecForMode(mode));
3677
+ if (!resumed) return null;
3678
+ if (previousId && previousId !== resumed.id) {
3679
+ statusRoutes?.clearGatewaySessionRoute?.(previousId);
3680
+ mgr.closeSession(previousId, 'cli-resume');
3681
+ }
3682
+ session = resumed;
3683
+ currentCwd = resumed.cwd || currentCwd;
3684
+ applyResolvedCwd(currentCwd, { markRefresh: false });
3685
+ const resumeEffort = hasOwn(route, 'effort') ? route.effort : resumed.effort;
3686
+ route = resolveRoute(config, { provider: resumed.provider, model: resumed.model, effort: resumeEffort });
3687
+ await refreshRouteEffort();
3688
+ session.effort = route.effectiveEffort || null;
3689
+ session.cwd = currentCwd;
3690
+ applyDeferredToolSurface(session, mode, standaloneTools);
3691
+ invalidatePreSessionToolSurface();
3692
+ invalidateContextStatusCache();
3693
+ sessionNeedsCwdRefresh = false;
3694
+ statusRoutes?.writeGatewaySessionRoute?.(session.id, routeForStatusline(route));
3695
+ return {
3696
+ id: resumed.id,
3697
+ messages: resumed.messages || [],
3698
+ cwd: currentCwd,
3699
+ provider: resumed.provider,
3700
+ model: resumed.model,
3701
+ };
3702
+ },
3703
+ };
3704
+ }