@leo000001/opencode-quota-sidebar 3.0.9 → 4.0.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +0 -1
  2. package/README.md +157 -42
  3. package/README.zh-CN.md +157 -42
  4. package/SECURITY.md +1 -1
  5. package/dist/cli.d.ts +18 -0
  6. package/dist/cli.js +354 -0
  7. package/dist/cli_render.d.ts +17 -0
  8. package/dist/cli_render.js +292 -0
  9. package/dist/events.d.ts +1 -1
  10. package/dist/events.js +2 -2
  11. package/dist/format.d.ts +4 -0
  12. package/dist/format.js +302 -41
  13. package/dist/history_messages.d.ts +8 -0
  14. package/dist/history_messages.js +157 -0
  15. package/dist/history_usage.d.ts +93 -0
  16. package/dist/history_usage.js +251 -0
  17. package/dist/index.js +29 -4
  18. package/dist/period.d.ts +29 -1
  19. package/dist/period.js +187 -9
  20. package/dist/provider_catalog.d.ts +8 -0
  21. package/dist/provider_catalog.js +68 -0
  22. package/dist/providers/core/anthropic.d.ts +1 -1
  23. package/dist/providers/core/anthropic.js +69 -45
  24. package/dist/providers/core/openai.js +101 -8
  25. package/dist/providers/index.d.ts +1 -2
  26. package/dist/providers/index.js +1 -3
  27. package/dist/quota.d.ts +4 -2
  28. package/dist/quota.js +18 -21
  29. package/dist/quota_render.d.ts +1 -1
  30. package/dist/quota_render.js +23 -24
  31. package/dist/quota_service.d.ts +1 -0
  32. package/dist/quota_service.js +151 -19
  33. package/dist/storage.d.ts +1 -1
  34. package/dist/storage.js +4 -4
  35. package/dist/storage_dates.d.ts +1 -1
  36. package/dist/storage_dates.js +8 -5
  37. package/dist/storage_parse.js +23 -1
  38. package/dist/supported_quota.d.ts +4 -0
  39. package/dist/supported_quota.js +36 -0
  40. package/dist/title.js +18 -8
  41. package/dist/tools.d.ts +14 -3
  42. package/dist/tools.js +54 -2
  43. package/dist/tui.tsx +17 -6
  44. package/dist/tui_helpers.js +11 -6
  45. package/dist/types.d.ts +8 -0
  46. package/dist/usage.d.ts +18 -0
  47. package/dist/usage.js +93 -9
  48. package/dist/usage_service.d.ts +4 -1
  49. package/dist/usage_service.js +193 -189
  50. package/package.json +4 -1
  51. package/quota-sidebar.config.example.json +36 -45
  52. package/dist/providers/third_party/xyai.d.ts +0 -2
  53. package/dist/providers/third_party/xyai.js +0 -348
package/CHANGELOG.md CHANGED
@@ -8,7 +8,6 @@
8
8
  - Parse Kimi's `5h` and `Weekly` windows, including reset timestamps, and render them like other subscription providers.
9
9
  - Accept OpenCode provider discovery responses that expose Kimi API keys through provider `key` fields.
10
10
  - Add built-in MiniMax Coding Plan quota support, including global endpoint matching and pricing aliases.
11
- - Add built-in XYAI quota support with login-based session auth and legacy alias compatibility.
12
11
  - Keep session measured cost aligned with OpenCode root-session `message.cost` while still including descendant subagent usage in API-equivalent cost.
13
12
  - Support OpenCode long-context pricing tiers via `context_over_200k` when estimating API-equivalent cost.
14
13
  - Bump the usage billing cache version so `/qday`, `/qweek`, and `/qmonth` recompute historical API cost with the updated rules.
