@gonrocca/zero-pi 0.1.71 → 0.1.72

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.
@@ -0,0 +1,7 @@
1
+ export type MarkdownToken = { type?: string; text?: string; lang?: string; raw?: string };
2
+
3
+ const EMPTY_HTML_COMMENT = /^<!--\s*-->$/;
4
+
5
+ export function isEmptyHtmlComment(token: MarkdownToken): boolean {
6
+ return token.type === "html" && typeof token.raw === "string" && EMPTY_HTML_COMMENT.test(token.raw.trim());
7
+ }
@@ -1,5 +1,6 @@
1
1
  import { Markdown, visibleWidth } from "@earendil-works/pi-tui";
2
2
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ import { isEmptyHtmlComment, type MarkdownToken } from "./markdown-cleanup.ts";
3
4
 
4
5
  type MarkdownInstance = {
5
6
  theme: {
@@ -8,10 +9,10 @@ type MarkdownInstance = {
8
9
  codeBlockIndent?: string;
9
10
  highlightCode?: (code: string, lang?: string) => string[];
10
11
  };
11
- renderToken: (token: { type?: string; text?: string; lang?: string }, width: number, nextTokenType?: string, styleContext?: unknown) => string[];
12
+ renderToken: (token: MarkdownToken, width: number, nextTokenType?: string, styleContext?: unknown) => string[];
12
13
  };
13
14
 
14
- const PATCHED = Symbol.for("gon.pi.pretty-code-fences.patched");
15
+ const PATCHED = Symbol.for("gon.pi.pretty-code-fences.patched.v2");
15
16
 
16
17
  function displayLang(lang?: string): string {
17
18
  const raw = (lang ?? "").trim().toLowerCase();
@@ -42,6 +43,8 @@ function patchMarkdownRenderer(): void {
42
43
 
43
44
  const original = proto.renderToken;
44
45
  proto.renderToken = function prettyRenderToken(token, width, nextTokenType, styleContext): string[] {
46
+ if (isEmptyHtmlComment(token)) return [];
47
+
45
48
  if (token?.type !== "code") {
46
49
  return original.call(this, token, width, nextTokenType, styleContext);
47
50
  }
@@ -0,0 +1,155 @@
1
+ // zero-pi — prettier tool execution cards.
2
+ //
3
+ // Runtime patch only: pi owns the ToolExecutionComponent. This extension keeps
4
+ // the visual change defensive and dependency-free for tests by importing pi's
5
+ // component and pi-tui's width helpers dynamically at runtime.
6
+
7
+ const PATCHED = Symbol.for("gon.pi.pretty-tool-cards.patched");
8
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
9
+
10
+ interface ExtensionAPI {}
11
+
12
+ type ToolExecutionClass = {
13
+ prototype: {
14
+ render: (width: number) => string[];
15
+ toolName?: string;
16
+ args?: unknown;
17
+ isPartial?: boolean;
18
+ result?: { isError?: boolean };
19
+ [PATCHED]?: boolean;
20
+ };
21
+ };
22
+
23
+ type WidthFns = {
24
+ visibleWidth: (text: string) => number;
25
+ truncateToWidth: (text: string, maxWidth: number, ellipsis?: string) => string;
26
+ };
27
+
28
+ function rgb(hex: string, text: string): string {
29
+ const clean = hex.replace(/^#/, "");
30
+ const r = Number.parseInt(clean.slice(0, 2), 16);
31
+ const g = Number.parseInt(clean.slice(2, 4), 16);
32
+ const b = Number.parseInt(clean.slice(4, 6), 16);
33
+ return `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
34
+ }
35
+
36
+ const c = {
37
+ border: (s: string) => rgb("#a78bfa", s),
38
+ borderDim: (s: string) => rgb("#3c3552", s),
39
+ cyan: (s: string) => rgb("#35e8ff", s),
40
+ gold: (s: string) => rgb("#ffd166", s),
41
+ mint: (s: string) => rgb("#2dfcb3", s),
42
+ rose: (s: string) => rgb("#ff4f7b", s),
43
+ dim: (s: string) => rgb("#6e657e", s),
44
+ };
45
+
46
+ function stripAnsi(text: string): string {
47
+ return text.replace(ANSI_RE, "");
48
+ }
49
+
50
+ // Width MUST be measured with the same rule pi-tui's doRender validates with:
51
+ // emoji/CJK count as 2 cells, ANSI and OSC sequences count as 0. Inside pi the
52
+ // real pi-tui helpers are injected at register time; this naive fallback only
53
+ // serves tests and non-pi contexts, where nothing enforces terminal width.
54
+ export const fallbackWidthFns: WidthFns = {
55
+ visibleWidth: (text) => stripAnsi(text).length,
56
+ truncateToWidth: (text, maxWidth, ellipsis = "…") => {
57
+ const plain = stripAnsi(text);
58
+ if (plain.length <= maxWidth) return text;
59
+ return plain.slice(0, Math.max(0, maxWidth - 1)) + ellipsis;
60
+ },
61
+ };
62
+
63
+ let widthFns: WidthFns = fallbackWidthFns;
64
+
65
+ export function setWidthFns(fns: WidthFns): void {
66
+ widthFns = fns;
67
+ }
68
+
69
+ function padAnsi(text: string, width: number): string {
70
+ const clipped = widthFns.truncateToWidth(text, width, "…");
71
+ return clipped + " ".repeat(Math.max(0, width - widthFns.visibleWidth(clipped)));
72
+ }
73
+
74
+ function basename(path: string): string {
75
+ return path.split(/[\\/]/).filter(Boolean).pop() ?? path;
76
+ }
77
+
78
+ export function toolCardTitle(toolName: string, args?: unknown): string {
79
+ const name = toolName || "tool";
80
+ if (args && typeof args === "object") {
81
+ const a = args as Record<string, unknown>;
82
+ const path = typeof a.path === "string" ? a.path : typeof a.url === "string" ? a.url : "";
83
+ if (path) {
84
+ const lineRange = typeof a.offset === "number"
85
+ ? `:${a.offset}${typeof a.limit === "number" ? `-${a.offset + a.limit - 1}` : ""}`
86
+ : "";
87
+ return `${name} · ${basename(path)}${lineRange}`;
88
+ }
89
+ const command = typeof a.command === "string" ? a.command.trim() : "";
90
+ if (command) return `${name} · ${command.split(/\s+/).slice(0, 3).join(" ")}`;
91
+ }
92
+ return name;
93
+ }
94
+
95
+ export function toolCardStatus(isPartial: boolean, isError: boolean): { glyph: string; color: (s: string) => string; label: string } {
96
+ if (isPartial) return { glyph: "⠋", color: c.cyan, label: "running" };
97
+ if (isError) return { glyph: "✗", color: c.rose, label: "error" };
98
+ return { glyph: "✓", color: c.mint, label: "ok" };
99
+ }
100
+
101
+ export function frameToolCard(lines: string[], width: number, title: string, status = toolCardStatus(false, false)): string[] {
102
+ if (width < 28) return lines;
103
+ const inner = Math.max(8, width - 4);
104
+ const cleanLines = [...lines];
105
+ while (cleanLines.length > 0 && stripAnsi(cleanLines[0] ?? "").trim() === "") cleanLines.shift();
106
+ while (cleanLines.length > 0 && stripAnsi(cleanLines[cleanLines.length - 1] ?? "").trim() === "") cleanLines.pop();
107
+
108
+ const label = `${status.color(status.glyph)} ${c.gold(title)} ${c.dim(`(${status.label})`)}`;
109
+ const topPrefix = `${c.border("╭─")} ${label} `;
110
+ const topSuffix = c.border("╮");
111
+ const topFill = Math.max(1, width - widthFns.visibleWidth(topPrefix) - widthFns.visibleWidth(topSuffix));
112
+ const bottom = `${c.border("╰")}${c.borderDim("─".repeat(Math.max(1, width - 2)))}${c.border("╯")}`;
113
+
114
+ // Clamp: a title wider than the terminal would also trip doRender's width check.
115
+ const framed = [widthFns.truncateToWidth(`${topPrefix}${c.borderDim("─".repeat(topFill))}${topSuffix}`, width, "…")];
116
+ for (const line of cleanLines) {
117
+ framed.push(`${c.border("│")} ${padAnsi(line, inner)} ${c.border("│")}`);
118
+ }
119
+ framed.push(bottom);
120
+ return framed;
121
+ }
122
+
123
+ export function patchToolCards(ToolExecutionComponent: ToolExecutionClass): boolean {
124
+ const proto = ToolExecutionComponent.prototype;
125
+ if (!proto || typeof proto.render !== "function") return false;
126
+ if (proto[PATCHED]) return false;
127
+ proto[PATCHED] = true;
128
+
129
+ const originalRender = proto.render;
130
+ proto.render = function prettyToolCardRender(width: number): string[] {
131
+ const raw = originalRender.call(this, Math.max(24, width - 4));
132
+ if (raw.length === 0) return raw;
133
+ const status = toolCardStatus(Boolean(this.isPartial), Boolean(this.result?.isError));
134
+ return frameToolCard(raw, width, toolCardTitle(this.toolName ?? "tool", this.args), status);
135
+ };
136
+ return true;
137
+ }
138
+
139
+ export default function (_pi: ExtensionAPI) {
140
+ void Promise.all([
141
+ import("@earendil-works/pi-coding-agent"),
142
+ import("@earendil-works/pi-tui"),
143
+ ])
144
+ .then(([agent, tui]) => {
145
+ const helpers = tui as { visibleWidth?: WidthFns["visibleWidth"]; truncateToWidth?: WidthFns["truncateToWidth"] };
146
+ if (!helpers.visibleWidth || !helpers.truncateToWidth) return;
147
+ setWidthFns({ visibleWidth: helpers.visibleWidth, truncateToWidth: helpers.truncateToWidth });
148
+ const ToolExecutionComponent = (agent as { ToolExecutionComponent?: ToolExecutionClass }).ToolExecutionComponent;
149
+ if (ToolExecutionComponent) patchToolCards(ToolExecutionComponent);
150
+ })
151
+ .catch(() => {
152
+ // Dependencies are only available inside pi's runtime. Tests and non-TUI
153
+ // modes skip the patch instead of rendering cards measured with the fallback.
154
+ });
155
+ }
@@ -0,0 +1,54 @@
1
+ // zero-pi — quick theme switcher for the ZERO theme pack.
2
+
3
+ interface ThemeSwitchCtx {
4
+ ui?: {
5
+ setTheme?: (theme: string) => { success: boolean; error?: string };
6
+ notify?: (message: string, type?: "info" | "warning" | "error") => void;
7
+ };
8
+ }
9
+
10
+ interface PiAPI {
11
+ registerCommand?(name: string, options: { description: string; handler: (args: string, ctx: ThemeSwitchCtx) => unknown }): void;
12
+ }
13
+
14
+ export const ZERO_THEMES = {
15
+ neon: "zero-omp-neon",
16
+ omp: "zero-omp-neon",
17
+ sunset: "zero-sunset",
18
+ sdd: "zero-sdd",
19
+ sith: "zero-sith",
20
+ saiyan: "zero-saiyan",
21
+ matrix: "zero-matrix",
22
+ cyberpunk: "zero-cyberpunk",
23
+ } as const;
24
+
25
+ export type ZeroThemeAlias = keyof typeof ZERO_THEMES;
26
+
27
+ export function resolveZeroTheme(input: string): string | undefined {
28
+ const raw = input.trim().toLowerCase();
29
+ if (!raw) return undefined;
30
+ return ZERO_THEMES[raw as ZeroThemeAlias] ?? (raw.startsWith("zero-") ? raw : undefined);
31
+ }
32
+
33
+ export function zeroThemeUsage(): string {
34
+ return "Uso: /zero-theme neon|sunset|sdd|sith|saiyan|matrix|cyberpunk";
35
+ }
36
+
37
+ export default function register(api?: PiAPI): void {
38
+ api?.registerCommand?.("zero-theme", {
39
+ description: "Switch between ZERO theme pack variants",
40
+ handler: (args, ctx) => {
41
+ const theme = resolveZeroTheme(args);
42
+ if (!theme) {
43
+ ctx.ui?.notify?.(zeroThemeUsage(), "warning");
44
+ return;
45
+ }
46
+ const result = ctx.ui?.setTheme?.(theme);
47
+ if (!result?.success) {
48
+ ctx.ui?.notify?.(`No pude activar ${theme}: ${result?.error ?? "theme no encontrado"}`, "error");
49
+ return;
50
+ }
51
+ ctx.ui?.notify?.(`ZERO theme activo: ${theme}`, "info");
52
+ },
53
+ });
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gonrocca/zero-pi",
3
- "version": "0.1.71",
3
+ "version": "0.1.72",
4
4
  "description": "zero-pi — an installable layer for pi (pi.dev): the zero spec-driven development workflow (clarify → explore → plan → analyze → build → veredicto) with automatic clarify/analyze gates, per-phase model autotune, and token-efficient batched builds. Adds capability to pi without modifying pi.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -26,8 +26,10 @@
26
26
  "extensions": [
27
27
  "./extensions/zero-banner.ts",
28
28
  "./extensions/zero-hud.ts",
29
+ "./extensions/zero-theme.ts",
29
30
  "./extensions/zero-pretty-code-fences.ts",
30
31
  "./extensions/zero-pretty-input-box.ts",
32
+ "./extensions/zero-pretty-tool-cards.ts",
31
33
  "./extensions/zero-activity-panel.ts",
32
34
  "./extensions/working-phrases.ts",
33
35
  "./extensions/win-tree-kill.ts",
@@ -58,8 +60,11 @@
58
60
  "assets/preview.png",
59
61
  "extensions/zero-banner.ts",
60
62
  "extensions/zero-hud.ts",
63
+ "extensions/zero-theme.ts",
61
64
  "extensions/zero-pretty-code-fences.ts",
65
+ "extensions/markdown-cleanup.ts",
62
66
  "extensions/zero-pretty-input-box.ts",
67
+ "extensions/zero-pretty-tool-cards.ts",
63
68
  "extensions/zero-activity-panel.ts",
64
69
  "extensions/zero-statusline.ts",
65
70
  "extensions/working-phrases.ts",
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "zero-cyberpunk",
4
+ "vars": {
5
+ "bg": "#080713",
6
+ "panel": "#111026",
7
+ "panel2": "#1a1235",
8
+ "panelTool": "#101c32",
9
+ "panelOk": "#09231f",
10
+ "panelErr": "#2b0b20",
11
+ "selected": "#2d1a4f",
12
+ "textMain": "#f3ecff",
13
+ "prose": "#cbbde8",
14
+ "muted": "#9f8bc0",
15
+ "dim": "#625176",
16
+ "magenta": "#ff2bd6",
17
+ "pink": "#ff5dba",
18
+ "cyan": "#00e5ff",
19
+ "yellow": "#ffe156",
20
+ "violet": "#9b5cff",
21
+ "mint": "#37ffbf",
22
+ "orange": "#ff8c42",
23
+ "red": "#ff3864"
24
+ },
25
+ "colors": {
26
+ "accent": "magenta",
27
+ "border": "cyan",
28
+ "borderAccent": "magenta",
29
+ "borderMuted": "dim",
30
+ "success": "mint",
31
+ "error": "red",
32
+ "warning": "yellow",
33
+ "muted": "muted",
34
+ "dim": "dim",
35
+ "text": "textMain",
36
+ "thinkingText": "prose",
37
+ "selectedBg": "selected",
38
+ "userMessageBg": "panel2",
39
+ "userMessageText": "yellow",
40
+ "customMessageBg": "panel",
41
+ "customMessageText": "prose",
42
+ "customMessageLabel": "cyan",
43
+ "toolPendingBg": "panel2",
44
+ "toolSuccessBg": "panelTool",
45
+ "toolErrorBg": "panelErr",
46
+ "toolTitle": "magenta",
47
+ "toolOutput": "prose",
48
+ "mdHeading": "cyan",
49
+ "mdLink": "magenta",
50
+ "mdLinkUrl": "cyan",
51
+ "mdCode": "mint",
52
+ "mdCodeBlock": "mint",
53
+ "mdCodeBlockBorder": "cyan",
54
+ "mdQuote": "muted",
55
+ "mdQuoteBorder": "dim",
56
+ "mdHr": "dim",
57
+ "mdListBullet": "yellow",
58
+ "toolDiffAdded": "mint",
59
+ "toolDiffRemoved": "red",
60
+ "toolDiffContext": "muted",
61
+ "syntaxComment": "dim",
62
+ "syntaxKeyword": "magenta",
63
+ "syntaxFunction": "cyan",
64
+ "syntaxVariable": "yellow",
65
+ "syntaxString": "mint",
66
+ "syntaxNumber": "orange",
67
+ "syntaxType": "violet",
68
+ "syntaxOperator": "red",
69
+ "syntaxPunctuation": "muted",
70
+ "thinkingOff": "dim",
71
+ "thinkingMinimal": "muted",
72
+ "thinkingLow": "cyan",
73
+ "thinkingMedium": "yellow",
74
+ "thinkingHigh": "magenta",
75
+ "thinkingXhigh": "pink",
76
+ "bashMode": "magenta"
77
+ },
78
+ "export": { "pageBg": "#080713", "cardBg": "#111026", "infoBg": "#1a1235" }
79
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "zero-matrix",
4
+ "vars": {
5
+ "bg": "#020604",
6
+ "panel": "#07110c",
7
+ "panel2": "#0a1710",
8
+ "panelTool": "#081a12",
9
+ "panelOk": "#092013",
10
+ "panelErr": "#1c090b",
11
+ "selected": "#102b1b",
12
+ "textMain": "#dfffe8",
13
+ "prose": "#a8d8b5",
14
+ "muted": "#78a886",
15
+ "dim": "#3d6048",
16
+ "green": "#00ff66",
17
+ "lime": "#b6ff4d",
18
+ "mint": "#5cffc4",
19
+ "teal": "#00d9a3",
20
+ "amber": "#d4ff62",
21
+ "red": "#ff4d6d",
22
+ "cyan": "#6fffe9"
23
+ },
24
+ "colors": {
25
+ "accent": "green",
26
+ "border": "green",
27
+ "borderAccent": "lime",
28
+ "borderMuted": "dim",
29
+ "success": "green",
30
+ "error": "red",
31
+ "warning": "amber",
32
+ "muted": "muted",
33
+ "dim": "dim",
34
+ "text": "textMain",
35
+ "thinkingText": "prose",
36
+ "selectedBg": "selected",
37
+ "userMessageBg": "panel2",
38
+ "userMessageText": "lime",
39
+ "customMessageBg": "panel",
40
+ "customMessageText": "prose",
41
+ "customMessageLabel": "green",
42
+ "toolPendingBg": "panel2",
43
+ "toolSuccessBg": "panelTool",
44
+ "toolErrorBg": "panelErr",
45
+ "toolTitle": "lime",
46
+ "toolOutput": "prose",
47
+ "mdHeading": "green",
48
+ "mdLink": "cyan",
49
+ "mdLinkUrl": "teal",
50
+ "mdCode": "mint",
51
+ "mdCodeBlock": "mint",
52
+ "mdCodeBlockBorder": "green",
53
+ "mdQuote": "muted",
54
+ "mdQuoteBorder": "dim",
55
+ "mdHr": "dim",
56
+ "mdListBullet": "green",
57
+ "toolDiffAdded": "green",
58
+ "toolDiffRemoved": "red",
59
+ "toolDiffContext": "muted",
60
+ "syntaxComment": "dim",
61
+ "syntaxKeyword": "green",
62
+ "syntaxFunction": "lime",
63
+ "syntaxVariable": "cyan",
64
+ "syntaxString": "mint",
65
+ "syntaxNumber": "amber",
66
+ "syntaxType": "teal",
67
+ "syntaxOperator": "red",
68
+ "syntaxPunctuation": "muted",
69
+ "thinkingOff": "dim",
70
+ "thinkingMinimal": "muted",
71
+ "thinkingLow": "teal",
72
+ "thinkingMedium": "lime",
73
+ "thinkingHigh": "green",
74
+ "thinkingXhigh": "cyan",
75
+ "bashMode": "green"
76
+ },
77
+ "export": { "pageBg": "#020604", "cardBg": "#07110c", "infoBg": "#0a1710" }
78
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "zero-saiyan",
4
+ "vars": {
5
+ "bg": "#080b16",
6
+ "panel": "#10182b",
7
+ "panel2": "#17213a",
8
+ "panelTool": "#10243a",
9
+ "panelOk": "#10281d",
10
+ "panelErr": "#2a1212",
11
+ "selected": "#25365c",
12
+ "textMain": "#f5f0df",
13
+ "prose": "#d7caa8",
14
+ "muted": "#aa9b75",
15
+ "dim": "#6e654a",
16
+ "gold": "#ffd60a",
17
+ "ki": "#ffb703",
18
+ "orange": "#ff7a00",
19
+ "blue": "#4cc9f0",
20
+ "royal": "#4361ee",
21
+ "mint": "#51ffb6",
22
+ "rose": "#ff5d73",
23
+ "white": "#fff7cc"
24
+ },
25
+ "colors": {
26
+ "accent": "gold",
27
+ "border": "blue",
28
+ "borderAccent": "gold",
29
+ "borderMuted": "dim",
30
+ "success": "mint",
31
+ "error": "rose",
32
+ "warning": "orange",
33
+ "muted": "muted",
34
+ "dim": "dim",
35
+ "text": "textMain",
36
+ "thinkingText": "prose",
37
+ "selectedBg": "selected",
38
+ "userMessageBg": "panel2",
39
+ "userMessageText": "gold",
40
+ "customMessageBg": "panel",
41
+ "customMessageText": "prose",
42
+ "customMessageLabel": "blue",
43
+ "toolPendingBg": "panel2",
44
+ "toolSuccessBg": "panelTool",
45
+ "toolErrorBg": "panelErr",
46
+ "toolTitle": "gold",
47
+ "toolOutput": "prose",
48
+ "mdHeading": "gold",
49
+ "mdLink": "blue",
50
+ "mdLinkUrl": "royal",
51
+ "mdCode": "mint",
52
+ "mdCodeBlock": "mint",
53
+ "mdCodeBlockBorder": "blue",
54
+ "mdQuote": "muted",
55
+ "mdQuoteBorder": "dim",
56
+ "mdHr": "dim",
57
+ "mdListBullet": "gold",
58
+ "toolDiffAdded": "mint",
59
+ "toolDiffRemoved": "rose",
60
+ "toolDiffContext": "muted",
61
+ "syntaxComment": "dim",
62
+ "syntaxKeyword": "blue",
63
+ "syntaxFunction": "gold",
64
+ "syntaxVariable": "ki",
65
+ "syntaxString": "mint",
66
+ "syntaxNumber": "orange",
67
+ "syntaxType": "royal",
68
+ "syntaxOperator": "rose",
69
+ "syntaxPunctuation": "muted",
70
+ "thinkingOff": "dim",
71
+ "thinkingMinimal": "muted",
72
+ "thinkingLow": "blue",
73
+ "thinkingMedium": "gold",
74
+ "thinkingHigh": "orange",
75
+ "thinkingXhigh": "white",
76
+ "bashMode": "gold"
77
+ },
78
+ "export": { "pageBg": "#080b16", "cardBg": "#10182b", "infoBg": "#17213a" }
79
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "zero-sith",
4
+ "vars": {
5
+ "bg": "#07060a",
6
+ "panel": "#130911",
7
+ "panel2": "#1b0d18",
8
+ "panelTool": "#1a101d",
9
+ "panelOk": "#10191a",
10
+ "panelErr": "#2a0710",
11
+ "selected": "#311026",
12
+ "textMain": "#f3e8ef",
13
+ "prose": "#cdb7c6",
14
+ "muted": "#a98999",
15
+ "dim": "#705160",
16
+ "red": "#ff335f",
17
+ "crimson": "#c9184a",
18
+ "saber": "#ff1744",
19
+ "violet": "#9d4edd",
20
+ "purple": "#c77dff",
21
+ "amber": "#ffb703",
22
+ "cyan": "#43d9ff",
23
+ "mint": "#4dffc3"
24
+ },
25
+ "colors": {
26
+ "accent": "saber",
27
+ "border": "crimson",
28
+ "borderAccent": "saber",
29
+ "borderMuted": "dim",
30
+ "success": "mint",
31
+ "error": "red",
32
+ "warning": "amber",
33
+ "muted": "muted",
34
+ "dim": "dim",
35
+ "text": "textMain",
36
+ "thinkingText": "prose",
37
+ "selectedBg": "selected",
38
+ "userMessageBg": "panel2",
39
+ "userMessageText": "red",
40
+ "customMessageBg": "panel",
41
+ "customMessageText": "prose",
42
+ "customMessageLabel": "purple",
43
+ "toolPendingBg": "panel2",
44
+ "toolSuccessBg": "panelTool",
45
+ "toolErrorBg": "panelErr",
46
+ "toolTitle": "red",
47
+ "toolOutput": "prose",
48
+ "mdHeading": "purple",
49
+ "mdLink": "cyan",
50
+ "mdLinkUrl": "violet",
51
+ "mdCode": "mint",
52
+ "mdCodeBlock": "mint",
53
+ "mdCodeBlockBorder": "crimson",
54
+ "mdQuote": "muted",
55
+ "mdQuoteBorder": "dim",
56
+ "mdHr": "dim",
57
+ "mdListBullet": "red",
58
+ "toolDiffAdded": "mint",
59
+ "toolDiffRemoved": "red",
60
+ "toolDiffContext": "muted",
61
+ "syntaxComment": "dim",
62
+ "syntaxKeyword": "purple",
63
+ "syntaxFunction": "red",
64
+ "syntaxVariable": "amber",
65
+ "syntaxString": "mint",
66
+ "syntaxNumber": "cyan",
67
+ "syntaxType": "violet",
68
+ "syntaxOperator": "red",
69
+ "syntaxPunctuation": "muted",
70
+ "thinkingOff": "dim",
71
+ "thinkingMinimal": "muted",
72
+ "thinkingLow": "violet",
73
+ "thinkingMedium": "amber",
74
+ "thinkingHigh": "red",
75
+ "thinkingXhigh": "purple",
76
+ "bashMode": "red"
77
+ },
78
+ "export": { "pageBg": "#07060a", "cardBg": "#130911", "infoBg": "#1b0d18" }
79
+ }