claude-den 0.1.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.
@@ -0,0 +1,1467 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/program.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/cli/init.ts
7
+ import inquirer from "inquirer";
8
+ import chalk2 from "chalk";
9
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
10
+ import { dirname as dirname2, join as join2 } from "path";
11
+ import { homedir as homedir3 } from "os";
12
+
13
+ // src/detect/terminal.ts
14
+ import { existsSync } from "fs";
15
+ var TERMINAL_ENV_CHECKS = [
16
+ { env: "GHOSTTY_RESOURCES_DIR", type: "ghostty", name: "Ghostty" },
17
+ { env: "TERM_PROGRAM", value: "iTerm.app", type: "iterm2", name: "iTerm2" },
18
+ { env: "TERM_PROGRAM", value: "WarpTerminal", type: "warp", name: "Warp" },
19
+ { env: "KITTY_PID", type: "kitty", name: "Kitty" },
20
+ { env: "ALACRITTY_LOG", type: "alacritty", name: "Alacritty" },
21
+ {
22
+ env: "TERM_PROGRAM",
23
+ value: "Apple_Terminal",
24
+ type: "terminal.app",
25
+ name: "Terminal.app"
26
+ },
27
+ {
28
+ env: "WT_SESSION",
29
+ type: "windows-terminal",
30
+ name: "Windows Terminal"
31
+ }
32
+ ];
33
+ var CONFIG_PATHS = {
34
+ ghostty: "~/.config/ghostty/config",
35
+ iterm2: "~/Library/Preferences/com.googlecode.iterm2.plist",
36
+ kitty: "~/.config/kitty/kitty.conf",
37
+ alacritty: "~/.config/alacritty/alacritty.toml",
38
+ warp: "~/.warp/themes",
39
+ "terminal.app": null,
40
+ "windows-terminal": null,
41
+ unknown: null
42
+ };
43
+ function expandHome(filepath) {
44
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
45
+ return filepath.replace(/^~/, home);
46
+ }
47
+ function getVersion(type) {
48
+ const versionEnvMap = {
49
+ iterm2: "TERM_PROGRAM_VERSION"
50
+ };
51
+ const envKey = versionEnvMap[type];
52
+ return envKey ? process.env[envKey] ?? null : null;
53
+ }
54
+ function getConfigPath(type) {
55
+ const template = CONFIG_PATHS[type];
56
+ if (!template) return null;
57
+ const expanded = expandHome(template);
58
+ return expanded;
59
+ }
60
+ function detectTerminal(env = process.env) {
61
+ for (const check2 of TERMINAL_ENV_CHECKS) {
62
+ const envValue = env[check2.env];
63
+ if (envValue === void 0) continue;
64
+ if (check2.value && envValue !== check2.value) continue;
65
+ return {
66
+ type: check2.type,
67
+ name: check2.name,
68
+ version: getVersion(check2.type),
69
+ configPath: getConfigPath(check2.type)
70
+ };
71
+ }
72
+ return {
73
+ type: "unknown",
74
+ name: "Unknown Terminal",
75
+ version: null,
76
+ configPath: null
77
+ };
78
+ }
79
+ function isTerminalInstalled(type) {
80
+ const appPaths = {
81
+ ghostty: "/Applications/Ghostty.app",
82
+ iterm2: "/Applications/iTerm.app",
83
+ warp: "/Applications/Warp.app",
84
+ kitty: "/Applications/kitty.app",
85
+ alacritty: "/Applications/Alacritty.app"
86
+ };
87
+ const appPath = appPaths[type];
88
+ if (!appPath) return false;
89
+ return existsSync(appPath);
90
+ }
91
+ function listInstalledTerminals() {
92
+ const terminals = [];
93
+ for (const check2 of TERMINAL_ENV_CHECKS) {
94
+ if (check2.type !== "terminal.app" && check2.type !== "windows-terminal" && check2.type !== "unknown") {
95
+ if (isTerminalInstalled(check2.type)) {
96
+ terminals.push({
97
+ type: check2.type,
98
+ name: check2.name,
99
+ version: null,
100
+ configPath: getConfigPath(check2.type)
101
+ });
102
+ }
103
+ }
104
+ }
105
+ return terminals;
106
+ }
107
+
108
+ // src/detect/capabilities.ts
109
+ function detectCapabilities(env = process.env) {
110
+ const colorTerm = env.COLORTERM ?? "";
111
+ const term = env.TERM ?? "";
112
+ const termProgram = env.TERM_PROGRAM ?? "";
113
+ const trueColor = colorTerm === "truecolor" || colorTerm === "24bit" || term.includes("256color") || termProgram === "iTerm.app" || termProgram === "WarpTerminal" || env.GHOSTTY_RESOURCES_DIR !== void 0;
114
+ const color256 = trueColor || term.includes("256color") || term === "xterm";
115
+ const unicode = (() => {
116
+ const lang = env.LANG ?? "";
117
+ const lcAll = env.LC_ALL ?? "";
118
+ return lang.includes("UTF-8") || lang.includes("utf-8") || lcAll.includes("UTF-8") || lcAll.includes("utf-8");
119
+ })();
120
+ const mouseSupport = env.GHOSTTY_RESOURCES_DIR !== void 0 || termProgram === "iTerm.app" || env.KITTY_PID !== void 0;
121
+ const hyperlinks = env.GHOSTTY_RESOURCES_DIR !== void 0 || termProgram === "iTerm.app" || env.KITTY_PID !== void 0 || termProgram === "WarpTerminal";
122
+ const sixel = env.KITTY_PID !== void 0;
123
+ return {
124
+ trueColor,
125
+ color256,
126
+ unicode,
127
+ mouseSupport,
128
+ hyperlinks,
129
+ sixel
130
+ };
131
+ }
132
+
133
+ // src/detect/os.ts
134
+ import { platform, arch, homedir } from "os";
135
+ import { existsSync as existsSync2 } from "fs";
136
+ function detectOS(env = process.env) {
137
+ const osType = resolveOSType(env);
138
+ const shell = resolveShell(env);
139
+ return {
140
+ type: osType,
141
+ arch: arch(),
142
+ shell,
143
+ homeDir: homedir()
144
+ };
145
+ }
146
+ function resolveOSType(env) {
147
+ const p = platform();
148
+ if (p === "darwin") return "macos";
149
+ if (p === "win32") return "windows";
150
+ if (p === "linux") {
151
+ const isWSL = env.WSL_DISTRO_NAME !== void 0 || env.WSLENV !== void 0 || existsSync2("/proc/sys/fs/binfmt_misc/WSLInterop");
152
+ return isWSL ? "wsl" : "linux";
153
+ }
154
+ return "linux";
155
+ }
156
+ function resolveShell(env) {
157
+ const shell = env.SHELL ?? env.ComSpec ?? "";
158
+ if (shell.includes("zsh")) return "zsh";
159
+ if (shell.includes("bash")) return "bash";
160
+ if (shell.includes("fish")) return "fish";
161
+ if (shell.includes("powershell") || shell.includes("pwsh")) return "powershell";
162
+ return shell.split("/").pop() ?? "unknown";
163
+ }
164
+
165
+ // src/themes/catppuccin-mocha.ts
166
+ var catppuccinMocha = {
167
+ name: "catppuccin-mocha",
168
+ displayName: "Catppuccin Mocha",
169
+ description: "Soothing pastel theme with warm purple tones",
170
+ author: "Catppuccin",
171
+ variant: "dark",
172
+ colors: {
173
+ background: "#1e1e2e",
174
+ foreground: "#cdd6f4",
175
+ cursor: "#f5e0dc",
176
+ selectionBackground: "#585b70",
177
+ selectionForeground: "#cdd6f4",
178
+ black: "#45475a",
179
+ red: "#f38ba8",
180
+ green: "#a6e3a1",
181
+ yellow: "#f9e2af",
182
+ blue: "#89b4fa",
183
+ magenta: "#f5c2e7",
184
+ cyan: "#94e2d5",
185
+ white: "#bac2de",
186
+ brightBlack: "#585b70",
187
+ brightRed: "#f38ba8",
188
+ brightGreen: "#a6e3a1",
189
+ brightYellow: "#f9e2af",
190
+ brightBlue: "#89b4fa",
191
+ brightMagenta: "#f5c2e7",
192
+ brightCyan: "#94e2d5",
193
+ brightWhite: "#a6adc8"
194
+ },
195
+ appearance: {
196
+ backgroundOpacity: 0.85,
197
+ backgroundBlur: 30,
198
+ cursorStyle: "bar",
199
+ cursorBlink: true
200
+ }
201
+ };
202
+
203
+ // src/themes/nord.ts
204
+ var nord = {
205
+ name: "nord",
206
+ displayName: "Nord",
207
+ description: "Arctic, north-bluish color palette",
208
+ author: "Arctic Ice Studio",
209
+ variant: "dark",
210
+ colors: {
211
+ background: "#2e3440",
212
+ foreground: "#d8dee9",
213
+ cursor: "#d8dee9",
214
+ selectionBackground: "#434c5e",
215
+ selectionForeground: "#d8dee9",
216
+ black: "#3b4252",
217
+ red: "#bf616a",
218
+ green: "#a3be8c",
219
+ yellow: "#ebcb8b",
220
+ blue: "#81a1c1",
221
+ magenta: "#b48ead",
222
+ cyan: "#88c0d0",
223
+ white: "#e5e9f0",
224
+ brightBlack: "#4c566a",
225
+ brightRed: "#bf616a",
226
+ brightGreen: "#a3be8c",
227
+ brightYellow: "#ebcb8b",
228
+ brightBlue: "#81a1c1",
229
+ brightMagenta: "#b48ead",
230
+ brightCyan: "#8fbcbb",
231
+ brightWhite: "#eceff4"
232
+ },
233
+ appearance: {
234
+ backgroundOpacity: 0.9,
235
+ backgroundBlur: 20,
236
+ cursorStyle: "bar",
237
+ cursorBlink: true
238
+ }
239
+ };
240
+
241
+ // src/themes/tokyo-night.ts
242
+ var tokyoNight = {
243
+ name: "tokyo-night",
244
+ displayName: "Tokyo Night",
245
+ description: "Clean dark theme inspired by Tokyo city lights",
246
+ author: "Enkia",
247
+ variant: "dark",
248
+ colors: {
249
+ background: "#1a1b26",
250
+ foreground: "#c0caf5",
251
+ cursor: "#c0caf5",
252
+ selectionBackground: "#33467c",
253
+ selectionForeground: "#c0caf5",
254
+ black: "#15161e",
255
+ red: "#f7768e",
256
+ green: "#9ece6a",
257
+ yellow: "#e0af68",
258
+ blue: "#7aa2f7",
259
+ magenta: "#bb9af7",
260
+ cyan: "#7dcfff",
261
+ white: "#a9b1d6",
262
+ brightBlack: "#414868",
263
+ brightRed: "#f7768e",
264
+ brightGreen: "#9ece6a",
265
+ brightYellow: "#e0af68",
266
+ brightBlue: "#7aa2f7",
267
+ brightMagenta: "#bb9af7",
268
+ brightCyan: "#7dcfff",
269
+ brightWhite: "#c0caf5"
270
+ },
271
+ appearance: {
272
+ backgroundOpacity: 0.88,
273
+ backgroundBlur: 25,
274
+ cursorStyle: "bar",
275
+ cursorBlink: true
276
+ }
277
+ };
278
+
279
+ // src/themes/dracula.ts
280
+ var dracula = {
281
+ name: "dracula",
282
+ displayName: "Dracula",
283
+ description: "Dark theme with vibrant colors",
284
+ author: "Dracula Theme",
285
+ variant: "dark",
286
+ colors: {
287
+ background: "#282a36",
288
+ foreground: "#f8f8f2",
289
+ cursor: "#f8f8f2",
290
+ selectionBackground: "#44475a",
291
+ selectionForeground: "#f8f8f2",
292
+ black: "#21222c",
293
+ red: "#ff5555",
294
+ green: "#50fa7b",
295
+ yellow: "#f1fa8c",
296
+ blue: "#bd93f9",
297
+ magenta: "#ff79c6",
298
+ cyan: "#8be9fd",
299
+ white: "#f8f8f2",
300
+ brightBlack: "#6272a4",
301
+ brightRed: "#ff6e6e",
302
+ brightGreen: "#69ff94",
303
+ brightYellow: "#ffffa5",
304
+ brightBlue: "#d6acff",
305
+ brightMagenta: "#ff92df",
306
+ brightCyan: "#a4ffff",
307
+ brightWhite: "#ffffff"
308
+ },
309
+ appearance: {
310
+ backgroundOpacity: 0.9,
311
+ backgroundBlur: 20,
312
+ cursorStyle: "bar",
313
+ cursorBlink: true
314
+ }
315
+ };
316
+
317
+ // src/themes/gruvbox.ts
318
+ var gruvbox = {
319
+ name: "gruvbox",
320
+ displayName: "Gruvbox Dark",
321
+ description: "Retro groove color scheme with warm earthy tones",
322
+ author: "morhetz",
323
+ variant: "dark",
324
+ colors: {
325
+ background: "#282828",
326
+ foreground: "#ebdbb2",
327
+ cursor: "#ebdbb2",
328
+ selectionBackground: "#504945",
329
+ selectionForeground: "#ebdbb2",
330
+ black: "#282828",
331
+ red: "#cc241d",
332
+ green: "#98971a",
333
+ yellow: "#d79921",
334
+ blue: "#458588",
335
+ magenta: "#b16286",
336
+ cyan: "#689d6a",
337
+ white: "#a89984",
338
+ brightBlack: "#928374",
339
+ brightRed: "#fb4934",
340
+ brightGreen: "#b8bb26",
341
+ brightYellow: "#fabd2f",
342
+ brightBlue: "#83a598",
343
+ brightMagenta: "#d3869b",
344
+ brightCyan: "#8ec07c",
345
+ brightWhite: "#ebdbb2"
346
+ },
347
+ appearance: {
348
+ backgroundOpacity: 0.92,
349
+ backgroundBlur: 15,
350
+ cursorStyle: "block",
351
+ cursorBlink: false
352
+ }
353
+ };
354
+
355
+ // src/themes/index.ts
356
+ var THEMES = /* @__PURE__ */ new Map([
357
+ [catppuccinMocha.name, catppuccinMocha],
358
+ [nord.name, nord],
359
+ [tokyoNight.name, tokyoNight],
360
+ [dracula.name, dracula],
361
+ [gruvbox.name, gruvbox]
362
+ ]);
363
+ var DEFAULT_THEME = "catppuccin-mocha";
364
+ function getTheme(name) {
365
+ return THEMES.get(name);
366
+ }
367
+ function listThemes() {
368
+ return Array.from(THEMES.values());
369
+ }
370
+ function getThemeOrDefault(name) {
371
+ const theme = name ? THEMES.get(name) : void 0;
372
+ return theme ?? THEMES.get(DEFAULT_THEME);
373
+ }
374
+
375
+ // src/configs/ghostty/config.ts
376
+ function generateGhosttyConfig(theme) {
377
+ const { colors, appearance } = theme;
378
+ return `# ============================================
379
+ # Claude Den - Ghostty Config
380
+ # Theme: ${theme.displayName}
381
+ # Generated by claude-den
382
+ # Reload: Cmd + Shift + ,
383
+ # ============================================
384
+
385
+ # --- Typography ---
386
+ font-family = "Maple Mono NF CN"
387
+ font-size = 14
388
+ adjust-cell-height = 2
389
+
390
+ # --- Theme: ${theme.displayName} ---
391
+ background = ${colors.background}
392
+ foreground = ${colors.foreground}
393
+ cursor-color = ${colors.cursor}
394
+ selection-background = ${colors.selectionBackground}
395
+ selection-foreground = ${colors.selectionForeground}
396
+
397
+ palette = 0=${colors.black}
398
+ palette = 1=${colors.red}
399
+ palette = 2=${colors.green}
400
+ palette = 3=${colors.yellow}
401
+ palette = 4=${colors.blue}
402
+ palette = 5=${colors.magenta}
403
+ palette = 6=${colors.cyan}
404
+ palette = 7=${colors.white}
405
+ palette = 8=${colors.brightBlack}
406
+ palette = 9=${colors.brightRed}
407
+ palette = 10=${colors.brightGreen}
408
+ palette = 11=${colors.brightYellow}
409
+ palette = 12=${colors.brightBlue}
410
+ palette = 13=${colors.brightMagenta}
411
+ palette = 14=${colors.brightCyan}
412
+ palette = 15=${colors.brightWhite}
413
+
414
+ # --- Window and Appearance ---
415
+ background-opacity = ${appearance.backgroundOpacity}
416
+ background-blur-radius = ${appearance.backgroundBlur}
417
+ macos-titlebar-style = transparent
418
+ window-padding-x = 10
419
+ window-padding-y = 8
420
+ window-save-state = always
421
+ window-theme = auto
422
+
423
+ # --- Cursor ---
424
+ cursor-style = ${appearance.cursorStyle}
425
+ cursor-style-blink = ${appearance.cursorBlink}
426
+ cursor-opacity = 0.8
427
+
428
+ # --- Mouse ---
429
+ mouse-hide-while-typing = true
430
+ copy-on-select = clipboard
431
+
432
+ # --- Quick Terminal ---
433
+ quick-terminal-position = top
434
+ quick-terminal-screen = mouse
435
+ quick-terminal-autohide = true
436
+ quick-terminal-animation-duration = 0.15
437
+
438
+ # --- Security ---
439
+ clipboard-paste-protection = true
440
+ clipboard-paste-bracketed-safe = true
441
+
442
+ # --- Shell Integration ---
443
+ shell-integration = zsh
444
+
445
+ # --- Claude Code Optimizations ---
446
+ initial-window = true
447
+ quit-after-last-window-closed = true
448
+ notify-on-command-finish = always
449
+
450
+ # --- Performance ---
451
+ scrollback-limit = 25000000
452
+
453
+ # --- Keybindings (Claude Code Workflow) ---
454
+ keybind = cmd+d=new_split:right
455
+ keybind = cmd+shift+enter=toggle_split_zoom
456
+ keybind = cmd+shift+f=toggle_split_zoom
457
+ `;
458
+ }
459
+
460
+ // src/configs/iterm2/profile.ts
461
+ function hexToRgbComponents(hex) {
462
+ const clean = hex.replace("#", "");
463
+ return {
464
+ r: parseInt(clean.substring(0, 2), 16) / 255,
465
+ g: parseInt(clean.substring(2, 4), 16) / 255,
466
+ b: parseInt(clean.substring(4, 6), 16) / 255
467
+ };
468
+ }
469
+ function colorEntry(hex) {
470
+ const { r, g, b } = hexToRgbComponents(hex);
471
+ return {
472
+ "Red Component": r,
473
+ "Green Component": g,
474
+ "Blue Component": b,
475
+ "Alpha Component": 1,
476
+ "Color Space": "sRGB"
477
+ };
478
+ }
479
+ function generateIterm2Profile(theme) {
480
+ const { colors, appearance } = theme;
481
+ const profile = {
482
+ "Name": `Den ${theme.displayName}`,
483
+ "Guid": `den-${theme.name}`,
484
+ "Normal Font": "MapleMono-NF-CN-Regular 14",
485
+ "Transparency": 1 - appearance.backgroundOpacity,
486
+ "Blur": appearance.backgroundBlur > 0,
487
+ "Blur Radius": appearance.backgroundBlur / 3,
488
+ "Background Color": colorEntry(colors.background),
489
+ "Foreground Color": colorEntry(colors.foreground),
490
+ "Cursor Color": colorEntry(colors.cursor),
491
+ "Selection Color": colorEntry(colors.selectionBackground),
492
+ "Selected Text Color": colorEntry(colors.selectionForeground),
493
+ "Ansi 0 Color": colorEntry(colors.black),
494
+ "Ansi 1 Color": colorEntry(colors.red),
495
+ "Ansi 2 Color": colorEntry(colors.green),
496
+ "Ansi 3 Color": colorEntry(colors.yellow),
497
+ "Ansi 4 Color": colorEntry(colors.blue),
498
+ "Ansi 5 Color": colorEntry(colors.magenta),
499
+ "Ansi 6 Color": colorEntry(colors.cyan),
500
+ "Ansi 7 Color": colorEntry(colors.white),
501
+ "Ansi 8 Color": colorEntry(colors.brightBlack),
502
+ "Ansi 9 Color": colorEntry(colors.brightRed),
503
+ "Ansi 10 Color": colorEntry(colors.brightGreen),
504
+ "Ansi 11 Color": colorEntry(colors.brightYellow),
505
+ "Ansi 12 Color": colorEntry(colors.brightBlue),
506
+ "Ansi 13 Color": colorEntry(colors.brightMagenta),
507
+ "Ansi 14 Color": colorEntry(colors.brightCyan),
508
+ "Ansi 15 Color": colorEntry(colors.brightWhite),
509
+ "Cursor Type": appearance.cursorStyle === "bar" ? 1 : appearance.cursorStyle === "underline" ? 2 : 0,
510
+ "Blinking Cursor": appearance.cursorBlink,
511
+ "Unlimited Scrollback": true,
512
+ "Mouse Reporting": true,
513
+ "Unicode Version": 9
514
+ };
515
+ return JSON.stringify(profile, null, 2);
516
+ }
517
+
518
+ // src/configs/kitty/config.ts
519
+ function generateKittyConfig(theme) {
520
+ const { colors, appearance } = theme;
521
+ const cursorShape = appearance.cursorStyle === "bar" ? "beam" : appearance.cursorStyle === "underline" ? "underline" : "block";
522
+ return `# ============================================
523
+ # Claude Den - Kitty Config
524
+ # Theme: ${theme.displayName}
525
+ # Generated by claude-den
526
+ # ============================================
527
+
528
+ # --- Typography ---
529
+ font_family Maple Mono NF CN
530
+ font_size 14.0
531
+
532
+ # --- Theme: ${theme.displayName} ---
533
+ background ${colors.background}
534
+ foreground ${colors.foreground}
535
+ cursor ${colors.cursor}
536
+ selection_background ${colors.selectionBackground}
537
+ selection_foreground ${colors.selectionForeground}
538
+
539
+ color0 ${colors.black}
540
+ color1 ${colors.red}
541
+ color2 ${colors.green}
542
+ color3 ${colors.yellow}
543
+ color4 ${colors.blue}
544
+ color5 ${colors.magenta}
545
+ color6 ${colors.cyan}
546
+ color7 ${colors.white}
547
+ color8 ${colors.brightBlack}
548
+ color9 ${colors.brightRed}
549
+ color10 ${colors.brightGreen}
550
+ color11 ${colors.brightYellow}
551
+ color12 ${colors.brightBlue}
552
+ color13 ${colors.brightMagenta}
553
+ color14 ${colors.brightCyan}
554
+ color15 ${colors.brightWhite}
555
+
556
+ # --- Appearance ---
557
+ background_opacity ${appearance.backgroundOpacity}
558
+ cursor_shape ${cursorShape}
559
+ cursor_blink_interval ${appearance.cursorBlink ? "0.5" : "0"}
560
+ hide_window_decorations titlebar-only
561
+ window_padding_width 8
562
+
563
+ # --- Performance ---
564
+ scrollback_lines 250000
565
+
566
+ # --- Keybindings (Claude Code Workflow) ---
567
+ map cmd+d launch --location=vsplit --cwd=current
568
+ map cmd+shift+enter toggle_layout stack
569
+ map cmd+shift+f toggle_layout stack
570
+
571
+ # --- Shell Integration ---
572
+ shell_integration enabled
573
+ `;
574
+ }
575
+
576
+ // src/configs/alacritty/config.ts
577
+ function generateAlacrittyConfig(theme) {
578
+ const { colors, appearance } = theme;
579
+ const cursorShape = appearance.cursorStyle === "bar" ? "Beam" : appearance.cursorStyle === "underline" ? "Underline" : "Block";
580
+ const config = {
581
+ font: {
582
+ normal: { family: "Maple Mono NF CN" },
583
+ size: 14
584
+ },
585
+ window: {
586
+ opacity: appearance.backgroundOpacity,
587
+ blur: appearance.backgroundBlur > 0,
588
+ padding: { x: 10, y: 8 },
589
+ decorations: "Transparent"
590
+ },
591
+ cursor: {
592
+ style: {
593
+ shape: cursorShape,
594
+ blinking: appearance.cursorBlink ? "On" : "Off"
595
+ }
596
+ },
597
+ colors: {
598
+ primary: {
599
+ background: colors.background,
600
+ foreground: colors.foreground
601
+ },
602
+ cursor: {
603
+ text: colors.background,
604
+ cursor: colors.cursor
605
+ },
606
+ selection: {
607
+ text: colors.selectionForeground,
608
+ background: colors.selectionBackground
609
+ },
610
+ normal: {
611
+ black: colors.black,
612
+ red: colors.red,
613
+ green: colors.green,
614
+ yellow: colors.yellow,
615
+ blue: colors.blue,
616
+ magenta: colors.magenta,
617
+ cyan: colors.cyan,
618
+ white: colors.white
619
+ },
620
+ bright: {
621
+ black: colors.brightBlack,
622
+ red: colors.brightRed,
623
+ green: colors.brightGreen,
624
+ yellow: colors.brightYellow,
625
+ blue: colors.brightBlue,
626
+ magenta: colors.brightMagenta,
627
+ cyan: colors.brightCyan,
628
+ white: colors.brightWhite
629
+ }
630
+ },
631
+ scrolling: {
632
+ history: 1e5
633
+ }
634
+ };
635
+ return `# ============================================
636
+ # Claude Den - Alacritty Config
637
+ # Theme: ${theme.displayName}
638
+ # Generated by claude-den
639
+ # ============================================
640
+
641
+ ${toToml(config)}`;
642
+ }
643
+ function toToml(obj, prefix = "") {
644
+ const lines = [];
645
+ for (const [key, value] of Object.entries(obj)) {
646
+ const fullKey = prefix ? `${prefix}.${key}` : key;
647
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
648
+ lines.push(`[${fullKey}]`);
649
+ for (const [subKey, subValue] of Object.entries(value)) {
650
+ if (typeof subValue === "object" && subValue !== null && !Array.isArray(subValue)) {
651
+ lines.push("");
652
+ lines.push(...toToml({ [subKey]: subValue }, fullKey).split("\n"));
653
+ } else {
654
+ lines.push(`${subKey} = ${formatTomlValue(subValue)}`);
655
+ }
656
+ }
657
+ lines.push("");
658
+ }
659
+ }
660
+ return lines.join("\n");
661
+ }
662
+ function formatTomlValue(value) {
663
+ if (typeof value === "string") return `"${value}"`;
664
+ if (typeof value === "number") return String(value);
665
+ if (typeof value === "boolean") return String(value);
666
+ return String(value);
667
+ }
668
+
669
+ // src/configs/starship/config.ts
670
+ function generateStarshipConfig(theme) {
671
+ const { colors } = theme;
672
+ return `# ============================================
673
+ # Claude Den - Starship Config
674
+ # Theme: ${theme.displayName}
675
+ # Generated by claude-den
676
+ # Place at: ~/.config/starship.toml
677
+ # ============================================
678
+
679
+ format = """
680
+ $directory$git_branch$git_status$nodejs$python$rust$golang$cmd_duration$line_break$character"""
681
+
682
+ [character]
683
+ success_symbol = "[\u276F](bold ${colors.green})"
684
+ error_symbol = "[\u276F](bold ${colors.red})"
685
+ vimcmd_symbol = "[\u276E](bold ${colors.blue})"
686
+
687
+ [directory]
688
+ style = "bold ${colors.blue}"
689
+ truncation_length = 3
690
+ truncate_to_repo = true
691
+ format = "[$path]($style)[$read_only]($read_only_style) "
692
+
693
+ [git_branch]
694
+ style = "bold ${colors.magenta}"
695
+ format = "[$symbol$branch(:$remote_branch)]($style) "
696
+ symbol = " "
697
+
698
+ [git_status]
699
+ style = "bold ${colors.red}"
700
+ format = '([$all_status$ahead_behind]($style) )'
701
+ conflicted = "="
702
+ ahead = "\u21E1\${count}"
703
+ behind = "\u21E3\${count}"
704
+ diverged = "\u21D5\u21E1\${ahead_count}\u21E3\${behind_count}"
705
+ untracked = "?\${count}"
706
+ stashed = "\\$\${count}"
707
+ modified = "!\${count}"
708
+ staged = "+\${count}"
709
+ deleted = "\u2718\${count}"
710
+
711
+ [nodejs]
712
+ style = "bold ${colors.green}"
713
+ format = "[$symbol($version)]($style) "
714
+ symbol = " "
715
+
716
+ [python]
717
+ style = "bold ${colors.yellow}"
718
+ format = '[$symbol\${pyenv_prefix}(\${version})]($style) '
719
+ symbol = " "
720
+
721
+ [rust]
722
+ style = "bold ${colors.red}"
723
+ format = "[$symbol($version)]($style) "
724
+ symbol = " "
725
+
726
+ [golang]
727
+ style = "bold ${colors.cyan}"
728
+ format = "[$symbol($version)]($style) "
729
+ symbol = " "
730
+
731
+ [cmd_duration]
732
+ style = "bold ${colors.yellow}"
733
+ min_time = 2_000
734
+ format = "[$duration]($style) "
735
+ show_milliseconds = false
736
+
737
+ [line_break]
738
+ disabled = false
739
+ `;
740
+ }
741
+
742
+ // src/configs/tmux/config.ts
743
+ var LAYOUTS = /* @__PURE__ */ new Map([
744
+ [
745
+ "coding",
746
+ {
747
+ name: "coding",
748
+ description: "Claude Code left, editor/shell right",
749
+ panes: [
750
+ { command: "claude", split: "horizontal", size: "60%" },
751
+ { command: "$SHELL", split: "vertical" }
752
+ ]
753
+ }
754
+ ],
755
+ [
756
+ "parallel",
757
+ {
758
+ name: "parallel",
759
+ description: "2x2 grid for parallel Claude agents",
760
+ panes: [
761
+ { command: "claude", split: "horizontal", size: "50%" },
762
+ { command: "claude", split: "vertical", size: "50%" },
763
+ { command: "claude", split: "horizontal", size: "50%" },
764
+ { command: "claude", split: "vertical" }
765
+ ]
766
+ }
767
+ ],
768
+ [
769
+ "monitor",
770
+ {
771
+ name: "monitor",
772
+ description: "Claude + logs + git + system monitor",
773
+ panes: [
774
+ { command: "claude", split: "horizontal", size: "60%" },
775
+ { command: "lazygit 2>/dev/null || git log --oneline -20", split: "vertical", size: "50%" },
776
+ { command: "btop 2>/dev/null || top", split: "vertical" }
777
+ ]
778
+ }
779
+ ]
780
+ ]);
781
+ function generateTmuxConfig(theme) {
782
+ const { colors } = theme;
783
+ return `# ============================================
784
+ # Claude Den - tmux Config
785
+ # Theme: ${theme.displayName}
786
+ # Generated by claude-den
787
+ # Place at: ~/.tmux.conf
788
+ # ============================================
789
+
790
+ # --- General ---
791
+ set -g default-terminal "tmux-256color"
792
+ set -ag terminal-overrides ",xterm-256color:RGB"
793
+ set -g mouse on
794
+ set -g history-limit 250000
795
+ set -g base-index 1
796
+ setw -g pane-base-index 1
797
+ set -g renumber-windows on
798
+ set -s escape-time 0
799
+ set -g focus-events on
800
+
801
+ # --- Theme: ${theme.displayName} ---
802
+ set -g status-style "bg=${colors.background},fg=${colors.foreground}"
803
+ set -g status-left "#[bg=${colors.blue},fg=${colors.background},bold] #S #[default] "
804
+ set -g status-right "#[fg=${colors.brightBlack}]%H:%M #[fg=${colors.magenta}]#h "
805
+ set -g status-left-length 30
806
+ set -g status-right-length 50
807
+
808
+ setw -g window-status-format "#[fg=${colors.brightBlack}] #I:#W "
809
+ setw -g window-status-current-format "#[bg=${colors.blue},fg=${colors.background},bold] #I:#W "
810
+
811
+ set -g pane-border-style "fg=${colors.brightBlack}"
812
+ set -g pane-active-border-style "fg=${colors.blue}"
813
+ set -g message-style "bg=${colors.yellow},fg=${colors.background}"
814
+
815
+ # --- Keybindings ---
816
+ set -g prefix C-a
817
+ unbind C-b
818
+ bind C-a send-prefix
819
+
820
+ # Split panes (Claude Code workflow)
821
+ bind | split-window -h -c "#{pane_current_path}"
822
+ bind - split-window -v -c "#{pane_current_path}"
823
+ unbind '"'
824
+ unbind %
825
+
826
+ # Navigate panes with Alt+arrow
827
+ bind -n M-Left select-pane -L
828
+ bind -n M-Right select-pane -R
829
+ bind -n M-Up select-pane -U
830
+ bind -n M-Down select-pane -D
831
+
832
+ # Resize panes
833
+ bind -r H resize-pane -L 5
834
+ bind -r J resize-pane -D 5
835
+ bind -r K resize-pane -U 5
836
+ bind -r L resize-pane -R 5
837
+
838
+ # Reload config
839
+ bind r source-file ~/.tmux.conf \\; display "Config reloaded!"
840
+
841
+ # New window in current path
842
+ bind c new-window -c "#{pane_current_path}"
843
+ `;
844
+ }
845
+ function generateTmuxLayoutScript(layout) {
846
+ const sessionName = `den-${layout.name}`;
847
+ const lines = [
848
+ "#!/usr/bin/env bash",
849
+ `# Claude Den Layout: ${layout.name} - ${layout.description}`,
850
+ "",
851
+ `SESSION="${sessionName}"`,
852
+ "",
853
+ "# Kill existing session if any",
854
+ `tmux has-session -t $SESSION 2>/dev/null && tmux kill-session -t $SESSION`,
855
+ "",
856
+ "# Create new session",
857
+ `tmux new-session -d -s $SESSION -x $(tput cols) -y $(tput lines)`,
858
+ ""
859
+ ];
860
+ for (let i = 0; i < layout.panes.length; i++) {
861
+ const pane = layout.panes[i];
862
+ if (i > 0) {
863
+ const splitFlag = pane.split === "horizontal" ? "-h" : "-v";
864
+ const sizeFlag = pane.size ? `-p ${parseInt(pane.size)}` : "";
865
+ lines.push(`tmux split-window ${splitFlag} ${sizeFlag} -t $SESSION`);
866
+ }
867
+ lines.push(`tmux send-keys -t $SESSION '${pane.command}' Enter`);
868
+ lines.push("");
869
+ }
870
+ lines.push("# Select first pane");
871
+ lines.push(`tmux select-pane -t $SESSION:0.0`);
872
+ lines.push("");
873
+ lines.push("# Attach to session");
874
+ lines.push(`tmux attach-session -t $SESSION`);
875
+ return lines.join("\n");
876
+ }
877
+
878
+ // src/cli/backup.ts
879
+ import {
880
+ copyFileSync,
881
+ existsSync as existsSync3,
882
+ mkdirSync,
883
+ readFileSync,
884
+ writeFileSync
885
+ } from "fs";
886
+ import { join, basename, dirname } from "path";
887
+ import { homedir as homedir2 } from "os";
888
+ import chalk from "chalk";
889
+ var BACKUP_DIR = join(homedir2(), ".config", "claude-den", "backups");
890
+ function ensureBackupDir() {
891
+ if (!existsSync3(BACKUP_DIR)) {
892
+ mkdirSync(BACKUP_DIR, { recursive: true });
893
+ }
894
+ }
895
+ function getManifestPath() {
896
+ return join(BACKUP_DIR, "manifest.json");
897
+ }
898
+ function readManifest() {
899
+ const manifestPath = getManifestPath();
900
+ if (!existsSync3(manifestPath)) return null;
901
+ const raw = readFileSync(manifestPath, "utf-8");
902
+ return JSON.parse(raw);
903
+ }
904
+ function writeManifest(manifest) {
905
+ ensureBackupDir();
906
+ writeFileSync(getManifestPath(), JSON.stringify(manifest, null, 2), "utf-8");
907
+ }
908
+ function backupFile(sourcePath) {
909
+ ensureBackupDir();
910
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
911
+ const backupName = `${basename(sourcePath)}.${timestamp}.bak`;
912
+ const backupPath = join(BACKUP_DIR, backupName);
913
+ copyFileSync(sourcePath, backupPath);
914
+ const manifest = readManifest() ?? {
915
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
916
+ files: []
917
+ };
918
+ const updatedManifest = {
919
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
920
+ files: [
921
+ ...manifest.files,
922
+ { source: sourcePath, backup: backupPath }
923
+ ]
924
+ };
925
+ writeManifest(updatedManifest);
926
+ return backupPath;
927
+ }
928
+ function registerBackupCommand(program2) {
929
+ program2.command("backup").description("Backup current terminal configurations").action(() => {
930
+ console.log(chalk.bold.blue("\n Claude Den Backup\n"));
931
+ const home = homedir2();
932
+ const configFiles = [
933
+ join(home, ".config", "ghostty", "config"),
934
+ join(home, ".config", "kitty", "kitty.conf"),
935
+ join(home, ".config", "alacritty", "alacritty.toml"),
936
+ join(home, ".config", "starship.toml"),
937
+ join(home, ".tmux.conf")
938
+ ];
939
+ let backupCount = 0;
940
+ for (const file of configFiles) {
941
+ if (existsSync3(file)) {
942
+ const backupPath = backupFile(file);
943
+ console.log(chalk.green(` \u2713 ${file}`));
944
+ console.log(chalk.dim(` \u2192 ${backupPath}`));
945
+ backupCount++;
946
+ }
947
+ }
948
+ if (backupCount === 0) {
949
+ console.log(chalk.dim(" No config files found to backup.\n"));
950
+ } else {
951
+ console.log(
952
+ chalk.green(`
953
+ Backed up ${backupCount} file(s) to ${BACKUP_DIR}
954
+ `)
955
+ );
956
+ }
957
+ });
958
+ }
959
+ function registerRestoreCommand(program2) {
960
+ program2.command("restore").description("Restore terminal configurations from backup").action(() => {
961
+ console.log(chalk.bold.blue("\n Claude Den Restore\n"));
962
+ const manifest = readManifest();
963
+ if (!manifest || manifest.files.length === 0) {
964
+ console.log(chalk.dim(" No backups found.\n"));
965
+ return;
966
+ }
967
+ console.log(
968
+ chalk.dim(` Backup from: ${manifest.timestamp}
969
+ `)
970
+ );
971
+ let restoreCount = 0;
972
+ for (const entry of manifest.files) {
973
+ if (existsSync3(entry.backup)) {
974
+ const dir = dirname(entry.source);
975
+ if (!existsSync3(dir)) {
976
+ mkdirSync(dir, { recursive: true });
977
+ }
978
+ copyFileSync(entry.backup, entry.source);
979
+ console.log(chalk.green(` \u2713 Restored ${entry.source}`));
980
+ restoreCount++;
981
+ } else {
982
+ console.log(
983
+ chalk.yellow(` ! Backup missing: ${entry.backup}`)
984
+ );
985
+ }
986
+ }
987
+ console.log(
988
+ chalk.green(`
989
+ Restored ${restoreCount} file(s).
990
+ `)
991
+ );
992
+ });
993
+ }
994
+
995
+ // src/cli/init.ts
996
+ var CONFIG_DESTINATIONS = {
997
+ ghostty: (home) => join2(home, ".config", "ghostty", "config"),
998
+ kitty: (home) => join2(home, ".config", "kitty", "kitty.conf"),
999
+ alacritty: (home) => join2(home, ".config", "alacritty", "alacritty.toml")
1000
+ };
1001
+ var CONFIG_GENERATORS = {
1002
+ ghostty: generateGhosttyConfig,
1003
+ iterm2: generateIterm2Profile,
1004
+ kitty: generateKittyConfig,
1005
+ alacritty: generateAlacrittyConfig
1006
+ };
1007
+ function writeConfig(path, content) {
1008
+ const dir = dirname2(path);
1009
+ if (!existsSync4(dir)) {
1010
+ mkdirSync2(dir, { recursive: true });
1011
+ }
1012
+ writeFileSync2(path, content, "utf-8");
1013
+ }
1014
+ function registerInitCommand(program2) {
1015
+ program2.command("init").description("Interactive setup wizard for Claude Code terminal experience").option("-t, --theme <name>", "Theme name (skip theme selection)").option("--no-starship", "Skip Starship configuration").option("--no-tmux", "Skip tmux configuration").action(async (options) => {
1016
+ console.log(
1017
+ chalk2.bold.blue("\n Claude Den\n")
1018
+ );
1019
+ console.log(
1020
+ chalk2.dim(" Your cozy terminal den for Claude Code\n")
1021
+ );
1022
+ const terminal = detectTerminal();
1023
+ const capabilities = detectCapabilities();
1024
+ const os = detectOS();
1025
+ console.log(chalk2.green(" Detected environment:"));
1026
+ console.log(` Terminal: ${chalk2.bold(terminal.name)}`);
1027
+ console.log(` OS: ${chalk2.bold(os.type)} (${os.arch})`);
1028
+ console.log(` Shell: ${chalk2.bold(os.shell)}`);
1029
+ console.log(
1030
+ ` TrueColor: ${capabilities.trueColor ? chalk2.green("Yes") : chalk2.yellow("No")}`
1031
+ );
1032
+ console.log("");
1033
+ const installed = listInstalledTerminals();
1034
+ const terminalChoices = [
1035
+ ...terminal.type !== "unknown" ? [
1036
+ {
1037
+ name: `${terminal.name} (current)`,
1038
+ value: terminal.type
1039
+ }
1040
+ ] : [],
1041
+ ...installed.filter((t) => t.type !== terminal.type).map((t) => ({ name: t.name, value: t.type }))
1042
+ ];
1043
+ if (terminalChoices.length === 0) {
1044
+ terminalChoices.push({
1045
+ name: "Ghostty (recommended for Claude Code)",
1046
+ value: "ghostty"
1047
+ });
1048
+ }
1049
+ const { selectedTerminal } = await inquirer.prompt([
1050
+ {
1051
+ type: "list",
1052
+ name: "selectedTerminal",
1053
+ message: "Which terminal do you want to configure?",
1054
+ choices: terminalChoices
1055
+ }
1056
+ ]);
1057
+ const themes = listThemes();
1058
+ let selectedTheme;
1059
+ if (options.theme) {
1060
+ selectedTheme = getThemeOrDefault(options.theme);
1061
+ console.log(` Theme: ${chalk2.bold(selectedTheme.displayName)}
1062
+ `);
1063
+ } else {
1064
+ const { themeName } = await inquirer.prompt([
1065
+ {
1066
+ type: "list",
1067
+ name: "themeName",
1068
+ message: "Choose a color theme:",
1069
+ choices: themes.map((t) => ({
1070
+ name: `${t.displayName} - ${chalk2.dim(t.description)}`,
1071
+ value: t.name
1072
+ }))
1073
+ }
1074
+ ]);
1075
+ selectedTheme = getThemeOrDefault(themeName);
1076
+ }
1077
+ const { setupStarship, setupTmux } = await inquirer.prompt([
1078
+ {
1079
+ type: "confirm",
1080
+ name: "setupStarship",
1081
+ message: "Setup Starship prompt with Claude Code theme?",
1082
+ default: options.starship !== false,
1083
+ when: () => options.starship !== false
1084
+ },
1085
+ {
1086
+ type: "confirm",
1087
+ name: "setupTmux",
1088
+ message: "Setup tmux with Claude Code workflow keybindings?",
1089
+ default: options.tmux !== false,
1090
+ when: () => options.tmux !== false
1091
+ }
1092
+ ]);
1093
+ console.log(chalk2.blue("\n Installing configurations...\n"));
1094
+ const home = homedir3();
1095
+ const generator = CONFIG_GENERATORS[selectedTerminal];
1096
+ if (generator) {
1097
+ const configContent = generator(selectedTheme);
1098
+ const getDestination = CONFIG_DESTINATIONS[selectedTerminal];
1099
+ if (getDestination) {
1100
+ const destPath = getDestination(home);
1101
+ if (existsSync4(destPath)) {
1102
+ backupFile(destPath);
1103
+ console.log(chalk2.dim(` Backed up existing config`));
1104
+ }
1105
+ writeConfig(destPath, configContent);
1106
+ console.log(
1107
+ chalk2.green(` \u2713 ${selectedTerminal} config \u2192 ${destPath}`)
1108
+ );
1109
+ } else if (selectedTerminal === "iterm2") {
1110
+ const profilePath = join2(
1111
+ home,
1112
+ ".config",
1113
+ "claude-den",
1114
+ `iterm2-${selectedTheme.name}.json`
1115
+ );
1116
+ writeConfig(profilePath, configContent);
1117
+ console.log(
1118
+ chalk2.green(
1119
+ ` \u2713 iTerm2 profile \u2192 ${profilePath}`
1120
+ )
1121
+ );
1122
+ console.log(
1123
+ chalk2.dim(
1124
+ " Import via iTerm2 \u2192 Settings \u2192 Profiles \u2192 Other Actions \u2192 Import JSON Profiles"
1125
+ )
1126
+ );
1127
+ }
1128
+ }
1129
+ if (setupStarship !== false) {
1130
+ const starshipPath = join2(home, ".config", "starship.toml");
1131
+ if (existsSync4(starshipPath)) {
1132
+ backupFile(starshipPath);
1133
+ }
1134
+ writeConfig(starshipPath, generateStarshipConfig(selectedTheme));
1135
+ console.log(chalk2.green(` \u2713 Starship config \u2192 ${starshipPath}`));
1136
+ const shellRcPath = os.shell === "zsh" ? join2(home, ".zshrc") : os.shell === "bash" ? join2(home, ".bashrc") : null;
1137
+ if (shellRcPath && existsSync4(shellRcPath)) {
1138
+ const { readFileSync: readFileSync2 } = await import("fs");
1139
+ const rcContent = readFileSync2(shellRcPath, "utf-8");
1140
+ if (!rcContent.includes("starship init")) {
1141
+ console.log(
1142
+ chalk2.yellow(
1143
+ `
1144
+ Note: Add this to your ${shellRcPath}:`
1145
+ )
1146
+ );
1147
+ console.log(
1148
+ chalk2.dim(` eval "$(starship init ${os.shell})"
1149
+ `)
1150
+ );
1151
+ }
1152
+ }
1153
+ }
1154
+ if (setupTmux !== false) {
1155
+ const tmuxPath = join2(home, ".tmux.conf");
1156
+ if (existsSync4(tmuxPath)) {
1157
+ backupFile(tmuxPath);
1158
+ }
1159
+ writeConfig(tmuxPath, generateTmuxConfig(selectedTheme));
1160
+ console.log(chalk2.green(` \u2713 tmux config \u2192 ${tmuxPath}`));
1161
+ }
1162
+ console.log(chalk2.bold.green("\n Setup complete!\n"));
1163
+ console.log(chalk2.dim(" Quick tips:"));
1164
+ console.log(chalk2.dim(" \u2022 den theme <name> Switch theme"));
1165
+ console.log(chalk2.dim(" \u2022 den layout coding Launch coding layout"));
1166
+ console.log(chalk2.dim(" \u2022 den doctor Check terminal setup"));
1167
+ console.log("");
1168
+ });
1169
+ }
1170
+
1171
+ // src/cli/theme.ts
1172
+ import chalk3 from "chalk";
1173
+ function renderThemePreview(theme) {
1174
+ const { colors } = theme;
1175
+ console.log(chalk3.bold(`
1176
+ ${theme.displayName}`));
1177
+ console.log(chalk3.dim(` ${theme.description} (by ${theme.author})
1178
+ `));
1179
+ const normalColors = [
1180
+ ["black", colors.black],
1181
+ ["red", colors.red],
1182
+ ["green", colors.green],
1183
+ ["yellow", colors.yellow],
1184
+ ["blue", colors.blue],
1185
+ ["magenta", colors.magenta],
1186
+ ["cyan", colors.cyan],
1187
+ ["white", colors.white]
1188
+ ];
1189
+ const brightColors = [
1190
+ ["brBlack", colors.brightBlack],
1191
+ ["brRed", colors.brightRed],
1192
+ ["brGreen", colors.brightGreen],
1193
+ ["brYellow", colors.brightYellow],
1194
+ ["brBlue", colors.brightBlue],
1195
+ ["brMagenta", colors.brightMagenta],
1196
+ ["brCyan", colors.brightCyan],
1197
+ ["brWhite", colors.brightWhite]
1198
+ ];
1199
+ const swatch = (hex) => chalk3.bgHex(hex)(" ");
1200
+ console.log(
1201
+ " Normal: " + normalColors.map(([, c]) => swatch(c)).join(" ")
1202
+ );
1203
+ console.log(
1204
+ " Bright: " + brightColors.map(([, c]) => swatch(c)).join(" ")
1205
+ );
1206
+ console.log(
1207
+ `
1208
+ BG: ${chalk3.bgHex(colors.background)(" ")} FG: ${chalk3.hex(colors.foreground)("Hello Claude")}`
1209
+ );
1210
+ console.log("");
1211
+ }
1212
+ function registerThemeCommand(program2) {
1213
+ const themeCmd = program2.command("theme").description("Manage terminal themes");
1214
+ themeCmd.command("list").description("List all available themes").action(() => {
1215
+ const themes = listThemes();
1216
+ console.log(chalk3.bold.blue("\n Available Themes\n"));
1217
+ for (const theme of themes) {
1218
+ const colorDots = [
1219
+ theme.colors.red,
1220
+ theme.colors.green,
1221
+ theme.colors.blue,
1222
+ theme.colors.magenta,
1223
+ theme.colors.cyan
1224
+ ].map((c) => chalk3.hex(c)("\u25CF")).join(" ");
1225
+ console.log(
1226
+ ` ${chalk3.bold(theme.name.padEnd(20))} ${colorDots} ${chalk3.dim(theme.description)}`
1227
+ );
1228
+ }
1229
+ console.log("");
1230
+ });
1231
+ themeCmd.command("preview <name>").description("Preview a theme's colors").action((name) => {
1232
+ const theme = getTheme(name);
1233
+ if (!theme) {
1234
+ console.log(chalk3.red(` Theme "${name}" not found.`));
1235
+ console.log(
1236
+ chalk3.dim(" Run `den theme list` to see available themes.\n")
1237
+ );
1238
+ return;
1239
+ }
1240
+ renderThemePreview(theme);
1241
+ });
1242
+ themeCmd.command("apply <name>").description("Apply theme to all configured terminals").action(async (name) => {
1243
+ const theme = getTheme(name);
1244
+ if (!theme) {
1245
+ console.log(chalk3.red(` Theme "${name}" not found.
1246
+ `));
1247
+ return;
1248
+ }
1249
+ console.log(
1250
+ chalk3.blue(`
1251
+ Applying theme: ${chalk3.bold(theme.displayName)}
1252
+ `)
1253
+ );
1254
+ console.log(
1255
+ chalk3.dim(` Run \`den init --theme ${name}\` to apply to specific terminals.
1256
+ `)
1257
+ );
1258
+ });
1259
+ }
1260
+
1261
+ // src/cli/layout.ts
1262
+ import { execSync, execFileSync } from "child_process";
1263
+ import { writeFileSync as writeFileSync3, unlinkSync } from "fs";
1264
+ import { join as join3 } from "path";
1265
+ import { tmpdir } from "os";
1266
+ import chalk4 from "chalk";
1267
+ function registerLayoutCommand(program2) {
1268
+ const layoutCmd = program2.command("layout").description("Launch tmux layouts for Claude Code workflows");
1269
+ layoutCmd.command("list").description("List available layouts").action(() => {
1270
+ console.log(chalk4.bold.blue("\n Available Layouts\n"));
1271
+ for (const [name, layout] of LAYOUTS) {
1272
+ console.log(
1273
+ ` ${chalk4.bold(name.padEnd(15))} ${chalk4.dim(layout.description)}`
1274
+ );
1275
+ console.log(
1276
+ chalk4.dim(
1277
+ ` ${"".padEnd(15)} ${layout.panes.length} panes`
1278
+ )
1279
+ );
1280
+ }
1281
+ console.log("");
1282
+ });
1283
+ layoutCmd.command("start <name>").description("Start a tmux layout").action((name) => {
1284
+ const layout = LAYOUTS.get(name);
1285
+ if (!layout) {
1286
+ console.log(chalk4.red(` Layout "${name}" not found.`));
1287
+ console.log(
1288
+ chalk4.dim(" Run `den layout list` to see available layouts.\n")
1289
+ );
1290
+ return;
1291
+ }
1292
+ try {
1293
+ execFileSync("which", ["tmux"], { stdio: "pipe" });
1294
+ } catch {
1295
+ console.log(
1296
+ chalk4.red(" tmux is not installed. Install with: brew install tmux\n")
1297
+ );
1298
+ return;
1299
+ }
1300
+ const script = generateTmuxLayoutScript(layout);
1301
+ console.log(
1302
+ chalk4.blue(
1303
+ `
1304
+ Launching layout: ${chalk4.bold(layout.name)}
1305
+ `
1306
+ )
1307
+ );
1308
+ const scriptPath = join3(tmpdir(), `claude-den-layout-${Date.now()}.sh`);
1309
+ try {
1310
+ writeFileSync3(scriptPath, script, { mode: 493 });
1311
+ execSync(`bash "${scriptPath}"`, { stdio: "inherit" });
1312
+ } catch {
1313
+ } finally {
1314
+ try {
1315
+ unlinkSync(scriptPath);
1316
+ } catch {
1317
+ }
1318
+ }
1319
+ });
1320
+ }
1321
+
1322
+ // src/cli/doctor.ts
1323
+ import { execFileSync as execFileSync2 } from "child_process";
1324
+ import { existsSync as existsSync5, readdirSync } from "fs";
1325
+ import { join as join4 } from "path";
1326
+ import { homedir as homedir4 } from "os";
1327
+ import chalk5 from "chalk";
1328
+ function check(name, test) {
1329
+ try {
1330
+ const result = test();
1331
+ return { name, ...result };
1332
+ } catch {
1333
+ return { name, status: "fail", message: "Check failed" };
1334
+ }
1335
+ }
1336
+ var ALLOWED_COMMANDS = /* @__PURE__ */ new Set(["claude", "starship", "tmux", "git"]);
1337
+ function commandExists(cmd) {
1338
+ if (!ALLOWED_COMMANDS.has(cmd)) return false;
1339
+ try {
1340
+ execFileSync2("which", [cmd], { stdio: "pipe" });
1341
+ return true;
1342
+ } catch {
1343
+ return false;
1344
+ }
1345
+ }
1346
+ function formatCheck(result) {
1347
+ const icon = result.status === "ok" ? chalk5.green("\u2713") : result.status === "warn" ? chalk5.yellow("!") : chalk5.red("\u2717");
1348
+ return ` ${icon} ${result.name.padEnd(25)} ${chalk5.dim(result.message)}`;
1349
+ }
1350
+ function registerDoctorCommand(program2) {
1351
+ program2.command("doctor").description("Diagnose your terminal setup for Claude Code").action(() => {
1352
+ console.log(chalk5.bold.blue("\n Claude Den Doctor\n"));
1353
+ const home = homedir4();
1354
+ const terminal = detectTerminal();
1355
+ const capabilities = detectCapabilities();
1356
+ const os = detectOS();
1357
+ const checks = [
1358
+ // Terminal
1359
+ check(
1360
+ "Terminal",
1361
+ () => terminal.type !== "unknown" ? { status: "ok", message: `${terminal.name} detected` } : { status: "warn", message: "Unknown terminal" }
1362
+ ),
1363
+ // TrueColor
1364
+ check(
1365
+ "TrueColor support",
1366
+ () => capabilities.trueColor ? { status: "ok", message: "24-bit color supported" } : { status: "warn", message: "Limited to 256 colors" }
1367
+ ),
1368
+ // Unicode
1369
+ check(
1370
+ "Unicode support",
1371
+ () => capabilities.unicode ? { status: "ok", message: "UTF-8 enabled" } : { status: "warn", message: "UTF-8 not detected in locale" }
1372
+ ),
1373
+ // Claude Code
1374
+ check(
1375
+ "Claude Code",
1376
+ () => commandExists("claude") ? { status: "ok", message: "Installed" } : { status: "fail", message: "Not found. Install: npm i -g @anthropic-ai/claude-code" }
1377
+ ),
1378
+ // Starship
1379
+ check("Starship", () => {
1380
+ if (!commandExists("starship")) {
1381
+ return { status: "warn", message: "Not installed. Install: brew install starship" };
1382
+ }
1383
+ const configPath = join4(home, ".config", "starship.toml");
1384
+ return existsSync5(configPath) ? { status: "ok", message: "Installed and configured" } : { status: "warn", message: "Installed but no config found" };
1385
+ }),
1386
+ // tmux
1387
+ check(
1388
+ "tmux",
1389
+ () => commandExists("tmux") ? { status: "ok", message: "Installed" } : { status: "warn", message: "Not installed. Install: brew install tmux" }
1390
+ ),
1391
+ // Font
1392
+ check("Maple Mono NF CN", () => {
1393
+ const fontPaths = [
1394
+ join4(home, "Library", "Fonts"),
1395
+ "/Library/Fonts",
1396
+ "/System/Library/Fonts"
1397
+ ];
1398
+ for (const fontPath of fontPaths) {
1399
+ try {
1400
+ const files = readdirSync(fontPath);
1401
+ if (files.some((f) => f.includes("MapleMono"))) {
1402
+ return { status: "ok", message: "Font installed" };
1403
+ }
1404
+ } catch {
1405
+ }
1406
+ }
1407
+ return {
1408
+ status: "warn",
1409
+ message: "Font not found. Install: brew install --cask font-maple-mono-nf-cn"
1410
+ };
1411
+ }),
1412
+ // Shell
1413
+ check("Shell", () => ({
1414
+ status: "ok",
1415
+ message: `${os.shell} on ${os.type} (${os.arch})`
1416
+ })),
1417
+ // Git
1418
+ check(
1419
+ "Git",
1420
+ () => commandExists("git") ? { status: "ok", message: "Installed" } : { status: "fail", message: "Not found" }
1421
+ )
1422
+ ];
1423
+ for (const result of checks) {
1424
+ console.log(formatCheck(result));
1425
+ }
1426
+ const failCount = checks.filter((c) => c.status === "fail").length;
1427
+ const warnCount = checks.filter((c) => c.status === "warn").length;
1428
+ console.log("");
1429
+ if (failCount > 0) {
1430
+ console.log(
1431
+ chalk5.red(
1432
+ ` ${failCount} issue(s) need fixing. Run den init to setup.
1433
+ `
1434
+ )
1435
+ );
1436
+ } else if (warnCount > 0) {
1437
+ console.log(
1438
+ chalk5.yellow(
1439
+ ` ${warnCount} suggestion(s). Run den init to improve your setup.
1440
+ `
1441
+ )
1442
+ );
1443
+ } else {
1444
+ console.log(
1445
+ chalk5.green(" Everything looks great! Happy coding with Claude.\n")
1446
+ );
1447
+ }
1448
+ });
1449
+ }
1450
+
1451
+ // src/cli/program.ts
1452
+ function createProgram() {
1453
+ const program2 = new Command();
1454
+ program2.name("den").description("Your cozy terminal den for Claude Code").version("0.1.0");
1455
+ registerInitCommand(program2);
1456
+ registerThemeCommand(program2);
1457
+ registerLayoutCommand(program2);
1458
+ registerDoctorCommand(program2);
1459
+ registerBackupCommand(program2);
1460
+ registerRestoreCommand(program2);
1461
+ return program2;
1462
+ }
1463
+
1464
+ // bin/den.ts
1465
+ var program = createProgram();
1466
+ program.parse(process.argv);
1467
+ //# sourceMappingURL=den.js.map