# Changelog

## 2.1.0

### Minor Changes

- 7f901ff: Reduce model-catalog visibility latency so external integrators list OpenCode models immediately after startup:

  - The cache-only refresh pass now publishes the persisted catalog instead of only returning it, so the model snapshot converges without waiting for network discovery.
  - Go (`opencode-go-console`) discovery publishes live `/models` rows before models.dev enrichment: the first publication needs no network beyond the catalog fetch, and enrichment merges in a second pass when the ~5MB metadata payload lands (`fetchPublicModelsRows` + `buildProviderSources` + `getModelsDevSnapshot`).
  - When `/models` is unreachable and nothing is persisted yet, a bundled fallback catalog of the public Go `lite` ids keeps the provider visible offline; a persisted catalog or live discovery always supersedes it.
  - Both providers share one consolidated `refreshModels` publication path with tests for cache-only, network, and network-failure branches.

## 2.0.2

### Patch Changes

- 899a666: Use shared OpenCode URL constants and canonical inference discovery endpoints, preserving legacy gateway bases in cached models.

## 2.0.1

### Patch Changes

- 3b7795e: Resolve model protocols and canonical OpenCode inference URLs, including Gemini on Go and Qwen3.8 Max. Respect PI_CODING_AGENT_DIR for isolated session storage.

## 2.0.0

### Major Changes

