claudish 7.20.1 → 7.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +546 -165
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/version.ts
|
|
654
|
-
var VERSION = "7.
|
|
654
|
+
var VERSION = "7.22.0";
|
|
655
655
|
|
|
656
656
|
// src/logger.ts
|
|
657
657
|
var exports_logger = {};
|
|
@@ -3654,7 +3654,10 @@ var require_sdk = __commonJS((exports) => {
|
|
|
3654
3654
|
var exports_onepassword = {};
|
|
3655
3655
|
__export(exports_onepassword, {
|
|
3656
3656
|
withSdkRetry: () => withSdkRetry,
|
|
3657
|
+
wasOpAuthorizationDenied: () => wasOpAuthorizationDenied,
|
|
3657
3658
|
valueTail: () => valueTail,
|
|
3659
|
+
setScreenLockProbe: () => setScreenLockProbe,
|
|
3660
|
+
setLockRetryTiming: () => setLockRetryTiming,
|
|
3658
3661
|
resolveSecretsPartial: () => resolveSecretsPartial,
|
|
3659
3662
|
resolveSecrets: () => resolveSecrets,
|
|
3660
3663
|
resolveSdkAuth: () => resolveSdkAuth,
|
|
@@ -3663,7 +3666,10 @@ __export(exports_onepassword, {
|
|
|
3663
3666
|
resolveGlobImport: () => resolveGlobImport,
|
|
3664
3667
|
resolveDesktopAccount: () => resolveDesktopAccount,
|
|
3665
3668
|
resetSdkClientCache: () => resetSdkClientCache,
|
|
3669
|
+
resetOpFailures: () => resetOpFailures,
|
|
3670
|
+
renderOpFailureNotice: () => renderOpFailureNotice,
|
|
3666
3671
|
recordOpHydratedVars: () => recordOpHydratedVars,
|
|
3672
|
+
recordOpFailure: () => recordOpFailure,
|
|
3667
3673
|
readEnvironment: () => readEnvironment,
|
|
3668
3674
|
parseOpFlag: () => parseOpFlag,
|
|
3669
3675
|
parseGlobImport: () => parseGlobImport,
|
|
@@ -3671,16 +3677,20 @@ __export(exports_onepassword, {
|
|
|
3671
3677
|
listVaults: () => listVaults,
|
|
3672
3678
|
listItems: () => listItems,
|
|
3673
3679
|
isTransientSdkError: () => isTransientSdkError,
|
|
3680
|
+
isScreenLocked: () => isScreenLocked,
|
|
3674
3681
|
isOpReference: () => isOpReference,
|
|
3675
3682
|
isOpHydratedVar: () => isOpHydratedVar,
|
|
3683
|
+
isLockedDenial: () => isLockedDenial,
|
|
3676
3684
|
isGlobImport: () => isGlobImport,
|
|
3677
3685
|
globToRegExp: () => globToRegExp,
|
|
3686
|
+
getOpFailures: () => getOpFailures,
|
|
3678
3687
|
filterGlobFields: () => filterGlobFields,
|
|
3679
3688
|
envNameFromOpRef: () => envNameFromOpRef,
|
|
3680
3689
|
discoverItemFieldsById: () => discoverItemFieldsById,
|
|
3681
3690
|
discoverItemFields: () => discoverItemFields,
|
|
3682
3691
|
detectSdkAuth: () => detectSdkAuth,
|
|
3683
3692
|
defaultSdkClientFactory: () => defaultSdkClientFactory,
|
|
3693
|
+
defaultScreenLockProbe: () => defaultScreenLockProbe,
|
|
3684
3694
|
defaultOpAccountLister: () => defaultOpAccountLister,
|
|
3685
3695
|
collectConfigImports: () => collectConfigImports,
|
|
3686
3696
|
buildAuthError: () => buildAuthError,
|
|
@@ -3700,6 +3710,43 @@ function recordOpHydratedVars(names) {
|
|
|
3700
3710
|
function isOpHydratedVar(name) {
|
|
3701
3711
|
return !!name && opHydratedVars.has(name);
|
|
3702
3712
|
}
|
|
3713
|
+
function recordOpFailure(failure) {
|
|
3714
|
+
const dup = opSourceFailures.some((f) => f.kind === failure.kind && f.source === failure.source && f.message === failure.message);
|
|
3715
|
+
if (!dup)
|
|
3716
|
+
opSourceFailures.push(failure);
|
|
3717
|
+
}
|
|
3718
|
+
function getOpFailures() {
|
|
3719
|
+
return opSourceFailures;
|
|
3720
|
+
}
|
|
3721
|
+
function resetOpFailures() {
|
|
3722
|
+
opSourceFailures.length = 0;
|
|
3723
|
+
}
|
|
3724
|
+
function wasOpAuthorizationDenied() {
|
|
3725
|
+
return opSourceFailures.some((f) => /denied authorization/i.test(f.message));
|
|
3726
|
+
}
|
|
3727
|
+
function renderOpFailureNotice(envVar) {
|
|
3728
|
+
if (opSourceFailures.length === 0)
|
|
3729
|
+
return [];
|
|
3730
|
+
const lines = [`1Password was consulted for ${envVar} this run and failed:`];
|
|
3731
|
+
for (const f of opSourceFailures) {
|
|
3732
|
+
const where = f.source ? `${f.kind} ${f.source}` : f.kind;
|
|
3733
|
+
lines.push(` ${where} \u2014 ${f.message.split(`
|
|
3734
|
+
`)[0]}`);
|
|
3735
|
+
}
|
|
3736
|
+
lines.push("");
|
|
3737
|
+
if (wasOpAuthorizationDenied()) {
|
|
3738
|
+
lines.push(" The 1Password desktop app declined to release secrets. This happens when");
|
|
3739
|
+
lines.push(" the approval prompt was dismissed, or when your Mac is locked and the");
|
|
3740
|
+
lines.push(" prompt cannot be shown at all.");
|
|
3741
|
+
lines.push("");
|
|
3742
|
+
lines.push(" Fix: unlock the Mac, approve the 1Password prompt, and re-run.");
|
|
3743
|
+
lines.push(" Headless (no desktop app): export OP_SERVICE_ACCOUNT_TOKEN='ops_...'");
|
|
3744
|
+
} else {
|
|
3745
|
+
lines.push(" Fix: check the reference resolves \u2014 claudish config \u2192 1Password tab.");
|
|
3746
|
+
lines.push(" Headless (no desktop app): export OP_SERVICE_ACCOUNT_TOKEN='ops_...'");
|
|
3747
|
+
}
|
|
3748
|
+
return lines;
|
|
3749
|
+
}
|
|
3703
3750
|
function buildAuthError(detail) {
|
|
3704
3751
|
return new Error(`${detail}
|
|
3705
3752
|
Set OP_SERVICE_ACCOUNT_TOKEN (service account, headless) or OP_ACCOUNT (your 1Password account URL, e.g. my-team.1password.com) for the desktop app \u2014 or set \`onepasswordAccount\` in ~/.claudish/config.json.`);
|
|
@@ -4035,7 +4082,97 @@ function runSdkExclusive(op, label = "op:sdk-op", meta) {
|
|
|
4035
4082
|
function sdkSleep(ms) {
|
|
4036
4083
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4037
4084
|
}
|
|
4085
|
+
function setLockRetryTiming(opts) {
|
|
4086
|
+
lockRetrySeconds = opts?.seconds ?? LOCK_RETRY_SECONDS;
|
|
4087
|
+
lockTickMs = opts?.tickMs ?? 1000;
|
|
4088
|
+
}
|
|
4089
|
+
function setScreenLockProbe(probe) {
|
|
4090
|
+
screenLockProbe = probe ?? defaultScreenLockProbe;
|
|
4091
|
+
}
|
|
4092
|
+
function isScreenLocked() {
|
|
4093
|
+
return screenLockProbe();
|
|
4094
|
+
}
|
|
4095
|
+
function isLockedDenial(err, env = process.env) {
|
|
4096
|
+
const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
|
|
4097
|
+
if (!msg.includes("denied authorization"))
|
|
4098
|
+
return false;
|
|
4099
|
+
if (env.OP_SERVICE_ACCOUNT_TOKEN)
|
|
4100
|
+
return false;
|
|
4101
|
+
return isScreenLocked();
|
|
4102
|
+
}
|
|
4103
|
+
async function countdownForUnlock(round, rounds) {
|
|
4104
|
+
const ttyOut = process.stderr.isTTY === true;
|
|
4105
|
+
const ttyIn = process.stdin.isTTY === true;
|
|
4106
|
+
let cancelled = false;
|
|
4107
|
+
if (round === 1) {
|
|
4108
|
+
process.stderr.write(`
|
|
4109
|
+
${bold("\uD83D\uDD10 1Password needs your OK \u2014 but your Mac is locked, so it can't ask.")}
|
|
4110
|
+
Unlock your Mac and approve the popup. Claudish picks it up from there.
|
|
4111
|
+
|
|
4112
|
+
`);
|
|
4113
|
+
}
|
|
4114
|
+
let restoreInput = () => {};
|
|
4115
|
+
if (ttyIn) {
|
|
4116
|
+
const onKey = (buf) => {
|
|
4117
|
+
const k = buf.toString();
|
|
4118
|
+
if (k === "\x1B" || k === "q" || k === "\x03")
|
|
4119
|
+
cancelled = true;
|
|
4120
|
+
};
|
|
4121
|
+
const wasRaw = process.stdin.isRaw === true;
|
|
4122
|
+
try {
|
|
4123
|
+
process.stdin.setRawMode(true);
|
|
4124
|
+
process.stdin.resume();
|
|
4125
|
+
process.stdin.on("data", onKey);
|
|
4126
|
+
restoreInput = () => {
|
|
4127
|
+
process.stdin.off("data", onKey);
|
|
4128
|
+
process.stdin.setRawMode(wasRaw);
|
|
4129
|
+
process.stdin.pause();
|
|
4130
|
+
};
|
|
4131
|
+
} catch {
|
|
4132
|
+
restoreInput = () => {};
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
const stop = ttyIn ? "Esc to stop waiting" : "Ctrl-C to stop waiting";
|
|
4136
|
+
const line = (secs) => dim(` waiting ${secs}s \xB7 try ${round} of ${rounds} \xB7 ${stop}`);
|
|
4137
|
+
if (!ttyOut)
|
|
4138
|
+
process.stderr.write(`${line(lockRetrySeconds)}
|
|
4139
|
+
`);
|
|
4140
|
+
try {
|
|
4141
|
+
for (let remaining = lockRetrySeconds;remaining > 0; remaining--) {
|
|
4142
|
+
if (cancelled)
|
|
4143
|
+
break;
|
|
4144
|
+
if (!isScreenLocked())
|
|
4145
|
+
break;
|
|
4146
|
+
if (ttyOut)
|
|
4147
|
+
process.stderr.write(`\r\x1B[2K${line(remaining)}`);
|
|
4148
|
+
await sdkSleep(lockTickMs);
|
|
4149
|
+
}
|
|
4150
|
+
} finally {
|
|
4151
|
+
restoreInput();
|
|
4152
|
+
if (ttyOut)
|
|
4153
|
+
process.stderr.write("\r\x1B[2K");
|
|
4154
|
+
}
|
|
4155
|
+
if (cancelled) {
|
|
4156
|
+
process.stderr.write(` OK, not waiting. You can unlock and re-run any time.
|
|
4157
|
+
`);
|
|
4158
|
+
return "cancel";
|
|
4159
|
+
}
|
|
4160
|
+
return "retry";
|
|
4161
|
+
}
|
|
4038
4162
|
async function withSdkRetry(op, label = "op:sdk-op") {
|
|
4163
|
+
for (let round = 1;; round++) {
|
|
4164
|
+
try {
|
|
4165
|
+
return await withSdkTransientRetry(op, label);
|
|
4166
|
+
} catch (err) {
|
|
4167
|
+
if (round > LOCK_RETRY_ROUNDS || !isLockedDenial(err))
|
|
4168
|
+
throw err;
|
|
4169
|
+
if (await countdownForUnlock(round, LOCK_RETRY_ROUNDS) === "cancel")
|
|
4170
|
+
throw err;
|
|
4171
|
+
resetSdkClientCache();
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
async function withSdkTransientRetry(op, label) {
|
|
4039
4176
|
const MAX_ATTEMPTS = 3;
|
|
4040
4177
|
let lastErr;
|
|
4041
4178
|
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
@@ -4211,7 +4348,7 @@ async function readEnvironment(environmentId, opts = {}) {
|
|
|
4211
4348
|
}
|
|
4212
4349
|
return out;
|
|
4213
4350
|
}
|
|
4214
|
-
var OP_REF_RE, opHydratedVars, ENV_VAR_NAME_RE, sdkClientCache, defaultSdkClientFactory = async (auth) => {
|
|
4351
|
+
var OP_REF_RE, opHydratedVars, opSourceFailures, ENV_VAR_NAME_RE, sdkClientCache, defaultSdkClientFactory = async (auth) => {
|
|
4215
4352
|
const key = sdkAuthCacheKey(auth);
|
|
4216
4353
|
const cached = sdkClientCache.get(key);
|
|
4217
4354
|
if (cached)
|
|
@@ -4232,7 +4369,21 @@ var OP_REF_RE, opHydratedVars, ENV_VAR_NAME_RE, sdkClientCache, defaultSdkClient
|
|
|
4232
4369
|
sdkClientCache.set(key, build);
|
|
4233
4370
|
build.catch(() => sdkClientCache.delete(key));
|
|
4234
4371
|
return build;
|
|
4235
|
-
}, sdkQueue,
|
|
4372
|
+
}, sdkQueue, LOCK_RETRY_ROUNDS = 3, LOCK_RETRY_SECONDS = 10, lockRetrySeconds, lockTickMs = 1000, styled = (code, s) => process.stderr.isTTY === true ? `\x1B[${code}m${s}\x1B[0m` : s, bold = (s) => styled("1", s), dim = (s) => styled("2", s), defaultScreenLockProbe = () => {
|
|
4373
|
+
if (process.platform !== "darwin")
|
|
4374
|
+
return false;
|
|
4375
|
+
try {
|
|
4376
|
+
const res = spawnSync("ioreg", ["-n", "Root", "-d1", "-a"], {
|
|
4377
|
+
encoding: "utf-8",
|
|
4378
|
+
timeout: 2000
|
|
4379
|
+
});
|
|
4380
|
+
if (res.status !== 0 || typeof res.stdout !== "string")
|
|
4381
|
+
return false;
|
|
4382
|
+
return /CGSSessionScreenIsLocked<\/key>\s*(?:<true\/>|<integer>1<\/integer>)/.test(res.stdout);
|
|
4383
|
+
} catch {
|
|
4384
|
+
return false;
|
|
4385
|
+
}
|
|
4386
|
+
}, screenLockProbe, defaultOpAccountLister = () => {
|
|
4236
4387
|
try {
|
|
4237
4388
|
const res = spawnSync("op", ["account", "list", "--format=json"], { encoding: "utf-8" });
|
|
4238
4389
|
if (res.error || res.status !== 0)
|
|
@@ -4263,9 +4414,12 @@ var init_onepassword = __esm(() => {
|
|
|
4263
4414
|
init_startup_trace();
|
|
4264
4415
|
OP_REF_RE = /^op:\/\/[^\s]+$/;
|
|
4265
4416
|
opHydratedVars = new Set;
|
|
4417
|
+
opSourceFailures = [];
|
|
4266
4418
|
ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
4267
4419
|
sdkClientCache = new Map;
|
|
4268
4420
|
sdkQueue = Promise.resolve();
|
|
4421
|
+
lockRetrySeconds = LOCK_RETRY_SECONDS;
|
|
4422
|
+
screenLockProbe = defaultScreenLockProbe;
|
|
4269
4423
|
});
|
|
4270
4424
|
|
|
4271
4425
|
// src/auth/credentials/op-source.ts
|
|
@@ -4571,12 +4725,14 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
|
|
|
4571
4725
|
} catch (err) {
|
|
4572
4726
|
if (err instanceof OpAuthError && onAuthFailure === "skip") {
|
|
4573
4727
|
console.error(`[claudish] 1Password auth unavailable, skipping op:// keys: ${err.message}`);
|
|
4728
|
+
const { recordOpFailure: recordOpFailure3 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
|
|
4729
|
+
recordOpFailure3({ kind: "auth", message: err.message });
|
|
4574
4730
|
return {};
|
|
4575
4731
|
}
|
|
4576
4732
|
throw err;
|
|
4577
4733
|
}
|
|
4578
4734
|
}
|
|
4579
|
-
const { collectConfigImports: collectConfigImports2, resolveSecrets: resolveSecrets2, recordOpHydratedVars: recordOpHydratedVars2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
|
|
4735
|
+
const { collectConfigImports: collectConfigImports2, resolveSecrets: resolveSecrets2, recordOpHydratedVars: recordOpHydratedVars2, recordOpFailure: recordOpFailure2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
|
|
4580
4736
|
const cfg = readConfigRaw();
|
|
4581
4737
|
const out = {};
|
|
4582
4738
|
try {
|
|
@@ -4613,6 +4769,7 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
|
|
|
4613
4769
|
} catch (globErr) {
|
|
4614
4770
|
const m = globErr instanceof Error ? globErr.message : String(globErr);
|
|
4615
4771
|
console.error(`[claudish] 1Password import skipped: ${m}`);
|
|
4772
|
+
recordOpFailure2({ kind: "import", source: globPath, message: m });
|
|
4616
4773
|
}
|
|
4617
4774
|
}
|
|
4618
4775
|
if (cfg.customEndpoints && typeof cfg.customEndpoints === "object") {
|
|
@@ -4654,16 +4811,19 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
|
|
|
4654
4811
|
} catch (envErr) {
|
|
4655
4812
|
const m = envErr instanceof Error ? envErr.message : String(envErr);
|
|
4656
4813
|
console.error(`[claudish] 1Password environment skipped: ${m}`);
|
|
4814
|
+
recordOpFailure2({ kind: "environment", source: envId, message: m });
|
|
4657
4815
|
}
|
|
4658
4816
|
}
|
|
4659
4817
|
}
|
|
4660
4818
|
} catch (err) {
|
|
4661
4819
|
if (err instanceof OpAuthError && onAuthFailure === "skip") {
|
|
4662
4820
|
console.error(`[claudish] 1Password resolution skipped: ${err.message}`);
|
|
4821
|
+
recordOpFailure2({ kind: "auth", message: err.message });
|
|
4663
4822
|
return out;
|
|
4664
4823
|
}
|
|
4665
4824
|
const message = err instanceof Error ? err.message : String(err);
|
|
4666
4825
|
console.error(`[claudish] 1Password secret resolution failed: ${message}`);
|
|
4826
|
+
recordOpFailure2({ kind: "reference", message });
|
|
4667
4827
|
if (onAuthFailure === "throw")
|
|
4668
4828
|
throw err;
|
|
4669
4829
|
}
|
|
@@ -37305,6 +37465,140 @@ var init_connection_error = __esm(() => {
|
|
|
37305
37465
|
BUN_CONNECT_MESSAGE = /unable to connect\. is the computer able to access the url\?/i;
|
|
37306
37466
|
});
|
|
37307
37467
|
|
|
37468
|
+
// src/handlers/shared/stream-head-sniffer.ts
|
|
37469
|
+
function isRetryableStreamError(code, type, message) {
|
|
37470
|
+
if (RETRYABLE_ERROR_CODES.has(code))
|
|
37471
|
+
return true;
|
|
37472
|
+
if (RETRYABLE_ERROR_TYPES.has(type))
|
|
37473
|
+
return true;
|
|
37474
|
+
return /overloaded|try again later|temporarily unavailable|please retry/i.test(message);
|
|
37475
|
+
}
|
|
37476
|
+
async function sniffResponsesStreamHead(response, opts = {}) {
|
|
37477
|
+
const budgetMs = opts.budgetMs ?? DEFAULT_SNIFF_BUDGET_MS;
|
|
37478
|
+
const logMsg = opts.log ?? (() => {});
|
|
37479
|
+
if (!response.body)
|
|
37480
|
+
return { kind: "clean", response };
|
|
37481
|
+
const reader = response.body.getReader();
|
|
37482
|
+
const decoder = new TextDecoder;
|
|
37483
|
+
const consumed = [];
|
|
37484
|
+
let pending = "";
|
|
37485
|
+
const deadline = Date.now() + budgetMs;
|
|
37486
|
+
const replayResponse = () => {
|
|
37487
|
+
const buffered = consumed.slice();
|
|
37488
|
+
const body = new ReadableStream({
|
|
37489
|
+
start: async (controller) => {
|
|
37490
|
+
try {
|
|
37491
|
+
for (const chunk of buffered)
|
|
37492
|
+
controller.enqueue(chunk);
|
|
37493
|
+
while (true) {
|
|
37494
|
+
const { done, value } = await reader.read();
|
|
37495
|
+
if (done)
|
|
37496
|
+
break;
|
|
37497
|
+
if (value)
|
|
37498
|
+
controller.enqueue(value);
|
|
37499
|
+
}
|
|
37500
|
+
controller.close();
|
|
37501
|
+
} catch (error46) {
|
|
37502
|
+
try {
|
|
37503
|
+
controller.error(error46);
|
|
37504
|
+
} catch {}
|
|
37505
|
+
}
|
|
37506
|
+
},
|
|
37507
|
+
cancel: () => {
|
|
37508
|
+
reader.cancel().catch(() => {});
|
|
37509
|
+
}
|
|
37510
|
+
});
|
|
37511
|
+
return new Response(body, {
|
|
37512
|
+
status: response.status,
|
|
37513
|
+
statusText: response.statusText,
|
|
37514
|
+
headers: response.headers
|
|
37515
|
+
});
|
|
37516
|
+
};
|
|
37517
|
+
try {
|
|
37518
|
+
while (true) {
|
|
37519
|
+
const remaining = deadline - Date.now();
|
|
37520
|
+
if (remaining <= 0) {
|
|
37521
|
+
logMsg(`[StreamSniff] budget ${budgetMs}ms elapsed with no verdict \u2014 streaming through`);
|
|
37522
|
+
return { kind: "clean", response: replayResponse() };
|
|
37523
|
+
}
|
|
37524
|
+
let timer;
|
|
37525
|
+
const timeout = new Promise((resolve) => {
|
|
37526
|
+
timer = setTimeout(() => resolve("timeout"), remaining);
|
|
37527
|
+
});
|
|
37528
|
+
let result;
|
|
37529
|
+
try {
|
|
37530
|
+
result = await Promise.race([reader.read(), timeout]);
|
|
37531
|
+
} finally {
|
|
37532
|
+
if (timer)
|
|
37533
|
+
clearTimeout(timer);
|
|
37534
|
+
}
|
|
37535
|
+
if (result === "timeout") {
|
|
37536
|
+
logMsg(`[StreamSniff] budget ${budgetMs}ms elapsed mid-read \u2014 streaming through`);
|
|
37537
|
+
return { kind: "clean", response: replayResponse() };
|
|
37538
|
+
}
|
|
37539
|
+
if (result.done)
|
|
37540
|
+
return { kind: "clean", response: replayResponse() };
|
|
37541
|
+
if (!result.value)
|
|
37542
|
+
continue;
|
|
37543
|
+
consumed.push(result.value);
|
|
37544
|
+
pending += decoder.decode(result.value, { stream: true });
|
|
37545
|
+
const lines = pending.split(`
|
|
37546
|
+
`);
|
|
37547
|
+
pending = lines.pop() ?? "";
|
|
37548
|
+
for (const line of lines) {
|
|
37549
|
+
const trimmed = line.trim();
|
|
37550
|
+
if (!trimmed.startsWith("data:"))
|
|
37551
|
+
continue;
|
|
37552
|
+
const payload = trimmed.slice(5).trim();
|
|
37553
|
+
if (!payload || payload === "[DONE]")
|
|
37554
|
+
continue;
|
|
37555
|
+
let event;
|
|
37556
|
+
try {
|
|
37557
|
+
event = JSON.parse(payload);
|
|
37558
|
+
} catch {
|
|
37559
|
+
continue;
|
|
37560
|
+
}
|
|
37561
|
+
const type = String(event?.type ?? "");
|
|
37562
|
+
if (PREAMBLE_EVENTS.has(type))
|
|
37563
|
+
continue;
|
|
37564
|
+
if (type === "error" || type === "response.failed") {
|
|
37565
|
+
const err = event.error ?? event.response?.error ?? {};
|
|
37566
|
+
const code = String(err.code ?? event.code ?? "");
|
|
37567
|
+
const errType = String(err.type ?? event.error_type ?? "");
|
|
37568
|
+
const message = String(err.message ?? event.message ?? "Unknown API error");
|
|
37569
|
+
if (isRetryableStreamError(code, errType, message)) {
|
|
37570
|
+
reader.cancel().catch(() => {});
|
|
37571
|
+
return { kind: "retryable", code: code || errType || "unknown", message };
|
|
37572
|
+
}
|
|
37573
|
+
return { kind: "clean", response: replayResponse() };
|
|
37574
|
+
}
|
|
37575
|
+
return { kind: "clean", response: replayResponse() };
|
|
37576
|
+
}
|
|
37577
|
+
}
|
|
37578
|
+
} catch (error46) {
|
|
37579
|
+
logMsg(`[StreamSniff] read failed (${error46}) \u2014 handing stream to parser`);
|
|
37580
|
+
return { kind: "clean", response: replayResponse() };
|
|
37581
|
+
}
|
|
37582
|
+
}
|
|
37583
|
+
var DEFAULT_SNIFF_BUDGET_MS = 12000, PREAMBLE_EVENTS, RETRYABLE_ERROR_CODES, RETRYABLE_ERROR_TYPES;
|
|
37584
|
+
var init_stream_head_sniffer = __esm(() => {
|
|
37585
|
+
PREAMBLE_EVENTS = new Set(["response.created", "response.in_progress"]);
|
|
37586
|
+
RETRYABLE_ERROR_CODES = new Set([
|
|
37587
|
+
"server_is_overloaded",
|
|
37588
|
+
"server_error",
|
|
37589
|
+
"internal_error",
|
|
37590
|
+
"internal_server_error",
|
|
37591
|
+
"rate_limit_exceeded",
|
|
37592
|
+
"overloaded",
|
|
37593
|
+
"slow_down"
|
|
37594
|
+
]);
|
|
37595
|
+
RETRYABLE_ERROR_TYPES = new Set([
|
|
37596
|
+
"service_unavailable_error",
|
|
37597
|
+
"overloaded_error",
|
|
37598
|
+
"api_error"
|
|
37599
|
+
]);
|
|
37600
|
+
});
|
|
37601
|
+
|
|
37308
37602
|
// src/handlers/shared/stream-parsers/anthropic-sse.ts
|
|
37309
37603
|
function createAnthropicPassthroughStream(c, response, opts) {
|
|
37310
37604
|
const encoder = new TextEncoder;
|
|
@@ -37970,6 +38264,11 @@ data: ${JSON.stringify(data)}
|
|
|
37970
38264
|
`));
|
|
37971
38265
|
}
|
|
37972
38266
|
};
|
|
38267
|
+
const safeClose = () => {
|
|
38268
|
+
try {
|
|
38269
|
+
controller.close();
|
|
38270
|
+
} catch {}
|
|
38271
|
+
};
|
|
37973
38272
|
const closeReasoning = () => {
|
|
37974
38273
|
if (reasoningIdx >= 0) {
|
|
37975
38274
|
send("content_block_stop", { type: "content_block_stop", index: reasoningIdx });
|
|
@@ -38192,7 +38491,7 @@ data: ${JSON.stringify(data)}
|
|
|
38192
38491
|
}
|
|
38193
38492
|
if (opts.onTokenUpdate)
|
|
38194
38493
|
opts.onTokenUpdate(inputTokens, outputTokens);
|
|
38195
|
-
|
|
38494
|
+
safeClose();
|
|
38196
38495
|
return;
|
|
38197
38496
|
}
|
|
38198
38497
|
} catch (parseError) {
|
|
@@ -38220,7 +38519,7 @@ data: ${JSON.stringify(data)}
|
|
|
38220
38519
|
isClosed = true;
|
|
38221
38520
|
if (opts.onTokenUpdate)
|
|
38222
38521
|
opts.onTokenUpdate(inputTokens, outputTokens);
|
|
38223
|
-
|
|
38522
|
+
safeClose();
|
|
38224
38523
|
} catch (error46) {
|
|
38225
38524
|
if (pingInterval) {
|
|
38226
38525
|
clearInterval(pingInterval);
|
|
@@ -38256,9 +38555,7 @@ data: ${JSON.stringify(data)}
|
|
|
38256
38555
|
isClosed = true;
|
|
38257
38556
|
if (opts.onTokenUpdate)
|
|
38258
38557
|
opts.onTokenUpdate(inputTokens, outputTokens);
|
|
38259
|
-
|
|
38260
|
-
controller.close();
|
|
38261
|
-
} catch {}
|
|
38558
|
+
safeClose();
|
|
38262
38559
|
}
|
|
38263
38560
|
}
|
|
38264
38561
|
},
|
|
@@ -38871,6 +39168,35 @@ class ComposedHandler {
|
|
|
38871
39168
|
if (droppedParams.length > 0) {
|
|
38872
39169
|
c.header("X-Dropped-Params", droppedParams.join(", "));
|
|
38873
39170
|
}
|
|
39171
|
+
if (this.resolveStreamFormat() === "openai-responses-sse") {
|
|
39172
|
+
const settled = await this.settleResponsesStreamHead(response, () => this.provider.enqueueRequest ? this.provider.enqueueRequest(doFetch) : doFetch());
|
|
39173
|
+
if (settled.kind === "exhausted") {
|
|
39174
|
+
const waited = STREAM_RETRY_DELAYS_MS.slice(0, settled.attempts).reduce((sum, ms) => sum + ms, 0);
|
|
39175
|
+
const surfaced = `${this.provider.displayName} is overloaded upstream (${settled.code}): ${settled.message} ` + `claudish retried ${settled.attempts}\xD7 over ${Math.round(waited / 1000)}s without success.`;
|
|
39176
|
+
logStderr(`Error: ${surfaced}`);
|
|
39177
|
+
try {
|
|
39178
|
+
recordStats({
|
|
39179
|
+
model_id: this.targetModel,
|
|
39180
|
+
provider_name: this.provider.name,
|
|
39181
|
+
stream_format: this.provider.streamFormat,
|
|
39182
|
+
latency_ms: Math.round(performance.now() - startTime),
|
|
39183
|
+
success: false,
|
|
39184
|
+
http_status: 503,
|
|
39185
|
+
error_class: "server_error",
|
|
39186
|
+
error_code: settled.code,
|
|
39187
|
+
token_strategy: this.options.tokenStrategy ?? "standard",
|
|
39188
|
+
adapter_name: this.getActiveAdapterName(),
|
|
39189
|
+
middleware_names: this.middlewareManager.getActiveNames(this.bareModelName),
|
|
39190
|
+
fallback_used: fallbackMeta !== undefined,
|
|
39191
|
+
fallback_chain: fallbackMeta?.chain,
|
|
39192
|
+
fallback_attempts: fallbackMeta?.attempts,
|
|
39193
|
+
invocation_mode: this.options.invocationMode ?? "auto-route"
|
|
39194
|
+
});
|
|
39195
|
+
} catch {}
|
|
39196
|
+
return c.json(wrapAnthropicError(503, surfaced, "overloaded_error"), 503);
|
|
39197
|
+
}
|
|
39198
|
+
response = settled.response;
|
|
39199
|
+
}
|
|
38874
39200
|
latencyMs = Math.round(performance.now() - startTime);
|
|
38875
39201
|
const httpStatus = response.status;
|
|
38876
39202
|
let streamApiError = null;
|
|
@@ -38902,6 +39228,52 @@ class ComposedHandler {
|
|
|
38902
39228
|
streamApiError = { code, message };
|
|
38903
39229
|
});
|
|
38904
39230
|
}
|
|
39231
|
+
async settleResponsesStreamHead(initial, reissue) {
|
|
39232
|
+
let response = initial;
|
|
39233
|
+
for (let attempt = 0;; attempt++) {
|
|
39234
|
+
const verdict = await sniffResponsesStreamHead(response, { log });
|
|
39235
|
+
if (verdict.kind === "clean")
|
|
39236
|
+
return { kind: "ok", response: verdict.response };
|
|
39237
|
+
const delayMs = STREAM_RETRY_DELAYS_MS[attempt];
|
|
39238
|
+
if (delayMs === undefined) {
|
|
39239
|
+
log(`[${this.provider.displayName}] in-stream ${verdict.code} persisted after ` + `${attempt} retries \u2014 surfacing 503 so the client can retry`);
|
|
39240
|
+
return {
|
|
39241
|
+
kind: "exhausted",
|
|
39242
|
+
code: verdict.code,
|
|
39243
|
+
message: verdict.message,
|
|
39244
|
+
attempts: attempt
|
|
39245
|
+
};
|
|
39246
|
+
}
|
|
39247
|
+
log(`[${this.provider.displayName}] in-stream ${verdict.code} before any output \u2014 ` + `retry ${attempt + 1}/${STREAM_RETRY_DELAYS_MS.length} in ${delayMs / 1000}s`);
|
|
39248
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
39249
|
+
let next;
|
|
39250
|
+
try {
|
|
39251
|
+
next = await reissue();
|
|
39252
|
+
} catch (error46) {
|
|
39253
|
+
log(`[${this.provider.displayName}] retry fetch failed: ${error46}`);
|
|
39254
|
+
return {
|
|
39255
|
+
kind: "exhausted",
|
|
39256
|
+
code: verdict.code,
|
|
39257
|
+
message: `${verdict.message} (retry could not reach the provider: ${error46})`,
|
|
39258
|
+
attempts: attempt + 1
|
|
39259
|
+
};
|
|
39260
|
+
}
|
|
39261
|
+
if (!next.ok) {
|
|
39262
|
+
const body = await next.text().catch(() => "");
|
|
39263
|
+
log(`[${this.provider.displayName}] retry returned HTTP ${next.status}`);
|
|
39264
|
+
return {
|
|
39265
|
+
kind: "exhausted",
|
|
39266
|
+
code: `http_${next.status}`,
|
|
39267
|
+
message: body.slice(0, 500) || `HTTP ${next.status}`,
|
|
39268
|
+
attempts: attempt + 1
|
|
39269
|
+
};
|
|
39270
|
+
}
|
|
39271
|
+
response = next;
|
|
39272
|
+
}
|
|
39273
|
+
}
|
|
39274
|
+
resolveStreamFormat() {
|
|
39275
|
+
return this.provider.overrideStreamFormat?.() ?? this.explicitAdapter?.getStreamFormat() ?? this.modelAdapter?.getStreamFormat() ?? this.getAdapter().getStreamFormat();
|
|
39276
|
+
}
|
|
38905
39277
|
handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete, onApiError) {
|
|
38906
39278
|
let pendingOnComplete = onComplete;
|
|
38907
39279
|
const onTokenUpdate = (input, output) => {
|
|
@@ -38927,7 +39299,7 @@ class ComposedHandler {
|
|
|
38927
39299
|
pendingOnComplete = undefined;
|
|
38928
39300
|
}
|
|
38929
39301
|
};
|
|
38930
|
-
const streamFormat = this.
|
|
39302
|
+
const streamFormat = this.resolveStreamFormat();
|
|
38931
39303
|
const priorInputTokens = this.tokenTracker.getLastInputTokens();
|
|
38932
39304
|
switch (streamFormat) {
|
|
38933
39305
|
case "openai-sse":
|
|
@@ -39031,6 +39403,7 @@ function getRecoveryHint(status, errorText, providerName) {
|
|
|
39031
39403
|
}
|
|
39032
39404
|
return `Unexpected HTTP ${status} from ${providerName}.`;
|
|
39033
39405
|
}
|
|
39406
|
+
var STREAM_RETRY_DELAYS_MS;
|
|
39034
39407
|
var init_composed_handler = __esm(() => {
|
|
39035
39408
|
init_dialect_manager();
|
|
39036
39409
|
init_logger();
|
|
@@ -39043,6 +39416,7 @@ var init_composed_handler = __esm(() => {
|
|
|
39043
39416
|
init_anthropic_error();
|
|
39044
39417
|
init_connection_error();
|
|
39045
39418
|
init_openai_compat();
|
|
39419
|
+
init_stream_head_sniffer();
|
|
39046
39420
|
init_anthropic_sse();
|
|
39047
39421
|
init_gemini_sse();
|
|
39048
39422
|
init_ollama_jsonl();
|
|
@@ -39050,6 +39424,7 @@ var init_composed_handler = __esm(() => {
|
|
|
39050
39424
|
init_openai_responses_sse();
|
|
39051
39425
|
init_openai_sse();
|
|
39052
39426
|
init_token_tracker();
|
|
39427
|
+
STREAM_RETRY_DELAYS_MS = [3000, 15000, 30000];
|
|
39053
39428
|
});
|
|
39054
39429
|
|
|
39055
39430
|
// src/handlers/fallback-handler.ts
|
|
@@ -42454,7 +42829,12 @@ function getMissingKeyError(resolution) {
|
|
|
42454
42829
|
const lines = [];
|
|
42455
42830
|
lines.push(`Error: ${resolution.apiKeyDescription} is required for model "${resolution.fullModelId}"`);
|
|
42456
42831
|
lines.push("");
|
|
42457
|
-
|
|
42832
|
+
const opNotice = renderOpFailureNotice(resolution.requiredApiKeyEnvVar);
|
|
42833
|
+
if (opNotice.length > 0) {
|
|
42834
|
+
lines.push(...opNotice);
|
|
42835
|
+
lines.push("");
|
|
42836
|
+
}
|
|
42837
|
+
lines.push(opNotice.length > 0 ? "Or set the key directly:" : "Set it with:");
|
|
42458
42838
|
lines.push(` export ${resolution.requiredApiKeyEnvVar}='your-key-here'`);
|
|
42459
42839
|
if (resolution.apiKeyUrl) {
|
|
42460
42840
|
lines.push("");
|
|
@@ -42533,6 +42913,7 @@ var init_provider_resolver = __esm(() => {
|
|
|
42533
42913
|
init_provider_definitions();
|
|
42534
42914
|
init_provider_registry();
|
|
42535
42915
|
init_remote_provider_registry();
|
|
42916
|
+
init_onepassword();
|
|
42536
42917
|
init_routing_hints();
|
|
42537
42918
|
API_KEY_INFO = new Proxy({}, {
|
|
42538
42919
|
get(_target, prop) {
|
|
@@ -60138,7 +60519,7 @@ function tokBarCells(tokensPerSec, maxTokPerSec, tokWidth) {
|
|
|
60138
60519
|
const raw2 = Math.round(tokWidth * Math.max(0, tokensPerSec) / denom);
|
|
60139
60520
|
return Math.min(tokWidth, Math.max(0, raw2));
|
|
60140
60521
|
}
|
|
60141
|
-
var C,
|
|
60522
|
+
var C, bold2, A, LATENCY_BUCKETS, latencyFg = "#ffffff", LATENCY_FG_ANSI = "\x1B[38;2;255;255;255m", ANSI_RESET = "\x1B[0m", STAGE_BG, STAGE_FG, STAGE_BG_ANSI;
|
|
60142
60523
|
var init_theme2 = __esm(() => {
|
|
60143
60524
|
C = {
|
|
60144
60525
|
bg: "#000000",
|
|
@@ -60169,10 +60550,10 @@ var init_theme2 = __esm(() => {
|
|
|
60169
60550
|
chipKeyBg: "#3a3a3a",
|
|
60170
60551
|
chipLabelBg: "#222222"
|
|
60171
60552
|
};
|
|
60172
|
-
|
|
60553
|
+
bold2 = createTextAttributes({ bold: true });
|
|
60173
60554
|
A = {
|
|
60174
|
-
bold,
|
|
60175
|
-
boldIf: (enabled) => enabled ?
|
|
60555
|
+
bold: bold2,
|
|
60556
|
+
boldIf: (enabled) => enabled ? bold2 : undefined
|
|
60176
60557
|
};
|
|
60177
60558
|
LATENCY_BUCKETS = [
|
|
60178
60559
|
{ maxMs: 500, hex: "#1f8f3b" },
|
|
@@ -63508,99 +63889,99 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
|
|
|
63508
63889
|
function printHelp() {
|
|
63509
63890
|
const useColor = !!process.stdout.isTTY && !process.env.NO_COLOR;
|
|
63510
63891
|
const c = (code) => (s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
63511
|
-
const
|
|
63512
|
-
const
|
|
63892
|
+
const bold3 = c("1");
|
|
63893
|
+
const dim2 = c("2");
|
|
63513
63894
|
const cyan = c("36");
|
|
63514
63895
|
const green = c("32");
|
|
63515
63896
|
const yellow = c("33");
|
|
63516
63897
|
const magenta = c("35");
|
|
63517
63898
|
const blue = c("34");
|
|
63518
|
-
const h = (title) =>
|
|
63899
|
+
const h = (title) => bold3(cyan(`\u258C ${title}`));
|
|
63519
63900
|
console.log(`
|
|
63520
|
-
${
|
|
63521
|
-
${
|
|
63901
|
+
${bold3("claudish")} ${dim2("\xB7")} Run Claude Code with any AI model
|
|
63902
|
+
${dim2("OpenRouter \xB7 Gemini \xB7 OpenAI \xB7 xAI \xB7 MiniMax \xB7 Kimi \xB7 GLM \xB7 Z.AI \xB7 Sakana \xB7 Poe \xB7 LiteLLM \xB7 Local")}
|
|
63522
63903
|
|
|
63523
63904
|
${h("USAGE")}
|
|
63524
|
-
${green("claudish")} ${
|
|
63525
|
-
${green("claudish")} ${yellow("[OPTIONS] <claude-args...>")} ${
|
|
63526
|
-
${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${yellow('"prompt"')} ${
|
|
63527
|
-
${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${green("-f")} ${yellow("input.md")} ${
|
|
63905
|
+
${green("claudish")} ${dim2("# Interactive mode (default, model selector)")}
|
|
63906
|
+
${green("claudish")} ${yellow("[OPTIONS] <claude-args...>")} ${dim2("# Single-shot mode (requires --model)")}
|
|
63907
|
+
${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${yellow('"prompt"')} ${dim2("# Run models in parallel (magmux grid)")}
|
|
63908
|
+
${green("claudish")} ${green("--team")} ${yellow("a,b,c")} ${green("-f")} ${yellow("input.md")} ${dim2("# Team mode with file input")}
|
|
63528
63909
|
|
|
63529
63910
|
${h("MODEL ROUTING")}
|
|
63530
|
-
${
|
|
63531
|
-
${magenta("google@gemini-3-pro")} ${
|
|
63532
|
-
${magenta("openrouter@google/gemini-3-pro")} ${
|
|
63533
|
-
${magenta("oai@gpt-5.3")} ${
|
|
63534
|
-
${magenta("ollama@llama3.2:3")} ${
|
|
63535
|
-
${magenta("ollama@llama3.2:0")} ${
|
|
63536
|
-
|
|
63537
|
-
${
|
|
63538
|
-
${magenta("g, gemini")} ${
|
|
63539
|
-
${magenta("oai")} ${
|
|
63540
|
-
${magenta("cx, codex")} ${
|
|
63541
|
-
${magenta("or")} ${
|
|
63542
|
-
${magenta("x-ai, xai, grok")} ${
|
|
63543
|
-
${magenta("mm, mmax")} ${
|
|
63544
|
-
${magenta("mmc")} ${
|
|
63545
|
-
${magenta("kimi, moon")} ${
|
|
63546
|
-
${magenta("kc")} ${
|
|
63547
|
-
${magenta("glm, zhipu")} ${
|
|
63548
|
-
${magenta("gc")} ${
|
|
63549
|
-
${magenta("z-ai, zai")} ${
|
|
63550
|
-
${magenta("oc, llama, lc, meta")} ${
|
|
63551
|
-
${magenta("zen")} ${
|
|
63552
|
-
${magenta("zengo, zgo")} ${
|
|
63553
|
-
${magenta("v, vertex")} ${
|
|
63554
|
-
${magenta("go")} ${
|
|
63555
|
-
${magenta("poe")} ${
|
|
63556
|
-
${magenta("litellm, ll")} ${
|
|
63557
|
-
${magenta("ds")} ${
|
|
63558
|
-
${magenta("sakana, fugu")} ${
|
|
63559
|
-
${magenta("sc")} ${
|
|
63560
|
-
${magenta("ollama")} ${
|
|
63561
|
-
${magenta("lms, lmstudio")} ${
|
|
63562
|
-
${magenta("vllm")} ${
|
|
63563
|
-
${magenta("mlx")} ${
|
|
63564
|
-
|
|
63565
|
-
${
|
|
63566
|
-
${yellow("google/*, gemini-*")} ${
|
|
63567
|
-
${yellow("openai/*, gpt-*, o1-*")} ${
|
|
63568
|
-
${yellow("x-ai/*, grok-*")} ${
|
|
63569
|
-
${yellow("meta-llama/*, llama-*")} ${
|
|
63570
|
-
${yellow("minimax/*, abab-*")} ${
|
|
63571
|
-
${yellow("moonshot/*, kimi-*")} ${
|
|
63572
|
-
${yellow("zhipu/*, glm-*")} ${
|
|
63573
|
-
${yellow("sakana/*, fugu-*")} ${
|
|
63574
|
-
${yellow("poe:*")} ${
|
|
63575
|
-
${yellow("anthropic/*, claude-*")} ${
|
|
63576
|
-
${yellow("(unknown vendor/)")} ${
|
|
63577
|
-
|
|
63578
|
-
${
|
|
63911
|
+
${bold3("New syntax:")} ${yellow("provider@model[:concurrency]")}
|
|
63912
|
+
${magenta("google@gemini-3-pro")} ${dim2("Direct Google API (explicit)")}
|
|
63913
|
+
${magenta("openrouter@google/gemini-3-pro")} ${dim2("OpenRouter (explicit)")}
|
|
63914
|
+
${magenta("oai@gpt-5.3")} ${dim2("Direct OpenAI API (shortcut)")}
|
|
63915
|
+
${magenta("ollama@llama3.2:3")} ${dim2("Local Ollama, 3 concurrent requests")}
|
|
63916
|
+
${magenta("ollama@llama3.2:0")} ${dim2("Local Ollama, no limits")}
|
|
63917
|
+
|
|
63918
|
+
${bold3("Provider shortcuts:")}
|
|
63919
|
+
${magenta("g, gemini")} ${dim2("->")} Google Gemini ${dim2("google@gemini-3-pro")}
|
|
63920
|
+
${magenta("oai")} ${dim2("->")} OpenAI Direct ${dim2("oai@gpt-5.3")}
|
|
63921
|
+
${magenta("cx, codex")} ${dim2("->")} OpenAI Codex ${dim2("cx@gpt-5.3 (Responses API)")}
|
|
63922
|
+
${magenta("or")} ${dim2("->")} OpenRouter ${dim2("or@openai/gpt-5.3")}
|
|
63923
|
+
${magenta("x-ai, xai, grok")} ${dim2("->")} xAI / Grok ${dim2("x-ai@grok-3")}
|
|
63924
|
+
${magenta("mm, mmax")} ${dim2("->")} MiniMax Direct ${dim2("mm@MiniMax-M2.1")}
|
|
63925
|
+
${magenta("mmc")} ${dim2("->")} MiniMax Coding ${dim2("mmc@MiniMax-M2.1")}
|
|
63926
|
+
${magenta("kimi, moon")} ${dim2("->")} Kimi Direct ${dim2("kimi@kimi-k2-thinking-turbo")}
|
|
63927
|
+
${magenta("kc")} ${dim2("->")} Kimi Coding ${dim2("kc@kimi-k2-thinking-turbo")}
|
|
63928
|
+
${magenta("glm, zhipu")} ${dim2("->")} GLM Direct ${dim2("glm@glm-4.7")}
|
|
63929
|
+
${magenta("gc")} ${dim2("->")} GLM Coding ${dim2("gc@glm-4.7")}
|
|
63930
|
+
${magenta("z-ai, zai")} ${dim2("->")} Z.AI Direct ${dim2("z-ai@glm-4.7")}
|
|
63931
|
+
${magenta("oc, llama, lc, meta")} ${dim2("->")} OllamaCloud ${dim2("oc@llama-3.1")}
|
|
63932
|
+
${magenta("zen")} ${dim2("->")} OpenCode Zen ${dim2("zen@grok-code")}
|
|
63933
|
+
${magenta("zengo, zgo")} ${dim2("->")} OpenCode Zen Go ${dim2("zengo@grok-code")}
|
|
63934
|
+
${magenta("v, vertex")} ${dim2("->")} Vertex AI ${dim2("v@gemini-2.5-flash")}
|
|
63935
|
+
${magenta("go")} ${dim2("->")} Gemini Code Assist ${dim2("go@gemini-2.5-flash")}
|
|
63936
|
+
${magenta("poe")} ${dim2("->")} Poe ${dim2("poe@GPT-4o")}
|
|
63937
|
+
${magenta("litellm, ll")} ${dim2("->")} LiteLLM ${dim2("ll@gpt-4o (needs LITELLM_BASE_URL)")}
|
|
63938
|
+
${magenta("ds")} ${dim2("->")} DeepSeek ${dim2("ds@deepseek-chat")}
|
|
63939
|
+
${magenta("sakana, fugu")} ${dim2("->")} Sakana Fugu ${dim2("fugu@fugu-ultra")}
|
|
63940
|
+
${magenta("sc")} ${dim2("->")} Sakana Subscription ${dim2("sc@fugu-ultra")}
|
|
63941
|
+
${magenta("ollama")} ${dim2("->")} Ollama (local) ${dim2("ollama@llama3.2")}
|
|
63942
|
+
${magenta("lms, lmstudio")} ${dim2("->")} LM Studio (local) ${dim2("lms@qwen")}
|
|
63943
|
+
${magenta("vllm")} ${dim2("->")} vLLM (local) ${dim2("vllm@model")}
|
|
63944
|
+
${magenta("mlx")} ${dim2("->")} MLX (local) ${dim2("mlx@model")}
|
|
63945
|
+
|
|
63946
|
+
${bold3("Native auto-detection")} ${dim2("(when no provider specified):")}
|
|
63947
|
+
${yellow("google/*, gemini-*")} ${dim2("->")} Google API
|
|
63948
|
+
${yellow("openai/*, gpt-*, o1-*")} ${dim2("->")} OpenAI API
|
|
63949
|
+
${yellow("x-ai/*, grok-*")} ${dim2("->")} xAI
|
|
63950
|
+
${yellow("meta-llama/*, llama-*")} ${dim2("->")} OllamaCloud
|
|
63951
|
+
${yellow("minimax/*, abab-*")} ${dim2("->")} MiniMax API
|
|
63952
|
+
${yellow("moonshot/*, kimi-*")} ${dim2("->")} Kimi API
|
|
63953
|
+
${yellow("zhipu/*, glm-*")} ${dim2("->")} GLM API
|
|
63954
|
+
${yellow("sakana/*, fugu-*")} ${dim2("->")} Sakana Fugu
|
|
63955
|
+
${yellow("poe:*")} ${dim2("->")} Poe
|
|
63956
|
+
${yellow("anthropic/*, claude-*")} ${dim2("->")} Native Anthropic
|
|
63957
|
+
${yellow("(unknown vendor/)")} ${dim2("->")} Error (use openrouter@vendor/model)
|
|
63958
|
+
|
|
63959
|
+
${dim2("A defaultProvider (config / --default-provider) catches bare names that match no rule.")}
|
|
63579
63960
|
|
|
63580
63961
|
${h("OPTIONS")}
|
|
63581
63962
|
${green("-i, --interactive")} Run in interactive mode (default when no prompt given)
|
|
63582
63963
|
${green("-m, --model")} ${yellow("<model>")} Model to use (required for single-shot mode)
|
|
63583
63964
|
${green("--profile")} ${yellow("<name>")} Use named profile for model mapping (default profile if omitted)
|
|
63584
63965
|
${green("--default-provider")} ${yellow("<name>")} Fallback provider for bare model names (builtin or customEndpoints key)
|
|
63585
|
-
${
|
|
63966
|
+
${dim2("Precedence: this flag > CLAUDISH_DEFAULT_PROVIDER env > config.json")}
|
|
63586
63967
|
${green("--anthropic-api-billing")} Use your real ANTHROPIC_API_KEY for native Claude models
|
|
63587
|
-
${
|
|
63588
|
-
${
|
|
63589
|
-
${
|
|
63968
|
+
${dim2("(metered API billing). Default: the key is hidden so Claude Code")}
|
|
63969
|
+
${dim2("uses your claude.ai subscription. Env: CLAUDISH_ANTHROPIC_API_BILLING")}
|
|
63970
|
+
${dim2("Config: anthropicApiBilling: true")}
|
|
63590
63971
|
${green("--config")} ${yellow("<file>")} Use THIS config file for the run, fully replacing the machine
|
|
63591
|
-
${
|
|
63592
|
-
${
|
|
63593
|
-
${
|
|
63972
|
+
${dim2("global (~/.claudish/config.json) AND project (.claudish.json).")}
|
|
63973
|
+
${dim2("A file naming no op:// source never touches 1Password (no prompt).")}
|
|
63974
|
+
${dim2("Env vars still resolve first. Env: CLAUDISH_CONFIG")}
|
|
63594
63975
|
${green("--op")} ${yellow("<op://glob>")} Load API keys from a 1Password item glob (SDK-based, no op CLI)
|
|
63595
63976
|
${green("--op")} ${yellow("<glob>")} ${green("--list")} Preview which fields the glob would import (names only, no values)
|
|
63596
63977
|
${green("--op-env")} ${yellow("<id>")} Load env vars from a 1Password Environment (highest priority)
|
|
63597
63978
|
${green("--port")} ${yellow("<port>")} Proxy server port (default: random)
|
|
63598
63979
|
${green("-d, --debug-claudish")} Enable claudish debug logging to file (logs/claudish_*.log)
|
|
63599
|
-
${
|
|
63980
|
+
${dim2('Always-on: CLAUDISH_DEBUG=1 env var or "debug": true in config.json')}
|
|
63600
63981
|
${green("--no-debug-claudish")} Force debug logging off for this run (when globally enabled)
|
|
63601
63982
|
${green("--log-off")} Disable always-on structural logging (~/.claudish/logs/)
|
|
63602
63983
|
${green("--log-diag")} ${yellow("<mode>")} Diagnostic output: auto (default), logfile, off
|
|
63603
|
-
${
|
|
63984
|
+
${dim2('Also: CLAUDISH_DIAG_MODE env var or "diagMode" in config.json')}
|
|
63604
63985
|
${green("--log-level")} ${yellow("<level>")} Log verbosity: debug (full), info (truncated), minimal (labels)
|
|
63605
63986
|
${green("-q, --quiet")} Suppress [claudish] log messages (default in single-shot mode)
|
|
63606
63987
|
${green("-v, --verbose")} Show [claudish] log messages (default in interactive mode)
|
|
@@ -63624,13 +64005,13 @@ ${h("OPTIONS")}
|
|
|
63624
64005
|
${h("MODEL DISCOVERY")}
|
|
63625
64006
|
${green("--models")} Top 100 ranked (Firebase + local providers)
|
|
63626
64007
|
${green("--models --provider")} ${yellow("<slug>")} Filter the catalog to one provider
|
|
63627
|
-
${
|
|
64008
|
+
${dim2("e.g. --provider opencode-zen, anthropic, openai")}
|
|
63628
64009
|
${green("--providers")} Every provider + active-model count
|
|
63629
64010
|
${green("-s, --models-search")} ${yellow("<query>")} Fuzzy search: id, brand synonyms (chatgpt,
|
|
63630
|
-
${
|
|
64011
|
+
${dim2("claude, grok), gateways (zen, oc, codex), caps")}
|
|
63631
64012
|
${green("--models-top")} Curated recommended models (flagship + fast)
|
|
63632
64013
|
${green("--probe")} ${yellow("<models...>")} Probe each provider in the fallback chain with
|
|
63633
|
-
${
|
|
64014
|
+
${dim2("a real 1-token request (may incur tiny cost)")}
|
|
63634
64015
|
${green("--no-probe")} Skip live requests, show static chain only
|
|
63635
64016
|
${green("--probe-timeout")} ${yellow("<secs>")} Per-link timeout for live probes (default: 40)
|
|
63636
64017
|
${green("--models-refresh")} Force refresh the slim model catalog from Firebase
|
|
@@ -63639,11 +64020,11 @@ ${h("MODEL DISCOVERY")}
|
|
|
63639
64020
|
|
|
63640
64021
|
${h("TEAM MODE")}
|
|
63641
64022
|
${green("--team")} ${yellow("<models>")} Run multiple models in parallel (comma-separated)
|
|
63642
|
-
${
|
|
64023
|
+
${dim2('Example: --team minimax-m2.5,kimi-k2.5 "prompt"')}
|
|
63643
64024
|
${green("--mode")} ${yellow("<mode>")} Team mode: default (grid), interactive, json
|
|
63644
64025
|
${green("-f, --file")} ${yellow("<path>")} Read prompt from file (use with --team or single-shot)
|
|
63645
64026
|
|
|
63646
|
-
${h("MODEL MAPPING")} ${
|
|
64027
|
+
${h("MODEL MAPPING")} ${dim2("(per-role override)")}
|
|
63647
64028
|
${green("--model-opus")} ${yellow("<model>")} Model for Opus role (planning, complex tasks)
|
|
63648
64029
|
${green("--model-sonnet")} ${yellow("<model>")} Model for Sonnet role (default coding)
|
|
63649
64030
|
${green("--model-haiku")} ${yellow("<model>")} Model for Haiku role (fast tasks, background)
|
|
@@ -63651,13 +64032,13 @@ ${h("MODEL MAPPING")} ${dim("(per-role override)")}
|
|
|
63651
64032
|
|
|
63652
64033
|
${h("SUBCOMMANDS")}
|
|
63653
64034
|
${green("claudish config")} Open the interactive config TUI (profiles,
|
|
63654
|
-
${
|
|
64035
|
+
${dim2("providers, routing, 1Password)")}
|
|
63655
64036
|
${green("claudish providers")} ${yellow("[--json]")} Show provider credential status (no key material)
|
|
63656
64037
|
${green("claudish quota")} ${yellow("[provider]")} Show remaining quota/usage (alias: usage)
|
|
63657
64038
|
${green("claudish serve")} ${yellow("--port <n> --models <p>")} Run the Claude Desktop redirect gateway
|
|
63658
64039
|
${green("claudish update")} Check for updates and install the latest version
|
|
63659
64040
|
|
|
63660
|
-
${
|
|
64041
|
+
${bold3("Profiles:")}
|
|
63661
64042
|
${green("claudish init")} ${yellow("[--local|--global]")} Setup wizard - create config + first profile
|
|
63662
64043
|
${green("claudish profile list")} ${yellow("[scope]")} List all profiles (both scopes by default)
|
|
63663
64044
|
${green("claudish profile add")} ${yellow("[scope]")} Add a new profile
|
|
@@ -63665,104 +64046,104 @@ ${h("SUBCOMMANDS")}
|
|
|
63665
64046
|
${green("claudish profile use")} ${yellow("[name] [scope]")} Set default profile
|
|
63666
64047
|
${green("claudish profile show")} ${yellow("[name] [scope]")} Show profile details
|
|
63667
64048
|
${green("claudish profile edit")} ${yellow("[name] [scope]")} Edit a profile
|
|
63668
|
-
${
|
|
64049
|
+
${dim2("scope = --local (.claudish.json) | --global (~/.claudish/config.json) | (prompted)")}
|
|
63669
64050
|
|
|
63670
|
-
${
|
|
64051
|
+
${bold3("Authentication:")}
|
|
63671
64052
|
${green("claudish login")} ${yellow("[provider]")} Login to an OAuth provider (interactive if omitted)
|
|
63672
64053
|
${green("claudish logout")} ${yellow("[provider]")} Clear OAuth credentials
|
|
63673
|
-
${
|
|
64054
|
+
${dim2("Providers: gemini, kimi")}
|
|
63674
64055
|
|
|
63675
|
-
${h("1PASSWORD")} ${
|
|
63676
|
-
${
|
|
64056
|
+
${h("1PASSWORD")} ${dim2("(SDK-based \u2014 no op CLI needed for secrets)")}
|
|
64057
|
+
${dim2("Auth via OP_SERVICE_ACCOUNT_TOKEN, or OP_ACCOUNT / onepasswordAccount config (DesktopAuth).")}
|
|
63677
64058
|
${green("--op")} ${yellow("<glob> --list")} Preview which fields a glob would import (names only)
|
|
63678
64059
|
${green("--op")} ${yellow("<glob>")} ${yellow("[...args]")} Resolve a glob into env vars, then run a session
|
|
63679
|
-
${
|
|
63680
|
-
${
|
|
64060
|
+
${dim2("Inline op import requires a GLOB (self-names via field labels)")}
|
|
64061
|
+
${dim2('Example: claudish --op "op://Jack/Keys/**" --model gpt-4o "task"')}
|
|
63681
64062
|
${green("--op-env")} ${yellow("<id>")} Load a 1Password Environment (highest-priority source)
|
|
63682
|
-
${
|
|
64063
|
+
${dim2("Persistent setup (single refs, sets, environments, account): claudish config -> 1Password tab")}
|
|
63683
64064
|
|
|
63684
64065
|
${h("CLAUDE CODE FLAG PASSTHROUGH")}
|
|
63685
|
-
${
|
|
63686
|
-
${green("claudish")} --model grok ${yellow("--agent test")} ${yellow('"task"')} ${
|
|
63687
|
-
${green("claudish")} --model grok ${yellow("--effort high")} --stdin ${yellow('"task"')} ${
|
|
63688
|
-
${green("claudish")} --model grok ${yellow("--permission-mode plan")} -i ${
|
|
63689
|
-
${
|
|
64066
|
+
${dim2("Any unrecognized flag is forwarded to Claude Code. Claudish flags can appear in any order.")}
|
|
64067
|
+
${green("claudish")} --model grok ${yellow("--agent test")} ${yellow('"task"')} ${dim2("# --agent passes through")}
|
|
64068
|
+
${green("claudish")} --model grok ${yellow("--effort high")} --stdin ${yellow('"task"')} ${dim2("# --effort passes, --stdin stays")}
|
|
64069
|
+
${green("claudish")} --model grok ${yellow("--permission-mode plan")} -i ${dim2("# works in interactive too")}
|
|
64070
|
+
${dim2("Use -- when a Claude Code flag value starts with '-':")}
|
|
63690
64071
|
${green("claudish")} --model grok ${green("--")} ${yellow('--system-prompt "-verbose mode" "task"')}
|
|
63691
64072
|
|
|
63692
64073
|
${h("CUSTOM MODELS & ENDPOINTS")}
|
|
63693
|
-
${
|
|
64074
|
+
${dim2("Claudish accepts ANY valid model ID from the Firebase catalog, even if not in --models:")}
|
|
63694
64075
|
${green("claudish")} --model ${yellow("openrouter@your_provider/custom-model-123")} ${yellow('"task"')}
|
|
63695
|
-
${
|
|
64076
|
+
${dim2("Named custom endpoints live in ~/.claudish/config.json under 'customEndpoints' and route via @:")}
|
|
63696
64077
|
${green("claudish")} --model ${yellow("my-vllm@llama3.1-70b")} ${yellow('"task"')}
|
|
63697
64078
|
|
|
63698
64079
|
${h("MODES")}
|
|
63699
|
-
${green("\u2022")} ${
|
|
63700
|
-
${green("\u2022")} ${
|
|
64080
|
+
${green("\u2022")} ${bold3("Interactive")} ${dim2("(default):")} shows model selector, starts a persistent session
|
|
64081
|
+
${green("\u2022")} ${bold3("Single-shot")} ${dim2("(--model):")} runs one task headless and exits
|
|
63701
64082
|
|
|
63702
64083
|
${h("NOTES")}
|
|
63703
|
-
${yellow("\u2022")} Permission prompts are ${
|
|
64084
|
+
${yellow("\u2022")} Permission prompts are ${bold3("ENABLED")} by default (normal Claude Code behavior)
|
|
63704
64085
|
${yellow("\u2022")} Use ${green("-y")} / ${green("--auto-approve")} to skip permission prompts
|
|
63705
64086
|
${yellow("\u2022")} Model selector appears ONLY in interactive mode when ${green("--model")} not specified
|
|
63706
64087
|
${yellow("\u2022")} ${green("--dangerous")} disables the sandbox \u2014 use with extreme caution
|
|
63707
64088
|
|
|
63708
64089
|
${h("ENVIRONMENT VARIABLES")}
|
|
63709
|
-
${
|
|
64090
|
+
${dim2("Claudish auto-loads a .env file from the current directory.")}
|
|
63710
64091
|
|
|
63711
|
-
${
|
|
64092
|
+
${bold3("Claude Code installation:")}
|
|
63712
64093
|
${blue("CLAUDE_PATH")} Custom path to Claude Code binary
|
|
63713
|
-
${
|
|
64094
|
+
${dim2("Search: CLAUDE_PATH -> ~/.claude/local/claude -> PATH")}
|
|
63714
64095
|
|
|
63715
|
-
${
|
|
64096
|
+
${bold3("API keys")} ${dim2("(at least one required for cloud models):")}
|
|
63716
64097
|
${blue("OPENROUTER_API_KEY")} OpenRouter (default backend)
|
|
63717
|
-
${blue("GEMINI_API_KEY")} Google Gemini ${
|
|
63718
|
-
${blue("OPENAI_API_KEY")} OpenAI ${
|
|
63719
|
-
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${
|
|
63720
|
-
${blue("XAI_API_KEY")} xAI / Grok ${
|
|
63721
|
-
${blue("MINIMAX_API_KEY")} MiniMax ${
|
|
63722
|
-
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${
|
|
63723
|
-
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${
|
|
63724
|
-
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${
|
|
63725
|
-
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${
|
|
63726
|
-
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${
|
|
63727
|
-
${blue("ZAI_API_KEY")} Z.AI ${
|
|
63728
|
-
${blue("DEEPSEEK_API_KEY")} DeepSeek ${
|
|
63729
|
-
${blue("SAKANA_API_KEY")} Sakana Fugu ${
|
|
63730
|
-
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${
|
|
63731
|
-
${blue("OLLAMA_API_KEY")} OllamaCloud ${
|
|
63732
|
-
${blue("OPENCODE_API_KEY")} OpenCode Zen ${
|
|
63733
|
-
${blue("POE_API_KEY")} Poe ${
|
|
63734
|
-
${blue("LITELLM_API_KEY")} LiteLLM ${
|
|
63735
|
-
${blue("VERTEX_API_KEY")} Vertex AI Express ${
|
|
63736
|
-
${blue("VERTEX_PROJECT")} Vertex AI project ID ${
|
|
63737
|
-
${blue("VERTEX_LOCATION")} Vertex AI region ${
|
|
64098
|
+
${blue("GEMINI_API_KEY")} Google Gemini ${dim2("(g@, gemini@; alias GOOGLE_API_KEY)")}
|
|
64099
|
+
${blue("OPENAI_API_KEY")} OpenAI ${dim2("(oai@)")}
|
|
64100
|
+
${blue("OPENAI_CODEX_API_KEY")} OpenAI Codex / Responses API ${dim2("(cx@, codex@)")}
|
|
64101
|
+
${blue("XAI_API_KEY")} xAI / Grok ${dim2("(x-ai@, grok@)")}
|
|
64102
|
+
${blue("MINIMAX_API_KEY")} MiniMax ${dim2("(mm@, mmax@)")}
|
|
64103
|
+
${blue("MINIMAX_CODING_API_KEY")} MiniMax Coding Plan ${dim2("(mmc@)")}
|
|
64104
|
+
${blue("MOONSHOT_API_KEY")} Kimi / Moonshot ${dim2("(kimi@, moon@; alias KIMI_API_KEY)")}
|
|
64105
|
+
${blue("KIMI_CODING_API_KEY")} Kimi Coding Plan ${dim2("(kc@)")}
|
|
64106
|
+
${blue("ZHIPU_API_KEY")} GLM / Zhipu ${dim2("(glm@, zhipu@; alias GLM_API_KEY)")}
|
|
64107
|
+
${blue("GLM_CODING_API_KEY")} GLM Coding Plan ${dim2("(gc@; alias ZAI_CODING_API_KEY)")}
|
|
64108
|
+
${blue("ZAI_API_KEY")} Z.AI ${dim2("(z-ai@, zai@)")}
|
|
64109
|
+
${blue("DEEPSEEK_API_KEY")} DeepSeek ${dim2("(ds@)")}
|
|
64110
|
+
${blue("SAKANA_API_KEY")} Sakana Fugu ${dim2("(sakana@, fugu@)")}
|
|
64111
|
+
${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim2("(sc@; separate subscription key)")}
|
|
64112
|
+
${blue("OLLAMA_API_KEY")} OllamaCloud ${dim2("(oc@, llama@)")}
|
|
64113
|
+
${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim2("(zen@; optional - free models work without it)")}
|
|
64114
|
+
${blue("POE_API_KEY")} Poe ${dim2("(poe@)")}
|
|
64115
|
+
${blue("LITELLM_API_KEY")} LiteLLM ${dim2("(litellm@, ll@; needs LITELLM_BASE_URL)")}
|
|
64116
|
+
${blue("VERTEX_API_KEY")} Vertex AI Express ${dim2("(v@)")}
|
|
64117
|
+
${blue("VERTEX_PROJECT")} Vertex AI project ID ${dim2("(OAuth mode, v@)")}
|
|
64118
|
+
${blue("VERTEX_LOCATION")} Vertex AI region ${dim2("(default: us-central1)")}
|
|
63738
64119
|
${blue("ANTHROPIC_API_KEY")} Placeholder (prevents Claude Code dialog)
|
|
63739
64120
|
${blue("ANTHROPIC_AUTH_TOKEN")} Placeholder (prevents Claude Code login screen)
|
|
63740
64121
|
|
|
63741
|
-
${
|
|
64122
|
+
${bold3("Custom / base-URL overrides:")}
|
|
63742
64123
|
${blue("GEMINI_BASE_URL")} Custom Gemini endpoint
|
|
63743
64124
|
${blue("OPENAI_BASE_URL")} Custom OpenAI / Azure endpoint
|
|
63744
64125
|
${blue("MINIMAX_BASE_URL")} Custom MiniMax endpoint
|
|
63745
|
-
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${
|
|
63746
|
-
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${
|
|
63747
|
-
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${
|
|
63748
|
-
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${
|
|
63749
|
-
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${
|
|
63750
|
-
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${
|
|
63751
|
-
|
|
63752
|
-
${
|
|
63753
|
-
${blue("OLLAMA_BASE_URL")} Ollama server ${
|
|
63754
|
-
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${
|
|
63755
|
-
${blue("VLLM_BASE_URL")} vLLM server ${
|
|
63756
|
-
${blue("MLX_BASE_URL")} MLX server ${
|
|
63757
|
-
|
|
63758
|
-
${
|
|
63759
|
-
${blue("CLAUDISH_MODEL")} Default model ${
|
|
63760
|
-
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${
|
|
64126
|
+
${blue("MOONSHOT_BASE_URL")} Custom Kimi / Moonshot endpoint ${dim2("(alias KIMI_BASE_URL)")}
|
|
64127
|
+
${blue("ZHIPU_BASE_URL")} Custom GLM / Zhipu endpoint ${dim2("(alias GLM_BASE_URL)")}
|
|
64128
|
+
${blue("SAKANA_BASE_URL")} Custom Sakana endpoint ${dim2("(default: https://api.sakana.ai)")}
|
|
64129
|
+
${blue("LITELLM_BASE_URL")} LiteLLM gateway base URL ${dim2("(required for ll@)")}
|
|
64130
|
+
${blue("OLLAMACLOUD_BASE_URL")} OllamaCloud ${dim2("(default: https://ollama.com)")}
|
|
64131
|
+
${blue("OPENCODE_BASE_URL")} OpenCode Zen ${dim2("(default: https://opencode.ai/zen)")}
|
|
64132
|
+
|
|
64133
|
+
${bold3("Local providers:")}
|
|
64134
|
+
${blue("OLLAMA_BASE_URL")} Ollama server ${dim2("(default: http://localhost:11434; alias OLLAMA_HOST)")}
|
|
64135
|
+
${blue("LMSTUDIO_BASE_URL")} LM Studio server ${dim2("(default: http://localhost:1234)")}
|
|
64136
|
+
${blue("VLLM_BASE_URL")} vLLM server ${dim2("(default: http://localhost:8000)")}
|
|
64137
|
+
${blue("MLX_BASE_URL")} MLX server ${dim2("(default: http://127.0.0.1:8080)")}
|
|
64138
|
+
|
|
64139
|
+
${bold3("Claudish settings:")}
|
|
64140
|
+
${blue("CLAUDISH_MODEL")} Default model ${dim2("(default: openai/gpt-5.3)")}
|
|
64141
|
+
${blue("CLAUDISH_DEFAULT_PROVIDER")} Fallback provider for bare names ${dim2("(see --default-provider)")}
|
|
63761
64142
|
${blue("CLAUDISH_PORT")} Default proxy port
|
|
63762
64143
|
${blue("CLAUDISH_CONTEXT_WINDOW")} Override context window size
|
|
63763
64144
|
${blue("CLAUDISH_DIAG_MODE")} Diagnostic output: auto / logfile / off
|
|
63764
|
-
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${
|
|
63765
|
-
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${
|
|
64145
|
+
${blue("CLAUDISH_DEBUG")} Always enable debug logging: 1 / true ${dim2("(same as -d)")}
|
|
64146
|
+
${blue("CLAUDISH_ANTHROPIC_API_BILLING")} Bill native Claude to your API key ${dim2("(see --anthropic-api-billing)")}
|
|
63766
64147
|
${blue("CLAUDISH_MCP_TOOLS")} MCP tool gating: all / low-level / agentic / channel
|
|
63767
64148
|
${blue("CLAUDISH_MODEL_OPUS")} Override model for Opus role
|
|
63768
64149
|
${blue("CLAUDISH_MODEL_SONNET")} Override model for Sonnet role
|
|
@@ -63770,41 +64151,41 @@ ${h("ENVIRONMENT VARIABLES")}
|
|
|
63770
64151
|
${blue("CLAUDISH_MODEL_SUBAGENT")} Override model for sub-agents
|
|
63771
64152
|
${blue("NO_COLOR")} Set to disable colored output
|
|
63772
64153
|
|
|
63773
|
-
${
|
|
64154
|
+
${bold3("1Password auth:")}
|
|
63774
64155
|
${blue("OP_SERVICE_ACCOUNT_TOKEN")} Service-account token (preferred for headless)
|
|
63775
|
-
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${
|
|
64156
|
+
${blue("OP_ACCOUNT")} Account URL for DesktopAuth ${dim2("(e.g. my-team.1password.com)")}
|
|
63776
64157
|
|
|
63777
64158
|
${h("EXAMPLES")}
|
|
63778
|
-
${
|
|
64159
|
+
${dim2("# Interactive (default) - model selector")}
|
|
63779
64160
|
${green("claudish")}
|
|
63780
|
-
${green("claudish")} --free ${
|
|
64161
|
+
${green("claudish")} --free ${dim2("# only FREE models")}
|
|
63781
64162
|
|
|
63782
|
-
${
|
|
64163
|
+
${dim2("# Explicit provider routing")}
|
|
63783
64164
|
${green("claudish")} --model ${magenta("google@gemini-3-pro")} ${yellow('"implement auth"')}
|
|
63784
64165
|
${green("claudish")} --model ${magenta("oai@gpt-5.3")} ${yellow('"add tests for login"')}
|
|
63785
64166
|
${green("claudish")} --model ${magenta("openrouter@deepseek/deepseek-r1")} ${yellow('"unknown vendor"')}
|
|
63786
64167
|
|
|
63787
|
-
${
|
|
64168
|
+
${dim2("# Native auto-detection (provider inferred from model name)")}
|
|
63788
64169
|
${green("claudish")} --model ${yellow("gpt-4o")} ${yellow('"routes to OpenAI"')}
|
|
63789
64170
|
${green("claudish")} --model ${yellow("gemini-2.5-pro")} ${yellow('"routes to Google"')}
|
|
63790
64171
|
|
|
63791
|
-
${
|
|
64172
|
+
${dim2("# Per-role model mapping")}
|
|
63792
64173
|
${green("claudish")} --model-opus ${magenta("oai@gpt-5.3")} --model-sonnet ${magenta("google@gemini-3-pro")}
|
|
63793
64174
|
|
|
63794
|
-
${
|
|
63795
|
-
${
|
|
64175
|
+
${dim2("# stdin for large prompts (diffs, code review)")}
|
|
64176
|
+
${dim2("git diff |")} ${green("claudish")} --stdin --model ${magenta("oai@gpt-5.3")} ${yellow('"Review these changes"')}
|
|
63796
64177
|
|
|
63797
|
-
${
|
|
64178
|
+
${dim2("# Local models with concurrency control")}
|
|
63798
64179
|
${green("claudish")} --model ${magenta("ollama@llama3.2:3")} ${yellow('"3 concurrent requests"')}
|
|
63799
64180
|
${green("claudish")} --model ${magenta("lms@qwen2.5-coder")} ${yellow('"LM Studio shortcut"')}
|
|
63800
64181
|
${green("claudish")} --model ${yellow('"http://localhost:8000/mistral"')} ${yellow('"any OpenAI-compatible URL"')}
|
|
63801
64182
|
|
|
63802
|
-
${
|
|
64183
|
+
${dim2("# Autonomous (no prompts, no sandbox) \u2014 use with caution")}
|
|
63803
64184
|
${green("claudish")} -y --dangerous ${yellow('"refactor entire codebase"')}
|
|
63804
64185
|
|
|
63805
64186
|
${h("MORE INFO")}
|
|
63806
|
-
${
|
|
63807
|
-
${
|
|
64187
|
+
${dim2("GitHub:")} ${blue("https://github.com/MadAppGang/claude-code")}
|
|
64188
|
+
${dim2("OpenRouter:")} ${blue("https://openrouter.ai")}
|
|
63808
64189
|
`);
|
|
63809
64190
|
}
|
|
63810
64191
|
function printAIAgentGuide() {
|
|
@@ -71859,8 +72240,8 @@ var init_claude_runner = __esm(() => {
|
|
|
71859
72240
|
init_model_catalog();
|
|
71860
72241
|
init_config();
|
|
71861
72242
|
init_logger();
|
|
71862
|
-
init_model_discovery();
|
|
71863
72243
|
init_profile_config();
|
|
72244
|
+
init_model_discovery();
|
|
71864
72245
|
init_model_parser();
|
|
71865
72246
|
init_routing_rules();
|
|
71866
72247
|
init_telemetry();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.22.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"ai"
|
|
61
61
|
],
|
|
62
62
|
"optionalDependencies": {
|
|
63
|
-
"@claudish/magmux-darwin-arm64": "7.
|
|
64
|
-
"@claudish/magmux-darwin-x64": "7.
|
|
65
|
-
"@claudish/magmux-linux-arm64": "7.
|
|
66
|
-
"@claudish/magmux-linux-x64": "7.
|
|
63
|
+
"@claudish/magmux-darwin-arm64": "7.22.0",
|
|
64
|
+
"@claudish/magmux-darwin-x64": "7.22.0",
|
|
65
|
+
"@claudish/magmux-linux-arm64": "7.22.0",
|
|
66
|
+
"@claudish/magmux-linux-x64": "7.22.0"
|
|
67
67
|
},
|
|
68
68
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
69
69
|
"license": "MIT",
|