@vimukthid/ccsl 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js ADDED
@@ -0,0 +1,1225 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // node_modules/tsup/assets/esm_shims.js
13
+ import path from "path";
14
+ import { fileURLToPath } from "url";
15
+ var init_esm_shims = __esm({
16
+ "node_modules/tsup/assets/esm_shims.js"() {
17
+ "use strict";
18
+ }
19
+ });
20
+
21
+ // src/config/defaults.ts
22
+ var defaultWidgets, defaultConfig;
23
+ var init_defaults = __esm({
24
+ "src/config/defaults.ts"() {
25
+ "use strict";
26
+ init_esm_shims();
27
+ defaultWidgets = ["model", "context", "tokens", "cost"];
28
+ defaultConfig = {
29
+ theme: "minimal",
30
+ widgets: defaultWidgets,
31
+ separator: " \u2502 ",
32
+ icons: "auto",
33
+ padding: 1
34
+ };
35
+ }
36
+ });
37
+
38
+ // src/config/loader.ts
39
+ import { cosmiconfig } from "cosmiconfig";
40
+ async function loadConfig(searchFrom) {
41
+ try {
42
+ const result = await explorer.search(searchFrom);
43
+ if (result && result.config) {
44
+ return mergeConfig(defaultConfig, result.config);
45
+ }
46
+ } catch {
47
+ }
48
+ return { ...defaultConfig };
49
+ }
50
+ function mergeConfig(defaults, userConfig) {
51
+ return {
52
+ theme: userConfig.theme ?? defaults.theme,
53
+ widgets: userConfig.widgets ?? defaults.widgets,
54
+ separator: userConfig.separator ?? defaults.separator,
55
+ icons: userConfig.icons ?? defaults.icons,
56
+ padding: userConfig.padding ?? defaults.padding,
57
+ customTheme: userConfig.customTheme
58
+ };
59
+ }
60
+ function getConfigPath(scope) {
61
+ if (scope === "local") {
62
+ return ".ccslrc.json";
63
+ }
64
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
65
+ return `${home}/.config/ccsl/config.json`;
66
+ }
67
+ var explorer;
68
+ var init_loader = __esm({
69
+ "src/config/loader.ts"() {
70
+ "use strict";
71
+ init_esm_shims();
72
+ init_defaults();
73
+ explorer = cosmiconfig("ccsl", {
74
+ searchPlaces: [
75
+ ".ccslrc",
76
+ ".ccslrc.json",
77
+ ".ccslrc.yaml",
78
+ ".ccslrc.yml",
79
+ ".ccslrc.js",
80
+ ".ccslrc.cjs",
81
+ ".config/ccsl/config.json",
82
+ "ccsl.config.js",
83
+ "ccsl.config.cjs"
84
+ ]
85
+ });
86
+ }
87
+ });
88
+
89
+ // src/themes/index.ts
90
+ var neonTheme, rainbowTheme, oceanTheme, minimalTheme, monochromeTheme, corporateTheme, themes, themeNames;
91
+ var init_themes = __esm({
92
+ "src/themes/index.ts"() {
93
+ "use strict";
94
+ init_esm_shims();
95
+ neonTheme = {
96
+ name: "neon",
97
+ colors: {
98
+ model: { fg: "#00ffff", bold: true },
99
+ context: { fg: "#ff00ff" },
100
+ contextHigh: { fg: "#ffff00" },
101
+ contextCritical: { fg: "#ff0000", bold: true },
102
+ tokens: { fg: "#00ff00" },
103
+ cost: { fg: "#ffff00" },
104
+ duration: { fg: "#00aaff" },
105
+ lines: { fg: "#ff6600" },
106
+ linesAdded: { fg: "#00ff00" },
107
+ linesRemoved: { fg: "#ff0066" },
108
+ directory: { fg: "#00ffff" },
109
+ version: { fg: "#aaaaff" },
110
+ separator: { fg: "#666666" }
111
+ }
112
+ };
113
+ rainbowTheme = {
114
+ name: "rainbow",
115
+ colors: {
116
+ model: { fg: "#ff0000", bold: true },
117
+ context: { fg: "#ff7f00" },
118
+ contextHigh: { fg: "#ffff00" },
119
+ contextCritical: { fg: "#ff0000", bold: true },
120
+ tokens: { fg: "#00ff00" },
121
+ cost: { fg: "#0000ff" },
122
+ duration: { fg: "#4b0082" },
123
+ lines: { fg: "#9400d3" },
124
+ linesAdded: { fg: "#00ff00" },
125
+ linesRemoved: { fg: "#ff0000" },
126
+ directory: { fg: "#ff7f00" },
127
+ version: { fg: "#9400d3" },
128
+ separator: { fg: "#888888" }
129
+ }
130
+ };
131
+ oceanTheme = {
132
+ name: "ocean",
133
+ colors: {
134
+ model: { fg: "#00bcd4", bold: true },
135
+ context: { fg: "#2d8b8b" },
136
+ contextHigh: { fg: "#4dd0e1" },
137
+ contextCritical: { fg: "#ff5252", bold: true },
138
+ tokens: { fg: "#80deea" },
139
+ cost: { fg: "#4dd0e1" },
140
+ duration: { fg: "#0288d1" },
141
+ lines: { fg: "#26c6da" },
142
+ linesAdded: { fg: "#69f0ae" },
143
+ linesRemoved: { fg: "#ff5252" },
144
+ directory: { fg: "#00bcd4" },
145
+ version: { fg: "#80deea" },
146
+ separator: { fg: "#37474f" }
147
+ }
148
+ };
149
+ minimalTheme = {
150
+ name: "minimal",
151
+ colors: {
152
+ model: { fg: "#888888" },
153
+ context: { fg: "#ffffff" },
154
+ contextHigh: { fg: "#e5c07b" },
155
+ contextCritical: { fg: "#e06c75", bold: true },
156
+ tokens: { fg: "#666666", dim: true },
157
+ cost: { fg: "#61afef" },
158
+ duration: { fg: "#666666", dim: true },
159
+ lines: { fg: "#abb2bf" },
160
+ linesAdded: { fg: "#98c379" },
161
+ linesRemoved: { fg: "#e06c75" },
162
+ directory: { fg: "#888888" },
163
+ version: { fg: "#5c6370" },
164
+ separator: { fg: "#444444" }
165
+ },
166
+ icons: {
167
+ model: "",
168
+ context: "",
169
+ tokens: "",
170
+ duration: "",
171
+ lines: "",
172
+ directory: ""
173
+ }
174
+ };
175
+ monochromeTheme = {
176
+ name: "monochrome",
177
+ colors: {
178
+ model: { fg: "#ffffff", bold: true },
179
+ context: { fg: "#cccccc" },
180
+ contextHigh: { fg: "#ffffff", bold: true },
181
+ contextCritical: { fg: "#ffffff", bold: true, underline: true },
182
+ tokens: { fg: "#aaaaaa" },
183
+ cost: { fg: "#999999" },
184
+ duration: { fg: "#888888" },
185
+ lines: { fg: "#777777" },
186
+ linesAdded: { fg: "#cccccc" },
187
+ linesRemoved: { fg: "#888888" },
188
+ directory: { fg: "#aaaaaa" },
189
+ version: { fg: "#666666" },
190
+ separator: { fg: "#444444" }
191
+ },
192
+ icons: {
193
+ model: "",
194
+ context: "",
195
+ tokens: "",
196
+ duration: "",
197
+ lines: "",
198
+ directory: ""
199
+ }
200
+ };
201
+ corporateTheme = {
202
+ name: "corporate",
203
+ colors: {
204
+ model: { fg: "#3b82f6", bold: true },
205
+ context: { fg: "#64748b" },
206
+ contextHigh: { fg: "#f59e0b" },
207
+ contextCritical: { fg: "#ef4444", bold: true },
208
+ tokens: { fg: "#4682b4" },
209
+ cost: { fg: "#6b7280" },
210
+ duration: { fg: "#64748b" },
211
+ lines: { fg: "#94a3b8" },
212
+ linesAdded: { fg: "#22c55e" },
213
+ linesRemoved: { fg: "#ef4444" },
214
+ directory: { fg: "#3b82f6" },
215
+ version: { fg: "#94a3b8" },
216
+ separator: { fg: "#334155" }
217
+ }
218
+ };
219
+ themes = {
220
+ neon: neonTheme,
221
+ rainbow: rainbowTheme,
222
+ ocean: oceanTheme,
223
+ minimal: minimalTheme,
224
+ monochrome: monochromeTheme,
225
+ corporate: corporateTheme
226
+ };
227
+ themeNames = Object.keys(themes);
228
+ }
229
+ });
230
+
231
+ // src/utils/icons.ts
232
+ function detectIconSupport() {
233
+ if (detectedIconMode !== null) {
234
+ return detectedIconMode;
235
+ }
236
+ const term = process.env.TERM || "";
237
+ const termProgram = process.env.TERM_PROGRAM || "";
238
+ const nerdFontEnv = process.env.NERD_FONT || "";
239
+ if (nerdFontEnv === "1" || nerdFontEnv.toLowerCase() === "true") {
240
+ detectedIconMode = "nerd";
241
+ return "nerd";
242
+ }
243
+ const nerdFontTerminals = ["iTerm.app", "WezTerm", "Alacritty", "kitty", "Hyper", "Tabby"];
244
+ if (nerdFontTerminals.some((t) => termProgram.includes(t))) {
245
+ detectedIconMode = "nerd";
246
+ return "nerd";
247
+ }
248
+ if (term.includes("256color") || term.includes("truecolor")) {
249
+ detectedIconMode = "unicode";
250
+ return "unicode";
251
+ }
252
+ detectedIconMode = "ascii";
253
+ return "ascii";
254
+ }
255
+ function getIcon(key, theme, mode) {
256
+ if (theme.icons && theme.icons[key]) {
257
+ return theme.icons[key] || "";
258
+ }
259
+ const effectiveMode = mode === "auto" ? detectIconSupport() : mode;
260
+ switch (effectiveMode) {
261
+ case "nerd":
262
+ return nerdIcons[key] || "";
263
+ case "unicode":
264
+ return unicodeIcons[key] || "";
265
+ case "ascii":
266
+ return asciiIcons[key] || "";
267
+ default:
268
+ return unicodeIcons[key] || "";
269
+ }
270
+ }
271
+ var nerdIcons, unicodeIcons, asciiIcons, detectedIconMode;
272
+ var init_icons = __esm({
273
+ "src/utils/icons.ts"() {
274
+ "use strict";
275
+ init_esm_shims();
276
+ nerdIcons = {
277
+ model: "\u25C8",
278
+ context: "\u25D0",
279
+ tokens: "\u{F0284}",
280
+ cost: "$",
281
+ duration: "\u23F1",
282
+ lines: "\xB1",
283
+ directory: "",
284
+ version: ""
285
+ };
286
+ unicodeIcons = {
287
+ model: "\u25C8",
288
+ context: "\u25D0",
289
+ tokens: "\u21C5",
290
+ cost: "$",
291
+ duration: "\u23F1",
292
+ lines: "\xB1",
293
+ directory: "\u{1F4C1}",
294
+ version: "v"
295
+ };
296
+ asciiIcons = {
297
+ model: "*",
298
+ context: "%",
299
+ tokens: "",
300
+ cost: "$",
301
+ duration: "",
302
+ lines: "",
303
+ directory: "",
304
+ version: "v"
305
+ };
306
+ detectedIconMode = null;
307
+ }
308
+ });
309
+
310
+ // src/utils/colors.ts
311
+ import chalk from "chalk";
312
+ function applyStyle(text, style) {
313
+ if (!style) return text;
314
+ let result = chalk;
315
+ if (style.fg) {
316
+ result = result.hex(style.fg);
317
+ }
318
+ if (style.bg) {
319
+ result = result.bgHex(style.bg);
320
+ }
321
+ if (style.bold) {
322
+ result = result.bold;
323
+ }
324
+ if (style.dim) {
325
+ result = result.dim;
326
+ }
327
+ if (style.italic) {
328
+ result = result.italic;
329
+ }
330
+ if (style.underline) {
331
+ result = result.underline;
332
+ }
333
+ return result(text);
334
+ }
335
+ var init_colors = __esm({
336
+ "src/utils/colors.ts"() {
337
+ "use strict";
338
+ init_esm_shims();
339
+ }
340
+ });
341
+
342
+ // src/utils/format.ts
343
+ function formatNumber(num) {
344
+ if (num >= 1e6) {
345
+ return `${(num / 1e6).toFixed(1)}m`;
346
+ }
347
+ if (num >= 1e3) {
348
+ return `${(num / 1e3).toFixed(1)}k`;
349
+ }
350
+ return num.toString();
351
+ }
352
+ function formatDuration(ms) {
353
+ const seconds = Math.floor(ms / 1e3);
354
+ if (seconds < 60) {
355
+ return `${seconds}s`;
356
+ }
357
+ const minutes = Math.floor(seconds / 60);
358
+ if (minutes < 60) {
359
+ const remainingSeconds = seconds % 60;
360
+ return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`;
361
+ }
362
+ const hours = Math.floor(minutes / 60);
363
+ const remainingMinutes = minutes % 60;
364
+ return remainingMinutes > 0 ? `${hours}h${remainingMinutes}m` : `${hours}h`;
365
+ }
366
+ function formatCost(usd) {
367
+ if (usd < 0.01) {
368
+ return usd.toFixed(4);
369
+ }
370
+ if (usd < 1) {
371
+ return usd.toFixed(2);
372
+ }
373
+ return usd.toFixed(2);
374
+ }
375
+ var init_format = __esm({
376
+ "src/utils/format.ts"() {
377
+ "use strict";
378
+ init_esm_shims();
379
+ }
380
+ });
381
+
382
+ // src/widgets/index.ts
383
+ import path2 from "path";
384
+ function renderWidget(widget, input, theme, config) {
385
+ switch (widget) {
386
+ case "model":
387
+ return renderModel(input, theme, config);
388
+ case "context":
389
+ return renderContext(input, theme, config);
390
+ case "tokens":
391
+ return renderTokens(input, theme, config);
392
+ case "cost":
393
+ return renderCostWidget(input, theme, config);
394
+ case "duration":
395
+ return renderDurationWidget(input, theme, config);
396
+ case "lines":
397
+ return renderLines(input, theme, config);
398
+ case "directory":
399
+ return renderDirectory(input, theme, config);
400
+ case "version":
401
+ return renderVersion(input, theme, config);
402
+ default:
403
+ return { content: "", visible: false };
404
+ }
405
+ }
406
+ function renderModel(input, theme, config) {
407
+ const displayName = input.model?.display_name;
408
+ if (!displayName) {
409
+ return { content: "", visible: false };
410
+ }
411
+ const icon = getIcon("model", theme, config.icons);
412
+ const text = icon ? `${icon} ${displayName}` : displayName;
413
+ const content = applyStyle(text, theme.colors.model);
414
+ return { content, visible: true };
415
+ }
416
+ function renderContext(input, theme, config) {
417
+ const percentage = input.context_window?.used_percentage;
418
+ if (percentage === void 0) {
419
+ return { content: "", visible: false };
420
+ }
421
+ const icon = getIcon("context", theme, config.icons);
422
+ const roundedPercent = Math.round(percentage);
423
+ const progressBar = renderProgressBar(percentage, theme);
424
+ const value = `${roundedPercent}%`;
425
+ const text = icon ? `${icon} ${progressBar} ${value}` : `${progressBar} ${value}`;
426
+ let colorKey = "context";
427
+ if (percentage >= 80) {
428
+ colorKey = "contextCritical";
429
+ } else if (percentage >= 60) {
430
+ colorKey = "contextHigh";
431
+ }
432
+ const style = theme.colors[colorKey] || theme.colors.context;
433
+ const content = applyStyle(text, style);
434
+ return { content, visible: true };
435
+ }
436
+ function renderProgressBar(percentage, theme) {
437
+ const totalBars = 10;
438
+ const filledBars = Math.round(percentage / 100 * totalBars);
439
+ const emptyBars = totalBars - filledBars;
440
+ const filledChar = "\u2588";
441
+ const emptyChar = "\u2591";
442
+ let filledStyle = theme.colors.context;
443
+ if (percentage >= 80) {
444
+ filledStyle = theme.colors.contextCritical || theme.colors.context;
445
+ } else if (percentage >= 60) {
446
+ filledStyle = theme.colors.contextHigh || theme.colors.context;
447
+ }
448
+ const filled = applyStyle(filledChar.repeat(filledBars), filledStyle);
449
+ const empty = applyStyle(emptyChar.repeat(emptyBars), { fg: "#444444", dim: true });
450
+ return `${filled}${empty}`;
451
+ }
452
+ function renderTokens(input, theme, config) {
453
+ const inputTokens = input.context_window?.total_input_tokens;
454
+ const outputTokens = input.context_window?.total_output_tokens;
455
+ if (inputTokens === void 0 && outputTokens === void 0) {
456
+ return { content: "", visible: false };
457
+ }
458
+ const icon = getIcon("tokens", theme, config.icons);
459
+ const inStr = formatNumber(inputTokens ?? 0);
460
+ const outStr = formatNumber(outputTokens ?? 0);
461
+ const text = icon ? `${icon} \u2191${inStr} \u2193${outStr}` : `\u2191${inStr} \u2193${outStr}`;
462
+ const content = applyStyle(text, theme.colors.tokens);
463
+ return { content, visible: true };
464
+ }
465
+ function renderCostWidget(input, theme, config) {
466
+ const costUsd = input.cost?.total_cost_usd;
467
+ if (costUsd === void 0) {
468
+ return { content: "", visible: false };
469
+ }
470
+ const icon = getIcon("cost", theme, config.icons);
471
+ const value = formatCost(costUsd);
472
+ const text = icon ? `${icon}${value}` : `$${value}`;
473
+ const content = applyStyle(text, theme.colors.cost);
474
+ return { content, visible: true };
475
+ }
476
+ function renderDurationWidget(input, theme, config) {
477
+ const durationMs = input.cost?.total_duration_ms;
478
+ if (durationMs === void 0) {
479
+ return { content: "", visible: false };
480
+ }
481
+ const icon = getIcon("duration", theme, config.icons);
482
+ const value = formatDuration(durationMs);
483
+ const text = icon ? `${icon} ${value}` : value;
484
+ const content = applyStyle(text, theme.colors.duration);
485
+ return { content, visible: true };
486
+ }
487
+ function renderLines(input, theme, config) {
488
+ const added = input.cost?.total_lines_added;
489
+ const removed = input.cost?.total_lines_removed;
490
+ if (added === void 0 && removed === void 0) {
491
+ return { content: "", visible: false };
492
+ }
493
+ const icon = getIcon("lines", theme, config.icons);
494
+ const addedStr = applyStyle(`+${added ?? 0}`, theme.colors.linesAdded || theme.colors.lines);
495
+ const removedStr = applyStyle(`-${removed ?? 0}`, theme.colors.linesRemoved || theme.colors.lines);
496
+ const text = icon ? `${icon} ${addedStr} ${removedStr}` : `${addedStr} ${removedStr}`;
497
+ return { content: text, visible: true };
498
+ }
499
+ function renderDirectory(input, theme, config) {
500
+ const dir = input.workspace?.current_dir || input.cwd;
501
+ if (!dir) {
502
+ return { content: "", visible: false };
503
+ }
504
+ const icon = getIcon("directory", theme, config.icons);
505
+ const dirName = path2.basename(dir);
506
+ const text = icon ? `${icon} ${dirName}` : dirName;
507
+ const content = applyStyle(text, theme.colors.directory);
508
+ return { content, visible: true };
509
+ }
510
+ function renderVersion(input, theme, config) {
511
+ const version = input.version;
512
+ if (!version) {
513
+ return { content: "", visible: false };
514
+ }
515
+ const icon = getIcon("version", theme, config.icons);
516
+ const text = icon ? `${icon}${version}` : `v${version}`;
517
+ const content = applyStyle(text, theme.colors.version);
518
+ return { content, visible: true };
519
+ }
520
+ var availableWidgets;
521
+ var init_widgets = __esm({
522
+ "src/widgets/index.ts"() {
523
+ "use strict";
524
+ init_esm_shims();
525
+ init_icons();
526
+ init_colors();
527
+ init_format();
528
+ availableWidgets = [
529
+ "model",
530
+ "context",
531
+ "tokens",
532
+ "cost",
533
+ "duration",
534
+ "lines",
535
+ "directory",
536
+ "version"
537
+ ];
538
+ }
539
+ });
540
+
541
+ // src/formatter.ts
542
+ function formatStatusLine(input, config) {
543
+ const theme = config.customTheme || themes[config.theme] || themes.minimal;
544
+ const renderedWidgets = [];
545
+ for (const widget of config.widgets) {
546
+ const result = renderWidget(widget, input, theme, config);
547
+ if (result.visible && result.content) {
548
+ renderedWidgets.push(result.content);
549
+ }
550
+ }
551
+ if (renderedWidgets.length === 0) {
552
+ return "";
553
+ }
554
+ const separator = applyStyle(config.separator, theme.colors.separator);
555
+ const statusLine = renderedWidgets.join(separator);
556
+ const padding = " ".repeat(config.padding);
557
+ return `\x1B[0m${padding}${statusLine}${padding}`;
558
+ }
559
+ var sampleStatusInput;
560
+ var init_formatter = __esm({
561
+ "src/formatter.ts"() {
562
+ "use strict";
563
+ init_esm_shims();
564
+ init_themes();
565
+ init_widgets();
566
+ init_colors();
567
+ sampleStatusInput = {
568
+ hook_event_name: "Status",
569
+ session_id: "sample-session-123",
570
+ model: {
571
+ id: "claude-opus-4-1",
572
+ display_name: "Opus"
573
+ },
574
+ workspace: {
575
+ current_dir: "/home/user/my-project",
576
+ project_dir: "/home/user/my-project"
577
+ },
578
+ version: "1.0.80",
579
+ cost: {
580
+ total_cost_usd: 0.0234,
581
+ total_duration_ms: 45e3,
582
+ total_api_duration_ms: 2300,
583
+ total_lines_added: 156,
584
+ total_lines_removed: 23
585
+ },
586
+ context_window: {
587
+ total_input_tokens: 15234,
588
+ total_output_tokens: 4521,
589
+ context_window_size: 2e5,
590
+ used_percentage: 42.5,
591
+ remaining_percentage: 57.5,
592
+ current_usage: {
593
+ input_tokens: 8500,
594
+ output_tokens: 1200,
595
+ cache_creation_input_tokens: 5e3,
596
+ cache_read_input_tokens: 2e3
597
+ }
598
+ }
599
+ };
600
+ }
601
+ });
602
+
603
+ // src/config/claude.ts
604
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "fs";
605
+ import { dirname, join } from "path";
606
+ import { homedir } from "os";
607
+ function getClaudeSettingsPath() {
608
+ const claudeDir = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
609
+ return join(claudeDir, "settings.json");
610
+ }
611
+ function getClaudeSettings() {
612
+ const settingsPath = getClaudeSettingsPath();
613
+ if (!existsSync(settingsPath)) {
614
+ return null;
615
+ }
616
+ try {
617
+ const content = readFileSync(settingsPath, "utf8");
618
+ return JSON.parse(content);
619
+ } catch {
620
+ return null;
621
+ }
622
+ }
623
+ function backupClaudeSettings() {
624
+ const settingsPath = getClaudeSettingsPath();
625
+ if (!existsSync(settingsPath)) {
626
+ return null;
627
+ }
628
+ const backupPath = settingsPath + ".backup";
629
+ try {
630
+ copyFileSync(settingsPath, backupPath);
631
+ return backupPath;
632
+ } catch {
633
+ return null;
634
+ }
635
+ }
636
+ function installToClaudeSettings(command = "npx @vimukthid/ccsl") {
637
+ const settingsPath = getClaudeSettingsPath();
638
+ const dir = dirname(settingsPath);
639
+ if (!existsSync(dir)) {
640
+ mkdirSync(dir, { recursive: true });
641
+ }
642
+ let settings = {};
643
+ if (existsSync(settingsPath)) {
644
+ try {
645
+ const content = readFileSync(settingsPath, "utf8");
646
+ settings = JSON.parse(content);
647
+ } catch {
648
+ settings = {};
649
+ }
650
+ }
651
+ settings.statusLine = {
652
+ type: "command",
653
+ command
654
+ };
655
+ try {
656
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
657
+ return true;
658
+ } catch {
659
+ return false;
660
+ }
661
+ }
662
+ function uninstallFromClaudeSettings() {
663
+ const settingsPath = getClaudeSettingsPath();
664
+ if (!existsSync(settingsPath)) {
665
+ return true;
666
+ }
667
+ try {
668
+ const content = readFileSync(settingsPath, "utf8");
669
+ const settings = JSON.parse(content);
670
+ delete settings.statusLine;
671
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
672
+ return true;
673
+ } catch {
674
+ return false;
675
+ }
676
+ }
677
+ function isInstalledInClaude() {
678
+ const settings = getClaudeSettings();
679
+ if (!settings?.statusLine) {
680
+ return false;
681
+ }
682
+ const command = settings.statusLine.command || "";
683
+ return command.includes("ccsl") || command.includes("@vimukthid/ccsl");
684
+ }
685
+ function getCurrentClaudeCommand() {
686
+ const settings = getClaudeSettings();
687
+ return settings?.statusLine?.command || null;
688
+ }
689
+ var init_claude = __esm({
690
+ "src/config/claude.ts"() {
691
+ "use strict";
692
+ init_esm_shims();
693
+ }
694
+ });
695
+
696
+ // src/tui/app.tsx
697
+ var app_exports = {};
698
+ __export(app_exports, {
699
+ launchTui: () => launchTui
700
+ });
701
+ import { useState } from "react";
702
+ import { render, Box, Text, useApp, useInput } from "ink";
703
+ import SelectInput from "ink-select-input";
704
+ import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
705
+ import { dirname as dirname2 } from "path";
706
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
707
+ function App({ initialConfig, scope }) {
708
+ const { exit } = useApp();
709
+ const [screen, setScreen] = useState("main");
710
+ const [config, setConfig] = useState(initialConfig);
711
+ const [message, setMessage] = useState("");
712
+ useInput((input, key) => {
713
+ if (key.escape) {
714
+ if (screen === "main") {
715
+ exit();
716
+ } else {
717
+ setScreen("main");
718
+ }
719
+ }
720
+ if (input === "q" && screen === "main") {
721
+ exit();
722
+ }
723
+ });
724
+ const saveConfig = () => {
725
+ const configPath = getConfigPath(scope);
726
+ try {
727
+ const dir = dirname2(configPath);
728
+ if (!existsSync2(dir)) {
729
+ mkdirSync2(dir, { recursive: true });
730
+ }
731
+ writeFileSync2(configPath, JSON.stringify(config, null, 2));
732
+ setMessage("Configuration saved!");
733
+ setTimeout(() => setMessage(""), 2e3);
734
+ } catch (err) {
735
+ setMessage(`Error saving: ${err}`);
736
+ }
737
+ };
738
+ const renderMain = () => {
739
+ const items = [
740
+ { label: "Select Theme", value: "themes" },
741
+ { label: "Configure Widgets", value: "widgets" },
742
+ { label: "General Settings", value: "settings" },
743
+ { label: "Live Preview", value: "preview" },
744
+ { label: "Install to Claude Code", value: "install" },
745
+ { label: "Save Configuration", value: "save" },
746
+ { label: "Exit", value: "exit" }
747
+ ];
748
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
749
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
750
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "CCSL Configuration" }),
751
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
752
+ " (",
753
+ scope,
754
+ ")"
755
+ ] })
756
+ ] }),
757
+ /* @__PURE__ */ jsx(
758
+ SelectInput,
759
+ {
760
+ items,
761
+ onSelect: (item) => {
762
+ if (item.value === "exit") {
763
+ exit();
764
+ } else if (item.value === "save") {
765
+ saveConfig();
766
+ } else {
767
+ setScreen(item.value);
768
+ }
769
+ }
770
+ }
771
+ ),
772
+ message && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "green", children: message }) }),
773
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press q or Esc to exit" }) })
774
+ ] });
775
+ };
776
+ const renderThemes = () => {
777
+ const items = themeNames.map((name) => ({
778
+ label: `${name}${config.theme === name ? " (current)" : ""}`,
779
+ value: name
780
+ }));
781
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
782
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Select Theme" }) }),
783
+ /* @__PURE__ */ jsx(
784
+ SelectInput,
785
+ {
786
+ items,
787
+ onSelect: (item) => {
788
+ setConfig({ ...config, theme: item.value });
789
+ setScreen("main");
790
+ }
791
+ }
792
+ ),
793
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
794
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Preview:" }),
795
+ /* @__PURE__ */ jsx(Text, { children: formatStatusLine(sampleStatusInput, config) })
796
+ ] }),
797
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Esc to go back" }) })
798
+ ] });
799
+ };
800
+ const renderWidgets = () => {
801
+ const items = availableWidgets.map((widget) => ({
802
+ label: `${config.widgets.includes(widget) ? "[x]" : "[ ]"} ${widget}`,
803
+ value: widget
804
+ }));
805
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
806
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Configure Widgets" }) }),
807
+ /* @__PURE__ */ jsx(
808
+ SelectInput,
809
+ {
810
+ items,
811
+ onSelect: (item) => {
812
+ const widget = item.value;
813
+ const newWidgets = config.widgets.includes(widget) ? config.widgets.filter((w) => w !== widget) : [...config.widgets, widget];
814
+ setConfig({ ...config, widgets: newWidgets });
815
+ }
816
+ }
817
+ ),
818
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
819
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
820
+ "Current order: ",
821
+ config.widgets.join(", ")
822
+ ] }),
823
+ /* @__PURE__ */ jsx(Text, { children: formatStatusLine(sampleStatusInput, config) })
824
+ ] }),
825
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Esc to go back" }) })
826
+ ] });
827
+ };
828
+ const renderSettings = () => {
829
+ const iconOptions = [
830
+ { label: `Icons: auto${config.icons === "auto" ? " (current)" : ""}`, value: "icon-auto" },
831
+ { label: `Icons: nerd${config.icons === "nerd" ? " (current)" : ""}`, value: "icon-nerd" },
832
+ {
833
+ label: `Icons: unicode${config.icons === "unicode" ? " (current)" : ""}`,
834
+ value: "icon-unicode"
835
+ },
836
+ { label: `Icons: ascii${config.icons === "ascii" ? " (current)" : ""}`, value: "icon-ascii" }
837
+ ];
838
+ const separatorOptions = [
839
+ {
840
+ label: `Separator: " \u2502 "${config.separator === " \u2502 " ? " (current)" : ""}`,
841
+ value: "sep- \u2502 "
842
+ },
843
+ {
844
+ label: `Separator: " | "${config.separator === " | " ? " (current)" : ""}`,
845
+ value: "sep- | "
846
+ },
847
+ {
848
+ label: `Separator: " \xB7 "${config.separator === " \xB7 " ? " (current)" : ""}`,
849
+ value: "sep- \xB7 "
850
+ },
851
+ {
852
+ label: `Separator: " "${config.separator === " " ? " (current)" : ""}`,
853
+ value: "sep- "
854
+ }
855
+ ];
856
+ const items = [...iconOptions, ...separatorOptions];
857
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
858
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "General Settings" }) }),
859
+ /* @__PURE__ */ jsx(
860
+ SelectInput,
861
+ {
862
+ items,
863
+ onSelect: (item) => {
864
+ if (item.value.startsWith("icon-")) {
865
+ const iconMode = item.value.replace("icon-", "");
866
+ setConfig({ ...config, icons: iconMode });
867
+ } else if (item.value.startsWith("sep-")) {
868
+ const sep = item.value.replace("sep-", "");
869
+ setConfig({ ...config, separator: sep });
870
+ }
871
+ }
872
+ }
873
+ ),
874
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: formatStatusLine(sampleStatusInput, config) }) }),
875
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Esc to go back" }) })
876
+ ] });
877
+ };
878
+ const renderPreview = () => {
879
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
880
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Live Preview" }) }),
881
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
882
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
883
+ "Theme: ",
884
+ config.theme
885
+ ] }),
886
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
887
+ "Widgets: ",
888
+ config.widgets.join(", ")
889
+ ] }),
890
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
891
+ "Icons: ",
892
+ config.icons
893
+ ] })
894
+ ] }),
895
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Output:" }) }),
896
+ /* @__PURE__ */ jsx(Text, { children: formatStatusLine(sampleStatusInput, config) }),
897
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Esc to go back" }) })
898
+ ] });
899
+ };
900
+ const renderInstall = () => {
901
+ const installed = isInstalledInClaude();
902
+ const currentCmd = getCurrentClaudeCommand();
903
+ const items = [
904
+ { label: installed ? "Update Installation" : "Install to Claude Code", value: "install" },
905
+ { label: "Back", value: "back" }
906
+ ];
907
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
908
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Claude Code Integration" }) }),
909
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, flexDirection: "column", children: installed ? /* @__PURE__ */ jsxs(Fragment, { children: [
910
+ /* @__PURE__ */ jsx(Text, { color: "green", children: "Status: Installed" }),
911
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
912
+ "Command: ",
913
+ currentCmd
914
+ ] })
915
+ ] }) : /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Status: Not installed" }) }),
916
+ /* @__PURE__ */ jsx(
917
+ SelectInput,
918
+ {
919
+ items,
920
+ onSelect: (item) => {
921
+ if (item.value === "install") {
922
+ const success = installToClaudeSettings();
923
+ if (success) {
924
+ setMessage("Installed! Restart Claude Code to apply.");
925
+ } else {
926
+ setMessage("Installation failed. Check permissions.");
927
+ }
928
+ setTimeout(() => setMessage(""), 3e3);
929
+ } else {
930
+ setScreen("main");
931
+ }
932
+ }
933
+ }
934
+ ),
935
+ message && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: message.includes("failed") ? "red" : "green", children: message }) }),
936
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Esc to go back" }) })
937
+ ] });
938
+ };
939
+ return /* @__PURE__ */ jsxs(Box, { padding: 1, flexDirection: "column", children: [
940
+ screen === "main" && renderMain(),
941
+ screen === "themes" && renderThemes(),
942
+ screen === "widgets" && renderWidgets(),
943
+ screen === "settings" && renderSettings(),
944
+ screen === "preview" && renderPreview(),
945
+ screen === "install" && renderInstall()
946
+ ] });
947
+ }
948
+ async function launchTui(scope) {
949
+ const config = await loadConfig();
950
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx(App, { initialConfig: config, scope }));
951
+ await waitUntilExit();
952
+ }
953
+ var init_app = __esm({
954
+ "src/tui/app.tsx"() {
955
+ "use strict";
956
+ init_esm_shims();
957
+ init_loader();
958
+ init_themes();
959
+ init_formatter();
960
+ init_widgets();
961
+ init_claude();
962
+ }
963
+ });
964
+
965
+ // src/cli.ts
966
+ init_esm_shims();
967
+ init_loader();
968
+ import { Command } from "commander";
969
+
970
+ // src/parser.ts
971
+ init_esm_shims();
972
+ import { z } from "zod";
973
+ var StatusInputSchema = z.object({
974
+ hook_event_name: z.string().optional(),
975
+ session_id: z.string().optional(),
976
+ transcript_path: z.string().optional(),
977
+ cwd: z.string().optional(),
978
+ model: z.object({
979
+ id: z.string().optional(),
980
+ display_name: z.string().optional()
981
+ }).optional(),
982
+ workspace: z.object({
983
+ current_dir: z.string().optional(),
984
+ project_dir: z.string().optional()
985
+ }).optional(),
986
+ version: z.string().optional(),
987
+ output_style: z.object({
988
+ name: z.string().optional()
989
+ }).optional(),
990
+ cost: z.object({
991
+ total_cost_usd: z.number().optional(),
992
+ total_duration_ms: z.number().optional(),
993
+ total_api_duration_ms: z.number().optional(),
994
+ total_lines_added: z.number().optional(),
995
+ total_lines_removed: z.number().optional()
996
+ }).optional(),
997
+ context_window: z.object({
998
+ total_input_tokens: z.number().optional(),
999
+ total_output_tokens: z.number().optional(),
1000
+ context_window_size: z.number().optional(),
1001
+ used_percentage: z.number().optional(),
1002
+ remaining_percentage: z.number().optional(),
1003
+ current_usage: z.object({
1004
+ input_tokens: z.number().optional(),
1005
+ output_tokens: z.number().optional(),
1006
+ cache_creation_input_tokens: z.number().optional(),
1007
+ cache_read_input_tokens: z.number().optional()
1008
+ }).nullable().optional()
1009
+ }).optional()
1010
+ }).passthrough();
1011
+ function parseStatusInput(input) {
1012
+ try {
1013
+ const trimmed = input.trim();
1014
+ if (!trimmed) {
1015
+ return null;
1016
+ }
1017
+ const parsed = JSON.parse(trimmed);
1018
+ const result = StatusInputSchema.safeParse(parsed);
1019
+ if (result.success) {
1020
+ return result.data;
1021
+ }
1022
+ return parsed;
1023
+ } catch {
1024
+ return null;
1025
+ }
1026
+ }
1027
+ async function readStdin() {
1028
+ return new Promise((resolve) => {
1029
+ let data = "";
1030
+ process.stdin.setEncoding("utf8");
1031
+ process.stdin.on("readable", () => {
1032
+ let chunk;
1033
+ while ((chunk = process.stdin.read()) !== null) {
1034
+ data += chunk;
1035
+ }
1036
+ });
1037
+ process.stdin.on("end", () => {
1038
+ resolve(data);
1039
+ });
1040
+ process.stdin.on("error", () => {
1041
+ resolve("");
1042
+ });
1043
+ });
1044
+ }
1045
+ function isInteractiveMode() {
1046
+ return process.stdin.isTTY === true;
1047
+ }
1048
+
1049
+ // src/cli.ts
1050
+ init_formatter();
1051
+ init_themes();
1052
+ init_claude();
1053
+ init_defaults();
1054
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync3 } from "fs";
1055
+ import { dirname as dirname3 } from "path";
1056
+ var program = new Command();
1057
+ program.name("ccsl").description("Customizable status line formatter for Claude Code CLI").version("1.0.0");
1058
+ program.command("install").description("Install ccsl to Claude Code settings.json").option("-c, --command <cmd>", "Custom command to use", "npx @vimukthid/ccsl").action(async (options) => {
1059
+ console.log("\nInstalling ccsl to Claude Code...\n");
1060
+ if (isInstalledInClaude()) {
1061
+ const currentCmd = getCurrentClaudeCommand();
1062
+ console.log(` Already installed with command: ${currentCmd}`);
1063
+ console.log(" Updating configuration...\n");
1064
+ }
1065
+ const backupPath = backupClaudeSettings();
1066
+ if (backupPath) {
1067
+ console.log(` Backup created: ${backupPath}`);
1068
+ }
1069
+ const success = installToClaudeSettings(options.command);
1070
+ if (success) {
1071
+ console.log(` Installed to: ${getClaudeSettingsPath()}`);
1072
+ console.log(` Command: ${options.command}`);
1073
+ console.log("\n ccsl is now configured for Claude Code!");
1074
+ console.log(" Restart Claude Code to see your new status line.\n");
1075
+ } else {
1076
+ console.error("\n Failed to install. Check file permissions.\n");
1077
+ process.exit(1);
1078
+ }
1079
+ });
1080
+ program.command("uninstall").description("Remove ccsl from Claude Code settings.json").action(async () => {
1081
+ console.log("\nRemoving ccsl from Claude Code...\n");
1082
+ if (!isInstalledInClaude()) {
1083
+ console.log(" ccsl is not currently installed in Claude Code.\n");
1084
+ return;
1085
+ }
1086
+ const backupPath = backupClaudeSettings();
1087
+ if (backupPath) {
1088
+ console.log(` Backup created: ${backupPath}`);
1089
+ }
1090
+ const success = uninstallFromClaudeSettings();
1091
+ if (success) {
1092
+ console.log(" Successfully removed from Claude Code settings.\n");
1093
+ } else {
1094
+ console.error("\n Failed to uninstall. Check file permissions.\n");
1095
+ process.exit(1);
1096
+ }
1097
+ });
1098
+ program.command("theme [name]").description("Quick switch theme or list available themes").option("-l, --list", "List available themes").action(async (name, options) => {
1099
+ if (options.list || !name) {
1100
+ listThemes();
1101
+ return;
1102
+ }
1103
+ await switchTheme(name);
1104
+ });
1105
+ program.command("preview").description("Preview current configuration with sample data").action(async () => {
1106
+ await previewConfig();
1107
+ });
1108
+ program.command("init").description("Create local config file").option("-g, --global", "Create global config file instead").action(async (options) => {
1109
+ const scope = options.global ? "global" : "local";
1110
+ await initConfig(scope);
1111
+ });
1112
+ program.command("config").description("Open TUI configuration").option("-g, --global", "Configure global settings").option("-l, --local", "Configure local project settings").action(async (options) => {
1113
+ const scope = options.global ? "global" : "local";
1114
+ await runTui(scope);
1115
+ });
1116
+ program.action(async () => {
1117
+ if (isInteractiveMode()) {
1118
+ await runTui("local");
1119
+ } else {
1120
+ const stdinData = await readStdin();
1121
+ const input = parseStatusInput(stdinData);
1122
+ if (!input) {
1123
+ console.log("");
1124
+ return;
1125
+ }
1126
+ const config = await loadConfig();
1127
+ const output = formatStatusLine(input, config);
1128
+ console.log(output);
1129
+ }
1130
+ });
1131
+ async function runTui(scope) {
1132
+ const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_app(), app_exports));
1133
+ await launchTui2(scope);
1134
+ }
1135
+ function listThemes() {
1136
+ console.log("\nAvailable themes:\n");
1137
+ const descriptions = {
1138
+ neon: "Vibrant cyberpunk with electric colors",
1139
+ rainbow: "Colorful gradient transitions",
1140
+ ocean: "Cool blues and teals",
1141
+ minimal: "Clean, understated (default)",
1142
+ monochrome: "Pure grayscale",
1143
+ corporate: "Professional muted blues"
1144
+ };
1145
+ for (const name of themeNames) {
1146
+ const desc = descriptions[name] || "";
1147
+ console.log(` ${name.padEnd(12)} - ${desc}`);
1148
+ }
1149
+ console.log("\nUse 'ccsl theme <name>' to switch themes");
1150
+ console.log("Use 'ccsl preview' to see the current theme\n");
1151
+ }
1152
+ async function switchTheme(themeName) {
1153
+ if (!themeNames.includes(themeName)) {
1154
+ console.error(`
1155
+ Error: Unknown theme '${themeName}'`);
1156
+ console.log(`Available themes: ${themeNames.join(", ")}
1157
+ `);
1158
+ process.exit(1);
1159
+ }
1160
+ const configPath = getConfigPath("local");
1161
+ const config = await loadConfig();
1162
+ config.theme = themeName;
1163
+ try {
1164
+ const dir = dirname3(configPath);
1165
+ if (!existsSync3(dir)) {
1166
+ mkdirSync3(dir, { recursive: true });
1167
+ }
1168
+ writeFileSync3(configPath, JSON.stringify(config, null, 2));
1169
+ console.log(`
1170
+ Theme switched to '${themeName}'
1171
+ `);
1172
+ const output = formatStatusLine(sampleStatusInput, config);
1173
+ console.log("Preview:");
1174
+ console.log(output);
1175
+ console.log("");
1176
+ } catch (err) {
1177
+ console.error(`
1178
+ Error saving config: ${err}
1179
+ `);
1180
+ process.exit(1);
1181
+ }
1182
+ }
1183
+ async function previewConfig() {
1184
+ const config = await loadConfig();
1185
+ console.log("\nCurrent configuration:");
1186
+ console.log(` Theme: ${config.theme}`);
1187
+ console.log(` Widgets: ${config.widgets.join(", ")}`);
1188
+ console.log(` Separator: "${config.separator}"`);
1189
+ console.log(` Icons: ${config.icons}`);
1190
+ console.log("\nPreview with sample data:\n");
1191
+ console.log(formatStatusLine(sampleStatusInput, config));
1192
+ console.log("");
1193
+ if (isInstalledInClaude()) {
1194
+ console.log(`Claude Code: Installed (${getCurrentClaudeCommand()})`);
1195
+ } else {
1196
+ console.log("Claude Code: Not installed (run 'ccsl install')");
1197
+ }
1198
+ console.log("");
1199
+ }
1200
+ async function initConfig(scope) {
1201
+ const configPath = getConfigPath(scope);
1202
+ if (existsSync3(configPath)) {
1203
+ console.log(`
1204
+ Config file already exists at ${configPath}
1205
+ `);
1206
+ return;
1207
+ }
1208
+ try {
1209
+ const dir = dirname3(configPath);
1210
+ if (!existsSync3(dir)) {
1211
+ mkdirSync3(dir, { recursive: true });
1212
+ }
1213
+ writeFileSync3(configPath, JSON.stringify(defaultConfig, null, 2));
1214
+ console.log(`
1215
+ Created config file at ${configPath}
1216
+ `);
1217
+ } catch (err) {
1218
+ console.error(`
1219
+ Error creating config: ${err}
1220
+ `);
1221
+ process.exit(1);
1222
+ }
1223
+ }
1224
+ program.parse();
1225
+ //# sourceMappingURL=cli.js.map