- be8ae77: **Org-scoped Console device sign-in** (parity with opencode-copilot-chat #66 and the tanstack adapter):

  - The device authorization request opts in to organization scoping (`supports_org_scope: true`). When the Console grants a scoped session, the organization is the one chosen during browser approval (`org_id` at token exchange, persisted as `OPENCODE_CONSOLE_SCOPED_ORG_ID` and honored across refreshes — a refresh that changes the scope is a hard error).
  - Un-scoped single-org accounts self-select; multi-org accounts pick explicitly after sign-in (no silent first-org auto-select).
  - `/opencode-console switch-org` is rejected for server-scoped sessions ("sign in again to switch"); status output marks scoped sessions.

  **Fixed streaming for non-OpenAI-routed models:** catalog models now carry the extension-level `api` with the real gateway route in `wireApi`, so every model goes through this extension's stream wrapper. Previously anthropic/google-routed models bypassed it and failed with 404 (doubled `/v1` on the wire: `…/inference/anthropic/v1/v1/messages`).

- be8ae77: **BREAKING: API-key (service key) auth removed — device-code (OAuth) sign-in is now the only auth method.**

  Both providers (`opencode-console`, `opencode-go-console`) register OAuth-only auth, so pi's `/login` offers just the "…(OAuth device code)" path — the native "Enter API key" prompt is gone, and stored `{ "type": "api_key" }` auth.json entries no longer resolve ("Provider is not configured").

  - Removed the `apiKey: "$OPENCODE_API_KEY"` registration, service-key credential resolution, the `serviceKey` stream flag and its terminal-401 behavior, the service-key `/models` catalog paths, and the service-key command branches (status/masking, switch-org rejection, key-based refresh).
  - Console model discovery is always the org-scoped `/api/config` catalog; Go keeps the public `/models` catalog, now called with the session's access token.
  - Auth-facing copy now says "(OAuth)" / "device code" so the method reads unambiguously against pi's native API-key option (e.g. provider names "OpenCode Console (OAuth device code)", status "Auth: device-code (OAuth) session").
  - **Migrating:** delete any `api_key` entries for these provider ids from `~/.pi/agent/auth.json` (they are inert) and run `/login opencode-console` (or `/login opencode-go-console`).

## Unreleased — 2.0.0 (BREAKING)

### Major Changes

- **BREAKING: API-key (service key) auth removed — device-code (OAuth) sign-in is now the only auth method.** Both providers register OAuth-only auth, so pi's `/login` offers just the "…(OAuth device code)" path (no native "Enter API key" prompt), and stored `{ "type": "api_key" }` auth.json entries no longer resolve.
  - Removed the `apiKey: "$OPENCODE_API_KEY"` registration, service-key credential resolution, the `serviceKey` stream flag and its terminal-401 behavior, the service-key `/models` catalog paths, and the service-key command branches.
  - Console model discovery is always the org-scoped `/api/config` catalog; Go keeps the public `/models` catalog, now called with the session's access token.
  - Auth-facing copy now says "(OAuth)" / "device code" — provider names "OpenCode Console (OAuth device code)" / "OpenCode Go (OAuth device code)", status line "Auth: device-code (OAuth) session" — so the method reads unambiguously against pi's native API-key option.
  - **Migrating:** delete any `api_key` entries for `opencode-console` / `opencode-go-console` from `~/.pi/agent/auth.json` (they are inert) and run `/login opencode-console` (or `/login opencode-go-console`).
- **Org-scoped device sign-in.** The device authorization request now opts in to organization scoping (`supports_org_scope`), matching the sister projects: the workspace is chosen during browser approval when the Console grants a scoped session (`org_id` at token exchange, persisted and honored across refreshes; scope changes are rejected). Un-scoped single-org accounts self-select and multi-org accounts pick explicitly after sign-in — no silent first-org pin. `switch-org` is rejected for server-scoped sessions ("sign in again to switch").
- **Fixed streaming for non-OpenAI-routed models.** Catalog models now carry the extension-level `api` (so pi's provider composer routes every model through this extension's stream wrapper) with the real gateway route in `wireApi`; previously, anthropic/google-routed models bypassed the wrapper and hit the gateway with a doubled `/v1` (`…/inference/anthropic/v1/v1/messages`) and failed with 404.

## 1.0.5

### Patch Changes

- ae9f304: Retry-layer parity with the sister bridge, verified by a full source diff: transient-retry 500 responses carrying a bare "Internal server error." body (pi-ai formats them with a leading status, so the match is allowed there too); patch 400 context-overflow responses by shrinking the completion budget and retrying (`maximum context length is X … you requested Y … Z in the completion` — pi's token estimates are heuristic and can undercount long transcripts, and the reduction respects whichever token field the API variant sends); and a fresh `x-opencode-request` tracing id per request attempt instead of one reused from the session load.

## 1.0.4

### Patch Changes

- 5303bad: Serve the persisted model catalog for pi's cache-only refresh (startup, `-p` mode, and credential changes) instead of returning an empty list, which previously cleared the provider's models and left pi falling back to another configured provider. The cached catalog is also kept when a network refresh fails.

## 1.0.3

### Patch Changes

- 0bdf59d: Refresh model facts against the current gateway catalog: route `qwen3.8-max` to OpenAI-completions on both gateways (the endpoint table gives this one Qwen tier a different API from the Messages-mapped family — pi's official config and independent routers agree), and filter `jev*` ids from every catalog source. Jev models run the System One structured-decision protocol (models.dev lists them with output limit 0, structured-only, no tool call) and cannot serve chat text; the Console supplemental table, which only held jev mirrors, collapses to empty — remaining Go supplemental mirrors are unaffected.

## 1.0.2

### Patch Changes

- 5cf8057: Fall back to a deterministic per-conversation session id when the caller supplies no `options.sessionId`: hash the wire model id plus the first two transcript messages (FNV-1a, prefixed `pi-`) and send it as the gateway's required `x-opencode-session` routing header, mirroring the sister bridge's proven-in-marketplace approach. Explicit caller session ids still win, and pre-existing header overrides are still respected, but Go-surface chats no longer depend on runtime session plumbing for their routing key.

## 1.0.1

### Patch Changes

- f5f2c15: Send the `x-opencode-session` header the Go surface requires, and use the raw upstream model id instead of the duplicate-disambiguated pi id, so console-catalog models such as `opencode-go/deepseek-v4.1-flash` no longer fail with `MissingSessionID` or `Model is unavailable`.

## 1.0.0

### Major Changes

- 321d00c: Align auth with OpenCode's current two-auth-system model (Console + Go, with Zen merged into Console):

  - Add service-key auth (workspace `sk-` API keys) for both providers via pi's standard `auth.json` entries — store `{ "opencode-console": { "type": "api_key", "key": "sk-…" } }` or the same under the new `opencode-go-console` id. A stored credential owns the provider; pi's `/login` also gains an "Enter API key" prompt, and the `$OPENCODE_API_KEY` env template covers the nothing-stored fallback (matching upstream's own env convention).
  - Add a Go-mode provider `opencode-go-console` ("OpenCode Go") mirroring the sister bridge: device-code sign-in reuses the shared Console device flow, model discovery always loads the public Go gateway catalog (`https://opencode.ai/zen/go/v1/models`, the auth-ignored `lite` list), and requests target the Go gateway with `Authorization: Bearer` (service key or Console access token) plus the org id headers for session credentials. `opencode-go` stays free of collisions with pi's built-in provider of the same name.
  - Console keeps its org-scoped `/api/config` catalog for device sessions and switches to the shared public `/models` catalog (`https://opencode.ai/zen/v1`) when a service key is stored; public rows are enriched from models.dev (`opencode` / `opencode-go` provider entries), dropping disabled/deprecated ids.
  - The single canonical refresh path rotates the shared Console session once (freshest entry first, with a sibling-entry fallback when a lineage's refresh token has gone dead) and mirrors rotated token fields into the sibling provider's oauth entry, so both stay valid under refresh-token rotation while each entry keeps its own org choice. Go sign-out preserves the Console session; a 401 on a service key is terminal (keys don't rotate).
  - `/opencode-console` and `/opencode-go-console` manage both credential types (`status`, `refresh`, `logout`, Console `switch-org`); also fixed the `switch-org` subcommand alias that previously fell through to `status`, and the first streaming request now loads the stored credential before sending (previously it relied solely on a 401-triggered refresh).

### Patch Changes

- 321d00c: Port the sister bridge's catalog fixes and metadata parity ahead of the v1.0.0 bump:

  - Route model families the way the gateways actually behave even when models.dev omits a package name: Grok and Muse Spark ids route to Responses, Qwen ids to Messages, Go MiniMax ids to Messages, and Console Gemini ids to Google.
  - Filter internal `test*` smoke-test ids that leak into authenticated discovery instead of listing them as unenriched entries.
  - Enrich discovery-only ids that models.dev has not cataloged yet with mirrored sibling metadata (Console: `jev-1.13`, `jev-1.13-free`; Go: `deepseek-flash`, `minimax-m2.5`, `kimi-k2.5`, `glm-5.1`, `glm-5`, `qwen3.5-plus`, `mimo-v2-pro`, `mimo-v2-omni`, `omen-alpha`, `hy3-preview`); canonical upstream entries supersede the mirrors automatically once they land.
  - Hide the legacy alias id (`deepseek-flash` → `deepseek-v4.1-flash`) when both are served in one discovery response; alias-only discovery keeps its mirrored metadata.
  - Map `reasoning_options` effort values onto pi's thinking levels (unsupported levels are explicitly `null` so pi's clamping picks a supported effort instead of sending one the gateway rejects); toggle/budget-only models are unmapped.
  - Cache the models.dev snapshot in-process with a 6h TTL and a 15s timeout instead of refetching the full catalog on every model refresh, keeping provider-level `npm` routing inheritance.

## 0.1.0

### Minor Changes

- 3175e6d: Match sibling-bridge streaming resilience: retry transient network/server failures with backoff, force-refresh the session once on 401 mid-stream, and drop rejected request options (`temperature`, reasoning/thinking) on retryable 400s. Also persist the org list across restarts so `/opencode-console switch-org` works without re-signing in.

### Patch Changes

- 20afea4: Add the `pullfrog.yml` workflow to mirror the sibling `pi-provider-poolside` setup.
- f06f76b: Open Console device sign-in at `https://opencode.ai/console/device` instead of doubling the `/console` path.

## 0.0.1

- Initial release: Pi provider for OpenCode Console via OAuth 2.0 device authorization grant.
- Discover account-specific models from the org-scoped `/api/config` endpoint.
- Route chat requests to the right upstream wire API per-model (`anthropic-messages`, `openai-completions`, `openai-responses`, `google-generative-ai`), delegating streaming and parsing to pi-ai's built-in implementations.
- Auto-refresh the OAuth access token within 5 minutes of expiry, single-flight.
- Add `/opencode-console` for `status`, `refresh`, `switch-org`, and `logout`.
- Tests, package metadata, Changesets, CI, and npm trusted publishing.
