Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@cortexkit/opencode-anthropic-auth

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cortexkit/opencode-anthropic-auth - npm Package Compare versions

Comparing version
1.1.3
to
1.2.0
dist/index-sebye7nt.js

Sorry, the diff of this file is too big to display

+6
-254
#!/usr/bin/env node
import { stdin as input, stdout as output } from 'node:process';
import { createInterface } from 'node:readline/promises';
import { authorize, exchange, generateRelayToken, getAccountStoragePath, loadAccounts, saveAccounts, WORKER_SCRIPT, } from '@cortexkit/anthropic-auth-core';
function defaultStorage() {
return {
version: 1,
main: { type: 'opencode', provider: 'anthropic' },
fallbackOn: [401, 403, 429],
refresh: {
enabled: true,
intervalMinutes: 10,
refreshBeforeExpiryMinutes: 240,
},
quota: {
enabled: true,
checkIntervalMinutes: 5,
minimumRemaining: {
five_hour: 10,
seven_day: 20,
},
failClosedOnUnknownQuota: true,
},
accounts: [],
};
}
function usage() {
console.log(`Usage:
import{l as y,m as w,o as l,p as u,q as m,ra as b,ta as k}from"./index-sebye7nt.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:
opencode-anthropic-auth login [label]

@@ -34,228 +8,6 @@ opencode-anthropic-auth list

Fallback accounts are stored in:
${getAccountStoragePath()}`);
}
function requireText(value, name) {
const trimmed = value?.trim();
if (!trimmed)
throw new Error(`${name} is required`);
return trimmed;
}
async function cloudflareRequest(options) {
const response = await fetch(`https://api.cloudflare.com/client/v4${options.path}`, {
method: options.method,
headers: {
authorization: `Bearer ${options.token}`,
...(options.body instanceof FormData
? {}
: { 'content-type': 'application/json' }),
...options.headers,
},
body: options.body,
});
const text = await response.text();
let data;
try {
data = JSON.parse(text);
}
catch {
throw new Error(`Cloudflare API returned ${response.status}: ${text}`);
}
if (!response.ok || data.success === false) {
const message = data.errors
?.map((error) => error.message)
.filter(Boolean)
.join('; ');
throw new Error(message || `Cloudflare API returned ${response.status}`);
}
return data.result;
}
async function createKvNamespace(token, accountId, title) {
return cloudflareRequest({
token,
method: 'POST',
path: `/accounts/${accountId}/storage/kv/namespaces`,
body: JSON.stringify({ title }),
});
}
async function uploadRelayWorker(options) {
const metadata = {
main_module: 'worker.js',
compatibility_date: '2026-04-28',
bindings: [
{
type: 'kv_namespace',
name: 'RELAY_STATE',
namespace_id: options.kvNamespaceId,
},
{
type: 'secret_text',
name: 'RELAY_TOKEN',
text: options.relayToken,
},
],
};
const form = new FormData();
form.set('metadata', JSON.stringify(metadata));
form.set('worker.js', new Blob([WORKER_SCRIPT], { type: 'application/javascript+module' }), 'worker.js');
return cloudflareRequest({
token: options.token,
method: 'PUT',
path: `/accounts/${options.accountId}/workers/scripts/${options.scriptName}`,
body: form,
});
}
async function enableWorkersDev(token, accountId, scriptName) {
await cloudflareRequest({
token,
method: 'POST',
path: `/accounts/${accountId}/workers/scripts/${scriptName}/subdomain`,
body: JSON.stringify({ enabled: true, previews_enabled: false }),
});
}
async function getWorkersSubdomain(token, accountId) {
return cloudflareRequest({
token,
method: 'GET',
path: `/accounts/${accountId}/workers/subdomain`,
}).catch(() => null);
}
async function relaySetup() {
const storage = (await loadAccounts()) ?? defaultStorage();
const token = requireText(process.env.CLOUDFLARE_API_TOKEN?.trim() ||
(await prompt('Cloudflare API token: ')), 'Cloudflare API token');
const accountId = requireText(process.env.CLOUDFLARE_ACCOUNT_ID ||
(await prompt('Cloudflare account ID: ')), 'Cloudflare account ID');
const scriptName = (await prompt('Worker name [opencode-anthropic-relay]: ')) ||
'opencode-anthropic-relay';
const kvTitle = `${scriptName}-state`;
const relayToken = generateRelayToken();
console.log('Creating Cloudflare KV namespace...');
const namespace = await createKvNamespace(token, accountId, kvTitle);
console.log('Uploading relay Worker...');
await uploadRelayWorker({
token,
accountId,
scriptName,
kvNamespaceId: namespace.id,
relayToken,
});
await enableWorkersDev(token, accountId, scriptName).catch((error) => {
console.warn(`Could not enable workers.dev automatically: ${error instanceof Error ? error.message : String(error)}`);
});
const subdomain = await getWorkersSubdomain(token, accountId);
const defaultUrl = subdomain?.subdomain
? `https://${scriptName}.${subdomain.subdomain}.workers.dev`
: '';
const url = defaultUrl ||
requireText(await prompt('Relay Worker URL: '), 'Relay Worker URL');
storage.relay = {
enabled: true,
url,
token: relayToken,
fallbackToDirect: true,
transport: 'http',
};
await saveAccounts(storage);
console.log(`Relay enabled at ${url}`);
console.log(`Config saved to ${getAccountStoragePath()}.`);
}
async function prompt(message) {
const rl = createInterface({ input, output });
try {
return (await rl.question(message)).trim();
}
finally {
rl.close();
}
}
function upsertAccount(storage, account) {
const index = storage.accounts.findIndex((candidate) => candidate.id === account.id ||
(account.label && candidate.label === account.label));
if (index >= 0) {
storage.accounts[index] = {
...storage.accounts[index],
...account,
addedAt: storage.accounts[index]?.addedAt ?? account.addedAt,
quota: account.quota,
lastRefreshedAt: account.lastRefreshedAt,
lastRefreshError: account.lastRefreshError,
lastQuotaRefreshError: account.lastQuotaRefreshError,
};
return;
}
storage.accounts.push(account);
}
async function login(labelArg) {
const storage = (await loadAccounts()) ?? defaultStorage();
const label = labelArg?.trim() || (await prompt('Fallback account label (optional): '));
const authorization = await authorize('max');
console.log('\nOpen this URL in your browser and complete Claude sign-in:\n');
console.log(`${authorization.url}\n`);
const code = await prompt('Paste the full callback URL or authorization code here: ');
const result = await exchange(code, authorization.verifier, authorization.redirectUri, authorization.state);
if (result.type === 'failed') {
throw new Error('Authentication failed');
}
const now = Date.now();
upsertAccount(storage, {
id: label || crypto.randomUUID(),
label: label || undefined,
type: 'oauth',
access: result.access,
refresh: result.refresh,
expires: result.expires,
enabled: true,
addedAt: now,
lastUsed: now,
});
await saveAccounts(storage);
console.log(`\nSaved fallback account${label ? ` "${label}"` : ''}.`);
}
async function listAccounts() {
const storage = await loadAccounts();
if (!storage?.accounts.length) {
console.log(`No fallback accounts found at ${getAccountStoragePath()}.`);
return;
}
for (const [index, account] of storage.accounts.entries()) {
const label = account.label || account.id;
const status = account.enabled === false ? 'disabled' : 'enabled';
const fiveHour = account.quota?.five_hour?.remainingPercent;
const sevenDay = account.quota?.seven_day?.remainingPercent;
const quota = fiveHour === undefined && sevenDay === undefined
? 'quota unknown'
: `5h ${fiveHour ?? '?'}%, 1w ${sevenDay ?? '?'}% remaining`;
console.log(`${index + 1}. ${label} (${status}) — ${quota}`);
}
}
async function main() {
const [command, label] = process.argv.slice(2);
if (!command ||
command === 'help' ||
command === '--help' ||
command === '-h') {
usage();
return;
}
if (command === 'login') {
await login(label);
return;
}
if (command === 'list') {
await listAccounts();
return;
}
if (command === 'relay' && label === 'setup') {
await relaySetup();
return;
}
usage();
process.exitCode = 1;
}
try {
await main();
}
catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
}
${l()}`)}function p(e,t){let a=e?.trim();if(!a)throw Error(`${t} is required`);return a}async function d(e){let t=await fetch(`https://api.cloudflare.com/client/v4${e.path}`,{method:e.method,headers:{authorization:`Bearer ${e.token}`,...e.body instanceof FormData?{}:{"content-type":"application/json"},...e.headers},body:e.body}),a=await t.text(),n;try{n=JSON.parse(a)}catch{throw Error(`Cloudflare API returned ${t.status}: ${a}`)}if(!t.ok||n.success===!1){let r=n.errors?.map((o)=>o.message).filter(Boolean).join("; ");throw Error(r||`Cloudflare API returned ${t.status}`)}return n.result}async function E(e,t,a){return d({token:e,method:"POST",path:`/accounts/${t}/storage/kv/namespaces`,body:JSON.stringify({title:a})})}async function I(e){let t={main_module:"worker.js",compatibility_date:"2026-04-28",bindings:[{type:"kv_namespace",name:"RELAY_STATE",namespace_id:e.kvNamespaceId},{type:"secret_text",name:"RELAY_TOKEN",text:e.relayToken}]},a=new FormData;return a.set("metadata",JSON.stringify(t)),a.set("worker.js",new Blob([k],{type:"application/javascript+module"}),"worker.js"),d({token:e.token,method:"PUT",path:`/accounts/${e.accountId}/workers/scripts/${e.scriptName}`,body:a})}async function T(e,t,a){await d({token:e,method:"POST",path:`/accounts/${t}/workers/scripts/${a}/subdomain`,body:JSON.stringify({enabled:!0,previews_enabled:!1})})}async function C(e,t){return d({token:e,method:"GET",path:`/accounts/${t}/workers/subdomain`}).catch(()=>null)}async function S(){let e=await u()??v(),t=p(process.env.CLOUDFLARE_API_TOKEN?.trim()||await c("Cloudflare API token: "),"Cloudflare API token"),a=p(process.env.CLOUDFLARE_ACCOUNT_ID||await c("Cloudflare account ID: "),"Cloudflare account ID"),n=await c("Worker name [opencode-anthropic-relay]: ")||"opencode-anthropic-relay",r=`${n}-state`,o=b();console.log("Creating Cloudflare KV namespace...");let s=await E(t,a,r);console.log("Uploading relay Worker..."),await I({token:t,accountId:a,scriptName:n,kvNamespaceId:s.id,relayToken:o}),await T(t,a,n).catch((f)=>{console.warn(`Could not enable workers.dev automatically: ${f instanceof Error?f.message:String(f)}`)});let i=await C(t,a),g=(i?.subdomain?`https://${n}.${i.subdomain}.workers.dev`:"")||p(await c("Relay Worker URL: "),"Relay Worker URL");e.relay={enabled:!0,url:g,token:o,fallbackToDirect:!0,transport:"http"},await m(e),console.log(`Relay enabled at ${g}`),console.log(`Config saved to ${l()}.`)}async function c(e){let t=R({input:A,output:$});try{return(await t.question(e)).trim()}finally{t.close()}}function O(e,t){let a=e.accounts.findIndex((n)=>n.id===t.id||t.label&&n.label===t.label);if(a>=0){e.accounts[a]={...e.accounts[a],...t,addedAt:e.accounts[a]?.addedAt??t.addedAt,quota:t.quota,lastRefreshedAt:t.lastRefreshedAt,lastRefreshError:t.lastRefreshError,lastQuotaRefreshError:t.lastQuotaRefreshError};return}e.accounts.push(t)}async function U(e){let t=await u()??v(),a=e?.trim()||await c("Fallback account label (optional): "),n=await y("max");console.log(`
Open this URL in your browser and complete Claude sign-in:
`),console.log(`${n.url}
`);let r=await c("Paste the full callback URL or authorization code here: "),o=await w(r,n.verifier,n.redirectUri,n.state);if(o.type==="failed")throw Error("Authentication failed");let s=Date.now();O(t,{id:a||crypto.randomUUID(),label:a||void 0,type:"oauth",access:o.access,refresh:o.refresh,expires:o.expires,enabled:!0,addedAt:s,lastUsed:s}),await m(t),console.log(`
Saved fallback account${a?` "${a}"`:""}.`)}async function _(){let e=await u();if(!e?.accounts.length){console.log(`No fallback accounts found at ${l()}.`);return}for(let[t,a]of e.accounts.entries()){let n=a.label||a.id,r=a.enabled===!1?"disabled":"enabled",o=a.quota?.five_hour?.remainingPercent,s=a.quota?.seven_day?.remainingPercent,i=o===void 0&&s===void 0?"quota unknown":`5h ${o??"?"}%, 1w ${s??"?"}% remaining`;console.log(`${t+1}. ${n} (${r}) — ${i}`)}}async function x(){let[e,t]=process.argv.slice(2);if(!e||e==="help"||e==="--help"||e==="-h"){h();return}if(e==="login"){await U(t);return}if(e==="list"){await _();return}if(e==="relay"&&t==="setup"){await S();return}h(),process.exitCode=1}try{await x()}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exitCode=1}

@@ -1,1039 +0,5 @@

import { randomUUID } from 'node:crypto';
import { acquireRefreshFileLock, authorize, buildClaudeQuotaSummary, buildFallbackQuotaSummaries, buildRefreshOperationError, CACHE_1H_COMMAND_NAME, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CLAUDE_CACHE_KEEP_COMMAND_NAME, CLAUDE_DUMP_COMMAND_NAME, CLAUDE_FAST_COMMAND_NAME, CLAUDE_QUOTAS_COMMAND_NAME, ClaudeOAuthRefreshError, exchange, executeCache1hCommand, executeCacheKeepCommand, executeDumpCommand, executeFastModeCommand, FallbackAccountManager, fetchOAuthQuotaSnapshot, formatRefreshBackoffMessage, getCache1hMode, getCache1hPersistentMode, getCacheKeepWindow, getQuotaCheckIntervalMs, getQuotaNextRefreshAt, getRelayConfig, hashRefreshToken, isCache1hEnabled, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isCacheKeepPersistentlyEnabled, isDumpPersistentlyEnabled, isFastModeEnabled, isFastModePersistentlyEnabled, isFastModeSupportedModel, loadAccounts, log, mergeAnthropicBetas, parseCache1hCommandAction, parseCacheKeepCommandAction, parseDumpCommandAction, parseFastModeCommandAction, quotaSnapshotPassesPolicy, refreshBackoffActive, refreshClaudeOAuthToken, resolveClaudeCodeIdentity, saveAccounts, sendViaRelay, setCache1hPersistentEnabled, setCache1hPersistentMode, setCache1hState, setCacheKeepPersistentEnabled, setCacheKeepPersistentWindow, setDumpEnabled, setDumpPersistentEnabled, setFastModeEnabled, setFastModePersistentEnabled, shouldFallbackStatus, } from '@cortexkit/anthropic-auth-core';
import { resolvePromptContext } from "./prompt-context.js";
import { addFastModeBetaHeader, createStrippedStream, isInsecure, mergeHeaders, rewriteRequestBody, rewriteUrl, setOAuthHeaders, } from "./transform.js";
const HANDLED_SENTINEL = '__OPENCODE_ANTHROPIC_AUTH_COMMAND_HANDLED__';
const MAIN_AUTH_REFRESH_TICK_MS = 60_000;
const MIN_MAIN_REFRESH_BEFORE_EXPIRY_MINUTES = 240;
const DEFAULT_MAIN_REFRESH_BEFORE_EXPIRY_MINUTES = MIN_MAIN_REFRESH_BEFORE_EXPIRY_MINUTES;
let nextPerfRequestId = 1;
let eventLoopLagMonitorStarted = false;
function perfLoggingEnabled() {
return process.env.OPENCODE_ANTHROPIC_AUTH_PERF === '1';
}
function nowMs() {
return performance.now();
}
function roundMs(value) {
return Math.round(value * 10) / 10;
}
function startEventLoopLagMonitor() {
if (eventLoopLagMonitorStarted ||
process.env.NODE_ENV === 'test' ||
!perfLoggingEnabled()) {
return;
}
eventLoopLagMonitorStarted = true;
const intervalMs = 100;
const thresholdMs = 250;
let expected = nowMs() + intervalMs;
setInterval(() => {
const current = nowMs();
const lag = current - expected;
expected = current + intervalMs;
if (lag < thresholdMs)
return;
log('[perf] opencode event_loop_lag', {
lagMs: roundMs(lag),
thresholdMs,
});
}, intervalMs).unref?.();
}
function createPerfTrace(data) {
const start = nowMs();
const trace = {
requestId: String(nextPerfRequestId++),
start,
last: start,
mark(stage, stageData) {
const current = nowMs();
if (perfLoggingEnabled()) {
log('[perf] opencode request stage', {
requestId: trace.requestId,
stage,
deltaMs: roundMs(current - trace.last),
totalMs: roundMs(current - trace.start),
...stageData,
});
}
trace.last = current;
},
done(stage, stageData) {
const current = nowMs();
if (perfLoggingEnabled()) {
log('[perf] opencode request done', {
requestId: trace.requestId,
stage,
deltaMs: roundMs(current - trace.last),
totalMs: roundMs(current - trace.start),
...stageData,
});
}
trace.last = current;
},
};
if (perfLoggingEnabled()) {
log('[perf] opencode request start', {
requestId: trace.requestId,
...data,
});
}
return trace;
}
async function sendIgnoredMessage(ctx, sessionId, text) {
const session = ctx.client.session;
const promptContext = await resolvePromptContext(ctx.client, sessionId);
const request = {
path: { id: sessionId },
body: {
noReply: true,
parts: [{ type: 'text', text, ignored: true }],
},
};
if (promptContext?.agent)
request.body.agent = promptContext.agent;
if (promptContext?.model)
request.body.model = promptContext.model;
if (promptContext?.variant)
request.body.variant = promptContext.variant;
if (typeof session?.promptAsync === 'function') {
await session.promptAsync(request);
return;
}
if (typeof session?.prompt === 'function') {
await Promise.resolve(session.prompt(request));
return;
}
throw new Error('OpenCode session prompt API is unavailable for ignored replies.');
}
function throwHandledSentinel() {
throw new Error(HANDLED_SENTINEL);
}
export const AnthropicAuthPlugin = async (ctx) => {
startEventLoopLagMonitor();
const { client } = ctx;
const fallbackManager = new FallbackAccountManager();
fallbackManager.startBackgroundRefresh();
let latestRefreshMainAccessToken = null;
const cacheKeepManager = new CacheKeepManager({
loadStorage: () => loadAccounts(),
prepareHeaders: async (headers, target) => {
if (!latestGetAuth)
return headers;
const auth = await latestGetAuth();
if (auth.type !== 'oauth')
return headers;
if (!auth.access || (auth.expires && auth.expires < Date.now())) {
if (!latestRefreshMainAccessToken)
return headers;
auth.access = await latestRefreshMainAccessToken();
}
if (!auth.access)
return headers;
try {
const parsedBody = JSON.parse(target.bodyText);
const identity = await resolveClaudeCodeIdentity(auth.access, typeof parsedBody.model === 'string' ? parsedBody.model : undefined);
headers.delete('anthropic-beta');
setOAuthHeaders(headers, auth.access, {
body: parsedBody,
identity,
});
headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [
CACHE_KEEP_EXTENDED_TTL_BETA,
]));
if (parsedBody.speed === 'fast')
addFastModeBetaHeader(headers);
}
catch {
setOAuthHeaders(headers, auth.access);
}
return headers;
},
log,
});
const initialCache1hStorage = await loadAccounts();
const relayConfig = getRelayConfig(initialCache1hStorage);
setCache1hState({
enabled: isCache1hPersistentlyEnabled(initialCache1hStorage),
mode: getCache1hPersistentMode(initialCache1hStorage),
});
setDumpEnabled(isDumpPersistentlyEnabled(initialCache1hStorage));
setFastModeEnabled(isFastModePersistentlyEnabled(initialCache1hStorage));
let latestGetAuth = null;
let mainBackgroundRefreshTimer = null;
function mainRefreshBeforeExpiryMs(storage) {
const minutes = storage?.refresh?.refreshBeforeExpiryMinutes ??
DEFAULT_MAIN_REFRESH_BEFORE_EXPIRY_MINUTES;
return Math.max(MIN_MAIN_REFRESH_BEFORE_EXPIRY_MINUTES, minutes) * 60_000;
}
function mainRefreshEnabled(storage) {
return storage?.refresh?.enabled !== false;
}
async function clearStaleMainRefreshError(refreshToken) {
if (!refreshToken)
return;
const storage = await loadAccounts();
const error = storage?.refresh?.mainLastRefreshError;
if (!storage?.refresh || !error?.tokenHash)
return;
const tokenHash = hashRefreshToken(refreshToken);
if (error.tokenHash === tokenHash)
return;
storage.refresh.mainLastRefreshError = undefined;
await saveAccounts(storage);
log('[refresh] opencode main oauth cleared stale backoff after token rotation', {
previousCheckedAt: error.checkedAt,
previousNextRetryAt: error.nextRetryAt,
previousRetryCount: error.retryCount,
});
}
async function buildQuotaCommandSummary() {
const accounts = [];
if (latestGetAuth) {
try {
const auth = await latestGetAuth();
if (auth.type === 'oauth' && auth.access) {
accounts.push({
name: 'OpenCode anthropic',
role: 'main',
quota: await fetchOAuthQuotaSnapshot({ accessToken: auth.access }),
});
}
else if (auth.type === 'oauth') {
accounts.push({
name: 'OpenCode anthropic',
role: 'main',
error: 'missing access token; send a request first or reconnect auth',
});
}
}
catch (error) {
accounts.push({
name: 'OpenCode anthropic',
role: 'main',
error: error instanceof Error ? error.message : String(error),
});
}
}
const { storage, errors } = await fallbackManager.refreshQuotaForAllAccounts();
accounts.push(...buildFallbackQuotaSummaries(storage, new Map(errors.map((error) => [error.accountId, error.message]))));
if (!latestGetAuth) {
accounts.unshift({
name: 'OpenCode anthropic',
role: 'main',
error: 'auth loader has not run yet; send a request first',
});
}
return buildClaudeQuotaSummary({ accounts, refreshedAt: Date.now() });
}
async function executePersistentCache1hCommand(argumentsText) {
const action = parseCache1hCommandAction(argumentsText);
if (action.type === 'enable' || action.type === 'disable') {
const enabled = action.type === 'enable';
const storage = await setCache1hPersistentEnabled(enabled);
const mode = getCache1hPersistentMode(storage);
setCache1hState({ enabled, mode });
return executeCache1hCommand({ argumentsText, enabled, mode });
}
if (action.type === 'mode') {
const storage = await setCache1hPersistentMode(action.mode);
const enabled = isCache1hPersistentlyEnabled(storage);
setCache1hState({ enabled, mode: action.mode });
return executeCache1hCommand({
argumentsText,
enabled,
mode: action.mode,
});
}
const storage = await loadAccounts();
const enabled = isCache1hPersistentlyEnabled(storage);
const mode = getCache1hPersistentMode(storage);
setCache1hState({ enabled, mode });
return executeCache1hCommand({ argumentsText, enabled, mode });
}
async function executePersistentCacheKeepCommand(argumentsText) {
const action = parseCacheKeepCommandAction(argumentsText);
let storage = await loadAccounts();
if (action.type === 'window') {
storage = await setCacheKeepPersistentWindow(action.startHour, action.endHour);
}
else if (action.type === 'disable') {
storage = await setCacheKeepPersistentEnabled(false);
}
const window = getCacheKeepWindow(storage);
const stats = cacheKeepManager.stats(window);
return executeCacheKeepCommand({
argumentsText,
enabled: isCacheKeepPersistentlyEnabled(storage),
window,
hybridActive: isCacheKeepHybridActive(storage),
trackedSessions: stats.trackedSessions,
nextPrewarmAt: stats.nextPrewarmAt,
});
}
async function executePersistentDumpCommand(argumentsText) {
const action = parseDumpCommandAction(argumentsText);
if (action.type === 'enable' || action.type === 'disable') {
const enabled = action.type === 'enable';
await setDumpPersistentEnabled(enabled);
setDumpEnabled(enabled);
return executeDumpCommand({ argumentsText, enabled });
}
const storage = await loadAccounts();
const enabled = isDumpPersistentlyEnabled(storage);
setDumpEnabled(enabled);
return executeDumpCommand({ argumentsText, enabled });
}
async function executePersistentFastModeCommand(argumentsText) {
const action = parseFastModeCommandAction(argumentsText);
if (action.type === 'enable' || action.type === 'disable') {
const enabled = action.type === 'enable';
await setFastModePersistentEnabled(enabled);
setFastModeEnabled(enabled);
return executeFastModeCommand({ argumentsText, enabled });
}
const storage = await loadAccounts();
const enabled = isFastModePersistentlyEnabled(storage);
setFastModeEnabled(enabled);
return executeFastModeCommand({ argumentsText, enabled });
}
return {
config: async (config) => {
config.command = {
...(config.command ?? {}),
[CACHE_1H_COMMAND_NAME]: {
template: CACHE_1H_COMMAND_NAME,
description: 'Show or toggle 1-hour Anthropic ephemeral prompt cache TTL.',
},
[CLAUDE_CACHE_KEEP_COMMAND_NAME]: {
template: CLAUDE_CACHE_KEEP_COMMAND_NAME,
description: 'Keep hybrid Claude cache warm for recently used sessions during a local time window.',
},
[CLAUDE_QUOTAS_COMMAND_NAME]: {
template: CLAUDE_QUOTAS_COMMAND_NAME,
description: 'Show current Claude OAuth quota usage for all accounts.',
},
[CLAUDE_DUMP_COMMAND_NAME]: {
template: CLAUDE_DUMP_COMMAND_NAME,
description: 'Show or toggle Anthropic request dump capture for debugging.',
},
[CLAUDE_FAST_COMMAND_NAME]: {
template: CLAUDE_FAST_COMMAND_NAME,
description: 'Show or toggle Anthropic fast mode for supported Opus models.',
},
};
},
'command.execute.before': async (input) => {
if (input.command === CACHE_1H_COMMAND_NAME) {
await sendIgnoredMessage(ctx, input.sessionID, await executePersistentCache1hCommand(input.arguments));
throwHandledSentinel();
}
if (input.command === CLAUDE_CACHE_KEEP_COMMAND_NAME) {
await sendIgnoredMessage(ctx, input.sessionID, await executePersistentCacheKeepCommand(input.arguments));
throwHandledSentinel();
}
if (input.command === CLAUDE_QUOTAS_COMMAND_NAME) {
await sendIgnoredMessage(ctx, input.sessionID, await buildQuotaCommandSummary());
throwHandledSentinel();
}
if (input.command === CLAUDE_DUMP_COMMAND_NAME) {
await sendIgnoredMessage(ctx, input.sessionID, await executePersistentDumpCommand(input.arguments));
throwHandledSentinel();
}
if (input.command === CLAUDE_FAST_COMMAND_NAME) {
await sendIgnoredMessage(ctx, input.sessionID, await executePersistentFastModeCommand(input.arguments));
throwHandledSentinel();
}
},
auth: {
provider: 'anthropic',
async loader(getAuth, provider) {
latestGetAuth = getAuth;
const auth = await getAuth();
if (auth.type === 'oauth') {
// zero out cost for max plan
for (const model of Object.values(provider.models)) {
model.cost = {
input: 0,
output: 0,
cache: {
read: 0,
write: 0,
},
};
}
// Shared inflight refresh promise — prevents concurrent token refreshes
// from racing against each other (and causing 401 cascades with token rotation)
let refreshPromise = null;
let mainQuotaCache = null;
let mainQuotaRefreshPromise = null;
let mainQuotaRetryAfter = 0;
async function refreshMainAccessToken() {
if (!refreshPromise) {
refreshPromise = (async () => {
const maxRetries = 2;
const baseDelayMs = 500;
let leaseId = null;
let leaseTokenHash = null;
let releaseFileLock = null;
async function updateMainRefreshState(update) {
const storage = (await loadAccounts()) ?? {
version: 1,
main: { type: 'opencode', provider: 'anthropic' },
accounts: [],
};
storage.refresh = storage.refresh ?? {};
update(storage);
await saveAccounts(storage);
}
for (let attempt = 0; attempt <= maxRetries; attempt++) {
let freshAuth = null;
try {
if (attempt > 0) {
const delay = baseDelayMs * 2 ** (attempt - 1);
await new Promise((resolve) => setTimeout(resolve, delay));
}
// Re-read auth to get the latest refresh token.
// The outer `auth` snapshot may be stale if tokens
// were rotated since the fetch() call was made.
freshAuth = await getAuth();
if (!freshAuth.refresh) {
throw new Error('Token refresh failed: missing refresh token');
}
const storage = await loadAccounts();
const refreshTokenHash = hashRefreshToken(freshAuth.refresh);
const mainError = storage?.refresh?.mainLastRefreshError;
log('[refresh] opencode main oauth refresh check', {
attempt,
expiresInMs: freshAuth.expires
? freshAuth.expires - Date.now()
: undefined,
hasBackoff: Boolean(mainError),
backoffActive: mainError
? refreshBackoffActive(mainError, freshAuth.refresh, Date.now())
: false,
retryCount: mainError?.retryCount,
nextRetryAt: mainError?.nextRetryAt,
});
if (mainError &&
refreshBackoffActive(mainError, freshAuth.refresh, Date.now())) {
log('[refresh] opencode main oauth refresh skipped backoff', {
nextRetryAt: mainError.nextRetryAt,
retryCount: mainError.retryCount,
});
throw new Error(formatRefreshBackoffMessage(mainError, Date.now()));
}
if (storage?.refresh?.mainRefreshLeaseUntil &&
storage.refresh.mainRefreshLeaseUntil > Date.now() &&
storage.refresh.mainRefreshLeaseTokenHash ===
refreshTokenHash) {
log('[refresh] opencode main oauth refresh skipped lease', {
leaseUntil: storage.refresh.mainRefreshLeaseUntil,
});
throw new Error('Claude OAuth refresh is already in progress');
}
const fileLock = await acquireRefreshFileLock({
name: 'opencode-main-oauth-refresh',
ttlMs: 2 * 60_000,
});
if (!fileLock) {
log('[refresh] opencode main oauth refresh skipped file lock');
throw new Error('Claude OAuth refresh is already in progress');
}
releaseFileLock = fileLock.release;
leaseId = randomUUID();
leaseTokenHash = refreshTokenHash;
await updateMainRefreshState((nextStorage) => {
nextStorage.refresh = nextStorage.refresh ?? {};
nextStorage.refresh.mainRefreshLeaseId =
leaseId ?? undefined;
nextStorage.refresh.mainRefreshLeaseUntil =
Date.now() + 2 * 60_000;
nextStorage.refresh.mainRefreshLeaseTokenHash =
refreshTokenHash;
});
const latestLease = await loadAccounts();
log('[refresh] opencode main oauth refresh lease acquired', {
attempt,
leaseUntil: Date.now() + 2 * 60_000,
});
if (latestLease?.refresh?.mainRefreshLeaseId !== leaseId ||
latestLease.refresh.mainRefreshLeaseTokenHash !==
refreshTokenHash) {
throw new Error('Claude OAuth refresh is already in progress');
}
log('[refresh] opencode main oauth refresh request start', {
attempt,
});
const refreshed = await refreshClaudeOAuthToken({
refreshToken: freshAuth.refresh,
});
// biome-ignore lint/suspicious/noExplicitAny: SDK types don't expose auth.set
await client.auth.set({
path: {
id: 'anthropic',
},
body: {
type: 'oauth',
refresh: refreshed.refresh,
access: refreshed.access,
expires: refreshed.expires,
},
});
await updateMainRefreshState((storage) => {
if (!storage?.refresh)
return;
storage.refresh.mainLastRefreshError = undefined;
if (storage.refresh.mainRefreshLeaseId === leaseId) {
storage.refresh.mainRefreshLeaseId = undefined;
storage.refresh.mainRefreshLeaseUntil = undefined;
storage.refresh.mainRefreshLeaseTokenHash = undefined;
}
});
log('[refresh] opencode main oauth refresh succeeded', {
attempt,
expiresInMs: refreshed.expires - Date.now(),
});
return refreshed.access;
}
catch (error) {
const isNetworkError = error instanceof Error &&
(error.message.includes('fetch failed') ||
('code' in error &&
(error.code === 'ECONNRESET' ||
error.code === 'ECONNREFUSED' ||
error.code === 'ETIMEDOUT' ||
error.code === 'UND_ERR_CONNECT_TIMEOUT')));
if (attempt < maxRetries &&
(isNetworkError ||
(error instanceof ClaudeOAuthRefreshError &&
error.status >= 500))) {
continue;
}
log('[refresh] opencode main oauth refresh attempt failed', {
attempt,
error: error instanceof Error
? error.message
: String(error),
transient: isNetworkError,
});
const failedRefreshToken = freshAuth?.refresh;
if (failedRefreshToken &&
error instanceof ClaudeOAuthRefreshError) {
await updateMainRefreshState((storage) => {
storage.refresh = storage.refresh ?? {};
storage.refresh.mainLastRefreshError =
buildRefreshOperationError({
error,
now: Date.now(),
refreshToken: failedRefreshToken,
previous: storage.refresh.mainLastRefreshError,
});
});
}
throw error;
}
finally {
if (leaseId) {
await updateMainRefreshState((storage) => {
if (!storage?.refresh)
return;
if (storage.refresh.mainRefreshLeaseId === leaseId &&
storage.refresh.mainRefreshLeaseTokenHash ===
leaseTokenHash) {
storage.refresh.mainRefreshLeaseId = undefined;
storage.refresh.mainRefreshLeaseUntil = undefined;
storage.refresh.mainRefreshLeaseTokenHash = undefined;
}
}).catch(() => { });
}
await releaseFileLock?.().catch(() => { });
}
}
// Unreachable — each iteration either returns or throws.
// Kept as a TypeScript exhaustiveness guard.
throw new Error('Token refresh exhausted all retries');
})().finally(() => {
refreshPromise = null;
});
}
return refreshPromise;
}
latestRefreshMainAccessToken = refreshMainAccessToken;
function startMainBackgroundRefresh() {
if (mainBackgroundRefreshTimer) {
clearInterval(mainBackgroundRefreshTimer);
mainBackgroundRefreshTimer = null;
}
const run = async () => {
try {
const storage = await loadAccounts();
if (!mainRefreshEnabled(storage))
return;
const latestAuth = await getAuth();
if (latestAuth.type !== 'oauth')
return;
await clearStaleMainRefreshError(latestAuth.refresh);
if (!latestAuth.expires)
return;
const expiresInMs = latestAuth.expires - Date.now();
const refreshBeforeMs = mainRefreshBeforeExpiryMs(storage);
if (expiresInMs > refreshBeforeMs) {
return;
}
log('[refresh] opencode main oauth background due', {
expiresInMs,
refreshBeforeMs,
});
if (latestAuth.refresh &&
refreshBackoffActive(storage?.refresh?.mainLastRefreshError, latestAuth.refresh, Date.now())) {
log('[refresh] opencode main oauth background skipped backoff', {
nextRetryAt: storage?.refresh?.mainLastRefreshError?.nextRetryAt,
retryCount: storage?.refresh?.mainLastRefreshError?.retryCount,
});
return;
}
if (latestAuth.refresh &&
storage?.refresh?.mainRefreshLeaseUntil &&
storage.refresh.mainRefreshLeaseUntil > Date.now() &&
storage.refresh.mainRefreshLeaseTokenHash ===
hashRefreshToken(latestAuth.refresh)) {
return;
}
await refreshMainAccessToken();
log('[refresh] opencode main oauth refreshed in background', {
expires: latestAuth.expires,
});
}
catch (error) {
log('[refresh] opencode main oauth refresh failed', {
message: error instanceof Error ? error.message : String(error),
});
}
};
mainBackgroundRefreshTimer = setInterval(() => {
void run();
}, MAIN_AUTH_REFRESH_TICK_MS);
if ('unref' in mainBackgroundRefreshTimer) {
mainBackgroundRefreshTimer.unref();
}
}
startMainBackgroundRefresh();
function isReplayableRequest(input, body) {
if (input instanceof Request && input.body)
return false;
return body == null || typeof body === 'string';
}
function isSubagentRequest(headers) {
return headers.has('x-parent-session-id');
}
function isStreamingRateLimitText(text) {
return (text.includes('rate_limit_error') ||
/exceed your account'?s rate limit/i.test(text));
}
function mainQuotaRoutingEnabled(storage) {
return storage?.quota?.enabled === true;
}
async function inspectStreamingRateLimit(response, trace) {
if (!response.body || response.status !== 200) {
trace?.mark('inspect_stream_skip', { status: response.status });
return { response, rateLimited: false };
}
if (response.headers.get('x-cortexkit-relay-optimistic') === 'true') {
trace?.mark('inspect_stream_skip', {
status: response.status,
reason: 'optimistic_relay',
});
return { response, rateLimited: false };
}
const start = nowMs();
const reader = response.body.getReader();
const chunks = [];
const decoder = new TextDecoder();
let text = '';
let bytes = 0;
while (!text.includes('\n\n') && text.length < 65_536) {
const { done, value } = await reader.read();
if (done)
break;
chunks.push(value);
bytes += value.byteLength;
text += decoder.decode(value, { stream: true });
if (isStreamingRateLimitText(text))
break;
}
if (isStreamingRateLimitText(text)) {
await reader.cancel().catch(() => { });
trace?.mark('inspect_stream_first_event', {
ms: roundMs(nowMs() - start),
bytes,
rateLimited: true,
});
return { response, rateLimited: true };
}
const stream = new ReadableStream({
start(controller) {
for (const chunk of chunks)
controller.enqueue(chunk);
},
async pull(controller) {
const { done, value } = await reader.read();
if (done) {
controller.close();
return;
}
controller.enqueue(value);
},
cancel(reason) {
return reader.cancel(reason);
},
});
trace?.mark('inspect_stream_first_event', {
ms: roundMs(nowMs() - start),
bytes,
rateLimited: false,
});
return {
response: new Response(stream, {
status: response.status,
statusText: response.statusText,
headers: response.headers,
}),
rateLimited: false,
};
}
async function sendWithAccessToken(input, init, accessToken, trace, route = 'unknown') {
const start = nowMs();
const requestHeaders = mergeHeaders(input, init);
const relayAffinity = requestHeaders.get('x-session-affinity') ||
requestHeaders.get('x-opencode-session');
const subagentRequest = isSubagentRequest(requestHeaders);
requestHeaders.delete('x-parent-session-id');
requestHeaders.delete('x-session-affinity');
requestHeaders.delete('x-opencode-session');
let body = init?.body;
let modelForIdentity;
if (body && typeof body === 'string') {
try {
const parsedBody = JSON.parse(body);
if (typeof parsedBody.model === 'string') {
modelForIdentity = parsedBody.model;
}
}
catch { }
}
const identity = await resolveClaudeCodeIdentity(accessToken, modelForIdentity);
const originalBytes = typeof body === 'string' ? body.length : undefined;
if (body && typeof body === 'string') {
const rewriteStart = nowMs();
const fastModeRequested = (() => {
if (!isFastModeEnabled())
return false;
try {
return isFastModeSupportedModel(JSON.parse(body).model);
}
catch {
return false;
}
})();
body = await rewriteRequestBody(body, {
cache1hEnabled: !subagentRequest && isCache1hEnabled(),
cache1hMode: getCache1hMode(),
fastModeEnabled: fastModeRequested,
identity,
});
try {
setOAuthHeaders(requestHeaders, accessToken, {
body: JSON.parse(body),
identity,
});
}
catch {
setOAuthHeaders(requestHeaders, accessToken, { identity });
}
if (fastModeRequested)
addFastModeBetaHeader(requestHeaders);
trace?.mark('rewrite_body', {
route,
ms: roundMs(nowMs() - rewriteStart),
originalBytes,
rewrittenBytes: body.length,
cacheEnabled: !subagentRequest && isCache1hEnabled(),
cacheMode: getCache1hMode(),
fastModeEnabled: fastModeRequested,
subagent: subagentRequest,
});
}
const rewritten = rewriteUrl(input);
if (route === 'main' &&
typeof body === 'string' &&
!subagentRequest &&
isCache1hEnabled() &&
getCache1hMode() === 'hybrid') {
const storage = await loadAccounts();
const tracked = await cacheKeepManager.track({
sessionId: relayAffinity,
url: rewritten.url?.toString() ?? rewritten.input.toString(),
headers: requestHeaders,
bodyText: body,
storage,
cacheMode: 'hybrid',
});
if (tracked.tracked) {
trace?.mark('cachekeep_track', { session: relayAffinity });
}
}
const directFetch = () => fetch(rewritten.input, {
...init,
body,
headers: requestHeaders,
...(isInsecure() && { tls: { rejectUnauthorized: false } }),
});
const sendStart = nowMs();
const response = await sendViaRelay({
config: relayConfig,
input: rewritten.input,
init,
headers: requestHeaders,
body,
fallback: directFetch,
affinity: relayAffinity,
optimisticResponse: relayConfig?.transport === 'websocket',
});
trace?.mark('send_headers_received', {
route,
ms: roundMs(nowMs() - sendStart),
status: response.status,
relayConfigured: relayConfig != null,
totalSendWithAccessMs: roundMs(nowMs() - start),
});
return response;
}
async function refreshMainQuotaCache(accessToken, storage) {
const now = Date.now();
const quota = await fetchOAuthQuotaSnapshot({ accessToken });
mainQuotaCache = {
accessToken,
refreshAfter: getQuotaNextRefreshAt(quota, storage, now),
quota,
};
return quota;
}
function refreshMainQuotaCacheInBackground(accessToken, storage) {
const now = Date.now();
if (mainQuotaRefreshPromise || now < mainQuotaRetryAfter)
return;
mainQuotaRefreshPromise = refreshMainQuotaCache(accessToken, storage)
.catch((error) => {
mainQuotaRetryAfter = now + getQuotaCheckIntervalMs(storage);
throw error;
})
.finally(() => {
mainQuotaRefreshPromise = null;
});
void mainQuotaRefreshPromise.catch(() => { });
}
async function getMainQuotaForRouting(accessToken, storage) {
const now = Date.now();
if (mainQuotaCache?.accessToken !== accessToken) {
return await refreshMainQuotaCache(accessToken, storage);
}
if (now >= mainQuotaCache.refreshAfter) {
refreshMainQuotaCacheInBackground(accessToken, storage);
}
return mainQuotaCache.quota;
}
async function tryUsableFallbackAccounts(input, init, accounts, storage, currentResponse, trace) {
if (!accounts.length)
return currentResponse ?? null;
await currentResponse?.body?.cancel().catch(() => { });
let lastResponse = currentResponse ?? null;
for (const [index, account] of accounts.entries()) {
const access = account.access;
if (!access)
continue;
let response = await sendWithAccessToken(input, init, access, trace, `fallback_${index}`);
lastResponse = response;
let fallbackAgain = shouldFallbackStatus(response.status, storage);
if (!fallbackAgain) {
const inspected = await inspectStreamingRateLimit(response, trace);
response = inspected.response;
lastResponse = response;
fallbackAgain = inspected.rateLimited;
}
if (!fallbackAgain) {
await fallbackManager.markUsed(account);
return response;
}
if (index < accounts.length - 1) {
await response.body?.cancel().catch(() => { });
}
}
return lastResponse;
}
async function tryFallbackAccounts(input, init, mainResponse, preselectedAccounts, trace) {
if (!isReplayableRequest(input, init?.body))
return mainResponse;
const loadStart = nowMs();
const storage = await loadAccounts();
trace?.mark('fallback_load_storage', {
ms: roundMs(nowMs() - loadStart),
});
let currentResponse = mainResponse;
let shouldFallback = shouldFallbackStatus(currentResponse.status, storage);
if (!shouldFallback) {
const inspected = await inspectStreamingRateLimit(currentResponse, trace);
currentResponse = inspected.response;
shouldFallback = inspected.rateLimited;
}
if (!shouldFallback) {
return currentResponse;
}
let accounts = preselectedAccounts;
if (!accounts) {
const accountsStart = nowMs();
accounts = await fallbackManager.getUsableFallbackAccounts();
trace?.mark('fallback_get_accounts', {
ms: roundMs(nowMs() - accountsStart),
accounts: accounts.length,
});
}
return ((await tryUsableFallbackAccounts(input, init, accounts, storage, currentResponse, trace)) ?? currentResponse);
}
return {
apiKey: '',
async fetch(input, init) {
const initialBody = init?.body;
const trace = createPerfTrace({
bodyBytes: typeof initialBody === 'string'
? initialBody.length
: undefined,
relayConfigured: relayConfig != null,
});
const authStart = nowMs();
const auth = await getAuth();
trace.mark('get_auth', {
ms: roundMs(nowMs() - authStart),
authType: auth.type,
hasAccess: Boolean(auth.access),
});
if (auth.type !== 'oauth') {
const response = await fetch(input, init);
trace.done('non_oauth_passthrough', { status: response.status });
return response;
}
await clearStaleMainRefreshError(auth.refresh);
if (!auth.access || !auth.expires || auth.expires < Date.now()) {
log('[refresh] opencode main oauth refresh required for request', {
hasAccess: Boolean(auth.access),
expiresInMs: auth.expires
? auth.expires - Date.now()
: undefined,
});
const refreshStart = nowMs();
auth.access = await refreshMainAccessToken();
trace.mark('refresh_main_access', {
ms: roundMs(nowMs() - refreshStart),
});
}
if (!auth.access) {
trace.done('missing_access_error');
throw new Error('OAuth access token is missing after refresh');
}
const loadStart = nowMs();
const storage = await loadAccounts();
trace.mark('load_storage', { ms: roundMs(nowMs() - loadStart) });
let preselectedFallbackAccounts;
if (isReplayableRequest(input, init?.body) &&
mainQuotaRoutingEnabled(storage)) {
try {
const quotaStart = nowMs();
const mainQuota = await getMainQuotaForRouting(auth.access, storage);
trace.mark('main_quota_for_routing', {
ms: roundMs(nowMs() - quotaStart),
passes: quotaSnapshotPassesPolicy(mainQuota, storage),
});
if (!quotaSnapshotPassesPolicy(mainQuota, storage)) {
const fallbackStart = nowMs();
preselectedFallbackAccounts =
await fallbackManager.getUsableFallbackAccounts();
trace.mark('preselect_fallback_accounts', {
ms: roundMs(nowMs() - fallbackStart),
accounts: preselectedFallbackAccounts.length,
});
const fallbackResponse = await tryUsableFallbackAccounts(input, init, preselectedFallbackAccounts, storage, undefined, trace);
if (fallbackResponse) {
trace.done('return_preselected_fallback', {
status: fallbackResponse.status,
});
return createStrippedStream(fallbackResponse);
}
}
}
catch (error) {
trace.mark('main_quota_for_routing_error', {
error: error instanceof Error ? error.message : String(error),
});
// Main quota checks should optimize routing, not break requests.
}
}
const mainResponse = await sendWithAccessToken(input, init, auth.access, trace, 'main');
const response = await tryFallbackAccounts(input, init, mainResponse, preselectedFallbackAccounts, trace);
trace.done('return_response', { status: response.status });
return createStrippedStream(response);
},
};
}
return {};
},
methods: [
{
label: 'Claude Pro/Max',
type: 'oauth',
authorize: async () => {
const result = await authorize('max');
return {
url: result.url,
instructions: 'Paste the authorization code here:',
method: 'code',
callback: async (code) => {
return exchange(code, result.verifier, result.redirectUri, result.state);
},
};
},
},
{
label: 'Create an API Key',
type: 'oauth',
authorize: async () => {
const result = await authorize('console');
return {
url: result.url,
instructions: 'Paste the authorization code here:',
method: 'code',
callback: async (code) => {
const credentials = await exchange(code, result.verifier, result.redirectUri, result.state);
if (credentials.type === 'failed')
return credentials;
const apiKey = await fetch(`https://api.anthropic.com/api/oauth/claude_cli/create_api_key`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
authorization: `Bearer ${credentials.access}`,
},
}).then((r) => r.json());
return { type: 'success', key: apiKey.raw_key };
},
};
},
},
{
provider: 'anthropic',
label: 'Manually enter API Key',
type: 'api',
},
],
},
// biome-ignore lint/suspicious/noExplicitAny: Plugin type doesn't include undocumented auth/hooks
};
};
import{$ as H1,A as Q1,B as L1,C as x0,D as j0,E as v1,F as J0,G as N1,H as _1,I as H0,J as F1,K as q0,L as M1,M as K0,N as Z0,O as $0,P as l,Q as B1,R as G0,S as s0,T as e0,U as S0,V as j1,W as J1,X as K1,Y as D0,Z as U1,_ as x1,a as p0,aa as q1,b as c0,ba as S1,c as a,ca as A1,d as r,da as E1,e as o0,ea as V0,f as u,fa as P0,g as t0,ga as R1,h as a0,ha as A0,i as r0,ia as X0,j as N0,ja as f1,k as W1,ka as W0,l as _0,la as C1,m as F0,ma as E0,n as H,na as Y0,oa as T1,p as S,pa as y1,q as M0,qa as k1,r as Y1,s,sa as g1,t as e,u as w1,v as z1,w as B0,x as I1,y as U0,z as O1}from"./index-sebye7nt.js";import{randomUUID as Pj}from"node:crypto";function m(j){return typeof j==="object"&&j!==null}function a1(j){if(Array.isArray(j))return j;if(m(j)&&Array.isArray(j.data))return j.data;return[]}function r1(j){if(!m(j)||!m(j.info))return;return typeof j.info.role==="string"?j.info.role:void 0}function m0(j){if(!m(j)||!m(j.info))return null;let J=j.info,K=m(J.model)?J.model:void 0,Z=typeof J.agent==="string"?J.agent:void 0,G=typeof K?.providerID==="string"?K.providerID:typeof J.providerID==="string"?J.providerID:void 0,D=typeof K?.modelID==="string"?K.modelID:typeof J.modelID==="string"?J.modelID:void 0,F=typeof K?.variant==="string"?K.variant:typeof J.variant==="string"?J.variant:void 0;if(!Z&&(!G||!D)&&!F)return null;let A={};if(Z)A.agent=Z;if(G&&D)A.model={providerID:G,modelID:D};if(F)A.variant=F;return A}function b0(j,J){return{agent:j.agent??J.agent,model:j.model??J.model,variant:j.variant??J.variant}}function h0(j){return Boolean(j.agent&&j.model&&j.variant)}async function u0(j,J){if(!j||!J)return null;let K=j;if(typeof K.session?.messages!=="function")return null;let Z=[];try{Z=a1(await Promise.resolve(K.session.messages({path:{id:J},query:{limit:100}})))}catch{return null}if(Z.length===0)return null;let G={};for(let D=Z.length-1;D>=0;D--){if(r1(Z[D])!=="assistant")continue;let F=m0(Z[D]);if(!F)continue;if(G=b0(G,F),h0(G))return G}for(let D=Z.length-1;D>=0;D--){let F=m0(Z[D]);if(!F)continue;if(G=b0(G,F),h0(G))return G}if(!G.agent&&!G.model&&!G.variant)return null;return G}function d0(j){return`${p0}${j.charAt(0).toUpperCase()}${j.slice(1)}`}function s1(j){if(j==="StructuredOutput")return j;return`${j.charAt(0).toLowerCase()}${j.slice(1)}`}function Z1(j,J){let K=new Headers;if(j instanceof Request)j.headers.forEach((G,D)=>{K.set(D,G)});let Z=J?.headers;if(Z){if(Z instanceof Headers)Z.forEach((G,D)=>{K.set(D,G)});else if(Array.isArray(Z))for(let G of Z){let[D,F]=G;if(typeof F<"u")K.set(D,String(F))}else for(let[G,D]of Object.entries(Z))if(typeof D<"u")K.set(G,String(D))}return K}function L0(j){return j.set("anthropic-beta",a(j.get("anthropic-beta"),[c0])),j}function d(j,J,K={}){return J1(j,J,K)}function e1(j){if(j.tools&&Array.isArray(j.tools))j.tools=j.tools.map((J)=>({...J,name:J.name?d0(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:d0(K.name)};return K});return J});return JSON.stringify(K1(j))}function O0(j){return j.replace(/"name"\s*:\s*"mcp_([^"]+)"/g,(J,K)=>`"name": "${s1(K)}"`)}function n0(j,J=!1){if(J)return{ready:O0(j),pending:""};let K=j.length,Z='"name"',G=Math.max(0,j.length-Z.length+1);for(let F=G;F<j.length;F++)if(Z.startsWith(j.slice(F))){K=Math.min(K,F);break}let D=j.lastIndexOf(Z);if(D!==-1){let F=j.slice(D);if(/^"name"\s*(?::\s*(?:"[^"]*)?)?$/.test(F))K=Math.min(K,D)}if(K<j.length)return{ready:O0(j.slice(0,K)),pending:j.slice(K)};return{ready:O0(j),pending:""}}function $1(){if(!process.env.ANTHROPIC_BASE_URL?.trim())return!1;let j=process.env.ANTHROPIC_INSECURE?.trim();return j==="1"||j==="true"}function jj(){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 G1(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,Z=jj();if(Z)J.protocol=Z.protocol,J.host=Z.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 c(j){let Z=j.split(/\n\n+/).filter((G)=>{if(G.includes(o0))return!1;for(let D of a0)if(G.includes(D))return!1;return!0}).join(`
`);for(let G of r0)Z=Z.replace(G.match,G.replacement);return Z.trim()}function E(j){return j!=null&&typeof j==="object"&&!Array.isArray(j)}function Jj(j){let J={type:"text",text:u};if(j==null)return[J];if(typeof j==="string"){let Z=c(j);if(Z===u)return[J];return[J,{type:"text",text:Z}]}if(E(j)){let Z=typeof j.type==="string"?j.type:"text",G=typeof j.text==="string"?j.text:"";return[J,{...j,type:Z,text:c(G)}]}if(!Array.isArray(j))return[J];let K=j.map((Z)=>{if(typeof Z==="string")return{type:"text",text:c(Z)};if(E(Z)&&Z.type==="text"&&typeof Z.text==="string")return{...Z,type:"text",text:c(Z.text)};return{type:"text",text:String(Z)}});if(K[0]?.text===u)return K;return[J,...K]}var D1={type:"ephemeral",ttl:"1h"};function Kj(j){if(E(j.cache_control))return j.cache_control;if(E(j.cacheControl))return j.cacheControl;return null}function t(j,J){if(!E(j))return!1;return delete j.cacheControl,j.cache_control=J?{...D1}:{type:"ephemeral"},!0}function i0(j){if(!E(j))return;delete j.cache_control,delete j.cacheControl}function Zj(j){if(Array.isArray(j))return j;if(typeof j==="string")return[{type:"text",text:j}];return null}function o(j,J){if(!E(j))return;let K=Kj(j);if(!K||K.type!=="ephemeral")return;if(J)K.ttl="1h";else delete K.ttl}function l0(j,J){if(Array.isArray(j.system))for(let K of j.system)o(K,J);else o(j.system,J);if(!Array.isArray(j.messages))return;for(let K of j.messages)if(o(K,J),E(K)&&Array.isArray(K.content))for(let Z of K.content)o(Z,J)}function $j(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),E(K)&&Array.isArray(K.content))for(let Z of K.content)J(Z)}function V1(j){i0(j),$j(j,i0)}function Gj(j){V1(j),j.cache_control={...D1}}function Q0(j){if(!E(j))return!1;let J=Zj(j.content);if(!J?.length)return t(j,!0);j.content=J;let K=[...J].reverse().find((Z)=>E(Z)&&Z.type!=="thinking");return t(K??j,!0)}function Dj(j){if(V1(j),Array.isArray(j.system)){let K=j.system.findIndex((D)=>E(D)&&D.text===u),Z=j.system.slice(K>=0?K+1:0).filter(E),G=Z[Z.length-1];t(G,!0)}else t(j.system,!0);if(!Array.isArray(j.messages))return;Q0(j.messages[0]),Q0(j.messages[1]);let J=j.messages.length-2;if(J>1)Q0(j.messages[J])}function Vj(j,J){if(!J.enabled){l0(j,!1),delete j.cache_control,delete j.cacheControl;return}if(J.mode==="automatic"){Gj(j);return}if(J.mode==="hybrid"){Dj(j);return}l0(j,!0),delete j.cacheControl}async function P1(j,J={}){try{let K=JSON.parse(j),Z=Array.isArray(K.messages)&&K.messages.some((G)=>G.role==="user")?e0(K.messages,void 0,t0):null;if(K.system=Jj(K.system),Z&&Array.isArray(K.system))K.system.unshift({type:"text",text:Z});if(Vj(K,{enabled:J.cache1hEnabled??!1,mode:J.cache1hMode??"explicit"}),J.fastModeEnabled&&r(K.model))K.speed="fast";else if(K.speed==="fast")delete K.speed;if(J.identity)j1(K,J.identity);return await s0(e1(K))}catch{return j}}function v0(j){if(!j.body)return j;let J=j.body.getReader(),K=new TextDecoder,Z=new TextEncoder,G="",D=new ReadableStream({async pull(F){let{done:A,value:T}=await J.read();if(A){let h=n0(`${G}${K.decode()}`,!0);if(h.ready)F.enqueue(Z.encode(h.ready));F.close();return}let z0=G+K.decode(T,{stream:!0}),b=n0(z0);if(G=b.pending,b.ready)F.enqueue(Z.encode(b.ready))}});return new Response(D,{status:j.status,statusText:j.statusText,headers:j.headers})}var Xj="__OPENCODE_ANTHROPIC_AUTH_COMMAND_HANDLED__",Wj=60000,m1=240,Yj=m1,wj=1,X1=!1;function w0(){return process.env.OPENCODE_ANTHROPIC_AUTH_PERF==="1"}function M(){return performance.now()}function q(j){return Math.round(j*10)/10}function zj(){if(X1||!1||!w0())return;X1=!0;let j=100,J=250,K=M()+j;setInterval(()=>{let Z=M(),G=Z-K;if(K=Z+j,G<J)return;H("[perf] opencode event_loop_lag",{lagMs:q(G),thresholdMs:J})},j).unref?.()}function Ij(j){let J=M(),K={requestId:String(wj++),start:J,last:J,mark(Z,G){let D=M();if(w0())H("[perf] opencode request stage",{requestId:K.requestId,stage:Z,deltaMs:q(D-K.last),totalMs:q(D-K.start),...G});K.last=D},done(Z,G){let D=M();if(w0())H("[perf] opencode request done",{requestId:K.requestId,stage:Z,deltaMs:q(D-K.last),totalMs:q(D-K.start),...G});K.last=D}};if(w0())H("[perf] opencode request start",{requestId:K.requestId,...j});return K}async function n(j,J,K){let Z=j.client.session,G=await u0(j.client,J),D={path:{id:J},body:{noReply:!0,parts:[{type:"text",text:K,ignored:!0}]}};if(G?.agent)D.body.agent=G.agent;if(G?.model)D.body.model=G.model;if(G?.variant)D.body.variant=G.variant;if(typeof Z?.promptAsync==="function"){await Z.promptAsync(D);return}if(typeof Z?.prompt==="function"){await Promise.resolve(Z.prompt(D));return}throw Error("OpenCode session prompt API is unavailable for ignored replies.")}function i(){throw Error(Xj)}var Bj=async(j)=>{zj();let{client:J}=j,K=new M1;K.startBackgroundRefresh();let Z=null,G=new E1({loadStorage:()=>S(),prepareHeaders:async($,O)=>{if(!A)return $;let L=await A();if(L.type!=="oauth")return $;if(!L.access||L.expires&&L.expires<Date.now()){if(!Z)return $;L.access=await Z()}if(!L.access)return $;try{let Q=JSON.parse(O.bodyText),U=await S0(L.access,typeof Q.model==="string"?Q.model:void 0);if($.delete("anthropic-beta"),d($,L.access,{body:Q,identity:U}),$.set("anthropic-beta",a($.get("anthropic-beta"),[U1])),Q.speed==="fast")L0($)}catch{d($,L.access)}return $},log:H}),D=await S(),F=k1(D);l({enabled:s(D),mode:e(D)}),P0(B0(D)),W0(U0(D));let A=null,T=null;function z0($){let O=$?.refresh?.refreshBeforeExpiryMinutes??Yj;return Math.max(m1,O)*60000}function b($){return $?.refresh?.enabled!==!1}async function h($){if(!$)return;let O=await S(),L=O?.refresh?.mainLastRefreshError;if(!O?.refresh||!L?.tokenHash)return;let Q=j0($);if(L.tokenHash===Q)return;O.refresh.mainLastRefreshError=void 0,await M0(O),H("[refresh] opencode main oauth cleared stale backoff after token rotation",{previousCheckedAt:L.checkedAt,previousNextRetryAt:L.nextRetryAt,previousRetryCount:L.retryCount})}async function b1(){let $=[];if(A)try{let Q=await A();if(Q.type==="oauth"&&Q.access)$.push({name:"OpenCode anthropic",role:"main",quota:await q0({accessToken:Q.access})});else if(Q.type==="oauth")$.push({name:"OpenCode anthropic",role:"main",error:"missing access token; send a request first or reconnect auth"})}catch(Q){$.push({name:"OpenCode anthropic",role:"main",error:Q instanceof Error?Q.message:String(Q)})}let{storage:O,errors:L}=await K.refreshQuotaForAllAccounts();if($.push(...T1(O,new Map(L.map((Q)=>[Q.accountId,Q.message])))),!A)$.unshift({name:"OpenCode anthropic",role:"main",error:"auth loader has not run yet; send a request first"});return y1({accounts:$,refreshedAt:Date.now()})}async function h1($){let O=B1($);if(O.type==="enable"||O.type==="disable"){let f=O.type==="enable",y=await w1(f),k=e(y);return l({enabled:f,mode:k}),G0({argumentsText:$,enabled:f,mode:k})}if(O.type==="mode"){let f=await z1(O.mode),y=s(f);return l({enabled:y,mode:O.mode}),G0({argumentsText:$,enabled:y,mode:O.mode})}let L=await S(),Q=s(L),U=e(L);return l({enabled:Q,mode:U}),G0({argumentsText:$,enabled:Q,mode:U})}async function u1($){let O=x1($),L=await S();if(O.type==="window")L=await Q1(O.startHour,O.endHour);else if(O.type==="disable")L=await L1(!1);let Q=H1(L),U=G.stats(Q);return A1({argumentsText:$,enabled:q1(L),window:Q,hybridActive:S1(L),trackedSessions:U.trackedSessions,nextPrewarmAt:U.nextPrewarmAt})}async function d1($){let O=R1($);if(O.type==="enable"||O.type==="disable"){let U=O.type==="enable";return await I1(U),P0(U),A0({argumentsText:$,enabled:U})}let L=await S(),Q=B0(L);return P0(Q),A0({argumentsText:$,enabled:Q})}async function n1($){let O=C1($);if(O.type==="enable"||O.type==="disable"){let U=O.type==="enable";return await O1(U),W0(U),E0({argumentsText:$,enabled:U})}let L=await S(),Q=U0(L);return W0(Q),E0({argumentsText:$,enabled:Q})}return{config:async($)=>{$.command={...$.command??{},[K0]:{template:K0,description:"Show or toggle 1-hour Anthropic ephemeral prompt cache TTL."},[D0]:{template:D0,description:"Keep hybrid Claude cache warm for recently used sessions during a local time window."},[Y0]:{template:Y0,description:"Show current Claude OAuth quota usage for all accounts."},[V0]:{template:V0,description:"Show or toggle Anthropic request dump capture for debugging."},[X0]:{template:X0,description:"Show or toggle Anthropic fast mode for supported Opus models."}}},"command.execute.before":async($)=>{if($.command===K0)await n(j,$.sessionID,await h1($.arguments)),i();if($.command===D0)await n(j,$.sessionID,await u1($.arguments)),i();if($.command===Y0)await n(j,$.sessionID,await b1()),i();if($.command===V0)await n(j,$.sessionID,await d1($.arguments)),i();if($.command===X0)await n(j,$.sessionID,await n1($.arguments)),i()},auth:{provider:"anthropic",async loader($,O){if(A=$,(await $()).type==="oauth"){let i1=function(){if(T)clearInterval(T),T=null;let V=async()=>{try{let X=await S();if(!b(X))return;let Y=await $();if(Y.type!=="oauth")return;if(await h(Y.refresh),!Y.expires)return;let I=Y.expires-Date.now(),B=z0(X);if(I>B)return;if(H("[refresh] opencode main oauth background due",{expiresInMs:I,refreshBeforeMs:B}),Y.refresh&&J0(X?.refresh?.mainLastRefreshError,Y.refresh,Date.now())){H("[refresh] opencode main oauth background skipped backoff",{nextRetryAt:X?.refresh?.mainLastRefreshError?.nextRetryAt,retryCount:X?.refresh?.mainLastRefreshError?.retryCount});return}if(Y.refresh&&X?.refresh?.mainRefreshLeaseUntil&&X.refresh.mainRefreshLeaseUntil>Date.now()&&X.refresh.mainRefreshLeaseTokenHash===j0(Y.refresh))return;await k(),H("[refresh] opencode main oauth refreshed in background",{expires:Y.expires})}catch(X){H("[refresh] opencode main oauth refresh failed",{message:X instanceof Error?X.message:String(X)})}};if(T=setInterval(()=>{V()},Wj),"unref"in T)T.unref()},R0=function(V,X){if(V instanceof Request&&V.body)return!1;return X==null||typeof X==="string"},l1=function(V){return V.has("x-parent-session-id")},f0=function(V){return V.includes("rate_limit_error")||/exceed your account'?s rate limit/i.test(V)},p1=function(V){return V?.quota?.enabled===!0},c1=function(V,X){let Y=Date.now();if(f||Y<y)return;f=y0(V,X).catch((I)=>{throw y=Y+_1(X),I}).finally(()=>{f=null}),f.catch(()=>{})};for(let V of Object.values(O.models))V.cost={input:0,output:0,cache:{read:0,write:0}};let Q=null,U=null,f=null,y=0;async function k(){if(!Q)Q=(async()=>{let Y=null,I=null,B=null;async function _(z){let v=await S()??{version:1,main:{type:"opencode",provider:"anthropic"},accounts:[]};v.refresh=v.refresh??{},z(v),await M0(v)}for(let z=0;z<=2;z++){let v=null;try{if(z>0){let x=500*2**(z-1);await new Promise((I0)=>setTimeout(I0,x))}if(v=await $(),!v.refresh)throw Error("Token refresh failed: missing refresh token");let P=await S(),W=j0(v.refresh),w=P?.refresh?.mainLastRefreshError;if(H("[refresh] opencode main oauth refresh check",{attempt:z,expiresInMs:v.expires?v.expires-Date.now():void 0,hasBackoff:Boolean(w),backoffActive:w?J0(w,v.refresh,Date.now()):!1,retryCount:w?.retryCount,nextRetryAt:w?.nextRetryAt}),w&&J0(w,v.refresh,Date.now()))throw H("[refresh] opencode main oauth refresh skipped backoff",{nextRetryAt:w.nextRetryAt,retryCount:w.retryCount}),Error(N1(w,Date.now()));if(P?.refresh?.mainRefreshLeaseUntil&&P.refresh.mainRefreshLeaseUntil>Date.now()&&P.refresh.mainRefreshLeaseTokenHash===W)throw H("[refresh] opencode main oauth refresh skipped lease",{leaseUntil:P.refresh.mainRefreshLeaseUntil}),Error("Claude OAuth refresh is already in progress");let N=await Y1({name:"opencode-main-oauth-refresh",ttlMs:120000});if(!N)throw H("[refresh] opencode main oauth refresh skipped file lock"),Error("Claude OAuth refresh is already in progress");B=N.release,Y=Pj(),I=W,await _((x)=>{x.refresh=x.refresh??{},x.refresh.mainRefreshLeaseId=Y??void 0,x.refresh.mainRefreshLeaseUntil=Date.now()+120000,x.refresh.mainRefreshLeaseTokenHash=W});let C=await S();if(H("[refresh] opencode main oauth refresh lease acquired",{attempt:z,leaseUntil:Date.now()+120000}),C?.refresh?.mainRefreshLeaseId!==Y||C.refresh.mainRefreshLeaseTokenHash!==W)throw Error("Claude OAuth refresh is already in progress");H("[refresh] opencode main oauth refresh request start",{attempt:z});let R=await W1({refreshToken:v.refresh,maxRetries:0});return await J.auth.set({path:{id:"anthropic"},body:{type:"oauth",refresh:R.refresh,access:R.access,expires:R.expires}}),await _((x)=>{if(!x?.refresh)return;if(x.refresh.mainLastRefreshError=void 0,x.refresh.mainRefreshLeaseId===Y)x.refresh.mainRefreshLeaseId=void 0,x.refresh.mainRefreshLeaseUntil=void 0,x.refresh.mainRefreshLeaseTokenHash=void 0}),H("[refresh] opencode main oauth refresh succeeded",{attempt:z,expiresInMs:R.expires-Date.now()}),R.access}catch(P){let W=P instanceof Error&&(P.message.includes("fetch failed")||("code"in P)&&(P.code==="ECONNRESET"||P.code==="ECONNREFUSED"||P.code==="ETIMEDOUT"||P.code==="UND_ERR_CONNECT_TIMEOUT"));if(z<2&&(W||P instanceof N0&&P.status>=500))continue;H("[refresh] opencode main oauth refresh attempt failed",{attempt:z,error:P instanceof Error?P.message:String(P),transient:W});let w=v?.refresh;if(w&&P instanceof N0)await _((N)=>{N.refresh=N.refresh??{},N.refresh.mainLastRefreshError=v1({error:P,now:Date.now(),refreshToken:w,previous:N.refresh.mainLastRefreshError})});throw P}finally{if(Y)await _((P)=>{if(!P?.refresh)return;if(P.refresh.mainRefreshLeaseId===Y&&P.refresh.mainRefreshLeaseTokenHash===I)P.refresh.mainRefreshLeaseId=void 0,P.refresh.mainRefreshLeaseUntil=void 0,P.refresh.mainRefreshLeaseTokenHash=void 0}).catch(()=>{});await B?.().catch(()=>{})}}throw Error("Token refresh exhausted all retries")})().finally(()=>{Q=null});return Q}Z=k,i1();async function C0(V,X){if(!V.body||V.status!==200)return X?.mark("inspect_stream_skip",{status:V.status}),{response:V,rateLimited:!1};if(V.headers.get("x-cortexkit-relay-optimistic")==="true")return X?.mark("inspect_stream_skip",{status:V.status,reason:"optimistic_relay"}),{response:V,rateLimited:!1};let Y=M(),I=V.body.getReader(),B=[],_=new TextDecoder,z="",v=0;while(!z.includes(`
`)&&z.length<65536){let{done:W,value:w}=await I.read();if(W)break;if(B.push(w),v+=w.byteLength,z+=_.decode(w,{stream:!0}),f0(z))break}if(f0(z))return await I.cancel().catch(()=>{}),X?.mark("inspect_stream_first_event",{ms:q(M()-Y),bytes:v,rateLimited:!0}),{response:V,rateLimited:!0};let P=new ReadableStream({start(W){for(let w of B)W.enqueue(w)},async pull(W){let{done:w,value:N}=await I.read();if(w){W.close();return}W.enqueue(N)},cancel(W){return I.cancel(W)}});return X?.mark("inspect_stream_first_event",{ms:q(M()-Y),bytes:v,rateLimited:!1}),{response:new Response(P,{status:V.status,statusText:V.statusText,headers:V.headers}),rateLimited:!1}}async function T0(V,X,Y,I,B="unknown"){let _=M(),z=Z1(V,X),v=z.get("x-session-affinity")||z.get("x-opencode-session"),P=l1(z);z.delete("x-parent-session-id"),z.delete("x-session-affinity"),z.delete("x-opencode-session");let W=X?.body,w;if(W&&typeof W==="string")try{let g=JSON.parse(W);if(typeof g.model==="string")w=g.model}catch{}let N=await S0(Y,w),C=typeof W==="string"?W.length:void 0;if(W&&typeof W==="string"){let g=M(),p=(()=>{if(!f1())return!1;try{return r(JSON.parse(W).model)}catch{return!1}})();W=await P1(W,{cache1hEnabled:!P&&Z0(),cache1hMode:$0(),fastModeEnabled:p,identity:N});try{d(z,Y,{body:JSON.parse(W),identity:N})}catch{d(z,Y,{identity:N})}if(p)L0(z);I?.mark("rewrite_body",{route:B,ms:q(M()-g),originalBytes:C,rewrittenBytes:W.length,cacheEnabled:!P&&Z0(),cacheMode:$0(),fastModeEnabled:p,subagent:P})}let R=G1(V);if(B==="main"&&typeof W==="string"&&!P&&Z0()&&$0()==="hybrid"){let g=await S();if((await G.track({sessionId:v,url:R.url?.toString()??R.input.toString(),headers:z,bodyText:W,storage:g,cacheMode:"hybrid"})).tracked)I?.mark("cachekeep_track",{session:v})}let x=()=>fetch(R.input,{...X,body:W,headers:z,...$1()&&{tls:{rejectUnauthorized:!1}}}),I0=M(),g0=await g1({config:F,input:R.input,init:X,headers:z,body:W,fallback:x,affinity:v,optimisticResponse:F?.transport==="websocket"});return I?.mark("send_headers_received",{route:B,ms:q(M()-I0),status:g0.status,relayConfigured:F!=null,totalSendWithAccessMs:q(M()-_)}),g0}async function y0(V,X){let Y=Date.now(),I=await q0({accessToken:V});return U={accessToken:V,refreshAfter:F1(I,X,Y),quota:I},I}async function o1(V,X){let Y=Date.now();if(U?.accessToken!==V)return await y0(V,X);if(Y>=U.refreshAfter)c1(V,X);return U.quota}async function k0(V,X,Y,I,B,_){if(!Y.length)return B??null;await B?.body?.cancel().catch(()=>{});let z=B??null;for(let[v,P]of Y.entries()){let W=P.access;if(!W)continue;let w=await T0(V,X,W,_,`fallback_${v}`);z=w;let N=x0(w.status,I);if(!N){let C=await C0(w,_);w=C.response,z=w,N=C.rateLimited}if(!N)return await K.markUsed(P),w;if(v<Y.length-1)await w.body?.cancel().catch(()=>{})}return z}async function t1(V,X,Y,I,B,_){if(!R0(V,X?.body))return Y;let z=M(),v=_??await S();B?.mark("fallback_load_storage",{ms:q(M()-z),cached:!!_});let P=Y,W=x0(P.status,v);if(!W){let N=await C0(P,B);P=N.response,W=N.rateLimited}if(!W)return P;let w=I;if(!w){let N=M();w=await K.getUsableFallbackAccounts(),B?.mark("fallback_get_accounts",{ms:q(M()-N),accounts:w.length})}return await k0(V,X,w,v,P,B)??P}return{apiKey:"",async fetch(V,X){let Y=X?.body,I=Ij({bodyBytes:typeof Y==="string"?Y.length:void 0,relayConfigured:F!=null}),B=M(),_=await $();if(I.mark("get_auth",{ms:q(M()-B),authType:_.type,hasAccess:Boolean(_.access)}),_.type!=="oauth"){let N=await fetch(V,X);return I.done("non_oauth_passthrough",{status:N.status}),N}if(await h(_.refresh),!_.access||!_.expires||_.expires<Date.now()){H("[refresh] opencode main oauth refresh required for request",{hasAccess:Boolean(_.access),expiresInMs:_.expires?_.expires-Date.now():void 0});let N=M();_.access=await k(),I.mark("refresh_main_access",{ms:q(M()-N)})}if(!_.access)throw I.done("missing_access_error"),Error("OAuth access token is missing after refresh");let z=M(),v=await S();I.mark("load_storage",{ms:q(M()-z)});let P;if(R0(V,X?.body)&&p1(v))try{let N=M(),C=await o1(_.access,v);if(I.mark("main_quota_for_routing",{ms:q(M()-N),passes:H0(C,v)}),!H0(C,v)){let R=M();P=await K.getUsableFallbackAccounts(),I.mark("preselect_fallback_accounts",{ms:q(M()-R),accounts:P.length});let x=await k0(V,X,P,v,void 0,I);if(x)return I.done("return_preselected_fallback",{status:x.status}),v0(x)}}catch(N){I.mark("main_quota_for_routing_error",{error:N instanceof Error?N.message:String(N)})}let W=await T0(V,X,_.access,I,"main"),w=await t1(V,X,W,P,I,v);return I.done("return_response",{status:w.status}),v0(w)}}}return{}},methods:[{label:"Claude Pro/Max",type:"oauth",authorize:async()=>{let $=await _0("max");return{url:$.url,instructions:"Paste the authorization code here:",method:"code",callback:async(O)=>{return F0(O,$.verifier,$.redirectUri,$.state)}}}},{label:"Create an API Key",type:"oauth",authorize:async()=>{let $=await _0("console");return{url:$.url,instructions:"Paste the authorization code here:",method:"code",callback:async(O)=>{let L=await F0(O,$.verifier,$.redirectUri,$.state);if(L.type==="failed")return L;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 ${L.access}`}}).then((U)=>U.json())).raw_key}}}}},{provider:"anthropic",label:"Manually enter API Key",type:"api"}]}}};export{Bj as AnthropicAuthPlugin};
{
"name": "@cortexkit/opencode-anthropic-auth",
"version": "1.1.3",
"version": "1.2.0",
"type": "module",

@@ -22,3 +22,3 @@ "repository": {

"engines": {
"bun": "1.3.11"
"bun": "1.3.14"
},

@@ -31,3 +31,4 @@ "files": [

"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json",
"build": "rm -rf dist && bun build src/index.ts src/cli.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --minify && tsc -p tsconfig.build.json --emitDeclarationOnly",
"build:dev": "rm -rf dist && tsc -p tsconfig.build.json",
"dev": "bun ../../scripts/dev.ts",

@@ -45,4 +46,4 @@ "dev:clean": "bun ../../scripts/dev-clean.ts",

"dependencies": {
"@cortexkit/anthropic-auth-core": "1.1.3"
"@cortexkit/anthropic-auth-core": "1.2.0"
}
}

@@ -484,2 +484,21 @@ # CortexKit Anthropic Auth for OpenCode and Pi

### Build modes
Two build modes are available:
```bash
bun run build # Deploy: bun build → bundled dist/ with all deps inlined (core + xxhash-wasm)
bun run build:dev # Dev: tsc → individual dist/*.js files (requires workspace node_modules)
```
The default `build` uses `bun build` to bundle `@cortexkit/anthropic-auth-core` and all transitive dependencies into self-contained output files. No `node_modules/` needed at runtime — the plugin works via `file://` path in OpenCode config:
```json
{
"plugin": ["file:///path/to/anthropic-auth/packages/opencode"]
}
```
`@opencode-ai/plugin` remains external (peer dep provided by OpenCode).
Inspect package contents:

@@ -486,0 +505,0 @@

function isRecord(value) {
return typeof value === 'object' && value !== null;
}
function extractMessages(response) {
if (Array.isArray(response))
return response;
if (isRecord(response) && Array.isArray(response.data))
return response.data;
return [];
}
function getRole(message) {
if (!isRecord(message) || !isRecord(message.info))
return undefined;
return typeof message.info.role === 'string' ? message.info.role : undefined;
}
function extractFromMessage(message) {
if (!isRecord(message) || !isRecord(message.info))
return null;
const info = message.info;
const modelInfo = isRecord(info.model) ? info.model : undefined;
const agent = typeof info.agent === 'string' ? info.agent : undefined;
const providerID = typeof modelInfo?.providerID === 'string'
? modelInfo.providerID
: typeof info.providerID === 'string'
? info.providerID
: undefined;
const modelID = typeof modelInfo?.modelID === 'string'
? modelInfo.modelID
: typeof info.modelID === 'string'
? info.modelID
: undefined;
const variant = typeof modelInfo?.variant === 'string'
? modelInfo.variant
: typeof info.variant === 'string'
? info.variant
: undefined;
if (!agent && (!providerID || !modelID) && !variant)
return null;
const context = {};
if (agent)
context.agent = agent;
if (providerID && modelID)
context.model = { providerID, modelID };
if (variant)
context.variant = variant;
return context;
}
function mergeContexts(base, patch) {
return {
agent: base.agent ?? patch.agent,
model: base.model ?? patch.model,
variant: base.variant ?? patch.variant,
};
}
function isComplete(context) {
return Boolean(context.agent && context.model && context.variant);
}
export async function resolvePromptContext(client, sessionId) {
if (!client || !sessionId)
return null;
const typedClient = client;
if (typeof typedClient.session?.messages !== 'function')
return null;
let messages = [];
try {
messages = extractMessages(await Promise.resolve(typedClient.session.messages({
path: { id: sessionId },
query: { limit: 100 },
})));
}
catch {
return null;
}
if (messages.length === 0)
return null;
let result = {};
for (let index = messages.length - 1; index >= 0; index--) {
if (getRole(messages[index]) !== 'assistant')
continue;
const context = extractFromMessage(messages[index]);
if (!context)
continue;
result = mergeContexts(result, context);
if (isComplete(result))
return result;
}
for (let index = messages.length - 1; index >= 0; index--) {
const context = extractFromMessage(messages[index]);
if (!context)
continue;
result = mergeContexts(result, context);
if (isComplete(result))
return result;
}
if (!result.agent && !result.model && !result.variant)
return null;
return result;
}
import { applyClaudeCodeHeaders, applyClaudeCodeMetadata, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_IDENTITY, FAST_MODE_BETA, isFastModeSupportedModel, mergeAnthropicBetas, OPENCODE_IDENTITY_PREFIX, orderClaudeCodeBody, PARAGRAPH_REMOVAL_ANCHORS, REQUIRED_BETAS, signRequestBody, TEXT_REPLACEMENTS, TOOL_PREFIX, } from '@cortexkit/anthropic-auth-core';
/**
* Prefix a tool name with TOOL_PREFIX and uppercase the first character.
* Claude Code uses PascalCase tool names (e.g. mcp_Bash, mcp_Read);
* lowercase names (mcp_bash, mcp_read) are flagged as non-Claude-Code clients.
*/
function prefixName(name) {
return `${TOOL_PREFIX}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
}
/**
* Reverse prefixName: strip TOOL_PREFIX and restore the original leading case.
*/
function unprefixName(name) {
// StructuredOutput is still used as StructuredOutput
if (name === 'StructuredOutput') {
return name;
}
return `${name.charAt(0).toLowerCase()}${name.slice(1)}`;
}
/**
* Merge headers from a Request object and/or a RequestInit headers value
* into a single Headers instance.
*/
export function mergeHeaders(input, init) {
const headers = new Headers();
if (input instanceof Request) {
input.headers.forEach((value, key) => {
headers.set(key, value);
});
}
const initHeaders = init?.headers;
if (initHeaders) {
if (initHeaders instanceof Headers) {
initHeaders.forEach((value, key) => {
headers.set(key, value);
});
}
else if (Array.isArray(initHeaders)) {
for (const entry of initHeaders) {
const [key, value] = entry;
if (typeof value !== 'undefined') {
headers.set(key, String(value));
}
}
}
else {
for (const [key, value] of Object.entries(initHeaders)) {
if (typeof value !== 'undefined') {
headers.set(key, String(value));
}
}
}
}
return headers;
}
/**
* Merge incoming beta headers with the required OAuth betas, deduplicating.
*/
export function mergeBetaHeaders(headers) {
const incomingBeta = headers.get('anthropic-beta') || '';
const incomingBetasList = incomingBeta
.split(',')
.map((b) => b.trim())
.filter(Boolean);
return [...new Set([...REQUIRED_BETAS, ...incomingBetasList])].join(',');
}
export function addFastModeBetaHeader(headers) {
headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [FAST_MODE_BETA]));
return headers;
}
/**
* Set OAuth-required headers on the request: authorization, beta, user-agent.
* Removes x-api-key since we're using OAuth.
*/
export function setOAuthHeaders(headers, accessToken, options = {}) {
return applyClaudeCodeHeaders(headers, accessToken, options);
}
/**
* Add TOOL_PREFIX to tool names in the request body.
* Prefixes both tool definitions and tool_use blocks in messages.
*/
export function prefixToolNames(parsed) {
if (parsed.tools && Array.isArray(parsed.tools)) {
parsed.tools = parsed.tools.map((tool) => ({
...tool,
name: tool.name ? prefixName(tool.name) : tool.name,
}));
}
if (parsed.messages && Array.isArray(parsed.messages)) {
parsed.messages = parsed.messages.map((msg) => {
if (msg.content && Array.isArray(msg.content)) {
msg.content = msg.content.map((block) => {
if (block.type === 'tool_use' && block.name) {
return { ...block, name: prefixName(block.name) };
}
return block;
});
}
return msg;
});
}
return JSON.stringify(orderClaudeCodeBody(parsed));
}
/**
* Strip TOOL_PREFIX from tool names in streaming response text.
*/
export function stripToolPrefix(text) {
return text.replace(/"name"\s*:\s*"mcp_([^"]+)"/g, (_match, name) => `"name": "${unprefixName(name)}"`);
}
function splitToolPrefixRewriteBuffer(buffer, flush = false) {
if (flush)
return { ready: stripToolPrefix(buffer), pending: '' };
let keepFrom = buffer.length;
const marker = '"name"';
const partialMarkerStart = Math.max(0, buffer.length - marker.length + 1);
for (let index = partialMarkerStart; index < buffer.length; index++) {
if (marker.startsWith(buffer.slice(index))) {
keepFrom = Math.min(keepFrom, index);
break;
}
}
const lastName = buffer.lastIndexOf(marker);
if (lastName !== -1) {
const tail = buffer.slice(lastName);
if (/^"name"\s*(?::\s*(?:"[^"]*)?)?$/.test(tail)) {
keepFrom = Math.min(keepFrom, lastName);
}
}
if (keepFrom < buffer.length) {
return {
ready: stripToolPrefix(buffer.slice(0, keepFrom)),
pending: buffer.slice(keepFrom),
};
}
return { ready: stripToolPrefix(buffer), pending: '' };
}
/**
* Check if TLS verification should be skipped for custom API endpoints.
* Only effective when ANTHROPIC_BASE_URL is also set.
*/
export function isInsecure() {
if (!process.env.ANTHROPIC_BASE_URL?.trim())
return false;
const raw = process.env.ANTHROPIC_INSECURE?.trim();
return raw === '1' || raw === 'true';
}
/**
* Parse ANTHROPIC_BASE_URL from the environment.
* Returns a valid HTTP(S) URL or null if unset/invalid.
*/
function resolveBaseUrl() {
const raw = process.env.ANTHROPIC_BASE_URL?.trim();
if (!raw)
return null;
try {
const baseUrl = new URL(raw);
if ((baseUrl.protocol !== 'http:' && baseUrl.protocol !== 'https:') ||
baseUrl.username ||
baseUrl.password) {
return null;
}
return baseUrl;
}
catch {
return null;
}
}
/**
* Rewrite the request URL to add ?beta=true for /v1/messages requests.
* When ANTHROPIC_BASE_URL is set, overrides the origin (protocol + host)
* for all API requests flowing through the fetch wrapper.
* Returns the modified input and URL (if applicable).
*/
export function rewriteUrl(input) {
let requestUrl = null;
try {
if (typeof input === 'string' || input instanceof URL) {
requestUrl = new URL(input.toString());
}
else if (input instanceof Request) {
requestUrl = new URL(input.url);
}
}
catch {
requestUrl = null;
}
if (!requestUrl)
return { input, url: null };
const originalHref = requestUrl.href;
const baseUrl = resolveBaseUrl();
if (baseUrl) {
requestUrl.protocol = baseUrl.protocol;
requestUrl.host = baseUrl.host;
}
if (requestUrl.pathname === '/v1/messages' &&
!requestUrl.searchParams.has('beta')) {
requestUrl.searchParams.set('beta', 'true');
}
if (requestUrl.href === originalHref) {
return { input, url: requestUrl };
}
const newInput = input instanceof Request
? new Request(requestUrl.toString(), input)
: requestUrl;
return { input: newInput, url: requestUrl };
}
/**
* Sanitize OpenCode-branded strings from the system prompt text.
*
* 1. Removes the OPENCODE_IDENTITY paragraph.
* 2. Removes any paragraph (text between blank lines) that contains
* one of the PARAGRAPH_REMOVAL_ANCHORS — typically URLs that
* identify OpenCode-specific content.
* 3. Applies TEXT_REPLACEMENTS for inline occurrences of "OpenCode"
* inside paragraphs we want to keep.
*
* This approach is resilient to upstream rewording of the OpenCode
* prompt — as long as the anchor strings (URLs, etc.) still appear
* somewhere in the paragraph, the removal works.
*/
export function sanitizeSystemText(text) {
// Split into paragraphs (separated by one or more blank lines)
const paragraphs = text.split(/\n\n+/);
const filtered = paragraphs.filter((paragraph) => {
if (paragraph.includes(OPENCODE_IDENTITY_PREFIX)) {
// If the paragraph contains the identity, drop it entirely
return false;
}
// Remove paragraphs containing any removal anchor
for (const anchor of PARAGRAPH_REMOVAL_ANCHORS) {
if (paragraph.includes(anchor))
return false;
}
return true;
});
let result = filtered.join('\n\n');
// Apply inline text replacements
for (const rule of TEXT_REPLACEMENTS) {
result = result.replace(rule.match, rule.replacement);
}
return result.trim();
}
function isRecord(value) {
return value != null && typeof value === 'object' && !Array.isArray(value);
}
/**
* Sanitize system prompt and prepend Claude Code identity.
* Handles all Anthropic API system formats: undefined, string, or array of text blocks.
*/
export function prependClaudeCodeIdentity(system) {
const identityBlock = {
type: 'text',
text: CLAUDE_CODE_IDENTITY,
};
if (system == null)
return [identityBlock];
if (typeof system === 'string') {
const sanitized = sanitizeSystemText(system);
if (sanitized === CLAUDE_CODE_IDENTITY)
return [identityBlock];
return [identityBlock, { type: 'text', text: sanitized }];
}
if (isRecord(system)) {
const type = typeof system.type === 'string' ? system.type : 'text';
const text = typeof system.text === 'string' ? system.text : '';
return [identityBlock, { ...system, type, text: sanitizeSystemText(text) }];
}
if (!Array.isArray(system))
return [identityBlock];
const sanitized = system.map((item) => {
if (typeof item === 'string') {
return { type: 'text', text: sanitizeSystemText(item) };
}
if (isRecord(item) &&
item.type === 'text' &&
typeof item.text === 'string') {
return {
...item,
type: 'text',
text: sanitizeSystemText(item.text),
};
}
return { type: 'text', text: String(item) };
});
// Idempotency: don't double-prepend if first block already has the identity
if (sanitized[0]?.text === CLAUDE_CODE_IDENTITY) {
return sanitized;
}
return [identityBlock, ...sanitized];
}
const CACHE_1H_CONTROL = { type: 'ephemeral', ttl: '1h' };
function getCacheControl(value) {
if (isRecord(value.cache_control))
return value.cache_control;
if (isRecord(value.cacheControl))
return value.cacheControl;
return null;
}
function setWireCacheControl(value, withTtl) {
if (!isRecord(value))
return false;
delete value.cacheControl;
value.cache_control = withTtl
? { ...CACHE_1H_CONTROL }
: { type: 'ephemeral' };
return true;
}
function removeCacheControl(value) {
if (!isRecord(value))
return;
delete value.cache_control;
delete value.cacheControl;
}
function normalizeContentToArray(content) {
if (Array.isArray(content))
return content;
if (typeof content === 'string')
return [{ type: 'text', text: content }];
return null;
}
function updateCacheControlTtl(value, cache1hEnabled) {
if (!isRecord(value))
return;
const cacheControl = getCacheControl(value);
if (!cacheControl || cacheControl.type !== 'ephemeral')
return;
if (cache1hEnabled) {
cacheControl.ttl = '1h';
}
else {
delete cacheControl.ttl;
}
}
function applyCache1hTtl(parsed, cache1hEnabled) {
if (Array.isArray(parsed.system)) {
for (const block of parsed.system)
updateCacheControlTtl(block, cache1hEnabled);
}
else {
updateCacheControlTtl(parsed.system, cache1hEnabled);
}
if (!Array.isArray(parsed.messages))
return;
for (const message of parsed.messages) {
updateCacheControlTtl(message, cache1hEnabled);
if (isRecord(message) && Array.isArray(message.content)) {
for (const block of message.content) {
updateCacheControlTtl(block, cache1hEnabled);
}
}
}
}
function walkCacheControlTargets(parsed, visitor) {
if (Array.isArray(parsed.system)) {
for (const block of parsed.system)
visitor(block);
}
else {
visitor(parsed.system);
}
if (!Array.isArray(parsed.messages))
return;
for (const message of parsed.messages) {
visitor(message);
if (isRecord(message) && Array.isArray(message.content)) {
for (const block of message.content)
visitor(block);
}
}
}
function removeAllCacheControls(parsed) {
removeCacheControl(parsed);
walkCacheControlTargets(parsed, removeCacheControl);
}
function applyAutomaticCache1h(parsed) {
removeAllCacheControls(parsed);
parsed.cache_control = { ...CACHE_1H_CONTROL };
}
function setMessageCacheAnchor(message) {
if (!isRecord(message))
return false;
const content = normalizeContentToArray(message.content);
if (!content?.length)
return setWireCacheControl(message, true);
message.content = content;
const lastCacheableBlock = [...content]
.reverse()
.find((block) => isRecord(block) && block.type !== 'thinking');
return setWireCacheControl(lastCacheableBlock ?? message, true);
}
function applyHybridCache1h(parsed) {
removeAllCacheControls(parsed);
if (Array.isArray(parsed.system)) {
const identityIndex = parsed.system.findIndex((block) => isRecord(block) && block.text === CLAUDE_CODE_IDENTITY);
const cacheableSystemBlocks = parsed.system
.slice(identityIndex >= 0 ? identityIndex + 1 : 0)
.filter(isRecord);
const lastSystemBlock = cacheableSystemBlocks[cacheableSystemBlocks.length - 1];
setWireCacheControl(lastSystemBlock, true);
}
else {
setWireCacheControl(parsed.system, true);
}
if (!Array.isArray(parsed.messages))
return;
setMessageCacheAnchor(parsed.messages[0]);
setMessageCacheAnchor(parsed.messages[1]);
const movingMessageIndex = parsed.messages.length - 2;
if (movingMessageIndex > 1) {
setMessageCacheAnchor(parsed.messages[movingMessageIndex]);
}
}
function applyCache1hStrategy(parsed, options) {
if (!options.enabled) {
applyCache1hTtl(parsed, false);
delete parsed.cache_control;
delete parsed.cacheControl;
return;
}
if (options.mode === 'automatic') {
applyAutomaticCache1h(parsed);
return;
}
if (options.mode === 'hybrid') {
applyHybridCache1h(parsed);
return;
}
applyCache1hTtl(parsed, true);
delete parsed.cacheControl;
}
/**
* Rewrite the full request body: sanitize system prompt and prefix tool names.
*/
export async function rewriteRequestBody(body, options = {}) {
try {
const parsed = JSON.parse(body);
const billingHeader = Array.isArray(parsed.messages) &&
parsed.messages.some((message) => message.role === 'user')
? buildBillingHeaderValue(parsed.messages, undefined, CLAUDE_CODE_ENTRYPOINT)
: null;
// Sanitize system prompt and prepend Claude Code identity
parsed.system = prependClaudeCodeIdentity(parsed.system);
// Prepend the billing header as a separate system block so the
// final layout is: [billing header, identity, ...rest]
if (billingHeader && Array.isArray(parsed.system)) {
parsed.system.unshift({ type: 'text', text: billingHeader });
}
applyCache1hStrategy(parsed, {
enabled: options.cache1hEnabled ?? false,
mode: options.cache1hMode ?? 'explicit',
});
if (options.fastModeEnabled && isFastModeSupportedModel(parsed.model)) {
parsed.speed = 'fast';
}
else if (parsed.speed === 'fast') {
delete parsed.speed;
}
if (options.identity)
applyClaudeCodeMetadata(parsed, options.identity);
return await signRequestBody(prefixToolNames(parsed));
}
catch {
return body;
}
}
/**
* Create a streaming response that strips the tool prefix from tool names.
*/
export function createStrippedStream(response) {
if (!response.body)
return response;
const reader = response.body.getReader();
const decoder = new TextDecoder();
const encoder = new TextEncoder();
let pending = '';
const stream = new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read();
if (done) {
const flushed = splitToolPrefixRewriteBuffer(`${pending}${decoder.decode()}`, true);
if (flushed.ready)
controller.enqueue(encoder.encode(flushed.ready));
controller.close();
return;
}
const text = pending + decoder.decode(value, { stream: true });
const rewritten = splitToolPrefixRewriteBuffer(text);
pending = rewritten.pending;
if (rewritten.ready)
controller.enqueue(encoder.encode(rewritten.ready));
},
});
return new Response(stream, {
status: response.status,
statusText: response.statusText,
headers: response.headers,
});
}