@aiwayds/dsh-tui-pi 2.16.0 → 2.18.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 (47) hide show
  1. package/README.md +3 -3
  2. package/README.zh-CN.md +3 -3
  3. package/cordis.patch.yml +14 -0
  4. package/lib/index.js +70 -124
  5. package/lib/index.js.map +1 -1
  6. package/lib/selectors.d.ts +7 -5
  7. package/lib/selectors.js +19 -23
  8. package/lib/selectors.js.map +1 -1
  9. package/lib/theme/index.d.ts +6 -3
  10. package/lib/theme/index.js +30 -2
  11. package/lib/theme/index.js.map +1 -1
  12. package/lib/theme/palette.d.ts +2 -0
  13. package/lib/theme/palette.js +1 -1
  14. package/lib/theme/palette.js.map +1 -1
  15. package/lib/theme/registry.d.ts +49 -0
  16. package/lib/theme/registry.js +211 -0
  17. package/lib/theme/registry.js.map +1 -0
  18. package/lib/theme-preview.d.ts +98 -0
  19. package/lib/theme-preview.js +266 -0
  20. package/lib/theme-preview.js.map +1 -0
  21. package/lib/theme-settings.js +6 -5
  22. package/lib/theme-settings.js.map +1 -1
  23. package/lib/tui.d.ts +3 -0
  24. package/lib/tui.js +1 -1
  25. package/lib/tui.js.map +1 -1
  26. package/package.json +6 -4
  27. package/skills/dsh-tui-pi-config/SKILL.md +11 -4
  28. package/themes/ayu-light.json +25 -0
  29. package/themes/catppuccin-latte.json +25 -0
  30. package/themes/catppuccin-mocha.json +25 -0
  31. package/themes/dracula-light.json +25 -0
  32. package/themes/dracula.json +25 -0
  33. package/themes/github-dark.json +25 -0
  34. package/themes/github-light.json +25 -0
  35. package/themes/gruvbox-dark.json +25 -0
  36. package/themes/gruvbox-light.json +25 -0
  37. package/themes/material-light.json +25 -0
  38. package/themes/monokai.json +25 -0
  39. package/themes/nord-dark.json +25 -0
  40. package/themes/nord-light.json +25 -0
  41. package/themes/one-dark.json +25 -0
  42. package/themes/one-light.json +25 -0
  43. package/themes/solarized-dark.json +25 -0
  44. package/themes/solarized-light.json +25 -0
  45. package/themes/synthwave.json +25 -0
  46. package/themes/tokyo-night-light.json +25 -0
  47. package/themes/tokyo-night.json +25 -0
