claudish 7.60.0 → 7.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +335 -134
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -729,7 +729,7 @@ var init_onepassword_config = __esm(() => {
729
729
  });
730
730
 
731
731
  // src/version.ts
732
- var VERSION = "7.60.0";
732
+ var VERSION = "7.61.0";
733
733
 
734
734
  // src/logger.ts
735
735
  var exports_logger = {};
@@ -5358,6 +5358,57 @@ var init_op_source = __esm(() => {
5358
5358
  environmentResolutions = new Map;
5359
5359
  });
5360
5360
 
5361
+ // src/classifier-passthrough.ts
5362
+ function blockText(block) {
5363
+ if (typeof block === "string")
5364
+ return block;
5365
+ if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
5366
+ return block.text;
5367
+ }
5368
+ return null;
5369
+ }
5370
+ function startsWithMarker(text) {
5371
+ let i = 0;
5372
+ while (i < text.length) {
5373
+ const ch = text.charCodeAt(i);
5374
+ if (ch !== 32 && ch !== 9 && ch !== 10 && ch !== 13 && ch !== 12 && ch !== 11)
5375
+ break;
5376
+ i++;
5377
+ }
5378
+ return text.startsWith(CLASSIFIER_SYSTEM_MARKER, i);
5379
+ }
5380
+ function isAutoModeClassifierRequest(body) {
5381
+ if (!body || typeof body !== "object")
5382
+ return false;
5383
+ const system = body.system;
5384
+ if (typeof system === "string")
5385
+ return startsWithMarker(system);
5386
+ if (!Array.isArray(system))
5387
+ return false;
5388
+ for (const block of system) {
5389
+ const text = blockText(block);
5390
+ if (text !== null && startsWithMarker(text))
5391
+ return true;
5392
+ }
5393
+ return false;
5394
+ }
5395
+ function rewriteClassifierForNative(body, model) {
5396
+ body.model = model;
5397
+ delete body.thinking;
5398
+ }
5399
+ function resolveClassifierConfig(config, env = process.env) {
5400
+ const flagModel = config.classifierModel?.trim();
5401
+ const flagProvider = config.classifierProvider?.trim().toLowerCase();
5402
+ const envProvider = env.CLAUDISH_CLASSIFIER_PROVIDER?.trim().toLowerCase();
5403
+ const envModel = env.CLAUDISH_CLASSIFIER_MODEL?.trim();
5404
+ const enabled = !!flagModel || flagProvider === "anthropic" || envProvider === "anthropic" || !!envModel;
5405
+ return { enabled, model: flagModel || envModel || DEFAULT_CLASSIFIER_MODEL };
5406
+ }
5407
+ function classifierPassthroughEnabled(config, env = process.env) {
5408
+ return resolveClassifierConfig(config, env).enabled;
5409
+ }
5410
+ var CLASSIFIER_SYSTEM_MARKER = "You are a security monitor for autonomous AI coding agents.", DEFAULT_CLASSIFIER_MODEL = "claude-sonnet-5";
5411
+
5361
5412
  // src/onepassword-command.ts
5362
5413
  var exports_onepassword_command = {};
