ccstatusline-usage 2.0.27 → 2.0.29
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/defaults/settings-enhanced.json +73 -0
- package/dist/ccstatusline.js +115 -72
- package/package.json +6 -2
- package/scripts/context.sh +58 -0
- package/scripts/setup-enhanced.sh +98 -0
- package/scripts/usage.sh +147 -0
|
@@ -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
|
+
}
|
package/dist/ccstatusline.js
CHANGED
|
@@ -32383,8 +32383,8 @@ var require_utils = __commonJS((exports) => {
|
|
|
32383
32383
|
}
|
|
32384
32384
|
return output;
|
|
32385
32385
|
};
|
|
32386
|
-
exports.basename = (
|
|
32387
|
-
const segs =
|
|
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,13 +50982,19 @@ 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: "
|
|
50985
|
+
{ id: "session-usage", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh session", timeout: 5000 },
|
|
50986
50986
|
{ id: "sep1", type: "separator" },
|
|
50987
|
-
{ id: "
|
|
50987
|
+
{ id: "weekly-usage", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh weekly", timeout: 5000 },
|
|
50988
50988
|
{ id: "sep2", type: "separator" },
|
|
50989
|
-
{ id: "
|
|
50989
|
+
{ id: "reset-timer", type: "custom-command", color: "brightBlue", commandPath: "$PKG/scripts/usage.sh reset", timeout: 5000 },
|
|
50990
|
+
{ id: "sep3", type: "separator" },
|
|
50991
|
+
{ id: "model", type: "model", color: "magenta" },
|
|
50992
|
+
{ id: "sep4", type: "separator" },
|
|
50993
|
+
{ id: "session-id", type: "claude-session-id", color: "cyan" }
|
|
50994
|
+
],
|
|
50995
|
+
[
|
|
50996
|
+
{ id: "context-usage", type: "custom-command", color: "blue", commandPath: "$PKG/scripts/context.sh", timeout: 5000 }
|
|
50990
50997
|
],
|
|
50991
|
-
[],
|
|
50992
50998
|
[]
|
|
50993
50999
|
]),
|
|
50994
51000
|
flexMode: FlexModeSchema.default("full-minus-40"),
|
|
@@ -51444,7 +51450,7 @@ import { execSync as execSync3 } from "child_process";
|
|
|
51444
51450
|
import * as fs5 from "fs";
|
|
51445
51451
|
import * as path4 from "path";
|
|
51446
51452
|
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils";
|
|
51447
|
-
var PACKAGE_VERSION = "2.0.
|
|
51453
|
+
var PACKAGE_VERSION = "2.0.29";
|
|
51448
51454
|
function getPackageVersion() {
|
|
51449
51455
|
if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
|
|
51450
51456
|
return PACKAGE_VERSION;
|
|
@@ -53806,8 +53812,33 @@ var CustomTextEditor = ({ widget, onComplete, onCancel }) => {
|
|
|
53806
53812
|
};
|
|
53807
53813
|
// src/widgets/CustomCommand.tsx
|
|
53808
53814
|
import { execSync as execSync7 } from "child_process";
|
|
53815
|
+
import * as fs6 from "fs";
|
|
53809
53816
|
var import_react30 = __toESM(require_react(), 1);
|
|
53810
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 < 5; 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
|
+
dir = path5.dirname(dir);
|
|
53836
|
+
}
|
|
53837
|
+
} catch {}
|
|
53838
|
+
}
|
|
53839
|
+
return "";
|
|
53840
|
+
}
|
|
53841
|
+
var PKG_DIR = getPackageDir();
|
|
53811
53842
|
|
|
53812
53843
|
class CustomCommandWidget {
|
|
53813
53844
|
getDefaultColor() {
|
|
@@ -53844,6 +53875,17 @@ class CustomCommandWidget {
|
|
|
53844
53875
|
}
|
|
53845
53876
|
return null;
|
|
53846
53877
|
}
|
|
53878
|
+
resolveCommandPath(commandPath) {
|
|
53879
|
+
if (commandPath.startsWith("$PKG/") || commandPath.startsWith("$PACKAGE_DIR/")) {
|
|
53880
|
+
const relativePath = commandPath.replace(/^\$(PKG|PACKAGE_DIR)\//, "");
|
|
53881
|
+
const resolved = path5.join(PKG_DIR, relativePath);
|
|
53882
|
+
return resolved;
|
|
53883
|
+
}
|
|
53884
|
+
if (commandPath.startsWith("$HOME/")) {
|
|
53885
|
+
return commandPath.replace("$HOME", process.env.HOME ?? "~");
|
|
53886
|
+
}
|
|
53887
|
+
return commandPath;
|
|
53888
|
+
}
|
|
53847
53889
|
render(item, context, settings) {
|
|
53848
53890
|
if (context.isPreview) {
|
|
53849
53891
|
return item.commandPath ? `[cmd: ${item.commandPath.substring(0, 20)}${item.commandPath.length > 20 ? "..." : ""}]` : "[No command]";
|
|
@@ -53851,7 +53893,8 @@ class CustomCommandWidget {
|
|
|
53851
53893
|
try {
|
|
53852
53894
|
const timeout = item.timeout ?? 1000;
|
|
53853
53895
|
const jsonInput = JSON.stringify(context.data);
|
|
53854
|
-
|
|
53896
|
+
const resolvedPath = this.resolveCommandPath(item.commandPath);
|
|
53897
|
+
let output = execSync7(resolvedPath, {
|
|
53855
53898
|
encoding: "utf8",
|
|
53856
53899
|
input: jsonInput,
|
|
53857
53900
|
timeout,
|
|
@@ -54272,13 +54315,13 @@ class CurrentWorkingDirWidget {
|
|
|
54272
54315
|
supportsColors(item) {
|
|
54273
54316
|
return true;
|
|
54274
54317
|
}
|
|
54275
|
-
abbreviatePath(
|
|
54318
|
+
abbreviatePath(path6) {
|
|
54276
54319
|
const homeDir = os5.homedir();
|
|
54277
|
-
const useBackslash =
|
|
54320
|
+
const useBackslash = path6.includes("\\") && !path6.includes("/");
|
|
54278
54321
|
const sep = useBackslash ? "\\" : "/";
|
|
54279
|
-
let normalizedPath =
|
|
54280
|
-
if (
|
|
54281
|
-
normalizedPath = "~" +
|
|
54322
|
+
let normalizedPath = path6;
|
|
54323
|
+
if (path6.startsWith(homeDir)) {
|
|
54324
|
+
normalizedPath = "~" + path6.slice(homeDir.length);
|
|
54282
54325
|
}
|
|
54283
54326
|
const parts = normalizedPath.split(/[\\/]+/).filter((part) => part !== "");
|
|
54284
54327
|
const abbreviated = parts.map((part, index) => {
|
|
@@ -58232,42 +58275,42 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
58232
58275
|
});
|
|
58233
58276
|
|
|
58234
58277
|
// src/utils/jsonl.ts
|
|
58235
|
-
import * as
|
|
58236
|
-
import
|
|
58278
|
+
import * as fs7 from "fs";
|
|
58279
|
+
import path7 from "node:path";
|
|
58237
58280
|
|
|
58238
58281
|
// node_modules/tinyglobby/dist/index.mjs
|
|
58239
|
-
import
|
|
58282
|
+
import path6, { posix } from "path";
|
|
58240
58283
|
|
|
58241
58284
|
// node_modules/fdir/dist/index.mjs
|
|
58242
58285
|
import { createRequire as createRequire2 } from "module";
|
|
58243
|
-
import { basename as basename2, dirname as
|
|
58286
|
+
import { basename as basename2, dirname as dirname3, normalize, relative, resolve as resolve2, sep } from "path";
|
|
58244
58287
|
import * as nativeFs from "fs";
|
|
58245
58288
|
var __require2 = /* @__PURE__ */ createRequire2(import.meta.url);
|
|
58246
|
-
function cleanPath(
|
|
58247
|
-
let normalized = normalize(
|
|
58289
|
+
function cleanPath(path6) {
|
|
58290
|
+
let normalized = normalize(path6);
|
|
58248
58291
|
if (normalized.length > 1 && normalized[normalized.length - 1] === sep)
|
|
58249
58292
|
normalized = normalized.substring(0, normalized.length - 1);
|
|
58250
58293
|
return normalized;
|
|
58251
58294
|
}
|
|
58252
58295
|
var SLASHES_REGEX = /[\\/]/g;
|
|
58253
|
-
function convertSlashes(
|
|
58254
|
-
return
|
|
58296
|
+
function convertSlashes(path6, separator) {
|
|
58297
|
+
return path6.replace(SLASHES_REGEX, separator);
|
|
58255
58298
|
}
|
|
58256
58299
|
var WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i;
|
|
58257
|
-
function isRootDirectory(
|
|
58258
|
-
return
|
|
58300
|
+
function isRootDirectory(path6) {
|
|
58301
|
+
return path6 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path6);
|
|
58259
58302
|
}
|
|
58260
|
-
function normalizePath(
|
|
58303
|
+
function normalizePath(path6, options) {
|
|
58261
58304
|
const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
|
|
58262
|
-
const pathNeedsCleaning = process.platform === "win32" &&
|
|
58305
|
+
const pathNeedsCleaning = process.platform === "win32" && path6.includes("/") || path6.startsWith(".");
|
|
58263
58306
|
if (resolvePaths)
|
|
58264
|
-
|
|
58307
|
+
path6 = resolve2(path6);
|
|
58265
58308
|
if (normalizePath$1 || pathNeedsCleaning)
|
|
58266
|
-
|
|
58267
|
-
if (
|
|
58309
|
+
path6 = cleanPath(path6);
|
|
58310
|
+
if (path6 === ".")
|
|
58268
58311
|
return "";
|
|
58269
|
-
const needsSeperator =
|
|
58270
|
-
return convertSlashes(needsSeperator ?
|
|
58312
|
+
const needsSeperator = path6[path6.length - 1] !== pathSeparator;
|
|
58313
|
+
return convertSlashes(needsSeperator ? path6 + pathSeparator : path6, pathSeparator);
|
|
58271
58314
|
}
|
|
58272
58315
|
function joinPathWithBasePath(filename, directoryPath) {
|
|
58273
58316
|
return directoryPath + filename;
|
|
@@ -58307,9 +58350,9 @@ var pushDirectory = (directoryPath, paths) => {
|
|
|
58307
58350
|
paths.push(directoryPath || ".");
|
|
58308
58351
|
};
|
|
58309
58352
|
var pushDirectoryFilter = (directoryPath, paths, filters) => {
|
|
58310
|
-
const
|
|
58311
|
-
if (filters.every((filter) => filter(
|
|
58312
|
-
paths.push(
|
|
58353
|
+
const path6 = directoryPath || ".";
|
|
58354
|
+
if (filters.every((filter) => filter(path6, true)))
|
|
58355
|
+
paths.push(path6);
|
|
58313
58356
|
};
|
|
58314
58357
|
var empty$2 = () => {};
|
|
58315
58358
|
function build$6(root, options) {
|
|
@@ -58366,29 +58409,29 @@ var empty = () => {};
|
|
|
58366
58409
|
function build$3(options) {
|
|
58367
58410
|
return options.group ? groupFiles : empty;
|
|
58368
58411
|
}
|
|
58369
|
-
var resolveSymlinksAsync = function(
|
|
58370
|
-
const { queue, fs:
|
|
58412
|
+
var resolveSymlinksAsync = function(path6, state, callback$1) {
|
|
58413
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
58371
58414
|
queue.enqueue();
|
|
58372
|
-
|
|
58415
|
+
fs7.realpath(path6, (error43, resolvedPath) => {
|
|
58373
58416
|
if (error43)
|
|
58374
58417
|
return queue.dequeue(suppressErrors ? null : error43, state);
|
|
58375
|
-
|
|
58418
|
+
fs7.stat(resolvedPath, (error$1, stat) => {
|
|
58376
58419
|
if (error$1)
|
|
58377
58420
|
return queue.dequeue(suppressErrors ? null : error$1, state);
|
|
58378
|
-
if (stat.isDirectory() && isRecursive(
|
|
58421
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
58379
58422
|
return queue.dequeue(null, state);
|
|
58380
58423
|
callback$1(stat, resolvedPath);
|
|
58381
58424
|
queue.dequeue(null, state);
|
|
58382
58425
|
});
|
|
58383
58426
|
});
|
|
58384
58427
|
};
|
|
58385
|
-
var resolveSymlinks = function(
|
|
58386
|
-
const { queue, fs:
|
|
58428
|
+
var resolveSymlinks = function(path6, state, callback$1) {
|
|
58429
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
58387
58430
|
queue.enqueue();
|
|
58388
58431
|
try {
|
|
58389
|
-
const resolvedPath =
|
|
58390
|
-
const stat =
|
|
58391
|
-
if (stat.isDirectory() && isRecursive(
|
|
58432
|
+
const resolvedPath = fs7.realpathSync(path6);
|
|
58433
|
+
const stat = fs7.statSync(resolvedPath);
|
|
58434
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
58392
58435
|
return;
|
|
58393
58436
|
callback$1(stat, resolvedPath);
|
|
58394
58437
|
} catch (e) {
|
|
@@ -58401,10 +58444,10 @@ function build$2(options, isSynchronous) {
|
|
|
58401
58444
|
return null;
|
|
58402
58445
|
return isSynchronous ? resolveSymlinks : resolveSymlinksAsync;
|
|
58403
58446
|
}
|
|
58404
|
-
function isRecursive(
|
|
58447
|
+
function isRecursive(path6, resolved, state) {
|
|
58405
58448
|
if (state.options.useRealPaths)
|
|
58406
58449
|
return isRecursiveUsingRealPaths(resolved, state);
|
|
58407
|
-
let parent =
|
|
58450
|
+
let parent = dirname3(path6);
|
|
58408
58451
|
let depth = 1;
|
|
58409
58452
|
while (parent !== state.root && depth < 2) {
|
|
58410
58453
|
const resolvedPath = state.symlinks.get(parent);
|
|
@@ -58412,9 +58455,9 @@ function isRecursive(path5, resolved, state) {
|
|
|
58412
58455
|
if (isSameRoot)
|
|
58413
58456
|
depth++;
|
|
58414
58457
|
else
|
|
58415
|
-
parent =
|
|
58458
|
+
parent = dirname3(parent);
|
|
58416
58459
|
}
|
|
58417
|
-
state.symlinks.set(
|
|
58460
|
+
state.symlinks.set(path6, resolved);
|
|
58418
58461
|
return depth > 1;
|
|
58419
58462
|
}
|
|
58420
58463
|
function isRecursiveUsingRealPaths(resolved, state) {
|
|
@@ -58470,23 +58513,23 @@ var walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
|
58470
58513
|
state.queue.enqueue();
|
|
58471
58514
|
if (currentDepth < 0)
|
|
58472
58515
|
return state.queue.dequeue(null, state);
|
|
58473
|
-
const { fs:
|
|
58516
|
+
const { fs: fs7 } = state;
|
|
58474
58517
|
state.visited.push(crawlPath);
|
|
58475
58518
|
state.counts.directories++;
|
|
58476
|
-
|
|
58519
|
+
fs7.readdir(crawlPath || ".", readdirOpts, (error43, entries = []) => {
|
|
58477
58520
|
callback$1(entries, directoryPath, currentDepth);
|
|
58478
58521
|
state.queue.dequeue(state.options.suppressErrors ? null : error43, state);
|
|
58479
58522
|
});
|
|
58480
58523
|
};
|
|
58481
58524
|
var walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
58482
|
-
const { fs:
|
|
58525
|
+
const { fs: fs7 } = state;
|
|
58483
58526
|
if (currentDepth < 0)
|
|
58484
58527
|
return;
|
|
58485
58528
|
state.visited.push(crawlPath);
|
|
58486
58529
|
state.counts.directories++;
|
|
58487
58530
|
let entries = [];
|
|
58488
58531
|
try {
|
|
58489
|
-
entries =
|
|
58532
|
+
entries = fs7.readdirSync(crawlPath || ".", readdirOpts);
|
|
58490
58533
|
} catch (e) {
|
|
58491
58534
|
if (!state.options.suppressErrors)
|
|
58492
58535
|
throw e;
|
|
@@ -58592,23 +58635,23 @@ var Walker = class {
|
|
|
58592
58635
|
const filename = this.joinPath(entry.name, directoryPath);
|
|
58593
58636
|
this.pushFile(filename, files, this.state.counts, filters);
|
|
58594
58637
|
} else if (entry.isDirectory()) {
|
|
58595
|
-
let
|
|
58596
|
-
if (exclude && exclude(entry.name,
|
|
58638
|
+
let path6 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
|
|
58639
|
+
if (exclude && exclude(entry.name, path6))
|
|
58597
58640
|
continue;
|
|
58598
|
-
this.pushDirectory(
|
|
58599
|
-
this.walkDirectory(this.state,
|
|
58641
|
+
this.pushDirectory(path6, paths, filters);
|
|
58642
|
+
this.walkDirectory(this.state, path6, path6, depth - 1, this.walk);
|
|
58600
58643
|
} else if (this.resolveSymlink && entry.isSymbolicLink()) {
|
|
58601
|
-
let
|
|
58602
|
-
this.resolveSymlink(
|
|
58644
|
+
let path6 = joinPathWithBasePath(entry.name, directoryPath);
|
|
58645
|
+
this.resolveSymlink(path6, this.state, (stat, resolvedPath) => {
|
|
58603
58646
|
if (stat.isDirectory()) {
|
|
58604
58647
|
resolvedPath = normalizePath(resolvedPath, this.state.options);
|
|
58605
|
-
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath :
|
|
58648
|
+
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path6 + pathSeparator))
|
|
58606
58649
|
return;
|
|
58607
|
-
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath :
|
|
58650
|
+
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path6 + pathSeparator, depth - 1, this.walk);
|
|
58608
58651
|
} else {
|
|
58609
|
-
resolvedPath = useRealPaths ? resolvedPath :
|
|
58652
|
+
resolvedPath = useRealPaths ? resolvedPath : path6;
|
|
58610
58653
|
const filename = basename2(resolvedPath);
|
|
58611
|
-
const directoryPath$1 = normalizePath(
|
|
58654
|
+
const directoryPath$1 = normalizePath(dirname3(resolvedPath), this.state.options);
|
|
58612
58655
|
resolvedPath = this.joinPath(filename, directoryPath$1);
|
|
58613
58656
|
this.pushFile(resolvedPath, files, this.state.counts, filters);
|
|
58614
58657
|
}
|
|
@@ -58766,7 +58809,7 @@ var Builder = class {
|
|
|
58766
58809
|
isMatch = globFn(patterns, ...options);
|
|
58767
58810
|
this.globCache[patterns.join("\x00")] = isMatch;
|
|
58768
58811
|
}
|
|
58769
|
-
this.options.filters.push((
|
|
58812
|
+
this.options.filters.push((path6) => isMatch(path6));
|
|
58770
58813
|
return this;
|
|
58771
58814
|
}
|
|
58772
58815
|
};
|
|
@@ -58845,7 +58888,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
58845
58888
|
if (!result.endsWith("*") && expandDirectories)
|
|
58846
58889
|
result += "/**";
|
|
58847
58890
|
const escapedCwd = escapePath(cwd2);
|
|
58848
|
-
if (
|
|
58891
|
+
if (path6.isAbsolute(result.replace(ESCAPING_BACKSLASHES, "")))
|
|
58849
58892
|
result = posix.relative(escapedCwd, result);
|
|
58850
58893
|
else
|
|
58851
58894
|
result = posix.normalize(result);
|
|
@@ -58882,7 +58925,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
58882
58925
|
}
|
|
58883
58926
|
props.depthOffset = newCommonPath.length;
|
|
58884
58927
|
props.commonPath = newCommonPath;
|
|
58885
|
-
props.root = newCommonPath.length > 0 ?
|
|
58928
|
+
props.root = newCommonPath.length > 0 ? path6.posix.join(cwd2, ...newCommonPath) : cwd2;
|
|
58886
58929
|
}
|
|
58887
58930
|
return result;
|
|
58888
58931
|
}
|
|
@@ -59015,18 +59058,18 @@ function globSync(patternsOrOptions, options) {
|
|
|
59015
59058
|
...options,
|
|
59016
59059
|
patterns: patternsOrOptions
|
|
59017
59060
|
} : patternsOrOptions;
|
|
59018
|
-
const cwd2 = opts.cwd ?
|
|
59061
|
+
const cwd2 = opts.cwd ? path6.resolve(opts.cwd).replace(BACKSLASHES, "/") : process.cwd().replace(BACKSLASHES, "/");
|
|
59019
59062
|
return crawl(opts, cwd2, true);
|
|
59020
59063
|
}
|
|
59021
59064
|
|
|
59022
59065
|
// src/utils/jsonl.ts
|
|
59023
59066
|
import { promisify } from "util";
|
|
59024
|
-
var readFile4 = promisify(
|
|
59025
|
-
var
|
|
59026
|
-
var statSync4 =
|
|
59067
|
+
var readFile4 = promisify(fs7.readFile);
|
|
59068
|
+
var readFileSync5 = fs7.readFileSync;
|
|
59069
|
+
var statSync4 = fs7.statSync;
|
|
59027
59070
|
async function getSessionDuration(transcriptPath) {
|
|
59028
59071
|
try {
|
|
59029
|
-
if (!
|
|
59072
|
+
if (!fs7.existsSync(transcriptPath)) {
|
|
59030
59073
|
return null;
|
|
59031
59074
|
}
|
|
59032
59075
|
const content = await readFile4(transcriptPath, "utf-8");
|
|
@@ -59078,7 +59121,7 @@ async function getSessionDuration(transcriptPath) {
|
|
|
59078
59121
|
}
|
|
59079
59122
|
async function getTokenMetrics(transcriptPath) {
|
|
59080
59123
|
try {
|
|
59081
|
-
if (!
|
|
59124
|
+
if (!fs7.existsSync(transcriptPath)) {
|
|
59082
59125
|
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
59083
59126
|
}
|
|
59084
59127
|
const content = await readFile4(transcriptPath, "utf-8");
|
|
@@ -59131,7 +59174,7 @@ function getBlockMetrics() {
|
|
|
59131
59174
|
function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
59132
59175
|
const sessionDurationMs = sessionDurationHours * 60 * 60 * 1000;
|
|
59133
59176
|
const now = new Date;
|
|
59134
|
-
const pattern =
|
|
59177
|
+
const pattern = path7.posix.join(rootDir.replace(/\\/g, "/"), "projects", "**", "*.jsonl");
|
|
59135
59178
|
const files = globSync([pattern], {
|
|
59136
59179
|
absolute: true,
|
|
59137
59180
|
cwd: rootDir
|
|
@@ -59225,7 +59268,7 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
|
59225
59268
|
function getAllTimestampsFromFile(filePath) {
|
|
59226
59269
|
const timestamps = [];
|
|
59227
59270
|
try {
|
|
59228
|
-
const content =
|
|
59271
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
59229
59272
|
const lines = content.trim().split(`
|
|
59230
59273
|
`).filter((line) => line.length > 0);
|
|
59231
59274
|
for (const line of lines) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccstatusline-usage",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.29",
|
|
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"
|
package/scripts/usage.sh
ADDED
|
@@ -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
|