ccstatusline 2.1.6 → 2.1.8
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/README.md +8 -3
- package/dist/ccstatusline.js +1044 -779
- package/package.json +2 -2
package/dist/ccstatusline.js
CHANGED
|
@@ -32056,8 +32056,8 @@ var require_utils = __commonJS((exports) => {
|
|
|
32056
32056
|
}
|
|
32057
32057
|
return output;
|
|
32058
32058
|
};
|
|
32059
|
-
exports.basename = (
|
|
32060
|
-
const segs =
|
|
32059
|
+
exports.basename = (path6, { windows } = {}) => {
|
|
32060
|
+
const segs = path6.split(windows ? /[\\/]/ : "/");
|
|
32061
32061
|
const last = segs[segs.length - 1];
|
|
32062
32062
|
if (last === "") {
|
|
32063
32063
|
return segs[segs.length - 2];
|
|
@@ -32408,7 +32408,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
32408
32408
|
var syntaxError = (type, char) => {
|
|
32409
32409
|
return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
|
|
32410
32410
|
};
|
|
32411
|
-
var
|
|
32411
|
+
var parse6 = (input, options) => {
|
|
32412
32412
|
if (typeof input !== "string") {
|
|
32413
32413
|
throw new TypeError("Expected a string");
|
|
32414
32414
|
}
|
|
@@ -32557,7 +32557,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
32557
32557
|
output = token.close = `)$))${extglobStar}`;
|
|
32558
32558
|
}
|
|
32559
32559
|
if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
|
|
32560
|
-
const expression =
|
|
32560
|
+
const expression = parse6(rest, { ...options, fastpaths: false }).output;
|
|
32561
32561
|
output = token.close = `)${expression})${extglobStar})`;
|
|
32562
32562
|
}
|
|
32563
32563
|
if (token.prev.type === "bos") {
|
|
@@ -33083,7 +33083,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
33083
33083
|
}
|
|
33084
33084
|
return state;
|
|
33085
33085
|
};
|
|
33086
|
-
|
|
33086
|
+
parse6.fastpaths = (input, options) => {
|
|
33087
33087
|
const opts = { ...options };
|
|
33088
33088
|
const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
|
|
33089
33089
|
const len = input.length;
|
|
@@ -33151,13 +33151,13 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
33151
33151
|
}
|
|
33152
33152
|
return source;
|
|
33153
33153
|
};
|
|
33154
|
-
module.exports =
|
|
33154
|
+
module.exports = parse6;
|
|
33155
33155
|
});
|
|
33156
33156
|
|
|
33157
33157
|
// node_modules/picomatch/lib/picomatch.js
|
|
33158
33158
|
var require_picomatch = __commonJS((exports, module) => {
|
|
33159
33159
|
var scan = require_scan();
|
|
33160
|
-
var
|
|
33160
|
+
var parse6 = require_parse();
|
|
33161
33161
|
var utils = require_utils();
|
|
33162
33162
|
var constants2 = require_constants3();
|
|
33163
33163
|
var isObject2 = (val) => val && typeof val === "object" && !Array.isArray(val);
|
|
@@ -33247,7 +33247,7 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
33247
33247
|
picomatch.parse = (pattern, options) => {
|
|
33248
33248
|
if (Array.isArray(pattern))
|
|
33249
33249
|
return pattern.map((p) => picomatch.parse(p, options));
|
|
33250
|
-
return
|
|
33250
|
+
return parse6(pattern, { ...options, fastpaths: false });
|
|
33251
33251
|
};
|
|
33252
33252
|
picomatch.scan = (input, options) => scan(input, options);
|
|
33253
33253
|
picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
|
|
@@ -33273,10 +33273,10 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
33273
33273
|
}
|
|
33274
33274
|
let parsed = { negated: false, fastpaths: true };
|
|
33275
33275
|
if (options.fastpaths !== false && (input[0] === "." || input[0] === "*")) {
|
|
33276
|
-
parsed.output =
|
|
33276
|
+
parsed.output = parse6.fastpaths(input, options);
|
|
33277
33277
|
}
|
|
33278
33278
|
if (!parsed.output) {
|
|
33279
|
-
parsed =
|
|
33279
|
+
parsed = parse6(input, options);
|
|
33280
33280
|
}
|
|
33281
33281
|
return picomatch.compileRe(parsed, options, returnOutput, returnState);
|
|
33282
33282
|
};
|
|
@@ -39277,108 +39277,15 @@ var import_react46 = __toESM(require_react(), 1);
|
|
|
39277
39277
|
|
|
39278
39278
|
// src/utils/claude-settings.ts
|
|
39279
39279
|
import { execSync } from "child_process";
|
|
39280
|
-
import * as fs2 from "fs";
|
|
39281
|
-
import * as os2 from "os";
|
|
39282
|
-
import * as path from "path";
|
|
39283
|
-
var readFile = fs2.promises.readFile;
|
|
39284
|
-
var writeFile = fs2.promises.writeFile;
|
|
39285
|
-
var mkdir = fs2.promises.mkdir;
|
|
39286
|
-
var CCSTATUSLINE_COMMANDS = {
|
|
39287
|
-
NPM: "npx -y ccstatusline@latest",
|
|
39288
|
-
BUNX: "bunx -y ccstatusline@latest",
|
|
39289
|
-
SELF_MANAGED: "ccstatusline"
|
|
39290
|
-
};
|
|
39291
|
-
function getClaudeConfigDir() {
|
|
39292
|
-
const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
|
39293
|
-
if (envConfigDir) {
|
|
39294
|
-
try {
|
|
39295
|
-
const resolvedPath = path.resolve(envConfigDir);
|
|
39296
|
-
if (fs2.existsSync(resolvedPath)) {
|
|
39297
|
-
const stats = fs2.statSync(resolvedPath);
|
|
39298
|
-
if (stats.isDirectory()) {
|
|
39299
|
-
return resolvedPath;
|
|
39300
|
-
}
|
|
39301
|
-
} else {
|
|
39302
|
-
return resolvedPath;
|
|
39303
|
-
}
|
|
39304
|
-
} catch {}
|
|
39305
|
-
}
|
|
39306
|
-
return path.join(os2.homedir(), ".claude");
|
|
39307
|
-
}
|
|
39308
|
-
function getClaudeSettingsPath() {
|
|
39309
|
-
return path.join(getClaudeConfigDir(), "settings.json");
|
|
39310
|
-
}
|
|
39311
|
-
async function loadClaudeSettings() {
|
|
39312
|
-
try {
|
|
39313
|
-
const settingsPath = getClaudeSettingsPath();
|
|
39314
|
-
if (!fs2.existsSync(settingsPath)) {
|
|
39315
|
-
return {};
|
|
39316
|
-
}
|
|
39317
|
-
const content = await readFile(settingsPath, "utf-8");
|
|
39318
|
-
return JSON.parse(content);
|
|
39319
|
-
} catch {
|
|
39320
|
-
return {};
|
|
39321
|
-
}
|
|
39322
|
-
}
|
|
39323
|
-
async function saveClaudeSettings(settings) {
|
|
39324
|
-
const settingsPath = getClaudeSettingsPath();
|
|
39325
|
-
const dir = path.dirname(settingsPath);
|
|
39326
|
-
await mkdir(dir, { recursive: true });
|
|
39327
|
-
await writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
39328
|
-
}
|
|
39329
|
-
async function isInstalled() {
|
|
39330
|
-
const settings = await loadClaudeSettings();
|
|
39331
|
-
const validCommands = [
|
|
39332
|
-
CCSTATUSLINE_COMMANDS.NPM,
|
|
39333
|
-
CCSTATUSLINE_COMMANDS.BUNX,
|
|
39334
|
-
CCSTATUSLINE_COMMANDS.SELF_MANAGED
|
|
39335
|
-
];
|
|
39336
|
-
return validCommands.includes(settings.statusLine?.command ?? "") && (settings.statusLine?.padding === 0 || settings.statusLine?.padding === undefined);
|
|
39337
|
-
}
|
|
39338
|
-
function isBunxAvailable() {
|
|
39339
|
-
try {
|
|
39340
|
-
const command = process.platform === "win32" ? "where bunx" : "which bunx";
|
|
39341
|
-
execSync(command, { stdio: "ignore" });
|
|
39342
|
-
return true;
|
|
39343
|
-
} catch {
|
|
39344
|
-
return false;
|
|
39345
|
-
}
|
|
39346
|
-
}
|
|
39347
|
-
async function installStatusLine(useBunx = false) {
|
|
39348
|
-
const settings = await loadClaudeSettings();
|
|
39349
|
-
settings.statusLine = {
|
|
39350
|
-
type: "command",
|
|
39351
|
-
command: useBunx ? CCSTATUSLINE_COMMANDS.BUNX : CCSTATUSLINE_COMMANDS.NPM,
|
|
39352
|
-
padding: 0
|
|
39353
|
-
};
|
|
39354
|
-
await saveClaudeSettings(settings);
|
|
39355
|
-
}
|
|
39356
|
-
async function uninstallStatusLine() {
|
|
39357
|
-
const settings = await loadClaudeSettings();
|
|
39358
|
-
if (settings.statusLine) {
|
|
39359
|
-
delete settings.statusLine;
|
|
39360
|
-
await saveClaudeSettings(settings);
|
|
39361
|
-
}
|
|
39362
|
-
}
|
|
39363
|
-
async function getExistingStatusLine() {
|
|
39364
|
-
const settings = await loadClaudeSettings();
|
|
39365
|
-
return settings.statusLine?.command ?? null;
|
|
39366
|
-
}
|
|
39367
|
-
|
|
39368
|
-
// src/utils/clone-settings.ts
|
|
39369
|
-
function cloneSettings(settings) {
|
|
39370
|
-
const cloneFn = globalThis.structuredClone;
|
|
39371
|
-
if (typeof cloneFn === "function") {
|
|
39372
|
-
return cloneFn(settings);
|
|
39373
|
-
}
|
|
39374
|
-
return JSON.parse(JSON.stringify(settings));
|
|
39375
|
-
}
|
|
39376
|
-
|
|
39377
|
-
// src/utils/config.ts
|
|
39378
39280
|
import * as fs3 from "fs";
|
|
39379
39281
|
import * as os3 from "os";
|
|
39380
39282
|
import * as path2 from "path";
|
|
39381
39283
|
|
|
39284
|
+
// src/utils/config.ts
|
|
39285
|
+
import * as fs2 from "fs";
|
|
39286
|
+
import * as os2 from "os";
|
|
39287
|
+
import * as path from "path";
|
|
39288
|
+
|
|
39382
39289
|
// node_modules/zod/v4/classic/external.js
|
|
39383
39290
|
var exports_external = {};
|
|
39384
39291
|
__export(exports_external, {
|
|
@@ -40060,15 +39967,15 @@ function mergeDefs(...defs) {
|
|
|
40060
39967
|
function cloneDef(schema) {
|
|
40061
39968
|
return mergeDefs(schema._zod.def);
|
|
40062
39969
|
}
|
|
40063
|
-
function getElementAtPath(obj,
|
|
40064
|
-
if (!
|
|
39970
|
+
function getElementAtPath(obj, path) {
|
|
39971
|
+
if (!path)
|
|
40065
39972
|
return obj;
|
|
40066
|
-
return
|
|
39973
|
+
return path.reduce((acc, key) => acc?.[key], obj);
|
|
40067
39974
|
}
|
|
40068
39975
|
function promiseAllObject(promisesObj) {
|
|
40069
39976
|
const keys = Object.keys(promisesObj);
|
|
40070
|
-
const
|
|
40071
|
-
return Promise.all(
|
|
39977
|
+
const promises = keys.map((key) => promisesObj[key]);
|
|
39978
|
+
return Promise.all(promises).then((results) => {
|
|
40072
39979
|
const resolvedObj = {};
|
|
40073
39980
|
for (let i = 0;i < keys.length; i++) {
|
|
40074
39981
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -40398,11 +40305,11 @@ function aborted(x, startIndex = 0) {
|
|
|
40398
40305
|
}
|
|
40399
40306
|
return false;
|
|
40400
40307
|
}
|
|
40401
|
-
function prefixIssues(
|
|
40308
|
+
function prefixIssues(path, issues) {
|
|
40402
40309
|
return issues.map((iss) => {
|
|
40403
40310
|
var _a;
|
|
40404
40311
|
(_a = iss).path ?? (_a.path = []);
|
|
40405
|
-
iss.path.unshift(
|
|
40312
|
+
iss.path.unshift(path);
|
|
40406
40313
|
return iss;
|
|
40407
40314
|
});
|
|
40408
40315
|
}
|
|
@@ -40533,7 +40440,7 @@ function treeifyError(error, _mapper) {
|
|
|
40533
40440
|
return issue2.message;
|
|
40534
40441
|
};
|
|
40535
40442
|
const result = { errors: [] };
|
|
40536
|
-
const processError = (error2,
|
|
40443
|
+
const processError = (error2, path = []) => {
|
|
40537
40444
|
var _a, _b;
|
|
40538
40445
|
for (const issue2 of error2.issues) {
|
|
40539
40446
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -40543,7 +40450,7 @@ function treeifyError(error, _mapper) {
|
|
|
40543
40450
|
} else if (issue2.code === "invalid_element") {
|
|
40544
40451
|
processError({ issues: issue2.issues }, issue2.path);
|
|
40545
40452
|
} else {
|
|
40546
|
-
const fullpath = [...
|
|
40453
|
+
const fullpath = [...path, ...issue2.path];
|
|
40547
40454
|
if (fullpath.length === 0) {
|
|
40548
40455
|
result.errors.push(mapper(issue2));
|
|
40549
40456
|
continue;
|
|
@@ -40575,8 +40482,8 @@ function treeifyError(error, _mapper) {
|
|
|
40575
40482
|
}
|
|
40576
40483
|
function toDotPath(_path) {
|
|
40577
40484
|
const segs = [];
|
|
40578
|
-
const
|
|
40579
|
-
for (const seg of
|
|
40485
|
+
const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
40486
|
+
for (const seg of path) {
|
|
40580
40487
|
if (typeof seg === "number")
|
|
40581
40488
|
segs.push(`[${seg}]`);
|
|
40582
40489
|
else if (typeof seg === "symbol")
|
|
@@ -50999,6 +50906,84 @@ function generateGuid() {
|
|
|
50999
50906
|
function isRecord(value) {
|
|
51000
50907
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
51001
50908
|
}
|
|
50909
|
+
var V1_FIELD_RULES = [
|
|
50910
|
+
{
|
|
50911
|
+
key: "flexMode",
|
|
50912
|
+
isValid: (value) => typeof value === "string"
|
|
50913
|
+
},
|
|
50914
|
+
{
|
|
50915
|
+
key: "compactThreshold",
|
|
50916
|
+
isValid: (value) => typeof value === "number"
|
|
50917
|
+
},
|
|
50918
|
+
{
|
|
50919
|
+
key: "colorLevel",
|
|
50920
|
+
isValid: (value) => typeof value === "number"
|
|
50921
|
+
},
|
|
50922
|
+
{
|
|
50923
|
+
key: "defaultSeparator",
|
|
50924
|
+
isValid: (value) => typeof value === "string"
|
|
50925
|
+
},
|
|
50926
|
+
{
|
|
50927
|
+
key: "defaultPadding",
|
|
50928
|
+
isValid: (value) => typeof value === "string"
|
|
50929
|
+
},
|
|
50930
|
+
{
|
|
50931
|
+
key: "inheritSeparatorColors",
|
|
50932
|
+
isValid: (value) => typeof value === "boolean"
|
|
50933
|
+
},
|
|
50934
|
+
{
|
|
50935
|
+
key: "overrideBackgroundColor",
|
|
50936
|
+
isValid: (value) => typeof value === "string"
|
|
50937
|
+
},
|
|
50938
|
+
{
|
|
50939
|
+
key: "overrideForegroundColor",
|
|
50940
|
+
isValid: (value) => typeof value === "string"
|
|
50941
|
+
},
|
|
50942
|
+
{
|
|
50943
|
+
key: "globalBold",
|
|
50944
|
+
isValid: (value) => typeof value === "boolean"
|
|
50945
|
+
}
|
|
50946
|
+
];
|
|
50947
|
+
function toWidgetLine(line, stripSeparators) {
|
|
50948
|
+
const lineToProcess = stripSeparators ? line.filter((item) => {
|
|
50949
|
+
if (isRecord(item)) {
|
|
50950
|
+
return item.type !== "separator";
|
|
50951
|
+
}
|
|
50952
|
+
return true;
|
|
50953
|
+
}) : line;
|
|
50954
|
+
const typedLine = [];
|
|
50955
|
+
for (const item of lineToProcess) {
|
|
50956
|
+
if (isRecord(item) && typeof item.type === "string") {
|
|
50957
|
+
typedLine.push({
|
|
50958
|
+
...item,
|
|
50959
|
+
id: generateGuid(),
|
|
50960
|
+
type: item.type
|
|
50961
|
+
});
|
|
50962
|
+
}
|
|
50963
|
+
}
|
|
50964
|
+
return typedLine;
|
|
50965
|
+
}
|
|
50966
|
+
function migrateV1Lines(data) {
|
|
50967
|
+
if (!Array.isArray(data.lines)) {
|
|
50968
|
+
return;
|
|
50969
|
+
}
|
|
50970
|
+
const stripSeparators = Boolean(data.defaultSeparator);
|
|
50971
|
+
const processedLines = [];
|
|
50972
|
+
for (const line of data.lines) {
|
|
50973
|
+
if (Array.isArray(line)) {
|
|
50974
|
+
processedLines.push(toWidgetLine(line, stripSeparators));
|
|
50975
|
+
}
|
|
50976
|
+
}
|
|
50977
|
+
return processedLines;
|
|
50978
|
+
}
|
|
50979
|
+
function copyV1Fields(data, target) {
|
|
50980
|
+
for (const rule of V1_FIELD_RULES) {
|
|
50981
|
+
const value = data[rule.key];
|
|
50982
|
+
if (rule.isValid(value)) {
|
|
50983
|
+
target[rule.key] = value;
|
|
50984
|
+
}
|
|
50985
|
+
}
|
|
50986
|
+
}
|
|
51002
50987
|
var migrations = [
|
|
51003
50988
|
{
|
|
51004
50989
|
fromVersion: 1,
|
|
@@ -51006,52 +50991,11 @@ var migrations = [
|
|
|
51006
50991
|
description: "Migrate from v1 to v2",
|
|
51007
50992
|
migrate: (data) => {
|
|
51008
50993
|
const migrated = {};
|
|
51009
|
-
|
|
51010
|
-
|
|
51011
|
-
for (const line of data.lines) {
|
|
51012
|
-
if (Array.isArray(line)) {
|
|
51013
|
-
let processedLine = line;
|
|
51014
|
-
if (data.defaultSeparator) {
|
|
51015
|
-
processedLine = line.filter((item) => {
|
|
51016
|
-
if (isRecord(item)) {
|
|
51017
|
-
return item.type !== "separator";
|
|
51018
|
-
}
|
|
51019
|
-
return true;
|
|
51020
|
-
});
|
|
51021
|
-
}
|
|
51022
|
-
const typedLine = [];
|
|
51023
|
-
for (const item of processedLine) {
|
|
51024
|
-
if (isRecord(item) && typeof item.type === "string") {
|
|
51025
|
-
typedLine.push({
|
|
51026
|
-
...item,
|
|
51027
|
-
id: generateGuid(),
|
|
51028
|
-
type: item.type
|
|
51029
|
-
});
|
|
51030
|
-
}
|
|
51031
|
-
}
|
|
51032
|
-
processedLines.push(typedLine);
|
|
51033
|
-
}
|
|
51034
|
-
}
|
|
50994
|
+
const processedLines = migrateV1Lines(data);
|
|
50995
|
+
if (processedLines) {
|
|
51035
50996
|
migrated.lines = processedLines;
|
|
51036
50997
|
}
|
|
51037
|
-
|
|
51038
|
-
migrated.flexMode = data.flexMode;
|
|
51039
|
-
if (typeof data.compactThreshold === "number")
|
|
51040
|
-
migrated.compactThreshold = data.compactThreshold;
|
|
51041
|
-
if (typeof data.colorLevel === "number")
|
|
51042
|
-
migrated.colorLevel = data.colorLevel;
|
|
51043
|
-
if (typeof data.defaultSeparator === "string")
|
|
51044
|
-
migrated.defaultSeparator = data.defaultSeparator;
|
|
51045
|
-
if (typeof data.defaultPadding === "string")
|
|
51046
|
-
migrated.defaultPadding = data.defaultPadding;
|
|
51047
|
-
if (typeof data.inheritSeparatorColors === "boolean")
|
|
51048
|
-
migrated.inheritSeparatorColors = data.inheritSeparatorColors;
|
|
51049
|
-
if (typeof data.overrideBackgroundColor === "string")
|
|
51050
|
-
migrated.overrideBackgroundColor = data.overrideBackgroundColor;
|
|
51051
|
-
if (typeof data.overrideForegroundColor === "string")
|
|
51052
|
-
migrated.overrideForegroundColor = data.overrideForegroundColor;
|
|
51053
|
-
if (typeof data.globalBold === "boolean")
|
|
51054
|
-
migrated.globalBold = data.globalBold;
|
|
50998
|
+
copyV1Fields(data, migrated);
|
|
51055
50999
|
migrated.version = 2;
|
|
51056
51000
|
migrated.updatemessage = {
|
|
51057
51001
|
message: "ccstatusline updated to v2.0.0, launch tui to use new settings",
|
|
@@ -51101,85 +51045,224 @@ function needsMigration(data, targetVersion) {
|
|
|
51101
51045
|
}
|
|
51102
51046
|
|
|
51103
51047
|
// src/utils/config.ts
|
|
51104
|
-
var
|
|
51105
|
-
var
|
|
51106
|
-
var
|
|
51107
|
-
var
|
|
51108
|
-
var
|
|
51109
|
-
|
|
51110
|
-
|
|
51048
|
+
var readFile = fs2.promises.readFile;
|
|
51049
|
+
var writeFile = fs2.promises.writeFile;
|
|
51050
|
+
var mkdir = fs2.promises.mkdir;
|
|
51051
|
+
var DEFAULT_SETTINGS_PATH = path.join(os2.homedir(), ".config", "ccstatusline", "settings.json");
|
|
51052
|
+
var settingsPath = DEFAULT_SETTINGS_PATH;
|
|
51053
|
+
function initConfigPath(filePath) {
|
|
51054
|
+
settingsPath = filePath ? path.resolve(filePath) : DEFAULT_SETTINGS_PATH;
|
|
51055
|
+
}
|
|
51056
|
+
function getConfigPath() {
|
|
51057
|
+
return settingsPath;
|
|
51058
|
+
}
|
|
51059
|
+
function isCustomConfigPath() {
|
|
51060
|
+
return settingsPath !== DEFAULT_SETTINGS_PATH;
|
|
51061
|
+
}
|
|
51062
|
+
function getSettingsPaths() {
|
|
51063
|
+
const configDir = path.dirname(settingsPath);
|
|
51064
|
+
const parsedPath = path.parse(settingsPath);
|
|
51065
|
+
const backupBaseName = parsedPath.ext ? `${parsedPath.name}.bak` : `${parsedPath.base}.bak`;
|
|
51066
|
+
return {
|
|
51067
|
+
configDir,
|
|
51068
|
+
settingsPath,
|
|
51069
|
+
settingsBackupPath: path.join(configDir, backupBaseName)
|
|
51070
|
+
};
|
|
51071
|
+
}
|
|
51072
|
+
async function writeSettingsJson(settings, paths) {
|
|
51073
|
+
await mkdir(paths.configDir, { recursive: true });
|
|
51074
|
+
await writeFile(paths.settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
51075
|
+
}
|
|
51076
|
+
async function backupBadSettings(paths) {
|
|
51111
51077
|
try {
|
|
51112
|
-
if (
|
|
51113
|
-
const content = await
|
|
51114
|
-
await
|
|
51115
|
-
console.error(`Bad settings backed up to ${
|
|
51078
|
+
if (fs2.existsSync(paths.settingsPath)) {
|
|
51079
|
+
const content = await readFile(paths.settingsPath, "utf-8");
|
|
51080
|
+
await writeFile(paths.settingsBackupPath, content, "utf-8");
|
|
51081
|
+
console.error(`Bad settings backed up to ${paths.settingsBackupPath}`);
|
|
51116
51082
|
}
|
|
51117
51083
|
} catch (error43) {
|
|
51118
51084
|
console.error("Failed to backup bad settings:", error43);
|
|
51119
51085
|
}
|
|
51120
51086
|
}
|
|
51121
|
-
async function writeDefaultSettings() {
|
|
51087
|
+
async function writeDefaultSettings(paths) {
|
|
51122
51088
|
const defaults = SettingsSchema.parse({});
|
|
51123
51089
|
const settingsWithVersion = {
|
|
51124
51090
|
...defaults,
|
|
51125
51091
|
version: CURRENT_VERSION
|
|
51126
51092
|
};
|
|
51127
51093
|
try {
|
|
51128
|
-
await
|
|
51129
|
-
|
|
51130
|
-
console.error(`Default settings written to ${SETTINGS_PATH}`);
|
|
51094
|
+
await writeSettingsJson(settingsWithVersion, paths);
|
|
51095
|
+
console.error(`Default settings written to ${paths.settingsPath}`);
|
|
51131
51096
|
} catch (error43) {
|
|
51132
51097
|
console.error("Failed to write default settings:", error43);
|
|
51133
51098
|
}
|
|
51134
51099
|
return defaults;
|
|
51135
51100
|
}
|
|
51101
|
+
async function recoverWithDefaults(paths) {
|
|
51102
|
+
await backupBadSettings(paths);
|
|
51103
|
+
return await writeDefaultSettings(paths);
|
|
51104
|
+
}
|
|
51136
51105
|
async function loadSettings() {
|
|
51106
|
+
const paths = getSettingsPaths();
|
|
51137
51107
|
try {
|
|
51138
|
-
if (!
|
|
51139
|
-
return await writeDefaultSettings();
|
|
51140
|
-
const content = await
|
|
51108
|
+
if (!fs2.existsSync(paths.settingsPath))
|
|
51109
|
+
return await writeDefaultSettings(paths);
|
|
51110
|
+
const content = await readFile(paths.settingsPath, "utf-8");
|
|
51141
51111
|
let rawData;
|
|
51142
51112
|
try {
|
|
51143
51113
|
rawData = JSON.parse(content);
|
|
51144
51114
|
} catch {
|
|
51145
51115
|
console.error("Failed to parse settings.json, backing up and using defaults");
|
|
51146
|
-
await
|
|
51147
|
-
return await writeDefaultSettings();
|
|
51116
|
+
return await recoverWithDefaults(paths);
|
|
51148
51117
|
}
|
|
51149
51118
|
const hasVersion = typeof rawData === "object" && rawData !== null && "version" in rawData;
|
|
51150
51119
|
if (!hasVersion) {
|
|
51151
51120
|
const v1Result = SettingsSchema_v1.safeParse(rawData);
|
|
51152
51121
|
if (!v1Result.success) {
|
|
51153
51122
|
console.error("Invalid v1 settings format:", v1Result.error);
|
|
51154
|
-
await
|
|
51155
|
-
return await writeDefaultSettings();
|
|
51123
|
+
return await recoverWithDefaults(paths);
|
|
51156
51124
|
}
|
|
51157
51125
|
rawData = migrateConfig(rawData, CURRENT_VERSION);
|
|
51158
|
-
await
|
|
51126
|
+
await writeSettingsJson(rawData, paths);
|
|
51159
51127
|
} else if (needsMigration(rawData, CURRENT_VERSION)) {
|
|
51160
51128
|
rawData = migrateConfig(rawData, CURRENT_VERSION);
|
|
51161
|
-
await
|
|
51129
|
+
await writeSettingsJson(rawData, paths);
|
|
51162
51130
|
}
|
|
51163
51131
|
const result = SettingsSchema.safeParse(rawData);
|
|
51164
51132
|
if (!result.success) {
|
|
51165
51133
|
console.error("Failed to parse settings:", result.error);
|
|
51166
|
-
await
|
|
51167
|
-
return await writeDefaultSettings();
|
|
51134
|
+
return await recoverWithDefaults(paths);
|
|
51168
51135
|
}
|
|
51169
51136
|
return result.data;
|
|
51170
51137
|
} catch (error43) {
|
|
51171
51138
|
console.error("Error loading settings:", error43);
|
|
51172
|
-
await
|
|
51173
|
-
return await writeDefaultSettings();
|
|
51139
|
+
return await recoverWithDefaults(paths);
|
|
51174
51140
|
}
|
|
51175
51141
|
}
|
|
51176
51142
|
async function saveSettings(settings) {
|
|
51177
|
-
|
|
51143
|
+
const paths = getSettingsPaths();
|
|
51178
51144
|
const settingsWithVersion = {
|
|
51179
51145
|
...settings,
|
|
51180
51146
|
version: CURRENT_VERSION
|
|
51181
51147
|
};
|
|
51182
|
-
await
|
|
51148
|
+
await writeSettingsJson(settingsWithVersion, paths);
|
|
51149
|
+
}
|
|
51150
|
+
|
|
51151
|
+
// src/utils/claude-settings.ts
|
|
51152
|
+
var readFile2 = fs3.promises.readFile;
|
|
51153
|
+
var writeFile2 = fs3.promises.writeFile;
|
|
51154
|
+
var mkdir2 = fs3.promises.mkdir;
|
|
51155
|
+
var CCSTATUSLINE_COMMANDS = {
|
|
51156
|
+
NPM: "npx -y ccstatusline@latest",
|
|
51157
|
+
BUNX: "bunx -y ccstatusline@latest",
|
|
51158
|
+
SELF_MANAGED: "ccstatusline"
|
|
51159
|
+
};
|
|
51160
|
+
function isKnownCommand(command) {
|
|
51161
|
+
const prefixes = [CCSTATUSLINE_COMMANDS.NPM, CCSTATUSLINE_COMMANDS.BUNX, CCSTATUSLINE_COMMANDS.SELF_MANAGED];
|
|
51162
|
+
return prefixes.some((prefix) => command === prefix || command.startsWith(`${prefix} --config `));
|
|
51163
|
+
}
|
|
51164
|
+
function needsQuoting(filePath) {
|
|
51165
|
+
if (process.platform === "win32") {
|
|
51166
|
+
return /[\s&()<>|^"]/.test(filePath);
|
|
51167
|
+
}
|
|
51168
|
+
return /[\s()[\];&#|'"\\$`]/.test(filePath);
|
|
51169
|
+
}
|
|
51170
|
+
function quotePathIfNeeded(filePath) {
|
|
51171
|
+
if (!needsQuoting(filePath)) {
|
|
51172
|
+
return filePath;
|
|
51173
|
+
}
|
|
51174
|
+
if (process.platform === "win32") {
|
|
51175
|
+
return `"${filePath.replace(/"/g, '""')}"`;
|
|
51176
|
+
}
|
|
51177
|
+
return `'${filePath.replace(/'/g, "'\\''")}'`;
|
|
51178
|
+
}
|
|
51179
|
+
function getClaudeConfigDir() {
|
|
51180
|
+
const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
|
51181
|
+
if (envConfigDir) {
|
|
51182
|
+
try {
|
|
51183
|
+
const resolvedPath = path2.resolve(envConfigDir);
|
|
51184
|
+
if (fs3.existsSync(resolvedPath)) {
|
|
51185
|
+
const stats = fs3.statSync(resolvedPath);
|
|
51186
|
+
if (stats.isDirectory()) {
|
|
51187
|
+
return resolvedPath;
|
|
51188
|
+
}
|
|
51189
|
+
} else {
|
|
51190
|
+
return resolvedPath;
|
|
51191
|
+
}
|
|
51192
|
+
} catch {}
|
|
51193
|
+
}
|
|
51194
|
+
return path2.join(os3.homedir(), ".claude");
|
|
51195
|
+
}
|
|
51196
|
+
function getClaudeSettingsPath() {
|
|
51197
|
+
return path2.join(getClaudeConfigDir(), "settings.json");
|
|
51198
|
+
}
|
|
51199
|
+
async function loadClaudeSettings() {
|
|
51200
|
+
try {
|
|
51201
|
+
const settingsPath2 = getClaudeSettingsPath();
|
|
51202
|
+
if (!fs3.existsSync(settingsPath2)) {
|
|
51203
|
+
return {};
|
|
51204
|
+
}
|
|
51205
|
+
const content = await readFile2(settingsPath2, "utf-8");
|
|
51206
|
+
return JSON.parse(content);
|
|
51207
|
+
} catch {
|
|
51208
|
+
return {};
|
|
51209
|
+
}
|
|
51210
|
+
}
|
|
51211
|
+
async function saveClaudeSettings(settings) {
|
|
51212
|
+
const settingsPath2 = getClaudeSettingsPath();
|
|
51213
|
+
const dir = path2.dirname(settingsPath2);
|
|
51214
|
+
await mkdir2(dir, { recursive: true });
|
|
51215
|
+
await writeFile2(settingsPath2, JSON.stringify(settings, null, 2), "utf-8");
|
|
51216
|
+
}
|
|
51217
|
+
async function isInstalled() {
|
|
51218
|
+
const settings = await loadClaudeSettings();
|
|
51219
|
+
const command = settings.statusLine?.command ?? "";
|
|
51220
|
+
return isKnownCommand(command) && (settings.statusLine?.padding === 0 || settings.statusLine?.padding === undefined);
|
|
51221
|
+
}
|
|
51222
|
+
function isBunxAvailable() {
|
|
51223
|
+
try {
|
|
51224
|
+
const command = process.platform === "win32" ? "where bunx" : "which bunx";
|
|
51225
|
+
execSync(command, { stdio: "ignore" });
|
|
51226
|
+
return true;
|
|
51227
|
+
} catch {
|
|
51228
|
+
return false;
|
|
51229
|
+
}
|
|
51230
|
+
}
|
|
51231
|
+
function buildCommand(baseCommand) {
|
|
51232
|
+
if (isCustomConfigPath()) {
|
|
51233
|
+
return `${baseCommand} --config ${quotePathIfNeeded(getConfigPath())}`;
|
|
51234
|
+
}
|
|
51235
|
+
return baseCommand;
|
|
51236
|
+
}
|
|
51237
|
+
async function installStatusLine(useBunx = false) {
|
|
51238
|
+
const settings = await loadClaudeSettings();
|
|
51239
|
+
const baseCommand = useBunx ? CCSTATUSLINE_COMMANDS.BUNX : CCSTATUSLINE_COMMANDS.NPM;
|
|
51240
|
+
settings.statusLine = {
|
|
51241
|
+
type: "command",
|
|
51242
|
+
command: buildCommand(baseCommand),
|
|
51243
|
+
padding: 0
|
|
51244
|
+
};
|
|
51245
|
+
await saveClaudeSettings(settings);
|
|
51246
|
+
}
|
|
51247
|
+
async function uninstallStatusLine() {
|
|
51248
|
+
const settings = await loadClaudeSettings();
|
|
51249
|
+
if (settings.statusLine) {
|
|
51250
|
+
delete settings.statusLine;
|
|
51251
|
+
await saveClaudeSettings(settings);
|
|
51252
|
+
}
|
|
51253
|
+
}
|
|
51254
|
+
async function getExistingStatusLine() {
|
|
51255
|
+
const settings = await loadClaudeSettings();
|
|
51256
|
+
return settings.statusLine?.command ?? null;
|
|
51257
|
+
}
|
|
51258
|
+
|
|
51259
|
+
// src/utils/clone-settings.ts
|
|
51260
|
+
function cloneSettings(settings) {
|
|
51261
|
+
const cloneFn = globalThis.structuredClone;
|
|
51262
|
+
if (typeof cloneFn === "function") {
|
|
51263
|
+
return cloneFn(settings);
|
|
51264
|
+
}
|
|
51265
|
+
return JSON.parse(JSON.stringify(settings));
|
|
51183
51266
|
}
|
|
51184
51267
|
|
|
51185
51268
|
// src/utils/open-url.ts
|
|
@@ -51201,6 +51284,32 @@ function runOpenCommand(command, args) {
|
|
|
51201
51284
|
}
|
|
51202
51285
|
return null;
|
|
51203
51286
|
}
|
|
51287
|
+
var PLATFORM_OPEN_PLANS = {
|
|
51288
|
+
darwin: [
|
|
51289
|
+
{
|
|
51290
|
+
command: "open",
|
|
51291
|
+
args: (url2) => [url2]
|
|
51292
|
+
}
|
|
51293
|
+
],
|
|
51294
|
+
win32: [
|
|
51295
|
+
{
|
|
51296
|
+
command: "cmd",
|
|
51297
|
+
args: (url2) => ["/c", "start", "", url2]
|
|
51298
|
+
}
|
|
51299
|
+
],
|
|
51300
|
+
linux: [
|
|
51301
|
+
{
|
|
51302
|
+
command: "xdg-open",
|
|
51303
|
+
args: (url2) => [url2],
|
|
51304
|
+
errorPrefix: "xdg-open failed: "
|
|
51305
|
+
},
|
|
51306
|
+
{
|
|
51307
|
+
command: "gio",
|
|
51308
|
+
args: (url2) => ["open", url2],
|
|
51309
|
+
errorPrefix: "gio open failed: "
|
|
51310
|
+
}
|
|
51311
|
+
]
|
|
51312
|
+
};
|
|
51204
51313
|
function openExternalUrl(url2) {
|
|
51205
51314
|
let parsedUrl;
|
|
51206
51315
|
try {
|
|
@@ -51218,31 +51327,28 @@ function openExternalUrl(url2) {
|
|
|
51218
51327
|
};
|
|
51219
51328
|
}
|
|
51220
51329
|
const platform3 = os4.platform();
|
|
51221
|
-
|
|
51222
|
-
|
|
51223
|
-
return
|
|
51224
|
-
|
|
51225
|
-
|
|
51226
|
-
|
|
51227
|
-
return commandError ? { success: false, error: commandError } : { success: true };
|
|
51330
|
+
const plans = PLATFORM_OPEN_PLANS[platform3];
|
|
51331
|
+
if (!plans) {
|
|
51332
|
+
return {
|
|
51333
|
+
success: false,
|
|
51334
|
+
error: `Unsupported platform: ${platform3}`
|
|
51335
|
+
};
|
|
51228
51336
|
}
|
|
51229
|
-
|
|
51230
|
-
|
|
51231
|
-
|
|
51337
|
+
const errors3 = [];
|
|
51338
|
+
for (const plan of plans) {
|
|
51339
|
+
const commandError = runOpenCommand(plan.command, plan.args(url2));
|
|
51340
|
+
if (!commandError) {
|
|
51232
51341
|
return { success: true };
|
|
51233
51342
|
}
|
|
51234
|
-
|
|
51235
|
-
|
|
51236
|
-
|
|
51343
|
+
if (plan.errorPrefix) {
|
|
51344
|
+
errors3.push(`${plan.errorPrefix}${commandError}`);
|
|
51345
|
+
} else {
|
|
51346
|
+
errors3.push(commandError);
|
|
51237
51347
|
}
|
|
51238
|
-
return {
|
|
51239
|
-
success: false,
|
|
51240
|
-
error: `xdg-open failed: ${xdgError}; gio open failed: ${gioError}`
|
|
51241
|
-
};
|
|
51242
51348
|
}
|
|
51243
51349
|
return {
|
|
51244
51350
|
success: false,
|
|
51245
|
-
error:
|
|
51351
|
+
error: errors3.join("; ")
|
|
51246
51352
|
};
|
|
51247
51353
|
}
|
|
51248
51354
|
|
|
@@ -51478,7 +51584,7 @@ import { execSync as execSync3 } from "child_process";
|
|
|
51478
51584
|
import * as fs5 from "fs";
|
|
51479
51585
|
import * as path4 from "path";
|
|
51480
51586
|
var __dirname = "/Users/sirmalloc/Projects/Personal/ccstatusline/src/utils";
|
|
51481
|
-
var PACKAGE_VERSION = "2.1.
|
|
51587
|
+
var PACKAGE_VERSION = "2.1.8";
|
|
51482
51588
|
function getPackageVersion() {
|
|
51483
51589
|
if (/^\d+\.\d+\.\d+/.test(PACKAGE_VERSION)) {
|
|
51484
51590
|
return PACKAGE_VERSION;
|
|
@@ -54566,54 +54672,309 @@ var CustomCommandEditor = ({ widget, onComplete, onCancel, action }) => {
|
|
|
54566
54672
|
children: "Unknown editor mode"
|
|
54567
54673
|
}, undefined, false, undefined, this);
|
|
54568
54674
|
};
|
|
54569
|
-
// src/utils/usage.ts
|
|
54570
|
-
import {
|
|
54571
|
-
execSync as execSync6,
|
|
54572
|
-
spawnSync as spawnSync2
|
|
54573
|
-
} from "child_process";
|
|
54574
|
-
import * as fs7 from "fs";
|
|
54575
|
-
import * as os7 from "os";
|
|
54576
|
-
import * as path7 from "path";
|
|
54577
|
-
|
|
54578
|
-
// src/utils/jsonl.ts
|
|
54675
|
+
// src/utils/usage-fetch.ts
|
|
54676
|
+
import { execSync as execSync6 } from "child_process";
|
|
54579
54677
|
import * as fs6 from "fs";
|
|
54580
|
-
import
|
|
54581
|
-
import os6 from "
|
|
54582
|
-
import
|
|
54678
|
+
import * as https from "https";
|
|
54679
|
+
import * as os6 from "os";
|
|
54680
|
+
import * as path5 from "path";
|
|
54583
54681
|
|
|
54584
|
-
//
|
|
54585
|
-
|
|
54682
|
+
// src/utils/usage-types.ts
|
|
54683
|
+
var FIVE_HOUR_BLOCK_MS = 5 * 60 * 60 * 1000;
|
|
54684
|
+
var SEVEN_DAY_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
|
|
54685
|
+
var UsageErrorSchema = exports_external.enum(["no-credentials", "timeout", "api-error", "parse-error"]);
|
|
54586
54686
|
|
|
54587
|
-
//
|
|
54588
|
-
|
|
54589
|
-
|
|
54590
|
-
|
|
54591
|
-
var
|
|
54592
|
-
|
|
54593
|
-
|
|
54687
|
+
// src/utils/usage-fetch.ts
|
|
54688
|
+
var CACHE_DIR = path5.join(os6.homedir(), ".cache", "ccstatusline");
|
|
54689
|
+
var CACHE_FILE = path5.join(CACHE_DIR, "usage.json");
|
|
54690
|
+
var LOCK_FILE = path5.join(CACHE_DIR, "usage.lock");
|
|
54691
|
+
var CACHE_MAX_AGE = 180;
|
|
54692
|
+
var LOCK_MAX_AGE = 30;
|
|
54693
|
+
var TOKEN_CACHE_MAX_AGE = 3600;
|
|
54694
|
+
var UsageCredentialsSchema = exports_external.object({ claudeAiOauth: exports_external.object({ accessToken: exports_external.string().nullable().optional() }).optional() });
|
|
54695
|
+
var CachedUsageDataSchema = exports_external.object({
|
|
54696
|
+
sessionUsage: exports_external.number().nullable().optional(),
|
|
54697
|
+
sessionResetAt: exports_external.string().nullable().optional(),
|
|
54698
|
+
weeklyUsage: exports_external.number().nullable().optional(),
|
|
54699
|
+
weeklyResetAt: exports_external.string().nullable().optional(),
|
|
54700
|
+
extraUsageEnabled: exports_external.boolean().nullable().optional(),
|
|
54701
|
+
extraUsageLimit: exports_external.number().nullable().optional(),
|
|
54702
|
+
extraUsageUsed: exports_external.number().nullable().optional(),
|
|
54703
|
+
extraUsageUtilization: exports_external.number().nullable().optional(),
|
|
54704
|
+
error: exports_external.string().nullable().optional()
|
|
54705
|
+
});
|
|
54706
|
+
var UsageApiResponseSchema = exports_external.object({
|
|
54707
|
+
five_hour: exports_external.object({
|
|
54708
|
+
utilization: exports_external.number().nullable().optional(),
|
|
54709
|
+
resets_at: exports_external.string().nullable().optional()
|
|
54710
|
+
}).optional(),
|
|
54711
|
+
seven_day: exports_external.object({
|
|
54712
|
+
utilization: exports_external.number().nullable().optional(),
|
|
54713
|
+
resets_at: exports_external.string().nullable().optional()
|
|
54714
|
+
}).optional(),
|
|
54715
|
+
extra_usage: exports_external.object({
|
|
54716
|
+
is_enabled: exports_external.boolean().nullable().optional(),
|
|
54717
|
+
monthly_limit: exports_external.number().nullable().optional(),
|
|
54718
|
+
used_credits: exports_external.number().nullable().optional(),
|
|
54719
|
+
utilization: exports_external.number().nullable().optional()
|
|
54720
|
+
}).optional()
|
|
54721
|
+
});
|
|
54722
|
+
function parseJsonWithSchema(rawJson, schema) {
|
|
54723
|
+
try {
|
|
54724
|
+
const parsed = schema.safeParse(JSON.parse(rawJson));
|
|
54725
|
+
return parsed.success ? parsed.data : null;
|
|
54726
|
+
} catch {
|
|
54727
|
+
return null;
|
|
54728
|
+
}
|
|
54729
|
+
}
|
|
54730
|
+
function parseUsageAccessToken(rawJson) {
|
|
54731
|
+
const parsed = parseJsonWithSchema(rawJson, UsageCredentialsSchema);
|
|
54732
|
+
return parsed?.claudeAiOauth?.accessToken ?? null;
|
|
54733
|
+
}
|
|
54734
|
+
function parseCachedUsageData(rawJson) {
|
|
54735
|
+
const parsed = parseJsonWithSchema(rawJson, CachedUsageDataSchema);
|
|
54736
|
+
if (!parsed) {
|
|
54737
|
+
return null;
|
|
54738
|
+
}
|
|
54739
|
+
const parsedError = UsageErrorSchema.safeParse(parsed.error);
|
|
54740
|
+
return {
|
|
54741
|
+
sessionUsage: parsed.sessionUsage ?? undefined,
|
|
54742
|
+
sessionResetAt: parsed.sessionResetAt ?? undefined,
|
|
54743
|
+
weeklyUsage: parsed.weeklyUsage ?? undefined,
|
|
54744
|
+
weeklyResetAt: parsed.weeklyResetAt ?? undefined,
|
|
54745
|
+
extraUsageEnabled: parsed.extraUsageEnabled ?? undefined,
|
|
54746
|
+
extraUsageLimit: parsed.extraUsageLimit ?? undefined,
|
|
54747
|
+
extraUsageUsed: parsed.extraUsageUsed ?? undefined,
|
|
54748
|
+
extraUsageUtilization: parsed.extraUsageUtilization ?? undefined,
|
|
54749
|
+
error: parsedError.success ? parsedError.data : undefined
|
|
54750
|
+
};
|
|
54751
|
+
}
|
|
54752
|
+
function parseUsageApiResponse(rawJson) {
|
|
54753
|
+
const parsed = parseJsonWithSchema(rawJson, UsageApiResponseSchema);
|
|
54754
|
+
if (!parsed) {
|
|
54755
|
+
return null;
|
|
54756
|
+
}
|
|
54757
|
+
return {
|
|
54758
|
+
sessionUsage: parsed.five_hour?.utilization ?? undefined,
|
|
54759
|
+
sessionResetAt: parsed.five_hour?.resets_at ?? undefined,
|
|
54760
|
+
weeklyUsage: parsed.seven_day?.utilization ?? undefined,
|
|
54761
|
+
weeklyResetAt: parsed.seven_day?.resets_at ?? undefined,
|
|
54762
|
+
extraUsageEnabled: parsed.extra_usage?.is_enabled ?? undefined,
|
|
54763
|
+
extraUsageLimit: parsed.extra_usage?.monthly_limit ?? undefined,
|
|
54764
|
+
extraUsageUsed: parsed.extra_usage?.used_credits ?? undefined,
|
|
54765
|
+
extraUsageUtilization: parsed.extra_usage?.utilization ?? undefined
|
|
54766
|
+
};
|
|
54767
|
+
}
|
|
54768
|
+
var cachedUsageData = null;
|
|
54769
|
+
var usageCacheTime = 0;
|
|
54770
|
+
var cachedUsageToken = null;
|
|
54771
|
+
var usageTokenCacheTime = 0;
|
|
54772
|
+
function setCachedUsageError(error43, now) {
|
|
54773
|
+
const errorData = { error: error43 };
|
|
54774
|
+
cachedUsageData = errorData;
|
|
54775
|
+
usageCacheTime = now;
|
|
54776
|
+
return errorData;
|
|
54777
|
+
}
|
|
54778
|
+
function getStaleUsageOrError(error43, now) {
|
|
54779
|
+
const stale = readStaleUsageCache();
|
|
54780
|
+
if (stale && !stale.error) {
|
|
54781
|
+
cachedUsageData = stale;
|
|
54782
|
+
usageCacheTime = now;
|
|
54783
|
+
return stale;
|
|
54784
|
+
}
|
|
54785
|
+
return setCachedUsageError(error43, now);
|
|
54786
|
+
}
|
|
54787
|
+
function getUsageToken() {
|
|
54788
|
+
const now = Math.floor(Date.now() / 1000);
|
|
54789
|
+
if (cachedUsageToken && now - usageTokenCacheTime < TOKEN_CACHE_MAX_AGE) {
|
|
54790
|
+
return cachedUsageToken;
|
|
54791
|
+
}
|
|
54792
|
+
try {
|
|
54793
|
+
const isMac = process.platform === "darwin";
|
|
54794
|
+
if (isMac) {
|
|
54795
|
+
const result = execSync6('security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
54796
|
+
const token2 = parseUsageAccessToken(result);
|
|
54797
|
+
if (token2) {
|
|
54798
|
+
cachedUsageToken = token2;
|
|
54799
|
+
usageTokenCacheTime = now;
|
|
54800
|
+
}
|
|
54801
|
+
return token2;
|
|
54802
|
+
}
|
|
54803
|
+
const credFile = path5.join(getClaudeConfigDir(), ".credentials.json");
|
|
54804
|
+
const token = parseUsageAccessToken(fs6.readFileSync(credFile, "utf8"));
|
|
54805
|
+
if (token) {
|
|
54806
|
+
cachedUsageToken = token;
|
|
54807
|
+
usageTokenCacheTime = now;
|
|
54808
|
+
}
|
|
54809
|
+
return token;
|
|
54810
|
+
} catch {
|
|
54811
|
+
return null;
|
|
54812
|
+
}
|
|
54813
|
+
}
|
|
54814
|
+
function readStaleUsageCache() {
|
|
54815
|
+
try {
|
|
54816
|
+
return parseCachedUsageData(fs6.readFileSync(CACHE_FILE, "utf8"));
|
|
54817
|
+
} catch {
|
|
54818
|
+
return null;
|
|
54819
|
+
}
|
|
54820
|
+
}
|
|
54821
|
+
var USAGE_API_HOST = "api.anthropic.com";
|
|
54822
|
+
var USAGE_API_PATH = "/api/oauth/usage";
|
|
54823
|
+
async function fetchFromUsageApi(token) {
|
|
54824
|
+
return new Promise((resolve3) => {
|
|
54825
|
+
let settled = false;
|
|
54826
|
+
const finish = (value) => {
|
|
54827
|
+
if (settled) {
|
|
54828
|
+
return;
|
|
54829
|
+
}
|
|
54830
|
+
settled = true;
|
|
54831
|
+
resolve3(value);
|
|
54832
|
+
};
|
|
54833
|
+
const request2 = https.request({
|
|
54834
|
+
hostname: USAGE_API_HOST,
|
|
54835
|
+
path: USAGE_API_PATH,
|
|
54836
|
+
method: "GET",
|
|
54837
|
+
headers: {
|
|
54838
|
+
Authorization: `Bearer ${token}`,
|
|
54839
|
+
"anthropic-beta": "oauth-2025-04-20"
|
|
54840
|
+
},
|
|
54841
|
+
timeout: 5000
|
|
54842
|
+
}, (response) => {
|
|
54843
|
+
let data = "";
|
|
54844
|
+
response.setEncoding("utf8");
|
|
54845
|
+
response.on("data", (chunk) => {
|
|
54846
|
+
data += chunk;
|
|
54847
|
+
});
|
|
54848
|
+
response.on("end", () => {
|
|
54849
|
+
if (response.statusCode === 200 && data) {
|
|
54850
|
+
finish(data);
|
|
54851
|
+
return;
|
|
54852
|
+
}
|
|
54853
|
+
finish(null);
|
|
54854
|
+
});
|
|
54855
|
+
});
|
|
54856
|
+
request2.on("error", () => {
|
|
54857
|
+
finish(null);
|
|
54858
|
+
});
|
|
54859
|
+
request2.on("timeout", () => {
|
|
54860
|
+
request2.destroy();
|
|
54861
|
+
finish(null);
|
|
54862
|
+
});
|
|
54863
|
+
request2.end();
|
|
54864
|
+
});
|
|
54865
|
+
}
|
|
54866
|
+
async function fetchUsageData() {
|
|
54867
|
+
const now = Math.floor(Date.now() / 1000);
|
|
54868
|
+
if (cachedUsageData) {
|
|
54869
|
+
const cacheAge = now - usageCacheTime;
|
|
54870
|
+
if (!cachedUsageData.error && cacheAge < CACHE_MAX_AGE) {
|
|
54871
|
+
return cachedUsageData;
|
|
54872
|
+
}
|
|
54873
|
+
if (cachedUsageData.error && cacheAge < LOCK_MAX_AGE) {
|
|
54874
|
+
return cachedUsageData;
|
|
54875
|
+
}
|
|
54876
|
+
}
|
|
54877
|
+
try {
|
|
54878
|
+
const stat = fs6.statSync(CACHE_FILE);
|
|
54879
|
+
const fileAge = now - Math.floor(stat.mtimeMs / 1000);
|
|
54880
|
+
if (fileAge < CACHE_MAX_AGE) {
|
|
54881
|
+
const fileData = parseCachedUsageData(fs6.readFileSync(CACHE_FILE, "utf8"));
|
|
54882
|
+
if (fileData && !fileData.error) {
|
|
54883
|
+
cachedUsageData = fileData;
|
|
54884
|
+
usageCacheTime = now;
|
|
54885
|
+
return fileData;
|
|
54886
|
+
}
|
|
54887
|
+
}
|
|
54888
|
+
} catch {}
|
|
54889
|
+
const token = getUsageToken();
|
|
54890
|
+
if (!token) {
|
|
54891
|
+
return getStaleUsageOrError("no-credentials", now);
|
|
54892
|
+
}
|
|
54893
|
+
try {
|
|
54894
|
+
const lockStat = fs6.statSync(LOCK_FILE);
|
|
54895
|
+
const lockAge = now - Math.floor(lockStat.mtimeMs / 1000);
|
|
54896
|
+
if (lockAge < LOCK_MAX_AGE) {
|
|
54897
|
+
const stale = readStaleUsageCache();
|
|
54898
|
+
if (stale && !stale.error)
|
|
54899
|
+
return stale;
|
|
54900
|
+
return { error: "timeout" };
|
|
54901
|
+
}
|
|
54902
|
+
} catch {}
|
|
54903
|
+
try {
|
|
54904
|
+
const lockDir = path5.dirname(LOCK_FILE);
|
|
54905
|
+
if (!fs6.existsSync(lockDir)) {
|
|
54906
|
+
fs6.mkdirSync(lockDir, { recursive: true });
|
|
54907
|
+
}
|
|
54908
|
+
fs6.writeFileSync(LOCK_FILE, "");
|
|
54909
|
+
} catch {}
|
|
54910
|
+
try {
|
|
54911
|
+
const response = await fetchFromUsageApi(token);
|
|
54912
|
+
if (!response) {
|
|
54913
|
+
return getStaleUsageOrError("api-error", now);
|
|
54914
|
+
}
|
|
54915
|
+
const usageData = parseUsageApiResponse(response);
|
|
54916
|
+
if (!usageData) {
|
|
54917
|
+
return getStaleUsageOrError("parse-error", now);
|
|
54918
|
+
}
|
|
54919
|
+
if (usageData.sessionUsage === undefined && usageData.weeklyUsage === undefined) {
|
|
54920
|
+
return getStaleUsageOrError("parse-error", now);
|
|
54921
|
+
}
|
|
54922
|
+
try {
|
|
54923
|
+
if (!fs6.existsSync(CACHE_DIR)) {
|
|
54924
|
+
fs6.mkdirSync(CACHE_DIR, { recursive: true });
|
|
54925
|
+
}
|
|
54926
|
+
fs6.writeFileSync(CACHE_FILE, JSON.stringify(usageData));
|
|
54927
|
+
} catch {}
|
|
54928
|
+
cachedUsageData = usageData;
|
|
54929
|
+
usageCacheTime = now;
|
|
54930
|
+
return usageData;
|
|
54931
|
+
} catch {
|
|
54932
|
+
return getStaleUsageOrError("parse-error", now);
|
|
54933
|
+
}
|
|
54934
|
+
}
|
|
54935
|
+
// src/utils/jsonl-cache.ts
|
|
54936
|
+
import * as fs9 from "fs";
|
|
54937
|
+
import { createHash } from "node:crypto";
|
|
54938
|
+
import os7 from "node:os";
|
|
54939
|
+
import path8 from "node:path";
|
|
54940
|
+
|
|
54941
|
+
// src/utils/jsonl-blocks.ts
|
|
54942
|
+
import * as fs8 from "fs";
|
|
54943
|
+
import path7 from "node:path";
|
|
54944
|
+
|
|
54945
|
+
// node_modules/tinyglobby/dist/index.mjs
|
|
54946
|
+
import path6, { posix } from "path";
|
|
54947
|
+
|
|
54948
|
+
// node_modules/fdir/dist/index.mjs
|
|
54949
|
+
import { createRequire as createRequire2 } from "module";
|
|
54950
|
+
import { basename as basename2, dirname as dirname4, normalize, relative, resolve as resolve3, sep } from "path";
|
|
54951
|
+
import * as nativeFs from "fs";
|
|
54952
|
+
var __require2 = /* @__PURE__ */ createRequire2(import.meta.url);
|
|
54953
|
+
function cleanPath(path6) {
|
|
54954
|
+
let normalized = normalize(path6);
|
|
54594
54955
|
if (normalized.length > 1 && normalized[normalized.length - 1] === sep)
|
|
54595
54956
|
normalized = normalized.substring(0, normalized.length - 1);
|
|
54596
54957
|
return normalized;
|
|
54597
54958
|
}
|
|
54598
54959
|
var SLASHES_REGEX = /[\\/]/g;
|
|
54599
|
-
function convertSlashes(
|
|
54600
|
-
return
|
|
54960
|
+
function convertSlashes(path6, separator) {
|
|
54961
|
+
return path6.replace(SLASHES_REGEX, separator);
|
|
54601
54962
|
}
|
|
54602
54963
|
var WINDOWS_ROOT_DIR_REGEX = /^[a-z]:[\\/]$/i;
|
|
54603
|
-
function isRootDirectory(
|
|
54604
|
-
return
|
|
54964
|
+
function isRootDirectory(path6) {
|
|
54965
|
+
return path6 === "/" || WINDOWS_ROOT_DIR_REGEX.test(path6);
|
|
54605
54966
|
}
|
|
54606
|
-
function normalizePath(
|
|
54967
|
+
function normalizePath(path6, options) {
|
|
54607
54968
|
const { resolvePaths, normalizePath: normalizePath$1, pathSeparator } = options;
|
|
54608
|
-
const pathNeedsCleaning = process.platform === "win32" &&
|
|
54969
|
+
const pathNeedsCleaning = process.platform === "win32" && path6.includes("/") || path6.startsWith(".");
|
|
54609
54970
|
if (resolvePaths)
|
|
54610
|
-
|
|
54971
|
+
path6 = resolve3(path6);
|
|
54611
54972
|
if (normalizePath$1 || pathNeedsCleaning)
|
|
54612
|
-
|
|
54613
|
-
if (
|
|
54973
|
+
path6 = cleanPath(path6);
|
|
54974
|
+
if (path6 === ".")
|
|
54614
54975
|
return "";
|
|
54615
|
-
const needsSeperator =
|
|
54616
|
-
return convertSlashes(needsSeperator ?
|
|
54976
|
+
const needsSeperator = path6[path6.length - 1] !== pathSeparator;
|
|
54977
|
+
return convertSlashes(needsSeperator ? path6 + pathSeparator : path6, pathSeparator);
|
|
54617
54978
|
}
|
|
54618
54979
|
function joinPathWithBasePath(filename, directoryPath) {
|
|
54619
54980
|
return directoryPath + filename;
|
|
@@ -54653,9 +55014,9 @@ var pushDirectory = (directoryPath, paths) => {
|
|
|
54653
55014
|
paths.push(directoryPath || ".");
|
|
54654
55015
|
};
|
|
54655
55016
|
var pushDirectoryFilter = (directoryPath, paths, filters) => {
|
|
54656
|
-
const
|
|
54657
|
-
if (filters.every((filter) => filter(
|
|
54658
|
-
paths.push(
|
|
55017
|
+
const path6 = directoryPath || ".";
|
|
55018
|
+
if (filters.every((filter) => filter(path6, true)))
|
|
55019
|
+
paths.push(path6);
|
|
54659
55020
|
};
|
|
54660
55021
|
var empty$2 = () => {};
|
|
54661
55022
|
function build$6(root, options) {
|
|
@@ -54712,29 +55073,29 @@ var empty = () => {};
|
|
|
54712
55073
|
function build$3(options) {
|
|
54713
55074
|
return options.group ? groupFiles : empty;
|
|
54714
55075
|
}
|
|
54715
|
-
var resolveSymlinksAsync = function(
|
|
54716
|
-
const { queue, fs:
|
|
55076
|
+
var resolveSymlinksAsync = function(path6, state, callback$1) {
|
|
55077
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
54717
55078
|
queue.enqueue();
|
|
54718
|
-
|
|
55079
|
+
fs7.realpath(path6, (error43, resolvedPath) => {
|
|
54719
55080
|
if (error43)
|
|
54720
55081
|
return queue.dequeue(suppressErrors ? null : error43, state);
|
|
54721
|
-
|
|
55082
|
+
fs7.stat(resolvedPath, (error$1, stat) => {
|
|
54722
55083
|
if (error$1)
|
|
54723
55084
|
return queue.dequeue(suppressErrors ? null : error$1, state);
|
|
54724
|
-
if (stat.isDirectory() && isRecursive(
|
|
55085
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
54725
55086
|
return queue.dequeue(null, state);
|
|
54726
55087
|
callback$1(stat, resolvedPath);
|
|
54727
55088
|
queue.dequeue(null, state);
|
|
54728
55089
|
});
|
|
54729
55090
|
});
|
|
54730
55091
|
};
|
|
54731
|
-
var resolveSymlinks = function(
|
|
54732
|
-
const { queue, fs:
|
|
55092
|
+
var resolveSymlinks = function(path6, state, callback$1) {
|
|
55093
|
+
const { queue, fs: fs7, options: { suppressErrors } } = state;
|
|
54733
55094
|
queue.enqueue();
|
|
54734
55095
|
try {
|
|
54735
|
-
const resolvedPath =
|
|
54736
|
-
const stat =
|
|
54737
|
-
if (stat.isDirectory() && isRecursive(
|
|
55096
|
+
const resolvedPath = fs7.realpathSync(path6);
|
|
55097
|
+
const stat = fs7.statSync(resolvedPath);
|
|
55098
|
+
if (stat.isDirectory() && isRecursive(path6, resolvedPath, state))
|
|
54738
55099
|
return;
|
|
54739
55100
|
callback$1(stat, resolvedPath);
|
|
54740
55101
|
} catch (e) {
|
|
@@ -54747,10 +55108,10 @@ function build$2(options, isSynchronous) {
|
|
|
54747
55108
|
return null;
|
|
54748
55109
|
return isSynchronous ? resolveSymlinks : resolveSymlinksAsync;
|
|
54749
55110
|
}
|
|
54750
|
-
function isRecursive(
|
|
55111
|
+
function isRecursive(path6, resolved, state) {
|
|
54751
55112
|
if (state.options.useRealPaths)
|
|
54752
55113
|
return isRecursiveUsingRealPaths(resolved, state);
|
|
54753
|
-
let parent =
|
|
55114
|
+
let parent = dirname4(path6);
|
|
54754
55115
|
let depth = 1;
|
|
54755
55116
|
while (parent !== state.root && depth < 2) {
|
|
54756
55117
|
const resolvedPath = state.symlinks.get(parent);
|
|
@@ -54758,9 +55119,9 @@ function isRecursive(path5, resolved, state) {
|
|
|
54758
55119
|
if (isSameRoot)
|
|
54759
55120
|
depth++;
|
|
54760
55121
|
else
|
|
54761
|
-
parent =
|
|
55122
|
+
parent = dirname4(parent);
|
|
54762
55123
|
}
|
|
54763
|
-
state.symlinks.set(
|
|
55124
|
+
state.symlinks.set(path6, resolved);
|
|
54764
55125
|
return depth > 1;
|
|
54765
55126
|
}
|
|
54766
55127
|
function isRecursiveUsingRealPaths(resolved, state) {
|
|
@@ -54816,23 +55177,23 @@ var walkAsync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
|
54816
55177
|
state.queue.enqueue();
|
|
54817
55178
|
if (currentDepth < 0)
|
|
54818
55179
|
return state.queue.dequeue(null, state);
|
|
54819
|
-
const { fs:
|
|
55180
|
+
const { fs: fs7 } = state;
|
|
54820
55181
|
state.visited.push(crawlPath);
|
|
54821
55182
|
state.counts.directories++;
|
|
54822
|
-
|
|
55183
|
+
fs7.readdir(crawlPath || ".", readdirOpts, (error43, entries = []) => {
|
|
54823
55184
|
callback$1(entries, directoryPath, currentDepth);
|
|
54824
55185
|
state.queue.dequeue(state.options.suppressErrors ? null : error43, state);
|
|
54825
55186
|
});
|
|
54826
55187
|
};
|
|
54827
55188
|
var walkSync = (state, crawlPath, directoryPath, currentDepth, callback$1) => {
|
|
54828
|
-
const { fs:
|
|
55189
|
+
const { fs: fs7 } = state;
|
|
54829
55190
|
if (currentDepth < 0)
|
|
54830
55191
|
return;
|
|
54831
55192
|
state.visited.push(crawlPath);
|
|
54832
55193
|
state.counts.directories++;
|
|
54833
55194
|
let entries = [];
|
|
54834
55195
|
try {
|
|
54835
|
-
entries =
|
|
55196
|
+
entries = fs7.readdirSync(crawlPath || ".", readdirOpts);
|
|
54836
55197
|
} catch (e) {
|
|
54837
55198
|
if (!state.options.suppressErrors)
|
|
54838
55199
|
throw e;
|
|
@@ -54938,23 +55299,23 @@ var Walker = class {
|
|
|
54938
55299
|
const filename = this.joinPath(entry.name, directoryPath);
|
|
54939
55300
|
this.pushFile(filename, files, this.state.counts, filters);
|
|
54940
55301
|
} else if (entry.isDirectory()) {
|
|
54941
|
-
let
|
|
54942
|
-
if (exclude && exclude(entry.name,
|
|
55302
|
+
let path6 = joinDirectoryPath(entry.name, directoryPath, this.state.options.pathSeparator);
|
|
55303
|
+
if (exclude && exclude(entry.name, path6))
|
|
54943
55304
|
continue;
|
|
54944
|
-
this.pushDirectory(
|
|
54945
|
-
this.walkDirectory(this.state,
|
|
55305
|
+
this.pushDirectory(path6, paths, filters);
|
|
55306
|
+
this.walkDirectory(this.state, path6, path6, depth - 1, this.walk);
|
|
54946
55307
|
} else if (this.resolveSymlink && entry.isSymbolicLink()) {
|
|
54947
|
-
let
|
|
54948
|
-
this.resolveSymlink(
|
|
55308
|
+
let path6 = joinPathWithBasePath(entry.name, directoryPath);
|
|
55309
|
+
this.resolveSymlink(path6, this.state, (stat, resolvedPath) => {
|
|
54949
55310
|
if (stat.isDirectory()) {
|
|
54950
55311
|
resolvedPath = normalizePath(resolvedPath, this.state.options);
|
|
54951
|
-
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath :
|
|
55312
|
+
if (exclude && exclude(entry.name, useRealPaths ? resolvedPath : path6 + pathSeparator))
|
|
54952
55313
|
return;
|
|
54953
|
-
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath :
|
|
55314
|
+
this.walkDirectory(this.state, resolvedPath, useRealPaths ? resolvedPath : path6 + pathSeparator, depth - 1, this.walk);
|
|
54954
55315
|
} else {
|
|
54955
|
-
resolvedPath = useRealPaths ? resolvedPath :
|
|
55316
|
+
resolvedPath = useRealPaths ? resolvedPath : path6;
|
|
54956
55317
|
const filename = basename2(resolvedPath);
|
|
54957
|
-
const directoryPath$1 = normalizePath(
|
|
55318
|
+
const directoryPath$1 = normalizePath(dirname4(resolvedPath), this.state.options);
|
|
54958
55319
|
resolvedPath = this.joinPath(filename, directoryPath$1);
|
|
54959
55320
|
this.pushFile(resolvedPath, files, this.state.counts, filters);
|
|
54960
55321
|
}
|
|
@@ -55112,7 +55473,7 @@ var Builder = class {
|
|
|
55112
55473
|
isMatch = globFn(patterns, ...options);
|
|
55113
55474
|
this.globCache[patterns.join("\x00")] = isMatch;
|
|
55114
55475
|
}
|
|
55115
|
-
this.options.filters.push((
|
|
55476
|
+
this.options.filters.push((path6) => isMatch(path6));
|
|
55116
55477
|
return this;
|
|
55117
55478
|
}
|
|
55118
55479
|
};
|
|
@@ -55191,7 +55552,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
55191
55552
|
if (!result.endsWith("*") && expandDirectories)
|
|
55192
55553
|
result += "/**";
|
|
55193
55554
|
const escapedCwd = escapePath(cwd2);
|
|
55194
|
-
if (
|
|
55555
|
+
if (path6.isAbsolute(result.replace(ESCAPING_BACKSLASHES, "")))
|
|
55195
55556
|
result = posix.relative(escapedCwd, result);
|
|
55196
55557
|
else
|
|
55197
55558
|
result = posix.normalize(result);
|
|
@@ -55228,7 +55589,7 @@ function normalizePattern(pattern, expandDirectories, cwd2, props, isIgnore) {
|
|
|
55228
55589
|
}
|
|
55229
55590
|
props.depthOffset = newCommonPath.length;
|
|
55230
55591
|
props.commonPath = newCommonPath;
|
|
55231
|
-
props.root = newCommonPath.length > 0 ?
|
|
55592
|
+
props.root = newCommonPath.length > 0 ? path6.posix.join(cwd2, ...newCommonPath) : cwd2;
|
|
55232
55593
|
}
|
|
55233
55594
|
return result;
|
|
55234
55595
|
}
|
|
@@ -55361,184 +55722,37 @@ function globSync(patternsOrOptions, options) {
|
|
|
55361
55722
|
...options,
|
|
55362
55723
|
patterns: patternsOrOptions
|
|
55363
55724
|
} : patternsOrOptions;
|
|
55364
|
-
const cwd2 = opts.cwd ?
|
|
55725
|
+
const cwd2 = opts.cwd ? path6.resolve(opts.cwd).replace(BACKSLASHES, "/") : process.cwd().replace(BACKSLASHES, "/");
|
|
55365
55726
|
return crawl(opts, cwd2, true);
|
|
55366
55727
|
}
|
|
55367
55728
|
|
|
55368
|
-
// src/utils/jsonl.ts
|
|
55729
|
+
// src/utils/jsonl-lines.ts
|
|
55730
|
+
import * as fs7 from "fs";
|
|
55369
55731
|
import { promisify } from "util";
|
|
55370
|
-
var readFile4 = promisify(
|
|
55371
|
-
var
|
|
55372
|
-
|
|
55373
|
-
|
|
55374
|
-
|
|
55375
|
-
var existsSync7 = fs6.existsSync;
|
|
55376
|
-
function normalizeConfigDir(configDir) {
|
|
55377
|
-
return path6.resolve(configDir);
|
|
55378
|
-
}
|
|
55379
|
-
function getBlockCachePath(configDir = getClaudeConfigDir()) {
|
|
55380
|
-
const normalizedConfigDir = normalizeConfigDir(configDir);
|
|
55381
|
-
const configHash = createHash("sha256").update(normalizedConfigDir).digest("hex").slice(0, 16);
|
|
55382
|
-
return path6.join(os6.homedir(), ".cache", "ccstatusline", `block-cache-${configHash}.json`);
|
|
55383
|
-
}
|
|
55384
|
-
function readBlockCache(expectedConfigDir) {
|
|
55385
|
-
try {
|
|
55386
|
-
const normalizedExpectedConfigDir = expectedConfigDir !== undefined ? normalizeConfigDir(expectedConfigDir) : undefined;
|
|
55387
|
-
const cachePath = getBlockCachePath(normalizedExpectedConfigDir);
|
|
55388
|
-
if (!existsSync7(cachePath)) {
|
|
55389
|
-
return null;
|
|
55390
|
-
}
|
|
55391
|
-
const content = readFileSync4(cachePath, "utf-8");
|
|
55392
|
-
const cache3 = JSON.parse(content);
|
|
55393
|
-
if (typeof cache3.startTime !== "string") {
|
|
55394
|
-
return null;
|
|
55395
|
-
}
|
|
55396
|
-
if (normalizedExpectedConfigDir !== undefined) {
|
|
55397
|
-
if (typeof cache3.configDir !== "string") {
|
|
55398
|
-
return null;
|
|
55399
|
-
}
|
|
55400
|
-
if (cache3.configDir !== normalizedExpectedConfigDir) {
|
|
55401
|
-
return null;
|
|
55402
|
-
}
|
|
55403
|
-
}
|
|
55404
|
-
const date5 = new Date(cache3.startTime);
|
|
55405
|
-
if (Number.isNaN(date5.getTime())) {
|
|
55406
|
-
return null;
|
|
55407
|
-
}
|
|
55408
|
-
return date5;
|
|
55409
|
-
} catch {
|
|
55410
|
-
return null;
|
|
55411
|
-
}
|
|
55732
|
+
var readFile4 = promisify(fs7.readFile);
|
|
55733
|
+
var readFileSync5 = fs7.readFileSync;
|
|
55734
|
+
function splitJsonlContent(content) {
|
|
55735
|
+
return content.trim().split(`
|
|
55736
|
+
`).filter((line) => line.length > 0);
|
|
55412
55737
|
}
|
|
55413
|
-
function
|
|
55414
|
-
|
|
55415
|
-
|
|
55416
|
-
const cachePath = getBlockCachePath(normalizedConfigDir);
|
|
55417
|
-
const cacheDir = path6.dirname(cachePath);
|
|
55418
|
-
if (!existsSync7(cacheDir)) {
|
|
55419
|
-
mkdirSync3(cacheDir, { recursive: true });
|
|
55420
|
-
}
|
|
55421
|
-
const cache3 = {
|
|
55422
|
-
startTime: startTime.toISOString(),
|
|
55423
|
-
configDir: normalizedConfigDir
|
|
55424
|
-
};
|
|
55425
|
-
writeFileSync2(cachePath, JSON.stringify(cache3), "utf-8");
|
|
55426
|
-
} catch {}
|
|
55738
|
+
async function readJsonlLines(filePath) {
|
|
55739
|
+
const content = await readFile4(filePath, "utf-8");
|
|
55740
|
+
return splitJsonlContent(content);
|
|
55427
55741
|
}
|
|
55428
|
-
function
|
|
55429
|
-
const
|
|
55430
|
-
|
|
55431
|
-
const activeConfigDir = getClaudeConfigDir();
|
|
55432
|
-
const cachedStartTime = readBlockCache(activeConfigDir);
|
|
55433
|
-
if (cachedStartTime) {
|
|
55434
|
-
const blockEndTime = new Date(cachedStartTime.getTime() + sessionDurationMs);
|
|
55435
|
-
if (now.getTime() <= blockEndTime.getTime()) {
|
|
55436
|
-
return {
|
|
55437
|
-
startTime: cachedStartTime,
|
|
55438
|
-
lastActivity: now
|
|
55439
|
-
};
|
|
55440
|
-
}
|
|
55441
|
-
}
|
|
55442
|
-
const metrics = getBlockMetrics();
|
|
55443
|
-
if (metrics) {
|
|
55444
|
-
writeBlockCache(metrics.startTime, activeConfigDir);
|
|
55445
|
-
}
|
|
55446
|
-
return metrics;
|
|
55742
|
+
function readJsonlLinesSync(filePath) {
|
|
55743
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
55744
|
+
return splitJsonlContent(content);
|
|
55447
55745
|
}
|
|
55448
|
-
|
|
55746
|
+
function parseJsonlLine(line) {
|
|
55449
55747
|
try {
|
|
55450
|
-
|
|
55451
|
-
return null;
|
|
55452
|
-
}
|
|
55453
|
-
const content = await readFile4(transcriptPath, "utf-8");
|
|
55454
|
-
const lines = content.trim().split(`
|
|
55455
|
-
`).filter((line) => line.trim());
|
|
55456
|
-
if (lines.length === 0) {
|
|
55457
|
-
return null;
|
|
55458
|
-
}
|
|
55459
|
-
let firstTimestamp = null;
|
|
55460
|
-
let lastTimestamp = null;
|
|
55461
|
-
for (const line of lines) {
|
|
55462
|
-
try {
|
|
55463
|
-
const data = JSON.parse(line);
|
|
55464
|
-
if (data.timestamp) {
|
|
55465
|
-
firstTimestamp = new Date(data.timestamp);
|
|
55466
|
-
break;
|
|
55467
|
-
}
|
|
55468
|
-
} catch {}
|
|
55469
|
-
}
|
|
55470
|
-
for (let i = lines.length - 1;i >= 0; i--) {
|
|
55471
|
-
try {
|
|
55472
|
-
const data = JSON.parse(lines[i] ?? "");
|
|
55473
|
-
if (data.timestamp) {
|
|
55474
|
-
lastTimestamp = new Date(data.timestamp);
|
|
55475
|
-
break;
|
|
55476
|
-
}
|
|
55477
|
-
} catch {}
|
|
55478
|
-
}
|
|
55479
|
-
if (!firstTimestamp || !lastTimestamp) {
|
|
55480
|
-
return null;
|
|
55481
|
-
}
|
|
55482
|
-
const durationMs = lastTimestamp.getTime() - firstTimestamp.getTime();
|
|
55483
|
-
const totalMinutes = Math.floor(durationMs / (1000 * 60));
|
|
55484
|
-
if (totalMinutes < 1) {
|
|
55485
|
-
return "<1m";
|
|
55486
|
-
}
|
|
55487
|
-
const hours = Math.floor(totalMinutes / 60);
|
|
55488
|
-
const minutes = totalMinutes % 60;
|
|
55489
|
-
if (hours === 0) {
|
|
55490
|
-
return `${minutes}m`;
|
|
55491
|
-
} else if (minutes === 0) {
|
|
55492
|
-
return `${hours}hr`;
|
|
55493
|
-
} else {
|
|
55494
|
-
return `${hours}hr ${minutes}m`;
|
|
55495
|
-
}
|
|
55748
|
+
return JSON.parse(line);
|
|
55496
55749
|
} catch {
|
|
55497
55750
|
return null;
|
|
55498
55751
|
}
|
|
55499
55752
|
}
|
|
55500
|
-
|
|
55501
|
-
|
|
55502
|
-
|
|
55503
|
-
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
55504
|
-
}
|
|
55505
|
-
const content = await readFile4(transcriptPath, "utf-8");
|
|
55506
|
-
const lines = content.trim().split(`
|
|
55507
|
-
`);
|
|
55508
|
-
let inputTokens = 0;
|
|
55509
|
-
let outputTokens = 0;
|
|
55510
|
-
let cachedTokens = 0;
|
|
55511
|
-
let contextLength = 0;
|
|
55512
|
-
let mostRecentMainChainEntry = null;
|
|
55513
|
-
let mostRecentTimestamp = null;
|
|
55514
|
-
for (const line of lines) {
|
|
55515
|
-
try {
|
|
55516
|
-
const data = JSON.parse(line);
|
|
55517
|
-
if (data.message?.usage) {
|
|
55518
|
-
inputTokens += data.message.usage.input_tokens || 0;
|
|
55519
|
-
outputTokens += data.message.usage.output_tokens || 0;
|
|
55520
|
-
cachedTokens += data.message.usage.cache_read_input_tokens ?? 0;
|
|
55521
|
-
cachedTokens += data.message.usage.cache_creation_input_tokens ?? 0;
|
|
55522
|
-
if (data.isSidechain !== true && data.timestamp && !data.isApiErrorMessage) {
|
|
55523
|
-
const entryTime = new Date(data.timestamp);
|
|
55524
|
-
if (!mostRecentTimestamp || entryTime > mostRecentTimestamp) {
|
|
55525
|
-
mostRecentTimestamp = entryTime;
|
|
55526
|
-
mostRecentMainChainEntry = data;
|
|
55527
|
-
}
|
|
55528
|
-
}
|
|
55529
|
-
}
|
|
55530
|
-
} catch {}
|
|
55531
|
-
}
|
|
55532
|
-
if (mostRecentMainChainEntry?.message?.usage) {
|
|
55533
|
-
const usage = mostRecentMainChainEntry.message.usage;
|
|
55534
|
-
contextLength = (usage.input_tokens || 0) + (usage.cache_read_input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0);
|
|
55535
|
-
}
|
|
55536
|
-
const totalTokens = inputTokens + outputTokens + cachedTokens;
|
|
55537
|
-
return { inputTokens, outputTokens, cachedTokens, totalTokens, contextLength };
|
|
55538
|
-
} catch {
|
|
55539
|
-
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
55540
|
-
}
|
|
55541
|
-
}
|
|
55753
|
+
|
|
55754
|
+
// src/utils/jsonl-blocks.ts
|
|
55755
|
+
var statSync5 = fs8.statSync;
|
|
55542
55756
|
function getBlockMetrics() {
|
|
55543
55757
|
const claudeDir = getClaudeConfigDir();
|
|
55544
55758
|
if (!claudeDir)
|
|
@@ -55552,7 +55766,7 @@ function getBlockMetrics() {
|
|
|
55552
55766
|
function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
55553
55767
|
const sessionDurationMs = sessionDurationHours * 60 * 60 * 1000;
|
|
55554
55768
|
const now = new Date;
|
|
55555
|
-
const pattern =
|
|
55769
|
+
const pattern = path7.posix.join(rootDir.replace(/\\/g, "/"), "projects", "**", "*.jsonl");
|
|
55556
55770
|
const files = globSync([pattern], {
|
|
55557
55771
|
absolute: true,
|
|
55558
55772
|
cwd: rootDir
|
|
@@ -55560,7 +55774,7 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
|
55560
55774
|
if (files.length === 0)
|
|
55561
55775
|
return null;
|
|
55562
55776
|
const filesWithStats = files.map((file2) => {
|
|
55563
|
-
const stats =
|
|
55777
|
+
const stats = statSync5(file2);
|
|
55564
55778
|
return { file: file2, mtime: stats.mtime };
|
|
55565
55779
|
});
|
|
55566
55780
|
filesWithStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
@@ -55646,30 +55860,27 @@ function findMostRecentBlockStartTime(rootDir, sessionDurationHours = 5) {
|
|
|
55646
55860
|
function getAllTimestampsFromFile(filePath) {
|
|
55647
55861
|
const timestamps = [];
|
|
55648
55862
|
try {
|
|
55649
|
-
const
|
|
55650
|
-
const lines = content.trim().split(`
|
|
55651
|
-
`).filter((line) => line.length > 0);
|
|
55863
|
+
const lines = readJsonlLinesSync(filePath);
|
|
55652
55864
|
for (const line of lines) {
|
|
55653
|
-
|
|
55654
|
-
|
|
55655
|
-
const usage = json2.message?.usage;
|
|
55656
|
-
if (!usage)
|
|
55657
|
-
continue;
|
|
55658
|
-
const hasInputTokens = typeof usage.input_tokens === "number";
|
|
55659
|
-
const hasOutputTokens = typeof usage.output_tokens === "number";
|
|
55660
|
-
if (!hasInputTokens || !hasOutputTokens)
|
|
55661
|
-
continue;
|
|
55662
|
-
if (json2.isSidechain === true)
|
|
55663
|
-
continue;
|
|
55664
|
-
const timestamp = json2.timestamp;
|
|
55665
|
-
if (typeof timestamp !== "string")
|
|
55666
|
-
continue;
|
|
55667
|
-
const date5 = new Date(timestamp);
|
|
55668
|
-
if (!Number.isNaN(date5.getTime()))
|
|
55669
|
-
timestamps.push(date5);
|
|
55670
|
-
} catch {
|
|
55865
|
+
const json2 = parseJsonlLine(line);
|
|
55866
|
+
if (!json2) {
|
|
55671
55867
|
continue;
|
|
55672
55868
|
}
|
|
55869
|
+
const usage = json2.message?.usage;
|
|
55870
|
+
if (!usage)
|
|
55871
|
+
continue;
|
|
55872
|
+
const hasInputTokens = typeof usage.input_tokens === "number";
|
|
55873
|
+
const hasOutputTokens = typeof usage.output_tokens === "number";
|
|
55874
|
+
if (!hasInputTokens || !hasOutputTokens)
|
|
55875
|
+
continue;
|
|
55876
|
+
if (json2.isSidechain === true)
|
|
55877
|
+
continue;
|
|
55878
|
+
const timestamp = json2.timestamp;
|
|
55879
|
+
if (typeof timestamp !== "string")
|
|
55880
|
+
continue;
|
|
55881
|
+
const date5 = new Date(timestamp);
|
|
55882
|
+
if (!Number.isNaN(date5.getTime()))
|
|
55883
|
+
timestamps.push(date5);
|
|
55673
55884
|
}
|
|
55674
55885
|
return timestamps;
|
|
55675
55886
|
} catch {
|
|
@@ -55682,268 +55893,187 @@ function floorToHour(timestamp) {
|
|
|
55682
55893
|
return floored;
|
|
55683
55894
|
}
|
|
55684
55895
|
|
|
55685
|
-
// src/utils/
|
|
55686
|
-
var
|
|
55687
|
-
var
|
|
55688
|
-
var
|
|
55689
|
-
var
|
|
55690
|
-
|
|
55691
|
-
|
|
55692
|
-
var FIVE_HOUR_BLOCK_MS = 5 * 60 * 60 * 1000;
|
|
55693
|
-
var UsageErrorSchema = exports_external.enum(["no-credentials", "timeout", "api-error", "parse-error"]);
|
|
55694
|
-
var UsageCredentialsSchema = exports_external.object({ claudeAiOauth: exports_external.object({ accessToken: exports_external.string().nullable().optional() }).optional() });
|
|
55695
|
-
var CachedUsageDataSchema = exports_external.object({
|
|
55696
|
-
sessionUsage: exports_external.number().nullable().optional(),
|
|
55697
|
-
sessionResetAt: exports_external.string().nullable().optional(),
|
|
55698
|
-
weeklyUsage: exports_external.number().nullable().optional(),
|
|
55699
|
-
extraUsageEnabled: exports_external.boolean().nullable().optional(),
|
|
55700
|
-
extraUsageLimit: exports_external.number().nullable().optional(),
|
|
55701
|
-
extraUsageUsed: exports_external.number().nullable().optional(),
|
|
55702
|
-
extraUsageUtilization: exports_external.number().nullable().optional(),
|
|
55703
|
-
error: exports_external.string().nullable().optional()
|
|
55704
|
-
});
|
|
55705
|
-
var UsageApiResponseSchema = exports_external.object({
|
|
55706
|
-
five_hour: exports_external.object({
|
|
55707
|
-
utilization: exports_external.number().nullable().optional(),
|
|
55708
|
-
reset_at: exports_external.string().nullable().optional(),
|
|
55709
|
-
resets_at: exports_external.string().nullable().optional()
|
|
55710
|
-
}).optional(),
|
|
55711
|
-
seven_day: exports_external.object({ utilization: exports_external.number().nullable().optional() }).optional(),
|
|
55712
|
-
extra_usage: exports_external.object({
|
|
55713
|
-
is_enabled: exports_external.boolean().nullable().optional(),
|
|
55714
|
-
monthly_limit: exports_external.number().nullable().optional(),
|
|
55715
|
-
used_credits: exports_external.number().nullable().optional(),
|
|
55716
|
-
utilization: exports_external.number().nullable().optional()
|
|
55717
|
-
}).optional()
|
|
55718
|
-
});
|
|
55719
|
-
function parseJsonWithSchema(rawJson, schema) {
|
|
55720
|
-
try {
|
|
55721
|
-
const parsed = schema.safeParse(JSON.parse(rawJson));
|
|
55722
|
-
return parsed.success ? parsed.data : null;
|
|
55723
|
-
} catch {
|
|
55724
|
-
return null;
|
|
55725
|
-
}
|
|
55726
|
-
}
|
|
55727
|
-
function parseUsageAccessToken(rawJson) {
|
|
55728
|
-
const parsed = parseJsonWithSchema(rawJson, UsageCredentialsSchema);
|
|
55729
|
-
return parsed?.claudeAiOauth?.accessToken ?? null;
|
|
55730
|
-
}
|
|
55731
|
-
function parseCachedUsageData(rawJson) {
|
|
55732
|
-
const parsed = parseJsonWithSchema(rawJson, CachedUsageDataSchema);
|
|
55733
|
-
if (!parsed) {
|
|
55734
|
-
return null;
|
|
55735
|
-
}
|
|
55736
|
-
const parsedError = UsageErrorSchema.safeParse(parsed.error);
|
|
55737
|
-
return {
|
|
55738
|
-
sessionUsage: parsed.sessionUsage ?? undefined,
|
|
55739
|
-
sessionResetAt: parsed.sessionResetAt ?? undefined,
|
|
55740
|
-
weeklyUsage: parsed.weeklyUsage ?? undefined,
|
|
55741
|
-
extraUsageEnabled: parsed.extraUsageEnabled ?? undefined,
|
|
55742
|
-
extraUsageLimit: parsed.extraUsageLimit ?? undefined,
|
|
55743
|
-
extraUsageUsed: parsed.extraUsageUsed ?? undefined,
|
|
55744
|
-
extraUsageUtilization: parsed.extraUsageUtilization ?? undefined,
|
|
55745
|
-
error: parsedError.success ? parsedError.data : undefined
|
|
55746
|
-
};
|
|
55747
|
-
}
|
|
55748
|
-
function parseUsageApiResponse(rawJson) {
|
|
55749
|
-
const parsed = parseJsonWithSchema(rawJson, UsageApiResponseSchema);
|
|
55750
|
-
if (!parsed) {
|
|
55751
|
-
return null;
|
|
55752
|
-
}
|
|
55753
|
-
return {
|
|
55754
|
-
sessionUsage: parsed.five_hour?.utilization ?? undefined,
|
|
55755
|
-
sessionResetAt: parsed.five_hour?.resets_at ?? parsed.five_hour?.reset_at ?? undefined,
|
|
55756
|
-
weeklyUsage: parsed.seven_day?.utilization ?? undefined,
|
|
55757
|
-
extraUsageEnabled: parsed.extra_usage?.is_enabled ?? undefined,
|
|
55758
|
-
extraUsageLimit: parsed.extra_usage?.monthly_limit ?? undefined,
|
|
55759
|
-
extraUsageUsed: parsed.extra_usage?.used_credits ?? undefined,
|
|
55760
|
-
extraUsageUtilization: parsed.extra_usage?.utilization ?? undefined
|
|
55761
|
-
};
|
|
55762
|
-
}
|
|
55763
|
-
var cachedUsageData = null;
|
|
55764
|
-
var usageCacheTime = 0;
|
|
55765
|
-
var cachedUsageToken = null;
|
|
55766
|
-
var usageTokenCacheTime = 0;
|
|
55767
|
-
function setCachedUsageError(error43, now) {
|
|
55768
|
-
const errorData = { error: error43 };
|
|
55769
|
-
cachedUsageData = errorData;
|
|
55770
|
-
usageCacheTime = now;
|
|
55771
|
-
return errorData;
|
|
55896
|
+
// src/utils/jsonl-cache.ts
|
|
55897
|
+
var readFileSync7 = fs9.readFileSync;
|
|
55898
|
+
var writeFileSync3 = fs9.writeFileSync;
|
|
55899
|
+
var mkdirSync4 = fs9.mkdirSync;
|
|
55900
|
+
var existsSync8 = fs9.existsSync;
|
|
55901
|
+
function normalizeConfigDir(configDir) {
|
|
55902
|
+
return path8.resolve(configDir);
|
|
55772
55903
|
}
|
|
55773
|
-
function
|
|
55774
|
-
const
|
|
55775
|
-
|
|
55776
|
-
|
|
55777
|
-
usageCacheTime = now;
|
|
55778
|
-
return stale;
|
|
55779
|
-
}
|
|
55780
|
-
return setCachedUsageError(error43, now);
|
|
55904
|
+
function getBlockCachePath(configDir = getClaudeConfigDir()) {
|
|
55905
|
+
const normalizedConfigDir = normalizeConfigDir(configDir);
|
|
55906
|
+
const configHash = createHash("sha256").update(normalizedConfigDir).digest("hex").slice(0, 16);
|
|
55907
|
+
return path8.join(os7.homedir(), ".cache", "ccstatusline", `block-cache-${configHash}.json`);
|
|
55781
55908
|
}
|
|
55782
|
-
function
|
|
55783
|
-
const now = Math.floor(Date.now() / 1000);
|
|
55784
|
-
if (cachedUsageToken && now - usageTokenCacheTime < TOKEN_CACHE_MAX_AGE) {
|
|
55785
|
-
return cachedUsageToken;
|
|
55786
|
-
}
|
|
55909
|
+
function readBlockCache(expectedConfigDir) {
|
|
55787
55910
|
try {
|
|
55788
|
-
const
|
|
55789
|
-
|
|
55790
|
-
|
|
55791
|
-
|
|
55792
|
-
|
|
55793
|
-
|
|
55794
|
-
|
|
55911
|
+
const normalizedExpectedConfigDir = expectedConfigDir !== undefined ? normalizeConfigDir(expectedConfigDir) : undefined;
|
|
55912
|
+
const cachePath = getBlockCachePath(normalizedExpectedConfigDir);
|
|
55913
|
+
if (!existsSync8(cachePath)) {
|
|
55914
|
+
return null;
|
|
55915
|
+
}
|
|
55916
|
+
const content = readFileSync7(cachePath, "utf-8");
|
|
55917
|
+
const cache3 = JSON.parse(content);
|
|
55918
|
+
if (typeof cache3.startTime !== "string") {
|
|
55919
|
+
return null;
|
|
55920
|
+
}
|
|
55921
|
+
if (normalizedExpectedConfigDir !== undefined) {
|
|
55922
|
+
if (typeof cache3.configDir !== "string") {
|
|
55923
|
+
return null;
|
|
55924
|
+
}
|
|
55925
|
+
if (cache3.configDir !== normalizedExpectedConfigDir) {
|
|
55926
|
+
return null;
|
|
55795
55927
|
}
|
|
55796
|
-
return token2;
|
|
55797
55928
|
}
|
|
55798
|
-
const
|
|
55799
|
-
|
|
55800
|
-
|
|
55801
|
-
cachedUsageToken = token;
|
|
55802
|
-
usageTokenCacheTime = now;
|
|
55929
|
+
const date5 = new Date(cache3.startTime);
|
|
55930
|
+
if (Number.isNaN(date5.getTime())) {
|
|
55931
|
+
return null;
|
|
55803
55932
|
}
|
|
55804
|
-
return
|
|
55933
|
+
return date5;
|
|
55805
55934
|
} catch {
|
|
55806
55935
|
return null;
|
|
55807
55936
|
}
|
|
55808
55937
|
}
|
|
55809
|
-
function
|
|
55938
|
+
function writeBlockCache(startTime, configDir = getClaudeConfigDir()) {
|
|
55810
55939
|
try {
|
|
55811
|
-
|
|
55812
|
-
|
|
55813
|
-
|
|
55814
|
-
|
|
55940
|
+
const normalizedConfigDir = normalizeConfigDir(configDir);
|
|
55941
|
+
const cachePath = getBlockCachePath(normalizedConfigDir);
|
|
55942
|
+
const cacheDir = path8.dirname(cachePath);
|
|
55943
|
+
if (!existsSync8(cacheDir)) {
|
|
55944
|
+
mkdirSync4(cacheDir, { recursive: true });
|
|
55945
|
+
}
|
|
55946
|
+
const cache3 = {
|
|
55947
|
+
startTime: startTime.toISOString(),
|
|
55948
|
+
configDir: normalizedConfigDir
|
|
55949
|
+
};
|
|
55950
|
+
writeFileSync3(cachePath, JSON.stringify(cache3), "utf-8");
|
|
55951
|
+
} catch {}
|
|
55815
55952
|
}
|
|
55816
|
-
function
|
|
55817
|
-
const
|
|
55818
|
-
|
|
55819
|
-
|
|
55820
|
-
|
|
55821
|
-
|
|
55822
|
-
|
|
55823
|
-
|
|
55824
|
-
|
|
55825
|
-
|
|
55826
|
-
|
|
55827
|
-
|
|
55828
|
-
|
|
55829
|
-
|
|
55830
|
-
|
|
55831
|
-
|
|
55832
|
-
|
|
55833
|
-
};
|
|
55834
|
-
|
|
55835
|
-
const req = https.request(options, (res) => {
|
|
55836
|
-
let data = '';
|
|
55837
|
-
res.on('data', chunk => data += chunk);
|
|
55838
|
-
res.on('end', () => {
|
|
55839
|
-
if (res.statusCode === 200 && data) {
|
|
55840
|
-
process.stdout.write(data);
|
|
55841
|
-
} else {
|
|
55842
|
-
process.exit(1);
|
|
55843
|
-
}
|
|
55844
|
-
});
|
|
55845
|
-
});
|
|
55846
|
-
|
|
55847
|
-
req.on('error', () => process.exit(1));
|
|
55848
|
-
req.on('timeout', () => {
|
|
55849
|
-
req.destroy();
|
|
55850
|
-
process.exit(1);
|
|
55851
|
-
});
|
|
55852
|
-
req.end();
|
|
55853
|
-
`;
|
|
55854
|
-
const runtimePath = process.execPath || "node";
|
|
55855
|
-
const result = spawnSync2(runtimePath, ["-e", script], {
|
|
55856
|
-
encoding: "utf8",
|
|
55857
|
-
timeout: 6000,
|
|
55858
|
-
env: { ...process.env, TOKEN: token }
|
|
55859
|
-
});
|
|
55860
|
-
if (result.error || result.status !== 0 || !result.stdout) {
|
|
55861
|
-
return null;
|
|
55953
|
+
function getCachedBlockMetrics(sessionDurationHours = 5) {
|
|
55954
|
+
const sessionDurationMs = sessionDurationHours * 60 * 60 * 1000;
|
|
55955
|
+
const now = new Date;
|
|
55956
|
+
const activeConfigDir = getClaudeConfigDir();
|
|
55957
|
+
const cachedStartTime = readBlockCache(activeConfigDir);
|
|
55958
|
+
if (cachedStartTime) {
|
|
55959
|
+
const blockEndTime = new Date(cachedStartTime.getTime() + sessionDurationMs);
|
|
55960
|
+
if (now.getTime() <= blockEndTime.getTime()) {
|
|
55961
|
+
return {
|
|
55962
|
+
startTime: cachedStartTime,
|
|
55963
|
+
lastActivity: now
|
|
55964
|
+
};
|
|
55965
|
+
}
|
|
55966
|
+
}
|
|
55967
|
+
const metrics = getBlockMetrics();
|
|
55968
|
+
if (metrics) {
|
|
55969
|
+
writeBlockCache(metrics.startTime, activeConfigDir);
|
|
55862
55970
|
}
|
|
55863
|
-
return
|
|
55971
|
+
return metrics;
|
|
55864
55972
|
}
|
|
55865
|
-
|
|
55866
|
-
|
|
55867
|
-
|
|
55868
|
-
|
|
55869
|
-
if (!
|
|
55870
|
-
return
|
|
55973
|
+
// src/utils/jsonl-metrics.ts
|
|
55974
|
+
import * as fs10 from "fs";
|
|
55975
|
+
async function getSessionDuration(transcriptPath) {
|
|
55976
|
+
try {
|
|
55977
|
+
if (!fs10.existsSync(transcriptPath)) {
|
|
55978
|
+
return null;
|
|
55871
55979
|
}
|
|
55872
|
-
|
|
55873
|
-
|
|
55980
|
+
const lines = await readJsonlLines(transcriptPath);
|
|
55981
|
+
if (lines.length === 0) {
|
|
55982
|
+
return null;
|
|
55874
55983
|
}
|
|
55875
|
-
|
|
55876
|
-
|
|
55877
|
-
const
|
|
55878
|
-
|
|
55879
|
-
|
|
55880
|
-
|
|
55881
|
-
|
|
55882
|
-
cachedUsageData = fileData;
|
|
55883
|
-
usageCacheTime = now;
|
|
55884
|
-
return fileData;
|
|
55984
|
+
let firstTimestamp = null;
|
|
55985
|
+
let lastTimestamp = null;
|
|
55986
|
+
for (const line of lines) {
|
|
55987
|
+
const data = parseJsonlLine(line);
|
|
55988
|
+
if (data?.timestamp) {
|
|
55989
|
+
firstTimestamp = new Date(data.timestamp);
|
|
55990
|
+
break;
|
|
55885
55991
|
}
|
|
55886
55992
|
}
|
|
55887
|
-
|
|
55888
|
-
|
|
55889
|
-
|
|
55890
|
-
|
|
55891
|
-
|
|
55892
|
-
|
|
55893
|
-
|
|
55894
|
-
|
|
55895
|
-
|
|
55896
|
-
|
|
55897
|
-
if (stale && !stale.error)
|
|
55898
|
-
return stale;
|
|
55899
|
-
return { error: "timeout" };
|
|
55993
|
+
for (let i = lines.length - 1;i >= 0; i--) {
|
|
55994
|
+
const line = lines[i];
|
|
55995
|
+
if (!line) {
|
|
55996
|
+
continue;
|
|
55997
|
+
}
|
|
55998
|
+
const data = parseJsonlLine(line);
|
|
55999
|
+
if (data?.timestamp) {
|
|
56000
|
+
lastTimestamp = new Date(data.timestamp);
|
|
56001
|
+
break;
|
|
56002
|
+
}
|
|
55900
56003
|
}
|
|
55901
|
-
|
|
55902
|
-
|
|
55903
|
-
const lockDir = path7.dirname(LOCK_FILE);
|
|
55904
|
-
if (!fs7.existsSync(lockDir)) {
|
|
55905
|
-
fs7.mkdirSync(lockDir, { recursive: true });
|
|
56004
|
+
if (!firstTimestamp || !lastTimestamp) {
|
|
56005
|
+
return null;
|
|
55906
56006
|
}
|
|
55907
|
-
|
|
55908
|
-
|
|
55909
|
-
|
|
55910
|
-
|
|
55911
|
-
if (!response) {
|
|
55912
|
-
return getStaleUsageOrError("api-error", now);
|
|
56007
|
+
const durationMs = lastTimestamp.getTime() - firstTimestamp.getTime();
|
|
56008
|
+
const totalMinutes = Math.floor(durationMs / (1000 * 60));
|
|
56009
|
+
if (totalMinutes < 1) {
|
|
56010
|
+
return "<1m";
|
|
55913
56011
|
}
|
|
55914
|
-
const
|
|
55915
|
-
|
|
55916
|
-
|
|
56012
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
56013
|
+
const minutes = totalMinutes % 60;
|
|
56014
|
+
if (hours === 0) {
|
|
56015
|
+
return `${minutes}m`;
|
|
56016
|
+
} else if (minutes === 0) {
|
|
56017
|
+
return `${hours}hr`;
|
|
56018
|
+
} else {
|
|
56019
|
+
return `${hours}hr ${minutes}m`;
|
|
55917
56020
|
}
|
|
55918
|
-
|
|
55919
|
-
|
|
56021
|
+
} catch {
|
|
56022
|
+
return null;
|
|
56023
|
+
}
|
|
56024
|
+
}
|
|
56025
|
+
async function getTokenMetrics(transcriptPath) {
|
|
56026
|
+
try {
|
|
56027
|
+
if (!fs10.existsSync(transcriptPath)) {
|
|
56028
|
+
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
55920
56029
|
}
|
|
55921
|
-
|
|
55922
|
-
|
|
55923
|
-
|
|
56030
|
+
const lines = await readJsonlLines(transcriptPath);
|
|
56031
|
+
let inputTokens = 0;
|
|
56032
|
+
let outputTokens = 0;
|
|
56033
|
+
let cachedTokens = 0;
|
|
56034
|
+
let contextLength = 0;
|
|
56035
|
+
let mostRecentMainChainEntry = null;
|
|
56036
|
+
let mostRecentTimestamp = null;
|
|
56037
|
+
for (const line of lines) {
|
|
56038
|
+
const data = parseJsonlLine(line);
|
|
56039
|
+
if (data?.message?.usage) {
|
|
56040
|
+
inputTokens += data.message.usage.input_tokens || 0;
|
|
56041
|
+
outputTokens += data.message.usage.output_tokens || 0;
|
|
56042
|
+
cachedTokens += data.message.usage.cache_read_input_tokens ?? 0;
|
|
56043
|
+
cachedTokens += data.message.usage.cache_creation_input_tokens ?? 0;
|
|
56044
|
+
if (data.isSidechain !== true && data.timestamp && !data.isApiErrorMessage) {
|
|
56045
|
+
const entryTime = new Date(data.timestamp);
|
|
56046
|
+
if (!mostRecentTimestamp || entryTime > mostRecentTimestamp) {
|
|
56047
|
+
mostRecentTimestamp = entryTime;
|
|
56048
|
+
mostRecentMainChainEntry = data;
|
|
56049
|
+
}
|
|
56050
|
+
}
|
|
55924
56051
|
}
|
|
55925
|
-
|
|
55926
|
-
|
|
55927
|
-
|
|
55928
|
-
|
|
55929
|
-
|
|
56052
|
+
}
|
|
56053
|
+
if (mostRecentMainChainEntry?.message?.usage) {
|
|
56054
|
+
const usage = mostRecentMainChainEntry.message.usage;
|
|
56055
|
+
contextLength = (usage.input_tokens || 0) + (usage.cache_read_input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0);
|
|
56056
|
+
}
|
|
56057
|
+
const totalTokens = inputTokens + outputTokens + cachedTokens;
|
|
56058
|
+
return { inputTokens, outputTokens, cachedTokens, totalTokens, contextLength };
|
|
55930
56059
|
} catch {
|
|
55931
|
-
return
|
|
56060
|
+
return { inputTokens: 0, outputTokens: 0, cachedTokens: 0, totalTokens: 0, contextLength: 0 };
|
|
55932
56061
|
}
|
|
55933
56062
|
}
|
|
56063
|
+
// src/utils/usage-windows.ts
|
|
55934
56064
|
function clamp(value, min, max) {
|
|
55935
56065
|
return Math.max(min, Math.min(max, value));
|
|
55936
56066
|
}
|
|
55937
|
-
function buildUsageWindow(resetAtMs, nowMs) {
|
|
55938
|
-
if (!Number.isFinite(resetAtMs) || !Number.isFinite(nowMs)) {
|
|
56067
|
+
function buildUsageWindow(resetAtMs, nowMs, durationMs) {
|
|
56068
|
+
if (!Number.isFinite(resetAtMs) || !Number.isFinite(nowMs) || !Number.isFinite(durationMs) || durationMs <= 0) {
|
|
55939
56069
|
return null;
|
|
55940
56070
|
}
|
|
55941
|
-
const startAtMs = resetAtMs -
|
|
55942
|
-
const elapsedMs = clamp(nowMs - startAtMs, 0,
|
|
55943
|
-
const remainingMs =
|
|
55944
|
-
const elapsedPercent = elapsedMs /
|
|
56071
|
+
const startAtMs = resetAtMs - durationMs;
|
|
56072
|
+
const elapsedMs = clamp(nowMs - startAtMs, 0, durationMs);
|
|
56073
|
+
const remainingMs = durationMs - elapsedMs;
|
|
56074
|
+
const elapsedPercent = elapsedMs / durationMs * 100;
|
|
55945
56075
|
return {
|
|
55946
|
-
sessionDurationMs:
|
|
56076
|
+
sessionDurationMs: durationMs,
|
|
55947
56077
|
elapsedMs,
|
|
55948
56078
|
remainingMs,
|
|
55949
56079
|
elapsedPercent,
|
|
@@ -55958,14 +56088,14 @@ function getUsageWindowFromResetAt(sessionResetAt, nowMs = Date.now()) {
|
|
|
55958
56088
|
if (Number.isNaN(resetAtMs)) {
|
|
55959
56089
|
return null;
|
|
55960
56090
|
}
|
|
55961
|
-
return buildUsageWindow(resetAtMs, nowMs);
|
|
56091
|
+
return buildUsageWindow(resetAtMs, nowMs, FIVE_HOUR_BLOCK_MS);
|
|
55962
56092
|
}
|
|
55963
56093
|
function getUsageWindowFromBlockMetrics(blockMetrics, nowMs = Date.now()) {
|
|
55964
56094
|
const startAtMs = blockMetrics.startTime.getTime();
|
|
55965
56095
|
if (Number.isNaN(startAtMs)) {
|
|
55966
56096
|
return null;
|
|
55967
56097
|
}
|
|
55968
|
-
return buildUsageWindow(startAtMs + FIVE_HOUR_BLOCK_MS, nowMs);
|
|
56098
|
+
return buildUsageWindow(startAtMs + FIVE_HOUR_BLOCK_MS, nowMs, FIVE_HOUR_BLOCK_MS);
|
|
55969
56099
|
}
|
|
55970
56100
|
function resolveUsageWindowWithFallback(usageData, blockMetrics, nowMs = Date.now()) {
|
|
55971
56101
|
const usageWindow = getUsageWindowFromResetAt(usageData.sessionResetAt, nowMs);
|
|
@@ -55978,6 +56108,19 @@ function resolveUsageWindowWithFallback(usageData, blockMetrics, nowMs = Date.no
|
|
|
55978
56108
|
}
|
|
55979
56109
|
return getUsageWindowFromBlockMetrics(fallbackMetrics, nowMs);
|
|
55980
56110
|
}
|
|
56111
|
+
function getWeeklyUsageWindowFromResetAt(weeklyResetAt, nowMs = Date.now()) {
|
|
56112
|
+
if (!weeklyResetAt) {
|
|
56113
|
+
return null;
|
|
56114
|
+
}
|
|
56115
|
+
const resetAtMs = Date.parse(weeklyResetAt);
|
|
56116
|
+
if (Number.isNaN(resetAtMs)) {
|
|
56117
|
+
return null;
|
|
56118
|
+
}
|
|
56119
|
+
return buildUsageWindow(resetAtMs, nowMs, SEVEN_DAY_WINDOW_MS);
|
|
56120
|
+
}
|
|
56121
|
+
function resolveWeeklyUsageWindow(usageData, nowMs = Date.now()) {
|
|
56122
|
+
return getWeeklyUsageWindowFromResetAt(usageData.weeklyResetAt, nowMs);
|
|
56123
|
+
}
|
|
55981
56124
|
function formatUsageDuration(durationMs) {
|
|
55982
56125
|
const clampedMs = Math.max(0, durationMs);
|
|
55983
56126
|
const elapsedHours = Math.floor(clampedMs / (1000 * 60 * 60));
|
|
@@ -56004,7 +56147,6 @@ function makeUsageProgressBar(percent, width = 15) {
|
|
|
56004
56147
|
const empty2 = width - filled;
|
|
56005
56148
|
return "[" + "█".repeat(filled) + "░".repeat(empty2) + "]";
|
|
56006
56149
|
}
|
|
56007
|
-
|
|
56008
56150
|
// src/widgets/shared/usage-display.ts
|
|
56009
56151
|
function getUsageDisplayMode(item) {
|
|
56010
56152
|
const mode = item.metadata?.display;
|
|
@@ -56102,7 +56244,7 @@ class BlockTimerWidget {
|
|
|
56102
56244
|
}
|
|
56103
56245
|
return formatRawOrLabeledValue(item, "Block: ", "3hr 45m");
|
|
56104
56246
|
}
|
|
56105
|
-
const usageData =
|
|
56247
|
+
const usageData = context.usageData ?? {};
|
|
56106
56248
|
const window2 = resolveUsageWindowWithFallback(usageData, context.blockMetrics);
|
|
56107
56249
|
if (!window2) {
|
|
56108
56250
|
if (isUsageProgressMode(displayMode)) {
|
|
@@ -56283,27 +56425,27 @@ class CurrentWorkingDirWidget {
|
|
|
56283
56425
|
supportsColors(item) {
|
|
56284
56426
|
return true;
|
|
56285
56427
|
}
|
|
56286
|
-
abbreviateHomeDir(
|
|
56428
|
+
abbreviateHomeDir(path9) {
|
|
56287
56429
|
const homeDir = os8.homedir();
|
|
56288
|
-
if (
|
|
56430
|
+
if (path9 === homeDir) {
|
|
56289
56431
|
return "~";
|
|
56290
56432
|
}
|
|
56291
|
-
if (
|
|
56292
|
-
const boundaryChar =
|
|
56433
|
+
if (path9.startsWith(homeDir)) {
|
|
56434
|
+
const boundaryChar = path9[homeDir.length];
|
|
56293
56435
|
if (boundaryChar !== "/" && boundaryChar !== "\\") {
|
|
56294
|
-
return
|
|
56436
|
+
return path9;
|
|
56295
56437
|
}
|
|
56296
|
-
return "~" +
|
|
56438
|
+
return "~" + path9.slice(homeDir.length);
|
|
56297
56439
|
}
|
|
56298
|
-
return
|
|
56440
|
+
return path9;
|
|
56299
56441
|
}
|
|
56300
|
-
abbreviatePath(
|
|
56442
|
+
abbreviatePath(path9) {
|
|
56301
56443
|
const homeDir = os8.homedir();
|
|
56302
|
-
const useBackslash =
|
|
56444
|
+
const useBackslash = path9.includes("\\") && !path9.includes("/");
|
|
56303
56445
|
const sep2 = useBackslash ? "\\" : "/";
|
|
56304
|
-
let normalizedPath =
|
|
56305
|
-
if (
|
|
56306
|
-
normalizedPath = "~" +
|
|
56446
|
+
let normalizedPath = path9;
|
|
56447
|
+
if (path9.startsWith(homeDir)) {
|
|
56448
|
+
normalizedPath = "~" + path9.slice(homeDir.length);
|
|
56307
56449
|
}
|
|
56308
56450
|
const parts = normalizedPath.split(/[\\/]+/).filter((part) => part !== "");
|
|
56309
56451
|
const abbreviated = parts.map((part, index) => {
|
|
@@ -56503,7 +56645,7 @@ class FreeMemoryWidget {
|
|
|
56503
56645
|
}
|
|
56504
56646
|
}
|
|
56505
56647
|
// src/widgets/SessionName.ts
|
|
56506
|
-
import * as
|
|
56648
|
+
import * as fs11 from "fs";
|
|
56507
56649
|
|
|
56508
56650
|
class SessionNameWidget {
|
|
56509
56651
|
getDefaultColor() {
|
|
@@ -56530,7 +56672,7 @@ class SessionNameWidget {
|
|
|
56530
56672
|
return null;
|
|
56531
56673
|
}
|
|
56532
56674
|
try {
|
|
56533
|
-
const content =
|
|
56675
|
+
const content = fs11.readFileSync(transcriptPath, "utf-8");
|
|
56534
56676
|
const lines = content.split(`
|
|
56535
56677
|
`);
|
|
56536
56678
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -56596,7 +56738,7 @@ class SessionUsageWidget {
|
|
|
56596
56738
|
}
|
|
56597
56739
|
return formatRawOrLabeledValue(item, "Session: ", `${previewPercent.toFixed(1)}%`);
|
|
56598
56740
|
}
|
|
56599
|
-
const data =
|
|
56741
|
+
const data = context.usageData ?? {};
|
|
56600
56742
|
if (data.error)
|
|
56601
56743
|
return getUsageErrorMessage(data.error);
|
|
56602
56744
|
if (data.sessionUsage === undefined)
|
|
@@ -56665,7 +56807,7 @@ class WeeklyUsageWidget {
|
|
|
56665
56807
|
}
|
|
56666
56808
|
return formatRawOrLabeledValue(item, "Weekly: ", `${previewPercent.toFixed(1)}%`);
|
|
56667
56809
|
}
|
|
56668
|
-
const data =
|
|
56810
|
+
const data = context.usageData ?? {};
|
|
56669
56811
|
if (data.error)
|
|
56670
56812
|
return getUsageErrorMessage(data.error);
|
|
56671
56813
|
if (data.weeklyUsage === undefined)
|
|
@@ -56692,7 +56834,7 @@ class WeeklyUsageWidget {
|
|
|
56692
56834
|
return true;
|
|
56693
56835
|
}
|
|
56694
56836
|
}
|
|
56695
|
-
// src/widgets/
|
|
56837
|
+
// src/widgets/BlockResetTimer.ts
|
|
56696
56838
|
function makeTimerProgressBar2(percent, width) {
|
|
56697
56839
|
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
56698
56840
|
const filledWidth = Math.floor(clampedPercent / 100 * width);
|
|
@@ -56700,15 +56842,15 @@ function makeTimerProgressBar2(percent, width) {
|
|
|
56700
56842
|
return "█".repeat(filledWidth) + "░".repeat(emptyWidth);
|
|
56701
56843
|
}
|
|
56702
56844
|
|
|
56703
|
-
class
|
|
56845
|
+
class BlockResetTimerWidget {
|
|
56704
56846
|
getDefaultColor() {
|
|
56705
56847
|
return "brightBlue";
|
|
56706
56848
|
}
|
|
56707
56849
|
getDescription() {
|
|
56708
|
-
return "Shows time remaining until current 5hr block reset";
|
|
56850
|
+
return "Shows time remaining until current 5hr block reset window";
|
|
56709
56851
|
}
|
|
56710
56852
|
getDisplayName() {
|
|
56711
|
-
return "Reset Timer";
|
|
56853
|
+
return "Block Reset Timer";
|
|
56712
56854
|
}
|
|
56713
56855
|
getCategory() {
|
|
56714
56856
|
return "Usage";
|
|
@@ -56740,7 +56882,7 @@ class ResetTimerWidget {
|
|
|
56740
56882
|
}
|
|
56741
56883
|
return formatRawOrLabeledValue(item, "Reset: ", "4hr 30m");
|
|
56742
56884
|
}
|
|
56743
|
-
const usageData =
|
|
56885
|
+
const usageData = context.usageData ?? {};
|
|
56744
56886
|
const window2 = resolveUsageWindowWithFallback(usageData, context.blockMetrics);
|
|
56745
56887
|
if (!window2) {
|
|
56746
56888
|
if (usageData.error) {
|
|
@@ -56771,6 +56913,85 @@ class ResetTimerWidget {
|
|
|
56771
56913
|
return true;
|
|
56772
56914
|
}
|
|
56773
56915
|
}
|
|
56916
|
+
// src/widgets/WeeklyResetTimer.ts
|
|
56917
|
+
function makeTimerProgressBar3(percent, width) {
|
|
56918
|
+
const clampedPercent = Math.max(0, Math.min(100, percent));
|
|
56919
|
+
const filledWidth = Math.floor(clampedPercent / 100 * width);
|
|
56920
|
+
const emptyWidth = width - filledWidth;
|
|
56921
|
+
return "█".repeat(filledWidth) + "░".repeat(emptyWidth);
|
|
56922
|
+
}
|
|
56923
|
+
|
|
56924
|
+
class WeeklyResetTimerWidget {
|
|
56925
|
+
getDefaultColor() {
|
|
56926
|
+
return "brightBlue";
|
|
56927
|
+
}
|
|
56928
|
+
getDescription() {
|
|
56929
|
+
return "Shows time remaining until weekly usage reset";
|
|
56930
|
+
}
|
|
56931
|
+
getDisplayName() {
|
|
56932
|
+
return "Weekly Reset Timer";
|
|
56933
|
+
}
|
|
56934
|
+
getCategory() {
|
|
56935
|
+
return "Usage";
|
|
56936
|
+
}
|
|
56937
|
+
getEditorDisplay(item) {
|
|
56938
|
+
return {
|
|
56939
|
+
displayText: this.getDisplayName(),
|
|
56940
|
+
modifierText: getUsageDisplayModifierText(item)
|
|
56941
|
+
};
|
|
56942
|
+
}
|
|
56943
|
+
handleEditorAction(action, item) {
|
|
56944
|
+
if (action === "toggle-progress") {
|
|
56945
|
+
return cycleUsageDisplayMode(item);
|
|
56946
|
+
}
|
|
56947
|
+
if (action === "toggle-invert") {
|
|
56948
|
+
return toggleUsageInverted(item);
|
|
56949
|
+
}
|
|
56950
|
+
return null;
|
|
56951
|
+
}
|
|
56952
|
+
render(item, context, settings) {
|
|
56953
|
+
const displayMode = getUsageDisplayMode(item);
|
|
56954
|
+
const inverted = isUsageInverted(item);
|
|
56955
|
+
if (context.isPreview) {
|
|
56956
|
+
const previewPercent = inverted ? 90 : 10;
|
|
56957
|
+
if (isUsageProgressMode(displayMode)) {
|
|
56958
|
+
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
56959
|
+
const progressBar = makeTimerProgressBar3(previewPercent, barWidth);
|
|
56960
|
+
return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${previewPercent.toFixed(1)}%`);
|
|
56961
|
+
}
|
|
56962
|
+
return formatRawOrLabeledValue(item, "Weekly Reset: ", "36hr 30m");
|
|
56963
|
+
}
|
|
56964
|
+
const usageData = context.usageData ?? {};
|
|
56965
|
+
const window2 = resolveWeeklyUsageWindow(usageData);
|
|
56966
|
+
if (!window2) {
|
|
56967
|
+
if (usageData.error) {
|
|
56968
|
+
return getUsageErrorMessage(usageData.error);
|
|
56969
|
+
}
|
|
56970
|
+
return null;
|
|
56971
|
+
}
|
|
56972
|
+
if (isUsageProgressMode(displayMode)) {
|
|
56973
|
+
const barWidth = getUsageProgressBarWidth(displayMode);
|
|
56974
|
+
const percent = inverted ? window2.remainingPercent : window2.elapsedPercent;
|
|
56975
|
+
const progressBar = makeTimerProgressBar3(percent, barWidth);
|
|
56976
|
+
const percentage = percent.toFixed(1);
|
|
56977
|
+
return formatRawOrLabeledValue(item, "Weekly Reset ", `[${progressBar}] ${percentage}%`);
|
|
56978
|
+
}
|
|
56979
|
+
const remainingTime = formatUsageDuration(window2.remainingMs);
|
|
56980
|
+
return formatRawOrLabeledValue(item, "Weekly Reset: ", remainingTime);
|
|
56981
|
+
}
|
|
56982
|
+
getCustomKeybinds() {
|
|
56983
|
+
return [
|
|
56984
|
+
{ key: "p", label: "(p)rogress toggle", action: "toggle-progress" },
|
|
56985
|
+
{ key: "v", label: "in(v)ert fill", action: "toggle-invert" }
|
|
56986
|
+
];
|
|
56987
|
+
}
|
|
56988
|
+
supportsRawValue() {
|
|
56989
|
+
return true;
|
|
56990
|
+
}
|
|
56991
|
+
supportsColors(item) {
|
|
56992
|
+
return true;
|
|
56993
|
+
}
|
|
56994
|
+
}
|
|
56774
56995
|
// src/widgets/ContextBar.ts
|
|
56775
56996
|
function getDisplayMode(item) {
|
|
56776
56997
|
return item.metadata?.display === "progress" ? "progress" : "progress-short";
|
|
@@ -57047,45 +57268,64 @@ var LinkEditor = ({ widget, onComplete, onCancel, action }) => {
|
|
|
57047
57268
|
]
|
|
57048
57269
|
}, undefined, true, undefined, this);
|
|
57049
57270
|
};
|
|
57271
|
+
// src/utils/widget-manifest.ts
|
|
57272
|
+
var WIDGET_MANIFEST = [
|
|
57273
|
+
{ type: "model", create: () => new ModelWidget },
|
|
57274
|
+
{ type: "output-style", create: () => new OutputStyleWidget },
|
|
57275
|
+
{ type: "git-branch", create: () => new GitBranchWidget },
|
|
57276
|
+
{ type: "git-changes", create: () => new GitChangesWidget },
|
|
57277
|
+
{ type: "git-insertions", create: () => new GitInsertionsWidget },
|
|
57278
|
+
{ type: "git-deletions", create: () => new GitDeletionsWidget },
|
|
57279
|
+
{ type: "git-root-dir", create: () => new GitRootDirWidget },
|
|
57280
|
+
{ type: "git-worktree", create: () => new GitWorktreeWidget },
|
|
57281
|
+
{ type: "current-working-dir", create: () => new CurrentWorkingDirWidget },
|
|
57282
|
+
{ type: "tokens-input", create: () => new TokensInputWidget },
|
|
57283
|
+
{ type: "tokens-output", create: () => new TokensOutputWidget },
|
|
57284
|
+
{ type: "tokens-cached", create: () => new TokensCachedWidget },
|
|
57285
|
+
{ type: "tokens-total", create: () => new TokensTotalWidget },
|
|
57286
|
+
{ type: "context-length", create: () => new ContextLengthWidget },
|
|
57287
|
+
{ type: "context-percentage", create: () => new ContextPercentageWidget },
|
|
57288
|
+
{ type: "context-percentage-usable", create: () => new ContextPercentageUsableWidget },
|
|
57289
|
+
{ type: "session-clock", create: () => new SessionClockWidget },
|
|
57290
|
+
{ type: "session-cost", create: () => new SessionCostWidget },
|
|
57291
|
+
{ type: "block-timer", create: () => new BlockTimerWidget },
|
|
57292
|
+
{ type: "terminal-width", create: () => new TerminalWidthWidget },
|
|
57293
|
+
{ type: "version", create: () => new VersionWidget },
|
|
57294
|
+
{ type: "custom-text", create: () => new CustomTextWidget },
|
|
57295
|
+
{ type: "custom-command", create: () => new CustomCommandWidget },
|
|
57296
|
+
{ type: "link", create: () => new LinkWidget },
|
|
57297
|
+
{ type: "claude-session-id", create: () => new ClaudeSessionIdWidget },
|
|
57298
|
+
{ type: "session-name", create: () => new SessionNameWidget },
|
|
57299
|
+
{ type: "free-memory", create: () => new FreeMemoryWidget },
|
|
57300
|
+
{ type: "session-usage", create: () => new SessionUsageWidget },
|
|
57301
|
+
{ type: "weekly-usage", create: () => new WeeklyUsageWidget },
|
|
57302
|
+
{ type: "reset-timer", create: () => new BlockResetTimerWidget },
|
|
57303
|
+
{ type: "weekly-reset-timer", create: () => new WeeklyResetTimerWidget },
|
|
57304
|
+
{ type: "context-bar", create: () => new ContextBarWidget }
|
|
57305
|
+
];
|
|
57306
|
+
var LAYOUT_WIDGET_MANIFEST = [
|
|
57307
|
+
{
|
|
57308
|
+
type: "separator",
|
|
57309
|
+
displayName: "Separator",
|
|
57310
|
+
description: "A separator character between status line widgets",
|
|
57311
|
+
category: "Layout"
|
|
57312
|
+
},
|
|
57313
|
+
{
|
|
57314
|
+
type: "flex-separator",
|
|
57315
|
+
displayName: "Flex Separator",
|
|
57316
|
+
description: "Expands to fill available terminal width",
|
|
57317
|
+
category: "Layout"
|
|
57318
|
+
}
|
|
57319
|
+
];
|
|
57320
|
+
|
|
57050
57321
|
// src/utils/widgets.ts
|
|
57051
|
-
var widgetRegistry = new Map([
|
|
57052
|
-
|
|
57053
|
-
["output-style", new OutputStyleWidget],
|
|
57054
|
-
["git-branch", new GitBranchWidget],
|
|
57055
|
-
["git-changes", new GitChangesWidget],
|
|
57056
|
-
["git-insertions", new GitInsertionsWidget],
|
|
57057
|
-
["git-deletions", new GitDeletionsWidget],
|
|
57058
|
-
["git-root-dir", new GitRootDirWidget],
|
|
57059
|
-
["git-worktree", new GitWorktreeWidget],
|
|
57060
|
-
["current-working-dir", new CurrentWorkingDirWidget],
|
|
57061
|
-
["tokens-input", new TokensInputWidget],
|
|
57062
|
-
["tokens-output", new TokensOutputWidget],
|
|
57063
|
-
["tokens-cached", new TokensCachedWidget],
|
|
57064
|
-
["tokens-total", new TokensTotalWidget],
|
|
57065
|
-
["context-length", new ContextLengthWidget],
|
|
57066
|
-
["context-percentage", new ContextPercentageWidget],
|
|
57067
|
-
["context-percentage-usable", new ContextPercentageUsableWidget],
|
|
57068
|
-
["session-clock", new SessionClockWidget],
|
|
57069
|
-
["session-cost", new SessionCostWidget],
|
|
57070
|
-
["block-timer", new BlockTimerWidget],
|
|
57071
|
-
["terminal-width", new TerminalWidthWidget],
|
|
57072
|
-
["version", new VersionWidget],
|
|
57073
|
-
["custom-text", new CustomTextWidget],
|
|
57074
|
-
["custom-command", new CustomCommandWidget],
|
|
57075
|
-
["link", new LinkWidget],
|
|
57076
|
-
["claude-session-id", new ClaudeSessionIdWidget],
|
|
57077
|
-
["session-name", new SessionNameWidget],
|
|
57078
|
-
["free-memory", new FreeMemoryWidget],
|
|
57079
|
-
["session-usage", new SessionUsageWidget],
|
|
57080
|
-
["weekly-usage", new WeeklyUsageWidget],
|
|
57081
|
-
["reset-timer", new ResetTimerWidget],
|
|
57082
|
-
["context-bar", new ContextBarWidget]
|
|
57083
|
-
]);
|
|
57322
|
+
var widgetRegistry = new Map(WIDGET_MANIFEST.map((entry) => [entry.type, entry.create()]));
|
|
57323
|
+
var layoutWidgetTypes = new Set(LAYOUT_WIDGET_MANIFEST.map((entry) => entry.type));
|
|
57084
57324
|
function getWidget(type) {
|
|
57085
57325
|
return widgetRegistry.get(type) ?? null;
|
|
57086
57326
|
}
|
|
57087
57327
|
function getAllWidgetTypes(settings) {
|
|
57088
|
-
const allTypes =
|
|
57328
|
+
const allTypes = WIDGET_MANIFEST.map((entry) => entry.type);
|
|
57089
57329
|
if (!settings.powerline.enabled) {
|
|
57090
57330
|
if (!settings.defaultSeparator) {
|
|
57091
57331
|
allTypes.push("separator");
|
|
@@ -57094,30 +57334,18 @@ function getAllWidgetTypes(settings) {
|
|
|
57094
57334
|
}
|
|
57095
57335
|
return allTypes;
|
|
57096
57336
|
}
|
|
57097
|
-
var
|
|
57098
|
-
|
|
57099
|
-
|
|
57100
|
-
|
|
57101
|
-
|
|
57102
|
-
|
|
57103
|
-
|
|
57104
|
-
|
|
57105
|
-
description: "Expands to fill available terminal width",
|
|
57106
|
-
category: "Layout"
|
|
57337
|
+
var layoutCatalogEntries = new Map(LAYOUT_WIDGET_MANIFEST.map((entry) => [
|
|
57338
|
+
entry.type,
|
|
57339
|
+
{
|
|
57340
|
+
type: entry.type,
|
|
57341
|
+
displayName: entry.displayName,
|
|
57342
|
+
description: entry.description,
|
|
57343
|
+
category: entry.category,
|
|
57344
|
+
searchText: `${entry.displayName} ${entry.description} ${entry.type}`.toLowerCase()
|
|
57107
57345
|
}
|
|
57108
|
-
|
|
57346
|
+
]));
|
|
57109
57347
|
function getLayoutCatalogEntry(type) {
|
|
57110
|
-
|
|
57111
|
-
if (!layout) {
|
|
57112
|
-
return null;
|
|
57113
|
-
}
|
|
57114
|
-
return {
|
|
57115
|
-
type,
|
|
57116
|
-
displayName: layout.displayName,
|
|
57117
|
-
description: layout.description,
|
|
57118
|
-
category: layout.category,
|
|
57119
|
-
searchText: `${layout.displayName} ${layout.description} ${type}`.toLowerCase()
|
|
57120
|
-
};
|
|
57348
|
+
return layoutCatalogEntries.get(type) ?? null;
|
|
57121
57349
|
}
|
|
57122
57350
|
function getWidgetCatalog(settings) {
|
|
57123
57351
|
return getAllWidgetTypes(settings).map((type) => {
|
|
@@ -61200,7 +61428,7 @@ var App2 = () => {
|
|
|
61200
61428
|
});
|
|
61201
61429
|
const handleInstallSelection = import_react46.useCallback((command, displayName, useBunx) => {
|
|
61202
61430
|
getExistingStatusLine().then((existing) => {
|
|
61203
|
-
const isAlreadyInstalled =
|
|
61431
|
+
const isAlreadyInstalled = isKnownCommand(existing ?? "");
|
|
61204
61432
|
let message;
|
|
61205
61433
|
if (existing && !isAlreadyInstalled) {
|
|
61206
61434
|
message = `This will modify ${getClaudeSettingsPath()}
|
|
@@ -61347,6 +61575,10 @@ ${GITHUB_REPO_URL}`,
|
|
|
61347
61575
|
}, undefined, false, undefined, this)
|
|
61348
61576
|
]
|
|
61349
61577
|
}, undefined, true, undefined, this),
|
|
61578
|
+
isCustomConfigPath() && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
|
|
61579
|
+
dimColor: true,
|
|
61580
|
+
children: `Config: ${getConfigPath()}`
|
|
61581
|
+
}, undefined, false, undefined, this),
|
|
61350
61582
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusLinePreview, {
|
|
61351
61583
|
lines: settings.lines,
|
|
61352
61584
|
terminalWidth,
|
|
@@ -61578,6 +61810,24 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
61578
61810
|
}).nullable().optional()
|
|
61579
61811
|
});
|
|
61580
61812
|
|
|
61813
|
+
// src/utils/usage-prefetch.ts
|
|
61814
|
+
var USAGE_WIDGET_TYPES = new Set([
|
|
61815
|
+
"session-usage",
|
|
61816
|
+
"weekly-usage",
|
|
61817
|
+
"block-timer",
|
|
61818
|
+
"reset-timer",
|
|
61819
|
+
"weekly-reset-timer"
|
|
61820
|
+
]);
|
|
61821
|
+
function hasUsageDependentWidgets(lines) {
|
|
61822
|
+
return lines.some((line) => line.some((item) => USAGE_WIDGET_TYPES.has(item.type)));
|
|
61823
|
+
}
|
|
61824
|
+
async function prefetchUsageDataIfNeeded(lines) {
|
|
61825
|
+
if (!hasUsageDependentWidgets(lines)) {
|
|
61826
|
+
return null;
|
|
61827
|
+
}
|
|
61828
|
+
return await fetchUsageData();
|
|
61829
|
+
}
|
|
61830
|
+
|
|
61581
61831
|
// src/ccstatusline.ts
|
|
61582
61832
|
function hasSessionDurationInStatusJson(data) {
|
|
61583
61833
|
const durationMs = data.cost?.total_duration_ms;
|
|
@@ -61628,9 +61878,11 @@ async function renderMultipleLines(data) {
|
|
|
61628
61878
|
if (hasSessionClock && !hasSessionDurationInStatusJson(data) && data.transcript_path) {
|
|
61629
61879
|
sessionDuration = await getSessionDuration(data.transcript_path);
|
|
61630
61880
|
}
|
|
61881
|
+
const usageData = await prefetchUsageDataIfNeeded(lines);
|
|
61631
61882
|
const context = {
|
|
61632
61883
|
data,
|
|
61633
61884
|
tokenMetrics,
|
|
61885
|
+
usageData,
|
|
61634
61886
|
sessionDuration,
|
|
61635
61887
|
isPreview: false
|
|
61636
61888
|
};
|
|
@@ -61669,7 +61921,20 @@ async function renderMultipleLines(data) {
|
|
|
61669
61921
|
}
|
|
61670
61922
|
}
|
|
61671
61923
|
}
|
|
61924
|
+
function parseConfigArg() {
|
|
61925
|
+
const idx = process.argv.indexOf("--config");
|
|
61926
|
+
if (idx === -1)
|
|
61927
|
+
return;
|
|
61928
|
+
const configPath = process.argv[idx + 1];
|
|
61929
|
+
if (!configPath || configPath.startsWith("--")) {
|
|
61930
|
+
console.error("--config requires a file path argument");
|
|
61931
|
+
process.exit(1);
|
|
61932
|
+
}
|
|
61933
|
+
process.argv.splice(idx, 2);
|
|
61934
|
+
return configPath;
|
|
61935
|
+
}
|
|
61672
61936
|
async function main() {
|
|
61937
|
+
initConfigPath(parseConfigArg());
|
|
61673
61938
|
if (!process.stdin.isTTY) {
|
|
61674
61939
|
await ensureWindowsUtf8CodePage();
|
|
61675
61940
|
const input = await readStdin();
|