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-manager

v0.4.6

Published

Terminal UI for inspecting OpenCode metadata stores.

Readme

Note: This is an independent, community-maintained project created by fans of OpenCode. We are not affiliated with SST Corp. or the official OpenCode project. For the official OpenCode CLI, visit opencode.ai.

OpenCode Metadata Manager

Terminal UI for inspecting, filtering, and pruning OpenCode metadata stored on disk. The app is written in TypeScript, runs on Bun, and renders with @opentui/react.

Screenshots

Features

  • List both OpenCode projects and sessions from a local metadata root.
  • Filter by "missing only", bulk-select, and delete metadata safely.
  • Jump from a project directly to its sessions and keep contextual filters.
  • Fuzzy search across session titles and metadata (/ to focus, results ranked by relevance).
  • View session chat history with full conversation context (V to open viewer).
  • Search across all chat content in sessions within a project (F to search).
  • Rename sessions inline (Shift+R) with title validation.
  • Move sessions between projects (M) preserving session ID.
  • Copy sessions to other projects (P) with new session ID generation.
  • Rich help overlay with live key hints (? or H).
  • Zero-install via bunx so even CI shells can run it without cloning.
  • Token counting: View token usage per session, per project, and globally.
  • Experimental SQLite backend: Faster queries for large stores via --experimental-sqlite.

Token Counting

The TUI displays token telemetry from OpenCode's stored message data at three levels:

  1. Per-session: Shows a breakdown in the session Details pane (Input, Output, Reasoning, Cache Read, Cache Write, Total).
  2. Per-project: Shows total tokens for the highlighted project in the Projects panel.
  3. Global: Shows total tokens across all sessions in the header bar.

Token Definitions

| Field | Description | |---|---| | Input | Tokens in the prompt sent to the model | | Output | Tokens generated by the model | | Reasoning | Tokens used for chain-of-thought reasoning (some models) | | Cache Read | Tokens read from provider cache | | Cache Write | Tokens written to provider cache | | Total | Sum of all token fields |

