claudish 6.6.3 → 6.8.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
@@ -23252,6 +23252,24 @@ var init_provider_definitions = __esm(() => {
23252
23252
  isLocal: true,
23253
23253
  description: "Local MLX (mlx@)"
23254
23254
  },
23255
+ {
23256
+ name: "deepseek",
23257
+ displayName: "DeepSeek",
23258
+ transport: "openai",
23259
+ tokenStrategy: "delta-aware",
23260
+ baseUrl: "https://api.deepseek.com",
23261
+ baseUrlEnvVars: ["DEEPSEEK_BASE_URL"],
23262
+ apiPath: "/v1/chat/completions",
23263
+ apiKeyEnvVar: "DEEPSEEK_API_KEY",
23264
+ apiKeyDescription: "DeepSeek API Key",
23265
+ apiKeyUrl: "https://platform.deepseek.com/api_keys",
23266
+ shortcuts: ["ds"],
23267
+ shortestPrefix: "ds",
23268
+ legacyPrefixes: [{ prefix: "ds/", stripPrefix: true }],
23269
+ nativeModelPatterns: [{ pattern: /^deepseek\//i }, { pattern: /^deepseek-/i }],
23270
+ isDirectApi: true,
23271
+ description: "DeepSeek API (ds@)"
23272
+ },
23255
23273
  {
23256
23274
  name: "qwen",
23257
23275
  displayName: "Qwen",
@@ -24806,75 +24824,156 @@ var init_static_fallback = __esm(() => {
24806
24824
  minimax: "minimax",
24807
24825
  openrouter: "openrouter",
24808
24826
  ollamacloud: "meta-llama",
24809
- qwen: "qwen"
24827
+ qwen: "qwen",
24828
+ deepseek: "deepseek",
24829
+ grok: "x-ai"
24810
24830
  };
24811
24831
  });
24812
24832
 
24813
24833
  // src/providers/catalog-resolvers/openrouter.ts
24814
- import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
24834
+ import { readFileSync as readFileSync6, existsSync as existsSync8, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
24815
24835
  import { join as join10 } from "path";
24816
24836
  import { homedir as homedir9 } from "os";
24817
24837
 
24818
24838
  class OpenRouterCatalogResolver {
24819
24839
  provider = "openrouter";
24820
24840
  resolveSync(userInput) {
24841
+ const entries = this._getEntries();
24821
24842
  if (userInput.includes("/")) {
24822
- const models2 = this._getModels();
24823
- if (models2) {
24824
- const exactMatch = models2.find((m) => m.id === userInput);
24825
- return exactMatch ? exactMatch.id : userInput;
24843
+ if (entries) {
24844
+ for (const entry of entries) {
24845
+ for (const src of Object.values(entry.sources)) {
24846
+ if (src.externalId === userInput)
24847
+ return userInput;
24848
+ }
24849
+ }
24826
24850
  }
24827
24851
  return userInput;
24828
24852
  }
24829
- const models = this._getModels();
24830
- if (models) {
24853
+ if (entries) {
24854
+ const byModelId = entries.find((e) => e.modelId === userInput);
24855
+ if (byModelId) {
24856
+ const orId = this._getOpenRouterExternalId(byModelId);
24857
+ if (orId)
24858
+ return orId;
24859
+ }
24860
+ const byAlias = entries.find((e) => e.aliases.includes(userInput));
24861
+ if (byAlias) {
24862
+ const orId = this._getOpenRouterExternalId(byAlias);
24863
+ if (orId)
24864
+ return orId;
24865
+ }
24866
+ for (const entry of entries) {
24867
+ for (const src of Object.values(entry.sources)) {
24868
+ if (src.externalId === userInput) {
24869
+ const orId = this._getOpenRouterExternalId(entry);
24870
+ if (orId)
24871
+ return orId;
24872
+ }
24873
+ }
24874
+ }
24831
24875
  const suffix = `/${userInput}`;
24832
- const match2 = models.find((m) => m.id.endsWith(suffix));
24833
- if (match2)
24834
- return match2.id;
24876
+ for (const entry of entries) {
24877
+ const orId = this._getOpenRouterExternalId(entry);
24878
+ if (orId && orId.endsWith(suffix))
24879
+ return orId;
24880
+ }
24835
24881
  const lowerSuffix = `/${userInput.toLowerCase()}`;
24836
- const ciMatch = models.find((m) => m.id.toLowerCase().endsWith(lowerSuffix));
24837
- if (ciMatch)
24838
- return ciMatch.id;
24882
+ for (const entry of entries) {
24883
+ const orId = this._getOpenRouterExternalId(entry);
24884
+ if (orId && orId.toLowerCase().endsWith(lowerSuffix))
24885
+ return orId;
24886
+ }
24839
24887
  }
24840
24888
  return staticOpenRouterFallback(userInput);
24841
24889
  }
24842
24890
  async warmCache() {
24843
- try {
24844
- const existing = getCachedOpenRouterModels();
24845
- if (existing && existing.length > 0) {
24846
- _memCache = existing;
24847
- return;
24848
- }
24849
- const models = await ensureOpenRouterModelsLoaded();
24850
- if (models.length > 0) {
24851
- _memCache = models;
24852
- }
24853
- } catch {}
24891
+ if (!_warmPromise) {
24892
+ _warmPromise = this._fetchAndCache();
24893
+ }
24894
+ await _warmPromise;
24854
24895
  }
24855
24896
  isCacheWarm() {
24856
24897
  return _memCache !== null && _memCache.length > 0;
24857
24898
  }
24858
- _getModels() {
24899
+ async ensureReady(timeoutMs) {
24900
+ if (this.isCacheWarm())
24901
+ return;
24902
+ if (!_warmPromise) {
24903
+ _warmPromise = this._fetchAndCache();
24904
+ }
24905
+ await Promise.race([
24906
+ _warmPromise,
24907
+ new Promise((resolve2) => setTimeout(resolve2, timeoutMs))
24908
+ ]);
24909
+ }
24910
+ _getOpenRouterExternalId(entry) {
24911
+ const orSource = entry.sources["openrouter-api"];
24912
+ if (orSource?.externalId)
24913
+ return orSource.externalId;
24914
+ for (const src of Object.values(entry.sources)) {
24915
+ if (src.externalId.includes("/"))
24916
+ return src.externalId;
24917
+ }
24918
+ return null;
24919
+ }
24920
+ _getEntries() {
24859
24921
  if (_memCache)
24860
24922
  return _memCache;
24861
- const diskPath = join10(homedir9(), ".claudish", "all-models.json");
24862
- if (existsSync8(diskPath)) {
24923
+ if (existsSync8(DISK_CACHE_PATH)) {
24863
24924
  try {
24864
- const data = JSON.parse(readFileSync6(diskPath, "utf-8"));
24925
+ const data = JSON.parse(readFileSync6(DISK_CACHE_PATH, "utf-8"));
24926
+ if (data.version === 2 && Array.isArray(data.entries) && data.entries.length > 0) {
24927
+ _memCache = data.entries;
24928
+ return _memCache;
24929
+ }
24865
24930
  if (Array.isArray(data.models) && data.models.length > 0) {
24866
- _memCache = data.models;
24931
+ _memCache = data.models.map((m) => ({
24932
+ modelId: m.id.includes("/") ? m.id.split("/").slice(1).join("/") : m.id,
24933
+ aliases: [],
24934
+ sources: { "openrouter-api": { externalId: m.id } }
24935
+ }));
24867
24936
  return _memCache;
24868
24937
  }
24869
24938
  } catch {}
24870
24939
  }
24871
24940
  return null;
24872
24941
  }
24942
+ async _fetchAndCache() {
24943
+ try {
24944
+ const response = await fetch(FIREBASE_CATALOG_URL, {
24945
+ signal: AbortSignal.timeout(8000)
24946
+ });
24947
+ if (!response.ok) {
24948
+ throw new Error(`Firebase catalog returned ${response.status}`);
24949
+ }
24950
+ const data = await response.json();
24951
+ if (!Array.isArray(data.models) || data.models.length === 0)
24952
+ return;
24953
+ _memCache = data.models;
24954
+ const backwardCompatModels = [];
24955
+ for (const entry of data.models) {
24956
+ const orSource = entry.sources["openrouter-api"];
24957
+ if (orSource?.externalId) {
24958
+ backwardCompatModels.push({ id: orSource.externalId });
24959
+ }
24960
+ }
24961
+ const cacheDir = join10(homedir9(), ".claudish");
24962
+ mkdirSync8(cacheDir, { recursive: true });
24963
+ const diskData = {
24964
+ version: 2,
24965
+ lastUpdated: new Date().toISOString(),
24966
+ entries: data.models,
24967
+ models: backwardCompatModels
24968
+ };
24969
+ writeFileSync8(DISK_CACHE_PATH, JSON.stringify(diskData), "utf-8");
24970
+ } catch {}
24971
+ }
24873
24972
  }
24874
- var _memCache = null;
24973
+ var FIREBASE_CATALOG_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels?status=active&catalog=slim&limit=1000", DISK_CACHE_PATH, _memCache = null, _warmPromise = null;
24875
24974
  var init_openrouter2 = __esm(() => {
24876
- init_model_loader();
24877
24975
  init_static_fallback();
24976
+ DISK_CACHE_PATH = join10(homedir9(), ".claudish", "all-models.json");
24878
24977
  });
24879
24978
 
24880
24979
  // src/providers/catalog-resolvers/litellm.ts
@@ -24927,6 +25026,10 @@ class LiteLLMCatalogResolver {
24927
25026
  isCacheWarm() {
24928
25027
  return _memCache2 !== null && _memCache2.length > 0;
24929
25028
  }
25029
+ async ensureReady(_timeoutMs) {
25030
+ if (!this.isCacheWarm())
25031
+ await this.warmCache();
25032
+ }
24930
25033
  _getModelIds() {
24931
25034
  if (_memCache2)
24932
25035
  return _memCache2;
@@ -24977,6 +25080,12 @@ function logResolution(userInput, result, quiet = false) {
24977
25080
  `);
24978
25081
  }
24979
25082
  }
25083
+ async function ensureCatalogReady(provider, timeoutMs = 5000) {
25084
+ const resolver = getResolver(provider);
25085
+ if (!resolver || resolver.isCacheWarm())
25086
+ return;
25087
+ await resolver.ensureReady(timeoutMs);
25088
+ }
24980
25089
  async function warmAllCatalogs(providers) {
24981
25090
  const targets = providers ? [...RESOLVER_REGISTRY.entries()].filter(([k]) => providers.includes(k)) : [...RESOLVER_REGISTRY.entries()];
24982
25091
  await Promise.allSettled(targets.map(([, r]) => r.warmCache()));
@@ -25125,8 +25234,8 @@ async function warmZenModelCache() {
25125
25234
  if (models.length === 0)
25126
25235
  return;
25127
25236
  const cacheDir = join12(homedir11(), ".claudish");
25128
- const { mkdirSync: mkdirSync8, writeFileSync: writeSync } = await import("fs");
25129
- mkdirSync8(cacheDir, { recursive: true });
25237
+ const { mkdirSync: mkdirSync9, writeFileSync: writeSync } = await import("fs");
25238
+ mkdirSync9(cacheDir, { recursive: true });
25130
25239
  writeSync(join12(cacheDir, "zen-models.json"), JSON.stringify({ models, fetchedAt: new Date().toISOString() }));
25131
25240
  }
25132
25241
  function readZenGoModelCacheSync() {
@@ -25162,8 +25271,8 @@ async function warmZenGoModelCache() {
25162
25271
  if (models.length === 0)
25163
25272
  return;
25164
25273
  const cacheDir = join12(homedir11(), ".claudish");
25165
- const { mkdirSync: mkdirSync8, writeFileSync: writeSync } = await import("fs");
25166
- mkdirSync8(cacheDir, { recursive: true });
25274
+ const { mkdirSync: mkdirSync9, writeFileSync: writeSync } = await import("fs");
25275
+ mkdirSync9(cacheDir, { recursive: true });
25167
25276
  writeSync(join12(cacheDir, "zen-go-models.json"), JSON.stringify({ models, fetchedAt: new Date().toISOString() }));
25168
25277
  }
25169
25278
  function hasProviderCredentials(provider) {
@@ -25237,6 +25346,7 @@ var init_auto_route = __esm(() => {
25237
25346
  "minimax-coding": { apiKeyEnvVar: "MINIMAX_CODING_API_KEY" },
25238
25347
  glm: { apiKeyEnvVar: "ZHIPU_API_KEY" },
25239
25348
  "glm-coding": { apiKeyEnvVar: "GLM_CODING_API_KEY" },
25349
+ deepseek: { apiKeyEnvVar: "DEEPSEEK_API_KEY" },
25240
25350
  ollamacloud: { apiKeyEnvVar: "OLLAMA_API_KEY" }
25241
25351
  };
25242
25352
  PROVIDER_TO_PREFIX = (() => {
@@ -25639,7 +25749,7 @@ var init_provider_resolver = __esm(() => {
25639
25749
  });
25640
25750
 
25641
25751
  // src/services/pricing-cache.ts
25642
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync8, statSync as statSync2 } from "fs";
25752
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync12, mkdirSync as mkdirSync9, statSync as statSync2 } from "fs";
25643
25753
  import { homedir as homedir13 } from "os";
25644
25754
  import { join as join14 } from "path";
25645
25755
  function getDynamicPricingSync(provider, modelName) {
@@ -25723,12 +25833,12 @@ function loadDiskCache() {
25723
25833
  }
25724
25834
  function saveDiskCache() {
25725
25835
  try {
25726
- mkdirSync8(CACHE_DIR, { recursive: true });
25836
+ mkdirSync9(CACHE_DIR, { recursive: true });
25727
25837
  const data = {};
25728
25838
  for (const [key, pricing] of pricingMap) {
25729
25839
  data[key] = pricing;
25730
25840
  }
25731
- writeFileSync8(CACHE_FILE, JSON.stringify(data), "utf-8");
25841
+ writeFileSync9(CACHE_FILE, JSON.stringify(data), "utf-8");
25732
25842
  } catch (error2) {
25733
25843
  log(`[PricingCache] Error saving disk cache: ${error2}`);
25734
25844
  }
@@ -26305,8 +26415,8 @@ Details: ${e.message}`);
26305
26415
  const credPath = this.getCredentialsPath();
26306
26416
  const claudishDir = join15(homedir14(), ".claudish");
26307
26417
  if (!existsSync13(claudishDir)) {
26308
- const { mkdirSync: mkdirSync9 } = __require("fs");
26309
- mkdirSync9(claudishDir, { recursive: true });
26418
+ const { mkdirSync: mkdirSync10 } = __require("fs");
26419
+ mkdirSync10(claudishDir, { recursive: true });
26310
26420
  }
26311
26421
  const fd = openSync(credPath, "w", 384);
26312
26422
  try {
@@ -27163,8 +27273,8 @@ Details: ${e.message}`);
27163
27273
  const credPath = this.getCredentialsPath();
27164
27274
  const claudishDir = join16(homedir15(), ".claudish");
27165
27275
  if (!existsSync14(claudishDir)) {
27166
- const { mkdirSync: mkdirSync9 } = __require("fs");
27167
- mkdirSync9(claudishDir, { recursive: true });
27276
+ const { mkdirSync: mkdirSync10 } = __require("fs");
27277
+ mkdirSync10(claudishDir, { recursive: true });
27168
27278
  }
27169
27279
  const fd = openSync2(credPath, "w", 384);
27170
27280
  try {
@@ -27480,8 +27590,8 @@ class KimiOAuth {
27480
27590
  const deviceIdPath = this.getDeviceIdPath();
27481
27591
  const claudishDir = join18(homedir17(), ".claudish");
27482
27592
  if (!existsSync16(claudishDir)) {
27483
- const { mkdirSync: mkdirSync9 } = __require("fs");
27484
- mkdirSync9(claudishDir, { recursive: true });
27593
+ const { mkdirSync: mkdirSync10 } = __require("fs");
27594
+ mkdirSync10(claudishDir, { recursive: true });
27485
27595
  }
27486
27596
  if (existsSync16(deviceIdPath)) {
27487
27597
  try {
@@ -27764,8 +27874,8 @@ Waiting for authorization...`);
27764
27874
  const credPath = this.getCredentialsPath();
27765
27875
  const claudishDir = join18(homedir17(), ".claudish");
27766
27876
  if (!existsSync16(claudishDir)) {
27767
- const { mkdirSync: mkdirSync9 } = __require("fs");
27768
- mkdirSync9(claudishDir, { recursive: true });
27877
+ const { mkdirSync: mkdirSync10 } = __require("fs");
27878
+ mkdirSync10(claudishDir, { recursive: true });
27769
27879
  }
27770
27880
  const fd = openSync3(credPath, "w", 384);
27771
27881
  try {
@@ -28843,6 +28953,7 @@ var init_provider_profiles = __esm(() => {
28843
28953
  "glm-coding": glmProfile,
28844
28954
  "opencode-zen": openCodeZenProfile,
28845
28955
  "opencode-zen-go": openCodeZenProfile,
28956
+ deepseek: openaiProfile,
28846
28957
  ollamacloud: ollamaCloudProfile,
28847
28958
  litellm: litellmProfile,
28848
28959
  vertex: vertexProfile
@@ -29001,7 +29112,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29001
29112
  }
29002
29113
  return "auto-route";
29003
29114
  };
29004
- const getHandlerForRequest = (requestedModel) => {
29115
+ const getHandlerForRequest = async (requestedModel) => {
29005
29116
  if (monitorMode)
29006
29117
  return nativeHandler;
29007
29118
  let target = requestedModel;
@@ -29026,6 +29137,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29026
29137
  {
29027
29138
  const parsedTarget = parseModelSpec(target);
29028
29139
  if (parsedTarget.provider === "openrouter" || parsedTarget.provider === "litellm") {
29140
+ await ensureCatalogReady(parsedTarget.provider, 5000);
29029
29141
  const resolution = resolveModelNameSync(parsedTarget.model, parsedTarget.provider);
29030
29142
  logResolution(parsedTarget.model, resolution, options.quiet);
29031
29143
  if (resolution.wasResolved) {
@@ -29040,6 +29152,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29040
29152
  if (fallbackHandlerCache.has(cacheKey2)) {
29041
29153
  return fallbackHandlerCache.get(cacheKey2);
29042
29154
  }
29155
+ await ensureCatalogReady("openrouter", 5000);
29043
29156
  const matchedEntries = customRoutingRules ? matchRoutingRule(parsedForFallback.model, customRoutingRules) : null;
29044
29157
  const chain = matchedEntries ? buildRoutingChain(matchedEntries, parsedForFallback.model) : getFallbackChain(parsedForFallback.model, parsedForFallback.provider);
29045
29158
  if (chain.length > 0) {
@@ -29099,7 +29212,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29099
29212
  try {
29100
29213
  const body = await c.req.json();
29101
29214
  const reqModel = body.model || "claude-3-opus-20240229";
29102
- const handler = getHandlerForRequest(reqModel);
29215
+ const handler = await getHandlerForRequest(reqModel);
29103
29216
  if (handler instanceof NativeHandler) {
29104
29217
  const headers = { "Content-Type": "application/json" };
29105
29218
  if (anthropicApiKey)
@@ -29121,7 +29234,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29121
29234
  app.post("/v1/messages", async (c) => {
29122
29235
  try {
29123
29236
  const body = await c.req.json();
29124
- const handler = getHandlerForRequest(body.model);
29237
+ const handler = await getHandlerForRequest(body.model);
29125
29238
  return handler.handle(c, body);
29126
29239
  } catch (e) {
29127
29240
  log(`[Proxy] Error: ${e}`);
@@ -29210,7 +29323,7 @@ var exports_mcp_server = {};
29210
29323
  __export(exports_mcp_server, {
29211
29324
  startMcpServer: () => startMcpServer
29212
29325
  });
29213
- import { readFileSync as readFileSync17, existsSync as existsSync20, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, readdirSync as readdirSync3 } from "fs";
29326
+ import { readFileSync as readFileSync17, existsSync as existsSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readdirSync as readdirSync3 } from "fs";
29214
29327
  import { join as join22, dirname as dirname2 } from "path";
29215
29328
  import { homedir as homedir21 } from "os";
29216
29329
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -29242,8 +29355,8 @@ async function loadAllModels(forceRefresh = false) {
29242
29355
  throw new Error(`API returned ${response.status}`);
29243
29356
  const data = await response.json();
29244
29357
  const models = data.data || [];
29245
- mkdirSync9(CLAUDISH_CACHE_DIR, { recursive: true });
29246
- writeFileSync9(ALL_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
29358
+ mkdirSync10(CLAUDISH_CACHE_DIR, { recursive: true });
29359
+ writeFileSync10(ALL_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
29247
29360
  return models;
29248
29361
  } catch {
29249
29362
  if (existsSync20(ALL_MODELS_CACHE_PATH)) {
@@ -32719,9 +32832,9 @@ __export(exports_cli, {
32719
32832
  });
32720
32833
  import {
32721
32834
  readFileSync as readFileSync18,
32722
- writeFileSync as writeFileSync10,
32835
+ writeFileSync as writeFileSync11,
32723
32836
  existsSync as existsSync21,
32724
- mkdirSync as mkdirSync10,
32837
+ mkdirSync as mkdirSync11,
32725
32838
  copyFileSync,
32726
32839
  readdirSync as readdirSync4,
32727
32840
  unlinkSync as unlinkSync6
@@ -33071,8 +33184,8 @@ async function searchAndPrintModels(query, forceUpdate) {
33071
33184
  throw new Error(`API returned ${response.status}`);
33072
33185
  const data = await response.json();
33073
33186
  models = data.data;
33074
- mkdirSync10(CLAUDISH_CACHE_DIR2, { recursive: true });
33075
- writeFileSync10(ALL_MODELS_JSON_PATH, JSON.stringify({
33187
+ mkdirSync11(CLAUDISH_CACHE_DIR2, { recursive: true });
33188
+ writeFileSync11(ALL_MODELS_JSON_PATH, JSON.stringify({
33076
33189
  lastUpdated: new Date().toISOString(),
33077
33190
  models
33078
33191
  }), "utf-8");
@@ -33244,8 +33357,8 @@ async function printAllModels(jsonOutput, forceUpdate) {
33244
33357
  throw new Error(`API returned ${response.status}`);
33245
33358
  const data = await response.json();
33246
33359
  models = data.data;
33247
- mkdirSync10(CLAUDISH_CACHE_DIR2, { recursive: true });
33248
- writeFileSync10(ALL_MODELS_JSON_PATH, JSON.stringify({
33360
+ mkdirSync11(CLAUDISH_CACHE_DIR2, { recursive: true });
33361
+ writeFileSync11(ALL_MODELS_JSON_PATH, JSON.stringify({
33249
33362
  lastUpdated: new Date().toISOString(),
33250
33363
  models
33251
33364
  }), "utf-8");
@@ -33522,8 +33635,8 @@ async function updateModelsFromOpenRouter() {
33522
33635
  source: "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
33523
33636
  models: recommendations
33524
33637
  };
33525
- mkdirSync10(CLAUDISH_CACHE_DIR2, { recursive: true });
33526
- writeFileSync10(CACHED_MODELS_PATH, JSON.stringify(updatedData, null, 2), "utf-8");
33638
+ mkdirSync11(CLAUDISH_CACHE_DIR2, { recursive: true });
33639
+ writeFileSync11(CACHED_MODELS_PATH, JSON.stringify(updatedData, null, 2), "utf-8");
33527
33640
  console.error(`\u2705 Updated ${recommendations.length} models (last updated: ${updatedData.lastUpdated})`);
33528
33641
  } catch (error2) {
33529
33642
  console.error(`\u274C Failed to update models: ${error2 instanceof Error ? error2.message : String(error2)}`);
@@ -34173,15 +34286,15 @@ async function initializeClaudishSkill() {
34173
34286
  }
34174
34287
  try {
34175
34288
  if (!existsSync21(claudeDir)) {
34176
- mkdirSync10(claudeDir, { recursive: true });
34289
+ mkdirSync11(claudeDir, { recursive: true });
34177
34290
  console.log("\uD83D\uDCC1 Created .claude/ directory");
34178
34291
  }
34179
34292
  if (!existsSync21(skillsDir)) {
34180
- mkdirSync10(skillsDir, { recursive: true });
34293
+ mkdirSync11(skillsDir, { recursive: true });
34181
34294
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
34182
34295
  }
34183
34296
  if (!existsSync21(claudishSkillDir)) {
34184
- mkdirSync10(claudishSkillDir, { recursive: true });
34297
+ mkdirSync11(claudishSkillDir, { recursive: true });
34185
34298
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
34186
34299
  }
34187
34300
  copyFileSync(sourceSkillPath, skillFile);
@@ -34361,7 +34474,7 @@ async function fetchGLMCodingModels() {
34361
34474
  return [];
34362
34475
  }
34363
34476
  }
34364
- var __filename4, __dirname4, VERSION = "6.6.3", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
34477
+ var __filename4, __dirname4, VERSION = "6.8.0", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
34365
34478
  var init_cli = __esm(() => {
34366
34479
  init_config();
34367
34480
  init_model_loader();
@@ -34392,7 +34505,7 @@ __export(exports_update_checker, {
34392
34505
  checkForUpdates: () => checkForUpdates
34393
34506
  });
34394
34507
  import { execSync } from "child_process";
34395
- import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync7, writeFileSync as writeFileSync11 } from "fs";
34508
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync19, unlinkSync as unlinkSync7, writeFileSync as writeFileSync12 } from "fs";
34396
34509
  import { homedir as homedir23, platform as platform2, tmpdir } from "os";
34397
34510
  import { join as join24 } from "path";
34398
34511
  import { createInterface as createInterface2 } from "readline";
@@ -34413,7 +34526,7 @@ function getCacheFilePath() {
34413
34526
  }
34414
34527
  try {
34415
34528
  if (!existsSync22(cacheDir)) {
34416
- mkdirSync11(cacheDir, { recursive: true });
34529
+ mkdirSync12(cacheDir, { recursive: true });
34417
34530
  }
34418
34531
  return join24(cacheDir, "update-check.json");
34419
34532
  } catch {
@@ -34439,7 +34552,7 @@ function writeCache(latestVersion) {
34439
34552
  lastCheck: Date.now(),
34440
34553
  latestVersion
34441
34554
  };
34442
- writeFileSync11(cachePath, JSON.stringify(data), "utf-8");
34555
+ writeFileSync12(cachePath, JSON.stringify(data), "utf-8");
34443
34556
  } catch {}
34444
34557
  }
34445
34558
  function isCacheValid(cache) {
@@ -34715,7 +34828,7 @@ __export(exports_model_selector, {
34715
34828
  promptForApiKey: () => promptForApiKey,
34716
34829
  confirmAction: () => confirmAction
34717
34830
  });
34718
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync12, existsSync as existsSync23, mkdirSync as mkdirSync12 } from "fs";
34831
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, existsSync as existsSync23, mkdirSync as mkdirSync13 } from "fs";
34719
34832
  import { join as join25, dirname as dirname4 } from "path";
34720
34833
  import { homedir as homedir24 } from "os";
34721
34834
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -34753,8 +34866,8 @@ async function fetchAllModels(forceUpdate = false) {
34753
34866
  throw new Error(`API returned ${response.status}`);
34754
34867
  const data = await response.json();
34755
34868
  const models = data.data;
34756
- mkdirSync12(CLAUDISH_CACHE_DIR3, { recursive: true });
34757
- writeFileSync12(ALL_MODELS_JSON_PATH2, JSON.stringify({
34869
+ mkdirSync13(CLAUDISH_CACHE_DIR3, { recursive: true });
34870
+ writeFileSync13(ALL_MODELS_JSON_PATH2, JSON.stringify({
34758
34871
  lastUpdated: new Date().toISOString(),
34759
34872
  models
34760
34873
  }), "utf-8");
@@ -36634,7 +36747,7 @@ import os from "os";
36634
36747
  import path from "path";
36635
36748
  import { EventEmitter as EventEmitter3 } from "events";
36636
36749
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr4 } from "bun:ffi";
36637
- import { existsSync as existsSync25, writeFileSync as writeFileSync13 } from "fs";
36750
+ import { existsSync as existsSync25, writeFileSync as writeFileSync14 } from "fs";
36638
36751
  import { EventEmitter as EventEmitter4 } from "events";
36639
36752
  import { toArrayBuffer, ptr } from "bun:ffi";
36640
36753
  import { ptr as ptr2, toArrayBuffer as toArrayBuffer2 } from "bun:ffi";
@@ -41980,7 +42093,7 @@ function convertToDebugSymbols(symbols) {
41980
42093
  if (env.OTUI_DEBUG_FFI && globalFFILogPath) {
41981
42094
  const logPath = globalFFILogPath;
41982
42095
  const writeSync4 = (msg) => {
41983
- writeFileSync13(logPath, msg + `
42096
+ writeFileSync14(logPath, msg + `
41984
42097
  `, { flag: "a" });
41985
42098
  };
41986
42099
  Object.entries(symbols).forEach(([key, value]) => {
@@ -95546,10 +95659,10 @@ import { spawn as spawn3 } from "child_process";
95546
95659
  import {
95547
95660
  appendFileSync,
95548
95661
  existsSync as existsSync26,
95549
- mkdirSync as mkdirSync13,
95662
+ mkdirSync as mkdirSync14,
95550
95663
  readFileSync as readFileSync21,
95551
95664
  unlinkSync as unlinkSync8,
95552
- writeFileSync as writeFileSync14
95665
+ writeFileSync as writeFileSync15
95553
95666
  } from "fs";
95554
95667
  import { dirname as dirname6, join as join27 } from "path";
95555
95668
  import { fileURLToPath as fileURLToPath6 } from "url";
@@ -95562,7 +95675,7 @@ function formatElapsed(ms) {
95562
95675
  const rem = s % 60;
95563
95676
  return `${m2}m ${rem}s`;
95564
95677
  }
95565
- function findMultiplexerBinary() {
95678
+ function findMagmuxBinary() {
95566
95679
  const thisFile = fileURLToPath6(import.meta.url);
95567
95680
  const thisDir = dirname6(thisFile);
95568
95681
  const pkgRoot = join27(thisDir, "..");
@@ -95570,40 +95683,17 @@ function findMultiplexerBinary() {
95570
95683
  const arch = process.arch;
95571
95684
  const builtMagmux = join27(pkgRoot, "native", "magmux", "magmux");
95572
95685
  if (existsSync26(builtMagmux))
95573
- return { path: builtMagmux, kind: "magmux" };
95686
+ return builtMagmux;
95574
95687
  const bundledMagmux = join27(pkgRoot, "native", "magmux", `magmux-${platform3}-${arch}`);
95575
95688
  if (existsSync26(bundledMagmux))
95576
- return { path: bundledMagmux, kind: "magmux" };
95689
+ return bundledMagmux;
95577
95690
  try {
95578
95691
  const result = execSync3("which magmux", { encoding: "utf-8" }).trim();
95579
95692
  if (result)
95580
- return { path: result, kind: "magmux" };
95581
- } catch {}
95582
- const builtMtm = join27(pkgRoot, "native", "mtm", "mtm");
95583
- if (existsSync26(builtMtm))
95584
- return { path: builtMtm, kind: "mtm" };
95585
- const bundledMtm = join27(pkgRoot, "native", "mtm", `mtm-${platform3}-${arch}`);
95586
- if (existsSync26(bundledMtm))
95587
- return { path: bundledMtm, kind: "mtm" };
95588
- try {
95589
- const result = execSync3("which mtm", { encoding: "utf-8" }).trim();
95590
- if (result && isMtmForkWithGrid(result))
95591
- return { path: result, kind: "mtm" };
95693
+ return result;
95592
95694
  } catch {}
95593
- throw new Error(`No terminal multiplexer found. Install magmux (recommended) or build mtm:
95594
- ` + ` brew install MadAppGang/tap/magmux
95595
- ` + " # or: cd packages/cli/native/mtm && make");
95596
- }
95597
- function isMtmForkWithGrid(binPath) {
95598
- try {
95599
- const output = execSync3(`"${binPath}" --help 2>&1 || true`, {
95600
- encoding: "utf-8",
95601
- timeout: 2000
95602
- });
95603
- return output.includes("-g ");
95604
- } catch {
95605
- return false;
95606
- }
95695
+ throw new Error(`magmux not found. Install it:
95696
+ brew install MadAppGang/tap/magmux`);
95607
95697
  }
95608
95698
  function renderGridStatusBar(counts) {
95609
95699
  const elapsed = formatElapsed(counts.elapsedMs);
@@ -95671,7 +95761,7 @@ function pollStatus(state) {
95671
95761
  else
95672
95762
  failed++;
95673
95763
  } else {
95674
- if (elapsedMs > timeoutMs) {
95764
+ if (!state.interactive && elapsedMs > timeoutMs) {
95675
95765
  const newState = {
95676
95766
  ...current,
95677
95767
  state: "TIMEOUT",
@@ -95696,7 +95786,7 @@ function pollStatus(state) {
95696
95786
  }
95697
95787
  }
95698
95788
  if (changed) {
95699
- writeFileSync14(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
95789
+ writeFileSync15(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
95700
95790
  }
95701
95791
  const total = anonIds.length;
95702
95792
  const allDone = done + failed >= total;
@@ -95717,8 +95807,9 @@ function pollStatus(state) {
95717
95807
  }
95718
95808
  async function runWithGrid(sessionPath, models, input, opts) {
95719
95809
  const timeoutMs = (opts?.timeout ?? 300) * 1000;
95810
+ const interactive = opts?.interactive ?? false;
95720
95811
  const manifest = setupSession(sessionPath, models, input);
95721
- mkdirSync13(join27(sessionPath, "errors"), { recursive: true });
95812
+ mkdirSync14(join27(sessionPath, "errors"), { recursive: true });
95722
95813
  for (const anonId of Object.keys(manifest.models)) {
95723
95814
  const stale = join27(sessionPath, "work", anonId, ".exit-code");
95724
95815
  try {
@@ -95732,6 +95823,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
95732
95823
  const exitCodeFile = join27(sessionPath, "work", anonId, ".exit-code");
95733
95824
  const model = manifest.models[anonId].model;
95734
95825
  const paneIndex = Object.keys(manifest.models).indexOf(anonId);
95826
+ if (interactive) {
95827
+ return `claudish --model ${model} --dangerously-skip-permissions '${prompt}'`;
95828
+ }
95735
95829
  return [
95736
95830
  `claudish --model ${model} -y -v '${prompt}' 2>${errorLog};`,
95737
95831
  `_ec=$?; echo $_ec > ${exitCodeFile};`,
@@ -95747,10 +95841,10 @@ async function runWithGrid(sessionPath, models, input, opts) {
95747
95841
  `exec sleep 86400`
95748
95842
  ].join(" ");
95749
95843
  });
95750
- writeFileSync14(gridfilePath, gridLines.join(`
95844
+ writeFileSync15(gridfilePath, gridLines.join(`
95751
95845
  `) + `
95752
95846
  `, "utf-8");
95753
- const mux = findMultiplexerBinary();
95847
+ const magmuxPath = findMagmuxBinary();
95754
95848
  const statusbarPath = join27(sessionPath, "statusbar.txt");
95755
95849
  const statusPath = join27(sessionPath, "status.json");
95756
95850
  const statusCache = JSON.parse(readFileSync21(statusPath, "utf-8"));
@@ -95773,18 +95867,17 @@ async function runWithGrid(sessionPath, models, input, opts) {
95773
95867
  startTime,
95774
95868
  timeoutMs,
95775
95869
  statusbarPath,
95776
- completedAtMs: null
95870
+ completedAtMs: null,
95871
+ interactive
95777
95872
  };
95778
95873
  const pollInterval = setInterval(() => {
95779
95874
  pollStatus(pollState);
95780
95875
  }, 500);
95781
95876
  const spawnArgs = ["-g", gridfilePath, "-S", statusbarPath];
95782
- if (mux.kind === "mtm") {
95783
- spawnArgs.push("-t", "xterm-256color");
95784
- } else {
95877
+ if (!interactive) {
95785
95878
  spawnArgs.push("-w");
95786
95879
  }
95787
- const proc = spawn3(mux.path, spawnArgs, {
95880
+ const proc = spawn3(magmuxPath, spawnArgs, {
95788
95881
  stdio: "inherit",
95789
95882
  env: { ...process.env }
95790
95883
  });
@@ -95844,7 +95937,7 @@ Options (run / run-and-judge):
95844
95937
  --models <a,b,...> Comma-separated model IDs to run
95845
95938
  --input <text> Task prompt (or create input.md in --path beforehand)
95846
95939
  --timeout <secs> Timeout per model in seconds (default: 300)
95847
- --grid Show all models in an mtm grid with live output + status bar
95940
+ --grid Show all models in a magmux grid with live output + status bar
95848
95941
 
95849
95942
  Options (judge / run-and-judge):
95850
95943
  --judges <a,b,...> Comma-separated judge model IDs (default: same as runners)
@@ -95861,11 +95954,13 @@ Examples:
95861
95954
  `);
95862
95955
  }
95863
95956
  async function teamCommand(args) {
95864
- const subcommand = args[0];
95865
- if (!subcommand || hasFlag(args, "--help") || hasFlag(args, "-h")) {
95957
+ if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
95866
95958
  printHelp2();
95867
95959
  process.exit(0);
95868
95960
  }
95961
+ const firstArg = args[0] ?? "";
95962
+ const legacySubs = ["run", "judge", "run-and-judge", "status"];
95963
+ const subcommand = legacySubs.includes(firstArg) ? firstArg : "run";
95869
95964
  const rawSessionPath = getFlag(args, "--path") ?? ".";
95870
95965
  let sessionPath;
95871
95966
  try {
@@ -95876,22 +95971,36 @@ async function teamCommand(args) {
95876
95971
  }
95877
95972
  const modelsRaw = getFlag(args, "--models");
95878
95973
  const judgesRaw = getFlag(args, "--judges");
95879
- const input = getFlag(args, "--input");
95974
+ const mode = getFlag(args, "--mode") ?? "default";
95880
95975
  const timeoutStr = getFlag(args, "--timeout");
95881
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
+ }
95882
95993
  const models = modelsRaw ? modelsRaw.split(",").map((m2) => m2.trim()).filter(Boolean) : [];
95883
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;
95884
95996
  switch (subcommand) {
95885
95997
  case "run": {
95886
95998
  if (models.length === 0) {
95887
- console.error("Error: --models is required for 'run'");
95999
+ console.error("Error: --models is required");
96000
+ printHelp2();
95888
96001
  process.exit(1);
95889
96002
  }
95890
- if (hasFlag(args, "--grid")) {
95891
- const { runWithGrid: runWithGrid2 } = await Promise.resolve().then(() => (init_team_grid(), exports_team_grid));
95892
- const gridStatus = await runWithGrid2(sessionPath, models, input ?? "", { timeout });
95893
- printStatus(gridStatus);
95894
- } else {
96003
+ if (effectiveMode === "json") {
95895
96004
  setupSession(sessionPath, models, input);
95896
96005
  const runStatus = await runModels(sessionPath, {
95897
96006
  timeout,
@@ -95901,17 +96010,22 @@ async function teamCommand(args) {
95901
96010
  }
95902
96011
  });
95903
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);
95904
96018
  }
95905
96019
  break;
95906
96020
  }
95907
96021
  case "judge": {
95908
- const verdict = await judgeResponses(sessionPath, { judges });
96022
+ await judgeResponses(sessionPath, { judges });
95909
96023
  console.log(readFileSync22(join28(sessionPath, "verdict.md"), "utf-8"));
95910
96024
  break;
95911
96025
  }
95912
96026
  case "run-and-judge": {
95913
96027
  if (models.length === 0) {
95914
- console.error("Error: --models is required for 'run-and-judge'");
96028
+ console.error("Error: --models is required");
95915
96029
  process.exit(1);
95916
96030
  }
95917
96031
  setupSession(sessionPath, models, input);
@@ -95928,15 +96042,10 @@ async function teamCommand(args) {
95928
96042
  break;
95929
96043
  }
95930
96044
  case "status": {
95931
- const status = getStatus(sessionPath);
95932
- printStatus(status);
96045
+ const statusResult = getStatus(sessionPath);
96046
+ printStatus(statusResult);
95933
96047
  break;
95934
96048
  }
95935
- default: {
95936
- console.error(`Unknown team subcommand: ${subcommand}`);
95937
- printHelp2();
95938
- process.exit(1);
95939
- }
95940
96049
  }
95941
96050
  }
95942
96051
  var init_team_cli = __esm(() => {
@@ -95950,7 +96059,7 @@ __export(exports_claude_runner, {
95950
96059
  checkClaudeInstalled: () => checkClaudeInstalled
95951
96060
  });
95952
96061
  import { spawn as spawn4 } from "child_process";
95953
- import { writeFileSync as writeFileSync15, unlinkSync as unlinkSync9, mkdirSync as mkdirSync14, existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
96062
+ import { writeFileSync as writeFileSync16, unlinkSync as unlinkSync9, mkdirSync as mkdirSync15, existsSync as existsSync28, readFileSync as readFileSync23 } from "fs";
95954
96063
  import { tmpdir as tmpdir2, homedir as homedir25 } from "os";
95955
96064
  import { join as join29 } from "path";
95956
96065
  function hasNativeAnthropicMapping(config3) {
@@ -96059,14 +96168,14 @@ process.stdin.on('end', () => {
96059
96168
  }
96060
96169
  });
96061
96170
  `;
96062
- writeFileSync15(scriptPath, script, "utf-8");
96171
+ writeFileSync16(scriptPath, script, "utf-8");
96063
96172
  return scriptPath;
96064
96173
  }
96065
96174
  function createTempSettingsFile(modelDisplay, port) {
96066
96175
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
96067
96176
  const claudishDir = join29(homeDir, ".claudish");
96068
96177
  try {
96069
- mkdirSync14(claudishDir, { recursive: true });
96178
+ mkdirSync15(claudishDir, { recursive: true });
96070
96179
  } catch {}
96071
96180
  const timestamp = Date.now();
96072
96181
  const tempPath = join29(claudishDir, `settings-${timestamp}.json`);
@@ -96092,7 +96201,7 @@ function createTempSettingsFile(modelDisplay, port) {
96092
96201
  padding: 0
96093
96202
  };
96094
96203
  const settings = { statusLine };
96095
- writeFileSync15(tempPath, JSON.stringify(settings, null, 2), "utf-8");
96204
+ writeFileSync16(tempPath, JSON.stringify(settings, null, 2), "utf-8");
96096
96205
  return { path: tempPath, statusLine };
96097
96206
  }
96098
96207
  function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
@@ -96110,7 +96219,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
96110
96219
  userSettings = JSON.parse(rawUserSettings);
96111
96220
  }
96112
96221
  userSettings.statusLine = statusLine;
96113
- writeFileSync15(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
96222
+ writeFileSync16(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
96114
96223
  } catch {
96115
96224
  if (!config3.quiet) {
96116
96225
  console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
@@ -96118,7 +96227,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
96118
96227
  }
96119
96228
  config3.claudeArgs.splice(idx, 2);
96120
96229
  }
96121
- async function runClaudeWithProxy(config3, proxyUrl, onCleanup, ptyDiagRunner) {
96230
+ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
96122
96231
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
96123
96232
  const modelId = config3.model || (hasProfileMappings || config3.monitor ? undefined : "unknown");
96124
96233
  const portMatch = proxyUrl.match(/:(\d+)/);
@@ -96205,28 +96314,20 @@ Or set CLAUDE_PATH to your custom installation:`);
96205
96314
  }
96206
96315
  const needsShell = isWindows2() && claudeBinary.endsWith(".cmd");
96207
96316
  const spawnCommand = needsShell ? `"${claudeBinary}"` : claudeBinary;
96208
- let exitCode;
96209
- if (config3.interactive && ptyDiagRunner) {
96210
- exitCode = await ptyDiagRunner.run(spawnCommand, claudeArgs, env2);
96211
- try {
96212
- unlinkSync9(tempSettingsPath);
96213
- } catch {}
96214
- } else {
96215
- const proc = spawn4(spawnCommand, claudeArgs, {
96216
- env: env2,
96217
- stdio: "inherit",
96218
- shell: needsShell
96219
- });
96220
- setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
96221
- exitCode = await new Promise((resolve4) => {
96222
- proc.on("exit", (code) => {
96223
- resolve4(code ?? 1);
96224
- });
96317
+ const proc = spawn4(spawnCommand, claudeArgs, {
96318
+ env: env2,
96319
+ stdio: "inherit",
96320
+ shell: needsShell
96321
+ });
96322
+ setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
96323
+ const exitCode = await new Promise((resolve4) => {
96324
+ proc.on("exit", (code) => {
96325
+ resolve4(code ?? 1);
96225
96326
  });
96226
- try {
96227
- unlinkSync9(tempSettingsPath);
96228
- } catch {}
96229
- }
96327
+ });
96328
+ try {
96329
+ unlinkSync9(tempSettingsPath);
96330
+ } catch {}
96230
96331
  return exitCode;
96231
96332
  }
96232
96333
  function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
@@ -96330,20 +96431,16 @@ var init_claude_runner = __esm(() => {
96330
96431
  var exports_diag_output = {};
96331
96432
  __export(exports_diag_output, {
96332
96433
  createDiagOutput: () => createDiagOutput,
96333
- TmuxDiagOutput: () => TmuxDiagOutput,
96334
- OpentUiDiagOutput: () => OpentUiDiagOutput,
96335
96434
  NullDiagOutput: () => NullDiagOutput,
96336
- MtmDiagOutput: () => MtmDiagOutput,
96337
96435
  LogFileDiagOutput: () => LogFileDiagOutput
96338
96436
  });
96339
- import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync15, writeFileSync as writeFileSync16, unlinkSync as unlinkSync10 } from "fs";
96340
- import { execFileSync } from "child_process";
96437
+ import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync16, writeFileSync as writeFileSync17, unlinkSync as unlinkSync10 } from "fs";
96341
96438
  import { homedir as homedir26 } from "os";
96342
96439
  import { join as join30 } from "path";
96343
96440
  function getClaudishDir() {
96344
96441
  const dir = join30(homedir26(), ".claudish");
96345
96442
  try {
96346
- mkdirSync15(dir, { recursive: true });
96443
+ mkdirSync16(dir, { recursive: true });
96347
96444
  } catch {}
96348
96445
  return dir;
96349
96446
  }
@@ -96357,7 +96454,7 @@ class LogFileDiagOutput {
96357
96454
  constructor() {
96358
96455
  this.logPath = getDiagLogPath();
96359
96456
  try {
96360
- writeFileSync16(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
96457
+ writeFileSync17(this.logPath, `--- claudish diag session ${new Date().toISOString()} ---
96361
96458
  `);
96362
96459
  } catch {}
96363
96460
  this.stream = createWriteStream3(this.logPath, { flags: "a" });
@@ -96384,30 +96481,6 @@ class LogFileDiagOutput {
96384
96481
  }
96385
96482
  }
96386
96483
 
96387
- class MtmDiagOutput {
96388
- runner;
96389
- constructor(runner) {
96390
- this.runner = runner;
96391
- }
96392
- write(msg) {
96393
- this.runner.write(msg);
96394
- }
96395
- cleanup() {}
96396
- }
96397
-
96398
- class OpentUiDiagOutput {
96399
- inner;
96400
- constructor(runner) {
96401
- this.inner = new MtmDiagOutput(runner);
96402
- }
96403
- write(msg) {
96404
- this.inner.write(msg);
96405
- }
96406
- cleanup() {
96407
- this.inner.cleanup();
96408
- }
96409
- }
96410
-
96411
96484
  class NullDiagOutput {
96412
96485
  write(_msg) {}
96413
96486
  cleanup() {}
@@ -96420,389 +96493,22 @@ function createDiagOutput(options) {
96420
96493
  if (mode === "off") {
96421
96494
  return new NullDiagOutput;
96422
96495
  }
96423
- const mtmRunner = options.mtmRunner ?? options.ptyRunner ?? null;
96424
- if (mode === "pty" || mode === "auto") {
96425
- if (mtmRunner) {
96426
- return new MtmDiagOutput(mtmRunner);
96427
- }
96428
- if (mode === "pty") {
96429
- return new LogFileDiagOutput;
96430
- }
96431
- }
96432
- if (mode === "tmux" || mode === "auto") {
96433
- if (process.env.TMUX) {
96434
- return new TmuxDiagOutput;
96435
- }
96436
- if (mode === "tmux") {
96437
- return new LogFileDiagOutput;
96438
- }
96439
- }
96440
96496
  return new LogFileDiagOutput;
96441
96497
  }
96442
- var TmuxDiagOutput;
96443
- var init_diag_output = __esm(() => {
96444
- TmuxDiagOutput = class TmuxDiagOutput extends LogFileDiagOutput {
96445
- paneId = null;
96446
- constructor() {
96447
- super();
96448
- this.openTmuxPane();
96449
- }
96450
- openTmuxPane() {
96451
- try {
96452
- const targetPane = process.env.TMUX_PANE || "";
96453
- const args = ["split-window", "-v", "-l", "5", "-d", "-P", "-F", "#{pane_id}"];
96454
- if (targetPane) {
96455
- args.push("-t", targetPane);
96456
- }
96457
- args.push("tail", "-f", this.logPath);
96458
- const output = execFileSync("tmux", args, {
96459
- encoding: "utf-8",
96460
- stdio: ["pipe", "pipe", "pipe"]
96461
- });
96462
- this.paneId = output.trim();
96463
- } catch {
96464
- this.paneId = null;
96465
- }
96466
- }
96467
- cleanup() {
96468
- if (this.paneId) {
96469
- try {
96470
- execFileSync("tmux", ["kill-pane", "-t", this.paneId], {
96471
- stdio: ["pipe", "pipe", "pipe"]
96472
- });
96473
- } catch {}
96474
- this.paneId = null;
96475
- }
96476
- super.cleanup();
96477
- }
96478
- };
96479
- });
96480
-
96481
- // src/pty-diag-runner.ts
96482
- var exports_pty_diag_runner = {};
96483
- __export(exports_pty_diag_runner, {
96484
- tryCreatePtyRunner: () => tryCreatePtyRunner,
96485
- tryCreateMtmRunner: () => tryCreateMtmRunner,
96486
- PtyDiagRunner: () => MtmDiagRunner,
96487
- MtmDiagRunner: () => MtmDiagRunner
96488
- });
96489
- import { spawn as spawn5 } from "child_process";
96490
- import {
96491
- appendFileSync as appendFileSync2,
96492
- createWriteStream as createWriteStream4,
96493
- existsSync as existsSync29,
96494
- mkdirSync as mkdirSync16,
96495
- readFileSync as readFileSync24,
96496
- unlinkSync as unlinkSync11
96497
- } from "fs";
96498
- import { homedir as homedir27 } from "os";
96499
- import { dirname as dirname7, join as join31 } from "path";
96500
- import { execSync as execSync4 } from "child_process";
96501
- import { fileURLToPath as fileURLToPath7 } from "url";
96502
-
96503
- class MtmDiagRunner {
96504
- mtmProc = null;
96505
- logPath;
96506
- statusPath;
96507
- logStream = null;
96508
- constructor() {
96509
- const dir = join31(homedir27(), ".claudish");
96510
- try {
96511
- mkdirSync16(dir, { recursive: true });
96512
- } catch {}
96513
- this.logPath = join31(dir, `diag-${process.pid}.log`);
96514
- this.statusPath = join31(dir, `status-${process.pid}.txt`);
96515
- this.logStream = createWriteStream4(this.logPath, { flags: "w" });
96516
- this.logStream.on("error", () => {});
96517
- }
96518
- async run(claudeCommand, claudeArgs, env2) {
96519
- const mtmBin = this.findMtmBinary();
96520
- const quotedArgs = claudeArgs.map((a) => shellQuote(a)).join(" ");
96521
- const claudeCmd = `${shellQuote(claudeCommand)} ${quotedArgs}`;
96522
- const mergedEnv = { ...process.env, ...env2 };
96523
- this.mtmProc = spawn5(mtmBin, ["-t", "xterm-256color", "-e", claudeCmd, "-S", this.statusPath, "-L", this.logPath], {
96524
- stdio: "inherit",
96525
- env: mergedEnv
96526
- });
96527
- const exitCode = await new Promise((resolve4) => {
96528
- this.mtmProc.on("exit", (code) => {
96529
- resolve4(code ?? 1);
96530
- });
96531
- this.mtmProc.on("error", (err) => {
96532
- if (this.logStream) {
96533
- try {
96534
- this.logStream.write(`[mtm] spawn error: ${err.message}
96535
- `);
96536
- } catch {}
96537
- }
96538
- resolve4(1);
96539
- });
96540
- });
96541
- this.cleanup();
96542
- return exitCode;
96543
- }
96544
- write(msg) {
96545
- if (!this.logStream)
96546
- return;
96547
- const timestamp = new Date().toISOString();
96548
- try {
96549
- this.logStream.write(`[${timestamp}] ${msg}
96550
- `);
96551
- } catch {}
96552
- const parsed = parseLogMessage(msg);
96553
- if (parsed.isError) {
96554
- this.errorCount++;
96555
- this.lastError = parsed.short;
96556
- if (parsed.provider)
96557
- this.provider = parsed.provider;
96558
- }
96559
- if (msg.includes("HANDLER STARTED") || msg.includes("=== Request")) {
96560
- this.requestCount++;
96561
- }
96562
- const rtMatch = msg.match(/(\d+)ms\b/);
96563
- if (rtMatch && msg.includes("Response")) {
96564
- const ms = parseInt(rtMatch[1], 10);
96565
- this.roundtripSamples.push(ms);
96566
- if (this.roundtripSamples.length > 20)
96567
- this.roundtripSamples.shift();
96568
- this.avgRoundtripMs = Math.round(this.roundtripSamples.reduce((a, b2) => a + b2, 0) / this.roundtripSamples.length);
96569
- }
96570
- if (msg.includes("Format:") || msg.includes("Transport:") || msg.includes("Translator:")) {
96571
- const parts = msg.split(":").slice(1).join(":").trim();
96572
- if (parts)
96573
- this.adapters = parts;
96574
- }
96575
- if (msg.includes("Auth refreshed") && msg.includes("tier:")) {
96576
- const tierMatch = msg.match(/tier:\s*(.+)$/);
96577
- if (tierMatch)
96578
- this.provider = tierMatch[1].trim();
96579
- }
96580
- if (msg.includes("[Fallback]") && msg.includes("succeeded")) {
96581
- const fbMatch = msg.match(/\[Fallback\]\s+(\S+)\s+succeeded/);
96582
- if (fbMatch)
96583
- this.provider = fbMatch[1];
96584
- }
96585
- if (msg.includes("Rate limited") && msg.includes("retrying")) {
96586
- this.lastError = msg.replace(/.*\]\s*/, "").substring(0, 60);
96587
- }
96588
- this.refreshStatusBar();
96589
- }
96590
- modelName = "";
96591
- provider = "";
96592
- port = "";
96593
- quotaRemaining;
96594
- tokenPollTimer = null;
96595
- lastError = "";
96596
- errorCount = 0;
96597
- requestCount = 0;
96598
- totalCost = 0;
96599
- avgRoundtripMs = 0;
96600
- roundtripSamples = [];
96601
- adapters = "";
96602
- setPort(port) {
96603
- this.port = String(port);
96604
- this.tokenPollTimer = setInterval(() => {
96605
- const changed = this.readTokenFile();
96606
- if (changed)
96607
- this.refreshStatusBar();
96608
- }, 3000);
96609
- }
96610
- setModel(name) {
96611
- this.modelName = name.includes("/") ? name.split("/").pop() : name;
96612
- if (name.includes("@")) {
96613
- this.provider = name.split("@")[0];
96614
- } else if (name.includes("/")) {
96615
- this.provider = name.split("/")[0];
96616
- }
96617
- }
96618
- readTokenFile() {
96619
- if (!this.port)
96620
- return false;
96621
- try {
96622
- const tokPath = join31(homedir27(), ".claudish", `tokens-${this.port}.json`);
96623
- const tok = JSON.parse(readFileSync24(tokPath, "utf-8"));
96624
- let changed = false;
96625
- if (typeof tok.quota_remaining === "number" && tok.quota_remaining !== this.quotaRemaining) {
96626
- this.quotaRemaining = tok.quota_remaining;
96627
- changed = true;
96628
- }
96629
- if (tok.provider_name && tok.provider_name !== this.provider) {
96630
- this.provider = tok.provider_name;
96631
- changed = true;
96632
- }
96633
- return changed;
96634
- } catch {
96635
- return false;
96636
- }
96637
- }
96638
- refreshStatusBar() {
96639
- this.readTokenFile();
96640
- const bar = renderStatusBar({
96641
- model: this.modelName,
96642
- provider: this.provider,
96643
- errorCount: this.errorCount,
96644
- lastError: this.lastError,
96645
- requestCount: this.requestCount,
96646
- avgRoundtripMs: this.avgRoundtripMs,
96647
- quotaRemaining: this.quotaRemaining
96648
- });
96649
- try {
96650
- appendFileSync2(this.statusPath, bar + `
96651
- `);
96652
- } catch {}
96653
- }
96654
- getLogPath() {
96655
- return this.logPath;
96656
- }
96657
- cleanup() {
96658
- if (this.tokenPollTimer) {
96659
- clearInterval(this.tokenPollTimer);
96660
- this.tokenPollTimer = null;
96661
- }
96662
- if (this.logStream) {
96663
- try {
96664
- this.logStream.end();
96665
- } catch {}
96666
- this.logStream = null;
96667
- }
96668
- try {
96669
- unlinkSync11(this.logPath);
96670
- } catch {}
96671
- try {
96672
- unlinkSync11(this.statusPath);
96673
- } catch {}
96674
- if (this.mtmProc) {
96675
- try {
96676
- this.mtmProc.kill();
96677
- } catch {}
96678
- this.mtmProc = null;
96679
- }
96680
- }
96681
- findMtmBinary() {
96682
- const thisFile = fileURLToPath7(import.meta.url);
96683
- const thisDir = dirname7(thisFile);
96684
- const platform3 = process.platform;
96685
- const arch = process.arch;
96686
- const pkgRoot = join31(thisDir, "..");
96687
- const bundledPlatform = join31(pkgRoot, "native", "mtm", `mtm-${platform3}-${arch}`);
96688
- if (existsSync29(bundledPlatform))
96689
- return bundledPlatform;
96690
- const builtDev = join31(pkgRoot, "native", "mtm", "mtm");
96691
- if (existsSync29(builtDev))
96692
- return builtDev;
96693
- try {
96694
- const result = execSync4("which mtm", { encoding: "utf-8" }).trim();
96695
- if (result && this.isMtmFork(result))
96696
- return result;
96697
- } catch {}
96698
- throw new Error("mtm binary not found. Build it with: cd packages/cli/native/mtm && make");
96699
- }
96700
- isMtmFork(binPath) {
96701
- try {
96702
- const output = execSync4(`"${binPath}" --help 2>&1 || true`, {
96703
- encoding: "utf-8",
96704
- timeout: 2000
96705
- });
96706
- return output.includes("-e ");
96707
- } catch {
96708
- return false;
96709
- }
96710
- }
96711
- }
96712
- function shellQuote(s) {
96713
- return "'" + s.replace(/'/g, "'\\''") + "'";
96714
- }
96715
- function renderStatusBar(state) {
96716
- const { model, provider, errorCount, lastError, quotaRemaining } = state;
96717
- const parts = [];
96718
- parts.push("M: claudish ");
96719
- if (model)
96720
- parts.push(`C: ${model} `);
96721
- if (provider)
96722
- parts.push(`D: ${provider}`);
96723
- if (errorCount > 0) {
96724
- const errLabel = errorCount === 1 ? "\u26A0 1 error" : `\u26A0 ${errorCount} errors`;
96725
- parts.push(`R: ${errLabel} `);
96726
- if (lastError)
96727
- parts.push(`D: ${lastError}`);
96728
- }
96729
- if (typeof quotaRemaining === "number") {
96730
- const usedPct = Math.round((1 - quotaRemaining) * 100);
96731
- const barWidth = 8;
96732
- const usedCols = Math.max(usedPct > 0 ? 1 : 0, Math.round(usedPct / 100 * barWidth));
96733
- const freeCols = barWidth - usedCols;
96734
- const bar = "\u2588".repeat(usedCols) + "\u2591".repeat(freeCols);
96735
- const color = usedPct < 50 ? "g" : usedPct < 80 ? "y" : "r";
96736
- parts.push(`${color}: ${bar} ${usedPct}%`);
96737
- }
96738
- return parts.join("\t");
96739
- }
96740
- function parseLogMessage(msg) {
96741
- const providerMatch = msg.match(/\[(?!Fallback|Streaming|Auto-route|SSE)([^\]]+)\]/);
96742
- const provider = providerMatch?.[1];
96743
- if (msg.includes("All") && msg.includes("failed")) {
96744
- const countMatch = msg.match(/All (\d+)/);
96745
- return { isError: true, short: `all ${countMatch?.[1] || ""} providers failed`, provider };
96746
- }
96747
- if (msg.includes("[Fallback]")) {
96748
- if (msg.includes("succeeded")) {
96749
- const n = msg.match(/after (\d+)/)?.[1] || "?";
96750
- return { isError: false, short: `succeeded after ${n} retries`, provider };
96751
- }
96752
- const failMatch = msg.match(/\]\s*(.+?)\s+failed/);
96753
- return {
96754
- isError: false,
96755
- short: failMatch ? `${failMatch[1]} failed, retrying` : "fallback",
96756
- provider
96757
- };
96758
- }
96759
- const httpMatch = msg.match(/HTTP (\d{3})/);
96760
- if (httpMatch) {
96761
- const jsonMatch = msg.match(/"message"\s*:\s*"([^"]+)"/);
96762
- if (jsonMatch?.[1]) {
96763
- const detail = jsonMatch[1].replace(/is not a valid model ID/, "invalid model").replace(/Provider returned error/, "provider error");
96764
- return { isError: true, short: detail, provider };
96765
- }
96766
- const hintMatch = msg.match(/HTTP \d{3}\.\s*(.+?)\.?\s*$/);
96767
- if (hintMatch?.[1]) {
96768
- return { isError: true, short: hintMatch[1], provider };
96769
- }
96770
- return { isError: true, short: `HTTP ${httpMatch[1]}`, provider };
96771
- }
96772
- if (msg.toLowerCase().includes("error")) {
96773
- const short = msg.replace(/^Error\s*\[[^\]]+\]:\s*/, "").replace(/\.\s*$/, "");
96774
- return { isError: true, short: short.length > 80 ? short.slice(0, 79) + "\u2026" : short, provider };
96775
- }
96776
- return { isError: false, short: msg.length > 80 ? msg.slice(0, 79) + "\u2026" : msg };
96777
- }
96778
- async function tryCreateMtmRunner() {
96779
- if (process.env.MTM)
96780
- return null;
96781
- try {
96782
- const runner = new MtmDiagRunner;
96783
- runner.findMtmBinary();
96784
- return runner;
96785
- } catch {
96786
- return null;
96787
- }
96788
- }
96789
- var tryCreatePtyRunner;
96790
- var init_pty_diag_runner = __esm(() => {
96791
- tryCreatePtyRunner = tryCreateMtmRunner;
96792
- });
96498
+ var init_diag_output = () => {};
96793
96499
 
96794
96500
  // src/index.ts
96795
96501
  var import_dotenv3 = __toESM(require_main(), 1);
96796
- import { existsSync as existsSync30, readFileSync as readFileSync25 } from "fs";
96797
- import { homedir as homedir28 } from "os";
96798
- import { join as join32 } from "path";
96502
+ import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
96503
+ import { homedir as homedir27 } from "os";
96504
+ import { join as join31 } from "path";
96799
96505
  import_dotenv3.config({ quiet: true });
96800
96506
  function loadStoredApiKeys() {
96801
96507
  try {
96802
- const configPath = join32(homedir28(), ".claudish", "config.json");
96803
- if (!existsSync30(configPath))
96508
+ const configPath = join31(homedir27(), ".claudish", "config.json");
96509
+ if (!existsSync29(configPath))
96804
96510
  return;
96805
- const raw2 = readFileSync25(configPath, "utf-8");
96511
+ const raw2 = readFileSync24(configPath, "utf-8");
96806
96512
  const cfg = JSON.parse(raw2);
96807
96513
  if (cfg.apiKeys) {
96808
96514
  for (const [envVar, value] of Object.entries(cfg.apiKeys)) {
@@ -96903,8 +96609,7 @@ async function runCli() {
96903
96609
  getMissingKeysError: getMissingKeysError2
96904
96610
  } = await Promise.resolve().then(() => (init_provider_resolver(), exports_provider_resolver));
96905
96611
  const { initLogger: initLogger2, getLogFilePath: getLogFilePath2, getAlwaysOnLogPath: getAlwaysOnLogPath2, setDiagOutput: setDiagOutput2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
96906
- const { createDiagOutput: createDiagOutput2, LogFileDiagOutput: LogFileDiagOutput2 } = await Promise.resolve().then(() => (init_diag_output(), exports_diag_output));
96907
- const { tryCreateMtmRunner: tryCreateMtmRunner2 } = await Promise.resolve().then(() => (init_pty_diag_runner(), exports_pty_diag_runner));
96612
+ const { createDiagOutput: createDiagOutput2 } = await Promise.resolve().then(() => (init_diag_output(), exports_diag_output));
96908
96613
  const { findAvailablePort: findAvailablePort2 } = await Promise.resolve().then(() => (init_port_manager(), exports_port_manager));
96909
96614
  const { createProxyServer: createProxyServer2 } = await Promise.resolve().then(() => (init_proxy_server(), exports_proxy_server));
96910
96615
  const { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
@@ -97059,27 +96764,16 @@ async function runCli() {
97059
96764
  quiet: cliConfig.quiet,
97060
96765
  isInteractive: cliConfig.interactive
97061
96766
  });
97062
- const needsMtm = cliConfig.interactive && (cliConfig.diagMode === "auto" || cliConfig.diagMode === "pty");
97063
- const mtmRunner = needsMtm ? await tryCreateMtmRunner2() : null;
97064
- if (mtmRunner) {
97065
- if (explicitModel)
97066
- mtmRunner.setModel(explicitModel);
97067
- mtmRunner.setPort(port);
97068
- }
97069
96767
  const diag = createDiagOutput2({
97070
96768
  interactive: cliConfig.interactive,
97071
- mtmRunner,
97072
96769
  diagMode: cliConfig.diagMode
97073
96770
  });
97074
96771
  if (cliConfig.interactive) {
97075
96772
  setDiagOutput2(diag);
97076
- if (!mtmRunner && !process.env.TMUX && !cliConfig.quiet && diag instanceof LogFileDiagOutput2) {
97077
- console.log(`[claudish] Diagnostic log: ${diag.getLogPath()}`);
97078
- }
97079
96773
  }
97080
96774
  let exitCode = 0;
97081
96775
  try {
97082
- exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup(), mtmRunner);
96776
+ exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup());
97083
96777
  } finally {
97084
96778
  setDiagOutput2(null);
97085
96779
  diag.cleanup();