Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
a5597c2
feat(tui): Add V2 quota sidebar
Aug 2, 2026
a01a069
feat(auth): fall back to OpenCode credential database
Aug 2, 2026
65874b9
feat(tui): Add local quota slash commands
Aug 2, 2026
6ce71cc
feat(tui): Add collapsible quota sidebar
Aug 2, 2026
64f6c97
fix(tui): Type collapsible quota count
Aug 2, 2026
b6c0ae8
feat(auth)!: Remove auth.json credential fallback
Aug 2, 2026
870e22b
refactor(auth): update credential DB path resolution
Aug 6, 2026
5009ac0
chore(deps): bump @opentui/core and @opentui/solid to ^0.5.3
Aug 18, 2026
f02f6a8
fix(tui): Restore V2 packaging and event triggers
Aug 21, 2026
c57bef8
fix(auth): report OpenCode credential database sources
Aug 21, 2026
a76299f
fix(tooling): lint nested staged files
Aug 21, 2026
3ad220f
chore: Align fork with upstream main
Aug 23, 2026
54d4ce3
feat(quota): Show all OpenCode connections
Aug 26, 2026
d5c1955
fix(copilot): Show reported subscription plan
Aug 27, 2026
8483432
fix(tui): Restore local plugin discovery
Sep 5, 2026
0bbac1c
chore: Align fork with upstream main
Sep 6, 2026
02b576e
fix(quota): collapse credential alias rows before Go multi-connection…
ransagy Sep 8, 2026
173e851
fix(quota): collapse credential alias rows before Go multi-connection…
dmmop Sep 9, 2026
75fab71
chore: Align fork with upstream main
Sep 9, 2026
75d9b5d
fix(quota): Correct sidebar rendering and storage reads
Sep 9, 2026
f29a485
fix(tokens): read sessions and messages from the OpenCode 2 V2 store
ransagy Sep 17, 2026
776406f
fix(quota): move Zen and Go auth to the OpenCode Console platform
ransagy Sep 23, 2026
76e7fa8
fix(quota): read OpenCode Go windows from the Console API
ransagy Sep 23, 2026
8bf62c9
chore: align fork with upstream main
Sep 23, 2026
32b3a47
build: target OpenCode V2 plugin package
Sep 23, 2026
77ee71e
Merge branch 'pr-2-head'
Sep 23, 2026
e738f29
fix(kimi): support regional code plans
Sep 24, 2026
dd2afef
refactor(plugin): migrate entrypoints to V2
Sep 24, 2026
1c86c66
fix(quota): drop the auth.json fallback from the V2 branch
ransagy Sep 24, 2026
0164941
Merge pull request #3 from ransagy/fix/console-migration-quota-sources
dmmop Sep 24, 2026
b3706b1
chore(release): sync package version to 4.10.2
Sep 24, 2026
954a952
merge: record upstream 4.10.2 ancestry
Sep 24, 2026
113f6df
merge: bring origin/main (4.10.3) into the OpenCode 2 branch
slkiser Sep 25, 2026
521dabf
refactor!: delete the OpenCode 1 TUI and its tests
slkiser Sep 25, 2026
e0c6c3a
refactor(auth)!: read every OpenCode credential from the database
slkiser Sep 25, 2026
96ee44a
build!: one SQLite opener, no better-sqlite3, Node 22.13+
slkiser Sep 25, 2026
dd9e5dd
refactor!: remove modules left unused by the OpenCode 2 migration
slkiser Sep 25, 2026
4607d56
fix(tui): resolve the session model and slash arguments on OpenCode 2
slkiser Sep 25, 2026
a64dd07
fix(tui): show idle toasts once per turn
slkiser Sep 25, 2026
99f1589
fix(storage): resolve the OpenCode database path once, honoring OPENC…
slkiser Sep 25, 2026
a161fb1
refactor(cli)!: stop writing tui.json
slkiser Sep 25, 2026
f3696ef
refactor(config)!: remove tuiCommandDisplay and suppressWhenNativePro…
slkiser Sep 25, 2026
f4a9774
refactor(status)!: drop tui.json diagnostics and fix OpenCode 2 setup…
slkiser Sep 25, 2026
65a6d36
feat(announcements): announce 5.0 on OpenCode 2
slkiser Sep 25, 2026
2ef0f22
docs!: describe OpenCode 2 support
slkiser Sep 25, 2026
ed1c948
fix(tui): restore Home announcements, compact format style and toast …
slkiser Sep 25, 2026
fd16b9a
fix(tui): restore reset notifications and quota export on OpenCode 2
slkiser Sep 25, 2026
aa7e75c
fix(tui): refresh the Home footer every minute like v4
slkiser Sep 25, 2026
001f844
fix(cli): use OpenCode 2 login commands
slkiser Sep 25, 2026
99b8e34
build!: target @opencode/plugin 2.0.16
slkiser Sep 25, 2026
049896d
chore(release): set version to 5.0.0
slkiser Sep 25, 2026
f72fd1c
fix(config): resolve OpenCode config, cache and state dirs like OpenC…
slkiser Sep 25, 2026
7bfd2b6
fix: address v5.0.0 review findings
slkiser Sep 25, 2026
f16ea2f
fix: address second v5.0.0 review
slkiser Sep 25, 2026
34d2573
fix(tui): make quota command dialogs scrollable
slkiser Sep 25, 2026
b62da7f
feat(web): add quota slash commands for OpenCode 2 Web and Desktop
slkiser Sep 25, 2026
28c6139
feat(web): show full quota reports on Web and Desktop without duplica…
slkiser Sep 25, 2026
c676a33
feat(tui): restore tuiCommandDisplay with the popup as default
slkiser Sep 25, 2026
5c2e47c
feat: ask users to upvote the OpenCode ecosystem listing
slkiser Sep 26, 2026
a766117
docs(readme): tighten the v5 README
slkiser Sep 26, 2026
644efd5
fix(google): find Gemini CLI and AGY login plugins installed by OpenC…
slkiser Sep 26, 2026
de210c8
feat(cursor): support the cursor-opencode-provider plugin on OpenCode 2
slkiser Sep 26, 2026
9fda93c
fix(cursor): update Cursor model prices
slkiser Sep 26, 2026
252f7c7
chore(upstream): track cursor-opencode-provider and OpenCode 2 compan…
slkiser Sep 26, 2026
a21114d
docs(readme): friendlier upvote tip
slkiser Sep 26, 2026
b4f4d10
fix(google): read projectId from OpenCode 2 provider settings
slkiser Sep 26, 2026
9e1f225
refactor(google): drop unused provider context from availability checks
slkiser Sep 26, 2026
6b1d3c2
fix(providers): keep provider names in multi-account labels
slkiser Sep 26, 2026
baa996d
docs!: remove the v4 migration guide
slkiser Sep 26, 2026
cf3b5ab
ci(release): publish prereleases to the npm next tag
slkiser Sep 26, 2026
82081f8
feat(cli): check the OpenCode version in init and update
slkiser Sep 26, 2026
7143e4d
test: never let test git commands touch the real repository
slkiser Sep 26, 2026
78003a3
feat(server): compute quota surfaces on the server behind a plugin RPC
slkiser Sep 27, 2026
c7b0b4b
fix(server): leave an unset reset notice out of the surface RPC output
slkiser Sep 27, 2026
f3498ca
refactor(tui): render quota from the server RPC instead of computing …
slkiser Sep 27, 2026
713845c
feat(cli): read quota through the running OpenCode service
slkiser Sep 27, 2026
23aa94f
refactor(auth): name integration ids on every login read and model fa…
slkiser Sep 27, 2026
94f402f
refactor(auth): read OpenCode logins through the plugin integration API
slkiser Sep 27, 2026
21d77c2
fix(go): resolve the OpenCode Console login through the integration API
slkiser Sep 27, 2026
c2d5fd6
feat(zen): read the OpenCode Console login and org budget
slkiser Sep 27, 2026
940a720
feat: find the Claude CLI in usual install folders and report the log…
slkiser Sep 27, 2026
25c2773
fix: address v5 review findings
slkiser Sep 27, 2026
941ad41
fix(go): keep a Console 403 falling back to the Go API key
slkiser Sep 27, 2026
81ea903
feat(cli): run show and status without OpenCode, reading logins from …
slkiser Sep 27, 2026
2e41b68
merge: bring main (4.10.5) into the OpenCode 2 branch
slkiser Sep 27, 2026
9af0433
docs(providers): say Alibaba bl is found on your shell's PATH from th…
slkiser Sep 27, 2026
aab2eb9
fix(toast): space reset countdowns like the sidebar
slkiser Sep 27, 2026
5c604b6
fix(zen): treat an empty Console org budget as no budget
slkiser Sep 27, 2026
13e6d69
fix(tui): wrap long lines in the sidebar quota panel
slkiser Sep 27, 2026
0ee82b6
fix(cli): hide Node's experimental SQLite warning
slkiser Sep 27, 2026
02f0476
docs(readme): add an OpenCode listing badge
slkiser Sep 27, 2026
93e29eb
fix(tui): open quota commands locally so they never flash or create a…
slkiser Sep 28, 2026
db9eee1
fix(tui): handle quota commands typed right after OpenCode starts
slkiser Sep 28, 2026
291e963
merge: bring main (4.10.6) into the OpenCode 2 branch
slkiser Sep 28, 2026
69f3645
chore(release): sync package version to 5.0.0-beta.1
github-actions[bot] Sep 28, 2026
b21b28a
fix(tui): show quota report text in the base color like OpenCode's ou…
slkiser Sep 28, 2026
43a3da4
feat(tui): draw quota reports from their structured document in the d…
slkiser Sep 28, 2026
e3d32ad
fix(tui): don't repeat the report title in quota popups
slkiser Sep 29, 2026
60dbe10
docs(readme): remove the 5.0 beta note
slkiser Sep 29, 2026
f8a8d19
fix(tui): use OpenCode theme colors for quota text
slkiser Sep 29, 2026
f5794cd
fix(tui): color popup table headers with OpenCode's primary accent
slkiser Sep 29, 2026
4a5ee34
fix(reports): use clearer section titles in token reports
slkiser Sep 29, 2026
01e07a9
feat(tui): stretch popup tables to the dialog width
slkiser Sep 29, 2026
37b1695
feat(tui): lay out the /quota popup in aligned columns
slkiser Sep 29, 2026
f833e8f
fix(quota): only mark the active login when a provider has several
slkiser Sep 29, 2026
62b66be
fix(tui): start /quota popup values in one left-aligned column
slkiser Sep 29, 2026
29081da
feat(tui): group the /quota popup into quota and spending tables
slkiser Sep 29, 2026
4b69044
test: expect uncached remote refetches on Windows in the cross-surfac…
slkiser Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
25 changes: 24 additions & 1 deletion .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,32 @@ jobs:
name: release-package
path: package-artifacts

