opencode-anthropic-fix 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NOTICE ADDED
@@ -0,0 +1,53 @@
1
+ opencode-anthropic-fix
2
+ Copyright (C) 2025-2026 Marco Jardim and contributors.
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU General Public License as published by the Free Software
6
+ Foundation, either version 3 of the License, or (at your option) any later
7
+ version. The full text is in LICENSE.
8
+
9
+ This project is a fork of the original OpenCode Anthropic auth plugin by
10
+ AnomalyCo (https://github.com/anomalyco/opencode-anthropic-auth) and contains
11
+ modifications by the maintainers of this repository. GPL notices in this file,
12
+ in LICENSE, and in source headers must never be removed, including during a
13
+ dependency rollback.
14
+
15
+ Third-party dependencies
16
+ ========================
17
+
18
+ @tormentalabs/claude-code-wire-compat
19
+ Runtime-neutral Claude Code Messages wire compatibility primitives.
20
+ License: GPL-3.0-or-later
21
+ Copyright (C) claude-code-wire-compat contributors.
22
+ Upstream: https://github.com/marco-jardim/claude-code-wire-compat
23
+ Distributed with its own LICENSE and NOTICE inside the published artifact.
24
+
25
+ This package builds the outgoing Anthropic Messages request. Its npm `latest`
26
+ specifier is resolved to an exact version and integrity hash by package-lock.json;
27
+ the protocol profile is explicitly pinned in lib/mimicry/wire-compat.mjs.
28
+ Provenance and rollback instructions are in docs/shared-package-provenance.md.
29
+
30
+ @ai-sdk/anthropic (3.0.111)
31
+ @ai-sdk/provider
32
+ @ai-sdk/provider-utils
33
+ AI SDK Anthropic provider and supporting interfaces/utilities.
34
+ License: Apache-2.0
35
+ Upstream: https://github.com/vercel/ai
36
+ Copyright 2023 Vercel, Inc. (from the provider packages' notices).
37
+ The complete Apache-2.0 text is supplied in licenses/Apache-2.0.txt.
38
+ Transitive versions are recorded in package-lock.json. The provider-utils
39
+ package also contains an ISC-licensed zod3-to-json-schema implementation;
40
+ its vendored copyright notice and license are included in standalone builds.
41
+ The Anthropic provider is used by the OpenCode v2 compatibility adapter.
42
+
43
+ The npm source package publishes its runtime entrypoints, lib/**/*.mjs, user
44
+ documentation, licenses/, LICENSE and this NOTICE. Its dependencies retain their own
45
+ license files in node_modules; development-only dependencies are not included
46
+ by the package's files allowlist.
47
+
48
+ Standalone builds inline runtime dependencies. scripts/build.mjs collects
49
+ the dependency packages actually present in esbuild's input metadata and
50
+ includes their available LICENSE/NOTICE files and the complete Apache-2.0
51
+ text in THIRD_PARTY_NOTICES. That
52
+ document ships beside the dual-host bundle and is also embedded as comments
53
+ in each standalone JavaScript file so legacy single-file copies retain it.
package/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  Use your Claude Pro or Max subscription with [OpenCode](https://github.com/anomalyco/opencode). Supports multiple accounts with automatic rotation when you hit rate limits.
4
4
 
5
+ ## Supported Hosts
6
+
7
+ The plugin supports **both OpenCode v1 (1.x) and OpenCode v2 (2.x)** through separate host entries sharing the same OAuth, account rotation, and request runtime.
8
+
9
+ | Host | Supported entry and validated versions |
10
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | OpenCode v1 (1.x) | Legacy `index.mjs` factory and the recent-v1 `server()` entry. Host loading and registration tested on **1.2.27, 1.18.29, and 1.18.34**. |
12
+ | OpenCode v2 (2.x) | `setup()` server adapter and `./tui` entry. The compatibility target starts at **2.0.21**, with **2.0.21 and 2.0.22** tested. |
13
+
14
+ These are validated versions, not a claim that every intervening or newer host release has been tested. The v2 smoke tests use a local Anthropic simulator; real OAuth login, real Anthropic inference, and interactive TUI rendering still require manual validation. See the [v2 compatibility guide](docs/opencode-v2.md) for the exact scope and limitations.
15
+
5
16
  ## Background
6
17
 
7
18
  [AnomalyCo](https://github.com/anomalyco/opencode-anthropic-auth) originally published this as a built-in plugin shipped with OpenCode itself. The repo was archived following a legal request from Anthropic. Before it was archived, [rmk40](https://github.com/rmk40/opencode-anthropic-auth) — a frequent contributor unrelated to AnomalyCo — had developed multi-account support that never made it upstream.
@@ -32,6 +43,9 @@ If a document or comment claims this plugin branches on the provider, that claim
32
43
 
33
44
  **Prerequisites:** [OpenCode](https://github.com/anomalyco/opencode) installed, a Claude Pro or Max subscription, Node.js 18+.
34
45
 
46
+ The commands below install the **OpenCode v1** entry. For **OpenCode v2**, use the
47
+ [v2 package installation](#opencode-v2-package-installation) below instead.
48
+
35
49
  ```bash
36
50
  # 1. Clone and install
37
51
  git clone https://github.com/marco-jardim/opencode-anthropic-fix.git
@@ -88,7 +102,15 @@ The [original plugin](https://github.com/anomalyco/opencode-anthropic-auth) prov
88
102
 
89
103
  ### From npm (recommended)
90
104
 
91
- Add to your `opencode.json`:
105
+ For OpenCode v1, add to your `opencode.json`:
106
+
107
+ ```json
108
+ {
109
+ "plugin": ["opencode-anthropic-fix@latest"]
110
+ }
111
+ ```
112
+
113
+ For OpenCode v2 (tested on 2.0.21 and 2.0.22), use the `plugins` key:
92
114
 
93
115
  ```json
94
116
  {
@@ -98,7 +120,53 @@ Add to your `opencode.json`:
98
120
 
99
121
  OpenCode will install and load the plugin automatically on next start.
100
122
 
101
- ### Development (symlink)
123
+ The `./server` and `./tui` exports let modern hosts select their entrypoints;
124
+ older v1 loaders retain `index.mjs`. OpenCode v2 loads the package's `./tui` entry
125
+ alongside its server entry; do not install `tui.mjs` as a legacy standalone plugin.
126
+ The v2 `/anthropic` command calls the server through RPC and shows results in
127
+ a dialog and does not add administrative output or OAuth codes to model history.
128
+ See [the v2 guide](docs/opencode-v2.md) for the explicit package installer,
129
+ programmatic RPC interface, cancellation behavior and current validation limits.
130
+
131
+ The explicit package installer (`node scripts/install.mjs link --host=v2`,
132
+ `copy --host=v2`, or `uninstall --host=v2`) only replaces or removes CLI entries
133
+ it owns: links into its installed package or wrappers with its installer marker.
134
+ It refuses unrelated CLI files and symlinks before changing the package. Add
135
+ `--force` to deliberately replace/remove a foreign CLI entry, for example:
136
+
137
+ ```bash
138
+ node scripts/install.mjs copy --host=v2 --force
139
+ ```
140
+
141
+ `--force` never deletes CLI directories or unmanaged package directories and is
142
+ only supported with `--host=v2`.
143
+
144
+ ### OpenCode v2 Package Installation
145
+
146
+ From a checkout with dependencies installed, choose a development link or a standalone copy:
147
+
148
+ ```bash
149
+ # Development: link the dual-host package (directory junction on Windows)
150
+ node scripts/install.mjs link --host=v2
151
+
152
+ # Or: build and copy the standalone package, including server and TUI entries
153
+ npm run build
154
+ node scripts/install.mjs copy --host=v2
155
+ ```
156
+
157
+ Both modes install under `$XDG_CONFIG_HOME/opencode/node_modules/opencode-anthropic-fix`,
158
+ falling back to `~/.config/opencode/node_modules/opencode-anthropic-fix`, rather than
159
+ the legacy `plugin/` discovery directory. The copy needs no dependencies installed
160
+ at its destination. The installer prints the exact `plugins` configuration to add
161
+ to `opencode.json` and does not change your configuration. Remove old standalone
162
+ plugin entries it reports before enabling the package to avoid duplicate loading.
163
+ Restart OpenCode after installing or changing the plugin.
164
+
165
+ To uninstall the managed v2 package, run `node scripts/install.mjs uninstall --host=v2`
166
+ and remove its `plugins` configuration entry. See [the v2 guide](docs/opencode-v2.md)
167
+ for RPC commands, transport details, and validation limits.
168
+
169
+ ### OpenCode v1 Development (symlink)
102
170
 
103
171
  Best for active development. Edits to source files take effect immediately.
104
172
 
@@ -111,7 +179,7 @@ This creates:
111
179
  - **Plugin:** `~/.config/opencode/plugin/opencode-anthropic-auth-plugin.js` → `./index.mjs`
112
180
  - **CLI:** `~/.local/bin/opencode-anthropic-auth` → `./cli.mjs`
113
181
 
114
- ### Stable (copy)
182
+ ### OpenCode v1 Stable (copy)
115
183
 
116
184
  Bundles the plugin and CLI into self-contained single files (via esbuild) and copies them. No symlinks, no `node_modules` needed at the destination.
117
185
 
@@ -124,7 +192,7 @@ This creates:
124
192
  - **Plugin:** `~/.config/opencode/plugin/opencode-anthropic-auth-plugin.js` (standalone, ~50KB)
125
193
  - **CLI:** `~/.local/bin/opencode-anthropic-auth` (standalone, ~35KB)
126
194
 
127
- ### Uninstall
195
+ ### OpenCode v1 Uninstall
128
196
 
129
197
  ```bash
130
198
  npm run uninstall
@@ -0,0 +1,148 @@
1
+ # Decision: dual host adapters with one OAuth executor
2
+
3
+ ## Context and decision
4
+
5
+ OpenCode 2.0.21 uses a definition object, registration APIs, a separate TUI
6
+ plugin, and different provider/message schemas. The existing v1 factory cannot
7
+ be loaded unchanged by that host. Preserve `index.mjs` as the legacy factory;
8
+ expose `server.mjs` with v1 `server` and v2 `setup`, and a separate `tui.mjs`.
9
+
10
+ Move the existing implementation into `createAnthropicRuntime()` rather than
11
+ maintaining two OAuth pools or wire implementations. Mutable metrics, config,
12
+ retry state, refresh flights and telemetry belong to each runtime. Disposal
13
+ aborts requests, refresh waits and backoff, and flushes pending account writes.
14
+ Disk account format and the cross-process refresh lock remain shared.
15
+
16
+ ## Transport options
17
+
18
+ The native HTTP hooks do not expose a continuation that can own the existing
19
+ multi-account retry loop. Directly assigning a custom fetch to provider or model
20
+ settings was also rejected by the real 2.0.21 host: its overlay decoder requires
21
+ JSON values and fails on `settings.fetch`. A mocked hook test cannot detect this
22
+ constraint, which is why the binary smoke is part of validation.
23
+
24
+ Use the package spec `aisdk:@ai-sdk/anthropic@3.0.111` with a process-local HTTP
25
+ bridge. The versioned spec prevents the host from rewriting the unversioned
26
+ Anthropic SDK to its native provider, while remaining resolvable by the host's
27
+ built-in dynamic package loader. The
28
+ public `http.request` hook associates a request with its session and redirects
29
+ it to the bridge. A single-use random ticket identifies the original request;
30
+ the bridge invokes the existing executor and streams its response to the host.
31
+ No function is stored in provider/model settings. The SDK hook retains the
32
+ host's middleware fetch, and the executor remains the only retry owner for
33
+ managed OAuth requests. Other providers and explicitly selected foreign
34
+ connections retain their own settings.
35
+
36
+ The pin also makes Core's option/metadata key `anthropic@3.0.111`, whereas the
37
+ SDK reads and emits `anthropic`. A language-model boundary remaps incoming
38
+ provider options (including replay parts) and outgoing stream/non-stream metadata
39
+ (including reasoning signatures and finish metadata). An unversioned specifier
40
+ is not safe: `aisdk-native.ts:resolve` rewrites even the explicit `aisdk:` route
41
+ to the native provider. The host's dynamic SDK hook may install the pinned
42
+ package first; our later hook replaces that SDK with the plugin's pinned copy.
43
+
44
+ The bridge binds only to IPv4 loopback on an ephemeral port. It accepts only
45
+ issued request tickets, never accepts a caller-supplied destination, and strips
46
+ its private correlation data before the executor. Plugin unload closes it.
47
+ The public session-interruption event cancels pending requests because the
48
+ 2.0.21 AI SDK call does not itself receive the host's abort signal. Losing that
49
+ event subscription aborts active requests and rejects new requests.
50
+
51
+ This is immediate cancellation for primary execution events, not a guarantee
52
+ for auxiliary fiber interruption. 2.0.22 and inspected HEAD `f74512b` still omit
53
+ the interruption signal from `doStream`. Supplied SDK signals and loopback
54
+ disconnects propagate upstream. Otherwise `generate` and `title` tickets have a
55
+ 10-minute total deadline, including pre-header waits and streaming, to bound
56
+ orphaned requests. Slow primary/compaction streams are exempt. Upstream must pass
57
+ the Effect interruption signal to `doStream` as `abortSignal` for immediate
58
+ auxiliary cancellation; no plugin hook currently exposes that fiber lifetime.
59
+
60
+ Managed provider settings disable `timeout`, `headerTimeout` and `chunkTimeout`.
61
+ 2.0.22 already has HEAD's 300-second default header/chunk limits. These conflict
62
+ with an executor that bounds attempts but not total wall time (uncapped
63
+ Retry-After waits and repeated transient 429s). The auxiliary deadline remains
64
+ independent of those host defaults. 2.0.21 ignores the new header option and
65
+ uses `chunkTimeout: 0`, because its public schema rejects `false` for that field
66
+ (its fetch wrapper activates the timer only for positive numbers).
67
+
68
+ ## Credentials, commands and history
69
+
70
+ The plugin registers its own OAuth method ID. Host credential values are copies;
71
+ the pool on disk is authoritative for rotation, removal and refresh. A foreign
72
+ OAuth method or an explicit API-key/environment connection must not be replaced.
73
+ Only managed models receive zero costs across every tier and configured limits.
74
+
75
+ Administrative commands use a typed RPC definition and a local TUI slash layer.
76
+ They return bounded, sanitized dialog content; no prompt endpoint carries the
77
+ arguments or output. The server command name is reserved and returns guidance
78
+ for clients that have no administrative result channel.
79
+
80
+ V2 message policies operate on a temporary view and replace only pruned results.
81
+ Tool aliases are request-local and reversible. Summary compaction is selected
82
+ explicitly. Normal host history loading skips incompatible native checkpoints
83
+ and re-expands the original transcript; a new session is not required, and no
84
+ history is corrupted, although context can grow substantially. The defensive
85
+ adapter guard rejects opaque checkpoint parts only if explicitly passed to it.
86
+ The optional Haiku rolling-summary hook remains a v1
87
+ fork capability and emits a diagnostic when configured on v2.
88
+
89
+ ## Consequences and validation boundary
90
+
91
+ One extra pinned production dependency is required for a known parser/provider
92
+ contract. The standalone dual-package build bundles it; the host's dynamic
93
+ provider loader may also populate its own cache on first use. The loopback bridge adds
94
+ one local streaming hop; disposal, backpressure, request authentication,
95
+ interruption and non-replay after streamed bytes must be covered by tests.
96
+
97
+ Keep regression tests for the v1 exports and wire fixtures, deterministic v2
98
+ SDK/transport tests, isolated installer and bundle tests, and real host smoke
99
+ scripts. Smoke runs use temporary configuration roots and fake credentials.
100
+ They prove host integration; they do not prove an authenticated Anthropic session
101
+ or future host releases. See [support and usage](opencode-v2.md) for the recorded
102
+ validation matrix.
103
+
104
+ ## Host-contract review sources
105
+
106
+ Inspected `v2.0.21`, `v2.0.22` and upstream `f74512b` without changing the host:
107
+
108
+ - **Options and SDK loading:** `packages/core/src/provider.ts:30-34` strips
109
+ only `aisdk:`. In `v2.0.21`, `aisdk.ts:429-442` derives the option key,
110
+ `:362-367` assigns the same metadata key and `:690-700` nests request options.
111
+ `session/runner/publish-llm-event.ts:120,421-436` persists reasoning state only
112
+ under that key. `aisdk-native.ts:57,135-143` maps the unversioned Anthropic SDK
113
+ to the native provider, including explicit `aisdk:` specs. This behavior is
114
+ unchanged in the inspected 2.0.22/HEAD sources. `aisdk.ts:280-288,324-347` runs
115
+ SDK hooks in registration order and caches their final SDK; the dynamic hook
116
+ (`plugin/provider/dynamic.ts:10-15`) installs only when `evt.sdk` is empty.
117
+ Installation is inside that hook, not an independent prerequisite:
118
+ `plugin/provider/sdk-factory.ts:5-16` calls `npm.add(packageName)` and resolves
119
+ `installed.name` in its installed directory. With the built-in hook first it
120
+ can install before our replacement, so retaining the resolvable pin matters.
121
+ `plugin/internal.ts:213-226` puts provider plugins in the pre-list;
122
+ `plugin/supervisor.ts:138-155` places that list before external plugins.
123
+ - **Cancellation:** `session.ts@v2.0.21:405-411` invokes auxiliary generation
124
+ directly, not a primary execution. `aisdk.ts@v2.0.21:715-718`,
125
+ `@v2.0.22:733-736` and `@f74512b:729-732` call `language.doStream(options)`
126
+ without the `Effect.tryPromise` signal. Auxiliary generation also uses this
127
+ streaming route, not a separate `doGenerate` cancellation path.
128
+ - **Timeouts:** `provider.ts@v2.0.22:149-164` (HEAD `:151-166`) supplies the
129
+ 300,000 ms defaults; `aisdk.ts@v2.0.22:130-170` applies them around the
130
+ middleware fetch. `model-resolver.ts:373` merges provider settings after
131
+ removing model/variant transport settings. `packages/schema/src/provider.ts@v2.0.21:49-50`
132
+ permits `timeout: false` but only numeric `chunkTimeout`; `aisdk.ts:137-149`
133
+ treats zero as disabled. The executor's real budgets are in
134
+ `lib/host/runtime.mjs:2873,2912-2928,4278-4312,4393-4448`, not a total five-minute
135
+ deadline; `lib/backoff.mjs:11` caps account cooldowns, not whole requests.
136
+ - **History:** `session/history.ts@v2.0.21:23-26,99-107` filters incompatible
137
+ checkpoints and retains the original transcript for re-expansion.
138
+
139
+ The 2.0.21 → 2.0.22 diff contains no change to the consumed loader, OAuth
140
+ methods, SDK-hook, RPC or TUI-command interfaces. The plugin Promise/Effect
141
+ session APIs add `remove` and `compact`; the Core host adds parent-aware session
142
+ creation and metadata updates. Model capability overlays now merge instead of
143
+ replacing fields. None requires an adapter change here. The transport timeout
144
+ defaults and the expanded timeout schema are the relevant breaking behavior;
145
+ the new bounded host timeout retry policy does not supersede our managed retry
146
+ hook. Core also preserves HTTP options when rebuilding a session request and
147
+ adds content-filter explanations to published errors; neither changes our hook
148
+ shapes. Provider-specific Azure/DigitalOcean changes do not affect this route.
@@ -0,0 +1,198 @@
1
+ # OpenCode v2 adapter
2
+
3
+ ## Validation recorded on 2026-09-30
4
+
5
+ Local validation used Windows and Node 24.21.0, plus each official OpenCode
6
+ release's own runtime. Host binaries were downloaded from npm with SHA512
7
+ integrity verification. All smoke configurations and credentials were temporary.
8
+
9
+ | Host | Result | Scope |
10
+ | ------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | 1.2.27 | Passed | Legacy loader, OAuth registration, command registration, 23 OAuth models with zero costs. |
12
+ | 1.18.29 | Passed | Dual entry, OAuth registration, one administrative command, 16 OAuth models with zero costs. |
13
+ | 1.18.34 | Passed | Dual entry and public provider model hook, OAuth/command registration, 19 OAuth models with zero costs. |
14
+ | 2.0.21 | Passed | Server load, OAuth registration, 19 models, RPC without model invocation, chat, auxiliary generation, title, summary compaction, cancellation before response headers and plugin reload. |
15
+ | 2.0.22 | Passed | Same local Windows smoke scope as 2.0.21, including managed timeout settings and plugin reload. |
16
+
17
+ The original complete automated suite passed **2,286 tests across 113 files**, with two
18
+ platform skips on Windows. Build, ESLint, formatting and invariant checks passed;
19
+ the invariant check retains the existing warning about differing reverse-engineering
20
+ documentation baselines. Installer and standalone package tests run in temporary
21
+ directories. The v2 host smoke uses a local Anthropic simulator and blocks direct
22
+ Anthropic API access. The v1 host smoke checks loading and registration, not inference.
23
+
24
+ The v2 host-contract review reran both 2.0.21 and 2.0.22 Windows smokes with the
25
+ option/metadata adapter and host timeout fixes. Auxiliary orphan bounds are
26
+ tested with interrupted Effect fibers and loopback HTTP, not claimed as immediate
27
+ auxiliary cancellation by those host binaries.
28
+
29
+ Review verification: `npm test` and `npm run coverage` passed **2,057 tests in
30
+ 103 files**, with the same two platform skips. Coverage thresholds were unchanged;
31
+ the new language adapter had 100% statement/branch/function/line coverage.
32
+ ESLint, formatting, build and invariants passed (the existing baseline warning
33
+ remains). Negative controls temporarily removed the language wrapper, auxiliary
34
+ deadline and timeout settings and restored the inaccurate checkpoint wording:
35
+ six regression cases failed, then passed after restoring the fixes.
36
+
37
+ Run a pinned host again with `node scripts/run-host-smoke.mjs 2.0.21` or
38
+ `node scripts/run-host-smoke.mjs 2.0.22` (or one of the v1 versions above).
39
+ CI runs these five hosts on Linux and Windows; the
40
+ Linux jobs have not been run locally. Real OAuth login, real Anthropic inference
41
+ and interactive TUI rendering still require manual validation before release.
42
+ The TUI behavior is covered by deterministic tests, and its RPC runs in the real
43
+ v2 server smoke. See the [architecture decision](opencode-v2-architecture.md).
44
+
45
+ ## Installation
46
+
47
+ The npm package exposes separate `./server` and `./tui` entries for recent v1
48
+ and v2 hosts, and keeps the root `index.mjs` entry for legacy v1 loaders. Existing
49
+ `index.mjs`, `cli.mjs` and `lib/*` imports remain available. Use the v2 `plugins`
50
+ configuration key when loading the package in OpenCode 2.0.21.
51
+
52
+ For development or a standalone bundle, run:
53
+
54
+ ```sh
55
+ node scripts/install.mjs link --host=v2
56
+ # or
57
+ npm run build
58
+ node scripts/install.mjs copy --host=v2
59
+ ```
60
+
61
+ The explicit v2 mode installs the package in
62
+ `$XDG_CONFIG_HOME/opencode/node_modules/opencode-anthropic-fix`, falling back to
63
+ `~/.config/opencode/node_modules/opencode-anthropic-fix`. Development links use
64
+ a directory junction on Windows. The copy contains bundled server, TUI, RPC,
65
+ legacy plugin and CLI entries and requires no `npm install` at its destination.
66
+ The copy also contains a local SDK factory; initializing a managed model does
67
+ not resolve or download another AI SDK package into the host's cache.
68
+ The installer prints the exact configuration to add and leaves existing
69
+ configuration untouched. It reports old standalone plugin entries that could
70
+ cause duplicate loading; remove those entries before enabling the new package.
71
+
72
+ Use `node scripts/install.mjs uninstall --host=v2` to remove a managed package.
73
+ The installer refuses to replace or remove an unrecognized package directory or
74
+ one with additional files. Without `--host=v2`, installation keeps the legacy
75
+ standalone v1 behavior.
76
+
77
+ ## Transport and version boundary
78
+
79
+ The adapter targets the public OpenCode **2.0.21 and 2.0.22** contracts. It routes managed
80
+ Anthropic models through `aisdk:file://…/v2-sdk.mjs`;
81
+ the shipped factory and public SDK hook use the pinned `@ai-sdk/anthropic`
82
+ **3.0.111** provider. The local specifier prevents the native-provider rewrite
83
+ and avoids a redundant registry install by the host's built-in dynamic hook,
84
+ which runs **before** external plugin hooks. This is also true in the standalone
85
+ bundle, where `v2-sdk.mjs` is self-contained. Core now uses `anthropic` for both
86
+ options and persisted metadata, matching the SDK. The language adapter still
87
+ accepts the former `anthropic@3.0.111` input key for signed reasoning replay.
88
+ See [the cold-initialization investigation](opencode-v2-sdk-initialization.md)
89
+ for the host npm failure, mitigation, negative control and repeated smoke results.
90
+ The shared plugin executor keeps account rotation,
91
+ wire construction, backoff and the response compatibility shim on the same
92
+ path as v1. Explicitly selected API-key or unrelated OAuth connections retain
93
+ their own provider settings. A connection owned by this plugin is disabled
94
+ when its account pool has no enabled account; it cannot fall back to a stale
95
+ credential cached by the host.
96
+
97
+ OpenCode 2.0.21 accepts only JSON data in provider/model settings, so an injected
98
+ `settings.fetch` function is unavailable. On first use, the adapter opens an
99
+ HTTP bridge bound to `127.0.0.1` on an ephemeral port. The public HTTP request
100
+ hook redirects the host request to that bridge with a single-use random ticket.
101
+ The bridge retrieves the original destination from its own ticket map, invokes
102
+ the shared executor and streams the response back. It does not accept an
103
+ arbitrary target URL from incoming HTTP requests. The host's normal HTTP
104
+ middleware remains in place; no functions are stored in model settings.
105
+
106
+ Neither host forwards its fiber cancellation signal to the AI SDK call (also
107
+ verified in upstream revision `f74512b`).
108
+ The adapter therefore associates tickets with session IDs and listens
109
+ for the public `session.execution.interrupted` event. Interrupting a session or
110
+ unloading the plugin aborts its requests; a lost event stream aborts outstanding
111
+ requests and prevents new ones. A disconnected loopback request also cancels
112
+ its upstream operation. An SDK `abortSignal`, when supplied by a caller, reaches
113
+ the upstream through that disconnect path. **Auxiliary `session.generate` fiber
114
+ interruption alone does not emit a primary-execution event or disconnect HTTP.**
115
+ The bridge bounds `generate` and `title` requests to **10 minutes total**, starting
116
+ at the HTTP hook, including retries and streaming. This is an orphan-work bound,
117
+ not immediate cancellation; a legitimately long auxiliary call can also hit it.
118
+ Primary and compaction streams do not have this auxiliary deadline. Immediate
119
+ auxiliary cancellation requires upstream to pass the Effect interruption signal
120
+ as `abortSignal` into `doStream` and preserve it through fetch/middleware.
121
+ The correlation header is removed before the shared
122
+ executor sends a request to Anthropic. Plugin cleanup closes the local listener.
123
+
124
+ OpenCode 2.0.22 (and inspected HEAD) defaults `headerTimeout` and `chunkTimeout`
125
+ to 300,000 ms. Managed provider settings set those and `timeout` to `false` so
126
+ host timers cannot cut off the shared executor's retry/rotation waits. The
127
+ executor has attempt budgets, not a finite total retry deadline: account slots
128
+ are bounded by the pool, service errors normally get two retries, forced
129
+ `x-should-retry` normally gets three, but Retry-After waits and repeated transient
130
+ 429s can exceed five minutes. Primary cancellation/disconnect/disposal remain
131
+ available; auxiliary work has the separate bound above. 2.0.21 ignores the new
132
+ header setting; its number-only chunk schema requires `chunkTimeout: 0` to
133
+ disable that timer, while `timeout: false` is accepted on both hosts.
134
+
135
+ The compatibility route uses summary compaction. When switching from a native
136
+ provider, the host skips incompatible native checkpoints and re-expands the
137
+ original transcript (`session/history.ts:23-26,99-107` at `v2.0.21`). A new session
138
+ is not required and history is not corrupted, but context may grow substantially.
139
+ The adapter's rejection guard applies only if opaque checkpoint parts are
140
+ explicitly supplied to it; it does not describe normal host history loading.
141
+ Validation against other OpenCode versions is required before widening the
142
+ support claim. Host smoke tests exercise boot, RPC, streaming
143
+ generation and cancellation using a local mock upstream. They do not constitute
144
+ an authenticated end-to-end certification against Anthropic.
145
+
146
+ ## Administrative commands and the TUI
147
+
148
+ On OpenCode v2, the `./tui` entry registers `/anthropic` as a local TUI command.
149
+ The TUI calls the server through the plugin's RPC method and shows the result in
150
+ a dialog. Failures appear as toast notifications. Output is not inserted into
151
+ the conversation and the command does not submit a model prompt. OpenCode v1
152
+ continues to use the existing server slash-command hook.
153
+
154
+ Run the usual commands, for example `/anthropic usage`, `/anthropic switch 2`,
155
+ or `/anthropic set debug true`. OAuth keeps the same two-step flow:
156
+
157
+ 1. Run `/anthropic login` or `/anthropic reauth 1` and open the authorization URL.
158
+ 2. Complete authorization in the browser.
159
+ 3. Run `/anthropic login complete <code#state>` or
160
+ `/anthropic reauth complete <code#state>` in the same session.
161
+
162
+ When invoked from the home screen, the TUI creates an empty session before
163
+ running the command. That session holds the pending OAuth flow; it contains no
164
+ administrative output or authorization code. Commands entered through the
165
+ plugin's TUI layer are intercepted before the host's server command dispatch.
166
+
167
+ The RPC method is available to other OpenCode v2 clients. Use an existing
168
+ session and the location where the plugin is loaded:
169
+
170
+ ```js
171
+ import { anthropicCommandRpc } from "opencode-anthropic-fix/rpc";
172
+
173
+ const commands = client.rpc(anthropicCommandRpc);
174
+ const { output } = await commands.execute(
175
+ { sessionID, arguments: "usage" },
176
+ { location, signal: abortController.signal },
177
+ );
178
+ ```
179
+
180
+ The server also reserves the `anthropic` slash-command name. Clients that call
181
+ the server command endpoint directly receive an error directing them to the TUI
182
+ or RPC, because that endpoint cannot return administrative output. This avoids
183
+ starting an OAuth flow whose URL could not be displayed and prevents command
184
+ arguments from falling through to a model prompt.
185
+
186
+ The RPC ID is `opencode-anthropic-fix`; its method is `execute`. Input is
187
+ `{ sessionID, arguments }` and successful output is `{ output }`. The server
188
+ verifies that the session exists before executing a command. Arguments must be
189
+ a single CLI-style line of at most 8,192 characters. Responses are bounded to
190
+ 65,536 UTF-16 code units, with grapheme-safe truncation. The server removes
191
+ terminal escape sequences, token-shaped credentials and submitted OAuth
192
+ completion codes from responses and errors. Authorization URLs remain intact.
193
+
194
+ The plugin declares `command_failed` and `invalid_session` RPC errors. The host
195
+ can additionally return its standard `rpc.*` errors for unavailable services or
196
+ invalid requests. Unloading the TUI aborts outstanding RPC calls; disposing the
197
+ server registration propagates cancellation to its command executor and removes
198
+ the method. Neither RPC nor TUI requires an additional runtime SDK dependency.