mixdog 0.8.1 → 0.9.1

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 (299) hide show
  1. package/README.md +47 -23
  2. package/package.json +34 -28
  3. package/scripts/_test-folder-dialog.mjs +30 -0
  4. package/scripts/agent-parallel-smoke.mjs +388 -0
  5. package/scripts/agent-tag-reuse-smoke.mjs +183 -0
  6. package/scripts/background-task-meta-smoke.mjs +38 -0
  7. package/scripts/boot-smoke.mjs +52 -9
  8. package/scripts/build-runtime-linux.sh +348 -0
  9. package/scripts/build-runtime-macos.sh +217 -0
  10. package/scripts/build-runtime-windows.ps1 +242 -0
  11. package/scripts/compact-active-turn-test.mjs +68 -0
  12. package/scripts/compact-smoke.mjs +859 -129
  13. package/scripts/compact-trigger-migration-smoke.mjs +187 -0
  14. package/scripts/fix-brief-fn.mjs +35 -0
  15. package/scripts/fix-format-tool-surface.mjs +24 -0
  16. package/scripts/fix-tool-exec-visible.mjs +42 -0
  17. package/scripts/generate-runtime-manifest.mjs +166 -0
  18. package/scripts/hook-bus-test.mjs +330 -0
  19. package/scripts/lead-workflow-smoke.mjs +33 -39
  20. package/scripts/live-worker-smoke.mjs +43 -37
  21. package/scripts/llm-trace-summary.mjs +315 -0
  22. package/scripts/memory-meta-concurrency-test.mjs +20 -0
  23. package/scripts/output-style-smoke.mjs +56 -15
  24. package/scripts/parent-abort-link-test.mjs +44 -0
  25. package/scripts/patch-agent-brief.mjs +48 -0
  26. package/scripts/patch-app.mjs +21 -0
  27. package/scripts/patch-app2.mjs +18 -0
  28. package/scripts/patch-dist-brief.mjs +96 -0
  29. package/scripts/patch-tool-exec.mjs +70 -0
  30. package/scripts/pretool-ask-runtime-test.mjs +54 -0
  31. package/scripts/provider-toolcall-test.mjs +376 -0
  32. package/scripts/reactive-compact-persist-smoke.mjs +124 -0
  33. package/scripts/sanitize-tool-pairs-test.mjs +260 -0
  34. package/scripts/session-context-bench.mjs +205 -33
  35. package/scripts/session-ingest-smoke.mjs +177 -0
  36. package/scripts/set-effort-config-test.mjs +41 -0
  37. package/scripts/smoke-runtime-negative.ps1 +106 -0
  38. package/scripts/smoke-runtime-negative.sh +97 -0
  39. package/scripts/smoke.mjs +25 -0
  40. package/scripts/tool-result-hook-test.mjs +48 -0
  41. package/scripts/tool-smoke.mjs +1222 -90
  42. package/scripts/toolcall-args-test.mjs +150 -0
  43. package/scripts/tui-background-failure-smoke.mjs +73 -0
  44. package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
  45. package/src/agents/debugger/AGENT.md +8 -0
  46. package/src/agents/explore/AGENT.md +4 -0
  47. package/src/agents/heavy-worker/AGENT.md +9 -3
  48. package/src/agents/maintainer/AGENT.md +4 -0
  49. package/src/agents/reviewer/AGENT.md +8 -0
  50. package/src/agents/scheduler-task/AGENT.md +12 -0
  51. package/src/agents/scheduler-task/agent.json +6 -0
  52. package/src/agents/webhook-handler/AGENT.md +12 -0
  53. package/src/agents/webhook-handler/agent.json +6 -0
  54. package/src/agents/worker/AGENT.md +9 -3
  55. package/src/app.mjs +77 -3
  56. package/src/defaults/hidden-roles.json +17 -12
  57. package/src/headless-role.mjs +117 -0
  58. package/src/help.mjs +30 -0
  59. package/src/hooks/lib/permission-evaluator.cjs +11 -475
  60. package/src/lib/keychain-cjs.cjs +9 -1
  61. package/src/lib/mixdog-debug.cjs +0 -29
  62. package/src/lib/plugin-paths.cjs +1 -7
  63. package/src/lib/rules-builder.cjs +242 -98
  64. package/src/lib/text-utils.cjs +1 -1
  65. package/src/mixdog-session-runtime.mjs +2211 -446
  66. package/src/output-styles/default.md +12 -28
  67. package/src/output-styles/extreme-simple.md +9 -6
  68. package/src/output-styles/simple.md +22 -9
  69. package/src/repl.mjs +108 -59
  70. package/src/rules/agent/00-common.md +15 -0
  71. package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
  72. package/src/rules/agent/30-explorer.md +22 -0
  73. package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
  74. package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
  75. package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
  76. package/src/rules/lead/01-general.md +9 -5
  77. package/src/rules/lead/04-workflow.md +51 -12
  78. package/src/rules/lead/lead-tool.md +6 -0
  79. package/src/rules/shared/01-tool.md +12 -1
  80. package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
  81. package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
  82. package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
  83. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
  84. package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
  85. package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
  86. package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
  87. package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
  88. package/src/runtime/agent/orchestrator/config.mjs +174 -55
  89. package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
  90. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
  92. package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
  93. package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
  94. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
  95. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +380 -268
  96. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +131 -93
  97. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
  98. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
  99. package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
  100. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
  101. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
  102. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
  103. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
  104. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
  107. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +203 -71
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +512 -312
  109. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -518
  110. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
  111. package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
  112. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +289 -11
  113. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
  114. package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
  115. package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
  116. package/src/runtime/agent/orchestrator/session/loop.mjs +840 -612
  117. package/src/runtime/agent/orchestrator/session/manager.mjs +1574 -459
  118. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
  119. package/src/runtime/agent/orchestrator/session/store.mjs +67 -29
  120. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
  121. package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
  122. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
  123. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +35 -8
  124. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -8
  125. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +10 -53
  126. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
  127. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
  128. package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
  129. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
  130. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
  131. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
  132. package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
  133. package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
  134. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
  135. package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
  136. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
  137. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
  138. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
  139. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
  140. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
  141. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
  142. package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
  143. package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
  144. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
  145. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
  146. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
  147. package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
  148. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
  149. package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
  150. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
  151. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
  152. package/src/runtime/channels/index.mjs +149 -51
  153. package/src/runtime/channels/lib/cli-worker-host.mjs +1 -8
  154. package/src/runtime/channels/lib/config.mjs +0 -1
  155. package/src/runtime/channels/lib/drop-trace.mjs +1 -1
  156. package/src/runtime/channels/lib/executor.mjs +0 -3
  157. package/src/runtime/channels/lib/memory-client.mjs +0 -38
  158. package/src/runtime/channels/lib/output-forwarder.mjs +1 -8
  159. package/src/runtime/channels/lib/runtime-paths.mjs +0 -6
  160. package/src/runtime/channels/lib/scheduler.mjs +18 -14
  161. package/src/runtime/channels/lib/session-discovery.mjs +3 -6
  162. package/src/runtime/channels/lib/tool-format.mjs +0 -1
  163. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -12
  164. package/src/runtime/channels/lib/webhook.mjs +1 -1
  165. package/src/runtime/channels/tool-defs.mjs +29 -29
  166. package/src/runtime/lib/keychain-cjs.cjs +0 -1
  167. package/src/runtime/memory/data/runtime-manifest.json +6 -7
  168. package/src/runtime/memory/index.mjs +519 -118
  169. package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
  170. package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
  171. package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
  172. package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
  173. package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
  174. package/src/runtime/memory/lib/llm-worker-host.mjs +0 -4
  175. package/src/runtime/memory/lib/memory-cycle1.mjs +28 -7
  176. package/src/runtime/memory/lib/memory-cycle2.mjs +4 -5
  177. package/src/runtime/memory/lib/memory-cycle3.mjs +2 -2
  178. package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -2
  179. package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
  180. package/src/runtime/memory/lib/memory.mjs +88 -9
  181. package/src/runtime/memory/lib/model-profile.mjs +1 -1
  182. package/src/runtime/memory/lib/pg/adapter.mjs +1 -1
  183. package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
  184. package/src/runtime/memory/lib/runtime-fetcher.mjs +80 -21
  185. package/src/runtime/memory/lib/session-ingest.mjs +196 -0
  186. package/src/runtime/memory/lib/trace-store.mjs +96 -51
  187. package/src/runtime/memory/tool-defs.mjs +46 -37
  188. package/src/runtime/search/index.mjs +104 -473
  189. package/src/runtime/search/lib/config.mjs +0 -4
  190. package/src/runtime/search/lib/state.mjs +1 -15
  191. package/src/runtime/search/lib/web-tools.mjs +44 -25
  192. package/src/runtime/search/tool-defs.mjs +16 -23
  193. package/src/runtime/shared/abort-controller.mjs +1 -1
  194. package/src/runtime/shared/atomic-file.mjs +4 -3
  195. package/src/runtime/shared/background-tasks.mjs +122 -11
  196. package/src/runtime/shared/child-spawn-gate.mjs +139 -0
  197. package/src/runtime/shared/config.mjs +7 -4
  198. package/src/runtime/shared/err-text.mjs +131 -4
  199. package/src/runtime/shared/llm/cost.mjs +2 -2
  200. package/src/runtime/shared/llm/http-agent.mjs +23 -7
  201. package/src/runtime/shared/llm/index.mjs +34 -11
  202. package/src/runtime/shared/llm/usage-log.mjs +4 -4
  203. package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
  204. package/src/runtime/shared/singleton-owner.mjs +104 -0
  205. package/src/runtime/shared/tool-execution-contract.mjs +199 -20
  206. package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
  207. package/src/runtime/shared/tool-surface.mjs +624 -95
  208. package/src/runtime/shared/user-data-guard.mjs +0 -2
  209. package/src/standalone/agent-task-status.mjs +203 -0
  210. package/src/standalone/agent-task-status.test.mjs +76 -0
  211. package/src/standalone/agent-tool.mjs +1913 -0
  212. package/src/standalone/channel-worker.mjs +370 -14
  213. package/src/standalone/explore-tool.mjs +165 -70
  214. package/src/standalone/folder-dialog.mjs +314 -0
  215. package/src/standalone/hook-bus.mjs +898 -22
  216. package/src/standalone/memory-runtime-proxy.mjs +320 -0
  217. package/src/standalone/projects.mjs +226 -0
  218. package/src/standalone/provider-admin.mjs +41 -24
  219. package/src/standalone/seeds.mjs +1 -78
  220. package/src/standalone/usage-dashboard.mjs +96 -8
  221. package/src/tui/App.jsx +4800 -2140
  222. package/src/tui/components/AnsiText.jsx +39 -28
  223. package/src/tui/components/ContextPanel.jsx +14 -4
  224. package/src/tui/components/Markdown.jsx +43 -77
  225. package/src/tui/components/MarkdownTable.jsx +9 -184
  226. package/src/tui/components/Message.jsx +28 -11
  227. package/src/tui/components/Picker.jsx +95 -56
  228. package/src/tui/components/PromptInput.jsx +428 -239
  229. package/src/tui/components/QueuedCommands.jsx +1 -1
  230. package/src/tui/components/SlashCommandPalette.jsx +27 -21
  231. package/src/tui/components/Spinner.jsx +67 -38
  232. package/src/tui/components/StatusLine.jsx +606 -38
  233. package/src/tui/components/TextEntryPanel.jsx +128 -9
  234. package/src/tui/components/ToolExecution.jsx +597 -362
  235. package/src/tui/components/TurnDone.jsx +3 -3
  236. package/src/tui/components/UsagePanel.jsx +3 -5
  237. package/src/tui/components/tool-output-format.mjs +499 -0
  238. package/src/tui/components/tool-output-format.test.mjs +312 -0
  239. package/src/tui/dist/index.mjs +9192 -2399
  240. package/src/tui/engine-runtime-notification.test.mjs +115 -0
  241. package/src/tui/engine-tool-result-text.test.mjs +75 -0
  242. package/src/tui/engine.mjs +1455 -279
  243. package/src/tui/figures.mjs +21 -40
  244. package/src/tui/index.jsx +75 -31
  245. package/src/tui/input-editing.mjs +25 -0
  246. package/src/tui/markdown/format-token.mjs +671 -69
  247. package/src/tui/markdown/format-token.test.mjs +312 -0
  248. package/src/tui/markdown/render-ansi.mjs +94 -0
  249. package/src/tui/markdown/render-ansi.test.mjs +108 -0
  250. package/src/tui/markdown/stream-fence.mjs +34 -0
  251. package/src/tui/markdown/stream-fence.test.mjs +26 -0
  252. package/src/tui/markdown/table-layout.mjs +250 -0
  253. package/src/tui/paste-attachments.mjs +0 -7
  254. package/src/tui/spinner-verbs.mjs +1 -2
  255. package/src/tui/statusline-ansi-bridge.mjs +172 -0
  256. package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
  257. package/src/tui/theme.mjs +756 -24
  258. package/src/tui/time-format.mjs +1 -1
  259. package/src/tui/transcript-tool-failures.mjs +67 -0
  260. package/src/tui/transcript-tool-failures.test.mjs +111 -0
  261. package/src/ui/ansi.mjs +1 -2
  262. package/src/ui/markdown.mjs +85 -26
  263. package/src/ui/markdown.test.mjs +70 -0
  264. package/src/ui/model-display.mjs +121 -0
  265. package/src/ui/session-stats.mjs +44 -0
  266. package/src/ui/statusline-context-label.test.mjs +15 -0
  267. package/src/ui/statusline.mjs +386 -178
  268. package/src/ui/tool-card.mjs +2 -13
  269. package/src/vendor/statusline/bin/statusline-lib.mjs +1 -620
  270. package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
  271. package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
  272. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
  273. package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
  274. package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
  275. package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
  276. package/src/workflows/default/WORKFLOW.md +12 -5
  277. package/src/workflows/default/workflow.json +0 -1
  278. package/src/workflows/solo/WORKFLOW.md +15 -0
  279. package/src/workflows/solo/workflow.json +7 -0
  280. package/vendor/ink/build/ink.js +54 -8
  281. package/vendor/ink/build/output.js +6 -1
  282. package/src/agents/scheduler-task.md +0 -3
  283. package/src/agents/web-researcher/AGENT.md +0 -3
  284. package/src/agents/web-researcher/agent.json +0 -6
  285. package/src/agents/webhook-handler.md +0 -3
  286. package/src/hooks/lib/permission-rules.cjs +0 -170
  287. package/src/hooks/lib/settings-loader.cjs +0 -112
  288. package/src/lib/hook-pipe-path.cjs +0 -10
  289. package/src/rules/bridge/00-common.md +0 -5
  290. package/src/rules/bridge/30-explorer.md +0 -4
  291. package/src/rules/lead/00-tool-lead.md +0 -5
  292. package/src/rules/shared/00-language.md +0 -3
  293. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  294. package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
  295. package/src/runtime/channels/lib/hook-pipe-server.mjs +0 -671
  296. package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
  297. package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
  298. package/src/standalone/bridge-tool.mjs +0 -1414
  299. package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
