@cortexkit/opencode-anthropic-auth 2.2.7 → 2.3.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 (39) hide show
  1. package/dist/cli.js +43 -42
  2. package/dist/index-2jsr8wvj.js +43 -0
  3. package/dist/index-46e2gk3c.js +2 -0
  4. package/dist/{index-62x1p34p.js → index-71temqvq.js} +1 -1
  5. package/dist/{index-ppdrzs41.js → index-bcp23wwb.js} +1 -1
  6. package/dist/{index-hazrk5c3.js → index-c8ehrd0p.js} +1 -1
  7. package/dist/index-dpnhamzw.js +2 -0
  8. package/dist/{index-0kxy8k2c.js → index-m4dazzyf.js} +1 -1
  9. package/dist/{index-b1dvkp15.js → index-naff9h33.js} +1 -1
  10. package/dist/{index-6chd6jnr.js → index-sg0knfec.js} +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/oauth-destination.d.ts +35 -0
  13. package/dist/plugin-test-handles.d.ts +26 -0
  14. package/dist/rpc/port-file.js +1 -1
  15. package/dist/rpc/protocol.js +1 -1
  16. package/dist/rpc/rpc-client.js +1 -1
  17. package/dist/rpc/rpc-dir.js +1 -1
  18. package/dist/sidebar-state.d.ts +6 -3
  19. package/dist/sidebar-state.js +1 -1
  20. package/dist/tui/claude-sidebar.d.ts +58 -0
  21. package/dist/tui/menu-status.d.ts +70 -0
  22. package/dist/tui-preferences.js +2 -2
  23. package/dist/v2/adapter.d.ts +13 -8
  24. package/dist/v2/server.js +10 -10
  25. package/dist/v2/tui.d.ts +12 -0
  26. package/dist/v2/tui.js +4 -5
  27. package/package.json +2 -2
  28. package/src/sidebar-state.ts +55 -46
  29. package/src/tui/claude-sidebar.tsx +155 -15
  30. package/src/tui/entry.mjs +13 -0
  31. package/src/tui/menu-status.tsx +300 -0
  32. package/src/tui-compiled/sidebar-state.ts +55 -46
  33. package/src/tui-compiled/tui/claude-sidebar.tsx +112 -12
  34. package/src/tui-compiled/tui/menu-status.tsx +388 -0
  35. package/src/tui-compiled/tui-preferences.ts +32 -3
  36. package/src/tui-preferences.ts +32 -3
  37. package/dist/index-20d6rmjj.js +0 -2
  38. package/dist/index-cjjjgewq.js +0 -43
  39. package/dist/index-jvhs8sxv.js +0 -2
@@ -1,2 +1,2 @@
1
1
  var b="native-claude-oauth",f="Claude Pro / Max (native account pool)",j='In OpenCode, sign in to Anthropic with "Claude Pro / Max (native account pool)".',k="native-claude-vault";
2
- export{b as v,f as w,j as x,k as y};
2
+ export{b as w,f as x,j as y,k as z};
@@ -1,2 +1,2 @@
1
1
  import{existsSync as $,readFileSync as F}from"node:fs";import{homedir as Y}from"node:os";import{dirname as X,join as J,resolve as V}from"node:path";import{fileURLToPath as Z}from"node:url";var b="@cortexkit/opencode-anthropic-auth",G="@cortexkit/pi-anthropic-auth";function W(q=process.env,w=process.platform){return(w==="win32"?q.USERPROFILE||q.HOME:q.HOME)||Y()}function K(q=process.env,w=process.platform){let B=q.OPENCODE_CONFIG_DIR?.trim();if(B)return V(B);return J(q.XDG_CONFIG_HOME||J(W(q,w),".config"),"opencode")}function I(q=process.env){let w=q.XDG_DATA_HOME?.trim();if(w)return J(V(w),"opencode");return J(Y(),".local","share","opencode")}function M(q=process.env){return J(I(q),"auth.json")}function R(q=process.env,w=process.platform){let B=q.PI_CODING_AGENT_DIR?.trim()||q.PI_AGENT_DIR?.trim();if(B)return V(B);return J(W(q,w),".pi","agent")}function k(q=process.env){let w=q.PI_CODING_AGENT_DIR,B=W(q),z=w||J(B,".pi","agent");if(z==="~")z=B;else if(z.startsWith("~/")||process.platform==="win32"&&z.startsWith("~\\"))z=J(B,z.slice(2));if(z.startsWith("file://"))z=Z(z);return J(z,"auth.json")}async function x(){let q=X(Z(import.meta.url));for(let w=0;w<5;w++){let B=J(q,"package.json");if($(B))try{let Q=JSON.parse(F(B,"utf8"));if(typeof Q.version==="string"&&Q.version.trim())return Q.version.trim()}catch{}let z=X(q);if(z===q)break;q=z}return"1.22.0"}
2
- export{b as z,G as A,K as B,M as C,R as D,k as E,x as F};
2
+ export{b as A,G as B,K as C,M as D,R as E,k as F,x as G};
@@ -1,2 +1,2 @@
1
1
  var t=["claude-account","claude-cache","claude-cachekeep","claude-prime","claude-start","claude-quota","claude-dump","claude-fast","claude-routing","claude-killswitch","claude-logging"];
