ccstatusline-usage 2.0.28 → 2.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ {
2
+ "version": 3,
3
+ "lines": [
4
+ [
5
+ {
6
+ "id": "session-usage",
7
+ "type": "custom-command",
8
+ "color": "brightBlue",
9
+ "commandPath": "scripts/usage.sh session"
10
+ },
11
+ {
12
+ "id": "sep-session-weekly",
13
+ "type": "separator"
14
+ },
15
+ {
16
+ "id": "weekly-usage",
17
+ "type": "custom-command",
18
+ "color": "brightBlue",
19
+ "commandPath": "scripts/usage.sh weekly"
20
+ },
21
+ {
22
+ "id": "sep-weekly-reset",
23
+ "type": "separator"
24
+ },
25
+ {
26
+ "id": "reset-timer",
27
+ "type": "custom-command",
28
+ "color": "brightBlue",
29
+ "commandPath": "scripts/usage.sh reset"
30
+ },
31
+ {
32
+ "id": "sep-reset-model",
33
+ "type": "separator"
34
+ },
35
+ {
36
+ "id": "model",
37
+ "type": "model",
38
+ "color": "magenta"
39
+ },
40
+ {
41
+ "id": "sep-model-chatid",
42
+ "type": "separator"
43
+ },
44
+ {
45
+ "id": "chat-id",
46
+ "type": "claude-session-id",
47
+ "color": "cyan"
48
+ }
49
+ ],
50
+ [
51
+ {
52
+ "id": "context-usage",
53
+ "type": "custom-command",
54
+ "color": "blue",
55
+ "commandPath": "scripts/context.sh"
56
+ }
57
+ ],
58
+ []
59
+ ],
60
+ "flexMode": "full-minus-40",
61
+ "compactThreshold": 60,
62
+ "colorLevel": 2,
63
+ "inheritSeparatorColors": false,
64
+ "globalBold": false,
65
+ "powerline": {
66
+ "enabled": false,
67
+ "separators": [""],
68
+ "separatorInvertBackground": [false],
69
+ "startCaps": [],
70
+ "endCaps": [],
71
+ "autoAlign": false
72
+ }
73
+ }
@@ -32383,8 +32383,8 @@ var require_utils = __commonJS((exports) => {
32383
32383
  }
32384
32384
  return output;
32385
32385
  };
