cc-costline 0.3.0 → 0.3.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/dist/statusline.js +31 -29
- package/package.json +1 -1
package/dist/statusline.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync, existsSync,
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
@@ -46,44 +46,44 @@ export function formatCountdown(resetsAtMs) {
|
|
|
46
46
|
const minutes = totalMinutes % 60;
|
|
47
47
|
return `-${hours}:${String(minutes).padStart(2, "0")}`;
|
|
48
48
|
}
|
|
49
|
-
// ccclub rank fetcher
|
|
50
|
-
function getCcclubRank() {
|
|
49
|
+
// ccclub rank fetcher — cached per session (stale fallback on failure)
|
|
50
|
+
function getCcclubRank(sessionId) {
|
|
51
51
|
const configPath = join(homedir(), ".ccclub", "config.json");
|
|
52
52
|
if (!existsSync(configPath))
|
|
53
53
|
return null;
|
|
54
54
|
const cacheFile = "/tmp/sl-ccclub-rank";
|
|
55
|
-
|
|
55
|
+
let staleData = null;
|
|
56
56
|
if (existsSync(cacheFile)) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
catch { }
|
|
57
|
+
try {
|
|
58
|
+
const cached = JSON.parse(readFileSync(cacheFile, "utf-8"));
|
|
59
|
+
staleData = cached.data ?? null;
|
|
60
|
+
if (cached.sessionId === sessionId)
|
|
61
|
+
return staleData;
|
|
63
62
|
}
|
|
63
|
+
catch { }
|
|
64
64
|
}
|
|
65
65
|
try {
|
|
66
66
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
67
67
|
const code = config.groups?.[0];
|
|
68
68
|
const userId = config.userId;
|
|
69
69
|
if (!code || !userId)
|
|
70
|
-
return
|
|
70
|
+
return staleData;
|
|
71
71
|
const tz = -(new Date()).getTimezoneOffset();
|
|
72
72
|
const url = `${config.apiUrl}/api/rank/${code}?period=today&tz=${tz}`;
|
|
73
73
|
const response = execSync(`curl -sf "${url}"`, { encoding: "utf-8", timeout: 5000 });
|
|
74
74
|
if (!response)
|
|
75
|
-
return
|
|
75
|
+
return staleData;
|
|
76
76
|
const data = JSON.parse(response);
|
|
77
77
|
const rankings = data.rankings || [];
|
|
78
78
|
const me = rankings.find((r) => r.userId === userId);
|
|
79
79
|
if (!me)
|
|
80
|
-
return
|
|
80
|
+
return staleData;
|
|
81
81
|
const result = { rank: me.rank, total: rankings.length, cost: me.costUSD };
|
|
82
|
-
writeFileSync(cacheFile, JSON.stringify(result), "utf-8");
|
|
82
|
+
writeFileSync(cacheFile, JSON.stringify({ sessionId, data: result }), "utf-8");
|
|
83
83
|
return result;
|
|
84
84
|
}
|
|
85
85
|
catch {
|
|
86
|
-
return
|
|
86
|
+
return staleData;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
export function rankColor(rank) {
|
|
@@ -95,20 +95,20 @@ export function rankColor(rank) {
|
|
|
95
95
|
return FG_ORANGE;
|
|
96
96
|
return FG_CYAN;
|
|
97
97
|
}
|
|
98
|
-
// Claude usage fetcher
|
|
99
|
-
function getClaudeUsage() {
|
|
98
|
+
// Claude usage fetcher — cached per session (stale fallback on failure)
|
|
99
|
+
function getClaudeUsage(sessionId) {
|
|
100
100
|
const cacheFile = "/tmp/sl-claude-usage";
|
|
101
101
|
const hitFile = "/tmp/sl-claude-usage-hit";
|
|
102
102
|
const now = Date.now();
|
|
103
|
-
|
|
103
|
+
let staleData = null;
|
|
104
104
|
if (existsSync(cacheFile)) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
catch { }
|
|
105
|
+
try {
|
|
106
|
+
const cached = JSON.parse(readFileSync(cacheFile, "utf-8"));
|
|
107
|
+
staleData = cached.data ?? null;
|
|
108
|
+
if (cached.sessionId === sessionId)
|
|
109
|
+
return staleData;
|
|
111
110
|
}
|
|
111
|
+
catch { }
|
|
112
112
|
}
|
|
113
113
|
try {
|
|
114
114
|
const username = process.env.USER || process.env.USERNAME;
|
|
@@ -172,11 +172,11 @@ function getClaudeUsage() {
|
|
|
172
172
|
const result = { fiveHour, sevenDay };
|
|
173
173
|
if (fiveHourResetsAt)
|
|
174
174
|
result.fiveHourResetsAt = fiveHourResetsAt;
|
|
175
|
-
writeFileSync(cacheFile, JSON.stringify(result), "utf-8");
|
|
175
|
+
writeFileSync(cacheFile, JSON.stringify({ sessionId, data: result }), "utf-8");
|
|
176
176
|
return result;
|
|
177
177
|
}
|
|
178
178
|
catch {
|
|
179
|
-
return
|
|
179
|
+
return staleData;
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
export function render(input) {
|
|
@@ -191,9 +191,11 @@ export function render(input) {
|
|
|
191
191
|
const cost = data.cost?.total_cost_usd ?? 0;
|
|
192
192
|
const model = data.model?.display_name ?? "—";
|
|
193
193
|
const contextPct = Math.floor(data.context_window?.used_percentage ?? 0);
|
|
194
|
+
// Session ID from transcript path (filename without extension)
|
|
195
|
+
const transcriptPath = data.transcript_path ?? "";
|
|
196
|
+
const sessionId = transcriptPath ? transcriptPath.replace(/^.*\//, "").replace(/\.jsonl$/, "") : "";
|
|
194
197
|
// Token stats from transcript
|
|
195
198
|
let totalTokens = 0;
|
|
196
|
-
const transcriptPath = data.transcript_path ?? "";
|
|
197
199
|
if (transcriptPath) {
|
|
198
200
|
try {
|
|
199
201
|
const content = readFileSync(transcriptPath, "utf-8");
|
|
@@ -214,7 +216,7 @@ export function render(input) {
|
|
|
214
216
|
}
|
|
215
217
|
const cache = readCache();
|
|
216
218
|
const config = readConfig();
|
|
217
|
-
const claudeUsage = getClaudeUsage();
|
|
219
|
+
const claudeUsage = getClaudeUsage(sessionId);
|
|
218
220
|
const g = FG_GRAY_DIM;
|
|
219
221
|
const y = FG_YELLOW;
|
|
220
222
|
const m = FG_MODEL;
|
|
@@ -247,7 +249,7 @@ export function render(input) {
|
|
|
247
249
|
segments.push(usageParts.join(` ${g}·${r} `));
|
|
248
250
|
}
|
|
249
251
|
// #2 $53.6
|
|
250
|
-
const ccclubRank = getCcclubRank();
|
|
252
|
+
const ccclubRank = getCcclubRank(sessionId);
|
|
251
253
|
if (ccclubRank) {
|
|
252
254
|
const rc = rankColor(ccclubRank.rank);
|
|
253
255
|
segments.push(`${rc}#${ccclubRank.rank} ${formatCost(ccclubRank.cost)}${r}`);
|