ccstatusline-usage 2.0.28 → 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 +111 -74
- 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,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: "
|
|
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
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: "
|
|
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 }
|
|
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.
|
|
51453
|
+
var PACKAGE_VERSION = "2.0.29";
|
|
51454
51454
|
function getPackageVersion() {
|
|
51455
51455
|
if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
|
|
51456
51456
|
return PACKAGE_VERSION;
|
|
@@ -53812,8 +53812,33 @@ 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 < 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();
|
|
53817
53842
|
|
|
53818
53843
|
class CustomCommandWidget {
|
|
53819
53844
|
getDefaultColor() {
|
|
@@ -53850,6 +53875,17 @@ class CustomCommandWidget {
|
|
|
53850
53875
|
}
|
|
53851
53876
|
return null;
|
|
53852
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
|
+
}
|
|
53853
53889
|
render(item, context, settings) {
|
|
53854
53890
|
if (context.isPreview) {
|
|
53855
53891
|
return item.commandPath ? `[cmd: ${item.commandPath.substring(0, 20)}${item.commandPath.length > 20 ? "..." : ""}]` : "[No command]";
|
|
@@ -53857,7 +53893,8 @@ class CustomCommandWidget {
|
|
|
53857
53893
|
try {
|
|
53858
53894
|
const timeout = item.timeout ?? 1000;
|
|
53859
53895
|
const jsonInput = JSON.stringify(context.data);
|
|
53860
|
-
|
|
53896
|
+
const resolvedPath = this.resolveCommandPath(item.commandPath);
|
|
53897
|
+
let output = execSync7(resolvedPath, {
|
|
53861
53898
|
encoding: "utf8",
|
|
53862
53899
|
input: jsonInput,
|
|
53863
53900
|
timeout,
|
|
@@ -54278,13 +54315,13 @@ class CurrentWorkingDirWidget {
|
|
|
54278
54315
|
supportsColors(item) {
|
|
54279
54316
|
return true;
|
|
54280
54317
|
}
|
|
54281
|
-
abbreviatePath(
|
|
54318
|
+
abbreviatePath(path6) {
|
|
54282
54319
|
const homeDir = os5.homedir();
|
|
54283
|
-
const useBackslash =
|
|
54320
|
+
const useBackslash = path6.includes("\\") && !path6.includes("/");
|
|
54284
54321
|
const sep = useBackslash ? "\\" : "/";
|
|
54285
|
-
let normalizedPath =
|
|
54286
|
-
if (
|
|
54287
|
-
normalizedPath = "~" +
|
|
54322
|
+
let normalizedPath = path6;
|
|
54323
|
+
if (path6.startsWith(homeDir)) {
|
|
54324
|
+
normalizedPath = "~" + path6.slice(homeDir.length);
|
|
54288
54325
|
}
|
|
54289
54326
|
const parts = normalizedPath.split(/[\\/]+/).filter((part) => part !== "");
|
|
54290
54327
|
const abbreviated = parts.map((part, index) => {
|
|
@@ -58238,42 +58275,42 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
58238
58275
|
});
|
|
58239
58276
|
|
|
58240
58277
|
// src/utils/jsonl.ts
|
|
58241
|
-
import * as
|
|
58242
|
-
import
|
|
58278
|
+
import * as fs7 from "fs";
|
|
58279
|
+
import path7 from "node:path";
|
|
58243
58280
|
|
|
58244
58281
|
// node_modules/tinyglobby/dist/index.mjs
|
|
58245
|
-
import
|
|
58282
|
+
import path6, { posix } from "path";
|
|
58246
58283
|
|
|
58247
58284
|
// node_modules/fdir/dist/index.mjs
|
|
58248
58285
|
import { createRequire as createRequire2 } from "module";
|
|
58249
|
-
import { basename as basename2, dirname as
|
|
58286
|
+
import { basename as basename2, dirname as dirname3, normalize, relative, resolve as resolve2, sep } from "path";
|
|
58250
58287
|
import * as nativeFs from "fs";
|
|
58251
58288
|
var __require2 = /* @__PURE__ */ createRequire2(import.meta.url);
|
|
58252
|
-
function cleanPath(
|
|
58253
|
-
let normalized = normalize(
|
|
58289
|
+
function cleanPath(path6) {
|
|
58290
|
+
let normalized = normalize(path6);
|
|
58254
58291
|
if (normalized.length > 1 && normalized[normalized.length - 1] === sep)
|
|
58255
58292
|
normalized = normalized.substring(0, normalized.length - 1);
|
|
58256
58293
|
return normalized;
|
|
58257
58294
|
}
|
|
58258
58295
|
var SLASHES_REGEX = /[\\/]/g;
|
|
58259
|
-
function convertSlashes(
|
|
58260
|
-
return
|
|
58296
|
+
function convertSlashes(path6, separator) {
|
|
58297
|
+
return path6.replace(SLASHES_REGEX, separator);
|
|
58261
58298
|
}
|
|
58262
58299
|
var WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i;
|
|
58263
|
-
function isRootDirectory(
|
|
58264
|
-
return
|
|
58300
|
+
function isRootDirectory(path6) {
|
|
58301
|
+
return path6 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path6);
|
|
58265
58302
|
}
|
|
58266
|
-
function normalizePath(
|
|
58303
|
+
function normalizePath(path6, options) {
|
|
58267
58304
|
const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
|
|
58268
|
-
const pathNeedsCleaning = process.platform === "win32" &&
|
|
58305
|
+
const pathNeedsCleaning = process.platform === "win32" && path6.includes("/") || path6.startsWith(".");
|
|
58269
58306
|
if (resolvePaths)
|
|
58270
|
-
|
|
58307
|
+
path6 = resolve2(path6);
|
|
58271
58308
|
if (normalizePath$1 || pathNeedsCleaning)
|
|
58272
|
-
|
|
58273
|
-
if (
|
|
58309
|
+
path6 = cleanPath(path6);
|
|
58310
|
+
if (path6 === ".")
|
|
58274
58311
|
return "";
|
|
58275
|
-
const needsSeperator =
|
|
58276
|
-
return convertSlashes(needsSeperator ?
|
|
58312
|
+
const needsSeperator = path6[path6.length - 1] !== pathSeparator;
|
|
58313
|
+
return convertSlashes(needsSeperator ? path6 + pathSeparator : path6, pathSeparator);
|
|
58277
58314
|
}
|
|
58278
58315
|
function joinPathWithBasePath(filename, directoryPath) {
|
|
58279
58316
|
return directoryPath + filename;
|
|
@@ -58313,9 +58350,9 @@ var pushDirectory = (directoryPath, paths) => {
|
|
|
58313
58350
|
paths.push(directoryPath || ".");
|
|
58314
58351
|
};
|
|
58315
58352
|
var pushDirectoryFilter = (directoryPath, paths, filters) => {
|
|
58316
|
-
const
|
|
58317
|
-
if (filters.every((filter) => filter(
|
|
58318
|
-
paths.push(
|
|
58353
|
+
const path6 = directoryPath || ".";
|
|
58354
|
+
if (filters.every((filter) => filter(path6, true)))
|
|
58355
|
+
paths.push(path6);
|
|
58319
58356
|
};
|
|
58320
58357
|
var empty$2 = () => {};
|
|
58321
58358
|
function build$6(root, options) {
|
|
@@ -58372,29 +58409,29 @@ var empty = () => {};
|
|
|
58372
58409
|
function build$3(options) {
|
|
58373
58410
|
return options.group ? groupFiles : empty;
|
|
58374
58411
|
}
|
|
58375
|
-
var resolveSymlinksAsync = function(
|
|
58376
|
-
const { queue, fs:
|
|
58412
|
+
var resolveSymlinksAsync = function(path6, state, callback$1) {
|
|
58413
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
58377
58414
|
queue.enqueue();
|
|
58378
|
-
|
|
58415
|
+
fs7.realpath(path6, (error43, resolvedPath) => {
|
|
58379
58416
|
if (error43)
|
|
58380
58417
|
return queue.dequeue(suppressErrors ? null : error43, state);
|
|
58381
|
-
|
|
58418
|
+
fs7.stat(resolvedPath, (error$1, stat) => {
|
|
58382
58419
|
if (error$1)
|
|
58383
58420
|
return queue.dequeue(suppressErrors ? null : error$1, state);
|
|
58384
|
-
if (stat.isDirectory() && isRecursive(
|
|
58421
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
58385
58422
|
return queue.dequeue(null, state);
|
|
58386
58423
|
callback$1(stat, resolvedPath);
|
|
58387
58424
|
queue.dequeue(null, state);
|
|
58388
58425
|
});
|
|
58389
58426
|
});
|
|
58390
58427
|
};
|
|
58391
|
-
var resolveSymlinks = function(
|
|
58392
|
-
const { queue, fs:
|
|
58428
|
+
var resolveSymlinks = function(path6, state, callback$1) {
|
|
58429
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
58393
58430
|
queue.enqueue();
|
|
58394
58431
|
try {
|
|
58395
|
-
const resolvedPath =
|
|
58396
|
-
const stat =
|
|
58397
|
-
if (stat.isDirectory() && isRecursive(
|
|
58432
|
+
const resolvedPath = fs7.realpathSync(path6);
|
|
58433
|
+
const stat = fs7.statSync(resolvedPath);
|
|
58434
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
58398
58435
|
return;
|
|
58399
58436
|
callback$1(stat, resolvedPath);
|
|
58400
58437
|
} catch (e) {
|
|
@@ -58407,10 +58444,10 @@ function build$2(options, isSynchronous) {
|
|
|
58407
58444
|
return null;
|
|
58408
58445
|
return isSynchronous ? resolveSymlinks : resolveSymlinksAsync;
|
|
58409
58446
|
}
|
|
58410
|
-
function isRecursive(
|
|
58447
|
+
function isRecursive(path6, resolved, state) {
|
|
58411
58448
|
if (state.options.useRealPaths)
|
|
58412
58449
|
return isRecursiveUsingRealPaths(resolved, state);
|
|
58413
|
-
let parent =
|
|
58450
|
+
let parent = dirname3(path6);
|
|
58414
58451
|
let depth = 1;
|
|
58415
58452
|
while (parent !== state.root && depth < 2) {
|
|
58416
58453
|
const resolvedPath = state.symlinks.get(parent);
|
|
@@ -58418,9 +58455,9 @@ function isRecursive(path5, resolved, state) {
|
|
|
58418
58455
|
if (isSameRoot)
|
|
58419
58456
|
depth++;
|
|
58420
58457
|
else
|
|
58421
|
-
parent =
|
|
58458
|
+
parent = dirname3(parent);
|
|
58422
58459
|
}
|
|
58423
|
-
state.symlinks.set(
|
|
58460
|
+
state.symlinks.set(path6, resolved);
|
|
58424
58461
|
return depth > 1;
|
|
58425
58462
|
}
|
|
58426
58463
|
function isRecursiveUsingRealPaths(resolved, state) {
|
|
@@ -58476,23 +58513,23 @@ var walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
|
58476
58513
|
state.queue.enqueue();
|
|
58477
58514
|
if (currentDepth < 0)
|
|
58478
58515
|
return state.queue.dequeue(null, state);
|
|
58479
|
-
const { fs:
|
|
58516
|
+
const { fs: fs7 } = state;
|
|
58480
58517
|
state.visited.push(crawlPath);
|
|
58481
58518
|
state.counts.directories++;
|
|
58482
|
-
|
|
58519
|
+
fs7.readdir(crawlPath || ".", readdirOpts, (error43, entries = []) => {
|
|
58483
58520
|
callback$1(entries, directoryPath, currentDepth);
|
|
58484
58521
|
state.queue.dequeue(state.options.suppressErrors ? null : error43, state);
|
|
58485
58522
|
});
|
|
58486
58523
|
};
|
|
58487
58524
|
var walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
58488
|
-
const { fs:
|
|
58525
|
+
const { fs: fs7 } = state;
|
|
58489
58526
|
if (currentDepth < 0)
|
|
58490
58527
|
return;
|
|
58491
58528
|
state.visited.push(crawlPath);
|
|
58492
58529
|
state.counts.directories++;
|
|
58493
58530
|
let entries = [];
|
|
58494
58531
|
try {
|
|
58495
|
-
entries =
|
|
58532
|
+
entries = fs7.readdirSync(crawlPath || ".", readdirOpts);
|
|
58496
58533
|
} catch (e) {
|
|
58497
58534
|
if (!state.options.suppressErrors)
|
|
58498
58535
|
throw e;
|
|
@@ -58598,23 +58635,23 @@ var Walker = class {
|
|
|
58598
58635
|
const filename = this.joinPath(entry.name, directoryPath);
|
|
58599
58636
|
this.pushFile(filename, files, this.state.counts, filters);
|
|
58600
58637
|
} else if (entry.isDirectory()) {
|
|
58601
|
-
let
|
|
58602
|
-
if (exclude && exclude(entry.name,
|
|
58638
|
+
let path6 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
|
|
58639
|
+
if (exclude && exclude(entry.name, path6))
|
|
58603
58640
|
continue;
|
|
58604
|
-
this.pushDirectory(
|
|
58605
|
-
this.walkDirectory(this.state,
|
|
58641
|
+
this.pushDirectory(path6, paths, filters);
|
|
58642
|
+
this.walkDirectory(this.state, path6, path6, depth - 1, this.walk);
|
|
58606
58643
|
} else if (this.resolveSymlink && entry.isSymbolicLink()) {
|
|
58607
|
-
let
|
|
58608
|
-
this.resolveSymlink(
|
|
58644
|
+
let path6 = joinPathWithBasePath(entry.name, directoryPath);
|
|
58645
|
+
this.resolveSymlink(path6, this.state, (stat, resolvedPath) => {
|
|
58609
58646
|
if (stat.isDirectory()) {
|
|
58610
58647
|
resolvedPath = normalizePath(resolvedPath, this.state.options);
|
|
58611
|
-
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath :
|
|
58648
|
+
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path6 + pathSeparator))
|
|
58612
58649
|
return;
|
|
58613
|
-
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath :
|
|
58650
|
+
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path6 + pathSeparator, depth - 1, this.walk);
|
|
58614
58651
|
} else {
|
|
58615
|
-
resolvedPath = useRealPaths ? resolvedPath :
|
|
58652
|
+
resolvedPath = useRealPaths ? resolvedPath : path6;
|
|
58616
58653
|
const filename = basename2(resolvedPath);
|
|
58617
|
-
const directoryPath$1 = normalizePath(
|
|
58654
|
+
const directoryPath$1 = normalizePath(dirname3(resolvedPath), this.state.options);
|
|
58618
58655
|
resolvedPath = this.joinPath(filename, directoryPath$1);
|
|
58619
58656
|
this.pushFile(resolvedPath, files, this.state.counts, filters);
|
|
58620
58657
|
}
|
|
@@ -58772,7 +58809,7 @@ var Builder = class {
|
|
|
58772
58809
|
isMatch = globFn(patterns, ...options);
|
|
58773
58810
|
this.globCache[patterns.join("\x00")] = isMatch;
|
|
58774
58811
|
}
|
|
58775
|
-
this.options.filters.push((
|
|
58812
|
+
this.options.filters.push((path6) => isMatch(path6));
|
|
58776
58813
|
return this;
|
|
58777
58814
|
}
|
|
58778
58815
|
};
|
|
@@ -58851,7 +58888,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
58851
58888
|
if (!result.endsWith("*") && expandDirectories)
|
|
58852
58889
|
result += "/**";
|
|
58853
58890
|
const escapedCwd = escapePath(cwd2);
|
|
58854
|
-
if (
|
|
58891
|
+
if (path6.isAbsolute(result.replace(ESCAPING_BACKSLASHES, "")))
|
|
58855
58892
|
result = posix.relative(escapedCwd, result);
|
|
58856
58893
|
else
|
|
58857
58894
|
result = posix.normalize(result);
|
|
@@ -58888,7 +58925,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
58888
58925
|
}
|
|
58889
58926
|
props.depthOffset = newCommonPath.length;
|
|
58890
58927
|
props.commonPath = newCommonPath;
|
|
58891
|
-
props.root = newCommonPath.length > 0 ?
|
|
58928
|
+
props.root = newCommonPath.length > 0 ? path6.posix.join(cwd2, ...newCommonPath) : cwd2;
|
|
58892
58929
|
}
|
|
58893
58930
|
return result;
|
|
58894
58931
|
}
|
|
@@ -59021,18 +59058,18 @@ function globSync(patternsOrOptions, options) {
|
|
|
59021
59058
|
...options,
|
|
59022
59059
|
patterns: patternsOrOptions
|
|
59023
59060
|
} : patternsOrOptions;
|
|
59024
|
-
const cwd2 = opts.cwd ?
|
|
59061
|
+
const cwd2 = opts.cwd ? path6.resolve(opts.cwd).replace(BACKSLASHES, "/") : process.cwd().replace(BACKSLASHES, "/");
|
|
59025
59062
|
return crawl(opts, cwd2, true);
|
|
59026
59063
|
}
|
|
59027
59064
|
|
|
59028
59065
|
// src/utils/jsonl.ts
|
|
59029
59066
|
import { promisify } from "util";
|
|
59030
|
-
var readFile4 = promisify(
|
|
59031
|
-
var
|
|
59032
|
-
var statSync4 =
|
|
59067
|
+
var readFile4 = promisify(fs7.readFile);
|
|
59068
|
+
var readFileSync5 = fs7.readFileSync;
|
|
59069
|
+
var statSync4 = fs7.statSync;
|
|
59033
59070
|
async function getSessionDuration(transcriptPath) {
|
|
59034
59071
|
try {
|
|
59035
|
-
if (!
|
|
59072
|
+
if (!fs7.existsSync(transcriptPath)) {
|
|
59036
59073
|
return null;
|
|
59037
59074
|
}
|
|
59038
59075
|
const content = await readFile4(transcriptPath, "utf-8");
|
|
@@ -59084,7 +59121,7 @@ async function getSessionDuration(transcriptPath) {
|
|
|
59084
59121
|
}
|
|
59085
59122
|
async function getTokenMetrics(transcriptPath) {
|
|
59086
59123
|
try {
|
|
59087
|
-
if (!
|
|
59124
|
+
if (!fs7.existsSync(transcriptPath)) {
|
|
59088
59125
|
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
59089
59126
|
}
|
|
59090
59127
|
const content = await readFile4(transcriptPath, "utf-8");
|
|
@@ -59137,7 +59174,7 @@ function getBlockMetrics() {
|
|
|
59137
59174
|
function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
59138
59175
|
const sessionDurationMs = sessionDurationHours * 60 * 60 * 1000;
|
|
59139
59176
|
const now = new Date;
|
|
59140
|
-
const pattern =
|
|
59177
|
+
const pattern = path7.posix.join(rootDir.replace(/\\/g, "/"), "projects", "**", "*.jsonl");
|
|
59141
59178
|
const files = globSync([pattern], {
|
|
59142
59179
|
absolute: true,
|
|
59143
59180
|
cwd: rootDir
|
|
@@ -59231,7 +59268,7 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
|
59231
59268
|
function getAllTimestampsFromFile(filePath) {
|
|
59232
59269
|
const timestamps = [];
|
|
59233
59270
|
try {
|
|
59234
|
-
const content =
|
|
59271
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
59235
59272
|
const lines = content.trim().split(`
|
|
59236
59273
|
`).filter((line) => line.length > 0);
|
|
59237
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
|