@v1nvn/zai 0.25.0 → 0.27.0
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 +23 -7
- package/dist/index.js +40 -32
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -18,19 +18,35 @@ claude plugin install zai@agentic
|
|
|
18
18
|
In a terminal, bare:
|
|
19
19
|
|
|
20
20
|
```sh
|
|
21
|
-
npx -y @v1nvn/zai@0.
|
|
21
|
+
npx -y @v1nvn/zai@0.27.0
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Usage
|
|
25
25
|
|
|
26
26
|
| Invocation | Does |
|
|
27
27
|
|---|---|
|
|
28
|
-
| `npx -y @v1nvn/zai@0.
|
|
29
|
-
| `npx -y @v1nvn/zai@0.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
| `npx -y @v1nvn/zai@0.27.0` | usage report — models, quota window, remaining balance |
|
|
29
|
+
| `npx -y @v1nvn/zai@0.27.0 --auth-token TOKEN` | same, key on the command line (visible in `ps`) |
|
|
30
|
+
| `npx -y @v1nvn/zai@0.27.0 --auth-token=TOKEN` | `=` form — zsh quoting-safe |
|
|
31
|
+
| `npx -y @v1nvn/zai@0.27.0 --base-url URL` | another GLM endpoint (default `api.z.ai`) |
|
|
32
|
+
|
|
33
|
+
Each setting takes the first source that provides it:
|
|
34
|
+
|
|
35
|
+
| Setting | Flag | zai env | Claude Code env | Default |
|
|
36
|
+
|---|---|---|---|---|
|
|
37
|
+
| API key | `--auth-token` | `ZAI_AUTH_TOKEN` | `ANTHROPIC_AUTH_TOKEN` ¹ | — required |
|
|
38
|
+
| Base URL | `--base-url` | `ZAI_BASE_URL` | `ANTHROPIC_BASE_URL` ¹ | `https://api.z.ai` |
|
|
39
|
+
|
|
40
|
+
¹ Inherited only when the resolved base URL names a GLM host (`api.z.ai`,
|
|
41
|
+
`open.bigmodel.cn`, `dev.bigmodel.cn`) — that is what proves the token belongs
|
|
42
|
+
to a GLM Coding Plan. Claude Code routed elsewhere (plain Anthropic, another
|
|
43
|
+
proxy) is not a zai configuration; set `ZAI_AUTH_TOKEN`. Bigmodel accounts
|
|
44
|
+
point the base URL at their host; the monitor paths are identical
|
|
45
|
+
(`ZAI_BASE_URL=https://open.bigmodel.cn`). The hook reads the same env from
|
|
46
|
+
the Claude Code process; flags are a CLI affordance — `hooks.json` is static.
|
|
47
|
+
|
|
48
|
+
The API labels every bucket in Beijing time (UTC+8); the report shifts each
|
|
49
|
+
timestamp to your local zone for display.
|
|
34
50
|
|
|
35
51
|
## Develop
|
|
36
52
|
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, Option } from "commander";
|
|
3
3
|
//#region ../core/dist/index.js
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* yields an empty event, never a thrown error — a hook must always answer.
|
|
7
|
-
*/
|
|
8
|
-
function readHookEvent(stream = process.stdin) {
|
|
9
|
-
return new Promise((resolve) => {
|
|
4
|
+
function readAll(stream) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
10
6
|
let data = "";
|
|
11
7
|
stream.setEncoding("utf8");
|
|
12
8
|
stream.on("data", (chunk) => {
|
|
13
9
|
data += chunk;
|
|
14
10
|
});
|
|
15
11
|
stream.on("end", () => {
|
|
16
|
-
|
|
17
|
-
resolve(JSON.parse(data));
|
|
18
|
-
} catch {
|
|
19
|
-
resolve({});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
stream.on("error", () => {
|
|
23
|
-
resolve({});
|
|
12
|
+
resolve(data);
|
|
24
13
|
});
|
|
14
|
+
stream.on("error", reject);
|
|
25
15
|
});
|
|
26
16
|
}
|
|
27
17
|
/**
|
|
18
|
+
* Read the Claude Code hook event JSON from stdin; empty or unparseable input
|
|
19
|
+
* yields an empty event, never a thrown error — a hook must always answer.
|
|
20
|
+
*/
|
|
21
|
+
function readHookEvent(stream = process.stdin) {
|
|
22
|
+
return readAll(stream).then((data) => {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(data);
|
|
25
|
+
} catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}, () => ({}));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
28
31
|
* Print the UserPromptExpansion decision for a zero-token command: `block`
|
|
29
32
|
* keeps the command from reaching the model, with the output as the `reason`.
|
|
30
33
|
*/
|
|
@@ -34,15 +37,15 @@ function emitHookBlock(reason) {
|
|
|
34
37
|
reason
|
|
35
38
|
})}\n`);
|
|
36
39
|
}
|
|
37
|
-
function parseQuietly(program, args) {
|
|
40
|
+
function parseQuietly(program, args, recover) {
|
|
38
41
|
try {
|
|
39
42
|
program.allowExcessArguments(false).exitOverride().configureOutput({
|
|
40
43
|
writeOut: () => void 0,
|
|
41
44
|
writeErr: () => void 0
|
|
42
45
|
}).parse([...args], { from: "user" });
|
|
43
46
|
return program;
|
|
44
|
-
} catch {
|
|
45
|
-
return;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return recover?.(err);
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
function printUsageAndExit(program) {
|
|
@@ -67,6 +70,7 @@ async function hookOrPrint(hook, failure, run, stdin = process.stdin) {
|
|
|
67
70
|
process.exit(1);
|
|
68
71
|
}
|
|
69
72
|
}
|
|
73
|
+
Number.MAX_SAFE_INTEGER;
|
|
70
74
|
/**
|
|
71
75
|
* Plain-text rendering primitives shared by the zai and tokens report
|
|
72
76
|
* renderers. Output targets a monospace terminal / hook-block `reason`, so
|
|
@@ -97,6 +101,12 @@ var EIGHTHS = [
|
|
|
97
101
|
"▊",
|
|
98
102
|
"▉"
|
|
99
103
|
];
|
|
104
|
+
function rule() {
|
|
105
|
+
return "─".repeat(68);
|
|
106
|
+
}
|
|
107
|
+
function pad2(n) {
|
|
108
|
+
return String(n).padStart(2, "0");
|
|
109
|
+
}
|
|
100
110
|
function fmtTokens(n) {
|
|
101
111
|
if (n == null || Number.isNaN(n)) return "—";
|
|
102
112
|
if (n >= 1e9) return (n / 1e9).toFixed(1) + "B";
|
|
@@ -211,7 +221,6 @@ function resolveConfig(env, parsed) {
|
|
|
211
221
|
* passed through processQuotaLimit).
|
|
212
222
|
*/
|
|
213
223
|
var VBLOCKS = "▁▂▃▄▅▆▇";
|
|
214
|
-
var W = 68;
|
|
215
224
|
function parseSlot(s) {
|
|
216
225
|
const m = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2})/.exec(s ?? "");
|
|
217
226
|
if (!m) return null;
|
|
@@ -233,8 +242,8 @@ function shiftSlot(s, fromOffsetMin, toOffsetMin) {
|
|
|
233
242
|
const dt = new Date(utcMs + toOffsetMin * 6e4);
|
|
234
243
|
return {
|
|
235
244
|
h: dt.getUTCHours(),
|
|
236
|
-
day: `${MONTHS[dt.getUTCMonth()]} ${
|
|
237
|
-
time: `${
|
|
245
|
+
day: `${MONTHS[dt.getUTCMonth()]} ${pad2(dt.getUTCDate())}`,
|
|
246
|
+
time: `${pad2(dt.getUTCHours())}:${pad2(dt.getUTCMinutes())}`
|
|
238
247
|
};
|
|
239
248
|
}
|
|
240
249
|
function friendlyTool(code) {
|
|
@@ -298,7 +307,7 @@ function hourlyVerticalChart({ x, tok, nh, maxTok, peakIdx, slotFn }) {
|
|
|
298
307
|
const L = maxLab.length;
|
|
299
308
|
const AXIS = 1 + L + 1;
|
|
300
309
|
const P0 = AXIS + 2;
|
|
301
|
-
const PW =
|
|
310
|
+
const PW = 68 - P0;
|
|
302
311
|
const slot = Math.max(1, Math.floor(PW / nh));
|
|
303
312
|
const barW = slot >= 2 ? slot - 1 : 1;
|
|
304
313
|
function barLeft(i) {
|
|
@@ -309,7 +318,7 @@ function hourlyVerticalChart({ x, tok, nh, maxTok, peakIdx, slotFn }) {
|
|
|
309
318
|
}
|
|
310
319
|
const usedCols = nh * slot;
|
|
311
320
|
function blank() {
|
|
312
|
-
return Array(
|
|
321
|
+
return Array(68).fill(" ");
|
|
313
322
|
}
|
|
314
323
|
function glyph(i, r) {
|
|
315
324
|
const v = tok[i] || 0;
|
|
@@ -355,7 +364,7 @@ function hourlyVerticalChart({ x, tok, nh, maxTok, peakIdx, slotFn }) {
|
|
|
355
364
|
const col = barCenter(i);
|
|
356
365
|
if (col - last < 3) continue;
|
|
357
366
|
const s = slotOf(i);
|
|
358
|
-
const txt = s ?
|
|
367
|
+
const txt = s ? pad2(s.h) : " ";
|
|
359
368
|
hr[col] = txt[0];
|
|
360
369
|
hr[col + 1] = txt[1];
|
|
361
370
|
last = col;
|
|
@@ -369,7 +378,7 @@ function hourlyVerticalChart({ x, tok, nh, maxTok, peakIdx, slotFn }) {
|
|
|
369
378
|
const s = slotOf(i);
|
|
370
379
|
if (!s || s.day === lastDay) continue;
|
|
371
380
|
const col = barCenter(i);
|
|
372
|
-
if (col - last >= s.day.length && col + s.day.length <=
|
|
381
|
+
if (col - last >= s.day.length && col + s.day.length <= 68) {
|
|
373
382
|
for (let k = 0; k < s.day.length; k++) day[col + k] = s.day[k];
|
|
374
383
|
lastDay = s.day;
|
|
375
384
|
last = col + s.day.length;
|
|
@@ -384,9 +393,6 @@ function hourlyVerticalChart({ x, tok, nh, maxTok, peakIdx, slotFn }) {
|
|
|
384
393
|
}
|
|
385
394
|
function render({ platform, model, tool, quota, apiOffsetMin = 480, localOffsetMin, now = /* @__PURE__ */ new Date() }) {
|
|
386
395
|
const out = [];
|
|
387
|
-
function rule() {
|
|
388
|
-
return "─".repeat(W);
|
|
389
|
-
}
|
|
390
396
|
const toOffset = localOffsetMin != null ? localOffsetMin : -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
391
397
|
function convertSlot(s) {
|
|
392
398
|
return shiftSlot(s, apiOffsetMin, toOffset) ?? parseSlot(s);
|
|
@@ -413,7 +419,7 @@ function render({ platform, model, tool, quota, apiOffsetMin = 480, localOffsetM
|
|
|
413
419
|
const lastSlot = convertSlot(x[nh - 1]);
|
|
414
420
|
const win = firstSlot && lastSlot ? `${firstSlot.day} ${firstSlot.time} → ${lastSlot.day} ${lastSlot.time} · ${nh}h` : platform;
|
|
415
421
|
out.push(rule());
|
|
416
|
-
out.push(left + padL(win,
|
|
422
|
+
out.push(left + padL(win, 68 - left.length));
|
|
417
423
|
out.push(rule());
|
|
418
424
|
let lead = ` ${fmtTokens(total)} tokens across ${fmtNum(totalCalls)} model calls`;
|
|
419
425
|
if (peakIdx >= 0 && peakSlot) lead += ` — ${Math.round(pctPeak)}% of it in a single hour (${peakSlot.day} ${peakSlot.time}, ${fmtTokens(peakTok)} tokens / ${fmtNum(peakCalls)} calls)`;
|
|
@@ -489,14 +495,16 @@ function render({ platform, model, tool, quota, apiOffsetMin = 480, localOffsetM
|
|
|
489
495
|
}
|
|
490
496
|
//#endregion
|
|
491
497
|
//#region src/usage.ts
|
|
498
|
+
/**
|
|
499
|
+
* Usage query. Fetches model usage, tool usage, and quota limits from the GLM
|
|
500
|
+
* Coding Plan monitor API of the resolved base URL (paths are fixed) and
|
|
501
|
+
* renders the plain-text report.
|
|
502
|
+
*/
|
|
492
503
|
function queryParams(now = /* @__PURE__ */ new Date()) {
|
|
493
504
|
const startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1, now.getHours(), 0, 0, 0);
|
|
494
505
|
const endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), 59, 59, 999);
|
|
495
506
|
function formatDateTime(date) {
|
|
496
|
-
|
|
497
|
-
return String(n).padStart(2, "0");
|
|
498
|
-
}
|
|
499
|
-
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}:${p(date.getSeconds())}`;
|
|
507
|
+
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`;
|
|
500
508
|
}
|
|
501
509
|
return `?startTime=${encodeURIComponent(formatDateTime(startDate))}&endTime=${encodeURIComponent(formatDateTime(endDate))}`;
|
|
502
510
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../core/dist/index.js","../src/resolve.ts","../src/format.ts","../src/usage.ts","../src/index.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n//#region src/hook.ts\n/**\n* Read the Claude Code hook event JSON from stdin; empty or unparseable input\n* yields an empty event, never a thrown error — a hook must always answer.\n*/\nfunction readHookEvent(stream = process.stdin) {\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tstream.setEncoding(\"utf8\");\n\t\tstream.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tstream.on(\"end\", () => {\n\t\t\ttry {\n\t\t\t\tresolve(JSON.parse(data));\n\t\t\t} catch {\n\t\t\t\tresolve({});\n\t\t\t}\n\t\t});\n\t\tstream.on(\"error\", () => {\n\t\t\tresolve({});\n\t\t});\n\t});\n}\n/**\n* Which transcript lastReply should read, per the hook event: transcript_path\n* when it names a real file, else session_id, else nothing (lastReply then\n* falls back to the newest session for the current project).\n*/\nfunction replyTarget(event) {\n\tif (event.transcript_path !== void 0 && isFile$1(event.transcript_path)) return event.transcript_path;\n\treturn event.session_id || void 0;\n}\nfunction isFile$1(path) {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n/**\n* Print the UserPromptExpansion decision for a zero-token command: `block`\n* keeps the command from reaching the model, with the output as the `reason`.\n*/\nfunction emitHookBlock(reason) {\n\tprocess.stdout.write(`${JSON.stringify({\n\t\tdecision: \"block\",\n\t\treason\n\t})}\\n`);\n}\n//#endregion\n//#region src/cli.ts\nfunction parseQuietly(program, args) {\n\ttry {\n\t\tprogram.allowExcessArguments(false).exitOverride().configureOutput({\n\t\t\twriteOut: () => void 0,\n\t\t\twriteErr: () => void 0\n\t\t}).parse([...args], { from: \"user\" });\n\t\treturn program;\n\t} catch {\n\t\treturn;\n\t}\n}\nfunction printUsageAndExit(program) {\n\tconsole.error(program.helpInformation());\n\tprocess.exit(1);\n}\nasync function hookOrPrint(hook, failure, run, stdin = process.stdin) {\n\tif (hook) {\n\t\tlet reason;\n\t\ttry {\n\t\t\treason = await run(await readHookEvent(stdin));\n\t\t} catch (e) {\n\t\t\treason = `${failure}: ${e.message}`;\n\t\t}\n\t\temitHookBlock(reason);\n\t\treturn;\n\t}\n\ttry {\n\t\tconsole.log(await run(void 0));\n\t} catch (e) {\n\t\tconsole.error(e.message);\n\t\tprocess.exit(1);\n\t}\n}\n//#endregion\n//#region src/last-reply.ts\nfunction isFile(path) {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\nfunction textBlocks(entry) {\n\tconst content = entry.message?.content;\n\tif (entry.type !== \"assistant\" || !Array.isArray(content)) return;\n\tconst blocks = content.filter((b) => typeof b === \"object\" && b !== null && b.type === \"text\");\n\treturn blocks.length > 0 ? blocks : void 0;\n}\n/**\n* The last assistant text reply from a Claude Code session, reproducing Claude\n* Code's `/copy` byte-for-byte: the last assistant entry that contains a\n* `text` block, only its `text` block(s) (tool_use / thinking dropped), blocks\n* joined with a blank line, and no trailing newline.\n*\n* @param arg a transcript file, a session UUID under the project dir, or\n* nothing to use the newest session for the current project.\n*/\nfunction lastReply(arg) {\n\tconst claudeDir = process.env.CLAUDE_DIR ?? join(homedir(), \".claude\");\n\tconst proj = (process.env.CLAUDE_PROJECT_DIR ?? process.cwd()).replaceAll(\"/\", \"-\");\n\tconst projDir = join(claudeDir, \"projects\", proj);\n\tlet file;\n\tif (arg !== void 0) file = isFile(arg) ? arg : join(projDir, `${arg}.jsonl`);\n\telse if (existsSync(projDir)) {\n\t\tconst newest = readdirSync(projDir).filter((f) => f.endsWith(\".jsonl\")).map((f) => ({\n\t\t\tf,\n\t\t\tmtimeMs: statSync(join(projDir, f)).mtimeMs\n\t\t})).sort((a, b) => b.mtimeMs - a.mtimeMs).at(0);\n\t\tif (newest) file = join(projDir, newest.f);\n\t}\n\tif (file === void 0 || !isFile(file)) throw new Error(`no session transcript found in ${projDir}`);\n\tlet last;\n\tfor (const line of readFileSync(file, \"utf8\").split(\"\\n\")) {\n\t\tif (!line.includes(\"\\\"assistant\\\"\")) continue;\n\t\tlet entry;\n\t\ttry {\n\t\t\tentry = JSON.parse(line);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst blocks = textBlocks(entry);\n\t\tif (blocks) last = blocks;\n\t}\n\treturn (last ?? []).map((b) => b.text ?? \"\").join(\"\\n\\n\");\n}\n//#endregion\n//#region src/text-format.ts\n/**\n* Plain-text rendering primitives shared by the zai and tokens report\n* renderers. Output targets a monospace terminal / hook-block `reason`, so\n* everything here is fixed-width: padding, block-glyph bars, and compact\n* number formatting.\n*/\nvar MONTHS = [\n\t\"Jan\",\n\t\"Feb\",\n\t\"Mar\",\n\t\"Apr\",\n\t\"May\",\n\t\"Jun\",\n\t\"Jul\",\n\t\"Aug\",\n\t\"Sep\",\n\t\"Oct\",\n\t\"Nov\",\n\t\"Dec\"\n];\nvar EIGHTHS = [\n\t\"\",\n\t\"▏\",\n\t\"▎\",\n\t\"▍\",\n\t\"▌\",\n\t\"▋\",\n\t\"▊\",\n\t\"▉\"\n];\nfunction fmtTokens(n) {\n\tif (n == null || Number.isNaN(n)) return \"—\";\n\tif (n >= 1e9) return (n / 1e9).toFixed(1) + \"B\";\n\tif (n >= 1e6) return (n / 1e6).toFixed(1) + \"M\";\n\tif (n >= 1e3) return (n / 1e3).toFixed(1) + \"K\";\n\treturn String(n);\n}\nfunction fmtNum(n) {\n\treturn (n || 0).toLocaleString(\"en-US\");\n}\nfunction padR(s, n) {\n\treturn s.length >= n ? s : s + \" \".repeat(n - s.length);\n}\nfunction padL(s, n) {\n\treturn s.length >= n ? s : \" \".repeat(n - s.length) + s;\n}\n/** Fixed-width bar field (width cols): █ blocks + an eighth-fraction + trailing spaces. */\nfunction barField(v, max, width) {\n\tif (!v || v <= 0 || max <= 0) return \" \".repeat(width);\n\tconst scaled = v / max * width;\n\tlet full = Math.floor(scaled);\n\tlet fi = Math.round((scaled - full) * 8);\n\tif (fi === 8) {\n\t\tfull += 1;\n\t\tfi = 0;\n\t}\n\tif (full === 0 && fi === 0) fi = 1;\n\tlet s = \"█\".repeat(Math.min(full, width));\n\tif (full < width && fi > 0) s += EIGHTHS[fi];\n\tif (s.length < width) s += \" \".repeat(width - s.length);\n\treturn s.slice(0, width);\n}\n/** Filled/empty meter: █ for used, ░ for remaining. */\nfunction meter(pct, width) {\n\tlet filled = Math.round((pct || 0) / 100 * width);\n\tfilled = Math.max(0, Math.min(width, filled));\n\treturn \"█\".repeat(filled) + \"░\".repeat(width - filled);\n}\n//#endregion\nexport { MONTHS, barField, emitHookBlock, fmtNum, fmtTokens, hookOrPrint, lastReply, meter, padL, padR, parseQuietly, printUsageAndExit, readHookEvent, replyTarget };\n\n//# sourceMappingURL=index.js.map","import { parseQuietly } from '@v1nvn/agentic-core';\nimport { Command, Option } from 'commander';\n\nconst DEFAULT_BASE_URL = 'https://api.z.ai';\n\nconst GLM_HOSTS = new Set(['api.z.ai', 'dev.bigmodel.cn', 'open.bigmodel.cn']);\n\nexport interface ParsedArgs {\n readonly authToken: string | undefined;\n readonly baseUrl: string | undefined;\n readonly hook: boolean;\n}\n\nexport interface ResolvedConfig {\n readonly token: string;\n readonly url: string;\n}\n\ninterface BaseUrl {\n readonly glm: boolean;\n readonly origin: string;\n}\n\nfunction fromEnv(value: string | undefined): string | undefined {\n return value ? value : undefined;\n}\n\nfunction originOf(value: string): string | undefined {\n try {\n const url = new URL(value);\n return url.protocol === 'https:' || url.protocol === 'http:'\n ? url.origin\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isGlm(origin: string): boolean {\n return GLM_HOSTS.has(new URL(origin).hostname);\n}\n\nfunction resolveBaseUrl(\n flag: string | undefined,\n env: NodeJS.ProcessEnv,\n): BaseUrl {\n if (flag !== undefined) {\n const origin = originOf(flag);\n if (origin === undefined) {\n throw new Error(`invalid base URL: ${flag}`);\n }\n return { glm: isGlm(origin), origin };\n }\n const inherited = fromEnv(env.ANTHROPIC_BASE_URL);\n const origin = inherited === undefined ? undefined : originOf(inherited);\n if (origin !== undefined && isGlm(origin)) {\n return { glm: true, origin };\n }\n return { glm: false, origin: DEFAULT_BASE_URL };\n}\n\nexport function buildProgram(): Command {\n return new Command()\n .name('zai-usage')\n .addOption(\n new Option('--auth-token <token>', 'API key').env('ZAI_AUTH_TOKEN'),\n )\n .addOption(new Option('--base-url <url>', 'base URL').env('ZAI_BASE_URL'))\n .option('--hook', 'emit a UserPromptExpansion block instead of printing');\n}\n\nexport function parseArgs(args: readonly string[]): ParsedArgs | undefined {\n const program = parseQuietly(buildProgram(), args);\n if (program === undefined) {\n return undefined;\n }\n const { authToken, baseUrl, hook } = program.opts<{\n authToken: string | undefined;\n baseUrl: string | undefined;\n hook: boolean | undefined;\n }>();\n return {\n authToken: authToken || undefined,\n baseUrl: baseUrl || undefined,\n hook: hook ?? false,\n };\n}\n\nexport function resolveConfig(\n env: NodeJS.ProcessEnv,\n parsed: ParsedArgs,\n): ResolvedConfig {\n const base = resolveBaseUrl(parsed.baseUrl, env);\n const token =\n parsed.authToken ??\n (base.glm ? fromEnv(env.ANTHROPIC_AUTH_TOKEN) : undefined);\n if (token === undefined) {\n throw new Error(\n env.ANTHROPIC_AUTH_TOKEN\n ? 'ANTHROPIC_AUTH_TOKEN is set, but the resolved base URL does not name a GLM host, so it is not a GLM Coding Plan token — set ZAI_AUTH_TOKEN (or --auth-token)'\n : 'no API key: set ZAI_AUTH_TOKEN (or --auth-token)',\n );\n }\n return { token, url: base.origin };\n}\n","/**\n * Plain-text usage report renderer.\n *\n * Rendered for a monospace terminal / hook-block `reason`, so it must NOT rely on\n * markdown (bold, tables, fenced code). Alignment comes from fixed-width columns\n * and unicode block glyphs. Input is the parsed `data` of the three ZAI/ZHIPU\n * monitor endpoints (model-usage, tool-usage, quota/limit — the last already\n * passed through processQuotaLimit).\n */\n\nimport {\n barField,\n fmtNum,\n fmtTokens,\n meter,\n MONTHS,\n padL,\n padR,\n} from '@v1nvn/agentic-core';\n\n// Lower-half block eighths for vertical bars (1/8 .. 7/8); a full cell uses '█'.\nconst VBLOCKS = '▁▂▃▄▅▆▇';\n\nconst W = 68; // overall rule width\n\nexport interface ModelMixEntry {\n modelName?: string;\n sortOrder?: number;\n totalTokens?: number;\n}\n\nexport interface ZaiModelUsage {\n modelCallCount?: number[];\n modelDataList?: ModelMixEntry[];\n modelSummaryList?: ModelMixEntry[];\n tokensUsage?: number[];\n totalUsage?: { totalModelCallCount?: number; totalTokensUsage?: number };\n x_time?: string[];\n}\n\nexport interface ZaiToolUsage {\n totalUsage?: {\n totalNetworkSearchCount?: number;\n totalSearchMcpCount?: number;\n totalWebReadMcpCount?: number;\n totalZreadMcpCount?: number;\n };\n}\n\nexport interface ZaiQuotaLimit {\n currentUsage?: number;\n nextResetTime?: string;\n percentage?: number;\n totol?: number;\n type?: string;\n usageDetails?: { modelCode?: string; usage?: number }[];\n}\n\nexport interface ZaiQuota {\n level?: string;\n limits?: ZaiQuotaLimit[];\n}\n\nexport interface RenderInput {\n apiOffsetMin?: number;\n localOffsetMin?: number;\n model: ZaiModelUsage;\n now?: Date;\n platform: string;\n quota: ZaiQuota;\n tool: ZaiToolUsage;\n}\n\ninterface Slot {\n day: string;\n h: number;\n time: string;\n}\n\nfunction parseSlot(s: string | undefined): null | Slot {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2})/.exec(s ?? '');\n if (!m) {\n return null;\n }\n return {\n h: +m[4],\n day: `${MONTHS[+m[2] - 1]} ${m[3]}`,\n time: `${m[4]}:${m[5]}`,\n };\n}\n\n/**\n * Re-express a naive \"YYYY-MM-DD HH:MM\" string from one UTC offset to another.\n * Offsets are minutes east of UTC (Beijing = 480, IST = 330). Pure — does not\n * depend on the runtime timezone, so it is deterministic under test.\n */\nfunction shiftSlot(\n s: string,\n fromOffsetMin: number,\n toOffsetMin: number,\n): null | Slot {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2})/.exec(s);\n if (!m) {\n return null;\n }\n const utcMs =\n Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5]) - fromOffsetMin * 60000;\n const dt = new Date(utcMs + toOffsetMin * 60000);\n return {\n h: dt.getUTCHours(),\n day: `${MONTHS[dt.getUTCMonth()]} ${String(dt.getUTCDate()).padStart(2, '0')}`,\n time: `${String(dt.getUTCHours()).padStart(2, '0')}:${String(dt.getUTCMinutes()).padStart(2, '0')}`,\n };\n}\n\nfunction friendlyTool(code: string | undefined): string {\n switch ((code ?? '').toLowerCase()) {\n case 'search-prime':\n return 'web search';\n case 'web-reader':\n return 'web read';\n default:\n return code || 'other';\n }\n}\n\nfunction idleRuns(tok: number[]): { i: number; j: number; len: number }[] {\n const runs: { i: number; j: number; len: number }[] = [];\n let i = 0;\n while (i < tok.length) {\n if ((tok[i] || 0) === 0) {\n let j = i;\n while (j < tok.length && (tok[j] || 0) === 0) {\n j++;\n }\n runs.push({ i, j: j - 1, len: j - i });\n i = j;\n } else {\n i++;\n }\n }\n return runs;\n}\n\nfunction idleLabel(\n run: { i: number; j: number; len: number },\n x: string[],\n slotFn: (s: string) => null | Slot,\n): string {\n const a = slotFn(x[run.i]);\n const b = slotFn(x[run.j]);\n if (!a || !b) {\n return `idle (${run.len}h)`;\n }\n const start = `${a.day} ${a.time}`;\n const end = a.day === b.day ? b.time : `${b.day} ${b.time}`;\n return `idle ${start} → ${end} (${run.len}h)`;\n}\n\n// Per the usage-revision notice: Mon–Fri 14:00–18:00 Beijing (UTC+8) are peak\n// hours, where GLM-5.2 / GLM-5-Turbo tokens are billed at a 3× coefficient\n// (GLM-4.7 stays 1× all day). A bucket labelled \"HH:00\" spans HH:00–HH+1, so\n// the peak buckets are HH ∈ {14,15,16,17} on a weekday.\nfunction isPeakBucket(s: string | undefined): boolean {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):/.exec(s ?? '');\n if (!m) {\n return false;\n }\n const wd = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3])).getUTCDay(); // 0=Sun … 6=Sat\n return wd >= 1 && wd <= 5 && +m[4] >= 14 && +m[4] <= 17;\n}\n\n/** Local-time start/end of the 14:00–18:00 Beijing peak window (e.g. 11:30 / 15:30). */\nfunction localPeakWindow(\n apiOffsetMin: number,\n toOffsetMin: number,\n): null | { end: string; start: string } {\n const a = shiftSlot('2000-01-03 14:00', apiOffsetMin, toOffsetMin);\n const b = shiftSlot('2000-01-03 18:00', apiOffsetMin, toOffsetMin);\n if (!a || !b) {\n return null;\n }\n return { start: a.time, end: b.time };\n}\n\n/**\n * Vertical bar chart of hourly tokens. Returns an array of plain-text lines\n * (without the section header), or null if there are fewer than 2 buckets.\n *\n * Bars are scaled to `maxTok` across `ROWS` rows; the topmost filled cell of a\n * bar uses a fractional lower-block glyph (▁▂▃▄▅▆▇) for sub-row height. The\n * y-axis labels only the peak (top) and 0 (baseline); the header window and the\n * caller's peak annotation carry the exact values.\n */\nfunction hourlyVerticalChart({\n x,\n tok,\n nh,\n maxTok,\n peakIdx,\n slotFn,\n}: {\n maxTok: number;\n nh: number;\n peakIdx: number;\n slotFn: (s: string) => null | Slot;\n tok: number[];\n x: string[];\n}): null | string[] {\n const ROWS = 6; // bar rows above the baseline\n if (nh < 2 || maxTok <= 0) {\n return null;\n }\n\n const lines: string[] = [];\n const maxLab = fmtTokens(maxTok);\n const L = maxLab.length;\n const IND = 1; // leading indent\n const AXIS = IND + L + 1; // axis spine col (1-space gap after the label)\n const P0 = AXIS + 2; // first bar column (axis + 1-char gap)\n const PW = W - P0; // columns available for bars + gaps\n const slot = Math.max(1, Math.floor(PW / nh));\n const barW = slot >= 2 ? slot - 1 : 1;\n function barLeft(i: number): number {\n return P0 + i * slot;\n }\n function barCenter(i: number): number {\n return barLeft(i) + Math.floor(barW / 2);\n }\n const usedCols = nh * slot;\n function blank(): string[] {\n return Array<string>(W).fill(' ');\n }\n\n // bar glyph for hour i at row r (0 = bottom bar-row, ROWS-1 = top)\n function glyph(i: number, r: number): string {\n const v = tok[i] || 0;\n if (v <= 0) {\n return ' ';\n }\n const fill = (v / maxTok) * ROWS - r; // how much of row r the bar covers\n if (fill >= 1) {\n return '█';\n }\n if (fill > 0) {\n let e = Math.round(fill * 8); // 1..7 eighths\n if (e < 1) {\n e = 1;\n }\n if (e > 7) {\n e = 7;\n }\n return VBLOCKS[e - 1];\n }\n return ' ';\n }\n\n // bar rows, top → bottom; top row carries the max label + '┤', rest are '│'\n for (let r = ROWS - 1; r >= 0; r--) {\n const line = blank();\n line[AXIS] = r === ROWS - 1 ? '┤' : '│';\n if (r === ROWS - 1) {\n for (let k = 0; k < L; k++) {\n line[AXIS - 1 - L + k] = maxLab[k];\n }\n }\n for (let i = 0; i < nh; i++) {\n const g = glyph(i, r);\n if (g !== ' ') {\n for (let c = 0; c < barW; c++) {\n line[barLeft(i) + c] = g;\n }\n }\n }\n lines.push(line.join('').trimEnd());\n }\n\n // x-axis ticks: first, last, and every bucket landing on a 6h boundary (local)\n function slotOf(i: number): null | Slot {\n return slotFn(x[i]);\n }\n function isTick(i: number): boolean {\n if (i === 0 || i === nh - 1) {\n return true;\n }\n const s = slotOf(i);\n return !!s && s.h % 6 === 0;\n }\n\n // baseline: '0' label + corner '└' + '─' run, with '┬' under each tick\n const base = blank();\n base[AXIS - 2] = '0';\n base[AXIS] = '└';\n for (let c = AXIS + 1; c < P0 + usedCols; c++) {\n base[c] = '─';\n }\n for (let i = 0; i < nh; i++) {\n if (isTick(i)) {\n base[barCenter(i)] = '┬';\n }\n }\n lines.push(base.join('').trimEnd());\n\n // hour labels under ticks (skip if too close to the previous label)\n const hr = blank();\n let last = -10;\n for (let i = 0; i < nh; i++) {\n if (!isTick(i)) {\n continue;\n }\n const col = barCenter(i);\n if (col - last < 3) {\n continue;\n }\n const s = slotOf(i);\n const txt = s ? String(s.h).padStart(2, '0') : ' ';\n hr[col] = txt[0];\n hr[col + 1] = txt[1];\n last = col;\n }\n lines.push(hr.join('').trimEnd());\n\n // day labels under the first tick of each new local day\n const day = blank();\n let lastDay: null | string = null;\n last = -10;\n for (let i = 0; i < nh; i++) {\n if (!isTick(i)) {\n continue;\n }\n const s = slotOf(i);\n if (!s || s.day === lastDay) {\n continue;\n }\n const col = barCenter(i);\n if (col - last >= s.day.length && col + s.day.length <= W) {\n for (let k = 0; k < s.day.length; k++) {\n day[col + k] = s.day[k];\n }\n lastDay = s.day;\n last = col + s.day.length;\n }\n }\n if (day.some(c => c !== ' ')) {\n lines.push(day.join('').trimEnd());\n }\n\n // peak-window (↑) and peak (◂) markers under bar centers\n const mark = blank();\n for (let i = 0; i < nh; i++) {\n if (isPeakBucket(x[i])) {\n mark[barCenter(i)] = '↑';\n }\n }\n if (peakIdx >= 0) {\n mark[barCenter(peakIdx)] = '◂';\n }\n if (mark.some(c => c !== ' ')) {\n lines.push(mark.join('').trimEnd());\n }\n\n return lines;\n}\n\nexport function render({\n platform,\n model,\n tool,\n quota,\n apiOffsetMin = 480,\n localOffsetMin,\n now = new Date(),\n}: RenderInput): string {\n const out: string[] = [];\n function rule(): string {\n return '─'.repeat(W);\n }\n\n // The monitor API labels every bucket in Beijing time (UTC+8). Shift each\n // timestamp to the caller's offset (minutes east of UTC) for display.\n // Defaults to the JS runtime's local zone.\n const toOffset =\n localOffsetMin != null ? localOffsetMin : -new Date().getTimezoneOffset();\n function convertSlot(s: string): null | Slot {\n return shiftSlot(s, apiOffsetMin, toOffset) ?? parseSlot(s);\n }\n\n const x = model.x_time ?? [];\n const tok = model.tokensUsage ?? [];\n const calls = model.modelCallCount ?? [];\n const nh = x.length;\n\n const tu = model.totalUsage ?? {};\n const total =\n tu.totalTokensUsage != null\n ? tu.totalTokensUsage\n : tok.reduce((a, b) => a + (b || 0), 0);\n const totalCalls =\n tu.totalModelCallCount != null\n ? tu.totalModelCallCount\n : calls.reduce((a, b) => a + (b || 0), 0);\n\n // peak hour\n let peakIdx = -1;\n let peakTok = 0;\n for (let i = 0; i < tok.length; i++) {\n if (tok[i] > peakTok) {\n peakTok = tok[i];\n peakIdx = i;\n }\n }\n const peakCalls = peakIdx >= 0 ? calls[peakIdx] || 0 : 0;\n const pctPeak = total > 0 ? (peakTok / total) * 100 : 0;\n const peakSlot = peakIdx >= 0 ? convertSlot(x[peakIdx]) : null;\n\n const level = quota.level\n ? quota.level.charAt(0).toUpperCase() + quota.level.slice(1)\n : '';\n\n // ---- header ----\n const left = ` GLM Coding Plan${level ? ' · ' + level : ''}`;\n const firstSlot = convertSlot(x[0]);\n const lastSlot = convertSlot(x[nh - 1]);\n const win =\n firstSlot && lastSlot\n ? `${firstSlot.day} ${firstSlot.time} → ${lastSlot.day} ${lastSlot.time} · ${nh}h`\n : platform;\n out.push(rule());\n out.push(left + padL(win, W - left.length));\n out.push(rule());\n\n // ---- lead ----\n let lead = ` ${fmtTokens(total)} tokens across ${fmtNum(totalCalls)} model calls`;\n if (peakIdx >= 0 && peakSlot) {\n lead += ` — ${Math.round(pctPeak)}% of it in a single hour (${peakSlot.day} ${peakSlot.time}, ${fmtTokens(peakTok)} tokens / ${fmtNum(peakCalls)} calls)`;\n }\n lead += '.';\n out.push('');\n out.push(lead);\n\n // ---- stat block ----\n const activeHours = tok.filter(t => t > 0).length;\n const longest = idleRuns(tok)\n .filter(r => r.len >= 2)\n .sort((a, b) => b.len - a.len)\n .at(0);\n const tt = tool.totalUsage ?? {};\n const searchN = tt.totalNetworkSearchCount || 0;\n const readN = tt.totalWebReadMcpCount || 0;\n const zreadN = tt.totalZreadMcpCount || 0;\n const toolTotal =\n tt.totalSearchMcpCount != null\n ? tt.totalSearchMcpCount\n : searchN + readN + zreadN;\n\n // how much of the window's usage fell inside the 3× billing peak hours\n let peakWinActive = 0;\n let peakWinTokens = 0;\n for (let k = 0; k < nh; k++) {\n if (isPeakBucket(x[k]) && tok[k] > 0) {\n peakWinActive++;\n peakWinTokens += tok[k];\n }\n }\n const peakWinPct = total > 0 ? (peakWinTokens / total) * 100 : 0;\n const peakWin = localPeakWindow(apiOffsetMin, toOffset);\n\n out.push('');\n out.push(\n ` Peak ${padR(peakSlot ? peakSlot.day + ' ' + peakSlot.time : '—', 15)}${padL(fmtTokens(peakTok), 7)} tokens · ${padL(fmtNum(peakCalls), 5)} calls`,\n );\n out.push(\n ` Active ${padR(`${activeHours} / ${nh} hours`, 15)}${longest ? idleLabel(longest, x, convertSlot) : 'no idle gaps'}`,\n );\n out.push(\n ` Tools ${padR(`${toolTotal} calls`, 15)}${searchN} searches · ${readN} reads${zreadN ? ` · ${zreadN} zread` : ''}`,\n );\n if (peakWin) {\n out.push(\n ` Peak hrs Mon–Fri ${peakWin.start}–${peakWin.end} · GLM-5.2 3× · ${peakWinActive}h active · ${fmtTokens(peakWinTokens)} (${Math.round(peakWinPct)}%)`,\n );\n }\n\n // ---- hourly chart (vertical bars) ----\n out.push('');\n const chartHdr = ' Hourly tokens · ↑ peak hour ';\n out.push(chartHdr + '─'.repeat(Math.max(0, W - chartHdr.length)));\n const maxTok = peakTok || 1;\n const chartLines = hourlyVerticalChart({\n x,\n tok,\n nh,\n maxTok,\n peakIdx,\n slotFn: convertSlot,\n });\n if (chartLines) {\n out.push(...chartLines);\n if (peakIdx >= 0 && peakSlot) {\n out.push(\n ` ◂ peak ${peakSlot.day} ${peakSlot.time} ${fmtTokens(peakTok)} tokens · ${fmtNum(peakCalls)} calls`,\n );\n }\n } else {\n out.push(' (not enough hourly data to chart)');\n }\n\n // ---- model mix ----\n out.push('');\n out.push(' Model mix ' + '─'.repeat(Math.max(0, W - 11)));\n const mixSrc = model.modelSummaryList ?? model.modelDataList ?? [];\n const denom = mixSrc.reduce((a, m) => a + (m.totalTokens ?? 0), 0) || 1;\n const mixSorted = [...mixSrc].sort(\n (a, b) => (a.sortOrder || 0) - (b.sortOrder || 0),\n );\n for (const m of mixSorted) {\n const pct = ((m.totalTokens ?? 0) / denom) * 100;\n out.push(\n ` ${padR(m.modelName || '?', 11)}${padL(fmtTokens(m.totalTokens), 8)} ${padL(pct.toFixed(1) + '%', 6)} ${barField(pct, 100, 20)}`,\n );\n }\n\n // ---- limits ----\n out.push('');\n out.push(' Limits ' + '─'.repeat(Math.max(0, W - 8)));\n\n // Peak-window row, always present under Limits. The bar is now's progress\n // through the 14:00–18:00 Beijing window: empty before it opens, full after\n // it closes, and no fill on weekends, when the window does not bill. The\n // start/end labels come from peakWin, already shifted to the caller's offset.\n const bj = new Date(now.getTime() + apiOffsetMin * 60000);\n const bjDay = bj.getUTCDay();\n const inWindow = bjDay >= 1 && bjDay <= 5;\n const elapsedMin = inWindow\n ? Math.max(\n 0,\n Math.min(240, (bj.getUTCHours() - 14) * 60 + bj.getUTCMinutes()),\n )\n : 0;\n if (peakWin) {\n out.push(\n ` ${padR('Peak', 16)}${padL(peakWin.start, 5)} ${meter(Math.round((elapsedMin / 240) * 100), 22)} ${peakWin.end}`,\n );\n }\n\n const limits = quota.limits ?? [];\n const mcp = limits.find(l => /mcp/i.test(l.type ?? ''));\n const tok5 = limits.find(l => /token/i.test(l.type ?? ''));\n if (tok5) {\n const reset = new Date(tok5.nextResetTime ?? '').toLocaleTimeString(\n 'en-IN',\n );\n out.push(\n ` ${padR('Tokens · 5h', 16)}${padL(`${tok5.percentage || 0}%`, 5)} ${meter(tok5.percentage, 22)} ${reset}`,\n );\n }\n\n if (tok5 && mcp) {\n out.push('');\n }\n\n if (mcp) {\n const reset = new Date(mcp.nextResetTime ?? '').toLocaleString('en-IN');\n out.push(\n ` ${padR('MCP · this month', 16)}${padL(`${mcp.percentage || 0}%`, 5)} ${meter(mcp.percentage, 22)} ${reset}`,\n );\n const det = mcp.usageDetails ?? [];\n const parts = det\n .map(d => `${friendlyTool(d.modelCode)} ${fmtNum(d.usage)}`)\n .join(' ');\n if (parts) {\n out.push(\n ` ${fmtNum(mcp.currentUsage)}M / ${fmtNum(mcp.totol)}M · ${parts}`,\n );\n }\n }\n\n out.push('');\n out.push(rule());\n return out.join('\\n');\n}\n","/**\n * Usage query. Fetches model usage, tool usage, and quota limits from the GLM\n * Coding Plan monitor API of the resolved base URL (paths are fixed) and\n * renders the plain-text report.\n */\n\nimport type { ZaiModelUsage, ZaiQuota, ZaiToolUsage } from './format.js';\nimport type { ResolvedConfig } from './resolve.js';\n\nimport { render } from './format.js';\n\ninterface RawLimit {\n currentValue?: number;\n nextResetTime?: string;\n percentage?: number;\n type?: string;\n usage?: number;\n usageDetails?: { modelCode?: string; usage?: number }[];\n}\n\ninterface RawQuota {\n level?: string;\n limits?: RawLimit[];\n}\n\n// Auth failures arrive as HTTP 200 with success false.\ninterface RawEnvelope {\n code?: number;\n data?: unknown;\n msg?: string;\n success?: boolean;\n}\n\n// The monitor API labels every bucket in Beijing time; the query window runs\n// from yesterday at the current hour to the end of today's current hour.\nfunction queryParams(now = new Date()): string {\n const startDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() - 1,\n now.getHours(),\n 0,\n 0,\n 0,\n );\n const endDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n now.getHours(),\n 59,\n 59,\n 999,\n );\n function formatDateTime(date: Date): string {\n function p(n: number): string {\n return String(n).padStart(2, '0');\n }\n return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}:${p(date.getSeconds())}`;\n }\n return `?startTime=${encodeURIComponent(formatDateTime(startDate))}&endTime=${encodeURIComponent(formatDateTime(endDate))}`;\n}\n\n// Rename the API's limit kinds to their display names; `totol` is the field the\n// renderer reads (sic — the upstream spelling).\nfunction processQuotaLimit(data: RawQuota): ZaiQuota {\n if (!data.limits) {\n return data;\n }\n data.limits = data.limits.map(item => {\n if (item.type === 'TOKENS_LIMIT') {\n return {\n type: 'Token usage(5 Hour)',\n percentage: item.percentage,\n nextResetTime: item.nextResetTime,\n };\n }\n if (item.type === 'TIME_LIMIT') {\n return {\n type: 'MCP usage(1 Month)',\n percentage: item.percentage,\n currentUsage: item.currentValue,\n totol: item.usage,\n usageDetails: item.usageDetails,\n nextResetTime: item.nextResetTime,\n };\n }\n return item;\n });\n return data;\n}\n\nasync function fetchJson(\n apiUrl: string,\n label: string,\n authToken: string,\n query = '',\n): Promise<unknown> {\n const res = await fetch(apiUrl + query, {\n headers: {\n Authorization: authToken,\n 'Accept-Language': 'en-US,en',\n 'Content-Type': 'application/json',\n },\n });\n const body = await res.text();\n if (res.status !== 200) {\n throw new Error(`[${label}] HTTP ${res.status}\\n${body}`);\n }\n let json: RawEnvelope;\n try {\n json = JSON.parse(body) as RawEnvelope;\n } catch (e) {\n throw new Error(\n `[${label}] could not parse response: ${(e as Error).message}`,\n { cause: e },\n );\n }\n if (json.success === false) {\n throw new Error(\n `[${label}] ${json.msg ?? 'request failed'} (code ${json.code ?? '?'})`,\n );\n }\n return json.data ?? json;\n}\n\nexport async function fetchReport(config: ResolvedConfig): Promise<string> {\n const platform = config.url.includes('bigmodel') ? 'ZHIPU' : 'ZAI';\n\n const query = queryParams();\n try {\n const [model, tool, quotaRaw] = await Promise.all([\n fetchJson(\n `${config.url}/api/monitor/usage/model-usage`,\n 'Model usage',\n config.token,\n query,\n ),\n fetchJson(\n `${config.url}/api/monitor/usage/tool-usage`,\n 'Tool usage',\n config.token,\n query,\n ),\n fetchJson(\n `${config.url}/api/monitor/usage/quota/limit`,\n 'Quota limit',\n config.token,\n ),\n ]);\n return render({\n platform,\n model: model as ZaiModelUsage,\n tool: tool as ZaiToolUsage,\n quota: processQuotaLimit(quotaRaw as RawQuota),\n });\n } catch (e) {\n throw new Error(`Request failed: ${(e as Error).message}`, { cause: e });\n }\n}\n","import { hookOrPrint, printUsageAndExit } from '@v1nvn/agentic-core';\n\nimport { buildProgram, parseArgs, resolveConfig } from './resolve.js';\nimport { fetchReport } from './usage.js';\n\nconst parsed =\n parseArgs(process.argv.slice(2)) ?? printUsageAndExit(buildProgram());\n\nawait hookOrPrint(parsed.hook, 'query failed', () =>\n fetchReport(resolveConfig(process.env, parsed)),\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../core/dist/index.js","../src/resolve.ts","../src/format.ts","../src/usage.ts","../src/index.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n//#region src/input.ts\nfunction readAll(stream) {\n\treturn new Promise((resolve, reject) => {\n\t\tlet data = \"\";\n\t\tstream.setEncoding(\"utf8\");\n\t\tstream.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tstream.on(\"end\", () => {\n\t\t\tresolve(data);\n\t\t});\n\t\tstream.on(\"error\", reject);\n\t});\n}\nfunction readStdin(stream = process.stdin) {\n\treturn readAll(stream);\n}\n/** A markdown file's contents, with the CLI's no-such-file error. */\nfunction readMarkdownFile(path) {\n\tif (!statSync(path, { throwIfNoEntry: false })?.isFile()) throw new Error(`no such file: ${path}`);\n\treturn readFileSync(path, \"utf8\");\n}\n//#endregion\n//#region src/hook.ts\n/**\n* Read the Claude Code hook event JSON from stdin; empty or unparseable input\n* yields an empty event, never a thrown error — a hook must always answer.\n*/\nfunction readHookEvent(stream = process.stdin) {\n\treturn readAll(stream).then((data) => {\n\t\ttry {\n\t\t\treturn JSON.parse(data);\n\t\t} catch {\n\t\t\treturn {};\n\t\t}\n\t}, () => ({}));\n}\n/**\n* Which transcript lastReply should read, per the hook event: transcript_path\n* when it names a real file, else session_id, else nothing (lastReply then\n* falls back to the newest session for the current project).\n*/\nfunction replyTarget(event) {\n\tif (event.transcript_path !== void 0 && isFile(event.transcript_path)) return event.transcript_path;\n\treturn event.session_id || void 0;\n}\nfunction isFile(path) {\n\ttry {\n\t\treturn statSync(path).isFile();\n\t} catch {\n\t\treturn false;\n\t}\n}\n/**\n* Print the UserPromptExpansion decision for a zero-token command: `block`\n* keeps the command from reaching the model, with the output as the `reason`.\n*/\nfunction emitHookBlock(reason) {\n\tprocess.stdout.write(`${JSON.stringify({\n\t\tdecision: \"block\",\n\t\treason\n\t})}\\n`);\n}\n//#endregion\n//#region src/cli.ts\nfunction parseQuietly(program, args, recover) {\n\ttry {\n\t\tprogram.allowExcessArguments(false).exitOverride().configureOutput({\n\t\t\twriteOut: () => void 0,\n\t\t\twriteErr: () => void 0\n\t\t}).parse([...args], { from: \"user\" });\n\t\treturn program;\n\t} catch (err) {\n\t\treturn recover?.(err);\n\t}\n}\nfunction printUsageAndExit(program) {\n\tconsole.error(program.helpInformation());\n\tprocess.exit(1);\n}\nasync function hookOrPrint(hook, failure, run, stdin = process.stdin) {\n\tif (hook) {\n\t\tlet reason;\n\t\ttry {\n\t\t\treason = await run(await readHookEvent(stdin));\n\t\t} catch (e) {\n\t\t\treason = `${failure}: ${e.message}`;\n\t\t}\n\t\temitHookBlock(reason);\n\t\treturn;\n\t}\n\ttry {\n\t\tconsole.log(await run(void 0));\n\t} catch (e) {\n\t\tconsole.error(e.message);\n\t\tprocess.exit(1);\n\t}\n}\n//#endregion\n//#region src/dev.ts\nvar RELOAD_DEBOUNCE_MS = 150;\nvar IGNORED_SEGMENTS = [\n\t\"/node_modules/\",\n\t\"/dist/\",\n\t\"/.git/\",\n\t\"/coverage/\"\n];\nfunction shouldReload(file) {\n\treturn IGNORED_SEGMENTS.every((seg) => !file.includes(seg));\n}\n/**\n* Debounced file-change reloads, serialized via a promise chain: concurrent\n* saves never overlap, and a mid-reload save still produces a follow-up.\n*/\nfunction watchWithReload(vite, reload) {\n\tlet chain = Promise.resolve();\n\tlet timer;\n\tvite.watcher.on(\"change\", (file) => {\n\t\tif (!shouldReload(file)) return;\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = void 0;\n\t\t\tchain = chain.then(reload);\n\t\t}, RELOAD_DEBOUNCE_MS);\n\t});\n}\n//#endregion\n//#region src/last-reply.ts\nfunction textBlocks(entry) {\n\tconst content = entry.message?.content;\n\tif (entry.type !== \"assistant\" || !Array.isArray(content)) return;\n\tconst blocks = content.filter((b) => typeof b === \"object\" && b !== null && b.type === \"text\");\n\treturn blocks.length > 0 ? blocks : void 0;\n}\nfunction claudeProjectsDir() {\n\tconst claudeDir = process.env.CLAUDE_DIR ?? join(homedir(), \".claude\");\n\treturn join(claudeDir, \"projects\");\n}\n/**\n* The last assistant text reply from a Claude Code session, reproducing Claude\n* Code's `/copy` byte-for-byte: the last assistant entry that contains a\n* `text` block, only its `text` block(s) (tool_use / thinking dropped), blocks\n* joined with a blank line, and no trailing newline.\n*\n* @param arg a transcript file, a session UUID under the project dir, or\n* nothing to use the newest session for the current project.\n*/\nfunction lastReply(arg) {\n\tconst proj = (process.env.CLAUDE_PROJECT_DIR ?? process.cwd()).replaceAll(\"/\", \"-\");\n\tconst projDir = join(claudeProjectsDir(), proj);\n\tlet file;\n\tif (arg !== void 0) file = isFile(arg) ? arg : join(projDir, `${arg}.jsonl`);\n\telse if (existsSync(projDir)) {\n\t\tconst newest = readdirSync(projDir).filter((f) => f.endsWith(\".jsonl\")).map((f) => ({\n\t\t\tf,\n\t\t\tmtimeMs: statSync(join(projDir, f)).mtimeMs\n\t\t})).sort((a, b) => b.mtimeMs - a.mtimeMs).at(0);\n\t\tif (newest) file = join(projDir, newest.f);\n\t}\n\tif (file === void 0 || !isFile(file)) throw new Error(`no session transcript found in ${projDir}`);\n\tlet last;\n\tfor (const line of readFileSync(file, \"utf8\").split(\"\\n\")) {\n\t\tif (!line.includes(\"\\\"assistant\\\"\")) continue;\n\t\tlet entry;\n\t\ttry {\n\t\t\tentry = JSON.parse(line);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst blocks = textBlocks(entry);\n\t\tif (blocks) last = blocks;\n\t}\n\treturn (last ?? []).map((b) => b.text ?? \"\").join(\"\\n\\n\");\n}\n//#endregion\n//#region src/logger.ts\nvar LEVEL_RANK = {\n\tdebug: 10,\n\tinfo: 20,\n\twarn: 30,\n\terror: 40,\n\tsilent: Number.MAX_SAFE_INTEGER\n};\nfunction levelEnabled(active, wanted) {\n\treturn LEVEL_RANK[wanted] >= LEVEL_RANK[active];\n}\nvar LEVEL_LABEL = {\n\tdebug: \"DEBUG\",\n\terror: \"ERROR\",\n\tinfo: \"INFO\",\n\twarn: \"WARN\"\n};\nvar Logger = class {\n\tactiveLevel;\n\tstderr;\n\tconstructor(activeLevel, stderr = (line) => process.stderr.write(`${line}\\n`)) {\n\t\tthis.activeLevel = activeLevel;\n\t\tthis.stderr = stderr;\n\t}\n\tdebug(message) {\n\t\tthis.log(\"debug\", message);\n\t}\n\terror(message) {\n\t\tthis.log(\"error\", message);\n\t}\n\tinfo(message) {\n\t\tthis.log(\"info\", message);\n\t}\n\twarn(message) {\n\t\tthis.log(\"warn\", message);\n\t}\n\tlog(level, message) {\n\t\tif (levelEnabled(this.activeLevel, level)) this.stderr(`${LEVEL_LABEL[level]} ${message}`);\n\t}\n};\n//#endregion\n//#region src/shutdown.ts\n/** Close each closable in order (best-effort), then force-exit. */\nfunction shutdownOnSignals(closables, signals = [\"SIGINT\", \"SIGTERM\"]) {\n\tconst shutdown = () => {\n\t\tclosables.reduce((acc, closable) => acc.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait closable.close();\n\t\t\t} catch {}\n\t\t}), Promise.resolve()).finally(() => {\n\t\t\tprocess.exit(0);\n\t\t});\n\t};\n\tfor (const signal of signals) process.on(signal, shutdown);\n}\n//#endregion\n//#region src/text-format.ts\n/**\n* Plain-text rendering primitives shared by the zai and tokens report\n* renderers. Output targets a monospace terminal / hook-block `reason`, so\n* everything here is fixed-width: padding, block-glyph bars, and compact\n* number formatting.\n*/\nvar MONTHS = [\n\t\"Jan\",\n\t\"Feb\",\n\t\"Mar\",\n\t\"Apr\",\n\t\"May\",\n\t\"Jun\",\n\t\"Jul\",\n\t\"Aug\",\n\t\"Sep\",\n\t\"Oct\",\n\t\"Nov\",\n\t\"Dec\"\n];\nvar EIGHTHS = [\n\t\"\",\n\t\"▏\",\n\t\"▎\",\n\t\"▍\",\n\t\"▌\",\n\t\"▋\",\n\t\"▊\",\n\t\"▉\"\n];\nvar RULE_WIDTH = 68;\nfunction rule() {\n\treturn \"─\".repeat(68);\n}\nfunction pad2(n) {\n\treturn String(n).padStart(2, \"0\");\n}\n/** Local-time `YYYY-MM-DD` key. */\nfunction ymd(date) {\n\treturn `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n}\nfunction fmtTokens(n) {\n\tif (n == null || Number.isNaN(n)) return \"—\";\n\tif (n >= 1e9) return (n / 1e9).toFixed(1) + \"B\";\n\tif (n >= 1e6) return (n / 1e6).toFixed(1) + \"M\";\n\tif (n >= 1e3) return (n / 1e3).toFixed(1) + \"K\";\n\treturn String(n);\n}\nfunction fmtNum(n) {\n\treturn (n || 0).toLocaleString(\"en-US\");\n}\nfunction padR(s, n) {\n\treturn s.length >= n ? s : s + \" \".repeat(n - s.length);\n}\nfunction padL(s, n) {\n\treturn s.length >= n ? s : \" \".repeat(n - s.length) + s;\n}\n/** Fixed-width bar field (width cols): █ blocks + an eighth-fraction + trailing spaces. */\nfunction barField(v, max, width) {\n\tif (!v || v <= 0 || max <= 0) return \" \".repeat(width);\n\tconst scaled = v / max * width;\n\tlet full = Math.floor(scaled);\n\tlet fi = Math.round((scaled - full) * 8);\n\tif (fi === 8) {\n\t\tfull += 1;\n\t\tfi = 0;\n\t}\n\tif (full === 0 && fi === 0) fi = 1;\n\tlet s = \"█\".repeat(Math.min(full, width));\n\tif (full < width && fi > 0) s += EIGHTHS[fi];\n\tif (s.length < width) s += \" \".repeat(width - s.length);\n\treturn s.slice(0, width);\n}\n/** Filled/empty meter: █ for used, ░ for remaining. */\nfunction meter(pct, width) {\n\tlet filled = Math.round((pct || 0) / 100 * width);\n\tfilled = Math.max(0, Math.min(width, filled));\n\treturn \"█\".repeat(filled) + \"░\".repeat(width - filled);\n}\n//#endregion\nexport { Logger, MONTHS, RULE_WIDTH, barField, claudeProjectsDir, emitHookBlock, fmtNum, fmtTokens, hookOrPrint, isFile, lastReply, levelEnabled, meter, pad2, padL, padR, parseQuietly, printUsageAndExit, readAll, readHookEvent, readMarkdownFile, readStdin, replyTarget, rule, shutdownOnSignals, watchWithReload, ymd };\n\n//# sourceMappingURL=index.js.map","import { parseQuietly } from '@v1nvn/agentic-core';\nimport { Command, Option } from 'commander';\n\nconst DEFAULT_BASE_URL = 'https://api.z.ai';\n\nconst GLM_HOSTS = new Set(['api.z.ai', 'dev.bigmodel.cn', 'open.bigmodel.cn']);\n\nexport interface ParsedArgs {\n readonly authToken: string | undefined;\n readonly baseUrl: string | undefined;\n readonly hook: boolean;\n}\n\nexport interface ResolvedConfig {\n readonly token: string;\n readonly url: string;\n}\n\ninterface BaseUrl {\n readonly glm: boolean;\n readonly origin: string;\n}\n\nfunction fromEnv(value: string | undefined): string | undefined {\n return value ? value : undefined;\n}\n\nfunction originOf(value: string): string | undefined {\n try {\n const url = new URL(value);\n return url.protocol === 'https:' || url.protocol === 'http:'\n ? url.origin\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isGlm(origin: string): boolean {\n return GLM_HOSTS.has(new URL(origin).hostname);\n}\n\nfunction resolveBaseUrl(\n flag: string | undefined,\n env: NodeJS.ProcessEnv,\n): BaseUrl {\n if (flag !== undefined) {\n const origin = originOf(flag);\n if (origin === undefined) {\n throw new Error(`invalid base URL: ${flag}`);\n }\n return { glm: isGlm(origin), origin };\n }\n const inherited = fromEnv(env.ANTHROPIC_BASE_URL);\n const origin = inherited === undefined ? undefined : originOf(inherited);\n if (origin !== undefined && isGlm(origin)) {\n return { glm: true, origin };\n }\n return { glm: false, origin: DEFAULT_BASE_URL };\n}\n\nexport function buildProgram(): Command {\n return new Command()\n .name('zai-usage')\n .addOption(\n new Option('--auth-token <token>', 'API key').env('ZAI_AUTH_TOKEN'),\n )\n .addOption(new Option('--base-url <url>', 'base URL').env('ZAI_BASE_URL'))\n .option('--hook', 'emit a UserPromptExpansion block instead of printing');\n}\n\nexport function parseArgs(args: readonly string[]): ParsedArgs | undefined {\n const program = parseQuietly(buildProgram(), args);\n if (program === undefined) {\n return undefined;\n }\n const { authToken, baseUrl, hook } = program.opts<{\n authToken: string | undefined;\n baseUrl: string | undefined;\n hook: boolean | undefined;\n }>();\n return {\n authToken: authToken || undefined,\n baseUrl: baseUrl || undefined,\n hook: hook ?? false,\n };\n}\n\nexport function resolveConfig(\n env: NodeJS.ProcessEnv,\n parsed: ParsedArgs,\n): ResolvedConfig {\n const base = resolveBaseUrl(parsed.baseUrl, env);\n const token =\n parsed.authToken ??\n (base.glm ? fromEnv(env.ANTHROPIC_AUTH_TOKEN) : undefined);\n if (token === undefined) {\n throw new Error(\n env.ANTHROPIC_AUTH_TOKEN\n ? 'ANTHROPIC_AUTH_TOKEN is set, but the resolved base URL does not name a GLM host, so it is not a GLM Coding Plan token — set ZAI_AUTH_TOKEN (or --auth-token)'\n : 'no API key: set ZAI_AUTH_TOKEN (or --auth-token)',\n );\n }\n return { token, url: base.origin };\n}\n","/**\n * Plain-text usage report renderer.\n *\n * Rendered for a monospace terminal / hook-block `reason`, so it must NOT rely on\n * markdown (bold, tables, fenced code). Alignment comes from fixed-width columns\n * and unicode block glyphs. Input is the parsed `data` of the three ZAI/ZHIPU\n * monitor endpoints (model-usage, tool-usage, quota/limit — the last already\n * passed through processQuotaLimit).\n */\n\nimport {\n barField,\n fmtNum,\n fmtTokens,\n meter,\n MONTHS,\n pad2,\n padL,\n padR,\n rule,\n RULE_WIDTH,\n} from '@v1nvn/agentic-core';\n\n// Lower-half block eighths for vertical bars (1/8 .. 7/8); a full cell uses '█'.\nconst VBLOCKS = '▁▂▃▄▅▆▇';\n\nexport interface ModelMixEntry {\n modelName?: string;\n sortOrder?: number;\n totalTokens?: number;\n}\n\nexport interface ZaiModelUsage {\n modelCallCount?: number[];\n modelDataList?: ModelMixEntry[];\n modelSummaryList?: ModelMixEntry[];\n tokensUsage?: number[];\n totalUsage?: { totalModelCallCount?: number; totalTokensUsage?: number };\n x_time?: string[];\n}\n\nexport interface ZaiToolUsage {\n totalUsage?: {\n totalNetworkSearchCount?: number;\n totalSearchMcpCount?: number;\n totalWebReadMcpCount?: number;\n totalZreadMcpCount?: number;\n };\n}\n\nexport interface ZaiQuotaLimit {\n currentUsage?: number;\n nextResetTime?: string;\n percentage?: number;\n totol?: number;\n type?: string;\n usageDetails?: { modelCode?: string; usage?: number }[];\n}\n\nexport interface ZaiQuota {\n level?: string;\n limits?: ZaiQuotaLimit[];\n}\n\nexport interface RenderInput {\n apiOffsetMin?: number;\n localOffsetMin?: number;\n model: ZaiModelUsage;\n now?: Date;\n platform: string;\n quota: ZaiQuota;\n tool: ZaiToolUsage;\n}\n\ninterface Slot {\n day: string;\n h: number;\n time: string;\n}\n\nfunction parseSlot(s: string | undefined): null | Slot {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2})/.exec(s ?? '');\n if (!m) {\n return null;\n }\n return {\n h: +m[4],\n day: `${MONTHS[+m[2] - 1]} ${m[3]}`,\n time: `${m[4]}:${m[5]}`,\n };\n}\n\n/**\n * Re-express a naive \"YYYY-MM-DD HH:MM\" string from one UTC offset to another.\n * Offsets are minutes east of UTC (Beijing = 480, IST = 330). Pure — does not\n * depend on the runtime timezone, so it is deterministic under test.\n */\nfunction shiftSlot(\n s: string,\n fromOffsetMin: number,\n toOffsetMin: number,\n): null | Slot {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2})/.exec(s);\n if (!m) {\n return null;\n }\n const utcMs =\n Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5]) - fromOffsetMin * 60000;\n const dt = new Date(utcMs + toOffsetMin * 60000);\n return {\n h: dt.getUTCHours(),\n day: `${MONTHS[dt.getUTCMonth()]} ${pad2(dt.getUTCDate())}`,\n time: `${pad2(dt.getUTCHours())}:${pad2(dt.getUTCMinutes())}`,\n };\n}\n\nfunction friendlyTool(code: string | undefined): string {\n switch ((code ?? '').toLowerCase()) {\n case 'search-prime':\n return 'web search';\n case 'web-reader':\n return 'web read';\n default:\n return code || 'other';\n }\n}\n\nfunction idleRuns(tok: number[]): { i: number; j: number; len: number }[] {\n const runs: { i: number; j: number; len: number }[] = [];\n let i = 0;\n while (i < tok.length) {\n if ((tok[i] || 0) === 0) {\n let j = i;\n while (j < tok.length && (tok[j] || 0) === 0) {\n j++;\n }\n runs.push({ i, j: j - 1, len: j - i });\n i = j;\n } else {\n i++;\n }\n }\n return runs;\n}\n\nfunction idleLabel(\n run: { i: number; j: number; len: number },\n x: string[],\n slotFn: (s: string) => null | Slot,\n): string {\n const a = slotFn(x[run.i]);\n const b = slotFn(x[run.j]);\n if (!a || !b) {\n return `idle (${run.len}h)`;\n }\n const start = `${a.day} ${a.time}`;\n const end = a.day === b.day ? b.time : `${b.day} ${b.time}`;\n return `idle ${start} → ${end} (${run.len}h)`;\n}\n\n// Per the usage-revision notice: Mon–Fri 14:00–18:00 Beijing (UTC+8) are peak\n// hours, where GLM-5.2 / GLM-5-Turbo tokens are billed at a 3× coefficient\n// (GLM-4.7 stays 1× all day). A bucket labelled \"HH:00\" spans HH:00–HH+1, so\n// the peak buckets are HH ∈ {14,15,16,17} on a weekday.\nfunction isPeakBucket(s: string | undefined): boolean {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):/.exec(s ?? '');\n if (!m) {\n return false;\n }\n const wd = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3])).getUTCDay(); // 0=Sun … 6=Sat\n return wd >= 1 && wd <= 5 && +m[4] >= 14 && +m[4] <= 17;\n}\n\n/** Local-time start/end of the 14:00–18:00 Beijing peak window (e.g. 11:30 / 15:30). */\nfunction localPeakWindow(\n apiOffsetMin: number,\n toOffsetMin: number,\n): null | { end: string; start: string } {\n const a = shiftSlot('2000-01-03 14:00', apiOffsetMin, toOffsetMin);\n const b = shiftSlot('2000-01-03 18:00', apiOffsetMin, toOffsetMin);\n if (!a || !b) {\n return null;\n }\n return { start: a.time, end: b.time };\n}\n\n/**\n * Vertical bar chart of hourly tokens. Returns an array of plain-text lines\n * (without the section header), or null if there are fewer than 2 buckets.\n *\n * Bars are scaled to `maxTok` across `ROWS` rows; the topmost filled cell of a\n * bar uses a fractional lower-block glyph (▁▂▃▄▅▆▇) for sub-row height. The\n * y-axis labels only the peak (top) and 0 (baseline); the header window and the\n * caller's peak annotation carry the exact values.\n */\nfunction hourlyVerticalChart({\n x,\n tok,\n nh,\n maxTok,\n peakIdx,\n slotFn,\n}: {\n maxTok: number;\n nh: number;\n peakIdx: number;\n slotFn: (s: string) => null | Slot;\n tok: number[];\n x: string[];\n}): null | string[] {\n const ROWS = 6; // bar rows above the baseline\n if (nh < 2 || maxTok <= 0) {\n return null;\n }\n\n const lines: string[] = [];\n const maxLab = fmtTokens(maxTok);\n const L = maxLab.length;\n const IND = 1; // leading indent\n const AXIS = IND + L + 1; // axis spine col (1-space gap after the label)\n const P0 = AXIS + 2; // first bar column (axis + 1-char gap)\n const PW = RULE_WIDTH - P0; // columns available for bars + gaps\n const slot = Math.max(1, Math.floor(PW / nh));\n const barW = slot >= 2 ? slot - 1 : 1;\n function barLeft(i: number): number {\n return P0 + i * slot;\n }\n function barCenter(i: number): number {\n return barLeft(i) + Math.floor(barW / 2);\n }\n const usedCols = nh * slot;\n function blank(): string[] {\n return Array<string>(RULE_WIDTH).fill(' ');\n }\n\n // bar glyph for hour i at row r (0 = bottom bar-row, ROWS-1 = top)\n function glyph(i: number, r: number): string {\n const v = tok[i] || 0;\n if (v <= 0) {\n return ' ';\n }\n const fill = (v / maxTok) * ROWS - r; // how much of row r the bar covers\n if (fill >= 1) {\n return '█';\n }\n if (fill > 0) {\n let e = Math.round(fill * 8); // 1..7 eighths\n if (e < 1) {\n e = 1;\n }\n if (e > 7) {\n e = 7;\n }\n return VBLOCKS[e - 1];\n }\n return ' ';\n }\n\n // bar rows, top → bottom; top row carries the max label + '┤', rest are '│'\n for (let r = ROWS - 1; r >= 0; r--) {\n const line = blank();\n line[AXIS] = r === ROWS - 1 ? '┤' : '│';\n if (r === ROWS - 1) {\n for (let k = 0; k < L; k++) {\n line[AXIS - 1 - L + k] = maxLab[k];\n }\n }\n for (let i = 0; i < nh; i++) {\n const g = glyph(i, r);\n if (g !== ' ') {\n for (let c = 0; c < barW; c++) {\n line[barLeft(i) + c] = g;\n }\n }\n }\n lines.push(line.join('').trimEnd());\n }\n\n // x-axis ticks: first, last, and every bucket landing on a 6h boundary (local)\n function slotOf(i: number): null | Slot {\n return slotFn(x[i]);\n }\n function isTick(i: number): boolean {\n if (i === 0 || i === nh - 1) {\n return true;\n }\n const s = slotOf(i);\n return !!s && s.h % 6 === 0;\n }\n\n // baseline: '0' label + corner '└' + '─' run, with '┬' under each tick\n const base = blank();\n base[AXIS - 2] = '0';\n base[AXIS] = '└';\n for (let c = AXIS + 1; c < P0 + usedCols; c++) {\n base[c] = '─';\n }\n for (let i = 0; i < nh; i++) {\n if (isTick(i)) {\n base[barCenter(i)] = '┬';\n }\n }\n lines.push(base.join('').trimEnd());\n\n // hour labels under ticks (skip if too close to the previous label)\n const hr = blank();\n let last = -10;\n for (let i = 0; i < nh; i++) {\n if (!isTick(i)) {\n continue;\n }\n const col = barCenter(i);\n if (col - last < 3) {\n continue;\n }\n const s = slotOf(i);\n const txt = s ? pad2(s.h) : ' ';\n hr[col] = txt[0];\n hr[col + 1] = txt[1];\n last = col;\n }\n lines.push(hr.join('').trimEnd());\n\n // day labels under the first tick of each new local day\n const day = blank();\n let lastDay: null | string = null;\n last = -10;\n for (let i = 0; i < nh; i++) {\n if (!isTick(i)) {\n continue;\n }\n const s = slotOf(i);\n if (!s || s.day === lastDay) {\n continue;\n }\n const col = barCenter(i);\n if (col - last >= s.day.length && col + s.day.length <= RULE_WIDTH) {\n for (let k = 0; k < s.day.length; k++) {\n day[col + k] = s.day[k];\n }\n lastDay = s.day;\n last = col + s.day.length;\n }\n }\n if (day.some(c => c !== ' ')) {\n lines.push(day.join('').trimEnd());\n }\n\n // peak-window (↑) and peak (◂) markers under bar centers\n const mark = blank();\n for (let i = 0; i < nh; i++) {\n if (isPeakBucket(x[i])) {\n mark[barCenter(i)] = '↑';\n }\n }\n if (peakIdx >= 0) {\n mark[barCenter(peakIdx)] = '◂';\n }\n if (mark.some(c => c !== ' ')) {\n lines.push(mark.join('').trimEnd());\n }\n\n return lines;\n}\n\nexport function render({\n platform,\n model,\n tool,\n quota,\n apiOffsetMin = 480,\n localOffsetMin,\n now = new Date(),\n}: RenderInput): string {\n const out: string[] = [];\n\n // The monitor API labels every bucket in Beijing time (UTC+8). Shift each\n // timestamp to the caller's offset (minutes east of UTC) for display.\n // Defaults to the JS runtime's local zone.\n const toOffset =\n localOffsetMin != null ? localOffsetMin : -new Date().getTimezoneOffset();\n function convertSlot(s: string): null | Slot {\n return shiftSlot(s, apiOffsetMin, toOffset) ?? parseSlot(s);\n }\n\n const x = model.x_time ?? [];\n const tok = model.tokensUsage ?? [];\n const calls = model.modelCallCount ?? [];\n const nh = x.length;\n\n const tu = model.totalUsage ?? {};\n const total =\n tu.totalTokensUsage != null\n ? tu.totalTokensUsage\n : tok.reduce((a, b) => a + (b || 0), 0);\n const totalCalls =\n tu.totalModelCallCount != null\n ? tu.totalModelCallCount\n : calls.reduce((a, b) => a + (b || 0), 0);\n\n // peak hour\n let peakIdx = -1;\n let peakTok = 0;\n for (let i = 0; i < tok.length; i++) {\n if (tok[i] > peakTok) {\n peakTok = tok[i];\n peakIdx = i;\n }\n }\n const peakCalls = peakIdx >= 0 ? calls[peakIdx] || 0 : 0;\n const pctPeak = total > 0 ? (peakTok / total) * 100 : 0;\n const peakSlot = peakIdx >= 0 ? convertSlot(x[peakIdx]) : null;\n\n const level = quota.level\n ? quota.level.charAt(0).toUpperCase() + quota.level.slice(1)\n : '';\n\n const left = ` GLM Coding Plan${level ? ' · ' + level : ''}`;\n const firstSlot = convertSlot(x[0]);\n const lastSlot = convertSlot(x[nh - 1]);\n const win =\n firstSlot && lastSlot\n ? `${firstSlot.day} ${firstSlot.time} → ${lastSlot.day} ${lastSlot.time} · ${nh}h`\n : platform;\n out.push(rule());\n out.push(left + padL(win, RULE_WIDTH - left.length));\n out.push(rule());\n\n let lead = ` ${fmtTokens(total)} tokens across ${fmtNum(totalCalls)} model calls`;\n if (peakIdx >= 0 && peakSlot) {\n lead += ` — ${Math.round(pctPeak)}% of it in a single hour (${peakSlot.day} ${peakSlot.time}, ${fmtTokens(peakTok)} tokens / ${fmtNum(peakCalls)} calls)`;\n }\n lead += '.';\n out.push('');\n out.push(lead);\n\n const activeHours = tok.filter(t => t > 0).length;\n const longest = idleRuns(tok)\n .filter(r => r.len >= 2)\n .sort((a, b) => b.len - a.len)\n .at(0);\n const tt = tool.totalUsage ?? {};\n const searchN = tt.totalNetworkSearchCount || 0;\n const readN = tt.totalWebReadMcpCount || 0;\n const zreadN = tt.totalZreadMcpCount || 0;\n const toolTotal =\n tt.totalSearchMcpCount != null\n ? tt.totalSearchMcpCount\n : searchN + readN + zreadN;\n\n // how much of the window's usage fell inside the 3× billing peak hours\n let peakWinActive = 0;\n let peakWinTokens = 0;\n for (let k = 0; k < nh; k++) {\n if (isPeakBucket(x[k]) && tok[k] > 0) {\n peakWinActive++;\n peakWinTokens += tok[k];\n }\n }\n const peakWinPct = total > 0 ? (peakWinTokens / total) * 100 : 0;\n const peakWin = localPeakWindow(apiOffsetMin, toOffset);\n\n out.push('');\n out.push(\n ` Peak ${padR(peakSlot ? peakSlot.day + ' ' + peakSlot.time : '—', 15)}${padL(fmtTokens(peakTok), 7)} tokens · ${padL(fmtNum(peakCalls), 5)} calls`,\n );\n out.push(\n ` Active ${padR(`${activeHours} / ${nh} hours`, 15)}${longest ? idleLabel(longest, x, convertSlot) : 'no idle gaps'}`,\n );\n out.push(\n ` Tools ${padR(`${toolTotal} calls`, 15)}${searchN} searches · ${readN} reads${zreadN ? ` · ${zreadN} zread` : ''}`,\n );\n if (peakWin) {\n out.push(\n ` Peak hrs Mon–Fri ${peakWin.start}–${peakWin.end} · GLM-5.2 3× · ${peakWinActive}h active · ${fmtTokens(peakWinTokens)} (${Math.round(peakWinPct)}%)`,\n );\n }\n\n out.push('');\n const chartHdr = ' Hourly tokens · ↑ peak hour ';\n out.push(chartHdr + '─'.repeat(Math.max(0, RULE_WIDTH - chartHdr.length)));\n const maxTok = peakTok || 1;\n const chartLines = hourlyVerticalChart({\n x,\n tok,\n nh,\n maxTok,\n peakIdx,\n slotFn: convertSlot,\n });\n if (chartLines) {\n out.push(...chartLines);\n if (peakIdx >= 0 && peakSlot) {\n out.push(\n ` ◂ peak ${peakSlot.day} ${peakSlot.time} ${fmtTokens(peakTok)} tokens · ${fmtNum(peakCalls)} calls`,\n );\n }\n } else {\n out.push(' (not enough hourly data to chart)');\n }\n\n out.push('');\n out.push(' Model mix ' + '─'.repeat(Math.max(0, RULE_WIDTH - 11)));\n const mixSrc = model.modelSummaryList ?? model.modelDataList ?? [];\n const denom = mixSrc.reduce((a, m) => a + (m.totalTokens ?? 0), 0) || 1;\n const mixSorted = [...mixSrc].sort(\n (a, b) => (a.sortOrder || 0) - (b.sortOrder || 0),\n );\n for (const m of mixSorted) {\n const pct = ((m.totalTokens ?? 0) / denom) * 100;\n out.push(\n ` ${padR(m.modelName || '?', 11)}${padL(fmtTokens(m.totalTokens), 8)} ${padL(pct.toFixed(1) + '%', 6)} ${barField(pct, 100, 20)}`,\n );\n }\n\n out.push('');\n out.push(' Limits ' + '─'.repeat(Math.max(0, RULE_WIDTH - 8)));\n\n // Peak-window row, always present under Limits. The bar is now's progress\n // through the 14:00–18:00 Beijing window: empty before it opens, full after\n // it closes, and no fill on weekends, when the window does not bill. The\n // start/end labels come from peakWin, already shifted to the caller's offset.\n const bj = new Date(now.getTime() + apiOffsetMin * 60000);\n const bjDay = bj.getUTCDay();\n const inWindow = bjDay >= 1 && bjDay <= 5;\n const elapsedMin = inWindow\n ? Math.max(\n 0,\n Math.min(240, (bj.getUTCHours() - 14) * 60 + bj.getUTCMinutes()),\n )\n : 0;\n if (peakWin) {\n out.push(\n ` ${padR('Peak', 16)}${padL(peakWin.start, 5)} ${meter(Math.round((elapsedMin / 240) * 100), 22)} ${peakWin.end}`,\n );\n }\n\n const limits = quota.limits ?? [];\n const mcp = limits.find(l => /mcp/i.test(l.type ?? ''));\n const tok5 = limits.find(l => /token/i.test(l.type ?? ''));\n if (tok5) {\n const reset = new Date(tok5.nextResetTime ?? '').toLocaleTimeString(\n 'en-IN',\n );\n out.push(\n ` ${padR('Tokens · 5h', 16)}${padL(`${tok5.percentage || 0}%`, 5)} ${meter(tok5.percentage, 22)} ${reset}`,\n );\n }\n\n if (tok5 && mcp) {\n out.push('');\n }\n\n if (mcp) {\n const reset = new Date(mcp.nextResetTime ?? '').toLocaleString('en-IN');\n out.push(\n ` ${padR('MCP · this month', 16)}${padL(`${mcp.percentage || 0}%`, 5)} ${meter(mcp.percentage, 22)} ${reset}`,\n );\n const det = mcp.usageDetails ?? [];\n const parts = det\n .map(d => `${friendlyTool(d.modelCode)} ${fmtNum(d.usage)}`)\n .join(' ');\n if (parts) {\n out.push(\n ` ${fmtNum(mcp.currentUsage)}M / ${fmtNum(mcp.totol)}M · ${parts}`,\n );\n }\n }\n\n out.push('');\n out.push(rule());\n return out.join('\\n');\n}\n","/**\n * Usage query. Fetches model usage, tool usage, and quota limits from the GLM\n * Coding Plan monitor API of the resolved base URL (paths are fixed) and\n * renders the plain-text report.\n */\n\nimport { pad2 } from '@v1nvn/agentic-core';\n\nimport type { ZaiModelUsage, ZaiQuota, ZaiToolUsage } from './format.js';\nimport type { ResolvedConfig } from './resolve.js';\n\nimport { render } from './format.js';\n\ninterface RawLimit {\n currentValue?: number;\n nextResetTime?: string;\n percentage?: number;\n type?: string;\n usage?: number;\n usageDetails?: { modelCode?: string; usage?: number }[];\n}\n\ninterface RawQuota {\n level?: string;\n limits?: RawLimit[];\n}\n\n// Auth failures arrive as HTTP 200 with success false.\ninterface RawEnvelope {\n code?: number;\n data?: unknown;\n msg?: string;\n success?: boolean;\n}\n\n// The monitor API labels every bucket in Beijing time; the query window runs\n// from yesterday at the current hour to the end of today's current hour.\nfunction queryParams(now = new Date()): string {\n const startDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() - 1,\n now.getHours(),\n 0,\n 0,\n 0,\n );\n const endDate = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n now.getHours(),\n 59,\n 59,\n 999,\n );\n function formatDateTime(date: Date): string {\n return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`;\n }\n return `?startTime=${encodeURIComponent(formatDateTime(startDate))}&endTime=${encodeURIComponent(formatDateTime(endDate))}`;\n}\n\n// Rename the API's limit kinds to their display names; `totol` is the field the\n// renderer reads (sic — the upstream spelling).\nfunction processQuotaLimit(data: RawQuota): ZaiQuota {\n if (!data.limits) {\n return data;\n }\n data.limits = data.limits.map(item => {\n if (item.type === 'TOKENS_LIMIT') {\n return {\n type: 'Token usage(5 Hour)',\n percentage: item.percentage,\n nextResetTime: item.nextResetTime,\n };\n }\n if (item.type === 'TIME_LIMIT') {\n return {\n type: 'MCP usage(1 Month)',\n percentage: item.percentage,\n currentUsage: item.currentValue,\n totol: item.usage,\n usageDetails: item.usageDetails,\n nextResetTime: item.nextResetTime,\n };\n }\n return item;\n });\n return data;\n}\n\nasync function fetchJson(\n apiUrl: string,\n label: string,\n authToken: string,\n query = '',\n): Promise<unknown> {\n const res = await fetch(apiUrl + query, {\n headers: {\n Authorization: authToken,\n 'Accept-Language': 'en-US,en',\n 'Content-Type': 'application/json',\n },\n });\n const body = await res.text();\n if (res.status !== 200) {\n throw new Error(`[${label}] HTTP ${res.status}\\n${body}`);\n }\n let json: RawEnvelope;\n try {\n json = JSON.parse(body) as RawEnvelope;\n } catch (e) {\n throw new Error(\n `[${label}] could not parse response: ${(e as Error).message}`,\n { cause: e },\n );\n }\n if (json.success === false) {\n throw new Error(\n `[${label}] ${json.msg ?? 'request failed'} (code ${json.code ?? '?'})`,\n );\n }\n return json.data ?? json;\n}\n\nexport async function fetchReport(config: ResolvedConfig): Promise<string> {\n const platform = config.url.includes('bigmodel') ? 'ZHIPU' : 'ZAI';\n\n const query = queryParams();\n try {\n const [model, tool, quotaRaw] = await Promise.all([\n fetchJson(\n `${config.url}/api/monitor/usage/model-usage`,\n 'Model usage',\n config.token,\n query,\n ),\n fetchJson(\n `${config.url}/api/monitor/usage/tool-usage`,\n 'Tool usage',\n config.token,\n query,\n ),\n fetchJson(\n `${config.url}/api/monitor/usage/quota/limit`,\n 'Quota limit',\n config.token,\n ),\n ]);\n return render({\n platform,\n model: model as ZaiModelUsage,\n tool: tool as ZaiToolUsage,\n quota: processQuotaLimit(quotaRaw as RawQuota),\n });\n } catch (e) {\n throw new Error(`Request failed: ${(e as Error).message}`, { cause: e });\n }\n}\n","import { hookOrPrint, printUsageAndExit } from '@v1nvn/agentic-core';\n\nimport { buildProgram, parseArgs, resolveConfig } from './resolve.js';\nimport { fetchReport } from './usage.js';\n\nconst parsed =\n parseArgs(process.argv.slice(2)) ?? printUsageAndExit(buildProgram());\n\nawait hookOrPrint(parsed.hook, 'query failed', () =>\n fetchReport(resolveConfig(process.env, parsed)),\n);\n"],"mappings":";;;AAIA,SAAS,QAAQ,QAAQ;CACxB,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,IAAI,OAAO;EACX,OAAO,YAAY,MAAM;EACzB,OAAO,GAAG,SAAS,UAAU;GAC5B,QAAQ;EACT,CAAC;EACD,OAAO,GAAG,aAAa;GACtB,QAAQ,IAAI;EACb,CAAC;EACD,OAAO,GAAG,SAAS,MAAM;CAC1B,CAAC;AACF;;;;;AAeA,SAAS,cAAc,SAAS,QAAQ,OAAO;CAC9C,OAAO,QAAQ,MAAM,CAAC,CAAC,MAAM,SAAS;EACrC,IAAI;GACH,OAAO,KAAK,MAAM,IAAI;EACvB,QAAQ;GACP,OAAO,CAAC;EACT;CACD,UAAU,CAAC,EAAE;AACd;;;;;AAqBA,SAAS,cAAc,QAAQ;CAC9B,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU;EACtC,UAAU;EACV;CACD,CAAC,EAAE,GAAG;AACP;AAGA,SAAS,aAAa,SAAS,MAAM,SAAS;CAC7C,IAAI;EACH,QAAQ,qBAAqB,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC,gBAAgB;GAClE,gBAAgB,KAAK;GACrB,gBAAgB,KAAK;EACtB,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,EAAE,MAAM,OAAO,CAAC;EACpC,OAAO;CACR,SAAS,KAAK;EACb,OAAO,UAAU,GAAG;CACrB;AACD;AACA,SAAS,kBAAkB,SAAS;CACnC,QAAQ,MAAM,QAAQ,gBAAgB,CAAC;CACvC,QAAQ,KAAK,CAAC;AACf;AACA,eAAe,YAAY,MAAM,SAAS,KAAK,QAAQ,QAAQ,OAAO;CACrE,IAAI,MAAM;EACT,IAAI;EACJ,IAAI;GACH,SAAS,MAAM,IAAI,MAAM,cAAc,KAAK,CAAC;EAC9C,SAAS,GAAG;GACX,SAAS,GAAG,QAAQ,IAAI,EAAE;EAC3B;EACA,cAAc,MAAM;EACpB;CACD;CACA,IAAI;EACH,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC;CAC9B,SAAS,GAAG;EACX,QAAQ,MAAM,EAAE,OAAO;EACvB,QAAQ,KAAK,CAAC;CACf;AACD;AAoFS,OAAO;;;;;;;AAyDhB,IAAI,SAAS;CACZ;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AACA,IAAI,UAAU;CACb;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAEA,SAAS,OAAO;CACf,OAAO,IAAI,OAAO,EAAE;AACrB;AACA,SAAS,KAAK,GAAG;CAChB,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;AACjC;AAKA,SAAS,UAAU,GAAG;CACrB,IAAI,KAAK,QAAQ,OAAO,MAAM,CAAC,GAAG,OAAO;CACzC,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAA,CAAK,QAAQ,CAAC,IAAI;CAC5C,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAA,CAAK,QAAQ,CAAC,IAAI;CAC5C,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAA,CAAK,QAAQ,CAAC,IAAI;CAC5C,OAAO,OAAO,CAAC;AAChB;AACA,SAAS,OAAO,GAAG;CAClB,QAAQ,KAAK,EAAA,CAAG,eAAe,OAAO;AACvC;AACA,SAAS,KAAK,GAAG,GAAG;CACnB,OAAO,EAAE,UAAU,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,EAAE,MAAM;AACvD;AACA,SAAS,KAAK,GAAG,GAAG;CACnB,OAAO,EAAE,UAAU,IAAI,IAAI,IAAI,OAAO,IAAI,EAAE,MAAM,IAAI;AACvD;;AAEA,SAAS,SAAS,GAAG,KAAK,OAAO;CAChC,IAAI,CAAC,KAAK,KAAK,KAAK,OAAO,GAAG,OAAO,IAAI,OAAO,KAAK;CACrD,MAAM,SAAS,IAAI,MAAM;CACzB,IAAI,OAAO,KAAK,MAAM,MAAM;CAC5B,IAAI,KAAK,KAAK,OAAO,SAAS,QAAQ,CAAC;CACvC,IAAI,OAAO,GAAG;EACb,QAAQ;EACR,KAAK;CACN;CACA,IAAI,SAAS,KAAK,OAAO,GAAG,KAAK;CACjC,IAAI,IAAI,IAAI,OAAO,KAAK,IAAI,MAAM,KAAK,CAAC;CACxC,IAAI,OAAO,SAAS,KAAK,GAAG,KAAK,QAAQ;CACzC,IAAI,EAAE,SAAS,OAAO,KAAK,IAAI,OAAO,QAAQ,EAAE,MAAM;CACtD,OAAO,EAAE,MAAM,GAAG,KAAK;AACxB;;AAEA,SAAS,MAAM,KAAK,OAAO;CAC1B,IAAI,SAAS,KAAK,OAAO,OAAO,KAAK,MAAM,KAAK;CAChD,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM,CAAC;CAC5C,OAAO,IAAI,OAAO,MAAM,IAAI,IAAI,OAAO,QAAQ,MAAM;AACtD;;;ACtTA,IAAM,mBAAmB;AAEzB,IAAM,4BAAY,IAAI,IAAI;CAAC;CAAY;CAAmB;AAAkB,CAAC;AAkB7E,SAAS,QAAQ,OAA+C;CAC9D,OAAO,QAAQ,QAAQ,KAAA;AACzB;AAEA,SAAS,SAAS,OAAmC;CACnD,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,KAAK;EACzB,OAAO,IAAI,aAAa,YAAY,IAAI,aAAa,UACjD,IAAI,SACJ,KAAA;CACN,QAAQ;EACN;CACF;AACF;AAEA,SAAS,MAAM,QAAyB;CACtC,OAAO,UAAU,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,QAAQ;AAC/C;AAEA,SAAS,eACP,MACA,KACS;CACT,IAAI,SAAS,KAAA,GAAW;EACtB,MAAM,SAAS,SAAS,IAAI;EAC5B,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,MAAM,qBAAqB,MAAM;EAE7C,OAAO;GAAE,KAAK,MAAM,MAAM;GAAG;EAAO;CACtC;CACA,MAAM,YAAY,QAAQ,IAAI,kBAAkB;CAChD,MAAM,SAAS,cAAc,KAAA,IAAY,KAAA,IAAY,SAAS,SAAS;CACvE,IAAI,WAAW,KAAA,KAAa,MAAM,MAAM,GACtC,OAAO;EAAE,KAAK;EAAM;CAAO;CAE7B,OAAO;EAAE,KAAK;EAAO,QAAQ;CAAiB;AAChD;AAEA,SAAgB,eAAwB;CACtC,OAAO,IAAI,QAAQ,CAAC,CACjB,KAAK,WAAW,CAAC,CACjB,UACC,IAAI,OAAO,wBAAwB,SAAS,CAAC,CAAC,IAAI,gBAAgB,CACpE,CAAC,CACA,UAAU,IAAI,OAAO,oBAAoB,UAAU,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CACzE,OAAO,UAAU,sDAAsD;AAC5E;AAEA,SAAgB,UAAU,MAAiD;CACzE,MAAM,UAAU,aAAa,aAAa,GAAG,IAAI;CACjD,IAAI,YAAY,KAAA,GACd;CAEF,MAAM,EAAE,WAAW,SAAS,SAAS,QAAQ,KAI1C;CACH,OAAO;EACL,WAAW,aAAa,KAAA;EACxB,SAAS,WAAW,KAAA;EACpB,MAAM,QAAQ;CAChB;AACF;AAEA,SAAgB,cACd,KACA,QACgB;CAChB,MAAM,OAAO,eAAe,OAAO,SAAS,GAAG;CAC/C,MAAM,QACJ,OAAO,cACN,KAAK,MAAM,QAAQ,IAAI,oBAAoB,IAAI,KAAA;CAClD,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MACR,IAAI,uBACA,iKACA,kDACN;CAEF,OAAO;EAAE;EAAO,KAAK,KAAK;CAAO;AACnC;;;;;;;;;;;;AChFA,IAAM,UAAU;AAwDhB,SAAS,UAAU,GAAoC;CACrD,MAAM,IAAI,2CAA2C,KAAK,KAAK,EAAE;CACjE,IAAI,CAAC,GACH,OAAO;CAET,OAAO;EACL,GAAG,CAAC,EAAE;EACN,KAAK,GAAG,OAAO,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE;EAC/B,MAAM,GAAG,EAAE,GAAG,GAAG,EAAE;CACrB;AACF;;;;;;AAOA,SAAS,UACP,GACA,eACA,aACa;CACb,MAAM,IAAI,2CAA2C,KAAK,CAAC;CAC3D,IAAI,CAAC,GACH,OAAO;CAET,MAAM,QACJ,KAAK,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,gBAAgB;CACpE,MAAM,KAAK,IAAI,KAAK,QAAQ,cAAc,GAAK;CAC/C,OAAO;EACL,GAAG,GAAG,YAAY;EAClB,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,GAAG,KAAK,GAAG,WAAW,CAAC;EACxD,MAAM,GAAG,KAAK,GAAG,YAAY,CAAC,EAAE,GAAG,KAAK,GAAG,cAAc,CAAC;CAC5D;AACF;AAEA,SAAS,aAAa,MAAkC;CACtD,SAAS,QAAQ,GAAA,CAAI,YAAY,GAAjC;EACE,KAAK,gBACH,OAAO;EACT,KAAK,cACH,OAAO;EACT,SACE,OAAO,QAAQ;CACnB;AACF;AAEA,SAAS,SAAS,KAAwD;CACxE,MAAM,OAAgD,CAAC;CACvD,IAAI,IAAI;CACR,OAAO,IAAI,IAAI,QACb,KAAK,IAAI,MAAM,OAAO,GAAG;EACvB,IAAI,IAAI;EACR,OAAO,IAAI,IAAI,WAAW,IAAI,MAAM,OAAO,GACzC;EAEF,KAAK,KAAK;GAAE;GAAG,GAAG,IAAI;GAAG,KAAK,IAAI;EAAE,CAAC;EACrC,IAAI;CACN,OACE;CAGJ,OAAO;AACT;AAEA,SAAS,UACP,KACA,GACA,QACQ;CACR,MAAM,IAAI,OAAO,EAAE,IAAI,EAAE;CACzB,MAAM,IAAI,OAAO,EAAE,IAAI,EAAE;CACzB,IAAI,CAAC,KAAK,CAAC,GACT,OAAO,SAAS,IAAI,IAAI;CAI1B,OAAO,QAAQ,GAFE,EAAE,IAAI,GAAG,EAAE,OAEP,KADT,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAG,EAAE,IAAI,GAAG,EAAE,OACvB,IAAI,IAAI,IAAI;AAC5C;AAMA,SAAS,aAAa,GAAgC;CACpD,MAAM,IAAI,oCAAoC,KAAK,KAAK,EAAE;CAC1D,IAAI,CAAC,GACH,OAAO;CAET,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU;CACjE,OAAO,MAAM,KAAK,MAAM,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC,EAAE,MAAM;AACvD;;AAGA,SAAS,gBACP,cACA,aACuC;CACvC,MAAM,IAAI,UAAU,oBAAoB,cAAc,WAAW;CACjE,MAAM,IAAI,UAAU,oBAAoB,cAAc,WAAW;CACjE,IAAI,CAAC,KAAK,CAAC,GACT,OAAO;CAET,OAAO;EAAE,OAAO,EAAE;EAAM,KAAK,EAAE;CAAK;AACtC;;;;;;;;;;AAWA,SAAS,oBAAoB,EAC3B,GACA,KACA,IACA,QACA,SACA,UAQkB;CAClB,MAAM,OAAO;CACb,IAAI,KAAK,KAAK,UAAU,GACtB,OAAO;CAGT,MAAM,QAAkB,CAAC;CACzB,MAAM,SAAS,UAAU,MAAM;CAC/B,MAAM,IAAI,OAAO;CAEjB,MAAM,OAAO,IAAM,IAAI;CACvB,MAAM,KAAK,OAAO;CAClB,MAAM,KAAA,KAAkB;CACxB,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,EAAE,CAAC;CAC5C,MAAM,OAAO,QAAQ,IAAI,OAAO,IAAI;CACpC,SAAS,QAAQ,GAAmB;EAClC,OAAO,KAAK,IAAI;CAClB;CACA,SAAS,UAAU,GAAmB;EACpC,OAAO,QAAQ,CAAC,IAAI,KAAK,MAAM,OAAO,CAAC;CACzC;CACA,MAAM,WAAW,KAAK;CACtB,SAAS,QAAkB;EACzB,OAAO,MAAA,EAAwB,CAAC,CAAC,KAAK,GAAG;CAC3C;CAGA,SAAS,MAAM,GAAW,GAAmB;EAC3C,MAAM,IAAI,IAAI,MAAM;EACpB,IAAI,KAAK,GACP,OAAO;EAET,MAAM,OAAQ,IAAI,SAAU,OAAO;EACnC,IAAI,QAAQ,GACV,OAAO;EAET,IAAI,OAAO,GAAG;GACZ,IAAI,IAAI,KAAK,MAAM,OAAO,CAAC;GAC3B,IAAI,IAAI,GACN,IAAI;GAEN,IAAI,IAAI,GACN,IAAI;GAEN,OAAO,QAAQ,IAAI;EACrB;EACA,OAAO;CACT;CAGA,KAAK,IAAI,IAAI,GAAU,KAAK,GAAG,KAAK;EAClC,MAAM,OAAO,MAAM;EACnB,KAAK,QAAQ,MAAM,IAAW,MAAM;EACpC,IAAI,MAAM,GACR,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO;EAGpC,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAC3B,MAAM,IAAI,MAAM,GAAG,CAAC;GACpB,IAAI,MAAM,KACR,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KACxB,KAAK,QAAQ,CAAC,IAAI,KAAK;EAG7B;EACA,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC;CACpC;CAGA,SAAS,OAAO,GAAwB;EACtC,OAAO,OAAO,EAAE,EAAE;CACpB;CACA,SAAS,OAAO,GAAoB;EAClC,IAAI,MAAM,KAAK,MAAM,KAAK,GACxB,OAAO;EAET,MAAM,IAAI,OAAO,CAAC;EAClB,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,MAAM;CAC5B;CAGA,MAAM,OAAO,MAAM;CACnB,KAAK,OAAO,KAAK;CACjB,KAAK,QAAQ;CACb,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,KAAK,UAAU,KACxC,KAAK,KAAK;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,IAAI,OAAO,CAAC,GACV,KAAK,UAAU,CAAC,KAAK;CAGzB,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC;CAGlC,MAAM,KAAK,MAAM;CACjB,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,IAAI,CAAC,OAAO,CAAC,GACX;EAEF,MAAM,MAAM,UAAU,CAAC;EACvB,IAAI,MAAM,OAAO,GACf;EAEF,MAAM,IAAI,OAAO,CAAC;EAClB,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC,IAAI;EAC5B,GAAG,OAAO,IAAI;EACd,GAAG,MAAM,KAAK,IAAI;EAClB,OAAO;CACT;CACA,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC;CAGhC,MAAM,MAAM,MAAM;CAClB,IAAI,UAAyB;CAC7B,OAAO;CACP,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,IAAI,CAAC,OAAO,CAAC,GACX;EAEF,MAAM,IAAI,OAAO,CAAC;EAClB,IAAI,CAAC,KAAK,EAAE,QAAQ,SAClB;EAEF,MAAM,MAAM,UAAU,CAAC;EACvB,IAAI,MAAM,QAAQ,EAAE,IAAI,UAAU,MAAM,EAAE,IAAI,UAAA,IAAsB;GAClE,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,IAAI,QAAQ,KAChC,IAAI,MAAM,KAAK,EAAE,IAAI;GAEvB,UAAU,EAAE;GACZ,OAAO,MAAM,EAAE,IAAI;EACrB;CACF;CACA,IAAI,IAAI,MAAK,MAAK,MAAM,GAAG,GACzB,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC;CAInC,MAAM,OAAO,MAAM;CACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,IAAI,aAAa,EAAE,EAAE,GACnB,KAAK,UAAU,CAAC,KAAK;CAGzB,IAAI,WAAW,GACb,KAAK,UAAU,OAAO,KAAK;CAE7B,IAAI,KAAK,MAAK,MAAK,MAAM,GAAG,GAC1B,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC;CAGpC,OAAO;AACT;AAEA,SAAgB,OAAO,EACrB,UACA,OACA,MACA,OACA,eAAe,KACf,gBACA,sBAAM,IAAI,KAAK,KACO;CACtB,MAAM,MAAgB,CAAC;CAKvB,MAAM,WACJ,kBAAkB,OAAO,iBAAiB,kBAAC,IAAI,KAAK,EAAA,CAAE,kBAAkB;CAC1E,SAAS,YAAY,GAAwB;EAC3C,OAAO,UAAU,GAAG,cAAc,QAAQ,KAAK,UAAU,CAAC;CAC5D;CAEA,MAAM,IAAI,MAAM,UAAU,CAAC;CAC3B,MAAM,MAAM,MAAM,eAAe,CAAC;CAClC,MAAM,QAAQ,MAAM,kBAAkB,CAAC;CACvC,MAAM,KAAK,EAAE;CAEb,MAAM,KAAK,MAAM,cAAc,CAAC;CAChC,MAAM,QACJ,GAAG,oBAAoB,OACnB,GAAG,mBACH,IAAI,QAAQ,GAAG,MAAM,KAAK,KAAK,IAAI,CAAC;CAC1C,MAAM,aACJ,GAAG,uBAAuB,OACtB,GAAG,sBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,KAAK,IAAI,CAAC;CAG5C,IAAI,UAAU;CACd,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,IAAI,IAAI,KAAK,SAAS;EACpB,UAAU,IAAI;EACd,UAAU;CACZ;CAEF,MAAM,YAAY,WAAW,IAAI,MAAM,YAAY,IAAI;CACvD,MAAM,UAAU,QAAQ,IAAK,UAAU,QAAS,MAAM;CACtD,MAAM,WAAW,WAAW,IAAI,YAAY,EAAE,QAAQ,IAAI;CAE1D,MAAM,QAAQ,MAAM,QAChB,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,MAAM,CAAC,IACzD;CAEJ,MAAM,OAAO,mBAAmB,QAAQ,QAAQ,QAAQ;CACxD,MAAM,YAAY,YAAY,EAAE,EAAE;CAClC,MAAM,WAAW,YAAY,EAAE,KAAK,EAAE;CACtC,MAAM,MACJ,aAAa,WACT,GAAG,UAAU,IAAI,GAAG,UAAU,KAAK,KAAK,SAAS,IAAI,GAAG,SAAS,KAAK,KAAK,GAAG,KAC9E;CACN,IAAI,KAAK,KAAK,CAAC;CACf,IAAI,KAAK,OAAO,KAAK,KAAA,KAAkB,KAAK,MAAM,CAAC;CACnD,IAAI,KAAK,KAAK,CAAC;CAEf,IAAI,OAAO,IAAI,UAAU,KAAK,EAAE,iBAAiB,OAAO,UAAU,EAAE;CACpE,IAAI,WAAW,KAAK,UAClB,QAAQ,MAAM,KAAK,MAAM,OAAO,EAAE,4BAA4B,SAAS,IAAI,GAAG,SAAS,KAAK,IAAI,UAAU,OAAO,EAAE,YAAY,OAAO,SAAS,EAAE;CAEnJ,QAAQ;CACR,IAAI,KAAK,EAAE;CACX,IAAI,KAAK,IAAI;CAEb,MAAM,cAAc,IAAI,QAAO,MAAK,IAAI,CAAC,CAAC,CAAC;CAC3C,MAAM,UAAU,SAAS,GAAG,CAAC,CAC1B,QAAO,MAAK,EAAE,OAAO,CAAC,CAAC,CACvB,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAC7B,GAAG,CAAC;CACP,MAAM,KAAK,KAAK,cAAc,CAAC;CAC/B,MAAM,UAAU,GAAG,2BAA2B;CAC9C,MAAM,QAAQ,GAAG,wBAAwB;CACzC,MAAM,SAAS,GAAG,sBAAsB;CACxC,MAAM,YACJ,GAAG,uBAAuB,OACtB,GAAG,sBACH,UAAU,QAAQ;CAGxB,IAAI,gBAAgB;CACpB,IAAI,gBAAgB;CACpB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KACtB,IAAI,aAAa,EAAE,EAAE,KAAK,IAAI,KAAK,GAAG;EACpC;EACA,iBAAiB,IAAI;CACvB;CAEF,MAAM,aAAa,QAAQ,IAAK,gBAAgB,QAAS,MAAM;CAC/D,MAAM,UAAU,gBAAgB,cAAc,QAAQ;CAEtD,IAAI,KAAK,EAAE;CACX,IAAI,KACF,aAAa,KAAK,WAAW,SAAS,MAAM,MAAM,SAAS,OAAO,KAAK,EAAE,IAAI,KAAK,UAAU,OAAO,GAAG,CAAC,EAAE,YAAY,KAAK,OAAO,SAAS,GAAG,CAAC,EAAE,OAClJ;CACA,IAAI,KACF,aAAa,KAAK,GAAG,YAAY,KAAK,GAAG,SAAS,EAAE,IAAI,UAAU,UAAU,SAAS,GAAG,WAAW,IAAI,gBACzG;CACA,IAAI,KACF,aAAa,KAAK,GAAG,UAAU,SAAS,EAAE,IAAI,QAAQ,cAAc,MAAM,QAAQ,SAAS,MAAM,OAAO,UAAU,IACpH;CACA,IAAI,SACF,IAAI,KACF,qBAAqB,QAAQ,MAAM,GAAG,QAAQ,IAAI,kBAAkB,cAAc,aAAa,UAAU,aAAa,EAAE,IAAI,KAAK,MAAM,UAAU,EAAE,GACrJ;CAGF,IAAI,KAAK,EAAE;CAEX,IAAI,KAAK,kCAAW,IAAI,OAAO,KAAK,IAAI,GAAA,EAA+B,CAAC,CAAC;CAEzE,MAAM,aAAa,oBAAoB;EACrC;EACA;EACA;EACA,QALa,WAAW;EAMxB;EACA,QAAQ;CACV,CAAC;CACD,IAAI,YAAY;EACd,IAAI,KAAK,GAAG,UAAU;EACtB,IAAI,WAAW,KAAK,UAClB,IAAI,KACF,cAAc,SAAS,IAAI,GAAG,SAAS,KAAK,IAAI,UAAU,OAAO,EAAE,YAAY,OAAO,SAAS,EAAE,OACnG;CAEJ,OACE,IAAI,KAAK,sCAAsC;CAGjD,IAAI,KAAK,EAAE;CACX,IAAI,KAAK,gBAAgB,IAAI,OAAO,KAAK,IAAI,GAAA,EAAkB,CAAC,CAAC;CACjE,MAAM,SAAS,MAAM,oBAAoB,MAAM,iBAAiB,CAAC;CACjE,MAAM,QAAQ,OAAO,QAAQ,GAAG,MAAM,KAAK,EAAE,eAAe,IAAI,CAAC,KAAK;CACtE,MAAM,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,MAC3B,GAAG,OAAO,EAAE,aAAa,MAAM,EAAE,aAAa,EACjD;CACA,KAAK,MAAM,KAAK,WAAW;EACzB,MAAM,OAAQ,EAAE,eAAe,KAAK,QAAS;EAC7C,IAAI,KACF,MAAM,KAAK,EAAE,aAAa,KAAK,EAAE,IAAI,KAAK,UAAU,EAAE,WAAW,GAAG,CAAC,EAAE,IAAI,KAAK,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,IAAI,SAAS,KAAK,KAAK,EAAE,GACpI;CACF;CAEA,IAAI,KAAK,EAAE;CACX,IAAI,KAAK,aAAa,IAAI,OAAO,KAAK,IAAI,GAAA,EAAiB,CAAC,CAAC;CAM7D,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,IAAI,eAAe,GAAK;CACxD,MAAM,QAAQ,GAAG,UAAU;CAE3B,MAAM,aADW,SAAS,KAAK,SAAS,IAEpC,KAAK,IACH,GACA,KAAK,IAAI,MAAM,GAAG,YAAY,IAAI,MAAM,KAAK,GAAG,cAAc,CAAC,CACjE,IACA;CACJ,IAAI,SACF,IAAI,KACF,MAAM,KAAK,QAAQ,EAAE,IAAI,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,MAAM,KAAK,MAAO,aAAa,MAAO,GAAG,GAAG,EAAE,EAAE,IAAI,QAAQ,KAClH;CAGF,MAAM,SAAS,MAAM,UAAU,CAAC;CAChC,MAAM,MAAM,OAAO,MAAK,MAAK,OAAO,KAAK,EAAE,QAAQ,EAAE,CAAC;CACtD,MAAM,OAAO,OAAO,MAAK,MAAK,SAAS,KAAK,EAAE,QAAQ,EAAE,CAAC;CACzD,IAAI,MAAM;EACR,MAAM,QAAQ,IAAI,KAAK,KAAK,iBAAiB,EAAE,CAAC,CAAC,mBAC/C,OACF;EACA,IAAI,KACF,MAAM,KAAK,eAAe,EAAE,IAAI,KAAK,GAAG,KAAK,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,MAAM,KAAK,YAAY,EAAE,EAAE,IAAI,OACzG;CACF;CAEA,IAAI,QAAQ,KACV,IAAI,KAAK,EAAE;CAGb,IAAI,KAAK;EACP,MAAM,QAAQ,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAAC,CAAC,eAAe,OAAO;EACtE,IAAI,KACF,MAAM,KAAK,oBAAoB,EAAE,IAAI,KAAK,GAAG,IAAI,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,MAAM,IAAI,YAAY,EAAE,EAAE,IAAI,OAC5G;EAEA,MAAM,SADM,IAAI,gBAAgB,CAAC,EAAA,CAE9B,KAAI,MAAK,GAAG,aAAa,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,KAAK,GAAG,CAAC,CAC3D,KAAK,IAAI;EACZ,IAAI,OACF,IAAI,KACF,MAAM,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,IAAI,KAAK,EAAE,MAAM,OAC/D;CAEJ;CAEA,IAAI,KAAK,EAAE;CACX,IAAI,KAAK,KAAK,CAAC;CACf,OAAO,IAAI,KAAK,IAAI;AACtB;;;;;;;;ACvhBA,SAAS,YAAY,sBAAM,IAAI,KAAK,GAAW;CAC7C,MAAM,YAAY,IAAI,KACpB,IAAI,YAAY,GAChB,IAAI,SAAS,GACb,IAAI,QAAQ,IAAI,GAChB,IAAI,SAAS,GACb,GACA,GACA,CACF;CACA,MAAM,UAAU,IAAI,KAClB,IAAI,YAAY,GAChB,IAAI,SAAS,GACb,IAAI,QAAQ,GACZ,IAAI,SAAS,GACb,IACA,IACA,GACF;CACA,SAAS,eAAe,MAAoB;EAC1C,OAAO,GAAG,KAAK,YAAY,EAAE,GAAG,KAAK,KAAK,SAAS,IAAI,CAAC,EAAE,GAAG,KAAK,KAAK,QAAQ,CAAC,EAAE,GAAG,KAAK,KAAK,SAAS,CAAC,EAAE,GAAG,KAAK,KAAK,WAAW,CAAC,EAAE,GAAG,KAAK,KAAK,WAAW,CAAC;CACjK;CACA,OAAO,cAAc,mBAAmB,eAAe,SAAS,CAAC,EAAE,WAAW,mBAAmB,eAAe,OAAO,CAAC;AAC1H;AAIA,SAAS,kBAAkB,MAA0B;CACnD,IAAI,CAAC,KAAK,QACR,OAAO;CAET,KAAK,SAAS,KAAK,OAAO,KAAI,SAAQ;EACpC,IAAI,KAAK,SAAS,gBAChB,OAAO;GACL,MAAM;GACN,YAAY,KAAK;GACjB,eAAe,KAAK;EACtB;EAEF,IAAI,KAAK,SAAS,cAChB,OAAO;GACL,MAAM;GACN,YAAY,KAAK;GACjB,cAAc,KAAK;GACnB,OAAO,KAAK;GACZ,cAAc,KAAK;GACnB,eAAe,KAAK;EACtB;EAEF,OAAO;CACT,CAAC;CACD,OAAO;AACT;AAEA,eAAe,UACb,QACA,OACA,WACA,QAAQ,IACU;CAClB,MAAM,MAAM,MAAM,MAAM,SAAS,OAAO,EACtC,SAAS;EACP,eAAe;EACf,mBAAmB;EACnB,gBAAgB;CAClB,EACF,CAAC;CACD,MAAM,OAAO,MAAM,IAAI,KAAK;CAC5B,IAAI,IAAI,WAAW,KACjB,MAAM,IAAI,MAAM,IAAI,MAAM,SAAS,IAAI,OAAO,IAAI,MAAM;CAE1D,IAAI;CACJ,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,SAAS,GAAG;EACV,MAAM,IAAI,MACR,IAAI,MAAM,8BAA+B,EAAY,WACrD,EAAE,OAAO,EAAE,CACb;CACF;CACA,IAAI,KAAK,YAAY,OACnB,MAAM,IAAI,MACR,IAAI,MAAM,IAAI,KAAK,OAAO,iBAAiB,SAAS,KAAK,QAAQ,IAAI,EACvE;CAEF,OAAO,KAAK,QAAQ;AACtB;AAEA,eAAsB,YAAY,QAAyC;CACzE,MAAM,WAAW,OAAO,IAAI,SAAS,UAAU,IAAI,UAAU;CAE7D,MAAM,QAAQ,YAAY;CAC1B,IAAI;EACF,MAAM,CAAC,OAAO,MAAM,YAAY,MAAM,QAAQ,IAAI;GAChD,UACE,GAAG,OAAO,IAAI,iCACd,eACA,OAAO,OACP,KACF;GACA,UACE,GAAG,OAAO,IAAI,gCACd,cACA,OAAO,OACP,KACF;GACA,UACE,GAAG,OAAO,IAAI,iCACd,eACA,OAAO,KACT;EACF,CAAC;EACD,OAAO,OAAO;GACZ;GACO;GACD;GACN,OAAO,kBAAkB,QAAoB;EAC/C,CAAC;CACH,SAAS,GAAG;EACV,MAAM,IAAI,MAAM,mBAAoB,EAAY,WAAW,EAAE,OAAO,EAAE,CAAC;CACzE;AACF;;;ACzJA,IAAM,SACJ,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC,KAAK,kBAAkB,aAAa,CAAC;AAEtE,MAAM,YAAY,OAAO,MAAM,sBAC7B,YAAY,cAAc,QAAQ,KAAK,MAAM,CAAC,CAChD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v1nvn/zai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "GLM Coding Plan usage and quota report — the zai-usage CLI behind the zai plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
"claude-code",
|
|
18
18
|
"usage"
|
|
19
19
|
],
|
|
20
|
-
"author":
|
|
20
|
+
"author": {
|
|
21
|
+
"name": "v1nvn",
|
|
22
|
+
"email": "v1n@outlook.com"
|
|
23
|
+
},
|
|
21
24
|
"license": "MIT",
|
|
22
25
|
"repository": {
|
|
23
26
|
"type": "git",
|
|
@@ -34,7 +37,7 @@
|
|
|
34
37
|
"node": ">=22"
|
|
35
38
|
},
|
|
36
39
|
"dependencies": {
|
|
37
|
-
"@v1nvn/agentic-core": "^0.
|
|
40
|
+
"@v1nvn/agentic-core": "^0.27.0",
|
|
38
41
|
"commander": "^15.0.0"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|