@vimukthid/ccsl 1.0.0 → 1.0.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.
package/dist/index.cjs CHANGED
@@ -35,9 +35,11 @@ __export(src_exports, {
35
35
  defaultConfig: () => defaultConfig,
36
36
  formatStatusLine: () => formatStatusLine,
37
37
  getClaudeSettingsPath: () => getClaudeSettingsPath,
38
+ getConfigPath: () => getConfigPath,
38
39
  installToClaudeSettings: () => installToClaudeSettings,
39
40
  isInstalledInClaude: () => isInstalledInClaude,
40
41
  loadConfig: () => loadConfig,
42
+ loadConfigForScope: () => loadConfigForScope,
41
43
  parseStatusInput: () => parseStatusInput,
42
44
  sampleStatusInput: () => sampleStatusInput,
43
45
  themeNames: () => themeNames,
@@ -62,7 +64,11 @@ var neonTheme = {
62
64
  linesRemoved: { fg: "#ff0066" },
63
65
  directory: { fg: "#00ffff" },
64
66
  version: { fg: "#aaaaff" },
65
- separator: { fg: "#666666" }
67
+ separator: { fg: "#666666" },
68
+ usage: { fg: "#00ffaa" },
69
+ usageHigh: { fg: "#ffff00" },
70
+ usageCritical: { fg: "#ff0000", bold: true },
71
+ resetTime: { fg: "#ff00ff" }
66
72
  }
67
73
  };
68
74
  var rainbowTheme = {
@@ -80,7 +86,11 @@ var rainbowTheme = {
80
86
  linesRemoved: { fg: "#ff0000" },
81
87
  directory: { fg: "#ff7f00" },
82
88
  version: { fg: "#9400d3" },
83
- separator: { fg: "#888888" }
89
+ separator: { fg: "#888888" },
90
+ usage: { fg: "#00ffff" },
91
+ usageHigh: { fg: "#ffff00" },
92
+ usageCritical: { fg: "#ff0000", bold: true },
93
+ resetTime: { fg: "#ff7f00" }
84
94
  }
85
95
  };
86
96
  var oceanTheme = {
@@ -98,7 +108,11 @@ var oceanTheme = {
98
108
  linesRemoved: { fg: "#ff5252" },
99
109
  directory: { fg: "#00bcd4" },
100
110
  version: { fg: "#80deea" },
101
- separator: { fg: "#37474f" }
111
+ separator: { fg: "#37474f" },
112
+ usage: { fg: "#26c6da" },
113
+ usageHigh: { fg: "#4dd0e1" },
114
+ usageCritical: { fg: "#ff5252", bold: true },
115
+ resetTime: { fg: "#0288d1" }
102
116
  }
103
117
  };
104
118
  var minimalTheme = {
@@ -116,7 +130,11 @@ var minimalTheme = {
116
130
  linesRemoved: { fg: "#e06c75" },
117
131
  directory: { fg: "#888888" },
118
132
  version: { fg: "#5c6370" },
119
- separator: { fg: "#444444" }
133
+ separator: { fg: "#444444" },
134
+ usage: { fg: "#98c379" },
135
+ usageHigh: { fg: "#e5c07b" },
136
+ usageCritical: { fg: "#e06c75", bold: true },
137
+ resetTime: { fg: "#61afef" }
120
138
  },
121
139
  icons: {
122
140
  model: "",
@@ -124,7 +142,9 @@ var minimalTheme = {
124
142
  tokens: "",
125
143
  duration: "",
126
144
  lines: "",
127
- directory: ""
145
+ directory: "",
146
+ usage: "",
147
+ resetTime: ""
128
148
  }
129
149
  };
130
150
  var monochromeTheme = {
@@ -142,7 +162,11 @@ var monochromeTheme = {
142
162
  linesRemoved: { fg: "#888888" },
143
163
  directory: { fg: "#aaaaaa" },
144
164
  version: { fg: "#666666" },
145
- separator: { fg: "#444444" }
165
+ separator: { fg: "#444444" },
166
+ usage: { fg: "#bbbbbb" },
167
+ usageHigh: { fg: "#ffffff", bold: true },
168
+ usageCritical: { fg: "#ffffff", bold: true, underline: true },
169
+ resetTime: { fg: "#999999" }
146
170
  },
147
171
  icons: {
148
172
  model: "",
@@ -150,7 +174,9 @@ var monochromeTheme = {
150
174
  tokens: "",
151
175
  duration: "",
152
176
  lines: "",
153
- directory: ""
177
+ directory: "",
178
+ usage: "",
179
+ resetTime: ""
154
180
  }
155
181
  };
156
182
  var corporateTheme = {
@@ -168,7 +194,11 @@ var corporateTheme = {
168
194
  linesRemoved: { fg: "#ef4444" },
169
195
  directory: { fg: "#3b82f6" },
170
196
  version: { fg: "#94a3b8" },
171
- separator: { fg: "#334155" }
197
+ separator: { fg: "#334155" },
198
+ usage: { fg: "#22c55e" },
199
+ usageHigh: { fg: "#f59e0b" },
200
+ usageCritical: { fg: "#ef4444", bold: true },
201
+ resetTime: { fg: "#3b82f6" }
172
202
  }
173
203
  };
174
204
  var themes = {
@@ -190,7 +220,9 @@ var nerdIcons = {
190
220
  duration: "\u23F1",
191
221
  lines: "\xB1",
192
222
  directory: "",
193
- version: ""
223
+ version: "",
224
+ usage: "\u{F04C5}",
225
+ resetTime: "\u{F051F}"
194
226
  };
195
227
  var unicodeIcons = {
196
228
  model: "\u25C8",
@@ -200,7 +232,9 @@ var unicodeIcons = {
200
232
  duration: "\u23F1",
201
233
  lines: "\xB1",
202
234
  directory: "\u{1F4C1}",
203
- version: "v"
235
+ version: "v",
236
+ usage: "\u25B0",
237
+ resetTime: "\u27F3"
204
238
  };
205
239
  var asciiIcons = {
206
240
  model: "*",
@@ -210,7 +244,9 @@ var asciiIcons = {
210
244
  duration: "",
211
245
  lines: "",
212
246
  directory: "",
213
- version: "v"
247
+ version: "v",
248
+ usage: "#",
249
+ resetTime: "~"
214
250
  };
215
251
  var detectedIconMode = null;
216
252
  function detectIconSupport() {
@@ -323,7 +359,9 @@ var availableWidgets = [
323
359
  "duration",
324
360
  "lines",
325
361
  "directory",
326
- "version"
362
+ "version",
363
+ "usage",
364
+ "resetTime"
327
365
  ];
328
366
  function renderWidget(widget, input, theme, config) {
329
367
  switch (widget) {
@@ -343,6 +381,10 @@ function renderWidget(widget, input, theme, config) {
343
381
  return renderDirectory(input, theme, config);
344
382
  case "version":
345
383
  return renderVersion(input, theme, config);
384
+ case "usage":
385
+ return renderUsage(input, theme, config);
386
+ case "resetTime":
387
+ return renderResetTime(input, theme, config);
346
388
  default:
347
389
  return { content: "", visible: false };
348
390
  }
@@ -461,6 +503,106 @@ function renderVersion(input, theme, config) {
461
503
  const content = applyStyle(text, theme.colors.version);
462
504
  return { content, visible: true };
463
505
  }
506
+ function renderUsage(input, theme, config) {
507
+ const sessionUsage = input.session_usage;
508
+ if (!sessionUsage) {
509
+ return { content: "", visible: false };
510
+ }
511
+ const { requests_used, requests_limit, usage_percentage, plan } = sessionUsage;
512
+ if (requests_used === void 0 && usage_percentage === void 0) {
513
+ return { content: "", visible: false };
514
+ }
515
+ const icon = getIcon("usage", theme, config.icons);
516
+ let percent = usage_percentage;
517
+ if (percent === void 0 && requests_used !== void 0 && requests_limit !== void 0 && requests_limit > 0) {
518
+ percent = requests_used / requests_limit * 100;
519
+ }
520
+ let text = "";
521
+ if (icon) {
522
+ text += `${icon} `;
523
+ }
524
+ if (percent !== void 0) {
525
+ const progressBar = renderUsageBar(percent, theme);
526
+ text += progressBar + " ";
527
+ }
528
+ if (requests_used !== void 0 && requests_limit !== void 0) {
529
+ text += `${requests_used}/${requests_limit}`;
530
+ } else if (percent !== void 0) {
531
+ text += `${Math.round(percent)}%`;
532
+ }
533
+ if (plan) {
534
+ text += ` (${plan})`;
535
+ }
536
+ let colorKey = "usage";
537
+ if (percent !== void 0) {
538
+ if (percent >= 90) {
539
+ colorKey = "usageCritical";
540
+ } else if (percent >= 70) {
541
+ colorKey = "usageHigh";
542
+ }
543
+ }
544
+ const style = theme.colors[colorKey] || theme.colors.usage;
545
+ const content = applyStyle(text.trim(), style);
546
+ return { content, visible: true };
547
+ }
548
+ function renderUsageBar(percentage, theme) {
549
+ const totalBars = 5;
550
+ const filledBars = Math.round(percentage / 100 * totalBars);
551
+ const emptyBars = totalBars - filledBars;
552
+ const filledChar = "\u25B0";
553
+ const emptyChar = "\u25B1";
554
+ let filledStyle = theme.colors.usage;
555
+ if (percentage >= 90) {
556
+ filledStyle = theme.colors.usageCritical || theme.colors.usage;
557
+ } else if (percentage >= 70) {
558
+ filledStyle = theme.colors.usageHigh || theme.colors.usage;
559
+ }
560
+ const filled = applyStyle(filledChar.repeat(filledBars), filledStyle);
561
+ const empty = applyStyle(emptyChar.repeat(emptyBars), { fg: "#444444", dim: true });
562
+ return `${filled}${empty}`;
563
+ }
564
+ function renderResetTime(input, theme, config) {
565
+ const sessionUsage = input.session_usage;
566
+ if (!sessionUsage) {
567
+ return { content: "", visible: false };
568
+ }
569
+ const { reset_at, reset_in_seconds } = sessionUsage;
570
+ if (reset_at === void 0 && reset_in_seconds === void 0) {
571
+ return { content: "", visible: false };
572
+ }
573
+ const icon = getIcon("resetTime", theme, config.icons);
574
+ let timeStr = "";
575
+ if (reset_in_seconds !== void 0) {
576
+ timeStr = formatResetDuration(reset_in_seconds);
577
+ } else if (reset_at) {
578
+ try {
579
+ const resetDate = new Date(reset_at);
580
+ const now = /* @__PURE__ */ new Date();
581
+ const diffSeconds = Math.max(0, Math.floor((resetDate.getTime() - now.getTime()) / 1e3));
582
+ timeStr = formatResetDuration(diffSeconds);
583
+ } catch {
584
+ timeStr = reset_at;
585
+ }
586
+ }
587
+ const text = icon ? `${icon} ${timeStr}` : timeStr;
588
+ const content = applyStyle(text, theme.colors.resetTime);
589
+ return { content, visible: true };
590
+ }
591
+ function formatResetDuration(seconds) {
592
+ if (seconds <= 0) {
593
+ return "now";
594
+ }
595
+ const hours = Math.floor(seconds / 3600);
596
+ const minutes = Math.floor(seconds % 3600 / 60);
597
+ if (hours > 0) {
598
+ return minutes > 0 ? `${hours}h${minutes}m` : `${hours}h`;
599
+ }
600
+ if (minutes > 0) {
601
+ const secs = seconds % 60;
602
+ return secs > 0 ? `${minutes}m${secs}s` : `${minutes}m`;
603
+ }
604
+ return `${seconds}s`;
605
+ }
464
606
 
465
607
  // src/formatter.ts
466
608
  function formatStatusLine(input, config) {
@@ -511,6 +653,13 @@ var sampleStatusInput = {
511
653
  cache_creation_input_tokens: 5e3,
512
654
  cache_read_input_tokens: 2e3
513
655
  }
656
+ },
657
+ session_usage: {
658
+ requests_used: 45,
659
+ requests_limit: 100,
660
+ usage_percentage: 45,
661
+ reset_in_seconds: 7200,
662
+ plan: "Pro"
514
663
  }
515
664
  };
516
665
 
@@ -552,6 +701,21 @@ var StatusInputSchema = import_zod.z.object({
552
701
  cache_creation_input_tokens: import_zod.z.number().optional(),
553
702
  cache_read_input_tokens: import_zod.z.number().optional()
554
703
  }).nullable().optional()
704
+ }).optional(),
705
+ // Session usage and rate limit information
706
+ session_usage: import_zod.z.object({
707
+ // Number of requests/messages used in current session
708
+ requests_used: import_zod.z.number().optional(),
709
+ // Maximum requests allowed in the session period
710
+ requests_limit: import_zod.z.number().optional(),
711
+ // Percentage of session usage (0-100)
712
+ usage_percentage: import_zod.z.number().optional(),
713
+ // ISO timestamp when the usage limit resets
714
+ reset_at: import_zod.z.string().optional(),
715
+ // Seconds until reset
716
+ reset_in_seconds: import_zod.z.number().optional(),
717
+ // Plan/tier name (e.g., "Pro", "Free", "Max")
718
+ plan: import_zod.z.string().optional()
555
719
  }).optional()
556
720
  }).passthrough();
557
721
  function parseStatusInput(input) {
@@ -573,6 +737,7 @@ function parseStatusInput(input) {
573
737
 
574
738
  // src/config/loader.ts
575
739
  var import_cosmiconfig = require("cosmiconfig");
740
+ var import_fs = require("fs");
576
741
 
577
742
  // src/config/defaults.ts
578
743
  var defaultWidgets = ["model", "context", "tokens", "cost"];
@@ -604,10 +769,33 @@ async function loadConfig(searchFrom) {
604
769
  if (result && result.config) {
605
770
  return mergeConfig(defaultConfig, result.config);
606
771
  }
772
+ const globalPath = getConfigPath("global");
773
+ if ((0, import_fs.existsSync)(globalPath)) {
774
+ const globalResult = await explorer.load(globalPath);
775
+ if (globalResult && globalResult.config) {
776
+ return mergeConfig(defaultConfig, globalResult.config);
777
+ }
778
+ }
607
779
  } catch {
608
780
  }
609
781
  return { ...defaultConfig };
610
782
  }
783
+ async function loadConfigForScope(scope) {
784
+ const configPath = getConfigPath(scope);
785
+ if (scope === "global") {
786
+ if ((0, import_fs.existsSync)(configPath)) {
787
+ try {
788
+ const result = await explorer.load(configPath);
789
+ if (result && result.config) {
790
+ return mergeConfig(defaultConfig, result.config);
791
+ }
792
+ } catch {
793
+ }
794
+ }
795
+ return { ...defaultConfig };
796
+ }
797
+ return loadConfig();
798
+ }
611
799
  function mergeConfig(defaults, userConfig) {
612
800
  return {
613
801
  theme: userConfig.theme ?? defaults.theme,
@@ -618,9 +806,16 @@ function mergeConfig(defaults, userConfig) {
618
806
  customTheme: userConfig.customTheme
619
807
  };
620
808
  }
809
+ function getConfigPath(scope) {
810
+ if (scope === "local") {
811
+ return ".ccslrc.json";
812
+ }
813
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
814
+ return `${home}/.config/ccsl/config.json`;
815
+ }
621
816
 
622
817
  // src/config/claude.ts
623
- var import_fs = require("fs");
818
+ var import_fs2 = require("fs");
624
819
  var import_path2 = require("path");
625
820
  var import_os = require("os");
626
821
  function getClaudeSettingsPath() {
@@ -629,11 +824,11 @@ function getClaudeSettingsPath() {
629
824
  }
630
825
  function getClaudeSettings() {
631
826
  const settingsPath = getClaudeSettingsPath();
632
- if (!(0, import_fs.existsSync)(settingsPath)) {
827
+ if (!(0, import_fs2.existsSync)(settingsPath)) {
633
828
  return null;
634
829
  }
635
830
  try {
636
- const content = (0, import_fs.readFileSync)(settingsPath, "utf8");
831
+ const content = (0, import_fs2.readFileSync)(settingsPath, "utf8");
637
832
  return JSON.parse(content);
638
833
  } catch {
639
834
  return null;
@@ -642,13 +837,13 @@ function getClaudeSettings() {
642
837
  function installToClaudeSettings(command = "npx @vimukthid/ccsl") {
643
838
  const settingsPath = getClaudeSettingsPath();
644
839
  const dir = (0, import_path2.dirname)(settingsPath);
645
- if (!(0, import_fs.existsSync)(dir)) {
646
- (0, import_fs.mkdirSync)(dir, { recursive: true });
840
+ if (!(0, import_fs2.existsSync)(dir)) {
841
+ (0, import_fs2.mkdirSync)(dir, { recursive: true });
647
842
  }
648
843
  let settings = {};
649
- if ((0, import_fs.existsSync)(settingsPath)) {
844
+ if ((0, import_fs2.existsSync)(settingsPath)) {
650
845
  try {
651
- const content = (0, import_fs.readFileSync)(settingsPath, "utf8");
846
+ const content = (0, import_fs2.readFileSync)(settingsPath, "utf8");
652
847
  settings = JSON.parse(content);
653
848
  } catch {
654
849
  settings = {};
@@ -659,7 +854,7 @@ function installToClaudeSettings(command = "npx @vimukthid/ccsl") {
659
854
  command
660
855
  };
661
856
  try {
662
- (0, import_fs.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2));
857
+ (0, import_fs2.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2));
663
858
  return true;
664
859
  } catch {
665
860
  return false;
@@ -667,14 +862,14 @@ function installToClaudeSettings(command = "npx @vimukthid/ccsl") {
667
862
  }
668
863
  function uninstallFromClaudeSettings() {
669
864
  const settingsPath = getClaudeSettingsPath();
670
- if (!(0, import_fs.existsSync)(settingsPath)) {
865
+ if (!(0, import_fs2.existsSync)(settingsPath)) {
671
866
  return true;
672
867
  }
673
868
  try {
674
- const content = (0, import_fs.readFileSync)(settingsPath, "utf8");
869
+ const content = (0, import_fs2.readFileSync)(settingsPath, "utf8");
675
870
  const settings = JSON.parse(content);
676
871
  delete settings.statusLine;
677
- (0, import_fs.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2));
872
+ (0, import_fs2.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2));
678
873
  return true;
679
874
  } catch {
680
875
  return false;
@@ -695,9 +890,11 @@ function isInstalledInClaude() {
695
890
  defaultConfig,
696
891
  formatStatusLine,
697
892
  getClaudeSettingsPath,
893
+ getConfigPath,
698
894
  installToClaudeSettings,
699
895
  isInstalledInClaude,
700
896
  loadConfig,
897
+ loadConfigForScope,
701
898
  parseStatusInput,
702
899
  sampleStatusInput,
703
900
  themeNames,