package/src/tui/theme.mjs CHANGED
@@ -1,14 +1,30 @@
1
1
  /**
2
- * src/tui/theme.mjs — Claude Code dark palette for the React/ink TUI.
2
+ * src/tui/theme.mjs — active-theme registry for the React/ink TUI.
3
3
  *
4
- * Claude Code-inspired dark palette tuned for Windows Terminal.
5
4
  * ink accepts `rgb(r,g,b)` strings directly on the `color`/`backgroundColor`
6
5
  * props, so these are plain strings (no escape wrapping needed — ink emits the
7
6
  * SGR and honors NO_COLOR/non-TTY itself).
8
7
  *
9
- * Dark-fixed for now (terminal background detection can pick light later).
8
+ * The exported `theme` is a SINGLETON object: every TUI module does
9
+ * `import { theme } from '../theme.mjs'` and reads live keys off it. A theme
10
+ * switch mutates this object in-place (`Object.assign(theme, palette)`) so the
11
+ * existing imports observe the new colors without re-importing. A monotonic
12
+ * `themeVersion` lets modules that cache derived values (chalk colorizers,
13
+ * parsed RGB tuples) invalidate when the active theme changes.
14
+ *
15
+ * The setting persists under `ui.theme` in mixdog-config.json. The config
16
+ * module is imported lazily through a dist-aware dynamic specifier (esbuild
17
+ * leaves dynamic-import strings alone), so this color module stays free of a
18
+ * static keychain/config dependency.
10
19
  */