- name: Choose npm dist-tag
id: dist-tag
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}
RELEASE_PRERELEASE: ${{ github.event.release.prerelease }}
run: |
VERSION="${RELEASE_TAG#v}"
if [ "$RELEASE_PRERELEASE" = "true" ] || [[ "$VERSION" == *-* ]]; then
DIST_TAG="next"
else
DIST_TAG="latest"
fi
echo "Publishing $VERSION to the npm '$DIST_TAG' dist-tag"
echo "dist-tag=$DIST_TAG" >> "$GITHUB_OUTPUT"

- name: Verify and publish exact release artifact
env:
DIST_TAG: ${{ steps.dist-tag.outputs.dist-tag }}
run: |
node scripts/verify-release-artifact.mjs package-artifacts
TARBALLS=(package-artifacts/*.tgz)
if [ "${#TARBALLS[@]}" -ne 1 ]; then
echo "Expected exactly one release tarball." >&2
exit 1
fi
npm publish "./${TARBALLS[0]}" --access public --provenance --ignore-scripts
npm publish "./${TARBALLS[0]}" --tag "$DIST_TAG" --access public --provenance --ignore-scripts

backfill-version:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -195,6 +212,12 @@ jobs:
BRANCH="$DEFAULT_BRANCH"
fi

git fetch origin "$BRANCH"
if ! git merge-base --is-ancestor "$GITHUB_SHA" "origin/$BRANCH"; then
echo "Release commit $GITHUB_SHA is not on branch '$BRANCH'; refusing to commit the version there." >&2
exit 1
fi

echo "Committing synced package version to branch '$BRANCH'"

git config user.name "github-actions[bot]"
Expand Down
39 changes: 8 additions & 31 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Thanks for contributing. This repo has strict local-only behavior and regression

## Development Setup

- The published package runtime supports Node.js `>=22.0.0` (matches `package.json` engines).
- The published package runtime supports Node.js `^22.13.0 || >=23.4.0` (matches `package.json` engines; `node:sqlite` needs no flag from those versions).
- Repository development uses pnpm v11, which requires Node.js `>=22` for the pnpm CLI.
- Enable the pinned package manager and install dependencies with:

Expand Down Expand Up @@ -52,36 +52,14 @@ It checks Biome linting and formatting, the pinned TypeScript toolchain, reposit

Use `pnpm run test:watch` for local iteration. Use `pnpm run build:check` when you need the build plus package dry-run check.

## Maintainer stabilization checks

These commands are for maintainers. They do not replace `pnpm verify`.

### Connected OpenCode

`pnpm run test:stabilization:tui` builds this worktree, copies `$OPENCODE_CONFIG_DIR` or the default OpenCode config directory into a `0700` temp directory, points only the OpenCode Quota plugin entries at this worktree's `dist/index.js` and `dist/tui.js`, enables sidebar/toast/compact with the prompt bar off, and launches real `opencode`. Companion plugin order and other copied settings stay as they were. The real config is never edited. OpenCode is launched only with the temp copy. That copy is deleted on exit, on prepare/copy/transform failure, and after forwarded `SIGINT`/`SIGTERM`/`SIGHUP`. After those signals, the runner waits a bounded grace period, then force-terminates the child (process group where safe) so cleanup cannot wait forever.

This uses real credentials and makes real quota/API calls.

After the first TUI session exits, the script offers a second session with the prompt bar on. Use `pnpm run test:stabilization:tui:prompt-bar` to skip the first stage. Use `pnpm run test:stabilization:web` to launch `opencode web` instead.

Web mode runs the fixed `opencode models` command directly, without a shell or model request, in the same isolated environment used for `opencode web`. Plain catalog lines count as usable models. Structured catalog entries must explicitly report a usable state; aliases and disabled, hidden, unavailable, or unknown entries are rejected. If the copied default is stale, the runner prefers the first usable same-provider model using locale-independent ordering and rewrites only the temp JSONC copy. Comments and plugin order stay intact. An empty, failed, or unusable catalog stops the Web launch and prints click/select steps. The real config is not edited. After choosing a model, run `/quota`, then `/quota_status`.

Web diagnostics live outside the temp config in a `0700` directory with a `0600` file. Runner output, server output, each log read, the number of log files, and the final file all have fixed limits and use a truncation marker. Header and cookie values, credentials, request and response bodies, serialized config, and marked private content are replaced with redaction markers. Log capture starts at the pre-launch offsets rather than copying full historical logs. Diagnostic creation, reads, and writes are best-effort; a failure cannot replace the Web child exit result, and the path prints only after a successful write. Classification requires markers in order. A generic send failure, or a busy marker without earlier successful output evidence, is `unknown-unclassified`. #272 requires hook entry, successful output evidence, and an affirmative session-busy marker. A model error is `invalid-model-before-hook` only when no hook-entry marker exists. Signals stop preflight or Web, escalate after the grace period when needed, clean the temp config, and retain the original signal exit code.

The prompt bar is a fixed 12-cell bar. The label is the provider plus window, for example `OpenAI 5h`. When you resize the terminal, check placement and clipping. The bar does not grow.

### Fake-data fixtures

`pnpm run test:stabilization:fixtures` runs a frozen Vitest set for config symlinks, config write targets, atomic JSON, OpenCode Go, Synthetic empty responses/surfaces, OpenRouter diagnostics/surfaces, Alibaba Token Plan process/provider, quota status, prompt selection, prompt-bar identity, TUI runtime, quota export, API-key query/config, and contribution guidance. It does not use real credentials, network provider calls, or the real `bl` executable. Before Vitest starts, the runner creates a `0700` temp HOME/XDG sandbox, strips known provider credential/session env vars and `OPENCODE_CONFIG`/`OPENCODE_CONFIG_DIR`, then deletes the sandbox on success, error, or signal.

## CI Checks (Automated)

PR and `main` pushes trigger `.github/workflows/ci.yml` (`CI` workflow):

- Job: `pnpm-quality` on Node `24.x`
- Steps: frozen install, `pnpm verify`, then one exact npm artifact pack and upload
- Job: `runtime-smoke` on Node `22.x` and `24.x`
- Runtime smoke installs that exact packed artifact as a consumer and verifies the default/server imports, TUI export payload, CLI help, and `engines.node >=22.0.0`
- Runtime smoke installs that exact packed artifact as a consumer and verifies the default/server imports, TUI export payload, CLI help, and `engines.node ^22.13.0 || >=23.4.0`

Release workflow `.github/workflows/publish-npm.yml` first checks the release tag, SHA, and package version, then runs `pnpm verify` on Node 24. After that, it packs one exact artifact, smoke-tests that artifact on Node 22 and 24, verifies it again before provenance publishing, and backfills the release version. Run `pnpm run release:check` on Node 24 when the release environment is available; it adds the release-version assertion after the canonical gate.

Expand All @@ -100,13 +78,12 @@ Recommended settings for `main`:

- Never invoke an LLM/model API to compute toast/report output. Everything must remain local and deterministic.
- Rich accounting currency quantities must preserve the provider's uppercase ISO code and render through the shared formatter (for example, `USD 12.50`), never a provider-formatted currency string, bare symbol, decorative glyph, conversion, or cross-currency sum.
- The server plugin is the sole owner of deterministic slash commands for TUI and Desktop/server. It registers each `cfg.command` once, injects exactly one ignored/no-reply output message with `session.prompt({ noReply: true, ignored: true })`, and must throw `handled()` so OpenCode does not continue into `prompt(...)`.
- The TUI plugin owns only Sidebar, Compact status, home-bottom, prompt-wrapper, refresh, and resource-lifecycle surfaces. It must not register keymap commands or render native slash-command dialogs.
- Slash commands (`/quota`, `/quota_status`, `/quota_announcements`, `/pricing_refresh`, `/tokens_*`) must route through `buildQuotaDialogCommandOutput()`; do not duplicate command-output logic in `src/plugin.ts`.
- The handled-sentinel path can surface popup/log noise until upstream adds a clean cancellation API; keep docs aligned with anomalyco/opencode#18554 and anomalyco/opencode#18559.
- Keep `handled()` / `isCommandHandledError(...)` tests aligned with the server/web/desktop handled-sentinel boundary.
- `injectRawOutput()` is shared by inline slash commands and the server `tool.quota_status` compatibility path.
- Keep `tests/plugin.command-handled-boundary.test.ts`, `tests/tui-smoke.test.ts`, and `tests/command-handled.test.ts` aligned with these invariants.
- OpenCode Quota supports only OpenCode 2. Do not add OpenCode 1 code paths, plugin APIs, or database tables.
- The server plugin (`src/plugin.ts`) registers the `quota_status` tool, the slash commands, and the `slkiser.opencode-quota` RPC, and computes the text of every surface. OpenCode 2 gives plugins no Web or Desktop UI hooks, so Web and Desktop get slash commands but no toasts or panels. Commands never call a model.
- The TUI plugin (`src/tui-v2.tsx`) only renders: toasts, the Sidebar panel, the compact line and prompt bar below the prompt, the Home footer line, and report popups. It gets every text through the RPC and imports no provider or credential module (`tests/tui-dist-import-graph.test.ts`, `tests/plugin.command-handled-boundary.test.ts`).
- Slash commands (`/quota`, `/quota_status`, `/quota_announcements`, `/pricing_refresh`, `/tokens_*`), the `quota_status` tool, and the RPC `command` method must route through `buildQuotaDialogCommandOutput()`; do not duplicate command-output logic in `src/plugin.ts` or `src/tui-v2.tsx`.
- Read OpenCode credentials only through `ctx.integration`, inside `src/lib/opencode-auth.ts`, never from `auth.json` or the `credential` table. The one exception: the terminal command (`src/lib/cli-show.ts`) binds the read-only reader in `src/lib/opencode-auth-sqlite.ts`, the only code that queries the `credential` table; `src/plugin.ts` and `src/tui-v2.tsx` must never reach it (`tests/tui-dist-import-graph.test.ts`). Every reader call still names its integration ids.
- Keep `tests/plugin.command-handled-boundary.test.ts` aligned with these invariants.

Additional boundary tests to keep healthy when touching plugin/provider logic:

Expand Down
Loading
Loading