npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aexol/opencode-tui

v0.3.6

Published

OpenCode TUI plugin bundle with a SQLite-backed server recall target

Readme

@aexol/opencode-tui

@aexol/opencode-tui is an OpenCode plugin package that ships explicit target-only plugin entrypoints: a TUI bundle for local sidebar and prompt utilities plus a small server target for compaction continuation control and local session recall.

The TUI bundle entrypoint is src/tui.ts, exposed as ./tui under plugin id @aexol/opencode-tui. The package also exposes src/server.ts as ./server, a separate target-only server module that keeps the compaction auto-continue hook and adds direct readonly SQLite session recall tools. There is no root . runtime export. TUI plugins are registered through the static registry in src/plugins/registry.ts, and the server target delegates through src/plugins/server/index.ts.

What this repo ships

Package-level plugin targets:

  • ./tuisrc/tui.ts → the real TUI bundle
  • ./serversrc/server.ts → server hooks for compaction auto-continue gating plus readonly session recall tools

TUI registry plugins only

This list is the TUI bundle registry from src/plugins/registry.ts only.

  • It is the ordered list of plugins mounted by ./tui.
  • It is not the shared config-key list.
  • It does not include server-only gates or tools.
  • databasesessions is intentionally absent here because it is a shared config key for the separate ./server target, not a TUI registry plugin.

The TUI bundle currently wires these plugins, in registry order:

  1. tps
  2. autoapprove
  3. usage
  4. notifications
  5. sessions
  6. enchanter
  7. autopilot
  8. queue

That 8-item order is the source of truth for TUI registry docs and contributor guidance.