32386
- exports.basename = (path5, { windows } = {}) => {
32387
- const segs = path5.split(windows ? /[\\/]/ : "/");
32386
+ exports.basename = (path6, { windows } = {}) => {
32387
+ const segs = path6.split(windows ? /[\\/]/ : "/");
32388
32388
  const last = segs[segs.length - 1];
32389
32389
  if (last === "") {
32390
32390
  return segs[segs.length - 2];
@@ -50982,18 +50982,18 @@ var SettingsSchema = exports_external.object({
50982
50982
  version: exports_external.number().default(CURRENT_VERSION),
50983
50983
  lines: exports_external.array(exports_external.array(WidgetItemSchema)).min(1).default([
50984
50984
  [
50985
- { id: "model", type: "model", color: "magenta" },
50985
+ { id: "session-usage", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh session", timeout: 5000, label: "Session Usage" },
50986
50986
  { id: "sep1", type: "separator" },
50987
- { id: "context", type: "context-percentage", color: "blue" },
50987
+ { id: "weekly-usage", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh weekly", timeout: 5000, label: "Weekly Usage" },
50988
50988
  { id: "sep2", type: "separator" },
50989
- { id: "session-clock", type: "session-clock", color: "yellow" },
50989
+ { id: "reset-timer", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh reset", timeout: 5000, label: "Reset Timer" },
50990
50990
  { id: "sep3", type: "separator" },
50991
+ { id: "model", type: "model", color: "magenta" },
50992
+ { id: "sep4", type: "separator" },
50991
50993
  { id: "session-id", type: "claude-session-id", color: "cyan" }
50992
50994
  ],
50993
50995
  [
50994
- { id: "git-branch", type: "git-branch", color: "green" },
50995
- { id: "sep4", type: "separator" },
50996
- { id: "git-changes", type: "git-changes", color: "yellow" }
50996
+ { id: "context-usage", type: "custom-command", color: "blue", commandPath: "$PKG/scripts/context.sh", timeout: 5000, label: "Context Bar" }
50997
50997
  ],
50998
50998
  []
50999
50999
  ]),
@@ -51450,7 +51450,7 @@ import { execSync as execSync3 } from "child_process";
51450
51450
  import * as fs5 from "fs";
51451
51451
  import * as path4 from "path";
51452
51452
  var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils";
51453
- var PACKAGE_VERSION = "2.0.28";
51453
+ var PACKAGE_VERSION = "2.0.30";
51454
51454
  function getPackageVersion() {
51455
51455
  if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
51456
51456
  return PACKAGE_VERSION;
@@ -53812,8 +53812,56 @@ var CustomTextEditor = ({ widget, onComplete, onCancel }) => {
53812
53812
  };
53813
53813
  // src/widgets/CustomCommand.tsx
53814
53814
  import { execSync as execSync7 } from "child_process";
53815
+ import * as fs6 from "fs";
53815
53816
  var import_react30 = __toESM(require_react(), 1);
53816
53817
  var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
53818
+ import * as path5 from "path";
53819
+ function getPackageDir() {
53820
+ const scriptPath = process.argv[1];
53821
+ if (scriptPath) {
53822
+ try {
53823
+ const realPath = fs6.realpathSync(scriptPath);
53824
+ let dir = path5.dirname(realPath);
53825
+ for (let i = 0;i < 10; i++) {
53826
+ const pkgJson = path5.join(dir, "package.json");
53827
+ if (fs6.existsSync(pkgJson)) {
53828
+ try {
53829
+ const pkg = JSON.parse(fs6.readFileSync(pkgJson, "utf8"));
53830
+ if (pkg.name === "ccstatusline-usage") {
53831
+ return dir;
53832
+ }
53833
+ } catch {}
53834
+ }
53835
+ const scriptsDir = path5.join(dir, "scripts");
53836
+ if (fs6.existsSync(path5.join(scriptsDir, "usage.sh"))) {
53837
+ return dir;
53838
+ }
53839
+ dir = path5.dirname(dir);
53840
+ }
53841
+ } catch {}
53842
+ }
53843
+ const home = process.env.HOME ?? "";
53844
+ const npxPaths = [
53845
+ path5.join(home, ".npm", "_npx"),
53846
+ path5.join(home, ".cache", "npm", "_npx"),
53847
+ path5.join(home, ".local", "share", "npm", "_npx")
53848
+ ];
53849
+ for (const npxBase of npxPaths) {
53850
+ if (fs6.existsSync(npxBase)) {
53851
+ try {
53852
+ const entries = fs6.readdirSync(npxBase);
53853
+ for (const entry of entries) {
53854
+ const pkgDir = path5.join(npxBase, entry, "node_modules", "ccstatusline-usage");
53855
+ if (fs6.existsSync(path5.join(pkgDir, "scripts", "usage.sh"))) {
53856
+ return pkgDir;
53857
+ }
53858
+ }
53859
+ } catch {}
53860
+ }
53861
+ }
53862
+ return "";
53863
+ }
53864
+ var PKG_DIR = getPackageDir();
53817
53865
 
53818
53866
  class CustomCommandWidget {
53819
53867
  getDefaultColor() {
@@ -53826,9 +53874,11 @@ class CustomCommandWidget {
53826
53874
  return "Custom Command";
53827
53875
  }
53828
53876
  getEditorDisplay(item) {
53829
- const cmd = item.commandPath ?? "No command";
53830
- const truncatedCmd = cmd.length > 20 ? `${cmd.substring(0, 17)}...` : cmd;
53831
- const displayText = `${this.getDisplayName()} (${truncatedCmd})`;
53877
+ const displayText = item.label ? item.label : (() => {
53878
+ const cmd = item.commandPath ?? "No command";
53879
+ const truncatedCmd = cmd.length > 20 ? `${cmd.substring(0, 17)}...` : cmd;
53880
+ return `${this.getDisplayName()} (${truncatedCmd})`;
53881
+ })();
53832
53882
  const modifiers = [];
53833
53883
  if (item.maxWidth) {
53834
53884
  modifiers.push(`max:${item.maxWidth}`);
@@ -53850,6 +53900,17 @@ class CustomCommandWidget {
53850
53900
  }
53851
53901
  return null;
53852
53902
  }
53903
+ resolveCommandPath(commandPath) {
53904
+ if (commandPath.startsWith("$PKG/") || commandPath.startsWith("$PACKAGE_DIR/")) {
53905
+ const relativePath = commandPath.replace(/^\$(PKG|PACKAGE_DIR)\//, "");
53906
+ const resolved = path5.join(PKG_DIR, relativePath);
53907
+ return resolved;
53908
+ }
53909
+ if (commandPath.startsWith("$HOME/")) {
53910
+ return commandPath.replace("$HOME", process.env.HOME ?? "~");
53911
+ }
53912
+ return commandPath;
53913
+ }
53853
53914
  render(item, context, settings) {
53854
53915
  if (context.isPreview) {
53855
53916
  return item.commandPath ? `[cmd: ${item.commandPath.substring(0, 20)}${item.commandPath.length > 20 ? "..." : ""}]` : "[No command]";
@@ -53857,7 +53918,8 @@ class CustomCommandWidget {
53857
53918
  try {
53858
53919
  const timeout = item.timeout ?? 1000;
53859
53920
  const jsonInput = JSON.stringify(context.data);
53860
- let output = execSync7(item.commandPath, {
53921
+ const resolvedPath = this.resolveCommandPath(item.commandPath);
53922
+ let output = execSync7(resolvedPath, {
53861
53923
  encoding: "utf8",
53862
53924
  input: jsonInput,
53863
53925
  timeout,
@@ -54278,13 +54340,13 @@ class CurrentWorkingDirWidget {
54278
54340
  supportsColors(item) {
54279
54341
  return true;
54280
54342
  }
54281
- abbreviatePath(path5) {
54343
+ abbreviatePath(path6) {
54282
54344
  const homeDir = os5.homedir();
54283
- const useBackslash = path5.includes("\\") && !path5.includes("/");
54345
+ const useBackslash = path6.includes("\\") && !path6.includes("/");
54284
54346
  const sep = useBackslash ? "\\" : "/";
54285
- let normalizedPath = path5;
54286
- if (path5.startsWith(homeDir)) {
54287
- normalizedPath = "~" + path5.slice(homeDir.length);
54347
+ let normalizedPath = path6;
54348
+ if (path6.startsWith(homeDir)) {
54349
+ normalizedPath = "~" + path6.slice(homeDir.length);
54288
54350
  }
54289
54351
  const parts = normalizedPath.split(/[\\/]+/).filter((part) => part !== "");
54290
54352
  const abbreviated = parts.map((part, index) => {
@@ -58238,42 +58300,42 @@ var StatusJSONSchema = exports_external.looseObject({
58238
58300
  });
58239
58301
 
58240
58302
  // src/utils/jsonl.ts
58241
- import * as fs6 from "fs";
58242
- import path6 from "node:path";
58303
+ import * as fs7 from "fs";
58304
+ import path7 from "node:path";
58243
58305
 
58244
58306
  // node_modules/tinyglobby/dist/index.mjs
58245
- import path5, { posix } from "path";
58307
+ import path6, { posix } from "path";
58246
58308
 
58247
58309
  // node_modules/fdir/dist/index.mjs
58248
58310
  import { createRequire as createRequire2 } from "module";
58249
- import { basename as basename2, dirname as dirname2, normalize, relative, resolve as resolve2, sep } from "path";
58311
+ import { basename as basename2, dirname as dirname3, normalize, relative, resolve as resolve2, sep } from "path";
58250
58312
  import * as nativeFs from "fs";
58251
58313
  var __require2 = /* @__PURE__ */ createRequire2(import.meta.url);
58252
- function cleanPath(path5) {
58253
- let normalized = normalize(path5);
58314
+ function cleanPath(path6) {
58315
+ let normalized = normalize(path6);
58254
58316
  if (normalized.length > 1 && normalized[normalized.length - 1] === sep)
58255
58317
  normalized = normalized.substring(0, normalized.length - 1);
58256
58318
  return normalized;
58257
58319
  }
58258
58320
  var SLASHES_REGEX = /[\\/]/g;
58259
- function convertSlashes(path5, separator) {
58260
- return path5.replace(SLASHES_REGEX, separator);
58321
+ function convertSlashes(path6, separator) {
58322
+ return path6.replace(SLASHES_REGEX, separator);
58261
58323
  }
58262
58324
  var WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i;
58263
- function isRootDirectory(path5) {
58264
- return path5 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path5);
58325
+ function isRootDirectory(path6) {
58326
+ return path6 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path6);
58265
58327
  }
58266
- function normalizePath(path5, options) {
58328
+ function normalizePath(path6, options) {
58267
58329
  const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
58268
- const pathNeedsCleaning = process.platform === "win32" && path5.includes("/") || path5.startsWith(".");
58330
+ const pathNeedsCleaning = process.platform === "win32" && path6.includes("/") || path6.startsWith(".");
58269
58331
  if (resolvePaths)
58270
- path5 = resolve2(path5);
58332
+ path6 = resolve2(path6);
58271
58333
  if (normalizePath$1 || pathNeedsCleaning)
58272
- path5 = cleanPath(path5);
58273
- if (path5 === ".")
58334
+ path6 = cleanPath(path6);
58335
+ if (path6 === ".")
58274
58336
  return "";
58275
- const needsSeperator = path5[path5.length - 1] !== pathSeparator;
58276
- return convertSlashes(needsSeperator ? path5 + pathSeparator : path5, pathSeparator);
58337
+ const needsSeperator = path6[path6.length - 1] !== pathSeparator;
58338
+ return convertSlashes(needsSeperator ? path6 + pathSeparator : path6, pathSeparator);
58277
58339
  }
58278
58340
  function joinPathWithBasePath(filename, directoryPath) {
58279
58341
  return directoryPath + filename;
@@ -58313,9 +58375,9 @@ var pushDirectory = (directoryPath, paths) => {
58313
58375
  paths.push(directoryPath || ".");
58314
58376
  };
58315
58377
  var pushDirectoryFilter = (directoryPath, paths, filters) => {
58316
- const path5 = directoryPath || ".";
58317
- if (filters.every((filter) => filter(path5, true)))
58318
- paths.push(path5);
58378
+ const path6 = directoryPath || ".";
58379
+ if (filters.every((filter) => filter(path6, true)))
58380
+ paths.push(path6);
58319
58381
  };
58320
58382
  var empty$2 = () => {};
58321
58383
  function build$6(root, options) {
@@ -58372,29 +58434,29 @@ var empty = () => {};
58372
58434
  function build$3(options) {
58373
58435
  return options.group ? groupFiles : empty;
58374
58436
  }
58375
- var resolveSymlinksAsync = function(path5, state, callback$1) {
58376
- const { queue, fs: fs6, options: { suppressErrors } } = state;
58437
+ var resolveSymlinksAsync = function(path6, state, callback$1) {
58438
+ const { queue, fs: fs7, options: { suppressErrors } } = state;
58377
58439
  queue.enqueue();
58378
- fs6.realpath(path5, (error43, resolvedPath) => {
58440
+ fs7.realpath(path6, (error43, resolvedPath) => {
58379
58441
  if (error43)
58380
58442
  return queue.dequeue(suppressErrors ? null : error43, state);
58381
- fs6.stat(resolvedPath, (error$1, stat) => {
58443
+ fs7.stat(resolvedPath, (error$1, stat) => {
58382
58444
  if (error$1)
58383
58445
  return queue.dequeue(suppressErrors ? null : error$1, state);
58384
- if (stat.isDirectory() && isRecursive(path5, resolvedPath, state))
58446
+ if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
58385
58447
  return queue.dequeue(null, state);
58386
58448
  callback$1(stat, resolvedPath);
58387
58449
  queue.dequeue(null, state);
58388
58450
  });
58389
58451
  });
58390
58452
  };
58391
- var resolveSymlinks = function(path5, state, callback$1) {
58392
- const { queue, fs: fs6, options: { suppressErrors } } = state;
58453
+ var resolveSymlinks = function(path6, state, callback$1) {
58454
+ const { queue, fs: fs7, options: { suppressErrors } } = state;
58393
58455
  queue.enqueue();
58394
58456
  try {
58395
- const resolvedPath = fs6.realpathSync(path5);
58396
- const stat = fs6.statSync(resolvedPath);
58397
- if (stat.isDirectory() && isRecursive(path5, resolvedPath, state))
58457
+ const resolvedPath = fs7.realpathSync(path6);
58458
+ const stat = fs7.statSync(resolvedPath);
58459
+ if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
58398
58460
  return;
58399
58461
  callback$1(stat, resolvedPath);
58400
58462
  } catch (e) {
@@ -58407,10 +58469,10 @@ function build$2(options, isSynchronous) {
58407
58469
  return null;
58408
58470
  return isSynchronous ? resolveSymlinks : resolveSymlinksAsync;
58409
58471
  }
58410
- function isRecursive(path5, resolved, state) {
58472
+ function isRecursive(path6, resolved, state) {
58411
58473
  if (state.options.useRealPaths)
58412
58474
  return isRecursiveUsingRealPaths(resolved, state);
58413
- let parent = dirname2(path5);
58475
+ let parent = dirname3(path6);
58414
58476
  let depth = 1;
58415
58477
  while (parent !== state.root && depth < 2) {
58416
58478
  const resolvedPath = state.symlinks.get(parent);
@@ -58418,9 +58480,9 @@ function isRecursive(path5, resolved, state) {
58418
58480
  if (isSameRoot)
58419
58481
  depth++;
58420
58482
  else
58421
- parent = dirname2(parent);
58483
+ parent = dirname3(parent);
58422
58484
  }
58423
- state.symlinks.set(path5, resolved);
58485
+ state.symlinks.set(path6, resolved);
58424
58486
  return depth > 1;
58425
58487
  }
58426
58488
  function isRecursiveUsingRealPaths(resolved, state) {
@@ -58476,23 +58538,23 @@ var walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
58476
58538
  state.queue.enqueue();
58477
58539
  if (currentDepth < 0)
58478
58540
  return state.queue.dequeue(null, state);
58479
- const { fs: fs6 } = state;
58541
+ const { fs: fs7 } = state;
58480
58542
  state.visited.push(crawlPath);
58481
58543
  state.counts.directories++;
58482
- fs6.readdir(crawlPath || ".", readdirOpts, (error43, entries = []) => {
58544
+ fs7.readdir(crawlPath || ".", readdirOpts, (error43, entries = []) => {
58483
58545
  callback$1(entries, directoryPath, currentDepth);
58484
58546
  state.queue.dequeue(state.options.suppressErrors ? null : error43, state);
58485
58547
  });
58486
58548
  };
58487
58549
  var walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
58488
- const { fs: fs6 } = state;
58550
+ const { fs: fs7 } = state;
58489
58551
  if (currentDepth < 0)
58490
58552
  return;
58491
58553
  state.visited.push(crawlPath);
58492
58554
  state.counts.directories++;
58493
58555
  let entries = [];
58494
58556
  try {
58495
- entries = fs6.readdirSync(crawlPath || ".", readdirOpts);
58557
+ entries = fs7.readdirSync(crawlPath || ".", readdirOpts);
58496
58558
  } catch (e) {
58497
58559
  if (!state.options.suppressErrors)
58498
58560
  throw e;
@@ -58598,23 +58660,23 @@ var Walker = class {
58598
58660
  const filename = this.joinPath(entry.name, directoryPath);
58599
58661
  this.pushFile(filename, files, this.state.counts, filters);
58600
58662
  } else if (entry.isDirectory()) {
58601
- let path5 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
58602
- if (exclude && exclude(entry.name, path5))
58663
+ let path6 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
58664
+ if (exclude && exclude(entry.name, path6))
58603
58665
  continue;
58604
- this.pushDirectory(path5, paths, filters);
58605
- this.walkDirectory(this.state, path5, path5, depth - 1, this.walk);
58666
+ this.pushDirectory(path6, paths, filters);
58667
+ this.walkDirectory(this.state, path6, path6, depth - 1, this.walk);
58606
58668
  } else if (this.resolveSymlink && entry.isSymbolicLink()) {
58607
- let path5 = joinPathWithBasePath(entry.name, directoryPath);
58608
- this.resolveSymlink(path5, this.state, (stat, resolvedPath) => {
58669
+ let path6 = joinPathWithBasePath(entry.name, directoryPath);
58670
+ this.resolveSymlink(path6, this.state, (stat, resolvedPath) => {
58609
58671
  if (stat.isDirectory()) {
58610
58672
  resolvedPath = normalizePath(resolvedPath, this.state.options);
58611
- if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path5 + pathSeparator))
58673
+ if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path6 + pathSeparator))
58612
58674
  return;
58613
- this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path5 + pathSeparator, depth - 1, this.walk);
58675
+ this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path6 + pathSeparator, depth - 1, this.walk);
58614
58676
  } else {
58615
- resolvedPath = useRealPaths ? resolvedPath : path5;
58677
+ resolvedPath = useRealPaths ? resolvedPath : path6;
58616
58678
  const filename = basename2(resolvedPath);
58617
- const directoryPath$1 = normalizePath(dirname2(resolvedPath), this.state.options);
58679
+ const directoryPath$1 = normalizePath(dirname3(resolvedPath), this.state.options);
58618
58680
  resolvedPath = this.joinPath(filename, directoryPath$1);
58619
58681
  this.pushFile(resolvedPath, files, this.state.counts, filters);
58620
58682
  }
@@ -58772,7 +58834,7 @@ var Builder = class {
58772
58834
  isMatch = globFn(patterns, ...options);
58773
58835
  this.globCache[patterns.join("\x00")] = isMatch;
58774
58836
  }
58775
- this.options.filters.push((path5) => isMatch(path5));
58837
+ this.options.filters.push((path6) => isMatch(path6));
58776
58838
  return this;
58777
58839
  }
58778
58840
  };
@@ -58851,7 +58913,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
58851
58913
  if (!result.endsWith("*") && expandDirectories)
58852
58914
  result += "/**";
58853
58915
  const escapedCwd = escapePath(cwd2);
58854
- if (path5.isAbsolute(result.replace(ESCAPING_BACKSLASHES, "")))
58916
+ if (path6.isAbsolute(result.replace(ESCAPING_BACKSLASHES, "")))
58855
58917
  result = posix.relative(escapedCwd, result);
58856
58918
  else
58857
58919
  result = posix.normalize(result);
@@ -58888,7 +58950,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
58888
58950
  }
58889
58951
  props.depthOffset = newCommonPath.length;
58890
58952
  props.commonPath = newCommonPath;
58891
- props.root = newCommonPath.length > 0 ? path5.posix.join(cwd2, ...newCommonPath) : cwd2;
58953
+ props.root = newCommonPath.length > 0 ? path6.posix.join(cwd2, ...newCommonPath) : cwd2;
58892
58954
  }
58893
58955
  return result;
58894
58956
  }
@@ -59021,18 +59083,18 @@ function globSync(patternsOrOptions, options) {
59021
59083
  ...options,
59022
59084
  patterns: patternsOrOptions
59023
59085
  } : patternsOrOptions;
59024
- const cwd2 = opts.cwd ? path5.resolve(opts.cwd).replace(BACKSLASHES, "/") : process.cwd().replace(BACKSLASHES, "/");
59086
+ const cwd2 = opts.cwd ? path6.resolve(opts.cwd).replace(BACKSLASHES, "/") : process.cwd().replace(BACKSLASHES, "/");
59025
59087
  return crawl(opts, cwd2, true);
59026
59088
  }
59027
59089
 
59028
59090
  // src/utils/jsonl.ts
59029
59091
  import { promisify } from "util";
59030
- var readFile4 = promisify(fs6.readFile);
59031
- var readFileSync4 = fs6.readFileSync;
59032
- var statSync4 = fs6.statSync;
59092
+ var readFile4 = promisify(fs7.readFile);
59093
+ var readFileSync5 = fs7.readFileSync;
59094
+ var statSync4 = fs7.statSync;
59033
59095
  async function getSessionDuration(transcriptPath) {
59034
59096
  try {
59035
- if (!fs6.existsSync(transcriptPath)) {
59097
+ if (!fs7.existsSync(transcriptPath)) {
59036
59098
  return null;
59037
59099
  }
59038
59100
  const content = await readFile4(transcriptPath, "utf-8");
@@ -59084,7 +59146,7 @@ async function getSessionDuration(transcriptPath) {
59084
59146
  }
59085
59147
  async function getTokenMetrics(transcriptPath) {
59086
59148
  try {
59087
- if (!fs6.existsSync(transcriptPath)) {
59149
+ if (!fs7.existsSync(transcriptPath)) {
59088
59150
  return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
59089
59151
  }
59090
59152
  const content = await readFile4(transcriptPath, "utf-8");
@@ -59137,7 +59199,7 @@ function getBlockMetrics() {
59137
59199
  function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
59138
59200
  const sessionDurationMs = sessionDurationHours * 60 * 60 * 1000;
59139
59201
  const now = new Date;
59140
- const pattern = path6.posix.join(rootDir.replace(/\\/g, "/"), "projects", "**", "*.jsonl");
59202
+ const pattern = path7.posix.join(rootDir.replace(/\\/g, "/"), "projects", "**", "*.jsonl");
59141
59203
  const files = globSync([pattern], {
59142
59204
  absolute: true,
59143
59205
  cwd: rootDir
@@ -59231,7 +59293,7 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
59231
59293
  function getAllTimestampsFromFile(filePath) {
59232
59294
  const timestamps = [];
59233
59295
  try {
59234
- const content = readFileSync4(filePath, "utf-8");
59296
+ const content = readFileSync5(filePath, "utf-8");
59235
59297
  const lines = content.trim().split(`
59236
59298
  `).filter((line) => line.length > 0);
59237
59299
  for (const line of lines) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstatusline-usage",
3
- "version": "2.0.28",
3
+ "version": "2.0.30",
4
4
  "description": "A customizable status line formatter for Claude Code CLI",
5
5
  "module": "src/ccstatusline.ts",
6
6
  "type": "module",
@@ -8,7 +8,11 @@
8
8
  "ccstatusline": "dist/ccstatusline.js"
9
9
  },
10
10
  "files": [
11
- "dist/"
11
+ "dist/",
12
+ "scripts/usage.sh",
13
+ "scripts/context.sh",
14
+ "scripts/setup-enhanced.sh",
15
+ "defaults/"
12
16
  ],
13
17
  "scripts": {
14
18
  "start": "bun run src/ccstatusline.ts",
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+
3
+ CACHE_FILE="$HOME/.claude/.statusline/context.json"
4
+
5
+ make_bar() {
6
+ local pct="$1"
7
+ local width=15
8
+ local filled=$((pct * width / 100))
9
+ local empty=$((width - filled))
10
+ printf "["
11
+ printf "█%.0s" $(seq 1 "$filled")
12
+ printf "░%.0s" $(seq 1 "$empty")
13
+ printf "]"
14
+ }
15
+
16
+ format_tokens() {
17
+ local tokens="$1"
18
+ if [[ $tokens -ge 1000 ]]; then
19
+ echo "$((tokens / 1000))k"
20
+ else
21
+ echo "$tokens"
22
+ fi
23
+ }
24
+
25
+ if [[ ! -f "$CACHE_FILE" ]]; then
26
+ BAR=$(make_bar 0)
27
+ echo "Context: $BAR 0k/200k (0%)"
28
+ exit 0
29
+ fi
30
+
31
+ INPUT=$(cat "$CACHE_FILE")
32
+
33
+ MAX_TOKENS=$(echo "$INPUT" | jq -r '.context_window_size // empty')
34
+ CURRENT_USAGE=$(echo "$INPUT" | jq -r '.current_usage // empty')
35
+
36
+ if [[ -z "$MAX_TOKENS" || "$MAX_TOKENS" == "null" || -z "$CURRENT_USAGE" || "$CURRENT_USAGE" == "null" ]]; then
37
+ BAR=$(make_bar 0)
38
+ echo "Context: $BAR 0k/200k (0%)"
39
+ exit 0
40
+ fi
41
+
42
+ INPUT_TOKENS=$(echo "$INPUT" | jq -r '.current_usage.input_tokens // 0')
43
+ CACHE_CREATE=$(echo "$INPUT" | jq -r '.current_usage.cache_creation_input_tokens // 0')
44
+ CACHE_READ=$(echo "$INPUT" | jq -r '.current_usage.cache_read_input_tokens // 0')
45
+
46
+ CURRENT_TOKENS=$((INPUT_TOKENS + CACHE_CREATE + CACHE_READ))
47
+
48
+ if [[ $MAX_TOKENS -gt 0 ]]; then
49
+ PERCENT=$((CURRENT_TOKENS * 100 / MAX_TOKENS))
50
+ else
51
+ PERCENT=0
52
+ fi
53
+
54
+ CURRENT_FMT=$(format_tokens "$CURRENT_TOKENS")
55
+ MAX_FMT=$(format_tokens "$MAX_TOKENS")
56
+ BAR=$(make_bar "$PERCENT")
57
+
58
+ echo "Context: $BAR ${CURRENT_FMT}/${MAX_FMT} (${PERCENT}%)"
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # Setup script for ccstatusline-usage enhanced configuration
3
+ # Installs usage scripts and applies enhanced settings
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$HOME/.local/share/ccstatusline"
8
+ CONFIG_DIR="$HOME/.config/ccstatusline"
9
+ SETTINGS_FILE="$CONFIG_DIR/settings.json"
10
+
11
+ # Find the package directory (where this script is located)
12
+ PKG_DIR="$(cd "$(dirname "$0")/.." && pwd)"
13
+
14
+ echo "Setting up ccstatusline-usage enhanced configuration..."
15
+
16
+ # Create directories
17
+ mkdir -p "$SCRIPT_DIR"
18
+ mkdir -p "$CONFIG_DIR"
19
+
20
+ # Copy scripts
21
+ if [[ -f "$PKG_DIR/scripts/usage.sh" ]]; then
22
+ cp "$PKG_DIR/scripts/usage.sh" "$SCRIPT_DIR/"
23
+ chmod +x "$SCRIPT_DIR/usage.sh"
24
+ echo "✓ Installed usage.sh to $SCRIPT_DIR/"
25
+ else
26
+ echo "✗ usage.sh not found in package"
27
+ exit 1
28
+ fi
29
+
30
+ if [[ -f "$PKG_DIR/scripts/context.sh" ]]; then
31
+ cp "$PKG_DIR/scripts/context.sh" "$SCRIPT_DIR/"
32
+ chmod +x "$SCRIPT_DIR/context.sh"
33
+ echo "✓ Installed context.sh to $SCRIPT_DIR/"
34
+ else
35
+ echo "✗ context.sh not found in package"
36
+ exit 1
37
+ fi
38
+
39
+ # Create enhanced settings with correct paths
40
+ cat > "$SETTINGS_FILE" << 'EOF'
41
+ {
42
+ "version": 3,
43
+ "lines": [
44
+ [
45
+ {
46
+ "id": "session-usage",
47
+ "type": "custom-command",
48
+ "color": "brightBlue",
49
+ "commandPath": "$HOME/.local/share/ccstatusline/usage.sh session",
50
+ "timeout": 5000
51
+ },
52
+ {"id": "sep1", "type": "separator"},
53
+ {
54
+ "id": "weekly-usage",
55
+ "type": "custom-command",
56
+ "color": "brightBlue",
57
+ "commandPath": "$HOME/.local/share/ccstatusline/usage.sh weekly",
58
+ "timeout": 5000
59
+ },
60
+ {"id": "sep2", "type": "separator"},
61
+ {
62
+ "id": "reset-timer",
63
+ "type": "custom-command",
64
+ "color": "brightBlue",
65
+ "commandPath": "$HOME/.local/share/ccstatusline/usage.sh reset",
66
+ "timeout": 5000
67
+ },
68
+ {"id": "sep3", "type": "separator"},
69
+ {"id": "model", "type": "model", "color": "magenta"},
70
+ {"id": "sep4", "type": "separator"},
71
+ {"id": "session-id", "type": "claude-session-id", "color": "cyan"}
72
+ ],
73
+ [
74
+ {
75
+ "id": "context-usage",
76
+ "type": "custom-command",
77
+ "color": "blue",
78
+ "commandPath": "$HOME/.local/share/ccstatusline/context.sh",
79
+ "timeout": 5000
80
+ }
81
+ ],
82
+ []
83
+ ],
84
+ "flexMode": "full-minus-40",
85
+ "compactThreshold": 60,
86
+ "colorLevel": 2
87
+ }
88
+ EOF
89
+
90
+ # Expand $HOME in the settings file
91
+ sed -i.bak "s|\$HOME|$HOME|g" "$SETTINGS_FILE" && rm -f "$SETTINGS_FILE.bak"
92
+
93
+ echo "✓ Created enhanced settings at $SETTINGS_FILE"
94
+ echo ""
95
+ echo "Setup complete! Run 'npx ccstatusline-usage' to configure."
96
+ echo ""
97
+ echo "Note: The usage widgets require Anthropic API access."
98
+ echo "Make sure you have valid credentials in ~/.claude/credentials.json"
@@ -0,0 +1,147 @@
1
+ #!/bin/bash
2
+
3
+ # Cross-platform usage script for ccstatusline-usage
4
+ # Works on both macOS and Linux
5
+
6
+ CACHE_FILE="$HOME/.cache/ccstatusline-api.json"
7
+ LOCK_FILE="$HOME/.cache/ccstatusline-api.lock"
8
+
9
+ # Detect OS for platform-specific commands
10
+ is_macos() {
11
+ [[ "$(uname)" == "Darwin" ]]
12
+ }
13
+
14
+ # Get file modification time (seconds since epoch)
15
+ get_mtime() {
16
+ if is_macos; then
17
+ stat -f '%m' "$1" 2>/dev/null
18
+ else
19
+ stat -c '%Y' "$1" 2>/dev/null
20
+ fi
21
+ }
22
+
23
+ # Get OAuth token from credentials
24
+ get_token() {
25
+ if is_macos; then
26
+ # macOS: read from keychain
27
+ security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null | jq -r '.claudeAiOauth.accessToken // empty'
28
+ else
29
+ # Linux: read from credentials file
30
+ jq -r '.claudeAiOauth.accessToken // empty' ~/.claude/.credentials.json 2>/dev/null
31
+ fi
32
+ }
33
+
34
+ # Parse ISO date to epoch
35
+ parse_iso_date() {
36
+ local iso_date="$1"
37
+ # Remove fractional seconds and Z suffix
38
+ local clean_date="${iso_date%%.*}"
39
+ clean_date="${clean_date%%Z}"
40
+
41
+ if is_macos; then
42
+ TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%S" "$clean_date" "+%s" 2>/dev/null
43
+ else
44
+ # Linux: use date -d with ISO format
45
+ date -d "$clean_date" "+%s" 2>/dev/null
46
+ fi
47
+ }
48
+
49
+ fetch_api() {
50
+ local NOW=$(date +%s)
51
+
52
+ # Use cache if < 180 seconds old
53
+ if [[ -f "$CACHE_FILE" ]]; then
54
+ local MTIME=$(get_mtime "$CACHE_FILE")
55
+ if [[ -n "$MTIME" ]]; then
56
+ local CACHE_AGE=$((NOW - MTIME))
57
+ [[ $CACHE_AGE -lt 180 ]] && return 0
58
+ fi
59
+ fi
60
+
61
+ # Rate limit: only try API once per 30 seconds
62
+ if [[ -f "$LOCK_FILE" ]]; then
63
+ local LOCK_MTIME=$(get_mtime "$LOCK_FILE")
64
+ if [[ -n "$LOCK_MTIME" ]]; then
65
+ local LOCK_AGE=$((NOW - LOCK_MTIME))
66
+ if [[ $LOCK_AGE -lt 30 ]]; then
67
+ [[ -f "$CACHE_FILE" ]] && return 0
68
+ return 1
69
+ fi
70
+ fi
71
+ fi
72
+
73
+ touch "$LOCK_FILE"
74
+
75
+ TOKEN=$(get_token)
76
+ [[ -z "$TOKEN" ]] && return 1
77
+
78
+ RESPONSE=$(curl -s --max-time 5 "https://api.anthropic.com/api/oauth/usage" \
79
+ -H "Authorization: Bearer $TOKEN" \
80
+ -H "anthropic-beta: oauth-2025-04-20" 2>/dev/null)
81
+ [[ -z "$RESPONSE" ]] && return 1
82
+
83
+ # Ensure cache directory exists
84
+ mkdir -p "$(dirname "$CACHE_FILE")"
85
+ echo "$RESPONSE" > "$CACHE_FILE"
86
+ return 0
87
+ }
88
+
89
+ make_bar() {
90
+ local pct="$1"
91
+ local width=15
92
+ local filled=$((pct * width / 100))
93
+ local empty=$((width - filled))
94
+ printf "["
95
+ printf "█%.0s" $(seq 1 "$filled")
96
+ printf "░%.0s" $(seq 1 "$empty")
97
+ printf "]"
98
+ }
99
+
100
+ MODE="${1:-all}"
101
+
102
+ fetch_api || { echo "[API Error]"; exit 1; }
103
+
104
+ case "$MODE" in
105
+ session)
106
+ SESSION=$(jq -r '.five_hour.utilization // empty' "$CACHE_FILE" 2>/dev/null)
107
+ [[ -z "$SESSION" ]] && { echo "[Parse Error]"; exit 1; }
108
+ SESSION_INT=${SESSION%.*}
109
+ SESSION_BAR=$(make_bar "$SESSION_INT")
110
+ echo "Session: $SESSION_BAR ${SESSION}%"
111
+ ;;
112
+ weekly)
113
+ WEEKLY=$(jq -r '.seven_day.utilization // empty' "$CACHE_FILE" 2>/dev/null)
114
+ [[ -z "$WEEKLY" ]] && { echo "[Parse Error]"; exit 1; }
115
+ WEEKLY_INT=${WEEKLY%.*}
116
+ WEEKLY_BAR=$(make_bar "$WEEKLY_INT")
117
+ echo "Weekly: $WEEKLY_BAR ${WEEKLY}%"
118
+ ;;
119
+ reset)
120
+ RESETS_AT=$(jq -r '.five_hour.resets_at // empty' "$CACHE_FILE" 2>/dev/null)
121
+ [[ -z "$RESETS_AT" ]] && { echo "[Parse Error]"; exit 1; }
122
+ RESET_EPOCH=$(parse_iso_date "$RESETS_AT")
123
+ NOW_EPOCH=$(date -u +%s)
124
+ if [[ -z "$RESET_EPOCH" ]]; then
125
+ echo "[Date Error]"
126
+ exit 1
127
+ fi
128
+ DIFF=$((RESET_EPOCH - NOW_EPOCH))
129
+ if [[ $DIFF -le 0 ]]; then
130
+ echo "Reset now"
131
+ else
132
+ HOURS=$((DIFF / 3600))
133
+ MINUTES=$(((DIFF % 3600) / 60))
134
+ echo "${HOURS}:$(printf '%02d' $MINUTES) hr"
135
+ fi
136
+ ;;
137
+ *)
138
+ SESSION=$(jq -r '.five_hour.utilization // empty' "$CACHE_FILE" 2>/dev/null)
139
+ WEEKLY=$(jq -r '.seven_day.utilization // empty' "$CACHE_FILE" 2>/dev/null)
140
+ [[ -z "$SESSION" || -z "$WEEKLY" ]] && { echo "[Parse Error]"; exit 1; }
141
+ SESSION_INT=${SESSION%.*}
142
+ WEEKLY_INT=${WEEKLY%.*}
143
+ SESSION_BAR=$(make_bar "$SESSION_INT")
144
+ WEEKLY_BAR=$(make_bar "$WEEKLY_INT")
145
+ echo "Session: $SESSION_BAR ${SESSION}% | Weekly: $WEEKLY_BAR ${WEEKLY}%"
146
+ ;;
147
+ esac