@prnv/tuck 1.4.1 → 1.5.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/index.js CHANGED
@@ -9,85 +9,203 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
- // src/ui/banner.ts
12
+ // src/ui/theme.ts
13
13
  import chalk from "chalk";
14
+ import figures from "figures";
15
+ import logSymbols from "log-symbols";
16
+ var DIVIDER_WIDTH, INDENT, colors, c, icons, categoryStyles, divider, indent, formatCount, formatStatus, boxStyles;
17
+ var init_theme = __esm({
18
+ "src/ui/theme.ts"() {
19
+ "use strict";
20
+ DIVIDER_WIDTH = 60;
21
+ INDENT = " ";
22
+ colors = {
23
+ // Brand
24
+ brand: chalk.cyan,
25
+ brandBold: chalk.bold.cyan,
26
+ brandDim: chalk.dim.cyan,
27
+ brandBg: chalk.bgCyan.black,
28
+ // Status
29
+ success: chalk.green,
30
+ warning: chalk.yellow,
31
+ error: chalk.red,
32
+ info: chalk.blue,
33
+ // Text
34
+ muted: chalk.dim,
35
+ bold: chalk.bold,
36
+ highlight: chalk.bold.white,
37
+ // Direct color aliases (for compatibility)
38
+ cyan: chalk.cyan,
39
+ green: chalk.green,
40
+ yellow: chalk.yellow,
41
+ red: chalk.red,
42
+ blue: chalk.blue,
43
+ dim: chalk.dim,
44
+ white: chalk.white
45
+ };
46
+ c = colors;
47
+ icons = {
48
+ // Status icons (colored, from log-symbols)
49
+ success: logSymbols.success,
50
+ error: logSymbols.error,
51
+ warning: logSymbols.warning,
52
+ info: logSymbols.info,
53
+ // Action icons (from figures - auto fallback)
54
+ tick: figures.tick,
55
+ cross: figures.cross,
56
+ pointer: figures.pointer,
57
+ arrowRight: figures.arrowRight,
58
+ arrowDown: figures.arrowDown,
59
+ arrowUp: figures.arrowUp,
60
+ // Progress icons
61
+ circle: figures.circle,
62
+ circleFilled: figures.circleFilled,
63
+ bullet: figures.bullet,
64
+ ellipsis: figures.ellipsis,
65
+ // File operations
66
+ add: c.success(figures.tick),
67
+ remove: c.error(figures.cross),
68
+ modify: c.warning("~"),
69
+ sync: c.brand(figures.arrowRight),
70
+ // Tree/structure
71
+ line: figures.line,
72
+ corner: figures.lineDownRight,
73
+ tee: figures.lineDownRightArc,
74
+ // Category icons
75
+ shell: "$",
76
+ git: figures.star,
77
+ editors: figures.pointer,
78
+ terminal: "#",
79
+ ssh: figures.warning,
80
+ misc: figures.bullet
81
+ };
82
+ categoryStyles = {
83
+ shell: { icon: "$", color: c.success },
84
+ git: { icon: figures.star, color: c.warning },
85
+ editors: { icon: figures.pointer, color: c.brand },
86
+ terminal: { icon: "#", color: c.info },
87
+ ssh: { icon: figures.warning, color: c.error },
88
+ misc: { icon: figures.bullet, color: c.muted }
89
+ };
90
+ divider = (width = DIVIDER_WIDTH) => c.muted("\u2500".repeat(width));
91
+ indent = (level = 1) => INDENT.repeat(level);
92
+ formatCount = (n, singular, plural) => {
93
+ const word = n === 1 ? singular : plural || `${singular}s`;
94
+ return `${c.bold(n.toString())} ${word}`;
95
+ };
96
+ formatStatus = (status) => {
97
+ switch (status) {
98
+ case "added":
99
+ return c.success(status);
100
+ case "modified":
101
+ return c.warning(status);
102
+ case "deleted":
103
+ return c.error(status);
104
+ default:
105
+ return c.muted(status);
106
+ }
107
+ };
108
+ boxStyles = {
109
+ /** Compact header box */
110
+ header: {
111
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
112
+ borderStyle: "round",
113
+ borderColor: "cyan"
114
+ },
115
+ /** Standard info box */
116
+ info: {
117
+ padding: 1,
118
+ margin: { top: 1, bottom: 1, left: 0, right: 0 },
119
+ borderStyle: "round",
120
+ borderColor: "cyan"
121
+ },
122
+ /** Success box */
123
+ success: {
124
+ padding: 1,
125
+ margin: { top: 1, bottom: 1, left: 0, right: 0 },
126
+ borderStyle: "round",
127
+ borderColor: "green"
128
+ },
129
+ /** Error box */
130
+ error: {
131
+ padding: 1,
132
+ margin: { top: 1, bottom: 1, left: 0, right: 0 },
133
+ borderStyle: "round",
134
+ borderColor: "red"
135
+ }
136
+ };
137
+ }
138
+ });
139
+
140
+ // src/ui/banner.ts
14
141
  import boxen from "boxen";
15
142
  var banner, miniBanner, customHelp, nextSteps;
