@cortexkit/opencode-anthropic-auth 1.18.0 → 1.19.1

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.
@@ -1 +1 @@
1
- import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r}from"./index-xjvcfyt6.js";import"./index-h0pmqm96.js";import"./index-1ets4bf8.js";import"./index-9aeag0wm.js";export{i as setSidebarState,k as resolveActiveAccount,c as normalizeSidebarState,a as getSidebarStateFile,h as getSidebarState,f as getInitialSidebarRoutingTestHooks,n as getFableRecoverySummary,o as getCollapsedQuotaSummary,l as formatScopedQuotaLabel,m as formatFallbackModelLabel,j as drainSidebarWrites,r as computeQuotaPacing,d as __setSidebarStateWriteTestHooks,e as __setInitialSidebarRoutingTestHooks,g as __acquireSidebarStateLockForTest,q as SEVEN_DAY_MS,p as FIVE_HOUR_MS,b as DEFAULT_SIDEBAR_STATE};
1
+ import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r}from"./index-a13w4gm9.js";import"./index-vwgzgh5x.js";import"./index-dex8fs0m.js";import"./index-dzs7w297.js";export{i as setSidebarState,k as resolveActiveAccount,c as normalizeSidebarState,a as getSidebarStateFile,h as getSidebarState,f as getInitialSidebarRoutingTestHooks,n as getFableRecoverySummary,o as getCollapsedQuotaSummary,l as formatScopedQuotaLabel,m as formatFallbackModelLabel,j as drainSidebarWrites,r as computeQuotaPacing,d as __setSidebarStateWriteTestHooks,e as __setInitialSidebarRoutingTestHooks,g as __acquireSidebarStateLockForTest,q as SEVEN_DAY_MS,p as FIVE_HOUR_MS,b as DEFAULT_SIDEBAR_STATE};
@@ -1,4 +1,5 @@
1
1
  import { type Cache1hMode, type ClaudeCodeIdentity } from '@cortexkit/anthropic-auth-core';
2
+ import { type ServerSideFallbackOutcome } from './server-fallback';
2
3
  export type FetchInput = string | URL | Request;
3
4
  /**
4
5
  * Merge headers from a Request object and/or a RequestInit headers value
@@ -84,14 +85,19 @@ export declare function rewriteRequestBody(body: string, options?: {
84
85
  identity?: ClaudeCodeIdentity;
85
86
  perf?: RewritePerfCallback;
86
87
  hybridStandbyAnchor?: HybridMessageCacheAnchor;
88
+ serverSideFallbackEnabled?: boolean;
87
89
  }): Promise<string>;
88
90
  /**
89
91
  * Create a streaming response that strips the tool prefix from tool names.
90
92
  */
91
93
  export declare function createStrippedStream(response: Response, options?: {
92
94
  perf?: RewritePerfCallback;
93
- onContentFilter?: () => boolean | undefined;
95
+ onContentFilter?: (context?: {
96
+ completedToolUse: boolean;
97
+ }) => boolean | undefined;
94
98
  onComplete?: (finishReason: string) => void;
95
99
  contentFilterModel?: unknown;
100
+ serverSideFallbackModel?: string;
101
+ onServerSideFallbackOutcome?: (outcome: ServerSideFallbackOutcome) => void;
96
102
  }): Response;
97
103
  export {};
@@ -1,3 +1,4 @@
1
+ import { watch } from 'node:fs';
1
2
  export declare const TUI_PREFS_FILE_ENV = "OPENCODE_TUI_PREFERENCES_FILE";
2
3
  export declare function getTuiPreferencesFile(): string;
3
4
  export declare function readTuiPreferencesFile(): Promise<Record<string, unknown>>;
@@ -37,5 +38,7 @@ export declare function resolveAnthropicAuthPrefs(root: Record<string, unknown>)
37
38
  export declare function computeEffectiveOrder(root: Record<string, unknown>, pluginKey: string, defaultOrder: number): number;
38
39
  type JsonValue = string | number | boolean | null;
39
40
  export declare function queueTuiPreferenceUpdate(pluginKey: string, path: string[], value: JsonValue): Promise<void>;
40
- export declare function watchTuiPreferences(onChange: () => void): () => void;
41
+ export declare function watchTuiPreferences(onChange: () => void, options?: {
42
+ watchDirectory?: typeof watch;
43
+ }): () => void;
41
44
  export {};
