@webfueler/oc-dash 0.1.5 → 0.1.7

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/README.md CHANGED
@@ -1,176 +1,122 @@
1
1
  # oc-dash
2
2
 
3
- A small local webapp that reads the opencode2 service API and shows session
4
- costs, token totals, and the subagent spend the opencode2 TUI never displays.
5
-
6
- Single package: Hono backend on Node 22, React + Vite + TypeScript frontend,
7
- plain CSS, inline-SVG activity chart. No chart library, no CSS framework.
8
-
9
- ## What it shows
10
-
11
- - **Cost hero** — one hero card with the range's total cost (USD, money-green),
12
- a `≈ $X/day` figure where the range spans full days (omitted for today), and
13
- a compact stat strip below it: tokens, prompts · steps, sessions ·
14
- subagents, active days · streak. When the stats endpoint is unavailable, the
15
- hero carries a fallback badge and the strip shows totals computed from the
16
- session list instead.
17
- - **Sessions table** — every session in the range with title, agent, model
18
- chip (full `provider/model · variant` string on hover), own cost, **incl.
19
- subagents** (recursive: parent cost plus the cost of all descendants at any
20
- depth), tokens, last activity, and outcome. Child sessions nest under their
21
- parent, **collapsed by default**: clicking a parent row (or focusing it and
22
- pressing Enter/Space) expands its subagents, and Expand all / Collapse all
23
- buttons sit in the section head. Tree state resets when the range changes.
24
- Rows whose outcome is `succeeded` render a dim check; `failed` and
25
- `interrupted` keep loud badges. A project filter is built from the session
26
- directories.
27
- - **Models table** — steps, tokens, and cost per model, with an `unpriced`
28
- flag on models that burn tokens but report zero cost.
29
- - **Activity chart** — steps per day, drawn as inline SVG: bars are
30
- width-capped and slot-centered, dotted gridlines mark 25/50/75% of the peak,
31
- zero-step days stay visible as stubs, and the Today range shows the trailing
32
- 7 days with the in-range day accented (`/api/summary` gains an additive,
33
- Today-only `contextActivity` field for this).
34
-
35
- Refreshes every 30 seconds while the tab is visible; refreshes immediately
36
- when the tab becomes visible again.
37
-
38
- ## Requirements
39
-
40
- - Node 22+
41
- - npm
42
- - A running local opencode2 service (the app only ever issues read-only GETs
43
- and never stops or restarts the service)
44
-
45
- ## Run without cloning
3
+ Track exactly what AI usage costs in opencode2. oc-dash is a local dashboard
4
+ over the service API that shows spend session by session, subagents included,
5
+ under any time range and filter combination.
46
6
 
47
- ```sh
48
- npx @webfueler/oc-dash
49
- ```
7
+ ## What it looks like
50
8
 
51
- Needs Node 22+ and npm. Serves the built frontend and API from a single
52
- process on http://localhost:4021 (override with `PORT`, e.g.
53
- `PORT=4022 npx @webfueler/oc-dash`).
9
+ One page: a cost hero, project and model filters with a filtered totals card,
10
+ then the sessions table, the models table, and an activity chart.
54
11
 
55
- Prefer the short command? A global install puts it on your PATH:
12
+ ![oc-dash dashboard, dark mode, 7-day range: the total cost hero, the project and model filters with the project filter set to oc-setup and the filtered totals card below it, then the sessions table, the models table, and the activity chart.](docs/screenshot.png)
56
13
 
57
- ```sh
58
- npm i -g @webfueler/oc-dash
59
- oc-dash
60
- ```
14
+ ## What you can learn
61
15
 
62
- The dashboard only reads from the opencode2 service, which must already
63
- be installed and running. When no registered service answers the
64
- startup probe, oc-dash prints a short message and exits non-zero it
65
- never starts, stops, or restarts a service. Start the service with:
16
+ - The total spend for a range, with a per-day average when the range covers
17
+ full days, plus tokens, prompts, steps, sessions, subagents, and streaks.
18
+ - Spend per project and per model under combined filters. Pick one or both;
19
+ the filtered totals card recomputes for the cut on screen.
20
+ - Subagent spend. Child sessions nest under their parent, and the Incl.
21
+ subagents column rolls descendant cost into the parent at any depth.
22
+ - Which sessions cost the most. Click the Own cost, Incl. subagents, or
23
+ Tokens header to sort; each cycles default, ascending, descending.
24
+ - Which models burned tokens at zero reported cost. The Models table flags
25
+ them `unpriced`.
66
26
 
