claudish 7.67.1 → 8.1.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 +612 -393
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -731,7 +731,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
731
731
|
});
|
|
732
732
|
|
|
733
733
|
// src/version.ts
|
|
734
|
-
var VERSION = "
|
|
734
|
+
var VERSION = "8.1.0";
|
|
735
735
|
|
|
736
736
|
// src/logger.ts
|
|
737
737
|
var exports_logger = {};
|
|
@@ -27458,6 +27458,271 @@ var init_stdio2 = __esm(() => {
|
|
|
27458
27458
|
init_stdio();
|
|
27459
27459
|
});
|
|
27460
27460
|
|
|
27461
|
+
// src/providers/all-models-cache.ts
|
|
27462
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
27463
|
+
import { homedir as homedir7 } from "os";
|
|
27464
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
27465
|
+
function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
|
|
27466
|
+
if (!existsSync5(path))
|
|
27467
|
+
return null;
|
|
27468
|
+
let raw;
|
|
27469
|
+
try {
|
|
27470
|
+
raw = JSON.parse(readFileSync5(path, "utf-8"));
|
|
27471
|
+
} catch {
|
|
27472
|
+
return null;
|
|
27473
|
+
}
|
|
27474
|
+
if (!raw || typeof raw !== "object")
|
|
27475
|
+
return null;
|
|
27476
|
+
const data = raw;
|
|
27477
|
+
const lastUpdated = typeof data.lastUpdated === "string" ? data.lastUpdated : new Date(0).toISOString();
|
|
27478
|
+
const models = Array.isArray(data.models) ? data.models : [];
|
|
27479
|
+
const entries = Array.isArray(data.entries) ? data.entries : [];
|
|
27480
|
+
return {
|
|
27481
|
+
version: 2,
|
|
27482
|
+
lastUpdated,
|
|
27483
|
+
entries,
|
|
27484
|
+
models
|
|
27485
|
+
};
|
|
27486
|
+
}
|
|
27487
|
+
function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
|
|
27488
|
+
const existing = readAllModelsCache(path);
|
|
27489
|
+
const merged = {
|
|
27490
|
+
version: 2,
|
|
27491
|
+
lastUpdated: data.lastUpdated ?? new Date().toISOString(),
|
|
27492
|
+
entries: data.entries ?? existing?.entries ?? [],
|
|
27493
|
+
models: data.models ?? existing?.models ?? []
|
|
27494
|
+
};
|
|
27495
|
+
mkdirSync5(dirname4(path), { recursive: true });
|
|
27496
|
+
writeFileSync5(path, JSON.stringify(merged), "utf-8");
|
|
27497
|
+
}
|
|
27498
|
+
var ALL_MODELS_CACHE_PATH;
|
|
27499
|
+
var init_all_models_cache = __esm(() => {
|
|
27500
|
+
ALL_MODELS_CACHE_PATH = join7(homedir7(), ".claudish", "all-models.json");
|
|
27501
|
+
});
|
|
27502
|
+
|
|
27503
|
+
// src/providers/model-ordering.ts
|
|
27504
|
+
function extractVersionParts(modelId) {
|
|
27505
|
+
const tokens = modelId.toLowerCase().split(/[\/_-]+/);
|
|
27506
|
+
let started = false;
|
|
27507
|
+
const parts = [];
|
|
27508
|
+
for (const token of tokens) {
|
|
27509
|
+
const match = token.match(/\d+(?:\.\d+)*/);
|
|
27510
|
+
if (!match) {
|
|
27511
|
+
if (started)
|
|
27512
|
+
break;
|
|
27513
|
+
continue;
|
|
27514
|
+
}
|
|
27515
|
+
if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
|
|
27516
|
+
continue;
|
|
27517
|
+
}
|
|
27518
|
+
if (!started) {
|
|
27519
|
+
started = true;
|
|
27520
|
+
for (const part of match[0].split(".")) {
|
|
27521
|
+
parts.push(Number.parseInt(part, 10));
|
|
27522
|
+
}
|
|
27523
|
+
if (!/^\d+(?:\.\d+)*$/.test(token)) {
|
|
27524
|
+
break;
|
|
27525
|
+
}
|
|
27526
|
+
continue;
|
|
27527
|
+
}
|
|
27528
|
+
if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
|
|
27529
|
+
break;
|
|
27530
|
+
}
|
|
27531
|
+
for (const part of token.split(".")) {
|
|
27532
|
+
parts.push(Number.parseInt(part, 10));
|
|
27533
|
+
}
|
|
27534
|
+
}
|
|
27535
|
+
return parts;
|
|
27536
|
+
}
|
|
27537
|
+
function compareVersionPartsDesc(a, b) {
|
|
27538
|
+
const maxLength = Math.max(a.length, b.length);
|
|
27539
|
+
for (let i = 0;i < maxLength; i++) {
|
|
27540
|
+
const aPart = a[i] ?? -1;
|
|
27541
|
+
const bPart = b[i] ?? -1;
|
|
27542
|
+
if (aPart !== bPart) {
|
|
27543
|
+
return bPart - aPart;
|
|
27544
|
+
}
|
|
27545
|
+
}
|
|
27546
|
+
return 0;
|
|
27547
|
+
}
|
|
27548
|
+
function compareByReleaseDateDesc(a, b) {
|
|
27549
|
+
const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
|
|
27550
|
+
const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
|
|
27551
|
+
const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
|
|
27552
|
+
const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
|
|
27553
|
+
if (aRelease !== bRelease) {
|
|
27554
|
+
return bRelease - aRelease;
|
|
27555
|
+
}
|
|
27556
|
+
const aId = a.id ?? a.modelId ?? "";
|
|
27557
|
+
const bId = b.id ?? b.modelId ?? "";
|
|
27558
|
+
const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
|
|
27559
|
+
if (versionCompare !== 0) {
|
|
27560
|
+
return versionCompare;
|
|
27561
|
+
}
|
|
27562
|
+
return aId.localeCompare(bId);
|
|
27563
|
+
}
|
|
27564
|
+
|
|
27565
|
+
// src/adapters/model-catalog.ts
|
|
27566
|
+
function lookupModel(modelId, cachePath) {
|
|
27567
|
+
const entry = findCacheEntry(modelId, cachePath);
|
|
27568
|
+
if (!entry || entry.contextWindow === undefined)
|
|
27569
|
+
return;
|
|
27570
|
+
return {
|
|
27571
|
+
modelId: entry.modelId,
|
|
27572
|
+
contextWindow: entry.contextWindow,
|
|
27573
|
+
supportsVision: entry.supportsVision,
|
|
27574
|
+
releaseDate: entry.releaseDate
|
|
27575
|
+
};
|
|
27576
|
+
}
|
|
27577
|
+
function lookupModelReasoning(modelId, cachePath) {
|
|
27578
|
+
return findCacheEntry(modelId, cachePath)?.reasoning;
|
|
27579
|
+
}
|
|
27580
|
+
function lookupModelTokenParam(modelId, cachePath) {
|
|
27581
|
+
return findCacheEntry(modelId, cachePath)?.tokenParam;
|
|
27582
|
+
}
|
|
27583
|
+
function lookupRouteReasoningMode(modelId, provider, cachePath) {
|
|
27584
|
+
return findCacheEntry(modelId, cachePath)?.aggregators?.find((aggregator) => aggregator.provider === provider)?.reasoning?.mode;
|
|
27585
|
+
}
|
|
27586
|
+
function lookupFamilyDefaultVariant(familyId, provider, cachePath) {
|
|
27587
|
+
const cache = readAllModelsCache(cachePath);
|
|
27588
|
+
if (!cache)
|
|
27589
|
+
return;
|
|
27590
|
+
for (const entry of cache.entries) {
|
|
27591
|
+
const rv = entry.routeVariant;
|
|
27592
|
+
if (!rv?.isDefault)
|
|
27593
|
+
continue;
|
|
27594
|
+
if (rv.provider !== provider)
|
|
27595
|
+
continue;
|
|
27596
|
+
if (rv.familyId === familyId || rv.baseModelId === familyId)
|
|
27597
|
+
return entry.modelId;
|
|
27598
|
+
}
|
|
27599
|
+
return;
|
|
27600
|
+
}
|
|
27601
|
+
function lookupVariantPresets(baseModelId, provider, cachePath) {
|
|
27602
|
+
const cache = readAllModelsCache(cachePath);
|
|
27603
|
+
if (!cache)
|
|
27604
|
+
return [];
|
|
27605
|
+
const wanted = stripVendorPrefix(baseModelId.toLowerCase());
|
|
27606
|
+
const found = [];
|
|
27607
|
+
for (const entry of cache.entries) {
|
|
27608
|
+
const rv = entry.routeVariant;
|
|
27609
|
+
if (!rv?.preset || !rv.baseModelId)
|
|
27610
|
+
continue;
|
|
27611
|
+
if (stripVendorPrefix(rv.baseModelId.toLowerCase()) !== wanted)
|
|
27612
|
+
continue;
|
|
27613
|
+
if (provider !== undefined && rv.provider !== provider)
|
|
27614
|
+
continue;
|
|
27615
|
+
found.push({ modelId: entry.modelId, preset: rv.preset, provider: rv.provider });
|
|
27616
|
+
}
|
|
27617
|
+
return found;
|
|
27618
|
+
}
|
|
27619
|
+
function lookupModelCapabilities(modelId, cachePath) {
|
|
27620
|
+
const entry = findCacheEntry(modelId, cachePath);
|
|
27621
|
+
if (!entry)
|
|
27622
|
+
return;
|
|
27623
|
+
return { supportsTools: entry.supportsTools, supportsThinking: entry.supportsThinking };
|
|
27624
|
+
}
|
|
27625
|
+
function lookupModelForProvider(modelId, provider, cachePath) {
|
|
27626
|
+
const entry = findCacheEntry(modelId, cachePath);
|
|
27627
|
+
if (!entry)
|
|
27628
|
+
return;
|
|
27629
|
+
return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
|
|
27630
|
+
}
|
|
27631
|
+
function resolveSubscriptionRouting(modelId, provider, cachePath) {
|
|
27632
|
+
const entry = findCacheEntry(modelId, cachePath);
|
|
27633
|
+
if (!entry)
|
|
27634
|
+
return { kind: "unknown" };
|
|
27635
|
+
if (entry.subscriptionPlans?.includes(provider)) {
|
|
27636
|
+
const agg = entry.aggregators?.find((a) => a.provider === provider);
|
|
27637
|
+
return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
|
|
27638
|
+
}
|
|
27639
|
+
return isSubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
|
|
27640
|
+
}
|
|
27641
|
+
function isSubscriptionPlan(provider, cachePath) {
|
|
27642
|
+
const cache = readAllModelsCache(cachePath);
|
|
27643
|
+
if (!cache)
|
|
27644
|
+
return false;
|
|
27645
|
+
return cache.entries.some((e) => e.subscriptionPlans?.includes(provider));
|
|
27646
|
+
}
|
|
27647
|
+
function stripVendorPrefix(lowerId) {
|
|
27648
|
+
return lowerId.includes("/") ? lowerId.substring(lowerId.lastIndexOf("/") + 1) : lowerId;
|
|
27649
|
+
}
|
|
27650
|
+
function findCacheEntry(modelId, cachePath) {
|
|
27651
|
+
if (modelId.includes("@")) {
|
|
27652
|
+
throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
|
|
27653
|
+
}
|
|
27654
|
+
const cache = readAllModelsCache(cachePath);
|
|
27655
|
+
if (!cache || cache.entries.length === 0)
|
|
27656
|
+
return;
|
|
27657
|
+
const lower = modelId.toLowerCase();
|
|
27658
|
+
const unprefixed = stripVendorPrefix(lower);
|
|
27659
|
+
for (const entry of cache.entries) {
|
|
27660
|
+
const entryId = entry.modelId.toLowerCase();
|
|
27661
|
+
const exactMatch = entryId === unprefixed || entryId === lower;
|
|
27662
|
+
const aliasMatch = entry.aliases?.some((a) => a.toLowerCase() === unprefixed || a.toLowerCase() === lower);
|
|
27663
|
+
if (exactMatch || aliasMatch) {
|
|
27664
|
+
return entry;
|
|
27665
|
+
}
|
|
27666
|
+
}
|
|
27667
|
+
return;
|
|
27668
|
+
}
|
|
27669
|
+
function classifyCatalogHit(entry, q) {
|
|
27670
|
+
const id = entry.modelId.toLowerCase();
|
|
27671
|
+
if (id === q || stripVendorPrefix(id) === q)
|
|
27672
|
+
return { bucket: "exact" };
|
|
27673
|
+
const aliases = entry.aliases ?? [];
|
|
27674
|
+
const exactAlias = aliases.find((a) => a.toLowerCase() === q || stripVendorPrefix(a.toLowerCase()) === q);
|
|
27675
|
+
if (exactAlias)
|
|
27676
|
+
return { bucket: "exact", matchedAlias: exactAlias };
|
|
27677
|
+
if (id.includes(q))
|
|
27678
|
+
return { bucket: "id" };
|
|
27679
|
+
const partialAlias = aliases.find((a) => a.toLowerCase().includes(q));
|
|
27680
|
+
return partialAlias ? { bucket: "alias", matchedAlias: partialAlias } : undefined;
|
|
27681
|
+
}
|
|
27682
|
+
function searchCatalogModels(query, limit = 10, cachePath) {
|
|
27683
|
+
const q = query.trim().toLowerCase();
|
|
27684
|
+
if (!q)
|
|
27685
|
+
return [];
|
|
27686
|
+
const cache = readAllModelsCache(cachePath);
|
|
27687
|
+
if (!cache || cache.entries.length === 0)
|
|
27688
|
+
return [];
|
|
27689
|
+
const exact = [];
|
|
27690
|
+
const idPartial = [];
|
|
27691
|
+
const aliasPartial = [];
|
|
27692
|
+
for (const entry of cache.entries) {
|
|
27693
|
+
const hit = classifyCatalogHit(entry, q);
|
|
27694
|
+
if (!hit)
|
|
27695
|
+
continue;
|
|
27696
|
+
const ranked = {
|
|
27697
|
+
entry,
|
|
27698
|
+
match: {
|
|
27699
|
+
modelId: entry.modelId,
|
|
27700
|
+
aliases: entry.aliases ?? [],
|
|
27701
|
+
subscriptionPlans: entry.subscriptionPlans ?? [],
|
|
27702
|
+
...hit.matchedAlias ? { matchedAlias: hit.matchedAlias } : {}
|
|
27703
|
+
}
|
|
27704
|
+
};
|
|
27705
|
+
if (hit.bucket === "exact")
|
|
27706
|
+
exact.push(ranked);
|
|
27707
|
+
else if (hit.bucket === "id")
|
|
27708
|
+
idPartial.push(ranked);
|
|
27709
|
+
else
|
|
27710
|
+
aliasPartial.push(ranked);
|
|
27711
|
+
}
|
|
27712
|
+
const byRelevance = (a, b) => {
|
|
27713
|
+
const lengthDelta = a.entry.modelId.length - b.entry.modelId.length;
|
|
27714
|
+
if (lengthDelta !== 0)
|
|
27715
|
+
return lengthDelta;
|
|
27716
|
+
return compareByReleaseDateDesc(a.entry, b.entry);
|
|
27717
|
+
};
|
|
27718
|
+
idPartial.sort(byRelevance);
|
|
27719
|
+
aliasPartial.sort(byRelevance);
|
|
27720
|
+
return [...exact, ...idPartial, ...aliasPartial].slice(0, limit).map((r) => r.match);
|
|
27721
|
+
}
|
|
27722
|
+
var init_model_catalog = __esm(() => {
|
|
27723
|
+
init_all_models_cache();
|
|
27724
|
+
});
|
|
27725
|
+
|
|
27461
27726
|
// src/agent-availability.ts
|
|
27462
27727
|
import { spawn } from "child_process";
|
|
27463
27728
|
function parseAvailableAgents(output) {
|
|
@@ -27574,26 +27839,26 @@ __export(exports_profile_config, {
|
|
|
27574
27839
|
setKeychainEnabled: () => setKeychainEnabled,
|
|
27575
27840
|
setProfile: () => setProfile
|
|
27576
27841
|
});
|
|
27577
|
-
import { existsSync as
|
|
27578
|
-
import { homedir as
|
|
27579
|
-
import { dirname as
|
|
27842
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
27843
|
+
import { homedir as homedir8 } from "os";
|
|
27844
|
+
import { dirname as dirname5, join as join8, parse as parse6 } from "path";
|
|
27580
27845
|
function activeConfigFile() {
|
|
27581
27846
|
return activeGlobalConfigFile(CONFIG_FILE);
|
|
27582
27847
|
}
|
|
27583
27848
|
function ensureConfigDir() {
|
|
27584
|
-
if (!
|
|
27585
|
-
|
|
27849
|
+
if (!existsSync6(CONFIG_DIR)) {
|
|
27850
|
+
mkdirSync6(CONFIG_DIR, { recursive: true });
|
|
27586
27851
|
}
|
|
27587
27852
|
}
|
|
27588
27853
|
function loadConfig() {
|
|
27589
27854
|
const activeFile = activeConfigFile();
|
|
27590
27855
|
if (!getConfigFileOverride())
|
|
27591
27856
|
ensureConfigDir();
|
|
27592
|
-
if (!
|
|
27857
|
+
if (!existsSync6(activeFile)) {
|
|
27593
27858
|
return { ...DEFAULT_CONFIG };
|
|
27594
27859
|
}
|
|
27595
27860
|
try {
|
|
27596
|
-
const content =
|
|
27861
|
+
const content = readFileSync6(activeFile, "utf-8");
|
|
27597
27862
|
const config2 = JSON.parse(content);
|
|
27598
27863
|
const merged = {
|
|
27599
27864
|
version: config2.version || DEFAULT_CONFIG.version,
|
|
@@ -27663,39 +27928,39 @@ function loadConfig() {
|
|
|
27663
27928
|
function saveConfig(config2) {
|
|
27664
27929
|
if (!getConfigFileOverride())
|
|
27665
27930
|
ensureConfigDir();
|
|
27666
|
-
|
|
27931
|
+
writeFileSync6(activeConfigFile(), JSON.stringify(config2, null, 2), "utf-8");
|
|
27667
27932
|
}
|
|
27668
27933
|
function configExists() {
|
|
27669
|
-
return
|
|
27934
|
+
return existsSync6(CONFIG_FILE);
|
|
27670
27935
|
}
|
|
27671
27936
|
function getConfigPath() {
|
|
27672
27937
|
return CONFIG_FILE;
|
|
27673
27938
|
}
|
|
27674
27939
|
function getLocalConfigPath() {
|
|
27675
|
-
const home =
|
|
27940
|
+
const home = homedir8();
|
|
27676
27941
|
let dir = process.cwd();
|
|
27677
27942
|
const root = parse6(dir).root;
|
|
27678
27943
|
while (dir !== root && dir !== home) {
|
|
27679
|
-
const candidate =
|
|
27680
|
-
if (
|
|
27944
|
+
const candidate = join8(dir, LOCAL_CONFIG_FILENAME);
|
|
27945
|
+
if (existsSync6(candidate))
|
|
27681
27946
|
return candidate;
|
|
27682
|
-
if (
|
|
27947
|
+
if (existsSync6(join8(dir, ".git"))) {
|
|
27683
27948
|
return candidate;
|
|
27684
27949
|
}
|
|
27685
|
-
dir =
|
|
27950
|
+
dir = dirname5(dir);
|
|
27686
27951
|
}
|
|
27687
|
-
return
|
|
27952
|
+
return join8(process.cwd(), LOCAL_CONFIG_FILENAME);
|
|
27688
27953
|
}
|
|
27689
27954
|
function localConfigExists() {
|
|
27690
|
-
return
|
|
27955
|
+
return existsSync6(getLocalConfigPath());
|
|
27691
27956
|
}
|
|
27692
27957
|
function readProOnUltracode(paths = defaultScopedConfigPaths) {
|
|
27693
27958
|
for (const pathFn of [paths.project, paths.global]) {
|
|
27694
27959
|
try {
|
|
27695
27960
|
const path = pathFn();
|
|
27696
|
-
if (!
|
|
27961
|
+
if (!existsSync6(path))
|
|
27697
27962
|
continue;
|
|
27698
|
-
const parsed = JSON.parse(
|
|
27963
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
27699
27964
|
if (typeof parsed?.proOnUltracode === "boolean")
|
|
27700
27965
|
return parsed.proOnUltracode;
|
|
27701
27966
|
} catch {}
|
|
@@ -27704,17 +27969,17 @@ function readProOnUltracode(paths = defaultScopedConfigPaths) {
|
|
|
27704
27969
|
}
|
|
27705
27970
|
function isProjectDirectory() {
|
|
27706
27971
|
const cwd = process.cwd();
|
|
27707
|
-
return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) =>
|
|
27972
|
+
return [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".claudish.json"].some((f) => existsSync6(join8(cwd, f)));
|
|
27708
27973
|
}
|
|
27709
27974
|
function loadLocalConfig() {
|
|
27710
27975
|
if (getConfigFileOverride())
|
|
27711
27976
|
return null;
|
|
27712
27977
|
const localPath = getLocalConfigPath();
|
|
27713
|
-
if (!
|
|
27978
|
+
if (!existsSync6(localPath)) {
|
|
27714
27979
|
return null;
|
|
27715
27980
|
}
|
|
27716
27981
|
try {
|
|
27717
|
-
const content =
|
|
27982
|
+
const content = readFileSync6(localPath, "utf-8");
|
|
27718
27983
|
const config2 = JSON.parse(content);
|
|
27719
27984
|
return {
|
|
27720
27985
|
...config2,
|
|
@@ -27732,7 +27997,7 @@ function saveLocalConfig(config2) {
|
|
|
27732
27997
|
if (toWrite.routing !== undefined && Object.keys(toWrite.routing).length === 0) {
|
|
27733
27998
|
delete toWrite.routing;
|
|
27734
27999
|
}
|
|
27735
|
-
|
|
28000
|
+
writeFileSync6(getLocalConfigPath(), JSON.stringify(toWrite, null, 2), "utf-8");
|
|
27736
28001
|
}
|
|
27737
28002
|
function loadConfigForScope(scope) {
|
|
27738
28003
|
if (scope === "local") {
|
|
@@ -27987,8 +28252,8 @@ function disableLocalProvider(providerName) {
|
|
|
27987
28252
|
}
|
|
27988
28253
|
var CONFIG_DIR, CONFIG_FILE, LOCAL_CONFIG_FILENAME = ".claudish.json", DEFAULT_CONFIG, defaultScopedConfigPaths;
|
|
27989
28254
|
var init_profile_config = __esm(() => {
|
|
27990
|
-
CONFIG_DIR =
|
|
27991
|
-
CONFIG_FILE =
|
|
28255
|
+
CONFIG_DIR = join8(homedir8(), ".claudish");
|
|
28256
|
+
CONFIG_FILE = join8(CONFIG_DIR, "config.json");
|
|
27992
28257
|
DEFAULT_CONFIG = {
|
|
27993
28258
|
version: "1.0.0",
|
|
27994
28259
|
defaultProfile: "default",
|
|
@@ -28095,153 +28360,6 @@ var init_remote_provider_types = __esm(() => {
|
|
|
28095
28360
|
};
|
|
28096
28361
|
});
|
|
28097
28362
|
|
|
28098
|
-
// src/providers/all-models-cache.ts
|
|
28099
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
28100
|
-
import { homedir as homedir8 } from "os";
|
|
28101
|
-
import { dirname as dirname5, join as join8 } from "path";
|
|
28102
|
-
function readAllModelsCache(path = ALL_MODELS_CACHE_PATH) {
|
|
28103
|
-
if (!existsSync6(path))
|
|
28104
|
-
return null;
|
|
28105
|
-
let raw;
|
|
28106
|
-
try {
|
|
28107
|
-
raw = JSON.parse(readFileSync6(path, "utf-8"));
|
|
28108
|
-
} catch {
|
|
28109
|
-
return null;
|
|
28110
|
-
}
|
|
28111
|
-
if (!raw || typeof raw !== "object")
|
|
28112
|
-
return null;
|
|
28113
|
-
const data = raw;
|
|
28114
|
-
const lastUpdated = typeof data.lastUpdated === "string" ? data.lastUpdated : new Date(0).toISOString();
|
|
28115
|
-
const models = Array.isArray(data.models) ? data.models : [];
|
|
28116
|
-
const entries = Array.isArray(data.entries) ? data.entries : [];
|
|
28117
|
-
return {
|
|
28118
|
-
version: 2,
|
|
28119
|
-
lastUpdated,
|
|
28120
|
-
entries,
|
|
28121
|
-
models
|
|
28122
|
-
};
|
|
28123
|
-
}
|
|
28124
|
-
function writeAllModelsCache(data, path = ALL_MODELS_CACHE_PATH) {
|
|
28125
|
-
const existing = readAllModelsCache(path);
|
|
28126
|
-
const merged = {
|
|
28127
|
-
version: 2,
|
|
28128
|
-
lastUpdated: data.lastUpdated ?? new Date().toISOString(),
|
|
28129
|
-
entries: data.entries ?? existing?.entries ?? [],
|
|
28130
|
-
models: data.models ?? existing?.models ?? []
|
|
28131
|
-
};
|
|
28132
|
-
mkdirSync6(dirname5(path), { recursive: true });
|
|
28133
|
-
writeFileSync6(path, JSON.stringify(merged), "utf-8");
|
|
28134
|
-
}
|
|
28135
|
-
var ALL_MODELS_CACHE_PATH;
|
|
28136
|
-
var init_all_models_cache = __esm(() => {
|
|
28137
|
-
ALL_MODELS_CACHE_PATH = join8(homedir8(), ".claudish", "all-models.json");
|
|
28138
|
-
});
|
|
28139
|
-
|
|
28140
|
-
// src/adapters/model-catalog.ts
|
|
28141
|
-
function lookupModel(modelId, cachePath) {
|
|
28142
|
-
const entry = findCacheEntry(modelId, cachePath);
|
|
28143
|
-
if (!entry || entry.contextWindow === undefined)
|
|
28144
|
-
return;
|
|
28145
|
-
return {
|
|
28146
|
-
modelId: entry.modelId,
|
|
28147
|
-
contextWindow: entry.contextWindow,
|
|
28148
|
-
supportsVision: entry.supportsVision,
|
|
28149
|
-
releaseDate: entry.releaseDate
|
|
28150
|
-
};
|
|
28151
|
-
}
|
|
28152
|
-
function lookupModelReasoning(modelId, cachePath) {
|
|
28153
|
-
return findCacheEntry(modelId, cachePath)?.reasoning;
|
|
28154
|
-
}
|
|
28155
|
-
function lookupModelTokenParam(modelId, cachePath) {
|
|
28156
|
-
return findCacheEntry(modelId, cachePath)?.tokenParam;
|
|
28157
|
-
}
|
|
28158
|
-
function lookupFamilyDefaultVariant(familyId, provider, cachePath) {
|
|
28159
|
-
const cache2 = readAllModelsCache(cachePath);
|
|
28160
|
-
if (!cache2)
|
|
28161
|
-
return;
|
|
28162
|
-
for (const entry of cache2.entries) {
|
|
28163
|
-
const rv = entry.routeVariant;
|
|
28164
|
-
if (!rv?.isDefault)
|
|
28165
|
-
continue;
|
|
28166
|
-
if (rv.provider !== provider)
|
|
28167
|
-
continue;
|
|
28168
|
-
if (rv.familyId === familyId || rv.baseModelId === familyId)
|
|
28169
|
-
return entry.modelId;
|
|
28170
|
-
}
|
|
28171
|
-
return;
|
|
28172
|
-
}
|
|
28173
|
-
function lookupVariantPresets(baseModelId, provider, cachePath) {
|
|
28174
|
-
const cache2 = readAllModelsCache(cachePath);
|
|
28175
|
-
if (!cache2)
|
|
28176
|
-
return [];
|
|
28177
|
-
const wanted = stripVendorPrefix(baseModelId.toLowerCase());
|
|
28178
|
-
const found = [];
|
|
28179
|
-
for (const entry of cache2.entries) {
|
|
28180
|
-
const rv = entry.routeVariant;
|
|
28181
|
-
if (!rv?.preset || !rv.baseModelId)
|
|
28182
|
-
continue;
|
|
28183
|
-
if (stripVendorPrefix(rv.baseModelId.toLowerCase()) !== wanted)
|
|
28184
|
-
continue;
|
|
28185
|
-
if (provider !== undefined && rv.provider !== provider)
|
|
28186
|
-
continue;
|
|
28187
|
-
found.push({ modelId: entry.modelId, preset: rv.preset, provider: rv.provider });
|
|
28188
|
-
}
|
|
28189
|
-
return found;
|
|
28190
|
-
}
|
|
28191
|
-
function lookupModelCapabilities(modelId, cachePath) {
|
|
28192
|
-
const entry = findCacheEntry(modelId, cachePath);
|
|
28193
|
-
if (!entry)
|
|
28194
|
-
return;
|
|
28195
|
-
return { supportsTools: entry.supportsTools, supportsThinking: entry.supportsThinking };
|
|
28196
|
-
}
|
|
28197
|
-
function lookupModelForProvider(modelId, provider, cachePath) {
|
|
28198
|
-
const entry = findCacheEntry(modelId, cachePath);
|
|
28199
|
-
if (!entry)
|
|
28200
|
-
return;
|
|
28201
|
-
return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
|
|
28202
|
-
}
|
|
28203
|
-
function resolveSubscriptionRouting(modelId, provider, cachePath) {
|
|
28204
|
-
const entry = findCacheEntry(modelId, cachePath);
|
|
28205
|
-
if (!entry)
|
|
28206
|
-
return { kind: "unknown" };
|
|
28207
|
-
if (entry.subscriptionPlans?.includes(provider)) {
|
|
28208
|
-
const agg = entry.aggregators?.find((a) => a.provider === provider);
|
|
28209
|
-
return agg?.externalId ? { kind: "serves", externalId: agg.externalId } : { kind: "unknown" };
|
|
28210
|
-
}
|
|
28211
|
-
return isSubscriptionPlan(provider, cachePath) ? { kind: "not-served" } : { kind: "unknown" };
|
|
28212
|
-
}
|
|
28213
|
-
function isSubscriptionPlan(provider, cachePath) {
|
|
28214
|
-
const cache2 = readAllModelsCache(cachePath);
|
|
28215
|
-
if (!cache2)
|
|
28216
|
-
return false;
|
|
28217
|
-
return cache2.entries.some((e) => e.subscriptionPlans?.includes(provider));
|
|
28218
|
-
}
|
|
28219
|
-
function stripVendorPrefix(lowerId) {
|
|
28220
|
-
return lowerId.includes("/") ? lowerId.substring(lowerId.lastIndexOf("/") + 1) : lowerId;
|
|
28221
|
-
}
|
|
28222
|
-
function findCacheEntry(modelId, cachePath) {
|
|
28223
|
-
if (modelId.includes("@")) {
|
|
28224
|
-
throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
|
|
28225
|
-
}
|
|
28226
|
-
const cache2 = readAllModelsCache(cachePath);
|
|
28227
|
-
if (!cache2 || cache2.entries.length === 0)
|
|
28228
|
-
return;
|
|
28229
|
-
const lower = modelId.toLowerCase();
|
|
28230
|
-
const unprefixed = stripVendorPrefix(lower);
|
|
28231
|
-
for (const entry of cache2.entries) {
|
|
28232
|
-
const entryId = entry.modelId.toLowerCase();
|
|
28233
|
-
const exactMatch = entryId === unprefixed || entryId === lower;
|
|
28234
|
-
const aliasMatch = entry.aliases?.some((a) => a.toLowerCase() === unprefixed || a.toLowerCase() === lower);
|
|
28235
|
-
if (exactMatch || aliasMatch) {
|
|
28236
|
-
return entry;
|
|
28237
|
-
}
|
|
28238
|
-
}
|
|
28239
|
-
return;
|
|
28240
|
-
}
|
|
28241
|
-
var init_model_catalog = __esm(() => {
|
|
28242
|
-
init_all_models_cache();
|
|
28243
|
-
});
|
|
28244
|
-
|
|
28245
28363
|
// src/adapters/tool-name-utils.ts
|
|
28246
28364
|
function hashToolName(name) {
|
|
28247
28365
|
let h1 = 3735928559;
|
|
@@ -39642,6 +39760,18 @@ var init_session_events = __esm(() => {
|
|
|
39642
39760
|
|
|
39643
39761
|
// src/session-events/pro-injection.ts
|
|
39644
39762
|
function resolveVariantPreset(bareModelName, provider, cachePath) {
|
|
39763
|
+
const routeMode = lookupRouteReasoningMode(bareModelName, provider, cachePath);
|
|
39764
|
+
if (routeMode) {
|
|
39765
|
+
if (routeMode.status !== "supported" || !routeMode.values.includes("pro")) {
|
|
39766
|
+
return;
|
|
39767
|
+
}
|
|
39768
|
+
return {
|
|
39769
|
+
params: { reasoning: { mode: "pro" } },
|
|
39770
|
+
provider,
|
|
39771
|
+
preset: "reasoning.mode=pro",
|
|
39772
|
+
sourceLabel: `route capability @ ${provider}`
|
|
39773
|
+
};
|
|
39774
|
+
}
|
|
39645
39775
|
for (const variant of lookupVariantPresets(bareModelName, provider, cachePath)) {
|
|
39646
39776
|
try {
|
|
39647
39777
|
const params = parseModelParams(variant.preset);
|
|
@@ -39649,9 +39779,9 @@ function resolveVariantPreset(bareModelName, provider, cachePath) {
|
|
|
39649
39779
|
continue;
|
|
39650
39780
|
return {
|
|
39651
39781
|
params,
|
|
39652
|
-
variantModelId: variant.modelId,
|
|
39653
39782
|
provider: variant.provider,
|
|
39654
|
-
preset: variant.preset
|
|
39783
|
+
preset: variant.preset,
|
|
39784
|
+
sourceLabel: `variant ${variant.modelId} @ ${variant.provider}`
|
|
39655
39785
|
};
|
|
39656
39786
|
} catch {}
|
|
39657
39787
|
}
|
|
@@ -39675,7 +39805,7 @@ function applyProInjection(requestPayload, opts) {
|
|
|
39675
39805
|
if (!resolved)
|
|
39676
39806
|
return false;
|
|
39677
39807
|
deepMergeParams(requestPayload, resolved.params);
|
|
39678
|
-
log(`[SessionEvents] ultracode active \u2192 preset ${resolved.preset} for ${opts.targetModel} ` + `(catalog
|
|
39808
|
+
log(`[SessionEvents] ultracode active \u2192 preset ${resolved.preset} for ${opts.targetModel} ` + `(catalog ${resolved.sourceLabel}, session ${opts.sessionId})`);
|
|
39679
39809
|
return true;
|
|
39680
39810
|
} catch {
|
|
39681
39811
|
return false;
|
|
@@ -48403,10 +48533,12 @@ var init_team_stream_capture = __esm(() => {
|
|
|
48403
48533
|
});
|
|
48404
48534
|
|
|
48405
48535
|
// src/channel/stream-json-reducer.ts
|
|
48406
|
-
function reachesAnswer(parsedType8, isJson) {
|
|
48536
|
+
function reachesAnswer(parsedType8, isJson, keepUnrecognizedJson) {
|
|
48407
48537
|
if (!isJson)
|
|
48408
48538
|
return true;
|
|
48409
|
-
|
|
48539
|
+
if (parsedType8 !== null && STREAM_JSON_EVENT_TYPES.has(parsedType8))
|
|
48540
|
+
return true;
|
|
48541
|
+
return keepUnrecognizedJson;
|
|
48410
48542
|
}
|
|
48411
48543
|
function labelFor(type, subtype) {
|
|
48412
48544
|
if (type === null)
|
|
@@ -48478,6 +48610,9 @@ class StreamJsonReducer {
|
|
|
48478
48610
|
get toolUseCount() {
|
|
48479
48611
|
return this._toolUseCount;
|
|
48480
48612
|
}
|
|
48613
|
+
get idleMs() {
|
|
48614
|
+
return Math.max(0, Date.now() - this.lastFrameAt);
|
|
48615
|
+
}
|
|
48481
48616
|
get terminalReason() {
|
|
48482
48617
|
return this._terminalReason;
|
|
48483
48618
|
}
|
|
@@ -48570,7 +48705,7 @@ class StreamJsonReducer {
|
|
|
48570
48705
|
this.opts.onSemanticLine?.(line, labelFor(type, frame ? asString(frame.subtype) : null));
|
|
48571
48706
|
if (frame && type !== null)
|
|
48572
48707
|
this.applyFrame(frame, type);
|
|
48573
|
-
if (!reachesAnswer(type, frame !== null))
|
|
48708
|
+
if (!reachesAnswer(type, frame !== null, this.opts.keepUnrecognizedJson ?? false))
|
|
48574
48709
|
return "";
|
|
48575
48710
|
const prose = this.capture.write(terminated ? `${line}
|
|
48576
48711
|
` : line);
|
|
@@ -49319,6 +49454,16 @@ function resolveClaudishSpawn(env = process.env) {
|
|
|
49319
49454
|
}
|
|
49320
49455
|
var CLAUDISH_BIN_ENV = "CLAUDISH_BIN";
|
|
49321
49456
|
|
|
49457
|
+
// src/stdio-decode.ts
|
|
49458
|
+
import { StringDecoder } from "string_decoder";
|
|
49459
|
+
function decodeChunk(decoder, chunk) {
|
|
49460
|
+
return typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
49461
|
+
}
|
|
49462
|
+
function newStdioDecoder() {
|
|
49463
|
+
return new StringDecoder("utf8");
|
|
49464
|
+
}
|
|
49465
|
+
var init_stdio_decode = () => {};
|
|
49466
|
+
|
|
49322
49467
|
// src/team-stats.ts
|
|
49323
49468
|
import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync10 } from "fs";
|
|
49324
49469
|
import { join as join28 } from "path";
|
|
@@ -49494,22 +49639,25 @@ var init_team_stats = () => {};
|
|
|
49494
49639
|
var exports_team_orchestrator = {};
|
|
49495
49640
|
__export(exports_team_orchestrator, {
|
|
49496
49641
|
DEFAULT_MIN_OUTPUT_BYTES: () => DEFAULT_MIN_OUTPUT_BYTES,
|
|
49497
|
-
DEFAULT_STALL_SECONDS: () => DEFAULT_STALL_SECONDS2,
|
|
49498
|
-
DRAIN_TIMEOUT_MS: () => DRAIN_TIMEOUT_MS,
|
|
49499
|
-
GRACE_INTERVAL_MS: () => GRACE_INTERVAL_MS,
|
|
49500
49642
|
STDOUT_TAIL_LIMIT: () => STDOUT_TAIL_LIMIT,
|
|
49501
49643
|
TEAM_CAPTURE_ENV_VAR: () => TEAM_CAPTURE_ENV_VAR,
|
|
49502
49644
|
aggregateVerdict: () => aggregateVerdict,
|
|
49503
49645
|
buildJudgePrompt: () => buildJudgePrompt,
|
|
49646
|
+
cancelTeamRun: () => cancelTeamRun,
|
|
49504
49647
|
classifyRunOutput: () => classifyRunOutput,
|
|
49505
49648
|
fisherYatesShuffle: () => fisherYatesShuffle,
|
|
49506
49649
|
getStatus: () => getStatus,
|
|
49507
49650
|
judgeResponses: () => judgeResponses,
|
|
49508
49651
|
meaningfulStderr: () => meaningfulStderr,
|
|
49509
49652
|
parseJudgeVotes: () => parseJudgeVotes,
|
|
49653
|
+
readTeamInputFile: () => readTeamInputFile,
|
|
49510
49654
|
resolveCaptureMode: () => resolveCaptureMode,
|
|
49511
49655
|
runModels: () => runModels,
|
|
49512
49656
|
setupSession: () => setupSession,
|
|
49657
|
+
shutdownAllTeamRuns: () => shutdownAllTeamRuns,
|
|
49658
|
+
startModels: () => startModels,
|
|
49659
|
+
teamSlotActivity: () => teamSlotActivity,
|
|
49660
|
+
teamSlotIdleSeconds: () => teamSlotIdleSeconds,
|
|
49513
49661
|
validateSessionPath: () => validateSessionPath
|
|
49514
49662
|
});
|
|
49515
49663
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -49521,12 +49669,57 @@ import {
|
|
|
49521
49669
|
readdirSync as readdirSync5,
|
|
49522
49670
|
writeFileSync as writeFileSync11
|
|
49523
49671
|
} from "fs";
|
|
49524
|
-
import { join as join29, resolve as resolve3 } from "path";
|
|
49672
|
+
import { basename as basename2, join as join29, resolve as resolve3 } from "path";
|
|
49525
49673
|
function resolveCaptureMode(explicit, env = process.env) {
|
|
49526
49674
|
if (explicit)
|
|
49527
49675
|
return explicit;
|
|
49528
49676
|
return env[TEAM_CAPTURE_ENV_VAR]?.trim().toLowerCase() === "print" ? "print" : "stream-json";
|
|
49529
49677
|
}
|
|
49678
|
+
function teamSlotIdleSeconds(teamSessionId) {
|
|
49679
|
+
const run = liveTeamRuns.get(teamSessionId);
|
|
49680
|
+
if (!run)
|
|
49681
|
+
return null;
|
|
49682
|
+
const out = {};
|
|
49683
|
+
for (const slotId of run.processes.keys()) {
|
|
49684
|
+
const idle = run.idleMsFor(slotId);
|
|
49685
|
+
if (idle !== null)
|
|
49686
|
+
out[slotId] = Math.round(idle / 1000);
|
|
49687
|
+
}
|
|
49688
|
+
return out;
|
|
49689
|
+
}
|
|
49690
|
+
function teamSlotActivity(teamSessionId) {
|
|
49691
|
+
const run = liveTeamRuns.get(teamSessionId);
|
|
49692
|
+
if (!run)
|
|
49693
|
+
return null;
|
|
49694
|
+
const out = {};
|
|
49695
|
+
for (const slotId of run.processes.keys()) {
|
|
49696
|
+
const activity = run.activityFor(slotId);
|
|
49697
|
+
if (activity !== null)
|
|
49698
|
+
out[slotId] = activity;
|
|
49699
|
+
}
|
|
49700
|
+
return out;
|
|
49701
|
+
}
|
|
49702
|
+
async function cancelTeamRun(teamSessionId, slotId) {
|
|
49703
|
+
const run = liveTeamRuns.get(teamSessionId);
|
|
49704
|
+
if (!run)
|
|
49705
|
+
return { found: false, cancelled: [] };
|
|
49706
|
+
const targets = slotId ? run.processes.has(slotId) ? [slotId] : [] : [...run.processes.keys()];
|
|
49707
|
+
const cancelled = [];
|
|
49708
|
+
for (const id of targets) {
|
|
49709
|
+
const proc = run.processes.get(id);
|
|
49710
|
+
if (!proc)
|
|
49711
|
+
continue;
|
|
49712
|
+
run.cancelledSlots.add(id);
|
|
49713
|
+
await terminateChildTree(proc);
|
|
49714
|
+
cancelled.push(id);
|
|
49715
|
+
}
|
|
49716
|
+
return { found: true, cancelled };
|
|
49717
|
+
}
|
|
49718
|
+
async function shutdownAllTeamRuns() {
|
|
49719
|
+
await Promise.all([...liveTeamRuns.keys()].map((id) => cancelTeamRun(id).catch(() => {
|
|
49720
|
+
return;
|
|
49721
|
+
})));
|
|
49722
|
+
}
|
|
49530
49723
|
function classifyRunOutput(opts) {
|
|
49531
49724
|
const {
|
|
49532
49725
|
outputSize,
|
|
@@ -49606,6 +49799,21 @@ function validateSessionPath(sessionPath) {
|
|
|
49606
49799
|
}
|
|
49607
49800
|
return resolved;
|
|
49608
49801
|
}
|
|
49802
|
+
function readTeamInputFile(inputPath) {
|
|
49803
|
+
const resolved = resolve3(inputPath);
|
|
49804
|
+
const cwd = process.cwd();
|
|
49805
|
+
if (!resolved.startsWith(`${cwd}/`) && resolved !== cwd) {
|
|
49806
|
+
throw new Error(`Input file must be within current directory: ${inputPath}`);
|
|
49807
|
+
}
|
|
49808
|
+
if (!existsSync20(resolved)) {
|
|
49809
|
+
throw new Error(`Input file not found: ${resolved}`);
|
|
49810
|
+
}
|
|
49811
|
+
const text = readFileSync19(resolved, "utf-8");
|
|
49812
|
+
if (text.trim().length === 0) {
|
|
49813
|
+
throw new Error(`Input file is empty: ${resolved}`);
|
|
49814
|
+
}
|
|
49815
|
+
return text;
|
|
49816
|
+
}
|
|
49609
49817
|
function setupSession(sessionPath, models, input) {
|
|
49610
49818
|
if (models.length === 0) {
|
|
49611
49819
|
throw new Error("At least one model is required");
|
|
@@ -49672,8 +49880,7 @@ function readFullOutputIfNeeded(opts) {
|
|
|
49672
49880
|
return;
|
|
49673
49881
|
}
|
|
49674
49882
|
}
|
|
49675
|
-
async function
|
|
49676
|
-
const timeoutMs = (opts.timeout ?? 300) * 1000;
|
|
49883
|
+
async function startModels(sessionPath, opts = {}) {
|
|
49677
49884
|
assertValidRequirePattern(opts.requirePattern);
|
|
49678
49885
|
const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
|
|
49679
49886
|
const statusPath = join29(sessionPath, "status.json");
|
|
@@ -49719,6 +49926,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49719
49926
|
mkdirSync11(statsDir(sessionPath), { recursive: true });
|
|
49720
49927
|
const processes = new Map;
|
|
49721
49928
|
const runtimes = new Map;
|
|
49929
|
+
const cancelledSlots = new Set;
|
|
49722
49930
|
const sigintHandler = () => {
|
|
49723
49931
|
for (const [, proc] of processes) {
|
|
49724
49932
|
signalProcessTree(proc, "SIGTERM");
|
|
@@ -49730,6 +49938,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49730
49938
|
for (const [anonId, entry] of Object.entries(manifest.models)) {
|
|
49731
49939
|
const outputPath = join29(sessionPath, `response-${anonId}.md`);
|
|
49732
49940
|
const errorLogPath = join29(sessionPath, "errors", `${anonId}.log`);
|
|
49941
|
+
const upstreamErrorLogPath = join29(sessionPath, "errors", `${anonId}-upstream.jsonl`);
|
|
49733
49942
|
const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
|
|
49734
49943
|
const args = [
|
|
49735
49944
|
"--model",
|
|
@@ -49750,21 +49959,37 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49750
49959
|
detached: KILL_PROCESS_GROUP,
|
|
49751
49960
|
env: {
|
|
49752
49961
|
...process.env,
|
|
49753
|
-
CLAUDISH_TOKEN_FILE: tokenFileFor(sessionPath, anonId)
|
|
49962
|
+
[ENV.CLAUDISH_TOKEN_FILE]: tokenFileFor(sessionPath, anonId),
|
|
49963
|
+
[UPSTREAM_ERROR_LOG_ENV]: upstreamErrorLogPath
|
|
49754
49964
|
}
|
|
49755
49965
|
});
|
|
49966
|
+
let lastOutputAt = Date.now();
|
|
49967
|
+
const stampLiveness = () => {
|
|
49968
|
+
lastOutputAt = Date.now();
|
|
49969
|
+
};
|
|
49970
|
+
const stdoutDecoder = newStdioDecoder();
|
|
49971
|
+
const stderrDecoder = newStdioDecoder();
|
|
49972
|
+
proc.stdout?.on("data", stampLiveness);
|
|
49973
|
+
proc.stderr?.on("data", stampLiveness);
|
|
49756
49974
|
let byteCount = 0;
|
|
49757
49975
|
let stdoutTail = "";
|
|
49758
49976
|
const outputStream = createWriteStream(outputPath);
|
|
49759
49977
|
let flushPartial = () => {};
|
|
49978
|
+
let reducer = null;
|
|
49760
49979
|
if (captureMode === "print") {
|
|
49761
49980
|
proc.stdout?.on("data", (chunk) => {
|
|
49762
49981
|
byteCount += chunk.length;
|
|
49763
|
-
stdoutTail = (stdoutTail + chunk
|
|
49982
|
+
stdoutTail = (stdoutTail + decodeChunk(stdoutDecoder, chunk)).slice(-STDOUT_TAIL_LIMIT);
|
|
49764
49983
|
});
|
|
49765
49984
|
proc.stdout?.pipe(outputStream);
|
|
49766
49985
|
} else {
|
|
49767
|
-
const
|
|
49986
|
+
const slotReducer = new StreamJsonReducer({
|
|
49987
|
+
sessionId: anonId,
|
|
49988
|
+
stallSeconds: 0,
|
|
49989
|
+
keepUnrecognizedJson: true,
|
|
49990
|
+
callback: () => {}
|
|
49991
|
+
});
|
|
49992
|
+
reducer = slotReducer;
|
|
49768
49993
|
const absorb = (text) => {
|
|
49769
49994
|
if (text.length === 0)
|
|
49770
49995
|
return;
|
|
@@ -49772,14 +49997,15 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49772
49997
|
stdoutTail = (stdoutTail + text).slice(-STDOUT_TAIL_LIMIT);
|
|
49773
49998
|
outputStream.write(text);
|
|
49774
49999
|
};
|
|
49775
|
-
proc.stdout?.on("data", (chunk) => absorb(
|
|
49776
|
-
flushPartial = () => absorb(
|
|
50000
|
+
proc.stdout?.on("data", (chunk) => absorb(slotReducer.feed(decodeChunk(stdoutDecoder, chunk))));
|
|
50001
|
+
flushPartial = () => absorb(slotReducer.end());
|
|
49777
50002
|
let captureFinalized = false;
|
|
49778
50003
|
const finalizeCapture = () => {
|
|
49779
50004
|
if (captureFinalized)
|
|
49780
50005
|
return;
|
|
49781
50006
|
captureFinalized = true;
|
|
49782
|
-
absorb(
|
|
50007
|
+
absorb(slotReducer.end());
|
|
50008
|
+
slotReducer.dispose();
|
|
49783
50009
|
outputStream.end();
|
|
49784
50010
|
};
|
|
49785
50011
|
proc.stdout?.on("end", finalizeCapture);
|
|
@@ -49787,7 +50013,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49787
50013
|
}
|
|
49788
50014
|
let stderr = "";
|
|
49789
50015
|
proc.stderr?.on("data", (chunk) => {
|
|
49790
|
-
stderr += chunk
|
|
50016
|
+
stderr += decodeChunk(stderrDecoder, chunk);
|
|
49791
50017
|
});
|
|
49792
50018
|
const command = `claudish ${args.join(" ")}`;
|
|
49793
50019
|
runtimes.set(anonId, {
|
|
@@ -49796,6 +50022,8 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49796
50022
|
getStderr: () => stderr,
|
|
49797
50023
|
getStdoutTail: () => stdoutTail,
|
|
49798
50024
|
getByteCount: () => byteCount,
|
|
50025
|
+
getIdleMs: () => Math.max(0, Date.now() - lastOutputAt),
|
|
50026
|
+
getActivity: () => reducer?.state ?? null,
|
|
49799
50027
|
flushPartial: () => flushPartial()
|
|
49800
50028
|
});
|
|
49801
50029
|
proc.stdin?.write(inputContent);
|
|
@@ -49833,8 +50061,9 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49833
50061
|
const failed = crashed || degraded !== null;
|
|
49834
50062
|
const state = crashed ? "FAILED" : degraded ? "EMPTY" : "COMPLETED";
|
|
49835
50063
|
if (failed) {
|
|
49836
|
-
const
|
|
49837
|
-
const
|
|
50064
|
+
const wasCancelled = cancelledSlots.has(anonId);
|
|
50065
|
+
const reason = wasCancelled ? "cancelled" : crashed ? "nonzero_exit" : degraded.reason;
|
|
50066
|
+
const detail = wasCancelled ? `Stopped on the caller's instruction via team(mode:"cancel"). ` + "Whatever the child had written up to that point is in its response file." : crashed ? `Child exited with code ${exitCode}.` : degraded.detail;
|
|
49838
50067
|
persistErrorLog(errorLogPath, `${state}: ${detail}`, stderr, stdoutTail);
|
|
49839
50068
|
updateModelStatus(anonId, {
|
|
49840
50069
|
state,
|
|
@@ -49849,6 +50078,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49849
50078
|
stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
|
|
49850
50079
|
stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
|
|
49851
50080
|
errorLogPath,
|
|
50081
|
+
upstreamErrorLogPath: existsSync20(upstreamErrorLogPath) ? upstreamErrorLogPath : undefined,
|
|
49852
50082
|
workDir: sessionPath
|
|
49853
50083
|
}
|
|
49854
50084
|
});
|
|
@@ -49909,102 +50139,36 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
49909
50139
|
emitProgress();
|
|
49910
50140
|
const progressHandle = setInterval(() => emitProgress("running"), POLL_MS);
|
|
49911
50141
|
progressHandle.unref?.();
|
|
49912
|
-
const
|
|
49913
|
-
|
|
49914
|
-
|
|
49915
|
-
|
|
49916
|
-
|
|
49917
|
-
|
|
49918
|
-
|
|
49919
|
-
|
|
49920
|
-
|
|
49921
|
-
|
|
49922
|
-
|
|
49923
|
-
|
|
49924
|
-
|
|
49925
|
-
|
|
49926
|
-
|
|
49927
|
-
|
|
49928
|
-
const proc = processes.get(id);
|
|
49929
|
-
if (!proc || statusCache.models[id]?.state !== "RUNNING")
|
|
49930
|
-
return;
|
|
49931
|
-
const rt = runtimes.get(id);
|
|
49932
|
-
rt?.flushPartial();
|
|
49933
|
-
const stderr = rt?.getStderr() ?? "";
|
|
49934
|
-
const stdoutTail = rt?.getStdoutTail() ?? "";
|
|
49935
|
-
const bytes2 = rt?.getByteCount() ?? 0;
|
|
49936
|
-
const grace = graceUsedMs(id, Date.now());
|
|
49937
|
-
const detail = `Killed by the orchestrator after ${(timeoutMs + grace) / 1000}s ` + `(deadline ${timeoutMs / 1000}s${grace ? ` + ${grace / 1000}s grace` : ""}) ` + `with ${bytes2} B of stdout \u2014 ${why}. ` + "That figure counts the ANSWER, not the wire format, so 0 B means the child had " + `not produced an assistant message yet \u2014 "did not finish", not "produced nothing".`;
|
|
49938
|
-
if (rt)
|
|
49939
|
-
persistErrorLog(rt.errorLogPath, `TIMEOUT: ${detail}`, stderr, stdoutTail);
|
|
49940
|
-
updateModelStatus(id, {
|
|
49941
|
-
state: "TIMEOUT",
|
|
49942
|
-
completedAt: new Date().toISOString(),
|
|
49943
|
-
outputSize: bytes2,
|
|
49944
|
-
error: rt ? {
|
|
49945
|
-
model: id,
|
|
49946
|
-
command: rt.command,
|
|
49947
|
-
reason: "timeout",
|
|
49948
|
-
detail,
|
|
49949
|
-
stderrSnippet: stderr ? redactSecrets(stderr).slice(-2000) : undefined,
|
|
49950
|
-
stdoutSnippet: stdoutTail ? redactSecrets(stdoutTail).slice(-2000) : undefined,
|
|
49951
|
-
errorLogPath: rt.errorLogPath,
|
|
49952
|
-
workDir: sessionPath
|
|
49953
|
-
} : undefined
|
|
49954
|
-
});
|
|
49955
|
-
opts.onStatusChange?.(id, statusCache.models[id]);
|
|
49956
|
-
const stopped = await terminateChildTree(proc);
|
|
49957
|
-
if (!stopped) {
|
|
49958
|
-
persistErrorLog(rt?.errorLogPath ?? join29(sessionPath, "errors", `${id}.log`), "TIMEOUT: child survived SIGKILL \u2014 it may still be running and billing", stderr, stdoutTail);
|
|
50142
|
+
const teamSessionId = basename2(sessionPath);
|
|
50143
|
+
liveTeamRuns.set(teamSessionId, {
|
|
50144
|
+
sessionPath,
|
|
50145
|
+
processes,
|
|
50146
|
+
idleMsFor: (slotId) => runtimes.get(slotId)?.getIdleMs() ?? null,
|
|
50147
|
+
activityFor: (slotId) => runtimes.get(slotId)?.getActivity() ?? null,
|
|
50148
|
+
cancelledSlots
|
|
50149
|
+
});
|
|
50150
|
+
const done = (async () => {
|
|
50151
|
+
try {
|
|
50152
|
+
await Promise.all(completionPromises);
|
|
50153
|
+
} finally {
|
|
50154
|
+
clearInterval(progressHandle);
|
|
50155
|
+
emitProgress("settled");
|
|
50156
|
+
process.off("SIGINT", sigintHandler);
|
|
50157
|
+
liveTeamRuns.delete(teamSessionId);
|
|
49959
50158
|
}
|
|
50159
|
+
return statusCache;
|
|
50160
|
+
})();
|
|
50161
|
+
done.catch(() => {});
|
|
50162
|
+
return {
|
|
50163
|
+
teamSessionId,
|
|
50164
|
+
sessionPath,
|
|
50165
|
+
slots: Object.fromEntries(Object.entries(manifest.models).map(([anonId, entry]) => [entry.model, anonId])),
|
|
50166
|
+
done
|
|
49960
50167
|
};
|
|
49961
|
-
|
|
49962
|
-
|
|
49963
|
-
|
|
49964
|
-
|
|
49965
|
-
}, () => {
|
|
49966
|
-
settled = true;
|
|
49967
|
-
});
|
|
49968
|
-
const deadlineWatcher = (async () => {
|
|
49969
|
-
await delay(timeoutMs);
|
|
49970
|
-
for (;; ) {
|
|
49971
|
-
if (settled)
|
|
49972
|
-
return;
|
|
49973
|
-
const running = runningIds();
|
|
49974
|
-
if (running.length === 0)
|
|
49975
|
-
return;
|
|
49976
|
-
const extended = [];
|
|
49977
|
-
const now2 = Date.now();
|
|
49978
|
-
for (const id of running) {
|
|
49979
|
-
const idleMs = idleMsFor(id);
|
|
49980
|
-
const usedGrace = graceUsedMs(id, now2);
|
|
49981
|
-
if (!graceEnabled) {
|
|
49982
|
-
await timeoutModel(id, "deadline reached (grace extension disabled)");
|
|
49983
|
-
} else if (usedGrace >= maxGraceMs) {
|
|
49984
|
-
await timeoutModel(id, `grace exhausted after ${Math.round(usedGrace / 1000)}s of extra time`);
|
|
49985
|
-
} else if (idleMs === null) {
|
|
49986
|
-
await timeoutModel(id, "deadline reached with no measurable progress to extend for");
|
|
49987
|
-
} else if (idleMs >= stallMs) {
|
|
49988
|
-
await timeoutModel(id, `no measurable progress for ${Math.round(idleMs / 1000)}s`);
|
|
49989
|
-
} else {
|
|
49990
|
-
if (!graceStartedAt.has(id))
|
|
49991
|
-
graceStartedAt.set(id, now2);
|
|
49992
|
-
extended.push(id);
|
|
49993
|
-
}
|
|
49994
|
-
}
|
|
49995
|
-
if (extended.length === 0)
|
|
49996
|
-
return;
|
|
49997
|
-
emitProgress("running");
|
|
49998
|
-
await delay(Math.min(GRACE_INTERVAL_MS, Math.max(1000, stallMs)));
|
|
49999
|
-
}
|
|
50000
|
-
})().catch(() => {});
|
|
50001
|
-
await Promise.race([allDone, deadlineWatcher]);
|
|
50002
|
-
if (!settled)
|
|
50003
|
-
await Promise.race([allDone, delay(DRAIN_TIMEOUT_MS)]);
|
|
50004
|
-
clearInterval(progressHandle);
|
|
50005
|
-
emitProgress("settled");
|
|
50006
|
-
process.off("SIGINT", sigintHandler);
|
|
50007
|
-
return statusCache;
|
|
50168
|
+
}
|
|
50169
|
+
async function runModels(sessionPath, opts = {}) {
|
|
50170
|
+
const handle = await startModels(sessionPath, opts);
|
|
50171
|
+
return handle.done;
|
|
50008
50172
|
}
|
|
50009
50173
|
async function judgeResponses(sessionPath, opts = {}) {
|
|
50010
50174
|
const responseFiles = readdirSync5(sessionPath).filter((f) => f.startsWith("response-") && f.endsWith(".md")).sort();
|
|
@@ -50186,16 +50350,17 @@ function formatVerdict(verdict, sessionPath) {
|
|
|
50186
50350
|
}
|
|
50187
50351
|
return output;
|
|
50188
50352
|
}
|
|
50189
|
-
var TEAM_CAPTURE_ENV_VAR = "CLAUDISH_TEAM_CAPTURE", STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0,
|
|
50190
|
-
const t = setTimeout(resolve4, ms);
|
|
50191
|
-
t.unref?.();
|
|
50192
|
-
}), BENIGN_STDERR_PATTERNS;
|
|
50353
|
+
var TEAM_CAPTURE_ENV_VAR = "CLAUDISH_TEAM_CAPTURE", liveTeamRuns, STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0, BENIGN_STDERR_PATTERNS;
|
|
50193
50354
|
var init_team_orchestrator = __esm(() => {
|
|
50194
50355
|
init_prehydrate();
|
|
50356
|
+
init_stream_json_reducer();
|
|
50357
|
+
init_config2();
|
|
50358
|
+
init_upstream_error_capture();
|
|
50195
50359
|
init_process_tree();
|
|
50196
50360
|
init_redact();
|
|
50361
|
+
init_stdio_decode();
|
|
50197
50362
|
init_team_stats();
|
|
50198
|
-
|
|
50363
|
+
liveTeamRuns = new Map;
|
|
50199
50364
|
API_ERROR_RE = /\[API Error:\s*([^\]]{0,300})\]/i;
|
|
50200
50365
|
BG_CEILING_RE = /Background tasks still running after (\d+)s; terminating/i;
|
|
50201
50366
|
BENIGN_STDERR_PATTERNS = [/^\s*\[claude-code:unrecognized_model\]/];
|
|
@@ -50217,7 +50382,7 @@ import {
|
|
|
50217
50382
|
} from "fs";
|
|
50218
50383
|
import { homedir as homedir28 } from "os";
|
|
50219
50384
|
import { join as join30, resolve as resolve4, sep } from "path";
|
|
50220
|
-
import { StringDecoder } from "string_decoder";
|
|
50385
|
+
import { StringDecoder as StringDecoder2 } from "string_decoder";
|
|
50221
50386
|
function buildChannelSpawnArgs(opts) {
|
|
50222
50387
|
return [
|
|
50223
50388
|
"--model",
|
|
@@ -50248,9 +50413,6 @@ function assertNoReservedFlags(flags) {
|
|
|
50248
50413
|
}
|
|
50249
50414
|
}
|
|
50250
50415
|
}
|
|
50251
|
-
function decodeChunk(decoder, chunk) {
|
|
50252
|
-
return typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
50253
|
-
}
|
|
50254
50416
|
function readTailText(path, maxBytes) {
|
|
50255
50417
|
let fd = null;
|
|
50256
50418
|
try {
|
|
@@ -50359,11 +50521,14 @@ class SessionManager {
|
|
|
50359
50521
|
throw new Error(`Max sessions (${this.maxSessions}) reached`);
|
|
50360
50522
|
}
|
|
50361
50523
|
assertNoReservedFlags(opts.claudishFlags);
|
|
50362
|
-
|
|
50524
|
+
if (opts.sessionId !== undefined && this.sessions.has(opts.sessionId)) {
|
|
50525
|
+
throw new Error(`Session id already in use: ${opts.sessionId}`);
|
|
50526
|
+
}
|
|
50527
|
+
const sessionId2 = opts.sessionId ?? randomUUID4().slice(0, 8);
|
|
50363
50528
|
const claudeSessionId = randomUUID4();
|
|
50364
50529
|
const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
|
|
50365
50530
|
const startedAt = new Date().toISOString();
|
|
50366
|
-
const sessionDir = join30(this.sessionsDir, sessionId2);
|
|
50531
|
+
const sessionDir = opts.sessionDir ?? join30(this.sessionsDir, sessionId2);
|
|
50367
50532
|
mkdirSync12(sessionDir, { recursive: true });
|
|
50368
50533
|
if (opts.prompt) {
|
|
50369
50534
|
writeFileSync12(join30(sessionDir, "prompt.md"), opts.prompt, "utf-8");
|
|
@@ -50373,7 +50538,7 @@ class SessionManager {
|
|
|
50373
50538
|
claudeSessionId,
|
|
50374
50539
|
claudishFlags: opts.claudishFlags
|
|
50375
50540
|
});
|
|
50376
|
-
const tokenFile = join30(sessionDir, "tokens.json");
|
|
50541
|
+
const tokenFile = opts.tokenFile ?? join30(sessionDir, "tokens.json");
|
|
50377
50542
|
const eventLogPath = join30(sessionDir, "events.jsonl");
|
|
50378
50543
|
const upstreamErrorLogPath = join30(sessionDir, "upstream-errors.jsonl");
|
|
50379
50544
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -50399,6 +50564,7 @@ class SessionManager {
|
|
|
50399
50564
|
status: "starting",
|
|
50400
50565
|
pid: proc.pid ?? null,
|
|
50401
50566
|
startedAt,
|
|
50567
|
+
idleSeconds: 0,
|
|
50402
50568
|
completedAt: null,
|
|
50403
50569
|
exitCode: null,
|
|
50404
50570
|
turnsCompleted: 0,
|
|
@@ -50419,8 +50585,8 @@ class SessionManager {
|
|
|
50419
50585
|
evictHandle: null,
|
|
50420
50586
|
stderr: "",
|
|
50421
50587
|
stderrTruncated: false,
|
|
50422
|
-
stdoutDecoder: new
|
|
50423
|
-
stderrDecoder: new
|
|
50588
|
+
stdoutDecoder: new StringDecoder2("utf8"),
|
|
50589
|
+
stderrDecoder: new StringDecoder2("utf8"),
|
|
50424
50590
|
outputLogStream,
|
|
50425
50591
|
sessionDir,
|
|
50426
50592
|
eventLogPath,
|
|
@@ -50441,6 +50607,7 @@ class SessionManager {
|
|
|
50441
50607
|
entry.reducer = new StreamJsonReducer({
|
|
50442
50608
|
sessionId: sessionId2,
|
|
50443
50609
|
stallSeconds: this.stallSeconds,
|
|
50610
|
+
keepUnrecognizedJson: opts.keepUnrecognizedJson,
|
|
50444
50611
|
callback: (sid, data) => {
|
|
50445
50612
|
const current = this.sessions.get(sid);
|
|
50446
50613
|
if (!current)
|
|
@@ -50527,6 +50694,7 @@ class SessionManager {
|
|
|
50527
50694
|
if (!entry)
|
|
50528
50695
|
return this.diskOutput(this.requireDiskRecord(sessionId2), tailLines);
|
|
50529
50696
|
entry.info.elapsedSeconds = this.getElapsed(entry.info.startedAt);
|
|
50697
|
+
entry.info.idleSeconds = entry.reducer ? Math.round(entry.reducer.idleMs / 1000) : null;
|
|
50530
50698
|
this.refreshAccounting(entry);
|
|
50531
50699
|
const lines = entry.scrollback.getLines(tailLines);
|
|
50532
50700
|
return {
|
|
@@ -50537,7 +50705,8 @@ class SessionManager {
|
|
|
50537
50705
|
totalLines: entry.scrollback.totalLines,
|
|
50538
50706
|
turnsCompleted: entry.info.turnsCompleted,
|
|
50539
50707
|
tokensUsed: entry.info.tokensUsed,
|
|
50540
|
-
elapsedSeconds: entry.info.elapsedSeconds
|
|
50708
|
+
elapsedSeconds: entry.info.elapsedSeconds,
|
|
50709
|
+
idleSeconds: entry.info.idleSeconds
|
|
50541
50710
|
};
|
|
50542
50711
|
}
|
|
50543
50712
|
getDiagnostics(sessionId2, eventLimit = DEFAULT_EVENT_LIMIT) {
|
|
@@ -50547,6 +50716,7 @@ class SessionManager {
|
|
|
50547
50716
|
return this.diskDiagnostics(this.requireDiskRecord(sessionId2), limit);
|
|
50548
50717
|
this.refreshAccounting(entry);
|
|
50549
50718
|
entry.info.elapsedSeconds = this.getElapsed(entry.info.startedAt);
|
|
50719
|
+
entry.info.idleSeconds = entry.reducer ? Math.round(entry.reducer.idleMs / 1000) : null;
|
|
50550
50720
|
return {
|
|
50551
50721
|
sessionId: sessionId2,
|
|
50552
50722
|
status: entry.info.status,
|
|
@@ -50555,6 +50725,7 @@ class SessionManager {
|
|
|
50555
50725
|
exitCode: entry.info.exitCode,
|
|
50556
50726
|
terminalReason: entry.info.terminalReason,
|
|
50557
50727
|
elapsedSeconds: entry.info.elapsedSeconds,
|
|
50728
|
+
idleSeconds: entry.info.idleSeconds,
|
|
50558
50729
|
timeoutSeconds: entry.timeoutSeconds,
|
|
50559
50730
|
outputBytes: entry.proseBytes,
|
|
50560
50731
|
turnsCompleted: entry.info.turnsCompleted,
|
|
@@ -50613,6 +50784,7 @@ class SessionManager {
|
|
|
50613
50784
|
continue;
|
|
50614
50785
|
if (!isTerminal2) {
|
|
50615
50786
|
entry.info.elapsedSeconds = this.getElapsed(entry.info.startedAt);
|
|
50787
|
+
entry.info.idleSeconds = entry.reducer ? Math.round(entry.reducer.idleMs / 1000) : null;
|
|
50616
50788
|
this.refreshAccounting(entry);
|
|
50617
50789
|
}
|
|
50618
50790
|
sessions2.push({ ...entry.info });
|
|
@@ -50624,6 +50796,7 @@ class SessionManager {
|
|
|
50624
50796
|
if (!entry)
|
|
50625
50797
|
return this.requireDiskRecord(sessionId2).info;
|
|
50626
50798
|
entry.info.elapsedSeconds = this.getElapsed(entry.info.startedAt);
|
|
50799
|
+
entry.info.idleSeconds = entry.reducer ? Math.round(entry.reducer.idleMs / 1000) : null;
|
|
50627
50800
|
this.refreshAccounting(entry);
|
|
50628
50801
|
return { ...entry.info };
|
|
50629
50802
|
}
|
|
@@ -50706,6 +50879,7 @@ class SessionManager {
|
|
|
50706
50879
|
model: metaString(meta3?.model) ?? "unknown",
|
|
50707
50880
|
spawnModel: metaString(meta3?.spawnModel),
|
|
50708
50881
|
status: metaStatus(meta3?.status) ?? "failed",
|
|
50882
|
+
idleSeconds: null,
|
|
50709
50883
|
pid: null,
|
|
50710
50884
|
startedAt,
|
|
50711
50885
|
completedAt,
|
|
@@ -50735,7 +50909,8 @@ class SessionManager {
|
|
|
50735
50909
|
totalLines: buffer.totalLines,
|
|
50736
50910
|
turnsCompleted: record4.info.turnsCompleted,
|
|
50737
50911
|
tokensUsed: record4.info.tokensUsed,
|
|
50738
|
-
elapsedSeconds: record4.info.elapsedSeconds
|
|
50912
|
+
elapsedSeconds: record4.info.elapsedSeconds,
|
|
50913
|
+
idleSeconds: null
|
|
50739
50914
|
};
|
|
50740
50915
|
}
|
|
50741
50916
|
diskDiagnostics(record4, limit) {
|
|
@@ -50753,6 +50928,7 @@ class SessionManager {
|
|
|
50753
50928
|
exitCode: info.exitCode,
|
|
50754
50929
|
terminalReason: info.terminalReason,
|
|
50755
50930
|
elapsedSeconds: info.elapsedSeconds,
|
|
50931
|
+
idleSeconds: null,
|
|
50756
50932
|
timeoutSeconds: 0,
|
|
50757
50933
|
outputBytes: diskProseBytes(outputTail, fileSize(outputLogPath)),
|
|
50758
50934
|
turnsCompleted: info.turnsCompleted,
|
|
@@ -50912,6 +51088,7 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
50912
51088
|
entry.info.exitCode = code;
|
|
50913
51089
|
entry.info.completedAt = at;
|
|
50914
51090
|
entry.info.elapsedSeconds = this.getElapsed(entry.info.startedAt);
|
|
51091
|
+
entry.info.idleSeconds = entry.reducer ? Math.round(entry.reducer.idleMs / 1000) : null;
|
|
50915
51092
|
entry.stdinClosed = true;
|
|
50916
51093
|
this.flushDecoders(entry);
|
|
50917
51094
|
const priorVerdict = TERMINAL_STATUSES.includes(entry.info.status) ? entry.info.status : null;
|
|
@@ -51076,13 +51253,14 @@ ${STDERR_TRUNCATION_MARKER} ${STDERR_SIDE_LIMIT} bytes per end \u2026
|
|
|
51076
51253
|
}
|
|
51077
51254
|
}
|
|
51078
51255
|
}
|
|
51079
|
-
var DEFAULT_MAX_SESSIONS = 20, DEFAULT_SCROLLBACK = 2000, DEFAULT_TIMEOUT = 600, MAX_TIMEOUT = 3600, KILL_GRACE_MS = 5000, TERMINAL_RETENTION_MS, MAX_TERMINAL_SESSIONS = 50, STDERR_SIDE_LIMIT, EVENT_LOG_LIMIT, EVENT_RING_SIZE = 200, EVENT_PREVIEW_CHARS = 800, DEFAULT_EVENT_LIMIT = 40, UPSTREAM_ERROR_TAIL_BYTES, STDERR_TRUNCATION_MARKER = "[claudish] \u2026 stderr truncated to", TERMINAL_STATUSES, KNOWN_STATUSES, SESSION_ID_RE, META_READ_LIMIT, OUTPUT_TAIL_BYTES, STDERR_READ_BYTES, EVENT_TAIL_BYTES, NO_TERMINAL_RECORD = "claudish_no_terminal_record", RESERVED_FLAG_ALIASES, TRANSPORT_BREAKING_FLAGS, RESERVED_CHILD_FLAGS, metaString = (v) => typeof v === "string" && v.length > 0 ? v : null, metaNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, metaStatus = (v) => typeof v === "string" && KNOWN_STATUSES.includes(v) ? v : null, CLAUDISH_NOTE_PREFIX = "[claudish] ";
|
|
51256
|
+
var DEFAULT_MAX_SESSIONS = 20, DRAIN_TIMEOUT_MS = 1e4, DEFAULT_SCROLLBACK = 2000, DEFAULT_TIMEOUT = 600, MAX_TIMEOUT = 3600, KILL_GRACE_MS = 5000, TERMINAL_RETENTION_MS, MAX_TERMINAL_SESSIONS = 50, STDERR_SIDE_LIMIT, EVENT_LOG_LIMIT, EVENT_RING_SIZE = 200, EVENT_PREVIEW_CHARS = 800, DEFAULT_EVENT_LIMIT = 40, UPSTREAM_ERROR_TAIL_BYTES, STDERR_TRUNCATION_MARKER = "[claudish] \u2026 stderr truncated to", TERMINAL_STATUSES, KNOWN_STATUSES, SESSION_ID_RE, META_READ_LIMIT, OUTPUT_TAIL_BYTES, STDERR_READ_BYTES, EVENT_TAIL_BYTES, NO_TERMINAL_RECORD = "claudish_no_terminal_record", RESERVED_FLAG_ALIASES, TRANSPORT_BREAKING_FLAGS, RESERVED_CHILD_FLAGS, metaString = (v) => typeof v === "string" && v.length > 0 ? v : null, metaNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, metaStatus = (v) => typeof v === "string" && KNOWN_STATUSES.includes(v) ? v : null, CLAUDISH_NOTE_PREFIX = "[claudish] ";
|
|
51080
51257
|
var init_session_manager = __esm(() => {
|
|
51081
51258
|
init_config2();
|
|
51082
51259
|
init_upstream_error_capture();
|
|
51083
51260
|
init_process_tree();
|
|
51084
51261
|
init_redact();
|
|
51085
51262
|
init_session_discovery();
|
|
51263
|
+
init_stdio_decode();
|
|
51086
51264
|
init_team_orchestrator();
|
|
51087
51265
|
init_team_stats();
|
|
51088
51266
|
init_scrollback_buffer();
|
|
@@ -51218,68 +51396,6 @@ var init_cache_ttl = __esm(() => {
|
|
|
51218
51396
|
FIREBASE_CACHE_TTL_MS = FIREBASE_CACHE_TTL_HOURS * 60 * 60 * 1000;
|
|
51219
51397
|
});
|
|
51220
51398
|
|
|
51221
|
-
// src/providers/model-ordering.ts
|
|
51222
|
-
function extractVersionParts(modelId) {
|
|
51223
|
-
const tokens = modelId.toLowerCase().split(/[\/_-]+/);
|
|
51224
|
-
let started = false;
|
|
51225
|
-
const parts = [];
|
|
51226
|
-
for (const token of tokens) {
|
|
51227
|
-
const match = token.match(/\d+(?:\.\d+)*/);
|
|
51228
|
-
if (!match) {
|
|
51229
|
-
if (started)
|
|
51230
|
-
break;
|
|
51231
|
-
continue;
|
|
51232
|
-
}
|
|
51233
|
-
if (!started && /^\d+b$/.test(token) && Number.parseInt(match[0], 10) > 10) {
|
|
51234
|
-
continue;
|
|
51235
|
-
}
|
|
51236
|
-
if (!started) {
|
|
51237
|
-
started = true;
|
|
51238
|
-
for (const part of match[0].split(".")) {
|
|
51239
|
-
parts.push(Number.parseInt(part, 10));
|
|
51240
|
-
}
|
|
51241
|
-
if (!/^\d+(?:\.\d+)*$/.test(token)) {
|
|
51242
|
-
break;
|
|
51243
|
-
}
|
|
51244
|
-
continue;
|
|
51245
|
-
}
|
|
51246
|
-
if (!/^\d{1,2}(?:\.\d+)?$/.test(token)) {
|
|
51247
|
-
break;
|
|
51248
|
-
}
|
|
51249
|
-
for (const part of token.split(".")) {
|
|
51250
|
-
parts.push(Number.parseInt(part, 10));
|
|
51251
|
-
}
|
|
51252
|
-
}
|
|
51253
|
-
return parts;
|
|
51254
|
-
}
|
|
51255
|
-
function compareVersionPartsDesc(a, b) {
|
|
51256
|
-
const maxLength = Math.max(a.length, b.length);
|
|
51257
|
-
for (let i = 0;i < maxLength; i++) {
|
|
51258
|
-
const aPart = a[i] ?? -1;
|
|
51259
|
-
const bPart = b[i] ?? -1;
|
|
51260
|
-
if (aPart !== bPart) {
|
|
51261
|
-
return bPart - aPart;
|
|
51262
|
-
}
|
|
51263
|
-
}
|
|
51264
|
-
return 0;
|
|
51265
|
-
}
|
|
51266
|
-
function compareByReleaseDateDesc(a, b) {
|
|
51267
|
-
const aReleaseRaw = a.releaseDate ? Date.parse(a.releaseDate) : 0;
|
|
51268
|
-
const bReleaseRaw = b.releaseDate ? Date.parse(b.releaseDate) : 0;
|
|
51269
|
-
const aRelease = Number.isNaN(aReleaseRaw) ? 0 : aReleaseRaw;
|
|
51270
|
-
const bRelease = Number.isNaN(bReleaseRaw) ? 0 : bReleaseRaw;
|
|
51271
|
-
if (aRelease !== bRelease) {
|
|
51272
|
-
return bRelease - aRelease;
|
|
51273
|
-
}
|
|
51274
|
-
const aId = a.id ?? a.modelId ?? "";
|
|
51275
|
-
const bId = b.id ?? b.modelId ?? "";
|
|
51276
|
-
const versionCompare = compareVersionPartsDesc(extractVersionParts(aId), extractVersionParts(bId));
|
|
51277
|
-
if (versionCompare !== 0) {
|
|
51278
|
-
return versionCompare;
|
|
51279
|
-
}
|
|
51280
|
-
return aId.localeCompare(bId);
|
|
51281
|
-
}
|
|
51282
|
-
|
|
51283
51399
|
// src/model-loader.ts
|
|
51284
51400
|
import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
51285
51401
|
import { homedir as homedir29 } from "os";
|
|
@@ -56440,7 +56556,7 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
|
|
|
56440
56556
|
});
|
|
56441
56557
|
tools.push({
|
|
56442
56558
|
name: "search_models",
|
|
56443
|
-
description: "Search
|
|
56559
|
+
description: "Search OpenRouter's listing by name, provider, or capability, and cross-reference " + "claudish's own catalog. SCOPE: the listing covers OpenRouter only, so a name's " + "absence from it is NOT evidence the name is unroutable \u2014 subscription wire ids " + "(`k3`) and catalog aliases live outside that namespace and are reported separately " + "here. This tool cannot tell you which provider will serve a model or whether the " + "hop is subscription or metered; call `preflight` for that.",
|
|
56444
56560
|
inputSchema: {
|
|
56445
56561
|
type: "object",
|
|
56446
56562
|
properties: {
|
|
@@ -56475,13 +56591,40 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
|
|
|
56475
56591
|
return b.score - a.score;
|
|
56476
56592
|
return compareByReleaseDateDesc(orderingKey(a.model), orderingKey(b.model));
|
|
56477
56593
|
}).slice(0, maxResults);
|
|
56594
|
+
const catalogMatches = searchCatalogModels(query, Math.max(maxResults, 5));
|
|
56595
|
+
const renderCatalogSection = () => {
|
|
56596
|
+
if (catalogMatches.length === 0)
|
|
56597
|
+
return "";
|
|
56598
|
+
let s = `
|
|
56599
|
+
## Catalog names (what claudish routes)
|
|
56600
|
+
|
|
56601
|
+
`;
|
|
56602
|
+
s += `| Bare name | Matched alias | Subscription plan |
|
|
56603
|
+
`;
|
|
56604
|
+
s += `|-----------|---------------|-------------------|
|
|
56605
|
+
`;
|
|
56606
|
+
for (const m of catalogMatches) {
|
|
56607
|
+
const plans = m.subscriptionPlans.length > 0 ? m.subscriptionPlans.join(", ") : "-";
|
|
56608
|
+
s += `| ${m.modelId} | ${m.matchedAlias ?? "-"} | ${plans} |
|
|
56609
|
+
`;
|
|
56610
|
+
}
|
|
56611
|
+
s += `
|
|
56612
|
+
Pass the **bare name**. Routing puts a subscription ahead of the metered API and ` + "rewrites the model to that plan's wire id for you. An aggregator-qualified id " + "(`moonshotai/...`, `accounts/fireworks/...`) pins that aggregator and bills per token.\n";
|
|
56613
|
+
return s;
|
|
56614
|
+
};
|
|
56478
56615
|
if (results.length === 0) {
|
|
56479
|
-
|
|
56480
|
-
|
|
56481
|
-
|
|
56616
|
+
const catalog = renderCatalogSection();
|
|
56617
|
+
const text = catalog ? `No OpenRouter listing matches "${query}", but claudish's catalog knows these:
|
|
56618
|
+
${catalog}` : `No models found matching "${query}".
|
|
56619
|
+
|
|
56620
|
+
` + "This searched OpenRouter's listing only. Subscription wire ids and catalog " + "aliases are not in it, so this is not proof the name is unroutable. Call " + "`list_models` for the recommended set, or `preflight` to test a specific name " + "against real routing.";
|
|
56621
|
+
return { content: [{ type: "text", text }] };
|
|
56482
56622
|
}
|
|
56483
56623
|
let output = `# Search Results for "${query}"
|
|
56484
56624
|
|
|
56625
|
+
`;
|
|
56626
|
+
output += `## OpenRouter listing
|
|
56627
|
+
|
|
56485
56628
|
`;
|
|
56486
56629
|
output += `| Model | Provider | Pricing | Context |
|
|
56487
56630
|
`;
|
|
@@ -56497,8 +56640,13 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
|
|
|
56497
56640
|
output += `| ${model.id} | ${provider} | ${pricing} | ${context} |
|
|
56498
56641
|
`;
|
|
56499
56642
|
}
|
|
56643
|
+
output += renderCatalogSection();
|
|
56644
|
+
const suggested = catalogMatches[0]?.modelId ?? results[0].model.id;
|
|
56500
56645
|
output += `
|
|
56501
|
-
Use with: run_prompt(model="${
|
|
56646
|
+
Use with: run_prompt(model="${suggested}", prompt="your prompt")`;
|
|
56647
|
+
output += `
|
|
56648
|
+
|
|
56649
|
+
To learn which provider would actually serve \`${suggested}\`, and whether that ` + "hop is covered by a subscription or billed per token, call " + `\`preflight({models: ["${suggested}"]})\`. This listing cannot answer that.`;
|
|
56502
56650
|
return { content: [{ type: "text", text: output }] };
|
|
56503
56651
|
}
|
|
56504
56652
|
});
|
|
@@ -56687,14 +56835,18 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56687
56835
|
});
|
|
56688
56836
|
tools.push({
|
|
56689
56837
|
name: "team",
|
|
56690
|
-
description: "Run AI models on a task with anonymized outputs and optional blind judging. Modes: 'run' (
|
|
56838
|
+
description: "Run AI models on a task with anonymized outputs and optional blind judging. " + "Modes: 'run' (START the models and return a slot map immediately \u2014 it does NOT " + "wait), 'status' (per-slot state, plus how long each slot has been silent), " + "'cancel' (stop one slot or the whole run), 'judge' (blind-vote on existing " + "outputs), 'run-and-judge' (the blocking pipeline). " + "NO SLOT IS EVER KILLED ON A TIMER. A team slot is a full Claude Code session and " + "may work for a long time; a slot inside a build or test suite emits nothing for " + "minutes and is working, not stuck. Poll 'status', judge the silence against the " + "task you set, and use 'cancel' if you decide a slot is wedged.",
|
|
56691
56839
|
inputSchema: {
|
|
56692
56840
|
type: "object",
|
|
56693
56841
|
properties: {
|
|
56694
56842
|
mode: {
|
|
56695
56843
|
type: "string",
|
|
56696
|
-
enum: ["run", "judge", "run-and-judge", "status"],
|
|
56697
|
-
description: "Operation mode"
|
|
56844
|
+
enum: ["run", "judge", "run-and-judge", "status", "cancel"],
|
|
56845
|
+
description: "Operation mode. 'run' STARTS the models and returns immediately with a " + "slot map \u2014 it does not wait. Poll 'status' for progress, then 'judge' once " + "the slots have finished. 'run-and-judge' is the blocking pipeline and holds " + "the call open for the whole run. 'cancel' stops one slot or the whole run."
|
|
56846
|
+
},
|
|
56847
|
+
slot: {
|
|
56848
|
+
type: "string",
|
|
56849
|
+
description: "For 'cancel': the anonymised slot id to stop (e.g. '02'), from the slot map " + "'run' returned. Omit to cancel every slot in the run."
|
|
56698
56850
|
},
|
|
56699
56851
|
path: {
|
|
56700
56852
|
type: "string",
|
|
@@ -56710,11 +56862,14 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56710
56862
|
items: { type: "string" },
|
|
56711
56863
|
description: "Model IDs to use as judges (default: same as runners)"
|
|
56712
56864
|
},
|
|
56865
|
+
input_file: {
|
|
56866
|
+
type: "string",
|
|
56867
|
+
description: "PREFERRED. Path to a file holding the task prompt, relative to the working " + "directory. Use this rather than `input` for anything longer than a sentence: " + "a prompt passed inline is echoed verbatim in the caller's terminal, where a " + "200-line review brief buries every other argument and makes the call " + "unreadable. Write the brief to the session directory first (input.md is the " + "conventional name) and point here."
|
|
56868
|
+
},
|
|
56713
56869
|
input: {
|
|
56714
56870
|
type: "string",
|
|
56715
|
-
description: "Task prompt text
|
|
56871
|
+
description: "Task prompt as inline text. Prefer `input_file` \u2014 inline text is rendered in " + "full in the caller's terminal. Passing both is an error. If neither is given, " + "an input.md already present in the session directory is used."
|
|
56716
56872
|
},
|
|
56717
|
-
timeout: { type: "number", description: "Per-model timeout in seconds (default: 300)" },
|
|
56718
56873
|
require_pattern: {
|
|
56719
56874
|
type: "string",
|
|
56720
56875
|
description: "Regex the response MUST match, or the slot is reported FAILED (state EMPTY, " + "reason 'shape_mismatch') instead of succeeded. Strongly recommended whenever " + "your prompt mandates an output shape \u2014 e.g. '```vote' for a voting panel. " + "Exit code 0 is not a success oracle: it is 0 on API errors and on a child " + "that simply never followed the format. Answers are no longer LOST to print " + "mode (every assistant message is captured), so a mismatch now means the model " + "did not produce the shape, not that the shape was discarded."
|
|
@@ -56742,8 +56897,12 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56742
56897
|
const path = args.path;
|
|
56743
56898
|
const models = args.models;
|
|
56744
56899
|
const judges = args.judges;
|
|
56745
|
-
const
|
|
56746
|
-
const
|
|
56900
|
+
const inlineInput = args.input;
|
|
56901
|
+
const inputFile = args.input_file;
|
|
56902
|
+
if (inlineInput !== undefined && inputFile !== undefined) {
|
|
56903
|
+
throw new Error("Pass `input_file` or `input`, not both. Prefer `input_file` \u2014 inline text is " + "rendered verbatim in the caller's terminal.");
|
|
56904
|
+
}
|
|
56905
|
+
const input = inputFile !== undefined ? readTeamInputFile(inputFile) : inlineInput;
|
|
56747
56906
|
const requirePattern = args.require_pattern;
|
|
56748
56907
|
const minOutputBytes = args.min_output_bytes;
|
|
56749
56908
|
const childFlags = buildChildClaudeFlags(args.agent, args.claude_flags);
|
|
@@ -56752,7 +56911,6 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56752
56911
|
const teamSessionId = resolved.split("/").filter(Boolean).pop() ?? "team";
|
|
56753
56912
|
const teamCreatedAt = new Date().toISOString();
|
|
56754
56913
|
const runOpts = {
|
|
56755
|
-
timeout,
|
|
56756
56914
|
requirePattern,
|
|
56757
56915
|
minOutputBytes,
|
|
56758
56916
|
claudeFlags: childFlags,
|
|
@@ -56773,9 +56931,51 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56773
56931
|
if (!models?.length)
|
|
56774
56932
|
throw new Error("'models' is required for 'run' mode");
|
|
56775
56933
|
setupSession(resolved, models, input);
|
|
56776
|
-
const
|
|
56934
|
+
const handle = await startModels(resolved, runOpts);
|
|
56935
|
+
return {
|
|
56936
|
+
content: [
|
|
56937
|
+
{
|
|
56938
|
+
type: "text",
|
|
56939
|
+
text: JSON.stringify({
|
|
56940
|
+
started: true,
|
|
56941
|
+
team_session_id: handle.teamSessionId,
|
|
56942
|
+
session_path: handle.sessionPath,
|
|
56943
|
+
slots: handle.slots,
|
|
56944
|
+
next: {
|
|
56945
|
+
status: `team(mode:"status", path:"${handle.sessionPath}")`,
|
|
56946
|
+
cancel: `team(mode:"cancel", path:"${handle.sessionPath}", slot:"<id>")`,
|
|
56947
|
+
judge: `team(mode:"judge", path:"${handle.sessionPath}") once every slot has finished`
|
|
56948
|
+
},
|
|
56949
|
+
note: "Nothing terminates a slot on a timer. `status` reports how many " + "seconds each slot has been silent; a slot inside a long build is " + "quiet and working. You decide whether to cancel."
|
|
56950
|
+
}, null, 2)
|
|
56951
|
+
}
|
|
56952
|
+
]
|
|
56953
|
+
};
|
|
56954
|
+
}
|
|
56955
|
+
case "cancel": {
|
|
56956
|
+
const slot = args.slot;
|
|
56957
|
+
const teamSessionId2 = resolved.split("/").filter(Boolean).pop() ?? "team";
|
|
56958
|
+
const result = await cancelTeamRun(teamSessionId2, slot);
|
|
56959
|
+
if (!result.found) {
|
|
56960
|
+
return {
|
|
56961
|
+
content: [
|
|
56962
|
+
{
|
|
56963
|
+
type: "text",
|
|
56964
|
+
text: JSON.stringify({
|
|
56965
|
+
cancelled: [],
|
|
56966
|
+
note: "No live run for that path. It already settled (read `status`), or " + "it was started by a different process \u2014 this server can only stop " + "children it spawned."
|
|
56967
|
+
})
|
|
56968
|
+
}
|
|
56969
|
+
]
|
|
56970
|
+
};
|
|
56971
|
+
}
|
|
56777
56972
|
return {
|
|
56778
|
-
content: [
|
|
56973
|
+
content: [
|
|
56974
|
+
{
|
|
56975
|
+
type: "text",
|
|
56976
|
+
text: JSON.stringify({ cancelled: result.cancelled }, null, 2)
|
|
56977
|
+
}
|
|
56978
|
+
]
|
|
56779
56979
|
};
|
|
56780
56980
|
}
|
|
56781
56981
|
case "judge": {
|
|
@@ -56792,7 +56992,25 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
56792
56992
|
}
|
|
56793
56993
|
case "status": {
|
|
56794
56994
|
const status = getStatus(resolved);
|
|
56795
|
-
|
|
56995
|
+
const teamSessionId2 = resolved.split("/").filter(Boolean).pop() ?? "team";
|
|
56996
|
+
const idle = teamSlotIdleSeconds(teamSessionId2);
|
|
56997
|
+
const settled = !Object.values(status.models).some((m) => m.state === "RUNNING");
|
|
56998
|
+
return {
|
|
56999
|
+
content: [
|
|
57000
|
+
{
|
|
57001
|
+
type: "text",
|
|
57002
|
+
text: JSON.stringify({
|
|
57003
|
+
...status,
|
|
57004
|
+
idle_seconds_by_slot: idle,
|
|
57005
|
+
activity_by_slot: teamSlotActivity(teamSessionId2),
|
|
57006
|
+
...idle ? {
|
|
57007
|
+
note: "idle_seconds_by_slot is how long each slot has been silent; " + "read it against activity_by_slot. Silence in tool_executing " + "is a build or test suite running, and is not a failure " + 'signal. Nothing cancels on your behalf \u2014 use mode:"cancel" ' + "if you decide to."
|
|
57008
|
+
} : {},
|
|
57009
|
+
...settled ? { summary: formatTeamResult(status, resolved) } : {}
|
|
57010
|
+
}, null, 2)
|
|
57011
|
+
}
|
|
57012
|
+
]
|
|
57013
|
+
};
|
|
56796
57014
|
}
|
|
56797
57015
|
default:
|
|
56798
57016
|
throw new Error(`Unknown mode: ${mode}`);
|
|
@@ -57112,7 +57330,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
57112
57330
|
});
|
|
57113
57331
|
tools.push({
|
|
57114
57332
|
name: "list_sessions",
|
|
57115
|
-
description: "List all active channel sessions. Optionally include completed sessions.",
|
|
57333
|
+
description: "List all active channel sessions. Optionally include completed sessions. " + "Each session reports `idleSeconds`: how long since the child last emitted " + "anything. Nothing kills a session for being idle \u2014 a child inside a long " + "Bash call is silent and working \u2014 so this is yours to judge against the " + "task you set, and `cancel_session` is yours to call if the answer is no.",
|
|
57116
57334
|
inputSchema: {
|
|
57117
57335
|
type: "object",
|
|
57118
57336
|
properties: {
|
|
@@ -57132,7 +57350,7 @@ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}`
|
|
|
57132
57350
|
});
|
|
57133
57351
|
tools.push({
|
|
57134
57352
|
name: "get_diagnostics",
|
|
57135
|
-
description: "Explain what a channel session actually did \u2014 stderr, upstream error bodies, the " + "recent event frames, the resolved model chain, accounting, and the paths to the " + "full records. Call this FIRST whenever a session fails, times out, or completes " + "with empty or surprising output; it needs no re-run and no debug flag.",
|
|
57353
|
+
description: "Explain what a channel session actually did \u2014 stderr, upstream error bodies, the " + "recent event frames, the resolved model chain, accounting, and the paths to the " + "full records. Call this FIRST whenever a session fails, times out, or completes " + "with empty or surprising output; it needs no re-run and no debug flag. " + "`idleSeconds` reports how long since the child last emitted a frame, and is " + "null once the session is no longer live. It is information, never a verdict: " + "claudish does not terminate a session for silence.",
|
|
57136
57354
|
inputSchema: {
|
|
57137
57355
|
type: "object",
|
|
57138
57356
|
properties: {
|
|
@@ -57289,6 +57507,7 @@ Call get_diagnostics with session_id: "${sessionId2}" for the stderr, the upstre
|
|
|
57289
57507
|
await server.connect(transport);
|
|
57290
57508
|
process.on("SIGTERM", () => {
|
|
57291
57509
|
sessionManager.shutdownAll().catch(() => {});
|
|
57510
|
+
shutdownAllTeamRuns().catch(() => {});
|
|
57292
57511
|
});
|
|
57293
57512
|
}
|
|
57294
57513
|
function startMcpServer() {
|
|
@@ -57331,6 +57550,7 @@ var init_mcp_server = __esm(() => {
|
|
|
57331
57550
|
init_server2();
|
|
57332
57551
|
init_stdio2();
|
|
57333
57552
|
init_types();
|
|
57553
|
+
init_model_catalog();
|
|
57334
57554
|
init_agent_availability();
|
|
57335
57555
|
init_prehydrate();
|
|
57336
57556
|
init_diagnostics();
|
|
@@ -57356,7 +57576,8 @@ var init_mcp_server = __esm(() => {
|
|
|
57356
57576
|
ALL_MODELS_CACHE_PATH2 = join34(CLAUDISH_CACHE_DIR, "all-models.json");
|
|
57357
57577
|
NEXT_STEP = {
|
|
57358
57578
|
nonzero_exit: "read the evidence log, then retry or drop the model",
|
|
57359
|
-
|
|
57579
|
+
cancelled: "you stopped this slot; nothing is wrong with it. Re-run it if you still want its vote",
|
|
57580
|
+
timeout: "grid mode only \u2014 magmux ended the pane. The orchestrator has no deadline",
|
|
57360
57581
|
api_error: "retry once, or route via a different provider (or@<model>)",
|
|
57361
57582
|
background_task_ceiling: "set CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 for children, or forbid background work in the prompt",
|
|
57362
57583
|
empty_output: "retry once; if it repeats, drop the model",
|
|
@@ -58239,7 +58460,8 @@ Options (run / run-and-judge):
|
|
|
58239
58460
|
--path <dir> Session directory (default: .)
|
|
58240
58461
|
--models <a,b,...> Comma-separated model IDs to run
|
|
58241
58462
|
--input <text> Task prompt (or create input.md in --path beforehand)
|
|
58242
|
-
--timeout <secs>
|
|
58463
|
+
--timeout <secs> Grid modes only: magmux's own per-pane timeout (default: 300).
|
|
58464
|
+
json mode has no deadline \u2014 nothing kills a working model.
|
|
58243
58465
|
--grid Show all models in a magmux grid with live output + status bar
|
|
58244
58466
|
|
|
58245
58467
|
Options (judge / run-and-judge):
|
|
@@ -58306,7 +58528,6 @@ async function teamCommand(args) {
|
|
|
58306
58528
|
if (effectiveMode === "json") {
|
|
58307
58529
|
setupSession(sessionPath, models, input);
|
|
58308
58530
|
const runStatus = await runModels(sessionPath, {
|
|
58309
|
-
timeout,
|
|
58310
58531
|
onStatusChange: (id, s) => {
|
|
58311
58532
|
process.stderr.write(`[team] ${id}: ${s.state}
|
|
58312
58533
|
`);
|
|
@@ -58335,7 +58556,6 @@ async function teamCommand(args) {
|
|
|
58335
58556
|
}
|
|
58336
58557
|
setupSession(sessionPath, models, input);
|
|
58337
58558
|
const status = await runModels(sessionPath, {
|
|
58338
|
-
timeout,
|
|
58339
58559
|
onStatusChange: (id, s) => {
|
|
58340
58560
|
process.stderr.write(`[team] ${id}: ${s.state}
|
|
58341
58561
|
`);
|
|
@@ -66218,9 +66438,9 @@ var require_internal = __commonJS(function(exports, module) {
|
|
|
66218
66438
|
}
|
|
66219
66439
|
InternalCodec.prototype.encoder = InternalEncoder;
|
|
66220
66440
|
InternalCodec.prototype.decoder = InternalDecoder;
|
|
66221
|
-
var
|
|
66441
|
+
var StringDecoder3 = __require("string_decoder").StringDecoder;
|
|
66222
66442
|
function InternalDecoder(options, codec2) {
|
|
66223
|
-
this.decoder = new
|
|
66443
|
+
this.decoder = new StringDecoder3(codec2.enc);
|
|
66224
66444
|
}
|
|
66225
66445
|
InternalDecoder.prototype.write = function(buf) {
|
|
66226
66446
|
if (!Buffer2.isBuffer(buf)) {
|
|
@@ -86111,7 +86331,7 @@ var init_widgets = __esm(() => {
|
|
|
86111
86331
|
|
|
86112
86332
|
// src/session/conversation.ts
|
|
86113
86333
|
import { closeSync as closeSync9, openSync as openSync9, readSync as readSync4, statSync as statSync9 } from "fs";
|
|
86114
|
-
import { StringDecoder as
|
|
86334
|
+
import { StringDecoder as StringDecoder3 } from "string_decoder";
|
|
86115
86335
|
function looksLikeTurn(line) {
|
|
86116
86336
|
const assistant = line.includes('"type":"assistant"');
|
|
86117
86337
|
if (!assistant && !line.includes('"type":"user"'))
|
|
@@ -86168,7 +86388,7 @@ function readConversation(file2, opts = {}) {
|
|
|
86168
86388
|
const size = statSync9(file2).size;
|
|
86169
86389
|
fd = openSync9(file2, "r");
|
|
86170
86390
|
const buf = Buffer.allocUnsafe(chunkBytes);
|
|
86171
|
-
const decoder = new
|
|
86391
|
+
const decoder = new StringDecoder3("utf-8");
|
|
86172
86392
|
let pending = "";
|
|
86173
86393
|
let pos = 0;
|
|
86174
86394
|
const consume = (line) => {
|
|
@@ -88463,7 +88683,6 @@ async function runCli() {
|
|
|
88463
88683
|
const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
|
|
88464
88684
|
setupSession2(sessionPath, cliConfig.team, prompt);
|
|
88465
88685
|
const status2 = await runModels2(sessionPath, {
|
|
88466
|
-
timeout: 300,
|
|
88467
88686
|
claudeFlags: ["--json"]
|
|
88468
88687
|
});
|
|
88469
88688
|
const result = { ...status2, responses: {} };
|