@cortexkit/opencode-anthropic-auth 1.9.1 → 1.9.3
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/README.md +2 -1
- package/dist/cli.js +1 -1
- package/dist/index-68qrf9fn.js +410 -0
- package/dist/index-9yjbmhf1.js +2 -0
- package/dist/index-agh52sak.js +2 -0
- package/dist/index.js +9 -9
- package/dist/sidebar-state.d.ts +9 -0
- package/dist/sidebar-state.js +1 -1
- package/dist/tui-preferences.d.ts +41 -0
- package/dist/tui-preferences.js +6 -0
- package/package.json +11 -5
- package/src/sidebar-state.ts +54 -0
- package/src/tui-preferences.ts +331 -0
- package/src/tui.tsx +300 -78
- package/dist/index-99mvcpj7.js +0 -2
- package/dist/index-hjkkewsy.js +0 -409
package/README.md
CHANGED
|
@@ -492,8 +492,9 @@ ls "$(node -p 'require("node:os").tmpdir()')/opencode-anthropic-auth-dumps"
|
|
|
492
492
|
Each filename includes a sanitized session/affinity segment so dumps from different sessions are easier to find. Each request gets:
|
|
493
493
|
|
|
494
494
|
- `*.body.json` — final rewritten Anthropic request body.
|
|
495
|
-
- `*.relay.json` — redacted relay payload/frame metadata.
|
|
496
495
|
- `*.meta.json` — hashes, byte counts, diff ranges, model, `messages[0]` hash, later-message hash, and cache-relevant structure.
|
|
496
|
+
- `*.relay.json` — redacted relay payload/frame metadata for relay requests.
|
|
497
|
+
- `*.request.json` — redacted direct request URL, method, and headers for direct requests.
|
|
497
498
|
|
|
498
499
|
Dump state is persisted in the active sidecar config as `dump.enabled` (`~/.config/opencode/anthropic-auth.json` for OpenCode, `~/.pi/agent/anthropic-auth.json` for Pi). Dumps may contain prompt content and should be treated as sensitive local debugging artifacts.
|
|
499
500
|
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{Oa as I,Qa as $,m as w,n as k,p as A,r as R,t as d,u as l,v as p}from"./index-68qrf9fn.js";import"./index-agh52sak.js";import{stdin as E,stdout as U}from"node:process";import{createInterface as _}from"node:readline/promises";function g(){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 y(){console.log(`Usage:
|
|
3
3
|
opencode-anthropic-auth login [label]
|
|
4
4
|
opencode-anthropic-auth api add [label]
|
|
5
5
|
opencode-anthropic-auth list
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
var Lf="9d1c250a-e61b-44d9-88ed-5944d1962f5e",M_={console:"https://platform.claude.com/oauth/authorize",max:"https://claude.ai/oauth/authorize"},hf="https://platform.claude.com/oauth/code/callback",Vf="https://platform.claude.com/v1/oauth/token",C_=["org:create_api_key","user:profile","user:inference","user:sessions:claude_code","user:mcp_servers","user:file_upload"],z1="mcp_";var L_="fast-mode-2026-02-01";function J1(f,_){let D=(f??"").split(",").map((E)=>E.trim()).filter(Boolean);return[...new Set([...D,..._])].join(",")}function W1(f){return typeof f==="string"&&(f.startsWith("claude-opus-4-6")||f.startsWith("claude-opus-4-7")||f.startsWith("claude-opus-4-8"))}var Y1="You are OpenCode",X1="You are a Claude agent, built on Anthropic's Claude Agent SDK.",Z1=["<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",If="67b",O_="sdk-cli",U_="0.94.0",H_="v24.3.0",S_="claude-cli/2.1.141 (external, sdk-cli)",N_=["explicit","automatic","hybrid"],Of="explicit",h1=["github.com/anomalyco/opencode","opencode.ai/docs"],V1=[{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 b_(f){let _="";for(let D of f)_+=String.fromCharCode(D);return btoa(_).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function A_(){let f=new Uint8Array(64);crypto.getRandomValues(f);let _=b_(f),D=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(_));return{verifier:_,challenge:b_(new Uint8Array(D)),method:"S256"}}function I0(f){if(!f)return;let _=Number(f);if(Number.isFinite(_)&&_>0)return Math.ceil(_);let D=Date.parse(f);if(Number.isFinite(D)){let E=Math.ceil((D-Date.now())/1000);return E>0?E:void 0}return}class y extends Error{status;body;retryAfter;constructor(f,_,D){super(`Claude OAuth refresh failed: ${f} — ${_}`);this.status=f,this.body=_,this.name="ClaudeOAuthRefreshError",this.retryAfter=I0(D??void 0)}}function Q0(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 B_(f){let _=f.fetchImpl??fetch,D=f.maxRetries??2,E=f.baseDelayMs??500;for(let $=0;$<=D;$++)try{if($>0){let L=E*2**($-1);await new Promise((O)=>setTimeout(O,L))}let m=await _(Vf,{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:Lf})});if(!m.ok){if(m.status>=500&&$<D){await m.body?.cancel().catch(()=>{});continue}let L=await m.text().catch(()=>"");throw new y(m.status,L,m.headers.get("retry-after"))}let M=await m.json(),C=f.now?.()??Date.now();return{access:M.access_token,refresh:M.refresh_token??f.refreshToken,expires:C+M.expires_in*1000,expiresIn:M.expires_in}}catch(m){if(m instanceof y)throw m;if($<D&&Q0(m))continue;throw m}throw Error("Token refresh exhausted all retries")}function q0(){return crypto.randomUUID().replace(/-/g,"")}function R0(f){let _=f.trim();try{let M=new URL(_),C=M.searchParams.get("code"),L=M.searchParams.get("state");if(C&&L)return{code:C,state:L}}catch{}let D=_.split("#");if(D.length===2&&D[0]&&D[1])return{code:D[0],state:D[1]};let E=new URLSearchParams(_),$=E.get("code"),m=E.get("state");if($&&m)return{code:$,state:m};return null}async function P0(f,_,D){let E=await fetch(Vf,{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:Lf,redirect_uri:D,code_verifier:_})});if(!E.ok)return{type:"failed"};let $=await E.json();return{type:"success",refresh:$.refresh_token,access:$.access_token,expires:Date.now()+$.expires_in*1000}}async function P1(f){let _=await A_(),D=q0(),E=new URL(M_[f],import.meta.url);return E.searchParams.set("code","true"),E.searchParams.set("client_id",Lf),E.searchParams.set("response_type","code"),E.searchParams.set("redirect_uri",hf),E.searchParams.set("scope",C_.join(" ")),E.searchParams.set("code_challenge",_.challenge),E.searchParams.set("code_challenge_method","S256"),E.searchParams.set("state",D),{url:E.toString(),redirectUri:hf,state:D,verifier:_.verifier}}async function x1(f,_,D,E){let $=R0(f);if(!$)return{type:"failed"};if(E&&$.state!==E)return{type:"failed"};return P0($,_,D)}import*as F_ from"node:fs";import*as K_ from"node:os";import*as j_ from"node:path";var x0=j_.join(K_.tmpdir(),"opencode-anthropic-auth.log"),G_=!1,T0=500,w0=50,o=[],n=null;function Qf(){if(n)clearTimeout(n),n=null;if(o.length===0)return;let f=o.join("");o=[];try{F_.appendFileSync(x0,f)}catch{}}function y0(){if(n)return;n=setTimeout(()=>{n=null,Qf()},T0)}function l0(f){if(f===void 0)return"";if(f instanceof Error)return` ${f.message}${f.stack?`
|
|
3
|
+
${f.stack}`:""}`;return` ${JSON.stringify(f)}`}function Q(f,_){if(G_)return;try{if(o.push(`[${new Date().toISOString()}] ${f}${l0(_)}
|
|
4
|
+
`),o.length>=w0)Qf();else y0()}catch{}}function A(f,_){Q(`[relay] ${f}`,_)}if(!G_)process.on("exit",Qf);import{createHash as I_,randomUUID as yf}from"node:crypto";import{mkdir as i0,readFile as Pf,rename as k0,rm as z_,stat as p0,writeFile as xf}from"node:fs/promises";import{homedir as d0}from"node:os";import{dirname as Q_,join as a}from"node:path";var v0=globalThis.setTimeout.bind(globalThis),u0=globalThis.clearTimeout.bind(globalThis),q_="anthropic-auth.json",r0="anthropic-auth-state.json",n0="https://api.anthropic.com/api/oauth/usage";function X(f){return f.type==="oauth"}function u1(f){return f.type==="api"}function g0(f){let _=f?.trim();if(!_)return!1;try{let D=new URL(_);return(D.protocol==="http:"||D.protocol==="https:")&&!D.username&&!D.password}catch{return!1}}function r1(f){return f.costZeroing?.enabled!==!1}var s0=[401,403,429],R_=240,c0=R_;var t0=300000,o0=3600000,e0=86400000,a0=60000,fD=900000,_D=300000,DD=5,J_={five_hour:0,seven_day:0},ED=!0,$D=60000,mD=60000,MD=600000,CD=1e4,LD=100;function OD(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return a(process.env.XDG_CONFIG_HOME||a(d0(),".config"),"opencode")}function z(){return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim()||a(OD(),q_)}function lf(f=z()){let _=process.env.OPENCODE_ANTHROPIC_AUTH_STATE_FILE?.trim();if(_)return _;return f.endsWith(q_)?a(Q_(f),r0):`${f}.state.json`}function N(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function W_(f){return{id:typeof f.id==="string"&&f.id.trim()?f.id.trim():yf(),label:typeof f.label==="string"?f.label: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}}function UD(f){if(!N(f))return null;if(f.type==="api"){let _=typeof f.baseURL==="string"?f.baseURL.trim():"",D=typeof f.apiKey==="string"?f.apiKey.trim():"";if(!g0(_))return null;let E=f.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...W_(f),type:"api",apiKey:D||void 0,baseURL:_,authHeader:E}}if(f.type!=="oauth")return null;if(typeof f.refresh!=="string"||!f.refresh.trim())return null;return{...W_(f),type:"oauth",access:typeof f.access==="string"?f.access:void 0,refresh:f.refresh,expires:typeof f.expires==="number"?f.expires:void 0,lastRefreshedAt:typeof f.lastRefreshedAt==="number"?f.lastRefreshedAt:void 0,lastRefreshError:Y_(f.lastRefreshError),lastQuotaRefreshError:Y_(f.lastQuotaRefreshError),quota:HD(f.quota)}}function Y_(f){if(!N(f))return;if(typeof f.message!=="string")return;let _=Number(f.checkedAt);if(!Number.isFinite(_))return;let D=Number(f.nextRetryAt),E=Number(f.retryCount);return{message:f.message,checkedAt:_,nextRetryAt:Number.isFinite(D)?D:void 0,retryCount:Number.isFinite(E)?E:void 0,tokenHash:typeof f.tokenHash==="string"?f.tokenHash:void 0}}function HD(f){if(!N(f))return;let _={};for(let D of["five_hour","seven_day"]){let E=f[D];if(!N(E))continue;let $=Number(E.usedPercent),m=Number(E.remainingPercent),M=Number(E.checkedAt);if(!Number.isFinite($)||!Number.isFinite(m)||!Number.isFinite(M))continue;_[D]={usedPercent:$,remainingPercent:m,checkedAt:M,resetsAt:typeof E.resetsAt==="string"?E.resetsAt:void 0}}return Object.keys(_).length?_:void 0}function SD(f){if(!N(f)||!Array.isArray(f.accounts))return null;return{version:1,main:{type:"opencode",provider:"anthropic"},routing:N(f.routing)?f.routing:void 0,fallbackOn:Array.isArray(f.fallbackOn)?f.fallbackOn.filter((_)=>Number.isInteger(_)):void 0,refresh:N(f.refresh)?f.refresh:void 0,quota:N(f.quota)?f.quota:void 0,claudeCache:N(f.claudeCache)?f.claudeCache:void 0,dump:N(f.dump)?f.dump:void 0,claudeFast:N(f.claudeFast)?f.claudeFast:void 0,costZeroing:N(f.costZeroing)?f.costZeroing:void 0,cacheKeep:N(f.cacheKeep)?f.cacheKeep:void 0,relay:N(f.relay)?f.relay:void 0,killswitch:N(f.killswitch)?f.killswitch:void 0,accounts:f.accounts.map(UD).filter((_)=>_!=null)}}async function Uf(f){try{return{exists:!0,value:JSON.parse(await Pf(f,"utf8"))}}catch(_){if(_.code==="ENOENT")return{exists:!1,value:null};return{exists:!1,value:null}}}function T(f){return Object.fromEntries(Object.entries(f).filter(([,_])=>_!==void 0))}function ND(f,_){if(!N(f))return f;let D=N(_)?_:{},E=N(D.main)?D.main:void 0,$=N(D.accounts)?D.accounts:{},m=N(f.quota)?f.quota:{},M=N(f.refresh)?f.refresh:{},C=E??m,L=E??M,O=Array.isArray(f.accounts)?f.accounts.map((U)=>{if(!N(U))return U;let b=typeof U.id==="string"&&N($[U.id])?$[U.id]:{};return{...U,...b}}):[];return{...f,refresh:T({...M,mainLastRefreshError:L.lastRefreshError,mainRefreshLeaseId:L.refreshLeaseId,mainRefreshLeaseUntil:L.refreshLeaseUntil,mainRefreshLeaseTokenHash:L.refreshLeaseTokenHash}),quota:T({...m,mainQuota:C.quota,mainQuotaCheckedAt:C.quotaCheckedAt,mainQuotaToken:C.quotaToken,mainLastQuotaApiError:C.lastQuotaApiError}),accounts:O}}async function V(f=z()){let _=await Uf(f);if(!_.exists)return null;let D=await Uf(lf(f));return SD(ND(_.value,D.value))}async function bD(f){let _=await Uf(f);return N(_.value)?_.value:{}}function AD(f){return Object.fromEntries(Object.entries(f).filter(([,_])=>_!==void 0))}function BD(f){return T({id:f.id,label:f.label,type:f.type,enabled:f.enabled,addedAt:f.addedAt,baseURL:f.type==="api"?f.baseURL:void 0,authHeader:f.type==="api"?f.authHeader:void 0})}function P_(f){if(f.type==="api")return T({apiKey:f.apiKey,lastUsed:f.lastUsed});return T({access:f.access,refresh:f.refresh,expires:f.expires,lastUsed:f.lastUsed,lastRefreshedAt:f.lastRefreshedAt,lastRefreshError:f.lastRefreshError,lastQuotaRefreshError:f.lastQuotaRefreshError,quota:f.quota})}function ff(f){return Math.max(f?.five_hour?.checkedAt??0,f?.seven_day?.checkedAt??0)}function FD(f,_){if(!N(f))return _;let D=f,E=ff(D.quota),$=ff(_.quota);if(E>$){let M=Boolean(D.access&&_.access&&D.access!==_.access),C=D.lastRefreshedAt??0,L=_.lastRefreshedAt??0;if(M&&L<=C){let O={...D};if(typeof _.lastUsed==="number"&&(typeof D.lastUsed!=="number"||_.lastUsed>D.lastUsed))O.lastUsed=_.lastUsed;return O}return{...D,..._,quota:D.quota,lastQuotaRefreshError:D.lastQuotaRefreshError}}let m={...D,..._};if(!("lastQuotaRefreshError"in _))delete m.lastQuotaRefreshError;if(!("lastRefreshError"in _))delete m.lastRefreshError;return m}function KD(f){let _=f.refresh?T({enabled:f.refresh.enabled,intervalMinutes:f.refresh.intervalMinutes,refreshBeforeExpiryMinutes:f.refresh.refreshBeforeExpiryMinutes}):void 0,D=f.quota?T({enabled:f.quota.enabled,checkIntervalMinutes:f.quota.checkIntervalMinutes,refreshEveryNRequests:f.quota.refreshEveryNRequests,minimumRemaining:f.quota.minimumRemaining,failClosedOnUnknownQuota:f.quota.failClosedOnUnknownQuota,showToasts:f.quota.showToasts}):void 0;return AD({version:1,main:f.main,routing:f.routing,fallbackOn:f.fallbackOn,refresh:_,quota:D,claudeCache:f.claudeCache,dump:f.dump,claudeFast:f.claudeFast,costZeroing:f.costZeroing,cacheKeep:f.cacheKeep,relay:f.relay,killswitch:f.killswitch,accounts:f.accounts.map(BD)})}function jD(f){let _=Object.fromEntries(f.accounts.map((D)=>[D.id,P_(D)]));return{version:1,main:T({quota:f.quota?.mainQuota,quotaCheckedAt:f.quota?.mainQuotaCheckedAt,quotaToken:f.quota?.mainQuotaToken,lastQuotaApiError:f.quota?.mainLastQuotaApiError,lastRefreshError:f.refresh?.mainLastRefreshError,refreshLeaseId:f.refresh?.mainRefreshLeaseId,refreshLeaseUntil:f.refresh?.mainRefreshLeaseUntil,refreshLeaseTokenHash:f.refresh?.mainRefreshLeaseTokenHash}),accounts:_}}async function Tf(f,_){await i0(Q_(f),{recursive:!0});let D=`${f}.${yf()}.tmp`;await xf(D,`${JSON.stringify(_,null,2)}
|
|
5
|
+
`,{encoding:"utf8",mode:384}),await k0(D,f)}async function q(f,_=z()){let E={...await bD(_),...KD(f)};await Tf(_,E),await Tf(lf(_),jD(f))}function GD(f,_){f.main=f.main??{};let D=typeof f.main.quotaCheckedAt==="number"?f.main.quotaCheckedAt:ff(f.main.quota),E=typeof _.quota?.mainQuotaCheckedAt==="number"?_.quota.mainQuotaCheckedAt:ff(_.quota?.mainQuota);if(D>E)return;f.main.quota=_.quota?.mainQuota,f.main.quotaCheckedAt=_.quota?.mainQuotaCheckedAt,f.main.quotaToken=_.quota?.mainQuotaToken,f.main.lastQuotaApiError=_.quota?.mainLastQuotaApiError}function zD(f,_){f.main=f.main??{},f.main.lastRefreshError=_.refresh?.mainLastRefreshError,f.main.refreshLeaseId=_.refresh?.mainRefreshLeaseId,f.main.refreshLeaseUntil=_.refresh?.mainRefreshLeaseUntil,f.main.refreshLeaseTokenHash=_.refresh?.mainRefreshLeaseTokenHash}function wf(f){if(Array.isArray(f))return f.map(wf);if(!N(f))return f;return Object.fromEntries(Object.entries(f).filter(([,_])=>_!==void 0).map(([_,D])=>[_,wf(D)]))}async function JD(f,_=z(),D={mainQuota:!0,mainRefresh:!0,accounts:!0}){let E=lf(_),$=(await Uf(E)).value,m=N($)?{...$,version:1}:{version:1};if(D.mainQuota)GD(m,f);if(D.mainRefresh)zD(m,f);if(D.accounts){let M=D.accounts===!0?null:new Set(D.accounts);m.accounts={...N(m.accounts)?m.accounts:{}};for(let C of f.accounts){if(M&&!M.has(C.id))continue;m.accounts[C.id]=FD(m.accounts[C.id],P_(C))}if(M){for(let C of M)if(!f.accounts.some((L)=>L.id===C))delete m.accounts[C]}}await Tf(E,wf(m))}async function Hf(f){let D=`${f.path??z()}.${f.name}.lock`,E=a(D,"owner.json"),$=yf(),m=f.now??Date.now,M=null,C=!1;async function L(){try{return JSON.parse(await Pf(D,"utf8"))}catch(K){if(K.code!=="EISDIR")throw K;return JSON.parse(await Pf(E,"utf8"))}}async function O(){await xf(D,`${JSON.stringify({ownerId:$,expiresAt:m()+f.ttlMs})}
|
|
6
|
+
`,{encoding:"utf8",mode:384})}async function U(){try{return await xf(D,`${JSON.stringify({ownerId:$,expiresAt:m()+f.ttlMs})}
|
|
7
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(K){let j=K.code;if(j==="EEXIST"||j==="EISDIR")return!1;throw K}}function b(){if(!f.renew||C)return;let K=f.renewIntervalMs??Math.max(1000,Math.floor(f.ttlMs/3));if(M=v0(()=>{(async()=>{try{let j=await L(),P=m();if(C||j?.ownerId!==$||Number(j?.expiresAt)<=P)return;await O(),b()}catch{}})()},K),"unref"in M)M.unref()}if(!await U()){try{let K=await L();if(Number(K?.expiresAt)>m())return null}catch{try{if((await p0(D)).mtimeMs+f.ttlMs>Date.now())return null}catch{return null}}if(await z_(D,{recursive:!0,force:!0}).catch(()=>{}),!await U())return null}return b(),{release:async()=>{if(C=!0,M)u0(M),M=null;try{if((await L())?.ownerId!==$)return}catch{return}await z_(D,{recursive:!0,force:!0}).catch(()=>{})}}}function n1(f){return f?.claudeCache?.enabled===!0}function WD(f){return typeof f==="string"&&N_.includes(f)?f:Of}function YD(f){return WD(f?.claudeCache?.mode)}async function g1(f,_,D=z()){let E=await V(D)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return E.claudeCache={...E.claudeCache??{},enabled:f,mode:_??YD(E)},await q(E,D),E}async function s1(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.claudeCache={...D.claudeCache??{},enabled:D.claudeCache?.enabled===!0,mode:f},await q(D,_),D}function c1(f){return f?.dump?.enabled===!0}async function t1(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.dump={...D.dump??{},enabled:f},await q(D,_),D}function o1(f){return f?.claudeFast?.enabled===!0}async function e1(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.claudeFast={...D.claudeFast??{},enabled:f},await q(D,_),D}async function a1(f,_,D=z()){let E=await V(D)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return E.cacheKeep={enabled:!0,startHour:f,endHour:_},await q(E,D),E}async function f$(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.cacheKeep={...D.cacheKeep??{},enabled:f},await q(D,_),D}function XD(f){return f?.fallbackOn?.length?f.fallbackOn:s0}function _$(f,_){return XD(_).includes(f)}function x_(f){let _=f?.quota?.minimumRemaining||{};return{five_hour:_.five_hour??_["5h"]??J_.five_hour,seven_day:_.seven_day??_["1w"]??J_.seven_day}}function _f(f){return f?.quota?.enabled!==!1}function ZD(f){return f?.refresh?.enabled!==!1}function hD(f){return Math.floor(Math.random()*Math.max(0,f))}function VD(f){let _=f?.refresh?.refreshBeforeExpiryMinutes??c0;return Math.max(R_,_)*60000}function T_(f){return I_("sha256").update(f).digest("hex")}function ID(f){if(f instanceof y)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 QD(f){let _=T_(f.refreshToken),E=(f.previous?.tokenHash===_?f.previous.retryCount??0:0)+1,$;if(f.error instanceof y&&f.error.retryAfter)$=f.error.retryAfter*1000;else if(ID(f.error))$=Math.min(o0,t0*2**Math.min(E-1,6));else $=e0;return{message:Df(f.error),checkedAt:f.now,nextRetryAt:f.now+$,retryCount:E,tokenHash:_}}function e(f,_,D){if(!f?.nextRetryAt||f.nextRetryAt<=D)return!1;if(!_)return!0;return f.tokenHash===T_(_)}function qf(f,_){return`Claude OAuth refresh is backed off for ${Math.max(1,Math.ceil(((f.nextRetryAt??_)-_)/1000))}s after: ${f.message}`}function Sf(f){let D=(f.previous?.retryCount??0)+1,E=k_(f.error)?Math.min(fD,a0*2**Math.min(D-1,6)):_D;return{message:Df(f.error),checkedAt:f.now,nextRetryAt:f.now+E,retryCount:D}}function g(f,_){if(!f?.nextRetryAt||f.nextRetryAt<=_)return!1;return!0}function D$(f,_){return`Quota API backed off for ${Math.max(1,Math.ceil(((f.nextRetryAt??_)-_)/1000))}s after: ${f.message}`}function Z(f){let _=f?.quota?.checkIntervalMinutes??DD;return Math.max(1,_)*60000}function w_(f){if(!f?.quota?.mainQuota||!f.quota.mainQuotaCheckedAt)return null;return{quota:f.quota.mainQuota,checkedAt:f.quota.mainQuotaCheckedAt,tokenFingerprint:f.quota.mainQuotaToken}}function y_(f){let _=f?.quota?.refreshEveryNRequests;return typeof _==="number"&&Number.isFinite(_)&&_>0?Math.floor(_):0}function kf(f){return f?.quota?.failClosedOnUnknownQuota??ED}function l_(f,_){if(!_f(_))return!0;let D=x_(_);for(let E of["five_hour","seven_day"]){let $=f?.[E];if(!$)return!kf(_);if($.remainingPercent<D[E])return!1}return!0}var h={five_hour:5,seven_day:10};function X_(f){return{five_hour:f?.five_hour??f?.["5h"]??h.five_hour,seven_day:f?.seven_day??f?.["1w"]??h.seven_day}}function qD(f){return f?.killswitch?.enabled===!0}function RD(f,_){if(!f?.killswitch)return h;if(_&&f.killswitch.accounts?.[_])return X_(f.killswitch.accounts[_]);return X_(f.killswitch.main)}function E$(f,_,D){if(!qD(_))return!0;let E=RD(_,D),$=!1;for(let m of["five_hour","seven_day"]){let M=f?.[m];if(!M){$=!0;continue}if(M.remainingPercent<E[m])return!1}if($)return!kf(_);return!0}function $$(f,_,D){let E=[],$=[f,..._.map((m)=>m.quota)];for(let m of $)for(let M of["five_hour","seven_day"]){let C=m?.[M]?.resetsAt;if(!C)continue;let L=Date.parse(C);if(Number.isFinite(L)&&L>D)E.push(L)}if(!E.length)return 300;return Math.max(1,Math.ceil((Math.min(...E)-D)/1000))+60}function m$(f){return f?.killswitch??{enabled:!1}}async function M$(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.killswitch=f,await q(D,_),D}function pf(f,_,D){if(!_f(_))return D+Z(_);let E=x_(_),$=[];for(let m of["five_hour","seven_day"]){let M=f?.[m];if(!M)return D+Z(_);if(M.remainingPercent>=E[m])continue;let C=M.resetsAt?Date.parse(M.resetsAt):Number.NaN;if(!Number.isFinite(C)||C<=D)return D+Z(_);$.push(C)}if(!$.length)return D+Z(_);return Math.min(...$)+60000}function l(f,_,D){return!f.access||!f.expires||f.expires-D<=VD(_)}function i_(f,_,D){if(!_f(_))return!0;let E=Z(_);return["five_hour","seven_day"].every(($)=>{let m=f?.[$];return Boolean(m&&D-m.checkedAt<E)})}function Rf(f,_,D){return!i_(f.quota,_,D)}function PD(f,_){if(!f)return!1;if(!f.resetsAt)return!0;let D=Date.parse(f.resetsAt);return!Number.isFinite(D)||D>_}function xD(f,_){return["five_hour","seven_day"].every((D)=>PD(f?.[D],_))}function k_(f){let _=Df(f);if(/Claude quota check failed: (429|5\d\d)\b/.test(_))return!0;if(!(f instanceof Error))return!1;let D=f.code;return _.includes("fetch failed")||D==="ECONNRESET"||D==="ECONNREFUSED"||D==="ETIMEDOUT"||D==="UND_ERR_CONNECT_TIMEOUT"}function TD(f,_,D,E){return k_(D)&&l_(f.quota,_)&&xD(f.quota,E)}function Z_(f){if(!Number.isFinite(f))return 0;if(f<0)return 0;if(f>100)return 100;return f}function h_(f,_){if(typeof f?.utilization!=="number")return;let D=Z_(f.utilization);return{usedPercent:D,remainingPercent:Z_(100-D),resetsAt:f.resets_at,checkedAt:_}}async function Nf(f){let D=await(f.fetchImpl??fetch)(n0,{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(!D.ok){let m=await D.text().catch(()=>"");throw Error(`Claude quota check failed: ${D.status} — ${m}`)}let E=f.now?.()??Date.now(),$=await D.json();return{five_hour:h_($.five_hour,E),seven_day:h_($.seven_day,E)}}function W(f,_){let D=f.accounts.findIndex((E)=>E.id===_.id);if(D>=0)f.accounts[D]=_}function Df(f){return f instanceof Error?f.message:String(f)}function p_(f,_,D){f.lastRefreshError=QD({error:_,now:D,refreshToken:f.refresh,previous:f.lastRefreshError})}function V_(f,_,D){if(f.lastQuotaRefreshError=Sf({error:_,now:D,previous:f.lastQuotaRefreshError}),_ instanceof y)p_(f,_,D)}function wD(f){return`fallback-oauth-refresh-${I_("sha256").update(f).digest("hex").slice(0,16)}`}class yD{now;fetchImpl;configPath;refreshPromises=new Map;refreshTimer=null;quotaTimer=null;quotaManager;onFallbackStorageChanged;constructor(f={}){this.now=f.now??Date.now,this.fetchImpl=f.fetchImpl??fetch,this.configPath=f.configPath??z(),this.quotaManager=f.quotaManager??null,this.onFallbackStorageChanged=f.onFallbackStorageChanged}seedFallbackQuota(f,_){if(!this.quotaManager)return;if(!f.quota)return;let D=Math.max(f.quota.five_hour?.checkedAt??0,f.quota.seven_day?.checkedAt??0);if(D<=0)return;let E=this.quotaManager.getFallback(f.id,f.access);if(E&&E.checkedAt>=D)return;let $=Z(_);this.quotaManager.setFallback(f.id,{quota:f.quota,refreshAfter:D+$,checkedAt:D},f.access)}async load(){return V(this.configPath)}async save(f,_){await JD(f,this.configPath,{accounts:_??!0})}startBackgroundRefresh(){let f=async()=>{await this.refreshDueAccounts(),await this.refreshQuotaForDueAccounts()};if(f().catch(()=>{}),!this.refreshTimer){if(this.refreshTimer=setInterval(()=>{f().catch(()=>{})},$D+hD(mD)),"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 D=[],E=!1;for(let $ of _.accounts){if($.enabled===!1||!X($))continue;try{let m=$;if(l(m,_,this.now())){let C=m.lastRefreshError;if(C&&e(C,m.refresh,this.now()))throw Error(qf(C,this.now()));m=await this.refreshAccount(m,_),E=!0}if(this.seedFallbackQuota(m,_),(this.quotaManager?this.quotaManager.isFallbackStale(m.id,m.access):Rf(m,_,this.now()))&&!g(m.lastQuotaRefreshError,this.now()))m=await this.refreshAccountQuota(m,_),E=!0;if(this.accountPassesQuotaPolicy(this.quotaPolicyAccount(m),_))D.push(m)}catch(m){if(TD($,_,m,this.now()))Q("[refresh] fallback quota using cached quota after refresh error",{accountId:$.id,error:Df(m)}),D.push($);else if(!kf(_))D.push($)}}if(E)await this.save(_);return D}async markUsed(f){let _=await this.load();if(!_)return;let D=_.accounts.find((E)=>E.id===f.id);if(!D)return;D.lastUsed=this.now(),await this.save(_)}accountPassesQuotaPolicy(f,_){return l_(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||!ZD(f))return;let _=!1;for(let D of f.accounts){if(D.enabled===!1||!X(D))continue;if(!l(D,f,this.now()))continue;if(e(D.lastRefreshError,D.refresh,this.now()))continue;try{Q("[refresh] fallback oauth background due",{accountId:D.id,expiresInMs:D.expires?D.expires-this.now():void 0}),await this.refreshAccount(D,f),_=!0}catch(E){Q("[refresh] fallback oauth background failed",{accountId:D.id,error:E instanceof Error?E.message:String(E)}),p_(D,E,this.now()),W(f,D),_=!0}}if(_)await this.save(f)}async refreshQuotaForDueAccounts(){let f=await this.load();if(!f||!_f(f))return;let _=!1;for(let D of f.accounts){if(D.enabled===!1||!X(D))continue;let E=D;try{if(l(E,f,this.now())){if(e(E.lastRefreshError,E.refresh,this.now()))continue;E=await this.refreshAccount(E,f),_=!0}if(g(E.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(E,f),!(this.quotaManager?this.quotaManager.isFallbackStale(E.id,E.access):Rf(E,f,this.now())))continue;await this.refreshAccountQuota(E,f),_=!0}catch($){V_(D,$,this.now()),W(f,D),_=!0}}if(_)await this.save(f),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(f={}){let _=await this.load(),D=[];if(!_||!_f(_))return{storage:_,errors:D};let E=f.force??!1,$=!1;for(let m of _.accounts){if(m.enabled===!1||!X(m))continue;let M=m;try{if(l(M,_,this.now())){let C=M.lastRefreshError;if(C&&e(C,M.refresh,this.now()))throw Error(qf(C,this.now()));M=await this.refreshAccount(M,_),$=!0}if(!E&&!Rf(M,_,this.now())){if(M.lastQuotaRefreshError)M.lastQuotaRefreshError=void 0,W(_,M),$=!0;continue}await this.refreshAccountQuota(M,_),$=!0}catch(C){V_(m,C,this.now()),W(_,m),$=!0,D.push({accountId:m.id,message:Df(C)})}}if($)await this.save(_);return{storage:_,errors:D}}async refreshAccount(f,_,D={}){let E=this.refreshPromises.get(f.id);if(E){let M=await E;return W(_,M),M}let $=this.refreshAccountNow(f,_,D).finally(()=>{this.refreshPromises.delete(f.id)});this.refreshPromises.set(f.id,$);let m=await $;return W(_,m),m}async waitForConcurrentFallbackRefresh(f,_,D,E){let $=Date.now()+CD;while(Date.now()<$){await new Promise((O)=>setTimeout(O,LD));let m=await this.load(),M=m?.accounts.find((O)=>O.id===f.id&&X(O));if(!M)continue;if((M.access!==D.access||M.refresh!==D.refresh||(M.expires??0)>(D.expires??0)+60000)&&(E.force||!l(M,m,this.now())))return W(_,M),Q("[refresh] fallback oauth joined concurrent refresh",{accountId:M.id,expiresInMs:M.expires?M.expires-this.now():void 0}),M;let L=M.lastRefreshError;if(L&&e(L,M.refresh,this.now()))throw W(_,M),Error(qf(L,this.now()))}return null}async refreshAccountNow(f,_,D){let E=await this.load(),$=E?.accounts.find((C)=>C.id===f.id&&X(C));if($&&!D.force&&!l($,E,this.now()))return W(_,$),$;let m=$??f,M=await Hf({name:wD(m.id),ttlMs:MD,path:this.configPath,now:this.now,renew:!0});if(!M){Q("[refresh] fallback oauth refresh skipped file lock",{accountId:m.id});let C=await this.waitForConcurrentFallbackRefresh(f,_,m,D);if(C)return C;throw Error("Fallback OAuth refresh is already in progress")}try{if(E=await this.load(),$=E?.accounts.find((O)=>O.id===f.id&&X(O)),$&&!D.force&&!l($,E,this.now()))return W(_,$),$;m=$??m;let C=m.refresh;Q("[refresh] fallback oauth refresh request start",{accountId:m.id,force:D.force===!0,expiresInMs:m.expires?m.expires-this.now():void 0});let L=await B_({refreshToken:C,fetchImpl:this.fetchImpl,now:this.now});return m.access=L.access,m.refresh=L.refresh,m.expires=L.expires,m.lastRefreshedAt=L.expires-L.expiresIn*1000,m.lastRefreshError=void 0,W(_,m),await this.save(_),Q("[refresh] fallback oauth refresh succeeded",{accountId:m.id,expiresInMs:m.expires?m.expires-this.now():void 0}),m}finally{await M.release()}}async refreshAccountQuota(f,_){let D=f;if(!D.access)throw Error(`Fallback account ${f.id} has no access token`);let E=(C)=>this.quotaManager?this.quotaManager.refreshFallback(D.id,C):Nf({accessToken:C,fetchImpl:this.fetchImpl,now:this.now}),$=this.now();try{D.quota=await E(D.access)}catch(C){if(!(C instanceof Error?C.message:String(C)).includes("Claude quota check failed: 401"))throw C;if(D=await this.refreshAccount(f,_,{force:!0}),!D.access)throw C;D.quota=await E(D.access)}let m=await this.load(),M=m?.accounts.find((C)=>C.id===D.id&&X(C));if(m&&M&&M.access!==D.access)return this.seedFallbackQuota(M,m),W(_,M),M;if(m&&M?.access===D.access&&M.quota&&ff(M.quota)>=$&&i_(M.quota,m,this.now()))return this.seedFallbackQuota(M,m),W(_,M),M;if(D.lastQuotaRefreshError=void 0,W(_,D),this.quotaManager&&D.quota){let C=this.now();this.quotaManager.setFallback(D.id,{quota:D.quota,refreshAfter:C+Z(_),checkedAt:C},D.access)}return D}}var O$="claude-cache",d_="## Claude Cache Status",lD="## Claude Cache Enabled",iD="## Claude Cache Disabled",kD="## Claude Cache Usage",pD="Usage: `/claude-cache`, `/claude-cache on`, `/claude-cache off`, or `/claude-cache mode explicit|automatic|hybrid`.",bf=!1,Af=Of;function U$(){return bf}function H$(){return Af}function S$(f){bf=f.enabled,Af=f.mode}function dD(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 Ef(f){let _=f?.enabled??bf,D=f?.mode??Af;return[d_,"",`- Enabled: ${_?"enabled":"disabled"}`,`- Mode: ${D}`,"- 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 N$(f){let _=dD(f.argumentsText),D=f.enabled??bf,E=f.mode??Af;if(_.type==="status")return Ef({enabled:D,mode:E});if(_.type==="enable")return[lD,"",Ef({enabled:!0,mode:E})].join(`
|
|
9
|
+
`);if(_.type==="disable")return[iD,"",Ef({enabled:!1,mode:E})].join(`
|
|
10
|
+
`);if(_.type==="mode")return[d_,"",`Mode updated to \`${_.mode}\`.`,"",Ef({enabled:D,mode:_.mode})].join(`
|
|
11
|
+
`);return[kD,"",pD,"",Ef({enabled:D,mode:E})].join(`
|
|
12
|
+
`)}import{randomBytes as vD,randomUUID as r_}from"node:crypto";var uD=1000,i=new Map;function $f(f,_,D){if(!f.has(_)&&f.size>=uD){let E=f.keys().next().value;if(E!==void 0)f.delete(E)}f.set(_,D)}function n_(f){let _=f||"anonymous",D=i.get(_);if(D)return D;let E={deviceId:vD(32).toString("hex"),sessionId:r_()};return $f(i,_,E),E}var rD=86400000,nD=300000,df=new Map,v_=new Map;async function gD(f,_){if(!f.startsWith("sk-ant-oat"))return null;let D=new AbortController,E=setTimeout(()=>D.abort(),5000);try{let $=new URL("https://api.anthropic.com/api/claude_cli/bootstrap");if($.searchParams.set("entrypoint",O_),_)$.searchParams.set("model",_);let m=await fetch($,{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:D.signal});if(!m.ok)return null;let C=(await m.json().catch(()=>null))?.oauth_account?.account_uuid;return typeof C==="string"&&C?C:null}catch{return null}finally{clearTimeout(E)}}async function F$(f,_){let D=n_(f);if(!f.startsWith("sk-ant-oat"))return D;let E=Date.now(),$=v_.get(f);if($&&$.expiresAt>E){if(!$.accountUuid)return D;let O=`account:${$.accountUuid}`,U=i.get(O);if(U)return $f(i,f,U),U}let m=df.get(f);if(!m)m=gD(f,_),df.set(f,m);let M=await m.finally(()=>{df.delete(f)});if($f(v_,f,{accountUuid:M,expiresAt:E+(M?rD:nD)}),!M)return D;let C=`account:${M}`,L=i.get(C);if(L)return $f(i,f,L),L;return D.accountUuid=M,$f(i,C,D),D}function k(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function sD(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 D=sD(_);if(!D){if(k(f.metadata))delete f.metadata.user_id;return!1}if(!k(f.metadata))f.metadata={};let E=f.metadata;if(k(E))E.user_id=D;return!0}var cD=["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"],tD=["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"],u_=["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 oD(f){return f.output_config?.format?.type==="json_schema"}function eD(f){return Array.isArray(f.tools)&&f.tools.length>0&&Array.isArray(f.system)&&k(f.thinking)&&k(f.context_management)&&k(f.output_config)&&k(f.diagnostics)}function aD(f,_=[]){let D=f?eD(f)?[...cD]:oD(f)?[...tD]:[...u_]:[...u_];if(f?.speed==="fast")D.push(L_);for(let E of _){let $=E.trim();if($)D.push($)}return[...new Set(D)].join(",")}function fE(){switch(process.platform){case"darwin":return"MacOS";case"win32":return"Windows";case"linux":return"Linux";case"freebsd":return"FreeBSD";default:return"Unknown"}}function _E(){switch(process.arch){case"arm64":return"arm64";case"x64":return"x64";case"ia32":return"x32";default:return process.arch}}function j$(f,_,D={}){let E=D.identity??n_(_),m=[...(f.get("anthropic-beta")??"").split(",").map((M)=>M.trim()).filter(Boolean),...D.extraBetas??[]];return f.set("accept","application/json"),f.set("authorization",`Bearer ${_}`),f.set("content-type","application/json"),f.set("user-agent",S_),f.set("anthropic-beta",aD(D.body,m)),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",r_()),f.set("x-claude-code-session-id",E.sessionId),f.set("x-stainless-arch",_E()),f.set("x-stainless-lang","js"),f.set("x-stainless-os",fE()),f.set("x-stainless-package-version",U_),f.set("x-stainless-retry-count","0"),f.set("x-stainless-runtime","node"),f.set("x-stainless-runtime-version",H_),f.set("x-stainless-timeout","600"),f.delete("x-api-key"),f}var DE=["model","messages","system","tools","tool_choice","metadata","max_tokens","temperature","thinking","context_management","output_config","diagnostics","stream","speed"];function g_(f){let _={};for(let D of DE)if(Object.hasOwn(f,D))_[D]=f[D];for(let[D,E]of Object.entries(f))if(!Object.hasOwn(_,D))_[D]=E;return _}import{createHash as $E}from"node:crypto";var EE=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 s_(){return function(f){let{exports:{mem:_,xxh32:D,xxh64:E,init32:$,update32:m,digest32:M,init64:C,update64:L,digest64:O}}=f,U=new Uint8Array(_.buffer);function b(H,G){if(_.buffer.byteLength<H+G){let Xf=Math.ceil((H+G-_.buffer.byteLength)/65536);_.grow(Xf),U=new Uint8Array(_.buffer)}}function K(H,G,Xf,Z0,h0,V0){b(H);let t=new Uint8Array(H);return U.set(t),Xf(0,G),t.set(U.subarray(0,H)),{update(r){let Zf;return U.set(t),typeof r=="string"?(b(3*r.length,H),Zf=S.encodeInto(r,U.subarray(H)).written):(b(r.byteLength,H),U.set(r,H),Zf=r.byteLength),Z0(0,H,Zf),t.set(U.subarray(0,H)),this},digest:()=>(U.set(t),V0(h0(0)))}}function j(H){return H>>>0}let P=2n**64n-1n;function J(H){return H&P}let S=new TextEncoder,d=0,v=0n;function u(H,G=d){return b(3*H.length,0),j(D(0,S.encodeInto(H,U).written,G))}function Cf(H,G=v){return b(3*H.length,0),J(E(0,S.encodeInto(H,U).written,G))}return{h32:u,h32ToString:(H,G=d)=>u(H,G).toString(16).padStart(8,"0"),h32Raw:(H,G=d)=>(b(H.byteLength,0),U.set(H),j(D(0,H.byteLength,G))),create32:(H=d)=>K(48,H,$,m,M,j),h64:Cf,h64ToString:(H,G=v)=>Cf(H,G).toString(16).padStart(16,"0"),h64Raw:(H,G=v)=>(b(H.byteLength,0),U.set(H),J(E(0,H.byteLength,G))),create64:(H=v)=>K(88,H,C,L,O,J)}}((await WebAssembly.instantiate(EE)).instance)}var mE=0x6e52736ac806831en,ME="cch=00000;";var uf=/("system":\[\{"type":"text","text":"x-anthropic-billing-header: cc_version=[^;"]+; cc_entrypoint=[^;"]+; )cch=([0-9a-f]{5});/,CE=/("system":\[\{"type":"text","text":"x-anthropic-billing-header: cc_version=[^;"]+; cc_entrypoint=[^;"]+; )cch=00000;/,c_=null,vf=null;async function LE(){if(vf)return;c_??=(async()=>{vf=(await s_()).h64Raw})(),await c_}async function OE(f){return await LE(),((vf?.(f,mE)??0n)&0xfffffn).toString(16).padStart(5,"0")}function UE(f){return f.replace(uf,`$1${ME}`)}function t_(f){return uf.exec(f)?.[2]??null}async function o_(f){if(!uf.test(f))return f;let _=UE(f),D=await OE(new TextEncoder().encode(_));return _.replace(CE,`$1cch=${D};`)}function HE(f=x,_=new Date){if(f===x)return If;return $E("sha256").update(f).digest("hex").slice(0,3)}function X$(f,_=x,D,E=new Date){let $=HE(_,E);return`x-anthropic-billing-header: cc_version=${_}.${$}; cc_entrypoint=${D}; cch=00000;`}var I$="claude-cachekeep",gf=3600000,rf=300000,SE=60000,Q$="extended-cache-ttl-2025-04-11",NE=32,e_=16777216,bE=2*gf,AE="## Claude Cache Keep Status",BE="## Claude Cache Keep Enabled",FE="## Claude Cache Keep Disabled",KE="## Claude Cache Keep Usage",jE="Usage: `/claude-cachekeep`, `/claude-cachekeep off`, or `/claude-cachekeep HH-HH`.";function Ff(f){return String(f).padStart(2,"0")}function GE(f){let _=f.trim();if(!_)return{type:"status"};if(_==="off")return{type:"disable"};let D=/^(\d{1,2})-(\d{1,2})$/.exec(_);if(!D)return{type:"usage"};let E=Number(D[1]),$=Number(D[2]);if(!Number.isInteger(E)||!Number.isInteger($)||E<0||E>23||$<0||$>23||E===$)return{type:"usage"};return{type:"window",startHour:E,endHour:$}}function sf(f){let _=Number(f?.cacheKeep?.startHour),D=Number(f?.cacheKeep?.endHour);if(!Number.isInteger(_)||!Number.isInteger(D)||_<0||_>23||D<0||D>23||_===D)return;return{startHour:_,endHour:D}}function _0(f){return f?.cacheKeep?.enabled===!0&&!!sf(f)}function zE(f){return _0(f)&&f?.claudeCache?.enabled===!0&&f.claudeCache.mode==="hybrid"}function a_(f,_=new Date){if(!f)return!1;let D=_.getHours();if(f.startHour<f.endHour)return D>=f.startHour&&D<f.endHour;return D>=f.startHour||D<f.endHour}function f0(f=new Date){return`${f.getFullYear()}-${Ff(f.getMonth()+1)}-${Ff(f.getDate())}`}function nf(f,_=new Date){if(f&&f.startHour>f.endHour&&_.getHours()<f.endHour){let D=new Date(_);return D.setDate(D.getDate()-1),f0(D)}return f0(_)}function Bf(f){let _=f.window?`${Ff(f.window.startHour)}-${Ff(f.window.endHour)}`:"not configured",D=[`Cache keep: ${f.enabled?"enabled":"disabled"}`,`Window: ${_}`,"Mode requirement: `/claude-cache mode hybrid` must be active."];if(typeof f.hybridActive==="boolean")D.push(`Hybrid active: ${f.hybridActive?"yes":"no"}`);if(typeof f.trackedSessions==="number")D.push(`Tracked sessions: ${f.trackedSessions}`);if(f.nextPrewarmAt)D.push(`Next prewarm: ${new Date(f.nextPrewarmAt).toLocaleString()}`);return D.join(`
|
|
13
|
+
`)}function q$(f){let _=GE(f.argumentsText),D={enabled:f.enabled??!1,window:f.window,trackedSessions:f.trackedSessions,nextPrewarmAt:f.nextPrewarmAt,hybridActive:f.hybridActive};if(_.type==="status")return[AE,"",Bf(D)].join(`
|
|
14
|
+
`);if(_.type==="disable")return[FE,"",Bf({...D,enabled:!1})].join(`
|
|
15
|
+
`);if(_.type==="window")return[BE,"",Bf({...D,enabled:!0,window:{startHour:_.startHour,endHour:_.endHour}})].join(`
|
|
16
|
+
`);return[KE,"",jE,"",Bf(D)].join(`
|
|
17
|
+
`)}function cf(f){if(!f||typeof f!=="object")return!1;if(Array.isArray(f))return f.some(cf);let _=f,D=_.cache_control;if(D&&typeof D==="object"&&D.type==="ephemeral")return!0;return Object.values(_).some(cf)}async function JE(f){let _;try{_=JSON.parse(f)}catch{return{ok:!1,reason:"body is not valid JSON"}}if(!cf(_))return{ok:!1,reason:"body has no explicit cache breakpoints"};let D=structuredClone(_);if(D.max_tokens=0,delete D.stream,D.thinking?.type==="enabled")delete D.thinking;if(D.output_config?.format)delete D.output_config;let m=D.tool_choice;if(m?.type==="tool"||m?.type==="any")delete D.tool_choice;return{ok:!0,bodyText:await o_(JSON.stringify(g_(D)))}}class WE{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)})})},SE),"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 D=nf(f,new Date(_)),E=[...this.targets.values()].filter((m)=>m.dayKey===D),$=E.length?Math.min(...E.map((m)=>m.cacheExpiresAt-rf)):void 0;return{trackedSessions:E.length,nextPrewarmAt:$}}trackedCount(){return this.targets.size}totalBodyBytes(){return[...this.targets.values()].reduce((f,_)=>f+_.bodyText.length,0)}evictOldestTarget(){let f=this.targets.keys().next().value;if(f!==void 0)this.targets.delete(f)}pruneTargets(f,_){for(let[D,E]of this.targets){if(_&&E.dayKey!==_){this.targets.delete(D);continue}if(f-E.cacheExpiresAt>bE)this.targets.delete(D)}while(this.targets.size>NE)this.evictOldestTarget();while(this.totalBodyBytes()>e_){let D=this.targets.size;if(this.evictOldestTarget(),this.targets.size===D)break}}track(f){if(!f.sessionId)return{tracked:!1,reason:"missing session id"};if(!_0(f.storage))return{tracked:!1,reason:"cachekeep disabled"};if(f.cacheMode!=="hybrid")return{tracked:!1,reason:"cache mode is not hybrid"};if(f.bodyText.length>e_)return{tracked:!1,reason:"body exceeds cachekeep memory budget"};let _=this.options.now?.()??Date.now(),D=sf(f.storage);if(!a_(D,new Date(_)))return{tracked:!1,reason:"outside configured window"};let E=nf(D,new Date(_));if(this.pruneTargets(_,E),this.targets.has(f.sessionId))this.targets.delete(f.sessionId);let $={};return f.headers.forEach((m,M)=>{$[M]=m}),this.targets.set(f.sessionId,{id:f.sessionId,url:f.url,headers:$,bodyText:f.bodyText,cacheExpiresAt:_+gf,dayKey:E}),this.pruneTargets(_,E),this.start(),{tracked:!0}}async tick(){let f=await this.options.loadStorage(),_=sf(f),D=this.options.now?.()??Date.now(),E=nf(_,new Date(D));if(this.pruneTargets(D,E),!this.targets.size){this.stop();return}if(!zE(f))return;if(!a_(_,new Date(D)))return;let $=D+rf;for(let m of this.targets.values()){if(m.cacheExpiresAt>$)continue;await this.prewarm(m,D)}}async prewarm(f,_){let D=await JE(f.bodyText);if(!D.ok){this.options.log?.("[cachekeep] prewarm skipped",{session:f.id,reason:D.reason}),this.targets.delete(f.id);return}let E=this.options.fetchImpl??fetch,$={...f,bodyText:D.bodyText},m=this.options.prepareHeaders?await this.options.prepareHeaders(new Headers(f.headers),$):new Headers(f.headers);m.delete("content-length"),m.delete("transfer-encoding");let M=await E(f.url,{method:"POST",headers:m,body:D.bodyText});if(!M.ok){this.options.log?.("[cachekeep] prewarm failed",{session:f.id,status:M.status,body:await M.text().catch(()=>"")}),f.cacheExpiresAt=_+rf+300000;return}await M.body?.cancel().catch(()=>{}),f.cacheExpiresAt=_+gf,this.options.log?.("[cachekeep] prewarm succeeded",{session:f.id})}}import{createHash as YE}from"node:crypto";import{mkdir as XE,writeFile as Kf}from"node:fs/promises";import{tmpdir as ZE}from"node:os";import{join as $0}from"node:path";var i$="claude-dump",hE="## Claude Dump Status",VE="## Claude Dump Enabled",IE="## Claude Dump Disabled",QE="## Claude Dump Usage",qE="Usage: `/claude-dump`, `/claude-dump on`, or `/claude-dump off`.",RE="OPENCODE_ANTHROPIC_AUTH_DUMP_DIR",PE=$0(ZE(),"opencode-anthropic-auth-dumps"),mf=!1,D0=0,xE=100,s=new Map;function k$(f){mf=f}function m0(){return process.env[RE]||PE}function TE(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 jf(f){let _=f?.enabled??mf;return[hE,"",`- Enabled: ${_?"enabled":"disabled"}`,`- Directory: ${m0()}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Captures: final rewritten Anthropic body in direct and relay modes; request/relay metadata is redacted","- Warning: body dumps may contain prompt/session content; turn this off after debugging"].join(`
|
|
18
|
+
`)}function p$(f){let _=TE(f.argumentsText),D=f.enabled??mf;if(_.type==="status")return jf({enabled:D});if(_.type==="enable")return[VE,"",jf({enabled:!0})].join(`
|
|
19
|
+
`);if(_.type==="disable")return[IE,"",jf({enabled:!1})].join(`
|
|
20
|
+
`);return[QE,"",qE,"",jf({enabled:D})].join(`
|
|
21
|
+
`)}function E0(f){return f.length<=16?f:`${f.slice(0,12)}…`}function M0(f){let _=f.trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/^-+|-+$/g,"");if(!_)return"session-unknown";return _.length<=80?_:_.slice(0,80)}function wE(f){if(f.transport!=="direct")return`${f.transport}-p${f.protocol}-${f.mode}`;return`direct${f.route?`-${M0(f.route)}`:""}`}function yE(f){let _=f.affinity?.trim();if(_)return`session:${_}`;return`request:${f.route??"direct"}:${f.url??""}`}function lE(f,_){if(!s.has(f))while(s.size>=xE){let D=s.keys().next().value;if(D===void 0)break;s.delete(D)}s.set(f,_)}function iE(f){if(f==null)return;return Object.fromEntries(new Headers(f).entries())}function C0(f){return YE("sha256").update(f).digest("hex")}function kE(f){return t_(f)}function pE(f,_){if(f==null)return null;if(f===_)return{changed:!1,firstByte:-1,lastPreviousByte:-1,lastCurrentByte:-1,previousBytes:f.length,currentBytes:_.length};let D=0;while(D<f.length&&D<_.length&&f[D]===_[D])D+=1;let E=f.length-1,$=_.length-1;while(E>=D&&$>=D&&f[E]===_[$])E-=1,$-=1;return{changed:!0,firstByte:D,lastPreviousByte:E,lastCurrentByte:$,changedPreviousBytes:E-D+1,changedCurrentBytes:$-D+1,previousBytes:f.length,currentBytes:_.length}}function dE(f){try{let _=JSON.parse(f);return _!=null&&typeof _==="object"&&!Array.isArray(_)?_:null}catch(_){return A(`dump body parse failed: ${_ instanceof Error?_.message:String(_)}`),null}}function tf(f){return C0(JSON.stringify(f))}function vE(f){let _=dE(f);if(!_)return{parseable:!1};let D=Array.isArray(_.messages)?_.messages:[],E=Array.isArray(_.system)?_.system:[],$=D[0],m=D.slice(1);return{parseable:!0,model:typeof _.model==="string"?_.model:void 0,stream:_.stream,systemCount:E.length,messagesCount:D.length,systemHash:tf(E),message0Hash:$===void 0?null:tf($),message0Bytes:$===void 0?0:JSON.stringify($).length,messagesAfter0Hash:tf(m),messagesAfter0Bytes:JSON.stringify(m).length,cch:kE(f)}}function Gf(f){if(Array.isArray(f))return f.map(Gf);if(f==null||typeof f!=="object")return f;let _={};for(let[D,E]of Object.entries(f)){let $=D.toLowerCase();if($==="authorization"||$==="x-api-key"||$==="cookie"||$==="set-cookie"){_[D]="[redacted]";continue}_[D]=Gf(E)}return _}async function L0(f){if(!mf)return;D0+=1;let _=f.affinity?.trim()||"session-unknown",D=`${new Date().toISOString().replace(/[:.]/g,"-")}-${String(D0).padStart(5,"0")}-${M0(_)}-${wE(f)}`,E=m0(),$=$0(E,D),m={body:`${$}.body.json`,metadata:`${$}.meta.json`};if(f.payload!==void 0)m.relay=`${$}.relay.json`;if(f.request!==void 0)m.request=`${$}.request.json`;try{await XE(E,{recursive:!0});let M={id:D,createdAt:new Date().toISOString(),session:E0(_),transport:f.transport,protocol:f.protocol,mode:f.mode,route:f.route,status:f.status,error:f.error,bodyBytes:f.bodyText.length,relayBytes:f.relayBytes,bodyHash:C0(f.bodyText),diff:pE(f.previousBodyText,f.bodyText),body:vE(f.bodyText),files:m},C=[Kf(m.body,f.bodyText,"utf8"),Kf(m.metadata,`${JSON.stringify(M,null,2)}
|
|
22
|
+
`,"utf8")];if(f.payload!==void 0&&m.relay)C.push(Kf(m.relay,`${JSON.stringify(Gf(f.payload),null,2)}
|
|
23
|
+
`,"utf8"));if(f.request!==void 0&&m.request)C.push(Kf(m.request,`${JSON.stringify(Gf({...f.request,headers:iE(f.request.headers)}),null,2)}
|
|
24
|
+
`,"utf8"));await Promise.all(C),A(`dumped request id=${D} session=${E0(_)} body=${m.body} meta=${m.metadata}`)}catch(M){A(`dump failed: ${M instanceof Error?M.message:String(M)}`)}}async function d$(f){if(!mf)return;let _=yE(f),D=s.get(_);await L0({affinity:f.affinity,transport:"direct",route:f.route,status:f.status,error:f.error,bodyText:f.bodyText,previousBodyText:D,request:{url:f.url,method:f.method,headers:f.headers}}),lE(_,f.bodyText)}async function O0(f){await L0({affinity:f.affinity,transport:f.transport,protocol:f.protocol,mode:f.mode,status:f.status,bodyText:f.bodyText,previousBodyText:f.previousBodyText,payload:f.payload,relayBytes:f.relayBytes})}var u$="claude-fast";var Jf=!1;function r$(){return Jf}function n$(f){Jf=f}function uE(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 zf(f){return["## Claude Fast Mode Status","",`- Enabled: ${f?.enabled??Jf?"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(`
|
|
25
|
+
`)}function g$(f){let _=uE(f.argumentsText),D=f.enabled??Jf;if(_.type==="status")return zf({enabled:D});if(_.type==="enable")return["## Claude Fast Mode Enabled","",zf({enabled:!0})].join(`
|
|
26
|
+
`);if(_.type==="disable")return["## Claude Fast Mode Disabled","",zf({enabled:!1})].join(`
|
|
27
|
+
`);return["## Claude Fast Mode Usage","","Usage: `/claude-fast`, `/claude-fast on`, or `/claude-fast off`.","",zf({enabled:D})].join(`
|
|
28
|
+
`)}var Mf="claude-killswitch";function rE(f){let _=f.trim().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&_[0]==="on")return{type:"on"};if(_.length===1&&_[0]==="off")return{type:"off"};if(_[0]==="set"){let D=[];for(let E=1;E<_.length;E++){let $=_[E]?.match(/^([^:]+):(\d+),(\d+)$/);if(!$)return{type:"usage"};let[,m,M,C]=$;D.push({account:m,fh:Number.parseInt(M,10),sd:Number.parseInt(C,10)})}if(D.length===0)return{type:"usage"};return{type:"set",entries:D}}return{type:"usage"}}function Wf(f,_){let D=f.enabled===!0,E=["## Killswitch","",`Status: **${D?"ON":"OFF"}**`];if(D){E.push(""),E.push("| Account | 5h threshold | 1w threshold |"),E.push("| ------- | ------------ | ------------ |");let $=f.main??{},m=$.five_hour??$["5h"]??h.five_hour,M=$.seven_day??$["1w"]??h.seven_day;E.push(`| main | ≥ ${m}% | ≥ ${M}% |`);for(let C of _){let L=f.accounts?.[C]??f.main??{},O=L.five_hour??L["5h"]??h.five_hour,U=L.seven_day??L["1w"]??h.seven_day;E.push(`| ${C} | ≥ ${O}% | ≥ ${U}% |`)}}return E.join(`
|
|
29
|
+
`)}var U0=["## Killswitch Commands","","```",`/${Mf} — show status`,`/${Mf} on — enable with current or default thresholds`,`/${Mf} off — disable`,`/${Mf} set all:5,10 — set all accounts to 5h≥5%, 1w≥10%`,`/${Mf} set main:3,8 work-alt:5,10 — per-account`,"```"].join(`
|
|
30
|
+
`);function t$(f){let _=rE(f.argumentsText);if(_.type==="status")return{text:`${Wf(f.config,f.accountIds)}
|
|
31
|
+
|
|
32
|
+
${U0}`};if(_.type==="on"){let E={...f.config,enabled:!0,main:f.config.main??{five_hour:h.five_hour,seven_day:h.seven_day}};return{text:`## Killswitch Enabled
|
|
33
|
+
|
|
34
|
+
${Wf(E,f.accountIds)}`,updatedConfig:E}}if(_.type==="off")return{text:"## Killswitch Disabled",updatedConfig:{...f.config,enabled:!1}};if(_.type==="set"){let E={...f.config.accounts??{}},$={...f.config,enabled:!0,accounts:E};for(let M of _.entries){let C={five_hour:M.fh,seven_day:M.sd};if(M.account==="main")$.main=C;else if(M.account==="all"){$.main=C;for(let L of f.accountIds)E[L]=C}else E[M.account]=C}return{text:`## Killswitch Updated
|
|
35
|
+
|
|
36
|
+
${Wf($,f.accountIds)}`,updatedConfig:$}}return{text:`${Wf(f.config,f.accountIds)}
|
|
37
|
+
|
|
38
|
+
${U0}`}}var nE=["claude-fable-5","claude-mythos-5"],e$={type:"adaptive",display:"summarized"},a$={input:10,output:50,cacheRead:1,cacheWrite5m:12.5,cacheWrite1h:20},fm=1e6,_m=128000,Dm="2026-06-09",Em={["claude-fable-5"]:{id:"claude-fable-5",name:"Claude Fable 5"},["claude-mythos-5"]:{id:"claude-mythos-5",name:"Claude Mythos 5",limited:!0}};function $m(f){return typeof f==="string"&&nE.some((_)=>f===_||f.startsWith(`${_}-`))}function mm(f){if(typeof f!=="string")return!1;if(f.startsWith("gAAAA"))return!0;if(!f.startsWith("{"))return!1;try{let _=JSON.parse(f);return _.type==="reasoning"&&typeof _.id==="string"&&_.id.startsWith("rs_")&&typeof _.encrypted_content==="string"&&_.encrypted_content.startsWith("gAAAA")}catch{return!1}}import{createHash as gE}from"node:crypto";var sE=globalThis.setTimeout;function I(f){return gE("sha256").update(f).digest("hex").slice(0,16)}class w{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,this.seedMainFromStorage(f.storage),this.seedMainBackoffFromStorage(f.storage)}getMain(f){if(f&&this.main&&this.mainTokenFp&&this.mainTokenFp!==I(f))this.main=null,this.mainTokenFp=null;return this.main}getFallback(f,_){let D=this.fallbacks.get(f)??null;if(!_||!D)return D;if(this.fallbackTokenFps.get(f)!==I(_))return this.fallbacks.delete(f),this.fallbackTokenFps.delete(f),null;return D}getAllFallbacks(){return this.fallbacks}setMain(f,_){this.mainTokenFp=I(f),this.main=_}setFallback(f,_,D){if(this.fallbacks.set(f,_),D)this.fallbackTokenFps.set(f,I(D));else this.fallbackTokenFps.delete(f)}async refreshMain(f){let _=I(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 D=w.fallbackInflightKey(f,_),E=this.inflightFallbacks.get(D);if(E)return E;if(this.isFallbackBackedOff(f,_)){let m=this.getFallback(f,_);if(m)return m.quota;throw Error("Quota API rate-limited — try again later")}let $=this._fetchFallback(f,_);return this.inflightFallbacks.set(D,$),$}async refreshAllFallbacks(f){let _=this.now();for(let D of f){if(D.enabled===!1)continue;if(!D.access)continue;let E=this.getFallback(D.id,D.access);if(E&&_<E.refreshAfter)continue;try{await this.refreshFallback(D.id,D.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 D=this.getFallback(f,_);if(!D)return!0;return this.now()>=D.refreshAfter}shouldRefreshOnRequestCount(f){let _=y_(this.storage);if(_<=0)return!1;return f>0&&f%_===0}needsRefresh(f){return this.isMainStale()||this.shouldRefreshOnRequestCount(f)}updateStorage(f){this.storage=f,this.seedMainFromStorage(f),this.seedMainBackoffFromStorage(f)}seedMainFromStorage(f,_){let D=w_(f);if(!D)return;let E=_?I(_):null;if(E&&D.tokenFingerprint&&D.tokenFingerprint!==E)return;let $={quota:D.quota,refreshAfter:pf(D.quota,f,D.checkedAt),checkedAt:D.checkedAt};if(this.main&&this.main.checkedAt>=$.checkedAt&&(!E||!this.mainTokenFp||this.mainTokenFp===E))return;this.main=$,this.mainTokenFp=D.tokenFingerprint??null}seedMainBackoffFromStorage(f){let _=f?.quota?.mainLastQuotaApiError;this.mainLastApiError=_&&g(_,this.now())?_:void 0}seedFallbacksFromAccounts(f){let _=Z(this.storage);for(let D of f){if(D.enabled===!1)continue;if(!D.quota)continue;let E=Math.max(D.quota.five_hour?.checkedAt??0,D.quota.seven_day?.checkedAt??0);if(E<=0)continue;let $=this.getFallback(D.id,D.access);if($&&$.checkedAt>=E)continue;this.setFallback(D.id,{quota:D.quota,refreshAfter:E+_,checkedAt:E},D.access)}}isBackedOff(){return g(this.mainLastApiError,this.now())}isFallbackBackedOff(f,_){if(_){if(this.fallbackErrorTokenFps.get(f)!==I(_))return!1}return g(this.fallbackApiErrors.get(f),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(f,_){return JSON.stringify([f,I(_)])}static quotaLockName(f){return`opencode-fallback-quota-refresh-${f.replace(/[^a-zA-Z0-9._-]+/g,"-")||"account"}`}_enqueueApiFetch(f){let _=async()=>{let E=this.now()-this.lastApiCallAt;if(E<w.API_CALL_GAP_MS)await new Promise(($)=>{let m=sE($,w.API_CALL_GAP_MS-E);if(typeof m==="object"&&"unref"in m)m.unref()});return this.lastApiCallAt=this.now(),f()},D=this.apiGate.then(_,_);return this.apiGate=D.catch(()=>{}),D}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 Hf({name:"opencode-main-quota-refresh",ttlMs:30000});if(!_){let D=this.main;if(D&&this.now()<D.refreshAfter)return D.quota;throw Error("Quota refresh is already in progress")}try{let D=this.now(),E=await Nf({accessToken:f,fetchImpl:this.fetchImpl,now:this.now}),$=this.now();return this.mainTokenFp=I(f),this.main={quota:E,refreshAfter:pf(E,this.storage,$),checkedAt:$},this.mainLastApiError=void 0,this.onMainQuotaFetched?.(E,$,this.mainTokenFp,D),E}catch(D){throw this._handleMainFetchError(D),D}finally{await _.release()}}finally{this.inflightMain=null}})}async _fetchFallback(f,_){return this._enqueueApiFetch(async()=>{try{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=await Hf({name:w.quotaLockName(f),ttlMs:30000});if(!D){let E=this.getFallback(f,_);if(E&&this.now()<E.refreshAfter)return E.quota;throw Error("Quota refresh is already in progress")}try{let E=await Nf({accessToken:_,fetchImpl:this.fetchImpl,now:this.now}),$=this.now();return this.setFallback(f,{quota:E,refreshAfter:$+Z(this.storage),checkedAt:$},_),this.fallbackApiErrors.delete(f),this.fallbackErrorTokenFps.delete(f),E}finally{await D.release()}}catch(D){throw this._handleFallbackFetchError(f,_,D),D}finally{this.inflightFallbacks.delete(w.fallbackInflightKey(f,_))}})}static isAuthError(f){let _=f instanceof Error?f.message:String(f);return/quota check failed: 401\b/.test(_)}_handleMainFetchError(f){if(w.isAuthError(f))return;this.mainLastApiError=Sf({error:f,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(f,_,D){if(w.isAuthError(D))return;let E=I(_),$=this.fallbackErrorTokenFps.get(f)===E?this.fallbackApiErrors.get(f):void 0;this.fallbackApiErrors.set(f,Sf({error:D,now:this.now(),previous:$})),this.fallbackErrorTokenFps.set(f,E)}}var Hm="claude-quota",H0={five_hour:"5h",seven_day:"1w"};function S0(f){return`${Math.round(f*10)/10}%`}function of(f,_){let D=Math.max(0,_-f),E=Math.floor(D/60000);if(E<1)return"just now";if(E===1)return"1m ago";if(E<60)return`${E}m ago`;let $=Math.floor(E/60),m=E%60;if(m===0)return`${$}h ago`;return`${$}h ${m}m ago`}function cE(f,_){let D=Date.parse(f);if(!Number.isFinite(D))return f;let E=D-_;if(E<=0)return"now";let $=Math.max(1,Math.ceil(E/60000));if($<60)return`in ${$}m`;let m=Math.floor($/60),M=$%60;if(M===0)return`in ${m}h`;return`in ${m}h ${M}m`}function tE(f,_){if(!f)return"";return`, resets ${cE(f,_)}`}function N0(f,_,D){if(!_)return` - ${H0[f]}: unknown`;return[` - ${H0[f]}: ${S0(_.remainingPercent)} remaining`,` (${S0(_.usedPercent)} used`,`${tE(_.resetsAt,D)}, checked ${of(_.checkedAt,D)})`].join("")}function oE(f){return f.label?.trim()||f.id}function eE(f){return f.lastQuotaRefreshError?.message??f.lastRefreshError?.message}function Sm(f,_=new Map){if(!f?.accounts.length)return[];return f.accounts.filter(X).map((D)=>{let E=_.get(D.id)??eE(D);return{name:oE(D),role:"fallback",enabled:D.enabled!==!1,quota:D.quota,lastRefreshedAt:D.lastRefreshedAt,...E&&{error:E}}})}function Nm(f){let _=f.now??Date.now(),D=["## Claude Quotas",""];if(f.refreshedAt)D.push(`Refreshed: ${of(f.refreshedAt,_)}`,"");if(!f.accounts.length)return D.push("No Claude OAuth accounts found yet."),D.join(`
|
|
39
|
+
`);for(let E of f.accounts){let $=E.role==="main"?"main":"fallback",m=E.enabled===!1?" disabled":"";if(D.push(`### ${E.name} (${$}${m})`),E.lastRefreshedAt)D.push(` - Last token refresh: ${of(E.lastRefreshedAt,_)}`);if(E.error)D.push(` - Error: ${E.error}`);D.push(N0("five_hour",E.quota?.five_hour,_)),D.push(N0("seven_day",E.quota?.seven_day,_)),D.push("")}return D.join(`
|
|
40
|
+
`).trimEnd()}import{Buffer as z0}from"node:buffer";import{createHash as aE,randomBytes as f1}from"node:crypto";class af extends Error{}class f_ extends Error{code="ECONNRESET";syscall="websocket";closeCode;closeReason;wasClean;constructor(f,_){super(f);this.name="RelayWebSocketConnectionResetError",this.closeCode=_?.code,this.closeReason=_?.reason,this.wasClean=_?.wasClean}}var R=new Map,p=new Map,b0=new Set,_1=7200000,D1=1800000,E1=128,$1=32,A0=0;function ef(){return A0+=1,`req_${Date.now().toString(36)}_${A0.toString(36)}`}function Yf(f){if(b0.has(f))return;b0.add(f),A(f)}function jm(f){let _=f?.relay;if(!_)return Yf("disabled: no relay config found"),null;if(_.enabled!==!0)return Yf("disabled: relay.enabled is not true"),null;if(!_.url?.trim()||!_.token?.trim())return Yf("disabled: missing relay url or token"),null;let D=_.transport==="http"?"http":"websocket";return Yf(`configured transport=${D} protocol=${D==="websocket"?2:1} url=${_.url.trim()} fallbackToDirect=${_.fallbackToDirect!==!1}`),{enabled:!0,url:_.url.trim(),token:_.token.trim(),fallbackToDirect:_.fallbackToDirect!==!1,transport:D}}function Gm(){return f1(32).toString("base64url")}function m1(f){return`sha256:${aE("sha256").update(f).digest("hex")}`}function B0(f,_){let D=0,E=Math.min(f.length,_.length);while(D<E&&f.charCodeAt(D)===_.charCodeAt(D))D++;let $=f.length,m=_.length;while($>D&&m>D&&f.charCodeAt($-1)===_.charCodeAt(m-1))$--,m--;return{start:D,deleteCount:$-D,insert:_.slice(D,m)}}function M1(f){return f.deleteCount===0&&f.insert.length===0}function F0(f){let _=f.match(/\bcch=([0-9a-f]{5});/),D=_?.[1];if(!D||_.index==null)return null;let E=_.index+4;return{start:E,end:E+D.length,token:D}}function C1(f,_,D,E){return`${f.slice(0,_)}${E}${f.slice(D)}`}function J0(f,_){let D=F0(f),E=F0(_);if(D&&E&&D.start===E.start&&D.end-D.start===E.end-E.start&&D.token!==E.token){let $={start:D.start,deleteCount:D.end-D.start,insert:E.token},m=C1(f,D.start,D.end,E.token),M=B0(m,_);return M1(M)?$:[$,M]}return B0(f,_)}function L1(f,_){if(typeof _!=="string")return!1;try{let D=f instanceof Request?new URL(f.url):new URL(f.toString());return D.pathname==="/v1/messages"||D.pathname==="/messages"}catch{return!1}}function O1(f){let _={};for(let[D,E]of f.entries()){if(D==="x-session-affinity"||D==="x-opencode-session")continue;_[D]=E}return _}async function K0(f,_,D){let E=B(),$=JSON.stringify(_);return c("http_payload_stringify",{session:F(_.affinity),ms:Y(B()-E),relayBytes:$.length,mode:_.mode}),fetch(f.url,{method:"POST",headers:{"content-type":"application/json","x-relay-token":f.token},body:$,signal:D??void 0})}function F(f){return f.length>12?`${f.slice(0,12)}…`:f}function B(){return performance.now()}function Y(f){return Math.round(f*10)/10}function U1(){return process.env.OPENCODE_ANTHROPIC_AUTH_PERF==="1"}function c(f,_){if(!U1())return;A(`[perf] relay ${f} ${JSON.stringify(_)}`)}function H1(f){let{input:_,init:D,headers:E,bodyText:$,affinity:m,previous:M,nextHash:C}=f,L=_ instanceof Request?_.url:_.toString(),O={protocol:1,type:"request",affinity:m,upstream:{url:L,method:D?.method||(_ instanceof Request?_.method:"POST"),headers:O1(E)},next_hash:C};return M?{...O,mode:"patch",base_hash:M.hash,revision:M.revision+1,patch:J0(M.body,$)}:{...O,mode:"full_sync",revision:1,body:$}}function __(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 W0(f,_,D,E){let $=Date.now();R.delete(f),R.set(f,{body:_,hash:D,revision:E,updatedAt:$}),D_($)}async function j0(f){let{config:_,payload:D,bodyText:E,fallback:$,signal:m}=f,M=D,C=await K0(_,M,m);if(C.status===409&&M.mode==="patch")A(`state mismatch from relay session=${F(M.affinity)}; retrying full_sync`),await C.body?.cancel().catch(()=>{}),M=__(M,E),C=await K0(_,M,m);if(!C.ok&&C.status>=500&&_.fallbackToDirect)return A(`relay returned ${C.status}; falling back direct session=${F(M.affinity)}`),await C.body?.cancel().catch(()=>{}),{response:await $(),payload:M,transport:"http",protocol:M.protocol,usedRelay:!1};return{response:C,payload:M,transport:"http",protocol:M.protocol,usedRelay:!0}}function S1(f,_){let D=new URL(f);return D.protocol=D.protocol==="http:"?"ws:":"wss:",D.pathname="/ws",D.searchParams.set("token",_),D.toString()}function N1(f){return new Uint8Array(z0.from(f,"base64"))}function b1(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(z0.from(String(f)))}function A1(f){return JSON.parse(f)}function G0(f){let _=f,D=[`code=${_.code??"unknown"}`,`wasClean=${_.wasClean??"unknown"}`];if(_.reason)D.push(`reason=${JSON.stringify(_.reason)}`);return D.join(" ")}function B1(f){let _=f.message||"relay websocket error";return f.status?`relay websocket error ${f.status}: ${_}`:_}class Y0{config;affinity;socket;connecting;queue=Promise.resolve();pending;serverState;lastUsedAt=Date.now();constructor(f,_){this.config=f,this.affinity=_}touch(f=Date.now()){this.lastUsedAt=f}canEvict(f=Date.now()){return!this.pending&&!this.connecting&&f-this.lastUsedAt>D1}dispose(){this.socket?.close(),this.socket=void 0,this.serverState=void 0,this.connecting=void 0}send(f,_,D=!1){this.touch();let E=B(),$=this.queue.catch(()=>{}).then(()=>this.startQueued(f,_,E,D)),m=$.then(async({response:M,getPayload:C})=>({response:await M,payload:C(),transport:"websocket",protocol:2,usedRelay:!0}));return this.queue=$.then(({done:M})=>M.catch(()=>{}),()=>{}),m}async startQueued(f,_,D,E){let $=B();await this.ensureConnected();let m=B(),M=R.get(this.affinity),C=this.serverState?.hash,L={...f,protocol:2,id:ef()};if(L.mode==="patch"&&(!C||C!==L.base_hash))L.mode="full_sync",L.revision=(this.serverState?.revision??0)+1,delete L.base_hash,delete L.patch,L.body=_;if(L.mode==="patch"&&M)L.patch=J0(M.body,_);A(`perf websocket send_start session=${F(this.affinity)} request=${L.id} mode=${L.mode} queueMs=${Y(m-D)} connectMs=${Y(m-$)} bodyBytes=${_.length} relayBytes=${JSON.stringify(L).length}`);let O=L,U=this.sendPayload(L,_,E);U.done.catch(()=>{});let b=U.done,K=U.response.catch((P)=>{if(!(P instanceof af)||L.mode!=="patch")throw P;let J=__(L,_);J.protocol=2,J.id=ef(),J.revision=(this.serverState?.revision??0)+1,O=J;let S=this.sendPayload(J,_,E);return S.done.catch(()=>{}),b=S.done,S.response}),j=K.then(()=>b,()=>b.catch(()=>{}));return{response:K,done:j,getPayload:()=>O}}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 D=S1(this.config.url,this.config.token),E=new URL(D);E.searchParams.set("affinity",this.affinity);let $=new WebSocket(E.toString());this.socket=$,this.serverState=void 0;let m=setTimeout(()=>{$.close(),_(Error("relay websocket ready timed out"))},15000);$.addEventListener("message",(M)=>{try{if(typeof M.data!=="string"){this.handleBinaryChunk(M.data);return}let C=A1(M.data);if(C.type==="ready"){clearTimeout(m),this.serverState=C.state,f();return}this.handleMessage(C)}catch(C){clearTimeout(m),_(C),this.failPending(C),$.close()}}),$.addEventListener("error",()=>{clearTimeout(m);let M=new f_("relay websocket error");_(M),this.failPending(M)}),$.addEventListener("close",(M)=>{if(clearTimeout(m),this.socket===$)this.socket=void 0,this.serverState=void 0,this.connecting=void 0;if(this.pending){if(this.pending.retryingBeforeResponse)return;let C=this.pending.responseStartedAt!=null,L=C?"closed after response_start before stream bytes":"closed before response";if(this.retryPendingBeforeResponse(this.pending,L,M))return;let O=C?new f_("relay websocket closed during response stream",M):Error("relay websocket closed before response");A(`websocket ${C?"closed during response stream":"closed before response without retry"} session=${F(this.affinity)} request=${this.pending.payload.id} chunks=${this.pending.streamChunkCount} bytes=${this.pending.streamByteCount} ${G0(M)}`),this.failPending(O)}})}).finally(()=>{this.connecting=void 0}),await this.connecting}sendPayload(f,_,D){let E=this.socket;if(!E||E.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");let $=B(),m,M,C=new Promise((O,U)=>{m=O,M=U});return{response:new Promise((O,U)=>{let b={payload:f,bodyText:_,resolve:O,reject:U,streamDone:!1,accepted:!1,responseStarted:!1,resolveDone:m,rejectDone:M,sentAt:$,optimisticResponse:D,streamChunkCount:0,streamByteCount:0,retryAttempts:0,retryingBeforeResponse:!1};if(this.pending=b,this.resetPendingTimeout(b),E.send(JSON.stringify(f)),D)this.resolvePendingResponse(b,200,"OK",{"content-type":"text/event-stream","x-cortexkit-relay-optimistic":"true"})}),done:C}}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,_,D){if(f.responseStartedAt!=null&&f.streamByteCount>0)return!1;if(f.streamDone)return!1;if(f.retryAttempts>=1)return!1;f.retryAttempts+=1,f.retryingBeforeResponse=!0,clearTimeout(f.timeout);let E=f.retryAttempts,$=f.payload.id;return A(`websocket ${_}; reconnecting and retrying full_sync session=${F(this.affinity)} request=${$} retry=${E} chunks=${f.streamChunkCount} bytes=${f.streamByteCount}${D?` ${G0(D)}`:""}`),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 m=__(f.payload,f.bodyText);m.protocol=2,m.id=ef(),m.revision=(this.serverState?.revision??0)+1,f.payload=m,f.accepted=!1,f.acceptedAt=void 0,f.responseStartedAt=void 0,f.sentAt=B(),f.retryingBeforeResponse=!1;let M=this.socket;if(!M||M.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");this.resetPendingTimeout(f),A(`perf websocket retry_send session=${F(this.affinity)} request=${m.id} previous=${$} mode=full_sync retry=${E} bodyBytes=${f.bodyText.length} relayBytes=${JSON.stringify(m).length}`),M.send(JSON.stringify(m))}catch(m){if(f.retryingBeforeResponse=!1,this.pending===f)this.failPending(m)}})(),!0}enqueueStreamChunk(f,_){f.streamChunkCount+=1,f.streamByteCount+=_.byteLength,f.streamController?.enqueue(_)}handleBinaryChunk(f){let _=this.pending;if(!_?.responseStarted)return;this.enqueueStreamChunk(_,b1(f))}resolvePendingResponse(f,_,D,E){if(f.responseStarted)return;f.responseStarted=!0;let $=new ReadableStream({start:(m)=>{f.streamController=m},cancel:()=>{this.socket?.close()}});f.resolve(new Response($,{status:_,statusText:D,headers:E}))}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 D=B();_.accepted=!0,_.acceptedAt=D,A(`perf websocket accepted session=${F(this.affinity)} request=${_.payload.id} sentMs=${Y(D-_.sentAt)} mode=${_.payload.mode}`),this.serverState={hash:f.hash,revision:f.revision},W0(this.affinity,_.bodyText,f.hash,f.revision),this.resetPendingTimeout(_);return}if(f.type==="response_start"){let D=B();if(_.responseStartedAt=D,A(`perf websocket response_start session=${F(this.affinity)} request=${_.payload.id} sentMs=${Y(D-_.sentAt)} upstreamMs=${_.acceptedAt==null?"unknown":Y(D-_.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
|
|
41
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_upstream_error",message:`Relay upstream returned HTTP ${f.status}`}})}
|
|
42
|
+
|
|
43
|
+
`)),this.finishPending();return}if(f.type==="chunk"){this.enqueueStreamChunk(_,N1(f.base64));return}if(f.type==="done"){this.finishPending(f);return}if(f.type==="error"){if(_.optimisticResponse&&_.responseStartedAt!=null){A(`websocket relay error during optimistic response session=${F(this.affinity)} request=${_.payload.id} status=${f.status} message=${f.message||"unknown"} chunks=${_.streamChunkCount} bytes=${_.streamByteCount}`),_.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
44
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_error",message:f.message||"relay error"}})}
|
|
45
|
+
|
|
46
|
+
`)),this.finishPending(),this.socket?.close();return}if(f.status===409&&this.retryPendingBeforeResponse(_,f.message||"state mismatch"))return;let D=f.status===409?new af(f.message||"state mismatch"):Error(B1(f));this.failPending(D)}}finishPending(f){let _=this.pending;if(!_)return;let D=B(),E=f&&"frames"in f?` upstreamChunks=${f.upstreamChunks??"unknown"} upstreamBytes=${f.upstreamBytes??"unknown"} frames=${f.frames} frameBytes=${f.frameBytes??"unknown"}`:"";if(A(`perf websocket done session=${F(this.affinity)} request=${_.payload.id} sentMs=${Y(D-_.sentAt)} streamMs=${_.responseStartedAt==null?"unknown":Y(D-_.responseStartedAt)} chunks=${_.streamChunkCount} bytes=${_.streamByteCount}${E}`),clearTimeout(_.timeout),!_.streamDone)_.streamDone=!0,_.streamController?.close();_.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 D_(f=Date.now()){for(let[_,D]of R)if(f-D.updatedAt>_1)R.delete(_);while(R.size>E1){let _=R.keys().next().value;if(_===void 0)break;R.delete(_)}for(let[_,D]of p)if(D.canEvict(f))D.dispose(),p.delete(_);while(p.size>$1){let _=!1;for(let[D,E]of p){if(!E.canEvict(f))continue;E.dispose(),p.delete(D),_=!0;break}if(!_)break}}function F1(f,_){D_();let D=p.get(_);if(D)return D.touch(),D;let E=new Y0(f,_);return p.set(_,E),D_(),E}async function zm(f){let{config:_,input:D,init:E,headers:$,body:m,fallback:M,affinity:C,optimisticResponse:L}=f;if(!_||!L1(D,m))return M();let O=C||$.get("x-session-affinity")||$.get("x-opencode-session");if(!O)return A("skipping relay: missing x-session-affinity header"),M();let U=m,b=B(),K=m1(U);c("hash_body",{session:F(O),ms:Y(B()-b),bodyBytes:U.length});let j=R.get(O),P=B(),J=H1({input:D,init:E,headers:$,bodyText:U,affinity:O,previous:j,nextHash:K});c("create_payload",{session:F(O),ms:Y(B()-P),mode:J.mode,bodyBytes:U.length,previousBytes:j?.body.length});try{let S,d=B();if(_.transport==="websocket")try{S=await F1(_,O).send(J,U,L===!0)}catch(H){A(`websocket relay failed session=${F(O)}; trying http relay: ${H instanceof Error?H.message:String(H)}`),S=await j0({config:_,payload:J,bodyText:U,fallback:M,signal:E?.signal})}else S=await j0({config:_,payload:J,bodyText:U,fallback:M,signal:E?.signal});if(c("send",{session:F(O),ms:Y(B()-d),transport:S.transport,protocol:S.protocol,mode:S.payload.mode,status:S.response.status,usedRelay:S.usedRelay}),!S.usedRelay)return S.response;if(S.transport==="http")W0(O,U,S.payload.next_hash,S.payload.revision);let v=B(),u=JSON.stringify(S.payload).length;c("payload_stringify",{session:F(O),ms:Y(B()-v),relayBytes:u}),A(`used relay transport=${S.transport} protocol=${S.protocol} mode=${S.payload.mode} status=${S.response.status} session=${F(O)} bodyBytes=${U.length} relayBytes=${u}`);let Cf=B();return await O0({affinity:O,transport:S.transport,protocol:S.protocol,mode:S.payload.mode,status:S.response.status,bodyText:U,previousBodyText:j?.body,payload:S.payload,relayBytes:u}),c("dump",{session:F(O),ms:Y(B()-Cf),enabled:!0}),S.response}catch(S){if(!_.fallbackToDirect)throw A(`relay failed session=${F(O)} and fallbackToDirect=false: ${S instanceof Error?S.message:String(S)}`),S;return A(`relay failed; falling back direct session=${F(O)}: ${S instanceof Error?S.message:String(S)}`),M()}}var Jm=`
|
|
47
|
+
async function hashBody(body) {
|
|
48
|
+
const bytes = new TextEncoder().encode(body)
|
|
49
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes)
|
|
50
|
+
const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('')
|
|
51
|
+
return 'sha256:' + hex
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function applyPatch(base, patch) {
|
|
55
|
+
return base.slice(0, patch.start) + patch.insert + base.slice(patch.start + patch.deleteCount)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function applyPatchSet(base, patch) {
|
|
59
|
+
if (!Array.isArray(patch)) return applyPatch(base, patch)
|
|
60
|
+
if (patch.length === 0) return base
|
|
61
|
+
|
|
62
|
+
let result = ''
|
|
63
|
+
let cursor = 0
|
|
64
|
+
for (const item of patch) {
|
|
65
|
+
if (item.start < cursor) return { error: 'overlapping patch', status: 400 }
|
|
66
|
+
result += base.slice(cursor, item.start)
|
|
67
|
+
result += item.insert
|
|
68
|
+
cursor = item.start + item.deleteCount
|
|
69
|
+
}
|
|
70
|
+
return result + base.slice(cursor)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function readState(env, affinity) {
|
|
74
|
+
const raw = await env.RELAY_STATE.get('session:' + affinity)
|
|
75
|
+
return raw ? JSON.parse(raw) : null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function writeState(env, affinity, state) {
|
|
79
|
+
await env.RELAY_STATE.put('session:' + affinity, JSON.stringify(state), { expirationTtl: 86400 })
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function resolveBody(env, payload) {
|
|
83
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
84
|
+
if (payload.mode === 'patch') {
|
|
85
|
+
const state = await readState(env, payload.affinity)
|
|
86
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
87
|
+
return { error: 'state mismatch', status: 409 }
|
|
88
|
+
}
|
|
89
|
+
return applyPatchSet(state.body, payload.patch)
|
|
90
|
+
}
|
|
91
|
+
return { error: 'unknown mode', status: 400 }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function prepareUpstream(env, payload) {
|
|
95
|
+
if ((payload.protocol !== 1 && payload.protocol !== 2) || payload.type !== 'request' || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
96
|
+
return { error: 'invalid payload', status: 400 }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const body = await resolveBody(env, payload)
|
|
100
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
101
|
+
|
|
102
|
+
if (typeof body !== 'string' || (await hashBody(body)) !== payload.next_hash) {
|
|
103
|
+
return { error: 'hash mismatch', status: 409 }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const stateWrite = writeState(env, payload.affinity, { body, hash: payload.next_hash, revision: payload.revision }).catch(() => {})
|
|
107
|
+
console.log(JSON.stringify({
|
|
108
|
+
relay: 'opencode-anthropic-auth',
|
|
109
|
+
transport: 'relay',
|
|
110
|
+
mode: payload.mode,
|
|
111
|
+
revision: payload.revision,
|
|
112
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
113
|
+
bodyBytes: body.length,
|
|
114
|
+
}))
|
|
115
|
+
|
|
116
|
+
return { body, stateWrite }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function resolveBodyFromState(state, payload) {
|
|
120
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
121
|
+
if (payload.mode === 'patch') {
|
|
122
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
123
|
+
return { error: 'state mismatch', status: 409 }
|
|
124
|
+
}
|
|
125
|
+
return applyPatchSet(state.body, payload.patch)
|
|
126
|
+
}
|
|
127
|
+
return { error: 'unknown mode', status: 400 }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function deferWorkerTask(task) {
|
|
131
|
+
return new Promise((resolve) => setTimeout(resolve, 0)).then(task)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const WEBSOCKET_STREAM_FLUSH_BYTES = 1024
|
|
135
|
+
const WEBSOCKET_STREAM_FLUSH_MS = 20
|
|
136
|
+
|
|
137
|
+
function createWebSocketStreamCoalescer(socket, options = {}) {
|
|
138
|
+
const flushBytes = options.flushBytes || WEBSOCKET_STREAM_FLUSH_BYTES
|
|
139
|
+
const flushMs = options.flushMs ?? WEBSOCKET_STREAM_FLUSH_MS
|
|
140
|
+
let chunks = []
|
|
141
|
+
let byteLength = 0
|
|
142
|
+
let flushTimer = null
|
|
143
|
+
const stats = {
|
|
144
|
+
upstreamChunks: 0,
|
|
145
|
+
upstreamBytes: 0,
|
|
146
|
+
frames: 0,
|
|
147
|
+
frameBytes: 0,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const clearFlushTimer = () => {
|
|
151
|
+
if (flushTimer === null) return
|
|
152
|
+
clearTimeout(flushTimer)
|
|
153
|
+
flushTimer = null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const mergeChunks = () => {
|
|
157
|
+
if (chunks.length === 1) return chunks[0]
|
|
158
|
+
const frame = new Uint8Array(byteLength)
|
|
159
|
+
let offset = 0
|
|
160
|
+
for (const chunk of chunks) {
|
|
161
|
+
frame.set(chunk, offset)
|
|
162
|
+
offset += chunk.byteLength
|
|
163
|
+
}
|
|
164
|
+
return frame
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const flush = () => {
|
|
168
|
+
clearFlushTimer()
|
|
169
|
+
if (byteLength === 0) return
|
|
170
|
+
const frame = mergeChunks()
|
|
171
|
+
chunks = []
|
|
172
|
+
byteLength = 0
|
|
173
|
+
socket.send(frame)
|
|
174
|
+
stats.frames += 1
|
|
175
|
+
stats.frameBytes += frame.byteLength
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const scheduleFlush = () => {
|
|
179
|
+
if (flushTimer !== null) return
|
|
180
|
+
flushTimer = setTimeout(flush, flushMs)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
push(value) {
|
|
185
|
+
const chunk = value instanceof Uint8Array ? value : new Uint8Array(value)
|
|
186
|
+
if (chunk.byteLength === 0) return
|
|
187
|
+
stats.upstreamChunks += 1
|
|
188
|
+
stats.upstreamBytes += chunk.byteLength
|
|
189
|
+
chunks.push(chunk)
|
|
190
|
+
byteLength += chunk.byteLength
|
|
191
|
+
if (byteLength >= flushBytes) flush()
|
|
192
|
+
else scheduleFlush()
|
|
193
|
+
},
|
|
194
|
+
flush,
|
|
195
|
+
stats() {
|
|
196
|
+
return { ...stats, pendingBytes: byteLength }
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function checkpointWebSocketState(env, payload, body, nextState) {
|
|
202
|
+
return deferWorkerTask(async () => {
|
|
203
|
+
try {
|
|
204
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
205
|
+
throw new Error('hash mismatch')
|
|
206
|
+
}
|
|
207
|
+
await writeState(env, payload.affinity, nextState)
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.log(JSON.stringify({
|
|
210
|
+
relay: 'opencode-anthropic-auth',
|
|
211
|
+
transport: 'websocket',
|
|
212
|
+
event: 'checkpoint_write_failed',
|
|
213
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
214
|
+
message: error instanceof Error ? error.message : String(error),
|
|
215
|
+
}))
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async function prepareWebSocketUpstream(env, state, payload) {
|
|
221
|
+
if (payload.protocol !== 2 || payload.type !== 'request' || !payload.id || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
222
|
+
return { error: 'invalid payload', status: 400 }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const body = resolveBodyFromState(state, payload)
|
|
226
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
227
|
+
if (typeof body !== 'string') return { error: 'invalid body', status: 400 }
|
|
228
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
229
|
+
return { error: 'hash mismatch', status: 409 }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const nextState = { body, hash: payload.next_hash, revision: payload.revision }
|
|
233
|
+
const checkpoint = checkpointWebSocketState(env, payload, body, nextState)
|
|
234
|
+
const logAccepted = () => console.log(JSON.stringify({
|
|
235
|
+
relay: 'opencode-anthropic-auth',
|
|
236
|
+
transport: 'websocket',
|
|
237
|
+
mode: payload.mode,
|
|
238
|
+
revision: payload.revision,
|
|
239
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
240
|
+
bodyBytes: body.length,
|
|
241
|
+
}))
|
|
242
|
+
|
|
243
|
+
return { body, state: nextState, checkpoint, logAccepted }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function headersToObject(headers) {
|
|
247
|
+
const result = {}
|
|
248
|
+
for (const [key, value] of headers.entries()) result[key] = value
|
|
249
|
+
return result
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function handleRelayPayload(env, payload) {
|
|
253
|
+
const prepared = await prepareUpstream(env, payload)
|
|
254
|
+
if (prepared.error) return prepared
|
|
255
|
+
const upstream = await fetch(payload.upstream.url, {
|
|
256
|
+
method: payload.upstream.method || 'POST',
|
|
257
|
+
headers: payload.upstream.headers,
|
|
258
|
+
body: prepared.body,
|
|
259
|
+
})
|
|
260
|
+
return { upstream, stateWrite: prepared.stateWrite }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async function handleWebSocket(socket, env, ctx, payload, getState, setState) {
|
|
264
|
+
const heartbeat = setInterval(() => {
|
|
265
|
+
try {
|
|
266
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'keepalive' }))
|
|
267
|
+
} catch {
|
|
268
|
+
clearInterval(heartbeat)
|
|
269
|
+
}
|
|
270
|
+
}, 15000)
|
|
271
|
+
let streamCoalescer = null
|
|
272
|
+
try {
|
|
273
|
+
const result = await prepareWebSocketUpstream(env, getState(), payload)
|
|
274
|
+
if (result.error) {
|
|
275
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: result.status, message: result.error }))
|
|
276
|
+
return
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
setState(result.state)
|
|
280
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'accepted', id: payload.id, hash: result.state.hash, revision: result.state.revision }))
|
|
281
|
+
ctx?.waitUntil?.(deferWorkerTask(result.logAccepted))
|
|
282
|
+
|
|
283
|
+
const upstreamPromise = fetch(payload.upstream.url, {
|
|
284
|
+
method: payload.upstream.method || 'POST',
|
|
285
|
+
headers: payload.upstream.headers,
|
|
286
|
+
body: result.body,
|
|
287
|
+
})
|
|
288
|
+
ctx?.waitUntil?.(result.checkpoint)
|
|
289
|
+
const upstream = await upstreamPromise
|
|
290
|
+
socket.send(JSON.stringify({
|
|
291
|
+
protocol: 2,
|
|
292
|
+
type: 'response_start',
|
|
293
|
+
id: payload.id,
|
|
294
|
+
status: upstream.status,
|
|
295
|
+
statusText: upstream.statusText,
|
|
296
|
+
headers: headersToObject(upstream.headers),
|
|
297
|
+
}))
|
|
298
|
+
|
|
299
|
+
const reader = upstream.body?.getReader()
|
|
300
|
+
if (reader) {
|
|
301
|
+
streamCoalescer = createWebSocketStreamCoalescer(socket)
|
|
302
|
+
while (true) {
|
|
303
|
+
const { done, value } = await reader.read()
|
|
304
|
+
if (done) break
|
|
305
|
+
streamCoalescer.push(value)
|
|
306
|
+
}
|
|
307
|
+
streamCoalescer.flush()
|
|
308
|
+
}
|
|
309
|
+
const stats = streamCoalescer?.stats?.() || {}
|
|
310
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'done', id: payload.id, ...stats }))
|
|
311
|
+
} catch (error) {
|
|
312
|
+
try {
|
|
313
|
+
streamCoalescer?.flush?.()
|
|
314
|
+
} catch {}
|
|
315
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
316
|
+
} finally {
|
|
317
|
+
clearInterval(heartbeat)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export default {
|
|
322
|
+
async fetch(request, env, ctx) {
|
|
323
|
+
if (request.headers.get('Upgrade') === 'websocket') {
|
|
324
|
+
const url = new URL(request.url)
|
|
325
|
+
const token = url.searchParams.get('token')
|
|
326
|
+
const affinity = url.searchParams.get('affinity')
|
|
327
|
+
if (token !== env.RELAY_TOKEN) return new Response('unauthorized', { status: 401 })
|
|
328
|
+
if (!affinity) return new Response('missing affinity', { status: 400 })
|
|
329
|
+
const pair = new WebSocketPair()
|
|
330
|
+
const client = pair[0]
|
|
331
|
+
const server = pair[1]
|
|
332
|
+
server.binaryType = 'arraybuffer'
|
|
333
|
+
let state = null
|
|
334
|
+
let ready = false
|
|
335
|
+
server.accept()
|
|
336
|
+
const loadState = readState(env, affinity).then((loadedState) => {
|
|
337
|
+
state = loadedState
|
|
338
|
+
ready = true
|
|
339
|
+
server.send(JSON.stringify({
|
|
340
|
+
protocol: 2,
|
|
341
|
+
type: 'ready',
|
|
342
|
+
state: state ? { hash: state.hash, revision: state.revision } : null,
|
|
343
|
+
}))
|
|
344
|
+
}).catch((error) => {
|
|
345
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
346
|
+
server.close(1011, 'state load failed')
|
|
347
|
+
})
|
|
348
|
+
ctx?.waitUntil?.(loadState)
|
|
349
|
+
if (!ctx?.waitUntil) void loadState
|
|
350
|
+
let busy = false
|
|
351
|
+
server.addEventListener('message', (event) => {
|
|
352
|
+
if (!ready) {
|
|
353
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 425, message: 'relay state is not ready' }))
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
if (busy) {
|
|
357
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 429, message: 'request already in flight' }))
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
let payload
|
|
361
|
+
try {
|
|
362
|
+
payload = JSON.parse(event.data)
|
|
363
|
+
} catch {
|
|
364
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 400, message: 'invalid JSON payload' }))
|
|
365
|
+
return
|
|
366
|
+
}
|
|
367
|
+
payload.affinity = affinity
|
|
368
|
+
busy = true
|
|
369
|
+
const run = handleWebSocket(server, env, ctx, payload, () => state, (nextState) => { state = nextState }).finally(() => { busy = false })
|
|
370
|
+
ctx?.waitUntil?.(run)
|
|
371
|
+
if (!ctx?.waitUntil) void run
|
|
372
|
+
})
|
|
373
|
+
return new Response(null, { status: 101, webSocket: client })
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (request.method === 'GET') {
|
|
377
|
+
return Response.json({ status: 'ok', transports: ['http', 'websocket'] })
|
|
378
|
+
}
|
|
379
|
+
if (request.method !== 'POST') return new Response('method not allowed', { status: 405 })
|
|
380
|
+
if (request.headers.get('x-relay-token') !== env.RELAY_TOKEN) {
|
|
381
|
+
return new Response('unauthorized', { status: 401 })
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
const payload = await request.json()
|
|
386
|
+
const result = await handleRelayPayload(env, payload)
|
|
387
|
+
if (result.error) return Response.json({ error: result.error }, { status: result.status })
|
|
388
|
+
|
|
389
|
+
if (result.stateWrite) ctx.waitUntil(result.stateWrite)
|
|
390
|
+
|
|
391
|
+
const upstream = result.upstream
|
|
392
|
+
return new Response(upstream.body, {
|
|
393
|
+
status: upstream.status,
|
|
394
|
+
statusText: upstream.statusText,
|
|
395
|
+
headers: upstream.headers,
|
|
396
|
+
})
|
|
397
|
+
} catch (error) {
|
|
398
|
+
return Response.json(
|
|
399
|
+
{ error: error instanceof Error ? error.message : 'internal relay error' },
|
|
400
|
+
{ status: 502 },
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
}
|
|
405
|
+
`;var Xm="claude-routing",$_=["main-first","fallback-first"],m_="main-first",X0="Usage: `/claude-routing`, `/claude-routing main-first`, or `/claude-routing fallback-first`.";function K1(f){return typeof f==="string"&&$_.includes(f)?f:m_}function Zm(f){return K1(f?.routing?.mode)}async function hm(f,_=z()){let D=await V(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.routing={...D.routing??{},mode:f},await q(D,_),D}function j1(f){let _=f.trim().toLowerCase().split(/\s+/).filter(Boolean);if(_.length===0)return{type:"status"};if(_.length===1&&$_.includes(_[0]))return{type:"mode",mode:_[0]};if(_.length===2&&_[0]==="mode"&&$_.includes(_[1]))return{type:"mode",mode:_[1]};return{type:"usage"}}function G1(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 E_(f){let _=f?.mode??m_;return["## Claude Routing Status","",`- Mode: \`${_}\``,`- Behavior: ${G1(_)}`,"",X0].join(`
|
|
406
|
+
`)}function Vm(f){let _=j1(f.argumentsText),D=f.mode??m_;if(_.type==="status")return E_({mode:D});if(_.type==="mode")return["## Claude Routing Updated","",`Mode updated to \`${_.mode}\`.`,"",...E_({mode:_.mode}).split(`
|
|
407
|
+
`).slice(2)].join(`
|
|
408
|
+
`);return["## Claude Routing Usage","",X0,"",...E_({mode:D}).split(`
|
|
409
|
+
`).slice(2)].join(`
|
|
410
|
+
`)}export{z1 as a,L_ as b,J1 as c,W1 as d,Y1 as e,X1 as f,Z1 as g,O_ as h,h1 as i,V1 as j,y as k,B_ as l,P1 as m,x1 as n,Q as o,X as p,u1 as q,g0 as r,r1 as s,z as t,V as u,q as v,JD as w,Hf as x,n1 as y,YD as z,g1 as A,s1 as B,c1 as C,t1 as D,o1 as E,e1 as F,a1 as G,f$ as H,_$ as I,T_ as J,QD as K,e as L,qf as M,D$ as N,w_ as O,l_ as P,qD as Q,E$ as R,$$ as S,m$ as T,M$ as U,pf as V,yD as W,O$ as X,U$ as Y,H$ as Z,S$ as _,dD as $,N$ as aa,o_ as ba,X$ as ca,F$ as da,K$ as ea,j$ as fa,g_ as ga,I$ as ha,Q$ as ia,GE as ja,sf as ka,_0 as la,zE as ma,q$ as na,WE as oa,i$ as pa,k$ as qa,TE as ra,p$ as sa,d$ as ta,u$ as ua,r$ as va,n$ as wa,uE as xa,g$ as ya,Mf as za,t$ as Aa,e$ as Ba,a$ as Ca,fm as Da,_m as Ea,Dm as Fa,Em as Ga,$m as Ha,mm as Ia,w as Ja,Hm as Ka,Sm as La,Nm as Ma,jm as Na,Gm as Oa,zm as Pa,Jm as Qa,Xm as Ra,Zm as Sa,hm as Ta,j1 as Ua,Vm as Va};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{mkdir as R,readFile as g,writeFile as q}from"node:fs/promises";import{tmpdir as C}from"node:os";import{dirname as y,join as V}from"node:path";var H="OPENCODE_ANTHROPIC_AUTH_SIDEBAR_STATE_FILE",k=V(C(),"opencode-anthropic-auth"),O=V(k,"sidebar-state.json");function h(){return process.env[H]||O}var b={main:{quota:null},fallbacks:[],activeId:void 0,route:"main",relay:null,fastMode:!1,lastUpdated:0};async function I(){try{let z=await g(h(),"utf8");return JSON.parse(z)}catch{return b}}async function S(z){try{let x=h();await R(y(x),{recursive:!0}),await q(x,JSON.stringify(z),"utf8")}catch{}}function D(z){let x=z.activeId;if(x&&x!=="main"){let J=z.fallbacks.find((K)=>K.enabled&&K.id===x);if(J)return{id:J.id,name:J.label??J.id,quota:J.quota}}return{id:"main",name:"main",quota:z.main.quota}}function F(z){let x=z?.five_hour?.usedPercent??null,J=z?.seven_day?.usedPercent??null;if(x==null&&J==null)return{fiveHourUsedPercent:x,sevenDayUsedPercent:J,text:null};return{fiveHourUsedPercent:x,sevenDayUsedPercent:J,text:`5h: ${x==null?"—":`${Math.round(x)}%`} 7d: ${J==null?"—":`${Math.round(J)}%`}`}}var U=18000000,v=604800000,N=300000,L=0.01,m=1;function T(z,x,J){if(!z.resetsAt)return null;let K=new Date(z.resetsAt).getTime();if(!Number.isFinite(K))return null;let Y=K-x,Q=J-Y;if(Q<N)return null;if(Q<x*L)return null;if(Q>=x)return null;let W=z.usedPercent,Z=Math.min(Math.max(Q/x*100,0),100),X=W-Z,j=Math.abs(X)<m?"on-pace":X>0?"deficit":"reserve",$=null;if(W>0){let G=Q*100/W,B=Y+G;if(B<K)$=new Date(B).toISOString()}return{pacePercent:Z,deltaPercent:X,state:j,runsOutAt:$}}
|
|
2
|
+
export{h as Wa,b as Xa,I as Ya,S as Za,D as _a,F as $a,U as ab,v as bb,T as cb};
|