opencode-context-indicator 1.1.0 → 1.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.
- package/README.md +67 -8
- package/package.json +9 -5
- package/tui.tsx +54 -4
package/README.md
CHANGED
|
@@ -73,6 +73,10 @@ other 5.6k 12%
|
|
|
73
73
|
updated 12:30:01
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
> Requires a `file://` install from a path outside `node_modules`; on the npm
|
|
77
|
+
> path the sidebar is auto-disabled. See
|
|
78
|
+
> [Live sidebar: npm vs file:// install](#live-sidebar-npm-vs-file-install).
|
|
79
|
+
|
|
76
80
|
### Slash commands (V2)
|
|
77
81
|
|
|
78
82
|
On OpenCode 2.x (Desktop **and** terminal TUI) the plugin registers two slash
|
|
@@ -225,6 +229,9 @@ Notes — these reflect what the plugin API actually exposes today:
|
|
|
225
229
|
therefore delivers everything through the log file, the TUI sidebar and the
|
|
226
230
|
`/context` / `/context-breakdown` slash commands. The sidebar is a TUI-process
|
|
227
231
|
slot and does not exist in the Desktop app; the slash commands work in **both**.
|
|
232
|
+
The TUI sidebar is **live only for a `file://` install** from a path outside
|
|
233
|
+
`node_modules`; on the npm path it is auto-disabled (upstream `#33884`) — see
|
|
234
|
+
[Live sidebar: npm vs file:// install](#live-sidebar-npm-vs-file-install).
|
|
228
235
|
* **V1 has no sidebar and no slash command.** The command/slot API (and the
|
|
229
236
|
`./tui` entry) is a V2 feature; OpenCode 1.x has no equivalent, so V1 is
|
|
230
237
|
toast + log only.
|
|
@@ -275,13 +282,55 @@ or add it to `opencode.jsonc`:
|
|
|
275
282
|
```
|
|
276
283
|
|
|
277
284
|
The `./tui` sidebar entry is loaded automatically alongside the main plugin in
|
|
278
|
-
the terminal TUI
|
|
279
|
-
|
|
285
|
+
the terminal TUI — but its live behaviour depends on the install method, see
|
|
286
|
+
[Live sidebar: npm vs file:// install](#live-sidebar-npm-vs-file-install) below.
|
|
287
|
+
For a CLI-only setup against remote servers, the package can also be listed in
|
|
288
|
+
[`cli.json`](https://opencode.ai/v2/docs/cli/plugins):
|
|
280
289
|
|
|
281
290
|
```json
|
|
282
291
|
{ "plugins": ["opencode-context-indicator"] }
|
|
283
292
|
```
|
|
284
293
|
|
|
294
|
+
### Live sidebar: npm vs file:// install
|
|
295
|
+
|
|
296
|
+
The TUI sidebar is a **TUI-process slot**. On OpenCode 2.x it behaves
|
|
297
|
+
differently depending on **how the plugin was installed** — an upstream OpenCode
|
|
298
|
+
limitation (`anomalyco/opencode#33884`), not a plugin bug: OpenCode's TUI loader
|
|
299
|
+
skips the host Solid transform for any path inside a `node_modules` directory, so
|
|
300
|
+
a slot mounted from an npm install renders once and then never live-updates.
|
|
301
|
+
|
|
302
|
+
| Install | Desktop | TUI commands | TUI live sidebar |
|
|
303
|
+
| --- | :---: | :---: | :---: |
|
|
304
|
+
| npm (`opencode plugin add opencode-context-indicator`) | ✅ | ✅ | ❌ auto-disabled (upstream #33884) |
|
|
305
|
+
| `file://` (path **outside** any `node_modules`) | ✅ | ✅ | ✅ live |
|
|
306
|
+
|
|
307
|
+
On the **npm** path the plugin detects that it lives under `node_modules` and
|
|
308
|
+
**disables the sidebar gracefully** — it logs a single hint and registers no
|
|
309
|
+
slot, so you never see a frozen "no data yet" panel. The `/context` /
|
|
310
|
+
`/context-breakdown` slash commands and the breakdown log file keep working on
|
|
311
|
+
every install.
|
|
312
|
+
|
|
313
|
+
#### Getting the live sidebar (`file://` install)
|
|
314
|
+
|
|
315
|
+
1. Put the package **outside** any `node_modules`: clone the repository, or
|
|
316
|
+
unpack the npm tarball (`npm pack opencode-context-indicator`, then extract
|
|
317
|
+
the `.tgz`) — e.g. into `C:\Users\you\plugins\opencode-context-indicator`.
|
|
318
|
+
Double-check that the chosen path contains **no `node_modules` segment**
|
|
319
|
+
(e.g. `C:\Users\you\plugins\...`, not `.../node_modules/...`).
|
|
320
|
+
2. Point OpenCode at that directory in `~/.config/opencode/opencode.jsonc`:
|
|
321
|
+
|
|
322
|
+
```jsonc
|
|
323
|
+
{
|
|
324
|
+
"plugins": ["file:///C:/Users/you/plugins/opencode-context-indicator"]
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
3. Restart OpenCode. The sidebar is now live and updates as context grows.
|
|
329
|
+
|
|
330
|
+
> ⚠️ The `file://` path must **not** contain a `node_modules` segment. If it
|
|
331
|
+
> does, OpenCode skips the Solid transform and the sidebar will not update; the
|
|
332
|
+
> plugin auto-disables it and logs the hint above.
|
|
333
|
+
|
|
285
334
|
### OpenCode 1.x (V1)
|
|
286
335
|
|
|
287
336
|
Add the package name to the `plugin` array in your `opencode.json`:
|
|
@@ -303,9 +352,11 @@ helper resolves. The `lib/` folder is support code, not a separate plugin entry:
|
|
|
303
352
|
~/.config/opencode/plugins/lib/dedup.js
|
|
304
353
|
```
|
|
305
354
|
|
|
306
|
-
To use the sidebar locally as well,
|
|
307
|
-
|
|
308
|
-
|
|
355
|
+
To use the sidebar locally as well, point OpenCode at a `file://` copy of the
|
|
356
|
+
package that lives **outside any `node_modules`** (see
|
|
357
|
+
[Live sidebar: npm vs file:// install](#live-sidebar-npm-vs-file-install)) — that
|
|
358
|
+
is the only install path that keeps the sidebar live. An npm install auto-disables
|
|
359
|
+
the sidebar instead.
|
|
309
360
|
|
|
310
361
|
---
|
|
311
362
|
|
|
@@ -322,9 +373,17 @@ recommended path for the sidebar).
|
|
|
322
373
|
* **OpenCode ≥ 2.0.16** for the V2 path (built and verified against
|
|
323
374
|
**2.0.19**).
|
|
324
375
|
* **TUI sidebar**: terminal TUI only, requires the OpenTUI rendering stack that
|
|
325
|
-
ships with OpenCode
|
|
326
|
-
|
|
327
|
-
|
|
376
|
+
ships with OpenCode. `@opentui/core` and `solid-js` are **optional** peer
|
|
377
|
+
dependencies resolved by OpenCode at runtime; the main plugin installs and runs
|
|
378
|
+
fine without them (the sidebar simply is not available). `@opentui/solid` is
|
|
379
|
+
instead shipped as a **pinned direct dependency** (exact `0.5.12`): OpenCode's
|
|
380
|
+
TUI loader does not expose a host instance of it, so for npm-installed plugins
|
|
381
|
+
the JSX pragma would otherwise fail to resolve `@opentui/solid/jsx-runtime`
|
|
382
|
+
(upstream: opencode issue #33884 — `node_modules` plugins are excluded from the
|
|
383
|
+
host Solid transform and get an isolated OpenTUI copy). Because of that same
|
|
384
|
+
upstream limitation, on the **npm** path the sidebar is **auto-disabled**
|
|
385
|
+
(the plugin logs one hint and registers no slot) — use a `file://` install for
|
|
386
|
+
the live sidebar, see [Live sidebar: npm vs file:// install](#live-sidebar-npm-vs-file-install).
|
|
328
387
|
|
|
329
388
|
---
|
|
330
389
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-context-indicator",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Real-time OpenCode context-window usage indicator: per-category token breakdown written to a log file, plus an optional TUI sidebar. Dual V1 + V2 plugin entry.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@opencode/plugin": ">=2.0.16",
|
|
39
39
|
"@opentui/core": ">=0.5.12",
|
|
40
|
-
"@opentui/solid": ">=0.5.12",
|
|
41
40
|
"solid-js": ">=1.9.0"
|
|
42
41
|
},
|
|
43
42
|
"peerDependenciesMeta": {
|
|
@@ -47,11 +46,16 @@
|
|
|
47
46
|
"@opentui/core": {
|
|
48
47
|
"optional": true
|
|
49
48
|
},
|
|
50
|
-
"@opentui/solid": {
|
|
51
|
-
"optional": true
|
|
52
|
-
},
|
|
53
49
|
"solid-js": {
|
|
54
50
|
"optional": true
|
|
55
51
|
}
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@opentui/solid": "0.5.12"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@opencode/plugin": "^2.0.19",
|
|
58
|
+
"@opentui/core": "^0.5.12",
|
|
59
|
+
"solid-js": "^1.9.12"
|
|
56
60
|
}
|
|
57
61
|
}
|
package/tui.tsx
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
1
2
|
/**
|
|
2
3
|
* tui.tsx — optional OpenCode TUI sidebar for `opencode-context-indicator`.
|
|
3
4
|
*
|
|
5
|
+
* The import-source pragma on the first line above is REQUIRED: without it the
|
|
6
|
+
* opencode TUI loader (Bun) transforms JSX against the React runtime and emits
|
|
7
|
+
* `import ... from "react/jsx-runtime"`, which the TUI runtime does not provide,
|
|
8
|
+
* so loading the plugin from the npm cache throws `Cannot find package 'react'`
|
|
9
|
+
* (react only ever resolved from a developer's local node_modules). The pragma
|
|
10
|
+
* must stay the very first line, before any import, and no other pragma-like
|
|
11
|
+
* token may appear in this file. See the OpenTUI Solid integration guide.
|
|
12
|
+
*
|
|
4
13
|
* Exposed as the `./tui` package entry ("beside the main plugin for automatic
|
|
5
14
|
* loading"). OpenCode loads it only in the terminal TUI; it is NOT loaded in
|
|
6
15
|
* the Desktop app (Desktop exposes no TUI slot API). It renders the
|
|
@@ -14,19 +23,45 @@
|
|
|
14
23
|
* file renders "no data yet". The main plugin never imports this file, so the
|
|
15
24
|
* absence of the OpenTUI peers cannot break the server/V1 path.
|
|
16
25
|
*
|
|
17
|
-
*
|
|
18
|
-
* @opentui/solid
|
|
26
|
+
* Runtime requirements: @opentui/core and solid-js are optional peers resolved
|
|
27
|
+
* by OpenCode at runtime. @opentui/solid is a pinned direct dependency (exact
|
|
28
|
+
* 0.5.12): OpenCode's TUI loader does not expose a host instance of it, so for
|
|
29
|
+
* npm-installed plugins the JSX pragma would otherwise fail to resolve
|
|
30
|
+
* `@opentui/solid/jsx-runtime` (upstream opencode issue #33884).
|
|
31
|
+
*
|
|
32
|
+
* Graceful mode: when this file is loaded from an npm install (its own path is
|
|
33
|
+
* inside a `node_modules` directory), OpenCode skips the host Solid transform
|
|
34
|
+
* for `node_modules` paths, so a mounted slot renders once and then never
|
|
35
|
+
* live-updates (anomalyco/opencode#33884). Rather than freeze a permanent
|
|
36
|
+
* "no data yet" panel, the entry detects that case, logs a single hint and
|
|
37
|
+
* registers no slot. Install via `file://` from a path outside any
|
|
38
|
+
* `node_modules` for the live sidebar (see README → "Live sidebar").
|
|
19
39
|
*/
|
|
20
40
|
import {Plugin, usePlugin} from "@opencode/plugin/tui"
|
|
21
41
|
import {createSignal, Show} from "solid-js"
|
|
42
|
+
import type {ColorInput} from "@opentui/core"
|
|
22
43
|
import {readFileSync} from "node:fs"
|
|
23
44
|
import {tmpdir} from "node:os"
|
|
24
45
|
import {join} from "node:path"
|
|
46
|
+
import {fileURLToPath} from "node:url"
|
|
25
47
|
|
|
26
48
|
const STATE_FILE = join(tmpdir(), "opencode-context-indicator-state.json")
|
|
27
49
|
const POLL_MS = 1000
|
|
28
50
|
const LABEL_WIDTH = 12
|
|
29
51
|
|
|
52
|
+
// True when this module was loaded from an npm install, i.e. its own file path
|
|
53
|
+
// contains a `node_modules` segment (OpenCode's TUI loader skips the host Solid
|
|
54
|
+
// transform for such paths → slots mount once but never live-update; see the
|
|
55
|
+
// Graceful mode note above). Normalised to forward slashes for Windows paths.
|
|
56
|
+
function isNodeModulesInstall(): boolean {
|
|
57
|
+
try {
|
|
58
|
+
const selfPath = fileURLToPath(import.meta.url).replace(/\\/g, "/").toLowerCase()
|
|
59
|
+
return selfPath.includes("/node_modules/")
|
|
60
|
+
} catch {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
30
65
|
type Categories = {
|
|
31
66
|
user?: number
|
|
32
67
|
assistant?: number
|
|
@@ -62,8 +97,10 @@ function num(v: unknown): number {
|
|
|
62
97
|
// Theme tokens are OpenTUI RGBA values (see ResolvedTheme.text.base/.muted);
|
|
63
98
|
// pass them straight to the renderer. Fall back to a named color when a token
|
|
64
99
|
// is absent so an unexpected theme shape can never blank the sidebar.
|
|
65
|
-
|
|
66
|
-
|
|
100
|
+
// `fg` on <text> is typed as OpenTUI's ColorInput (= string | RGBA); using the
|
|
101
|
+
// same alias keeps the JSX assignment type-correct instead of a loose `object`.
|
|
102
|
+
type Fg = ColorInput
|
|
103
|
+
function token(v: unknown, fallback: Fg): Fg {
|
|
67
104
|
return v && typeof v === "object" ? (v as Fg) : fallback
|
|
68
105
|
}
|
|
69
106
|
|
|
@@ -151,6 +188,19 @@ function Sidebar(props: { entry: () => StateEntry | null }) {
|
|
|
151
188
|
export default Plugin.define({
|
|
152
189
|
id: "context-indicator.tui",
|
|
153
190
|
setup(context) {
|
|
191
|
+
// npm installs (path under node_modules) cannot get live slot updates on
|
|
192
|
+
// this OpenCode version. Stay inert and log a single hint instead of
|
|
193
|
+
// registering a slot that would freeze on "no data yet".
|
|
194
|
+
if (isNodeModulesInstall()) {
|
|
195
|
+
console.log(
|
|
196
|
+
"[context-indicator] TUI sidebar disabled: npm-installed plugins cannot get " +
|
|
197
|
+
"live updates on this OpenCode version (anomalyco/opencode#33884). " +
|
|
198
|
+
'Install via file:// (see README → "Live sidebar") for the live sidebar. ' +
|
|
199
|
+
"Slash commands still work everywhere.",
|
|
200
|
+
)
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
|
|
154
204
|
// Re-read the bridge file once per second and re-render reactively.
|
|
155
205
|
const [tick, setTick] = createSignal(0)
|
|
156
206
|
let currentSession: string | undefined
|