@@ -1,6 +1,6 @@
1
- import{sc as c,tc as C,uc as h}from"./index-9aeag0wm.js";var m=C((v,k)=>{(function(Q){if(typeof k==="object"&&typeof k.exports==="object"){var J=Q(h,v);if(J!==void 0)k.exports=J}else if(typeof define==="function"&&define.amd)define(["require","exports","./impl/format","./impl/edit","./impl/scanner","./impl/parser"],Q)})(function(Q,J){Object.defineProperty(J,"__esModule",{value:!0}),J.applyEdits=J.modify=J.format=J.printParseErrorCode=J.ParseErrorCode=J.stripComments=J.visit=J.getNodeValue=J.getNodePath=J.findNodeAtOffset=J.findNodeAtLocation=J.parseTree=J.parse=J.getLocation=J.SyntaxKind=J.ScanError=J.createScanner=void 0;let X=Q("./impl/format"),Z=Q("./impl/edit"),$=Q("./impl/scanner"),G=Q("./impl/parser");J.createScanner=$.createScanner;var V;(function(z){z[z.None=0]="None",z[z.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=2]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",z[z.InvalidUnicode=4]="InvalidUnicode",z[z.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",z[z.InvalidCharacter=6]="InvalidCharacter"})(V||(J.ScanError=V={}));var Y;(function(z){z[z.OpenBraceToken=1]="OpenBraceToken",z[z.CloseBraceToken=2]="CloseBraceToken",z[z.OpenBracketToken=3]="OpenBracketToken",z[z.CloseBracketToken=4]="CloseBracketToken",z[z.CommaToken=5]="CommaToken",z[z.ColonToken=6]="ColonToken",z[z.NullKeyword=7]="NullKeyword",z[z.TrueKeyword=8]="TrueKeyword",z[z.FalseKeyword=9]="FalseKeyword",z[z.StringLiteral=10]="StringLiteral",z[z.NumericLiteral=11]="NumericLiteral",z[z.LineCommentTrivia=12]="LineCommentTrivia",z[z.BlockCommentTrivia=13]="BlockCommentTrivia",z[z.LineBreakTrivia=14]="LineBreakTrivia",z[z.Trivia=15]="Trivia",z[z.Unknown=16]="Unknown",z[z.EOF=17]="EOF"})(Y||(J.SyntaxKind=Y={})),J.getLocation=G.getLocation,J.parse=G.parse,J.parseTree=G.parseTree,J.findNodeAtLocation=G.findNodeAtLocation,J.findNodeAtOffset=G.findNodeAtOffset,J.getNodePath=G.getNodePath,J.getNodeValue=G.getNodeValue,J.visit=G.visit,J.stripComments=G.stripComments;var L;(function(z){z[z.InvalidSymbol=1]="InvalidSymbol",z[z.InvalidNumberFormat=2]="InvalidNumberFormat",z[z.PropertyNameExpected=3]="PropertyNameExpected",z[z.ValueExpected=4]="ValueExpected",z[z.ColonExpected=5]="ColonExpected",z[z.CommaExpected=6]="CommaExpected",z[z.CloseBraceExpected=7]="CloseBraceExpected",z[z.CloseBracketExpected=8]="CloseBracketExpected",z[z.EndOfFileExpected=9]="EndOfFileExpected",z[z.InvalidCommentToken=10]="InvalidCommentToken",z[z.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=12]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",z[z.InvalidUnicode=14]="InvalidUnicode",z[z.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",z[z.InvalidCharacter=16]="InvalidCharacter"})(L||(J.ParseErrorCode=L={}));function B(z){switch(z){case 1:return"InvalidSymbol";case 2:return"InvalidNumberFormat";case 3:return"PropertyNameExpected";case 4:return"ValueExpected";case 5:return"ColonExpected";case 6:return"CommaExpected";case 7:return"CloseBraceExpected";case 8:return"CloseBracketExpected";case 9:return"EndOfFileExpected";case 10:return"InvalidCommentToken";case 11:return"UnexpectedEndOfComment";case 12:return"UnexpectedEndOfString";case 13:return"UnexpectedEndOfNumber";case 14:return"InvalidUnicode";case 15:return"InvalidEscapeCharacter";case 16:return"InvalidCharacter"}return"<unknown ParseErrorCode>"}J.printParseErrorCode=B;function j(z,H,N){return X.format(z,H,N)}J.format=j;function A(z,H,N,R){return Z.setProperty(z,H,N,R)}J.modify=A;function O(z,H){let N=H.slice(0).sort((U,D)=>{let T=U.offset-D.offset;if(T===0)return U.length-D.length;return T}),R=z.length;for(let U=N.length-1;U>=0;U--){let D=N[U];if(D.offset+D.length<=R)z=Z.applyEdit(z,D);else throw Error("Overlapping edit");R=D.offset}return z}J.applyEdits=O})});var q=c(m(),1);import{watch as y}from"node:fs";import{mkdir as S,readFile as w,rename as E,writeFile as p}from"node:fs/promises";import{homedir as l}from"node:os";import{basename as x,dirname as P,join as _}from"node:path";import{clearTimeout as F,setTimeout as f}from"node:timers";var i="OPENCODE_TUI_PREFERENCES_FILE",s="tui-preferences.jsonc";function b(){let Q=process.env[i];if(Q)return Q;let J=process.env.OPENCODE_CONFIG_DIR||_(process.env.XDG_CONFIG_HOME||_(l(),".config"),"opencode");return _(J,s)}function I(Q){return typeof Q==="object"&&Q!==null&&!Array.isArray(Q)}async function Vz(){try{let Q=await w(b(),"utf8"),J=[],X=q.parse(Q,J,{allowTrailingComma:!0});if(J.length>0)return{};return I(X)?X:{}}catch{return{}}}var d="anthropic-auth",n=160,u={forceToTop:!1,order:n,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 W(Q,J){return typeof Q==="boolean"?Q:J}function M(Q,J,X,Z){if(typeof Q!=="number"||!Number.isFinite(Q))return J;return Math.min(Math.max(Math.round(Q),X),Z)}function a(Q,J,X){if(typeof Q!=="string"||Q.length===0)return J;return Q.slice(0,X)}function K(Q,J){if(typeof Q!=="string")return J;return[...Q][0]??J}function Yz(Q){let J=Q[d];if(!I(J))return structuredClone(u);let X=u,Z=I(J.header)?J.header:{},$=I(J.sections)?J.sections:{},G=I(J.appearance)?J.appearance:{},V=M(G.warnThreshold,X.appearance.warnThreshold,0,99),Y=Math.max(M(G.errorThreshold,X.appearance.errorThreshold,0,100),Math.min(V+1,100));return{forceToTop:W(J.forceToTop,X.forceToTop),order:M(J.order,X.order,-1e4,1e4),startCollapsed:W(J.startCollapsed,X.startCollapsed),rememberCollapsed:W(J.rememberCollapsed,X.rememberCollapsed),collapsed:typeof J.collapsed==="boolean"?J.collapsed:null,pollMs:M(J.pollMs,X.pollMs,500,30000),refreshDebounceMs:M(J.refreshDebounceMs,X.refreshDebounceMs,50,5000),header:{label:a(Z.label,X.header.label,20),showVersion:W(Z.showVersion,X.header.showVersion)},sections:{quota:W($.quota,X.sections.quota),fallbackAccounts:W($.fallbackAccounts,X.sections.fallbackAccounts),routing:W($.routing,X.sections.routing),cache:W($.cache,X.sections.cache),health:W($.health,X.sections.health),pacing:W($.pacing,X.sections.pacing)},appearance:{barWidth:M(G.barWidth,X.appearance.barWidth,4,40),barFilledChar:K(G.barFilledChar,X.appearance.barFilledChar),barEmptyChar:K(G.barEmptyChar,X.appearance.barEmptyChar),warnThreshold:V,errorThreshold:Y}}}var t=-1e5;function Hz(Q,J,X){let Z=Q[J];if(!I(Z))return X;if(Z.forceToTop===!0)return t+Object.keys(Q).indexOf(J);return M(Z.order,X,-1e4,1e4)}var o=`// Shared preferences for opencode TUI plugins.
1
+ import{tc as c,uc as C,vc as v}from"./index-dzs7w297.js";var m=C((h,k)=>{(function(Q){if(typeof k==="object"&&typeof k.exports==="object"){var J=Q(v,h);if(J!==void 0)k.exports=J}else if(typeof define==="function"&&define.amd)define(["require","exports","./impl/format","./impl/edit","./impl/scanner","./impl/parser"],Q)})(function(Q,J){Object.defineProperty(J,"__esModule",{value:!0}),J.applyEdits=J.modify=J.format=J.printParseErrorCode=J.ParseErrorCode=J.stripComments=J.visit=J.getNodeValue=J.getNodePath=J.findNodeAtOffset=J.findNodeAtLocation=J.parseTree=J.parse=J.getLocation=J.SyntaxKind=J.ScanError=J.createScanner=void 0;let X=Q("./impl/format"),G=Q("./impl/edit"),Z=Q("./impl/scanner"),$=Q("./impl/parser");J.createScanner=Z.createScanner;var V;(function(z){z[z.None=0]="None",z[z.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=2]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",z[z.InvalidUnicode=4]="InvalidUnicode",z[z.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",z[z.InvalidCharacter=6]="InvalidCharacter"})(V||(J.ScanError=V={}));var Y;(function(z){z[z.OpenBraceToken=1]="OpenBraceToken",z[z.CloseBraceToken=2]="CloseBraceToken",z[z.OpenBracketToken=3]="OpenBracketToken",z[z.CloseBracketToken=4]="CloseBracketToken",z[z.CommaToken=5]="CommaToken",z[z.ColonToken=6]="ColonToken",z[z.NullKeyword=7]="NullKeyword",z[z.TrueKeyword=8]="TrueKeyword",z[z.FalseKeyword=9]="FalseKeyword",z[z.StringLiteral=10]="StringLiteral",z[z.NumericLiteral=11]="NumericLiteral",z[z.LineCommentTrivia=12]="LineCommentTrivia",z[z.BlockCommentTrivia=13]="BlockCommentTrivia",z[z.LineBreakTrivia=14]="LineBreakTrivia",z[z.Trivia=15]="Trivia",z[z.Unknown=16]="Unknown",z[z.EOF=17]="EOF"})(Y||(J.SyntaxKind=Y={})),J.getLocation=$.getLocation,J.parse=$.parse,J.parseTree=$.parseTree,J.findNodeAtLocation=$.findNodeAtLocation,J.findNodeAtOffset=$.findNodeAtOffset,J.getNodePath=$.getNodePath,J.getNodeValue=$.getNodeValue,J.visit=$.visit,J.stripComments=$.stripComments;var A;(function(z){z[z.InvalidSymbol=1]="InvalidSymbol",z[z.InvalidNumberFormat=2]="InvalidNumberFormat",z[z.PropertyNameExpected=3]="PropertyNameExpected",z[z.ValueExpected=4]="ValueExpected",z[z.ColonExpected=5]="ColonExpected",z[z.CommaExpected=6]="CommaExpected",z[z.CloseBraceExpected=7]="CloseBraceExpected",z[z.CloseBracketExpected=8]="CloseBracketExpected",z[z.EndOfFileExpected=9]="EndOfFileExpected",z[z.InvalidCommentToken=10]="InvalidCommentToken",z[z.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",z[z.UnexpectedEndOfString=12]="UnexpectedEndOfString",z[z.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",z[z.InvalidUnicode=14]="InvalidUnicode",z[z.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",z[z.InvalidCharacter=16]="InvalidCharacter"})(A||(J.ParseErrorCode=A={}));function L(z){switch(z){case 1:return"InvalidSymbol";case 2:return"InvalidNumberFormat";case 3:return"PropertyNameExpected";case 4:return"ValueExpected";case 5:return"ColonExpected";case 6:return"CommaExpected";case 7:return"CloseBraceExpected";case 8:return"CloseBracketExpected";case 9:return"EndOfFileExpected";case 10:return"InvalidCommentToken";case 11:return"UnexpectedEndOfComment";case 12:return"UnexpectedEndOfString";case 13:return"UnexpectedEndOfNumber";case 14:return"InvalidUnicode";case 15:return"InvalidEscapeCharacter";case 16:return"InvalidCharacter"}return"<unknown ParseErrorCode>"}J.printParseErrorCode=L;function W(z,B,j){return X.format(z,B,j)}J.format=W;function q(z,B,j,R){return G.setProperty(z,B,j,R)}J.modify=q;function O(z,B){let j=B.slice(0).sort((M,N)=>{let T=M.offset-N.offset;if(T===0)return M.length-N.length;return T}),R=z.length;for(let M=j.length-1;M>=0;M--){let N=j[M];if(N.offset+N.length<=R)z=G.applyEdit(z,N);else throw Error("Overlapping edit");R=N.offset}return z}J.applyEdits=O})});var I=c(m(),1);import{readFileSync as y,watch as S}from"node:fs";import{mkdir as E,readFile as g,rename as p,writeFile as l}from"node:fs/promises";import{homedir as x}from"node:os";import{basename as i,dirname as P,join as w}from"node:path";import{clearTimeout as _,setTimeout as f}from"node:timers";var s="OPENCODE_TUI_PREFERENCES_FILE",d="tui-preferences.jsonc";function b(){let Q=process.env[s];if(Q)return Q;let J=process.env.OPENCODE_CONFIG_DIR||w(process.env.XDG_CONFIG_HOME||w(x(),".config"),"opencode");return w(J,d)}function U(Q){return typeof Q==="object"&&Q!==null&&!Array.isArray(Q)}async function Yz(){try{let Q=await g(b(),"utf8"),J=[],X=I.parse(Q,J,{allowTrailingComma:!0});if(J.length>0)return{};return U(X)?X:{}}catch{return{}}}var n="anthropic-auth",t=160,u={forceToTop:!1,order:t,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 H(Q,J){return typeof Q==="boolean"?Q:J}function D(Q,J,X,G){if(typeof Q!=="number"||!Number.isFinite(Q))return J;return Math.min(Math.max(Math.round(Q),X),G)}function a(Q,J,X){if(typeof Q!=="string"||Q.length===0)return J;return Q.slice(0,X)}function K(Q,J){if(typeof Q!=="string")return J;return[...Q][0]??J}function Bz(Q){let J=Q[n];if(!U(J))return structuredClone(u);let X=u,G=U(J.header)?J.header:{},Z=U(J.sections)?J.sections:{},$=U(J.appearance)?J.appearance:{},V=D($.warnThreshold,X.appearance.warnThreshold,0,99),Y=Math.max(D($.errorThreshold,X.appearance.errorThreshold,0,100),Math.min(V+1,100));return{forceToTop:H(J.forceToTop,X.forceToTop),order:D(J.order,X.order,-1e4,1e4),startCollapsed:H(J.startCollapsed,X.startCollapsed),rememberCollapsed:H(J.rememberCollapsed,X.rememberCollapsed),collapsed:typeof J.collapsed==="boolean"?J.collapsed:null,pollMs:D(J.pollMs,X.pollMs,500,30000),refreshDebounceMs:D(J.refreshDebounceMs,X.refreshDebounceMs,50,5000),header:{label:a(G.label,X.header.label,20),showVersion:H(G.showVersion,X.header.showVersion)},sections:{quota:H(Z.quota,X.sections.quota),fallbackAccounts:H(Z.fallbackAccounts,X.sections.fallbackAccounts),routing:H(Z.routing,X.sections.routing),cache:H(Z.cache,X.sections.cache),health:H(Z.health,X.sections.health),pacing:H(Z.pacing,X.sections.pacing)},appearance:{barWidth:D($.barWidth,X.appearance.barWidth,4,40),barFilledChar:K($.barFilledChar,X.appearance.barFilledChar),barEmptyChar:K($.barEmptyChar,X.appearance.barEmptyChar),warnThreshold:V,errorThreshold:Y}}}var o=-1e5;function Hz(Q,J,X){let G=Q[J];if(!U(G))return X;if(G.forceToTop===!0)return o+Object.keys(Q).indexOf(J);return D(G.order,X,-1e4,1e4)}var e=`// 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 e(Q,J,X){let Z=b();await S(P(Z),{recursive:!0});let $;try{$=await w(Z,"utf8")}catch{$=""}if($.trim()==="")$=o;let G=q.modify($,[Q,...J],X,{formattingOptions:{insertSpaces:!0,tabSize:2}}),V=q.applyEdits($,G),Y=`${Z}.${process.pid}.tmp`;await p(Y,V,"utf8"),await E(Y,Z)}var g=Promise.resolve();function Wz(Q,J,X){return g=g.then(()=>e(Q,J,X)).catch(()=>{}),g}var r=150,zz=100;function Bz(Q){let J=b(),X=x(J),Z=null,$=null,G=!1,V=!1,Y=async()=>{let B=await w(J,"utf8").catch(()=>null);if(V||B===null)return;if(B===$)return;$=B,Q()},L=()=>{if(G=!0,Z)F(Z);Z=f(()=>{Z=null,Y()},r)};w(J,"utf8").then((B)=>{if(!G&&$===null)$=B}).catch(()=>{});try{let B=y(P(J),(z,H)=>{let N=H===X||H?.startsWith(`${X}.`)&&H.endsWith(".tmp");if(H!=null&&!N)return;L()}),j=null,A=!1,O=()=>{if(V||j)return;j=f(()=>{if(j=null,V||A)return;A=!0,Y().finally(()=>{A=!1,O()})},zz),j.unref?.()};return O(),()=>{if(V=!0,Z)F(Z);if(j)F(j);B.close()}}catch{return()=>{}}}export{Bz as watchTuiPreferences,Yz as resolveAnthropicAuthPrefs,Vz as readTuiPreferencesFile,Wz as queueTuiPreferenceUpdate,b as getTuiPreferencesFile,Hz as computeEffectiveOrder,i as TUI_PREFS_FILE_ENV,d as PLUGIN_KEY,n as DEFAULT_SLOT_ORDER,u as DEFAULT_PREFS};
6
+ `;async function r(Q,J,X){let G=b();await E(P(G),{recursive:!0});let Z;try{Z=await g(G,"utf8")}catch{Z=""}if(Z.trim()==="")Z=e;let $=I.modify(Z,[Q,...J],X,{formattingOptions:{insertSpaces:!0,tabSize:2}}),V=I.applyEdits(Z,$),Y=`${G}.${process.pid}.tmp`;await l(Y,V,"utf8"),await p(Y,G)}var F=Promise.resolve();function Wz(Q,J,X){return F=F.then(()=>r(Q,J,X)).catch(()=>{}),F}var zz=150,Jz=100;function jz(Q,J={}){let X=b(),G=i(X),Z=null,$=null;try{$=y(X,"utf8")}catch{}let V=!1,Y=async()=>{let z=await g(X,"utf8").catch(()=>null);if(V||z===null)return;if(z===$)return;$=z,Q()},A=()=>{if(Z)_(Z);Z=f(()=>{Z=null,Y()},zz)},L=null;try{L=(J.watchDirectory??S)(P(X),(z,B)=>{let j=B===G||B?.startsWith(`${G}.`)&&B.endsWith(".tmp");if(B!=null&&!j)return;A()})}catch{if($===null)return()=>{}}let W=null,q=!1,O=()=>{if(V||W)return;W=f(()=>{if(W=null,V||q)return;q=!0,Y().finally(()=>{q=!1,O()})},Jz),W.unref?.()};return O(),()=>{if(V=!0,Z)_(Z);if(W)_(W);L?.close()}}export{jz as watchTuiPreferences,Bz as resolveAnthropicAuthPrefs,Yz as readTuiPreferencesFile,Wz as queueTuiPreferenceUpdate,b as getTuiPreferencesFile,Hz as computeEffectiveOrder,s as TUI_PREFS_FILE_ENV,n as PLUGIN_KEY,t as DEFAULT_SLOT_ORDER,u as DEFAULT_PREFS};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-anthropic-auth",
3
- "version": "1.18.0",
3
+ "version": "1.19.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,7 +61,7 @@
61
61
  "@opencode-ai/plugin": "*"
62
62
  },
63
63
  "dependencies": {
64
- "@cortexkit/anthropic-auth-core": "1.18.0",
64
+ "@cortexkit/anthropic-auth-core": "1.19.1",
65
65
  "@opentui/core": "0.4.3",
66
66
  "@opentui/solid": "0.4.3",
67
67
  "jsonc-parser": "^3.3.1",
@@ -39,7 +39,7 @@ export interface SidebarAccountState {
39
39
 
40
40
  export interface FableRecoverySidebarState {
41
41
  sessionId: string
42
- mode: 'opus' | 'fable'
42
+ mode: 'opus' | 'fable' | 'server'
43
43
  remaining: number
44
44
  changedAt: number
45
45
  /**
@@ -48,6 +48,8 @@ export interface FableRecoverySidebarState {
48
48
  * state files; older recoveries default to Fable 5 in the summary.
49
49
  */
50
50
  requestedModelId?: string
51
+ /** Anthropic-selected target while server-side safety fallback is active. */
52
+ targetModelId?: string
51
53
  }
52
54
 
53
55
  export interface SidebarState {
@@ -280,7 +282,9 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
280
282
  .flatMap((recovery): FableRecoverySidebarState[] => {
281
283
  if (
282
284
  typeof recovery.sessionId !== 'string' ||
283
- (recovery.mode !== 'opus' && recovery.mode !== 'fable') ||
285
+ (recovery.mode !== 'opus' &&
286
+ recovery.mode !== 'fable' &&
287
+ recovery.mode !== 'server') ||
284
288
  typeof recovery.remaining !== 'number' ||
285
289
  !Number.isFinite(recovery.remaining) ||
286
290
  typeof recovery.changedAt !== 'number' ||
@@ -297,6 +301,10 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
297
301
  typeof recovery.requestedModelId === 'string'
298
302
  ? recovery.requestedModelId
299
303
  : undefined,
304
+ targetModelId:
305
+ typeof recovery.targetModelId === 'string'
306
+ ? recovery.targetModelId
307
+ : undefined,
300
308
  },
301
309
  ]
302
310
  })
@@ -697,6 +705,8 @@ export function formatFallbackModelLabel(modelId: string | undefined): string {
697
705
  return 'Fable 5'
698
706
  if (modelId === 'claude-opus-5' || modelId?.startsWith('claude-opus-5-'))
699
707
  return 'Opus 5'
708
+ if (modelId === 'claude-opus-4-8' || modelId?.startsWith('claude-opus-4-8-'))
709
+ return 'Opus 4.8'
700
710
  return modelId ?? 'Fable 5'
701
711
  }
702
712
 
@@ -711,6 +721,9 @@ export function getFableRecoverySummary(
711
721
  if (recovery.mode === 'fable') {
712
722
  return `${formatFallbackModelLabel(recovery.requestedModelId)} · restored`
713
723
  }
724
+ if (recovery.mode === 'server') {
725
+ return `${formatFallbackModelLabel(recovery.requestedModelId)}→${formatFallbackModelLabel(recovery.targetModelId)} · safety`
726
+ }
714
727
  return `Opus 4.8 · ${recovery.remaining} left`
715
728
  }
716
729
 
@@ -39,7 +39,7 @@ export interface SidebarAccountState {
39
39
 
40
40
  export interface FableRecoverySidebarState {
41
41
  sessionId: string
42
- mode: 'opus' | 'fable'
42
+ mode: 'opus' | 'fable' | 'server'
43
43
  remaining: number
44
44
  changedAt: number
45
45
  /**
@@ -48,6 +48,8 @@ export interface FableRecoverySidebarState {
48
48
  * state files; older recoveries default to Fable 5 in the summary.
49
49
  */
50
50
  requestedModelId?: string
51
+ /** Anthropic-selected target while server-side safety fallback is active. */
52
+ targetModelId?: string
51
53
  }
52
54
 
53
55
  export interface SidebarState {
@@ -280,7 +282,9 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
280
282
  .flatMap((recovery): FableRecoverySidebarState[] => {
281
283
  if (
282
284
  typeof recovery.sessionId !== 'string' ||
283
- (recovery.mode !== 'opus' && recovery.mode !== 'fable') ||
285
+ (recovery.mode !== 'opus' &&
286
+ recovery.mode !== 'fable' &&
287
+ recovery.mode !== 'server') ||
284
288
  typeof recovery.remaining !== 'number' ||
285
289
  !Number.isFinite(recovery.remaining) ||
286
290
  typeof recovery.changedAt !== 'number' ||
@@ -297,6 +301,10 @@ export function normalizeSidebarState(raw: unknown): SidebarState {
297
301
  typeof recovery.requestedModelId === 'string'
298
302
  ? recovery.requestedModelId
299
303
  : undefined,
304
+ targetModelId:
305
+ typeof recovery.targetModelId === 'string'
306
+ ? recovery.targetModelId
307
+ : undefined,
300
308
  },
301
309
  ]
302
310
  })
@@ -697,6 +705,8 @@ export function formatFallbackModelLabel(modelId: string | undefined): string {
697
705
  return 'Fable 5'
698
706
  if (modelId === 'claude-opus-5' || modelId?.startsWith('claude-opus-5-'))
699
707
  return 'Opus 5'
708
+ if (modelId === 'claude-opus-4-8' || modelId?.startsWith('claude-opus-4-8-'))
709
+ return 'Opus 4.8'
700
710
  return modelId ?? 'Fable 5'
701
711
  }
702
712
 
@@ -711,6 +721,9 @@ export function getFableRecoverySummary(
711
721
  if (recovery.mode === 'fable') {
712
722
  return `${formatFallbackModelLabel(recovery.requestedModelId)} · restored`
713
723
  }
724
+ if (recovery.mode === 'server') {
725
+ return `${formatFallbackModelLabel(recovery.requestedModelId)}→${formatFallbackModelLabel(recovery.targetModelId)} · safety`
726
+ }
714
727
  return `Opus 4.8 · ${recovery.remaining} left`
715
728
  }
716
729
 
@@ -1,4 +1,4 @@
1
- import { watch } from 'node:fs'
1
+ import { readFileSync, watch } from 'node:fs'
2
2
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
3
3
  import { homedir } from 'node:os'
4
4
  import { basename, dirname, join } from 'node:path'
@@ -292,12 +292,22 @@ const WATCH_POLL_MS = 100
292
292
  // events, and against mtime granularity.
293
293
  //
294
294
  // Returns a disposer; never throws.
295
- export function watchTuiPreferences(onChange: () => void): () => void {
295
+ export function watchTuiPreferences(
296
+ onChange: () => void,
297
+ options: { watchDirectory?: typeof watch } = {},
298
+ ): () => void {
296
299
  const file = getTuiPreferencesFile()
297
300
  const name = basename(file)
298
301
  let timer: ReturnType<typeof nativeSetTimeout> | null = null
302
+ // Capture the baseline before returning. An asynchronous seed can resolve
303
+ // after the caller's first write and absorb that change as already seen.
299
304
  let lastSeen: string | null = null
300
- let observedEvent = false
305
+ try {
306
+ lastSeen = readFileSync(file, 'utf8')
307
+ } catch {
308
+ // Missing/unreadable files can still be created later and detected by the
309
+ // directory watcher or polling fallback.
310
+ }
301
311
  let disposed = false
302
312
 
303
313
  const checkForChange = async () => {
@@ -309,7 +319,6 @@ export function watchTuiPreferences(onChange: () => void): () => void {
309
319
  }
310
320
 
311
321
  const scheduleCheck = () => {
312
- observedEvent = true
313
322
  if (timer) nativeClearTimeout(timer)
314
323
  timer = nativeSetTimeout(() => {
315
324
  timer = null
@@ -317,54 +326,52 @@ export function watchTuiPreferences(onChange: () => void): () => void {
317
326
  }, WATCH_DEBOUNCE_MS)
318
327
  }
319
328
 
320
- // Seed asynchronously. If a real file event arrives before the read resolves,
321
- // do not let the seed overwrite that pending change; the debounced re-read
322
- // will compare against the previous value and fire.
323
- void readFile(file, 'utf8')
324
- .then((text) => {
325
- if (!observedEvent && lastSeen === null) lastSeen = text
326
- })
327
- .catch(() => {})
328
-
329
+ let watcher: ReturnType<typeof watch> | null = null
329
330
  try {
330
- const watcher = watch(dirname(file), (_event, filename) => {
331
- // Exact match against the preferences file name, plus the temp file
332
- // we use for atomic writes (carrying our pid + `.tmp`).
333
- const isOurs =
334
- filename === name ||
335
- (filename?.startsWith(`${name}.`) && filename.endsWith('.tmp'))
336
- if (filename != null && !isOurs) return
337
- scheduleCheck()
338
- })
331
+ watcher = (options.watchDirectory ?? watch)(
332
+ dirname(file),
333
+ (_event, filename) => {
334
+ // Exact match against the preferences file name, plus the temp file
335
+ // we use for atomic writes (carrying our pid + `.tmp`).
336
+ const isOurs =
337
+ filename === name ||
338
+ (filename?.startsWith(`${name}.`) && filename.endsWith('.tmp'))
339
+ if (filename != null && !isOurs) return
340
+ scheduleCheck()
341
+ },
342
+ )
343
+ } catch {
344
+ // If the file exists, polling remains a complete fallback even when Bun
345
+ // cannot allocate a directory watcher (for example, transient EBADF).
346
+ // If neither the file nor its directory can be observed, remain a no-op.
347
+ if (lastSeen === null) return () => {}
348
+ }
339
349
 
340
- // Bun's fs.watch can miss atomic temp-file rename updates on some
341
- // backends, so keep a low-cost polling loop as the correctness path.
342
- // Use recursive timers instead of fs.watchFile because watchFile can keep
343
- // Bun test processes alive long after unwatchFile().
344
- let pollTimer: ReturnType<typeof nativeSetTimeout> | null = null
345
- let pollInFlight = false
346
- const schedulePoll = () => {
347
- if (disposed || pollTimer) return
348
- pollTimer = nativeSetTimeout(() => {
349
- pollTimer = null
350
- if (disposed || pollInFlight) return
351
- pollInFlight = true
352
- void checkForChange().finally(() => {
353
- pollInFlight = false
354
- schedulePoll()
355
- })
356
- }, WATCH_POLL_MS)
357
- pollTimer.unref?.()
358
- }
359
- schedulePoll()
350
+ // Bun's fs.watch can miss atomic temp-file renames and can itself fail after
351
+ // repeated close/recreate cycles, so polling must be independent of watcher
352
+ // construction. Recursive unreferenced timers avoid fs.watchFile's lingering
353
+ // handles while the host's normal event loop keeps active watchers polling.
354
+ let pollTimer: ReturnType<typeof nativeSetTimeout> | null = null
355
+ let pollInFlight = false
356
+ const schedulePoll = () => {
357
+ if (disposed || pollTimer) return
358
+ pollTimer = nativeSetTimeout(() => {
359
+ pollTimer = null
360
+ if (disposed || pollInFlight) return
361
+ pollInFlight = true
362
+ void checkForChange().finally(() => {
363
+ pollInFlight = false
364
+ schedulePoll()
365
+ })
366
+ }, WATCH_POLL_MS)
367
+ pollTimer.unref?.()
368
+ }
369
+ schedulePoll()
360
370
 
361
- return () => {
362
- disposed = true
363
- if (timer) nativeClearTimeout(timer)
364
- if (pollTimer) nativeClearTimeout(pollTimer)
365
- watcher.close()
366
- }
367
- } catch {
368
- return () => {}
371
+ return () => {
372
+ disposed = true
373
+ if (timer) nativeClearTimeout(timer)
374
+ if (pollTimer) nativeClearTimeout(pollTimer)
375
+ watcher?.close()
369
376
  }
370
377
  }
@@ -682,7 +682,7 @@ function QuotaSidebar(props) {
682
682
  const needsReauth = () => enabledFallbacks().some(f => f.needsReauth);
683
683
  const degraded = () => quotaBackedOff() || refreshBackedOff() || needsReauth();
684
684
  const fableRecoverySummary = () => getFableRecoverySummary(state(), props.sessionId);
685
- const fableRecoveryTone = () => state().fableRecoveries?.find(recovery => recovery.sessionId === props.sessionId)?.mode === 'opus' ? 'warn' : 'ok';
685
+ const fableRecoveryTone = () => state().fableRecoveries?.find(recovery => recovery.sessionId === props.sessionId)?.mode === 'fable' ? 'ok' : 'warn';
686
686
  const cacheKeep = () => state().cacheKeep;
687
687
  const showCache = () => prefs().sections.cache && cacheKeep() != null && cacheKeep()?.window != null;
688
688
  const relayValue = () => {
@@ -1,4 +1,4 @@
1
- import { watch } from 'node:fs'
1
+ import { readFileSync, watch } from 'node:fs'
2
2
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
3
3
  import { homedir } from 'node:os'
4
4
  import { basename, dirname, join } from 'node:path'
@@ -292,12 +292,22 @@ const WATCH_POLL_MS = 100
292
292
  // events, and against mtime granularity.
293
293
  //
294
294
  // Returns a disposer; never throws.
295
- export function watchTuiPreferences(onChange: () => void): () => void {
295
+ export function watchTuiPreferences(
296
+ onChange: () => void,
297
+ options: { watchDirectory?: typeof watch } = {},
298
+ ): () => void {
296
299
  const file = getTuiPreferencesFile()
297
300
  const name = basename(file)
298
301
  let timer: ReturnType<typeof nativeSetTimeout> | null = null
302
+ // Capture the baseline before returning. An asynchronous seed can resolve
303
+ // after the caller's first write and absorb that change as already seen.
299
304
  let lastSeen: string | null = null
300
- let observedEvent = false
305
+ try {
306
+ lastSeen = readFileSync(file, 'utf8')
307
+ } catch {
308
+ // Missing/unreadable files can still be created later and detected by the
309
+ // directory watcher or polling fallback.
310
+ }
301
311
  let disposed = false
302
312
 
303
313
  const checkForChange = async () => {
@@ -309,7 +319,6 @@ export function watchTuiPreferences(onChange: () => void): () => void {
309
319
  }
310
320
 
311
321
  const scheduleCheck = () => {
312
- observedEvent = true
313
322
  if (timer) nativeClearTimeout(timer)
314
323
  timer = nativeSetTimeout(() => {
315
324
  timer = null
@@ -317,54 +326,52 @@ export function watchTuiPreferences(onChange: () => void): () => void {
317
326
  }, WATCH_DEBOUNCE_MS)
318
327
  }
319
328
 
320
- // Seed asynchronously. If a real file event arrives before the read resolves,
321
- // do not let the seed overwrite that pending change; the debounced re-read
322
- // will compare against the previous value and fire.
323
- void readFile(file, 'utf8')
324
- .then((text) => {
325
- if (!observedEvent && lastSeen === null) lastSeen = text
326
- })
327
- .catch(() => {})
328
-
329
+ let watcher: ReturnType<typeof watch> | null = null
329
330
  try {
330
- const watcher = watch(dirname(file), (_event, filename) => {
331
- // Exact match against the preferences file name, plus the temp file
332
- // we use for atomic writes (carrying our pid + `.tmp`).
333
- const isOurs =
334
- filename === name ||
335
- (filename?.startsWith(`${name}.`) && filename.endsWith('.tmp'))
336
- if (filename != null && !isOurs) return
337
- scheduleCheck()
338
- })
331
+ watcher = (options.watchDirectory ?? watch)(
332
+ dirname(file),
333
+ (_event, filename) => {
334
+ // Exact match against the preferences file name, plus the temp file
335
+ // we use for atomic writes (carrying our pid + `.tmp`).
336
+ const isOurs =
337
+ filename === name ||
338
+ (filename?.startsWith(`${name}.`) && filename.endsWith('.tmp'))
339
+ if (filename != null && !isOurs) return
340
+ scheduleCheck()
341
+ },
342
+ )
343
+ } catch {
344
+ // If the file exists, polling remains a complete fallback even when Bun
345
+ // cannot allocate a directory watcher (for example, transient EBADF).
346
+ // If neither the file nor its directory can be observed, remain a no-op.
347
+ if (lastSeen === null) return () => {}
348
+ }
339
349
 
340
- // Bun's fs.watch can miss atomic temp-file rename updates on some
341
- // backends, so keep a low-cost polling loop as the correctness path.
342
- // Use recursive timers instead of fs.watchFile because watchFile can keep
343
- // Bun test processes alive long after unwatchFile().
344
- let pollTimer: ReturnType<typeof nativeSetTimeout> | null = null
345
- let pollInFlight = false
346
- const schedulePoll = () => {
347
- if (disposed || pollTimer) return
348
- pollTimer = nativeSetTimeout(() => {
349
- pollTimer = null
350
- if (disposed || pollInFlight) return
351
- pollInFlight = true
352
- void checkForChange().finally(() => {
353
- pollInFlight = false
354
- schedulePoll()
355
- })
356
- }, WATCH_POLL_MS)
357
- pollTimer.unref?.()
358
- }
359
- schedulePoll()
350
+ // Bun's fs.watch can miss atomic temp-file renames and can itself fail after
351
+ // repeated close/recreate cycles, so polling must be independent of watcher
352
+ // construction. Recursive unreferenced timers avoid fs.watchFile's lingering
353
+ // handles while the host's normal event loop keeps active watchers polling.
354
+ let pollTimer: ReturnType<typeof nativeSetTimeout> | null = null
355
+ let pollInFlight = false
356
+ const schedulePoll = () => {
357
+ if (disposed || pollTimer) return
358
+ pollTimer = nativeSetTimeout(() => {
359
+ pollTimer = null
360
+ if (disposed || pollInFlight) return
361
+ pollInFlight = true
362
+ void checkForChange().finally(() => {
363
+ pollInFlight = false
364
+ schedulePoll()
365
+ })
366
+ }, WATCH_POLL_MS)
367
+ pollTimer.unref?.()
368
+ }
369
+ schedulePoll()
360
370
 
361
- return () => {
362
- disposed = true
363
- if (timer) nativeClearTimeout(timer)
364
- if (pollTimer) nativeClearTimeout(pollTimer)
365
- watcher.close()
366
- }
367
- } catch {
368
- return () => {}
371
+ return () => {
372
+ disposed = true
373
+ if (timer) nativeClearTimeout(timer)
374
+ if (pollTimer) nativeClearTimeout(pollTimer)
375
+ watcher?.close()
369
376
  }
370
377
  }
package/src/tui.tsx CHANGED
@@ -644,9 +644,9 @@ function QuotaSidebar(props: {
644
644
  const fableRecoveryTone = (): Tone =>
645
645
  state().fableRecoveries?.find(
646
646
  (recovery) => recovery.sessionId === props.sessionId,
647
- )?.mode === 'opus'
648
- ? 'warn'
649
- : 'ok'
647
+ )?.mode === 'fable'
648
+ ? 'ok'
649
+ : 'warn'
650
650
  const cacheKeep = () => state().cacheKeep
651
651
  const showCache = () =>
652
652
  prefs().sections.cache && cacheKeep() != null && cacheKeep()?.window != null