opencode-context-indicator 1.1.5 → 1.2.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.
package/README.md CHANGED
@@ -8,8 +8,13 @@ filling it: system prompt, tool schemas, user/assistant text, reasoning, tool
8
8
  arguments and the residual "other" bucket.
9
9
 
10
10
  The package ships a **dual V1 + V2 plugin** (one entry works in both OpenCode
11
- generations) plus an optional TUI sidebar module exposed as the `./tui` entry.
12
- The V2 path is **tested against opencode v2.0.19**; the V1 path against 1.18.29+.
11
+ generations) plus an optional TUI module (`./tui` entry) that renders a **live
12
+ sidebar** and a **zero-LLM `/cx` breakdown panel** with measured contributors
13
+ and a redacted export. The V2 path is **tested against opencode v2.0.22**; the
14
+ V1 path against 1.18.29+.
15
+
16
+ > **V1 is feature-frozen.** It is kept working for compatibility (bug fixes
17
+ > only); all new features land in the V2 path.
13
18
 
14
19
  ![TUI sidebar — per-category context breakdown](docs/sidebar.png)
15
20
 
@@ -38,8 +43,10 @@ For every served request the plugin estimates how the context window is split:
38
43
  (Cyrillic ≈ 2.5, CJK ≈ 1.5, latin/ASCII ≈ 4 chars/token) — not a tokenizer.
39
44
  `reasoning` also carries the exact value reported by the model when present.
40
45
  * `other` is the residual (`input − sum of estimates`).
41
- * Tool **results** are deliberately not counted; only tool **call arguments**
42
- (results are not part of the sent prompt).
46
+ * Tool **results** are deliberately not counted in the server-side categories;
47
+ only tool **call arguments** are. The TUI panel's *largest contributors*
48
+ section **does** measure retained results — that is why it can explain the
49
+ (often large) residual `other` bucket.
43
50
  * `ctx` is OpenCode's native overflow count: `tokens.total` when present, else
44
51
  `input + output + cache.read + cache.write`. Percentages are **not clamped**
45
52
  at 100% — exceeding the window stays visible.
@@ -218,23 +225,57 @@ back to a plain notice if needed.
218
225
  is evicted by the `state.json` LRU cap (`MAX_TRACKED_SESSIONS`) — it may
219
226
  momentarily appear in the table.
220
227
 
228
+ ### TUI session panel (V2, terminal only)
229
+
230
+ #### TUI panel (/cx) — zero-LLM breakdown
231
+
232
+ `/cx` opens a full `session.panel` showing the breakdown for the current session
233
+ **and its subagent descendants**, read from the same `state.json` bridge as the
234
+ sidebar. Keys: `/cx` opens, `esc` closes, `r` refreshes (re-read the bridge),
235
+ `e` exports a redacted snapshot.
236
+
237
+ **Zero LLM calls.** Unlike `/context` and `/context-breakdown` (which run a real
238
+ agent turn so the model renders the table), the panel only reads local TUI data
239
+ and the state file; it never wakes the session and never grows the context.
240
+
241
+ The **largest contributors (measured)** section char-counts the in-process
242
+ message list and labels each row `assistant 21:04 reasoning — 4.5k "…"`: role
243
+ in full words, the message's own clock time, the bucket (`reasoning` /
244
+ `tool args (bash)` / `tool result (task)`), the token estimate and a bounded
245
+ one-line preview of that part. Tool calls are measured **per tool call** (each
246
+ carries its tool name); tool **result outputs** are counted here but not by the
247
+ server's categories — which is why the residual `other` can look large. Top 5
248
+ are shown. Empty state: `no messages yet`.
249
+
250
+ Live only for a `file://` install from a path outside `node_modules`; the npm
251
+ path auto-disables it (upstream `#33884`). The Desktop has no TUI, so it uses
252
+ `/context` and `/context-breakdown` instead.
253
+
254
+ #### Export (redacted)
255
+
256
+ `e` writes a redacted JSON snapshot — no message text, no full session id, no
257
+ tool output content — under `%TEMP%/opencode-context-indicator/exports/`
258
+ (`$TMPDIR/...` elsewhere), named `context-<id8>-<yyyymmdd-HHMMSSmmm>.json`, and
259
+ shows a toast with the file name. It never throws; on failure it logs and shows
260
+ an error toast.
261
+
221
262
  ---
222
263
 
223
264
  ## Surface matrix
224
265
 
225
- | Surface | Toast | TUI sidebar | Breakdown log file | Slash commands |
226
- | --- | :---: | :---: | :---: | :---: |
227
- | OpenCode **1.x** — Desktop | ✅ | — | ✅ | — |
228
- | OpenCode **1.x** — TUI | ✅ | — | ✅ | — |
229
- | OpenCode **2.x** — TUI | — | ✅ | ✅ | ✅ |
230
- | OpenCode **2.x** — Desktop | — | — | ✅ | ✅ |
266
+ | Surface | Toast | TUI sidebar | TUI panel (/cx) | Breakdown log file | Slash commands |
267
+ | --- | :---: | :---: | :---: | :---: | :---: |
268
+ | OpenCode **1.x** — Desktop | ✅ | — | — | ✅ | — |
269
+ | OpenCode **1.x** — TUI | ✅ | — | — | ✅ | — |
270
+ | OpenCode **2.x** — TUI | — | ✅ | ✅ | ✅ | ✅ |
271
+ | OpenCode **2.x** — Desktop | — | — | — | ✅ | ✅ |
231
272
 
