@cortexkit/opencode-anthropic-auth 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/index-4wz5npbg.js +325 -0
- package/dist/index-nfgq84t3.js +2 -0
- package/dist/index.js +3 -3
- package/dist/sidebar-state.d.ts +42 -0
- package/dist/sidebar-state.js +1 -0
- package/dist/tui.d.ts +6 -0
- package/package.json +16 -3
- package/src/sidebar-state.ts +79 -0
- package/src/tui.tsx +401 -0
- package/dist/index-wc8ekdxb.js +0 -325
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{m as y,n as w,p as l,q as u,
|
|
2
|
+
import{m as y,n as w,p as l,q as u,qa as b,r as m,sa as k}from"./index-4wz5npbg.js";import{stdin as A,stdout as $}from"node:process";import{createInterface as R}from"node:readline/promises";function v(){return{version:1,main:{type:"opencode",provider:"anthropic"},fallbackOn:[401,403,429],refresh:{enabled:!0,intervalMinutes:10,refreshBeforeExpiryMinutes:240},quota:{enabled:!0,checkIntervalMinutes:5,minimumRemaining:{five_hour:10,seven_day:20},failClosedOnUnknownQuota:!0},accounts:[]}}function h(){console.log(`Usage:
|
|
3
3
|
opencode-anthropic-auth login [label]
|
|
4
4
|
opencode-anthropic-auth list
|
|
5
5
|
opencode-anthropic-auth relay setup
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
var s="9d1c250a-e61b-44d9-88ed-5944d1962f5e",uf={console:"https://platform.claude.com/oauth/authorize",max:"https://claude.ai/oauth/authorize"},jf="https://platform.claude.com/oauth/code/callback",bf="https://platform.claude.com/v1/oauth/token",df=["org:create_api_key","user:profile","user:inference","user:sessions:claude_code","user:mcp_servers","user:file_upload"],Lm="mcp_";var gf="fast-mode-2026-02-01";function Xm(f,_){let m=(f??"").split(",").map(($)=>$.trim()).filter(Boolean);return[...new Set([...m,..._])].join(",")}function Zm(f){return typeof f==="string"&&(f.startsWith("claude-opus-4-6")||f.startsWith("claude-opus-4-7")||f.startsWith("claude-opus-4-8"))}var Ym="You are OpenCode",Am="You are a Claude agent, built on Anthropic's Claude Agent SDK.",Qm=["<use_parallel_tool_calls>","For maximum efficiency, whenever you perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially. Prioritize calling independent tools in parallel whenever possible. For example, when reading 3 known files, run 3 tool calls in parallel to read all 3 files into context at the same time. When running multiple independent read-only commands like `ls` or `list_dir`, run all of those commands in parallel. Err on the side of maximizing parallel tool calls for independent work rather than running too many tools sequentially.","","Do not parallelize tool calls when one call depends on the output of another call. If a tool call needs an ID, filename, search result, or any other value returned by a previous tool call, run the first call, wait for its result, then run the dependent call using the real returned value. Never invent placeholder IDs, guessed task IDs, or other guessed values for dependent tool calls just to place them in the same parallel block.","</use_parallel_tool_calls>"].join(`
|
|
2
|
+
`);var x="2.1.141",Kf="67b",nf="sdk-cli",cf="0.94.0",sf="v24.3.0",rf="claude-cli/2.1.141 (external, sdk-cli)",tf=["explicit","automatic","hybrid"],r="explicit",xm=["github.com/anomalyco/opencode","opencode.ai/docs"],Im=[{match:"if OpenCode honestly",replacement:"if the assistant honestly"},{match:"Here is some useful information about the environment you are running in:",replacement:"Environment context you are running in:"}];function of(f){let _="";for(let m of f)_+=String.fromCharCode(m);return btoa(_).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function af(){let f=new Uint8Array(64);crypto.getRandomValues(f);let _=of(f),m=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(_));return{verifier:_,challenge:of(new Uint8Array(m)),method:"S256"}}function $1(f){if(!f)return;let _=Number(f);if(Number.isFinite(_)&&_>0)return Math.ceil(_);let m=Date.parse(f);if(Number.isFinite(m)){let $=Math.ceil((m-Date.now())/1000);return $>0?$:void 0}return}class q extends Error{status;body;retryAfter;constructor(f,_,m){super(`Claude OAuth refresh failed: ${f} — ${_}`);this.status=f,this.body=_,this.name="ClaudeOAuthRefreshError",this.retryAfter=$1(m??void 0)}}function D1(f){if(!(f instanceof Error))return!1;let _=f.code;return f.message.includes("fetch failed")||_==="ECONNRESET"||_==="ECONNREFUSED"||_==="ETIMEDOUT"||_==="UND_ERR_CONNECT_TIMEOUT"}async function ef(f){let _=f.fetchImpl??fetch,m=f.maxRetries??2,$=f.baseDelayMs??500;for(let D=0;D<=m;D++)try{if(D>0){let U=$*2**(D-1);await new Promise((j)=>setTimeout(j,U))}let E=await _(bf,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","User-Agent":"axios/1.13.6"},body:JSON.stringify({grant_type:"refresh_token",refresh_token:f.refreshToken,client_id:s})});if(!E.ok){if(E.status>=500&&D<m){await E.body?.cancel().catch(()=>{});continue}let U=await E.text().catch(()=>"");throw new q(E.status,U,E.headers.get("retry-after"))}let C=await E.json(),H=f.now?.()??Date.now();return{access:C.access_token,refresh:C.refresh_token??f.refreshToken,expires:H+C.expires_in*1000,expiresIn:C.expires_in}}catch(E){if(E instanceof q)throw E;if(D<m&&D1(E))continue;throw E}throw Error("Token refresh exhausted all retries")}function E1(){return crypto.randomUUID().replace(/-/g,"")}function C1(f){let _=f.trim();try{let C=new URL(_),H=C.searchParams.get("code"),U=C.searchParams.get("state");if(H&&U)return{code:H,state:U}}catch{}let m=_.split("#");if(m.length===2&&m[0]&&m[1])return{code:m[0],state:m[1]};let $=new URLSearchParams(_),D=$.get("code"),E=$.get("state");if(D&&E)return{code:D,state:E};return null}async function H1(f,_,m){let $=await fetch(bf,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json, text/plain, */*","User-Agent":"axios/1.13.6"},body:JSON.stringify({code:f.code,state:f.state,grant_type:"authorization_code",client_id:s,redirect_uri:m,code_verifier:_})});if(!$.ok)return{type:"failed"};let D=await $.json();return{type:"success",refresh:D.refresh_token,access:D.access_token,expires:Date.now()+D.expires_in*1000}}async function Rm(f){let _=await af(),m=E1(),$=new URL(uf[f],import.meta.url);return $.searchParams.set("code","true"),$.searchParams.set("client_id",s),$.searchParams.set("response_type","code"),$.searchParams.set("redirect_uri",jf),$.searchParams.set("scope",df.join(" ")),$.searchParams.set("code_challenge",_.challenge),$.searchParams.set("code_challenge_method","S256"),$.searchParams.set("state",m),{url:$.toString(),redirectUri:jf,state:m,verifier:_.verifier}}async function wm(f,_,m,$){let D=C1(f);if(!D)return{type:"failed"};if($&&D.state!==$)return{type:"failed"};return H1(D,_,m)}import*as f0 from"node:fs";import*as _0 from"node:os";import*as m0 from"node:path";var U1=m0.join(_0.tmpdir(),"opencode-anthropic-auth.log"),$0=!1,M1=500,S1=50,y=[],i=null;function Nf(){if(i)clearTimeout(i),i=null;if(y.length===0)return;let f=y.join("");y=[];try{f0.appendFileSync(U1,f)}catch{}}function j1(){if(i)return;i=setTimeout(()=>{i=null,Nf()},M1)}function b1(f){if(f===void 0)return"";if(f instanceof Error)return` ${f.message}${f.stack?`
|
|
3
|
+
${f.stack}`:""}`;return` ${JSON.stringify(f)}`}function Z(f,_){if($0)return;try{if(y.push(`[${new Date().toISOString()}] ${f}${b1(_)}
|
|
4
|
+
`),y.length>=S1)Nf();else j1()}catch{}}function F(f,_){Z(`[relay] ${f}`,_)}if(!$0)process.on("exit",Nf);import{createHash as S0,randomUUID as zf}from"node:crypto";import{mkdir as K1,readFile as t,rename as N1,rm as D0,stat as F1,writeFile as Jf}from"node:fs/promises";import{homedir as G1}from"node:os";import{dirname as J1,join as o}from"node:path";var z1=globalThis.setTimeout.bind(globalThis),W1=globalThis.clearTimeout.bind(globalThis),O1="anthropic-auth.json",B1="https://api.anthropic.com/api/oauth/usage",V1=[401,403,429],j0=240,L1=j0;var X1=300000,Z1=3600000,Y1=86400000,A1=60000,Q1=900000,x1=300000,I1=5,E0={five_hour:0,seven_day:0},q1=!0,P1=60000,h1=60000,T1=600000,R1=1e4,w1=100;function i1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return o(process.env.XDG_CONFIG_HOME||o(G1(),".config"),"opencode")}function L(){return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim()||o(i1(),O1)}function z(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function k1(f){if(!z(f))return null;if(f.type!=="oauth")return null;if(typeof f.refresh!=="string"||!f.refresh.trim())return null;return{id:typeof f.id==="string"&&f.id.trim()?f.id.trim():zf(),label:typeof f.label==="string"?f.label:void 0,type:"oauth",access:typeof f.access==="string"?f.access:void 0,refresh:f.refresh,expires:typeof f.expires==="number"?f.expires:void 0,enabled:typeof f.enabled==="boolean"?f.enabled:void 0,addedAt:typeof f.addedAt==="number"?f.addedAt:void 0,lastUsed:typeof f.lastUsed==="number"?f.lastUsed:void 0,lastRefreshedAt:typeof f.lastRefreshedAt==="number"?f.lastRefreshedAt:void 0,lastRefreshError:C0(f.lastRefreshError),lastQuotaRefreshError:C0(f.lastQuotaRefreshError),quota:l1(f.quota)}}function C0(f){if(!z(f))return;if(typeof f.message!=="string")return;let _=Number(f.checkedAt);if(!Number.isFinite(_))return;let m=Number(f.nextRetryAt),$=Number(f.retryCount);return{message:f.message,checkedAt:_,nextRetryAt:Number.isFinite(m)?m:void 0,retryCount:Number.isFinite($)?$:void 0,tokenHash:typeof f.tokenHash==="string"?f.tokenHash:void 0}}function l1(f){if(!z(f))return;let _={};for(let m of["five_hour","seven_day"]){let $=f[m];if(!z($))continue;let D=Number($.usedPercent),E=Number($.remainingPercent),C=Number($.checkedAt);if(!Number.isFinite(D)||!Number.isFinite(E)||!Number.isFinite(C))continue;_[m]={usedPercent:D,remainingPercent:E,checkedAt:C,resetsAt:typeof $.resetsAt==="string"?$.resetsAt:void 0}}return Object.keys(_).length?_:void 0}function y1(f){if(!z(f)||!Array.isArray(f.accounts))return null;return{version:1,main:{type:"opencode",provider:"anthropic"},routing:z(f.routing)?f.routing:void 0,fallbackOn:Array.isArray(f.fallbackOn)?f.fallbackOn.filter((_)=>Number.isInteger(_)):void 0,refresh:z(f.refresh)?f.refresh:void 0,quota:z(f.quota)?f.quota:void 0,claudeCache:z(f.claudeCache)?f.claudeCache:void 0,dump:z(f.dump)?f.dump:void 0,claudeFast:z(f.claudeFast)?f.claudeFast:void 0,cacheKeep:z(f.cacheKeep)?f.cacheKeep:void 0,relay:z(f.relay)?f.relay:void 0,accounts:f.accounts.map(k1).filter((_)=>_!=null)}}async function Y(f=L()){try{let _=await t(f,"utf8");return y1(JSON.parse(_))}catch(_){if(_.code==="ENOENT")return null;return null}}async function p1(f){try{let _=await t(f,"utf8"),m=JSON.parse(_);return z(m)?m:{}}catch{return{}}}function v1(f){return Object.fromEntries(Object.entries(f).filter(([,_])=>_!==void 0))}async function A(f,_=L()){await K1(J1(_),{recursive:!0});let $={...await p1(_),...v1(f)},D=`${_}.${zf()}.tmp`;await Jf(D,`${JSON.stringify($,null,2)}
|
|
5
|
+
`,{encoding:"utf8",mode:384}),await N1(D,_)}async function Wf(f){let m=`${f.path??L()}.${f.name}.lock`,$=o(m,"owner.json"),D=zf(),E=f.now??Date.now,C=null,H=!1;async function U(){try{return JSON.parse(await t(m,"utf8"))}catch(N){if(N.code!=="EISDIR")throw N;return JSON.parse(await t($,"utf8"))}}async function j(){await Jf(m,`${JSON.stringify({ownerId:D,expiresAt:E()+f.ttlMs})}
|
|
6
|
+
`,{encoding:"utf8",mode:384})}async function b(){try{return await Jf(m,`${JSON.stringify({ownerId:D,expiresAt:E()+f.ttlMs})}
|
|
7
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(N){let G=N.code;if(G==="EEXIST"||G==="EISDIR")return!1;throw N}}function K(){if(!f.renew||H)return;let N=f.renewIntervalMs??Math.max(1000,Math.floor(f.ttlMs/3));if(C=z1(()=>{(async()=>{try{let G=await U(),S=E();if(H||G?.ownerId!==D||Number(G?.expiresAt)<=S)return;await j(),K()}catch{}})()},N),"unref"in C)C.unref()}if(!await b()){try{let N=await U();if(Number(N?.expiresAt)>E())return null}catch{try{if((await F1(m)).mtimeMs+f.ttlMs>Date.now())return null}catch{return null}}if(await D0(m,{recursive:!0,force:!0}).catch(()=>{}),!await b())return null}return K(),{release:async()=>{if(H=!0,C)W1(C),C=null;try{if((await U())?.ownerId!==D)return}catch{return}await D0(m,{recursive:!0,force:!0}).catch(()=>{})}}}function nm(f){return f?.claudeCache?.enabled===!0}function u1(f){return typeof f==="string"&&tf.includes(f)?f:r}function d1(f){return u1(f?.claudeCache?.mode)}async function cm(f,_,m=L()){let $=await Y(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return $.claudeCache={...$.claudeCache??{},enabled:f,mode:_??d1($)},await A($,m),$}async function sm(f,_=L()){let m=await Y(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return m.claudeCache={...m.claudeCache??{},enabled:m.claudeCache?.enabled===!0,mode:f},await A(m,_),m}function rm(f){return f?.dump?.enabled===!0}async function tm(f,_=L()){let m=await Y(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return m.dump={...m.dump??{},enabled:f},await A(m,_),m}function om(f){return f?.claudeFast?.enabled===!0}async function am(f,_=L()){let m=await Y(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return m.claudeFast={...m.claudeFast??{},enabled:f},await A(m,_),m}async function em(f,_,m=L()){let $=await Y(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return $.cacheKeep={enabled:!0,startHour:f,endHour:_},await A($,m),$}async function f$(f,_=L()){let m=await Y(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return m.cacheKeep={...m.cacheKeep??{},enabled:f},await A(m,_),m}function g1(f){return f?.fallbackOn?.length?f.fallbackOn:V1}function _$(f,_){return g1(_).includes(f)}function b0(f){let _=f?.quota?.minimumRemaining||{};return{five_hour:_.five_hour??_["5h"]??E0.five_hour,seven_day:_.seven_day??_["1w"]??E0.seven_day}}function v(f){return f?.quota?.enabled!==!1}function n1(f){return f?.refresh?.enabled!==!1}function c1(f){return Math.floor(Math.random()*Math.max(0,f))}function s1(f){let _=f?.refresh?.refreshBeforeExpiryMinutes??L1;return Math.max(j0,_)*60000}function K0(f){return S0("sha256").update(f).digest("hex")}function r1(f){if(f instanceof q)return f.status===429||f.status>=500;if(!(f instanceof Error))return!1;return f.message.includes("fetch failed")||"code"in f&&(f.code==="ECONNRESET"||f.code==="ECONNREFUSED"||f.code==="ETIMEDOUT"||f.code==="UND_ERR_CONNECT_TIMEOUT")}function t1(f){let _=K0(f.refreshToken),$=(f.previous?.tokenHash===_?f.previous.retryCount??0:0)+1,D;if(f.error instanceof q&&f.error.retryAfter)D=f.error.retryAfter*1000;else if(r1(f.error))D=Math.min(Z1,X1*2**Math.min($-1,6));else D=Y1;return{message:u(f.error),checkedAt:f.now,nextRetryAt:f.now+D,retryCount:$,tokenHash:_}}function p(f,_,m){if(!f?.nextRetryAt||f.nextRetryAt<=m)return!1;if(!_)return!0;return f.tokenHash===K0(_)}function Ff(f,_){return`Claude OAuth refresh is backed off for ${Math.max(1,Math.ceil(((f.nextRetryAt??_)-_)/1000))}s after: ${f.message}`}function a(f){let m=(f.previous?.retryCount??0)+1,$=z0(f.error)?Math.min(Q1,A1*2**Math.min(m-1,6)):x1;return{message:u(f.error),checkedAt:f.now,nextRetryAt:f.now+$,retryCount:m}}function k(f,_){if(!f?.nextRetryAt||f.nextRetryAt<=_)return!1;return!0}function X(f){let _=f?.quota?.checkIntervalMinutes??I1;return Math.max(1,_)*60000}function N0(f){if(!f?.quota?.mainQuota||!f.quota.mainQuotaCheckedAt)return null;return{quota:f.quota.mainQuota,checkedAt:f.quota.mainQuotaCheckedAt,tokenFingerprint:f.quota.mainQuotaToken}}function F0(f){let _=f?.quota?.refreshEveryNRequests;return typeof _==="number"&&Number.isFinite(_)&&_>0?Math.floor(_):0}function G0(f){return f?.quota?.failClosedOnUnknownQuota??q1}function J0(f,_){if(!v(_))return!0;let m=b0(_);for(let $ of["five_hour","seven_day"]){let D=f?.[$];if(!D)return!G0(_);if(D.remainingPercent<m[$])return!1}return!0}function Of(f,_,m){if(!v(_))return m+X(_);let $=b0(_),D=[];for(let E of["five_hour","seven_day"]){let C=f?.[E];if(!C)return m+X(_);if(C.remainingPercent>=$[E])continue;let H=C.resetsAt?Date.parse(C.resetsAt):Number.NaN;if(!Number.isFinite(H)||H<=m)return m+X(_);D.push(H)}if(!D.length)return m+X(_);return Math.min(...D)+60000}function P(f,_,m){return!f.access||!f.expires||f.expires-m<=s1(_)}function Gf(f,_,m){if(!v(_))return!1;let $=X(_);return["five_hour","seven_day"].some((D)=>{let E=f.quota?.[D];return!E||m-E.checkedAt>=$})}function o1(f,_){if(!f)return!1;if(!f.resetsAt)return!0;let m=Date.parse(f.resetsAt);return!Number.isFinite(m)||m>_}function a1(f,_){return["five_hour","seven_day"].every((m)=>o1(f?.[m],_))}function z0(f){let _=u(f);if(/Claude quota check failed: (429|5\d\d)\b/.test(_))return!0;if(!(f instanceof Error))return!1;let m=f.code;return _.includes("fetch failed")||m==="ECONNRESET"||m==="ECONNREFUSED"||m==="ETIMEDOUT"||m==="UND_ERR_CONNECT_TIMEOUT"}function e1(f,_,m,$){return z0(m)&&J0(f.quota,_)&&a1(f.quota,$)}function H0(f){if(!Number.isFinite(f))return 0;if(f<0)return 0;if(f>100)return 100;return f}function U0(f,_){if(typeof f?.utilization!=="number")return;let m=H0(f.utilization);return{usedPercent:m,remainingPercent:H0(100-m),resetsAt:f.resets_at,checkedAt:_}}async function e(f){let m=await(f.fetchImpl??fetch)(B1,{method:"GET",headers:{Authorization:`Bearer ${f.accessToken}`,Accept:"application/json","Content-Type":"application/json","anthropic-beta":"oauth-2025-04-20","User-Agent":`claude-code/${x}`}});if(!m.ok){let E=await m.text().catch(()=>"");throw Error(`Claude quota check failed: ${m.status} — ${E}`)}let $=f.now?.()??Date.now(),D=await m.json();return{five_hour:U0(D.five_hour,$),seven_day:U0(D.seven_day,$)}}function V(f,_){let m=f.accounts.findIndex(($)=>$.id===_.id);if(m>=0)f.accounts[m]=_}function u(f){return f instanceof Error?f.message:String(f)}function W0(f,_,m){f.lastRefreshError=t1({error:_,now:m,refreshToken:f.refresh,previous:f.lastRefreshError})}function M0(f,_,m){if(f.lastQuotaRefreshError=a({error:_,now:m,previous:f.lastQuotaRefreshError}),_ instanceof q)W0(f,_,m)}function f_(f){return`fallback-oauth-refresh-${S0("sha256").update(f).digest("hex").slice(0,16)}`}class __{now;fetchImpl;configPath;refreshPromises=new Map;refreshTimer=null;quotaTimer=null;quotaManager;constructor(f={}){this.now=f.now??Date.now,this.fetchImpl=f.fetchImpl??fetch,this.configPath=f.configPath??L(),this.quotaManager=f.quotaManager??null}seedFallbackQuota(f,_){if(!this.quotaManager)return;if(this.quotaManager.getFallback(f.id,f.access))return;if(!f.quota)return;let m=Math.max(f.quota.five_hour?.checkedAt??0,f.quota.seven_day?.checkedAt??0);if(m<=0)return;let $=X(_);this.quotaManager.setFallback(f.id,{quota:f.quota,refreshAfter:m+$,checkedAt:m},f.access)}async load(){return Y(this.configPath)}async save(f){await A(f,this.configPath)}startBackgroundRefresh(){let f=async()=>{await this.refreshDueAccounts(),await this.refreshQuotaForDueAccounts()};if(f().catch(()=>{}),!this.refreshTimer){if(this.refreshTimer=setInterval(()=>{f().catch(()=>{})},P1+c1(h1)),"unref"in this.refreshTimer)this.refreshTimer.unref()}}stopBackgroundRefresh(){if(this.refreshTimer)clearInterval(this.refreshTimer);if(this.quotaTimer)clearInterval(this.quotaTimer);this.refreshTimer=null,this.quotaTimer=null}async getUsableFallbackAccounts(f){let _=f!==void 0?f:await this.load();if(!_)return[];let m=[],$=!1;for(let D of _.accounts){if(D.enabled===!1)continue;try{let E=D;if(P(E,_,this.now())){let H=E.lastRefreshError;if(H&&p(H,E.refresh,this.now()))throw Error(Ff(H,this.now()));E=await this.refreshAccount(E,_),$=!0}if(this.seedFallbackQuota(E,_),(this.quotaManager?this.quotaManager.isFallbackStale(E.id,E.access):Gf(E,_,this.now()))&&!k(E.lastQuotaRefreshError,this.now()))E=await this.refreshAccountQuota(E,_),$=!0;if(this.accountPassesQuotaPolicy(this.quotaPolicyAccount(E),_))m.push(E)}catch(E){if(e1(D,_,E,this.now()))Z("[refresh] fallback quota using cached quota after refresh error",{accountId:D.id,error:u(E)}),m.push(D);else if(!G0(_))m.push(D)}}if($)await this.save(_);return m}async markUsed(f){let _=await this.load();if(!_)return;let m=_.accounts.find(($)=>$.id===f.id);if(!m)return;m.lastUsed=this.now(),await this.save(_)}accountPassesQuotaPolicy(f,_){return J0(f.quota,_)}quotaPolicyAccount(f){if(!this.quotaManager)return f;let _=this.quotaManager.getFallback(f.id,f.access)?.quota;return _?{...f,quota:_}:f}async refreshDueAccounts(){let f=await this.load();if(!f||!n1(f))return;let _=!1;for(let m of f.accounts){if(m.enabled===!1)continue;if(!P(m,f,this.now()))continue;if(p(m.lastRefreshError,m.refresh,this.now()))continue;try{Z("[refresh] fallback oauth background due",{accountId:m.id,expiresInMs:m.expires?m.expires-this.now():void 0}),await this.refreshAccount(m,f),_=!0}catch($){Z("[refresh] fallback oauth background failed",{accountId:m.id,error:$ instanceof Error?$.message:String($)}),W0(m,$,this.now()),V(f,m),_=!0}}if(_)await this.save(f)}async refreshQuotaForDueAccounts(){let f=await this.load();if(!f||!v(f))return;let _=!1;for(let m of f.accounts){if(m.enabled===!1)continue;let $=m;try{if(P($,f,this.now())){if(p($.lastRefreshError,$.refresh,this.now()))continue;$=await this.refreshAccount($,f),_=!0}if(k($.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota($,f),!(this.quotaManager?this.quotaManager.isFallbackStale($.id,$.access):Gf($,f,this.now())))continue;await this.refreshAccountQuota($,f),_=!0}catch(D){M0(m,D,this.now()),V(f,m),_=!0}}if(_)await this.save(f)}async refreshQuotaForAllAccounts(f={}){let _=await this.load(),m=[];if(!_||!v(_))return{storage:_,errors:m};let $=f.force??!1,D=!1;for(let E of _.accounts){if(E.enabled===!1)continue;let C=E;try{if(P(C,_,this.now())){let H=C.lastRefreshError;if(H&&p(H,C.refresh,this.now()))throw Error(Ff(H,this.now()));C=await this.refreshAccount(C,_),D=!0}if(!$&&!Gf(C,_,this.now())){if(C.lastQuotaRefreshError)C.lastQuotaRefreshError=void 0,V(_,C),D=!0;continue}await this.refreshAccountQuota(C,_),D=!0}catch(H){M0(E,H,this.now()),V(_,E),D=!0,m.push({accountId:E.id,message:u(H)})}}if(D)await this.save(_);return{storage:_,errors:m}}async refreshAccount(f,_,m={}){let $=this.refreshPromises.get(f.id);if($){let C=await $;return V(_,C),C}let D=this.refreshAccountNow(f,_,m).finally(()=>{this.refreshPromises.delete(f.id)});this.refreshPromises.set(f.id,D);let E=await D;return V(_,E),E}async waitForConcurrentFallbackRefresh(f,_,m,$){let D=Date.now()+R1;while(Date.now()<D){await new Promise((j)=>setTimeout(j,w1));let E=await this.load(),C=E?.accounts.find((j)=>j.id===f.id);if(!C)continue;if((C.access!==m.access||C.refresh!==m.refresh||(C.expires??0)>(m.expires??0)+60000)&&($.force||!P(C,E,this.now())))return V(_,C),Z("[refresh] fallback oauth joined concurrent refresh",{accountId:C.id,expiresInMs:C.expires?C.expires-this.now():void 0}),C;let U=C.lastRefreshError;if(U&&p(U,C.refresh,this.now()))throw V(_,C),Error(Ff(U,this.now()))}return null}async refreshAccountNow(f,_,m){let $=await this.load(),D=$?.accounts.find((H)=>H.id===f.id);if(D&&!m.force&&!P(D,$,this.now()))return V(_,D),D;let E=D??f,C=await Wf({name:f_(E.id),ttlMs:T1,path:this.configPath,now:this.now,renew:!0});if(!C){Z("[refresh] fallback oauth refresh skipped file lock",{accountId:E.id});let H=await this.waitForConcurrentFallbackRefresh(f,_,E,m);if(H)return H;throw Error("Fallback OAuth refresh is already in progress")}try{if($=await this.load(),D=$?.accounts.find((j)=>j.id===f.id),D&&!m.force&&!P(D,$,this.now()))return V(_,D),D;E=D??E;let H=E.refresh;Z("[refresh] fallback oauth refresh request start",{accountId:E.id,force:m.force===!0,expiresInMs:E.expires?E.expires-this.now():void 0});let U=await ef({refreshToken:H,fetchImpl:this.fetchImpl,now:this.now});return E.access=U.access,E.refresh=U.refresh,E.expires=U.expires,E.lastRefreshedAt=U.expires-U.expiresIn*1000,E.lastRefreshError=void 0,V(_,E),await this.save(_),Z("[refresh] fallback oauth refresh succeeded",{accountId:E.id,expiresInMs:E.expires?E.expires-this.now():void 0}),E}finally{await C.release()}}async refreshAccountQuota(f,_){let m=f;if(!m.access)throw Error(`Fallback account ${f.id} has no access token`);let $=(D)=>this.quotaManager?this.quotaManager.refreshFallback(m.id,D):e({accessToken:D,fetchImpl:this.fetchImpl,now:this.now});try{m.quota=await $(m.access)}catch(D){if(!(D instanceof Error?D.message:String(D)).includes("Claude quota check failed: 401"))throw D;if(m=await this.refreshAccount(f,_,{force:!0}),!m.access)throw D;m.quota=await $(m.access)}if(m.lastQuotaRefreshError=void 0,V(_,m),this.quotaManager&&m.quota){let D=this.now();this.quotaManager.setFallback(m.id,{quota:m.quota,refreshAfter:D+X(_),checkedAt:D},m.access)}return m}}var D$="claude-cache",O0="## Claude Cache Status",m_="## Claude Cache Enabled",$_="## Claude Cache Disabled",D_="## Claude Cache Usage",E_="Usage: `/claude-cache`, `/claude-cache on`, `/claude-cache off`, or `/claude-cache mode explicit|automatic|hybrid`.",ff=!1,_f=r;function E$(){return ff}function C$(){return _f}function H$(f){ff=f.enabled,_f=f.mode}function C_(f){let _=f.trim().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&_[0]==="on")return{type:"enable"};if(_.length===1&&_[0]==="off")return{type:"disable"};if(_.length===2&&_[0]==="mode"&&(_[1]==="explicit"||_[1]==="automatic"||_[1]==="hybrid"))return{type:"mode",mode:_[1]};return{type:"usage"}}function d(f){let _=f?.enabled??ff,m=f?.mode??_f;return[O0,"",`- Enabled: ${_?"enabled":"disabled"}`,`- Mode: ${m}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Scope: main sessions only; subagent sessions keep default ephemeral cache behavior","- Modes: explicit = existing OpenCode breakpoints; automatic = top-level cache_control only; hybrid = system + messages[0] + top-level cache_control","- TTL: 1h when enabled for main sessions; default ephemeral cache behavior otherwise"].join(`
|
|
8
|
+
`)}function U$(f){let _=C_(f.argumentsText),m=f.enabled??ff,$=f.mode??_f;if(_.type==="status")return d({enabled:m,mode:$});if(_.type==="enable")return[m_,"",d({enabled:!0,mode:$})].join(`
|
|
9
|
+
`);if(_.type==="disable")return[$_,"",d({enabled:!1,mode:$})].join(`
|
|
10
|
+
`);if(_.type==="mode")return[O0,"",`Mode updated to \`${_.mode}\`.`,"",d({enabled:m,mode:_.mode})].join(`
|
|
11
|
+
`);return[D_,"",E_,"",d({enabled:m,mode:$})].join(`
|
|
12
|
+
`)}import{randomBytes as H_,randomUUID as V0}from"node:crypto";var U_=1000,g=new Map;function Vf(f,_,m){if(!f.has(_)&&f.size>=U_){let $=f.keys().next().value;if($!==void 0)f.delete($)}f.set(_,m)}function L0(f){let _=f||"anonymous",m=g.get(_);if(m)return m;let $={deviceId:H_(32).toString("hex"),sessionId:V0()};return Vf(g,_,$),$}var Bf=new Map;async function M_(f,_){if(!f.startsWith("sk-ant-oat"))return null;let m=new AbortController,$=setTimeout(()=>m.abort(),5000);try{let D=new URL("https://api.anthropic.com/api/claude_cli/bootstrap");if(D.searchParams.set("entrypoint",nf),_)D.searchParams.set("model",_);let E=await fetch(D,{method:"GET",headers:{accept:"application/json, text/plain, */*",authorization:`Bearer ${f}`,"content-type":"application/json","anthropic-beta":"oauth-2025-04-20","user-agent":`claude-code/${x}`},signal:m.signal});if(!E.ok)return null;let H=(await E.json().catch(()=>null))?.oauth_account?.account_uuid;return typeof H==="string"&&H?H:null}catch{return null}finally{clearTimeout($)}}async function b$(f,_){let m=L0(f);if(!f.startsWith("sk-ant-oat"))return m;let $=Bf.get(f);if(!$)$=M_(f,_),Bf.set(f,$);let D=await $;if(!D)return Bf.delete(f),m;let E=`account:${D}`,C=g.get(E);if(C)return Vf(g,f,C),C;return m.accountUuid=D,Vf(g,E,m),m}function h(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function S_(f){if(!f.accountUuid)return null;return JSON.stringify({device_id:f.deviceId,account_uuid:f.accountUuid,session_id:f.sessionId})}function K$(f,_){let m=S_(_);if(!m){if(h(f.metadata))delete f.metadata.user_id;return!1}if(!h(f.metadata))f.metadata={};let $=f.metadata;if(h($))$.user_id=m;return!0}var j_=["claude-code-20250219","oauth-2025-04-20","interleaved-thinking-2025-05-14","context-management-2025-06-27","prompt-caching-scope-2026-01-05","advisor-tool-2026-03-01","advanced-tool-use-2025-11-20","context-1m-2025-08-07","effort-2025-11-24","extended-cache-ttl-2025-04-11","cache-diagnosis-2026-04-07"],b_=["oauth-2025-04-20","interleaved-thinking-2025-05-14","context-management-2025-06-27","prompt-caching-scope-2026-01-05","advisor-tool-2026-03-01","structured-outputs-2025-12-15","cache-diagnosis-2026-04-07"],B0=["oauth-2025-04-20","interleaved-thinking-2025-05-14","context-management-2025-06-27","prompt-caching-scope-2026-01-05","advisor-tool-2026-03-01","cache-diagnosis-2026-04-07"];function K_(f){return f.output_config?.format?.type==="json_schema"}function N_(f){return Array.isArray(f.tools)&&f.tools.length>0&&Array.isArray(f.system)&&h(f.thinking)&&h(f.context_management)&&h(f.output_config)&&h(f.diagnostics)}function F_(f,_=[]){let m=f?N_(f)?[...j_]:K_(f)?[...b_]:[...B0]:[...B0];if(f?.speed==="fast")m.push(gf);for(let $ of _){let D=$.trim();if(D)m.push(D)}return[...new Set(m)].join(",")}function G_(){switch(process.platform){case"darwin":return"MacOS";case"win32":return"Windows";case"linux":return"Linux";case"freebsd":return"FreeBSD";default:return"Unknown"}}function J_(){switch(process.arch){case"arm64":return"arm64";case"x64":return"x64";case"ia32":return"x32";default:return process.arch}}function N$(f,_,m={}){let $=m.identity??L0(_),E=[...(f.get("anthropic-beta")??"").split(",").map((C)=>C.trim()).filter(Boolean),...m.extraBetas??[]];return f.set("accept","application/json"),f.set("authorization",`Bearer ${_}`),f.set("content-type","application/json"),f.set("user-agent",rf),f.set("anthropic-beta",F_(m.body,E)),f.set("anthropic-dangerous-direct-browser-access","true"),f.set("anthropic-version","2023-06-01"),f.set("x-app","cli"),f.set("x-client-request-id",V0()),f.set("x-claude-code-session-id",$.sessionId),f.set("x-stainless-arch",J_()),f.set("x-stainless-lang","js"),f.set("x-stainless-os",G_()),f.set("x-stainless-package-version",cf),f.set("x-stainless-retry-count","0"),f.set("x-stainless-runtime","node"),f.set("x-stainless-runtime-version",sf),f.set("x-stainless-timeout","600"),f.delete("x-api-key"),f}var z_=["model","messages","system","tools","tool_choice","metadata","max_tokens","temperature","thinking","context_management","output_config","diagnostics","stream","speed"];function X0(f){let _={};for(let m of z_)if(Object.hasOwn(f,m))_[m]=f[m];for(let[m,$]of Object.entries(f))if(!Object.hasOwn(_,m))_[m]=$;return _}import{createHash as O_}from"node:crypto";var W_=new Uint8Array([0,97,115,109,1,0,0,0,1,48,8,96,3,127,127,127,1,127,96,3,127,127,127,0,96,2,127,127,0,96,1,127,1,127,96,3,127,127,126,1,126,96,3,126,127,127,1,126,96,2,127,126,0,96,1,127,1,126,3,11,10,0,0,2,1,3,4,5,6,1,7,5,3,1,0,1,7,85,9,3,109,101,109,2,0,5,120,120,104,51,50,0,0,6,105,110,105,116,51,50,0,2,8,117,112,100,97,116,101,51,50,0,3,8,100,105,103,101,115,116,51,50,0,4,5,120,120,104,54,52,0,5,6,105,110,105,116,54,52,0,7,8,117,112,100,97,116,101,54,52,0,8,8,100,105,103,101,115,116,54,52,0,9,10,251,22,10,242,1,1,4,127,32,0,32,1,106,33,3,32,1,65,16,79,4,127,32,3,65,16,107,33,6,32,2,65,168,136,141,161,2,106,33,3,32,2,65,137,235,208,208,7,107,33,4,32,2,65,207,140,162,142,6,106,33,5,3,64,32,3,32,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,3,32,4,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,4,32,2,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,2,32,5,32,0,65,4,106,34,0,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,5,32,6,32,0,65,4,106,34,0,79,13,0,11,32,2,65,12,119,32,5,65,18,119,106,32,4,65,7,119,106,32,3,65,1,119,106,5,32,2,65,177,207,217,178,1,106,11,32,1,106,32,0,32,1,65,15,113,16,1,11,146,1,0,32,1,32,2,106,33,2,3,64,32,1,65,4,106,32,2,75,69,4,64,32,0,32,1,40,2,0,65,189,220,202,149,124,108,106,65,17,119,65,175,214,211,190,2,108,33,0,32,1,65,4,106,33,1,12,1,11,11,3,64,32,1,32,2,79,69,4,64,32,0,32,1,45,0,0,65,177,207,217,178,1,108,106,65,11,119,65,177,243,221,241,121,108,33,0,32,1,65,1,106,33,1,12,1,11,11,32,0,32,0,65,15,118,115,65,247,148,175,175,120,108,34,0,65,13,118,32,0,115,65,189,220,202,149,124,108,34,0,65,16,118,32,0,115,11,63,0,32,0,65,8,106,32,1,65,168,136,141,161,2,106,54,2,0,32,0,65,12,106,32,1,65,137,235,208,208,7,107,54,2,0,32,0,65,16,106,32,1,54,2,0,32,0,65,20,106,32,1,65,207,140,162,142,6,106,54,2,0,11,195,4,1,6,127,32,1,32,2,106,33,6,32,0,65,24,106,33,4,32,0,65,40,106,40,2,0,33,3,32,0,32,0,40,2,0,32,2,106,54,2,0,32,0,65,4,106,34,5,32,5,40,2,0,32,2,65,16,79,32,0,40,2,0,65,16,79,114,114,54,2,0,32,2,32,3,106,65,16,73,4,64,32,3,32,4,106,32,1,32,2,252,10,0,0,32,0,65,40,106,32,2,32,3,106,54,2,0,15,11,32,3,4,64,32,3,32,4,106,32,1,65,16,32,3,107,34,2,252,10,0,0,32,0,65,8,106,34,3,32,3,40,2,0,32,4,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,54,2,0,32,0,65,12,106,34,3,32,3,40,2,0,32,4,65,4,106,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,54,2,0,32,0,65,16,106,34,3,32,3,40,2,0,32,4,65,8,106,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,54,2,0,32,0,65,20,106,34,3,32,3,40,2,0,32,4,65,12,106,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,54,2,0,32,0,65,40,106,65,0,54,2,0,32,1,32,2,106,33,1,11,32,1,32,6,65,16,107,77,4,64,32,6,65,16,107,33,8,32,0,65,8,106,40,2,0,33,2,32,0,65,12,106,40,2,0,33,3,32,0,65,16,106,40,2,0,33,5,32,0,65,20,106,40,2,0,33,7,3,64,32,2,32,1,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,2,32,3,32,1,65,4,106,34,1,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,3,32,5,32,1,65,4,106,34,1,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,5,32,7,32,1,65,4,106,34,1,40,2,0,65,247,148,175,175,120,108,106,65,13,119,65,177,243,221,241,121,108,33,7,32,8,32,1,65,4,106,34,1,79,13,0,11,32,0,65,8,106,32,2,54,2,0,32,0,65,12,106,32,3,54,2,0,32,0,65,16,106,32,5,54,2,0,32,0,65,20,106,32,7,54,2,0,11,32,1,32,6,73,4,64,32,4,32,1,32,6,32,1,107,34,1,252,10,0,0,32,0,65,40,106,32,1,54,2,0,11,11,97,1,1,127,32,0,65,16,106,40,2,0,33,1,32,0,65,4,106,40,2,0,4,127,32,1,65,12,119,32,0,65,20,106,40,2,0,65,18,119,106,32,0,65,12,106,40,2,0,65,7,119,106,32,0,65,8,106,40,2,0,65,1,119,106,5,32,1,65,177,207,217,178,1,106,11,32,0,40,2,0,106,32,0,65,24,106,32,0,65,40,106,40,2,0,16,1,11,255,3,2,3,126,1,127,32,0,32,1,106,33,6,32,1,65,32,79,4,126,32,6,65,32,107,33,6,32,2,66,214,235,130,238,234,253,137,245,224,0,124,33,3,32,2,66,177,169,172,193,173,184,212,166,61,125,33,4,32,2,66,249,234,208,208,231,201,161,228,225,0,124,33,5,3,64,32,3,32,0,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,3,32,4,32,0,65,8,106,34,0,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,4,32,2,32,0,65,8,106,34,0,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,2,32,5,32,0,65,8,106,34,0,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,5,32,6,32,0,65,8,106,34,0,79,13,0,11,32,2,66,12,137,32,5,66,18,137,124,32,4,66,7,137,124,32,3,66,1,137,124,32,3,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,4,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,2,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,5,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,5,32,2,66,197,207,217,178,241,229,186,234,39,124,11,32,1,173,124,32,0,32,1,65,31,113,16,6,11,134,2,0,32,1,32,2,106,33,2,3,64,32,2,32,1,65,8,106,79,4,64,32,1,41,3,0,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,32,0,133,66,27,137,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,33,0,32,1,65,8,106,33,1,12,1,11,11,32,1,65,4,106,32,2,77,4,64,32,0,32,1,53,2,0,66,135,149,175,175,152,182,222,155,158,127,126,133,66,23,137,66,207,214,211,190,210,199,171,217,66,126,66,249,243,221,241,153,246,153,171,22,124,33,0,32,1,65,4,106,33,1,11,3,64,32,1,32,2,73,4,64,32,0,32,1,49,0,0,66,197,207,217,178,241,229,186,234,39,126,133,66,11,137,66,135,149,175,175,152,182,222,155,158,127,126,33,0,32,1,65,1,106,33,1,12,1,11,11,32,0,32,0,66,33,136,133,66,207,214,211,190,210,199,171,217,66,126,34,0,32,0,66,29,136,133,66,249,243,221,241,153,246,153,171,22,126,34,0,32,0,66,32,136,133,11,77,0,32,0,65,8,106,32,1,66,214,235,130,238,234,253,137,245,224,0,124,55,3,0,32,0,65,16,106,32,1,66,177,169,172,193,173,184,212,166,61,125,55,3,0,32,0,65,24,106,32,1,55,3,0,32,0,65,32,106,32,1,66,249,234,208,208,231,201,161,228,225,0,124,55,3,0,11,244,4,2,3,127,4,126,32,1,32,2,106,33,5,32,0,65,40,106,33,4,32,0,65,200,0,106,40,2,0,33,3,32,0,32,0,41,3,0,32,2,173,124,55,3,0,32,2,32,3,106,65,32,73,4,64,32,3,32,4,106,32,1,32,2,252,10,0,0,32,0,65,200,0,106,32,2,32,3,106,54,2,0,15,11,32,3,4,64,32,3,32,4,106,32,1,65,32,32,3,107,34,2,252,10,0,0,32,0,65,8,106,34,3,32,3,41,3,0,32,4,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,55,3,0,32,0,65,16,106,34,3,32,3,41,3,0,32,4,65,8,106,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,55,3,0,32,0,65,24,106,34,3,32,3,41,3,0,32,4,65,16,106,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,55,3,0,32,0,65,32,106,34,3,32,3,41,3,0,32,4,65,24,106,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,55,3,0,32,0,65,200,0,106,65,0,54,2,0,32,1,32,2,106,33,1,11,32,1,65,32,106,32,5,77,4,64,32,5,65,32,107,33,2,32,0,65,8,106,41,3,0,33,6,32,0,65,16,106,41,3,0,33,7,32,0,65,24,106,41,3,0,33,8,32,0,65,32,106,41,3,0,33,9,3,64,32,6,32,1,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,6,32,7,32,1,65,8,106,34,1,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,7,32,8,32,1,65,8,106,34,1,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,8,32,9,32,1,65,8,106,34,1,41,3,0,66,207,214,211,190,210,199,171,217,66,126,124,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,33,9,32,2,32,1,65,8,106,34,1,79,13,0,11,32,0,65,8,106,32,6,55,3,0,32,0,65,16,106,32,7,55,3,0,32,0,65,24,106,32,8,55,3,0,32,0,65,32,106,32,9,55,3,0,11,32,1,32,5,73,4,64,32,4,32,1,32,5,32,1,107,34,1,252,10,0,0,32,0,65,200,0,106,32,1,54,2,0,11,11,188,2,1,5,126,32,0,65,24,106,41,3,0,33,1,32,0,41,3,0,34,2,66,32,90,4,126,32,0,65,8,106,41,3,0,34,3,66,1,137,32,0,65,16,106,41,3,0,34,4,66,7,137,124,32,1,66,12,137,32,0,65,32,106,41,3,0,34,5,66,18,137,124,124,32,3,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,4,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,1,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,32,5,66,207,214,211,190,210,199,171,217,66,126,66,31,137,66,135,149,175,175,152,182,222,155,158,127,126,133,66,135,149,175,175,152,182,222,155,158,127,126,66,157,163,181,234,131,177,141,138,250,0,125,5,32,1,66,197,207,217,178,241,229,186,234,39,124,11,32,2,124,32,0,65,40,106,32,2,66,31,131,167,16,6,11]);async function Z0(){return function(f){let{exports:{mem:_,xxh32:m,xxh64:$,init32:D,update32:E,digest32:C,init64:H,update64:U,digest64:j}}=f,b=new Uint8Array(_.buffer);function K(M,J){if(_.buffer.byteLength<M+J){let Mf=Math.ceil((M+J-_.buffer.byteLength)/65536);_.grow(Mf),b=new Uint8Array(_.buffer)}}function N(M,J,Mf,f1,_1,m1){K(M);let l=new Uint8Array(M);return b.set(l),Mf(0,J),l.set(b.subarray(0,M)),{update(w){let Sf;return b.set(l),typeof w=="string"?(K(3*w.length,M),Sf=B.encodeInto(w,b.subarray(M)).written):(K(w.byteLength,M),b.set(w,M),Sf=w.byteLength),f1(0,M,Sf),l.set(b.subarray(0,M)),this},digest:()=>(b.set(l),m1(_1(0)))}}function G(M){return M>>>0}let S=2n**64n-1n;function O(M){return M&S}let B=new TextEncoder,n=0,c=0n;function pf(M,J=n){return K(3*M.length,0),G(m(0,B.encodeInto(M,b).written,J))}function vf(M,J=c){return K(3*M.length,0),O($(0,B.encodeInto(M,b).written,J))}return{h32:pf,h32ToString:(M,J=n)=>pf(M,J).toString(16).padStart(8,"0"),h32Raw:(M,J=n)=>(K(M.byteLength,0),b.set(M),G(m(0,M.byteLength,J))),create32:(M=n)=>N(48,M,D,E,C,G),h64:vf,h64ToString:(M,J=c)=>vf(M,J).toString(16).padStart(16,"0"),h64Raw:(M,J=c)=>(K(M.byteLength,0),b.set(M),O($(0,M.byteLength,J))),create64:(M=c)=>N(88,M,H,U,j,O)}}((await WebAssembly.instantiate(W_)).instance)}var B_=0x6e52736ac806831en,V_="cch=00000;";var Xf=/("system":\[\{"type":"text","text":"x-anthropic-billing-header: cc_version=[^;"]+; cc_entrypoint=[^;"]+; )cch=([0-9a-f]{5});/,L_=/("system":\[\{"type":"text","text":"x-anthropic-billing-header: cc_version=[^;"]+; cc_entrypoint=[^;"]+; )cch=00000;/,Y0=null,Lf=null;async function X_(){if(Lf)return;Y0??=(async()=>{Lf=(await Z0()).h64Raw})(),await Y0}async function Z_(f){return await X_(),((Lf?.(f,B_)??0n)&0xfffffn).toString(16).padStart(5,"0")}function Y_(f){return f.replace(Xf,`$1${V_}`)}function A0(f){return Xf.exec(f)?.[2]??null}async function Q0(f){if(!Xf.test(f))return f;let _=Y_(f),m=await Z_(new TextEncoder().encode(_));return _.replace(L_,`$1cch=${m};`)}function A_(f=x,_=new Date){if(f===x)return Kf;let m=_.toISOString().slice(0,10);return O_("sha256").update(`${m}${f}`).digest("hex").slice(0,3)}function O$(f,_=x,m,$=new Date){let D=A_(_,$);return`x-anthropic-billing-header: cc_version=${_}.${D}; cc_entrypoint=${m}; cch=00000;`}var X$="claude-cachekeep",x0=3600000,Zf=300000,Q_=60000,Z$="extended-cache-ttl-2025-04-11",x_="## Claude Cache Keep Status",I_="## Claude Cache Keep Enabled",q_="## Claude Cache Keep Disabled",P_="## Claude Cache Keep Usage",h_="Usage: `/claude-cachekeep`, `/claude-cachekeep off`, or `/claude-cachekeep HH-HH`.";function $f(f){return String(f).padStart(2,"0")}function T_(f){let _=f.trim();if(!_)return{type:"status"};if(_==="off")return{type:"disable"};let m=/^(\d{1,2})-(\d{1,2})$/.exec(_);if(!m)return{type:"usage"};let $=Number(m[1]),D=Number(m[2]);if(!Number.isInteger($)||!Number.isInteger(D)||$<0||$>23||D<0||D>23||$===D)return{type:"usage"};return{type:"window",startHour:$,endHour:D}}function Af(f){let _=Number(f?.cacheKeep?.startHour),m=Number(f?.cacheKeep?.endHour);if(!Number.isInteger(_)||!Number.isInteger(m)||_<0||_>23||m<0||m>23||_===m)return;return{startHour:_,endHour:m}}function P0(f){return f?.cacheKeep?.enabled===!0&&!!Af(f)}function R_(f){return P0(f)&&f?.claudeCache?.enabled===!0&&f.claudeCache.mode==="hybrid"}function I0(f,_=new Date){if(!f)return!1;let m=_.getHours();if(f.startHour<f.endHour)return m>=f.startHour&&m<f.endHour;return m>=f.startHour||m<f.endHour}function q0(f=new Date){return`${f.getFullYear()}-${$f(f.getMonth()+1)}-${$f(f.getDate())}`}function Yf(f,_=new Date){if(f&&f.startHour>f.endHour&&_.getHours()<f.endHour){let m=new Date(_);return m.setDate(m.getDate()-1),q0(m)}return q0(_)}function mf(f){let _=f.window?`${$f(f.window.startHour)}-${$f(f.window.endHour)}`:"not configured",m=[`Cache keep: ${f.enabled?"enabled":"disabled"}`,`Window: ${_}`,"Mode requirement: `/claude-cache mode hybrid` must be active."];if(typeof f.hybridActive==="boolean")m.push(`Hybrid active: ${f.hybridActive?"yes":"no"}`);if(typeof f.trackedSessions==="number")m.push(`Tracked sessions: ${f.trackedSessions}`);if(f.nextPrewarmAt)m.push(`Next prewarm: ${new Date(f.nextPrewarmAt).toLocaleString()}`);return m.join(`
|
|
13
|
+
`)}function Y$(f){let _=T_(f.argumentsText),m={enabled:f.enabled??!1,window:f.window,trackedSessions:f.trackedSessions,nextPrewarmAt:f.nextPrewarmAt,hybridActive:f.hybridActive};if(_.type==="status")return[x_,"",mf(m)].join(`
|
|
14
|
+
`);if(_.type==="disable")return[q_,"",mf({...m,enabled:!1})].join(`
|
|
15
|
+
`);if(_.type==="window")return[I_,"",mf({...m,enabled:!0,window:{startHour:_.startHour,endHour:_.endHour}})].join(`
|
|
16
|
+
`);return[P_,"",h_,"",mf(m)].join(`
|
|
17
|
+
`)}function Qf(f){if(!f||typeof f!=="object")return!1;if(Array.isArray(f))return f.some(Qf);let _=f,m=_.cache_control;if(m&&typeof m==="object"&&m.type==="ephemeral")return!0;return Object.values(_).some(Qf)}async function w_(f){let _;try{_=JSON.parse(f)}catch{return{ok:!1,reason:"body is not valid JSON"}}if(!Qf(_))return{ok:!1,reason:"body has no explicit cache breakpoints"};let m=structuredClone(_);if(m.max_tokens=0,delete m.stream,m.thinking?.type==="enabled")delete m.thinking;if(m.output_config?.format)delete m.output_config;let E=m.tool_choice;if(E?.type==="tool"||E?.type==="any")delete m.tool_choice;return{ok:!0,bodyText:await Q0(JSON.stringify(X0(m)))}}class i_{options;targets=new Map;timer=null;constructor(f){this.options=f}start(){if(this.timer)return;if(this.timer=setInterval(()=>{this.tick().catch((f)=>{this.options.log?.("[cachekeep] tick failed",{error:f instanceof Error?f.message:String(f)})})},Q_),"unref"in this.timer)this.timer.unref()}stop(){if(this.timer)clearInterval(this.timer);this.timer=null}stats(f,_=this.options.now?.()??Date.now()){let m=Yf(f,new Date(_)),$=[...this.targets.values()].filter((E)=>E.dayKey===m),D=$.length?Math.min(...$.map((E)=>E.cacheExpiresAt-Zf)):void 0;return{trackedSessions:$.length,nextPrewarmAt:D}}trackedCount(){return this.targets.size}track(f){if(!f.sessionId)return{tracked:!1,reason:"missing session id"};if(!P0(f.storage))return{tracked:!1,reason:"cachekeep disabled"};if(f.cacheMode!=="hybrid")return{tracked:!1,reason:"cache mode is not hybrid"};let _=this.options.now?.()??Date.now(),m=Af(f.storage);if(!I0(m,new Date(_)))return{tracked:!1,reason:"outside configured window"};let $={};return f.headers.forEach((D,E)=>{$[E]=D}),this.targets.set(f.sessionId,{id:f.sessionId,url:f.url,headers:$,bodyText:f.bodyText,cacheExpiresAt:_+x0,dayKey:Yf(m,new Date(_))}),this.start(),{tracked:!0}}async tick(){let f=await this.options.loadStorage(),_=Af(f),m=this.options.now?.()??Date.now(),$=Yf(_,new Date(m));for(let[E,C]of this.targets)if(C.dayKey!==$)this.targets.delete(E);if(!this.targets.size){this.stop();return}if(!R_(f))return;if(!I0(_,new Date(m)))return;let D=m+Zf;for(let E of this.targets.values()){if(E.cacheExpiresAt>D)continue;await this.prewarm(E,m)}}async prewarm(f,_){let m=await w_(f.bodyText);if(!m.ok){this.options.log?.("[cachekeep] prewarm skipped",{session:f.id,reason:m.reason}),this.targets.delete(f.id);return}let $=this.options.fetchImpl??fetch,D={...f,bodyText:m.bodyText},E=this.options.prepareHeaders?await this.options.prepareHeaders(new Headers(f.headers),D):new Headers(f.headers);E.delete("content-length"),E.delete("transfer-encoding");let C=await $(f.url,{method:"POST",headers:E,body:m.bodyText});if(!C.ok){this.options.log?.("[cachekeep] prewarm failed",{session:f.id,status:C.status,body:await C.text().catch(()=>"")}),f.cacheExpiresAt=_+Zf+300000;return}await C.body?.cancel().catch(()=>{}),f.cacheExpiresAt=_+x0,this.options.log?.("[cachekeep] prewarm succeeded",{session:f.id})}}import{createHash as k_}from"node:crypto";import{mkdir as l_,writeFile as xf}from"node:fs/promises";import{tmpdir as y_}from"node:os";import{join as R0}from"node:path";var T$="claude-dump",p_="## Claude Dump Status",v_="## Claude Dump Enabled",u_="## Claude Dump Disabled",d_="## Claude Dump Usage",g_="Usage: `/claude-dump`, `/claude-dump on`, or `/claude-dump off`.",n_="OPENCODE_ANTHROPIC_AUTH_DUMP_DIR",c_=R0(y_(),"opencode-anthropic-auth-dumps"),Ef=!1,h0=0;function R$(f){Ef=f}function w0(){return process.env[n_]||c_}function s_(f){let _=f.trim().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&_[0]==="on")return{type:"enable"};if(_.length===1&&_[0]==="off")return{type:"disable"};return{type:"usage"}}function Df(f){let _=f?.enabled??Ef;return[p_,"",`- Enabled: ${_?"enabled":"disabled"}`,`- Directory: ${w0()}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Captures: final rewritten Anthropic body plus redacted relay payload metadata","- Warning: body dumps may contain prompt/session content; turn this off after debugging"].join(`
|
|
18
|
+
`)}function w$(f){let _=s_(f.argumentsText),m=f.enabled??Ef;if(_.type==="status")return Df({enabled:m});if(_.type==="enable")return[v_,"",Df({enabled:!0})].join(`
|
|
19
|
+
`);if(_.type==="disable")return[u_,"",Df({enabled:!1})].join(`
|
|
20
|
+
`);return[d_,"",g_,"",Df({enabled:m})].join(`
|
|
21
|
+
`)}function T0(f){return f.length<=16?f:`${f.slice(0,12)}…`}function i0(f){return k_("sha256").update(f).digest("hex")}function r_(f){return A0(f)}function t_(f,_){if(f==null)return null;if(f===_)return{changed:!1,firstByte:-1,lastPreviousByte:-1,lastCurrentByte:-1,previousBytes:f.length,currentBytes:_.length};let m=0;while(m<f.length&&m<_.length&&f[m]===_[m])m+=1;let $=f.length-1,D=_.length-1;while($>=m&&D>=m&&f[$]===_[D])$-=1,D-=1;return{changed:!0,firstByte:m,lastPreviousByte:$,lastCurrentByte:D,changedPreviousBytes:$-m+1,changedCurrentBytes:D-m+1,previousBytes:f.length,currentBytes:_.length}}function o_(f){try{let _=JSON.parse(f);return _!=null&&typeof _==="object"&&!Array.isArray(_)?_:null}catch(_){return F(`dump body parse failed: ${_ instanceof Error?_.message:String(_)}`),null}}function If(f){return i0(JSON.stringify(f))}function a_(f){let _=o_(f);if(!_)return{parseable:!1};let m=Array.isArray(_.messages)?_.messages:[],$=Array.isArray(_.system)?_.system:[],D=m[0],E=m.slice(1);return{parseable:!0,model:typeof _.model==="string"?_.model:void 0,stream:_.stream,systemCount:$.length,messagesCount:m.length,systemHash:If($),message0Hash:D===void 0?null:If(D),message0Bytes:D===void 0?0:JSON.stringify(D).length,messagesAfter0Hash:If(E),messagesAfter0Bytes:JSON.stringify(E).length,cch:r_(f)}}function qf(f){if(Array.isArray(f))return f.map(qf);if(f==null||typeof f!=="object")return f;let _={};for(let[m,$]of Object.entries(f)){let D=m.toLowerCase();if(D==="authorization"||D==="x-api-key"||D==="cookie"||D==="set-cookie"){_[m]="[redacted]";continue}_[m]=qf($)}return _}async function k0(f){if(!Ef)return;h0+=1;let _=`${new Date().toISOString().replace(/[:.]/g,"-")}-${String(h0).padStart(5,"0")}-${f.transport}-p${f.protocol}-${f.mode}`,m=w0(),$=R0(m,_);try{await l_(m,{recursive:!0});let D={id:_,createdAt:new Date().toISOString(),session:T0(f.affinity),transport:f.transport,protocol:f.protocol,mode:f.mode,status:f.status,bodyBytes:f.bodyText.length,relayBytes:f.relayBytes,bodyHash:i0(f.bodyText),diff:t_(f.previousBodyText,f.bodyText),body:a_(f.bodyText),files:{body:`${$}.body.json`,relay:`${$}.relay.json`,metadata:`${$}.meta.json`}};await Promise.all([xf(`${$}.body.json`,f.bodyText,"utf8"),xf(`${$}.relay.json`,`${JSON.stringify(qf(f.payload),null,2)}
|
|
22
|
+
`,"utf8"),xf(`${$}.meta.json`,`${JSON.stringify(D,null,2)}
|
|
23
|
+
`,"utf8")]),F(`dumped request id=${_} session=${T0(f.affinity)} body=${$}.body.json meta=${$}.meta.json`)}catch(D){F(`dump failed: ${D instanceof Error?D.message:String(D)}`)}}var k$="claude-fast";var Hf=!1;function l$(){return Hf}function y$(f){Hf=f}function e_(f){let _=f.trim().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&_[0]==="on")return{type:"enable"};if(_.length===1&&_[0]==="off")return{type:"disable"};return{type:"usage"}}function Cf(f){return["## Claude Fast Mode Status","",`- Enabled: ${f?.enabled??Hf?"enabled":"disabled"}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Scope: adds Anthropic fast mode to supported Opus requests","- Supported models: claude-opus-4-6, claude-opus-4-7, and claude-opus-4-8",'- Request changes: adds `speed: "fast"` and the `fast-mode-2026-02-01` beta header',"- Note: fast and standard speeds do not share prompt-cache prefixes"].join(`
|
|
24
|
+
`)}function p$(f){let _=e_(f.argumentsText),m=f.enabled??Hf;if(_.type==="status")return Cf({enabled:m});if(_.type==="enable")return["## Claude Fast Mode Enabled","",Cf({enabled:!0})].join(`
|
|
25
|
+
`);if(_.type==="disable")return["## Claude Fast Mode Disabled","",Cf({enabled:!1})].join(`
|
|
26
|
+
`);return["## Claude Fast Mode Usage","","Usage: `/claude-fast`, `/claude-fast on`, or `/claude-fast off`.","",Cf({enabled:m})].join(`
|
|
27
|
+
`)}import{createHash as fm}from"node:crypto";var _m=globalThis.setTimeout;function Q(f){return fm("sha256").update(f).digest("hex").slice(0,16)}class T{main=null;mainTokenFp=null;fallbacks=new Map;fallbackTokenFps=new Map;inflightMain=null;inflightFallbacks=new Map;mainLastApiError=void 0;fallbackApiErrors=new Map;fallbackErrorTokenFps=new Map;apiGate=Promise.resolve();lastApiCallAt=0;storage;fetchImpl;now;onMainQuotaFetched;onApiError;constructor(f){this.storage=f.storage,this.fetchImpl=f.fetchImpl??fetch,this.now=f.now??Date.now,this.onMainQuotaFetched=f.onMainQuotaFetched,this.onApiError=f.onApiError;let _=N0(f.storage);if(_)this.main={quota:_.quota,refreshAfter:Of(_.quota,f.storage,_.checkedAt),checkedAt:_.checkedAt},this.mainTokenFp=_.tokenFingerprint??null;let m=f.storage?.quota?.mainLastQuotaApiError;if(m&&k(m,this.now()))this.mainLastApiError=m}getMain(f){if(f&&this.main&&this.mainTokenFp&&this.mainTokenFp!==Q(f))this.main=null,this.mainTokenFp=null;return this.main}getFallback(f,_){let m=this.fallbacks.get(f)??null;if(!_||!m)return m;if(this.fallbackTokenFps.get(f)!==Q(_))return this.fallbacks.delete(f),this.fallbackTokenFps.delete(f),null;return m}getAllFallbacks(){return this.fallbacks}setMain(f,_){this.mainTokenFp=Q(f),this.main=_}setFallback(f,_,m){if(this.fallbacks.set(f,_),m)this.fallbackTokenFps.set(f,Q(m));else this.fallbackTokenFps.delete(f)}async refreshMain(f){let _=Q(f);if(this.mainTokenFp&&this.mainTokenFp!==_)this.main=null,this.mainTokenFp=null;if(this.inflightMain)return this.inflightMain;if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}return this.inflightMain=this._fetchMain(f),this.inflightMain}async refreshFallback(f,_){let m=T.fallbackInflightKey(f,_),$=this.inflightFallbacks.get(m);if($)return $;if(this.isFallbackBackedOff(f,_)){let E=this.getFallback(f,_);if(E)return E.quota;throw Error("Quota API rate-limited — try again later")}let D=this._fetchFallback(f,_);return this.inflightFallbacks.set(m,D),D}async refreshAllFallbacks(f){let _=this.now();for(let m of f){if(m.enabled===!1)continue;if(!m.access)continue;let $=this.getFallback(m.id,m.access);if($&&_<$.refreshAfter)continue;try{await this.refreshFallback(m.id,m.access)}catch{}}}refreshMainInBackground(f){if(this.inflightMain)return;if(this.isBackedOff())return;this.refreshMain(f).catch(()=>{})}isMainStale(){if(!this.main)return!0;return this.now()>=this.main.refreshAfter}isFallbackStale(f,_){let m=this.getFallback(f,_);if(!m)return!0;return this.now()>=m.refreshAfter}shouldRefreshOnRequestCount(f){let _=F0(this.storage);if(_<=0)return!1;return f>0&&f%_===0}needsRefresh(f){return this.isMainStale()||this.shouldRefreshOnRequestCount(f)}updateStorage(f){this.storage=f}seedFallbacksFromAccounts(f){let _=X(this.storage);for(let m of f){if(m.enabled===!1)continue;if(this.getFallback(m.id,m.access))continue;if(!m.quota)continue;let $=Math.max(m.quota.five_hour?.checkedAt??0,m.quota.seven_day?.checkedAt??0);if($<=0)continue;this.setFallback(m.id,{quota:m.quota,refreshAfter:$+_,checkedAt:$},m.access)}}isBackedOff(){return k(this.mainLastApiError,this.now())}isFallbackBackedOff(f,_){if(_){if(this.fallbackErrorTokenFps.get(f)!==Q(_))return!1}return k(this.fallbackApiErrors.get(f),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(f,_){return JSON.stringify([f,Q(_)])}_enqueueApiFetch(f){let _=async()=>{let $=this.now()-this.lastApiCallAt;if($<T.API_CALL_GAP_MS)await new Promise((D)=>{let E=_m(D,T.API_CALL_GAP_MS-$);if(typeof E==="object"&&"unref"in E)E.unref()});return this.lastApiCallAt=this.now(),f()},m=this.apiGate.then(_,_);return this.apiGate=m.catch(()=>{}),m}async _fetchMain(f){return this._enqueueApiFetch(async()=>{try{if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}let _=await Wf({name:"opencode-main-quota-refresh",ttlMs:30000});if(!_){if(this.main)return this.main.quota;throw Error("Quota refresh is already in progress")}try{let m=await e({accessToken:f,fetchImpl:this.fetchImpl,now:this.now}),$=this.now();return this.mainTokenFp=Q(f),this.main={quota:m,refreshAfter:Of(m,this.storage,$),checkedAt:$},this.mainLastApiError=void 0,this.onMainQuotaFetched?.(m,$,this.mainTokenFp),m}catch(m){throw this._handleMainFetchError(m),m}finally{await _.release()}}finally{this.inflightMain=null}})}async _fetchFallback(f,_){return this._enqueueApiFetch(async()=>{try{if(this.isFallbackBackedOff(f,_)){let D=this.getFallback(f,_);if(D)return D.quota;throw Error("Quota API rate-limited — try again later")}let m=await e({accessToken:_,fetchImpl:this.fetchImpl,now:this.now}),$=this.now();return this.setFallback(f,{quota:m,refreshAfter:$+X(this.storage),checkedAt:$},_),this.fallbackApiErrors.delete(f),this.fallbackErrorTokenFps.delete(f),m}catch(m){throw this._handleFallbackFetchError(f,_,m),m}finally{this.inflightFallbacks.delete(T.fallbackInflightKey(f,_))}})}static isAuthError(f){let _=f instanceof Error?f.message:String(f);return/quota check failed: 401\b/.test(_)}_handleMainFetchError(f){if(T.isAuthError(f))return;this.mainLastApiError=a({error:f,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(f,_,m){if(T.isAuthError(m))return;let $=Q(_),D=this.fallbackErrorTokenFps.get(f)===$?this.fallbackApiErrors.get(f):void 0;this.fallbackApiErrors.set(f,a({error:m,now:this.now(),previous:D})),this.fallbackErrorTokenFps.set(f,$)}}var n$="claude-quota",l0={five_hour:"5h",seven_day:"1w"};function y0(f){return`${Math.round(f*10)/10}%`}function Pf(f,_){let m=Math.max(0,_-f),$=Math.floor(m/60000);if($<1)return"just now";if($===1)return"1m ago";if($<60)return`${$}m ago`;let D=Math.floor($/60),E=$%60;if(E===0)return`${D}h ago`;return`${D}h ${E}m ago`}function mm(f,_){let m=Date.parse(f);if(!Number.isFinite(m))return f;let $=m-_;if($<=0)return"now";let D=Math.max(1,Math.ceil($/60000));if(D<60)return`in ${D}m`;let E=Math.floor(D/60),C=D%60;if(C===0)return`in ${E}h`;return`in ${E}h ${C}m`}function $m(f,_){if(!f)return"";return`, resets ${mm(f,_)}`}function p0(f,_,m){if(!_)return` - ${l0[f]}: unknown`;return[` - ${l0[f]}: ${y0(_.remainingPercent)} remaining`,` (${y0(_.usedPercent)} used`,`${$m(_.resetsAt,m)}, checked ${Pf(_.checkedAt,m)})`].join("")}function Dm(f){return f.label?.trim()||f.id}function Em(f){return f.lastQuotaRefreshError?.message??f.lastRefreshError?.message}function c$(f,_=new Map){if(!f?.accounts.length)return[];return f.accounts.map((m)=>{let $=_.get(m.id)??Em(m);return{name:Dm(m),role:"fallback",enabled:m.enabled!==!1,quota:m.quota,lastRefreshedAt:m.lastRefreshedAt,...$&&{error:$}}})}function s$(f){let _=f.now??Date.now(),m=["## Claude Quotas",""];if(f.refreshedAt)m.push(`Refreshed: ${Pf(f.refreshedAt,_)}`,"");if(!f.accounts.length)return m.push("No Claude OAuth accounts found yet."),m.join(`
|
|
28
|
+
`);for(let $ of f.accounts){let D=$.role==="main"?"main":"fallback",E=$.enabled===!1?" disabled":"";if(m.push(`### ${$.name} (${D}${E})`),$.lastRefreshedAt)m.push(` - Last token refresh: ${Pf($.lastRefreshedAt,_)}`);if($.error)m.push(` - Error: ${$.error}`);m.push(p0("five_hour",$.quota?.five_hour,_)),m.push(p0("seven_day",$.quota?.seven_day,_)),m.push("")}return m.join(`
|
|
29
|
+
`).trimEnd()}import{Buffer as r0}from"node:buffer";import{createHash as Cm,randomBytes as Hm}from"node:crypto";class Tf extends Error{}var wf=new Map,v0=new Map,u0=new Set,d0=0;function hf(){return d0+=1,`req_${Date.now().toString(36)}_${d0.toString(36)}`}function Uf(f){if(u0.has(f))return;u0.add(f),F(f)}function fD(f){let _=f?.relay;if(!_)return Uf("disabled: no relay config found"),null;if(_.enabled!==!0)return Uf("disabled: relay.enabled is not true"),null;if(!_.url?.trim()||!_.token?.trim())return Uf("disabled: missing relay url or token"),null;let m=_.transport==="http"?"http":"websocket";return Uf(`configured transport=${m} protocol=${m==="websocket"?2:1} url=${_.url.trim()} fallbackToDirect=${_.fallbackToDirect!==!1}`),{enabled:!0,url:_.url.trim(),token:_.token.trim(),fallbackToDirect:_.fallbackToDirect!==!1,transport:m}}function _D(){return Hm(32).toString("base64url")}function Um(f){return`sha256:${Cm("sha256").update(f).digest("hex")}`}function g0(f,_){let m=0,$=Math.min(f.length,_.length);while(m<$&&f.charCodeAt(m)===_.charCodeAt(m))m++;let D=f.length,E=_.length;while(D>m&&E>m&&f.charCodeAt(D-1)===_.charCodeAt(E-1))D--,E--;return{start:m,deleteCount:D-m,insert:_.slice(m,E)}}function Mm(f){return f.deleteCount===0&&f.insert.length===0}function n0(f){let _=f.match(/\bcch=([0-9a-f]{5});/),m=_?.[1];if(!m||_.index==null)return null;let $=_.index+4;return{start:$,end:$+m.length,token:m}}function Sm(f,_,m,$){return`${f.slice(0,_)}${$}${f.slice(m)}`}function t0(f,_){let m=n0(f),$=n0(_);if(m&&$&&m.start===$.start&&m.end-m.start===$.end-$.start&&m.token!==$.token){let D={start:m.start,deleteCount:m.end-m.start,insert:$.token},E=Sm(f,m.start,m.end,$.token),C=g0(E,_);return Mm(C)?D:[D,C]}return g0(f,_)}function jm(f,_){if(typeof _!=="string")return!1;try{let m=f instanceof Request?new URL(f.url):new URL(f.toString());return m.pathname==="/v1/messages"||m.pathname==="/messages"}catch{return!1}}function bm(f){let _={};for(let[m,$]of f.entries()){if(m==="x-session-affinity"||m==="x-opencode-session")continue;_[m]=$}return _}async function c0(f,_){return fetch(f.url,{method:"POST",headers:{"content-type":"application/json","x-relay-token":f.token},body:JSON.stringify(_)})}function W(f){return f.length>12?`${f.slice(0,12)}…`:f}function I(){return performance.now()}function R(f){return Math.round(f*10)/10}function Km(f){let{input:_,init:m,headers:$,bodyText:D,affinity:E,previous:C,nextHash:H}=f,U=_ instanceof Request?_.url:_.toString(),j={protocol:1,type:"request",affinity:E,upstream:{url:U,method:m?.method||(_ instanceof Request?_.method:"POST"),headers:bm($)},next_hash:H};return C?{...j,mode:"patch",base_hash:C.hash,revision:C.revision+1,patch:t0(C.body,D)}:{...j,mode:"full_sync",revision:1,body:D}}function Rf(f,_){return{protocol:f.protocol,type:"request",affinity:f.affinity,upstream:f.upstream,next_hash:f.next_hash,mode:"full_sync",revision:1,body:_}}function o0(f,_,m,$){wf.set(f,{body:_,hash:m,revision:$})}async function s0(f){let{config:_,payload:m,bodyText:$,fallback:D}=f,E=m,C=await c0(_,E);if(C.status===409&&E.mode==="patch")F(`state mismatch from relay session=${W(E.affinity)}; retrying full_sync`),await C.body?.cancel().catch(()=>{}),E=Rf(E,$),C=await c0(_,E);if(!C.ok&&C.status>=500&&_.fallbackToDirect)return F(`relay returned ${C.status}; falling back direct session=${W(E.affinity)}`),await C.body?.cancel().catch(()=>{}),{response:await D(),payload:E,transport:"http",protocol:E.protocol,usedRelay:!1};return{response:C,payload:E,transport:"http",protocol:E.protocol,usedRelay:!0}}function Nm(f,_){let m=new URL(f);return m.protocol=m.protocol==="http:"?"ws:":"wss:",m.pathname="/ws",m.searchParams.set("token",_),m.toString()}function Fm(f){return new Uint8Array(r0.from(f,"base64"))}function Gm(f){if(f instanceof Uint8Array)return f;if(f instanceof ArrayBuffer)return new Uint8Array(f);if(ArrayBuffer.isView(f))return new Uint8Array(f.buffer,f.byteOffset,f.byteLength);return new Uint8Array(r0.from(String(f)))}function Jm(f){return JSON.parse(f)}function zm(f){let _=f.message||"relay websocket error";return f.status?`relay websocket error ${f.status}: ${_}`:_}class a0{config;affinity;socket;connecting;queue=Promise.resolve();pending;serverState;constructor(f,_){this.config=f,this.affinity=_}send(f,_,m=!1){let $=I(),D=this.queue.catch(()=>{}).then(()=>this.startQueued(f,_,$,m)),E=D.then(async({response:C,getPayload:H})=>({response:await C,payload:H(),transport:"websocket",protocol:2,usedRelay:!0}));return this.queue=D.then(({done:C})=>C.catch(()=>{}),()=>{}),E}async startQueued(f,_,m,$){let D=I();await this.ensureConnected();let E=I(),C=wf.get(this.affinity),H=this.serverState?.hash,U={...f,protocol:2,id:hf()};if(U.mode==="patch"&&(!H||H!==U.base_hash))U.mode="full_sync",U.revision=(this.serverState?.revision??0)+1,delete U.base_hash,delete U.patch,U.body=_;if(U.mode==="patch"&&C)U.patch=t0(C.body,_);F(`perf websocket send_start session=${W(this.affinity)} request=${U.id} mode=${U.mode} queueMs=${R(E-m)} connectMs=${R(E-D)} bodyBytes=${_.length} relayBytes=${JSON.stringify(U).length}`);let j=U,b=this.sendPayload(U,_,$);b.done.catch(()=>{});let K=b.done,N=b.response.catch((S)=>{if(!(S instanceof Tf)||U.mode!=="patch")throw S;let O=Rf(U,_);O.protocol=2,O.id=hf(),O.revision=(this.serverState?.revision??0)+1,j=O;let B=this.sendPayload(O,_,$);return B.done.catch(()=>{}),K=B.done,B.response}),G=N.then(()=>K,()=>K.catch(()=>{}));return{response:N,done:G,getPayload:()=>j}}async ensureConnected(){if(this.socket?.readyState===WebSocket.OPEN&&this.serverState!==void 0)return;if(this.connecting)return await this.connecting;this.connecting=new Promise((f,_)=>{let m=Nm(this.config.url,this.config.token),$=new URL(m);$.searchParams.set("affinity",this.affinity);let D=new WebSocket($.toString());this.socket=D,this.serverState=void 0;let E=setTimeout(()=>{D.close(),_(Error("relay websocket ready timed out"))},15000);D.addEventListener("message",(C)=>{try{if(typeof C.data!=="string"){this.handleBinaryChunk(C.data);return}let H=Jm(C.data);if(H.type==="ready"){clearTimeout(E),this.serverState=H.state,f();return}this.handleMessage(H)}catch(H){clearTimeout(E),_(H),this.failPending(H),D.close()}}),D.addEventListener("error",()=>{clearTimeout(E);let C=Error("relay websocket error");_(C),this.failPending(C)}),D.addEventListener("close",()=>{if(clearTimeout(E),this.socket===D)this.socket=void 0,this.serverState=void 0,this.connecting=void 0;if(this.pending){if(this.pending.retryingBeforeResponse)return;if(this.retryPendingBeforeResponse(this.pending,"closed before response"))return;let C=Error("relay websocket closed before response");this.failPending(C)}})}).finally(()=>{this.connecting=void 0}),await this.connecting}sendPayload(f,_,m){let $=this.socket;if(!$||$.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");let D=I(),E,C,H=new Promise((j,b)=>{E=j,C=b});return{response:new Promise((j,b)=>{let K={payload:f,bodyText:_,resolve:j,reject:b,streamDone:!1,accepted:!1,responseStarted:!1,resolveDone:E,rejectDone:C,sentAt:D,optimisticResponse:m,retryAttempts:0,retryingBeforeResponse:!1};if(this.pending=K,this.resetPendingTimeout(K),$.send(JSON.stringify(f)),m)this.resolvePendingResponse(K,200,"OK",{"content-type":"text/event-stream","x-cortexkit-relay-optimistic":"true"})}),done:H}}resetPendingTimeout(f){clearTimeout(f.timeout),f.timeout=setTimeout(()=>{if(this.pending!==f)return;if(this.retryPendingBeforeResponse(f,"response timed out"))return;this.failPending(Error("relay websocket response timed out")),this.socket?.close()},45000)}retryPendingBeforeResponse(f,_){if(f.responseStartedAt!=null)return!1;if(f.streamDone)return!1;if(f.retryAttempts>=1)return!1;f.retryAttempts+=1,f.retryingBeforeResponse=!0,clearTimeout(f.timeout);let m=f.retryAttempts,$=f.payload.id;return F(`websocket ${_}; reconnecting and retrying full_sync session=${W(this.affinity)} request=${$} retry=${m}`),this.socket?.close(),this.socket=void 0,this.serverState=void 0,this.connecting=void 0,(async()=>{try{if(await this.ensureConnected(),this.pending!==f)return;let D=Rf(f.payload,f.bodyText);D.protocol=2,D.id=hf(),D.revision=(this.serverState?.revision??0)+1,f.payload=D,f.accepted=!1,f.acceptedAt=void 0,f.responseStartedAt=void 0,f.sentAt=I(),f.retryingBeforeResponse=!1;let E=this.socket;if(!E||E.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");this.resetPendingTimeout(f),F(`perf websocket retry_send session=${W(this.affinity)} request=${D.id} previous=${$} mode=full_sync retry=${m} bodyBytes=${f.bodyText.length} relayBytes=${JSON.stringify(D).length}`),E.send(JSON.stringify(D))}catch(D){if(f.retryingBeforeResponse=!1,this.pending===f)this.failPending(D)}})(),!0}handleBinaryChunk(f){let _=this.pending;if(!_?.responseStarted)return;_.streamController?.enqueue(Gm(f))}resolvePendingResponse(f,_,m,$){if(f.responseStarted)return;f.responseStarted=!0;let D=new ReadableStream({start:(E)=>{f.streamController=E},cancel:()=>{this.socket?.close()}});f.resolve(new Response(D,{status:_,statusText:m,headers:$}))}handleMessage(f){if(f.type==="keepalive"){if(this.pending)this.resetPendingTimeout(this.pending);return}let _=this.pending;if(!_)return;if("id"in f&&f.id&&f.id!==_.payload.id)return;if(f.type==="accepted"){let m=I();_.accepted=!0,_.acceptedAt=m,F(`perf websocket accepted session=${W(this.affinity)} request=${_.payload.id} sentMs=${R(m-_.sentAt)} mode=${_.payload.mode}`),this.serverState={hash:f.hash,revision:f.revision},o0(this.affinity,_.bodyText,f.hash,f.revision),this.resetPendingTimeout(_);return}if(f.type==="response_start"){let m=I();if(_.responseStartedAt=m,F(`perf websocket response_start session=${W(this.affinity)} request=${_.payload.id} sentMs=${R(m-_.sentAt)} upstreamMs=${_.acceptedAt==null?"unknown":R(m-_.acceptedAt)} status=${f.status}`),clearTimeout(_.timeout),this.resolvePendingResponse(_,f.status,f.statusText,f.headers),_.optimisticResponse&&f.status>=400)_.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
30
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_upstream_error",message:`Relay upstream returned HTTP ${f.status}`}})}
|
|
31
|
+
|
|
32
|
+
`)),this.finishPending();return}if(f.type==="chunk"){_.streamController?.enqueue(Fm(f.base64));return}if(f.type==="done"){this.finishPending();return}if(f.type==="error"){if(_.optimisticResponse&&_.responseStartedAt!=null){F(`websocket relay error during optimistic response session=${W(this.affinity)} request=${_.payload.id} status=${f.status} message=${f.message||"unknown"}`),_.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
33
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_error",message:f.message||"relay error"}})}
|
|
34
|
+
|
|
35
|
+
`)),this.finishPending(),this.socket?.close();return}if(f.status===409&&this.retryPendingBeforeResponse(_,f.message||"state mismatch"))return;let m=f.status===409?new Tf(f.message||"state mismatch"):Error(zm(f));this.failPending(m)}}finishPending(){let f=this.pending;if(!f)return;let _=I();if(F(`perf websocket done session=${W(this.affinity)} request=${f.payload.id} sentMs=${R(_-f.sentAt)} streamMs=${f.responseStartedAt==null?"unknown":R(_-f.responseStartedAt)}`),clearTimeout(f.timeout),!f.streamDone)f.streamDone=!0,f.streamController?.close();f.resolveDone(),this.pending=void 0}failPending(f){let _=this.pending;if(!_)return;if(clearTimeout(_.timeout),this.pending=void 0,_.responseStarted)_.streamController?.error(f);else _.reject(f);_.rejectDone(f)}}function Wm(f,_){let m=v0.get(_);if(m)return m;let $=new a0(f,_);return v0.set(_,$),$}async function mD(f){let{config:_,input:m,init:$,headers:D,body:E,fallback:C,affinity:H,optimisticResponse:U}=f;if(!_||!jm(m,E))return C();let j=H||D.get("x-session-affinity")||D.get("x-opencode-session");if(!j)return F("skipping relay: missing x-session-affinity header"),C();let b=E,K=Um(b),N=wf.get(j),G=Km({input:m,init:$,headers:D,bodyText:b,affinity:j,previous:N,nextHash:K});try{let S;if(_.transport==="websocket")try{S=await Wm(_,j).send(G,b,U===!0)}catch(B){F(`websocket relay failed session=${W(j)}; trying http relay: ${B instanceof Error?B.message:String(B)}`),S=await s0({config:_,payload:G,bodyText:b,fallback:C})}else S=await s0({config:_,payload:G,bodyText:b,fallback:C});if(!S.usedRelay)return S.response;if(S.transport==="http")o0(j,b,S.payload.next_hash,S.payload.revision);let O=JSON.stringify(S.payload).length;return F(`used relay transport=${S.transport} protocol=${S.protocol} mode=${S.payload.mode} status=${S.response.status} session=${W(j)} bodyBytes=${b.length} relayBytes=${O}`),await k0({affinity:j,transport:S.transport,protocol:S.protocol,mode:S.payload.mode,status:S.response.status,bodyText:b,previousBodyText:N?.body,payload:S.payload,relayBytes:O}),S.response}catch(S){if(!_.fallbackToDirect)throw F(`relay failed session=${W(j)} and fallbackToDirect=false: ${S instanceof Error?S.message:String(S)}`),S;return F(`relay failed; falling back direct session=${W(j)}: ${S instanceof Error?S.message:String(S)}`),C()}}var $D=`
|
|
36
|
+
async function hashBody(body) {
|
|
37
|
+
const bytes = new TextEncoder().encode(body)
|
|
38
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes)
|
|
39
|
+
const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('')
|
|
40
|
+
return 'sha256:' + hex
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function applyPatch(base, patch) {
|
|
44
|
+
return base.slice(0, patch.start) + patch.insert + base.slice(patch.start + patch.deleteCount)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function applyPatchSet(base, patch) {
|
|
48
|
+
if (!Array.isArray(patch)) return applyPatch(base, patch)
|
|
49
|
+
if (patch.length === 0) return base
|
|
50
|
+
|
|
51
|
+
let result = ''
|
|
52
|
+
let cursor = 0
|
|
53
|
+
for (const item of patch) {
|
|
54
|
+
if (item.start < cursor) return { error: 'overlapping patch', status: 400 }
|
|
55
|
+
result += base.slice(cursor, item.start)
|
|
56
|
+
result += item.insert
|
|
57
|
+
cursor = item.start + item.deleteCount
|
|
58
|
+
}
|
|
59
|
+
return result + base.slice(cursor)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function readState(env, affinity) {
|
|
63
|
+
const raw = await env.RELAY_STATE.get('session:' + affinity)
|
|
64
|
+
return raw ? JSON.parse(raw) : null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function writeState(env, affinity, state) {
|
|
68
|
+
await env.RELAY_STATE.put('session:' + affinity, JSON.stringify(state), { expirationTtl: 86400 })
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function resolveBody(env, payload) {
|
|
72
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
73
|
+
if (payload.mode === 'patch') {
|
|
74
|
+
const state = await readState(env, payload.affinity)
|
|
75
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
76
|
+
return { error: 'state mismatch', status: 409 }
|
|
77
|
+
}
|
|
78
|
+
return applyPatchSet(state.body, payload.patch)
|
|
79
|
+
}
|
|
80
|
+
return { error: 'unknown mode', status: 400 }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function prepareUpstream(env, payload) {
|
|
84
|
+
if ((payload.protocol !== 1 && payload.protocol !== 2) || payload.type !== 'request' || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
85
|
+
return { error: 'invalid payload', status: 400 }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const body = await resolveBody(env, payload)
|
|
89
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
90
|
+
|
|
91
|
+
if (typeof body !== 'string' || (await hashBody(body)) !== payload.next_hash) {
|
|
92
|
+
return { error: 'hash mismatch', status: 409 }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const stateWrite = writeState(env, payload.affinity, { body, hash: payload.next_hash, revision: payload.revision }).catch(() => {})
|
|
96
|
+
console.log(JSON.stringify({
|
|
97
|
+
relay: 'opencode-anthropic-auth',
|
|
98
|
+
transport: 'relay',
|
|
99
|
+
mode: payload.mode,
|
|
100
|
+
revision: payload.revision,
|
|
101
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
102
|
+
bodyBytes: body.length,
|
|
103
|
+
}))
|
|
104
|
+
|
|
105
|
+
return { body, stateWrite }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolveBodyFromState(state, payload) {
|
|
109
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
110
|
+
if (payload.mode === 'patch') {
|
|
111
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
112
|
+
return { error: 'state mismatch', status: 409 }
|
|
113
|
+
}
|
|
114
|
+
return applyPatchSet(state.body, payload.patch)
|
|
115
|
+
}
|
|
116
|
+
return { error: 'unknown mode', status: 400 }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function deferWorkerTask(task) {
|
|
120
|
+
return new Promise((resolve) => setTimeout(resolve, 0)).then(task)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function checkpointWebSocketState(env, payload, body, nextState) {
|
|
124
|
+
return deferWorkerTask(async () => {
|
|
125
|
+
try {
|
|
126
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
127
|
+
throw new Error('hash mismatch')
|
|
128
|
+
}
|
|
129
|
+
await writeState(env, payload.affinity, nextState)
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.log(JSON.stringify({
|
|
132
|
+
relay: 'opencode-anthropic-auth',
|
|
133
|
+
transport: 'websocket',
|
|
134
|
+
event: 'checkpoint_write_failed',
|
|
135
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
136
|
+
message: error instanceof Error ? error.message : String(error),
|
|
137
|
+
}))
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function prepareWebSocketUpstream(env, state, payload) {
|
|
143
|
+
if (payload.protocol !== 2 || payload.type !== 'request' || !payload.id || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
144
|
+
return { error: 'invalid payload', status: 400 }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const body = resolveBodyFromState(state, payload)
|
|
148
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
149
|
+
if (typeof body !== 'string') return { error: 'invalid body', status: 400 }
|
|
150
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
151
|
+
return { error: 'hash mismatch', status: 409 }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const nextState = { body, hash: payload.next_hash, revision: payload.revision }
|
|
155
|
+
const checkpoint = checkpointWebSocketState(env, payload, body, nextState)
|
|
156
|
+
const logAccepted = () => console.log(JSON.stringify({
|
|
157
|
+
relay: 'opencode-anthropic-auth',
|
|
158
|
+
transport: 'websocket',
|
|
159
|
+
mode: payload.mode,
|
|
160
|
+
revision: payload.revision,
|
|
161
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
162
|
+
bodyBytes: body.length,
|
|
163
|
+
}))
|
|
164
|
+
|
|
165
|
+
return { body, state: nextState, checkpoint, logAccepted }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function headersToObject(headers) {
|
|
169
|
+
const result = {}
|
|
170
|
+
for (const [key, value] of headers.entries()) result[key] = value
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function handleRelayPayload(env, payload) {
|
|
175
|
+
const prepared = await prepareUpstream(env, payload)
|
|
176
|
+
if (prepared.error) return prepared
|
|
177
|
+
const upstream = await fetch(payload.upstream.url, {
|
|
178
|
+
method: payload.upstream.method || 'POST',
|
|
179
|
+
headers: payload.upstream.headers,
|
|
180
|
+
body: prepared.body,
|
|
181
|
+
})
|
|
182
|
+
return { upstream, stateWrite: prepared.stateWrite }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function handleWebSocket(socket, env, ctx, payload, getState, setState) {
|
|
186
|
+
const heartbeat = setInterval(() => {
|
|
187
|
+
try {
|
|
188
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'keepalive' }))
|
|
189
|
+
} catch {
|
|
190
|
+
clearInterval(heartbeat)
|
|
191
|
+
}
|
|
192
|
+
}, 15000)
|
|
193
|
+
try {
|
|
194
|
+
const result = await prepareWebSocketUpstream(env, getState(), payload)
|
|
195
|
+
if (result.error) {
|
|
196
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: result.status, message: result.error }))
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
setState(result.state)
|
|
201
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'accepted', id: payload.id, hash: result.state.hash, revision: result.state.revision }))
|
|
202
|
+
ctx?.waitUntil?.(deferWorkerTask(result.logAccepted))
|
|
203
|
+
|
|
204
|
+
const upstreamPromise = fetch(payload.upstream.url, {
|
|
205
|
+
method: payload.upstream.method || 'POST',
|
|
206
|
+
headers: payload.upstream.headers,
|
|
207
|
+
body: result.body,
|
|
208
|
+
})
|
|
209
|
+
ctx?.waitUntil?.(result.checkpoint)
|
|
210
|
+
const upstream = await upstreamPromise
|
|
211
|
+
socket.send(JSON.stringify({
|
|
212
|
+
protocol: 2,
|
|
213
|
+
type: 'response_start',
|
|
214
|
+
id: payload.id,
|
|
215
|
+
status: upstream.status,
|
|
216
|
+
statusText: upstream.statusText,
|
|
217
|
+
headers: headersToObject(upstream.headers),
|
|
218
|
+
}))
|
|
219
|
+
|
|
220
|
+
const reader = upstream.body?.getReader()
|
|
221
|
+
if (reader) {
|
|
222
|
+
while (true) {
|
|
223
|
+
const { done, value } = await reader.read()
|
|
224
|
+
if (done) break
|
|
225
|
+
socket.send(value)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'done', id: payload.id }))
|
|
229
|
+
} catch (error) {
|
|
230
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
231
|
+
} finally {
|
|
232
|
+
clearInterval(heartbeat)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default {
|
|
237
|
+
async fetch(request, env, ctx) {
|
|
238
|
+
if (request.headers.get('Upgrade') === 'websocket') {
|
|
239
|
+
const url = new URL(request.url)
|
|
240
|
+
const token = url.searchParams.get('token')
|
|
241
|
+
const affinity = url.searchParams.get('affinity')
|
|
242
|
+
if (token !== env.RELAY_TOKEN) return new Response('unauthorized', { status: 401 })
|
|
243
|
+
if (!affinity) return new Response('missing affinity', { status: 400 })
|
|
244
|
+
const pair = new WebSocketPair()
|
|
245
|
+
const client = pair[0]
|
|
246
|
+
const server = pair[1]
|
|
247
|
+
server.binaryType = 'arraybuffer'
|
|
248
|
+
let state = null
|
|
249
|
+
let ready = false
|
|
250
|
+
server.accept()
|
|
251
|
+
const loadState = readState(env, affinity).then((loadedState) => {
|
|
252
|
+
state = loadedState
|
|
253
|
+
ready = true
|
|
254
|
+
server.send(JSON.stringify({
|
|
255
|
+
protocol: 2,
|
|
256
|
+
type: 'ready',
|
|
257
|
+
state: state ? { hash: state.hash, revision: state.revision } : null,
|
|
258
|
+
}))
|
|
259
|
+
}).catch((error) => {
|
|
260
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
261
|
+
server.close(1011, 'state load failed')
|
|
262
|
+
})
|
|
263
|
+
ctx?.waitUntil?.(loadState)
|
|
264
|
+
if (!ctx?.waitUntil) void loadState
|
|
265
|
+
let busy = false
|
|
266
|
+
server.addEventListener('message', (event) => {
|
|
267
|
+
if (!ready) {
|
|
268
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 425, message: 'relay state is not ready' }))
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
if (busy) {
|
|
272
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 429, message: 'request already in flight' }))
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
let payload
|
|
276
|
+
try {
|
|
277
|
+
payload = JSON.parse(event.data)
|
|
278
|
+
} catch {
|
|
279
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 400, message: 'invalid JSON payload' }))
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
payload.affinity = affinity
|
|
283
|
+
busy = true
|
|
284
|
+
const run = handleWebSocket(server, env, ctx, payload, () => state, (nextState) => { state = nextState }).finally(() => { busy = false })
|
|
285
|
+
ctx?.waitUntil?.(run)
|
|
286
|
+
if (!ctx?.waitUntil) void run
|
|
287
|
+
})
|
|
288
|
+
return new Response(null, { status: 101, webSocket: client })
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (request.method === 'GET') {
|
|
292
|
+
return Response.json({ status: 'ok', transports: ['http', 'websocket'] })
|
|
293
|
+
}
|
|
294
|
+
if (request.method !== 'POST') return new Response('method not allowed', { status: 405 })
|
|
295
|
+
if (request.headers.get('x-relay-token') !== env.RELAY_TOKEN) {
|
|
296
|
+
return new Response('unauthorized', { status: 401 })
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
try {
|
|
300
|
+
const payload = await request.json()
|
|
301
|
+
const result = await handleRelayPayload(env, payload)
|
|
302
|
+
if (result.error) return Response.json({ error: result.error }, { status: result.status })
|
|
303
|
+
|
|
304
|
+
if (result.stateWrite) ctx.waitUntil(result.stateWrite)
|
|
305
|
+
|
|
306
|
+
const upstream = result.upstream
|
|
307
|
+
return new Response(upstream.body, {
|
|
308
|
+
status: upstream.status,
|
|
309
|
+
statusText: upstream.statusText,
|
|
310
|
+
headers: upstream.headers,
|
|
311
|
+
})
|
|
312
|
+
} catch (error) {
|
|
313
|
+
return Response.json(
|
|
314
|
+
{ error: error instanceof Error ? error.message : 'internal relay error' },
|
|
315
|
+
{ status: 502 },
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
}
|
|
320
|
+
`;var CD="claude-routing",lf=["main-first","fallback-first"],yf="main-first",e0="Usage: `/claude-routing`, `/claude-routing main-first`, or `/claude-routing fallback-first`.";function Om(f){return typeof f==="string"&&lf.includes(f)?f:yf}function HD(f){return Om(f?.routing?.mode)}async function UD(f,_=L()){let m=await Y(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return m.routing={...m.routing??{},mode:f},await A(m,_),m}function Bm(f){let _=f.trim().toLowerCase().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&lf.includes(_[0]))return{type:"mode",mode:_[0]};if(_.length===2&&_[0]==="mode"&&lf.includes(_[1]))return{type:"mode",mode:_[1]};return{type:"usage"}}function Vm(f){if(f==="fallback-first")return"Try usable fallback accounts before the main account. If no fallback succeeds, try the main account.";return"Try the main account first. Use fallback accounts only when quota policy or fallback errors require it."}function kf(f){let _=f?.mode??yf;return["## Claude Routing Status","",`- Mode: \`${_}\``,`- Behavior: ${Vm(_)}`,"",e0].join(`
|
|
321
|
+
`)}function MD(f){let _=Bm(f.argumentsText),m=f.mode??yf;if(_.type==="status")return kf({mode:m});if(_.type==="mode")return["## Claude Routing Updated","",`Mode updated to \`${_.mode}\`.`,"",...kf({mode:_.mode}).split(`
|
|
322
|
+
`).slice(2)].join(`
|
|
323
|
+
`);return["## Claude Routing Usage","",e0,"",...kf({mode:m}).split(`
|
|
324
|
+
`).slice(2)].join(`
|
|
325
|
+
`)}export{Lm as a,gf as b,Xm as c,Zm as d,Ym as e,Am as f,Qm as g,nf as h,xm as i,Im as j,q as k,ef as l,Rm as m,wm as n,Z as o,L as p,Y as q,A as r,Wf as s,nm as t,d1 as u,cm as v,sm as w,rm as x,tm as y,om as z,am as A,em as B,f$ as C,_$ as D,K0 as E,t1 as F,p as G,Ff as H,J0 as I,__ as J,D$ as K,E$ as L,C$ as M,H$ as N,C_ as O,U$ as P,Q0 as Q,O$ as R,b$ as S,K$ as T,N$ as U,X0 as V,X$ as W,Z$ as X,T_ as Y,Af as Z,P0 as _,R_ as $,Y$ as aa,i_ as ba,T$ as ca,R$ as da,s_ as ea,w$ as fa,k$ as ga,l$ as ha,y$ as ia,e_ as ja,p$ as ka,T as la,n$ as ma,c$ as na,s$ as oa,fD as pa,_D as qa,mD as ra,$D as sa,CD as ta,HD as ua,UD as va,Bm as wa,MD as xa};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{mkdir as y,readFile as z,writeFile as C}from"node:fs/promises";import{tmpdir as G}from"node:os";import{dirname as H,join as v}from"node:path";var J="OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE",K=v(G(),"opencode-anthropic-auth"),M=v(K,"sidebar-state.json");function x(){return process.env[J]||M}var O={main:{quota:null},fallbacks:[],activeId:void 0,route:"main",relay:null,fastMode:!1,lastUpdated:0};async function X(){try{let q=await z(x(),"utf8");return JSON.parse(q)}catch{return O}}async function Y(q){try{let u=x();await y(H(u),{recursive:!0}),await C(u,JSON.stringify(q),"utf8")}catch{}}
|
|
2
|
+
export{x as ya,O as za,X as Aa,Y as Ba};
|