mixdog 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,490 @@
1
+ /**
2
+ * settings-picker.mjs — the SETTINGS picker cluster.
3
+ *
4
+ * Extracted from App.jsx behavior-preservingly as a dependency-injection
5
+ * factory. The function body is the original App logic verbatim, with closure
6
+ * identifiers threaded through the factory argument. openSettingsPicker
7
+ * self-references (for light refresh) via the local const; all other openers it
8
+ * routes to are threaded as lazy getter wrappers so they resolve the live
9
+ * binding at call time.
10
+ */
11
+ import { outputStyleNotice } from './route-pickers.mjs';
12
+
13
+ export function createSettingsPicker({
14
+ store,
15
+ state,
16
+ setPicker,
17
+ setProviderPrompt,
18
+ setChannelPrompt,
19
+ setHookPrompt,
20
+ setSettingsPrompt,
21
+ settingsHeavyCacheRef,
22
+ formatDuration,
23
+ displayModelName,
24
+ routeModelLabel,
25
+ workflowDisplayName,
26
+ workflowSwitchNotice,
27
+ themeNotice,
28
+ openModelPicker,
29
+ openSearchPicker,
30
+ openAgentsPicker,
31
+ openWorkflowPicker,
32
+ openOutputStylePicker,
33
+ openBridgePicker,
34
+ openToolsPicker,
35
+ openProviderSetupPicker,
36
+ openThemePicker,
37
+ openAutoClearPicker,
38
+ openProfilePicker,
39
+ openMemoryCorePicker,
40
+ openMcpPicker,
41
+ openPluginsPicker,
42
+ openHooksPicker,
43
+ openSkillsPicker,
44
+ openUpdatePicker,
45
+ openChannelSettingTypePicker,
46
+ }) {
47
+ const openSettingsPicker = (opts = {}) => {
48
+ const light = opts.light === true;
49
+ const overrides = opts.overrides || null;
50
+ const heavyCache = light ? settingsHeavyCacheRef.current : null;
51
+ const autoClear = store.getAutoClear?.() || {};
52
+ const compaction = store.getCompactionSettings?.() || {};
53
+ const memory = store.getMemorySettings?.() || { enabled: true };
54
+ const channels = store.getChannelSettings?.({ includeStatus: false }) || { enabled: true };
55
+ const outputStyle = store.getOutputStyle?.() || store.listOutputStyles?.() || {};
56
+ const workflow = state.workflow || {};
57
+ const mcp = heavyCache ? heavyCache.mcp : (store.mcpStatus?.() || { connectedCount: 0, configuredCount: 0, failedCount: 0 });
58
+ const hooks = heavyCache ? heavyCache.hooks : (store.hooksStatus?.() || { ruleCount: 0 });
59
+ const plugins = heavyCache ? heavyCache.plugins : (store.pluginsStatus?.() || { count: 0 });
60
+ const skills = heavyCache ? heavyCache.skills : (store.skillsStatus?.() || { count: 0 });
61
+ const channelWorker = store.getChannelWorkerStatus?.();
62
+ let channelBackend = 'discord';
63
+ if (heavyCache) {
64
+ channelBackend = heavyCache.channelBackend || 'discord';
65
+ } else {
66
+ try {
67
+ channelBackend = store.getChannelSetup?.()?.backend || 'discord';
68
+ } catch {
69
+ channelBackend = 'discord';
70
+ }
71
+ }
72
+ if (overrides && Object.prototype.hasOwnProperty.call(overrides, 'channelBackend')) {
73
+ channelBackend = overrides.channelBackend;
74
+ }
75
+ // Refresh the cache every build (light or full) so the next light
76
+ // refresh reuses whatever was most recently known, and so an
77
+ // optimistic override (e.g. channel backend cycle) sticks without
78
+ // re-running the heavy getter it came from.
79
+ settingsHeavyCacheRef.current = { mcp, hooks, plugins, skills, channelBackend };
80
+ const channelBackendLabel = channelBackend === 'telegram' ? 'Telegram' : 'Discord';
81
+ const remoteEnabled = store.isRemoteEnabled?.() === true;
82
+ const remoteRuntimeDescription = channelWorker?.running
83
+ ? `runtime running · pid ${channelWorker.pid}`
84
+ : 'runtime stopped';
85
+ const compactType = compaction.compactType || compaction.type || 'semantic';
86
+ const compactTypeLabel = compactType === 'recall-fasttrack' ? 'Fast-track' : 'Default';
87
+ const outputStyleLabel = outputStyle?.current?.label || outputStyle?.current?.id || outputStyle?.configured || 'Default';
88
+ const workflowLabel = workflowDisplayName(workflow);
89
+ const boolLabel = (enabled) => enabled ? 'On' : 'Off';
90
+ const compactTypeDescription = compactType === 'recall-fasttrack'
91
+ ? (memory.enabled === false
92
+ ? 'Injects raw transcript lines (Recap off: no LLM chunking).'
93
+ : 'Uses Memory recall to rebuild context faster on large histories.')
94
+ : 'Uses semantic summarization for predictable context compaction.';
95
+ const applyAutoClear = (patch = {}) => {
96
+ try {
97
+ const next = store.setAutoClear?.(patch);
98
+ if (!next) store.pushNotice('autoclear unavailable', 'warn');
99
+ else store.pushNotice(next.enabled ? `Auto-clear on · idle ${formatDuration(next.idleMs)}` : 'Auto-clear off', 'info');
100
+ } catch (e) {
101
+ store.pushNotice(`autoclear failed: ${e?.message || e}`, 'error');
102
+ }
103
+ openSettingsPicker({ light: true });
104
+ };
105
+ // On/Off toggle only — idle-window override lives in the Advanced picker
106
+ // (openAutoClearPicker), opened via Enter on this row.
107
+ const autoClearEnabled = autoClear.enabled !== false;
108
+ const toggleAutoClear = () => applyAutoClear({ enabled: !autoClearEnabled });
109
+ const applyCompaction = (patch = {}) => {
110
+ void Promise.resolve(store.setCompactionSettings?.(patch))
111
+ .then((next) => {
112
+ if (!next) {
113
+ store.pushNotice('compaction setting is busy', 'warn');
114
+ return;
115
+ }
116
+ store.pushNotice(`Compaction ${next.auto !== false ? 'auto on' : 'auto off'} · ${next.compactType === 'recall-fasttrack' ? 'Fast-track' : 'Default'}`, 'info');
117
+ })
118
+ .catch((e) => store.pushNotice(`compaction failed: ${e?.message || e}`, 'error'))
119
+ .finally(() => openSettingsPicker({ light: true }));
120
+ };
121
+ const applyMemory = (enabled) => {
122
+ void Promise.resolve(store.setMemoryEnabled?.(enabled))
123
+ .then((next) => {
124
+ if (!next) {
125
+ store.pushNotice('recap setting is busy', 'warn');
126
+ return;
127
+ }
128
+ store.pushNotice(`Recap ${next.enabled ? 'on' : 'off'}`, 'info');
129
+ })
130
+ .catch((e) => store.pushNotice(`recap setting failed: ${e?.message || e}`, 'error'))
131
+ .finally(() => openSettingsPicker({ light: true }));
132
+ };
133
+ const applyChannels = (enabled) => {
134
+ void Promise.resolve(store.setChannelsEnabled?.(enabled))
135
+ .then((next) => {
136
+ if (!next) {
137
+ store.pushNotice('channel setting is busy', 'warn');
138
+ return;
139
+ }
140
+ store.pushNotice(`Channels ${next.enabled ? 'on' : 'off'}`, 'info');
141
+ })
142
+ .catch((e) => store.pushNotice(`channel setting failed: ${e?.message || e}`, 'error'))
143
+ .finally(() => openSettingsPicker({ light: true }));
144
+ };
145
+ const cycleOutputStyle = (direction = 1) => {
146
+ let status = null;
147
+ try { status = store.listOutputStyles?.() || null; } catch (e) {
148
+ store.pushNotice(`could not list output styles: ${e?.message || e}`, 'error');
149
+ return;
150
+ }
151
+ const styles = Array.isArray(status?.styles) ? status.styles : [];
152
+ if (!styles.length) {
153
+ store.pushNotice('no output styles available', 'warn');
154
+ return;
155
+ }
156
+ const currentId = status?.current?.id || 'default';
157
+ const currentIndex = Math.max(0, styles.findIndex((style) => style.id === currentId));
158
+ const next = styles[(currentIndex + direction + styles.length) % styles.length];
159
+ void store.setOutputStyle?.(next.id)
160
+ .then((result) => {
161
+ if (!result) {
162
+ store.pushNotice('Output style switch is already running.', 'warn');
163
+ return;
164
+ }
165
+ store.pushNotice(outputStyleNotice(result), 'info');
166
+ })
167
+ .catch((e) => store.pushNotice(`Couldn’t switch output style: ${e?.message || e}`, 'error'))
168
+ .finally(() => openSettingsPicker({ light: true }));
169
+ };
170
+ const cycleWorkflow = (direction = 1) => {
171
+ let workflows = [];
172
+ try { workflows = store.listWorkflows?.() || []; } catch (e) {
173
+ store.pushNotice(`could not list workflows: ${e?.message || e}`, 'error');
174
+ return;
175
+ }
176
+ if (!workflows.length) {
177
+ store.pushNotice('no workflows available', 'warn');
178
+ return;
179
+ }
180
+ const activeIndex = workflows.findIndex((item) => item.active);
181
+ const currentIndex = activeIndex >= 0 ? activeIndex : Math.max(0, workflows.findIndex((item) => item.id === workflow.id));
182
+ const next = workflows[(currentIndex + direction + workflows.length) % workflows.length];
183
+ void store.setWorkflow?.(next.id)
184
+ .then((result) => {
185
+ if (!result) {
186
+ store.pushNotice('Workflow switch is already running.', 'warn');
187
+ return;
188
+ }
189
+ store.pushNotice(workflowSwitchNotice(result), 'info');
190
+ })
191
+ .catch((e) => store.pushNotice(`Couldn’t switch workflow: ${e?.message || e}`, 'error'))
192
+ .finally(() => openSettingsPicker({ light: true }));
193
+ };
194
+ const cycleTheme = (direction = 1) => {
195
+ let themes = [];
196
+ try { themes = store.listThemes?.() || []; } catch (e) {
197
+ store.pushNotice(`could not list themes: ${e?.message || e}`, 'error');
198
+ return;
199
+ }
200
+ if (!themes.length) {
201
+ store.pushNotice('no themes available', 'warn');
202
+ return;
203
+ }
204
+ const currentId = store.getTheme?.() || themes.find((t) => t.current)?.id || themes[0]?.id;
205
+ const currentIndex = Math.max(0, themes.findIndex((t) => t.id === currentId));
206
+ const next = themes[(currentIndex + direction + themes.length) % themes.length];
207
+ try {
208
+ const applied = store.setTheme?.(next.id, { persist: true });
209
+ store.pushNotice(themeNotice(applied || next), 'info');
210
+ } catch (e) {
211
+ store.pushNotice(`Couldn’t set theme: ${e?.message || e}`, 'error');
212
+ }
213
+ openSettingsPicker({ light: true });
214
+ };
215
+ const applyRemoteRuntime = () => {
216
+ const enabled = store.toggleRemote?.() === true;
217
+ store.pushNotice(enabled ? 'Remote mode ON' : 'Remote mode OFF', 'info');
218
+ openSettingsPicker({ light: true });
219
+ };
220
+ const cycleChannelBackend = (direction = 1) => {
221
+ const backends = ['discord', 'telegram'];
222
+ const currentIndex = Math.max(0, backends.indexOf(channelBackend));
223
+ const chosen = backends[(currentIndex + direction + backends.length) % backends.length];
224
+ if (chosen === channelBackend) {
225
+ openSettingsPicker({ light: true, overrides: { channelBackend } });
226
+ return;
227
+ }
228
+ try {
229
+ store.setBackend(chosen);
230
+ const label = chosen === 'telegram' ? 'Telegram' : 'Discord';
231
+ const restartHint = (store.isRemoteEnabled?.() === true || channelWorker?.running)
232
+ ? `Channel set to ${label}. Restart remote to apply.`
233
+ : `Channel set to ${label}.`;
234
+ store.pushNotice(restartHint, 'info');
235
+ } catch (e) {
236
+ store.pushNotice(`channel backend failed: ${e?.message || e}`, 'error');
237
+ }
238
+ openSettingsPicker({ light: true, overrides: { channelBackend: chosen } });
239
+ };
240
+ const items = [
241
+ {
242
+ value: 'profile',
243
+ label: 'Profile',
244
+ meta: (() => {
245
+ try {
246
+ const p = store.getProfile?.();
247
+ const lang = p?.languageEntry?.label || 'System';
248
+ return p?.title ? `${p.title} · ${lang}` : lang;
249
+ } catch { return 'System'; }
250
+ })(),
251
+ description: 'Your title and response language.',
252
+ _action: 'profile',
253
+ },
254
+ {
255
+ value: 'autoclear',
256
+ label: 'Auto-clear',
257
+ meta: autoClearEnabled ? `On (${formatDuration(autoClear.idleMs)})` : 'Off',
258
+ description: autoClearEnabled
259
+ ? `Clear idle sessions after ${formatDuration(autoClear.idleMs)}${autoClear.custom ? '' : ` (${autoClear.provider || 'default'} default)`}. Enter for options.`
260
+ : 'Idle auto-clear disabled. Enter for options.',
261
+ _action: 'autoclear',
262
+ },
263
+ {
264
+ value: 'autocompact',
265
+ label: 'Auto-compact',
266
+ meta: boolLabel(compaction.auto !== false),
267
+ description: 'Compact when context is high.',
268
+ _action: 'autocompact',
269
+ },
270
+ {
271
+ value: 'compact-type',
272
+ label: 'Compact type',
273
+ meta: compactTypeLabel,
274
+ description: compactTypeDescription,
275
+ _action: 'compact-type',
276
+ },
277
+ {
278
+ value: 'core-memory',
279
+ label: 'Recap',
280
+ meta: boolLabel(memory.enabled !== false),
281
+ description: 'Recap on/off, list and edit memories.',
282
+ _action: 'core-memory',
283
+ },
284
+ {
285
+ value: 'channels',
286
+ label: 'Channels enabled',
287
+ meta: boolLabel(channels.enabled !== false),
288
+ description: channels.enabled === false
289
+ ? 'Channel tools disabled.'
290
+ : 'Discord, schedules, and webhooks.',
291
+ _action: 'channels',
292
+ },
293
+ {
294
+ value: 'remote-runtime',
295
+ label: 'Remote Runtime',
296
+ meta: boolLabel(remoteEnabled),
297
+ description: remoteRuntimeDescription,
298
+ _action: 'remote-runtime',
299
+ },
300
+ {
301
+ value: 'channel-backend',
302
+ label: 'Channel',
303
+ meta: channelBackendLabel,
304
+ description: 'Left/Right or Enter changes channel type (Discord or Telegram).',
305
+ _action: 'channel-backend',
306
+ },
307
+ {
308
+ value: 'channel-setting',
309
+ label: 'Setting',
310
+ description: 'Configure credentials and main channel/chat for the active type.',
311
+ _action: 'channel-setting',
312
+ },
313
+ {
314
+ value: 'output-style',
315
+ label: 'Output style',
316
+ meta: outputStyleLabel,
317
+ description: 'Response tone and format.',
318
+ _action: 'output-style',
319
+ },
320
+ {
321
+ value: 'theme',
322
+ label: 'Theme',
323
+ meta: (() => {
324
+ try {
325
+ const id = store.getTheme?.();
326
+ const entry = (store.listThemes?.() || []).find((t) => t.id === id);
327
+ return entry?.label || id || 'Default';
328
+ } catch { return 'Default'; }
329
+ })(),
330
+ description: 'TUI color theme.',
331
+ _action: 'theme',
332
+ },
333
+ {
334
+ value: 'workflow',
335
+ label: 'Workflow',
336
+ meta: workflowLabel,
337
+ description: 'Active agent routing profile.',
338
+ _action: 'workflow',
339
+ },
340
+ {
341
+ value: 'model',
342
+ label: 'Model',
343
+ meta: displayModelName(state.model, state.provider),
344
+ description: 'Main chat model.',
345
+ _action: 'model',
346
+ },
347
+ {
348
+ value: 'search',
349
+ label: 'Search model',
350
+ meta: routeModelLabel(store.getSearchRoute?.()),
351
+ description: 'Native search model.',
352
+ _action: 'search',
353
+ },
354
+ {
355
+ value: 'providers',
356
+ label: 'Providers',
357
+ description: 'Auth, API keys, OAuth, local.',
358
+ _action: 'providers',
359
+ },
360
+ {
361
+ value: 'mcp',
362
+ label: 'MCP servers',
363
+ description: `${mcp.connectedCount || 0}/${mcp.configuredCount || 0} connected${mcp.failedCount ? ` · ${mcp.failedCount} failed` : ''}`,
364
+ _action: 'mcp',
365
+ },
366
+ {
367
+ value: 'plugins',
368
+ label: 'Plugins',
369
+ description: `${plugins.count || 0} detected`,
370
+ _action: 'plugins',
371
+ },
372
+ {
373
+ value: 'hooks',
374
+ label: 'Hooks',
375
+ description: `${hooks.ruleCount || 0} before-tool rules`,
376
+ _action: 'hooks',
377
+ },
378
+ {
379
+ value: 'skills',
380
+ label: 'Skills',
381
+ description: `${skills.count || 0} available`,
382
+ _action: 'skills',
383
+ },
384
+ {
385
+ value: 'update',
386
+ label: 'Update',
387
+ meta: (() => {
388
+ try {
389
+ const upd = store.getUpdateSettings?.() || {};
390
+ const current = upd.currentVersion || 'unknown';
391
+ if (upd.updateAvailable && upd.latestVersion) return `${current} → ${upd.latestVersion}`;
392
+ if (!upd.currentVersion) return 'unknown';
393
+ return `${current} (latest)`;
394
+ } catch { return 'unknown'; }
395
+ })(),
396
+ description: 'Check version and update mixdog.',
397
+ _action: 'update',
398
+ },
399
+ ];
400
+ setProviderPrompt(null);
401
+ setChannelPrompt(null);
402
+ setHookPrompt(null);
403
+ setSettingsPrompt(null);
404
+ setPicker({
405
+ title: 'Settings',
406
+ description: 'Runtime, model, tools, and integrations.',
407
+ help: '↑/↓ Select · ←/→ Change · Enter Open/Toggle · Esc Close',
408
+ indexMode: 'always',
409
+ labelWidth: 18,
410
+ metaWidth: 18,
411
+ items,
412
+ initialIndex: opts.focus ? Math.max(0, items.findIndex((item) => item.value === opts.focus)) : undefined,
413
+ onLeft: (item) => {
414
+ if (item?._action === 'autoclear') toggleAutoClear();
415
+ else if (item?._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
416
+ else if (item?._action === 'compact-type') {
417
+ const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
418
+ applyCompaction({ compactType: nextType });
419
+ }
420
+ else if (item?._action === 'core-memory') applyMemory(!(memory.enabled !== false));
421
+ else if (item?._action === 'channels') applyChannels(!(channels.enabled !== false));
422
+ else if (item?._action === 'remote-runtime') applyRemoteRuntime();
423
+ else if (item?._action === 'channel-backend') cycleChannelBackend(-1);
424
+ else if (item?._action === 'output-style') cycleOutputStyle(-1);
425
+ else if (item?._action === 'theme') cycleTheme(-1);
426
+ else if (item?._action === 'workflow') cycleWorkflow(-1);
427
+ },
428
+ onRight: (item) => {
429
+ if (item?._action === 'autoclear') toggleAutoClear();
430
+ else if (item?._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
431
+ else if (item?._action === 'compact-type') {
432
+ const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
433
+ applyCompaction({ compactType: nextType });
434
+ }
435
+ else if (item?._action === 'core-memory') applyMemory(!(memory.enabled !== false));
436
+ else if (item?._action === 'channels') applyChannels(!(channels.enabled !== false));
437
+ else if (item?._action === 'remote-runtime') applyRemoteRuntime();
438
+ else if (item?._action === 'channel-backend') cycleChannelBackend(1);
439
+ else if (item?._action === 'output-style') cycleOutputStyle(1);
440
+ else if (item?._action === 'theme') cycleTheme(1);
441
+ else if (item?._action === 'workflow') cycleWorkflow(1);
442
+ },
443
+ onSelect: (_value, item) => {
444
+ setPicker(null);
445
+ if (item._action === 'autoclear') openAutoClearPicker({ returnTo: openSettingsPicker });
446
+ else if (item._action === 'profile') openProfilePicker({ returnTo: openSettingsPicker });
447
+ else if (item._action === 'autocompact') applyCompaction({ auto: !(compaction.auto !== false) });
448
+ else if (item._action === 'compact-type') {
449
+ const nextType = compactType === 'recall-fasttrack' ? 'semantic' : 'recall-fasttrack';
450
+ applyCompaction({ compactType: nextType });
451
+ }
452
+ else if (item._action === 'core-memory') openMemoryCorePicker({ returnTo: () => openSettingsPicker() });
453
+ else if (item._action === 'channels') applyChannels(!(channels.enabled !== false));
454
+ else if (item._action === 'remote-runtime') applyRemoteRuntime();
455
+ else if (item._action === 'channel-backend') cycleChannelBackend(1);
456
+ else if (item._action === 'channel-setting') openChannelSettingTypePicker({ returnTo: openSettingsPicker });
457
+ else if (item._action === 'output-style') openOutputStylePicker({ returnTo: openSettingsPicker });
458
+ else if (item._action === 'theme') openThemePicker({ returnTo: openSettingsPicker });
459
+ else if (item._action === 'workflow') openWorkflowPicker({ returnTo: openSettingsPicker });
460
+ else if (item._action === 'model') openModelPicker({
461
+ returnTo: openSettingsPicker,
462
+ returnLabel: 'Settings',
463
+ returnOnNestedCancel: true,
464
+ onAfterSelect: openSettingsPicker,
465
+ });
466
+ else if (item._action === 'search') openSearchPicker({
467
+ returnTo: openSettingsPicker,
468
+ returnLabel: 'Settings',
469
+ returnOnNestedCancel: true,
470
+ });
471
+ else if (item._action === 'providers') void openProviderSetupPicker({
472
+ returnTo: openSettingsPicker,
473
+ onCancel: openSettingsPicker,
474
+ continueLabel: 'Back to settings',
475
+ continueDescription: 'return to settings',
476
+ });
477
+ else if (item._action === 'mcp') openMcpPicker();
478
+ else if (item._action === 'plugins') openPluginsPicker();
479
+ else if (item._action === 'hooks') openHooksPicker();
480
+ else if (item._action === 'skills') openSkillsPicker();
481
+ else if (item._action === 'update') openUpdatePicker({ returnTo: openSettingsPicker });
482
+ },
483
+ onCancel: () => {
484
+ setPicker(null);
485
+ },
486
+ });
487
+ };
488
+
489
+ return { openSettingsPicker };
490
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * slash-commands.mjs — the /command registry plus the pure string/matching
3
+ * helpers that operate on it. Extracted verbatim from App.jsx (behavior-
4
+ * preserving): no hooks, no App state, no closures — plain data + pure fns.
5
+ */
6
+ export const SLASH_COMMANDS = [
7
+ { name: 'clear', usage: '/clear', aliases: ['new'], aliasUsage: ['new'], description: 'Start a fresh chat' },
8
+ { name: 'project', usage: '/project', aliases: ['projects'], aliasUsage: ['projects'], showAliasUsage: false, description: 'Switch working directory (project)' },
9
+ { name: 'compact', usage: '/compact', description: 'Compact older conversation context' },
10
+ { name: 'autoclear', usage: '/autoclear', description: 'Reduce cache-miss cost after long idle gaps' },
11
+ { name: 'resume', usage: '/resume', description: 'Resume a saved chat' },
12
+ { name: 'context', usage: '/context', description: 'Show current context surface' },
13
+ { name: 'usage', usage: '/usage', params: '[refresh]', description: 'Show total provider quota / balance' },
14
+ { name: 'model', usage: '/model', description: 'Switch model for subsequent turns' },
15
+ { name: 'search', usage: '/search', description: 'Set the web search provider/model' },
16
+ { name: 'workflow', usage: '/workflow', description: 'Switch the active workflow' },
17
+ { name: 'outputstyle', usage: '/OutputStyle', aliases: ['output-style', 'style'], aliasUsage: ['style'], showAliasUsage: false, params: '[name]', description: 'Switch Lead output style' },
18
+ { name: 'theme', usage: '/theme', params: '[id]', description: 'Change the TUI color theme' },
19
+ { name: 'agents', usage: '/agents', description: 'Show available workflow agents' },
20
+ { name: 'effort', usage: '/effort', params: '[level]', description: 'Set reasoning effort for the current model' },
21
+ { name: 'fast', usage: '/fast', params: '[on|off]', description: 'Toggle Fast mode for the current model' },
22
+ { name: 'mcp', usage: '/mcp', description: 'Manage MCP servers and tools' },
23
+ { name: 'skills', usage: '/skills', description: 'Choose a skill for the next request' },
24
+ { name: 'memory', usage: '/memory', description: 'List and edit core memories' },
25
+ { name: 'recap', usage: '/recap', params: '[on|off]', description: 'Toggle background memory recap cycles' },
26
+ { name: 'plugins', usage: '/plugins', description: 'Manage local plugin integrations' },
27
+ { name: 'hooks', usage: '/hooks', description: 'Manage before-tool hook rules and events' },
28
+ { name: 'providers', usage: '/providers', description: 'Manage auth, API keys, OAuth, and local endpoints' },
29
+ { name: 'channels', usage: '/channels', description: 'Manage Discord, channels, schedules, webhooks' },
30
+ { name: 'remote', usage: '/remote', description: 'Claim remote for this session (takes over from any other session)' },
31
+ { name: 'schedules', usage: '/schedules', description: 'Manage schedules' },
32
+ { name: 'webhooks', usage: '/webhooks', description: 'Manage inbound webhooks' },
33
+ { name: 'settings', usage: '/setting', aliases: ['setting', 'config'], aliasUsage: ['settings', 'config'], showAliasUsage: false, description: 'Open runtime settings' },
34
+ { name: 'profile', usage: '/profile', description: 'Set your title and response language' },
35
+ { name: 'update', usage: '/update', description: 'Check version and update mixdog' },
36
+ { name: 'voice', usage: '/voice', description: 'Toggle voice input (Ctrl+Space to record)' },
37
+ { name: 'quit', usage: '/quit', aliases: ['exit', 'q'], aliasUsage: ['exit', 'q'], description: 'Quit the TUI' },
38
+ ];
39
+
40
+ export function slashQuery(value) {
41
+ const text = String(value ?? '');
42
+ if (!/^\/[^\s]*$/.test(text)) return null;
43
+ return text.slice(1).toLowerCase();
44
+ }
45
+
46
+ export function slashCommandMatches(command, query) {
47
+ const needle = String(query || '').toLowerCase();
48
+ if (!needle) return true;
49
+ if (String(command?.name || '').toLowerCase().startsWith(needle)) return true;
50
+ return (command?.aliases || []).some((alias) => String(alias || '').toLowerCase().startsWith(needle));
51
+ }
52
+
53
+ export function compareSlashCommands(a, b) {
54
+ return String(a?.name || '').localeCompare(String(b?.name || ''), 'en', { sensitivity: 'base' });
55
+ }
56
+
57
+ /** Prompt-owned overlays absorb PageUp/PageDown and wheel scroll instead of the transcript. */
58
+ export function overlayBlocksGlobalTranscriptScroll(owner = {}) {
59
+ return !!(
60
+ owner.slashPaletteOpen ||
61
+ owner.picker ||
62
+ owner.toolApproval ||
63
+ owner.contextPanel ||
64
+ owner.usagePanel ||
65
+ owner.providerPrompt ||
66
+ owner.channelPrompt ||
67
+ owner.hookPrompt ||
68
+ owner.settingsPrompt
69
+ );
70
+ }
71
+
72
+ export function normalizeSlashCommandName(cmd) {
73
+ const name = String(cmd || '').toLowerCase();
74
+ const command = SLASH_COMMANDS.find((item) => item.name === name || (item.aliases || []).includes(name));
75
+ return command?.name || name;
76
+ }
77
+
78
+ export function slashCommandTokenForPaletteAccept(command, draftValue = '') {
79
+ if (!command) return '';
80
+ const text = String(draftValue ?? '').trim();
81
+ const typedToken = text.startsWith('/') ? text.slice(1).split(/\s+/)[0]?.toLowerCase() : '';
82
+ const canonical = String(command.name || '').toLowerCase();
83
+ const aliases = (command.aliases || []).map((alias) => String(alias || '').toLowerCase());
84
+ if (typedToken && (typedToken === canonical || aliases.includes(typedToken))) {
85
+ return typedToken;
86
+ }
87
+ return command.name;
88
+ }
89
+
90
+ export function slashCommandForName(cmd) {
91
+ const name = normalizeSlashCommandName(cmd);
92
+ return SLASH_COMMANDS.find((item) => item.name === name) || null;
93
+ }
94
+
95
+ export function slashArgumentHint(value) {
96
+ const text = String(value ?? '');
97
+ const match = text.match(/^\/([^\s]+)\s+$/);
98
+ if (!match) return '';
99
+ const command = slashCommandForName(match[1]);
100
+ return command?.params ? `${command.usage} ${command.params}` : '';
101
+ }