claudish 7.15.0 → 7.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +161 -52
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -581,7 +581,7 @@ var init_onepassword_config = __esm(() => {
581
581
  });
582
582
 
583
583
  // src/version.ts
584
- var VERSION = "7.15.0";
584
+ var VERSION = "7.17.0";
585
585
 
586
586
  // src/logger.ts
587
587
  var exports_logger = {};
@@ -4306,7 +4306,7 @@ function computeHasOpSources() {
4306
4306
  if (argv.some((a) => a === "--op" || a.startsWith("--op=") || a === "--op-env" || a.startsWith("--op-env="))) {
4307
4307
  return true;
4308
4308
  }
4309
- if (readAllOnepasswordEnvironments().length > 0)
4309
+ if (configEnvironmentIds().length > 0)
4310
4310
  return true;
4311
4311
  const cfg = readConfigRaw();
4312
4312
  if (cfg.apiKeys) {
@@ -4351,6 +4351,31 @@ function runOpExclusive(op, label = "op:resolve", meta) {
4351
4351
  });
4352
4352
  return run;
4353
4353
  }
4354
+ function flagEnvironmentIds() {
4355
+ const argv = process.argv.slice(2);
4356
+ const ids = [];
4357
+ for (let i = 0;i < argv.length; i++) {
4358
+ const a = argv[i];
4359
+ if (a === "--op-env") {
4360
+ const v = argv[i + 1];
4361
+ if (v && !v.startsWith("-"))
4362
+ ids.push(v);
4363
+ } else if (a.startsWith("--op-env=")) {
4364
+ const v = a.slice("--op-env=".length);
4365
+ if (v)
4366
+ ids.push(v);
4367
+ }
4368
+ }
4369
+ return ids;
4370
+ }
4371
+ function configEnvironmentIds() {
4372
+ if (testSeams?.config)
4373
+ return testSeams.config.onepasswordEnvironments ?? [];
4374
+ return readAllOnepasswordEnvironments();
4375
+ }
4376
+ function registeredEnvironmentIds() {
4377
+ return [...new Set([...configEnvironmentIds(), ...flagEnvironmentIds()])];
4378
+ }
4354
4379
  function maskGlobForTrace(globPath) {
4355
4380
  const body = globPath.startsWith("op://") ? globPath.slice("op://".length) : globPath;
4356
4381
  const segments = body.split("/");
@@ -4387,10 +4412,34 @@ async function resolveGlobShared(globPath, auth) {
4387
4412
  });
4388
4413
  return { resolved: await promise, cacheHit: false };
4389
4414
  }
4415
+ async function resolveEnvironmentShared(envId, auth) {
4416
+ const existing = environmentResolutions.get(envId);
4417
+ if (existing)
4418
+ return { resolved: await existing, cacheHit: true };
4419
+ const spanName = `op:env-resolve(${envId})`;
4420
+ const promise = (async () => {
4421
+ const { readEnvironment: readEnvironment2, recordOpHydratedVars: recordOpHydratedVars2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
4422
+ const resolved = await traceSpan(spanName, () => readEnvironment2(envId, { auth, sdkFactory: testSeams?.sdkFactory }));
4423
+ addSpanMeta(spanName, { vars: Object.keys(resolved).length });
4424
+ for (const [k, v] of Object.entries(resolved)) {
4425
+ resolvedCache.set(k, v);
4426
+ globResolvedVars.add(k);
4427
+ }
4428
+ recordOpHydratedVars2(Object.keys(resolved));
4429
+ return resolved;
4430
+ })();
4431
+ environmentResolutions.set(envId, promise);
4432
+ promise.catch(() => {
4433
+ if (environmentResolutions.get(envId) === promise)
4434
+ environmentResolutions.delete(envId);
4435
+ });
4436
+ return { resolved: await promise, cacheHit: false };
4437
+ }
4390
4438
  function invalidateOpResolutionCache() {
4391
4439
  resolvedCache.clear();
4392
4440
  globResolutions.clear();
4393
4441
  globResolvedVars.clear();
4442
+ environmentResolutions.clear();
4394
4443
  sniffed = undefined;
4395
4444
  }
4396
4445
  async function resolveOpKeyForEnvVars(wanted, opts = {}) {
@@ -4514,6 +4563,28 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4514
4563
  Object.assign(out, resolved);
4515
4564
  }
4516
4565
  }
