claudish 7.39.0 → 7.41.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 +1888 -360
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -729,7 +729,7 @@ var init_onepassword_config = __esm(() => {
729
729
  });
730
730
 
731
731
  // src/version.ts
732
- var VERSION = "7.39.0";
732
+ var VERSION = "7.41.0";
733
733
 
734
734
  // src/logger.ts
735
735
  var exports_logger = {};
@@ -27958,6 +27958,26 @@ var init_provider_definitions = __esm(() => {
27958
27958
  isDirectApi: true,
27959
27959
  description: "Antigravity subscription (ag@; go@ deprecated)"
27960
27960
  },
27961
+ {
27962
+ name: "devin",
27963
+ displayName: "Devin",
27964
+ transport: "devin",
27965
+ baseUrl: "https://server.codeium.com",
27966
+ baseUrlEnvVars: ["WINDSURF_API_SERVER_URL"],
27967
+ apiPath: "/exa.api_server_pb.ApiServerService/GetChatMessage",
27968
+ apiKeyEnvVar: "",
27969
+ apiKeyDescription: "Devin CLI session token (~/.local/share/devin/credentials.toml)",
27970
+ apiKeyUrl: "https://devin.ai/",
27971
+ shortcuts: ["dv", "devin"],
27972
+ shortestPrefix: "dv",
27973
+ legacyPrefixes: [
27974
+ { prefix: "dv/", stripPrefix: true },
27975
+ { prefix: "devin/", stripPrefix: true }
27976
+ ],
27977
+ modelDiscovery: { path: "", format: "devin-connect" },
27978
+ isDirectApi: true,
27979
+ description: "Devin subscription (dv@, devin@)"
27980
+ },
27961
27981
  {
27962
27982
  name: "gemini-codeassist",
27963
27983
  displayName: "Gemini Code Assist",
@@ -28570,7 +28590,8 @@ var init_remote_provider_types = __esm(() => {
28570
28590
  "minimax-coding",
28571
28591
  "kimi-coding",
28572
28592
  "glm-coding",
28573
- "qwen-cloud"
28593
+ "qwen-cloud",
28594
+ "devin"
28574
28595
  ]);
28575
28596
  PROVIDER_ALIAS = {
28576
28597
  google: "gemini",
@@ -29275,7 +29296,7 @@ class BaseAPIFormat {
29275
29296
  }
29276
29297
  }
29277
29298
  }
29278
- var EFFORT_ORDER, NON_ANTHROPIC_REASONING_FIELDS, DefaultAPIFormat;
29299
+ var EFFORT_ORDER, EFFORT_LEVELS, NON_ANTHROPIC_REASONING_FIELDS, DefaultAPIFormat;
29279
29300
  var init_base_api_format = __esm(() => {
29280
29301
  init_remote_provider_types();
29281
29302
  init_logger();
@@ -29283,6 +29304,7 @@ var init_base_api_format = __esm(() => {
29283
29304
  init_tool_name_utils();
29284
29305
  init_openai_tools();
29285
29306
  EFFORT_ORDER = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
29307
+ EFFORT_LEVELS = EFFORT_ORDER;
29286
29308
  NON_ANTHROPIC_REASONING_FIELDS = [
29287
29309
  "reasoning_effort",
29288
29310
  "enable_thinking",
@@ -31551,19 +31573,101 @@ var init_codex_credential = __esm(() => {
31551
31573
  init_api_key_credential();
31552
31574
  });
31553
31575
 
31554
- // src/auth/oauth-registry.ts
31555
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
31576
+ // src/providers/devin/devin-credentials.ts
31577
+ import { readFileSync as readFileSync9 } from "fs";
31556
31578
  import { homedir as homedir13 } from "os";
31557
31579
  import { join as join13 } from "path";
31580
+ function devinCredentialsPath() {
31581
+ return credentialsPathOverride ?? join13(homedir13(), ".local", "share", "devin", "credentials.toml");
31582
+ }
31583
+ function readTomlString(source, key) {
31584
+ const match = source.match(new RegExp(`^\\s*${key}\\s*=\\s*"([^"]*)"`, "m"));
31585
+ const value = match?.[1]?.trim();
31586
+ return value ? value : undefined;
31587
+ }
31588
+ function readCredentialsFile() {
31589
+ const path = devinCredentialsPath();
31590
+ if (fileCache && fileCache.path === path)
31591
+ return fileCache.value;
31592
+ let value = {};
31593
+ try {
31594
+ const source = readFileSync9(path, "utf8");
31595
+ value = {
31596
+ apiKey: readTomlString(source, "windsurf_api_key"),
31597
+ serverUrl: readTomlString(source, "api_server_url")
31598
+ };
31599
+ } catch {}
31600
+ fileCache = { path, value };
31601
+ return value;
31602
+ }
31603
+ function readDevinApiKey() {
31604
+ const fromEnv = realValue(process.env[DEVIN_API_KEY_ENV]);
31605
+ if (fromEnv?.trim())
31606
+ return fromEnv.trim();
31607
+ const fromConfig = realValue(getApiKey(DEVIN_API_KEY_ENV));
31608
+ if (fromConfig?.trim())
31609
+ return fromConfig.trim();
31610
+ const fromFile = readCredentialsFile().apiKey;
31611
+ return fromFile?.trim() ? fromFile.trim() : undefined;
31612
+ }
31613
+ function hasDevinCredentials() {
31614
+ return readDevinApiKey() !== undefined;
31615
+ }
31616
+ function readDevinServerUrl() {
31617
+ const fromEnv = realValue(process.env[DEVIN_SERVER_URL_ENV])?.trim();
31618
+ const url2 = fromEnv || readCredentialsFile().serverUrl || DEFAULT_DEVIN_SERVER_URL;
31619
+ return url2.replace(/\/+$/, "");
31620
+ }
31621
+ var DEVIN_API_KEY_ENV = "WINDSURF_API_KEY", DEVIN_SERVER_URL_ENV = "WINDSURF_API_SERVER_URL", DEFAULT_DEVIN_SERVER_URL = "https://server.codeium.com", credentialsPathOverride = null, fileCache = null;
31622
+ var init_devin_credentials = __esm(() => {
31623
+ init_env_placeholder();
31624
+ init_profile_config();
31625
+ });
31626
+
31627
+ // src/auth/credentials/devin-credential.ts
31628
+ function devinAuthHeaders(apiKey) {
31629
+ return {
31630
+ authorization: `Basic ${apiKey}-${apiKey}`,
31631
+ "connect-protocol-version": "1"
31632
+ };
31633
+ }
31634
+
31635
+ class DevinCredentialProvider {
31636
+ catalogName = "devin";
31637
+ async isAvailable() {
31638
+ try {
31639
+ return hasDevinCredentials();
31640
+ } catch {
31641
+ return false;
31642
+ }
31643
+ }
31644
+ async getRequestAuth() {
31645
+ const apiKey = readDevinApiKey();
31646
+ if (!apiKey) {
31647
+ const err = new Error("No Devin credential. Sign in with the Devin CLI (`devin login`), or set WINDSURF_API_KEY. " + "Expected ~/.local/share/devin/credentials.toml.");
31648
+ err.terminal = true;
31649
+ throw err;
31650
+ }
31651
+ return { headers: devinAuthHeaders(apiKey) };
31652
+ }
31653
+ }
31654
+ var init_devin_credential = __esm(() => {
31655
+ init_devin_credentials();
31656
+ });
31657
+
31658
+ // src/auth/oauth-registry.ts
31659
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
31660
+ import { homedir as homedir14 } from "os";
31661
+ import { join as join14 } from "path";
31558
31662
  function hasValidOAuthCredentials(descriptor) {
31559
- const credPath = join13(homedir13(), ".claudish", descriptor.credentialFile);
31663
+ const credPath = join14(homedir14(), ".claudish", descriptor.credentialFile);
31560
31664
  if (!existsSync11(credPath))
31561
31665
  return false;
31562
31666
  if (descriptor.validationMode === "file-exists") {
31563
31667
  return true;
31564
31668
  }
31565
31669
  try {
31566
- const data = JSON.parse(readFileSync9(credPath, "utf-8"));
31670
+ const data = JSON.parse(readFileSync10(credPath, "utf-8"));
31567
31671
  if (!data.access_token)
31568
31672
  return false;
31569
31673
  if (data.refresh_token)
@@ -31668,9 +31772,9 @@ var init_gemini_credential = __esm(() => {
31668
31772
  // src/auth/kimi-oauth.ts
31669
31773
  import { exec as exec3 } from "child_process";
31670
31774
  import { randomBytes as randomBytes3 } from "crypto";
31671
- import { closeSync as closeSync4, existsSync as existsSync12, openSync as openSync4, readFileSync as readFileSync10, unlinkSync as unlinkSync4, writeSync as writeSync4 } from "fs";
31672
- import { homedir as homedir14, hostname as hostname3, platform, release as release2 } from "os";
31673
- import { join as join14 } from "path";
31775
+ import { closeSync as closeSync4, existsSync as existsSync12, openSync as openSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeSync as writeSync4 } from "fs";
31776
+ import { homedir as homedir15, hostname as hostname3, platform, release as release2 } from "os";
31777
+ import { join as join15 } from "path";
31674
31778
  import { promisify as promisify3 } from "util";
31675
31779
 
31676
31780
  class KimiOAuth {
@@ -31698,23 +31802,23 @@ class KimiOAuth {
31698
31802
  return this.credentials !== null && !!this.credentials.refresh_token;
31699
31803
  }
31700
31804
  getCredentialsPath() {
31701
- const claudishDir = join14(homedir14(), ".claudish");
31702
- return join14(claudishDir, "kimi-oauth.json");
31805
+ const claudishDir = join15(homedir15(), ".claudish");
31806
+ return join15(claudishDir, "kimi-oauth.json");
31703
31807
  }
31704
31808
  getDeviceIdPath() {
31705
- const claudishDir = join14(homedir14(), ".claudish");
31706
- return join14(claudishDir, "kimi-device-id");
31809
+ const claudishDir = join15(homedir15(), ".claudish");
31810
+ return join15(claudishDir, "kimi-device-id");
31707
31811
  }
31708
31812
  loadOrCreateDeviceId() {
31709
31813
  const deviceIdPath = this.getDeviceIdPath();
31710
- const claudishDir = join14(homedir14(), ".claudish");
31814
+ const claudishDir = join15(homedir15(), ".claudish");
31711
31815
  if (!existsSync12(claudishDir)) {
31712
31816
  const { mkdirSync: mkdirSync7 } = __require("fs");
31713
31817
  mkdirSync7(claudishDir, { recursive: true });
31714
31818
  }
31715
31819
  if (existsSync12(deviceIdPath)) {
31716
31820
  try {
31717
- const deviceId2 = readFileSync10(deviceIdPath, "utf-8").trim();
31821
+ const deviceId2 = readFileSync11(deviceIdPath, "utf-8").trim();
31718
31822
  if (deviceId2) {
31719
31823
  return deviceId2;
31720
31824
  }
@@ -31973,7 +32077,7 @@ Details: ${e.message}`);
31973
32077
  return null;
31974
32078
  }
31975
32079
  try {
31976
- const data = readFileSync10(credPath, "utf-8");
32080
+ const data = readFileSync11(credPath, "utf-8");
31977
32081
  const credentials2 = JSON.parse(data);
31978
32082
  if (!credentials2.access_token || !credentials2.refresh_token || !credentials2.expires_at || !credentials2.scope || !credentials2.token_type) {
31979
32083
  log("[KimiOAuth] Invalid credentials file structure");
@@ -31988,7 +32092,7 @@ Details: ${e.message}`);
31988
32092
  }
31989
32093
  saveCredentials(credentials2) {
31990
32094
  const credPath = this.getCredentialsPath();
31991
- const claudishDir = join14(homedir14(), ".claudish");
32095
+ const claudishDir = join15(homedir15(), ".claudish");
31992
32096
  if (!existsSync12(claudishDir)) {
31993
32097
  const { mkdirSync: mkdirSync7 } = __require("fs");
31994
32098
  mkdirSync7(claudishDir, { recursive: true });
@@ -32164,8 +32268,8 @@ var init_native_anthropic_credential = __esm(() => {
32164
32268
  // src/auth/vertex-auth.ts
32165
32269
  import { exec as exec4 } from "child_process";
32166
32270
  import { existsSync as existsSync13 } from "fs";
32167
- import { homedir as homedir15 } from "os";
32168
- import { join as join15 } from "path";
32271
+ import { homedir as homedir16 } from "os";
32272
+ import { join as join16 } from "path";
32169
32273
  import { promisify as promisify4 } from "util";
32170
32274
 
32171
32275
  class VertexAuthManager {
@@ -32220,7 +32324,7 @@ class VertexAuthManager {
32220
32324
  }
32221
32325
  async tryADC() {
32222
32326
  try {
32223
- const adcPath = join15(homedir15(), ".config/gcloud/application_default_credentials.json");
32327
+ const adcPath = join16(homedir16(), ".config/gcloud/application_default_credentials.json");
32224
32328
  if (!existsSync13(adcPath)) {
32225
32329
  log("[VertexAuth] ADC credentials file not found");
32226
32330
  return null;
@@ -32284,7 +32388,7 @@ function validateVertexOAuthConfig() {
32284
32388
  ` + ` export VERTEX_PROJECT='your-gcp-project-id'
32285
32389
  ` + " export VERTEX_LOCATION='us-central1' # optional";
32286
32390
  }
32287
- const adcPath = join15(homedir15(), ".config/gcloud/application_default_credentials.json");
32391
+ const adcPath = join16(homedir16(), ".config/gcloud/application_default_credentials.json");
32288
32392
  const hasADC = existsSync13(adcPath);
32289
32393
  const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
32290
32394
  if (!hasADC && !hasServiceAccount) {
@@ -32405,6 +32509,7 @@ class CredentialAuthority {
32405
32509
  authority.register(makeCodexCredential(), ["openai-codex"]);
32406
32510
  authority.register(new GeminiCodeAssistCredentialProvider, ["gemini-codeassist"]);
32407
32511
  authority.register(new AntigravityCredentialProvider, ["antigravity"]);
32512
+ authority.register(new DevinCredentialProvider, ["devin"]);
32408
32513
  authority.register(makeKimiCredential(), ["kimi"]);
32409
32514
  authority.register(makeKimiCodingCredential(), ["kimi-coding"]);
32410
32515
  authority.register(new VertexCredentialProvider, ["vertex"]);
@@ -32416,6 +32521,7 @@ class CredentialAuthority {
32416
32521
  "openai-codex",
32417
32522
  "gemini-codeassist",
32418
32523
  "antigravity",
32524
+ "devin",
32419
32525
  "kimi",
32420
32526
  "kimi-coding",
32421
32527
  "vertex",
@@ -32447,6 +32553,7 @@ var init_authority = __esm(() => {
32447
32553
  init_antigravity_credential();
32448
32554
  init_api_key_credential();
32449
32555
  init_codex_credential();
32556
+ init_devin_credential();
32450
32557
  init_gemini_credential();
32451
32558
  init_kimi_credential();
32452
32559
  init_local_credential();
@@ -34690,9 +34797,9 @@ var init_antigravity2 = __esm(() => {
34690
34797
  });
34691
34798
 
34692
34799
  // src/auth/quota/sources/codex.ts
34693
- import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
34694
- import { homedir as homedir16 } from "os";
34695
- import { join as join16 } from "path";
34800
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
34801
+ import { homedir as homedir17 } from "os";
34802
+ import { join as join17 } from "path";
34696
34803
  function formatWindowMinutes(minutes) {
34697
34804
  if (!Number.isFinite(minutes) || minutes <= 0)
34698
34805
  return "";
@@ -34706,7 +34813,7 @@ function formatWindowMinutes(minutes) {
34706
34813
  return `${hours}h${minutes % 60}m`;
34707
34814
  }
34708
34815
  function credentialsPath() {
34709
- return join16(homedir16(), ".claudish", "codex-oauth.json");
34816
+ return join17(homedir17(), ".claudish", "codex-oauth.json");
34710
34817
  }
34711
34818
  function planLabel(planType) {
34712
34819
  if (!planType)
@@ -34758,10 +34865,10 @@ function scrapeCodexHeaders(headers) {
34758
34865
  }
34759
34866
  function resolveProbeModel() {
34760
34867
  try {
34761
- const cachePath = join16(homedir16(), ".codex", "models_cache.json");
34868
+ const cachePath = join17(homedir17(), ".codex", "models_cache.json");
34762
34869
  if (!existsSync14(cachePath))
34763
34870
  return;
34764
- const cache2 = JSON.parse(readFileSync11(cachePath, "utf-8"));
34871
+ const cache2 = JSON.parse(readFileSync12(cachePath, "utf-8"));
34765
34872
  for (const m of cache2.models ?? []) {
34766
34873
  const slug = m?.slug ?? m?.id;
34767
34874
  if (typeof slug === "string" && slug.length > 0)
@@ -34775,7 +34882,7 @@ function readCodexCredentials() {
34775
34882
  const path = credentialsPath();
34776
34883
  if (!existsSync14(path))
34777
34884
  return;
34778
- return JSON.parse(readFileSync11(path, "utf-8"));
34885
+ return JSON.parse(readFileSync12(path, "utf-8"));
34779
34886
  } catch {
34780
34887
  return;
34781
34888
  }
@@ -35187,8 +35294,8 @@ var init_harness = __esm(() => {
35187
35294
 
35188
35295
  // src/behavior/journal.ts
35189
35296
  import { appendFile as appendFile2, mkdir, readFile, rename, stat, writeFile } from "fs/promises";
35190
- import { homedir as homedir17 } from "os";
35191
- import { dirname as dirname6, join as join17 } from "path";
35297
+ import { homedir as homedir18 } from "os";
35298
+ import { dirname as dirname6, join as join18 } from "path";
35192
35299
  function classifyPath(observed, expected) {
35193
35300
  if (!observed)
35194
35301
  return "not_applicable";
@@ -35200,7 +35307,7 @@ function classifyPath(observed, expected) {
35200
35307
  return dirOf(observed) === dirOf(expected) ? "same_dir_wrong_name" : "outside_expected_dir";
35201
35308
  }
35202
35309
  function journalPath() {
35203
- return join17(homedir17(), ".claudish", "behavior-journal.jsonl");
35310
+ return join18(homedir18(), ".claudish", "behavior-journal.jsonl");
35204
35311
  }
35205
35312
  async function prune(path) {
35206
35313
  const content = await readFile(path, "utf8");
@@ -35261,8 +35368,8 @@ __export(exports_aggregate, {
35261
35368
  });
35262
35369
  import { createHash as createHash4, randomBytes as randomBytes4 } from "crypto";
35263
35370
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
35264
- import { homedir as homedir18 } from "os";
35265
- import { dirname as dirname7, join as join18 } from "path";
35371
+ import { homedir as homedir19 } from "os";
35372
+ import { dirname as dirname7, join as join19 } from "path";
35266
35373
  function contextBucket(inputTokens) {
35267
35374
  if (inputTokens < 50000)
35268
35375
  return "0-50k";
@@ -35380,7 +35487,7 @@ function pendingReports() {
35380
35487
  return [...sessions.values()].map(toReport);
35381
35488
  }
35382
35489
  function outboxPath() {
35383
- return join18(homedir18(), ".claudish", "behavior-outbox.jsonl");
35490
+ return join19(homedir19(), ".claudish", "behavior-outbox.jsonl");
35384
35491
  }
35385
35492
  function spoolPendingSync(path = outboxPath()) {
35386
35493
  if (sessions.size === 0)
@@ -35603,10 +35710,10 @@ __export(exports_live_log, {
35603
35710
  recordLiveDivergence: () => recordLiveDivergence
35604
35711
  });
35605
35712
  import { appendFile as appendFile3 } from "fs/promises";
35606
- import { homedir as homedir19 } from "os";
35607
- import { join as join19 } from "path";
35713
+ import { homedir as homedir20 } from "os";
35714
+ import { join as join20 } from "path";
35608
35715
  function defaultPath() {
35609
- return join19(homedir19(), ".claudish", "behavior-divergences.jsonl");
35716
+ return join20(homedir20(), ".claudish", "behavior-divergences.jsonl");
35610
35717
  }
35611
35718
  async function recordLiveDivergence(entry, path = defaultPath()) {
35612
35719
  try {
@@ -36263,9 +36370,9 @@ var init_hooks = __esm(() => {
36263
36370
  });
36264
36371
 
36265
36372
  // src/behavior/observer/corpus.ts
36266
- import { appendFileSync as appendFileSync3, readFileSync as readFileSync12, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
36267
- import { homedir as homedir20 } from "os";
36268
- import { join as join20 } from "path";
36373
+ import { appendFileSync as appendFileSync3, readFileSync as readFileSync13, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
36374
+ import { homedir as homedir21 } from "os";
36375
+ import { join as join21 } from "path";
36269
36376
  function directoryOf2(filePath) {
36270
36377
  const slash = filePath.lastIndexOf("/");
36271
36378
  return slash > 0 ? filePath.slice(0, slash) : undefined;
@@ -36287,7 +36394,7 @@ function writeTargetsOf(row) {
36287
36394
  function replayTranscript(file2) {
36288
36395
  let text;
36289
36396
  try {
36290
- text = readFileSync12(file2, "utf8");
36397
+ text = readFileSync13(file2, "utf8");
36291
36398
  } catch {
36292
36399
  return [];
36293
36400
  }
@@ -36344,26 +36451,26 @@ function listTranscripts(root) {
36344
36451
  return files;
36345
36452
  }
36346
36453
  for (const project of projects) {
36347
- const dir = join20(root, project);
36454
+ const dir = join21(root, project);
36348
36455
  try {
36349
36456
  if (!statSync2(dir).isDirectory())
36350
36457
  continue;
36351
36458
  for (const f of readdirSync2(dir)) {
36352
36459
  if (f.endsWith(".jsonl"))
36353
- files.push(join20(dir, f));
36460
+ files.push(join21(dir, f));
36354
36461
  }
36355
36462
  } catch {}
36356
36463
  }
36357
36464
  return files;
36358
36465
  }
36359
36466
  function buildCorpus(options = {}) {
36360
- const root = options.projectsRoot ?? join20(homedir20(), ".claude", "projects");
36467
+ const root = options.projectsRoot ?? join21(homedir21(), ".claude", "projects");
36361
36468
  const files = listTranscripts(root);
36362
36469
  const records = [];
36363
36470
  for (const f of files)
36364
36471
  records.push(...replayTranscript(f));
36365
36472
  if (options.write && records.length > 0) {
36366
- const outputPath = options.outputPath ?? join20(homedir20(), ".claudish", "behavior-divergences.jsonl");
36473
+ const outputPath = options.outputPath ?? join21(homedir21(), ".claudish", "behavior-divergences.jsonl");
36367
36474
  try {
36368
36475
  appendFileSync3(outputPath, `${records.map((r) => JSON.stringify(r)).join(`
36369
36476
  `)}
@@ -36683,6 +36790,33 @@ var init_middleware = __esm(() => {
36683
36790
  init_gemini_thought_signature();
36684
36791
  });
36685
36792
 
36793
+ // src/handlers/shared/quota-exhaustion.ts
36794
+ function hasQuotaExhaustionWording(errorBody) {
36795
+ const lower = (errorBody || "").toLowerCase();
36796
+ return EXHAUSTION_PHRASES.some((phrase) => lower.includes(phrase));
36797
+ }
36798
+ function isQuotaExhaustionError(status, errorBody) {
36799
+ if (status !== 401 && status !== 403 && status !== 429)
36800
+ return false;
36801
+ return hasQuotaExhaustionWording(errorBody);
36802
+ }
36803
+ var EXHAUSTION_PHRASES;
36804
+ var init_quota_exhaustion = __esm(() => {
36805
+ EXHAUSTION_PHRASES = [
36806
+ "usage limit",
36807
+ "billing cycle",
36808
+ "quota",
36809
+ "insufficient balance",
36810
+ "insufficient_quota",
36811
+ "upgrade your plan",
36812
+ "exceeded your current",
36813
+ "out of credits",
36814
+ "credit balance",
36815
+ "daily limit",
36816
+ "plan limit"
36817
+ ];
36818
+ });
36819
+
36686
36820
  // src/providers/transport/openai.ts
36687
36821
  class OpenAIProviderTransport {
36688
36822
  name;
@@ -36768,11 +36902,14 @@ class OpenAIProviderTransport {
36768
36902
  function isTerminal429(body) {
36769
36903
  if (!body)
36770
36904
  return false;
36905
+ if (isQuotaExhaustionError(429, body))
36906
+ return true;
36771
36907
  const lower = body.toLowerCase();
36772
36908
  return lower.includes("insufficient balance") || lower.includes("insufficient_balance") || lower.includes("insufficient_quota") || lower.includes("insufficient quota") || lower.includes("billing_not_active") || lower.includes("billing not active") || lower.includes("quota_exceeded") || lower.includes("exceeded your current quota") || lower.includes("out of credits") || lower.includes('"code":"1113"') || lower.includes('"code":1113');
36773
36909
  }
36774
36910
  var OpenAITimeoutError, OpenAIConnectionError;
36775
36911
  var init_openai = __esm(() => {
36912
+ init_quota_exhaustion();
36776
36913
  init_logger();
36777
36914
  OpenAITimeoutError = class OpenAITimeoutError extends Error {
36778
36915
  constructor(baseUrl) {
@@ -37098,13 +37235,13 @@ var init_model_parser = __esm(() => {
37098
37235
  import {
37099
37236
  existsSync as existsSync15,
37100
37237
  mkdirSync as mkdirSync8,
37101
- readFileSync as readFileSync13,
37238
+ readFileSync as readFileSync14,
37102
37239
  renameSync,
37103
37240
  unlinkSync as unlinkSync5,
37104
37241
  writeFileSync as writeFileSync7
37105
37242
  } from "fs";
37106
- import { homedir as homedir21 } from "os";
37107
- import { join as join21 } from "path";
37243
+ import { homedir as homedir22 } from "os";
37244
+ import { join as join22 } from "path";
37108
37245
  function ensureDir() {
37109
37246
  if (!existsSync15(CLAUDISH_DIR)) {
37110
37247
  mkdirSync8(CLAUDISH_DIR, { recursive: true });
@@ -37114,7 +37251,7 @@ function readFromDisk() {
37114
37251
  try {
37115
37252
  if (!existsSync15(BUFFER_FILE))
37116
37253
  return [];
37117
- const raw = readFileSync13(BUFFER_FILE, "utf-8");
37254
+ const raw = readFileSync14(BUFFER_FILE, "utf-8");
37118
37255
  const parsed = JSON.parse(raw);
37119
37256
  if (!Array.isArray(parsed.events))
37120
37257
  return [];
@@ -37139,7 +37276,7 @@ function writeToDisk(events) {
37139
37276
  ensureDir();
37140
37277
  const trimmed2 = enforceSizeCap([...events]);
37141
37278
  const payload = { version: 1, events: trimmed2 };
37142
- const tmpFile = join21(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37279
+ const tmpFile = join22(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37143
37280
  writeFileSync7(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
37144
37281
  renameSync(tmpFile, BUFFER_FILE);
37145
37282
  memoryCache = trimmed2;
@@ -37212,8 +37349,8 @@ function syncFlushOnExit() {
37212
37349
  var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
37213
37350
  var init_stats_buffer = __esm(() => {
37214
37351
  BUFFER_MAX_BYTES = 64 * 1024;
37215
- CLAUDISH_DIR = join21(homedir21(), ".claudish");
37216
- BUFFER_FILE = join21(CLAUDISH_DIR, "stats-buffer.json");
37352
+ CLAUDISH_DIR = join22(homedir22(), ".claudish");
37353
+ BUFFER_FILE = join22(CLAUDISH_DIR, "stats-buffer.json");
37217
37354
  process.on("exit", syncFlushOnExit);
37218
37355
  process.on("SIGTERM", () => {
37219
37356
  try {
@@ -38327,9 +38464,9 @@ function compareByReleaseDateDesc(a, b) {
38327
38464
  }
38328
38465
 
38329
38466
  // src/model-loader.ts
38330
- import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
38331
- import { homedir as homedir22 } from "os";
38332
- import { join as join22 } from "path";
38467
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
38468
+ import { homedir as homedir23 } from "os";
38469
+ import { join as join23 } from "path";
38333
38470
  function groupRecommendedModels(entries) {
38334
38471
  const byId = new Map;
38335
38472
  const categoryOrder = new Map;
@@ -38441,7 +38578,7 @@ async function getRecommendedModels(opts = {}) {
38441
38578
  }
38442
38579
  if (!forceRefresh && existsSync16(RECOMMENDED_MODELS_CACHE_PATH)) {
38443
38580
  try {
38444
- const cacheData = JSON.parse(readFileSync14(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38581
+ const cacheData = JSON.parse(readFileSync15(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38445
38582
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
38446
38583
  _cachedRecommendedModels = cacheData;
38447
38584
  return cacheData;
@@ -38457,7 +38594,7 @@ async function getRecommendedModels(opts = {}) {
38457
38594
  if (data.models && data.models.length > 0) {
38458
38595
  _cachedRecommendedModels = data;
38459
38596
  try {
38460
- const cacheDir = join22(homedir22(), ".claudish");
38597
+ const cacheDir = join23(homedir23(), ".claudish");
38461
38598
  mkdirSync9(cacheDir, { recursive: true });
38462
38599
  writeFileSync8(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
38463
38600
  } catch {}
@@ -38472,7 +38609,7 @@ function getRecommendedModelsSync() {
38472
38609
  return _cachedRecommendedModels;
38473
38610
  if (existsSync16(RECOMMENDED_MODELS_CACHE_PATH)) {
38474
38611
  try {
38475
- const cacheData = JSON.parse(readFileSync14(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38612
+ const cacheData = JSON.parse(readFileSync15(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38476
38613
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
38477
38614
  _cachedRecommendedModels = cacheData;
38478
38615
  return cacheData;
@@ -38596,7 +38733,7 @@ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels =
38596
38733
  var init_model_loader = __esm(() => {
38597
38734
  init_cache_ttl();
38598
38735
  FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
38599
- RECOMMENDED_MODELS_CACHE_PATH = join22(homedir22(), ".claudish", "recommended-models-cache.json");
38736
+ RECOMMENDED_MODELS_CACHE_PATH = join23(homedir23(), ".claudish", "recommended-models-cache.json");
38600
38737
  FIREBASE_SLUG_TO_PROVIDER_NAME = {
38601
38738
  openai: "openai",
38602
38739
  google: "google",
@@ -38664,26 +38801,277 @@ var init_context_window_fallback = __esm(() => {
38664
38801
  inFlight2 = new Map;
38665
38802
  });
38666
38803
 
38667
- // src/handlers/shared/quota-exhaustion.ts
38668
- function isQuotaExhaustionError(status, errorBody) {
38669
- if (status !== 401 && status !== 403 && status !== 429)
38670
- return false;
38671
- const lower = (errorBody || "").toLowerCase();
38672
- return EXHAUSTION_PHRASES.some((phrase) => lower.includes(phrase));
38804
+ // src/providers/devin/proto-codec.ts
38805
+ function cat(parts) {
38806
+ let total = 0;
38807
+ for (const part of parts)
38808
+ total += part.length;
38809
+ const out = new Uint8Array(total);
38810
+ let offset = 0;
38811
+ for (const part of parts) {
38812
+ out.set(part, offset);
38813
+ offset += part.length;
38814
+ }
38815
+ return out;
38673
38816
  }
38674
- var EXHAUSTION_PHRASES;
38675
- var init_quota_exhaustion = __esm(() => {
38676
- EXHAUSTION_PHRASES = [
38677
- "usage limit",
38678
- "billing cycle",
38679
- "quota",
38680
- "insufficient balance",
38681
- "insufficient_quota",
38682
- "upgrade your plan",
38683
- "exceeded your current",
38684
- "out of credits",
38685
- "credit balance"
38686
- ];
38817
+ function varint(n) {
38818
+ let value = BigInt(n);
38819
+ const out = [];
38820
+ do {
38821
+ let byte = Number(value & 0x7fn);
38822
+ value >>= 7n;
38823
+ if (value > 0n)
38824
+ byte |= 128;
38825
+ out.push(byte);
38826
+ } while (value > 0n);
38827
+ return new Uint8Array(out);
38828
+ }
38829
+ function tag(fieldNumber, wireType) {
38830
+ return varint(fieldNumber << 3 | wireType);
38831
+ }
38832
+ function bytes(fieldNumber, value) {
38833
+ const body = typeof value === "string" ? textEncoder.encode(value) : value;
38834
+ return cat([tag(fieldNumber, 2), varint(body.length), body]);
38835
+ }
38836
+ function vint(fieldNumber, value) {
38837
+ return cat([tag(fieldNumber, 0), varint(value)]);
38838
+ }
38839
+ function msg(...parts) {
38840
+ return cat(parts);
38841
+ }
38842
+ function writeUint32BE(target, offset, value) {
38843
+ target[offset] = value >>> 24 & 255;
38844
+ target[offset + 1] = value >>> 16 & 255;
38845
+ target[offset + 2] = value >>> 8 & 255;
38846
+ target[offset + 3] = value & 255;
38847
+ }
38848
+ function readUint32BE(source, offset) {
38849
+ return (source[offset] << 24 | source[offset + 1] << 16 | source[offset + 2] << 8 | source[offset + 3]) >>> 0;
38850
+ }
38851
+ function envelope(payload, flags = 0) {
38852
+ const out = new Uint8Array(FRAME_HEADER_BYTES + payload.length);
38853
+ out[0] = flags;
38854
+ writeUint32BE(out, 1, payload.length);
38855
+ out.set(payload, FRAME_HEADER_BYTES);
38856
+ return out;
38857
+ }
38858
+ function readVarintAt(buf, p) {
38859
+ let value = 0n;
38860
+ let shift = 0n;
38861
+ let offset = p;
38862
+ while (offset < buf.length) {
38863
+ const byte = buf[offset++];
38864
+ value |= BigInt(byte & 127) << shift;
38865
+ if ((byte & 128) === 0)
38866
+ break;
38867
+ shift += 7n;
38868
+ }
38869
+ return [value, offset];
38870
+ }
38871
+ function parseTLV(buf) {
38872
+ const out = [];
38873
+ let p = 0;
38874
+ while (p < buf.length) {
38875
+ const start = p;
38876
+ let rawTag;
38877
+ [rawTag, p] = readVarintAt(buf, p);
38878
+ const no = Number(rawTag >> 3n);
38879
+ const wire = Number(rawTag & 7n);
38880
+ if (no === 0)
38881
+ break;
38882
+ let payloadStart = p;
38883
+ if (wire === 0) {
38884
+ [, p] = readVarintAt(buf, p);
38885
+ } else if (wire === 1) {
38886
+ p += 8;
38887
+ } else if (wire === 5) {
38888
+ p += 4;
38889
+ } else if (wire === 2) {
38890
+ let len;
38891
+ [len, p] = readVarintAt(buf, p);
38892
+ payloadStart = p;
38893
+ p += Number(len);
38894
+ } else {
38895
+ break;
38896
+ }
38897
+ if (p > buf.length)
38898
+ break;
38899
+ out.push({ no, wire, raw: buf.subarray(start, p), payload: buf.subarray(payloadStart, p) });
38900
+ }
38901
+ return out;
38902
+ }
38903
+ function readVarintValue(tlv) {
38904
+ if (tlv.wire !== 0)
38905
+ return 0;
38906
+ const [value] = readVarintAt(tlv.payload, 0);
38907
+ return Number(value);
38908
+ }
38909
+ function readFloat32LE(tlv) {
38910
+ if (tlv.wire !== 5 || tlv.payload.length < 4)
38911
+ return 0;
38912
+ const view = new DataView(tlv.payload.buffer, tlv.payload.byteOffset, tlv.payload.byteLength);
38913
+ return view.getFloat32(0, true);
38914
+ }
38915
+ function readString(tlv) {
38916
+ return textDecoder.decode(tlv.payload);
38917
+ }
38918
+ function createFrameReader() {
38919
+ let pending = new Uint8Array(0);
38920
+ return (chunk) => {
38921
+ if (chunk.length > 0) {
38922
+ if (pending.length === 0) {
38923
+ pending = chunk;
38924
+ } else {
38925
+ const merged = new Uint8Array(pending.length + chunk.length);
38926
+ merged.set(pending, 0);
38927
+ merged.set(chunk, pending.length);
38928
+ pending = merged;
38929
+ }
38930
+ }
38931
+ const frames = [];
38932
+ let offset = 0;
38933
+ while (offset + FRAME_HEADER_BYTES <= pending.length) {
38934
+ const flags = pending[offset];
38935
+ const length = readUint32BE(pending, offset + 1);
38936
+ const end = offset + FRAME_HEADER_BYTES + length;
38937
+ if (end > pending.length)
38938
+ break;
38939
+ frames.push({ flags, payload: pending.slice(offset + FRAME_HEADER_BYTES, end) });
38940
+ offset = end;
38941
+ }
38942
+ if (offset > 0)
38943
+ pending = pending.slice(offset);
38944
+ return frames;
38945
+ };
38946
+ }
38947
+ var FRAME_HEADER_BYTES = 5, FRAME_FLAG_END_OF_STREAM = 2, textEncoder, textDecoder;
38948
+ var init_proto_codec = __esm(() => {
38949
+ textEncoder = new TextEncoder;
38950
+ textDecoder = new TextDecoder;
38951
+ });
38952
+
38953
+ // src/handlers/shared/devin-stream-head-sniffer.ts
38954
+ function classifyDevinStreamError(code, message) {
38955
+ const lowerCode = code.toLowerCase();
38956
+ if (RETRYABLE_CODES.has(lowerCode))
38957
+ return "retryable";
38958
+ if (TERMINAL_CODES.has(lowerCode))
38959
+ return "terminal";
38960
+ if (lowerCode === "resource_exhausted") {
38961
+ return QUOTA_MESSAGE_RE.test(message) ? "terminal" : "retryable";
38962
+ }
38963
+ if (RETRYABLE_MESSAGE_RE.test(message))
38964
+ return "retryable";
38965
+ return "terminal";
38966
+ }
38967
+ async function sniffDevinStreamHead(response, opts = {}) {
38968
+ const budgetMs = opts.budgetMs ?? DEVIN_SNIFF_BUDGET_MS;
38969
+ const logMsg = opts.log ?? (() => {});
38970
+ if (!response.body)
38971
+ return { kind: "clean", response };
38972
+ const reader = response.body.getReader();
38973
+ const consumed = [];
38974
+ const nextFrames = createFrameReader();
38975
+ const decoder = new TextDecoder;
38976
+ const deadline = Date.now() + budgetMs;
38977
+ const replayResponse = () => {
38978
+ const buffered = consumed.slice();
38979
+ const body = new ReadableStream({
38980
+ start: async (controller) => {
38981
+ try {
38982
+ for (const chunk of buffered)
38983
+ controller.enqueue(chunk);
38984
+ while (true) {
38985
+ const { done, value } = await reader.read();
38986
+ if (done)
38987
+ break;
38988
+ if (value)
38989
+ controller.enqueue(value);
38990
+ }
38991
+ controller.close();
38992
+ } catch (error46) {
38993
+ try {
38994
+ controller.error(error46);
38995
+ } catch {}
38996
+ }
38997
+ },
38998
+ cancel: () => {
38999
+ reader.cancel().catch(() => {});
39000
+ }
39001
+ });
39002
+ return new Response(body, {
39003
+ status: response.status,
39004
+ statusText: response.statusText,
39005
+ headers: response.headers
39006
+ });
39007
+ };
39008
+ try {
39009
+ while (true) {
39010
+ const remaining = deadline - Date.now();
39011
+ if (remaining <= 0) {
39012
+ logMsg(`[DevinSniff] budget ${budgetMs}ms elapsed with no verdict \u2014 streaming through`);
39013
+ return { kind: "clean", response: replayResponse() };
39014
+ }
39015
+ let timer;
39016
+ const timeout = new Promise((resolve2) => {
39017
+ timer = setTimeout(() => resolve2("timeout"), remaining);
39018
+ });
39019
+ let result;
39020
+ try {
39021
+ result = await Promise.race([reader.read(), timeout]);
39022
+ } finally {
39023
+ if (timer)
39024
+ clearTimeout(timer);
39025
+ }
39026
+ if (result === "timeout") {
39027
+ logMsg(`[DevinSniff] budget ${budgetMs}ms elapsed mid-read \u2014 streaming through`);
39028
+ return { kind: "clean", response: replayResponse() };
39029
+ }
39030
+ if (result.done)
39031
+ return { kind: "clean", response: replayResponse() };
39032
+ if (!result.value)
39033
+ continue;
39034
+ consumed.push(result.value);
39035
+ for (const frame of nextFrames(result.value)) {
39036
+ if (frame.flags !== FRAME_FLAG_END_OF_STREAM) {
39037
+ return { kind: "clean", response: replayResponse() };
39038
+ }
39039
+ const raw = decoder.decode(frame.payload).trim();
39040
+ if (!raw || raw === "{}") {
39041
+ return { kind: "clean", response: replayResponse() };
39042
+ }
39043
+ let code = "unknown";
39044
+ let message = raw;
39045
+ try {
39046
+ const parsed = JSON.parse(raw);
39047
+ code = String(parsed?.error?.code ?? parsed?.code ?? "unknown");
39048
+ message = String(parsed?.error?.message ?? parsed?.message ?? raw);
39049
+ } catch {}
39050
+ const kind = classifyDevinStreamError(code, message);
39051
+ logMsg(`[DevinSniff] in-stream error ${code} classified ${kind}: ${message.slice(0, 200)}`);
39052
+ reader.cancel().catch(() => {});
39053
+ return { kind, code, message };
39054
+ }
39055
+ }
39056
+ } catch (error46) {
39057
+ logMsg(`[DevinSniff] read failed (${error46}) \u2014 handing stream to parser`);
39058
+ return { kind: "clean", response: replayResponse() };
39059
+ }
39060
+ }
39061
+ var DEVIN_SNIFF_BUDGET_MS = 12000, RETRYABLE_CODES, TERMINAL_CODES, RETRYABLE_MESSAGE_RE, QUOTA_MESSAGE_RE;
39062
+ var init_devin_stream_head_sniffer = __esm(() => {
39063
+ init_proto_codec();
39064
+ RETRYABLE_CODES = new Set(["unavailable", "internal", "deadline_exceeded", "aborted"]);
39065
+ TERMINAL_CODES = new Set([
39066
+ "permission_denied",
39067
+ "unauthenticated",
39068
+ "invalid_argument",
39069
+ "not_found",
39070
+ "failed_precondition",
39071
+ "unimplemented"
39072
+ ]);
39073
+ RETRYABLE_MESSAGE_RE = /third-party model provider is experiencing issues|overloaded|temporarily unavailable|try again|please retry/i;
39074
+ QUOTA_MESSAGE_RE = /quota|out of credits|credit balance|billing|plan limit|exceeded your/i;
38687
39075
  });
38688
39076
 
38689
39077
  // src/handlers/shared/stream-head-sniffer.ts
@@ -39158,6 +39546,350 @@ var init_anthropic_sse = __esm(() => {
39158
39546
  init_logger();
39159
39547
  });
39160
39548
 
39549
+ // src/handlers/shared/stream-parsers/devin-connect.ts
39550
+ function createDevinConnectStream(_c, response, opts) {
39551
+ const encoder = new TextEncoder;
39552
+ let isClosed = false;
39553
+ let pingInterval = null;
39554
+ const stream = new ReadableStream({
39555
+ async start(controller) {
39556
+ const send = (event, data) => {
39557
+ if (!isClosed) {
39558
+ controller.enqueue(encoder.encode(`event: ${event}
39559
+ data: ${JSON.stringify(data)}
39560
+
39561
+ `));
39562
+ }
39563
+ };
39564
+ const msgId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
39565
+ let finalized2 = false;
39566
+ let curIdx = 0;
39567
+ let textIdx = -1;
39568
+ let textStarted = false;
39569
+ let thinkingIdx = -1;
39570
+ let thinkingStarted = false;
39571
+ let inputTokens = 0;
39572
+ let outputTokens = 0;
39573
+ let sawUsage = false;
39574
+ let rawStopReason = null;
39575
+ let servedModel = "";
39576
+ let toolBlocksEmitted = 0;
39577
+ let current = null;
39578
+ let lastActivity = Date.now();
39579
+ const textDecoder2 = new TextDecoder;
39580
+ const reasoningDecoder = new TextDecoder;
39581
+ send("message_start", {
39582
+ type: "message_start",
39583
+ message: {
39584
+ id: msgId,
39585
+ type: "message",
39586
+ role: "assistant",
39587
+ content: [],
39588
+ model: opts.modelName,
39589
+ stop_reason: null,
39590
+ stop_sequence: null,
39591
+ usage: messageStartUsage(opts.priorInputTokens)
39592
+ }
39593
+ });
39594
+ send("ping", { type: "ping" });
39595
+ pingInterval = setInterval(() => {
39596
+ if (!isClosed && Date.now() - lastActivity > 1000) {
39597
+ send("ping", { type: "ping" });
39598
+ }
39599
+ }, 1000);
39600
+ const closeThinking = () => {
39601
+ if (!thinkingStarted)
39602
+ return;
39603
+ send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
39604
+ thinkingStarted = false;
39605
+ };
39606
+ const closeText = () => {
39607
+ if (!textStarted)
39608
+ return;
39609
+ send("content_block_stop", { type: "content_block_stop", index: textIdx });
39610
+ textStarted = false;
39611
+ };
39612
+ const closeCurrentTool = () => {
39613
+ if (!current || current.closed)
39614
+ return;
39615
+ const call = current;
39616
+ current = null;
39617
+ if (call.buffered) {
39618
+ let args = call.args;
39619
+ if (opts.repairToolArgs) {
39620
+ try {
39621
+ const repaired = opts.repairToolArgs(call.name, args);
39622
+ if (typeof repaired === "string" && repaired !== args) {
39623
+ log(`[DevinConnect] tool call repaired: ${call.name}`);
39624
+ args = repaired;
39625
+ }
39626
+ } catch (err) {
39627
+ log(`[DevinConnect] repairToolArgs threw for ${call.name}: ${err}`);
39628
+ }
39629
+ }
39630
+ send("content_block_delta", {
39631
+ type: "content_block_delta",
39632
+ index: call.blockIndex,
39633
+ delta: { type: "input_json_delta", partial_json: args || "{}" }
39634
+ });
39635
+ } else if (!call.args) {
39636
+ send("content_block_delta", {
39637
+ type: "content_block_delta",
39638
+ index: call.blockIndex,
39639
+ delta: { type: "input_json_delta", partial_json: "{}" }
39640
+ });
39641
+ }
39642
+ send("content_block_stop", { type: "content_block_stop", index: call.blockIndex });
39643
+ call.closed = true;
39644
+ };
39645
+ const finalize = (reason, errorMessage) => {
39646
+ if (finalized2)
39647
+ return;
39648
+ finalized2 = true;
39649
+ closeCurrentTool();
39650
+ closeThinking();
39651
+ closeText();
39652
+ if (servedModel && servedModel !== opts.modelName) {
39653
+ log(`[DevinConnect] served model: ${servedModel} (requested ${opts.modelName})`);
39654
+ }
39655
+ if (sawUsage) {
39656
+ log(`[DevinConnect] usage: input=${inputTokens}, output=${outputTokens}` + (rawStopReason !== null ? `, raw stop_reason=${rawStopReason}` : ""));
39657
+ }
39658
+ opts.onTokenUpdate?.(inputTokens, outputTokens);
39659
+ if (reason === "error") {
39660
+ log(`[DevinConnect] stream error: ${errorMessage}`);
39661
+ send("error", { type: "error", error: { type: "api_error", message: errorMessage } });
39662
+ } else {
39663
+ send("message_delta", {
39664
+ type: "message_delta",
39665
+ delta: {
39666
+ stop_reason: toolBlocksEmitted > 0 ? "tool_use" : "end_turn",
39667
+ stop_sequence: null
39668
+ },
39669
+ usage: {
39670
+ ...inputTokens > 0 ? { input_tokens: inputTokens } : {},
39671
+ output_tokens: outputTokens
39672
+ }
39673
+ });
39674
+ opts.onTurnEnd?.();
39675
+ send("message_stop", { type: "message_stop" });
39676
+ }
39677
+ if (!isClosed) {
39678
+ isClosed = true;
39679
+ if (pingInterval) {
39680
+ clearInterval(pingInterval);
39681
+ pingInterval = null;
39682
+ }
39683
+ try {
39684
+ controller.close();
39685
+ } catch {}
39686
+ }
39687
+ };
39688
+ const readUsageGroup = (payload) => {
39689
+ for (const entry of parseTLV(payload)) {
39690
+ if (entry.no !== USAGE_ENTRY || entry.wire !== 2)
39691
+ continue;
39692
+ let key = "";
39693
+ let value = null;
39694
+ for (const field of parseTLV(entry.payload)) {
39695
+ if (field.no === USAGE_ENTRY_KEY && field.wire === 2) {
39696
+ key = readString(field);
39697
+ } else if (field.no === USAGE_ENTRY_STAT && field.wire === 2) {
39698
+ for (const stat2 of parseTLV(field.payload)) {
39699
+ if (stat2.no === USAGE_STAT_VALUE && stat2.wire === 5) {
39700
+ value = Math.round(readFloat32LE(stat2));
39701
+ }
39702
+ }
39703
+ }
39704
+ }
39705
+ if (key === USAGE_KEY_INPUT) {
39706
+ inputTokens = value ?? 0;
39707
+ sawUsage = true;
39708
+ } else if (key === USAGE_KEY_OUTPUT) {
39709
+ outputTokens = value ?? 0;
39710
+ sawUsage = true;
39711
+ }
39712
+ }
39713
+ };
39714
+ const readToolCall = (payload) => {
39715
+ let id = "";
39716
+ let name = "";
39717
+ let fragment = null;
39718
+ for (const field of parseTLV(payload)) {
39719
+ if (field.no === TOOL_ID && field.wire === 2)
39720
+ id = readString(field);
39721
+ else if (field.no === TOOL_NAME && field.wire === 2)
39722
+ name = readString(field);
39723
+ else if (field.no === TOOL_ARGS_FRAGMENT && field.wire === 2)
39724
+ fragment = field;
39725
+ }
39726
+ if (name) {
39727
+ closeCurrentTool();
39728
+ closeThinking();
39729
+ closeText();
39730
+ const restored = opts.toolNameMap?.get(name) ?? name;
39731
+ const blockIndex = curIdx++;
39732
+ const toolId = id || `toolu_${Date.now()}_${blockIndex}`;
39733
+ current = {
39734
+ id: toolId,
39735
+ name: restored,
39736
+ blockIndex,
39737
+ buffered: opts.shouldBufferTool?.(restored) ?? false,
39738
+ args: "",
39739
+ decoder: new TextDecoder,
39740
+ closed: false
39741
+ };
39742
+ toolBlocksEmitted++;
39743
+ opts.onToolCallObserved?.(restored);
39744
+ send("content_block_start", {
39745
+ type: "content_block_start",
39746
+ index: blockIndex,
39747
+ content_block: { type: "tool_use", id: toolId, name: restored, input: {} }
39748
+ });
39749
+ }
39750
+ if (!fragment)
39751
+ return;
39752
+ const chunk = current ? current.decoder.decode(fragment.payload, { stream: true }) : readString(fragment);
39753
+ if (!chunk)
39754
+ return;
39755
+ if (!current) {
39756
+ log("[DevinConnect] argument fragment with no open tool call, dropping");
39757
+ return;
39758
+ }
39759
+ current.args += chunk;
39760
+ if (!current.buffered) {
39761
+ send("content_block_delta", {
39762
+ type: "content_block_delta",
39763
+ index: current.blockIndex,
39764
+ delta: { type: "input_json_delta", partial_json: chunk }
39765
+ });
39766
+ }
39767
+ };
39768
+ const readMessageFrame = (payload) => {
39769
+ for (const field of parseTLV(payload)) {
39770
+ lastActivity = Date.now();
39771
+ if (field.no === FIELD_TEXT && field.wire === 2) {
39772
+ const text = textDecoder2.decode(field.payload, { stream: true });
39773
+ if (!text)
39774
+ continue;
39775
+ closeCurrentTool();
39776
+ closeThinking();
39777
+ if (!textStarted) {
39778
+ textIdx = curIdx++;
39779
+ send("content_block_start", {
39780
+ type: "content_block_start",
39781
+ index: textIdx,
39782
+ content_block: { type: "text", text: "" }
39783
+ });
39784
+ textStarted = true;
39785
+ }
39786
+ opts.onAssistantText?.(text, "text");
39787
+ send("content_block_delta", {
39788
+ type: "content_block_delta",
39789
+ index: textIdx,
39790
+ delta: { type: "text_delta", text }
39791
+ });
39792
+ } else if (field.no === FIELD_REASONING && field.wire === 2) {
39793
+ const thinking = reasoningDecoder.decode(field.payload, { stream: true });
39794
+ if (!thinking)
39795
+ continue;
39796
+ closeCurrentTool();
39797
+ if (!thinkingStarted) {
39798
+ thinkingIdx = curIdx++;
39799
+ send("content_block_start", {
39800
+ type: "content_block_start",
39801
+ index: thinkingIdx,
39802
+ content_block: { type: "thinking", thinking: "" }
39803
+ });
39804
+ thinkingStarted = true;
39805
+ }
39806
+ opts.onAssistantText?.(thinking, "reasoning");
39807
+ send("content_block_delta", {
39808
+ type: "content_block_delta",
39809
+ index: thinkingIdx,
39810
+ delta: { type: "thinking_delta", thinking }
39811
+ });
39812
+ } else if (field.no === FIELD_TOOL_CALL && field.wire === 2) {
39813
+ readToolCall(field.payload);
39814
+ } else if (field.no === FIELD_STOP_REASON && field.wire === 0) {
39815
+ rawStopReason = readVarintValue(field);
39816
+ } else if (field.no === FIELD_META && field.wire === 2) {
39817
+ for (const sub of parseTLV(field.payload)) {
39818
+ if (sub.no === META_SERVED_MODEL && sub.wire === 2) {
39819
+ const uid = readString(sub);
39820
+ if (uid && uid !== servedModel) {
39821
+ servedModel = uid;
39822
+ opts.onServedModel?.(uid);
39823
+ }
39824
+ }
39825
+ }
39826
+ } else if (field.no === FIELD_USAGE && field.wire === 2) {
39827
+ readUsageGroup(field.payload);
39828
+ }
39829
+ }
39830
+ };
39831
+ try {
39832
+ const body = response.body;
39833
+ if (!body) {
39834
+ finalize("error", "Devin returned no response body");
39835
+ return;
39836
+ }
39837
+ const reader = body.getReader();
39838
+ const nextFrames = createFrameReader();
39839
+ while (true) {
39840
+ const { done, value } = await reader.read();
39841
+ if (done)
39842
+ break;
39843
+ if (!value)
39844
+ continue;
39845
+ for (const frame of nextFrames(value)) {
39846
+ if (frame.flags === FRAME_FLAG_END_OF_STREAM) {
39847
+ const raw = new TextDecoder().decode(frame.payload).trim();
39848
+ if (!raw || raw === "{}") {
39849
+ finalize("done");
39850
+ return;
39851
+ }
39852
+ let code = "unknown";
39853
+ let message = raw;
39854
+ try {
39855
+ const parsed = JSON.parse(raw);
39856
+ code = String(parsed?.error?.code ?? parsed?.code ?? "unknown");
39857
+ message = String(parsed?.error?.message ?? parsed?.message ?? raw);
39858
+ } catch {}
39859
+ opts.onApiError?.(code, message);
39860
+ finalize("error", `${code}: ${message}`);
39861
+ return;
39862
+ }
39863
+ readMessageFrame(frame.payload);
39864
+ }
39865
+ }
39866
+ finalize("done");
39867
+ } catch (e) {
39868
+ finalize("error", String(e));
39869
+ }
39870
+ },
39871
+ cancel() {
39872
+ isClosed = true;
39873
+ if (pingInterval) {
39874
+ clearInterval(pingInterval);
39875
+ pingInterval = null;
39876
+ }
39877
+ }
39878
+ });
39879
+ return new Response(stream, {
39880
+ headers: {
39881
+ "Content-Type": "text/event-stream",
39882
+ "Cache-Control": "no-cache",
39883
+ Connection: "keep-alive"
39884
+ }
39885
+ });
39886
+ }
39887
+ var FIELD_TEXT = 3, FIELD_STOP_REASON = 5, FIELD_TOOL_CALL = 6, FIELD_META = 7, FIELD_REASONING = 9, FIELD_USAGE = 28, TOOL_ID = 1, TOOL_NAME = 2, TOOL_ARGS_FRAGMENT = 3, META_SERVED_MODEL = 9, USAGE_ENTRY = 2, USAGE_ENTRY_KEY = 5, USAGE_ENTRY_STAT = 4, USAGE_STAT_VALUE = 2, USAGE_KEY_INPUT = "input_tokens", USAGE_KEY_OUTPUT = "output_tokens";
39888
+ var init_devin_connect = __esm(() => {
39889
+ init_logger();
39890
+ init_proto_codec();
39891
+ });
39892
+
39161
39893
  // src/handlers/shared/stream-parsers/gemini-sse.ts
39162
39894
  function createGeminiSseStream(_c, response, opts) {
39163
39895
  const encoder = new TextEncoder;
@@ -39968,8 +40700,8 @@ var init_openai_responses_sse = __esm(() => {
39968
40700
 
39969
40701
  // src/handlers/shared/token-tracker.ts
39970
40702
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
39971
- import { homedir as homedir23 } from "os";
39972
- import { dirname as dirname8, join as join23 } from "path";
40703
+ import { homedir as homedir24 } from "os";
40704
+ import { dirname as dirname8, join as join24 } from "path";
39973
40705
  function stripProviderPrefix(name) {
39974
40706
  const at = name.indexOf("@");
39975
40707
  return at === -1 ? name : name.slice(at + 1);
@@ -40131,7 +40863,7 @@ class TokenTracker {
40131
40863
  };
40132
40864
  }
40133
40865
  const override = process.env.CLAUDISH_TOKEN_FILE;
40134
- const outPath = override || join23(homedir23(), ".claudish", `tokens-${this.port}.json`);
40866
+ const outPath = override || join24(homedir24(), ".claudish", `tokens-${this.port}.json`);
40135
40867
  mkdirSync10(dirname8(outPath), { recursive: true });
40136
40868
  writeFileSync9(outPath, JSON.stringify(data), "utf-8");
40137
40869
  } catch (e) {
@@ -40229,10 +40961,10 @@ class ComposedHandler {
40229
40961
  if (!this.getModelSupportsVision()) {
40230
40962
  const imageBlocks = [];
40231
40963
  for (let msgIdx = 0;msgIdx < messages.length; msgIdx++) {
40232
- const msg = messages[msgIdx];
40233
- if (Array.isArray(msg.content)) {
40234
- for (let partIdx = 0;partIdx < msg.content.length; partIdx++) {
40235
- const part = msg.content[partIdx];
40964
+ const msg2 = messages[msgIdx];
40965
+ if (Array.isArray(msg2.content)) {
40966
+ for (let partIdx = 0;partIdx < msg2.content.length; partIdx++) {
40967
+ const part = msg2.content[partIdx];
40236
40968
  if (part.type === "image_url" || part.type === "image" || part.type === "document") {
40237
40969
  imageBlocks.push({ msgIdx, partIdx, block: part });
40238
40970
  }
@@ -40256,25 +40988,25 @@ class ComposedHandler {
40256
40988
  };
40257
40989
  }
40258
40990
  log(`[ComposedHandler] Vision proxy described ${descriptions.length} image(s)`);
40259
- for (const msg of messages) {
40260
- if (Array.isArray(msg.content)) {
40261
- msg.content = msg.content.filter((part) => part.type !== "image" && part.type !== "document");
40262
- if (msg.content.length === 1 && msg.content[0].type === "text") {
40263
- msg.content = msg.content[0].text;
40264
- } else if (msg.content.length === 0) {
40265
- msg.content = "";
40991
+ for (const msg2 of messages) {
40992
+ if (Array.isArray(msg2.content)) {
40993
+ msg2.content = msg2.content.filter((part) => part.type !== "image" && part.type !== "document");
40994
+ if (msg2.content.length === 1 && msg2.content[0].type === "text") {
40995
+ msg2.content = msg2.content[0].text;
40996
+ } else if (msg2.content.length === 0) {
40997
+ msg2.content = "";
40266
40998
  }
40267
40999
  }
40268
41000
  }
40269
41001
  } else {
40270
41002
  log("[ComposedHandler] Stripping image/document blocks (vision not supported)");
40271
- for (const msg of messages) {
40272
- if (Array.isArray(msg.content)) {
40273
- msg.content = msg.content.filter((part) => part.type !== "image_url" && part.type !== "image" && part.type !== "document");
40274
- if (msg.content.length === 1 && msg.content[0].type === "text") {
40275
- msg.content = msg.content[0].text;
40276
- } else if (msg.content.length === 0) {
40277
- msg.content = "";
41003
+ for (const msg2 of messages) {
41004
+ if (Array.isArray(msg2.content)) {
41005
+ msg2.content = msg2.content.filter((part) => part.type !== "image_url" && part.type !== "image" && part.type !== "document");
41006
+ if (msg2.content.length === 1 && msg2.content[0].type === "text") {
41007
+ msg2.content = msg2.content[0].text;
41008
+ } else if (msg2.content.length === 0) {
41009
+ msg2.content = "";
40278
41010
  }
40279
41011
  }
40280
41012
  }
@@ -40312,7 +41044,7 @@ class ComposedHandler {
40312
41044
  const behaviorSession = this.behaviorEngine.startSession({
40313
41045
  modelId: this.bareModelName,
40314
41046
  providerName: this.provider.name,
40315
- isNativeAnthropic: /^claude[-.]/i.test(this.bareModelName) || this.provider.name === "anthropic"
41047
+ isNativeAnthropic: !this.options.forceForeignModel && (/^claude[-.]/i.test(this.bareModelName) || this.provider.name === "anthropic")
40316
41048
  });
40317
41049
  if (!behaviorSession.isNoop) {
40318
41050
  behaviorSession.applyRequest(claudeRequest, claudeRequest.tools ?? [], tools, messages);
@@ -40368,13 +41100,14 @@ class ComposedHandler {
40368
41100
  }
40369
41101
  const endpoint = this.provider.getEndpoint(this.targetModel);
40370
41102
  const headers = await this.provider.getHeaders();
40371
- headers["Content-Type"] = "application/json";
41103
+ const serialized = this.provider.serializeBody?.(requestPayload);
41104
+ headers["Content-Type"] = serialized?.contentType ?? "application/json";
40372
41105
  log(`[${this.provider.displayName}] Calling API: ${endpoint}`);
40373
41106
  const requestInit = this.provider.getRequestInit?.() || {};
40374
41107
  const doFetch = () => fetch(endpoint, {
40375
41108
  method: "POST",
40376
41109
  headers,
40377
- body: JSON.stringify(requestPayload),
41110
+ body: serialized?.body ?? JSON.stringify(requestPayload),
40378
41111
  ...requestInit
40379
41112
  });
40380
41113
  let response;
@@ -40383,9 +41116,9 @@ class ComposedHandler {
40383
41116
  } catch (error46) {
40384
41117
  const conn = classifyConnectionError(error46);
40385
41118
  if (conn) {
40386
- const msg = buildConnectionErrorMessage(conn.kind, this.provider.displayName, endpoint);
40387
- log(`[${this.provider.displayName}] ${msg} (code=${conn.code})`);
40388
- logStderr(`Error: ${msg}`);
41119
+ const msg2 = buildConnectionErrorMessage(conn.kind, this.provider.displayName, endpoint);
41120
+ log(`[${this.provider.displayName}] ${msg2} (code=${conn.code})`);
41121
+ logStderr(`Error: ${msg2}`);
40389
41122
  reportError({
40390
41123
  error: error46,
40391
41124
  providerName: this.provider.name,
@@ -40417,7 +41150,7 @@ class ComposedHandler {
40417
41150
  invocation_mode: this.options.invocationMode ?? "auto-route"
40418
41151
  });
40419
41152
  } catch {}
40420
- return c.json(wrapAnthropicError(400, msg, "connection_error"), 400);
41153
+ return c.json(wrapAnthropicError(400, msg2, "connection_error"), 400);
40421
41154
  }
40422
41155
  throw error46;
40423
41156
  }
@@ -40434,12 +41167,12 @@ class ComposedHandler {
40434
41167
  try {
40435
41168
  await this.provider.forceRefreshAuth();
40436
41169
  const retryHeaders = await this.provider.getHeaders();
40437
- retryHeaders["Content-Type"] = "application/json";
41170
+ retryHeaders["Content-Type"] = serialized?.contentType ?? "application/json";
40438
41171
  const retryInit = this.provider.getRequestInit?.() || {};
40439
41172
  const retryResp = await fetch(endpoint, {
40440
41173
  method: "POST",
40441
41174
  headers: retryHeaders,
40442
- body: JSON.stringify(requestPayload),
41175
+ body: serialized?.body ?? JSON.stringify(requestPayload),
40443
41176
  ...retryInit
40444
41177
  });
40445
41178
  if (retryResp.ok) {
@@ -40619,6 +41352,48 @@ class ComposedHandler {
40619
41352
  }
40620
41353
  response = settled.response;
40621
41354
  }
41355
+ if (this.resolveStreamFormat() === "connect-proto") {
41356
+ const settled = await this.settleDevinStreamHead(response, () => this.provider.enqueueRequest ? this.provider.enqueueRequest(doFetch) : doFetch());
41357
+ if (settled.kind !== "ok") {
41358
+ const isTerminal2 = settled.kind === "terminal";
41359
+ const httpStatus2 = isTerminal2 ? 400 : 503;
41360
+ const surfaced = isTerminal2 ? `${this.provider.displayName} rejected the request (${settled.code}): ${settled.message}` : `${this.provider.displayName} is overloaded upstream (${settled.code}): ${settled.message} ` + `claudish retried ${settled.attempts}\xD7 over ` + `${Math.round(STREAM_RETRY_DELAYS_MS.slice(0, settled.attempts).reduce((sum, ms) => sum + ms, 0) / 1000)}s without success.`;
41361
+ logStderr(`Error: ${surfaced}`);
41362
+ reportError({
41363
+ error: new Error(settled.message),
41364
+ providerName: this.provider.name,
41365
+ providerDisplayName: this.provider.displayName,
41366
+ streamFormat: this.provider.streamFormat,
41367
+ modelId: this.targetModel,
41368
+ httpStatus: httpStatus2,
41369
+ isStreaming: true,
41370
+ retryAttempted: !isTerminal2,
41371
+ isInteractive: this.isInteractive,
41372
+ providerErrorType: settled.code
41373
+ });
41374
+ try {
41375
+ recordStats({
41376
+ model_id: this.targetModel,
41377
+ provider_name: this.provider.name,
41378
+ stream_format: this.provider.streamFormat,
41379
+ latency_ms: Math.round(performance.now() - startTime),
41380
+ success: false,
41381
+ http_status: httpStatus2,
41382
+ error_class: isTerminal2 ? "client_error" : "server_error",
41383
+ error_code: settled.code,
41384
+ token_strategy: this.options.tokenStrategy ?? "standard",
41385
+ adapter_name: this.getActiveAdapterName(),
41386
+ middleware_names: this.middlewareManager.getActiveNames(this.bareModelName),
41387
+ fallback_used: fallbackMeta !== undefined,
41388
+ fallback_chain: fallbackMeta?.chain,
41389
+ fallback_attempts: fallbackMeta?.attempts,
41390
+ invocation_mode: this.options.invocationMode ?? "auto-route"
41391
+ });
41392
+ } catch {}
41393
+ return isTerminal2 ? c.json(wrapAnthropicError(400, surfaced, "invalid_request_error"), 400) : c.json(wrapAnthropicError(503, surfaced, "overloaded_error"), 503);
41394
+ }
41395
+ response = settled.response;
41396
+ }
40622
41397
  latencyMs = Math.round(performance.now() - startTime);
40623
41398
  const httpStatus = response.status;
40624
41399
  this.capturePlanUsage(response);
@@ -40697,6 +41472,55 @@ class ComposedHandler {
40697
41472
  response = next;
40698
41473
  }
40699
41474
  }
41475
+ async settleDevinStreamHead(initial, reissue) {
41476
+ const rewrite = this.provider.rewriteInStreamError?.bind(this.provider);
41477
+ let response = initial;
41478
+ for (let attempt = 0;; attempt++) {
41479
+ const verdict = await sniffDevinStreamHead(response, { log });
41480
+ if (verdict.kind === "clean")
41481
+ return { kind: "ok", response: verdict.response };
41482
+ if (verdict.kind === "terminal") {
41483
+ const message = rewrite?.(verdict.code, verdict.message) ?? verdict.message;
41484
+ log(`[${this.provider.displayName}] terminal in-stream error ${verdict.code}`);
41485
+ return { kind: "terminal", code: verdict.code, message };
41486
+ }
41487
+ const delayMs = STREAM_RETRY_DELAYS_MS[attempt];
41488
+ if (delayMs === undefined) {
41489
+ log(`[${this.provider.displayName}] in-stream ${verdict.code} persisted after ` + `${attempt} retries \u2014 surfacing 503 so the client can retry`);
41490
+ return {
41491
+ kind: "exhausted",
41492
+ code: verdict.code,
41493
+ message: verdict.message,
41494
+ attempts: attempt
41495
+ };
41496
+ }
41497
+ log(`[${this.provider.displayName}] in-stream ${verdict.code} before any output \u2014 ` + `retry ${attempt + 1}/${STREAM_RETRY_DELAYS_MS.length} in ${delayMs / 1000}s`);
41498
+ await new Promise((resolve2) => setTimeout(resolve2, delayMs));
41499
+ let next;
41500
+ try {
41501
+ next = await reissue();
41502
+ } catch (error46) {
41503
+ log(`[${this.provider.displayName}] retry fetch failed: ${error46}`);
41504
+ return {
41505
+ kind: "exhausted",
41506
+ code: verdict.code,
41507
+ message: `${verdict.message} (retry could not reach the provider: ${error46})`,
41508
+ attempts: attempt + 1
41509
+ };
41510
+ }
41511
+ if (!next.ok) {
41512
+ const body = await next.text().catch(() => "");
41513
+ log(`[${this.provider.displayName}] retry returned HTTP ${next.status}`);
41514
+ return {
41515
+ kind: "exhausted",
41516
+ code: `http_${next.status}`,
41517
+ message: body.slice(0, 500) || `HTTP ${next.status}`,
41518
+ attempts: attempt + 1
41519
+ };
41520
+ }
41521
+ response = next;
41522
+ }
41523
+ }
40700
41524
  resolveStreamFormat() {
40701
41525
  return this.provider.overrideStreamFormat?.() ?? this.explicitAdapter?.getStreamFormat() ?? this.modelAdapter?.getStreamFormat() ?? this.getAdapter().getStreamFormat();
40702
41526
  }
@@ -40782,6 +41606,23 @@ class ComposedHandler {
40782
41606
  priorInputTokens
40783
41607
  });
40784
41608
  }
41609
+ case "connect-proto":
41610
+ return createDevinConnectStream(c, response, {
41611
+ modelName: this.bareModelName,
41612
+ onTokenUpdate,
41613
+ priorInputTokens,
41614
+ onApiError,
41615
+ toolNameMap,
41616
+ onServedModel: (uid) => {
41617
+ if (uid !== this.bareModelName)
41618
+ this.tokenTracker.setActiveModelName(uid);
41619
+ },
41620
+ repairToolArgs: (name, argsJson) => behaviorSession?.repairToolCall(name, argsJson) ?? null,
41621
+ shouldBufferTool: (name) => behaviorSession?.interceptsTool(name) ?? false,
41622
+ onAssistantText: (text, kind) => behaviorSession?.observeText(text, kind),
41623
+ onToolCallObserved: (name) => behaviorSession?.observeToolCall(name),
41624
+ onTurnEnd: () => behaviorSession?.finishTurn()
41625
+ });
40785
41626
  case "ollama-jsonl":
40786
41627
  return createOllamaJsonlStream(c, response, {
40787
41628
  modelName: this.bareModelName,
@@ -40837,6 +41678,9 @@ function getRecoveryHint(status, errorText, providerName) {
40837
41678
  if (status === 429 && isTerminal429(errorText)) {
40838
41679
  return "Out of quota \u2014 check your plan & billing details. This won't recover on retry.";
40839
41680
  }
41681
+ if (isQuotaExhaustionError(status, errorText)) {
41682
+ return "Subscription allowance spent \u2014 this refills on the provider's own schedule (see the message below). Reducing concurrency won't help; switch model/provider or wait.";
41683
+ }
40840
41684
  if (status === 429 || lower.includes("rate limit")) {
40841
41685
  return "Rate limited. Wait, reduce concurrency, or check plan limits.";
40842
41686
  }
@@ -40883,10 +41727,12 @@ var init_composed_handler = __esm(() => {
40883
41727
  init_anthropic_error();
40884
41728
  init_connection_error();
40885
41729
  init_context_window_fallback();
41730
+ init_devin_stream_head_sniffer();
40886
41731
  init_openai_compat();
40887
41732
  init_quota_exhaustion();
40888
41733
  init_stream_head_sniffer();
40889
41734
  init_anthropic_sse();
41735
+ init_devin_connect();
40890
41736
  init_gemini_sse();
40891
41737
  init_ollama_jsonl();
40892
41738
  init_openai_responses_sse();
@@ -40895,6 +41741,209 @@ var init_composed_handler = __esm(() => {
40895
41741
  STREAM_RETRY_DELAYS_MS = [3000, 15000, 30000];
40896
41742
  });
40897
41743
 
41744
+ // src/providers/devin/devin-request.ts
41745
+ import { randomUUID as randomUUID4 } from "crypto";
41746
+ function encodeChatMetadata(meta3) {
41747
+ const version2 = meta3.clientVersion ?? DEVIN_CLI_VERSION;
41748
+ return msg(bytes(1, "devin-cli"), bytes(2, version2), bytes(3, meta3.apiKey), bytes(4, "en"), bytes(5, meta3.platform ?? process.platform), bytes(7, version2), bytes(12, "chisel"), bytes(28, "chisel"));
41749
+ }
41750
+ function encodeMessage(message) {
41751
+ const parts = [
41752
+ bytes(1, message.id ?? randomUUID4()),
41753
+ vint(2, DEVIN_ROLE[message.role])
41754
+ ];
41755
+ if (message.text)
41756
+ parts.push(bytes(3, message.text));
41757
+ if (message.toolCall) {
41758
+ parts.push(bytes(6, msg(bytes(1, message.toolCall.id), bytes(2, message.toolCall.name), bytes(3, message.toolCall.argumentsJson))));
41759
+ }
41760
+ if (message.toolCallId)
41761
+ parts.push(bytes(7, message.toolCallId));
41762
+ return msg(...parts);
41763
+ }
41764
+ function encodeTool(tool) {
41765
+ return msg(bytes(1, tool.name), bytes(2, tool.description ?? ""), bytes(3, tool.parametersJson));
41766
+ }
41767
+ function encodeRequestBodyParts(req) {
41768
+ const parts = [];
41769
+ if (req.system)
41770
+ parts.push(bytes(2, req.system));
41771
+ for (const message of req.messages)
41772
+ parts.push(bytes(3, encodeMessage(message)));
41773
+ parts.push(vint(7, req.modelEnum ?? DEFAULT_MODEL_ENUM));
41774
+ for (const tool of req.tools ?? [])
41775
+ parts.push(bytes(10, encodeTool(tool)));
41776
+ parts.push(bytes(21, req.modelUid));
41777
+ return parts;
41778
+ }
41779
+ function encodeDevinRequest(req, meta3) {
41780
+ const body = msg(bytes(1, encodeChatMetadata(meta3)), ...encodeRequestBodyParts(req));
41781
+ return envelope(body);
41782
+ }
41783
+ function describeDevinRequestForLog(req) {
41784
+ const roles = { user: 0, assistant: 0, tool_result: 0 };
41785
+ let toolCalls = 0;
41786
+ for (const message of req.messages) {
41787
+ roles[message.role]++;
41788
+ if (message.toolCall)
41789
+ toolCalls++;
41790
+ }
41791
+ const size = encodeRequestBodyParts(req).reduce((total, part) => total + part.length, 0);
41792
+ const fields = [
41793
+ `uid=${req.modelUid}`,
41794
+ `enum=${req.modelEnum ?? DEFAULT_MODEL_ENUM}`,
41795
+ `messages=${req.messages.length}`,
41796
+ `(user ${roles.user}/assistant ${roles.assistant}/tool_result ${roles.tool_result}`,
41797
+ `calls ${toolCalls})`,
41798
+ `tools=${req.tools?.length ?? 0}`,
41799
+ `system=${req.system?.length ?? 0}ch`
41800
+ ];
41801
+ fields.push(`body=${size}B (excl. metadata)`);
41802
+ return fields.join(" ");
41803
+ }
41804
+ var DEVIN_CLI_VERSION = "3000.3.27", DEFAULT_MODEL_ENUM = 5, DEVIN_ROLE;
41805
+ var init_devin_request = __esm(() => {
41806
+ init_proto_codec();
41807
+ DEVIN_ROLE = {
41808
+ user: 1,
41809
+ assistant: 2,
41810
+ tool_result: 4
41811
+ };
41812
+ });
41813
+
41814
+ // src/providers/devin/devin-models.ts
41815
+ var exports_devin_models = {};
41816
+ __export(exports_devin_models, {
41817
+ getServedDevinModels: () => getServedDevinModels,
41818
+ fetchDevinModelConfigs: () => fetchDevinModelConfigs,
41819
+ fetchDevinAllowedUids: () => fetchDevinAllowedUids,
41820
+ _resetDevinModelCache: () => _resetDevinModelCache
41821
+ });
41822
+ function unaryMetadata(apiKey) {
41823
+ return msg(bytes(1, "chisel"), bytes(2, DEVIN_CLI_VERSION), bytes(3, apiKey), bytes(4, "en"), bytes(5, process.platform), bytes(7, DEVIN_CLI_VERSION));
41824
+ }
41825
+ async function postUnary(path, apiKey) {
41826
+ const url2 = `${readDevinServerUrl()}${path}`;
41827
+ try {
41828
+ const response = await fetch(url2, {
41829
+ method: "POST",
41830
+ headers: {
41831
+ authorization: `Basic ${apiKey}-${apiKey}`,
41832
+ "content-type": "application/proto",
41833
+ "connect-protocol-version": "1"
41834
+ },
41835
+ body: msg(bytes(1, unaryMetadata(apiKey))),
41836
+ signal: AbortSignal.timeout(UNARY_TIMEOUT_MS)
41837
+ });
41838
+ if (!response.ok) {
41839
+ log(`[Devin] ${path} failed: HTTP ${response.status}`);
41840
+ return null;
41841
+ }
41842
+ return new Uint8Array(await response.arrayBuffer());
41843
+ } catch (err) {
41844
+ log(`[Devin] ${path} error: ${err}`);
41845
+ return null;
41846
+ }
41847
+ }
41848
+ function decodeModelDetails(payload) {
41849
+ let maxOutput = 0;
41850
+ let family = "";
41851
+ for (const sub of parseTLV(payload)) {
41852
+ if (sub.no === 13 && sub.wire === 0)
41853
+ maxOutput = readVarintValue(sub);
41854
+ else if (sub.no === 23 && sub.wire === 2)
41855
+ family = readString(sub);
41856
+ }
41857
+ return { maxOutput, family };
41858
+ }
41859
+ function decodeModelConfig(payload) {
41860
+ let uid = "";
41861
+ let displayName = "";
41862
+ let contextWindow = 0;
41863
+ let details = { maxOutput: 0, family: "" };
41864
+ for (const field of parseTLV(payload)) {
41865
+ if (field.no === 22 && field.wire === 2)
41866
+ uid = readString(field);
41867
+ else if (field.no === 1 && field.wire === 2)
41868
+ displayName = readString(field);
41869
+ else if (field.no === 18 && field.wire === 0)
41870
+ contextWindow = readVarintValue(field);
41871
+ else if (field.no === 23 && field.wire === 2)
41872
+ details = decodeModelDetails(field.payload);
41873
+ }
41874
+ if (!uid)
41875
+ return null;
41876
+ return { uid, displayName: displayName || uid, contextWindow, ...details };
41877
+ }
41878
+ function topLevelDelimited(body, fieldNumber) {
41879
+ return parseTLV(body).filter((field) => field.no === fieldNumber && field.wire === 2);
41880
+ }
41881
+ async function fetchDevinModelConfigs(apiKey) {
41882
+ const body = await postUnary(MODEL_CONFIGS_PATH, apiKey);
41883
+ if (!body)
41884
+ return [];
41885
+ const configs = [];
41886
+ for (const field of topLevelDelimited(body, 1)) {
41887
+ const config2 = decodeModelConfig(field.payload);
41888
+ if (config2)
41889
+ configs.push(config2);
41890
+ }
41891
+ log(`[Devin] GetCliModelConfigs: ${configs.length} configs`);
41892
+ return configs;
41893
+ }
41894
+ async function fetchDevinAllowedUids(apiKey) {
41895
+ const body = await postUnary(TEAM_SETTINGS_PATH, apiKey);
41896
+ if (!body)
41897
+ return [];
41898
+ const uids = [];
41899
+ for (const field of topLevelDelimited(body, 7)) {
41900
+ const uid = readString(field).trim();
41901
+ if (uid)
41902
+ uids.push(uid);
41903
+ }
41904
+ log(`[Devin] GetCliTeamSettings: ${uids.length} allowed uids`);
41905
+ return uids;
41906
+ }
41907
+ async function getServedDevinModels(opts) {
41908
+ const now = Date.now();
41909
+ if (!opts?.force && rosterCache && now - rosterCacheAt < ROSTER_TTL_MS)
41910
+ return rosterCache;
41911
+ const apiKey = opts?.apiKey ?? readDevinApiKey();
41912
+ if (!apiKey)
41913
+ return rosterCache ?? [];
41914
+ try {
41915
+ const [configs, allowed] = await Promise.all([
41916
+ fetchDevinModelConfigs(apiKey),
41917
+ fetchDevinAllowedUids(apiKey)
41918
+ ]);
41919
+ if (configs.length === 0)
41920
+ return rosterCache ?? [];
41921
+ const entitled = new Set(allowed);
41922
+ const served = configs.filter((config2) => config2.contextWindow > 0 && (entitled.size === 0 || entitled.has(config2.uid)));
41923
+ if (entitled.size === 0) {
41924
+ log("[Devin] entitlement unknown \u2014 using the full config list (superset)");
41925
+ }
41926
+ rosterCache = served;
41927
+ rosterCacheAt = now;
41928
+ return served;
41929
+ } catch (err) {
41930
+ log(`[Devin] served-model discovery error: ${err}`);
41931
+ return rosterCache ?? [];
41932
+ }
41933
+ }
41934
+ function _resetDevinModelCache() {
41935
+ rosterCache = null;
41936
+ rosterCacheAt = 0;
41937
+ }
41938
+ var MODEL_CONFIGS_PATH = "/exa.api_server_pb.ApiServerService/GetCliModelConfigs", TEAM_SETTINGS_PATH = "/exa.seat_management_pb.SeatManagementService/GetCliTeamSettings", ROSTER_TTL_MS, UNARY_TIMEOUT_MS = 1e4, rosterCache = null, rosterCacheAt = 0;
41939
+ var init_devin_models = __esm(() => {
41940
+ init_logger();
41941
+ init_devin_credentials();
41942
+ init_devin_request();
41943
+ init_proto_codec();
41944
+ ROSTER_TTL_MS = 5 * 60 * 1000;
41945
+ });
41946
+
40898
41947
  // src/providers/model-discovery.ts
40899
41948
  function resolveBaseUrl(catalogName) {
40900
41949
  const def = getProviderByName(catalogName);
@@ -40955,6 +42004,22 @@ async function discoverProviderModels(providerName) {
40955
42004
  const descriptor = def?.modelDiscovery;
40956
42005
  if (!def || !descriptor)
40957
42006
  return [];
42007
+ if (descriptor.format === "devin-connect") {
42008
+ const { getServedDevinModels: getServedDevinModels2 } = await Promise.resolve().then(() => (init_devin_models(), exports_devin_models));
42009
+ const served = await getServedDevinModels2();
42010
+ if (served.length === 0) {
42011
+ log(`[model-discovery:${providerName}] no models for this subscription`);
42012
+ return [];
42013
+ }
42014
+ const models2 = served.map((model) => ({
42015
+ id: model.uid,
42016
+ displayName: model.displayName,
42017
+ contextWindow: model.contextWindow
42018
+ }));
42019
+ log(`[model-discovery:${providerName}] discovered ${models2.length} models`);
42020
+ _cache.set(providerName, { models: models2, expiresAt: Date.now() + CACHE_TTL_MS });
42021
+ return models2;
42022
+ }
40958
42023
  const baseUrl = resolveBaseUrl(providerName);
40959
42024
  if (!baseUrl)
40960
42025
  return [];
@@ -41129,24 +42194,24 @@ async function discoverViaOpenAIModels(endpoint, headers, cacheKey) {
41129
42194
  function classifyFetchError(e, endpoint) {
41130
42195
  const name = e?.name ?? "";
41131
42196
  const code = e?.cause?.code ?? "";
41132
- const msg = e instanceof Error ? e.message : String(e);
42197
+ const msg2 = e instanceof Error ? e.message : String(e);
41133
42198
  const url2 = tryParseUrl(endpoint);
41134
42199
  const host = url2?.host ?? endpoint;
41135
42200
  const isLocal = !!url2 && /^(localhost|127\.0\.0\.1|0\.0\.0\.0|::1)$/i.test(url2.hostname);
41136
- if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg)) {
42201
+ if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg2)) {
41137
42202
  return `${host} unresponsive (>${FETCH_TIMEOUT_MS2 / 1000}s) \u2014 check if the server is overloaded`;
41138
42203
  }
41139
42204
  if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
41140
42205
  return `cannot resolve host ${url2?.hostname ?? endpoint} \u2014 check the URL`;
41141
42206
  }
41142
- const isConnRefused = code === "ECONNREFUSED" || code === "ECONNRESET" || /unable to connect|connection refused|fetch failed/i.test(msg);
42207
+ const isConnRefused = code === "ECONNREFUSED" || code === "ECONNRESET" || /unable to connect|connection refused|fetch failed/i.test(msg2);
41143
42208
  if (isConnRefused) {
41144
42209
  if (isLocal) {
41145
42210
  return `${host} not reachable \u2014 is the server running? Press u to change URL.`;
41146
42211
  }
41147
42212
  return `${host} not reachable \u2014 check the URL or network. Press u to change.`;
41148
42213
  }
41149
- return `${host}: ${msg}`;
42214
+ return `${host}: ${msg2}`;
41150
42215
  }
41151
42216
  function tryParseUrl(s) {
41152
42217
  try {
@@ -42173,6 +43238,10 @@ function buildCredentialHint(modelName, providers) {
42173
43238
  lines.push(` Run: claudish ${hint.loginFlag} (authenticate via OAuth)`);
42174
43239
  hasOption = true;
42175
43240
  }
43241
+ if (hint.note) {
43242
+ lines.push(` ${hint.note}`);
43243
+ hasOption = true;
43244
+ }
42176
43245
  if (hint.apiKeyEnvVar) {
42177
43246
  lines.push(` Set: export ${hint.apiKeyEnvVar}=your-key (for ${provider})`);
42178
43247
  hasOption = true;
@@ -42195,6 +43264,10 @@ var init_routing_hints = __esm(() => {
42195
43264
  google: { loginFlag: "login gemini", apiKeyEnvVar: "GEMINI_API_KEY" },
42196
43265
  "gemini-codeassist": { loginFlag: "login gemini", apiKeyEnvVar: "GEMINI_API_KEY" },
42197
43266
  antigravity: { loginFlag: "login antigravity" },
43267
+ devin: {
43268
+ note: "Sign in with the Devin CLI (`devin login`) \u2014 claudish reads ~/.local/share/devin/credentials.toml",
43269
+ apiKeyEnvVar: "WINDSURF_API_KEY"
43270
+ },
42198
43271
  openai: { apiKeyEnvVar: "OPENAI_API_KEY" },
42199
43272
  "openai-codex": { loginFlag: "login codex", apiKeyEnvVar: "OPENAI_CODEX_API_KEY" },
42200
43273
  minimax: { apiKeyEnvVar: "MINIMAX_API_KEY" },
@@ -42249,13 +43322,15 @@ var init_default_routing_rules = __esm(() => {
42249
43322
  "o3-*": ["openai-codex", "openai", "openrouter"],
42250
43323
  "gemini-*": ["antigravity", "google", "openrouter"],
42251
43324
  "grok-*": ["x-ai", "openrouter"],
42252
- "kimi-*": ["kimi-coding", "kimi", "openrouter"],
42253
- "k3*": ["kimi-coding", "kimi", "openrouter"],
42254
- "minimax-*": ["minimax-coding", "minimax", "openrouter"],
42255
- "glm-*": ["glm-coding", "glm", "openrouter"],
42256
- "qwen3.*": ["qwen-cloud", "openrouter"],
43325
+ "kimi-*": ["kimi-coding", "opencode-zen-go", "kimi", "openrouter"],
43326
+ "k3*": ["kimi-coding", "opencode-zen-go", "kimi", "openrouter"],
43327
+ "minimax-*": ["minimax-coding", "opencode-zen-go", "minimax", "openrouter"],
43328
+ "glm-*": ["glm-coding", "opencode-zen-go", "glm", "openrouter"],
43329
+ "qwen3.*": ["qwen-cloud", "opencode-zen-go", "openrouter"],
42257
43330
  "z-ai-*": ["z-ai", "openrouter"],
42258
- "deepseek-*": ["deepseek", "openrouter"],
43331
+ "deepseek-*": ["opencode-zen-go", "deepseek", "openrouter"],
43332
+ "mimo-*": ["opencode-zen-go", "openrouter"],
43333
+ "hy3*": ["opencode-zen-go", "openrouter"],
42259
43334
  fugu: ["sakana-subscription", "sakana"],
42260
43335
  "fugu-*": ["sakana-subscription", "sakana"],
42261
43336
  "*-zen": ["opencode-zen"],
@@ -43095,10 +44170,10 @@ var init_signal_watcher = __esm(() => {
43095
44170
 
43096
44171
  // src/channel/session-manager.ts
43097
44172
  import { spawn } from "child_process";
43098
- import { randomUUID as randomUUID4 } from "crypto";
44173
+ import { randomUUID as randomUUID5 } from "crypto";
43099
44174
  import { createWriteStream, mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
43100
- import { homedir as homedir24 } from "os";
43101
- import { join as join24 } from "path";
44175
+ import { homedir as homedir25 } from "os";
44176
+ import { join as join25 } from "path";
43102
44177
 
43103
44178
  class SessionManager {
43104
44179
  sessions = new Map;
@@ -43110,20 +44185,20 @@ class SessionManager {
43110
44185
  constructor(options) {
43111
44186
  this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
43112
44187
  this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
43113
- this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join24(homedir24(), ".claudish", "sessions");
44188
+ this.sessionsDir = options?.sessionsDir ?? process.env.CLAUDISH_SESSIONS_DIR ?? join25(homedir25(), ".claudish", "sessions");
43114
44189
  this.onStateChange = options?.onStateChange;
43115
44190
  }
43116
44191
  createSession(opts) {
43117
44192
  if (this.activeSessions >= this.maxSessions) {
43118
44193
  throw new Error(`Max sessions (${this.maxSessions}) reached`);
43119
44194
  }
43120
- const sessionId2 = randomUUID4().slice(0, 8);
44195
+ const sessionId2 = randomUUID5().slice(0, 8);
43121
44196
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
43122
44197
  const startedAt = new Date().toISOString();
43123
- const sessionDir = join24(this.sessionsDir, sessionId2);
44198
+ const sessionDir = join25(this.sessionsDir, sessionId2);
43124
44199
  mkdirSync11(sessionDir, { recursive: true });
43125
44200
  if (opts.prompt) {
43126
- writeFileSync10(join24(sessionDir, "prompt.md"), opts.prompt, "utf-8");
44201
+ writeFileSync10(join25(sessionDir, "prompt.md"), opts.prompt, "utf-8");
43127
44202
  }
43128
44203
  const args = [
43129
44204
  "--model",
@@ -43157,7 +44232,7 @@ class SessionManager {
43157
44232
  });
43158
44233
  }
43159
44234
  });
43160
- const outputLogStream = createWriteStream(join24(sessionDir, "output.log"));
44235
+ const outputLogStream = createWriteStream(join25(sessionDir, "output.log"));
43161
44236
  const entry = {
43162
44237
  info: {
43163
44238
  sessionId: sessionId2,
@@ -43204,9 +44279,9 @@ class SessionManager {
43204
44279
  watcher.processExited(code);
43205
44280
  outputLogStream.end();
43206
44281
  if (entry.stderr) {
43207
- writeFileSync10(join24(sessionDir, "stderr.log"), entry.stderr, "utf-8");
44282
+ writeFileSync10(join25(sessionDir, "stderr.log"), entry.stderr, "utf-8");
43208
44283
  }
43209
- writeFileSync10(join24(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
44284
+ writeFileSync10(join25(sessionDir, "meta.json"), JSON.stringify(entry.info, null, 2), "utf-8");
43210
44285
  this.cleanupSigint();
43211
44286
  });
43212
44287
  proc.on("error", (err) => {
@@ -45282,8 +46357,8 @@ var init_openrouter_api_format = __esm(() => {
45282
46357
  convertMessages(claudeRequest, filterIdentityFn) {
45283
46358
  const messages = super.convertMessages(claudeRequest, filterIdentityFn);
45284
46359
  if (this.modelId.includes("grok") || this.modelId.includes("x-ai")) {
45285
- const msg = "IMPORTANT: When calling tools, you MUST use the OpenAI tool_calls format with JSON. NEVER use XML format like <xai:function_call>.";
45286
- this.appendToSystemPrompt(messages, msg);
46360
+ const msg2 = "IMPORTANT: When calling tools, you MUST use the OpenAI tool_calls format with JSON. NEVER use XML format like <xai:function_call>.";
46361
+ this.appendToSystemPrompt(messages, msg2);
45287
46362
  }
45288
46363
  if (this.modelId.includes("gemini") || this.modelId.includes("google/")) {
45289
46364
  const geminiMsg = `CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
@@ -45404,7 +46479,11 @@ class FallbackHandler {
45404
46479
  }
45405
46480
  errors3.push({ provider: name, status: response.status, message: errorBody });
45406
46481
  if (!isLast) {
45407
- logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
46482
+ if (hasQuotaExhaustionWording(errorBody)) {
46483
+ logStderr(`[Fallback] ${name} subscription allowance is spent \u2014 falling through to the next provider, which is billed PER TOKEN. Use a provider prefix (e.g. \`zgo@model\`) to fail instead of switching.`);
46484
+ } else {
46485
+ logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
46486
+ }
45408
46487
  }
45409
46488
  } catch (err) {
45410
46489
  errors3.push({ provider: name, status: 0, message: err.message });
@@ -45441,8 +46520,8 @@ ${summary}`);
45441
46520
  }
45442
46521
  }
45443
46522
  function isRetryableError(status, errorBody) {
45444
- if (isQuotaExhaustionError(status, errorBody))
45445
- return false;
46523
+ if (hasQuotaExhaustionWording(errorBody))
46524
+ return true;
45446
46525
  if (status === 401 || status === 403)
45447
46526
  return true;
45448
46527
  if (status === 402)
@@ -45599,12 +46678,12 @@ function rewriteAdvisorToolResults(payload, getAdviceFor) {
45599
46678
  if (!Array.isArray(messages))
45600
46679
  return [];
45601
46680
  const rewritten = [];
45602
- for (const msg of messages) {
45603
- if (!msg || typeof msg !== "object")
46681
+ for (const msg2 of messages) {
46682
+ if (!msg2 || typeof msg2 !== "object")
45604
46683
  continue;
45605
- if (msg.role !== "user")
46684
+ if (msg2.role !== "user")
45606
46685
  continue;
45607
- const content = msg.content;
46686
+ const content = msg2.content;
45608
46687
  if (!Array.isArray(content))
45609
46688
  continue;
45610
46689
  for (const block of content) {
@@ -45634,12 +46713,12 @@ function findPendingAdvisorToolResults(payload) {
45634
46713
  if (!Array.isArray(messages))
45635
46714
  return [];
45636
46715
  const found = [];
45637
- for (const msg of messages) {
45638
- if (!msg || typeof msg !== "object")
46716
+ for (const msg2 of messages) {
46717
+ if (!msg2 || typeof msg2 !== "object")
45639
46718
  continue;
45640
- if (msg.role !== "user")
46719
+ if (msg2.role !== "user")
45641
46720
  continue;
45642
- const content = msg.content;
46721
+ const content = msg2.content;
45643
46722
  if (!Array.isArray(content))
45644
46723
  continue;
45645
46724
  for (const block of content) {
@@ -46137,13 +47216,277 @@ var init_api_key_map = __esm(() => {
46137
47216
  "qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
46138
47217
  ollamacloud: { envVar: "OLLAMA_API_KEY" },
46139
47218
  "opencode-zen": { envVar: "OPENCODE_API_KEY" },
46140
- "opencode-zen-go": { envVar: "OPENCODE_API_KEY" },
47219
+ "opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
46141
47220
  "gemini-codeassist": { envVar: "GEMINI_API_KEY" },
46142
47221
  vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
46143
47222
  poe: { envVar: "POE_API_KEY" }
46144
47223
  };
46145
47224
  });
46146
47225
 
47226
+ // src/providers/devin/tool-descriptions.ts
47227
+ function currentMonthAndYear(now = new Date) {
47228
+ return `${MONTHS[now.getMonth()]} ${now.getFullYear()}`;
47229
+ }
47230
+ function buildWebSearchDescription(monthAndYear) {
47231
+ return `Runs a web search and lets you fold the results into your answer.
47232
+
47233
+ - Reaches live sources, so it covers current events and material recent enough to post-date your
47234
+ training data. This is the tool for any question that runs past your knowledge cutoff.
47235
+ - Results arrive as search-result blocks; links inside them are already written as markdown
47236
+ hyperlinks.
47237
+ - The entire search happens within a single API call \u2014 there is nothing extra to orchestrate.
47238
+
47239
+ NON-NEGOTIABLE OUTPUT REQUIREMENT \u2014 this is MANDATORY, and you must never skip it:
47240
+ - Once you have answered the user's question, the very end of your response MUST carry a section
47241
+ headed \`Sources:\`.
47242
+ - Beneath that heading, list every URL from the search results that is relevant to the answer,
47243
+ each written as a markdown hyperlink in the form [Title](URL).
47244
+ - Leaving the sources section out is not an option, however short or obvious the answer looks.
47245
+ - Shape of the finished response:
47246
+
47247
+ [your answer goes here]
47248
+
47249
+ Sources:
47250
+ - [First page title](https://first.example/page)
47251
+ - [Second page title](https://second.example/page)
47252
+
47253
+ Other things worth knowing:
47254
+ - Results can be confined by domain: \`allowed_domains\` restricts the search to specific sites,
47255
+ \`blocked_domains\` keeps named sites out.
47256
+ - Web search is served only within the United States.
47257
+
47258
+ Dates in queries \u2014 get the year right:
47259
+ - The present month is ${monthAndYear}. Any query about recent material, current documentation or
47260
+ ongoing events MUST be qualified with that year.
47261
+ - For example, asked for "latest React docs", search for React documentation carrying the current
47262
+ year, not the one before it.`;
47263
+ }
47264
+ function buildDevinToolDescriptions(now = new Date) {
47265
+ return new Map([
47266
+ ["Read", READ_DESCRIPTION],
47267
+ ["TaskOutput", TASK_OUTPUT_DESCRIPTION],
47268
+ ["WebSearch", buildWebSearchDescription(currentMonthAndYear(now))]
47269
+ ]);
47270
+ }
47271
+ function toolName(tool) {
47272
+ if (!tool || typeof tool !== "object")
47273
+ return;
47274
+ const record4 = tool;
47275
+ const nested = record4.function?.name;
47276
+ if (typeof nested === "string")
47277
+ return nested;
47278
+ return typeof record4.name === "string" ? record4.name : undefined;
47279
+ }
47280
+ function applyDevinToolDescriptions(tools, descriptions = DEVIN_TOOL_DESCRIPTIONS) {
47281
+ return tools.map((tool) => {
47282
+ const name = toolName(tool);
47283
+ const replacement = name === undefined ? undefined : descriptions.get(name);
47284
+ if (replacement === undefined)
47285
+ return tool;
47286
+ const record4 = tool;
47287
+ if (record4.function && typeof record4.function === "object") {
47288
+ return {
47289
+ ...record4,
47290
+ function: { ...record4.function, description: replacement }
47291
+ };
47292
+ }
47293
+ return { ...record4, description: replacement };
47294
+ });
47295
+ }
47296
+ var MONTHS, READ_DESCRIPTION = `Retrieves the contents of a single file from the machine's local disk.
47297
+
47298
+ Nothing on the host is out of bounds \u2014 assume you can open whatever you need. When the user hands
47299
+ you a path, take it at face value and try it; aiming at a file that turns out not to exist is
47300
+ harmless, the call simply comes back as an error.
47301
+
47302
+ Calling conventions:
47303
+ - \`file_path\` has to be a fully-qualified absolute path. A relative path will not be accepted.
47304
+ - Left unbounded, the call hands back at most the first 2000 lines, counted from the top of the file.
47305
+ - If you already know which region of the file matters, ask for that region alone. On large files
47306
+ this is the difference between a cheap call and an expensive one.
47307
+ - Output is formatted the way \`cat -n\` formats it: each line prefixed with its number, and the
47308
+ numbering begins at 1.
47309
+ - Image files work (PNG, JPG and the rest). The picture itself is handed over for you to look at,
47310
+ since the model behind this session takes visual input as well as text.
47311
+ - PDF documents work. Once a document runs past ten pages the \`pages\` argument becomes REQUIRED \u2014
47312
+ give it the span you want, for instance \`pages: "1-5"\`. Leaving \`pages\` off a long PDF makes the
47313
+ call fail outright. One request may cover twenty pages at most.
47314
+ - Jupyter notebooks (\`.ipynb\`) come back fully expanded: every cell together with the output that
47315
+ cell produced, so source, prose and rendered figures all arrive in one piece.
47316
+ - Files only, never directories. To find out what a folder holds, reach for the shell tool
47317
+ registered for this session.
47318
+ - Screenshots are a routine case. Whenever a path to a screenshot is supplied, view it through this
47319
+ tool rather than by any other route; paths inside temporary directories are fine.
47320
+ - Opening a file that exists but holds nothing gives you a system-reminder notice standing in for
47321
+ the file body.
47322
+ - Do not re-open a file just to confirm an edit you have already made. Had that Edit or Write
47323
+ failed it would have raised an error at the time, and the harness keeps track of each file's
47324
+ current state on your behalf.`, TASK_OUTPUT_DESCRIPTION = `DEPRECATED \u2014 in almost every case reach for Read instead.
47325
+
47326
+ The reason it is deprecated: a task launched in the background already reports the path of its
47327
+ output file as part of the tool result, and a <task-notification> quoting that same path arrives
47328
+ once the task finishes. The path is in front of you either way, so routing back through this tool
47329
+ buys nothing.
47330
+
47331
+ Which route to take, by task kind:
47332
+ - bash tasks \u2014 open the reported output path with Read. Both stdout and stderr are captured there.
47333
+ - local_agent tasks \u2014 take the answer straight from what the Agent tool returned. NEVER open the
47334
+ \`.output\` file with Read. That entry is a symlink pointing at the subagent's ENTIRE conversation
47335
+ transcript in JSONL form, and pulling it in WILL overflow your context window.
47336
+ - remote_agent tasks \u2014 open the reported output path with Read, exactly as for bash; it holds the
47337
+ remote session's streamed output.
47338
+
47339
+ If you call it anyway, this is what it does:
47340
+ - Fetches the output of a task that is either still running or already finished \u2014 a backgrounded
47341
+ shell, an agent, or a remote session.
47342
+ - Identifies which task through the \`task_id\` parameter.
47343
+ - Replies with the task's output alongside its status.
47344
+ - \`block=true\` is the default and makes the call wait until the task has completed.
47345
+ - \`block=false\` returns straight away with whatever the status is at that moment.
47346
+ - The \`/tasks\` command lists the ids you can pass.
47347
+ - Every task flavour is supported: backgrounded shells, asynchronous agents, and remote sessions.`, DEVIN_TOOL_DESCRIPTIONS;
47348
+ var init_tool_descriptions = __esm(() => {
47349
+ MONTHS = [
47350
+ "January",
47351
+ "February",
47352
+ "March",
47353
+ "April",
47354
+ "May",
47355
+ "June",
47356
+ "July",
47357
+ "August",
47358
+ "September",
47359
+ "October",
47360
+ "November",
47361
+ "December"
47362
+ ];
47363
+ DEVIN_TOOL_DESCRIPTIONS = buildDevinToolDescriptions();
47364
+ });
47365
+
47366
+ // src/adapters/devin-api-format.ts
47367
+ function contentToText(content) {
47368
+ if (typeof content === "string")
47369
+ return content;
47370
+ if (!Array.isArray(content))
47371
+ return "";
47372
+ const parts = [];
47373
+ for (const part of content) {
47374
+ if (typeof part === "string") {
47375
+ parts.push(part);
47376
+ continue;
47377
+ }
47378
+ if (part && typeof part === "object" && "text" in part) {
47379
+ const { text } = part;
47380
+ if (typeof text === "string")
47381
+ parts.push(text);
47382
+ }
47383
+ }
47384
+ return parts.join(`
47385
+ `);
47386
+ }
47387
+ var DEVIN_RELOCATION_NOTE, DEVIN_MINIMAL_SYSTEM = "You are a coding agent.", DevinAPIFormat;
47388
+ var init_devin_api_format = __esm(() => {
47389
+ init_tool_descriptions();
47390
+ init_base_api_format();
47391
+ DEVIN_RELOCATION_NOTE = "You are a coding agent. Your complete operating instructions for this session are supplied " + "in the first user message, inside <system_instructions> tags. Treat everything inside those " + "tags as your system prompt and follow it exactly.";
47392
+ DevinAPIFormat = class DevinAPIFormat extends BaseAPIFormat {
47393
+ processTextContent(textContent, _accumulatedText) {
47394
+ return {
47395
+ cleanedText: textContent,
47396
+ extractedToolCalls: [],
47397
+ wasTransformed: false
47398
+ };
47399
+ }
47400
+ shouldHandle(_modelId) {
47401
+ return false;
47402
+ }
47403
+ getName() {
47404
+ return "DevinAPIFormat";
47405
+ }
47406
+ getStreamFormat() {
47407
+ return "connect-proto";
47408
+ }
47409
+ getContextWindow() {
47410
+ return 0;
47411
+ }
47412
+ supportsVision() {
47413
+ return false;
47414
+ }
47415
+ applyNativeReasoning(request, originalRequest) {
47416
+ const effort = this.resolveEffortLevel(originalRequest);
47417
+ if (effort)
47418
+ request.effort = effort;
47419
+ return request;
47420
+ }
47421
+ buildPayload(_claudeRequest, messages, tools) {
47422
+ const systemParts = [];
47423
+ const devinMessages = [];
47424
+ for (const message of messages) {
47425
+ const role = message?.role;
47426
+ if (role === "system") {
47427
+ const text = contentToText(message.content);
47428
+ if (text)
47429
+ systemParts.push(text);
47430
+ continue;
47431
+ }
47432
+ if (role === "tool") {
47433
+ devinMessages.push({
47434
+ role: "tool_result",
47435
+ text: contentToText(message.content),
47436
+ toolCallId: message.tool_call_id
47437
+ });
47438
+ continue;
47439
+ }
47440
+ if (role === "assistant") {
47441
+ const text = contentToText(message.content);
47442
+ if (text)
47443
+ devinMessages.push({ role: "assistant", text });
47444
+ for (const call of message.tool_calls ?? []) {
47445
+ devinMessages.push({
47446
+ role: "assistant",
47447
+ toolCall: {
47448
+ id: call?.id ?? "",
47449
+ name: call?.function?.name ?? "",
47450
+ argumentsJson: call?.function?.arguments || "{}"
47451
+ }
47452
+ });
47453
+ }
47454
+ continue;
47455
+ }
47456
+ devinMessages.push({ role: "user", text: contentToText(message.content) });
47457
+ }
47458
+ const devinTools = applyDevinToolDescriptions(tools).map((tool) => ({
47459
+ name: tool?.function?.name ?? tool?.name ?? "",
47460
+ description: tool?.function?.description ?? tool?.description ?? "",
47461
+ parametersJson: JSON.stringify(tool?.function?.parameters ?? tool?.parameters ?? { type: "object", properties: {} })
47462
+ }));
47463
+ let system;
47464
+ if (systemParts.length > 0) {
47465
+ devinMessages.unshift({
47466
+ role: "user",
47467
+ text: `<system_instructions>
47468
+ ${systemParts.join(`
47469
+
47470
+ `)}
47471
+ </system_instructions>`
47472
+ });
47473
+ system = DEVIN_RELOCATION_NOTE;
47474
+ } else if (devinTools.length > 0) {
47475
+ system = DEVIN_MINIMAL_SYSTEM;
47476
+ }
47477
+ const payload = {
47478
+ modelUid: this.modelId,
47479
+ messages: devinMessages
47480
+ };
47481
+ if (system)
47482
+ payload.system = system;
47483
+ if (devinTools.length > 0)
47484
+ payload.tools = devinTools;
47485
+ return payload;
47486
+ }
47487
+ };
47488
+ });
47489
+
46147
47490
  // src/adapters/ollama-api-format.ts
46148
47491
  var OllamaAPIFormat;
46149
47492
  var init_ollama_api_format = __esm(() => {
@@ -46171,11 +47514,11 @@ var init_ollama_api_format = __esm(() => {
46171
47514
  messages.push({ role: "system", content });
46172
47515
  }
46173
47516
  if (claudeRequest.messages) {
46174
- for (const msg of claudeRequest.messages) {
46175
- if (msg.role === "user") {
46176
- messages.push(this.processUserMessage(msg));
46177
- } else if (msg.role === "assistant") {
46178
- messages.push(this.processAssistantMessage(msg));
47517
+ for (const msg2 of claudeRequest.messages) {
47518
+ if (msg2.role === "user") {
47519
+ messages.push(this.processUserMessage(msg2));
47520
+ } else if (msg2.role === "assistant") {
47521
+ messages.push(this.processAssistantMessage(msg2));
46179
47522
  }
46180
47523
  }
46181
47524
  }
@@ -46200,10 +47543,10 @@ var init_ollama_api_format = __esm(() => {
46200
47543
  supportsVision() {
46201
47544
  return false;
46202
47545
  }
46203
- processUserMessage(msg) {
46204
- if (Array.isArray(msg.content)) {
47546
+ processUserMessage(msg2) {
47547
+ if (Array.isArray(msg2.content)) {
46205
47548
  const textParts = [];
46206
- for (const block of msg.content) {
47549
+ for (const block of msg2.content) {
46207
47550
  if (block.type === "text") {
46208
47551
  textParts.push(block.text);
46209
47552
  } else if (block.type === "tool_result") {
@@ -46215,12 +47558,12 @@ var init_ollama_api_format = __esm(() => {
46215
47558
 
46216
47559
  `) };
46217
47560
  }
46218
- return { role: "user", content: msg.content };
47561
+ return { role: "user", content: msg2.content };
46219
47562
  }
46220
- processAssistantMessage(msg) {
46221
- if (Array.isArray(msg.content)) {
47563
+ processAssistantMessage(msg2) {
47564
+ if (Array.isArray(msg2.content)) {
46222
47565
  const strings = [];
46223
- for (const block of msg.content) {
47566
+ for (const block of msg2.content) {
46224
47567
  if (block.type === "text") {
46225
47568
  strings.push(block.text);
46226
47569
  } else if (block.type === "tool_use") {
@@ -46230,17 +47573,17 @@ var init_ollama_api_format = __esm(() => {
46230
47573
  return { role: "assistant", content: strings.join(`
46231
47574
  `) };
46232
47575
  }
46233
- return { role: "assistant", content: msg.content };
47576
+ return { role: "assistant", content: msg2.content };
46234
47577
  }
46235
47578
  };
46236
47579
  });
46237
47580
 
46238
47581
  // src/providers/api-key-provenance.ts
46239
- import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
46240
- import { homedir as homedir25 } from "os";
46241
- import { join as join25, resolve as resolve2 } from "path";
47582
+ import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
47583
+ import { homedir as homedir26 } from "os";
47584
+ import { join as join26, resolve as resolve2 } from "path";
46242
47585
  function activeConfigPath() {
46243
- return activeGlobalConfigFile(join25(homedir25(), ".claudish", "config.json"));
47586
+ return activeGlobalConfigFile(join26(homedir26(), ".claudish", "config.json"));
46244
47587
  }
46245
47588
  function configLayerLabel() {
46246
47589
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -46319,7 +47662,7 @@ function readDotenvKey(envVars) {
46319
47662
  const dotenvPath = resolve2(".env");
46320
47663
  if (!existsSync17(dotenvPath))
46321
47664
  return null;
46322
- const parsed = import_dotenv.parse(readFileSync15(dotenvPath, "utf-8"));
47665
+ const parsed = import_dotenv.parse(readFileSync16(dotenvPath, "utf-8"));
46323
47666
  for (const v of envVars) {
46324
47667
  if (parsed[v])
46325
47668
  return parsed[v];
@@ -46334,7 +47677,7 @@ function readConfigKey(envVar) {
46334
47677
  const configPath = activeConfigPath();
46335
47678
  if (!existsSync17(configPath))
46336
47679
  return null;
46337
- const cfg = JSON.parse(readFileSync15(configPath, "utf-8"));
47680
+ const cfg = JSON.parse(readFileSync16(configPath, "utf-8"));
46338
47681
  return cfg.apiKeys?.[envVar] || null;
46339
47682
  } catch {
46340
47683
  return null;
@@ -46346,6 +47689,161 @@ var init_api_key_provenance = __esm(() => {
46346
47689
  import_dotenv = __toESM(require_main(), 1);
46347
47690
  });
46348
47691
 
47692
+ // src/providers/devin/model-id-resolver.ts
47693
+ function parseDevinUidTier(uid) {
47694
+ let base = uid.trim();
47695
+ let fast = false;
47696
+ if (base.toLowerCase().endsWith(FAST_SUFFIX)) {
47697
+ fast = true;
47698
+ base = base.slice(0, -FAST_SUFFIX.length);
47699
+ }
47700
+ const match2 = base.match(TIER_SUFFIX_RE);
47701
+ const candidate = match2?.[1]?.toLowerCase();
47702
+ return { tier: isEffortLevel(candidate) ? candidate : null, fast };
47703
+ }
47704
+ function effortIndex(level) {
47705
+ return EFFORT_LEVELS.indexOf(level);
47706
+ }
47707
+ function resolveDevinModelUid(requested, effort, served) {
47708
+ const req = requested.trim();
47709
+ if (!req || served.length === 0)
47710
+ return req || requested;
47711
+ const lower = req.toLowerCase();
47712
+ const exact = served.find((model) => model.uid.toLowerCase() === lower);
47713
+ if (exact)
47714
+ return exact.uid;
47715
+ const prefix = `${lower}-`;
47716
+ const candidates = served.filter((model) => model.family.toLowerCase() === lower || model.uid.toLowerCase().startsWith(prefix));
47717
+ if (candidates.length === 0)
47718
+ return req;
47719
+ const nonFast = candidates.filter((model) => !parseDevinUidTier(model.uid).fast);
47720
+ const pool = nonFast.length > 0 ? nonFast : candidates;
47721
+ if (pool.length === 1)
47722
+ return pool[0].uid;
47723
+ const tiered = pool.map((model) => ({ model, tier: parseDevinUidTier(model.uid).tier })).filter((entry) => entry.tier !== null);
47724
+ if (tiered.length === 0)
47725
+ return pool[0].uid;
47726
+ const target = effort ? effortIndex(effort) : EFFORT_LEVELS.length - 1;
47727
+ let best = tiered[0];
47728
+ let bestDistance = Number.POSITIVE_INFINITY;
47729
+ for (const entry of tiered) {
47730
+ const distance = Math.abs(effortIndex(entry.tier) - target);
47731
+ if (distance < bestDistance || distance === bestDistance && effortIndex(entry.tier) > effortIndex(best.tier)) {
47732
+ best = entry;
47733
+ bestDistance = distance;
47734
+ }
47735
+ }
47736
+ return best.model.uid;
47737
+ }
47738
+ var FAST_SUFFIX = "-fast", TIER_SUFFIX_RE;
47739
+ var init_model_id_resolver = __esm(() => {
47740
+ init_base_api_format();
47741
+ TIER_SUFFIX_RE = new RegExp(`-(${[...EFFORT_LEVELS].sort((a, b) => b.length - a.length).join("|")})$`, "i");
47742
+ });
47743
+
47744
+ // src/providers/transport/devin.ts
47745
+ class DevinProviderTransport {
47746
+ name = "devin";
47747
+ displayName = "Devin";
47748
+ streamFormat = "connect-proto";
47749
+ modelName;
47750
+ cachedAuth = null;
47751
+ served = [];
47752
+ resolvedUid;
47753
+ constructor(modelName) {
47754
+ this.modelName = modelName;
47755
+ this.resolvedUid = modelName;
47756
+ }
47757
+ getEndpoint() {
47758
+ return `${readDevinServerUrl()}${CHAT_PATH}`;
47759
+ }
47760
+ async getHeaders() {
47761
+ if (this.cachedAuth)
47762
+ return { ...this.cachedAuth.headers };
47763
+ const apiKey = readDevinApiKey();
47764
+ return apiKey ? devinAuthHeaders(apiKey) : {};
47765
+ }
47766
+ async refreshAuth() {
47767
+ this.cachedAuth = await credentials.getRequestAuth("devin", { model: this.modelName });
47768
+ this.served = await getServedDevinModels();
47769
+ log(`[Devin] auth refreshed, model: ${this.modelName}, served roster: ${this.served.length} models`);
47770
+ }
47771
+ serializeBody(payload) {
47772
+ const apiKey = readDevinApiKey();
47773
+ if (!apiKey) {
47774
+ const err = new Error("No Devin credential available when encoding the request.");
47775
+ err.terminal = true;
47776
+ throw err;
47777
+ }
47778
+ const request = payload;
47779
+ this.resolvedUid = resolveDevinModelUid(request.modelUid || this.modelName, request.effort, this.served);
47780
+ const resolved = { ...request, modelUid: this.resolvedUid };
47781
+ if (this.resolvedUid !== this.modelName) {
47782
+ log(`[Devin] model resolved: ${this.modelName} -> ${this.resolvedUid}`);
47783
+ }
47784
+ log(`[Devin] request ${describeDevinRequestForLog(resolved)}`);
47785
+ return {
47786
+ body: encodeDevinRequest(resolved, { apiKey }),
47787
+ contentType: CHAT_CONTENT_TYPE
47788
+ };
47789
+ }
47790
+ getContextWindow() {
47791
+ if (this.served.length === 0)
47792
+ return 0;
47793
+ const uid = resolveDevinModelUid(this.modelName, undefined, this.served);
47794
+ return this.served.find((model) => model.uid === uid)?.contextWindow ?? 0;
47795
+ }
47796
+ getActiveModelName() {
47797
+ return this.resolvedUid !== this.modelName ? this.resolvedUid : undefined;
47798
+ }
47799
+ async discoverProbeModel(exclude) {
47800
+ if (!readDevinApiKey()) {
47801
+ return {
47802
+ model: null,
47803
+ reason: "no Devin credential \u2014 sign in with the Devin CLI (`devin login`), or set WINDSURF_API_KEY"
47804
+ };
47805
+ }
47806
+ const served = await getServedDevinModels();
47807
+ if (served.length === 0) {
47808
+ return { model: null, reason: "Devin reported no models for this subscription" };
47809
+ }
47810
+ const ranked = [...served].sort((a, b) => {
47811
+ const diff = b.contextWindow - a.contextWindow;
47812
+ return diff !== 0 ? diff : a.uid.localeCompare(b.uid);
47813
+ });
47814
+ const candidate = ranked.find((model) => !exclude?.has(model.uid));
47815
+ if (!candidate) {
47816
+ return { model: null, reason: "every Devin model was already tried in this probe round" };
47817
+ }
47818
+ return { model: candidate.uid };
47819
+ }
47820
+ rewriteInStreamError(_code, message) {
47821
+ if (this.served.length === 0)
47822
+ return message;
47823
+ if (this.served.some((model) => model.uid === this.resolvedUid))
47824
+ return message;
47825
+ const families = [...new Set(this.served.map((model) => model.family).filter(Boolean))].sort();
47826
+ const stem = this.resolvedUid.split("-")[0]?.toLowerCase() ?? "";
47827
+ const related = families.filter((f) => f.toLowerCase().startsWith(stem));
47828
+ const ordered = [...related, ...families.filter((f) => !related.includes(f))];
47829
+ const SHOWN = 12;
47830
+ const shown = ordered.slice(0, SHOWN);
47831
+ const more = ordered.length - shown.length;
47832
+ const familyClause = shown.length > 0 ? ` Available families: ${shown.join(", ")}${more > 0 ? `, +${more} more` : ""}.` : "";
47833
+ return `\`${this.resolvedUid}\` is not served by your Devin subscription.${familyClause} ` + "Run `claudish models dv@` to list the uids this subscription can call. " + `(Upstream said: ${message})`;
47834
+ }
47835
+ }
47836
+ var CHAT_PATH = "/exa.api_server_pb.ApiServerService/GetChatMessage", CHAT_CONTENT_TYPE = "application/connect+proto";
47837
+ var init_devin = __esm(() => {
47838
+ init_authority();
47839
+ init_devin_credential();
47840
+ init_logger();
47841
+ init_devin_credentials();
47842
+ init_devin_models();
47843
+ init_devin_request();
47844
+ init_model_id_resolver();
47845
+ });
47846
+
46349
47847
  // src/providers/transport/gemini-apikey.ts
46350
47848
  class GeminiProviderTransport {
46351
47849
  name = "gemini";
@@ -46378,7 +47876,7 @@ var init_gemini_apikey = __esm(() => {
46378
47876
  });
46379
47877
 
46380
47878
  // src/providers/transport/gemini-codeassist.ts
46381
- import { randomUUID as randomUUID5 } from "crypto";
47879
+ import { randomUUID as randomUUID6 } from "crypto";
46382
47880
  function createActivityRequestId4() {
46383
47881
  return Math.random().toString(36).substring(7);
46384
47882
  }
@@ -46487,21 +47985,21 @@ class GeminiCodeAssistProviderTransport {
46487
47985
  log(`[GeminiCodeAssist] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}, served: ${this.servedModels.join(",") || "(none)"}`);
46488
47986
  }
46489
47987
  transformPayload(payload) {
46490
- const envelope = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
46491
- this.lastEnvelope = envelope;
46492
- return envelope;
47988
+ const envelope2 = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
47989
+ this.lastEnvelope = envelope2;
47990
+ return envelope2;
46493
47991
  }
46494
47992
  buildEnvelope(innerPayload, model) {
46495
- const envelope = {
47993
+ const envelope2 = {
46496
47994
  model,
46497
47995
  project: this.projectId,
46498
- user_prompt_id: randomUUID5(),
47996
+ user_prompt_id: randomUUID6(),
46499
47997
  request: innerPayload
46500
47998
  };
46501
47999
  if (this.tierId && this.tierId !== "free-tier") {
46502
- envelope.enabled_credit_types = ["GOOGLE_ONE_AI"];
48000
+ envelope2.enabled_credit_types = ["GOOGLE_ONE_AI"];
46503
48001
  }
46504
- return envelope;
48002
+ return envelope2;
46505
48003
  }
46506
48004
  async enqueueRequest(fetchFn) {
46507
48005
  const queue = GeminiRequestQueue.getInstance();
@@ -46828,11 +48326,12 @@ function createHandlerForProvider(ctx) {
46828
48326
  log(`[Proxy] Handler: provider=${ctx.provider.name}, model=${ctx.modelName}`);
46829
48327
  return profile.createHandler(ctx);
46830
48328
  }
46831
- var geminiProfile, geminiCodeAssistProfile, antigravityProfile, openaiProfile, openaiCodexProfile, anthropicCompatProfile, glmProfile, openCodeZenProfile, ollamaCloudProfile, litellmProfile, vertexProfile, PROVIDER_PROFILES;
48329
+ var geminiProfile, geminiCodeAssistProfile, antigravityProfile, devinProfile, openaiProfile, openaiCodexProfile, anthropicCompatProfile, glmProfile, openCodeZenProfile, ollamaCloudProfile, litellmProfile, vertexProfile, PROVIDER_PROFILES;
46832
48330
  var init_provider_profiles = __esm(() => {
46833
48331
  init_anthropic_api_format();
46834
48332
  init_base_api_format();
46835
48333
  init_codex_api_format();
48334
+ init_devin_api_format();
46836
48335
  init_gemini_api_format();
46837
48336
  init_litellm_api_format();
46838
48337
  init_ollama_api_format();
@@ -46845,6 +48344,7 @@ var init_provider_profiles = __esm(() => {
46845
48344
  init_runtime_providers();
46846
48345
  init_anthropic_compat();
46847
48346
  init_antigravity();
48347
+ init_devin();
46848
48348
  init_gemini_apikey();
46849
48349
  init_gemini_codeassist();
46850
48350
  init_litellm();
@@ -46890,6 +48390,19 @@ var init_provider_profiles = __esm(() => {
46890
48390
  return handler;
46891
48391
  }
46892
48392
  };
48393
+ devinProfile = {
48394
+ createHandler(ctx) {
48395
+ const transport = new DevinProviderTransport(ctx.modelName);
48396
+ const adapter = new DevinAPIFormat(ctx.modelName);
48397
+ const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
48398
+ adapter,
48399
+ forceForeignModel: true,
48400
+ ...ctx.sharedOpts
48401
+ });
48402
+ log(`[Proxy] Created Devin handler (composed): ${ctx.modelName}`);
48403
+ return handler;
48404
+ }
48405
+ };
46893
48406
  openaiProfile = {
46894
48407
  createHandler(ctx) {
46895
48408
  if (requiresResponsesApi(ctx.modelName)) {
@@ -46958,7 +48471,8 @@ var init_provider_profiles = __esm(() => {
46958
48471
  const zenApiKey = ctx.apiKey;
46959
48472
  const isGoProvider = ctx.provider.name === "opencode-zen-go";
46960
48473
  if (ctx.modelName.toLowerCase().includes("minimax")) {
46961
- const transport2 = new AnthropicProviderTransport(ctx.provider, zenApiKey);
48474
+ const bearerProvider = { ...ctx.provider, authScheme: "bearer" };
48475
+ const transport2 = new AnthropicProviderTransport(bearerProvider, zenApiKey);
46962
48476
  const adapter2 = new AnthropicAPIFormat(ctx.modelName, ctx.provider.name);
46963
48477
  const handler2 = new ComposedHandler(transport2, ctx.targetModel, ctx.modelName, ctx.port, {
46964
48478
  adapter: adapter2,
@@ -47069,6 +48583,7 @@ var init_provider_profiles = __esm(() => {
47069
48583
  gemini: geminiProfile,
47070
48584
  "gemini-codeassist": geminiCodeAssistProfile,
47071
48585
  antigravity: antigravityProfile,
48586
+ devin: devinProfile,
47072
48587
  openai: openaiProfile,
47073
48588
  "openai-codex": openaiCodexProfile,
47074
48589
  "x-ai": openaiProfile,
@@ -47807,9 +49322,9 @@ var init_poe = __esm(() => {
47807
49322
  });
47808
49323
 
47809
49324
  // src/services/pricing-cache.ts
47810
- import { existsSync as existsSync18, readFileSync as readFileSync16, statSync as statSync4 } from "fs";
47811
- import { homedir as homedir26 } from "os";
47812
- import { join as join26 } from "path";
49325
+ import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync4 } from "fs";
49326
+ import { homedir as homedir27 } from "os";
49327
+ import { join as join27 } from "path";
47813
49328
  function prefixMatch(modelName) {
47814
49329
  for (const [key, pricing] of pricingMap) {
47815
49330
  if (modelName.startsWith(key))
@@ -47852,7 +49367,7 @@ function loadDiskCache() {
47852
49367
  const stat2 = statSync4(CACHE_FILE);
47853
49368
  const age = Date.now() - stat2.mtimeMs;
47854
49369
  const isFresh = age < CACHE_TTL_MS3;
47855
- const raw2 = readFileSync16(CACHE_FILE, "utf-8");
49370
+ const raw2 = readFileSync17(CACHE_FILE, "utf-8");
47856
49371
  const data = JSON.parse(raw2);
47857
49372
  for (const [key, pricing] of Object.entries(data)) {
47858
49373
  pricingMap.set(key, pricing);
@@ -47868,8 +49383,8 @@ var init_pricing_cache = __esm(() => {
47868
49383
  init_logger();
47869
49384
  init_catalog_query();
47870
49385
  pricingMap = new Map;
47871
- CACHE_DIR = join26(homedir26(), ".claudish");
47872
- CACHE_FILE = join26(CACHE_DIR, "pricing-cache.json");
49386
+ CACHE_DIR = join27(homedir27(), ".claudish");
49387
+ CACHE_FILE = join27(CACHE_DIR, "pricing-cache.json");
47873
49388
  CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
47874
49389
  });
47875
49390
 
@@ -48364,20 +49879,20 @@ var init_redact = __esm(() => {
48364
49879
  });
48365
49880
 
48366
49881
  // src/team-stats.ts
48367
- import { existsSync as existsSync19, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
48368
- import { join as join27 } from "path";
49882
+ import { existsSync as existsSync19, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "fs";
49883
+ import { join as join28 } from "path";
48369
49884
  function statsDir(sessionPath) {
48370
- return join27(sessionPath, "stats");
49885
+ return join28(sessionPath, "stats");
48371
49886
  }
48372
49887
  function tokenFileFor(sessionPath, anonId) {
48373
- return join27(statsDir(sessionPath), `${anonId}.json`);
49888
+ return join28(statsDir(sessionPath), `${anonId}.json`);
48374
49889
  }
48375
49890
  function readTokenStats(sessionPath, anonId) {
48376
49891
  const path = tokenFileFor(sessionPath, anonId);
48377
49892
  if (!existsSync19(path))
48378
49893
  return null;
48379
49894
  try {
48380
- return JSON.parse(readFileSync17(path, "utf-8"));
49895
+ return JSON.parse(readFileSync18(path, "utf-8"));
48381
49896
  } catch {
48382
49897
  return null;
48383
49898
  }
@@ -48454,10 +49969,10 @@ function renderTeamStats(sessionPath, manifest, status, opts) {
48454
49969
  if (stats?.is_free)
48455
49970
  anyFree = true;
48456
49971
  const name = model.length > nameWidth ? `${model.slice(0, nameWidth - 1)}\u2026` : model;
48457
- const bytes = m.outputSize > 0 ? fmtBytes(m.outputSize) : "";
49972
+ const bytes2 = m.outputSize > 0 ? fmtBytes(m.outputSize) : "";
48458
49973
  const tokens = stats ? `${fmtTokens(inTok)}/${outTok > 0 ? fmtTokens(outTok) : "-"}` : "";
48459
49974
  const cost = stats ? fmtCost(stats.total_cost, stats.is_free) : "";
48460
- rows.push(` ${id} ${name.padEnd(nameWidth)} ${fmtState(m.state)} ` + `${bytes.padStart(7)} ${tokens.padStart(12)} ${cost.padStart(7)}`.trimEnd());
49975
+ rows.push(` ${id} ${name.padEnd(nameWidth)} ${fmtState(m.state)} ` + `${bytes2.padStart(7)} ${tokens.padStart(12)} ${cost.padStart(7)}`.trimEnd());
48461
49976
  }
48462
49977
  const parts = [`${ids.length} models`];
48463
49978
  if (done)
@@ -48525,7 +50040,7 @@ ${segs.join(" \xB7 ")}`;
48525
50040
  }
48526
50041
  function writeStatusFile(sessionPath, manifest, status, opts) {
48527
50042
  try {
48528
- writeFileSync11(join27(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
50043
+ writeFileSync11(join28(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
48529
50044
  `, "utf-8");
48530
50045
  } catch {}
48531
50046
  }
@@ -48553,11 +50068,11 @@ import {
48553
50068
  createWriteStream as createWriteStream2,
48554
50069
  existsSync as existsSync20,
48555
50070
  mkdirSync as mkdirSync12,
48556
- readFileSync as readFileSync18,
50071
+ readFileSync as readFileSync19,
48557
50072
  readdirSync as readdirSync3,
48558
50073
  writeFileSync as writeFileSync12
48559
50074
  } from "fs";
48560
- import { join as join28, resolve as resolve3 } from "path";
50075
+ import { join as join29, resolve as resolve3 } from "path";
48561
50076
  function classifyRunOutput(opts) {
48562
50077
  const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
48563
50078
  const apiError = API_ERROR_RE.exec(stdoutTail);
@@ -48618,18 +50133,18 @@ function setupSession(sessionPath, models, input) {
48618
50133
  if (models.length === 0) {
48619
50134
  throw new Error("At least one model is required");
48620
50135
  }
48621
- if (existsSync20(join28(sessionPath, "manifest.json"))) {
50136
+ if (existsSync20(join29(sessionPath, "manifest.json"))) {
48622
50137
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
48623
50138
  }
48624
50139
  const sentinels = models.filter(isSentinelModel);
48625
50140
  if (sentinels.length > 0) {
48626
50141
  throw new Error(`Invalid model(s) for team run: ${sentinels.join(", ")}. These are Claude Code agent selectors, not external model IDs. Use real external models (e.g., "gemini-2.0-flash", "gpt-4o", "or@deepseek/deepseek-r1"). For Claude models, use a Task agent instead of the team tool.`);
48627
50142
  }
48628
- mkdirSync12(join28(sessionPath, "work"), { recursive: true });
48629
- mkdirSync12(join28(sessionPath, "errors"), { recursive: true });
50143
+ mkdirSync12(join29(sessionPath, "work"), { recursive: true });
50144
+ mkdirSync12(join29(sessionPath, "errors"), { recursive: true });
48630
50145
  if (input !== undefined) {
48631
- writeFileSync12(join28(sessionPath, "input.md"), input, "utf-8");
48632
- } else if (!existsSync20(join28(sessionPath, "input.md"))) {
50146
+ writeFileSync12(join29(sessionPath, "input.md"), input, "utf-8");
50147
+ } else if (!existsSync20(join29(sessionPath, "input.md"))) {
48633
50148
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
48634
50149
  }
48635
50150
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -48646,9 +50161,9 @@ function setupSession(sessionPath, models, input) {
48646
50161
  model: models[i],
48647
50162
  assignedAt: now
48648
50163
  };
48649
- mkdirSync12(join28(sessionPath, "work", anonId), { recursive: true });
50164
+ mkdirSync12(join29(sessionPath, "work", anonId), { recursive: true });
48650
50165
  }
48651
- writeFileSync12(join28(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
50166
+ writeFileSync12(join29(sessionPath, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
48652
50167
  const status = {
48653
50168
  startedAt: now,
48654
50169
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -48662,17 +50177,17 @@ function setupSession(sessionPath, models, input) {
48662
50177
  }
48663
50178
  ]))
48664
50179
  };
48665
- writeFileSync12(join28(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
50180
+ writeFileSync12(join29(sessionPath, "status.json"), JSON.stringify(status, null, 2), "utf-8");
48666
50181
  return manifest;
48667
50182
  }
48668
50183
  async function runModels(sessionPath, opts = {}) {
48669
50184
  const timeoutMs = (opts.timeout ?? 300) * 1000;
48670
- const manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
48671
- const statusPath = join28(sessionPath, "status.json");
48672
- const inputPath = join28(sessionPath, "input.md");
48673
- const inputContent = readFileSync18(inputPath, "utf-8");
50185
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
50186
+ const statusPath = join29(sessionPath, "status.json");
50187
+ const inputPath = join29(sessionPath, "input.md");
50188
+ const inputContent = readFileSync19(inputPath, "utf-8");
48674
50189
  const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
48675
- const statusCache = JSON.parse(readFileSync18(statusPath, "utf-8"));
50190
+ const statusCache = JSON.parse(readFileSync19(statusPath, "utf-8"));
48676
50191
  function updateModelStatus(id, update) {
48677
50192
  statusCache.models[id] = { ...statusCache.models[id], ...update };
48678
50193
  writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
@@ -48691,8 +50206,8 @@ async function runModels(sessionPath, opts = {}) {
48691
50206
  process.on("SIGINT", sigintHandler);
48692
50207
  const completionPromises = [];
48693
50208
  for (const [anonId, entry] of Object.entries(manifest.models)) {
48694
- const outputPath = join28(sessionPath, `response-${anonId}.md`);
48695
- const errorLogPath = join28(sessionPath, "errors", `${anonId}.log`);
50209
+ const outputPath = join29(sessionPath, `response-${anonId}.md`);
50210
+ const errorLogPath = join29(sessionPath, "errors", `${anonId}.log`);
48696
50211
  const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
48697
50212
  const args = ["--model", spawnModel, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
48698
50213
  updateModelStatus(anonId, {
@@ -48841,14 +50356,14 @@ async function runModels(sessionPath, opts = {}) {
48841
50356
  const rt = runtimes.get(id);
48842
50357
  const stderr = rt?.getStderr() ?? "";
48843
50358
  const stdoutTail = rt?.getStdoutTail() ?? "";
48844
- const bytes = rt?.getByteCount() ?? 0;
48845
- const detail = `Killed by the orchestrator after ${timeoutMs / 1000}s with ${bytes} B of stdout. ` + "In --quiet print mode the child emits its answer only at the end, so 0 B means " + `"did not finish", not "produced nothing".`;
50359
+ const bytes2 = rt?.getByteCount() ?? 0;
50360
+ const detail = `Killed by the orchestrator after ${timeoutMs / 1000}s with ${bytes2} B of stdout. ` + "In --quiet print mode the child emits its answer only at the end, so 0 B means " + `"did not finish", not "produced nothing".`;
48846
50361
  if (rt)
48847
50362
  persistErrorLog(rt.errorLogPath, `TIMEOUT: ${detail}`, stderr, stdoutTail);
48848
50363
  updateModelStatus(id, {
48849
50364
  state: "TIMEOUT",
48850
50365
  completedAt: new Date().toISOString(),
48851
- outputSize: bytes,
50366
+ outputSize: bytes2,
48852
50367
  error: rt ? {
48853
50368
  model: id,
48854
50369
  command: rt.command,
@@ -48882,23 +50397,23 @@ async function judgeResponses(sessionPath, opts = {}) {
48882
50397
  const responses = {};
48883
50398
  for (const file2 of responseFiles) {
48884
50399
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
48885
- responses[id] = readFileSync18(join28(sessionPath, file2), "utf-8");
50400
+ responses[id] = readFileSync19(join29(sessionPath, file2), "utf-8");
48886
50401
  }
48887
- const input = readFileSync18(join28(sessionPath, "input.md"), "utf-8");
50402
+ const input = readFileSync19(join29(sessionPath, "input.md"), "utf-8");
48888
50403
  const judgePrompt = buildJudgePrompt(input, responses);
48889
- writeFileSync12(join28(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50404
+ writeFileSync12(join29(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
48890
50405
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
48891
- const judgePath = join28(sessionPath, "judging");
50406
+ const judgePath = join29(sessionPath, "judging");
48892
50407
  mkdirSync12(judgePath, { recursive: true });
48893
50408
  setupSession(judgePath, judgeModels, judgePrompt);
48894
50409
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
48895
50410
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
48896
50411
  const verdict = aggregateVerdict(votes, Object.keys(responses));
48897
- writeFileSync12(join28(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50412
+ writeFileSync12(join29(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
48898
50413
  return verdict;
48899
50414
  }
48900
50415
  function getStatus(sessionPath) {
48901
- return JSON.parse(readFileSync18(join28(sessionPath, "status.json"), "utf-8"));
50416
+ return JSON.parse(readFileSync19(join29(sessionPath, "status.json"), "utf-8"));
48902
50417
  }
48903
50418
  function fisherYatesShuffle(arr) {
48904
50419
  for (let i = arr.length - 1;i > 0; i--) {
@@ -48908,7 +50423,7 @@ function fisherYatesShuffle(arr) {
48908
50423
  return arr;
48909
50424
  }
48910
50425
  function getDefaultJudgeModels(sessionPath) {
48911
- const manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
50426
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
48912
50427
  return Object.values(manifest.models).map((e) => e.model);
48913
50428
  }
48914
50429
  function buildJudgePrompt(input, responses) {
@@ -48971,7 +50486,7 @@ function parseJudgeVotes(judgePath, responseIds) {
48971
50486
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
48972
50487
  let content;
48973
50488
  try {
48974
- content = readFileSync18(join28(judgePath, file2), "utf-8");
50489
+ content = readFileSync19(join29(judgePath, file2), "utf-8");
48975
50490
  } catch {
48976
50491
  continue;
48977
50492
  }
@@ -49023,7 +50538,7 @@ function aggregateVerdict(votes, responseIds) {
49023
50538
  function formatVerdict(verdict, sessionPath) {
49024
50539
  let manifest = null;
49025
50540
  try {
49026
- manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
50541
+ manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
49027
50542
  } catch {}
49028
50543
  let output = `# Team Verdict
49029
50544
 
@@ -49078,14 +50593,14 @@ __export(exports_mcp_server, {
49078
50593
  parseAnthropicSse: () => parseAnthropicSse,
49079
50594
  formatTeamResult: () => formatTeamResult
49080
50595
  });
49081
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync19, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
49082
- import { homedir as homedir27 } from "os";
49083
- import { dirname as dirname9, join as join29, resolve as resolve4 } from "path";
50596
+ import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync20, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
50597
+ import { homedir as homedir28 } from "os";
50598
+ import { dirname as dirname9, join as join30, resolve as resolve4 } from "path";
49084
50599
  import { fileURLToPath } from "url";
49085
50600
  async function loadAllModels(forceRefresh = false) {
49086
50601
  if (!forceRefresh && existsSync21(ALL_MODELS_CACHE_PATH2)) {
49087
50602
  try {
49088
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_CACHE_PATH2, "utf-8"));
50603
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_CACHE_PATH2, "utf-8"));
49089
50604
  const lastUpdated = new Date(cacheData.lastUpdated);
49090
50605
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
49091
50606
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -49104,7 +50619,7 @@ async function loadAllModels(forceRefresh = false) {
49104
50619
  return models;
49105
50620
  } catch {
49106
50621
  if (existsSync21(ALL_MODELS_CACHE_PATH2)) {
49107
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_CACHE_PATH2, "utf-8"));
50622
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_CACHE_PATH2, "utf-8"));
49108
50623
  return cacheData.models || [];
49109
50624
  }
49110
50625
  return [];
@@ -49686,7 +51201,7 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49686
51201
  let stderrFull = stderr_snippet || "";
49687
51202
  if (error_log_path) {
49688
51203
  try {
49689
- stderrFull = readFileSync19(error_log_path, "utf-8");
51204
+ stderrFull = readFileSync20(error_log_path, "utf-8");
49690
51205
  } catch {}
49691
51206
  }
49692
51207
  const sessionData = {};
@@ -49694,16 +51209,16 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49694
51209
  const sp = session_path;
49695
51210
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
49696
51211
  try {
49697
- sessionData[file2] = readFileSync19(join29(sp, file2), "utf-8");
51212
+ sessionData[file2] = readFileSync20(join30(sp, file2), "utf-8");
49698
51213
  } catch {}
49699
51214
  }
49700
51215
  try {
49701
- const errorDir = join29(sp, "errors");
51216
+ const errorDir = join30(sp, "errors");
49702
51217
  if (existsSync21(errorDir)) {
49703
51218
  for (const f of readdirSync4(errorDir)) {
49704
51219
  if (f.endsWith(".log")) {
49705
51220
  try {
49706
- sessionData[`errors/${f}`] = readFileSync19(join29(errorDir, f), "utf-8");
51221
+ sessionData[`errors/${f}`] = readFileSync20(join30(errorDir, f), "utf-8");
49707
51222
  } catch {}
49708
51223
  }
49709
51224
  }
@@ -49713,7 +51228,7 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49713
51228
  for (const f of readdirSync4(sp)) {
49714
51229
  if (f.startsWith("response-") && f.endsWith(".md")) {
49715
51230
  try {
49716
- const content = readFileSync19(join29(sp, f), "utf-8");
51231
+ const content = readFileSync20(join30(sp, f), "utf-8");
49717
51232
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
49718
51233
  } catch {}
49719
51234
  }
@@ -49722,9 +51237,9 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49722
51237
  }
49723
51238
  let version2 = "unknown";
49724
51239
  try {
49725
- const pkgPath = join29(__dirname2, "../package.json");
51240
+ const pkgPath = join30(__dirname2, "../package.json");
49726
51241
  if (existsSync21(pkgPath)) {
49727
- version2 = JSON.parse(readFileSync19(pkgPath, "utf-8")).version;
51242
+ version2 = JSON.parse(readFileSync20(pkgPath, "utf-8")).version;
49728
51243
  }
49729
51244
  } catch {}
49730
51245
  const report = {
@@ -50128,8 +51643,8 @@ var init_mcp_server = __esm(() => {
50128
51643
  import_dotenv2.config({ quiet: true });
50129
51644
  __filename2 = fileURLToPath(import.meta.url);
50130
51645
  __dirname2 = dirname9(__filename2);
50131
- CLAUDISH_CACHE_DIR = join29(homedir27(), ".claudish");
50132
- ALL_MODELS_CACHE_PATH2 = join29(CLAUDISH_CACHE_DIR, "all-models.json");
51646
+ CLAUDISH_CACHE_DIR = join30(homedir28(), ".claudish");
51647
+ ALL_MODELS_CACHE_PATH2 = join30(CLAUDISH_CACHE_DIR, "all-models.json");
50133
51648
  NEXT_STEP = {
50134
51649
  nonzero_exit: "read the evidence log, then retry or drop the model",
50135
51650
  timeout: "raise `timeout`, or pick a faster model",
@@ -50154,7 +51669,7 @@ var exports_serve_command = {};
50154
51669
  __export(exports_serve_command, {
50155
51670
  serveCommand: () => serveCommand
50156
51671
  });
50157
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
51672
+ import { existsSync as existsSync22, readFileSync as readFileSync21 } from "fs";
50158
51673
  function parseServeArgs(args) {
50159
51674
  const out = {};
50160
51675
  for (let i = 0;i < args.length; i++) {
@@ -50178,7 +51693,7 @@ function loadModelMap(path) {
50178
51693
  }
50179
51694
  let raw2;
50180
51695
  try {
50181
- raw2 = readFileSync20(path, "utf-8");
51696
+ raw2 = readFileSync21(path, "utf-8");
50182
51697
  } catch (e) {
50183
51698
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
50184
51699
  }
@@ -50255,7 +51770,7 @@ var exports_behavior_command = {};
50255
51770
  __export(exports_behavior_command, {
50256
51771
  behaviorCommand: () => behaviorCommand
50257
51772
  });
50258
- import { existsSync as existsSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
51773
+ import { existsSync as existsSync23, readFileSync as readFileSync22, writeFileSync as writeFileSync14 } from "fs";
50259
51774
  function severityColor(sev) {
50260
51775
  if (sev === "fix")
50261
51776
  return green(sev);
@@ -50354,7 +51869,7 @@ function setTelemetryEnabled(value) {
50354
51869
  let cfg = {};
50355
51870
  try {
50356
51871
  if (existsSync23(path)) {
50357
- const parsed = JSON.parse(readFileSync21(path, "utf-8"));
51872
+ const parsed = JSON.parse(readFileSync22(path, "utf-8"));
50358
51873
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
50359
51874
  cfg = parsed;
50360
51875
  }
@@ -50376,7 +51891,7 @@ function showTelemetry(action, json2) {
50376
51891
  try {
50377
51892
  const path = outboxPath();
50378
51893
  if (existsSync23(path)) {
50379
- pending = readFileSync21(path, "utf8").split(`
51894
+ pending = readFileSync22(path, "utf8").split(`
50380
51895
  `).filter(Boolean).length;
50381
51896
  }
50382
51897
  } catch {}
@@ -50449,6 +51964,12 @@ function describeSourceSync(p, config3) {
50449
51964
  return "oauth";
50450
51965
  if (p.catalogName === "antigravity" && hasSharedAntigravityToken())
50451
51966
  return "oauth";
51967
+ if (p.catalogName === "devin") {
51968
+ if (realValue(process.env.WINDSURF_API_KEY))
51969
+ return "env";
51970
+ if (hasDevinCredentials())
51971
+ return "oauth";
51972
+ }
50452
51973
  const hasCfg = !!p.apiKeyEnvVar && !!realValue(config3.apiKeys?.[p.apiKeyEnvVar]);
50453
51974
  const hasEnv = !!p.apiKeyEnvVar && !!realValue(process.env[p.apiKeyEnvVar]);
50454
51975
  if (hasEnv && hasCfg)
@@ -50469,6 +51990,7 @@ async function describeSource(p, config3) {
50469
51990
  }
50470
51991
  var init_source = __esm(() => {
50471
51992
  init_profile_config();
51993
+ init_devin_credentials();
50472
51994
  init_antigravity_token();
50473
51995
  init_oauth_registry();
50474
51996
  init_api_key_credential();
@@ -50516,8 +52038,8 @@ function providerIsReadyForDisplay(p, config3, localLiveness) {
50516
52038
  function providerAuthCapabilities(p, config3) {
50517
52039
  const apiKeySupported = !!p.apiKeyEnvVar;
50518
52040
  const apiKeySet = apiKeySupported && (!!process.env[p.apiKeyEnvVar] || !!config3.apiKeys?.[p.apiKeyEnvVar]);
50519
- const oauthSupported = !!p.oauthSlug;
50520
- const oauthSet = oauthSupported && (hasOAuthCredentials(p.catalogName) || p.catalogName === "antigravity" && hasSharedAntigravityToken());
52041
+ const oauthSupported = !!p.oauthSlug || p.catalogName === "devin";
52042
+ const oauthSet = oauthSupported && (hasOAuthCredentials(p.catalogName) || p.catalogName === "antigravity" && hasSharedAntigravityToken() || p.catalogName === "devin" && hasDevinCredentials());
50521
52043
  return {
50522
52044
  apiKey: { supported: apiKeySupported, set: apiKeySet },
50523
52045
  oauth: { supported: oauthSupported, set: oauthSet }
@@ -50535,6 +52057,7 @@ var init_providers = __esm(() => {
50535
52057
  init_antigravity_token();
50536
52058
  init_source();
50537
52059
  init_oauth_registry();
52060
+ init_devin_credentials();
50538
52061
  init_provider_definitions();
50539
52062
  SKIP = new Set(["qwen", "native-anthropic"]);
50540
52063
  PROVIDERS = getAllProviders().filter((d) => !SKIP.has(d.name)).map(toProviderDef);
@@ -59783,18 +61306,18 @@ var require_dbcs_codec = __commonJS((exports) => {
59783
61306
  DBCSCodec.prototype.encoder = DBCSEncoder;
59784
61307
  DBCSCodec.prototype.decoder = DBCSDecoder;
59785
61308
  DBCSCodec.prototype._getDecodeTrieNode = function(addr) {
59786
- var bytes = [];
61309
+ var bytes2 = [];
59787
61310
  for (;addr > 0; addr >>>= 8) {
59788
- bytes.push(addr & 255);
61311
+ bytes2.push(addr & 255);
59789
61312
  }
59790
- if (bytes.length == 0) {
59791
- bytes.push(0);
61313
+ if (bytes2.length == 0) {
61314
+ bytes2.push(0);
59792
61315
  }
59793
61316
  var node = this.decodeTables[0];
59794
- for (var i2 = bytes.length - 1;i2 > 0; i2--) {
59795
- var val = node[bytes[i2]];
61317
+ for (var i2 = bytes2.length - 1;i2 > 0; i2--) {
61318
+ var val = node[bytes2[i2]];
59796
61319
  if (val == UNASSIGNED) {
59797
- node[bytes[i2]] = NODE_START - this.decodeTables.length;
61320
+ node[bytes2[i2]] = NODE_START - this.decodeTables.length;
59798
61321
  this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));
59799
61322
  } else if (val <= NODE_START) {
59800
61323
  node = this.decodeTables[NODE_START - val];
@@ -61845,10 +63368,10 @@ var init_RemoveFileError = __esm(() => {
61845
63368
 
61846
63369
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
61847
63370
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
61848
- import { readFileSync as readFileSync22, unlinkSync as unlinkSync6, writeFileSync as writeFileSync15 } from "fs";
63371
+ import { readFileSync as readFileSync23, unlinkSync as unlinkSync6, writeFileSync as writeFileSync15 } from "fs";
61849
63372
  import path from "path";
61850
63373
  import os from "os";
61851
- import { randomUUID as randomUUID6 } from "crypto";
63374
+ import { randomUUID as randomUUID7 } from "crypto";
61852
63375
  function editAsync(text = "", callback, fileOptions) {
61853
63376
  const editor = new ExternalEditor(text, fileOptions);
61854
63377
  editor.runAsync((err, result) => {
@@ -61940,7 +63463,7 @@ class ExternalEditor {
61940
63463
  createTemporaryFile() {
61941
63464
  try {
61942
63465
  const baseDir = this.fileOptions.dir ?? os.tmpdir();
61943
- const id = randomUUID6();
63466
+ const id = randomUUID7();
61944
63467
  const prefix = sanitizeAffix(this.fileOptions.prefix);
61945
63468
  const postfix = sanitizeAffix(this.fileOptions.postfix);
61946
63469
  const filename = `${prefix}${id}${postfix}`;
@@ -61961,7 +63484,7 @@ class ExternalEditor {
61961
63484
  }
61962
63485
  readTemporaryFile() {
61963
63486
  try {
61964
- const tempFileBuffer = readFileSync22(this.tempFile);
63487
+ const tempFileBuffer = readFileSync23(this.tempFile);
61965
63488
  if (tempFileBuffer.length === 0) {
61966
63489
  this.text = "";
61967
63490
  } else {
@@ -62943,8 +64466,8 @@ var init_dist16 = __esm(() => {
62943
64466
  // src/auth/antigravity-oauth.ts
62944
64467
  import { spawnSync as spawnSync3 } from "child_process";
62945
64468
  import { existsSync as existsSync24, unlinkSync as unlinkSync7 } from "fs";
62946
- import { homedir as homedir28 } from "os";
62947
- import { join as join30 } from "path";
64469
+ import { homedir as homedir29 } from "os";
64470
+ import { join as join31 } from "path";
62948
64471
  async function defaultSuggestModel() {
62949
64472
  try {
62950
64473
  const tok = readSharedAntigravityToken();
@@ -63065,7 +64588,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
63065
64588
  async logout(deps) {
63066
64589
  deleteSharedAntigravityToken(deps);
63067
64590
  try {
63068
- const tokenFile = join30(homedir28(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
64591
+ const tokenFile = join31(homedir29(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
63069
64592
  if (existsSync24(tokenFile))
63070
64593
  unlinkSync7(tokenFile);
63071
64594
  } catch {}
@@ -64517,11 +66040,11 @@ async function probeLink(proxyUrl, link, timeoutMs) {
64517
66040
  } catch (e) {
64518
66041
  const latencyMs = Date.now() - startedAt;
64519
66042
  const name = e?.name || "";
64520
- const msg = String(e?.message || e);
64521
- if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg)) {
64522
- return { state: "timeout", latencyMs, errorMessage: msg };
66043
+ const msg2 = String(e?.message || e);
66044
+ if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg2)) {
66045
+ return { state: "timeout", latencyMs, errorMessage: msg2 };
64523
66046
  }
64524
- return { state: "network-error", latencyMs, errorMessage: msg };
66047
+ return { state: "network-error", latencyMs, errorMessage: msg2 };
64525
66048
  }
64526
66049
  const ttfbMs = Date.now() - startedAt;
64527
66050
  if (!response.ok) {
@@ -64550,7 +66073,7 @@ function annotateOAuthHint(result, provider, isOAuth) {
64550
66073
  return result;
64551
66074
  if (result.state === "live")
64552
66075
  return result;
64553
- const loginCommand2 = provider === "gemini-codeassist" ? "claudish login gemini" : provider === "antigravity" ? "claudish login antigravity" : provider === "vertex" ? "gcloud auth application-default login" : undefined;
66076
+ const loginCommand2 = provider === "gemini-codeassist" ? "claudish login gemini" : provider === "antigravity" ? "claudish login antigravity" : provider === "vertex" ? "gcloud auth application-default login" : provider === "devin" ? "devin login" : undefined;
64554
66077
  if (!loginCommand2)
64555
66078
  return result;
64556
66079
  if (result.httpStatus === 403)
@@ -64658,9 +66181,9 @@ function extractErrorMessage(body) {
64658
66181
  return;
64659
66182
  try {
64660
66183
  const parsed = JSON.parse(body);
64661
- const msg = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
64662
- if (typeof msg === "string" && msg.length > 0) {
64663
- return msg.length > 160 ? `${msg.slice(0, 157)}...` : msg;
66184
+ const msg2 = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
66185
+ if (typeof msg2 === "string" && msg2.length > 0) {
66186
+ return msg2.length > 160 ? `${msg2.slice(0, 157)}...` : msg2;
64664
66187
  }
64665
66188
  } catch {}
64666
66189
  const trimmed2 = body.trim();
@@ -64876,7 +66399,7 @@ function isFailureState(state) {
64876
66399
  }
64877
66400
  var STREAM_MS_FLOOR = 50, OAUTH_PROVIDERS2, PROBE_PROMPT = "Count from one to twenty in words, one per line.", PROBE_MAX_TOKENS = 512;
64878
66401
  var init_probe_live = __esm(() => {
64879
- OAUTH_PROVIDERS2 = new Set(["vertex", "gemini-codeassist"]);
66402
+ OAUTH_PROVIDERS2 = new Set(["vertex", "gemini-codeassist", "devin"]);
64880
66403
  });
64881
66404
 
64882
66405
  // src/tui/theme.ts
@@ -67154,19 +68677,19 @@ import {
67154
68677
  copyFileSync as copyFileSync2,
67155
68678
  existsSync as existsSync25,
67156
68679
  mkdirSync as mkdirSync14,
67157
- readFileSync as readFileSync23,
68680
+ readFileSync as readFileSync24,
67158
68681
  readdirSync as readdirSync5,
67159
68682
  unlinkSync as unlinkSync8,
67160
68683
  writeFileSync as writeFileSync16
67161
68684
  } from "fs";
67162
- import { homedir as homedir29 } from "os";
67163
- import { dirname as dirname10, join as join31 } from "path";
68685
+ import { homedir as homedir30 } from "os";
68686
+ import { dirname as dirname10, join as join32 } from "path";
67164
68687
  import { fileURLToPath as fileURLToPath2 } from "url";
67165
68688
  function getVersion3() {
67166
68689
  return VERSION;
67167
68690
  }
67168
68691
  function clearAllModelCaches() {
67169
- const cacheDir = join31(homedir29(), ".claudish");
68692
+ const cacheDir = join32(homedir30(), ".claudish");
67170
68693
  if (!existsSync25(cacheDir))
67171
68694
  return;
67172
68695
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
@@ -67175,7 +68698,7 @@ function clearAllModelCaches() {
67175
68698
  const files = readdirSync5(cacheDir);
67176
68699
  for (const file2 of files) {
67177
68700
  if (cachePatterns.includes(file2)) {
67178
- unlinkSync8(join31(cacheDir, file2));
68701
+ unlinkSync8(join32(cacheDir, file2));
67179
68702
  cleared++;
67180
68703
  }
67181
68704
  }
@@ -67585,7 +69108,7 @@ Usage: claudish --models --provider <slug>`);
67585
69108
  });
67586
69109
  config3.resolvedDefaultProvider = resolved;
67587
69110
  if (resolved.legacyAutoPromoted && !config3.quiet) {
67588
- const markerFile = join31(homedir29(), ".claudish", ".legacy-litellm-hint-shown");
69111
+ const markerFile = join32(homedir30(), ".claudish", ".legacy-litellm-hint-shown");
67589
69112
  if (!existsSync25(markerFile)) {
67590
69113
  const hint = buildLegacyHint(resolved);
67591
69114
  if (hint) {
@@ -68056,6 +69579,9 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
68056
69579
  } else if (providerName === "litellm") {
68057
69580
  formatAdapterName = "LiteLLMAPIFormat";
68058
69581
  declaredStreamFormat = "openai-sse";
69582
+ } else if (providerName === "devin") {
69583
+ formatAdapterName = "DevinAPIFormat";
69584
+ declaredStreamFormat = "connect-proto";
68059
69585
  } else {
68060
69586
  formatAdapterName = "OpenAIAPIFormat";
68061
69587
  declaredStreamFormat = "openai-sse";
@@ -68094,8 +69620,8 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
68094
69620
  console.error(`${DIM}Probing providers via live requests (may incur small cost, use --no-probe to skip)...${RESET}`);
68095
69621
  liveProxy2 = await createProxyServer2(probePort, process.env.OPENROUTER_API_KEY, undefined, false, process.env.ANTHROPIC_API_KEY, undefined, { quiet: true });
68096
69622
  } catch (e) {
68097
- const msg = e instanceof Error ? e.message : String(e);
68098
- console.error(`${YELLOW}Failed to start probe proxy (${msg}). Falling back to static probe.${RESET}`);
69623
+ const msg2 = e instanceof Error ? e.message : String(e);
69624
+ console.error(`${YELLOW}Failed to start probe proxy (${msg2}). Falling back to static probe.${RESET}`);
68099
69625
  liveProxy2 = null;
68100
69626
  }
68101
69627
  }
@@ -68660,8 +70186,8 @@ ${h("MORE INFO")}
68660
70186
  }
68661
70187
  function printAIAgentGuide() {
68662
70188
  try {
68663
- const guidePath = join31(__dirname3, "../AI_AGENT_GUIDE.md");
68664
- const guideContent = readFileSync23(guidePath, "utf-8");
70189
+ const guidePath = join32(__dirname3, "../AI_AGENT_GUIDE.md");
70190
+ const guideContent = readFileSync24(guidePath, "utf-8");
68665
70191
  console.log(guideContent);
68666
70192
  } catch (error46) {
68667
70193
  console.error("Error reading AI Agent Guide:");
@@ -68677,10 +70203,10 @@ async function initializeClaudishSkill() {
68677
70203
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
68678
70204
  `);
68679
70205
  const cwd = process.cwd();
68680
- const claudeDir = join31(cwd, ".claude");
68681
- const skillsDir = join31(claudeDir, "skills");
68682
- const claudishSkillDir = join31(skillsDir, "claudish-usage");
68683
- const skillFile = join31(claudishSkillDir, "SKILL.md");
70206
+ const claudeDir = join32(cwd, ".claude");
70207
+ const skillsDir = join32(claudeDir, "skills");
70208
+ const claudishSkillDir = join32(skillsDir, "claudish-usage");
70209
+ const skillFile = join32(claudishSkillDir, "SKILL.md");
68684
70210
  if (existsSync25(skillFile)) {
68685
70211
  console.log("\u2705 Claudish skill already installed at:");
68686
70212
  console.log(` ${skillFile}
@@ -68688,7 +70214,7 @@ async function initializeClaudishSkill() {
68688
70214
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
68689
70215
  return;
68690
70216
  }
68691
- const sourceSkillPath = join31(__dirname3, "../skills/claudish-usage/SKILL.md");
70217
+ const sourceSkillPath = join32(__dirname3, "../skills/claudish-usage/SKILL.md");
68692
70218
  if (!existsSync25(sourceSkillPath)) {
68693
70219
  console.error("\u274C Error: Claudish skill file not found in installation.");
68694
70220
  console.error(` Expected at: ${sourceSkillPath}`);
@@ -68791,24 +70317,24 @@ __export(exports_update_checker, {
68791
70317
  clearCache: () => clearCache,
68792
70318
  checkForUpdates: () => checkForUpdates
68793
70319
  });
68794
- import { existsSync as existsSync26, mkdirSync as mkdirSync15, readFileSync as readFileSync24, unlinkSync as unlinkSync9, writeFileSync as writeFileSync17 } from "fs";
68795
- import { homedir as homedir30, platform as platform2, tmpdir } from "os";
68796
- import { join as join32 } from "path";
70320
+ import { existsSync as existsSync26, mkdirSync as mkdirSync15, readFileSync as readFileSync25, unlinkSync as unlinkSync9, writeFileSync as writeFileSync17 } from "fs";
70321
+ import { homedir as homedir31, platform as platform2, tmpdir } from "os";
70322
+ import { join as join33 } from "path";
68797
70323
  function getCacheFilePath() {
68798
70324
  let cacheDir;
68799
70325
  if (isWindows) {
68800
- const localAppData = process.env.LOCALAPPDATA || join32(homedir30(), "AppData", "Local");
68801
- cacheDir = join32(localAppData, "claudish");
70326
+ const localAppData = process.env.LOCALAPPDATA || join33(homedir31(), "AppData", "Local");
70327
+ cacheDir = join33(localAppData, "claudish");
68802
70328
  } else {
68803
- cacheDir = join32(homedir30(), ".cache", "claudish");
70329
+ cacheDir = join33(homedir31(), ".cache", "claudish");
68804
70330
  }
68805
70331
  try {
68806
70332
  if (!existsSync26(cacheDir)) {
68807
70333
  mkdirSync15(cacheDir, { recursive: true });
68808
70334
  }
68809
- return join32(cacheDir, "update-check.json");
70335
+ return join33(cacheDir, "update-check.json");
68810
70336
  } catch {
68811
- return join32(tmpdir(), "claudish-update-check.json");
70337
+ return join33(tmpdir(), "claudish-update-check.json");
68812
70338
  }
68813
70339
  }
68814
70340
  function readCache() {
@@ -68817,7 +70343,7 @@ function readCache() {
68817
70343
  if (!existsSync26(cachePath)) {
68818
70344
  return null;
68819
70345
  }
68820
- const data = JSON.parse(readFileSync24(cachePath, "utf-8"));
70346
+ const data = JSON.parse(readFileSync25(cachePath, "utf-8"));
68821
70347
  return data;
68822
70348
  } catch {
68823
70349
  return null;
@@ -69725,15 +71251,15 @@ var init_local_liveness = __esm(() => {
69725
71251
  });
69726
71252
 
69727
71253
  // src/providers/probe-catalog.ts
69728
- import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync18 } from "fs";
69729
- import { homedir as homedir31 } from "os";
69730
- import { dirname as dirname11, join as join33 } from "path";
71254
+ import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync26, writeFileSync as writeFileSync18 } from "fs";
71255
+ import { homedir as homedir32 } from "os";
71256
+ import { dirname as dirname11, join as join34 } from "path";
69731
71257
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
69732
71258
  if (!existsSync27(path2))
69733
71259
  return null;
69734
71260
  let raw2;
69735
71261
  try {
69736
- raw2 = JSON.parse(readFileSync25(path2, "utf-8"));
71262
+ raw2 = JSON.parse(readFileSync26(path2, "utf-8"));
69737
71263
  } catch {
69738
71264
  return null;
69739
71265
  }
@@ -69862,7 +71388,7 @@ function isValidResponse(raw2) {
69862
71388
  var PROBE_MODELS_URL = "https://us-central1-claudish-6da10.cloudfunctions.net/probeModels", CACHE_TTL_MS4, FETCH_TIMEOUT_MS3 = 15000, PROBE_MODELS_CACHE_PATH, _inFlight = null;
69863
71389
  var init_probe_catalog = __esm(() => {
69864
71390
  CACHE_TTL_MS4 = 60 * 60 * 1000;
69865
- PROBE_MODELS_CACHE_PATH = join33(homedir31(), ".claudish", "probe-models.json");
71391
+ PROBE_MODELS_CACHE_PATH = join34(homedir32(), ".claudish", "probe-models.json");
69866
71392
  });
69867
71393
 
69868
71394
  // src/tui/constants.ts
@@ -74309,8 +75835,8 @@ function useRouteProbe(config3) {
74309
75835
  try {
74310
75836
  proxyUrl = await ensureProbeProxy();
74311
75837
  } catch (err) {
74312
- const msg = err instanceof Error ? err.message : String(err);
74313
- setProbeResults((prev) => prev.map((e) => ({ ...e, status: "failed", error: `probe proxy: ${msg}` })));
75838
+ const msg2 = err instanceof Error ? err.message : String(err);
75839
+ setProbeResults((prev) => prev.map((e) => ({ ...e, status: "failed", error: `probe proxy: ${msg2}` })));
74314
75840
  setProbeMode("done");
74315
75841
  return;
74316
75842
  }
@@ -74664,12 +76190,12 @@ function App({ requestLogin } = {}) {
74664
76190
  }));
74665
76191
  setStatusMsg(`1Password test ok \u2192 ${note}`);
74666
76192
  } catch (err) {
74667
- const msg = err instanceof Error ? err.message : String(err);
76193
+ const msg2 = err instanceof Error ? err.message : String(err);
74668
76194
  setOpTestResults((prev) => ({
74669
76195
  ...prev,
74670
- [key]: { status: "failed", error: msg }
76196
+ [key]: { status: "failed", error: msg2 }
74671
76197
  }));
74672
- setStatusMsg(msg);
76198
+ setStatusMsg(msg2);
74673
76199
  } finally {
74674
76200
  setOpBusy(false);
74675
76201
  }
@@ -74744,14 +76270,14 @@ function App({ requestLogin } = {}) {
74744
76270
  invalidateProbeProxyHandlers();
74745
76271
  refreshConfig();
74746
76272
  } catch (testErr) {
74747
- const msg = testErr instanceof Error ? testErr.message : String(testErr);
74748
- console.error(`[claudish] 1Password add: saved but live resolve failed: ${msg}`);
74749
- setStatusMsg(`1Password ${kindWord} saved (${scope}) \u2014 live resolve failed: ${msg}`);
76273
+ const msg2 = testErr instanceof Error ? testErr.message : String(testErr);
76274
+ console.error(`[claudish] 1Password add: saved but live resolve failed: ${msg2}`);
76275
+ setStatusMsg(`1Password ${kindWord} saved (${scope}) \u2014 live resolve failed: ${msg2}`);
74750
76276
  }
74751
76277
  } catch (err) {
74752
- const msg = err instanceof Error ? err.message : String(err);
74753
- console.error(`[claudish] 1Password add failed to persist: ${msg}`);
74754
- setStatusMsg(`1Password add failed: ${msg}`);
76278
+ const msg2 = err instanceof Error ? err.message : String(err);
76279
+ console.error(`[claudish] 1Password add failed to persist: ${msg2}`);
76280
+ setStatusMsg(`1Password add failed: ${msg2}`);
74755
76281
  setMode("browse");
74756
76282
  resetOpWizard();
74757
76283
  } finally {
@@ -74771,8 +76297,8 @@ function App({ requestLogin } = {}) {
74771
76297
  setOpVaults(vaults);
74772
76298
  setStatusMsg(`1Password: ${vaults.length} vault${vaults.length === 1 ? "" : "s"}.`);
74773
76299
  } catch (err) {
74774
- const msg = err instanceof Error ? err.message : String(err);
74775
- setStatusMsg(msg);
76300
+ const msg2 = err instanceof Error ? err.message : String(err);
76301
+ setStatusMsg(msg2);
74776
76302
  setMode("browse");
74777
76303
  } finally {
74778
76304
  setOpBusy(false);
@@ -74793,8 +76319,8 @@ function App({ requestLogin } = {}) {
74793
76319
  setOpItems(items);
74794
76320
  setStatusMsg(`1Password: ${items.length} item${items.length === 1 ? "" : "s"}.`);
74795
76321
  } catch (err) {
74796
- const msg = err instanceof Error ? err.message : String(err);
74797
- setStatusMsg(msg);
76322
+ const msg2 = err instanceof Error ? err.message : String(err);
76323
+ setStatusMsg(msg2);
74798
76324
  setMode("browse");
74799
76325
  } finally {
74800
76326
  setOpBusy(false);
@@ -74822,8 +76348,8 @@ function App({ requestLogin } = {}) {
74822
76348
  setOpFields(fields);
74823
76349
  setStatusMsg(`1Password: ${fields.length} field${fields.length === 1 ? "" : "s"}.`);
74824
76350
  } catch (err) {
74825
- const msg = err instanceof Error ? err.message : String(err);
74826
- setStatusMsg(msg);
76351
+ const msg2 = err instanceof Error ? err.message : String(err);
76352
+ setStatusMsg(msg2);
74827
76353
  setMode("browse");
74828
76354
  } finally {
74829
76355
  setOpBusy(false);
@@ -74839,9 +76365,9 @@ function App({ requestLogin } = {}) {
74839
76365
  setOpEnvPreview(names);
74840
76366
  setStatusMsg(`1Password environment \u2192 ${names.length} var${names.length === 1 ? "" : "s"}. Enter to save.`);
74841
76367
  } catch (err) {
74842
- const msg = err instanceof Error ? err.message : String(err);
76368
+ const msg2 = err instanceof Error ? err.message : String(err);
74843
76369
  setOpEnvPreview(null);
74844
- setStatusMsg(msg);
76370
+ setStatusMsg(msg2);
74845
76371
  } finally {
74846
76372
  setOpBusy(false);
74847
76373
  }
@@ -74949,10 +76475,10 @@ function App({ requestLogin } = {}) {
74949
76475
  }
74950
76476
  } catch (err) {
74951
76477
  const ms = Date.now() - startMs;
74952
- const msg = err instanceof Error ? err.message : String(err);
76478
+ const msg2 = err instanceof Error ? err.message : String(err);
74953
76479
  setTestResults((prev) => ({
74954
76480
  ...prev,
74955
- [provName]: { status: "failed", error: `proxy: ${msg}`, ms }
76481
+ [provName]: { status: "failed", error: `proxy: ${msg2}`, ms }
74956
76482
  }));
74957
76483
  }
74958
76484
  }, []);
@@ -76219,14 +77745,14 @@ import {
76219
77745
  existsSync as existsSync28,
76220
77746
  mkdirSync as mkdirSync17,
76221
77747
  openSync as openSync5,
76222
- readFileSync as readFileSync26,
77748
+ readFileSync as readFileSync27,
76223
77749
  readdirSync as readdirSync6,
76224
77750
  statSync as statSync5,
76225
77751
  unlinkSync as unlinkSync10,
76226
77752
  writeFileSync as writeFileSync19
76227
77753
  } from "fs";
76228
- import { homedir as homedir32, tmpdir as tmpdir2 } from "os";
76229
- import { dirname as dirname12, join as join34 } from "path";
77754
+ import { homedir as homedir33, tmpdir as tmpdir2 } from "os";
77755
+ import { dirname as dirname12, join as join35 } from "path";
76230
77756
  import { isatty } from "tty";
76231
77757
  function releaseTerminalIsolation() {
76232
77758
  if (!restoreTerminal)
@@ -76261,14 +77787,14 @@ function isProxyAuthMode(config3) {
76261
77787
  }
76262
77788
  function managedSettingsPath() {
76263
77789
  if (isWindows2()) {
76264
- return join34(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
77790
+ return join35(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
76265
77791
  }
76266
77792
  if (process.platform === "darwin") {
76267
77793
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
76268
77794
  }
76269
77795
  return "/etc/claude-code/managed-settings.json";
76270
77796
  }
76271
- function managedSettingsForcesClaudeAi(readFile3 = readFileSync26) {
77797
+ function managedSettingsForcesClaudeAi(readFile3 = readFileSync27) {
76272
77798
  try {
76273
77799
  const raw2 = readFile3(managedSettingsPath(), "utf-8");
76274
77800
  const parsed = JSON.parse(raw2);
@@ -76282,9 +77808,9 @@ function isWindows2() {
76282
77808
  }
76283
77809
  function createStatusLineScript(tokenFilePath) {
76284
77810
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
76285
- const claudishDir = join34(homeDir, ".claudish");
77811
+ const claudishDir = join35(homeDir, ".claudish");
76286
77812
  const timestamp = Date.now();
76287
- const scriptPath = join34(claudishDir, `status-${timestamp}.js`);
77813
+ const scriptPath = join35(claudishDir, `status-${timestamp}.js`);
76288
77814
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
76289
77815
  const script = `
76290
77816
  const fs = require('fs');
@@ -76448,7 +77974,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
76448
77974
  if (!name.startsWith("tokens-") || !name.endsWith(".json"))
76449
77975
  continue;
76450
77976
  scanned++;
76451
- const full = join34(dir, name);
77977
+ const full = join35(dir, name);
76452
77978
  try {
76453
77979
  if (statSync5(full).mtimeMs >= cutoff)
76454
77980
  continue;
@@ -76465,7 +77991,7 @@ function parseSettingsArg(value) {
76465
77991
  if (value.trimStart().startsWith("{")) {
76466
77992
  return JSON.parse(value);
76467
77993
  }
76468
- return JSON.parse(readFileSync26(value, "utf-8"));
77994
+ return JSON.parse(readFileSync27(value, "utf-8"));
76469
77995
  }
76470
77996
  function parseSettingsArgSafe(value) {
76471
77997
  try {
@@ -76477,9 +78003,9 @@ function parseSettingsArgSafe(value) {
76477
78003
  }
76478
78004
  function userSettingsFileCandidates(cwd) {
76479
78005
  return [
76480
- join34(homedir32(), ".claude", "settings.json"),
76481
- join34(cwd, ".claude", "settings.json"),
76482
- join34(cwd, ".claude", "settings.local.json")
78006
+ join35(homedir33(), ".claude", "settings.json"),
78007
+ join35(cwd, ".claude", "settings.json"),
78008
+ join35(cwd, ".claude", "settings.local.json")
76483
78009
  ];
76484
78010
  }
76485
78011
  function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
@@ -76520,13 +78046,13 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
76520
78046
  }
76521
78047
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
76522
78048
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
76523
- const claudishDir = join34(homeDir, ".claudish");
78049
+ const claudishDir = join35(homeDir, ".claudish");
76524
78050
  try {
76525
78051
  mkdirSync17(claudishDir, { recursive: true });
76526
78052
  } catch {}
76527
78053
  const timestamp = Date.now();
76528
- const tempPath = join34(claudishDir, `settings-${timestamp}.json`);
76529
- const tokenFilePath = join34(claudishDir, `tokens-${port}.json`);
78054
+ const tempPath = join35(claudishDir, `settings-${timestamp}.json`);
78055
+ const tokenFilePath = join35(claudishDir, `tokens-${port}.json`);
76530
78056
  cleanupStaleTokenFiles(claudishDir);
76531
78057
  initializeTokenFile(tokenFilePath);
76532
78058
  let statusCommand;
@@ -76541,13 +78067,15 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLi
76541
78067
  const DIM4 = "\\033[2m";
76542
78068
  const RESET4 = "\\033[0m";
76543
78069
  const BOLD4 = "\\033[1m";
78070
+ const readPlanBash = `PLAN_PAIR=$(echo "$TOKENS" | grep -o '"id": *"[^"]*", *"used_pct": *[0-9]*' | sed 's/"id": *"\\([^"]*\\)", *"used_pct": *\\([0-9]*\\)/\\2 \\1/' | sort -rn | head -1); if [ -n "$PLAN_PAIR" ]; then PLAN_PCT="\${PLAN_PAIR%% *}"; PLAN_ID="\${PLAN_PAIR#* }"; case "$PLAN_PCT" in ''|*[!0-9]*) PLAN_PCT="" ;; esac; [ -n "$PLAN_PCT" ] && PLAN_DISPLAY="$PLAN_ID:$PLAN_PCT%"; fi;`;
76544
78071
  const formatTokensBash = `fmt_tok() { local n=\${1:-0}; if [ "$n" -ge 1000000 ]; then echo "$((n/1000000))M"; elif [ "$n" -ge 1000 ]; then echo "$((n/1000))k"; else echo "$n"; fi; }`;
76545
78072
  const effWinBash = `eff_win() { local w=\${1:-0}; local m=\${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-}; local a=\${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-}; case "$m" in ''|*[!0-9]*) m=${CLAUDE_CODE_DEFAULT_MAX_CONTEXT};; esac; case "$a" in ''|*[!0-9]*) a=0;; esac; case "$w" in ''|*[!0-9]*) w=0;; esac; if [ "$w" -gt 0 ]; then if [ "$m" -gt 0 ] && [ "$m" -lt "$w" ]; then w=$m; fi; if [ "$a" -gt 0 ] && [ "$a" -lt "$w" ]; then w=$a; fi; fi; echo "$w"; }`;
76546
78073
  const dirPrelude = `DIR=$(basename "$(pwd)"); [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true; `;
76547
- const readState = `CTX=-1; COST="0"; IS_FREE="false"; IS_EST="false"; PROVIDER=""; TOKEN_MODEL=""; IN_TOK=0; CTX_WIN=0; ${formatTokensBash}; ${effWinBash}; if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d '\\n\\r'); V=$(echo "$TOKENS" | grep -o '"context_left_percent": *-\\?[0-9]*' | grep -o '\\-\\?[0-9]*'); [ -n "$V" ] && CTX="$V"; V=$(echo "$TOKENS" | grep -o '"total_cost": *[0-9.]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && COST="$V"; V=$(echo "$TOKENS" | grep -o '"input_tokens": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && IN_TOK="$V"; V=$(echo "$TOKENS" | grep -o '"context_window": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && CTX_WIN="$V"; V=$(echo "$TOKENS" | grep -o '"is_free": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_FREE="$V"; V=$(echo "$TOKENS" | grep -o '"is_estimated": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_EST="$V"; V=$(echo "$TOKENS" | grep -o '"provider_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && PROVIDER="$V"; V=$(echo "$TOKENS" | grep -o '"model_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && TOKEN_MODEL="$V"; fi; if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi; MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}"; if [ -n "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi; EFF_WIN=$(eff_win $CTX_WIN); if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi; if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi`;
76548
- const segmentWithDir = `printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
76549
- const segmentNoDirWithProvider = `printf "${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$PROVIDER" "$COST_DISPLAY" "$CTX_DISPLAY"`;
76550
- const segmentNoDirNoProvider = `printf "${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$COST_DISPLAY" "$CTX_DISPLAY"`;
78074
+ const readState = `CTX=-1; COST="0"; IS_FREE="false"; IS_EST="false"; PROVIDER=""; TOKEN_MODEL=""; IN_TOK=0; CTX_WIN=0; PLAN_DISPLAY=""; ${formatTokensBash}; ${effWinBash}; if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d '\\n\\r'); V=$(echo "$TOKENS" | grep -o '"context_left_percent": *-\\?[0-9]*' | grep -o '\\-\\?[0-9]*'); [ -n "$V" ] && CTX="$V"; V=$(echo "$TOKENS" | grep -o '"total_cost": *[0-9.]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && COST="$V"; V=$(echo "$TOKENS" | grep -o '"input_tokens": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && IN_TOK="$V"; V=$(echo "$TOKENS" | grep -o '"context_window": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && CTX_WIN="$V"; V=$(echo "$TOKENS" | grep -o '"is_free": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_FREE="$V"; V=$(echo "$TOKENS" | grep -o '"is_estimated": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_EST="$V"; V=$(echo "$TOKENS" | grep -o '"provider_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && PROVIDER="$V"; V=$(echo "$TOKENS" | grep -o '"model_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && TOKEN_MODEL="$V"; ${readPlanBash} fi; if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi; MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}"; if [ -n "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi; EFF_WIN=$(eff_win $CTX_WIN); if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi; if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi`;
78075
+ const planSuffix = `if [ -n "$PLAN_DISPLAY" ]; then printf " ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4}" "$PLAN_DISPLAY"; fi`;
78076
+ const segmentWithDir = `printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
78077
+ const segmentNoDirWithProvider = `printf "${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$PROVIDER" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
78078
+ const segmentNoDirNoProvider = `printf "${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
76551
78079
  const segmentNoDir = `if [ -n "$PROVIDER" ]; then ${segmentNoDirWithProvider}; else ${segmentNoDirNoProvider}; fi`;
76552
78080
  statusCommand = userStatusLineCommand ? buildChainedStatusCommand(userStatusLineCommand, readState, segmentNoDir) : `JSON=$(cat); ${dirPrelude}${readState}; ${segmentWithDir}`;
76553
78081
  }
@@ -76797,8 +78325,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
76797
78325
  console.error("Install it from: https://claude.com/claude-code");
76798
78326
  console.error(`
76799
78327
  Or set CLAUDE_PATH to your custom installation:`);
76800
- const home = homedir32();
76801
- const localPath = isWindows2() ? join34(home, ".claude", "local", "claude.exe") : join34(home, ".claude", "local", "claude");
78328
+ const home = homedir33();
78329
+ const localPath = isWindows2() ? join35(home, ".claude", "local", "claude.exe") : join35(home, ".claude", "local", "claude");
76802
78330
  console.error(` export CLAUDE_PATH=${localPath}`);
76803
78331
  process.exit(1);
76804
78332
  }
@@ -76882,16 +78410,16 @@ async function findClaudeBinary() {
76882
78410
  return process.env.CLAUDE_PATH;
76883
78411
  }
76884
78412
  }
76885
- const home = homedir32();
76886
- const localPath = isWindows3 ? join34(home, ".claude", "local", "claude.exe") : join34(home, ".claude", "local", "claude");
78413
+ const home = homedir33();
78414
+ const localPath = isWindows3 ? join35(home, ".claude", "local", "claude.exe") : join35(home, ".claude", "local", "claude");
76887
78415
  if (existsSync28(localPath)) {
76888
78416
  return localPath;
76889
78417
  }
76890
78418
  if (isWindows3) {
76891
78419
  const windowsPaths = [
76892
- join34(home, "AppData", "Roaming", "npm", "claude.cmd"),
76893
- join34(home, ".npm-global", "claude.cmd"),
76894
- join34(home, "node_modules", ".bin", "claude.cmd")
78420
+ join35(home, "AppData", "Roaming", "npm", "claude.cmd"),
78421
+ join35(home, ".npm-global", "claude.cmd"),
78422
+ join35(home, "node_modules", ".bin", "claude.cmd")
76895
78423
  ];
76896
78424
  for (const path2 of windowsPaths) {
76897
78425
  if (existsSync28(path2)) {
@@ -76902,11 +78430,11 @@ async function findClaudeBinary() {
76902
78430
  const commonPaths = [
76903
78431
  "/usr/local/bin/claude",
76904
78432
  "/opt/homebrew/bin/claude",
76905
- join34(home, ".npm-global/bin/claude"),
76906
- join34(home, ".local/bin/claude"),
76907
- join34(home, "node_modules/.bin/claude"),
78433
+ join35(home, ".npm-global/bin/claude"),
78434
+ join35(home, ".local/bin/claude"),
78435
+ join35(home, "node_modules/.bin/claude"),
76908
78436
  "/data/data/com.termux/files/usr/bin/claude",
76909
- join34(home, "../usr/bin/claude")
78437
+ join35(home, "../usr/bin/claude")
76910
78438
  ];
76911
78439
  for (const path2 of commonPaths) {
76912
78440
  if (existsSync28(path2)) {
@@ -76970,17 +78498,17 @@ __export(exports_diag_output, {
76970
78498
  LogFileDiagOutput: () => LogFileDiagOutput
76971
78499
  });
76972
78500
  import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync18, unlinkSync as unlinkSync11, writeFileSync as writeFileSync20 } from "fs";
76973
- import { homedir as homedir33 } from "os";
76974
- import { join as join35 } from "path";
78501
+ import { homedir as homedir34 } from "os";
78502
+ import { join as join36 } from "path";
76975
78503
  function getClaudishDir() {
76976
- const dir = join35(homedir33(), ".claudish");
78504
+ const dir = join36(homedir34(), ".claudish");
76977
78505
  try {
76978
78506
  mkdirSync18(dir, { recursive: true });
76979
78507
  } catch {}
76980
78508
  return dir;
76981
78509
  }
76982
78510
  function getDiagLogPath() {
76983
- return join35(getClaudishDir(), `diag-${process.pid}.log`);
78511
+ return join36(getClaudishDir(), `diag-${process.pid}.log`);
76984
78512
  }
76985
78513
 
76986
78514
  class LogFileDiagOutput {
@@ -76995,9 +78523,9 @@ class LogFileDiagOutput {
76995
78523
  this.stream = createWriteStream3(this.logPath, { flags: "a" });
76996
78524
  this.stream.on("error", () => {});
76997
78525
  }
76998
- write(msg) {
78526
+ write(msg2) {
76999
78527
  const timestamp = new Date().toISOString();
77000
- const line = `[${timestamp}] ${msg}
78528
+ const line = `[${timestamp}] ${msg2}
77001
78529
  `;
77002
78530
  try {
77003
78531
  this.stream.write(line);
@@ -77191,9 +78719,9 @@ __export(exports_team_grid, {
77191
78719
  });
77192
78720
  import { spawn as spawn5 } from "child_process";
77193
78721
  import { execSync as execSync2 } from "child_process";
77194
- import { existsSync as existsSync29, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
78722
+ import { existsSync as existsSync29, readFileSync as readFileSync28, writeFileSync as writeFileSync21 } from "fs";
77195
78723
  import { connect as netConnect } from "net";
77196
- import { dirname as dirname13, join as join36 } from "path";
78724
+ import { dirname as dirname13, join as join37 } from "path";
77197
78725
  import { setTimeout as wait } from "timers/promises";
77198
78726
  import { fileURLToPath as fileURLToPath3 } from "url";
77199
78727
  function resolveRouteInfo(modelId) {
@@ -77287,17 +78815,17 @@ function buildPaneHeader(model, prompt, bg) {
77287
78815
  function findMagmuxBinary() {
77288
78816
  const thisFile = fileURLToPath3(import.meta.url);
77289
78817
  const thisDir = dirname13(thisFile);
77290
- const pkgRoot = join36(thisDir, "..");
78818
+ const pkgRoot = join37(thisDir, "..");
77291
78819
  const platform3 = process.platform;
77292
78820
  const arch = process.arch;
77293
- const bundledMagmux = join36(pkgRoot, "native", `magmux-${platform3}-${arch}`);
78821
+ const bundledMagmux = join37(pkgRoot, "native", `magmux-${platform3}-${arch}`);
77294
78822
  if (existsSync29(bundledMagmux))
77295
78823
  return bundledMagmux;
77296
78824
  try {
77297
78825
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
77298
78826
  let searchDir = pkgRoot;
77299
78827
  for (let i = 0;i < 5; i++) {
77300
- const candidate = join36(searchDir, "node_modules", pkgName, "bin", "magmux");
78828
+ const candidate = join37(searchDir, "node_modules", pkgName, "bin", "magmux");
77301
78829
  if (existsSync29(candidate))
77302
78830
  return candidate;
77303
78831
  const parent = dirname13(searchDir);
@@ -77404,9 +78932,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
77404
78932
  const keep = opts?.keep ?? false;
77405
78933
  const manifest = setupSession(sessionPath, models, input);
77406
78934
  const startedAt = new Date().toISOString();
77407
- const gridfilePath = join36(sessionPath, "gridfile.txt");
77408
- const prompt = readFileSync27(join36(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
77409
- const rawPrompt = readFileSync27(join36(sessionPath, "input.md"), "utf-8");
78935
+ const gridfilePath = join37(sessionPath, "gridfile.txt");
78936
+ const prompt = readFileSync28(join37(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
78937
+ const rawPrompt = readFileSync28(join37(sessionPath, "input.md"), "utf-8");
77410
78938
  const usedBannerColors = new Set;
77411
78939
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
77412
78940
  const model = manifest.models[anonId].model;
@@ -77437,7 +78965,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
77437
78965
  });
77438
78966
  const [{ results: results2 }] = await Promise.all([subscription, procExit]);
77439
78967
  const status = buildTeamStatus(manifest, startedAt, results2?.panes ?? null);
77440
- const statusPath = join36(sessionPath, "status.json");
78968
+ const statusPath = join37(sessionPath, "status.json");
77441
78969
  writeFileSync21(statusPath, JSON.stringify(status, null, 2), "utf-8");
77442
78970
  return status;
77443
78971
  }
@@ -77461,8 +78989,8 @@ var init_team_grid = __esm(() => {
77461
78989
  init_op_source();
77462
78990
  init_startup_trace();
77463
78991
  var import_dotenv3 = __toESM(require_main(), 1);
77464
- import { existsSync as existsSync30, readFileSync as readFileSync28 } from "fs";
77465
- import { join as join37, resolve as resolve5 } from "path";
78992
+ import { existsSync as existsSync30, readFileSync as readFileSync29 } from "fs";
78993
+ import { join as join38, resolve as resolve5 } from "path";
77466
78994
  import_dotenv3.config({ quiet: true });
77467
78995
  function classifyStartupKind() {
77468
78996
  const argv = process.argv.slice(2);
@@ -77709,14 +79237,14 @@ async function runCli() {
77709
79237
  if (cliConfig.team && cliConfig.team.length > 0) {
77710
79238
  let prompt = cliConfig.claudeArgs.join(" ");
77711
79239
  if (cliConfig.inputFile) {
77712
- prompt = readFileSync28(cliConfig.inputFile, "utf-8");
79240
+ prompt = readFileSync29(cliConfig.inputFile, "utf-8");
77713
79241
  }
77714
79242
  if (!prompt.trim()) {
77715
79243
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
77716
79244
  process.exit(1);
77717
79245
  }
77718
79246
  const mode = cliConfig.teamMode ?? "default";
77719
- const sessionPath = join37(process.cwd(), `.claudish-team-${Date.now()}`);
79247
+ const sessionPath = join38(process.cwd(), `.claudish-team-${Date.now()}`);
77720
79248
  if (mode === "json") {
77721
79249
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
77722
79250
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -77726,9 +79254,9 @@ async function runCli() {
77726
79254
  });
77727
79255
  const result = { ...status2, responses: {} };
77728
79256
  for (const anonId of Object.keys(status2.models)) {
77729
- const responsePath = join37(sessionPath, `response-${anonId}.md`);
79257
+ const responsePath = join38(sessionPath, `response-${anonId}.md`);
77730
79258
  try {
77731
- const raw2 = readFileSync28(responsePath, "utf-8").trim();
79259
+ const raw2 = readFileSync29(responsePath, "utf-8").trim();
77732
79260
  try {
77733
79261
  result.responses[anonId] = JSON.parse(raw2);
77734
79262
  } catch {