agy-cli-usage 0.2.0 → 0.3.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/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ ## [0.3.0](https://github.com/abruption/agy-cli-usage/compare/v0.2.0...v0.3.0) (2026-06-24)
2
+
3
+
4
+ ### Features
5
+
6
+ * add --version flag and self-update command ([#8](https://github.com/abruption/agy-cli-usage/issues/8)) ([811e82f](https://github.com/abruption/agy-cli-usage/commit/811e82f057e709b92b7a7665b01c54dde913b0d4)), closes [#7](https://github.com/abruption/agy-cli-usage/issues/7)
7
+
8
+
9
+ ### Bug Fixes
10
+
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
+
13
+ ## [0.2.0](https://github.com/abruption/agy-cli-usage/compare/v0.1.0...v0.2.0) (2026-06-24)
14
+
15
+ ### Features
16
+
17
+ * **credentials:** read agy token file for headless Linux (no keyring) ([5914e6c](https://github.com/abruption/agy-cli-usage/commit/5914e6cc3cf3977bb6c6f974f68bd40209bc376e))
18
+
19
+ ## [0.1.0](https://github.com/abruption/agy-cli-usage/compare/e1d582dd618fe06fd607d00846f5b7a66acf924d...v0.1.0) (2026-06-24)
20
+
21
+ ### Features
22
+
23
+ * headless usage/quota monitor for Antigravity CLI (agy) ([e1d582d](https://github.com/abruption/agy-cli-usage/commit/e1d582dd618fe06fd607d00846f5b7a66acf924d))
package/README.md CHANGED
@@ -73,12 +73,14 @@ npm run check # 구문 검사
73
73
  ```
74
74
 
75
75
  - **CI** (`.github/workflows/ci.yml`): push/PR마다 ubuntu(Node 18/20/22) + macOS/Windows(Node 22)에서 테스트.
76
- - **Release** (`.github/workflows/release.yml`): `v*` 태그 push 빌드·테스트 후 npm publish(provenance) + GitHub Release 생성. `NPM_TOKEN` 시크릿 필요.
76
+ - **Release** ([release-please](https://github.com/googleapis/release-please), `.github/workflows/release-please.yml`): Conventional Commits 기반 **완전 자동화**. `NPM_TOKEN` 시크릿 필요.
77
77
 
78
- ```bash
79
- npm version patch # package.json 버전 +0.0.1 & v* 태그 생성
80
- git push --follow-tags # Release 워크플로 실행 npm 자동 배포
81
- ```
78
+ 릴리스 절차 — 수동 버전 범프 없음:
79
+
80
+ 1. `feat:`/`fix:` 등 Conventional Commits를 main에 머지하면, release-please가 **Release PR**(버전 범프 + CHANGELOG 갱신)을 자동 생성·유지.
81
+ 2. 그 **Release PR을 머지**하면 → GitHub Release + 태그 생성 → 같은 워크플로가 `npm publish --provenance` 실행.
82
+
83
+ > 즉 "Release PR 머지" 한 번이 전체 배포다.
82
84
 
83
85
  ## 주의
84
86
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agy-cli-usage",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
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
  "bin": {
@@ -20,6 +20,7 @@
20
20
  "src/",
21
21
  "server.js",
22
22
  "README.md",
23
+ "CHANGELOG.md",
23
24
  "LICENSE"
24
25
  ],
25
26
  "keywords": [
package/src/main.js CHANGED
@@ -9,12 +9,15 @@
9
9
  // agy-usage --channel daily|prod Cloud Code host (default: auto-detect)
10
10
  // agy-usage --no-cache bypass the 5-minute cache
11
11
  // agy-usage --refresh force a fresh fetch (alias for --no-cache)
12
+ // agy-usage update [--check] self-update via npm
13
+ // agy-usage --version | -v print the installed version
12
14
 
13
15
  import { getAccessToken, CredentialError } from './credentials.js';
14
16
  import { fetchQuotaSummary } from './api.js';
15
17
  import { captureUsageViaPty } from './pty-fallback.js';
16
18
  import { fromApi, fromPty } from './quota.js';
17
19
  import { renderPanel } from './render.js';
20
+ import { currentVersion, runUpdate } from './update.js';
18
21
  import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
19
22
  import { homedir } from 'node:os';
20
23
  import { join } from 'node:path';
@@ -24,16 +27,19 @@ const CACHE_FILE = join(CACHE_DIR, 'quota.json');
24
27
  const CACHE_TTL_MS = 5 * 60 * 1000;
25
28
 
26
29
  function parseArgs(argv) {
27
- const o = { json: false, watch: null, source: 'auto', channel: 'auto', cache: true };
30
+ const o = { json: false, watch: null, source: 'auto', channel: 'auto', cache: true, command: null, check: false };
28
31
  for (let i = 0; i < argv.length; i++) {
29
32
  const a = argv[i];
30
- if (a === '--json') o.json = true;
33
+ if (a === 'update' && o.command == null) o.command = 'update';
34
+ else if (a === '--json') o.json = true;
31
35
  else if (a === '--watch') {
32
36
  const n = Number(argv[i + 1]);
33
37
  if (Number.isFinite(n)) { o.watch = n; i++; } else o.watch = 60;
34
38
  } else if (a === '--source') o.source = argv[++i];
35
39
  else if (a === '--channel') o.channel = argv[++i];
36
40
  else if (a === '--no-cache' || a === '--refresh') o.cache = false;
41
+ else if (a === '--check') o.check = true;
42
+ else if (a === '-v' || a === '--version') o.version = true;
37
43
  else if (a === '-h' || a === '--help') o.help = true;
38
44
  }
39
45
  return o;
@@ -47,6 +53,8 @@ const HELP = `agy-usage — Antigravity CLI (agy) usage/quota monitor
47
53
  agy-usage --source <auto|api|pty>
48
54
  agy-usage --channel <auto|daily|prod>
49
55
  agy-usage --no-cache | --refresh
56
+ agy-usage update [--check] self-update via npm (--check: report only)
57
+ agy-usage --version | -v
50
58
  `;
51
59
 
52
60
  // --- cache -------------------------------------------------------------------
@@ -104,6 +112,8 @@ async function once(opts) {
104
112
  async function main() {
105
113
  const opts = parseArgs(process.argv.slice(2));
106
114
  if (opts.help) { process.stdout.write(HELP); return; }
115
+ if (opts.version) { process.stdout.write(currentVersion() + '\n'); return; }
116
+ if (opts.command === 'update') { process.exit(await runUpdate({ checkOnly: opts.check })); }
107
117
 
108
118
  if (opts.watch != null) {
109
119
  const intervalMs = Math.max(5, opts.watch) * 1000;
package/src/update.js ADDED
@@ -0,0 +1,87 @@
1
+ // Self-update + version helpers for the CLI.
2
+ //
3
+ // `agy-cli-usage update` check the registry and `npm install -g` if newer
4
+ // `agy-cli-usage update --check` report only, don't install
5
+ // `agy-cli-usage --version` print the installed version
6
+
7
+ import { execFileSync, spawnSync } from 'node:child_process';
8
+ import { readFileSync } from 'node:fs';
9
+
10
+ const PKG_NAME = 'agy-cli-usage';
11
+
12
+ /** Installed version, read from this package's package.json. */
13
+ export function currentVersion() {
14
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
15
+ return pkg.version;
16
+ }
17
+
18
+ /**
19
+ * Compare two dotted versions numerically (prerelease tags ignored).
20
+ * @returns negative if a<b, 0 if equal, positive if a>b
21
+ */
22
+ export function semverCompare(a, b) {
23
+ const norm = (v) =>
24
+ String(v)
25
+ .replace(/^v/, '')
26
+ .split('-')[0]
27
+ .split('.')
28
+ .map((n) => parseInt(n, 10) || 0);
29
+ const pa = norm(a);
30
+ const pb = norm(b);
31
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
32
+ const d = (pa[i] || 0) - (pb[i] || 0);
33
+ if (d !== 0) return d;
34
+ }
35
+ return 0;
36
+ }
37
+
38
+ /** Latest published version: prefer the user's configured registry (npm view), fall back to public. */
39
+ export async function latestVersion() {
40
+ try {
41
+ const out = execFileSync('npm', ['view', PKG_NAME, 'version'], {
42
+ encoding: 'utf8',
43
+ stdio: ['ignore', 'pipe', 'ignore'],
44
+ }).trim();
45
+ if (out) return out;
46
+ } catch {
47
+ // npm missing or offline — try the public registry directly
48
+ }
49
+ try {
50
+ const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`);
51
+ if (res.ok) return (await res.json()).version;
52
+ } catch {
53
+ // offline
54
+ }
55
+ return null;
56
+ }
57
+
58
+ /**
59
+ * Run the update flow.
60
+ * @param {{ checkOnly?: boolean }} opts
61
+ * @returns {Promise<number>} process exit code
62
+ */
63
+ export async function runUpdate({ checkOnly = false } = {}) {
64
+ const current = currentVersion();
65
+ const latest = await latestVersion();
66
+ if (!latest) {
67
+ process.stderr.write('Could not determine the latest version (offline or npm unavailable).\n');
68
+ return 1;
69
+ }
70
+ if (semverCompare(latest, current) <= 0) {
71
+ process.stdout.write(`agy-cli-usage is up to date (${current}).\n`);
72
+ return 0;
73
+ }
74
+ process.stdout.write(`Update available: ${current} -> ${latest}\n`);
75
+ if (checkOnly) {
76
+ process.stdout.write('Run `agy-cli-usage update` to install it.\n');
77
+ return 0;
78
+ }
79
+ process.stdout.write(`Installing ${PKG_NAME}@${latest} globally…\n`);
80
+ const r = spawnSync('npm', ['install', '-g', `${PKG_NAME}@${latest}`], { stdio: 'inherit' });
81
+ if (r.error) {
82
+ process.stderr.write(`Failed to run npm: ${r.error.message}\nInstall manually: npm install -g ${PKG_NAME}@latest\n`);
83
+ return 1;
84
+ }
85
+ if (r.status === 0) process.stdout.write(`Updated to ${latest}.\n`);
86
+ return r.status ?? 0;
87
+ }