claudish 6.13.0 → 6.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +120 -125
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -22367,7 +22367,7 @@ var init_profile_config = __esm(() => {
22367
22367
  });
22368
22368
 
22369
22369
  // src/version.ts
22370
- var VERSION = "6.13.0";
22370
+ var VERSION = "6.13.1";
22371
22371
 
22372
22372
  // src/telemetry.ts
22373
22373
  var exports_telemetry = {};
@@ -107726,14 +107726,14 @@ __export(exports_team_grid, {
107726
107726
  import { spawn as spawn5 } from "child_process";
107727
107727
  import {
107728
107728
  existsSync as existsSync29,
107729
- mkdirSync as mkdirSync16,
107730
107729
  readFileSync as readFileSync24,
107731
- unlinkSync as unlinkSync11,
107732
107730
  writeFileSync as writeFileSync18
107733
107731
  } from "fs";
107734
107732
  import { dirname as dirname6, join as join30 } from "path";
107735
107733
  import { fileURLToPath as fileURLToPath6 } from "url";
107736
107734
  import { execSync as execSync2 } from "child_process";
107735
+ import { connect as netConnect } from "net";
107736
+ import { setTimeout as wait } from "timers/promises";
107737
107737
  function resolveRouteInfo(modelId) {
107738
107738
  const parsed = parseModelSpec(modelId);
107739
107739
  if (parsed.isExplicitProvider) {
@@ -107787,21 +107787,22 @@ function resolveRouteInfo(modelId) {
107787
107787
  source: "auto"
107788
107788
  };
107789
107789
  }
107790
- function buildPaneHeader(model, prompt) {
107791
- const route = resolveRouteInfo(model);
107792
- const esc2 = (s) => s.replace(/'/g, "'\\''");
107793
- const bgColors = [
107794
- "48;2;40;90;180",
107795
- "48;2;140;60;160",
107796
- "48;2;30;130;100",
107797
- "48;2;160;80;40",
107798
- "48;2;60;120;60",
107799
- "48;2;160;50;70"
107800
- ];
107790
+ function pickBannerColor(model, used) {
107801
107791
  let hash = 0;
107802
107792
  for (let i = 0;i < model.length; i++)
107803
107793
  hash = (hash << 5) - hash + model.charCodeAt(i) | 0;
107804
- const bg2 = bgColors[Math.abs(hash) % bgColors.length];
107794
+ const start = Math.abs(hash) % BANNER_BG_COLORS.length;
107795
+ let idx = start;
107796
+ if (used.size < BANNER_BG_COLORS.length) {
107797
+ while (used.has(idx))
107798
+ idx = (idx + 1) % BANNER_BG_COLORS.length;
107799
+ }
107800
+ used.add(idx);
107801
+ return BANNER_BG_COLORS[idx];
107802
+ }
107803
+ function buildPaneHeader(model, prompt, bg2) {
107804
+ const route = resolveRouteInfo(model);
107805
+ const esc2 = (s) => s.replace(/'/g, "'\\''");
107805
107806
  const chainStr = route.chain.join(" \u2192 ");
107806
107807
  const sourceLabel = route.sourceDetail ? `${route.source}: ${route.sourceDetail}` : route.source;
107807
107808
  const lines = [];
@@ -107843,133 +107844,113 @@ function findMagmuxBinary() {
107843
107844
  throw new Error(`magmux not found. Install it:
107844
107845
  brew install MadAppGang/tap/magmux`);
107845
107846
  }
107846
- function finalizeStatus(statusPath, sessionPath, anonIds, mode) {
107847
- const statusCache = JSON.parse(readFileSync24(statusPath, "utf-8"));
107848
- for (const anonId of anonIds) {
107849
- const current = statusCache.models[anonId];
107850
- if (current.state === "COMPLETED" || current.state === "FAILED")
107851
- continue;
107852
- const exitCodePath = join30(sessionPath, "work", anonId, ".exit-code");
107853
- if (existsSync29(exitCodePath)) {
107854
- const code = parseInt(readFileSync24(exitCodePath, "utf-8").trim(), 10);
107855
- statusCache.models[anonId] = {
107856
- ...current,
107857
- state: code === 0 ? "COMPLETED" : "FAILED",
107858
- exitCode: code,
107859
- startedAt: current.startedAt ?? statusCache.startedAt,
107860
- completedAt: new Date().toISOString()
107861
- };
107862
- } else if (mode === "interactive") {
107863
- statusCache.models[anonId] = {
107864
- ...current,
107865
- state: "COMPLETED",
107866
- exitCode: 0,
107867
- startedAt: current.startedAt ?? statusCache.startedAt,
107868
- completedAt: new Date().toISOString()
107847
+ async function subscribeToMagmux(sockPath, onEvent) {
107848
+ let client = null;
107849
+ for (let attempt = 0;attempt < 40; attempt++) {
107850
+ if (existsSync29(sockPath)) {
107851
+ try {
107852
+ client = await new Promise((resolve4, reject) => {
107853
+ const s = netConnect(sockPath);
107854
+ s.once("connect", () => resolve4(s));
107855
+ s.once("error", reject);
107856
+ });
107857
+ break;
107858
+ } catch {}
107859
+ }
107860
+ await wait(50);
107861
+ }
107862
+ if (!client) {
107863
+ return { results: null, client: null };
107864
+ }
107865
+ return await new Promise((resolve4) => {
107866
+ let buf = "";
107867
+ let finalResults = null;
107868
+ client.on("data", (chunk) => {
107869
+ buf += chunk.toString("utf-8");
107870
+ let nl = buf.indexOf(`
107871
+ `);
107872
+ while (nl >= 0) {
107873
+ const line = buf.slice(0, nl).trim();
107874
+ buf = buf.slice(nl + 1);
107875
+ nl = buf.indexOf(`
107876
+ `);
107877
+ if (!line)
107878
+ continue;
107879
+ try {
107880
+ const evt = JSON.parse(line);
107881
+ onEvent?.(evt);
107882
+ if (evt.type === "results") {
107883
+ finalResults = evt;
107884
+ }
107885
+ } catch {}
107886
+ }
107887
+ });
107888
+ const done = () => resolve4({ results: finalResults, client });
107889
+ client.once("end", done);
107890
+ client.once("close", done);
107891
+ client.once("error", done);
107892
+ });
107893
+ }
107894
+ function buildTeamStatus(manifest, startedAt, results) {
107895
+ const anonIds = Object.keys(manifest.models);
107896
+ const models = {};
107897
+ for (let i = 0;i < anonIds.length; i++) {
107898
+ const anonId = anonIds[i];
107899
+ const result = results?.find((r) => r.pane === i);
107900
+ if (!result) {
107901
+ models[anonId] = {
107902
+ state: "TIMEOUT",
107903
+ exitCode: null,
107904
+ startedAt,
107905
+ completedAt: null,
107906
+ outputSize: 0
107869
107907
  };
107870
- } else {
107871
- statusCache.models[anonId] = { ...current, state: "TIMEOUT" };
107908
+ continue;
107872
107909
  }
107910
+ let state;
107911
+ switch (result.state) {
107912
+ case "completed":
107913
+ case "awaiting_input":
107914
+ state = "COMPLETED";
107915
+ break;
107916
+ case "failed":
107917
+ state = "FAILED";
107918
+ break;
107919
+ default:
107920
+ state = "TIMEOUT";
107921
+ }
107922
+ models[anonId] = {
107923
+ state,
107924
+ exitCode: result.exitCode,
107925
+ startedAt: result.startedAt ?? startedAt,
107926
+ completedAt: result.completedAt ?? new Date().toISOString(),
107927
+ outputSize: result.response?.length ?? 0
107928
+ };
107873
107929
  }
107874
- writeFileSync18(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
107930
+ return { startedAt, models };
107875
107931
  }
107876
107932
  async function runWithGrid(sessionPath, models, input, opts) {
107877
107933
  const mode = opts?.mode ?? "default";
107878
107934
  const keep = opts?.keep ?? false;
107879
107935
  const manifest = setupSession(sessionPath, models, input);
107880
- mkdirSync16(join30(sessionPath, "errors"), { recursive: true });
107881
- for (const anonId of Object.keys(manifest.models)) {
107882
- const stale = join30(sessionPath, "work", anonId, ".exit-code");
107883
- try {
107884
- unlinkSync11(stale);
107885
- } catch {}
107886
- }
107936
+ const startedAt = new Date().toISOString();
107887
107937
  const gridfilePath = join30(sessionPath, "gridfile.txt");
107888
107938
  const prompt = readFileSync24(join30(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
107889
- const totalPanes = Object.keys(manifest.models).length;
107890
- const workDir = join30(sessionPath, "work");
107891
- const statusJsonAllDone = JSON.stringify({
107892
- cmd: "status",
107893
- text: `C: claudish team G: ${totalPanes} done G: complete D: __TS__ D: ctrl-g q to quit`
107894
- });
107895
- const statusJsonWithFails = JSON.stringify({
107896
- cmd: "status",
107897
- text: `C: claudish team G: __D__ done R: __F__ failed D: __TS__ D: ctrl-g q to quit`
107898
- });
107899
- const statusJsonRunning = JSON.stringify({
107900
- cmd: "status",
107901
- text: `C: claudish team G: __D__ done C: __R__ running R: __F__ failed D: __TS__`
107902
- });
107903
- const tplDir = join30(sessionPath, "status-tpl");
107904
- mkdirSync16(tplDir, { recursive: true });
107905
- writeFileSync18(join30(tplDir, "all-done.json"), statusJsonAllDone);
107906
- writeFileSync18(join30(tplDir, "with-fails.json"), statusJsonWithFails);
107907
- writeFileSync18(join30(tplDir, "running.json"), statusJsonRunning);
107908
- const statusFunc = [
107909
- `_update_bar() {`,
107910
- `_d=0; _f=0;`,
107911
- `for _ecf in $(find ${workDir} -name .exit-code 2>/dev/null); do`,
107912
- `_c=$(cat "$_ecf" 2>/dev/null);`,
107913
- `if [ "$_c" = "0" ]; then _d=$((_d+1)); else _f=$((_f+1)); fi;`,
107914
- `done;`,
107915
- `_r=$((${totalPanes}-_d-_f));`,
107916
- `_e=$SECONDS;`,
107917
- `if [ $_e -ge 60 ]; then _ts="$((_e/60))m $((_e%60))s"; else _ts="\${_e}s"; fi;`,
107918
- `if [ $_r -eq 0 ] && [ $_f -eq 0 ]; then`,
107919
- `sed "s/__TS__/\${_ts}/" ${tplDir}/all-done.json | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107920
- `elif [ $_r -eq 0 ] && [ $_f -gt 0 ]; then`,
107921
- `sed -e "s/__D__/\${_d}/" -e "s/__F__/\${_f}/" -e "s/__TS__/\${_ts}/" ${tplDir}/with-fails.json | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107922
- `else`,
107923
- `sed -e "s/__D__/\${_d}/" -e "s/__R__/\${_r}/" -e "s/__F__/\${_f}/" -e "s/__TS__/\${_ts}/" ${tplDir}/running.json | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107924
- `fi;`,
107925
- `};`
107926
- ].join(" ");
107927
107939
  const rawPrompt = readFileSync24(join30(sessionPath, "input.md"), "utf-8");
107940
+ const usedBannerColors = new Set;
107928
107941
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
107929
- const errorLog = join30(sessionPath, "errors", `${anonId}.log`);
107930
- const exitCodeFile = join30(sessionPath, "work", anonId, ".exit-code");
107931
107942
  const model = manifest.models[anonId].model;
107932
- const paneIndex = Object.keys(manifest.models).indexOf(anonId);
107933
107943
  if (mode === "interactive") {
107934
- const modelList = Object.values(manifest.models).map((m2) => m2.model).join(", ");
107935
- const interactiveJson = JSON.stringify({
107936
- cmd: "status",
107937
- text: `C: claudish team W: ${modelList} D: ctrl-g Tab switch D: ctrl-g q quit`
107938
- });
107939
- const interactiveJsonFile = join30(tplDir, "interactive.json");
107940
- writeFileSync18(interactiveJsonFile, interactiveJson);
107941
- return [
107942
- `if [ -n "$MAGMUX_SOCK" ]; then cat ${interactiveJsonFile} | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null; fi;`,
107943
- `claudish --model ${model} -i --dangerously-skip-permissions '${prompt}' 2>${errorLog};`,
107944
- `_ec=$?; echo $_ec > ${exitCodeFile}`
107945
- ].join(" ");
107944
+ return `claudish --model ${model} -i --dangerously-skip-permissions '${prompt}'`;
107946
107945
  }
107947
- const header = buildPaneHeader(model, rawPrompt);
107948
- return [
107949
- `${statusFunc}`,
107950
- `if [ -n "$MAGMUX_SOCK" ]; then _update_bar; fi;`,
107951
- `${header}`,
107952
- `claudish --model ${model} -y --quiet '${prompt}' 2>${errorLog};`,
107953
- `_ec=$?; echo $_ec > ${exitCodeFile};`,
107954
- `if [ -n "$MAGMUX_SOCK" ]; then`,
107955
- ` _update_bar;`,
107956
- ` if [ $_ec -eq 0 ]; then`,
107957
- ` echo '{"cmd":"tint","pane":${paneIndex},"color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107958
- ` echo '{"cmd":"overlay","pane":${paneIndex},"text":"DONE","color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107959
- ` else`,
107960
- ` echo '{"cmd":"tint","pane":${paneIndex},"color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107961
- ` echo '{"cmd":"overlay","pane":${paneIndex},"text":"FAIL","color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
107962
- ` fi;`,
107963
- `fi;`,
107964
- `exec sleep 86400`
107965
- ].join(" ");
107946
+ const bg2 = pickBannerColor(model, usedBannerColors);
107947
+ const header = buildPaneHeader(model, rawPrompt, bg2);
107948
+ return `${header} claudish --model ${model} -y --quiet '${prompt}'`;
107966
107949
  });
107967
107950
  writeFileSync18(gridfilePath, gridLines.join(`
107968
107951
  `) + `
107969
107952
  `, "utf-8");
107970
107953
  const magmuxPath = findMagmuxBinary();
107971
- const statusPath = join30(sessionPath, "status.json");
107972
- const anonIds = Object.keys(manifest.models);
107973
107954
  const spawnArgs = ["-g", gridfilePath];
107974
107955
  if (!keep && mode === "default") {
107975
107956
  spawnArgs.push("-w");
@@ -107978,19 +107959,33 @@ async function runWithGrid(sessionPath, models, input, opts) {
107978
107959
  stdio: "inherit",
107979
107960
  env: { ...process.env }
107980
107961
  });
107981
- await new Promise((resolve4) => {
107962
+ const sockPath = `/tmp/magmux-${proc.pid}.sock`;
107963
+ const subscription = subscribeToMagmux(sockPath);
107964
+ const procExit = new Promise((resolve4) => {
107982
107965
  proc.on("exit", () => resolve4());
107983
107966
  proc.on("error", () => resolve4());
107984
107967
  });
107985
- finalizeStatus(statusPath, sessionPath, anonIds, mode);
107986
- return JSON.parse(readFileSync24(statusPath, "utf-8"));
107968
+ const [{ results }] = await Promise.all([subscription, procExit]);
107969
+ const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
107970
+ const statusPath = join30(sessionPath, "status.json");
107971
+ writeFileSync18(statusPath, JSON.stringify(status, null, 2), "utf-8");
107972
+ return status;
107987
107973
  }
107974
+ var BANNER_BG_COLORS;
107988
107975
  var init_team_grid = __esm(() => {
107989
107976
  init_team_orchestrator();
107990
107977
  init_model_parser();
107991
107978
  init_routing_rules();
107992
107979
  init_auto_route();
107993
107980
  init_profile_config();
107981
+ BANNER_BG_COLORS = [
107982
+ "48;2;40;90;180",
107983
+ "48;2;140;60;160",
107984
+ "48;2;30;130;100",
107985
+ "48;2;160;80;40",
107986
+ "48;2;60;120;60",
107987
+ "48;2;160;50;70"
107988
+ ];
107994
107989
  });
107995
107990
 
107996
107991
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "6.13.0",
3
+ "version": "6.13.1",
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",
@@ -59,10 +59,10 @@
59
59
  "ai"
60
60
  ],
61
61
  "optionalDependencies": {
62
- "@claudish/magmux-darwin-arm64": "6.13.0",
63
- "@claudish/magmux-darwin-x64": "6.13.0",
64
- "@claudish/magmux-linux-arm64": "6.13.0",
65
- "@claudish/magmux-linux-x64": "6.13.0"
62
+ "@claudish/magmux-darwin-arm64": "6.13.1",
63
+ "@claudish/magmux-darwin-x64": "6.13.1",
64
+ "@claudish/magmux-linux-arm64": "6.13.1",
65
+ "@claudish/magmux-linux-x64": "6.13.1"
66
66
  },
67
67
  "author": "Jack Rudenko <i@madappgang.com>",
68
68
  "license": "MIT",