Behavior Notes

  • Token data is read from storage/message/<sessionId>/*.json files (assistant messages only).
  • If token telemetry is missing or unreadable, the display shows ? instead of 0.
  • Token summaries are cached in memory and refreshed when you press R to reload.
  • Large datasets are handled with lazy computation to avoid UI freezes.

Requirements

  • Bun 1.3.0+ (developed/tested on 1.3.x).
  • A node-compatible terminal (truecolor improves readability but is optional).

Installation

# Clone the repo and install deps
git clone [email protected]:kcrommett/oc-manager.git
cd oc-manager
bun install

# Or run on demand without cloning
bunx opencode-manager --help

The repository ships with a focused .gitignore, keeping node_modules/, caches, and logs out of Git history.

Usage

The manager provides both a Terminal UI (TUI) and a scriptable CLI interface.

Terminal UI (TUI)

The TUI is the default interface when no subcommand is provided:

# Preferred: zero-install command
bunx opencode-manager --root ~/.local/share/opencode

# Local dev run (forwards extra args after --)
bun run tui -- --root ~/.local/share/opencode

# Legacy Python wrapper (still used by some automation)
./manage_opencode_projects.py --root ~/.local/share/opencode -- --help

Keyboard reference:

  • Global: Tab/1/2 switch tabs, / search (fuzzy), X clear search, R reload, Q quit, ?/H help.
  • Projects: Space toggle selection, A select all, M missing-only filter, D delete, Enter jump to Sessions, Esc clear selection.
  • Sessions: Space select, A select all, S toggle sort, V view chat, F search chats, D delete, Y copy ID, Shift+R rename, M move, P copy, C clear filter, Enter details, Esc clear selection.
  • Chat Search: Type query + Enter to search, Up/Down navigate, Enter opens result, Esc close.
  • Chat Viewer: Esc close, Up/Down navigate, PgUp/PgDn jump 10, Home/End first/last, Y copy message.

Command Line Interface (CLI)

The CLI provides scriptable access to all management operations. Use subcommands to list, search, and modify metadata.

Global Options

| Option | Default | Description | |--------|---------|-------------| | -r, --root <path> | ~/.local/share/opencode | Root path to OpenCode metadata store | | -f, --format <fmt> | table | Output format: json, ndjson, or table | | -l, --limit <n> | 200 | Maximum number of records to return | | --sort <order> | updated | Sort order: updated or created | | -y, --yes | false | Skip confirmation prompts for destructive operations | | -n, --dry-run | false | Preview changes without executing | | -q, --quiet | false | Suppress non-essential output | | -c, --clipboard | false | Copy output to clipboard | | --backup-dir <path> | — | Directory for backup copies before deletion | | --experimental-sqlite | false | Use SQLite database instead of JSONL files (experimental) | | --db <path> | ~/.local/share/opencode/opencode.db | Path to SQLite database (implies --experimental-sqlite) | | --sqlite-strict | false | Fail on any SQLite warning or malformed data | | --force-write | false | Wait for SQLite write locks to clear before failing |

Experimental SQLite Support

OpenCode can store metadata in SQLite databases. The CLI supports this mode with --experimental-sqlite or by pointing directly at a database with --db <path>.

Key behaviors:

  • Read operations open SQLite in readonly mode by default.
  • Write operations may fail if OpenCode has the database locked. Use --force-write to wait for the lock to clear.
  • When malformed rows are encountered, the CLI logs a warning and returns partial results. Use --sqlite-strict to fail fast.

When to use SQLite vs JSONL:

  • Use SQLite when your OpenCode installation no longer writes JSONL files or when you want faster list/search operations on large stores.
  • Use JSONL when you need maximal compatibility with older OpenCode versions or when you want to avoid SQLite locking.

Known limitations and differences:

  • Schema changes in OpenCode may break compatibility. The CLI validates required tables/columns and warns if the schema is incomplete.
  • SQLite records use virtual file paths (e.g., sqlite:project:proj_123) instead of JSON file paths.
  • Results may differ slightly from JSONL when extra SQLite-only rows exist.

Examples:

# List projects using the default SQLite database
opencode-manager projects list --experimental-sqlite

# List sessions using an explicit SQLite database path
opencode-manager sessions list --db ~/.local/share/opencode/opencode.db

# Fail fast on malformed SQLite data
opencode-manager projects list --db ~/.local/share/opencode/opencode.db --sqlite-strict

# Wait for locks before destructive operations
opencode-manager projects delete --id proj_missing --db ~/.local/share/opencode/opencode.db --yes --force-write

Commands Overview

opencode-manager
├── projects
│   ├── list      List projects (--missing-only, --search)
│   └── delete    Delete project metadata (--id, --yes, --dry-run, --backup-dir)
├── sessions
│   ├── list      List sessions (--project, --search)
│   ├── delete    Delete session metadata (--session, --yes, --dry-run, --backup-dir)
│   ├── rename    Rename a session (--session, --title)
│   ├── move      Move session to another project (--session, --to)
│   └── copy      Copy session to another project (--session, --to)
├── chat
│   ├── list      List messages in a session (--session, --include-parts)
│   ├── show      Show a specific message (--session, --message or --index, --clipboard)
│   └── search    Search chat content across sessions (--query, --project)
├── tokens
│   ├── session   Show token usage for a session (--session)
│   ├── project   Show token usage for a project (--project)
│   └── global    Show global token usage
└── tui           Launch the Terminal UI

TUI Subcommand

The tui subcommand explicitly launches the Terminal UI. This is equivalent to running opencode-manager with no subcommand:

# These are equivalent:
opencode-manager
opencode-manager tui
opencode-manager tui --root ~/.local/share/opencode

Use the explicit tui subcommand when you want to be clear about intent in scripts or when combining with other options. Note that tui --help shows the TUI help screen (key bindings), not Commander CLI help.

Help System

The manager uses a dual help system depending on context:

| Command | Help Type | Content | |---------|-----------|---------| | opencode-manager --help | TUI help | Key bindings and TUI usage | | opencode-manager -h | TUI help | Same as --help | | opencode-manager tui --help | TUI help | Key bindings (routes to TUI help) | | opencode-manager projects --help | CLI help | Commander subcommand help | | opencode-manager sessions --help | CLI help | Commander subcommand help | | opencode-manager chat --help | CLI help | Commander subcommand help | | opencode-manager tokens --help | CLI help | Commander subcommand help |

Why? The root command defaults to launching the TUI, so --help shows TUI-relevant information (key bindings). CLI subcommands use standard Commander.js help showing options and usage.

To see all CLI subcommands, use any subcommand with --help:

# Shows TUI key bindings
opencode-manager --help

# Shows CLI subcommand help with options
opencode-manager projects --help
opencode-manager projects list --help

Output Format Examples

The CLI supports three output formats via --format:

Table (default) — Human-readable columnar output:

$ bunx opencode-manager projects list --limit 3

   #  State  Path                                                Project ID                Created
----  -----  --------------------------------------------------  ------------------------  ----------------
   1    ✓    /home/user/repos/my-app                             a1b2c3d4e5f6g7h8i9j0k1l2  2026-01-04 09:20
   2    ✓    /home/user/repos/api-server                         b2c3d4e5f6g7h8i9j0k1l2m3  2026-01-03 14:15
   3    ✗    /home/user/repos/deleted-project                    c3d4e5f6g7h8i9j0k1l2m3n4  2025-12-28 10:30

JSON — Structured output with metadata envelope:

$ bunx opencode-manager sessions list --project prj_abc123 --format json --limit 2

{
  "ok": true,
  "data": [
    {
      "index": 1,
      "sessionId": "sess_xyz789",
      "projectId": "prj_abc123",
      "directory": "/home/user/repos/my-app",
      "title": "Refactor auth module",
      "version": "1.1.4",
      "updatedAt": "2026-01-05T14:32:00.000Z",
      "createdAt": "2026-01-03T09:15:00.000Z"
    },
    {
      "index": 2,
      "sessionId": "sess_uvw456",
      "projectId": "prj_abc123",
      "directory": "/home/user/repos/my-app",
      "title": "Add unit tests",
      "version": "1.1.4",
      "updatedAt": "2026-01-04T16:45:00.000Z",
      "createdAt": "2026-01-02T11:20:00.000Z"
    }
  ],
  "meta": {
    "count": 2,
    "limit": 2
  }
}

JSON output auto-detects your terminal: pretty-printed with indentation when output goes to a TTY, compact single-line when piped to another command.

The meta object contains:

  • count — Number of items in the data array
  • limit — The limit that was applied (if --limit was specified)

NDJSON — Newline-delimited JSON for streaming/piping:

$ bunx opencode-manager sessions list --format ndjson --limit 2

{"index":1,"sessionId":"ses_abc123","projectId":"prj_xyz789","title":"Feature implementation","createdAt":"2026-01-06T10:30:00.000Z"}
{"index":2,"sessionId":"ses_def456","projectId":"prj_xyz789","title":"Bug fix session","createdAt":"2026-01-06T11:15:00.000Z"}

Each line is a complete JSON object, ideal for piping to jq or line-by-line processing. For single-record commands like tokens global, NDJSON outputs one line with the same structure as the JSON data field.

Piping examples:

# Count sessions per project
bunx opencode-manager sessions list --format ndjson | jq -s 'group_by(.projectId) | map({project: .[0].projectId, count: length})'

# Get all session IDs as plain text
bunx opencode-manager sessions list --format json | jq -r '.data[].sessionId'

# Export chat history to file
bunx opencode-manager chat list --session sess_xyz789 --include-parts --format json > chat-export.json

# Dry-run delete to preview affected files
bunx opencode-manager projects delete --id prj_old --dry-run --format json

Token Output Format

Token commands (tokens session, tokens project, tokens global) return structured summaries of token usage.

Session tokens — Single session summary with kind discriminator:

$ bunx opencode-manager tokens session --session sess_xyz789 --format json

# When token data is available (kind: "known"):
{
  "ok": true,
  "data": {
    "kind": "known",
    "tokens": {
      "input": 12500,
      "output": 8750,
      "reasoning": 2100,
      "cacheRead": 4200,
      "cacheWrite": 950,
      "total": 28500
    }
  }
}

# When token data is unavailable (kind: "unknown"):
{
  "ok": true,
  "data": {
    "kind": "unknown",
    "reason": "no_messages"
  }
}

The reason field indicates why tokens are unavailable:

  • "missing" — Session metadata file not found
  • "parse_error" — Token data couldn't be parsed
  • "no_messages" — Session has no messages with token data

Project/Global tokens — Aggregate summary across multiple sessions:

$ bunx opencode-manager tokens project --project prj_abc123 --format json

{
  "ok": true,
  "data": {
    "total": {
      "kind": "known",
      "tokens": { "input": 125000, "output": 98000, "reasoning": 32000, "cacheRead": 15000, "cacheWrite": 6500, "total": 276500 }
    },
    "knownOnly": { "input": 125000, "output": 98000, "reasoning": 32000, "cacheRead": 15000, "cacheWrite": 6500, "total": 276500 },
    "unknownSessions": 2
  }
}

Aggregate summary fields:

  • total — Combined TokenSummary (same structure as session tokens)
  • knownOnly — Token breakdown from sessions with available data only (omitted if all unknown)
  • unknownSessions — Count of sessions where token data was unavailable

Note: The tokens commands require exact IDs (no prefix matching). Use full session/project IDs as shown in sessions list or projects list output.

Exit Codes

| Code | Meaning | |------|---------| | 0 | Success | | 1 | General error | | 2 | Usage error (missing required options, invalid arguments) | | 3 | Resource not found (invalid project/session/message ID) | | 4 | File operation error (backup or delete failure) |

ID Resolution

Most commands accept ID prefixes for convenience. The CLI will match the prefix to a unique ID:

# Full ID
opencode-manager sessions delete --session sess_01JGNPE16DT1JX1YA8KTPMDRW3

# Prefix match (if unique)
opencode-manager sessions delete --session sess_01JGN

# Ambiguous prefix (fails with error listing matches)
opencode-manager sessions delete --session sess_01
# Error: Multiple sessions match prefix 'sess_01': sess_01JGN..., sess_01ABC...

Commands supporting prefix matching:

  • projects delete --id
  • sessions delete --session, sessions rename --session, sessions move --session, sessions copy --session
  • sessions move --to, sessions copy --to (project ID)
  • chat list --session, chat show --session
  • chat show --message (also supports 1-based --index)

Commands requiring exact IDs:

  • tokens session --session — requires full session ID
  • tokens project --project — requires full project ID

Clipboard Support

The --clipboard flag (or Y key in the TUI) copies content to the system clipboard. Platform support:

| Platform | Tool Required | Notes | |----------|---------------|-------| | macOS | None | Uses built-in pbcopy | | Linux | xclip | Install via apt install xclip or equivalent | | Windows | — | Not currently supported |

On Linux, if xclip is not installed, clipboard operations will fail silently in the TUI or show an error message in the CLI.

Delete Semantics

Delete commands (projects delete, sessions delete) remove metadata files only:

| Command | Deletes | Preserves | |---------|---------|-----------| | projects delete | Project metadata (storage/project/<id>.json) | Sessions, messages, parts | | sessions delete | Session metadata (storage/sessions/<projectId>.json entry) | Message and part files |

Safety features:

  • Confirmation required — Destructive operations require --yes flag or interactive confirmation:

    # Will prompt for confirmation (interactive)
    opencode-manager projects delete --id prj_abc123
      
    # Skip confirmation (scripts)
    opencode-manager projects delete --id prj_abc123 --yes
  • Dry-run preview — Use --dry-run to see what would be deleted without making changes:

    opencode-manager sessions delete --session sess_xyz789 --dry-run
    # Output shows files that would be affected
  • Backup before delete — Use --backup-dir to copy files before deletion:

    opencode-manager projects delete --id prj_abc123 --backup-dir ./backups --yes
    # Creates backup, then deletes original

Note: Session deletion leaves associated chat message files intact. To fully remove a session's data, you would need to manually delete the message files from storage/message/<sessionId>/.

Development Workflow

  1. Install dependencies with bun install.
  2. Run the TUI via bun run tui (pass storage flags after --).
  3. Use bun run dev for watch mode.
  4. Type-check with bun run typecheck (tsc --noEmit).

Project Structure

src/
  bin/opencode-manager.ts       # Bun-native CLI shim exposed as the bin entry
  cli/
    index.ts                    # Commander program with global options
    commands/                   # Subcommand implementations (projects, sessions, chat, tokens)
    resolvers.ts                # ID prefix resolution helpers
  lib/
    opencode-data.ts            # JSONL file-based data access
    opencode-data-sqlite.ts     # SQLite backend (experimental)
    opencode-data-provider.ts   # Unified DataProvider abstraction
  tui/
    app.tsx                     # Main TUI implementation (panels, search, help)
    index.tsx                   # TUI entrypoint with launchTUI(), parseArgs(), bootstrap()
tests/
  fixtures/                     # Test data (JSONL and SQLite fixtures)
  lib/                          # Unit tests for data modules
  cli/                          # CLI integration tests
manage_opencode_projects.py     # Legacy Python launcher for backwards compatibility
PROJECT-SUMMARY.md              # Extended design notes & roadmap

Packaging & Publish

  1. bun install
  2. bun run typecheck
  3. Update version in package.json
  4. npm publish (package exposes the opencode-manager bin with public access)

Troubleshooting

  • tmux failures: Some sandboxed environments block tmux sockets under /tmp. Run bun run tui directly if tmux refuses to start.
  • Rendering glitches: OpenTUI expects all textual content inside <text> nodes. When adding UI components, follow the existing helpers (e.g., KeyChip, Bullet).
  • Search won’t clear: Press Esc while the search bar is focused, or hit X while in normal navigation.

Contributing

Issues and pull requests are welcome. Please include reproduction steps for metadata edge cases and run bun run typecheck before submitting patches.

License

MIT © OpenCode contributors. See LICENSE.