11
- export const theme = {
20
+
21
+ // ── Palettes ──────────────────────────────────────────────────────────────
22
+ // Each palette is a COMPLETE set of theme keys. Non-default palettes spread the
23
+ // Mixdog base first so a missing key can never leak the previous theme's color
24
+ // through Object.assign.
25
+
26
+ /** Default Mixdog dark palette (preserves the original colors verbatim). */
27
+ const mixdogPalette = {
12
28
  background: 'rgb(13,13,13)', // opaque TUI surface; masks clipped scrollback behind fixed rows
13
29
  claude: 'rgb(215,119,87)', // orange title/header accent
14
30
  claudeShimmer: 'rgb(235,159,127)',
@@ -25,43 +41,759 @@ export const theme = {
25
41
  statusText: 'rgb(198,198,198)',
26
42
  statusSubtle: 'rgb(168,168,168)',
27
43
  timerText: 'rgb(168,168,168)', // live elapsed timer — metadata weight, no bright accent
28
- text: 'rgb(198,198,198)', // Claude Code-like primary text
44
+ text: 'rgb(198,198,198)', // primary text
29
45
  inverseText: 'rgb(0,0,0)', // text on an inverted (light) background
46
+ selectionText: 'rgb(0,0,0)', // text inside an active drag/copy selection
47
+ selectionBackground: 'rgb(245,245,245)', // selection highlight band
30
48
  inactive: 'rgb(136,136,136)', // secondary text
31
49
  subtle: 'rgb(140,140,140)', // helper text / quiet rules
32
50
  promptBorder: 'rgb(158,158,158)', // input border / prompt
33
- success: 'rgb(28,150,78)', // muted Claude-like green accent
34
- error: 'rgb(210,60,76)', // muted Claude-like red accent
51
+ success: 'rgb(28,150,78)', // muted green accent
52
+ error: 'rgb(210,60,76)', // muted red accent
35
53
  warning: 'rgb(204,157,44)', // muted amber
36
- suggestion: 'rgb(47,127,255)', // dense Claude-like path/link blue
54
+ suggestion: 'rgb(47,127,255)', // path/link blue
37
55
  panelTitle: 'rgb(215,119,87)', // panel/picker titles stay orange
38
56
  permission: 'rgb(239,68,88)', // permission red
39
57
  code: 'rgb(47,127,255)', // inline code/link accent
40
58
  codeBlock: 'rgb(136,190,142)', // code block body
41
- userMessageBackground: 'rgb(108,108,108)', // Claude Code prompt band
59
+ // Markdown (pi dark.json md* tokens headings/code/quotes only in format-token)
60
+ mdHeading: 'rgb(240,198,116)', // #f0c674 warm yellow-beige
61
+ mdCode: 'rgb(138,190,183)', // #8abeb7 muted teal (inline codespan)
62
+ mdCodeBlock: 'rgb(181,189,104)', // #b5bd68 muted green (fenced blocks)
63
+ mdQuote: 'rgb(128,128,128)', // #808080 quote body
64
+ mdQuoteBorder: 'rgb(128,128,128)', // blockquote bar
65
+ mdHr: 'rgb(128,128,128)', // horizontal rule
66
+ mdListBullet: 'rgb(138,190,183)', // list markers (pi accent)
67
+ // Markdown extras (fenced fences / inline links / emphasis) — warm dark base.
68
+ mdCodeBlockBorder: 'rgb(110,110,110)', // ``` fence + lang label rule
69
+ mdCodeBlockBg: 'rgb(34,35,40)', // code-block background band (distinct from bg)
70
+ mdCodeSpanBg: 'rgb(42,43,48)', // inline codespan background (subtle lift from block bg)
71
+ mdLink: 'rgb(47,127,255)', // link URL (suggestion blue)
72
+ mdLinkText: 'rgb(138,190,183)', // link label (teal accent)
73
+ mdStrong: 'rgb(235,159,127)', // **bold** warm amber
74
+ mdEmph: 'rgb(229,192,123)', // *italic* soft yellow
75
+ // Diff / patch rendering (OpenCode + Codex conventions, ANSI-safe).
76
+ mdDiffAdded: 'rgb(120,200,130)', // + lines (green)
77
+ mdDiffRemoved: 'rgb(224,108,117)', // - lines (red)
78
+ mdDiffHunk: 'rgb(130,139,184)', // @@ hunk markers
79
+ mdDiffHeader: 'rgb(170,150,210)', // ---/+++ / diff --git headers
80
+ mdDiffContext: 'rgb(140,140,140)', // unchanged context lines
81
+ mdDiffAddedBg: 'rgb(33,58,43)', // #213A2B muted add tint (codex dark)
82
+ mdDiffRemovedBg: 'rgb(74,34,29)', // #4A221D muted del tint (codex dark)
83
+ // Lightweight syntax highlight palette (regex token classes).
84
+ syntaxComment: 'rgb(128,128,128)',
85
+ syntaxKeyword: 'rgb(215,119,87)', // brand orange
86
+ syntaxFunction: 'rgb(138,190,183)', // teal
87
+ syntaxVariable: 'rgb(224,108,117)', // red-pink
88
+ syntaxString: 'rgb(181,189,104)', // #b5bd68 green
89
+ syntaxNumber: 'rgb(235,159,127)', // amber
90
+ syntaxType: 'rgb(229,192,123)', // yellow
91
+ syntaxOperator: 'rgb(138,190,183)', // teal/cyan
92
+ syntaxPunctuation: 'rgb(198,198,198)', // body text
93
+ userMessageBackground: 'rgb(108,108,108)', // user prompt band
42
94
  userMessageBackgroundHover: 'rgb(120,120,120)', // hover variant
43
95
  fastMode: 'rgb(255,120,20)',
44
96
  };
45
97
 
46
- /* --- Glyphs (refs/claude-code/src/constants/figures.ts) ------------------- */
98
+ /** Teal dark — teal accent, soft body. */
99
+ const piDarkPalette = {
100
+ ...mixdogPalette,
101
+ claude: 'rgb(138,190,183)', // pi accent teal as the title/header accent
102
+ claudeShimmer: 'rgb(170,214,208)',
103
+ spinnerGlyph: 'rgb(138,190,183)',
104
+ spinnerText: 'rgb(138,190,183)',
105
+ spinnerShimmer: 'rgb(170,214,208)',
106
+ panelTitle: 'rgb(138,190,183)',
107
+ thinkingText: 'rgb(190,190,190)',
108
+ statusText: 'rgb(212,212,212)',
109
+ text: 'rgb(212,212,212)', // #d4d4d4
110
+ promptBorder: 'rgb(120,128,140)',
111
+ success: 'rgb(181,189,104)', // #b5bd68
112
+ error: 'rgb(204,102,102)', // #cc6666
113
+ warning: 'rgb(255,255,0)', // #ffff00
114
+ suggestion: 'rgb(95,135,255)', // #5f87ff
115
+ permission: 'rgb(204,102,102)',
116
+ selectionText: 'rgb(26,27,33)',
117
+ selectionBackground: 'rgb(212,212,212)',
118
+ code: 'rgb(95,135,255)',
119
+ codeBlock: 'rgb(181,189,104)',
120
+ mdCodeBlockBorder: 'rgb(96,104,116)',
121
+ mdCodeBlockBg: 'rgb(32,36,44)',
122
+ mdCodeSpanBg: 'rgb(40,44,52)',
123
+ mdLink: 'rgb(95,135,255)',
124
+ mdLinkText: 'rgb(138,190,183)',
125
+ mdStrong: 'rgb(181,189,104)',
126
+ mdEmph: 'rgb(229,192,123)',
127
+ mdDiffAdded: 'rgb(181,189,104)', // #b5bd68
128
+ mdDiffRemoved: 'rgb(204,102,102)', // #cc6666
129
+ mdDiffHunk: 'rgb(129,162,190)',
130
+ mdDiffHeader: 'rgb(178,148,187)',
131
+ mdDiffContext: 'rgb(150,150,150)',
132
+ mdDiffAddedBg: 'rgb(30,46,34)',
133
+ mdDiffRemovedBg: 'rgb(58,32,32)',
134
+ syntaxKeyword: 'rgb(178,148,187)', // pi mauve keyword
135
+ syntaxFunction: 'rgb(129,162,190)', // soft blue
136
+ syntaxString: 'rgb(181,189,104)',
137
+ syntaxNumber: 'rgb(222,147,95)',
138
+ syntaxOperator: 'rgb(138,190,183)',
139
+ userMessageBackground: 'rgb(52,53,65)', // #343541
140
+ userMessageBackgroundHover: 'rgb(64,65,79)',
141
+ };
142
+
143
+ /** Warm dark — orange accent, bright body text. */
144
+ const claudeDarkPalette = {
145
+ ...mixdogPalette,
146
+ background: 'rgb(13,13,13)', // keep the opaque dark surface (Claude's bg is decorative)
147
+ claude: 'rgb(215,119,87)',
148
+ claudeShimmer: 'rgb(235,159,127)',
149
+ spinnerGlyph: 'rgb(215,119,87)',
150
+ spinnerText: 'rgb(215,119,87)',
151
+ spinnerShimmer: 'rgb(255,214,186)',
152
+ panelTitle: 'rgb(215,119,87)',
153
+ text: 'rgb(235,235,235)',
154
+ thinkingText: 'rgb(200,200,200)',
155
+ thinkingBase: 'rgb(153,153,153)',
156
+ thinkingGlow: 'rgb(225,225,225)',
157
+ statusText: 'rgb(220,220,220)',
158
+ statusSubtle: 'rgb(150,150,150)',
159
+ timerText: 'rgb(150,150,150)',
160
+ inactive: 'rgb(153,153,153)',
161
+ subtle: 'rgb(120,120,120)',
162
+ promptBorder: 'rgb(136,136,136)',
163
+ success: 'rgb(78,186,101)',
164
+ error: 'rgb(255,107,128)',
165
+ warning: 'rgb(255,193,7)',
166
+ suggestion: 'rgb(177,185,249)', // blue-purple
167
+ permission: 'rgb(177,185,249)',
168
+ selectionText: 'rgb(13,13,13)',
169
+ selectionBackground: 'rgb(235,235,235)',
170
+ code: 'rgb(177,185,249)',
171
+ codeBlock: 'rgb(200,200,200)', // plain code body (no brand coloring)
172
+ mdHeading: 'rgb(235,159,127)', // warm heading accent
173
+ mdCode: 'rgb(177,185,249)', // inline codespan = permission/suggestion blue-purple
174
+ mdCodeBlock: 'rgb(200,200,200)', // fenced blocks stay plain
175
+ mdQuote: 'rgb(140,140,140)',
176
+ mdQuoteBorder: 'rgb(140,140,140)',
177
+ mdHr: 'rgb(140,140,140)',
178
+ mdListBullet: 'rgb(177,185,249)',
179
+ mdCodeBlockBorder: 'rgb(120,120,120)',
180
+ mdCodeBlockBg: 'rgb(34,35,40)',
181
+ mdCodeSpanBg: 'rgb(42,43,48)',
182
+ mdLink: 'rgb(177,185,249)',
183
+ mdLinkText: 'rgb(150,200,210)',
184
+ mdStrong: 'rgb(235,159,127)',
185
+ mdEmph: 'rgb(229,192,123)',
186
+ mdDiffAdded: 'rgb(78,186,101)',
187
+ mdDiffRemoved: 'rgb(255,107,128)',
188
+ mdDiffHunk: 'rgb(150,160,200)',
189
+ mdDiffHeader: 'rgb(177,185,249)',
190
+ mdDiffContext: 'rgb(150,150,150)',
191
+ mdDiffAddedBg: 'rgb(28,46,34)',
192
+ mdDiffRemovedBg: 'rgb(58,30,36)',
193
+ syntaxComment: 'rgb(140,140,140)',
194
+ syntaxKeyword: 'rgb(235,159,127)',
195
+ syntaxFunction: 'rgb(177,185,249)',
196
+ syntaxVariable: 'rgb(255,107,128)',
197
+ syntaxString: 'rgb(140,200,150)',
198
+ syntaxNumber: 'rgb(235,159,127)',
199
+ syntaxType: 'rgb(229,192,123)',
200
+ syntaxOperator: 'rgb(150,200,210)',
201
+ syntaxPunctuation: 'rgb(220,220,220)',
202
+ userMessageBackground: 'rgb(55,55,55)',
203
+ userMessageBackgroundHover: 'rgb(70,70,70)',
204
+ fastMode: 'rgb(255,120,20)',
205
+ };
206
+
207
+ /** Violet dark — classic purple/pink/cyan contrast. */
208
+ const draculaPalette = {
209
+ ...mixdogPalette,
210
+ background: 'rgb(40,42,54)',
211
+ claude: 'rgb(189,147,249)', // purple
212
+ claudeShimmer: 'rgb(212,182,251)',
213
+ spinnerGlyph: 'rgb(189,147,249)',
214
+ spinnerText: 'rgb(189,147,249)',
215
+ spinnerShimmer: 'rgb(212,182,251)',
216
+ panelTitle: 'rgb(189,147,249)',
217
+ text: 'rgb(248,248,242)',
218
+ thinkingText: 'rgb(180,180,200)',
219
+ thinkingBase: 'rgb(98,114,164)',
220
+ thinkingGlow: 'rgb(220,220,235)',
221
+ statusText: 'rgb(230,230,235)',
222
+ statusSubtle: 'rgb(98,114,164)',
223
+ timerText: 'rgb(98,114,164)',
224
+ inactive: 'rgb(98,114,164)',
225
+ subtle: 'rgb(98,114,164)',
226
+ promptBorder: 'rgb(98,114,164)',
227
+ success: 'rgb(80,250,123)', // green
228
+ error: 'rgb(255,85,85)', // red
229
+ warning: 'rgb(241,250,140)', // yellow
230
+ suggestion: 'rgb(139,233,253)', // cyan
231
+ permission: 'rgb(255,85,85)',
232
+ selectionText: 'rgb(40,42,54)',
233
+ selectionBackground: 'rgb(248,248,242)',
234
+ code: 'rgb(139,233,253)',
235
+ codeBlock: 'rgb(248,248,242)',
236
+ mdHeading: 'rgb(189,147,249)',
237
+ mdCode: 'rgb(80,250,123)',
238
+ mdCodeBlock: 'rgb(248,248,242)',
239
+ mdQuote: 'rgb(98,114,164)',
240
+ mdQuoteBorder: 'rgb(98,114,164)',
241
+ mdHr: 'rgb(98,114,164)',
242
+ mdListBullet: 'rgb(189,147,249)',
243
+ mdCodeBlockBorder: 'rgb(68,71,90)',
244
+ mdCodeBlockBg: 'rgb(60,63,79)',
245
+ mdCodeSpanBg: 'rgb(68,71,87)',
246
+ mdLink: 'rgb(139,233,253)',
247
+ mdLinkText: 'rgb(255,121,198)', // pink
248
+ mdStrong: 'rgb(255,184,108)', // orange
249
+ mdEmph: 'rgb(241,250,140)',
250
+ mdDiffAdded: 'rgb(80,250,123)',
251
+ mdDiffRemoved: 'rgb(255,85,85)',
252
+ mdDiffHunk: 'rgb(98,114,164)',
253
+ mdDiffHeader: 'rgb(255,121,198)',
254
+ mdDiffContext: 'rgb(98,114,164)',
255
+ mdDiffAddedBg: 'rgb(26,58,26)',
256
+ mdDiffRemovedBg: 'rgb(58,26,26)',
257
+ syntaxComment: 'rgb(98,114,164)',
258
+ syntaxKeyword: 'rgb(255,121,198)',
259
+ syntaxFunction: 'rgb(80,250,123)',
260
+ syntaxVariable: 'rgb(248,248,242)',
261
+ syntaxString: 'rgb(241,250,140)',
262
+ syntaxNumber: 'rgb(189,147,249)',
263
+ syntaxType: 'rgb(139,233,253)',
264
+ syntaxOperator: 'rgb(255,121,198)',
265
+ syntaxPunctuation: 'rgb(248,248,242)',
266
+ userMessageBackground: 'rgb(68,71,90)',
267
+ userMessageBackgroundHover: 'rgb(82,85,104)',
268
+ };
269
+
270
+ /** Midnight dark — soft blue/purple contrast. */
271
+ const tokyonightPalette = {
272
+ ...mixdogPalette,
273
+ background: 'rgb(26,27,38)',
274
+ claude: 'rgb(130,170,255)', // blue
275
+ claudeShimmer: 'rgb(170,198,255)',
276
+ spinnerGlyph: 'rgb(130,170,255)',
277
+ spinnerText: 'rgb(130,170,255)',
278
+ spinnerShimmer: 'rgb(170,198,255)',
279
+ panelTitle: 'rgb(130,170,255)',
280
+ text: 'rgb(200,211,245)',
281
+ thinkingText: 'rgb(170,180,210)',
282
+ thinkingBase: 'rgb(130,139,184)',
283
+ thinkingGlow: 'rgb(210,218,250)',
284
+ statusText: 'rgb(200,211,245)',
285
+ statusSubtle: 'rgb(130,139,184)',
286
+ timerText: 'rgb(130,139,184)',
287
+ inactive: 'rgb(130,139,184)',
288
+ subtle: 'rgb(115,122,162)',
289
+ promptBorder: 'rgb(115,122,162)',
290
+ success: 'rgb(195,232,141)',
291
+ error: 'rgb(255,117,127)',
292
+ warning: 'rgb(255,150,108)',
293
+ suggestion: 'rgb(130,170,255)',
294
+ permission: 'rgb(255,117,127)',
295
+ selectionText: 'rgb(26,27,38)',
296
+ selectionBackground: 'rgb(200,211,245)',
297
+ code: 'rgb(130,170,255)',
298
+ codeBlock: 'rgb(200,211,245)',
299
+ mdHeading: 'rgb(192,153,255)', // purple
300
+ mdCode: 'rgb(195,232,141)', // green
301
+ mdCodeBlock: 'rgb(200,211,245)',
302
+ mdQuote: 'rgb(255,199,119)',
303
+ mdQuoteBorder: 'rgb(130,139,184)',
304
+ mdHr: 'rgb(130,139,184)',
305
+ mdListBullet: 'rgb(130,170,255)',
306
+ mdCodeBlockBorder: 'rgb(84,92,126)',
307
+ mdCodeBlockBg: 'rgb(45,47,64)',
308
+ mdCodeSpanBg: 'rgb(53,55,72)',
309
+ mdLink: 'rgb(130,170,255)',
310
+ mdLinkText: 'rgb(134,225,252)', // cyan
311
+ mdStrong: 'rgb(255,150,108)', // orange
312
+ mdEmph: 'rgb(255,199,119)', // yellow
313
+ mdDiffAdded: 'rgb(79,214,190)',
314
+ mdDiffRemoved: 'rgb(197,59,83)',
315
+ mdDiffHunk: 'rgb(130,139,184)',
316
+ mdDiffHeader: 'rgb(192,153,255)',
317
+ mdDiffContext: 'rgb(130,139,184)',
318
+ mdDiffAddedBg: 'rgb(32,48,59)',
319
+ mdDiffRemovedBg: 'rgb(55,34,44)',
320
+ syntaxComment: 'rgb(130,139,184)',
321
+ syntaxKeyword: 'rgb(192,153,255)',
322
+ syntaxFunction: 'rgb(130,170,255)',
323
+ syntaxVariable: 'rgb(255,117,127)',
324
+ syntaxString: 'rgb(195,232,141)',
325
+ syntaxNumber: 'rgb(255,150,108)',
326
+ syntaxType: 'rgb(255,199,119)',
327
+ syntaxOperator: 'rgb(134,225,252)',
328
+ syntaxPunctuation: 'rgb(200,211,245)',
329
+ userMessageBackground: 'rgb(34,36,54)',
330
+ userMessageBackgroundHover: 'rgb(46,49,71)',
331
+ };
332
+
333
+ /** Frost dark — cool arctic blue/teal contrast. */
334
+ const nordPalette = {
335
+ ...mixdogPalette,
336
+ background: 'rgb(46,52,64)',
337
+ claude: 'rgb(136,192,208)', // nord8 frost
338
+ claudeShimmer: 'rgb(168,212,224)',
339
+ spinnerGlyph: 'rgb(136,192,208)',
340
+ spinnerText: 'rgb(136,192,208)',
341
+ spinnerShimmer: 'rgb(168,212,224)',
342
+ panelTitle: 'rgb(136,192,208)',
343
+ text: 'rgb(236,239,244)',
344
+ thinkingText: 'rgb(200,206,218)',
345
+ thinkingBase: 'rgb(139,149,167)',
346
+ thinkingGlow: 'rgb(226,230,238)',
347
+ statusText: 'rgb(216,222,233)',
348
+ statusSubtle: 'rgb(139,149,167)',
349
+ timerText: 'rgb(139,149,167)',
350
+ inactive: 'rgb(139,149,167)',
351
+ subtle: 'rgb(118,128,146)',
352
+ promptBorder: 'rgb(76,86,106)',
353
+ success: 'rgb(163,190,140)',
354
+ error: 'rgb(191,97,106)',
355
+ warning: 'rgb(208,135,112)',
356
+ suggestion: 'rgb(129,161,193)',
357
+ permission: 'rgb(191,97,106)',
358
+ selectionText: 'rgb(46,52,64)',
359
+ selectionBackground: 'rgb(236,239,244)',
360
+ code: 'rgb(129,161,193)',
361
+ codeBlock: 'rgb(216,222,233)',
362
+ mdHeading: 'rgb(136,192,208)',
363
+ mdCode: 'rgb(163,190,140)',
364
+ mdCodeBlock: 'rgb(216,222,233)',
365
+ mdQuote: 'rgb(139,149,167)',
366
+ mdQuoteBorder: 'rgb(139,149,167)',
367
+ mdHr: 'rgb(139,149,167)',
368
+ mdListBullet: 'rgb(136,192,208)',
369
+ mdCodeBlockBorder: 'rgb(67,76,94)',
370
+ mdCodeBlockBg: 'rgb(64,71,87)',
371
+ mdCodeSpanBg: 'rgb(72,79,95)',
372
+ mdLink: 'rgb(129,161,193)',
373
+ mdLinkText: 'rgb(143,188,187)',
374
+ mdStrong: 'rgb(235,203,139)',
375
+ mdEmph: 'rgb(208,135,112)',
376
+ mdDiffAdded: 'rgb(163,190,140)',
377
+ mdDiffRemoved: 'rgb(191,97,106)',
378
+ mdDiffHunk: 'rgb(139,149,167)',
379
+ mdDiffHeader: 'rgb(180,142,173)',
380
+ mdDiffContext: 'rgb(139,149,167)',
381
+ mdDiffAddedBg: 'rgb(50,62,52)',
382
+ mdDiffRemovedBg: 'rgb(70,52,56)',
383
+ syntaxComment: 'rgb(139,149,167)',
384
+ syntaxKeyword: 'rgb(129,161,193)',
385
+ syntaxFunction: 'rgb(136,192,208)',
386
+ syntaxVariable: 'rgb(143,188,187)',
387
+ syntaxString: 'rgb(163,190,140)',
388
+ syntaxNumber: 'rgb(180,142,173)',
389
+ syntaxType: 'rgb(143,188,187)',
390
+ syntaxOperator: 'rgb(129,161,193)',
391
+ syntaxPunctuation: 'rgb(216,222,233)',
392
+ userMessageBackground: 'rgb(67,76,94)',
393
+ userMessageBackgroundHover: 'rgb(76,86,106)',
394
+ };
395
+
396
+ /** Earth dark — retro warm earthy contrast. */
397
+ const gruvboxPalette = {
398
+ ...mixdogPalette,
399
+ background: 'rgb(40,40,40)',
400
+ claude: 'rgb(131,165,152)', // blue-bright
401
+ claudeShimmer: 'rgb(166,194,184)',
402
+ spinnerGlyph: 'rgb(131,165,152)',
403
+ spinnerText: 'rgb(131,165,152)',
404
+ spinnerShimmer: 'rgb(166,194,184)',
405
+ panelTitle: 'rgb(131,165,152)',
406
+ text: 'rgb(235,219,178)',
407
+ thinkingText: 'rgb(213,198,161)',
408
+ thinkingBase: 'rgb(146,131,116)',
409
+ thinkingGlow: 'rgb(240,228,196)',
410
+ statusText: 'rgb(235,219,178)',
411
+ statusSubtle: 'rgb(146,131,116)',
412
+ timerText: 'rgb(146,131,116)',
413
+ inactive: 'rgb(146,131,116)',
414
+ subtle: 'rgb(146,131,116)',
415
+ promptBorder: 'rgb(102,92,84)',
416
+ success: 'rgb(184,187,38)',
417
+ error: 'rgb(251,73,52)',
418
+ warning: 'rgb(254,128,25)',
419
+ suggestion: 'rgb(131,165,152)',
420
+ permission: 'rgb(251,73,52)',
421
+ selectionText: 'rgb(40,40,40)',
422
+ selectionBackground: 'rgb(235,219,178)',
423
+ code: 'rgb(142,192,124)',
424
+ codeBlock: 'rgb(235,219,178)',
425
+ mdHeading: 'rgb(131,165,152)',
426
+ mdCode: 'rgb(250,189,47)',
427
+ mdCodeBlock: 'rgb(235,219,178)',
428
+ mdQuote: 'rgb(146,131,116)',
429
+ mdQuoteBorder: 'rgb(146,131,116)',
430
+ mdHr: 'rgb(146,131,116)',
431
+ mdListBullet: 'rgb(131,165,152)',
432
+ mdCodeBlockBorder: 'rgb(80,73,69)',
433
+ mdCodeBlockBg: 'rgb(60,58,52)',
434
+ mdCodeSpanBg: 'rgb(68,66,60)',
435
+ mdLink: 'rgb(142,192,124)',
436
+ mdLinkText: 'rgb(184,187,38)',
437
+ mdStrong: 'rgb(254,128,25)',
438
+ mdEmph: 'rgb(211,134,155)',
439
+ mdDiffAdded: 'rgb(152,151,26)',
440
+ mdDiffRemoved: 'rgb(204,36,29)',
441
+ mdDiffHunk: 'rgb(104,157,106)',
442
+ mdDiffHeader: 'rgb(211,134,155)',
443
+ mdDiffContext: 'rgb(146,131,116)',
444
+ mdDiffAddedBg: 'rgb(50,48,47)',
445
+ mdDiffRemovedBg: 'rgb(50,41,41)',
446
+ syntaxComment: 'rgb(146,131,116)',
447
+ syntaxKeyword: 'rgb(251,73,52)',
448
+ syntaxFunction: 'rgb(184,187,38)',
449
+ syntaxVariable: 'rgb(131,165,152)',
450
+ syntaxString: 'rgb(250,189,47)',
451
+ syntaxNumber: 'rgb(211,134,155)',
452
+ syntaxType: 'rgb(142,192,124)',
453
+ syntaxOperator: 'rgb(254,128,25)',
454
+ syntaxPunctuation: 'rgb(235,219,178)',
455
+ userMessageBackground: 'rgb(80,73,69)',
456
+ userMessageBackgroundHover: 'rgb(102,92,84)',
457
+ };
458
+
459
+ /** Pastel dark — gentle violet/blue contrast. */
460
+ const catppuccinPalette = {
461
+ ...mixdogPalette,
462
+ background: 'rgb(30,30,46)',
463
+ claude: 'rgb(137,180,250)', // blue
464
+ claudeShimmer: 'rgb(180,190,254)',
465
+ spinnerGlyph: 'rgb(137,180,250)',
466
+ spinnerText: 'rgb(137,180,250)',
467
+ spinnerShimmer: 'rgb(180,190,254)',
468
+ panelTitle: 'rgb(137,180,250)',
469
+ text: 'rgb(205,214,244)',
470
+ thinkingText: 'rgb(186,194,222)',
471
+ thinkingBase: 'rgb(147,153,178)',
472
+ thinkingGlow: 'rgb(215,222,250)',
473
+ statusText: 'rgb(205,214,244)',
474
+ statusSubtle: 'rgb(147,153,178)',
475
+ timerText: 'rgb(147,153,178)',
476
+ inactive: 'rgb(147,153,178)',
477
+ subtle: 'rgb(127,132,156)',
478
+ promptBorder: 'rgb(88,91,112)',
479
+ success: 'rgb(166,227,161)',
480
+ error: 'rgb(243,139,168)',
481
+ warning: 'rgb(249,226,175)',
482
+ suggestion: 'rgb(137,180,250)',
483
+ permission: 'rgb(243,139,168)',
484
+ selectionText: 'rgb(30,30,46)',
485
+ selectionBackground: 'rgb(205,214,244)',
486
+ code: 'rgb(166,227,161)',
487
+ codeBlock: 'rgb(205,214,244)',
488
+ mdHeading: 'rgb(203,166,247)', // mauve
489
+ mdCode: 'rgb(166,227,161)',
490
+ mdCodeBlock: 'rgb(205,214,244)',
491
+ mdQuote: 'rgb(249,226,175)',
492
+ mdQuoteBorder: 'rgb(147,153,178)',
493
+ mdHr: 'rgb(166,173,200)',
494
+ mdListBullet: 'rgb(137,180,250)',
495
+ mdCodeBlockBorder: 'rgb(49,50,68)',
496
+ mdCodeBlockBg: 'rgb(49,50,68)',
497
+ mdCodeSpanBg: 'rgb(57,58,76)',
498
+ mdLink: 'rgb(137,180,250)',
499
+ mdLinkText: 'rgb(137,220,235)', // sky
500
+ mdStrong: 'rgb(250,179,135)', // peach
501
+ mdEmph: 'rgb(249,226,175)',
502
+ mdDiffAdded: 'rgb(166,227,161)',
503
+ mdDiffRemoved: 'rgb(243,139,168)',
504
+ mdDiffHunk: 'rgb(250,179,135)',
505
+ mdDiffHeader: 'rgb(203,166,247)',
506
+ mdDiffContext: 'rgb(147,153,178)',
507
+ mdDiffAddedBg: 'rgb(36,49,43)',
508
+ mdDiffRemovedBg: 'rgb(60,42,50)',
509
+ syntaxComment: 'rgb(147,153,178)',
510
+ syntaxKeyword: 'rgb(203,166,247)',
511
+ syntaxFunction: 'rgb(137,180,250)',
512
+ syntaxVariable: 'rgb(243,139,168)',
513
+ syntaxString: 'rgb(166,227,161)',
514
+ syntaxNumber: 'rgb(250,179,135)',
515
+ syntaxType: 'rgb(249,226,175)',
516
+ syntaxOperator: 'rgb(137,220,235)',
517
+ syntaxPunctuation: 'rgb(205,214,244)',
518
+ userMessageBackground: 'rgb(49,50,68)',
519
+ userMessageBackgroundHover: 'rgb(69,71,90)',
520
+ };
521
+
522
+ /** Forest dark — soft natural green contrast. */
523
+ const everforestPalette = {
524
+ ...mixdogPalette,
525
+ background: 'rgb(45,53,59)',
526
+ claude: 'rgb(167,192,128)', // green
527
+ claudeShimmer: 'rgb(193,212,162)',
528
+ spinnerGlyph: 'rgb(167,192,128)',
529
+ spinnerText: 'rgb(167,192,128)',
530
+ spinnerShimmer: 'rgb(193,212,162)',
531
+ panelTitle: 'rgb(167,192,128)',
532
+ text: 'rgb(211,198,170)',
533
+ thinkingText: 'rgb(189,178,153)',
534
+ thinkingBase: 'rgb(122,132,120)',
535
+ thinkingGlow: 'rgb(220,210,185)',
536
+ statusText: 'rgb(211,198,170)',
537
+ statusSubtle: 'rgb(122,132,120)',
538
+ timerText: 'rgb(122,132,120)',
539
+ inactive: 'rgb(122,132,120)',
540
+ subtle: 'rgb(122,132,120)',
541
+ promptBorder: 'rgb(133,146,137)',
542
+ success: 'rgb(167,192,128)',
543
+ error: 'rgb(230,126,128)',
544
+ warning: 'rgb(230,152,117)',
545
+ suggestion: 'rgb(127,187,179)',
546
+ permission: 'rgb(230,126,128)',
547
+ selectionText: 'rgb(45,53,59)',
548
+ selectionBackground: 'rgb(211,198,170)',
549
+ code: 'rgb(131,192,146)',
550
+ codeBlock: 'rgb(211,198,170)',
551
+ mdHeading: 'rgb(214,153,182)', // purple
552
+ mdCode: 'rgb(167,192,128)',
553
+ mdCodeBlock: 'rgb(211,198,170)',
554
+ mdQuote: 'rgb(219,188,127)',
555
+ mdQuoteBorder: 'rgb(122,132,120)',
556
+ mdHr: 'rgb(122,132,120)',
557
+ mdListBullet: 'rgb(167,192,128)',
558
+ mdCodeBlockBorder: 'rgb(52,63,68)',
559
+ mdCodeBlockBg: 'rgb(62,71,78)',
560
+ mdCodeSpanBg: 'rgb(70,79,86)',
561
+ mdLink: 'rgb(167,192,128)',
562
+ mdLinkText: 'rgb(131,192,146)', // cyan
563
+ mdStrong: 'rgb(230,152,117)', // orange
564
+ mdEmph: 'rgb(219,188,127)', // yellow
565
+ mdDiffAdded: 'rgb(167,192,128)',
566
+ mdDiffRemoved: 'rgb(230,126,128)',
567
+ mdDiffHunk: 'rgb(131,192,146)',
568
+ mdDiffHeader: 'rgb(214,153,182)',
569
+ mdDiffContext: 'rgb(122,132,120)',
570
+ mdDiffAddedBg: 'rgb(40,54,46)',
571
+ mdDiffRemovedBg: 'rgb(58,42,44)',
572
+ syntaxComment: 'rgb(122,132,120)',
573
+ syntaxKeyword: 'rgb(214,153,182)',
574
+ syntaxFunction: 'rgb(167,192,128)',
575
+ syntaxVariable: 'rgb(230,126,128)',
576
+ syntaxString: 'rgb(167,192,128)',
577
+ syntaxNumber: 'rgb(230,152,117)',
578
+ syntaxType: 'rgb(219,188,127)',
579
+ syntaxOperator: 'rgb(131,192,146)',
580
+ syntaxPunctuation: 'rgb(211,198,170)',
581
+ userMessageBackground: 'rgb(52,63,68)',
582
+ userMessageBackgroundHover: 'rgb(61,72,77)',
583
+ };
584
+
585
+ /** Light — near-white surface with high-contrast dark text. */
586
+ const whitePalette = {
587
+ ...mixdogPalette,
588
+ background: 'rgb(250,250,250)',
589
+ text: 'rgb(28,28,30)',
590
+ statusText: 'rgb(40,40,42)',
591
+ statusSubtle: 'rgb(120,120,124)',
592
+ thinkingText: 'rgb(60,60,64)',
593
+ thinkingAccent: 'rgb(110,110,116)',
594
+ thinkingBase: 'rgb(120,120,126)',
595
+ thinkingGlow: 'rgb(80,80,86)',
596
+ timerText: 'rgb(120,120,126)',
597
+ inactive: 'rgb(120,120,126)',
598
+ subtle: 'rgb(140,140,146)',
599
+ promptBorder: 'rgb(180,180,186)',
600
+ inverseText: 'rgb(250,250,250)',
601
+ selectionText: 'rgb(20,20,22)',
602
+ selectionBackground: 'rgb(180,213,255)',
603
+ claude: 'rgb(199,108,78)',
604
+ claudeShimmer: 'rgb(219,128,98)',
605
+ mixdogOrange: 'rgb(199,108,78)',
606
+ mixdogAmber: 'rgb(180,120,40)',
607
+ mixdogIvory: 'rgb(72,68,64)',
608
+ spinnerGlyph: 'rgb(199,108,78)',
609
+ spinnerText: 'rgb(199,108,78)',
610
+ spinnerShimmer: 'rgb(229,148,118)',
611
+ panelTitle: 'rgb(199,108,78)',
612
+ success: 'rgb(34,134,58)',
613
+ error: 'rgb(207,34,46)',
614
+ warning: 'rgb(154,103,0)',
615
+ suggestion: 'rgb(9,105,218)',
616
+ permission: 'rgb(207,34,46)',
617
+ code: 'rgb(9,105,218)',
618
+ codeBlock: 'rgb(36,41,47)',
619
+ mdHeading: 'rgb(130,80,8)',
620
+ mdCode: 'rgb(0,92,197)',
621
+ mdCodeBlock: 'rgb(36,41,47)',
622
+ mdQuote: 'rgb(106,115,125)',
623
+ mdQuoteBorder: 'rgb(175,184,193)',
624
+ mdHr: 'rgb(175,184,193)',
625
+ mdListBullet: 'rgb(9,105,218)',
626
+ mdCodeBlockBorder: 'rgb(200,206,212)',
627
+ mdCodeBlockBg: 'rgb(232,232,236)',
628
+ mdCodeSpanBg: 'rgb(240,240,244)',
629
+ mdLink: 'rgb(9,105,218)',
630
+ mdLinkText: 'rgb(0,92,197)',
631
+ mdStrong: 'rgb(130,80,8)',
632
+ mdEmph: 'rgb(154,103,0)',
633
+ mdDiffAdded: 'rgb(34,134,58)',
634
+ mdDiffRemoved: 'rgb(207,34,46)',
635
+ mdDiffHunk: 'rgb(9,105,218)',
636
+ mdDiffHeader: 'rgb(110,80,170)',
637
+ mdDiffContext: 'rgb(106,115,125)',
638
+ mdDiffAddedBg: 'rgb(218,243,224)',
639
+ mdDiffRemovedBg: 'rgb(255,224,228)',
640
+ syntaxComment: 'rgb(106,115,125)',
641
+ syntaxKeyword: 'rgb(207,34,46)',
642
+ syntaxFunction: 'rgb(9,105,218)',
643
+ syntaxVariable: 'rgb(149,33,110)',
644
+ syntaxString: 'rgb(10,120,60)',
645
+ syntaxNumber: 'rgb(0,92,197)',
646
+ syntaxType: 'rgb(130,80,8)',
647
+ syntaxOperator: 'rgb(36,41,47)',
648
+ syntaxPunctuation: 'rgb(36,41,47)',
649
+ userMessageBackground: 'rgb(232,232,234)',
650
+ userMessageBackgroundHover: 'rgb(222,222,226)',
651
+ fastMode: 'rgb(255,106,0)',
652
+ };
653
+
654
+ // ── Registry / metadata ─────────────────────────────────────────────────────
655
+ const THEME_REGISTRY = {
656
+ mixdog: { id: 'mixdog', label: 'Basic', description: 'Warm dark base with teal markdown accents.', palette: mixdogPalette },
657
+ 'pi-dark': { id: 'pi-dark', label: 'Teal', description: 'Teal accent with soft body text.', palette: piDarkPalette },
658
+ 'claude-dark': { id: 'claude-dark', label: 'Warm', description: 'Orange accent with bright body text.', palette: claudeDarkPalette },
659
+ dracula: { id: 'dracula', label: 'Violet', description: 'Purple/pink accents with cyan links.', palette: draculaPalette },
660
+ tokyonight: { id: 'tokyonight', label: 'Midnight', description: 'Soft blue/purple dark with neon markdown.', palette: tokyonightPalette },
661
+ nord: { id: 'nord', label: 'Frost', description: 'Cool arctic blue/teal dark.', palette: nordPalette },
662
+ gruvbox: { id: 'gruvbox', label: 'Earth', description: 'Retro warm earthy dark with green/orange accents.', palette: gruvboxPalette },
663
+ catppuccin: { id: 'catppuccin', label: 'Pastel', description: 'Gentle pastel violet/blue dark.', palette: catppuccinPalette },
664
+ everforest: { id: 'everforest', label: 'Forest', description: 'Soft natural green dark, easy on the eyes.', palette: everforestPalette },
665
+ white: { id: 'white', label: 'Light', description: 'Bright white background with high-contrast dark text.', palette: whitePalette },
666
+ };
667
+
668
+ const DEFAULT_THEME_ID = 'mixdog';
669
+ const THEME_ORDER = ['mixdog', 'pi-dark', 'claude-dark', 'dracula', 'tokyonight', 'nord', 'gruvbox', 'catppuccin', 'everforest', 'white'];
670
+
671
+ /**
672
+ * Live singleton consumed across the TUI. Seeded with the default palette and
673
+ * mutated in-place by `applyPalette()` so `import { theme }` references stay
674
+ * valid after a theme switch.
675
+ */
676
+ export const theme = { ...mixdogPalette };
677
+
678
+ let _activeThemeId = DEFAULT_THEME_ID;
679
+ let _themeVersion = 0;
680
+
681
+ /** Monotonic counter bumped on every theme switch (cache-invalidation key). */
682
+ export function getThemeVersion() {
683
+ return _themeVersion;
684
+ }
685
+
686
+ /** Active theme id (e.g. 'mixdog'). */
687
+ export function getThemeSetting() {
688
+ return _activeThemeId;
689
+ }
690
+
691
+ /** Coerce any value to a known theme id, falling back to the default. */
692
+ export function resolveThemeId(id) {
693
+ const key = String(id || '').trim();
694
+ return THEME_REGISTRY[key] ? key : DEFAULT_THEME_ID;
695
+ }
696
+
697
+ /** Picker-ready metadata for every theme, in display order. */
698
+ export function listThemes() {
699
+ return THEME_ORDER.filter((id) => THEME_REGISTRY[id]).map((id) => {
700
+ const entry = THEME_REGISTRY[id];
701
+ return {
702
+ id: entry.id,
703
+ label: entry.label,
704
+ description: entry.description,
705
+ current: entry.id === _activeThemeId,
706
+ };
707
+ });
708
+ }
709
+
710
+ export function emitTerminalBackground(rgbString) {
711
+ try {
712
+ const m = /^rgb\((\d+),(\d+),(\d+)\)$/.exec(String(rgbString || '').replace(/\s+/g, ''));
713
+ if (!m) return;
714
+ const hex = (n) => Math.max(0, Math.min(255, Number(n))).toString(16).padStart(2, '0');
715
+ // OSC 11 ; rgb:RR/GG/BB (BEL-terminated). Many terminals also accept #RRGGBB.
716
+ const seq = `\x1b]11;rgb:${hex(m[1])}${hex(m[1])}/${hex(m[2])}${hex(m[2])}/${hex(m[3])}${hex(m[3])}\x07`;
717
+ if (process.stdout && process.stdout.isTTY) process.stdout.write(seq);
718
+ } catch { /* terminals that ignore OSC 11 are harmless */ }
719
+ }
720
+
721
+ function applyPalette(id) {
722
+ const entry = THEME_REGISTRY[resolveThemeId(id)];
723
+ Object.assign(theme, entry.palette);
724
+ _activeThemeId = entry.id;
725
+ _themeVersion += 1;
726
+ emitTerminalBackground(theme.background);
727
+ return entry;
728
+ }
729
+
730
+ /**
731
+ * Apply a theme by id. Unknown ids fall back to the default without throwing.
732
+ * Persists `ui.theme` to mixdog-config.json unless `persist` is false.
733
+ * Returns `{ id, label, description }` for the applied theme.
734
+ */
735
+ export function setThemeSetting(id, { persist = true } = {}) {
736
+ const entry = applyPalette(id);
737
+ if (persist) void persistThemeSetting(entry.id);
738
+ return { id: entry.id, label: entry.label, description: entry.description };
739
+ }
740
+
741
+ // ── Persistence (lazy, dist-aware) ──────────────────────────────────────────
742
+ const CONFIG_MODULE = import.meta.url.replace(/\\/g, '/').includes('/tui/dist/')
743
+ ? '../../runtime/shared/config.mjs'
744
+ : '../runtime/shared/config.mjs';
745
+ let _configModulePromise = null;
746
+ function loadConfigModule() {
747
+ if (!_configModulePromise) _configModulePromise = import(CONFIG_MODULE);
748
+ return _configModulePromise;
749
+ }
750
+
751
+ async function persistThemeSetting(id) {
752
+ try {
753
+ const { updateConfig } = await loadConfigModule();
754
+ updateConfig((cfg) => {
755
+ const ui = cfg && typeof cfg.ui === 'object' && cfg.ui ? cfg.ui : {};
756
+ return { ...cfg, ui: { ...ui, theme: id } };
757
+ });
758
+ } catch {
759
+ // Persistence is best-effort; a missing/locked config must never crash the TUI.
760
+ }
761
+ }
762
+
763
+ /**
764
+ * Read `ui.theme` from mixdog-config.json and apply it (no re-persist). Safe to
765
+ * call once at boot; returns the resolved active id. Unknown/missing values
766
+ * leave the default in place.
767
+ */
768
+ export async function loadThemeSettingFromConfig() {
769
+ try {
770
+ const { readConfig } = await loadConfigModule();
771
+ const cfg = readConfig() || {};
772
+ const stored = cfg && cfg.ui && typeof cfg.ui === 'object' ? cfg.ui.theme : null;
773
+ if (stored && THEME_REGISTRY[resolveThemeId(stored)] && resolveThemeId(stored) === String(stored)) {
774
+ applyPalette(stored);
775
+ }
776
+ } catch {
777
+ // Fall back to the already-applied default theme.
778
+ }
779
+ return _activeThemeId;
780
+ }
781
+
782
+ /* --- Glyphs --------------------------------------------------------------- */
47
783
  import {
48
784
  BLACK_CIRCLE,
49
- POINTER,
50
- EFFORT_LOW,
51
- EFFORT_MEDIUM,
52
- EFFORT_HIGH,
53
- EFFORT_MAX,
54
785
  RESULT_GUTTER_GLYPH,
786
+ RESULT_GUTTER_CONT_GLYPH,
55
787
  } from './figures.mjs';
56
788
 
57
- /** Turn marker — CC BLACK_CIRCLE (`⏺` on macOS; `●` elsewhere). */
789
+ /** Turn marker — BLACK_CIRCLE (`⏺` on macOS; `●` elsewhere). */
58
790
  export const TURN_MARKER = BLACK_CIRCLE;
59
- /** Result-tree gutter — CC MessageResponse style `⎿`, ASCII only when requested. */
791
+ /** Result-tree gutter — `└` (U+2514) padded to a 2-col hanging indent. */
60
792
  export const RESULT_GUTTER = ` ${RESULT_GUTTER_GLYPH} `;
61
- /** Continuation indent aligning under the result content. */
62
- export const RESULT_INDENT = ' ';
63
- /** Prompt prefix glyph before the input CC figures.pointer `❯`. */
64
- export const PROMPT_GLYPH = POINTER;
65
-
66
- /** Effort-level glyphs (figures.ts EFFORT_*). */
67
- export const EFFORT_GLYPH = { low: EFFORT_LOW, medium: EFFORT_MEDIUM, high: EFFORT_HIGH, max: EFFORT_MAX };
793
+ /**
794
+ * Continuation rail for every result row AFTER the first — `│` (U+2502) at the
795
+ * same 2-col hanging indent so a multi-line tool result keeps a continuous left
796
+ * rail under the `└` head. Same width/padding as RESULT_GUTTER so the body text
797
+ * column never shifts between the first and following rows.
798
+ */
799
+ export const RESULT_GUTTER_CONT = ` ${RESULT_GUTTER_CONT_GLYPH} `;