@bastani/atomic 0.6.6-1 → 0.6.7-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 (53) hide show
  1. package/README.md +22 -16
  2. package/dist/sdk/components/compact-switcher.d.ts.map +1 -1
  3. package/dist/sdk/components/connectors.d.ts +1 -0
  4. package/dist/sdk/components/connectors.d.ts.map +1 -1
  5. package/dist/sdk/components/edge.d.ts +1 -1
  6. package/dist/sdk/components/edge.d.ts.map +1 -1
  7. package/dist/sdk/components/graph-theme.d.ts.map +1 -1
  8. package/dist/sdk/components/header.d.ts.map +1 -1
  9. package/dist/sdk/components/node-card.d.ts.map +1 -1
  10. package/dist/sdk/components/orchestrator-panel.d.ts +7 -1
  11. package/dist/sdk/components/orchestrator-panel.d.ts.map +1 -1
  12. package/dist/sdk/components/renderer-background.d.ts +9 -0
  13. package/dist/sdk/components/renderer-background.d.ts.map +1 -0
  14. package/dist/sdk/components/session-graph-panel.d.ts.map +1 -1
  15. package/dist/sdk/components/statusline.d.ts.map +1 -1
  16. package/dist/sdk/components/tui-diagnostics.d.ts +56 -0
  17. package/dist/sdk/components/tui-diagnostics.d.ts.map +1 -0
  18. package/dist/sdk/components/workflow-picker-panel.d.ts +2 -1
  19. package/dist/sdk/components/workflow-picker-panel.d.ts.map +1 -1
  20. package/dist/sdk/providers/copilot.d.ts +3 -2
  21. package/dist/sdk/providers/copilot.d.ts.map +1 -1
  22. package/dist/sdk/runtime/executor.d.ts.map +1 -1
  23. package/dist/sdk/runtime/theme.d.ts +4 -0
  24. package/dist/sdk/runtime/theme.d.ts.map +1 -1
  25. package/dist/theme/colors.d.ts +2 -0
  26. package/dist/theme/colors.d.ts.map +1 -1
  27. package/package.json +2 -1
  28. package/src/cli.ts +3 -3
  29. package/src/commands/cli/chat/index.ts +10 -4
  30. package/src/commands/cli/management-commands.ts +4 -3
  31. package/src/commands/cli/session.test.ts +79 -6
  32. package/src/commands/cli/session.ts +65 -9
  33. package/src/completions/fish.ts +9 -3
  34. package/src/completions/powershell.ts +27 -3
  35. package/src/completions/zsh.ts +9 -2
  36. package/src/sdk/components/compact-switcher.tsx +10 -5
  37. package/src/sdk/components/connectors.ts +4 -0
  38. package/src/sdk/components/edge.tsx +5 -3
  39. package/src/sdk/components/graph-theme.ts +2 -3
  40. package/src/sdk/components/header.tsx +21 -9
  41. package/src/sdk/components/node-card.tsx +13 -7
  42. package/src/sdk/components/orchestrator-panel.tsx +47 -2
  43. package/src/sdk/components/renderer-background.ts +49 -0
  44. package/src/sdk/components/session-graph-panel.tsx +9 -2
  45. package/src/sdk/components/statusline.tsx +26 -22
  46. package/src/sdk/components/tui-diagnostics.ts +273 -0
  47. package/src/sdk/components/workflow-picker-panel.tsx +33 -22
  48. package/src/sdk/providers/copilot.ts +10 -4
  49. package/src/sdk/runtime/executor.ts +28 -1
  50. package/src/sdk/runtime/theme.ts +28 -36
  51. package/src/services/system/install-ui.ts +16 -17
  52. package/src/theme/colors.ts +14 -9
  53. package/src/theme/logo.ts +23 -12
@@ -43,6 +43,11 @@ import { useLatest } from "./hooks.ts";
43
43
  import { resolveTheme, type TerminalTheme } from "../runtime/theme.ts";
44
44
  import type { AgentType, WorkflowInput, WorkflowDefinition, Registry } from "../types.ts";
45
45
  import { ErrorBoundary } from "./error-boundary.tsx";
