agy-cli-usage 0.4.2 → 0.4.3
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/CHANGELOG.md +7 -0
- package/dist/src/main.d.ts +8 -0
- package/dist/src/main.js +60 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
* use plain v* tags in release-please ([#12](https://github.com/abruption/agy-cli-usage/issues/12)) ([74b648d](https://github.com/abruption/agy-cli-usage/commit/74b648df24967f71a43095a80e7340a6b5ac2e39)), closes [#9](https://github.com/abruption/agy-cli-usage/issues/9)
|
|
12
12
|
|
|
13
|
+
## [0.4.3](https://github.com/abruption/agy-cli-usage/compare/v0.4.2...v0.4.3) (2026-07-02)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* key the quota cache by source/channel, validate --source/--channel ([#33](https://github.com/abruption/agy-cli-usage/issues/33)) ([19e6860](https://github.com/abruption/agy-cli-usage/commit/19e6860bcf2aa8a547b880a4430027539b4343fb)), closes [#30](https://github.com/abruption/agy-cli-usage/issues/30)
|
|
19
|
+
|
|
13
20
|
## [0.4.2](https://github.com/abruption/agy-cli-usage/compare/v0.4.1...v0.4.2) (2026-06-30)
|
|
14
21
|
|
|
15
22
|
|
package/dist/src/main.d.ts
CHANGED
|
@@ -11,10 +11,18 @@ export interface CliOptions {
|
|
|
11
11
|
version?: boolean;
|
|
12
12
|
help?: boolean;
|
|
13
13
|
}
|
|
14
|
+
/** Exported for direct unit testing (no process.argv/exit side effects). */
|
|
15
|
+
export declare function parseArgs(argv: string[]): CliOptions;
|
|
16
|
+
/** Exported for direct unit testing via an injected `cacheFile` — not part of the CLI's public surface. */
|
|
17
|
+
export declare function readCache(source: SnapshotOptions['source'], channel: SnapshotOptions['channel'], cacheFile?: string): Snapshot | null;
|
|
18
|
+
/** Exported for direct unit testing via an injected `cacheFile` — not part of the CLI's public surface. */
|
|
19
|
+
export declare function writeCache(snap: Snapshot, source: SnapshotOptions['source'], channel: SnapshotOptions['channel'], cacheFile?: string): void;
|
|
14
20
|
/** Subset of options needed to produce a snapshot (also usable from server.ts). */
|
|
15
21
|
export interface SnapshotOptions {
|
|
16
22
|
source: 'auto' | 'api' | 'pty';
|
|
17
23
|
channel: 'auto' | 'daily' | 'prod';
|
|
18
24
|
cache: boolean;
|
|
25
|
+
/** Override the cache file path — for tests only; defaults to the real user cache. */
|
|
26
|
+
cacheFile?: string;
|
|
19
27
|
}
|
|
20
28
|
export declare function getSnapshot(opts: SnapshotOptions): Promise<Snapshot>;
|
package/dist/src/main.js
CHANGED
|
@@ -17,14 +17,18 @@ import { captureUsageViaPty } from './pty-fallback.js';
|
|
|
17
17
|
import { fromApi, fromPty } from './quota.js';
|
|
18
18
|
import { renderPanel } from './render.js';
|
|
19
19
|
import { currentVersion, runUpdate } from './update.js';
|
|
20
|
-
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
20
|
+
import { readFileSync, writeFileSync, mkdirSync, realpathSync } from 'node:fs';
|
|
21
21
|
import { homedir } from 'node:os';
|
|
22
|
-
import { join } from 'node:path';
|
|
22
|
+
import { join, dirname } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
23
24
|
const CACHE_DIR = join(process.env.XDG_CACHE_HOME || join(homedir(), '.cache'), 'agy-usage');
|
|
24
25
|
const CACHE_FILE = join(CACHE_DIR, 'quota.json');
|
|
25
26
|
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
27
|
+
const VALID_SOURCES = ['auto', 'api', 'pty'];
|
|
28
|
+
const VALID_CHANNELS = ['auto', 'daily', 'prod'];
|
|
26
29
|
const errMessage = (e) => (e instanceof Error ? e.message : String(e));
|
|
27
|
-
|
|
30
|
+
/** Exported for direct unit testing (no process.argv/exit side effects). */
|
|
31
|
+
export function parseArgs(argv) {
|
|
28
32
|
const o = {
|
|
29
33
|
json: false, watch: null, source: 'auto', channel: 'auto', cache: true, command: null, check: false,
|
|
30
34
|
};
|
|
@@ -43,10 +47,20 @@ function parseArgs(argv) {
|
|
|
43
47
|
else
|
|
44
48
|
o.watch = 60;
|
|
45
49
|
}
|
|
46
|
-
else if (a === '--source')
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
else if (a === '--source') {
|
|
51
|
+
const v = argv[++i];
|
|
52
|
+
if (!VALID_SOURCES.includes(v)) {
|
|
53
|
+
throw new Error(`invalid --source '${v}' — expected one of: ${VALID_SOURCES.join(', ')}`);
|
|
54
|
+
}
|
|
55
|
+
o.source = v;
|
|
56
|
+
}
|
|
57
|
+
else if (a === '--channel') {
|
|
58
|
+
const v = argv[++i];
|
|
59
|
+
if (!VALID_CHANNELS.includes(v)) {
|
|
60
|
+
throw new Error(`invalid --channel '${v}' — expected one of: ${VALID_CHANNELS.join(', ')}`);
|
|
61
|
+
}
|
|
62
|
+
o.channel = v;
|
|
63
|
+
}
|
|
50
64
|
else if (a === '--no-cache' || a === '--refresh')
|
|
51
65
|
o.cache = false;
|
|
52
66
|
else if (a === '--check')
|
|
@@ -69,22 +83,25 @@ const HELP = `agy-cli-usage — Antigravity CLI (agy) usage/quota monitor
|
|
|
69
83
|
agy-cli-usage update [--check] self-update via npm (--check: report only)
|
|
70
84
|
agy-cli-usage --version | -v
|
|
71
85
|
`;
|
|
72
|
-
|
|
73
|
-
function readCache() {
|
|
86
|
+
/** Exported for direct unit testing via an injected `cacheFile` — not part of the CLI's public surface. */
|
|
87
|
+
export function readCache(source, channel, cacheFile = CACHE_FILE) {
|
|
74
88
|
try {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
return
|
|
89
|
+
const entry = JSON.parse(readFileSync(cacheFile, 'utf8'));
|
|
90
|
+
if (entry.source !== source || entry.channel !== channel)
|
|
91
|
+
return null;
|
|
92
|
+
if (Date.now() - entry.ts < CACHE_TTL_MS)
|
|
93
|
+
return entry.snap;
|
|
78
94
|
}
|
|
79
95
|
catch {
|
|
80
|
-
/* no/expired cache */
|
|
96
|
+
/* no/expired/incompatible-format cache */
|
|
81
97
|
}
|
|
82
98
|
return null;
|
|
83
99
|
}
|
|
84
|
-
|
|
100
|
+
/** Exported for direct unit testing via an injected `cacheFile` — not part of the CLI's public surface. */
|
|
101
|
+
export function writeCache(snap, source, channel, cacheFile = CACHE_FILE) {
|
|
85
102
|
try {
|
|
86
|
-
mkdirSync(
|
|
87
|
-
writeFileSync(
|
|
103
|
+
mkdirSync(dirname(cacheFile), { recursive: true });
|
|
104
|
+
writeFileSync(cacheFile, JSON.stringify({ ts: Date.now(), source, channel, snap }));
|
|
88
105
|
}
|
|
89
106
|
catch {
|
|
90
107
|
/* cache is best-effort */
|
|
@@ -92,7 +109,7 @@ function writeCache(snap) {
|
|
|
92
109
|
}
|
|
93
110
|
export async function getSnapshot(opts) {
|
|
94
111
|
if (opts.cache && opts.source !== 'pty') {
|
|
95
|
-
const cached = readCache();
|
|
112
|
+
const cached = readCache(opts.source, opts.channel, opts.cacheFile);
|
|
96
113
|
if (cached)
|
|
97
114
|
return cached;
|
|
98
115
|
}
|
|
@@ -114,7 +131,7 @@ export async function getSnapshot(opts) {
|
|
|
114
131
|
snap = fromPty(await captureUsageViaPty());
|
|
115
132
|
}
|
|
116
133
|
}
|
|
117
|
-
writeCache(snap);
|
|
134
|
+
writeCache(snap, opts.source, opts.channel, opts.cacheFile);
|
|
118
135
|
return snap;
|
|
119
136
|
}
|
|
120
137
|
// --- main --------------------------------------------------------------------
|
|
@@ -157,13 +174,31 @@ async function main() {
|
|
|
157
174
|
await once(opts);
|
|
158
175
|
}
|
|
159
176
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
177
|
+
// Only run the CLI when this file is executed directly (as the `bin` entry
|
|
178
|
+
// point) — guarded so parseArgs/readCache/writeCache/etc. can be imported
|
|
179
|
+
// for unit testing without triggering a full live CLI run (network calls,
|
|
180
|
+
// process.exit()) as an import side effect. realpathSync resolves symlinks
|
|
181
|
+
// on process.argv[1] (npm global `bin` entries are frequently symlinks);
|
|
182
|
+
// import.meta.url is already symlink-resolved by Node's ESM loader.
|
|
183
|
+
function isMainModule() {
|
|
184
|
+
if (!process.argv[1])
|
|
185
|
+
return false;
|
|
186
|
+
try {
|
|
187
|
+
return fileURLToPath(import.meta.url) === realpathSync(process.argv[1]);
|
|
163
188
|
}
|
|
164
|
-
|
|
165
|
-
|
|
189
|
+
catch {
|
|
190
|
+
return false;
|
|
166
191
|
}
|
|
167
|
-
|
|
168
|
-
|
|
192
|
+
}
|
|
193
|
+
if (isMainModule()) {
|
|
194
|
+
main().catch((err) => {
|
|
195
|
+
if (err instanceof CredentialError) {
|
|
196
|
+
process.stderr.write(`credential error: ${err.message}\n`);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
process.stderr.write(`error: ${errMessage(err)}\n`);
|
|
200
|
+
}
|
|
201
|
+
process.exit(1);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
169
204
|
//# sourceMappingURL=main.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agy-cli-usage",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Headless usage/quota monitor for the Antigravity CLI (agy) — reads Cloud Code quota directly, with a PTY fallback. No IDE required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/src/main.d.ts",
|