@cortexkit/opencode-anthropic-auth 2.2.8 → 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.
@@ -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>;
@@ -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 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-j6x60aqq.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};
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-71temqvq.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
1
  import { AnthropicOAuthOriginError, 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';
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
  /**