46
+ import {
47
+ requestRendererBackgroundRepaint,
48
+ resetRendererTerminalBackground,
49
+ setRendererBackground,
50
+ } from "./renderer-background.ts";
46
51
 
47
52
  // ─── Theme ──────────────────────────────────────
48
53
  // The picker uses a slightly extended palette vs. the base terminal theme:
@@ -68,26 +73,21 @@ export interface PickerTheme {
68
73
  borderActive: string;
69
74
  }
70
75
 
71
- export function buildPickerTheme(base: TerminalTheme, isDark: boolean): PickerTheme {
72
- // For dark mode the prototype values track Catppuccin Mocha. For light
73
- // mode we derive muted variants from the base palette — the specific
74
- // extras (`info`, `mauve`, the three-level background ladder) have no
75
- // direct entries in `TerminalTheme`, so we pick close-enough Catppuccin
76
- // values to keep the picker visually consistent with the orchestrator.
76
+ export function buildPickerTheme(base: TerminalTheme): PickerTheme {
77
77
  return {
78
78
  background: base.bg,
79
- backgroundPanel: isDark ? "#181825" : "#e6e9ef",
80
- backgroundElement: isDark ? "#11111b" : "#dce0e8",
79
+ backgroundPanel: base.backgroundPanel,
80
+ backgroundElement: base.backgroundElement,
81
81
  surface: base.surface,
82
82
  text: base.text,
83
- textMuted: isDark ? "#a6adc8" : "#5c5f77",
83
+ textMuted: base.textMuted,
84
84
  textDim: base.dim,
85
85
  primary: base.accent,
86
86
  success: base.success,
87
87
  error: base.error,
88
88
  warning: base.warning,
89
- info: isDark ? "#89dceb" : "#04a5e5",
90
- mauve: isDark ? "#cba6f7" : "#8839ef",
89
+ info: base.info,
90
+ mauve: base.mauve,
91
91
  border: base.borderDim,
92
92
  borderActive: base.border,
93
93
  };
@@ -324,7 +324,7 @@ const WorkflowList = memo(function WorkflowList({
324
324
 
325
325
  if (rows.length === 0) {
326
326
  return (
327
- <box paddingLeft={2} paddingTop={2}>
327
+ <box paddingLeft={2} paddingTop={2} backgroundColor={theme.backgroundPanel}>
328
328
  <text>
329
329
  <span fg={theme.textDim}>no matches</span>
330
330
  </text>
@@ -333,7 +333,7 @@ const WorkflowList = memo(function WorkflowList({
333
333
  }
334
334
 
335
335
  return (
336
- <box flexDirection="column">
336
+ <box flexDirection="column" backgroundColor={theme.backgroundPanel}>
337
337
  {rows.map((row, i) => {
338
338
  if (row.kind === "section") {
339
339
  const ag = row.agent;
@@ -343,6 +343,7 @@ const WorkflowList = memo(function WorkflowList({
343
343
  height={2}
344
344
  paddingTop={1}
345
345
  paddingLeft={2}
346
+ backgroundColor={theme.backgroundPanel}
346
347
  >
347
348
  <text>
348
349
  <span fg={theme[AGENT_COLOR[ag]]}>
@@ -362,7 +363,7 @@ const WorkflowList = memo(function WorkflowList({
362
363
  key={`wf-${wf.agent}-${wf.name}`}
363
364
  height={1}
364
365
  flexDirection="row"
365
- backgroundColor={isFocused ? theme.border : "transparent"}
366
+ backgroundColor={isFocused ? theme.border : theme.backgroundPanel}
366
367
  paddingLeft={1}
367
368
  paddingRight={2}
368
369
  >
@@ -545,6 +546,7 @@ function TextAreaContent({
545
546
  onInput: (value: string) => void;
546
547
  }) {
547
548
  const theme = usePickerTheme();
549
+ const backgroundColor = focused ? theme.backgroundPanel : theme.backgroundElement;
548
550
  const instanceRef = useRef<TextareaRenderable | null>(null);
549
551
  const onInputRef = useLatest(onInput);
550
552
  const lastTextRef = useRef(value);
@@ -593,8 +595,8 @@ function TextAreaContent({
593
595
  placeholder={placeholder}
594
596
  focused={focused}
595
597
  textColor={theme.text}
596
- backgroundColor="transparent"
597
- focusedBackgroundColor="transparent"
598
+ backgroundColor={backgroundColor}
599
+ focusedBackgroundColor={backgroundColor}
598
600
  focusedTextColor={theme.text}
599
601
  placeholderColor={theme.textDim}
600
602
  wrapMode="word"
@@ -616,6 +618,7 @@ function StringContent({
616
618
  onInput: (value: string) => void;
617
619
  }) {
618
620
  const theme = usePickerTheme();
621
+ const backgroundColor = focused ? theme.backgroundPanel : theme.backgroundElement;
619
622
  return (
620
623
  <input
621
624
  value={value}
@@ -623,8 +626,8 @@ function StringContent({
623
626
  focused={focused}
624
627
  onInput={onInput}
625
628
  textColor={theme.text}
626
- backgroundColor="transparent"
627
- focusedBackgroundColor="transparent"
629
+ backgroundColor={backgroundColor}
630
+ focusedBackgroundColor={backgroundColor}
628
631
  focusedTextColor={theme.text}
629
632
  flexGrow={1}
630
633
  />
@@ -883,7 +886,7 @@ function InputPhase({
883
886
  renderBefore={syncScrollFrame}
884
887
  style={{
885
888
  rootOptions: {
886
- backgroundColor: "transparent",
889
+ backgroundColor: theme.background,
887
890
  border: false,
888
891
  },
889
892
  contentOptions: {
@@ -1481,6 +1484,7 @@ export class WorkflowPickerPanel {
1481
1484
  private renderer: CliRenderer;
1482
1485
  private root: Root;
1483
1486
  private destroyed = false;
1487
+ private terminalBackgroundSynced: boolean;
1484
1488
  private resolveSelection: ((r: WorkflowPickerResult | null) => void) | null =
1485
1489
  null;
1486
1490
  private selectionPromise: Promise<WorkflowPickerResult | null>;
@@ -1488,14 +1492,17 @@ export class WorkflowPickerPanel {
1488
1492
  private constructor(
1489
1493
  renderer: CliRenderer,
1490
1494
  options: WorkflowPickerPanelOptions,
1495
+ { syncTerminalBackground = false }: { syncTerminalBackground?: boolean } = {},
1491
1496
  ) {
1492
1497
  this.renderer = renderer;
1498
+ this.terminalBackgroundSynced = syncTerminalBackground;
1493
1499
  this.selectionPromise = new Promise((resolve) => {
1494
1500
  this.resolveSelection = resolve;
1495
1501
  });
1496
1502
 
1497
- const isDark = renderer.themeMode !== "light";
1498
- const theme = buildPickerTheme(resolveTheme(renderer.themeMode), isDark);
1503
+ const termTheme = resolveTheme(renderer.themeMode);
1504
+ setRendererBackground(renderer, termTheme.bg, { syncTerminalDefault: syncTerminalBackground });
1505
+ const theme = buildPickerTheme(termTheme);
1499
1506
  // Filter registry to only the workflows for the selected agent.
1500
1507
  const workflows = options.registry
1501
1508
  .list()
@@ -1528,6 +1535,7 @@ export class WorkflowPickerPanel {
1528
1535
  />
1529
1536
  </ErrorBoundary>,
1530
1537
  );
1538
+ requestRendererBackgroundRepaint(this.renderer);
1531
1539
  }
1532
1540
 
1533
1541
  /**
@@ -1550,7 +1558,7 @@ export class WorkflowPickerPanel {
1550
1558
  "SIGFPE",
1551
1559
  ],
1552
1560
  });
1553
- return new WorkflowPickerPanel(renderer, options);
1561
+ return new WorkflowPickerPanel(renderer, options, { syncTerminalBackground: true });
1554
1562
  }
1555
1563
 
1556
1564
  /** Create with an externally-provided renderer (e.g. a test renderer). */
@@ -1580,6 +1588,9 @@ export class WorkflowPickerPanel {
1580
1588
  this.resolveSelection = null;
1581
1589
  }
1582
1590
  try {
1591
+ if (this.terminalBackgroundSynced) {
1592
+ resetRendererTerminalBackground(this.renderer);
1593
+ }
1583
1594
  this.renderer.destroy();
1584
1595
  } catch (err) {
1585
1596
  console.error("[WorkflowPickerPanel] destroy failed:", err);
@@ -94,11 +94,15 @@ export function enumeratePathCandidates(cmd: string, pathEnv: string): string[]
94
94
  return results;
95
95
  }
96
96
 
97
- export function resolveCopilotCliPath(): string | undefined {
97
+ export type CommandPathResolver = (cmd: string) => string | null;
98
+
99
+ export function resolveCopilotCliPath(
100
+ resolveCommandPath: CommandPathResolver = getCommandPath,
101
+ ): string | undefined {
98
102
  const envPath = process.env["COPILOT_CLI_PATH"];
99
103
  if (envPath) return envPath;
100
104
 
101
- const primary = getCommandPath("copilot");
105
+ const primary = resolveCommandPath("copilot");
102
106
  if (primary === null) return undefined;
103
107
  if (!isCopilotShim(primary)) return primary;
104
108
 
@@ -119,11 +123,13 @@ export function resolveCopilotCliPath(): string | undefined {
119
123
  * - `cliPath` from {@link resolveCopilotCliPath} when resolvable; omitted
120
124
  * otherwise so the SDK falls back to its bundled CLI.
121
125
  */
122
- export function copilotSdkLaunchOptions(): CopilotClientOptions {
126
+ export function copilotSdkLaunchOptions(
127
+ resolveCommandPath: CommandPathResolver = getCommandPath,
128
+ ): CopilotClientOptions {
123
129
  const options: CopilotClientOptions = {
124
130
  env: copilotSubprocessEnv(),
125
131
  };
126
- const cliPath = resolveCopilotCliPath();
132
+ const cliPath = resolveCopilotCliPath(resolveCommandPath);
127
133
  if (cliPath !== undefined) {
128
134
  options.cliPath = cliPath;
129
135
  }
@@ -504,7 +504,11 @@ export async function executeWorkflow(
504
504
  const launcherExt = isWin ? "ps1" : "sh";
505
505
  const launcherPath = join(sessionsBaseDir, `orchestrator.${launcherExt}`);
506
506
  const logPath = join(sessionsBaseDir, "orchestrator.log");
507
- const launcherEnvVars = agent === "claude" ? atomicTempEnv() : {};
507
+ const launcherEnvVars = {
508
+ ...(agent === "claude" ? atomicTempEnv() : {}),
509
+ ...terminalCapabilityEnv(),
510
+ ...workflowDiagnosticsEnv(),
511
+ };
508
512
 
509
513
  // Inputs are passed through as base64-encoded JSON so long multiline
510
514
  // text values survive shell quoting without any further escaping.
@@ -579,6 +583,29 @@ export async function executeWorkflow(
579
583
  return { id: workflowRunId, tmuxSessionName };
580
584
  }
581
585
 
586
+ function workflowDiagnosticsEnv(): Record<string, string> {
587
+ const keys = [
588
+ "ATOMIC_TUI_DIAGNOSTICS",
589
+ "ATOMIC_TUI_DIAGNOSTICS_DIR",
590
+ "ATOMIC_TUI_DIAGNOSTICS_INTERVAL_MS",
591
+ "ATOMIC_TUI_DIAGNOSTICS_MAX",
592
+ "ATOMIC_TUI_DIAGNOSTICS_OPENTUI_DUMP",
593
+ ];
594
+ const env: Record<string, string> = {};
595
+ for (const key of keys) {
596
+ const value = process.env[key];
597
+ if (value !== undefined) env[key] = value;
598
+ }
599
+ return env;
600
+ }
601
+
602
+ function terminalCapabilityEnv(): Record<string, string> {
603
+ const env: Record<string, string> = {};
604
+ const colorterm = process.env.COLORTERM;
605
+ if (colorterm !== undefined) env.COLORTERM = colorterm;
606
+ return env;
607
+ }
608
+
582
609
  /**
583
610
  * Print a short banner telling the user the workflow is running in the
584
611
  * background and how to attach to it. Written to stdout so scripts can
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { ThemeMode } from "@opentui/core";
11
+ import { flavors, type CatppuccinFlavor } from "@catppuccin/palette";
11
12
 
12
13
  // ---------------------------------------------------------------------------
13
14
  // Theme type
@@ -15,56 +16,47 @@ import type { ThemeMode } from "@opentui/core";
15
16
 
16
17
  export interface TerminalTheme {
17
18
  bg: string;
19
+ backgroundPanel: string;
20
+ backgroundElement: string;
18
21
  surface: string;
19
22
  selection: string;
20
23
  border: string;
21
24
  borderDim: string;
22
25
  accent: string;
23
26
  text: string;
27
+ textMuted: string;
24
28
  dim: string;
29
+ info: string;
25
30
  success: string;
26
31
  error: string;
27
32
  warning: string;
28
33
  mauve: string;
29
34
  }
30
35
 
31
- // ---------------------------------------------------------------------------
32
- // Catppuccin Mocha (dark)
33
- // ---------------------------------------------------------------------------
34
-
35
- const CATPPUCCIN_MOCHA: TerminalTheme = {
36
- bg: "#1e1e2e", // Base
37
- surface: "#313244", // Surface0
38
- selection: "#45475a", // Surface1
39
- border: "#6c7086", // Overlay0
40
- borderDim: "#585b70", // Surface2
41
- accent: "#89b4fa", // Blue
42
- text: "#cdd6f4", // Text
43
- dim: "#7f849c", // Overlay1
44
- success: "#a6e3a1", // Green
45
- error: "#f38ba8", // Red
46
- warning: "#f9e2af", // Yellow
47
- mauve: "#cba6f7", // Mauve
48
- };
49
-
50
- // ---------------------------------------------------------------------------
51
- // Catppuccin Latte (light)
52
- // ---------------------------------------------------------------------------
36
+ function buildTerminalTheme(flavor: CatppuccinFlavor): TerminalTheme {
37
+ const { colors } = flavor;
38
+ return {
39
+ bg: colors.base.hex,
40
+ backgroundPanel: colors.mantle.hex,
41
+ backgroundElement: colors.crust.hex,
42
+ surface: colors.surface0.hex,
43
+ selection: colors.surface1.hex,
44
+ border: colors.overlay0.hex,
45
+ borderDim: colors.surface2.hex,
46
+ accent: colors.blue.hex,
47
+ text: colors.text.hex,
48
+ textMuted: flavor.dark ? colors.subtext0.hex : colors.subtext1.hex,
49
+ dim: colors.overlay1.hex,
50
+ info: colors.sky.hex,
51
+ success: colors.green.hex,
52
+ error: colors.red.hex,
53
+ warning: colors.yellow.hex,
54
+ mauve: colors.mauve.hex,
55
+ };
56
+ }
53
57
 
54
- const CATPPUCCIN_LATTE: TerminalTheme = {
55
- bg: "#eff1f5", // Base
56
- surface: "#ccd0da", // Surface0
57
- selection: "#bcc0cc", // Surface1
58
- border: "#9ca0b0", // Overlay0
59
- borderDim: "#acb0be", // Surface2
60
- accent: "#1e66f5", // Blue
61
- text: "#4c4f69", // Text
62
- dim: "#8c8fa1", // Overlay1
63
- success: "#40a02b", // Green
64
- error: "#d20f39", // Red
65
- warning: "#df8e1d", // Yellow
66
- mauve: "#8839ef", // Mauve
67
- };
58
+ const CATPPUCCIN_MOCHA = buildTerminalTheme(flavors.mocha);
59
+ const CATPPUCCIN_LATTE = buildTerminalTheme(flavors.latte);
68
60
 
69
61
  // ---------------------------------------------------------------------------
70
62
  // Public API
@@ -22,7 +22,7 @@
22
22
  * library, just what auto-sync needs to stop being visually noisy.
23
23
  */
24
24
 
25
- import { COLORS } from "../../theme/colors.ts";
25
+ import { COLORS, PALETTE, paletteRgb, type PaletteKey } from "../../theme/colors.ts";
26
26
  import {
27
27
  supportsTrueColor,
28
28
  supports256Color,
@@ -34,9 +34,9 @@ const BAR_EMPTY = "・";
34
34
 
35
35
  /**
36
36
  * Semantic bar states mapped to Catppuccin Mocha colors:
37
- * progress → Yellow #f9e2af (warm accent; "in flight")
38
- * success → Green #a6e3a1 (universal "completed")
39
- * error → Red #f38ba8 (universal "failed")
37
+ * progress → Yellow (warm accent; "in flight")
38
+ * success → Green (universal "completed")
39
+ * error → Red (universal "failed")
40
40
  *
41
41
  * The empty track stays dim regardless — only the filled portion carries
42
42
  * the status signal, which keeps the bar legible while still telegraphing
@@ -44,17 +44,16 @@ const BAR_EMPTY = "・";
44
44
  */
45
45
  type BarState = "progress" | "success" | "error";
46
46
 
47
+ const BAR_STATE_PALETTE: Record<BarState, PaletteKey> = {
48
+ progress: "warning",
49
+ success: "success",
50
+ error: "error",
51
+ };
52
+
47
53
  function fillColor(state: BarState): string {
48
54
  if (supportsTrueColor()) {
49
- switch (state) {
50
- case "success":
51
- return "\x1b[38;2;166;227;161m"; // Catppuccin Green #a6e3a1
52
- case "error":
53
- return "\x1b[38;2;243;139;168m"; // Catppuccin Red #f38ba8
54
- case "progress":
55
- default:
56
- return "\x1b[38;2;249;226;175m"; // Catppuccin Yellow #f9e2af
57
- }
55
+ const [r, g, b] = PALETTE[BAR_STATE_PALETTE[state]];
56
+ return `\x1b[38;2;${r};${g};${b}m`;
58
57
  }
59
58
  if (supports256Color()) {
60
59
  switch (state) {
@@ -78,7 +77,7 @@ function fillColor(state: BarState): string {
78
77
  }
79
78
  }
80
79
 
81
- type RGB = [number, number, number];
80
+ type RGB = readonly [number, number, number];
82
81
 
83
82
  /**
84
83
  * Gradient endpoints for the filled bar segment. Each state interpolates
@@ -88,12 +87,12 @@ type RGB = [number, number, number];
88
87
  function gradientEndpoints(state: BarState): { start: RGB; end: RGB } {
89
88
  switch (state) {
90
89
  case "success":
91
- return { start: [126, 201, 138], end: [166, 227, 161] };
90
+ return { start: paletteRgb("teal"), end: paletteRgb("green") };
92
91
  case "error":
93
- return { start: [224, 108, 136], end: [243, 139, 168] };
92
+ return { start: paletteRgb("maroon"), end: paletteRgb("red") };
94
93
  case "progress":
95
94
  default:
96
- return { start: [242, 196, 120], end: [249, 226, 175] };
95
+ return { start: paletteRgb("peach"), end: paletteRgb("yellow") };
97
96
  }
98
97
  }
99
98
 
@@ -1,4 +1,5 @@
1
1
  import { supportsColor, supportsTrueColor } from "../services/system/detect.ts";
2
+ import { flavors, type ColorName } from "@catppuccin/palette";
2
3
 
3
4
  /**
4
5
  * ANSI color and formatting codes for CLI output
@@ -31,20 +32,24 @@ export const COLORS = supportsColor() ? ANSI_CODES : NO_COLORS;
31
32
  //
32
33
  // Truecolor terminals get the full palette via 24-bit ANSI SGR; legacy
33
34
  // terminals degrade to basic ANSI; NO_COLOR emits plain text.
34
- // Hex values mirror .impeccable.md and src/sdk/runtime/theme.ts.
35
35
  // ---------------------------------------------------------------------------
36
36
 
37
37
  export type PaletteKey = "text" | "dim" | "accent" | "success" | "error" | "warning" | "mauve" | "info";
38
38
 
39
+ export function paletteRgb(name: ColorName): readonly [number, number, number] {
40
+ const { r, g, b } = flavors.mocha.colors[name].rgb;
41
+ return [r, g, b];
42
+ }
43
+
39
44
  export const PALETTE: Record<PaletteKey, readonly [number, number, number]> = {
40
- text: [205, 214, 244], // #cdd6f4
41
- dim: [127, 132, 156], // #7f849c (Overlay1)
42
- accent: [137, 180, 250], // #89b4fa (Blue)
43
- success: [166, 227, 161], // #a6e3a1 (Green)
44
- error: [243, 139, 168], // #f38ba8 (Red)
45
- warning: [249, 226, 175], // #f9e2af (Yellow)
46
- mauve: [203, 166, 247], // #cba6f7 (Mauve)
47
- info: [137, 220, 235], // #89dceb (Sky)
45
+ text: paletteRgb("text"),
46
+ dim: paletteRgb("overlay1"),
47
+ accent: paletteRgb("blue"),
48
+ success: paletteRgb("green"),
49
+ error: paletteRgb("red"),
50
+ warning: paletteRgb("yellow"),
51
+ mauve: paletteRgb("mauve"),
52
+ info: paletteRgb("sky"),
48
53
  };
49
54
 
50
55
  export interface PaintOptions {
package/src/theme/logo.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  supports256Color,
10
10
  supportsColor,
11
11
  } from "../services/system/detect.ts";
12
+ import { flavors, type CatppuccinFlavor, type ColorName } from "@catppuccin/palette";
12
13
 
13
14
  export const ATOMIC_BLOCK_LOGO = [
14
15
  "█▀▀█ ▀▀█▀▀ █▀▀█ █▀▄▀█ ▀█▀ █▀▀",
@@ -16,17 +17,27 @@ export const ATOMIC_BLOCK_LOGO = [
16
17
  "▀ ▀ ▀ ▀▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀",
17
18
  ];
18
19
 
19
- /** Catppuccin-inspired gradient (dark terminal). */
20
- export const GRADIENT_DARK = [
21
- "#f5e0dc", "#f2cdcd", "#f5c2e7", "#cba6f7",
22
- "#b4befe", "#89b4fa", "#74c7ec", "#89dceb", "#94e2d5",
23
- ];
20
+ const GRADIENT_COLOR_NAMES = [
21
+ "rosewater",
22
+ "flamingo",
23
+ "pink",
24
+ "mauve",
25
+ "lavender",
26
+ "blue",
27
+ "sapphire",
28
+ "sky",
29
+ "teal",
30
+ ] as const satisfies readonly ColorName[];
24
31
 
25
- /** Catppuccin-inspired gradient (light terminal). */
26
- export const GRADIENT_LIGHT = [
27
- "#dc8a78", "#dd7878", "#ea76cb", "#8839ef",
28
- "#7287fd", "#1e66f5", "#209fb5", "#04a5e5", "#179299",
29
- ];
32
+ function gradientFromFlavor(flavor: CatppuccinFlavor): string[] {
33
+ return GRADIENT_COLOR_NAMES.map((name) => flavor.colors[name].hex);
34
+ }
35
+
36
+ /** Catppuccin gradient (dark terminal). */
37
+ export const GRADIENT_DARK = gradientFromFlavor(flavors.mocha);
38
+
39
+ /** Catppuccin gradient (light terminal). */
40
+ export const GRADIENT_LIGHT = gradientFromFlavor(flavors.latte);
30
41
 
31
42
  /** 256-color approximation of the gradient. */
32
43
  export const GRADIENT_256 = [224, 218, 219, 183, 147, 111, 117, 159, 115];
@@ -40,7 +51,7 @@ function hexToRgb(hex: string): [number, number, number] {
40
51
  ];
41
52
  }
42
53
 
43
- function interpolateHex(gradient: string[], t: number): [number, number, number] {
54
+ function interpolateHex(gradient: readonly string[], t: number): [number, number, number] {
44
55
  const pos = Math.max(0, Math.min(1, t)) * (gradient.length - 1);
45
56
  const lo = Math.floor(pos);
46
57
  const hi = Math.min(lo + 1, gradient.length - 1);
@@ -60,7 +71,7 @@ function interpolate256(gradient: number[], t: number): number {
60
71
  return gradient[lo]!;
61
72
  }
62
73
 
63
- export function colorizeLineTrueColor(line: string, gradient: string[]): string {
74
+ export function colorizeLineTrueColor(line: string, gradient: readonly string[]): string {
64
75
  let out = "";
65
76
  const len = line.length;
66
77
  for (let i = 0; i < len; i++) {