claudish 5.3.0 → 5.4.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
@@ -27484,6 +27484,7 @@ __export(exports_logger, {
27484
27484
  setLogLevel: () => setLogLevel,
27485
27485
  maskCredential: () => maskCredential,
27486
27486
  logStructured: () => logStructured,
27487
+ logStderr: () => logStderr,
27487
27488
  log: () => log,
27488
27489
  isLoggingEnabled: () => isLoggingEnabled,
27489
27490
  initLogger: () => initLogger,
@@ -27557,6 +27558,11 @@ function log(message, forceConsole = false) {
27557
27558
  console.log(message);
27558
27559
  }
27559
27560
  }
27561
+ function logStderr(message) {
27562
+ process.stderr.write(`[claudish] ${message}
27563
+ `);
27564
+ log(message);
27565
+ }
27560
27566
  function getLogFilePath() {
27561
27567
  return logFilePath;
27562
27568
  }
@@ -28463,11 +28469,15 @@ function loadConfig() {
28463
28469
  try {
28464
28470
  const content = readFileSync4(CONFIG_FILE, "utf-8");
28465
28471
  const config3 = JSON.parse(content);
28466
- return {
28472
+ const merged = {
28467
28473
  version: config3.version || DEFAULT_CONFIG.version,
28468
28474
  defaultProfile: config3.defaultProfile || DEFAULT_CONFIG.defaultProfile,
28469
28475
  profiles: config3.profiles || DEFAULT_CONFIG.profiles
28470
28476
  };
28477
+ if (config3.telemetry !== undefined) {
28478
+ merged.telemetry = config3.telemetry;
28479
+ }
28480
+ return merged;
28471
28481
  } catch (error46) {
28472
28482
  console.error(`Warning: Failed to load config, using defaults: ${error46}`);
28473
28483
  return { ...DEFAULT_CONFIG };
@@ -32635,6 +32645,433 @@ var init_profile_commands = __esm(() => {
32635
32645
  init_dist8();
32636
32646
  });
32637
32647
 
32648
+ // src/telemetry.ts
32649
+ var exports_telemetry = {};
32650
+ __export(exports_telemetry, {
32651
+ sanitizeMessage: () => sanitizeMessage,
32652
+ runConsentPrompt: () => runConsentPrompt,
32653
+ reportError: () => reportError,
32654
+ initTelemetry: () => initTelemetry,
32655
+ handleTelemetryCommand: () => handleTelemetryCommand,
32656
+ enforceReportSize: () => enforceReportSize,
32657
+ detectRuntime: () => detectRuntime,
32658
+ detectInstallMethod: () => detectInstallMethod,
32659
+ classifyError: () => classifyError,
32660
+ buildReport: () => buildReport
32661
+ });
32662
+ import { randomBytes as randomBytes3 } from "node:crypto";
32663
+ import { createRequire as createRequire2 } from "node:module";
32664
+ function getVersion() {
32665
+ try {
32666
+ const require2 = createRequire2(import.meta.url);
32667
+ const pkg = require2("../package.json");
32668
+ return pkg.version ?? "unknown";
32669
+ } catch {
32670
+ return "unknown";
32671
+ }
32672
+ }
32673
+ function detectRuntime() {
32674
+ if (process.versions.bun) {
32675
+ const major2 = process.versions.bun.split(".").slice(0, 2).join(".");
32676
+ return `bun-${major2}`;
32677
+ }
32678
+ const major = process.versions.node?.split(".")[0] ?? "unknown";
32679
+ return `node-${major}`;
32680
+ }
32681
+ function detectInstallMethod() {
32682
+ const scriptPath = process.argv[1] || "";
32683
+ if (scriptPath.includes("/.bun/"))
32684
+ return "bun";
32685
+ if (scriptPath.includes("/Cellar/") || scriptPath.includes("/homebrew/"))
32686
+ return "homebrew";
32687
+ if (scriptPath.includes("/node_modules/") || scriptPath.includes("/.nvm/") || scriptPath.includes("/npm/"))
32688
+ return "npm";
32689
+ return "binary";
32690
+ }
32691
+ function sanitizeMessage(msg) {
32692
+ if (typeof msg !== "string")
32693
+ return "<non-string>";
32694
+ let s = msg;
32695
+ s = s.replace(/\?[^\s"'`]*/g, "?<redacted>");
32696
+ s = s.replace(/\/(?:home|Users)\/[^\s"'`]+/g, "<path>");
32697
+ s = s.replace(/[A-Za-z]:\\[Uu]sers\\[^\s"'`]+/g, "<path>");
32698
+ s = s.replace(/\/(?:var|tmp|private|opt|etc)\/[^\s"'`]+/g, "<path>");
32699
+ s = s.replace(/~\/[^\s]*/g, "<path>");
32700
+ s = s.replace(/localhost:(\d+)/g, "localhost:<port>");
32701
+ s = s.replace(/127\.0\.0\.1:(\d+)/g, "localhost:<port>");
32702
+ s = s.replace(/\b(?!127\.0\.0\.1)(\d{1,3}\.){3}\d{1,3}\b/g, "<host>");
32703
+ s = s.replace(/\[[0-9a-fA-F:]{4,}\]/g, "<host>");
32704
+ s = s.replace(/https?:\/\/([a-zA-Z0-9.-]+)(:\d+)?/g, (match, host) => {
32705
+ const lowerHost = host.toLowerCase();
32706
+ for (const pub of KNOWN_PUBLIC_HOSTS) {
32707
+ if (lowerHost === pub || lowerHost.endsWith("." + pub)) {
32708
+ return match;
32709
+ }
32710
+ }
32711
+ return "https://<host>";
32712
+ });
32713
+ s = s.replace(/Bearer\s+[^\s"']+/gi, "Bearer <credential>");
32714
+ s = s.replace(/[Aa]uthorization:\s*[^\s"']+/g, "Authorization: <credential>");
32715
+ s = s.replace(/\beyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/g, "<credential>");
32716
+ s = s.replace(/\bsk-[a-zA-Z0-9_\-]{10,}/g, "<credential>");
32717
+ s = s.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "<email>");
32718
+ s = s.replace(/[a-zA-Z0-9+\-_]{20,}={0,2}/g, "<credential>");
32719
+ if (s.length > 500) {
32720
+ s = s.slice(0, 497) + "...";
32721
+ }
32722
+ return s;
32723
+ }
32724
+ function sanitizeModelId(modelId, providerName) {
32725
+ if (PUBLIC_PROVIDERS.has(providerName)) {
32726
+ return modelId;
32727
+ }
32728
+ const atIdx = modelId.indexOf("@");
32729
+ if (atIdx !== -1) {
32730
+ return modelId.slice(0, atIdx + 1) + "<custom>";
32731
+ }
32732
+ return "<local-model>";
32733
+ }
32734
+ function classifyError(error46, httpStatus, errorText) {
32735
+ if (error46 && typeof error46 === "object") {
32736
+ const code = error46.code ?? error46.cause?.code;
32737
+ if (code === "ECONNREFUSED")
32738
+ return { error_class: "connection", error_code: "econnrefused" };
32739
+ if (code === "ECONNRESET")
32740
+ return { error_class: "connection", error_code: "econnreset" };
32741
+ if (code === "ETIMEDOUT")
32742
+ return { error_class: "connection", error_code: "timeout" };
32743
+ }
32744
+ if (error46 instanceof Error && error46.name === "AbortError") {
32745
+ return { error_class: "connection", error_code: "timeout" };
32746
+ }
32747
+ if (httpStatus !== undefined) {
32748
+ if (httpStatus === 400) {
32749
+ const lower = errorText?.toLowerCase() ?? "";
32750
+ if (lower.includes("context") || lower.includes("too long") || lower.includes("token")) {
32751
+ return { error_class: "http_error", error_code: "context_length_exceeded" };
32752
+ }
32753
+ if (lower.includes("unsupported content type") || lower.includes("unsupported_content_type")) {
32754
+ return { error_class: "http_error", error_code: "unsupported_content_type" };
32755
+ }
32756
+ return { error_class: "http_error", error_code: "bad_request_400" };
32757
+ }
32758
+ if (httpStatus === 401)
32759
+ return { error_class: "auth", error_code: "unauthorized_401" };
32760
+ if (httpStatus === 403)
32761
+ return { error_class: "auth", error_code: "forbidden_403" };
32762
+ if (httpStatus === 404)
32763
+ return { error_class: "http_error", error_code: "not_found_404" };
32764
+ if (httpStatus === 429)
32765
+ return { error_class: "rate_limit", error_code: "rate_limited_429" };
32766
+ if (httpStatus === 503)
32767
+ return { error_class: "overload", error_code: "service_unavailable_503" };
32768
+ if (httpStatus >= 500)
32769
+ return { error_class: "http_error", error_code: "server_error_5xx" };
32770
+ if (httpStatus >= 400)
32771
+ return { error_class: "http_error", error_code: `http_error_${httpStatus}` };
32772
+ }
32773
+ const msg = error46 instanceof Error ? error46.message.toLowerCase() : "";
32774
+ if (msg.includes("oauth") || msg.includes("token expired") || msg.includes("invalid token") || msg.includes("refresh token") || msg.includes("auth")) {
32775
+ return { error_class: "auth", error_code: "oauth_refresh_failed" };
32776
+ }
32777
+ if (msg.includes("json") || msg.includes("parse")) {
32778
+ return { error_class: "stream", error_code: "json_parse_error" };
32779
+ }
32780
+ if (msg.includes("stream")) {
32781
+ return { error_class: "stream", error_code: "stream_parse_error" };
32782
+ }
32783
+ if (msg.includes("config") || msg.includes("missing") || msg.includes("api key")) {
32784
+ return { error_class: "config", error_code: "config_error" };
32785
+ }
32786
+ return { error_class: "unknown", error_code: "unknown_error" };
32787
+ }
32788
+ function buildReport(ctx) {
32789
+ const { error_class, error_code } = classifyError(ctx.error, ctx.httpStatus, ctx.error instanceof Error ? ctx.error.message : String(ctx.error));
32790
+ let rawMessage;
32791
+ if (ctx.error instanceof Error) {
32792
+ rawMessage = ctx.error.message;
32793
+ } else if (typeof ctx.error === "string") {
32794
+ rawMessage = ctx.error;
32795
+ } else {
32796
+ rawMessage = String(ctx.error);
32797
+ }
32798
+ const report = {
32799
+ schema_version: 1,
32800
+ claudish_version: claudishVersion,
32801
+ install_method: installMethod,
32802
+ error_class,
32803
+ error_code,
32804
+ error_message_template: sanitizeMessage(rawMessage),
32805
+ provider_name: ctx.providerName,
32806
+ model_id: sanitizeModelId(ctx.modelId, ctx.providerName),
32807
+ stream_format: ctx.streamFormat,
32808
+ http_status: ctx.httpStatus ?? null,
32809
+ is_streaming: ctx.isStreaming,
32810
+ retry_attempted: ctx.retryAttempted,
32811
+ session_id: sessionId,
32812
+ timestamp: new Date().toISOString(),
32813
+ platform: process.platform,
32814
+ node_runtime: detectRuntime()
32815
+ };
32816
+ if (ctx.modelMappingRole !== undefined)
32817
+ report.model_mapping_role = ctx.modelMappingRole;
32818
+ if (ctx.concurrency !== undefined)
32819
+ report.concurrency = ctx.concurrency;
32820
+ if (ctx.adapterName !== undefined)
32821
+ report.adapter_name = ctx.adapterName;
32822
+ if (ctx.authType !== undefined)
32823
+ report.auth_type = ctx.authType;
32824
+ if (ctx.contextWindow !== undefined)
32825
+ report.context_window = ctx.contextWindow;
32826
+ if (ctx.providerErrorType !== undefined)
32827
+ report.provider_error_type = ctx.providerErrorType;
32828
+ return report;
32829
+ }
32830
+ function enforceReportSize(report) {
32831
+ let serialized = JSON.stringify(report);
32832
+ if (serialized.length <= MAX_REPORT_BYTES)
32833
+ return serialized;
32834
+ let msg = report.error_message_template;
32835
+ while (serialized.length > MAX_REPORT_BYTES && msg.length > 0) {
32836
+ msg = msg.slice(0, Math.max(0, msg.length - 50));
32837
+ const trimmed = { ...report, error_message_template: msg + "..." };
32838
+ serialized = JSON.stringify(trimmed);
32839
+ }
32840
+ return serialized.length <= MAX_REPORT_BYTES ? serialized : null;
32841
+ }
32842
+ async function sendReport(report) {
32843
+ try {
32844
+ const serialized = enforceReportSize(report);
32845
+ if (serialized === null)
32846
+ return;
32847
+ const controller = new AbortController;
32848
+ const timeout = setTimeout(() => controller.abort(), 3000);
32849
+ try {
32850
+ await fetch(TELEMETRY_ENDPOINT, {
32851
+ method: "POST",
32852
+ headers: { "Content-Type": "application/json" },
32853
+ body: serialized,
32854
+ signal: controller.signal
32855
+ });
32856
+ } finally {
32857
+ clearTimeout(timeout);
32858
+ }
32859
+ } catch {
32860
+ log("[Telemetry] Failed to send report (silently discarded)");
32861
+ }
32862
+ }
32863
+ function showConsentPromptAsync(ctx) {
32864
+ if (consentPromptActive)
32865
+ return;
32866
+ try {
32867
+ const profileConfig = loadConfig();
32868
+ if (profileConfig.telemetry?.askedAt !== undefined)
32869
+ return;
32870
+ } catch {
32871
+ return;
32872
+ }
32873
+ consentPromptActive = true;
32874
+ runConsentPrompt(ctx).catch(() => {
32875
+ consentPromptActive = false;
32876
+ });
32877
+ }
32878
+ async function runConsentPrompt(ctx) {
32879
+ const { createInterface: createInterface2 } = await import("node:readline");
32880
+ const errorSummary = classifyError(ctx.error, ctx.httpStatus);
32881
+ process.stderr.write(`
32882
+ [claudish] An error occurred: ` + errorSummary.error_code + `
32883
+ `);
32884
+ process.stderr.write(`Help improve claudish by sending an anonymous error report?
32885
+ Sends: version, error type, provider, model, platform.
32886
+ Does NOT send: prompts, paths, API keys, or credentials.
32887
+ Disable anytime: claudish telemetry off
32888
+ `);
32889
+ const answer = await new Promise((resolve) => {
32890
+ const rl = createInterface2({ input: process.stdin, output: process.stderr });
32891
+ rl.question("Send anonymous error report? [y/N] ", (ans) => {
32892
+ rl.close();
32893
+ resolve(ans.trim().toLowerCase());
32894
+ });
32895
+ });
32896
+ const accepted = answer === "y" || answer === "yes";
32897
+ try {
32898
+ const profileConfig = loadConfig();
32899
+ profileConfig.telemetry = {
32900
+ enabled: accepted,
32901
+ askedAt: new Date().toISOString(),
32902
+ promptedVersion: claudishVersion
32903
+ };
32904
+ saveConfig(profileConfig);
32905
+ consentEnabled = accepted;
32906
+ } catch {}
32907
+ if (accepted) {
32908
+ process.stderr.write(`[claudish] Error reporting enabled. Thank you!
32909
+ `);
32910
+ try {
32911
+ const report = buildReport(ctx);
32912
+ sendReport(report);
32913
+ } catch {}
32914
+ } else {
32915
+ process.stderr.write(`[claudish] Error reporting disabled. You can enable it later: claudish telemetry on
32916
+ `);
32917
+ }
32918
+ consentPromptActive = false;
32919
+ }
32920
+ function initTelemetry(config3) {
32921
+ if (initialized)
32922
+ return;
32923
+ initialized = true;
32924
+ const envOverride = process.env.CLAUDISH_TELEMETRY;
32925
+ if (envOverride === "0" || envOverride === "false" || envOverride === "off") {
32926
+ consentEnabled = false;
32927
+ return;
32928
+ }
32929
+ try {
32930
+ const profileConfig = loadConfig();
32931
+ consentEnabled = profileConfig.telemetry?.enabled ?? false;
32932
+ } catch {
32933
+ consentEnabled = false;
32934
+ }
32935
+ sessionId = randomBytes3(8).toString("hex");
32936
+ claudishVersion = getVersion();
32937
+ installMethod = detectInstallMethod();
32938
+ }
32939
+ function reportError(ctx) {
32940
+ if (!initialized || !consentEnabled) {
32941
+ if (initialized && !consentEnabled && ctx.isInteractive && process.stderr.isTTY) {
32942
+ showConsentPromptAsync(ctx);
32943
+ }
32944
+ return;
32945
+ }
32946
+ const envOverride = process.env.CLAUDISH_TELEMETRY;
32947
+ if (envOverride === "0" || envOverride === "false" || envOverride === "off") {
32948
+ return;
32949
+ }
32950
+ try {
32951
+ const report = buildReport(ctx);
32952
+ sendReport(report);
32953
+ } catch {
32954
+ log("[Telemetry] Error building report (silently discarded)");
32955
+ }
32956
+ }
32957
+ async function handleTelemetryCommand(subcommand) {
32958
+ switch (subcommand) {
32959
+ case "on": {
32960
+ const cfg = loadConfig();
32961
+ cfg.telemetry = {
32962
+ ...cfg.telemetry ?? {},
32963
+ enabled: true,
32964
+ askedAt: cfg.telemetry?.askedAt ?? new Date().toISOString(),
32965
+ promptedVersion: claudishVersion || getVersion()
32966
+ };
32967
+ saveConfig(cfg);
32968
+ process.stderr.write(`[claudish] Telemetry enabled. Anonymous error reports will be sent.
32969
+ `);
32970
+ process.exit(0);
32971
+ }
32972
+ case "off": {
32973
+ const cfg = loadConfig();
32974
+ cfg.telemetry = {
32975
+ ...cfg.telemetry ?? {},
32976
+ enabled: false,
32977
+ askedAt: cfg.telemetry?.askedAt ?? new Date().toISOString()
32978
+ };
32979
+ saveConfig(cfg);
32980
+ process.stderr.write(`[claudish] Telemetry disabled. No error reports will be sent.
32981
+ `);
32982
+ process.exit(0);
32983
+ }
32984
+ case "status": {
32985
+ const cfg = loadConfig();
32986
+ const t = cfg.telemetry;
32987
+ const envOverride = process.env.CLAUDISH_TELEMETRY;
32988
+ const envDisabled = envOverride === "0" || envOverride === "false" || envOverride === "off";
32989
+ if (envDisabled) {
32990
+ process.stderr.write(`[claudish] Telemetry: DISABLED (CLAUDISH_TELEMETRY env var override)
32991
+ `);
32992
+ } else if (!t) {
32993
+ process.stderr.write(`[claudish] Telemetry: NOT YET CONFIGURED (will prompt on first error)
32994
+ `);
32995
+ } else {
32996
+ const state = t.enabled ? "ENABLED" : "DISABLED";
32997
+ const asked = t.askedAt ? `(configured ${t.askedAt})` : "(never prompted)";
32998
+ process.stderr.write(`[claudish] Telemetry: ${state} ${asked}
32999
+ `);
33000
+ }
33001
+ process.stderr.write(`
33002
+ Data collected when enabled:
33003
+ `);
33004
+ process.stderr.write(` - Claudish version, error type, provider name, model ID
33005
+ `);
33006
+ process.stderr.write(` - Platform (darwin/linux/win32), runtime, install method
33007
+ `);
33008
+ process.stderr.write(` - Sanitized error message (no paths, no credentials)
33009
+ `);
33010
+ process.stderr.write(` - Ephemeral session ID (not stored, not correlatable)
33011
+ `);
33012
+ process.stderr.write(`
33013
+ Data NEVER collected:
33014
+ `);
33015
+ process.stderr.write(` - Prompt content, AI responses, tool names
33016
+ `);
33017
+ process.stderr.write(` - API keys, credentials, file paths, hostnames
33018
+ `);
33019
+ process.stderr.write(` - Your name, email, or IP address
33020
+ `);
33021
+ process.stderr.write(`
33022
+ Manage: claudish telemetry on|off|reset
33023
+ `);
33024
+ process.exit(0);
33025
+ }
33026
+ case "reset": {
33027
+ const cfg = loadConfig();
33028
+ if (cfg.telemetry) {
33029
+ delete cfg.telemetry.askedAt;
33030
+ cfg.telemetry.enabled = false;
33031
+ saveConfig(cfg);
33032
+ }
33033
+ process.stderr.write(`[claudish] Telemetry consent reset. You will be asked again on the next error.
33034
+ `);
33035
+ process.exit(0);
33036
+ }
33037
+ default:
33038
+ process.stderr.write(`[claudish] Unknown telemetry subcommand: "${subcommand}"
33039
+ Usage: claudish telemetry on|off|status|reset
33040
+ `);
33041
+ process.exit(1);
33042
+ }
33043
+ }
33044
+ var TELEMETRY_ENDPOINT = "https://claudish.com/v1/report", MAX_REPORT_BYTES = 4096, KNOWN_PUBLIC_HOSTS, PUBLIC_PROVIDERS, consentEnabled = false, sessionId = "", initialized = false, claudishVersion = "", installMethod = "unknown", consentPromptActive = false;
33045
+ var init_telemetry = __esm(() => {
33046
+ init_profile_config();
33047
+ init_logger();
33048
+ KNOWN_PUBLIC_HOSTS = new Set([
33049
+ "api.openai.com",
33050
+ "openrouter.ai",
33051
+ "generativelanguage.googleapis.com",
33052
+ "api.anthropic.com",
33053
+ "aip.googleapis.com",
33054
+ "api.mistral.ai",
33055
+ "api.cohere.ai"
33056
+ ]);
33057
+ PUBLIC_PROVIDERS = new Set([
33058
+ "openrouter",
33059
+ "gemini",
33060
+ "gemini-codeassist",
33061
+ "openai",
33062
+ "vertex",
33063
+ "ollamacloud",
33064
+ "anthropic",
33065
+ "minimax",
33066
+ "kimi",
33067
+ "glm",
33068
+ "zai",
33069
+ "minimax-coding",
33070
+ "kimi-coding",
33071
+ "glm-coding"
33072
+ ]);
33073
+ });
33074
+
32638
33075
  // src/config.ts
32639
33076
  var exports_config = {};
32640
33077
  __export(exports_config, {
@@ -34033,7 +34470,7 @@ __export(exports_cli, {
34033
34470
  requiresOpenRouterKey: () => requiresOpenRouterKey,
34034
34471
  parseArgs: () => parseArgs,
34035
34472
  isLocalModel: () => isLocalModel,
34036
- getVersion: () => getVersion,
34473
+ getVersion: () => getVersion2,
34037
34474
  getMissingKeysError: () => getMissingKeysError,
34038
34475
  getMissingKeyResolutions: () => getMissingKeyResolutions,
34039
34476
  getMissingKeyError: () => getMissingKeyError
@@ -34042,7 +34479,7 @@ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsS
34042
34479
  import { fileURLToPath as fileURLToPath4 } from "node:url";
34043
34480
  import { dirname as dirname4, join as join11 } from "node:path";
34044
34481
  import { homedir as homedir10 } from "node:os";
34045
- function getVersion() {
34482
+ function getVersion2() {
34046
34483
  return VERSION;
34047
34484
  }
34048
34485
  function clearAllModelCaches() {
@@ -35387,7 +35824,7 @@ async function fetchGLMCodingModels2() {
35387
35824
  return [];
35388
35825
  }
35389
35826
  }
35390
- var __filename5, __dirname5, VERSION = "5.3.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
35827
+ var __filename5, __dirname5, VERSION = "5.4.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
35391
35828
  var init_cli = __esm(() => {
35392
35829
  init_config();
35393
35830
  init_model_loader();
@@ -63117,21 +63554,30 @@ class ComposedHandler {
63117
63554
  provider;
63118
63555
  adapterManager;
63119
63556
  explicitAdapter;
63557
+ modelAdapter;
63120
63558
  middlewareManager;
63121
63559
  tokenTracker;
63122
63560
  targetModel;
63123
63561
  options;
63562
+ isInteractive;
63124
63563
  constructor(provider, targetModel, modelName, port, options = {}) {
63125
63564
  this.provider = provider;
63126
63565
  this.targetModel = targetModel;
63127
63566
  this.options = options;
63128
63567
  this.explicitAdapter = options.adapter;
63568
+ this.isInteractive = options.isInteractive ?? false;
63129
63569
  this.adapterManager = new AdapterManager(targetModel);
63570
+ const resolvedModelAdapter = this.adapterManager.getAdapter();
63571
+ if (resolvedModelAdapter.getName() !== "DefaultAdapter") {
63572
+ this.modelAdapter = resolvedModelAdapter;
63573
+ }
63130
63574
  this.middlewareManager = new MiddlewareManager;
63131
- this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
63575
+ if (targetModel.includes("gemini") || targetModel.includes("google/")) {
63576
+ this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
63577
+ }
63132
63578
  this.middlewareManager.initialize().catch((err) => log(`[ComposedHandler:${targetModel}] Middleware init error: ${err}`));
63133
63579
  this.tokenTracker = new TokenTracker(port, {
63134
- contextWindow: this.getAdapter().getContextWindow(),
63580
+ contextWindow: this.getModelContextWindow(),
63135
63581
  providerName: provider.name,
63136
63582
  modelName,
63137
63583
  providerDisplayName: provider.displayName
@@ -63140,6 +63586,12 @@ class ComposedHandler {
63140
63586
  getAdapter() {
63141
63587
  return this.explicitAdapter || this.adapterManager.getAdapter();
63142
63588
  }
63589
+ getModelContextWindow() {
63590
+ return this.modelAdapter?.getContextWindow() ?? this.getAdapter().getContextWindow();
63591
+ }
63592
+ getModelSupportsVision() {
63593
+ return this.modelAdapter?.supportsVision() ?? this.getAdapter().supportsVision();
63594
+ }
63143
63595
  async handle(c, payload) {
63144
63596
  const { claudeRequest, droppedParams } = transformOpenAIToClaude(payload);
63145
63597
  const adapter = this.getAdapter();
@@ -63147,7 +63599,7 @@ class ComposedHandler {
63147
63599
  adapter.reset();
63148
63600
  const messages = adapter.convertMessages(claudeRequest, filterIdentity);
63149
63601
  const tools = adapter.convertTools(claudeRequest, this.options.summarizeTools);
63150
- if (!adapter.supportsVision()) {
63602
+ if (!this.getModelSupportsVision()) {
63151
63603
  const imageBlocks = [];
63152
63604
  for (let msgIdx = 0;msgIdx < messages.length; msgIdx++) {
63153
63605
  const msg = messages[msgIdx];
@@ -63214,12 +63666,28 @@ class ComposedHandler {
63214
63666
  Object.assign(requestPayload, extraFields);
63215
63667
  }
63216
63668
  adapter.prepareRequest(requestPayload, claudeRequest);
63669
+ if (this.modelAdapter && this.modelAdapter !== adapter) {
63670
+ this.modelAdapter.prepareRequest(requestPayload, claudeRequest);
63671
+ }
63217
63672
  const toolNameMap = adapter.getToolNameMap();
63218
63673
  if (this.provider.refreshAuth) {
63219
63674
  try {
63220
63675
  await this.provider.refreshAuth();
63221
63676
  } catch (err) {
63222
63677
  log(`[${this.provider.displayName}] Auth/health check failed: ${err.message}`);
63678
+ logStderr(`Error [${this.provider.displayName}]: Auth/health check failed — ${err.message}. Check credentials and server.`);
63679
+ reportError({
63680
+ error: err,
63681
+ providerName: this.provider.name,
63682
+ providerDisplayName: this.provider.displayName,
63683
+ streamFormat: this.provider.streamFormat,
63684
+ modelId: this.targetModel,
63685
+ httpStatus: undefined,
63686
+ isStreaming: false,
63687
+ retryAttempted: false,
63688
+ isInteractive: this.isInteractive,
63689
+ authType: "oauth"
63690
+ });
63223
63691
  return c.json({ error: { type: "connection_error", message: err.message } }, 503);
63224
63692
  }
63225
63693
  if (this.provider.getContextWindow) {
@@ -63253,6 +63721,18 @@ class ComposedHandler {
63253
63721
  if (error46.code === "ECONNREFUSED" || error46.cause?.code === "ECONNREFUSED") {
63254
63722
  const msg = `Cannot connect to ${this.provider.displayName} at ${endpoint}. Make sure the server is running.`;
63255
63723
  log(`[${this.provider.displayName}] ${msg}`);
63724
+ logStderr(`Error: ${msg} Check the server is running.`);
63725
+ reportError({
63726
+ error: error46,
63727
+ providerName: this.provider.name,
63728
+ providerDisplayName: this.provider.displayName,
63729
+ streamFormat: this.provider.streamFormat,
63730
+ modelId: this.targetModel,
63731
+ httpStatus: undefined,
63732
+ isStreaming: false,
63733
+ retryAttempted: false,
63734
+ isInteractive: this.isInteractive
63735
+ });
63256
63736
  return c.json({ error: { type: "connection_error", message: msg } }, 503);
63257
63737
  }
63258
63738
  throw error46;
@@ -63277,15 +63757,63 @@ class ComposedHandler {
63277
63757
  } else {
63278
63758
  const errorText = await retryResp.text();
63279
63759
  log(`[${this.provider.displayName}] Retry failed: ${errorText}`);
63760
+ logStderr(`Error [${this.provider.displayName}]: HTTP ${retryResp.status} after auth retry. Check API key.`);
63761
+ reportError({
63762
+ error: new Error(errorText),
63763
+ providerName: this.provider.name,
63764
+ providerDisplayName: this.provider.displayName,
63765
+ streamFormat: this.provider.streamFormat,
63766
+ modelId: this.targetModel,
63767
+ httpStatus: retryResp.status,
63768
+ isStreaming: false,
63769
+ retryAttempted: true,
63770
+ isInteractive: this.isInteractive,
63771
+ authType: "oauth"
63772
+ });
63280
63773
  return c.json({ error: errorText }, retryResp.status);
63281
63774
  }
63282
63775
  } catch (err) {
63283
63776
  log(`[${this.provider.displayName}] Auth refresh failed: ${err.message}`);
63777
+ logStderr(`Error [${this.provider.displayName}]: Authentication failed — ${err.message}. Check API key.`);
63778
+ reportError({
63779
+ error: err,
63780
+ providerName: this.provider.name,
63781
+ providerDisplayName: this.provider.displayName,
63782
+ streamFormat: this.provider.streamFormat,
63783
+ modelId: this.targetModel,
63784
+ httpStatus: 401,
63785
+ isStreaming: false,
63786
+ retryAttempted: true,
63787
+ isInteractive: this.isInteractive,
63788
+ authType: "oauth"
63789
+ });
63284
63790
  return c.json({ error: { type: "authentication_error", message: err.message } }, 401);
63285
63791
  }
63286
63792
  } else {
63287
63793
  const errorText = await response.text();
63288
63794
  log(`[${this.provider.displayName}] Error: ${errorText}`);
63795
+ const hint = getRecoveryHint(response.status, errorText, this.provider.displayName);
63796
+ logStderr(`Error [${this.provider.displayName}]: HTTP ${response.status}. ${hint}`);
63797
+ let providerErrorType;
63798
+ try {
63799
+ const parsed = JSON.parse(errorText);
63800
+ providerErrorType = parsed?.error?.type || parsed?.type || parsed?.code || undefined;
63801
+ if (typeof providerErrorType === "string" && providerErrorType.length > 50) {
63802
+ providerErrorType = undefined;
63803
+ }
63804
+ } catch {}
63805
+ reportError({
63806
+ error: new Error(errorText),
63807
+ providerName: this.provider.name,
63808
+ providerDisplayName: this.provider.displayName,
63809
+ streamFormat: this.provider.streamFormat,
63810
+ modelId: this.targetModel,
63811
+ httpStatus: response.status,
63812
+ isStreaming: false,
63813
+ retryAttempted: false,
63814
+ isInteractive: this.isInteractive,
63815
+ providerErrorType
63816
+ });
63289
63817
  return c.json({ error: errorText }, response.status);
63290
63818
  }
63291
63819
  }
@@ -63360,6 +63888,34 @@ class ComposedHandler {
63360
63888
  }
63361
63889
  }
63362
63890
  }
63891
+ function getRecoveryHint(status, errorText, providerName) {
63892
+ const lower = errorText.toLowerCase();
63893
+ if (status === 503 || lower.includes("overloaded")) {
63894
+ return "Provider overloaded. Retry or use a different model.";
63895
+ }
63896
+ if (status === 429 || lower.includes("rate limit")) {
63897
+ return "Rate limited. Wait, reduce concurrency, or check plan limits.";
63898
+ }
63899
+ if (status === 401 || status === 403) {
63900
+ return "Check API key / OAuth credentials.";
63901
+ }
63902
+ if (status === 404) {
63903
+ return "Verify model name is correct.";
63904
+ }
63905
+ if (status === 400) {
63906
+ if (lower.includes("unsupported content type") || lower.includes("unsupported_content_type")) {
63907
+ return "Model doesn't support this content format. Try a different model.";
63908
+ }
63909
+ if (lower.includes("context") || lower.includes("too long") || lower.includes("token")) {
63910
+ return "Input too large. Reduce message history or use a larger-context model.";
63911
+ }
63912
+ return "Request format may be incompatible with provider.";
63913
+ }
63914
+ if (status >= 500) {
63915
+ return "Server error — retry after a brief wait.";
63916
+ }
63917
+ return `Unexpected HTTP ${status} from ${providerName}.`;
63918
+ }
63363
63919
  var init_composed_handler = __esm(() => {
63364
63920
  init_adapter_manager();
63365
63921
  init_middleware();
@@ -63373,6 +63929,7 @@ var init_composed_handler = __esm(() => {
63373
63929
  init_gemini_sse();
63374
63930
  init_logger();
63375
63931
  init_vision_proxy();
63932
+ init_telemetry();
63376
63933
  });
63377
63934
 
63378
63935
  // src/providers/transport/litellm.ts
@@ -64028,7 +64585,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64028
64585
  if (!openRouterHandlers.has(modelId)) {
64029
64586
  const orProvider = new OpenRouterProvider(openrouterApiKey || "");
64030
64587
  const orAdapter = new OpenRouterAdapter(modelId);
64031
- openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, { adapter: orAdapter }));
64588
+ openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, { adapter: orAdapter, isInteractive: options.isInteractive }));
64032
64589
  }
64033
64590
  return openRouterHandlers.get(modelId);
64034
64591
  };
@@ -64041,7 +64598,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64041
64598
  const modelId = targetModel.replace(/^poe:/, "");
64042
64599
  if (!poeHandlers.has(modelId)) {
64043
64600
  const poeTransport = new PoeProvider(poeApiKey);
64044
- poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port));
64601
+ poeHandlers.set(modelId, new ComposedHandler(poeTransport, modelId, modelId, port, { isInteractive: options.isInteractive }));
64045
64602
  }
64046
64603
  return poeHandlers.get(modelId);
64047
64604
  };
@@ -64061,7 +64618,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64061
64618
  const handler = new ComposedHandler(provider, resolved.modelName, resolved.modelName, port, {
64062
64619
  adapter,
64063
64620
  tokenStrategy: "local",
64064
- summarizeTools: options.summarizeTools
64621
+ summarizeTools: options.summarizeTools,
64622
+ isInteractive: options.isInteractive
64065
64623
  });
64066
64624
  localProviderHandlers.set(targetModel, handler);
64067
64625
  log(`[Proxy] Created local provider handler: ${resolved.provider.name}/${resolved.modelName}${resolved.concurrency !== undefined ? ` (concurrency: ${resolved.concurrency})` : ""}`);
@@ -64075,7 +64633,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64075
64633
  const handler = new ComposedHandler(provider, urlParsed.modelName, urlParsed.modelName, port, {
64076
64634
  adapter,
64077
64635
  tokenStrategy: "local",
64078
- summarizeTools: options.summarizeTools
64636
+ summarizeTools: options.summarizeTools,
64637
+ isInteractive: options.isInteractive
64079
64638
  });
64080
64639
  localProviderHandlers.set(targetModel, handler);
64081
64640
  log(`[Proxy] Created URL-based local provider handler: ${urlParsed.baseUrl}/${urlParsed.modelName}`);
@@ -64089,7 +64648,10 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64089
64648
  }
64090
64649
  const resolution = resolveModelProvider(targetModel);
64091
64650
  if (resolution.wasAutoRouted && resolution.autoRouteMessage) {
64092
- console.error(`[Auto-route] ${resolution.autoRouteMessage}`);
64651
+ if (!options.quiet) {
64652
+ console.error(`[Auto-route] ${resolution.autoRouteMessage}`);
64653
+ }
64654
+ log(`[Auto-route] ${resolution.autoRouteMessage}`);
64093
64655
  }
64094
64656
  if (resolution.category === "openrouter") {
64095
64657
  if (resolution.wasAutoRouted && resolution.fullModelId) {
@@ -64111,7 +64673,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64111
64673
  const gemProvider = new GeminiApiKeyProvider(resolved.provider, resolved.modelName, apiKey);
64112
64674
  const gemAdapter = new GeminiAdapter(resolved.modelName);
64113
64675
  handler = new ComposedHandler(gemProvider, targetModel, resolved.modelName, port, {
64114
- adapter: gemAdapter
64676
+ adapter: gemAdapter,
64677
+ isInteractive: options.isInteractive
64115
64678
  });
64116
64679
  log(`[Proxy] Created Gemini handler (composed): ${resolved.modelName}`);
64117
64680
  } else if (resolved.provider.name === "gemini-codeassist") {
@@ -64119,7 +64682,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64119
64682
  const gcaAdapter = new GeminiAdapter(resolved.modelName);
64120
64683
  handler = new ComposedHandler(gcaProvider, targetModel, resolved.modelName, port, {
64121
64684
  adapter: gcaAdapter,
64122
- unwrapGeminiResponse: true
64685
+ unwrapGeminiResponse: true,
64686
+ isInteractive: options.isInteractive
64123
64687
  });
64124
64688
  log(`[Proxy] Created Gemini Code Assist handler (composed): ${resolved.modelName}`);
64125
64689
  } else if (resolved.provider.name === "openai") {
@@ -64127,14 +64691,16 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64127
64691
  const oaiAdapter = new OpenAIAdapter(resolved.modelName, resolved.provider.capabilities);
64128
64692
  handler = new ComposedHandler(oaiProvider, targetModel, resolved.modelName, port, {
64129
64693
  adapter: oaiAdapter,
64130
- tokenStrategy: "delta-aware"
64694
+ tokenStrategy: "delta-aware",
64695
+ isInteractive: options.isInteractive
64131
64696
  });
64132
64697
  log(`[Proxy] Created OpenAI handler (composed): ${resolved.modelName}`);
64133
64698
  } else if (resolved.provider.name === "minimax" || resolved.provider.name === "minimax-coding" || resolved.provider.name === "kimi" || resolved.provider.name === "kimi-coding" || resolved.provider.name === "zai") {
64134
64699
  const acProvider = new AnthropicCompatProvider(resolved.provider, apiKey);
64135
64700
  const acAdapter = new AnthropicPassthroughAdapter(resolved.modelName, resolved.provider.name);
64136
64701
  handler = new ComposedHandler(acProvider, targetModel, resolved.modelName, port, {
64137
- adapter: acAdapter
64702
+ adapter: acAdapter,
64703
+ isInteractive: options.isInteractive
64138
64704
  });
64139
64705
  log(`[Proxy] Created ${resolved.provider.name} handler (composed): ${resolved.modelName}`);
64140
64706
  } else if (resolved.provider.name === "glm" || resolved.provider.name === "glm-coding") {
@@ -64142,7 +64708,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64142
64708
  const glmAdapter = new OpenAIAdapter(resolved.modelName, resolved.provider.capabilities);
64143
64709
  handler = new ComposedHandler(glmProvider, targetModel, resolved.modelName, port, {
64144
64710
  adapter: glmAdapter,
64145
- tokenStrategy: "delta-aware"
64711
+ tokenStrategy: "delta-aware",
64712
+ isInteractive: options.isInteractive
64146
64713
  });
64147
64714
  log(`[Proxy] Created ${resolved.provider.name} handler (composed): ${resolved.modelName}`);
64148
64715
  } else if (resolved.provider.name === "opencode-zen") {
@@ -64150,7 +64717,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64150
64717
  const zenAcProvider = new AnthropicCompatProvider(resolved.provider, apiKey);
64151
64718
  const zenAcAdapter = new AnthropicPassthroughAdapter(resolved.modelName, resolved.provider.name);
64152
64719
  handler = new ComposedHandler(zenAcProvider, targetModel, resolved.modelName, port, {
64153
- adapter: zenAcAdapter
64720
+ adapter: zenAcAdapter,
64721
+ isInteractive: options.isInteractive
64154
64722
  });
64155
64723
  log(`[Proxy] Created OpenCode Zen (Anthropic composed): ${resolved.modelName}`);
64156
64724
  } else {
@@ -64158,7 +64726,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64158
64726
  const zenAdapter = new OpenAIAdapter(resolved.modelName, resolved.provider.capabilities);
64159
64727
  handler = new ComposedHandler(zenProvider, targetModel, resolved.modelName, port, {
64160
64728
  adapter: zenAdapter,
64161
- tokenStrategy: "delta-aware"
64729
+ tokenStrategy: "delta-aware",
64730
+ isInteractive: options.isInteractive
64162
64731
  });
64163
64732
  log(`[Proxy] Created OpenCode Zen (composed): ${resolved.modelName}`);
64164
64733
  }
@@ -64167,19 +64736,23 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64167
64736
  const ocAdapter = new OllamaCloudAdapter(resolved.modelName);
64168
64737
  handler = new ComposedHandler(ocProvider, targetModel, resolved.modelName, port, {
64169
64738
  adapter: ocAdapter,
64170
- tokenStrategy: "accumulate-both"
64739
+ tokenStrategy: "accumulate-both",
64740
+ isInteractive: options.isInteractive
64171
64741
  });
64172
64742
  log(`[Proxy] Created OllamaCloud handler (composed): ${resolved.modelName}`);
64173
64743
  } else if (resolved.provider.name === "litellm") {
64174
64744
  if (!resolved.provider.baseUrl) {
64175
- console.error("Error: LITELLM_BASE_URL or --litellm-url is required for LiteLLM provider.");
64176
- console.error("Set it with: export LITELLM_BASE_URL='https://your-litellm-instance.com'");
64177
- console.error("Or use: claudish --litellm-url https://your-instance.com --model litellm@model 'task'");
64745
+ logStderr("Error: LITELLM_BASE_URL or --litellm-url is required for LiteLLM provider.");
64746
+ logStderr("Set it with: export LITELLM_BASE_URL='https://your-litellm-instance.com'");
64747
+ logStderr("Or use: claudish --litellm-url https://your-instance.com --model litellm@model 'task'");
64178
64748
  return null;
64179
64749
  }
64180
64750
  const provider = new LiteLLMProvider(resolved.provider.baseUrl, apiKey, resolved.modelName);
64181
64751
  const adapter = new LiteLLMAdapter(resolved.modelName, resolved.provider.baseUrl);
64182
- handler = new ComposedHandler(provider, targetModel, resolved.modelName, port, { adapter });
64752
+ handler = new ComposedHandler(provider, targetModel, resolved.modelName, port, {
64753
+ adapter,
64754
+ isInteractive: options.isInteractive
64755
+ });
64183
64756
  log(`[Proxy] Created LiteLLM handler (composed): ${resolved.modelName} (${resolved.provider.baseUrl})`);
64184
64757
  } else if (resolved.provider.name === "vertex") {
64185
64758
  const hasApiKey = !!process.env.VERTEX_API_KEY;
@@ -64190,7 +64763,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64190
64763
  const vxGemProvider = new GeminiApiKeyProvider(expressProvider, resolved.modelName, process.env.VERTEX_API_KEY);
64191
64764
  const vxGemAdapter = new GeminiAdapter(resolved.modelName);
64192
64765
  handler = new ComposedHandler(vxGemProvider, targetModel, resolved.modelName, port, {
64193
- adapter: vxGemAdapter
64766
+ adapter: vxGemAdapter,
64767
+ isInteractive: options.isInteractive
64194
64768
  });
64195
64769
  log(`[Proxy] Created Vertex AI Express handler (composed): ${resolved.modelName}`);
64196
64770
  } else if (vertexConfig) {
@@ -64213,7 +64787,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
64213
64787
  }
64214
64788
  handler = new ComposedHandler(vxProvider, targetModel, resolved.modelName, port, {
64215
64789
  adapter: vxAdapter,
64216
- ...handlerOpts
64790
+ ...handlerOpts,
64791
+ isInteractive: options.isInteractive
64217
64792
  });
64218
64793
  log(`[Proxy] Created Vertex AI OAuth handler (composed): ${resolved.modelName} [${parsed.publisher}] (project: ${vertexConfig.projectId})`);
64219
64794
  } else {
@@ -64570,6 +65145,7 @@ var isKimiLogout = args.includes("--kimi-logout");
64570
65145
  var isUpdateCommand = args.includes("update");
64571
65146
  var isInitCommand = args[0] === "init" || args.includes("init");
64572
65147
  var isProfileCommand = args[0] === "profile" || args.some((a, i) => a === "profile" && (i === 0 || !args[i - 1]?.startsWith("-")));
65148
+ var isTelemetryCommand = args[0] === "telemetry";
64573
65149
  if (isMcpMode) {
64574
65150
  Promise.resolve().then(() => (init_mcp_server(), exports_mcp_server)).then((mcp) => mcp.startMcpServer());
64575
65151
  } else if (isGeminiLogin) {
@@ -64634,10 +65210,16 @@ if (isMcpMode) {
64634
65210
  } else if (isProfileCommand) {
64635
65211
  const profileArgIndex = args.findIndex((a) => a === "profile");
64636
65212
  Promise.resolve().then(() => (init_profile_commands(), exports_profile_commands)).then((pc) => pc.profileCommand(args.slice(profileArgIndex + 1)).catch(handlePromptExit));
65213
+ } else if (isTelemetryCommand) {
65214
+ const subcommand = args[1] ?? "status";
65215
+ Promise.resolve().then(() => (init_telemetry(), exports_telemetry)).then((tel) => {
65216
+ tel.initTelemetry({ interactive: true });
65217
+ return tel.handleTelemetryCommand(subcommand);
65218
+ });
64637
65219
  } else {
64638
65220
  runCli();
64639
65221
  }
64640
- function detectInstallMethod() {
65222
+ function detectInstallMethod2() {
64641
65223
  const scriptPath = process.argv[1] || "";
64642
65224
  if (scriptPath.includes("/.bun/")) {
64643
65225
  return "bun";
@@ -64662,13 +65244,13 @@ function getUpdateCommand2(method) {
64662
65244
  }
64663
65245
  }
64664
65246
  async function runSelfUpdate() {
64665
- const { getVersion: getVersion2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
65247
+ const { getVersion: getVersion3 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
64666
65248
  const { execSync: execSync2 } = await import("node:child_process");
64667
65249
  const { createInterface: createInterface3 } = await import("node:readline");
64668
- const currentVersion = getVersion2();
64669
- const installMethod = detectInstallMethod();
65250
+ const currentVersion = getVersion3();
65251
+ const installMethod2 = detectInstallMethod2();
64670
65252
  console.log(`claudish v${currentVersion}`);
64671
- console.log(`Installation: ${installMethod}`);
65253
+ console.log(`Installation: ${installMethod2}`);
64672
65254
  console.log(`
64673
65255
  Checking for updates...
64674
65256
  `);
@@ -64686,7 +65268,7 @@ Checking for updates...
64686
65268
  console.log(`✓ claudish is up to date (v${currentVersion})`);
64687
65269
  process.exit(0);
64688
65270
  }
64689
- const updateCmd = getUpdateCommand2(installMethod);
65271
+ const updateCmd = getUpdateCommand2(installMethod2);
64690
65272
  console.log(`New version available: v${currentVersion} → v${latestVersion}
64691
65273
  `);
64692
65274
  const shouldUpdate = await new Promise((resolve) => {
@@ -64727,7 +65309,7 @@ Update failed. Try manually:
64727
65309
  }
64728
65310
  async function runCli() {
64729
65311
  const { checkClaudeInstalled: checkClaudeInstalled2, runClaudeWithProxy: runClaudeWithProxy2 } = await Promise.resolve().then(() => (init_claude_runner(), exports_claude_runner));
64730
- const { parseArgs: parseArgs2, getVersion: getVersion2 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
65312
+ const { parseArgs: parseArgs2, getVersion: getVersion3 } = await Promise.resolve().then(() => (init_cli(), exports_cli));
64731
65313
  const { DEFAULT_PORT_RANGE: DEFAULT_PORT_RANGE2 } = await Promise.resolve().then(() => (init_config(), exports_config));
64732
65314
  const { selectModel: selectModel2, promptForApiKey: promptForApiKey2 } = await Promise.resolve().then(() => (init_model_selector(), exports_model_selector));
64733
65315
  const {
@@ -64750,6 +65332,8 @@ async function runCli() {
64750
65332
  try {
64751
65333
  const cliConfig = await parseArgs2(process.argv.slice(2));
64752
65334
  initLogger2(cliConfig.debug, cliConfig.logLevel);
65335
+ const { initTelemetry: initTelemetry2 } = await Promise.resolve().then(() => (init_telemetry(), exports_telemetry));
65336
+ initTelemetry2(cliConfig);
64753
65337
  if (cliConfig.debug && !cliConfig.quiet) {
64754
65338
  const logFile = getLogFilePath2();
64755
65339
  if (logFile) {
@@ -64757,7 +65341,7 @@ async function runCli() {
64757
65341
  }
64758
65342
  }
64759
65343
  if (cliConfig.interactive && !cliConfig.jsonOutput) {
64760
- const shouldExit = await checkForUpdates2(getVersion2(), {
65344
+ const shouldExit = await checkForUpdates2(getVersion3(), {
64761
65345
  quiet: cliConfig.quiet,
64762
65346
  skipPrompt: false
64763
65347
  });
@@ -64845,7 +65429,9 @@ async function runCli() {
64845
65429
  subagent: cliConfig.modelSubagent
64846
65430
  };
64847
65431
  const proxy = await createProxyServer2(port, cliConfig.monitor ? undefined : cliConfig.openrouterApiKey, cliConfig.monitor ? undefined : explicitModel, cliConfig.monitor, cliConfig.anthropicApiKey, modelMap, {
64848
- summarizeTools: cliConfig.summarizeTools
65432
+ summarizeTools: cliConfig.summarizeTools,
65433
+ quiet: cliConfig.quiet,
65434
+ isInteractive: cliConfig.interactive
64849
65435
  });
64850
65436
  let exitCode = 0;
64851
65437
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "5.3.0",
3
+ "version": "5.4.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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.2.0",
3
- "lastUpdated": "2026-03-02",
3
+ "lastUpdated": "2026-03-03",
4
4
  "source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
5
5
  "models": [
6
6
  {
@@ -121,7 +121,7 @@
121
121
  "average": "$0.32/1M"
122
122
  },
123
123
  "context": "163K",
124
- "maxOutputTokens": 163840,
124
+ "maxOutputTokens": 65536,
125
125
  "modality": "text->text",
126
126
  "supportsTools": true,
127
127
  "supportsReasoning": true,