claudish 7.24.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 +1715 -579
  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.24.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,
@@ -27006,6 +27196,9 @@ function loadConfig() {
27006
27196
  if (config2.customEndpoints !== undefined) {
27007
27197
  merged.customEndpoints = config2.customEndpoints;
27008
27198
  }
27199
+ if (config2.behavior !== undefined) {
27200
+ merged.behavior = config2.behavior;
27201
+ }
27009
27202
  return merged;
27010
27203
  } catch (error46) {
27011
27204
  console.error(`Warning: Failed to load config, using defaults: ${error46}`);
@@ -27024,26 +27217,26 @@ function getConfigPath() {
27024
27217
  return CONFIG_FILE;
27025
27218
  }
27026
27219
  function getLocalConfigPath() {
27027
- const home = homedir6();
27220
+ const home = homedir7();
27028
27221
  let dir = process.cwd();
27029
27222
  const root = parse6(dir).root;
27030
27223
  while (dir !== root && dir !== home) {
27031
- const candidate = join6(dir, LOCAL_CONFIG_FILENAME);
27224
+ const candidate = join7(dir, LOCAL_CONFIG_FILENAME);
27032
27225
  if (existsSync5(candidate))
27033
27226
  return candidate;
27034
- if (existsSync5(join6(dir, ".git"))) {
27227
+ if (existsSync5(join7(dir, ".git"))) {
27035
27228
  return candidate;
27036
27229
  }
27037
- dir = dirname3(dir);
27230
+ dir = dirname4(dir);
27038
27231
  }
27039
- return join6(process.cwd(), LOCAL_CONFIG_FILENAME);
27232
+ return join7(process.cwd(), LOCAL_CONFIG_FILENAME);
27040
27233
  }
27041
27234
  function localConfigExists() {
27042
27235
  return existsSync5(getLocalConfigPath());
27043
27236
  }
27044
27237
  function isProjectDirectory() {
27045
27238
  const cwd = process.cwd();
27046
- 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)));
27047
27240
  }
