@cortexkit/opencode-anthropic-auth 1.22.0 → 2.0.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.
Files changed (91) hide show
  1. package/README.md +259 -198
  2. package/dist/billing-lineage.d.ts +51 -0
  3. package/dist/cli-failure.d.ts +69 -0
  4. package/dist/cli.d.ts +16 -10
  5. package/dist/cli.js +111 -6
  6. package/dist/custody-dimensions.d.ts +19 -0
  7. package/dist/custody-mode.d.ts +46 -0
  8. package/dist/effort-history.d.ts +11 -2
  9. package/dist/fable-fallback.d.ts +1 -1
  10. package/dist/index-1jkyhgyr.js +2 -0
  11. package/dist/{index-bx5hsgf8.js → index-2arfb1y3.js} +2 -2
  12. package/dist/{index-926t2bzc.js → index-4ya27n12.js} +1 -1
  13. package/dist/{index-cgez4m0h.js → index-aaajxwzd.js} +1 -1
  14. package/dist/index-ae3fq4n6.js +42 -0
  15. package/dist/index-fds0s2j4.js +2 -0
  16. package/dist/index-nngmvczq.js +450 -0
  17. package/dist/index-pn597b6f.js +2 -0
  18. package/dist/{index-7f57ewkp.js → index-rqync0pc.js} +1 -1
  19. package/dist/index.js +1 -33
  20. package/dist/native-command.d.ts +19 -0
  21. package/dist/prime-manager-registry.d.ts +5 -1
  22. package/dist/rpc/notifications.d.ts +4 -3
  23. package/dist/rpc/port-file.js +1 -1
  24. package/dist/rpc/protocol.d.ts +15 -4
  25. package/dist/rpc/protocol.js +1 -1
  26. package/dist/rpc/rpc-client.d.ts +3 -1
  27. package/dist/rpc/rpc-client.js +1 -1
  28. package/dist/rpc/rpc-dir.js +1 -1
  29. package/dist/rpc/rpc-server.d.ts +5 -1
  30. package/dist/rpc/server-registry.d.ts +10 -0
  31. package/dist/setup/activation.d.ts +7 -0
  32. package/dist/setup/claustrum.d.ts +26 -0
  33. package/dist/setup/command-runner.d.ts +2 -0
  34. package/dist/setup/command.d.ts +20 -0
  35. package/dist/setup/command.test.d.ts +1 -0
  36. package/dist/setup/detect.d.ts +5 -0
  37. package/dist/setup/jsonc.d.ts +9 -0
  38. package/dist/setup/native-activation.d.ts +29 -0
  39. package/dist/setup/native-enrollment.d.ts +26 -0
  40. package/dist/setup/native-enrollment.test.d.ts +1 -0
  41. package/dist/setup/native-local.d.ts +20 -0
  42. package/dist/setup/native-login.d.ts +3 -0
  43. package/dist/setup/native-paths.d.ts +15 -0
  44. package/dist/setup/native-paths.test.d.ts +1 -0
  45. package/dist/setup/opencode-config.d.ts +18 -0
  46. package/dist/setup/paths.d.ts +15 -0
  47. package/dist/setup/pi.d.ts +18 -0
  48. package/dist/setup/process-fence.d.ts +20 -0
  49. package/dist/setup/process-fence.test.d.ts +1 -0
  50. package/dist/setup/types.d.ts +37 -0
  51. package/dist/sidebar-state.d.ts +3 -1
  52. package/dist/sidebar-state.js +1 -1
  53. package/dist/transform.d.ts +5 -1
  54. package/dist/tui/command-dialogs.d.ts +32 -2
  55. package/dist/tui-preferences.js +2 -2
  56. package/dist/v2/activation.d.ts +7 -0
  57. package/dist/v2/adapter.d.ts +276 -0
  58. package/dist/v2/install.d.ts +13 -0
  59. package/dist/v2/lifecycle.d.ts +8 -0
  60. package/dist/v2/menu-contract.d.ts +8 -0
  61. package/dist/v2/menu.d.ts +10 -0
  62. package/dist/v2/models.d.ts +6 -0
  63. package/dist/v2/ownership.d.ts +11 -0
  64. package/dist/v2/prime.d.ts +12 -0
  65. package/dist/v2/rpc.d.ts +50 -0
  66. package/dist/v2/server.d.ts +8 -0
  67. package/dist/v2/server.js +4 -0
  68. package/dist/v2/setup.d.ts +58 -0
  69. package/dist/v2/source.d.ts +41 -0
  70. package/dist/v2/tui.d.ts +13 -0
  71. package/dist/v2/tui.js +2 -0
  72. package/dist/v2/wire.d.ts +36 -0
  73. package/package.json +26 -6
  74. package/src/rpc/notifications.ts +37 -26
  75. package/src/rpc/protocol.ts +24 -7
  76. package/src/rpc/rpc-client.ts +18 -1
  77. package/src/rpc/rpc-server.ts +38 -8
  78. package/src/rpc/server-registry.ts +61 -0
  79. package/src/sidebar-state.ts +26 -2
  80. package/src/tui/command-dialogs.tsx +537 -68
  81. package/src/tui/entry.mjs +44 -18
  82. package/src/tui-compiled/rpc/protocol.ts +24 -7
  83. package/src/tui-compiled/rpc/rpc-client.ts +18 -1
  84. package/src/tui-compiled/sidebar-state.ts +26 -2
  85. package/src/tui-compiled/tui/command-dialogs.tsx +488 -95
  86. package/src/tui-compiled/tui.tsx +25 -7
  87. package/src/tui.tsx +38 -9
  88. package/dist/index-8aga2zwv.js +0 -4
  89. package/dist/index-d3f8g6ve.js +0 -428
  90. package/dist/index-sh51yqxs.js +0 -2
  91. package/dist/logger-jrkranbz.js +0 -1
