ccstatusline-usage 2.3.17 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -3
- package/dist/ccstatusline.js +251 -124
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
1
|
<pre>
|
|
4
2
|
_ _ _ _
|
|
5
3
|
___ ___ ___| |_ __ _| |_ _ _ ___| (_)_ __ ___
|
|
@@ -36,6 +34,42 @@ This fork adds API-based usage widgets beyond the upstream:
|
|
|
36
34
|
- **Context Window Display** - Visual bar showing context usage
|
|
37
35
|
- **Off Peak** - Shows peak/off-peak status with countdown timer (peak hours drain sessions faster)
|
|
38
36
|
- **Two-line Layout** - Session info on line 1, context on line 2
|
|
37
|
+
- **Multi-provider routing** - Usage widgets dispatch per model: Anthropic models hit the usage API; opencode/local models (GLM, Kimi, MiniMax, Qwen, Ollama) skip the fetch and gracefully hide usage bars while keeping the real-time context bar.
|
|
38
|
+
|
|
39
|
+
### Multi-Provider Routing (Opencode / Local Models)
|
|
40
|
+
|
|
41
|
+
Claude Code can route individual prompts to non-Anthropic backends via opencode or a local Ollama runtime. The status line reads the `model.id` that Claude Code sends on stdin each render and dispatches through a per-provider resolver (`src/utils/usage/resolver.ts`):
|
|
42
|
+
|
|
43
|
+
- **Anthropic** (`opus`, `sonnet`, `haiku` in the id) — fetches Session/Weekly/Reset from the usage API.
|
|
44
|
+
- **Opencode** (`glm`, `kimi`, `minimax`, `mm-`, `qwen`, `owen`, `mimo`) — no usage API call; Session/Weekly/Reset widgets hide themselves. Context Bar still renders when `context_window` is in the payload.
|
|
45
|
+
- **Unknown model id** — same behavior as opencode (hides usage widgets).
|
|
46
|
+
|
|
47
|
+
This means opencode-routed turns don't trigger pointless Anthropic API calls or rate-limiting during heavy local usage.
|
|
48
|
+
|
|
49
|
+
Example — configure Claude Code to route a model through opencode (edit `~/.claude/settings.json`):
|
|
50
|
+
|
|
51
|
+
```jsonc
|
|
52
|
+
{
|
|
53
|
+
"statusLine": {
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "npx -y ccstatusline-usage@latest",
|
|
56
|
+
"padding": 0
|
|
57
|
+
},
|
|
58
|
+
"model": "glm-5.1" // or "kimi-k2.6", "minimax-m2.7", "qwen-3.6-plus", "qwen3.6:35b-a3b-q4_K_M" for local Ollama
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
What the status line renders per model:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
# Anthropic (opus / sonnet / haiku)
|
|
66
|
+
Session: [████░░░░░░░░░░░] 27.0% | Weekly: [████░░░░░░░░░░░] 34.0% | 2:03 hr | Model: Opus 4.7
|
|
67
|
+
Context: [██████░░░░░░░░░] 389k/1M (39%) | Pace: [░░░░░░█|░░░░░░░] D4/7 -8% | Off-peak (4:03 hr)
|
|
68
|
+
|
|
69
|
+
# Opencode / local (glm-5.1, kimi, qwen, …)
|
|
70
|
+
Model: glm-5.1 | Off-peak (4:03 hr)
|
|
71
|
+
Context: [██░░░░░░░░░░░░░] 50k/200k (25%)
|
|
72
|
+
```
|
|
39
73
|
|
|
40
74
|
### Enhanced Status Line Preview
|
|
41
75
|
|
|
@@ -46,7 +80,6 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
46
80
|
|
|
47
81
|