232
273
  Notes — these reflect what the plugin API actually exposes today:
233
274
 
234
275
  * **V2 has no toast channel on the server side.** The V2 plugin API
235
276
  (`ctx.*`) exposes no TUI/toast method (opencode issue `#49380`); the V2 path
236
- therefore delivers everything through the log file, the TUI sidebar and the
237
- `/context` / `/context-breakdown` slash commands. The sidebar is a TUI-process
277
+ therefore delivers everything through the log file, the TUI sidebar, the
278
+ `/cx` session panel and the `/context` / `/context-breakdown` slash commands. The sidebar is a TUI-process
238
279
  slot and does not exist in the Desktop app; the slash commands work in **both**.
239
280
  The TUI sidebar is **live only for a `file://` install** from a path outside
240
281
  `node_modules`; on the npm path it is auto-disabled (upstream `#33884`) — see
@@ -255,7 +296,7 @@ and `$TMPDIR` (usually `/tmp`) elsewhere:
255
296
  | File | Purpose |
256
297
  | --- | --- |
257
298
  | `context-breakdown.log` | Human-readable live snapshot + bounded final summaries |
258
- | `opencode-context-indicator-state.json` | Machine-readable snapshot consumed by the TUI sidebar |
299
+ | `opencode-context-indicator-state.json` | Machine-readable snapshot consumed by the TUI sidebar and the `/cx` panel |
259
300
  | `context-events.log` | Raw event tap — **only** when `DEBUG_EVENTS` is flipped to `true` in the source (off by default) |
260
301
 
261
302
  The live `context-breakdown.log` snapshot is **rewritten** (never grows); final
@@ -306,15 +347,15 @@ limitation (`anomalyco/opencode#33884`), not a plugin bug: OpenCode's TUI loader
306
347
  skips the host Solid transform for any path inside a `node_modules` directory, so
307
348
  a slot mounted from an npm install renders once and then never live-updates.
308
349
 
