@v1nvn/zai 0.35.0 → 0.36.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 CHANGED
@@ -1,14 +1,18 @@
1
1
  # @v1nvn/zai
2
2
 
3
- The CLI behind the zai plugin: it reports GLM Coding Plan quota and usage for
4
- the current account, straight to the terminal — no model tokens, no browser.
3
+ The home of the zai plugin — and its plugin root: the `zai-usage` CLI in `src/`,
4
+ the mod's hooks module at `hooks/register.ts` (`.ts`/`.tsx` the engine loads
5
+ directly, no build), engine tests at `tests/`. It reports GLM Coding Plan quota
6
+ and usage for the current account — models, tools, limits — straight to the
7
+ terminal; no browser, nothing written.
5
8
 
6
9
  User-facing docs: [root README](../../README.md).
7
10
 
8
11
  ## Quickstart
9
12
 
10
- In Claude Code, the plugin is the way in — `/zai:usage` runs this CLI through
11
- a `UserPromptExpansion` hook with zero model tokens:
13
+ In Claude Code, the plugin is the way in — a mod serves the one surface the
14
+ model never reads: `/zai-usage` execs the shipped CLI and shows its report as
15
+ dim transcript rows (nothing execs until the command runs).
12
16
 
13
17
  ```sh
14
18
  claude plugin marketplace add v1nvn/agentic
@@ -18,17 +22,18 @@ claude plugin install zai@agentic
18
22
  In a terminal, bare:
19
23
 
20
24
  ```sh
21
- npx -y @v1nvn/zai@0.35.0
25
+ npx -y @v1nvn/zai@0.36.0
22
26
  ```
23
27
 
24
28
  ## Usage
25
29
 
26
30
  | Invocation | Does |
27
31
  |---|---|
28
- | `npx -y @v1nvn/zai@0.35.0` | usage report — models, quota window, remaining balance |
29
- | `npx -y @v1nvn/zai@0.35.0 --auth-token TOKEN` | same, key on the command line (visible in `ps`) |
30
- | `npx -y @v1nvn/zai@0.35.0 --auth-token=TOKEN` | `=` form — zsh quoting-safe |
31
- | `npx -y @v1nvn/zai@0.35.0 --base-url URL` | another GLM endpoint (default `api.z.ai`) |
32
+ | `/zai-usage` | the account's usage report, as dim transcript rows |
33
+ | `npx -y @v1nvn/zai@0.36.0` | the same report, printed bare |
34
+ | `npx -y @v1nvn/zai@0.36.0 --auth-token TOKEN` | same, key on the command line (visible in `ps`) |
35
+ | `npx -y @v1nvn/zai@0.36.0 --auth-token=TOKEN` | `=` form — zsh quoting-safe |
36
+ | `npx -y @v1nvn/zai@0.36.0 --base-url URL` | another GLM endpoint (default `api.z.ai`) |
32
37
 
33
38
  Each setting takes the first source that provides it:
34
39
 
@@ -42,8 +47,8 @@ Each setting takes the first source that provides it:
42
47
  to a GLM Coding Plan. Claude Code routed elsewhere (plain Anthropic, another
43
48
  proxy) is not a zai configuration; set `ZAI_AUTH_TOKEN`. Bigmodel accounts
44
49
  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.
50
+ (`ZAI_BASE_URL=https://open.bigmodel.cn`). The mod's exec runs inside the
51
+ session's shell, so it inherits the same environment `npx zai-usage` reads.
47
52
 
48
53
  The API labels every bucket in Beijing time (UTC+8); the report shifts each
49
54
  timestamp to your local zone for display.
@@ -51,11 +56,18 @@ timestamp to your local zone for display.
51
56
  ## Develop
52
57
 
53
58
  ```sh
54
- yarn workspace @v1nvn/zai build
55
- yarn workspace @v1nvn/zai test
56
- yarn lint && yarn typecheck # from the repo root
59
+ yarn workspace @v1nvn/zai test # the CLI side (vitest)
60
+ claude plugin validate packages/zai # the mod, as the engine reads it
61
+ claude plugin test packages/zai # the mod, through the engine
62
+ yarn lint && yarn typecheck # from the repo root (typecheck
63
+ # covers tsconfig.mods.json too)
57
64
  ```
