oc2token 0.1.0 → 0.1.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 (71) hide show
  1. package/README.md +40 -15
  2. package/dist/src/accounting/index.d.ts +1 -1
  3. package/dist/src/accounting/index.js +1 -1
  4. package/dist/src/accounting/index.js.map +1 -1
  5. package/dist/src/accounting/reducer.d.ts +1 -2
  6. package/dist/src/accounting/reducer.js +0 -22
  7. package/dist/src/accounting/reducer.js.map +1 -1
  8. package/dist/src/antigravity/discovery.d.ts +4 -0
  9. package/dist/src/antigravity/discovery.js +25 -2
  10. package/dist/src/antigravity/discovery.js.map +1 -1
  11. package/dist/src/antigravity/scanner.js +173 -156
  12. package/dist/src/antigravity/scanner.js.map +1 -1
  13. package/dist/src/application.js +87 -75
  14. package/dist/src/application.js.map +1 -1
  15. package/dist/src/cache/lock.js +4 -1
  16. package/dist/src/cache/lock.js.map +1 -1
  17. package/dist/src/cache/schema.js +13 -1
  18. package/dist/src/cache/schema.js.map +1 -1
  19. package/dist/src/cache/store.d.ts +1 -0
  20. package/dist/src/cache/store.js +27 -0
  21. package/dist/src/cache/store.js.map +1 -1
  22. package/dist/src/cli.js +174 -46
  23. package/dist/src/cli.js.map +1 -1
  24. package/dist/src/codex/discovery.d.ts +4 -0
  25. package/dist/src/codex/discovery.js +59 -47
  26. package/dist/src/codex/discovery.js.map +1 -1
  27. package/dist/src/codex/scanner.js +37 -11
  28. package/dist/src/codex/scanner.js.map +1 -1
  29. package/dist/src/collector/collector.js +44 -14
  30. package/dist/src/collector/collector.js.map +1 -1
  31. package/dist/src/collector/types.d.ts +8 -0
  32. package/dist/src/collector/types.js.map +1 -1
  33. package/dist/src/dashboard/render/dashboard.js +18 -5
  34. package/dist/src/dashboard/render/dashboard.js.map +1 -1
  35. package/dist/src/dashboard/render/format.d.ts +4 -0
  36. package/dist/src/dashboard/render/format.js +9 -0
  37. package/dist/src/dashboard/render/format.js.map +1 -1
  38. package/dist/src/dashboard/render/types.d.ts +14 -0
  39. package/dist/src/dashboard/render/types.js +40 -13
  40. package/dist/src/dashboard/render/types.js.map +1 -1
  41. package/dist/src/dashboard/scheduler/refresh-scheduler.js +2 -1
  42. package/dist/src/dashboard/scheduler/refresh-scheduler.js.map +1 -1
  43. package/dist/src/dashboard/settings/index.js +29 -4
  44. package/dist/src/dashboard/settings/index.js.map +1 -1
  45. package/dist/src/dashboard/state/refresh-coordinator.d.ts +7 -0
  46. package/dist/src/dashboard/state/refresh-coordinator.js +30 -0
  47. package/dist/src/dashboard/state/refresh-coordinator.js.map +1 -1
  48. package/dist/src/domain/records.d.ts +15 -1
  49. package/dist/src/domain/records.js +15 -1
  50. package/dist/src/domain/records.js.map +1 -1
  51. package/dist/src/domain/tokens.d.ts +12 -0
  52. package/dist/src/domain/tokens.js +19 -3
  53. package/dist/src/domain/tokens.js.map +1 -1
  54. package/dist/src/domain/windows.js +37 -13
  55. package/dist/src/domain/windows.js.map +1 -1
  56. package/dist/src/opencode/adapter.js +12 -3
  57. package/dist/src/opencode/adapter.js.map +1 -1
  58. package/dist/src/opencode/client.d.ts +10 -0
  59. package/dist/src/opencode/client.js +17 -3
  60. package/dist/src/opencode/client.js.map +1 -1
  61. package/dist/src/opencode/stats.js +33 -9
  62. package/dist/src/opencode/stats.js.map +1 -1
  63. package/dist/src/opencode/transport.d.ts +10 -0
  64. package/dist/src/opencode/transport.js +23 -9
  65. package/dist/src/opencode/transport.js.map +1 -1
  66. package/dist/src/output/table.js +6 -2
  67. package/dist/src/output/table.js.map +1 -1
  68. package/dist/src/pricing/pricing.d.ts +30 -0
  69. package/dist/src/pricing/pricing.js +67 -27
  70. package/dist/src/pricing/pricing.js.map +1 -1
  71. package/package.json +32 -7
