@1930dev/opencode-usage 0.1.0 → 0.1.2

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 +58 -34
  2. package/dist/cli.js +7 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # opencode-usage
2
2
 
3
- Usage tracking, cost estimation, and model ranking CLI for [opencode](https://opencode.ai).
3
+ Usage tracking, budget percentages and model ranking for [opencode](https://opencode.ai):
4
+ a CLI, and a `/usage` slash command for the TUI.
4
5
 
5
6
  ## Install
6
7
 
@@ -15,14 +16,22 @@ Requires [Bun](https://bun.sh): the CLI reads opencode's SQLite through `bun:sql
15
16
  ```bash
16
17
  # Local usage from opencode's SQLite (all providers, all projects)
17
18
  opencode-usage usage # last 7 days, grouped by provider
19
+
20
+ # Window
18
21
  opencode-usage usage --today # today only
19
22
  opencode-usage usage --since 30d # last 30 days
20
- opencode-usage usage --by model # group by model instead of provider
21
- opencode-usage usage --by project # group by project directory
22
- opencode-usage usage --by agent # group by agent (build/plan/etc)
23
- opencode-usage usage --pct # add % BUDGET column (requires --by provider)
24
- # --by provider lists every connected provider, including those idle in the window
25
- opencode-usage usage --json # machine-readable output
23
+
24
+ # Grouping
25
+ opencode-usage usage --by agent # by agent (build/plan/etc)
26
+ opencode-usage usage --by day # by day
27
+ opencode-usage usage --by model # by model
28
+ opencode-usage usage --by project # by project directory
29
+ opencode-usage usage --by provider # the default; lists every connected
30
+ # provider, idle ones included
31
+
32
+ # Output
33
+ opencode-usage usage --json # machine-readable
34
+ opencode-usage usage --pct # add the % BUDGET column (--by provider only)
26
35
 
27
36
  # Connected providers + live quota
28
37
  opencode-usage providers
@@ -74,19 +83,20 @@ Restart opencode after a rebuild: the bundle is read once at start.
74
83
  Normalized percentage of budget consumed per provider, from these sources (in priority):
75
84
 
76
85
  1. **Live quota** — provider-reported usage:
77
- - `opencode-go` (Zen): rolling 5h / weekly / monthly % (binding window)
78
86
  - `github-copilot`: premium requests entitlement (7000/mo)
87
+ - `opencode-go` (Zen): rolling 5h / weekly / monthly % (binding window)
79
88
  - `openrouter`: credits used / total credits
80
89
  - `zai`: coding plan quota
81
90
 
82
- 2. **Documented limits** — monthly equivalent of daily limits:
83
- - `groq`: 200k tokens/day 6M/month
84
- - `google`: 1500 requests/day 45k/month
85
- - `digitalocean`: 5M tokens/day → 150M/month
86
- - `cerebras`: 1M tokens/day 30M/month
87
- - `google` (Gemini free): 1500 requests/day 45k/month
88
- - `groq`: 200k tokens/day 6M/month
89
- - `cerebras`: 1M tokens/day → 30M/month
91
+ 2. **Documented limits** — published quotas, used when the provider reports none:
92
+ - `cerebras`: 1M tokens/day (free tier)
93
+ - `cloudflare-workers-ai`: 100k neurons/day (free tier)
94
+ - `digitalocean`: 5M tokens/day (paid)
95
+ - `google`: 1500 requests/day (free tier)
96
+ - `groq`: 200k tokens/day (free tier)
97
+ - `nvidia`: 1000 credits/month (free tier)
98
+ - `orcarouter`: undocumented
99
+ - `snowflake-cortex`: 100 credits/month (paid)
90
100
 
91
101
  3. **budgets.json** — your monthly USD per provider:
92
102
  ```json
@@ -108,36 +118,50 @@ glm-5.3-flash GLM 5.3-Flash 58 72 $0.11 534.9
108
118
  ...
109
119
  ```
110
120
 
111
- Data from [Artificial Analysis](https://artificialanalysis.ai) (Intelligence Index v4.1) + [models.dev](https://models.dev) pricing.
121
+ Intelligence indices from [Artificial Analysis](https://artificialanalysis.ai), pricing
122
+ from [models.dev](https://models.dev).
123
+
124
+ `top` needs an `AA_API_KEY` for the indices. This package ships neither a key nor a copy
125
+ of the data: the free Data API tier is "internal use only; no redistribution", and
126
+ attribution is required on every tier — which is why the credit is printed under the
127
+ table and carried in `--json`.
112
128
 
113
129
  ## Requirements
114
130
 
115
- - [Bun](https://bun.sh) 1.0
116
- - [opencode](https://opencode.ai) with existing sessions (reads `~/.local/share/opencode/opencode.db`)
117
- - For live quota: credentials already configured in opencode (`~/.local/share/opencode/auth.json`)
131
+ - [Bun](https://bun.sh) >= 1.0 — the CLI reads opencode's SQLite through `bun:sqlite`
132
+ - [opencode](https://opencode.ai) with existing sessions, at
133
+ `~/.local/share/opencode/opencode.db`
134
+ - For live quota: provider credentials already configured in opencode, at
135
+ `~/.local/share/opencode/auth.json`
118
136
 
119
137
  ## Configuration
120
138
 
121
- - `OPENCODE_DB_PATH` — override opencode database path
122
- - `OPENCODE_AUTH_PATH` override auth.json path
123
- - `OPENCODE_IMP_CACHE` cache directory (default `~/.cache/opencode-usage`)
124
- - `OPENCODE_IMP_BUDGETS` — budgets.json path
125
- - `AA_API_KEY` — Artificial Analysis API key, used by `top`. Without it, ranking is skipped
126
- - `INFISICAL_PROJECT_ID` — optional: read `AA_API_KEY` from Infisical through the
127
- `infisical-secret` wrapper instead of from the environment
139
+ - `AA_API_KEY` — Artificial Analysis key, used by `top` for the intelligence indices.
140
+ Optional: without it `top` still prints prices, only without `IQ` and `IQ/$`.
141
+ A free key is at [artificialanalysis.ai/data-api](https://artificialanalysis.ai/data-api)
142
+ - `OPENCODE_AUTH_PATH` — override the path to opencode's `auth.json`
143
+ - `OPENCODE_DB_PATH` — override the path to opencode's database
144
+ - `OPENCODE_USAGE_BUDGETS` — override the path to `budgets.json`
145
+ - `OPENCODE_USAGE_CACHE` cache directory (default `~/.cache/opencode-usage`)
128
146
 
129
147
  ## Development
130
148
 
131
149
  ```bash
132
- bun install # install workspace deps
133
- bun test # run tests
134
- bunx tsc --noEmit # typecheck
150
+ bun install # install workspace deps
151
+ bun run build # write dist/tui.js and dist/cli.js
152
+ bun run preview # render the /usage dialog headless, at several widths
153
+ bun test # run tests
154
+ bunx tsc --noEmit # typecheck
135
155
  ```
136
156
 
137
- The workspace is a Bun monorepo with three packages:
138
- - `@opencode-usage/core` shared data layer (SQLite, quotas, matching)
139
- - `@opencode-usage/cli` — the `opencode-usage` CLI
140
- - `@opencode-usage/plugin` — TUI plugin for opencode itself
157
+ The workspace is a Bun monorepo. The packages are listed by dependency order,
158
+ since `cli` and `plugin` both build on `core`:
159
+
160
+ - `@opencode-usage/core` — shared data layer (SQLite, quotas, matching, ranking)
161
+ - `@opencode-usage/cli` — the `opencode-usage` binary
162
+ - `@opencode-usage/plugin` — the opencode TUI plugin
163
+
164
+ Only the root package is published; `core` is inlined into both bundles.
141
165
 
142
166
  ## License
143
167
 
package/dist/cli.js CHANGED
@@ -448,7 +448,6 @@ function providersTable(statuses, local) {
448
448
  // packages/core/src/ranking/fetch.ts
449
449
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
450
450
  import path3 from "path";
451
- var {$ } = globalThis.Bun;
452
451
  var TTL_MS2 = 24 * 60 * 60 * 1000;
453
452
  async function readCache2(file) {
454
453
  try {
@@ -481,24 +480,14 @@ async function fetchModelsDev() {
481
480
  await writeCache2("models-dev.json", flat);
482
481
  return flat;
483
482
  }
484
- async function aaApiKey() {
485
- if (process.env.AA_API_KEY)
486
- return process.env.AA_API_KEY;
487
- const projectId = process.env.INFISICAL_PROJECT_ID;
488
- if (!projectId)
489
- return;
490
- try {
491
- const out = await $`infisical-secret get AA_API_KEY --projectId ${projectId} --env prod --plain --silent`.text();
492
- return out.trim() || undefined;
493
- } catch {
494
- return;
495
- }
483
+ function aaApiKey() {
484
+ return process.env.AA_API_KEY || undefined;
496
485
  }
497
486
  async function fetchAA() {
498
487
  const cached = await readCache2("aa.json");
499
488
  if (cached)
500
489
  return cached;
501
- const key = await aaApiKey();
490
+ const key = aaApiKey();
502
491
  if (!key)
503
492
  return [];
504
493
  const res = await fetch("https://artificialanalysis.ai/api/v2/data/llms/models", {
@@ -585,6 +574,7 @@ function valueScore(intelligenceIndex, cost) {
585
574
  }
586
575
 
587
576
  // packages/core/src/top.ts
577
+ var RANKING_ATTRIBUTION = "Intelligence: Artificial Analysis (artificialanalysis.ai) \xB7 Pricing: models.dev";
588
578
  async function buildTop(limit) {
589
579
  const [modelsDev, aaModels] = await Promise.all([fetchModelsDev(), fetchAA()]);
590
580
  const match = buildMatcher(aaModels, modelsDev);
@@ -883,7 +873,7 @@ async function cmdTop(flags, json) {
883
873
  const limit = typeof flags.get("--limit") === "string" ? Number(flags.get("--limit")) : 20;
884
874
  const rows = await buildTop(limit);
885
875
  if (json) {
886
- console.log(JSON.stringify(rows, null, 2));
876
+ console.log(JSON.stringify({ attribution: RANKING_ATTRIBUTION, models: rows }, null, 2));
887
877
  return;
888
878
  }
889
879
  const head = ["MODEL", "NAME", "IQ", "CODING", "$/M", "IQ/$"];
@@ -901,6 +891,8 @@ async function cmdTop(flags, json) {
901
891
  r.value !== undefined ? r.value.toFixed(1) : "\u2014"
902
892
  ]));
903
893
  }
894
+ console.log(`
895
+ ${RANKING_ATTRIBUTION}`);
904
896
  }
905
897
  if (import.meta.main) {
906
898
  const { cmd, flags } = parseArgs(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1930dev/opencode-usage",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Usage tracking, budget percentages and model ranking for opencode \u2014 CLI plus a /usage TUI plugin",
5
5
  "type": "module",
6
6
  "bin": {