@@ -0,0 +1,276 @@
1
+ import { type ClaudeCodeIdentity, TrailingAssistantHistoryError } from '@cortexkit/anthropic-auth-core';
2
+ import type { AccountRequest, AttemptOutcome, ChooseAccountInput, HeaderEdits, HostError, LimitSignal, OpenCode2AuthAdapter, RequestScope, Transport } from '@cortexkit/common-auth/opencode2';
3
+ import { EffortMarkerCorrelationError } from '../effort-history';
4
+ import { createStrippedStream, rewriteRequestBody } from '../transform';
5
+ /** The provider OpenCode 2 serves Claude under. */
6
+ export declare const ANTHROPIC_PROVIDER_ID = "anthropic";
7
+ /**
8
+ * Plugin-internal request headers that correlate a request with this
9
+ * plugin's own state. They are meaningful only inside the plugin and are
10
+ * removed before the request goes upstream, on both routes.
11
+ */
12
+ export declare const INTERNAL_REQUEST_HEADERS: readonly string[];
13
+ /**
14
+ * Fixed text of the refusal raised when the source has no credential for a
15
+ * send. It names no account, route or vault, because the host shows and logs
16
+ * it.
17
+ */
18
+ export declare const NO_ACCOUNT_REFUSAL = "Claude pool login is selected but no native account is usable. Complete offline migration or repair the pool and its quota policy before retrying.";
19
+ /**
20
+ * Most sends whose credential may wait between `accountHeaders` and
21
+ * `rewriteRequest` at once. Matches the installer's own default record bound;
22
+ * the oldest is dropped first, and a send whose entry was dropped is refused
23
+ * rather than sent without it.
24
+ */
25
+ export declare const DEFAULT_MAX_PENDING_SENDS = 512;
26
+ /**
27
+ * How long `onAttemptEnd` waits for the source to finish recording how a send
28
+ * ended. After that the adapter returns and logs a warning; the source's own
29
+ * work is not cancelled.
30
+ */
31
+ export declare const DEFAULT_ATTEMPT_END_TIMEOUT_MS = 5000;
32
+ /** Which kind of credential one send goes out with. */
33
+ export type NativeAnthropicRoute = 'oauth' | 'api';
34
+ /**
35
+ * Where one send goes: directly to Anthropic, or through the selected HTTP
36
+ * relay. A selected WebSocket relay appears here only so the adapter can
37
+ * refuse it before anything is sent. No local proxy transport is used.
38
+ */
39
+ export type NativeAnthropicDispatch = {
40
+ readonly kind: 'direct';
41
+ } | {
42
+ readonly kind: 'http-relay';
43
+ readonly url: string;
44
+ readonly token: string;
45
+ } | {
46
+ readonly kind: 'websocket-relay';
47
+ };
48
+ /**
49
+ * What the source authorizes for one send. `provenance` is the source's own
50
+ * record of the account and credential version that serve it (a local slot,
51
+ * a vault receipt with its version, an API key row). The adapter hands it back
52
+ * unchanged with every response, error and end of that send, so the source
53
+ * can tie a 401 or a quota reading to the exact account and version served.
54
+ */
55
+ export type NativeAnthropicAuthorization<P> = {
56
+ readonly route: 'oauth';
57
+ readonly accessToken: string;
58
+ /** The Claude Code identity of the account, when the source knows it. */
59
+ readonly identity?: ClaudeCodeIdentity;
60
+ /** Additional OAuth request headers; authorization and x-api-key edits are ignored so they cannot replace the authorized bearer. */
61
+ readonly headers?: HeaderEdits;
62
+ readonly provenance: P;
63
+ readonly dispatch?: NativeAnthropicDispatch;
64
+ } | {
65
+ readonly route: 'api';
66
+ /**
67
+ * API-route authentication headers must set authorization or x-api-key.
68
+ */
69
+ readonly headers: HeaderEdits;
70
+ /** The URL the send goes to instead of the host's, for this account. */
71
+ readonly baseURL?: string;
72
+ readonly provenance: P;
73
+ readonly dispatch?: NativeAnthropicDispatch;
74
+ };
75
+ /**
76
+ * Correlation metadata carried by common-auth's request hooks for one send.
77
+ * It contains neither credentials nor request body content.
78
+ */
79
+ export interface NativeAnthropicAttemptData<P> {
80
+ readonly route: NativeAnthropicRoute;
81
+ readonly provenance: P;
82
+ readonly dispatch: 'direct' | 'http-relay';
83
+ }
84
+ /**
85
+ * One send, as the source's response, error and end callbacks receive it:
86
+ * the host's request scope, the attempt, and what the source authorized.
87
+ */
88
+ export interface NativeAnthropicAttemptContext<P> extends AccountRequest {
89
+ readonly attemptId: string;
90
+ readonly transport: Transport | undefined;
91
+ readonly route: NativeAnthropicRoute;
92
+ readonly provenance: P;
93
+ readonly dispatch: 'direct' | 'http-relay';
94
+ }
95
+ /** Non-nullable options accepted by rewriteRequestBody. */
96
+ type RewriteBodyOptions = NonNullable<Parameters<typeof rewriteRequestBody>[1]>;
97
+ /**
98
+ * The body rewrite options a source supplies for an OAuth send: billing
99
+ * lineage, effort plan, cache, fast mode, safety and diagnostics inputs. Two
100
+ * options are left out because the adapter sets them: the Claude Code
101
+ * identity, which the source returns with the credential, and the session id,
102
+ * which is the host's own session id for the request.
103
+ */
104
+ export type NativeAnthropicBodyOptions = Omit<RewriteBodyOptions, 'identity' | 'sessionId'>;
105
+ type StrippedStreamOptions = NonNullable<Parameters<typeof createStrippedStream>[1]>;
106
+ /**
107
+ * The response observers a source may attach to an OAuth response. Content
108
+ * filter recovery and relay error hooks are left out on purpose: they exist
109
+ * to send the request again, and this adapter never sends.
110
+ */
111
+ export type NativeAnthropicResponseOptions = Pick<StrippedStreamOptions, 'perf' | 'onComplete' | 'serverSideFallbackModel' | 'onServerSideFallbackOutcome' | 'onMessageStart' | 'onMessageDelta' | 'onMessageResponse' | 'onStreamEnd' | 'laneStart'>;
112
+ /** What `requestOptions` receives for an OAuth send, before its body is rewritten. */
113
+ export interface NativeAnthropicRequestContext<P> extends NativeAnthropicAttemptContext<P> {
114
+ readonly route: 'oauth';
115
+ /**
116
+ * This plugin's own correlation headers found on the request (lower-case
117
+ * names, such as the effort plan or billing lineage id), already removed
118
+ * from it. The adapter does not interpret them; the source looks them up
119
+ * in its own trackers.
120
+ */
121
+ readonly correlation: Readonly<Record<string, string>>;
122
+ }
123
+ /**
124
+ * What the source's response callbacks receive: the send, plus the HTTP
125
+ * status of its response, before the body is read.
126
+ */
127
+ export interface NativeAnthropicResponseContext<P> extends NativeAnthropicAttemptContext<P> {
128
+ readonly status: number;
129
+ }
130
+ /** An `error` event inside a streamed response. */
131
+ export interface NativeAnthropicStreamErrorContext<P> extends NativeAnthropicAttemptContext<P> {
132
+ /** The provider's `error.type`, such as `overloaded_error`. */
133
+ readonly errorType: string | undefined;
134
+ readonly message: string | undefined;
135
+ }
136
+ /**
137
+ * How a send ended. `localRefusal` is set when the adapter refused the
138
+ * request itself before anything was sent (a malformed history, say); a
139
+ * provider 400 never carries it.
140
+ */
141
+ export interface NativeAnthropicAttemptOutcome extends AttemptOutcome {
142
+ readonly localRefusal?: {
143
+ readonly check: string;
144
+ };
145
+ }
146
+ /**
147
+ * The Core-owned source of accounts and policy. Every member is a function
148
+ * property, so under `strictFunctionTypes` a callback that accepts less than
149
+ * the adapter passes it is rejected at compile time.
150
+ */
151
+ export interface NativeAnthropicSource<Q, P> {
152
+ /** Picks the account for one request; `undefined` refuses it. */
153
+ readonly chooseAccount: (input: ChooseAccountInput) => Promise<string | undefined> | string | undefined;
154
+ /**
155
+ * The credential for one send with the chosen account; `undefined` refuses
156
+ * the request before anything is sent.
157
+ */
158
+ readonly authorizeAccount: (scope: RequestScope, accountId: string) => Promise<NativeAnthropicAuthorization<P> | undefined> | NativeAnthropicAuthorization<P> | undefined;
159
+ /** Body rewrite options for an OAuth send. */
160
+ readonly requestOptions?: (input: NativeAnthropicRequestContext<P>) => Promise<NativeAnthropicBodyOptions> | NativeAnthropicBodyOptions;
161
+ /** Rechecks policy after asynchronous rewriting, immediately before dispatch. */
162
+ readonly admitRequest?: (input: NativeAnthropicAttemptContext<P>) => Promise<void> | void;
163
+ /** Response observers for an OAuth response. */
164
+ readonly responseOptions?: (input: NativeAnthropicResponseContext<P>) => NativeAnthropicResponseOptions | undefined;
165
+ /** Quota carried by the upstream response headers, read once per response. */
166
+ readonly quotaFromHeaders?: (headers: Headers, input: NativeAnthropicResponseContext<P>) => Q | undefined;
167
+ /**
168
+ * Classifies an error response before its body streams. `body()` reads a
169
+ * copy, so the host still receives the body.
170
+ */
171
+ readonly limitFromResponse?: (input: NativeAnthropicResponseContext<P> & {
172
+ readonly headers: Headers;
173
+ readonly body: () => Promise<string>;
174
+ }) => Promise<LimitSignal | undefined> | LimitSignal | undefined;
175
+ /** Classifies a relay-local failure, never an Anthropic credential failure. */
176
+ readonly limitFromRelayFailure?: (input: NativeAnthropicResponseContext<P>) => Promise<LimitSignal | undefined> | LimitSignal | undefined;
177
+ /** Classifies an `error` event inside a streamed response. */
178
+ readonly limitFromStreamError?: (input: NativeAnthropicStreamErrorContext<P>) => LimitSignal | undefined;
179
+ /**
180
+ * Classifies the error the host hands the retry hook. Never asked about a
181
+ * send the adapter refused locally.
182
+ */
183
+ readonly limitFromHostError?: (error: HostError, input: NativeAnthropicAttemptContext<P>) => LimitSignal | undefined;
184
+ /**
185
+ * How a send ended, with the provenance of the credential it used, so a
186
+ * 401 can be reported against the exact vault receipt version served.
187
+ */
188
+ readonly onAttemptEnd?: (input: NativeAnthropicAttemptContext<P>, outcome: NativeAnthropicAttemptOutcome) => Promise<void> | void;
189
+ /**
190
+ * Called by the adapter's `forgetSession`; drops whatever the source keeps
191
+ * for the session.
192
+ */
193
+ readonly forgetSession?: (sessionID: string) => void;
194
+ }
195
+ export interface NativeAnthropicAdapterLogger {
196
+ warn(message: string, data?: Record<string, unknown>): void;
197
+ }
198
+ export interface NativeAnthropicAdapterDeps<Q, P> {
199
+ readonly source: NativeAnthropicSource<Q, P>;
200
+ readonly log?: NativeAnthropicAdapterLogger;
201
+ /** Maximum number of authorized sends waiting for their request rewrite. */
202
+ readonly maxPendingSends?: number;
203
+ /**
204
+ * How long `onAttemptEnd` waits for the source to record how a send
205
+ * ended; the source's work is not cancelled.
206
+ */
207
+ readonly attemptEndTimeoutMs?: number;
208
+ }
209
+ export interface NativeAnthropicAdapter<Q, P> {
210
+ readonly adapter: OpenCode2AuthAdapter<Q, NativeAnthropicAttemptData<P>>;
211
+ /**
212
+ * Drops the session's authorized sends that have not been rewritten yet,
213
+ * revokes its choices, authorizations and rewrites still in progress so
214
+ * none of them can return, and calls the source's `forgetSession`.
215
+ */
216
+ forgetSession(sessionID: string): void;
217
+ /** Revokes all pending work. Later calls refuse without invoking the source. */
218
+ dispose(): void;
219
+ /** Number of sends authorized and not yet rewritten or ended. */
220
+ readonly pendingSendCount: number;
221
+ /** Number of OAuth access tokens held for sends not yet rewritten. */
222
+ readonly heldCredentialCount: number;
223
+ /**
224
+ * Number of sends whose credentials are still held to scrub their errors:
225
+ * kept until the send ends cleanly, the retry hook has classified its
226
+ * failure, its session is forgotten, or maxPendingSends evicts the oldest.
227
+ */
228
+ readonly heldRedactorCount: number;
229
+ /** Number of choices, authorizations and rewrites still in progress. */
230
+ readonly operationsInProgress: number;
231
+ }
232
+ /**
233
+ * The request was refused before anything was sent because the source had
234
+ * no credential for it. Never retried on the host's own credential.
235
+ */
236
+ export declare class NativeAnthropicNoAccountError extends Error {
237
+ readonly sessionID: string;
238
+ readonly requestKind: string;
239
+ readonly kind = "no-account";
240
+ readonly providerID = "anthropic";
241
+ constructor(sessionID: string, requestKind: string);
242
+ }
243
+ /**
244
+ * The request was refused because its session was forgotten while the
245
+ * account choice, authorization or request rewrite for it was still in
246
+ * progress. Nothing from that work is returned or kept, and nothing is sent.
247
+ */
248
+ export declare class NativeAnthropicRevokedError extends Error {
249
+ readonly sessionID: string;
250
+ readonly requestKind: string;
251
+ readonly kind = "session-forgotten";
252
+ readonly providerID = "anthropic";
253
+ constructor(sessionID: string, requestKind: string);
254
+ }
255
+ /** OpenCode 2's HTTP model driver cannot speak the relay's binary WebSocket protocol. */
256
+ export declare class NativeAnthropicTransportRefusal extends Error {
257
+ readonly kind = "unsupported-transport";
258
+ readonly providerID = "anthropic";
259
+ constructor();
260
+ }
261
+ /**
262
+ * The request was refused with a local 400 because it can never succeed as
263
+ * written: its history ends on a meaningful assistant turn, or an effort
264
+ * marker in it cannot be matched to the session's effort plan. Nothing was
265
+ * sent, and another account cannot help, so the adapter never reports it as
266
+ * an account limit. The message and `check` describe only the shape of the
267
+ * problem, never conversation content.
268
+ */
269
+ export declare class NativeAnthropicLocalRefusal extends Error {
270
+ readonly kind = "local-invalid-request";
271
+ readonly status = 400;
272
+ readonly check: string;
273
+ constructor(cause: TrailingAssistantHistoryError | EffortMarkerCorrelationError);
274
+ }
275
+ export declare function createNativeAnthropicAdapter<Q, P>(deps: NativeAnthropicAdapterDeps<Q, P>): NativeAnthropicAdapter<Q, P>;
276
+ export {};
@@ -0,0 +1,13 @@
1
+ import { type InstallOpenCode2AuthOptions, type OpenCode2AuthInstallation, type OpenCode2HookContext } from '@cortexkit/common-auth/opencode2';
2
+ import { type NativeAnthropicAdapterDeps, type NativeAnthropicAttemptData } from './adapter';
3
+ export interface NativeAnthropicInstallation<Q, P> {
4
+ readonly installation: OpenCode2AuthInstallation<Q, NativeAnthropicAttemptData<P>>;
5
+ readonly forgetSession: (sessionID: string) => void;
6
+ readonly dispose: () => Promise<void>;
7
+ }
8
+ /**
9
+ * The shared installer removes request records on session deletion. Also cancel
10
+ * the adapter's pending credential lookup and body preparation: removing a
11
+ * record alone cannot stop an asynchronous callback from returning a token.
12
+ */
13
+ export declare function installNativeAnthropic<Q, P>(ctx: OpenCode2HookContext, deps: NativeAnthropicAdapterDeps<Q, P>, ownership: NonNullable<InstallOpenCode2AuthOptions['gateOnPlaceholder']>): Promise<NativeAnthropicInstallation<Q, P>>;
@@ -0,0 +1,8 @@
1
+ import { type NativeAccountRuntime } from '@cortexkit/anthropic-auth-core';
2
+ /**
3
+ * Background quota and profile reads obtain their own account credentials.
4
+ * They must not inherit the model policy of the latest user request.
5
+ */
6
+ export declare function startNativeAnthropicLifecycle(runtime: NativeAccountRuntime, fetchImpl?: typeof fetch): {
7
+ dispose(): Promise<void>;
8
+ };
@@ -0,0 +1,8 @@
1
+ import type { NativeMenuCommandId, NativeMenuDispatch } from '@cortexkit/anthropic-auth-core';
2
+ /** Account, setting and session actions exposed through the server's menu RPC. */
3
+ export interface NativeMenuCapabilities {
4
+ readonly dispatch: NativeMenuDispatch;
5
+ readonly readStatus: (command: Exclude<NativeMenuCommandId, 'start'>) => Promise<string>;
6
+ readonly forgetSession: (sessionID: string) => void;
7
+ readonly close: () => void;
8
+ }
@@ -0,0 +1,10 @@
1
+ import { type NativeAccountRuntime } from '@cortexkit/anthropic-auth-core';
2
+ import type { NativeMenuCapabilities } from './menu-contract';
3
+ import type { NativeSource } from './source';
4
+ export type { NativeMenuCapabilities } from './menu-contract';
5
+ /** Account and setting changes use the same Core runtime as model requests. */
6
+ export declare function createNativeMenuCapabilities(options: {
7
+ readonly runtime: NativeAccountRuntime;
8
+ readonly source: NativeSource;
9
+ readonly start: (sessionID: string, text: string) => Promise<void>;
10
+ }): NativeMenuCapabilities;
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from '@opencode/plugin';
2
+ /** Each model variant supplies request settings for adaptive thinking and its selected reasoning effort. */
3
+ export declare function createNativeClaudeModelRules(): {
4
+ install: (ctx: Pick<Plugin.Context, 'model'>) => Promise<import("@opencode/plugin/promise/registration").Registration>;
5
+ modelId: (id: string) => string;
6
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Read the credential OpenCode attached to this request: the bearer token, or
3
+ * else the API key. When a user signs in through this plugin (Claude pool
4
+ * login or vault activation), OpenCode stores a fixed, non-secret placeholder
5
+ * string instead of a real token: placeholderSecret('anthropic') from
6
+ * @cortexkit/common-auth. The request hooks that installOpenCode2Auth installs
7
+ * serve a request from the plugin's own accounts only when this value equals
8
+ * that placeholder exactly. Any real token or key, whether from OpenCode's own
9
+ * login, a configured API key or an environment variable, is left untouched.
10
+ */
11
+ export declare function preparedAnthropicCredential(headers: Headers): string | undefined;
@@ -0,0 +1,12 @@
1
+ import { type NativeAccountRuntime, type NativePoolPaths, PrimeManager } from '@cortexkit/anthropic-auth-core';
2
+ import type { NativeSource } from './source';
3
+ /** After the five-hour quota resets, send one minimal authenticated request to start its next window and record that request's token usage. */
4
+ export declare function createNativePrime(options: {
5
+ runtime: NativeAccountRuntime;
6
+ paths: NativePoolPaths;
7
+ source: NativeSource;
8
+ fetch?: typeof fetch;
9
+ }): {
10
+ manager: PrimeManager;
11
+ dispose(): Promise<void>;
12
+ };
@@ -0,0 +1,50 @@
1
+ import type { CommandApplyRequest, CommandApplyResult, CommandDialogPayload, CommandMenu } from '@cortexkit/anthropic-auth-core';
2
+ import type { Plugin } from '@opencode/plugin';
3
+ import type { Registration } from '@opencode/plugin/promise/registration';
4
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
5
+ import type { NativeMenuCapabilities } from './menu-contract';
6
+ export declare const NATIVE_MENU_RPC: {
7
+ readonly id: 'cortexkit-anthropic-native';
8
+ readonly methods: {
9
+ readonly open: {
10
+ readonly input: StandardSchemaV1<Record<string, unknown> & {
11
+ sessionId: string;
12
+ }, Record<string, unknown> & {
13
+ sessionId: string;
14
+ }>;
15
+ readonly output: StandardSchemaV1<CommandDialogPayload, CommandDialogPayload>;
16
+ };
17
+ readonly apply: {
18
+ readonly input: StandardSchemaV1<CommandApplyRequest & {
19
+ sessionId: string;
20
+ }, CommandApplyRequest & {
21
+ sessionId: string;
22
+ }>;
23
+ readonly output: StandardSchemaV1<CommandApplyResult, CommandApplyResult>;
24
+ };
25
+ };
26
+ readonly events: {
27
+ readonly opened: {
28
+ readonly schema: StandardSchemaV1<{
29
+ sessionId: string;
30
+ payload: CommandDialogPayload;
31
+ }, {
32
+ sessionId: string;
33
+ payload: CommandDialogPayload;
34
+ }>;
35
+ };
36
+ readonly notification: {
37
+ readonly schema: StandardSchemaV1<{
38
+ sessionId: string;
39
+ message: string;
40
+ kind: 'info' | 'warning' | 'error';
41
+ }, {
42
+ sessionId: string;
43
+ message: string;
44
+ kind: 'info' | 'warning' | 'error';
45
+ }>;
46
+ };
47
+ };
48
+ };
49
+ /** OpenCode routes these RPC calls to the current project. No separate loopback server is started. */
50
+ export declare function registerNativeMenu(ctx: Pick<Plugin.Context, 'rpc' | 'command' | 'event'>, command: CommandMenu, capabilities: NativeMenuCapabilities): Promise<Registration>;
@@ -0,0 +1,8 @@
1
+ export type { AnthropicAuthV2Options } from './setup';
2
+ export { ANTHROPIC_AUTH_PLUGIN_ID, createAnthropicAuthPlugin, setupAnthropicAuth, } from './setup';
3
+ declare const _default: {
4
+ id: string;
5
+ setup: (context: import("@opencode/plugin/promise/plugin").Context) => Promise<import("@opencode/plugin/promise/plugin").Cleanup | void> | import("@opencode/plugin/promise/plugin").Cleanup | void;
6
+ server: import("@opencode-ai/plugin").Plugin;
7
+ };
8
+ export default _default;
@@ -0,0 +1,4 @@
1
+ import{a as O2,b as t$,c as $1,d as j$,e as B$,f as k2,g as M2,h as V$,i as K1,j as Q$,k as H$,l as U$,m as C$,n as L$,o as B1}from"../index-ae3fq4n6.js";import"../index-2arfb1y3.js";import"../index-rqync0pc.js";import{t as z1}from"../index-1jkyhgyr.js";import"../index-pn597b6f.js";import"../index-fds0s2j4.js";import{$b as T$,Cd as Y1,Ha as x2,Hd as W1,Ia as l$,Id as o$,Jb as h2,Jc as w$,Jd as n$,Kb as m2,Kd as r$,Nd as J1,Pd as R$,Qa as u$,Qd as q$,Sc as y$,Sd as p2,Ud as h$,Vb as O$,Wa as A2,Xb as E$,Yd as s$,Zb as S$,Zd as a$,aa as G$,ab as p$,ac as x$,ad as I$,ae as k$,ee as J$,fc as Y$,fd as X2,fe as z$,gd as W$,ge as c2,jd as A$,ld as G1,oa as S2,sd as N2,ta as X$,td as d$,ua as R2,va as q2,vb as _2,vd as c$,xd as i$,yd as X1,zc as b$,zd as P2}from"../index-nngmvczq.js";import"../index-4ya27n12.js";import"../index-aaajxwzd.js";class U2 extends Error{kind;providerID;sessionID;requestKind;constructor(Z){super(Z.message??`${Z.providerID} ${Z.requestKind} request refused (${Z.kind})`);this.name="OpenCode2AuthError",this.kind=Z.kind,this.providerID=Z.providerID,this.sessionID=Z.sessionID,this.requestKind=Z.requestKind}}function W2(Z){return`common-auth-placeholder.${Z}`}function s2(Z){let K=W2(Z.integrationID);return{type:"oauth",methodID:Z.methodID,access:K,refresh:K,expires:Z.now+31536000000,metadata:{["commonAuthPlaceholder"]:!0}}}function w2(Z,K){if(Z?.type!=="oauth")return!1;let L=K===void 0?void 0:W2(K),J=(N)=>L===void 0?N.startsWith("common-auth-placeholder."):N===L;return J(Z.access)&&J(Z.refresh)}var a2="No browser sign-in: this connects the plugin to the accounts in its vault.";async function y2(Z,K){let L=K.now??Date.now,{integrationID:J}=K,N=(F)=>s2({integrationID:J,methodID:F,now:L()}),M=async(F,V)=>{return await K.onLogin(F,{integrationID:J,methodID:V}),N(V)},T=(F)=>async(V)=>{let Y=F.method.id,H=await F.authorize(V),_={url:H.url,instructions:H.instructions,...H.expiresAt===void 0?{}:{expiresAt:H.expiresAt}};if(H.mode==="auto")return{..._,mode:"auto",callback:H.callback.then((x)=>M(x,Y))};let Q=H.callback;return{..._,mode:"code",callback:async(x)=>M(await Q(x),Y)}};return Z.integration.transform((F)=>{let V=K.label===void 0?{}:{label:()=>K.label};for(let _ of K.methods)F.method.update({integrationID:J,method:_.method,authorize:T(_),refresh:async(Q)=>{if(!w2(Q,J))throw Error("This login method refreshes only its pool placeholder; sign in again with the plugin's login method.");return N(Q.methodID)},...V});let Y=K.vault;if(Y===void 0)return;let H=Y.method.id;F.method.update({integrationID:J,method:Y.method,authorize:async()=>({url:"",instructions:Y.instructions??a2,mode:"auto",callback:Promise.resolve().then(()=>Y.activate({integrationID:J,methodID:H})).then(()=>N(H))}),refresh:async(_)=>{if(!w2(_,J)||_.methodID!==H)throw Error("This login method refreshes only its vault placeholder; choose the plugin's vault login method again.");return N(H)},...V})})}function V1(Z){let K=[],L;for(let J of Z.split(/\r?\n/))if(J.startsWith("data:"))K.push(J.slice(5).replace(/^ /,""));else if(J.startsWith("event:"))L=J.slice(6).trim();if(K.length===0)return;return L===void 0?{data:K.join(`
2
+ `)}:{event:L,data:K.join(`
3
+ `)}}function I2(Z,K){let L=new TextDecoder,J="",N=(T)=>{let F=V1(T);if(!F)return;try{Z(F)}catch(V){K(V)}},M=()=>{for(;;){let T=/\r?\n\r?\n/.exec(J);if(!T)return;let F=J.slice(0,T.index);J=J.slice(T.index+T[0].length),N(F)}};return new TransformStream({transform(T,F){F.enqueue(T),J+=L.decode(T,{stream:!0}),M()},flush(){if(J+=L.decode(),M(),J.trim()!=="")N(J);J=""}})}var t2=512,B2="x-common-auth-attempt",J2=(Z,K)=>JSON.stringify([Z,K]),G2=(Z)=>({providerID:Z.model.providerID,modelID:Z.model.id,sessionID:Z.sessionID,agent:Z.agent,kind:Z.kind});function Q1(Z){let K=Z.headers;return typeof K==="object"&&K!==null}function H1(Z,K){let L=Z.getReader();return new ReadableStream({async pull(J){let N;try{N=await L.read()}catch(M){K({reason:"failed",message:M instanceof Error?M.message:String(M)}),J.error(M);return}if(N.done)K(),J.close();else J.enqueue(N.value)},async cancel(J){K({reason:"cancelled",...J===void 0?{}:{message:String(J)}}),await L.cancel(J)}})}function g2(Z,K){for(let[L,J]of Object.entries(K)){let N=L.toLowerCase();for(let M of Object.keys(Z))if(M.toLowerCase()===N)delete Z[M];if(J!==null)Z[L]=J}}function U1(Z,K){for(let[L,J]of Object.entries(K))if(J===null)Z.delete(L);else Z.set(L,J)}async function f2(Z,K,L={}){let{providerID:J}=K,N=L.gateOnPlaceholder,M=($)=>N===void 0||N.credential($)===W2(J),T=L.logger,F=Math.max(1,L.maxRecords??t2),V=[...L.hostCredentials??[W2(J)],...N?[W2(J)]:[]].filter(($)=>$!==""),Y=new Map,H=new WeakMap,_=new Map,Q=new Set,x=new Map,y=!1,D=!1,v=new Map,i=0,r=!1,n=new Map,c=($,z)=>{try{T?.warn($,z)}catch{}},G=($)=>$ instanceof Error?$.message:String($),j=async($,z)=>{let C=v.get($);if(!C||C.size===0)return;await Promise.all([...C].map(async(P)=>{try{await P(z)}catch(b){c("opencode2 auth listener threw; the request is unaffected",{event:$,error:G(b)})}}))},B=async($,z)=>{try{await K.onAttemptEnd?.($,z)}catch(C){c("opencode2 auth onAttemptEnd threw; the request is unaffected",{attemptId:$.attemptId,error:G(C)})}},S=($,z)=>{if($.ended||!$.attempt)return;let C={...$.status===void 0?{}:{status:$.status},outputStarted:$.outputStarted,...$.limit?{limit:$.limit.signal}:{},...z?{error:z}:{}};if(z)$.endError=z;$.ended=B($.attempt,C)},E=($,z)=>S($,{reason:"abandoned",message:z}),g=($)=>[...Y.values()].filter((z)=>z.key===$),h=($)=>g($).at(-1),d=($)=>{if(Y.delete($.id),!g($.key).length)_.delete($.key)},p=($)=>{Y.set($.id,$);while(Y.size>F){let z=Y.values().next().value;if(z===void 0)break;E(z,"dropped to keep the record bound"),d(z)}},I=($)=>$.accountId===void 0?void 0:{...$.scope,accountId:$.accountId},X=($,z)=>new U2({kind:"no-account",providerID:J,sessionID:$.sessionID,requestKind:$.kind,...z===void 0?{}:{message:z}}),W=($)=>{n.get($)?.clear(),n.delete($)},U=async($,z)=>{let C=()=>X($,`${J} ${$.kind} request has no account: its auth selection was revoked by session forgetting or installation disposal`);if(r)throw C();let P=n.get($.sessionID);if(!P)P=new Set,n.set($.sessionID,P);let b={};P.add(b);let f=()=>{if(!P.has(b))throw C()};try{return await z(f)}finally{if(P.delete(b),P.size===0&&n.get($.sessionID)===P)n.delete($.sessionID)}},A=($,z)=>{for(let[C,P]of z)if(V.some((b)=>P.includes(b)))throw new U2({kind:"host-credential-on-wire",providerID:J,sessionID:$.sessionID,requestKind:$.kind,message:`${J} ${$.kind} request still carries the host's placeholder credential in ${C}; the adapter's account headers must replace it`})},R=($)=>{for(let z of g($))if(z.ended||!z.attempt)d(z);else if(z.transport==="ws"||z.judged)E(z,"a newer attempt of its session and kind began"),d(z)},O=async($,z,C,P)=>{let b=J2($.sessionID,$.kind),f=_.get(b);_.delete(b);let k=f?.accountId??h(b)?.accountId;R(b);let w={...$,...k===void 0?{}:{previousAccountId:k},...f?.rerouteFrom===void 0?{}:{rerouteFrom:f.rerouteFrom}},m=await K.chooseAccount(w);C();let Z2={},n2;if(m!==void 0){let T2=await K.accountHeaders({...$,accountId:m});if(C(),Q1(T2))Z2=T2.headers,n2=T2.attempt;else Z2=T2}let r2=`attempt-${++i}`,H2={id:r2,key:b,scope:$,accountId:m,headers:Z2,attempt:m===void 0?void 0:{...$,accountId:m,attemptId:r2,transport:P,data:n2},...P===void 0?{}:{transport:P},outputStarted:!1};if(p(H2),H2.attempt)j("select",{...$,accountId:H2.attempt.accountId,hook:z,...w.previousAccountId===void 0?{}:{previousAccountId:w.previousAccountId},...w.rerouteFrom===void 0?{}:{rerouteFrom:w.rerouteFrom},handle:H2.attempt});return H2},q=async($,z,C,P,b)=>{let f=J2($.sessionID,$.kind),k=P===void 0?void 0:Y.get(P);if(k?.key!==f)k=void 0;if(!k){if(k=h(f),g(f).filter((m)=>m.transport===void 0&&!m.ended).length>1&&!D)D=!0,c("opencode2 auth tied a send without its attempt mark to the newest of several waiting attempts",{sessionID:$.sessionID,kind:$.kind})}if(!k||k.transport!==void 0||k.ended)k=await O($,z,b,C);else if(k.transport=C,k.attempt)k.attempt.transport=C;if(C==="ws"){for(let w of g(f))if(w!==k&&w.transport==="ws")E(w,"a newer attempt of its session and kind went out over WebSocket")}return k},l=async($,z)=>{try{return await z()}catch(C){throw S($,{reason:"failed",message:G(C)}),C}},u=($,z)=>{let C=g(J2($,z)).filter((P)=>P.transport==="ws").at(-1);return C?.attempt!==void 0&&!C.ended?C:void 0},s=($,z,C)=>{let P=I($);if(!P||!$.attempt||$.limit)return;$.limit={signal:z,delivered:j("limit",{...P,via:C,limit:z,outputStarted:$.outputStarted,handle:$.attempt})}},$2=($,z,C,P)=>{let b=I($);if(!b||!$.attempt)return;j("quota",{...b,transport:z,...P===void 0?{}:{status:P},quota:C,handle:$.attempt})},K2=($,z,C,P)=>{let b=$.attempt;if(!b)return;let f=K.inspectEvent?.(P===void 0?{transport:z,data:C,attempt:b}:{transport:z,data:C,event:P,attempt:b});if(!f)return;if(f.quota!==void 0)$2($,z,f.quota);if(f.outputStarted)$.outputStarted=!0;if(f.limit)s($,f.limit,z);if(f.error!==void 0)S($,{reason:"failed",message:f.error});else if(f.done)S($)},e=($,z)=>{let C=$.attempt;if(!C||z.accountId===$.accountId)return;if(C.reboundFrom??=C.accountId,C.accountId=z.accountId,"data"in z)C.data=z.data;$.accountId=z.accountId},o=($)=>!$.attempt||$.endError!==void 0||$.status!==void 0&&$.status>=400,Y2=($)=>{let z=[...Y.values()].filter((w)=>w.scope.sessionID===$),C=z.filter((w)=>w.limit&&!w.rerouted).at(-1);if(C)return C;let P=z.filter((w)=>w.scope.kind==="primary"),b=P.length>0?P:z;if(b.length<=1)return b[0];let f=b.filter((w)=>!w.judged&&o(w)).at(-1);if(f)return f;let k=b.filter((w)=>w.attempt&&!w.ended);if(k.length>1)return"ambiguous";return k[0]??b.at(-1)},a={providerID:J},t=[];t.push(await Z.session.hook("model.request",($)=>{if(N)return;return U(G2($),async(z)=>{let C=await O(G2($),"model.request",z);if(z(),C.accountId===void 0)throw X(C.scope);g2($.headers,{...C.headers,[B2]:C.id})})},a)),t.push(await Z.session.hook("http.request",($)=>{if(N){let z=M($.request.headers);if(x.set($.sessionID,z),!z)return}return U(G2($),async(z)=>{let C=$.request.headers.get(B2)??void 0,P=N?await O(G2($),"http.request",z,"http"):await q(G2($),"http.request","http",C,z);z();let b=I(P),f=P.attempt;if(!b||!f)throw X(P.scope);await l(P,async()=>{let k=$.request;if(K.rewriteRequest){if(C!==void 0){let Z2=new Headers(k.headers);Z2.delete(B2),k=new Request(k,{headers:Z2})}k=await K.rewriteRequest({...b,request:k,attempt:f})??k,z()}let w=new Headers(k.headers);w.delete(B2),U1(w,P.headers),A(P.scope,w.entries());let m=new Request(k,{headers:w});H.set(m,P),$.request=m})})},a)),t.push(await Z.session.hook("http.response",async($)=>{let z=H.get($.request);if(!z){if(N)return;if(!y)y=!0,c("opencode2 auth dropped an http.response whose request it did not produce",{sessionID:$.sessionID,kind:$.kind});return}let C=$.response;if(K.answeredBy&&z.attempt){let w=z.attempt,m=await l(z,async()=>K.answeredBy?.({request:$.request,response:C,attempt:w}));if(m)e(z,m)}let P=I(z),b=z.attempt;if(!P||!b)return;z.status=C.status;let f=K.quotaFromHeaders?.(C.headers,C.status,b);if(f!==void 0)$2(z,"http",f,C.status);if(!C.ok&&K.limitFromResponse){let w=await K.limitFromResponse({status:C.status,headers:C.headers,body:()=>C.clone().text(),attempt:b});if(w)s(z,w,"http")}if(!C.ok||!C.body)S(z);let k=C;if(C.body&&(K.inspectEvent||K.onAttemptEnd)){let w=C.body;if(K.inspectEvent)w=w.pipeThrough(I2((m)=>K2(z,"http",m.data,m.event),(m)=>c("opencode2 auth event inspection threw",{error:G(m)})));k=new Response(H1(w,(m)=>S(z,m)),{status:C.status,statusText:C.statusText,headers:C.headers})}if(K.rewriteResponse)k=await K.rewriteResponse({...P,request:$.request,response:k,attempt:b})??k;if(k!==C)$.response=k},a)),t.push(await Z.session.hook("experimental.ws.handshake",($)=>{if(N){let z=M(new Headers($.headers)),C=J2($.sessionID,$.kind);if(x.set($.sessionID,z),Q.delete(C),!z)return}return U(G2($),async(z)=>{let C;for(let k of Object.keys($.headers)){if(k.toLowerCase()!==B2)continue;C??=$.headers[k],delete $.headers[k]}let P=N?await O(G2($),"experimental.ws.handshake",z,"ws"):await q(G2($),"experimental.ws.handshake","ws",C,z);z();let b=I(P),f=P.attempt;if(!b||!f)throw X(P.scope);await l(P,async()=>{g2($.headers,P.headers);let k=K.rewriteHandshakeURL?.({...b,url:$.url,attempt:f});if(k!==void 0)$.url=k;if(A(P.scope,Object.entries($.headers)),N)Q.add(P.key)})})},a));let Q2=K.rewriteWebSocketFrame?.bind(K);if(Q2)t.push(await Z.session.hook("experimental.ws.send",async($)=>{let z=G2($);if(N&&!Q.has(J2(z.sessionID,z.kind)))return;let C=u(z.sessionID,z.kind),P=await Q2({...z,attempt:C?.attempt,frame:$.frame});if(P!==void 0)$.frame=P},a));t.push(await Z.session.hook("experimental.ws.receive",($)=>{if(N&&!Q.has(J2($.sessionID,$.kind)))return;let z=u($.sessionID,$.kind);if(!z)return;try{K2(z,"ws",$.frame)}catch(C){c("opencode2 auth frame inspection threw",{error:G(C)})}},a)),t.push(await Z.session.hook("retry",async($)=>{if(N&&x.get($.sessionID)!==!0)return;let z=Y2($.sessionID);if(!z)return;let C=$.decision;if(z==="ambiguous"){await j("retry",{sessionID:$.sessionID,attempt:$.attempt,reason:"host-decides",hostDecision:C,decision:C});return}let P=z;await U(P.scope,async(b)=>{P.judged=!0;let f=C,k,w,m=P.attempt;if(P.accountId===void 0||!m)f={retry:!1},k="no-account";else if(P.outputStarted)f={retry:!1},k="output-started";else{if(!P.limit){let Z2=K.limitFromError?.($.error,m);if(Z2)s(P,Z2,"error")}if(P.ended)await P.ended,b();if(P.limit)await P.limit.delivered,b(),P.rerouted=!0,w={accountId:P.accountId,limit:P.limit.signal},f={retry:!0,delay:0},k="reroute";else k="host-decides"}if($.decision=f,f.retry&&P.accountId!==void 0)_.set(P.key,{sessionID:P.scope.sessionID,accountId:P.accountId,...w===void 0?{}:{rerouteFrom:w}});await j("retry",{sessionID:$.sessionID,...P.accountId===void 0?{}:{accountId:P.accountId},kind:P.scope.kind,attempt:$.attempt,reason:k,hostDecision:C,decision:f,...m===void 0?{}:{handle:m}})})},a));let j2=($)=>{W($),x.delete($);for(let z of Q)if(JSON.parse(z)[0]===$)Q.delete(z);for(let z of[...Y.values()]){if(z.scope.sessionID!==$)continue;E(z,"its session was forgotten"),Y.delete(z.id)}for(let[z,C]of _)if(C.sessionID===$)_.delete(z)},b2=new AbortController,o2=Z.event;if(o2)(async()=>{try{for await(let $ of o2.subscribe({signal:b2.signal}))if($.type==="session.deleted")j2($.data.sessionID)}catch($){if(!b2.signal.aborted)c("opencode2 auth stopped listening for session deletion",{error:G($)})}})();return{on($,z){let C=v.get($);if(!C)C=new Set,v.set($,C);let P=z;return C.add(P),()=>{C.delete(P)}},accountFor($,z){return h(J2($,z))?.accountId},forgetSession:j2,get size(){return Y.size},async dispose(){if(r)return;r=!0;for(let $ of n.keys())W($);b2.abort();for(let $ of Y.values())E($,"the installation was disposed");Y.clear(),_.clear(),Q.clear(),x.clear(),v.clear(),await Promise.all(t.map(async($)=>{try{await $.dispose()}catch(z){c("opencode2 auth hook did not dispose cleanly",{error:G(z)})}}))}}}var e2="native-claude-oauth",$$="native-claude-vault";import{createHash as C1}from"node:crypto";var L2="anthropic",M$="x-common-auth-attempt",L1=["x-session-affinity","x-opencode-session","x-parent-session-id",j$,O2,M2,M$],F2=new Set(["authorization","x-api-key"]),M1="Claude pool login is selected but no native account is usable. Complete offline migration or repair the pool and its quota policy before retrying.",_1=512,N1=5000,P1=500,K$=new Set(["invalid_request_error","authentication_error","billing_error","permission_error","not_found_error","request_too_large","rate_limit_error","timeout_error","api_error","overloaded_error"]);class _$ extends Error{sessionID;requestKind;kind="no-account";providerID=L2;constructor(Z,K){super(M1);this.sessionID=Z;this.requestKind=K;this.name="NativeAnthropicNoAccountError"}}class l2 extends Error{sessionID;requestKind;kind="session-forgotten";providerID=L2;constructor(Z,K){super("request refused: its session was closed while it was being prepared");this.sessionID=Z;this.requestKind=K;this.name="NativeAnthropicRevokedError"}}class V2 extends Error{kind="unsupported-transport";providerID=L2;constructor(){super("request refused: WebSocket relay is not supported on OpenCode 2; select HTTP relay or direct transport");this.name="NativeAnthropicTransportRefusal"}}class N$ extends Error{kind="local-invalid-request";status=400;check;constructor(Z){super(Z.message,{cause:Z});this.name="NativeAnthropicLocalRefusal",this.check=Z.check}}var z2=(Z)=>typeof Z==="object"&&Z!==null&&!Array.isArray(Z);function C2(Z){try{return JSON.parse(Z)}catch{return}}function v2(Z){let K={};for(let[L,J]of Object.entries(Z??{}))K[L.toLowerCase()]=J;return K}function Z$(Z){let K={};for(let L of L1){let J=Z.get(L);if(J!==null&&L!==M$)K[L]=J;Z.delete(L)}return K}function T1(Z){try{return new URL(Z).pathname.endsWith("/messages")}catch{return!1}}function F1(Z){return Z instanceof J$||Z instanceof B$?new N$(Z):void 0}function O1(Z,K){let L=[];if(Z.oauth)L.push(Z.oauth.accessToken);for(let[J,N]of Object.entries(Z.apiHeaders??{})){if(N===null||!F2.has(J))continue;L.push(N.replace(/^Bearer\s+/i,""))}for(let J of F2){let N=K.get(J);if(N!==null)L.push(N.replace(/^Bearer\s+/i,""))}if(Z.dispatch?.kind==="http-relay")L.push(Z.dispatch.token);return[...new Set(L.filter(Boolean))]}var E1=new Set(["oauth-2025-04-20","claude-code-20250219",V$]);function S1(Z){let K=Z.split(",").map((L)=>L.trim()).filter((L)=>L&&!E1.has(L));return G$(null,K)}function x1(Z){let K=C2(Z);if(!z2(K))return Z;let L=z$(K.messages),J=Object.hasOwn(K,"fallbacks"),{droppedMarkers:N}=Q$(K,!1),M=J&&!Object.hasOwn(K,"fallbacks"),T=W$(K);return L>0||N>0||M||T?JSON.stringify(K):Z}async function A1(Z,K){if(!(Z instanceof Promise))return"settled";let L;try{return await Promise.race([Z.then(()=>"settled"),new Promise((J)=>{L=setTimeout(()=>J("timed-out"),K)})])}finally{if(L!==void 0)clearTimeout(L)}}function E2(Z){let{source:K,log:L}=Z,J=Math.max(1,Z.maxPendingSends??_1),N=Z.attemptEndTimeoutMs??N1,M=new Map,T=new WeakMap,F=new WeakMap,V=new Map,Y=new WeakMap,H=h2([]);H.dispose();let _=(X)=>(X&&V.get(X)?.redactor)??H,Q=(X)=>{let W=V.get(X);if(!W)return;V.delete(X),W.redactor.dispose(),W.scope.dispose()},x=(X,W,U,A)=>{let R=O1(W,A),O=m2(R,U);y.set(X,U),V.set(X,{sessionID:W.sessionID,redactor:h2(R),scope:O}),O.settled.then(()=>Q(X));while(V.size>J){let q=V.keys().next().value;if(q===void 0)break;Q(q)}},y=new WeakMap,D=(X,W)=>{let U=X?y.get(X):void 0;if(!U||!W.ok)return H.redactResponse(W);let A=m2([],U),R=A.redactResponse(W);return A.dispose(),R},v=(X,W)=>{let U=X?V.get(X)?.scope:void 0;if(!U)return D(X,W);try{return U.redactResponse(W)}catch{return D(X,W)}},i=!1,r=new WeakMap,n=(X,W)=>{if(X&&!W.ok)r.set(W.headers,X);return W},c=(X,W)=>{if(W.dispatch!=="http-relay")return!0;let U=/^req_[A-Za-z0-9_-]+$/.test(X.get("request-id")??"");return F.set(W,U),U},G=(X)=>new _$(X.sessionID,X.kind),j=new Map,B=async(X,W)=>{if(i)throw new l2(X.sessionID,X.kind);let U={revoked:!1},A=j.get(X.sessionID);if(!A)A=new Set,j.set(X.sessionID,A);A.add(U);let R=()=>{if(i||U.revoked)throw new l2(X.sessionID,X.kind)};try{let O=await W(R);return R(),O}finally{let O=j.get(X.sessionID);if(O?.delete(U)&&O.size===0)j.delete(X.sessionID)}},S=(X,W)=>{M.set(X,W);while(M.size>J){let U=M.keys().next().value;if(U===void 0)break;M.delete(U),L?.warn("dropped the oldest pending Anthropic send to stay bounded",{bound:J})}},E=(X,W)=>({providerID:X.providerID,modelID:X.modelID,sessionID:X.sessionID,agent:X.agent,kind:X.kind,accountId:X.accountId,attemptId:X.attemptId,transport:X.transport,route:W.route,provenance:W.provenance,dispatch:W.dispatch}),g=(X)=>B(X,async(W)=>{let{accountId:U,...A}=X,R=await K.authorizeAccount(A,U);return W(),h(A,R)}),h=(X,W)=>{if(!W)throw G(X);if(W.dispatch?.kind==="websocket-relay")throw new V2;let U=W.dispatch?.kind==="http-relay"?"http-relay":"direct",A=W.dispatch?.kind==="http-relay"?{authorization:null,"x-api-key":null,"x-relay-token":W.dispatch.token}:void 0;if(W.route==="oauth"){if(!W.accessToken)throw G(X);X$(W.accessToken,L2);let q=Object.freeze({route:"oauth",provenance:W.provenance,dispatch:U});S(q,{sessionID:X.sessionID,oauth:{accessToken:W.accessToken,...W.identity?{identity:W.identity}:{}},dispatch:W.dispatch,oauthHeaders:W.headers});let l=v2(W.headers);for(let u of F2)delete l[u];return delete l["anthropic-beta"],{headers:A??{...l,"x-api-key":null,authorization:`Bearer ${W.accessToken}`},attempt:q}}let R={authorization:null,"x-api-key":null,...v2(W.headers)};if(!R.authorization&&!R["x-api-key"])throw G(X);let O=Object.freeze({route:"api",provenance:W.provenance,dispatch:U});return S(O,{sessionID:X.sessionID,...W.baseURL?{baseURL:W.baseURL}:{},dispatch:W.dispatch,apiHeaders:R}),{headers:A??R,attempt:O}},d=(X)=>B(X,(W)=>p(X,W)),p=async(X,W)=>{let{request:U,attempt:A}=X,R=A.data,O=R?M.get(R):void 0;if(R)M.delete(R);if(!R||!O||R.route==="oauth"&&!O.oauth)throw G(X);let q=new Headers(U.headers);Y$(q);let l=Z$(q),u=U.body===null?void 0:await U.text();W();let s=u!==void 0&&T1(U.url);try{if(R.route==="oauth"&&O.oauth){let{accessToken:e,identity:o}=O.oauth;for(let[a,t]of Object.entries(v2(O.oauthHeaders))){if(F2.has(a))continue;if(t===null)q.delete(a);else q.set(a,t)}let Y2=null;if(u!==void 0&&s){let a={...E(A,R),modelID:(()=>{let j2=C2(u);return X2(z2(j2)&&typeof j2.model==="string"?j2.model:X.modelID)})(),route:"oauth",correlation:l},t=await K.requestOptions?.(a)??{};W(),u=await C$(u,{...t,...o?{identity:o}:{},sessionId:X.sessionID});let Q2=C2(u);Y2=z2(Q2)?Q2:null}H$(q,e,{body:Y2,...o?{identity:o}:{}})}else{if(u!==void 0&&s)u=x1(u);q.delete("authorization"),q.delete("x-api-key");for(let[o,Y2]of Object.entries(O.apiHeaders??{}))if(Y2===null)q.delete(o);else q.set(o,Y2);if(u!==void 0&&s&&!q.has("content-type"))q.set("content-type","application/json");let e=q.get("anthropic-beta");if(e!==null){let o=S1(e);if(o)q.set("anthropic-beta",o);else q.delete("anthropic-beta")}}}catch(e){let o=F1(e);if(!o)throw e;throw T.set(R,o.check),L?.warn("refused an Anthropic request locally; nothing was sent",{check:o.check}),o}let $2=u!==void 0?C2(u):void 0;if(await K.admitRequest?.({...E(A,R),modelID:X2(z2($2)&&typeof $2.model==="string"?$2.model:X.modelID)}),Z$(q),u!==void 0)q.delete("content-length");W(),x(R,O,z2($2)&&$2.stream===!0?"event-stream":"http",q);let K2=U$(U.url,O.baseURL!==void 0?{baseURL:O.baseURL}:{}).url?.toString()??U.url;if(O.dispatch?.kind==="http-relay"){let e=u??"";q.delete("x-relay-token");let o={protocol:1,type:"request",affinity:X.sessionID,upstream:{url:K2,method:U.method,headers:Object.fromEntries(q)},mode:"full_sync",revision:1,body:e,next_hash:`sha256:${C1("sha256").update(e).digest("hex")}`};return new Request(O.dispatch.url,{method:"POST",headers:{"content-type":"application/json","x-relay-token":O.dispatch.token},redirect:"error",signal:U.signal,body:JSON.stringify(o)})}return new Request(K2,{method:U.method,headers:q,redirect:U.redirect,signal:U.signal,...u!==void 0?{body:u}:{}})};return{adapter:{providerID:L2,chooseAccount:(X)=>B(X,async()=>{let W=await K.chooseAccount(X);if(!W)throw G(X);return W}),accountHeaders:g,rewriteRequest:d,rewriteHandshakeURL(){throw new V2},rewriteResponse({response:X,attempt:W}){let U=W.data;if(U&&!c(X.headers,U)){if(X.status===401)return Q(U),X.body?.cancel().catch(()=>{}),Response.json({type:"error",error:{type:"api_error",message:"Relay authentication failed before Anthropic received the request"}},{status:502});return v(U,X)}let A=v(U,X);if(U?.route!=="oauth"||!A.body)return n(U,A);let R={...E(W,U),status:X.status},O=K.responseOptions?.(R)??{},q=(X.headers.get("content-type")??"").includes("application/json");return n(U,L$(A,{...O,laneStartOAuthServed:!0,...q?{responseMode:"json"}:{}}))},quotaFromHeaders(X,W,U){let A=U.data;if(!A||!c(X,A))return;return K.quotaFromHeaders?.(X,{...E(U,A),status:W})},async limitFromResponse({status:X,headers:W,body:U,attempt:A}){let R=A.data;if(!R)return;if(!c(W,R))return K.limitFromRelayFailure?.({...E(A,R),status:X});if(Y.set(R,`provider responded with HTTP ${X}`),!K.limitFromResponse)return;let O=r.get(W)===R,q=_(R);return K.limitFromResponse({...E(A,R),status:X,headers:W,body:async()=>O?await U():q.redactText(await U())})},inspectEvent({data:X,event:W,attempt:U}){let A=C2(X);if(!z2(A))return;let R=typeof A.type==="string"?A.type:W;if(R==="content_block_start"||R==="content_block_delta")return{outputStarted:!0};if(R==="message_stop")return{done:!0};if(R!=="error")return;let O=U.data,q=_(O),l=z2(A.error)?A.error:{},u=typeof l.type!=="string"?void 0:K$.has(l.type)?l.type:q.redactText(l.type),s=typeof l.message==="string"?q.redactText(l.message):void 0;if(O?.dispatch==="http-relay"&&F.get(O)===!1)return;let $2=O?K.limitFromStreamError?.({...E(U,O),errorType:u,message:s}):void 0,K2={error:[u??"error",s].filter(Boolean).join(": ").slice(0,P1),...$2?{limit:$2}:{}};if(O&&K2.error)Y.set(O,K2.error);return K2},limitFromError(X,W){let U=W.data;if(!U||T.has(U))return;let A={type:K$.has(X.type)?X.type:"provider_error",message:Y.get(U)??"provider request failed",...X.status!==void 0?{status:X.status}:{}};if(Q(U),U.dispatch==="http-relay"&&F.get(U)===!1)return;return K.limitFromHostError?.(A,E(W,U))},async onAttemptEnd(X,W){let U=X.data;if(!U)return;M.delete(U);let A=W.error?.reason;if(A==="cancelled"||A==="abandoned"||A===void 0&&(W.status===void 0||W.status<400))Q(U);let R=T.get(U),{status:O,...q}=W,l=K.onAttemptEnd?.(E(X,U),{...q,...O!==void 0&&(U.dispatch!=="http-relay"||F.get(U)===!0)?{status:O}:{},...R!==void 0?{localRefusal:{check:R}}:{}});if(await A1(l,N)==="timed-out")L?.warn("the account source did not finish recording a send",{timeoutMs:N})}},dispose(){i=!0;for(let[X,W]of j){for(let U of W)U.revoked=!0;K.forgetSession?.(X)}j.clear(),M.clear();for(let X of[...V.keys()])Q(X)},forgetSession(X){for(let W of j.get(X)??[])W.revoked=!0;j.delete(X);for(let[W,U]of M)if(U.sessionID===X)M.delete(W);for(let[W,U]of[...V])if(U.sessionID===X)Q(W);K.forgetSession?.(X)},get pendingSendCount(){return M.size},get heldCredentialCount(){let X=0;for(let W of M.values())if(W.oauth)X++;return X},get heldRedactorCount(){return V.size},get operationsInProgress(){let X=0;for(let W of j.values())X+=W.size;return X}}}async function P$(Z,K,L){let J=E2(K),N=[],M=async(Q,x,y)=>{let D=await Z.session.hook(Q,x,y);return N.push(D),D},T=new AbortController,F;try{F=await f2({session:{hook:M},event:Z.event},J.adapter,{logger:K.log,gateOnPlaceholder:L})}catch(Q){throw J.dispose(),await Promise.allSettled(N.map((x)=>x.dispose())),Q}let V=(Q)=>{J.forgetSession(Q),F.forgetSession(Q)},Y=Z.event,H=Y?(async()=>{try{for await(let Q of Y.subscribe({signal:T.signal}))if(Q.type==="session.deleted")V(Q.data.sessionID)}catch(Q){if(!T.signal.aborted)K.log?.warn("stopped listening for session deletion",{error:Q instanceof Error?Q.name:"unknown"})}})():Promise.resolve(),_;return{installation:F,forgetSession:V,dispose(){if(_)return _;return J.dispose(),T.abort(),_=(async()=>{await F.dispose(),await H})(),_}}}function F$(Z,K){let L=new AbortController,J,N=!1,M=async()=>{let V=await Z.read();if(L.signal.throwIfAborted(),V.policyStorage.relay?.enabled===!0&&V.policyStorage.relay.transport!=="http")return;let Y=V,H=A2(Y.policyStorage);for(let _ of Y.accounts){if(L.signal.aborted)return;if(!_.enabled||_.type!=="oauth")continue;if(Y.policyStorage.quota?.enabled!==!1&&Date.now()-x2(_.quota)>=H)await Z.fetchQuota(_.id,K,L.signal).catch(()=>{});if(!T$(_.profile)&&!L.signal.aborted)await Z.fetchProfile(_.id,K,L.signal).catch(()=>{})}},T=()=>{if(N||J)return J;return J=M().catch(()=>{if(!L.signal.aborted)S2.debug("opencode2","native background readings did not complete")}).finally(()=>{J=void 0}),J},F=Z.vault.watch({intervalMs:60000,onRefresh:T,shouldRefresh:async()=>{let V=await Z.read();return V.policyStorage.relay?.enabled!==!0||V.policyStorage.relay.transport==="http"}});return F.ready.catch(()=>{}),{async dispose(){N=!0,F.close(),L.abort(),await J}}}var u2=(Z)=>Z!==null&&typeof Z==="object"&&!Array.isArray(Z)?Z:{};function D$(Z){let{runtime:K,source:L}=Z,J=new Map,N=!1,M=async(Y,H)=>{await K.updateSettings((_)=>({..._,[Y]:{...u2(_[Y]),...H}}))},T=()=>({ok:!0,text:"Native Claude settings updated."}),F=async(Y,H)=>{if(N)throw Error("Native menu is closed");switch(H.signal?.throwIfAborted(),Y.action){case"enable":case"disable":return await K.setEnabled(Y.values.id,Y.action==="enable"),T();case"remove":return await K.remove(Y.values.id),T();case"move-up":case"move-down":{let Q=(await K.read()).accounts.map((i)=>i.id),x=Q.indexOf(Y.values.id),y=x+(Y.action==="move-up"?-1:1);if(x<0||y<0||y>=Q.length)return{ok:!1,text:"Account cannot move in that direction."};let D=Q[x],v=Q[y];if(D===void 0||v===void 0)return{ok:!1,text:"Account order changed."};return Q[x]=v,Q[y]=D,await K.reorder(Q),T()}case"add-apikey":return await K.addApi(Y.values),{ok:!0,text:"API route stored in the native account pool."};case"add-oauth-start":{let _=new AbortController;J.get(Y.sessionId)?.active.abort();let Q={active:_,auth:void 0};J.set(Y.sessionId,Q);let x=await R2("max");if(N||_.signal.aborted||H.signal?.aborted)return{ok:!1,text:"Sign-in cancelled."};return Q.auth=x,{ok:!0,text:`Open ${x.url} and paste the returned code using Finish OAuth sign-in.`}}case"add-oauth-finish":{let _=J.get(Y.sessionId);if(!_?.auth)return{ok:!1,text:"Start OAuth sign-in in this session first."};let Q=await q2(Y.values.code,_.auth.verifier,_.auth.redirectUri,_.auth.state);if(_.active.signal.throwIfAborted(),H.signal?.throwIfAborted(),N||Q.type!=="success")return{ok:!1,text:"OAuth sign-in did not complete."};if(await K.loginOAuth({routeId:crypto.randomUUID(),credential:Q,label:Y.values.label}),_.active.signal.throwIfAborted(),H.signal?.throwIfAborted(),N)return{ok:!1,text:"Sign-in cancelled."};return J.delete(Y.sessionId),{ok:!0,text:"OAuth account stored in the native account pool."}}case"reset-backoff":{let _=await K.read();for(let Q of _.accounts){if(H.signal?.throwIfAborted(),Q.type!=="oauth")continue;let x=Q.source==="vault"?await K.authorizeVault(Q.id,H.signal):await K.captureLocalSubject(Q.id);await K.resetBackoff(Q.id,x)}return T()}case"enrollment-reset":{let _=await S$(E$("opencode"),O$);return{ok:_==="reset",text:_==="reset"?"Terminal enrollment state reset. Run offline setup to reconnect.":"Only terminal enrollment state may be reset; active enrollment was left unchanged."}}case"quota-refresh":{let Q=(await K.read()).accounts.filter((D)=>D.type==="oauth"&&D.enabled),x=await Promise.allSettled(Q.map((D)=>K.fetchQuota(D.id,void 0,H.signal)));return{ok:x.every((D)=>D.status==="fulfilled"),text:`${x.filter((D)=>D.status==="fulfilled").length}/${Q.length} native quota readings refreshed.`}}case"routing-reset":return await L.resetRouting(Y.sessionId),T();case"routing-mode":return await M("routing",{mode:Y.values.mode}),T();case"killswitch-on":case"killswitch-off":return await M("killswitch",{enabled:Y.action==="killswitch-on"}),T();case"killswitch-set":return await K.updateSettings((_)=>{let Q=u2(_.killswitch),x={...u2(Q.accounts)},y=Q.main;for(let D of Y.values.entries){let v={five_hour:D.fh,seven_day:D.sd,...D.scoped!==void 0?{scoped:D.scoped}:{}};if(D.account==="main"||D.account==="all")y=v;if(D.account==="all")for(let i of Object.keys(x))x[i]=v;else if(D.account!=="main")x[D.account]=v}return{..._,killswitch:{...Q,main:y,accounts:x}}}),T();case"cache-on":case"cache-off":return await M("claudeCache",{enabled:Y.action==="cache-on"}),T();case"cache-mode":return await M("claudeCache",{mode:Y.values.mode}),T();case"cachekeep-always":return await M("cacheKeep",{enabled:!0,always:!0}),T();case"cachekeep-off":return await M("cacheKeep",{enabled:!1}),T();case"cachekeep-window":return await M("cacheKeep",{enabled:!0,always:!1,startHour:Y.values.startHour,endHour:Y.values.endHour}),T();case"cachekeep-subagents":return await M("cacheKeep",{subagents:Y.values.enabled==="on"}),T();case"dump-on":case"dump-off":return await M("dump",{enabled:Y.action==="dump-on"}),T();case"logging-level":return await M("logging",{level:Y.values.level}),T();case"fast-on":case"fast-off":return await M("claudeFast",{enabled:Y.action==="fast-on"}),T();case"prime-on":case"prime-off":return await M("prime",{enabled:Y.action==="prime-on"}),T();case"start-fire":return await V(Y.sessionId),{ok:!0,text:"Claude lane start queued in this session."}}},V=(Y)=>Z.start(Y,k2);return{dispatch:F,async readStatus(Y){let H=await K.read();if(Y==="account")return H.accounts.map((Q)=>`${Q.id}${Q.label?` (${Q.label})`:""}: ${Q.type}, ${Q.source}, ${Q.enabled?"enabled":"disabled"}${Q.state?`, ${A$(Q)}`:""}${Q.accountIdentity?`, ${Q.accountIdentity}`:""}`).join(`
4
+ `)||"No native Claude accounts.";if(Y==="quota")return k$({accounts:H.accounts.filter((Q)=>Q.type==="oauth").map((Q)=>({name:Q.label??Q.id,role:Q.id==="main"?"main":"fallback",enabled:Q.enabled,quota:Q.quota,tierLabel:x$(Q.profile),lastRefreshedAt:Q.lastRefreshedAt,error:Q.lastQuotaRefreshError?.message}))}).replace(/Usage:[^\n]*/,"Use /claude to refresh native quota readings.");if(Y==="prime")return q$({enabled:H.policyStorage.prime?.enabled===!0,accounts:R$(H.policyStorage)}).replace(/Usage:[^\n]*/,"Use /claude to change Prime settings.");let _={routing:"routing",killswitch:"killswitch",cache:"claudeCache",cachekeep:"cacheKeep",dump:"dump",logging:"logging",fast:"claudeFast",prime:"prime"};return JSON.stringify(H.settings[_[Y]]??{})},forgetSession(Y){J.get(Y)?.active.abort(),J.delete(Y)},close(){N=!0;for(let Y of J.values())Y.active.abort();J.clear()}}}function g$(){let Z=new Map;return{install:(L)=>L.model.transform((J)=>{Z.clear();for(let N of J.list("anthropic")){if(Z.set(String(N.id),String(N.modelID)),!(b$(N.modelID)||I$(N.modelID)||w$(N.modelID)||y$(N.modelID)))continue;J.update("anthropic",String(N.id),(M)=>{let T=["low","medium","high","xhigh","max"],F=M.variants.filter((V)=>!T.some((Y)=>Y===String(V.id)));M.variants=[...F,...T.map((V)=>({id:V,settings:{effort:V,thinking:{type:"adaptive",display:"summarized"}}}))]})}}),modelId:(L)=>Z.get(L)??L}}function f$(Z){return Z.get("authorization")?.match(/^Bearer ([^\s]+)$/i)?.[1]??Z.get("x-api-key")??void 0}var v$=(Z)=>Z!==null&&typeof Z==="object"&&!Array.isArray(Z)?Z:{};function m$(Z){let{runtime:K,source:L}=Z,J=new AbortController,N=new Set,M=(V)=>({providerID:"anthropic",modelID:p2().model,sessionID:`oc2-prime:${V}`,agent:"prime",kind:"generate"}),T=async(V)=>{let Y=M(V),H=E2({source:L}),_=performance.now();try{for(let Q=0;Q<3;Q++){if(J.signal.throwIfAborted(),(await K.read()).policyStorage.prime?.enabled!==!0)throw Error("Native Prime is disabled");let y=await H.adapter.accountHeaders({...Y,accountId:V});if(!("headers"in y)||typeof y.headers!=="object"||y.headers===null||typeof y.attempt!=="object"||y.attempt===null)throw Error("Native Prime authorization refused");let D={...Y,accountId:V,attemptId:crypto.randomUUID(),transport:"http",data:y.attempt},v,i=!1,r=!1,n=(c)=>{r=!0,c.body?.cancel().catch(()=>{})};try{let c=await H.adapter.rewriteRequest?.({...Y,accountId:V,attempt:D,request:new Request("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(p2()),signal:J.signal})});if(!c)throw Error("Native Prime rewrite refused");let G=new Headers(c.headers);for(let[p,I]of Object.entries(y.headers))if(I===null)G.delete(p);else G.set(p,I);let j=new Request(c,{headers:G}),B=await(Z.fetch??fetch)(j),S=await H.adapter.rewriteResponse?.({...Y,accountId:V,request:j,response:B,attempt:D})??B;v=S.status,H.adapter.quotaFromHeaders?.(S.headers,S.status,D);let E=S.ok?void 0:await H.adapter.limitFromResponse?.({status:S.status,headers:S.headers,body:()=>S.clone().text(),attempt:D});if(E&&/^(vault-newer|local-newer|relay-direct):/.test(E.reason)&&Q<2){if(n(S),await L.chooseAccount({...Y,rerouteFrom:{accountId:V,limit:E}})!==V)throw Error("Native Prime retry changed account");continue}if(!S.ok)return n(S),{ok:!1,status:v,ms:performance.now()-_,error:"Native Prime upstream refused the request"};let g=v$(await S.json()),h=v$(g.usage),d={inputTokens:typeof h.input_tokens==="number"?h.input_tokens:void 0,outputTokens:typeof h.output_tokens==="number"?h.output_tokens:void 0};if(D.data?.dispatch==="http-relay"&&!/^req_[A-Za-z0-9_-]+$/.test(S.headers.get("request-id")??""))throw Error("Native Prime relay response has no upstream provenance");if(i=await L.recordPrime(y.attempt.provenance,d),!i)throw Error("Native Prime counter attribution was superseded");return{ok:!0,status:v,ms:performance.now()-_,usage:d}}finally{await H.adapter.onAttemptEnd?.(D,{status:v,outputStarted:!1,...i?{}:{error:{reason:r?"cancelled":"failed"}}})}}return{ok:!1,error:"Native Prime retry budget exhausted"}}catch{return{ok:!1,error:"Native Prime was not completed",ms:performance.now()-_}}finally{H.dispose()}},F=new h$({storagePath:Z.paths.legacyConfig,loadStorage:async()=>(await K.read()).policyStorage,async getAccountFingerprint(V){let Y=await K.read(),H=Y.accounts.find((Q)=>Q.id===V);if(!H?.enabled||H.type!=="oauth")return;if(Y.policyStorage.relay?.enabled===!0&&Y.policyStorage.relay.transport!=="http")return;if(H.source==="vault"){let Q=await K.authorizeVault(V,J.signal);return K.getOrCreateAuthLineage(V,Q)}let _=await K.authorizeLocal(V,{signal:J.signal});return _.status==="usable"?K.getOrCreateAuthLineage(V,_.subject):void 0},async refreshQuota(V){let Y=await K.read();if(Y.policyStorage.relay?.enabled===!0&&Y.policyStorage.relay.transport!=="http")throw Error("WebSocket relay is unsupported on OpenCode 2");return{quota:await K.fetchQuota(V,Z.fetch,J.signal),fresh:!0}},sendPrime(V){let Y=T(V);return N.add(Y),Y.finally(()=>N.delete(Y)),Y},async recordSuccess(V){let Y=(await K.read()).accounts.find((H)=>H.id===V);if(!Y?.prime)throw Error("Native Prime counters are unavailable");return Y.prime}});return F.start(),{manager:F,async dispose(){F.stop(),J.abort(),await Promise.allSettled(N)}}}var d2=(Z)=>["five_hour","seven_day"].some((K)=>(Z?.[K]?.remainingPercent??1)<=0);function e$(Z){let{runtime:K}=Z,L=o$("native-auth"),J=new Map,N=(G)=>{let j=G.routingPath??c$(Z.paths.legacyConfig),B=J.get(j);if(!B)B=new i$({path:j,vaultSeed:G.routingSeed}),J.set(j,B);return B.setVaultSeed(G.routingSeed),B},M=new WeakMap,T=new Map,F=new Map,V=new Map,Y=new WeakSet,H=!1,_=()=>{while(T.size>512){let G=T.keys().next();if(!G.done)T.delete(G.value)}},Q=(G,j)=>JSON.stringify([G.sessionID,G.kind,G.modelID,j]),x=(G)=>{if(H)throw Error("Native Anthropic source is closed");let j=V.get(G.sessionID);if(!j){j=new AbortController,V.set(G.sessionID,j);while(V.size>512){let B=V.keys().next();if(!B.done)n.forgetSession?.(B.value)}}return j},y=(G,j,B)=>G.enabled&&(G.type==="api"||P2(G,j,X2(B)).status==="allowed"),D=async(G,j,B,S)=>{let E=await K.read();S.signal.throwIfAborted(),v(E);let g=E.accounts.find((h)=>h.id===G);if(!g||g.type!==B||!y(g,E,j))return!1;if(B==="api"){let h=E.accounts.find((d)=>d.id==="main"&&d.type==="oauth");return!!h&&N2(h.quota,E.policyStorage)&&d2(h.quota)}return!0},v=(G)=>{let j=G.policyStorage.relay;if(j?.enabled===!0&&j.transport!=="http")throw new V2},i=async(G,j)=>{if(v(G),j||G.policyStorage.relay?.enabled!==!0)return{dispatch:{kind:"direct"},relayFallback:!1};let B=await K.getRelayConfig();if(!B)throw Error("request refused: native HTTP relay configuration is unavailable");if(B.transport!=="http")throw new V2;return{dispatch:{kind:"http-relay",url:B.url,token:B.token},relayFallback:B.fallbackToDirect}};async function r(G,j,B){if(G.kind==="local")await K.publishLocal(G.subject,B);else if(G.kind==="vault"&&j.receipt)await K.vault.publish(j.receipt,B);else if(G.kind==="api"&&B.lastUsed!==void 0)await K.publishApi(G.subject,{lastUsed:B.lastUsed})}let n={async chooseAccount(G){let j=x(G);Z.onOwnedRequest?.();let B=await K.read();j.signal.throwIfAborted(),v(B);let S=X2(await Z.resolveModelId?.(G)??G.modelID);if(j.signal.throwIfAborted(),B.mode==="claustrum")B=await r$(K,j.signal),j.signal.throwIfAborted();if(B.policyStorage.quota?.enabled!==!1){let I=!1;for(let X of B.accounts){if(!X.enabled||X.type!=="oauth")continue;if(p$(X.quota)?N2(X.quota,B.policyStorage,Date.now(),S):Date.now()-x2(X.quota)<A2(B.policyStorage))continue;try{await K.fetchQuota(X.id,Z.fetch,j.signal),I=!0}catch{j.signal.throwIfAborted()}}if(I)B=await K.read();j.signal.throwIfAborted()}let E=G.rerouteFrom?T.get(G.rerouteFrom.limit.reason):void 0;if(G.rerouteFrom&&/^(vault-newer|local-newer|relay-direct):/.test(G.rerouteFrom.limit.reason)&&!E)return;if(E&&G.rerouteFrom){T.delete(G.rerouteFrom.limit.reason);let I=B.accounts.find((U)=>U.id===E.accountId);if(!I||!y(I,B,S))return;let X=Q(G,E.accountId),W=F.get(X)??[];return W.push(E),F.set(X,W),E.accountId}let g=[];for(let I of B.accounts){if(I.type!=="oauth"||!y(I,B,S))continue;if(I.source==="local"){let X=await K.authorizeLocal(I.id,{signal:j.signal,policy:(W,U)=>P2(W,U,S)});if(j.signal.throwIfAborted(),X.status!=="usable")continue}g.push(I)}let h=g.filter((I)=>I.id!==G.rerouteFrom?.accountId);if(c2(B.policyStorage)==="sticky-balanced"){let I=h.map((W,U)=>({accountId:W.id,order:U,quota:W.quota??{kind:"unknown"}})),X=await N(B).resolve({sessionId:G.sessionID,family:d$(S),modelId:S,affinityModelId:G.modelID,candidates:I,retainAccountIds:new Set(h.map((W)=>W.id)),...B.mode==="claustrum"?{accountIdentities:new Map(B.accounts.flatMap((W)=>W.accountIdentity?[[W.id,W.accountIdentity]]:[]))}:{},storage:B.policyStorage,inputBytes:1,preferredAccountId:G.previousAccountId});if(j.signal.throwIfAborted(),X)return X.accountId}else{let X=c2(B.policyStorage)==="fallback-first"?[...h.filter((W)=>W.id!=="main"),...h.filter((W)=>W.id==="main")]:[...h.filter((W)=>W.id==="main"),...h.filter((W)=>W.id!=="main")];if(X[0])return X[0].id}if(B.mode==="claustrum")throw new n$;let d=B.accounts.find((I)=>I.id==="main"&&I.type==="oauth");if(!d)return;let p=d.quota;if(G.rerouteFrom?.limit.status===429||!N2(p,B.policyStorage))try{p=await K.fetchQuota("main",Z.fetch,j.signal)}catch{return}if(j.signal.throwIfAborted(),!d2(p))return;return B.accounts.find((I)=>I.type==="api"&&I.enabled&&I.id!==G.rerouteFrom?.accountId)?.id},async authorizeAccount(G,j){let B=x(G),S=await K.read();B.signal.throwIfAborted(),v(S);let E=X2(await Z.resolveModelId?.(G)??G.modelID);B.signal.throwIfAborted();let g=S.accounts.find((O)=>O.id===j);if(!g||!y(g,S,E))return;let h=Q(G,j),d=F.get(h),p=d?.shift();if(d?.length===0)F.delete(h);let{dispatch:I,relayFallback:X}=await i(S,p?.direct===!0);if(B.signal.throwIfAborted(),p?.auth){if(!await D(j,E,p.auth.route,B))return;let O=M.get(p.auth.provenance);if(O?.receipt?.expiresAtMs!==void 0&&O.receipt.expiresAtMs!==null&&O.receipt.expiresAtMs<Date.now()+300000)return;if(O)M.set(p.auth.provenance,{...O,scope:{...G,modelID:E},account:g,active:B,relayFallback:X});return{...p.auth,dispatch:I}}let W={scope:{...G,modelID:E},active:B,account:g,retry:p?.retry??!1,relayFallback:X,quota:g.quota};if(g.type==="api"){let O=S.accounts.find((s)=>s.id==="main"&&s.type==="oauth");if(!O||!N2(O.quota,S.policyStorage)||!d2(O.quota))return;let q=await K.authorizeApi(j,B.signal);if(B.signal.throwIfAborted(),!await D(j,E,"api",B))return;let l={kind:"api",subject:q.subject};return M.set(l,W),{route:"api",headers:q.authHeader==="authorization-bearer"?{authorization:`Bearer ${q.apiKey}`}:{"x-api-key":q.apiKey},baseURL:q.baseURL,provenance:l,dispatch:I}}if(g.source==="vault"){let O=await K.authorizeVault(j,B.signal);if(B.signal.throwIfAborted(),!await D(j,E,"oauth",B))return;let q={kind:"vault",credentialId:O.credentialId,recordVersion:O.recordVersion};M.set(q,{...W,receipt:O});let l=O.assertedAccountIdentity;if(!l)return;return{route:"oauth",accessToken:O.accessToken,provenance:q,dispatch:I,identity:_2(l,l)}}let U=await K.authorizeLocal(j,{signal:B.signal,policy:(O,q)=>P2(O,q,E)});if(B.signal.throwIfAborted(),U.status!=="usable")return;if(!await D(j,E,"oauth",B))return;let A={kind:"local",subject:U.subject};M.set(A,{...W,access:U.access});let R=U.subject.binding.identity;return{route:"oauth",accessToken:U.access,provenance:A,dispatch:I,identity:_2(R,R)}},async requestOptions(G){let j=x(G),B=await K.read();j.signal.throwIfAborted();let S=B.accounts.find((g)=>g.id===G.accountId);if(!S||!y(S,B,G.modelID))throw Error("request refused: native account is ineligible for this model");let E=M.get(G.provenance);if(E)M.set(G.provenance,{...E,scope:{...E.scope,modelID:G.modelID}});return Z.requestOptions(G,B)},async admitRequest(G){let j=M.get(G.provenance);if(!j||!await D(G.accountId,G.modelID,G.route,j.active))throw Error("request refused: native account policy changed before dispatch");M.set(G.provenance,{...j,scope:{...j.scope,modelID:G.modelID}})},responseOptions(G){return Z.responseOptions?.({...G,modelID:M.get(G.provenance)?.scope.modelID??G.modelID})},quotaFromHeaders(G,j){let B=M.get(j.provenance),S=t$(G);if(S)Z.onRequestId?.(j,S);if(!B||j.route!=="oauth"||!s$(G))return;let E=j.provenance.kind==="local"?j.provenance.subject.binding.identity:B.receipt?.assertedAccountIdentity,g={...a$(G),...E?{accountIdentity:E}:{}};B.quota=l$(B.quota,g);let h=r(j.provenance,B,{quota:B.quota});return c.set(j.provenance,h),h.catch(()=>{}),g},async limitFromResponse(G){let j=M.get(G.provenance);if(!j)return;if(G.status===401&&j.receipt){if(!Y.has(j.receipt))Y.add(j.receipt),await K.vault.reportFailure(j.receipt,401,G.dispatch==="http-relay"?"relay_status_field":"direct");if(j.retry||j.active.signal.aborted)return;let S=j.active,E=await K.vault.prepareRetry(j.receipt,S.signal);if(S.signal.throwIfAborted(),!E.retry)return;let g=E.receipt,h=g.assertedAccountIdentity;if(!h)return;let d={kind:"vault",credentialId:g.credentialId,recordVersion:g.recordVersion};M.set(d,{...j,receipt:g,retry:!0});let p=`vault-newer:${G.attemptId}`;return T.set(p,{sessionID:G.sessionID,accountId:G.accountId,retry:!0,auth:{route:"oauth",accessToken:g.accessToken,provenance:d,identity:_2(h,h)}}),_(),{reason:p,status:401}}if(G.status===401&&G.provenance.kind==="local"&&j.access&&!j.retry){if(j.active.signal.aborted)return;let S=j.active,E=await K.authorizeLocal(G.accountId,{rejectedAccessToken:j.access,signal:S.signal,policy:(p,I)=>P2(p,I,j.scope.modelID)});if(S.signal.throwIfAborted(),E.status!=="usable"||E.access===j.access)return;let g={kind:"local",subject:E.subject};M.set(g,{...j,access:E.access,retry:!0});let h=E.subject.binding.identity,d=`local-newer:${G.attemptId}`;return T.set(d,{sessionID:G.sessionID,accountId:G.accountId,retry:!0,auth:{route:"oauth",accessToken:E.access,provenance:g,identity:_2(h,h)}}),_(),{reason:d,status:401}}let B=await K.read();if(u$(G.status,B.policyStorage))return{reason:`provider-${G.status}`,status:G.status};return},limitFromRelayFailure(G){let j=M.get(G.provenance);if(!j?.relayFallback||j.active.signal.aborted||!(G.status===401||G.status>=500))return;let B=`relay-direct:${G.attemptId}`;return T.set(B,{sessionID:G.sessionID,accountId:G.accountId,direct:!0,retry:!1}),_(),{reason:B}},limitFromStreamError(G){return G.errorType==="rate_limit_error"?{reason:"provider-rate-limit",status:429}:void 0},limitFromHostError(G,j){let B=M.get(j.provenance);if(j.dispatch==="http-relay"&&B?.relayFallback&&!B.active.signal.aborted&&G.status===void 0){let S=`relay-direct:${j.attemptId}`;return T.set(S,{sessionID:j.sessionID,accountId:j.accountId,direct:!0,retry:!1}),_(),{reason:S}}return},async onAttemptEnd(G,j){let B=M.get(G.provenance);if(!B)return;try{if(await c.get(G.provenance),j.status===401&&B.receipt&&!Y.has(B.receipt))Y.add(B.receipt),await K.vault.reportFailure(B.receipt,401,G.dispatch==="http-relay"?"relay_status_field":"direct");if(!j.localRefusal&&j.status!==void 0)L.publish(()=>r(G.provenance,B,{lastUsed:Date.now()}))}finally{M.delete(G.provenance),c.delete(G.provenance)}},forgetSession(G){V.get(G)?.abort(),V.delete(G);for(let[j,B]of T)if(B.sessionID===G)T.delete(j);for(let[j,B]of F)if(B[0]?.sessionID===G)F.delete(j);Z.onForgetSession?.(G)},resetRouting:async(G)=>N(await K.read()).clear(G),async recordPrime(G,j){let B=M.get(G);if(!B||B.active.signal.aborted)return!1;if(G.kind==="local")return K.incrementPrimeUsage(B.account.id,G.subject,j);if(G.kind==="vault"&&B.receipt)return K.incrementPrimeUsage(B.account.id,B.receipt,j);return!1},close(){H=!0;for(let G of V.values())G.abort();return V.clear(),F.clear(),T.clear(),L.drain()}},c=new WeakMap;return n}function Z1(){let Z=new $1,K=new Map,L=new Map,J=new Map,N=new Set,M=new Set,T=new Map,F=(V)=>{while(V.size>512){let Y=V.keys().next();if(!Y.done)V.delete(Y.value)}};return{async install(V){let Y=[];try{Y.push(await V.session.hook("context",(H)=>{let _=H.messages.map((x)=>{return{info:{id:x.id,sessionID:H.sessionID,role:x.role,agent:H.agent,model:{providerID:H.model.providerID,modelID:H.model.id}},parts:x.content.map((y)=>({type:y.type,...y.type==="text"?{text:y.text}:{}}))}});Z.observeMessages(_);let Q=H.messages.findLast((x)=>x.role==="user"&&x.id);if(Q?.id)K.set(H.sessionID,Q.id);if(Q?.content.some((x)=>x.type==="text"&&x.text===k2))N.add(H.sessionID);else N.delete(H.sessionID);F(K)},{providerID:"anthropic"})),Y.push(await V.session.hook("model.request",(H)=>{if(H.kind!=="primary")return;let _=K.get(H.sessionID);if(!_)return;if(Z.markHeaders({sessionId:H.sessionID,messageId:_,agent:H.agent,headers:H.headers}),N.has(H.sessionID))H.headers[M2]="1"},{providerID:"anthropic"}))}catch(H){throw await Promise.allSettled(Y.map((_)=>_.dispose())),H}return{dispose:async()=>{await Promise.all(Y.map((H)=>H.dispose()))}}},requestOptions(V,Y){let H=Z.resolveHeader(V.correlation[O2]);if(H)L.set(V.attemptId,H),F(L);T.set(V.attemptId,V.sessionID),F(T);let _=V.correlation[M2]==="1";if(_)M.add(V.attemptId);return{cache1hEnabled:V.agent!=="compaction"&&V.agent!=="title"&&(Y.policyStorage.claudeCache?.enabled??!0),cache1hMode:Y.policyStorage.claudeCache?.mode??"explicit",fastModeEnabled:Y.policyStorage.claudeFast?.enabled===!0,thinkingPrefixMismatchBehavior:Y.policyStorage.thinkingBinding?.prefixMismatchBehavior,midConversationEffortEnabled:!1,serverSideFallbackEnabled:K1(process.env.OPENCODE_ANTHROPIC_AUTH_CONTENT_FILTER_FALLBACK)==="server",laneStart:_,billingLineage:H?{promptId:H.promptId,previousRequestId:H.previousRequestId}:void 0,cacheDiagnosticsPreviousMessageId:J.get(V.sessionID)}},responseOptions(V){return{serverSideFallbackModel:X2(V.modelID),laneStart:M.has(V.attemptId),onMessageStart(Y){if(V.kind==="primary"&&typeof Y.id==="string")J.set(V.sessionID,Y.id),F(J)},onStreamEnd(){L.delete(V.attemptId),M.delete(V.attemptId),T.delete(V.attemptId)}}},onRequestId(V,Y){Z.commit(L.get(V.attemptId),Y)},forgetSession(V){Z.clearSession(V),K.delete(V),J.delete(V),N.delete(V);for(let[Y,H]of T)if(H===V)L.delete(Y),M.delete(Y),T.delete(Y)}}}var D2="cortexkit-anthropic-auth",R1='This OpenCode is enrolled in the Claude vault and uses only vault accounts. Choose "Claude vault accounts" instead; no local account was changed.',q1="This OpenCode is not enrolled in the Claude vault. Enroll it first, or sign in with Claude Pro / Max.",k1="The Claude vault enrollment could not be read; repair it and retry. Nothing was changed.";function D1(Z){let K=Z.authorize??R2,L=Z.exchange??q2,J=()=>{if(!Z.isActive())throw Error("Claude authentication setup is closed")},N=async()=>{let F;try{F=await Z.readMode()}catch{throw Error(k1)}return J(),F},M=async()=>{if(await N()!=="local")throw Error(R1)};return{integrationID:"anthropic",methods:[{method:{id:e2,type:"oauth",label:"Claude Pro / Max (native account pool)"},async authorize(){J(),await M();let F=await K("max");return J(),{mode:"code",url:F.url,instructions:"Paste the authorization code returned by Claude.",callback:async(V)=>{J();let Y=await L(V,F.verifier,F.redirectUri,F.state);if(!Z.isActive()||Y.type!=="success")throw Error("Claude sign-in did not complete");return{access:Y.access,refresh:Y.refresh,expires:Y.expires}}}}}],vault:{method:{id:$$,type:"oauth",label:"Claude vault accounts"},async activate(){if(J(),await N()!=="claustrum")throw Error(q1)}},async onLogin(F){J(),await M(),await Z.runtime.loginOAuth({routeId:"main",credential:F,replace:!0}),J()},label:"Claude native account pool"}}function b1(Z){return{readMode:()=>G1("opencode",Z),disconnectVault:()=>J1({host:"opencode",env:Z})}}function i2(Z={}){return{id:D2,setup:(K)=>j1(K,Z)}}async function j1(Z,K={}){let L=K.paths??await Y1(),J=X1({paths:L,host:"opencode",local:K.local,vault:K.vault}),N=b1(K.vault?.env??process.env),M=!0,T=Z1(),F=g$(),V,Y,H=e$({runtime:J,paths:L,fetch:K.fetch,requestOptions:T.requestOptions,responseOptions:T.responseOptions,onRequestId:T.onRequestId,onForgetSession:T.forgetSession,resolveModelId:async(v)=>F.modelId(v.modelID),onOwnedRequest:()=>{V??=F$(J,K.fetch),Y??=m$({runtime:J,paths:L,source:H,fetch:K.fetch})}}),_=D$({runtime:J,source:H,start:async(v,i)=>{await Z.session.synthetic({sessionID:v,text:i,description:"Claude lane start",resume:!0})}}),Q=[],x=await P$(Z,{source:H,log:{warn:(v,i)=>S2.warn("opencode2",v,i)}},{credential:f$}).catch((v)=>{throw _.close(),H.close(),J.close(),v}),y,D=()=>{if(y)return y;return M=!1,_.close(),H.close(),y=(async()=>{await Promise.allSettled([x.dispose(),V?.dispose(),Y?.dispose(),...Q.map((v)=>v.dispose())]),await H.close(),J.close()})(),y};try{Q.push(await T.install(Z)),Q.push(await F.install(Z)),Q.push(await y2(Z,D1({isActive:()=>M,readMode:N.readMode,runtime:J})));let v={host:"opencode",dispatch:_.dispatch,readStatus:(r)=>_.readStatus(r),readAccounts:()=>J.read(),readMode:N.readMode,disconnectVault:N.disconnectVault,interactive:!0},i=W1(v);return Q.push(await z1(Z,i,_)),D}catch(v){throw await D(),v}}var lK={id:D2,setup:i2().setup,server:B1};export{j1 as setupAnthropicAuth,lK as default,i2 as createAnthropicAuthPlugin,D2 as ANTHROPIC_AUTH_PLUGIN_ID};
@@ -0,0 +1,58 @@
1
+ import { authorize, exchange, type NativeAccountRuntime, type NativeAccountRuntimeOptions, type NativePoolPaths } from '@cortexkit/anthropic-auth-core';
2
+ import { type RegisterOpenCode2AuthMethodsOptions } from '@cortexkit/common-auth/opencode2';
3
+ import type { Plugin } from '@opencode/plugin';
4
+ export declare const ANTHROPIC_AUTH_PLUGIN_ID = "cortexkit-anthropic-auth";
5
+ /**
6
+ * The account source vault enrollment selects: 'local' serves accounts stored
7
+ * in this machine's account pool, 'claustrum' serves accounts from the
8
+ * Claustrum vault this OpenCode is enrolled in.
9
+ */
10
+ export type NativeEnrollmentMode = 'local' | 'claustrum';
11
+ export interface AnthropicAuthV2Options {
12
+ readonly paths?: NativePoolPaths;
13
+ readonly local?: NativeAccountRuntimeOptions['local'];
14
+ readonly vault?: NativeAccountRuntimeOptions['vault'];
15
+ readonly fetch?: typeof fetch;
16
+ }
17
+ /** The OAuth result a completed Claude Pro / Max sign-in hands to the pool. */
18
+ export interface ClaudeOAuthLogin {
19
+ readonly access: string;
20
+ readonly refresh: string;
21
+ readonly expires: number;
22
+ }
23
+ export declare const LOCAL_LOGIN_REFUSED_IN_VAULT = "This OpenCode is enrolled in the Claude vault and uses only vault accounts. Choose \"Claude vault accounts\" instead; no local account was changed.";
24
+ export declare const VAULT_ACTIVATION_REFUSED_LOCALLY = "This OpenCode is not enrolled in the Claude vault. Enroll it first, or sign in with Claude Pro / Max.";
25
+ export declare const ENROLLMENT_UNREADABLE = "The Claude vault enrollment could not be read; repair it and retry. Nothing was changed.";
26
+ export interface ClaudeLoginMethodsInput {
27
+ /** False once setup is disposed; every step refuses after that. */
28
+ readonly isActive: () => boolean;
29
+ readonly readMode: () => Promise<NativeEnrollmentMode>;
30
+ /** Verifies a completed sign-in's account and writes it to the local pool. */
31
+ readonly runtime: Pick<NativeAccountRuntime, 'loginOAuth'>;
32
+ readonly authorize?: typeof authorize;
33
+ readonly exchange?: typeof exchange;
34
+ }
35
+ /**
36
+ * Builds the two login methods OpenCode 2 offers for the anthropic provider:
37
+ * the Claude Pro / Max browser sign-in, which writes to the local account
38
+ * pool, and vault activation, which writes nothing locally. Vault enrollment
39
+ * alone decides which one works. When OpenCode is enrolled in the vault, the
40
+ * browser sign-in refuses before it opens a browser and again before it
41
+ * writes, and only vault activation succeeds. When it is not enrolled, vault
42
+ * activation refuses. An enrollment that cannot be read refuses both, since
43
+ * neither account source can then be shown to be the right one.
44
+ */
45
+ export declare function claudeLoginMethods(input: ClaudeLoginMethodsInput): RegisterOpenCode2AuthMethodsOptions<ClaudeOAuthLogin>;
46
+ /**
47
+ * OpenCode's vault enrollment callbacks for the login methods and the
48
+ * `claude` menu. Both use only the enrollment files that `env` names.
49
+ * Disconnecting ends this OpenCode's vault enrollment and never reads or
50
+ * changes OpenCode's own stored sign-ins.
51
+ */
52
+ export declare function nativeEnrollmentCallbacks(env: NodeJS.ProcessEnv): {
53
+ readMode: () => Promise<NativeEnrollmentMode>;
54
+ disconnectVault: () => Promise<import("@cortexkit/anthropic-auth-core").NativeVaultDisconnectResult>;
55
+ };
56
+ export declare function createAnthropicAuthPlugin(options?: AnthropicAuthV2Options): Plugin.Plugin;
57
+ /** Install request hooks before credential transfer to the shared pool finishes; requests must refuse until that transfer commits, never reuse old host tokens. */
58
+ export declare function setupAnthropicAuth(ctx: Plugin.Context, options?: AnthropicAuthV2Options): Promise<Plugin.Cleanup>;