@cortexkit/opencode-anthropic-auth 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/cli.js +1 -1
- package/dist/index-ws2d5kxr.js +323 -0
- package/dist/index.js +3 -3
- package/package.json +2 -2
- package/dist/index-v5pddj3r.js +0 -318
package/README.md
CHANGED
|
@@ -19,12 +19,13 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
|
|
|
19
19
|
| Primary Claude Pro/Max OAuth | OpenCode `/connect anthropic` | Pi `/login anthropic` |
|
|
20
20
|
| Provider integration point | OpenCode plugin fetch/request transform | Pi `registerProvider("anthropic")` provider override |
|
|
21
21
|
| Sidecar config | `~/.config/opencode/anthropic-auth.json` | `~/.pi/agent/anthropic-auth.json` |
|
|
22
|
-
| Commands | `/claude-cache`, `/claude-cachekeep`, `/claude-fast`, `/claude-quota`, `/claude-dump` | `/claude-cache`, `/claude-cachekeep`, `/claude-fast`, `/claude-quota`, `/claude-dump` |
|
|
22
|
+
| Commands | `/claude-cache`, `/claude-cachekeep`, `/claude-routing`, `/claude-fast`, `/claude-quota`, `/claude-dump` | `/claude-cache`, `/claude-cachekeep`, `/claude-routing`, `/claude-fast`, `/claude-quota`, `/claude-dump` |
|
|
23
23
|
| Fallback accounts, quota routing, relay, dumps, fast mode | Supported | Supported through the same shared core and Pi sidecar |
|
|
24
24
|
|
|
25
25
|
## What CortexKit adds over the original plugin
|
|
26
26
|
|
|
27
27
|
- **Fallback Claude accounts**: keep each agent's normal Anthropic login as the primary account, then route to ordered fallback OAuth accounts on auth/quota/rate-limit failures.
|
|
28
|
+
- **Routing mode toggle**: use `/claude-routing fallback-first` to prefer sidecar fallback accounts before the main account.
|
|
28
29
|
- **Quota-aware routing**: skip main or fallback accounts when their 5-hour or 7-day Claude quota falls below your configured minimum.
|
|
29
30
|
- **Persistent Claude cache controls**: manage Anthropic 1-hour prompt caching from `/claude-cache` with explicit, automatic, or hybrid modes.
|
|
30
31
|
- **Cache keepalive**: use `/claude-cachekeep HH-HH` to pre-warm hybrid cache anchors for active sessions before the 1-hour TTL expires.
|
|
@@ -155,6 +156,9 @@ Example:
|
|
|
155
156
|
"version": 1,
|
|
156
157
|
"main": { "type": "opencode", "provider": "anthropic" },
|
|
157
158
|
"fallbackOn": [401, 403, 429],
|
|
159
|
+
"routing": {
|
|
160
|
+
"mode": "main-first"
|
|
161
|
+
},
|
|
158
162
|
"refresh": {
|
|
159
163
|
"enabled": true,
|
|
160
164
|
"intervalMinutes": 10,
|
|
@@ -195,11 +199,13 @@ Example:
|
|
|
195
199
|
}
|
|
196
200
|
```
|
|
197
201
|
|
|
198
|
-
The `
|
|
202
|
+
The `routing` block controls `/claude-routing`, `claudeCache` controls `/claude-cache`, `cacheKeep` controls `/claude-cachekeep`, and `claudeFast` controls `/claude-fast`. The `main` field identifies OpenCode's primary auth entry; Pi keeps primary OAuth credentials in Pi's own credential store, but uses the same sidecar shape for CortexKit settings and fallback accounts.
|
|
199
203
|
|
|
200
204
|
## Fallback accounts
|
|
201
205
|
|
|
202
|
-
Fallback accounts are separate Claude OAuth accounts managed by this plugin.
|
|
206
|
+
Fallback accounts are separate Claude OAuth accounts managed by this plugin. By default, the main account is tried first unless quota policy says it is currently unusable. Fallbacks are then tried in sidecar order when the primary request returns a configured fallback status.
|
|
207
|
+
|
|
208
|
+
Use `/claude-routing fallback-first` to prefer usable fallback accounts before the main account. Use `/claude-routing main-first` to restore the default. The command persists `routing.mode` and takes effect on the next request without restarting.
|
|
203
209
|
|
|
204
210
|
Default fallback statuses:
|
|
205
211
|
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{l as y,m as w,o as l,p as u,q as m,ra as b,ta as k}from"./index-
|
|
2
|
+
import{l as y,m as w,o as l,p as u,q as m,ra as b,ta as k}from"./index-ws2d5kxr.js";import{stdin as A,stdout as $}from"node:process";import{createInterface as R}from"node:readline/promises";function v(){return{version:1,main:{type:"opencode",provider:"anthropic"},fallbackOn:[401,403,429],refresh:{enabled:!0,intervalMinutes:10,refreshBeforeExpiryMinutes:240},quota:{enabled:!0,checkIntervalMinutes:5,minimumRemaining:{five_hour:10,seven_day:20},failClosedOnUnknownQuota:!0},accounts:[]}}function h(){console.log(`Usage:
|
|
3
3
|
opencode-anthropic-auth login [label]
|
|
4
4
|
opencode-anthropic-auth list
|
|
5
5
|
opencode-anthropic-auth relay setup
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
var d="9d1c250a-e61b-44d9-88ed-5944d1962f5e",wf={console:"https://platform.claude.com/oauth/authorize",max:"https://claude.ai/oauth/authorize"},Mf="https://platform.claude.com/oauth/code/callback",Hf="https://platform.claude.com/v1/oauth/token",Rf=["org:create_api_key","user:profile","user:inference","user:sessions:claude_code","user:mcp_servers","user:file_upload"],__="mcp_";var kf="fast-mode-2026-02-01";function $_(f,m){let _=(f??"").split(",").map(($)=>$.trim()).filter(Boolean);return[...new Set([..._,...m])].join(",")}function E_(f){return typeof f==="string"&&(f.startsWith("claude-opus-4-6")||f.startsWith("claude-opus-4-7"))}var D_="You are OpenCode",C_="You are a Claude agent, built on Anthropic's Claude Agent SDK.";var Z="2.1.141",Ff="67b",nf="sdk-cli",uf="0.94.0",cf="v24.3.0",lf="claude-cli/2.1.141 (external, sdk-cli)",pf=["explicit","automatic","hybrid"],v="explicit",M_=["github.com/anomalyco/opencode","opencode.ai/docs"],H_=[{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 yf(f){let m="";for(let _ of f)m+=String.fromCharCode(_);return btoa(m).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function df(){let f=new Uint8Array(64);crypto.getRandomValues(f);let m=yf(f),_=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(m));return{verifier:m,challenge:yf(new Uint8Array(_)),method:"S256"}}function t0(f){if(!f)return;let m=Number(f);if(Number.isFinite(m)&&m>0)return Math.ceil(m);let _=Date.parse(f);if(Number.isFinite(_)){let $=Math.ceil((_-Date.now())/1000);return $>0?$:void 0}return}class Y extends Error{status;body;retryAfter;constructor(f,m,_){super(`Claude OAuth refresh failed: ${f} — ${m}`);this.status=f,this.body=m,this.name="ClaudeOAuthRefreshError",this.retryAfter=t0(_??void 0)}}function g0(f){if(!(f instanceof Error))return!1;let m=f.code;return f.message.includes("fetch failed")||m==="ECONNRESET"||m==="ECONNREFUSED"||m==="ETIMEDOUT"||m==="UND_ERR_CONNECT_TIMEOUT"}async function vf(f){let m=f.fetchImpl??fetch,_=f.maxRetries??2,$=f.baseDelayMs??500;for(let E=0;E<=_;E++)try{if(E>0){let M=$*2**(E-1);await new Promise((b)=>setTimeout(b,M))}let D=await m(Hf,{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:d})});if(!D.ok){if(D.status>=500&&E<_){await D.body?.cancel().catch(()=>{});continue}let M=await D.text().catch(()=>"");throw new Y(D.status,M,D.headers.get("retry-after"))}let C=await D.json(),H=f.now?.()??Date.now();return{access:C.access_token,refresh:C.refresh_token??f.refreshToken,expires:H+C.expires_in*1000,expiresIn:C.expires_in}}catch(D){if(D instanceof Y)throw D;if(E<_&&g0(D))continue;throw D}throw Error("Token refresh exhausted all retries")}function r0(){return crypto.randomUUID().replace(/-/g,"")}function s0(f){let m=f.trim();try{let C=new URL(m),H=C.searchParams.get("code"),M=C.searchParams.get("state");if(H&&M)return{code:H,state:M}}catch{}let _=m.split("#");if(_.length===2&&_[0]&&_[1])return{code:_[0],state:_[1]};let $=new URLSearchParams(m),E=$.get("code"),D=$.get("state");if(E&&D)return{code:E,state:D};return null}async function o0(f,m,_){let $=await fetch(Hf,{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:d,redirect_uri:_,code_verifier:m})});if(!$.ok)return{type:"failed"};let E=await $.json();return{type:"success",refresh:E.refresh_token,access:E.access_token,expires:Date.now()+E.expires_in*1000}}async function K_(f){let m=await df(),_=r0(),$=new URL(wf[f],import.meta.url);return $.searchParams.set("code","true"),$.searchParams.set("client_id",d),$.searchParams.set("response_type","code"),$.searchParams.set("redirect_uri",Mf),$.searchParams.set("scope",Rf.join(" ")),$.searchParams.set("code_challenge",m.challenge),$.searchParams.set("code_challenge_method","S256"),$.searchParams.set("state",_),{url:$.toString(),redirectUri:Mf,state:_,verifier:m.verifier}}async function j_(f,m,_,$){let E=s0(f);if(!E)return{type:"failed"};if($&&E.state!==$)return{type:"failed"};return o0(E,m,_)}import*as tf from"node:fs";import*as gf from"node:os";import*as rf from"node:path";var a0=rf.join(gf.tmpdir(),"opencode-anthropic-auth.log"),sf=!1,e0=500,f1=50,i=[],P=null;function bf(){if(P)clearTimeout(P),P=null;if(i.length===0)return;let f=i.join("");i=[];try{tf.appendFileSync(a0,f)}catch{}}function m1(){if(P)return;P=setTimeout(()=>{P=null,bf()},e0)}function _1(f){if(f===void 0)return"";if(f instanceof Error)return` ${f.message}${f.stack?`
|
|
2
|
+
${f.stack}`:""}`;return` ${JSON.stringify(f)}`}function L(f,m){if(sf)return;try{if(i.push(`[${new Date().toISOString()}] ${f}${_1(m)}
|
|
3
|
+
`),i.length>=f1)bf();else m1()}catch{}}function K(f,m){L(`[relay] ${f}`,m)}if(!sf)process.on("exit",bf);import{createHash as E0,randomUUID as Kf}from"node:crypto";import{mkdir as $1,readFile as t,rename as E1,rm as of,stat as D1,writeFile as D0}from"node:fs/promises";import{homedir as C1}from"node:os";import{dirname as M1,join as g}from"node:path";var H1="anthropic-auth.json",F1="https://api.anthropic.com/api/oauth/usage",b1=[401,403,429],C0=240,N1=C0;var S1=300000,K1=3600000,j1=86400000,I1=5,af={five_hour:0,seven_day:0},U1=!0,G1=60000,J1=60000,B1=120000,A1=1e4,T1=100;function L1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return g(process.env.XDG_CONFIG_HOME||g(C1(),".config"),"opencode")}function T(){return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim()||g(L1(),H1)}function U(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function W1(f){if(!U(f))return null;if(f.type!=="oauth")return null;if(typeof f.refresh!=="string"||!f.refresh.trim())return null;return{id:typeof f.id==="string"&&f.id.trim()?f.id.trim():Kf(),label:typeof f.label==="string"?f.label:void 0,type:"oauth",access:typeof f.access==="string"?f.access:void 0,refresh:f.refresh,expires:typeof f.expires==="number"?f.expires:void 0,enabled:typeof f.enabled==="boolean"?f.enabled:void 0,addedAt:typeof f.addedAt==="number"?f.addedAt:void 0,lastUsed:typeof f.lastUsed==="number"?f.lastUsed:void 0,lastRefreshedAt:typeof f.lastRefreshedAt==="number"?f.lastRefreshedAt:void 0,lastRefreshError:ef(f.lastRefreshError),lastQuotaRefreshError:ef(f.lastQuotaRefreshError),quota:z1(f.quota)}}function ef(f){if(!U(f))return;if(typeof f.message!=="string")return;let m=Number(f.checkedAt);if(!Number.isFinite(m))return;let _=Number(f.nextRetryAt),$=Number(f.retryCount);return{message:f.message,checkedAt:m,nextRetryAt:Number.isFinite(_)?_:void 0,retryCount:Number.isFinite($)?$:void 0,tokenHash:typeof f.tokenHash==="string"?f.tokenHash:void 0}}function z1(f){if(!U(f))return;let m={};for(let _ of["five_hour","seven_day"]){let $=f[_];if(!U($))continue;let E=Number($.usedPercent),D=Number($.remainingPercent),C=Number($.checkedAt);if(!Number.isFinite(E)||!Number.isFinite(D)||!Number.isFinite(C))continue;m[_]={usedPercent:E,remainingPercent:D,checkedAt:C,resetsAt:typeof $.resetsAt==="string"?$.resetsAt:void 0}}return Object.keys(m).length?m:void 0}function O1(f){if(!U(f)||!Array.isArray(f.accounts))return null;return{version:1,main:{type:"opencode",provider:"anthropic"},routing:U(f.routing)?f.routing:void 0,fallbackOn:Array.isArray(f.fallbackOn)?f.fallbackOn.filter((m)=>Number.isInteger(m)):void 0,refresh:U(f.refresh)?f.refresh:void 0,quota:U(f.quota)?f.quota:void 0,claudeCache:U(f.claudeCache)?f.claudeCache:void 0,dump:U(f.dump)?f.dump:void 0,claudeFast:U(f.claudeFast)?f.claudeFast:void 0,cacheKeep:U(f.cacheKeep)?f.cacheKeep:void 0,relay:U(f.relay)?f.relay:void 0,accounts:f.accounts.map(W1).filter((m)=>m!=null)}}async function z(f=T()){try{let m=await t(f,"utf8");return O1(JSON.parse(m))}catch(m){if(m.code==="ENOENT")return null;return null}}async function Q1(f){try{let m=await t(f,"utf8"),_=JSON.parse(m);return U(_)?_:{}}catch{return{}}}function Z1(f){return Object.fromEntries(Object.entries(f).filter(([,m])=>m!==void 0))}async function O(f,m=T()){await $1(M1(m),{recursive:!0});let $={...await Q1(m),...Z1(f)},E=`${m}.${Kf()}.tmp`;await D0(E,`${JSON.stringify($,null,2)}
|
|
4
|
+
`,{encoding:"utf8",mode:384}),await E1(E,m)}async function X1(f){let _=`${f.path??T()}.${f.name}.lock`,$=g(_,"owner.json"),E=Kf(),D=f.now??Date.now;async function C(){try{return JSON.parse(await t(_,"utf8"))}catch(M){if(M.code!=="EISDIR")throw M;return JSON.parse(await t($,"utf8"))}}async function H(){try{return await D0(_,`${JSON.stringify({ownerId:E,expiresAt:D()+f.ttlMs})}
|
|
5
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(M){let b=M.code;if(b==="EEXIST"||b==="EISDIR")return!1;throw M}}if(!await H()){try{let M=await C();if(Number(M?.expiresAt)>D())return null}catch{try{if((await D1(_)).mtimeMs+f.ttlMs>Date.now())return null}catch{return null}}if(await of(_,{recursive:!0,force:!0}).catch(()=>{}),!await H())return null}return{release:async()=>{try{if((await C())?.ownerId!==E)return}catch{return}await of(_,{recursive:!0,force:!0}).catch(()=>{})}}}function z_(f){return f?.claudeCache?.enabled===!0}function Y1(f){return typeof f==="string"&&pf.includes(f)?f:v}function V1(f){return Y1(f?.claudeCache?.mode)}async function O_(f,m,_=T()){let $=await z(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return $.claudeCache={...$.claudeCache??{},enabled:f,mode:m??V1($)},await O($,_),$}async function Q_(f,m=T()){let _=await z(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.claudeCache={..._.claudeCache??{},enabled:_.claudeCache?.enabled===!0,mode:f},await O(_,m),_}function Z_(f){return f?.dump?.enabled===!0}async function X_(f,m=T()){let _=await z(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.dump={..._.dump??{},enabled:f},await O(_,m),_}function Y_(f){return f?.claudeFast?.enabled===!0}async function V_(f,m=T()){let _=await z(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.claudeFast={..._.claudeFast??{},enabled:f},await O(_,m),_}async function h_(f,m,_=T()){let $=await z(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return $.cacheKeep={enabled:!0,startHour:f,endHour:m},await O($,_),$}async function q_(f,m=T()){let _=await z(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.cacheKeep={..._.cacheKeep??{},enabled:f},await O(_,m),_}function h1(f){return f?.fallbackOn?.length?f.fallbackOn:b1}function x_(f,m){return h1(m).includes(f)}function M0(f){let m=f?.quota?.minimumRemaining||{};return{five_hour:m.five_hour??m["5h"]??af.five_hour,seven_day:m.seven_day??m["1w"]??af.seven_day}}function n(f){return f?.quota?.enabled!==!1}function q1(f){return f?.refresh?.enabled!==!1}function x1(f){return Math.floor(Math.random()*Math.max(0,f))}function P1(f){let m=f?.refresh?.refreshBeforeExpiryMinutes??N1;return Math.max(C0,m)*60000}function H0(f){return E0("sha256").update(f).digest("hex")}function w1(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 i1(f){let m=H0(f.refreshToken),$=(f.previous?.tokenHash===m?f.previous.retryCount??0:0)+1,E;if(f.error instanceof Y&&f.error.retryAfter)E=f.error.retryAfter*1000;else if(w1(f.error))E=Math.min(K1,S1*2**Math.min($-1,6));else E=j1;return{message:u(f.error),checkedAt:f.now,nextRetryAt:f.now+E,retryCount:$,tokenHash:m}}function R(f,m,_){if(!f?.nextRetryAt||f.nextRetryAt<=_)return!1;if(!m)return!0;return f.tokenHash===H0(m)}function Nf(f,m){return`Claude OAuth refresh is backed off for ${Math.max(1,Math.ceil(((f.nextRetryAt??m)-m)/1000))}s after: ${f.message}`}function k(f){let m=f?.quota?.checkIntervalMinutes??I1;return Math.max(1,m)*60000}function F0(f){return f?.quota?.failClosedOnUnknownQuota??U1}function b0(f,m){if(!n(m))return!0;let _=M0(m);for(let $ of["five_hour","seven_day"]){let E=f?.[$];if(!E)return!F0(m);if(E.remainingPercent<_[$])return!1}return!0}function P_(f,m,_){if(!n(m))return _+k(m);let $=M0(m),E=[];for(let D of["five_hour","seven_day"]){let C=f?.[D];if(!C)return _+k(m);if(C.remainingPercent>=$[D])continue;let H=C.resetsAt?Date.parse(C.resetsAt):Number.NaN;if(!Number.isFinite(H)||H<=_)return _+k(m);E.push(H)}if(!E.length)return _+k(m);return Math.min(...E)+60000}function V(f,m,_){return!f.access||!f.expires||f.expires-_<=P1(m)}function Sf(f,m,_){if(!n(m))return!1;let $=k(m);return["five_hour","seven_day"].some((E)=>{let D=f.quota?.[E];return!D||_-D.checkedAt>=$})}function R1(f,m){if(!f)return!1;if(!f.resetsAt)return!0;let _=Date.parse(f.resetsAt);return!Number.isFinite(_)||_>m}function k1(f,m){return["five_hour","seven_day"].every((_)=>R1(f?.[_],m))}function n1(f){let m=u(f);if(/Claude quota check failed: (429|5\d\d)\b/.test(m))return!0;if(!(f instanceof Error))return!1;let _=f.code;return m.includes("fetch failed")||_==="ECONNRESET"||_==="ECONNREFUSED"||_==="ETIMEDOUT"||_==="UND_ERR_CONNECT_TIMEOUT"}function u1(f,m,_,$){return n1(_)&&b0(f.quota,m)&&k1(f.quota,$)}function f0(f){if(!Number.isFinite(f))return 0;if(f<0)return 0;if(f>100)return 100;return f}function m0(f,m){if(typeof f?.utilization!=="number")return;let _=f0(f.utilization);return{usedPercent:_,remainingPercent:f0(100-_),resetsAt:f.resets_at,checkedAt:m}}async function _0(f){let _=await(f.fetchImpl??fetch)(F1,{method:"GET",headers:{Authorization:`Bearer ${f.accessToken}`,Accept:"application/json","Content-Type":"application/json","anthropic-beta":"oauth-2025-04-20","User-Agent":`claude-code/${Z}`}});if(!_.ok){let D=await _.text().catch(()=>"");throw Error(`Claude quota check failed: ${_.status} — ${D}`)}let $=f.now?.()??Date.now(),E=await _.json();return{five_hour:m0(E.five_hour,$),seven_day:m0(E.seven_day,$)}}function A(f,m){let _=f.accounts.findIndex(($)=>$.id===m.id);if(_>=0)f.accounts[_]=m}function u(f){return f instanceof Error?f.message:String(f)}function N0(f,m,_){f.lastRefreshError=i1({error:m,now:_,refreshToken:f.refresh,previous:f.lastRefreshError})}function $0(f,m,_){if(f.lastQuotaRefreshError={message:u(m),checkedAt:_},m instanceof Y)N0(f,m,_)}function c1(f){return`fallback-oauth-refresh-${E0("sha256").update(f).digest("hex").slice(0,16)}`}class l1{now;fetchImpl;configPath;refreshPromises=new Map;refreshTimer=null;quotaTimer=null;constructor(f={}){this.now=f.now??Date.now,this.fetchImpl=f.fetchImpl??fetch,this.configPath=f.configPath??T()}async load(){return z(this.configPath)}async save(f){await O(f,this.configPath)}startBackgroundRefresh(){let f=async()=>{await this.refreshDueAccounts(),await this.refreshQuotaForDueAccounts()};if(f().catch(()=>{}),!this.refreshTimer){if(this.refreshTimer=setInterval(()=>{f().catch(()=>{})},G1+x1(J1)),"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 m=f!==void 0?f:await this.load();if(!m)return[];let _=[],$=!1;for(let E of m.accounts){if(E.enabled===!1)continue;try{let D=E;if(V(D,m,this.now())){let C=D.lastRefreshError;if(C&&R(C,D.refresh,this.now()))throw Error(Nf(C,this.now()));D=await this.refreshAccount(D,m),$=!0}if(Sf(D,m,this.now()))D=await this.refreshAccountQuota(D,m),$=!0;if(this.accountPassesQuotaPolicy(D,m))_.push(D)}catch(D){if(u1(E,m,D,this.now()))L("[refresh] fallback quota using cached quota after refresh error",{accountId:E.id,error:u(D)}),_.push(E);else if(!F0(m))_.push(E)}}if($)await this.save(m);return _}async markUsed(f){let m=await this.load();if(!m)return;let _=m.accounts.find(($)=>$.id===f.id);if(!_)return;_.lastUsed=this.now(),await this.save(m)}accountPassesQuotaPolicy(f,m){return b0(f.quota,m)}async refreshDueAccounts(){let f=await this.load();if(!f||!q1(f))return;let m=!1;for(let _ of f.accounts){if(_.enabled===!1)continue;if(!V(_,f,this.now()))continue;if(R(_.lastRefreshError,_.refresh,this.now())){L("[refresh] fallback oauth skipped backoff",{accountId:_.id,nextRetryAt:_.lastRefreshError?.nextRetryAt,retryCount:_.lastRefreshError?.retryCount});continue}try{L("[refresh] fallback oauth background due",{accountId:_.id,expiresInMs:_.expires?_.expires-this.now():void 0}),await this.refreshAccount(_,f),m=!0}catch($){L("[refresh] fallback oauth background failed",{accountId:_.id,error:$ instanceof Error?$.message:String($)}),N0(_,$,this.now()),A(f,_),m=!0}}if(m)await this.save(f)}async refreshQuotaForDueAccounts(){let f=await this.load();if(!f||!n(f))return;let m=!1;for(let _ of f.accounts){if(_.enabled===!1)continue;let $=_;try{if(V($,f,this.now())){if(R($.lastRefreshError,$.refresh,this.now()))continue;$=await this.refreshAccount($,f),m=!0}if(!Sf($,f,this.now()))continue;await this.refreshAccountQuota($,f),m=!0}catch(E){$0(_,E,this.now()),A(f,_),m=!0}}if(m)await this.save(f)}async refreshQuotaForAllAccounts(){let f=await this.load(),m=[];if(!f||!n(f))return{storage:f,errors:m};let _=!1;for(let $ of f.accounts){if($.enabled===!1)continue;let E=$;try{if(V(E,f,this.now())){let D=E.lastRefreshError;if(D&&R(D,E.refresh,this.now()))throw Error(Nf(D,this.now()));E=await this.refreshAccount(E,f),_=!0}if(!Sf(E,f,this.now())){if(E.lastQuotaRefreshError)E.lastQuotaRefreshError=void 0,A(f,E),_=!0;continue}await this.refreshAccountQuota(E,f),_=!0}catch(D){$0($,D,this.now()),A(f,$),_=!0,m.push({accountId:$.id,message:u(D)})}}if(_)await this.save(f);return{storage:f,errors:m}}async refreshAccount(f,m,_={}){let $=this.refreshPromises.get(f.id);if($){let C=await $;return A(m,C),C}let E=this.refreshAccountNow(f,m,_).finally(()=>{this.refreshPromises.delete(f.id)});this.refreshPromises.set(f.id,E);let D=await E;return A(m,D),D}async waitForConcurrentFallbackRefresh(f,m,_,$){let E=Date.now()+A1;while(Date.now()<E){await new Promise((b)=>setTimeout(b,T1));let D=await this.load(),C=D?.accounts.find((b)=>b.id===f.id);if(!C)continue;if((C.access!==_.access||C.refresh!==_.refresh||(C.expires??0)>(_.expires??0)+60000)&&($.force||!V(C,D,this.now())))return A(m,C),L("[refresh] fallback oauth joined concurrent refresh",{accountId:C.id,expiresInMs:C.expires?C.expires-this.now():void 0}),C;let M=C.lastRefreshError;if(M&&R(M,C.refresh,this.now()))throw A(m,C),Error(Nf(M,this.now()))}return null}async refreshAccountNow(f,m,_){let $=await this.load(),E=$?.accounts.find((H)=>H.id===f.id);if(E&&!_.force&&!V(E,$,this.now()))return A(m,E),E;let D=E??f,C=await X1({name:c1(D.id),ttlMs:B1,path:this.configPath,now:this.now});if(!C){L("[refresh] fallback oauth refresh skipped file lock",{accountId:D.id});let H=await this.waitForConcurrentFallbackRefresh(f,m,D,_);if(H)return H;throw Error("Fallback OAuth refresh is already in progress")}try{if($=await this.load(),E=$?.accounts.find((b)=>b.id===f.id),E&&!_.force&&!V(E,$,this.now()))return A(m,E),E;D=E??D;let H=D.refresh;L("[refresh] fallback oauth refresh request start",{accountId:D.id,force:_.force===!0,expiresInMs:D.expires?D.expires-this.now():void 0});let M=await vf({refreshToken:H,fetchImpl:this.fetchImpl,now:this.now});return D.access=M.access,D.refresh=M.refresh,D.expires=M.expires,D.lastRefreshedAt=M.expires-M.expiresIn*1000,D.lastRefreshError=void 0,A(m,D),await this.save(m),L("[refresh] fallback oauth refresh succeeded",{accountId:D.id,expiresInMs:D.expires?D.expires-this.now():void 0}),D}finally{await C.release()}}async refreshAccountQuota(f,m){let _=f;if(!_.access)throw Error(`Fallback account ${f.id} has no access token`);try{_.quota=await _0({accessToken:_.access,fetchImpl:this.fetchImpl,now:this.now})}catch($){if(!($ instanceof Error?$.message:String($)).includes("Claude quota check failed: 401"))throw $;if(_=await this.refreshAccount(f,m,{force:!0}),!_.access)throw $;_.quota=await _0({accessToken:_.access,fetchImpl:this.fetchImpl,now:this.now})}return _.lastQuotaRefreshError=void 0,A(m,_),_}}var R_="claude-cache",S0="## Claude Cache Status",p1="## Claude Cache Enabled",y1="## Claude Cache Disabled",d1="## Claude Cache Usage",v1="Usage: `/claude-cache`, `/claude-cache on`, `/claude-cache off`, or `/claude-cache mode explicit|automatic|hybrid`.",r=!1,s=v;function k_(){return r}function n_(){return s}function u_(f){r=f.enabled,s=f.mode}function t1(f){let m=f.trim().split(/\s+/).filter(Boolean);if(m.length===0)return{type:"status"};if(m.length===1&&m[0]==="on")return{type:"enable"};if(m.length===1&&m[0]==="off")return{type:"disable"};if(m.length===2&&m[0]==="mode"&&(m[1]==="explicit"||m[1]==="automatic"||m[1]==="hybrid"))return{type:"mode",mode:m[1]};return{type:"usage"}}function c(f){let m=f?.enabled??r,_=f?.mode??s;return[S0,"",`- Enabled: ${m?"enabled":"disabled"}`,`- Mode: ${_}`,"- 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(`
|
|
6
|
+
`)}function c_(f){let m=t1(f.argumentsText),_=f.enabled??r,$=f.mode??s;if(m.type==="status")return c({enabled:_,mode:$});if(m.type==="enable")return[p1,"",c({enabled:!0,mode:$})].join(`
|
|
7
|
+
`);if(m.type==="disable")return[y1,"",c({enabled:!1,mode:$})].join(`
|
|
8
|
+
`);if(m.type==="mode")return[S0,"",`Mode updated to \`${m.mode}\`.`,"",c({enabled:_,mode:m.mode})].join(`
|
|
9
|
+
`);return[d1,"",v1,"",c({enabled:_,mode:$})].join(`
|
|
10
|
+
`)}import{randomBytes as g1,randomUUID as j0}from"node:crypto";var r1=1000,l=new Map;function If(f,m,_){if(!f.has(m)&&f.size>=r1){let $=f.keys().next().value;if($!==void 0)f.delete($)}f.set(m,_)}function I0(f){let m=f||"anonymous",_=l.get(m);if(_)return _;let $={deviceId:g1(32).toString("hex"),sessionId:j0()};return If(l,m,$),$}var jf=new Map;async function s1(f,m){if(!f.startsWith("sk-ant-oat"))return null;let _=new AbortController,$=setTimeout(()=>_.abort(),5000);try{let E=new URL("https://api.anthropic.com/api/claude_cli/bootstrap");if(E.searchParams.set("entrypoint",nf),m)E.searchParams.set("model",m);let D=await fetch(E,{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/${Z}`},signal:_.signal});if(!D.ok)return null;let H=(await D.json().catch(()=>null))?.oauth_account?.account_uuid;return typeof H==="string"&&H?H:null}catch{return null}finally{clearTimeout($)}}async function d_(f,m){let _=I0(f);if(!f.startsWith("sk-ant-oat"))return _;let $=jf.get(f);if(!$)$=s1(f,m),jf.set(f,$);let E=await $;if(!E)return jf.delete(f),_;let D=`account:${E}`,C=l.get(D);if(C)return If(l,f,C),C;return _.accountUuid=E,If(l,D,_),_}function h(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function o1(f){if(!f.accountUuid)return null;return JSON.stringify({device_id:f.deviceId,account_uuid:f.accountUuid,session_id:f.sessionId})}function v_(f,m){let _=o1(m);if(!_){if(h(f.metadata))delete f.metadata.user_id;return!1}if(!h(f.metadata))f.metadata={};let $=f.metadata;if(h($))$.user_id=_;return!0}var a1=["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"],e1=["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"],K0=["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 fm(f){return f.output_config?.format?.type==="json_schema"}function mm(f){return Array.isArray(f.tools)&&f.tools.length>0&&Array.isArray(f.system)&&h(f.thinking)&&h(f.context_management)&&h(f.output_config)&&h(f.diagnostics)}function _m(f,m=[]){let _=f?mm(f)?[...a1]:fm(f)?[...e1]:[...K0]:[...K0];if(f?.speed==="fast")_.push(kf);for(let $ of m){let E=$.trim();if(E)_.push(E)}return[...new Set(_)].join(",")}function $m(){switch(process.platform){case"darwin":return"MacOS";case"win32":return"Windows";case"linux":return"Linux";case"freebsd":return"FreeBSD";default:return"Unknown"}}function Em(){switch(process.arch){case"arm64":return"arm64";case"x64":return"x64";case"ia32":return"x32";default:return process.arch}}function t_(f,m,_={}){let $=_.identity??I0(m),D=[...(f.get("anthropic-beta")??"").split(",").map((C)=>C.trim()).filter(Boolean),..._.extraBetas??[]];return f.set("accept","application/json"),f.set("authorization",`Bearer ${m}`),f.set("content-type","application/json"),f.set("user-agent",lf),f.set("anthropic-beta",_m(_.body,D)),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",j0()),f.set("x-claude-code-session-id",$.sessionId),f.set("x-stainless-arch",Em()),f.set("x-stainless-lang","js"),f.set("x-stainless-os",$m()),f.set("x-stainless-package-version",uf),f.set("x-stainless-retry-count","0"),f.set("x-stainless-runtime","node"),f.set("x-stainless-runtime-version",cf),f.set("x-stainless-timeout","600"),f.delete("x-api-key"),f}var Dm=["model","messages","system","tools","tool_choice","metadata","max_tokens","temperature","thinking","context_management","output_config","diagnostics","stream","speed"];function U0(f){let m={};for(let _ of Dm)if(Object.hasOwn(f,_))m[_]=f[_];for(let[_,$]of Object.entries(f))if(!Object.hasOwn(m,_))m[_]=$;return m}import{createHash as Mm}from"node:crypto";var Cm=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 G0(){return function(f){let{exports:{mem:m,xxh32:_,xxh64:$,init32:E,update32:D,digest32:C,init64:H,update64:M,digest64:b}}=f,S=new Uint8Array(m.buffer);function j(F,I){if(m.buffer.byteLength<F+I){let Df=Math.ceil((F+I-m.buffer.byteLength)/65536);m.grow(Df),S=new Uint8Array(m.buffer)}}function Q(F,I,Df,y0,d0,v0){j(F);let w=new Uint8Array(F);return S.set(w),Df(0,I),w.set(S.subarray(0,F)),{update(x){let Cf;return S.set(w),typeof x=="string"?(j(3*x.length,F),Cf=B.encodeInto(x,S.subarray(F)).written):(j(x.byteLength,F),S.set(x,F),Cf=x.byteLength),y0(0,F,Cf),w.set(S.subarray(0,F)),this},digest:()=>(S.set(w),v0(d0(0)))}}function W(F){return F>>>0}let N=2n**64n-1n;function J(F){return F&N}let B=new TextEncoder,p=0,y=0n;function xf(F,I=p){return j(3*F.length,0),W(_(0,B.encodeInto(F,S).written,I))}function Pf(F,I=y){return j(3*F.length,0),J($(0,B.encodeInto(F,S).written,I))}return{h32:xf,h32ToString:(F,I=p)=>xf(F,I).toString(16).padStart(8,"0"),h32Raw:(F,I=p)=>(j(F.byteLength,0),S.set(F),W(_(0,F.byteLength,I))),create32:(F=p)=>Q(48,F,E,D,C,W),h64:Pf,h64ToString:(F,I=y)=>Pf(F,I).toString(16).padStart(16,"0"),h64Raw:(F,I=y)=>(j(F.byteLength,0),S.set(F),J($(0,F.byteLength,I))),create64:(F=y)=>Q(88,F,H,M,b,J)}}((await WebAssembly.instantiate(Cm)).instance)}var Hm=0x6e52736ac806831en,o=/\bcch=([0-9a-f]{5});/,J0=null,Uf=null;async function Fm(){if(Uf)return;J0??=(async()=>{Uf=(await G0()).h64Raw})(),await J0}async function bm(f){return await Fm(),((Uf?.(f,Hm)??0n)&0xfffffn).toString(16).padStart(5,"0")}async function B0(f){if(!o.test(f))return f;let m=await bm(new TextEncoder().encode(f));return f.replace(o,`cch=${m};`)}function Nm(f=Z,m=new Date){if(f===Z)return Ff;let _=m.toISOString().slice(0,10);return Mm("sha256").update(`${_}${f}`).digest("hex").slice(0,3)}function e_(f,m=Z,_,$=new Date){let E=Nm(m,$);return`x-anthropic-billing-header: cc_version=${m}.${E}; cc_entrypoint=${_}; cch=00000;`}var $$="claude-cachekeep",A0=3600000,Gf=300000,Sm=60000,E$="extended-cache-ttl-2025-04-11",Km="## Claude Cache Keep Status",jm="## Claude Cache Keep Enabled",Im="## Claude Cache Keep Disabled",Um="## Claude Cache Keep Usage",Gm="Usage: `/claude-cachekeep`, `/claude-cachekeep off`, or `/claude-cachekeep HH-HH`.";function e(f){return String(f).padStart(2,"0")}function Jm(f){let m=f.trim();if(!m)return{type:"status"};if(m==="off")return{type:"disable"};let _=/^(\d{1,2})-(\d{1,2})$/.exec(m);if(!_)return{type:"usage"};let $=Number(_[1]),E=Number(_[2]);if(!Number.isInteger($)||!Number.isInteger(E)||$<0||$>23||E<0||E>23||$===E)return{type:"usage"};return{type:"window",startHour:$,endHour:E}}function Bf(f){let m=Number(f?.cacheKeep?.startHour),_=Number(f?.cacheKeep?.endHour);if(!Number.isInteger(m)||!Number.isInteger(_)||m<0||m>23||_<0||_>23||m===_)return;return{startHour:m,endHour:_}}function W0(f){return f?.cacheKeep?.enabled===!0&&!!Bf(f)}function Bm(f){return W0(f)&&f?.claudeCache?.enabled===!0&&f.claudeCache.mode==="hybrid"}function T0(f,m=new Date){if(!f)return!1;let _=m.getHours();if(f.startHour<f.endHour)return _>=f.startHour&&_<f.endHour;return _>=f.startHour||_<f.endHour}function L0(f=new Date){return`${f.getFullYear()}-${e(f.getMonth()+1)}-${e(f.getDate())}`}function Jf(f,m=new Date){if(f&&f.startHour>f.endHour&&m.getHours()<f.endHour){let _=new Date(m);return _.setDate(_.getDate()-1),L0(_)}return L0(m)}function a(f){let m=f.window?`${e(f.window.startHour)}-${e(f.window.endHour)}`:"not configured",_=[`Cache keep: ${f.enabled?"enabled":"disabled"}`,`Window: ${m}`,"Mode requirement: `/claude-cache mode hybrid` must be active."];if(typeof f.hybridActive==="boolean")_.push(`Hybrid active: ${f.hybridActive?"yes":"no"}`);if(typeof f.trackedSessions==="number")_.push(`Tracked sessions: ${f.trackedSessions}`);if(f.nextPrewarmAt)_.push(`Next prewarm: ${new Date(f.nextPrewarmAt).toLocaleString()}`);return _.join(`
|
|
11
|
+
`)}function D$(f){let m=Jm(f.argumentsText),_={enabled:f.enabled??!1,window:f.window,trackedSessions:f.trackedSessions,nextPrewarmAt:f.nextPrewarmAt,hybridActive:f.hybridActive};if(m.type==="status")return[Km,"",a(_)].join(`
|
|
12
|
+
`);if(m.type==="disable")return[Im,"",a({..._,enabled:!1})].join(`
|
|
13
|
+
`);if(m.type==="window")return[jm,"",a({..._,enabled:!0,window:{startHour:m.startHour,endHour:m.endHour}})].join(`
|
|
14
|
+
`);return[Um,"",Gm,"",a(_)].join(`
|
|
15
|
+
`)}function Af(f){if(!f||typeof f!=="object")return!1;if(Array.isArray(f))return f.some(Af);let m=f,_=m.cache_control;if(_&&typeof _==="object"&&_.type==="ephemeral")return!0;return Object.values(m).some(Af)}async function Am(f){let m;try{m=JSON.parse(f)}catch{return{ok:!1,reason:"body is not valid JSON"}}if(!Af(m))return{ok:!1,reason:"body has no explicit cache breakpoints"};let _=structuredClone(m);if(_.max_tokens=0,delete _.stream,_.thinking?.type==="enabled")delete _.thinking;if(_.output_config?.format)delete _.output_config;let D=_.tool_choice;if(D?.type==="tool"||D?.type==="any")delete _.tool_choice;let C=JSON.stringify(U0(_)).replace(o,"cch=00000;");return{ok:!0,bodyText:await B0(C)}}class Tm{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)})})},Sm),"unref"in this.timer)this.timer.unref()}stop(){if(this.timer)clearInterval(this.timer);this.timer=null}stats(f,m=this.options.now?.()??Date.now()){let _=Jf(f,new Date(m)),$=[...this.targets.values()].filter((D)=>D.dayKey===_),E=$.length?Math.min(...$.map((D)=>D.cacheExpiresAt-Gf)):void 0;return{trackedSessions:$.length,nextPrewarmAt:E}}track(f){if(!f.sessionId)return{tracked:!1,reason:"missing session id"};if(!W0(f.storage))return{tracked:!1,reason:"cachekeep disabled"};if(f.cacheMode!=="hybrid")return{tracked:!1,reason:"cache mode is not hybrid"};let m=this.options.now?.()??Date.now(),_=Bf(f.storage);if(!T0(_,new Date(m)))return{tracked:!1,reason:"outside configured window"};let $={};return f.headers.forEach((E,D)=>{$[D]=E}),this.targets.set(f.sessionId,{id:f.sessionId,url:f.url,headers:$,bodyText:f.bodyText,cacheExpiresAt:m+A0,dayKey:Jf(_,new Date(m))}),this.start(),{tracked:!0}}async tick(){let f=await this.options.loadStorage(),m=Bf(f),_=this.options.now?.()??Date.now(),$=Jf(m,new Date(_));for(let[D,C]of this.targets)if(C.dayKey!==$)this.targets.delete(D);if(!this.targets.size){this.stop();return}if(!Bm(f))return;if(!T0(m,new Date(_)))return;let E=_+Gf;for(let D of this.targets.values()){if(D.cacheExpiresAt>E)continue;await this.prewarm(D,_)}}async prewarm(f,m){let _=await Am(f.bodyText);if(!_.ok){this.options.log?.("[cachekeep] prewarm skipped",{session:f.id,reason:_.reason}),this.targets.delete(f.id);return}let $=this.options.fetchImpl??fetch,E={...f,bodyText:_.bodyText},D=this.options.prepareHeaders?await this.options.prepareHeaders(new Headers(f.headers),E):new Headers(f.headers);D.delete("content-length"),D.delete("transfer-encoding");let C=await $(f.url,{method:"POST",headers:D,body:_.bodyText});if(!C.ok){this.options.log?.("[cachekeep] prewarm failed",{session:f.id,status:C.status,body:await C.text().catch(()=>"")}),f.cacheExpiresAt=m+Gf+300000;return}await C.body?.cancel().catch(()=>{}),f.cacheExpiresAt=m+A0,this.options.log?.("[cachekeep] prewarm succeeded",{session:f.id})}}import{createHash as Lm}from"node:crypto";import{mkdir as Wm,writeFile as Tf}from"node:fs/promises";import{tmpdir as zm}from"node:os";import{join as Q0}from"node:path";var S$="claude-dump",Om="## Claude Dump Status",Qm="## Claude Dump Enabled",Zm="## Claude Dump Disabled",Xm="## Claude Dump Usage",Ym="Usage: `/claude-dump`, `/claude-dump on`, or `/claude-dump off`.",Wf=Q0(zm(),"opencode-anthropic-auth-dumps"),mf=!1,z0=0;function K$(f){mf=f}function Vm(f){let m=f.trim().split(/\s+/).filter(Boolean);if(m.length===0)return{type:"status"};if(m.length===1&&m[0]==="on")return{type:"enable"};if(m.length===1&&m[0]==="off")return{type:"disable"};return{type:"usage"}}function ff(f){let m=f?.enabled??mf;return[Om,"",`- Enabled: ${m?"enabled":"disabled"}`,`- Directory: ${Wf}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Captures: final rewritten Anthropic body plus redacted relay payload metadata","- Warning: body dumps may contain prompt/session content; turn this off after debugging"].join(`
|
|
16
|
+
`)}function j$(f){let m=Vm(f.argumentsText),_=f.enabled??mf;if(m.type==="status")return ff({enabled:_});if(m.type==="enable")return[Qm,"",ff({enabled:!0})].join(`
|
|
17
|
+
`);if(m.type==="disable")return[Zm,"",ff({enabled:!1})].join(`
|
|
18
|
+
`);return[Xm,"",Ym,"",ff({enabled:_})].join(`
|
|
19
|
+
`)}function O0(f){return f.length<=16?f:`${f.slice(0,12)}…`}function Z0(f){return Lm("sha256").update(f).digest("hex")}function hm(f){return f.match(/\bcch=([0-9a-f]{5});/)?.[1]??null}function qm(f,m){if(f==null)return null;if(f===m)return{changed:!1,firstByte:-1,lastPreviousByte:-1,lastCurrentByte:-1,previousBytes:f.length,currentBytes:m.length};let _=0;while(_<f.length&&_<m.length&&f[_]===m[_])_+=1;let $=f.length-1,E=m.length-1;while($>=_&&E>=_&&f[$]===m[E])$-=1,E-=1;return{changed:!0,firstByte:_,lastPreviousByte:$,lastCurrentByte:E,changedPreviousBytes:$-_+1,changedCurrentBytes:E-_+1,previousBytes:f.length,currentBytes:m.length}}function xm(f){try{let m=JSON.parse(f);return m!=null&&typeof m==="object"&&!Array.isArray(m)?m:null}catch(m){return K(`dump body parse failed: ${m instanceof Error?m.message:String(m)}`),null}}function Lf(f){return Z0(JSON.stringify(f))}function Pm(f){let m=xm(f);if(!m)return{parseable:!1};let _=Array.isArray(m.messages)?m.messages:[],$=Array.isArray(m.system)?m.system:[],E=_[0],D=_.slice(1);return{parseable:!0,model:typeof m.model==="string"?m.model:void 0,stream:m.stream,systemCount:$.length,messagesCount:_.length,systemHash:Lf($),message0Hash:E===void 0?null:Lf(E),message0Bytes:E===void 0?0:JSON.stringify(E).length,messagesAfter0Hash:Lf(D),messagesAfter0Bytes:JSON.stringify(D).length,cch:hm(f)}}function zf(f){if(Array.isArray(f))return f.map(zf);if(f==null||typeof f!=="object")return f;let m={};for(let[_,$]of Object.entries(f)){let E=_.toLowerCase();if(E==="authorization"||E==="x-api-key"||E==="cookie"||E==="set-cookie"){m[_]="[redacted]";continue}m[_]=zf($)}return m}async function X0(f){if(!mf)return;z0+=1;let m=`${new Date().toISOString().replace(/[:.]/g,"-")}-${String(z0).padStart(5,"0")}-${f.transport}-p${f.protocol}-${f.mode}`,_=Q0(Wf,m);try{await Wm(Wf,{recursive:!0});let $={id:m,createdAt:new Date().toISOString(),session:O0(f.affinity),transport:f.transport,protocol:f.protocol,mode:f.mode,status:f.status,bodyBytes:f.bodyText.length,relayBytes:f.relayBytes,bodyHash:Z0(f.bodyText),diff:qm(f.previousBodyText,f.bodyText),body:Pm(f.bodyText),files:{body:`${_}.body.json`,relay:`${_}.relay.json`,metadata:`${_}.meta.json`}};await Promise.all([Tf(`${_}.body.json`,f.bodyText,"utf8"),Tf(`${_}.relay.json`,`${JSON.stringify(zf(f.payload),null,2)}
|
|
20
|
+
`,"utf8"),Tf(`${_}.meta.json`,`${JSON.stringify($,null,2)}
|
|
21
|
+
`,"utf8")]),K(`dumped request id=${m} session=${O0(f.affinity)} body=${_}.body.json meta=${_}.meta.json`)}catch($){K(`dump failed: ${$ instanceof Error?$.message:String($)}`)}}var U$="claude-fast";var $f=!1;function G$(){return $f}function J$(f){$f=f}function wm(f){let m=f.trim().split(/\s+/).filter(Boolean);if(m.length===0)return{type:"status"};if(m.length===1&&m[0]==="on")return{type:"enable"};if(m.length===1&&m[0]==="off")return{type:"disable"};return{type:"usage"}}function _f(f){return["## Claude Fast Mode Status","",`- Enabled: ${f?.enabled??$f?"enabled":"disabled"}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Scope: adds Anthropic fast mode to supported Opus requests","- Supported models: claude-opus-4-6 and claude-opus-4-7",'- 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(`
|
|
22
|
+
`)}function B$(f){let m=wm(f.argumentsText),_=f.enabled??$f;if(m.type==="status")return _f({enabled:_});if(m.type==="enable")return["## Claude Fast Mode Enabled","",_f({enabled:!0})].join(`
|
|
23
|
+
`);if(m.type==="disable")return["## Claude Fast Mode Disabled","",_f({enabled:!1})].join(`
|
|
24
|
+
`);return["## Claude Fast Mode Usage","","Usage: `/claude-fast`, `/claude-fast on`, or `/claude-fast off`.","",_f({enabled:_})].join(`
|
|
25
|
+
`)}var T$="claude-quota",Y0={five_hour:"5h",seven_day:"1w"};function V0(f){return`${Math.round(f*10)/10}%`}function Of(f,m){let _=Math.max(0,m-f),$=Math.floor(_/60000);if($<1)return"just now";if($===1)return"1m ago";if($<60)return`${$}m ago`;let E=Math.floor($/60),D=$%60;if(D===0)return`${E}h ago`;return`${E}h ${D}m ago`}function im(f,m){let _=Date.parse(f);if(!Number.isFinite(_))return f;let $=_-m;if($<=0)return"now";let E=Math.max(1,Math.ceil($/60000));if(E<60)return`in ${E}m`;let D=Math.floor(E/60),C=E%60;if(C===0)return`in ${D}h`;return`in ${D}h ${C}m`}function Rm(f,m){if(!f)return"";return`, resets ${im(f,m)}`}function h0(f,m,_){if(!m)return` - ${Y0[f]}: unknown`;return[` - ${Y0[f]}: ${V0(m.remainingPercent)} remaining`,` (${V0(m.usedPercent)} used`,`${Rm(m.resetsAt,_)}, checked ${Of(m.checkedAt,_)})`].join("")}function km(f){return f.label?.trim()||f.id}function nm(f){return f.lastQuotaRefreshError?.message??f.lastRefreshError?.message}function L$(f,m=new Map){if(!f?.accounts.length)return[];return f.accounts.map((_)=>{let $=m.get(_.id)??nm(_);return{name:km(_),role:"fallback",enabled:_.enabled!==!1,quota:_.quota,lastRefreshedAt:_.lastRefreshedAt,...$&&{error:$}}})}function W$(f){let m=f.now??Date.now(),_=["## Claude Quotas",""];if(f.refreshedAt)_.push(`Refreshed: ${Of(f.refreshedAt,m)}`,"");if(!f.accounts.length)return _.push("No Claude OAuth accounts found yet."),_.join(`
|
|
26
|
+
`);for(let $ of f.accounts){let E=$.role==="main"?"main":"fallback",D=$.enabled===!1?" disabled":"";if(_.push(`### ${$.name} (${E}${D})`),$.lastRefreshedAt)_.push(` - Last token refresh: ${Of($.lastRefreshedAt,m)}`);if($.error)_.push(` - Error: ${$.error}`);_.push(h0("five_hour",$.quota?.five_hour,m)),_.push(h0("seven_day",$.quota?.seven_day,m)),_.push("")}return _.join(`
|
|
27
|
+
`).trimEnd()}import{Buffer as n0}from"node:buffer";import{createHash as um,randomBytes as cm}from"node:crypto";class Zf extends Error{}var Yf=new Map,q0=new Map,x0=new Set,P0=0;function Qf(){return P0+=1,`req_${Date.now().toString(36)}_${P0.toString(36)}`}function Ef(f){if(x0.has(f))return;x0.add(f),K(f)}function Y$(f){let m=f?.relay;if(!m)return Ef("disabled: no relay config found"),null;if(m.enabled!==!0)return Ef("disabled: relay.enabled is not true"),null;if(!m.url?.trim()||!m.token?.trim())return Ef("disabled: missing relay url or token"),null;let _=m.transport==="http"?"http":"websocket";return Ef(`configured transport=${_} protocol=${_==="websocket"?2:1} url=${m.url.trim()} fallbackToDirect=${m.fallbackToDirect!==!1}`),{enabled:!0,url:m.url.trim(),token:m.token.trim(),fallbackToDirect:m.fallbackToDirect!==!1,transport:_}}function V$(){return cm(32).toString("base64url")}function lm(f){return`sha256:${um("sha256").update(f).digest("hex")}`}function w0(f,m){let _=0,$=Math.min(f.length,m.length);while(_<$&&f.charCodeAt(_)===m.charCodeAt(_))_++;let E=f.length,D=m.length;while(E>_&&D>_&&f.charCodeAt(E-1)===m.charCodeAt(D-1))E--,D--;return{start:_,deleteCount:E-_,insert:m.slice(_,D)}}function pm(f){return f.deleteCount===0&&f.insert.length===0}function i0(f){let m=f.match(/\bcch=([0-9a-f]{5});/),_=m?.[1];if(!_||m.index==null)return null;let $=m.index+4;return{start:$,end:$+_.length,token:_}}function ym(f,m,_,$){return`${f.slice(0,m)}${$}${f.slice(_)}`}function u0(f,m){let _=i0(f),$=i0(m);if(_&&$&&_.start===$.start&&_.end-_.start===$.end-$.start&&_.token!==$.token){let E={start:_.start,deleteCount:_.end-_.start,insert:$.token},D=ym(f,_.start,_.end,$.token),C=w0(D,m);return pm(C)?E:[E,C]}return w0(f,m)}function dm(f,m){if(typeof m!=="string")return!1;try{let _=f instanceof Request?new URL(f.url):new URL(f.toString());return _.pathname==="/v1/messages"||_.pathname==="/messages"}catch{return!1}}function vm(f){let m={};for(let[_,$]of f.entries()){if(_==="x-session-affinity"||_==="x-opencode-session")continue;m[_]=$}return m}async function R0(f,m){return fetch(f.url,{method:"POST",headers:{"content-type":"application/json","x-relay-token":f.token},body:JSON.stringify(m)})}function G(f){return f.length>12?`${f.slice(0,12)}…`:f}function X(){return performance.now()}function q(f){return Math.round(f*10)/10}function tm(f){let{input:m,init:_,headers:$,bodyText:E,affinity:D,previous:C,nextHash:H}=f,M=m instanceof Request?m.url:m.toString(),b={protocol:1,type:"request",affinity:D,upstream:{url:M,method:_?.method||(m instanceof Request?m.method:"POST"),headers:vm($)},next_hash:H};return C?{...b,mode:"patch",base_hash:C.hash,revision:C.revision+1,patch:u0(C.body,E)}:{...b,mode:"full_sync",revision:1,body:E}}function Xf(f,m){return{protocol:f.protocol,type:"request",affinity:f.affinity,upstream:f.upstream,next_hash:f.next_hash,mode:"full_sync",revision:1,body:m}}function c0(f,m,_,$){Yf.set(f,{body:m,hash:_,revision:$})}async function k0(f){let{config:m,payload:_,bodyText:$,fallback:E}=f,D=_,C=await R0(m,D);if(C.status===409&&D.mode==="patch")K(`state mismatch from relay session=${G(D.affinity)}; retrying full_sync`),await C.body?.cancel().catch(()=>{}),D=Xf(D,$),C=await R0(m,D);if(!C.ok&&C.status>=500&&m.fallbackToDirect)return K(`relay returned ${C.status}; falling back direct session=${G(D.affinity)}`),await C.body?.cancel().catch(()=>{}),{response:await E(),payload:D,transport:"http",protocol:D.protocol,usedRelay:!1};return{response:C,payload:D,transport:"http",protocol:D.protocol,usedRelay:!0}}function gm(f,m){let _=new URL(f);return _.protocol=_.protocol==="http:"?"ws:":"wss:",_.pathname="/ws",_.searchParams.set("token",m),_.toString()}function rm(f){return new Uint8Array(n0.from(f,"base64"))}function sm(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(n0.from(String(f)))}function om(f){return JSON.parse(f)}class l0{config;affinity;socket;connecting;queue=Promise.resolve();pending;serverState;constructor(f,m){this.config=f,this.affinity=m}send(f,m,_=!1){let $=X(),E=this.queue.catch(()=>{}).then(()=>this.startQueued(f,m,$,_)),D=E.then(async({response:C,getPayload:H})=>({response:await C,payload:H(),transport:"websocket",protocol:2,usedRelay:!0}));return this.queue=E.then(({done:C})=>C.catch(()=>{}),()=>{}),D}async startQueued(f,m,_,$){let E=X();await this.ensureConnected();let D=X(),C=Yf.get(this.affinity),H=this.serverState?.hash,M={...f,protocol:2,id:Qf()};if(M.mode==="patch"&&(!H||H!==M.base_hash))M.mode="full_sync",M.revision=(this.serverState?.revision??0)+1,delete M.base_hash,delete M.patch,M.body=m;if(M.mode==="patch"&&C)M.patch=u0(C.body,m);K(`perf websocket send_start session=${G(this.affinity)} request=${M.id} mode=${M.mode} queueMs=${q(D-_)} connectMs=${q(D-E)} bodyBytes=${m.length} relayBytes=${JSON.stringify(M).length}`);let b=M,S=this.sendPayload(M,m,$);S.done.catch(()=>{});let j=S.done,Q=S.response.catch((N)=>{if(!(N instanceof Zf)||M.mode!=="patch")throw N;let J=Xf(M,m);J.protocol=2,J.id=Qf(),J.revision=(this.serverState?.revision??0)+1,b=J;let B=this.sendPayload(J,m,$);return B.done.catch(()=>{}),j=B.done,B.response}),W=Q.then(()=>j,()=>j.catch(()=>{}));return{response:Q,done:W,getPayload:()=>b}}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,m)=>{let _=gm(this.config.url,this.config.token),$=new URL(_);$.searchParams.set("affinity",this.affinity);let E=new WebSocket($.toString());this.socket=E,this.serverState=void 0;let D=setTimeout(()=>{E.close(),m(Error("relay websocket ready timed out"))},15000);E.addEventListener("message",(C)=>{try{if(typeof C.data!=="string"){this.handleBinaryChunk(C.data);return}let H=om(C.data);if(H.type==="ready"){clearTimeout(D),this.serverState=H.state,f();return}this.handleMessage(H)}catch(H){clearTimeout(D),m(H),this.failPending(H),E.close()}}),E.addEventListener("error",()=>{clearTimeout(D);let C=Error("relay websocket error");m(C),this.failPending(C)}),E.addEventListener("close",()=>{if(clearTimeout(D),this.socket===E)this.socket=void 0,this.serverState=void 0,this.connecting=void 0;if(this.pending){if(this.pending.retryingBeforeResponse)return;if(this.retryPendingBeforeResponse(this.pending,"closed before response"))return;let C=Error("relay websocket closed before response");this.failPending(C)}})}).finally(()=>{this.connecting=void 0}),await this.connecting}sendPayload(f,m,_){let $=this.socket;if(!$||$.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");let E=X(),D,C,H=new Promise((b,S)=>{D=b,C=S});return{response:new Promise((b,S)=>{let j={payload:f,bodyText:m,resolve:b,reject:S,streamDone:!1,accepted:!1,responseStarted:!1,resolveDone:D,rejectDone:C,sentAt:E,optimisticResponse:_,retryAttempts:0,retryingBeforeResponse:!1};if(this.pending=j,this.resetPendingTimeout(j),$.send(JSON.stringify(f)),_)this.resolvePendingResponse(j,200,"OK",{"content-type":"text/event-stream","x-cortexkit-relay-optimistic":"true"})}),done:H}}resetPendingTimeout(f){clearTimeout(f.timeout),f.timeout=setTimeout(()=>{if(this.pending!==f)return;if(this.retryPendingBeforeResponse(f,"response timed out"))return;this.failPending(Error("relay websocket response timed out")),this.socket?.close()},45000)}retryPendingBeforeResponse(f,m){if(f.responseStartedAt!=null)return!1;if(f.streamDone)return!1;if(f.retryAttempts>=1)return!1;f.retryAttempts+=1,f.retryingBeforeResponse=!0,clearTimeout(f.timeout);let _=f.retryAttempts,$=f.payload.id;return K(`websocket ${m}; reconnecting and retrying full_sync session=${G(this.affinity)} request=${$} retry=${_}`),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 E=Xf(f.payload,f.bodyText);E.protocol=2,E.id=Qf(),E.revision=(this.serverState?.revision??0)+1,f.payload=E,f.accepted=!1,f.acceptedAt=void 0,f.responseStartedAt=void 0,f.sentAt=X(),f.retryingBeforeResponse=!1;let D=this.socket;if(!D||D.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");this.resetPendingTimeout(f),K(`perf websocket retry_send session=${G(this.affinity)} request=${E.id} previous=${$} mode=full_sync retry=${_} bodyBytes=${f.bodyText.length} relayBytes=${JSON.stringify(E).length}`),D.send(JSON.stringify(E))}catch(E){if(f.retryingBeforeResponse=!1,this.pending===f)this.failPending(E)}})(),!0}handleBinaryChunk(f){let m=this.pending;if(!m?.responseStarted)return;m.streamController?.enqueue(sm(f))}resolvePendingResponse(f,m,_,$){if(f.responseStarted)return;f.responseStarted=!0;let E=new ReadableStream({start:(D)=>{f.streamController=D},cancel:()=>{this.socket?.close()}});f.resolve(new Response(E,{status:m,statusText:_,headers:$}))}handleMessage(f){if(f.type==="keepalive"){if(this.pending)this.resetPendingTimeout(this.pending);return}let m=this.pending;if(!m)return;if("id"in f&&f.id&&f.id!==m.payload.id)return;if(f.type==="accepted"){let _=X();m.accepted=!0,m.acceptedAt=_,K(`perf websocket accepted session=${G(this.affinity)} request=${m.payload.id} sentMs=${q(_-m.sentAt)} mode=${m.payload.mode}`),this.serverState={hash:f.hash,revision:f.revision},c0(this.affinity,m.bodyText,f.hash,f.revision),this.resetPendingTimeout(m);return}if(f.type==="response_start"){let _=X();if(m.responseStartedAt=_,K(`perf websocket response_start session=${G(this.affinity)} request=${m.payload.id} sentMs=${q(_-m.sentAt)} upstreamMs=${m.acceptedAt==null?"unknown":q(_-m.acceptedAt)} status=${f.status}`),clearTimeout(m.timeout),this.resolvePendingResponse(m,f.status,f.statusText,f.headers),m.optimisticResponse&&f.status>=400)m.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
28
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_upstream_error",message:`Relay upstream returned HTTP ${f.status}`}})}
|
|
29
|
+
|
|
30
|
+
`)),this.finishPending();return}if(f.type==="chunk"){m.streamController?.enqueue(rm(f.base64));return}if(f.type==="done"){this.finishPending();return}if(f.type==="error"){if(m.optimisticResponse&&m.responseStartedAt!=null){K(`websocket relay error during optimistic response session=${G(this.affinity)} request=${m.payload.id} status=${f.status} message=${f.message||"unknown"}`),m.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
31
|
+
data: ${JSON.stringify({type:"error",error:{type:"relay_error",message:f.message||"relay error"}})}
|
|
32
|
+
|
|
33
|
+
`)),this.finishPending(),this.socket?.close();return}if(f.status===409&&this.retryPendingBeforeResponse(m,f.message||"state mismatch"))return;let _=f.status===409?new Zf(f.message||"state mismatch"):Error(f.message||"relay websocket error");this.failPending(_)}}finishPending(){let f=this.pending;if(!f)return;let m=X();if(K(`perf websocket done session=${G(this.affinity)} request=${f.payload.id} sentMs=${q(m-f.sentAt)} streamMs=${f.responseStartedAt==null?"unknown":q(m-f.responseStartedAt)}`),clearTimeout(f.timeout),!f.streamDone)f.streamDone=!0,f.streamController?.close();f.resolveDone(),this.pending=void 0}failPending(f){let m=this.pending;if(!m)return;if(clearTimeout(m.timeout),this.pending=void 0,m.responseStarted)m.streamController?.error(f);else m.reject(f);m.rejectDone(f)}}function am(f,m){let _=q0.get(m);if(_)return _;let $=new l0(f,m);return q0.set(m,$),$}async function h$(f){let{config:m,input:_,init:$,headers:E,body:D,fallback:C,affinity:H,optimisticResponse:M}=f;if(!m||!dm(_,D))return C();let b=H||E.get("x-session-affinity")||E.get("x-opencode-session");if(!b)return K("skipping relay: missing x-session-affinity header"),C();let S=D,j=lm(S),Q=Yf.get(b),W=tm({input:_,init:$,headers:E,bodyText:S,affinity:b,previous:Q,nextHash:j});try{let N;if(m.transport==="websocket")try{N=await am(m,b).send(W,S,M===!0)}catch(B){K(`websocket relay failed session=${G(b)}; trying http relay: ${B instanceof Error?B.message:String(B)}`),N=await k0({config:m,payload:W,bodyText:S,fallback:C})}else N=await k0({config:m,payload:W,bodyText:S,fallback:C});if(!N.usedRelay)return N.response;if(N.transport==="http")c0(b,S,N.payload.next_hash,N.payload.revision);let J=JSON.stringify(N.payload).length;return K(`used relay transport=${N.transport} protocol=${N.protocol} mode=${N.payload.mode} status=${N.response.status} session=${G(b)} bodyBytes=${S.length} relayBytes=${J}`),await X0({affinity:b,transport:N.transport,protocol:N.protocol,mode:N.payload.mode,status:N.response.status,bodyText:S,previousBodyText:Q?.body,payload:N.payload,relayBytes:J}),N.response}catch(N){if(!m.fallbackToDirect)throw K(`relay failed session=${G(b)} and fallbackToDirect=false: ${N instanceof Error?N.message:String(N)}`),N;return K(`relay failed; falling back direct session=${G(b)}: ${N instanceof Error?N.message:String(N)}`),C()}}var q$=`
|
|
34
|
+
async function hashBody(body) {
|
|
35
|
+
const bytes = new TextEncoder().encode(body)
|
|
36
|
+
const digest = await crypto.subtle.digest('SHA-256', bytes)
|
|
37
|
+
const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('')
|
|
38
|
+
return 'sha256:' + hex
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function applyPatch(base, patch) {
|
|
42
|
+
return base.slice(0, patch.start) + patch.insert + base.slice(patch.start + patch.deleteCount)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function applyPatchSet(base, patch) {
|
|
46
|
+
if (!Array.isArray(patch)) return applyPatch(base, patch)
|
|
47
|
+
if (patch.length === 0) return base
|
|
48
|
+
|
|
49
|
+
let result = ''
|
|
50
|
+
let cursor = 0
|
|
51
|
+
for (const item of patch) {
|
|
52
|
+
if (item.start < cursor) return { error: 'overlapping patch', status: 400 }
|
|
53
|
+
result += base.slice(cursor, item.start)
|
|
54
|
+
result += item.insert
|
|
55
|
+
cursor = item.start + item.deleteCount
|
|
56
|
+
}
|
|
57
|
+
return result + base.slice(cursor)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function readState(env, affinity) {
|
|
61
|
+
const raw = await env.RELAY_STATE.get('session:' + affinity)
|
|
62
|
+
return raw ? JSON.parse(raw) : null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function writeState(env, affinity, state) {
|
|
66
|
+
await env.RELAY_STATE.put('session:' + affinity, JSON.stringify(state), { expirationTtl: 86400 })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function resolveBody(env, payload) {
|
|
70
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
71
|
+
if (payload.mode === 'patch') {
|
|
72
|
+
const state = await readState(env, payload.affinity)
|
|
73
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
74
|
+
return { error: 'state mismatch', status: 409 }
|
|
75
|
+
}
|
|
76
|
+
return applyPatchSet(state.body, payload.patch)
|
|
77
|
+
}
|
|
78
|
+
return { error: 'unknown mode', status: 400 }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function prepareUpstream(env, payload) {
|
|
82
|
+
if ((payload.protocol !== 1 && payload.protocol !== 2) || payload.type !== 'request' || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
83
|
+
return { error: 'invalid payload', status: 400 }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const body = await resolveBody(env, payload)
|
|
87
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
88
|
+
|
|
89
|
+
if (typeof body !== 'string' || (await hashBody(body)) !== payload.next_hash) {
|
|
90
|
+
return { error: 'hash mismatch', status: 409 }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const stateWrite = writeState(env, payload.affinity, { body, hash: payload.next_hash, revision: payload.revision }).catch(() => {})
|
|
94
|
+
console.log(JSON.stringify({
|
|
95
|
+
relay: 'opencode-anthropic-auth',
|
|
96
|
+
transport: 'relay',
|
|
97
|
+
mode: payload.mode,
|
|
98
|
+
revision: payload.revision,
|
|
99
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
100
|
+
bodyBytes: body.length,
|
|
101
|
+
}))
|
|
102
|
+
|
|
103
|
+
return { body, stateWrite }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function resolveBodyFromState(state, payload) {
|
|
107
|
+
if (payload.mode === 'full_sync') return payload.body
|
|
108
|
+
if (payload.mode === 'patch') {
|
|
109
|
+
if (!state || state.hash !== payload.base_hash) {
|
|
110
|
+
return { error: 'state mismatch', status: 409 }
|
|
111
|
+
}
|
|
112
|
+
return applyPatchSet(state.body, payload.patch)
|
|
113
|
+
}
|
|
114
|
+
return { error: 'unknown mode', status: 400 }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function deferWorkerTask(task) {
|
|
118
|
+
return new Promise((resolve) => setTimeout(resolve, 0)).then(task)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function checkpointWebSocketState(env, payload, body, nextState) {
|
|
122
|
+
return deferWorkerTask(async () => {
|
|
123
|
+
try {
|
|
124
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
125
|
+
throw new Error('hash mismatch')
|
|
126
|
+
}
|
|
127
|
+
await writeState(env, payload.affinity, nextState)
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.log(JSON.stringify({
|
|
130
|
+
relay: 'opencode-anthropic-auth',
|
|
131
|
+
transport: 'websocket',
|
|
132
|
+
event: 'checkpoint_write_failed',
|
|
133
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
134
|
+
message: error instanceof Error ? error.message : String(error),
|
|
135
|
+
}))
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function prepareWebSocketUpstream(env, state, payload) {
|
|
141
|
+
if (payload.protocol !== 2 || payload.type !== 'request' || !payload.id || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
142
|
+
return { error: 'invalid payload', status: 400 }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const body = resolveBodyFromState(state, payload)
|
|
146
|
+
if (body && typeof body === 'object' && 'error' in body) return body
|
|
147
|
+
if (typeof body !== 'string') return { error: 'invalid body', status: 400 }
|
|
148
|
+
if ((await hashBody(body)) !== payload.next_hash) {
|
|
149
|
+
return { error: 'hash mismatch', status: 409 }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const nextState = { body, hash: payload.next_hash, revision: payload.revision }
|
|
153
|
+
const checkpoint = checkpointWebSocketState(env, payload, body, nextState)
|
|
154
|
+
const logAccepted = () => console.log(JSON.stringify({
|
|
155
|
+
relay: 'opencode-anthropic-auth',
|
|
156
|
+
transport: 'websocket',
|
|
157
|
+
mode: payload.mode,
|
|
158
|
+
revision: payload.revision,
|
|
159
|
+
affinity: String(payload.affinity).slice(0, 12),
|
|
160
|
+
bodyBytes: body.length,
|
|
161
|
+
}))
|
|
162
|
+
|
|
163
|
+
return { body, state: nextState, checkpoint, logAccepted }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function headersToObject(headers) {
|
|
167
|
+
const result = {}
|
|
168
|
+
for (const [key, value] of headers.entries()) result[key] = value
|
|
169
|
+
return result
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function handleRelayPayload(env, payload) {
|
|
173
|
+
const prepared = await prepareUpstream(env, payload)
|
|
174
|
+
if (prepared.error) return prepared
|
|
175
|
+
const upstream = await fetch(payload.upstream.url, {
|
|
176
|
+
method: payload.upstream.method || 'POST',
|
|
177
|
+
headers: payload.upstream.headers,
|
|
178
|
+
body: prepared.body,
|
|
179
|
+
})
|
|
180
|
+
return { upstream, stateWrite: prepared.stateWrite }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function handleWebSocket(socket, env, ctx, payload, getState, setState) {
|
|
184
|
+
const heartbeat = setInterval(() => {
|
|
185
|
+
try {
|
|
186
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'keepalive' }))
|
|
187
|
+
} catch {
|
|
188
|
+
clearInterval(heartbeat)
|
|
189
|
+
}
|
|
190
|
+
}, 15000)
|
|
191
|
+
try {
|
|
192
|
+
const result = await prepareWebSocketUpstream(env, getState(), payload)
|
|
193
|
+
if (result.error) {
|
|
194
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: result.status, message: result.error }))
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
setState(result.state)
|
|
199
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'accepted', id: payload.id, hash: result.state.hash, revision: result.state.revision }))
|
|
200
|
+
ctx?.waitUntil?.(deferWorkerTask(result.logAccepted))
|
|
201
|
+
|
|
202
|
+
const upstreamPromise = fetch(payload.upstream.url, {
|
|
203
|
+
method: payload.upstream.method || 'POST',
|
|
204
|
+
headers: payload.upstream.headers,
|
|
205
|
+
body: result.body,
|
|
206
|
+
})
|
|
207
|
+
ctx?.waitUntil?.(result.checkpoint)
|
|
208
|
+
const upstream = await upstreamPromise
|
|
209
|
+
socket.send(JSON.stringify({
|
|
210
|
+
protocol: 2,
|
|
211
|
+
type: 'response_start',
|
|
212
|
+
id: payload.id,
|
|
213
|
+
status: upstream.status,
|
|
214
|
+
statusText: upstream.statusText,
|
|
215
|
+
headers: headersToObject(upstream.headers),
|
|
216
|
+
}))
|
|
217
|
+
|
|
218
|
+
const reader = upstream.body?.getReader()
|
|
219
|
+
if (reader) {
|
|
220
|
+
while (true) {
|
|
221
|
+
const { done, value } = await reader.read()
|
|
222
|
+
if (done) break
|
|
223
|
+
socket.send(value)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'done', id: payload.id }))
|
|
227
|
+
} catch (error) {
|
|
228
|
+
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
229
|
+
} finally {
|
|
230
|
+
clearInterval(heartbeat)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export default {
|
|
235
|
+
async fetch(request, env, ctx) {
|
|
236
|
+
if (request.headers.get('Upgrade') === 'websocket') {
|
|
237
|
+
const url = new URL(request.url)
|
|
238
|
+
const token = url.searchParams.get('token')
|
|
239
|
+
const affinity = url.searchParams.get('affinity')
|
|
240
|
+
if (token !== env.RELAY_TOKEN) return new Response('unauthorized', { status: 401 })
|
|
241
|
+
if (!affinity) return new Response('missing affinity', { status: 400 })
|
|
242
|
+
const pair = new WebSocketPair()
|
|
243
|
+
const client = pair[0]
|
|
244
|
+
const server = pair[1]
|
|
245
|
+
server.binaryType = 'arraybuffer'
|
|
246
|
+
let state = null
|
|
247
|
+
let ready = false
|
|
248
|
+
server.accept()
|
|
249
|
+
const loadState = readState(env, affinity).then((loadedState) => {
|
|
250
|
+
state = loadedState
|
|
251
|
+
ready = true
|
|
252
|
+
server.send(JSON.stringify({
|
|
253
|
+
protocol: 2,
|
|
254
|
+
type: 'ready',
|
|
255
|
+
state: state ? { hash: state.hash, revision: state.revision } : null,
|
|
256
|
+
}))
|
|
257
|
+
}).catch((error) => {
|
|
258
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
259
|
+
server.close(1011, 'state load failed')
|
|
260
|
+
})
|
|
261
|
+
ctx?.waitUntil?.(loadState)
|
|
262
|
+
if (!ctx?.waitUntil) void loadState
|
|
263
|
+
let busy = false
|
|
264
|
+
server.addEventListener('message', (event) => {
|
|
265
|
+
if (!ready) {
|
|
266
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 425, message: 'relay state is not ready' }))
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
if (busy) {
|
|
270
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 429, message: 'request already in flight' }))
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
let payload
|
|
274
|
+
try {
|
|
275
|
+
payload = JSON.parse(event.data)
|
|
276
|
+
} catch {
|
|
277
|
+
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 400, message: 'invalid JSON payload' }))
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
payload.affinity = affinity
|
|
281
|
+
busy = true
|
|
282
|
+
const run = handleWebSocket(server, env, ctx, payload, () => state, (nextState) => { state = nextState }).finally(() => { busy = false })
|
|
283
|
+
ctx?.waitUntil?.(run)
|
|
284
|
+
if (!ctx?.waitUntil) void run
|
|
285
|
+
})
|
|
286
|
+
return new Response(null, { status: 101, webSocket: client })
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (request.method === 'GET') {
|
|
290
|
+
return Response.json({ status: 'ok', transports: ['http', 'websocket'] })
|
|
291
|
+
}
|
|
292
|
+
if (request.method !== 'POST') return new Response('method not allowed', { status: 405 })
|
|
293
|
+
if (request.headers.get('x-relay-token') !== env.RELAY_TOKEN) {
|
|
294
|
+
return new Response('unauthorized', { status: 401 })
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const payload = await request.json()
|
|
299
|
+
const result = await handleRelayPayload(env, payload)
|
|
300
|
+
if (result.error) return Response.json({ error: result.error }, { status: result.status })
|
|
301
|
+
|
|
302
|
+
if (result.stateWrite) ctx.waitUntil(result.stateWrite)
|
|
303
|
+
|
|
304
|
+
const upstream = result.upstream
|
|
305
|
+
return new Response(upstream.body, {
|
|
306
|
+
status: upstream.status,
|
|
307
|
+
statusText: upstream.statusText,
|
|
308
|
+
headers: upstream.headers,
|
|
309
|
+
})
|
|
310
|
+
} catch (error) {
|
|
311
|
+
return Response.json(
|
|
312
|
+
{ error: error instanceof Error ? error.message : 'internal relay error' },
|
|
313
|
+
{ status: 502 },
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
}
|
|
318
|
+
`;var w$="claude-routing",hf=["main-first","fallback-first"],qf="main-first",p0="Usage: `/claude-routing`, `/claude-routing main-first`, or `/claude-routing fallback-first`.";function em(f){return typeof f==="string"&&hf.includes(f)?f:qf}function i$(f){return em(f?.routing?.mode)}async function R$(f,m=T()){let _=await z(m)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.routing={..._.routing??{},mode:f},await O(_,m),_}function f_(f){let m=f.trim().toLowerCase().split(/\s+/).filter(Boolean);if(m.length===0)return{type:"status"};if(m.length===1&&hf.includes(m[0]))return{type:"mode",mode:m[0]};if(m.length===2&&m[0]==="mode"&&hf.includes(m[1]))return{type:"mode",mode:m[1]};return{type:"usage"}}function m_(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 Vf(f){let m=f?.mode??qf;return["## Claude Routing Status","",`- Mode: \`${m}\``,`- Behavior: ${m_(m)}`,"",p0].join(`
|
|
319
|
+
`)}function k$(f){let m=f_(f.argumentsText),_=f.mode??qf;if(m.type==="status")return Vf({mode:_});if(m.type==="mode")return["## Claude Routing Updated","",`Mode updated to \`${m.mode}\`.`,"",...Vf({mode:m.mode}).split(`
|
|
320
|
+
`).slice(2)].join(`
|
|
321
|
+
`);return["## Claude Routing Usage","",p0,"",...Vf({mode:_}).split(`
|
|
322
|
+
`).slice(2)].join(`
|
|
323
|
+
`)}export{__ as a,kf as b,$_ as c,E_ as d,D_ as e,C_ as f,nf as g,M_ as h,H_ as i,Y as j,vf as k,K_ as l,j_ as m,L as n,T as o,z as p,O as q,X1 as r,z_ as s,V1 as t,O_ as u,Q_ as v,Z_ as w,X_ as x,Y_ as y,V_ as z,h_ as A,q_ as B,x_ as C,H0 as D,i1 as E,R as F,Nf as G,k as H,b0 as I,P_ as J,_0 as K,l1 as L,R_ as M,k_ as N,n_ as O,u_ as P,t1 as Q,c_ as R,B0 as S,e_ as T,d_ as U,v_ as V,t_ as W,U0 as X,$$ as Y,E$ as Z,Jm as _,Bf as $,W0 as aa,Bm as ba,D$ as ca,Tm as da,S$ as ea,K$ as fa,Vm as ga,j$ as ha,U$ as ia,G$ as ja,J$ as ka,wm as la,B$ as ma,T$ as na,L$ as oa,W$ as pa,Y$ as qa,V$ as ra,h$ as sa,q$ as ta,w$ as ua,i$ as va,R$ as wa,f_ as xa,k$ as ya};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{$ as
|
|
1
|
+
import{$ as A1,A as v1,B as F1,C as S0,D as $0,E as U1,F as p,G as E0,H as H1,I as C0,J as x1,K as A0,L as q1,M as G0,N as D0,O as V0,P as c,Q as S1,R as P0,S as K1,T as Z1,U as R0,V as $1,W as G1,X as D1,Y as X0,Z as E1,_ as C1,a as a0,aa as R1,b as r0,ba as T1,c as e,ca as f1,d as j0,da as y1,e as s0,ea as W0,f as n,fa as Y0,g as e0,ga as k1,h as j1,ha as T0,i as J1,ia as w0,j as v0,ja as g1,k as O1,ka as z0,l as F0,la as m1,m as U0,ma as f0,n as q,na as I0,oa as b1,p as C,pa as h1,q as H0,qa as d1,r as L1,s as K0,sa as u1,t as Z0,u as N1,ua as Q0,v as _1,va as y0,w as x0,wa as i1,x as B1,xa as n1,y as q0,ya as k0,z as M1}from"./index-ws2d5kxr.js";import{randomUUID as Oj}from"node:crypto";function b(j){return typeof j==="object"&&j!==null}function $j(j){if(Array.isArray(j))return j;if(b(j)&&Array.isArray(j.data))return j.data;return[]}function Gj(j){if(!b(j)||!b(j.info))return;return typeof j.info.role==="string"?j.info.role:void 0}function u0(j){if(!b(j)||!b(j.info))return null;let J=j.info,K=b(J.model)?J.model:void 0,G=typeof J.agent==="string"?J.agent:void 0,D=typeof K?.providerID==="string"?K.providerID:typeof J.providerID==="string"?J.providerID:void 0,V=typeof K?.modelID==="string"?K.modelID:typeof J.modelID==="string"?J.modelID:void 0,v=typeof K?.variant==="string"?K.variant:typeof J.variant==="string"?J.variant:void 0;if(!G&&(!D||!V)&&!v)return null;let R={};if(G)R.agent=G;if(D&&V)R.model={providerID:D,modelID:V};if(v)R.variant=v;return R}function i0(j,J){return{agent:j.agent??J.agent,model:j.model??J.model,variant:j.variant??J.variant}}function n0(j){return Boolean(j.agent&&j.model&&j.variant)}async function l0(j,J){if(!j||!J)return null;let K=j;if(typeof K.session?.messages!=="function")return null;let G=[];try{G=$j(await Promise.resolve(K.session.messages({path:{id:J},query:{limit:100}})))}catch{return null}if(G.length===0)return null;let D={};for(let V=G.length-1;V>=0;V--){if(Gj(G[V])!=="assistant")continue;let v=u0(G[V]);if(!v)continue;if(D=i0(D,v),n0(D))return D}for(let V=G.length-1;V>=0;V--){let v=u0(G[V]);if(!v)continue;if(D=i0(D,v),n0(D))return D}if(!D.agent&&!D.model&&!D.variant)return null;return D}function p0(j){return`${a0}${j.charAt(0).toUpperCase()}${j.slice(1)}`}function Dj(j){if(j==="StructuredOutput")return j;return`${j.charAt(0).toLowerCase()}${j.slice(1)}`}function V1(j,J){let K=new Headers;if(j instanceof Request)j.headers.forEach((D,V)=>{K.set(V,D)});let G=J?.headers;if(G){if(G instanceof Headers)G.forEach((D,V)=>{K.set(V,D)});else if(Array.isArray(G))for(let D of G){let[V,v]=D;if(typeof v<"u")K.set(V,String(v))}else for(let[D,V]of Object.entries(G))if(typeof V<"u")K.set(D,String(V))}return K}function M0(j){return j.set("anthropic-beta",e(j.get("anthropic-beta"),[r0])),j}function l(j,J,K={}){return G1(j,J,K)}function Vj(j){if(j.tools&&Array.isArray(j.tools))j.tools=j.tools.map((J)=>({...J,name:J.name?p0(J.name):J.name}));if(j.messages&&Array.isArray(j.messages))j.messages=j.messages.map((J)=>{if(J.content&&Array.isArray(J.content))J.content=J.content.map((K)=>{if(K.type==="tool_use"&&K.name)return{...K,name:p0(K.name)};return K});return J});return JSON.stringify(D1(j))}function _0(j){return j.replace(/"name"\s*:\s*"mcp_([^"]+)"/g,(J,K)=>`"name": "${Dj(K)}"`)}function c0(j,J=!1){if(J)return{ready:_0(j),pending:""};let K=j.length,G='"name"',D=Math.max(0,j.length-G.length+1);for(let v=D;v<j.length;v++)if(G.startsWith(j.slice(v))){K=Math.min(K,v);break}let V=j.lastIndexOf(G);if(V!==-1){let v=j.slice(V);if(/^"name"\s*(?::\s*(?:"[^"]*)?)?$/.test(v))K=Math.min(K,V)}if(K<j.length)return{ready:_0(j.slice(0,K)),pending:j.slice(K)};return{ready:_0(j),pending:""}}function P1(){if(!process.env.ANTHROPIC_BASE_URL?.trim())return!1;let j=process.env.ANTHROPIC_INSECURE?.trim();return j==="1"||j==="true"}function Pj(){let j=process.env.ANTHROPIC_BASE_URL?.trim();if(!j)return null;try{let J=new URL(j);if(J.protocol!=="http:"&&J.protocol!=="https:"||J.username||J.password)return null;return J}catch{return null}}function X1(j){let J=null;try{if(typeof j==="string"||j instanceof URL)J=new URL(j.toString());else if(j instanceof Request)J=new URL(j.url)}catch{J=null}if(!J)return{input:j,url:null};let K=J.href,G=Pj();if(G)J.protocol=G.protocol,J.host=G.host;if(J.pathname==="/v1/messages"&&!J.searchParams.has("beta"))J.searchParams.set("beta","true");if(J.href===K)return{input:j,url:J};return{input:j instanceof Request?new Request(J.toString(),j):J,url:J}}function a(j){let G=j.split(/\n\n+/).filter((D)=>{if(D.includes(s0))return!1;for(let V of j1)if(D.includes(V))return!1;return!0}).join(`
|
|
2
2
|
|
|
3
|
-
`);for(let D of s0)$=$.replace(D.match,D.replacement);return $.trim()}function C(j){return j!=null&&typeof j==="object"&&!Array.isArray(j)}function Zj(j){let J={type:"text",text:d};if(j==null)return[J];if(typeof j==="string"){let $=a(j);if($===d)return[J];return[J,{type:"text",text:$}]}if(C(j)){let $=typeof j.type==="string"?j.type:"text",D=typeof j.text==="string"?j.text:"";return[J,{...j,type:$,text:a(D)}]}if(!Array.isArray(j))return[J];let K=j.map(($)=>{if(typeof $==="string")return{type:"text",text:a($)};if(C($)&&$.type==="text"&&typeof $.text==="string")return{...$,type:"text",text:a($.text)};return{type:"text",text:String($)}});if(K[0]?.text===d)return K;return[J,...K]}var V1={type:"ephemeral",ttl:"1h"};function $j(j){if(C(j.cache_control))return j.cache_control;if(C(j.cacheControl))return j.cacheControl;return null}function s(j,J){if(!C(j))return!1;return delete j.cacheControl,j.cache_control=J?{...V1}:{type:"ephemeral"},!0}function n0(j){if(!C(j))return;delete j.cache_control,delete j.cacheControl}function Gj(j){if(Array.isArray(j))return j;if(typeof j==="string")return[{type:"text",text:j}];return null}function r(j,J){if(!C(j))return;let K=$j(j);if(!K||K.type!=="ephemeral")return;if(J)K.ttl="1h";else delete K.ttl}function p0(j,J){if(Array.isArray(j.system))for(let K of j.system)r(K,J);else r(j.system,J);if(!Array.isArray(j.messages))return;for(let K of j.messages)if(r(K,J),C(K)&&Array.isArray(K.content))for(let $ of K.content)r($,J)}function Dj(j,J){if(Array.isArray(j.system))for(let K of j.system)J(K);else J(j.system);if(!Array.isArray(j.messages))return;for(let K of j.messages)if(J(K),C(K)&&Array.isArray(K.content))for(let $ of K.content)J($)}function P1(j){n0(j),Dj(j,n0)}function Vj(j){P1(j),j.cache_control={...V1}}function L0(j){if(!C(j))return!1;let J=Gj(j.content);if(!J?.length)return s(j,!0);j.content=J;let K=[...J].reverse().find(($)=>C($)&&$.type!=="thinking");return s(K??j,!0)}function Pj(j){if(P1(j),Array.isArray(j.system)){let K=j.system.findIndex((V)=>C(V)&&V.text===d),$=j.system.slice(K>=0?K+1:0).filter(C),D=$[$.length-1];s(D,!0)}else s(j.system,!0);if(!Array.isArray(j.messages))return;L0(j.messages[0]),L0(j.messages[1]);let J=j.messages.length-2;if(J>1)L0(j.messages[J])}function Xj(j,J){if(!J.enabled){p0(j,!1),delete j.cache_control,delete j.cacheControl;return}if(J.mode==="automatic"){Vj(j);return}if(J.mode==="hybrid"){Pj(j);return}p0(j,!0),delete j.cacheControl}async function X1(j,J={}){try{let K=JSON.parse(j),$=Array.isArray(K.messages)&&K.messages.some((D)=>D.role==="user")?j1(K.messages,void 0,a0):null;if(K.system=Zj(K.system),$&&Array.isArray(K.system))K.system.unshift({type:"text",text:$});if(Xj(K,{enabled:J.cache1hEnabled??!1,mode:J.cache1hMode??"explicit"}),J.fastModeEnabled&&j0(K.model))K.speed="fast";else if(K.speed==="fast")delete K.speed;if(J.identity)J1(K,J.identity);return await e0(Jj(K))}catch{return j}}function _0(j){if(!j.body)return j;let J=j.body.getReader(),K=new TextDecoder,$=new TextEncoder,D="",V=new ReadableStream({async pull(B){let{done:E,value:y}=await J.read();if(E){let u=i0(`${D}${K.decode()}`,!0);if(u.ready)B.enqueue($.encode(u.ready));B.close();return}let O0=D+K.decode(y,{stream:!0}),h=i0(O0);if(D=h.pending,h.ready)B.enqueue($.encode(h.ready))}});return new Response(V,{status:j.status,statusText:j.statusText,headers:j.headers})}var Yj="__OPENCODE_ANTHROPIC_AUTH_COMMAND_HANDLED__",wj=60000,zj=60000,Ij=5000,W1=200,h1=240,Oj=h1,Qj=1,Y1=!1;function I0(){return process.env.OPENCODE_ANTHROPIC_AUTH_PERF==="1"}function M(){return performance.now()}function S(j){return Math.round(j*10)/10}function w1(j){return Math.floor(Math.random()*Math.max(0,j))}function Lj(){if(Y1||!1||!I0())return;Y1=!0;let j=100,J=250,K=M()+j;setInterval(()=>{let $=M(),D=$-K;if(K=$+j,D<J)return;U("[perf] opencode event_loop_lag",{lagMs:S(D),thresholdMs:J})},j).unref?.()}function Nj(j){let J=M(),K={requestId:String(Qj++),start:J,last:J,mark($,D){let V=M();if(I0())U("[perf] opencode request stage",{requestId:K.requestId,stage:$,deltaMs:S(V-K.last),totalMs:S(V-K.start),...D});K.last=V},done($,D){let V=M();if(I0())U("[perf] opencode request done",{requestId:K.requestId,stage:$,deltaMs:S(V-K.last),totalMs:S(V-K.start),...D});K.last=V}};if(I0())U("[perf] opencode request start",{requestId:K.requestId,...j});return K}async function i(j,J,K){let $=j.client.session,D=await d0(j.client,J),V={path:{id:J},body:{noReply:!0,parts:[{type:"text",text:K,ignored:!0}]}};if(D?.agent)V.body.agent=D.agent;if(D?.model)V.body.model=D.model;if(D?.variant)V.body.variant=D.variant;if(typeof $?.promptAsync==="function"){await $.promptAsync(V);return}if(typeof $?.prompt==="function"){await Promise.resolve($.prompt(V));return}throw Error("OpenCode session prompt API is unavailable for ignored replies.")}function n(){throw Error(Yj)}var qj=async(j)=>{Lj();let{client:J}=j,K=new U1;K.startBackgroundRefresh();let $=null,D=new R1({loadStorage:()=>A(),prepareHeaders:async(Z,Q)=>{if(!E)return Z;let W=await E();if(W.type!=="oauth")return Z;if(!W.access||W.expires&&W.expires<Date.now()){if(!$)return Z;W.access=await $()}if(!W.access)return Z;try{let N=JSON.parse(Q.bodyText),x=await E0(W.access,typeof N.model==="string"?N.model:void 0);if(Z.delete("anthropic-beta"),l(Z,W.access,{body:N,identity:x}),Z.set("anthropic-beta",e(Z.get("anthropic-beta"),[H1])),N.speed==="fast")N0(Z)}catch{l(Z,W.access)}return Z},log:U}),V=await A(),B=b1(V);c({enabled:J0(V),mode:K0(V)}),W0(U0(V)),w0(x0(V));let E=null,y=null;function O0(Z){let Q=Z?.refresh?.refreshBeforeExpiryMinutes??Oj;return Math.max(h1,Q)*60000}function h(Z){return Z?.refresh?.enabled!==!1}async function u(Z){if(!Z)return;let Q=await A(),W=Q?.refresh?.mainLastRefreshError;if(!Q?.refresh||!W?.tokenHash)return;let N=Z0(Z);if(W.tokenHash===N)return;if(W.nextRetryAt&&W.nextRetryAt>Date.now()){U("[refresh] opencode main oauth keeping backoff despite token rotation",{nextRetryAt:W.nextRetryAt,retryCount:W.retryCount,remainingMs:W.nextRetryAt-Date.now()});return}Q.refresh.mainLastRefreshError=void 0,await v0(Q),U("[refresh] opencode main oauth cleared stale backoff after token rotation",{previousCheckedAt:W.checkedAt,previousNextRetryAt:W.nextRetryAt,previousRetryCount:W.retryCount})}async function u1(){let Z=[];if(E)try{let N=await E();if(N.type==="oauth"&&N.access)Z.push({name:"OpenCode anthropic",role:"main",quota:await A0({accessToken:N.access})});else if(N.type==="oauth")Z.push({name:"OpenCode anthropic",role:"main",error:"missing access token; send a request first or reconnect auth"})}catch(N){Z.push({name:"OpenCode anthropic",role:"main",error:N instanceof Error?N.message:String(N)})}let{storage:Q,errors:W}=await K.refreshQuotaForAllAccounts();if(Z.push(...k1(Q,new Map(W.map((N)=>[N.accountId,N.message])))),!E)Z.unshift({name:"OpenCode anthropic",role:"main",error:"auth loader has not run yet; send a request first"});return g1({accounts:Z,refreshedAt:Date.now()})}async function d1(Z){let Q=x1(Z);if(Q.type==="enable"||Q.type==="disable"){let f=Q.type==="enable",k=await O1(f),g=K0(k);return c({enabled:f,mode:g}),V0({argumentsText:Z,enabled:f,mode:g})}if(Q.type==="mode"){let f=await Q1(Q.mode),k=J0(f);return c({enabled:k,mode:Q.mode}),V0({argumentsText:Z,enabled:k,mode:Q.mode})}let W=await A(),N=J0(W),x=K0(W);return c({enabled:N,mode:x}),V0({argumentsText:Z,enabled:N,mode:x})}async function l1(Z){let Q=q1(Z),W=await A();if(Q.type==="window")W=await _1(Q.startHour,Q.endHour);else if(Q.type==="disable")W=await F1(!1);let N=S1(W),x=D.stats(N);return C1({argumentsText:Z,enabled:A1(W),window:N,hybridActive:E1(W),trackedSessions:x.trackedSessions,nextPrewarmAt:x.nextPrewarmAt})}async function i1(Z){let Q=T1(Z);if(Q.type==="enable"||Q.type==="disable"){let x=Q.type==="enable";return await L1(x),W0(x),C0({argumentsText:Z,enabled:x})}let W=await A(),N=U0(W);return W0(N),C0({argumentsText:Z,enabled:N})}async function n1(Z){let Q=y1(Z);if(Q.type==="enable"||Q.type==="disable"){let x=Q.type==="enable";return await N1(x),w0(x),R0({argumentsText:Z,enabled:x})}let W=await A(),N=x0(W);return w0(N),R0({argumentsText:Z,enabled:N})}return{config:async(Z)=>{Z.command={...Z.command??{},[$0]:{template:$0,description:"Show or toggle 1-hour Anthropic ephemeral prompt cache TTL."},[P0]:{template:P0,description:"Keep hybrid Claude cache warm for recently used sessions during a local time window."},[z0]:{template:z0,description:"Show current Claude OAuth quota usage for all accounts."},[X0]:{template:X0,description:"Show or toggle Anthropic request dump capture for debugging."},[Y0]:{template:Y0,description:"Show or toggle Anthropic fast mode for supported Opus models."}}},"command.execute.before":async(Z)=>{if(Z.command===$0)await i(j,Z.sessionID,await d1(Z.arguments)),n();if(Z.command===P0)await i(j,Z.sessionID,await l1(Z.arguments)),n();if(Z.command===z0)await i(j,Z.sessionID,await u1()),n();if(Z.command===X0)await i(j,Z.sessionID,await i1(Z.arguments)),n();if(Z.command===Y0)await i(j,Z.sessionID,await n1(Z.arguments)),n()},auth:{provider:"anthropic",async loader(Z,Q){if(E=Z,(await Z()).type==="oauth"){let p1=function(){if(y)clearInterval(y),y=null;let P=async()=>{try{let X=await A();if(!h(X))return;let z=await Z();if(z.type!=="oauth")return;if(await u(z.refresh),!z.expires)return;let I=z.expires-Date.now(),v=O0(X);if(I>v)return;if(U("[refresh] opencode main oauth background due",{expiresInMs:I,refreshBeforeMs:v}),z.refresh&&p(X?.refresh?.mainLastRefreshError,z.refresh,Date.now())){U("[refresh] opencode main oauth background skipped backoff",{nextRetryAt:X?.refresh?.mainLastRefreshError?.nextRetryAt,retryCount:X?.refresh?.mainLastRefreshError?.retryCount,expiresInMs:I});return}if(z.refresh&&X?.refresh?.mainRefreshLeaseUntil&&X.refresh.mainRefreshLeaseUntil>Date.now()&&X.refresh.mainRefreshLeaseTokenHash===Z0(z.refresh))return;await g();let O=await Z();U("[refresh] opencode main oauth refreshed in background",{newExpiresInMs:O.expires?O.expires-Date.now():void 0})}catch(X){U("[refresh] opencode main oauth refresh failed",{message:X instanceof Error?X.message:String(X)})}};if(y=setInterval(()=>{P()},wj+w1(zj)),"unref"in y)y.unref()},T0=function(P,X){if(P instanceof Request&&P.body)return!1;return X==null||typeof X==="string"},c1=function(P){return P.has("x-parent-session-id")},f0=function(P){return P.includes("rate_limit_error")||/exceed your account'?s rate limit/i.test(P)},o1=function(P){return P?.quota?.enabled===!0},t1=function(P,X){let z=Date.now();if(f||z<k)return;f=g0(P,X).catch((I)=>{throw k=z+M1(X),I}).finally(()=>{f=null}),f.catch(()=>{})};for(let P of Object.values(Q.models))P.cost={input:0,output:0,cache:{read:0,write:0}};let N=null,x=null,f=null,k=0;async function g(){if(!N)N=(async()=>{let z=null,I=null,v=null;async function O(L){let Y=await A()??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};Y.refresh=Y.refresh??{},L(Y),await v0(Y)}async function F(L){let Y=Date.now()+Ij;while(Date.now()<Y){await new Promise((w)=>setTimeout(w,W1+w1(W1)));let G=await Z();if(G.type!=="oauth"||!G.access)continue;if((G.access!==L.access||G.refresh!==L.refresh||(G.expires??0)>(L.expires??0)+60000)&&(!G.expires||G.expires>Date.now()))return U("[refresh] opencode main oauth joined concurrent refresh",{expiresInMs:G.expires?G.expires-Date.now():void 0}),G.access}return null}for(let L=0;L<=2;L++){let Y=null;try{if(L>0){let H=500*2**(L-1);await new Promise((o)=>setTimeout(o,H))}if(Y=await Z(),!Y.refresh)throw Error("Token refresh failed: missing refresh token");let G=await A(),_=Z0(Y.refresh),w=G?.refresh?.mainLastRefreshError;if(U("[refresh] opencode main oauth refresh check",{attempt:L,expiresInMs:Y.expires?Y.expires-Date.now():void 0,hasBackoff:Boolean(w),backoffActive:w?p(w,Y.refresh,Date.now()):!1,retryCount:w?.retryCount,nextRetryAt:w?.nextRetryAt}),w&&p(w,Y.refresh,Date.now()))throw U("[refresh] opencode main oauth refresh skipped backoff",{nextRetryAt:w.nextRetryAt,retryCount:w.retryCount}),Error(q0(w,Date.now()));if(G?.refresh?.mainRefreshLeaseUntil&&G.refresh.mainRefreshLeaseUntil>Date.now()&&G.refresh.mainRefreshLeaseTokenHash===_){U("[refresh] opencode main oauth refresh skipped lease",{leaseUntil:G.refresh.mainRefreshLeaseUntil});let H=await F(Y);if(H)return H;throw Error("Claude OAuth refresh is already in progress")}let q=await I1({name:"opencode-main-oauth-refresh",ttlMs:120000});if(!q){U("[refresh] opencode main oauth refresh skipped file lock");let H=await F(Y);if(H)return H;throw Error("Claude OAuth refresh is already in progress")}v=q.release,z=Wj(),I=_,await O((H)=>{H.refresh=H.refresh??{},H.refresh.mainRefreshLeaseId=z??void 0,H.refresh.mainRefreshLeaseUntil=Date.now()+120000,H.refresh.mainRefreshLeaseTokenHash=_});let R=await A();if(U("[refresh] opencode main oauth refresh lease acquired",{attempt:L,leaseUntil:Date.now()+120000}),R?.refresh?.mainRefreshLeaseId!==z||R.refresh.mainRefreshLeaseTokenHash!==_)throw Error("Claude OAuth refresh is already in progress");U("[refresh] opencode main oauth refresh request start",{attempt:L});let T=await z1({refreshToken:Y.refresh,maxRetries:0});return await J.auth.set({path:{id:"anthropic"},body:{type:"oauth",refresh:T.refresh,access:T.access,expires:T.expires}}),await O((H)=>{if(!H?.refresh)return;if(H.refresh.mainLastRefreshError=void 0,H.refresh.mainRefreshLeaseId===z)H.refresh.mainRefreshLeaseId=void 0,H.refresh.mainRefreshLeaseUntil=void 0,H.refresh.mainRefreshLeaseTokenHash=void 0}),U("[refresh] opencode main oauth refresh succeeded",{attempt:L,expiresInMs:T.expires-Date.now()}),T.access}catch(G){let _=G instanceof Error&&(G.message.includes("fetch failed")||("code"in G)&&(G.code==="ECONNRESET"||G.code==="ECONNREFUSED"||G.code==="ETIMEDOUT"||G.code==="UND_ERR_CONNECT_TIMEOUT"));if(L<2&&(_||G instanceof F0&&G.status>=500))continue;U("[refresh] opencode main oauth refresh attempt failed",{attempt:L,error:G instanceof Error?G.message:String(G),transient:_});let w=Y?.refresh;if(w&&G instanceof F0)await O((q)=>{q.refresh=q.refresh??{},q.refresh.mainLastRefreshError=B1({error:G,now:Date.now(),refreshToken:w,previous:q.refresh.mainLastRefreshError})});throw G}finally{if(z)await O((G)=>{if(!G?.refresh)return;if(G.refresh.mainRefreshLeaseId===z&&G.refresh.mainRefreshLeaseTokenHash===I)G.refresh.mainRefreshLeaseId=void 0,G.refresh.mainRefreshLeaseUntil=void 0,G.refresh.mainRefreshLeaseTokenHash=void 0}).catch(()=>{});await v?.().catch(()=>{})}}throw Error("Token refresh exhausted all retries")})().finally(()=>{N=null});return N}$=g,p1();async function y0(P,X){if(!P.body||P.status!==200)return X?.mark("inspect_stream_skip",{status:P.status}),{response:P,rateLimited:!1};if(P.headers.get("x-cortexkit-relay-optimistic")==="true")return X?.mark("inspect_stream_skip",{status:P.status,reason:"optimistic_relay"}),{response:P,rateLimited:!1};let z=M(),I=P.body.getReader(),v=[],O=new TextDecoder,F="",L=0;while(!F.includes(`
|
|
3
|
+
`);for(let D of J1)G=G.replace(D.match,D.replacement);return G.trim()}function T(j){return j!=null&&typeof j==="object"&&!Array.isArray(j)}function Xj(j){let J={type:"text",text:n};if(j==null)return[J];if(typeof j==="string"){let G=a(j);if(G===n)return[J];return[J,{type:"text",text:G}]}if(T(j)){let G=typeof j.type==="string"?j.type:"text",D=typeof j.text==="string"?j.text:"";return[J,{...j,type:G,text:a(D)}]}if(!Array.isArray(j))return[J];let K=j.map((G)=>{if(typeof G==="string")return{type:"text",text:a(G)};if(T(G)&&G.type==="text"&&typeof G.text==="string")return{...G,type:"text",text:a(G.text)};return{type:"text",text:String(G)}});if(K[0]?.text===n)return K;return[J,...K]}var W1={type:"ephemeral",ttl:"1h"};function Wj(j){if(T(j.cache_control))return j.cache_control;if(T(j.cacheControl))return j.cacheControl;return null}function s(j,J){if(!T(j))return!1;return delete j.cacheControl,j.cache_control=J?{...W1}:{type:"ephemeral"},!0}function o0(j){if(!T(j))return;delete j.cache_control,delete j.cacheControl}function Yj(j){if(Array.isArray(j))return j;if(typeof j==="string")return[{type:"text",text:j}];return null}function r(j,J){if(!T(j))return;let K=Wj(j);if(!K||K.type!=="ephemeral")return;if(J)K.ttl="1h";else delete K.ttl}function t0(j,J){if(Array.isArray(j.system))for(let K of j.system)r(K,J);else r(j.system,J);if(!Array.isArray(j.messages))return;for(let K of j.messages)if(r(K,J),T(K)&&Array.isArray(K.content))for(let G of K.content)r(G,J)}function wj(j,J){if(Array.isArray(j.system))for(let K of j.system)J(K);else J(j.system);if(!Array.isArray(j.messages))return;for(let K of j.messages)if(J(K),T(K)&&Array.isArray(K.content))for(let G of K.content)J(G)}function Y1(j){o0(j),wj(j,o0)}function zj(j){Y1(j),j.cache_control={...W1}}function B0(j){if(!T(j))return!1;let J=Yj(j.content);if(!J?.length)return s(j,!0);j.content=J;let K=[...J].reverse().find((G)=>T(G)&&G.type!=="thinking");return s(K??j,!0)}function Ij(j){if(Y1(j),Array.isArray(j.system)){let K=j.system.findIndex((V)=>T(V)&&V.text===n),G=j.system.slice(K>=0?K+1:0).filter(T),D=G[G.length-1];s(D,!0)}else s(j.system,!0);if(!Array.isArray(j.messages))return;B0(j.messages[0]),B0(j.messages[1]);let J=j.messages.length-2;if(J>1)B0(j.messages[J])}function Qj(j,J){if(!J.enabled){t0(j,!1),delete j.cache_control,delete j.cacheControl;return}if(J.mode==="automatic"){zj(j);return}if(J.mode==="hybrid"){Ij(j);return}t0(j,!0),delete j.cacheControl}async function w1(j,J={}){try{let K=JSON.parse(j),G=Array.isArray(K.messages)&&K.messages.some((D)=>D.role==="user")?Z1(K.messages,void 0,e0):null;if(K.system=Xj(K.system),G&&Array.isArray(K.system))K.system.unshift({type:"text",text:G});if(Qj(K,{enabled:J.cache1hEnabled??!1,mode:J.cache1hMode??"explicit"}),J.fastModeEnabled&&j0(K.model))K.speed="fast";else if(K.speed==="fast")delete K.speed;if(J.identity)$1(K,J.identity);return await K1(Vj(K))}catch{return j}}function J0(j){if(!j.body)return j;let J=j.body.getReader(),K=new TextDecoder,G=new TextEncoder,D="",V=new ReadableStream({async pull(v){let{done:R,value:y}=await J.read();if(R){let i=c0(`${D}${K.decode()}`,!0);if(i.ready)v.enqueue(G.encode(i.ready));v.close();return}let L0=D+K.decode(y,{stream:!0}),u=c0(L0);if(D=u.pending,u.ready)v.enqueue(G.encode(u.ready))}});return new Response(V,{status:j.status,statusText:j.statusText,headers:j.headers})}var Lj="__OPENCODE_ANTHROPIC_AUTH_COMMAND_HANDLED__",Nj=60000,_j=60000,Bj=5000,z1=200,l1=240,Mj=l1,vj=1,I1=!1;function O0(){return process.env.OPENCODE_ANTHROPIC_AUTH_PERF==="1"}function B(){return performance.now()}function E(j){return Math.round(j*10)/10}function Q1(j){return Math.floor(Math.random()*Math.max(0,j))}function Fj(){if(I1||!1||!O0())return;I1=!0;let j=100,J=250,K=B()+j;setInterval(()=>{let G=B(),D=G-K;if(K=G+j,D<J)return;q("[perf] opencode event_loop_lag",{lagMs:E(D),thresholdMs:J})},j).unref?.()}function Uj(j){let J=B(),K={requestId:String(vj++),start:J,last:J,mark(G,D){let V=B();if(O0())q("[perf] opencode request stage",{requestId:K.requestId,stage:G,deltaMs:E(V-K.last),totalMs:E(V-K.start),...D});K.last=V},done(G,D){let V=B();if(O0())q("[perf] opencode request done",{requestId:K.requestId,stage:G,deltaMs:E(V-K.last),totalMs:E(V-K.start),...D});K.last=V}};if(O0())q("[perf] opencode request start",{requestId:K.requestId,...j});return K}async function h(j,J,K){let G=j.client.session,D=await l0(j.client,J),V={path:{id:J},body:{noReply:!0,parts:[{type:"text",text:K,ignored:!0}]}};if(D?.agent)V.body.agent=D.agent;if(D?.model)V.body.model=D.model;if(D?.variant)V.body.variant=D.variant;if(typeof G?.promptAsync==="function"){await G.promptAsync(V);return}if(typeof G?.prompt==="function"){await Promise.resolve(G.prompt(V));return}throw Error("OpenCode session prompt API is unavailable for ignored replies.")}function d(){throw Error(Lj)}var Tj=async(j)=>{Fj();let{client:J}=j,K=new q1;K.startBackgroundRefresh();let G=null,D=new y1({loadStorage:()=>C(),prepareHeaders:async(Z,w)=>{if(!R)return Z;let Y=await R();if(Y.type!=="oauth")return Z;if(!Y.access||Y.expires&&Y.expires<Date.now()){if(!G)return Z;Y.access=await G()}if(!Y.access)return Z;try{let L=JSON.parse(w.bodyText),S=await R0(Y.access,typeof L.model==="string"?L.model:void 0);if(Z.delete("anthropic-beta"),l(Z,Y.access,{body:L,identity:S}),Z.set("anthropic-beta",e(Z.get("anthropic-beta"),[E1])),L.speed==="fast")M0(Z)}catch{l(Z,Y.access)}return Z},log:q}),V=await C(),v=d1(V);c({enabled:K0(V),mode:Z0(V)}),Y0(x0(V)),z0(q0(V));let R=null,y=null;function L0(Z){let w=Z?.refresh?.refreshBeforeExpiryMinutes??Mj;return Math.max(l1,w)*60000}function u(Z){return Z?.refresh?.enabled!==!1}async function i(Z){if(!Z)return;let w=await C(),Y=w?.refresh?.mainLastRefreshError;if(!w?.refresh||!Y?.tokenHash)return;let L=$0(Z);if(Y.tokenHash===L)return;if(Y.nextRetryAt&&Y.nextRetryAt>Date.now()){q("[refresh] opencode main oauth keeping backoff despite token rotation",{nextRetryAt:Y.nextRetryAt,retryCount:Y.retryCount,remainingMs:Y.nextRetryAt-Date.now()});return}w.refresh.mainLastRefreshError=void 0,await H0(w),q("[refresh] opencode main oauth cleared stale backoff after token rotation",{previousCheckedAt:Y.checkedAt,previousNextRetryAt:Y.nextRetryAt,previousRetryCount:Y.retryCount})}async function p1(){let Z=[];if(R)try{let L=await R();if(L.type==="oauth"&&L.access)Z.push({name:"OpenCode anthropic",role:"main",quota:await A0({accessToken:L.access})});else if(L.type==="oauth")Z.push({name:"OpenCode anthropic",role:"main",error:"missing access token; send a request first or reconnect auth"})}catch(L){Z.push({name:"OpenCode anthropic",role:"main",error:L instanceof Error?L.message:String(L)})}let{storage:w,errors:Y}=await K.refreshQuotaForAllAccounts();if(Z.push(...b1(w,new Map(Y.map((L)=>[L.accountId,L.message])))),!R)Z.unshift({name:"OpenCode anthropic",role:"main",error:"auth loader has not run yet; send a request first"});return h1({accounts:Z,refreshedAt:Date.now()})}async function c1(Z){let w=S1(Z);if(w.type==="enable"||w.type==="disable"){let f=w.type==="enable",k=await N1(f),g=Z0(k);return c({enabled:f,mode:g}),P0({argumentsText:Z,enabled:f,mode:g})}if(w.type==="mode"){let f=await _1(w.mode),k=K0(f);return c({enabled:k,mode:w.mode}),P0({argumentsText:Z,enabled:k,mode:w.mode})}let Y=await C(),L=K0(Y),S=Z0(Y);return c({enabled:L,mode:S}),P0({argumentsText:Z,enabled:L,mode:S})}async function o1(Z){let w=C1(Z),Y=await C();if(w.type==="window")Y=await v1(w.startHour,w.endHour);else if(w.type==="disable")Y=await F1(!1);let L=A1(Y),S=D.stats(L);return f1({argumentsText:Z,enabled:R1(Y),window:L,hybridActive:T1(Y),trackedSessions:S.trackedSessions,nextPrewarmAt:S.nextPrewarmAt})}async function t1(Z){let w=k1(Z);if(w.type==="enable"||w.type==="disable"){let S=w.type==="enable";return await B1(S),Y0(S),T0({argumentsText:Z,enabled:S})}let Y=await C(),L=x0(Y);return Y0(L),T0({argumentsText:Z,enabled:L})}async function a1(Z){let w=m1(Z);if(w.type==="enable"||w.type==="disable"){let S=w.type==="enable";return await M1(S),z0(S),f0({argumentsText:Z,enabled:S})}let Y=await C(),L=q0(Y);return z0(L),f0({argumentsText:Z,enabled:L})}async function r1(Z){let w=n1(Z);if(w.type==="mode")return await i1(w.mode),k0({argumentsText:Z,mode:w.mode});let Y=await C();return k0({argumentsText:Z,mode:y0(Y)})}return{config:async(Z)=>{Z.command={...Z.command??{},[G0]:{template:G0,description:"Show or toggle 1-hour Anthropic ephemeral prompt cache TTL."},[X0]:{template:X0,description:"Keep hybrid Claude cache warm for recently used sessions during a local time window."},[I0]:{template:I0,description:"Show current Claude OAuth quota usage for all accounts."},[W0]:{template:W0,description:"Show or toggle Anthropic request dump capture for debugging."},[w0]:{template:w0,description:"Show or toggle Anthropic fast mode for supported Opus models."},[Q0]:{template:Q0,description:"Show or change Claude account routing between main-first and fallback-first."}}},"command.execute.before":async(Z)=>{if(Z.command===G0)await h(j,Z.sessionID,await c1(Z.arguments)),d();if(Z.command===X0)await h(j,Z.sessionID,await o1(Z.arguments)),d();if(Z.command===I0)await h(j,Z.sessionID,await p1()),d();if(Z.command===W0)await h(j,Z.sessionID,await t1(Z.arguments)),d();if(Z.command===w0)await h(j,Z.sessionID,await a1(Z.arguments)),d();if(Z.command===Q0)await h(j,Z.sessionID,await r1(Z.arguments)),d()},auth:{provider:"anthropic",async loader(Z,w){if(R=Z,(await Z()).type==="oauth"){let s1=function(){if(y)clearInterval(y),y=null;let P=async()=>{try{let X=await C();if(!u(X))return;let I=await Z();if(I.type!=="oauth")return;if(await i(I.refresh),!I.expires)return;let W=I.expires-Date.now(),x=L0(X);if(W>x)return;if(q("[refresh] opencode main oauth background due",{expiresInMs:W,refreshBeforeMs:x}),I.refresh&&p(X?.refresh?.mainLastRefreshError,I.refresh,Date.now())){q("[refresh] opencode main oauth background skipped backoff",{nextRetryAt:X?.refresh?.mainLastRefreshError?.nextRetryAt,retryCount:X?.refresh?.mainLastRefreshError?.retryCount,expiresInMs:W});return}if(I.refresh&&X?.refresh?.mainRefreshLeaseUntil&&X.refresh.mainRefreshLeaseUntil>Date.now()&&X.refresh.mainRefreshLeaseTokenHash===$0(I.refresh))return;await g();let Q=await Z();q("[refresh] opencode main oauth refreshed in background",{newExpiresInMs:Q.expires?Q.expires-Date.now():void 0})}catch(X){q("[refresh] opencode main oauth refresh failed",{message:X instanceof Error?X.message:String(X)})}};if(y=setInterval(()=>{P()},Nj+Q1(_j)),"unref"in y)y.unref()},g0=function(P,X){if(P instanceof Request&&P.body)return!1;return X==null||typeof X==="string"},e1=function(P){return P.has("x-parent-session-id")},m0=function(P){return P.includes("rate_limit_error")||/exceed your account'?s rate limit/i.test(P)},jj=function(P){return P?.quota?.enabled===!0},Jj=function(P,X){let I=Date.now();if(f||I<k)return;f=d0(P,X).catch((W)=>{throw k=I+H1(X),W}).finally(()=>{f=null}),f.catch(()=>{})};for(let P of Object.values(w.models))P.cost={input:0,output:0,cache:{read:0,write:0}};let L=null,S=null,f=null,k=0;async function g(){if(!L)L=(async()=>{let I=null,W=null,x=null;async function Q(z){let O=await C()??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};O.refresh=O.refresh??{},z(O),await H0(O)}async function F(z){let O=Date.now()+Bj;while(Date.now()<O){await new Promise((_)=>setTimeout(_,z1+Q1(z1)));let $=await Z();if($.type!=="oauth"||!$.access)continue;if(($.access!==z.access||$.refresh!==z.refresh||($.expires??0)>(z.expires??0)+60000)&&(!$.expires||$.expires>Date.now()))return q("[refresh] opencode main oauth joined concurrent refresh",{expiresInMs:$.expires?$.expires-Date.now():void 0}),$.access}return null}for(let z=0;z<=2;z++){let O=null;try{if(z>0){let U=500*2**(z-1);await new Promise((o)=>setTimeout(o,U))}if(O=await Z(),!O.refresh)throw Error("Token refresh failed: missing refresh token");let $=await C(),M=$0(O.refresh),_=$?.refresh?.mainLastRefreshError;if(q("[refresh] opencode main oauth refresh check",{attempt:z,expiresInMs:O.expires?O.expires-Date.now():void 0,hasBackoff:Boolean(_),backoffActive:_?p(_,O.refresh,Date.now()):!1,retryCount:_?.retryCount,nextRetryAt:_?.nextRetryAt}),_&&p(_,O.refresh,Date.now()))throw q("[refresh] opencode main oauth refresh skipped backoff",{nextRetryAt:_.nextRetryAt,retryCount:_.retryCount}),Error(E0(_,Date.now()));if($?.refresh?.mainRefreshLeaseUntil&&$.refresh.mainRefreshLeaseUntil>Date.now()&&$.refresh.mainRefreshLeaseTokenHash===M){q("[refresh] opencode main oauth refresh skipped lease",{leaseUntil:$.refresh.mainRefreshLeaseUntil});let U=await F(O);if(U)return U;throw Error("Claude OAuth refresh is already in progress")}let N=await L1({name:"opencode-main-oauth-refresh",ttlMs:120000});if(!N){q("[refresh] opencode main oauth refresh skipped file lock");let U=await F(O);if(U)return U;throw Error("Claude OAuth refresh is already in progress")}x=N.release,I=Oj(),W=M,await Q((U)=>{U.refresh=U.refresh??{},U.refresh.mainRefreshLeaseId=I??void 0,U.refresh.mainRefreshLeaseUntil=Date.now()+120000,U.refresh.mainRefreshLeaseTokenHash=M});let H=await C();if(q("[refresh] opencode main oauth refresh lease acquired",{attempt:z,leaseUntil:Date.now()+120000}),H?.refresh?.mainRefreshLeaseId!==I||H.refresh.mainRefreshLeaseTokenHash!==M)throw Error("Claude OAuth refresh is already in progress");q("[refresh] opencode main oauth refresh request start",{attempt:z});let A=await O1({refreshToken:O.refresh,maxRetries:0});return await J.auth.set({path:{id:"anthropic"},body:{type:"oauth",refresh:A.refresh,access:A.access,expires:A.expires}}),await Q((U)=>{if(!U?.refresh)return;if(U.refresh.mainLastRefreshError=void 0,U.refresh.mainRefreshLeaseId===I)U.refresh.mainRefreshLeaseId=void 0,U.refresh.mainRefreshLeaseUntil=void 0,U.refresh.mainRefreshLeaseTokenHash=void 0}),q("[refresh] opencode main oauth refresh succeeded",{attempt:z,expiresInMs:A.expires-Date.now()}),A.access}catch($){let M=$ instanceof Error&&($.message.includes("fetch failed")||("code"in $)&&($.code==="ECONNRESET"||$.code==="ECONNREFUSED"||$.code==="ETIMEDOUT"||$.code==="UND_ERR_CONNECT_TIMEOUT"));if(z<2&&(M||$ instanceof v0&&$.status>=500))continue;q("[refresh] opencode main oauth refresh attempt failed",{attempt:z,error:$ instanceof Error?$.message:String($),transient:M});let _=O?.refresh;if(_&&$ instanceof v0)await Q((N)=>{N.refresh=N.refresh??{},N.refresh.mainLastRefreshError=U1({error:$,now:Date.now(),refreshToken:_,previous:N.refresh.mainLastRefreshError})});throw $}finally{if(I)await Q(($)=>{if(!$?.refresh)return;if($.refresh.mainRefreshLeaseId===I&&$.refresh.mainRefreshLeaseTokenHash===W)$.refresh.mainRefreshLeaseId=void 0,$.refresh.mainRefreshLeaseUntil=void 0,$.refresh.mainRefreshLeaseTokenHash=void 0}).catch(()=>{});await x?.().catch(()=>{})}}throw Error("Token refresh exhausted all retries")})().finally(()=>{L=null});return L}G=g,s1();async function b0(P,X){if(!P.body||P.status!==200)return X?.mark("inspect_stream_skip",{status:P.status}),{response:P,rateLimited:!1};if(P.headers.get("x-cortexkit-relay-optimistic")==="true")return X?.mark("inspect_stream_skip",{status:P.status,reason:"optimistic_relay"}),{response:P,rateLimited:!1};let I=B(),W=P.body.getReader(),x=[],Q=new TextDecoder,F="",z=0;while(!F.includes(`
|
|
4
4
|
|
|
5
|
-
`)&&F.length<65536){let{done
|
|
5
|
+
`)&&F.length<65536){let{done:$,value:M}=await W.read();if($)break;if(x.push(M),z+=M.byteLength,F+=Q.decode(M,{stream:!0}),m0(F))break}if(m0(F))return await W.cancel().catch(()=>{}),X?.mark("inspect_stream_first_event",{ms:E(B()-I),bytes:z,rateLimited:!0}),{response:P,rateLimited:!0};let O=new ReadableStream({start($){for(let M of x)$.enqueue(M)},async pull($){let{done:M,value:_}=await W.read();if(M){$.close();return}$.enqueue(_)},cancel($){return W.cancel($)}});return X?.mark("inspect_stream_first_event",{ms:E(B()-I),bytes:z,rateLimited:!1}),{response:new Response(O,{status:P.status,statusText:P.statusText,headers:P.headers}),rateLimited:!1}}async function h0(P,X,I,W,x="unknown"){let Q=B(),F=V1(P,X),z=F.get("x-session-affinity")||F.get("x-opencode-session"),O=e1(F);F.delete("x-parent-session-id"),F.delete("x-session-affinity"),F.delete("x-opencode-session");let $=X?.body,M;if($&&typeof $==="string")try{let m=JSON.parse($);if(typeof m.model==="string")M=m.model}catch{}let _=await R0(I,M),N=typeof $==="string"?$.length:void 0;if($&&typeof $==="string"){let m=B(),t=(()=>{if(!g1())return!1;try{return j0(JSON.parse($).model)}catch{return!1}})();$=await w1($,{cache1hEnabled:!O&&D0(),cache1hMode:V0(),fastModeEnabled:t,identity:_});try{l(F,I,{body:JSON.parse($),identity:_})}catch{l(F,I,{identity:_})}if(t)M0(F);W?.mark("rewrite_body",{route:x,ms:E(B()-m),originalBytes:N,rewrittenBytes:$.length,cacheEnabled:!O&&D0(),cacheMode:V0(),fastModeEnabled:t,subagent:O})}let H=X1(P);if(x==="main"&&typeof $==="string"&&!O&&D0()&&V0()==="hybrid"){let m=await C();if((await D.track({sessionId:z,url:H.url?.toString()??H.input.toString(),headers:F,bodyText:$,storage:m,cacheMode:"hybrid"})).tracked)W?.mark("cachekeep_track",{session:z})}let A=()=>fetch(H.input,{...X,body:$,headers:F,...P1()&&{tls:{rejectUnauthorized:!1}}}),U=B(),o=await u1({config:v,input:H.input,init:X,headers:F,body:$,fallback:A,affinity:z,optimisticResponse:v?.transport==="websocket"});return W?.mark("send_headers_received",{route:x,ms:E(B()-U),status:o.status,relayConfigured:v!=null,totalSendWithAccessMs:E(B()-Q)}),o}async function d0(P,X){let I=Date.now(),W=await A0({accessToken:P});return S={accessToken:P,refreshAfter:x1(W,X,I),quota:W},W}async function Kj(P,X){let I=Date.now();if(S?.accessToken!==P)return await d0(P,X);if(I>=S.refreshAfter)Jj(P,X);return S.quota}async function N0(P,X,I,W,x,Q,F){if(!I.length)return x??null;let z=F?.returnLastOnExhausted??!0;await x?.body?.cancel().catch(()=>{});let O=x??null;for(let[$,M]of I.entries()){let _=M.access;if(!_)continue;let N=await h0(P,X,_,Q,`fallback_${$}`);O=N;let H=S0(N.status,W);if(!H){let A=await b0(N,Q);N=A.response,O=N,H=A.rateLimited}if(!H)return await K.markUsed(M),N;if($<I.length-1||!z)await N.body?.cancel().catch(()=>{})}return z?O:null}async function Zj(P,X,I,W,x,Q){if(!g0(P,X?.body))return I;let F=B(),z=Q??await C();x?.mark("fallback_load_storage",{ms:E(B()-F),cached:!!Q});let O=I,$=S0(O.status,z);if(!$){let _=await b0(O,x);O=_.response,$=_.rateLimited}if(!$)return O;let M=W;if(!M){let _=B();M=await K.getUsableFallbackAccounts(),x?.mark("fallback_get_accounts",{ms:E(B()-_),accounts:M.length})}return await N0(P,X,M,z,O,x)??O}return{apiKey:"",async fetch(P,X){let I=X?.body,W=Uj({bodyBytes:typeof I==="string"?I.length:void 0,relayConfigured:v!=null}),x=B(),Q=await Z();if(W.mark("get_auth",{ms:E(B()-x),authType:Q.type,hasAccess:Boolean(Q.access)}),Q.type!=="oauth"){let N=await fetch(P,X);return W.done("non_oauth_passthrough",{status:N.status}),N}await i(Q.refresh);let F=B(),z=await C();W.mark("load_storage",{ms:E(B()-F)});let O=g0(P,X?.body),$;if(O&&y0(z)==="fallback-first")try{let N=B();$=await K.getUsableFallbackAccounts(z),W.mark("fallback_first_get_accounts",{ms:E(B()-N),accounts:$.length});let H=await N0(P,X,$,z,void 0,W,{returnLastOnExhausted:!1});if(H)return W.done("return_fallback_first",{status:H.status}),J0(H);$=[]}catch(N){W.mark("fallback_first_error",{error:N instanceof Error?N.message:String(N)})}if(!Q.access||!Q.expires||Q.expires<Date.now()){let H=(await C())?.refresh?.mainLastRefreshError;if(Q.refresh&&H&&p(H,Q.refresh,Date.now()))throw q("[refresh] opencode main oauth request skipped backoff",{nextRetryAt:H.nextRetryAt,retryCount:H.retryCount,expiresInMs:Q.expires?Q.expires-Date.now():void 0}),Error(E0(H,Date.now()));q("[refresh] opencode main oauth refresh required for request",{hasAccess:Boolean(Q.access),expiresInMs:Q.expires?Q.expires-Date.now():void 0,expiredAgoMs:Q.expires&&Q.expires<Date.now()?Date.now()-Q.expires:void 0});let A=B();Q.access=await g(),W.mark("refresh_main_access",{ms:E(B()-A)})}if(!Q.access)throw W.done("missing_access_error"),Error("OAuth access token is missing after refresh");if(O&&jj(z))try{let N=B(),H=await Kj(Q.access,z);if(W.mark("main_quota_for_routing",{ms:E(B()-N),passes:C0(H,z)}),!C0(H,z)){let A=B();$=await K.getUsableFallbackAccounts(),W.mark("preselect_fallback_accounts",{ms:E(B()-A),accounts:$.length});let U=await N0(P,X,$,z,void 0,W);if(U)return W.done("return_preselected_fallback",{status:U.status}),J0(U)}}catch(N){W.mark("main_quota_for_routing_error",{error:N instanceof Error?N.message:String(N)})}let M=await h0(P,X,Q.access,W,"main"),_=await Zj(P,X,M,$,W,z);return W.done("return_response",{status:_.status}),J0(_)}}}return{}},methods:[{label:"Claude Pro/Max",type:"oauth",authorize:async()=>{let Z=await F0("max");return{url:Z.url,instructions:"Paste the authorization code here:",method:"code",callback:async(w)=>{return U0(w,Z.verifier,Z.redirectUri,Z.state)}}}},{label:"Create an API Key",type:"oauth",authorize:async()=>{let Z=await F0("console");return{url:Z.url,instructions:"Paste the authorization code here:",method:"code",callback:async(w)=>{let Y=await U0(w,Z.verifier,Z.redirectUri,Z.state);if(Y.type==="failed")return Y;return{type:"success",key:(await fetch("https://api.anthropic.com/api/oauth/claude_cli/create_api_key",{method:"POST",headers:{"Content-Type":"application/json",authorization:`Bearer ${Y.access}`}}).then((S)=>S.json())).raw_key}}}}},{provider:"anthropic",label:"Manually enter API Key",type:"api"}]}}};export{Tj as AnthropicAuthPlugin};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/opencode-anthropic-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -41,6 +41,6 @@
|
|
|
41
41
|
"@opencode-ai/plugin": "*"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@cortexkit/anthropic-auth-core": "1.
|
|
44
|
+
"@cortexkit/anthropic-auth-core": "1.3.0"
|
|
45
45
|
}
|
|
46
46
|
}
|
package/dist/index-v5pddj3r.js
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
var v="9d1c250a-e61b-44d9-88ed-5944d1962f5e",w0={console:"https://platform.claude.com/oauth/authorize",max:"https://claude.ai/oauth/authorize"},E0="https://platform.claude.com/oauth/code/callback",F0="https://platform.claude.com/v1/oauth/token",A0=["org:create_api_key","user:profile","user:inference","user:sessions:claude_code","user:mcp_servers","user:file_upload"],c$="mcp_";var h0="fast-mode-2026-02-01";function d$(f,$){let _=(f??"").split(",").map((D)=>D.trim()).filter(Boolean);return[...new Set([..._,...$])].join(",")}function g$(f){return typeof f==="string"&&(f.startsWith("claude-opus-4-6")||f.startsWith("claude-opus-4-7"))}var s$="You are OpenCode",r$="You are a Claude agent, built on Anthropic's Claude Agent SDK.";var S="2.1.141",M0="67b",x0="sdk-cli",P0="0.94.0",k0="v24.3.0",R0="claude-cli/2.1.141 (external, sdk-cli)",i0=["explicit","automatic","hybrid"],c="explicit",t$=["github.com/anomalyco/opencode","opencode.ai/docs"],o$=[{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 y0(f){let $="";for(let _ of f)$+=String.fromCharCode(_);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function l0(){let f=new Uint8Array(64);crypto.getRandomValues(f);let $=y0(f),_=await crypto.subtle.digest("SHA-256",new TextEncoder().encode($));return{verifier:$,challenge:y0(new Uint8Array(_)),method:"S256"}}function nf(f){if(!f)return;let $=Number(f);if(Number.isFinite($)&&$>0)return Math.ceil($);let _=Date.parse(f);if(Number.isFinite(_)){let D=Math.ceil((_-Date.now())/1000);return D>0?D:void 0}return}class L extends Error{status;body;retryAfter;constructor(f,$,_){super(`Claude OAuth refresh failed: ${f} — ${$}`);this.status=f,this.body=$,this.name="ClaudeOAuthRefreshError",this.retryAfter=nf(_??void 0)}}function uf(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 p0(f){let $=f.fetchImpl??fetch,_=f.maxRetries??2,D=f.baseDelayMs??500;for(let m=0;m<=_;m++)try{if(m>0){let F=D*2**(m-1);await new Promise((C)=>setTimeout(C,F))}let H=await $(F0,{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:v})});if(!H.ok){if(H.status>=500&&m<_){await H.body?.cancel().catch(()=>{});continue}let F=await H.text().catch(()=>"");throw new L(H.status,F,H.headers.get("retry-after"))}let E=await H.json(),M=f.now?.()??Date.now();return{access:E.access_token,refresh:E.refresh_token??f.refreshToken,expires:M+E.expires_in*1000,expiresIn:E.expires_in}}catch(H){if(H instanceof L)throw H;if(m<_&&uf(H))continue;throw H}throw Error("Token refresh exhausted all retries")}function vf(){return crypto.randomUUID().replace(/-/g,"")}function cf(f){let $=f.trim();try{let E=new URL($),M=E.searchParams.get("code"),F=E.searchParams.get("state");if(M&&F)return{code:M,state:F}}catch{}let _=$.split("#");if(_.length===2&&_[0]&&_[1])return{code:_[0],state:_[1]};let D=new URLSearchParams($),m=D.get("code"),H=D.get("state");if(m&&H)return{code:m,state:H};return null}async function df(f,$,_){let D=await fetch(F0,{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:v,redirect_uri:_,code_verifier:$})});if(!D.ok)return{type:"failed"};let m=await D.json();return{type:"success",refresh:m.refresh_token,access:m.access_token,expires:Date.now()+m.expires_in*1000}}async function __(f){let $=await l0(),_=vf(),D=new URL(w0[f],import.meta.url);return D.searchParams.set("code","true"),D.searchParams.set("client_id",v),D.searchParams.set("response_type","code"),D.searchParams.set("redirect_uri",E0),D.searchParams.set("scope",A0.join(" ")),D.searchParams.set("code_challenge",$.challenge),D.searchParams.set("code_challenge_method","S256"),D.searchParams.set("state",_),{url:D.toString(),redirectUri:E0,state:_,verifier:$.verifier}}async function D_(f,$,_,D){let m=cf(f);if(!m)return{type:"failed"};if(D&&m.state!==D)return{type:"failed"};return df(m,$,_)}import*as n0 from"node:fs";import*as u0 from"node:os";import*as v0 from"node:path";var gf=v0.join(u0.tmpdir(),"opencode-anthropic-auth.log"),c0=!1,sf=500,rf=50,k=[],x=null;function j0(){if(x)clearTimeout(x),x=null;if(k.length===0)return;let f=k.join("");k=[];try{n0.appendFileSync(gf,f)}catch{}}function tf(){if(x)return;x=setTimeout(()=>{x=null,j0()},sf)}function of(f){if(f===void 0)return"";if(f instanceof Error)return` ${f.message}${f.stack?`
|
|
2
|
-
${f.stack}`:""}`;return` ${JSON.stringify(f)}`}function V(f,$){if(c0)return;try{if(k.push(`[${new Date().toISOString()}] ${f}${of($)}
|
|
3
|
-
`),k.length>=rf)j0();else tf()}catch{}}function G(f,$){V(`[relay] ${f}`,$)}if(!c0)process.on("exit",j0);import{createHash as ff,randomUUID as K0}from"node:crypto";import{mkdir as af,readFile as d,rename as ef,rm as d0,stat as f1,writeFile as $f}from"node:fs/promises";import{homedir as $1}from"node:os";import{dirname as _1,join as g}from"node:path";var D1="anthropic-auth.json",m1="https://api.anthropic.com/api/oauth/usage",H1=[401,403,429],_f=240,E1=_f;var F1=300000,M1=3600000,j1=86400000,C1=5,g0={five_hour:0,seven_day:0},K1=!0,b1=60000,G1=60000,J1=120000,N1=1e4,W1=100;function I1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return g(process.env.XDG_CONFIG_HOME||g($1(),".config"),"opencode")}function X(){return process.env.OPENCODE_ANTHROPIC_AUTH_FILE?.trim()||g(I1(),D1)}function W(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function Q1(f){if(!W(f))return null;if(f.type!=="oauth")return null;if(typeof f.refresh!=="string"||!f.refresh.trim())return null;return{id:typeof f.id==="string"&&f.id.trim()?f.id.trim():K0(),label:typeof f.label==="string"?f.label:void 0,type:"oauth",access:typeof f.access==="string"?f.access:void 0,refresh:f.refresh,expires:typeof f.expires==="number"?f.expires:void 0,enabled:typeof f.enabled==="boolean"?f.enabled:void 0,addedAt:typeof f.addedAt==="number"?f.addedAt:void 0,lastUsed:typeof f.lastUsed==="number"?f.lastUsed:void 0,lastRefreshedAt:typeof f.lastRefreshedAt==="number"?f.lastRefreshedAt:void 0,lastRefreshError:s0(f.lastRefreshError),lastQuotaRefreshError:s0(f.lastQuotaRefreshError),quota:U1(f.quota)}}function s0(f){if(!W(f))return;if(typeof f.message!=="string")return;let $=Number(f.checkedAt);if(!Number.isFinite($))return;let _=Number(f.nextRetryAt),D=Number(f.retryCount);return{message:f.message,checkedAt:$,nextRetryAt:Number.isFinite(_)?_:void 0,retryCount:Number.isFinite(D)?D:void 0,tokenHash:typeof f.tokenHash==="string"?f.tokenHash:void 0}}function U1(f){if(!W(f))return;let $={};for(let _ of["five_hour","seven_day"]){let D=f[_];if(!W(D))continue;let m=Number(D.usedPercent),H=Number(D.remainingPercent),E=Number(D.checkedAt);if(!Number.isFinite(m)||!Number.isFinite(H)||!Number.isFinite(E))continue;$[_]={usedPercent:m,remainingPercent:H,checkedAt:E,resetsAt:typeof D.resetsAt==="string"?D.resetsAt:void 0}}return Object.keys($).length?$:void 0}function Z1(f){if(!W(f)||!Array.isArray(f.accounts))return null;return{version:1,main:{type:"opencode",provider:"anthropic"},fallbackOn:Array.isArray(f.fallbackOn)?f.fallbackOn.filter(($)=>Number.isInteger($)):void 0,refresh:W(f.refresh)?f.refresh:void 0,quota:W(f.quota)?f.quota:void 0,claudeCache:W(f.claudeCache)?f.claudeCache:void 0,dump:W(f.dump)?f.dump:void 0,claudeFast:W(f.claudeFast)?f.claudeFast:void 0,cacheKeep:W(f.cacheKeep)?f.cacheKeep:void 0,relay:W(f.relay)?f.relay:void 0,accounts:f.accounts.map(Q1).filter(($)=>$!=null)}}async function O(f=X()){try{let $=await d(f,"utf8");return Z1(JSON.parse($))}catch($){if($.code==="ENOENT")return null;return null}}async function X1(f){try{let $=await d(f,"utf8"),_=JSON.parse($);return W(_)?_:{}}catch{return{}}}function z1(f){return Object.fromEntries(Object.entries(f).filter(([,$])=>$!==void 0))}async function q(f,$=X()){await af(_1($),{recursive:!0});let D={...await X1($),...z1(f)},m=`${$}.${K0()}.tmp`;await $f(m,`${JSON.stringify(D,null,2)}
|
|
4
|
-
`,{encoding:"utf8",mode:384}),await ef(m,$)}async function V1(f){let _=`${f.path??X()}.${f.name}.lock`,D=g(_,"owner.json"),m=K0(),H=f.now??Date.now;async function E(){try{return JSON.parse(await d(_,"utf8"))}catch(F){if(F.code!=="EISDIR")throw F;return JSON.parse(await d(D,"utf8"))}}async function M(){try{return await $f(_,`${JSON.stringify({ownerId:m,expiresAt:H()+f.ttlMs})}
|
|
5
|
-
`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(F){let C=F.code;if(C==="EEXIST"||C==="EISDIR")return!1;throw F}}if(!await M()){try{let F=await E();if(Number(F?.expiresAt)>H())return null}catch{try{if((await f1(_)).mtimeMs+f.ttlMs>Date.now())return null}catch{return null}}if(await d0(_,{recursive:!0,force:!0}).catch(()=>{}),!await M())return null}return{release:async()=>{try{if((await E())?.ownerId!==m)return}catch{return}await d0(_,{recursive:!0,force:!0}).catch(()=>{})}}}function G_(f){return f?.claudeCache?.enabled===!0}function B1(f){return typeof f==="string"&&i0.includes(f)?f:c}function S1(f){return B1(f?.claudeCache?.mode)}async function J_(f,$,_=X()){let D=await O(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.claudeCache={...D.claudeCache??{},enabled:f,mode:$??S1(D)},await q(D,_),D}async function N_(f,$=X()){let _=await O($)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.claudeCache={..._.claudeCache??{},enabled:_.claudeCache?.enabled===!0,mode:f},await q(_,$),_}function W_(f){return f?.dump?.enabled===!0}async function I_(f,$=X()){let _=await O($)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.dump={..._.dump??{},enabled:f},await q(_,$),_}function Q_(f){return f?.claudeFast?.enabled===!0}async function U_(f,$=X()){let _=await O($)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.claudeFast={..._.claudeFast??{},enabled:f},await q(_,$),_}async function Z_(f,$,_=X()){let D=await O(_)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return D.cacheKeep={enabled:!0,startHour:f,endHour:$},await q(D,_),D}async function X_(f,$=X()){let _=await O($)??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};return _.cacheKeep={..._.cacheKeep??{},enabled:f},await q(_,$),_}function Y1(f){return f?.fallbackOn?.length?f.fallbackOn:H1}function z_(f,$){return Y1($).includes(f)}function Df(f){let $=f?.quota?.minimumRemaining||{};return{five_hour:$.five_hour??$["5h"]??g0.five_hour,seven_day:$.seven_day??$["1w"]??g0.seven_day}}function y(f){return f?.quota?.enabled!==!1}function L1(f){return f?.refresh?.enabled!==!1}function T1(f){return Math.floor(Math.random()*Math.max(0,f))}function O1(f){let $=f?.refresh?.refreshBeforeExpiryMinutes??E1;return Math.max(_f,$)*60000}function mf(f){return ff("sha256").update(f).digest("hex")}function q1(f){if(f instanceof L)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 w1(f){let $=mf(f.refreshToken),D=(f.previous?.tokenHash===$?f.previous.retryCount??0:0)+1,m;if(f.error instanceof L&&f.error.retryAfter)m=f.error.retryAfter*1000;else if(q1(f.error))m=Math.min(M1,F1*2**Math.min(D-1,6));else m=j1;return{message:b0(f.error),checkedAt:f.now,nextRetryAt:f.now+m,retryCount:D,tokenHash:$}}function R(f,$,_){if(!f?.nextRetryAt||f.nextRetryAt<=_)return!1;if(!$)return!0;return f.tokenHash===mf($)}function C0(f,$){return`Claude OAuth refresh is backed off for ${Math.max(1,Math.ceil(((f.nextRetryAt??$)-$)/1000))}s after: ${f.message}`}function i(f){let $=f?.quota?.checkIntervalMinutes??C1;return Math.max(1,$)*60000}function Hf(f){return f?.quota?.failClosedOnUnknownQuota??K1}function A1(f,$){if(!y($))return!0;let _=Df($);for(let D of["five_hour","seven_day"]){let m=f?.[D];if(!m)return!Hf($);if(m.remainingPercent<_[D])return!1}return!0}function V_(f,$,_){if(!y($))return _+i($);let D=Df($),m=[];for(let H of["five_hour","seven_day"]){let E=f?.[H];if(!E)return _+i($);if(E.remainingPercent>=D[H])continue;let M=E.resetsAt?Date.parse(E.resetsAt):Number.NaN;if(!Number.isFinite(M)||M<=_)return _+i($);m.push(M)}if(!m.length)return _+i($);return Math.min(...m)+60000}function T(f,$,_){return!f.access||!f.expires||f.expires-_<=O1($)}function r0(f,$,_){if(!y($))return!1;let D=i($);return["five_hour","seven_day"].some((m)=>{let H=f.quota?.[m];return!H||_-H.checkedAt>=D})}function t0(f){if(!Number.isFinite(f))return 0;if(f<0)return 0;if(f>100)return 100;return f}function o0(f,$){if(typeof f?.utilization!=="number")return;let _=t0(f.utilization);return{usedPercent:_,remainingPercent:t0(100-_),resetsAt:f.resets_at,checkedAt:$}}async function a0(f){let _=await(f.fetchImpl??fetch)(m1,{method:"GET",headers:{Authorization:`Bearer ${f.accessToken}`,Accept:"application/json","Content-Type":"application/json","anthropic-beta":"oauth-2025-04-20","User-Agent":`claude-code/${S}`}});if(!_.ok){let H=await _.text().catch(()=>"");throw Error(`Claude quota check failed: ${_.status} — ${H}`)}let D=f.now?.()??Date.now(),m=await _.json();return{five_hour:o0(m.five_hour,D),seven_day:o0(m.seven_day,D)}}function Z(f,$){let _=f.accounts.findIndex((D)=>D.id===$.id);if(_>=0)f.accounts[_]=$}function b0(f){return f instanceof Error?f.message:String(f)}function Ef(f,$,_){f.lastRefreshError=w1({error:$,now:_,refreshToken:f.refresh,previous:f.lastRefreshError})}function e0(f,$,_){if(f.lastQuotaRefreshError={message:b0($),checkedAt:_},$ instanceof L)Ef(f,$,_)}function h1(f){return`fallback-oauth-refresh-${ff("sha256").update(f).digest("hex").slice(0,16)}`}class x1{now;fetchImpl;configPath;refreshPromises=new Map;refreshTimer=null;quotaTimer=null;constructor(f={}){this.now=f.now??Date.now,this.fetchImpl=f.fetchImpl??fetch,this.configPath=f.configPath??X()}async load(){return O(this.configPath)}async save(f){await q(f,this.configPath)}startBackgroundRefresh(){let f=async()=>{await this.refreshDueAccounts(),await this.refreshQuotaForDueAccounts()};if(f().catch(()=>{}),!this.refreshTimer){if(this.refreshTimer=setInterval(()=>{f().catch(()=>{})},b1+T1(G1)),"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=!1;for(let m of $.accounts){if(m.enabled===!1)continue;try{let H=m;if(T(H,$,this.now())){let E=H.lastRefreshError;if(E&&R(E,H.refresh,this.now()))throw Error(C0(E,this.now()));H=await this.refreshAccount(H,$),D=!0}if(r0(H,$,this.now()))H=await this.refreshAccountQuota(H,$),D=!0;if(this.accountPassesQuotaPolicy(H,$))_.push(H)}catch{if(!Hf($))_.push(m)}}if(D)await this.save($);return _}async markUsed(f){let $=await this.load();if(!$)return;let _=$.accounts.find((D)=>D.id===f.id);if(!_)return;_.lastUsed=this.now(),await this.save($)}accountPassesQuotaPolicy(f,$){return A1(f.quota,$)}async refreshDueAccounts(){let f=await this.load();if(!f||!L1(f))return;let $=!1;for(let _ of f.accounts){if(_.enabled===!1)continue;if(!T(_,f,this.now()))continue;if(R(_.lastRefreshError,_.refresh,this.now())){V("[refresh] fallback oauth skipped backoff",{accountId:_.id,nextRetryAt:_.lastRefreshError?.nextRetryAt,retryCount:_.lastRefreshError?.retryCount});continue}try{V("[refresh] fallback oauth background due",{accountId:_.id,expiresInMs:_.expires?_.expires-this.now():void 0}),await this.refreshAccount(_,f),$=!0}catch(D){V("[refresh] fallback oauth background failed",{accountId:_.id,error:D instanceof Error?D.message:String(D)}),Ef(_,D,this.now()),Z(f,_),$=!0}}if($)await this.save(f)}async refreshQuotaForDueAccounts(){let f=await this.load();if(!f||!y(f))return;let $=!1;for(let _ of f.accounts){if(_.enabled===!1)continue;let D=_;try{if(T(D,f,this.now())){if(R(D.lastRefreshError,D.refresh,this.now()))continue;D=await this.refreshAccount(D,f),$=!0}if(!r0(D,f,this.now()))continue;await this.refreshAccountQuota(D,f),$=!0}catch(m){e0(_,m,this.now()),Z(f,_),$=!0}}if($)await this.save(f)}async refreshQuotaForAllAccounts(){let f=await this.load(),$=[];if(!f||!y(f))return{storage:f,errors:$};let _=!1;for(let D of f.accounts){if(D.enabled===!1)continue;let m=D;try{if(T(m,f,this.now())){let H=m.lastRefreshError;if(H&&R(H,m.refresh,this.now()))throw Error(C0(H,this.now()));m=await this.refreshAccount(m,f),_=!0}await this.refreshAccountQuota(m,f),_=!0}catch(H){e0(D,H,this.now()),Z(f,D),_=!0,$.push({accountId:D.id,message:b0(H)})}}if(_)await this.save(f);return{storage:f,errors:$}}async refreshAccount(f,$,_={}){let D=this.refreshPromises.get(f.id);if(D){let E=await D;return Z($,E),E}let m=this.refreshAccountNow(f,$,_).finally(()=>{this.refreshPromises.delete(f.id)});this.refreshPromises.set(f.id,m);let H=await m;return Z($,H),H}async waitForConcurrentFallbackRefresh(f,$,_,D){let m=Date.now()+N1;while(Date.now()<m){await new Promise((C)=>setTimeout(C,W1));let H=await this.load(),E=H?.accounts.find((C)=>C.id===f.id);if(!E)continue;if((E.access!==_.access||E.refresh!==_.refresh||(E.expires??0)>(_.expires??0)+60000)&&(D.force||!T(E,H,this.now())))return Z($,E),V("[refresh] fallback oauth joined concurrent refresh",{accountId:E.id,expiresInMs:E.expires?E.expires-this.now():void 0}),E;let F=E.lastRefreshError;if(F&&R(F,E.refresh,this.now()))throw Z($,E),Error(C0(F,this.now()))}return null}async refreshAccountNow(f,$,_){let D=await this.load(),m=D?.accounts.find((M)=>M.id===f.id);if(m&&!_.force&&!T(m,D,this.now()))return Z($,m),m;let H=m??f,E=await V1({name:h1(H.id),ttlMs:J1,path:this.configPath,now:this.now});if(!E){V("[refresh] fallback oauth refresh skipped file lock",{accountId:H.id});let M=await this.waitForConcurrentFallbackRefresh(f,$,H,_);if(M)return M;throw Error("Fallback OAuth refresh is already in progress")}try{if(D=await this.load(),m=D?.accounts.find((C)=>C.id===f.id),m&&!_.force&&!T(m,D,this.now()))return Z($,m),m;H=m??H;let M=H.refresh;V("[refresh] fallback oauth refresh request start",{accountId:H.id,force:_.force===!0,expiresInMs:H.expires?H.expires-this.now():void 0});let F=await p0({refreshToken:M,fetchImpl:this.fetchImpl,now:this.now});return H.access=F.access,H.refresh=F.refresh,H.expires=F.expires,H.lastRefreshedAt=F.expires-F.expiresIn*1000,H.lastRefreshError=void 0,Z($,H),await this.save($),V("[refresh] fallback oauth refresh succeeded",{accountId:H.id,expiresInMs:H.expires?H.expires-this.now():void 0}),H}finally{await E.release()}}async refreshAccountQuota(f,$){let _=f;if(!_.access)throw Error(`Fallback account ${f.id} has no access token`);try{_.quota=await a0({accessToken:_.access,fetchImpl:this.fetchImpl,now:this.now})}catch(D){if(!(D instanceof Error?D.message:String(D)).includes("Claude quota check failed: 401"))throw D;if(_=await this.refreshAccount(f,$,{force:!0}),!_.access)throw D;_.quota=await a0({accessToken:_.access,fetchImpl:this.fetchImpl,now:this.now})}return _.lastQuotaRefreshError=void 0,Z($,_),_}}var Y_="claude-cache",Ff="## Claude Cache Status",P1="## Claude Cache Enabled",k1="## Claude Cache Disabled",R1="## Claude Cache Usage",i1="Usage: `/claude-cache`, `/claude-cache on`, `/claude-cache off`, or `/claude-cache mode explicit|automatic|hybrid`.",s=!1,r=c;function L_(){return s}function T_(){return r}function O_(f){s=f.enabled,r=f.mode}function y1(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 l(f){let $=f?.enabled??s,_=f?.mode??r;return[Ff,"",`- Enabled: ${$?"enabled":"disabled"}`,`- Mode: ${_}`,"- 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(`
|
|
6
|
-
`)}function q_(f){let $=y1(f.argumentsText),_=f.enabled??s,D=f.mode??r;if($.type==="status")return l({enabled:_,mode:D});if($.type==="enable")return[P1,"",l({enabled:!0,mode:D})].join(`
|
|
7
|
-
`);if($.type==="disable")return[k1,"",l({enabled:!1,mode:D})].join(`
|
|
8
|
-
`);if($.type==="mode")return[Ff,"",`Mode updated to \`${$.mode}\`.`,"",l({enabled:_,mode:$.mode})].join(`
|
|
9
|
-
`);return[R1,"",i1,"",l({enabled:_,mode:D})].join(`
|
|
10
|
-
`)}import{randomBytes as l1,randomUUID as jf}from"node:crypto";var p1=1000,p=new Map;function J0(f,$,_){if(!f.has($)&&f.size>=p1){let D=f.keys().next().value;if(D!==void 0)f.delete(D)}f.set($,_)}function Cf(f){let $=f||"anonymous",_=p.get($);if(_)return _;let D={deviceId:l1(32).toString("hex"),sessionId:jf()};return J0(p,$,D),D}var G0=new Map;async function n1(f,$){if(!f.startsWith("sk-ant-oat"))return null;let _=new AbortController,D=setTimeout(()=>_.abort(),5000);try{let m=new URL("https://api.anthropic.com/api/claude_cli/bootstrap");if(m.searchParams.set("entrypoint",x0),$)m.searchParams.set("model",$);let H=await fetch(m,{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/${S}`},signal:_.signal});if(!H.ok)return null;let M=(await H.json().catch(()=>null))?.oauth_account?.account_uuid;return typeof M==="string"&&M?M:null}catch{return null}finally{clearTimeout(D)}}async function x_(f,$){let _=Cf(f);if(!f.startsWith("sk-ant-oat"))return _;let D=G0.get(f);if(!D)D=n1(f,$),G0.set(f,D);let m=await D;if(!m)return G0.delete(f),_;let H=`account:${m}`,E=p.get(H);if(E)return J0(p,f,E),E;return _.accountUuid=m,J0(p,H,_),_}function w(f){return f!=null&&typeof f==="object"&&!Array.isArray(f)}function u1(f){if(!f.accountUuid)return null;return JSON.stringify({device_id:f.deviceId,account_uuid:f.accountUuid,session_id:f.sessionId})}function P_(f,$){let _=u1($);if(!_){if(w(f.metadata))delete f.metadata.user_id;return!1}if(!w(f.metadata))f.metadata={};let D=f.metadata;if(w(D))D.user_id=_;return!0}var v1=["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"],c1=["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"],Mf=["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 d1(f){return f.output_config?.format?.type==="json_schema"}function g1(f){return Array.isArray(f.tools)&&f.tools.length>0&&Array.isArray(f.system)&&w(f.thinking)&&w(f.context_management)&&w(f.output_config)&&w(f.diagnostics)}function s1(f,$=[]){let _=f?g1(f)?[...v1]:d1(f)?[...c1]:[...Mf]:[...Mf];if(f?.speed==="fast")_.push(h0);for(let D of $){let m=D.trim();if(m)_.push(m)}return[...new Set(_)].join(",")}function r1(){switch(process.platform){case"darwin":return"MacOS";case"win32":return"Windows";case"linux":return"Linux";case"freebsd":return"FreeBSD";default:return"Unknown"}}function t1(){switch(process.arch){case"arm64":return"arm64";case"x64":return"x64";case"ia32":return"x32";default:return process.arch}}function k_(f,$,_={}){let D=_.identity??Cf($),H=[...(f.get("anthropic-beta")??"").split(",").map((E)=>E.trim()).filter(Boolean),..._.extraBetas??[]];return f.set("accept","application/json"),f.set("authorization",`Bearer ${$}`),f.set("content-type","application/json"),f.set("user-agent",R0),f.set("anthropic-beta",s1(_.body,H)),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",jf()),f.set("x-claude-code-session-id",D.sessionId),f.set("x-stainless-arch",t1()),f.set("x-stainless-lang","js"),f.set("x-stainless-os",r1()),f.set("x-stainless-package-version",P0),f.set("x-stainless-retry-count","0"),f.set("x-stainless-runtime","node"),f.set("x-stainless-runtime-version",k0),f.set("x-stainless-timeout","600"),f.delete("x-api-key"),f}var o1=["model","messages","system","tools","tool_choice","metadata","max_tokens","temperature","thinking","context_management","output_config","diagnostics","stream","speed"];function Kf(f){let $={};for(let _ of o1)if(Object.hasOwn(f,_))$[_]=f[_];for(let[_,D]of Object.entries(f))if(!Object.hasOwn($,_))$[_]=D;return $}import{createHash as e1}from"node:crypto";var a1=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 bf(){return function(f){let{exports:{mem:$,xxh32:_,xxh64:D,init32:m,update32:H,digest32:E,init64:M,update64:F,digest64:C}}=f,b=new Uint8Array($.buffer);function J(j,N){if($.buffer.byteLength<j+N){let m0=Math.ceil((j+N-$.buffer.byteLength)/65536);$.grow(m0),b=new Uint8Array($.buffer)}}function B(j,N,m0,yf,lf,pf){J(j);let P=new Uint8Array(j);return b.set(P),m0(0,N),P.set(b.subarray(0,j)),{update(h){let H0;return b.set(P),typeof h=="string"?(J(3*h.length,j),H0=U.encodeInto(h,b.subarray(j)).written):(J(h.byteLength,j),b.set(h,j),H0=h.byteLength),yf(0,j,H0),P.set(b.subarray(0,j)),this},digest:()=>(b.set(P),pf(lf(0)))}}function z(j){return j>>>0}let K=2n**64n-1n;function Q(j){return j&K}let U=new TextEncoder,n=0,u=0n;function O0(j,N=n){return J(3*j.length,0),z(_(0,U.encodeInto(j,b).written,N))}function q0(j,N=u){return J(3*j.length,0),Q(D(0,U.encodeInto(j,b).written,N))}return{h32:O0,h32ToString:(j,N=n)=>O0(j,N).toString(16).padStart(8,"0"),h32Raw:(j,N=n)=>(J(j.byteLength,0),b.set(j),z(_(0,j.byteLength,N))),create32:(j=n)=>B(48,j,m,H,E,z),h64:q0,h64ToString:(j,N=u)=>q0(j,N).toString(16).padStart(16,"0"),h64Raw:(j,N=u)=>(J(j.byteLength,0),b.set(j),Q(D(0,j.byteLength,N))),create64:(j=u)=>B(88,j,M,F,C,Q)}}((await WebAssembly.instantiate(a1)).instance)}var f$=0x6e52736ac806831en,t=/\bcch=([0-9a-f]{5});/,Gf=null,N0=null;async function $$(){if(N0)return;Gf??=(async()=>{N0=(await bf()).h64Raw})(),await Gf}async function _$(f){return await $$(),((N0?.(f,f$)??0n)&0xfffffn).toString(16).padStart(5,"0")}async function Jf(f){if(!t.test(f))return f;let $=await _$(new TextEncoder().encode(f));return f.replace(t,`cch=${$};`)}function D$(f=S,$=new Date){if(f===S)return M0;let _=$.toISOString().slice(0,10);return e1("sha256").update(`${_}${f}`).digest("hex").slice(0,3)}function n_(f,$=S,_,D=new Date){let m=D$($,D);return`x-anthropic-billing-header: cc_version=${$}.${m}; cc_entrypoint=${_}; cch=00000;`}var d_="claude-cachekeep",Nf=3600000,W0=300000,m$=60000,g_="extended-cache-ttl-2025-04-11",H$="## Claude Cache Keep Status",E$="## Claude Cache Keep Enabled",F$="## Claude Cache Keep Disabled",M$="## Claude Cache Keep Usage",j$="Usage: `/claude-cachekeep`, `/claude-cachekeep off`, or `/claude-cachekeep HH-HH`.";function a(f){return String(f).padStart(2,"0")}function C$(f){let $=f.trim();if(!$)return{type:"status"};if($==="off")return{type:"disable"};let _=/^(\d{1,2})-(\d{1,2})$/.exec($);if(!_)return{type:"usage"};let D=Number(_[1]),m=Number(_[2]);if(!Number.isInteger(D)||!Number.isInteger(m)||D<0||D>23||m<0||m>23||D===m)return{type:"usage"};return{type:"window",startHour:D,endHour:m}}function Q0(f){let $=Number(f?.cacheKeep?.startHour),_=Number(f?.cacheKeep?.endHour);if(!Number.isInteger($)||!Number.isInteger(_)||$<0||$>23||_<0||_>23||$===_)return;return{startHour:$,endHour:_}}function Qf(f){return f?.cacheKeep?.enabled===!0&&!!Q0(f)}function K$(f){return Qf(f)&&f?.claudeCache?.enabled===!0&&f.claudeCache.mode==="hybrid"}function Wf(f,$=new Date){if(!f)return!1;let _=$.getHours();if(f.startHour<f.endHour)return _>=f.startHour&&_<f.endHour;return _>=f.startHour||_<f.endHour}function If(f=new Date){return`${f.getFullYear()}-${a(f.getMonth()+1)}-${a(f.getDate())}`}function I0(f,$=new Date){if(f&&f.startHour>f.endHour&&$.getHours()<f.endHour){let _=new Date($);return _.setDate(_.getDate()-1),If(_)}return If($)}function o(f){let $=f.window?`${a(f.window.startHour)}-${a(f.window.endHour)}`:"not configured",_=[`Cache keep: ${f.enabled?"enabled":"disabled"}`,`Window: ${$}`,"Mode requirement: `/claude-cache mode hybrid` must be active."];if(typeof f.hybridActive==="boolean")_.push(`Hybrid active: ${f.hybridActive?"yes":"no"}`);if(typeof f.trackedSessions==="number")_.push(`Tracked sessions: ${f.trackedSessions}`);if(f.nextPrewarmAt)_.push(`Next prewarm: ${new Date(f.nextPrewarmAt).toLocaleString()}`);return _.join(`
|
|
11
|
-
`)}function s_(f){let $=C$(f.argumentsText),_={enabled:f.enabled??!1,window:f.window,trackedSessions:f.trackedSessions,nextPrewarmAt:f.nextPrewarmAt,hybridActive:f.hybridActive};if($.type==="status")return[H$,"",o(_)].join(`
|
|
12
|
-
`);if($.type==="disable")return[F$,"",o({..._,enabled:!1})].join(`
|
|
13
|
-
`);if($.type==="window")return[E$,"",o({..._,enabled:!0,window:{startHour:$.startHour,endHour:$.endHour}})].join(`
|
|
14
|
-
`);return[M$,"",j$,"",o(_)].join(`
|
|
15
|
-
`)}function U0(f){if(!f||typeof f!=="object")return!1;if(Array.isArray(f))return f.some(U0);let $=f,_=$.cache_control;if(_&&typeof _==="object"&&_.type==="ephemeral")return!0;return Object.values($).some(U0)}async function b$(f){let $;try{$=JSON.parse(f)}catch{return{ok:!1,reason:"body is not valid JSON"}}if(!U0($))return{ok:!1,reason:"body has no explicit cache breakpoints"};let _=structuredClone($);if(_.max_tokens=0,delete _.stream,_.thinking?.type==="enabled")delete _.thinking;if(_.output_config?.format)delete _.output_config;let H=_.tool_choice;if(H?.type==="tool"||H?.type==="any")delete _.tool_choice;let E=JSON.stringify(Kf(_)).replace(t,"cch=00000;");return{ok:!0,bodyText:await Jf(E)}}class G${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)})})},m$),"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 _=I0(f,new Date($)),D=[...this.targets.values()].filter((H)=>H.dayKey===_),m=D.length?Math.min(...D.map((H)=>H.cacheExpiresAt-W0)):void 0;return{trackedSessions:D.length,nextPrewarmAt:m}}track(f){if(!f.sessionId)return{tracked:!1,reason:"missing session id"};if(!Qf(f.storage))return{tracked:!1,reason:"cachekeep disabled"};if(f.cacheMode!=="hybrid")return{tracked:!1,reason:"cache mode is not hybrid"};let $=this.options.now?.()??Date.now(),_=Q0(f.storage);if(!Wf(_,new Date($)))return{tracked:!1,reason:"outside configured window"};let D={};return f.headers.forEach((m,H)=>{D[H]=m}),this.targets.set(f.sessionId,{id:f.sessionId,url:f.url,headers:D,bodyText:f.bodyText,cacheExpiresAt:$+Nf,dayKey:I0(_,new Date($))}),this.start(),{tracked:!0}}async tick(){let f=await this.options.loadStorage(),$=Q0(f),_=this.options.now?.()??Date.now(),D=I0($,new Date(_));for(let[H,E]of this.targets)if(E.dayKey!==D)this.targets.delete(H);if(!this.targets.size){this.stop();return}if(!K$(f))return;if(!Wf($,new Date(_)))return;let m=_+W0;for(let H of this.targets.values()){if(H.cacheExpiresAt>m)continue;await this.prewarm(H,_)}}async prewarm(f,$){let _=await b$(f.bodyText);if(!_.ok){this.options.log?.("[cachekeep] prewarm skipped",{session:f.id,reason:_.reason}),this.targets.delete(f.id);return}let D=this.options.fetchImpl??fetch,m={...f,bodyText:_.bodyText},H=this.options.prepareHeaders?await this.options.prepareHeaders(new Headers(f.headers),m):new Headers(f.headers);H.delete("content-length"),H.delete("transfer-encoding");let E=await D(f.url,{method:"POST",headers:H,body:_.bodyText});if(!E.ok){this.options.log?.("[cachekeep] prewarm failed",{session:f.id,status:E.status,body:await E.text().catch(()=>"")}),f.cacheExpiresAt=$+W0+300000;return}await E.body?.cancel().catch(()=>{}),f.cacheExpiresAt=$+Nf,this.options.log?.("[cachekeep] prewarm succeeded",{session:f.id})}}import{createHash as J$}from"node:crypto";import{mkdir as N$,writeFile as Z0}from"node:fs/promises";import{tmpdir as W$}from"node:os";import{join as Xf}from"node:path";var $D="claude-dump",I$="## Claude Dump Status",Q$="## Claude Dump Enabled",U$="## Claude Dump Disabled",Z$="## Claude Dump Usage",X$="Usage: `/claude-dump`, `/claude-dump on`, or `/claude-dump off`.",z0=Xf(W$(),"opencode-anthropic-auth-dumps"),f0=!1,Uf=0;function _D(f){f0=f}function z$(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 e(f){let $=f?.enabled??f0;return[I$,"",`- Enabled: ${$?"enabled":"disabled"}`,`- Directory: ${z0}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Captures: final rewritten Anthropic body plus redacted relay payload metadata","- Warning: body dumps may contain prompt/session content; turn this off after debugging"].join(`
|
|
16
|
-
`)}function DD(f){let $=z$(f.argumentsText),_=f.enabled??f0;if($.type==="status")return e({enabled:_});if($.type==="enable")return[Q$,"",e({enabled:!0})].join(`
|
|
17
|
-
`);if($.type==="disable")return[U$,"",e({enabled:!1})].join(`
|
|
18
|
-
`);return[Z$,"",X$,"",e({enabled:_})].join(`
|
|
19
|
-
`)}function Zf(f){return f.length<=16?f:`${f.slice(0,12)}…`}function zf(f){return J$("sha256").update(f).digest("hex")}function V$(f){return f.match(/\bcch=([0-9a-f]{5});/)?.[1]??null}function B$(f,$){if(f==null)return null;if(f===$)return{changed:!1,firstByte:-1,lastPreviousByte:-1,lastCurrentByte:-1,previousBytes:f.length,currentBytes:$.length};let _=0;while(_<f.length&&_<$.length&&f[_]===$[_])_+=1;let D=f.length-1,m=$.length-1;while(D>=_&&m>=_&&f[D]===$[m])D-=1,m-=1;return{changed:!0,firstByte:_,lastPreviousByte:D,lastCurrentByte:m,changedPreviousBytes:D-_+1,changedCurrentBytes:m-_+1,previousBytes:f.length,currentBytes:$.length}}function S$(f){try{let $=JSON.parse(f);return $!=null&&typeof $==="object"&&!Array.isArray($)?$:null}catch($){return G(`dump body parse failed: ${$ instanceof Error?$.message:String($)}`),null}}function X0(f){return zf(JSON.stringify(f))}function Y$(f){let $=S$(f);if(!$)return{parseable:!1};let _=Array.isArray($.messages)?$.messages:[],D=Array.isArray($.system)?$.system:[],m=_[0],H=_.slice(1);return{parseable:!0,model:typeof $.model==="string"?$.model:void 0,stream:$.stream,systemCount:D.length,messagesCount:_.length,systemHash:X0(D),message0Hash:m===void 0?null:X0(m),message0Bytes:m===void 0?0:JSON.stringify(m).length,messagesAfter0Hash:X0(H),messagesAfter0Bytes:JSON.stringify(H).length,cch:V$(f)}}function V0(f){if(Array.isArray(f))return f.map(V0);if(f==null||typeof f!=="object")return f;let $={};for(let[_,D]of Object.entries(f)){let m=_.toLowerCase();if(m==="authorization"||m==="x-api-key"||m==="cookie"||m==="set-cookie"){$[_]="[redacted]";continue}$[_]=V0(D)}return $}async function Vf(f){if(!f0)return;Uf+=1;let $=`${new Date().toISOString().replace(/[:.]/g,"-")}-${String(Uf).padStart(5,"0")}-${f.transport}-p${f.protocol}-${f.mode}`,_=Xf(z0,$);try{await N$(z0,{recursive:!0});let D={id:$,createdAt:new Date().toISOString(),session:Zf(f.affinity),transport:f.transport,protocol:f.protocol,mode:f.mode,status:f.status,bodyBytes:f.bodyText.length,relayBytes:f.relayBytes,bodyHash:zf(f.bodyText),diff:B$(f.previousBodyText,f.bodyText),body:Y$(f.bodyText),files:{body:`${_}.body.json`,relay:`${_}.relay.json`,metadata:`${_}.meta.json`}};await Promise.all([Z0(`${_}.body.json`,f.bodyText,"utf8"),Z0(`${_}.relay.json`,`${JSON.stringify(V0(f.payload),null,2)}
|
|
20
|
-
`,"utf8"),Z0(`${_}.meta.json`,`${JSON.stringify(D,null,2)}
|
|
21
|
-
`,"utf8")]),G(`dumped request id=${$} session=${Zf(f.affinity)} body=${_}.body.json meta=${_}.meta.json`)}catch(D){G(`dump failed: ${D instanceof Error?D.message:String(D)}`)}}var HD="claude-fast";var _0=!1;function ED(){return _0}function FD(f){_0=f}function L$(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 $0(f){return["## Claude Fast Mode Status","",`- Enabled: ${f?.enabled??_0?"enabled":"disabled"}`,"- Persisted: ~/.config/opencode/anthropic-auth.json","- Scope: adds Anthropic fast mode to supported Opus requests","- Supported models: claude-opus-4-6 and claude-opus-4-7",'- 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(`
|
|
22
|
-
`)}function MD(f){let $=L$(f.argumentsText),_=f.enabled??_0;if($.type==="status")return $0({enabled:_});if($.type==="enable")return["## Claude Fast Mode Enabled","",$0({enabled:!0})].join(`
|
|
23
|
-
`);if($.type==="disable")return["## Claude Fast Mode Disabled","",$0({enabled:!1})].join(`
|
|
24
|
-
`);return["## Claude Fast Mode Usage","","Usage: `/claude-fast`, `/claude-fast on`, or `/claude-fast off`.","",$0({enabled:_})].join(`
|
|
25
|
-
`)}var CD="claude-quota",Bf={five_hour:"5h",seven_day:"1w"};function Sf(f){return`${Math.round(f*10)/10}%`}function B0(f,$){let _=Math.max(0,$-f),D=Math.floor(_/60000);if(D<1)return"just now";if(D===1)return"1m ago";if(D<60)return`${D}m ago`;let m=Math.floor(D/60),H=D%60;if(H===0)return`${m}h ago`;return`${m}h ${H}m ago`}function T$(f,$){let _=Date.parse(f);if(!Number.isFinite(_))return f;let D=_-$;if(D<=0)return"now";let m=Math.max(1,Math.ceil(D/60000));if(m<60)return`in ${m}m`;let H=Math.floor(m/60),E=m%60;if(E===0)return`in ${H}h`;return`in ${H}h ${E}m`}function O$(f,$){if(!f)return"";return`, resets ${T$(f,$)}`}function Yf(f,$,_){if(!$)return` - ${Bf[f]}: unknown`;return[` - ${Bf[f]}: ${Sf($.remainingPercent)} remaining`,` (${Sf($.usedPercent)} used`,`${O$($.resetsAt,_)}, checked ${B0($.checkedAt,_)})`].join("")}function q$(f){return f.label?.trim()||f.id}function w$(f){return f.lastQuotaRefreshError?.message??f.lastRefreshError?.message}function KD(f,$=new Map){if(!f?.accounts.length)return[];return f.accounts.map((_)=>{let D=$.get(_.id)??w$(_);return{name:q$(_),role:"fallback",enabled:_.enabled!==!1,quota:_.quota,lastRefreshedAt:_.lastRefreshedAt,...D&&{error:D}}})}function bD(f){let $=f.now??Date.now(),_=["## Claude Quotas",""];if(f.refreshedAt)_.push(`Refreshed: ${B0(f.refreshedAt,$)}`,"");if(!f.accounts.length)return _.push("No Claude OAuth accounts found yet."),_.join(`
|
|
26
|
-
`);for(let D of f.accounts){let m=D.role==="main"?"main":"fallback",H=D.enabled===!1?" disabled":"";if(_.push(`### ${D.name} (${m}${H})`),D.lastRefreshedAt)_.push(` - Last token refresh: ${B0(D.lastRefreshedAt,$)}`);if(D.error)_.push(` - Error: ${D.error}`);_.push(Yf("five_hour",D.quota?.five_hour,$)),_.push(Yf("seven_day",D.quota?.seven_day,$)),_.push("")}return _.join(`
|
|
27
|
-
`).trimEnd()}import{Buffer as xf}from"node:buffer";import{createHash as A$,randomBytes as h$}from"node:crypto";class Y0 extends Error{}var T0=new Map,Lf=new Map,Tf=new Set,Of=0;function S0(){return Of+=1,`req_${Date.now().toString(36)}_${Of.toString(36)}`}function D0(f){if(Tf.has(f))return;Tf.add(f),G(f)}function QD(f){let $=f?.relay;if(!$)return D0("disabled: no relay config found"),null;if($.enabled!==!0)return D0("disabled: relay.enabled is not true"),null;if(!$.url?.trim()||!$.token?.trim())return D0("disabled: missing relay url or token"),null;let _=$.transport==="http"?"http":"websocket";return D0(`configured transport=${_} protocol=${_==="websocket"?2:1} url=${$.url.trim()} fallbackToDirect=${$.fallbackToDirect!==!1}`),{enabled:!0,url:$.url.trim(),token:$.token.trim(),fallbackToDirect:$.fallbackToDirect!==!1,transport:_}}function UD(){return h$(32).toString("base64url")}function x$(f){return`sha256:${A$("sha256").update(f).digest("hex")}`}function qf(f,$){let _=0,D=Math.min(f.length,$.length);while(_<D&&f.charCodeAt(_)===$.charCodeAt(_))_++;let m=f.length,H=$.length;while(m>_&&H>_&&f.charCodeAt(m-1)===$.charCodeAt(H-1))m--,H--;return{start:_,deleteCount:m-_,insert:$.slice(_,H)}}function P$(f){return f.deleteCount===0&&f.insert.length===0}function wf(f){let $=f.match(/\bcch=([0-9a-f]{5});/),_=$?.[1];if(!_||$.index==null)return null;let D=$.index+4;return{start:D,end:D+_.length,token:_}}function k$(f,$,_,D){return`${f.slice(0,$)}${D}${f.slice(_)}`}function Pf(f,$){let _=wf(f),D=wf($);if(_&&D&&_.start===D.start&&_.end-_.start===D.end-D.start&&_.token!==D.token){let m={start:_.start,deleteCount:_.end-_.start,insert:D.token},H=k$(f,_.start,_.end,D.token),E=qf(H,$);return P$(E)?m:[m,E]}return qf(f,$)}function R$(f,$){if(typeof $!=="string")return!1;try{let _=f instanceof Request?new URL(f.url):new URL(f.toString());return _.pathname==="/v1/messages"||_.pathname==="/messages"}catch{return!1}}function i$(f){let $={};for(let[_,D]of f.entries()){if(_==="x-session-affinity"||_==="x-opencode-session")continue;$[_]=D}return $}async function Af(f,$){return fetch(f.url,{method:"POST",headers:{"content-type":"application/json","x-relay-token":f.token},body:JSON.stringify($)})}function I(f){return f.length>12?`${f.slice(0,12)}…`:f}function Y(){return performance.now()}function A(f){return Math.round(f*10)/10}function y$(f){let{input:$,init:_,headers:D,bodyText:m,affinity:H,previous:E,nextHash:M}=f,F=$ instanceof Request?$.url:$.toString(),C={protocol:1,type:"request",affinity:H,upstream:{url:F,method:_?.method||($ instanceof Request?$.method:"POST"),headers:i$(D)},next_hash:M};return E?{...C,mode:"patch",base_hash:E.hash,revision:E.revision+1,patch:Pf(E.body,m)}:{...C,mode:"full_sync",revision:1,body:m}}function L0(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 kf(f,$,_,D){T0.set(f,{body:$,hash:_,revision:D})}async function hf(f){let{config:$,payload:_,bodyText:D,fallback:m}=f,H=_,E=await Af($,H);if(E.status===409&&H.mode==="patch")G(`state mismatch from relay session=${I(H.affinity)}; retrying full_sync`),await E.body?.cancel().catch(()=>{}),H=L0(H,D),E=await Af($,H);if(!E.ok&&E.status>=500&&$.fallbackToDirect)return G(`relay returned ${E.status}; falling back direct session=${I(H.affinity)}`),await E.body?.cancel().catch(()=>{}),{response:await m(),payload:H,transport:"http",protocol:H.protocol,usedRelay:!1};return{response:E,payload:H,transport:"http",protocol:H.protocol,usedRelay:!0}}function l$(f,$){let _=new URL(f);return _.protocol=_.protocol==="http:"?"ws:":"wss:",_.pathname="/ws",_.searchParams.set("token",$),_.toString()}function p$(f){return new Uint8Array(xf.from(f,"base64"))}function n$(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(xf.from(String(f)))}function u$(f){return JSON.parse(f)}class Rf{config;affinity;socket;connecting;queue=Promise.resolve();pending;serverState;constructor(f,$){this.config=f,this.affinity=$}send(f,$,_=!1){let D=Y(),m=this.queue.catch(()=>{}).then(()=>this.startQueued(f,$,D,_)),H=m.then(async({response:E,getPayload:M})=>({response:await E,payload:M(),transport:"websocket",protocol:2,usedRelay:!0}));return this.queue=m.then(({done:E})=>E.catch(()=>{}),()=>{}),H}async startQueued(f,$,_,D){let m=Y();await this.ensureConnected();let H=Y(),E=T0.get(this.affinity),M=this.serverState?.hash,F={...f,protocol:2,id:S0()};if(F.mode==="patch"&&(!M||M!==F.base_hash))F.mode="full_sync",F.revision=(this.serverState?.revision??0)+1,delete F.base_hash,delete F.patch,F.body=$;if(F.mode==="patch"&&E)F.patch=Pf(E.body,$);G(`perf websocket send_start session=${I(this.affinity)} request=${F.id} mode=${F.mode} queueMs=${A(H-_)} connectMs=${A(H-m)} bodyBytes=${$.length} relayBytes=${JSON.stringify(F).length}`);let C=F,b=this.sendPayload(F,$,D);b.done.catch(()=>{});let J=b.done,B=b.response.catch((K)=>{if(!(K instanceof Y0)||F.mode!=="patch")throw K;let Q=L0(F,$);Q.protocol=2,Q.id=S0(),Q.revision=(this.serverState?.revision??0)+1,C=Q;let U=this.sendPayload(Q,$,D);return U.done.catch(()=>{}),J=U.done,U.response}),z=B.then(()=>J,()=>J.catch(()=>{}));return{response:B,done:z,getPayload:()=>C}}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 _=l$(this.config.url,this.config.token),D=new URL(_);D.searchParams.set("affinity",this.affinity);let m=new WebSocket(D.toString());this.socket=m,this.serverState=void 0;let H=setTimeout(()=>{m.close(),$(Error("relay websocket ready timed out"))},15000);m.addEventListener("message",(E)=>{try{if(typeof E.data!=="string"){this.handleBinaryChunk(E.data);return}let M=u$(E.data);if(M.type==="ready"){clearTimeout(H),this.serverState=M.state,f();return}this.handleMessage(M)}catch(M){clearTimeout(H),$(M),this.failPending(M),m.close()}}),m.addEventListener("error",()=>{clearTimeout(H);let E=Error("relay websocket error");$(E),this.failPending(E)}),m.addEventListener("close",()=>{if(clearTimeout(H),this.socket===m)this.socket=void 0,this.serverState=void 0,this.connecting=void 0;if(this.pending){if(this.pending.retryingBeforeResponse)return;if(this.retryPendingBeforeResponse(this.pending,"closed before response"))return;let E=Error("relay websocket closed before response");this.failPending(E)}})}).finally(()=>{this.connecting=void 0}),await this.connecting}sendPayload(f,$,_){let D=this.socket;if(!D||D.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");let m=Y(),H,E,M=new Promise((C,b)=>{H=C,E=b});return{response:new Promise((C,b)=>{let J={payload:f,bodyText:$,resolve:C,reject:b,streamDone:!1,accepted:!1,responseStarted:!1,resolveDone:H,rejectDone:E,sentAt:m,optimisticResponse:_,retryAttempts:0,retryingBeforeResponse:!1};if(this.pending=J,this.resetPendingTimeout(J),D.send(JSON.stringify(f)),_)this.resolvePendingResponse(J,200,"OK",{"content-type":"text/event-stream","x-cortexkit-relay-optimistic":"true"})}),done:M}}resetPendingTimeout(f){clearTimeout(f.timeout),f.timeout=setTimeout(()=>{if(this.pending!==f)return;if(this.retryPendingBeforeResponse(f,"response timed out"))return;this.failPending(Error("relay websocket response timed out")),this.socket?.close()},45000)}retryPendingBeforeResponse(f,$){if(f.responseStartedAt!=null)return!1;if(f.streamDone)return!1;if(f.retryAttempts>=1)return!1;f.retryAttempts+=1,f.retryingBeforeResponse=!0,clearTimeout(f.timeout);let _=f.retryAttempts,D=f.payload.id;return G(`websocket ${$}; reconnecting and retrying full_sync session=${I(this.affinity)} request=${D} retry=${_}`),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=L0(f.payload,f.bodyText);m.protocol=2,m.id=S0(),m.revision=(this.serverState?.revision??0)+1,f.payload=m,f.accepted=!1,f.acceptedAt=void 0,f.responseStartedAt=void 0,f.sentAt=Y(),f.retryingBeforeResponse=!1;let H=this.socket;if(!H||H.readyState!==WebSocket.OPEN)throw Error("relay websocket is not connected");this.resetPendingTimeout(f),G(`perf websocket retry_send session=${I(this.affinity)} request=${m.id} previous=${D} mode=full_sync retry=${_} bodyBytes=${f.bodyText.length} relayBytes=${JSON.stringify(m).length}`),H.send(JSON.stringify(m))}catch(m){if(f.retryingBeforeResponse=!1,this.pending===f)this.failPending(m)}})(),!0}handleBinaryChunk(f){let $=this.pending;if(!$?.responseStarted)return;$.streamController?.enqueue(n$(f))}resolvePendingResponse(f,$,_,D){if(f.responseStarted)return;f.responseStarted=!0;let m=new ReadableStream({start:(H)=>{f.streamController=H},cancel:()=>{this.socket?.close()}});f.resolve(new Response(m,{status:$,statusText:_,headers:D}))}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 _=Y();$.accepted=!0,$.acceptedAt=_,G(`perf websocket accepted session=${I(this.affinity)} request=${$.payload.id} sentMs=${A(_-$.sentAt)} mode=${$.payload.mode}`),this.serverState={hash:f.hash,revision:f.revision},kf(this.affinity,$.bodyText,f.hash,f.revision),this.resetPendingTimeout($);return}if(f.type==="response_start"){let _=Y();if($.responseStartedAt=_,G(`perf websocket response_start session=${I(this.affinity)} request=${$.payload.id} sentMs=${A(_-$.sentAt)} upstreamMs=${$.acceptedAt==null?"unknown":A(_-$.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
|
|
28
|
-
data: ${JSON.stringify({type:"error",error:{type:"relay_upstream_error",message:`Relay upstream returned HTTP ${f.status}`}})}
|
|
29
|
-
|
|
30
|
-
`)),this.finishPending();return}if(f.type==="chunk"){$.streamController?.enqueue(p$(f.base64));return}if(f.type==="done"){this.finishPending();return}if(f.type==="error"){if($.optimisticResponse&&$.responseStartedAt!=null){G(`websocket relay error during optimistic response session=${I(this.affinity)} request=${$.payload.id} status=${f.status} message=${f.message||"unknown"}`),$.streamController?.enqueue(new TextEncoder().encode(`event: error
|
|
31
|
-
data: ${JSON.stringify({type:"error",error:{type:"relay_error",message:f.message||"relay error"}})}
|
|
32
|
-
|
|
33
|
-
`)),this.finishPending(),this.socket?.close();return}if(f.status===409&&this.retryPendingBeforeResponse($,f.message||"state mismatch"))return;let _=f.status===409?new Y0(f.message||"state mismatch"):Error(f.message||"relay websocket error");this.failPending(_)}}finishPending(){let f=this.pending;if(!f)return;let $=Y();if(G(`perf websocket done session=${I(this.affinity)} request=${f.payload.id} sentMs=${A($-f.sentAt)} streamMs=${f.responseStartedAt==null?"unknown":A($-f.responseStartedAt)}`),clearTimeout(f.timeout),!f.streamDone)f.streamDone=!0,f.streamController?.close();f.resolveDone(),this.pending=void 0}failPending(f){let $=this.pending;if(!$)return;if(clearTimeout($.timeout),this.pending=void 0,$.responseStarted)$.streamController?.error(f);else $.reject(f);$.rejectDone(f)}}function v$(f,$){let _=Lf.get($);if(_)return _;let D=new Rf(f,$);return Lf.set($,D),D}async function ZD(f){let{config:$,input:_,init:D,headers:m,body:H,fallback:E,affinity:M,optimisticResponse:F}=f;if(!$||!R$(_,H))return E();let C=M||m.get("x-session-affinity")||m.get("x-opencode-session");if(!C)return G("skipping relay: missing x-session-affinity header"),E();let b=H,J=x$(b),B=T0.get(C),z=y$({input:_,init:D,headers:m,bodyText:b,affinity:C,previous:B,nextHash:J});try{let K;if($.transport==="websocket")try{K=await v$($,C).send(z,b,F===!0)}catch(U){G(`websocket relay failed session=${I(C)}; trying http relay: ${U instanceof Error?U.message:String(U)}`),K=await hf({config:$,payload:z,bodyText:b,fallback:E})}else K=await hf({config:$,payload:z,bodyText:b,fallback:E});if(!K.usedRelay)return K.response;if(K.transport==="http")kf(C,b,K.payload.next_hash,K.payload.revision);let Q=JSON.stringify(K.payload).length;return G(`used relay transport=${K.transport} protocol=${K.protocol} mode=${K.payload.mode} status=${K.response.status} session=${I(C)} bodyBytes=${b.length} relayBytes=${Q}`),await Vf({affinity:C,transport:K.transport,protocol:K.protocol,mode:K.payload.mode,status:K.response.status,bodyText:b,previousBodyText:B?.body,payload:K.payload,relayBytes:Q}),K.response}catch(K){if(!$.fallbackToDirect)throw G(`relay failed session=${I(C)} and fallbackToDirect=false: ${K instanceof Error?K.message:String(K)}`),K;return G(`relay failed; falling back direct session=${I(C)}: ${K instanceof Error?K.message:String(K)}`),E()}}var XD=`
|
|
34
|
-
async function hashBody(body) {
|
|
35
|
-
const bytes = new TextEncoder().encode(body)
|
|
36
|
-
const digest = await crypto.subtle.digest('SHA-256', bytes)
|
|
37
|
-
const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('')
|
|
38
|
-
return 'sha256:' + hex
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function applyPatch(base, patch) {
|
|
42
|
-
return base.slice(0, patch.start) + patch.insert + base.slice(patch.start + patch.deleteCount)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function applyPatchSet(base, patch) {
|
|
46
|
-
if (!Array.isArray(patch)) return applyPatch(base, patch)
|
|
47
|
-
if (patch.length === 0) return base
|
|
48
|
-
|
|
49
|
-
let result = ''
|
|
50
|
-
let cursor = 0
|
|
51
|
-
for (const item of patch) {
|
|
52
|
-
if (item.start < cursor) return { error: 'overlapping patch', status: 400 }
|
|
53
|
-
result += base.slice(cursor, item.start)
|
|
54
|
-
result += item.insert
|
|
55
|
-
cursor = item.start + item.deleteCount
|
|
56
|
-
}
|
|
57
|
-
return result + base.slice(cursor)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function readState(env, affinity) {
|
|
61
|
-
const raw = await env.RELAY_STATE.get('session:' + affinity)
|
|
62
|
-
return raw ? JSON.parse(raw) : null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function writeState(env, affinity, state) {
|
|
66
|
-
await env.RELAY_STATE.put('session:' + affinity, JSON.stringify(state), { expirationTtl: 86400 })
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function resolveBody(env, payload) {
|
|
70
|
-
if (payload.mode === 'full_sync') return payload.body
|
|
71
|
-
if (payload.mode === 'patch') {
|
|
72
|
-
const state = await readState(env, payload.affinity)
|
|
73
|
-
if (!state || state.hash !== payload.base_hash) {
|
|
74
|
-
return { error: 'state mismatch', status: 409 }
|
|
75
|
-
}
|
|
76
|
-
return applyPatchSet(state.body, payload.patch)
|
|
77
|
-
}
|
|
78
|
-
return { error: 'unknown mode', status: 400 }
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function prepareUpstream(env, payload) {
|
|
82
|
-
if ((payload.protocol !== 1 && payload.protocol !== 2) || payload.type !== 'request' || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
83
|
-
return { error: 'invalid payload', status: 400 }
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const body = await resolveBody(env, payload)
|
|
87
|
-
if (body && typeof body === 'object' && 'error' in body) return body
|
|
88
|
-
|
|
89
|
-
if (typeof body !== 'string' || (await hashBody(body)) !== payload.next_hash) {
|
|
90
|
-
return { error: 'hash mismatch', status: 409 }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const stateWrite = writeState(env, payload.affinity, { body, hash: payload.next_hash, revision: payload.revision }).catch(() => {})
|
|
94
|
-
console.log(JSON.stringify({
|
|
95
|
-
relay: 'opencode-anthropic-auth',
|
|
96
|
-
transport: 'relay',
|
|
97
|
-
mode: payload.mode,
|
|
98
|
-
revision: payload.revision,
|
|
99
|
-
affinity: String(payload.affinity).slice(0, 12),
|
|
100
|
-
bodyBytes: body.length,
|
|
101
|
-
}))
|
|
102
|
-
|
|
103
|
-
return { body, stateWrite }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function resolveBodyFromState(state, payload) {
|
|
107
|
-
if (payload.mode === 'full_sync') return payload.body
|
|
108
|
-
if (payload.mode === 'patch') {
|
|
109
|
-
if (!state || state.hash !== payload.base_hash) {
|
|
110
|
-
return { error: 'state mismatch', status: 409 }
|
|
111
|
-
}
|
|
112
|
-
return applyPatchSet(state.body, payload.patch)
|
|
113
|
-
}
|
|
114
|
-
return { error: 'unknown mode', status: 400 }
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function deferWorkerTask(task) {
|
|
118
|
-
return new Promise((resolve) => setTimeout(resolve, 0)).then(task)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function checkpointWebSocketState(env, payload, body, nextState) {
|
|
122
|
-
return deferWorkerTask(async () => {
|
|
123
|
-
try {
|
|
124
|
-
if ((await hashBody(body)) !== payload.next_hash) {
|
|
125
|
-
throw new Error('hash mismatch')
|
|
126
|
-
}
|
|
127
|
-
await writeState(env, payload.affinity, nextState)
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.log(JSON.stringify({
|
|
130
|
-
relay: 'opencode-anthropic-auth',
|
|
131
|
-
transport: 'websocket',
|
|
132
|
-
event: 'checkpoint_write_failed',
|
|
133
|
-
affinity: String(payload.affinity).slice(0, 12),
|
|
134
|
-
message: error instanceof Error ? error.message : String(error),
|
|
135
|
-
}))
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async function prepareWebSocketUpstream(env, state, payload) {
|
|
141
|
-
if (payload.protocol !== 2 || payload.type !== 'request' || !payload.id || !payload.affinity || !payload.upstream?.url || !payload.next_hash) {
|
|
142
|
-
return { error: 'invalid payload', status: 400 }
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const body = resolveBodyFromState(state, payload)
|
|
146
|
-
if (body && typeof body === 'object' && 'error' in body) return body
|
|
147
|
-
if (typeof body !== 'string') return { error: 'invalid body', status: 400 }
|
|
148
|
-
if ((await hashBody(body)) !== payload.next_hash) {
|
|
149
|
-
return { error: 'hash mismatch', status: 409 }
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const nextState = { body, hash: payload.next_hash, revision: payload.revision }
|
|
153
|
-
const checkpoint = checkpointWebSocketState(env, payload, body, nextState)
|
|
154
|
-
const logAccepted = () => console.log(JSON.stringify({
|
|
155
|
-
relay: 'opencode-anthropic-auth',
|
|
156
|
-
transport: 'websocket',
|
|
157
|
-
mode: payload.mode,
|
|
158
|
-
revision: payload.revision,
|
|
159
|
-
affinity: String(payload.affinity).slice(0, 12),
|
|
160
|
-
bodyBytes: body.length,
|
|
161
|
-
}))
|
|
162
|
-
|
|
163
|
-
return { body, state: nextState, checkpoint, logAccepted }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function headersToObject(headers) {
|
|
167
|
-
const result = {}
|
|
168
|
-
for (const [key, value] of headers.entries()) result[key] = value
|
|
169
|
-
return result
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async function handleRelayPayload(env, payload) {
|
|
173
|
-
const prepared = await prepareUpstream(env, payload)
|
|
174
|
-
if (prepared.error) return prepared
|
|
175
|
-
const upstream = await fetch(payload.upstream.url, {
|
|
176
|
-
method: payload.upstream.method || 'POST',
|
|
177
|
-
headers: payload.upstream.headers,
|
|
178
|
-
body: prepared.body,
|
|
179
|
-
})
|
|
180
|
-
return { upstream, stateWrite: prepared.stateWrite }
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function handleWebSocket(socket, env, ctx, payload, getState, setState) {
|
|
184
|
-
const heartbeat = setInterval(() => {
|
|
185
|
-
try {
|
|
186
|
-
socket.send(JSON.stringify({ protocol: 2, type: 'keepalive' }))
|
|
187
|
-
} catch {
|
|
188
|
-
clearInterval(heartbeat)
|
|
189
|
-
}
|
|
190
|
-
}, 15000)
|
|
191
|
-
try {
|
|
192
|
-
const result = await prepareWebSocketUpstream(env, getState(), payload)
|
|
193
|
-
if (result.error) {
|
|
194
|
-
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: result.status, message: result.error }))
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
setState(result.state)
|
|
199
|
-
socket.send(JSON.stringify({ protocol: 2, type: 'accepted', id: payload.id, hash: result.state.hash, revision: result.state.revision }))
|
|
200
|
-
ctx?.waitUntil?.(deferWorkerTask(result.logAccepted))
|
|
201
|
-
|
|
202
|
-
const upstreamPromise = fetch(payload.upstream.url, {
|
|
203
|
-
method: payload.upstream.method || 'POST',
|
|
204
|
-
headers: payload.upstream.headers,
|
|
205
|
-
body: result.body,
|
|
206
|
-
})
|
|
207
|
-
ctx?.waitUntil?.(result.checkpoint)
|
|
208
|
-
const upstream = await upstreamPromise
|
|
209
|
-
socket.send(JSON.stringify({
|
|
210
|
-
protocol: 2,
|
|
211
|
-
type: 'response_start',
|
|
212
|
-
id: payload.id,
|
|
213
|
-
status: upstream.status,
|
|
214
|
-
statusText: upstream.statusText,
|
|
215
|
-
headers: headersToObject(upstream.headers),
|
|
216
|
-
}))
|
|
217
|
-
|
|
218
|
-
const reader = upstream.body?.getReader()
|
|
219
|
-
if (reader) {
|
|
220
|
-
while (true) {
|
|
221
|
-
const { done, value } = await reader.read()
|
|
222
|
-
if (done) break
|
|
223
|
-
socket.send(value)
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
socket.send(JSON.stringify({ protocol: 2, type: 'done', id: payload.id }))
|
|
227
|
-
} catch (error) {
|
|
228
|
-
socket.send(JSON.stringify({ protocol: 2, type: 'error', id: payload.id, status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
229
|
-
} finally {
|
|
230
|
-
clearInterval(heartbeat)
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export default {
|
|
235
|
-
async fetch(request, env, ctx) {
|
|
236
|
-
if (request.headers.get('Upgrade') === 'websocket') {
|
|
237
|
-
const url = new URL(request.url)
|
|
238
|
-
const token = url.searchParams.get('token')
|
|
239
|
-
const affinity = url.searchParams.get('affinity')
|
|
240
|
-
if (token !== env.RELAY_TOKEN) return new Response('unauthorized', { status: 401 })
|
|
241
|
-
if (!affinity) return new Response('missing affinity', { status: 400 })
|
|
242
|
-
const pair = new WebSocketPair()
|
|
243
|
-
const client = pair[0]
|
|
244
|
-
const server = pair[1]
|
|
245
|
-
server.binaryType = 'arraybuffer'
|
|
246
|
-
let state = null
|
|
247
|
-
let ready = false
|
|
248
|
-
server.accept()
|
|
249
|
-
const loadState = readState(env, affinity).then((loadedState) => {
|
|
250
|
-
state = loadedState
|
|
251
|
-
ready = true
|
|
252
|
-
server.send(JSON.stringify({
|
|
253
|
-
protocol: 2,
|
|
254
|
-
type: 'ready',
|
|
255
|
-
state: state ? { hash: state.hash, revision: state.revision } : null,
|
|
256
|
-
}))
|
|
257
|
-
}).catch((error) => {
|
|
258
|
-
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 500, message: error instanceof Error ? error.message : String(error) }))
|
|
259
|
-
server.close(1011, 'state load failed')
|
|
260
|
-
})
|
|
261
|
-
ctx?.waitUntil?.(loadState)
|
|
262
|
-
if (!ctx?.waitUntil) void loadState
|
|
263
|
-
let busy = false
|
|
264
|
-
server.addEventListener('message', (event) => {
|
|
265
|
-
if (!ready) {
|
|
266
|
-
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 425, message: 'relay state is not ready' }))
|
|
267
|
-
return
|
|
268
|
-
}
|
|
269
|
-
if (busy) {
|
|
270
|
-
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 429, message: 'request already in flight' }))
|
|
271
|
-
return
|
|
272
|
-
}
|
|
273
|
-
let payload
|
|
274
|
-
try {
|
|
275
|
-
payload = JSON.parse(event.data)
|
|
276
|
-
} catch {
|
|
277
|
-
server.send(JSON.stringify({ protocol: 2, type: 'error', status: 400, message: 'invalid JSON payload' }))
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
payload.affinity = affinity
|
|
281
|
-
busy = true
|
|
282
|
-
const run = handleWebSocket(server, env, ctx, payload, () => state, (nextState) => { state = nextState }).finally(() => { busy = false })
|
|
283
|
-
ctx?.waitUntil?.(run)
|
|
284
|
-
if (!ctx?.waitUntil) void run
|
|
285
|
-
})
|
|
286
|
-
return new Response(null, { status: 101, webSocket: client })
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (request.method === 'GET') {
|
|
290
|
-
return Response.json({ status: 'ok', transports: ['http', 'websocket'] })
|
|
291
|
-
}
|
|
292
|
-
if (request.method !== 'POST') return new Response('method not allowed', { status: 405 })
|
|
293
|
-
if (request.headers.get('x-relay-token') !== env.RELAY_TOKEN) {
|
|
294
|
-
return new Response('unauthorized', { status: 401 })
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
const payload = await request.json()
|
|
299
|
-
const result = await handleRelayPayload(env, payload)
|
|
300
|
-
if (result.error) return Response.json({ error: result.error }, { status: result.status })
|
|
301
|
-
|
|
302
|
-
if (result.stateWrite) ctx.waitUntil(result.stateWrite)
|
|
303
|
-
|
|
304
|
-
const upstream = result.upstream
|
|
305
|
-
return new Response(upstream.body, {
|
|
306
|
-
status: upstream.status,
|
|
307
|
-
statusText: upstream.statusText,
|
|
308
|
-
headers: upstream.headers,
|
|
309
|
-
})
|
|
310
|
-
} catch (error) {
|
|
311
|
-
return Response.json(
|
|
312
|
-
{ error: error instanceof Error ? error.message : 'internal relay error' },
|
|
313
|
-
{ status: 502 },
|
|
314
|
-
)
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
}
|
|
318
|
-
`;export{c$ as a,h0 as b,d$ as c,g$ as d,s$ as e,r$ as f,x0 as g,t$ as h,o$ as i,L as j,p0 as k,__ as l,D_ as m,V as n,X as o,O as p,q,V1 as r,G_ as s,S1 as t,J_ as u,N_ as v,W_ as w,I_ as x,Q_ as y,U_ as z,Z_ as A,X_ as B,z_ as C,mf as D,w1 as E,R as F,C0 as G,i as H,A1 as I,V_ as J,a0 as K,x1 as L,Y_ as M,L_ as N,T_ as O,O_ as P,y1 as Q,q_ as R,Jf as S,n_ as T,x_ as U,P_ as V,k_ as W,Kf as X,d_ as Y,g_ as Z,C$ as _,Q0 as $,Qf as aa,K$ as ba,s_ as ca,G$ as da,$D as ea,_D as fa,z$ as ga,DD as ha,HD as ia,ED as ja,FD as ka,L$ as la,MD as ma,CD as na,KD as oa,bD as pa,QD as qa,UD as ra,ZD as sa,XD as ta};
|