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.
- package/dist/index.js +1715 -579
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -651,7 +651,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/version.ts
|
|
654
|
-
var VERSION = "7.
|
|
654
|
+
var VERSION = "7.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
|
|
1304
|
+
import { copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1189
1305
|
import { createRequire } from "module";
|
|
1190
|
-
import { homedir as
|
|
1191
|
-
import { dirname as
|
|
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 ??
|
|
1198
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
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
|
|
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
|
|
4258
|
+
return null;
|
|
4099
4259
|
if (env.OP_SERVICE_ACCOUNT_TOKEN)
|
|
4100
|
-
return
|
|
4101
|
-
return
|
|
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
|
-
${
|
|
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 (!
|
|
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
|
-
|
|
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
|
|
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
|
-
})
|
|
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
|
|
4427
|
-
import { homedir as
|
|
4428
|
-
import { join as
|
|
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(
|
|
4706
|
+
const configPath = activeGlobalConfigFile(join6(homedir6(), ".claudish", "config.json"));
|
|
4521
4707
|
if (!existsSync4(configPath))
|
|
4522
4708
|
return {};
|
|
4523
|
-
return JSON.parse(
|
|
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 {
|
|
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
|
|
26942
|
-
import { homedir as
|
|
26943
|
-
import { dirname as
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
27224
|
+
const candidate = join7(dir, LOCAL_CONFIG_FILENAME);
|
|
27032
27225
|
if (existsSync5(candidate))
|
|
27033
27226
|
return candidate;
|
|
27034
|
-
if (existsSync5(
|
|
27227
|
+
if (existsSync5(join7(dir, ".git"))) {
|
|
27035
27228
|
return candidate;
|
|
27036
27229
|
}
|
|
27037
|
-
dir =
|
|
27230
|
+
dir = dirname4(dir);
|
|
27038
27231
|
}
|
|
27039
|
-
return
|
|
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(
|
|
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 =
|
|
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 =
|
|
27316
|
-
CONFIG_FILE =
|
|
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
|
|
28044
|
-
import { join as
|
|
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(
|
|
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
|
|
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
|
|
28165
|
-
import { join as
|
|
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 =
|
|
28192
|
-
return
|
|
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 =
|
|
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 =
|
|
28508
|
+
const claudishDir = join9(homedir9(), ".claudish");
|
|
28316
28509
|
if (!existsSync7(claudishDir)) {
|
|
28317
|
-
const { mkdirSync:
|
|
28318
|
-
|
|
28510
|
+
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
28511
|
+
mkdirSync6(claudishDir, { recursive: true });
|
|
28319
28512
|
}
|
|
28320
|
-
const fd =
|
|
28513
|
+
const fd = openSync2(credPath, "w", 384);
|
|
28321
28514
|
try {
|
|
28322
28515
|
const data = JSON.stringify(credentials, null, 2);
|
|
28323
|
-
|
|
28516
|
+
writeSync2(fd, data, 0, "utf-8");
|
|
28324
28517
|
} finally {
|
|
28325
|
-
|
|
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
|
|
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
|
|
28629
|
-
import { join as
|
|
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 =
|
|
28656
|
-
return
|
|
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 =
|
|
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 =
|
|
28966
|
+
const claudishDir = join10(homedir10(), ".claudish");
|
|
28774
28967
|
if (!existsSync8(claudishDir)) {
|
|
28775
|
-
const { mkdirSync:
|
|
28776
|
-
|
|
28968
|
+
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
28969
|
+
mkdirSync6(claudishDir, { recursive: true });
|
|
28777
28970
|
}
|
|
28778
|
-
const fd =
|
|
28971
|
+
const fd = openSync3(credPath, "w", 384);
|
|
28779
28972
|
try {
|
|
28780
28973
|
const data = JSON.stringify(credentials, null, 2);
|
|
28781
|
-
|
|
28974
|
+
writeSync3(fd, data, 0, "utf-8");
|
|
28782
28975
|
} finally {
|
|
28783
|
-
|
|
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
|
|
29138
|
-
import { homedir as
|
|
29139
|
-
import { join as
|
|
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 =
|
|
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(
|
|
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
|
|
29259
|
-
import { homedir as
|
|
29260
|
-
import { join as
|
|
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 =
|
|
29289
|
-
return
|
|
29481
|
+
const claudishDir = join12(homedir12(), ".claudish");
|
|
29482
|
+
return join12(claudishDir, "kimi-oauth.json");
|
|
29290
29483
|
}
|
|
29291
29484
|
getDeviceIdPath() {
|
|
29292
|
-
const claudishDir =
|
|
29293
|
-
return
|
|
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 =
|
|
29490
|
+
const claudishDir = join12(homedir12(), ".claudish");
|
|
29298
29491
|
if (!existsSync10(claudishDir)) {
|
|
29299
|
-
const { mkdirSync:
|
|
29300
|
-
|
|
29492
|
+
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
29493
|
+
mkdirSync6(claudishDir, { recursive: true });
|
|
29301
29494
|
}
|
|
29302
29495
|
if (existsSync10(deviceIdPath)) {
|
|
29303
29496
|
try {
|
|
29304
|
-
const deviceId2 =
|
|
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 =
|
|
29507
|
+
const fd = openSync4(deviceIdPath, "w", 384);
|
|
29315
29508
|
try {
|
|
29316
|
-
|
|
29509
|
+
writeSync4(fd, deviceId, 0, "utf-8");
|
|
29317
29510
|
} finally {
|
|
29318
|
-
|
|
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":
|
|
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 =
|
|
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 =
|
|
29771
|
+
const claudishDir = join12(homedir12(), ".claudish");
|
|
29579
29772
|
if (!existsSync10(claudishDir)) {
|
|
29580
|
-
const { mkdirSync:
|
|
29581
|
-
|
|
29773
|
+
const { mkdirSync: mkdirSync6 } = __require("fs");
|
|
29774
|
+
mkdirSync6(claudishDir, { recursive: true });
|
|
29582
29775
|
}
|
|
29583
|
-
const fd =
|
|
29776
|
+
const fd = openSync4(credPath, "w", 384);
|
|
29584
29777
|
try {
|
|
29585
29778
|
const data = JSON.stringify(credentials, null, 2);
|
|
29586
|
-
|
|
29779
|
+
writeSync4(fd, data, 0, "utf-8");
|
|
29587
29780
|
} finally {
|
|
29588
|
-
|
|
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
|
|
29755
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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
|
|
30423
|
-
import { homedir as
|
|
30424
|
-
import { dirname as
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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
|
|
31546
|
-
import { homedir as
|
|
31547
|
-
import { join as
|
|
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 =
|
|
31568
|
-
|
|
31771
|
+
const sessionDir = join15(homedir15(), ".claudish", "sessions", sessionId);
|
|
31772
|
+
mkdirSync7(sessionDir, { recursive: true });
|
|
31569
31773
|
if (opts.prompt) {
|
|
31570
|
-
writeFileSync7(
|
|
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(
|
|
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(
|
|
31848
|
+
writeFileSync7(join15(sessionDir, "stderr.log"), entry.stderr, "utf-8");
|
|
31645
31849
|
}
|
|
31646
|
-
writeFileSync7(
|
|
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
|
|
31820
|
-
import { homedir as
|
|
31821
|
-
import { join as
|
|
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(
|
|
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 =
|
|
31936
|
-
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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((
|
|
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 =
|
|
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
|
|
37360
|
-
readFileSync as
|
|
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
|
|
37366
|
-
import { join as
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
37475
|
-
BUFFER_FILE =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
38580
|
-
timer = setTimeout(() =>
|
|
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
|
-
|
|
39467
|
-
|
|
39468
|
-
|
|
39469
|
-
|
|
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
|
|
39640
|
-
import { homedir as
|
|
39641
|
-
import { join as
|
|
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
|
|
39785
|
-
|
|
39786
|
-
|
|
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((
|
|
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((
|
|
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
|
|
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
|
|
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
|
|
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
|
|
42274
|
-
import { homedir as
|
|
42275
|
-
import { join as
|
|
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(
|
|
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 (${
|
|
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 =
|
|
43197
|
+
const dotenvPath = resolve2(".env");
|
|
42354
43198
|
if (!existsSync15(dotenvPath))
|
|
42355
43199
|
return null;
|
|
42356
|
-
const parsed = import_dotenv.parse(
|
|
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(
|
|
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((
|
|
43254
|
+
return new Promise((resolve3, reject) => {
|
|
42411
43255
|
const queuedRequest = {
|
|
42412
43256
|
fetchFn,
|
|
42413
|
-
resolve:
|
|
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((
|
|
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((
|
|
44111
|
+
return new Promise((resolve3, reject) => {
|
|
43268
44112
|
const queuedRequest = {
|
|
43269
44113
|
fetchFn,
|
|
43270
|
-
resolve:
|
|
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((
|
|
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((
|
|
44511
|
+
return new Promise((resolve3, reject) => {
|
|
43668
44512
|
const queuedRequest = {
|
|
43669
44513
|
fetchFn,
|
|
43670
|
-
resolve:
|
|
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((
|
|
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
|
|
43930
|
-
import { homedir as
|
|
43931
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
43991
|
-
CACHE_FILE =
|
|
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
|
|
44455
|
-
mkdirSync as
|
|
44456
|
-
readFileSync as
|
|
45479
|
+
existsSync as existsSync18,
|
|
45480
|
+
mkdirSync as mkdirSync11,
|
|
45481
|
+
readFileSync as readFileSync16,
|
|
44457
45482
|
readdirSync as readdirSync2,
|
|
44458
|
-
writeFileSync as
|
|
45483
|
+
writeFileSync as writeFileSync12
|
|
44459
45484
|
} from "fs";
|
|
44460
|
-
import { join as
|
|
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 =
|
|
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 (
|
|
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
|
-
|
|
44489
|
-
|
|
45553
|
+
mkdirSync11(join22(sessionPath, "work"), { recursive: true });
|
|
45554
|
+
mkdirSync11(join22(sessionPath, "errors"), { recursive: true });
|
|
44490
45555
|
if (input !== undefined) {
|
|
44491
|
-
|
|
44492
|
-
} else if (!
|
|
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
|
-
|
|
45574
|
+
mkdirSync11(join22(sessionPath, "work", anonId), { recursive: true });
|
|
44510
45575
|
}
|
|
44511
|
-
|
|
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
|
-
|
|
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(
|
|
44531
|
-
const statusPath =
|
|
44532
|
-
const inputPath =
|
|
44533
|
-
const inputContent =
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
44552
|
-
const errorLogPath =
|
|
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((
|
|
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
|
-
|
|
45664
|
+
resolve4();
|
|
44583
45665
|
return;
|
|
44584
45666
|
}
|
|
44585
45667
|
resolved = true;
|
|
44586
45668
|
const outputSize = byteCount;
|
|
44587
|
-
const
|
|
44588
|
-
|
|
44589
|
-
|
|
44590
|
-
|
|
44591
|
-
|
|
44592
|
-
|
|
44593
|
-
|
|
44594
|
-
|
|
44595
|
-
|
|
44596
|
-
|
|
44597
|
-
|
|
44598
|
-
|
|
44599
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45710
|
+
resolve4();
|
|
44610
45711
|
return;
|
|
44611
45712
|
}
|
|
44612
45713
|
if (stderr) {
|
|
44613
|
-
|
|
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((
|
|
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
|
-
|
|
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] =
|
|
45809
|
+
responses[id] = readFileSync16(join22(sessionPath, file2), "utf-8");
|
|
44659
45810
|
}
|
|
44660
|
-
const input =
|
|
45811
|
+
const input = readFileSync16(join22(sessionPath, "input.md"), "utf-8");
|
|
44661
45812
|
const judgePrompt = buildJudgePrompt(input, responses);
|
|
44662
|
-
|
|
45813
|
+
writeFileSync12(join22(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
|
|
44663
45814
|
const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
|
|
44664
|
-
const judgePath =
|
|
44665
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
44850
|
-
import { homedir as
|
|
44851
|
-
import { dirname as
|
|
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 &&
|
|
46010
|
+
if (!forceRefresh && existsSync19(ALL_MODELS_CACHE_PATH2)) {
|
|
44855
46011
|
try {
|
|
44856
|
-
const cacheData = JSON.parse(
|
|
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
|
-
|
|
44871
|
-
|
|
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 (
|
|
44875
|
-
const cacheData = JSON.parse(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
44988
|
-
|
|
44989
|
-
|
|
44990
|
-
|
|
44991
|
-
|
|
44992
|
-
|
|
44993
|
-
|
|
44994
|
-
|
|
44995
|
-
|
|
44996
|
-
|
|
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
|
-
|
|
45012
|
-
|
|
45013
|
-
|
|
45014
|
-
|
|
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
|
-
|
|
45021
|
-
|
|
45022
|
-
|
|
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,
|
|
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,
|
|
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 =
|
|
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] =
|
|
46606
|
+
sessionData[file2] = readFileSync17(join23(sp, file2), "utf-8");
|
|
45448
46607
|
} catch {}
|
|
45449
46608
|
}
|
|
45450
46609
|
try {
|
|
45451
|
-
const errorDir =
|
|
45452
|
-
if (
|
|
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}`] =
|
|
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 =
|
|
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 =
|
|
45476
|
-
if (
|
|
45477
|
-
version2 = JSON.parse(
|
|
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
|
|
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 =
|
|
45850
|
-
CLAUDISH_CACHE_DIR =
|
|
45851
|
-
ALL_MODELS_CACHE_PATH2 =
|
|
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
|
|
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 (!
|
|
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 =
|
|
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
|
|
48880
|
+
let resolve4;
|
|
47689
48881
|
let reject;
|
|
47690
48882
|
const promise3 = new Promise((res, rej) => {
|
|
47691
|
-
|
|
48883
|
+
resolve4 = res;
|
|
47692
48884
|
reject = rej;
|
|
47693
48885
|
});
|
|
47694
|
-
return { promise: promise3, resolve:
|
|
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:
|
|
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(() =>
|
|
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((
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
58676
|
-
const { join:
|
|
58677
|
-
const { homedir:
|
|
58678
|
-
const credPath =
|
|
58679
|
-
if (!
|
|
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(
|
|
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 =
|
|
58736
|
-
if (
|
|
58737
|
-
const cache2 = JSON.parse(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
60751
|
-
const t =
|
|
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((
|
|
62692
|
-
resolveQuit =
|
|
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
|
|
62757
|
-
mkdirSync as
|
|
62758
|
-
readFileSync as
|
|
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
|
|
63897
|
+
writeFileSync as writeFileSync15
|
|
62762
63898
|
} from "fs";
|
|
62763
|
-
import { homedir as
|
|
62764
|
-
import { dirname as
|
|
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 =
|
|
62771
|
-
if (!
|
|
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(
|
|
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 =
|
|
63190
|
-
if (!
|
|
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
|
-
|
|
63197
|
-
|
|
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
|
|
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 =
|
|
64258
|
-
const guideContent =
|
|
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 =
|
|
64275
|
-
const skillsDir =
|
|
64276
|
-
const claudishSkillDir =
|
|
64277
|
-
const skillFile =
|
|
64278
|
-
if (
|
|
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 =
|
|
64286
|
-
if (!
|
|
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 (!
|
|
64296
|
-
|
|
65431
|
+
if (!existsSync21(claudeDir)) {
|
|
65432
|
+
mkdirSync13(claudeDir, { recursive: true });
|
|
64297
65433
|
console.log("\uD83D\uDCC1 Created .claude/ directory");
|
|
64298
65434
|
}
|
|
64299
|
-
if (!
|
|
64300
|
-
|
|
65435
|
+
if (!existsSync21(skillsDir)) {
|
|
65436
|
+
mkdirSync13(skillsDir, { recursive: true });
|
|
64301
65437
|
console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
|
|
64302
65438
|
}
|
|
64303
|
-
if (!
|
|
64304
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
64389
|
-
import { homedir as
|
|
64390
|
-
import { join as
|
|
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 ||
|
|
64395
|
-
cacheDir =
|
|
65530
|
+
const localAppData = process.env.LOCALAPPDATA || join25(homedir23(), "AppData", "Local");
|
|
65531
|
+
cacheDir = join25(localAppData, "claudish");
|
|
64396
65532
|
} else {
|
|
64397
|
-
cacheDir =
|
|
65533
|
+
cacheDir = join25(homedir23(), ".cache", "claudish");
|
|
64398
65534
|
}
|
|
64399
65535
|
try {
|
|
64400
|
-
if (!
|
|
64401
|
-
|
|
65536
|
+
if (!existsSync22(cacheDir)) {
|
|
65537
|
+
mkdirSync14(cacheDir, { recursive: true });
|
|
64402
65538
|
}
|
|
64403
|
-
return
|
|
65539
|
+
return join25(cacheDir, "update-check.json");
|
|
64404
65540
|
} catch {
|
|
64405
|
-
return
|
|
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 (!
|
|
65547
|
+
if (!existsSync22(cachePath)) {
|
|
64412
65548
|
return null;
|
|
64413
65549
|
}
|
|
64414
|
-
const data = JSON.parse(
|
|
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
|
-
|
|
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 (
|
|
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((
|
|
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
|
|
65317
|
-
import { homedir as
|
|
65318
|
-
import { dirname as
|
|
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 (!
|
|
66456
|
+
if (!existsSync23(path2))
|
|
65321
66457
|
return null;
|
|
65322
66458
|
let raw2;
|
|
65323
66459
|
try {
|
|
65324
|
-
raw2 = JSON.parse(
|
|
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
|
-
|
|
65334
|
-
|
|
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 =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
71664
|
-
renderer.once("destroy", () =>
|
|
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
|
|
71787
|
-
existsSync as
|
|
71788
|
-
mkdirSync as
|
|
71789
|
-
openSync as
|
|
71790
|
-
readFileSync as
|
|
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
|
|
72928
|
+
writeFileSync as writeFileSync18
|
|
71793
72929
|
} from "fs";
|
|
71794
|
-
import { homedir as
|
|
71795
|
-
import { join as
|
|
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
|
|
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 =
|
|
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 =
|
|
72987
|
+
const claudishDir = join27(homeDir, ".claudish");
|
|
71852
72988
|
const timestamp = Date.now();
|
|
71853
|
-
const scriptPath =
|
|
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
|
-
|
|
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 =
|
|
73086
|
+
const claudishDir = join27(homeDir, ".claudish");
|
|
71951
73087
|
try {
|
|
71952
|
-
|
|
73088
|
+
mkdirSync16(claudishDir, { recursive: true });
|
|
71953
73089
|
} catch {}
|
|
71954
73090
|
const timestamp = Date.now();
|
|
71955
|
-
const tempPath =
|
|
71956
|
-
const tokenFilePath =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
72171
|
-
const localPath = isWindows2() ?
|
|
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 =
|
|
73318
|
+
const fd = openSync5("/dev/fd/0", "r+");
|
|
72183
73319
|
if (isatty(fd)) {
|
|
72184
73320
|
ttyFd = fd;
|
|
72185
73321
|
} else {
|
|
72186
|
-
|
|
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
|
-
|
|
73345
|
+
closeSync5(fdToClose);
|
|
72210
73346
|
} catch {}
|
|
72211
73347
|
});
|
|
72212
73348
|
}
|
|
72213
73349
|
setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
|
|
72214
|
-
const exitCode = await new Promise((
|
|
73350
|
+
const exitCode = await new Promise((resolve4) => {
|
|
72215
73351
|
proc.on("exit", (code) => {
|
|
72216
73352
|
setClaudeCodeRunning(false);
|
|
72217
|
-
|
|
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 (
|
|
73387
|
+
if (existsSync24(process.env.CLAUDE_PATH)) {
|
|
72252
73388
|
return process.env.CLAUDE_PATH;
|
|
72253
73389
|
}
|
|
72254
73390
|
}
|
|
72255
|
-
const home =
|
|
72256
|
-
const localPath = isWindows3 ?
|
|
72257
|
-
if (
|
|
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
|
-
|
|
72263
|
-
|
|
72264
|
-
|
|
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 (
|
|
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
|
-
|
|
72276
|
-
|
|
72277
|
-
|
|
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
|
-
|
|
73415
|
+
join27(home, "../usr/bin/claude")
|
|
72280
73416
|
];
|
|
72281
73417
|
for (const path2 of commonPaths) {
|
|
72282
|
-
if (
|
|
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((
|
|
73433
|
+
const exitCode = await new Promise((resolve4) => {
|
|
72298
73434
|
proc.on("exit", (code) => {
|
|
72299
|
-
|
|
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
|
-
|
|
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
|
|
72340
|
-
import { homedir as
|
|
72341
|
-
import { join as
|
|
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 =
|
|
73479
|
+
const dir = join28(homedir26(), ".claudish");
|
|
72344
73480
|
try {
|
|
72345
|
-
|
|
73481
|
+
mkdirSync17(dir, { recursive: true });
|
|
72346
73482
|
} catch {}
|
|
72347
73483
|
return dir;
|
|
72348
73484
|
}
|
|
72349
73485
|
function getDiagLogPath() {
|
|
72350
|
-
return
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
72657
|
-
const pkgRoot =
|
|
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 =
|
|
72661
|
-
if (
|
|
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 =
|
|
72668
|
-
if (
|
|
73803
|
+
const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
|
|
73804
|
+
if (existsSync25(candidate))
|
|
72669
73805
|
return candidate;
|
|
72670
|
-
const parent =
|
|
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 (
|
|
73823
|
+
if (existsSync25(sockPath)) {
|
|
72688
73824
|
try {
|
|
72689
|
-
client = await new Promise((
|
|
73825
|
+
client = await new Promise((resolve4, reject) => {
|
|
72690
73826
|
const s = netConnect(sockPath);
|
|
72691
|
-
s.once("connect", () =>
|
|
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((
|
|
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 = () =>
|
|
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 =
|
|
72775
|
-
const prompt =
|
|
72776
|
-
const rawPrompt =
|
|
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
|
-
|
|
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((
|
|
72802
|
-
proc.on("exit", () =>
|
|
72803
|
-
proc.on("error", () =>
|
|
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 =
|
|
72808
|
-
|
|
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
|
|
72832
|
-
import { join as
|
|
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:
|
|
72931
|
-
exists:
|
|
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(() => (
|
|
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 =
|
|
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 =
|
|
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 =
|
|
74219
|
+
const responsePath = join30(sessionPath, `response-${anonId}.md`);
|
|
73084
74220
|
try {
|
|
73085
|
-
const raw2 =
|
|
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((
|
|
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
|
-
|
|
74272
|
+
resolve5(ans.trim().toLowerCase());
|
|
73137
74273
|
});
|
|
73138
74274
|
});
|
|
73139
74275
|
const declined = answer === "n" || answer === "no";
|