|
|
48
82
|
|
|
49
|
-
</div>
|
|
50
83
|
<br />
|
|
51
84
|
|
|
52
85
|
## 📚 Table of Contents
|
|
@@ -67,6 +100,20 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
67
100
|
|
|
68
101
|
## 🆕 Recent Updates
|
|
69
102
|
|
|
103
|
+
### [v2.4.1](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.4.1) - Weekly Pace: showPercent toggle + decimal precision
|
|
104
|
+
|
|
105
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **`%` keybind — always show delta on `On Pace`** — Previously `On Pace` was the only pace band that hid its delta. Toggle `showPercent` in the editor to render `D4/7: On Pace +3%` (or `-2%`, or `+0%`) so you can see how close to a band edge you are.
|
|
106
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **`.` keybind — decimal precision** — Cycles 0 → 1 → 2 → 3 → 0 decimal places for all deltas (Warm/Cool/Overcooking/Underusing, `On Pace` when `showPercent` is on, and the pendulum bar). Replaces `Math.round()` with `toFixed(decimals)` in a shared `formatDelta` helper.
|
|
107
|
+
- Both toggles are metadata-gated and orthogonal — omitted keys behave identically to before.
|
|
108
|
+
- Thanks to @BenIsLegit ([#3](https://github.com/pcvelz/ccstatusline-usage/pull/3)).
|
|
109
|
+
|
|
110
|
+
### [v2.4.0](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.4.0) - Multi-provider router for usage widgets
|
|
111
|
+
|
|
112
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Provider pattern end-to-end** — Usage widgets now dispatch through `resolveProvider(modelId)` in `src/utils/usage/resolver.ts`. Anthropic models (`opus`/`sonnet`/`haiku`) fetch from the usage API; opencode/local models (`glm`, `kimi`, `minimax`, `mm-`, `qwen`, `owen`, `mimo`) skip the fetch entirely so heavy local-model sessions no longer trigger needless Anthropic API calls or rate-limiting.
|
|
113
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): The prefetch layer (`usage-prefetch.ts`) now reads `data.model.id` from the payload and dispatches via `provider.fetchUsage()` instead of the hardcoded Anthropic path. `opencodeProvider` / `nullProvider` return empty `UsageData`, so Session/Weekly/Reset widgets hide themselves naturally.
|
|
114
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Context Bar stays backend-agnostic** — renders whenever `context_window` is present in the payload, regardless of which provider handled the turn.
|
|
115
|
+
- See the new [Multi-Provider Routing](#multi-provider-routing-opencode--local-models) section under Fork Enhancements for example config.
|
|
116
|
+
|
|
70
117
|
### [v2.3.17](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.17) - Local model fallback for API usage widgets
|
|
71
118
|
|
|
72
119
|
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Local model fallback** — When the active model is not Opus/Sonnet/Haiku (e.g. a local Ollama model like `qwen3-coder:30b`), the Session, Weekly, and Context widgets now render empty-bar placeholders (`[░░░░░░░░░░░░░░░] -.0%`) and the Reset Timer shows `-:00 hr` instead of misleading Claude API values.
|
package/dist/ccstatusline.js
CHANGED
|
@@ -52556,7 +52556,7 @@ class OutputStyleWidget {
|
|
|
52556
52556
|
}
|
|
52557
52557
|
|
|
52558
52558
|
// src/utils/git.ts
|
|
52559
|
-
import {
|
|
52559
|
+
import { execFileSync } from "child_process";
|
|
52560
52560
|
function resolveGitCwd(context) {
|
|
52561
52561
|
const candidates = [
|
|
52562
52562
|
context.data?.cwd,
|
|
@@ -52571,13 +52571,18 @@ function resolveGitCwd(context) {
|
|
|
52571
52571
|
return;
|
|
52572
52572
|
}
|
|
52573
52573
|
function runGit(command, context) {
|
|
52574
|
+
const args = command.trim().split(/\s+/).filter(Boolean);
|
|
52575
|
+
return runGitArgs(args, context, command);
|
|
52576
|
+
}
|
|
52577
|
+
function runGitArgs(args, context, cacheCommand) {
|
|
52574
52578
|
const cwd2 = resolveGitCwd(context);
|
|
52575
|
-
const
|
|
52579
|
+
const cacheToken = cacheCommand ?? args.join("\x00");
|
|
52580
|
+
const cacheKey = `${cacheToken}|${cwd2 ?? ""}`;
|
|
52576
52581
|
if (gitCommandCache.has(cacheKey)) {
|
|
52577
52582
|
return gitCommandCache.get(cacheKey) ?? null;
|
|
52578
52583
|
}
|
|
52579
52584
|
try {
|
|
52580
|
-
const output =
|
|
52585
|
+
const output = execFileSync("git", args, {
|
|
52581
52586
|
encoding: "utf8",
|
|
52582
52587
|
stdio: ["pipe", "pipe", "ignore"],
|
|
52583
52588
|
...cwd2 ? { cwd: cwd2 } : {}
|
|
@@ -53136,7 +53141,7 @@ var init_GitRootDir = __esm(() => {
|
|
|
53136
53141
|
});
|
|
53137
53142
|
|
|
53138
53143
|
// src/utils/gh-pr-cache.ts
|
|
53139
|
-
import { execFileSync } from "child_process";
|
|
53144
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
53140
53145
|
import {
|
|
53141
53146
|
existsSync as existsSync2,
|
|
53142
53147
|
mkdirSync,
|
|
@@ -53278,7 +53283,7 @@ function truncateTitle(title, maxWidth) {
|
|
|
53278
53283
|
var PR_CACHE_TTL = 30000, GH_TIMEOUT = 5000, DEFAULT_TITLE_MAX_WIDTH = 30, DEFAULT_PR_CACHE_DEPS;
|
|
53279
53284
|
var init_gh_pr_cache = __esm(() => {
|
|
53280
53285
|
DEFAULT_PR_CACHE_DEPS = {
|
|
53281
|
-
execFileSync,
|
|
53286
|
+
execFileSync: execFileSync2,
|
|
53282
53287
|
existsSync: existsSync2,
|
|
53283
53288
|
mkdirSync,
|
|
53284
53289
|
readFileSync: readFileSync2,
|
|
@@ -53956,7 +53961,7 @@ function parseRemoteUrl(url2) {
|
|
|
53956
53961
|
}
|
|
53957
53962
|
}
|
|
53958
53963
|
function getRemoteInfo(remoteName, context) {
|
|
53959
|
-
const url2 =
|
|
53964
|
+
const url2 = runGitArgs(["remote", "get-url", "--", remoteName], context, `remote get-url -- ${remoteName}`);
|
|
53960
53965
|
if (!url2) {
|
|
53961
53966
|
return null;
|
|
53962
53967
|
}
|
|
@@ -55301,6 +55306,15 @@ function getContextConfig(modelIdentifier, contextWindowSize) {
|
|
|
55301
55306
|
if (!modelIdentifier) {
|
|
55302
55307
|
return defaultConfig;
|
|
55303
55308
|
}
|
|
55309
|
+
const normalizedModel = modelIdentifier.toLowerCase().trim();
|
|
55310
|
+
for (const [modelName, contextSize] of Object.entries(OPENCODE_MODEL_CONTEXT_MAP)) {
|
|
55311
|
+
if (normalizedModel.includes(modelName)) {
|
|
55312
|
+
return {
|
|
55313
|
+
maxTokens: contextSize,
|
|
55314
|
+
usableTokens: Math.floor(contextSize * USABLE_CONTEXT_RATIO)
|
|
55315
|
+
};
|
|
55316
|
+
}
|
|
55317
|
+
}
|
|
55304
55318
|
const inferredWindowSize = parseContextWindowSize(modelIdentifier);
|
|
55305
55319
|
if (inferredWindowSize !== null) {
|
|
55306
55320
|
return {
|
|
@@ -55310,7 +55324,24 @@ function getContextConfig(modelIdentifier, contextWindowSize) {
|
|
|
55310
55324
|
}
|
|
55311
55325
|
return defaultConfig;
|
|
55312
55326
|
}
|
|
55313
|
-
var DEFAULT_CONTEXT_WINDOW_SIZE = 200000, USABLE_CONTEXT_RATIO = 0.8;
|
|
55327
|
+
var DEFAULT_CONTEXT_WINDOW_SIZE = 200000, USABLE_CONTEXT_RATIO = 0.8, OPENCODE_MODEL_CONTEXT_MAP;
|
|
55328
|
+
var init_model_context = __esm(() => {
|
|
55329
|
+
OPENCODE_MODEL_CONTEXT_MAP = {
|
|
55330
|
+
"glm-5.1": 1e6,
|
|
55331
|
+
"glm-4.5": 1e6,
|
|
55332
|
+
"glm-4.0": 1e6,
|
|
55333
|
+
"mm-2.7": 1e6,
|
|
55334
|
+
"mm-2.5": 1e6,
|
|
55335
|
+
"kimi-k2.6": 1e6,
|
|
55336
|
+
"kimi-k2.5": 1e6,
|
|
55337
|
+
"owen-3.6": 1e6,
|
|
55338
|
+
"owen-3.5": 1e6,
|
|
55339
|
+
"qwen-2.5": 1e6,
|
|
55340
|
+
"qwen-2.0": 1e6,
|
|
55341
|
+
"qwen-1.5": 1e6,
|
|
55342
|
+
"qwen-1.0": 1e6
|
|
55343
|
+
};
|
|
55344
|
+
});
|
|
55314
55345
|
|
|
55315
55346
|
// src/utils/context-percentage.ts
|
|
55316
55347
|
function calculateContextPercentage(context) {
|
|
@@ -55325,10 +55356,12 @@ function calculateContextPercentage(context) {
|
|
|
55325
55356
|
const contextConfig = getContextConfig(modelIdentifier, contextWindowMetrics.windowSize);
|
|
55326
55357
|
return Math.min(100, context.tokenMetrics.contextLength / contextConfig.maxTokens * 100);
|
|
55327
55358
|
}
|
|
55328
|
-
var init_context_percentage = () => {
|
|
55359
|
+
var init_context_percentage = __esm(() => {
|
|
55360
|
+
init_model_context();
|
|
55361
|
+
});
|
|
55329
55362
|
|
|
55330
55363
|
// src/utils/terminal.ts
|
|
55331
|
-
import { execSync
|
|
55364
|
+
import { execSync } from "child_process";
|
|
55332
55365
|
import * as fs2 from "fs";
|
|
55333
55366
|
import * as path2 from "path";
|
|
55334
55367
|
function getPackageVersion() {
|
|
@@ -55352,7 +55385,7 @@ function getPackageVersion() {
|
|
|
55352
55385
|
function probeTerminalWidth() {
|
|
55353
55386
|
if (process.env.TMUX) {
|
|
55354
55387
|
try {
|
|
55355
|
-
const output =
|
|
55388
|
+
const output = execSync("tmux display-message -p '#{pane_width}'", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], timeout: 2000 }).trim();
|
|
55356
55389
|
const parsed = parseInt(output, 10);
|
|
55357
55390
|
if (!isNaN(parsed) && parsed > 0)
|
|
55358
55391
|
return parsed;
|
|
@@ -55378,7 +55411,7 @@ function probeTerminalWidth() {
|
|
|
55378
55411
|
}
|
|
55379
55412
|
}
|
|
55380
55413
|
try {
|
|
55381
|
-
const width =
|
|
55414
|
+
const width = execSync("tput cols 2>/dev/null", {
|
|
55382
55415
|
encoding: "utf8",
|
|
55383
55416
|
stdio: ["pipe", "pipe", "ignore"]
|
|
55384
55417
|
}).trim();
|
|
@@ -55395,7 +55428,7 @@ function parsePositiveInteger(value) {
|
|
|
55395
55428
|
}
|
|
55396
55429
|
function getParentProcessId(pid) {
|
|
55397
55430
|
try {
|
|
55398
|
-
const parentPidOutput =
|
|
55431
|
+
const parentPidOutput = execSync(`ps -o ppid= -p ${pid}`, {
|
|
55399
55432
|
encoding: "utf8",
|
|
55400
55433
|
stdio: ["pipe", "pipe", "ignore"],
|
|
55401
55434
|
shell: "/bin/sh"
|
|
@@ -55407,7 +55440,7 @@ function getParentProcessId(pid) {
|
|
|
55407
55440
|
}
|
|
55408
55441
|
function getTTYForProcess(pid) {
|
|
55409
55442
|
try {
|
|
55410
|
-
const tty2 =
|
|
55443
|
+
const tty2 = execSync(`ps -o tty= -p ${pid}`, {
|
|
55411
55444
|
encoding: "utf8",
|
|
55412
55445
|
stdio: ["pipe", "pipe", "ignore"],
|
|
55413
55446
|
shell: "/bin/sh"
|
|
@@ -55422,7 +55455,7 @@ function getTTYForProcess(pid) {
|
|
|
55422
55455
|
}
|
|
55423
55456
|
function getWidthForTTY(tty2) {
|
|
55424
55457
|
try {
|
|
55425
|
-
const width =
|
|
55458
|
+
const width = execSync(`stty size < /dev/${tty2} | awk '{print $2}'`, {
|
|
55426
55459
|
encoding: "utf8",
|
|
55427
55460
|
stdio: ["pipe", "pipe", "ignore"],
|
|
55428
55461
|
shell: "/bin/sh"
|
|
@@ -55438,7 +55471,7 @@ function getTerminalWidth() {
|
|
|
55438
55471
|
function canDetectTerminalWidth() {
|
|
55439
55472
|
return probeTerminalWidth() !== null;
|
|
55440
55473
|
}
|
|
55441
|
-
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.
|
|
55474
|
+
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.4.1";
|
|
55442
55475
|
var init_terminal = () => {};
|
|
55443
55476
|
|
|
55444
55477
|
// src/utils/renderer.ts
|
|
@@ -56311,6 +56344,7 @@ class ContextPercentageWidget {
|
|
|
56311
56344
|
}
|
|
56312
56345
|
}
|
|
56313
56346
|
var init_ContextPercentage = __esm(() => {
|
|
56347
|
+
init_model_context();
|
|
56314
56348
|
init_context_inverse();
|
|
56315
56349
|
});
|
|
56316
56350
|
|
|
@@ -56371,6 +56405,7 @@ class ContextPercentageUsableWidget {
|
|
|
56371
56405
|
}
|
|
56372
56406
|
}
|
|
56373
56407
|
var init_ContextPercentageUsable = __esm(() => {
|
|
56408
|
+
init_model_context();
|
|
56374
56409
|
init_context_inverse();
|
|
56375
56410
|
});
|
|
56376
56411
|
|
|
@@ -57026,7 +57061,7 @@ var init_CustomSymbol = __esm(async () => {
|
|
|
57026
57061
|
});
|
|
57027
57062
|
|
|
57028
57063
|
// src/widgets/CustomCommand.tsx
|
|
57029
|
-
import { execSync as
|
|
57064
|
+
import { execSync as execSync2 } from "child_process";
|
|
57030
57065
|
|
|
57031
57066
|
class CustomCommandWidget {
|
|
57032
57067
|
getDefaultColor() {
|
|
@@ -57073,7 +57108,7 @@ class CustomCommandWidget {
|
|
|
57073
57108
|
try {
|
|
57074
57109
|
const timeout = item.timeout ?? 1000;
|
|
57075
57110
|
const jsonInput = JSON.stringify(context.data);
|
|
57076
|
-
let output =
|
|
57111
|
+
let output = execSync2(item.commandPath, {
|
|
57077
57112
|
encoding: "utf8",
|
|
57078
57113
|
input: jsonInput,
|
|
57079
57114
|
timeout,
|
|
@@ -58237,7 +58272,7 @@ var init_usage_types = __esm(() => {
|
|
|
58237
58272
|
});
|
|
58238
58273
|
|
|
58239
58274
|
// src/utils/usage-fetch.ts
|
|
58240
|
-
import { execFileSync as
|
|
58275
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
58241
58276
|
import * as fs3 from "fs";
|
|
58242
58277
|
import * as https from "https";
|
|
58243
58278
|
import * as os4 from "os";
|
|
@@ -58383,7 +58418,7 @@ function parseMacKeychainCredentialCandidates(rawDump, servicePrefix = MACOS_USA
|
|
|
58383
58418
|
}
|
|
58384
58419
|
function readMacKeychainSecret(service) {
|
|
58385
58420
|
try {
|
|
58386
|
-
return
|
|
58421
|
+
return execFileSync3("security", ["find-generic-password", "-s", service, "-w"], { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] }).trim();
|
|
58387
58422
|
} catch {
|
|
58388
58423
|
return null;
|
|
58389
58424
|
}
|
|
@@ -58394,7 +58429,7 @@ function readUsageTokenFromMacKeychainService(service) {
|
|
|
58394
58429
|
}
|
|
58395
58430
|
function listMacKeychainCredentialCandidates() {
|
|
58396
58431
|
try {
|
|
58397
|
-
const rawDump =
|
|
58432
|
+
const rawDump = execFileSync3("security", ["dump-keychain"], {
|
|
58398
58433
|
encoding: "utf8",
|
|
58399
58434
|
maxBuffer: MACOS_SECURITY_DUMP_MAX_BUFFER,
|
|
58400
58435
|
stdio: ["pipe", "pipe", "ignore"]
|
|
@@ -58640,7 +58675,8 @@ var init_usage_fetch = __esm(() => {
|
|
|
58640
58675
|
extraUsageLimit: exports_external.number().nullable().optional(),
|
|
58641
58676
|
extraUsageUsed: exports_external.number().nullable().optional(),
|
|
58642
58677
|
extraUsageUtilization: exports_external.number().nullable().optional(),
|
|
58643
|
-
error: exports_external.string().nullable().optional()
|
|
58678
|
+
error: exports_external.string().nullable().optional(),
|
|
58679
|
+
provider: exports_external.enum(["anthropic", "opencode"]).nullable().optional()
|
|
58644
58680
|
});
|
|
58645
58681
|
UsageApiResponseSchema = exports_external.object({
|
|
58646
58682
|
five_hour: exports_external.object({
|
|
@@ -62796,7 +62832,7 @@ var init_TotalSpeed = __esm(async () => {
|
|
|
62796
62832
|
});
|
|
62797
62833
|
|
|
62798
62834
|
// src/widgets/FreeMemory.ts
|
|
62799
|
-
import { execSync as
|
|
62835
|
+
import { execSync as execSync3 } from "child_process";
|
|
62800
62836
|
import os7 from "os";
|
|
62801
62837
|
function formatBytes(bytes) {
|
|
62802
62838
|
const GB = 1024 ** 3;
|
|
@@ -62812,7 +62848,7 @@ function formatBytes(bytes) {
|
|
|
62812
62848
|
}
|
|
62813
62849
|
function getUsedMemoryMacOS() {
|
|
62814
62850
|
try {
|
|
62815
|
-
const output =
|
|
62851
|
+
const output = execSync3("vm_stat", { encoding: "utf8" });
|
|
62816
62852
|
const lines = output.split(`
|
|
62817
62853
|
`);
|
|
62818
62854
|
const firstLine = lines[0];
|
|
@@ -62934,6 +62970,61 @@ class SessionNameWidget {
|
|
|
62934
62970
|
}
|
|
62935
62971
|
var init_SessionName = () => {};
|
|
62936
62972
|
|
|
62973
|
+
// src/utils/usage/providers/anthropic.ts
|
|
62974
|
+
var anthropicProvider;
|
|
62975
|
+
var init_anthropic = __esm(() => {
|
|
62976
|
+
init_usage_fetch();
|
|
62977
|
+
anthropicProvider = {
|
|
62978
|
+
name: "anthropic",
|
|
62979
|
+
async fetchUsage() {
|
|
62980
|
+
const data = await fetchUsageData();
|
|
62981
|
+
return { ...data, provider: "anthropic" };
|
|
62982
|
+
}
|
|
62983
|
+
};
|
|
62984
|
+
});
|
|
62985
|
+
|
|
62986
|
+
// src/utils/usage/providers/null.ts
|
|
62987
|
+
var nullProvider;
|
|
62988
|
+
var init_null = __esm(() => {
|
|
62989
|
+
nullProvider = {
|
|
62990
|
+
name: "null",
|
|
62991
|
+
fetchUsage() {
|
|
62992
|
+
return Promise.resolve({ provider: null });
|
|
62993
|
+
}
|
|
62994
|
+
};
|
|
62995
|
+
});
|
|
62996
|
+
|
|
62997
|
+
// src/utils/usage/providers/opencode.ts
|
|
62998
|
+
var opencodeProvider;
|
|
62999
|
+
var init_opencode = __esm(() => {
|
|
63000
|
+
opencodeProvider = {
|
|
63001
|
+
name: "opencode",
|
|
63002
|
+
fetchUsage() {
|
|
63003
|
+
return Promise.resolve({ provider: "opencode" });
|
|
63004
|
+
}
|
|
63005
|
+
};
|
|
63006
|
+
});
|
|
63007
|
+
|
|
63008
|
+
// src/utils/usage/resolver.ts
|
|
63009
|
+
function resolveProvider(modelId) {
|
|
63010
|
+
if (!modelId)
|
|
63011
|
+
return nullProvider;
|
|
63012
|
+
const id = modelId.toLowerCase();
|
|
63013
|
+
if (ANTHROPIC_KEYWORDS.some((k) => id.includes(k)))
|
|
63014
|
+
return anthropicProvider;
|
|
63015
|
+
if (OPENCODE_PATTERN.test(id))
|
|
63016
|
+
return opencodeProvider;
|
|
63017
|
+
return nullProvider;
|
|
63018
|
+
}
|
|
63019
|
+
var OPENCODE_PATTERN, ANTHROPIC_KEYWORDS;
|
|
63020
|
+
var init_resolver = __esm(() => {
|
|
63021
|
+
init_anthropic();
|
|
63022
|
+
init_null();
|
|
63023
|
+
init_opencode();
|
|
63024
|
+
OPENCODE_PATTERN = /(?:^|[^a-z])(glm|kimi|minimax|mm-|qwen|owen|mimo)/i;
|
|
63025
|
+
ANTHROPIC_KEYWORDS = ["opus", "sonnet", "haiku"];
|
|
63026
|
+
});
|
|
63027
|
+
|
|
62937
63028
|
// src/widgets/ApiUsage.tsx
|
|
62938
63029
|
function getDisplaySize(context) {
|
|
62939
63030
|
const w = context.terminalWidth ?? 0;
|
|
@@ -62991,17 +63082,6 @@ function getModelId(context) {
|
|
|
62991
63082
|
const model = context.data?.model;
|
|
62992
63083
|
return (typeof model === "string" ? model : model?.id) ?? "";
|
|
62993
63084
|
}
|
|
62994
|
-
function isLocalModel(context) {
|
|
62995
|
-
const modelId = getModelId(context);
|
|
62996
|
-
if (modelId === "")
|
|
62997
|
-
return false;
|
|
62998
|
-
return !(modelId.includes("opus") || modelId.includes("sonnet") || modelId.includes("haiku"));
|
|
62999
|
-
}
|
|
63000
|
-
function renderLocalUsageFallback(label, shortLabel, size2) {
|
|
63001
|
-
if (size2 === "mobile")
|
|
63002
|
-
return `${shortLabel}: [░░░░] -.0%`;
|
|
63003
|
-
return `${label}: [░░░░░░░░░░░░░░░] -.0%`;
|
|
63004
|
-
}
|
|
63005
63085
|
|
|
63006
63086
|
class SessionUsageWidget {
|
|
63007
63087
|
getDefaultColor() {
|
|
@@ -63028,8 +63108,8 @@ class SessionUsageWidget {
|
|
|
63028
63108
|
if (data.sessionUsage === undefined)
|
|
63029
63109
|
return null;
|
|
63030
63110
|
const size2 = getDisplaySize(context);
|
|
63031
|
-
if (
|
|
63032
|
-
return
|
|
63111
|
+
if (resolveProvider(getModelId(context)).name === "null")
|
|
63112
|
+
return null;
|
|
63033
63113
|
const extraUsed = data.extraUsageUsed;
|
|
63034
63114
|
const extraLimit = data.extraUsageLimit;
|
|
63035
63115
|
if (size2 !== "mobile" && data.extraUsageEnabled === true && extraUsed !== undefined && extraLimit !== undefined && data.sessionUsage >= 100 && (data.weeklyUsage === undefined || data.weeklyUsage < 100)) {
|
|
@@ -63071,8 +63151,8 @@ class WeeklyUsageWidget {
|
|
|
63071
63151
|
if (data.weeklyUsage === undefined)
|
|
63072
63152
|
return null;
|
|
63073
63153
|
const size2 = getDisplaySize(context);
|
|
63074
|
-
if (
|
|
63075
|
-
return
|
|
63154
|
+
if (resolveProvider(getModelId(context)).name === "null")
|
|
63155
|
+
return null;
|
|
63076
63156
|
const extraUsed = data.extraUsageUsed;
|
|
63077
63157
|
const extraLimit = data.extraUsageLimit;
|
|
63078
63158
|
if (data.extraUsageEnabled === true && extraUsed !== undefined && extraLimit !== undefined && data.weeklyUsage >= 100) {
|
|
@@ -63111,8 +63191,8 @@ class ResetTimerWidget {
|
|
|
63111
63191
|
const data = context.usageData ?? {};
|
|
63112
63192
|
if (data.error)
|
|
63113
63193
|
return getUsageErrorMessage(data.error);
|
|
63114
|
-
if (
|
|
63115
|
-
return
|
|
63194
|
+
if (resolveProvider(getModelId(context)).name === "null")
|
|
63195
|
+
return null;
|
|
63116
63196
|
const modelId = getModelId(context);
|
|
63117
63197
|
const is1mModel = modelId.includes("[1m]");
|
|
63118
63198
|
const isOpus = modelId.includes("opus");
|
|
@@ -63171,8 +63251,6 @@ class ContextBarWidget {
|
|
|
63171
63251
|
const cw = context.data?.context_window;
|
|
63172
63252
|
if (!cw)
|
|
63173
63253
|
return null;
|
|
63174
|
-
if (isLocalModel(context) && !getModelId(context).includes("qwen"))
|
|
63175
|
-
return renderLocalUsageFallback("Context", "C", getDisplaySize(context));
|
|
63176
63254
|
const total = Number(cw.context_window_size) || 200000;
|
|
63177
63255
|
let used = 0;
|
|
63178
63256
|
if (typeof cw.current_usage === "number") {
|
|
@@ -63202,6 +63280,7 @@ class ContextBarWidget {
|
|
|
63202
63280
|
var DARK_RED_OPEN2 = "\x1B[38;2;204;0;0m", DARK_RED_CLOSE2 = "\x1B[39m", MOBILE_THRESHOLD = 134, MEDIUM_THRESHOLD2 = 178, MOBILE_BAR_WIDTH = 4, MEDIUM_BAR_WIDTH = 8, DEFAULT_BAR_WIDTH = 15;
|
|
63203
63281
|
var init_ApiUsage = __esm(() => {
|
|
63204
63282
|
init_usage();
|
|
63283
|
+
init_resolver();
|
|
63205
63284
|
});
|
|
63206
63285
|
|
|
63207
63286
|
// src/widgets/WeeklyResetTimer.ts
|
|
@@ -63775,11 +63854,11 @@ var init_ThinkingEffort = __esm(() => {
|
|
|
63775
63854
|
});
|
|
63776
63855
|
|
|
63777
63856
|
// src/widgets/Battery.ts
|
|
63778
|
-
import { execSync as
|
|
63857
|
+
import { execSync as execSync4 } from "child_process";
|
|
63779
63858
|
import { readFileSync as readFileSync11 } from "fs";
|
|
63780
63859
|
function getMacBatteryInfo() {
|
|
63781
63860
|
try {
|
|
63782
|
-
const output =
|
|
63861
|
+
const output = execSync4("pmset -g batt", { encoding: "utf-8", timeout: 2000 });
|
|
63783
63862
|
const match = /(\d+)%;\s*(charging|discharging|charged|finishing charge|AC attached)/i.exec(output);
|
|
63784
63863
|
const percentStr = match?.[1];
|
|
63785
63864
|
const stateStr = match?.[2];
|
|
@@ -63976,18 +64055,28 @@ var init_VimMode = __esm(() => {
|
|
|
63976
64055
|
function getPaceDisplayMode(item) {
|
|
63977
64056
|
return item.metadata?.display === "pendulum" ? "pendulum" : "text";
|
|
63978
64057
|
}
|
|
63979
|
-
function
|
|
64058
|
+
function getDecimalPrecision(item) {
|
|
64059
|
+
const val = Number(item.metadata?.decimals);
|
|
64060
|
+
return val === 1 || val === 2 || val === 3 ? val : 0;
|
|
64061
|
+
}
|
|
64062
|
+
function formatDelta(delta, decimals) {
|
|
64063
|
+
return delta.toFixed(decimals);
|
|
64064
|
+
}
|
|
64065
|
+
function computePace(actualPercent, expectedPercent, showPercent = false, decimals = 0) {
|
|
63980
64066
|
const delta = actualPercent - expectedPercent;
|
|
63981
64067
|
const dayOfWeek = Math.max(1, Math.min(7, Math.ceil(expectedPercent * 7 / 100)));
|
|
63982
64068
|
let status;
|
|
63983
64069
|
if (delta > 15) {
|
|
63984
|
-
status = `Overcooking +${
|
|
64070
|
+
status = `Overcooking +${formatDelta(delta, decimals)}%`;
|
|
63985
64071
|
} else if (delta > 5) {
|
|
63986
|
-
status = `Warm +${
|
|
64072
|
+
status = `Warm +${formatDelta(delta, decimals)}%`;
|
|
63987
64073
|
} else if (delta < -15) {
|
|
63988
|
-
status = `Underusing ${
|
|
64074
|
+
status = `Underusing ${formatDelta(delta, decimals)}%`;
|
|
63989
64075
|
} else if (delta < -5) {
|
|
63990
|
-
status = `Cool ${
|
|
64076
|
+
status = `Cool ${formatDelta(delta, decimals)}%`;
|
|
64077
|
+
} else if (showPercent) {
|
|
64078
|
+
const sign = delta >= 0 ? "+" : "";
|
|
64079
|
+
status = `On Pace ${sign}${formatDelta(delta, decimals)}%`;
|
|
63991
64080
|
} else {
|
|
63992
64081
|
status = "On Pace";
|
|
63993
64082
|
}
|
|
@@ -64013,24 +64102,52 @@ class WeeklyPaceWidget {
|
|
|
64013
64102
|
if (mode === "pendulum") {
|
|
64014
64103
|
modifiers.push("pendulum bar");
|
|
64015
64104
|
}
|
|
64105
|
+
if (item.metadata?.showPercent === "true") {
|
|
64106
|
+
modifiers.push("always %");
|
|
64107
|
+
}
|
|
64108
|
+
const decimals = getDecimalPrecision(item);
|
|
64109
|
+
if (decimals > 0) {
|
|
64110
|
+
modifiers.push(`.${"0".repeat(decimals)}`);
|
|
64111
|
+
}
|
|
64016
64112
|
return {
|
|
64017
64113
|
displayText: this.getDisplayName(),
|
|
64018
64114
|
modifierText: makeModifierText(modifiers)
|
|
64019
64115
|
};
|
|
64020
64116
|
}
|
|
64021
64117
|
handleEditorAction(action, item) {
|
|
64022
|
-
if (action
|
|
64023
|
-
|
|
64118
|
+
if (action === "toggle-pendulum") {
|
|
64119
|
+
const currentMode = getPaceDisplayMode(item);
|
|
64120
|
+
const nextMode = currentMode === "text" ? "pendulum" : "text";
|
|
64121
|
+
return {
|
|
64122
|
+
...item,
|
|
64123
|
+
metadata: {
|
|
64124
|
+
...item.metadata ?? {},
|
|
64125
|
+
display: nextMode
|
|
64126
|
+
}
|
|
64127
|
+
};
|
|
64024
64128
|
}
|
|
64025
|
-
|
|
64026
|
-
|
|
64027
|
-
|
|
64028
|
-
|
|
64029
|
-
|
|
64030
|
-
|
|
64031
|
-
|
|
64032
|
-
|
|
64033
|
-
|
|
64129
|
+
if (action === "toggle-show-percent") {
|
|
64130
|
+
const current = item.metadata?.showPercent === "true";
|
|
64131
|
+
return {
|
|
64132
|
+
...item,
|
|
64133
|
+
metadata: {
|
|
64134
|
+
...item.metadata ?? {},
|
|
64135
|
+
showPercent: current ? "false" : "true"
|
|
64136
|
+
}
|
|
64137
|
+
};
|
|
64138
|
+
}
|
|
64139
|
+
if (action === "cycle-decimals") {
|
|
64140
|
+
const current = getDecimalPrecision(item);
|
|
64141
|
+
const next = current >= 3 ? 0 : current + 1;
|
|
64142
|
+
return {
|
|
64143
|
+
...item,
|
|
64144
|
+
metadata: {
|
|
64145
|
+
...item.metadata ?? {},
|
|
64146
|
+
decimals: String(next)
|
|
64147
|
+
}
|
|
64148
|
+
};
|
|
64149
|
+
}
|
|
64150
|
+
return null;
|
|
64034
64151
|
}
|
|
64035
64152
|
render(item, context, settings) {
|
|
64036
64153
|
const displayMode = getPaceDisplayMode(item);
|
|
@@ -64052,21 +64169,25 @@ class WeeklyPaceWidget {
|
|
|
64052
64169
|
if (!window2)
|
|
64053
64170
|
return null;
|
|
64054
64171
|
const actualPercent = Math.max(0, Math.min(100, data.weeklyUsage));
|
|
64055
|
-
const
|
|
64172
|
+
const showPercent = item.metadata?.showPercent === "true";
|
|
64173
|
+
const decimals = getDecimalPrecision(item);
|
|
64174
|
+
const { delta, dayOfWeek, status } = computePace(actualPercent, window2.elapsedPercent, showPercent, decimals);
|
|
64056
64175
|
const width = context.terminalWidth ?? 0;
|
|
64057
64176
|
const mobile = width > 0 && width < MOBILE_THRESHOLD2;
|
|
64058
64177
|
const medium = width >= MOBILE_THRESHOLD2 && width < MEDIUM_THRESHOLD3;
|
|
64059
64178
|
if (displayMode === "pendulum" && !mobile) {
|
|
64060
64179
|
const halfWidth = medium ? 4 : 7;
|
|
64061
64180
|
const sign = delta >= 0 ? "+" : "";
|
|
64062
|
-
const barDisplay = `${makePendulumBar(delta, halfWidth)} D${dayOfWeek}/7 ${sign}${
|
|
64181
|
+
const barDisplay = `${makePendulumBar(delta, halfWidth)} D${dayOfWeek}/7 ${sign}${formatDelta(delta, decimals)}%`;
|
|
64063
64182
|
return formatRawOrLabeledValue(item, "Pace: ", barDisplay);
|
|
64064
64183
|
}
|
|
64065
64184
|
return formatRawOrLabeledValue(item, "", `D${dayOfWeek}/7: ${status}`);
|
|
64066
64185
|
}
|
|
64067
64186
|
getCustomKeybinds() {
|
|
64068
64187
|
return [
|
|
64069
|
-
{ key: "p", label: "(p)endulum toggle", action: "toggle-pendulum" }
|
|
64188
|
+
{ key: "p", label: "(p)endulum toggle", action: "toggle-pendulum" },
|
|
64189
|
+
{ key: "%", label: "(%) always show percent", action: "toggle-show-percent" },
|
|
64190
|
+
{ key: ".", label: "(.) decimal precision", action: "cycle-decimals" }
|
|
64070
64191
|
];
|
|
64071
64192
|
}
|
|
64072
64193
|
supportsRawValue() {
|
|
@@ -64904,7 +65025,7 @@ var init_config = __esm(() => {
|
|
|
64904
65025
|
});
|
|
64905
65026
|
|
|
64906
65027
|
// src/utils/claude-settings.ts
|
|
64907
|
-
import { execSync as
|
|
65028
|
+
import { execSync as execSync5 } from "child_process";
|
|
64908
65029
|
import * as fs11 from "fs";
|
|
64909
65030
|
import * as os9 from "os";
|
|
64910
65031
|
import * as path9 from "path";
|
|
@@ -65013,7 +65134,7 @@ async function isInstalled() {
|
|
|
65013
65134
|
function isBunxAvailable() {
|
|
65014
65135
|
try {
|
|
65015
65136
|
const command = process.platform === "win32" ? "where bunx" : "which bunx";
|
|
65016
|
-
|
|
65137
|
+
execSync5(command, { stdio: "ignore" });
|
|
65017
65138
|
return true;
|
|
65018
65139
|
} catch {
|
|
65019
65140
|
return false;
|
|
@@ -65021,7 +65142,7 @@ function isBunxAvailable() {
|
|
|
65021
65142
|
}
|
|
65022
65143
|
function getClaudeCodeVersion() {
|
|
65023
65144
|
try {
|
|
65024
|
-
const output =
|
|
65145
|
+
const output = execSync5("claude --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"], timeout: 5000 }).trim();
|
|
65025
65146
|
const match = /^(\d+\.\d+\.\d+)/.exec(output);
|
|
65026
65147
|
return match?.[1] ?? null;
|
|
65027
65148
|
} catch {
|
|
@@ -65832,7 +65953,7 @@ function openExternalUrl(url2) {
|
|
|
65832
65953
|
}
|
|
65833
65954
|
|
|
65834
65955
|
// src/utils/powerline.ts
|
|
65835
|
-
import { execSync as
|
|
65956
|
+
import { execSync as execSync6 } from "child_process";
|
|
65836
65957
|
import * as fs12 from "fs";
|
|
65837
65958
|
import * as os11 from "os";
|
|
65838
65959
|
import * as path10 from "path";
|
|
@@ -65966,7 +66087,7 @@ async function installPowerlineFonts() {
|
|
|
65966
66087
|
if (fs12.existsSync(tempDir)) {
|
|
65967
66088
|
fs12.rmSync(tempDir, { recursive: true, force: true });
|
|
65968
66089
|
}
|
|
65969
|
-
|
|
66090
|
+
execSync6(`git clone --depth=1 https://github.com/powerline/fonts.git "${tempDir}"`, {
|
|
65970
66091
|
stdio: "pipe",
|
|
65971
66092
|
encoding: "utf8"
|
|
65972
66093
|
});
|
|
@@ -65974,14 +66095,14 @@ async function installPowerlineFonts() {
|
|
|
65974
66095
|
const installScript = path10.join(tempDir, "install.sh");
|
|
65975
66096
|
if (fs12.existsSync(installScript)) {
|
|
65976
66097
|
fs12.chmodSync(installScript, 493);
|
|
65977
|
-
|
|
66098
|
+
execSync6(`cd "${tempDir}" && ./install.sh`, {
|
|
65978
66099
|
stdio: "pipe",
|
|
65979
66100
|
encoding: "utf8",
|
|
65980
66101
|
shell: "/bin/bash"
|
|
65981
66102
|
});
|
|
65982
66103
|
if (platform4 === "linux") {
|
|
65983
66104
|
try {
|
|
65984
|
-
|
|
66105
|
+
execSync6("fc-cache -f -v", {
|
|
65985
66106
|
stdio: "pipe",
|
|
65986
66107
|
encoding: "utf8"
|
|
65987
66108
|
});
|
|
@@ -71250,56 +71371,7 @@ var StatusJSONSchema = exports_external.looseObject({
|
|
|
71250
71371
|
// src/ccstatusline.ts
|
|
71251
71372
|
init_ansi();
|
|
71252
71373
|
init_colors();
|
|
71253
|
-
init_config();
|
|
71254
|
-
init_jsonl();
|
|
71255
|
-
await init_renderer2();
|
|
71256
71374
|
|
|
71257
|
-
// src/utils/skills.ts
|
|
71258
|
-
import * as fs13 from "fs";
|
|
71259
|
-
import * as os13 from "os";
|
|
71260
|
-
import * as path11 from "path";
|
|
71261
|
-
var EMPTY = { totalInvocations: 0, uniqueSkills: [], lastSkill: null };
|
|
71262
|
-
function getSkillsDir() {
|
|
71263
|
-
return path11.join(os13.homedir(), ".cache", "ccstatusline", "skills");
|
|
71264
|
-
}
|
|
71265
|
-
function getSkillsFilePath(sessionId) {
|
|
71266
|
-
return path11.join(getSkillsDir(), `skills-${sessionId}.jsonl`);
|
|
71267
|
-
}
|
|
71268
|
-
function getSkillsMetrics(sessionId) {
|
|
71269
|
-
const filePath = getSkillsFilePath(sessionId);
|
|
71270
|
-
if (!fs13.existsSync(filePath)) {
|
|
71271
|
-
return EMPTY;
|
|
71272
|
-
}
|
|
71273
|
-
try {
|
|
71274
|
-
const invocations = fs13.readFileSync(filePath, "utf-8").trim().split(`
|
|
71275
|
-
`).filter((line) => line.trim()).map((line) => {
|
|
71276
|
-
try {
|
|
71277
|
-
return JSON.parse(line);
|
|
71278
|
-
} catch {
|
|
71279
|
-
return null;
|
|
71280
|
-
}
|
|
71281
|
-
}).filter((e) => e !== null && typeof e.skill === "string" && typeof e.session_id === "string");
|
|
71282
|
-
if (invocations.length === 0) {
|
|
71283
|
-
return EMPTY;
|
|
71284
|
-
}
|
|
71285
|
-
const uniqueSkills = [];
|
|
71286
|
-
const seenSkills = new Set;
|
|
71287
|
-
for (let i = invocations.length - 1;i >= 0; i--) {
|
|
71288
|
-
const skill = invocations[i]?.skill;
|
|
71289
|
-
if (skill && !seenSkills.has(skill)) {
|
|
71290
|
-
seenSkills.add(skill);
|
|
71291
|
-
uniqueSkills.push(skill);
|
|
71292
|
-
}
|
|
71293
|
-
}
|
|
71294
|
-
return {
|
|
71295
|
-
totalInvocations: invocations.length,
|
|
71296
|
-
uniqueSkills,
|
|
71297
|
-
lastSkill: invocations[invocations.length - 1]?.skill ?? null
|
|
71298
|
-
};
|
|
71299
|
-
} catch {
|
|
71300
|
-
return EMPTY;
|
|
71301
|
-
}
|
|
71302
|
-
}
|
|
71303
71375
|
// src/utils/compact-renderer.ts
|
|
71304
71376
|
init_source();
|
|
71305
71377
|
init_ColorLevel();
|
|
@@ -71361,11 +71433,63 @@ function renderCompactOutput(preRenderedLines, settings, maxWidth) {
|
|
|
71361
71433
|
}
|
|
71362
71434
|
}
|
|
71363
71435
|
|
|
71436
|
+
// src/ccstatusline.ts
|
|
71437
|
+
init_config();
|
|
71438
|
+
init_jsonl();
|
|
71439
|
+
await init_renderer2();
|
|
71440
|
+
|
|
71441
|
+
// src/utils/skills.ts
|
|
71442
|
+
import * as fs13 from "fs";
|
|
71443
|
+
import * as os13 from "os";
|
|
71444
|
+
import * as path11 from "path";
|
|
71445
|
+
var EMPTY = { totalInvocations: 0, uniqueSkills: [], lastSkill: null };
|
|
71446
|
+
function getSkillsDir() {
|
|
71447
|
+
return path11.join(os13.homedir(), ".cache", "ccstatusline", "skills");
|
|
71448
|
+
}
|
|
71449
|
+
function getSkillsFilePath(sessionId) {
|
|
71450
|
+
return path11.join(getSkillsDir(), `skills-${sessionId}.jsonl`);
|
|
71451
|
+
}
|
|
71452
|
+
function getSkillsMetrics(sessionId) {
|
|
71453
|
+
const filePath = getSkillsFilePath(sessionId);
|
|
71454
|
+
if (!fs13.existsSync(filePath)) {
|
|
71455
|
+
return EMPTY;
|
|
71456
|
+
}
|
|
71457
|
+
try {
|
|
71458
|
+
const invocations = fs13.readFileSync(filePath, "utf-8").trim().split(`
|
|
71459
|
+
`).filter((line) => line.trim()).map((line) => {
|
|
71460
|
+
try {
|
|
71461
|
+
return JSON.parse(line);
|
|
71462
|
+
} catch {
|
|
71463
|
+
return null;
|
|
71464
|
+
}
|
|
71465
|
+
}).filter((e) => e !== null && typeof e.skill === "string" && typeof e.session_id === "string");
|
|
71466
|
+
if (invocations.length === 0) {
|
|
71467
|
+
return EMPTY;
|
|
71468
|
+
}
|
|
71469
|
+
const uniqueSkills = [];
|
|
71470
|
+
const seenSkills = new Set;
|
|
71471
|
+
for (let i = invocations.length - 1;i >= 0; i--) {
|
|
71472
|
+
const skill = invocations[i]?.skill;
|
|
71473
|
+
if (skill && !seenSkills.has(skill)) {
|
|
71474
|
+
seenSkills.add(skill);
|
|
71475
|
+
uniqueSkills.push(skill);
|
|
71476
|
+
}
|
|
71477
|
+
}
|
|
71478
|
+
return {
|
|
71479
|
+
totalInvocations: invocations.length,
|
|
71480
|
+
uniqueSkills,
|
|
71481
|
+
lastSkill: invocations[invocations.length - 1]?.skill ?? null
|
|
71482
|
+
};
|
|
71483
|
+
} catch {
|
|
71484
|
+
return EMPTY;
|
|
71485
|
+
}
|
|
71486
|
+
}
|
|
71487
|
+
|
|
71364
71488
|
// src/ccstatusline.ts
|
|
71365
71489
|
init_terminal();
|
|
71366
71490
|
|
|
71367
71491
|
// src/utils/usage-prefetch.ts
|
|
71368
|
-
|
|
71492
|
+
init_resolver();
|
|
71369
71493
|
var USAGE_WIDGET_TYPES = new Set([
|
|
71370
71494
|
"session-usage",
|
|
71371
71495
|
"weekly-usage",
|
|
@@ -71406,17 +71530,20 @@ async function prefetchUsageDataIfNeeded(lines, data) {
|
|
|
71406
71530
|
if (!hasUsageDependentWidgets(lines)) {
|
|
71407
71531
|
return null;
|
|
71408
71532
|
}
|
|
71533
|
+
const model = data?.model;
|
|
71534
|
+
const modelId = (typeof model === "string" ? model : model?.id) ?? "";
|
|
71535
|
+
const provider = resolveProvider(modelId);
|
|
71409
71536
|
const rateLimitsData = extractUsageDataFromRateLimits(data?.rate_limits);
|
|
71410
71537
|
if (hasCompleteRateLimitsUsageData(rateLimitsData)) {
|
|
71411
71538
|
if (hasExtraUsageDependentWidgets(lines)) {
|
|
71412
|
-
const apiData = await
|
|
71539
|
+
const apiData = await provider.fetchUsage();
|
|
71413
71540
|
if (apiData.error === undefined) {
|
|
71414
71541
|
return { ...rateLimitsData, extraUsageEnabled: apiData.extraUsageEnabled, extraUsageLimit: apiData.extraUsageLimit, extraUsageUsed: apiData.extraUsageUsed, extraUsageUtilization: apiData.extraUsageUtilization };
|
|
71415
71542
|
}
|
|
71416
71543
|
}
|
|
71417
71544
|
return rateLimitsData;
|
|
71418
71545
|
}
|
|
71419
|
-
return
|
|
71546
|
+
return provider.fetchUsage();
|
|
71420
71547
|
}
|
|
71421
71548
|
|
|
71422
71549
|
// src/ccstatusline.ts
|
|
@@ -71460,8 +71587,8 @@ async function ensureWindowsUtf8CodePage() {
|
|
|
71460
71587
|
return;
|
|
71461
71588
|
}
|
|
71462
71589
|
try {
|
|
71463
|
-
const { execFileSync:
|
|
71464
|
-
|
|
71590
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
71591
|
+
execFileSync4("chcp.com", ["65001"], { stdio: "ignore" });
|
|
71465
71592
|
} catch {}
|
|
71466
71593
|
}
|
|
71467
71594
|
async function renderMultipleLines(data) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccstatusline-usage",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "A customizable status line formatter for Claude Code CLI",
|
|
5
5
|
"module": "src/ccstatusline.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"chalk": "^5.5.0",
|
|
31
31
|
"eslint": "^10.0.0",
|
|
32
32
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
33
|
-
"eslint-plugin-import": "^2.32.0",
|
|
34
33
|
"eslint-plugin-import-newlines": "^2.0.0",
|
|
34
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
35
35
|
"eslint-plugin-react": "^7.37.5",
|
|
36
36
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
37
37
|
"globals": "^17.3.0",
|