claude-scope 0.5.8 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/claude-scope.cjs +449 -232
  2. package/package.json +1 -1
@@ -275,6 +275,70 @@ function createGit(cwd) {
275
275
  return new NativeGit(cwd);
276
276
  }
277
277
 
278
+ // src/ui/utils/colors.ts
279
+ var reset = "\x1B[0m";
280
+ var red = "\x1B[31m";
281
+ var gray = "\x1B[90m";
282
+ var lightGray = "\x1B[37m";
283
+ var bold = "\x1B[1m";
284
+ function colorize(text, color) {
285
+ return `${color}${text}${reset}`;
286
+ }
287
+
288
+ // src/ui/theme/gray-theme.ts
289
+ var GRAY_THEME = {
290
+ name: "gray",
291
+ description: "Neutral gray theme for minimal color distraction",
292
+ colors: {
293
+ base: {
294
+ text: gray,
295
+ muted: gray,
296
+ accent: gray,
297
+ border: gray
298
+ },
299
+ semantic: {
300
+ success: gray,
301
+ warning: gray,
302
+ error: gray,
303
+ info: gray
304
+ },
305
+ git: {
306
+ branch: gray,
307
+ changes: gray
308
+ },
309
+ context: {
310
+ low: gray,
311
+ medium: gray,
312
+ high: gray,
313
+ bar: gray
314
+ },
315
+ lines: {
316
+ added: gray,
317
+ removed: gray
318
+ },
319
+ cost: {
320
+ amount: gray,
321
+ currency: gray
322
+ },
323
+ duration: {
324
+ value: gray,
325
+ unit: gray
326
+ },
327
+ model: {
328
+ name: gray,
329
+ version: gray
330
+ },
331
+ poker: {
332
+ participating: lightGray,
333
+ nonParticipating: gray,
334
+ result: gray
335
+ }
336
+ }
337
+ };
338
+
339
+ // src/ui/theme/index.ts
340
+ var DEFAULT_THEME = GRAY_THEME.colors;
341
+
278
342
  // src/ui/utils/style-utils.ts