58
65
 
66
+ The mod API is early access and moves between Claude Code releases — a build
67
+ that refuses the module loads nothing, so validate after every engine update
68
+ and re-vendor `types/claude-code.d.ts` (repo root) from the engine-laid
69
+ `.claude-plugin/types/` when it changes. Read `references/mods.md` first.
70
+
59
71
  ## Modules
60
72
 
61
73
  | File | Role |
@@ -64,9 +76,14 @@ yarn lint && yarn typecheck # from the repo root
64
76
  | `src/usage.ts` | the GLM API call and the report it builds |
65
77
  | `src/resolve.ts` | auth-token resolution chain |
66
78
  | `src/format.ts` | the printed table |
79
+ | `hooks/register.ts` | the mod: registers `/zai-usage`, execs the CLI, shows its report |
80
+ | `bin/usage.mjs` | the standalone build the mod execs — committed, synced by `yarn build` |
67
81
 
68
82
  ## Contracts
69
83
 
70
84
  - One job: print the report, exit 0. Nothing is written anywhere.
71
- - The hook path and the terminal path run the same bin — the hook only
72
- feeds it the session's transcript context.
85
+ - `/zai-usage` is one `node <plugin root>/bin/usage.mjs` exec through the
86
+ session's Bash tool — the same query `npx zai-usage` runs, awaited as-is. The
87
+ one allow rule it needs is `Bash(node <plugin root>/bin/usage.mjs)`; the
88
+ first run asks for it once, then it is remembered. Its report is dim
89
+ transcript rows the model never reads.
package/dist/index.js CHANGED
@@ -1,42 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command, Option } from "commander";
3
3
  //#region ../core/dist/index.js
