claudish 7.25.0 → 7.26.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.
Files changed (2) hide show
  1. package/dist/index.js +1022 -440
  2. 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.25.0";
654
+ var VERSION = "7.26.0";
655
655
 
656
656
  // src/logger.ts
657
657
  var exports_logger = {};
@@ -1173,6 +1173,122 @@ var init_startup_trace = __esm(() => {
1173
1173
  spans = [];
1174
1174
  });
1175
1175
 
1176
+ // src/providers/onepassword-handshake-lock.ts
1177
+ import { closeSync, mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync3, rmSync, statSync, writeSync } from "fs";
1178
+ import { homedir as homedir4 } from "os";
1179
+ import { dirname as dirname2, join as join4 } from "path";
1180
+ function defaultLockPath() {
1181
+ return join4(homedir4(), ".claudish", "op-handshake.lock");
1182
+ }
1183
+ function currentLockPath() {
1184
+ return lockPath ?? defaultLockPath();
1185
+ }
1186
+ function trace(message) {
1187
+ if (process.env.CLAUDISH_OP_LOCK_TRACE !== "1")
1188
+ return;
1189
+ console.error(`[op-lock] pid=${process.pid} ${message}`);
1190
+ }
1191
+ function readHolder(path) {
1192
+ try {
1193
+ const [pidRaw, atRaw] = readFileSync3(path, "utf-8").trim().split(/\s+/);
1194
+ const pid = Number(pidRaw);
1195
+ const at = Number(atRaw);
1196
+ if (!Number.isInteger(pid) || pid <= 0)
1197
+ return null;
1198
+ return { pid, at: Number.isFinite(at) ? at : 0 };
1199
+ } catch {
1200
+ return null;
1201
+ }
1202
+ }
1203
+ function holderAlive(pid) {
1204
+ try {
1205
+ process.kill(pid, 0);
1206
+ return true;
1207
+ } catch (err) {
1208
+ return err?.code === "EPERM";
1209
+ }
1210
+ }
1211
+ function isAbandoned(path) {
1212
+ const holder = readHolder(path);
1213
+ if (!holder) {
1214
+ try {
1215
+ return Date.now() - statSync(path).mtimeMs > timing.staleMs;
1216
+ } catch {
1217
+ return false;
1218
+ }
1219
+ }
1220
+ if (holder.pid !== process.pid && !holderAlive(holder.pid))
1221
+ return true;
1222
+ return Date.now() - holder.at > timing.staleMs;
1223
+ }
1224
+ async function acquire(path) {
1225
+ const deadline = Date.now() + timing.timeoutMs;
1226
+ let madeDir = false;
1227
+ for (;; ) {
1228
+ try {
1229
+ if (!madeDir) {
1230
+ mkdirSync3(dirname2(path), { recursive: true });
1231
+ madeDir = true;
1232
+ }
1233
+ const fd = openSync(path, "wx");
1234
+ try {
1235
+ writeSync(fd, `${process.pid} ${Date.now()}`);
1236
+ } finally {
1237
+ closeSync(fd);
1238
+ }
1239
+ return true;
1240
+ } catch (err) {
1241
+ if (err?.code !== "EEXIST")
1242
+ return false;
1243
+ if (isAbandoned(path)) {
1244
+ try {
1245
+ rmSync(path, { force: true });
1246
+ } catch {}
1247
+ continue;
1248
+ }
1249
+ if (Date.now() >= deadline)
1250
+ return false;
1251
+ await sleep(timing.pollMs + Math.floor(Math.random() * timing.pollMs));
1252
+ }
1253
+ }
1254
+ }
1255
+ function release(path) {
1256
+ try {
1257
+ if (readHolder(path)?.pid === process.pid)
1258
+ rmSync(path, { force: true });
1259
+ } catch {}
1260
+ }
1261
+ async function withHandshakeLock(handshake) {
1262
+ if (process.env.CLAUDISH_NO_OP_HANDSHAKE_LOCK === "1") {
1263
+ trace("bypassed (CLAUDISH_NO_OP_HANDSHAKE_LOCK=1)");
1264
+ return handshake();
1265
+ }
1266
+ const path = currentLockPath();
1267
+ const t0 = Date.now();
1268
+ let held = false;
1269
+ try {
1270
+ held = await acquire(path);
1271
+ } catch {
1272
+ held = false;
1273
+ }
1274
+ trace(`${held ? "acquired" : "NOT held (timeout or unwritable)"} after ${Date.now() - t0}ms`);
1275
+ try {
1276
+ return await handshake();
1277
+ } finally {
1278
+ if (held)
1279
+ release(path);
1280
+ trace(`handshake done after ${Date.now() - t0}ms${held ? ", released" : ""}`);
1281
+ }
1282
+ }
1283
+ var DEFAULT_STALE_MS = 120000, DEFAULT_TIMEOUT_MS = 45000, DEFAULT_POLL_MS = 60, timing, lockPath, sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1284
+ var init_onepassword_handshake_lock = __esm(() => {
1285
+ timing = {
1286
+ staleMs: DEFAULT_STALE_MS,
1287
+ timeoutMs: DEFAULT_TIMEOUT_MS,
1288
+ pollMs: DEFAULT_POLL_MS
1289
+ };
1290
+ });
1291
+
1176
1292
  // src/providers/onepassword-wasm.ts
1177
1293
  var exports_onepassword_wasm = {};
