ctheme 0.1.0 → 0.1.2

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/DEVELOPMENT.md ADDED
@@ -0,0 +1,262 @@
1
+ # Development
2
+
3
+ ## Purpose
4
+
5
+ `ctheme` is a terminal theming CLI.
6
+
7
+ Scope:
8
+
9
+ - terminal color themes
10
+ - terminal font selection
11
+ - live Apple Terminal profile switching
12
+ - config snippet generation for Ghostty, Kitty, and WezTerm
13
+ - custom theme authoring
14
+ - Google Fonts discovery and install helpers
15
+
16
+ Out of scope:
17
+
18
+ - editor themes
19
+ - app chrome theming
20
+ - IDE plugins
21
+ - Codex-specific config behavior
22
+
23
+ ## Repository Layout
24
+
25
+ ```text
26
+ bin/ctheme.js Main CLI entrypoint and all runtime logic
27
+ README.md User-facing docs
28
+ DEVELOPMENT.md Contributor docs
29
+ package.json npm package metadata
30
+ ```
31
+
32
+ This project is intentionally small. Most behavior lives in one file so it stays easy to ship and debug.
33
+
34
+ ## Runtime State
35
+
36
+ `ctheme` keeps its own state under:
37
+
38
+ ```text
39
+ ~/.ctheme/themes
40
+ ~/.ctheme/snippets
41
+ ~/.ctheme/snippets/.ctheme-state.json
42
+ ~/Library/Fonts/pretty-code
43
+ ```
44
+
45
+ What each path is for:
46
+
47
+ - `~/.ctheme/themes`: saved custom theme JSON palettes
48
+ - `~/.ctheme/snippets`: generated terminal config snippets and AppleScript files
49
+ - `~/.ctheme/snippets/.ctheme-state.json`: restore state for `ctheme reset`
50
+ - `~/Library/Fonts/pretty-code`: Google Fonts installed by the CLI
51
+
52
+ Relevant env vars:
53
+
54
+ ```text
55
+ CTHEME_HOME
56
+ CTHEME_THEME_DIR
57
+ CTHEME_SNIPPET_DIR
58
+ CTHEME_SKIP_FONT_BOOTSTRAP
59
+ ```
60
+
61
+ ## Command Map
62
+
63
+ Main commands:
64
+
65
+ - `ctheme use <theme>`: apply a theme live to the current terminal when supported
66
+ - `ctheme reset`: restore the original terminal state
67
+ - `ctheme list`: list bundled and saved themes
68
+ - `ctheme preview <theme>`: inspect palette colors in the current shell
69
+ - `ctheme make`: create a theme from flags or launch the wizard
70
+ - `ctheme wizard`: force the interactive onboarding flow
71
+ - `ctheme init <name>`: create a starter theme file
72
+ - `ctheme term <target>`: generate or apply terminal-target snippets
73
+ - `ctheme font ...`: search, install, and list fonts
74
+
75
+ ## Internal Architecture
76
+
77
+ ### 1. Presets
78
+
79
+ Bundled presets are plain palette objects in `PRESETS`.
80
+
81
+ Each preset should carry:
82
+
83
+ - colors
84
+ - terminal font
85
+ - UI font
86
+ - code font
87
+
88
+ The bundled presets should feel visibly distinct. Avoid making every theme share the same font pairing.
89
+
90
+ ### 2. Theme Building
91
+
92
+ `buildTheme()` turns a palette into the normalized theme object used by preview and terminal rendering.
93
+
94
+ Important rule:
95
+
96
+ - readability wins over palette purity
97
+
98
+ Light themes in particular are normalized through contrast helpers so accents and syntax colors remain readable.
99
+
100
+ ### 3. Terminal Writers
101
+
102
+ Target-specific renderers:
103
+
104
+ - `renderAppleTerminalProfile()`
105
+ - `renderGhosttySnippet()`
106
+ - `renderKittySnippet()`
107
+ - `renderWeztermSnippet()`
108
+
109
+ Target-specific application:
110
+
111
+ - Apple Terminal applies live through AppleScript
112
+ - Ghostty and Kitty get include lines appended
113
+ - WezTerm writes a standalone file when safe
114
+
115
+ ### 4. Wizard Flow
116
+
117
+ The wizard is implemented in `runMakeWizard()`.
118
+
119
+ Current flow:
120
+
121
+ 1. pick a base preset
122
+ 2. name the theme
123
+ 3. adjust colors
124
+ 4. choose fonts
125
+ 5. review summary
126
+ 6. save
127
+ 7. optionally install fonts
128
+ 8. optionally apply live
129
+
130
+ When changing the wizard:
131
+
132
+ - keep prompts short
133
+ - always show a default
134
+ - keep blank input as “accept default”
135
+ - prefer a summary/confirmation before writing files
136
+
137
+ ### 5. Font Helpers
138
+
139
+ Font listing uses macOS AppKit through JXA.
140
+
141
+ Google Fonts install flow:
142
+
143
+ 1. search metadata from `fonts.google.com`
144
+ 2. resolve family path from `google/fonts`
145
+ 3. download font files into `~/Library/Fonts/pretty-code`
146
+
147
+ Do not bundle font files in the repo.
148
+
149
+ ### 6. Install Bootstrap
150
+
151
+ `npm install -g ctheme` runs `scripts/postinstall.js`.
152
+
153
+ That script:
154
+
155
+ - runs on macOS only
156
+ - best-effort installs the curated default font pack
157
+ - never hard-fails the package install because of a font download problem
158
+
159
+ Skip it with:
160
+
161
+ ```bash
162
+ CTHEME_SKIP_FONT_BOOTSTRAP=1 npm install -g ctheme
163
+ ```
164
+
165
+ ## Local Development
166
+
167
+ Install the CLI locally:
168
+
169
+ ```bash
170
+ npm install -g . --force
171
+ ```
172
+
173
+ Basic smoke checks:
174
+
175
+ ```bash
176
+ ctheme --help
177
+ ctheme list
178
+ ctheme preview solarized
179
+ ctheme font list
180
+ ctheme status
181
+ ```
182
+
183
+ ## Manual Test Matrix
184
+
185
+ ### Apple Terminal
186
+
187
+ ```bash
188
+ ctheme use solarized
189
+ ctheme use harbor --default
190
+ ctheme reset
191
+ ```
192
+
193
+ Verify:
194
+
195
+ - theme applies immediately
196
+ - `--default` changes startup/default profile
197
+ - `reset` restores the saved profile or `Basic`
198
+
199
+ ### Wizard
200
+
201
+ ```bash
202
+ ctheme wizard
203
+ ctheme make
204
+ ctheme make mytheme --preset harbor --terminal-font "Space Mono"
205
+ ```
206
+
207
+ Verify:
208
+
209
+ - defaults are shown
210
+ - summary appears before writing
211
+ - saved JSON lands in `~/.ctheme/themes`
212
+ - `ctheme use mytheme` picks up the saved terminal font
213
+
214
+ ### Fonts
215
+
216
+ ```bash
217
+ ctheme font search "mono"
218
+ ctheme font install "IBM Plex Mono"
219
+ ctheme font list
220
+ ```
221
+
222
+ Verify:
223
+
224
+ - search returns real families
225
+ - install downloads files into `~/Library/Fonts/pretty-code`
226
+ - list prints real family names, not ObjC bridge values
227
+
228
+ ### Pack/Publish
229
+
230
+ ```bash
231
+ npm test
232
+ npm pack --dry-run
233
+ npm publish --dry-run
234
+ ```
235
+
236
+ ## Release Process
237
+
238
+ 1. update version in `package.json`
239
+ 2. run smoke tests
240
+ 3. run `npm pack --dry-run`
241
+ 4. run `npm publish --dry-run`
242
+ 5. commit
243
+ 6. push `main`
244
+ 7. publish for real with `npm publish`
245
+
246
+ ## Contribution Rules
247
+
248
+ - Keep the product terminal-focused.
249
+ - Prefer short commands over complicated command trees.
250
+ - Preserve live-apply behavior wherever possible.
251
+ - When a target cannot reload live, say that clearly.
252
+ - Avoid growing the tool into a general desktop-theme manager.
253
+ - Do not reintroduce Codex/editor/app-specific behavior.
254
+ - Do not add hidden state outside `~/.ctheme` and the managed fonts directory.
255
+
256
+ ## Git Hygiene
257
+
258
+ This repo should stay self-contained.
259
+
260
+ - commit from `/Users/arjunkshah21/Downloads/pretty-code`
261
+ - push to `origin main`
262
+ - do not mix unrelated parent-directory changes into this repo
package/README.md CHANGED
@@ -18,6 +18,12 @@ From npm:
18
18
  npm install -g ctheme