4
- function readAll(stream) {
5
- return new Promise((resolve, reject) => {
6
- let data = "";
7
- stream.setEncoding("utf8");
8
- stream.on("data", (chunk) => {
9
- data += chunk;
10
- });
11
- stream.on("end", () => {
12
- resolve(data);
13
- });
14
- stream.on("error", reject);
15
- });
16
- }
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
- /**
31
- * Print the UserPromptExpansion decision for a zero-token command: `block`
32
- * keeps the command from reaching the model, with the output as the `reason`.
33
- */
34
- function emitHookBlock(reason) {
35
- process.stdout.write(`${JSON.stringify({
36
- decision: "block",
37
- reason
38
- })}\n`);
39
- }
40
4
  function parseQuietly(program, args, recover) {
41
5
  try {
42
6
  program.allowExcessArguments(false).exitOverride().configureOutput({
@@ -52,24 +16,6 @@ function printUsageAndExit(program) {
52
16
  console.error(program.helpInformation());
53
17
  process.exit(1);
54
18
  }
55
- async function hookOrPrint(hook, failure, run, stdin = process.stdin) {
56
- if (hook) {
57
- let reason;
58
- try {
59
- reason = await run(await readHookEvent(stdin));
60
- } catch (e) {
61
- reason = `${failure}: ${e.message}`;
62
- }
63
- emitHookBlock(reason);
64
- return;
65
- }
66
- try {
67
- console.log(await run(void 0));
68
- } catch (e) {
69
- console.error(e.message);
70
- process.exit(1);
71
- }
72
- }
73
19
  Number.MAX_SAFE_INTEGER;
74
20
  //#endregion
75
21
  //#region src/resolve.ts
@@ -114,16 +60,15 @@ function resolveBaseUrl(flag, env) {
114
60
  };
115
61
  }
116
62
  function buildProgram() {
117
- return new Command().name("zai-usage").addOption(new Option("--auth-token <token>", "API key").env("ZAI_AUTH_TOKEN")).addOption(new Option("--base-url <url>", "base URL").env("ZAI_BASE_URL")).option("--hook", "emit a UserPromptExpansion block instead of printing");
63
+ return new Command().name("zai-usage").addOption(new Option("--auth-token <token>", "API key").env("ZAI_AUTH_TOKEN")).addOption(new Option("--base-url <url>", "base URL").env("ZAI_BASE_URL"));
118
64
  }
119
65
  function parseArgs(args) {
120
66
  const program = parseQuietly(buildProgram(), args);
121
67
  if (program === void 0) return;
122
- const { authToken, baseUrl, hook } = program.opts();
68
+ const { authToken, baseUrl } = program.opts();
123
69
  return {
124
70
  authToken: authToken || void 0,
125
- baseUrl: baseUrl || void 0,
126
- hook: hook ?? false
71
+ baseUrl: baseUrl || void 0
127
72
  };
128
73
  }
129
74
  function resolveConfig(env, parsed) {
@@ -568,7 +513,12 @@ async function fetchReport(config) {
568
513
  //#endregion
569
514
  //#region src/index.ts
570
515
  var parsed = parseArgs(process.argv.slice(2)) ?? printUsageAndExit(buildProgram());
571
- await hookOrPrint(parsed.hook, "query failed", () => fetchReport(resolveConfig(process.env, parsed)));
516
+ try {
517
+ console.log(await fetchReport(resolveConfig(process.env, parsed)));
518
+ } catch (e) {
519
+ console.error(e.message);
520
+ process.exit(1);
521
+ }
572
522
  //#endregion
573
523
  export {};
574
524
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../core/dist/index.js","../src/resolve.ts","../../tokens/dist/text.js","../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\tfunction 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\nexport { Logger, claudeProjectsDir, emitHookBlock, hookOrPrint, isFile, lastReply, levelEnabled, parseQuietly, printUsageAndExit, readAll, readHookEvent, readMarkdownFile, readStdin, replyTarget, shutdownOnSignals, watchWithReload };\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","//#region src/text.ts\n/**\n* Plain-text rendering primitives for the fixed-width reports. Output targets\n* a monospace terminal — the pane — so everything here is fixed-width:\n* padding, block-glyph bars, and compact 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}\n/** '2026-08-15' → 'Aug 15'. */\nfunction dayLabel(day) {\n\tconst [, , month, date] = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(day) ?? [];\n\treturn month !== void 0 && date !== void 0 ? `${MONTHS[+month - 1] ?? day} ${date}` : day;\n}\nfunction fmtClock(date) {\n\treturn `${pad2(date.getHours())}:${pad2(date.getMinutes())}`;\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 { MONTHS, RULE_WIDTH, barField, dayLabel, fmtClock, fmtNum, fmtTokens, meter, pad2, padL, padR, rule, ymd };\n\n//# sourceMappingURL=text.js.map","/**\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/tokens/text';\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/tokens/text';\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":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../core/dist/index.js","../src/resolve.ts","../../tokens/dist/text.js","../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/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}\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/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/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}\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\tfunction 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\nexport { Logger, claudeProjectsDir, lastReply, levelEnabled, parseQuietly, printUsageAndExit, readMarkdownFile, readStdin, shutdownOnSignals, watchWithReload };\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}\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}\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 } = program.opts<{\n authToken: string | undefined;\n baseUrl: string | undefined;\n }>();\n return {\n authToken: authToken || undefined,\n baseUrl: baseUrl || undefined,\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","//#region src/text.ts\n/**\n* Plain-text rendering primitives for the fixed-width reports. Output targets\n* a monospace terminal — the pane — so everything here is fixed-width:\n* padding, block-glyph bars, and compact 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}\n/** '2026-08-15' → 'Aug 15'. */\nfunction dayLabel(day) {\n\tconst [, , month, date] = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(day) ?? [];\n\treturn month !== void 0 && date !== void 0 ? `${MONTHS[+month - 1] ?? day} ${date}` : day;\n}\nfunction fmtClock(date) {\n\treturn `${pad2(date.getHours())}:${pad2(date.getMinutes())}`;\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 { MONTHS, RULE_WIDTH, barField, dayLabel, fmtClock, fmtNum, fmtTokens, meter, pad2, padL, padR, rule, ymd };\n\n//# sourceMappingURL=text.js.map","/**\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/tokens/text';\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/tokens/text';\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 { 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\ntry {\n console.log(await fetchReport(resolveConfig(process.env, parsed)));\n} catch (e) {\n console.error((e as Error).message);\n // CLIs report failure through the exit code; the rule targets libraries.\n // eslint-disable-next-line n/no-process-exit\n process.exit(1);\n}\n"],"mappings":"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"}