claudish 6.8.0 → 6.9.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
CHANGED
|
@@ -33064,6 +33064,16 @@ async function parseArgs(args) {
|
|
|
33064
33064
|
if (["auto", "logfile", "off"].includes(mode)) {
|
|
33065
33065
|
config3.diagMode = mode;
|
|
33066
33066
|
}
|
|
33067
|
+
} else if (arg === "--team" && i + 1 < args.length) {
|
|
33068
|
+
const models = args[++i].split(",").map((m) => m.trim()).filter(Boolean);
|
|
33069
|
+
config3.team = models;
|
|
33070
|
+
} else if (arg === "--mode" && i + 1 < args.length) {
|
|
33071
|
+
const mode = args[++i].toLowerCase();
|
|
33072
|
+
if (["default", "interactive", "json"].includes(mode)) {
|
|
33073
|
+
config3.teamMode = mode;
|
|
33074
|
+
}
|
|
33075
|
+
} else if ((arg === "-f" || arg === "--file") && i + 1 < args.length) {
|
|
33076
|
+
config3.inputFile = args[++i];
|
|
33067
33077
|
} else if (arg === "--") {
|
|
33068
33078
|
config3.claudeArgs.push(...args.slice(i + 1));
|
|
33069
33079
|
break;
|
|
@@ -33941,6 +33951,8 @@ claudish - Run Claude Code with any AI model (OpenRouter, Gemini, OpenAI, MiniMa
|
|
|
33941
33951
|
USAGE:
|
|
33942
33952
|
claudish # Interactive mode (default, shows model selector)
|
|
33943
33953
|
claudish [OPTIONS] <claude-args...> # Single-shot mode (requires --model)
|
|
33954
|
+
claudish --team a,b,c "prompt" # Run models in parallel (magmux grid)
|
|
33955
|
+
claudish --team a,b,c -f input.md # Team mode with file input
|
|
33944
33956
|
|
|
33945
33957
|
MODEL ROUTING:
|
|
33946
33958
|
New syntax: provider@model[:concurrency]
|
|
@@ -34013,6 +34025,10 @@ OPTIONS:
|
|
|
34013
34025
|
--models List ALL models (OpenRouter + OpenCode Zen + Ollama)
|
|
34014
34026
|
--models <query> Fuzzy search all models by name, ID, or description
|
|
34015
34027
|
--top-models List recommended/top programming models (curated)
|
|
34028
|
+
--team <models> Run multiple models in parallel (comma-separated)
|
|
34029
|
+
Example: --team minimax-m2.5,kimi-k2.5 "prompt"
|
|
34030
|
+
--mode <mode> Team mode: default (grid), interactive, json
|
|
34031
|
+
-f, --file <path> Read prompt from file (use with --team or single-shot)
|
|
34016
34032
|
--probe <models...> Show fallback chain for each model (diagnostic)
|
|
34017
34033
|
--json Output in JSON format (use with --models, --top-models, --probe)
|
|
34018
34034
|
--force-update Force refresh model cache from OpenRouter API
|
|
@@ -34474,7 +34490,7 @@ async function fetchGLMCodingModels() {
|
|
|
34474
34490
|
return [];
|
|
34475
34491
|
}
|
|
34476
34492
|
}
|
|
34477
|
-
var __filename4, __dirname4, VERSION = "6.
|
|
34493
|
+
var __filename4, __dirname4, VERSION = "6.9.0", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
|
|
34478
34494
|
var init_cli = __esm(() => {
|
|
34479
34495
|
init_config();
|
|
34480
34496
|
init_model_loader();
|
|
@@ -95650,418 +95666,16 @@ var init_tui = __esm(async () => {
|
|
|
95650
95666
|
}
|
|
95651
95667
|
});
|
|
95652
95668
|
|
|
95653
|
-
// src/team-grid.ts
|
|
95654
|
-
var exports_team_grid = {};
|
|
95655
|
-
__export(exports_team_grid, {
|
|
95656
|
-
runWithGrid: () => runWithGrid
|
|
95657
|
-
});
|
|
95658
|
-
import { spawn as spawn3 } from "child_process";
|
|
95659
|
-
import {
|
|
95660
|
-
appendFileSync,
|
|
95661
|
-
existsSync as existsSync26,
|
|
95662
|
-
mkdirSync as mkdirSync14,
|
|
95663
|
-
readFileSync as readFileSync21,
|
|
95664
|
-
unlinkSync as unlinkSync8,
|
|
95665
|
-
writeFileSync as writeFileSync15
|
|
95666
|
-
} from "fs";
|
|
95667
|
-
import { dirname as dirname6, join as join27 } from "path";
|
|
95668
|
-
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
95669
|
-
import { execSync as execSync3 } from "child_process";
|
|
95670
|
-
function formatElapsed(ms) {
|
|
95671
|
-
const s = Math.floor(ms / 1000);
|
|
95672
|
-
if (s < 60)
|
|
95673
|
-
return `${s}s`;
|
|
95674
|
-
const m2 = Math.floor(s / 60);
|
|
95675
|
-
const rem = s % 60;
|
|
95676
|
-
return `${m2}m ${rem}s`;
|
|
95677
|
-
}
|
|
95678
|
-
function findMagmuxBinary() {
|
|
95679
|
-
const thisFile = fileURLToPath6(import.meta.url);
|
|
95680
|
-
const thisDir = dirname6(thisFile);
|
|
95681
|
-
const pkgRoot = join27(thisDir, "..");
|
|
95682
|
-
const platform3 = process.platform;
|
|
95683
|
-
const arch = process.arch;
|
|
95684
|
-
const builtMagmux = join27(pkgRoot, "native", "magmux", "magmux");
|
|
95685
|
-
if (existsSync26(builtMagmux))
|
|
95686
|
-
return builtMagmux;
|
|
95687
|
-
const bundledMagmux = join27(pkgRoot, "native", "magmux", `magmux-${platform3}-${arch}`);
|
|
95688
|
-
if (existsSync26(bundledMagmux))
|
|
95689
|
-
return bundledMagmux;
|
|
95690
|
-
try {
|
|
95691
|
-
const result = execSync3("which magmux", { encoding: "utf-8" }).trim();
|
|
95692
|
-
if (result)
|
|
95693
|
-
return result;
|
|
95694
|
-
} catch {}
|
|
95695
|
-
throw new Error(`magmux not found. Install it:
|
|
95696
|
-
brew install MadAppGang/tap/magmux`);
|
|
95697
|
-
}
|
|
95698
|
-
function renderGridStatusBar(counts) {
|
|
95699
|
-
const elapsed = formatElapsed(counts.elapsedMs);
|
|
95700
|
-
const { done, running, failed, total, allDone } = counts;
|
|
95701
|
-
if (allDone) {
|
|
95702
|
-
if (failed > 0) {
|
|
95703
|
-
return [
|
|
95704
|
-
"C: claudish team",
|
|
95705
|
-
`G: ${done} done`,
|
|
95706
|
-
`R: ${failed} failed`,
|
|
95707
|
-
`D: ${elapsed}`,
|
|
95708
|
-
"R: \u2717 issues",
|
|
95709
|
-
"D: ctrl-g q to quit"
|
|
95710
|
-
].join("\t");
|
|
95711
|
-
}
|
|
95712
|
-
return [
|
|
95713
|
-
"C: claudish team",
|
|
95714
|
-
`G: ${total} done`,
|
|
95715
|
-
`D: ${elapsed}`,
|
|
95716
|
-
"G: \u2713 complete",
|
|
95717
|
-
"D: ctrl-g q to quit"
|
|
95718
|
-
].join("\t");
|
|
95719
|
-
}
|
|
95720
|
-
return [
|
|
95721
|
-
"C: claudish team",
|
|
95722
|
-
`G: ${done} done`,
|
|
95723
|
-
`C: ${running} running`,
|
|
95724
|
-
`R: ${failed} failed`,
|
|
95725
|
-
`D: ${elapsed}`
|
|
95726
|
-
].join("\t");
|
|
95727
|
-
}
|
|
95728
|
-
function pollStatus(state) {
|
|
95729
|
-
const { statusCache, statusPath, sessionPath, anonIds, startTime, timeoutMs, statusbarPath } = state;
|
|
95730
|
-
const elapsedMs = Date.now() - startTime;
|
|
95731
|
-
let changed = false;
|
|
95732
|
-
let done = 0;
|
|
95733
|
-
let running = 0;
|
|
95734
|
-
let failed = 0;
|
|
95735
|
-
for (const anonId of anonIds) {
|
|
95736
|
-
const current = statusCache.models[anonId];
|
|
95737
|
-
if (current.state === "COMPLETED" || current.state === "FAILED" || current.state === "TIMEOUT") {
|
|
95738
|
-
if (current.state === "COMPLETED")
|
|
95739
|
-
done++;
|
|
95740
|
-
else
|
|
95741
|
-
failed++;
|
|
95742
|
-
continue;
|
|
95743
|
-
}
|
|
95744
|
-
const exitCodePath = join27(sessionPath, "work", anonId, ".exit-code");
|
|
95745
|
-
if (existsSync26(exitCodePath)) {
|
|
95746
|
-
const codeStr = readFileSync21(exitCodePath, "utf-8").trim();
|
|
95747
|
-
const code = parseInt(codeStr, 10);
|
|
95748
|
-
const isSuccess = code === 0;
|
|
95749
|
-
const newState = {
|
|
95750
|
-
...current,
|
|
95751
|
-
state: isSuccess ? "COMPLETED" : "FAILED",
|
|
95752
|
-
exitCode: code,
|
|
95753
|
-
startedAt: current.startedAt ?? new Date().toISOString(),
|
|
95754
|
-
completedAt: new Date().toISOString(),
|
|
95755
|
-
outputSize: 0
|
|
95756
|
-
};
|
|
95757
|
-
statusCache.models[anonId] = newState;
|
|
95758
|
-
changed = true;
|
|
95759
|
-
if (isSuccess)
|
|
95760
|
-
done++;
|
|
95761
|
-
else
|
|
95762
|
-
failed++;
|
|
95763
|
-
} else {
|
|
95764
|
-
if (!state.interactive && elapsedMs > timeoutMs) {
|
|
95765
|
-
const newState = {
|
|
95766
|
-
...current,
|
|
95767
|
-
state: "TIMEOUT",
|
|
95768
|
-
startedAt: current.startedAt ?? new Date().toISOString(),
|
|
95769
|
-
completedAt: new Date().toISOString(),
|
|
95770
|
-
outputSize: 0
|
|
95771
|
-
};
|
|
95772
|
-
statusCache.models[anonId] = newState;
|
|
95773
|
-
changed = true;
|
|
95774
|
-
failed++;
|
|
95775
|
-
} else {
|
|
95776
|
-
if (current.state === "PENDING" && elapsedMs > 1000) {
|
|
95777
|
-
statusCache.models[anonId] = {
|
|
95778
|
-
...current,
|
|
95779
|
-
state: "RUNNING",
|
|
95780
|
-
startedAt: current.startedAt ?? new Date().toISOString()
|
|
95781
|
-
};
|
|
95782
|
-
changed = true;
|
|
95783
|
-
}
|
|
95784
|
-
running++;
|
|
95785
|
-
}
|
|
95786
|
-
}
|
|
95787
|
-
}
|
|
95788
|
-
if (changed) {
|
|
95789
|
-
writeFileSync15(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
|
|
95790
|
-
}
|
|
95791
|
-
const total = anonIds.length;
|
|
95792
|
-
const allDone = done + failed >= total;
|
|
95793
|
-
if (allDone && !state.completedAtMs) {
|
|
95794
|
-
state.completedAtMs = elapsedMs;
|
|
95795
|
-
}
|
|
95796
|
-
const counts = {
|
|
95797
|
-
done,
|
|
95798
|
-
running,
|
|
95799
|
-
failed,
|
|
95800
|
-
total,
|
|
95801
|
-
elapsedMs: state.completedAtMs ?? elapsedMs,
|
|
95802
|
-
allDone
|
|
95803
|
-
};
|
|
95804
|
-
appendFileSync(statusbarPath, renderGridStatusBar(counts) + `
|
|
95805
|
-
`);
|
|
95806
|
-
return allDone;
|
|
95807
|
-
}
|
|
95808
|
-
async function runWithGrid(sessionPath, models, input, opts) {
|
|
95809
|
-
const timeoutMs = (opts?.timeout ?? 300) * 1000;
|
|
95810
|
-
const interactive = opts?.interactive ?? false;
|
|
95811
|
-
const manifest = setupSession(sessionPath, models, input);
|
|
95812
|
-
mkdirSync14(join27(sessionPath, "errors"), { recursive: true });
|
|
95813
|
-
for (const anonId of Object.keys(manifest.models)) {
|
|
95814
|
-
const stale = join27(sessionPath, "work", anonId, ".exit-code");
|
|
95815
|
-
try {
|
|
95816
|
-
unlinkSync8(stale);
|
|
95817
|
-
} catch {}
|
|
95818
|
-
}
|
|
95819
|
-
const gridfilePath = join27(sessionPath, "gridfile.txt");
|
|
95820
|
-
const prompt = readFileSync21(join27(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''");
|
|
95821
|
-
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
95822
|
-
const errorLog = join27(sessionPath, "errors", `${anonId}.log`);
|
|
95823
|
-
const exitCodeFile = join27(sessionPath, "work", anonId, ".exit-code");
|
|
95824
|
-
const model = manifest.models[anonId].model;
|
|
95825
|
-
const paneIndex = Object.keys(manifest.models).indexOf(anonId);
|
|
95826
|
-
if (interactive) {
|
|
95827
|
-
return `claudish --model ${model} --dangerously-skip-permissions '${prompt}'`;
|
|
95828
|
-
}
|
|
95829
|
-
return [
|
|
95830
|
-
`claudish --model ${model} -y -v '${prompt}' 2>${errorLog};`,
|
|
95831
|
-
`_ec=$?; echo $_ec > ${exitCodeFile};`,
|
|
95832
|
-
`if [ -n "$MAGMUX_SOCK" ]; then`,
|
|
95833
|
-
` if [ $_ec -eq 0 ]; then`,
|
|
95834
|
-
` echo '{"cmd":"tint","pane":${paneIndex},"color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
95835
|
-
` echo '{"cmd":"overlay","pane":${paneIndex},"text":"DONE","color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
95836
|
-
` else`,
|
|
95837
|
-
` echo '{"cmd":"tint","pane":${paneIndex},"color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
95838
|
-
` echo '{"cmd":"overlay","pane":${paneIndex},"text":"FAIL","color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
95839
|
-
` fi;`,
|
|
95840
|
-
`fi;`,
|
|
95841
|
-
`exec sleep 86400`
|
|
95842
|
-
].join(" ");
|
|
95843
|
-
});
|
|
95844
|
-
writeFileSync15(gridfilePath, gridLines.join(`
|
|
95845
|
-
`) + `
|
|
95846
|
-
`, "utf-8");
|
|
95847
|
-
const magmuxPath = findMagmuxBinary();
|
|
95848
|
-
const statusbarPath = join27(sessionPath, "statusbar.txt");
|
|
95849
|
-
const statusPath = join27(sessionPath, "status.json");
|
|
95850
|
-
const statusCache = JSON.parse(readFileSync21(statusPath, "utf-8"));
|
|
95851
|
-
const anonIds = Object.keys(manifest.models);
|
|
95852
|
-
const startTime = Date.now();
|
|
95853
|
-
appendFileSync(statusbarPath, renderGridStatusBar({
|
|
95854
|
-
done: 0,
|
|
95855
|
-
running: 0,
|
|
95856
|
-
failed: 0,
|
|
95857
|
-
total: anonIds.length,
|
|
95858
|
-
elapsedMs: 0,
|
|
95859
|
-
allDone: false
|
|
95860
|
-
}) + `
|
|
95861
|
-
`);
|
|
95862
|
-
const pollState = {
|
|
95863
|
-
statusCache,
|
|
95864
|
-
statusPath,
|
|
95865
|
-
sessionPath,
|
|
95866
|
-
anonIds,
|
|
95867
|
-
startTime,
|
|
95868
|
-
timeoutMs,
|
|
95869
|
-
statusbarPath,
|
|
95870
|
-
completedAtMs: null,
|
|
95871
|
-
interactive
|
|
95872
|
-
};
|
|
95873
|
-
const pollInterval = setInterval(() => {
|
|
95874
|
-
pollStatus(pollState);
|
|
95875
|
-
}, 500);
|
|
95876
|
-
const spawnArgs = ["-g", gridfilePath, "-S", statusbarPath];
|
|
95877
|
-
if (!interactive) {
|
|
95878
|
-
spawnArgs.push("-w");
|
|
95879
|
-
}
|
|
95880
|
-
const proc = spawn3(magmuxPath, spawnArgs, {
|
|
95881
|
-
stdio: "inherit",
|
|
95882
|
-
env: { ...process.env }
|
|
95883
|
-
});
|
|
95884
|
-
await new Promise((resolve4) => {
|
|
95885
|
-
proc.on("exit", () => resolve4());
|
|
95886
|
-
proc.on("error", () => resolve4());
|
|
95887
|
-
});
|
|
95888
|
-
clearInterval(pollInterval);
|
|
95889
|
-
pollStatus(pollState);
|
|
95890
|
-
return JSON.parse(readFileSync21(statusPath, "utf-8"));
|
|
95891
|
-
}
|
|
95892
|
-
var init_team_grid = __esm(() => {
|
|
95893
|
-
init_team_orchestrator();
|
|
95894
|
-
});
|
|
95895
|
-
|
|
95896
|
-
// src/team-cli.ts
|
|
95897
|
-
var exports_team_cli = {};
|
|
95898
|
-
__export(exports_team_cli, {
|
|
95899
|
-
teamCommand: () => teamCommand
|
|
95900
|
-
});
|
|
95901
|
-
import { readFileSync as readFileSync22 } from "fs";
|
|
95902
|
-
import { join as join28 } from "path";
|
|
95903
|
-
function getFlag(args, flag) {
|
|
95904
|
-
const idx = args.indexOf(flag);
|
|
95905
|
-
if (idx === -1 || idx + 1 >= args.length)
|
|
95906
|
-
return;
|
|
95907
|
-
return args[idx + 1];
|
|
95908
|
-
}
|
|
95909
|
-
function hasFlag(args, flag) {
|
|
95910
|
-
return args.includes(flag);
|
|
95911
|
-
}
|
|
95912
|
-
function printStatus(status) {
|
|
95913
|
-
const modelIds = Object.keys(status.models).sort();
|
|
95914
|
-
console.log(`
|
|
95915
|
-
Team Status (started: ${status.startedAt})`);
|
|
95916
|
-
console.log("\u2500".repeat(60));
|
|
95917
|
-
for (const id of modelIds) {
|
|
95918
|
-
const m2 = status.models[id];
|
|
95919
|
-
const duration3 = m2.startedAt && m2.completedAt ? `${Math.round((new Date(m2.completedAt).getTime() - new Date(m2.startedAt).getTime()) / 1000)}s` : m2.startedAt ? "running" : "pending";
|
|
95920
|
-
const size = m2.outputSize > 0 ? ` (${m2.outputSize} bytes)` : "";
|
|
95921
|
-
console.log(` ${id} ${m2.state.padEnd(10)} ${duration3}${size}`);
|
|
95922
|
-
}
|
|
95923
|
-
console.log("");
|
|
95924
|
-
}
|
|
95925
|
-
function printHelp2() {
|
|
95926
|
-
console.log(`
|
|
95927
|
-
Usage: claudish team <subcommand> [options]
|
|
95928
|
-
|
|
95929
|
-
Subcommands:
|
|
95930
|
-
run Run multiple models on a task in parallel
|
|
95931
|
-
judge Blind-judge existing model outputs
|
|
95932
|
-
run-and-judge Run models then judge their outputs
|
|
95933
|
-
status Show current session status
|
|
95934
|
-
|
|
95935
|
-
Options (run / run-and-judge):
|
|
95936
|
-
--path <dir> Session directory (default: .)
|
|
95937
|
-
--models <a,b,...> Comma-separated model IDs to run
|
|
95938
|
-
--input <text> Task prompt (or create input.md in --path beforehand)
|
|
95939
|
-
--timeout <secs> Timeout per model in seconds (default: 300)
|
|
95940
|
-
--grid Show all models in a magmux grid with live output + status bar
|
|
95941
|
-
|
|
95942
|
-
Options (judge / run-and-judge):
|
|
95943
|
-
--judges <a,b,...> Comma-separated judge model IDs (default: same as runners)
|
|
95944
|
-
|
|
95945
|
-
Options (status):
|
|
95946
|
-
--path <dir> Session directory (default: .)
|
|
95947
|
-
|
|
95948
|
-
Examples:
|
|
95949
|
-
claudish team run --path ./review --models minimax-m2.5,kimi-k2.5 --input "Review this code"
|
|
95950
|
-
claudish team run --grid --models kimi-k2.5,gpt-5.4,gemini-3.1-pro --input "Solve this"
|
|
95951
|
-
claudish team judge --path ./review
|
|
95952
|
-
claudish team run-and-judge --path ./review --models gpt-5.4,gemini-3.1-pro-preview --input "Evaluate this design"
|
|
95953
|
-
claudish team status --path ./review
|
|
95954
|
-
`);
|
|
95955
|
-
}
|
|
95956
|
-
async function teamCommand(args) {
|
|
95957
|
-
if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
|
|
95958
|
-
printHelp2();
|
|
95959
|
-
process.exit(0);
|
|
95960
|
-
}
|
|
95961
|
-
const firstArg = args[0] ?? "";
|
|
95962
|
-
const legacySubs = ["run", "judge", "run-and-judge", "status"];
|
|
95963
|
-
const subcommand = legacySubs.includes(firstArg) ? firstArg : "run";
|
|
95964
|
-
const rawSessionPath = getFlag(args, "--path") ?? ".";
|
|
95965
|
-
let sessionPath;
|
|
95966
|
-
try {
|
|
95967
|
-
sessionPath = validateSessionPath(rawSessionPath);
|
|
95968
|
-
} catch (err) {
|
|
95969
|
-
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
95970
|
-
process.exit(1);
|
|
95971
|
-
}
|
|
95972
|
-
const modelsRaw = getFlag(args, "--models");
|
|
95973
|
-
const judgesRaw = getFlag(args, "--judges");
|
|
95974
|
-
const mode = getFlag(args, "--mode") ?? "default";
|
|
95975
|
-
const timeoutStr = getFlag(args, "--timeout");
|
|
95976
|
-
const timeout = timeoutStr ? parseInt(timeoutStr, 10) : 300;
|
|
95977
|
-
let input = getFlag(args, "--input");
|
|
95978
|
-
if (!input) {
|
|
95979
|
-
const flagsWithValues = ["--models", "--judges", "--mode", "--path", "--timeout", "--input"];
|
|
95980
|
-
const positionals = args.filter((a, i) => {
|
|
95981
|
-
if (legacySubs.includes(a) && i === 0)
|
|
95982
|
-
return false;
|
|
95983
|
-
if (a.startsWith("--"))
|
|
95984
|
-
return false;
|
|
95985
|
-
const prev = args[i - 1];
|
|
95986
|
-
if (prev && flagsWithValues.includes(prev))
|
|
95987
|
-
return false;
|
|
95988
|
-
return true;
|
|
95989
|
-
});
|
|
95990
|
-
if (positionals.length > 0)
|
|
95991
|
-
input = positionals.join(" ");
|
|
95992
|
-
}
|
|
95993
|
-
const models = modelsRaw ? modelsRaw.split(",").map((m2) => m2.trim()).filter(Boolean) : [];
|
|
95994
|
-
const judges = judgesRaw ? judgesRaw.split(",").map((m2) => m2.trim()).filter(Boolean) : undefined;
|
|
95995
|
-
const effectiveMode = hasFlag(args, "--interactive") ? "interactive" : hasFlag(args, "--grid") ? "default" : mode;
|
|
95996
|
-
switch (subcommand) {
|
|
95997
|
-
case "run": {
|
|
95998
|
-
if (models.length === 0) {
|
|
95999
|
-
console.error("Error: --models is required");
|
|
96000
|
-
printHelp2();
|
|
96001
|
-
process.exit(1);
|
|
96002
|
-
}
|
|
96003
|
-
if (effectiveMode === "json") {
|
|
96004
|
-
setupSession(sessionPath, models, input);
|
|
96005
|
-
const runStatus = await runModels(sessionPath, {
|
|
96006
|
-
timeout,
|
|
96007
|
-
onStatusChange: (id, s) => {
|
|
96008
|
-
process.stderr.write(`[team] ${id}: ${s.state}
|
|
96009
|
-
`);
|
|
96010
|
-
}
|
|
96011
|
-
});
|
|
96012
|
-
printStatus(runStatus);
|
|
96013
|
-
} else {
|
|
96014
|
-
const { runWithGrid: runWithGrid2 } = await Promise.resolve().then(() => (init_team_grid(), exports_team_grid));
|
|
96015
|
-
const interactive = effectiveMode === "interactive";
|
|
96016
|
-
const gridStatus = await runWithGrid2(sessionPath, models, input ?? "", { timeout, interactive });
|
|
96017
|
-
printStatus(gridStatus);
|
|
96018
|
-
}
|
|
96019
|
-
break;
|
|
96020
|
-
}
|
|
96021
|
-
case "judge": {
|
|
96022
|
-
await judgeResponses(sessionPath, { judges });
|
|
96023
|
-
console.log(readFileSync22(join28(sessionPath, "verdict.md"), "utf-8"));
|
|
96024
|
-
break;
|
|
96025
|
-
}
|
|
96026
|
-
case "run-and-judge": {
|
|
96027
|
-
if (models.length === 0) {
|
|
96028
|
-
console.error("Error: --models is required");
|
|
96029
|
-
process.exit(1);
|
|
96030
|
-
}
|
|
96031
|
-
setupSession(sessionPath, models, input);
|
|
96032
|
-
const status = await runModels(sessionPath, {
|
|
96033
|
-
timeout,
|
|
96034
|
-
onStatusChange: (id, s) => {
|
|
96035
|
-
process.stderr.write(`[team] ${id}: ${s.state}
|
|
96036
|
-
`);
|
|
96037
|
-
}
|
|
96038
|
-
});
|
|
96039
|
-
printStatus(status);
|
|
96040
|
-
await judgeResponses(sessionPath, { judges });
|
|
96041
|
-
console.log(readFileSync22(join28(sessionPath, "verdict.md"), "utf-8"));
|
|
96042
|
-
break;
|
|
96043
|
-
}
|
|
96044
|
-
case "status": {
|
|
96045
|
-
const statusResult = getStatus(sessionPath);
|
|
96046
|
-
printStatus(statusResult);
|
|
96047
|
-
break;
|
|
96048
|
-
}
|
|
96049
|
-
}
|
|
96050
|
-
}
|
|
96051
|
-
var init_team_cli = __esm(() => {
|
|
96052
|
-
init_team_orchestrator();
|
|
96053
|
-
});
|
|
96054
|
-
|
|
96055
95669
|
// src/claude-runner.ts
|
|
96056
95670
|
var exports_claude_runner = {};
|
|
96057
95671
|
__export(exports_claude_runner, {
|
|
96058
95672
|
runClaudeWithProxy: () => runClaudeWithProxy,
|
|
96059
95673
|
checkClaudeInstalled: () => checkClaudeInstalled
|
|
96060
95674
|
});
|
|
96061
|
-
import { spawn as
|
|
96062
|
-
import { writeFileSync as
|
|
95675
|
+
import { spawn as spawn3 } from "child_process";
|
|
95676
|
+
import { writeFileSync as writeFileSync15, unlinkSync as unlinkSync8, mkdirSync as mkdirSync14, existsSync as existsSync26, readFileSync as readFileSync21 } from "fs";
|
|
96063
95677
|
import { tmpdir as tmpdir2, homedir as homedir25 } from "os";
|
|
96064
|
-
import { join as
|
|
95678
|
+
import { join as join27 } from "path";
|
|
96065
95679
|
function hasNativeAnthropicMapping(config3) {
|
|
96066
95680
|
const models = [
|
|
96067
95681
|
config3.model,
|
|
@@ -96077,9 +95691,9 @@ function isWindows2() {
|
|
|
96077
95691
|
}
|
|
96078
95692
|
function createStatusLineScript(tokenFilePath) {
|
|
96079
95693
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
96080
|
-
const claudishDir =
|
|
95694
|
+
const claudishDir = join27(homeDir, ".claudish");
|
|
96081
95695
|
const timestamp = Date.now();
|
|
96082
|
-
const scriptPath =
|
|
95696
|
+
const scriptPath = join27(claudishDir, `status-${timestamp}.js`);
|
|
96083
95697
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
96084
95698
|
const script = `
|
|
96085
95699
|
const fs = require('fs');
|
|
@@ -96168,18 +95782,18 @@ process.stdin.on('end', () => {
|
|
|
96168
95782
|
}
|
|
96169
95783
|
});
|
|
96170
95784
|
`;
|
|
96171
|
-
|
|
95785
|
+
writeFileSync15(scriptPath, script, "utf-8");
|
|
96172
95786
|
return scriptPath;
|
|
96173
95787
|
}
|
|
96174
95788
|
function createTempSettingsFile(modelDisplay, port) {
|
|
96175
95789
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
96176
|
-
const claudishDir =
|
|
95790
|
+
const claudishDir = join27(homeDir, ".claudish");
|
|
96177
95791
|
try {
|
|
96178
|
-
|
|
95792
|
+
mkdirSync14(claudishDir, { recursive: true });
|
|
96179
95793
|
} catch {}
|
|
96180
95794
|
const timestamp = Date.now();
|
|
96181
|
-
const tempPath =
|
|
96182
|
-
const tokenFilePath =
|
|
95795
|
+
const tempPath = join27(claudishDir, `settings-${timestamp}.json`);
|
|
95796
|
+
const tokenFilePath = join27(claudishDir, `tokens-${port}.json`);
|
|
96183
95797
|
let statusCommand;
|
|
96184
95798
|
if (isWindows2()) {
|
|
96185
95799
|
const scriptPath = createStatusLineScript(tokenFilePath);
|
|
@@ -96201,7 +95815,7 @@ function createTempSettingsFile(modelDisplay, port) {
|
|
|
96201
95815
|
padding: 0
|
|
96202
95816
|
};
|
|
96203
95817
|
const settings = { statusLine };
|
|
96204
|
-
|
|
95818
|
+
writeFileSync15(tempPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
96205
95819
|
return { path: tempPath, statusLine };
|
|
96206
95820
|
}
|
|
96207
95821
|
function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
|
|
@@ -96215,11 +95829,11 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
|
|
|
96215
95829
|
if (userSettingsValue.trimStart().startsWith("{")) {
|
|
96216
95830
|
userSettings = JSON.parse(userSettingsValue);
|
|
96217
95831
|
} else {
|
|
96218
|
-
const rawUserSettings =
|
|
95832
|
+
const rawUserSettings = readFileSync21(userSettingsValue, "utf-8");
|
|
96219
95833
|
userSettings = JSON.parse(rawUserSettings);
|
|
96220
95834
|
}
|
|
96221
95835
|
userSettings.statusLine = statusLine;
|
|
96222
|
-
|
|
95836
|
+
writeFileSync15(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
|
|
96223
95837
|
} catch {
|
|
96224
95838
|
if (!config3.quiet) {
|
|
96225
95839
|
console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
|
|
@@ -96308,13 +95922,13 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
|
|
|
96308
95922
|
console.error(`
|
|
96309
95923
|
Or set CLAUDE_PATH to your custom installation:`);
|
|
96310
95924
|
const home = homedir25();
|
|
96311
|
-
const localPath = isWindows2() ?
|
|
95925
|
+
const localPath = isWindows2() ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
|
|
96312
95926
|
console.error(` export CLAUDE_PATH=${localPath}`);
|
|
96313
95927
|
process.exit(1);
|
|
96314
95928
|
}
|
|
96315
95929
|
const needsShell = isWindows2() && claudeBinary.endsWith(".cmd");
|
|
96316
95930
|
const spawnCommand = needsShell ? `"${claudeBinary}"` : claudeBinary;
|
|
96317
|
-
const proc =
|
|
95931
|
+
const proc = spawn3(spawnCommand, claudeArgs, {
|
|
96318
95932
|
env: env2,
|
|
96319
95933
|
stdio: "inherit",
|
|
96320
95934
|
shell: needsShell
|
|
@@ -96326,7 +95940,7 @@ Or set CLAUDE_PATH to your custom installation:`);
|
|
|
96326
95940
|
});
|
|
96327
95941
|
});
|
|
96328
95942
|
try {
|
|
96329
|
-
|
|
95943
|
+
unlinkSync8(tempSettingsPath);
|
|
96330
95944
|
} catch {}
|
|
96331
95945
|
return exitCode;
|
|
96332
95946
|
}
|
|
@@ -96345,7 +95959,7 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
|
|
|
96345
95959
|
} catch {}
|
|
96346
95960
|
}
|
|
96347
95961
|
try {
|
|
96348
|
-
|
|
95962
|
+
unlinkSync8(tempSettingsPath);
|
|
96349
95963
|
} catch {}
|
|
96350
95964
|
process.exit(0);
|
|
96351
95965
|
});
|
|
@@ -96354,23 +95968,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
|
|
|
96354
95968
|
async function findClaudeBinary() {
|
|
96355
95969
|
const isWindows3 = process.platform === "win32";
|
|
96356
95970
|
if (process.env.CLAUDE_PATH) {
|
|
96357
|
-
if (
|
|
95971
|
+
if (existsSync26(process.env.CLAUDE_PATH)) {
|
|
96358
95972
|
return process.env.CLAUDE_PATH;
|
|
96359
95973
|
}
|
|
96360
95974
|
}
|
|
96361
95975
|
const home = homedir25();
|
|
96362
|
-
const localPath = isWindows3 ?
|
|
96363
|
-
if (
|
|
95976
|
+
const localPath = isWindows3 ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
|
|
95977
|
+
if (existsSync26(localPath)) {
|
|
96364
95978
|
return localPath;
|
|
96365
95979
|
}
|
|
96366
95980
|
if (isWindows3) {
|
|
96367
95981
|
const windowsPaths = [
|
|
96368
|
-
|
|
96369
|
-
|
|
96370
|
-
|
|
95982
|
+
join27(home, "AppData", "Roaming", "npm", "claude.cmd"),
|
|
95983
|
+
join27(home, ".npm-global", "claude.cmd"),
|
|
95984
|
+
join27(home, "node_modules", ".bin", "claude.cmd")
|
|
96371
95985
|
];
|
|
96372
95986
|
for (const path2 of windowsPaths) {
|
|
96373
|
-
if (
|
|
95987
|
+
if (existsSync26(path2)) {
|
|
96374
95988
|
return path2;
|
|
96375
95989
|
}
|
|
96376
95990
|
}
|
|
@@ -96378,21 +95992,21 @@ async function findClaudeBinary() {
|
|
|
96378
95992
|
const commonPaths = [
|
|
96379
95993
|
"/usr/local/bin/claude",
|
|
96380
95994
|
"/opt/homebrew/bin/claude",
|
|
96381
|
-
|
|
96382
|
-
|
|
96383
|
-
|
|
95995
|
+
join27(home, ".npm-global/bin/claude"),
|
|
95996
|
+
join27(home, ".local/bin/claude"),
|
|
95997
|
+
join27(home, "node_modules/.bin/claude"),
|
|
96384
95998
|
"/data/data/com.termux/files/usr/bin/claude",
|
|
96385
|
-
|
|
95999
|
+
join27(home, "../usr/bin/claude")
|
|
96386
96000
|
];
|
|
96387
96001
|
for (const path2 of commonPaths) {
|
|
96388
|
-
if (
|
|
96002
|
+
if (existsSync26(path2)) {
|
|
96389
96003
|
return path2;
|
|
96390
96004
|
}
|
|
96391
96005
|
}
|
|
96392
96006
|
}
|
|
96393
96007
|
try {
|
|
96394
96008
|
const shellCommand = isWindows3 ? "where claude" : "command -v claude";
|
|
96395
|
-
const proc =
|
|
96009
|
+
const proc = spawn3(shellCommand, [], {
|
|
96396
96010
|
stdio: "pipe",
|
|
96397
96011
|
shell: true
|
|
96398
96012
|
});
|
|
@@ -96434,18 +96048,18 @@ __export(exports_diag_output, {
|
|
|
96434
96048
|
NullDiagOutput: () => NullDiagOutput,
|
|
96435
96049
|
LogFileDiagOutput: () => LogFileDiagOutput
|
|
96436
96050
|
});
|
|
96437
|
-
import { createWriteStream as createWriteStream3, mkdirSync as
|
|
96051
|
+
import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync15, writeFileSync as writeFileSync16, unlinkSync as unlinkSync9 } from "fs";
|
|
96438
96052
|
import { homedir as homedir26 } from "os";
|
|
96439
|
-
import { join as
|
|
96053
|
+
import { join as join28 } from "path";
|
|
96440
96054
|
function getClaudishDir() {
|
|
96441
|
-
const dir =
|
|
96055
|
+
const dir = join28(homedir26(), ".claudish");
|
|
96442
96056
|
try {
|
|
96443
|
-
|
|
96057
|
+
mkdirSync15(dir, { recursive: true });
|
|
96444
96058
|
} catch {}
|
|
96445
96059
|
return dir;
|
|
96446
96060
|
}
|
|
96447
96061
|
function getDiagLogPath() {
|
|
96448
|
-
return
|
|
96062
|
+
return join28(getClaudishDir(), `diag-${process.pid}.log`);
|
|
96449
96063
|
}
|
|
96450
96064
|
|
|
96451
96065
|
class LogFileDiagOutput {
|
|
@@ -96454,7 +96068,7 @@ class LogFileDiagOutput {
|
|
|
96454
96068
|
constructor() {
|
|
96455
96069
|
this.logPath = getDiagLogPath();
|
|
96456
96070
|
try {
|
|
96457
|
-
|
|
96071
|
+
writeFileSync16(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
|
|
96458
96072
|
`);
|
|
96459
96073
|
} catch {}
|
|
96460
96074
|
this.stream = createWriteStream3(this.logPath, { flags: "a" });
|
|
@@ -96473,7 +96087,7 @@ class LogFileDiagOutput {
|
|
|
96473
96087
|
this.stream.end();
|
|
96474
96088
|
} catch {}
|
|
96475
96089
|
try {
|
|
96476
|
-
|
|
96090
|
+
unlinkSync9(this.logPath);
|
|
96477
96091
|
} catch {}
|
|
96478
96092
|
}
|
|
96479
96093
|
getLogPath() {
|
|
@@ -96497,18 +96111,274 @@ function createDiagOutput(options) {
|
|
|
96497
96111
|
}
|
|
96498
96112
|
var init_diag_output = () => {};
|
|
96499
96113
|
|
|
96114
|
+
// src/team-grid.ts
|
|
96115
|
+
var exports_team_grid = {};
|
|
96116
|
+
__export(exports_team_grid, {
|
|
96117
|
+
runWithGrid: () => runWithGrid
|
|
96118
|
+
});
|
|
96119
|
+
import { spawn as spawn4 } from "child_process";
|
|
96120
|
+
import {
|
|
96121
|
+
appendFileSync,
|
|
96122
|
+
existsSync as existsSync28,
|
|
96123
|
+
mkdirSync as mkdirSync16,
|
|
96124
|
+
readFileSync as readFileSync22,
|
|
96125
|
+
unlinkSync as unlinkSync10,
|
|
96126
|
+
writeFileSync as writeFileSync17
|
|
96127
|
+
} from "fs";
|
|
96128
|
+
import { dirname as dirname6, join as join29 } from "path";
|
|
96129
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
96130
|
+
import { execSync as execSync3 } from "child_process";
|
|
96131
|
+
function formatElapsed(ms) {
|
|
96132
|
+
const s = Math.floor(ms / 1000);
|
|
96133
|
+
if (s < 60)
|
|
96134
|
+
return `${s}s`;
|
|
96135
|
+
const m2 = Math.floor(s / 60);
|
|
96136
|
+
const rem = s % 60;
|
|
96137
|
+
return `${m2}m ${rem}s`;
|
|
96138
|
+
}
|
|
96139
|
+
function findMagmuxBinary() {
|
|
96140
|
+
const thisFile = fileURLToPath6(import.meta.url);
|
|
96141
|
+
const thisDir = dirname6(thisFile);
|
|
96142
|
+
const pkgRoot = join29(thisDir, "..");
|
|
96143
|
+
const platform3 = process.platform;
|
|
96144
|
+
const arch = process.arch;
|
|
96145
|
+
const builtMagmux = join29(pkgRoot, "native", "magmux", "magmux");
|
|
96146
|
+
if (existsSync28(builtMagmux))
|
|
96147
|
+
return builtMagmux;
|
|
96148
|
+
const bundledMagmux = join29(pkgRoot, "native", "magmux", `magmux-${platform3}-${arch}`);
|
|
96149
|
+
if (existsSync28(bundledMagmux))
|
|
96150
|
+
return bundledMagmux;
|
|
96151
|
+
try {
|
|
96152
|
+
const pkgName = `@claudish/magmux-${platform3}-${arch}`;
|
|
96153
|
+
let searchDir = pkgRoot;
|
|
96154
|
+
for (let i = 0;i < 5; i++) {
|
|
96155
|
+
const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
|
|
96156
|
+
if (existsSync28(candidate))
|
|
96157
|
+
return candidate;
|
|
96158
|
+
const parent = dirname6(searchDir);
|
|
96159
|
+
if (parent === searchDir)
|
|
96160
|
+
break;
|
|
96161
|
+
searchDir = parent;
|
|
96162
|
+
}
|
|
96163
|
+
} catch {}
|
|
96164
|
+
try {
|
|
96165
|
+
const result = execSync3("which magmux", { encoding: "utf-8" }).trim();
|
|
96166
|
+
if (result)
|
|
96167
|
+
return result;
|
|
96168
|
+
} catch {}
|
|
96169
|
+
throw new Error(`magmux not found. Install it:
|
|
96170
|
+
brew install MadAppGang/tap/magmux`);
|
|
96171
|
+
}
|
|
96172
|
+
function renderGridStatusBar(counts) {
|
|
96173
|
+
const elapsed = formatElapsed(counts.elapsedMs);
|
|
96174
|
+
const { done, running, failed, total, allDone } = counts;
|
|
96175
|
+
if (allDone) {
|
|
96176
|
+
if (failed > 0) {
|
|
96177
|
+
return [
|
|
96178
|
+
"C: claudish team",
|
|
96179
|
+
`G: ${done} done`,
|
|
96180
|
+
`R: ${failed} failed`,
|
|
96181
|
+
`D: ${elapsed}`,
|
|
96182
|
+
"R: \u2717 issues",
|
|
96183
|
+
"D: ctrl-g q to quit"
|
|
96184
|
+
].join("\t");
|
|
96185
|
+
}
|
|
96186
|
+
return [
|
|
96187
|
+
"C: claudish team",
|
|
96188
|
+
`G: ${total} done`,
|
|
96189
|
+
`D: ${elapsed}`,
|
|
96190
|
+
"G: \u2713 complete",
|
|
96191
|
+
"D: ctrl-g q to quit"
|
|
96192
|
+
].join("\t");
|
|
96193
|
+
}
|
|
96194
|
+
return [
|
|
96195
|
+
"C: claudish team",
|
|
96196
|
+
`G: ${done} done`,
|
|
96197
|
+
`C: ${running} running`,
|
|
96198
|
+
`R: ${failed} failed`,
|
|
96199
|
+
`D: ${elapsed}`
|
|
96200
|
+
].join("\t");
|
|
96201
|
+
}
|
|
96202
|
+
function pollStatus(state) {
|
|
96203
|
+
const { statusCache, statusPath, sessionPath, anonIds, startTime, timeoutMs, statusbarPath } = state;
|
|
96204
|
+
const elapsedMs = Date.now() - startTime;
|
|
96205
|
+
let changed = false;
|
|
96206
|
+
let done = 0;
|
|
96207
|
+
let running = 0;
|
|
96208
|
+
let failed = 0;
|
|
96209
|
+
for (const anonId of anonIds) {
|
|
96210
|
+
const current = statusCache.models[anonId];
|
|
96211
|
+
if (current.state === "COMPLETED" || current.state === "FAILED" || current.state === "TIMEOUT") {
|
|
96212
|
+
if (current.state === "COMPLETED")
|
|
96213
|
+
done++;
|
|
96214
|
+
else
|
|
96215
|
+
failed++;
|
|
96216
|
+
continue;
|
|
96217
|
+
}
|
|
96218
|
+
const exitCodePath = join29(sessionPath, "work", anonId, ".exit-code");
|
|
96219
|
+
if (existsSync28(exitCodePath)) {
|
|
96220
|
+
const codeStr = readFileSync22(exitCodePath, "utf-8").trim();
|
|
96221
|
+
const code = parseInt(codeStr, 10);
|
|
96222
|
+
const isSuccess = code === 0;
|
|
96223
|
+
const newState = {
|
|
96224
|
+
...current,
|
|
96225
|
+
state: isSuccess ? "COMPLETED" : "FAILED",
|
|
96226
|
+
exitCode: code,
|
|
96227
|
+
startedAt: current.startedAt ?? new Date().toISOString(),
|
|
96228
|
+
completedAt: new Date().toISOString(),
|
|
96229
|
+
outputSize: 0
|
|
96230
|
+
};
|
|
96231
|
+
statusCache.models[anonId] = newState;
|
|
96232
|
+
changed = true;
|
|
96233
|
+
if (isSuccess)
|
|
96234
|
+
done++;
|
|
96235
|
+
else
|
|
96236
|
+
failed++;
|
|
96237
|
+
} else {
|
|
96238
|
+
if (!state.interactive && elapsedMs > timeoutMs) {
|
|
96239
|
+
const newState = {
|
|
96240
|
+
...current,
|
|
96241
|
+
state: "TIMEOUT",
|
|
96242
|
+
startedAt: current.startedAt ?? new Date().toISOString(),
|
|
96243
|
+
completedAt: new Date().toISOString(),
|
|
96244
|
+
outputSize: 0
|
|
96245
|
+
};
|
|
96246
|
+
statusCache.models[anonId] = newState;
|
|
96247
|
+
changed = true;
|
|
96248
|
+
failed++;
|
|
96249
|
+
} else {
|
|
96250
|
+
if (current.state === "PENDING" && elapsedMs > 1000) {
|
|
96251
|
+
statusCache.models[anonId] = {
|
|
96252
|
+
...current,
|
|
96253
|
+
state: "RUNNING",
|
|
96254
|
+
startedAt: current.startedAt ?? new Date().toISOString()
|
|
96255
|
+
};
|
|
96256
|
+
changed = true;
|
|
96257
|
+
}
|
|
96258
|
+
running++;
|
|
96259
|
+
}
|
|
96260
|
+
}
|
|
96261
|
+
}
|
|
96262
|
+
if (changed) {
|
|
96263
|
+
writeFileSync17(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
|
|
96264
|
+
}
|
|
96265
|
+
const total = anonIds.length;
|
|
96266
|
+
const allDone = done + failed >= total;
|
|
96267
|
+
if (allDone && !state.completedAtMs) {
|
|
96268
|
+
state.completedAtMs = elapsedMs;
|
|
96269
|
+
}
|
|
96270
|
+
const counts = {
|
|
96271
|
+
done,
|
|
96272
|
+
running,
|
|
96273
|
+
failed,
|
|
96274
|
+
total,
|
|
96275
|
+
elapsedMs: state.completedAtMs ?? elapsedMs,
|
|
96276
|
+
allDone
|
|
96277
|
+
};
|
|
96278
|
+
appendFileSync(statusbarPath, renderGridStatusBar(counts) + `
|
|
96279
|
+
`);
|
|
96280
|
+
return allDone;
|
|
96281
|
+
}
|
|
96282
|
+
async function runWithGrid(sessionPath, models, input, opts) {
|
|
96283
|
+
const timeoutMs = (opts?.timeout ?? 300) * 1000;
|
|
96284
|
+
const interactive = opts?.interactive ?? false;
|
|
96285
|
+
const manifest = setupSession(sessionPath, models, input);
|
|
96286
|
+
mkdirSync16(join29(sessionPath, "errors"), { recursive: true });
|
|
96287
|
+
for (const anonId of Object.keys(manifest.models)) {
|
|
96288
|
+
const stale = join29(sessionPath, "work", anonId, ".exit-code");
|
|
96289
|
+
try {
|
|
96290
|
+
unlinkSync10(stale);
|
|
96291
|
+
} catch {}
|
|
96292
|
+
}
|
|
96293
|
+
const gridfilePath = join29(sessionPath, "gridfile.txt");
|
|
96294
|
+
const prompt = readFileSync22(join29(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
|
|
96295
|
+
const gridLines = Object.entries(manifest.models).map(([anonId]) => {
|
|
96296
|
+
const errorLog = join29(sessionPath, "errors", `${anonId}.log`);
|
|
96297
|
+
const exitCodeFile = join29(sessionPath, "work", anonId, ".exit-code");
|
|
96298
|
+
const model = manifest.models[anonId].model;
|
|
96299
|
+
const paneIndex = Object.keys(manifest.models).indexOf(anonId);
|
|
96300
|
+
if (interactive) {
|
|
96301
|
+
return `claudish --model ${model} --dangerously-skip-permissions '${prompt}'`;
|
|
96302
|
+
}
|
|
96303
|
+
return [
|
|
96304
|
+
`claudish --model ${model} -y -v '${prompt}' 2>${errorLog};`,
|
|
96305
|
+
`_ec=$?; echo $_ec > ${exitCodeFile};`,
|
|
96306
|
+
`if [ -n "$MAGMUX_SOCK" ]; then`,
|
|
96307
|
+
` if [ $_ec -eq 0 ]; then`,
|
|
96308
|
+
` echo '{"cmd":"tint","pane":${paneIndex},"color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
96309
|
+
` echo '{"cmd":"overlay","pane":${paneIndex},"text":"DONE","color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
96310
|
+
` else`,
|
|
96311
|
+
` echo '{"cmd":"tint","pane":${paneIndex},"color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
96312
|
+
` echo '{"cmd":"overlay","pane":${paneIndex},"text":"FAIL","color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
|
|
96313
|
+
` fi;`,
|
|
96314
|
+
`fi;`,
|
|
96315
|
+
`exec sleep 86400`
|
|
96316
|
+
].join(" ");
|
|
96317
|
+
});
|
|
96318
|
+
writeFileSync17(gridfilePath, gridLines.join(`
|
|
96319
|
+
`) + `
|
|
96320
|
+
`, "utf-8");
|
|
96321
|
+
const magmuxPath = findMagmuxBinary();
|
|
96322
|
+
const statusbarPath = join29(sessionPath, "statusbar.txt");
|
|
96323
|
+
const statusPath = join29(sessionPath, "status.json");
|
|
96324
|
+
const statusCache = JSON.parse(readFileSync22(statusPath, "utf-8"));
|
|
96325
|
+
const anonIds = Object.keys(manifest.models);
|
|
96326
|
+
const startTime = Date.now();
|
|
96327
|
+
appendFileSync(statusbarPath, renderGridStatusBar({
|
|
96328
|
+
done: 0,
|
|
96329
|
+
running: 0,
|
|
96330
|
+
failed: 0,
|
|
96331
|
+
total: anonIds.length,
|
|
96332
|
+
elapsedMs: 0,
|
|
96333
|
+
allDone: false
|
|
96334
|
+
}) + `
|
|
96335
|
+
`);
|
|
96336
|
+
const pollState = {
|
|
96337
|
+
statusCache,
|
|
96338
|
+
statusPath,
|
|
96339
|
+
sessionPath,
|
|
96340
|
+
anonIds,
|
|
96341
|
+
startTime,
|
|
96342
|
+
timeoutMs,
|
|
96343
|
+
statusbarPath,
|
|
96344
|
+
completedAtMs: null,
|
|
96345
|
+
interactive
|
|
96346
|
+
};
|
|
96347
|
+
const pollInterval = setInterval(() => {
|
|
96348
|
+
pollStatus(pollState);
|
|
96349
|
+
}, 500);
|
|
96350
|
+
const spawnArgs = ["-g", gridfilePath, "-S", statusbarPath];
|
|
96351
|
+
if (!interactive) {
|
|
96352
|
+
spawnArgs.push("-w");
|
|
96353
|
+
}
|
|
96354
|
+
const proc = spawn4(magmuxPath, spawnArgs, {
|
|
96355
|
+
stdio: "inherit",
|
|
96356
|
+
env: { ...process.env }
|
|
96357
|
+
});
|
|
96358
|
+
await new Promise((resolve4) => {
|
|
96359
|
+
proc.on("exit", () => resolve4());
|
|
96360
|
+
proc.on("error", () => resolve4());
|
|
96361
|
+
});
|
|
96362
|
+
clearInterval(pollInterval);
|
|
96363
|
+
pollStatus(pollState);
|
|
96364
|
+
return JSON.parse(readFileSync22(statusPath, "utf-8"));
|
|
96365
|
+
}
|
|
96366
|
+
var init_team_grid = __esm(() => {
|
|
96367
|
+
init_team_orchestrator();
|
|
96368
|
+
});
|
|
96369
|
+
|
|
96500
96370
|
// src/index.ts
|
|
96501
96371
|
var import_dotenv3 = __toESM(require_main(), 1);
|
|
96502
|
-
import { existsSync as existsSync29, readFileSync as
|
|
96372
|
+
import { existsSync as existsSync29, readFileSync as readFileSync23 } from "fs";
|
|
96503
96373
|
import { homedir as homedir27 } from "os";
|
|
96504
|
-
import { join as
|
|
96374
|
+
import { join as join30 } from "path";
|
|
96505
96375
|
import_dotenv3.config({ quiet: true });
|
|
96506
96376
|
function loadStoredApiKeys() {
|
|
96507
96377
|
try {
|
|
96508
|
-
const configPath =
|
|
96378
|
+
const configPath = join30(homedir27(), ".claudish", "config.json");
|
|
96509
96379
|
if (!existsSync29(configPath))
|
|
96510
96380
|
return;
|
|
96511
|
-
const raw2 =
|
|
96381
|
+
const raw2 = readFileSync23(configPath, "utf-8");
|
|
96512
96382
|
const cfg = JSON.parse(raw2);
|
|
96513
96383
|
if (cfg.apiKeys) {
|
|
96514
96384
|
for (const [envVar, value] of Object.entries(cfg.apiKeys)) {
|
|
@@ -96543,7 +96413,6 @@ var firstPositional = args.find((a) => !a.startsWith("-"));
|
|
|
96543
96413
|
var isTelemetryCommand = firstPositional === "telemetry";
|
|
96544
96414
|
var isStatsCommand = firstPositional === "stats";
|
|
96545
96415
|
var isConfigCommand = firstPositional === "config";
|
|
96546
|
-
var isTeamCommand = firstPositional === "team";
|
|
96547
96416
|
var isLoginCommand = firstPositional === "login";
|
|
96548
96417
|
var isLogoutCommand = firstPositional === "logout";
|
|
96549
96418
|
var isQuotaCommand = firstPositional === "quota" || firstPositional === "usage";
|
|
@@ -96592,8 +96461,6 @@ if (isMcpMode) {
|
|
|
96592
96461
|
});
|
|
96593
96462
|
} else if (isConfigCommand) {
|
|
96594
96463
|
init_tui().then(() => exports_tui).then((m2) => m2.startConfigTui().catch(handlePromptExit));
|
|
96595
|
-
} else if (isTeamCommand) {
|
|
96596
|
-
Promise.resolve().then(() => (init_team_cli(), exports_team_cli)).then((m2) => m2.teamCommand(args.slice(1)));
|
|
96597
96464
|
} else {
|
|
96598
96465
|
runCli();
|
|
96599
96466
|
}
|
|
@@ -96622,6 +96489,32 @@ async function runCli() {
|
|
|
96622
96489
|
}
|
|
96623
96490
|
try {
|
|
96624
96491
|
const cliConfig = await parseArgs2(process.argv.slice(2));
|
|
96492
|
+
if (cliConfig.team && cliConfig.team.length > 0) {
|
|
96493
|
+
const { runWithGrid: runWithGrid2 } = await Promise.resolve().then(() => (init_team_grid(), exports_team_grid));
|
|
96494
|
+
let prompt = cliConfig.claudeArgs.join(" ");
|
|
96495
|
+
if (cliConfig.inputFile) {
|
|
96496
|
+
prompt = readFileSync23(cliConfig.inputFile, "utf-8");
|
|
96497
|
+
}
|
|
96498
|
+
if (!prompt.trim()) {
|
|
96499
|
+
console.error("Error: --team requires a prompt (positional args or -f <file>)");
|
|
96500
|
+
process.exit(1);
|
|
96501
|
+
}
|
|
96502
|
+
const interactive = cliConfig.teamMode !== "json";
|
|
96503
|
+
const sessionPath = join30(process.cwd(), `.claudish-team-${Date.now()}`);
|
|
96504
|
+
const status = await runWithGrid2(sessionPath, cliConfig.team, prompt, {
|
|
96505
|
+
timeout: 300,
|
|
96506
|
+
interactive
|
|
96507
|
+
});
|
|
96508
|
+
const modelIds = Object.keys(status.models).sort();
|
|
96509
|
+
console.log(`
|
|
96510
|
+
Team Status`);
|
|
96511
|
+
for (const id of modelIds) {
|
|
96512
|
+
const m2 = status.models[id];
|
|
96513
|
+
const duration3 = m2.startedAt && m2.completedAt ? `${Math.round((new Date(m2.completedAt).getTime() - new Date(m2.startedAt).getTime()) / 1000)}s` : "pending";
|
|
96514
|
+
console.log(` ${id} ${m2.state.padEnd(10)} ${duration3}`);
|
|
96515
|
+
}
|
|
96516
|
+
process.exit(0);
|
|
96517
|
+
}
|
|
96625
96518
|
const rawArgs = process.argv.slice(2);
|
|
96626
96519
|
const explicitNoAutoApprove = rawArgs.includes("--no-auto-approve");
|
|
96627
96520
|
if (cliConfig.autoApprove && !explicitNoAutoApprove && !cliConfig.stdin) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"dist/",
|
|
42
|
-
"native/magmux/magmux-*",
|
|
43
42
|
"AI_AGENT_GUIDE.md",
|
|
44
43
|
"recommended-models.json",
|
|
45
44
|
"skills/"
|
|
@@ -59,6 +58,12 @@
|
|
|
59
58
|
"model-context-protocol",
|
|
60
59
|
"ai"
|
|
61
60
|
],
|
|
61
|
+
"optionalDependencies": {
|
|
62
|
+
"@claudish/magmux-darwin-arm64": "6.9.0",
|
|
63
|
+
"@claudish/magmux-darwin-x64": "6.9.0",
|
|
64
|
+
"@claudish/magmux-linux-arm64": "6.9.0",
|
|
65
|
+
"@claudish/magmux-linux-x64": "6.9.0"
|
|
66
|
+
},
|
|
62
67
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
63
68
|
"license": "MIT",
|
|
64
69
|
"repository": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|