2
- export{t as q};
2
+ export{t as r};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{p as a}from"./index-cjjjgewq.js";import"./index-6chd6jnr.js";import"./index-hazrk5c3.js";import"./index-b1dvkp15.js";import"./index-20d6rmjj.js";import"./index-ppdrzs41.js";import"./index-62x1p34p.js";export{a as AnthropicAuthPlugin};
1
+ import{q as a}from"./index-2jsr8wvj.js";import"./index-sg0knfec.js";import"./index-c8ehrd0p.js";import"./index-naff9h33.js";import"./index-46e2gk3c.js";import"./index-bcp23wwb.js";import"./index-71temqvq.js";export{a as AnthropicAuthPlugin};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Test-only escape hatch for the OAuth destination rule.
3
+ *
4
+ * End-to-end suites run a real OpenCode process against a local mock of the
5
+ * Anthropic API, so they need OAuth sends to reach a loopback server. Setting
6
+ * this variable to that server's exact origin (for example
7
+ * `http://127.0.0.1:43123`) allows it in addition to api.anthropic.com. Only
8
+ * an `http://` or `https://` origin on 127.0.0.1, [::1] or localhost, with an
9
+ * explicit port and no user name, password, path, query or fragment, is
10
+ * accepted; any other value is ignored, so OAuth stays limited to
11
+ * api.anthropic.com. ANTHROPIC_BASE_URL never widens the rule. It is not a
12
+ * user setting and is deliberately left out of the public documentation.
13
+ */
14
+ export declare const TEST_OAUTH_LOOPBACK_ORIGIN_ENV = "ANTHROPIC_AUTH_TEST_OAUTH_LOOPBACK_ORIGIN";
15
+ /** The accepted loopback origin from TEST_OAUTH_LOOPBACK_ORIGIN_ENV, if any. */
16
+ export declare function testOAuthLoopbackOrigin(): string | undefined;
17
+ /**
18
+ * Throws AnthropicOAuthOriginError unless an OAuth token may be sent to
19
+ * `url`. Call it with the final URL, after rewriteUrl has applied any
20
+ * ANTHROPIC_BASE_URL or provider baseURL, so neither can redirect a token.
21
+ *
22
+ * ANTHROPIC_BASE_URL is not trusted either. OpenCode's release binaries are
23
+ * built with Bun's `.env` autoloading turned off, but OpenCode started with
24
+ * `bun run` (from source) loads a `.env` file from the working directory, so
25
+ * an opened repository could set the variable. An OAuth token therefore goes
26
+ * only to api.anthropic.com whatever the variable says.
27
+ */
28
+ export declare function requireOAuthDestination(url: string): URL;
29
+ /** True when an OAuth token may be sent to `url`. */
30
+ export declare function isAllowedOAuthDestination(url: string): boolean;
31
+ /**
32
+ * Fetch for OAuth sends: rechecks the destination on every call and refuses
33
+ * redirects.
34
+ */
35
+ export declare const fetchOAuth: typeof fetch;
@@ -0,0 +1,26 @@
1
+ import type { AccountStorage, acquireNativeAccountRuntime, CacheKeepManager, CustodyStatusState, PrimeManager, ProviderAccountUuid, QuotaManager } from '@cortexkit/anthropic-auth-core';
2
+ export interface PluginTestHandles {
3
+ primeManager: PrimeManager;
4
+ quotaManager: QuotaManager;
5
+ cacheKeepManager: CacheKeepManager;
6
+ resolveMainQuotaIdentity: (accessToken: string, model?: string, credentialAccountUuid?: string, credentialRecordVersion?: number) => Promise<{
7
+ quotaKey: string | undefined;
8
+ providerAccountUuid: ProviderAccountUuid | undefined;
9
+ generation: number;
10
+ routingLineage?: string;
11
+ stale: boolean;
12
+ state: CustodyStatusState;
13
+ }>;
14
+ resolveSidebarQuotaAccess: () => Promise<{
15
+ storage: AccountStorage | null;
16
+ access: undefined;
17
+ }>;
18
+ refreshSidebarQuota: () => Promise<void>;
19
+ fallbackRefreshReady: Promise<void>;
20
+ readonly scopedRuntime: ReturnType<typeof acquireNativeAccountRuntime>['vault'];
21
+ notificationMessageIdBeforeAssistant: (latestAssistantMessageId: string, latestUserMessageId?: string) => string | undefined;
22
+ trackDesktopNoticeMessageId: (sessionId: string, messageId: string) => void;
23
+ isDesktopNoticeMessage: (sessionId: string, messageId?: string) => boolean;
24
+ }
25
+ export declare let pluginTestHandles: WeakMap<object, PluginTestHandles> | undefined;
26
+ export declare function enablePluginTestHandles(): WeakMap<object, PluginTestHandles>;
@@ -1 +1 @@
1
- import{fa as a,ga as b}from"../index-ppdrzs41.js";import"../index-62x1p34p.js";export{a as writePortFile,b as discoverPortFile};
1
+ import{ga as a,ha as b}from"../index-bcp23wwb.js";import"../index-71temqvq.js";export{a as writePortFile,b as discoverPortFile};
@@ -1 +1 @@
1
- import{q as a}from"../index-6chd6jnr.js";import"../index-62x1p34p.js";export{a as COMMAND_MODAL_NAMES};
1
+ import{r as a}from"../index-sg0knfec.js";import"../index-71temqvq.js";export{a as COMMAND_MODAL_NAMES};
@@ -1 +1 @@
1
- import{ga as s}from"../index-ppdrzs41.js";import"../index-62x1p34p.js";async function i(e,o,t,n){let r=await s(e,n);if(!r)return null;let a=new AbortController,l=setTimeout(()=>a.abort(),2000);try{let p=await fetch(`http://127.0.0.1:${r.port}/rpc/${o}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.token}`},body:JSON.stringify(t),signal:a.signal});if(!p.ok)return null;return await p.json()}catch{return null}finally{clearTimeout(l)}}function c(e,o){return{async pending(t,n){return(await i(e,"pending-notifications",{lastReceivedId:t,sessionId:n},o))?.messages??[]},async apply(t){return await i(e,"apply",{...t},o)??{text:"apply failed",knobs:{}}},async applyMenu(t){if(t.command!=="claude"||!t.sessionId?.trim())throw TypeError("A claude menu sessionId is required");let n=await i(e,"apply-menu",{...t},o);if(!n)throw Error("Menu apply unavailable; outcome unknown");return n}}}export{c as createRpcClient};
1
+ import{ha as s}from"../index-bcp23wwb.js";import"../index-71temqvq.js";async function i(e,o,t,n){let r=await s(e,n);if(!r)return null;let a=new AbortController,l=setTimeout(()=>a.abort(),2000);try{let p=await fetch(`http://127.0.0.1:${r.port}/rpc/${o}`,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${r.token}`},body:JSON.stringify(t),signal:a.signal});if(!p.ok)return null;return await p.json()}catch{return null}finally{clearTimeout(l)}}function c(e,o){return{async pending(t,n){return(await i(e,"pending-notifications",{lastReceivedId:t,sessionId:n},o))?.messages??[]},async apply(t){return await i(e,"apply",{...t},o)??{text:"apply failed",knobs:{}}},async applyMenu(t){if(t.command!=="claude"||!t.sessionId?.trim())throw TypeError("A claude menu sessionId is required");let n=await i(e,"apply-menu",{...t},o);if(!n)throw Error("Menu apply unavailable; outcome unknown");return n}}}export{c as createRpcClient};
@@ -1 +1 @@
1
- import{r as a,s as b}from"../index-hazrk5c3.js";import"../index-62x1p34p.js";export{a as tmpdir,b as getRpcDir};
1
+ import{s as a,t as b}from"../index-c8ehrd0p.js";import"../index-71temqvq.js";export{a as tmpdir,b as getRpcDir};
@@ -35,7 +35,7 @@ export interface AccountQuota {
35
35
  }
36
36
  export interface SidebarAccountState {
37
37
  id: string;
38
- label: string | undefined;
38
+ label?: string;
39
39
  quota: AccountQuota | null;
40
40
  enabled: boolean;
41
41
  stateLine?: string;
@@ -82,7 +82,7 @@ export interface SidebarState {
82
82
  refreshBackoffUntil?: number;
83
83
  };
84
84
  fallbacks: SidebarAccountState[];
85
- activeId: string | undefined;
85
+ activeId?: string;
86
86
  route: string;
87
87
  relay: {
88
88
  enabled: boolean;
@@ -139,7 +139,10 @@ export interface SidebarStateWriteOptions {
139
139
  }) | undefined | Promise<(Pick<SidebarState, 'activeId' | 'route'> & {
140
140
  state?: SidebarState;
141
141
  }) | undefined>;
142
- onRoutingResolved?: (routing: Pick<SidebarState, 'activeId' | 'route'>) => void;
142
+ onRoutingResolved?: (routing: {
143
+ activeId: string | undefined;
144
+ route: string;
145
+ }) => void;
143
146
  }
144
147
  export declare function setSidebarState(state: SidebarState, stateFile?: string, options?: SidebarStateWriteOptions): Promise<void>;
145
148
  export declare function drainSidebarWrites(): Promise<void>;
@@ -1 +1 @@
1
- import{$ as v,G as a,H as b,I as c,J as d,K as e,L as f,M as g,N as h,O as i,P as j,Q as k,R as l,S as m,T as n,U as o,V as p,W as q,X as r,Y as s,Z as t,_ as u,aa as w,ba as x,ca as y,da as z,ea as A}from"./index-20d6rmjj.js";import"./index-62x1p34p.js";export{i as setSidebarState,r as scopedQuotaShortNames,k as resolveActiveAccount,s as quotaLabelColumnWidth,c as normalizeSidebarState,a as getSidebarStateFile,h as getSidebarState,f as getInitialSidebarRoutingTestHooks,p as getFableRecoverySummary,w as getCollapsedQuotaSummary,x as getCollapsedAccounts,q as formatQuotaRowLabel,m as formatPrimeTime,n as formatPrimeCost,o as formatPrimeAccountValue,l as formatFallbackModelLabel,u as fitQuotaRow,v as fitPaceLine,j as drainSidebarWrites,A as computeQuotaPacing,d as __setSidebarStateWriteTestHooks,e as __setInitialSidebarRoutingTestHooks,g as __acquireSidebarStateLockForTest,z as SEVEN_DAY_MS,t as QUOTA_BAR_MIN_CELLS,y as FIVE_HOUR_MS,b as DEFAULT_SIDEBAR_STATE};
1
+ import{$ as u,H as a,I as b,J as c,K as d,L as e,M as f,N as g,O as h,P as i,Q as j,R as k,S as l,T as m,U as n,V as o,W as p,X as q,Y as r,Z as s,_ as t,aa as v,ba as w,ca as x,da as y,ea as z,fa as A}from"./index-46e2gk3c.js";import"./index-71temqvq.js";export{i as setSidebarState,r as scopedQuotaShortNames,k as resolveActiveAccount,s as quotaLabelColumnWidth,c as normalizeSidebarState,a as getSidebarStateFile,h as getSidebarState,f as getInitialSidebarRoutingTestHooks,p as getFableRecoverySummary,w as getCollapsedQuotaSummary,x as getCollapsedAccounts,q as formatQuotaRowLabel,m as formatPrimeTime,n as formatPrimeCost,o as formatPrimeAccountValue,l as formatFallbackModelLabel,u as fitQuotaRow,v as fitPaceLine,j as drainSidebarWrites,A as computeQuotaPacing,d as __setSidebarStateWriteTestHooks,e as __setInitialSidebarRoutingTestHooks,g as __acquireSidebarStateLockForTest,z as SEVEN_DAY_MS,t as QUOTA_BAR_MIN_CELLS,y as FIVE_HOUR_MS,b as DEFAULT_SIDEBAR_STATE};
@@ -41,6 +41,12 @@ export interface SidebarController {
41
41
  toggleCollapsed: () => void;
42
42
  /** Stops the preference watcher; OpenCode 1 keeps it for the process. */
43
43
  dispose: () => void;
44
+ /**
45
+ * However many refreshes in a row have failed, a retry never waits longer
46
+ * than this. Every attempt costs the server a full runtime read, so a
47
+ * failing sidebar must not keep trying at the poll rate forever.
48
+ */
49
+ retryMaxMs: number;
44
50
  }
45
51
  export declare function createSidebarController(initialPrefs: AnthropicAuthTuiPrefs): SidebarController;
46
52
  /** The sidebar panel for one session; the host owns polling and the theme. */
@@ -95,5 +101,57 @@ export interface ClaudeSidebarHost {
95
101
  }
96
102
  /** Reads one session's sidebar state from the location's server. */
97
103
  export type ReadSidebarState = (sessionID: string, signal: AbortSignal) => Promise<SidebarState>;
104
+ /**
105
+ * What the sidebar reads and draws with, independent of the host chrome.
106
+ * The timer functions default to the global ones; a test passes its own so it
107
+ * can drive the refresh schedule without touching the shared globals.
108
+ */
109
+ export interface HostSidebarPropsState {
110
+ read: ReadSidebarState;
111
+ controller: SidebarController;
112
+ sessionId: string;
113
+ setTimeoutImpl?: typeof globalThis.setTimeout;
114
+ /** Clears a handle `setTimeoutImpl` returned, whatever type that was. */
115
+ clearTimeoutImpl?: (handle: unknown) => void;
116
+ }
117
+ /** The refresh loop's own timers, so a test can drive its schedule. */
118
+ export interface SidebarScheduleTimers {
119
+ setTimeoutImpl?: typeof globalThis.setTimeout;
120
+ clearTimeoutImpl?: (handle: unknown) => void;
121
+ }
122
+ /**
123
+ * Delay before the next refresh after `failures` failed reads in a row, each
124
+ * one longer than the last until the controller's limit. A successful read
125
+ * resets the count, so a healthy server is polled at the configured rate. A
126
+ * failed read still costs the server a full runtime read, so retrying at the
127
+ * poll rate keeps that cost alive for as long as the failure lasts.
128
+ */
129
+ export declare function sidebarRetryDelay(pollMs: number, failures: number, retryMaxMs: number): number;
130
+ /** Starts and stops the refresh schedule the sidebar lives on. */
131
+ export interface SidebarSchedule {
132
+ /**
133
+ * Reads once and then keeps the retry timer running. Safe to call more than
134
+ * once: a running schedule is left alone.
135
+ */
136
+ start: () => void;
137
+ /**
138
+ * Stops the schedule for good: clears the waiting timer and aborts a read
139
+ * still in flight, so it cannot queue another one. The item that unmounts a
140
+ * sidebar calls this; without it, a failing refresh would keep polling the
141
+ * server from a sidebar nobody is looking at.
142
+ */
143
+ stop: () => void;
144
+ }
145
+ export declare function createSidebarSchedule(options: {
146
+ read: ReadSidebarState;
147
+ sessionId: string;
148
+ pollRate: () => {
149
+ pollMs: number;
150
+ retryMaxMs: number;
151
+ };
152
+ /** Receives each answer that differs from the one before it. */
153
+ onState: (state: SidebarState) => void;
154
+ } & SidebarScheduleTimers): SidebarSchedule;
155
+ export declare function useHostSidebarState(props: HostSidebarPropsState): () => SidebarState;
98
156
  /** Claims the OpenCode 2 session sidebar; the returned function releases it. */
99
157
  export declare function mountClaudeSidebar(host: ClaudeSidebarHost, read: ReadSidebarState): Promise<() => void>;
@@ -0,0 +1,70 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ import { type JSX } from 'solid-js';
3
+ import type { SidebarState } from '../sidebar-state.js';
4
+ import { type AnthropicAuthTuiPrefs } from '../tui-preferences.js';
5
+ import { type HostTheme, type SidebarTheme } from './claude-sidebar.js';
6
+ /** One status line, classified for drawing. */
7
+ export type StatusLine = {
8
+ readonly kind: 'heading';
9
+ readonly level: number;
10
+ readonly text: string;
11
+ } | {
12
+ readonly kind: 'bullet';
13
+ readonly indent: number;
14
+ readonly text: string;
15
+ } | {
16
+ readonly kind: 'text';
17
+ readonly text: string;
18
+ } | {
19
+ readonly kind: 'blank';
20
+ };
21
+ /**
22
+ * Splits a section's status lines (each may hold several lines) and classifies
23
+ * each one. Only line-leading Markdown is read: `#` headings and `-`, `*` or
24
+ * `+` bullets. Everything else, including any `*` inside a line, stays as
25
+ * written. Runs of blank lines collapse to one, and leading or trailing blank
26
+ * lines are dropped.
27
+ */
28
+ export declare function parseStatusLines(lines: readonly string[]): StatusLine[];
29
+ /** Draws status lines with headings and bullets styled, not as Markdown. */
30
+ export declare function StatusText(props: {
31
+ readonly lines: readonly string[];
32
+ readonly theme: SidebarTheme;
33
+ }): JSX.Element;
34
+ /**
35
+ * OpenCode 1's quota view: one account block for main and for each enabled or
36
+ * vault-held fallback, as the sidebar draws them.
37
+ */
38
+ export declare function QuotaStatus(props: {
39
+ readonly state: SidebarState;
40
+ readonly theme: SidebarTheme;
41
+ readonly prefs: AnthropicAuthTuiPrefs;
42
+ readonly now: number;
43
+ }): JSX.Element;
44
+ /** One section's status, as the `/claude` menu hands it over. */
45
+ export interface MenuStatusView {
46
+ readonly title: string;
47
+ readonly lines: readonly string[];
48
+ /**
49
+ * Reads the sidebar's quota state; given for the Quota section only, whose
50
+ * view then draws account blocks instead of the text.
51
+ */
52
+ readonly readQuota?: (signal: AbortSignal) => Promise<SidebarState>;
53
+ }
54
+ /** The OpenCode 2 TUI context members the status dialog uses. */
55
+ export interface MenuStatusHost {
56
+ readonly theme: HostTheme;
57
+ readonly ui: {
58
+ readonly dialog: {
59
+ show(render: () => JSX.Element, onClose?: () => void): void;
60
+ set(options: {
61
+ readonly size?: 'medium' | 'large' | 'xlarge';
62
+ }): void;
63
+ };
64
+ };
65
+ }
66
+ /**
67
+ * Shows a section's status in a wide OpenCode 2 dialog. The returned promise
68
+ * settles when the person closes the dialog, or when `signal` aborts.
69
+ */
70
+ export declare function showMenuStatusDialog(host: MenuStatusHost, view: MenuStatusView, signal?: AbortSignal): Promise<void>;
@@ -1,6 +1,6 @@
1
- import"./index-62x1p34p.js";import{readFileSync as k,watch as C}from"node:fs";import{mkdir as _,readFile as I,rename as E,writeFile as b}from"node:fs/promises";import{homedir as g}from"node:os";import{basename as F,dirname as P,join as N}from"node:path";import{clearTimeout as D,setTimeout as L}from"node:timers";import{applyEdits as T,modify as y,parse as f}from"jsonc-parser";var v="OPENCODE_TUI_PREFERENCES_FILE",h="tui-preferences.jsonc";function A(){let J=process.env[v];if(J)return J;let z=process.env.OPENCODE_CONFIG_DIR||N(process.env.XDG_CONFIG_HOME||N(g(),".config"),"opencode");return N(z,h)}function H(J){return typeof J==="object"&&J!==null&&!Array.isArray(J)}async function qq(){try{let J=await I(A(),"utf8"),z=[],q=f(J,z,{allowTrailingComma:!0});if(z.length>0)return{};return H(q)?q:{}}catch{return{}}}var m="anthropic-auth",p=160,R={forceToTop:!1,order:p,startCollapsed:!1,rememberCollapsed:!0,collapsed:null,pollMs:1500,refreshDebounceMs:200,header:{label:"CLAUDE",showVersion:!0},sections:{quota:!0,fallbackAccounts:!0,routing:!0,cache:!0,health:!0,pacing:!0},appearance:{barWidth:10,barFilledChar:"█",barEmptyChar:"░",warnThreshold:50,errorThreshold:80}};function $(J,z){return typeof J==="boolean"?J:z}function Y(J,z,q,X){if(typeof J!=="number"||!Number.isFinite(J))return z;return Math.min(Math.max(Math.round(J),q),X)}function c(J,z,q){if(typeof J!=="string"||J.length===0)return z;return J.slice(0,q)}function w(J,z){if(typeof J!=="string")return z;return[...J][0]??z}function zq(J){let z=J[m];if(!H(z))return structuredClone(R);let q=R,X=H(z.header)?z.header:{},Q=H(z.sections)?z.sections:{},Z=H(z.appearance)?z.appearance:{},G=Y(Z.warnThreshold,q.appearance.warnThreshold,0,99),V=Math.max(Y(Z.errorThreshold,q.appearance.errorThreshold,0,100),Math.min(G+1,100));return{forceToTop:$(z.forceToTop,q.forceToTop),order:Y(z.order,q.order,-1e4,1e4),startCollapsed:$(z.startCollapsed,q.startCollapsed),rememberCollapsed:$(z.rememberCollapsed,q.rememberCollapsed),collapsed:typeof z.collapsed==="boolean"?z.collapsed:null,pollMs:Y(z.pollMs,q.pollMs,500,30000),refreshDebounceMs:Y(z.refreshDebounceMs,q.refreshDebounceMs,50,5000),header:{label:c(X.label,q.header.label,20),showVersion:$(X.showVersion,q.header.showVersion)},sections:{quota:$(Q.quota,q.sections.quota),fallbackAccounts:$(Q.fallbackAccounts,q.sections.fallbackAccounts),routing:$(Q.routing,q.sections.routing),cache:$(Q.cache,q.sections.cache),health:$(Q.health,q.sections.health),pacing:$(Q.pacing,q.sections.pacing)},appearance:{barWidth:Y(Z.barWidth,q.appearance.barWidth,4,40),barFilledChar:w(Z.barFilledChar,q.appearance.barFilledChar),barEmptyChar:w(Z.barEmptyChar,q.appearance.barEmptyChar),warnThreshold:G,errorThreshold:V}}}var u=-1e5;function Jq(J,z,q){let X=J[z];if(!H(X))return q;if(X.forceToTop===!0)return u+Object.keys(J).indexOf(z);return Y(X.order,q,-1e4,1e4)}var s=`// Shared preferences for opencode TUI plugins.
1
+ import"./index-71temqvq.js";import{readFileSync as S,statSync as b,watch as F}from"node:fs";import{mkdir as g,readFile as I,rename as T,writeFile as y}from"node:fs/promises";import{homedir as h}from"node:os";import{basename as v,dirname as _,join as N}from"node:path";import{clearTimeout as D,setTimeout as P}from"node:timers";import{applyEdits as f,modify as m,parse as p}from"jsonc-parser";var c="OPENCODE_TUI_PREFERENCES_FILE",u="tui-preferences.jsonc";function K(){let Q=process.env[c];if(Q)return Q;let q=process.env.OPENCODE_CONFIG_DIR||N(process.env.XDG_CONFIG_HOME||N(h(),".config"),"opencode");return N(q,u)}function H(Q){return typeof Q==="object"&&Q!==null&&!Array.isArray(Q)}async function Zq(){try{let Q=await I(K(),"utf8"),q=[],J=p(Q,q,{allowTrailingComma:!0});if(q.length>0)return{};return H(J)?J:{}}catch{return{}}}var s="anthropic-auth",d=160,k={forceToTop:!1,order:d,startCollapsed:!1,rememberCollapsed:!0,collapsed:null,pollMs:1500,refreshDebounceMs:200,header:{label:"CLAUDE",showVersion:!0},sections:{quota:!0,fallbackAccounts:!0,routing:!0,cache:!0,health:!0,pacing:!0},appearance:{barWidth:10,barFilledChar:"█",barEmptyChar:"░",warnThreshold:50,errorThreshold:80}};function z(Q,q){return typeof Q==="boolean"?Q:q}function B(Q,q,J,Z){if(typeof Q!=="number"||!Number.isFinite(Q))return q;return Math.min(Math.max(Math.round(Q),J),Z)}function o(Q,q,J){if(typeof Q!=="string"||Q.length===0)return q;return Q.slice(0,J)}function x(Q,q){if(typeof Q!=="string")return q;return[...Q][0]??q}function $q(Q){let q=Q[s];if(!H(q))return structuredClone(k);let J=k,Z=H(q.header)?q.header:{},X=H(q.sections)?q.sections:{},$=H(q.appearance)?q.appearance:{},Y=B($.warnThreshold,J.appearance.warnThreshold,0,99),G=Math.max(B($.errorThreshold,J.appearance.errorThreshold,0,100),Math.min(Y+1,100));return{forceToTop:z(q.forceToTop,J.forceToTop),order:B(q.order,J.order,-1e4,1e4),startCollapsed:z(q.startCollapsed,J.startCollapsed),rememberCollapsed:z(q.rememberCollapsed,J.rememberCollapsed),collapsed:typeof q.collapsed==="boolean"?q.collapsed:null,pollMs:B(q.pollMs,J.pollMs,500,30000),refreshDebounceMs:B(q.refreshDebounceMs,J.refreshDebounceMs,50,5000),header:{label:o(Z.label,J.header.label,20),showVersion:z(Z.showVersion,J.header.showVersion)},sections:{quota:z(X.quota,J.sections.quota),fallbackAccounts:z(X.fallbackAccounts,J.sections.fallbackAccounts),routing:z(X.routing,J.sections.routing),cache:z(X.cache,J.sections.cache),health:z(X.health,J.sections.health),pacing:z(X.pacing,J.sections.pacing)},appearance:{barWidth:B($.barWidth,J.appearance.barWidth,4,40),barFilledChar:x($.barFilledChar,J.appearance.barFilledChar),barEmptyChar:x($.barEmptyChar,J.appearance.barEmptyChar),warnThreshold:Y,errorThreshold:G}}}var n=-1e5;function zq(Q,q,J){let Z=Q[q];if(!H(Z))return J;if(Z.forceToTop===!0)return n+Object.keys(Q).indexOf(q);return B(Z.order,J,-1e4,1e4)}var i=`// Shared preferences for opencode TUI plugins.
2
2
  // One top-level key per plugin (short name). See each plugin's README for
3
3
  // its supported settings. This file is safe to hand-edit; plugins update
4
4
  // individual keys in place and preserve comments.
5
5
  {}
6
- `;async function d(J,z,q){let X=A();await _(P(X),{recursive:!0});let Q;try{Q=await I(X,"utf8")}catch{Q=""}if(Q.trim()==="")Q=s;let Z=y(Q,[J,...z],q,{formattingOptions:{insertSpaces:!0,tabSize:2}}),G=T(Q,Z),V=`${X}.${process.pid}.tmp`;await b(V,G,"utf8"),await E(V,X)}var U=Promise.resolve();function Qq(J,z,q){return U=U.then(()=>d(J,z,q)).catch(()=>{}),U}var o=150,n=100;function Xq(J,z={}){let q=A(),X=F(q),Q=null,Z=null;try{Z=k(q,"utf8")}catch{}let G=!1,V=async()=>{let W=await I(q,"utf8").catch(()=>null);if(G||W===null)return;if(W===Z)return;Z=W,J()},x=()=>{if(Q)D(Q);Q=L(()=>{Q=null,V()},o)},K=null;try{K=(z.watchDirectory??C)(P(q),(W,j)=>{let S=j===X||j?.startsWith(`${X}.`)&&j.endsWith(".tmp");if(j!=null&&!S)return;x()})}catch{if(Z===null)return()=>{}}let B=null,M=!1,O=()=>{if(G||B)return;B=L(()=>{if(B=null,G||M)return;M=!0,V().finally(()=>{M=!1,O()})},n),B.unref?.()};return O(),()=>{if(G=!0,Q)D(Q);if(B)D(B);K?.close()}}export{Xq as watchTuiPreferences,zq as resolveAnthropicAuthPrefs,qq as readTuiPreferencesFile,Qq as queueTuiPreferenceUpdate,A as getTuiPreferencesFile,Jq as computeEffectiveOrder,v as TUI_PREFS_FILE_ENV,m as PLUGIN_KEY,p as DEFAULT_SLOT_ORDER,R as DEFAULT_PREFS};
6
+ `;async function r(Q,q,J){let Z=K();await g(_(Z),{recursive:!0});let X;try{X=await I(Z,"utf8")}catch{X=""}if(X.trim()==="")X=i;let $=m(X,[Q,...q],J,{formattingOptions:{insertSpaces:!0,tabSize:2}}),Y=f(X,$),G=`${Z}.${process.pid}.tmp`;await y(G,Y,"utf8"),await T(G,Z)}var U=Promise.resolve();function Gq(Q,q,J){return U=U.then(()=>r(Q,q,J)).catch(()=>{}),U}var t=150,l=100;function C(Q){try{let q=b(Q,{bigint:!0});return`${q.ino}:${q.size}:${q.mtimeNs}:${q.ctimeNs}`}catch{return null}}function Vq(Q,q={}){let J=K(),Z=v(J),X=null,$=null;try{$=S(J,"utf8")}catch{}let Y=C(J),G=!1,A=async(R=!1)=>{let V=await C(J);if(V===null)return;if(V===Y&&$!==null&&!R)return;let M=await I(J,"utf8").catch(()=>null);if(G||M===null)return;if(Y=V,M===$)return;$=M,Q()},E=()=>{if(X)D(X);X=P(()=>{X=null,A(!0)},t)},O=null;try{O=(q.watchDirectory??F)(_(J),(R,V)=>{let w=V===Z||V?.startsWith(`${Z}.`)&&V.endsWith(".tmp");if(V!=null&&!w)return;E()})}catch{if($===null)return()=>{}}let W=null,j=!1,L=()=>{if(G||W)return;W=P(()=>{if(W=null,G||j)return;j=!0,A().finally(()=>{j=!1,L()})},l),W.unref?.()};return L(),()=>{if(G=!0,X)D(X);if(W)D(W);O?.close()}}export{Vq as watchTuiPreferences,$q as resolveAnthropicAuthPrefs,Zq as readTuiPreferencesFile,Gq as queueTuiPreferenceUpdate,K as getTuiPreferencesFile,zq as computeEffectiveOrder,c as TUI_PREFS_FILE_ENV,s as PLUGIN_KEY,d as DEFAULT_SLOT_ORDER,k as DEFAULT_PREFS};
@@ -1,5 +1,5 @@
1
- import { type ClaudeCodeIdentity, type RequestGzipLatch, TrailingAssistantHistoryError } from '@cortexkit/anthropic-auth-core';
2
- import type { AccountRequest, AttemptOutcome, ChooseAccountInput, HeaderEdits, HostError, LimitSignal, OpenCode2AuthAdapter, RequestScope, Transport } from '@cortexkit/common-auth/opencode2';
1
+ import { AnthropicOAuthOriginError, type ClaudeCodeIdentity, type RequestGzipLatch, TrailingAssistantHistoryError } from '@cortexkit/anthropic-auth-core';
2
+ import type { AccountRequest, AttemptOutcome, ChooseAccountInput, ChooseAccountResult, HeaderEdits, HostError, LimitSignal, OpenCode2AuthAdapter, RequestScope, Transport } from '@cortexkit/common-auth/opencode2';
3
3
  import { EffortMarkerCorrelationError } from '../effort-history';
4
4
  import { createStrippedStream, rewriteRequestBody } from '../transform';
5
5
  /** The provider OpenCode 2 serves Claude under. */
@@ -150,8 +150,12 @@ export interface NativeAnthropicAttemptOutcome extends AttemptOutcome {
150
150
  * the adapter passes it is rejected at compile time.
151
151
  */
152
152
  export interface NativeAnthropicSource<Q, P> {
153
- /** Picks the account for one request; `undefined` refuses it. */
154
- readonly chooseAccount: (input: ChooseAccountInput) => Promise<string | undefined> | string | undefined;
153
+ /**
154
+ * Picks the account for one request; `undefined` refuses it. In phase
155
+ * `retry` it may instead return a hold, which keeps the refused account and
156
+ * waits the given delay before the host retries.
157
+ */
158
+ readonly chooseAccount: (input: ChooseAccountInput) => Promise<ChooseAccountResult> | ChooseAccountResult;
155
159
  /** Discards one queued choice that the installer will not authorize. */
156
160
  readonly dropChoice?: (input: AccountRequest) => Promise<void> | void;
157
161
  /**
@@ -220,7 +224,7 @@ export interface NativeAnthropicAdapterDeps<Q, P> {
220
224
  readonly requestGzipLatch?: RequestGzipLatch;
221
225
  }
222
226
  export interface NativeAnthropicAdapter<Q, P> {
223
- readonly adapter: OpenCode2AuthAdapter<Q, NativeAnthropicAttemptData<P>> & {
227
+ readonly adapter: OpenCode2AuthAdapter<Q, NativeAnthropicAttemptData<P>, ChooseAccountResult> & {
224
228
  readonly dropChoice: (input: AccountRequest) => Promise<void> | void;
225
229
  };
226
230
  /**
@@ -275,8 +279,9 @@ export declare class NativeAnthropicTransportRefusal extends Error {
275
279
  }
276
280
  /**
277
281
  * The request was refused with a local 400 because it can never succeed as
278
- * written: its history ends on a meaningful assistant turn, or an effort
279
- * marker in it cannot be matched to the session's effort plan. Nothing was
282
+ * written: its history ends on a meaningful assistant turn, an effort marker
283
+ * in it cannot be matched to the session's effort plan, or it is an OAuth
284
+ * request whose URL is not Anthropic's API server. Nothing was
280
285
  * sent, and another account cannot help, so the adapter never reports it as
281
286
  * an account limit. The message and `check` describe only the shape of the
282
287
  * problem, never conversation content.
@@ -285,7 +290,7 @@ export declare class NativeAnthropicLocalRefusal extends Error {
285
290
  readonly kind = "local-invalid-request";
286
291
  readonly status = 400;
287
292
  readonly check: string;
288
- constructor(cause: TrailingAssistantHistoryError | EffortMarkerCorrelationError);
293
+ constructor(cause: TrailingAssistantHistoryError | EffortMarkerCorrelationError | AnthropicOAuthOriginError);
289
294
  }
290
295
  export declare function createNativeAnthropicAdapter<Q, P>(deps: NativeAnthropicAdapterDeps<Q, P>): NativeAnthropicAdapter<Q, P>;
291
296
  export {};