ccstatusline-usage 2.3.10 → 2.3.11
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 +29 -19
- package/dist/ccstatusline.js +150 -356
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,6 +47,7 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
47
47
|

|
|
48
48
|
|
|
49
49
|
</div>
|
|
50
|
+
<br />
|
|
50
51
|
|
|
51
52
|
## 📚 Table of Contents
|
|
52
53
|
|
|
@@ -54,19 +55,22 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
54
55
|
- [Features](#-features)
|
|
55
56
|
- [Localizations](#-localizations)
|
|
56
57
|
- [Quick Start](#-quick-start)
|
|
57
|
-
- [Windows Support](
|
|
58
|
-
- [Usage](
|
|
59
|
-
- [
|
|
60
|
-
- [Development](#️-development)
|
|
58
|
+
- [Windows Support](docs/WINDOWS.md)
|
|
59
|
+
- [Usage](docs/USAGE.md)
|
|
60
|
+
- [Development](docs/DEVELOPMENT.md)
|
|
61
61
|
- [Contributing](#-contributing)
|
|
62
62
|
- [Uninstall](#️-uninstall)
|
|
63
63
|
- [License](#-license)
|
|
64
64
|
- [Related Projects](#-related-projects)
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
<br />
|
|
67
67
|
|
|
68
68
|
## 🆕 Recent Updates
|
|
69
69
|
|
|
70
|
+
### [v2.3.11](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.11) - Fix dual-cache drift between Weekly Usage and Weekly Pace
|
|
71
|
+
|
|
72
|
+
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Unified usage data source** — Session Usage, Weekly Usage, and Reset Timer widgets now read from the shared `context.usageData` pipeline instead of maintaining a separate API cache. Previously, around the weekly reset boundary the two caches could drift and show contradictory data (e.g. `Weekly: 99%` alongside `Pace: D1/7 +2%`). Deleted ~330 lines of duplicate fetching/caching infrastructure from `ApiUsage.tsx` (556 → 227 lines). Upstream merge: #278 (JSONL token overcounting fix), #283 (model display name parenthetical strip — integrated into fork's existing `[1m]`-aware display logic).
|
|
73
|
+
|
|
70
74
|
### [v2.3.10](https://github.com/pcvelz/ccstatusline-usage/releases/tag/v2.3.10) - Extra usage on session limit, fix empty separator for null widgets
|
|
71
75
|
|
|
72
76
|
- [pcvelz/ccstatusline-usage](https://github.com/pcvelz/ccstatusline-usage): **Extra usage on session limit** — Reset Timer now shows extra usage spending when session limit reaches 100% (not just weekly limit or charged 1M model).
|
|
@@ -182,6 +186,10 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
182
186
|
- **🔗 Git widget link modes (v2.2.6)** - `Git Branch` can render clickable GitHub branch links, and `Git Root Dir` can render clickable IDE links for VS Code and Cursor.
|
|
183
187
|
- **🤝 Better subagent-aware speed reporting** - Token speed calculations continue to include referenced subagent activity so displayed speeds better reflect actual concurrent work.
|
|
184
188
|
|
|
189
|
+
<br />
|
|
190
|
+
<details>
|
|
191
|
+
<summary><b>Older updates (v2.1.10 and earlier)</b></summary>
|
|
192
|
+
|
|
185
193
|
### v2.1.0 - v2.1.10 - Usage widgets, links, new git insertions / deletions widgets, and reliability fixes
|
|
186
194
|
|
|
187
195
|
- **🧩 New Usage widgets (v2.1.0)** - Added **Session Usage**, **Weekly Usage**, **Block Reset Timer**, and **Context Bar** widgets.
|
|
@@ -278,7 +286,9 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
278
286
|
- **🔤 Custom Separators** - Add multiple Powerline separators with custom hex codes for font support
|
|
279
287
|
- **🚀 Auto Font Install** - Automatic Powerline font installation with user consent
|
|
280
288
|
|
|
281
|
-
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
<br />
|
|
282
292
|
|
|
283
293
|
## ✨ Features
|
|
284
294
|
|
|
@@ -290,13 +300,13 @@ Session: [████░░░░░░░░░░░] 27.0% | Weekly: [██
|
|
|
290
300
|
- **📐 Multi-line Support** - Configure multiple independent status lines
|
|
291
301
|
- **🖥️ Interactive TUI** - Built-in configuration interface using React/Ink
|
|
292
302
|
- **🔎 Fast Widget Picker** - Add/change widgets by category with search and ranked matching
|
|
293
|
-
- **⚙️ Global Options** - Apply consistent formatting across all widgets (padding, separators, bold,
|
|
303
|
+
- **⚙️ Global Options** - Apply consistent formatting across all widgets (padding, separators, bold, minimalist mode, and color overrides)
|
|
294
304
|
- **🚀 Cross-platform** - Works seamlessly with both Bun and Node.js
|
|
295
305
|
- **🔧 Flexible Configuration** - Supports custom Claude Code config directory via `CLAUDE_CONFIG_DIR` environment variable
|
|
296
306
|
- **📏 Smart Width Detection** - Automatically adapts to terminal width with flex separators
|
|
297
307
|
- **⚡ Zero Config** - Sensible defaults that work out of the box
|
|
298
308
|
|
|
299
|
-
|
|
309
|
+
<br />
|
|
300
310
|
|
|
301
311
|
## 🌐 Localizations
|
|
302
312
|
|
|
@@ -304,7 +314,7 @@ The localizations in this section are third-party forks maintained outside this
|
|
|
304
314
|
|
|
305
315
|
- 🌏 **中文版 (Chinese):** [ccstatusline-zh](https://github.com/huangguang1999/ccstatusline-zh)
|
|
306
316
|
|
|
307
|
-
|
|
317
|
+
<br />
|
|
308
318
|
|
|
309
319
|
## 🚀 Quick Start
|
|
310
320
|
|
|
@@ -318,7 +328,9 @@ npx -y ccstatusline-usage@latest
|
|
|
318
328
|
bunx -y ccstatusline-usage@latest
|
|
319
329
|
```
|
|
320
330
|
|
|
321
|
-
|
|
331
|
+
<br />
|
|
332
|
+
<details>
|
|
333
|
+
<summary><b>Configure ccstatusline</b></summary>
|
|
322
334
|
|
|
323
335
|
The interactive configuration tool provides a terminal UI where you can:
|
|
324
336
|
- Configure multiple separate status lines
|
|
@@ -335,14 +347,16 @@ The interactive configuration tool provides a terminal UI where you can:
|
|
|
335
347
|
> ```bash
|
|
336
348
|
> # Linux/macOS
|
|
337
349
|
> export CLAUDE_CONFIG_DIR=/custom/path/to/.claude
|
|
338
|
-
>
|
|
339
|
-
> # Windows PowerShell
|
|
340
|
-
> $env:CLAUDE_CONFIG_DIR="C:\custom\path\.claude"
|
|
341
350
|
> ```
|
|
342
351
|
|
|
343
352
|
> 🌐 **Usage API proxy:** Usage widgets honor the uppercase `HTTPS_PROXY` environment variable for their direct API call to Anthropic.
|
|
344
353
|
|
|
345
|
-
|
|
354
|
+
> 🪟 **Windows Support:** PowerShell examples, installation notes, fonts, troubleshooting, WSL, and Windows Terminal configuration are in [docs/WINDOWS.md](docs/WINDOWS.md).
|
|
355
|
+
|
|
356
|
+
</details>
|
|
357
|
+
|
|
358
|
+
<details>
|
|
359
|
+
<summary><b>Claude Code settings.json format</b></summary>
|
|
346
360
|
|
|
347
361
|
When you install from the TUI, ccstatusline writes a `statusLine` command object to your Claude Code settings:
|
|
348
362
|
|
|
@@ -894,7 +908,6 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
894
908
|
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
895
909
|
5. Open a Pull Request
|
|
896
910
|
|
|
897
|
-
---
|
|
898
911
|
|
|
899
912
|
## 🗑️ Uninstall
|
|
900
913
|
|
|
@@ -904,13 +917,11 @@ rm -rf ~/.npm/_npx ~/.config/ccstatusline ~/.cache/ccstatusline*
|
|
|
904
917
|
jq 'del(.statusLine)' ~/.claude/settings.json > /tmp/cs.json && cat /tmp/cs.json > ~/.claude/settings.json
|
|
905
918
|
```
|
|
906
919
|
|
|
907
|
-
---
|
|
908
920
|
|
|
909
921
|
## 📄 License
|
|
910
922
|
|
|
911
923
|
[MIT](LICENSE) © Matthew Breedlove
|
|
912
924
|
|
|
913
|
-
---
|
|
914
925
|
|
|
915
926
|
## 👤 Author
|
|
916
927
|
|
|
@@ -930,7 +941,6 @@ jq 'del(.statusLine)' ~/.claude/settings.json > /tmp/cs.json && cat /tmp/cs.json
|
|
|
930
941
|
- [ccusage](https://github.com/ryoppippi/ccusage) - Track and display Claude Code usage metrics.
|
|
931
942
|
- [codachi](https://github.com/vincent-k2026/codachi) - A tamagotchi-style statusline pet that grows with your context window.
|
|
932
943
|
|
|
933
|
-
---
|
|
934
944
|
|
|
935
945
|
## 🙏 Acknowledgments
|
|
936
946
|
|
|
@@ -938,7 +948,7 @@ jq 'del(.statusLine)' ~/.claude/settings.json > /tmp/cs.json && cat /tmp/cs.json
|
|
|
938
948
|
- Powered by [Ink](https://github.com/vadimdemedes/ink) for the terminal UI
|
|
939
949
|
- Made with ❤️ for the Claude Code community
|
|
940
950
|
|
|
941
|
-
|
|
951
|
+
<br />
|
|
942
952
|
|
|
943
953
|
## Star History
|
|
944
954
|
|
package/dist/ccstatusline.js
CHANGED
|
@@ -52660,7 +52660,7 @@ class ModelWidget {
|
|
|
52660
52660
|
return null;
|
|
52661
52661
|
const is1m = modelId?.includes("[1m]") ?? false;
|
|
52662
52662
|
const suffix = is1m ? "[1m]" : "";
|
|
52663
|
-
const cleanDisplayName = modelDisplayName.replace(/\[1m\]/gi, "").replace(/\(
|
|
52663
|
+
const cleanDisplayName = modelDisplayName.replace(/\[1m\]/gi, "").replace(/\s*\(.*\)$/, "").trim();
|
|
52664
52664
|
const mobile = (context.terminalWidth ?? 0) > 0 && (context.terminalWidth ?? 0) < MEDIUM_THRESHOLD;
|
|
52665
52665
|
if (mobile && modelId) {
|
|
52666
52666
|
return `M: ${compactModelName(modelId)}${suffix}`;
|
|
@@ -55593,7 +55593,7 @@ function getTerminalWidth() {
|
|
|
55593
55593
|
function canDetectTerminalWidth() {
|
|
55594
55594
|
return probeTerminalWidth() !== null;
|
|
55595
55595
|
}
|
|
55596
|
-
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.
|
|
55596
|
+
var __dirname = "/Users/peter/Documents/Code/ccstatusline-usage/src/utils", PACKAGE_VERSION = "2.3.11";
|
|
55597
55597
|
var init_terminal = () => {};
|
|
55598
55598
|
|
|
55599
55599
|
// src/utils/renderer.ts
|
|
@@ -61697,19 +61697,35 @@ async function getTokenMetrics(transcriptPath) {
|
|
|
61697
61697
|
let contextLength = 0;
|
|
61698
61698
|
let mostRecentMainChainEntry = null;
|
|
61699
61699
|
let mostRecentTimestamp = null;
|
|
61700
|
+
const parsedEntries = [];
|
|
61701
|
+
let hasStopReasonField = false;
|
|
61700
61702
|
for (const line of lines) {
|
|
61701
61703
|
const data = parseJsonlLine(line);
|
|
61702
61704
|
if (data?.message?.usage) {
|
|
61703
|
-
|
|
61704
|
-
|
|
61705
|
-
|
|
61706
|
-
|
|
61707
|
-
|
|
61708
|
-
|
|
61709
|
-
|
|
61710
|
-
|
|
61711
|
-
|
|
61712
|
-
|
|
61705
|
+
parsedEntries.push(data);
|
|
61706
|
+
if (Object.hasOwn(data.message, "stop_reason")) {
|
|
61707
|
+
hasStopReasonField = true;
|
|
61708
|
+
}
|
|
61709
|
+
}
|
|
61710
|
+
}
|
|
61711
|
+
const entriesToCount = hasStopReasonField ? parsedEntries.filter((data, index) => {
|
|
61712
|
+
const stopReason = data.message?.stop_reason;
|
|
61713
|
+
return Boolean(stopReason) || stopReason === null && index === parsedEntries.length - 1;
|
|
61714
|
+
}) : parsedEntries;
|
|
61715
|
+
for (const data of entriesToCount) {
|
|
61716
|
+
const usage = data.message?.usage;
|
|
61717
|
+
if (!usage) {
|
|
61718
|
+
continue;
|
|
61719
|
+
}
|
|
61720
|
+
inputTokens += usage.input_tokens || 0;
|
|
61721
|
+
outputTokens += usage.output_tokens || 0;
|
|
61722
|
+
cachedTokens += usage.cache_read_input_tokens ?? 0;
|
|
61723
|
+
cachedTokens += usage.cache_creation_input_tokens ?? 0;
|
|
61724
|
+
if (data.isSidechain !== true && data.timestamp && !data.isApiErrorMessage) {
|
|
61725
|
+
const entryTime = new Date(data.timestamp);
|
|
61726
|
+
if (!mostRecentTimestamp || entryTime > mostRecentTimestamp) {
|
|
61727
|
+
mostRecentTimestamp = entryTime;
|
|
61728
|
+
mostRecentMainChainEntry = data;
|
|
61713
61729
|
}
|
|
61714
61730
|
}
|
|
61715
61731
|
}
|
|
@@ -63108,226 +63124,6 @@ class SessionNameWidget {
|
|
|
63108
63124
|
var init_SessionName = () => {};
|
|
63109
63125
|
|
|
63110
63126
|
// src/widgets/ApiUsage.tsx
|
|
63111
|
-
import {
|
|
63112
|
-
execSync as execSync5,
|
|
63113
|
-
spawnSync
|
|
63114
|
-
} from "child_process";
|
|
63115
|
-
import * as fs10 from "fs";
|
|
63116
|
-
import * as os8 from "os";
|
|
63117
|
-
import * as path9 from "path";
|
|
63118
|
-
function readTokenFromFile() {
|
|
63119
|
-
try {
|
|
63120
|
-
const creds = JSON.parse(fs10.readFileSync(CRED_FILE, "utf8"));
|
|
63121
|
-
return creds.claudeAiOauth?.accessToken ?? null;
|
|
63122
|
-
} catch {
|
|
63123
|
-
return null;
|
|
63124
|
-
}
|
|
63125
|
-
}
|
|
63126
|
-
function readTokenFromKeychain() {
|
|
63127
|
-
try {
|
|
63128
|
-
const result2 = execSync5('security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null', { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
63129
|
-
const parsed = JSON.parse(result2);
|
|
63130
|
-
return parsed.claudeAiOauth?.accessToken ?? null;
|
|
63131
|
-
} catch {
|
|
63132
|
-
return null;
|
|
63133
|
-
}
|
|
63134
|
-
}
|
|
63135
|
-
function invalidateTokenCache() {
|
|
63136
|
-
cachedToken = null;
|
|
63137
|
-
tokenCacheTime = 0;
|
|
63138
|
-
}
|
|
63139
|
-
function getToken() {
|
|
63140
|
-
const now2 = Math.floor(Date.now() / 1000);
|
|
63141
|
-
if (cachedToken && now2 - tokenCacheTime < TOKEN_CACHE_MAX_AGE) {
|
|
63142
|
-
return cachedToken;
|
|
63143
|
-
}
|
|
63144
|
-
let token = null;
|
|
63145
|
-
if (process.platform === "darwin")
|
|
63146
|
-
token = readTokenFromKeychain();
|
|
63147
|
-
token ??= readTokenFromFile();
|
|
63148
|
-
if (token) {
|
|
63149
|
-
cachedToken = token;
|
|
63150
|
-
tokenCacheTime = now2;
|
|
63151
|
-
}
|
|
63152
|
-
return token;
|
|
63153
|
-
}
|
|
63154
|
-
function readStaleCache() {
|
|
63155
|
-
try {
|
|
63156
|
-
return JSON.parse(fs10.readFileSync(CACHE_FILE2, "utf8"));
|
|
63157
|
-
} catch {
|
|
63158
|
-
return null;
|
|
63159
|
-
}
|
|
63160
|
-
}
|
|
63161
|
-
function fetchFromApi(token) {
|
|
63162
|
-
const script = `
|
|
63163
|
-
const https = require('https');
|
|
63164
|
-
const options = {
|
|
63165
|
-
hostname: 'api.anthropic.com',
|
|
63166
|
-
path: '/api/oauth/usage',
|
|
63167
|
-
method: 'GET',
|
|
63168
|
-
headers: {
|
|
63169
|
-
'Authorization': 'Bearer ' + process.env.TOKEN,
|
|
63170
|
-
'anthropic-beta': 'oauth-2025-04-20'
|
|
63171
|
-
},
|
|
63172
|
-
timeout: 5000
|
|
63173
|
-
};
|
|
63174
|
-
const req = https.request(options, (res) => {
|
|
63175
|
-
let data = '';
|
|
63176
|
-
res.on('data', chunk => data += chunk);
|
|
63177
|
-
res.on('end', () => {
|
|
63178
|
-
if (res.statusCode === 200) {
|
|
63179
|
-
process.stdout.write(data);
|
|
63180
|
-
} else if (res.statusCode === 401) {
|
|
63181
|
-
process.exit(2);
|
|
63182
|
-
} else if (res.statusCode === 429) {
|
|
63183
|
-
process.exit(3);
|
|
63184
|
-
} else {
|
|
63185
|
-
process.exit(1);
|
|
63186
|
-
}
|
|
63187
|
-
});
|
|
63188
|
-
});
|
|
63189
|
-
req.on('error', () => process.exit(1));
|
|
63190
|
-
req.on('timeout', () => { req.destroy(); process.exit(1); });
|
|
63191
|
-
req.end();
|
|
63192
|
-
`;
|
|
63193
|
-
const result2 = spawnSync("node", ["-e", script], {
|
|
63194
|
-
encoding: "utf8",
|
|
63195
|
-
timeout: 6000,
|
|
63196
|
-
env: { ...process.env, TOKEN: token }
|
|
63197
|
-
});
|
|
63198
|
-
if (result2.error || !result2.stdout) {
|
|
63199
|
-
if (result2.status === 2)
|
|
63200
|
-
return "auth-error";
|
|
63201
|
-
if (result2.status === 3)
|
|
63202
|
-
return "rate-limited";
|
|
63203
|
-
return null;
|
|
63204
|
-
}
|
|
63205
|
-
if (result2.status !== 0) {
|
|
63206
|
-
if (result2.status === 2)
|
|
63207
|
-
return "auth-error";
|
|
63208
|
-
if (result2.status === 3)
|
|
63209
|
-
return "rate-limited";
|
|
63210
|
-
return null;
|
|
63211
|
-
}
|
|
63212
|
-
return result2.stdout;
|
|
63213
|
-
}
|
|
63214
|
-
function fetchApiData() {
|
|
63215
|
-
const now2 = Math.floor(Date.now() / 1000);
|
|
63216
|
-
if (cachedData && !cachedData.error && now2 - cacheTime < CACHE_MAX_AGE2) {
|
|
63217
|
-
return cachedData;
|
|
63218
|
-
}
|
|
63219
|
-
try {
|
|
63220
|
-
const stat = fs10.statSync(CACHE_FILE2);
|
|
63221
|
-
const fileAge = now2 - Math.floor(stat.mtimeMs / 1000);
|
|
63222
|
-
if (fileAge < CACHE_MAX_AGE2) {
|
|
63223
|
-
const fileData = JSON.parse(fs10.readFileSync(CACHE_FILE2, "utf8"));
|
|
63224
|
-
if (!fileData.error) {
|
|
63225
|
-
cachedData = fileData;
|
|
63226
|
-
cacheTime = now2;
|
|
63227
|
-
return fileData;
|
|
63228
|
-
}
|
|
63229
|
-
}
|
|
63230
|
-
} catch {}
|
|
63231
|
-
try {
|
|
63232
|
-
const lockStat = fs10.statSync(LOCK_FILE2);
|
|
63233
|
-
const lockAge = now2 - Math.floor(lockStat.mtimeMs / 1000);
|
|
63234
|
-
if (lockAge < LOCK_MAX_AGE2) {
|
|
63235
|
-
const stale = readStaleCache();
|
|
63236
|
-
if (stale && !stale.error)
|
|
63237
|
-
return stale;
|
|
63238
|
-
return { error: "timeout" };
|
|
63239
|
-
}
|
|
63240
|
-
} catch {}
|
|
63241
|
-
try {
|
|
63242
|
-
const lockDir = path9.dirname(LOCK_FILE2);
|
|
63243
|
-
if (!fs10.existsSync(lockDir)) {
|
|
63244
|
-
fs10.mkdirSync(lockDir, { recursive: true });
|
|
63245
|
-
}
|
|
63246
|
-
fs10.writeFileSync(LOCK_FILE2, "");
|
|
63247
|
-
} catch {}
|
|
63248
|
-
const token = getToken();
|
|
63249
|
-
if (!token) {
|
|
63250
|
-
const stale = readStaleCache();
|
|
63251
|
-
if (stale && !stale.error)
|
|
63252
|
-
return stale;
|
|
63253
|
-
return { error: "no-credentials" };
|
|
63254
|
-
}
|
|
63255
|
-
try {
|
|
63256
|
-
const response = fetchFromApi(token);
|
|
63257
|
-
if (response === "auth-error") {
|
|
63258
|
-
invalidateTokenCache();
|
|
63259
|
-
const stale = readStaleCache();
|
|
63260
|
-
if (stale && !stale.error)
|
|
63261
|
-
return stale;
|
|
63262
|
-
return { error: "api-error" };
|
|
63263
|
-
}
|
|
63264
|
-
if (response === "rate-limited") {
|
|
63265
|
-
try {
|
|
63266
|
-
const futureTime = new Date(Date.now() + 90000);
|
|
63267
|
-
fs10.utimesSync(LOCK_FILE2, futureTime, futureTime);
|
|
63268
|
-
} catch {}
|
|
63269
|
-
const stale = readStaleCache();
|
|
63270
|
-
if (stale && !stale.error)
|
|
63271
|
-
return stale;
|
|
63272
|
-
return { error: "timeout" };
|
|
63273
|
-
}
|
|
63274
|
-
if (!response) {
|
|
63275
|
-
const stale = readStaleCache();
|
|
63276
|
-
if (stale && !stale.error)
|
|
63277
|
-
return stale;
|
|
63278
|
-
return { error: "api-error" };
|
|
63279
|
-
}
|
|
63280
|
-
const data = JSON.parse(response);
|
|
63281
|
-
const apiData = {};
|
|
63282
|
-
if (data.five_hour) {
|
|
63283
|
-
apiData.sessionUsage = data.five_hour.utilization;
|
|
63284
|
-
apiData.sessionResetAt = data.five_hour.resets_at;
|
|
63285
|
-
}
|
|
63286
|
-
if (data.seven_day) {
|
|
63287
|
-
apiData.weeklyUsage = data.seven_day.utilization;
|
|
63288
|
-
}
|
|
63289
|
-
if (data.extra_usage) {
|
|
63290
|
-
apiData.extraUsageEnabled = data.extra_usage.is_enabled === true;
|
|
63291
|
-
apiData.extraUsageLimit = data.extra_usage.monthly_limit;
|
|
63292
|
-
apiData.extraUsageUsed = data.extra_usage.used_credits;
|
|
63293
|
-
apiData.extraUsageUtilization = data.extra_usage.utilization;
|
|
63294
|
-
}
|
|
63295
|
-
if (apiData.sessionUsage === undefined && apiData.weeklyUsage === undefined) {
|
|
63296
|
-
const stale = readStaleCache();
|
|
63297
|
-
if (stale && !stale.error)
|
|
63298
|
-
return stale;
|
|
63299
|
-
return { error: "parse-error" };
|
|
63300
|
-
}
|
|
63301
|
-
apiData.fetchedAt = now2;
|
|
63302
|
-
try {
|
|
63303
|
-
const cacheDir = path9.dirname(CACHE_FILE2);
|
|
63304
|
-
if (!fs10.existsSync(cacheDir)) {
|
|
63305
|
-
fs10.mkdirSync(cacheDir, { recursive: true });
|
|
63306
|
-
}
|
|
63307
|
-
fs10.writeFileSync(CACHE_FILE2, JSON.stringify(apiData));
|
|
63308
|
-
} catch {}
|
|
63309
|
-
cachedData = apiData;
|
|
63310
|
-
cacheTime = now2;
|
|
63311
|
-
return apiData;
|
|
63312
|
-
} catch {
|
|
63313
|
-
const stale = readStaleCache();
|
|
63314
|
-
if (stale && !stale.error)
|
|
63315
|
-
return stale;
|
|
63316
|
-
return { error: "parse-error" };
|
|
63317
|
-
}
|
|
63318
|
-
}
|
|
63319
|
-
function getErrorMessage(error48) {
|
|
63320
|
-
switch (error48) {
|
|
63321
|
-
case "no-credentials":
|
|
63322
|
-
return "[No credentials]";
|
|
63323
|
-
case "timeout":
|
|
63324
|
-
return "[Timeout]";
|
|
63325
|
-
case "api-error":
|
|
63326
|
-
return "[API Error]";
|
|
63327
|
-
case "parse-error":
|
|
63328
|
-
return "[Parse Error]";
|
|
63329
|
-
}
|
|
63330
|
-
}
|
|
63331
63127
|
function getDisplaySize(context) {
|
|
63332
63128
|
const w = context.terminalWidth ?? 0;
|
|
63333
63129
|
if (w > 0 && w < MOBILE_THRESHOLD)
|
|
@@ -63352,6 +63148,18 @@ function formatUsageBar(label, shortLabel, percent, size2) {
|
|
|
63352
63148
|
const bar = makeProgressBar(percent, getBarWidth(size2));
|
|
63353
63149
|
return `${size2 === "mobile" ? shortLabel : label}: ${bar} ${percent.toFixed(1)}%`;
|
|
63354
63150
|
}
|
|
63151
|
+
function getCurrencySymbol() {
|
|
63152
|
+
try {
|
|
63153
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
63154
|
+
if (tz.startsWith("Europe/"))
|
|
63155
|
+
return "€";
|
|
63156
|
+
} catch {}
|
|
63157
|
+
return "$";
|
|
63158
|
+
}
|
|
63159
|
+
function formatCents(cents) {
|
|
63160
|
+
const symbol2 = getCurrencySymbol();
|
|
63161
|
+
return `${symbol2}${(cents / 100).toFixed(2)}`;
|
|
63162
|
+
}
|
|
63355
63163
|
|
|
63356
63164
|
class SessionUsageWidget {
|
|
63357
63165
|
getDefaultColor() {
|
|
@@ -63366,15 +63174,15 @@ class SessionUsageWidget {
|
|
|
63366
63174
|
getCategory() {
|
|
63367
63175
|
return "API Usage";
|
|
63368
63176
|
}
|
|
63369
|
-
getEditorDisplay(
|
|
63177
|
+
getEditorDisplay(_item) {
|
|
63370
63178
|
return { displayText: this.getDisplayName() };
|
|
63371
63179
|
}
|
|
63372
|
-
render(
|
|
63180
|
+
render(_item, context, _settings) {
|
|
63373
63181
|
if (context.isPreview)
|
|
63374
63182
|
return "Session: [███░░░░░░░░░░░░] 20%";
|
|
63375
|
-
const data =
|
|
63183
|
+
const data = context.usageData ?? {};
|
|
63376
63184
|
if (data.error)
|
|
63377
|
-
return
|
|
63185
|
+
return getUsageErrorMessage(data.error);
|
|
63378
63186
|
if (data.sessionUsage === undefined)
|
|
63379
63187
|
return null;
|
|
63380
63188
|
return formatUsageBar("Session", "S", data.sessionUsage, getDisplaySize(context));
|
|
@@ -63382,7 +63190,7 @@ class SessionUsageWidget {
|
|
|
63382
63190
|
supportsRawValue() {
|
|
63383
63191
|
return false;
|
|
63384
63192
|
}
|
|
63385
|
-
supportsColors(
|
|
63193
|
+
supportsColors(_item) {
|
|
63386
63194
|
return true;
|
|
63387
63195
|
}
|
|
63388
63196
|
}
|
|
@@ -63400,15 +63208,15 @@ class WeeklyUsageWidget {
|
|
|
63400
63208
|
getCategory() {
|
|
63401
63209
|
return "API Usage";
|
|
63402
63210
|
}
|
|
63403
|
-
getEditorDisplay(
|
|
63211
|
+
getEditorDisplay(_item) {
|
|
63404
63212
|
return { displayText: this.getDisplayName() };
|
|
63405
63213
|
}
|
|
63406
|
-
render(
|
|
63214
|
+
render(_item, context, _settings) {
|
|
63407
63215
|
if (context.isPreview)
|
|
63408
63216
|
return "Weekly: [██░░░░░░░░░░░░░] 12%";
|
|
63409
|
-
const data =
|
|
63217
|
+
const data = context.usageData ?? {};
|
|
63410
63218
|
if (data.error)
|
|
63411
|
-
return
|
|
63219
|
+
return getUsageErrorMessage(data.error);
|
|
63412
63220
|
if (data.weeklyUsage === undefined)
|
|
63413
63221
|
return null;
|
|
63414
63222
|
return formatUsageBar("Weekly", "W", data.weeklyUsage, getDisplaySize(context));
|
|
@@ -63416,7 +63224,7 @@ class WeeklyUsageWidget {
|
|
|
63416
63224
|
supportsRawValue() {
|
|
63417
63225
|
return false;
|
|
63418
63226
|
}
|
|
63419
|
-
supportsColors(
|
|
63227
|
+
supportsColors(_item) {
|
|
63420
63228
|
return true;
|
|
63421
63229
|
}
|
|
63422
63230
|
}
|
|
@@ -63434,15 +63242,15 @@ class ResetTimerWidget {
|
|
|
63434
63242
|
getCategory() {
|
|
63435
63243
|
return "API Usage";
|
|
63436
63244
|
}
|
|
63437
|
-
getEditorDisplay(
|
|
63245
|
+
getEditorDisplay(_item) {
|
|
63438
63246
|
return { displayText: this.getDisplayName() };
|
|
63439
63247
|
}
|
|
63440
|
-
render(
|
|
63248
|
+
render(_item, context, settings) {
|
|
63441
63249
|
if (context.isPreview)
|
|
63442
63250
|
return "4:30 hr";
|
|
63443
|
-
const data =
|
|
63251
|
+
const data = context.usageData ?? {};
|
|
63444
63252
|
if (data.error)
|
|
63445
|
-
return
|
|
63253
|
+
return getUsageErrorMessage(data.error);
|
|
63446
63254
|
const model = context.data?.model;
|
|
63447
63255
|
const modelId = (typeof model === "string" ? model : model?.id) ?? "";
|
|
63448
63256
|
const is1mModel = modelId.includes("[1m]");
|
|
@@ -63472,22 +63280,10 @@ class ResetTimerWidget {
|
|
|
63472
63280
|
supportsRawValue() {
|
|
63473
63281
|
return false;
|
|
63474
63282
|
}
|
|
63475
|
-
supportsColors(
|
|
63283
|
+
supportsColors(_item) {
|
|
63476
63284
|
return true;
|
|
63477
63285
|
}
|
|
63478
63286
|
}
|
|
63479
|
-
function getCurrencySymbol() {
|
|
63480
|
-
try {
|
|
63481
|
-
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
63482
|
-
if (tz.startsWith("Europe/"))
|
|
63483
|
-
return "€";
|
|
63484
|
-
} catch {}
|
|
63485
|
-
return "$";
|
|
63486
|
-
}
|
|
63487
|
-
function formatCents(cents) {
|
|
63488
|
-
const symbol2 = getCurrencySymbol();
|
|
63489
|
-
return `${symbol2}${(cents / 100).toFixed(2)}`;
|
|
63490
|
-
}
|
|
63491
63287
|
|
|
63492
63288
|
class ContextBarWidget {
|
|
63493
63289
|
getDefaultColor() {
|
|
@@ -63502,10 +63298,10 @@ class ContextBarWidget {
|
|
|
63502
63298
|
getCategory() {
|
|
63503
63299
|
return "API Usage";
|
|
63504
63300
|
}
|
|
63505
|
-
getEditorDisplay(
|
|
63301
|
+
getEditorDisplay(_item) {
|
|
63506
63302
|
return { displayText: this.getDisplayName() };
|
|
63507
63303
|
}
|
|
63508
|
-
render(
|
|
63304
|
+
render(_item, context, _settings) {
|
|
63509
63305
|
if (context.isPreview)
|
|
63510
63306
|
return "Context: [████░░░░░░░░░░░] 50k/200k (25%)";
|
|
63511
63307
|
const cw = context.data?.context_window;
|
|
@@ -63533,15 +63329,13 @@ class ContextBarWidget {
|
|
|
63533
63329
|
supportsRawValue() {
|
|
63534
63330
|
return false;
|
|
63535
63331
|
}
|
|
63536
|
-
supportsColors(
|
|
63332
|
+
supportsColors(_item) {
|
|
63537
63333
|
return true;
|
|
63538
63334
|
}
|
|
63539
63335
|
}
|
|
63540
|
-
var
|
|
63336
|
+
var MOBILE_THRESHOLD = 134, MEDIUM_THRESHOLD2 = 178, MOBILE_BAR_WIDTH = 4, MEDIUM_BAR_WIDTH = 8, DEFAULT_BAR_WIDTH = 15;
|
|
63541
63337
|
var init_ApiUsage = __esm(() => {
|
|
63542
|
-
|
|
63543
|
-
LOCK_FILE2 = path9.join(os8.homedir(), ".cache", "ccstatusline-api.lock");
|
|
63544
|
-
CRED_FILE = path9.join(os8.homedir(), ".claude", ".credentials.json");
|
|
63338
|
+
init_usage();
|
|
63545
63339
|
});
|
|
63546
63340
|
|
|
63547
63341
|
// src/widgets/WeeklyResetTimer.ts
|
|
@@ -64118,11 +63912,11 @@ var init_ThinkingEffort = __esm(() => {
|
|
|
64118
63912
|
});
|
|
64119
63913
|
|
|
64120
63914
|
// src/widgets/Battery.ts
|
|
64121
|
-
import { execSync as
|
|
64122
|
-
import { readFileSync as
|
|
63915
|
+
import { execSync as execSync5 } from "child_process";
|
|
63916
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
64123
63917
|
function getMacBatteryInfo() {
|
|
64124
63918
|
try {
|
|
64125
|
-
const output =
|
|
63919
|
+
const output = execSync5("pmset -g batt", { encoding: "utf-8", timeout: 2000 });
|
|
64126
63920
|
const match = /(\d+)%;\s*(charging|discharging|charged|finishing charge|AC attached)/i.exec(output);
|
|
64127
63921
|
const percentStr = match?.[1];
|
|
64128
63922
|
const stateStr = match?.[2];
|
|
@@ -64139,8 +63933,8 @@ function getMacBatteryInfo() {
|
|
|
64139
63933
|
}
|
|
64140
63934
|
function getLinuxBatteryInfo() {
|
|
64141
63935
|
try {
|
|
64142
|
-
const capacity =
|
|
64143
|
-
const status =
|
|
63936
|
+
const capacity = readFileSync11("/sys/class/power_supply/BAT0/capacity", "utf-8").trim();
|
|
63937
|
+
const status = readFileSync11("/sys/class/power_supply/BAT0/status", "utf-8").trim().toLowerCase();
|
|
64144
63938
|
const percent = parseInt(capacity, 10);
|
|
64145
63939
|
if (isNaN(percent)) {
|
|
64146
63940
|
return null;
|
|
@@ -65123,11 +64917,11 @@ var init_hooks = __esm(async () => {
|
|
|
65123
64917
|
});
|
|
65124
64918
|
|
|
65125
64919
|
// src/utils/config.ts
|
|
65126
|
-
import * as
|
|
65127
|
-
import * as
|
|
65128
|
-
import * as
|
|
64920
|
+
import * as fs10 from "fs";
|
|
64921
|
+
import * as os8 from "os";
|
|
64922
|
+
import * as path9 from "path";
|
|
65129
64923
|
function initConfigPath(filePath) {
|
|
65130
|
-
settingsPath = filePath ?
|
|
64924
|
+
settingsPath = filePath ? path9.resolve(filePath) : DEFAULT_SETTINGS_PATH;
|
|
65131
64925
|
}
|
|
65132
64926
|
function getConfigPath() {
|
|
65133
64927
|
return settingsPath;
|
|
@@ -65136,13 +64930,13 @@ function isCustomConfigPath() {
|
|
|
65136
64930
|
return settingsPath !== DEFAULT_SETTINGS_PATH;
|
|
65137
64931
|
}
|
|
65138
64932
|
function getSettingsPaths() {
|
|
65139
|
-
const configDir =
|
|
65140
|
-
const parsedPath =
|
|
64933
|
+
const configDir = path9.dirname(settingsPath);
|
|
64934
|
+
const parsedPath = path9.parse(settingsPath);
|
|
65141
64935
|
const backupBaseName = parsedPath.ext ? `${parsedPath.name}.bak` : `${parsedPath.base}.bak`;
|
|
65142
64936
|
return {
|
|
65143
64937
|
configDir,
|
|
65144
64938
|
settingsPath,
|
|
65145
|
-
settingsBackupPath:
|
|
64939
|
+
settingsBackupPath: path9.join(configDir, backupBaseName)
|
|
65146
64940
|
};
|
|
65147
64941
|
}
|
|
65148
64942
|
async function ensureDir(dir) {
|
|
@@ -65159,7 +64953,7 @@ async function writeSettingsJson(settings, paths) {
|
|
|
65159
64953
|
}
|
|
65160
64954
|
async function backupBadSettings(paths) {
|
|
65161
64955
|
try {
|
|
65162
|
-
if (
|
|
64956
|
+
if (fs10.existsSync(paths.settingsPath)) {
|
|
65163
64957
|
const content = await readFile3(paths.settingsPath, "utf-8");
|
|
65164
64958
|
await writeFile(paths.settingsBackupPath, content, "utf-8");
|
|
65165
64959
|
console.error(`Bad settings backed up to ${paths.settingsBackupPath}`);
|
|
@@ -65189,7 +64983,7 @@ async function recoverWithDefaults(paths) {
|
|
|
65189
64983
|
async function loadSettings() {
|
|
65190
64984
|
const paths = getSettingsPaths();
|
|
65191
64985
|
try {
|
|
65192
|
-
if (!
|
|
64986
|
+
if (!fs10.existsSync(paths.settingsPath))
|
|
65193
64987
|
return await writeDefaultSettings(paths);
|
|
65194
64988
|
const content = await readFile3(paths.settingsPath, "utf-8");
|
|
65195
64989
|
let rawData;
|
|
@@ -65239,18 +65033,18 @@ var readFile3, writeFile, mkdir, DEFAULT_SETTINGS_PATH, settingsPath;
|
|
|
65239
65033
|
var init_config = __esm(() => {
|
|
65240
65034
|
init_Settings();
|
|
65241
65035
|
init_migrations();
|
|
65242
|
-
readFile3 =
|
|
65243
|
-
writeFile =
|
|
65244
|
-
mkdir =
|
|
65245
|
-
DEFAULT_SETTINGS_PATH =
|
|
65036
|
+
readFile3 = fs10.promises.readFile;
|
|
65037
|
+
writeFile = fs10.promises.writeFile;
|
|
65038
|
+
mkdir = fs10.promises.mkdir;
|
|
65039
|
+
DEFAULT_SETTINGS_PATH = path9.join(os8.homedir(), ".config", "ccstatusline", "settings.json");
|
|
65246
65040
|
settingsPath = DEFAULT_SETTINGS_PATH;
|
|
65247
65041
|
});
|
|
65248
65042
|
|
|
65249
65043
|
// src/utils/claude-settings.ts
|
|
65250
|
-
import { execSync as
|
|
65251
|
-
import * as
|
|
65252
|
-
import * as
|
|
65253
|
-
import * as
|
|
65044
|
+
import { execSync as execSync6 } from "child_process";
|
|
65045
|
+
import * as fs11 from "fs";
|
|
65046
|
+
import * as os9 from "os";
|
|
65047
|
+
import * as path10 from "path";
|
|
65254
65048
|
function isKnownCommand(command) {
|
|
65255
65049
|
const prefixes = [CCSTATUSLINE_COMMANDS.NPM, CCSTATUSLINE_COMMANDS.BUNX, CCSTATUSLINE_COMMANDS.SELF_MANAGED];
|
|
65256
65050
|
return prefixes.some((prefix) => command === prefix || command.startsWith(`${prefix} --config `));
|
|
@@ -65274,9 +65068,9 @@ function getClaudeConfigDir() {
|
|
|
65274
65068
|
const envConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
|
65275
65069
|
if (envConfigDir) {
|
|
65276
65070
|
try {
|
|
65277
|
-
const resolvedPath =
|
|
65278
|
-
if (
|
|
65279
|
-
const stats =
|
|
65071
|
+
const resolvedPath = path10.resolve(envConfigDir);
|
|
65072
|
+
if (fs11.existsSync(resolvedPath)) {
|
|
65073
|
+
const stats = fs11.statSync(resolvedPath);
|
|
65280
65074
|
if (stats.isDirectory()) {
|
|
65281
65075
|
return resolvedPath;
|
|
65282
65076
|
}
|
|
@@ -65285,16 +65079,16 @@ function getClaudeConfigDir() {
|
|
|
65285
65079
|
}
|
|
65286
65080
|
} catch {}
|
|
65287
65081
|
}
|
|
65288
|
-
return
|
|
65082
|
+
return path10.join(os9.homedir(), ".claude");
|
|
65289
65083
|
}
|
|
65290
65084
|
function getClaudeSettingsPath() {
|
|
65291
|
-
return
|
|
65085
|
+
return path10.join(getClaudeConfigDir(), "settings.json");
|
|
65292
65086
|
}
|
|
65293
65087
|
async function backupClaudeSettings(suffix = ".bak") {
|
|
65294
65088
|
const settingsPath2 = getClaudeSettingsPath();
|
|
65295
65089
|
const backupPath = settingsPath2 + suffix;
|
|
65296
65090
|
try {
|
|
65297
|
-
if (
|
|
65091
|
+
if (fs11.existsSync(settingsPath2)) {
|
|
65298
65092
|
const content = await readFile4(settingsPath2, "utf-8");
|
|
65299
65093
|
await writeFile2(backupPath, content, "utf-8");
|
|
65300
65094
|
return backupPath;
|
|
@@ -65307,11 +65101,11 @@ async function backupClaudeSettings(suffix = ".bak") {
|
|
|
65307
65101
|
function loadClaudeSettingsSync(options = {}) {
|
|
65308
65102
|
const { logErrors = true } = options;
|
|
65309
65103
|
const settingsPath2 = getClaudeSettingsPath();
|
|
65310
|
-
if (!
|
|
65104
|
+
if (!fs11.existsSync(settingsPath2)) {
|
|
65311
65105
|
return {};
|
|
65312
65106
|
}
|
|
65313
65107
|
try {
|
|
65314
|
-
const content =
|
|
65108
|
+
const content = fs11.readFileSync(settingsPath2, "utf-8");
|
|
65315
65109
|
return JSON.parse(content);
|
|
65316
65110
|
} catch (error48) {
|
|
65317
65111
|
if (logErrors) {
|
|
@@ -65323,7 +65117,7 @@ function loadClaudeSettingsSync(options = {}) {
|
|
|
65323
65117
|
async function loadClaudeSettings(options = {}) {
|
|
65324
65118
|
const { logErrors = true } = options;
|
|
65325
65119
|
const settingsPath2 = getClaudeSettingsPath();
|
|
65326
|
-
if (!
|
|
65120
|
+
if (!fs11.existsSync(settingsPath2)) {
|
|
65327
65121
|
return {};
|
|
65328
65122
|
}
|
|
65329
65123
|
try {
|
|
@@ -65338,7 +65132,7 @@ async function loadClaudeSettings(options = {}) {
|
|
|
65338
65132
|
}
|
|
65339
65133
|
async function saveClaudeSettings(settings) {
|
|
65340
65134
|
const settingsPath2 = getClaudeSettingsPath();
|
|
65341
|
-
const dir =
|
|
65135
|
+
const dir = path10.dirname(settingsPath2);
|
|
65342
65136
|
await backupClaudeSettings();
|
|
65343
65137
|
await ensureDir(dir);
|
|
65344
65138
|
await writeFile2(settingsPath2, JSON.stringify(settings, null, 2), "utf-8");
|
|
@@ -65356,7 +65150,7 @@ async function isInstalled() {
|
|
|
65356
65150
|
function isBunxAvailable() {
|
|
65357
65151
|
try {
|
|
65358
65152
|
const command = process.platform === "win32" ? "where bunx" : "which bunx";
|
|
65359
|
-
|
|
65153
|
+
execSync6(command, { stdio: "ignore" });
|
|
65360
65154
|
return true;
|
|
65361
65155
|
} catch {
|
|
65362
65156
|
return false;
|
|
@@ -65370,7 +65164,7 @@ function buildCommand(baseCommand) {
|
|
|
65370
65164
|
}
|
|
65371
65165
|
async function loadSavedSettingsForHookSync() {
|
|
65372
65166
|
const configPath = getConfigPath();
|
|
65373
|
-
if (!
|
|
65167
|
+
if (!fs11.existsSync(configPath)) {
|
|
65374
65168
|
return null;
|
|
65375
65169
|
}
|
|
65376
65170
|
try {
|
|
@@ -65437,8 +65231,8 @@ var readFile4, writeFile2, CCSTATUSLINE_COMMANDS;
|
|
|
65437
65231
|
var init_claude_settings = __esm(() => {
|
|
65438
65232
|
init_Settings();
|
|
65439
65233
|
init_config();
|
|
65440
|
-
readFile4 =
|
|
65441
|
-
writeFile2 =
|
|
65234
|
+
readFile4 = fs11.promises.readFile;
|
|
65235
|
+
writeFile2 = fs11.promises.writeFile;
|
|
65442
65236
|
CCSTATUSLINE_COMMANDS = {
|
|
65443
65237
|
NPM: "npx -y ccstatusline-usage@latest",
|
|
65444
65238
|
BUNX: "bunx -y ccstatusline-usage@latest",
|
|
@@ -66031,10 +65825,10 @@ function cloneSettings(settings) {
|
|
|
66031
65825
|
init_config();
|
|
66032
65826
|
|
|
66033
65827
|
// src/utils/open-url.ts
|
|
66034
|
-
import { spawnSync
|
|
66035
|
-
import * as
|
|
65828
|
+
import { spawnSync } from "child_process";
|
|
65829
|
+
import * as os10 from "os";
|
|
66036
65830
|
function runOpenCommand(command, args) {
|
|
66037
|
-
const result2 =
|
|
65831
|
+
const result2 = spawnSync(command, args, {
|
|
66038
65832
|
stdio: "ignore",
|
|
66039
65833
|
windowsHide: true
|
|
66040
65834
|
});
|
|
@@ -66091,7 +65885,7 @@ function openExternalUrl(url2) {
|
|
|
66091
65885
|
error: "Only http(s) URLs are supported"
|
|
66092
65886
|
};
|
|
66093
65887
|
}
|
|
66094
|
-
const platform3 =
|
|
65888
|
+
const platform3 = os10.platform();
|
|
66095
65889
|
const plans = PLATFORM_OPEN_PLANS[platform3];
|
|
66096
65890
|
if (!plans) {
|
|
66097
65891
|
return {
|
|
@@ -66118,10 +65912,10 @@ function openExternalUrl(url2) {
|
|
|
66118
65912
|
}
|
|
66119
65913
|
|
|
66120
65914
|
// src/utils/powerline.ts
|
|
66121
|
-
import { execSync as
|
|
66122
|
-
import * as
|
|
66123
|
-
import * as
|
|
66124
|
-
import * as
|
|
65915
|
+
import { execSync as execSync7 } from "child_process";
|
|
65916
|
+
import * as fs12 from "fs";
|
|
65917
|
+
import * as os11 from "os";
|
|
65918
|
+
import * as path11 from "path";
|
|
66125
65919
|
var fontsInstalledThisSession = false;
|
|
66126
65920
|
function checkPowerlineFonts() {
|
|
66127
65921
|
if (process.env.DEBUG_FONT_INSTALL === "1" && !fontsInstalledThisSession) {
|
|
@@ -66137,24 +65931,24 @@ function checkPowerlineFonts() {
|
|
|
66137
65931
|
leftArrow: "",
|
|
66138
65932
|
leftThinArrow: ""
|
|
66139
65933
|
};
|
|
66140
|
-
const platform4 =
|
|
65934
|
+
const platform4 = os11.platform();
|
|
66141
65935
|
let fontPaths = [];
|
|
66142
65936
|
if (platform4 === "darwin") {
|
|
66143
65937
|
fontPaths = [
|
|
66144
|
-
|
|
65938
|
+
path11.join(os11.homedir(), "Library", "Fonts"),
|
|
66145
65939
|
"/Library/Fonts",
|
|
66146
65940
|
"/System/Library/Fonts"
|
|
66147
65941
|
];
|
|
66148
65942
|
} else if (platform4 === "linux") {
|
|
66149
65943
|
fontPaths = [
|
|
66150
|
-
|
|
66151
|
-
|
|
65944
|
+
path11.join(os11.homedir(), ".local", "share", "fonts"),
|
|
65945
|
+
path11.join(os11.homedir(), ".fonts"),
|
|
66152
65946
|
"/usr/share/fonts",
|
|
66153
65947
|
"/usr/local/share/fonts"
|
|
66154
65948
|
];
|
|
66155
65949
|
} else if (platform4 === "win32") {
|
|
66156
65950
|
fontPaths = [
|
|
66157
|
-
|
|
65951
|
+
path11.join(os11.homedir(), "AppData", "Local", "Microsoft", "Windows", "Fonts"),
|
|
66158
65952
|
"C:\\Windows\\Fonts"
|
|
66159
65953
|
];
|
|
66160
65954
|
}
|
|
@@ -66170,9 +65964,9 @@ function checkPowerlineFonts() {
|
|
|
66170
65964
|
/fira.*code.*nerd/i
|
|
66171
65965
|
];
|
|
66172
65966
|
for (const fontPath of fontPaths) {
|
|
66173
|
-
if (
|
|
65967
|
+
if (fs12.existsSync(fontPath)) {
|
|
66174
65968
|
try {
|
|
66175
|
-
const files =
|
|
65969
|
+
const files = fs12.readdirSync(fontPath);
|
|
66176
65970
|
for (const file2 of files) {
|
|
66177
65971
|
for (const pattern of powerlineFontPatterns) {
|
|
66178
65972
|
if (pattern.test(file2)) {
|
|
@@ -66207,7 +66001,7 @@ async function checkPowerlineFontsAsync() {
|
|
|
66207
66001
|
if (quickCheck.installed) {
|
|
66208
66002
|
return quickCheck;
|
|
66209
66003
|
}
|
|
66210
|
-
const platform4 =
|
|
66004
|
+
const platform4 = os11.platform();
|
|
66211
66005
|
if (platform4 === "linux" || platform4 === "darwin") {
|
|
66212
66006
|
try {
|
|
66213
66007
|
const { exec: exec2 } = await import("child_process");
|
|
@@ -66230,44 +66024,44 @@ async function checkPowerlineFontsAsync() {
|
|
|
66230
66024
|
async function installPowerlineFonts() {
|
|
66231
66025
|
await Promise.resolve();
|
|
66232
66026
|
try {
|
|
66233
|
-
const platform4 =
|
|
66027
|
+
const platform4 = os11.platform();
|
|
66234
66028
|
let fontDir;
|
|
66235
66029
|
if (platform4 === "darwin") {
|
|
66236
|
-
fontDir =
|
|
66030
|
+
fontDir = path11.join(os11.homedir(), "Library", "Fonts");
|
|
66237
66031
|
} else if (platform4 === "linux") {
|
|
66238
|
-
fontDir =
|
|
66032
|
+
fontDir = path11.join(os11.homedir(), ".local", "share", "fonts");
|
|
66239
66033
|
} else if (platform4 === "win32") {
|
|
66240
|
-
fontDir =
|
|
66034
|
+
fontDir = path11.join(os11.homedir(), "AppData", "Local", "Microsoft", "Windows", "Fonts");
|
|
66241
66035
|
} else {
|
|
66242
66036
|
return {
|
|
66243
66037
|
success: false,
|
|
66244
66038
|
message: "Unsupported platform for font installation"
|
|
66245
66039
|
};
|
|
66246
66040
|
}
|
|
66247
|
-
if (!
|
|
66248
|
-
|
|
66041
|
+
if (!fs12.existsSync(fontDir)) {
|
|
66042
|
+
fs12.mkdirSync(fontDir, { recursive: true });
|
|
66249
66043
|
}
|
|
66250
|
-
const tempDir =
|
|
66044
|
+
const tempDir = path11.join(os11.tmpdir(), `ccstatusline-powerline-fonts-${Date.now()}`);
|
|
66251
66045
|
try {
|
|
66252
|
-
if (
|
|
66253
|
-
|
|
66046
|
+
if (fs12.existsSync(tempDir)) {
|
|
66047
|
+
fs12.rmSync(tempDir, { recursive: true, force: true });
|
|
66254
66048
|
}
|
|
66255
|
-
|
|
66049
|
+
execSync7(`git clone --depth=1 https://github.com/powerline/fonts.git "${tempDir}"`, {
|
|
66256
66050
|
stdio: "pipe",
|
|
66257
66051
|
encoding: "utf8"
|
|
66258
66052
|
});
|
|
66259
66053
|
if (platform4 === "darwin" || platform4 === "linux") {
|
|
66260
|
-
const installScript =
|
|
66261
|
-
if (
|
|
66262
|
-
|
|
66263
|
-
|
|
66054
|
+
const installScript = path11.join(tempDir, "install.sh");
|
|
66055
|
+
if (fs12.existsSync(installScript)) {
|
|
66056
|
+
fs12.chmodSync(installScript, 493);
|
|
66057
|
+
execSync7(`cd "${tempDir}" && ./install.sh`, {
|
|
66264
66058
|
stdio: "pipe",
|
|
66265
66059
|
encoding: "utf8",
|
|
66266
66060
|
shell: "/bin/bash"
|
|
66267
66061
|
});
|
|
66268
66062
|
if (platform4 === "linux") {
|
|
66269
66063
|
try {
|
|
66270
|
-
|
|
66064
|
+
execSync7("fc-cache -f -v", {
|
|
66271
66065
|
stdio: "pipe",
|
|
66272
66066
|
encoding: "utf8"
|
|
66273
66067
|
});
|
|
@@ -66285,10 +66079,10 @@ async function installPowerlineFonts() {
|
|
|
66285
66079
|
}
|
|
66286
66080
|
} else {
|
|
66287
66081
|
let findFontFiles = function(dir) {
|
|
66288
|
-
const files =
|
|
66082
|
+
const files = fs12.readdirSync(dir);
|
|
66289
66083
|
for (const file2 of files) {
|
|
66290
|
-
const filePath =
|
|
66291
|
-
const stat =
|
|
66084
|
+
const filePath = path11.join(dir, file2);
|
|
66085
|
+
const stat = fs12.statSync(filePath);
|
|
66292
66086
|
if (stat.isDirectory() && !file2.startsWith(".")) {
|
|
66293
66087
|
findFontFiles(filePath);
|
|
66294
66088
|
} else if (file2.endsWith(".ttf") || file2.endsWith(".otf")) {
|
|
@@ -66302,10 +66096,10 @@ async function installPowerlineFonts() {
|
|
|
66302
66096
|
findFontFiles(tempDir);
|
|
66303
66097
|
let installedCount = 0;
|
|
66304
66098
|
for (const fontFile of fontFiles) {
|
|
66305
|
-
const fileName =
|
|
66306
|
-
const destPath =
|
|
66099
|
+
const fileName = path11.basename(fontFile);
|
|
66100
|
+
const destPath = path11.join(fontDir, fileName);
|
|
66307
66101
|
try {
|
|
66308
|
-
|
|
66102
|
+
fs12.copyFileSync(fontFile, destPath);
|
|
66309
66103
|
installedCount++;
|
|
66310
66104
|
} catch {}
|
|
66311
66105
|
}
|
|
@@ -66323,9 +66117,9 @@ async function installPowerlineFonts() {
|
|
|
66323
66117
|
message: "Platform-specific installation not implemented"
|
|
66324
66118
|
};
|
|
66325
66119
|
} finally {
|
|
66326
|
-
if (
|
|
66120
|
+
if (fs12.existsSync(tempDir)) {
|
|
66327
66121
|
try {
|
|
66328
|
-
|
|
66122
|
+
fs12.rmSync(tempDir, { recursive: true, force: true });
|
|
66329
66123
|
} catch {}
|
|
66330
66124
|
}
|
|
66331
66125
|
}
|
|
@@ -69326,7 +69120,7 @@ var MainMenu = ({
|
|
|
69326
69120
|
// src/tui/components/PowerlineSetup.tsx
|
|
69327
69121
|
await init_build2();
|
|
69328
69122
|
var import_react43 = __toESM(require_react(), 1);
|
|
69329
|
-
import * as
|
|
69123
|
+
import * as os12 from "os";
|
|
69330
69124
|
|
|
69331
69125
|
// src/utils/powerline-settings.ts
|
|
69332
69126
|
init_colors();
|
|
@@ -70092,7 +69886,7 @@ var PowerlineSetup = ({
|
|
|
70092
69886
|
}, undefined, false, undefined, this)
|
|
70093
69887
|
]
|
|
70094
69888
|
}, undefined, true, undefined, this),
|
|
70095
|
-
|
|
69889
|
+
os12.platform() === "darwin" && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
|
|
70096
69890
|
children: [
|
|
70097
69891
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
|
|
70098
69892
|
dimColor: true,
|
|
@@ -70108,7 +69902,7 @@ var PowerlineSetup = ({
|
|
|
70108
69902
|
}, undefined, false, undefined, this)
|
|
70109
69903
|
]
|
|
70110
69904
|
}, undefined, true, undefined, this),
|
|
70111
|
-
|
|
69905
|
+
os12.platform() === "linux" && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
|
|
70112
69906
|
children: [
|
|
70113
69907
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
|
|
70114
69908
|
dimColor: true,
|
|
@@ -70124,7 +69918,7 @@ var PowerlineSetup = ({
|
|
|
70124
69918
|
}, undefined, false, undefined, this)
|
|
70125
69919
|
]
|
|
70126
69920
|
}, undefined, true, undefined, this),
|
|
70127
|
-
|
|
69921
|
+
os12.platform() === "win32" && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
|
|
70128
69922
|
children: [
|
|
70129
69923
|
/* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
|
|
70130
69924
|
dimColor: true,
|
|
@@ -71339,23 +71133,23 @@ init_jsonl();
|
|
|
71339
71133
|
await init_renderer2();
|
|
71340
71134
|
|
|
71341
71135
|
// src/utils/skills.ts
|
|
71342
|
-
import * as
|
|
71343
|
-
import * as
|
|
71344
|
-
import * as
|
|
71136
|
+
import * as fs13 from "fs";
|
|
71137
|
+
import * as os13 from "os";
|
|
71138
|
+
import * as path12 from "path";
|
|
71345
71139
|
var EMPTY = { totalInvocations: 0, uniqueSkills: [], lastSkill: null };
|
|
71346
71140
|
function getSkillsDir() {
|
|
71347
|
-
return
|
|
71141
|
+
return path12.join(os13.homedir(), ".cache", "ccstatusline", "skills");
|
|
71348
71142
|
}
|
|
71349
71143
|
function getSkillsFilePath(sessionId) {
|
|
71350
|
-
return
|
|
71144
|
+
return path12.join(getSkillsDir(), `skills-${sessionId}.jsonl`);
|
|
71351
71145
|
}
|
|
71352
71146
|
function getSkillsMetrics(sessionId) {
|
|
71353
71147
|
const filePath = getSkillsFilePath(sessionId);
|
|
71354
|
-
if (!
|
|
71148
|
+
if (!fs13.existsSync(filePath)) {
|
|
71355
71149
|
return EMPTY;
|
|
71356
71150
|
}
|
|
71357
71151
|
try {
|
|
71358
|
-
const invocations =
|
|
71152
|
+
const invocations = fs13.readFileSync(filePath, "utf-8").trim().split(`
|
|
71359
71153
|
`).filter((line) => line.trim()).map((line) => {
|
|
71360
71154
|
try {
|
|
71361
71155
|
return JSON.parse(line);
|
|
@@ -71690,16 +71484,16 @@ async function handleHook() {
|
|
|
71690
71484
|
return;
|
|
71691
71485
|
}
|
|
71692
71486
|
const filePath = getSkillsFilePath(sessionId);
|
|
71693
|
-
const
|
|
71694
|
-
const
|
|
71695
|
-
|
|
71487
|
+
const fs14 = await import("fs");
|
|
71488
|
+
const path13 = await import("path");
|
|
71489
|
+
fs14.mkdirSync(path13.dirname(filePath), { recursive: true });
|
|
71696
71490
|
const entry = JSON.stringify({
|
|
71697
71491
|
timestamp: new Date().toISOString(),
|
|
71698
71492
|
session_id: sessionId,
|
|
71699
71493
|
skill: skillName,
|
|
71700
71494
|
source: data.hook_event_name
|
|
71701
71495
|
});
|
|
71702
|
-
|
|
71496
|
+
fs14.appendFileSync(filePath, entry + `
|
|
71703
71497
|
`);
|
|
71704
71498
|
} catch {}
|
|
71705
71499
|
console.log("{}");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccstatusline-usage",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.11",
|
|
4
4
|
"description": "A customizable status line formatter for Claude Code CLI",
|
|
5
5
|
"module": "src/ccstatusline.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"lint": "bun tsc --noEmit && eslint . --config eslint.config.js --max-warnings=0",
|
|
20
20
|
"lint:fix": "bun tsc --noEmit && eslint . --config eslint.config.js --max-warnings=0 --fix",
|
|
21
21
|
"docs": "typedoc",
|
|
22
|
-
"docs:clean": "rm -rf
|
|
22
|
+
"docs:clean": "rm -rf typedoc"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@eslint/js": "^10.0.1",
|