16
143
  var init_banner = __esm({
17
144
  "src/ui/banner.ts"() {
18
145
  "use strict";
146
+ init_theme();
19
147
  banner = () => {
20
148
  const art = `
21
149
  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
22
150
  \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D
23
- \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D
24
- \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557
151
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D
152
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557
25
153
  \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557
26
154
  \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D`;
27
- console.log(chalk.cyan(art));
28
- console.log(chalk.dim(" Modern Dotfiles Manager\n"));
155
+ console.log(colors.brand(art));
156
+ console.log(colors.muted(" Modern Dotfiles Manager\n"));
29
157
  };
30
158
  miniBanner = () => {
31
- console.log(
32
- boxen(chalk.cyan.bold("tuck") + chalk.dim(" \xB7 Modern Dotfiles Manager"), {
33
- padding: { top: 0, bottom: 0, left: 1, right: 1 },
34
- borderStyle: "round",
35
- borderColor: "cyan"
36
- })
37
- );
159
+ console.log(boxen(colors.brandBold("tuck") + colors.muted(" \xB7 Modern Dotfiles Manager"), boxStyles.header));
38
160
  console.log();
39
161
  };
40
162
  customHelp = (version) => {
41
- const title = boxen(chalk.cyan.bold("tuck") + chalk.dim(` v${version}`), {
42
- padding: { top: 0, bottom: 0, left: 1, right: 1 },
43
- borderStyle: "round",
44
- borderColor: "cyan"
45
- });
163
+ const title = boxen(colors.brandBold("tuck") + colors.muted(` v${version}`), boxStyles.header);
46
164
  const quickStart = `
47
- ${chalk.bold.cyan("Quick Start:")}
48
- ${chalk.cyan("tuck init")} Set up tuck (auto-creates GitHub repo)
49
- ${chalk.cyan("tuck add <file>")} Start tracking a dotfile
50
- ${chalk.cyan("tuck sync")} Commit your changes
51
- ${chalk.cyan("tuck push")} Push to GitHub
165
+ ${colors.brandBold("Quick Start:")}
166
+ ${indent()}${colors.brand("tuck init")} Set up tuck
167
+ ${indent()}${colors.brand("tuck add <file>")} Track a dotfile
168
+ ${indent()}${colors.brand("tuck sync")} Commit changes
169
+ ${indent()}${colors.brand("tuck push")} Push to remote
52
170
 
53
- ${chalk.bold.cyan("On a New Machine:")}
54
- ${chalk.cyan("tuck apply <user>")} Apply dotfiles from GitHub
171
+ ${colors.brandBold("New Machine:")}
172
+ ${indent()}${colors.brand("tuck apply <user>")} Apply dotfiles from GitHub
55
173
  `;
56
174
  const commands = `
57
- ${chalk.bold.cyan("Commands:")}
58
- ${chalk.cyan("Getting Started")}
59
- init Initialize tuck repository
60
- scan Auto-detect and select dotfiles to track
61
- apply <source> Apply dotfiles from a repository
175
+ ${colors.brandBold("Commands:")}
176
+ ${indent()}${colors.brand("Getting Started")}
177
+ ${indent()}${indent()}init Initialize tuck
178
+ ${indent()}${indent()}scan Detect dotfiles
179
+ ${indent()}${indent()}apply <source> Apply from repo
62
180
 
63
- ${chalk.cyan("Managing Files")}
64
- add <paths...> Track dotfile(s)
65
- remove <paths...> Stop tracking dotfile(s)
66
- list List all tracked files
67
- status Show repository status
181
+ ${indent()}${colors.brand("Managing Files")}
182
+ ${indent()}${indent()}add <paths...> Track files
183
+ ${indent()}${indent()}remove <paths...> Untrack files
184
+ ${indent()}${indent()}list List tracked
185
+ ${indent()}${indent()}status Show status
68
186
 
69
- ${chalk.cyan("Syncing")}
70
- sync Sync changes to repository
71
- push Push to remote
72
- pull Pull from remote
73
- diff Show pending changes
187
+ ${indent()}${colors.brand("Syncing")}
188
+ ${indent()}${indent()}sync Commit changes
189
+ ${indent()}${indent()}push Push to remote
190
+ ${indent()}${indent()}pull Pull from remote
191
+ ${indent()}${indent()}diff Show changes
74
192
 
75
- ${chalk.cyan("Restoring")}
76
- restore Restore dotfiles to system
77
- undo Undo last apply (Time Machine backup)
193
+ ${indent()}${colors.brand("Restoring")}
194
+ ${indent()}${indent()}restore Restore files
195
+ ${indent()}${indent()}undo Undo last apply
78
196
 
79
- ${chalk.cyan("Configuration")}
80
- config Manage tuck configuration
197
+ ${indent()}${colors.brand("Config")}
198
+ ${indent()}${indent()}config Manage settings
81
199
  `;
82
200
  const footer = `
83
- ${chalk.dim("Run")} ${chalk.cyan("tuck <command> --help")} ${chalk.dim("for detailed command info")}
84
- ${chalk.dim("Documentation:")} ${chalk.cyan("https://github.com/Pranav-Karra-3301/tuck")}
201
+ ${colors.muted("Run")} ${colors.brand("tuck <command> --help")} ${colors.muted("for details")}
202
+ ${colors.muted("Docs:")} ${colors.brand("https://github.com/Pranav-Karra-3301/tuck")}
85
203
  `;
86
204
  return `${title}
87
205
  ${quickStart}${commands}${footer}`;
88
206
  };
89
207
  nextSteps = (steps) => {
90
- const content = steps.map((step, i) => `${chalk.cyan(`${i + 1}.`)} ${step}`).join("\n");
208
+ const content = steps.map((step, i) => `${colors.brand(`${i + 1}.`)} ${step}`).join("\n");
91
209
  console.log(
92
210
  boxen(content, {
93
211
  padding: 1,
@@ -103,75 +221,65 @@ ${quickStart}${commands}${footer}`;
103
221
  });
104
222
 
105
223
  // src/ui/logger.ts
106
- import chalk2 from "chalk";
107
- var logger, formatCount, formatStatus;
224
+ import logSymbols2 from "log-symbols";
225
+ import figures2 from "figures";
226
+ var fileIcons, logger;
108
227
  var init_logger = __esm({
109
228
  "src/ui/logger.ts"() {
110
229
  "use strict";
230
+ init_theme();
231
+ init_theme();
232
+ fileIcons = {
233
+ add: colors.success(figures2.tick),
234
+ modify: colors.warning("~"),
235
+ delete: colors.error(figures2.cross),
236
+ sync: colors.brand(figures2.arrowRight),
237
+ merge: colors.info("+")
238
+ };
111
239
  logger = {
112
240
  info: (msg) => {
113
- console.log(chalk2.blue("i"), msg);
241
+ console.log(logSymbols2.info, msg);
114
242
  },
115
243
  success: (msg) => {
116
- console.log(chalk2.green("ok"), msg);
244
+ console.log(logSymbols2.success, msg);
117
245
  },
118
246
  warning: (msg) => {
119
- console.log(chalk2.yellow("!"), msg);
247
+ console.log(logSymbols2.warning, msg);
120
248
  },
121
249
  error: (msg) => {
122
- console.log(chalk2.red("x"), msg);
250
+ console.log(logSymbols2.error, msg);
123
251
  },
124
252
  debug: (msg) => {
125
253
  if (process.env.DEBUG) {
126
- console.log(chalk2.gray("*"), chalk2.gray(msg));
254
+ console.log(colors.muted(figures2.bullet), colors.muted(msg));
127
255
  }
128
256
  },
129
257
  step: (current, total, msg) => {
130
- console.log(chalk2.dim(`[${current}/${total}]`), msg);
258
+ const counter = colors.muted(`[${current}/${total}]`);
259
+ console.log(counter, msg);
131
260
  },
132
261
  file: (action, path) => {
133
- const icons = {
134
- add: chalk2.green("+"),
135
- modify: chalk2.yellow("~"),
136
- delete: chalk2.red("-"),
137
- sync: chalk2.blue("<>"),
138
- merge: chalk2.magenta("+")
139
- };
140
- console.log(` ${icons[action]} ${path}`);
262
+ const icon = fileIcons[action];
263
+ console.log(`${indent()}${icon} ${colors.brand(path)}`);
141
264
  },
142
265
  tree: (items) => {
143
- items.forEach(({ name, isLast, indent = 0 }) => {
144
- const indentation = " ".repeat(indent);
145
- const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
146
- console.log(chalk2.dim(indentation + prefix) + name);
266
+ items.forEach(({ name, isLast, indent: indent2 = 0 }) => {
267
+ const indentation = indent(indent2);
268
+ const prefix = isLast ? figures2.lineUpRight : figures2.lineDownRightArc;
269
+ console.log(colors.muted(indentation + prefix + figures2.line), name);
147
270
  });
148
271
  },
149
272
  blank: () => {
150
273
  console.log();
151
274
  },
152
275
  dim: (msg) => {
153
- console.log(chalk2.dim(msg));
276
+ console.log(colors.muted(msg));
154
277
  },
155
278
  heading: (msg) => {
156
- console.log(chalk2.bold.cyan(msg));
157
- }
158
- };
159
- formatCount = (count, singular, plural) => {
160
- const word = count === 1 ? singular : plural || `${singular}s`;
161
- return `${chalk2.bold(count.toString())} ${word}`;
162
- };
163
- formatStatus = (status) => {
164
- switch (status) {
165
- case "modified":
166
- return chalk2.yellow("modified");
167
- case "added":
168
- return chalk2.green("added");
169
- case "deleted":
170
- return chalk2.red("deleted");
171
- case "untracked":
172
- return chalk2.gray("untracked");
173
- default:
174
- return status;
279
+ console.log(colors.brandBold(msg));
280
+ },
281
+ divider: () => {
282
+ console.log(divider(DIVIDER_WIDTH));
175
283
  }
176
284
  };
177
285
  }
@@ -179,18 +287,27 @@ var init_logger = __esm({
179
287
 
180
288
  // src/ui/prompts.ts
181
289
  import * as p from "@clack/prompts";
182
- import chalk3 from "chalk";
183
290
  var prompts;
184
291
  var init_prompts = __esm({
185
292
  "src/ui/prompts.ts"() {
186
293
  "use strict";
294
+ init_theme();
187
295
  prompts = {
296
+ /**
297
+ * Display command intro header
298
+ */
188
299
  intro: (title) => {
189
- p.intro(chalk3.bgCyan(chalk3.black(` ${title} `)));
300
+ p.intro(colors.brandBg(` ${title} `));
190
301
  },
302
+ /**
303
+ * Display command outro/success message
304
+ */
191
305
  outro: (message) => {
192
- p.outro(chalk3.green(message));
306
+ p.outro(colors.success(message));
193
307
  },
308
+ /**
309
+ * Confirm dialog (yes/no)
310
+ */
194
311
  confirm: async (message, initial = false) => {
195
312
  const result = await p.confirm({ message, initialValue: initial });
196
313
  if (p.isCancel(result)) {
@@ -198,6 +315,9 @@ var init_prompts = __esm({
198
315
  }
199
316
  return result;
200
317
  },
318
+ /**
319
+ * Single select from options
320
+ */
201
321
  select: async (message, options) => {
202
322
  const result = await p.select({
203
323
  message,
@@ -212,6 +332,9 @@ var init_prompts = __esm({
212
332
  }
213
333
  return result;
214
334
  },
335
+ /**
336
+ * Multi-select from options
337
+ */
215
338
  multiselect: async (message, options, config) => {
216
339
  const mappedOptions = options.map((opt) => ({
217
340
  value: opt.value,
@@ -220,8 +343,8 @@ var init_prompts = __esm({
220
343
  }));
221
344
  const result = await p.multiselect({
222
345
  message,
346
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
223
347
  options: mappedOptions,
224
- // eslint-disable-line @typescript-eslint/no-explicit-any
225
348
  required: config?.required ?? false,
226
349
  initialValues: config?.initialValues
227
350
  });
@@ -230,6 +353,9 @@ var init_prompts = __esm({
230
353
  }
231
354
  return result;
232
355
  },
356
+ /**
357
+ * Text input
358
+ */
233
359
  text: async (message, options) => {
234
360
  const result = await p.text({
235
361
  message,
@@ -242,6 +368,9 @@ var init_prompts = __esm({
242
368
  }
243
369
  return result;
244
370
  },
371
+ /**
372
+ * Password input (hidden)
373
+ */
245
374
  password: async (message) => {
246
375
  const result = await p.password({ message });
247
376
  if (p.isCancel(result)) {
@@ -249,14 +378,26 @@ var init_prompts = __esm({
249
378
  }
250
379
  return result;
251
380
  },
381
+ /**
382
+ * Create a spinner for async operations
383
+ */
252
384
  spinner: () => p.spinner(),
385
+ /**
386
+ * Display a note/info box
387
+ */
253
388
  note: (message, title) => {
254
389
  p.note(message, title);
255
390
  },
391
+ /**
392
+ * Cancel operation and exit
393
+ */
256
394
  cancel: (message = "Operation cancelled") => {
257
395
  p.cancel(message);
258
396
  process.exit(0);
259
397
  },
398
+ /**
399
+ * Logging helpers
400
+ */
260
401
  log: {
261
402
  info: (message) => {
262
403
  p.log.info(message);
@@ -277,6 +418,9 @@ var init_prompts = __esm({
277
418
  p.log.message(message);
278
419
  }
279
420
  },
421
+ /**
422
+ * Group multiple prompts
423
+ */
280
424
  group: async (steps, options) => {
281
425
  const results = await p.group(steps, {
282
426
  onCancel: () => {
@@ -294,52 +438,78 @@ var init_prompts = __esm({
294
438
  });
295
439
 
296
440
  // src/ui/spinner.ts
297
- import ora from "ora";
298
- import chalk4 from "chalk";
441
+ import * as p2 from "@clack/prompts";
442
+ import logSymbols3 from "log-symbols";
299
443
  var createSpinner, withSpinner;
300
444
  var init_spinner = __esm({
301
445
  "src/ui/spinner.ts"() {
302
446
  "use strict";
447
+ init_theme();
303
448
  createSpinner = (initialText) => {
304
- const spinner2 = ora({
305
- text: initialText,
306
- color: "cyan",
307
- spinner: "dots"
308
- });
449
+ const spinner4 = p2.spinner();
450
+ let currentText = initialText || "";
451
+ let started = false;
309
452
  return {
310
453
  start: (text2) => {
311
- if (text2) spinner2.text = text2;
312
- spinner2.start();
454
+ currentText = text2 || currentText || "Loading...";
455
+ spinner4.start(currentText);
456
+ started = true;
313
457
  },
314
458
  stop: () => {
315
- spinner2.stop();
459
+ if (started) {
460
+ spinner4.stop(currentText);
461
+ started = false;
462
+ }
316
463
  },
317
464
  succeed: (text2) => {
318
- spinner2.succeed(text2 ? chalk4.green(text2) : void 0);
465
+ if (started) {
466
+ spinner4.stop(colors.success(text2 || currentText));
467
+ started = false;
468
+ } else {
469
+ console.log(logSymbols3.success, colors.success(text2 || currentText));
470
+ }
319
471
  },
320
472
  fail: (text2) => {
321
- spinner2.fail(text2 ? chalk4.red(text2) : void 0);
473
+ if (started) {
474
+ spinner4.stop(colors.error(text2 || currentText));
475
+ started = false;
476
+ } else {
477
+ console.log(logSymbols3.error, colors.error(text2 || currentText));
478
+ }
322
479
  },
323
480
  warn: (text2) => {
324
- spinner2.warn(text2 ? chalk4.yellow(text2) : void 0);
481
+ if (started) {
482
+ spinner4.stop(colors.warning(text2 || currentText));
483
+ started = false;
484
+ } else {
485
+ console.log(logSymbols3.warning, colors.warning(text2 || currentText));
486
+ }
325
487
  },
326
488
  info: (text2) => {
327
- spinner2.info(text2 ? chalk4.blue(text2) : void 0);
489
+ if (started) {
490
+ spinner4.stop(colors.info(text2 || currentText));
491
+ started = false;
492
+ } else {
493
+ console.log(logSymbols3.info, colors.info(text2 || currentText));
494
+ }
328
495
  },
329
496
  text: (text2) => {
330
- spinner2.text = text2;
497
+ currentText = text2;
498
+ if (started) {
499
+ spinner4.message(text2);
500
+ }
331
501
  }
332
502
  };
333
503
  };
334
504
  withSpinner = async (text2, fn, options) => {
335
- const spinner2 = createSpinner(text2);
336
- spinner2.start();
505
+ const spinner4 = createSpinner(text2);
506
+ spinner4.start();
337
507
  try {
338
508
  const result = await fn();
339
- spinner2.succeed(options?.successText || text2);
509
+ spinner4.succeed(options?.successText || text2);
340
510
  return result;
341
511
  } catch (error) {
342
- spinner2.fail(options?.failText || text2);
512
+ spinner4.fail(options?.failText || text2);
343
513
  throw error;
344
514
  }
345
515
  };
@@ -347,26 +517,21 @@ var init_spinner = __esm({
347
517
  });
348
518
 
349
519
  // src/ui/table.ts
350
- import chalk5 from "chalk";
351
520
  var init_table = __esm({
352
521
  "src/ui/table.ts"() {
353
522
  "use strict";
523
+ init_theme();
354
524
  }
355
525
  });
356
526
 
357
527
  // src/ui/progress.ts
358
- import chalk6 from "chalk";
359
- import ora2 from "ora";
360
- var ICONS;
528
+ import * as p3 from "@clack/prompts";
529
+ import logSymbols4 from "log-symbols";
530
+ import figures3 from "figures";
361
531
  var init_progress = __esm({
362
532
  "src/ui/progress.ts"() {
363
533
  "use strict";
364
- ICONS = {
365
- pending: chalk6.dim("\u25CB"),
366
- in_progress: chalk6.cyan("\u25CF"),
367
- completed: chalk6.green("\u2713"),
368
- error: chalk6.red("\u2717")
369
- };
534
+ init_theme();
370
535
  }
371
536
  });
372
537
 
@@ -374,6 +539,7 @@ var init_progress = __esm({
374
539
  var init_ui = __esm({
375
540
  "src/ui/index.ts"() {
376
541
  "use strict";
542
+ init_theme();
377
543
  init_banner();
378
544
  init_logger();
379
545
  init_prompts();
@@ -388,6 +554,7 @@ import { homedir } from "os";
388
554
  import { join, dirname } from "path";
389
555
  import { readFileSync } from "fs";
390
556
  import { fileURLToPath } from "url";
557
+ import figures4 from "figures";
391
558
  var __dirname, packageJsonPath, VERSION_VALUE, VERSION, DESCRIPTION, HOME_DIR, DEFAULT_TUCK_DIR, MANIFEST_FILE, CONFIG_FILE, BACKUP_DIR, FILES_DIR, CATEGORIES;
392
559
  var init_constants = __esm({
393
560
  "src/constants.ts"() {
@@ -425,7 +592,7 @@ var init_constants = __esm({
425
592
  },
426
593
  git: {
427
594
  patterns: [".gitconfig", ".gitignore_global", ".gitmessage", ".gitattributes"],
428
- icon: "*"
595
+ icon: figures4.star
429
596
  },
430
597
  editors: {
431
598
  patterns: [
@@ -437,7 +604,7 @@ var init_constants = __esm({
437
604
  ".ideavimrc",
438
605
  ".nanorc"
439
606
  ],
440
- icon: ">"
607
+ icon: figures4.pointer
441
608
  },
442
609
  terminal: {
443
610
  patterns: [
@@ -453,11 +620,11 @@ var init_constants = __esm({
453
620
  },
454
621
  ssh: {
455
622
  patterns: [".ssh/config"],
456
- icon: "!"
623
+ icon: figures4.warning
457
624
  },
458
625
  misc: {
459
626
  patterns: [],
460
- icon: "-"
627
+ icon: figures4.bullet
461
628
  }
462
629
  };
463
630
  }
@@ -771,7 +938,7 @@ var init_config_schema = __esm({
771
938
  });
772
939
 
773
940
  // src/errors.ts
774
- import chalk7 from "chalk";
941
+ import chalk2 from "chalk";
775
942
  var TuckError, NotInitializedError, AlreadyInitializedError, FileNotFoundError, FileNotTrackedError, FileAlreadyTrackedError, GitError, ConfigError, ManifestError, PermissionError, GitHubCliError, BackupError, SecretsDetectedError, handleError;
776
943
  var init_errors = __esm({
777
944
  "src/errors.ts"() {
@@ -886,22 +1053,22 @@ var init_errors = __esm({
886
1053
  };
887
1054
  handleError = (error) => {
888
1055
  if (error instanceof TuckError) {
889
- console.error(chalk7.red("x"), error.message);
1056
+ console.error(chalk2.red("x"), error.message);
890
1057
  if (error.suggestions && error.suggestions.length > 0) {
891
1058
  console.error();
892
- console.error(chalk7.dim("Suggestions:"));
893
- error.suggestions.forEach((s) => console.error(chalk7.dim(` \u2192 ${s}`)));
1059
+ console.error(chalk2.dim("Suggestions:"));
1060
+ error.suggestions.forEach((s) => console.error(chalk2.dim(` \u2192 ${s}`)));
894
1061
  }
895
1062
  process.exit(1);
896
1063
  }
897
1064
  if (error instanceof Error) {
898
- console.error(chalk7.red("x"), "An unexpected error occurred:", error.message);
1065
+ console.error(chalk2.red("x"), "An unexpected error occurred:", error.message);
899
1066
  if (process.env.DEBUG) {
900
1067
  console.error(error.stack);
901
1068
  }
902
1069
  process.exit(1);
903
1070
  }
904
- console.error(chalk7.red("x"), "An unknown error occurred");
1071
+ console.error(chalk2.red("x"), "An unknown error occurred");
905
1072
  process.exit(1);
906
1073
  };
907
1074
  }
@@ -3191,8 +3358,8 @@ var init_files = __esm({
3191
3358
  });
3192
3359
 
3193
3360
  // src/lib/fileTracking.ts
3194
- import chalk8 from "chalk";
3195
- import ora3 from "ora";
3361
+ import chalk3 from "chalk";
3362
+ import ora from "ora";
3196
3363
  import { ensureDir as ensureDir2 } from "fs-extra";
3197
3364
  import { dirname as dirname4 } from "path";
3198
3365
  var SENSITIVE_FILE_PATTERNS, isSensitiveFile, trackFilesWithProgress;
@@ -3249,19 +3416,19 @@ var init_fileTracking = __esm({
3249
3416
  const sensitiveFiles = [];
3250
3417
  let succeeded = 0;
3251
3418
  console.log();
3252
- console.log(chalk8.bold.cyan(`${actionVerb} ${total} ${total === 1 ? "file" : "files"}...`));
3253
- console.log(chalk8.dim("\u2500".repeat(50)));
3419
+ console.log(chalk3.bold.cyan(`${actionVerb} ${total} ${total === 1 ? "file" : "files"}...`));
3420
+ console.log(chalk3.dim("\u2500".repeat(50)));
3254
3421
  console.log();
3255
3422
  for (let i = 0; i < files.length; i++) {
3256
3423
  const file = files[i];
3257
3424
  const expandedPath = expandPath(file.path);
3258
- const indexStr = chalk8.dim(`[${i + 1}/${total}]`);
3425
+ const indexStr = chalk3.dim(`[${i + 1}/${total}]`);
3259
3426
  const category = file.category || detectCategory(expandedPath);
3260
3427
  const filename = sanitizeFilename(expandedPath);
3261
3428
  const categoryInfo = CATEGORIES[category];
3262
3429
  const icon = categoryInfo?.icon || "\u25CB";
3263
- const spinner2 = ora3({
3264
- text: `${indexStr} ${actionVerb} ${chalk8.cyan(collapsePath(file.path))}`,
3430
+ const spinner4 = ora({
3431
+ text: `${indexStr} ${actionVerb} ${chalk3.cyan(collapsePath(file.path))}`,
3265
3432
  color: "cyan",
3266
3433
  spinner: "dots",
3267
3434
  indent: 2
@@ -3291,9 +3458,9 @@ var init_fileTracking = __esm({
3291
3458
  modified: now,
3292
3459
  checksum
3293
3460
  });
3294
- spinner2.stop();
3295
- const categoryStr = showCategory ? chalk8.dim(` ${icon} ${category}`) : "";
3296
- console.log(` ${chalk8.green("\u2713")} ${indexStr} ${collapsePath(file.path)}${categoryStr}`);
3461
+ spinner4.stop();
3462
+ const categoryStr = showCategory ? chalk3.dim(` ${icon} ${category}`) : "";
3463
+ console.log(` ${chalk3.green("\u2713")} ${indexStr} ${collapsePath(file.path)}${categoryStr}`);
3297
3464
  if (isSensitiveFile(collapsePath(file.path))) {
3298
3465
  sensitiveFiles.push(file.path);
3299
3466
  }
@@ -3305,30 +3472,30 @@ var init_fileTracking = __esm({
3305
3472
  await new Promise((resolve2) => setTimeout(resolve2, delayBetween));
3306
3473
  }
3307
3474
  } catch (error) {
3308
- spinner2.stop();
3475
+ spinner4.stop();
3309
3476
  const errorObj = error instanceof Error ? error : new Error(String(error));
3310
3477
  errors.push({ path: file.path, error: errorObj });
3311
- console.log(` ${chalk8.red("\u2717")} ${indexStr} ${collapsePath(file.path)} ${chalk8.red("- failed")}`);
3478
+ console.log(` ${chalk3.red("\u2717")} ${indexStr} ${collapsePath(file.path)} ${chalk3.red("- failed")}`);
3312
3479
  }
3313
3480
  }
3314
3481
  console.log();
3315
3482
  if (succeeded > 0) {
3316
- console.log(chalk8.green("\u2713"), chalk8.bold(`Tracked ${succeeded} ${succeeded === 1 ? "file" : "files"} successfully`));
3483
+ console.log(chalk3.green("\u2713"), chalk3.bold(`Tracked ${succeeded} ${succeeded === 1 ? "file" : "files"} successfully`));
3317
3484
  }
3318
3485
  if (errors.length > 0) {
3319
3486
  console.log();
3320
- console.log(chalk8.red("\u2717"), chalk8.bold(`Failed to track ${errors.length} ${errors.length === 1 ? "file" : "files"}:`));
3487
+ console.log(chalk3.red("\u2717"), chalk3.bold(`Failed to track ${errors.length} ${errors.length === 1 ? "file" : "files"}:`));
3321
3488
  for (const { path, error } of errors) {
3322
- console.log(chalk8.dim(` \u2022 ${collapsePath(path)}: ${error.message}`));
3489
+ console.log(chalk3.dim(` \u2022 ${collapsePath(path)}: ${error.message}`));
3323
3490
  }
3324
3491
  }
3325
3492
  if (sensitiveFiles.length > 0) {
3326
3493
  console.log();
3327
- console.log(chalk8.yellow("\u26A0"), chalk8.yellow("Warning: Some files may contain sensitive data:"));
3494
+ console.log(chalk3.yellow("\u26A0"), chalk3.yellow("Warning: Some files may contain sensitive data:"));
3328
3495
  for (const path of sensitiveFiles) {
3329
- console.log(chalk8.dim(` \u2022 ${collapsePath(path)}`));
3496
+ console.log(chalk3.dim(` \u2022 ${collapsePath(path)}`));
3330
3497
  }
3331
- console.log(chalk8.dim(" Make sure your repository is private!"));
3498
+ console.log(chalk3.dim(" Make sure your repository is private!"));
3332
3499
  }
3333
3500
  return {
3334
3501
  succeeded,
@@ -3385,7 +3552,7 @@ var init_backup = __esm({
3385
3552
  // src/lib/hooks.ts
3386
3553
  import { exec } from "child_process";
3387
3554
  import { promisify as promisify2 } from "util";
3388
- import chalk9 from "chalk";
3555
+ import chalk4 from "chalk";
3389
3556
  var execAsync, runHook, runPreSyncHook, runPostSyncHook, runPreRestoreHook, runPostRestoreHook;
3390
3557
  var init_hooks = __esm({
3391
3558
  "src/lib/hooks.ts"() {
@@ -3405,19 +3572,19 @@ var init_hooks = __esm({
3405
3572
  }
3406
3573
  if (!options?.trustHooks) {
3407
3574
  console.log();
3408
- console.log(chalk9.yellow.bold("WARNING: Hook Execution"));
3409
- console.log(chalk9.dim("\u2500".repeat(50)));
3410
- console.log(chalk9.white(`Hook type: ${chalk9.cyan(hookType)}`));
3411
- console.log(chalk9.white("Command:"));
3412
- console.log(chalk9.red(` ${command}`));
3413
- console.log(chalk9.dim("\u2500".repeat(50)));
3575
+ console.log(chalk4.yellow.bold("WARNING: Hook Execution"));
3576
+ console.log(chalk4.dim("\u2500".repeat(50)));
3577
+ console.log(chalk4.white(`Hook type: ${chalk4.cyan(hookType)}`));
3578
+ console.log(chalk4.white("Command:"));
3579
+ console.log(chalk4.red(` ${command}`));
3580
+ console.log(chalk4.dim("\u2500".repeat(50)));
3414
3581
  console.log(
3415
- chalk9.yellow(
3582
+ chalk4.yellow(
3416
3583
  "SECURITY: Hooks can execute arbitrary commands on your system."
3417
3584
  )
3418
3585
  );
3419
3586
  console.log(
3420
- chalk9.yellow(
3587
+ chalk4.yellow(
3421
3588
  "Only proceed if you trust the source of this configuration."
3422
3589
  )
3423
3590
  );
@@ -3483,13 +3650,13 @@ __export(restore_exports, {
3483
3650
  runRestore: () => runRestore
3484
3651
  });
3485
3652
  import { Command } from "commander";
3486
- import chalk10 from "chalk";
3487
3653
  import { join as join7 } from "path";
3488
3654
  import { chmod, stat as stat4 } from "fs/promises";
3489
3655
  var fixSSHPermissions, fixGPGPermissions, prepareFilesToRestore, restoreFiles, runInteractiveRestore, runRestore, runRestoreCommand, restoreCommand;
3490
3656
  var init_restore = __esm({
3491
3657
  "src/commands/restore.ts"() {
3492
3658
  "use strict";
3659
+ init_theme();
3493
3660
  init_ui();
3494
3661
  init_paths();
3495
3662
  init_manifest();
@@ -3615,14 +3782,16 @@ var init_restore = __esm({
3615
3782
  }
3616
3783
  const fileOptions = files.map((file) => {
3617
3784
  const categoryConfig = CATEGORIES[file.category] || { icon: "\u{1F4C4}" };
3618
- const status = file.existsAtTarget ? chalk10.yellow("(exists, will backup)") : "";
3785
+ const status = file.existsAtTarget ? colors.yellow("(exists, will backup)") : "";
3619
3786
  return {
3620
3787
  value: file.id,
3621
3788
  label: `${categoryConfig.icon} ${file.source} ${status}`,
3622
3789
  hint: file.category
3623
3790
  };
3624
3791
  });
3625
- const selectedIds = await prompts.multiselect("Select files to restore:", fileOptions, { required: true });
3792
+ const selectedIds = await prompts.multiselect("Select files to restore:", fileOptions, {
3793
+ required: true
3794
+ });
3626
3795
  if (selectedIds.length === 0) {
3627
3796
  prompts.cancel("No files selected");
3628
3797
  return;
@@ -3634,7 +3803,7 @@ var init_restore = __esm({
3634
3803
  prompts.log.warning(
3635
3804
  `${existingFiles.length} file${existingFiles.length > 1 ? "s" : ""} will be backed up:`
3636
3805
  );
3637
- existingFiles.forEach((f) => console.log(chalk10.dim(` ${f.source}`)));
3806
+ existingFiles.forEach((f) => console.log(colors.dim(` ${f.source}`)));
3638
3807
  console.log();
3639
3808
  }
3640
3809
  const useSymlink = await prompts.select("Restore method:", [
@@ -4389,7 +4558,7 @@ var init_patterns = __esm({
4389
4558
  low: 3
4390
4559
  };
4391
4560
  const minLevel = severityOrder[minSeverity];
4392
- return ALL_SECRET_PATTERNS.filter((p2) => severityOrder[p2.severity] <= minLevel);
4561
+ return ALL_SECRET_PATTERNS.filter((p4) => severityOrder[p4.severity] <= minLevel);
4393
4562
  };
4394
4563
  createCustomPattern = (id, name, pattern, options) => {
4395
4564
  return {
@@ -4561,7 +4730,7 @@ var init_scanner = __esm({
4561
4730
  }
4562
4731
  if (options.excludePatternIds && options.excludePatternIds.length > 0) {
4563
4732
  const excludeSet = new Set(options.excludePatternIds);
4564
- patterns = patterns.filter((p2) => !excludeSet.has(p2.id));
4733
+ patterns = patterns.filter((p4) => !excludeSet.has(p4.id));
4565
4734
  }
4566
4735
  for (const pattern of patterns) {
4567
4736
  if (Date.now() - scanStartTime > SCAN_TIMEOUT_MS) {
@@ -5094,10 +5263,10 @@ var init_external = __esm({
5094
5263
  "credential"
5095
5264
  ];
5096
5265
  const ruleIdLower = ruleId.toLowerCase();
5097
- if (criticalPatterns.some((p2) => ruleIdLower.includes(p2))) {
5266
+ if (criticalPatterns.some((p4) => ruleIdLower.includes(p4))) {
5098
5267
  return "critical";
5099
5268
  }
5100
- if (highPatterns.some((p2) => ruleIdLower.includes(p2))) {
5269
+ if (highPatterns.some((p4) => ruleIdLower.includes(p4))) {
5101
5270
  return "high";
5102
5271
  }
5103
5272
  return "medium";
@@ -5248,11 +5417,11 @@ var init_secrets = __esm({
5248
5417
  }
5249
5418
  }
5250
5419
  const customPatterns = (security.customPatterns || []).map(
5251
- (p2, i) => createCustomPattern(`config-${i}`, p2.name || `Custom Pattern ${i + 1}`, p2.pattern, {
5252
- severity: p2.severity,
5253
- description: p2.description,
5254
- placeholder: p2.placeholder,
5255
- flags: p2.flags
5420
+ (p4, i) => createCustomPattern(`config-${i}`, p4.name || `Custom Pattern ${i + 1}`, p4.pattern, {
5421
+ severity: p4.severity,
5422
+ description: p4.description,
5423
+ placeholder: p4.placeholder,
5424
+ flags: p4.flags
5256
5425
  })
5257
5426
  );
5258
5427
  return scanFiles(filepaths, {
@@ -5317,7 +5486,6 @@ var init_secrets = __esm({
5317
5486
 
5318
5487
  // src/commands/secrets.ts
5319
5488
  import { Command as Command3 } from "commander";
5320
- import chalk12 from "chalk";
5321
5489
  var runSecretsList, runSecretsSet, runSecretsUnset, runSecretsPath, runScanHistory, runScanFiles, displayScanResults, secretsCommand;
5322
5490
  var init_secrets2 = __esm({
5323
5491
  "src/commands/secrets.ts"() {
@@ -5345,19 +5513,19 @@ var init_secrets2 = __esm({
5345
5513
  return;
5346
5514
  }
5347
5515
  console.log();
5348
- console.log(chalk12.bold.cyan(`Stored Secrets (${secrets.length})`));
5349
- console.log(chalk12.dim("\u2500".repeat(50)));
5516
+ console.log(colors.bold.cyan(`Stored Secrets (${secrets.length})`));
5517
+ console.log(colors.dim("\u2500".repeat(50)));
5350
5518
  console.log();
5351
5519
  for (const secret of secrets) {
5352
- console.log(` ${chalk12.green(secret.name)}`);
5353
- console.log(` ${chalk12.dim("Placeholder:")} ${chalk12.cyan(secret.placeholder)}`);
5520
+ console.log(` ${colors.green(secret.name)}`);
5521
+ console.log(` ${colors.dim("Placeholder:")} ${colors.cyan(secret.placeholder)}`);
5354
5522
  if (secret.description) {
5355
- console.log(` ${chalk12.dim("Type:")} ${secret.description}`);
5523
+ console.log(` ${colors.dim("Type:")} ${secret.description}`);
5356
5524
  }
5357
5525
  if (secret.source) {
5358
- console.log(` ${chalk12.dim("Source:")} ${secret.source}`);
5526
+ console.log(` ${colors.dim("Source:")} ${secret.source}`);
5359
5527
  }
5360
- console.log(` ${chalk12.dim("Added:")} ${new Date(secret.addedAt).toLocaleDateString()}`);
5528
+ console.log(` ${colors.dim("Added:")} ${new Date(secret.addedAt).toLocaleDateString()}`);
5361
5529
  console.log();
5362
5530
  }
5363
5531
  logger.dim(`Secrets file: ${getSecretsPath(tuckDir)}`);
@@ -5418,22 +5586,22 @@ var init_secrets2 = __esm({
5418
5586
  }
5419
5587
  const limit = options.limit ? parseInt(options.limit, 10) : 50;
5420
5588
  prompts.intro("tuck secrets scan-history");
5421
- const spinner2 = prompts.spinner();
5422
- spinner2.start("Scanning git history for secrets...");
5589
+ const spinner4 = prompts.spinner();
5590
+ spinner4.start("Scanning git history for secrets...");
5423
5591
  try {
5424
5592
  const logEntries = await getLog(tuckDir, {
5425
5593
  maxCount: limit,
5426
5594
  since: options.since
5427
5595
  });
5428
5596
  if (logEntries.length === 0) {
5429
- spinner2.stop("No commits found");
5597
+ spinner4.stop("No commits found");
5430
5598
  return;
5431
5599
  }
5432
5600
  let simpleGit2;
5433
5601
  try {
5434
5602
  simpleGit2 = (await import("simple-git")).default;
5435
5603
  } catch (importError) {
5436
- spinner2.stop("Git integration is unavailable (simple-git module could not be loaded).");
5604
+ spinner4.stop("Git integration is unavailable (simple-git module could not be loaded).");
5437
5605
  const errorMsg = importError instanceof Error ? importError.message : String(importError);
5438
5606
  logger.error(`Failed to load simple-git for scan-history: ${errorMsg}`);
5439
5607
  return;
@@ -5443,7 +5611,7 @@ var init_secrets2 = __esm({
5443
5611
  let scannedCommits = 0;
5444
5612
  for (const entry of logEntries) {
5445
5613
  scannedCommits++;
5446
- spinner2.message(`Scanning commit ${scannedCommits}/${logEntries.length}...`);
5614
+ spinner4.message(`Scanning commit ${scannedCommits}/${logEntries.length}...`);
5447
5615
  try {
5448
5616
  const diff = await git.diff([`${entry.hash}^`, entry.hash]);
5449
5617
  if (diff) {
@@ -5478,7 +5646,7 @@ var init_secrets2 = __esm({
5478
5646
  continue;
5479
5647
  }
5480
5648
  }
5481
- spinner2.stop(`Scanned ${scannedCommits} commits`);
5649
+ spinner4.stop(`Scanned ${scannedCommits} commits`);
5482
5650
  if (results.length === 0) {
5483
5651
  console.log();
5484
5652
  logger.success("No secrets found in git history");
@@ -5486,32 +5654,32 @@ var init_secrets2 = __esm({
5486
5654
  return;
5487
5655
  }
5488
5656
  console.log();
5489
- console.log(chalk12.bold.red(`Found potential secrets in ${results.length} commits`));
5490
- console.log(chalk12.dim("\u2500".repeat(60)));
5657
+ console.log(colors.bold.red(`Found potential secrets in ${results.length} commits`));
5658
+ console.log(colors.dim("\u2500".repeat(60)));
5491
5659
  console.log();
5492
5660
  for (const result of results) {
5493
- console.log(chalk12.yellow(`Commit: ${result.commit}`));
5494
- console.log(chalk12.dim(` Author: ${result.author}`));
5495
- console.log(chalk12.dim(` Date: ${result.date}`));
5496
- console.log(chalk12.dim(` Message: ${result.message}`));
5661
+ console.log(colors.yellow(`Commit: ${result.commit}`));
5662
+ console.log(colors.dim(` Author: ${result.author}`));
5663
+ console.log(colors.dim(` Date: ${result.date}`));
5664
+ console.log(colors.dim(` Message: ${result.message}`));
5497
5665
  console.log();
5498
5666
  for (const secret of result.secrets) {
5499
- const severityColor = secret.severity === "critical" ? chalk12.red : secret.severity === "high" ? chalk12.yellow : chalk12.dim;
5667
+ const severityColor = secret.severity === "critical" ? colors.red : secret.severity === "high" ? colors.yellow : colors.dim;
5500
5668
  console.log(` ${severityColor(`[${secret.severity}]`)} ${secret.pattern}`);
5501
- console.log(chalk12.dim(` Value: ${secret.redactedValue}`));
5669
+ console.log(colors.dim(` Value: ${secret.redactedValue}`));
5502
5670
  }
5503
5671
  console.log();
5504
5672
  }
5505
- console.log(chalk12.dim("\u2500".repeat(60)));
5673
+ console.log(colors.dim("\u2500".repeat(60)));
5506
5674
  console.log();
5507
5675
  logger.warning("If these secrets are still valid, rotate them immediately!");
5508
5676
  console.log();
5509
5677
  logger.dim("To remove secrets from git history, consider using:");
5510
5678
  logger.dim(" - git filter-branch");
5511
5679
  logger.dim(" - BFG Repo-Cleaner (https://rtyley.github.io/bfg-repo-cleaner/)");
5512
- prompts.outro(chalk12.red(`${results.length} commits with potential secrets`));
5680
+ prompts.outro(colors.red(`${results.length} commits with potential secrets`));
5513
5681
  } catch (error) {
5514
- spinner2.stop("Scan failed");
5682
+ spinner4.stop("Scan failed");
5515
5683
  throw error;
5516
5684
  }
5517
5685
  };
@@ -5527,7 +5695,7 @@ var init_secrets2 = __esm({
5527
5695
  logger.dim("Usage: tuck secrets scan <file> [files...]");
5528
5696
  return;
5529
5697
  }
5530
- const expandedPaths = paths.map((p2) => expandPath(p2));
5698
+ const expandedPaths = paths.map((p4) => expandPath(p4));
5531
5699
  for (const path of expandedPaths) {
5532
5700
  if (!await pathExists(path)) {
5533
5701
  logger.warning(`File not found: ${path}`);
@@ -5543,10 +5711,10 @@ var init_secrets2 = __esm({
5543
5711
  logger.error("No valid files to scan");
5544
5712
  return;
5545
5713
  }
5546
- const spinner2 = prompts.spinner();
5547
- spinner2.start(`Scanning ${existingPaths.length} file(s)...`);
5714
+ const spinner4 = prompts.spinner();
5715
+ spinner4.start(`Scanning ${existingPaths.length} file(s)...`);
5548
5716
  const summary = await scanForSecrets(existingPaths, tuckDir);
5549
- spinner2.stop("Scan complete");
5717
+ spinner4.stop("Scan complete");
5550
5718
  if (summary.filesWithSecrets === 0) {
5551
5719
  console.log();
5552
5720
  logger.success("No secrets detected");
@@ -5556,28 +5724,34 @@ var init_secrets2 = __esm({
5556
5724
  };
5557
5725
  displayScanResults = (summary) => {
5558
5726
  console.log();
5559
- console.log(chalk12.bold.red(`Found ${summary.totalSecrets} potential secret(s) in ${summary.filesWithSecrets} file(s)`));
5560
- console.log(chalk12.dim("\u2500".repeat(60)));
5727
+ console.log(
5728
+ colors.bold.red(
5729
+ `Found ${summary.totalSecrets} potential secret(s) in ${summary.filesWithSecrets} file(s)`
5730
+ )
5731
+ );
5732
+ console.log(colors.dim("\u2500".repeat(60)));
5561
5733
  console.log();
5562
5734
  if (summary.bySeverity.critical > 0) {
5563
- console.log(chalk12.red(` Critical: ${summary.bySeverity.critical}`));
5735
+ console.log(colors.red(` Critical: ${summary.bySeverity.critical}`));
5564
5736
  }
5565
5737
  if (summary.bySeverity.high > 0) {
5566
- console.log(chalk12.yellow(` High: ${summary.bySeverity.high}`));
5738
+ console.log(colors.yellow(` High: ${summary.bySeverity.high}`));
5567
5739
  }
5568
5740
  if (summary.bySeverity.medium > 0) {
5569
- console.log(chalk12.blue(` Medium: ${summary.bySeverity.medium}`));
5741
+ console.log(colors.blue(` Medium: ${summary.bySeverity.medium}`));
5570
5742
  }
5571
5743
  if (summary.bySeverity.low > 0) {
5572
- console.log(chalk12.dim(` Low: ${summary.bySeverity.low}`));
5744
+ console.log(colors.dim(` Low: ${summary.bySeverity.low}`));
5573
5745
  }
5574
5746
  console.log();
5575
5747
  for (const result of summary.results) {
5576
- console.log(chalk12.cyan(result.collapsedPath));
5748
+ console.log(colors.cyan(result.collapsedPath));
5577
5749
  for (const match of result.matches) {
5578
- const severityColor = match.severity === "critical" ? chalk12.red : match.severity === "high" ? chalk12.yellow : match.severity === "medium" ? chalk12.blue : chalk12.dim;
5579
- console.log(` ${chalk12.dim(`Line ${match.line}:`)} ${severityColor(`[${match.severity}]`)} ${match.patternName}`);
5580
- console.log(chalk12.dim(` ${match.context}`));
5750
+ const severityColor = match.severity === "critical" ? colors.red : match.severity === "high" ? colors.yellow : match.severity === "medium" ? colors.blue : colors.dim;
5751
+ console.log(
5752
+ ` ${colors.dim(`Line ${match.line}:`)} ${severityColor(`[${match.severity}]`)} ${match.patternName}`
5753
+ );
5754
+ console.log(colors.dim(` ${match.context}`));
5581
5755
  }
5582
5756
  console.log();
5583
5757
  }
@@ -5590,9 +5764,7 @@ var init_secrets2 = __esm({
5590
5764
  new Command3("set").description("Set a secret value (prompts securely)").argument("<name>", "Secret name (e.g., GITHUB_TOKEN)").action(runSecretsSet)
5591
5765
  ).addCommand(
5592
5766
  new Command3("unset").description("Remove a secret").argument("<name>", "Secret name to remove").action(runSecretsUnset)
5593
- ).addCommand(
5594
- new Command3("path").description("Show path to secrets file").action(runSecretsPath)
5595
- ).addCommand(
5767
+ ).addCommand(new Command3("path").description("Show path to secrets file").action(runSecretsPath)).addCommand(
5596
5768
  new Command3("scan").description("Scan files for secrets").argument("[paths...]", "Files to scan").action(runScanFiles)
5597
5769
  ).addCommand(
5598
5770
  new Command3("scan-history").description("Scan git history for leaked secrets").option("--since <date>", "Only scan commits after this date (e.g., 2024-01-01)").option("--limit <n>", "Maximum number of commits to scan", "50").action(runScanHistory)
@@ -5607,7 +5779,6 @@ __export(sync_exports, {
5607
5779
  syncCommand: () => syncCommand
5608
5780
  });
5609
5781
  import { Command as Command4 } from "commander";
5610
- import chalk13 from "chalk";
5611
5782
  import { join as join12 } from "path";
5612
5783
  var detectChanges, pullIfBehind, detectNewDotfiles, generateCommitMessage, syncFiles, scanAndHandleSecrets, runInteractiveSync, pushWithSpinner, runSync, runSyncCommand, syncCommand;
5613
5784
  var init_sync = __esm({
@@ -5720,7 +5891,9 @@ var init_sync = __esm({
5720
5891
  changes.push(`\u2022 ${file}`);
5721
5892
  });
5722
5893
  } else {
5723
- changes.push(`${result.modified.length > 0 ? "\n" : ""}Deleted: ${result.deleted.length} files`);
5894
+ changes.push(
5895
+ `${result.modified.length > 0 ? "\n" : ""}Deleted: ${result.deleted.length} files`
5896
+ );
5724
5897
  }
5725
5898
  }
5726
5899
  if (changes.length > 0) {
@@ -5794,14 +5967,14 @@ var init_sync = __esm({
5794
5967
  if (!scanningEnabled) {
5795
5968
  return true;
5796
5969
  }
5797
- const modifiedPaths = changes.filter((c) => c.status === "modified").map((c) => expandPath(c.source));
5970
+ const modifiedPaths = changes.filter((c2) => c2.status === "modified").map((c2) => expandPath(c2.source));
5798
5971
  if (modifiedPaths.length === 0) {
5799
5972
  return true;
5800
5973
  }
5801
- const spinner2 = prompts.spinner();
5802
- spinner2.start("Scanning for secrets...");
5974
+ const spinner4 = prompts.spinner();
5975
+ spinner4.start("Scanning for secrets...");
5803
5976
  const summary = await scanForSecrets(modifiedPaths, tuckDir);
5804
- spinner2.stop("Scan complete");
5977
+ spinner4.stop("Scan complete");
5805
5978
  if (summary.totalSecrets === 0) {
5806
5979
  return true;
5807
5980
  }
@@ -5817,14 +5990,18 @@ var init_sync = __esm({
5817
5990
  }
5818
5991
  if (action === "ignore") {
5819
5992
  for (const result of summary.results) {
5820
- const sourcePath = changes.find((c) => expandPath(c.source) === result.path)?.source;
5993
+ const sourcePath = changes.find((c2) => expandPath(c2.source) === result.path)?.source;
5821
5994
  if (sourcePath) {
5822
5995
  await addToTuckignore(tuckDir, sourcePath);
5823
5996
  logger.dim(`Added ${collapsePath(result.path)} to .tuckignore`);
5824
5997
  }
5825
5998
  }
5826
5999
  const filesToRemove = new Set(summary.results.map((r) => r.path));
5827
- changes.splice(0, changes.length, ...changes.filter((c) => !filesToRemove.has(expandPath(c.source))));
6000
+ changes.splice(
6001
+ 0,
6002
+ changes.length,
6003
+ ...changes.filter((c2) => !filesToRemove.has(expandPath(c2.source)))
6004
+ );
5828
6005
  if (changes.length === 0) {
5829
6006
  prompts.log.info("No remaining changes to sync");
5830
6007
  return false;
@@ -5844,7 +6021,9 @@ var init_sync = __esm({
5844
6021
  pullSpinner.stop(`Could not pull: ${pullResult.error}`);
5845
6022
  prompts.log.warning("Continuing with local changes...");
5846
6023
  } else if (pullResult.pulled) {
5847
- pullSpinner.stop(`Pulled ${pullResult.behind} commit${pullResult.behind > 1 ? "s" : ""} from remote`);
6024
+ pullSpinner.stop(
6025
+ `Pulled ${pullResult.behind} commit${pullResult.behind > 1 ? "s" : ""} from remote`
6026
+ );
5848
6027
  } else {
5849
6028
  pullSpinner.stop("Up to date with remote");
5850
6029
  }
@@ -5889,19 +6068,19 @@ var init_sync = __esm({
5889
6068
  }
5890
6069
  if (changes.length > 0) {
5891
6070
  console.log();
5892
- console.log(chalk13.bold("Changes to tracked files:"));
6071
+ console.log(colors.bold("Changes to tracked files:"));
5893
6072
  for (const change of changes) {
5894
6073
  if (change.status === "modified") {
5895
- console.log(chalk13.yellow(` ~ ${change.path}`));
6074
+ console.log(colors.yellow(` ~ ${change.path}`));
5896
6075
  } else if (change.status === "deleted") {
5897
- console.log(chalk13.red(` - ${change.path}`));
6076
+ console.log(colors.red(` - ${change.path}`));
5898
6077
  }
5899
6078
  }
5900
6079
  }
5901
6080
  let filesToTrack = [];
5902
6081
  if (newFiles.length > 0) {
5903
6082
  console.log();
5904
- console.log(chalk13.bold(`New dotfiles found (${newFiles.length}):`));
6083
+ console.log(colors.bold(`New dotfiles found (${newFiles.length}):`));
5905
6084
  const grouped = {};
5906
6085
  for (const file of newFiles) {
5907
6086
  if (!grouped[file.category]) grouped[file.category] = [];
@@ -5909,23 +6088,28 @@ var init_sync = __esm({
5909
6088
  }
5910
6089
  for (const [category, files] of Object.entries(grouped)) {
5911
6090
  const categoryInfo = DETECTION_CATEGORIES[category] || { icon: "-", name: category };
5912
- console.log(chalk13.cyan(` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? "s" : ""}`));
6091
+ console.log(
6092
+ colors.cyan(
6093
+ ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? "s" : ""}`
6094
+ )
6095
+ );
5913
6096
  }
5914
6097
  console.log();
5915
- const trackNewFiles = await prompts.confirm("Would you like to track some of these new files?", true);
6098
+ const trackNewFiles = await prompts.confirm(
6099
+ "Would you like to track some of these new files?",
6100
+ true
6101
+ );
5916
6102
  if (trackNewFiles) {
5917
6103
  const selectOptions = newFiles.map((f) => ({
5918
6104
  value: f.path,
5919
- label: `${collapsePath(expandPath(f.path))}${f.sensitive ? chalk13.yellow(" [sensitive]") : ""}`,
6105
+ label: `${collapsePath(expandPath(f.path))}${f.sensitive ? colors.yellow(" [sensitive]") : ""}`,
5920
6106
  hint: f.category
5921
6107
  }));
5922
6108
  const nonSensitiveFiles = newFiles.filter((f) => !f.sensitive);
5923
6109
  const initialValues = nonSensitiveFiles.map((f) => f.path);
5924
- const selected = await prompts.multiselect(
5925
- "Select files to track:",
5926
- selectOptions,
5927
- { initialValues }
5928
- );
6110
+ const selected = await prompts.multiselect("Select files to track:", selectOptions, {
6111
+ initialValues
6112
+ });
5929
6113
  filesToTrack = selected.map((path) => ({ path }));
5930
6114
  }
5931
6115
  }
@@ -5945,12 +6129,12 @@ var init_sync = __esm({
5945
6129
  }
5946
6130
  if (largeFiles.length > 0) {
5947
6131
  console.log();
5948
- console.log(chalk13.yellow("Large files detected:"));
6132
+ console.log(colors.yellow("Large files detected:"));
5949
6133
  for (const file of largeFiles) {
5950
- console.log(chalk13.yellow(` ${file.path} (${file.size})`));
6134
+ console.log(colors.yellow(` ${file.path} (${file.size})`));
5951
6135
  }
5952
6136
  console.log();
5953
- console.log(chalk13.dim("GitHub has a 50MB warning and 100MB hard limit."));
6137
+ console.log(colors.dim("GitHub has a 50MB warning and 100MB hard limit."));
5954
6138
  console.log();
5955
6139
  const hasBlockers = largeFiles.some((f) => f.sizeBytes >= SIZE_BLOCK_THRESHOLD);
5956
6140
  if (hasBlockers) {
@@ -5961,10 +6145,10 @@ var init_sync = __esm({
5961
6145
  ]);
5962
6146
  if (action === "ignore") {
5963
6147
  for (const file of largeFiles) {
5964
- const fullPath = changes.find((c) => c.path === file.path)?.source;
6148
+ const fullPath = changes.find((c2) => c2.path === file.path)?.source;
5965
6149
  if (fullPath) {
5966
6150
  await addToTuckignore(tuckDir, fullPath);
5967
- const index = changes.findIndex((c) => c.path === file.path);
6151
+ const index = changes.findIndex((c2) => c2.path === file.path);
5968
6152
  if (index > -1) changes.splice(index, 1);
5969
6153
  }
5970
6154
  }
@@ -5985,10 +6169,10 @@ var init_sync = __esm({
5985
6169
  ]);
5986
6170
  if (action === "ignore") {
5987
6171
  for (const file of largeFiles) {
5988
- const fullPath = changes.find((c) => c.path === file.path)?.source;
6172
+ const fullPath = changes.find((c2) => c2.path === file.path)?.source;
5989
6173
  if (fullPath) {
5990
6174
  await addToTuckignore(tuckDir, fullPath);
5991
- const index = changes.findIndex((c) => c.path === file.path);
6175
+ const index = changes.findIndex((c2) => c2.path === file.path);
5992
6176
  if (index > -1) changes.splice(index, 1);
5993
6177
  }
5994
6178
  }
@@ -6013,12 +6197,16 @@ var init_sync = __esm({
6013
6197
  let result = { modified: [], deleted: [] };
6014
6198
  if (changes.length > 0) {
6015
6199
  const message = options.message || generateCommitMessage({
6016
- modified: changes.filter((c) => c.status === "modified").map((c) => c.path),
6017
- deleted: changes.filter((c) => c.status === "deleted").map((c) => c.path)
6200
+ modified: changes.filter((c2) => c2.status === "modified").map((c2) => c2.path),
6201
+ deleted: changes.filter((c2) => c2.status === "deleted").map((c2) => c2.path)
6018
6202
  });
6019
6203
  console.log();
6020
- console.log(chalk13.dim("Commit message:"));
6021
- console.log(chalk13.cyan(message.split("\n").map((line) => ` ${line}`).join("\n")));
6204
+ console.log(colors.dim("Commit message:"));
6205
+ console.log(
6206
+ colors.cyan(
6207
+ message.split("\n").map((line) => ` ${line}`).join("\n")
6208
+ )
6209
+ );
6022
6210
  console.log();
6023
6211
  result = await syncFiles(tuckDir, changes, { ...options, message });
6024
6212
  } else if (filesToTrack.length > 0) {
@@ -6043,21 +6231,21 @@ var init_sync = __esm({
6043
6231
  }
6044
6232
  };
6045
6233
  pushWithSpinner = async (tuckDir, _options) => {
6046
- const spinner2 = prompts.spinner();
6234
+ const spinner4 = prompts.spinner();
6047
6235
  try {
6048
6236
  const status = await getStatus(tuckDir);
6049
6237
  const needsUpstream = !status.tracking;
6050
6238
  const branch = status.branch;
6051
- spinner2.start("Pushing to remote...");
6239
+ spinner4.start("Pushing to remote...");
6052
6240
  await push(tuckDir, {
6053
6241
  setUpstream: needsUpstream,
6054
6242
  branch: needsUpstream ? branch : void 0
6055
6243
  });
6056
- spinner2.stop("Pushed to remote");
6244
+ spinner4.stop("Pushed to remote");
6057
6245
  return true;
6058
6246
  } catch (error) {
6059
6247
  const errorMsg = error instanceof Error ? error.message : String(error);
6060
- spinner2.stop(`Push failed: ${errorMsg}`);
6248
+ spinner4.stop(`Push failed: ${errorMsg}`);
6061
6249
  prompts.log.warning("Run 'tuck push' to try again");
6062
6250
  return false;
6063
6251
  }
@@ -6090,7 +6278,7 @@ var init_sync = __esm({
6090
6278
  if (!options.force) {
6091
6279
  const scanningEnabled = await isSecretScanningEnabled(tuckDir);
6092
6280
  if (scanningEnabled) {
6093
- const modifiedPaths = changes.filter((c) => c.status === "modified").map((c) => expandPath(c.source));
6281
+ const modifiedPaths = changes.filter((c2) => c2.status === "modified").map((c2) => expandPath(c2.source));
6094
6282
  if (modifiedPaths.length > 0) {
6095
6283
  const summary = await scanForSecrets(modifiedPaths, tuckDir);
6096
6284
  if (summary.totalSecrets > 0) {
@@ -6124,7 +6312,9 @@ var init_sync = __esm({
6124
6312
  }
6125
6313
  }
6126
6314
  };
6127
- syncCommand = new Command4("sync").description("Sync all dotfile changes (pull, detect changes, scan for new files, track, commit, push)").argument("[message]", "Commit message").option("-m, --message <msg>", "Commit message").option("--no-commit", "Stage changes but don't commit").option("--no-push", "Commit but don't push to remote").option("--no-pull", "Don't pull from remote first").option("--no-scan", "Don't scan for new dotfiles").option("--no-hooks", "Skip execution of pre/post sync hooks").option("--trust-hooks", "Trust and run hooks without confirmation (use with caution)").option("-f, --force", "Skip secret scanning (not recommended)").action(async (messageArg, options) => {
6315
+ syncCommand = new Command4("sync").description(
6316
+ "Sync all dotfile changes (pull, detect changes, scan for new files, track, commit, push)"
6317
+ ).argument("[message]", "Commit message").option("-m, --message <msg>", "Commit message").option("--no-commit", "Stage changes but don't commit").option("--no-push", "Commit but don't push to remote").option("--no-pull", "Don't pull from remote first").option("--no-scan", "Don't scan for new dotfiles").option("--no-hooks", "Skip execution of pre/post sync hooks").option("--trust-hooks", "Trust and run hooks without confirmation (use with caution)").option("-f, --force", "Skip secret scanning (not recommended)").action(async (messageArg, options) => {
6128
6318
  await runSyncCommand(messageArg, options);
6129
6319
  });
6130
6320
  }
@@ -6132,7 +6322,7 @@ var init_sync = __esm({
6132
6322
 
6133
6323
  // src/index.ts
6134
6324
  import { Command as Command16 } from "commander";
6135
- import chalk24 from "chalk";
6325
+ import chalk5 from "chalk";
6136
6326
 
6137
6327
  // src/commands/init.ts
6138
6328
  init_ui();
@@ -6150,7 +6340,6 @@ import { Command as Command2 } from "commander";
6150
6340
  import { join as join8 } from "path";
6151
6341
  import { writeFile as writeFile3 } from "fs/promises";
6152
6342
  import { ensureDir as ensureDir4 } from "fs-extra";
6153
- import chalk11 from "chalk";
6154
6343
  import { copy as copy3 } from "fs-extra";
6155
6344
  import { tmpdir } from "os";
6156
6345
  import { readFile as readFile4, rm as rm2 } from "fs/promises";
@@ -6325,7 +6514,7 @@ var setupAlternativeAuth = async (tuckDir) => {
6325
6514
  const diagnosis = await diagnoseAuthIssue();
6326
6515
  prompts.log.warning(diagnosis.issue);
6327
6516
  for (const suggestion of diagnosis.suggestions) {
6328
- console.log(chalk11.dim(` ${suggestion}`));
6517
+ console.log(colors.muted(` ${suggestion}`));
6329
6518
  }
6330
6519
  console.log();
6331
6520
  }
@@ -6395,7 +6584,7 @@ var setupAlternativeAuth = async (tuckDir) => {
6395
6584
  if (sshInfo.publicKey) {
6396
6585
  console.log();
6397
6586
  prompts.log.info("Your public key (copy this to GitHub):");
6398
- console.log(chalk11.cyan(sshInfo.publicKey));
6587
+ console.log(colors.brand(sshInfo.publicKey));
6399
6588
  console.log();
6400
6589
  }
6401
6590
  }
@@ -6420,7 +6609,10 @@ var setupAlternativeAuth = async (tuckDir) => {
6420
6609
  return { remoteUrl: null, pushed: false };
6421
6610
  }
6422
6611
  if (authMethod === "fine-grained" || authMethod === "classic") {
6423
- return await setupTokenAuth(tuckDir, authMethod === "fine-grained" ? "fine-grained" : "classic");
6612
+ return await setupTokenAuth(
6613
+ tuckDir,
6614
+ authMethod === "fine-grained" ? "fine-grained" : "classic"
6615
+ );
6424
6616
  }
6425
6617
  return { remoteUrl: null, pushed: false };
6426
6618
  };
@@ -6481,7 +6673,9 @@ var setupTokenAuth = async (tuckDir, preferredType) => {
6481
6673
  const detectedType = detectTokenType(token);
6482
6674
  const finalType = detectedType !== "unknown" ? detectedType : tokenType;
6483
6675
  if (detectedType !== "unknown" && detectedType !== tokenType) {
6484
- prompts.log.info(`Detected ${detectedType === "fine-grained" ? "fine-grained" : "classic"} token`);
6676
+ prompts.log.info(
6677
+ `Detected ${detectedType === "fine-grained" ? "fine-grained" : "classic"} token`
6678
+ );
6485
6679
  }
6486
6680
  const storeSpinner = prompts.spinner();
6487
6681
  storeSpinner.start("Storing credentials securely...");
@@ -6491,7 +6685,9 @@ var setupTokenAuth = async (tuckDir, preferredType) => {
6491
6685
  prompts.log.success("Authentication configured successfully");
6492
6686
  } catch (error) {
6493
6687
  storeSpinner.stop("Failed to store credentials");
6494
- prompts.log.warning(`Could not store credentials: ${error instanceof Error ? error.message : String(error)}`);
6688
+ prompts.log.warning(
6689
+ `Could not store credentials: ${error instanceof Error ? error.message : String(error)}`
6690
+ );
6495
6691
  prompts.log.info("You may be prompted for credentials when pushing");
6496
6692
  }
6497
6693
  await configureGitCredentialHelper().catch((error) => {
@@ -6530,7 +6726,9 @@ var promptForManualRepoUrl = async (tuckDir, username, preferredProtocol = "http
6530
6726
  prompts.log.success("Remote configured");
6531
6727
  return { remoteUrl: repoUrl, pushed: false };
6532
6728
  } catch (error) {
6533
- prompts.log.error(`Failed to add remote: ${error instanceof Error ? error.message : String(error)}`);
6729
+ prompts.log.error(
6730
+ `Failed to add remote: ${error instanceof Error ? error.message : String(error)}`
6731
+ );
6534
6732
  return { remoteUrl: null, pushed: false };
6535
6733
  }
6536
6734
  };
@@ -6576,7 +6774,9 @@ var setupGitHubRepo = async (tuckDir) => {
6576
6774
  return await setupAlternativeAuth(tuckDir);
6577
6775
  }
6578
6776
  } catch (error) {
6579
- prompts.log.warning(`Authentication failed: ${error instanceof Error ? error.message : String(error)}`);
6777
+ prompts.log.warning(
6778
+ `Authentication failed: ${error instanceof Error ? error.message : String(error)}`
6779
+ );
6580
6780
  const useAlt = await prompts.confirm("Try alternative authentication?", true);
6581
6781
  if (useAlt) {
6582
6782
  return await setupAlternativeAuth(tuckDir);
@@ -6607,16 +6807,18 @@ var setupGitHubRepo = async (tuckDir) => {
6607
6807
  ]);
6608
6808
  let repo;
6609
6809
  try {
6610
- const spinner2 = prompts.spinner();
6611
- spinner2.start(`Creating repository ${user.login}/${repoName}...`);
6810
+ const spinner4 = prompts.spinner();
6811
+ spinner4.start(`Creating repository ${user.login}/${repoName}...`);
6612
6812
  repo = await createRepo({
6613
6813
  name: repoName,
6614
6814
  description: "My dotfiles managed with tuck",
6615
6815
  isPrivate: visibility === "private"
6616
6816
  });
6617
- spinner2.stop(`Repository created: ${repo.fullName}`);
6817
+ spinner4.stop(`Repository created: ${repo.fullName}`);
6618
6818
  } catch (error) {
6619
- prompts.log.error(`Failed to create repository: ${error instanceof Error ? error.message : String(error)}`);
6819
+ prompts.log.error(
6820
+ `Failed to create repository: ${error instanceof Error ? error.message : String(error)}`
6821
+ );
6620
6822
  return { remoteUrl: null, pushed: false };
6621
6823
  }
6622
6824
  const remoteUrl = await getPreferredRepoUrl(repo);
@@ -6625,14 +6827,14 @@ var setupGitHubRepo = async (tuckDir) => {
6625
6827
  const shouldPush = await prompts.confirm("Push initial commit to GitHub?", true);
6626
6828
  if (shouldPush) {
6627
6829
  try {
6628
- const spinner2 = prompts.spinner();
6629
- spinner2.start("Creating initial commit...");
6830
+ const spinner4 = prompts.spinner();
6831
+ spinner4.start("Creating initial commit...");
6630
6832
  await stageAll(tuckDir);
6631
6833
  await commit(tuckDir, "Initial commit: tuck dotfiles setup");
6632
- spinner2.stop("Initial commit created");
6633
- spinner2.start("Pushing to GitHub...");
6834
+ spinner4.stop("Initial commit created");
6835
+ spinner4.start("Pushing to GitHub...");
6634
6836
  await push(tuckDir, { remote: "origin", branch: "main", setUpstream: true });
6635
- spinner2.stop("Pushed to GitHub");
6837
+ spinner4.stop("Pushed to GitHub");
6636
6838
  prompts.note(
6637
6839
  `Your dotfiles are now at:
6638
6840
  ${repo.url}
@@ -6643,7 +6845,9 @@ tuck apply ${user.login}`,
6643
6845
  );
6644
6846
  return { remoteUrl, pushed: true };
6645
6847
  } catch (error) {
6646
- prompts.log.error(`Failed to push: ${error instanceof Error ? error.message : String(error)}`);
6848
+ prompts.log.error(
6849
+ `Failed to push: ${error instanceof Error ? error.message : String(error)}`
6850
+ );
6647
6851
  return { remoteUrl, pushed: false };
6648
6852
  }
6649
6853
  }
@@ -6685,7 +6889,9 @@ var analyzeRepository = async (repoDir) => {
6685
6889
  const categories = await readdir5(filesDir);
6686
6890
  for (const category of categories) {
6687
6891
  const categoryPath = join8(filesDir, category);
6688
- const categoryStats = await import("fs/promises").then((fs) => fs.stat(categoryPath).catch(() => null));
6892
+ const categoryStats = await import("fs/promises").then(
6893
+ (fs) => fs.stat(categoryPath).catch(() => null)
6894
+ );
6689
6895
  if (categoryStats?.isDirectory()) {
6690
6896
  const files = await readdir5(categoryPath);
6691
6897
  foundFiles.push(...files);
@@ -6698,7 +6904,7 @@ var analyzeRepository = async (repoDir) => {
6698
6904
  try {
6699
6905
  const rootFiles = await readdir4(repoDir);
6700
6906
  for (const file of rootFiles) {
6701
- if (commonPatterns.some((p2) => file.includes(p2) || file.startsWith("."))) {
6907
+ if (commonPatterns.some((p4) => file.includes(p4) || file.startsWith("."))) {
6702
6908
  foundFiles.push(file);
6703
6909
  }
6704
6910
  }
@@ -6730,10 +6936,10 @@ var importExistingRepo = async (tuckDir, repoName, analysis, repoDir) => {
6730
6936
  const remoteUrl = protocol === "ssh" ? `git@github.com:${repoName}.git` : `https://github.com/${repoName}.git`;
6731
6937
  if (analysis.type === "valid-tuck") {
6732
6938
  prompts.log.step("Importing tuck repository...");
6733
- const spinner2 = prompts.spinner();
6734
- spinner2.start("Copying repository...");
6939
+ const spinner4 = prompts.spinner();
6940
+ spinner4.start("Copying repository...");
6735
6941
  await copy3(repoDir, tuckDir, { overwrite: true });
6736
- spinner2.stop("Repository imported");
6942
+ spinner4.stop("Repository imported");
6737
6943
  const fileCount = Object.keys(analysis.manifest.files).length;
6738
6944
  const grouped = {};
6739
6945
  for (const [_id, file] of Object.entries(analysis.manifest.files)) {
@@ -6746,7 +6952,11 @@ var importExistingRepo = async (tuckDir, repoName, analysis, repoDir) => {
6746
6952
  const { DETECTION_CATEGORIES: DETECTION_CATEGORIES2 } = await Promise.resolve().then(() => (init_detect(), detect_exports));
6747
6953
  for (const [category, files] of Object.entries(grouped)) {
6748
6954
  const categoryInfo = DETECTION_CATEGORIES2[category] || { icon: "-", name: category };
6749
- console.log(chalk11.cyan(` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? "s" : ""}`));
6955
+ console.log(
6956
+ colors.brand(
6957
+ ` ${categoryInfo.icon} ${categoryInfo.name}: ${files.length} file${files.length > 1 ? "s" : ""}`
6958
+ )
6959
+ );
6750
6960
  }
6751
6961
  console.log();
6752
6962
  prompts.note(
@@ -6814,7 +7024,8 @@ var importExistingRepo = async (tuckDir, repoName, analysis, repoDir) => {
6814
7024
  let count = 0;
6815
7025
  const entries = await readdir4(dir);
6816
7026
  for (const entry of entries) {
6817
- if (entry === ".git" || entry === ".tuckmanifest.json" || entry === ".tuckrc.json") continue;
7027
+ if (entry === ".git" || entry === ".tuckmanifest.json" || entry === ".tuckrc.json")
7028
+ continue;
6818
7029
  const fullPath = join8(dir, entry);
6819
7030
  const stats = await stat11(fullPath).catch(() => null);
6820
7031
  if (stats?.isDirectory()) {
@@ -6868,7 +7079,9 @@ var importExistingRepo = async (tuckDir, repoName, analysis, repoDir) => {
6868
7079
  await addRemote(tuckDir, "origin", remoteUrl);
6869
7080
  if (action === "fresh") {
6870
7081
  prompts.log.info("Tuck initialized. When you push, it will replace the repository contents.");
6871
- prompts.log.info("Run 'tuck add' to track files, then 'tuck sync && tuck push --force' to update remote");
7082
+ prompts.log.info(
7083
+ "Run 'tuck add' to track files, then 'tuck sync && tuck push --force' to update remote"
7084
+ );
6872
7085
  } else {
6873
7086
  prompts.log.info("Tuck initialized with remote configured");
6874
7087
  prompts.log.info("Run 'tuck add' to start tracking files");
@@ -6913,17 +7126,14 @@ var runInteractiveInit = async () => {
6913
7126
  const ghInstalled = await isGhInstalled();
6914
7127
  const ghAuth = ghInstalled && await isGhAuthenticated();
6915
7128
  if (ghAuth) {
6916
- const spinner2 = prompts.spinner();
6917
- spinner2.start("Checking for existing dotfiles repository on GitHub...");
7129
+ const spinner4 = prompts.spinner();
7130
+ spinner4.start("Checking for existing dotfiles repository on GitHub...");
6918
7131
  try {
6919
7132
  const user = await getAuthenticatedUser();
6920
7133
  const existingRepoName = await findDotfilesRepo(user.login);
6921
7134
  if (existingRepoName) {
6922
- spinner2.stop(`Found repository: ${existingRepoName}`);
6923
- const importRepo = await prompts.confirm(
6924
- `Import dotfiles from ${existingRepoName}?`,
6925
- true
6926
- );
7135
+ spinner4.stop(`Found repository: ${existingRepoName}`);
7136
+ const importRepo = await prompts.confirm(`Import dotfiles from ${existingRepoName}?`, true);
6927
7137
  if (importRepo) {
6928
7138
  const tempDir = join8(tmpdir(), `tuck-import-${Date.now()}`);
6929
7139
  const cloneSpinner = prompts.spinner();
@@ -6954,7 +7164,9 @@ var runInteractiveInit = async () => {
6954
7164
  if (result.filesApplied > 0) {
6955
7165
  prompts.log.info(`Applied ${result.filesApplied} files to your system`);
6956
7166
  } else if (result.filesInRepo > 0) {
6957
- prompts.log.info('Files are ready in ~/.tuck. Run "tuck restore" to apply them to your system');
7167
+ prompts.log.info(
7168
+ 'Files are ready in ~/.tuck. Run "tuck restore" to apply them to your system'
7169
+ );
6958
7170
  }
6959
7171
  } else {
6960
7172
  prompts.log.success(`Tuck initialized with ${existingRepoName} as remote`);
@@ -6978,9 +7190,7 @@ var runInteractiveInit = async () => {
6978
7190
  } else if (phase === "importing") {
6979
7191
  prompts.log.warning(errorMessage);
6980
7192
  } else {
6981
- prompts.log.warning(
6982
- `Could not clone repository: ${errorMessage}`
6983
- );
7193
+ prompts.log.warning(`Could not clone repository: ${errorMessage}`);
6984
7194
  }
6985
7195
  console.log();
6986
7196
  const useAsRemoteAnyway = await prompts.confirm(
@@ -7014,10 +7224,10 @@ var runInteractiveInit = async () => {
7014
7224
  skipExistingRepoQuestion = true;
7015
7225
  }
7016
7226
  } else {
7017
- spinner2.stop("No existing dotfiles repository found");
7227
+ spinner4.stop("No existing dotfiles repository found");
7018
7228
  }
7019
7229
  } catch {
7020
- spinner2.stop("Could not check for existing repositories");
7230
+ spinner4.stop("Could not check for existing repositories");
7021
7231
  }
7022
7232
  }
7023
7233
  if (!skipExistingRepoQuestion) {
@@ -7057,7 +7267,10 @@ var runInteractiveInit = async () => {
7057
7267
  console.log();
7058
7268
  }
7059
7269
  if (!remoteUrl) {
7060
- const wantsRemote = await prompts.confirm("Would you like to set up a remote repository?", true);
7270
+ const wantsRemote = await prompts.confirm(
7271
+ "Would you like to set up a remote repository?",
7272
+ true
7273
+ );
7061
7274
  if (wantsRemote) {
7062
7275
  const ghResult = await setupGitHubRepo(tuckDir);
7063
7276
  remoteUrl = ghResult.remoteUrl;
@@ -7147,7 +7360,7 @@ Example URLs:
7147
7360
  console.log();
7148
7361
  prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);
7149
7362
  for (const sf of sensitiveFiles) {
7150
- console.log(chalk11.yellow(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));
7363
+ console.log(colors.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));
7151
7364
  }
7152
7365
  console.log();
7153
7366
  const trackSensitive = await prompts.confirm(
@@ -7156,10 +7369,7 @@ Example URLs:
7156
7369
  );
7157
7370
  if (trackSensitive) {
7158
7371
  for (const sf of sensitiveFiles) {
7159
- const track = await prompts.confirm(
7160
- `Track ${collapsePath(sf.path)}?`,
7161
- false
7162
- );
7372
+ const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);
7163
7373
  if (track) {
7164
7374
  filesToTrack.push(sf.path);
7165
7375
  }
@@ -7177,7 +7387,7 @@ Example URLs:
7177
7387
  console.log();
7178
7388
  prompts.log.warning(`Found ${sensitiveFiles.length} sensitive file(s):`);
7179
7389
  for (const sf of sensitiveFiles) {
7180
- console.log(chalk11.yellow(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));
7390
+ console.log(colors.warning(` ! ${collapsePath(sf.path)} - ${sf.description || sf.category}`));
7181
7391
  }
7182
7392
  console.log();
7183
7393
  const trackSensitive = await prompts.confirm(
@@ -7187,10 +7397,7 @@ Example URLs:
7187
7397
  if (trackSensitive) {
7188
7398
  const filesToTrack = [];
7189
7399
  for (const sf of sensitiveFiles) {
7190
- const track = await prompts.confirm(
7191
- `Track ${collapsePath(sf.path)}?`,
7192
- false
7193
- );
7400
+ const track = await prompts.confirm(`Track ${collapsePath(sf.path)}?`, false);
7194
7401
  if (track) {
7195
7402
  filesToTrack.push(sf.path);
7196
7403
  }
@@ -7320,7 +7527,6 @@ init_constants();
7320
7527
  init_files();
7321
7528
  import { Command as Command5 } from "commander";
7322
7529
  import { basename as basename6 } from "path";
7323
- import chalk14 from "chalk";
7324
7530
 
7325
7531
  // src/lib/binary.ts
7326
7532
  init_paths();
@@ -7533,13 +7739,10 @@ If you need to backup SSH keys, use a secure password manager.`
7533
7739
  logger.warning(
7534
7740
  `File ${path} is ${formatFileSize(sizeCheck.size)} (exceeds GitHub's 100MB limit)`
7535
7741
  );
7536
- const action = await prompts.select(
7537
- "How would you like to proceed?",
7538
- [
7539
- { value: "ignore", label: "Add to .tuckignore and skip" },
7540
- { value: "cancel", label: "Cancel operation" }
7541
- ]
7542
- );
7742
+ const action = await prompts.select("How would you like to proceed?", [
7743
+ { value: "ignore", label: "Add to .tuckignore and skip" },
7744
+ { value: "cancel", label: "Cancel operation" }
7745
+ ]);
7543
7746
  if (action === "ignore") {
7544
7747
  await addToTuckignore(tuckDir, collapsedPath);
7545
7748
  logger.success(`Added ${path} to .tuckignore`);
@@ -7552,14 +7755,11 @@ If you need to backup SSH keys, use a secure password manager.`
7552
7755
  logger.warning(
7553
7756
  `File ${path} is ${formatFileSize(sizeCheck.size)}. GitHub recommends files under 50MB.`
7554
7757
  );
7555
- const action = await prompts.select(
7556
- "How would you like to proceed?",
7557
- [
7558
- { value: "continue", label: "Track it anyway" },
7559
- { value: "ignore", label: "Add to .tuckignore and skip" },
7560
- { value: "cancel", label: "Cancel operation" }
7561
- ]
7562
- );
7758
+ const action = await prompts.select("How would you like to proceed?", [
7759
+ { value: "continue", label: "Track it anyway" },
7760
+ { value: "ignore", label: "Add to .tuckignore and skip" },
7761
+ { value: "cancel", label: "Cancel operation" }
7762
+ ]);
7563
7763
  if (action === "ignore") {
7564
7764
  await addToTuckignore(tuckDir, collapsedPath);
7565
7765
  logger.success(`Added ${path} to .tuckignore`);
@@ -7599,14 +7799,16 @@ var addFiles = async (filesToAdd, tuckDir, options) => {
7599
7799
  };
7600
7800
  var displaySecretWarning = (summary) => {
7601
7801
  console.log();
7602
- console.log(chalk14.bold.red(` Security Warning: Found ${summary.totalSecrets} potential secret(s)`));
7802
+ console.log(
7803
+ colors.error(colors.bold(` Security Warning: Found ${summary.totalSecrets} potential secret(s)`))
7804
+ );
7603
7805
  console.log();
7604
7806
  for (const result of summary.results) {
7605
- console.log(` ${chalk14.cyan(result.collapsedPath)}`);
7807
+ console.log(` ${colors.brand(result.collapsedPath)}`);
7606
7808
  for (const match of result.matches) {
7607
- const severityColor = match.severity === "critical" ? chalk14.red : match.severity === "high" ? chalk14.yellow : match.severity === "medium" ? chalk14.blue : chalk14.dim;
7809
+ const severityColor = match.severity === "critical" ? colors.error : match.severity === "high" ? colors.warning : match.severity === "medium" ? colors.info : colors.muted;
7608
7810
  console.log(
7609
- ` ${chalk14.dim(`Line ${match.line}:`)} ${match.redactedValue} ${severityColor(`[${match.severity}]`)}`
7811
+ ` ${colors.muted(`Line ${match.line}:`)} ${match.redactedValue} ${severityColor(`[${match.severity}]`)}`
7610
7812
  );
7611
7813
  }
7612
7814
  console.log();
@@ -7678,7 +7880,7 @@ var handleSecretsDetected = async (summary, filesToAdd, tuckDir) => {
7678
7880
  }
7679
7881
  case "proceed": {
7680
7882
  const confirmed = await prompts.confirm(
7681
- chalk14.red("Are you SURE you want to track files containing secrets?"),
7883
+ colors.error("Are you SURE you want to track files containing secrets?"),
7682
7884
  false
7683
7885
  );
7684
7886
  if (!confirmed) {
@@ -7908,7 +8110,6 @@ init_manifest();
7908
8110
  init_git();
7909
8111
  init_errors();
7910
8112
  import { Command as Command7 } from "commander";
7911
- import chalk15 from "chalk";
7912
8113
  var runInteractivePush = async (tuckDir) => {
7913
8114
  prompts.intro("tuck push");
7914
8115
  const hasRemoteRepo = await hasRemote(tuckDir);
@@ -7937,13 +8138,13 @@ var runInteractivePush = async (tuckDir) => {
7937
8138
  return;
7938
8139
  }
7939
8140
  console.log();
7940
- console.log(chalk15.dim("Remote:"), remoteUrl);
7941
- console.log(chalk15.dim("Branch:"), branch);
8141
+ console.log(colors.dim("Remote:"), remoteUrl);
8142
+ console.log(colors.dim("Branch:"), branch);
7942
8143
  if (status.ahead > 0) {
7943
- console.log(chalk15.dim("Commits:"), chalk15.green(`\u2191 ${status.ahead} to push`));
8144
+ console.log(colors.dim("Commits:"), colors.green(`\u2191 ${status.ahead} to push`));
7944
8145
  }
7945
8146
  if (status.behind > 0) {
7946
- console.log(chalk15.dim("Warning:"), chalk15.yellow(`\u2193 ${status.behind} commits behind remote`));
8147
+ console.log(colors.dim("Warning:"), colors.yellow(`\u2193 ${status.behind} commits behind remote`));
7947
8148
  const pullFirst = await prompts.confirm("Pull changes first?", true);
7948
8149
  if (pullFirst) {
7949
8150
  prompts.log.info("Run 'tuck pull' first, then push");
@@ -7989,7 +8190,7 @@ var runInteractivePush = async (tuckDir) => {
7989
8190
  viewUrl = remoteUrl.replace("git@github.com:", "https://github.com/").replace(".git", "");
7990
8191
  }
7991
8192
  console.log();
7992
- console.log(chalk15.dim("View at:"), chalk15.cyan(viewUrl));
8193
+ console.log(colors.dim("View at:"), colors.cyan(viewUrl));
7993
8194
  }
7994
8195
  prompts.outro("");
7995
8196
  };
@@ -8042,7 +8243,6 @@ init_manifest();
8042
8243
  init_git();
8043
8244
  init_errors();
8044
8245
  import { Command as Command8 } from "commander";
8045
- import chalk16 from "chalk";
8046
8246
  var runInteractivePull = async (tuckDir) => {
8047
8247
  prompts.intro("tuck pull");
8048
8248
  const hasRemoteRepo = await hasRemote(tuckDir);
@@ -8058,23 +8258,23 @@ var runInteractivePull = async (tuckDir) => {
8058
8258
  const branch = await getCurrentBranch(tuckDir);
8059
8259
  const remoteUrl = await getRemoteUrl(tuckDir);
8060
8260
  console.log();
8061
- console.log(chalk16.dim("Remote:"), remoteUrl);
8062
- console.log(chalk16.dim("Branch:"), branch);
8261
+ console.log(colors.dim("Remote:"), remoteUrl);
8262
+ console.log(colors.dim("Branch:"), branch);
8063
8263
  if (status.behind === 0) {
8064
8264
  prompts.log.success("Already up to date");
8065
8265
  return;
8066
8266
  }
8067
- console.log(chalk16.dim("Commits:"), chalk16.yellow(`\u2193 ${status.behind} to pull`));
8267
+ console.log(colors.dim("Commits:"), colors.yellow(`\u2193 ${status.behind} to pull`));
8068
8268
  if (status.ahead > 0) {
8069
8269
  console.log(
8070
- chalk16.dim("Note:"),
8071
- chalk16.yellow(`You also have ${status.ahead} local commit${status.ahead > 1 ? "s" : ""} to push`)
8270
+ colors.dim("Note:"),
8271
+ colors.yellow(`You also have ${status.ahead} local commit${status.ahead > 1 ? "s" : ""} to push`)
8072
8272
  );
8073
8273
  }
8074
8274
  if (status.modified.length > 0 || status.staged.length > 0) {
8075
8275
  console.log();
8076
8276
  prompts.log.warning("You have uncommitted changes");
8077
- console.log(chalk16.dim("Modified:"), status.modified.join(", "));
8277
+ console.log(colors.dim("Modified:"), status.modified.join(", "));
8078
8278
  const continueAnyway = await prompts.confirm("Pull anyway? (may cause merge conflicts)");
8079
8279
  if (!continueAnyway) {
8080
8280
  prompts.cancel("Commit or stash your changes first with 'tuck sync'");
@@ -8128,6 +8328,7 @@ init_restore();
8128
8328
 
8129
8329
  // src/commands/status.ts
8130
8330
  init_ui();
8331
+ init_prompts();
8131
8332
  init_paths();
8132
8333
  init_manifest();
8133
8334
  init_git();
@@ -8136,8 +8337,9 @@ init_tuckignore();
8136
8337
  init_errors();
8137
8338
  init_constants();
8138
8339
  import { Command as Command9 } from "commander";
8139
- import chalk17 from "chalk";
8140
8340
  import boxen2 from "boxen";
8341
+ import logSymbols5 from "log-symbols";
8342
+ import figures5 from "figures";
8141
8343
  var detectFileChanges = async (tuckDir) => {
8142
8344
  const files = await getAllTrackedFiles(tuckDir);
8143
8345
  const ignoredPaths = await loadTuckignore(tuckDir);
@@ -8217,44 +8419,50 @@ var getFullStatus = async (tuckDir) => {
8217
8419
  }
8218
8420
  };
8219
8421
  };
8422
+ var formatRemoteUrl = (url) => {
8423
+ return url.replace(/^https?:\/\//, "").replace(/\.git$/, "").replace(/^github\.com\//, "");
8424
+ };
8220
8425
  var printStatus = (status) => {
8221
8426
  const headerLines = [
8222
- `${chalk17.bold.cyan("tuck")} ${chalk17.dim(`v${VERSION}`)}`,
8427
+ `${colors.brandBold("tuck")} ${colors.muted(`v${VERSION}`)}`,
8223
8428
  "",
8224
- `${chalk17.dim("Repository:")} ${collapsePath(status.tuckDir)}`,
8225
- `${chalk17.dim("Branch:")} ${chalk17.cyan(status.branch)}`
8429
+ `${colors.muted("Repository:")} ${collapsePath(status.tuckDir)}`,
8430
+ `${colors.muted("Branch:")} ${colors.brand(status.branch)}`
8226
8431
  ];
8227
8432
  if (status.remote) {
8228
- const shortRemote = status.remote.length > 40 ? status.remote.replace(/^https?:\/\//, "").replace(/\.git$/, "") : status.remote;
8229
- headerLines.push(`${chalk17.dim("Remote:")} ${shortRemote}`);
8433
+ headerLines.push(`${colors.muted("Remote:")} ${formatRemoteUrl(status.remote)}`);
8230
8434
  } else {
8231
- headerLines.push(`${chalk17.dim("Remote:")} ${chalk17.yellow("not configured")}`);
8435
+ headerLines.push(`${colors.muted("Remote:")} ${colors.warning("not configured")}`);
8232
8436
  }
8233
- console.log(boxen2(headerLines.join("\n"), {
8234
- padding: { top: 0, bottom: 0, left: 1, right: 1 },
8235
- borderColor: "cyan",
8236
- borderStyle: "round"
8237
- }));
8437
+ console.log(boxen2(headerLines.join("\n"), boxStyles.header));
8238
8438
  if (status.remote) {
8239
- let remoteInfo = "";
8439
+ console.log();
8240
8440
  switch (status.remoteStatus) {
8241
8441
  case "up-to-date":
8242
- remoteInfo = chalk17.green("\u2713 Up to date with remote");
8442
+ console.log(logSymbols5.success, colors.success("Up to date with remote"));
8243
8443
  break;
8244
8444
  case "ahead":
8245
- remoteInfo = chalk17.yellow(`\u2191 ${status.ahead} commit${status.ahead > 1 ? "s" : ""} ahead of remote`);
8445
+ console.log(
8446
+ colors.warning(figures5.arrowUp),
8447
+ colors.warning(`${status.ahead} commit${status.ahead > 1 ? "s" : ""} ahead`)
8448
+ );
8246
8449
  break;
8247
8450
  case "behind":
8248
- remoteInfo = chalk17.yellow(`\u2193 ${status.behind} commit${status.behind > 1 ? "s" : ""} behind remote`);
8451
+ console.log(
8452
+ colors.warning(figures5.arrowDown),
8453
+ colors.warning(`${status.behind} commit${status.behind > 1 ? "s" : ""} behind`)
8454
+ );
8249
8455
  break;
8250
8456
  case "diverged":
8251
- remoteInfo = chalk17.red(`\u26A0 Diverged (${status.ahead} ahead, ${status.behind} behind)`);
8457
+ console.log(
8458
+ logSymbols5.warning,
8459
+ colors.error(`Diverged (${status.ahead} ahead, ${status.behind} behind)`)
8460
+ );
8252
8461
  break;
8253
8462
  }
8254
- console.log("\n" + remoteInfo);
8255
8463
  }
8256
8464
  console.log();
8257
- console.log(chalk17.bold(`Tracked Files: ${status.trackedCount}`));
8465
+ console.log(colors.bold(`${status.trackedCount} files tracked`));
8258
8466
  const categoryOrder = ["shell", "git", "editors", "terminal", "ssh", "misc"];
8259
8467
  const sortedCategories = Object.keys(status.categoryCounts).sort((a, b) => {
8260
8468
  const aIdx = categoryOrder.indexOf(a);
@@ -8265,66 +8473,74 @@ var printStatus = (status) => {
8265
8473
  return aIdx - bIdx;
8266
8474
  });
8267
8475
  if (sortedCategories.length > 0) {
8268
- for (const category of sortedCategories) {
8269
- const count = status.categoryCounts[category];
8270
- console.log(chalk17.dim(` ${category}: ${count} file${count > 1 ? "s" : ""}`));
8271
- }
8476
+ const categoryLine = sortedCategories.map((cat) => {
8477
+ const style = categoryStyles[cat] || categoryStyles.misc;
8478
+ const count = status.categoryCounts[cat];
8479
+ return `${style.color(style.icon)} ${cat}: ${count}`;
8480
+ }).join(" ");
8481
+ console.log(colors.muted(indent() + categoryLine));
8272
8482
  }
8273
8483
  if (status.changes.length > 0) {
8274
8484
  console.log();
8275
- console.log(chalk17.bold("Changes detected:"));
8485
+ console.log(colors.bold("Changes:"));
8276
8486
  for (const change of status.changes) {
8277
8487
  const statusText = formatStatus(change.status);
8278
- console.log(` ${statusText}: ${chalk17.cyan(change.path)}`);
8488
+ console.log(`${indent()}${statusText} ${colors.brand(change.path)}`);
8279
8489
  }
8280
8490
  }
8281
8491
  const hasGitChanges = status.gitChanges.staged.length > 0 || status.gitChanges.modified.length > 0 || status.gitChanges.untracked.length > 0;
8282
8492
  if (hasGitChanges) {
8283
8493
  console.log();
8284
- console.log(chalk17.bold("Repository changes:"));
8494
+ console.log(colors.bold("Repository:"));
8285
8495
  if (status.gitChanges.staged.length > 0) {
8286
- console.log(chalk17.green(" Staged:"));
8287
- status.gitChanges.staged.forEach((f) => console.log(chalk17.green(` + ${f}`)));
8496
+ console.log(colors.success(`${indent()}Staged:`));
8497
+ status.gitChanges.staged.forEach(
8498
+ (f) => console.log(colors.success(`${indent()}${indent()}+ ${f}`))
8499
+ );
8288
8500
  }
8289
8501
  if (status.gitChanges.modified.length > 0) {
8290
- console.log(chalk17.yellow(" Modified:"));
8291
- status.gitChanges.modified.forEach((f) => console.log(chalk17.yellow(` ~ ${f}`)));
8502
+ console.log(colors.warning(`${indent()}Modified:`));
8503
+ status.gitChanges.modified.forEach(
8504
+ (f) => console.log(colors.warning(`${indent()}${indent()}~ ${f}`))
8505
+ );
8292
8506
  }
8293
8507
  if (status.gitChanges.untracked.length > 0) {
8294
- console.log(chalk17.dim(" Untracked:"));
8295
- status.gitChanges.untracked.forEach((f) => console.log(chalk17.dim(` ? ${f}`)));
8508
+ console.log(colors.muted(`${indent()}Untracked:`));
8509
+ status.gitChanges.untracked.forEach(
8510
+ (f) => console.log(colors.muted(`${indent()}${indent()}? ${f}`))
8511
+ );
8296
8512
  }
8297
8513
  }
8298
8514
  console.log();
8299
8515
  if (status.changes.length > 0) {
8300
- prompts.note("Run 'tuck sync' to commit changes", "Next step");
8516
+ prompts.note("Run 'tuck sync' to commit changes", "Next");
8301
8517
  } else if (status.remoteStatus === "ahead") {
8302
- prompts.note("Run 'tuck push' to push changes to remote", "Next step");
8518
+ prompts.note("Run 'tuck push' to push changes", "Next");
8303
8519
  } else if (status.remoteStatus === "behind") {
8304
- prompts.note("Run 'tuck pull' to pull changes from remote", "Next step");
8520
+ prompts.note("Run 'tuck pull' to pull changes", "Next");
8305
8521
  } else if (status.trackedCount === 0) {
8306
- prompts.note("Run 'tuck add <path>' to start tracking files", "Next step");
8522
+ prompts.note("Run 'tuck add <path>' to start tracking", "Next");
8307
8523
  } else {
8308
- prompts.outro("Everything is up to date");
8524
+ prompts.outro("Everything up to date");
8309
8525
  }
8310
8526
  };
8311
8527
  var printShortStatus = (status) => {
8312
8528
  const parts = [];
8313
8529
  parts.push(`[${status.branch}]`);
8314
8530
  if (status.remoteStatus === "ahead") {
8315
- parts.push(`\u2191${status.ahead}`);
8531
+ parts.push(colors.warning(`${figures5.arrowUp}${status.ahead}`));
8316
8532
  } else if (status.remoteStatus === "behind") {
8317
- parts.push(`\u2193${status.behind}`);
8533
+ parts.push(colors.warning(`${figures5.arrowDown}${status.behind}`));
8318
8534
  } else if (status.remoteStatus === "diverged") {
8319
- parts.push(`\u2191${status.ahead}\u2193${status.behind}`);
8535
+ parts.push(colors.error(`${figures5.arrowUp}${status.ahead}${figures5.arrowDown}${status.behind}`));
8320
8536
  }
8321
8537
  if (status.changes.length > 0) {
8322
- const modified = status.changes.filter((c) => c.status === "modified").length;
8323
- const deleted = status.changes.filter((c) => c.status === "deleted").length;
8324
- if (modified > 0) parts.push(`~${modified}`);
8325
- if (deleted > 0) parts.push(`-${deleted}`);
8538
+ const modified = status.changes.filter((ch) => ch.status === "modified").length;
8539
+ const deleted = status.changes.filter((ch) => ch.status === "deleted").length;
8540
+ if (modified > 0) parts.push(colors.warning(`~${modified}`));
8541
+ if (deleted > 0) parts.push(colors.error(`-${deleted}`));
8326
8542
  }
8327
- parts.push(`(${status.trackedCount} tracked)`);
8543
+ parts.push(colors.muted(`(${status.trackedCount} tracked)`));
8328
8544
  console.log(parts.join(" "));
8329
8545
  };
8330
8546
  var printJsonStatus = (status) => {
@@ -8357,7 +8573,6 @@ init_manifest();
8357
8573
  init_errors();
8358
8574
  init_constants();
8359
8575
  import { Command as Command10 } from "commander";
8360
- import chalk18 from "chalk";
8361
8576
  var groupByCategory2 = async (tuckDir) => {
8362
8577
  const files = await getAllTrackedFiles(tuckDir);
8363
8578
  const groups = /* @__PURE__ */ new Map();
@@ -8396,15 +8611,15 @@ var printList = (groups) => {
8396
8611
  totalFiles += fileCount;
8397
8612
  console.log();
8398
8613
  console.log(
8399
- chalk18.bold(`${group2.icon} ${group2.name}`) + chalk18.dim(` (${formatCount(fileCount, "file")})`)
8614
+ colors.bold(`${group2.icon} ${group2.name}`) + colors.dim(` (${formatCount(fileCount, "file")})`)
8400
8615
  );
8401
8616
  group2.files.forEach((file, index) => {
8402
8617
  const isLast = index === group2.files.length - 1;
8403
8618
  const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
8404
8619
  const name = file.source.split("/").pop() || file.source;
8405
- const arrow = chalk18.dim(" \u2192 ");
8406
- const dest = chalk18.dim(file.source);
8407
- console.log(chalk18.dim(prefix) + chalk18.cyan(name) + arrow + dest);
8620
+ const arrow = colors.dim(" \u2192 ");
8621
+ const dest = colors.dim(file.source);
8622
+ console.log(colors.dim(prefix) + colors.cyan(name) + arrow + dest);
8408
8623
  });
8409
8624
  }
8410
8625
  console.log();
@@ -8465,9 +8680,15 @@ init_git();
8465
8680
  init_files();
8466
8681
  init_errors();
8467
8682
  import { Command as Command11 } from "commander";
8468
- import chalk19 from "chalk";
8469
8683
  import { join as join14 } from "path";
8684
+ init_tuckignore();
8470
8685
  import { readFile as readFile9 } from "fs/promises";
8686
+ var isBinary = async (path) => {
8687
+ if (!await pathExists(path)) {
8688
+ return false;
8689
+ }
8690
+ return await isBinaryExecutable(path);
8691
+ };
8471
8692
  var getFileDiff = async (tuckDir, source) => {
8472
8693
  const tracked = await getTrackedFileBySource(tuckDir, source);
8473
8694
  if (!tracked) {
@@ -8483,15 +8704,60 @@ var getFileDiff = async (tuckDir, source) => {
8483
8704
  if (!await pathExists(systemPath)) {
8484
8705
  diff.hasChanges = true;
8485
8706
  if (await pathExists(repoPath)) {
8486
- diff.repoContent = await readFile9(repoPath, "utf-8");
8707
+ const repoContent = await readFile9(repoPath, "utf-8");
8708
+ diff.repoContent = repoContent;
8709
+ diff.repoSize = repoContent.length;
8487
8710
  }
8488
8711
  return diff;
8489
8712
  }
8490
8713
  if (!await pathExists(repoPath)) {
8491
8714
  diff.hasChanges = true;
8492
- diff.systemContent = await readFile9(systemPath, "utf-8");
8715
+ const systemContent = await readFile9(systemPath, "utf-8");
8716
+ diff.systemContent = systemContent;
8717
+ diff.systemSize = systemContent.length;
8493
8718
  return diff;
8494
8719
  }
8720
+ const systemIsBinary = await isBinary(systemPath);
8721
+ const repoIsBinary = await isBinary(repoPath);
8722
+ if (systemIsBinary || repoIsBinary) {
8723
+ diff.isBinary = true;
8724
+ try {
8725
+ const systemBuffer = await readFile9(systemPath);
8726
+ diff.systemSize = systemBuffer.length;
8727
+ } catch {
8728
+ }
8729
+ try {
8730
+ const repoBuffer = await readFile9(repoPath);
8731
+ diff.repoSize = repoBuffer.length;
8732
+ } catch {
8733
+ }
8734
+ const systemChecksum2 = await getFileChecksum(systemPath);
8735
+ const repoChecksum2 = await getFileChecksum(repoPath);
8736
+ diff.hasChanges = systemChecksum2 !== repoChecksum2;
8737
+ return diff;
8738
+ }
8739
+ const systemIsDir = await isDirectory(systemPath);
8740
+ const repoIsDir = await isDirectory(repoPath);
8741
+ if (systemIsDir || repoIsDir) {
8742
+ diff.isDirectory = true;
8743
+ diff.hasChanges = true;
8744
+ if (systemIsDir) {
8745
+ const files = await getDirectoryFiles(systemPath);
8746
+ diff.fileCount = files.length;
8747
+ }
8748
+ if (repoIsDir) {
8749
+ const files = await getDirectoryFiles(repoPath);
8750
+ diff.fileCount = (diff.fileCount || 0) + files.length;
8751
+ }
8752
+ return diff;
8753
+ }
8754
+ try {
8755
+ const systemSizeCheck = await checkFileSizeThreshold(systemPath);
8756
+ const repoSizeCheck = await checkFileSizeThreshold(repoPath);
8757
+ diff.systemSize = systemSizeCheck.size;
8758
+ diff.repoSize = repoSizeCheck.size;
8759
+ } catch {
8760
+ }
8495
8761
  const systemChecksum = await getFileChecksum(systemPath);
8496
8762
  const repoChecksum = await getFileChecksum(repoPath);
8497
8763
  if (systemChecksum !== repoChecksum) {
@@ -8501,28 +8767,45 @@ var getFileDiff = async (tuckDir, source) => {
8501
8767
  }
8502
8768
  return diff;
8503
8769
  };
8504
- var formatUnifiedDiff = (source, systemContent, repoContent) => {
8770
+ var formatUnifiedDiff = (diff) => {
8505
8771
  const lines = [];
8506
- lines.push(chalk19.bold(`--- a/${source} (system)`));
8507
- lines.push(chalk19.bold(`+++ b/${source} (repository)`));
8772
+ lines.push(colors.bold(`--- a/${diff.source} (system)`));
8773
+ lines.push(colors.bold(`+++ b/${diff.source} (repository)`));
8774
+ if (diff.isBinary) {
8775
+ const sysSize = diff.systemSize ? formatFileSize(diff.systemSize) : "0 B";
8776
+ const repoSize = diff.repoSize ? formatFileSize(diff.repoSize) : "0 B";
8777
+ lines.push(colors.dim("Binary files differ"));
8778
+ lines.push(colors.dim(` System: ${sysSize}`));
8779
+ lines.push(colors.dim(` Repo: ${repoSize}`));
8780
+ return lines.join("\n");
8781
+ }
8782
+ if (diff.isDirectory) {
8783
+ const fileCount = diff.fileCount || 0;
8784
+ lines.push(colors.dim("Directory content changed"));
8785
+ lines.push(colors.dim(` Contains ${fileCount} file${fileCount > 1 ? "s" : ""}`));
8786
+ return lines.join("\n");
8787
+ }
8788
+ const { systemContent, repoContent } = diff;
8508
8789
  if (!systemContent && repoContent) {
8509
- lines.push(chalk19.red("File missing on system"));
8510
- lines.push(chalk19.dim("Repository content:"));
8790
+ lines.push(colors.red("File missing on system"));
8791
+ lines.push(colors.dim("Repository content:"));
8511
8792
  repoContent.split("\n").forEach((line) => {
8512
- lines.push(chalk19.green(`+ ${line}`));
8793
+ lines.push(colors.green(`+ ${line}`));
8513
8794
  });
8514
8795
  } else if (systemContent && !repoContent) {
8515
- lines.push(chalk19.yellow("File not yet synced to repository"));
8516
- lines.push(chalk19.dim("System content:"));
8796
+ lines.push(colors.yellow("File not yet synced to repository"));
8797
+ lines.push(colors.dim("System content:"));
8517
8798
  systemContent.split("\n").forEach((line) => {
8518
- lines.push(chalk19.red(`- ${line}`));
8799
+ lines.push(colors.red(`- ${line}`));
8519
8800
  });
8520
8801
  } else if (systemContent && repoContent) {
8802
+ const CONTEXT_LINES = 3;
8521
8803
  const systemLines = systemContent.split("\n");
8522
8804
  const repoLines = repoContent.split("\n");
8523
8805
  const maxLines = Math.max(systemLines.length, repoLines.length);
8524
8806
  let inDiff = false;
8525
8807
  let diffStart = 0;
8808
+ let contextCount = 0;
8526
8809
  for (let i = 0; i < maxLines; i++) {
8527
8810
  const sysLine = systemLines[i];
8528
8811
  const repoLine = repoLines[i];
@@ -8530,17 +8813,25 @@ var formatUnifiedDiff = (source, systemContent, repoContent) => {
8530
8813
  if (!inDiff) {
8531
8814
  inDiff = true;
8532
8815
  diffStart = i;
8533
- lines.push(chalk19.cyan(`@@ -${i + 1} +${i + 1} @@`));
8816
+ const startLine = Math.max(0, diffStart - CONTEXT_LINES + 1);
8817
+ const endLine = Math.min(maxLines, diffStart + CONTEXT_LINES);
8818
+ lines.push(
8819
+ colors.cyan(
8820
+ `@@ -${startLine + 1},${endLine - startLine} +${startLine + 1},${endLine - startLine} @@`
8821
+ )
8822
+ );
8534
8823
  }
8535
8824
  if (sysLine !== void 0) {
8536
- lines.push(chalk19.red(`- ${sysLine}`));
8825
+ lines.push(colors.red(`- ${sysLine}`));
8537
8826
  }
8538
8827
  if (repoLine !== void 0) {
8539
- lines.push(chalk19.green(`+ ${repoLine}`));
8828
+ lines.push(colors.green(`+ ${repoLine}`));
8540
8829
  }
8830
+ contextCount = 0;
8541
8831
  } else if (inDiff) {
8542
- lines.push(chalk19.dim(` ${sysLine || ""}`));
8543
- if (i - diffStart > 3) {
8832
+ lines.push(colors.dim(` ${sysLine || ""}`));
8833
+ contextCount++;
8834
+ if (contextCount > CONTEXT_LINES * 2) {
8544
8835
  inDiff = false;
8545
8836
  }
8546
8837
  }
@@ -8564,54 +8855,77 @@ var runDiff = async (paths, options) => {
8564
8855
  }
8565
8856
  return;
8566
8857
  }
8567
- if (paths.length === 0) {
8568
- const allFiles = await getAllTrackedFiles(tuckDir);
8569
- const changedFiles = [];
8570
- for (const [, file] of Object.entries(allFiles)) {
8858
+ const allFiles = await getAllTrackedFiles(tuckDir);
8859
+ const changedFiles = [];
8860
+ const filesToCheck = paths.length === 0 ? Object.values(allFiles) : paths.map((path) => {
8861
+ const expandedPath = expandPath(path);
8862
+ const collapsedPath = collapsePath(expandedPath);
8863
+ const tracked = Object.entries(allFiles).find(([, f]) => f.source === collapsedPath);
8864
+ if (!tracked) {
8865
+ throw new FileNotFoundError(`Not tracked: ${path}`);
8866
+ }
8867
+ return tracked[1];
8868
+ });
8869
+ for (const file of filesToCheck) {
8870
+ if (options.category && file.category !== options.category) {
8871
+ continue;
8872
+ }
8873
+ if (await isIgnored(tuckDir, file.source)) {
8874
+ continue;
8875
+ }
8876
+ try {
8571
8877
  const diff = await getFileDiff(tuckDir, file.source);
8572
- if (diff.hasChanges) {
8878
+ if (diff && diff.hasChanges) {
8573
8879
  changedFiles.push(diff);
8574
8880
  }
8881
+ } catch (error) {
8882
+ if (error instanceof FileNotFoundError) {
8883
+ logger.warning(`File not found: ${file.source}`);
8884
+ } else if (error instanceof PermissionError) {
8885
+ logger.warning(`Permission denied: ${file.source}`);
8886
+ } else {
8887
+ throw error;
8888
+ }
8575
8889
  }
8576
- if (changedFiles.length === 0) {
8890
+ }
8891
+ if (changedFiles.length === 0) {
8892
+ if (paths.length > 0) {
8577
8893
  logger.success("No differences found");
8578
- return;
8579
- }
8580
- if (options.stat) {
8894
+ } else {
8581
8895
  prompts.intro("tuck diff");
8582
8896
  console.log();
8583
- console.log(chalk19.bold(`${changedFiles.length} file${changedFiles.length > 1 ? "s" : ""} changed:`));
8584
- console.log();
8585
- for (const diff of changedFiles) {
8586
- console.log(chalk19.yellow(` ~ ${diff.source}`));
8587
- }
8897
+ logger.success("No differences found");
8588
8898
  console.log();
8589
- return;
8590
8899
  }
8900
+ return;
8901
+ }
8902
+ prompts.intro("tuck diff");
8903
+ console.log();
8904
+ if (options.stat || options.nameOnly) {
8905
+ const label = options.nameOnly ? "Changed files:" : `${changedFiles.length} file${changedFiles.length > 1 ? "s" : ""} changed:`;
8906
+ console.log(colors.bold(label));
8907
+ console.log();
8591
8908
  for (const diff of changedFiles) {
8592
- console.log();
8593
- console.log(formatUnifiedDiff(diff.source, diff.systemContent, diff.repoContent));
8594
- console.log();
8909
+ const status = diff.isDirectory ? colors.dim("[dir]") : diff.isBinary ? colors.dim("[bin]") : "";
8910
+ console.log(` ${colors.yellow("~")} ${diff.source} ${status}`);
8595
8911
  }
8912
+ console.log();
8913
+ prompts.outro(`Found ${changedFiles.length} changed file(s)`);
8596
8914
  return;
8597
8915
  }
8598
- for (const path of paths) {
8599
- const expandedPath = expandPath(path);
8600
- const collapsedPath = collapsePath(expandedPath);
8601
- const diff = await getFileDiff(tuckDir, collapsedPath);
8602
- if (!diff.hasChanges) {
8603
- logger.info(`No changes: ${path}`);
8604
- continue;
8605
- }
8606
- if (options.stat) {
8607
- console.log(chalk19.yellow(`~ ${path}`));
8608
- } else {
8609
- console.log(formatUnifiedDiff(path, diff.systemContent, diff.repoContent));
8610
- console.log();
8611
- }
8916
+ for (const diff of changedFiles) {
8917
+ console.log(formatUnifiedDiff(diff));
8918
+ console.log();
8919
+ }
8920
+ prompts.outro(`Found ${changedFiles.length} changed file(s)`);
8921
+ if (options.exitCode) {
8922
+ process.exit(1);
8612
8923
  }
8613
8924
  };
8614
- var diffCommand = new Command11("diff").description("Show differences between system and repository").argument("[paths...]", "Specific files to diff").option("--staged", "Show staged git changes").option("--stat", "Show diffstat only").action(async (paths, options) => {
8925
+ var diffCommand = new Command11("diff").description("Show differences between system and repository").argument("[paths...]", "Specific files to diff").option("--staged", "Show staged git changes").option("--stat", "Show diffstat only").option(
8926
+ "--category <category>",
8927
+ "Filter by file category (shell, git, editors, terminal, ssh, misc)"
8928
+ ).option("--name-only", "Show only changed file names").option("--exit-code", "Return exit code 1 if differences found").action(async (paths, options) => {
8615
8929
  await runDiff(paths, options);
8616
8930
  });
8617
8931
 
@@ -8622,41 +8936,106 @@ init_config();
8622
8936
  init_manifest();
8623
8937
  init_errors();
8624
8938
  import { Command as Command12 } from "commander";
8625
- import chalk20 from "chalk";
8626
8939
  import { spawn } from "child_process";
8627
8940
  var CONFIG_KEYS = [
8628
8941
  // Repository settings
8629
- { path: "repository.defaultBranch", type: "string", description: "Default git branch name", section: "repository" },
8630
- { path: "repository.autoCommit", type: "boolean", description: "Auto-commit changes on sync", section: "repository" },
8631
- { path: "repository.autoPush", type: "boolean", description: "Auto-push after commit", section: "repository" },
8942
+ {
8943
+ path: "repository.defaultBranch",
8944
+ type: "string",
8945
+ description: "Default git branch name",
8946
+ section: "repository"
8947
+ },
8948
+ {
8949
+ path: "repository.autoCommit",
8950
+ type: "boolean",
8951
+ description: "Auto-commit changes on sync",
8952
+ section: "repository"
8953
+ },
8954
+ {
8955
+ path: "repository.autoPush",
8956
+ type: "boolean",
8957
+ description: "Auto-push after commit",
8958
+ section: "repository"
8959
+ },
8632
8960
  // File settings
8633
- { path: "files.strategy", type: "enum", description: "File copy strategy", section: "files", options: ["copy", "symlink"] },
8634
- { path: "files.backupOnRestore", type: "boolean", description: "Create backups before restore", section: "files" },
8635
- { path: "files.backupDir", type: "string", description: "Backup directory path", section: "files" },
8961
+ {
8962
+ path: "files.strategy",
8963
+ type: "enum",
8964
+ description: "File copy strategy",
8965
+ section: "files",
8966
+ options: ["copy", "symlink"]
8967
+ },
8968
+ {
8969
+ path: "files.backupOnRestore",
8970
+ type: "boolean",
8971
+ description: "Create backups before restore",
8972
+ section: "files"
8973
+ },
8974
+ {
8975
+ path: "files.backupDir",
8976
+ type: "string",
8977
+ description: "Backup directory path",
8978
+ section: "files"
8979
+ },
8636
8980
  // UI settings
8637
8981
  { path: "ui.colors", type: "boolean", description: "Enable colored output", section: "ui" },
8638
8982
  { path: "ui.emoji", type: "boolean", description: "Enable emoji in output", section: "ui" },
8639
8983
  { path: "ui.verbose", type: "boolean", description: "Enable verbose logging", section: "ui" },
8640
8984
  // Hook settings
8641
- { path: "hooks.preSync", type: "string", description: "Command to run before sync", section: "hooks" },
8642
- { path: "hooks.postSync", type: "string", description: "Command to run after sync", section: "hooks" },
8643
- { path: "hooks.preRestore", type: "string", description: "Command to run before restore", section: "hooks" },
8644
- { path: "hooks.postRestore", type: "string", description: "Command to run after restore", section: "hooks" },
8985
+ {
8986
+ path: "hooks.preSync",
8987
+ type: "string",
8988
+ description: "Command to run before sync",
8989
+ section: "hooks"
8990
+ },
8991
+ {
8992
+ path: "hooks.postSync",
8993
+ type: "string",
8994
+ description: "Command to run after sync",
8995
+ section: "hooks"
8996
+ },
8997
+ {
8998
+ path: "hooks.preRestore",
8999
+ type: "string",
9000
+ description: "Command to run before restore",
9001
+ section: "hooks"
9002
+ },
9003
+ {
9004
+ path: "hooks.postRestore",
9005
+ type: "string",
9006
+ description: "Command to run after restore",
9007
+ section: "hooks"
9008
+ },
8645
9009
  // Template settings
8646
- { path: "templates.enabled", type: "boolean", description: "Enable template processing", section: "templates" },
9010
+ {
9011
+ path: "templates.enabled",
9012
+ type: "boolean",
9013
+ description: "Enable template processing",
9014
+ section: "templates"
9015
+ },
8647
9016
  // Encryption settings
8648
- { path: "encryption.enabled", type: "boolean", description: "Enable file encryption", section: "encryption" },
8649
- { path: "encryption.gpgKey", type: "string", description: "GPG key for encryption", section: "encryption" }
9017
+ {
9018
+ path: "encryption.enabled",
9019
+ type: "boolean",
9020
+ description: "Enable file encryption",
9021
+ section: "encryption"
9022
+ },
9023
+ {
9024
+ path: "encryption.gpgKey",
9025
+ type: "string",
9026
+ description: "GPG key for encryption",
9027
+ section: "encryption"
9028
+ }
8650
9029
  ];
8651
9030
  var getKeyInfo = (path) => {
8652
9031
  return CONFIG_KEYS.find((k) => k.path === path);
8653
9032
  };
8654
9033
  var formatConfigValue = (value) => {
8655
- if (value === void 0 || value === null) return chalk20.dim("(not set)");
8656
- if (typeof value === "boolean") return value ? chalk20.green("true") : chalk20.yellow("false");
8657
- if (Array.isArray(value)) return value.length ? chalk20.cyan(value.join(", ")) : chalk20.dim("[]");
8658
- if (typeof value === "object") return chalk20.dim(JSON.stringify(value));
8659
- return chalk20.white(String(value));
9034
+ if (value === void 0 || value === null) return colors.dim("(not set)");
9035
+ if (typeof value === "boolean") return value ? colors.green("true") : colors.yellow("false");
9036
+ if (Array.isArray(value)) return value.length ? colors.cyan(value.join(", ")) : colors.dim("[]");
9037
+ if (typeof value === "object") return colors.dim(JSON.stringify(value));
9038
+ return colors.white(String(value));
8660
9039
  };
8661
9040
  var printConfig = (config) => {
8662
9041
  console.log(JSON.stringify(config, null, 2));
@@ -8722,7 +9101,7 @@ var runConfigList = async () => {
8722
9101
  const config = await loadConfig(tuckDir);
8723
9102
  prompts.intro("tuck config");
8724
9103
  console.log();
8725
- console.log(chalk20.dim("Configuration file:"), collapsePath(getConfigPath(tuckDir)));
9104
+ console.log(colors.dim("Configuration file:"), collapsePath(getConfigPath(tuckDir)));
8726
9105
  console.log();
8727
9106
  printConfig(config);
8728
9107
  };
@@ -8750,7 +9129,10 @@ var runConfigEdit = async () => {
8750
9129
  };
8751
9130
  var runConfigReset = async () => {
8752
9131
  const tuckDir = getTuckDir();
8753
- const confirm2 = await prompts.confirm("Reset configuration to defaults? This cannot be undone.", false);
9132
+ const confirm2 = await prompts.confirm(
9133
+ "Reset configuration to defaults? This cannot be undone.",
9134
+ false
9135
+ );
8754
9136
  if (!confirm2) {
8755
9137
  prompts.cancel("Operation cancelled");
8756
9138
  return;
@@ -8771,15 +9153,15 @@ var showConfigView = async (config) => {
8771
9153
  for (const section of sections) {
8772
9154
  const sectionConfig = configObj[section.key];
8773
9155
  if (!sectionConfig || typeof sectionConfig !== "object") continue;
8774
- console.log(chalk20.bold.cyan(`${section.icon} ${section.title}`));
8775
- console.log(chalk20.dim("-".repeat(40)));
9156
+ console.log(colors.bold.cyan(`${section.icon} ${section.title}`));
9157
+ console.log(colors.dim("-".repeat(40)));
8776
9158
  for (const [key, value] of Object.entries(sectionConfig)) {
8777
9159
  const keyInfo = getKeyInfo(`${section.key}.${key}`);
8778
9160
  const displayValue = formatConfigValue(value);
8779
9161
  const description = keyInfo?.description || "";
8780
- console.log(` ${chalk20.white(key)}: ${displayValue}`);
9162
+ console.log(` ${colors.white(key)}: ${displayValue}`);
8781
9163
  if (description) {
8782
- console.log(chalk20.dim(` ${description}`));
9164
+ console.log(colors.dim(` ${description}`));
8783
9165
  }
8784
9166
  }
8785
9167
  console.log();
@@ -8788,7 +9170,7 @@ var showConfigView = async (config) => {
8788
9170
  var runConfigWizard = async (config, tuckDir) => {
8789
9171
  prompts.log.info("Let's configure tuck for your workflow");
8790
9172
  console.log();
8791
- console.log(chalk20.bold.cyan("* Repository Behavior"));
9173
+ console.log(colors.bold.cyan("* Repository Behavior"));
8792
9174
  const autoCommit = await prompts.confirm(
8793
9175
  "Auto-commit changes when running sync?",
8794
9176
  config.repository.autoCommit ?? true
@@ -8798,7 +9180,7 @@ var runConfigWizard = async (config, tuckDir) => {
8798
9180
  config.repository.autoPush ?? false
8799
9181
  );
8800
9182
  console.log();
8801
- console.log(chalk20.bold.cyan("> File Strategy"));
9183
+ console.log(colors.bold.cyan("> File Strategy"));
8802
9184
  const rawStrategy = await prompts.select("How should tuck manage files?", [
8803
9185
  { value: "copy", label: "Copy files", hint: "Safe, independent copies" },
8804
9186
  { value: "symlink", label: "Symlink files", hint: "Real-time updates, single source of truth" }
@@ -8809,8 +9191,8 @@ var runConfigWizard = async (config, tuckDir) => {
8809
9191
  config.files.backupOnRestore ?? true
8810
9192
  );
8811
9193
  console.log();
8812
- console.log(chalk20.bold.cyan("# User Interface"));
8813
- const colors = await prompts.confirm("Enable colored output?", config.ui.colors ?? true);
9194
+ console.log(colors.bold.cyan("# User Interface"));
9195
+ const colors2 = await prompts.confirm("Enable colored output?", config.ui.colors ?? true);
8814
9196
  const emoji = await prompts.confirm("Enable emoji in output?", config.ui.emoji ?? true);
8815
9197
  const verbose = await prompts.confirm("Enable verbose logging?", config.ui.verbose ?? false);
8816
9198
  const updatedConfig = {
@@ -8826,7 +9208,7 @@ var runConfigWizard = async (config, tuckDir) => {
8826
9208
  backupOnRestore
8827
9209
  },
8828
9210
  ui: {
8829
- colors,
9211
+ colors: colors2,
8830
9212
  emoji,
8831
9213
  verbose
8832
9214
  }
@@ -8979,7 +9361,6 @@ import { join as join16 } from "path";
8979
9361
  import { readFile as readFile12, rm as rm4, chmod as chmod3, stat as stat10 } from "fs/promises";
8980
9362
  import { ensureDir as ensureDir7, pathExists as fsPathExists } from "fs-extra";
8981
9363
  import { tmpdir as tmpdir2 } from "os";
8982
- import chalk21 from "chalk";
8983
9364
 
8984
9365
  // src/lib/timemachine.ts
8985
9366
  init_paths();
@@ -9537,7 +9918,10 @@ var applyWithMerge = async (files, dryRun) => {
9537
9918
  if (isShellFile(file.source) && await pathExists(file.destination)) {
9538
9919
  const mergeResult = await smartMerge(file.destination, fileContent);
9539
9920
  if (dryRun) {
9540
- logger.file("merge", `${collapsePath(file.destination)} (${mergeResult.preservedBlocks} blocks preserved)`);
9921
+ logger.file(
9922
+ "merge",
9923
+ `${collapsePath(file.destination)} (${mergeResult.preservedBlocks} blocks preserved)`
9924
+ );
9541
9925
  } else {
9542
9926
  const { writeFile: writeFile8 } = await import("fs/promises");
9543
9927
  const { ensureDir: ensureDir8 } = await import("fs-extra");
@@ -9557,10 +9941,7 @@ var applyWithMerge = async (files, dryRun) => {
9557
9941
  const fileExists = await pathExists(file.destination);
9558
9942
  await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });
9559
9943
  await fixSecurePermissions(file.destination);
9560
- logger.file(
9561
- fileExists ? "modify" : "add",
9562
- collapsePath(file.destination)
9563
- );
9944
+ logger.file(fileExists ? "modify" : "add", collapsePath(file.destination));
9564
9945
  }
9565
9946
  }
9566
9947
  result.appliedCount++;
@@ -9591,10 +9972,7 @@ var applyWithReplace = async (files, dryRun) => {
9591
9972
  const fileExists = await pathExists(file.destination);
9592
9973
  await copyFileOrDir(file.repoPath, file.destination, { overwrite: true });
9593
9974
  await fixSecurePermissions(file.destination);
9594
- logger.file(
9595
- fileExists ? "modify" : "add",
9596
- collapsePath(file.destination)
9597
- );
9975
+ logger.file(fileExists ? "modify" : "add", collapsePath(file.destination));
9598
9976
  }
9599
9977
  result.appliedCount++;
9600
9978
  }
@@ -9603,14 +9981,14 @@ var applyWithReplace = async (files, dryRun) => {
9603
9981
  var displayPlaceholderWarnings = (filesWithPlaceholders) => {
9604
9982
  if (filesWithPlaceholders.length === 0) return;
9605
9983
  console.log();
9606
- console.log(chalk21.yellow("\u26A0 Warning: Some files contain unresolved placeholders:"));
9984
+ console.log(colors.yellow("\u26A0 Warning: Some files contain unresolved placeholders:"));
9607
9985
  console.log();
9608
9986
  for (const { path, placeholders } of filesWithPlaceholders) {
9609
- console.log(chalk21.dim(` ${path}:`));
9987
+ console.log(colors.dim(` ${path}:`));
9610
9988
  const maxToShow = 5;
9611
9989
  if (placeholders.length <= maxToShow) {
9612
9990
  for (const placeholder of placeholders) {
9613
- console.log(chalk21.yellow(` {{${placeholder}}}`));
9991
+ console.log(colors.yellow(` {{${placeholder}}}`));
9614
9992
  }
9615
9993
  } else {
9616
9994
  const firstCount = 3;
@@ -9618,23 +9996,23 @@ var displayPlaceholderWarnings = (filesWithPlaceholders) => {
9618
9996
  const firstPlaceholders = placeholders.slice(0, firstCount);
9619
9997
  const lastPlaceholders = placeholders.slice(-lastCount);
9620
9998
  for (const placeholder of firstPlaceholders) {
9621
- console.log(chalk21.yellow(` {{${placeholder}}}`));
9999
+ console.log(colors.yellow(` {{${placeholder}}}`));
9622
10000
  }
9623
- console.log(chalk21.dim(" ..."));
10001
+ console.log(colors.dim(" ..."));
9624
10002
  for (const placeholder of lastPlaceholders) {
9625
- console.log(chalk21.yellow(` {{${placeholder}}}`));
10003
+ console.log(colors.yellow(` {{${placeholder}}}`));
9626
10004
  }
9627
10005
  const shownCount = firstPlaceholders.length + lastPlaceholders.length;
9628
10006
  const hiddenCount = placeholders.length - shownCount;
9629
10007
  if (hiddenCount > 0) {
9630
- console.log(chalk21.dim(` ... and ${hiddenCount} more not shown`));
10008
+ console.log(colors.dim(` ... and ${hiddenCount} more not shown`));
9631
10009
  }
9632
10010
  }
9633
10011
  }
9634
10012
  console.log();
9635
- console.log(chalk21.dim(" These placeholders need to be replaced with actual values."));
9636
- console.log(chalk21.dim(" Use `tuck secrets set <NAME> <value>` to configure secrets,"));
9637
- console.log(chalk21.dim(" then re-apply to populate them."));
10013
+ console.log(colors.dim(" These placeholders need to be replaced with actual values."));
10014
+ console.log(colors.dim(" Use `tuck secrets set <NAME> <value>` to configure secrets,"));
10015
+ console.log(colors.dim(" then re-apply to populate them."));
9638
10016
  };
9639
10017
  var runInteractiveApply = async (source, options) => {
9640
10018
  banner();
@@ -9651,10 +10029,10 @@ var runInteractiveApply = async (source, options) => {
9651
10029
  }
9652
10030
  let repoDir;
9653
10031
  try {
9654
- const spinner2 = prompts.spinner();
9655
- spinner2.start("Cloning repository...");
10032
+ const spinner4 = prompts.spinner();
10033
+ spinner4.start("Cloning repository...");
9656
10034
  repoDir = await cloneSource(repoId, isUrl);
9657
- spinner2.stop("Repository cloned");
10035
+ spinner4.stop("Repository cloned");
9658
10036
  } catch (error) {
9659
10037
  prompts.log.error(`Failed to clone: ${error instanceof Error ? error.message : String(error)}`);
9660
10038
  return;
@@ -9685,11 +10063,11 @@ var runInteractiveApply = async (source, options) => {
9685
10063
  }
9686
10064
  for (const [category, categoryFiles] of Object.entries(byCategory)) {
9687
10065
  const categoryConfig = CATEGORIES[category] || { icon: "\u{1F4C4}" };
9688
- console.log(chalk21.bold(` ${categoryConfig.icon} ${category}`));
10066
+ console.log(colors.bold(` ${categoryConfig.icon} ${category}`));
9689
10067
  for (const file of categoryFiles) {
9690
10068
  const exists = await pathExists(file.destination);
9691
- const status = exists ? chalk21.yellow("(will update)") : chalk21.green("(new)");
9692
- console.log(chalk21.dim(` ${collapsePath(file.destination)} ${status}`));
10069
+ const status = exists ? colors.yellow("(will update)") : colors.green("(new)");
10070
+ console.log(colors.dim(` ${collapsePath(file.destination)} ${status}`));
9693
10071
  }
9694
10072
  }
9695
10073
  console.log();
@@ -9746,10 +10124,10 @@ var runInteractiveApply = async (source, options) => {
9746
10124
  }
9747
10125
  }
9748
10126
  if (existingPaths.length > 0 && !options.dryRun) {
9749
- const spinner2 = prompts.spinner();
9750
- spinner2.start("Creating backup snapshot...");
10127
+ const spinner4 = prompts.spinner();
10128
+ spinner4.start("Creating backup snapshot...");
9751
10129
  const snapshot = await createPreApplySnapshot(existingPaths, repoId);
9752
- spinner2.stop(`Backup created: ${snapshot.id}`);
10130
+ spinner4.stop(`Backup created: ${snapshot.id}`);
9753
10131
  console.log();
9754
10132
  }
9755
10133
  if (options.dryRun) {
@@ -9855,7 +10233,6 @@ var applyCommand = new Command13("apply").description("Apply dotfiles from a rep
9855
10233
  init_ui();
9856
10234
  init_paths();
9857
10235
  import { Command as Command14 } from "commander";
9858
- import chalk22 from "chalk";
9859
10236
  var showSnapshotList = async () => {
9860
10237
  const snapshots = await listSnapshots();
9861
10238
  if (snapshots.length === 0) {
@@ -9868,11 +10245,11 @@ var showSnapshotList = async () => {
9868
10245
  for (const snapshot of snapshots) {
9869
10246
  const date = formatSnapshotDate(snapshot.id);
9870
10247
  const fileCount = snapshot.files.filter((f) => f.existed).length;
9871
- console.log(chalk22.cyan(` ${snapshot.id}`));
9872
- console.log(chalk22.dim(` Date: ${date}`));
9873
- console.log(chalk22.dim(` Reason: ${snapshot.reason}`));
9874
- console.log(chalk22.dim(` Files: ${fileCount} file(s) backed up`));
9875
- console.log(chalk22.dim(` Machine: ${snapshot.machine}`));
10248
+ console.log(colors.cyan(` ${snapshot.id}`));
10249
+ console.log(colors.dim(` Date: ${date}`));
10250
+ console.log(colors.dim(` Reason: ${snapshot.reason}`));
10251
+ console.log(colors.dim(` Files: ${fileCount} file(s) backed up`));
10252
+ console.log(colors.dim(` Machine: ${snapshot.machine}`));
9876
10253
  console.log();
9877
10254
  }
9878
10255
  const totalSize = await getSnapshotsSize();
@@ -9883,18 +10260,18 @@ var showSnapshotList = async () => {
9883
10260
  };
9884
10261
  var showSnapshotDetails = (snapshot) => {
9885
10262
  console.log();
9886
- console.log(chalk22.bold("Snapshot Details:"));
9887
- console.log(chalk22.dim(` ID: ${snapshot.id}`));
9888
- console.log(chalk22.dim(` Date: ${formatSnapshotDate(snapshot.id)}`));
9889
- console.log(chalk22.dim(` Reason: ${snapshot.reason}`));
9890
- console.log(chalk22.dim(` Machine: ${snapshot.machine}`));
10263
+ console.log(colors.bold("Snapshot Details:"));
10264
+ console.log(colors.dim(` ID: ${snapshot.id}`));
10265
+ console.log(colors.dim(` Date: ${formatSnapshotDate(snapshot.id)}`));
10266
+ console.log(colors.dim(` Reason: ${snapshot.reason}`));
10267
+ console.log(colors.dim(` Machine: ${snapshot.machine}`));
9891
10268
  console.log();
9892
- console.log(chalk22.bold("Files in snapshot:"));
10269
+ console.log(colors.bold("Files in snapshot:"));
9893
10270
  for (const file of snapshot.files) {
9894
10271
  if (file.existed) {
9895
- console.log(chalk22.dim(` ok ${collapsePath(file.originalPath)}`));
10272
+ console.log(colors.dim(` ok ${collapsePath(file.originalPath)}`));
9896
10273
  } else {
9897
- console.log(chalk22.dim(` - ${collapsePath(file.originalPath)} (did not exist)`));
10274
+ console.log(colors.dim(` - ${collapsePath(file.originalPath)} (did not exist)`));
9898
10275
  }
9899
10276
  }
9900
10277
  console.log();
@@ -9989,10 +10366,7 @@ var runInteractiveUndo = async () => {
9989
10366
  label: `${s.id} - ${s.reason.slice(0, 40)}${s.reason.length > 40 ? "..." : ""}`,
9990
10367
  hint: `${s.files.filter((f) => f.existed).length} files`
9991
10368
  }));
9992
- const selectedId = await prompts.select(
9993
- "Select a snapshot to restore:",
9994
- snapshotOptions
9995
- );
10369
+ const selectedId = await prompts.select("Select a snapshot to restore:", snapshotOptions);
9996
10370
  const snapshot = await getSnapshot(selectedId);
9997
10371
  if (!snapshot) {
9998
10372
  prompts.log.error("Snapshot not found");
@@ -10002,11 +10376,11 @@ var runInteractiveUndo = async () => {
10002
10376
  prompts.log.info("Files in this snapshot:");
10003
10377
  for (const file of snapshot.files.slice(0, 10)) {
10004
10378
  if (file.existed) {
10005
- console.log(chalk22.dim(` ${collapsePath(file.originalPath)}`));
10379
+ console.log(colors.dim(` ${collapsePath(file.originalPath)}`));
10006
10380
  }
10007
10381
  }
10008
10382
  if (snapshot.files.length > 10) {
10009
- console.log(chalk22.dim(` ... and ${snapshot.files.length - 10} more`));
10383
+ console.log(colors.dim(` ... and ${snapshot.files.length - 10} more`));
10010
10384
  }
10011
10385
  console.log();
10012
10386
  const confirmed = await prompts.confirm("Restore these files?", true);
@@ -10014,10 +10388,10 @@ var runInteractiveUndo = async () => {
10014
10388
  prompts.cancel("Restore cancelled");
10015
10389
  return;
10016
10390
  }
10017
- const spinner2 = prompts.spinner();
10018
- spinner2.start("Restoring files...");
10391
+ const spinner4 = prompts.spinner();
10392
+ spinner4.start("Restoring files...");
10019
10393
  const restoredFiles = await restoreSnapshot(selectedId);
10020
- spinner2.stop(`Restored ${restoredFiles.length} files`);
10394
+ spinner4.stop(`Restored ${restoredFiles.length} files`);
10021
10395
  prompts.outro("Done!");
10022
10396
  };
10023
10397
  var runUndo = async (snapshotId, options) => {
@@ -10060,7 +10434,6 @@ init_detect();
10060
10434
  init_errors();
10061
10435
  init_fileTracking();
10062
10436
  import { Command as Command15 } from "commander";
10063
- import chalk23 from "chalk";
10064
10437
  init_tuckignore();
10065
10438
  var groupSelectableByCategory = (files) => {
10066
10439
  const grouped = {};
@@ -10085,18 +10458,18 @@ var displayGroupedFiles = (files, showAll) => {
10085
10458
  const trackedFiles = categoryFiles.filter((f) => f.alreadyTracked);
10086
10459
  console.log();
10087
10460
  console.log(
10088
- chalk23.bold(`${config.icon} ${config.name}`) + chalk23.dim(` (${newFiles.length} new, ${trackedFiles.length} tracked)`)
10461
+ colors.bold(`${config.icon} ${config.name}`) + colors.dim(` (${newFiles.length} new, ${trackedFiles.length} tracked)`)
10089
10462
  );
10090
- console.log(chalk23.dim("\u2500".repeat(50)));
10463
+ console.log(colors.dim("\u2500".repeat(50)));
10091
10464
  for (const file of categoryFiles) {
10092
10465
  if (!showAll && file.alreadyTracked) continue;
10093
- const status = file.selected ? chalk23.green("[x]") : chalk23.dim("[ ]");
10466
+ const status = file.selected ? colors.green("[x]") : colors.dim("[ ]");
10094
10467
  const name = file.path;
10095
- const tracked = file.alreadyTracked ? chalk23.dim(" (tracked)") : "";
10096
- const sensitive = file.sensitive ? chalk23.yellow(" [!]") : "";
10097
- const dir = file.isDirectory ? chalk23.cyan(" [dir]") : "";
10468
+ const tracked = file.alreadyTracked ? colors.dim(" (tracked)") : "";
10469
+ const sensitive = file.sensitive ? colors.yellow(" [!]") : "";
10470
+ const dir = file.isDirectory ? colors.cyan(" [dir]") : "";
10098
10471
  console.log(` ${status} ${name}${dir}${sensitive}${tracked}`);
10099
- console.log(chalk23.dim(` ${file.description}`));
10472
+ console.log(colors.dim(` ${file.description}`));
10100
10473
  }
10101
10474
  }
10102
10475
  };
@@ -10111,16 +10484,16 @@ var runInteractiveSelection = async (files) => {
10111
10484
  for (const [category, categoryFiles] of Object.entries(grouped)) {
10112
10485
  const config = DETECTION_CATEGORIES[category] || { icon: "-", name: category };
10113
10486
  console.log();
10114
- console.log(chalk23.bold(`${config.icon} ${config.name}`));
10115
- console.log(chalk23.dim(config.description || ""));
10487
+ console.log(colors.bold(`${config.icon} ${config.name}`));
10488
+ console.log(colors.dim(config.description || ""));
10116
10489
  console.log();
10117
10490
  const options = categoryFiles.map((file) => {
10118
10491
  let label = file.path;
10119
10492
  if (file.sensitive) {
10120
- label += chalk23.yellow(" [!]");
10493
+ label += colors.yellow(" [!]");
10121
10494
  }
10122
10495
  if (file.isDirectory) {
10123
- label += chalk23.cyan(" [dir]");
10496
+ label += colors.cyan(" [dir]");
10124
10497
  }
10125
10498
  return {
10126
10499
  value: file.path,
@@ -10149,11 +10522,11 @@ var runQuickScan = async (files) => {
10149
10522
  const trackedFiles = files.filter((f) => f.alreadyTracked);
10150
10523
  console.log();
10151
10524
  console.log(
10152
- chalk23.bold.cyan("Detected Dotfiles: ") + chalk23.white(`${newFiles.length} new, ${trackedFiles.length} already tracked`)
10525
+ colors.bold.cyan("Detected Dotfiles: ") + colors.white(`${newFiles.length} new, ${trackedFiles.length} already tracked`)
10153
10526
  );
10154
10527
  displayGroupedFiles(files, false);
10155
10528
  console.log();
10156
- console.log(chalk23.dim("\u2500".repeat(60)));
10529
+ console.log(colors.dim("\u2500".repeat(60)));
10157
10530
  console.log();
10158
10531
  if (newFiles.length > 0) {
10159
10532
  logger.info(`Found ${newFiles.length} new dotfiles to track`);
@@ -10169,23 +10542,23 @@ var showSummary = (selected) => {
10169
10542
  return;
10170
10543
  }
10171
10544
  console.log();
10172
- console.log(chalk23.bold.cyan(`Selected ${selected.length} files to track:`));
10173
- console.log(chalk23.dim("\u2500".repeat(50)));
10545
+ console.log(colors.bold.cyan(`Selected ${selected.length} files to track:`));
10546
+ console.log(colors.dim("\u2500".repeat(50)));
10174
10547
  console.log();
10175
10548
  const grouped = groupSelectableByCategory(selected);
10176
10549
  for (const [category, files] of Object.entries(grouped)) {
10177
10550
  const config = DETECTION_CATEGORIES[category] || { icon: "-", name: category };
10178
- console.log(chalk23.bold(`${config.icon} ${config.name}`));
10551
+ console.log(colors.bold(`${config.icon} ${config.name}`));
10179
10552
  for (const file of files) {
10180
- const sensitive = file.sensitive ? chalk23.yellow(" \u26A0") : "";
10181
- console.log(chalk23.dim(` \u2022 ${collapsePath(file.path)}${sensitive}`));
10553
+ const sensitive = file.sensitive ? colors.yellow(" \u26A0") : "";
10554
+ console.log(colors.dim(` \u2022 ${collapsePath(file.path)}${sensitive}`));
10182
10555
  }
10183
10556
  console.log();
10184
10557
  }
10185
10558
  const sensitiveFiles = selected.filter((f) => f.sensitive);
10186
10559
  if (sensitiveFiles.length > 0) {
10187
- console.log(chalk23.yellow("\u26A0 Warning: Some files may contain sensitive data"));
10188
- console.log(chalk23.dim(" Make sure your repository is private!"));
10560
+ console.log(colors.yellow("\u26A0 Warning: Some files may contain sensitive data"));
10561
+ console.log(colors.dim(" Make sure your repository is private!"));
10189
10562
  console.log();
10190
10563
  }
10191
10564
  };
@@ -10207,10 +10580,10 @@ var runScan = async (options) => {
10207
10580
  } catch {
10208
10581
  throw new NotInitializedError();
10209
10582
  }
10210
- const spinner2 = prompts.spinner();
10211
- spinner2.start("Scanning for dotfiles...");
10583
+ const spinner4 = prompts.spinner();
10584
+ spinner4.start("Scanning for dotfiles...");
10212
10585
  const detected = await detectDotfiles();
10213
- spinner2.stop(`Found ${detected.length} dotfiles on this system`);
10586
+ spinner4.stop(`Found ${detected.length} dotfiles on this system`);
10214
10587
  if (detected.length === 0) {
10215
10588
  logger.warning("No common dotfiles detected on this system");
10216
10589
  return;
@@ -10238,7 +10611,7 @@ var runScan = async (options) => {
10238
10611
  logger.warning(`No dotfiles found in category: ${options.category}`);
10239
10612
  logger.info("Available categories:");
10240
10613
  for (const [key, config] of Object.entries(DETECTION_CATEGORIES)) {
10241
- console.log(chalk23.dim(` ${config.icon} ${key} - ${config.name}`));
10614
+ console.log(colors.dim(` ${config.icon} ${key} - ${config.name}`));
10242
10615
  }
10243
10616
  return;
10244
10617
  }
@@ -10296,10 +10669,7 @@ var runScan = async (options) => {
10296
10669
  return;
10297
10670
  }
10298
10671
  showSummary(selected);
10299
- const confirmed = await prompts.confirm(
10300
- `Track these ${selected.length} files?`,
10301
- true
10302
- );
10672
+ const confirmed = await prompts.confirm(`Track these ${selected.length} files?`, true);
10303
10673
  if (!confirmed) {
10304
10674
  prompts.cancel("Operation cancelled");
10305
10675
  return;
@@ -10335,7 +10705,7 @@ init_manifest();
10335
10705
  init_git();
10336
10706
  var program = new Command16();
10337
10707
  program.name("tuck").description(DESCRIPTION).version(VERSION, "-v, --version", "Display version number").configureOutput({
10338
- outputError: (str, write) => write(chalk24.red(str))
10708
+ outputError: (str, write) => write(chalk5.red(str))
10339
10709
  }).addHelpText("beforeAll", customHelp(VERSION)).helpOption("-h, --help", "Display this help message").showHelpAfterError(false);
10340
10710
  program.configureHelp({
10341
10711
  formatHelp: () => ""
@@ -10359,12 +10729,12 @@ var runDefaultAction = async () => {
10359
10729
  const tuckDir = getTuckDir();
10360
10730
  if (!await pathExists(tuckDir)) {
10361
10731
  miniBanner();
10362
- console.log(chalk24.bold("Get started with tuck:\n"));
10363
- console.log(chalk24.cyan(" tuck init") + chalk24.dim(" - Set up tuck and create a GitHub repo"));
10364
- console.log(chalk24.cyan(" tuck scan") + chalk24.dim(" - Find dotfiles to track"));
10732
+ console.log(chalk5.bold("Get started with tuck:\n"));
10733
+ console.log(chalk5.cyan(" tuck init") + chalk5.dim(" - Set up tuck and create a GitHub repo"));
10734
+ console.log(chalk5.cyan(" tuck scan") + chalk5.dim(" - Find dotfiles to track"));
10365
10735
  console.log();
10366
- console.log(chalk24.dim("On a new machine:"));
10367
- console.log(chalk24.cyan(" tuck apply <username>") + chalk24.dim(" - Apply your dotfiles"));
10736
+ console.log(chalk5.dim("On a new machine:"));
10737
+ console.log(chalk5.cyan(" tuck apply <username>") + chalk5.dim(" - Apply your dotfiles"));
10368
10738
  console.log();
10369
10739
  return;
10370
10740
  }
@@ -10373,38 +10743,38 @@ var runDefaultAction = async () => {
10373
10743
  const trackedCount = Object.keys(manifest.files).length;
10374
10744
  const gitStatus = await getStatus(tuckDir);
10375
10745
  miniBanner();
10376
- console.log(chalk24.bold("Status:\n"));
10377
- console.log(` Tracked files: ${chalk24.cyan(trackedCount.toString())}`);
10746
+ console.log(chalk5.bold("Status:\n"));
10747
+ console.log(` Tracked files: ${chalk5.cyan(trackedCount.toString())}`);
10378
10748
  const pendingChanges = gitStatus.modified.length + gitStatus.staged.length;
10379
10749
  if (pendingChanges > 0) {
10380
- console.log(` Pending changes: ${chalk24.yellow(pendingChanges.toString())}`);
10750
+ console.log(` Pending changes: ${chalk5.yellow(pendingChanges.toString())}`);
10381
10751
  } else {
10382
- console.log(` Pending changes: ${chalk24.dim("none")}`);
10752
+ console.log(` Pending changes: ${chalk5.dim("none")}`);
10383
10753
  }
10384
10754
  if (gitStatus.ahead > 0) {
10385
- console.log(` Commits to push: ${chalk24.yellow(gitStatus.ahead.toString())}`);
10755
+ console.log(` Commits to push: ${chalk5.yellow(gitStatus.ahead.toString())}`);
10386
10756
  }
10387
10757
  console.log();
10388
- console.log(chalk24.bold("Next steps:\n"));
10758
+ console.log(chalk5.bold("Next steps:\n"));
10389
10759
  if (trackedCount === 0) {
10390
- console.log(chalk24.cyan(" tuck scan") + chalk24.dim(" - Find dotfiles to track"));
10391
- console.log(chalk24.cyan(" tuck add <file>") + chalk24.dim(" - Track a specific file"));
10760
+ console.log(chalk5.cyan(" tuck scan") + chalk5.dim(" - Find dotfiles to track"));
10761
+ console.log(chalk5.cyan(" tuck add <file>") + chalk5.dim(" - Track a specific file"));
10392
10762
  } else if (pendingChanges > 0) {
10393
- console.log(chalk24.cyan(" tuck sync") + chalk24.dim(" - Commit and push your changes"));
10394
- console.log(chalk24.cyan(" tuck diff") + chalk24.dim(" - Preview what changed"));
10763
+ console.log(chalk5.cyan(" tuck sync") + chalk5.dim(" - Commit and push your changes"));
10764
+ console.log(chalk5.cyan(" tuck diff") + chalk5.dim(" - Preview what changed"));
10395
10765
  } else if (gitStatus.ahead > 0) {
10396
- console.log(chalk24.cyan(" tuck push") + chalk24.dim(" - Push commits to GitHub"));
10766
+ console.log(chalk5.cyan(" tuck push") + chalk5.dim(" - Push commits to GitHub"));
10397
10767
  } else {
10398
- console.log(chalk24.dim(" All synced! Your dotfiles are up to date."));
10768
+ console.log(chalk5.dim(" All synced! Your dotfiles are up to date."));
10399
10769
  console.log();
10400
- console.log(chalk24.cyan(" tuck scan") + chalk24.dim(" - Find more dotfiles to track"));
10401
- console.log(chalk24.cyan(" tuck list") + chalk24.dim(" - See tracked files"));
10770
+ console.log(chalk5.cyan(" tuck scan") + chalk5.dim(" - Find more dotfiles to track"));
10771
+ console.log(chalk5.cyan(" tuck list") + chalk5.dim(" - See tracked files"));
10402
10772
  }
10403
10773
  console.log();
10404
10774
  } catch {
10405
10775
  miniBanner();
10406
- console.log(chalk24.yellow("Tuck directory exists but may be corrupted."));
10407
- console.log(chalk24.dim("Run `tuck init` to reinitialize."));
10776
+ console.log(chalk5.yellow("Tuck directory exists but may be corrupted."));
10777
+ console.log(chalk5.dim("Run `tuck init` to reinitialize."));
10408
10778
  console.log();
10409
10779
  }
10410
10780
  };