ccus-cli 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +219 -202
- package/dist/lib/aggregate-dashboard.js +407 -407
- package/dist/lib/payload.js +91 -2
- package/package.json +39 -35
package/dist/lib/payload.js
CHANGED
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.readSessionId = readSessionId;
|
|
7
7
|
exports.extractWorkspaceDir = extractWorkspaceDir;
|
|
8
8
|
exports.parseStatuslinePayload = parseStatuslinePayload;
|
|
9
|
+
exports.resolveCtxTier = resolveCtxTier;
|
|
10
|
+
exports.resolveCtxRedThresholds = resolveCtxRedThresholds;
|
|
9
11
|
exports.formatStatusLine = formatStatusLine;
|
|
10
12
|
exports.createPersistedStatuslineEvent = createPersistedStatuslineEvent;
|
|
11
13
|
exports.computeStatuslineEvent = computeStatuslineEvent;
|
|
@@ -146,16 +148,103 @@ function parseStatuslinePayload(input) {
|
|
|
146
148
|
const parsed = JSON.parse(trimmed);
|
|
147
149
|
return isRecord(parsed) ? parsed : {};
|
|
148
150
|
}
|
|
151
|
+
/** statusline 里 ctx 段标红用的 ANSI 颜色码,仅作用于展示,不进任何落盘/导出契约。 */
|
|
152
|
+
const ANSI_RED = "\x1b[31m";
|
|
153
|
+
const ANSI_RESET = "\x1b[0m";
|
|
154
|
+
/** contextMax 超过该值就当作 1M 长上下文窗口,否则按 200K 档。 */
|
|
155
|
+
const CTX_TIER_1M_MIN_MAX = 400_000;
|
|
156
|
+
/**
|
|
157
|
+
* 各档位的内置默认阈值(百分比超阈值或已用 token 超阈值,任一满足即标红)。
|
|
158
|
+
*
|
|
159
|
+
* 200K 窗口余量小、到 80%(约 160K)才提醒;1M 窗口虽大但 50%(约 500K)已用很多,提前提醒。
|
|
160
|
+
*/
|
|
161
|
+
const CTX_TIER_DEFAULTS = {
|
|
162
|
+
"200k": { pct: 80, tokens: null },
|
|
163
|
+
"1m": { pct: 50, tokens: null },
|
|
164
|
+
};
|
|
165
|
+
/** 根据 contextMax 判断当前上下文窗口档位;拿不到 contextMax 时回退到 200K 档。 */
|
|
166
|
+
function resolveCtxTier(contextMax) {
|
|
167
|
+
return contextMax !== null && contextMax > CTX_TIER_1M_MIN_MAX ? "1m" : "200k";
|
|
168
|
+
}
|
|
169
|
+
/** 把 `120000` / `120k` / `0.5m` 这类写法解析成整数 token;非法或空返回 null。 */
|
|
170
|
+
function parseTokenThreshold(raw) {
|
|
171
|
+
const text = raw.trim().toLowerCase();
|
|
172
|
+
if (text === "") {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const multiplier = text.endsWith("m") ? 1_000_000 : text.endsWith("k") ? 1_000 : 1;
|
|
176
|
+
const numericPart = multiplier === 1 ? text : text.slice(0, -1);
|
|
177
|
+
const parsed = Number(numericPart) * multiplier;
|
|
178
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
|
|
179
|
+
}
|
|
180
|
+
/** 按顺序读第一个能解析成非负数的百分比环境变量;全部缺失/非法时返回 fallback。 */
|
|
181
|
+
function readPctEnv(env, keys, fallback) {
|
|
182
|
+
for (const key of keys) {
|
|
183
|
+
const raw = (env[key] ?? "").trim();
|
|
184
|
+
if (raw === "") {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const parsed = Number(raw);
|
|
188
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
189
|
+
return parsed;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return fallback;
|
|
193
|
+
}
|
|
194
|
+
/** 按顺序读第一个非空的 token 阈值环境变量;全部缺失时返回 fallback。 */
|
|
195
|
+
function readTokensEnv(env, keys, fallback) {
|
|
196
|
+
for (const key of keys) {
|
|
197
|
+
const raw = env[key] ?? "";
|
|
198
|
+
if (raw.trim() === "") {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
return parseTokenThreshold(raw);
|
|
202
|
+
}
|
|
203
|
+
return fallback;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 解析某个上下文档位的 ctx 标红阈值,两个条件取「或」:百分比超阈值,或已用 token 超阈值。
|
|
207
|
+
*
|
|
208
|
+
* 优先级:档位专属环境变量 > 通用环境变量 > 档位内置默认。
|
|
209
|
+
*
|
|
210
|
+
* - 百分比:`CCUS_CTX_RED_PCT_200K` / `CCUS_CTX_RED_PCT_1M` → `CCUS_CTX_RED_PCT` → 档位默认(200K=80,1M=50)。
|
|
211
|
+
* - token:`CCUS_CTX_RED_TOKENS_200K` / `CCUS_CTX_RED_TOKENS_1M` → `CCUS_CTX_RED_TOKENS` → 档位默认(默认不启用)。
|
|
212
|
+
* token 支持 `120000` / `120k` / `0.5m` 写法。
|
|
213
|
+
*
|
|
214
|
+
* 阈值只影响 statusline 颜色展示,不改变 stdin/stdout 文本契约,也不落盘。
|
|
215
|
+
*/
|
|
216
|
+
function resolveCtxRedThresholds(contextMax, env = process.env) {
|
|
217
|
+
const tier = resolveCtxTier(contextMax);
|
|
218
|
+
const defaults = CTX_TIER_DEFAULTS[tier];
|
|
219
|
+
const tierSuffix = tier === "1m" ? "1M" : "200K";
|
|
220
|
+
const pct = readPctEnv(env, [`CCUS_CTX_RED_PCT_${tierSuffix}`, "CCUS_CTX_RED_PCT"], defaults.pct);
|
|
221
|
+
const tokens = readTokensEnv(env, [`CCUS_CTX_RED_TOKENS_${tierSuffix}`, "CCUS_CTX_RED_TOKENS"], defaults.tokens);
|
|
222
|
+
return { tier, pct, tokens };
|
|
223
|
+
}
|
|
224
|
+
/** 判断 ctx 是否达到标红条件:百分比超阈值,或已用 token 超阈值,任一满足即标红。 */
|
|
225
|
+
function isContextHot(contextWindowPct, contextUsed, thresholds) {
|
|
226
|
+
if (contextWindowPct !== null && contextWindowPct > thresholds.pct) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
if (thresholds.tokens !== null && contextUsed !== null && contextUsed >= thresholds.tokens) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
149
234
|
/**
|
|
150
235
|
* 生成真正显示在 Claude Code statusline 上的短文本。
|
|
151
236
|
*
|
|
152
237
|
* 这里必须保持单行、紧凑,避免污染 statusline 展示区域。
|
|
153
238
|
*/
|
|
154
|
-
function formatStatusLine(event, gitBranch = null) {
|
|
239
|
+
function formatStatusLine(event, gitBranch = null, env = process.env) {
|
|
155
240
|
const timeLabel = (0, time_1.formatClock)(new Date(event.timestamp));
|
|
156
241
|
const usageLabel = event.usagePct === null ? "5h --" : `5h ${event.usagePct.toFixed(1)}%`;
|
|
157
242
|
const sevenDayLabel = event.sevenDayUsagePct === null ? "7d --" : `7d ${event.sevenDayUsagePct.toFixed(1)}%`;
|
|
158
|
-
const
|
|
243
|
+
const contextText = event.contextWindowPct === null ? "ctx --" : `ctx ${event.contextWindowPct.toFixed(1)}%`;
|
|
244
|
+
// ctx 占用超阈值时整段标红,提醒上下文快满;阈值按窗口大小(200K / 1M)分档,由 resolveCtxRedThresholds 决定。
|
|
245
|
+
const contextLabel = isContextHot(event.contextWindowPct, event.contextUsed ?? null, resolveCtxRedThresholds(event.contextMax ?? null, env))
|
|
246
|
+
? `${ANSI_RED}${contextText}${ANSI_RESET}`
|
|
247
|
+
: contextText;
|
|
159
248
|
const modelLabel = event.modelName ?? "model --";
|
|
160
249
|
const workspaceLabel = event.workspaceName ?? "workspace --";
|
|
161
250
|
const segments = [usageLabel, sevenDayLabel, contextLabel, modelLabel, workspaceLabel];
|
package/package.json
CHANGED
|
@@ -1,35 +1,39 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ccus-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Claude Code statusline usage logger and dashboard CLI",
|
|
5
|
-
"type": "commonjs",
|
|
6
|
-
"bin": {
|
|
7
|
-
"ccus": "dist/cli.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/cli.js",
|
|
11
|
-
"dist/lib/**/*.js",
|
|
12
|
-
"dist/types.js"
|
|
13
|
-
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsc -p tsconfig.json",
|
|
16
|
-
"prepublishOnly": "npm run build",
|
|
17
|
-
"test": "node --test dist/test",
|
|
18
|
-
"test:src": "node --import tsx --test src/test/payload.test.ts src/test/dashboard.test.ts src/test/export.test.ts src/test/storage.test.ts src/test/claude.test.ts src/test/aggregate.test.ts src/test/aggregate-dashboard.test.ts src/test/install.test.ts src/test/debug.test.ts src/test/time.test.ts src/test/update-check.test.ts"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"claude-code",
|
|
22
|
-
"statusline",
|
|
23
|
-
"cli",
|
|
24
|
-
"dashboard"
|
|
25
|
-
],
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
},
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "ccus-cli",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Claude Code statusline usage logger and dashboard CLI",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ccus": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/cli.js",
|
|
11
|
+
"dist/lib/**/*.js",
|
|
12
|
+
"dist/types.js"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"test": "node --test dist/test",
|
|
18
|
+
"test:src": "node --import tsx --test src/test/payload.test.ts src/test/dashboard.test.ts src/test/export.test.ts src/test/storage.test.ts src/test/claude.test.ts src/test/aggregate.test.ts src/test/aggregate-dashboard.test.ts src/test/install.test.ts src/test/debug.test.ts src/test/time.test.ts src/test/update-check.test.ts"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"claude-code",
|
|
22
|
+
"statusline",
|
|
23
|
+
"cli",
|
|
24
|
+
"dashboard"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/gaoshang212/ccus-cli.git"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^24.0.0",
|
|
36
|
+
"tsx": "^4.20.0",
|
|
37
|
+
"typescript": "^5.8.3"
|
|
38
|
+
}
|
|
39
|
+
}
|