@@ -1 +1 @@
1
- {"version":3,"file":"palette.js","sourceRoot":"","sources":["../../src/theme/palette.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"palette.js","sourceRoot":"","sources":["../../src/theme/palette.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Theme file registry: discovers themes from the npm-bundled `themes/`
3
+ * directory and the user's `$DSH_HOME/themes` directory, parses+validates
4
+ * each `*.json` theme file into a full `Palette`, and merges them into one
5
+ * registry keyed by theme id. The user directory wins over the bundled
6
+ * themes on name collisions, and the two hard-coded GitHub palettes always
7
+ * win over a bundled JSON of the same name (their exact values are
8
+ * load-bearing — the e2e suite asserts the canvas RGB).
9
+ *
10
+ * JSON contract (a user-writable theme file):
11
+ * - required: `name` (string, the theme id), `dark` (boolean), and 13 hex
12
+ * colors (`#rrggbb`, six hex digits): `canvas` `canvasSubtle` `canvasInset`
13
+ * `fgDefault` `fgMuted` `fgSubtle` `borderDefault` `borderMuted` `accent`
14
+ * `success` `danger` `attention` `thinking`.
15
+ * - optional (derived when absent): `accentMuted`, `successMuted`,
16
+ * `dangerMuted`, `attentionMuted`, `thinkingPanelBg`, `toolPanelBg`,
17
+ * `panelBorder`, `panelBoxBorder` — see `deriveDefault`.
18
+ */
19
+ import { type Palette } from './palette.ts';
20
+ /** npm-bundled themes dir (repo-root `themes/`; resolves up from lib/ at runtime). */
21
+ export declare function builtinThemesDir(): string;
22
+ /** User themes dir: `$DSH_HOME/themes` (home is the dshHome() result). */
23
+ export declare function userThemesDir(home: string): string;
24
+ /**
25
+ * Parse + validate one theme JSON file and derive its missing optional
26
+ * fields into a complete `Palette`. Throws an `Error` carrying the `source`
27
+ * (the file path) and the offending field on any invalid input.
28
+ */
29
+ export declare function parseThemeFile(raw: string, source: string): Palette;
30
+ /**
31
+ * Scan one directory for `*.json` theme files, parsing each into a full
32
+ * `Palette`. Invalid files are skipped with a `warn` line (fail-open); a
33
+ * missing/unreadable directory yields an empty Map (never throws).
34
+ */
35
+ export declare function scanThemeDir(dir: string, warn?: (msg: string) => void): Map<string, Palette>;
36
+ /**
37
+ * Merge-register all discoverable themes: the bundled `themes/` directory
38
+ * first, then the user's `$DSH_HOME/themes` — user themes override bundled
39
+ * ones of the same name. The hard-coded `github-light`/`github-dark` palettes
40
+ * are always re-seeded over a bundled JSON of the same name (their exact
41
+ * values are load-bearing for the e2e suite).
42
+ *
43
+ * @param opts.home - the dsh home (defaults to `$DSH_HOME` or `~/.dsh`).
44
+ * @param opts.warn - per-file skip reporter (invalid themes are fail-open).
45
+ */
46
+ export declare function discoverThemes(opts?: {
47
+ home?: string;
48
+ warn?: (msg: string) => void;
49
+ }): Map<string, Palette>;
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Theme file registry: discovers themes from the npm-bundled `themes/`
3
+ * directory and the user's `$DSH_HOME/themes` directory, parses+validates
4
+ * each `*.json` theme file into a full `Palette`, and merges them into one
5
+ * registry keyed by theme id. The user directory wins over the bundled
6
+ * themes on name collisions, and the two hard-coded GitHub palettes always
7
+ * win over a bundled JSON of the same name (their exact values are
8
+ * load-bearing — the e2e suite asserts the canvas RGB).
9
+ *
10
+ * JSON contract (a user-writable theme file):
11
+ * - required: `name` (string, the theme id), `dark` (boolean), and 13 hex
12
+ * colors (`#rrggbb`, six hex digits): `canvas` `canvasSubtle` `canvasInset`
13
+ * `fgDefault` `fgMuted` `fgSubtle` `borderDefault` `borderMuted` `accent`
14
+ * `success` `danger` `attention` `thinking`.
15
+ * - optional (derived when absent): `accentMuted`, `successMuted`,
16
+ * `dangerMuted`, `attentionMuted`, `thinkingPanelBg`, `toolPanelBg`,
17
+ * `panelBorder`, `panelBoxBorder` — see `deriveDefault`.
18
+ */
19
+ import { readdirSync, readFileSync } from 'node:fs';
20
+ import { homedir } from 'node:os';
21
+ import { dirname, join, resolve } from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+ import { blend, githubDark, githubLight } from "./palette.js";
24
+ /** #rrggbb hex matcher — same shape as palette.ts's internal HEX6. */
25
+ const HEX6 = /^#[0-9a-fA-F]{6}$/;
26
+ /** The 13 required color fields of a user theme file. */
27
+ const REQUIRED_COLORS = [
28
+ 'canvas', 'canvasSubtle', 'canvasInset',
29
+ 'fgDefault', 'fgMuted', 'fgSubtle',
30
+ 'borderDefault', 'borderMuted',
31
+ 'accent', 'success', 'danger', 'attention', 'thinking',
32
+ ];
33
+ /** True when `value` is a #rrggbb hex string. */
34
+ function isHex(value) {
35
+ return typeof value === 'string' && HEX6.test(value);
36
+ }
37
+ /** Default $DSH_HOME (mirrors append-system.ts's dshHome — kept local to avoid a business-module dependency here). */
38
+ function defaultDshHome() {
39
+ return process.env.DSH_HOME ?? join(homedir(), '.dsh');
40
+ }
41
+ /** npm-bundled themes dir (repo-root `themes/`; resolves up from lib/ at runtime). */
42
+ export function builtinThemesDir() {
43
+ // Compiled: lib/theme/registry.js → ../.. = package root. From src/ the
44
+ // same two hops land on the repo root too.
45
+ return resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'themes');
46
+ }
47
+ /** User themes dir: `$DSH_HOME/themes` (home is the dshHome() result). */
48
+ export function userThemesDir(home) {
49
+ return join(home, 'themes');
50
+ }
51
+ /** Derive the optional-field default for one field (see the JSON contract). */
52
+ function deriveDefault(field, dark, canvas, accent, colors, derived) {
53
+ switch (field) {
54
+ case 'accentMuted':
55
+ return dark ? blend(canvas, accent, 0.25) : blend(canvas, accent, 0.18);
56
+ case 'successMuted':
57
+ return blend(canvas, colors['success'], 0.25);
58
+ case 'dangerMuted':
59
+ return blend(canvas, colors['danger'], 0.25);
60
+ case 'attentionMuted':
61
+ return blend(canvas, colors['attention'], 0.25);
62
+ case 'thinkingPanelBg':
63
+ return dark ? blend(canvas, colors['thinking'], 0.25) : blend(canvas, colors['thinking'], 0.12);
64
+ case 'toolPanelBg':
65
+ // Defaults to accentMuted — parseThemeFile derives accentMuted first.
66
+ return derived.get('accentMuted');
67
+ case 'panelBorder':
68
+ return colors['borderDefault'];
69
+ case 'panelBoxBorder':
70
+ return blend(canvas, accent, 0.70);
71
+ default:
72
+ throw new Error(`internal: no derivation for theme field "${field}"`);
73
+ }
74
+ }
75
+ /**
76
+ * Parse + validate one theme JSON file and derive its missing optional
77
+ * fields into a complete `Palette`. Throws an `Error` carrying the `source`
78
+ * (the file path) and the offending field on any invalid input.
79
+ */
80
+ export function parseThemeFile(raw, source) {
81
+ let data;
82
+ try {
83
+ data = JSON.parse(raw);
84
+ }
85
+ catch (error) {
86
+ throw new Error(`${source}: invalid theme JSON (${error instanceof Error ? error.message : String(error)})`);
87
+ }
88
+ if (data === null || typeof data !== 'object' || Array.isArray(data)) {
89
+ throw new Error(`${source}: theme must be a JSON object`);
90
+ }
91
+ const input = data;
92
+ const name = input['name'];
93
+ if (typeof name !== 'string' || name === '') {
94
+ throw new Error(`${source}: theme "name" must be a non-empty string`);
95
+ }
96
+ const dark = input['dark'];
97
+ if (typeof dark !== 'boolean') {
98
+ throw new Error(`${source}: theme "dark" must be a boolean`);
99
+ }
100
+ const colors = {};
101
+ for (const field of REQUIRED_COLORS) {
102
+ const value = input[field];
103
+ if (!isHex(value)) {
104
+ throw new Error(`${source}: missing or invalid hex color "${field}" (expected #rrggbb)`);
105
+ }
106
+ colors[field] = value;
107
+ }
108
+ // Optional fields: an explicitly provided value is used verbatim (and must
109
+ // be a valid hex — a malformed one is a rejected file, not a silent
110
+ // derivation); absent fields derive per the contract formulas. Derived
111
+ // values are cached so `toolPanelBg` (which defaults to `accentMuted`) can
112
+ // read them back.
113
+ const derived = new Map();
114
+ const optional = (field) => {
115
+ const existing = derived.get(field);
116
+ if (existing !== undefined)
117
+ return existing;
118
+ const value = input[field];
119
+ let resolved;
120
+ if (value === undefined) {
121
+ resolved = deriveDefault(field, dark, colors['canvas'], colors['accent'], colors, derived);
122
+ }
123
+ else if (!isHex(value)) {
124
+ throw new Error(`${source}: invalid hex color "${field}" (expected #rrggbb)`);
125
+ }
126
+ else {
127
+ resolved = value;
128
+ }
129
+ derived.set(field, resolved);
130
+ return resolved;
131
+ };
132
+ // toolPanelBg derives from accentMuted, so force accentMuted's derivation
133
+ // before reading it (optional() caches per field, so order matters).
134
+ const accentMuted = optional('accentMuted');
135
+ const toolPanelBg = optional('toolPanelBg');
136
+ const get = (field) => colors[field];
137
+ return {
138
+ name,
139
+ dark,
140
+ canvas: get('canvas'),
141
+ canvasSubtle: get('canvasSubtle'),
142
+ canvasInset: get('canvasInset'),
143
+ fgDefault: get('fgDefault'),
144
+ fgMuted: get('fgMuted'),
145
+ fgSubtle: get('fgSubtle'),
146
+ borderDefault: get('borderDefault'),
147
+ borderMuted: get('borderMuted'),
148
+ accent: get('accent'),
149
+ accentMuted,
150
+ success: get('success'),
151
+ successMuted: optional('successMuted'),
152
+ danger: get('danger'),
153
+ dangerMuted: optional('dangerMuted'),
154
+ attention: get('attention'),
155
+ attentionMuted: optional('attentionMuted'),
156
+ thinking: get('thinking'),
157
+ thinkingPanelBg: optional('thinkingPanelBg'),
158
+ toolPanelBg,
159
+ panelBorder: optional('panelBorder'),
160
+ panelBoxBorder: optional('panelBoxBorder'),
161
+ };
162
+ }
163
+ /**
164
+ * Scan one directory for `*.json` theme files, parsing each into a full
165
+ * `Palette`. Invalid files are skipped with a `warn` line (fail-open); a
166
+ * missing/unreadable directory yields an empty Map (never throws).
167
+ */
168
+ export function scanThemeDir(dir, warn) {
169
+ const themes = new Map();
170
+ let files;
171
+ try {
172
+ files = readdirSync(dir, { withFileTypes: true })
173
+ .filter(entry => entry.isFile() && entry.name.endsWith('.json'))
174
+ .map(entry => join(dir, entry.name));
175
+ }
176
+ catch {
177
+ // Missing/unreadable directory: nothing to register (fail-open).
178
+ return themes;
179
+ }
180
+ for (const file of files) {
181
+ try {
182
+ const palette = parseThemeFile(readFileSync(file, 'utf8'), file);
183
+ themes.set(palette.name, palette);
184
+ }
185
+ catch (error) {
186
+ warn?.(`theme registry: skipping ${file}: ${error instanceof Error ? error.message : String(error)}`);
187
+ }
188
+ }
189
+ return themes;
190
+ }
191
+ /**
192
+ * Merge-register all discoverable themes: the bundled `themes/` directory
193
+ * first, then the user's `$DSH_HOME/themes` — user themes override bundled
194
+ * ones of the same name. The hard-coded `github-light`/`github-dark` palettes
195
+ * are always re-seeded over a bundled JSON of the same name (their exact
196
+ * values are load-bearing for the e2e suite).
197
+ *
198
+ * @param opts.home - the dsh home (defaults to `$DSH_HOME` or `~/.dsh`).
199
+ * @param opts.warn - per-file skip reporter (invalid themes are fail-open).
200
+ */
201
+ export function discoverThemes(opts) {
202
+ const registry = scanThemeDir(builtinThemesDir(), opts?.warn);
203
+ // The canonical GitHub palettes win over any bundled JSON of the same name.
204
+ registry.set(githubLight.name, githubLight);
205
+ registry.set(githubDark.name, githubDark);
206
+ for (const [name, palette] of scanThemeDir(userThemesDir(opts?.home ?? defaultDshHome()), opts?.warn)) {
207
+ registry.set(name, palette);
208
+ }
209
+ return registry;
210
+ }
211
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/theme/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Theme picker's live preview pane: a mock chat page rendered with the
3
+ * SELECTED theme's palette, so the user sees what the TUI will look like
4
+ * before committing to a theme. The left list (a TablePanel) owns the
5
+ * keyboard; every selection change calls `setPalette` and the pane repaints
6
+ * in the selected theme. `auto` (no fixed palette) shows a hint instead of
7
+ * a mock page.
8
+ *
9
+ * The pane is a self-drawn component (like ThinkPanel/ToolPanel): every row
10
+ * is painted with a full-width `ansiBg` backdrop, so surfaces (bubbles,
11
+ * think/tool panels, code blocks, the input dock) read as solid blocks in
12
+ * the theme's real colors — the same canvas the live TUI paints.
13
+ */
14
+ import type { Component } from '@earendil-works/pi-tui';
15
+ import { type ThemePreference, type TuiTheme } from './theme/index.ts';
16
+ import { type Palette } from './theme/palette.ts';
17
+ /** A mock chat page built from a palette. Fixed row count for the budget. */
18
+ export declare class ThemePreviewPane implements Component {
19
+ private row;
20
+ private readonly getTheme;
21
+ /** `getTheme` is the CURRENT active TuiTheme (used when `auto` is selected). */
22
+ constructor(getTheme: () => TuiTheme);
23
+ /** Switch the preview to a theme row; `undefined` (auto) shows the hint. */
24
+ setRow(row: ThemePickerRow | undefined): void;
25
+ /** The palette the mock page currently renders with (for tests). */
26
+ currentPalette(): Palette | undefined;
27
+ invalidate(): void;
28
+ render(width: number): string[];
29
+ /** `auto` selected: show a short hint in the current theme instead of a mock. */
30
+ private renderAuto;
31
+ }
32
+ /** A theme picker row: the selectable value, name, description and palette. */
33
+ export interface ThemePickerRow {
34
+ value: string;
35
+ label: string;
36
+ description: string;
37
+ palette?: Palette;
38
+ }
39
+ /** Options for the theme picker's registry rows (custom themes). */
40
+ export interface PickThemeOptions {
41
+ /**
42
+ * Full theme registry (theme id → palette), as produced by
43
+ * `discoverThemes` — every entry becomes a selectable row after the
44
+ * constant auto/light/dark rows. Absent: the picker shows only those
45
+ * three rows (the historical behavior).
46
+ */
47
+ themes?: ReadonlyMap<string, Palette>;
48
+ /**
49
+ * Theme ids that live in the user themes directory. Entries in `themes`
50
+ * whose id appears here are labeled "user theme"; the rest (the bundled
51
+ * themes) are labeled "built-in".
52
+ */
53
+ userNames?: ReadonlySet<string>;
54
+ }
55
+ /**
56
+ * Build the picker rows — a flat two-level list: `auto` first, then every
57
+ * registered theme. The two GitHub defaults lead the theme block (they are
58
+ * the out-of-the-box choices and keep the e2e navigation stable), user
59
+ * themes follow, the remaining built-ins come last. The old `light`/`dark`
60
+ * alias rows are gone — those names stay valid as stored preferences (they
61
+ * resolve through resolveTheme's alias handling) but no longer get their own
62
+ * rows.
63
+ */
64
+ export declare function themePickerRows(options?: PickThemeOptions): ThemePickerRow[];
65
+ /** Terminal width at which the picker switches from stacked to side-by-side. */
66
+ export declare const DUAL_PANE_MIN_COLUMNS = 100;
67
+ /** Floor of the left list pane in dual-pane mode. */
68
+ export declare const LEFT_PANE_MIN_COLUMNS = 30;
69
+ /**
70
+ * Content-row budget inside the framed overlay: the overlay is capped at 75%
71
+ * of the terminal, the FramedOverlay adds 4 chrome rows (top/bottom borders +
72
+ * a blank spacer each), and the preview pane renders exactly its own height.
73
+ * Testable; `rows` injected.
74
+ */
75
+ export declare function overlayContentBudget(rows?: number | undefined): number;
76
+ /**
77
+ * The theme picker overlay: a left TablePanel of themes + a right preview
78
+ * pane that repaints with the SELECTED theme's palette on every cursor move
79
+ * (history.ts's pattern — compare selectedRow before/after handleInput, an
80
+ * explicit action, never the render path). Side-by-side on wide terminals
81
+ * (HStack), stacked on narrow ones (VStack). Renders exactly
82
+ * `overlayContentBudget()` rows.
83
+ */
84
+ export declare class ThemePickerOverlay implements Component {
85
+ private readonly list;
86
+ private readonly preview;
87
+ private readonly rows;
88
+ private readonly onPick;
89
+ private readonly footer;
90
+ private closed;
91
+ constructor(theme: TuiTheme, rows: readonly ThemePickerRow[], preselect: number, onPick: (value: string | undefined) => void, getTheme: () => TuiTheme);
92
+ invalidate(): void;
93
+ render(width: number): string[];
94
+ handleInput(data: string): void;
95
+ private finish;
96
+ /** The currently selected row (test seam). */
97
+ selectedValue(): ThemePreference | undefined;
98
+ }
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Theme picker's live preview pane: a mock chat page rendered with the
3
+ * SELECTED theme's palette, so the user sees what the TUI will look like
4
+ * before committing to a theme. The left list (a TablePanel) owns the
5
+ * keyboard; every selection change calls `setPalette` and the pane repaints
6
+ * in the selected theme. `auto` (no fixed palette) shows a hint instead of
7
+ * a mock page.
8
+ *
9
+ * The pane is a self-drawn component (like ThinkPanel/ToolPanel): every row
10
+ * is painted with a full-width `ansiBg` backdrop, so surfaces (bubbles,
11
+ * think/tool panels, code blocks, the input dock) read as solid blocks in
12
+ * the theme's real colors — the same canvas the live TUI paints.
13
+ */
14
+ import { HStack, VStack } from '@earendil-works/pi-tui';
15
+ import { TablePanel } from "./panels.js";
16
+ import { ansiBg, ansiFg, BOLD, buildTheme, RESET } from "./theme/index.js";
17
+ import { githubDark, githubLight } from "./theme/palette.js";
18
+ import { visibleWidth } from "./text.js";
19
+ /**
20
+ * Paint one full-width row: `content` (which may carry its own SGR) on the
21
+ * `bg` backdrop, with `bg` re-applied after any mid-line RESET and trailing
22
+ * padding kept on the backdrop (frame.ts fillLine's pattern, but on an
23
+ * arbitrary palette surface).
24
+ */
25
+ function fill(bg, content, width) {
26
+ const pad = Math.max(0, width - visibleWidth(content));
27
+ const prefix = ansiBg(bg);
28
+ const guarded = content.replace(/\x1b\[0m/g, `\x1b[0m${prefix}`);
29
+ return prefix + guarded + prefix + ' '.repeat(pad) + RESET;
30
+ }
31
+ /**
32
+ * One mock chat page row. `surface` is the palette surface to paint the row
33
+ * on; `content` is the styled text (already carrying its foreground SGR).
34
+ */
35
+ function surfaceRow(surface, content, width) {
36
+ return fill(surface, content, width);
37
+ }
38
+ /** A mock chat page built from a palette. Fixed row count for the budget. */
39
+ export class ThemePreviewPane {
40
+ row;
41
+ getTheme;
42
+ /** `getTheme` is the CURRENT active TuiTheme (used when `auto` is selected). */
43
+ constructor(getTheme) {
44
+ this.getTheme = getTheme;
45
+ }
46
+ /** Switch the preview to a theme row; `undefined` (auto) shows the hint. */
47
+ setRow(row) {
48
+ this.row = row;
49
+ }
50
+ /** The palette the mock page currently renders with (for tests). */
51
+ currentPalette() {
52
+ return this.row?.palette;
53
+ }
54
+ invalidate() { }
55
+ render(width) {
56
+ const row = this.row;
57
+ if (row === undefined || row.palette === undefined)
58
+ return this.renderAuto(width);
59
+ const p = buildTheme(row.palette).palette;
60
+ const fg = (hex, text) => ansiFg(hex) + text + RESET;
61
+ const bold = (hex, text) => ansiFg(hex) + BOLD + text + RESET;
62
+ const canvas = (content) => surfaceRow(p.canvas, content, width);
63
+ const lines = [];
64
+ // Title bar: the theme label + its description, accent-tinted, on the
65
+ // inset surface (the description carries the "GitHub light palette" /
66
+ // "GitHub dark palette" text the e2e suite asserts).
67
+ const title = `${row.label} — ${row.description}`;
68
+ lines.push(surfaceRow(p.canvasInset, ` ${bold(p.accent, title)} `, width));
69
+ lines.push(canvas(''));
70
+ // User message bubble (canvasSubtle backdrop + fgDefault text).
71
+ lines.push(canvas(` ${fg(p.fgDefault, '▎帮我分析这段代码')} `));
72
+ // Think panel (its own purple surface + italic thinking text).
73
+ lines.push(surfaceRow(p.thinkingPanelBg, ` ${bold(p.thinking, 'thinking')}`, width));
74
+ lines.push(surfaceRow(p.thinkingPanelBg, ` ${fg(p.fgMuted, '让我看看这段代码……')}`, width));
75
+ lines.push(canvas(''));
76
+ // Tool card (blue surface + accent tool name).
77
+ lines.push(surfaceRow(p.toolPanelBg, ` ${bold(p.accent, '⎿ read_file')}`, width));
78
+ lines.push(surfaceRow(p.toolPanelBg, ` ${fg(p.fgMuted, 'reading src/index.ts (1.2k lines)')}`, width));
79
+ lines.push(canvas(''));
80
+ // Code block (canvasSubtle surface, bordered).
81
+ lines.push(surfaceRow(p.canvasSubtle, ` ${fg(p.fgMuted, '┌─ code ──────────────')}`, width));
82
+ lines.push(surfaceRow(p.canvasSubtle, ` ${fg(p.fgDefault, '│ const x = 42;')}`, width));
83
+ lines.push(surfaceRow(p.canvasSubtle, ` ${fg(p.fgDefault, '│ console.log(x * 2);')}`, width));
84
+ lines.push(surfaceRow(p.canvasSubtle, ` ${fg(p.fgMuted, '└─────────────────────')}`, width));
85
+ lines.push(canvas(''));
86
+ // Assistant reply.
87
+ lines.push(canvas(` ${fg(p.fgDefault, '结果:x * 2 = 84。')} `));
88
+ lines.push(canvas(''));
89
+ // Input dock placeholder (inset surface).
90
+ lines.push(surfaceRow(p.canvasInset, ` ${fg(p.fgMuted, 'Type a message…')}`, width));
91
+ return lines;
92
+ }
93
+ /** `auto` selected: show a short hint in the current theme instead of a mock. */
94
+ renderAuto(width) {
95
+ const p = this.getTheme().palette;
96
+ const fg = (hex, text) => ansiFg(hex) + text + RESET;
97
+ const bold = (hex, text) => ansiFg(hex) + BOLD + text + RESET;
98
+ const lines = [];
99
+ lines.push(surfaceRow(p.canvasInset, ` ${bold(p.accent, 'auto')} `, width));
100
+ lines.push(surfaceRow(p.canvas, '', width));
101
+ lines.push(surfaceRow(p.canvas, ` ${fg(p.fgDefault, 'Theme follows the terminal.')}`, width));
102
+ lines.push(surfaceRow(p.canvas, ` ${fg(p.fgMuted, 'Pick light/dark or a named theme to preview it.')}`, width));
103
+ lines.push(surfaceRow(p.canvas, '', width));
104
+ lines.push(surfaceRow(p.canvasInset, ` ${fg(p.fgMuted, 'Type a message…')}`, width));
105
+ return lines;
106
+ }
107
+ }
108
+ /**
109
+ * Build the picker rows — a flat two-level list: `auto` first, then every
110
+ * registered theme. The two GitHub defaults lead the theme block (they are
111
+ * the out-of-the-box choices and keep the e2e navigation stable), user
112
+ * themes follow, the remaining built-ins come last. The old `light`/`dark`
113
+ * alias rows are gone — those names stay valid as stored preferences (they
114
+ * resolve through resolveTheme's alias handling) but no longer get their own
115
+ * rows.
116
+ */
117
+ export function themePickerRows(options) {
118
+ const rows = [
119
+ { value: 'auto', label: 'auto', description: 'follow the terminal light/dark signal' },
120
+ ];
121
+ const themes = options?.themes;
122
+ if (themes === undefined) {
123
+ // No registry (the legacy no-argument mount): just the two defaults.
124
+ rows.push({ value: 'github-light', label: 'github-light', description: 'GitHub light palette', palette: githubLight }, { value: 'github-dark', label: 'github-dark', description: 'GitHub dark palette', palette: githubDark });
125
+ return rows;
126
+ }
127
+ const userNames = options?.userNames;
128
+ const row = (name, palette, description) => ({
129
+ value: name,
130
+ label: name,
131
+ description,
132
+ palette,
133
+ });
134
+ // The two defaults keep their classic descriptions (the e2e suite asserts
135
+ // the "GitHub light/dark palette" texts); other rows just carry their
136
+ // origin — the name is already in the Theme column.
137
+ // A user theme overriding a default id shows its own palette under the
138
+ // default's name (discoverThemes merges user-over-builtin).
139
+ const origin = (name) => userNames?.has(name) === true ? 'user theme' : 'built-in';
140
+ rows.push(row('github-light', themes.get('github-light') ?? githubLight, 'GitHub light palette'), row('github-dark', themes.get('github-dark') ?? githubDark, 'GitHub dark palette'));
141
+ // Reserved names that resolveTheme handles specially never get rows.
142
+ const reserved = new Set(['auto', 'light', 'dark', 'github-light', 'github-dark']);
143
+ for (const [name, palette] of themes) {
144
+ if (reserved.has(name))
145
+ continue;
146
+ rows.push(row(name, palette, origin(name)));
147
+ }
148
+ return rows;
149
+ }
150
+ /** Terminal width at which the picker switches from stacked to side-by-side. */
151
+ export const DUAL_PANE_MIN_COLUMNS = 100;
152
+ /** Floor of the left list pane in dual-pane mode. */
153
+ export const LEFT_PANE_MIN_COLUMNS = 30;
154
+ /**
155
+ * A one-column divider between the theme list and the preview pane, so the
156
+ * two panes read as distinct surfaces instead of abutting columns.
157
+ */
158
+ class Divider {
159
+ render() {
160
+ return ['│'];
161
+ }
162
+ invalidate() { }
163
+ }
164
+ /**
165
+ * Content-row budget inside the framed overlay: the overlay is capped at 75%
166
+ * of the terminal, the FramedOverlay adds 4 chrome rows (top/bottom borders +
167
+ * a blank spacer each), and the preview pane renders exactly its own height.
168
+ * Testable; `rows` injected.
169
+ */
170
+ export function overlayContentBudget(rows = process.stdout.rows) {
171
+ return Math.max(6, Math.floor((rows ?? 24) * 0.85) - 4);
172
+ }
173
+ /**
174
+ * The theme picker overlay: a left TablePanel of themes + a right preview
175
+ * pane that repaints with the SELECTED theme's palette on every cursor move
176
+ * (history.ts's pattern — compare selectedRow before/after handleInput, an
177
+ * explicit action, never the render path). Side-by-side on wide terminals
178
+ * (HStack), stacked on narrow ones (VStack). Renders exactly
179
+ * `overlayContentBudget()` rows.
180
+ */
181
+ export class ThemePickerOverlay {
182
+ list;
183
+ preview;
184
+ rows;
185
+ onPick;
186
+ footer;
187
+ closed = false;
188
+ constructor(theme, rows, preselect, onPick, getTheme) {
189
+ this.rows = rows;
190
+ this.onPick = onPick;
191
+ this.footer = '↑↓ navigate · Enter select · Esc back';
192
+ this.preview = new ThemePreviewPane(getTheme);
193
+ this.preview.setRow(rows[Math.max(0, preselect)]);
194
+ this.list = new TablePanel(theme, {
195
+ title: '● Theme',
196
+ columns: [
197
+ { key: 'theme', title: 'Theme', width: Math.max(5, ...rows.map(row => row.label.length)) },
198
+ { key: 'description', title: 'Description', flex: true },
199
+ ],
200
+ rows,
201
+ renderCell: (row, column) => column.key === 'description' ? row.description : row.label,
202
+ preselect,
203
+ onSelect: row => this.finish(row.value),
204
+ onCancel: () => this.finish(undefined),
205
+ footer: this.footer,
206
+ maxVisible: 12,
207
+ });
208
+ }
209
+ invalidate() {
210
+ this.list.invalidate();
211
+ this.preview.invalidate();
212
+ }
213
+ render(width) {
214
+ const budget = overlayContentBudget();
215
+ let lines;
216
+ if (width >= DUAL_PANE_MIN_COLUMNS) {
217
+ // Left pane keeps a ~40% column floor (same as the history browser);
218
+ // a one-column divider separates the panes; the preview grows into
219
+ // the rest.
220
+ const leftWidth = Math.max(LEFT_PANE_MIN_COLUMNS, Math.floor(width * 0.4));
221
+ const stack = new HStack([
222
+ { component: this.list, basis: leftWidth, shrink: 1, minSize: LEFT_PANE_MIN_COLUMNS },
223
+ { component: new Divider(), basis: 1, grow: 0, shrink: 0 },
224
+ { component: this.preview, basis: 0, grow: 1, minSize: 24 },
225
+ ]);
226
+ lines = stack.render(width);
227
+ }
228
+ else {
229
+ // Stacked: the list keeps its intrinsic height; the preview pane gets
230
+ // the remaining budget rows so its mock page stays visible (a fixed
231
+ // basis would overflow the budget on short terminals).
232
+ const listRows = Math.min(12, Math.max(3, budget - 10));
233
+ const stack = new VStack([
234
+ { component: this.list, basis: listRows, grow: 0, shrink: 0 },
235
+ { component: this.preview, basis: Math.max(6, budget - listRows), grow: 0, shrink: 0 },
236
+ ]);
237
+ lines = stack.render(width);
238
+ }
239
+ if (lines.length > budget)
240
+ return lines.slice(0, budget);
241
+ while (lines.length < budget)
242
+ lines.push('');
243
+ return lines;
244
+ }
245
+ handleInput(data) {
246
+ if (this.closed)
247
+ return;
248
+ const before = this.list.selectedRow();
249
+ this.list.handleInput(data);
250
+ const selected = this.list.selectedRow();
251
+ if (selected !== undefined && selected.value !== before?.value) {
252
+ this.preview.setRow(selected);
253
+ }
254
+ }
255
+ finish(value) {
256
+ if (this.closed)
257
+ return;
258
+ this.closed = true;
259
+ this.onPick(value);
260
+ }
261
+ /** The currently selected row (test seam). */
262
+ selectedValue() {
263
+ return this.list.selectedRow()?.value;
264
+ }
265
+ }
266
+ //# sourceMappingURL=theme-preview.js.map