279
343
  function withLabel(prefix, value) {
280
344
  if (prefix === "") return value;
@@ -292,75 +356,89 @@ function progressBar(percent, width = 10) {
292
356
 
293
357
  // src/widgets/git/styles.ts
294
358
  var gitStyles = {
295
- minimal: (data) => {
296
- return data.branch;
359
+ minimal: (data, colors) => {
360
+ if (!colors) return data.branch;
361
+ return colorize(data.branch, colors.branch);
297
362
  },
298
- balanced: (data) => {
363
+ balanced: (data, colors) => {
299
364
  if (data.changes && data.changes.files > 0) {
300
365
  const parts = [];
301
366
  if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
302
367
  if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
303
368
  if (parts.length > 0) {
304
- return `${data.branch} [${parts.join(" ")}]`;
369
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
370
+ const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
371
+ return `${branch} ${changes}`;
305
372
  }
306
373
  }
307
- return data.branch;
374
+ return colors ? colorize(data.branch, colors.branch) : data.branch;
308
375
  },
309
- compact: (data) => {
376
+ compact: (data, colors) => {
310
377
  if (data.changes && data.changes.files > 0) {
311
378
  const parts = [];
312
379
  if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
313
380
  if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
314
381
  if (parts.length > 0) {
315
- return `${data.branch} ${parts.join("/")}`;
382
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
383
+ const changesStr = parts.join("/");
384
+ return `${branch} ${changesStr}`;
316
385
  }
317
386
  }
318
- return data.branch;
387
+ return colors ? colorize(data.branch, colors.branch) : data.branch;
319
388
  },
320
- playful: (data) => {
389
+ playful: (data, colors) => {
321
390
  if (data.changes && data.changes.files > 0) {
322
391
  const parts = [];
323
392
  if (data.changes.insertions > 0) parts.push(`\u2B06${data.changes.insertions}`);
324
393
  if (data.changes.deletions > 0) parts.push(`\u2B07${data.changes.deletions}`);
325
394
  if (parts.length > 0) {
326
- return `\u{1F500} ${data.branch} ${parts.join(" ")}`;
395
+ const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
396
+ return `\u{1F500} ${branch2} ${parts.join(" ")}`;
327
397
  }
328
398
  }
329
- return `\u{1F500} ${data.branch}`;
399
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
400
+ return `\u{1F500} ${branch}`;
330
401
  },
331
- verbose: (data) => {
402
+ verbose: (data, colors) => {
332
403
  if (data.changes && data.changes.files > 0) {
333
404
  const parts = [];
334
405
  if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions} insertions`);
335
406
  if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions} deletions`);
336
407
  if (parts.length > 0) {
337
- return `branch: ${data.branch} [${parts.join(", ")}]`;
408
+ const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
409
+ const changes = colors ? colorize(`[${parts.join(", ")}]`, colors.changes) : `[${parts.join(", ")}]`;
410
+ return `branch: ${branch2} ${changes}`;
338
411
  }
339
412
  }
340
- return `branch: ${data.branch} (HEAD)`;
413
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
414
+ return `branch: ${branch} (HEAD)`;
341
415
  },
342
- labeled: (data) => {
416
+ labeled: (data, colors) => {
343
417
  if (data.changes && data.changes.files > 0) {
344
418
  const parts = [];
345
419
  if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
346
420
  if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
347
421
  if (parts.length > 0) {
422
+ const branch2 = colors ? colorize(data.branch, colors.branch) : data.branch;
348
423
  const changes = `${data.changes.files} files: ${parts.join("/")}`;
349
- return `Git: ${data.branch} [${changes}]`;
424
+ return `Git: ${branch2} [${changes}]`;
350
425
  }
351
426
  }
352
- return `Git: ${data.branch}`;
427
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
428
+ return `Git: ${branch}`;
353
429
  },
354
- indicator: (data) => {
430
+ indicator: (data, colors) => {
355
431
  if (data.changes && data.changes.files > 0) {
356
432
  const parts = [];
357
433
  if (data.changes.insertions > 0) parts.push(`+${data.changes.insertions}`);
358
434
  if (data.changes.deletions > 0) parts.push(`-${data.changes.deletions}`);
359
435
  if (parts.length > 0) {
360
- return `\u25CF ${data.branch} [${parts.join(" ")}]`;
436
+ const branch = colors ? colorize(data.branch, colors.branch) : data.branch;
437
+ const changes = colors ? colorize(`[${parts.join(" ")}]`, colors.changes) : `[${parts.join(" ")}]`;
438
+ return `\u25CF ${branch} ${changes}`;
361
439
  }
362
440
  }
363
- return withIndicator(data.branch);
441
+ return withIndicator(colors ? colorize(data.branch, colors.branch) : data.branch);
364
442
  }
365
443
  };
366
444
 
@@ -379,14 +457,17 @@ var GitWidget = class {
379
457
  git = null;
380
458
  enabled = true;
381
459
  cwd = null;
460
+ colors;
382
461
  styleFn = gitStyles.balanced;
383
462
  /**
384
463
  * @param gitFactory - Optional factory function for creating IGit instances
385
464
  * If not provided, uses default createGit (production)
386
465
  * Tests can inject MockGit factory here
466
+ * @param colors - Optional theme colors
387
467
  */
388
- constructor(gitFactory) {
468
+ constructor(gitFactory, colors) {
389
469
  this.gitFactory = gitFactory || createGit;
470
+ this.colors = colors ?? DEFAULT_THEME;
390
471
  }
391
472
  setStyle(style = "balanced") {
392
473
  const fn = gitStyles[style];
@@ -424,7 +505,7 @@ var GitWidget = class {
424
505
  } catch {
425
506
  }
426
507
  const renderData = { branch, changes };
427
- return this.styleFn(renderData);
508
+ return this.styleFn(renderData, this.colors.git);
428
509
  } catch {
429
510
  return null;
430
511
  }
@@ -444,25 +525,37 @@ var GitWidget = class {
444
525
 
445
526
  // src/widgets/git-tag/styles.ts
446
527
  var gitTagStyles = {
447
- balanced: (data) => {
448
- return data.tag || "\u2014";
528
+ balanced: (data, colors) => {
529
+ const tag = data.tag || "\u2014";
530
+ if (!colors) return tag;
531
+ return colorize(tag, colors.branch);
449
532
  },
450
- compact: (data) => {
533
+ compact: (data, colors) => {
451
534
  if (!data.tag) return "\u2014";
452
- return data.tag.replace(/^v/, "");
535
+ const tag = data.tag.replace(/^v/, "");
536
+ if (!colors) return tag;
537
+ return colorize(tag, colors.branch);
453
538
  },
454
- playful: (data) => {
455
- return `\u{1F3F7}\uFE0F ${data.tag || "\u2014"}`;
539
+ playful: (data, colors) => {
540
+ const tag = data.tag || "\u2014";
541
+ if (!colors) return `\u{1F3F7}\uFE0F ${tag}`;
542
+ return `\u{1F3F7}\uFE0F ${colorize(tag, colors.branch)}`;
456
543
  },
457
- verbose: (data) => {
544
+ verbose: (data, colors) => {
458
545
  if (!data.tag) return "version: none";
459
- return `version ${data.tag}`;
546
+ const tag = `version ${data.tag}`;
547
+ if (!colors) return tag;
548
+ return `version ${colorize(data.tag, colors.branch)}`;
460
549
  },
461
- labeled: (data) => {
462
- return withLabel("Tag", data.tag || "none");
550
+ labeled: (data, colors) => {
551
+ const tag = data.tag || "none";
552
+ if (!colors) return withLabel("Tag", tag);
553
+ return withLabel("Tag", colorize(tag, colors.branch));
463
554
  },
464
- indicator: (data) => {
465
- return withIndicator(data.tag || "\u2014");
555
+ indicator: (data, colors) => {
556
+ const tag = data.tag || "\u2014";
557
+ if (!colors) return withIndicator(tag);
558
+ return withIndicator(colorize(tag, colors.branch));
466
559
  }
467
560
  };
468
561
 
@@ -481,14 +574,17 @@ var GitTagWidget = class {
481
574
  git = null;
482
575
  enabled = true;
483
576
  cwd = null;
577
+ colors;
484
578
  styleFn = gitTagStyles.balanced;
485
579
  /**
486
580
  * @param gitFactory - Optional factory function for creating IGit instances
487
581
  * If not provided, uses default createGit (production)
488
582
  * Tests can inject MockGit factory here
583
+ * @param colors - Optional theme colors
489
584
  */
490
- constructor(gitFactory) {
585
+ constructor(gitFactory, colors) {
491
586
  this.gitFactory = gitFactory || createGit;
587
+ this.colors = colors ?? DEFAULT_THEME;
492
588
  }
493
589
  setStyle(style = "balanced") {
494
590
  const fn = gitTagStyles[style];
@@ -506,7 +602,7 @@ var GitTagWidget = class {
506
602
  try {
507
603
  const latestTag = await (this.git.latestTag?.() ?? Promise.resolve(null));
508
604
  const renderData = { tag: latestTag };
509
- return this.styleFn(renderData);
605
+ return this.styleFn(renderData, this.colors.git);
510
606
  } catch {
511
607
  return null;
512
608
  }
@@ -524,34 +620,6 @@ var GitTagWidget = class {
524
620
  }
525
621
  };
526
622
 
527
- // src/widgets/model/styles.ts
528
- function getShortName(displayName) {
529
- return displayName.replace(/^Claude\s+/, "");
530
- }
531
- var modelStyles = {
532
- balanced: (data) => {
533
- return data.displayName;
534
- },
535
- compact: (data) => {
536
- return getShortName(data.displayName);
537
- },
538
- playful: (data) => {
539
- return `\u{1F916} ${getShortName(data.displayName)}`;
540
- },
541
- technical: (data) => {
542
- return data.id;
543
- },
544
- symbolic: (data) => {
545
- return `\u25C6 ${getShortName(data.displayName)}`;
546
- },
547
- labeled: (data) => {
548
- return withLabel("Model", getShortName(data.displayName));
549
- },
550
- indicator: (data) => {
551
- return withIndicator(getShortName(data.displayName));
552
- }
553
- };
554
-
555
623
  // src/widgets/core/stdin-data-widget.ts
556
624
  var StdinDataWidget = class {
557
625
  /**
@@ -610,6 +678,50 @@ var StdinDataWidget = class {
610
678
  }
611
679
  };
612
680
 
681
+ // src/widgets/model/styles.ts
682
+ function getShortName(displayName) {
683
+ return displayName.replace(/^Claude\s+/, "");
684
+ }
685
+ var modelStyles = {
686
+ balanced: (data, colors) => {
687
+ if (!colors) return data.displayName;
688
+ return colorize(data.displayName, colors.name);
689
+ },
690
+ compact: (data, colors) => {
691
+ const shortName = getShortName(data.displayName);
692
+ if (!colors) return shortName;
693
+ return colorize(shortName, colors.name);
694
+ },
695
+ playful: (data, colors) => {
696
+ const shortName = getShortName(data.displayName);
697
+ if (!colors) return `\u{1F916} ${shortName}`;
698
+ return `\u{1F916} ${colorize(shortName, colors.name)}`;
699
+ },
700
+ technical: (data, colors) => {
701
+ if (!colors) return data.id;
702
+ const match = data.id.match(/^(.+?)-(\d[\d.]*)$/);
703
+ if (match) {
704
+ return colorize(match[1], colors.name) + colorize(`-${match[2]}`, colors.version);
705
+ }
706
+ return colorize(data.id, colors.name);
707
+ },
708
+ symbolic: (data, colors) => {
709
+ const shortName = getShortName(data.displayName);
710
+ if (!colors) return `\u25C6 ${shortName}`;
711
+ return `\u25C6 ${colorize(shortName, colors.name)}`;
712
+ },
713
+ labeled: (data, colors) => {
714
+ const shortName = getShortName(data.displayName);
715
+ if (!colors) return withLabel("Model", shortName);
716
+ return withLabel("Model", colorize(shortName, colors.name));
717
+ },
718
+ indicator: (data, colors) => {
719
+ const shortName = getShortName(data.displayName);
720
+ if (!colors) return withIndicator(shortName);
721
+ return withIndicator(colorize(shortName, colors.name));
722
+ }
723
+ };
724
+
613
725
  // src/widgets/model-widget.ts
614
726
  var ModelWidget = class extends StdinDataWidget {
615
727
  id = "model";
@@ -621,7 +733,12 @@ var ModelWidget = class extends StdinDataWidget {
621
733
  0
622
734
  // First line
623
735
  );
736
+ colors;
624
737
  styleFn = modelStyles.balanced;
738
+ constructor(colors) {
739
+ super();
740
+ this.colors = colors ?? DEFAULT_THEME;
741
+ }
625
742
  setStyle(style = "balanced") {
626
743
  const fn = modelStyles[style];
627
744
  if (fn) {
@@ -633,87 +750,64 @@ var ModelWidget = class extends StdinDataWidget {
633
750
  displayName: data.model.display_name,
634
751
  id: data.model.id
635
752
  };
636
- return this.styleFn(renderData);
753
+ return this.styleFn(renderData, this.colors.model);
637
754
  }
638
755
  };
639
756
 
640
- // src/ui/utils/colors.ts
641
- var reset = "\x1B[0m";
642
- var red = "\x1B[31m";
643
- var gray = "\x1B[90m";
644
- var lightGray = "\x1B[37m";
645
- var bold = "\x1B[1m";
646
-
647
- // src/ui/theme/default-theme.ts
648
- var DEFAULT_THEME = {
649
- context: {
650
- low: gray,
651
- medium: gray,
652
- high: gray
653
- },
654
- lines: {
655
- added: gray,
656
- removed: gray
657
- }
658
- };
659
-
660
- // src/ui/utils/formatters.ts
661
- function formatDuration(ms) {
662
- if (ms <= 0) return "0s";
663
- const seconds = Math.floor(ms / TIME.MS_PER_SECOND);
664
- const hours = Math.floor(seconds / TIME.SECONDS_PER_HOUR);
665
- const minutes = Math.floor(seconds % TIME.SECONDS_PER_HOUR / TIME.SECONDS_PER_MINUTE);
666
- const secs = seconds % TIME.SECONDS_PER_MINUTE;
667
- const parts = [];
668
- if (hours > 0) {
669
- parts.push(`${hours}h`);
670
- parts.push(`${minutes}m`);
671
- parts.push(`${secs}s`);
672
- } else if (minutes > 0) {
673
- parts.push(`${minutes}m`);
674
- parts.push(`${secs}s`);
757
+ // src/widgets/context/styles.ts
758
+ function getContextColor(percent, colors) {
759
+ const clampedPercent = Math.max(0, Math.min(100, percent));
760
+ if (clampedPercent < 50) {
761
+ return colors.low;
762
+ } else if (clampedPercent < 80) {
763
+ return colors.medium;
675
764
  } else {
676
- parts.push(`${secs}s`);
765
+ return colors.high;
677
766
  }
678
- return parts.join(" ");
679
- }
680
- function formatCostUSD(usd) {
681
- return `$${usd.toFixed(2)}`;
682
767
  }
683
- function colorize(text, color) {
684
- return `${color}${text}${ANSI_COLORS.RESET}`;
685
- }
686
-
687
- // src/widgets/context/styles.ts
688
768
  var contextStyles = {
689
- balanced: (data) => {
769
+ balanced: (data, colors) => {
690
770
  const bar = progressBar(data.percent, 10);
691
- return `[${bar}] ${data.percent}%`;
771
+ const output = `[${bar}] ${data.percent}%`;
772
+ if (!colors) return output;
773
+ return colorize(output, getContextColor(data.percent, colors));
692
774
  },
693
- compact: (data) => {
694
- return `${data.percent}%`;
775
+ compact: (data, colors) => {
776
+ const output = `${data.percent}%`;
777
+ if (!colors) return output;
778
+ return colorize(output, getContextColor(data.percent, colors));
695
779
  },
696
- playful: (data) => {
780
+ playful: (data, colors) => {
697
781
  const bar = progressBar(data.percent, 10);
698
- return `\u{1F9E0} [${bar}] ${data.percent}%`;
782
+ const output = `\u{1F9E0} [${bar}] ${data.percent}%`;
783
+ if (!colors) return output;
784
+ return `\u{1F9E0} ` + colorize(`[${bar}] ${data.percent}%`, getContextColor(data.percent, colors));
699
785
  },
700
- verbose: (data) => {
786
+ verbose: (data, colors) => {
701
787
  const usedFormatted = data.used.toLocaleString();
702
788
  const maxFormatted = data.contextWindowSize.toLocaleString();
703
- return `${usedFormatted} / ${maxFormatted} tokens (${data.percent}%)`;
789
+ const output = `${usedFormatted} / ${maxFormatted} tokens (${data.percent}%)`;
790
+ if (!colors) return output;
791
+ return colorize(output, getContextColor(data.percent, colors));
704
792
  },
705
- symbolic: (data) => {
793
+ symbolic: (data, colors) => {
706
794
  const filled = Math.round(data.percent / 100 * 5);
707
795
  const empty = 5 - filled;
708
- return `${"\u25AE".repeat(filled)}${"\u25AF".repeat(empty)} ${data.percent}%`;
796
+ const output = `${"\u25AE".repeat(filled)}${"\u25AF".repeat(empty)} ${data.percent}%`;
797
+ if (!colors) return output;
798
+ return colorize(output, getContextColor(data.percent, colors));
709
799
  },
710
- "compact-verbose": (data) => {
800
+ "compact-verbose": (data, colors) => {
711
801
  const usedK = data.used >= 1e3 ? `${Math.floor(data.used / 1e3)}K` : data.used.toString();
712
802
  const maxK = data.contextWindowSize >= 1e3 ? `${Math.floor(data.contextWindowSize / 1e3)}K` : data.contextWindowSize.toString();
713
- return `${data.percent}% (${usedK}/${maxK})`;
803
+ const output = `${data.percent}% (${usedK}/${maxK})`;
804
+ if (!colors) return output;
805
+ return colorize(output, getContextColor(data.percent, colors));
714
806
  },
715
- indicator: (data) => {
716
- return `\u25CF ${data.percent}%`;
807
+ indicator: (data, colors) => {
808
+ const output = `\u25CF ${data.percent}%`;
809
+ if (!colors) return output;
810
+ return colorize(output, getContextColor(data.percent, colors));
717
811
  }
718
812
  };
719
813
 
@@ -732,7 +826,7 @@ var ContextWidget = class extends StdinDataWidget {
732
826
  styleFn = contextStyles.balanced;
733
827
  constructor(colors) {
734
828
  super();
735
- this.colors = colors ?? DEFAULT_THEME.context;
829
+ this.colors = colors ?? DEFAULT_THEME;
736
830
  }
737
831
  setStyle(style = "balanced") {
738
832
  const fn = contextStyles[style];
@@ -750,38 +844,68 @@ var ContextWidget = class extends StdinDataWidget {
750
844
  contextWindowSize: context_window_size,
751
845
  percent
752
846
  };
753
- const output = this.styleFn(renderData);
754
- const color = this.getContextColor(percent);
755
- return colorize(output, color);
756
- }
757
- getContextColor(percent) {
758
- const clampedPercent = Math.max(0, Math.min(100, percent));
759
- if (clampedPercent < 50) {
760
- return this.colors.low;
761
- } else if (clampedPercent < 80) {
762
- return this.colors.medium;
763
- } else {
764
- return this.colors.high;
765
- }
847
+ return this.styleFn(renderData, this.colors.context);
766
848
  }
767
849
  };
768
850
 
851
+ // src/ui/utils/formatters.ts
852
+ function formatDuration(ms) {
853
+ if (ms <= 0) return "0s";
854
+ const seconds = Math.floor(ms / TIME.MS_PER_SECOND);
855
+ const hours = Math.floor(seconds / TIME.SECONDS_PER_HOUR);
856
+ const minutes = Math.floor(seconds % TIME.SECONDS_PER_HOUR / TIME.SECONDS_PER_MINUTE);
857
+ const secs = seconds % TIME.SECONDS_PER_MINUTE;
858
+ const parts = [];
859
+ if (hours > 0) {
860
+ parts.push(`${hours}h`);
861
+ parts.push(`${minutes}m`);
862
+ parts.push(`${secs}s`);
863
+ } else if (minutes > 0) {
864
+ parts.push(`${minutes}m`);
865
+ parts.push(`${secs}s`);
866
+ } else {
867
+ parts.push(`${secs}s`);
868
+ }
869
+ return parts.join(" ");
870
+ }
871
+ function formatCostUSD(usd) {
872
+ return `$${usd.toFixed(2)}`;
873
+ }
874
+ function colorize2(text, color) {
875
+ return `${color}${text}${ANSI_COLORS.RESET}`;
876
+ }
877
+
769
878
  // src/widgets/cost/styles.ts
770
879
  var costStyles = {
771
- balanced: (data) => {
772
- return formatCostUSD(data.costUsd);
880
+ balanced: (data, colors) => {
881
+ const formatted = formatCostUSD(data.costUsd);
882
+ if (!colors) return formatted;
883
+ const amountStr = data.costUsd.toFixed(2);
884
+ return colorize("$", colors.currency) + colorize(amountStr, colors.amount);
773
885
  },
774
- compact: (data) => {
775
- return formatCostUSD(data.costUsd);
886
+ compact: (data, colors) => {
887
+ return costStyles.balanced(data, colors);
776
888
  },
777
- playful: (data) => {
778
- return `\u{1F4B0} ${formatCostUSD(data.costUsd)}`;
889
+ playful: (data, colors) => {
890
+ const formatted = formatCostUSD(data.costUsd);
891
+ if (!colors) return `\u{1F4B0} ${formatted}`;
892
+ const amountStr = data.costUsd.toFixed(2);
893
+ const colored = colorize("$", colors.currency) + colorize(amountStr, colors.amount);
894
+ return `\u{1F4B0} ${colored}`;
779
895
  },
780
- labeled: (data) => {
781
- return withLabel("Cost", formatCostUSD(data.costUsd));
896
+ labeled: (data, colors) => {
897
+ const formatted = formatCostUSD(data.costUsd);
898
+ if (!colors) return withLabel("Cost", formatted);
899
+ const amountStr = data.costUsd.toFixed(2);
900
+ const colored = colorize("$", colors.currency) + colorize(amountStr, colors.amount);
901
+ return withLabel("Cost", colored);
782
902
  },
783
- indicator: (data) => {
784
- return withIndicator(formatCostUSD(data.costUsd));
903
+ indicator: (data, colors) => {
904
+ const formatted = formatCostUSD(data.costUsd);
905
+ if (!colors) return withIndicator(formatted);
906
+ const amountStr = data.costUsd.toFixed(2);
907
+ const colored = colorize("$", colors.currency) + colorize(amountStr, colors.amount);
908
+ return withIndicator(colored);
785
909
  }
786
910
  };
787
911
 
@@ -796,7 +920,12 @@ var CostWidget = class extends StdinDataWidget {
796
920
  0
797
921
  // First line
798
922
  );
923
+ colors;
799
924
  styleFn = costStyles.balanced;
925
+ constructor(colors) {
926
+ super();
927
+ this.colors = colors ?? DEFAULT_THEME;
928
+ }
800
929
  setStyle(style = "balanced") {
801
930
  const fn = costStyles[style];
802
931
  if (fn) {
@@ -808,52 +937,55 @@ var CostWidget = class extends StdinDataWidget {
808
937
  const renderData = {
809
938
  costUsd: data.cost.total_cost_usd
810
939
  };
811
- return this.styleFn(renderData);
940
+ return this.styleFn(renderData, this.colors.cost);
812
941
  }
813
942
  };
814
943
 
815
944
  // src/widgets/lines/styles.ts
816
- function createLinesStyles(colors) {
817
- return {
818
- balanced: (data) => {
819
- const addedStr = colorize(`+${data.added}`, colors.added);
820
- const removedStr = colorize(`-${data.removed}`, colors.removed);
821
- return `${addedStr}/${removedStr}`;
822
- },
823
- compact: (data) => {
824
- const addedStr = colorize(`+${data.added}`, colors.added);
825
- const removedStr = colorize(`-${data.removed}`, colors.removed);
826
- return `${addedStr}${removedStr}`;
827
- },
828
- playful: (data) => {
829
- const addedStr = colorize(`\u2795${data.added}`, colors.added);
830
- const removedStr = colorize(`\u2796${data.removed}`, colors.removed);
831
- return `${addedStr} ${removedStr}`;
832
- },
833
- verbose: (data) => {
834
- const parts = [];
835
- if (data.added > 0) {
836
- parts.push(colorize(`+${data.added} added`, colors.added));
837
- }
838
- if (data.removed > 0) {
839
- parts.push(colorize(`-${data.removed} removed`, colors.removed));
840
- }
841
- return parts.join(", ");
842
- },
843
- labeled: (data) => {
844
- const addedStr = colorize(`+${data.added}`, colors.added);
845
- const removedStr = colorize(`-${data.removed}`, colors.removed);
846
- const lines = `${addedStr}/${removedStr}`;
847
- return withLabel("Lines", lines);
848
- },
849
- indicator: (data) => {
850
- const addedStr = colorize(`+${data.added}`, colors.added);
851
- const removedStr = colorize(`-${data.removed}`, colors.removed);
852
- const lines = `${addedStr}/${removedStr}`;
853
- return withIndicator(lines);
945
+ var linesStyles = {
946
+ balanced: (data, colors) => {
947
+ if (!colors) return `+${data.added}/-${data.removed}`;
948
+ const addedStr = colorize(`+${data.added}`, colors.added);
949
+ const removedStr = colorize(`-${data.removed}`, colors.removed);
950
+ return `${addedStr}/${removedStr}`;
951
+ },
952
+ compact: (data, colors) => {
953
+ if (!colors) return `+${data.added}-${data.removed}`;
954
+ const addedStr = colorize(`+${data.added}`, colors.added);
955
+ const removedStr = colorize(`-${data.removed}`, colors.removed);
956
+ return `${addedStr}${removedStr}`;
957
+ },
958
+ playful: (data, colors) => {
959
+ if (!colors) return `\u2795${data.added} \u2796${data.removed}`;
960
+ const addedStr = colorize(`\u2795${data.added}`, colors.added);
961
+ const removedStr = colorize(`\u2796${data.removed}`, colors.removed);
962
+ return `${addedStr} ${removedStr}`;
963
+ },
964
+ verbose: (data, colors) => {
965
+ const parts = [];
966
+ if (data.added > 0) {
967
+ const text = `+${data.added} added`;
968
+ parts.push(colors ? colorize(text, colors.added) : text);
854
969
  }
855
- };
856
- }
970
+ if (data.removed > 0) {
971
+ const text = `-${data.removed} removed`;
972
+ parts.push(colors ? colorize(text, colors.removed) : text);
973
+ }
974
+ return parts.join(", ");
975
+ },
976
+ labeled: (data, colors) => {
977
+ const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
978
+ const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
979
+ const lines = `${addedStr}/${removedStr}`;
980
+ return withLabel("Lines", lines);
981
+ },
982
+ indicator: (data, colors) => {
983
+ const addedStr = colors ? colorize(`+${data.added}`, colors.added) : `+${data.added}`;
984
+ const removedStr = colors ? colorize(`-${data.removed}`, colors.removed) : `-${data.removed}`;
985
+ const lines = `${addedStr}/${removedStr}`;
986
+ return withIndicator(lines);
987
+ }
988
+ };
857
989
 
858
990
  // src/widgets/lines-widget.ts
859
991
  var LinesWidget = class extends StdinDataWidget {
@@ -867,16 +999,13 @@ var LinesWidget = class extends StdinDataWidget {
867
999
  // First line
868
1000
  );
869
1001
  colors;
870
- linesStyles;
871
- styleFn;
1002
+ styleFn = linesStyles.balanced;
872
1003
  constructor(colors) {
873
1004
  super();
874
- this.colors = colors ?? DEFAULT_THEME.lines;
875
- this.linesStyles = createLinesStyles(this.colors);
876
- this.styleFn = this.linesStyles.balanced;
1005
+ this.colors = colors ?? DEFAULT_THEME;
877
1006
  }
878
1007
  setStyle(style = "balanced") {
879
- const fn = this.linesStyles[style];
1008
+ const fn = linesStyles[style];
880
1009
  if (fn) {
881
1010
  this.styleFn = fn;
882
1011
  }
@@ -885,43 +1014,89 @@ var LinesWidget = class extends StdinDataWidget {
885
1014
  const added = data.cost?.total_lines_added ?? 0;
886
1015
  const removed = data.cost?.total_lines_removed ?? 0;
887
1016
  const renderData = { added, removed };
888
- return this.styleFn(renderData);
1017
+ return this.styleFn(renderData, this.colors.lines);
889
1018
  }
890
1019
  };
891
1020
 
892
1021
  // src/widgets/duration/styles.ts
893
1022
  var durationStyles = {
894
- balanced: (data) => {
895
- return formatDuration(data.durationMs);
1023
+ balanced: (data, colors) => {
1024
+ const formatted = formatDuration(data.durationMs);
1025
+ if (!colors) return formatted;
1026
+ return formatDurationWithColors(data.durationMs, colors);
896
1027
  },
897
- compact: (data) => {
1028
+ compact: (data, colors) => {
898
1029
  const totalSeconds = Math.floor(data.durationMs / 1e3);
899
1030
  const hours = Math.floor(totalSeconds / 3600);
900
1031
  const minutes = Math.floor(totalSeconds % 3600 / 60);
1032
+ if (!colors) {
1033
+ if (hours > 0) {
1034
+ return `${hours}h${minutes}m`;
1035
+ }
1036
+ return `${minutes}m`;
1037
+ }
901
1038
  if (hours > 0) {
902
- return `${hours}h${minutes}m`;
1039
+ return colorize(`${hours}`, colors.value) + colorize("h", colors.unit) + colorize(`${minutes}`, colors.value) + colorize("m", colors.unit);
903
1040
  }
904
- return `${minutes}m`;
1041
+ return colorize(`${minutes}`, colors.value) + colorize("m", colors.unit);
905
1042
  },
906
- playful: (data) => {
1043
+ playful: (data, colors) => {
907
1044
  const totalSeconds = Math.floor(data.durationMs / 1e3);
908
1045
  const hours = Math.floor(totalSeconds / 3600);
909
1046
  const minutes = Math.floor(totalSeconds % 3600 / 60);
1047
+ if (!colors) {
1048
+ if (hours > 0) {
1049
+ return `\u231B ${hours}h ${minutes}m`;
1050
+ }
1051
+ return `\u231B ${minutes}m`;
1052
+ }
910
1053
  if (hours > 0) {
911
- return `\u231B ${hours}h ${minutes}m`;
1054
+ const colored = colorize(`${hours}`, colors.value) + colorize("h", colors.unit) + colorize(` ${minutes}`, colors.value) + colorize("m", colors.unit);
1055
+ return `\u231B ${colored}`;
912
1056
  }
913
- return `\u231B ${minutes}m`;
1057
+ return `\u231B ` + colorize(`${minutes}`, colors.value) + colorize("m", colors.unit);
914
1058
  },
915
- technical: (data) => {
916
- return `${Math.floor(data.durationMs)}ms`;
1059
+ technical: (data, colors) => {
1060
+ const value = `${Math.floor(data.durationMs)}ms`;
1061
+ if (!colors) return value;
1062
+ return colorize(`${Math.floor(data.durationMs)}`, colors.value) + colorize("ms", colors.unit);
917
1063
  },
918
- labeled: (data) => {
919
- return withLabel("Time", formatDuration(data.durationMs));
1064
+ labeled: (data, colors) => {
1065
+ const formatted = formatDuration(data.durationMs);
1066
+ if (!colors) return withLabel("Time", formatted);
1067
+ const colored = formatDurationWithColors(data.durationMs, colors);
1068
+ return withLabel("Time", colored);
920
1069
  },
921
- indicator: (data) => {
922
- return withIndicator(formatDuration(data.durationMs));
1070
+ indicator: (data, colors) => {
1071
+ const formatted = formatDuration(data.durationMs);
1072
+ if (!colors) return withIndicator(formatted);
1073
+ const colored = formatDurationWithColors(data.durationMs, colors);
1074
+ return withIndicator(colored);
923
1075
  }
924
1076
  };
1077
+ function formatDurationWithColors(ms, colors) {
1078
+ if (ms <= 0) return colorize("0s", colors.value);
1079
+ const totalSeconds = Math.floor(ms / 1e3);
1080
+ const hours = Math.floor(totalSeconds / 3600);
1081
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
1082
+ const seconds = totalSeconds % 60;
1083
+ const parts = [];
1084
+ if (hours > 0) {
1085
+ parts.push(
1086
+ colorize(`${hours}`, colors.value) + colorize("h", colors.unit),
1087
+ colorize(`${minutes}`, colors.value) + colorize("m", colors.unit),
1088
+ colorize(`${seconds}`, colors.value) + colorize("s", colors.unit)
1089
+ );
1090
+ } else if (minutes > 0) {
1091
+ parts.push(
1092
+ colorize(`${minutes}`, colors.value) + colorize("m", colors.unit),
1093
+ colorize(`${seconds}`, colors.value) + colorize("s", colors.unit)
1094
+ );
1095
+ } else {
1096
+ parts.push(colorize(`${seconds}`, colors.value) + colorize("s", colors.unit));
1097
+ }
1098
+ return parts.join(" ");
1099
+ }
925
1100
 
926
1101
  // src/widgets/duration-widget.ts
927
1102
  var DurationWidget = class extends StdinDataWidget {
@@ -934,7 +1109,12 @@ var DurationWidget = class extends StdinDataWidget {
934
1109
  0
935
1110
  // First line
936
1111
  );
1112
+ colors;
937
1113
  styleFn = durationStyles.balanced;
1114
+ constructor(colors) {
1115
+ super();
1116
+ this.colors = colors ?? DEFAULT_THEME;
1117
+ }
938
1118
  setStyle(style = "balanced") {
939
1119
  const fn = durationStyles[style];
940
1120
  if (fn) {
@@ -946,7 +1126,7 @@ var DurationWidget = class extends StdinDataWidget {
946
1126
  const renderData = {
947
1127
  durationMs: data.cost.total_duration_ms
948
1128
  };
949
- return this.styleFn(renderData);
1129
+ return this.styleFn(renderData, this.colors.duration);
950
1130
  }
951
1131
  };
952
1132
 
@@ -1240,6 +1420,16 @@ var SUIT_SYMBOLS = {
1240
1420
  diamonds: "\u2666",
1241
1421
  clubs: "\u2663"
1242
1422
  };
1423
+ var EMOJI_SYMBOLS = {
1424
+ spades: "\u2660\uFE0F",
1425
+ // ♠️
1426
+ hearts: "\u2665\uFE0F",
1427
+ // ♥️
1428
+ diamonds: "\u2666\uFE0F",
1429
+ // ♦️
1430
+ clubs: "\u2663\uFE0F"
1431
+ // ♣️
1432
+ };
1243
1433
  function isRedSuit(suit) {
1244
1434
  return suit === "hearts" || suit === "diamonds";
1245
1435
  }
@@ -1279,6 +1469,9 @@ function getRankValue(rank) {
1279
1469
  function formatCard(card) {
1280
1470
  return `${card.rank}${SUIT_SYMBOLS[card.suit]}`;
1281
1471
  }
1472
+ function formatCardEmoji(card) {
1473
+ return `${card.rank}${EMOJI_SYMBOLS[card.suit]}`;
1474
+ }
1282
1475
 
1283
1476
  // src/widgets/poker/deck.ts
1284
1477
  var ALL_SUITS = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs];
@@ -1650,13 +1843,13 @@ var HAND_ABBREVIATIONS = {
1650
1843
  "Straight Flush": "SF",
1651
1844
  "Four of a Kind": "4K",
1652
1845
  "Full House": "FH",
1653
- "Flush": "FL",
1654
- "Straight": "ST",
1846
+ Flush: "FL",
1847
+ Straight: "ST",
1655
1848
  "Three of a Kind": "3K",
1656
1849
  "Two Pair": "2P",
1657
1850
  "One Pair": "1P",
1658
1851
  "High Card": "HC",
1659
- "Nothing": "\u2014"
1852
+ Nothing: "\u2014"
1660
1853
  };
1661
1854
  function formatCardByParticipation(cardData, isParticipating) {
1662
1855
  const color = isRedSuit(cardData.card.suit) ? red : gray;
@@ -1688,16 +1881,22 @@ function formatCardTextCompact(card) {
1688
1881
  const rankSymbol = rankSymbols[rank] ?? rank;
1689
1882
  return `${rankSymbol}${card.suit}`;
1690
1883
  }
1691
- function formatHandResult(handResult) {
1884
+ function formatCardEmojiByParticipation(cardData, isParticipating) {
1885
+ const cardText = formatCardEmoji(cardData.card);
1886
+ if (isParticipating) {
1887
+ return `${bold}(${cardText})${reset} `;
1888
+ } else {
1889
+ return `${cardText} `;
1890
+ }
1891
+ }
1892
+ function formatHandResult(handResult, colors) {
1692
1893
  if (!handResult) {
1693
1894
  return "\u2014";
1694
1895
  }
1695
1896
  const playerParticipates = handResult.participatingIndices.some((idx) => idx < 2);
1696
- if (!playerParticipates) {
1697
- return `Nothing \u{1F0CF}`;
1698
- } else {
1699
- return `${handResult.name}! ${handResult.emoji}`;
1700
- }
1897
+ const resultText = !playerParticipates ? `Nothing \u{1F0CF}` : `${handResult.name}! ${handResult.emoji}`;
1898
+ if (!colors) return resultText;
1899
+ return colorize2(resultText, colors.result);
1701
1900
  }
1702
1901
  function getHandAbbreviation(handResult) {
1703
1902
  if (!handResult) {
@@ -1707,28 +1906,41 @@ function getHandAbbreviation(handResult) {
1707
1906
  return `${abbreviation} (${handResult.name})`;
1708
1907
  }
1709
1908
  var pokerStyles = {
1710
- balanced: (data) => {
1909
+ balanced: (data, colors) => {
1711
1910
  const { holeCards, boardCards, handResult } = data;
1712
1911
  const participatingSet = new Set(handResult?.participatingIndices || []);
1713
1912
  const handStr = holeCards.map((hc, idx) => formatCardByParticipation(hc, participatingSet.has(idx))).join("");
1714
1913
  const boardStr = boardCards.map((bc, idx) => formatCardByParticipation(bc, participatingSet.has(idx + 2))).join("");
1715
- const handLabel = colorize("Hand:", lightGray);
1716
- const boardLabel = colorize("Board:", lightGray);
1717
- return `${handLabel} ${handStr}| ${boardLabel} ${boardStr}\u2192 ${formatHandResult(handResult)}`;
1914
+ const labelColor = colors?.participating ?? lightGray;
1915
+ const handLabel = colorize2("Hand:", labelColor);
1916
+ const boardLabel = colorize2("Board:", labelColor);
1917
+ return `${handLabel} ${handStr}| ${boardLabel} ${boardStr}\u2192 ${formatHandResult(handResult, colors)}`;
1718
1918
  },
1719
- compact: (data) => {
1720
- return pokerStyles.balanced(data);
1919
+ compact: (data, colors) => {
1920
+ return pokerStyles.balanced(data, colors);
1721
1921
  },
1722
- playful: (data) => {
1723
- return pokerStyles.balanced(data);
1922
+ playful: (data, colors) => {
1923
+ return pokerStyles.balanced(data, colors);
1724
1924
  },
1725
- "compact-verbose": (data) => {
1925
+ "compact-verbose": (data, colors) => {
1726
1926
  const { holeCards, boardCards, handResult } = data;
1727
1927
  const participatingSet = new Set(handResult?.participatingIndices || []);
1728
1928
  const handStr = holeCards.map((hc, idx) => formatCardCompact(hc, participatingSet.has(idx))).join("");
1729
1929
  const boardStr = boardCards.map((bc, idx) => formatCardCompact(bc, participatingSet.has(idx + 2))).join("");
1730
1930
  const abbreviation = getHandAbbreviation(handResult);
1731
- return `${handStr}| ${boardStr}\u2192 ${abbreviation}`;
1931
+ const result = `${handStr}| ${boardStr}\u2192 ${abbreviation}`;
1932
+ if (!colors) return result;
1933
+ return colorize2(result, colors.result);
1934
+ },
1935
+ emoji: (data, colors) => {
1936
+ const { holeCards, boardCards, handResult } = data;
1937
+ const participatingSet = new Set(handResult?.participatingIndices || []);
1938
+ const handStr = holeCards.map((hc, idx) => formatCardEmojiByParticipation(hc, participatingSet.has(idx))).join("");
1939
+ const boardStr = boardCards.map((bc, idx) => formatCardEmojiByParticipation(bc, participatingSet.has(idx + 2))).join("");
1940
+ const labelColor = colors?.participating ?? lightGray;
1941
+ const handLabel = colorize2("Hand:", labelColor);
1942
+ const boardLabel = colorize2("Board:", labelColor);
1943
+ return `${handLabel} ${handStr}| ${boardLabel} ${boardStr}\u2192 ${formatHandResult(handResult, colors)}`;
1732
1944
  }
1733
1945
  };
1734
1946
 
@@ -1749,6 +1961,7 @@ var PokerWidget = class extends StdinDataWidget {
1749
1961
  lastUpdateTimestamp = 0;
1750
1962
  THROTTLE_MS = 5e3;
1751
1963
  // 5 seconds
1964
+ colors;
1752
1965
  styleFn = pokerStyles.balanced;
1753
1966
  setStyle(style = DEFAULT_WIDGET_STYLE) {
1754
1967
  const fn = pokerStyles[style];
@@ -1756,6 +1969,10 @@ var PokerWidget = class extends StdinDataWidget {
1756
1969
  this.styleFn = fn;
1757
1970
  }
1758
1971
  }
1972
+ constructor(colors) {
1973
+ super();
1974
+ this.colors = colors ?? DEFAULT_THEME;
1975
+ }
1759
1976
  /**
1760
1977
  * Generate new poker hand on each update
1761
1978
  */
@@ -1817,14 +2034,14 @@ var PokerWidget = class extends StdinDataWidget {
1817
2034
  boardCards: boardCardsData,
1818
2035
  handResult
1819
2036
  };
1820
- return this.styleFn(renderData);
2037
+ return this.styleFn(renderData, this.colors.poker);
1821
2038
  }
1822
2039
  getHandName(text) {
1823
2040
  const match = text.match(/^([^!]+)/);
1824
2041
  return match ? match[1].trim() : "Nothing";
1825
2042
  }
1826
2043
  getHandEmoji(text) {
1827
- const match = text.match(/([🃏♠️♥️♦️♣️🎉✨🌟])/);
2044
+ const match = text.match(/([🃏♠️♥️♦️♣️🎉✨🌟])/u);
1828
2045
  return match ? match[1] : "\u{1F0CF}";
1829
2046
  }
1830
2047
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-scope",
3
- "version": "0.5.8",
3
+ "version": "0.6.1",
4
4
  "description": "Claude Code plugin for session status and analytics",
5
5
  "license": "MIT",
6
6
  "type": "module",