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 +621 -35
- package/package.json +1 -1
- package/recommended-models.json +2 -2
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
|
-
|
|
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: () =>
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
64176
|
-
|
|
64177
|
-
|
|
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, {
|
|
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
|
|
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:
|
|
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 =
|
|
64669
|
-
const
|
|
65250
|
+
const currentVersion = getVersion3();
|
|
65251
|
+
const installMethod2 = detectInstallMethod2();
|
|
64670
65252
|
console.log(`claudish v${currentVersion}`);
|
|
64671
|
-
console.log(`Installation: ${
|
|
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(
|
|
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:
|
|
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(
|
|
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
package/recommended-models.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.2.0",
|
|
3
|
-
"lastUpdated": "2026-03-
|
|
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":
|
|
124
|
+
"maxOutputTokens": 65536,
|
|
125
125
|
"modality": "text->text",
|
|
126
126
|
"supportsTools": true,
|
|
127
127
|
"supportsReasoning": true,
|