309
- | Install | Desktop | TUI commands | TUI live sidebar |
310
- | --- | :---: | :---: | :---: |
311
- | npm (`opencode plugin add opencode-context-indicator`) | ✅ | ✅ | ❌ auto-disabled (upstream #33884) |
312
- | `file://` (path **outside** any `node_modules`) | ✅ | ✅ | ✅ live |
350
+ | Install | Desktop | TUI commands | TUI live sidebar | TUI panel (/cx) |
351
+ | --- | :---: | :---: | :---: | :---: |
352
+ | npm (`opencode plugin add opencode-context-indicator`) | ✅ | ✅ | ❌ auto-disabled (upstream #33884) | ❌ auto-disabled |
353
+ | `file://` (path **outside** any `node_modules`) | ✅ | ✅ | ✅ live | ✅ live |
313
354
 
314
355
  On the **npm** path the plugin detects that it lives under `node_modules` and
315
- **disables the sidebar gracefully** — it logs a single hint and registers no
316
- slot, so you never see a frozen "no data yet" panel. The `/context` /
317
- `/context-breakdown` slash commands and the breakdown log file keep working on
356
+ **disables the sidebar and the panel gracefully** — it logs a single hint and
357
+ registers no slot, so you never see a frozen "no data yet" panel. The `/context`
358
+ / `/context-breakdown` slash commands and the breakdown log file keep working on
318
359
  every install.
319
360
 
320
361
  #### Getting the live sidebar (`file://` install)
@@ -350,13 +391,21 @@ Add the package name to the `plugin` array in your `opencode.json`:
350
391
 
351
392
  ### Local file (no npm)
352
393
 
353
- Copy `index.js` and `lib/dedup.js` into `~/.config/opencode/plugins/`, keeping
354
- the `lib/` subdirectory next to the plugin file so the plugin's `import` of the
355
- helper resolves. The `lib/` folder is support code, not a separate plugin entry:
394
+ Copy `index.js` and the whole `lib/` directory into
395
+ `~/.config/opencode/plugins/`, keeping the `lib/` subdirectory next to the
396
+ plugin file so the plugin's relative imports resolve. The `lib/` folder is
397
+ support code, not a separate plugin entry:
356
398
 
357
399
  ```
358
400
  ~/.config/opencode/plugins/context-indicator.js
401
+ ~/.config/opencode/plugins/lib/cache.js
402
+ ~/.config/opencode/plugins/lib/commands.js
359
403
  ~/.config/opencode/plugins/lib/dedup.js
404
+ ~/.config/opencode/plugins/lib/estimate.js
405
+ ~/.config/opencode/plugins/lib/limits.js
406
+ ~/.config/opencode/plugins/lib/state.js
407
+ ~/.config/opencode/plugins/lib/v1.js
408
+ ~/.config/opencode/plugins/lib/v2.js
360
409
  ```
361
410
 
362
411
  To use the sidebar locally as well, point OpenCode at a `file://` copy of the
@@ -372,18 +421,21 @@ the sidebar instead.
372
421
  * **Node.js ≥ 18** (the main plugin uses only Node built-ins). `@opencode/plugin`
373
422
  is an **optional** peer dependency: OpenCode resolves it at runtime, and
374
423
  `index.js` itself does not import it (the V2 `define` helper is inlined).
375
- * **OpenCode ≥ 1.18.29** for the V1 path. ⚠️ The V1 path relies on
376
- `experimental.chat.*` hooks, which are **experimental** and may change or stop
377
- firing in future OpenCode 1.x releases; if they do, the indicator degrades
424
+ * **OpenCode ≥ 1.18.29** for the V1 path. ⚠️ **V1 is feature-frozen** — it
425
+ receives bug fixes only; all new features land in the V2 path. The V1 path
426
+ relies on `experimental.chat.*` hooks, which are **experimental** and may
427
+ change or stop firing in future OpenCode 1.x releases; if they do, the
428
+ indicator degrades
378
429
  gracefully (the breakdown falls back to throttled `session.messages` fetches
379
430
  and toasts keep working).
380
431
  * **OpenCode ≥ 2.0.16** for the V2 path (built and verified against
381
- **2.0.19**).
432
+ **2.0.22**).
382
433
  * **TUI sidebar**: terminal TUI only, requires the OpenTUI rendering stack that
383
434
  ships with OpenCode. `@opentui/core` and `solid-js` are **optional** peer
384
435
  dependencies resolved by OpenCode at runtime; the main plugin installs and runs
385
436
  fine without them (the sidebar simply is not available). `@opentui/solid` is
386
- instead shipped as a **pinned direct dependency** (exact `0.5.12`): OpenCode's
437
+ instead shipped as a **pinned direct dependency** (exact `0.5.14`, matching
438
+ the OpenTUI stack OpenCode 2.0.22 ships): OpenCode's
387
439
  TUI loader does not expose a host instance of it, so for npm-installed plugins
388
440
  the JSX pragma would otherwise fail to resolve `@opentui/solid/jsx-runtime`
389
441
  (upstream: opencode issue #33884 — `node_modules` plugins are excluded from the
@@ -419,7 +471,10 @@ The package default export is a dual plugin:
419
471
  experimental transform hooks + toasts.
420
472
 
421
473
  Both paths write the same breakdown log; the V2 path additionally feeds the
422
- sidebar through `opencode-context-indicator-state.json`. Cross-instance
474
+ sidebar and the `/cx` panel through `opencode-context-indicator-state.json`.
475
+ The `./tui` entry (OpenCode 2.x terminal TUI) renders the sidebar slot and the
476
+ `session.panel` contribution (`/cx`), with measured per-part contributors and
477
+ the redacted export. Cross-instance
423
478
  duplicate final summaries are suppressed with an atomic claim marker
424
479
  (`lib/dedup.js`). Every file / estimate / subagent path is fault-tolerant: a
425
480
  failure is logged and never breaks the main event or toast path.
@@ -429,14 +484,6 @@ This plugin does not touch `opencode-token-monitor`
429
484
 
430
485
  ---
431
486
 
432
- ## Screenshots
433
-
434
- <!-- TODO: add screenshots -->
435
-
436
- _(to be added)_
437
-
438
- ---
439
-
440
487
  ## Contributing
441
488
 
442
489
  Issues and pull requests are welcome. Please keep changes minimal and
@@ -467,10 +514,12 @@ STEP 80 s, ~3 min total.
467
514
 
468
515
  | Step | What | Why |
469
516
  |---|---|---|
470
- | (a) tarball composition | `package.json` `files[]` field expands to exactly 6 members | no test/node_modules/tsconfig in the tarball |
517
+ | (a) tarball composition | `package.json` `files[]` expands to the base files plus every `lib/*` module (count asserted dynamically) | no test/node_modules/tsconfig in the tarball |
471
518
  | (b) pragma regression | esbuild `--jsx=automatic` → `@opentui/solid/jsx-runtime` present, `react/jsx-runtime` absent | a removed/broken pragma kills the sidebar on npm install |
472
519
  | (c) resolve chain | replica install → `import.meta.resolve` for all tui.tsx imports | broken peer/optional dep silently breaks the sidebar |
473
520
  | (d) unit harness T1–T12 | all limit/agent/state fix assertions | regressions in modelLimits, writeStateFile, hydrate |
521
+ | (e) corporate-identifier scan | no forbidden identifiers in the published surface + test tree | compliance |
522
+ | (f) non-English scan | no non-ASCII letters (`\p{L}` above U+007F) in any repo file | English-only source rule |
474
523
 
475
524
  **Isolated E2E — `test/e2e-tui.mjs`** (requires the OpenCode CLI)
476
525