package/README.md CHANGED
@@ -16,7 +16,7 @@ The screenshot above comes from [`./assets/OpenCode-Quota-Sidebar.png`](./assets
16
16
  - Renders dedicated `TITLE`, `USAGE`, and `QUOTA` blocks in the TUI sidebar
17
17
  - Keeps the shared `session.title` on a compact single line instead of pushing multiline telemetry into every client
18
18
  - Aggregates usage for `session`, `day`, `week`, and `month`
19
- - Supports provider quota/balance fetchers for OpenAI, Copilot, Anthropic, Kimi, Zhipu, MiniMax, RightCode, and XYAI
19
+ - Supports provider quota/balance fetchers for OpenAI, Copilot, Anthropic, Kimi, Zhipu, MiniMax, and RightCode
20
20
  - Can include descendant subagent sessions in session-scoped usage/quota totals
21
21
  - Exposes `quota_summary` and `quota_show` tools for reports and title toggling
22
22
 
@@ -46,24 +46,23 @@ Session-scoped aggregation can include descendant subagent sessions when `sideba
46
46
 
47
47
  Built-in quota adapters:
48
48
 
49
- | Provider | Endpoint family | Auth | Quota shape | Notes |
50
- | ------------------- | ---------------------------------------------------------- | --------------------- | -------------------------- | --------------------------------------------------------- |
51
- | OpenAI Codex | `chatgpt.com/backend-api/wham/usage` | OAuth | Multi-window subscription | Reads ChatGPT usage windows such as short-term + weekly |
52
- | GitHub Copilot | `api.github.com/copilot_internal/user` | OAuth | Monthly subscription | Uses the Copilot internal user endpoint |
53
- | Anthropic | `api.anthropic.com/api/oauth/usage` | OAuth | Multi-window subscription | Supports plan-based usage windows |
54
- | Kimi For Coding | `api.kimi.com/coding/v1/usages` | API key | Multi-window subscription | Typically `5h` + weekly windows |
55
- | Zhipu Coding Plan | `bigmodel.cn/api/monitor/usage/quota/limit` | API key | Token quota | Coding-plan style quota window |
56
- | MiniMax Coding Plan | `www.minimaxi.com/v1/api/openplatform/coding_plan/remains` | API key | Multi-window subscription | Typically `5h` + weekly windows |
57
- | RightCode | `www.right.codes/account/summary` | API key | Daily quota and/or balance | Prefix-based subscription matching, with balance fallback |
58
- | XYAI | `new.xychatai.com/frontend-api/*` | Login -> session auth | Daily balance | Disabled by default, configured in `quota.providers.xyai` |
49
+ | Provider | Endpoint family | Auth | Quota shape | Notes |
50
+ | ------------------- | ---------------------------------------------------------- | ------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
51
+ | OpenAI Codex | `chatgpt.com/backend-api/wham/usage` | OAuth | Multi-window subscription | Reads ChatGPT usage windows such as short-term + weekly; Pro plans may also expose Codex Spark limits (`additional_rate_limits`) |
52
+ | GitHub Copilot | `api.github.com/copilot_internal/user` | OAuth | Monthly subscription | Uses the Copilot internal user endpoint |
53
+ | Anthropic | `api.anthropic.com/api/oauth/usage` | OAuth | Multi-window subscription | Supports plan-based usage windows |
54
+ | Kimi For Coding | `api.kimi.com/coding/v1/usages` | API key | Multi-window subscription | Typically `5h` + weekly windows |
55
+ | Zhipu Coding Plan | `bigmodel.cn/api/monitor/usage/quota/limit` | API key | Token quota | Coding-plan style quota window |
56
+ | MiniMax Coding Plan | `www.minimaxi.com/v1/api/openplatform/coding_plan/remains` | API key | Multi-window subscription | Typically `5h` + weekly windows |
57
+ | RightCode | `www.right.codes/account/summary` | API key | Daily quota and/or balance | Prefix-based subscription matching, with balance fallback |
59
58
 
60
59
  Generic providers without a built-in quota endpoint can still contribute usage totals, but they will not show quota/balance unless an adapter exists.
61
60
 
62
61
  Provider notes:
63
62
 
64
63
  - OpenAI, Copilot, and Anthropic quota support is based on OAuth/session auth, not generic API-key billing endpoints
64
+ - **OpenAI Codex Spark**: OpenAI Pro subscriptions may expose additional per-feature windows (e.g. `GPT-5.3-Codex-Spark`) in the `additional_rate_limits` field of the `wham/usage` response. When present, the plugin automatically parses and renders these as extra windows under the OpenAI quota line. No extra config is required. Code review quota (`code_review_rate_limit`) is not displayed yet.
65
65
  - RightCode can show both a daily allowance line and a balance line
66
- - XYAI requires login credentials in config so the plugin can obtain and cache session auth
67
66
  - Copilot quota is supported, but API-equivalent cost is intentionally not shown because runtime pricing is not reliable enough
68
67
 
69
68
  ## Display Rules
@@ -98,7 +97,7 @@ For OpenCode `>=1.2.15`, keep server plugins in `opencode.json` and TUI plugins
98
97
 
99
98
  ## Sidebar Demo
100
99
 
101
- Typical TUI sidebar layout:
100
+ Typical TUI sidebar layout (with Codex Spark windows):
102
101
 
103
102
  ```text
104
103
  TITLE
@@ -110,6 +109,8 @@ USAGE
110
109
  QUOTA
111
110
  OAI 5h80 R3h20m
112
111
  W70 R2D04h
112
+ Sk5h100 R1h00m
113
+ SkW100 R3D04h
113
114
  Cop M78 R12D00h
114
115
  RC D$88.9/$60 E6D00h
115
116
  B260
@@ -121,31 +122,41 @@ Compact shared title example:
121
122
  Fix quota adapter matching | OAI 5h80 R3h20m W70 R2D04h | RC D$88.9/$60 B260 | Cd66% | Est$12.8
122
123
  ```
123
124
 
124
- Another compact title example with multiple providers:
125
-
126
- ```text
127
- Add XYAI quota adapter | Ant 5h100 W77 O7d60 | Cop M78 R04-01 | Cd52% | Est$2.34
128
- ```
129
-
130
125
  ## Tool Report Demo
131
126
 
132
- Example `quota_summary` markdown output shape:
127
+ Example historical `quota_summary` markdown output shape:
133
128
 
134
129
  ```md
135
- ## Session Usage
130
+ ## Quota History - Daily since 2026-02-18
131
+
132
+ ### Quota Status
133
+
134
+ - OpenAI: 5h | 80.0% | reset 3h20m; Weekly | 70.0% | reset 2D04h
135
+ - Copilot: Monthly | 78.0% | reset 12D00h
136
+ - RightCode: Daily $88.9/$60 | reset 6D00h
137
+
138
+ ### Totals
139
+
140
+ | Metric | Total | Avg/Period |
141
+ | ------------ | ----: | ---------: |
142
+ | Requests | 184 | 26.3 |
143
+ | Total Tokens | 277k | 39.6k |
144
+ | Cache Hit | 63.1% | 58.4% |
145
+ | API Cost | $12.8 | $1.83 |
146
+
147
+ ### Provider Breakdown
136
148
 
137
- - Requests: 184
138
- - Input: 189k
139
- - Output: 53.2k
140
- - Cache Read: 31.4k
141
- - Cache Write: 3.2k
142
- - Cost as API: $12.8
149
+ | Provider | Req | Input | Output | Total | Share | Cache Hit | API Cost |
150
+ | --------- | --: | ----: | -----: | ----: | ----: | --------: | -------: |
151
+ | OpenAI | 140 | 160k | 61k | 221k | 79.8% | 66.2% | $10.4 |
152
+ | Anthropic | 44 | 29k | 27.1k | 56.1k | 20.2% | 51.3% | $2.34 |
143
153
 
144
- ## Quota
154
+ ### Period Detail
145
155
 
146
- - OpenAI: 5h 80% (reset 3h20m), Weekly 70% (reset 2D04h)
147
- - Copilot: Monthly 78% (reset 12D00h)
148
- - RightCode: Daily $88.9/$60 (exp 6D00h), Balance $260
156
+ | Period | Requests | Input | Output | Cache | Cache Hit | Total | API Cost |
157
+ | ------------ | -------: | ----: | -----: | ----: | --------: | ----: | -------: |
158
+ | 2026-02-18 | 12 | 18.3k | 4.2k | 8.9k | 32.7% | 31.4k | $1.12 |
159
+ | 2026-02-24\* | 17 | 8.1k | 2.0k | 3.4k | 66.0% | 13.5k | $0.88 |
149
160
  ```
150
161
 
151
162
  The tool already returns full markdown. Clients should display that report directly instead of replacing it with a short summary.
@@ -185,6 +196,8 @@ Quota tokens:
185
196
  - `D`: daily window
186
197
  - `W`: weekly window
187
198
  - `M`: monthly window
199
+ - `Sk5h`: OpenAI Codex Spark short window (e.g. 5h)
200
+ - `SkW`: OpenAI Codex Spark weekly window
188
201
  - `R3h20m`: resets in `3h20m`
189
202
  - `R2D04h`: resets in `2D04h`
190
203
  - `E6D00h`: expires in `6D00h`
@@ -192,6 +205,8 @@ Quota tokens:
192
205
  Example compact quota fragments:
193
206
 
194
207
  - `OAI 5h80 R3h20m`: OpenAI short window, 80% remaining, resets in `3h20m`
208
+ - `OAI Sk5h100 R1h00m`: OpenAI Codex Spark 5h window, 100% remaining, resets in `1h00m`
209
+ - `OAI SkW100 R3D04h`: OpenAI Codex Spark weekly window, 100% remaining, resets in `3D04h`
195
210
  - `Cop M78 R12D00h`: Copilot monthly quota, 78% remaining, resets in `12D00h`
196
211
  - `RC D$88.9/$60 E6D00h B260`: RightCode daily quota plus balance
197
212
 
@@ -223,13 +238,10 @@ See [`quota-sidebar.config.example.json`](./quota-sidebar.config.example.json) f
223
238
  Important config notes:
224
239
 
225
240
  - `sidebar.titleMode`: `auto`, `compact`, or `multiline`
226
- - `sidebar.showCost`: controls API-equivalent cost in sidebar, title, markdown report, and toast
241
+ - `sidebar.showCost`: controls API-equivalent cost in sidebar, title, markdown report, toast, and CLI output
227
242
  - `sidebar.wrapQuotaLines`: wraps long quota lines with indentation instead of dropping fields
228
243
  - `sidebar.includeChildren`: includes descendant subagent sessions for `period=session`
229
- - `quota.providers.xyai.enabled`: must be explicitly enabled if you want XYAI quota
230
- - `quota.providers.xyai.login.username/password`: used to fetch and refresh XYAI session auth
231
-
232
- Config is layered. The later source overrides the earlier one:
244
+ Config is layered. The later source overrides the earlier one:
233
245
 
234
246
  1. global config
235
247
  2. worktree config
@@ -258,25 +270,48 @@ Behavior notes:
258
270
 
259
271
  - `quota_summary` returns the full markdown report body
260
272
  - `quota_summary` can show a toast in addition to returning markdown
273
+ - `quota_summary` accepts `period`, `since`, `last`, `toast`, and `includeChildren`
261
274
  - `quota_summary(includeChildren=true)` only changes `period=session`
275
+ - `day/week/month` scans all sessions in the selected time range, so child sessions are included when they have activity in that range
276
+ - `day/week/month` does not do parent-tree rollup; child sessions are counted as independent sessions, not merged through `includeChildren`
277
+ - `since` and `last` are mutually exclusive
278
+ - `period=session` does not accept `since` or `last`
262
279
  - `quota_show(enabled=true|false)` can explicitly force a state instead of toggling
280
+ - Historical reports support both absolute `since` and relative `last`
281
+ - `since` accepts `YYYY-MM` or `YYYY-MM-DD`
282
+ - `last` accepts a positive integer and is relative to the current period: `day=7`, `week=8`, `month=6`
283
+ - Empty `period=day|week|month` means the current natural day/week/month
263
284
 
264
285
  Example command aliases:
265
286
 
287
+ For direct in-chat history output, define command aliases that call `quota_summary`.
288
+ The old TUI history popup path was removed; history now goes through the tool report directly.
289
+ These aliases are still OpenCode command templates, so they expand into prompt text before the model/tool chain runs. For the cleanest direct output path, prefer the standalone CLI.
290
+
291
+ Examples:
292
+
293
+ - `quota_summary(period=day)` -> today
294
+ - `quota_summary(period=week)` -> this week
295
+ - `quota_summary(period=month)` -> this month
296
+ - `quota_summary(period=day,last=7)` -> last 7 days
297
+ - `quota_summary(period=week,last=8)` -> last 8 weeks
298
+ - `quota_summary(period=month,last=6)` -> last 6 months
299
+ - `quota_summary(period=month,since=2026-01)` -> since Jan 2026
300
+
266
301
  ```json
267
302
  {
268
303
  "command": {
269
304
  "qday": {
270
- "description": "Show today's usage and quota",
271
- "template": "Call tool quota_summary with period=day and toast=true."
305
+ "description": "Today / last N days / since date",
306
+ "template": "Run /qday for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=day, toast=true. If `$ARGUMENTS` is a positive integer: period=day, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM-DD: period=day, since=<that date>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM-DD."
272
307
  },
273
308
  "qweek": {
274
- "description": "Show this week's usage and quota",
275
- "template": "Call tool quota_summary with period=week and toast=true."
309
+ "description": "This week / last N weeks / since date",
310
+ "template": "Run /qweek for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=week, toast=true. If `$ARGUMENTS` is a positive integer: period=week, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM-DD: period=week, since=<that date>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM-DD."
276
311
  },
277
312
  "qmonth": {
278
- "description": "Show this month's usage and quota",
279
- "template": "Call tool quota_summary with period=month and toast=true."
313
+ "description": "This month / last N months / since month",
314
+ "template": "Run /qmonth for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=month, toast=true. If `$ARGUMENTS` is a positive integer: period=month, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM: period=month, since=<that month>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM."
280
315
  },
281
316
  "qtoggle": {
282
317
  "description": "Toggle sidebar usage display on/off",
@@ -286,6 +321,86 @@ Example command aliases:
286
321
  }
287
322
  ```
288
323
 
324
+ ## CLI
325
+
326
+ The package exposes a standalone CLI dashboard. After installing globally or making the `bin` available:
327
+
328
+ ```bash
329
+ # Current period (single snapshot)
330
+ opencode-quota day # today
331
+ opencode-quota week # this week (Monday-based)
332
+ opencode-quota month # this month
333
+
334
+ # Multi-period history
335
+ opencode-quota day 7 # last 7 days
336
+ opencode-quota week 8 # last 8 weeks
337
+ opencode-quota month 6 # last 6 months
338
+
339
+ # Absolute start date
340
+ opencode-quota day --since 2026-04-01
341
+ opencode-quota week --since 2026-04-01
342
+ opencode-quota month --since 2026-01
343
+
344
+ # Also accepted as positional (equivalent to --since)
345
+ opencode-quota day 2026-04-01
346
+ opencode-quota month 2026-01
347
+ ```
348
+
349
+ When called without `last` or `--since`, the CLI renders a single-period snapshot (`QUOTA + TOTALS + PROVIDERS`). When called with `last` or `--since`, it renders multi-period history with a larger multi-line `TREND` block.
350
+
351
+ ### CLI semantics
352
+
353
+ - `day` = current natural day; `week` = current natural week (Monday-based); `month` = current natural month
354
+ - A positional integer maps to `last=<N>` (number of periods back from now)
355
+ - A positional date string maps to `--since` (`YYYY-MM-DD` for day/week, `YYYY-MM` for month)
356
+ - `--since` and `--last` are mutually exclusive
357
+ - `last` is limited to 90 for day, reasonable ranges for week/month
358
+
359
+ ### Trend section
360
+
361
+ The `TREND` block appears only in multi-period mode. Each metric (`Requests`, `Tokens`, `Cache`, `Cost`) is rendered as a small multi-line bar chart:
362
+
363
+ - one summary line: the current value only
364
+ - one bar row per visible period (latest 8 periods max), ordered oldest-to-newest
365
+ - the current period is marked with `*`
366
+
367
+ Interpretation example:
368
+
369
+ ```text
370
+ Requests 12.3k
371
+ 04-08 | ███░░░░░░░░░░░░░░░ | 4.1k
372
+ 04-09 | ██████░░░░░░░░░░░░ | 8.2k
373
+ 04-10* | █████████████░░░░░ | 12.3k
374
+ ```
375
+
376
+ This means the current bucket has `12.3k` requests, and the bar rows below show the relative size of each visible bucket from oldest to newest.
377
+
378
+ ### Connection behavior
379
+
380
+ - The CLI talks to the local OpenCode API at `http://localhost:4096` by default
381
+ - Set `OPENCODE_BASE_URL` to override (e.g. `http://192.168.1.10:4096`)
382
+ - If no server is running and `OPENCODE_BASE_URL` is not set, the CLI attempts to start one:
383
+ - **Linux/macOS**: runs `opencode serve --hostname=127.0.0.1 --port=4096`
384
+ - **Windows**: tries `opencode.cmd`, then `opencode` via `shell: true`, then `bash -lc opencode`
385
+ - The auto-start waits up to 10 seconds for the server to print `opencode server listening on <url>`
386
+ - If auto-start fails, check that `opencode` is in your `PATH`
387
+ - On Windows, the `shell: true` path is usually the most reliable when `opencode.cmd` is not directly spawnable from Node
388
+
389
+ ### Platform notes
390
+
391
+ - **Terminal encoding**: the dashboard uses Unicode box-drawing and block elements (`█░`). Requires a UTF-8 capable terminal. Windows users should use Windows Terminal, PowerShell 7+, or a terminal that supports UTF-8. Classic cmd.exe with legacy codepages (CP437/CP850) may render garbled characters.
392
+ - **Alignment**: weekly/monthly trend labels can still be truncated when the visible label is very long (for example long absolute week ranges). This is a known presentation tradeoff in the current terminal renderer.
393
+ - **Windows PATH**: the CLI tries multiple command forms to find `opencode`. If none work, ensure `opencode` or `opencode.cmd` is on your PATH, or start the server manually and set `OPENCODE_BASE_URL`.
394
+ - **Node.js**: requires `>=18`
395
+
396
+ ### Environment variables
397
+
398
+ | Variable | Default | Purpose |
399
+ | ---------------------------- | ------------------------- | -------------------------------------------------------------------------------- |
400
+ | `OPENCODE_BASE_URL` | `http://localhost:4096` | OpenCode API endpoint; set this if the server is remote or on a non-default port |
401
+ | `OPENCODE_QUOTA_CONFIG_HOME` | `~/.config/opencode` | Global config directory override |
402
+ | `OPENCODE_QUOTA_DATA_HOME` | `~/.local/share/opencode` | Global data directory override |
403
+
289
404
  ## Development
290
405
 
291
406
  ```bash
package/README.zh-CN.md CHANGED
@@ -13,7 +13,7 @@ OpenCode 插件:在 TUI sidebar 中显示 token 用量和 provider quota,同
13
13
  - 在 TUI sidebar 中渲染结构化的 `TITLE`、`USAGE`、`QUOTA` 三个区块
14
14
  - 让共享 `session.title` 保持紧凑单行,而不是把多行遥测数据写进所有客户端都共用的标题
15
15
  - 统计 `session`、`day`、`week`、`month` 四种范围的 usage
16
- - 内置支持 OpenAI、Copilot、Anthropic、Kimi、Zhipu、MiniMax、RightCode、XYAI 的 quota / balance 获取
16
+ - 内置支持 OpenAI、Copilot、Anthropic、Kimi、Zhipu、MiniMax、RightCode 的 quota / balance 获取
17
17
  - session 级统计可选聚合 descendant subagent sessions
18
18
  - 提供 `quota_summary` 和 `quota_show` 两个工具
19
19
 
@@ -43,23 +43,22 @@ OpenCode 插件:在 TUI sidebar 中显示 token 用量和 provider quota,同
43
43
 
44
44
  内置 quota adapter 如下:
45
45
 
46
- | Provider | Endpoint family | 鉴权方式 | 展示形态 | 说明 |
47
- | ------------------- | ---------------------------------------------------------- | ------------------- | --------------- | -------------------------------------------------- |
48
- | OpenAI Codex | `chatgpt.com/backend-api/wham/usage` | OAuth | 多窗口订阅额度 | 读取 ChatGPT usage 窗口,例如短窗口 + 周窗口 |
49
- | GitHub Copilot | `api.github.com/copilot_internal/user` | OAuth | 月度额度 | 使用 Copilot internal user 接口 |
50
- | Anthropic | `api.anthropic.com/api/oauth/usage` | OAuth | 多窗口订阅额度 | 支持 plan-based usage windows |
51
- | Kimi For Coding | `api.kimi.com/coding/v1/usages` | API key | 多窗口订阅额度 | 通常为 `5h` + weekly |
52
- | Zhipu Coding Plan | `bigmodel.cn/api/monitor/usage/quota/limit` | API key | token quota | coding plan 风格额度 |
53
- | MiniMax Coding Plan | `www.minimaxi.com/v1/api/openplatform/coding_plan/remains` | API key | 多窗口订阅额度 | 通常为 `5h` + weekly |
54
- | RightCode | `www.right.codes/account/summary` | API key | 日额度和/或余额 | 按 prefix 匹配订阅,失败时回退为 balance |
55
- | XYAI | `new.xychatai.com/frontend-api/*` | 登录态 session auth | 日额度 / 日余额 | 默认关闭,需要在 `quota.providers.xyai` 中显式开启 |
46
+ | Provider | Endpoint family | 鉴权方式 | 展示形态 | 说明 |
47
+ | ------------------- | ---------------------------------------------------------- | -------- | --------------- | --------------------------------------------------------------------------------------------------------------- |
48
+ | OpenAI Codex | `chatgpt.com/backend-api/wham/usage` | OAuth | 多窗口订阅额度 | 读取 ChatGPT usage 窗口,例如短窗口 + 周窗口;Pro 订阅可能额外提供 Codex Spark 限额(`additional_rate_limits`) |
49
+ | GitHub Copilot | `api.github.com/copilot_internal/user` | OAuth | 月度额度 | 使用 Copilot internal user 接口 |
50
+ | Anthropic | `api.anthropic.com/api/oauth/usage` | OAuth | 多窗口订阅额度 | 支持 plan-based usage windows |
51
+ | Kimi For Coding | `api.kimi.com/coding/v1/usages` | API key | 多窗口订阅额度 | 通常为 `5h` + weekly |
52
+ | Zhipu Coding Plan | `bigmodel.cn/api/monitor/usage/quota/limit` | API key | token quota | coding plan 风格额度 |
53
+ | MiniMax Coding Plan | `www.minimaxi.com/v1/api/openplatform/coding_plan/remains` | API key | 多窗口订阅额度 | 通常为 `5h` + weekly |
54
+ | RightCode | `www.right.codes/account/summary` | API key | 日额度和/或余额 | 按 prefix 匹配订阅,失败时回退为 balance |
56
55
 
57
56
  补充说明:
58
57
 
59
58
  - 没有内置 quota adapter 的 generic provider 仍然可以参与 usage 聚合,但不会显示 quota/balance
60
59
  - OpenAI、Copilot、Anthropic 的 quota 支持依赖 OAuth / session auth,而不是通用 API key 账单接口
60
+ - **OpenAI Codex Spark**:OpenAI Pro 订阅的 `wham/usage` 响应中可能包含 `additional_rate_limits` 字段,其中带有 `GPT-5.3-Codex-Spark` 等额外功能窗口。插件会自动解析并将其显示在 OpenAI quota 行下,无需额外配置。`code_review_rate_limit`(代码审查额度)目前暂不展示。
61
61
  - RightCode 可能同时显示 daily allowance 和 balance 两行
62
- - XYAI 需在配置中提供登录信息,插件会自行获取并缓存 session auth
63
62
  - Copilot 支持 quota 展示,但当前不会显示 API-equivalent cost,因为 pricing metadata 不够稳定
64
63
 
65
64
  ## 展示规则
@@ -79,7 +78,7 @@ title 相关补充:
79
78
 
80
79
  ## Sidebar 示例
81
80
 
82
- 典型的 TUI sidebar 布局:
81
+ 典型的 TUI sidebar 布局(含 Codex Spark 窗口):
83
82
 
84
83
  ```text
85
84
  TITLE
@@ -91,6 +90,8 @@ USAGE
91
90
  QUOTA
92
91
  OAI 5h80 R3h20m
93
92
  W70 R2D04h
93
+ Sk5h100 R1h00m
94
+ SkW100 R3D04h
94
95
  Cop M78 R12D00h
95
96
  RC D$88.9/$60 E6D00h
96
97
  B260
@@ -102,31 +103,41 @@ compact shared title 示例:
102
103
  Fix quota adapter matching | OAI 5h80 R3h20m W70 R2D04h | RC D$88.9/$60 B260 | Cd66% | Est$12.8
103
104
  ```
104
105
 
105
- 另一个多 provider 示例:
106
-
107
- ```text
108
- Add XYAI quota adapter | Ant 5h100 W77 O7d60 | Cop M78 R04-01 | Cd52% | Est$2.34
109
- ```
110
-
111
106
  ## Tool Report 示例
112
107
 
113
- `quota_summary` 返回的 markdown 大致会是这样的结构:
108
+ 历史 `quota_summary` markdown 大致会是这样的结构:
114
109
 
115
110
  ```md
116
- ## Session Usage
111
+ ## Quota History - Daily since 2026-02-18
112
+
113
+ ### Quota Status
114
+
115
+ - OpenAI: 5h | 80.0% | reset 3h20m; Weekly | 70.0% | reset 2D04h
116
+ - Copilot: Monthly | 78.0% | reset 12D00h
117
+ - RightCode: Daily $88.9/$60 | reset 6D00h
118
+
119
+ ### Totals
120
+
121
+ | Metric | Total | Avg/Period |
122
+ | ------------ | ----: | ---------: |
123
+ | Requests | 184 | 26.3 |
124
+ | Total Tokens | 277k | 39.6k |
125
+ | Cache Hit | 63.1% | 58.4% |
126
+ | API Cost | $12.8 | $1.83 |
127
+
128
+ ### Provider Breakdown
117
129
 
118
- - Requests: 184
119
- - Input: 189k
120
- - Output: 53.2k
121
- - Cache Read: 31.4k
122
- - Cache Write: 3.2k
123
- - Cost as API: $12.8
130
+ | Provider | Req | Input | Output | Total | Share | Cache Hit | API Cost |
131
+ | --------- | --: | ----: | -----: | ----: | ----: | --------: | -------: |
132
+ | OpenAI | 140 | 160k | 61k | 221k | 79.8% | 66.2% | $10.4 |
133
+ | Anthropic | 44 | 29k | 27.1k | 56.1k | 20.2% | 51.3% | $2.34 |
124
134
 
125
- ## Quota
135
+ ### Period Detail
126
136
 
127
- - OpenAI: 5h 80% (reset 3h20m), Weekly 70% (reset 2D04h)
128
- - Copilot: Monthly 78% (reset 12D00h)
129
- - RightCode: Daily $88.9/$60 (exp 6D00h), Balance $260
137
+ | Period | Requests | Input | Output | Cache | Cache Hit | Total | API Cost |
138
+ | ------------ | -------: | ----: | -----: | ----: | --------: | ----: | -------: |
139
+ | 2026-02-18 | 12 | 18.3k | 4.2k | 8.9k | 32.7% | 31.4k | $1.12 |
140
+ | 2026-02-24\* | 17 | 8.1k | 2.0k | 3.4k | 66.0% | 13.5k | $0.88 |
130
141
  ```
131
142
 
132
143
  这个工具本身就返回完整 markdown,调用方应该直接展示,而不是再压缩成一句话摘要。
@@ -170,6 +181,8 @@ Quota token:
170
181
  - `D`:daily window
171
182
  - `W`:weekly window
172
183
  - `M`:monthly window
184
+ - `Sk5h`:OpenAI Codex Spark 短窗口(如 5h)
185
+ - `SkW`:OpenAI Codex Spark 周窗口
173
186
  - `R3h20m`:还剩 `3h20m` 重置
174
187
  - `R2D04h`:还剩 `2D04h` 重置
175
188
  - `E6D00h`:还剩 `6D00h` 到期
@@ -177,6 +190,8 @@ Quota token:
177
190
  compact quota 片段示例:
178
191
 
179
192
  - `OAI 5h80 R3h20m`:OpenAI 短窗口剩余 80%,还剩 `3h20m` 重置
193
+ - `OAI Sk5h100 R1h00m`:OpenAI Codex Spark 5h 窗口剩余 100%,还剩 `1h00m` 重置
194
+ - `OAI SkW100 R3D04h`:OpenAI Codex Spark 周窗口剩余 100%,还剩 `3D04h` 重置
180
195
  - `Cop M78 R12D00h`:Copilot 月额度剩余 78%,还剩 `12D00h` 重置
181
196
  - `RC D$88.9/$60 E6D00h B260`:RightCode 日额度 + 余额
182
197
 
@@ -230,13 +245,10 @@ OpenCode `>=1.2.15` 时,server 插件放在 `opencode.json`,TUI 插件放在
230
245
  重要配置项:
231
246
 
232
247
  - `sidebar.titleMode`:`auto`、`compact`、`multiline`
233
- - `sidebar.showCost`:控制 sidebar、title、markdown report、toast 中的 API-equivalent cost 可见性
248
+ - `sidebar.showCost`:控制 sidebar、title、markdown report、toast 和 CLI 中的 API-equivalent cost 可见性
234
249
  - `sidebar.wrapQuotaLines`:长 quota 行是否自动续行并缩进
235
250
  - `sidebar.includeChildren`:`period=session` 时是否聚合 descendant subagent sessions
236
- - `quota.providers.xyai.enabled`:是否启用 XYAI quota
237
- - `quota.providers.xyai.login.username/password`:XYAI 登录信息,用于换取和刷新 session auth
238
-
239
- 配置采用分层覆盖,后层配置覆盖前层配置:
251
+ 配置采用分层覆盖,后层配置覆盖前层配置:
240
252
 
241
253
  1. 全局配置
242
254
  2. worktree 配置
@@ -265,25 +277,48 @@ usage 聚合采用增量模式。插件会为每个 session 维护 cursor,优
265
277
 
266
278
  - `quota_summary` 返回完整 markdown report
267
279
  - `quota_summary` 可以同时触发 toast 展示
280
+ - `quota_summary` 参数为 `period`、`since`、`last`、`toast`、`includeChildren`
268
281
  - `quota_summary(includeChildren=true)` 只影响 `period=session`
282
+ - `day/week/month` 会扫描所选时间范围内的全部 sessions,所以 child sessions 只要在该范围内有 activity 就会被统计进去
283
+ - `day/week/month` 不做 parent 树 rollup;child sessions 会作为独立 sessions 计入,而不是通过 `includeChildren` 合并到 parent
284
+ - `since` 和 `last` 互斥
285
+ - `period=session` 不支持 `since` / `last`
269
286
  - `quota_show(enabled=true|false)` 可以显式指定目标状态,而不是只做 toggle
287
+ - 历史报告同时支持绝对时间 `since` 和相对区间 `last`
288
+ - `since` 支持 `YYYY-MM` 或 `YYYY-MM-DD`
289
+ - `last` 需要正整数,并按当前 period 相对计算:`day=7`、`week=8`、`month=6`
290
+ - 空参数的 `period=day|week|month` 表示当前自然日 / 自然周 / 自然月
270
291
 
271
292
  命令别名示例:
272
293
 
294
+ 如果你想直接走工具输出查看历史,可以在配置里声明调用 `quota_summary` 的命令别名。
295
+ 旧的 TUI 历史弹窗路径已经移除,历史查看统一回到 tool report。
296
+ 这些别名本质上仍然是 OpenCode 的 command template,因此会先展开为提示词,再进入模型 / tool 链路。若想要更直接、更干净的输出路径,优先使用独立 CLI。
297
+
298
+ 示例:
299
+
300
+ - `quota_summary(period=day)` -> 今天
301
+ - `quota_summary(period=week)` -> 本周
302
+ - `quota_summary(period=month)` -> 本月
303
+ - `quota_summary(period=day,last=7)` -> 最近 7 天
304
+ - `quota_summary(period=week,last=8)` -> 最近 8 周
305
+ - `quota_summary(period=month,last=6)` -> 最近 6 个月
306
+ - `quota_summary(period=month,since=2026-01)` -> 从 2026-01 开始
307
+
273
308
  ```json
274
309
  {
275
310
  "command": {
276
311
  "qday": {
277
- "description": "Show today's usage and quota",
278
- "template": "Call tool quota_summary with period=day and toast=true."
312
+ "description": "Today / last N days / since date",
313
+ "template": "Run /qday for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=day, toast=true. If `$ARGUMENTS` is a positive integer: period=day, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM-DD: period=day, since=<that date>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM-DD."
279
314
  },
280
315
  "qweek": {
281
- "description": "Show this week's usage and quota",
282
- "template": "Call tool quota_summary with period=week and toast=true."
316
+ "description": "This week / last N weeks / since date",
317
+ "template": "Run /qweek for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=week, toast=true. If `$ARGUMENTS` is a positive integer: period=week, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM-DD: period=week, since=<that date>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM-DD."
283
318
  },
284
319
  "qmonth": {
285
- "description": "Show this month's usage and quota",
286
- "template": "Call tool quota_summary with period=month and toast=true."
320
+ "description": "This month / last N months / since month",
321
+ "template": "Run /qmonth for opencode-quota-sidebar. Call tool quota_summary exactly once and return its full report directly. If `$ARGUMENTS` is empty: period=month, toast=true. If `$ARGUMENTS` is a positive integer: period=month, last=<that integer>, toast=true. If `$ARGUMENTS` matches YYYY-MM: period=month, since=<that month>, toast=true. Otherwise briefly explain: empty, positive integer, or YYYY-MM."
287
322
  },
288
323
  "qtoggle": {
289
324
  "description": "Toggle sidebar usage display on/off",
@@ -293,6 +328,86 @@ usage 聚合采用增量模式。插件会为每个 session 维护 cursor,优
293
328
  }
294
329
  ```
295
330
 
331
+ ## CLI
332
+
333
+ 这个包同时提供一个独立 CLI dashboard。全局安装或让 `bin` 可执行后:
334
+
335
+ ```bash
336
+ # 当前周期(单次快照)
337
+ opencode-quota day # 今天
338
+ opencode-quota week # 本周(周一起算)
339
+ opencode-quota month # 本月
340
+
341
+ # 多周期历史
342
+ opencode-quota day 7 # 最近 7 天
343
+ opencode-quota week 8 # 最近 8 周
344
+ opencode-quota month 6 # 最近 6 个月
345
+
346
+ # 绝对起始日期
347
+ opencode-quota day --since 2026-04-01
348
+ opencode-quota week --since 2026-04-01
349
+ opencode-quota month --since 2026-01
350
+
351
+ # 位置参数也接受日期字符串(等同于 --since)
352
+ opencode-quota day 2026-04-01
353
+ opencode-quota month 2026-01
354
+ ```
355
+
356
+ 不带 `last` 或 `--since` 时,CLI 渲染单周期快照(`QUOTA + TOTALS + PROVIDERS`)。带 `last` 或 `--since` 时渲染多周期历史,并额外展示更大的多行 `TREND` 区块。
357
+
358
+ ### CLI 语义
359
+
360
+ - `day` = 当前自然日;`week` = 当前自然周(周一起算);`month` = 当前自然月
361
+ - 位置参数正整数映射为 `last=<N>`(从当前往回数 N 个周期)
362
+ - 位置参数日期字符串映射为 `--since`(day/week 用 `YYYY-MM-DD`,month 用 `YYYY-MM`)
363
+ - `--since` 和 `--last` 互斥
364
+ - `last` 对 day 限制 90,week/month 也有合理范围限制
365
+
366
+ ### Trend 区块
367
+
368
+ `TREND` 区块仅在多周期模式下出现。每个指标(`Requests`、`Tokens`、`Cache`、`Cost`)都会渲染为一个小型多行柱状图:
369
+
370
+ - 一行摘要:当前值
371
+ - 每个可见周期一行柱状条(最多展示最近 8 个周期)
372
+ - 当前周期用 `*` 标记
373
+
374
+ 解读示例:
375
+
376
+ ```text
377
+ Requests 12.3k
378
+ 04-08 | ███░░░░░░░░░░░░░░░ | 4.1k
379
+ 04-09 | ██████░░░░░░░░░░░░ | 8.2k
380
+ 04-10* | █████████████░░░░░ | 12.3k
381
+ ```
382
+
383
+ 这表示当前 bucket 有 `12.3k` 请求,下面的柱状条则按时间顺序展示各个可见 bucket 的相对大小。
384
+
385
+ ### 连接行为
386
+
387
+ - CLI 默认连接本地 OpenCode API `http://localhost:4096`
388
+ - 通过 `OPENCODE_BASE_URL` 覆盖(例如 `http://192.168.1.10:4096`)
389
+ - 如果没有运行中的 server 且未设置 `OPENCODE_BASE_URL`,CLI 会尝试自动启动:
390
+ - **Linux/macOS**:运行 `opencode serve --hostname=127.0.0.1 --port=4096`
391
+ - **Windows**:依次尝试 `opencode.cmd`、`opencode`(通过 `shell: true`)、`bash -lc opencode`
392
+ - 自动启动等待最多 10 秒,直到 server 输出 `opencode server listening on <url>`
393
+ - 如果自动启动失败,请确认 `opencode` 在你的 `PATH` 中
394
+ - 在 Windows 上,如果 `opencode.cmd` 不能被 Node 直接 spawn,`shell: true` 通常是更可靠的兜底路径
395
+
396
+ ### 平台说明
397
+
398
+ - **终端编码**:dashboard 使用 Unicode 绘框字符和方块元素(`█░`),需要支持 UTF-8 的终端。Windows 用户应使用 Windows Terminal、PowerShell 7+ 或其他支持 UTF-8 的终端。经典 cmd.exe 使用传统代码页(CP437/CP850)时可能显示乱码。
399
+ - **对齐**:当 week/month 的可见标签非常长时(例如完整绝对日期范围),CLI 的 trend 标签仍可能被截断。这是当前终端 renderer 的已知展示取舍。
400
+ - **Windows PATH**:CLI 会尝试多种命令形式来找到 `opencode`。如果全部失败,请确认 `opencode` 或 `opencode.cmd` 在 PATH 中,或手动启动 server 后设置 `OPENCODE_BASE_URL`。
401
+ - **Node.js**:需要 `>=18`
402
+
403
+ ### 环境变量
404
+
405
+ | 变量 | 默认值 | 用途 |
406
+ | ---------------------------- | ------------------------- | -------------------------------------------------- |
407
+ | `OPENCODE_BASE_URL` | `http://localhost:4096` | OpenCode API 端点;server 在远程或非默认端口时设置 |
408
+ | `OPENCODE_QUOTA_CONFIG_HOME` | `~/.config/opencode` | 全局配置目录覆盖 |
409
+ | `OPENCODE_QUOTA_DATA_HOME` | `~/.local/share/opencode` | 全局数据目录覆盖 |
410
+
296
411
  ## 开发
297
412
 
298
413
  ```bash
package/SECURITY.md CHANGED
@@ -25,7 +25,7 @@ We will acknowledge reports as quickly as possible and provide a remediation tim
25
25
  - Keep debug logs free of secrets.
26
26
  - Prefer fail-closed behavior for writes (already enforced via symlink checks and atomic writes).
27
27
  - Quota fetching may contact provider-operated endpoints such as OpenAI, GitHub,
28
- Anthropic, Kimi, Zhipu, MiniMax, RightCode, and XYAI; review any new
28
+ Anthropic, Kimi, Zhipu, MiniMax, and RightCode; review any new
29
29
  provider integration for outbound data exposure and header/token handling.
30
30
  - Some quota integrations rely on beta or internal-style endpoints; document
31
31
  instability risks clearly and avoid assuming long-term API compatibility.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { type HistoryPeriod } from './period.js';
3
+ type CliCommand = {
4
+ period: HistoryPeriod;
5
+ since?: string;
6
+ last?: number;
7
+ };
8
+ type CliServerCommand = {
9
+ command: string;
10
+ args: string[];
11
+ shell?: boolean;
12
+ };
13
+ export declare function parseCliArgs(argv: string[]): CliCommand;
14
+ export declare function cliBaseUrl(): string;
15
+ export declare function cliServerCommandCandidates(platform?: NodeJS.Platform): CliServerCommand[];
16
+ export declare function runCli(argv: string[]): Promise<string>;
17
+ export declare function cliExitCodeForError(message: string): 0 | 1;
18
+ export {};