@kodo/agent-meter 1.0.0 → 1.0.1

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.
Files changed (3) hide show
  1. package/README.md +21 -5
  2. package/dist/cli.js +56 -2
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,24 +1,32 @@
1
- # agent-meter
1
+ # @kodo/agent-meter
2
2
 
3
3
  CLI tool for managing multiple Codex OAuth accounts and checking their rate limits / usage.
4
4
 
5
+ ![screenshot](assets/screenshot.png)
6
+
5
7
  ## Install
6
8
 
7
9
  ```bash
8
- pnpm install
10
+ npm install -g @kodo/agent-meter
11
+ ```
12
+
13
+ Or run directly with npx:
14
+
15
+ ```bash
16
+ npx @kodo/agent-meter list
9
17
  ```
10
18
 
11
19
  ## Usage
12
20
 
13
21
  ```bash
14
22
  # Add a new account (opens browser for OAuth login, then auto-checks usage)
15
- pnpm dev add
23
+ agent-meter add
16
24
 
17
25
  # List all accounts with real-time usage check
18
- pnpm dev list
26
+ agent-meter list
19
27
 
20
28
  # Remove an account by email
21
- pnpm dev delete <email>
29
+ agent-meter delete <email>
22
30
  ```
23
31
 
24
32
  ## How it works
@@ -28,6 +36,10 @@ pnpm dev delete <email>
28
36
  - `delete` removes the account and its `CODEX_HOME` directory
29
37
  - If a token expires during `list`, you'll be prompted to re-login on the spot
30
38
 
39
+ ## Prerequisites
40
+
41
+ - [Codex CLI](https://github.com/openai/codex) installed and available on PATH
42
+
31
43
  ## Options
32
44
 
33
45
  | Flag | Description |
@@ -35,3 +47,7 @@ pnpm dev delete <email>
35
47
  | `--json` | Output raw JSON |
36
48
  | `--verbose` | Enable verbose logging |
37
49
  | `--data-dir <path>` | Override the default `.data` directory |
50
+
51
+ ## License
52
+
53
+ MIT
package/dist/cli.js CHANGED
@@ -1,19 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
3
5
  import readline from 'node:readline';
4
6
  import { Command } from 'commander';
5
7
  import { createCodexHome, createDataPaths, ensureDataPaths, makeId, markLastUsed, nowIso, normalizeAccount, readStore, removeAccountFromStore, resolveAccountRef, updateAccount, writeStore, } from './core/accounts.js';
6
8
  import { ensureCodexInstalled, loadCredentials, runCodexLogin } from './core/auth.js';
7
9
  import { printJson, renderAccountsTable } from './core/output.js';
8
10
  import { checkAccount } from './core/usage.js';
11
+ const DEFAULT_DATA_DIR = path.join(os.homedir(), '.agent-meter');
9
12
  function resolveDataDir(opts) {
10
13
  if (!opts.dataDir)
11
- return `${process.cwd()}/.data`;
14
+ return DEFAULT_DATA_DIR;
12
15
  const resolved = opts.dataDir.startsWith('/') ? opts.dataDir : `${process.cwd()}/${opts.dataDir}`;
13
16
  return fs.existsSync(resolved) ? fs.realpathSync(resolved) : resolved;
14
17
  }
15
18
  function getStore(opts) {
16
19
  const dataDir = resolveDataDir(opts);
20
+ if (!opts.dataDir) {
21
+ migrateLegacyData(dataDir, Boolean(opts.verbose));
22
+ }
17
23
  const paths = createDataPaths(dataDir);
18
24
  ensureDataPaths(paths);
19
25
  return {
@@ -30,13 +36,61 @@ function confirm(question) {
30
36
  });
31
37
  });
32
38
  }
39
+ function migrateLegacyData(targetDir, verbose) {
40
+ if (fs.existsSync(path.join(targetDir, 'accounts.json')))
41
+ return;
42
+ const legacyDir = path.join(process.cwd(), '.data');
43
+ if (!fs.existsSync(path.join(legacyDir, 'accounts.json')))
44
+ return;
45
+ fs.mkdirSync(targetDir, { recursive: true });
46
+ const copyRecursive = (src, dest) => {
47
+ let stat;
48
+ try {
49
+ stat = fs.statSync(src);
50
+ }
51
+ catch {
52
+ return;
53
+ }
54
+ if (stat.isDirectory()) {
55
+ fs.mkdirSync(dest, { recursive: true });
56
+ for (const child of fs.readdirSync(src)) {
57
+ copyRecursive(path.join(src, child), path.join(dest, child));
58
+ }
59
+ }
60
+ else {
61
+ fs.copyFileSync(src, dest);
62
+ }
63
+ };
64
+ for (const entry of fs.readdirSync(legacyDir)) {
65
+ copyRecursive(path.join(legacyDir, entry), path.join(targetDir, entry));
66
+ }
67
+ // Rewrite codexHome paths in accounts.json to point to the new location
68
+ const accountsFile = path.join(targetDir, 'accounts.json');
69
+ try {
70
+ const raw = JSON.parse(fs.readFileSync(accountsFile, 'utf8'));
71
+ const legacyHomesDir = path.join(legacyDir, 'codex-homes');
72
+ const newHomesDir = path.join(targetDir, 'codex-homes');
73
+ const accounts = Array.isArray(raw?.accounts) ? raw.accounts : (Array.isArray(raw) ? raw : []);
74
+ for (const account of accounts) {
75
+ if (typeof account.codexHome === 'string' && account.codexHome.startsWith(legacyHomesDir)) {
76
+ account.codexHome = account.codexHome.replace(legacyHomesDir, newHomesDir);
77
+ }
78
+ }
79
+ fs.writeFileSync(accountsFile, JSON.stringify(raw, null, 2));
80
+ }
81
+ catch { /* best effort */ }
82
+ if (verbose) {
83
+ process.stderr.write(`Migrated data from ${legacyDir} → ${targetDir}\n`);
84
+ }
85
+ process.stdout.write(`✓ Data migrated from .data/ to ${targetDir}\n`);
86
+ }
33
87
  const program = new Command();
34
88
  program
35
89
  .name('agent-meter')
36
90
  .description('Multi-account Codex OAuth usage checker')
37
91
  .option('--json', 'output JSON')
38
92
  .option('--verbose', 'enable verbose logging')
39
- .option('--data-dir <path>', 'override .data directory');
93
+ .option('--data-dir <path>', `override data directory (default: ~/.agent-meter)`);
40
94
  program
41
95
  .command('add')
42
96
  .description('add a new account via codex login')
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@kodo/agent-meter",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "description": "CLI tool for managing multiple Codex OAuth accounts and checking rate limits",
6
6
  "bin": {
7
- "agent-meter": "./dist/cli.js"
7
+ "agent-meter": "dist/cli.js"
8
8
  },
9
9
  "files": [
10
10
  "dist"