19
19
  ```
20
20
 
21
+ On macOS, install also preloads the curated default font pack used by the bundled themes. If you want to skip that during install:
22
+
23
+ ```bash
24
+ CTHEME_SKIP_FONT_BOOTSTRAP=1 npm install -g ctheme
25
+ ```
26
+
21
27
  From GitHub:
22
28
 
23
29
  ```bash
@@ -71,6 +77,7 @@ The wizard walks through:
71
77
  - terminal font
72
78
  - UI font
73
79
  - code font
80
+ - theme summary before save
74
81
  - optional Google Fonts install
75
82
  - optional live apply
76
83
 
@@ -149,6 +156,7 @@ solarized, solarized-dark, velvet
149
156
  ```
150
157
 
151
158
  Bundled themes intentionally vary their font pairings so they do not all feel the same.
159
+ The npm install bootstrap preinstalls the curated font set those presets rely on, so the bundled themes render correctly immediately on macOS.
152
160
 
153
161
  ## Contributing
154
162
 
package/bin/ctheme.js CHANGED
@@ -94,9 +94,9 @@ const BUILTIN_THEMES = [
94
94
  ];
95
95
 
96
96
  const FONT_CHOICES = {
97
- ui: ["Manrope", "Space Grotesk", "Outfit", "Sora", "Plus Jakarta Sans", "Newsreader", "Fraunces"],
98
- code: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono"],
99
- terminal: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono"]
97
+ ui: ["Manrope", "Space Grotesk", "Outfit", "Sora", "Plus Jakarta Sans", "Newsreader", "Fraunces", "Bricolage Grotesque", "Urbanist", "Source Sans 3", "IBM Plex Sans", "Instrument Serif", "Syne"],
98
+ code: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono", "Roboto Mono", "Azeret Mono", "Victor Mono", "Ubuntu Mono"],
99
+ terminal: ["IBM Plex Mono", "Space Mono", "DM Mono", "Source Code Pro", "Fira Code", "JetBrains Mono", "Roboto Mono", "Azeret Mono", "Victor Mono", "Ubuntu Mono"]
100
100
  };
101
101
 
102
102
  const PRESETS = {
@@ -117,7 +117,7 @@ const PRESETS = {
117
117
  cyan: "#39c5cf"
118
118
  },
119
119
  paper: {
120
- fonts: { terminal: "IBM Plex Mono", ui: "Newsreader", code: "IBM Plex Mono" },
120
+ fonts: { terminal: "Source Code Pro", ui: "Newsreader", code: "Source Code Pro" },
121
121
  accent: "#005cc5",
122
122
  bg: "#fff8e8",
123
123
  surface: "#fffdf7",
@@ -149,7 +149,7 @@ const PRESETS = {
149
149
  cyan: "#7dcfff"
150
150
  },
151
151
  mint: {
152
- fonts: { terminal: "JetBrains Mono", ui: "Plus Jakarta Sans", code: "JetBrains Mono" },
152
+ fonts: { terminal: "Roboto Mono", ui: "Plus Jakarta Sans", code: "Roboto Mono" },
153
153
  accent: "#2bb673",
154
154
  bg: "#081411",
155
155
  surface: "#10201b",
@@ -165,7 +165,7 @@ const PRESETS = {
165
165
  cyan: "#5ad1e6"
166
166
  },
167
167
  obsidian: {
168
- fonts: { terminal: "IBM Plex Mono", ui: "Outfit", code: "IBM Plex Mono" },
168
+ fonts: { terminal: "Azeret Mono", ui: "Outfit", code: "Azeret Mono" },
169
169
  accent: "#58a6ff",
170
170
  bg: "#05070a",
171
171
  surface: "#0e131a",
@@ -181,7 +181,7 @@ const PRESETS = {
181
181
  cyan: "#7dd3fc"
182
182
  },
183
183
  glacier: {
184
- fonts: { terminal: "Space Mono", ui: "Space Grotesk", code: "Space Mono" },
184
+ fonts: { terminal: "Space Mono", ui: "Urbanist", code: "Space Mono" },
185
185
  accent: "#7aa2f7",
186
186
  bg: "#0a1220",
187
187
  surface: "#121c2f",
@@ -197,7 +197,7 @@ const PRESETS = {
197
197
  cyan: "#7dcfff"
198
198
  },
199
199
  cobalt: {
200
- fonts: { terminal: "Space Mono", ui: "Sora", code: "Space Mono" },
200
+ fonts: { terminal: "Victor Mono", ui: "Bricolage Grotesque", code: "Victor Mono" },
201
201
  accent: "#4da3ff",
202
202
  bg: "#09111f",
203
203
  surface: "#10203a",
@@ -229,7 +229,7 @@ const PRESETS = {
229
229
  cyan: "#8bd3dd"
230
230
  },
231
231
  lotus: {
232
- fonts: { terminal: "IBM Plex Mono", ui: "Newsreader", code: "IBM Plex Mono" },
232
+ fonts: { terminal: "Ubuntu Mono", ui: "Instrument Serif", code: "Ubuntu Mono" },
233
233
  accent: "#d16d9e",
234
234
  bg: "#fff7f3",
235
235
  surface: "#fffdfb",
@@ -245,7 +245,7 @@ const PRESETS = {
245
245
  cyan: "#4d8ca1"
246
246
  },
247
247
  dune: {
248
- fonts: { terminal: "JetBrains Mono", ui: "Sora", code: "JetBrains Mono" },
248
+ fonts: { terminal: "Fira Code", ui: "Syne", code: "Fira Code" },
249
249
  accent: "#d97706",
250
250
  bg: "#16110c",
251
251
  surface: "#231912",
@@ -261,7 +261,7 @@ const PRESETS = {
261
261
  cyan: "#67e8f9"
262
262
  },
263
263
  forest: {
264
- fonts: { terminal: "IBM Plex Mono", ui: "Newsreader", code: "IBM Plex Mono" },
264
+ fonts: { terminal: "IBM Plex Mono", ui: "IBM Plex Sans", code: "IBM Plex Mono" },
265
265
  accent: "#7ccf7a",
266
266
  bg: "#08100b",
267
267
  surface: "#112016",
@@ -277,7 +277,7 @@ const PRESETS = {
277
277
  cyan: "#6ee7b7"
278
278
  },
279
279
  aurora: {
280
- fonts: { terminal: "Space Mono", ui: "Outfit", code: "Space Mono" },
280
+ fonts: { terminal: "Space Mono", ui: "Urbanist", code: "Space Mono" },
281
281
  accent: "#7c5cff",
282
282
  bg: "#0f0a1f",
283
283
  surface: "#181131",
@@ -293,7 +293,7 @@ const PRESETS = {
293
293
  cyan: "#7bdff2"
294
294
  },
295
295
  espresso: {
296
- fonts: { terminal: "DM Mono", ui: "Fraunces", code: "DM Mono" },
296
+ fonts: { terminal: "Victor Mono", ui: "Instrument Serif", code: "Victor Mono" },
297
297
  accent: "#c67c4e",
298
298
  bg: "#120d0b",
299
299
  surface: "#1d1512",
@@ -325,7 +325,7 @@ const PRESETS = {
325
325
  cyan: "#bde0fe"
326
326
  },
327
327
  neon: {
328
- fonts: { terminal: "Space Mono", ui: "Space Grotesk", code: "Space Mono" },
328
+ fonts: { terminal: "Azeret Mono", ui: "Bricolage Grotesque", code: "Azeret Mono" },
329
329
  accent: "#00f5d4",
330
330
  bg: "#090414",
331
331
  surface: "#130a24",
@@ -341,7 +341,7 @@ const PRESETS = {
341
341
  cyan: "#00bbf9"
342
342
  },
343
343
  harbor: {
344
- fonts: { terminal: "IBM Plex Mono", ui: "Plus Jakarta Sans", code: "IBM Plex Mono" },
344
+ fonts: { terminal: "Roboto Mono", ui: "Plus Jakarta Sans", code: "Roboto Mono" },
345
345
  accent: "#3ba4c9",
346
346
  bg: "#f4f8fb",
347
347
  surface: "#ffffff",
@@ -389,7 +389,7 @@ const PRESETS = {
389
389
  cyan: "#2aa198"
390
390
  },
391
391
  velvet: {
392
- fonts: { terminal: "DM Mono", ui: "Fraunces", code: "DM Mono" },
392
+ fonts: { terminal: "Ubuntu Mono", ui: "Fraunces", code: "Ubuntu Mono" },
393
393
  accent: "#d4a5ff",
394
394
  bg: "#140d18",
395
395
  surface: "#211328",
@@ -406,179 +406,6 @@ const PRESETS = {
406
406
  }
407
407
  };
408
408
 
409
- const APP_PRESETS = {
410
- evergreen: {
411
- codeThemeId: "everforest",
412
- theme: {
413
- accent: "#93b259",
414
- contrast: 45,
415
- fonts: { code: "IBM Plex Mono", ui: "Manrope" },
416
- ink: "#5c6a72",
417
- opaqueWindows: true,
418
- semanticColors: {
419
- diffAdded: "#8da101",
420
- diffRemoved: "#f85552",
421
- skill: "#df69ba"
422
- },
423
- surface: "#fdf6e3"
424
- },
425
- variant: "light"
426
- },
427
- "evergreen-dark": {
428
- codeThemeId: "everforest",
429
- theme: {
430
- accent: "#a7c080",
431
- contrast: 60,
432
- fonts: { code: "IBM Plex Mono", ui: "Manrope" },
433
- ink: "#d3c6aa",
434
- opaqueWindows: true,
435
- semanticColors: {
436
- diffAdded: "#a7c080",
437
- diffRemoved: "#e67e80",
438
- skill: "#d699b6"
439
- },
440
- surface: "#2d353b"
441
- },
442
- variant: "dark"
443
- },
444
- solarized: {
445
- codeThemeId: "solarized",
446
- theme: {
447
- accent: "#268bd2",
448
- contrast: 45,
449
- fonts: { code: "Source Code Pro", ui: "Manrope" },
450
- ink: "#586e75",
451
- opaqueWindows: true,
452
- semanticColors: {
453
- diffAdded: "#859900",
454
- diffRemoved: "#dc322f",
455
- skill: "#d33682"
456
- },
457
- surface: "#fdf6e3"
458
- },
459
- variant: "light"
460
- },
461
- "solarized-dark": {
462
- codeThemeId: "solarized",
463
- theme: {
464
- accent: "#268bd2",
465
- contrast: 60,
466
- fonts: { code: "Source Code Pro", ui: "Manrope" },
467
- ink: "#839496",
468
- opaqueWindows: false,
469
- semanticColors: {
470
- diffAdded: "#859900",
471
- diffRemoved: "#dc322f",
472
- skill: "#d33682"
473
- },
474
- surface: "#002b36"
475
- },
476
- variant: "dark"
477
- },
478
- nord: {
479
- codeThemeId: "nord",
480
- theme: {
481
- accent: "#5e81ac",
482
- contrast: 48,
483
- fonts: { code: "Space Mono", ui: "Manrope" },
484
- ink: "#4c566a",
485
- opaqueWindows: true,
486
- semanticColors: {
487
- diffAdded: "#a3be8c",
488
- diffRemoved: "#bf616a",
489
- skill: "#b48ead"
490
- },
491
- surface: "#eceff4"
492
- },
493
- variant: "light"
494
- },
495
- "nord-dark": {
496
- codeThemeId: "nord",
497
- theme: {
498
- accent: "#88c0d0",
499
- contrast: 60,
500
- fonts: { code: "Space Mono", ui: "Manrope" },
501
- ink: "#e5e9f0",
502
- opaqueWindows: true,
503
- semanticColors: {
504
- diffAdded: "#a3be8c",
505
- diffRemoved: "#bf616a",
506
- skill: "#b48ead"
507
- },
508
- surface: "#2e3440"
509
- },
510
- variant: "dark"
511
- },
512
- rosepine: {
513
- codeThemeId: "rose-pine-dawn",
514
- theme: {
515
- accent: "#56949f",
516
- contrast: 44,
517
- fonts: { code: "DM Mono", ui: "Manrope" },
518
- ink: "#575279",
519
- opaqueWindows: true,
520
- semanticColors: {
521
- diffAdded: "#286983",
522
- diffRemoved: "#b4637a",
523
- skill: "#907aa9"
524
- },
525
- surface: "#faf4ed"
526
- },
527
- variant: "light"
528
- },
529
- "rosepine-dark": {
530
- codeThemeId: "rose-pine",
531
- theme: {
532
- accent: "#9ccfd8",
533
- contrast: 58,
534
- fonts: { code: "DM Mono", ui: "Manrope" },
535
- ink: "#e0def4",
536
- opaqueWindows: true,
537
- semanticColors: {
538
- diffAdded: "#31748f",
539
- diffRemoved: "#eb6f92",
540
- skill: "#c4a7e7"
541
- },
542
- surface: "#191724"
543
- },
544
- variant: "dark"
545
- },
546
- graphite: {
547
- codeThemeId: "github",
548
- theme: {
549
- accent: "#586069",
550
- contrast: 42,
551
- fonts: { code: "IBM Plex Mono", ui: "Manrope" },
552
- ink: "#24292f",
553
- opaqueWindows: true,
554
- semanticColors: {
555
- diffAdded: "#1a7f37",
556
- diffRemoved: "#cf222e",
557
- skill: "#8250df"
558
- },
559
- surface: "#f6f8fa"
560
- },
561
- variant: "light"
562
- },
563
- "graphite-dark": {
564
- codeThemeId: "github",
565
- theme: {
566
- accent: "#7d8590",
567
- contrast: 58,
568
- fonts: { code: "IBM Plex Mono", ui: "Manrope" },
569
- ink: "#c9d1d9",
570
- opaqueWindows: true,
571
- semanticColors: {
572
- diffAdded: "#3fb950",
573
- diffRemoved: "#f85149",
574
- skill: "#d2a8ff"
575
- },
576
- surface: "#0d1117"
577
- },
578
- variant: "dark"
579
- }
580
- };
581
-
582
409
  async function main() {
583
410
  try {
584
411
  const args = process.argv.slice(2);
@@ -862,11 +689,13 @@ async function runMakeWizard(initialName, flags) {
862
689
 
863
690
  try {
864
691
  const availablePresets = Object.keys(PRESETS).sort();
865
- console.log(`Theme wizard`);
692
+ console.log("Theme wizard");
693
+ console.log("Press Enter to keep the default shown in brackets.");
866
694
  console.log(`Presets: ${availablePresets.join(", ")}`);
867
695
  console.log(`UI font ideas: ${FONT_CHOICES.ui.join(", ")}`);
868
696
  console.log(`Code/terminal font ideas: ${FONT_CHOICES.code.join(", ")}`);
869
697
 
698
+ console.log("\nStep 1: Base");
870
699
  const basePresetName = await promptWithDefault(
871
700
  rl,
872
701
  "Base preset",
@@ -876,6 +705,7 @@ async function runMakeWizard(initialName, flags) {
876
705
  const defaultName = initialName || `${basePresetName}-custom`;
877
706
  const themeName = await promptWithDefault(rl, "Theme name", defaultName);
878
707
 
708
+ console.log("\nStep 2: Colors");
879
709
  const accent = await promptWithDefault(rl, "Accent color", flags.accent || preset.accent);
880
710
  const bg = await promptWithDefault(rl, "Background color", flags.bg || preset.bg);
881
711
  const surface = await promptWithDefault(rl, "Surface color", flags.surface || preset.surface);
@@ -888,6 +718,7 @@ async function runMakeWizard(initialName, flags) {
888
718
  const muted = await promptWithDefault(rl, "Muted color", flags.muted || preset.muted);
889
719
  const dim = await promptWithDefault(rl, "Dim color", flags.dim || preset.dim);
890
720
 
721
+ console.log("\nStep 3: Fonts");
891
722
  const fonts = {
892
723
  terminal: await promptWithDefault(
893
724
  rl,
@@ -906,6 +737,26 @@ async function runMakeWizard(initialName, flags) {
906
737
  )
907
738
  };
908
739
 
740
+ console.log("\nTheme summary:");
741
+ printThemeSummary({
742
+ name: themeName,
743
+ preset: basePresetName,
744
+ accent,
745
+ bg,
746
+ surface,
747
+ surfaceAlt,
748
+ fg,
749
+ muted,
750
+ dim,
751
+ fonts
752
+ });
753
+
754
+ const shouldWrite = await promptYesNo(rl, "Save this theme?", true);
755
+ if (!shouldWrite) {
756
+ console.log("Cancelled.");
757
+ return;
758
+ }
759
+
909
760
  const autoInstallFonts = await promptYesNo(rl, "Install any missing Google fonts automatically?", true);
910
761
  if (autoInstallFonts) {
911
762
  installFontsBestEffort([fonts.terminal, fonts.ui, fonts.code]);
@@ -1367,6 +1218,21 @@ function installFontsBestEffort(fonts) {
1367
1218
  }
1368
1219
  }
1369
1220
 
1221
+ function printThemeSummary(theme) {
1222
+ console.log(` name: ${theme.name}`);
1223
+ console.log(` preset: ${theme.preset}`);
1224
+ console.log(` accent: ${theme.accent}`);
1225
+ console.log(` bg: ${theme.bg}`);
1226
+ console.log(` surface: ${theme.surface}`);
1227
+ console.log(` surface alt: ${theme.surfaceAlt}`);
1228
+ console.log(` text: ${theme.fg}`);
1229
+ console.log(` muted: ${theme.muted}`);
1230
+ console.log(` dim: ${theme.dim}`);
1231
+ console.log(` terminal font: ${theme.fonts.terminal}`);
1232
+ console.log(` ui font: ${theme.fonts.ui}`);
1233
+ console.log(` code font: ${theme.fonts.code}`);
1234
+ }
1235
+
1370
1236
  function writeThemeAssets(paths, name, palette) {
1371
1237
  ensureDir(paths.paletteDir);
1372
1238
  fs.writeFileSync(path.join(paths.paletteDir, `${name}.json`), `${JSON.stringify(palette, null, 2)}\n`, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctheme",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Theme manager for making terminals look better with colors, fonts, and live profile switching",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,13 +20,16 @@
20
20
  ],
21
21
  "files": [
22
22
  "bin",
23
- "README.md"
23
+ "DEVELOPMENT.md",
24
+ "README.md",
25
+ "scripts"
24
26
  ],
25
27
  "bin": {
26
28
  "ctheme": "bin/ctheme.js"
27
29
  },
28
30
  "scripts": {
29
- "test": "node ./bin/ctheme.js --help"
31
+ "test": "node ./bin/ctheme.js --help",
32
+ "postinstall": "node ./scripts/postinstall.js"
30
33
  },
31
34
  "engines": {
32
35
  "node": ">=18"
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("child_process");
4
+ const path = require("path");
5
+
6
+ const DEFAULT_FONTS = [
7
+ "Azeret Mono",
8
+ "Bricolage Grotesque",
9
+ "DM Mono",
10
+ "Fira Code",
11
+ "Fraunces",
12
+ "IBM Plex Mono",
13
+ "IBM Plex Sans",
14
+ "Instrument Serif",
15
+ "JetBrains Mono",
16
+ "Newsreader",
17
+ "Outfit",
18
+ "Plus Jakarta Sans",
19
+ "Roboto Mono",
20
+ "Sora",
21
+ "Source Code Pro",
22
+ "Source Sans 3",
23
+ "Space Grotesk",
24
+ "Space Mono",
25
+ "Syne",
26
+ "Ubuntu Mono",
27
+ "Urbanist",
28
+ "Victor Mono"
29
+ ];
30
+
31
+ if (process.env.CTHEME_SKIP_FONT_BOOTSTRAP === "1") {
32
+ console.log("ctheme: skipping default font bootstrap");
33
+ process.exit(0);
34
+ }
35
+
36
+ if (process.platform !== "darwin") {
37
+ console.log("ctheme: skipping default font bootstrap on non-macOS");
38
+ process.exit(0);
39
+ }
40
+
41
+ const cliPath = path.join(__dirname, "..", "bin", "ctheme.js");
42
+ console.log(`ctheme: installing bundled default fonts (${DEFAULT_FONTS.length})`);
43
+
44
+ for (const family of DEFAULT_FONTS) {
45
+ const result = spawnSync(process.execPath, [cliPath, "font", "install", family], {
46
+ stdio: "inherit",
47
+ env: {
48
+ ...process.env,
49
+ CTHEME_SKIP_FONT_BOOTSTRAP: "1"
50
+ }
51
+ });
52
+
53
+ if (result.status !== 0) {
54
+ console.log(`ctheme: skipped ${family}`);
55
+ }
56
+ }
57
+