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

opencode-op-loading

v0.2.0

Published

opencode TUI plugin: terminal-title tab indicator — braille spinner while a session works, blinking ? while the agent waits for your input (permission/question).

Readme

opencode-op-loading

opencode TUI plugin that shows session state in the terminal title, which Ghostty and most terminals display in the tab. Two animated modes:

  1. Working: a braille spinner (⠋⠙⠹⠸…, 100ms — the same frames Codex CLI uses) while any session is busy or retrying.
  2. Waiting for you: a slow-blinking ? (500ms) while the agent is blocked on user input — a pending permission request or question. Visually distinct from the spinner so a background tab that needs attention is obvious at a glance.

Titles are written through opencode's own renderer title API and restored on idle.

Desktop notifications and sounds for these same events (permission, question, done, error) are built into opencode itself — enable them in tui.json with "attention": { "enabled": true }. opencode emits OSC 777;notify, which Ghostty turns into a native macOS notification when the terminal is unfocused. This plugin only handles the in-tab indicator.

Behavior

| opencode state | Tab title | | --- | --- | | Any session busy or retry | ⠹ OC \| <session title> (spinning, 100ms) | | Any pending permission or question | ? OC \| <session title> (blinking, 500ms) — wins over working | | All sessions idle | Restored (OC \| <session title>) | | TUI exit | Restored |

Sessions are tracked individually, so one session going idle does not clear the indicator while a subagent or another session is still working or waiting. Pending requests are tracked per session and cleared defensively when a session goes idle or is deleted (an aborted run can end without a reply event). Title writes can never throw into the TUI's event dispatch.

The title mirrors the TUI's own format (OC | <title>, truncated at 40 chars, OpenCode on home/placeholder titles) and respects the TUI's title controls: the "Disable terminal title" toggle (terminal_title_enabled kv) and OPENCODE_DISABLE_TERMINAL_TITLE.

Events used: session.status, session.deleted, permission.asked/permission.replied, question.asked/question.replied/question.rejected.

Install

This is a TUI plugin, so it is registered in tui.json, not in opencode.json.

Add it to one of:

  • ~/.config/opencode/tui.json (global)
  • tui.json / tui.jsonc in your project, or .opencode/tui.json

From a local checkout

{
  "plugin": ["/absolute/path/to/op-loading/src/index.ts"]
}

Relative paths also work and resolve relative to the tui.json that declares them.

From npm (if published)

{
  "plugin": ["opencode-op-loading"]
}

Restart opencode after editing the config — it is read once at startup.

From inside opencode

opencode's TUI has a built-in plugin installer that handles registration for npm packages automatically: open the plugins dialog (command palette → plugins → install), enter the package name, and pick global or project scope. This works because the package declares the exports["./tui"] entry the installer looks for.

Disable

Set OPENCODE_OP_LOADING_DISABLE=1 to turn the plugin off without unregistering it.

Debugging

Set OPENCODE_OP_LOADING_DEBUG=1 to append diagnostics to /tmp/op-loading.log.

Caveats

  • The indicator is cleared on idle, plugin dispose, and normal TUI exit. A hard crash (SIGKILL) can leave it set until the terminal's next title write resets it.
  • If the plugin is loaded while a session is already busy or has a pending request (e.g. opencode attach to a working server), the indicator appears on the next event rather than immediately.

History

v0.1 (opencode-osc94-progress) also emitted the ConEmu OSC 9;4 progress sequence (Ghostty surface bar / Windows Terminal taskbar). Removed in v0.2: the bar is invisible when the tab is in the background (where the indicator matters), and on macOS Ghostty expires it after 15s without a refresh. The title glyph plus opencode's native attention notifications cover the same need with less escape-sequence traffic.

Development

bun install
bun test             # behavior + entry-contract tests
bun run typecheck

No build step: opencode runs on Bun and loads the TypeScript entry directly (src/index.ts is both the dev and published entry; exports["./tui"] points at it because the TUI plugin loader resolves npm packages only via that subpath).

Three ways to load the plugin from source — restart opencode to pick up changes, there is no hot reload:

  1. In this repo: the root tui.json registers ./src/index.ts, so any opencode session started here loads it.
  2. Machine-wide: add "file:///absolute/path/to/op-loading/src/index.ts" to the plugin array in ~/.config/opencode/tui.json. Path specs are normalized to absolute file:// URLs before merging, so the global entry and this repo's tui.json dedupe instead of double-loading.
  3. Isolated sandbox: bun run dev creates a scratch project under .sandbox/ with its own tui.json and launches opencode there (global models/auth still apply, only plugin registration is project-scoped). --reset wipes the sandbox, --print just shows the paths without launching.

Manual verification in Ghostty: submit a prompt and confirm the spinner appears while busy; trigger a permission prompt (e.g. a bash command needing approval) and confirm the tab switches to the blinking ?; answer it and confirm the spinner returns; confirm the title restores on idle, Ctrl+C, and exit.