Skip to content

Latest commit

 

History

History
154 lines (119 loc) · 7.41 KB

File metadata and controls

154 lines (119 loc) · 7.41 KB

Plan: context-view plugin for OpenCode 2

Mark completed stages: [ ][x].

1. What it does

The plugin shows the "invisible" parts of the model context:

  • /context usage — visualization of context window usage: a 14×14 cell map by category (system prompt, tools, user/agent/thinking messages, tool output, compacted data, auto-compact buffer, free space), zoom (z) for large windows, content preview on Enter.
  • /context injections — tree of hidden injections: base prompt, tool definitions, skills, context files, injections from other extensions — with token estimates and raw previews.
  • Key mechanic: capture an Initial context snapshot on the first real turn or via a "silent probe" if a view opens before any turn; filtering of synthetic messages; strict privacy (raw content only via Enter, never logged).

2. Mapping onto the OpenCode 2 plugin architecture

The plugin uses both targets (dual-entrypoint package):

Concern OpenCode 2 equivalent
Per-dispatch capture Server plugin: Plugin.define({ id, setup }) from @opencode-ai/plugin, export ./server
Context event (final prompt + tools) ctx.session.hook("context", ...) — gives system, messages, the tools record right before model dispatch
/context command + fullscreen TUI TUI plugin: export ./tui, types from @opencode-ai/plugin/tui; slash command via api.keymap.registerLayer({ commands: [{ slashName: "context", namespace: "palette", run }] }), page via api.route.register([...])
Rendering JSX through @opentui/solid (host peer-dep), api.ui.Dialog*, api.ui.toast
Reported usage Provider tokens — api.client.session.messages() (usage of the last assistant message); model window — limit.context

V2 notes:

  • TUI plugin config lives in tui.json (or cli.jsonplugins), server plugins in opencode.json(c)plugins; auto-discovery in .opencode/plugins/.
  • Server and TUI are separate processes; they need a data channel.
  • The plugin API is beta: keep a thin adapter layer, version against an OpenCode release.
  • A single module cannot export both server and tui.

3. Data flow between server and TUI parts

Primary option — snapshots on disk. On every session.hook("context") the server plugin writes a snapshot (system prompt, active tools, message classification) to:

~/.cache/opencode/context-view/<hash(directory)>/<sessionID>.json

atomically (tmp + rename). The TUI plugin reads the current session's file when the view opens.

Fallback (degraded mode): without a snapshot (no turns yet), the TUI side builds an estimate from api.client.session.messages() plus heuristics for the prompt/tools, with a [Degraded: …] indicator.

4. Project layout

opencode-context-view/
├── package.json              # exports: "./server" → src/server/index.ts, "./tui" → src/tui/index.tsx
├── src/
│   ├── shared/               # pure types and logic, host-free
│   │   ├── types.ts          # categories, snapshot, usage
│   │   ├── classify.ts       # classify messages/system/tools into categories
│   │   ├── estimate.ts       # token estimation (~4 chars/token heuristic; optional tokenizer)
│   │   └── privacy.ts        # sanitizing, preview rules
│   ├── server/
│   │   └── index.ts          # Plugin.define: session.hook("context") → snapshot on disk
│   └── tui/
│       ├── index.tsx         # TuiPlugin: /context command, routes
│       ├── usage-view.tsx    # map + category legend + block stream
│       ├── injections-view.tsx
│       ├── map.tsx           # map geometry, Window/Fit scale
│       └── preview.tsx       # fullscreen block view
├── test/                     # unit tests for pure modules (classify, estimate, map)
└── doc/

Pure modules (shared/) stay isolated from hosts — easier to test.

5. Stages

Mark completed items in this file.

M0 — scaffold

  • Project scaffold (TypeScript; bun + bun test instead of pnpm/vitest)
  • Dual exports (./server, ./tui) in package.json
  • Dependencies: @opencode-ai/plugin@beta (deliberate deviation from the template's ^1.18.21: session hooks only exist in the v2 branch API); solid-js / @opentui/* types as peer/dev
  • Verify server-side loading in a live OpenCode (opencode2 api get /api/plugin)

M1 — data core (pure functions + tests)

  • Category types (System Prompt, Tools built-in/MCP/custom, User/Agent/Thinking/ Tool-call Messages, Tool Output, Skills/Instructions, Compacted, Free Space)
  • Classifier for the session.hook("context") payload → categories
  • Token estimator: character heuristic (~4 chars/token)
  • Reconcile totals with provider-reported usage — deferred: show estimates only ()
  • Unit tests over payload fixtures

M2 — server capture

  • ctx.session.hook("context") hook
  • Snapshot persistence (atomic tmp+rename, 0600 permissions, keyed by sessionID)
  • Compaction awareness (metadata compact/summary heuristic → "Compacted")
  • Automatic pruning of old snapshots (>7 days, hourly check)
  • Privacy: raw content only in the local snapshot, never logged

M3 — TUI MVP

  • /context slash command (palette, slash arguments [usage|injections]) registered through a keymap layer mounted in the app slot (keymap.layer requires the Keymap.Provider — it only works inside a component, same as internal TUI plugins)
  • Usage view: used/window (%) header, composition bar and per-category entry list
  • Navigation ↑↓, Enter preview, Esc via keymap layer (jk/PgUp/PgDn — under M4)
  • Degraded mode without a snapshot ("No captured dispatch yet…")

M4 — parity with the reference feature set

  • 14×14 map: Window/Fit scale via z, auto-compaction buffer
  • Block stream with gutter, block caps, Enter - View Content
  • Injections view: prompt/tool tree with raw previews
  • Responsive rules (3 width tiers; narrow fallback below 52 columns)
  • Mouse/scroll support, post-preview position restore

M5 — configuration and publishing

  • Override-only config: category colors as OpenCode theme keys (no hex/ANSI)
  • README (install, commands, privacy; no demo GIF yet)
  • Release process (changesets), npm publishing
  • Install: opencode2 plugin add …

6. Invariants

  • Normal turns are unaffected while inspection is not invoked; no provider requests.
  • Raw content only after explicit Enter; never logged and never sent to the model.
  • Parent/child contributions are never double-counted; every rendered line fits the width; views reflow.
  • Thinking-signature bytes are never rendered or persisted — size only.

7. Risks and open questions

  1. Beta APIsession.hook("context") and the TUI keymap/route APIs may change; a thin adapter layer is mandatory.
  2. No public API for the system prompt/tools outside a dispatch — hence server-side capture; if the hook proves insufficient, inspect the http.request hook as the source of truth.
  3. Compaction — V2 summary semantics differ from other agents; verify the actual post-compaction message shape on a live session.
  4. Tokenization — the heuristic diverges from providers; solved by an optional tokenizer dependency and rendering values as estimates ().