27048
27241
  function loadLocalConfig() {
27049
27242
  if (getConfigFileOverride())
@@ -27053,7 +27246,7 @@ function loadLocalConfig() {
27053
27246
  return null;
27054
27247
  }
27055
27248
  try {
27056
- const content = readFileSync4(localPath, "utf-8");
27249
+ const content = readFileSync5(localPath, "utf-8");
27057
27250
  const config2 = JSON.parse(content);
27058
27251
  return {
27059
27252
  ...config2,
@@ -27312,8 +27505,8 @@ function disableLocalProvider(providerName) {
27312
27505
  }
27313
27506
  var CONFIG_DIR, CONFIG_FILE, LOCAL_CONFIG_FILENAME = ".claudish.json", DEFAULT_CONFIG;
27314
27507
  var init_profile_config = __esm(() => {
27315
- CONFIG_DIR = join6(homedir6(), ".claudish");
27316
- CONFIG_FILE = join6(CONFIG_DIR, "config.json");
27508
+ CONFIG_DIR = join7(homedir7(), ".claudish");
27509
+ CONFIG_FILE = join7(CONFIG_DIR, "config.json");
27317
27510
  DEFAULT_CONFIG = {
27318
27511
  version: "1.0.0",
27319
27512
  defaultProfile: "default",
@@ -28040,8 +28233,8 @@ var init_provider_definitions = __esm(() => {
28040
28233
 
28041
28234
  // src/auth/credentials/api-key-credential.ts
28042
28235
  import { existsSync as existsSync6 } from "fs";
28043
- import { homedir as homedir7 } from "os";
28044
- import { join as join7 } from "path";
28236
+ import { homedir as homedir8 } from "os";
28237
+ import { join as join8 } from "path";
28045
28238
  function realValue(v) {
28046
28239
  if (!v)
28047
28240
  return;
@@ -28083,7 +28276,7 @@ class ApiKeyCredentialProvider {
28083
28276
  if (!this.oauthFallback)
28084
28277
  return false;
28085
28278
  try {
28086
- return existsSync6(join7(homedir7(), ".claudish", this.oauthFallback));
28279
+ return existsSync6(join8(homedir8(), ".claudish", this.oauthFallback));
28087
28280
  } catch {
28088
28281
  return false;
28089
28282
  }
@@ -28159,10 +28352,10 @@ var init_api_key_credential = __esm(() => {
28159
28352
  // src/auth/codex-oauth.ts
28160
28353
  import { exec } from "child_process";
28161
28354
  import { createHash as createHash2, randomBytes } from "crypto";
28162
- 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";
28163
28356
  import { createServer } from "http";
28164
- import { homedir as homedir8 } from "os";
28165
- import { join as join8 } from "path";
28357
+ import { homedir as homedir9 } from "os";
28358
+ import { join as join9 } from "path";
28166
28359
  import { promisify } from "util";
28167
28360
 
28168
28361
  class CodexOAuth {
@@ -28188,8 +28381,8 @@ class CodexOAuth {
28188
28381
  return this.credentials !== null && !!this.credentials.refresh_token;
28189
28382
  }
28190
28383
  getCredentialsPath() {
28191
- const claudishDir = join8(homedir8(), ".claudish");
28192
- return join8(claudishDir, "codex-oauth.json");
28384
+ const claudishDir = join9(homedir9(), ".claudish");
28385
+ return join9(claudishDir, "codex-oauth.json");
28193
28386
  }
28194
28387
  async login() {
28195
28388
  log("[CodexOAuth] Starting OAuth login flow");
@@ -28297,7 +28490,7 @@ Details: ${e.message}`);
28297
28490
  return null;
28298
28491
  }
28299
28492
  try {
28300
- const data = readFileSync5(credPath, "utf-8");
28493
+ const data = readFileSync6(credPath, "utf-8");
28301
28494
  const credentials = JSON.parse(data);
28302
28495
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
28303
28496
  log("[CodexOAuth] Invalid credentials file structure");
@@ -28312,17 +28505,17 @@ Details: ${e.message}`);
28312
28505
  }
28313
28506
  saveCredentials(credentials) {
28314
28507
  const credPath = this.getCredentialsPath();
28315
- const claudishDir = join8(homedir8(), ".claudish");
28508
+ const claudishDir = join9(homedir9(), ".claudish");
28316
28509
  if (!existsSync7(claudishDir)) {
28317
- const { mkdirSync: mkdirSync5 } = __require("fs");
28318
- mkdirSync5(claudishDir, { recursive: true });
28510
+ const { mkdirSync: mkdirSync6 } = __require("fs");
28511
+ mkdirSync6(claudishDir, { recursive: true });
28319
28512
  }
28320
- const fd = openSync(credPath, "w", 384);
28513
+ const fd = openSync2(credPath, "w", 384);
28321
28514
  try {
28322
28515
  const data = JSON.stringify(credentials, null, 2);
28323
- writeSync(fd, data, 0, "utf-8");
28516
+ writeSync2(fd, data, 0, "utf-8");
28324
28517
  } finally {
28325
- closeSync(fd);
28518
+ closeSync2(fd);
28326
28519
  }
28327
28520
  log(`[CodexOAuth] Credentials saved to ${credPath}`);
28328
28521
  }
@@ -28623,10 +28816,10 @@ var init_codex_credential = __esm(() => {
28623
28816
  // src/auth/gemini-oauth.ts
28624
28817
  import { exec as exec2 } from "child_process";
28625
28818
  import { createHash as createHash3, randomBytes as randomBytes2 } from "crypto";
28626
- 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";
28627
28820
  import { createServer as createServer2 } from "http";
28628
- import { homedir as homedir9 } from "os";
28629
- import { join as join9 } from "path";
28821
+ import { homedir as homedir10 } from "os";
28822
+ import { join as join10 } from "path";
28630
28823
  import { promisify as promisify2 } from "util";
28631
28824
 
28632
28825
  class GeminiOAuth {
@@ -28652,8 +28845,8 @@ class GeminiOAuth {
28652
28845
  return this.credentials !== null && !!this.credentials.refresh_token;
28653
28846
  }
28654
28847
  getCredentialsPath() {
28655
- const claudishDir = join9(homedir9(), ".claudish");
28656
- return join9(claudishDir, "gemini-oauth.json");
28848
+ const claudishDir = join10(homedir10(), ".claudish");
28849
+ return join10(claudishDir, "gemini-oauth.json");
28657
28850
  }
28658
28851
  async login() {
28659
28852
  log("[GeminiOAuth] Starting OAuth login flow");
@@ -28755,7 +28948,7 @@ Details: ${e.message}`);
28755
28948
  return null;
28756
28949
  }
28757
28950
  try {
28758
- const data = readFileSync6(credPath, "utf-8");
28951
+ const data = readFileSync7(credPath, "utf-8");
28759
28952
  const credentials = JSON.parse(data);
28760
28953
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at) {
28761
28954
  log("[GeminiOAuth] Invalid credentials file structure");
@@ -28770,17 +28963,17 @@ Details: ${e.message}`);
28770
28963
  }
28771
28964
  saveCredentials(credentials) {
28772
28965
  const credPath = this.getCredentialsPath();
28773
- const claudishDir = join9(homedir9(), ".claudish");
28966
+ const claudishDir = join10(homedir10(), ".claudish");
28774
28967
  if (!existsSync8(claudishDir)) {
28775
- const { mkdirSync: mkdirSync5 } = __require("fs");
28776
- mkdirSync5(claudishDir, { recursive: true });
28968
+ const { mkdirSync: mkdirSync6 } = __require("fs");
28969
+ mkdirSync6(claudishDir, { recursive: true });
28777
28970
  }
28778
- const fd = openSync2(credPath, "w", 384);
28971
+ const fd = openSync3(credPath, "w", 384);
28779
28972
  try {
28780
28973
  const data = JSON.stringify(credentials, null, 2);
28781
- writeSync2(fd, data, 0, "utf-8");
28974
+ writeSync3(fd, data, 0, "utf-8");
28782
28975
  } finally {
28783
- closeSync2(fd);
28976
+ closeSync3(fd);
28784
28977
  }
28785
28978
  log(`[GeminiOAuth] Credentials saved to ${credPath}`);
28786
28979
  }
@@ -29134,18 +29327,18 @@ var init_gemini_oauth = __esm(() => {
29134
29327
  });
29135
29328
 
29136
29329
  // src/auth/oauth-registry.ts
29137
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
29138
- import { homedir as homedir10 } from "os";
29139
- 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";
29140
29333
  function hasValidOAuthCredentials(descriptor) {
29141
- const credPath = join10(homedir10(), ".claudish", descriptor.credentialFile);
29334
+ const credPath = join11(homedir11(), ".claudish", descriptor.credentialFile);
29142
29335
  if (!existsSync9(credPath))
29143
29336
  return false;
29144
29337
  if (descriptor.validationMode === "file-exists") {
29145
29338
  return true;
29146
29339
  }
29147
29340
  try {
29148
- const data = JSON.parse(readFileSync7(credPath, "utf-8"));
29341
+ const data = JSON.parse(readFileSync8(credPath, "utf-8"));
29149
29342
  if (!data.access_token)
29150
29343
  return false;
29151
29344
  if (data.refresh_token)
@@ -29255,9 +29448,9 @@ var init_gemini_credential = __esm(() => {
29255
29448
  // src/auth/kimi-oauth.ts
29256
29449
  import { exec as exec3 } from "child_process";
29257
29450
  import { randomBytes as randomBytes3 } from "crypto";
29258
- import { closeSync as closeSync3, existsSync as existsSync10, openSync as openSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync4, writeSync as writeSync3 } from "fs";
29259
- import { homedir as homedir11, hostname as hostname3, platform, release } from "os";
29260
- 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";
29261
29454
  import { promisify as promisify3 } from "util";
29262
29455
 
29263
29456
  class KimiOAuth {
@@ -29285,23 +29478,23 @@ class KimiOAuth {
29285
29478
  return this.credentials !== null && !!this.credentials.refresh_token;
29286
29479
  }
29287
29480
  getCredentialsPath() {
29288
- const claudishDir = join11(homedir11(), ".claudish");
29289
- return join11(claudishDir, "kimi-oauth.json");
29481
+ const claudishDir = join12(homedir12(), ".claudish");
29482
+ return join12(claudishDir, "kimi-oauth.json");
29290
29483
  }
29291
29484
  getDeviceIdPath() {
29292
- const claudishDir = join11(homedir11(), ".claudish");
29293
- return join11(claudishDir, "kimi-device-id");
29485
+ const claudishDir = join12(homedir12(), ".claudish");
29486
+ return join12(claudishDir, "kimi-device-id");
29294
29487
  }
29295
29488
  loadOrCreateDeviceId() {
29296
29489
  const deviceIdPath = this.getDeviceIdPath();
29297
- const claudishDir = join11(homedir11(), ".claudish");
29490
+ const claudishDir = join12(homedir12(), ".claudish");
29298
29491
  if (!existsSync10(claudishDir)) {
29299
- const { mkdirSync: mkdirSync5 } = __require("fs");
29300
- mkdirSync5(claudishDir, { recursive: true });
29492
+ const { mkdirSync: mkdirSync6 } = __require("fs");
29493
+ mkdirSync6(claudishDir, { recursive: true });
29301
29494
  }
29302
29495
  if (existsSync10(deviceIdPath)) {
29303
29496
  try {
29304
- const deviceId2 = readFileSync8(deviceIdPath, "utf-8").trim();
29497
+ const deviceId2 = readFileSync9(deviceIdPath, "utf-8").trim();
29305
29498
  if (deviceId2) {
29306
29499
  return deviceId2;
29307
29500
  }
@@ -29311,11 +29504,11 @@ class KimiOAuth {
29311
29504
  }
29312
29505
  const deviceId = randomBytes3(16).toString("hex").replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5");
29313
29506
  try {
29314
- const fd = openSync3(deviceIdPath, "w", 384);
29507
+ const fd = openSync4(deviceIdPath, "w", 384);
29315
29508
  try {
29316
- writeSync3(fd, deviceId, 0, "utf-8");
29509
+ writeSync4(fd, deviceId, 0, "utf-8");
29317
29510
  } finally {
29318
- closeSync3(fd);
29511
+ closeSync4(fd);
29319
29512
  }
29320
29513
  log(`[KimiOAuth] New device ID created: ${deviceId}`);
29321
29514
  } catch (e) {
@@ -29332,7 +29525,7 @@ class KimiOAuth {
29332
29525
  "X-Msh-Version": this.getVersion(),
29333
29526
  "X-Msh-Device-Name": hostname3(),
29334
29527
  "X-Msh-Device-Model": `${platform()}-${process.arch}`,
29335
- "X-Msh-Os-Version": release(),
29528
+ "X-Msh-Os-Version": release2(),
29336
29529
  "X-Msh-Device-Id": this.deviceId
29337
29530
  };
29338
29531
  }
@@ -29560,7 +29753,7 @@ Details: ${e.message}`);
29560
29753
  return null;
29561
29754
  }
29562
29755
  try {
29563
- const data = readFileSync8(credPath, "utf-8");
29756
+ const data = readFileSync9(credPath, "utf-8");
29564
29757
  const credentials = JSON.parse(data);
29565
29758
  if (!credentials.access_token || !credentials.refresh_token || !credentials.expires_at || !credentials.scope || !credentials.token_type) {
29566
29759
  log("[KimiOAuth] Invalid credentials file structure");
@@ -29575,17 +29768,17 @@ Details: ${e.message}`);
29575
29768
  }
29576
29769
  saveCredentials(credentials) {
29577
29770
  const credPath = this.getCredentialsPath();
29578
- const claudishDir = join11(homedir11(), ".claudish");
29771
+ const claudishDir = join12(homedir12(), ".claudish");
29579
29772
  if (!existsSync10(claudishDir)) {
29580
- const { mkdirSync: mkdirSync5 } = __require("fs");
29581
- mkdirSync5(claudishDir, { recursive: true });
29773
+ const { mkdirSync: mkdirSync6 } = __require("fs");
29774
+ mkdirSync6(claudishDir, { recursive: true });
29582
29775
  }
29583
- const fd = openSync3(credPath, "w", 384);
29776
+ const fd = openSync4(credPath, "w", 384);
29584
29777
  try {
29585
29778
  const data = JSON.stringify(credentials, null, 2);
29586
- writeSync3(fd, data, 0, "utf-8");
29779
+ writeSync4(fd, data, 0, "utf-8");
29587
29780
  } finally {
29588
- closeSync3(fd);
29781
+ closeSync4(fd);
29589
29782
  }
29590
29783
  log(`[KimiOAuth] Credentials saved to ${credPath}`);
29591
29784
  }
@@ -29751,8 +29944,8 @@ var init_native_anthropic_credential = __esm(() => {
29751
29944
  // src/auth/vertex-auth.ts
29752
29945
  import { exec as exec4 } from "child_process";
29753
29946
  import { existsSync as existsSync11 } from "fs";
29754
- import { homedir as homedir12 } from "os";
29755
- import { join as join12 } from "path";
29947
+ import { homedir as homedir13 } from "os";
29948
+ import { join as join13 } from "path";
29756
29949
  import { promisify as promisify4 } from "util";
29757
29950
 
29758
29951
  class VertexAuthManager {
@@ -29807,7 +30000,7 @@ class VertexAuthManager {
29807
30000
  }
29808
30001
  async tryADC() {
29809
30002
  try {
29810
- const adcPath = join12(homedir12(), ".config/gcloud/application_default_credentials.json");
30003
+ const adcPath = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
29811
30004
  if (!existsSync11(adcPath)) {
29812
30005
  log("[VertexAuth] ADC credentials file not found");
29813
30006
  return null;
@@ -29871,7 +30064,7 @@ function validateVertexOAuthConfig() {
29871
30064
  ` + ` export VERTEX_PROJECT='your-gcp-project-id'
29872
30065
  ` + " export VERTEX_LOCATION='us-central1' # optional";
29873
30066
  }
29874
- const adcPath = join12(homedir12(), ".config/gcloud/application_default_credentials.json");
30067
+ const adcPath = join13(homedir13(), ".config/gcloud/application_default_credentials.json");
29875
30068
  const hasADC = existsSync11(adcPath);
29876
30069
  const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
29877
30070
  if (!hasADC && !hasServiceAccount) {
@@ -30419,15 +30612,15 @@ var init_routing_hints = __esm(() => {
30419
30612
  });
30420
30613
 
30421
30614
  // src/providers/all-models-cache.ts
30422
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
30423
- import { homedir as homedir13 } from "os";
30424
- 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";
30425
30618
  function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
30426
30619
  if (!existsSync12(path))
30427
30620
  return null;
30428
30621
  let raw;
30429
30622
  try {
30430
- raw = JSON.parse(readFileSync9(path, "utf-8"));
30623
+ raw = JSON.parse(readFileSync10(path, "utf-8"));
30431
30624
  } catch {
30432
30625
  return null;
30433
30626
  }
@@ -30452,12 +30645,12 @@ function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
30452
30645
  entries: data.entries ?? existing?.entries ?? [],
30453
30646
  models: data.models ?? existing?.models ?? []
30454
30647
  };
30455
- mkdirSync5(dirname4(path), { recursive: true });
30648
+ mkdirSync6(dirname5(path), { recursive: true });
30456
30649
  writeFileSync6(path, JSON.stringify(merged), "utf-8");
30457
30650
  }
30458
30651
  var ALL_MODELS_CACHE_PATH;
30459
30652
  var init_all_models_cache = __esm(() => {
30460
- ALL_MODELS_CACHE_PATH = join13(homedir13(), ".claudish", "all-models.json");
30653
+ ALL_MODELS_CACHE_PATH = join14(homedir14(), ".claudish", "all-models.json");
30461
30654
  });
30462
30655
 
30463
30656
  // src/adapters/model-catalog.ts
@@ -31284,10 +31477,21 @@ async function prehydrateCredentialsForSpawn(models) {
31284
31477
  return;
31285
31478
  try {
31286
31479
  await validateApiKeysForModels(wanted);
31480
+ publishOpSkipList();
31287
31481
  } catch {}
31288
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
+ }
31289
31491
  var init_prehydrate = __esm(() => {
31492
+ init_onepassword();
31290
31493
  init_provider_resolver();
31494
+ init_op_source();
31291
31495
  });
31292
31496
 
31293
31497
  // src/channel/diagnostics.ts
@@ -31542,9 +31746,9 @@ var init_signal_watcher = __esm(() => {
31542
31746
  // src/channel/session-manager.ts
31543
31747
  import { spawn } from "child_process";
31544
31748
  import { randomUUID as randomUUID2 } from "crypto";
31545
- import { createWriteStream, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
31546
- import { homedir as homedir14 } from "os";
31547
- 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";
31548
31752
 
31549
31753
  class SessionManager {
31550
31754
  sessions = new Map;
@@ -31564,10 +31768,10 @@ class SessionManager {
31564
31768
  const sessionId = randomUUID2().slice(0, 8);
31565
31769
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
31566
31770
  const startedAt = new Date().toISOString();
31567
- const sessionDir = join14(homedir14(), ".claudish", "sessions", sessionId);
31568
- mkdirSync6(sessionDir, { recursive: true });
31771
+ const sessionDir = join15(homedir15(), ".claudish", "sessions", sessionId);
31772
+ mkdirSync7(sessionDir, { recursive: true });
31569
31773
  if (opts.prompt) {
31570
- writeFileSync7(join14(sessionDir, "prompt.md"), opts.prompt, "utf-8");
31774
+ writeFileSync7(join15(sessionDir, "prompt.md"), opts.prompt, "utf-8");
31571
31775
  }
31572
31776
  const args = ["--model", opts.model, "-y", "--stdin", "--quiet", ...opts.claudishFlags ?? []];
31573
31777
  const proc = spawn("claudish", args, {
@@ -31594,7 +31798,7 @@ class SessionManager {
31594
31798
  });
31595
31799
  }
31596
31800
  });
31597
- const outputLogStream = createWriteStream(join14(sessionDir, "output.log"));
31801
+ const outputLogStream = createWriteStream(join15(sessionDir, "output.log"));
31598
31802
  const entry = {
31599
31803
  info: {
31600
31804
  sessionId,
@@ -31641,9 +31845,9 @@ class SessionManager {
31641
31845
  watcher.processExited(code);
31642
31846
  outputLogStream.end();
31643
31847
  if (entry.stderr) {
31644
- writeFileSync7(join14(sessionDir, "stderr.log"), entry.stderr, "utf-8");
31848
+ writeFileSync7(join15(sessionDir, "stderr.log"), entry.stderr, "utf-8");
31645
31849
  }
31646
- 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");
31647
31851
  this.cleanupSigint();
31648
31852
  });
31649
31853
  proc.on("error", (err) => {
@@ -31816,9 +32020,9 @@ var init_cache_ttl = __esm(() => {
31816
32020
  });
31817
32021
 
31818
32022
  // src/model-loader.ts
31819
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
31820
- import { homedir as homedir15 } from "os";
31821
- 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";
31822
32026
  function groupRecommendedModels(entries) {
31823
32027
  const byId = new Map;
31824
32028
  for (const entry of entries) {
@@ -31916,7 +32120,7 @@ async function getRecommendedModels(opts = {}) {
31916
32120
  }
31917
32121
  if (!forceRefresh && existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
31918
32122
  try {
31919
- const cacheData = JSON.parse(readFileSync10(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
32123
+ const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
31920
32124
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
31921
32125
  _cachedRecommendedModels = cacheData;
31922
32126
  return cacheData;
@@ -31932,8 +32136,8 @@ async function getRecommendedModels(opts = {}) {
31932
32136
  if (data.models && data.models.length > 0) {
31933
32137
  _cachedRecommendedModels = data;
31934
32138
  try {
31935
- const cacheDir = join15(homedir15(), ".claudish");
31936
- mkdirSync7(cacheDir, { recursive: true });
32139
+ const cacheDir = join16(homedir16(), ".claudish");
32140
+ mkdirSync8(cacheDir, { recursive: true });
31937
32141
  writeFileSync8(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
31938
32142
  } catch {}
31939
32143
  return data;
@@ -31947,7 +32151,7 @@ function getRecommendedModelsSync() {
31947
32151
  return _cachedRecommendedModels;
31948
32152
  if (existsSync13(RECOMMENDED_MODELS_CACHE_PATH)) {
31949
32153
  try {
31950
- const cacheData = JSON.parse(readFileSync10(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
32154
+ const cacheData = JSON.parse(readFileSync11(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
31951
32155
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
31952
32156
  _cachedRecommendedModels = cacheData;
31953
32157
  return cacheData;
@@ -32071,7 +32275,7 @@ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels =
32071
32275
  var init_model_loader = __esm(() => {
32072
32276
  init_cache_ttl();
32073
32277
  FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
32074
- RECOMMENDED_MODELS_CACHE_PATH = join15(homedir15(), ".claudish", "recommended-models-cache.json");
32278
+ RECOMMENDED_MODELS_CACHE_PATH = join16(homedir16(), ".claudish", "recommended-models-cache.json");
32075
32279
  FIREBASE_SLUG_TO_PROVIDER_NAME = {
32076
32280
  openai: "openai",
32077
32281
  google: "google",
@@ -32119,6 +32323,44 @@ async function isPortAvailable(port) {
32119
32323
  }
32120
32324
  var init_port_manager = () => {};
32121
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
+
32122
32364
  // ../../node_modules/.bun/hono@4.10.6/node_modules/hono/dist/compose.js
32123
32365
  var compose = (middleware, onError, onNotFound) => {
32124
32366
  return (context, next) => {
@@ -34112,9 +34354,12 @@ function transformOpenAIToClaude(claudeRequestInput) {
34112
34354
  var init_transform = () => {};
34113
34355
 
34114
34356
  // src/handlers/shared/format/openai-tools.ts
34357
+ function emptyParamsSchema() {
34358
+ return { type: "object", properties: {} };
34359
+ }
34115
34360
  function sanitizeSchemaForOpenAI(schema) {
34116
34361
  if (!schema || typeof schema !== "object") {
34117
- return removeUriFormat(schema);
34362
+ return emptyParamsSchema();
34118
34363
  }
34119
34364
  let root = { ...schema };
34120
34365
  const combinerKey = ["oneOf", "anyOf", "allOf"].find((k) => Array.isArray(root[k]) && root[k].length > 0);
@@ -34156,8 +34401,8 @@ function summarizeToolDescription(name, description) {
34156
34401
  return firstSentence;
34157
34402
  }
34158
34403
  function summarizeToolParameters(schema) {
34159
- if (!schema)
34160
- return schema;
34404
+ if (!schema || typeof schema !== "object")
34405
+ return emptyParamsSchema();
34161
34406
  const summarized = sanitizeSchemaForOpenAI({ ...schema });
34162
34407
  if (summarized.properties) {
34163
34408
  for (const prop of Object.values(summarized.properties)) {
@@ -36790,6 +37035,555 @@ ${text}`;
36790
37035
  };
36791
37036
  });
36792
37037
 
37038
+ // ../../node_modules/.bun/zod@4.1.13/node_modules/zod/index.js
37039
+ var init_zod = __esm(() => {
37040
+ init_external2();
37041
+ init_external2();
37042
+ });
37043
+
37044
+ // src/behavior/config.ts
37045
+ function parseBehaviorConfig(raw2) {
37046
+ if (raw2 === undefined || raw2 === null)
37047
+ return {};
37048
+ const result = BehaviorConfigSchema.safeParse(raw2);
37049
+ if (!result.success) {
37050
+ logStderr(`[behavior] Ignoring invalid "behavior" config: ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
37051
+ return {};
37052
+ }
37053
+ return result.data;
37054
+ }
37055
+ function resolveSeverity(ruleId, defaultSeverity, config2) {
37056
+ const rules = config2.rules;
37057
+ if (!rules)
37058
+ return defaultSeverity;
37059
+ const exact = rules[ruleId];
37060
+ if (exact)
37061
+ return exact;
37062
+ let best = null;
37063
+ for (const [pattern, severity] of Object.entries(rules)) {
37064
+ if (!pattern.includes("*"))
37065
+ continue;
37066
+ if (!globMatches(pattern, ruleId))
37067
+ continue;
37068
+ const len = pattern.replace(/\*/g, "").length;
37069
+ if (!best || len > best.len)
37070
+ best = { len, severity };
37071
+ }
37072
+ return best ? best.severity : defaultSeverity;
37073
+ }
37074
+ function globMatches(pattern, value) {
37075
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
37076
+ return new RegExp(`^${escaped}$`).test(value);
37077
+ }
37078
+ var SeveritySchema, BehaviorConfigSchema;
37079
+ var init_config = __esm(() => {
37080
+ init_zod();
37081
+ init_logger();
37082
+ SeveritySchema = exports_external.enum(["off", "warn", "fix"]);
37083
+ BehaviorConfigSchema = exports_external.object({
37084
+ preset: exports_external.string().optional(),
37085
+ rules: exports_external.record(exports_external.string(), SeveritySchema).optional(),
37086
+ hooks: exports_external.array(exports_external.string()).optional(),
37087
+ observer: exports_external.object({
37088
+ enabled: exports_external.boolean().optional(),
37089
+ mode: exports_external.enum(["off", "suggest", "enforce"]).optional(),
37090
+ model: exports_external.string().optional(),
37091
+ timeoutMs: exports_external.number().int().positive().optional()
37092
+ }).optional()
37093
+ });
37094
+ });
37095
+
37096
+ // src/behavior/harness.ts
37097
+ function textOf(value) {
37098
+ if (!value)
37099
+ return "";
37100
+ if (typeof value === "string")
37101
+ return value;
37102
+ if (Array.isArray(value)) {
37103
+ let out = "";
37104
+ for (const part of value) {
37105
+ if (typeof part === "string")
37106
+ out += part;
37107
+ else if (typeof part?.text === "string")
37108
+ out += part.text;
37109
+ else if (typeof part?.content === "string")
37110
+ out += part.content;
37111
+ }
37112
+ return out;
37113
+ }
37114
+ if (typeof value?.text === "string")
37115
+ return value.text;
37116
+ return "";
37117
+ }
37118
+ function matchPlanPath(text) {
37119
+ if (!PLAN_MODE_HINT.test(text))
37120
+ return;
37121
+ for (const re of PLAN_PATH_PATTERNS) {
37122
+ const m = re.exec(text);
37123
+ if (m?.[1])
37124
+ return m[1];
37125
+ }
37126
+ return;
37127
+ }
37128
+ function detectHarnessFacts(claudeRequest) {
37129
+ const facts = { planModeActive: false };
37130
+ let planPath = matchPlanPath(textOf(claudeRequest?.system));
37131
+ if (!planPath && Array.isArray(claudeRequest?.messages)) {
37132
+ const messages = claudeRequest.messages;
37133
+ for (let i = messages.length - 1;i >= 0; i--) {
37134
+ planPath = matchPlanPath(textOf(messages[i]?.content));
37135
+ if (planPath)
37136
+ break;
37137
+ }
37138
+ }
37139
+ if (planPath) {
37140
+ facts.planModeActive = true;
37141
+ facts.planFilePath = planPath;
37142
+ const slash = planPath.lastIndexOf("/");
37143
+ if (slash > 0)
37144
+ facts.planDir = planPath.slice(0, slash);
37145
+ }
37146
+ return facts;
37147
+ }
37148
+ var PLAN_PATH_PATTERNS, PLAN_MODE_HINT;
37149
+ var init_harness = __esm(() => {
37150
+ PLAN_PATH_PATTERNS = [
37151
+ /You should create your plan at\s+(\S+?\.md)/,
37152
+ /A plan file already exists at\s+(\S+?\.md)/,
37153
+ /Read-only except plan file\s*\(([^)]+\.md)\)/
37154
+ ];
37155
+ PLAN_MODE_HINT = /plan file|create your plan at|Plan mode is active|Plan mode still active/i;
37156
+ });
37157
+
37158
+ // src/behavior/engine.ts
37159
+ class BehaviorSession {
37160
+ active;
37161
+ modelId;
37162
+ providerName;
37163
+ facts = { planModeActive: false };
37164
+ bufferedTools = new Set;
37165
+ constructor(active, modelId, providerName) {
37166
+ this.active = active;
37167
+ this.modelId = modelId;
37168
+ this.providerName = providerName;
37169
+ }
37170
+ armBuffering() {
37171
+ const armed = new Set;
37172
+ for (const { rule, severity } of this.active) {
37173
+ if (severity !== "fix")
37174
+ continue;
37175
+ if (rule.armed && !rule.armed(this.facts))
37176
+ continue;
37177
+ for (const t of rule.interceptsTools ?? [])
37178
+ armed.add(t);
37179
+ }
37180
+ this.bufferedTools = armed;
37181
+ }
37182
+ get harness() {
37183
+ return this.facts;
37184
+ }
37185
+ get isNoop() {
37186
+ return this.active.length === 0;
37187
+ }
37188
+ applyRequest(claudeRequest, claudeTools, tools, messages) {
37189
+ if (this.active.length === 0)
37190
+ return;
37191
+ this.facts = detectHarnessFacts(claudeRequest);
37192
+ this.armBuffering();
37193
+ const ctx = {
37194
+ modelId: this.modelId,
37195
+ providerName: this.providerName,
37196
+ isNativeAnthropic: false,
37197
+ claudeRequest,
37198
+ claudeTools,
37199
+ tools,
37200
+ messages,
37201
+ harness: this.facts
37202
+ };
37203
+ for (const { rule, severity } of this.active) {
37204
+ if (!rule.onRequest)
37205
+ continue;
37206
+ let actions = [];
37207
+ try {
37208
+ actions = rule.onRequest(ctx) ?? [];
37209
+ } catch (err) {
37210
+ log(`[behavior] rule ${rule.id} onRequest threw: ${err}`);
37211
+ continue;
37212
+ }
37213
+ for (const action of actions)
37214
+ this.applyAction(rule.id, severity, action, ctx);
37215
+ }
37216
+ }
37217
+ interceptsTool(toolName) {
37218
+ return this.bufferedTools.has(toolName);
37219
+ }
37220
+ repairToolCall(toolName, rawArgs) {
37221
+ if (!this.bufferedTools.has(toolName))
37222
+ return null;
37223
+ let args = {};
37224
+ try {
37225
+ const parsed = JSON.parse(rawArgs || "{}");
37226
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
37227
+ args = parsed;
37228
+ } catch {
37229
+ return null;
37230
+ }
37231
+ let changed = false;
37232
+ for (const { rule, severity } of this.active) {
37233
+ if (!rule.onToolCall)
37234
+ continue;
37235
+ if (!(rule.interceptsTools ?? []).includes(toolName))
37236
+ continue;
37237
+ let actions = [];
37238
+ try {
37239
+ actions = rule.onToolCall({
37240
+ modelId: this.modelId,
37241
+ toolName,
37242
+ args,
37243
+ rawArgs,
37244
+ harness: this.facts
37245
+ }) ?? [];
37246
+ } catch (err) {
37247
+ log(`[behavior] rule ${rule.id} onToolCall threw: ${err}`);
37248
+ continue;
37249
+ }
37250
+ for (const action of actions) {
37251
+ if (action.type === "warn") {
37252
+ log(`[behavior] ${rule.id} (warn): ${action.message}`);
37253
+ continue;
37254
+ }
37255
+ if (action.type !== "repairToolArgs")
37256
+ continue;
37257
+ if (severity !== "fix") {
37258
+ log(`[behavior] ${rule.id} (warn-only, not applied): ${action.reason}`);
37259
+ continue;
37260
+ }
37261
+ args = action.args;
37262
+ changed = true;
37263
+ log(`[behavior] ${rule.id} repaired ${toolName}: ${action.reason}`);
37264
+ }
37265
+ }
37266
+ return changed ? JSON.stringify(args) : null;
37267
+ }
37268
+ applyAction(ruleId, severity, action, ctx) {
37269
+ if (action.type === "warn") {
37270
+ log(`[behavior] ${ruleId} (warn): ${action.message}`);
37271
+ return;
37272
+ }
37273
+ if (severity !== "fix") {
37274
+ log(`[behavior] ${ruleId} (warn-only, not applied): ${action.type}`);
37275
+ return;
37276
+ }
37277
+ switch (action.type) {
37278
+ case "injectSystemNote": {
37279
+ const req = ctx.claudeRequest;
37280
+ if (typeof req.system === "string") {
37281
+ req.system = `${req.system}
37282
+
37283
+ ${action.text}`;
37284
+ } else if (Array.isArray(req.system)) {
37285
+ req.system.push({ type: "text", text: action.text });
37286
+ } else {
37287
+ req.system = action.text;
37288
+ }
37289
+ log(`[behavior] ${ruleId} injected system note (${action.text.length} chars)`);
37290
+ break;
37291
+ }
37292
+ case "rewriteToolDescription": {
37293
+ let hits = 0;
37294
+ for (const t of ctx.claudeTools) {
37295
+ if (t?.name !== action.tool)
37296
+ continue;
37297
+ t.description = `${t.description ?? ""}${action.append}`;
37298
+ hits++;
37299
+ }
37300
+ for (const t of ctx.tools) {
37301
+ const fn = t?.function ?? t;
37302
+ if (fn?.name !== action.tool)
37303
+ continue;
37304
+ fn.description = `${fn.description ?? ""}${action.append}`;
37305
+ hits++;
37306
+ }
37307
+ log(`[behavior] ${ruleId} rewrote description of ${action.tool} (${hits} site(s))`);
37308
+ break;
37309
+ }
37310
+ case "repairToolArgs":
37311
+ log(`[behavior] ${ruleId} returned repairToolArgs from onRequest \u2014 ignored`);
37312
+ break;
37313
+ }
37314
+ }
37315
+ }
37316
+
37317
+ class BehaviorEngine {
37318
+ config;
37319
+ rules;
37320
+ constructor(config2, rules) {
37321
+ this.config = config2;
37322
+ this.rules = rules;
37323
+ }
37324
+ startSession(params) {
37325
+ const active = [];
37326
+ if (!params.isNativeAnthropic) {
37327
+ for (const rule of this.rules) {
37328
+ const severity = resolveSeverity(rule.id, rule.defaultSeverity, this.config);
37329
+ if (severity === "off")
37330
+ continue;
37331
+ let applies = false;
37332
+ try {
37333
+ applies = rule.appliesTo(params);
37334
+ } catch (err) {
37335
+ log(`[behavior] rule ${rule.id} appliesTo threw: ${err}`);
37336
+ continue;
37337
+ }
37338
+ if (applies)
37339
+ active.push({ rule, severity });
37340
+ }
37341
+ }
37342
+ if (active.length > 0) {
37343
+ log(`[behavior] ${active.length} rule(s) active for ${params.modelId}: ` + active.map((a) => `${a.rule.id}=${a.severity}`).join(", "));
37344
+ }
37345
+ return new BehaviorSession(active, params.modelId, params.providerName);
37346
+ }
37347
+ }
37348
+ var init_engine = __esm(() => {
37349
+ init_logger();
37350
+ init_config();
37351
+ init_harness();
37352
+ });
37353
+
37354
+ // src/behavior/rules/plan-mode.ts
37355
+ function directoryOf(filePath) {
37356
+ const slash = filePath.lastIndexOf("/");
37357
+ return slash > 0 ? filePath.slice(0, slash) : undefined;
37358
+ }
37359
+ var WRITE_TOOLS, planFilePathRule, PLAN_MODE_RULES;
37360
+ var init_plan_mode = __esm(() => {
37361
+ WRITE_TOOLS = ["Write", "Edit", "NotebookEdit"];
37362
+ planFilePathRule = {
37363
+ id: "plan-mode/plan-file-path",
37364
+ description: "Keep plan-mode writes on the plan file Claude Code assigned, and name that " + "path in the ExitPlanMode description.",
37365
+ defaultSeverity: "fix",
37366
+ interceptsTools: WRITE_TOOLS,
37367
+ appliesTo: ({ isNativeAnthropic }) => !isNativeAnthropic,
37368
+ armed: (facts) => facts.planModeActive === true,
37369
+ onRequest(ctx) {
37370
+ const { planModeActive, planFilePath } = ctx.harness;
37371
+ if (!planModeActive || !planFilePath)
37372
+ return [];
37373
+ const hasExitPlanMode = ctx.claudeTools.some((t) => t?.name === "ExitPlanMode") || ctx.tools.some((t) => (t?.function ?? t)?.name === "ExitPlanMode");
37374
+ if (!hasExitPlanMode)
37375
+ return [];
37376
+ return [
37377
+ {
37378
+ type: "rewriteToolDescription",
37379
+ tool: "ExitPlanMode",
37380
+ append: `
37381
+
37382
+ ## Plan file for THIS session
37383
+ Your plan MUST be written to exactly this path:
37384
+ ${planFilePath}
37385
+ Do not invent a different filename, and do not derive one from the task. Claude Code reads only that exact path; a plan written anywhere else is invisible to it and the approval will show "No plan found".`
37386
+ }
37387
+ ];
37388
+ },
37389
+ onToolCall(ctx) {
37390
+ const { planFilePath, planDir } = ctx.harness;
37391
+ if (!planFilePath || !planDir)
37392
+ return [];
37393
+ const filePath = ctx.args.file_path;
37394
+ if (typeof filePath !== "string" || filePath === planFilePath)
37395
+ return [];
37396
+ if (directoryOf(filePath) !== planDir)
37397
+ return [];
37398
+ return [
37399
+ {
37400
+ type: "repairToolArgs",
37401
+ args: { ...ctx.args, file_path: planFilePath },
37402
+ reason: `redirected ${ctx.toolName} from ${filePath} to the session's assigned ` + `plan file ${planFilePath}`
37403
+ }
37404
+ ];
37405
+ }
37406
+ };
37407
+ PLAN_MODE_RULES = [planFilePathRule];
37408
+ });
37409
+
37410
+ // src/behavior/hooks.ts
37411
+ import { isAbsolute, resolve } from "path";
37412
+ function isBehaviorRule(value) {
37413
+ return !!value && typeof value === "object" && typeof value.id === "string" && value.id.length > 0 && typeof value.appliesTo === "function" && (value.onRequest === undefined || typeof value.onRequest === "function") && (value.onToolCall === undefined || typeof value.onToolCall === "function");
37414
+ }
37415
+ function collectRules(mod) {
37416
+ const found = [];
37417
+ const consider = (v) => {
37418
+ if (Array.isArray(v))
37419
+ v.forEach(consider);
37420
+ else if (isBehaviorRule(v))
37421
+ found.push(v);
37422
+ };
37423
+ consider(mod?.default);
37424
+ consider(mod?.rules);
37425
+ for (const [key, value] of Object.entries(mod ?? {})) {
37426
+ if (key === "default" || key === "rules")
37427
+ continue;
37428
+ consider(value);
37429
+ }
37430
+ return [...new Set(found)];
37431
+ }
37432
+ function shortName(path) {
37433
+ const base = path.split("/").pop() ?? path;
37434
+ return base.replace(/\.[cm]?[jt]s$/, "");
37435
+ }
37436
+ async function loadHookRules(paths, cwd = process.cwd()) {
37437
+ if (!paths?.length)
37438
+ return [];
37439
+ const loaded = [];
37440
+ const seen = new Set;
37441
+ for (const raw2 of paths) {
37442
+ const abs = isAbsolute(raw2) ? raw2 : resolve(cwd, raw2);
37443
+ const rules = await importHook(abs, raw2);
37444
+ for (const rule of rules)
37445
+ namespaceInto(rule, abs, seen, loaded);
37446
+ }
37447
+ if (loaded.length > 0) {
37448
+ logStderr(`[behavior] Loaded ${loaded.length} hook rule(s): ${loaded.map((r) => r.id).join(", ")}`);
37449
+ }
37450
+ return loaded;
37451
+ }
37452
+ async function importHook(abs, raw2) {
37453
+ let mod;
37454
+ try {
37455
+ mod = await import(abs);
37456
+ } catch (err) {
37457
+ logStderr(`[behavior] Skipping hook ${raw2}: ${err instanceof Error ? err.message : err}`);
37458
+ return [];
37459
+ }
37460
+ const rules = collectRules(mod);
37461
+ if (rules.length === 0) {
37462
+ logStderr(`[behavior] Hook ${raw2} exported no valid BehaviorRule \u2014 skipped`);
37463
+ }
37464
+ return rules;
37465
+ }
37466
+ function namespaceInto(rule, abs, seen, out) {
37467
+ const namespaced = `hook:${shortName(abs)}/${rule.id}`;
37468
+ if (seen.has(namespaced)) {
37469
+ logStderr(`[behavior] Duplicate hook rule ${namespaced} \u2014 keeping the first`);
37470
+ return;
37471
+ }
37472
+ seen.add(namespaced);
37473
+ out.push({
37474
+ ...rule,
37475
+ id: namespaced,
37476
+ defaultSeverity: rule.defaultSeverity ?? "warn"
37477
+ });
37478
+ }
37479
+ var init_hooks = __esm(() => {
37480
+ init_logger();
37481
+ });
37482
+
37483
+ // src/behavior/observer/digest.ts
37484
+ var PATH_KEYS;
37485
+ var init_digest = __esm(() => {
37486
+ PATH_KEYS = new Set(["file_path", "path", "notebook_path", "filePath"]);
37487
+ });
37488
+
37489
+ // src/providers/ollama-discovery.ts
37490
+ function ollamaBaseUrl() {
37491
+ return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
37492
+ }
37493
+ async function fetchOllamaModels(options = {}) {
37494
+ const { enrichCapabilities = true } = options;
37495
+ const host = ollamaBaseUrl();
37496
+ try {
37497
+ const response = await fetch(`${host}/api/tags`, {
37498
+ signal: AbortSignal.timeout(3000)
37499
+ });
37500
+ if (!response.ok)
37501
+ return [];
37502
+ const data = await response.json();
37503
+ const models = data.models || [];
37504
+ const enriched = await Promise.all(models.map(async (m) => {
37505
+ let capabilities = [];
37506
+ if (enrichCapabilities) {
37507
+ try {
37508
+ const showResponse = await fetch(`${host}/api/show`, {
37509
+ method: "POST",
37510
+ headers: { "Content-Type": "application/json" },
37511
+ body: JSON.stringify({ name: m.name }),
37512
+ signal: AbortSignal.timeout(2000)
37513
+ });
37514
+ if (showResponse.ok) {
37515
+ const showData = await showResponse.json();
37516
+ capabilities = showData.capabilities || [];
37517
+ }
37518
+ } catch {}
37519
+ }
37520
+ const nameLower = String(m.name).toLowerCase();
37521
+ const supportsTools = capabilities.includes("tools");
37522
+ const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
37523
+ const sizeInfo = m.details?.parameter_size || "unknown size";
37524
+ const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
37525
+ return {
37526
+ id: `ollama/${m.name}`,
37527
+ name: m.name,
37528
+ description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
37529
+ provider: "ollama",
37530
+ pricing: { prompt: "0", completion: "0" },
37531
+ isLocal: true,
37532
+ supportsTools,
37533
+ isEmbeddingModel,
37534
+ capabilities,
37535
+ details: m.details,
37536
+ size: m.size
37537
+ };
37538
+ }));
37539
+ return enriched.filter((m) => !m.isEmbeddingModel);
37540
+ } catch {
37541
+ return [];
37542
+ }
37543
+ }
37544
+
37545
+ // src/behavior/observer/client.ts
37546
+ var init_client = __esm(() => {
37547
+ init_logger();
37548
+ });
37549
+
37550
+ // src/behavior/observer/corpus.ts
37551
+ var WRITE_TOOLS2;
37552
+ var init_corpus = __esm(() => {
37553
+ WRITE_TOOLS2 = new Set(["Write", "Edit", "NotebookEdit"]);
37554
+ });
37555
+
37556
+ // src/behavior/index.ts
37557
+ function createBehaviorEngine(rawConfig, extraRules = []) {
37558
+ return new BehaviorEngine(parseBehaviorConfig(rawConfig), [...BUILTIN_RULES, ...extraRules]);
37559
+ }
37560
+ function getBehaviorEngine() {
37561
+ if (!sharedEngine) {
37562
+ sharedEngine = createBehaviorEngine(loadConfig().behavior, hookRules);
37563
+ }
37564
+ return sharedEngine;
37565
+ }
37566
+ function registerHookRules(rules) {
37567
+ hookRules = [...hookRules, ...rules];
37568
+ sharedEngine = null;
37569
+ }
37570
+ var BUILTIN_RULES, sharedEngine = null, hookRules;
37571
+ var init_behavior = __esm(() => {
37572
+ init_profile_config();
37573
+ init_config();
37574
+ init_engine();
37575
+ init_plan_mode();
37576
+ init_engine();
37577
+ init_config();
37578
+ init_harness();
37579
+ init_hooks();
37580
+ init_digest();
37581
+ init_client();
37582
+ init_corpus();
37583
+ BUILTIN_RULES = [...PLAN_MODE_RULES];
37584
+ hookRules = [];
37585
+ });
37586
+
36793
37587
  // src/middleware/manager.ts
36794
37588
  class MiddlewareManager {
36795
37589
  middlewares = [];
@@ -37112,7 +37906,7 @@ class OpenAIProviderTransport {
37112
37906
  delayMs = 500 * (attempt + 1);
37113
37907
  }
37114
37908
  log(`[${this.displayName}] 429 rate limited, retry ${attempt + 1}/${maxRetries} in ${(delayMs / 1000).toFixed(1)}s`);
37115
- await new Promise((resolve) => setTimeout(resolve, delayMs));
37909
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
37116
37910
  continue;
37117
37911
  }
37118
37912
  return response;
@@ -37168,7 +37962,7 @@ var init_openai = __esm(() => {
37168
37962
  });
37169
37963
 
37170
37964
  // src/providers/catalog-query.ts
37171
- import { statSync } from "fs";
37965
+ import { statSync as statSync2 } from "fs";
37172
37966
  function project(entry) {
37173
37967
  return {
37174
37968
  modelId: entry.modelId,
@@ -37181,7 +37975,7 @@ function project(entry) {
37181
37975
  function getCachedEntries() {
37182
37976
  let mtimeMs;
37183
37977
  try {
37184
- mtimeMs = statSync(ALL_MODELS_CACHE_PATH).mtimeMs;
37978
+ mtimeMs = statSync2(ALL_MODELS_CACHE_PATH).mtimeMs;
37185
37979
  } catch {
37186
37980
  return null;
37187
37981
  }
@@ -37356,24 +38150,24 @@ var init_vision_proxy = __esm(() => {
37356
38150
  // src/stats-buffer.ts
37357
38151
  import {
37358
38152
  existsSync as existsSync14,
37359
- mkdirSync as mkdirSync8,
37360
- readFileSync as readFileSync11,
38153
+ mkdirSync as mkdirSync9,
38154
+ readFileSync as readFileSync12,
37361
38155
  renameSync,
37362
38156
  unlinkSync as unlinkSync5,
37363
38157
  writeFileSync as writeFileSync9
37364
38158
  } from "fs";
37365
- import { homedir as homedir16 } from "os";
37366
- import { join as join16 } from "path";
38159
+ import { homedir as homedir17 } from "os";
38160
+ import { join as join17 } from "path";
37367
38161
  function ensureDir() {
37368
38162
  if (!existsSync14(CLAUDISH_DIR)) {
37369
- mkdirSync8(CLAUDISH_DIR, { recursive: true });
38163
+ mkdirSync9(CLAUDISH_DIR, { recursive: true });
37370
38164
  }
37371
38165
  }
37372
38166
  function readFromDisk() {
37373
38167
  try {
37374
38168
  if (!existsSync14(BUFFER_FILE))
37375
38169
  return [];
37376
- const raw2 = readFileSync11(BUFFER_FILE, "utf-8");
38170
+ const raw2 = readFileSync12(BUFFER_FILE, "utf-8");
37377
38171
  const parsed = JSON.parse(raw2);
37378
38172
  if (!Array.isArray(parsed.events))
37379
38173
  return [];
@@ -37398,7 +38192,7 @@ function writeToDisk(events) {
37398
38192
  ensureDir();
37399
38193
  const trimmed = enforceSizeCap([...events]);
37400
38194
  const payload = { version: 1, events: trimmed };
37401
- const tmpFile = join16(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
38195
+ const tmpFile = join17(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37402
38196
  writeFileSync9(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
37403
38197
  renameSync(tmpFile, BUFFER_FILE);
37404
38198
  memoryCache = trimmed;
@@ -37471,8 +38265,8 @@ function syncFlushOnExit() {
37471
38265
  var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
37472
38266
  var init_stats_buffer = __esm(() => {
37473
38267
  BUFFER_MAX_BYTES = 64 * 1024;
37474
- CLAUDISH_DIR = join16(homedir16(), ".claudish");
37475
- BUFFER_FILE = join16(CLAUDISH_DIR, "stats-buffer.json");
38268
+ CLAUDISH_DIR = join17(homedir17(), ".claudish");
38269
+ BUFFER_FILE = join17(CLAUDISH_DIR, "stats-buffer.json");
37476
38270
  process.on("exit", syncFlushOnExit);
37477
38271
  process.on("SIGTERM", () => {
37478
38272
  try {
@@ -37831,11 +38625,11 @@ async function runConsentPrompt(ctx) {
37831
38625
  Does NOT send: prompts, paths, API keys, or credentials.
37832
38626
  Disable anytime: claudish telemetry off
37833
38627
  `);
37834
- const answer = await new Promise((resolve) => {
38628
+ const answer = await new Promise((resolve2) => {
37835
38629
  const rl = createInterface({ input: process.stdin, output: process.stderr });
37836
38630
  rl.question("Send anonymous error report? [y/N] ", (ans) => {
37837
38631
  rl.close();
37838
- resolve(ans.trim().toLowerCase());
38632
+ resolve2(ans.trim().toLowerCase());
37839
38633
  });
37840
38634
  });
37841
38635
  const accepted = answer === "y" || answer === "yes";
@@ -38576,8 +39370,8 @@ async function sniffResponsesStreamHead(response, opts = {}) {
38576
39370
  return { kind: "clean", response: replayResponse() };
38577
39371
  }
38578
39372
  let timer;
38579
- const timeout = new Promise((resolve) => {
38580
- timer = setTimeout(() => resolve("timeout"), remaining);
39373
+ const timeout = new Promise((resolve2) => {
39374
+ timer = setTimeout(() => resolve2("timeout"), remaining);
38581
39375
  });
38582
39376
  let result;
38583
39377
  try {
@@ -39306,6 +40100,7 @@ function createResponsesStreamHandler(c, response, opts) {
39306
40100
  let lastActivity = Date.now();
39307
40101
  let pingInterval = null;
39308
40102
  let isClosed = false;
40103
+ const streamMetadata = new Map;
39309
40104
  const functionCalls = new Map;
39310
40105
  const openToolBlocks = new Set;
39311
40106
  const stream = new ReadableStream({
@@ -39337,6 +40132,13 @@ data: ${JSON.stringify(data)}
39337
40132
  };
39338
40133
  const closeTools = () => {
39339
40134
  for (const fnCall of openToolBlocks) {
40135
+ if (fnCall.buffered && fnCall.arguments) {
40136
+ send("content_block_delta", {
40137
+ type: "content_block_delta",
40138
+ index: fnCall.index,
40139
+ delta: { type: "input_json_delta", partial_json: fnCall.arguments }
40140
+ });
40141
+ }
39340
40142
  send("content_block_stop", { type: "content_block_stop", index: fnCall.index });
39341
40143
  }
39342
40144
  openToolBlocks.clear();
@@ -39383,6 +40185,14 @@ data: ${JSON.stringify(data)}
39383
40185
  }
39384
40186
  try {
39385
40187
  const event = JSON.parse(data);
40188
+ if (opts.middlewareManager) {
40189
+ await opts.middlewareManager.afterStreamChunk({
40190
+ modelId: opts.modelName,
40191
+ chunk: event,
40192
+ delta: event,
40193
+ metadata: streamMetadata
40194
+ });
40195
+ }
39386
40196
  if (getLogLevel() === "debug" && event.type) {
39387
40197
  log(`[ResponsesSSE] Event: ${event.type}`);
39388
40198
  }
@@ -39414,7 +40224,8 @@ data: ${JSON.stringify(data)}
39414
40224
  name: fnName,
39415
40225
  arguments: "",
39416
40226
  index: curIdx++,
39417
- claudeId: callId
40227
+ claudeId: callId,
40228
+ buffered: opts.shouldBufferTool?.(fnName) === true
39418
40229
  };
39419
40230
  functionCalls.set(openaiCallId, fnCallData);
39420
40231
  if (itemId && itemId !== openaiCallId) {
@@ -39463,11 +40274,13 @@ data: ${JSON.stringify(data)}
39463
40274
  const fnCall = functionCalls.get(callId);
39464
40275
  if (fnCall) {
39465
40276
  fnCall.arguments += event.delta || "";
39466
- send("content_block_delta", {
39467
- type: "content_block_delta",
39468
- index: fnCall.index,
39469
- delta: { type: "input_json_delta", partial_json: event.delta || "" }
39470
- });
40277
+ if (!fnCall.buffered) {
40278
+ send("content_block_delta", {
40279
+ type: "content_block_delta",
40280
+ index: fnCall.index,
40281
+ delta: { type: "input_json_delta", partial_json: event.delta || "" }
40282
+ });
40283
+ }
39471
40284
  }
39472
40285
  } else if (event.type === "response.output_item.done") {
39473
40286
  if (event.item?.type === "reasoning" && event.item.encrypted_content) {
@@ -39482,6 +40295,23 @@ data: ${JSON.stringify(data)}
39482
40295
  const callId = event.item.call_id || event.item.id;
39483
40296
  const fnCall = functionCalls.get(callId) || functionCalls.get(event.item.id);
39484
40297
  if (fnCall && openToolBlocks.has(fnCall)) {
40298
+ if (fnCall.buffered) {
40299
+ let finalArgs = fnCall.arguments;
40300
+ try {
40301
+ const repaired = opts.onToolCall?.(fnCall.name, finalArgs);
40302
+ if (typeof repaired === "string" && repaired !== finalArgs) {
40303
+ log(`[ResponsesSSE] tool call repaired: ${fnCall.name}`);
40304
+ finalArgs = repaired;
40305
+ }
40306
+ } catch (err) {
40307
+ log(`[ResponsesSSE] onToolCall threw for ${fnCall.name}: ${err}`);
40308
+ }
40309
+ send("content_block_delta", {
40310
+ type: "content_block_delta",
40311
+ index: fnCall.index,
40312
+ delta: { type: "input_json_delta", partial_json: finalArgs }
40313
+ });
40314
+ }
39485
40315
  send("content_block_stop", { type: "content_block_stop", index: fnCall.index });
39486
40316
  openToolBlocks.delete(fnCall);
39487
40317
  }
@@ -39573,6 +40403,9 @@ data: ${JSON.stringify(data)}
39573
40403
  isClosed = true;
39574
40404
  if (opts.onTokenUpdate)
39575
40405
  opts.onTokenUpdate(inputTokens, outputTokens);
40406
+ if (opts.middlewareManager) {
40407
+ await opts.middlewareManager.afterStreamComplete(opts.modelName, streamMetadata);
40408
+ }
39576
40409
  safeClose();
39577
40410
  } catch (error46) {
39578
40411
  if (pingInterval) {
@@ -39636,9 +40469,9 @@ var init_openai_responses_sse = __esm(() => {
39636
40469
  });
39637
40470
 
39638
40471
  // src/handlers/shared/token-tracker.ts
39639
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "fs";
39640
- import { homedir as homedir17 } from "os";
39641
- 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";
39642
40475
 
39643
40476
  class TokenTracker {
39644
40477
  port;
@@ -39781,9 +40614,10 @@ class TokenTracker {
39781
40614
  if (this.quotaRemaining !== undefined) {
39782
40615
  data.quota_remaining = this.quotaRemaining;
39783
40616
  }
39784
- const claudishDir = join17(homedir17(), ".claudish");
39785
- mkdirSync9(claudishDir, { recursive: true });
39786
- 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");
39787
40621
  } catch (e) {
39788
40622
  log(`[TokenTracker] Error writing token file: ${e}`);
39789
40623
  }
@@ -39809,6 +40643,7 @@ class ComposedHandler {
39809
40643
  explicitAdapter;
39810
40644
  modelAdapter;
39811
40645
  middlewareManager;
40646
+ behaviorEngine;
39812
40647
  tokenTracker;
39813
40648
  targetModel;
39814
40649
  bareModelName;
@@ -39835,6 +40670,7 @@ class ComposedHandler {
39835
40670
  this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
39836
40671
  }
39837
40672
  this.middlewareManager.initialize().catch((err) => log(`[ComposedHandler:${this.bareModelName}] Middleware init error: ${err}`));
40673
+ this.behaviorEngine = getBehaviorEngine();
39838
40674
  this.tokenTracker = new TokenTracker(port, {
39839
40675
  contextWindow: this.getModelContextWindow(),
39840
40676
  providerName: provider.name,
@@ -39947,6 +40783,22 @@ class ComposedHandler {
39947
40783
  log(`[${this.provider.displayName}] Tools: ${toolNames}`);
39948
40784
  }
39949
40785
  }
40786
+ await this.middlewareManager.beforeRequest({
40787
+ modelId: this.bareModelName,
40788
+ messages,
40789
+ tools,
40790
+ stream: true,
40791
+ claudeRequest,
40792
+ claudeTools: claudeRequest.tools ?? []
40793
+ });
40794
+ const behaviorSession = this.behaviorEngine.startSession({
40795
+ modelId: this.bareModelName,
40796
+ providerName: this.provider.name,
40797
+ isNativeAnthropic: /^claude[-.]/i.test(this.bareModelName) || this.provider.name === "anthropic"
40798
+ });
40799
+ if (!behaviorSession.isNoop) {
40800
+ behaviorSession.applyRequest(claudeRequest, claudeRequest.tools ?? [], tools, messages);
40801
+ }
39950
40802
  let requestPayload = adapter.buildPayload(claudeRequest, messages, tools);
39951
40803
  const extraFields = this.provider.getExtraPayloadFields?.();
39952
40804
  if (extraFields) {
@@ -39993,12 +40845,6 @@ class ComposedHandler {
39993
40845
  if (this.provider.transformPayload) {
39994
40846
  requestPayload = this.provider.transformPayload(requestPayload);
39995
40847
  }
39996
- await this.middlewareManager.beforeRequest({
39997
- modelId: this.bareModelName,
39998
- messages,
39999
- tools,
40000
- stream: true
40001
- });
40002
40848
  const endpoint = this.provider.getEndpoint(this.targetModel);
40003
40849
  const headers = await this.provider.getHeaders();
40004
40850
  headers["Content-Type"] = "application/json";
@@ -40280,7 +41126,7 @@ class ComposedHandler {
40280
41126
  };
40281
41127
  return this.handleStream(c, response, adapter, claudeRequest, toolNameMap, onStreamComplete, (code, message) => {
40282
41128
  streamApiError = { code, message };
40283
- });
41129
+ }, behaviorSession);
40284
41130
  }
40285
41131
  async settleResponsesStreamHead(initial, reissue) {
40286
41132
  let response = initial;
@@ -40299,7 +41145,7 @@ class ComposedHandler {
40299
41145
  };
40300
41146
  }
40301
41147
  log(`[${this.provider.displayName}] in-stream ${verdict.code} before any output \u2014 ` + `retry ${attempt + 1}/${STREAM_RETRY_DELAYS_MS.length} in ${delayMs / 1000}s`);
40302
- await new Promise((resolve) => setTimeout(resolve, delayMs));
41148
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
40303
41149
  let next;
40304
41150
  try {
40305
41151
  next = await reissue();
@@ -40328,7 +41174,7 @@ class ComposedHandler {
40328
41174
  resolveStreamFormat() {
40329
41175
  return this.provider.overrideStreamFormat?.() ?? this.explicitAdapter?.getStreamFormat() ?? this.modelAdapter?.getStreamFormat() ?? this.getAdapter().getStreamFormat();
40330
41176
  }
40331
- handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete, onApiError) {
41177
+ handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete, onApiError, behaviorSession) {
40332
41178
  let pendingOnComplete = onComplete;
40333
41179
  const onTokenUpdate = (input, output) => {
40334
41180
  const strategy = this.options.tokenStrategy || "standard";
@@ -40365,7 +41211,10 @@ class ComposedHandler {
40365
41211
  toolNameMap: adapter.getToolNameMap(),
40366
41212
  contextWindow: lookupModelForProvider(this.bareModelName, this.provider.name),
40367
41213
  onApiError,
40368
- priorInputTokens
41214
+ priorInputTokens,
41215
+ middlewareManager: this.middlewareManager,
41216
+ shouldBufferTool: (name) => behaviorSession?.interceptsTool(name) ?? false,
41217
+ onToolCall: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null
40369
41218
  });
40370
41219
  case "anthropic-sse":
40371
41220
  return createAnthropicPassthroughStream(c, response, {
@@ -40461,6 +41310,7 @@ var STREAM_RETRY_DELAYS_MS;
40461
41310
  var init_composed_handler = __esm(() => {
40462
41311
  init_dialect_manager();
40463
41312
  init_logger();
41313
+ init_behavior();
40464
41314
  init_middleware();
40465
41315
  init_openai();
40466
41316
  init_vision_proxy();
@@ -41258,12 +42108,6 @@ var init_api_key_map = __esm(() => {
41258
42108
  };
41259
42109
  });
41260
42110
 
41261
- // ../../node_modules/.bun/zod@4.1.13/node_modules/zod/index.js
41262
- var init_zod = __esm(() => {
41263
- init_external2();
41264
- init_external2();
41265
- });
41266
-
41267
42111
  // src/adapters/anthropic-api-format.ts
41268
42112
  var AnthropicAPIFormat;
41269
42113
  var init_anthropic_api_format = __esm(() => {
@@ -41541,7 +42385,7 @@ class AnthropicProviderTransport {
41541
42385
  delayMs = 500 * (attempt + 1);
41542
42386
  }
41543
42387
  log(`[${this.displayName}] 429 rate limited, retry ${attempt + 1}/${maxRetries} in ${(delayMs / 1000).toFixed(1)}s`);
41544
- await new Promise((resolve) => setTimeout(resolve, delayMs));
42388
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
41545
42389
  continue;
41546
42390
  }
41547
42391
  return response;
@@ -41722,14 +42566,14 @@ async function discoverViaOllama(baseUrl, cacheKey) {
41722
42566
  let connectionError;
41723
42567
  let loadedRaw = [];
41724
42568
  try {
41725
- loadedRaw = await fetchOllamaModels(`${baseUrl}/api/ps`);
42569
+ loadedRaw = await fetchOllamaModels2(`${baseUrl}/api/ps`);
41726
42570
  } catch (e) {
41727
42571
  connectionError = classifyFetchError(e, `${baseUrl}/api/ps`);
41728
42572
  }
41729
42573
  let allRaw = loadedRaw;
41730
42574
  if (allRaw.length === 0) {
41731
42575
  try {
41732
- allRaw = await fetchOllamaModels(`${baseUrl}/api/tags`);
42576
+ allRaw = await fetchOllamaModels2(`${baseUrl}/api/tags`);
41733
42577
  } catch (e) {
41734
42578
  connectionError ??= classifyFetchError(e, `${baseUrl}/api/tags`);
41735
42579
  }
@@ -41840,7 +42684,7 @@ function extractLMStudioModels(body) {
41840
42684
  }
41841
42685
  return out;
41842
42686
  }
41843
- async function fetchOllamaModels(url2) {
42687
+ async function fetchOllamaModels2(url2) {
41844
42688
  const response = await fetch(url2, {
41845
42689
  method: "GET",
41846
42690
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
@@ -42270,11 +43114,11 @@ var init_ollama_api_format = __esm(() => {
42270
43114
  });
42271
43115
 
42272
43116
  // src/providers/api-key-provenance.ts
42273
- import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
42274
- import { homedir as homedir18 } from "os";
42275
- import { join as join18, resolve } 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";
42276
43120
  function activeConfigPath() {
42277
- return activeGlobalConfigFile(join18(homedir18(), ".claudish", "config.json"));
43121
+ return activeGlobalConfigFile(join19(homedir19(), ".claudish", "config.json"));
42278
43122
  }
42279
43123
  function configLayerLabel() {
42280
43124
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -42292,7 +43136,7 @@ function resolveApiKeyProvenance(envVar, aliases) {
42292
43136
  const allVars = [envVar, ...aliases || []];
42293
43137
  const dotenvValue = readDotenvKey(allVars);
42294
43138
  layers.push({
42295
- source: `.env (${resolve(".env")})`,
43139
+ source: `.env (${resolve2(".env")})`,
42296
43140
  maskedValue: maskKey(dotenvValue),
42297
43141
  isActive: false
42298
43142
  });
@@ -42350,10 +43194,10 @@ function formatProvenanceLog(p) {
42350
43194
  }
42351
43195
  function readDotenvKey(envVars) {
42352
43196
  try {
42353
- const dotenvPath = resolve(".env");
43197
+ const dotenvPath = resolve2(".env");
42354
43198
  if (!existsSync15(dotenvPath))
42355
43199
  return null;
42356
- const parsed = import_dotenv.parse(readFileSync12(dotenvPath, "utf-8"));
43200
+ const parsed = import_dotenv.parse(readFileSync13(dotenvPath, "utf-8"));
42357
43201
  for (const v of envVars) {
42358
43202
  if (parsed[v])
42359
43203
  return parsed[v];
@@ -42368,7 +43212,7 @@ function readConfigKey(envVar) {
42368
43212
  const configPath = activeConfigPath();
42369
43213
  if (!existsSync15(configPath))
42370
43214
  return null;
42371
- const cfg = JSON.parse(readFileSync12(configPath, "utf-8"));
43215
+ const cfg = JSON.parse(readFileSync13(configPath, "utf-8"));
42372
43216
  return cfg.apiKeys?.[envVar] || null;
42373
43217
  } catch {
42374
43218
  return null;
@@ -42407,10 +43251,10 @@ class GeminiRequestQueue {
42407
43251
  log(`[GeminiQueue] Queue full (${this.queue.length}/${this.maxQueueSize}), rejecting request`);
42408
43252
  throw new Error("Gemini request queue full. Please retry later.");
42409
43253
  }
42410
- return new Promise((resolve2, reject) => {
43254
+ return new Promise((resolve3, reject) => {
42411
43255
  const queuedRequest = {
42412
43256
  fetchFn,
42413
- resolve: resolve2,
43257
+ resolve: resolve3,
42414
43258
  reject
42415
43259
  };
42416
43260
  this.queue.push(queuedRequest);
@@ -42466,7 +43310,7 @@ class GeminiRequestQueue {
42466
43310
  if (timeSinceLastRequest < delayMs) {
42467
43311
  const waitMs = delayMs - timeSinceLastRequest;
42468
43312
  log(`[GeminiQueue] Waiting ${waitMs}ms before next request`);
42469
- await new Promise((resolve2) => setTimeout(resolve2, waitMs));
43313
+ await new Promise((resolve3) => setTimeout(resolve3, waitMs));
42470
43314
  }
42471
43315
  }
42472
43316
  handleRateLimitResponse(errorText) {
@@ -43264,10 +44108,10 @@ class LocalModelQueue {
43264
44108
  }
43265
44109
  throw new Error(`Local model queue full (${this.queue.length}/${this.maxQueueSize}). GPU is overloaded. Please wait for current requests to complete.`);
43266
44110
  }
43267
- return new Promise((resolve2, reject) => {
44111
+ return new Promise((resolve3, reject) => {
43268
44112
  const queuedRequest = {
43269
44113
  fetchFn,
43270
- resolve: resolve2,
44114
+ resolve: resolve3,
43271
44115
  reject,
43272
44116
  providerId
43273
44117
  };
@@ -43362,7 +44206,7 @@ class LocalModelQueue {
43362
44206
  return parsed;
43363
44207
  }
43364
44208
  delay(ms) {
43365
- return new Promise((resolve2) => setTimeout(resolve2, ms));
44209
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
43366
44210
  }
43367
44211
  getStats() {
43368
44212
  return {
@@ -43664,10 +44508,10 @@ class OpenRouterRequestQueue {
43664
44508
  }
43665
44509
  throw new Error(`OpenRouter request queue full (${this.queue.length}/${this.maxQueueSize}). The API is rate-limited. Please wait and try again.`);
43666
44510
  }
43667
- return new Promise((resolve2, reject) => {
44511
+ return new Promise((resolve3, reject) => {
43668
44512
  const queuedRequest = {
43669
44513
  fetchFn,
43670
- resolve: resolve2,
44514
+ resolve: resolve3,
43671
44515
  reject
43672
44516
  };
43673
44517
  this.queue.push(queuedRequest);
@@ -43735,7 +44579,7 @@ class OpenRouterRequestQueue {
43735
44579
  if (getLogLevel() === "debug") {
43736
44580
  log(`[OpenRouterQueue] Waiting ${waitMs}ms before next request`);
43737
44581
  }
43738
- await new Promise((resolve2) => setTimeout(resolve2, waitMs));
44582
+ await new Promise((resolve3) => setTimeout(resolve3, waitMs));
43739
44583
  }
43740
44584
  }
43741
44585
  calculateDelay() {
@@ -43926,9 +44770,9 @@ var init_poe = __esm(() => {
43926
44770
  });
43927
44771
 
43928
44772
  // src/services/pricing-cache.ts
43929
- import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync2 } from "fs";
43930
- import { homedir as homedir19 } from "os";
43931
- 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";
43932
44776
  function prefixMatch(modelName) {
43933
44777
  for (const [key, pricing] of pricingMap) {
43934
44778
  if (modelName.startsWith(key))
@@ -43968,10 +44812,10 @@ function loadDiskCache() {
43968
44812
  try {
43969
44813
  if (!existsSync16(CACHE_FILE))
43970
44814
  return false;
43971
- const stat = statSync2(CACHE_FILE);
44815
+ const stat = statSync3(CACHE_FILE);
43972
44816
  const age = Date.now() - stat.mtimeMs;
43973
44817
  const isFresh = age < CACHE_TTL_MS2;
43974
- const raw2 = readFileSync13(CACHE_FILE, "utf-8");
44818
+ const raw2 = readFileSync14(CACHE_FILE, "utf-8");
43975
44819
  const data = JSON.parse(raw2);
43976
44820
  for (const [key, pricing] of Object.entries(data)) {
43977
44821
  pricingMap.set(key, pricing);
@@ -43987,8 +44831,8 @@ var init_pricing_cache = __esm(() => {
43987
44831
  init_logger();
43988
44832
  init_catalog_query();
43989
44833
  pricingMap = new Map;
43990
- CACHE_DIR = join19(homedir19(), ".claudish");
43991
- CACHE_FILE = join19(CACHE_DIR, "pricing-cache.json");
44834
+ CACHE_DIR = join20(homedir20(), ".claudish");
44835
+ CACHE_FILE = join20(CACHE_DIR, "pricing-cache.json");
43992
44836
  CACHE_TTL_MS2 = 24 * 60 * 60 * 1000;
43993
44837
  });
43994
44838
 
@@ -44009,6 +44853,13 @@ async function createProxyServer(port, _openrouterApiKey, model, monitorMode = f
44009
44853
  } catch (err) {
44010
44854
  log(`[Proxy] customEndpoints load skipped: ${err instanceof Error ? err.message : String(err)}`);
44011
44855
  }
44856
+ try {
44857
+ const hookRules2 = await loadHookRules(parseBehaviorConfig(loadConfig().behavior).hooks);
44858
+ if (hookRules2.length > 0)
44859
+ registerHookRules(hookRules2);
44860
+ } catch (err) {
44861
+ log(`[Proxy] behavior hooks load skipped: ${err instanceof Error ? err.message : String(err)}`);
44862
+ }
44012
44863
  const nativeHandler = new NativeHandler(anthropicApiKey, options.advisorModels, options.advisorCollector);
44013
44864
  const openRouterHandlers = new Map;
44014
44865
  const localProviderHandlers = new Map;
@@ -44415,6 +45266,8 @@ var init_proxy_server = __esm(() => {
44415
45266
  init_model_loader();
44416
45267
  init_profile_config();
44417
45268
  init_api_key_map();
45269
+ init_behavior();
45270
+ init_hooks();
44418
45271
  init_custom_endpoints_loader();
44419
45272
  init_model_catalog_resolver();
44420
45273
  init_model_parser();
@@ -44435,6 +45288,175 @@ var init_proxy_server = __esm(() => {
44435
45288
  };
44436
45289
  });
44437
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
+
44438
45460
  // src/team-orchestrator.ts
44439
45461
  var exports_team_orchestrator = {};
44440
45462
  __export(exports_team_orchestrator, {
@@ -44445,21 +45467,64 @@ __export(exports_team_orchestrator, {
44445
45467
  judgeResponses: () => judgeResponses,
44446
45468
  getStatus: () => getStatus,
44447
45469
  fisherYatesShuffle: () => fisherYatesShuffle,
45470
+ classifyRunOutput: () => classifyRunOutput,
44448
45471
  buildJudgePrompt: () => buildJudgePrompt,
44449
- aggregateVerdict: () => aggregateVerdict
45472
+ aggregateVerdict: () => aggregateVerdict,
45473
+ STDOUT_TAIL_LIMIT: () => STDOUT_TAIL_LIMIT,
45474
+ DEFAULT_MIN_OUTPUT_BYTES: () => DEFAULT_MIN_OUTPUT_BYTES
44450
45475
  });
44451
45476
  import { spawn as spawn2 } from "child_process";
44452
45477
  import {
44453
45478
  createWriteStream as createWriteStream2,
44454
- existsSync as existsSync17,
44455
- mkdirSync as mkdirSync10,
44456
- readFileSync as readFileSync14,
45479
+ existsSync as existsSync18,
45480
+ mkdirSync as mkdirSync11,
45481
+ readFileSync as readFileSync16,
44457
45482
  readdirSync as readdirSync2,
44458
- writeFileSync as writeFileSync11
45483
+ writeFileSync as writeFileSync12
44459
45484
  } from "fs";
44460
- import { join as join20, resolve as resolve2 } 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
+ }
44461
45526
  function validateSessionPath(sessionPath) {
44462
- const resolved = resolve2(sessionPath);
45527
+ const resolved = resolve3(sessionPath);
44463
45528
  const cwd = process.cwd();
44464
45529
  if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
44465
45530
  throw new Error(`Session path must be within current directory: ${sessionPath}`);
@@ -44478,18 +45543,18 @@ function setupSession(sessionPath, models, input) {
44478
45543
  if (models.length === 0) {
44479
45544
  throw new Error("At least one model is required");
44480
45545
  }
44481
- if (existsSync17(join20(sessionPath, "manifest.json"))) {
45546
+ if (existsSync18(join22(sessionPath, "manifest.json"))) {
44482
45547
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
44483
45548
  }
44484
45549
  const sentinels = models.filter(isSentinelModel);
44485
45550
  if (sentinels.length > 0) {
44486
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.`);
44487
45552
  }
44488
- mkdirSync10(join20(sessionPath, "work"), { recursive: true });
44489
- mkdirSync10(join20(sessionPath, "errors"), { recursive: true });
45553
+ mkdirSync11(join22(sessionPath, "work"), { recursive: true });
45554
+ mkdirSync11(join22(sessionPath, "errors"), { recursive: true });
44490
45555
  if (input !== undefined) {
44491
- writeFileSync11(join20(sessionPath, "input.md"), input, "utf-8");
44492
- } else if (!existsSync17(join20(sessionPath, "input.md"))) {
45556
+ writeFileSync12(join22(sessionPath, "input.md"), input, "utf-8");
45557
+ } else if (!existsSync18(join22(sessionPath, "input.md"))) {
44493
45558
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
44494
45559
  }
44495
45560
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -44506,9 +45571,9 @@ function setupSession(sessionPath, models, input) {
44506
45571
  model: models[i],
44507
45572
  assignedAt: now
44508
45573
  };
44509
- mkdirSync10(join20(sessionPath, "work", anonId), { recursive: true });
45574
+ mkdirSync11(join22(sessionPath, "work", anonId), { recursive: true });
44510
45575
  }
44511
- 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");
44512
45577
  const status = {
44513
45578
  startedAt: now,
44514
45579
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -44522,22 +45587,25 @@ function setupSession(sessionPath, models, input) {
44522
45587
  }
44523
45588
  ]))
44524
45589
  };
44525
- 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");
44526
45591
  return manifest;
44527
45592
  }
44528
45593
  async function runModels(sessionPath, opts = {}) {
44529
45594
  const timeoutMs = (opts.timeout ?? 300) * 1000;
44530
- const manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
44531
- const statusPath = join20(sessionPath, "status.json");
44532
- const inputPath = join20(sessionPath, "input.md");
44533
- 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");
44534
45599
  await prehydrateCredentialsForSpawn(Object.values(manifest.models).map((m) => m.model));
44535
- const statusCache = JSON.parse(readFileSync14(statusPath, "utf-8"));
45600
+ const statusCache = JSON.parse(readFileSync16(statusPath, "utf-8"));
44536
45601
  function updateModelStatus(id, update) {
44537
45602
  statusCache.models[id] = { ...statusCache.models[id], ...update };
44538
- writeFileSync11(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
45603
+ writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
44539
45604
  }
45605
+ const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
45606
+ mkdirSync11(statsDir(sessionPath), { recursive: true });
44540
45607
  const processes = new Map;
45608
+ const runtimes = new Map;
44541
45609
  const sigintHandler = () => {
44542
45610
  for (const [, proc] of processes) {
44543
45611
  if (!proc.killed)
@@ -44548,8 +45616,8 @@ async function runModels(sessionPath, opts = {}) {
44548
45616
  process.on("SIGINT", sigintHandler);
44549
45617
  const completionPromises = [];
44550
45618
  for (const [anonId, entry] of Object.entries(manifest.models)) {
44551
- const outputPath = join20(sessionPath, `response-${anonId}.md`);
44552
- const errorLogPath = join20(sessionPath, "errors", `${anonId}.log`);
45619
+ const outputPath = join22(sessionPath, `response-${anonId}.md`);
45620
+ const errorLogPath = join22(sessionPath, "errors", `${anonId}.log`);
44553
45621
  const args = ["--model", entry.model, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
44554
45622
  updateModelStatus(anonId, {
44555
45623
  state: "RUNNING",
@@ -44557,11 +45625,17 @@ async function runModels(sessionPath, opts = {}) {
44557
45625
  });
44558
45626
  const proc = spawn2("claudish", args, {
44559
45627
  stdio: ["pipe", "pipe", "pipe"],
44560
- shell: false
45628
+ shell: false,
45629
+ env: {
45630
+ ...process.env,
45631
+ CLAUDISH_TOKEN_FILE: tokenFileFor(sessionPath, anonId)
45632
+ }
44561
45633
  });
44562
45634
  let byteCount = 0;
45635
+ let stdoutTail = "";
44563
45636
  proc.stdout?.on("data", (chunk) => {
44564
45637
  byteCount += chunk.length;
45638
+ stdoutTail = (stdoutTail + chunk.toString()).slice(-STDOUT_TAIL_LIMIT);
44565
45639
  });
44566
45640
  const outputStream = createWriteStream2(outputPath);
44567
45641
  proc.stdout?.pipe(outputStream);
@@ -44569,9 +45643,17 @@ async function runModels(sessionPath, opts = {}) {
44569
45643
  proc.stderr?.on("data", (chunk) => {
44570
45644
  stderr += chunk.toString();
44571
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
+ });
44572
45654
  proc.stdin?.write(inputContent);
44573
45655
  proc.stdin?.end();
44574
- const completionPromise = new Promise((resolve3) => {
45656
+ const completionPromise = new Promise((resolve4) => {
44575
45657
  let exitCode = null;
44576
45658
  let resolved = false;
44577
45659
  const finish = () => {
@@ -44579,38 +45661,57 @@ async function runModels(sessionPath, opts = {}) {
44579
45661
  return;
44580
45662
  if (statusCache.models[anonId].state === "TIMEOUT") {
44581
45663
  resolved = true;
44582
- resolve3();
45664
+ resolve4();
44583
45665
  return;
44584
45666
  }
44585
45667
  resolved = true;
44586
45668
  const outputSize = byteCount;
44587
- const failed = exitCode !== 0;
44588
- updateModelStatus(anonId, {
44589
- state: failed ? "FAILED" : "COMPLETED",
44590
- exitCode: exitCode ?? 1,
44591
- completedAt: new Date().toISOString(),
44592
- outputSize,
44593
- error: failed ? {
44594
- model: anonId,
44595
- command: `claudish ${args.join(" ")}`,
44596
- stderrSnippet: stderr ? stderr.slice(-2000) : undefined,
44597
- errorLogPath,
44598
- workDir: sessionPath
44599
- } : undefined
44600
- });
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
+ }
44601
45702
  opts.onStatusChange?.(anonId, statusCache.models[anonId]);
44602
- resolve3();
45703
+ resolve4();
44603
45704
  };
44604
45705
  outputStream.on("close", finish);
44605
45706
  proc.on("exit", (code) => {
44606
45707
  const current = statusCache.models[anonId];
44607
45708
  if (current?.state === "TIMEOUT") {
44608
45709
  resolved = true;
44609
- resolve3();
45710
+ resolve4();
44610
45711
  return;
44611
45712
  }
44612
45713
  if (stderr) {
44613
- writeFileSync11(errorLogPath, stderr, "utf-8");
45714
+ writeFileSync12(errorLogPath, redactSecrets(stderr), "utf-8");
44614
45715
  }
44615
45716
  exitCode = code;
44616
45717
  if (outputStream.destroyed) {
@@ -44621,29 +45722,79 @@ async function runModels(sessionPath, opts = {}) {
44621
45722
  processes.set(anonId, proc);
44622
45723
  completionPromises.push(completionPromise);
44623
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?.();
44624
45755
  let timeoutHandle = null;
44625
45756
  await Promise.race([
44626
45757
  Promise.all(completionPromises),
44627
- new Promise((resolve3) => {
45758
+ new Promise((resolve4) => {
44628
45759
  timeoutHandle = setTimeout(() => {
44629
45760
  for (const [id, proc] of processes) {
44630
45761
  const current = statusCache.models[id];
44631
45762
  if (current.state === "RUNNING") {
44632
45763
  if (!proc.killed)
44633
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);
44634
45772
  updateModelStatus(id, {
44635
45773
  state: "TIMEOUT",
44636
- 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
44637
45786
  });
44638
45787
  opts.onStatusChange?.(id, statusCache.models[id]);
44639
45788
  }
44640
45789
  }
44641
- resolve3();
45790
+ resolve4();
44642
45791
  }, timeoutMs);
44643
45792
  })
44644
45793
  ]);
44645
45794
  if (timeoutHandle !== null)
44646
45795
  clearTimeout(timeoutHandle);
45796
+ clearInterval(progressHandle);
45797
+ emitProgress("settled");
44647
45798
  process.off("SIGINT", sigintHandler);
44648
45799
  return statusCache;
44649
45800
  }
@@ -44655,23 +45806,23 @@ async function judgeResponses(sessionPath, opts = {}) {
44655
45806
  const responses = {};
44656
45807
  for (const file2 of responseFiles) {
44657
45808
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
44658
- responses[id] = readFileSync14(join20(sessionPath, file2), "utf-8");
45809
+ responses[id] = readFileSync16(join22(sessionPath, file2), "utf-8");
44659
45810
  }
44660
- const input = readFileSync14(join20(sessionPath, "input.md"), "utf-8");
45811
+ const input = readFileSync16(join22(sessionPath, "input.md"), "utf-8");
44661
45812
  const judgePrompt = buildJudgePrompt(input, responses);
44662
- writeFileSync11(join20(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
45813
+ writeFileSync12(join22(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
44663
45814
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
44664
- const judgePath = join20(sessionPath, "judging");
44665
- mkdirSync10(judgePath, { recursive: true });
45815
+ const judgePath = join22(sessionPath, "judging");
45816
+ mkdirSync11(judgePath, { recursive: true });
44666
45817
  setupSession(judgePath, judgeModels, judgePrompt);
44667
45818
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
44668
45819
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
44669
45820
  const verdict = aggregateVerdict(votes, Object.keys(responses));
44670
- writeFileSync11(join20(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
45821
+ writeFileSync12(join22(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
44671
45822
  return verdict;
44672
45823
  }
44673
45824
  function getStatus(sessionPath) {
44674
- return JSON.parse(readFileSync14(join20(sessionPath, "status.json"), "utf-8"));
45825
+ return JSON.parse(readFileSync16(join22(sessionPath, "status.json"), "utf-8"));
44675
45826
  }
44676
45827
  function fisherYatesShuffle(arr) {
44677
45828
  for (let i = arr.length - 1;i > 0; i--) {
@@ -44681,7 +45832,7 @@ function fisherYatesShuffle(arr) {
44681
45832
  return arr;
44682
45833
  }
44683
45834
  function getDefaultJudgeModels(sessionPath) {
44684
- const manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
45835
+ const manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
44685
45836
  return Object.values(manifest.models).map((e) => e.model);
44686
45837
  }
44687
45838
  function buildJudgePrompt(input, responses) {
@@ -44744,7 +45895,7 @@ function parseJudgeVotes(judgePath, responseIds) {
44744
45895
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
44745
45896
  let content;
44746
45897
  try {
44747
- content = readFileSync14(join20(judgePath, file2), "utf-8");
45898
+ content = readFileSync16(join22(judgePath, file2), "utf-8");
44748
45899
  } catch {
44749
45900
  continue;
44750
45901
  }
@@ -44796,7 +45947,7 @@ function aggregateVerdict(votes, responseIds) {
44796
45947
  function formatVerdict(verdict, sessionPath) {
44797
45948
  let manifest = null;
44798
45949
  try {
44799
- manifest = JSON.parse(readFileSync14(join20(sessionPath, "manifest.json"), "utf-8"));
45950
+ manifest = JSON.parse(readFileSync16(join22(sessionPath, "manifest.json"), "utf-8"));
44800
45951
  } catch {}
44801
45952
  let output = `# Team Verdict
44802
45953
 
@@ -44827,9 +45978,13 @@ function formatVerdict(verdict, sessionPath) {
44827
45978
  }
44828
45979
  return output;
44829
45980
  }
44830
- var SENTINEL_MODELS;
45981
+ var STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0, SENTINEL_MODELS;
44831
45982
  var init_team_orchestrator = __esm(() => {
44832
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;
44833
45988
  SENTINEL_MODELS = new Set([
44834
45989
  "internal",
44835
45990
  "default",
@@ -44844,16 +45999,17 @@ var exports_mcp_server = {};
44844
45999
  __export(exports_mcp_server, {
44845
46000
  startMcpServer: () => startMcpServer,
44846
46001
  runPromptViaProxy: () => runPromptViaProxy,
44847
- parseAnthropicSse: () => parseAnthropicSse
46002
+ parseAnthropicSse: () => parseAnthropicSse,
46003
+ formatTeamResult: () => formatTeamResult
44848
46004
  });
44849
- import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync15, readdirSync as readdirSync3, writeFileSync as writeFileSync12 } from "fs";
44850
- import { homedir as homedir20 } from "os";
44851
- 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";
44852
46008
  import { fileURLToPath } from "url";
44853
46009
  async function loadAllModels(forceRefresh = false) {
44854
- if (!forceRefresh && existsSync18(ALL_MODELS_CACHE_PATH2)) {
46010
+ if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
44855
46011
  try {
44856
- const cacheData = JSON.parse(readFileSync15(ALL_MODELS_CACHE_PATH2, "utf-8"));
46012
+ const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH2, "utf-8"));
44857
46013
  const lastUpdated = new Date(cacheData.lastUpdated);
44858
46014
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
44859
46015
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -44867,12 +46023,12 @@ async function loadAllModels(forceRefresh = false) {
44867
46023
  throw new Error(`API returned ${response.status}`);
44868
46024
  const data = await response.json();
44869
46025
  const models = data.data || [];
44870
- mkdirSync11(CLAUDISH_CACHE_DIR, { recursive: true });
44871
- 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");
44872
46028
  return models;
44873
46029
  } catch {
44874
- if (existsSync18(ALL_MODELS_CACHE_PATH2)) {
44875
- 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"));
44876
46032
  return cacheData.models || [];
44877
46033
  }
44878
46034
  return [];
@@ -44968,63 +46124,53 @@ function fuzzyScore(text, query) {
44968
46124
  }
44969
46125
  return queryIndex === lowerQuery.length ? score / lowerText.length : 0;
44970
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
+ }
44971
46136
  function formatTeamResult(status, sessionPath) {
44972
- const entries = Object.entries(status.models);
44973
- 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");
44974
46139
  const succeeded = entries.filter(([, m]) => m.state === "COMPLETED");
44975
- 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
+ }
44976
46149
  if (failed.length > 0) {
44977
- result += `
44978
-
44979
- ---
44980
- ## Failures Detected
44981
-
44982
- `;
44983
- result += `${succeeded.length}/${entries.length} models succeeded, ${failed.length} failed.
44984
-
44985
- `;
46150
+ lines.push("failures:");
44986
46151
  for (const [id, m] of failed) {
44987
- result += `### Model ${id}: ${m.state}
44988
- `;
44989
- if (m.error) {
44990
- result += `- **Model:** ${m.error.model}
44991
- `;
44992
- result += `- **Command:** \`${m.error.command}\`
44993
- `;
44994
- result += `- **Exit code:** ${m.exitCode}
44995
- `;
44996
- if (m.error.stderrSnippet) {
44997
- result += `- **Error output:**
44998
- \`\`\`
44999
- ${m.error.stderrSnippet}
45000
- \`\`\`
45001
- `;
45002
- }
45003
- result += `- **Full error log:** ${m.error.errorLogPath}
45004
- `;
45005
- result += `- **Working directory:** ${m.error.workDir}
45006
- `;
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");
45007
46162
  }
45008
- result += `
45009
- `;
45010
46163
  }
45011
- result += `---
45012
- `;
45013
- result += "**To help claudish devs fix this**, use the `report_error` tool with:\n";
45014
- result += '- `error_type`: "provider_failure" or "team_failure"\n';
45015
- result += `- \`session_path\`: "${sessionPath}"
45016
- `;
45017
- result += "- Copy the stderr snippet above into `stderr_snippet`\n";
45018
- 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}")`);
45019
46168
  }
45020
- return result;
45021
- }
45022
- function sanitize(text) {
45023
- if (!text)
45024
- return "";
45025
- 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
+ `);
45026
46172
  }
45027
- function defineTools(sessionManager) {
46173
+ function defineTools(sessionManager, notifyChannel) {
45028
46174
  const tools = [];
45029
46175
  tools.push({
45030
46176
  name: "run_prompt",
@@ -45355,12 +46501,25 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45355
46501
  const input = args.input;
45356
46502
  const timeout = args.timeout;
45357
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
+ };
45358
46517
  switch (mode) {
45359
46518
  case "run": {
45360
46519
  if (!models?.length)
45361
46520
  throw new Error("'models' is required for 'run' mode");
45362
46521
  setupSession(resolved, models, input);
45363
- const status = await runModels(resolved, { timeout });
46522
+ const status = await runModels(resolved, runOpts);
45364
46523
  return {
45365
46524
  content: [{ type: "text", text: formatTeamResult(status, resolved) }]
45366
46525
  };
@@ -45373,7 +46532,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45373
46532
  if (!models?.length)
45374
46533
  throw new Error("'models' is required for 'run-and-judge' mode");
45375
46534
  setupSession(resolved, models, input);
45376
- await runModels(resolved, { timeout });
46535
+ await runModels(resolved, runOpts);
45377
46536
  const verdict = await judgeResponses(resolved, { judges });
45378
46537
  return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
45379
46538
  }
@@ -45436,7 +46595,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45436
46595
  let stderrFull = stderr_snippet || "";
45437
46596
  if (error_log_path) {
45438
46597
  try {
45439
- stderrFull = readFileSync15(error_log_path, "utf-8");
46598
+ stderrFull = readFileSync17(error_log_path, "utf-8");
45440
46599
  } catch {}
45441
46600
  }
45442
46601
  const sessionData = {};
@@ -45444,16 +46603,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45444
46603
  const sp = session_path;
45445
46604
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
45446
46605
  try {
45447
- sessionData[file2] = readFileSync15(join21(sp, file2), "utf-8");
46606
+ sessionData[file2] = readFileSync17(join23(sp, file2), "utf-8");
45448
46607
  } catch {}
45449
46608
  }
45450
46609
  try {
45451
- const errorDir = join21(sp, "errors");
45452
- if (existsSync18(errorDir)) {
46610
+ const errorDir = join23(sp, "errors");
46611
+ if (existsSync19(errorDir)) {
45453
46612
  for (const f of readdirSync3(errorDir)) {
45454
46613
  if (f.endsWith(".log")) {
45455
46614
  try {
45456
- sessionData[`errors/${f}`] = readFileSync15(join21(errorDir, f), "utf-8");
46615
+ sessionData[`errors/${f}`] = readFileSync17(join23(errorDir, f), "utf-8");
45457
46616
  } catch {}
45458
46617
  }
45459
46618
  }
@@ -45463,7 +46622,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45463
46622
  for (const f of readdirSync3(sp)) {
45464
46623
  if (f.startsWith("response-") && f.endsWith(".md")) {
45465
46624
  try {
45466
- const content = readFileSync15(join21(sp, f), "utf-8");
46625
+ const content = readFileSync17(join23(sp, f), "utf-8");
45467
46626
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
45468
46627
  } catch {}
45469
46628
  }
@@ -45472,9 +46631,9 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
45472
46631
  }
45473
46632
  let version2 = "unknown";
45474
46633
  try {
45475
- const pkgPath = join21(__dirname2, "../package.json");
45476
- if (existsSync18(pkgPath)) {
45477
- 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;
45478
46637
  }
45479
46638
  } catch {}
45480
46639
  const report = {
@@ -45759,7 +46918,31 @@ To report this error, use the report_error tool with error_type: "provider_failu
45759
46918
  watchNotificationResult(result, { sessionId: sessionId2, eventType: event.type });
45760
46919
  })
45761
46920
  });
45762
- 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);
45763
46946
  const enabledTools = allTools.filter((t) => enabledGroups.has(t.group));
45764
46947
  const toolMap = new Map(enabledTools.map((t) => [t.name, t]));
45765
46948
  console.error(`[claudish] MCP server started (tools: ${toolMode}, ${enabledTools.length} tools)`);
@@ -45830,7 +47013,7 @@ When channel mode is active, you receive <channel source="claudish" ...> notific
45830
47013
  5. Use list_sessions to see all active/completed sessions.
45831
47014
  6. Use cancel_session to stop a running session.
45832
47015
 
45833
- 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;
45834
47017
  var init_mcp_server = __esm(() => {
45835
47018
  init_server2();
45836
47019
  init_stdio2();
@@ -45840,15 +47023,24 @@ var init_mcp_server = __esm(() => {
45840
47023
  init_channel();
45841
47024
  init_model_loader();
45842
47025
  init_port_manager();
47026
+ init_redact();
45843
47027
  init_provider_definitions();
45844
47028
  init_proxy_server();
45845
47029
  init_team_orchestrator();
45846
47030
  import_dotenv2 = __toESM(require_main(), 1);
45847
47031
  import_dotenv2.config({ quiet: true });
45848
47032
  __filename2 = fileURLToPath(import.meta.url);
45849
- __dirname2 = dirname5(__filename2);
45850
- CLAUDISH_CACHE_DIR = join21(homedir20(), ".claudish");
45851
- 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;
45852
47044
  EVENT_TO_TASK_STATUS = new Map([
45853
47045
  ["starting", "working"],
45854
47046
  ["running", "working"],
@@ -45865,7 +47057,7 @@ var exports_serve_command = {};
45865
47057
  __export(exports_serve_command, {
45866
47058
  serveCommand: () => serveCommand
45867
47059
  });
45868
- import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
47060
+ import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
45869
47061
  function parseServeArgs(args) {
45870
47062
  const out = {};
45871
47063
  for (let i = 0;i < args.length; i++) {
@@ -45884,12 +47076,12 @@ function parseServeArgs(args) {
45884
47076
  return out;
45885
47077
  }
45886
47078
  function loadModelMap(path) {
45887
- if (!existsSync19(path)) {
47079
+ if (!existsSync20(path)) {
45888
47080
  throw new Error(`--models file not found: ${path}`);
45889
47081
  }
45890
47082
  let raw2;
45891
47083
  try {
45892
- raw2 = readFileSync16(path, "utf-8");
47084
+ raw2 = readFileSync18(path, "utf-8");
45893
47085
  } catch (e) {
45894
47086
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
45895
47087
  }
@@ -47685,13 +48877,13 @@ var PromisePolyfill;
47685
48877
  var init_promise_polyfill = __esm(() => {
47686
48878
  PromisePolyfill = class PromisePolyfill extends Promise {
47687
48879
  static withResolver() {
47688
- let resolve3;
48880
+ let resolve4;
47689
48881
  let reject;
47690
48882
  const promise3 = new Promise((res, rej) => {
47691
- resolve3 = res;
48883
+ resolve4 = res;
47692
48884
  reject = rej;
47693
48885
  });
47694
- return { promise: promise3, resolve: resolve3, reject };
48886
+ return { promise: promise3, resolve: resolve4, reject };
47695
48887
  }
47696
48888
  };
47697
48889
  });
@@ -47728,7 +48920,7 @@ function createPrompt(view) {
47728
48920
  output
47729
48921
  });
47730
48922
  const screen = new ScreenManager(rl);
47731
- const { promise: promise3, resolve: resolve3, reject } = PromisePolyfill.withResolver();
48923
+ const { promise: promise3, resolve: resolve4, reject } = PromisePolyfill.withResolver();
47732
48924
  const cancel = () => reject(new CancelPromptError);
47733
48925
  if (signal) {
47734
48926
  const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
@@ -47755,7 +48947,7 @@ function createPrompt(view) {
47755
48947
  cycle(() => {
47756
48948
  try {
47757
48949
  const nextView = view(config3, (value) => {
47758
- setImmediate(() => resolve3(value));
48950
+ setImmediate(() => resolve4(value));
47759
48951
  });
47760
48952
  if (nextView === undefined) {
47761
48953
  const callerFilename = callSites[1]?.getFileName();
@@ -53596,7 +54788,7 @@ var require_lib2 = __commonJS((exports) => {
53596
54788
  return matches;
53597
54789
  };
53598
54790
  exports.analyse = analyse;
53599
- var detectFile = (filepath, opts = {}) => new Promise((resolve3, reject) => {
54791
+ var detectFile = (filepath, opts = {}) => new Promise((resolve4, reject) => {
53600
54792
  let fd;
53601
54793
  const fs = (0, node_1.default)();
53602
54794
  const handler = (err, buffer) => {
@@ -53606,7 +54798,7 @@ var require_lib2 = __commonJS((exports) => {
53606
54798
  if (err) {
53607
54799
  reject(err);
53608
54800
  } else if (buffer) {
53609
- resolve3((0, exports.detect)(buffer));
54801
+ resolve4((0, exports.detect)(buffer));
53610
54802
  } else {
53611
54803
  reject(new Error("No error and no buffer received"));
53612
54804
  }
@@ -57361,7 +58553,7 @@ var init_RemoveFileError = __esm(() => {
57361
58553
 
57362
58554
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
57363
58555
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
57364
- 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";
57365
58557
  import path from "path";
57366
58558
  import os from "os";
57367
58559
  import { randomUUID as randomUUID4 } from "crypto";
@@ -57470,14 +58662,14 @@ class ExternalEditor {
57470
58662
  if (Object.prototype.hasOwnProperty.call(this.fileOptions, "mode")) {
57471
58663
  opt.mode = this.fileOptions.mode;
57472
58664
  }
57473
- writeFileSync13(this.tempFile, this.text, opt);
58665
+ writeFileSync14(this.tempFile, this.text, opt);
57474
58666
  } catch (createFileError) {
57475
58667
  throw new CreateFileError(createFileError);
57476
58668
  }
57477
58669
  }
57478
58670
  readTemporaryFile() {
57479
58671
  try {
57480
- const tempFileBuffer = readFileSync17(this.tempFile);
58672
+ const tempFileBuffer = readFileSync19(this.tempFile);
57481
58673
  if (tempFileBuffer.length === 0) {
57482
58674
  this.text = "";
57483
58675
  } else {
@@ -58672,15 +59864,15 @@ async function geminiQuotaHandler() {
58672
59864
  }
58673
59865
  }
58674
59866
  async function codexQuotaHandler() {
58675
- const { readFileSync: readFileSync18, existsSync: existsSync20 } = await import("fs");
58676
- const { join: join22 } = await import("path");
58677
- const { homedir: homedir21 } = await import("os");
58678
- const credPath = join22(homedir21(), ".claudish", "codex-oauth.json");
58679
- 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)) {
58680
59872
  console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
58681
59873
  process.exit(1);
58682
59874
  }
58683
- const creds = JSON.parse(readFileSync18(credPath, "utf-8"));
59875
+ const creds = JSON.parse(readFileSync20(credPath, "utf-8"));
58684
59876
  let email3 = "";
58685
59877
  try {
58686
59878
  const parts = creds.access_token.split(".");
@@ -58732,9 +59924,9 @@ async function codexQuotaHandler() {
58732
59924
  }
58733
59925
  let modelSlugs = [];
58734
59926
  try {
58735
- const modelsPath = join22(homedir21(), ".codex", "models_cache.json");
58736
- if (existsSync20(modelsPath)) {
58737
- 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"));
58738
59930
  modelSlugs = (cache2.models || []).map((m) => m.slug || m.id).filter(Boolean);
58739
59931
  }
58740
59932
  } catch {}
@@ -58867,7 +60059,7 @@ __export(exports_config, {
58867
60059
  DEFAULT_PORT_RANGE: () => DEFAULT_PORT_RANGE
58868
60060
  });
58869
60061
  var DEFAULT_PORT_RANGE, ENV, OPENROUTER_API_URL2 = "https://openrouter.ai/api/v1/chat/completions", OPENROUTER_HEADERS;
58870
- var init_config = __esm(() => {
60062
+ var init_config2 = __esm(() => {
58871
60063
  DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
58872
60064
  ENV = {
58873
60065
  OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
@@ -59162,62 +60354,6 @@ var init_model_discovery = __esm(() => {
59162
60354
  _cache2 = new Map;
59163
60355
  });
59164
60356
 
59165
- // src/providers/ollama-discovery.ts
59166
- function ollamaBaseUrl() {
59167
- return process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434";
59168
- }
59169
- async function fetchOllamaModels2(options = {}) {
59170
- const { enrichCapabilities = true } = options;
59171
- const host = ollamaBaseUrl();
59172
- try {
59173
- const response = await fetch(`${host}/api/tags`, {
59174
- signal: AbortSignal.timeout(3000)
59175
- });
59176
- if (!response.ok)
59177
- return [];
59178
- const data = await response.json();
59179
- const models = data.models || [];
59180
- const enriched = await Promise.all(models.map(async (m) => {
59181
- let capabilities = [];
59182
- if (enrichCapabilities) {
59183
- try {
59184
- const showResponse = await fetch(`${host}/api/show`, {
59185
- method: "POST",
59186
- headers: { "Content-Type": "application/json" },
59187
- body: JSON.stringify({ name: m.name }),
59188
- signal: AbortSignal.timeout(2000)
59189
- });
59190
- if (showResponse.ok) {
59191
- const showData = await showResponse.json();
59192
- capabilities = showData.capabilities || [];
59193
- }
59194
- } catch {}
59195
- }
59196
- const nameLower = String(m.name).toLowerCase();
59197
- const supportsTools = capabilities.includes("tools");
59198
- const isEmbeddingModel = capabilities.includes("embedding") || nameLower.includes("embed");
59199
- const sizeInfo = m.details?.parameter_size || "unknown size";
59200
- const toolsIndicator = supportsTools ? "\u2713 tools" : "\u2717 no tools";
59201
- return {
59202
- id: `ollama/${m.name}`,
59203
- name: m.name,
59204
- description: `Local Ollama model (${sizeInfo}, ${toolsIndicator})`,
59205
- provider: "ollama",
59206
- pricing: { prompt: "0", completion: "0" },
59207
- isLocal: true,
59208
- supportsTools,
59209
- isEmbeddingModel,
59210
- capabilities,
59211
- details: m.details,
59212
- size: m.size
59213
- };
59214
- }));
59215
- return enriched.filter((m) => !m.isEmbeddingModel);
59216
- } catch {
59217
- return [];
59218
- }
59219
- }
59220
-
59221
60357
  // src/model-selector.ts
59222
60358
  var exports_model_selector = {};
59223
60359
  __export(exports_model_selector, {
@@ -59749,7 +60885,7 @@ async function selectModelFromProvider(provider, tierName, recommendedModels, _f
59749
60885
  }
59750
60886
  }
59751
60887
  if (provider === "ollama") {
59752
- const ollamaModels = await fetchOllamaModels2({ enrichCapabilities: false });
60888
+ const ollamaModels = await fetchOllamaModels({ enrichCapabilities: false });
59753
60889
  const chatModels = ollamaModels.map((m) => ({
59754
60890
  id: m.name,
59755
60891
  name: m.name,
@@ -60138,19 +61274,19 @@ async function probeLink(proxyUrl, link, timeoutMs) {
60138
61274
  }
60139
61275
  const streamResult = await consumeProbeStream(response, timeoutMs, startedAt);
60140
61276
  const totalMs = Date.now() - startedAt;
60141
- let timing;
61277
+ let timing2;
60142
61278
  if (streamResult.state === "live" && streamResult.ttftMs !== undefined && !streamResult.truncated) {
60143
61279
  const ttftMs = streamResult.ttftMs;
60144
61280
  const tokens = streamResult.tokens ?? 0;
60145
61281
  const streamMs = Math.max(STREAM_MS_FLOOR, totalMs - ttftMs);
60146
61282
  const tokensPerSec = tokens > 0 ? tokens / streamMs * 1000 : 0;
60147
- timing = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
61283
+ timing2 = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
60148
61284
  }
60149
61285
  const { ttftMs: _ttft, tokens: _tok, truncated: _trunc, ...rest } = streamResult;
60150
61286
  return annotateOAuthHint({
60151
61287
  ...rest,
60152
61288
  latencyMs: totalMs,
60153
- timing
61289
+ timing: timing2
60154
61290
  }, link.provider, isOAuth);
60155
61291
  }
60156
61292
  function annotateOAuthHint(result, provider, isOAuth) {
@@ -60747,8 +61883,8 @@ function breakdownNum(ms) {
60747
61883
  return formatLatency(ms);
60748
61884
  return `${Math.round(Math.max(0, ms))}`;
60749
61885
  }
60750
- function buildBarsLine(timing, scales, isFastest, usable) {
60751
- const t = timing;
61886
+ function buildBarsLine(timing2, scales, isFastest, usable) {
61887
+ const t = timing2;
60752
61888
  const showTokBar = usable >= PRINTER_BARS_FULL_WIDTH;
60753
61889
  const showBreakdown = usable >= PRINTER_BARS_FULL_WIDTH || usable >= PRINTER_BARS_NOTOK_WIDTH;
60754
61890
  const barCells = timelineBarCells(t.totalMs, scales.maxTotalMs, PRINTER_BAR_WIDTH);
@@ -62688,8 +63824,8 @@ async function startProbeTui(initial) {
62688
63824
  });
62689
63825
  const store = new ProbeStore(initial);
62690
63826
  let resolveQuit;
62691
- const quitPromise = new Promise((resolve3) => {
62692
- resolveQuit = resolve3;
63827
+ const quitPromise = new Promise((resolve4) => {
63828
+ resolveQuit = resolve4;
62693
63829
  });
62694
63830
  let quit = false;
62695
63831
  const onQuit = () => {
@@ -62753,22 +63889,22 @@ __export(exports_cli, {
62753
63889
  });
62754
63890
  import {
62755
63891
  copyFileSync as copyFileSync2,
62756
- existsSync as existsSync20,
62757
- mkdirSync as mkdirSync12,
62758
- readFileSync as readFileSync18,
63892
+ existsSync as existsSync21,
63893
+ mkdirSync as mkdirSync13,
63894
+ readFileSync as readFileSync20,
62759
63895
  readdirSync as readdirSync4,
62760
63896
  unlinkSync as unlinkSync7,
62761
- writeFileSync as writeFileSync14
63897
+ writeFileSync as writeFileSync15
62762
63898
  } from "fs";
62763
- import { homedir as homedir21 } from "os";
62764
- 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";
62765
63901
  import { fileURLToPath as fileURLToPath2 } from "url";
62766
63902
  function getVersion3() {
62767
63903
  return VERSION;
62768
63904
  }
62769
63905
  function clearAllModelCaches() {
62770
- const cacheDir = join22(homedir21(), ".claudish");
62771
- if (!existsSync20(cacheDir))
63906
+ const cacheDir = join24(homedir22(), ".claudish");
63907
+ if (!existsSync21(cacheDir))
62772
63908
  return;
62773
63909
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
62774
63910
  let cleared = 0;
@@ -62776,7 +63912,7 @@ function clearAllModelCaches() {
62776
63912
  const files = readdirSync4(cacheDir);
62777
63913
  for (const file2 of files) {
62778
63914
  if (cachePatterns.includes(file2)) {
62779
- unlinkSync7(join22(cacheDir, file2));
63915
+ unlinkSync7(join24(cacheDir, file2));
62780
63916
  cleared++;
62781
63917
  }
62782
63918
  }
@@ -63186,15 +64322,15 @@ Usage: claudish --models --provider <slug>`);
63186
64322
  });
63187
64323
  config3.resolvedDefaultProvider = resolved;
63188
64324
  if (resolved.legacyAutoPromoted && !config3.quiet) {
63189
- const markerFile = join22(homedir21(), ".claudish", ".legacy-litellm-hint-shown");
63190
- if (!existsSync20(markerFile)) {
64325
+ const markerFile = join24(homedir22(), ".claudish", ".legacy-litellm-hint-shown");
64326
+ if (!existsSync21(markerFile)) {
63191
64327
  const hint = buildLegacyHint(resolved);
63192
64328
  if (hint) {
63193
64329
  console.error(hint);
63194
64330
  }
63195
64331
  try {
63196
- mkdirSync12(dirname6(markerFile), { recursive: true });
63197
- writeFileSync14(markerFile, new Date().toISOString(), "utf-8");
64332
+ mkdirSync13(dirname8(markerFile), { recursive: true });
64333
+ writeFileSync15(markerFile, new Date().toISOString(), "utf-8");
63198
64334
  } catch {}
63199
64335
  }
63200
64336
  }
@@ -63300,7 +64436,7 @@ Local providers`);
63300
64436
  console.log(` ${"\u2500".repeat(70)}`);
63301
64437
  let ollamaLine = " Ollama: not running";
63302
64438
  try {
63303
- const ollamaModels = await fetchOllamaModels2();
64439
+ const ollamaModels = await fetchOllamaModels();
63304
64440
  if (ollamaModels.length > 0) {
63305
64441
  const toolCount = ollamaModels.filter((m) => m.supportsTools).length;
63306
64442
  ollamaLine = ` Ollama: ${ollamaModels.length} models installed (${toolCount} with tools) \u2014 use: claudish --model ollama@<name>`;
@@ -64254,8 +65390,8 @@ ${h("MORE INFO")}
64254
65390
  }
64255
65391
  function printAIAgentGuide() {
64256
65392
  try {
64257
- const guidePath = join22(__dirname3, "../AI_AGENT_GUIDE.md");
64258
- const guideContent = readFileSync18(guidePath, "utf-8");
65393
+ const guidePath = join24(__dirname3, "../AI_AGENT_GUIDE.md");
65394
+ const guideContent = readFileSync20(guidePath, "utf-8");
64259
65395
  console.log(guideContent);
64260
65396
  } catch (error46) {
64261
65397
  console.error("Error reading AI Agent Guide:");
@@ -64271,19 +65407,19 @@ async function initializeClaudishSkill() {
64271
65407
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
64272
65408
  `);
64273
65409
  const cwd = process.cwd();
64274
- const claudeDir = join22(cwd, ".claude");
64275
- const skillsDir = join22(claudeDir, "skills");
64276
- const claudishSkillDir = join22(skillsDir, "claudish-usage");
64277
- const skillFile = join22(claudishSkillDir, "SKILL.md");
64278
- 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)) {
64279
65415
  console.log("\u2705 Claudish skill already installed at:");
64280
65416
  console.log(` ${skillFile}
64281
65417
  `);
64282
65418
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
64283
65419
  return;
64284
65420
  }
64285
- const sourceSkillPath = join22(__dirname3, "../skills/claudish-usage/SKILL.md");
64286
- if (!existsSync20(sourceSkillPath)) {
65421
+ const sourceSkillPath = join24(__dirname3, "../skills/claudish-usage/SKILL.md");
65422
+ if (!existsSync21(sourceSkillPath)) {
64287
65423
  console.error("\u274C Error: Claudish skill file not found in installation.");
64288
65424
  console.error(` Expected at: ${sourceSkillPath}`);
64289
65425
  console.error(`
@@ -64292,16 +65428,16 @@ async function initializeClaudishSkill() {
64292
65428
  process.exit(1);
64293
65429
  }
64294
65430
  try {
64295
- if (!existsSync20(claudeDir)) {
64296
- mkdirSync12(claudeDir, { recursive: true });
65431
+ if (!existsSync21(claudeDir)) {
65432
+ mkdirSync13(claudeDir, { recursive: true });
64297
65433
  console.log("\uD83D\uDCC1 Created .claude/ directory");
64298
65434
  }
64299
- if (!existsSync20(skillsDir)) {
64300
- mkdirSync12(skillsDir, { recursive: true });
65435
+ if (!existsSync21(skillsDir)) {
65436
+ mkdirSync13(skillsDir, { recursive: true });
64301
65437
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
64302
65438
  }
64303
- if (!existsSync20(claudishSkillDir)) {
64304
- mkdirSync12(claudishSkillDir, { recursive: true });
65439
+ if (!existsSync21(claudishSkillDir)) {
65440
+ mkdirSync13(claudishSkillDir, { recursive: true });
64305
65441
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
64306
65442
  }
64307
65443
  copyFileSync2(sourceSkillPath, skillFile);
@@ -64358,7 +65494,7 @@ function printAvailableModels() {
64358
65494
  }
64359
65495
  var __filename3, __dirname3;
64360
65496
  var init_cli = __esm(() => {
64361
- init_config();
65497
+ init_config2();
64362
65498
  init_model_loader();
64363
65499
  init_model_selector();
64364
65500
  init_probe_results_printer();
@@ -64373,7 +65509,7 @@ var init_cli = __esm(() => {
64373
65509
  init_routing_rules();
64374
65510
  init_provider_resolver();
64375
65511
  __filename3 = fileURLToPath2(import.meta.url);
64376
- __dirname3 = dirname6(__filename3);
65512
+ __dirname3 = dirname8(__filename3);
64377
65513
  });
64378
65514
 
64379
65515
  // src/update-checker.ts
@@ -64385,33 +65521,33 @@ __export(exports_update_checker, {
64385
65521
  clearCache: () => clearCache,
64386
65522
  checkForUpdates: () => checkForUpdates
64387
65523
  });
64388
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync19, unlinkSync as unlinkSync8, writeFileSync as writeFileSync15 } from "fs";
64389
- import { homedir as homedir22, platform as platform2, tmpdir } from "os";
64390
- 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";
64391
65527
  function getCacheFilePath() {
64392
65528
  let cacheDir;
64393
65529
  if (isWindows) {
64394
- const localAppData = process.env.LOCALAPPDATA || join23(homedir22(), "AppData", "Local");
64395
- cacheDir = join23(localAppData, "claudish");
65530
+ const localAppData = process.env.LOCALAPPDATA || join25(homedir23(), "AppData", "Local");
65531
+ cacheDir = join25(localAppData, "claudish");
64396
65532
  } else {
64397
- cacheDir = join23(homedir22(), ".cache", "claudish");
65533
+ cacheDir = join25(homedir23(), ".cache", "claudish");
64398
65534
  }
64399
65535
  try {
64400
- if (!existsSync21(cacheDir)) {
64401
- mkdirSync13(cacheDir, { recursive: true });
65536
+ if (!existsSync22(cacheDir)) {
65537
+ mkdirSync14(cacheDir, { recursive: true });
64402
65538
  }
64403
- return join23(cacheDir, "update-check.json");
65539
+ return join25(cacheDir, "update-check.json");
64404
65540
  } catch {
64405
- return join23(tmpdir(), "claudish-update-check.json");
65541
+ return join25(tmpdir(), "claudish-update-check.json");
64406
65542
  }
64407
65543
  }
64408
65544
  function readCache() {
64409
65545
  try {
64410
65546
  const cachePath = getCacheFilePath();
64411
- if (!existsSync21(cachePath)) {
65547
+ if (!existsSync22(cachePath)) {
64412
65548
  return null;
64413
65549
  }
64414
- const data = JSON.parse(readFileSync19(cachePath, "utf-8"));
65550
+ const data = JSON.parse(readFileSync21(cachePath, "utf-8"));
64415
65551
  return data;
64416
65552
  } catch {
64417
65553
  return null;
@@ -64424,7 +65560,7 @@ function writeCache(latestVersion) {
64424
65560
  lastCheck: Date.now(),
64425
65561
  latestVersion
64426
65562
  };
64427
- writeFileSync15(cachePath, JSON.stringify(data), "utf-8");
65563
+ writeFileSync16(cachePath, JSON.stringify(data), "utf-8");
64428
65564
  } catch {}
64429
65565
  }
64430
65566
  function isCacheValid(cache2) {
@@ -64434,7 +65570,7 @@ function isCacheValid(cache2) {
64434
65570
  function clearCache() {
64435
65571
  try {
64436
65572
  const cachePath = getCacheFilePath();
64437
- if (existsSync21(cachePath)) {
65573
+ if (existsSync22(cachePath)) {
64438
65574
  unlinkSync8(cachePath);
64439
65575
  }
64440
65576
  } catch {}
@@ -64474,7 +65610,7 @@ async function fetchLatestVersionOrThrow(options = {}) {
64474
65610
  } catch (error46) {
64475
65611
  lastError = error46 instanceof Error && error46.name === "AbortError" ? new Error(`request timed out after ${timeoutMs}ms`) : error46 instanceof Error ? error46 : new Error(String(error46));
64476
65612
  if (attempt < retries) {
64477
- await new Promise((resolve3) => setTimeout(resolve3, 300 * (attempt + 1)));
65613
+ await new Promise((resolve4) => setTimeout(resolve4, 300 * (attempt + 1)));
64478
65614
  }
64479
65615
  } finally {
64480
65616
  clearTimeout(timeout);
@@ -65313,15 +66449,15 @@ var init_local_liveness = __esm(() => {
65313
66449
  });
65314
66450
 
65315
66451
  // src/providers/probe-catalog.ts
65316
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "fs";
65317
- import { homedir as homedir23 } from "os";
65318
- 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";
65319
66455
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
65320
- if (!existsSync22(path2))
66456
+ if (!existsSync23(path2))
65321
66457
  return null;
65322
66458
  let raw2;
65323
66459
  try {
65324
- raw2 = JSON.parse(readFileSync20(path2, "utf-8"));
66460
+ raw2 = JSON.parse(readFileSync22(path2, "utf-8"));
65325
66461
  } catch {
65326
66462
  return null;
65327
66463
  }
@@ -65330,8 +66466,8 @@ function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
65330
66466
  return raw2;
65331
66467
  }
65332
66468
  function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
65333
- mkdirSync14(dirname7(path2), { recursive: true });
65334
- writeFileSync16(path2, JSON.stringify(data), "utf-8");
66469
+ mkdirSync15(dirname9(path2), { recursive: true });
66470
+ writeFileSync17(path2, JSON.stringify(data), "utf-8");
65335
66471
  }
65336
66472
  function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
65337
66473
  if (!data?.generatedAt)
@@ -65450,7 +66586,7 @@ function isValidResponse(raw2) {
65450
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;
65451
66587
  var init_probe_catalog = __esm(() => {
65452
66588
  CACHE_TTL_MS4 = 60 * 60 * 1000;
65453
- PROBE_MODELS_CACHE_PATH = join24(homedir23(), ".claudish", "probe-models.json");
66589
+ PROBE_MODELS_CACHE_PATH = join26(homedir24(), ".claudish", "probe-models.json");
65454
66590
  });
65455
66591
 
65456
66592
  // src/tui/constants.ts
@@ -70207,14 +71343,14 @@ function App({ requestLogin } = {}) {
70207
71343
  return resolveSdkAuth({
70208
71344
  interactive: true,
70209
71345
  configAccount: readOnepasswordAccount(),
70210
- onNeedsPicker: (accounts) => new Promise((resolve3) => {
71346
+ onNeedsPicker: (accounts) => new Promise((resolve4) => {
70211
71347
  setOpAccounts(accounts);
70212
71348
  setOpAccountCursor(0);
70213
71349
  opPickerResolver.current = (url2) => {
70214
71350
  if (url2?.trim())
70215
71351
  saveOnepasswordAccount(url2.trim(), "global");
70216
71352
  opPickerResolver.current = null;
70217
- resolve3(url2);
71353
+ resolve4(url2);
70218
71354
  };
70219
71355
  setMode("pick_op_account");
70220
71356
  })
@@ -71660,8 +72796,8 @@ async function startConfigTui() {
71660
72796
  const renderer = await createCliRenderer2({
71661
72797
  exitOnCtrlC: false
71662
72798
  });
71663
- await new Promise((resolve3) => {
71664
- renderer.once("destroy", () => resolve3());
72799
+ await new Promise((resolve4) => {
72800
+ renderer.once("destroy", () => resolve4());
71665
72801
  createRoot2(renderer).render(/* @__PURE__ */ jsxDEV17(App, {
71666
72802
  requestLogin
71667
72803
  }, undefined, false, undefined, this));
@@ -71783,16 +72919,16 @@ __export(exports_claude_runner, {
71783
72919
  });
71784
72920
  import { spawn as spawn4 } from "child_process";
71785
72921
  import {
71786
- closeSync as closeSync4,
71787
- existsSync as existsSync23,
71788
- mkdirSync as mkdirSync15,
71789
- openSync as openSync4,
71790
- readFileSync as readFileSync21,
72922
+ closeSync as closeSync5,
72923
+ existsSync as existsSync24,
72924
+ mkdirSync as mkdirSync16,
72925
+ openSync as openSync5,
72926
+ readFileSync as readFileSync23,
71791
72927
  unlinkSync as unlinkSync9,
71792
- writeFileSync as writeFileSync17
72928
+ writeFileSync as writeFileSync18
71793
72929
  } from "fs";
71794
- import { homedir as homedir24, tmpdir as tmpdir2 } from "os";
71795
- import { join as join25 } from "path";
72930
+ import { homedir as homedir25, tmpdir as tmpdir2 } from "os";
72931
+ import { join as join27 } from "path";
71796
72932
  import { isatty } from "tty";
71797
72933
  function releaseTerminalIsolation() {
71798
72934
  if (!restoreTerminal)
@@ -71827,14 +72963,14 @@ function isProxyAuthMode(config3) {
71827
72963
  }
71828
72964
  function managedSettingsPath() {
71829
72965
  if (isWindows2()) {
71830
- return join25(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
72966
+ return join27(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
71831
72967
  }
71832
72968
  if (process.platform === "darwin") {
71833
72969
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
71834
72970
  }
71835
72971
  return "/etc/claude-code/managed-settings.json";
71836
72972
  }
71837
- function managedSettingsForcesClaudeAi(readFile = readFileSync21) {
72973
+ function managedSettingsForcesClaudeAi(readFile = readFileSync23) {
71838
72974
  try {
71839
72975
  const raw2 = readFile(managedSettingsPath(), "utf-8");
71840
72976
  const parsed = JSON.parse(raw2);
@@ -71848,9 +72984,9 @@ function isWindows2() {
71848
72984
  }
71849
72985
  function createStatusLineScript(tokenFilePath) {
71850
72986
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
71851
- const claudishDir = join25(homeDir, ".claudish");
72987
+ const claudishDir = join27(homeDir, ".claudish");
71852
72988
  const timestamp = Date.now();
71853
- const scriptPath = join25(claudishDir, `status-${timestamp}.js`);
72989
+ const scriptPath = join27(claudishDir, `status-${timestamp}.js`);
71854
72990
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
71855
72991
  const script = `
71856
72992
  const fs = require('fs');
@@ -71942,18 +73078,18 @@ process.stdin.on('end', () => {
71942
73078
  }
71943
73079
  });
71944
73080
  `;
71945
- writeFileSync17(scriptPath, script, "utf-8");
73081
+ writeFileSync18(scriptPath, script, "utf-8");
71946
73082
  return scriptPath;
71947
73083
  }
71948
73084
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
71949
73085
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
71950
- const claudishDir = join25(homeDir, ".claudish");
73086
+ const claudishDir = join27(homeDir, ".claudish");
71951
73087
  try {
71952
- mkdirSync15(claudishDir, { recursive: true });
73088
+ mkdirSync16(claudishDir, { recursive: true });
71953
73089
  } catch {}
71954
73090
  const timestamp = Date.now();
71955
- const tempPath = join25(claudishDir, `settings-${timestamp}.json`);
71956
- const tokenFilePath = join25(claudishDir, `tokens-${port}.json`);
73091
+ const tempPath = join27(claudishDir, `settings-${timestamp}.json`);
73092
+ const tokenFilePath = join27(claudishDir, `tokens-${port}.json`);
71957
73093
  let statusCommand;
71958
73094
  if (isWindows2()) {
71959
73095
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -71975,7 +73111,7 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode) {
71975
73111
  padding: 0
71976
73112
  };
71977
73113
  const settings = buildClaudishSettingsOverlay(statusLine, proxyAuthMode);
71978
- writeFileSync17(tempPath, JSON.stringify(settings, null, 2), "utf-8");
73114
+ writeFileSync18(tempPath, JSON.stringify(settings, null, 2), "utf-8");
71979
73115
  return { path: tempPath, statusLine };
71980
73116
  }
71981
73117
  function buildClaudishSettingsOverlay(statusLine, proxyAuthMode) {
@@ -71996,7 +73132,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
71996
73132
  if (userSettingsValue.trimStart().startsWith("{")) {
71997
73133
  userSettings = JSON.parse(userSettingsValue);
71998
73134
  } else {
71999
- const rawUserSettings = readFileSync21(userSettingsValue, "utf-8");
73135
+ const rawUserSettings = readFileSync23(userSettingsValue, "utf-8");
72000
73136
  userSettings = JSON.parse(rawUserSettings);
72001
73137
  }
72002
73138
  userSettings.statusLine = statusLine;
@@ -72006,7 +73142,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
72006
73142
  if (proxyAuthMode && !("forceLoginMethod" in userSettings)) {
72007
73143
  userSettings.forceLoginMethod = "console";
72008
73144
  }
72009
- writeFileSync17(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
73145
+ writeFileSync18(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
72010
73146
  } catch {
72011
73147
  if (!config3.quiet) {
72012
73148
  console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
@@ -72167,8 +73303,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
72167
73303
  console.error("Install it from: https://claude.com/claude-code");
72168
73304
  console.error(`
72169
73305
  Or set CLAUDE_PATH to your custom installation:`);
72170
- const home = homedir24();
72171
- 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");
72172
73308
  console.error(` export CLAUDE_PATH=${localPath}`);
72173
73309
  process.exit(1);
72174
73310
  }
@@ -72179,11 +73315,11 @@ Or set CLAUDE_PATH to your custom installation:`);
72179
73315
  const childWantsTty = config3.interactive && !process.stdout.isTTY && Boolean(process.stdin.isTTY);
72180
73316
  if (childWantsTty) {
72181
73317
  try {
72182
- const fd = openSync4("/dev/fd/0", "r+");
73318
+ const fd = openSync5("/dev/fd/0", "r+");
72183
73319
  if (isatty(fd)) {
72184
73320
  ttyFd = fd;
72185
73321
  } else {
72186
- closeSync4(fd);
73322
+ closeSync5(fd);
72187
73323
  }
72188
73324
  } catch {
72189
73325
  ttyFd = undefined;
@@ -72206,15 +73342,15 @@ Or set CLAUDE_PATH to your custom installation:`);
72206
73342
  const fdToClose = ttyFd;
72207
73343
  proc.on("spawn", () => {
72208
73344
  try {
72209
- closeSync4(fdToClose);
73345
+ closeSync5(fdToClose);
72210
73346
  } catch {}
72211
73347
  });
72212
73348
  }
72213
73349
  setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
72214
- const exitCode = await new Promise((resolve3) => {
73350
+ const exitCode = await new Promise((resolve4) => {
72215
73351
  proc.on("exit", (code) => {
72216
73352
  setClaudeCodeRunning(false);
72217
- resolve3(code ?? 1);
73353
+ resolve4(code ?? 1);
72218
73354
  });
72219
73355
  });
72220
73356
  releaseTerminalIsolation();
@@ -72248,23 +73384,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
72248
73384
  async function findClaudeBinary() {
72249
73385
  const isWindows3 = process.platform === "win32";
72250
73386
  if (process.env.CLAUDE_PATH) {
72251
- if (existsSync23(process.env.CLAUDE_PATH)) {
73387
+ if (existsSync24(process.env.CLAUDE_PATH)) {
72252
73388
  return process.env.CLAUDE_PATH;
72253
73389
  }
72254
73390
  }
72255
- const home = homedir24();
72256
- const localPath = isWindows3 ? join25(home, ".claude", "local", "claude.exe") : join25(home, ".claude", "local", "claude");
72257
- 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)) {
72258
73394
  return localPath;
72259
73395
  }
72260
73396
  if (isWindows3) {
72261
73397
  const windowsPaths = [
72262
- join25(home, "AppData", "Roaming", "npm", "claude.cmd"),
72263
- join25(home, ".npm-global", "claude.cmd"),
72264
- 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")
72265
73401
  ];
72266
73402
  for (const path2 of windowsPaths) {
72267
- if (existsSync23(path2)) {
73403
+ if (existsSync24(path2)) {
72268
73404
  return path2;
72269
73405
  }
72270
73406
  }
@@ -72272,14 +73408,14 @@ async function findClaudeBinary() {
72272
73408
  const commonPaths = [
72273
73409
  "/usr/local/bin/claude",
72274
73410
  "/opt/homebrew/bin/claude",
72275
- join25(home, ".npm-global/bin/claude"),
72276
- join25(home, ".local/bin/claude"),
72277
- 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"),
72278
73414
  "/data/data/com.termux/files/usr/bin/claude",
72279
- join25(home, "../usr/bin/claude")
73415
+ join27(home, "../usr/bin/claude")
72280
73416
  ];
72281
73417
  for (const path2 of commonPaths) {
72282
- if (existsSync23(path2)) {
73418
+ if (existsSync24(path2)) {
72283
73419
  return path2;
72284
73420
  }
72285
73421
  }
@@ -72294,9 +73430,9 @@ async function findClaudeBinary() {
72294
73430
  proc.stdout?.on("data", (data) => {
72295
73431
  output += data.toString();
72296
73432
  });
72297
- const exitCode = await new Promise((resolve3) => {
73433
+ const exitCode = await new Promise((resolve4) => {
72298
73434
  proc.on("exit", (code) => {
72299
- resolve3(code ?? 1);
73435
+ resolve4(code ?? 1);
72300
73436
  });
72301
73437
  });
72302
73438
  if (exitCode === 0 && output.trim()) {
@@ -72319,7 +73455,7 @@ async function checkClaudeInstalled() {
72319
73455
  var restoreTerminal = null, MIN_AUTO_COMPACT_WINDOW = 200000;
72320
73456
  var init_claude_runner = __esm(() => {
72321
73457
  init_model_catalog();
72322
- init_config();
73458
+ init_config2();
72323
73459
  init_logger();
72324
73460
  init_profile_config();
72325
73461
  init_model_discovery();
@@ -72336,18 +73472,18 @@ __export(exports_diag_output, {
72336
73472
  NullDiagOutput: () => NullDiagOutput,
72337
73473
  LogFileDiagOutput: () => LogFileDiagOutput
72338
73474
  });
72339
- import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync16, unlinkSync as unlinkSync10, writeFileSync as writeFileSync18 } from "fs";
72340
- import { homedir as homedir25 } from "os";
72341
- 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";
72342
73478
  function getClaudishDir() {
72343
- const dir = join26(homedir25(), ".claudish");
73479
+ const dir = join28(homedir26(), ".claudish");
72344
73480
  try {
72345
- mkdirSync16(dir, { recursive: true });
73481
+ mkdirSync17(dir, { recursive: true });
72346
73482
  } catch {}
72347
73483
  return dir;
72348
73484
  }
72349
73485
  function getDiagLogPath() {
72350
- return join26(getClaudishDir(), `diag-${process.pid}.log`);
73486
+ return join28(getClaudishDir(), `diag-${process.pid}.log`);
72351
73487
  }
72352
73488
 
72353
73489
  class LogFileDiagOutput {
@@ -72356,7 +73492,7 @@ class LogFileDiagOutput {
72356
73492
  constructor() {
72357
73493
  this.logPath = getDiagLogPath();
72358
73494
  try {
72359
- writeFileSync18(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
73495
+ writeFileSync19(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
72360
73496
  `);
72361
73497
  } catch {}
72362
73498
  this.stream = createWriteStream3(this.logPath, { flags: "a" });
@@ -72558,9 +73694,9 @@ __export(exports_team_grid, {
72558
73694
  });
72559
73695
  import { spawn as spawn5 } from "child_process";
72560
73696
  import { execSync as execSync2 } from "child_process";
72561
- 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";
72562
73698
  import { connect as netConnect } from "net";
72563
- import { dirname as dirname8, join as join27 } from "path";
73699
+ import { dirname as dirname10, join as join29 } from "path";
72564
73700
  import { setTimeout as wait } from "timers/promises";
72565
73701
  import { fileURLToPath as fileURLToPath3 } from "url";
72566
73702
  function resolveRouteInfo(modelId) {
@@ -72653,21 +73789,21 @@ function buildPaneHeader(model, prompt, bg) {
72653
73789
  }
72654
73790
  function findMagmuxBinary() {
72655
73791
  const thisFile = fileURLToPath3(import.meta.url);
72656
- const thisDir = dirname8(thisFile);
72657
- const pkgRoot = join27(thisDir, "..");
73792
+ const thisDir = dirname10(thisFile);
73793
+ const pkgRoot = join29(thisDir, "..");
72658
73794
  const platform3 = process.platform;
72659
73795
  const arch = process.arch;
72660
- const bundledMagmux = join27(pkgRoot, "native", `magmux-${platform3}-${arch}`);
72661
- if (existsSync24(bundledMagmux))
73796
+ const bundledMagmux = join29(pkgRoot, "native", `magmux-${platform3}-${arch}`);
73797
+ if (existsSync25(bundledMagmux))
72662
73798
  return bundledMagmux;
72663
73799
  try {
72664
73800
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
72665
73801
  let searchDir = pkgRoot;
72666
73802
  for (let i = 0;i < 5; i++) {
72667
- const candidate = join27(searchDir, "node_modules", pkgName, "bin", "magmux");
72668
- if (existsSync24(candidate))
73803
+ const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
73804
+ if (existsSync25(candidate))
72669
73805
  return candidate;
72670
- const parent = dirname8(searchDir);
73806
+ const parent = dirname10(searchDir);
72671
73807
  if (parent === searchDir)
72672
73808
  break;
72673
73809
  searchDir = parent;
@@ -72684,11 +73820,11 @@ function findMagmuxBinary() {
72684
73820
  async function subscribeToMagmux(sockPath, onEvent) {
72685
73821
  let client = null;
72686
73822
  for (let attempt = 0;attempt < 40; attempt++) {
72687
- if (existsSync24(sockPath)) {
73823
+ if (existsSync25(sockPath)) {
72688
73824
  try {
72689
- client = await new Promise((resolve3, reject) => {
73825
+ client = await new Promise((resolve4, reject) => {
72690
73826
  const s = netConnect(sockPath);
72691
- s.once("connect", () => resolve3(s));
73827
+ s.once("connect", () => resolve4(s));
72692
73828
  s.once("error", reject);
72693
73829
  });
72694
73830
  break;
@@ -72699,7 +73835,7 @@ async function subscribeToMagmux(sockPath, onEvent) {
72699
73835
  if (!client) {
72700
73836
  return { results: null, client: null };
72701
73837
  }
72702
- return await new Promise((resolve3) => {
73838
+ return await new Promise((resolve4) => {
72703
73839
  let buf = "";
72704
73840
  let finalResults = null;
72705
73841
  client.on("data", (chunk) => {
@@ -72722,7 +73858,7 @@ async function subscribeToMagmux(sockPath, onEvent) {
72722
73858
  } catch {}
72723
73859
  }
72724
73860
  });
72725
- const done = () => resolve3({ results: finalResults, client });
73861
+ const done = () => resolve4({ results: finalResults, client });
72726
73862
  client.once("end", done);
72727
73863
  client.once("close", done);
72728
73864
  client.once("error", done);
@@ -72771,9 +73907,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
72771
73907
  const keep = opts?.keep ?? false;
72772
73908
  const manifest = setupSession(sessionPath, models, input);
72773
73909
  const startedAt = new Date().toISOString();
72774
- const gridfilePath = join27(sessionPath, "gridfile.txt");
72775
- const prompt = readFileSync22(join27(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
72776
- 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");
72777
73913
  const usedBannerColors = new Set;
72778
73914
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
72779
73915
  const model = manifest.models[anonId].model;
@@ -72784,7 +73920,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
72784
73920
  const header = buildPaneHeader(model, rawPrompt, bg);
72785
73921
  return `${header} claudish --model ${model} -y --quiet '${prompt}'`;
72786
73922
  });
72787
- writeFileSync19(gridfilePath, `${gridLines.join(`
73923
+ writeFileSync20(gridfilePath, `${gridLines.join(`
72788
73924
  `)}
72789
73925
  `, "utf-8");
72790
73926
  const magmuxPath = findMagmuxBinary();
@@ -72798,14 +73934,14 @@ async function runWithGrid(sessionPath, models, input, opts) {
72798
73934
  });
72799
73935
  const sockPath = `/tmp/magmux-${proc.pid}.sock`;
72800
73936
  const subscription = subscribeToMagmux(sockPath);
72801
- const procExit = new Promise((resolve3) => {
72802
- proc.on("exit", () => resolve3());
72803
- proc.on("error", () => resolve3());
73937
+ const procExit = new Promise((resolve4) => {
73938
+ proc.on("exit", () => resolve4());
73939
+ proc.on("error", () => resolve4());
72804
73940
  });
72805
73941
  const [{ results }] = await Promise.all([subscription, procExit]);
72806
73942
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
72807
- const statusPath = join27(sessionPath, "status.json");
72808
- 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");
72809
73945
  return status;
72810
73946
  }
72811
73947
  var BANNER_BG_COLORS;
@@ -72828,8 +73964,8 @@ var init_team_grid = __esm(() => {
72828
73964
  init_op_source();
72829
73965
  init_startup_trace();
72830
73966
  var import_dotenv3 = __toESM(require_main(), 1);
72831
- import { existsSync as existsSync25, readFileSync as readFileSync23 } from "fs";
72832
- import { join as join28, resolve as resolve3 } from "path";
73967
+ import { existsSync as existsSync26, readFileSync as readFileSync25 } from "fs";
73968
+ import { join as join30, resolve as resolve4 } from "path";
72833
73969
  import_dotenv3.config({ quiet: true });
72834
73970
  function classifyStartupKind() {
72835
73971
  const argv = process.argv.slice(2);
@@ -72927,8 +74063,8 @@ async function applyOpImport() {
72927
74063
  async function applyConfigOverride() {
72928
74064
  const { planConfigOverride: planConfigOverride2, setConfigFileOverride: setConfigFileOverride2 } = await Promise.resolve().then(() => exports_config_override);
72929
74065
  const plan = planConfigOverride2(process.argv.slice(2), process.env, {
72930
- resolve: resolve3,
72931
- exists: existsSync25
74066
+ resolve: resolve4,
74067
+ exists: existsSync26
72932
74068
  });
72933
74069
  if (plan.kind === "none")
72934
74070
  return;
@@ -73036,7 +74172,7 @@ async function runCli() {
73036
74172
  const endImports = beginSpan("startup:cli-imports");
73037
74173
  const { checkClaudeInstalled: checkClaudeInstalled2, runClaudeWithProxy: runClaudeWithProxy2 } = await Promise.resolve().then(() => (init_claude_runner(), exports_claude_runner));
73038
74174
  const { parseArgs: parseArgs2, getVersion: getVersion4 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
73039
- const { DEFAULT_PORT_RANGE: DEFAULT_PORT_RANGE2 } = await Promise.resolve().then(() => (init_config(), exports_config));
74175
+ const { DEFAULT_PORT_RANGE: DEFAULT_PORT_RANGE2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
73040
74176
  const { selectModel: selectModel2, promptForApiKey: promptForApiKey2 } = await Promise.resolve().then(() => (init_model_selector(), exports_model_selector));
73041
74177
  const {
73042
74178
  resolveModelProvider: resolveModelProvider2,
@@ -73063,14 +74199,14 @@ async function runCli() {
73063
74199
  if (cliConfig.team && cliConfig.team.length > 0) {
73064
74200
  let prompt = cliConfig.claudeArgs.join(" ");
73065
74201
  if (cliConfig.inputFile) {
73066
- prompt = readFileSync23(cliConfig.inputFile, "utf-8");
74202
+ prompt = readFileSync25(cliConfig.inputFile, "utf-8");
73067
74203
  }
73068
74204
  if (!prompt.trim()) {
73069
74205
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
73070
74206
  process.exit(1);
73071
74207
  }
73072
74208
  const mode = cliConfig.teamMode ?? "default";
73073
- const sessionPath = join28(process.cwd(), `.claudish-team-${Date.now()}`);
74209
+ const sessionPath = join30(process.cwd(), `.claudish-team-${Date.now()}`);
73074
74210
  if (mode === "json") {
73075
74211
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
73076
74212
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -73080,9 +74216,9 @@ async function runCli() {
73080
74216
  });
73081
74217
  const result = { ...status2, responses: {} };
73082
74218
  for (const anonId of Object.keys(status2.models)) {
73083
- const responsePath = join28(sessionPath, `response-${anonId}.md`);
74219
+ const responsePath = join30(sessionPath, `response-${anonId}.md`);
73084
74220
  try {
73085
- const raw2 = readFileSync23(responsePath, "utf-8").trim();
74221
+ const raw2 = readFileSync25(responsePath, "utf-8").trim();
73086
74222
  try {
73087
74223
  result.responses[anonId] = JSON.parse(raw2);
73088
74224
  } catch {
@@ -73129,11 +74265,11 @@ Team Status`);
73129
74265
  You can disable it anytime with: --no-auto-approve
73130
74266
 
73131
74267
  `);
73132
- const answer = await new Promise((resolve4) => {
74268
+ const answer = await new Promise((resolve5) => {
73133
74269
  const rl = createInterface2({ input: process.stdin, output: process.stderr });
73134
74270
  rl.question("Enable auto-approve? [Y/n] ", (ans) => {
73135
74271
  rl.close();
73136
- resolve4(ans.trim().toLowerCase());
74272
+ resolve5(ans.trim().toLowerCase());
73137
74273
  });
73138
74274
  });
73139
74275
  const declined = answer === "n" || answer === "no";