@bismawy/pi-arnative 0.2.11 → 0.3.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.
package/lib/color.ts ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * OKLCH color math — the single source of truth for theme generation
3
+ * (`themes/gen-themes.mjs`) and the theme self-check
4
+ * (`extensions/ui-render-tweaks.ts`). No dependencies.
5
+ */
6
+ import { assert, isMain } from "./check.ts";
7
+
8
+ interface Rgb {
9
+ r: number;
10
+ g: number;
11
+ b: number;
12
+ }
13
+ interface Oklch {
14
+ L: number;
15
+ C: number;
16
+ H: number;
17
+ }
18
+
19
+ const clamp01 = (x: number): number => (x < 0 ? 0 : x > 1 ? 1 : x);
20
+
21
+ /** `"oklch(62% 0.1 200)"` or `"oklch(0.62 0.1 200)"` -> Oklch, or null when not OKLCH. */
22
+ export function parseOklch(value: string): Oklch | null {
23
+ const m = /^oklch\(\s*([0-9]*\.?[0-9]+)(%?)\s+([0-9]*\.?[0-9]+)\s+([0-9]*\.?[0-9]+)(?:deg)?\s*\)$/i.exec(value.trim());
24
+ if (!m) return null;
25
+ const raw = Number(m[1]);
26
+ return { L: m[2] === "%" ? raw / 100 : raw, C: Number(m[3]), H: Number(m[4]) };
27
+ }
28
+
29
+ function linearFromOklab(L: number, C: number, H: number): [number, number, number] {
30
+ const h = (H * Math.PI) / 180;
31
+ const a = C * Math.cos(h);
32
+ const b = C * Math.sin(h);
33
+ const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
34
+ const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
35
+ const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
36
+ return [
37
+ 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
38
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
39
+ -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,
40
+ ];
41
+ }
42
+
43
+ const encode = (c: number): number => (c <= 0.0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055);
44
+ const inGamut = (rgb: readonly number[]): boolean => rgb.every((c) => c >= -1e-4 && c <= 1 + 1e-4);
45
+
46
+ /** OKLCH -> sRGB, reducing chroma until the result fits sRGB. Returns the chroma actually used. */
47
+ export function oklchToRgb(L: number, C: number, H: number): Rgb & { chroma: number } {
48
+ let used = C;
49
+ if (!inGamut(linearFromOklab(L, C, H))) {
50
+ let lo = 0;
51
+ let hi = C;
52
+ for (let i = 0; i < 24; i++) {
53
+ const mid = (lo + hi) / 2;
54
+ if (inGamut(linearFromOklab(L, mid, H))) lo = mid;
55
+ else hi = mid;
56
+ }
57
+ used = lo;
58
+ }
59
+ const [r, g, b] = linearFromOklab(L, used, H).map((c) => clamp01(encode(c)));
60
+ return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), chroma: used };
61
+ }
62
+
63
+ const oklchToHex = (L: number, C: number, H: number): string => {
64
+ const { r, g, b } = oklchToRgb(L, C, H);
65
+ return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
66
+ };
67
+
68
+ /** Any theme color value (hex or oklch) -> lowercase `#rrggbb`. Throws otherwise. */
69
+ export function toHex(value: string): string {
70
+ const v = value.trim();
71
+ if (/^#[0-9a-f]{6}$/i.test(v)) return v.toLowerCase();
72
+ if (/^#[0-9a-f]{3}$/i.test(v)) return `#${v.slice(1).split("").map((c) => c + c).join("")}`.toLowerCase();
73
+ const o = parseOklch(v);
74
+ if (o) return oklchToHex(o.L, o.C, o.H);
75
+ throw new Error(`Not a hex/oklch color: ${value}`);
76
+ }
77
+
78
+ function relativeLuminance(hex: string): number {
79
+ const [r, g, b] = [1, 3, 5]
80
+ .map((i) => parseInt(hex.slice(i, i + 2), 16) / 255)
81
+ .map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4));
82
+ return 0.2126 * r! + 0.7152 * g! + 0.0722 * b!;
83
+ }
84
+
85
+ export function contrast(a: string, b: string): number {
86
+ const [hi, lo] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
87
+ return (hi! + 0.05) / (lo! + 0.05);
88
+ }
89
+
90
+ /** sRGB hex -> OKLCH (seeds a theme's hue from a reference color). */
91
+ export function hexToOklch(hex: string): Oklch {
92
+ const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
93
+ const lin = [r!, g!, b!].map((c) => (c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4));
94
+ const l = Math.cbrt(0.4122214708 * lin[0]! + 0.5363325363 * lin[1]! + 0.0514459929 * lin[2]!);
95
+ const m = Math.cbrt(0.2119034982 * lin[0]! + 0.6806995451 * lin[1]! + 0.1073969566 * lin[2]!);
96
+ const s = Math.cbrt(0.0883024619 * lin[0]! + 0.2817188376 * lin[1]! + 0.6299787005 * lin[2]!);
97
+ const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
98
+ const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
99
+ const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
100
+ return { L, C: Math.hypot(A, B), H: ((Math.atan2(B, A) * 180) / Math.PI + 360) % 360 };
101
+ }
102
+
103
+ if (isMain(import.meta.url)) {
104
+ const o = parseOklch("oklch(62% 0.1 200)");
105
+ assert(o !== null && Math.abs(o.L - 0.62) < 1e-9 && o.C === 0.1 && o.H === 200, "parseOklch reads percent L");
106
+ assert(parseOklch("oklch(0.62 0.1 200)")?.L === 0.62, "parseOklch reads fractional L");
107
+ assert(parseOklch("#fff") === null, "parseOklch rejects hex");
108
+ assert(toHex("#0AF") === "#00aaff", "toHex expands #rgb");
109
+ assert(toHex("oklch(100% 0 0)") === "#ffffff", "toHex converts oklch to hex");
110
+ assert(oklchToHex(1, 0, 0) === "#ffffff", "oklch L=1 is white");
111
+ assert(oklchToHex(0, 0, 0) === "#000000", "oklch L=0 is black");
112
+ assert(contrast("#ffffff", "#000000") === 21, "white on black = 21:1");
113
+ assert(Math.abs(contrast("#000000", "#ffffff") - 21) < 1e-9, "contrast is order-independent");
114
+ const back = hexToOklch("#00d7ff");
115
+ assert(Math.abs(back.H - 218) < 6, `hexToOklch hue of #00d7ff ~218 (got ${back.H.toFixed(1)})`);
116
+ assert(oklchToRgb(0.7, 0.4, 145).chroma < 0.4, "out-of-gamut chroma is reduced");
117
+ console.log("lib/color.ts OK");
118
+ }
package/lib/format.ts CHANGED
@@ -23,6 +23,12 @@ export function modelDisplayParts(model?: { id?: string; name?: string; provider
23
23
  return { name, provider };
24
24
  }
25
25
 
26
+ // Picker rows for every /arnative list (themes, header & footer presets):
27
+ // `● name` marks the active entry, everything else gets a two-space indent.
28
+ export function markedLabels(names: readonly string[], current: string | undefined): string[] {
29
+ return names.map((n) => `${n === current ? "● " : " "}${n}`);
30
+ }
31
+
26
32
  // Expand-hint key follows the active keybinding; outside a pi session keyText() is empty.
27
33
  export function expandKeyName(): string {
28
34
  try {
@@ -10,7 +10,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSy
10
10
  import { dirname, join } from "node:path";
11
11
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
12
12
 
13
- export interface UsageEntry {
13
+ interface UsageEntry {
14
14
  provider: string;
15
15
  model: string;
16
16
  input: number;
@@ -19,14 +19,14 @@ export interface UsageEntry {
19
19
  cost: number;
20
20
  }
21
21
 
22
- export interface FileCacheItem {
22
+ interface FileCacheItem {
23
23
  mtimeMs: number;
24
24
  size: number;
25
25
  v?: number;
26
26
  entries: UsageEntry[];
27
27
  }
28
28
 
29
- export interface UsageModelStats {
29
+ interface UsageModelStats {
30
30
  name: string;
31
31
  sessions: number;
32
32
  msgs: number;
@@ -37,7 +37,7 @@ export interface UsageModelStats {
37
37
  cost: number;
38
38
  }
39
39
 
40
- export interface UsageProviderStats {
40
+ interface UsageProviderStats {
41
41
  name: string;
42
42
  sessions: number;
43
43
  msgs: number;
@@ -62,20 +62,19 @@ export interface UsageSummary {
62
62
  };
63
63
  }
64
64
 
65
+ /** Scaled value with 1 decimal ("2.5k"); a value that rounds up to the next unit is promoted (999,999 -> "1M", not "1000k"). */
66
+ const fmtUnit = (v: number, unit: string, next: string): string => {
67
+ const s = v.toFixed(1).replace(/\.0$/, "");
68
+ return s === "1000" ? `1${next}` : `${s}${unit}`;
69
+ };
70
+
65
71
  /** Token count with k/M/B units; 0 or negative = "-". */
66
72
  export function formatTokens(n: number): string {
67
73
  if (!n || n <= 0) return "-";
68
74
  if (n < 1000) return String(n);
69
- if (n < 1_000_000) {
70
- const k = n / 1000;
71
- return `${k < 10 ? k.toFixed(1) : Math.round(k)}k`;
72
- }
73
- if (n < 1_000_000_000) {
74
- const m = n / 1_000_000;
75
- return `${m.toFixed(1).replace(/\.0$/, "")}M`;
76
- }
77
- const b = n / 1_000_000_000;
78
- return `${b.toFixed(1).replace(/\.0$/, "")}B`;
75
+ if (n < 1_000_000) return fmtUnit(n / 1000, "k", "M");
76
+ if (n < 1_000_000_000) return fmtUnit(n / 1_000_000, "M", "B");
77
+ return fmtUnit(n / 1_000_000_000, "B", "T");
79
78
  }
80
79
 
81
80
  const CACHE_FILE_PATH = join(getAgentDir(), "arnative-usage-cache.json");
@@ -258,6 +257,15 @@ export function collectUsageSummary(forceScan = false): UsageSummary {
258
257
  }
259
258
  }
260
259
 
260
+ // Session files deleted on disk must leave the cache, or the file grows forever.
261
+ const known = new Set(files);
262
+ for (const k of diskCache.keys()) {
263
+ if (!known.has(k)) {
264
+ diskCache.delete(k);
265
+ cacheDirty = true;
266
+ }
267
+ }
268
+
261
269
  if (cacheDirty) {
262
270
  saveDiskCache(diskCache);
263
271
  }
@@ -328,7 +336,6 @@ export function collectUsageSummary(forceScan = false): UsageSummary {
328
336
 
329
337
  // Match model names across id shapes ("gemini-3.8-flash", "vendor/gemini-…").
330
338
  const modelMatches = (mNameLower: string, targetLower: string): boolean =>
331
- !targetLower ||
332
339
  mNameLower === targetLower ||
333
340
  mNameLower.endsWith("/" + targetLower) ||
334
341
  mNameLower.split(":")[0] === targetLower ||
@@ -336,12 +343,14 @@ const modelMatches = (mNameLower: string, targetLower: string): boolean =>
336
343
 
337
344
  /** All-time usage for one model (same numbers as /usage; the active session is already in its own file). */
338
345
  export function getModelAllTimeUsage(modelId?: string): { input: number; output: number; cacheRead: number } {
346
+ // An empty target used to match EVERY model -> the Model tab showed the grand total under "No Model".
347
+ if (!modelId) return { input: 0, output: 0, cacheRead: 0 };
339
348
  const summary = collectUsageSummary();
340
349
  let inp = 0;
341
350
  let out = 0;
342
351
  let read = 0;
343
352
 
344
- const target = (modelId || "").toLowerCase();
353
+ const target = modelId.toLowerCase();
345
354
  for (const p of summary.providers) {
346
355
  for (const m of p.models) {
347
356
  if (modelMatches(m.name.toLowerCase(), target)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bismawy/pi-arnative",
3
- "version": "0.2.11",
3
+ "version": "0.3.0",
4
4
  "description": "Arnative look for Pi: warm-neutral themes, rounded tool boxes, tabbed header, compact footer, transcript clock, and a /usage dashboard.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -22,6 +22,7 @@
22
22
  "lib",
23
23
  "themes",
24
24
  "CHANGELOG.md",
25
+ "LICENSE",
25
26
  "README.md"
26
27
  ],
27
28
  "pi": {
@@ -39,8 +40,8 @@
39
40
  "@earendil-works/pi-tui": "*"
40
41
  },
41
42
  "scripts": {
42
- "dev": "pi --extension ./extensions/tools.ts --extension ./extensions/section-headers.ts --extension ./extensions/footer.ts --extension ./extensions/timestamps.ts --extension ./extensions/ui-render-tweaks.ts --extension ./extensions/usage.ts",
43
- "test": "node lib/box.ts && node lib/ansi.ts && node lib/shortcuts.ts && node themes/gen-themes.mjs --check && node extensions/tools.ts && node extensions/footer.ts && node extensions/timestamps.ts && node extensions/section-headers.ts && node extensions/ui-render-tweaks.ts && node extensions/usage.ts",
43
+ "dev": "pi --extension ./extensions/tools.ts --extension ./extensions/section-headers.ts --extension ./extensions/footer.ts --extension ./extensions/timestamps.ts --extension ./extensions/ui-render-tweaks.ts --extension ./extensions/usage.ts --extension ./extensions/arnative.ts",
44
+ "test": "node lib/box.ts && node lib/ansi.ts && node lib/shortcuts.ts && node themes/gen-themes.mjs --check && node extensions/tools.ts && node extensions/footer.ts && node extensions/timestamps.ts && node extensions/section-headers.ts && node extensions/ui-render-tweaks.ts && node extensions/usage.ts && node extensions/arnative.ts",
44
45
  "themes": "node themes/gen-themes.mjs"
45
46
  }
46
47
  }
@@ -1,94 +1,86 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
3
  "name": "arnative-cyberpunk",
4
+ "appearance": "dark",
4
5
  "vars": {
5
- "cyan": "#00f0ff",
6
- "blue": "#2a7fd4",
7
- "green": "#00ff9f",
8
- "red": "#ff4d6d",
9
- "yellow": "#ffe600",
10
- "text": "#eaeaf5",
11
- "gray": "#8b88a8",
12
- "dimGray": "#6f6a9a",
13
- "darkGray": "#4a4763",
14
- "accent": "#ff2e97",
15
- "softCyan": "#7fd8f0",
16
- "searchBg": "#5f3349",
17
- "selectedBg": "#2b2350",
18
- "userMsgBg": "#16131f",
19
- "toolPendingBg": "#0d0b16",
20
- "toolSuccessBg": "#0d2430",
21
- "toolErrorBg": "#3a1524",
22
- "customMsgBg": "#1a1329"
6
+ "fg": "oklch(88% 0.02 275)",
7
+ "fgMuted": "oklch(72% 0.02 275)",
8
+ "fgDim": "oklch(61% 0.02 275)",
9
+ "fgFaint": "oklch(49% 0.02 275)",
10
+ "accent": "oklch(78% 0.144 357)",
11
+ "accentSoft": "oklch(82% 0.036 357)",
12
+ "accentBorder": "oklch(82% 0.113 357)",
13
+ "success": "oklch(78% 0.15 145)",
14
+ "error": "oklch(76% 0.143 25)",
15
+ "warning": "oklch(86% 0.14 85)",
16
+ "surfaceMsg": "oklch(16% 0.01 275)"
23
17
  },
24
18
  "colors": {
25
19
  "accent": "accent",
26
- "tint": "softCyan",
27
- "border": "blue",
28
- "borderAccent": "cyan",
29
- "borderMuted": "darkGray",
30
- "success": "green",
31
- "error": "red",
32
- "warning": "yellow",
33
- "muted": "gray",
34
- "dim": "dimGray",
35
- "text": "text",
36
- "thinkingText": "gray",
20
+ "accentSoft": "accentSoft",
21
+ "border": "oklch(55% 0.07 357)",
22
+ "borderAccent": "accentBorder",
23
+ "borderMuted": "fgFaint",
24
+ "success": "success",
25
+ "error": "error",
26
+ "warning": "warning",
27
+ "muted": "fgMuted",
28
+ "dim": "fgDim",
29
+ "text": "fg",
37
30
 
38
- "selectedBg": "selectedBg",
39
- "scrollbarTrack": "darkGray",
40
- "scrollbarThumb": "softCyan",
41
- "searchMatchBg": "searchBg",
42
- "searchMatchText": "text",
43
- "userMessageBg": "userMsgBg",
44
- "userMessageText": "text",
45
- "customMessageBg": "customMsgBg",
46
- "customMessageText": "text",
47
- "customMessageLabel": "#00f0ff",
48
- "toolPendingBg": "toolPendingBg",
49
- "toolSuccessBg": "toolSuccessBg",
50
- "toolErrorBg": "toolErrorBg",
51
- "toolTitle": "text",
52
- "toolOutput": "gray",
31
+ "thinkingText": "fgMuted",
32
+ "selectedBg": "oklch(23% 0.05 357)",
33
+ "scrollbarTrack": "fgFaint",
34
+ "scrollbarThumb": "accentSoft",
35
+ "searchMatchBg": "oklch(30% 0.09 357)",
36
+ "searchMatchText": "fg",
37
+ "userMessageBg": "surfaceMsg",
38
+ "userMessageText": "fg",
39
+ "customMessageBg": "oklch(17% 0.03 190)",
40
+ "customMessageText": "fg",
41
+ "customMessageLabel": "oklch(78% 0.135 190)",
42
+ "toolPendingBg": "oklch(14% 0.059 357)",
43
+ "toolSuccessBg": "oklch(13% 0.043 145)",
44
+ "toolErrorBg": "oklch(13% 0.055 25)",
45
+ "toolTitle": "fg",
53
46
 
54
- "mdHeading": "#ffe600",
55
- "mdLink": "#00f0ff",
56
- "mdLinkUrl": "dimGray",
57
- "mdCode": "accent",
58
- "mdCodeBlock": "green",
59
- "mdCodeBlockBorder": "gray",
60
- "mdQuote": "gray",
61
- "mdQuoteBorder": "gray",
62
- "mdHr": "gray",
63
- "mdListBullet": "accent",
47
+ "toolOutput": "fgMuted",
48
+ "mdHeading": "oklch(88% 0.079 60)",
49
+ "mdLink": "oklch(80% 0.138 190)",
50
+ "mdLinkUrl": "fgDim",
51
+ "mdCode": "oklch(80% 0.128 357)",
52
+ "mdCodeBlock": "success",
53
+ "mdCodeBlockBorder": "fgMuted",
54
+ "mdQuote": "fgMuted",
55
+ "mdQuoteBorder": "fgMuted",
56
+ "mdHr": "fgFaint",
64
57
 
65
- "toolDiffAdded": "green",
66
- "toolDiffRemoved": "red",
67
- "toolDiffContext": "gray",
58
+ "mdListBullet": "oklch(80% 0.128 357)",
59
+ "toolDiffAdded": "success",
60
+ "toolDiffRemoved": "error",
61
+ "toolDiffContext": "fgMuted",
62
+ "syntaxComment": "fgDim",
63
+ "syntaxKeyword": "oklch(80% 0.128 357)",
64
+ "syntaxFunction": "oklch(86% 0.094 60)",
65
+ "syntaxVariable": "oklch(84% 0.11 320)",
66
+ "syntaxString": "oklch(82% 0.14 320)",
67
+ "syntaxNumber": "oklch(80% 0.115 30)",
68
+ "syntaxType": "oklch(80% 0.16 150)",
69
+ "syntaxOperator": "fg",
68
70
 
69
- "syntaxComment": "#6f6a9a",
70
- "syntaxKeyword": "#00f0ff",
71
- "syntaxFunction": "#ffe600",
72
- "syntaxVariable": "#ffd9f2",
73
- "syntaxString": "#ff2e97",
74
- "syntaxNumber": "#ff9a3c",
75
- "syntaxType": "#00ff9f",
76
- "syntaxOperator": "#c8c8e8",
77
- "syntaxPunctuation": "#9a96c0",
78
-
79
- "thinkingOff": "darkGray",
80
- "thinkingMinimal": "#33285c",
81
- "thinkingLow": "#4d3a94",
82
- "thinkingMedium": "#7a4fd6",
83
- "thinkingHigh": "#b84fe8",
84
- "thinkingXhigh": "#ff4fc3",
71
+ "syntaxPunctuation": "fgMuted",
72
+ "thinkingOff": "oklch(40% 0.02 275)",
73
+ "thinkingMinimal": "oklch(47% 0.05 357)",
74
+ "thinkingLow": "oklch(55% 0.08 357)",
75
+ "thinkingMedium": "oklch(63% 0.12 357)",
76
+ "thinkingHigh": "oklch(71% 0.16 357)",
77
+ "thinkingXhigh": "oklch(79% 0.136 357)",
85
78
  "thinkingMax": "accent",
86
-
87
- "bashMode": "green"
79
+ "bashMode": "success"
88
80
  },
89
81
  "export": {
90
- "pageBg": "#0d0b16",
91
- "cardBg": "#16131f",
92
- "infoBg": "#3a2a10"
82
+ "pageBg": "oklch(10% 0.02 275)",
83
+ "cardBg": "oklch(13% 0.02 275)",
84
+ "infoBg": "oklch(21% 0.05 357)"
93
85
  }
94
86
  }
@@ -1,94 +1,86 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
3
  "name": "arnative-dracula",
4
+ "appearance": "dark",
4
5
  "vars": {
5
- "cyan": "#8be9fd",
6
- "blue": "#6272a4",
7
- "green": "#50fa7b",
8
- "red": "#ff6363",
9
- "yellow": "#f1fa8c",
10
- "text": "#f8f8f2",
11
- "gray": "#8e96ba",
12
- "dimGray": "#6272a4",
13
- "darkGray": "#4a4e63",
14
- "accent": "#bd93f9",
15
- "softCyan": "#c9b8f2",
16
- "searchBg": "#59427b",
17
- "selectedBg": "#44475a",
18
- "userMsgBg": "#343746",
19
- "toolPendingBg": "#21222c",
20
- "toolSuccessBg": "#26332e",
21
- "toolErrorBg": "#412936",
22
- "customMsgBg": "#383a52"
6
+ "fg": "oklch(88% 0.012 285)",
7
+ "fgMuted": "oklch(72% 0.012 285)",
8
+ "fgDim": "oklch(61% 0.012 285)",
9
+ "fgFaint": "oklch(49% 0.012 285)",
10
+ "accent": "oklch(78% 0.135 302)",
11
+ "accentSoft": "oklch(82% 0.025 302)",
12
+ "accentBorder": "oklch(82% 0.084 302)",
13
+ "success": "oklch(78% 0.14 145)",
14
+ "error": "oklch(76% 0.14 25)",
15
+ "warning": "oklch(86% 0.14 85)",
16
+ "surfaceMsg": "oklch(29% 0.006 285)"
23
17
  },
24
18
  "colors": {
25
19
  "accent": "accent",
26
- "tint": "softCyan",
27
- "border": "blue",
28
- "borderAccent": "cyan",
29
- "borderMuted": "darkGray",
30
- "success": "green",
31
- "error": "red",
32
- "warning": "yellow",
33
- "muted": "gray",
34
- "dim": "dimGray",
35
- "text": "text",
36
- "thinkingText": "gray",
20
+ "accentSoft": "accentSoft",
21
+ "border": "oklch(55% 0.049 302)",
22
+ "borderAccent": "accentBorder",
23
+ "borderMuted": "fgFaint",
24
+ "success": "success",
25
+ "error": "error",
26
+ "warning": "warning",
27
+ "muted": "fgMuted",
28
+ "dim": "fgDim",
29
+ "text": "fg",
37
30
 
38
- "selectedBg": "selectedBg",
39
- "scrollbarTrack": "darkGray",
40
- "scrollbarThumb": "softCyan",
41
- "searchMatchBg": "searchBg",
42
- "searchMatchText": "text",
43
- "userMessageBg": "userMsgBg",
44
- "userMessageText": "text",
45
- "customMessageBg": "customMsgBg",
46
- "customMessageText": "text",
47
- "customMessageLabel": "#ff79c6",
48
- "toolPendingBg": "toolPendingBg",
49
- "toolSuccessBg": "toolSuccessBg",
50
- "toolErrorBg": "toolErrorBg",
51
- "toolTitle": "text",
52
- "toolOutput": "gray",
31
+ "thinkingText": "fgMuted",
32
+ "selectedBg": "oklch(36% 0.035 302)",
33
+ "scrollbarTrack": "fgFaint",
34
+ "scrollbarThumb": "accentSoft",
35
+ "searchMatchBg": "oklch(43% 0.063 302)",
36
+ "searchMatchText": "fg",
37
+ "userMessageBg": "surfaceMsg",
38
+ "userMessageText": "fg",
39
+ "customMessageBg": "oklch(30% 0.056 330)",
40
+ "customMessageText": "fg",
41
+ "customMessageLabel": "oklch(78% 0.098 330)",
42
+ "toolPendingBg": "oklch(27% 0.042 302)",
43
+ "toolSuccessBg": "oklch(26% 0.056 145)",
44
+ "toolErrorBg": "oklch(26% 0.056 25)",
45
+ "toolTitle": "fg",
53
46
 
54
- "mdHeading": "#f1fa8c",
55
- "mdLink": "#8be9fd",
56
- "mdLinkUrl": "dimGray",
57
- "mdCode": "accent",
58
- "mdCodeBlock": "green",
59
- "mdCodeBlockBorder": "gray",
60
- "mdQuote": "gray",
61
- "mdQuoteBorder": "gray",
62
- "mdHr": "gray",
63
- "mdListBullet": "accent",
47
+ "toolOutput": "fgMuted",
48
+ "mdHeading": "oklch(88% 0.079 60)",
49
+ "mdLink": "oklch(80% 0.098 190)",
50
+ "mdLinkUrl": "fgDim",
51
+ "mdCode": "oklch(80% 0.098 302)",
52
+ "mdCodeBlock": "success",
53
+ "mdCodeBlockBorder": "fgMuted",
54
+ "mdQuote": "fgMuted",
55
+ "mdQuoteBorder": "fgMuted",
56
+ "mdHr": "fgFaint",
64
57
 
65
- "toolDiffAdded": "green",
66
- "toolDiffRemoved": "red",
67
- "toolDiffContext": "gray",
58
+ "mdListBullet": "oklch(80% 0.098 302)",
59
+ "toolDiffAdded": "success",
60
+ "toolDiffRemoved": "error",
61
+ "toolDiffContext": "fgMuted",
62
+ "syntaxComment": "fgDim",
63
+ "syntaxKeyword": "oklch(80% 0.098 302)",
64
+ "syntaxFunction": "oklch(86% 0.112 135)",
65
+ "syntaxVariable": "oklch(84% 0.077 190)",
66
+ "syntaxString": "oklch(82% 0.098 60)",
67
+ "syntaxNumber": "oklch(80% 0.098 265)",
68
+ "syntaxType": "oklch(80% 0.112 190)",
69
+ "syntaxOperator": "fg",
68
70
 
69
- "syntaxComment": "#6272a4",
70
- "syntaxKeyword": "#ff79c6",
71
- "syntaxFunction": "#50fa7b",
72
- "syntaxVariable": "#8be9fd",
73
- "syntaxString": "#f1fa8c",
74
- "syntaxNumber": "#bd93f9",
75
- "syntaxType": "#8be9fd",
76
- "syntaxOperator": "#ff79c6",
77
- "syntaxPunctuation": "#f8f8f2",
78
-
79
- "thinkingOff": "darkGray",
80
- "thinkingMinimal": "#464a5d",
81
- "thinkingLow": "#6272a4",
82
- "thinkingMedium": "#7a6fd0",
83
- "thinkingHigh": "#bd93f9",
84
- "thinkingXhigh": "#ff79c6",
71
+ "syntaxPunctuation": "fgMuted",
72
+ "thinkingOff": "oklch(40% 0.012 285)",
73
+ "thinkingMinimal": "oklch(47% 0.035 302)",
74
+ "thinkingLow": "oklch(55% 0.056 302)",
75
+ "thinkingMedium": "oklch(63% 0.084 302)",
76
+ "thinkingHigh": "oklch(71% 0.112 302)",
77
+ "thinkingXhigh": "oklch(79% 0.128 302)",
85
78
  "thinkingMax": "accent",
86
-
87
- "bashMode": "green"
79
+ "bashMode": "success"
88
80
  },
89
81
  "export": {
90
- "pageBg": "#21222c",
91
- "cardBg": "#282a36",
92
- "infoBg": "#44475a"
82
+ "pageBg": "oklch(23% 0.012 285)",
83
+ "cardBg": "oklch(26% 0.012 285)",
84
+ "infoBg": "oklch(34% 0.035 302)"
93
85
  }
94
86
  }