package/README.md CHANGED
@@ -44,7 +44,7 @@ OpenCode 2 records rich token telemetry locally, but the raw message stream is n
44
44
  - **Trend sparkline** per window, not one row per bucket
45
45
  - **Privacy by design** — only normalized token counters are cached; no prompts, tool inputs, or session titles are stored
46
46
  - **Resilient collection** — paginated assistant-message aggregation with retry, dedup by `tokenRevision`, fallback when the filtered stats API ignores the range
47
- - **Scriptable** — stable JSON `schemaVersion: 3`, deterministic table output, exit codes `0` / `1` / `3`
47
+ - **Scriptable** — stable JSON `schemaVersion: 4`, deterministic table output, exit codes `0` / `1` / `3`
48
48
 
49
49
  ---
50
50
 
@@ -163,7 +163,7 @@ oc2token --no-color # or NO_COLOR=1 for plain output
163
163
  | `?` | Help |
164
164
  | `q` / `Ctrl+C` | Quit |
165
165
 
166
- Settings persist under the cache directory (`~/.cache/oc2token` on macOS/Linux or `$XDG_CACHE_HOME`). At least one provider must stay enabled.
166
+ Settings persist under the cache directory (`~/Library/Caches/oc2token` on macOS by default; `$XDG_CACHE_HOME/oc2token` when `XDG_CACHE_HOME` is set, otherwise `~/Library/Caches/oc2token` — see `src/application.ts:47-50`). Override with `--cache-dir`. At least one provider must stay enabled.
167
167
 
168
168
  **Theme.** Purple carries structure, orange carries activity and focus, cyan carries inputs. Respects `NO_COLOR` and `--no-color`.
169
169
 