5363
5414
  __export(exports_onepassword_command, {
@@ -31653,6 +31704,8 @@ var init_qwen_model_dialect = __esm(() => {
31653
31704
  }
31654
31705
  if (originalRequest.thinking)
31655
31706
  delete request.thinking;
31707
+ if (request.reasoning_effort !== undefined)
31708
+ delete request.reasoning_effort;
31656
31709
  return request;
31657
31710
  }
31658
31711
  shouldHandle(modelId) {
@@ -37046,6 +37099,9 @@ function hasModelUnsupportedWording(errorBody) {
37046
37099
  const lower = (errorBody || "").toLowerCase();
37047
37100
  return UNSUPPORTED_PHRASES.some((phrase) => lower.includes(phrase));
37048
37101
  }
37102
+ function hasActionableLink(errorBody) {
37103
+ return /https?:\/\/\S+/i.test(errorBody || "");
37104
+ }
37049
37105
  var UNSUPPORTED_PHRASES;
37050
37106
  var init_model_unsupported = __esm(() => {
37051
37107
  UNSUPPORTED_PHRASES = [
@@ -39256,7 +39312,7 @@ class ComposedHandler {
39256
39312
  }
39257
39313
  }
39258
39314
  if (this.provider.transformPayload) {
39259
- requestPayload = this.provider.transformPayload(requestPayload);
39315
+ requestPayload = this.provider.transformPayload(requestPayload, claudeRequest);
39260
39316
  }
39261
39317
  const endpoint = this.provider.getEndpoint(this.targetModel);
39262
39318
  const headers = await this.provider.getHeaders();
@@ -39899,6 +39955,9 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429)
39899
39955
  if (isQuotaExhaustionError(status, errorText)) {
39900
39956
  return "Out of quota \u2014 check your plan & billing details. This won't recover on retry.";
39901
39957
  }
39958
+ if (hasActionableLink(errorText)) {
39959
+ return "Provider rejected the request and gave a specific fix \u2014 follow the link in the message below.";
39960
+ }
39902
39961
  return "Check API key / OAuth credentials.";
39903
39962
  }
39904
39963
  if (status === 404) {
@@ -43669,14 +43728,19 @@ var init_ollamacloud = __esm(() => {
43669
43728
  });
43670
43729
 
43671
43730
  // src/providers/transport/openai-codex.ts
43672
- var OpenAICodexTransport;
43731
+ import { createHash as createHash5, randomBytes as randomBytes6 } from "crypto";
43732
+ var FALLBACK_CONVERSATION_KEY, OpenAICodexTransport;
43673
43733
  var init_openai_codex = __esm(() => {
43674
43734
  init_codex_api_format();
43675
43735
  init_model_catalog();
43676
43736
  init_authority();
43737
+ init_harness();
43677
43738
  init_openai();
43739
+ FALLBACK_CONVERSATION_KEY = randomBytes6(16).toString("hex");
43678
43740
  OpenAICodexTransport = class OpenAICodexTransport extends OpenAIProviderTransport {
43679
43741
  cachedAuth = null;
43742
+ cachedCacheKeyFor;
43743
+ cachedCacheKey = "";
43680
43744
  async refreshAuth() {
43681
43745
  try {
43682
43746
  this.cachedAuth = await credentials.getRequestAuth("openai-codex", { model: "" });
@@ -43692,7 +43756,7 @@ var init_openai_codex = __esm(() => {
43692
43756
  return { ...this.cachedAuth.headers };
43693
43757
  return super.getHeaders();
43694
43758
  }
43695
- transformPayload(payload) {
43759
+ transformPayload(payload, claudeRequest) {
43696
43760
  let normalizedPayload = payload;
43697
43761
  if (payload?.model) {
43698
43762
  const normalized = normalizeCodexModel(payload.model);
@@ -43700,8 +43764,24 @@ var init_openai_codex = __esm(() => {
43700
43764
  normalizedPayload = { ...payload, model: normalized };
43701
43765
  }
43702
43766
  }
43767
+ if (normalizedPayload && typeof normalizedPayload === "object") {
43768
+ normalizedPayload = {
43769
+ ...normalizedPayload,
43770
+ prompt_cache_key: normalizedPayload.prompt_cache_key ?? this.resolvePromptCacheKey(claudeRequest)
43771
+ };
43772
+ }
43703
43773
  return this.cachedAuth?.transformPayload?.(normalizedPayload) ?? normalizedPayload;
43704
43774
  }
43775
+ resolvePromptCacheKey(claudeRequest) {
43776
+ const sessionId2 = extractSessionId(claudeRequest);
43777
+ if (!sessionId2)
43778
+ return `claudish_${FALLBACK_CONVERSATION_KEY}`;
43779
+ if (this.cachedCacheKeyFor !== sessionId2) {
43780
+ this.cachedCacheKeyFor = sessionId2;
43781
+ this.cachedCacheKey = `claudish_${createHash5("sha256").update(sessionId2).digest("hex").slice(0, 32)}`;
43782
+ }
43783
+ return this.cachedCacheKey;
43784
+ }
43705
43785
  getContextWindow() {
43706
43786
  return lookupModelForProvider(this.modelName, this.name) ?? 0;
43707
43787
  }
@@ -44522,6 +44602,7 @@ var init_provider_definitions = __esm(() => {
44522
44602
  baseUrl: "https://api.z.ai",
44523
44603
  baseUrlEnvVars: ["ZHIPU_BASE_URL", "GLM_BASE_URL"],
44524
44604
  apiPath: "/api/paas/v4/chat/completions",
44605
+ modelDiscovery: { path: "/api/paas/v4/models", format: "openai-models-list" },
44525
44606
  apiKeyEnvVar: "ZHIPU_API_KEY",
44526
44607
  apiKeyAliases: ["GLM_API_KEY"],
44527
44608
  apiKeyDescription: "GLM/Zhipu API Key",
@@ -48075,6 +48156,14 @@ function classifyHttpError(status, body, latencyMs) {
48075
48156
  errorMessage: extractErrorMessage(body) || `HTTP ${authStatus}`
48076
48157
  };
48077
48158
  }
48159
+ if (hasActionableLink(body)) {
48160
+ return {
48161
+ state: "error",
48162
+ latencyMs,
48163
+ httpStatus: authStatus,
48164
+ errorMessage: extractErrorMessage(body) || `HTTP ${authStatus}`
48165
+ };
48166
+ }
48078
48167
  return {
48079
48168
  state: "auth-failed",
48080
48169
  latencyMs,
@@ -48121,6 +48210,20 @@ function classifyHttpError(status, body, latencyMs) {
48121
48210
  errorMessage: extractErrorMessage(body) || `HTTP ${status}`
48122
48211
  };
48123
48212
  }
48213
+ function truncateKeepingLink(text, max = 160) {
48214
+ if (text.length <= max)
48215
+ return text;
48216
+ const url2 = text.match(/https?:\/\/\S+/i)?.[0];
48217
+ if (!url2)
48218
+ return `${text.slice(0, max - 3)}...`;
48219
+ const room = max - url2.length - 4;
48220
+ if (room <= 0)
48221
+ return url2;
48222
+ const head = text.slice(0, room);
48223
+ const lastSpace = head.lastIndexOf(" ");
48224
+ const prose = (lastSpace > room * 0.5 ? head.slice(0, lastSpace) : head).trimEnd();
48225
+ return `${prose}... ${url2}`;
48226
+ }
48124
48227
  function extractErrorMessage(body) {
48125
48228
  if (!body)
48126
48229
  return;
@@ -48128,13 +48231,13 @@ function extractErrorMessage(body) {
48128
48231
  const parsed = JSON.parse(body);
48129
48232
  const msg2 = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
48130
48233
  if (typeof msg2 === "string" && msg2.length > 0) {
48131
- return msg2.length > 160 ? `${msg2.slice(0, 157)}...` : msg2;
48234
+ return truncateKeepingLink(msg2);
48132
48235
  }
48133
48236
  } catch {}
48134
48237
  const trimmed2 = body.trim();
48135
48238
  if (!trimmed2)
48136
48239
  return;
48137
- return trimmed2.length > 160 ? `${trimmed2.slice(0, 157)}...` : trimmed2;
48240
+ return truncateKeepingLink(trimmed2);
48138
48241
  }
48139
48242
  async function consumeProbeStream(response, timeoutMs, startedAt) {
48140
48243
  const body = response.body;
@@ -51893,6 +51996,41 @@ var exports_proxy_server = {};
51893
51996
  __export(exports_proxy_server, {
51894
51997
  createProxyServer: () => createProxyServer
51895
51998
  });
51999
+ import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync13 } from "fs";
52000
+ import { join as join29 } from "path";
52001
+ function maybeCaptureClassifierRequest(c, body) {
52002
+ if (!process.env.CLAUDISH_CLASSIFIER_DEBUG)
52003
+ return;
52004
+ try {
52005
+ const dir = join29(process.cwd(), "logs");
52006
+ if (!classifierCaptureDirReady) {
52007
+ mkdirSync13(dir, { recursive: true });
52008
+ classifierCaptureDirReady = true;
52009
+ }
52010
+ const record4 = {
52011
+ ts: new Date().toISOString(),
52012
+ model: body?.model,
52013
+ stream: body?.stream,
52014
+ max_tokens: body?.max_tokens,
52015
+ temperature: body?.temperature,
52016
+ top_p: body?.top_p,
52017
+ top_k: body?.top_k,
52018
+ thinking: body?.thinking,
52019
+ hasTools: Array.isArray(body?.tools) && body.tools.length > 0,
52020
+ tool_choice: body?.tool_choice,
52021
+ system: body?.system,
52022
+ headers: {
52023
+ "anthropic-beta": c.req.header("anthropic-beta") ?? null,
52024
+ "anthropic-version": c.req.header("anthropic-version") ?? null,
52025
+ "x-app": c.req.header("x-app") ?? null,
52026
+ authorization: c.req.header("authorization") ? "Bearer <present>" : null,
52027
+ "x-api-key": c.req.header("x-api-key") ? "<present>" : null
52028
+ }
52029
+ };
52030
+ appendFileSync7(join29(dir, "classifier-capture.jsonl"), `${JSON.stringify(record4)}
52031
+ `);
52032
+ } catch {}
52033
+ }
51896
52034
  async function createProxyServer(port, _openrouterApiKey, model, monitorMode = false, anthropicApiKey, modelMap, options = {}) {
51897
52035
  try {
51898
52036
  const config2 = loadConfig();
@@ -52304,6 +52442,12 @@ ${plan.hint}` : `[Route] ${plan.reason}`;
52304
52442
  try {
52305
52443
  const body = await c.req.json();
52306
52444
  log(`[RequestMeta] model=${body.model} output_config=${JSON.stringify(body.output_config) ?? "(none)"} metadata=${JSON.stringify(body.metadata) ?? "(none)"} anthropic-beta=${c.req.header("anthropic-beta") ?? "(none)"}`);
52445
+ maybeCaptureClassifierRequest(c, body);
52446
+ if (!monitorMode && options.classifier?.enabled && isAutoModeClassifierRequest(body)) {
52447
+ log(`[Classifier] auto-mode permission classifier \u2192 native Anthropic (model ${body.model} \u2192 ${options.classifier.model})`);
52448
+ rewriteClassifierForNative(body, options.classifier.model);
52449
+ return nativeHandler.handle(c, body);
52450
+ }
52307
52451
  const handler = await getHandlerForRequest(body.model);
52308
52452
  return await handler.handle(c, body);
52309
52453
  } catch (e) {
@@ -52349,7 +52493,7 @@ ${plan.hint}` : `[Route] ${plan.reason}`;
52349
52493
  }
52350
52494
  };
52351
52495
  }
52352
- var RoutingError;
52496
+ var RoutingError, classifierCaptureDirReady = false;
52353
52497
  var init_proxy_server = __esm(() => {
52354
52498
  init_dist();
52355
52499
  init_cors();
@@ -52429,12 +52573,12 @@ var init_redact = __esm(() => {
52429
52573
 
52430
52574
  // src/team-stats.ts
52431
52575
  import { existsSync as existsSync20, readFileSync as readFileSync19, writeFileSync as writeFileSync12 } from "fs";
52432
- import { join as join29 } from "path";
52576
+ import { join as join30 } from "path";
52433
52577
  function statsDir(sessionPath) {
52434
- return join29(sessionPath, "stats");
52578
+ return join30(sessionPath, "stats");
52435
52579
  }
52436
52580
  function tokenFileFor(sessionPath, anonId) {
52437
- return join29(statsDir(sessionPath), `${anonId}.json`);
52581
+ return join30(statsDir(sessionPath), `${anonId}.json`);
52438
52582
  }
52439
52583
  function readTokenStats(sessionPath, anonId) {
52440
52584
  const path = tokenFileFor(sessionPath, anonId);
@@ -52589,7 +52733,7 @@ ${segs.join(" \xB7 ")}`;
52589
52733
  }
52590
52734
  function writeStatusFile(sessionPath, manifest, status, opts) {
52591
52735
  try {
52592
- writeFileSync12(join29(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
52736
+ writeFileSync12(join30(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
52593
52737
  `, "utf-8");
52594
52738
  } catch {}
52595
52739
  }
@@ -52741,12 +52885,12 @@ import { spawn as spawn2 } from "child_process";
52741
52885
  import {
52742
52886
  createWriteStream as createWriteStream2,
52743
52887
  existsSync as existsSync21,
52744
- mkdirSync as mkdirSync13,
52888
+ mkdirSync as mkdirSync14,
52745
52889
  readFileSync as readFileSync20,
52746
52890
  readdirSync as readdirSync3,
52747
52891
  writeFileSync as writeFileSync13
52748
52892
  } from "fs";
52749
- import { join as join30, resolve as resolve3 } from "path";
52893
+ import { join as join31, resolve as resolve3 } from "path";
52750
52894
  function resolveCaptureMode(explicit, env = process.env) {
52751
52895
  if (explicit)
52752
52896
  return explicit;
@@ -52843,18 +52987,18 @@ function setupSession(sessionPath, models, input) {
52843
52987
  if (models.length === 0) {
52844
52988
  throw new Error("At least one model is required");
52845
52989
  }
52846
- if (existsSync21(join30(sessionPath, "manifest.json"))) {
52990
+ if (existsSync21(join31(sessionPath, "manifest.json"))) {
52847
52991
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
52848
52992
  }
52849
52993
  const sentinels = models.filter(isSentinelModel);
52850
52994
  if (sentinels.length > 0) {
52851
52995
  throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
52852
52996
  }
52853
- mkdirSync13(join30(sessionPath, "work"), { recursive: true });
52854
- mkdirSync13(join30(sessionPath, "errors"), { recursive: true });
52997
+ mkdirSync14(join31(sessionPath, "work"), { recursive: true });
52998
+ mkdirSync14(join31(sessionPath, "errors"), { recursive: true });
52855
52999
  if (input !== undefined) {
52856
- writeFileSync13(join30(sessionPath, "input.md"), input, "utf-8");
52857
- } else if (!existsSync21(join30(sessionPath, "input.md"))) {
53000
+ writeFileSync13(join31(sessionPath, "input.md"), input, "utf-8");
53001
+ } else if (!existsSync21(join31(sessionPath, "input.md"))) {
52858
53002
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
52859
53003
  }
52860
53004
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -52871,9 +53015,9 @@ function setupSession(sessionPath, models, input) {
52871
53015
  model: models[i],
52872
53016
  assignedAt: now
52873
53017
  };
52874
- mkdirSync13(join30(sessionPath, "work", anonId), { recursive: true });
53018
+ mkdirSync14(join31(sessionPath, "work", anonId), { recursive: true });
52875
53019
  }
52876
- writeFileSync13(join30(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
53020
+ writeFileSync13(join31(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
52877
53021
  const status = {
52878
53022
  startedAt: now,
52879
53023
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -52887,7 +53031,7 @@ function setupSession(sessionPath, models, input) {
52887
53031
  }
52888
53032
  ]))
52889
53033
  };
52890
- writeFileSync13(join30(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
53034
+ writeFileSync13(join31(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
52891
53035
  return manifest;
52892
53036
  }
52893
53037
  function assertValidRequirePattern(pattern) {
@@ -52912,9 +53056,9 @@ function readFullOutputIfNeeded(opts) {
52912
53056
  async function runModels(sessionPath, opts = {}) {
52913
53057
  const timeoutMs = (opts.timeout ?? 300) * 1000;
52914
53058
  assertValidRequirePattern(opts.requirePattern);
52915
- const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
52916
- const statusPath = join30(sessionPath, "status.json");
52917
- const inputPath = join30(sessionPath, "input.md");
53059
+ const manifest = JSON.parse(readFileSync20(join31(sessionPath, "manifest.json"), "utf-8"));
53060
+ const statusPath = join31(sessionPath, "status.json");
53061
+ const inputPath = join31(sessionPath, "input.md");
52918
53062
  const inputContent = readFileSync20(inputPath, "utf-8");
52919
53063
  const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
52920
53064
  const statusCache = JSON.parse(readFileSync20(statusPath, "utf-8"));
@@ -52953,7 +53097,7 @@ async function runModels(sessionPath, opts = {}) {
52953
53097
  persistErrorLog(rt.errorLogPath, `RECOVERED: ${note}`, stderr, stdoutTail);
52954
53098
  opts.onStatusChange?.(id, statusCache.models[id]);
52955
53099
  }
52956
- mkdirSync13(statsDir(sessionPath), { recursive: true });
53100
+ mkdirSync14(statsDir(sessionPath), { recursive: true });
52957
53101
  const processes = new Map;
52958
53102
  const runtimes = new Map;
52959
53103
  const sigintHandler = () => {
@@ -52965,8 +53109,8 @@ async function runModels(sessionPath, opts = {}) {
52965
53109
  process.on("SIGINT", sigintHandler);
52966
53110
  const completionPromises = [];
52967
53111
  for (const [anonId, entry] of Object.entries(manifest.models)) {
52968
- const outputPath = join30(sessionPath, `response-${anonId}.md`);
52969
- const errorLogPath = join30(sessionPath, "errors", `${anonId}.log`);
53112
+ const outputPath = join31(sessionPath, `response-${anonId}.md`);
53113
+ const errorLogPath = join31(sessionPath, "errors", `${anonId}.log`);
52970
53114
  const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
52971
53115
  const args = [
52972
53116
  "--model",
@@ -53192,7 +53336,7 @@ async function runModels(sessionPath, opts = {}) {
53192
53336
  opts.onStatusChange?.(id, statusCache.models[id]);
53193
53337
  const stopped = await terminateChildTree(proc);
53194
53338
  if (!stopped) {
53195
- persistErrorLog(rt?.errorLogPath ?? join30(sessionPath, "errors", `${id}.log`), "TIMEOUT: child survived SIGKILL \u2014 it may still be running and billing", stderr, stdoutTail);
53339
+ persistErrorLog(rt?.errorLogPath ?? join31(sessionPath, "errors", `${id}.log`), "TIMEOUT: child survived SIGKILL \u2014 it may still be running and billing", stderr, stdoutTail);
53196
53340
  }
53197
53341
  };
53198
53342
  const allDone = Promise.all(completionPromises);
@@ -53251,23 +53395,23 @@ async function judgeResponses(sessionPath, opts = {}) {
53251
53395
  const responses = {};
53252
53396
  for (const file2 of responseFiles) {
53253
53397
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
53254
- responses[id] = readFileSync20(join30(sessionPath, file2), "utf-8");
53398
+ responses[id] = readFileSync20(join31(sessionPath, file2), "utf-8");
53255
53399
  }
53256
- const input = readFileSync20(join30(sessionPath, "input.md"), "utf-8");
53400
+ const input = readFileSync20(join31(sessionPath, "input.md"), "utf-8");
53257
53401
  const judgePrompt = buildJudgePrompt(input, responses);
53258
- writeFileSync13(join30(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
53402
+ writeFileSync13(join31(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
53259
53403
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
53260
- const judgePath = join30(sessionPath, "judging");
53261
- mkdirSync13(judgePath, { recursive: true });
53404
+ const judgePath = join31(sessionPath, "judging");
53405
+ mkdirSync14(judgePath, { recursive: true });
53262
53406
  setupSession(judgePath, judgeModels, judgePrompt);
53263
53407
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
53264
53408
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
53265
53409
  const verdict = aggregateVerdict(votes, Object.keys(responses));
53266
- writeFileSync13(join30(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
53410
+ writeFileSync13(join31(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
53267
53411
  return verdict;
53268
53412
  }
53269
53413
  function getStatus(sessionPath) {
53270
- return JSON.parse(readFileSync20(join30(sessionPath, "status.json"), "utf-8"));
53414
+ return JSON.parse(readFileSync20(join31(sessionPath, "status.json"), "utf-8"));
53271
53415
  }
53272
53416
  function fisherYatesShuffle(arr) {
53273
53417
  for (let i = arr.length - 1;i > 0; i--) {
@@ -53277,7 +53421,7 @@ function fisherYatesShuffle(arr) {
53277
53421
  return arr;
53278
53422
  }
53279
53423
  function getDefaultJudgeModels(sessionPath) {
53280
- const manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
53424
+ const manifest = JSON.parse(readFileSync20(join31(sessionPath, "manifest.json"), "utf-8"));
53281
53425
  return Object.values(manifest.models).map((e) => e.model);
53282
53426
  }
53283
53427
  function buildJudgePrompt(input, responses) {
@@ -53340,7 +53484,7 @@ function parseJudgeVotes(judgePath, responseIds) {
53340
53484
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
53341
53485
  let content;
53342
53486
  try {
53343
- content = readFileSync20(join30(judgePath, file2), "utf-8");
53487
+ content = readFileSync20(join31(judgePath, file2), "utf-8");
53344
53488
  } catch {
53345
53489
  continue;
53346
53490
  }
@@ -53392,7 +53536,7 @@ function aggregateVerdict(votes, responseIds) {
53392
53536
  function formatVerdict(verdict, sessionPath) {
53393
53537
  let manifest = null;
53394
53538
  try {
53395
- manifest = JSON.parse(readFileSync20(join30(sessionPath, "manifest.json"), "utf-8"));
53539
+ manifest = JSON.parse(readFileSync20(join31(sessionPath, "manifest.json"), "utf-8"));
53396
53540
  } catch {}
53397
53541
  let output = `# Team Verdict
53398
53542
 
@@ -53453,9 +53597,9 @@ __export(exports_mcp_server, {
53453
53597
  parseAnthropicSse: () => parseAnthropicSse,
53454
53598
  formatTeamResult: () => formatTeamResult
53455
53599
  });
53456
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync21, readdirSync as readdirSync4, writeFileSync as writeFileSync14 } from "fs";
53600
+ import { existsSync as existsSync22, mkdirSync as mkdirSync15, readFileSync as readFileSync21, readdirSync as readdirSync4, writeFileSync as writeFileSync14 } from "fs";
53457
53601
  import { homedir as homedir29 } from "os";
53458
- import { dirname as dirname9, join as join31, resolve as resolve4 } from "path";
53602
+ import { dirname as dirname9, join as join32, resolve as resolve4 } from "path";
53459
53603
  import { fileURLToPath } from "url";
53460
53604
  async function loadAllModels(forceRefresh = false) {
53461
53605
  if (!forceRefresh && existsSync22(ALL_MODELS_CACHE_PATH2)) {
@@ -53474,7 +53618,7 @@ async function loadAllModels(forceRefresh = false) {
53474
53618
  throw new Error(`API returned ${response.status}`);
53475
53619
  const data = await response.json();
53476
53620
  const models = data.data || [];
53477
- mkdirSync14(CLAUDISH_CACHE_DIR, { recursive: true });
53621
+ mkdirSync15(CLAUDISH_CACHE_DIR, { recursive: true });
53478
53622
  writeFileSync14(ALL_MODELS_CACHE_PATH2, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
53479
53623
  return models;
53480
53624
  } catch {
@@ -54194,16 +54338,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
54194
54338
  const sp = session_path;
54195
54339
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
54196
54340
  try {
54197
- sessionData[file2] = readFileSync21(join31(sp, file2), "utf-8");
54341
+ sessionData[file2] = readFileSync21(join32(sp, file2), "utf-8");
54198
54342
  } catch {}
54199
54343
  }
54200
54344
  try {
54201
- const errorDir = join31(sp, "errors");
54345
+ const errorDir = join32(sp, "errors");
54202
54346
  if (existsSync22(errorDir)) {
54203
54347
  for (const f of readdirSync4(errorDir)) {
54204
54348
  if (f.endsWith(".log")) {
54205
54349
  try {
54206
- sessionData[`errors/${f}`] = readFileSync21(join31(errorDir, f), "utf-8");
54350
+ sessionData[`errors/${f}`] = readFileSync21(join32(errorDir, f), "utf-8");
54207
54351
  } catch {}
54208
54352
  }
54209
54353
  }
@@ -54213,7 +54357,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
54213
54357
  for (const f of readdirSync4(sp)) {
54214
54358
  if (f.startsWith("response-") && f.endsWith(".md")) {
54215
54359
  try {
54216
- const content = readFileSync21(join31(sp, f), "utf-8");
54360
+ const content = readFileSync21(join32(sp, f), "utf-8");
54217
54361
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
54218
54362
  } catch {}
54219
54363
  }
@@ -54222,7 +54366,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
54222
54366
  }
54223
54367
  let version2 = "unknown";
54224
54368
  try {
54225
- const pkgPath = join31(__dirname2, "../package.json");
54369
+ const pkgPath = join32(__dirname2, "../package.json");
54226
54370
  if (existsSync22(pkgPath)) {
54227
54371
  version2 = JSON.parse(readFileSync21(pkgPath, "utf-8")).version;
54228
54372
  }
@@ -54643,8 +54787,8 @@ var init_mcp_server = __esm(() => {
54643
54787
  import_dotenv2.config({ quiet: true });
54644
54788
  __filename2 = fileURLToPath(import.meta.url);
54645
54789
  __dirname2 = dirname9(__filename2);
54646
- CLAUDISH_CACHE_DIR = join31(homedir29(), ".claudish");
54647
- ALL_MODELS_CACHE_PATH2 = join31(CLAUDISH_CACHE_DIR, "all-models.json");
54790
+ CLAUDISH_CACHE_DIR = join32(homedir29(), ".claudish");
54791
+ ALL_MODELS_CACHE_PATH2 = join32(CLAUDISH_CACHE_DIR, "all-models.json");
54648
54792
  NEXT_STEP = {
54649
54793
  nonzero_exit: "read the evidence log, then retry or drop the model",
54650
54794
  timeout: "raise `timeout`, or pick a faster model",
@@ -54968,7 +55112,7 @@ import { spawn as spawn3 } from "child_process";
54968
55112
  import { execSync } from "child_process";
54969
55113
  import { existsSync as existsSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "fs";
54970
55114
  import { connect as netConnect } from "net";
54971
- import { dirname as dirname10, join as join32 } from "path";
55115
+ import { dirname as dirname10, join as join33 } from "path";
54972
55116
  import { setTimeout as wait } from "timers/promises";
54973
55117
  import { fileURLToPath as fileURLToPath2 } from "url";
54974
55118
  function resolveRouteInfo(modelId) {
@@ -55062,17 +55206,17 @@ function buildPaneHeader(model, prompt, bg) {
55062
55206
  function findMagmuxBinary() {
55063
55207
  const thisFile = fileURLToPath2(import.meta.url);
55064
55208
  const thisDir = dirname10(thisFile);
55065
- const pkgRoot = join32(thisDir, "..");
55209
+ const pkgRoot = join33(thisDir, "..");
55066
55210
  const platform2 = process.platform;
55067
55211
  const arch = process.arch;
55068
- const bundledMagmux = join32(pkgRoot, "native", `magmux-${platform2}-${arch}`);
55212
+ const bundledMagmux = join33(pkgRoot, "native", `magmux-${platform2}-${arch}`);
55069
55213
  if (existsSync25(bundledMagmux))
55070
55214
  return bundledMagmux;
55071
55215
  try {
55072
55216
  const pkgName = `@claudish/magmux-${platform2}-${arch}`;
55073
55217
  let searchDir = pkgRoot;
55074
55218
  for (let i = 0;i < 5; i++) {
55075
- const candidate = join32(searchDir, "node_modules", pkgName, "bin", "magmux");
55219
+ const candidate = join33(searchDir, "node_modules", pkgName, "bin", "magmux");
55076
55220
  if (existsSync25(candidate))
55077
55221
  return candidate;
55078
55222
  const parent = dirname10(searchDir);
@@ -55184,9 +55328,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
55184
55328
  const keep = opts?.keep ?? false;
55185
55329
  const manifest = setupSession(sessionPath, models, input);
55186
55330
  const startedAt = new Date().toISOString();
55187
- const gridfilePath = join32(sessionPath, "gridfile.txt");
55188
- const prompt = readFileSync24(join32(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
55189
- const rawPrompt = readFileSync24(join32(sessionPath, "input.md"), "utf-8");
55331
+ const gridfilePath = join33(sessionPath, "gridfile.txt");
55332
+ const prompt = readFileSync24(join33(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
55333
+ const rawPrompt = readFileSync24(join33(sessionPath, "input.md"), "utf-8");
55190
55334
  const usedBannerColors = new Set;
55191
55335
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
55192
55336
  const model = manifest.models[anonId].model;
@@ -55217,7 +55361,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
55217
55361
  });
55218
55362
  const [{ results }] = await Promise.all([subscription, procExit]);
55219
55363
  const status = buildTeamStatus(manifest, startedAt, results?.panes ?? null);
55220
- const statusPath = join32(sessionPath, "status.json");
55364
+ const statusPath = join33(sessionPath, "status.json");
55221
55365
  writeFileSync16(statusPath, JSON.stringify(status, null, 2), "utf-8");
55222
55366
  return status;
55223
55367
  }
@@ -55243,7 +55387,7 @@ __export(exports_team_cli, {
55243
55387
  teamCommand: () => teamCommand
55244
55388
  });
55245
55389
  import { readFileSync as readFileSync25 } from "fs";
55246
- import { join as join33 } from "path";
55390
+ import { join as join34 } from "path";
55247
55391
  function getFlag(args, flag) {
55248
55392
  const idx = args.indexOf(flag);
55249
55393
  if (idx === -1 || idx + 1 >= args.length)
@@ -55366,7 +55510,7 @@ async function teamCommand(args) {
55366
55510
  }
55367
55511
  case "judge": {
55368
55512
  await judgeResponses(sessionPath, { judges });
55369
- console.log(readFileSync25(join33(sessionPath, "verdict.md"), "utf-8"));
55513
+ console.log(readFileSync25(join34(sessionPath, "verdict.md"), "utf-8"));
55370
55514
  break;
55371
55515
  }
55372
55516
  case "run-and-judge": {
@@ -55384,7 +55528,7 @@ async function teamCommand(args) {
55384
55528
  });
55385
55529
  printStatus(status);
55386
55530
  await judgeResponses(sessionPath, { judges });
55387
- console.log(readFileSync25(join33(sessionPath, "verdict.md"), "utf-8"));
55531
+ console.log(readFileSync25(join34(sessionPath, "verdict.md"), "utf-8"));
55388
55532
  break;
55389
55533
  }
55390
55534
  case "status": {
@@ -67909,7 +68053,7 @@ var init_dist16 = __esm(() => {
67909
68053
  import { spawnSync as spawnSync3 } from "child_process";
67910
68054
  import { existsSync as existsSync26, unlinkSync as unlinkSync7 } from "fs";
67911
68055
  import { homedir as homedir30 } from "os";
67912
- import { join as join34 } from "path";
68056
+ import { join as join35 } from "path";
67913
68057
  async function defaultSuggestModel() {
67914
68058
  try {
67915
68059
  const tok = readSharedAntigravityToken();
@@ -68030,7 +68174,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
68030
68174
  async logout(deps) {
68031
68175
  deleteSharedAntigravityToken(deps);
68032
68176
  try {
68033
- const tokenFile = join34(homedir30(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
68177
+ const tokenFile = join35(homedir30(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
68034
68178
  if (existsSync26(tokenFile))
68035
68179
  unlinkSync7(tokenFile);
68036
68180
  } catch {}
@@ -68401,7 +68545,9 @@ var init_config2 = __esm(() => {
68401
68545
  CLAUDISH_SUMMARIZE_TOOLS: "CLAUDISH_SUMMARIZE_TOOLS",
68402
68546
  CLAUDISH_DIAG_MODE: "CLAUDISH_DIAG_MODE",
68403
68547
  CLAUDISH_DEBUG: "CLAUDISH_DEBUG",
68404
- CLAUDISH_ANTHROPIC_API_BILLING: "CLAUDISH_ANTHROPIC_API_BILLING"
68548
+ CLAUDISH_ANTHROPIC_API_BILLING: "CLAUDISH_ANTHROPIC_API_BILLING",
68549
+ CLAUDISH_CLASSIFIER_PROVIDER: "CLAUDISH_CLASSIFIER_PROVIDER",
68550
+ CLAUDISH_CLASSIFIER_MODEL: "CLAUDISH_CLASSIFIER_MODEL"
68405
68551
  };
68406
68552
  OPENROUTER_HEADERS = {
68407
68553
  "HTTP-Referer": "https://claudish.com",
@@ -71785,20 +71931,20 @@ __export(exports_cli, {
71785
71931
  import {
71786
71932
  copyFileSync as copyFileSync2,
71787
71933
  existsSync as existsSync27,
71788
- mkdirSync as mkdirSync15,
71934
+ mkdirSync as mkdirSync16,
71789
71935
  readFileSync as readFileSync27,
71790
71936
  readdirSync as readdirSync5,
71791
71937
  unlinkSync as unlinkSync8,
71792
71938
  writeFileSync as writeFileSync18
71793
71939
  } from "fs";
71794
71940
  import { homedir as homedir31 } from "os";
71795
- import { dirname as dirname11, join as join35 } from "path";
71941
+ import { dirname as dirname11, join as join36 } from "path";
71796
71942
  import { fileURLToPath as fileURLToPath3 } from "url";
71797
71943
  function getVersion3() {
71798
71944
  return VERSION;
71799
71945
  }
71800
71946
  function clearAllModelCaches() {
71801
- const cacheDir = join35(homedir31(), ".claudish");
71947
+ const cacheDir = join36(homedir31(), ".claudish");
71802
71948
  if (!existsSync27(cacheDir))
71803
71949
  return;
71804
71950
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
@@ -71807,7 +71953,7 @@ function clearAllModelCaches() {
71807
71953
  const files = readdirSync5(cacheDir);
71808
71954
  for (const file2 of files) {
71809
71955
  if (cachePatterns.includes(file2)) {
71810
- unlinkSync8(join35(cacheDir, file2));
71956
+ unlinkSync8(join36(cacheDir, file2));
71811
71957
  cleared++;
71812
71958
  }
71813
71959
  }
@@ -72013,6 +72159,20 @@ async function parseArgs(args) {
72013
72159
  config3.defaultProvider = dpArg;
72014
72160
  } else if (arg === "--anthropic-api-billing") {
72015
72161
  config3.anthropicApiBilling = true;
72162
+ } else if (arg === "--classifier-model") {
72163
+ const cmArg = args[++i];
72164
+ if (!cmArg) {
72165
+ console.error("--classifier-model requires a model id");
72166
+ process.exit(1);
72167
+ }
72168
+ config3.classifierModel = cmArg;
72169
+ } else if (arg === "--classifier-provider") {
72170
+ const cpArg = args[++i];
72171
+ if (!cpArg) {
72172
+ console.error("--classifier-provider requires a provider name (e.g. anthropic)");
72173
+ process.exit(1);
72174
+ }
72175
+ config3.classifierProvider = cpArg;
72016
72176
  } else if (arg === "--op-env" || arg.startsWith("--op-env=")) {
72017
72177
  const v = arg.startsWith("--op-env=") ? arg.slice("--op-env=".length) : args[++i];
72018
72178
  if (!v) {
@@ -72223,14 +72383,14 @@ Usage: claudish --models --provider <slug>`);
72223
72383
  });
72224
72384
  config3.resolvedDefaultProvider = resolved;
72225
72385
  if (resolved.legacyAutoPromoted && !config3.quiet) {
72226
- const markerFile = join35(homedir31(), ".claudish", ".legacy-litellm-hint-shown");
72386
+ const markerFile = join36(homedir31(), ".claudish", ".legacy-litellm-hint-shown");
72227
72387
  if (!existsSync27(markerFile)) {
72228
72388
  const hint = buildLegacyHint(resolved);
72229
72389
  if (hint) {
72230
72390
  console.error(hint);
72231
72391
  }
72232
72392
  try {
72233
- mkdirSync15(dirname11(markerFile), { recursive: true });
72393
+ mkdirSync16(dirname11(markerFile), { recursive: true });
72234
72394
  writeFileSync18(markerFile, new Date().toISOString(), "utf-8");
72235
72395
  } catch {}
72236
72396
  }
@@ -73333,7 +73493,7 @@ ${h("MORE INFO")}
73333
73493
  }
73334
73494
  function printAIAgentGuide() {
73335
73495
  try {
73336
- const guidePath = join35(__dirname3, "../AI_AGENT_GUIDE.md");
73496
+ const guidePath = join36(__dirname3, "../AI_AGENT_GUIDE.md");
73337
73497
  const guideContent = readFileSync27(guidePath, "utf-8");
73338
73498
  console.log(guideContent);
73339
73499
  } catch (error46) {
@@ -73350,10 +73510,10 @@ async function initializeClaudishSkill() {
73350
73510
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
73351
73511
  `);
73352
73512
  const cwd = process.cwd();
73353
- const claudeDir = join35(cwd, ".claude");
73354
- const skillsDir = join35(claudeDir, "skills");
73355
- const claudishSkillDir = join35(skillsDir, "claudish-usage");
73356
- const skillFile = join35(claudishSkillDir, "SKILL.md");
73513
+ const claudeDir = join36(cwd, ".claude");
73514
+ const skillsDir = join36(claudeDir, "skills");
73515
+ const claudishSkillDir = join36(skillsDir, "claudish-usage");
73516
+ const skillFile = join36(claudishSkillDir, "SKILL.md");
73357
73517
  if (existsSync27(skillFile)) {
73358
73518
  console.log("\u2705 Claudish skill already installed at:");
73359
73519
  console.log(` ${skillFile}
@@ -73361,7 +73521,7 @@ async function initializeClaudishSkill() {
73361
73521
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
73362
73522
  return;
73363
73523
  }
73364
- const sourceSkillPath = join35(__dirname3, "../skills/claudish-usage/SKILL.md");
73524
+ const sourceSkillPath = join36(__dirname3, "../skills/claudish-usage/SKILL.md");
73365
73525
  if (!existsSync27(sourceSkillPath)) {
73366
73526
  console.error("\u274C Error: Claudish skill file not found in installation.");
73367
73527
  console.error(` Expected at: ${sourceSkillPath}`);
@@ -73372,15 +73532,15 @@ async function initializeClaudishSkill() {
73372
73532
  }
73373
73533
  try {
73374
73534
  if (!existsSync27(claudeDir)) {
73375
- mkdirSync15(claudeDir, { recursive: true });
73535
+ mkdirSync16(claudeDir, { recursive: true });
73376
73536
  console.log("\uD83D\uDCC1 Created .claude/ directory");
73377
73537
  }
73378
73538
  if (!existsSync27(skillsDir)) {
73379
- mkdirSync15(skillsDir, { recursive: true });
73539
+ mkdirSync16(skillsDir, { recursive: true });
73380
73540
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
73381
73541
  }
73382
73542
  if (!existsSync27(claudishSkillDir)) {
73383
- mkdirSync15(claudishSkillDir, { recursive: true });
73543
+ mkdirSync16(claudishSkillDir, { recursive: true });
73384
73544
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
73385
73545
  }
73386
73546
  copyFileSync2(sourceSkillPath, skillFile);
@@ -73467,24 +73627,24 @@ __export(exports_update_checker, {
73467
73627
  clearCache: () => clearCache,
73468
73628
  checkForUpdates: () => checkForUpdates
73469
73629
  });
73470
- import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync28, unlinkSync as unlinkSync9, writeFileSync as writeFileSync19 } from "fs";
73630
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync28, unlinkSync as unlinkSync9, writeFileSync as writeFileSync19 } from "fs";
73471
73631
  import { homedir as homedir32, platform as platform2, tmpdir } from "os";
73472
- import { join as join36 } from "path";
73632
+ import { join as join37 } from "path";
73473
73633
  function getCacheFilePath() {
73474
73634
  let cacheDir;
73475
73635
  if (isWindows) {
73476
- const localAppData = process.env.LOCALAPPDATA || join36(homedir32(), "AppData", "Local");
73477
- cacheDir = join36(localAppData, "claudish");
73636
+ const localAppData = process.env.LOCALAPPDATA || join37(homedir32(), "AppData", "Local");
73637
+ cacheDir = join37(localAppData, "claudish");
73478
73638
  } else {
73479
- cacheDir = join36(homedir32(), ".cache", "claudish");
73639
+ cacheDir = join37(homedir32(), ".cache", "claudish");
73480
73640
  }
73481
73641
  try {
73482
73642
  if (!existsSync28(cacheDir)) {
73483
- mkdirSync16(cacheDir, { recursive: true });
73643
+ mkdirSync17(cacheDir, { recursive: true });
73484
73644
  }
73485
- return join36(cacheDir, "update-check.json");
73645
+ return join37(cacheDir, "update-check.json");
73486
73646
  } catch {
73487
- return join36(tmpdir(), "claudish-update-check.json");
73647
+ return join37(tmpdir(), "claudish-update-check.json");
73488
73648
  }
73489
73649
  }
73490
73650
  function readCache() {
@@ -74401,9 +74561,9 @@ var init_local_liveness = __esm(() => {
74401
74561
  });
74402
74562
 
74403
74563
  // src/providers/probe-catalog.ts
74404
- import { existsSync as existsSync29, mkdirSync as mkdirSync17, readFileSync as readFileSync29, writeFileSync as writeFileSync20 } from "fs";
74564
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync29, writeFileSync as writeFileSync20 } from "fs";
74405
74565
  import { homedir as homedir33 } from "os";
74406
- import { dirname as dirname12, join as join37 } from "path";
74566
+ import { dirname as dirname12, join as join38 } from "path";
74407
74567
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
74408
74568
  if (!existsSync29(path2))
74409
74569
  return null;
@@ -74418,7 +74578,7 @@ function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
74418
74578
  return raw2;
74419
74579
  }
74420
74580
  function writeProbeModelsCache(data, path2 = PROBE_MODELS_CACHE_PATH) {
74421
- mkdirSync17(dirname12(path2), { recursive: true });
74581
+ mkdirSync18(dirname12(path2), { recursive: true });
74422
74582
  writeFileSync20(path2, JSON.stringify(data), "utf-8");
74423
74583
  }
74424
74584
  function isCacheFresh(data, ttlMs = CACHE_TTL_MS4) {
@@ -74538,7 +74698,7 @@ function isValidResponse(raw2) {
74538
74698
  var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
74539
74699
  var init_probe_catalog = __esm(() => {
74540
74700
  CACHE_TTL_MS4 = 60 * 60 * 1000;
74541
- PROBE_MODELS_CACHE_PATH = join37(homedir33(), ".claudish", "probe-models.json");
74701
+ PROBE_MODELS_CACHE_PATH = join38(homedir33(), ".claudish", "probe-models.json");
74542
74702
  });
74543
74703
 
74544
74704
  // src/tui/constants.ts
@@ -80870,13 +81030,16 @@ var init_terminal_isolation = __esm(() => {
80870
81030
  // src/claude-runner.ts
80871
81031
  var exports_claude_runner = {};
80872
81032
  __export(exports_claude_runner, {
81033
+ shouldHideIncidentalAnthropicKey: () => shouldHideIncidentalAnthropicKey,
80873
81034
  runClaudeWithProxy: () => runClaudeWithProxy,
80874
81035
  resolveLocalContextWindow: () => resolveLocalContextWindow,
80875
81036
  resolveContextWindowEnv: () => resolveContextWindowEnv,
80876
81037
  managedSettingsForcesClaudeAi: () => managedSettingsForcesClaudeAi,
80877
81038
  isProxyAuthMode: () => isProxyAuthMode,
80878
81039
  initializeTokenFile: () => initializeTokenFile,
81040
+ hasResolvableAnthropicAuth: () => hasResolvableAnthropicAuth,
80879
81041
  discoverUserStatusLineCommand: () => discoverUserStatusLineCommand,
81042
+ defaultKeychainAnthropicProbe: () => defaultKeychainAnthropicProbe,
80880
81043
  createTempSettingsFile: () => createTempSettingsFile,
80881
81044
  createStatusLineScript: () => createStatusLineScript,
80882
81045
  computeMainThreadContextWindow: () => computeMainThreadContextWindow,
@@ -80889,11 +81052,11 @@ __export(exports_claude_runner, {
80889
81052
  MIN_AUTO_COMPACT_WINDOW: () => MIN_AUTO_COMPACT_WINDOW,
80890
81053
  CLAUDE_CODE_DEFAULT_MAX_CONTEXT: () => CLAUDE_CODE_DEFAULT_MAX_CONTEXT
80891
81054
  });
80892
- import { spawn as spawn5 } from "child_process";
81055
+ import { spawn as spawn5, spawnSync as spawnSync5 } from "child_process";
80893
81056
  import {
80894
81057
  closeSync as closeSync5,
80895
81058
  existsSync as existsSync30,
80896
- mkdirSync as mkdirSync18,
81059
+ mkdirSync as mkdirSync19,
80897
81060
  openSync as openSync5,
80898
81061
  readFileSync as readFileSync30,
80899
81062
  readdirSync as readdirSync6,
@@ -80902,7 +81065,7 @@ import {
80902
81065
  writeFileSync as writeFileSync21
80903
81066
  } from "fs";
80904
81067
  import { homedir as homedir34, tmpdir as tmpdir2 } from "os";
80905
- import { dirname as dirname13, join as join38 } from "path";
81068
+ import { dirname as dirname13, join as join39 } from "path";
80906
81069
  import { isatty } from "tty";
80907
81070
  function releaseTerminalIsolation() {
80908
81071
  if (!restoreTerminal)
@@ -80920,10 +81083,10 @@ function hasNativeAnthropicMapping(config3) {
80920
81083
  ];
80921
81084
  return models.some((m) => m && parseModelSpec(m).provider === "native-anthropic");
80922
81085
  }
80923
- function wantsAnthropicApiBilling(config3) {
81086
+ function wantsAnthropicApiBilling(config3, env = process.env) {
80924
81087
  if (config3.anthropicApiBilling)
80925
81088
  return true;
80926
- const raw2 = process.env[ENV.CLAUDISH_ANTHROPIC_API_BILLING];
81089
+ const raw2 = env[ENV.CLAUDISH_ANTHROPIC_API_BILLING];
80927
81090
  if (raw2 !== undefined && raw2 !== "" && raw2 !== "0" && raw2.toLowerCase() !== "false")
80928
81091
  return true;
80929
81092
  try {
@@ -80932,12 +81095,32 @@ function wantsAnthropicApiBilling(config3) {
80932
81095
  return false;
80933
81096
  }
80934
81097
  }
81098
+ function shouldHideIncidentalAnthropicKey(config3, env = process.env) {
81099
+ if (!hasNativeAnthropicMapping(config3))
81100
+ return false;
81101
+ if (!env.ANTHROPIC_API_KEY)
81102
+ return false;
81103
+ return !wantsAnthropicApiBilling(config3, env);
81104
+ }
81105
+ function hasResolvableAnthropicAuth(deps = {}) {
81106
+ const env = deps.env ?? process.env;
81107
+ const fileExists = deps.fileExists ?? existsSync30;
81108
+ const keychainProbe = deps.keychainProbe ?? defaultKeychainAnthropicProbe;
81109
+ if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_AUTH_TOKEN)
81110
+ return true;
81111
+ if (fileExists(join39(homedir34(), ".claude", ".credentials.json")))
81112
+ return true;
81113
+ return keychainProbe();
81114
+ }
81115
+ function shouldPreserveNativeAuth(config3) {
81116
+ return hasNativeAnthropicMapping(config3) || classifierPassthroughEnabled(config3) && hasResolvableAnthropicAuth();
81117
+ }
80935
81118
  function isProxyAuthMode(config3) {
80936
- return !config3.monitor && !hasNativeAnthropicMapping(config3);
81119
+ return !config3.monitor && !shouldPreserveNativeAuth(config3);
80937
81120
  }
80938
81121
  function managedSettingsPath() {
80939
81122
  if (isWindows2()) {
80940
- return join38(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
81123
+ return join39(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
80941
81124
  }
80942
81125
  if (process.platform === "darwin") {
80943
81126
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
@@ -80958,9 +81141,9 @@ function isWindows2() {
80958
81141
  }
80959
81142
  function createStatusLineScript(tokenFilePath) {
80960
81143
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
80961
- const claudishDir = join38(homeDir, ".claudish");
81144
+ const claudishDir = join39(homeDir, ".claudish");
80962
81145
  const timestamp = Date.now();
80963
- const scriptPath = join38(claudishDir, `status-${timestamp}.js`);
81146
+ const scriptPath = join39(claudishDir, `status-${timestamp}.js`);
80964
81147
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
80965
81148
  const script = `
80966
81149
  const fs = require('fs');
@@ -81092,7 +81275,7 @@ process.stdin.on('end', () => {
81092
81275
  }
81093
81276
  function initializeTokenFile(tokenFilePath) {
81094
81277
  try {
81095
- mkdirSync18(dirname13(tokenFilePath), { recursive: true });
81278
+ mkdirSync19(dirname13(tokenFilePath), { recursive: true });
81096
81279
  writeFileSync21(tokenFilePath, JSON.stringify({
81097
81280
  input_tokens: 0,
81098
81281
  output_tokens: 0,
@@ -81124,7 +81307,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
81124
81307
  if (!name.startsWith("tokens-") || !name.endsWith(".json"))
81125
81308
  continue;
81126
81309
  scanned++;
81127
- const full = join38(dir, name);
81310
+ const full = join39(dir, name);
81128
81311
  try {
81129
81312
  if (statSync5(full).mtimeMs >= cutoff)
81130
81313
  continue;
@@ -81153,9 +81336,9 @@ function parseSettingsArgSafe(value) {
81153
81336
  }
81154
81337
  function userSettingsFileCandidates(cwd) {
81155
81338
  return [
81156
- join38(homedir34(), ".claude", "settings.json"),
81157
- join38(cwd, ".claude", "settings.json"),
81158
- join38(cwd, ".claude", "settings.local.json")
81339
+ join39(homedir34(), ".claude", "settings.json"),
81340
+ join39(cwd, ".claude", "settings.json"),
81341
+ join39(cwd, ".claude", "settings.local.json")
81159
81342
  ];
81160
81343
  }
81161
81344
  function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
@@ -81196,13 +81379,13 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
81196
81379
  }
81197
81380
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
81198
81381
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
81199
- const claudishDir = join38(homeDir, ".claudish");
81382
+ const claudishDir = join39(homeDir, ".claudish");
81200
81383
  try {
81201
- mkdirSync18(claudishDir, { recursive: true });
81384
+ mkdirSync19(claudishDir, { recursive: true });
81202
81385
  } catch {}
81203
81386
  const timestamp = Date.now();
81204
- const tempPath = join38(claudishDir, `settings-${timestamp}.json`);
81205
- const tokenFilePath = join38(claudishDir, `tokens-${port}.json`);
81387
+ const tempPath = join39(claudishDir, `settings-${timestamp}.json`);
81388
+ const tokenFilePath = join39(claudishDir, `tokens-${port}.json`);
81206
81389
  cleanupStaleTokenFiles(claudishDir);
81207
81390
  initializeTokenFile(tokenFilePath);
81208
81391
  let statusCommand;
@@ -81398,12 +81581,15 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
81398
81581
  env[ENV.ANTHROPIC_MODEL] = modelId;
81399
81582
  env[ENV.ANTHROPIC_SMALL_FAST_MODEL] = modelId;
81400
81583
  }
81401
- if (hasNativeAnthropicMapping(config3)) {
81402
- if (process.env.ANTHROPIC_API_KEY && !wantsAnthropicApiBilling(config3)) {
81584
+ if (shouldPreserveNativeAuth(config3)) {
81585
+ if (shouldHideIncidentalAnthropicKey(config3)) {
81403
81586
  delete env.ANTHROPIC_API_KEY;
81404
81587
  hidAnthropicApiKey = true;
81405
81588
  }
81406
81589
  } else {
81590
+ if (classifierPassthroughEnabled(config3)) {
81591
+ console.error("[claudish] classifier passthrough enabled but no Anthropic credentials detected \u2014 " + "classifier requests will fail to authenticate against api.anthropic.com. " + "Map a role to a native Claude model (e.g. --model-sonnet claude-sonnet-5) or set ANTHROPIC_API_KEY.");
81592
+ }
81407
81593
  env.ANTHROPIC_API_KEY = "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx";
81408
81594
  env.ANTHROPIC_AUTH_TOKEN = "placeholder-token-not-used-proxy-handles-auth";
81409
81595
  const realWindow = await computeMainThreadContextWindow(config3);
@@ -81453,7 +81639,7 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
81453
81639
  console.error(`
81454
81640
  Or set CLAUDE_PATH to your custom installation:`);
81455
81641
  const home = homedir34();
81456
- const localPath = isWindows2() ? join38(home, ".claude", "local", "claude.exe") : join38(home, ".claude", "local", "claude");
81642
+ const localPath = isWindows2() ? join39(home, ".claude", "local", "claude.exe") : join39(home, ".claude", "local", "claude");
81457
81643
  console.error(` export CLAUDE_PATH=${localPath}`);
81458
81644
  process.exit(1);
81459
81645
  }
@@ -81538,15 +81724,15 @@ async function findClaudeBinary() {
81538
81724
  }
81539
81725
  }
81540
81726
  const home = homedir34();
81541
- const localPath = isWindows3 ? join38(home, ".claude", "local", "claude.exe") : join38(home, ".claude", "local", "claude");
81727
+ const localPath = isWindows3 ? join39(home, ".claude", "local", "claude.exe") : join39(home, ".claude", "local", "claude");
81542
81728
  if (existsSync30(localPath)) {
81543
81729
  return localPath;
81544
81730
  }
81545
81731
  if (isWindows3) {
81546
81732
  const windowsPaths = [
81547
- join38(home, "AppData", "Roaming", "npm", "claude.cmd"),
81548
- join38(home, ".npm-global", "claude.cmd"),
81549
- join38(home, "node_modules", ".bin", "claude.cmd")
81733
+ join39(home, "AppData", "Roaming", "npm", "claude.cmd"),
81734
+ join39(home, ".npm-global", "claude.cmd"),
81735
+ join39(home, "node_modules", ".bin", "claude.cmd")
81550
81736
  ];
81551
81737
  for (const path2 of windowsPaths) {
81552
81738
  if (existsSync30(path2)) {
@@ -81557,11 +81743,11 @@ async function findClaudeBinary() {
81557
81743
  const commonPaths = [
81558
81744
  "/usr/local/bin/claude",
81559
81745
  "/opt/homebrew/bin/claude",
81560
- join38(home, ".npm-global/bin/claude"),
81561
- join38(home, ".local/bin/claude"),
81562
- join38(home, "node_modules/.bin/claude"),
81746
+ join39(home, ".npm-global/bin/claude"),
81747
+ join39(home, ".local/bin/claude"),
81748
+ join39(home, "node_modules/.bin/claude"),
81563
81749
  "/data/data/com.termux/files/usr/bin/claude",
81564
- join38(home, "../usr/bin/claude")
81750
+ join39(home, "../usr/bin/claude")
81565
81751
  ];
81566
81752
  for (const path2 of commonPaths) {
81567
81753
  if (existsSync30(path2)) {
@@ -81601,7 +81787,21 @@ async function checkClaudeInstalled() {
81601
81787
  const binary = await findClaudeBinary();
81602
81788
  return binary !== null;
81603
81789
  }
81604
- var restoreTerminal = null, STALE_TOKEN_FILE_MS, MAX_TOKEN_FILES_SCANNED = 4000, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, USER_STATUS_LINE_TIMEOUT_SECONDS = 3, MIN_AUTO_COMPACT_WINDOW = 200000;
81790
+ var restoreTerminal = null, macosKeychainAnthropicResult, defaultKeychainAnthropicProbe = () => {
81791
+ if (process.platform !== "darwin")
81792
+ return false;
81793
+ if (macosKeychainAnthropicResult !== undefined)
81794
+ return macosKeychainAnthropicResult;
81795
+ try {
81796
+ const res = spawnSync5("security", ["find-generic-password", "-s", "Claude Code-credentials"], {
81797
+ stdio: "ignore"
81798
+ });
81799
+ macosKeychainAnthropicResult = !res.error && res.status === 0;
81800
+ } catch {
81801
+ macosKeychainAnthropicResult = false;
81802
+ }
81803
+ return macosKeychainAnthropicResult;
81804
+ }, STALE_TOKEN_FILE_MS, MAX_TOKEN_FILES_SCANNED = 4000, CLAUDE_CODE_DEFAULT_MAX_CONTEXT = 200000, USER_STATUS_LINE_TIMEOUT_SECONDS = 3, MIN_AUTO_COMPACT_WINDOW = 200000;
81605
81805
  var init_claude_runner = __esm(() => {
81606
81806
  init_model_catalog();
81607
81807
  init_config2();
@@ -81623,18 +81823,18 @@ __export(exports_diag_output, {
81623
81823
  NullDiagOutput: () => NullDiagOutput,
81624
81824
  LogFileDiagOutput: () => LogFileDiagOutput
81625
81825
  });
81626
- import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync19, unlinkSync as unlinkSync11, writeFileSync as writeFileSync22 } from "fs";
81826
+ import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync20, unlinkSync as unlinkSync11, writeFileSync as writeFileSync22 } from "fs";
81627
81827
  import { homedir as homedir35 } from "os";
81628
- import { join as join39 } from "path";
81828
+ import { join as join40 } from "path";
81629
81829
  function getClaudishDir() {
81630
- const dir = join39(homedir35(), ".claudish");
81830
+ const dir = join40(homedir35(), ".claudish");
81631
81831
  try {
81632
- mkdirSync19(dir, { recursive: true });
81832
+ mkdirSync20(dir, { recursive: true });
81633
81833
  } catch {}
81634
81834
  return dir;
81635
81835
  }
81636
81836
  function getDiagLogPath() {
81637
- return join39(getClaudishDir(), `diag-${process.pid}.log`);
81837
+ return join40(getClaudishDir(), `diag-${process.pid}.log`);
81638
81838
  }
81639
81839
 
81640
81840
  class LogFileDiagOutput {
@@ -82232,7 +82432,7 @@ __export(exports_session_discovery, {
82232
82432
  import { execFile, execFileSync as execFileSync2 } from "child_process";
82233
82433
  import { closeSync as closeSync6, openSync as openSync6, readSync, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
82234
82434
  import { homedir as homedir36 } from "os";
82235
- import { basename, join as join40 } from "path";
82435
+ import { basename, join as join41 } from "path";
82236
82436
  function slugForPath(absPath) {
82237
82437
  return absPath.replace(/[/.]/g, "-");
82238
82438
  }
@@ -82281,7 +82481,7 @@ function projectDirs() {
82281
82481
  }
82282
82482
  }
82283
82483
  function sessionsIn(dirName) {
82284
- const dir = join40(PROJECTS_DIR, dirName);
82484
+ const dir = join41(PROJECTS_DIR, dirName);
82285
82485
  let names;
82286
82486
  try {
82287
82487
  names = readdirSync7(dir).filter((n) => n.endsWith(".jsonl"));
@@ -82290,7 +82490,7 @@ function sessionsIn(dirName) {
82290
82490
  }
82291
82491
  const rows = [];
82292
82492
  for (const n of names) {
82293
- const file2 = join40(dir, n);
82493
+ const file2 = join41(dir, n);
82294
82494
  try {
82295
82495
  const st = statSync6(file2);
82296
82496
  if (st.size === 0)
@@ -82649,7 +82849,7 @@ function findLatestSessionId(cwd = process.cwd(), sinceMs = 0) {
82649
82849
  }
82650
82850
  var ENTRYPOINT_BYTES = 8192, PROJECTS_DIR, ACTIVE_WINDOW_MS = 120000, HEAD_BYTES, TAIL_BYTES, HARNESS_ENVELOPES, DEEP_TAIL_BYTES, RECENT_AI_TURNS = 5, RECENT_USER_TURNS = 1;
82651
82851
  var init_session_discovery = __esm(() => {
82652
- PROJECTS_DIR = join40(homedir36(), ".claude", "projects");
82852
+ PROJECTS_DIR = join41(homedir36(), ".claude", "projects");
82653
82853
  HEAD_BYTES = 64 * 1024;
82654
82854
  TAIL_BYTES = 128 * 1024;
82655
82855
  HARNESS_ENVELOPES = [
@@ -84343,9 +84543,9 @@ __export(exports_session_stats, {
84343
84543
  });
84344
84544
  import { readFileSync as readFileSync31 } from "fs";
84345
84545
  import { homedir as homedir37 } from "os";
84346
- import { join as join41 } from "path";
84546
+ import { join as join42 } from "path";
84347
84547
  function tokenFilePath(port) {
84348
- return process.env.CLAUDISH_TOKEN_FILE || join41(homedir37(), ".claudish", `tokens-${port}.json`);
84548
+ return process.env.CLAUDISH_TOKEN_FILE || join42(homedir37(), ".claudish", `tokens-${port}.json`);
84349
84549
  }
84350
84550
  function readSessionStats(port, opts) {
84351
84551
  let raw2;
@@ -84691,7 +84891,7 @@ init_op_source();
84691
84891
  init_startup_trace();
84692
84892
  var import_dotenv3 = __toESM(require_main(), 1);
84693
84893
  import { existsSync as existsSync31, readFileSync as readFileSync32 } from "fs";
84694
- import { join as join42, resolve as resolve5 } from "path";
84894
+ import { join as join43, resolve as resolve5 } from "path";
84695
84895
  import_dotenv3.config({ quiet: true });
84696
84896
  function classifyStartupKind() {
84697
84897
  const argv = process.argv.slice(2);
@@ -84952,7 +85152,7 @@ async function runCli() {
84952
85152
  process.exit(1);
84953
85153
  }
84954
85154
  const mode = cliConfig.teamMode ?? "default";
84955
- const sessionPath = join42(process.cwd(), `.claudish-team-${Date.now()}`);
85155
+ const sessionPath = join43(process.cwd(), `.claudish-team-${Date.now()}`);
84956
85156
  if (mode === "json") {
84957
85157
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
84958
85158
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -84962,7 +85162,7 @@ async function runCli() {
84962
85162
  });
84963
85163
  const result = { ...status2, responses: {} };
84964
85164
  for (const anonId of Object.keys(status2.models)) {
84965
- const responsePath = join42(sessionPath, `response-${anonId}.md`);
85165
+ const responsePath = join43(sessionPath, `response-${anonId}.md`);
84966
85166
  try {
84967
85167
  const raw2 = readFileSync32(responsePath, "utf-8").trim();
84968
85168
  try {
@@ -85169,7 +85369,8 @@ Team Status`);
85169
85369
  isInteractive: cliConfig.interactive,
85170
85370
  advisorModels: cliConfig.advisorModels,
85171
85371
  advisorCollector: cliConfig.advisorCollector,
85172
- modelChain: cliConfig.monitor ? undefined : cliConfig.modelChain
85372
+ modelChain: cliConfig.monitor ? undefined : cliConfig.modelChain,
85373
+ classifier: resolveClassifierConfig(cliConfig, process.env)
85173
85374
  }));
85174
85375
  const diag = createDiagOutput2({
85175
85376
  interactive: cliConfig.interactive,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.60.0",
3
+ "version": "7.61.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",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "7.60.0",
64
- "@claudish/magmux-darwin-x64": "7.60.0",
65
- "@claudish/magmux-linux-arm64": "7.60.0",
66
- "@claudish/magmux-linux-x64": "7.60.0"
63
+ "@claudish/magmux-darwin-arm64": "7.61.0",
64
+ "@claudish/magmux-darwin-x64": "7.61.0",
65
+ "@claudish/magmux-linux-arm64": "7.61.0",
66
+ "@claudish/magmux-linux-x64": "7.61.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",