1178
1294
  __export(exports_onepassword_wasm, {
@@ -1185,17 +1301,17 @@ __export(exports_onepassword_wasm, {
1185
1301
  SDK_CORE_INTEGRITY: () => SDK_CORE_INTEGRITY
1186
1302
  });
1187
1303
  import { createHash } from "crypto";
1188
- import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
1304
+ import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
1189
1305
  import { createRequire } from "module";
1190
- import { homedir as homedir4 } from "os";
1191
- import { dirname as dirname2, join as join4 } from "path";
1306
+ import { homedir as homedir5 } from "os";
1307
+ import { dirname as dirname3, join as join5 } from "path";
1192
1308
  import { gunzipSync } from "zlib";
1193
1309
  function tarballUrl() {
1194
1310
  return `https://registry.npmjs.org/@1password/sdk-core/-/sdk-core-${SDK_CORE_VERSION}.tgz`;
1195
1311
  }
1196
1312
  function cacheWasmPath() {
1197
- const root = cacheRootOverride ?? join4(homedir4(), ".claudish");
1198
- return join4(root, "cache", "1password", WASM_FILENAME);
1313
+ const root = cacheRootOverride ?? join5(homedir5(), ".claudish");
1314
+ return join5(root, "cache", "1password", WASM_FILENAME);
1199
1315
  }
1200
1316
  function verifyIntegrity(bytes) {
1201
1317
  const [algo, expected] = SDK_CORE_INTEGRITY.split("-", 2);
@@ -1236,7 +1352,7 @@ function installReadFileSyncIntercept() {
1236
1352
  }
1237
1353
  if (existsSync3(path)) {
1238
1354
  try {
1239
- mkdirSync3(dirname2(cached), { recursive: true });
1355
+ mkdirSync4(dirname3(cached), { recursive: true });
1240
1356
  copyFileSync(path, cached);
1241
1357
  } catch {}
1242
1358
  }
@@ -1259,7 +1375,7 @@ async function downloadAndCacheWasm() {
1259
1375
  if (!wasm) {
1260
1376
  throw new Error(`1Password runtime archive did not contain ${WASM_TARBALL_ENTRY}`);
1261
1377
  }
1262
- mkdirSync3(dirname2(cached), { recursive: true });
1378
+ mkdirSync4(dirname3(cached), { recursive: true });
1263
1379
  const tmp = `${cached}.tmp`;
1264
1380
  writeFileSync4(tmp, wasm);
1265
1381
  createRequire(import.meta.url)("node:fs").renameSync(tmp, cached);
@@ -1292,7 +1408,7 @@ function resolveNearbyWasmPath() {
1292
1408
  try {
1293
1409
  const require2 = createRequire(import.meta.url);
1294
1410
  const coreJs = require2.resolve("@1password/sdk-core/nodejs/core.js");
1295
- const wasm = join4(dirname2(coreJs), WASM_FILENAME);
1411
+ const wasm = join5(dirname3(coreJs), WASM_FILENAME);
1296
1412
  return existsSync3(wasm) ? wasm : null;
1297
1413
  } catch {
1298
1414
  return null;
@@ -1304,7 +1420,7 @@ function seedCacheFromNearbyWasm() {
1304
1420
  return false;
1305
1421
  try {
1306
1422
  const cached = cacheWasmPath();
1307
- mkdirSync3(dirname2(cached), { recursive: true });
1423
+ mkdirSync4(dirname3(cached), { recursive: true });
1308
1424
  copyFileSync(real, cached);
1309
1425
  return true;
1310
1426
  } catch {
@@ -3658,6 +3774,7 @@ __export(exports_onepassword, {
3658
3774
  valueTail: () => valueTail,
3659
3775
  setScreenLockProbe: () => setScreenLockProbe,
3660
3776
  setLockRetryTiming: () => setLockRetryTiming,
3777
+ setAppLockProbe: () => setAppLockProbe,
3661
3778
  resolveSecretsPartial: () => resolveSecretsPartial,
3662
3779
  resolveSecrets: () => resolveSecrets,
3663
3780
  resolveSdkAuth: () => resolveSdkAuth,
@@ -3682,6 +3799,7 @@ __export(exports_onepassword, {
3682
3799
  isOpHydratedVar: () => isOpHydratedVar,
3683
3800
  isLockedDenial: () => isLockedDenial,
3684
3801
  isGlobImport: () => isGlobImport,
3802
+ isAppLocked: () => isAppLocked,
3685
3803
  globToRegExp: () => globToRegExp,
3686
3804
  getOpFailures: () => getOpFailures,
3687
3805
  filterGlobFields: () => filterGlobFields,
@@ -3692,8 +3810,12 @@ __export(exports_onepassword, {
3692
3810
  defaultSdkClientFactory: () => defaultSdkClientFactory,
3693
3811
  defaultScreenLockProbe: () => defaultScreenLockProbe,
3694
3812
  defaultOpAccountLister: () => defaultOpAccountLister,
3813
+ defaultAppLockProbe: () => defaultAppLockProbe,
3814
+ currentLockCause: () => currentLockCause,
3695
3815
  collectConfigImports: () => collectConfigImports,
3816
+ classifyLockedDenial: () => classifyLockedDenial,
3696
3817
  buildAuthError: () => buildAuthError,
3818
+ appLockedFromSettings: () => appLockedFromSettings,
3697
3819
  acquireSdkClient: () => acquireSdkClient,
3698
3820
  OP_REF_RE: () => OP_REF_RE
3699
3821
  });
@@ -3735,11 +3857,24 @@ function renderOpFailureNotice(envVar) {
3735
3857
  }
3736
3858
  lines.push("");
3737
3859
  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.");
3860
+ const cause = currentLockCause();
3861
+ if (cause === "screen") {
3862
+ lines.push(" Your Mac is locked, so the 1Password approval prompt cannot be shown.");
3863
+ lines.push("");
3864
+ lines.push(" Fix: unlock the Mac, approve the prompt, and re-run.");
3865
+ } else if (cause === "app") {
3866
+ lines.push(" The 1Password app is LOCKED. With shared lock state (the default) a locked");
3867
+ lines.push(" app refuses the SDK outright \u2014 no approval prompt is ever shown, which is");
3868
+ lines.push(" why nothing appeared on screen.");
3869
+ lines.push("");
3870
+ lines.push(" Fix: unlock 1Password (Touch ID is enough) and re-run.");
3871
+ lines.push(" To stop it re-locking mid-session, raise Settings \u2192 Security \u2192 auto-lock.");
3872
+ } else {
3873
+ lines.push(" The 1Password desktop app declined to release secrets. The approval prompt");
3874
+ lines.push(" was most likely dismissed.");
3875
+ lines.push("");
3876
+ lines.push(" Fix: re-run and approve the 1Password prompt.");
3877
+ }
3743
3878
  lines.push(" Headless (no desktop app): export OP_SERVICE_ACCOUNT_TOKEN='ops_...'");
3744
3879
  } else {
3745
3880
  lines.push(" Fix: check the reference resolves \u2014 claudish config \u2192 1Password tab.");
@@ -4092,25 +4227,57 @@ function setScreenLockProbe(probe) {
4092
4227
  function isScreenLocked() {
4093
4228
  return screenLockProbe();
4094
4229
  }
4095
- function isLockedDenial(err, env = process.env) {
4230
+ function appLockedFromSettings(settings, nowSeconds) {
4231
+ if (typeof settings !== "object" || settings === null)
4232
+ return false;
4233
+ const s = settings;
4234
+ if (s["developers.sdkSharedLockState.enabled"] !== true)
4235
+ return false;
4236
+ const last = s["security.authenticatedUnlock.deviceBasedUnlock.lastUnlock"];
4237
+ const after = s["security.authenticatedUnlock.deviceBasedUnlock.askUnlockAfter"];
4238
+ if (typeof last !== "number" || typeof after !== "number")
4239
+ return false;
4240
+ return nowSeconds - last > after;
4241
+ }
4242
+ function setAppLockProbe(probe) {
4243
+ appLockProbe = probe ?? defaultAppLockProbe;
4244
+ }
4245
+ function isAppLocked() {
4246
+ return appLockProbe();
4247
+ }
4248
+ function currentLockCause() {
4249
+ if (isScreenLocked())
4250
+ return "screen";
4251
+ if (isAppLocked())
4252
+ return "app";
4253
+ return null;
4254
+ }
4255
+ function classifyLockedDenial(err, env = process.env) {
4096
4256
  const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
4097
4257
  if (!msg.includes("denied authorization"))
4098
- return false;
4258
+ return null;
4099
4259
  if (env.OP_SERVICE_ACCOUNT_TOKEN)
4100
- return false;
4101
- return isScreenLocked();
4260
+ return null;
4261
+ return currentLockCause();
4262
+ }
4263
+ function isLockedDenial(err, env = process.env) {
4264
+ return classifyLockedDenial(err, env) !== null;
4102
4265
  }
4103
- async function countdownForUnlock(round, rounds) {
4266
+ async function countdownForUnlock(round, rounds, cause) {
4104
4267
  const ttyOut = process.stderr.isTTY === true;
4105
4268
  const ttyIn = process.stdin.isTTY === true;
4106
4269
  let cancelled = false;
4107
4270
  if (round === 1) {
4271
+ const explain = cause === "screen" ? `${bold("\uD83D\uDD10 1Password needs your OK \u2014 but your Mac is locked, so it can't ask.")}
4272
+ Unlock your Mac and approve the popup. Claudish picks it up from there.` : `${bold("\uD83D\uDD10 1Password is locked, so it turned claudish away without asking you.")}
4273
+ Unlock 1Password (Touch ID is enough). Claudish retries on its own \u2014
4274
+ no popup will appear until it's unlocked.`;
4108
4275
  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.
4276
+ ${explain}
4111
4277
 
4112
4278
  `);
4113
4279
  }
4280
+ const stillLocked = () => cause === "screen" ? isScreenLocked() : isAppLocked();
4114
4281
  let restoreInput = () => {};
4115
4282
  if (ttyIn) {
4116
4283
  const onKey = (buf) => {
@@ -4141,7 +4308,7 @@ ${bold("\uD83D\uDD10 1Password needs your OK \u2014 but your Mac is locked, so i
4141
4308
  for (let remaining = lockRetrySeconds;remaining > 0; remaining--) {
4142
4309
  if (cancelled)
4143
4310
  break;
4144
- if (!isScreenLocked())
4311
+ if (!stillLocked())
4145
4312
  break;
4146
4313
  if (ttyOut)
4147
4314
  process.stderr.write(`\r\x1B[2K${line(remaining)}`);
@@ -4164,9 +4331,10 @@ async function withSdkRetry(op, label = "op:sdk-op") {
4164
4331
  try {
4165
4332
  return await withSdkTransientRetry(op, label);
4166
4333
  } catch (err) {
4167
- if (round > LOCK_RETRY_ROUNDS || !isLockedDenial(err))
4334
+ const cause = classifyLockedDenial(err);
4335
+ if (round > LOCK_RETRY_ROUNDS || cause === null)
4168
4336
  throw err;
4169
- if (await countdownForUnlock(round, LOCK_RETRY_ROUNDS) === "cancel")
4337
+ if (await countdownForUnlock(round, LOCK_RETRY_ROUNDS, cause) === "cancel")
4170
4338
  throw err;
4171
4339
  resetSdkClientCache();
4172
4340
  }
@@ -4359,11 +4527,12 @@ var OP_REF_RE, opHydratedVars, opSourceFailures, ENV_VAR_NAME_RE, sdkClientCache
4359
4527
  await ensureOpWasmAvailable2();
4360
4528
  return Promise.resolve().then(() => __toESM(require_sdk(), 1));
4361
4529
  });
4362
- const client = await traceSpan("op:client-handshake", () => createClient({
4530
+ const build2 = () => createClient({
4363
4531
  auth: auth.kind === "token" ? auth.token : new DesktopAuth(auth.accountName),
4364
4532
  integrationName: "claudish",
4365
4533
  integrationVersion: VERSION || "1.0.0"
4366
- }), { mayIncludeUserPrompt: true, authKind: auth.kind });
4534
+ });
4535
+ const client = await traceSpan("op:client-handshake", () => auth.kind === "token" ? build2() : withHandshakeLock(build2), { mayIncludeUserPrompt: true, authKind: auth.kind });
4367
4536
  return client;
4368
4537
  })();
4369
4538
  sdkClientCache.set(key, build);
@@ -4383,7 +4552,7 @@ var OP_REF_RE, opHydratedVars, opSourceFailures, ENV_VAR_NAME_RE, sdkClientCache
4383
4552
  } catch {
4384
4553
  return false;
4385
4554
  }
4386
- }, screenLockProbe, defaultOpAccountLister = () => {
4555
+ }, screenLockProbe, defaultAppLockProbe = () => false, appLockProbe, defaultOpAccountLister = () => {
4387
4556
  try {
4388
4557
  const res = spawnSync("op", ["account", "list", "--format=json"], { encoding: "utf-8" });
4389
4558
  if (res.error || res.status !== 0)
@@ -4412,6 +4581,7 @@ var OP_REF_RE, opHydratedVars, opSourceFailures, ENV_VAR_NAME_RE, sdkClientCache
4412
4581
  };
4413
4582
  var init_onepassword = __esm(() => {
4414
4583
  init_startup_trace();
4584
+ init_onepassword_handshake_lock();
4415
4585
  OP_REF_RE = /^op:\/\/[^\s]+$/;
4416
4586
  opHydratedVars = new Set;
4417
4587
  opSourceFailures = [];
@@ -4420,18 +4590,34 @@ var init_onepassword = __esm(() => {
4420
4590
  sdkQueue = Promise.resolve();
4421
4591
  lockRetrySeconds = LOCK_RETRY_SECONDS;
4422
4592
  screenLockProbe = defaultScreenLockProbe;
4593
+ appLockProbe = defaultAppLockProbe;
4423
4594
  });
4424
4595
 
4425
4596
  // src/auth/credentials/op-source.ts
4426
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
4427
- import { homedir as homedir5 } from "os";
4428
- import { join as join5 } from "path";
4597
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
4598
+ import { homedir as homedir6 } from "os";
4599
+ import { join as join6 } from "path";
4429
4600
  function warnOnce(message) {
4430
4601
  if (warnedMessages.has(message))
4431
4602
  return;
4432
4603
  warnedMessages.add(message);
4433
4604
  console.error(message);
4434
4605
  }
4606
+ function recordOpUnavailableVars(names) {
4607
+ for (const n of names) {
4608
+ if (typeof n === "string" && n.length > 0)
4609
+ opUnavailableVars.add(n);
4610
+ }
4611
+ }
4612
+ function getOpUnavailableVars() {
4613
+ return [...opUnavailableVars].sort();
4614
+ }
4615
+ function inheritedUnavailable() {
4616
+ const raw = process.env[OP_UNAVAILABLE_ENV];
4617
+ if (!raw)
4618
+ return new Set;
4619
+ return new Set(raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0));
4620
+ }
4435
4621
  function saveAccount(accountUrl, scope) {
4436
4622
  try {
4437
4623
  saveOnepasswordAccount(accountUrl, scope);
@@ -4517,10 +4703,10 @@ function readConfigRaw() {
4517
4703
  if (testSeams?.config)
4518
4704
  return testSeams.config;
4519
4705
  try {
4520
- const configPath = activeGlobalConfigFile(join5(homedir5(), ".claudish", "config.json"));
4706
+ const configPath = activeGlobalConfigFile(join6(homedir6(), ".claudish", "config.json"));
4521
4707
  if (!existsSync4(configPath))
4522
4708
  return {};
4523
- return JSON.parse(readFileSync3(configPath, "utf-8"));
4709
+ return JSON.parse(readFileSync4(configPath, "utf-8"));
4524
4710
  } catch {
4525
4711
  return {};
4526
4712
  }
@@ -4623,12 +4809,12 @@ async function resolveGlobShared(globPath, auth) {
4623
4809
  return { resolved: await existing, cacheHit: true };
4624
4810
  const spanName = `op:glob-resolve(${maskGlobForTrace(globPath)})`;
4625
4811
  const promise = (async () => {
4626
- const { resolveGlobImportAll: resolveGlobImportAll2, recordOpHydratedVars: recordOpHydratedVars2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4627
- const resolved = await traceSpan(spanName, () => resolveGlobImportAll2(globPath, {
4812
+ const { resolveGlobImportAll: resolveGlobImportAll2, recordOpHydratedVars: recordOpHydratedVars2, withSdkRetry: withSdkRetry2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4813
+ const resolved = await traceSpan(spanName, () => withSdkRetry2(() => resolveGlobImportAll2(globPath, {
4628
4814
  auth,
4629
4815
  sdkFactory: testSeams?.sdkFactory,
4630
4816
  warn: (m) => console.error(m)
4631
- }));
4817
+ }), spanName));
4632
4818
  addSpanMeta(spanName, { vars: Object.keys(resolved).length });
4633
4819
  for (const [k, v] of Object.entries(resolved)) {
4634
4820
  resolvedCache.set(k, v);
@@ -4650,8 +4836,8 @@ async function resolveEnvironmentShared(envId, auth) {
4650
4836
  return { resolved: await existing, cacheHit: true };
4651
4837
  const spanName = `op:env-resolve(${envId})`;
4652
4838
  const promise = (async () => {
4653
- const { readEnvironment: readEnvironment2, recordOpHydratedVars: recordOpHydratedVars2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4654
- const resolved = await traceSpan(spanName, () => readEnvironment2(envId, { auth, sdkFactory: testSeams?.sdkFactory }));
4839
+ const { readEnvironment: readEnvironment2, recordOpHydratedVars: recordOpHydratedVars2, withSdkRetry: withSdkRetry2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4840
+ const resolved = await traceSpan(spanName, () => withSdkRetry2(() => readEnvironment2(envId, { auth, sdkFactory: testSeams?.sdkFactory }), spanName));
4655
4841
  addSpanMeta(spanName, { vars: Object.keys(resolved).length });
4656
4842
  for (const [k, v] of Object.entries(resolved)) {
4657
4843
  resolvedCache.set(k, v);
@@ -4686,6 +4872,8 @@ async function resolveOpKeyForEnvVars(wanted, opts = {}) {
4686
4872
  else
4687
4873
  stillWanted.add(w);
4688
4874
  }
4875
+ for (const skip of inheritedUnavailable())
4876
+ stillWanted.delete(skip);
4689
4877
  if (stillWanted.size === 0)
4690
4878
  return cached;
4691
4879
  const label = `op:resolve(${[...stillWanted].sort().join(",")})`;
@@ -4712,6 +4900,7 @@ async function resolveOpKeyForEnvVars(wanted, opts = {}) {
4712
4900
  resolvedCache.set(k, v);
4713
4901
  out[k] = v;
4714
4902
  }
4903
+ recordOpUnavailableVars([...wantNow].filter((w) => !(w in resolved)));
4715
4904
  return out;
4716
4905
  }, label);
4717
4906
  }
@@ -4738,7 +4927,13 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4738
4927
  throw err;
4739
4928
  }
4740
4929
  }
4741
- const { collectConfigImports: collectConfigImports2, resolveSecrets: resolveSecrets2, recordOpHydratedVars: recordOpHydratedVars2, recordOpFailure: recordOpFailure2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4930
+ const {
4931
+ collectConfigImports: collectConfigImports2,
4932
+ resolveSecrets: resolveSecrets2,
4933
+ recordOpHydratedVars: recordOpHydratedVars2,
4934
+ recordOpFailure: recordOpFailure2,
4935
+ withSdkRetry: withSdkRetry2
4936
+ } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4742
4937
  const cfg = readConfigRaw();
4743
4938
  const out = {};
4744
4939
  try {
@@ -4751,10 +4946,7 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4751
4946
  wantedRefs[envVar] = ref;
4752
4947
  }
4753
4948
  if (Object.keys(wantedRefs).length > 0) {
4754
- const resolved = await resolveSecrets2(wantedRefs, {
4755
- auth,
4756
- sdkFactory: testSeams?.sdkFactory
4757
- });
4949
+ const resolved = await withSdkRetry2(() => resolveSecrets2(wantedRefs, { auth, sdkFactory: testSeams?.sdkFactory }), "op:resolve-refs");
4758
4950
  Object.assign(out, resolved);
4759
4951
  }
4760
4952
  const stillWanted = new Set([...wanted].filter((w) => !(w in out)));
@@ -4791,10 +4983,7 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4791
4983
  customRefs[envVar] = apiKey;
4792
4984
  }
4793
4985
  if (Object.keys(customRefs).length > 0) {
4794
- const resolved = await resolveSecrets2(customRefs, {
4795
- auth,
4796
- sdkFactory: testSeams?.sdkFactory
4797
- });
4986
+ const resolved = await withSdkRetry2(() => resolveSecrets2(customRefs, { auth, sdkFactory: testSeams?.sdkFactory }), "op:resolve-custom-endpoint-refs");
4798
4987
  Object.assign(out, resolved);
4799
4988
  }
4800
4989
  }
@@ -4837,11 +5026,12 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4837
5026
  recordOpHydratedVars2(Object.keys(out));
4838
5027
  return out;
4839
5028
  }
4840
- var warnedMessages, OpAuthError, cachedSdkAuth, sdkAuthResolved = false, authInFlight, testSeams, sniffed, opQueue, resolvedCache, globResolutions, globResolvedVars, environmentResolutions;
5029
+ var warnedMessages, opUnavailableVars, OP_UNAVAILABLE_ENV = "CLAUDISH_OP_UNAVAILABLE", OpAuthError, cachedSdkAuth, sdkAuthResolved = false, authInFlight, testSeams, sniffed, opQueue, resolvedCache, globResolutions, globResolvedVars, environmentResolutions;
4841
5030
  var init_op_source = __esm(() => {
4842
5031
  init_onepassword_config();
4843
5032
  init_startup_trace();
4844
5033
  warnedMessages = new Set;
5034
+ opUnavailableVars = new Set;
4845
5035
  OpAuthError = class OpAuthError extends Error {
4846
5036
  constructor(message) {
4847
5037
  super(message);
@@ -26938,15 +27128,15 @@ __export(exports_profile_config, {
26938
27128
  configExists: () => configExists,
26939
27129
  activeConfigFile: () => activeConfigFile
26940
27130
  });
26941
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
26942
- import { homedir as homedir6 } from "os";
26943
- import { dirname as dirname3, join as join6, parse as parse6 } from "path";
27131
+ import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
27132
+ import { homedir as homedir7 } from "os";
27133
+ import { dirname as dirname4, join as join7, parse as parse6 } from "path";
26944
27134
  function activeConfigFile() {
26945
27135
  return activeGlobalConfigFile(CONFIG_FILE);
26946
27136
  }
26947
27137
  function ensureConfigDir() {
26948
27138
  if (!existsSync5(CONFIG_DIR)) {
26949
- mkdirSync4(CONFIG_DIR, { recursive: true });
27139
+ mkdirSync5(CONFIG_DIR, { recursive: true });
26950
27140
  }
26951
27141
  }
26952
27142
  function loadConfig() {
@@ -26957,7 +27147,7 @@ function loadConfig() {
26957
27147
  return { ...DEFAULT_CONFIG };
26958
27148
  }
26959
27149
  try {
26960
- const content = readFileSync4(activeFile, "utf-8");
27150
+ const content = readFileSync5(activeFile, "utf-8");
26961
27151
  const config2 = JSON.parse(content);
26962
27152
  const merged = {
26963
27153
  version: config2.version || DEFAULT_CONFIG.version,
@@ -27027,26 +27217,26 @@ function getConfigPath() {
27027
27217
  return CONFIG_FILE;
27028
27218
  }
27029
27219
  function getLocalConfigPath() {
27030
- const home = homedir6();
27220
+ const home = homedir7();
27031
27221
  let dir = process.cwd();
27032
27222
  const root = parse6(dir).root;
27033
27223
  while (dir !== root && dir !== home) {
27034
- const candidate = join6(dir, LOCAL_CONFIG_FILENAME);
27224
+ const candidate = join7(dir, LOCAL_CONFIG_FILENAME);
27035
27225
  if (existsSync5(candidate))
27036
27226
  return candidate;
27037
- if (existsSync5(join6(dir, ".git"))) {
27227
+ if (existsSync5(join7(dir, ".git"))) {
27038
27228
  return candidate;
27039
27229
  }
27040
- dir = dirname3(dir);
27230
+ dir = dirname4(dir);
27041
27231
  }
27042
- return join6(process.cwd(), LOCAL_CONFIG_FILENAME);
27232
+ return join7(process.cwd(), LOCAL_CONFIG_FILENAME);
27043
27233
  }
27044
27234
  function localConfigExists() {
27045
27235
  return existsSync5(getLocalConfigPath());
27046
27236
  }
27047
27237
  function isProjectDirectory() {
27048
27238
  const cwd = process.cwd();
27049
- return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) => existsSync5(join6(cwd, f)));
27239
+ return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) => existsSync5(join7(cwd, f)));
27050
27240
  }
27051
27241
  function loadLocalConfig() {
27052
27242
  if (getConfigFileOverride())
@@ -27056,7 +27246,7 @@ function loadLocalConfig() {
27056
27246
  return null;
27057
27247
  }
27058
27248
  try {
27059
- const content = readFileSync4(localPath, "utf-8");
27249
+ const content = readFileSync5(localPath, "utf-8");
27060
27250
  const config2 = JSON.parse(content);
27061
27251
  return {
27062
27252
  ...config2,
@@ -27315,8 +27505,8 @@ function disableLocalProvider(providerName) {
27315
27505
  }
27316
27506
  var CONFIG_DIR, CONFIG_FILE, LOCAL_CONFIG_FILENAME = ".claudish.json", DEFAULT_CONFIG;
27317
27507
  var init_profile_config = __esm(() => {
27318
- CONFIG_DIR = join6(homedir6(), ".claudish");
27319
- CONFIG_FILE = join6(CONFIG_DIR, "config.json");
27508
+ CONFIG_DIR = join7(homedir7(), ".claudish");
27509
+ CONFIG_FILE = join7(CONFIG_DIR, "config.json");
27320
27510
  DEFAULT_CONFIG = {
27321
27511
  version: "1.0.0",
27322
27512
  defaultProfile: "default",
@@ -28043,8 +28233,8 @@ var init_provider_definitions = __esm(() => {
28043
28233
 
28044
28234
  // src/auth/credentials/api-key-credential.ts
28045
28235
  import { existsSync as existsSync6 } from "fs";
28046
- import { homedir as homedir7 } from "os";
28047
- import { join as join7 } from "path";
28236
+ import { homedir as homedir8 } from "os";
28237
+ import { join as join8 } from "path";
28048
28238
  function realValue(v) {
28049
28239
  if (!v)
28050
28240
  return;
@@ -28086,7 +28276,7 @@ class ApiKeyCredentialProvider {
28086
28276
  if (!this.oauthFallback)
28087
28277
  return false;
28088
28278
  try {
28089
- return existsSync6(join7(homedir7(), ".claudish", this.oauthFallback));
28279
+ return existsSync6(join8(homedir8(), ".claudish", this.oauthFallback));
28090
28280
  } catch {
28091
28281
  return false;
28092
28282
  }
@@ -28162,10 +28352,10 @@ var init_api_key_credential = __esm(() => {
28162
28352
  // src/auth/codex-oauth.ts
28163
28353
  import { exec } from "child_process";
28164
28354
  import { createHash as createHash2, randomBytes } from "crypto";
28165
- import { closeSync, existsSync as existsSync7, openSync, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeSync } from "fs";
28355
+ import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync2, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeSync as writeSync2 } from "fs";
28166
28356
  import { createServer } from "http";
28167
- import { homedir as homedir8 } from "os";
28168
- import { join as join8 } from "path";
28357
+ import { homedir as homedir9 } from "os";
28358
+ import { join as join9 } from "path";
28169
28359
  import { promisify } from "util";
28170
28360
 
28171
28361
  class CodexOAuth {
@@ -28191,8 +28381,8 @@ class CodexOAuth {
28191
28381
  return this.credentials !== null && !!this.credentials.refresh_token;
28192
28382
  }
28193
28383
  getCredentialsPath() {
28194
- const claudishDir = join8(homedir8(), ".claudish");
28195
- return join8(claudishDir, "codex-oauth.json");
28384
+ const claudishDir = join9(homedir9(), ".claudish");
28385
+ return join9(claudishDir, "codex-oauth.json");
28196
28386
  }
28197
28387
  async login() {
28198
28388
  log("[CodexOAuth] Starting OAuth login flow");
@@ -28300,7 +28490,7 @@ Details: ${e.message}`);
28300
28490
  return null;
28301
28491
  }
28302
28492
  try {
28303
- const data = readFileSync5(credPath, "utf-8");
28493
+ const data = readFileSync6(credPath, "utf-8");
28304
28494
  const credentials = JSON.parse(data);
28305
28495
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
28306
28496
  log("[CodexOAuth] Invalid credentials file structure");
@@ -28315,17 +28505,17 @@ Details: ${e.message}`);
28315
28505
  }
28316
28506
  saveCredentials(credentials) {
28317
28507
  const credPath = this.getCredentialsPath();
28318
- const claudishDir = join8(homedir8(), ".claudish");
28508
+ const claudishDir = join9(homedir9(), ".claudish");
28319
28509
  if (!existsSync7(claudishDir)) {
28320
- const { mkdirSync: mkdirSync5 } = __require("fs");
28321
- mkdirSync5(claudishDir, { recursive: true });
28510
+ const { mkdirSync: mkdirSync6 } = __require("fs");
28511
+ mkdirSync6(claudishDir, { recursive: true });
28322
28512
  }
28323
- const fd = openSync(credPath, "w", 384);
28513
+ const fd = openSync2(credPath, "w", 384);
28324
28514
  try {
28325
28515
  const data = JSON.stringify(credentials, null, 2);
28326
- writeSync(fd, data, 0, "utf-8");
28516
+ writeSync2(fd, data, 0, "utf-8");
28327
28517
  } finally {
28328
- closeSync(fd);
28518
+ closeSync2(fd);
28329
28519
  }
28330
28520
  log(`[CodexOAuth] Credentials saved to ${credPath}`);
28331
28521
  }
@@ -28626,10 +28816,10 @@ var init_codex_credential = __esm(() => {
28626
28816
  // src/auth/gemini-oauth.ts
28627
28817
  import { exec as exec2 } from "child_process";
28628
28818
  import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
28629
- import { closeSync as closeSync2, existsSync as existsSync8, openSync as openSync2, readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
28819
+ import { closeSync as closeSync3, existsSync as existsSync8, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "fs";
28630
28820
  import { createServer as createServer2 } from "http";
28631
- import { homedir as homedir9 } from "os";
28632
- import { join as join9 } from "path";
28821
+ import { homedir as homedir10 } from "os";
28822
+ import { join as join10 } from "path";
28633
28823
  import { promisify as promisify2 } from "util";
28634
28824
 
28635
28825
  class GeminiOAuth {
@@ -28655,8 +28845,8 @@ class GeminiOAuth {
28655
28845
  return this.credentials !== null && !!this.credentials.refresh_token;
28656
28846
  }
28657
28847
  getCredentialsPath() {
28658
- const claudishDir = join9(homedir9(), ".claudish");
28659
- return join9(claudishDir, "gemini-oauth.json");
28848
+ const claudishDir = join10(homedir10(), ".claudish");
28849
+ return join10(claudishDir, "gemini-oauth.json");
28660
28850
  }
28661
28851
  async login() {
28662
28852
  log("[GeminiOAuth] Starting OAuth login flow");
@@ -28758,7 +28948,7 @@ Details: ${e.message}`);
28758
28948
  return null;
28759
28949
  }
28760
28950
  try {
28761
- const data = readFileSync6(credPath, "utf-8");
28951
+ const data = readFileSync7(credPath, "utf-8");
28762
28952
  const credentials = JSON.parse(data);
28763
28953
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
28764
28954
  log("[GeminiOAuth] Invalid credentials file structure");
@@ -28773,17 +28963,17 @@ Details: ${e.message}`);
28773
28963
  }
28774
28964
  saveCredentials(credentials) {
28775
28965
  const credPath = this.getCredentialsPath();
28776
- const claudishDir = join9(homedir9(), ".claudish");
28966
+ const claudishDir = join10(homedir10(), ".claudish");
28777
28967
  if (!existsSync8(claudishDir)) {
28778
- const { mkdirSync: mkdirSync5 } = __require("fs");
28779
- mkdirSync5(claudishDir, { recursive: true });
28968
+ const { mkdirSync: mkdirSync6 } = __require("fs");
28969
+ mkdirSync6(claudishDir, { recursive: true });
28780
28970
  }
28781
- const fd = openSync2(credPath, "w", 384);
28971
+ const fd = openSync3(credPath, "w", 384);
28782
28972
  try {
28783
28973
  const data = JSON.stringify(credentials, null, 2);
28784
- writeSync2(fd, data, 0, "utf-8");
28974
+ writeSync3(fd, data, 0, "utf-8");
28785
28975
  } finally {
28786
- closeSync2(fd);
28976
+ closeSync3(fd);
28787
28977
  }
28788
28978
  log(`[GeminiOAuth] Credentials saved to ${credPath}`);
28789
28979
  }
@@ -29137,18 +29327,18 @@ var init_gemini_oauth = __esm(() => {
29137
29327
  });
29138
29328
 
29139
29329
  // src/auth/oauth-registry.ts
29140
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
29141
- import { homedir as homedir10 } from "os";
29142
- import { join as join10 } from "path";
29330
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
29331
+ import { homedir as homedir11 } from "os";
29332
+ import { join as join11 } from "path";
29143
29333
  function hasValidOAuthCredentials(descriptor) {
29144
- const credPath = join10(homedir10(), ".claudish", descriptor.credentialFile);
29334
+ const credPath = join11(homedir11(), ".claudish", descriptor.credentialFile);
29145
29335
  if (!existsSync9(credPath))
29146
29336
  return false;
29147
29337
  if (descriptor.validationMode === "file-exists") {
29148
29338
  return true;
29149
29339
  }
29150
29340
  try {
29151
- const data = JSON.parse(readFileSync7(credPath, "utf-8"));
29341
+ const data = JSON.parse(readFileSync8(credPath, "utf-8"));
29152
29342
  if (!data.access_token)
29153
29343
  return false;
29154
29344
  if (data.refresh_token)
@@ -29258,9 +29448,9 @@ var init_gemini_credential = __esm(() => {
29258
29448
  // src/auth/kimi-oauth.ts
29259
29449
  import { exec as exec3 } from "child_process";
29260
29450
  import { randomBytes as randomBytes3 } from "crypto";
29261
- import { closeSync as closeSync3, existsSync as existsSync10, openSync as openSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync4, writeSync as writeSync3 } from "fs";
29262
- import { homedir as homedir11, hostname as hostname3, platform, release } from "os";
29263
- import { join as join11 } from "path";
29451
+ import { closeSync as closeSync4, existsSync as existsSync10, openSync as openSync4, readFileSync as readFileSync9, unlinkSync as unlinkSync4, writeSync as writeSync4 } from "fs";
29452
+ import { homedir as homedir12, hostname as hostname3, platform, release as release2 } from "os";
29453
+ import { join as join12 } from "path";
29264
29454
  import { promisify as promisify3 } from "util";
29265
29455
 
29266
29456
  class KimiOAuth {
@@ -29288,23 +29478,23 @@ class KimiOAuth {
29288
29478
  return this.credentials !== null && !!this.credentials.refresh_token;
29289
29479
  }
29290
29480
  getCredentialsPath() {
29291
- const claudishDir = join11(homedir11(), ".claudish");
29292
- return join11(claudishDir, "kimi-oauth.json");
29481
+ const claudishDir = join12(homedir12(), ".claudish");
29482
+ return join12(claudishDir, "kimi-oauth.json");
29293
29483
  }
29294
29484
  getDeviceIdPath() {
29295
- const claudishDir = join11(homedir11(), ".claudish");
29296
- return join11(claudishDir, "kimi-device-id");
29485
+ const claudishDir = join12(homedir12(), ".claudish");
29486
+ return join12(claudishDir, "kimi-device-id");
29297
29487
  }
29298
29488
  loadOrCreateDeviceId() {
29299
29489
  const deviceIdPath = this.getDeviceIdPath();
29300
- const claudishDir = join11(homedir11(), ".claudish");
29490
+ const claudishDir = join12(homedir12(), ".claudish");
29301
29491
  if (!existsSync10(claudishDir)) {
29302
- const { mkdirSync: mkdirSync5 } = __require("fs");
29303
- mkdirSync5(claudishDir, { recursive: true });
29492
+ const { mkdirSync: mkdirSync6 } = __require("fs");
29493
+ mkdirSync6(claudishDir, { recursive: true });
29304
29494
  }
29305
29495
  if (existsSync10(deviceIdPath)) {
29306
29496
  try {
29307
- const deviceId2 = readFileSync8(deviceIdPath, "utf-8").trim();
29497
+ const deviceId2 = readFileSync9(deviceIdPath, "utf-8").trim();
29308
29498
  if (deviceId2) {
29309
29499
  return deviceId2;
29310
29500
  }
@@ -29314,11 +29504,11 @@ class KimiOAuth {
29314
29504
  }
29315
29505
  const deviceId = randomBytes3(16).toString("hex").replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
29316
29506
  try {
29317
- const fd = openSync3(deviceIdPath, "w", 384);
29507
+ const fd = openSync4(deviceIdPath, "w", 384);
29318
29508
  try {
29319
- writeSync3(fd, deviceId, 0, "utf-8");
29509
+ writeSync4(fd, deviceId, 0, "utf-8");
29320
29510
  } finally {
29321
- closeSync3(fd);
29511
+ closeSync4(fd);
29322
29512
  }
29323
29513
  log(`[KimiOAuth] New device ID created: ${deviceId}`);
29324
29514
  } catch (e) {
@@ -29335,7 +29525,7 @@ class KimiOAuth {
29335
29525
  "X-Msh-Version": this.getVersion(),
29336
29526
  "X-Msh-Device-Name": hostname3(),
29337
29527
  "X-Msh-Device-Model": `${platform()}-${process.arch}`,
29338
- "X-Msh-Os-Version": release(),
29528
+ "X-Msh-Os-Version": release2(),
29339
29529
  "X-Msh-Device-Id": this.deviceId
29340
29530
  };
29341
29531
  }
@@ -29563,7 +29753,7 @@ Details: ${e.message}`);
29563
29753
  return null;
29564
29754
  }
29565
29755
  try {
29566
- const data = readFileSync8(credPath, "utf-8");
29756
+ const data = readFileSync9(credPath, "utf-8");
29567
29757
  const credentials = JSON.parse(data);
29568
29758
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at || !credentials.scope || !credentials.token_type) {
29569
29759
  log("[KimiOAuth] Invalid credentials file structure");
@@ -29578,17 +29768,17 @@ Details: ${e.message}`);
29578
29768
  }
29579
29769
  saveCredentials(credentials) {
29580
29770
  const credPath = this.getCredentialsPath();
29581
- const claudishDir = join11(homedir11(), ".claudish");
29771
+ const claudishDir = join12(homedir12(), ".claudish");
29582
29772
  if (!existsSync10(claudishDir)) {
29583
- const { mkdirSync: mkdirSync5 } = __require("fs");
29584
- mkdirSync5(claudishDir, { recursive: true });
29773
+ const { mkdirSync: mkdirSync6 } = __require("fs");
29774
+ mkdirSync6(claudishDir, { recursive: true });
29585
29775
  }
29586
- const fd = openSync3(credPath, "w", 384);
29776
+ const fd = openSync4(credPath, "w", 384);
29587
29777
  try {
29588
29778
  const data = JSON.stringify(credentials, null, 2);
29589
- writeSync3(fd, data, 0, "utf-8");
29779
+ writeSync4(fd, data, 0, "utf-8");
29590
29780
  } finally {
29591
- closeSync3(fd);
29781
+ closeSync4(fd);
29592
29782
  }
29593
29783
  log(`[KimiOAuth] Credentials saved to ${credPath}`);
29594
29784
  }
@@ -29754,8 +29944,8 @@ var init_native_anthropic_credential = __esm(() => {
29754
29944
  // src/auth/vertex-auth.ts
29755
29945
  import { exec as exec4 } from "child_process";
29756
29946
  import { existsSync as existsSync11 } from "fs";
29757
- import { homedir as homedir12 } from "os";
29758
- import { join as join12 } from "path";
29947
+ import { homedir as homedir13 } from "os";
29948
+ import { join as join13 } from "path";
29759
29949
  import { promisify as promisify4 } from "util";
29760
29950
 
29761
29951
  class VertexAuthManager {
@@ -29810,7 +30000,7 @@ class VertexAuthManager {
29810
30000
  }
29811
30001
  async tryADC() {
29812
30002
  try {
29813
- const adcPath = join12(homedir12(), ".config/gcloud/application_default_credentials.json");
30003
+ const adcPath = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
29814
30004
  if (!existsSync11(adcPath)) {
29815
30005
  log("[VertexAuth] ADC credentials file not found");
29816
30006
  return null;
@@ -29874,7 +30064,7 @@ function validateVertexOAuthConfig() {
29874
30064
  ` + ` export VERTEX_PROJECT='your-gcp-project-id'
29875
30065
  ` + " export VERTEX_LOCATION='us-central1' # optional";
29876
30066
  }
29877
- const adcPath = join12(homedir12(), ".config/gcloud/application_default_credentials.json");
30067
+ const adcPath = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
29878
30068
  const hasADC = existsSync11(adcPath);
29879
30069
  const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
29880
30070
  if (!hasADC && !hasServiceAccount) {
@@ -30422,15 +30612,15 @@ var init_routing_hints = __esm(() => {
30422
30612
  });
30423
30613
 
30424
30614
  // src/providers/all-models-cache.ts
30425
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
30426
- import { homedir as homedir13 } from "os";
30427
- import { dirname as dirname4, join as join13 } from "path";
30615
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
30616
+ import { homedir as homedir14 } from "os";
30617
+ import { dirname as dirname5, join as join14 } from "path";
30428
30618
  function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
30429
30619
  if (!existsSync12(path))
30430
30620
  return null;
30431
30621
  let raw;
30432
30622
  try {
30433
- raw = JSON.parse(readFileSync9(path, "utf-8"));
30623
+ raw = JSON.parse(readFileSync10(path, "utf-8"));
30434
30624
  } catch {
30435
30625
  return null;
30436
30626
  }
@@ -30455,12 +30645,12 @@ function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
30455
30645
  entries: data.entries ?? existing?.entries ?? [],
30456
30646
  models: data.models ?? existing?.models ?? []
30457
30647
  };
30458
- mkdirSync5(dirname4(path), { recursive: true });
30648
+ mkdirSync6(dirname5(path), { recursive: true });
30459
30649
  writeFileSync6(path, JSON.stringify(merged), "utf-8");
30460
30650
  }
30461
30651
  var ALL_MODELS_CACHE_PATH;
30462
30652
  var init_all_models_cache = __esm(() => {
30463
- ALL_MODELS_CACHE_PATH = join13(homedir13(), ".claudish", "all-models.json");
30653
+ ALL_MODELS_CACHE_PATH = join14(homedir14(), ".claudish", "all-models.json");
30464
30654
  });
30465
30655
 
30466
30656
  // src/adapters/model-catalog.ts
@@ -31287,10 +31477,21 @@ async function prehydrateCredentialsForSpawn(models) {
31287
31477
  return;
31288
31478
  try {
31289
31479
  await validateApiKeysForModels(wanted);
31480
+ publishOpSkipList();
31290
31481
  } catch {}
31291
31482
  }
31483
+ function publishOpSkipList() {
31484
+ if (getOpFailures().length > 0)
31485
+ return;
31486
+ const unavailable = getOpUnavailableVars();
31487
+ if (unavailable.length === 0)
31488
+ return;
31489
+ process.env[OP_UNAVAILABLE_ENV] = unavailable.join(",");
31490
+ }
31292
31491
  var init_prehydrate = __esm(() => {
31492
+ init_onepassword();
31293
31493
  init_provider_resolver();
31494
+ init_op_source();
31294
31495
  });
31295
31496
 
31296
31497
  // src/channel/diagnostics.ts
@@ -31545,9 +31746,9 @@ var init_signal_watcher = __esm(() => {
31545
31746
  // src/channel/session-manager.ts
31546
31747
  import { spawn } from "child_process";
31547
31748
  import { randomUUID as randomUUID2 } from "crypto";
31548
- import { createWriteStream, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
31549
- import { homedir as homedir14 } from "os";
31550
- import { join as join14 } from "path";
31749
+ import { createWriteStream, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
31750
+ import { homedir as homedir15 } from "os";
31751
+ import { join as join15 } from "path";
31551
31752
 
31552
31753
  class SessionManager {
31553
31754
  sessions = new Map;
@@ -31567,10 +31768,10 @@ class SessionManager {
31567
31768
  const sessionId = randomUUID2().slice(0, 8);
31568
31769
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
31569
31770
  const startedAt = new Date().toISOString();
31570
- const sessionDir = join14(homedir14(), ".claudish", "sessions", sessionId);
31571
- mkdirSync6(sessionDir, { recursive: true });
31771
+ const sessionDir = join15(homedir15(), ".claudish", "sessions", sessionId);
31772
+ mkdirSync7(sessionDir, { recursive: true });
31572
31773
  if (opts.prompt) {
31573
- writeFileSync7(join14(sessionDir, "prompt.md"), opts.prompt, "utf-8");
31774
+ writeFileSync7(join15(sessionDir, "prompt.md"), opts.prompt, "utf-8");
31574
31775
  }
31575
31776
  const args = ["--model", opts.model, "-y", "--stdin", "--quiet", ...opts.claudishFlags ?? []];
31576
31777
  const proc = spawn("claudish", args, {
@@ -31597,7 +31798,7 @@ class SessionManager {
31597
31798
  });
31598
31799
  }
31599
31800
  });
31600
- const outputLogStream = createWriteStream(join14(sessionDir, "output.log"));
31801
+ const outputLogStream = createWriteStream(join15(sessionDir, "output.log"));
31601
31802
  const entry = {
31602
31803
  info: {
31603
31804
  sessionId,
@@ -31644,9 +31845,9 @@ class SessionManager {
31644
31845
  watcher.processExited(code);
31645
31846
  outputLogStream.end();
31646
31847
  if (entry.stderr) {
31647
- writeFileSync7(join14(sessionDir, "stderr.log"), entry.stderr, "utf-8");
31848
+ writeFileSync7(join15(sessionDir, "stderr.log"), entry.stderr, "utf-8");
31648
31849
  }
31649
- writeFileSync7(join14(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
31850
+ writeFileSync7(join15(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
31650
31851
  this.cleanupSigint();
31651
31852
  });
31652
31853
  proc.on("error", (err) => {
@@ -31819,9 +32020,9 @@ var init_cache_ttl = __esm(() => {
31819
32020
  });
31820
32021
 
31821
32022
  // src/model-loader.ts
31822
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
31823
- import { homedir as homedir15 } from "os";
31824
- import { join as join15 } from "path";
32023
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
32024
+ import { homedir as homedir16 } from "os";
32025
+ import { join as join16 } from "path";
31825
32026
  function groupRecommendedModels(entries) {
31826
32027
  const byId = new Map;
31827
32028
  for (const entry of entries) {
@@ -31919,7 +32120,7 @@ async function getRecommendedModels(opts = {}) {
31919
32120
  }
31920
32121
  if (!forceRefresh && existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
31921
32122
  try {
31922
- const cacheData = JSON.parse(readFileSync10(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
32123
+ const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
31923
32124
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
31924
32125
  _cachedRecommendedModels = cacheData;
31925
32126
  return cacheData;
@@ -31935,8 +32136,8 @@ async function getRecommendedModels(opts = {}) {
31935
32136
  if (data.models && data.models.length > 0) {
31936
32137
  _cachedRecommendedModels = data;
31937
32138
  try {
31938
- const cacheDir = join15(homedir15(), ".claudish");
31939
- mkdirSync7(cacheDir, { recursive: true });
32139
+ const cacheDir = join16(homedir16(), ".claudish");
32140
+ mkdirSync8(cacheDir, { recursive: true });
31940
32141
  writeFileSync8(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
31941
32142
  } catch {}
31942
32143
  return data;
@@ -31950,7 +32151,7 @@ function getRecommendedModelsSync() {
31950
32151
  return _cachedRecommendedModels;
31951
32152
  if (existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
31952
32153
  try {
31953
- const cacheData = JSON.parse(readFileSync10(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
32154
+ const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
31954
32155
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
31955
32156
  _cachedRecommendedModels = cacheData;
31956
32157
  return cacheData;
@@ -32074,7 +32275,7 @@ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels =
32074
32275
  var init_model_loader = __esm(() => {
32075
32276
  init_cache_ttl();
32076
32277
  FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
32077
- RECOMMENDED_MODELS_CACHE_PATH = join15(homedir15(), ".claudish", "recommended-models-cache.json");
32278
+ RECOMMENDED_MODELS_CACHE_PATH = join16(homedir16(), ".claudish", "recommended-models-cache.json");
32078
32279
  FIREBASE_SLUG_TO_PROVIDER_NAME = {
32079
32280
  openai: "openai",
32080
32281
  google: "google",
@@ -32122,6 +32323,44 @@ async function isPortAvailable(port) {
32122
32323
  }
32123
32324
  var init_port_manager = () => {};
32124
32325
 
32326
+ // src/redact.ts
32327
+ function isPlaceholder(value) {
32328
+ return PLACEHOLDER.test(value.trim());
32329
+ }
32330
+ function redactSecrets(text) {
32331
+ if (!text)
32332
+ return "";
32333
+ let out = text;
32334
+ out = out.replace(ASSIGNMENT_RE, (match, lhs, value) => isPlaceholder(value) ? match : `${lhs}${MASK}`);
32335
+ for (const { re } of TOKEN_PATTERNS) {
32336
+ out = out.replace(re, (match) => {
32337
+ const scheme = /^(Bearer|Basic|Token)\s/.exec(match);
32338
+ return scheme ? `${scheme[1]} ${MASK}` : MASK;
32339
+ });
32340
+ }
32341
+ return out;
32342
+ }
32343
+ function sanitizeForReport(text) {
32344
+ if (!text)
32345
+ return "";
32346
+ return redactSecrets(text).replace(/\/Users\/[^/\s]+/g, "/Users/***").replace(/\/home\/[^/\s]+/g, "/home/***").replace(/[A-Z]:\\Users\\[^\\\s]+/gi, "C:\\Users\\***").replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
32347
+ }
32348
+ var MASK = "***REDACTED***", PLACEHOLDER, ASSIGNMENT_RE, TOKEN_PATTERNS;
32349
+ var init_redact = __esm(() => {
32350
+ PLACEHOLDER = /^(['"`]?)(your[-_a-z0-9]*|<[^>]*>|\.\.\.|x{3,}|\*{3,}|REDACTED|CHANGEME|TODO|\$\{[^}]*\}|)(['"`]?)$/i;
32351
+ ASSIGNMENT_RE = /(["']?\b[A-Z][A-Z0-9_]*(?:_API_KEY|_KEY|_TOKEN|_SECRET|_PASSWORD)\b["']?\s*[:=]\s*)(["'`]?\$\{[^}]*\}["'`]?|["'`]?[^\s"'`,}]+["'`]?)/g;
32352
+ TOKEN_PATTERNS = [
32353
+ { name: "sk", re: /\bsk-[A-Za-z0-9_-]{16,}/g },
32354
+ { name: "google", re: /\bAIza[A-Za-z0-9_-]{20,}/g },
32355
+ { name: "xai", re: /\bxai-[A-Za-z0-9_-]{16,}/g },
32356
+ { name: "github", re: /\bgh[posur]_[A-Za-z0-9]{20,}/g },
32357
+ { name: "aws", re: /\bAKIA[0-9A-Z]{12,}/g },
32358
+ { name: "jwt", re: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g },
32359
+ { name: "zhipu", re: /\b[0-9a-f]{32}\.[A-Za-z0-9]{16}\b/g },
32360
+ { name: "bearer", re: /\b(?:Bearer|Basic|Token)\s+[A-Za-z0-9_.\-+/=]{12,}/g }
32361
+ ];
32362
+ });
32363
+
32125
32364
  // ../../node_modules/.bun/hono@4.10.6/node_modules/hono/dist/compose.js
32126
32365
  var compose = (middleware, onError, onNotFound) => {
32127
32366
  return (context, next) => {
@@ -34115,9 +34354,12 @@ function transformOpenAIToClaude(claudeRequestInput) {
34115
34354
  var init_transform = () => {};
34116
34355
 
34117
34356
  // src/handlers/shared/format/openai-tools.ts
34357
+ function emptyParamsSchema() {
34358
+ return { type: "object", properties: {} };
34359
+ }
34118
34360
  function sanitizeSchemaForOpenAI(schema) {
34119
34361
  if (!schema || typeof schema !== "object") {
34120
- return removeUriFormat(schema);
34362
+ return emptyParamsSchema();
34121
34363
  }
34122
34364
  let root = { ...schema };
34123
34365
  const combinerKey = ["oneOf", "anyOf", "allOf"].find((k) => Array.isArray(root[k]) && root[k].length > 0);
@@ -34159,8 +34401,8 @@ function summarizeToolDescription(name, description) {
34159
34401
  return firstSentence;
34160
34402
  }
34161
34403
  function summarizeToolParameters(schema) {
34162
- if (!schema)
34163
- return schema;
34404
+ if (!schema || typeof schema !== "object")
34405
+ return emptyParamsSchema();
34164
34406
  const summarized = sanitizeSchemaForOpenAI({ ...schema });
34165
34407
  if (summarized.properties) {
34166
34408
  for (const prop of Object.values(summarized.properties)) {
@@ -37720,7 +37962,7 @@ var init_openai = __esm(() => {
37720
37962
  });
37721
37963
 
37722
37964
  // src/providers/catalog-query.ts
37723
- import { statSync } from "fs";
37965
+ import { statSync as statSync2 } from "fs";
37724
37966
  function project(entry) {
37725
37967
  return {
37726
37968
  modelId: entry.modelId,
@@ -37733,7 +37975,7 @@ function project(entry) {
37733
37975
  function getCachedEntries() {
37734
37976
  let mtimeMs;
37735
37977
  try {
37736
- mtimeMs = statSync(ALL_MODELS_CACHE_PATH).mtimeMs;
37978
+ mtimeMs = statSync2(ALL_MODELS_CACHE_PATH).mtimeMs;
37737
37979
  } catch {
37738
37980
  return null;
37739
37981
  }
@@ -37908,24 +38150,24 @@ var init_vision_proxy = __esm(() => {
37908
38150
  // src/stats-buffer.ts
37909
38151
  import {
37910
38152
  existsSync as existsSync14,
37911
- mkdirSync as mkdirSync8,
37912
- readFileSync as readFileSync11,
38153
+ mkdirSync as mkdirSync9,
38154
+ readFileSync as readFileSync12,
37913
38155
  renameSync,
37914
38156
  unlinkSync as unlinkSync5,
37915
38157
  writeFileSync as writeFileSync9
37916
38158
  } from "fs";
37917
- import { homedir as homedir16 } from "os";
37918
- import { join as join16 } from "path";
38159
+ import { homedir as homedir17 } from "os";
38160
+ import { join as join17 } from "path";
37919
38161
  function ensureDir() {
37920
38162
  if (!existsSync14(CLAUDISH_DIR)) {
37921
- mkdirSync8(CLAUDISH_DIR, { recursive: true });
38163
+ mkdirSync9(CLAUDISH_DIR, { recursive: true });
37922
38164
  }
37923
38165
  }
37924
38166
  function readFromDisk() {
37925
38167
  try {
37926
38168
  if (!existsSync14(BUFFER_FILE))
37927
38169
  return [];
37928
- const raw2 = readFileSync11(BUFFER_FILE, "utf-8");
38170
+ const raw2 = readFileSync12(BUFFER_FILE, "utf-8");
37929
38171
  const parsed = JSON.parse(raw2);
37930
38172
  if (!Array.isArray(parsed.events))
37931
38173
  return [];
@@ -37950,7 +38192,7 @@ function writeToDisk(events) {
37950
38192
  ensureDir();
37951
38193
  const trimmed = enforceSizeCap([...events]);
37952
38194
  const payload = { version: 1, events: trimmed };
37953
- const tmpFile = join16(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
38195
+ const tmpFile = join17(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37954
38196
  writeFileSync9(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
37955
38197
  renameSync(tmpFile, BUFFER_FILE);
37956
38198
  memoryCache = trimmed;
@@ -38023,8 +38265,8 @@ function syncFlushOnExit() {
38023
38265
  var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
38024
38266
  var init_stats_buffer = __esm(() => {
38025
38267
  BUFFER_MAX_BYTES = 64 * 1024;
38026
- CLAUDISH_DIR = join16(homedir16(), ".claudish");
38027
- BUFFER_FILE = join16(CLAUDISH_DIR, "stats-buffer.json");
38268
+ CLAUDISH_DIR = join17(homedir17(), ".claudish");
38269
+ BUFFER_FILE = join17(CLAUDISH_DIR, "stats-buffer.json");
38028
38270
  process.on("exit", syncFlushOnExit);
38029
38271
  process.on("SIGTERM", () => {
38030
38272
  try {
@@ -40227,9 +40469,9 @@ var init_openai_responses_sse = __esm(() => {
40227
40469
  });
40228
40470
 
40229
40471
  // src/handlers/shared/token-tracker.ts
40230
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
40231
- import { homedir as homedir17 } from "os";
40232
- import { join as join17 } from "path";
40472
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
40473
+ import { homedir as homedir18 } from "os";
40474
+ import { dirname as dirname6, join as join18 } from "path";
40233
40475
 
40234
40476
  class TokenTracker {
40235
40477
  port;
@@ -40372,9 +40614,10 @@ class TokenTracker {
40372
40614
  if (this.quotaRemaining !== undefined) {
40373
40615
  data.quota_remaining = this.quotaRemaining;
40374
40616
  }
40375
- const claudishDir = join17(homedir17(), ".claudish");
40376
- mkdirSync9(claudishDir, { recursive: true });
40377
- writeFileSync10(join17(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
40617
+ const override = process.env.CLAUDISH_TOKEN_FILE;
40618
+ const outPath = override || join18(homedir18(), ".claudish", `tokens-${this.port}.json`);
40619
+ mkdirSync10(dirname6(outPath), { recursive: true });
40620
+ writeFileSync10(outPath, JSON.stringify(data), "utf-8");
40378
40621
  } catch (e) {
40379
40622
  log(`[TokenTracker] Error writing token file: ${e}`);
40380
40623
  }
@@ -42871,11 +43114,11 @@ var init_ollama_api_format = __esm(() => {
42871
43114
  });
42872
43115
 
42873
43116
  // src/providers/api-key-provenance.ts
42874
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
42875
- import { homedir as homedir18 } from "os";
42876
- import { join as join18, resolve as resolve2 } from "path";
43117
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
43118
+ import { homedir as homedir19 } from "os";
43119
+ import { join as join19, resolve as resolve2 } from "path";
42877
43120
  function activeConfigPath() {
42878
- return activeGlobalConfigFile(join18(homedir18(), ".claudish", "config.json"));
43121
+ return activeGlobalConfigFile(join19(homedir19(), ".claudish", "config.json"));
42879
43122
  }
42880
43123
  function configLayerLabel() {
42881
43124
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -42954,7 +43197,7 @@ function readDotenvKey(envVars) {
42954
43197
  const dotenvPath = resolve2(".env");
42955
43198
  if (!existsSync15(dotenvPath))
42956
43199
  return null;
42957
- const parsed = import_dotenv.parse(readFileSync12(dotenvPath, "utf-8"));
43200
+ const parsed = import_dotenv.parse(readFileSync13(dotenvPath, "utf-8"));
42958
43201
  for (const v of envVars) {
42959
43202
  if (parsed[v])
42960
43203
  return parsed[v];
@@ -42969,7 +43212,7 @@ function readConfigKey(envVar) {
42969
43212
  const configPath = activeConfigPath();
42970
43213
  if (!existsSync15(configPath))
42971
43214
  return null;
42972
- const cfg = JSON.parse(readFileSync12(configPath, "utf-8"));
43215
+ const cfg = JSON.parse(readFileSync13(configPath, "utf-8"));
42973
43216
  return cfg.apiKeys?.[envVar] || null;
42974
43217
  } catch {
42975
43218
  return null;
@@ -44527,9 +44770,9 @@ var init_poe = __esm(() => {
44527
44770
  });
44528
44771
 
44529
44772
  // src/services/pricing-cache.ts
44530
- import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync2 } from "fs";
44531
- import { homedir as homedir19 } from "os";
44532
- import { join as join19 } from "path";
44773
+ import { existsSync as existsSync16, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
44774
+ import { homedir as homedir20 } from "os";
44775
+ import { join as join20 } from "path";
44533
44776
  function prefixMatch(modelName) {
44534
44777
  for (const [key, pricing] of pricingMap) {
44535
44778
  if (modelName.startsWith(key))
@@ -44569,10 +44812,10 @@ function loadDiskCache() {
44569
44812
  try {
44570
44813
  if (!existsSync16(CACHE_FILE))
44571
44814
  return false;
44572
- const stat = statSync2(CACHE_FILE);
44815
+ const stat = statSync3(CACHE_FILE);
44573
44816
  const age = Date.now() - stat.mtimeMs;
44574
44817
  const isFresh = age < CACHE_TTL_MS2;
44575
- const raw2 = readFileSync13(CACHE_FILE, "utf-8");
44818
+ const raw2 = readFileSync14(CACHE_FILE, "utf-8");
44576
44819
  const data = JSON.parse(raw2);
44577
44820
  for (const [key, pricing] of Object.entries(data)) {
44578
44821
  pricingMap.set(key, pricing);
@@ -44588,8 +44831,8 @@ var init_pricing_cache = __esm(() => {
44588
44831
  init_logger();
44589
44832
  init_catalog_query();
44590
44833
  pricingMap = new Map;
44591
- CACHE_DIR = join19(homedir19(), ".claudish");
44592
- CACHE_FILE = join19(CACHE_DIR, "pricing-cache.json");
44834
+ CACHE_DIR = join20(homedir20(), ".claudish");
44835
+ CACHE_FILE = join20(CACHE_DIR, "pricing-cache.json");
44593
44836
  CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
44594
44837
  });
44595
44838
 
@@ -45045,6 +45288,175 @@ var init_proxy_server = __esm(() => {
45045
45288
  };
45046
45289
  });
45047
45290
 
45291
+ // src/team-stats.ts
45292
+ import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "fs";
45293
+ import { join as join21 } from "path";
45294
+ function statsDir(sessionPath) {
45295
+ return join21(sessionPath, "stats");
45296
+ }
45297
+ function tokenFileFor(sessionPath, anonId) {
45298
+ return join21(statsDir(sessionPath), `${anonId}.json`);
45299
+ }
45300
+ function readTokenStats(sessionPath, anonId) {
45301
+ const path = tokenFileFor(sessionPath, anonId);
45302
+ if (!existsSync17(path))
45303
+ return null;
45304
+ try {
45305
+ return JSON.parse(readFileSync15(path, "utf-8"));
45306
+ } catch {
45307
+ return null;
45308
+ }
45309
+ }
45310
+ function fmtTokens(n) {
45311
+ if (!n || n <= 0)
45312
+ return "0";
45313
+ if (n < 1000)
45314
+ return String(n);
45315
+ if (n < 1e6)
45316
+ return `${(n / 1000).toFixed(1)}k`;
45317
+ return `${(n / 1e6).toFixed(1)}M`;
45318
+ }
45319
+ function fmtCost(cost, isFree) {
45320
+ if (isFree)
45321
+ return "free";
45322
+ if (cost === undefined || cost <= 0)
45323
+ return "$0";
45324
+ return `$${cost.toFixed(3)}`;
45325
+ }
45326
+ function fmtBytes(n) {
45327
+ if (n <= 0)
45328
+ return "0B";
45329
+ if (n < 1024)
45330
+ return `${n}B`;
45331
+ if (n < 1024 * 1024)
45332
+ return `${(n / 1024).toFixed(1)}KB`;
45333
+ return `${(n / (1024 * 1024)).toFixed(1)}MB`;
45334
+ }
45335
+ function fmtState(state) {
45336
+ switch (state) {
45337
+ case "COMPLETED":
45338
+ return "done";
45339
+ case "RUNNING":
45340
+ return "run ";
45341
+ case "FAILED":
45342
+ return "FAIL";
45343
+ case "TIMEOUT":
45344
+ return "TIME";
45345
+ case "EMPTY":
45346
+ return "EMPT";
45347
+ case "PENDING":
45348
+ return "wait";
45349
+ default:
45350
+ return "? ";
45351
+ }
45352
+ }
45353
+ function renderTeamStats(sessionPath, manifest, status, opts) {
45354
+ const nameWidth = opts.modelNameWidth ?? 18;
45355
+ const ids = Object.keys(manifest.models).sort();
45356
+ let done = 0;
45357
+ let running = 0;
45358
+ let failed = 0;
45359
+ let totalTokens = 0;
45360
+ let totalCost = 0;
45361
+ let anyFree = false;
45362
+ const rows = [];
45363
+ for (const id of ids) {
45364
+ const m = status.models[id];
45365
+ if (!m)
45366
+ continue;
45367
+ const model = manifest.models[id]?.model ?? "unknown";
45368
+ const stats = readTokenStats(sessionPath, id);
45369
+ if (m.state === "COMPLETED")
45370
+ done++;
45371
+ else if (m.state === "RUNNING" || m.state === "PENDING")
45372
+ running++;
45373
+ else
45374
+ failed++;
45375
+ const inTok = stats?.input_tokens ?? 0;
45376
+ const outTok = stats?.output_tokens ?? 0;
45377
+ totalTokens += stats?.total_tokens ?? inTok + outTok;
45378
+ totalCost += stats?.total_cost ?? 0;
45379
+ if (stats?.is_free)
45380
+ anyFree = true;
45381
+ const name = model.length > nameWidth ? `${model.slice(0, nameWidth - 1)}\u2026` : model;
45382
+ const bytes = m.outputSize > 0 ? fmtBytes(m.outputSize) : "";
45383
+ const tokens = stats ? `${fmtTokens(inTok)}/${outTok > 0 ? fmtTokens(outTok) : "-"}` : "";
45384
+ const cost = stats ? fmtCost(stats.total_cost, stats.is_free) : "";
45385
+ rows.push(` ${id} ${name.padEnd(nameWidth)} ${fmtState(m.state)} ` + `${bytes.padStart(7)} ${tokens.padStart(12)} ${cost.padStart(7)}`.trimEnd());
45386
+ }
45387
+ const parts = [`${ids.length} models`];
45388
+ if (done)
45389
+ parts.push(`${done} done`);
45390
+ if (running)
45391
+ parts.push(`${running} running`);
45392
+ if (failed)
45393
+ parts.push(`${failed} failed`);
45394
+ parts.push(`${Math.round(opts.elapsedSeconds)}s`);
45395
+ if (totalTokens > 0)
45396
+ parts.push(`${fmtTokens(totalTokens)} tok`);
45397
+ if (totalCost > 0 || anyFree)
45398
+ parts.push(fmtCost(totalCost, anyFree && totalCost === 0));
45399
+ return [`team: ${parts.join(", ")}`, ...rows].join(`
45400
+ `);
45401
+ }
45402
+ function renderTeamStatsCompact(sessionPath, manifest, status, opts) {
45403
+ const ids = Object.keys(manifest.models).sort();
45404
+ let done = 0;
45405
+ let running = 0;
45406
+ let failed = 0;
45407
+ let totalTokens = 0;
45408
+ let totalCost = 0;
45409
+ const segs = [];
45410
+ for (const id of ids) {
45411
+ const m = status.models[id];
45412
+ if (!m)
45413
+ continue;
45414
+ const model = manifest.models[id]?.model ?? "unknown";
45415
+ const stats = readTokenStats(sessionPath, id);
45416
+ if (m.state === "COMPLETED")
45417
+ done++;
45418
+ else if (m.state === "RUNNING" || m.state === "PENDING")
45419
+ running++;
45420
+ else
45421
+ failed++;
45422
+ totalTokens += stats?.total_tokens ?? 0;
45423
+ totalCost += stats?.total_cost ?? 0;
45424
+ const bits = [id, model, fmtState(m.state).trim()];
45425
+ if (m.outputSize > 0)
45426
+ bits.push(fmtBytes(m.outputSize));
45427
+ else if (stats?.total_tokens)
45428
+ bits.push(`${fmtTokens(stats.total_tokens)} tok`);
45429
+ segs.push(bits.join(" "));
45430
+ }
45431
+ const counts = [];
45432
+ if (done)
45433
+ counts.push(`${done} done`);
45434
+ if (running)
45435
+ counts.push(`${running} run`);
45436
+ if (failed)
45437
+ counts.push(`${failed} fail`);
45438
+ const head = [`team ${ids.length}: ${counts.join(" ") || "starting"}`];
45439
+ head.push(`${Math.round(opts.elapsedSeconds)}s`);
45440
+ if (totalTokens > 0)
45441
+ head.push(`${fmtTokens(totalTokens)} tok`);
45442
+ if (totalCost > 0)
45443
+ head.push(fmtCost(totalCost));
45444
+ let line1 = head.join(" \xB7 ");
45445
+ if (line1.length > CHANNEL_LINE_BUDGET) {
45446
+ line1 = line1.replace(/^team \d+: /, `t${ids.length}: `);
45447
+ }
45448
+ return `${line1}
45449
+ ${segs.join(" \xB7 ")}`;
45450
+ }
45451
+ function writeStatusFile(sessionPath, manifest, status, opts) {
45452
+ try {
45453
+ writeFileSync11(join21(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
45454
+ `, "utf-8");
45455
+ } catch {}
45456
+ }
45457
+ var CHANNEL_LINE_BUDGET = 58;
45458
+ var init_team_stats = () => {};
45459
+
45048
45460
  // src/team-orchestrator.ts
45049
45461
  var exports_team_orchestrator = {};
45050
45462
  __export(exports_team_orchestrator, {
@@ -45055,19 +45467,62 @@ __export(exports_team_orchestrator, {
45055
45467
  judgeResponses: () => judgeResponses,
45056
45468
  getStatus: () => getStatus,
45057
45469
  fisherYatesShuffle: () => fisherYatesShuffle,
45470
+ classifyRunOutput: () => classifyRunOutput,
45058
45471
  buildJudgePrompt: () => buildJudgePrompt,
45059
- aggregateVerdict: () => aggregateVerdict
45472
+ aggregateVerdict: () => aggregateVerdict,
45473
+ STDOUT_TAIL_LIMIT: () => STDOUT_TAIL_LIMIT,
45474
+ DEFAULT_MIN_OUTPUT_BYTES: () => DEFAULT_MIN_OUTPUT_BYTES
45060
45475
  });
45061
45476
  import { spawn as spawn2 } from "child_process";
45062
45477
  import {
45063
45478
  createWriteStream as createWriteStream2,
45064
- existsSync as existsSync17,
45065
- mkdirSync as mkdirSync10,
45066
- readFileSync as readFileSync14,
45479
+ existsSync as existsSync18,
45480
+ mkdirSync as mkdirSync11,
45481
+ readFileSync as readFileSync16,
45067
45482
  readdirSync as readdirSync2,
45068
- writeFileSync as writeFileSync11
45483
+ writeFileSync as writeFileSync12
45069
45484
  } from "fs";
45070
- import { join as join20, resolve as resolve3 } from "path";
45485
+ import { join as join22, resolve as resolve3 } from "path";
45486
+ function classifyRunOutput(opts) {
45487
+ const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
45488
+ const apiError = API_ERROR_RE.exec(stdoutTail);
45489
+ if (apiError) {
45490
+ return {
45491
+ reason: "api_error",
45492
+ detail: `Child exited 0 but stdout carries an API error: ${apiError[1]?.trim() || "unknown"}`
45493
+ };
45494
+ }
45495
+ const bgCeiling = BG_CEILING_RE.exec(stderr);
45496
+ if (bgCeiling) {
45497
+ return {
45498
+ reason: "background_task_ceiling",
45499
+ detail: `Claude Code terminated the turn after ${bgCeiling[1]}s waiting on background tasks, ` + `flushing only partial output. Set CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 in the child ` + `environment to wait indefinitely, or tell the model not to spawn background work.`
45500
+ };
45501
+ }
45502
+ const tailIsWholeOutput = outputSize <= STDOUT_TAIL_LIMIT;
45503
+ if (outputSize === 0 || tailIsWholeOutput && stdoutTail.trim().length === 0) {
45504
+ return {
45505
+ reason: "empty_output",
45506
+ detail: `Child exited 0 but produced no non-whitespace output (${outputSize} B).`
45507
+ };
45508
+ }
45509
+ if (minOutputBytes > 0 && outputSize < minOutputBytes) {
45510
+ return {
45511
+ reason: "empty_output",
45512
+ detail: `Child exited 0 but produced only ${outputSize} B of stdout ` + `(caller required at least ${minOutputBytes} B).`
45513
+ };
45514
+ }
45515
+ return null;
45516
+ }
45517
+ function persistErrorLog(errorLogPath, header, stderr, stdoutTail) {
45518
+ const parts = [`=== ${redactSecrets(header)} ===`, ""];
45519
+ parts.push("--- stderr ---", stderr.trim() ? redactSecrets(stderr) : "(empty)", "");
45520
+ parts.push("--- stdout (tail) ---", stdoutTail.trim() ? redactSecrets(stdoutTail) : "(empty)", "");
45521
+ try {
45522
+ writeFileSync12(errorLogPath, parts.join(`
45523
+ `), "utf-8");
45524
+ } catch {}
45525
+ }
45071
45526
  function validateSessionPath(sessionPath) {
45072
45527
  const resolved = resolve3(sessionPath);
45073
45528
  const cwd = process.cwd();
@@ -45088,18 +45543,18 @@ function setupSession(sessionPath, models, input) {
45088
45543
  if (models.length === 0) {
45089
45544
  throw new Error("At least one model is required");
45090
45545
  }
45091
- if (existsSync17(join20(sessionPath, "manifest.json"))) {
45546
+ if (existsSync18(join22(sessionPath, "manifest.json"))) {
45092
45547
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
45093
45548
  }
45094
45549
  const sentinels = models.filter(isSentinelModel);
45095
45550
  if (sentinels.length > 0) {
45096
45551
  throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
45097
45552
  }
45098
- mkdirSync10(join20(sessionPath, "work"), { recursive: true });
45099
- mkdirSync10(join20(sessionPath, "errors"), { recursive: true });
45553
+ mkdirSync11(join22(sessionPath, "work"), { recursive: true });
45554
+ mkdirSync11(join22(sessionPath, "errors"), { recursive: true });
45100
45555
  if (input !== undefined) {
45101
- writeFileSync11(join20(sessionPath, "input.md"), input, "utf-8");
45102
- } else if (!existsSync17(join20(sessionPath, "input.md"))) {
45556
+ writeFileSync12(join22(sessionPath, "input.md"), input, "utf-8");
45557
+ } else if (!existsSync18(join22(sessionPath, "input.md"))) {
45103
45558
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
45104
45559
  }
45105
45560
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -45116,9 +45571,9 @@ function setupSession(sessionPath, models, input) {
45116
45571
  model: models[i],
45117
45572
  assignedAt: now
45118
45573
  };
45119
- mkdirSync10(join20(sessionPath, "work", anonId), { recursive: true });
45574
+ mkdirSync11(join22(sessionPath, "work", anonId), { recursive: true });
45120
45575
  }
45121
- writeFileSync11(join20(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
45576
+ writeFileSync12(join22(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
45122
45577
  const status = {
45123
45578
  startedAt: now,
45124
45579
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -45132,22 +45587,25 @@ function setupSession(sessionPath, models, input) {
45132
45587
  }
45133
45588
  ]))
45134
45589
  };
45135
- writeFileSync11(join20(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
45590
+ writeFileSync12(join22(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
45136
45591
  return manifest;
45137
45592
  }
45138
45593
  async function runModels(sessionPath, opts = {}) {
45139
45594
  const timeoutMs = (opts.timeout ?? 300) * 1000;
45140
- const manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
45141
- const statusPath = join20(sessionPath, "status.json");
45142
- const inputPath = join20(sessionPath, "input.md");
45143
- const inputContent = readFileSync14(inputPath, "utf-8");
45595
+ const manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
45596
+ const statusPath = join22(sessionPath, "status.json");
45597
+ const inputPath = join22(sessionPath, "input.md");
45598
+ const inputContent = readFileSync16(inputPath, "utf-8");
45144
45599
  await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
45145
- const statusCache = JSON.parse(readFileSync14(statusPath, "utf-8"));
45600
+ const statusCache = JSON.parse(readFileSync16(statusPath, "utf-8"));
45146
45601
  function updateModelStatus(id, update) {
45147
45602
  statusCache.models[id] = { ...statusCache.models[id], ...update };
45148
- writeFileSync11(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
45603
+ writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
45149
45604
  }
45605
+ const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
45606
+ mkdirSync11(statsDir(sessionPath), { recursive: true });
45150
45607
  const processes = new Map;
45608
+ const runtimes = new Map;
45151
45609
  const sigintHandler = () => {
45152
45610
  for (const [, proc] of processes) {
45153
45611
  if (!proc.killed)
@@ -45158,8 +45616,8 @@ async function runModels(sessionPath, opts = {}) {
45158
45616
  process.on("SIGINT", sigintHandler);
45159
45617
  const completionPromises = [];
45160
45618
  for (const [anonId, entry] of Object.entries(manifest.models)) {
45161
- const outputPath = join20(sessionPath, `response-${anonId}.md`);
45162
- const errorLogPath = join20(sessionPath, "errors", `${anonId}.log`);
45619
+ const outputPath = join22(sessionPath, `response-${anonId}.md`);
45620
+ const errorLogPath = join22(sessionPath, "errors", `${anonId}.log`);
45163
45621
  const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
45164
45622
  updateModelStatus(anonId, {
45165
45623
  state: "RUNNING",
@@ -45167,11 +45625,17 @@ async function runModels(sessionPath, opts = {}) {
45167
45625
  });
45168
45626
  const proc = spawn2("claudish", args, {
45169
45627
  stdio: ["pipe", "pipe", "pipe"],
45170
- shell: false
45628
+ shell: false,
45629
+ env: {
45630
+ ...process.env,
45631
+ CLAUDISH_TOKEN_FILE: tokenFileFor(sessionPath, anonId)
45632
+ }
45171
45633
  });
45172
45634
  let byteCount = 0;
45635
+ let stdoutTail = "";
45173
45636
  proc.stdout?.on("data", (chunk) => {
45174
45637
  byteCount += chunk.length;
45638
+ stdoutTail = (stdoutTail + chunk.toString()).slice(-STDOUT_TAIL_LIMIT);
45175
45639
  });
45176
45640
  const outputStream = createWriteStream2(outputPath);
45177
45641
  proc.stdout?.pipe(outputStream);
@@ -45179,6 +45643,14 @@ async function runModels(sessionPath, opts = {}) {
45179
45643
  proc.stderr?.on("data", (chunk) => {
45180
45644
  stderr += chunk.toString();
45181
45645
  });
45646
+ const command = `claudish ${args.join(" ")}`;
45647
+ runtimes.set(anonId, {
45648
+ command,
45649
+ errorLogPath,
45650
+ getStderr: () => stderr,
45651
+ getStdoutTail: () => stdoutTail,
45652
+ getByteCount: () => byteCount
45653
+ });
45182
45654
  proc.stdin?.write(inputContent);
45183
45655
  proc.stdin?.end();
45184
45656
  const completionPromise = new Promise((resolve4) => {
@@ -45194,20 +45666,39 @@ async function runModels(sessionPath, opts = {}) {
45194
45666
  }
45195
45667
  resolved = true;
45196
45668
  const outputSize = byteCount;
45197
- const failed = exitCode !== 0;
45198
- updateModelStatus(anonId, {
45199
- state: failed ? "FAILED" : "COMPLETED",
45200
- exitCode: exitCode ?? 1,
45201
- completedAt: new Date().toISOString(),
45202
- outputSize,
45203
- error: failed ? {
45204
- model: anonId,
45205
- command: `claudish ${args.join(" ")}`,
45206
- stderrSnippet: stderr ? stderr.slice(-2000) : undefined,
45207
- errorLogPath,
45208
- workDir: sessionPath
45209
- } : undefined
45210
- });
45669
+ const crashed = exitCode !== 0;
45670
+ const degraded = crashed ? null : classifyRunOutput({ outputSize, stdoutTail, stderr, minOutputBytes });
45671
+ const failed = crashed || degraded !== null;
45672
+ const state = crashed ? "FAILED" : degraded ? "EMPTY" : "COMPLETED";
45673
+ if (failed) {
45674
+ const reason = crashed ? "nonzero_exit" : degraded.reason;
45675
+ const detail = crashed ? `Child exited with code ${exitCode}.` : degraded.detail;
45676
+ persistErrorLog(errorLogPath, `${state}: ${detail}`, stderr, stdoutTail);
45677
+ updateModelStatus(anonId, {
45678
+ state,
45679
+ exitCode: exitCode ?? 1,
45680
+ completedAt: new Date().toISOString(),
45681
+ outputSize,
45682
+ error: {
45683
+ model: anonId,
45684
+ command,
45685
+ reason,
45686
+ detail,
45687
+ stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
45688
+ stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
45689
+ errorLogPath,
45690
+ workDir: sessionPath
45691
+ }
45692
+ });
45693
+ } else {
45694
+ updateModelStatus(anonId, {
45695
+ state,
45696
+ exitCode: exitCode ?? 0,
45697
+ completedAt: new Date().toISOString(),
45698
+ outputSize,
45699
+ error: undefined
45700
+ });
45701
+ }
45211
45702
  opts.onStatusChange?.(anonId, statusCache.models[anonId]);
45212
45703
  resolve4();
45213
45704
  };
@@ -45220,7 +45711,7 @@ async function runModels(sessionPath, opts = {}) {
45220
45711
  return;
45221
45712
  }
45222
45713
  if (stderr) {
45223
- writeFileSync11(errorLogPath, stderr, "utf-8");
45714
+ writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
45224
45715
  }
45225
45716
  exitCode = code;
45226
45717
  if (outputStream.destroyed) {
@@ -45231,6 +45722,36 @@ async function runModels(sessionPath, opts = {}) {
45231
45722
  processes.set(anonId, proc);
45232
45723
  completionPromises.push(completionPromise);
45233
45724
  }
45725
+ const runStartedMs = Date.now();
45726
+ const POLL_MS = 2000;
45727
+ const heartbeatMs = (opts.heartbeatSeconds ?? 60) * 1000;
45728
+ let lastSignature = "";
45729
+ let lastEmitMs = 0;
45730
+ const stateSignature = () => Object.entries(statusCache.models).sort(([a], [b]) => a.localeCompare(b)).map(([id, m]) => `${id}:${m.state}:${m.outputSize}`).join("|");
45731
+ const emitProgress = (phase = "running") => {
45732
+ const elapsedSeconds = (Date.now() - runStartedMs) / 1000;
45733
+ writeStatusFile(sessionPath, manifest, statusCache, { elapsedSeconds });
45734
+ if (!opts.onProgress)
45735
+ return;
45736
+ const signature = stateSignature();
45737
+ const changed = signature !== lastSignature;
45738
+ const heartbeatDue = Date.now() - lastEmitMs >= heartbeatMs;
45739
+ if (phase !== "settled" && !changed && !heartbeatDue)
45740
+ return;
45741
+ lastSignature = signature;
45742
+ lastEmitMs = Date.now();
45743
+ try {
45744
+ const models = Object.values(statusCache.models);
45745
+ opts.onProgress({
45746
+ rendered: renderTeamStatsCompact(sessionPath, manifest, statusCache, { elapsedSeconds }),
45747
+ phase,
45748
+ allFailed: models.length > 0 && models.every((m) => m.state !== "COMPLETED")
45749
+ });
45750
+ } catch {}
45751
+ };
45752
+ emitProgress();
45753
+ const progressHandle = setInterval(() => emitProgress("running"), POLL_MS);
45754
+ progressHandle.unref?.();
45234
45755
  let timeoutHandle = null;
45235
45756
  await Promise.race([
45236
45757
  Promise.all(completionPromises),
@@ -45241,9 +45762,27 @@ async function runModels(sessionPath, opts = {}) {
45241
45762
  if (current.state === "RUNNING") {
45242
45763
  if (!proc.killed)
45243
45764
  proc.kill("SIGTERM");
45765
+ const rt = runtimes.get(id);
45766
+ const stderr = rt?.getStderr() ?? "";
45767
+ const stdoutTail = rt?.getStdoutTail() ?? "";
45768
+ const bytes = rt?.getByteCount() ?? 0;
45769
+ const detail = `Killed by the orchestrator after ${timeoutMs / 1000}s with ${bytes} B of stdout. ` + `In --quiet print mode the child emits its answer only at the end, so 0 B means ` + `"did not finish", not "produced nothing".`;
45770
+ if (rt)
45771
+ persistErrorLog(rt.errorLogPath, `TIMEOUT: ${detail}`, stderr, stdoutTail);
45244
45772
  updateModelStatus(id, {
45245
45773
  state: "TIMEOUT",
45246
- completedAt: new Date().toISOString()
45774
+ completedAt: new Date().toISOString(),
45775
+ outputSize: bytes,
45776
+ error: rt ? {
45777
+ model: id,
45778
+ command: rt.command,
45779
+ reason: "timeout",
45780
+ detail,
45781
+ stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
45782
+ stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
45783
+ errorLogPath: rt.errorLogPath,
45784
+ workDir: sessionPath
45785
+ } : undefined
45247
45786
  });
45248
45787
  opts.onStatusChange?.(id, statusCache.models[id]);
45249
45788
  }
@@ -45254,6 +45793,8 @@ async function runModels(sessionPath, opts = {}) {
45254
45793
  ]);
45255
45794
  if (timeoutHandle !== null)
45256
45795
  clearTimeout(timeoutHandle);
45796
+ clearInterval(progressHandle);
45797
+ emitProgress("settled");
45257
45798
  process.off("SIGINT", sigintHandler);
45258
45799
  return statusCache;
45259
45800
  }
@@ -45265,23 +45806,23 @@ async function judgeResponses(sessionPath, opts = {}) {
45265
45806
  const responses = {};
45266
45807
  for (const file2 of responseFiles) {
45267
45808
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
45268
- responses[id] = readFileSync14(join20(sessionPath, file2), "utf-8");
45809
+ responses[id] = readFileSync16(join22(sessionPath, file2), "utf-8");
45269
45810
  }
45270
- const input = readFileSync14(join20(sessionPath, "input.md"), "utf-8");
45811
+ const input = readFileSync16(join22(sessionPath, "input.md"), "utf-8");
45271
45812
  const judgePrompt = buildJudgePrompt(input, responses);
45272
- writeFileSync11(join20(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
45813
+ writeFileSync12(join22(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
45273
45814
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
45274
- const judgePath = join20(sessionPath, "judging");
45275
- mkdirSync10(judgePath, { recursive: true });
45815
+ const judgePath = join22(sessionPath, "judging");
45816
+ mkdirSync11(judgePath, { recursive: true });
45276
45817
  setupSession(judgePath, judgeModels, judgePrompt);
45277
45818
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
45278
45819
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
45279
45820
  const verdict = aggregateVerdict(votes, Object.keys(responses));
45280
- writeFileSync11(join20(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
45821
+ writeFileSync12(join22(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
45281
45822
  return verdict;
45282
45823
  }
45283
45824
  function getStatus(sessionPath) {
45284
- return JSON.parse(readFileSync14(join20(sessionPath, "status.json"), "utf-8"));
45825
+ return JSON.parse(readFileSync16(join22(sessionPath, "status.json"), "utf-8"));
45285
45826
  }
45286
45827
  function fisherYatesShuffle(arr) {
45287
45828
  for (let i = arr.length - 1;i > 0; i--) {
@@ -45291,7 +45832,7 @@ function fisherYatesShuffle(arr) {
45291
45832
  return arr;
45292
45833
  }
45293
45834
  function getDefaultJudgeModels(sessionPath) {
45294
- const manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
45835
+ const manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
45295
45836
  return Object.values(manifest.models).map((e) => e.model);
45296
45837
  }
45297
45838
  function buildJudgePrompt(input, responses) {
@@ -45354,7 +45895,7 @@ function parseJudgeVotes(judgePath, responseIds) {
45354
45895
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
45355
45896
  let content;
45356
45897
  try {
45357
- content = readFileSync14(join20(judgePath, file2), "utf-8");
45898
+ content = readFileSync16(join22(judgePath, file2), "utf-8");
45358
45899
  } catch {
45359
45900
  continue;
45360
45901
  }
@@ -45406,7 +45947,7 @@ function aggregateVerdict(votes, responseIds) {
45406
45947
  function formatVerdict(verdict, sessionPath) {
45407
45948
  let manifest = null;
45408
45949
  try {
45409
- manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
45950
+ manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
45410
45951
  } catch {}
45411
45952
  let output = `# Team Verdict
45412
45953
 
@@ -45437,9 +45978,13 @@ function formatVerdict(verdict, sessionPath) {
45437
45978
  }
45438
45979
  return output;
45439
45980
  }
45440
- var SENTINEL_MODELS;
45981
+ var STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0, SENTINEL_MODELS;
45441
45982
  var init_team_orchestrator = __esm(() => {
45442
45983
  init_prehydrate();
45984
+ init_redact();
45985
+ init_team_stats();
45986
+ API_ERROR_RE = /\[API Error:\s*([^\]]{0,300})\]/i;
45987
+ BG_CEILING_RE = /Background tasks still running after (\d+)s; terminating/i;
45443
45988
  SENTINEL_MODELS = new Set([
45444
45989
  "internal",
45445
45990
  "default",
@@ -45454,16 +45999,17 @@ var exports_mcp_server = {};
45454
45999
  __export(exports_mcp_server, {
45455
46000
  startMcpServer: () => startMcpServer,
45456
46001
  runPromptViaProxy: () => runPromptViaProxy,
45457
- parseAnthropicSse: () => parseAnthropicSse
46002
+ parseAnthropicSse: () => parseAnthropicSse,
46003
+ formatTeamResult: () => formatTeamResult
45458
46004
  });
45459
- import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync15, readdirSync as readdirSync3, writeFileSync as writeFileSync12 } from "fs";
45460
- import { homedir as homedir20 } from "os";
45461
- import { dirname as dirname5, join as join21 } from "path";
46005
+ import { existsSync as existsSync19, mkdirSync as mkdirSync12, readFileSync as readFileSync17, readdirSync as readdirSync3, writeFileSync as writeFileSync13 } from "fs";
46006
+ import { homedir as homedir21 } from "os";
46007
+ import { dirname as dirname7, join as join23 } from "path";
45462
46008
  import { fileURLToPath } from "url";
45463
46009
  async function loadAllModels(forceRefresh = false) {
45464
- if (!forceRefresh && existsSync18(ALL_MODELS_CACHE_PATH2)) {
46010
+ if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
45465
46011
  try {
45466
- const cacheData = JSON.parse(readFileSync15(ALL_MODELS_CACHE_PATH2, "utf-8"));
46012
+ const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH2, "utf-8"));
45467
46013
  const lastUpdated = new Date(cacheData.lastUpdated);
45468
46014
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
45469
46015
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -45477,12 +46023,12 @@ async function loadAllModels(forceRefresh = false) {
45477
46023
  throw new Error(`API returned ${response.status}`);
45478
46024
  const data = await response.json();
45479
46025
  const models = data.data || [];
45480
- mkdirSync11(CLAUDISH_CACHE_DIR, { recursive: true });
45481
- writeFileSync12(ALL_MODELS_CACHE_PATH2, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
46026
+ mkdirSync12(CLAUDISH_CACHE_DIR, { recursive: true });
46027
+ writeFileSync13(ALL_MODELS_CACHE_PATH2, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
45482
46028
  return models;
45483
46029
  } catch {
45484
- if (existsSync18(ALL_MODELS_CACHE_PATH2)) {
45485
- const cacheData = JSON.parse(readFileSync15(ALL_MODELS_CACHE_PATH2, "utf-8"));
46030
+ if (existsSync19(ALL_MODELS_CACHE_PATH2)) {
46031
+ const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH2, "utf-8"));
45486
46032
  return cacheData.models || [];
45487
46033
  }
45488
46034
  return [];
@@ -45578,63 +46124,53 @@ function fuzzyScore(text, query) {
45578
46124
  }
45579
46125
  return queryIndex === lowerQuery.length ? score / lowerText.length : 0;
45580
46126
  }
46127
+ function fmtSize(n) {
46128
+ if (n <= 0)
46129
+ return "0B";
46130
+ if (n < 1024)
46131
+ return `${n}B`;
46132
+ if (n < 1024 * 1024)
46133
+ return `${(n / 1024).toFixed(1)}KB`;
46134
+ return `${(n / (1024 * 1024)).toFixed(1)}MB`;
46135
+ }
45581
46136
  function formatTeamResult(status, sessionPath) {
45582
- const entries = Object.entries(status.models);
45583
- const failed = entries.filter(([, m]) => m.state === "FAILED" || m.state === "TIMEOUT");
46137
+ const entries = Object.entries(status.models).sort(([a], [b]) => a.localeCompare(b));
46138
+ const failed = entries.filter(([, m]) => m.state === "FAILED" || m.state === "TIMEOUT" || m.state === "EMPTY");
45584
46139
  const succeeded = entries.filter(([, m]) => m.state === "COMPLETED");
45585
- let result = JSON.stringify(status, null, 2);
46140
+ const lines = [];
46141
+ lines.push(`<<<TEAM_RESULT path="${sessionPath}">>>`);
46142
+ lines.push(`status: ${failed.length === 0 ? "ok" : succeeded.length === 0 ? "all-failed" : "partial"}` + ` \u2014 ${succeeded.length}/${entries.length} succeeded`);
46143
+ if (succeeded.length > 0) {
46144
+ lines.push("succeeded:");
46145
+ for (const [id, m] of succeeded) {
46146
+ lines.push(` ${id} ${fmtSize(m.outputSize)} response-${id}.md`);
46147
+ }
46148
+ }
45586
46149
  if (failed.length > 0) {
45587
- result += `
45588
-
45589
- ---
45590
- ## Failures Detected
45591
-
45592
- `;
45593
- result += `${succeeded.length}/${entries.length} models succeeded, ${failed.length} failed.
45594
-
45595
- `;
46150
+ lines.push("failures:");
45596
46151
  for (const [id, m] of failed) {
45597
- result += `### Model ${id}: ${m.state}
45598
- `;
45599
- if (m.error) {
45600
- result += `- **Model:** ${m.error.model}
45601
- `;
45602
- result += `- **Command:** \`${m.error.command}\`
45603
- `;
45604
- result += `- **Exit code:** ${m.exitCode}
45605
- `;
45606
- if (m.error.stderrSnippet) {
45607
- result += `- **Error output:**
45608
- \`\`\`
45609
- ${m.error.stderrSnippet}
45610
- \`\`\`
45611
- `;
45612
- }
45613
- result += `- **Full error log:** ${m.error.errorLogPath}
45614
- `;
45615
- result += `- **Working directory:** ${m.error.workDir}
45616
- `;
46152
+ const reason = m.error?.reason ?? "unknown";
46153
+ const next = NEXT_STEP[reason] ?? "read the evidence log";
46154
+ lines.push(` ${id} ${m.state} reason=${reason}`);
46155
+ if (m.error?.detail)
46156
+ lines.push(` what: ${m.error.detail}`);
46157
+ lines.push(` next: ${next}`);
46158
+ if (m.error?.errorLogPath) {
46159
+ lines.push(` evidence: ${m.error.errorLogPath}`);
46160
+ } else {
46161
+ lines.push(" evidence: NONE CAPTURED \u2014 orchestrator bug, report via report_error");
45617
46162
  }
45618
- result += `
45619
- `;
45620
46163
  }
45621
- result += `---
45622
- `;
45623
- result += "**To help claudish devs fix this**, use the `report_error` tool with:\n";
45624
- result += '- `error_type`: "provider_failure" or "team_failure"\n';
45625
- result += `- \`session_path\`: "${sessionPath}"
45626
- `;
45627
- result += "- Copy the stderr snippet above into `stderr_snippet`\n";
45628
- result += "- Set `auto_send: true` to suggest enabling automatic reporting\n";
46164
+ lines.push("actions:");
46165
+ lines.push(` full stderr/stdout for one failure \u2192 Read the evidence path above`);
46166
+ lines.push(` machine-readable status \u2192 team(mode="status", path="${sessionPath}")`);
46167
+ lines.push(` report a provider bug \u2192 report_error(session_path="${sessionPath}")`);
45629
46168
  }
45630
- return result;
45631
- }
45632
- function sanitize(text) {
45633
- if (!text)
45634
- return "";
45635
- return text.replace(/sk-[a-zA-Z0-9_-]{10,}/g, "sk-***REDACTED***").replace(/Bearer [a-zA-Z0-9_.-]+/g, "Bearer ***REDACTED***").replace(/\/Users\/[^/\s]+/g, "/Users/***").replace(/\/home\/[^/\s]+/g, "/home/***").replace(/[A-Z_]+_API_KEY=[^\s]+/g, "***_API_KEY=REDACTED").replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
46169
+ lines.push("<<<END_TEAM_RESULT>>>");
46170
+ return lines.join(`
46171
+ `);
45636
46172
  }
45637
- function defineTools(sessionManager) {
46173
+ function defineTools(sessionManager, notifyChannel) {
45638
46174
  const tools = [];
45639
46175
  tools.push({
45640
46176
  name: "run_prompt",
@@ -45965,12 +46501,25 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45965
46501
  const input = args.input;
45966
46502
  const timeout = args.timeout;
45967
46503
  const resolved = validateSessionPath(path);
46504
+ const teamSessionId = resolved.split("/").filter(Boolean).pop() ?? "team";
46505
+ const teamCreatedAt = new Date().toISOString();
46506
+ const runOpts = {
46507
+ timeout,
46508
+ onProgress: (u) => notifyChannel({
46509
+ content: u.rendered,
46510
+ sessionId: teamSessionId,
46511
+ event: u.phase === "settled" ? u.allFailed ? "failed" : "completed" : "running",
46512
+ model: "team",
46513
+ elapsedSeconds: (Date.now() - Date.parse(teamCreatedAt)) / 1000,
46514
+ createdAt: teamCreatedAt
46515
+ })
46516
+ };
45968
46517
  switch (mode) {
45969
46518
  case "run": {
45970
46519
  if (!models?.length)
45971
46520
  throw new Error("'models' is required for 'run' mode");
45972
46521
  setupSession(resolved, models, input);
45973
- const status = await runModels(resolved, { timeout });
46522
+ const status = await runModels(resolved, runOpts);
45974
46523
  return {
45975
46524
  content: [{ type: "text", text: formatTeamResult(status, resolved) }]
45976
46525
  };
@@ -45983,7 +46532,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45983
46532
  if (!models?.length)
45984
46533
  throw new Error("'models' is required for 'run-and-judge' mode");
45985
46534
  setupSession(resolved, models, input);
45986
- await runModels(resolved, { timeout });
46535
+ await runModels(resolved, runOpts);
45987
46536
  const verdict = await judgeResponses(resolved, { judges });
45988
46537
  return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
45989
46538
  }
@@ -46046,7 +46595,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46046
46595
  let stderrFull = stderr_snippet || "";
46047
46596
  if (error_log_path) {
46048
46597
  try {
46049
- stderrFull = readFileSync15(error_log_path, "utf-8");
46598
+ stderrFull = readFileSync17(error_log_path, "utf-8");
46050
46599
  } catch {}
46051
46600
  }
46052
46601
  const sessionData = {};
@@ -46054,16 +46603,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46054
46603
  const sp = session_path;
46055
46604
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
46056
46605
  try {
46057
- sessionData[file2] = readFileSync15(join21(sp, file2), "utf-8");
46606
+ sessionData[file2] = readFileSync17(join23(sp, file2), "utf-8");
46058
46607
  } catch {}
46059
46608
  }
46060
46609
  try {
46061
- const errorDir = join21(sp, "errors");
46062
- if (existsSync18(errorDir)) {
46610
+ const errorDir = join23(sp, "errors");
46611
+ if (existsSync19(errorDir)) {
46063
46612
  for (const f of readdirSync3(errorDir)) {
46064
46613
  if (f.endsWith(".log")) {
46065
46614
  try {
46066
- sessionData[`errors/${f}`] = readFileSync15(join21(errorDir, f), "utf-8");
46615
+ sessionData[`errors/${f}`] = readFileSync17(join23(errorDir, f), "utf-8");
46067
46616
  } catch {}
46068
46617
  }
46069
46618
  }
@@ -46073,7 +46622,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46073
46622
  for (const f of readdirSync3(sp)) {
46074
46623
  if (f.startsWith("response-") && f.endsWith(".md")) {
46075
46624
  try {
46076
- const content = readFileSync15(join21(sp, f), "utf-8");
46625
+ const content = readFileSync17(join23(sp, f), "utf-8");
46077
46626
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
46078
46627
  } catch {}
46079
46628
  }
@@ -46082,9 +46631,9 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
46082
46631
  }
46083
46632
  let version2 = "unknown";
46084
46633
  try {
46085
- const pkgPath = join21(__dirname2, "../package.json");
46086
- if (existsSync18(pkgPath)) {
46087
- version2 = JSON.parse(readFileSync15(pkgPath, "utf-8")).version;
46634
+ const pkgPath = join23(__dirname2, "../package.json");
46635
+ if (existsSync19(pkgPath)) {
46636
+ version2 = JSON.parse(readFileSync17(pkgPath, "utf-8")).version;
46088
46637
  }
46089
46638
  } catch {}
46090
46639
  const report = {
@@ -46369,7 +46918,31 @@ To report this error, use the report_error tool with error_type: "provider_failu
46369
46918
  watchNotificationResult(result, { sessionId: sessionId2, eventType: event.type });
46370
46919
  })
46371
46920
  });
46372
- const allTools = defineTools(sessionManager);
46921
+ const channelEnabled = enabledGroups.has("channel");
46922
+ const notifyChannel = (p) => {
46923
+ if (!channelEnabled)
46924
+ return;
46925
+ try {
46926
+ const result = server.notification({
46927
+ method: "notifications/claude/channel",
46928
+ params: {
46929
+ content: p.content,
46930
+ meta: {
46931
+ session_id: p.sessionId,
46932
+ event: p.event,
46933
+ model: p.model,
46934
+ elapsed_seconds: String(Math.round(p.elapsedSeconds)),
46935
+ task_id: p.sessionId,
46936
+ status: mapEventToTaskStatus(p.event),
46937
+ created_at: p.createdAt,
46938
+ last_updated_at: new Date().toISOString()
46939
+ }
46940
+ }
46941
+ });
46942
+ watchNotificationResult(result, { sessionId: p.sessionId, eventType: p.event });
46943
+ } catch {}
46944
+ };
46945
+ const allTools = defineTools(sessionManager, notifyChannel);
46373
46946
  const enabledTools = allTools.filter((t) => enabledGroups.has(t.group));
46374
46947
  const toolMap = new Map(enabledTools.map((t) => [t.name, t]));
46375
46948
  console.error(`[claudish] MCP server started (tools: ${toolMode}, ${enabledTools.length} tools)`);
@@ -46440,7 +47013,7 @@ When channel mode is active, you receive <channel source="claudish" ...> notific
46440
47013
  5. Use list_sessions to see all active/completed sessions.
46441
47014
  6. Use cancel_session to stop a running session.
46442
47015
 
46443
- The session_id in the channel tag's meta attributes is the key for all tool calls.`, proxyInstance = null, proxyStarting = null, EVENT_TO_TASK_STATUS;
47016
+ The session_id in the channel tag's meta attributes is the key for all tool calls.`, proxyInstance = null, proxyStarting = null, NEXT_STEP, sanitize, EVENT_TO_TASK_STATUS;
46444
47017
  var init_mcp_server = __esm(() => {
46445
47018
  init_server2();
46446
47019
  init_stdio2();
@@ -46450,15 +47023,24 @@ var init_mcp_server = __esm(() => {
46450
47023
  init_channel();
46451
47024
  init_model_loader();
46452
47025
  init_port_manager();
47026
+ init_redact();
46453
47027
  init_provider_definitions();
46454
47028
  init_proxy_server();
46455
47029
  init_team_orchestrator();
46456
47030
  import_dotenv2 = __toESM(require_main(), 1);
46457
47031
  import_dotenv2.config({ quiet: true });
46458
47032
  __filename2 = fileURLToPath(import.meta.url);
46459
- __dirname2 = dirname5(__filename2);
46460
- CLAUDISH_CACHE_DIR = join21(homedir20(), ".claudish");
46461
- ALL_MODELS_CACHE_PATH2 = join21(CLAUDISH_CACHE_DIR, "all-models.json");
47033
+ __dirname2 = dirname7(__filename2);
47034
+ CLAUDISH_CACHE_DIR = join23(homedir21(), ".claudish");
47035
+ ALL_MODELS_CACHE_PATH2 = join23(CLAUDISH_CACHE_DIR, "all-models.json");
47036
+ NEXT_STEP = {
47037
+ nonzero_exit: "read the evidence log, then retry or drop the model",
47038
+ timeout: "raise `timeout`, or pick a faster model",
47039
+ api_error: "retry once, or route via a different provider (or@<model>)",
47040
+ background_task_ceiling: "set CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 for children, or forbid background work in the prompt",
47041
+ empty_output: "retry once; if it repeats, drop the model"
47042
+ };
47043
+ sanitize = sanitizeForReport;
46462
47044
  EVENT_TO_TASK_STATUS = new Map([
46463
47045
  ["starting", "working"],
46464
47046
  ["running", "working"],
@@ -46475,7 +47057,7 @@ var exports_serve_command = {};
46475
47057
  __export(exports_serve_command, {
46476
47058
  serveCommand: () => serveCommand
46477
47059
  });
46478
- import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
47060
+ import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
46479
47061
  function parseServeArgs(args) {
46480
47062
  const out = {};
46481
47063
  for (let i = 0;i < args.length; i++) {
@@ -46494,12 +47076,12 @@ function parseServeArgs(args) {
46494
47076
  return out;
46495
47077
  }
46496
47078
  function loadModelMap(path) {
46497
- if (!existsSync19(path)) {
47079
+ if (!existsSync20(path)) {
46498
47080
  throw new Error(`--models file not found: ${path}`);
46499
47081
  }
46500
47082
  let raw2;
46501
47083
  try {
46502
- raw2 = readFileSync16(path, "utf-8");
47084
+ raw2 = readFileSync18(path, "utf-8");
46503
47085
  } catch (e) {
46504
47086
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
46505
47087
  }
@@ -57971,7 +58553,7 @@ var init_RemoveFileError = __esm(() => {
57971
58553
 
57972
58554
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
57973
58555
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
57974
- import { readFileSync as readFileSync17, unlinkSync as unlinkSync6, writeFileSync as writeFileSync13 } from "fs";
58556
+ import { readFileSync as readFileSync19, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "fs";
57975
58557
  import path from "path";
57976
58558
  import os from "os";
57977
58559
  import { randomUUID as randomUUID4 } from "crypto";
@@ -58080,14 +58662,14 @@ class ExternalEditor {
58080
58662
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
58081
58663
  opt.mode = this.fileOptions.mode;
58082
58664
  }
58083
- writeFileSync13(this.tempFile, this.text, opt);
58665
+ writeFileSync14(this.tempFile, this.text, opt);
58084
58666
  } catch (createFileError) {
58085
58667
  throw new CreateFileError(createFileError);
58086
58668
  }
58087
58669
  }
58088
58670
  readTemporaryFile() {
58089
58671
  try {
58090
- const tempFileBuffer = readFileSync17(this.tempFile);
58672
+ const tempFileBuffer = readFileSync19(this.tempFile);
58091
58673
  if (tempFileBuffer.length === 0) {
58092
58674
  this.text = "";
58093
58675
  } else {
@@ -59282,15 +59864,15 @@ async function geminiQuotaHandler() {
59282
59864
  }
59283
59865
  }
59284
59866
  async function codexQuotaHandler() {
59285
- const { readFileSync: readFileSync18, existsSync: existsSync20 } = await import("fs");
59286
- const { join: join22 } = await import("path");
59287
- const { homedir: homedir21 } = await import("os");
59288
- const credPath = join22(homedir21(), ".claudish", "codex-oauth.json");
59289
- if (!existsSync20(credPath)) {
59867
+ const { readFileSync: readFileSync20, existsSync: existsSync21 } = await import("fs");
59868
+ const { join: join24 } = await import("path");
59869
+ const { homedir: homedir22 } = await import("os");
59870
+ const credPath = join24(homedir22(), ".claudish", "codex-oauth.json");
59871
+ if (!existsSync21(credPath)) {
59290
59872
  console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
59291
59873
  process.exit(1);
59292
59874
  }
59293
- const creds = JSON.parse(readFileSync18(credPath, "utf-8"));
59875
+ const creds = JSON.parse(readFileSync20(credPath, "utf-8"));
59294
59876
  let email3 = "";
59295
59877
  try {
59296
59878
  const parts = creds.access_token.split(".");
@@ -59342,9 +59924,9 @@ async function codexQuotaHandler() {
59342
59924
  }
59343
59925
  let modelSlugs = [];
59344
59926
  try {
59345
- const modelsPath = join22(homedir21(), ".codex", "models_cache.json");
59346
- if (existsSync20(modelsPath)) {
59347
- const cache2 = JSON.parse(readFileSync18(modelsPath, "utf-8"));
59927
+ const modelsPath = join24(homedir22(), ".codex", "models_cache.json");
59928
+ if (existsSync21(modelsPath)) {
59929
+ const cache2 = JSON.parse(readFileSync20(modelsPath, "utf-8"));
59348
59930
  modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
59349
59931
  }
59350
59932
  } catch {}
@@ -60692,19 +61274,19 @@ async function probeLink(proxyUrl, link, timeoutMs) {
60692
61274
  }
60693
61275
  const streamResult = await consumeProbeStream(response, timeoutMs, startedAt);
60694
61276
  const totalMs = Date.now() - startedAt;
60695
- let timing;
61277
+ let timing2;
60696
61278
  if (streamResult.state === "live" && streamResult.ttftMs !== undefined && !streamResult.truncated) {
60697
61279
  const ttftMs = streamResult.ttftMs;
60698
61280
  const tokens = streamResult.tokens ?? 0;
60699
61281
  const streamMs = Math.max(STREAM_MS_FLOOR, totalMs - ttftMs);
60700
61282
  const tokensPerSec = tokens > 0 ? tokens / streamMs * 1000 : 0;
60701
- timing = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
61283
+ timing2 = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
60702
61284
  }
60703
61285
  const { ttftMs: _ttft, tokens: _tok, truncated: _trunc, ...rest } = streamResult;
60704
61286
  return annotateOAuthHint({
60705
61287
  ...rest,
60706
61288
  latencyMs: totalMs,
60707
- timing
61289
+ timing: timing2
60708
61290
  }, link.provider, isOAuth);
60709
61291
  }
60710
61292
  function annotateOAuthHint(result, provider, isOAuth) {
@@ -61301,8 +61883,8 @@ function breakdownNum(ms) {
61301
61883
  return formatLatency(ms);
61302
61884
  return `${Math.round(Math.max(0, ms))}`;
61303
61885
  }
61304
- function buildBarsLine(timing, scales, isFastest, usable) {
61305
- const t = timing;
61886
+ function buildBarsLine(timing2, scales, isFastest, usable) {
61887
+ const t = timing2;
61306
61888
  const showTokBar = usable >= PRINTER_BARS_FULL_WIDTH;
61307
61889
  const showBreakdown = usable >= PRINTER_BARS_FULL_WIDTH || usable >= PRINTER_BARS_NOTOK_WIDTH;
61308
61890
  const barCells = timelineBarCells(t.totalMs, scales.maxTotalMs, PRINTER_BAR_WIDTH);
@@ -63307,22 +63889,22 @@ __export(exports_cli, {
63307
63889
  });
63308
63890
  import {
63309
63891
  copyFileSync as copyFileSync2,
63310
- existsSync as existsSync20,
63311
- mkdirSync as mkdirSync12,
63312
- readFileSync as readFileSync18,
63892
+ existsSync as existsSync21,
63893
+ mkdirSync as mkdirSync13,
63894
+ readFileSync as readFileSync20,
63313
63895
  readdirSync as readdirSync4,
63314
63896
  unlinkSync as unlinkSync7,
63315
- writeFileSync as writeFileSync14
63897
+ writeFileSync as writeFileSync15
63316
63898
  } from "fs";
63317
- import { homedir as homedir21 } from "os";
63318
- import { dirname as dirname6, join as join22 } from "path";
63899
+ import { homedir as homedir22 } from "os";
63900
+ import { dirname as dirname8, join as join24 } from "path";
63319
63901
  import { fileURLToPath as fileURLToPath2 } from "url";
63320
63902
  function getVersion3() {
63321
63903
  return VERSION;
63322
63904
  }
63323
63905
  function clearAllModelCaches() {
63324
- const cacheDir = join22(homedir21(), ".claudish");
63325
- if (!existsSync20(cacheDir))
63906
+ const cacheDir = join24(homedir22(), ".claudish");
63907
+ if (!existsSync21(cacheDir))
63326
63908
  return;
63327
63909
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
63328
63910
  let cleared = 0;
@@ -63330,7 +63912,7 @@ function clearAllModelCaches() {
63330
63912
  const files = readdirSync4(cacheDir);
63331
63913
  for (const file2 of files) {
63332
63914
  if (cachePatterns.includes(file2)) {
63333
- unlinkSync7(join22(cacheDir, file2));
63915
+ unlinkSync7(join24(cacheDir, file2));
63334
63916
  cleared++;
63335
63917
  }
63336
63918
  }
@@ -63740,15 +64322,15 @@ Usage: claudish --models --provider <slug>`);
63740
64322
  });
63741
64323
  config3.resolvedDefaultProvider = resolved;
63742
64324
  if (resolved.legacyAutoPromoted && !config3.quiet) {
63743
- const markerFile = join22(homedir21(), ".claudish", ".legacy-litellm-hint-shown");
63744
- if (!existsSync20(markerFile)) {
64325
+ const markerFile = join24(homedir22(), ".claudish", ".legacy-litellm-hint-shown");
64326
+ if (!existsSync21(markerFile)) {
63745
64327
  const hint = buildLegacyHint(resolved);
63746
64328
  if (hint) {
63747
64329
  console.error(hint);
63748
64330
  }
63749
64331
  try {
63750
- mkdirSync12(dirname6(markerFile), { recursive: true });
63751
- writeFileSync14(markerFile, new Date().toISOString(), "utf-8");
64332
+ mkdirSync13(dirname8(markerFile), { recursive: true });
64333
+ writeFileSync15(markerFile, new Date().toISOString(), "utf-8");
63752
64334
  } catch {}
63753
64335
  }
63754
64336
  }
@@ -64808,8 +65390,8 @@ ${h("MORE INFO")}
64808
65390
  }
64809
65391
  function printAIAgentGuide() {
64810
65392
  try {
64811
- const guidePath = join22(__dirname3, "../AI_AGENT_GUIDE.md");
64812
- const guideContent = readFileSync18(guidePath, "utf-8");
65393
+ const guidePath = join24(__dirname3, "../AI_AGENT_GUIDE.md");
65394
+ const guideContent = readFileSync20(guidePath, "utf-8");
64813
65395
  console.log(guideContent);
64814
65396
  } catch (error46) {
64815
65397
  console.error("Error reading AI Agent Guide:");
@@ -64825,19 +65407,19 @@ async function initializeClaudishSkill() {
64825
65407
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
64826
65408
  `);
64827
65409
  const cwd = process.cwd();
64828
- const claudeDir = join22(cwd, ".claude");
64829
- const skillsDir = join22(claudeDir, "skills");
64830
- const claudishSkillDir = join22(skillsDir, "claudish-usage");
64831
- const skillFile = join22(claudishSkillDir, "SKILL.md");
64832
- if (existsSync20(skillFile)) {
65410
+ const claudeDir = join24(cwd, ".claude");
65411
+ const skillsDir = join24(claudeDir, "skills");
65412
+ const claudishSkillDir = join24(skillsDir, "claudish-usage");
65413
+ const skillFile = join24(claudishSkillDir, "SKILL.md");
65414
+ if (existsSync21(skillFile)) {
64833
65415
  console.log("\u2705 Claudish skill already installed at:");
64834
65416
  console.log(` ${skillFile}
64835
65417
  `);
64836
65418
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
64837
65419
  return;
64838
65420
  }
64839
- const sourceSkillPath = join22(__dirname3, "../skills/claudish-usage/SKILL.md");
64840
- if (!existsSync20(sourceSkillPath)) {
65421
+ const sourceSkillPath = join24(__dirname3, "../skills/claudish-usage/SKILL.md");
65422
+ if (!existsSync21(sourceSkillPath)) {
64841
65423
  console.error("\u274C Error: Claudish skill file not found in installation.");
64842
65424
  console.error(` Expected at: ${sourceSkillPath}`);
64843
65425
  console.error(`
@@ -64846,16 +65428,16 @@ async function initializeClaudishSkill() {
64846
65428
  process.exit(1);
64847
65429
  }
64848
65430
  try {
64849
- if (!existsSync20(claudeDir)) {
64850
- mkdirSync12(claudeDir, { recursive: true });
65431
+ if (!existsSync21(claudeDir)) {
65432
+ mkdirSync13(claudeDir, { recursive: true });
64851
65433
  console.log("\uD83D\uDCC1 Created .claude/ directory");
64852
65434
  }
64853
- if (!existsSync20(skillsDir)) {
64854
- mkdirSync12(skillsDir, { recursive: true });
65435
+ if (!existsSync21(skillsDir)) {
65436
+ mkdirSync13(skillsDir, { recursive: true });
64855
65437
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
64856
65438
  }
64857
- if (!existsSync20(claudishSkillDir)) {
64858
- mkdirSync12(claudishSkillDir, { recursive: true });
65439
+ if (!existsSync21(claudishSkillDir)) {
65440
+ mkdirSync13(claudishSkillDir, { recursive: true });
64859
65441
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
64860
65442
  }
64861
65443
  copyFileSync2(sourceSkillPath, skillFile);
@@ -64927,7 +65509,7 @@ var init_cli = __esm(() => {
64927
65509
  init_routing_rules();
64928
65510
  init_provider_resolver();
64929
65511
  __filename3 = fileURLToPath2(import.meta.url);
64930
- __dirname3 = dirname6(__filename3);
65512
+ __dirname3 = dirname8(__filename3);
64931
65513
  });
64932
65514
 
64933
65515
  // src/update-checker.ts
@@ -64939,33 +65521,33 @@ __export(exports_update_checker, {
64939
65521
  clearCache: () => clearCache,
64940
65522
  checkForUpdates: () => checkForUpdates
64941
65523
  });
64942
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync15 } from "fs";
64943
- import { homedir as homedir22, platform as platform2, tmpdir } from "os";
64944
- import { join as join23 } from "path";
65524
+ import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync21, unlinkSync as unlinkSync8, writeFileSync as writeFileSync16 } from "fs";
65525
+ import { homedir as homedir23, platform as platform2, tmpdir } from "os";
65526
+ import { join as join25 } from "path";
64945
65527
  function getCacheFilePath() {
64946
65528
  let cacheDir;
64947
65529
  if (isWindows) {
64948
- const localAppData = process.env.LOCALAPPDATA || join23(homedir22(), "AppData", "Local");
64949
- cacheDir = join23(localAppData, "claudish");
65530
+ const localAppData = process.env.LOCALAPPDATA || join25(homedir23(), "AppData", "Local");
65531
+ cacheDir = join25(localAppData, "claudish");
64950
65532
  } else {
64951
- cacheDir = join23(homedir22(), ".cache", "claudish");
65533
+ cacheDir = join25(homedir23(), ".cache", "claudish");
64952
65534
  }
64953
65535
  try {
64954
- if (!existsSync21(cacheDir)) {
64955
- mkdirSync13(cacheDir, { recursive: true });
65536
+ if (!existsSync22(cacheDir)) {
65537
+ mkdirSync14(cacheDir, { recursive: true });
64956
65538
  }
64957
- return join23(cacheDir, "update-check.json");
65539
+ return join25(cacheDir, "update-check.json");
64958
65540
  } catch {
64959
- return join23(tmpdir(), "claudish-update-check.json");
65541
+ return join25(tmpdir(), "claudish-update-check.json");
64960
65542
  }
64961
65543
  }
64962
65544
  function readCache() {
64963
65545
  try {
64964
65546
  const cachePath = getCacheFilePath();
64965
- if (!existsSync21(cachePath)) {
65547
+ if (!existsSync22(cachePath)) {
64966
65548
  return null;
64967
65549
  }
64968
- const data = JSON.parse(readFileSync19(cachePath, "utf-8"));
65550
+ const data = JSON.parse(readFileSync21(cachePath, "utf-8"));
64969
65551
  return data;
64970
65552
  } catch {
64971
65553
  return null;
@@ -64978,7 +65560,7 @@ function writeCache(latestVersion) {
64978
65560
  lastCheck: Date.now(),
64979
65561
  latestVersion
64980
65562
  };
64981
- writeFileSync15(cachePath, JSON.stringify(data), "utf-8");
65563
+ writeFileSync16(cachePath, JSON.stringify(data), "utf-8");
64982
65564
  } catch {}
64983
65565
  }
64984
65566
  function isCacheValid(cache2) {
@@ -64988,7 +65570,7 @@ function isCacheValid(cache2) {
64988
65570
  function clearCache() {
64989
65571
  try {
64990
65572
  const cachePath = getCacheFilePath();
64991
- if (existsSync21(cachePath)) {
65573
+ if (existsSync22(cachePath)) {
64992
65574
  unlinkSync8(cachePath);
64993
65575
  }
64994
65576
  } catch {}
@@ -65867,15 +66449,15 @@ var init_local_liveness = __esm(() => {
65867
66449
  });
65868
66450
 
65869
66451
  // src/providers/probe-catalog.ts
65870
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "fs";
65871
- import { homedir as homedir23 } from "os";
65872
- import { dirname as dirname7, join as join24 } from "path";
66452
+ import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync22, writeFileSync as writeFileSync17 } from "fs";
66453
+ import { homedir as homedir24 } from "os";
66454
+ import { dirname as dirname9, join as join26 } from "path";
65873
66455
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
65874
- if (!existsSync22(path2))
66456
+ if (!existsSync23(path2))
65875
66457
  return null;
65876
66458
  let raw2;
65877
66459
  try {
65878
- raw2 = JSON.parse(readFileSync20(path2, "utf-8"));
66460
+ raw2 = JSON.parse(readFileSync22(path2, "utf-8"));
65879
66461
  } catch {
65880
66462
  return null;
65881
66463
  }
@@ -65884,8 +66466,8 @@ function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
65884
66466
  return raw2;
65885
66467
  }
65886
66468
  function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
65887
- mkdirSync14(dirname7(path2), { recursive: true });
65888
- writeFileSync16(path2, JSON.stringify(data), "utf-8");
66469
+ mkdirSync15(dirname9(path2), { recursive: true });
66470
+ writeFileSync17(path2, JSON.stringify(data), "utf-8");
65889
66471
  }
65890
66472
  function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
65891
66473
  if (!data?.generatedAt)
@@ -66004,7 +66586,7 @@ function isValidResponse(raw2) {
66004
66586
  var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
66005
66587
  var init_probe_catalog = __esm(() => {
66006
66588
  CACHE_TTL_MS4 = 60 * 60 * 1000;
66007
- PROBE_MODELS_CACHE_PATH = join24(homedir23(), ".claudish", "probe-models.json");
66589
+ PROBE_MODELS_CACHE_PATH = join26(homedir24(), ".claudish", "probe-models.json");
66008
66590
  });
66009
66591
 
66010
66592
  // src/tui/constants.ts
@@ -72337,16 +72919,16 @@ __export(exports_claude_runner, {
72337
72919
  });
72338
72920
  import { spawn as spawn4 } from "child_process";
72339
72921
  import {
72340
- closeSync as closeSync4,
72341
- existsSync as existsSync23,
72342
- mkdirSync as mkdirSync15,
72343
- openSync as openSync4,
72344
- readFileSync as readFileSync21,
72922
+ closeSync as closeSync5,
72923
+ existsSync as existsSync24,
72924
+ mkdirSync as mkdirSync16,
72925
+ openSync as openSync5,
72926
+ readFileSync as readFileSync23,
72345
72927
  unlinkSync as unlinkSync9,
72346
- writeFileSync as writeFileSync17
72928
+ writeFileSync as writeFileSync18
72347
72929
  } from "fs";
72348
- import { homedir as homedir24, tmpdir as tmpdir2 } from "os";
72349
- import { join as join25 } from "path";
72930
+ import { homedir as homedir25, tmpdir as tmpdir2 } from "os";
72931
+ import { join as join27 } from "path";
72350
72932
  import { isatty } from "tty";
72351
72933
  function releaseTerminalIsolation() {
72352
72934
  if (!restoreTerminal)
@@ -72381,14 +72963,14 @@ function isProxyAuthMode(config3) {
72381
72963
  }
72382
72964
  function managedSettingsPath() {
72383
72965
  if (isWindows2()) {
72384
- return join25(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
72966
+ return join27(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
72385
72967
  }
72386
72968
  if (process.platform === "darwin") {
72387
72969
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
72388
72970
  }
72389
72971
  return "/etc/claude-code/managed-settings.json";
72390
72972
  }
72391
- function managedSettingsForcesClaudeAi(readFile = readFileSync21) {
72973
+ function managedSettingsForcesClaudeAi(readFile = readFileSync23) {
72392
72974
  try {
72393
72975
  const raw2 = readFile(managedSettingsPath(), "utf-8");
72394
72976
  const parsed = JSON.parse(raw2);
@@ -72402,9 +72984,9 @@ function isWindows2() {
72402
72984
  }
72403
72985
  function createStatusLineScript(tokenFilePath) {
72404
72986
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
72405
- const claudishDir = join25(homeDir, ".claudish");
72987
+ const claudishDir = join27(homeDir, ".claudish");
72406
72988
  const timestamp = Date.now();
72407
- const scriptPath = join25(claudishDir, `status-${timestamp}.js`);
72989
+ const scriptPath = join27(claudishDir, `status-${timestamp}.js`);
72408
72990
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
72409
72991
  const script = `
72410
72992
  const fs = require('fs');
@@ -72496,18 +73078,18 @@ process.stdin.on('end', () => {
72496
73078
  }
72497
73079
  });
72498
73080
  `;
72499
- writeFileSync17(scriptPath, script, "utf-8");
73081
+ writeFileSync18(scriptPath, script, "utf-8");
72500
73082
  return scriptPath;
72501
73083
  }
72502
73084
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
72503
73085
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
72504
- const claudishDir = join25(homeDir, ".claudish");
73086
+ const claudishDir = join27(homeDir, ".claudish");
72505
73087
  try {
72506
- mkdirSync15(claudishDir, { recursive: true });
73088
+ mkdirSync16(claudishDir, { recursive: true });
72507
73089
  } catch {}
72508
73090
  const timestamp = Date.now();
72509
- const tempPath = join25(claudishDir, `settings-${timestamp}.json`);
72510
- const tokenFilePath = join25(claudishDir, `tokens-${port}.json`);
73091
+ const tempPath = join27(claudishDir, `settings-${timestamp}.json`);
73092
+ const tokenFilePath = join27(claudishDir, `tokens-${port}.json`);
72511
73093
  let statusCommand;
72512
73094
  if (isWindows2()) {
72513
73095
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -72529,7 +73111,7 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
72529
73111
  padding: 0
72530
73112
  };
72531
73113
  const settings = buildClaudishSettingsOverlay(statusLine, proxyAuthMode);
72532
- writeFileSync17(tempPath, JSON.stringify(settings, null, 2), "utf-8");
73114
+ writeFileSync18(tempPath, JSON.stringify(settings, null, 2), "utf-8");
72533
73115
  return { path: tempPath, statusLine };
72534
73116
  }
72535
73117
  function buildClaudishSettingsOverlay(statusLine, proxyAuthMode) {
@@ -72550,7 +73132,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
72550
73132
  if (userSettingsValue.trimStart().startsWith("{")) {
72551
73133
  userSettings = JSON.parse(userSettingsValue);
72552
73134
  } else {
72553
- const rawUserSettings = readFileSync21(userSettingsValue, "utf-8");
73135
+ const rawUserSettings = readFileSync23(userSettingsValue, "utf-8");
72554
73136
  userSettings = JSON.parse(rawUserSettings);
72555
73137
  }
72556
73138
  userSettings.statusLine = statusLine;
@@ -72560,7 +73142,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
72560
73142
  if (proxyAuthMode && !("forceLoginMethod" in userSettings)) {
72561
73143
  userSettings.forceLoginMethod = "console";
72562
73144
  }
72563
- writeFileSync17(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
73145
+ writeFileSync18(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
72564
73146
  } catch {
72565
73147
  if (!config3.quiet) {
72566
73148
  console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
@@ -72721,8 +73303,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
72721
73303
  console.error("Install it from: https://claude.com/claude-code");
72722
73304
  console.error(`
72723
73305
  Or set CLAUDE_PATH to your custom installation:`);
72724
- const home = homedir24();
72725
- const localPath = isWindows2() ? join25(home, ".claude", "local", "claude.exe") : join25(home, ".claude", "local", "claude");
73306
+ const home = homedir25();
73307
+ const localPath = isWindows2() ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
72726
73308
  console.error(` export CLAUDE_PATH=${localPath}`);
72727
73309
  process.exit(1);
72728
73310
  }
@@ -72733,11 +73315,11 @@ Or set CLAUDE_PATH to your custom installation:`);
72733
73315
  const childWantsTty = config3.interactive && !process.stdout.isTTY && Boolean(process.stdin.isTTY);
72734
73316
  if (childWantsTty) {
72735
73317
  try {
72736
- const fd = openSync4("/dev/fd/0", "r+");
73318
+ const fd = openSync5("/dev/fd/0", "r+");
72737
73319
  if (isatty(fd)) {
72738
73320
  ttyFd = fd;
72739
73321
  } else {
72740
- closeSync4(fd);
73322
+ closeSync5(fd);
72741
73323
  }
72742
73324
  } catch {
72743
73325
  ttyFd = undefined;
@@ -72760,7 +73342,7 @@ Or set CLAUDE_PATH to your custom installation:`);
72760
73342
  const fdToClose = ttyFd;
72761
73343
  proc.on("spawn", () => {
72762
73344
  try {
72763
- closeSync4(fdToClose);
73345
+ closeSync5(fdToClose);
72764
73346
  } catch {}
72765
73347
  });
72766
73348
  }
@@ -72802,23 +73384,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
72802
73384
  async function findClaudeBinary() {
72803
73385
  const isWindows3 = process.platform === "win32";
72804
73386
  if (process.env.CLAUDE_PATH) {
72805
- if (existsSync23(process.env.CLAUDE_PATH)) {
73387
+ if (existsSync24(process.env.CLAUDE_PATH)) {
72806
73388
  return process.env.CLAUDE_PATH;
72807
73389
  }
72808
73390
  }
72809
- const home = homedir24();
72810
- const localPath = isWindows3 ? join25(home, ".claude", "local", "claude.exe") : join25(home, ".claude", "local", "claude");
72811
- if (existsSync23(localPath)) {
73391
+ const home = homedir25();
73392
+ const localPath = isWindows3 ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
73393
+ if (existsSync24(localPath)) {
72812
73394
  return localPath;
72813
73395
  }
72814
73396
  if (isWindows3) {
72815
73397
  const windowsPaths = [
72816
- join25(home, "AppData", "Roaming", "npm", "claude.cmd"),
72817
- join25(home, ".npm-global", "claude.cmd"),
72818
- join25(home, "node_modules", ".bin", "claude.cmd")
73398
+ join27(home, "AppData", "Roaming", "npm", "claude.cmd"),
73399
+ join27(home, ".npm-global", "claude.cmd"),
73400
+ join27(home, "node_modules", ".bin", "claude.cmd")
72819
73401
  ];
72820
73402
  for (const path2 of windowsPaths) {
72821
- if (existsSync23(path2)) {
73403
+ if (existsSync24(path2)) {
72822
73404
  return path2;
72823
73405
  }
72824
73406
  }
@@ -72826,14 +73408,14 @@ async function findClaudeBinary() {
72826
73408
  const commonPaths = [
72827
73409
  "/usr/local/bin/claude",
72828
73410
  "/opt/homebrew/bin/claude",
72829
- join25(home, ".npm-global/bin/claude"),
72830
- join25(home, ".local/bin/claude"),
72831
- join25(home, "node_modules/.bin/claude"),
73411
+ join27(home, ".npm-global/bin/claude"),
73412
+ join27(home, ".local/bin/claude"),
73413
+ join27(home, "node_modules/.bin/claude"),
72832
73414
  "/data/data/com.termux/files/usr/bin/claude",
72833
- join25(home, "../usr/bin/claude")
73415
+ join27(home, "../usr/bin/claude")
72834
73416
  ];
72835
73417
  for (const path2 of commonPaths) {
72836
- if (existsSync23(path2)) {
73418
+ if (existsSync24(path2)) {
72837
73419
  return path2;
72838
73420
  }
72839
73421
  }
@@ -72890,18 +73472,18 @@ __export(exports_diag_output, {
72890
73472
  NullDiagOutput: () => NullDiagOutput,
72891
73473
  LogFileDiagOutput: () => LogFileDiagOutput
72892
73474
  });
72893
- import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync16, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
72894
- import { homedir as homedir25 } from "os";
72895
- import { join as join26 } from "path";
73475
+ import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync17, unlinkSync as unlinkSync10, writeFileSync as writeFileSync19 } from "fs";
73476
+ import { homedir as homedir26 } from "os";
73477
+ import { join as join28 } from "path";
72896
73478
  function getClaudishDir() {
72897
- const dir = join26(homedir25(), ".claudish");
73479
+ const dir = join28(homedir26(), ".claudish");
72898
73480
  try {
72899
- mkdirSync16(dir, { recursive: true });
73481
+ mkdirSync17(dir, { recursive: true });
72900
73482
  } catch {}
72901
73483
  return dir;
72902
73484
  }
72903
73485
  function getDiagLogPath() {
72904
- return join26(getClaudishDir(), `diag-${process.pid}.log`);
73486
+ return join28(getClaudishDir(), `diag-${process.pid}.log`);
72905
73487
  }
72906
73488
 
72907
73489
  class LogFileDiagOutput {
@@ -72910,7 +73492,7 @@ class LogFileDiagOutput {
72910
73492
  constructor() {
72911
73493
  this.logPath = getDiagLogPath();
72912
73494
  try {
72913
- writeFileSync18(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
73495
+ writeFileSync19(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
72914
73496
  `);
72915
73497
  } catch {}
72916
73498
  this.stream = createWriteStream3(this.logPath, { flags: "a" });
@@ -73112,9 +73694,9 @@ __export(exports_team_grid, {
73112
73694
  });
73113
73695
  import { spawn as spawn5 } from "child_process";
73114
73696
  import { execSync as execSync2 } from "child_process";
73115
- import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync19 } from "fs";
73697
+ import { existsSync as existsSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync20 } from "fs";
73116
73698
  import { connect as netConnect } from "net";
73117
- import { dirname as dirname8, join as join27 } from "path";
73699
+ import { dirname as dirname10, join as join29 } from "path";
73118
73700
  import { setTimeout as wait } from "timers/promises";
73119
73701
  import { fileURLToPath as fileURLToPath3 } from "url";
73120
73702
  function resolveRouteInfo(modelId) {
@@ -73207,21 +73789,21 @@ function buildPaneHeader(model, prompt, bg) {
73207
73789
  }
73208
73790
  function findMagmuxBinary() {
73209
73791
  const thisFile = fileURLToPath3(import.meta.url);
73210
- const thisDir = dirname8(thisFile);
73211
- const pkgRoot = join27(thisDir, "..");
73792
+ const thisDir = dirname10(thisFile);
73793
+ const pkgRoot = join29(thisDir, "..");
73212
73794
  const platform3 = process.platform;
73213
73795
  const arch = process.arch;
73214
- const bundledMagmux = join27(pkgRoot, "native", `magmux-${platform3}-${arch}`);
73215
- if (existsSync24(bundledMagmux))
73796
+ const bundledMagmux = join29(pkgRoot, "native", `magmux-${platform3}-${arch}`);
73797
+ if (existsSync25(bundledMagmux))
73216
73798
  return bundledMagmux;
73217
73799
  try {
73218
73800
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
73219
73801
  let searchDir = pkgRoot;
73220
73802
  for (let i = 0;i < 5; i++) {
73221
- const candidate = join27(searchDir, "node_modules", pkgName, "bin", "magmux");
73222
- if (existsSync24(candidate))
73803
+ const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
73804
+ if (existsSync25(candidate))
73223
73805
  return candidate;
73224
- const parent = dirname8(searchDir);
73806
+ const parent = dirname10(searchDir);
73225
73807
  if (parent === searchDir)
73226
73808
  break;
73227
73809
  searchDir = parent;
@@ -73238,7 +73820,7 @@ function findMagmuxBinary() {
73238
73820
  async function subscribeToMagmux(sockPath, onEvent) {
73239
73821
  let client = null;
73240
73822
  for (let attempt = 0;attempt < 40; attempt++) {
73241
- if (existsSync24(sockPath)) {
73823
+ if (existsSync25(sockPath)) {
73242
73824
  try {
73243
73825
  client = await new Promise((resolve4, reject) => {
73244
73826
  const s = netConnect(sockPath);
@@ -73325,9 +73907,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
73325
73907
  const keep = opts?.keep ?? false;
73326
73908
  const manifest = setupSession(sessionPath, models, input);
73327
73909
  const startedAt = new Date().toISOString();
73328
- const gridfilePath = join27(sessionPath, "gridfile.txt");
73329
- const prompt = readFileSync22(join27(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
73330
- const rawPrompt = readFileSync22(join27(sessionPath, "input.md"), "utf-8");
73910
+ const gridfilePath = join29(sessionPath, "gridfile.txt");
73911
+ const prompt = readFileSync24(join29(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
73912
+ const rawPrompt = readFileSync24(join29(sessionPath, "input.md"), "utf-8");
73331
73913
  const usedBannerColors = new Set;
73332
73914
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
73333
73915
  const model = manifest.models[anonId].model;
@@ -73338,7 +73920,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
73338
73920
  const header = buildPaneHeader(model, rawPrompt, bg);
73339
73921
  return `${header} claudish --model ${model} -y --quiet '${prompt}'`;
73340
73922
  });
73341
- writeFileSync19(gridfilePath, `${gridLines.join(`
73923
+ writeFileSync20(gridfilePath, `${gridLines.join(`
73342
73924
  `)}
73343
73925
  `, "utf-8");
73344
73926
  const magmuxPath = findMagmuxBinary();
@@ -73358,8 +73940,8 @@ async function runWithGrid(sessionPath, models, input, opts) {
73358
73940
  });
73359
73941
  const [{ results }] = await Promise.all([subscription, procExit]);
73360
73942
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
73361
- const statusPath = join27(sessionPath, "status.json");
73362
- writeFileSync19(statusPath, JSON.stringify(status, null, 2), "utf-8");
73943
+ const statusPath = join29(sessionPath, "status.json");
73944
+ writeFileSync20(statusPath, JSON.stringify(status, null, 2), "utf-8");
73363
73945
  return status;
73364
73946
  }
73365
73947
  var BANNER_BG_COLORS;
@@ -73382,8 +73964,8 @@ var init_team_grid = __esm(() => {
73382
73964
  init_op_source();
73383
73965
  init_startup_trace();
73384
73966
  var import_dotenv3 = __toESM(require_main(), 1);
73385
- import { existsSync as existsSync25, readFileSync as readFileSync23 } from "fs";
73386
- import { join as join28, resolve as resolve4 } from "path";
73967
+ import { existsSync as existsSync26, readFileSync as readFileSync25 } from "fs";
73968
+ import { join as join30, resolve as resolve4 } from "path";
73387
73969
  import_dotenv3.config({ quiet: true });
73388
73970
  function classifyStartupKind() {
73389
73971
  const argv = process.argv.slice(2);
@@ -73482,7 +74064,7 @@ async function applyConfigOverride() {
73482
74064
  const { planConfigOverride: planConfigOverride2, setConfigFileOverride: setConfigFileOverride2 } = await Promise.resolve().then(() => exports_config_override);
73483
74065
  const plan = planConfigOverride2(process.argv.slice(2), process.env, {
73484
74066
  resolve: resolve4,
73485
- exists: existsSync25
74067
+ exists: existsSync26
73486
74068
  });
73487
74069
  if (plan.kind === "none")
73488
74070
  return;
@@ -73617,14 +74199,14 @@ async function runCli() {
73617
74199
  if (cliConfig.team && cliConfig.team.length > 0) {
73618
74200
  let prompt = cliConfig.claudeArgs.join(" ");
73619
74201
  if (cliConfig.inputFile) {
73620
- prompt = readFileSync23(cliConfig.inputFile, "utf-8");
74202
+ prompt = readFileSync25(cliConfig.inputFile, "utf-8");
73621
74203
  }
73622
74204
  if (!prompt.trim()) {
73623
74205
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
73624
74206
  process.exit(1);
73625
74207
  }
73626
74208
  const mode = cliConfig.teamMode ?? "default";
73627
- const sessionPath = join28(process.cwd(), `.claudish-team-${Date.now()}`);
74209
+ const sessionPath = join30(process.cwd(), `.claudish-team-${Date.now()}`);
73628
74210
  if (mode === "json") {
73629
74211
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
73630
74212
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -73634,9 +74216,9 @@ async function runCli() {
73634
74216
  });
73635
74217
  const result = { ...status2, responses: {} };
73636
74218
  for (const anonId of Object.keys(status2.models)) {
73637
- const responsePath = join28(sessionPath, `response-${anonId}.md`);
74219
+ const responsePath = join30(sessionPath, `response-${anonId}.md`);
73638
74220
  try {
73639
- const raw2 = readFileSync23(responsePath, "utf-8").trim();
74221
+ const raw2 = readFileSync25(responsePath, "utf-8").trim();
73640
74222
  try {
73641
74223
  result.responses[anonId] = JSON.parse(raw2);
73642
74224
  } catch {