4566
+ const stillWantedEnv = new Set([...wanted].filter((w) => !(w in out)));
4567
+ if (stillWantedEnv.size > 0) {
4568
+ for (const envId of registeredEnvironmentIds()) {
4569
+ if (stillWantedEnv.size === 0)
4570
+ break;
4571
+ try {
4572
+ const { resolved, cacheHit } = await resolveEnvironmentShared(envId, auth);
4573
+ if (cacheHit)
4574
+ span?.addMeta({ globCacheHit: true });
4575
+ for (const w of [...stillWantedEnv]) {
4576
+ const v = resolved[w];
4577
+ if (v !== undefined) {
4578
+ out[w] = v;
4579
+ stillWantedEnv.delete(w);
4580
+ }
4581
+ }
4582
+ } catch (envErr) {
4583
+ const m = envErr instanceof Error ? envErr.message : String(envErr);
4584
+ console.error(`[claudish] 1Password environment skipped: ${m}`);
4585
+ }
4586
+ }
4587
+ }
4517
4588
  } catch (err) {
4518
4589
  if (err instanceof OpAuthError && onAuthFailure === "skip") {
4519
4590
  console.error(`[claudish] 1Password resolution skipped: ${err.message}`);
@@ -4528,7 +4599,7 @@ async function resolveOpKeyForEnvVarsInner(wanted, opts = {}, span) {
4528
4599
  recordOpHydratedVars2(Object.keys(out));
4529
4600
  return out;
4530
4601
  }
4531
- var OpAuthError, cachedSdkAuth, sdkAuthResolved = false, authInFlight, testSeams, sniffed, opQueue, resolvedCache, globResolutions, globResolvedVars;
4602
+ var OpAuthError, cachedSdkAuth, sdkAuthResolved = false, authInFlight, testSeams, sniffed, opQueue, resolvedCache, globResolutions, globResolvedVars, environmentResolutions;
4532
4603
  var init_op_source = __esm(() => {
4533
4604
  init_onepassword_config();
4534
4605
  init_startup_trace();
@@ -4542,6 +4613,7 @@ var init_op_source = __esm(() => {
4542
4613
  resolvedCache = new Map;
4543
4614
  globResolutions = new Map;
4544
4615
  globResolvedVars = new Set;
4616
+ environmentResolutions = new Map;
4545
4617
  });
4546
4618
 
4547
4619
  // src/onepassword-command.ts
@@ -30832,8 +30904,24 @@ var init_all_models_cache = __esm(() => {
30832
30904
 
30833
30905
  // src/adapters/model-catalog.ts
30834
30906
  function lookupModel(modelId, cachePath) {
30907
+ const entry = findCacheEntry(modelId, cachePath);
30908
+ if (!entry || entry.contextWindow === undefined)
30909
+ return;
30910
+ return {
30911
+ modelId: entry.modelId,
30912
+ contextWindow: entry.contextWindow,
30913
+ supportsVision: entry.supportsVision
30914
+ };
30915
+ }
30916
+ function lookupModelForProvider(modelId, provider, cachePath) {
30917
+ const entry = findCacheEntry(modelId, cachePath);
30918
+ if (!entry)
30919
+ return;
30920
+ return entry.aggregators?.find((a) => a.provider === provider)?.contextWindow ?? entry.contextWindow;
30921
+ }
30922
+ function findCacheEntry(modelId, cachePath) {
30835
30923
  if (modelId.includes("@")) {
30836
- throw new Error(`lookupModel() received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
30924
+ throw new Error(`model-catalog lookup received provider-routed ID "${modelId}" \u2014 callers must strip the "@" prefix before calling`);
30837
30925
  }
30838
30926
  const cache = readAllModelsCache(cachePath);
30839
30927
  if (!cache || cache.entries.length === 0)
@@ -30845,13 +30933,7 @@ function lookupModel(modelId, cachePath) {
30845
30933
  const exactMatch = entryId === unprefixed || entryId === lower;
30846
30934
  const aliasMatch = entry.aliases?.some((a) => a.toLowerCase() === unprefixed || a.toLowerCase() === lower);
30847
30935
  if (exactMatch || aliasMatch) {
30848
- if (entry.contextWindow === undefined)
30849
- return;
30850
- return {
30851
- modelId: entry.modelId,
30852
- contextWindow: entry.contextWindow,
30853
- supportsVision: entry.supportsVision
30854
- };
30936
+ return entry;
30855
30937
  }
30856
30938
  }
30857
30939
  return;
@@ -38385,9 +38467,20 @@ data: ${JSON.stringify(data)}
38385
38467
  const errMsg = err.message || event.message || "Unknown API error";
38386
38468
  const errCode = err.code || event.code || "";
38387
38469
  log(`[ResponsesSSE] API error: ${errCode} - ${errMsg}`);
38470
+ opts.onApiError?.(errCode, errMsg);
38388
38471
  closeReasoning();
38389
38472
  closeText();
38390
38473
  closeTools();
38474
+ const isCtxOverflow = errCode === "context_length_exceeded" || /context (length|window)|exceeds? the context|too long|maximum context/i.test(errMsg);
38475
+ let errorText = `
38476
+
38477
+ [API Error: ${errCode} ${errMsg}]`;
38478
+ if (isCtxOverflow) {
38479
+ const cap = opts.contextWindow && opts.contextWindow > 0 ? ` ~${Math.round(opts.contextWindow / 1000)}K tokens` : "";
38480
+ errorText = `
38481
+
38482
+ [Context limit reached] This model's backend enforces a smaller context window${cap} than its API spec. ` + "Run /clear to start fresh (/compact will also fail \u2014 it re-sends the full conversation), " + `or route the model via \`oai@${opts.modelName}\` to use the full-size window.`;
38483
+ }
38391
38484
  const errorIdx = curIdx++;
38392
38485
  send("content_block_start", {
38393
38486
  type: "content_block_start",
@@ -38397,9 +38490,7 @@ data: ${JSON.stringify(data)}
38397
38490
  send("content_block_delta", {
38398
38491
  type: "content_block_delta",
38399
38492
  index: errorIdx,
38400
- delta: { type: "text_delta", text: `
38401
-
38402
- [API Error: ${errCode} ${errMsg}]` }
38493
+ delta: { type: "text_delta", text: errorText }
38403
38494
  });
38404
38495
  send("content_block_stop", { type: "content_block_stop", index: errorIdx });
38405
38496
  send("message_delta", {
@@ -39078,6 +39169,7 @@ class ComposedHandler {
39078
39169
  }
39079
39170
  latencyMs = Math.round(performance.now() - startTime);
39080
39171
  const httpStatus = response.status;
39172
+ let streamApiError = null;
39081
39173
  const onStreamComplete = () => {
39082
39174
  try {
39083
39175
  const isFreeModel = this.tokenTracker.getTotalCost() === 0;
@@ -39086,7 +39178,7 @@ class ComposedHandler {
39086
39178
  provider_name: this.provider.name,
39087
39179
  stream_format: this.provider.streamFormat,
39088
39180
  latency_ms: latencyMs,
39089
- success: true,
39181
+ success: streamApiError === null,
39090
39182
  http_status: httpStatus,
39091
39183
  input_tokens: this.tokenTracker.getInputTokens(),
39092
39184
  output_tokens: this.tokenTracker.getOutputTokens(),
@@ -39102,9 +39194,11 @@ class ComposedHandler {
39102
39194
  });
39103
39195
  } catch {}
39104
39196
  };
39105
- return this.handleStream(c, response, adapter, claudeRequest, toolNameMap, onStreamComplete);
39197
+ return this.handleStream(c, response, adapter, claudeRequest, toolNameMap, onStreamComplete, (code, message) => {
39198
+ streamApiError = { code, message };
39199
+ });
39106
39200
  }
39107
- handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete) {
39201
+ handleStream(c, response, adapter, claudeRequest, toolNameMap, onComplete, onApiError) {
39108
39202
  let pendingOnComplete = onComplete;
39109
39203
  const onTokenUpdate = (input, output) => {
39110
39204
  const strategy = this.options.tokenStrategy || "standard";
@@ -39137,7 +39231,9 @@ class ComposedHandler {
39137
39231
  return createResponsesStreamHandler(c, response, {
39138
39232
  modelName: this.bareModelName,
39139
39233
  onTokenUpdate,
39140
- toolNameMap: adapter.getToolNameMap()
39234
+ toolNameMap: adapter.getToolNameMap(),
39235
+ contextWindow: lookupModelForProvider(this.bareModelName, this.provider.name),
39236
+ onApiError
39141
39237
  });
39142
39238
  case "anthropic-sse":
39143
39239
  return createAnthropicPassthroughStream(c, response, {
@@ -39240,6 +39336,7 @@ var init_composed_handler = __esm(() => {
39240
39336
  init_anthropic_sse();
39241
39337
  init_gemini_sse();
39242
39338
  init_ollama_jsonl();
39339
+ init_model_catalog();
39243
39340
  init_openai_responses_sse();
39244
39341
  init_openai_sse();
39245
39342
  init_token_tracker();
@@ -41875,6 +41972,7 @@ var init_ollamacloud = __esm(() => {
41875
41972
  var OpenAICodexTransport;
41876
41973
  var init_openai_codex = __esm(() => {
41877
41974
  init_codex_api_format();
41975
+ init_model_catalog();
41878
41976
  init_authority();
41879
41977
  init_openai();
41880
41978
  OpenAICodexTransport = class OpenAICodexTransport extends OpenAIProviderTransport {
@@ -41904,6 +42002,9 @@ var init_openai_codex = __esm(() => {
41904
42002
  }
41905
42003
  return this.cachedAuth?.transformPayload?.(normalizedPayload) ?? normalizedPayload;
41906
42004
  }
42005
+ getContextWindow() {
42006
+ return lookupModelForProvider(this.modelName, this.name) ?? 0;
42007
+ }
41907
42008
  };
41908
42009
  });
41909
42010
 
@@ -58594,6 +58695,7 @@ var init_config = __esm(() => {
58594
58695
  ANTHROPIC_DEFAULT_SONNET_MODEL: "ANTHROPIC_DEFAULT_SONNET_MODEL",
58595
58696
  ANTHROPIC_DEFAULT_HAIKU_MODEL: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
58596
58697
  CLAUDE_CODE_SUBAGENT_MODEL: "CLAUDE_CODE_SUBAGENT_MODEL",
58698
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "CLAUDE_CODE_AUTO_COMPACT_WINDOW",
58597
58699
  OLLAMA_BASE_URL: "OLLAMA_BASE_URL",
58598
58700
  OLLAMA_HOST: "OLLAMA_HOST",
58599
58701
  LMSTUDIO_BASE_URL: "LMSTUDIO_BASE_URL",
@@ -71279,6 +71381,7 @@ __export(exports_claude_runner, {
71279
71381
  runClaudeWithProxy: () => runClaudeWithProxy,
71280
71382
  managedSettingsForcesClaudeAi: () => managedSettingsForcesClaudeAi,
71281
71383
  isProxyAuthMode: () => isProxyAuthMode,
71384
+ computeMainThreadContextWindow: () => computeMainThreadContextWindow,
71282
71385
  checkClaudeInstalled: () => checkClaudeInstalled,
71283
71386
  buildClaudishSettingsOverlay: () => buildClaudishSettingsOverlay
71284
71387
  });
@@ -71497,6 +71600,29 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
71497
71600
  }
71498
71601
  config3.claudeArgs.splice(idx, 2);
71499
71602
  }
71603
+ async function computeMainThreadContextWindow(config3, cachePath) {
71604
+ const specs = [config3.model, config3.modelOpus, config3.modelSonnet].filter((s) => typeof s === "string" && s.length > 0);
71605
+ if (specs.length === 0)
71606
+ return 0;
71607
+ let min = Number.POSITIVE_INFINITY;
71608
+ for (const spec of specs) {
71609
+ try {
71610
+ const parsed = parseModelSpec(spec);
71611
+ let provider = parsed.provider;
71612
+ if (!parsed.isExplicitProvider) {
71613
+ const plan = await route(spec);
71614
+ if (plan.kind !== "ok")
71615
+ continue;
71616
+ provider = plan.primary.provider;
71617
+ }
71618
+ const win = lookupModelForProvider(parsed.model, provider, cachePath);
71619
+ if (typeof win === "number" && win > 0) {
71620
+ min = Math.min(min, win);
71621
+ }
71622
+ } catch {}
71623
+ }
71624
+ return Number.isFinite(min) ? min : 0;
71625
+ }
71500
71626
  async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
71501
71627
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
71502
71628
  const modelId = config3.model || (hasProfileMappings || config3.monitor ? undefined : "unknown");
@@ -71561,6 +71687,15 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
71561
71687
  if (hasNativeAnthropicMapping(config3)) {} else {
71562
71688
  env.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx";
71563
71689
  env.ANTHROPIC_AUTH_TOKEN = process.env.ANTHROPIC_AUTH_TOKEN || "placeholder-token-not-used-proxy-handles-auth";
71690
+ if (!process.env[ENV.CLAUDE_CODE_AUTO_COMPACT_WINDOW]) {
71691
+ const autoCompactWindow = await computeMainThreadContextWindow(config3);
71692
+ if (autoCompactWindow > 0) {
71693
+ env[ENV.CLAUDE_CODE_AUTO_COMPACT_WINDOW] = String(autoCompactWindow);
71694
+ if (!config3.quiet) {
71695
+ console.error(`[claudish] Auto-compact window: ${autoCompactWindow.toLocaleString()} tokens ` + "(Claude Code compacts before the backend's real limit)");
71696
+ }
71697
+ }
71698
+ }
71564
71699
  }
71565
71700
  }
71566
71701
  const log2 = (message) => {
@@ -71734,8 +71869,10 @@ async function checkClaudeInstalled() {
71734
71869
  return binary !== null;
71735
71870
  }
71736
71871
  var init_claude_runner = __esm(() => {
71872
+ init_model_catalog();
71737
71873
  init_config();
71738
71874
  init_model_parser();
71875
+ init_routing_rules();
71739
71876
  init_telemetry();
71740
71877
  });
71741
71878
 
@@ -72236,7 +72373,6 @@ var init_team_grid = __esm(() => {
72236
72373
 
72237
72374
  // src/index.ts
72238
72375
  init_op_source();
72239
- init_onepassword_config();
72240
72376
  init_startup_trace();
72241
72377
  var import_dotenv3 = __toESM(require_main(), 1);
72242
72378
  import { readFileSync as readFileSync23 } from "fs";
@@ -72273,42 +72409,15 @@ process.on("exit", () => {
72273
72409
  });
72274
72410
  async function applyOpEnvironment() {
72275
72411
  const argv = process.argv.slice(2);
72276
- let flagEnvId;
72277
72412
  for (let i = 0;i < argv.length; i++) {
72278
72413
  const a = argv[i];
72279
- if (a === "--op-env") {
72280
- flagEnvId = argv[i + 1];
72281
- break;
72282
- }
72283
- if (a.startsWith("--op-env=")) {
72284
- flagEnvId = a.slice("--op-env=".length);
72285
- break;
72286
- }
72287
- }
72288
- if (flagEnvId !== undefined && (flagEnvId === "" || flagEnvId.startsWith("-"))) {
72289
- console.error("[claudish] --op-env requires a 1Password Environment ID");
72290
- process.exit(1);
72291
- }
72292
- const configEnvIds = readAllOnepasswordEnvironments();
72293
- const envIds = [...configEnvIds];
72294
- if (flagEnvId !== undefined && flagEnvId !== "")
72295
- envIds.push(flagEnvId);
72296
- if (envIds.length === 0)
72297
- return;
72298
- try {
72299
- const { readEnvironment: readEnvironment2, recordOpHydratedVars: recordOpHydratedVars2 } = await Promise.resolve().then(() => (init_onepassword(), exports_onepassword));
72300
- const auth = await resolveExplicitFlagAuth();
72301
- for (const envId of envIds) {
72302
- const vars = await readEnvironment2(envId, { auth });
72303
- for (const [key, value] of Object.entries(vars)) {
72304
- process.env[key] = value;
72305
- }
72306
- recordOpHydratedVars2(Object.keys(vars));
72414
+ if (a !== "--op-env" && !a.startsWith("--op-env="))
72415
+ continue;
72416
+ const val = a === "--op-env" ? argv[i + 1] : a.slice("--op-env=".length);
72417
+ if (val === undefined || val === "" || val.startsWith("-")) {
72418
+ console.error("[claudish] --op-env requires a 1Password Environment ID");
72419
+ process.exit(1);
72307
72420
  }
72308
- } catch (err) {
72309
- const message = err instanceof Error ? err.message : String(err);
72310
- console.error(`[claudish] 1Password Environment load failed: ${message}`);
72311
- process.exit(1);
72312
72421
  }
72313
72422
  }
72314
72423
  async function applyOpImport() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.15.0",
3
+ "version": "7.17.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "7.15.0",
64
- "@claudish/magmux-darwin-x64": "7.15.0",
65
- "@claudish/magmux-linux-arm64": "7.15.0",
66
- "@claudish/magmux-linux-x64": "7.15.0"
63
+ "@claudish/magmux-darwin-arm64": "7.17.0",
64
+ "@claudish/magmux-darwin-x64": "7.17.0",
65
+ "@claudish/magmux-linux-arm64": "7.17.0",
66
+ "@claudish/magmux-linux-x64": "7.17.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",