67
- ```sh
68
- opencode serve --service
69
- ```
27
+ ## Reading the numbers
28
+
29
+ - A number served by the stats endpoint is exact for the window and filter
30
+ cut on screen.
31
+ - When a cut cannot be served, the card sums the session rows instead and
32
+ marks the result `≈` (approximate). The fallback is labeled, never silent.
33
+ - If stats and the session rows disagree about a model, the card says so
34
+ instead of showing either number.
35
+ - Stats totals exclude compaction usage. Session rows and the directory
36
+ fallback include it, so the two totals can differ.
37
+ - Costs are list-price estimates from models.dev, not your bill, and models
38
+ that burn tokens at zero reported cost are undercounted.
70
39
 
71
- If you don't have opencode yet, install it with
72
- `curl -fsSL https://opencode.ai/install | bash` (more options at
73
- https://opencode.ai).
40
+ ## Quick start
74
41
 
75
- ## Install
42
+ Requires Node 22+ with npm, and a running opencode2 service from the
43
+ compatible beta line. oc-dash only issues read-only GETs and never starts,
44
+ stops, or restarts the service.
76
45
 
77
46
  ```sh
78
- npm install
47
+ npx @webfueler/oc-dash
79
48
  ```
80
49
 
81
- ## Develop
50
+ Serves the dashboard on http://localhost:4021. Override the port with `PORT`,
51
+ for example `PORT=4022 npx @webfueler/oc-dash`.
82
52
 
83
- ```sh
84
- npm run dev
85
- ```
53
+ When no registered service answers the startup probe, oc-dash prints a short
54
+ message and exits non-zero. Start the service with `opencode2 serve --service`.
86
55
 
87
- Starts two processes: the API server on port 4021 and the Vite dev server on
88
- port 5273 (http://localhost:5273). The dev server proxies `/api/*` to 4021.
56
+ No opencode2 yet? Install the beta line with
57
+ `npm install -g @opencode-ai/cli@beta`; it puts the `opencode2` command on
58
+ your PATH. Exact money needs the stats route, which the beta line serves
59
+ (`@latest` does not yet). To skip `npx`, `npm i -g @webfueler/oc-dash` puts
60
+ `oc-dash` on your PATH.
89
61
 
90
- ## Build
62
+ ## Using the dashboard
91
63
 
92
- ```sh
93
- npm run build
94
- ```
64
+ Ranges sit in the top bar: Today, 7 days, 30 days, All. A range switch
65
+ refetches and collapses the session tree.
95
66
 
96
- Typechecks the frontend (`tsc --noEmit`), bundles it with Vite into `dist/`,
97
- and compiles the server with `tsc` into `dist-server/`.
67
+ The project and model filters sit above the tables, each with an All entry
68
+ and live counts. Type to search: projects match their full path, models their
69
+ display name and raw id. The model filter ignores reasoning variants; held
70
+ values survive range switches with a truthful 0 when nothing matches.
98
71
 
99
- ## Start (production)
72
+ The filtered totals card appears whenever either filter is active. Its money
73
+ comes from the stats engine when the exact cut can be served; otherwise it is
74
+ the row sum, marked `≈`. A project filter on its own unlocks extra stats
75
+ tiles (prompts, steps, activity, any positive compaction gap); a model filter
76
+ hides them.
100
77
 
101
- ```sh
102
- npm run build
103
- npm run start
104
- ```
78
+ Sessions nest under their parent, collapsed by default. Click a parent row or
79
+ press Enter/Space to expand it; Expand all and Collapse all sit in the
80
+ section head. Own cost is the session's own spend, Incl. subagents adds every
81
+ descendant. The model chip shows the display name, with the raw
82
+ `providerID/id · variant` on hover.
105
83
 
106
- Serves the built frontend and the API from a single process on port 4021
107
- (override with `PORT`). Open http://localhost:4021.
84
+ If the stats endpoint is down, the hero carries a fallback badge and totals
85
+ from the session rows, the filtered card labels its money approximate, and
86
+ the Models table stays empty. The dashboard refreshes every 30 seconds while
87
+ the tab is visible, and right away when it becomes visible again.
108
88
 
109
- ## Test
89
+ ## Known limits
110
90
 
111
- ```sh
112
- npm test # or: npx vitest run
113
- ```
91
+ - The opencode2 API and client are beta; a service update can change
92
+ behavior. Exact money needs a service that serves `session.stats`.
93
+ - The session walk stops after 50 pages of 100 rows. When it truncates, the
94
+ dashboard warns and a directory filter falls back to the approximate row sum.
95
+ - The service endpoint is discovered once and cached. If the service comes
96
+ back on a new port, restart the dashboard.
97
+ - Without a healthy service at startup, oc-dash exits. It never starts or
98
+ restarts one.
114
99
 
115
- Unit tests cover session-tree nesting, the recursive rollup math, unpriced
116
- model detection, and the client-side fallback totals.
100
+ ## Development
117
101
 
118
- ## Lint
102
+ Stack: Hono on Node 22 serves the API and built frontend from one process.
103
+ Frontend: React + Vite + TypeScript, plain CSS, inline-SVG chart. Tests use
104
+ vitest across the server routes, walk, and client logic; lint uses eslint.
119
105
 
120
106
  ```sh
121
- npm run lint
107
+ npm install
108
+ npm run dev # API on 4021, Vite on 5273, /api proxied to 4021
109
+ npm run build # typecheck, bundle the frontend, compile the server
110
+ npm run start # serve the build on 4021
111
+ npm test # vitest
112
+ npm run lint # eslint
122
113
  ```
123
114
 
124
- ## API surface (this app's own backend)
125
-
126
- | Endpoint | Purpose |
127
- | --- | --- |
128
- | `GET /api/health` | Dashboard health plus the opencode service URL and health |
129
- | `GET /api/summary?range=today\|7d\|30d\|all` | `session.stats` for the resolved window, with `tools="summary"` and the machine's local IANA timezone |
130
- | `GET /api/sessions?range=today\|7d\|30d\|all` | Cursor-paginated `GET /api/session` walk (limit 100, capped at 50 pages), windowed by `time.updated >= range start` |
131
-
132
- Range mapping: `today` starts at local midnight; `7d` and `30d` start now
133
- minus N×24h; `all` omits `from`/`to` so stats fall back to the earliest
134
- message. Nesting, filtering, and cost rollup happen in the frontend.
135
-
136
- If the stats endpoint is unavailable, `/api/summary` answers with
137
- `{ "degraded": true, "reason": ... }` instead of an error page, and the UI
138
- falls back to totals computed from the session list (marked as degraded).
115
+ The backend talks to the service through `@opencode/client`, pinned to an
116
+ exact beta build, and is discover-only. See
117
+ [docs/API.md](https://github.com/webfueler/oc-dash/blob/main/docs/API.md) for
118
+ the backend routes, the range mapping, and the project layout.
139
119
 
140
- ## How it connects
120
+ ## License
141
121
 
142
- The backend uses `@opencode/client` (pinned to the `beta` dist-tag) and is
143
- discover-only: `Service.discover()` finds a healthy registered service and
144
- never starts, stops, or restarts one. If nothing healthy is registered when
145
- the dashboard starts, it prints a short message (start `opencode serve
146
- --service`) and exits. If the service dies later, the UI shows its degraded
147
- state instead of crashing. Calls go through the typed client with a raw-fetch
148
- fallback (`Service.headers(endpoint)` auth attached).
149
-
150
- The discovered endpoint is cached for the life of the dashboard process, so
151
- if the opencode service comes back on a different port, restart the
152
- dashboard too.
153
-
154
- ## Estimate caveats (read before quoting numbers)
155
-
156
- - Session costs and the stats totals are **list-price estimates** based on
157
- models.dev pricing data, not your actual bill.
158
- - Providers without price data are **undercounted**: models flagged
159
- `unpriced` in the Models table burn real tokens but report zero cost, so
160
- real spend is higher than shown.
161
- - The stats endpoint adds **compaction usage** (not attributed to any
162
- session) to the totals, so KPI totals can legitimately exceed the sum of
163
- the session rollups in the table.
164
- - Subagent spend rolls up into the parent row; the opencode2 TUI does not
165
- show this.
166
-
167
- ## Project layout
168
-
169
- ```
170
- server/ Hono backend (entry, service connection, range mapping)
171
- src/ React frontend (components, tree/rollup logic, formatting)
172
- src/*.test.ts Unit tests (vitest)
173
- bin/oc-dash.js npx launcher (runs the compiled server)
174
- dist/ Built frontend (gitignored)
175
- dist-server/ Compiled server (gitignored)
176
- ```
122
+ MIT. Source, issues, and releases: https://github.com/webfueler/oc-dash.