token-quota 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jipengfei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # token-quota
2
+
3
+ One compact table of the remaining token-plan / purchased-package quota for three
4
+ platforms: **Doubao (Volcengine Ark)**, **Alibaba Bailian** and **Cursor**.
5
+
6
+ ```
7
+ $ token-quota
8
+ PLATFORM PLAN/PACKAGE TOTAL USED REMAINING RESET
9
+ -------- -------------------------------------- ----- ------ --------- ----------------
10
+ doubao agent-plan personal (medium) — 5h 100% 2.08% 97.92% 2026-09-19 16:29
11
+ doubao agent-plan personal (medium) — weekly 100% 57.53% 42.47% 2026-09-21 00:00
12
+ doubao agent-plan personal (medium) — monthly 100% 55.99% 44.01% 2026-09-28 23:59
13
+ bailian Alibaba Coding Plan — week 100% 64.4% 35.6% 2026-09-24 06:00
14
+ cursor Pro — included usage 100% 17% 83% 2026-09-30 19:39
15
+ cursor Pro — auto usage 100% 15% 85% 2026-09-30 19:39
16
+ cursor Pro — API usage 100% 42% 58% 2026-09-30 19:39
17
+ cursor Pro — spend limit $1.00 $0.00 $1.00 2026-09-30 19:39
18
+ ```
19
+
20
+ Read-only by design: **it queries, prints, exits**. No daemon, no background
21
+ refresh, no cache, no purchase or top-up action. It never prints, writes or
22
+ commits a credential value — credentials are only ever read by the vendor CLIs'
23
+ own credential stores. One platform failing never affects the others, and a
24
+ missing sign-in is a reported state, not a crash.
25
+
26
+ ## Install
27
+
28
+ Requires **Node.js >= 20**.
29
+
30
+ ```
31
+ npm install -g token-quota # then: token-quota
32
+ npx token-quota # one-off, no install
33
+ ```
34
+
35
+ The three data-source CLIs (`quota-axi`, `bailian-cli`, `@volcengine/ark-cli`)
36
+ are declared dependencies of this package, so they arrive with it — there is
37
+ nothing to install by hand.
38
+
39
+ ## Quick start
40
+
41
+ ```
42
+ token-quota # the table
43
+ token-quota --json # machine-readable { rows, notes }
44
+ token-quota --only cursor,doubao
45
+ token-quota setup # sign in to the platforms that are not configured
46
+ token-quota doctor # read-only check of what is missing
47
+ token-quota --help
48
+ token-quota --version
49
+ ```
50
+
51
+ First run on a fresh machine: `token-quota setup` walks platform by platform and
52
+ runs each platform's own login command. If everything is already signed in, just
53
+ run `token-quota`.
54
+
55
+ ## Commands
56
+
57
+ | Command | What it does |
58
+ | ------- | ------------ |
59
+ | *(none)* | Prints the quota table (or `--json`) and exits. |
60
+ | `setup` | Interactive sign-in wizard. Checks each selected platform, explains what is missing, runs that platform's own login command (`arkcli auth login volc-sso`, `bl auth login --console`) or asks you to sign in inside the Cursor editor, then re-checks and prints the final panel. Writes no file and stores no credential — every session stays owned by the tool that created it. Non-interactive runs (`token-quota setup | cat`) only print the manual steps and exit 0. |
61
+ | `doctor` | Read-only health check: Node version, the three data-source CLIs (`--version`), the sqlite3 the Cursor row needs, then one real read-only query per platform, each classified as working / not logged in / CLI missing / query failed, with the exact fix command for anything red. It never starts a login. Exits 0 only when everything is green. |
62
+
63
+ Both subcommands accept `--only <list>`, like the panel.
64
+
65
+ ```
66
+ $ token-quota doctor
67
+ token-quota doctor — read-only checks; nothing is signed in, written or refreshed
68
+
69
+ Environment
70
+ [ok] node v24.20.0 (requires >= 20)
71
+ [ok] sqlite3 (vendored for Windows) — .../vendor/sqlite3-shim/sqlite3.exe
72
+
73
+ Data-source CLIs
74
+ [ok] quota-axi 0.1.47 — package dependency: node .../quota-axi/dist/bin/quota-axi.js
75
+ [ok] bailian CLI (bl) 1.24.0 — package dependency: node .../bailian-cli/dist/bailian.mjs
76
+ [ok] arkcli (Volcengine Ark) 1.0.33 — package dependency: .../ark-cli/bin/arkcli-windows-amd64.exe
77
+
78
+ Platforms (real read-only queries)
79
+ [ok] doubao — 3 row(s) read
80
+ [ok] bailian — 1 row(s) read
81
+ [ok] cursor — 5 row(s) read
82
+
83
+ 3 of 3 platform(s) usable — everything checks out; `token-quota` is ready.
84
+ ```
85
+
86
+ ## Output
87
+
88
+ | Column | Meaning |
89
+ | ----------- | ------------------------------------------------------------------------- |
90
+ | `PLATFORM` | `doubao`, `bailian` or `cursor` |
91
+ | `PLAN` | The purchased plan/package, plus the usage window the row describes |
92
+ | `TOTAL` | The window's size (`100%` for percentage meters, USD for credit meters) |
93
+ | `USED` | How much of that window has been consumed |
94
+ | `REMAINING` | What is left (`TOTAL - USED`) |
95
+ | `RESET` | When the window resets/expires, in local time (`n/a` when not reported) |
96
+
97
+ A platform that cannot be queried still gets its row, with an explicit
98
+ `credential missing` or `query failed` state and a note naming the exact
99
+ credential or cause.
100
+
101
+ ## Data sources and credentials
102
+
103
+ | Platform | Source | Credentials |
104
+ | -------- | ------ | ----------- |
105
+ | Doubao (Volcengine Ark) | **ark-cli** (`arkcli usage plan`) | an Ark CLI SSO session from `arkcli auth login volc-sso` (one browser SSO sign-in). AK/SK pairs and `DOUBAO_*` model keys are not used and never printed. |
106
+ | Alibaba Bailian | **quota-axi** (`--provider alibaba`), which reads the local official Bailian CLI (`bl`) | a Bailian **console session** from `bl auth login --console` (one browser sign-in). `BAILIAN_PLAN_API_KEY` is a model inference key and is rejected by the usage API. |
107
+ | Cursor | **quota-axi** (`--provider cursor`) | the Cursor editor's own local sign-in store (sign in to the app once). On Windows quota-axi needs the `sqlite3` CLI to read it — see below. |
108
+
109
+ Credentials are only ever read from the config stores `quota-axi` and the
110
+ platform CLIs already own. `token-quota` never prints, logs or writes secret
111
+ values, and `quota-axi` is always run with `--no-credential-refresh`, so no read
112
+ can trigger an interactive re-login flow.
113
+
114
+ `QUOTA_AXI_BIN` and `ARKCLI_BIN` override how the two data-source CLIs are
115
+ launched (absolute path to the entry script or binary); they are meant for
116
+ development against a checkout, not for normal use.
117
+
118
+ ## Doubao quota granularity
119
+
120
+ Doubao quota is whatever `arkcli usage plan` reports: one row per usage period
121
+ (`5h`, `weekly`, `monthly`) of each subscribed plan item (`product edition
122
+ (tier)`). Items marked `subscribed:false` are hidden by default (the row count
123
+ is noted). If the SSO session is absent or expired, the doubao row reports
124
+ `credential missing` and names `arkcli auth login volc-sso`.
125
+
126
+ ## Why vendor/sqlite3-shim exists
127
+
128
+ quota-axi's Cursor provider reads the signed-in editor's `state.vscdb` by
129
+ spawning the `sqlite3` CLI. On Windows, a spawned process can only execute a
130
+ real `sqlite3.exe` (`.cmd` wrappers are invisible to it), and many machines do
131
+ not have sqlite3 installed. This package therefore vendors the official
132
+ public-domain `sqlite3.exe` (from sqlite.org, sqlite-tools-win-x64) in
133
+ `vendor/sqlite3-shim/` and prepends that directory to `PATH` **only for the
134
+ quota-axi subprocess**. Nothing is installed globally and the user's own
135
+ environment is untouched. `token-quota doctor` reports whether it is present;
136
+ if the vendored binary is missing or unusable, the cursor row says so explicitly.
137
+ On macOS/Linux quota-axi uses the system `sqlite3` (doctor checks that too).
138
+
139
+ ## Exit codes
140
+
141
+ - `0` — at least one platform returned usable data (missing credentials are a
142
+ reported state, not a crash); for `doctor`, every check is green
143
+ - `1` — every selected platform failed (for `doctor`, at least one check failed)
144
+ - `2` — bad usage (unknown argument or command, empty/unmatched `--only` list)
145
+
146
+ ## Development
147
+
148
+ No build step, no bundler: plain ESM, `node:test`, and the three runtime
149
+ dependencies the panel actually shells out to.
150
+
151
+ ```
152
+ npm run quota -- --json # run from a checkout (== node bin/token-quota.js)
153
+ npm run doctor
154
+ npm test # node --test
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * token-quota — one compact table of remaining token-plan / package quota.
4
+ *
5
+ * Usage:
6
+ * token-quota # or: npx token-quota
7
+ * token-quota --json # machine-readable
8
+ * token-quota --only cursor,doubao
9
+ * token-quota setup # sign-in wizard (interactive)
10
+ * token-quota doctor # read-only health check
11
+ *
12
+ * Read-only: it queries the platforms and prints values. It never writes
13
+ * credentials, never prints them, and never buys, tops up or changes anything.
14
+ * The only command that touches a vendor login is `setup`, which runs the
15
+ * platform's own login command and stores nothing itself.
16
+ */
17
+ import { parseArgs, UsageError, VERSION } from '../src/cli.js';
18
+ import { runDoctor } from '../src/doctor.js';
19
+ import { runPanel } from '../src/panel.js';
20
+ import { platforms } from '../src/platforms/index.js';
21
+ import { runSetup } from '../src/setup.js';
22
+
23
+ const USAGE = `token-quota — remaining token-plan / package quota for Cursor, Doubao (Volcengine Ark) and Alibaba Bailian
24
+
25
+ Usage: token-quota [--json] [--only <platform,...>] [--help] [--version]
26
+ token-quota setup [--only <platform,...>]
27
+ token-quota doctor [--only <platform,...>]
28
+
29
+ Commands:
30
+ (no command) print the quota table and exit
31
+ setup interactive sign-in wizard: checks each platform and, for
32
+ the ones that are not signed in, explains what is needed
33
+ and runs that platform's own login command; finishes by
34
+ printing the panel. Writes no file, stores no credential.
35
+ doctor read-only health check: Node version, the three
36
+ data-source CLIs, sqlite3, and one real read-only query
37
+ per platform, each classified and paired with its fix.
38
+ Never starts a login. Exits 0 only when everything is green.
39
+
40
+ Options:
41
+ --json print { rows, notes } as JSON instead of a table
42
+ --only <list> restrict to some platforms: ${platforms.map((p) => p.id).join(', ')}
43
+ --help show this help
44
+ --version print the installed version
45
+
46
+ Data sources:
47
+ cursor quota-axi — signed-in Cursor usage; the credential is the local
48
+ store the Cursor editor keeps
49
+ bailian quota-axi — reads Token Plan usage through the local official
50
+ Bailian CLI (bl)
51
+ doubao ark-cli (arkcli) — official Volcengine Ark usage-plan read
52
+
53
+ All three CLIs come with this package, so there is nothing to install by hand;
54
+ quota-axi is always run with --no-credential-refresh, so no read can trigger a
55
+ re-login.
56
+
57
+ Credentials (never printed, never written, never refreshed):
58
+ cursor sign in to the Cursor editor; quota-axi reads the local credential
59
+ store Cursor itself keeps (on Windows this package ships
60
+ vendor/sqlite3-shim/sqlite3.exe for that read)
61
+ bailian run \`bl auth login --console\` once; BAILIAN_PLAN_API_KEY is a model
62
+ inference key and cannot read Token Plan usage
63
+ doubao run \`arkcli auth login volc-sso\` once (one browser SSO sign-in);
64
+ AK/SK pairs and DOUBAO_* model keys are not used
65
+
66
+ New here? \`token-quota setup\` signs you in platform by platform, and
67
+ \`token-quota doctor\` reports what is missing without changing anything.
68
+
69
+ Exit codes:
70
+ 0 at least one platform returned usable data (doctor: every check green)
71
+ 1 every selected platform failed (doctor: at least one check failed)
72
+ 2 bad usage
73
+ `;
74
+
75
+ async function main(argv = process.argv.slice(2)) {
76
+ let options;
77
+ try {
78
+ options = parseArgs(argv);
79
+ } catch (error) {
80
+ if (!(error instanceof UsageError)) throw error;
81
+ process.stderr.write(`token-quota: ${error.message}\n\nrun \`token-quota --help\` for usage\n`);
82
+ return 2;
83
+ }
84
+
85
+ if (options.help) {
86
+ process.stdout.write(USAGE);
87
+ return 0;
88
+ }
89
+ if (options.version) {
90
+ process.stdout.write(`${VERSION}\n`);
91
+ return 0;
92
+ }
93
+ if (options.command === 'doctor') return runDoctor(options);
94
+ if (options.command === 'setup') return runSetup(options);
95
+ return runPanel(options);
96
+ }
97
+
98
+ main()
99
+ .then((code) => {
100
+ process.exitCode = code;
101
+ })
102
+ .catch((error) => {
103
+ process.stderr.write(`token-quota: ${error.message}\n`);
104
+ process.exitCode = 1;
105
+ });
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "token-quota",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "One compact table of remaining token-plan / package quota for Cursor, Doubao (Volcengine Ark) and Alibaba Bailian — read-only, no daemon",
6
+ "bin": {
7
+ "token-quota": "bin/token-quota.js"
8
+ },
9
+ "files": [
10
+ "bin/",
11
+ "src/",
12
+ "vendor/",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "quota": "node bin/token-quota.js",
18
+ "doctor": "node bin/token-quota.js doctor",
19
+ "setup": "node bin/token-quota.js setup",
20
+ "test": "node --test"
21
+ },
22
+ "dependencies": {
23
+ "@volcengine/ark-cli": "^1.0.33",
24
+ "bailian-cli": "^1.24.0",
25
+ "quota-axi": "^0.1.47"
26
+ },
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/jibuji/token-quota.git"
33
+ },
34
+ "homepage": "https://github.com/jibuji/token-quota#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/jibuji/token-quota/issues"
37
+ },
38
+ "keywords": [
39
+ "quota",
40
+ "token-plan",
41
+ "cli",
42
+ "cursor",
43
+ "doubao",
44
+ "volcengine-ark",
45
+ "bailian",
46
+ "dashscope"
47
+ ],
48
+ "license": "MIT"
49
+ }
package/src/cli.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared command-line plumbing: argument parsing, platform selection and the
3
+ * installed version. Every subcommand (panel, doctor, setup) parses its
4
+ * arguments through `parseArgs` so the flags behave identically.
5
+ *
6
+ * Deliberately knows nothing about the platform list (callers pass theirs in),
7
+ * so this module stays a leaf of the import graph.
8
+ */
9
+ import { readFileSync } from 'node:fs';
10
+
11
+ /** Installed package version (read from this package's own package.json). */
12
+ export const VERSION = JSON.parse(
13
+ readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
14
+ ).version;
15
+
16
+ /** Subcommands that take over instead of printing the panel. */
17
+ export const COMMANDS = ['setup', 'doctor'];
18
+
19
+ /** Bad usage — the CLI maps this to exit code 2. */
20
+ export class UsageError extends Error {
21
+ constructor(message) {
22
+ super(message);
23
+ this.name = 'UsageError';
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Parses argv into `{ command, json, only, help, version }`.
29
+ * Throws UsageError on anything unknown or incomplete.
30
+ */
31
+ export function parseArgs(argv = []) {
32
+ const options = { command: null, json: false, only: null, help: false, version: false };
33
+ for (let i = 0; i < argv.length; i += 1) {
34
+ const arg = argv[i];
35
+ if (arg === '--json') options.json = true;
36
+ else if (arg === '--help' || arg === '-h') options.help = true;
37
+ else if (arg === '--version' || arg === '-v') options.version = true;
38
+ else if (arg === '--only') {
39
+ const value = argv[i + 1];
40
+ if (value === undefined || value.startsWith('-')) {
41
+ throw new UsageError('--only needs a comma-separated platform list');
42
+ }
43
+ options.only = parseOnly(value);
44
+ i += 1;
45
+ } else if (arg.startsWith('--only=')) {
46
+ options.only = parseOnly(arg.slice('--only='.length));
47
+ } else if (arg.startsWith('-')) {
48
+ throw new UsageError(`unknown argument: ${arg}`);
49
+ } else if (options.command === null) {
50
+ if (!COMMANDS.includes(arg)) {
51
+ throw new UsageError(`unknown command: ${arg} (expected ${COMMANDS.join(' or ')})`);
52
+ }
53
+ options.command = arg;
54
+ } else {
55
+ throw new UsageError(`unexpected argument: ${arg}`);
56
+ }
57
+ }
58
+ return options;
59
+ }
60
+
61
+ /** `cursor,doubao` → ['cursor', 'doubao']. */
62
+ export function parseOnly(value) {
63
+ return String(value ?? '')
64
+ .split(',')
65
+ .map((name) => name.trim())
66
+ .filter(Boolean);
67
+ }
68
+
69
+ /** Selected platforms for an `--only` list; throws UsageError when nothing matches. */
70
+ export function selectPlatforms(only, available = []) {
71
+ if (!only || only.length === 0) return available;
72
+ const selected = available.filter((platform) => only.includes(platform.id));
73
+ if (selected.length === 0) {
74
+ throw new UsageError(
75
+ `no matching platform in --only ${only.join(',')} (known: ${available
76
+ .map((platform) => platform.id)
77
+ .join(', ')})`,
78
+ );
79
+ }
80
+ return selected;
81
+ }
82
+
83
+ /**
84
+ * `cmd --flag "arg with spaces"` — a single line for the `shell: true` launch
85
+ * path Windows needs for `.cmd` npm shims (passing args together with `shell`
86
+ * is deprecated). Only fixed flags are ever built here, never user input.
87
+ */
88
+ export function commandLine(command, args = []) {
89
+ return [command, ...args]
90
+ .map((part) => (/\s/.test(String(part)) ? `"${part}"` : String(part)))
91
+ .join(' ');
92
+ }