mixdog 0.8.0 → 0.9.0

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