@@ -172,7 +172,7 @@ Settings persist under the cache directory (`~/.cache/oc2token` on macOS/Linux o
172
172
  ## 🖥️ CLI reference
173
173
 
174
174
  ```
175
- oc2token 0.1.0
175
+ oc2token 0.1.1
176
176
 
177
177
  Usage:
178
178
  oc2token [hour|day|week]
@@ -183,7 +183,7 @@ Options:
183
183
  --once Collect once and exit
184
184
  --json Emit stable JSON and exit
185
185
  --format <mode> auto, dashboard, table, or json
186
- --refresh <seconds> Auto-refresh cadence; 0 is manual-only (60–14400)
186
+ --refresh <seconds> Auto-refresh cadence; 0 is manual-only (0 or 60–14400)
187
187
  --timezone <IANA> Zone for local day / ISO week boundaries
188
188
  --project <id> Restrict collection to an OpenCode project
189
189
  --cache-dir <path> Override the normalized metadata cache directory
@@ -201,6 +201,14 @@ Options:
201
201
  | `1` | Connection / validation / usage error |
202
202
  | `3` | Partial results — JSON emitted but coverage incomplete |
203
203
 
204
+ ### 💰 Costs (estimates only)
205
+
206
+ `costs`, `costsByProvider`, `costsByProject`, and per-breakdown `cost` fields are **rough USD estimates**, not bills. Pricing is compiled from public provider pages **as of 2026-09-02** (`src/pricing/pricing.ts:11-16`); rates change without notice and subscription/Zen at-cost pricing may differ from what you actually pay.
207
+
208
+ - Unknown models return `undefined` pricing (`pricingForModel` → `undefined`), surfaced as `null` cost in JSON. There is **no generic fallback price** — an unknown model contributes tokens but no dollars.
209
+ - `estimatedCostForBreakdowns(breakdowns, strict=true)` returns `undefined` if **any** model is unknown; the non-strict/partial variant skips unknown models instead. Window-level `costs` use the partial (skip-unknown) aggregation.
210
+ - `recorded_total` remains the source of truth for usage; costs are a convenience overlay.
211
+
204
212
  ### Filtering providers
205
213
 
206
214
  ```sh
@@ -224,7 +232,7 @@ oc2token --once --json --source codex | jq .totals.day.recorded_total
224
232
  |----------|--------|-----------|
225
233
  | **opencode** | OpenCode 2 local service (`@opencode-ai/client`) | session/message pagination with `tokenRevision` dedup |
226
234
  | **codex** | `~/.codex/sessions` rollouts (JSONL) | file scan + parse |
227
- | **antigravity** | Antigravity SQLite + session JSON | proto + scanner |
235
+ | **antigravity** | Antigravity SQLite (`gen_metadata` protobuf via `node:sqlite` + `src/antigravity/proto.ts`) | proto + scanner |
228
236
 
229
237
  All three emit the same `UsageRecord` shape and are merged by `Aggregator → CachedUsageSource → Dashboard`. `doctor` reports each independently:
230
238
 
@@ -250,28 +258,33 @@ oc2token --format table
250
258
 
251
259
  <p align="center"><img src="assets/screenshots/table.svg" width="100%" alt="Table output" /></p>
252
260
 
253
- ### JSON (`schemaVersion: 3`)
261
+ ### JSON (`schemaVersion: 4`)
254
262
 
255
263
  ```sh
256
264
  oc2token --json | jq .
257
265
  oc2token --once --json > snapshot.json
258
266
  ```
259
267
 
260
- Emits **all three windows**, `totalsByProvider`/`totalsByProject`, trends, and coverage in one stable contract:
268
+ Emits **all three windows**, `costs`, `totalsByProvider`/`totalsByProject`, `trends`, and coverage in one stable contract:
261
269
 
262
270
  ```json
263
271
  {
264
- "schemaVersion": 3,
272
+ "schemaVersion": 4,
265
273
  "source": "unified",
266
- "version": "0.1.0",
274
+ "version": "0.1.1",
267
275
  "windows": { "hour": { "kind": "hour", "from": "…", "to": "…", "label": "last 60 minutes" }, "day": {}, "week": {} },
268
276
  "totals": { "hour": { "recorded_total": 15582 }, "day": {}, "week": {} },
269
- "providersByWindow": { "day": [ { "name": "openai", "totals": {} } ] },
270
- "totalsByProvider": { "day": { "openai": { "recorded_total": 21785 } } },
277
+ "costs": { "hour": 0.042, "day": null, "week": null },
278
+ "trends": { "hour": [{ "label": "…", "totals": {}, "from": "…", "to": "…" }], "day": [], "week": [] },
279
+ "providersByWindow": { "day": [ { "name": "opencode", "totals": {}, "cost": 0.01 } ] },
280
+ "totalsByProvider": { "day": { "opencode": { "recorded_total": 21785 } } },
281
+ "totalsByProject": { "day": { "/Users/you/project": { "recorded_total": 9001 } } },
271
282
  "coverage": { "complete": true, "sessionsScanned": 14, "sessionsDiscovered": 14 }
272
283
  }
273
284
  ```
274
285
 
286
+ > `costs` / `cost` fields are **estimates only** (see [Costs](#-costs-estimates-only)). Unknown models yield `null`/`undefined` cost, never a guessed price. `totalsByProject` keys are absolute project paths — treat snapshots as containing PII if you share them.
287
+
275
288
  Use `--format json` for pretty-printed JSON without exiting interactive mode fallback.
276
289
 
277
290
  ---
@@ -281,8 +294,8 @@ Use `--format json` for pretty-printed JSON without exiting interactive mode fal
281
294
  | Option | CLI | Env / Persisted |
282
295
  |--------|-----|-----------------|
283
296
  | Timezone | `--timezone Europe/Berlin` | Local system zone by default; validated as IANA |
284
- | Refresh | `--refresh 300` (60–14400, `0` manual) | Persisted via Settings panel (`s`) |
285
- | Cache dir | `--cache-dir /tmp/oc2` | `~/.cache/oc2token` / `$XDG_CACHE_HOME/oc2token` |
297
+ | Refresh | `--refresh 300` (`0` manual-only, or 60–14400) | Persisted via Settings panel (`s`) |
298
+ | Cache dir | `--cache-dir /tmp/oc2` | `~/Library/Caches/oc2token`, or `$XDG_CACHE_HOME/oc2token` when set |
286
299
  | Project filter | `--project my-project` | Scopes OpenCode collection only |
287
300
  | Providers | `--source codex` | Persisted via Settings panel |
288
301
  | Color | `--no-color` | `NO_COLOR=1` disables all ANSI |
@@ -303,6 +316,18 @@ It **does not** persist:
303
316
 
304
317
  All collection is local-first; no network calls besides the loopback OpenCode service.
305
318
 
319
+ ### Paths are PII
320
+
321
+ `project` is persisted as an **absolute filesystem path** (e.g. `/Users/you/work/client-app`) in the normalized cache, in `--json` output (`totalsByProject`, `projects*`), and in table/dashboard project rows. Sharing a snapshot, cache directory, or screenshot exposes your directory layout and username. There is **no `--redact-projects` flag** — if you need to share output, scrub paths manually before posting.
322
+
323
+ ### Snapshot sanitizer is denylist-based
324
+
325
+ `src/cache/schema.ts:47,225-259` strips known-sensitive keys (`prompt`, `tool_input/output`, `api_key`, `authorization`, `password`, `secret`, `session_title/name`, `raw_content`, plus `content`/`parts`/`title`) from cached snapshots. This is a **denylist, not an allowlist**: a future field with a novel sensitive name would pass through. Treat the cache as usage-metadata-only by construction (records go through `normalizeRecord`), and review sanitizer keys when new snapshot fields are added.
326
+
327
+ ### `doctor` prints the endpoint
328
+
329
+ `oc2token doctor` prints `Endpoint: <url>` (loopback server URL) and per-provider status lines. The URL itself is not a credential (auth headers are never printed), but redact it in public bug reports anyway.
330
+
306
331
  ---
307
332
 
308
333
  ## 🧭 How it works
@@ -319,7 +344,7 @@ All collection is local-first; no network calls besides the loopback OpenCode se
319
344
  │ Aggregator │ dedup by sessionID/messageID + tokenRevision
320
345
  └──────┬──────┘
321
346
  ▼
322
- ┌──────────────┐ file lock · schema 1 · atomic writes
347
+ ┌──────────────┐ file lock · schema 2 · atomic writes
323
348
  │ CachedUsage │
324
349
  └──────┬──────┘
325
350
  ▼
@@ -352,7 +377,7 @@ src/
352
377
  opencode/ transport & doctor
353
378
  codex/ rollout discovery & scanner
354
379
  antigravity/ sqlite + proto + scanner
355
- cache/ filesystem lock & store (schema 1)
380
+ cache/ filesystem lock & store (schema 2)
356
381
  dashboard/ render, state, settings
357
382
  domain/ windows, tokens, records, contracts
358
383
  output/ dashboard / table / json renderers
@@ -1 +1 @@
1
- export { UsageRecordReducer, compareFreshness, reduceUsageRecords, sumRecordComponents, } from "./reducer.js";
1
+ export { UsageRecordReducer, compareFreshness, reduceUsageRecords, } from "./reducer.js";
@@ -1,2 +1,2 @@
1
- export { UsageRecordReducer, compareFreshness, reduceUsageRecords, sumRecordComponents, } from "./reducer.js";
1
+ export { UsageRecordReducer, compareFreshness, reduceUsageRecords, } from "./reducer.js";
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/accounting/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/accounting/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type UsageTotals } from "../domain/index.js";
1
+ import type { UsageTotals } from "../domain/index.js";
2
2
  import { type UsageRecord, type UsageWindow } from "../domain/index.js";
3
3
  /**
4
4
  * A deterministic, synchronous reducer for usage records.
@@ -18,4 +18,3 @@ export declare class UsageRecordReducer {
18
18
  }
19
19
  export declare function compareFreshness(left: UsageRecord, right: UsageRecord): number;
20
20
  export declare function reduceUsageRecords(records: ReadonlyArray<UsageRecord>): ReadonlyArray<UsageRecord>;
21
- export declare function sumRecordComponents(records: ReadonlyArray<UsageRecord>): UsageTotals;
@@ -1,6 +1,4 @@
1
- import { parseTokenComponents, toUsageTotals, } from "../domain/index.js";
2
1
  import { sumUsageRecords, } from "../domain/index.js";
3
- const COMPONENTS = ["input", "output", "reasoning", "cacheRead", "cacheWrite"];
4
2
  function compareRevision(left, right) {
5
3
  if (left === right) {
6
4
  return 0;
@@ -82,24 +80,4 @@ export function reduceUsageRecords(records) {
82
80
  reducer.upsertMany(records);
83
81
  return reducer.records();
84
82
  }
85
- export function sumRecordComponents(records) {
86
- const totals = {
87
- input: 0,
88
- output: 0,
89
- reasoning: 0,
90
- cacheRead: 0,
91
- cacheWrite: 0,
92
- };
93
- for (const record of records) {
94
- const normalized = parseTokenComponents(record);
95
- for (const component of COMPONENTS) {
96
- const next = totals[component] + normalized[component];
97
- if (!Number.isSafeInteger(next)) {
98
- throw new RangeError(`Summing ${component} exceeds the safe integer range`);
99
- }
100
- totals[component] = next;
101
- }
102
- }
103
- return toUsageTotals(totals);
104
- }
105
83
  //# sourceMappingURL=reducer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reducer.js","sourceRoot":"","sources":["../../../src/accounting/reducer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reducer.js","sourceRoot":"","sources":["../../../src/accounting/reducer.ts"],"names":[],"mappings":"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"}
@@ -14,5 +14,9 @@ export declare function defaultAntigravityHome(): string;
14
14
  * `resolveAntigravityHome` or explicit `root` parameter.
15
15
  * For test fixtures `ANTIGRAVITY_HOME` may point directly to a directory
16
16
  * containing `*.db` files — that directory is scanned as well.
17
+ *
18
+ * Scans are flat (no recursion, fixed known subpaths), symlinks are skipped
19
+ * via withFileTypes (never followed), and results are capped at
20
+ * MAX_DATABASE_FILES so huge homes fail bounded instead of hanging.
17
21
  */
18
22
  export declare function discoverAntigravityDatabases(root?: string): string[];
@@ -14,6 +14,9 @@ function resolveAntigravityHome(root) {
14
14
  }
15
15
  return defaultAntigravityHome();
16
16
  }
17
+ /** Bounds so a huge $HOME can never hang discovery. */
18
+ const MAX_DATABASE_FILES = 5_000;
19
+ const MAX_ENTRIES_PER_DIR = 10_000;
17
20
  /**
18
21
  * Scan Antigravity SQLite conversation databases.
19
22
  *
@@ -29,20 +32,36 @@ function resolveAntigravityHome(root) {
29
32
  * `resolveAntigravityHome` or explicit `root` parameter.
30
33
  * For test fixtures `ANTIGRAVITY_HOME` may point directly to a directory
31
34
  * containing `*.db` files — that directory is scanned as well.
35
+ *
36
+ * Scans are flat (no recursion, fixed known subpaths), symlinks are skipped
37
+ * via withFileTypes (never followed), and results are capped at
38
+ * MAX_DATABASE_FILES so huge homes fail bounded instead of hanging.
32
39
  */
33
40
  export function discoverAntigravityDatabases(root) {
34
41
  const base = resolveAntigravityHome(root);
35
42
  const seen = new Set();
36
43
  const result = [];
37
44
  const tryDir = (dir) => {
45
+ if (result.length >= MAX_DATABASE_FILES)
46
+ return;
38
47
  let entries;
39
48
  try {
40
- entries = readdirSync(dir);
49
+ entries = readdirSync(dir, { withFileTypes: true });
41
50
  }
42
51
  catch {
43
52
  return;
44
53
  }
45
- for (const file of entries) {
54
+ let scanned = 0;
55
+ for (const entry of entries) {
56
+ if (result.length >= MAX_DATABASE_FILES)
57
+ return;
58
+ if (scanned >= MAX_ENTRIES_PER_DIR)
59
+ break;
60
+ scanned += 1;
61
+ // Never follow symlinks; only regular files can be databases.
62
+ if (entry.isSymbolicLink() || !entry.isFile())
63
+ continue;
64
+ const file = entry.name;
46
65
  // Only *.db — ignore -shm/-wal sidecars and .pb files
47
66
  if (!file.toLowerCase().endsWith(".db")) {
48
67
  continue;
@@ -82,9 +101,13 @@ export function discoverAntigravityDatabases(root) {
82
101
  join("antigravity-ide", "implicit"),
83
102
  ];
84
103
  for (const rel of relativeFromHomedir) {
104
+ if (result.length >= MAX_DATABASE_FILES)
105
+ break;
85
106
  tryDir(join(base, rel));
86
107
  }
87
108
  for (const rel of relativeFromGemini) {
109
+ if (result.length >= MAX_DATABASE_FILES)
110
+ break;
88
111
  tryDir(join(base, rel));
89
112
  }
90
113
  // Also handle case where base is already a .gemini/antigravity-cli/conversations path's parent
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/antigravity/discovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/antigravity/discovery.ts"],"names":[],"mappings":"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"}