Repo map

  • src/tui.ts — TUI plugin entry; loops over the static registry
  • src/server.ts — target-only server plugin entry that delegates to src/plugins/server/index.ts
  • src/plugins/registry.ts — canonical plugin registration order and config-key wiring
  • src/plugins/server/index.ts — canonical server export surface for compaction gating and session recall tools
  • src/config.ts — config loader for plugin toggles and plugin settings
  • src/constants.ts — plugin id and config filename constants
  • scripts/generate-screenshots.tsx — scripted screenshot regeneration entrypoint
  • scripts/screenshot-*.ts* — OpenTUI test-render fixtures and local-environment rasterization helpers for plugin PNGs
  • src/plugins/shared/session-prompt.tsx — shared wrapper that renders the live prompt and publishes session-scoped prompt refs for prompt-mutating features
  • src/plugins/** — TUI plugin implementations plus the server export
  • src/plugins/server/** — server-target implementation files
  • src/plugins/*/README.md — per-plugin behavior and file-layout notes
  • docs/test-scenarios/** — manual local runtime smoke scenarios for plugin behavior that needs a real OpenCode host

Plugin docs

| Plugin | README | Screenshot assets | | --- | --- | --- | | TPS | src/plugins/tps/README.md | tps.png | | Auto-approve | src/plugins/autoapprove/README.md | autoapprove.png | | Usage | src/plugins/usage/README.md | sidebar.png, copilot-usage.png, codex-usage.png | | Notifications | src/plugins/notifications/README.md | notifications.png | | Sessions | src/plugins/sessions/README.md | sessions.png | | Enchanter | src/plugins/enchanter/README.md | enchanter.png | | Goal (autopilot key) | src/plugins/autopilot/README.md | autopilot.png | | Queue | src/plugins/queue/README.md | queue.png, queue-dialog.png |

Installation

Package metadata exposes explicit target-specific modules only:

  • @aexol/opencode-tui/tui resolves through the package ./tui export
  • @aexol/opencode-tui/server resolves through the package ./server export

Host config is split across OpenCode's two host layers:

  • ~/.config/opencode/opencode.jsonc is the server/plugin host config
  • ~/.config/opencode/tui.jsonc is the TUI host config

If you want both host layers to load this package in a normal local setup, add @aexol/opencode-tui@latest to both hosts' plugin arrays. The package metadata (oc-plugin: ["server", "tui"]) still matters, but it does not collapse the two host config files into one.

There is still no root package runtime export. The server target stays separate from the TUI registry, while both targets share the plugin-owned config file documented below.

Server target behavior

The separate ./server target currently exposes:

  • experimental.compaction.autocontinue gating that respects the persisted automation continuation policy already used by local queue/Goal behavior
  • session-list for local SQLite-backed session discovery by metadata/time filters, with recent-session ordering and user/assistant message counts
  • session-search for substring search across local OpenCode user/assistant text parts, with simple scoping filters for session/project/worktree/role/time
  • session-messages for browsing one local session's user/assistant messages with offset/limit/order/role controls
  • session-message for reading one local user/assistant message with its ordered text parts
  • session-context for expanding a small user/assistant message window around one local message id
  • session-transcript for reading one local session's user/assistant text transcript in ascending or descending order

Those server features are separate from the TUI registry list above. They are not TUI plugins and should not be added to the 8-item registry-order section.

The recall tools read the local OpenCode SQLite database in readonly mode. Database path resolution prefers OPENCODE_DB_PATH, then opencode db path, then ~/.local/share/opencode/opencode.db. They stay deliberately local and lightweight: no remote services, embeddings, large fuzzy-ranking stacks, or SDK-internal coupling.

For local development overrides, point each host at its own target artifact instead of assuming one host entry covers both:

// ~/.config/opencode/opencode.jsonc
{
  "plugin": ["/home/alek/projects/opencode-tui/dist/server.js"]
}
// ~/.config/opencode/tui.jsonc
{
  "plugin": ["/home/alek/projects/opencode-tui/dist/tui.js"]
}

You can reference just one direct target during development, but dist/tui.js and dist/server.js remain separate entrypoints and belong in different host config files.

Configuration

The package-owned shared plugin config lives at:

~/.config/opencode/aexol-opencode-tui.jsonc

Config rules in this repo:

  • the file uses a top-level plugins object
  • shared plugin-owned config keys currently include the 8 TUI registry keys tps, autoapprove, usage, notifications, sessions, enchanter, autopilot, queue, plus databasesessions
  • databasesessions is a shared config key, not a TUI registry plugin
  • each plugin should use an explicit object shape
  • missing plugin flags default to enabled
  • this file is shared by the TUI and server targets
  • plugins.databasesessions.enabled controls whether the server target registers the readonly session-list, session-search, session-messages, session-message, session-context, and session-transcript tools
  • config examples are the canonical source of truth; there is no shipped JSON schema

Canonical example:

{
  "plugins": {
    "tps": {
      "enabled": true
    },
    "autoapprove": {
      "enabled": true
    },
    "usage": {
      "enabled": true,
      "settings": {
        "copilot": {
          "enabled": true,
          "collect": true
        },
        "codex": {
          "enabled": true,
          "collect": true
        }
      }
    },
    "notifications": {
      "enabled": true,
      "settings": {
        "volume": 40,
        "eventFiles": {
          "question.asked": "/home/alek/.config/opencode/sounds/staplebops-01.aac",
          "permission.asked": "/home/alek/.config/opencode/sounds/staplebops-02.aac",
          "session.error": "/home/alek/.config/opencode/sounds/nope-03.aac",
          "session.completed": "/home/alek/.config/opencode/sounds/completed.mp3"
        }
      }
    },
    "sessions": {
      "enabled": true,
      "settings": {
        "recentSessions": 5
      }
    },
    "enchanter": {
      "enabled": true,
      "settings": {
        "model": "github-copilot/gpt-5.4"
      }
    },
    "autopilot": {
      "enabled": true,
      "settings": {
        "model": "github-copilot/gpt-5.4",
        "maxTurns": 6,
        "minConfidenceToContinue": 0.8,
        "cooldownMs": 5000,
        "askPolicy": "auto"
      }
    },
    "queue": {
      "enabled": true
    },
    "databasesessions": {
      "enabled": true
    }
  }
}

Plugin behavior reference

TPS

  • token-rate display plugin registered first in the prompt-right strip
  • when live samples go stale after a completed response, the fallback completed-message rate is shown and labeled avg

Autoapprove

  • state is root-session-family scoped, not exact-session scoped
  • a root session and its child/subagent sessions share one auto-approve toggle and permission-drain scope
  • it should only drain permission asks inside the active root session family
  • runtime listens only to confirmed permission lifecycle events plus route/session family refreshes
  • active-family permission.asked drains/replies without reloading unrelated families
  • permission.replied updates handled-request state
  • newly observed permission asks refresh the active root-session family before draining when needed
  • route changes reload the active root-session family
  • speculative permission.ask handling is intentionally not part of the contract
  • the app slot remains the primary runtime owner, while prompt-right proactively self-bootstraps via an idempotent fallback ensureReady(...) path when needed
  • if family-scope loading fails, the runtime degrades to current-session-only fallback, shows a warning toast, and exposes that degraded scope in the prompt-right control via a solo badge

Usage

  • settings live under plugins.usage.settings.{copilot,codex}
  • each provider uses { enabled, collect }
  • history files are written only when collect: true
  • history files live at:
    • ~/.local/share/opencode/copilot-usage-history.json
    • ~/.local/share/opencode/codex-usage-history.json
  • retained history is roughly 90 days for compact detail-dialog context
  • the plugin loads usage data on mount and manual refresh only
  • Copilot and Codex load independently so one provider can remain visible if the other errors
  • percentages, timestamps, and day labels use the runtime locale consistently

Notifications

  • event notifications route through host api.attention.notify when available
  • sound settings live in plugins.notifications.settings.{volume,eventFiles}
  • sound files are discovered from ~/.config/opencode/sounds
  • the sidebar keeps volume controls plus a runtime-only inline playback enable/disable action that does not persist to config, and still surfaces invalid override warnings
  • configured or discovered local sound files are preserved as a compatibility path: host notification is still sent, host sound is disabled for that event, and the plugin plays the local file through its serialized runtime queue
  • if host attention does not play a sound, the plugin falls back to local playback; manual/test playback remains local
  • completion sounds are limited to the active root session and suppressed after interrupt or error events
  • docs and examples should continue to show all four event file keys

Sessions

  • settings live under plugins.sessions.settings.{recentSessions}
  • the sessions sidebar no longer refreshes on global message.updated
  • live session.status updates drive busy/idle cues without forcing a full reload
  • load failures render a distinct error state with retry instead of collapsing into the empty state

Enchanter

  • separate plugin/config flag from queue
  • renders as a compact icon-only wand action in prompt-right UI, with hover styling
  • rewrites only the current session draft and does not submit it
  • preserves the user's language and only enriches or clarifies the existing draft unless the user explicitly asks for translation or broader changes
  • mixed prompts keep attached files and agent mentions unchanged while only the text portion is rewritten
  • requires plugins.enchanter.settings.model
  • that model must be set as provider/model
  • there is no global small_model fallback

Goal (autopilot config key)

  • separate plugin/config flag from queue and enchanter
  • runtime is app-mounted so idle/status listeners remain active outside sidebar remounts
  • current goal objective and state persist only for the exact currently routed session; child/subagent sessions do not inherit it
  • inspired by Codex CLI /goal, but implemented locally in this TUI plugin rather than integrated with Codex CLI internals
  • supported TUI actions are Set/Replace, Pause, Resume, Clear, and Audit log; command-like /goal ... prompt interception is not available through the current plugin API, so the sidebar is the supported control surface
  • goal states are active, paused, budgetLimited, and complete; objectives are bounded to 4000 characters and persist across turns/compaction
  • Set/Replace immediately submits the objective as the first live prompt turn when the session is idle, the prompt ref is available, the model config is valid, current-session asks are resolved according to policy, and the current-session queue length is zero; if a gate is unsafe, the active goal persists and starts later when the gate clears
  • requires plugins.autopilot.settings.model for the hidden goal audit session
  • that model must be set as provider/model
  • plugins.autopilot.settings.askPolicy defaults to "auto", which replies to current-session permissions with reply: "always" but leaves question asks for the user; set "manual" (or legacy alias "block") to leave all asks pending, or opt in to "aggressive" to also auto-reject current-session questions
  • main UI is sidebar-only as a compact status card with state, gate summary, elapsed time, ask policy, turn counts, latest audit summary, and audit-log access
  • uses a hidden temporary child session as a sidecar audit and expects structured decisions with status, confidence, reason, nextPrompt, and evidence
  • the audit dialog shows the goal objective, latest audit prompt, and latest parsed decision details in bounded readable sections when available
  • local gates stop autonomous continuation on max-turn/budget cap, cooldown, and queue collisions
  • queue coordination is strict and unconditional: Goal must not audit or continue unless the current session queue length is exactly zero
  • while Goal is active for the routed session under the default auto ask policy, current-session permissions are auto-replied with reply: "always" and current-session questions remain pending for the user; "aggressive" additionally auto-rejects current-session questions, and unresolved, manually blocked, still-pending, or failed asks still block continuation before auditing or first-turn submission
  • missing or malformed plugins.autopilot.settings.model config is surfaced immediately in sidebar/runtime state so invalid config blocks continuation before the first judge run
  • on route load/remount, Goal hydrates persisted current-session queue length before acting so queued drafts still block continuation even before the queue UI remounts
  • continuations replay through promptRef.set(...) + promptRef.submit() so submission uses the live selected model, agent, and variant

Queue

  • queue state is exact-session scoped: queued drafts, badge count, and pause/resume state are keyed by the exact current session id
  • the queue badge reflects only the current session's queued draft count
  • queue rows expose mixed prompt parts with compact text/file/agent counts so queued items with attachments stay distinguishable
  • inline editing is intentionally limited to text-only queued drafts; mixed items should be re-queued from the live prompt if their non-text parts need changes
  • queued drafts replay through promptRef.set(...) + promptRef.submit() so submission uses the live selected model, agent, and variant
  • prompt reconstruction preserves real pasted text content instead of OpenCode's visual [Pasted ~X lines] placeholder
  • queue status uses session.status as the primary gating and cycle-tracking surface
  • there is still a compatibility session.idle fallback
  • queue auto-drain does not poll prompt state; append validates on click, and auto-drain is interaction/submission/status-driven
  • the implementation keeps a small persisted queued-send-cycle remount snapshot for continuity across remounts
  • Goal/autopilot coordination stays indirect through a shared internal bridge; queue does not depend on Goal internals

Prompt-right integration contract

Prompt-mutating features in this repo must use src/plugins/shared/session-prompt.tsx. Plain session_prompt_right slots do not get the live prompt ref, so the shared wrapper publishes session-scoped prompt refs for consumers like queue, enchanter, and Goal/autopilot.

The shared wrapper renders the prompt-right strip in this order:

  1. token rate
  2. queue
  3. enchanter
  4. other prompt-right extensions wired through the shared wrapper

Local development

Install dependencies:

bun install

Typical verification flow:

bun run screenshots
bun test src/plugins/tps/metrics.test.ts
bun run typecheck
bun run lint
bun run build
bun test

Manual runtime smoke checklists live under docs/test-scenarios/ for behavior that needs a rebuilt local plugin target plus an OpenCode host restart.

Screenshot regeneration

Plugin PNGs under src/plugins/** are generated assets, not hand-captured screenshots.

  • Command: bun run screenshots
  • Fixture source: scripts/screenshot-fixtures.tsx
  • Entry script: scripts/generate-screenshots.tsx
  • Rendering source: OpenTUI test rendering via @opentui/solid/@opentui/core test helpers
  • Rasterization: headless Chrome/Chromium against a generated SVG snapshot with framed presentation around the captured TUI output

The command refreshes the checked-in plugin assets in place and requires a local Chrome/Chromium binary (google-chrome, chromium, or CHROME_BIN). Final PNGs depend on the local browser and available fonts, so treat them as generated repo assets rather than byte-for-byte portable output across every machine.

Published output includes separate target-only entry builds:

  • TUI runtime/types: dist/tui.js, dist/tui.d.ts
  • server runtime/types: dist/server.js, dist/server.d.ts

Published package metadata exposes those builds only through ./tui and ./server; it does not alias . to the TUI build.

bun run build emits both runtime .js files and declaration .d.ts files into dist/.

Contributor orientation

  • Start at src/tui.ts for the active registration flow.
  • Read src/plugins/registry.ts before changing docs that mention plugin order or plugin names.
  • Read src/config.ts before changing config docs or examples.
  • Read the target src/plugins/*/README.md before editing a plugin implementation.
  • Reuse src/plugins/shared/** only when duplication is real across multiple plugins.

Useful folder split notes:

  • src/plugins/queue/ includes index.tsx, prompt.ts, state.tsx, ui.tsx, types.ts, automation-policy.ts, prompt.test.ts, and state.test.ts
  • src/plugins/notifications/ includes index.tsx, sidebar.tsx, pending.ts, types.ts, runtime.ts, attention.ts, settings-config.ts, and sound-playback.ts
  • src/plugins/sessions/ includes index.tsx, sidebar.tsx, helpers.ts, and types.ts