claudish 7.40.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 +1834 -326
  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.40.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
  `)}
@@ -37128,13 +37235,13 @@ var init_model_parser = __esm(() => {
37128
37235
  import {
37129
37236
  existsSync as existsSync15,
37130
37237
  mkdirSync as mkdirSync8,
37131
- readFileSync as readFileSync13,
37238
+ readFileSync as readFileSync14,
37132
37239
  renameSync,
37133
37240
  unlinkSync as unlinkSync5,
37134
37241
  writeFileSync as writeFileSync7
37135
37242
  } from "fs";
37136
- import { homedir as homedir21 } from "os";
37137
- import { join as join21 } from "path";
37243
+ import { homedir as homedir22 } from "os";
37244
+ import { join as join22 } from "path";
37138
37245
  function ensureDir() {
37139
37246
  if (!existsSync15(CLAUDISH_DIR)) {
37140
37247
  mkdirSync8(CLAUDISH_DIR, { recursive: true });
@@ -37144,7 +37251,7 @@ function readFromDisk() {
37144
37251
  try {
37145
37252
  if (!existsSync15(BUFFER_FILE))
37146
37253
  return [];
37147
- const raw = readFileSync13(BUFFER_FILE, "utf-8");
37254
+ const raw = readFileSync14(BUFFER_FILE, "utf-8");
37148
37255
  const parsed = JSON.parse(raw);
37149
37256
  if (!Array.isArray(parsed.events))
37150
37257
  return [];
@@ -37169,7 +37276,7 @@ function writeToDisk(events) {
37169
37276
  ensureDir();
37170
37277
  const trimmed2 = enforceSizeCap([...events]);
37171
37278
  const payload = { version: 1, events: trimmed2 };
37172
- const tmpFile = join21(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37279
+ const tmpFile = join22(CLAUDISH_DIR, `stats-buffer.tmp.${process.pid}.json`);
37173
37280
  writeFileSync7(tmpFile, JSON.stringify(payload, null, 2), "utf-8");
37174
37281
  renameSync(tmpFile, BUFFER_FILE);
37175
37282
  memoryCache = trimmed2;
@@ -37242,8 +37349,8 @@ function syncFlushOnExit() {
37242
37349
  var BUFFER_MAX_BYTES, CLAUDISH_DIR, BUFFER_FILE, memoryCache = null, eventsSinceLastFlush = 0, flushScheduled = false;
37243
37350
  var init_stats_buffer = __esm(() => {
37244
37351
  BUFFER_MAX_BYTES = 64 * 1024;
37245
- CLAUDISH_DIR = join21(homedir21(), ".claudish");
37246
- BUFFER_FILE = join21(CLAUDISH_DIR, "stats-buffer.json");
37352
+ CLAUDISH_DIR = join22(homedir22(), ".claudish");
37353
+ BUFFER_FILE = join22(CLAUDISH_DIR, "stats-buffer.json");
37247
37354
  process.on("exit", syncFlushOnExit);
37248
37355
  process.on("SIGTERM", () => {
37249
37356
  try {
@@ -38357,9 +38464,9 @@ function compareByReleaseDateDesc(a, b) {
38357
38464
  }
38358
38465
 
38359
38466
  // src/model-loader.ts
38360
- import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
38361
- import { homedir as homedir22 } from "os";
38362
- 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";
38363
38470
  function groupRecommendedModels(entries) {
38364
38471
  const byId = new Map;
38365
38472
  const categoryOrder = new Map;
@@ -38471,7 +38578,7 @@ async function getRecommendedModels(opts = {}) {
38471
38578
  }
38472
38579
  if (!forceRefresh && existsSync16(RECOMMENDED_MODELS_CACHE_PATH)) {
38473
38580
  try {
38474
- const cacheData = JSON.parse(readFileSync14(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38581
+ const cacheData = JSON.parse(readFileSync15(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38475
38582
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
38476
38583
  _cachedRecommendedModels = cacheData;
38477
38584
  return cacheData;
@@ -38487,7 +38594,7 @@ async function getRecommendedModels(opts = {}) {
38487
38594
  if (data.models && data.models.length > 0) {
38488
38595
  _cachedRecommendedModels = data;
38489
38596
  try {
38490
- const cacheDir = join22(homedir22(), ".claudish");
38597
+ const cacheDir = join23(homedir23(), ".claudish");
38491
38598
  mkdirSync9(cacheDir, { recursive: true });
38492
38599
  writeFileSync8(RECOMMENDED_MODELS_CACHE_PATH, JSON.stringify(data), "utf-8");
38493
38600
  } catch {}
@@ -38502,7 +38609,7 @@ function getRecommendedModelsSync() {
38502
38609
  return _cachedRecommendedModels;
38503
38610
  if (existsSync16(RECOMMENDED_MODELS_CACHE_PATH)) {
38504
38611
  try {
38505
- const cacheData = JSON.parse(readFileSync14(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38612
+ const cacheData = JSON.parse(readFileSync15(RECOMMENDED_MODELS_CACHE_PATH, "utf-8"));
38506
38613
  if (cacheData.models && cacheData.models.length > 0 && isFreshEnough(cacheData)) {
38507
38614
  _cachedRecommendedModels = cacheData;
38508
38615
  return cacheData;
@@ -38626,7 +38733,7 @@ var _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels =
38626
38733
  var init_model_loader = __esm(() => {
38627
38734
  init_cache_ttl();
38628
38735
  FIREBASE_RECOMMENDED_URL = `${FIREBASE_BASE_URL}?catalog=recommended`;
38629
- RECOMMENDED_MODELS_CACHE_PATH = join22(homedir22(), ".claudish", "recommended-models-cache.json");
38736
+ RECOMMENDED_MODELS_CACHE_PATH = join23(homedir23(), ".claudish", "recommended-models-cache.json");
38630
38737
  FIREBASE_SLUG_TO_PROVIDER_NAME = {
38631
38738
  openai: "openai",
38632
38739
  google: "google",
@@ -38694,6 +38801,279 @@ var init_context_window_fallback = __esm(() => {
38694
38801
  inFlight2 = new Map;
38695
38802
  });
38696
38803
 
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;
38816
+ }
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;
39075
+ });
39076
+
38697
39077
  // src/handlers/shared/stream-head-sniffer.ts
38698
39078
  function isRetryableStreamError(code, type, message) {
38699
39079
  if (RETRYABLE_ERROR_CODES.has(code))
@@ -39166,6 +39546,350 @@ var init_anthropic_sse = __esm(() => {
39166
39546
  init_logger();
39167
39547
  });
39168
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
+
39169
39893
  // src/handlers/shared/stream-parsers/gemini-sse.ts
39170
39894
  function createGeminiSseStream(_c, response, opts) {
39171
39895
  const encoder = new TextEncoder;
@@ -39976,8 +40700,8 @@ var init_openai_responses_sse = __esm(() => {
39976
40700
 
39977
40701
  // src/handlers/shared/token-tracker.ts
39978
40702
  import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
39979
- import { homedir as homedir23 } from "os";
39980
- 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";
39981
40705
  function stripProviderPrefix(name) {
39982
40706
  const at = name.indexOf("@");
39983
40707
  return at === -1 ? name : name.slice(at + 1);
@@ -40139,7 +40863,7 @@ class TokenTracker {
40139
40863
  };
40140
40864
  }
40141
40865
  const override = process.env.CLAUDISH_TOKEN_FILE;
40142
- const outPath = override || join23(homedir23(), ".claudish", `tokens-${this.port}.json`);
40866
+ const outPath = override || join24(homedir24(), ".claudish", `tokens-${this.port}.json`);
40143
40867
  mkdirSync10(dirname8(outPath), { recursive: true });
40144
40868
  writeFileSync9(outPath, JSON.stringify(data), "utf-8");
40145
40869
  } catch (e) {
@@ -40237,10 +40961,10 @@ class ComposedHandler {
40237
40961
  if (!this.getModelSupportsVision()) {
40238
40962
  const imageBlocks = [];
40239
40963
  for (let msgIdx = 0;msgIdx < messages.length; msgIdx++) {
40240
- const msg = messages[msgIdx];
40241
- if (Array.isArray(msg.content)) {
40242
- for (let partIdx = 0;partIdx < msg.content.length; partIdx++) {
40243
- 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];
40244
40968
  if (part.type === "image_url" || part.type === "image" || part.type === "document") {
40245
40969
  imageBlocks.push({ msgIdx, partIdx, block: part });
40246
40970
  }
@@ -40264,25 +40988,25 @@ class ComposedHandler {
40264
40988
  };
40265
40989
  }
40266
40990
  log(`[ComposedHandler] Vision proxy described ${descriptions.length} image(s)`);
40267
- for (const msg of messages) {
40268
- if (Array.isArray(msg.content)) {
40269
- msg.content = msg.content.filter((part) => part.type !== "image" && part.type !== "document");
40270
- if (msg.content.length === 1 && msg.content[0].type === "text") {
40271
- msg.content = msg.content[0].text;
40272
- } else if (msg.content.length === 0) {
40273
- 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 = "";
40274
40998
  }
40275
40999
  }
40276
41000
  }
40277
41001
  } else {
40278
41002
  log("[ComposedHandler] Stripping image/document blocks (vision not supported)");
40279
- for (const msg of messages) {
40280
- if (Array.isArray(msg.content)) {
40281
- msg.content = msg.content.filter((part) => part.type !== "image_url" && part.type !== "image" && part.type !== "document");
40282
- if (msg.content.length === 1 && msg.content[0].type === "text") {
40283
- msg.content = msg.content[0].text;
40284
- } else if (msg.content.length === 0) {
40285
- 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 = "";
40286
41010
  }
40287
41011
  }
40288
41012
  }
@@ -40320,7 +41044,7 @@ class ComposedHandler {
40320
41044
  const behaviorSession = this.behaviorEngine.startSession({
40321
41045
  modelId: this.bareModelName,
40322
41046
  providerName: this.provider.name,
40323
- isNativeAnthropic: /^claude[-.]/i.test(this.bareModelName) || this.provider.name === "anthropic"
41047
+ isNativeAnthropic: !this.options.forceForeignModel && (/^claude[-.]/i.test(this.bareModelName) || this.provider.name === "anthropic")
40324
41048
  });
40325
41049
  if (!behaviorSession.isNoop) {
40326
41050
  behaviorSession.applyRequest(claudeRequest, claudeRequest.tools ?? [], tools, messages);
@@ -40376,13 +41100,14 @@ class ComposedHandler {
40376
41100
  }
40377
41101
  const endpoint = this.provider.getEndpoint(this.targetModel);
40378
41102
  const headers = await this.provider.getHeaders();
40379
- headers["Content-Type"] = "application/json";
41103
+ const serialized = this.provider.serializeBody?.(requestPayload);
41104
+ headers["Content-Type"] = serialized?.contentType ?? "application/json";
40380
41105
  log(`[${this.provider.displayName}] Calling API: ${endpoint}`);
40381
41106
  const requestInit = this.provider.getRequestInit?.() || {};
40382
41107
  const doFetch = () => fetch(endpoint, {
40383
41108
  method: "POST",
40384
41109
  headers,
40385
- body: JSON.stringify(requestPayload),
41110
+ body: serialized?.body ?? JSON.stringify(requestPayload),
40386
41111
  ...requestInit
40387
41112
  });
40388
41113
  let response;
@@ -40391,9 +41116,9 @@ class ComposedHandler {
40391
41116
  } catch (error46) {
40392
41117
  const conn = classifyConnectionError(error46);
40393
41118
  if (conn) {
40394
- const msg = buildConnectionErrorMessage(conn.kind, this.provider.displayName, endpoint);
40395
- log(`[${this.provider.displayName}] ${msg} (code=${conn.code})`);
40396
- 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}`);
40397
41122
  reportError({
40398
41123
  error: error46,
40399
41124
  providerName: this.provider.name,
@@ -40425,7 +41150,7 @@ class ComposedHandler {
40425
41150
  invocation_mode: this.options.invocationMode ?? "auto-route"
40426
41151
  });
40427
41152
  } catch {}
40428
- return c.json(wrapAnthropicError(400, msg, "connection_error"), 400);
41153
+ return c.json(wrapAnthropicError(400, msg2, "connection_error"), 400);
40429
41154
  }
40430
41155
  throw error46;
40431
41156
  }
@@ -40442,12 +41167,12 @@ class ComposedHandler {
40442
41167
  try {
40443
41168
  await this.provider.forceRefreshAuth();
40444
41169
  const retryHeaders = await this.provider.getHeaders();
40445
- retryHeaders["Content-Type"] = "application/json";
41170
+ retryHeaders["Content-Type"] = serialized?.contentType ?? "application/json";
40446
41171
  const retryInit = this.provider.getRequestInit?.() || {};
40447
41172
  const retryResp = await fetch(endpoint, {
40448
41173
  method: "POST",
40449
41174
  headers: retryHeaders,
40450
- body: JSON.stringify(requestPayload),
41175
+ body: serialized?.body ?? JSON.stringify(requestPayload),
40451
41176
  ...retryInit
40452
41177
  });
40453
41178
  if (retryResp.ok) {
@@ -40627,6 +41352,48 @@ class ComposedHandler {
40627
41352
  }
40628
41353
  response = settled.response;
40629
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
+ }
40630
41397
  latencyMs = Math.round(performance.now() - startTime);
40631
41398
  const httpStatus = response.status;
40632
41399
  this.capturePlanUsage(response);
@@ -40705,6 +41472,55 @@ class ComposedHandler {
40705
41472
  response = next;
40706
41473
  }
40707
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
+ }
40708
41524
  resolveStreamFormat() {
40709
41525
  return this.provider.overrideStreamFormat?.() ?? this.explicitAdapter?.getStreamFormat() ?? this.modelAdapter?.getStreamFormat() ?? this.getAdapter().getStreamFormat();
40710
41526
  }
@@ -40790,6 +41606,23 @@ class ComposedHandler {
40790
41606
  priorInputTokens
40791
41607
  });
40792
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
+ });
40793
41626
  case "ollama-jsonl":
40794
41627
  return createOllamaJsonlStream(c, response, {
40795
41628
  modelName: this.bareModelName,
@@ -40894,10 +41727,12 @@ var init_composed_handler = __esm(() => {
40894
41727
  init_anthropic_error();
40895
41728
  init_connection_error();
40896
41729
  init_context_window_fallback();
41730
+ init_devin_stream_head_sniffer();
40897
41731
  init_openai_compat();
40898
41732
  init_quota_exhaustion();
40899
41733
  init_stream_head_sniffer();
40900
41734
  init_anthropic_sse();
41735
+ init_devin_connect();
40901
41736
  init_gemini_sse();
40902
41737
  init_ollama_jsonl();
40903
41738
  init_openai_responses_sse();
@@ -40906,6 +41741,209 @@ var init_composed_handler = __esm(() => {
40906
41741
  STREAM_RETRY_DELAYS_MS = [3000, 15000, 30000];
40907
41742
  });
40908
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
+
40909
41947
  // src/providers/model-discovery.ts
40910
41948
  function resolveBaseUrl(catalogName) {
40911
41949
  const def = getProviderByName(catalogName);
@@ -40966,6 +42004,22 @@ async function discoverProviderModels(providerName) {
40966
42004
  const descriptor = def?.modelDiscovery;
40967
42005
  if (!def || !descriptor)
40968
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
+ }
40969
42023
  const baseUrl = resolveBaseUrl(providerName);
40970
42024
  if (!baseUrl)
40971
42025
  return [];
@@ -41140,24 +42194,24 @@ async function discoverViaOpenAIModels(endpoint, headers, cacheKey) {
41140
42194
  function classifyFetchError(e, endpoint) {
41141
42195
  const name = e?.name ?? "";
41142
42196
  const code = e?.cause?.code ?? "";
41143
- const msg = e instanceof Error ? e.message : String(e);
42197
+ const msg2 = e instanceof Error ? e.message : String(e);
41144
42198
  const url2 = tryParseUrl(endpoint);
41145
42199
  const host = url2?.host ?? endpoint;
41146
42200
  const isLocal = !!url2 && /^(localhost|127\.0\.0\.1|0\.0\.0\.0|::1)$/i.test(url2.hostname);
41147
- if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg)) {
42201
+ if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg2)) {
41148
42202
  return `${host} unresponsive (>${FETCH_TIMEOUT_MS2 / 1000}s) \u2014 check if the server is overloaded`;
41149
42203
  }
41150
42204
  if (code === "ENOTFOUND" || code === "EAI_AGAIN") {
41151
42205
  return `cannot resolve host ${url2?.hostname ?? endpoint} \u2014 check the URL`;
41152
42206
  }
41153
- 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);
41154
42208
  if (isConnRefused) {
41155
42209
  if (isLocal) {
41156
42210
  return `${host} not reachable \u2014 is the server running? Press u to change URL.`;
41157
42211
  }
41158
42212
  return `${host} not reachable \u2014 check the URL or network. Press u to change.`;
41159
42213
  }
41160
- return `${host}: ${msg}`;
42214
+ return `${host}: ${msg2}`;
41161
42215
  }
41162
42216
  function tryParseUrl(s) {
41163
42217
  try {
@@ -42184,6 +43238,10 @@ function buildCredentialHint(modelName, providers) {
42184
43238
  lines.push(` Run: claudish ${hint.loginFlag} (authenticate via OAuth)`);
42185
43239
  hasOption = true;
42186
43240
  }
43241
+ if (hint.note) {
43242
+ lines.push(` ${hint.note}`);
43243
+ hasOption = true;
43244
+ }
42187
43245
  if (hint.apiKeyEnvVar) {
42188
43246
  lines.push(` Set: export ${hint.apiKeyEnvVar}=your-key (for ${provider})`);
42189
43247
  hasOption = true;
@@ -42206,6 +43264,10 @@ var init_routing_hints = __esm(() => {
42206
43264
  google: { loginFlag: "login gemini", apiKeyEnvVar: "GEMINI_API_KEY" },
42207
43265
  "gemini-codeassist": { loginFlag: "login gemini", apiKeyEnvVar: "GEMINI_API_KEY" },
42208
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
+ },
42209
43271
  openai: { apiKeyEnvVar: "OPENAI_API_KEY" },
42210
43272
  "openai-codex": { loginFlag: "login codex", apiKeyEnvVar: "OPENAI_CODEX_API_KEY" },
42211
43273
  minimax: { apiKeyEnvVar: "MINIMAX_API_KEY" },
@@ -43108,10 +44170,10 @@ var init_signal_watcher = __esm(() => {
43108
44170
 
43109
44171
  // src/channel/session-manager.ts
43110
44172
  import { spawn } from "child_process";
43111
- import { randomUUID as randomUUID4 } from "crypto";
44173
+ import { randomUUID as randomUUID5 } from "crypto";
43112
44174
  import { createWriteStream, mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
43113
- import { homedir as homedir24 } from "os";
43114
- import { join as join24 } from "path";
44175
+ import { homedir as homedir25 } from "os";
44176
+ import { join as join25 } from "path";
43115
44177
 
43116
44178
  class SessionManager {
43117
44179
  sessions = new Map;
@@ -43123,20 +44185,20 @@ class SessionManager {
43123
44185
  constructor(options) {
43124
44186
  this.maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
43125
44187
  this.scrollbackCapacity = options?.scrollbackCapacity ?? DEFAULT_SCROLLBACK;
43126
- 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");
43127
44189
  this.onStateChange = options?.onStateChange;
43128
44190
  }
43129
44191
  createSession(opts) {
43130
44192
  if (this.activeSessions >= this.maxSessions) {
43131
44193
  throw new Error(`Max sessions (${this.maxSessions}) reached`);
43132
44194
  }
43133
- const sessionId2 = randomUUID4().slice(0, 8);
44195
+ const sessionId2 = randomUUID5().slice(0, 8);
43134
44196
  const timeout = Math.min(opts.timeoutSeconds ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
43135
44197
  const startedAt = new Date().toISOString();
43136
- const sessionDir = join24(this.sessionsDir, sessionId2);
44198
+ const sessionDir = join25(this.sessionsDir, sessionId2);
43137
44199
  mkdirSync11(sessionDir, { recursive: true });
43138
44200
  if (opts.prompt) {
43139
- writeFileSync10(join24(sessionDir, "prompt.md"), opts.prompt, "utf-8");
44201
+ writeFileSync10(join25(sessionDir, "prompt.md"), opts.prompt, "utf-8");
43140
44202
  }
43141
44203
  const args = [
43142
44204
  "--model",
@@ -43170,7 +44232,7 @@ class SessionManager {
43170
44232
  });
43171
44233
  }
43172
44234
  });
43173
- const outputLogStream = createWriteStream(join24(sessionDir, "output.log"));
44235
+ const outputLogStream = createWriteStream(join25(sessionDir, "output.log"));
43174
44236
  const entry = {
43175
44237
  info: {
43176
44238
  sessionId: sessionId2,
@@ -43217,9 +44279,9 @@ class SessionManager {
43217
44279
  watcher.processExited(code);
43218
44280
  outputLogStream.end();
43219
44281
  if (entry.stderr) {
43220
- writeFileSync10(join24(sessionDir, "stderr.log"), entry.stderr, "utf-8");
44282
+ writeFileSync10(join25(sessionDir, "stderr.log"), entry.stderr, "utf-8");
43221
44283
  }
43222
- 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");
43223
44285
  this.cleanupSigint();
43224
44286
  });
43225
44287
  proc.on("error", (err) => {
@@ -45295,8 +46357,8 @@ var init_openrouter_api_format = __esm(() => {
45295
46357
  convertMessages(claudeRequest, filterIdentityFn) {
45296
46358
  const messages = super.convertMessages(claudeRequest, filterIdentityFn);
45297
46359
  if (this.modelId.includes("grok") || this.modelId.includes("x-ai")) {
45298
- const msg = "IMPORTANT: When calling tools, you MUST use the OpenAI tool_calls format with JSON. NEVER use XML format like <xai:function_call>.";
45299
- 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);
45300
46362
  }
45301
46363
  if (this.modelId.includes("gemini") || this.modelId.includes("google/")) {
45302
46364
  const geminiMsg = `CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
@@ -45616,12 +46678,12 @@ function rewriteAdvisorToolResults(payload, getAdviceFor) {
45616
46678
  if (!Array.isArray(messages))
45617
46679
  return [];
45618
46680
  const rewritten = [];
45619
- for (const msg of messages) {
45620
- if (!msg || typeof msg !== "object")
46681
+ for (const msg2 of messages) {
46682
+ if (!msg2 || typeof msg2 !== "object")
45621
46683
  continue;
45622
- if (msg.role !== "user")
46684
+ if (msg2.role !== "user")
45623
46685
  continue;
45624
- const content = msg.content;
46686
+ const content = msg2.content;
45625
46687
  if (!Array.isArray(content))
45626
46688
  continue;
45627
46689
  for (const block of content) {
@@ -45651,12 +46713,12 @@ function findPendingAdvisorToolResults(payload) {
45651
46713
  if (!Array.isArray(messages))
45652
46714
  return [];
45653
46715
  const found = [];
45654
- for (const msg of messages) {
45655
- if (!msg || typeof msg !== "object")
46716
+ for (const msg2 of messages) {
46717
+ if (!msg2 || typeof msg2 !== "object")
45656
46718
  continue;
45657
- if (msg.role !== "user")
46719
+ if (msg2.role !== "user")
45658
46720
  continue;
45659
- const content = msg.content;
46721
+ const content = msg2.content;
45660
46722
  if (!Array.isArray(content))
45661
46723
  continue;
45662
46724
  for (const block of content) {
@@ -46161,6 +47223,270 @@ var init_api_key_map = __esm(() => {
46161
47223
  };
46162
47224
  });
46163
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
+
46164
47490
  // src/adapters/ollama-api-format.ts
46165
47491
  var OllamaAPIFormat;
46166
47492
  var init_ollama_api_format = __esm(() => {
@@ -46188,11 +47514,11 @@ var init_ollama_api_format = __esm(() => {
46188
47514
  messages.push({ role: "system", content });
46189
47515
  }
46190
47516
  if (claudeRequest.messages) {
46191
- for (const msg of claudeRequest.messages) {
46192
- if (msg.role === "user") {
46193
- messages.push(this.processUserMessage(msg));
46194
- } else if (msg.role === "assistant") {
46195
- 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));
46196
47522
  }
46197
47523
  }
46198
47524
  }
@@ -46217,10 +47543,10 @@ var init_ollama_api_format = __esm(() => {
46217
47543
  supportsVision() {
46218
47544
  return false;
46219
47545
  }
46220
- processUserMessage(msg) {
46221
- if (Array.isArray(msg.content)) {
47546
+ processUserMessage(msg2) {
47547
+ if (Array.isArray(msg2.content)) {
46222
47548
  const textParts = [];
46223
- for (const block of msg.content) {
47549
+ for (const block of msg2.content) {
46224
47550
  if (block.type === "text") {
46225
47551
  textParts.push(block.text);
46226
47552
  } else if (block.type === "tool_result") {
@@ -46232,12 +47558,12 @@ var init_ollama_api_format = __esm(() => {
46232
47558
 
46233
47559
  `) };
46234
47560
  }
46235
- return { role: "user", content: msg.content };
47561
+ return { role: "user", content: msg2.content };
46236
47562
  }
46237
- processAssistantMessage(msg) {
46238
- if (Array.isArray(msg.content)) {
47563
+ processAssistantMessage(msg2) {
47564
+ if (Array.isArray(msg2.content)) {
46239
47565
  const strings = [];
46240
- for (const block of msg.content) {
47566
+ for (const block of msg2.content) {
46241
47567
  if (block.type === "text") {
46242
47568
  strings.push(block.text);
46243
47569
  } else if (block.type === "tool_use") {
@@ -46247,17 +47573,17 @@ var init_ollama_api_format = __esm(() => {
46247
47573
  return { role: "assistant", content: strings.join(`
46248
47574
  `) };
46249
47575
  }
46250
- return { role: "assistant", content: msg.content };
47576
+ return { role: "assistant", content: msg2.content };
46251
47577
  }
46252
47578
  };
46253
47579
  });
46254
47580
 
46255
47581
  // src/providers/api-key-provenance.ts
46256
- import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
46257
- import { homedir as homedir25 } from "os";
46258
- 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";
46259
47585
  function activeConfigPath() {
46260
- return activeGlobalConfigFile(join25(homedir25(), ".claudish", "config.json"));
47586
+ return activeGlobalConfigFile(join26(homedir26(), ".claudish", "config.json"));
46261
47587
  }
46262
47588
  function configLayerLabel() {
46263
47589
  return getConfigFileOverride() ? activeConfigPath() : "~/.claudish/config.json";
@@ -46336,7 +47662,7 @@ function readDotenvKey(envVars) {
46336
47662
  const dotenvPath = resolve2(".env");
46337
47663
  if (!existsSync17(dotenvPath))
46338
47664
  return null;
46339
- const parsed = import_dotenv.parse(readFileSync15(dotenvPath, "utf-8"));
47665
+ const parsed = import_dotenv.parse(readFileSync16(dotenvPath, "utf-8"));
46340
47666
  for (const v of envVars) {
46341
47667
  if (parsed[v])
46342
47668
  return parsed[v];
@@ -46351,7 +47677,7 @@ function readConfigKey(envVar) {
46351
47677
  const configPath = activeConfigPath();
46352
47678
  if (!existsSync17(configPath))
46353
47679
  return null;
46354
- const cfg = JSON.parse(readFileSync15(configPath, "utf-8"));
47680
+ const cfg = JSON.parse(readFileSync16(configPath, "utf-8"));
46355
47681
  return cfg.apiKeys?.[envVar] || null;
46356
47682
  } catch {
46357
47683
  return null;
@@ -46363,6 +47689,161 @@ var init_api_key_provenance = __esm(() => {
46363
47689
  import_dotenv = __toESM(require_main(), 1);
46364
47690
  });
46365
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
+
46366
47847
  // src/providers/transport/gemini-apikey.ts
46367
47848
  class GeminiProviderTransport {
46368
47849
  name = "gemini";
@@ -46395,7 +47876,7 @@ var init_gemini_apikey = __esm(() => {
46395
47876
  });
46396
47877
 
46397
47878
  // src/providers/transport/gemini-codeassist.ts
46398
- import { randomUUID as randomUUID5 } from "crypto";
47879
+ import { randomUUID as randomUUID6 } from "crypto";
46399
47880
  function createActivityRequestId4() {
46400
47881
  return Math.random().toString(36).substring(7);
46401
47882
  }
@@ -46504,21 +47985,21 @@ class GeminiCodeAssistProviderTransport {
46504
47985
  log(`[GeminiCodeAssist] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}, served: ${this.servedModels.join(",") || "(none)"}`);
46505
47986
  }
46506
47987
  transformPayload(payload) {
46507
- const envelope = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
46508
- this.lastEnvelope = envelope;
46509
- return envelope;
47988
+ const envelope2 = this.cachedAuth?.transformPayload ? this.cachedAuth.transformPayload(payload) : this.buildEnvelope(payload, this.modelName);
47989
+ this.lastEnvelope = envelope2;
47990
+ return envelope2;
46510
47991
  }
46511
47992
  buildEnvelope(innerPayload, model) {
46512
- const envelope = {
47993
+ const envelope2 = {
46513
47994
  model,
46514
47995
  project: this.projectId,
46515
- user_prompt_id: randomUUID5(),
47996
+ user_prompt_id: randomUUID6(),
46516
47997
  request: innerPayload
46517
47998
  };
46518
47999
  if (this.tierId && this.tierId !== "free-tier") {
46519
- envelope.enabled_credit_types = ["GOOGLE_ONE_AI"];
48000
+ envelope2.enabled_credit_types = ["GOOGLE_ONE_AI"];
46520
48001
  }
46521
- return envelope;
48002
+ return envelope2;
46522
48003
  }
46523
48004
  async enqueueRequest(fetchFn) {
46524
48005
  const queue = GeminiRequestQueue.getInstance();
@@ -46845,11 +48326,12 @@ function createHandlerForProvider(ctx) {
46845
48326
  log(`[Proxy] Handler: provider=${ctx.provider.name}, model=${ctx.modelName}`);
46846
48327
  return profile.createHandler(ctx);
46847
48328
  }
46848
- 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;
46849
48330
  var init_provider_profiles = __esm(() => {
46850
48331
  init_anthropic_api_format();
46851
48332
  init_base_api_format();
46852
48333
  init_codex_api_format();
48334
+ init_devin_api_format();
46853
48335
  init_gemini_api_format();
46854
48336
  init_litellm_api_format();
46855
48337
  init_ollama_api_format();
@@ -46862,6 +48344,7 @@ var init_provider_profiles = __esm(() => {
46862
48344
  init_runtime_providers();
46863
48345
  init_anthropic_compat();
46864
48346
  init_antigravity();
48347
+ init_devin();
46865
48348
  init_gemini_apikey();
46866
48349
  init_gemini_codeassist();
46867
48350
  init_litellm();
@@ -46907,6 +48390,19 @@ var init_provider_profiles = __esm(() => {
46907
48390
  return handler;
46908
48391
  }
46909
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
+ };
46910
48406
  openaiProfile = {
46911
48407
  createHandler(ctx) {
46912
48408
  if (requiresResponsesApi(ctx.modelName)) {
@@ -47087,6 +48583,7 @@ var init_provider_profiles = __esm(() => {
47087
48583
  gemini: geminiProfile,
47088
48584
  "gemini-codeassist": geminiCodeAssistProfile,
47089
48585
  antigravity: antigravityProfile,
48586
+ devin: devinProfile,
47090
48587
  openai: openaiProfile,
47091
48588
  "openai-codex": openaiCodexProfile,
47092
48589
  "x-ai": openaiProfile,
@@ -47825,9 +49322,9 @@ var init_poe = __esm(() => {
47825
49322
  });
47826
49323
 
47827
49324
  // src/services/pricing-cache.ts
47828
- import { existsSync as existsSync18, readFileSync as readFileSync16, statSync as statSync4 } from "fs";
47829
- import { homedir as homedir26 } from "os";
47830
- 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";
47831
49328
  function prefixMatch(modelName) {
47832
49329
  for (const [key, pricing] of pricingMap) {
47833
49330
  if (modelName.startsWith(key))
@@ -47870,7 +49367,7 @@ function loadDiskCache() {
47870
49367
  const stat2 = statSync4(CACHE_FILE);
47871
49368
  const age = Date.now() - stat2.mtimeMs;
47872
49369
  const isFresh = age < CACHE_TTL_MS3;
47873
- const raw2 = readFileSync16(CACHE_FILE, "utf-8");
49370
+ const raw2 = readFileSync17(CACHE_FILE, "utf-8");
47874
49371
  const data = JSON.parse(raw2);
47875
49372
  for (const [key, pricing] of Object.entries(data)) {
47876
49373
  pricingMap.set(key, pricing);
@@ -47886,8 +49383,8 @@ var init_pricing_cache = __esm(() => {
47886
49383
  init_logger();
47887
49384
  init_catalog_query();
47888
49385
  pricingMap = new Map;
47889
- CACHE_DIR = join26(homedir26(), ".claudish");
47890
- CACHE_FILE = join26(CACHE_DIR, "pricing-cache.json");
49386
+ CACHE_DIR = join27(homedir27(), ".claudish");
49387
+ CACHE_FILE = join27(CACHE_DIR, "pricing-cache.json");
47891
49388
  CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
47892
49389
  });
47893
49390
 
@@ -48382,20 +49879,20 @@ var init_redact = __esm(() => {
48382
49879
  });
48383
49880
 
48384
49881
  // src/team-stats.ts
48385
- import { existsSync as existsSync19, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
48386
- 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";
48387
49884
  function statsDir(sessionPath) {
48388
- return join27(sessionPath, "stats");
49885
+ return join28(sessionPath, "stats");
48389
49886
  }
48390
49887
  function tokenFileFor(sessionPath, anonId) {
48391
- return join27(statsDir(sessionPath), `${anonId}.json`);
49888
+ return join28(statsDir(sessionPath), `${anonId}.json`);
48392
49889
  }
48393
49890
  function readTokenStats(sessionPath, anonId) {
48394
49891
  const path = tokenFileFor(sessionPath, anonId);
48395
49892
  if (!existsSync19(path))
48396
49893
  return null;
48397
49894
  try {
48398
- return JSON.parse(readFileSync17(path, "utf-8"));
49895
+ return JSON.parse(readFileSync18(path, "utf-8"));
48399
49896
  } catch {
48400
49897
  return null;
48401
49898
  }
@@ -48472,10 +49969,10 @@ function renderTeamStats(sessionPath, manifest, status, opts) {
48472
49969
  if (stats?.is_free)
48473
49970
  anyFree = true;
48474
49971
  const name = model.length > nameWidth ? `${model.slice(0, nameWidth - 1)}\u2026` : model;
48475
- const bytes = m.outputSize > 0 ? fmtBytes(m.outputSize) : "";
49972
+ const bytes2 = m.outputSize > 0 ? fmtBytes(m.outputSize) : "";
48476
49973
  const tokens = stats ? `${fmtTokens(inTok)}/${outTok > 0 ? fmtTokens(outTok) : "-"}` : "";
48477
49974
  const cost = stats ? fmtCost(stats.total_cost, stats.is_free) : "";
48478
- 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());
48479
49976
  }
48480
49977
  const parts = [`${ids.length} models`];
48481
49978
  if (done)
@@ -48543,7 +50040,7 @@ ${segs.join(" \xB7 ")}`;
48543
50040
  }
48544
50041
  function writeStatusFile(sessionPath, manifest, status, opts) {
48545
50042
  try {
48546
- writeFileSync11(join27(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
50043
+ writeFileSync11(join28(sessionPath, "status.txt"), `${renderTeamStats(sessionPath, manifest, status, opts)}
48547
50044
  `, "utf-8");
48548
50045
  } catch {}
48549
50046
  }
@@ -48571,11 +50068,11 @@ import {
48571
50068
  createWriteStream as createWriteStream2,
48572
50069
  existsSync as existsSync20,
48573
50070
  mkdirSync as mkdirSync12,
48574
- readFileSync as readFileSync18,
50071
+ readFileSync as readFileSync19,
48575
50072
  readdirSync as readdirSync3,
48576
50073
  writeFileSync as writeFileSync12
48577
50074
  } from "fs";
48578
- import { join as join28, resolve as resolve3 } from "path";
50075
+ import { join as join29, resolve as resolve3 } from "path";
48579
50076
  function classifyRunOutput(opts) {
48580
50077
  const { outputSize, stdoutTail, stderr, minOutputBytes } = opts;
48581
50078
  const apiError = API_ERROR_RE.exec(stdoutTail);
@@ -48636,18 +50133,18 @@ function setupSession(sessionPath, models, input) {
48636
50133
  if (models.length === 0) {
48637
50134
  throw new Error("At least one model is required");
48638
50135
  }
48639
- if (existsSync20(join28(sessionPath, "manifest.json"))) {
50136
+ if (existsSync20(join29(sessionPath, "manifest.json"))) {
48640
50137
  throw new Error(`Session already exists at ${sessionPath}. Use a new directory path or delete the existing session first.`);
48641
50138
  }
48642
50139
  const sentinels = models.filter(isSentinelModel);
48643
50140
  if (sentinels.length > 0) {
48644
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.`);
48645
50142
  }
48646
- mkdirSync12(join28(sessionPath, "work"), { recursive: true });
48647
- mkdirSync12(join28(sessionPath, "errors"), { recursive: true });
50143
+ mkdirSync12(join29(sessionPath, "work"), { recursive: true });
50144
+ mkdirSync12(join29(sessionPath, "errors"), { recursive: true });
48648
50145
  if (input !== undefined) {
48649
- writeFileSync12(join28(sessionPath, "input.md"), input, "utf-8");
48650
- } else if (!existsSync20(join28(sessionPath, "input.md"))) {
50146
+ writeFileSync12(join29(sessionPath, "input.md"), input, "utf-8");
50147
+ } else if (!existsSync20(join29(sessionPath, "input.md"))) {
48651
50148
  throw new Error(`No input.md found at ${sessionPath} and no input provided`);
48652
50149
  }
48653
50150
  const ids = models.map((_, i) => String(i + 1).padStart(2, "0"));
@@ -48664,9 +50161,9 @@ function setupSession(sessionPath, models, input) {
48664
50161
  model: models[i],
48665
50162
  assignedAt: now
48666
50163
  };
48667
- mkdirSync12(join28(sessionPath, "work", anonId), { recursive: true });
50164
+ mkdirSync12(join29(sessionPath, "work", anonId), { recursive: true });
48668
50165
  }
48669
- 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");
48670
50167
  const status = {
48671
50168
  startedAt: now,
48672
50169
  models: Object.fromEntries(Object.keys(manifest.models).map((id) => [
@@ -48680,17 +50177,17 @@ function setupSession(sessionPath, models, input) {
48680
50177
  }
48681
50178
  ]))
48682
50179
  };
48683
- 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");
48684
50181
  return manifest;
48685
50182
  }
48686
50183
  async function runModels(sessionPath, opts = {}) {
48687
50184
  const timeoutMs = (opts.timeout ?? 300) * 1000;
48688
- const manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
48689
- const statusPath = join28(sessionPath, "status.json");
48690
- const inputPath = join28(sessionPath, "input.md");
48691
- 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");
48692
50189
  const spawnPlan = await (opts.spawnPlanner ?? prehydrateCredentialsForSpawn)(Object.values(manifest.models).map((m) => m.model));
48693
- const statusCache = JSON.parse(readFileSync18(statusPath, "utf-8"));
50190
+ const statusCache = JSON.parse(readFileSync19(statusPath, "utf-8"));
48694
50191
  function updateModelStatus(id, update) {
48695
50192
  statusCache.models[id] = { ...statusCache.models[id], ...update };
48696
50193
  writeFileSync12(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
@@ -48709,8 +50206,8 @@ async function runModels(sessionPath, opts = {}) {
48709
50206
  process.on("SIGINT", sigintHandler);
48710
50207
  const completionPromises = [];
48711
50208
  for (const [anonId, entry] of Object.entries(manifest.models)) {
48712
- const outputPath = join28(sessionPath, `response-${anonId}.md`);
48713
- const errorLogPath = join28(sessionPath, "errors", `${anonId}.log`);
50209
+ const outputPath = join29(sessionPath, `response-${anonId}.md`);
50210
+ const errorLogPath = join29(sessionPath, "errors", `${anonId}.log`);
48714
50211
  const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
48715
50212
  const args = ["--model", spawnModel, "-y", "--stdin", "--quiet", ...opts.claudeFlags ?? []];
48716
50213
  updateModelStatus(anonId, {
@@ -48859,14 +50356,14 @@ async function runModels(sessionPath, opts = {}) {
48859
50356
  const rt = runtimes.get(id);
48860
50357
  const stderr = rt?.getStderr() ?? "";
48861
50358
  const stdoutTail = rt?.getStdoutTail() ?? "";
48862
- const bytes = rt?.getByteCount() ?? 0;
48863
- 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".`;
48864
50361
  if (rt)
48865
50362
  persistErrorLog(rt.errorLogPath, `TIMEOUT: ${detail}`, stderr, stdoutTail);
48866
50363
  updateModelStatus(id, {
48867
50364
  state: "TIMEOUT",
48868
50365
  completedAt: new Date().toISOString(),
48869
- outputSize: bytes,
50366
+ outputSize: bytes2,
48870
50367
  error: rt ? {
48871
50368
  model: id,
48872
50369
  command: rt.command,
@@ -48900,23 +50397,23 @@ async function judgeResponses(sessionPath, opts = {}) {
48900
50397
  const responses = {};
48901
50398
  for (const file2 of responseFiles) {
48902
50399
  const id = file2.replace(/^response-/, "").replace(/\.md$/, "");
48903
- responses[id] = readFileSync18(join28(sessionPath, file2), "utf-8");
50400
+ responses[id] = readFileSync19(join29(sessionPath, file2), "utf-8");
48904
50401
  }
48905
- const input = readFileSync18(join28(sessionPath, "input.md"), "utf-8");
50402
+ const input = readFileSync19(join29(sessionPath, "input.md"), "utf-8");
48906
50403
  const judgePrompt = buildJudgePrompt(input, responses);
48907
- writeFileSync12(join28(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
50404
+ writeFileSync12(join29(sessionPath, "judge-prompt.md"), judgePrompt, "utf-8");
48908
50405
  const judgeModels = opts.judges ?? getDefaultJudgeModels(sessionPath);
48909
- const judgePath = join28(sessionPath, "judging");
50406
+ const judgePath = join29(sessionPath, "judging");
48910
50407
  mkdirSync12(judgePath, { recursive: true });
48911
50408
  setupSession(judgePath, judgeModels, judgePrompt);
48912
50409
  await runModels(judgePath, { claudeFlags: opts.claudeFlags });
48913
50410
  const votes = parseJudgeVotes(judgePath, Object.keys(responses));
48914
50411
  const verdict = aggregateVerdict(votes, Object.keys(responses));
48915
- writeFileSync12(join28(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
50412
+ writeFileSync12(join29(sessionPath, "verdict.md"), formatVerdict(verdict, sessionPath), "utf-8");
48916
50413
  return verdict;
48917
50414
  }
48918
50415
  function getStatus(sessionPath) {
48919
- return JSON.parse(readFileSync18(join28(sessionPath, "status.json"), "utf-8"));
50416
+ return JSON.parse(readFileSync19(join29(sessionPath, "status.json"), "utf-8"));
48920
50417
  }
48921
50418
  function fisherYatesShuffle(arr) {
48922
50419
  for (let i = arr.length - 1;i > 0; i--) {
@@ -48926,7 +50423,7 @@ function fisherYatesShuffle(arr) {
48926
50423
  return arr;
48927
50424
  }
48928
50425
  function getDefaultJudgeModels(sessionPath) {
48929
- const manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
50426
+ const manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
48930
50427
  return Object.values(manifest.models).map((e) => e.model);
48931
50428
  }
48932
50429
  function buildJudgePrompt(input, responses) {
@@ -48989,7 +50486,7 @@ function parseJudgeVotes(judgePath, responseIds) {
48989
50486
  const judgeId = file2.replace(/^response-/, "").replace(/\.md$/, "");
48990
50487
  let content;
48991
50488
  try {
48992
- content = readFileSync18(join28(judgePath, file2), "utf-8");
50489
+ content = readFileSync19(join29(judgePath, file2), "utf-8");
48993
50490
  } catch {
48994
50491
  continue;
48995
50492
  }
@@ -49041,7 +50538,7 @@ function aggregateVerdict(votes, responseIds) {
49041
50538
  function formatVerdict(verdict, sessionPath) {
49042
50539
  let manifest = null;
49043
50540
  try {
49044
- manifest = JSON.parse(readFileSync18(join28(sessionPath, "manifest.json"), "utf-8"));
50541
+ manifest = JSON.parse(readFileSync19(join29(sessionPath, "manifest.json"), "utf-8"));
49045
50542
  } catch {}
49046
50543
  let output = `# Team Verdict
49047
50544
 
@@ -49096,14 +50593,14 @@ __export(exports_mcp_server, {
49096
50593
  parseAnthropicSse: () => parseAnthropicSse,
49097
50594
  formatTeamResult: () => formatTeamResult
49098
50595
  });
49099
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync19, readdirSync as readdirSync4, writeFileSync as writeFileSync13 } from "fs";
49100
- import { homedir as homedir27 } from "os";
49101
- 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";
49102
50599
  import { fileURLToPath } from "url";
49103
50600
  async function loadAllModels(forceRefresh = false) {
49104
50601
  if (!forceRefresh && existsSync21(ALL_MODELS_CACHE_PATH2)) {
49105
50602
  try {
49106
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_CACHE_PATH2, "utf-8"));
50603
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_CACHE_PATH2, "utf-8"));
49107
50604
  const lastUpdated = new Date(cacheData.lastUpdated);
49108
50605
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
49109
50606
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -49122,7 +50619,7 @@ async function loadAllModels(forceRefresh = false) {
49122
50619
  return models;
49123
50620
  } catch {
49124
50621
  if (existsSync21(ALL_MODELS_CACHE_PATH2)) {
49125
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_CACHE_PATH2, "utf-8"));
50622
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_CACHE_PATH2, "utf-8"));
49126
50623
  return cacheData.models || [];
49127
50624
  }
49128
50625
  return [];
@@ -49704,7 +51201,7 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49704
51201
  let stderrFull = stderr_snippet || "";
49705
51202
  if (error_log_path) {
49706
51203
  try {
49707
- stderrFull = readFileSync19(error_log_path, "utf-8");
51204
+ stderrFull = readFileSync20(error_log_path, "utf-8");
49708
51205
  } catch {}
49709
51206
  }
49710
51207
  const sessionData = {};
@@ -49712,16 +51209,16 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49712
51209
  const sp = session_path;
49713
51210
  for (const file2 of ["status.json", "manifest.json", "input.md"]) {
49714
51211
  try {
49715
- sessionData[file2] = readFileSync19(join29(sp, file2), "utf-8");
51212
+ sessionData[file2] = readFileSync20(join30(sp, file2), "utf-8");
49716
51213
  } catch {}
49717
51214
  }
49718
51215
  try {
49719
- const errorDir = join29(sp, "errors");
51216
+ const errorDir = join30(sp, "errors");
49720
51217
  if (existsSync21(errorDir)) {
49721
51218
  for (const f of readdirSync4(errorDir)) {
49722
51219
  if (f.endsWith(".log")) {
49723
51220
  try {
49724
- sessionData[`errors/${f}`] = readFileSync19(join29(errorDir, f), "utf-8");
51221
+ sessionData[`errors/${f}`] = readFileSync20(join30(errorDir, f), "utf-8");
49725
51222
  } catch {}
49726
51223
  }
49727
51224
  }
@@ -49731,7 +51228,7 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49731
51228
  for (const f of readdirSync4(sp)) {
49732
51229
  if (f.startsWith("response-") && f.endsWith(".md")) {
49733
51230
  try {
49734
- const content = readFileSync19(join29(sp, f), "utf-8");
51231
+ const content = readFileSync20(join30(sp, f), "utf-8");
49735
51232
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
49736
51233
  } catch {}
49737
51234
  }
@@ -49740,9 +51237,9 @@ Use with: run_prompt(model="${results2[0].model.id}", prompt="your prompt")`;
49740
51237
  }
49741
51238
  let version2 = "unknown";
49742
51239
  try {
49743
- const pkgPath = join29(__dirname2, "../package.json");
51240
+ const pkgPath = join30(__dirname2, "../package.json");
49744
51241
  if (existsSync21(pkgPath)) {
49745
- version2 = JSON.parse(readFileSync19(pkgPath, "utf-8")).version;
51242
+ version2 = JSON.parse(readFileSync20(pkgPath, "utf-8")).version;
49746
51243
  }
49747
51244
  } catch {}
49748
51245
  const report = {
@@ -50146,8 +51643,8 @@ var init_mcp_server = __esm(() => {
50146
51643
  import_dotenv2.config({ quiet: true });
50147
51644
  __filename2 = fileURLToPath(import.meta.url);
50148
51645
  __dirname2 = dirname9(__filename2);
50149
- CLAUDISH_CACHE_DIR = join29(homedir27(), ".claudish");
50150
- 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");
50151
51648
  NEXT_STEP = {
50152
51649
  nonzero_exit: "read the evidence log, then retry or drop the model",
50153
51650
  timeout: "raise `timeout`, or pick a faster model",
@@ -50172,7 +51669,7 @@ var exports_serve_command = {};
50172
51669
  __export(exports_serve_command, {
50173
51670
  serveCommand: () => serveCommand
50174
51671
  });
50175
- import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
51672
+ import { existsSync as existsSync22, readFileSync as readFileSync21 } from "fs";
50176
51673
  function parseServeArgs(args) {
50177
51674
  const out = {};
50178
51675
  for (let i = 0;i < args.length; i++) {
@@ -50196,7 +51693,7 @@ function loadModelMap(path) {
50196
51693
  }
50197
51694
  let raw2;
50198
51695
  try {
50199
- raw2 = readFileSync20(path, "utf-8");
51696
+ raw2 = readFileSync21(path, "utf-8");
50200
51697
  } catch (e) {
50201
51698
  throw new Error(`failed to read --models file ${path}: ${e instanceof Error ? e.message : String(e)}`);
50202
51699
  }
@@ -50273,7 +51770,7 @@ var exports_behavior_command = {};
50273
51770
  __export(exports_behavior_command, {
50274
51771
  behaviorCommand: () => behaviorCommand
50275
51772
  });
50276
- 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";
50277
51774
  function severityColor(sev) {
50278
51775
  if (sev === "fix")
50279
51776
  return green(sev);
@@ -50372,7 +51869,7 @@ function setTelemetryEnabled(value) {
50372
51869
  let cfg = {};
50373
51870
  try {
50374
51871
  if (existsSync23(path)) {
50375
- const parsed = JSON.parse(readFileSync21(path, "utf-8"));
51872
+ const parsed = JSON.parse(readFileSync22(path, "utf-8"));
50376
51873
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
50377
51874
  cfg = parsed;
50378
51875
  }
@@ -50394,7 +51891,7 @@ function showTelemetry(action, json2) {
50394
51891
  try {
50395
51892
  const path = outboxPath();
50396
51893
  if (existsSync23(path)) {
50397
- pending = readFileSync21(path, "utf8").split(`
51894
+ pending = readFileSync22(path, "utf8").split(`
50398
51895
  `).filter(Boolean).length;
50399
51896
  }
50400
51897
  } catch {}
@@ -50467,6 +51964,12 @@ function describeSourceSync(p, config3) {
50467
51964
  return "oauth";
50468
51965
  if (p.catalogName === "antigravity" && hasSharedAntigravityToken())
50469
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
+ }
50470
51973
  const hasCfg = !!p.apiKeyEnvVar && !!realValue(config3.apiKeys?.[p.apiKeyEnvVar]);
50471
51974
  const hasEnv = !!p.apiKeyEnvVar && !!realValue(process.env[p.apiKeyEnvVar]);
50472
51975
  if (hasEnv && hasCfg)
@@ -50487,6 +51990,7 @@ async function describeSource(p, config3) {
50487
51990
  }
50488
51991
  var init_source = __esm(() => {
50489
51992
  init_profile_config();
51993
+ init_devin_credentials();
50490
51994
  init_antigravity_token();
50491
51995
  init_oauth_registry();
50492
51996
  init_api_key_credential();
@@ -50534,8 +52038,8 @@ function providerIsReadyForDisplay(p, config3, localLiveness) {
50534
52038
  function providerAuthCapabilities(p, config3) {
50535
52039
  const apiKeySupported = !!p.apiKeyEnvVar;
50536
52040
  const apiKeySet = apiKeySupported && (!!process.env[p.apiKeyEnvVar] || !!config3.apiKeys?.[p.apiKeyEnvVar]);
50537
- const oauthSupported = !!p.oauthSlug;
50538
- 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());
50539
52043
  return {
50540
52044
  apiKey: { supported: apiKeySupported, set: apiKeySet },
50541
52045
  oauth: { supported: oauthSupported, set: oauthSet }
@@ -50553,6 +52057,7 @@ var init_providers = __esm(() => {
50553
52057
  init_antigravity_token();
50554
52058
  init_source();
50555
52059
  init_oauth_registry();
52060
+ init_devin_credentials();
50556
52061
  init_provider_definitions();
50557
52062
  SKIP = new Set(["qwen", "native-anthropic"]);
50558
52063
  PROVIDERS = getAllProviders().filter((d) => !SKIP.has(d.name)).map(toProviderDef);
@@ -59801,18 +61306,18 @@ var require_dbcs_codec = __commonJS((exports) => {
59801
61306
  DBCSCodec.prototype.encoder = DBCSEncoder;
59802
61307
  DBCSCodec.prototype.decoder = DBCSDecoder;
59803
61308
  DBCSCodec.prototype._getDecodeTrieNode = function(addr) {
59804
- var bytes = [];
61309
+ var bytes2 = [];
59805
61310
  for (;addr > 0; addr >>>= 8) {
59806
- bytes.push(addr & 255);
61311
+ bytes2.push(addr & 255);
59807
61312
  }
59808
- if (bytes.length == 0) {
59809
- bytes.push(0);
61313
+ if (bytes2.length == 0) {
61314
+ bytes2.push(0);
59810
61315
  }
59811
61316
  var node = this.decodeTables[0];
59812
- for (var i2 = bytes.length - 1;i2 > 0; i2--) {
59813
- var val = node[bytes[i2]];
61317
+ for (var i2 = bytes2.length - 1;i2 > 0; i2--) {
61318
+ var val = node[bytes2[i2]];
59814
61319
  if (val == UNASSIGNED) {
59815
- node[bytes[i2]] = NODE_START - this.decodeTables.length;
61320
+ node[bytes2[i2]] = NODE_START - this.decodeTables.length;
59816
61321
  this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));
59817
61322
  } else if (val <= NODE_START) {
59818
61323
  node = this.decodeTables[NODE_START - val];
@@ -61863,10 +63368,10 @@ var init_RemoveFileError = __esm(() => {
61863
63368
 
61864
63369
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
61865
63370
  import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
61866
- 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";
61867
63372
  import path from "path";
61868
63373
  import os from "os";
61869
- import { randomUUID as randomUUID6 } from "crypto";
63374
+ import { randomUUID as randomUUID7 } from "crypto";
61870
63375
  function editAsync(text = "", callback, fileOptions) {
61871
63376
  const editor = new ExternalEditor(text, fileOptions);
61872
63377
  editor.runAsync((err, result) => {
@@ -61958,7 +63463,7 @@ class ExternalEditor {
61958
63463
  createTemporaryFile() {
61959
63464
  try {
61960
63465
  const baseDir = this.fileOptions.dir ?? os.tmpdir();
61961
- const id = randomUUID6();
63466
+ const id = randomUUID7();
61962
63467
  const prefix = sanitizeAffix(this.fileOptions.prefix);
61963
63468
  const postfix = sanitizeAffix(this.fileOptions.postfix);
61964
63469
  const filename = `${prefix}${id}${postfix}`;
@@ -61979,7 +63484,7 @@ class ExternalEditor {
61979
63484
  }
61980
63485
  readTemporaryFile() {
61981
63486
  try {
61982
- const tempFileBuffer = readFileSync22(this.tempFile);
63487
+ const tempFileBuffer = readFileSync23(this.tempFile);
61983
63488
  if (tempFileBuffer.length === 0) {
61984
63489
  this.text = "";
61985
63490
  } else {
@@ -62961,8 +64466,8 @@ var init_dist16 = __esm(() => {
62961
64466
  // src/auth/antigravity-oauth.ts
62962
64467
  import { spawnSync as spawnSync3 } from "child_process";
62963
64468
  import { existsSync as existsSync24, unlinkSync as unlinkSync7 } from "fs";
62964
- import { homedir as homedir28 } from "os";
62965
- import { join as join30 } from "path";
64469
+ import { homedir as homedir29 } from "os";
64470
+ import { join as join31 } from "path";
62966
64471
  async function defaultSuggestModel() {
62967
64472
  try {
62968
64473
  const tok = readSharedAntigravityToken();
@@ -63083,7 +64588,7 @@ No session detected yet. Starting the Antigravity CLI interactively \u2014
63083
64588
  async logout(deps) {
63084
64589
  deleteSharedAntigravityToken(deps);
63085
64590
  try {
63086
- const tokenFile = join30(homedir28(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
64591
+ const tokenFile = join31(homedir29(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
63087
64592
  if (existsSync24(tokenFile))
63088
64593
  unlinkSync7(tokenFile);
63089
64594
  } catch {}
@@ -64535,11 +66040,11 @@ async function probeLink(proxyUrl, link, timeoutMs) {
64535
66040
  } catch (e) {
64536
66041
  const latencyMs = Date.now() - startedAt;
64537
66042
  const name = e?.name || "";
64538
- const msg = String(e?.message || e);
64539
- if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg)) {
64540
- 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 };
64541
66046
  }
64542
- return { state: "network-error", latencyMs, errorMessage: msg };
66047
+ return { state: "network-error", latencyMs, errorMessage: msg2 };
64543
66048
  }
64544
66049
  const ttfbMs = Date.now() - startedAt;
64545
66050
  if (!response.ok) {
@@ -64568,7 +66073,7 @@ function annotateOAuthHint(result, provider, isOAuth) {
64568
66073
  return result;
64569
66074
  if (result.state === "live")
64570
66075
  return result;
64571
- 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;
64572
66077
  if (!loginCommand2)
64573
66078
  return result;
64574
66079
  if (result.httpStatus === 403)
@@ -64676,9 +66181,9 @@ function extractErrorMessage(body) {
64676
66181
  return;
64677
66182
  try {
64678
66183
  const parsed = JSON.parse(body);
64679
- const msg = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
64680
- if (typeof msg === "string" && msg.length > 0) {
64681
- 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;
64682
66187
  }
64683
66188
  } catch {}
64684
66189
  const trimmed2 = body.trim();
@@ -64894,7 +66399,7 @@ function isFailureState(state) {
64894
66399
  }
64895
66400
  var STREAM_MS_FLOOR = 50, OAUTH_PROVIDERS2, PROBE_PROMPT = "Count from one to twenty in words, one per line.", PROBE_MAX_TOKENS = 512;
64896
66401
  var init_probe_live = __esm(() => {
64897
- OAUTH_PROVIDERS2 = new Set(["vertex", "gemini-codeassist"]);
66402
+ OAUTH_PROVIDERS2 = new Set(["vertex", "gemini-codeassist", "devin"]);
64898
66403
  });
64899
66404
 
64900
66405
  // src/tui/theme.ts
@@ -67172,19 +68677,19 @@ import {
67172
68677
  copyFileSync as copyFileSync2,
67173
68678
  existsSync as existsSync25,
67174
68679
  mkdirSync as mkdirSync14,
67175
- readFileSync as readFileSync23,
68680
+ readFileSync as readFileSync24,
67176
68681
  readdirSync as readdirSync5,
67177
68682
  unlinkSync as unlinkSync8,
67178
68683
  writeFileSync as writeFileSync16
67179
68684
  } from "fs";
67180
- import { homedir as homedir29 } from "os";
67181
- 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";
67182
68687
  import { fileURLToPath as fileURLToPath2 } from "url";
67183
68688
  function getVersion3() {
67184
68689
  return VERSION;
67185
68690
  }
67186
68691
  function clearAllModelCaches() {
67187
- const cacheDir = join31(homedir29(), ".claudish");
68692
+ const cacheDir = join32(homedir30(), ".claudish");
67188
68693
  if (!existsSync25(cacheDir))
67189
68694
  return;
67190
68695
  const cachePatterns = ["pricing-cache.json", "recommended-models-cache.json"];
@@ -67193,7 +68698,7 @@ function clearAllModelCaches() {
67193
68698
  const files = readdirSync5(cacheDir);
67194
68699
  for (const file2 of files) {
67195
68700
  if (cachePatterns.includes(file2)) {
67196
- unlinkSync8(join31(cacheDir, file2));
68701
+ unlinkSync8(join32(cacheDir, file2));
67197
68702
  cleared++;
67198
68703
  }
67199
68704
  }
@@ -67603,7 +69108,7 @@ Usage: claudish --models --provider <slug>`);
67603
69108
  });
67604
69109
  config3.resolvedDefaultProvider = resolved;
67605
69110
  if (resolved.legacyAutoPromoted && !config3.quiet) {
67606
- const markerFile = join31(homedir29(), ".claudish", ".legacy-litellm-hint-shown");
69111
+ const markerFile = join32(homedir30(), ".claudish", ".legacy-litellm-hint-shown");
67607
69112
  if (!existsSync25(markerFile)) {
67608
69113
  const hint = buildLegacyHint(resolved);
67609
69114
  if (hint) {
@@ -68074,6 +69579,9 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
68074
69579
  } else if (providerName === "litellm") {
68075
69580
  formatAdapterName = "LiteLLMAPIFormat";
68076
69581
  declaredStreamFormat = "openai-sse";
69582
+ } else if (providerName === "devin") {
69583
+ formatAdapterName = "DevinAPIFormat";
69584
+ declaredStreamFormat = "connect-proto";
68077
69585
  } else {
68078
69586
  formatAdapterName = "OpenAIAPIFormat";
68079
69587
  declaredStreamFormat = "openai-sse";
@@ -68112,8 +69620,8 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
68112
69620
  console.error(`${DIM}Probing providers via live requests (may incur small cost, use --no-probe to skip)...${RESET}`);
68113
69621
  liveProxy2 = await createProxyServer2(probePort, process.env.OPENROUTER_API_KEY, undefined, false, process.env.ANTHROPIC_API_KEY, undefined, { quiet: true });
68114
69622
  } catch (e) {
68115
- const msg = e instanceof Error ? e.message : String(e);
68116
- 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}`);
68117
69625
  liveProxy2 = null;
68118
69626
  }
68119
69627
  }
@@ -68678,8 +70186,8 @@ ${h("MORE INFO")}
68678
70186
  }
68679
70187
  function printAIAgentGuide() {
68680
70188
  try {
68681
- const guidePath = join31(__dirname3, "../AI_AGENT_GUIDE.md");
68682
- const guideContent = readFileSync23(guidePath, "utf-8");
70189
+ const guidePath = join32(__dirname3, "../AI_AGENT_GUIDE.md");
70190
+ const guideContent = readFileSync24(guidePath, "utf-8");
68683
70191
  console.log(guideContent);
68684
70192
  } catch (error46) {
68685
70193
  console.error("Error reading AI Agent Guide:");
@@ -68695,10 +70203,10 @@ async function initializeClaudishSkill() {
68695
70203
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
68696
70204
  `);
68697
70205
  const cwd = process.cwd();
68698
- const claudeDir = join31(cwd, ".claude");
68699
- const skillsDir = join31(claudeDir, "skills");
68700
- const claudishSkillDir = join31(skillsDir, "claudish-usage");
68701
- 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");
68702
70210
  if (existsSync25(skillFile)) {
68703
70211
  console.log("\u2705 Claudish skill already installed at:");
68704
70212
  console.log(` ${skillFile}
@@ -68706,7 +70214,7 @@ async function initializeClaudishSkill() {
68706
70214
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
68707
70215
  return;
68708
70216
  }
68709
- const sourceSkillPath = join31(__dirname3, "../skills/claudish-usage/SKILL.md");
70217
+ const sourceSkillPath = join32(__dirname3, "../skills/claudish-usage/SKILL.md");
68710
70218
  if (!existsSync25(sourceSkillPath)) {
68711
70219
  console.error("\u274C Error: Claudish skill file not found in installation.");
68712
70220
  console.error(` Expected at: ${sourceSkillPath}`);
@@ -68809,24 +70317,24 @@ __export(exports_update_checker, {
68809
70317
  clearCache: () => clearCache,
68810
70318
  checkForUpdates: () => checkForUpdates
68811
70319
  });
68812
- import { existsSync as existsSync26, mkdirSync as mkdirSync15, readFileSync as readFileSync24, unlinkSync as unlinkSync9, writeFileSync as writeFileSync17 } from "fs";
68813
- import { homedir as homedir30, platform as platform2, tmpdir } from "os";
68814
- 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";
68815
70323
  function getCacheFilePath() {
68816
70324
  let cacheDir;
68817
70325
  if (isWindows) {
68818
- const localAppData = process.env.LOCALAPPDATA || join32(homedir30(), "AppData", "Local");
68819
- cacheDir = join32(localAppData, "claudish");
70326
+ const localAppData = process.env.LOCALAPPDATA || join33(homedir31(), "AppData", "Local");
70327
+ cacheDir = join33(localAppData, "claudish");
68820
70328
  } else {
68821
- cacheDir = join32(homedir30(), ".cache", "claudish");
70329
+ cacheDir = join33(homedir31(), ".cache", "claudish");
68822
70330
  }
68823
70331
  try {
68824
70332
  if (!existsSync26(cacheDir)) {
68825
70333
  mkdirSync15(cacheDir, { recursive: true });
68826
70334
  }
68827
- return join32(cacheDir, "update-check.json");
70335
+ return join33(cacheDir, "update-check.json");
68828
70336
  } catch {
68829
- return join32(tmpdir(), "claudish-update-check.json");
70337
+ return join33(tmpdir(), "claudish-update-check.json");
68830
70338
  }
68831
70339
  }
68832
70340
  function readCache() {
@@ -68835,7 +70343,7 @@ function readCache() {
68835
70343
  if (!existsSync26(cachePath)) {
68836
70344
  return null;
68837
70345
  }
68838
- const data = JSON.parse(readFileSync24(cachePath, "utf-8"));
70346
+ const data = JSON.parse(readFileSync25(cachePath, "utf-8"));
68839
70347
  return data;
68840
70348
  } catch {
68841
70349
  return null;
@@ -69743,15 +71251,15 @@ var init_local_liveness = __esm(() => {
69743
71251
  });
69744
71252
 
69745
71253
  // src/providers/probe-catalog.ts
69746
- import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync18 } from "fs";
69747
- import { homedir as homedir31 } from "os";
69748
- 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";
69749
71257
  function readProbeModelsCache(path2 = PROBE_MODELS_CACHE_PATH) {
69750
71258
  if (!existsSync27(path2))
69751
71259
  return null;
69752
71260
  let raw2;
69753
71261
  try {
69754
- raw2 = JSON.parse(readFileSync25(path2, "utf-8"));
71262
+ raw2 = JSON.parse(readFileSync26(path2, "utf-8"));
69755
71263
  } catch {
69756
71264
  return null;
69757
71265
  }
@@ -69880,7 +71388,7 @@ function isValidResponse(raw2) {
69880
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;
69881
71389
  var init_probe_catalog = __esm(() => {
69882
71390
  CACHE_TTL_MS4 = 60 * 60 * 1000;
69883
- PROBE_MODELS_CACHE_PATH = join33(homedir31(), ".claudish", "probe-models.json");
71391
+ PROBE_MODELS_CACHE_PATH = join34(homedir32(), ".claudish", "probe-models.json");
69884
71392
  });
69885
71393
 
69886
71394
  // src/tui/constants.ts
@@ -74327,8 +75835,8 @@ function useRouteProbe(config3) {
74327
75835
  try {
74328
75836
  proxyUrl = await ensureProbeProxy();
74329
75837
  } catch (err) {
74330
- const msg = err instanceof Error ? err.message : String(err);
74331
- 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}` })));
74332
75840
  setProbeMode("done");
74333
75841
  return;
74334
75842
  }
@@ -74682,12 +76190,12 @@ function App({ requestLogin } = {}) {
74682
76190
  }));
74683
76191
  setStatusMsg(`1Password test ok \u2192 ${note}`);
74684
76192
  } catch (err) {
74685
- const msg = err instanceof Error ? err.message : String(err);
76193
+ const msg2 = err instanceof Error ? err.message : String(err);
74686
76194
  setOpTestResults((prev) => ({
74687
76195
  ...prev,
74688
- [key]: { status: "failed", error: msg }
76196
+ [key]: { status: "failed", error: msg2 }
74689
76197
  }));
74690
- setStatusMsg(msg);
76198
+ setStatusMsg(msg2);
74691
76199
  } finally {
74692
76200
  setOpBusy(false);
74693
76201
  }
@@ -74762,14 +76270,14 @@ function App({ requestLogin } = {}) {
74762
76270
  invalidateProbeProxyHandlers();
74763
76271
  refreshConfig();
74764
76272
  } catch (testErr) {
74765
- const msg = testErr instanceof Error ? testErr.message : String(testErr);
74766
- console.error(`[claudish] 1Password add: saved but live resolve failed: ${msg}`);
74767
- 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}`);
74768
76276
  }
74769
76277
  } catch (err) {
74770
- const msg = err instanceof Error ? err.message : String(err);
74771
- console.error(`[claudish] 1Password add failed to persist: ${msg}`);
74772
- 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}`);
74773
76281
  setMode("browse");
74774
76282
  resetOpWizard();
74775
76283
  } finally {
@@ -74789,8 +76297,8 @@ function App({ requestLogin } = {}) {
74789
76297
  setOpVaults(vaults);
74790
76298
  setStatusMsg(`1Password: ${vaults.length} vault${vaults.length === 1 ? "" : "s"}.`);
74791
76299
  } catch (err) {
74792
- const msg = err instanceof Error ? err.message : String(err);
74793
- setStatusMsg(msg);
76300
+ const msg2 = err instanceof Error ? err.message : String(err);
76301
+ setStatusMsg(msg2);
74794
76302
  setMode("browse");
74795
76303
  } finally {
74796
76304
  setOpBusy(false);
@@ -74811,8 +76319,8 @@ function App({ requestLogin } = {}) {
74811
76319
  setOpItems(items);
74812
76320
  setStatusMsg(`1Password: ${items.length} item${items.length === 1 ? "" : "s"}.`);
74813
76321
  } catch (err) {
74814
- const msg = err instanceof Error ? err.message : String(err);
74815
- setStatusMsg(msg);
76322
+ const msg2 = err instanceof Error ? err.message : String(err);
76323
+ setStatusMsg(msg2);
74816
76324
  setMode("browse");
74817
76325
  } finally {
74818
76326
  setOpBusy(false);
@@ -74840,8 +76348,8 @@ function App({ requestLogin } = {}) {
74840
76348
  setOpFields(fields);
74841
76349
  setStatusMsg(`1Password: ${fields.length} field${fields.length === 1 ? "" : "s"}.`);
74842
76350
  } catch (err) {
74843
- const msg = err instanceof Error ? err.message : String(err);
74844
- setStatusMsg(msg);
76351
+ const msg2 = err instanceof Error ? err.message : String(err);
76352
+ setStatusMsg(msg2);
74845
76353
  setMode("browse");
74846
76354
  } finally {
74847
76355
  setOpBusy(false);
@@ -74857,9 +76365,9 @@ function App({ requestLogin } = {}) {
74857
76365
  setOpEnvPreview(names);
74858
76366
  setStatusMsg(`1Password environment \u2192 ${names.length} var${names.length === 1 ? "" : "s"}. Enter to save.`);
74859
76367
  } catch (err) {
74860
- const msg = err instanceof Error ? err.message : String(err);
76368
+ const msg2 = err instanceof Error ? err.message : String(err);
74861
76369
  setOpEnvPreview(null);
74862
- setStatusMsg(msg);
76370
+ setStatusMsg(msg2);
74863
76371
  } finally {
74864
76372
  setOpBusy(false);
74865
76373
  }
@@ -74967,10 +76475,10 @@ function App({ requestLogin } = {}) {
74967
76475
  }
74968
76476
  } catch (err) {
74969
76477
  const ms = Date.now() - startMs;
74970
- const msg = err instanceof Error ? err.message : String(err);
76478
+ const msg2 = err instanceof Error ? err.message : String(err);
74971
76479
  setTestResults((prev) => ({
74972
76480
  ...prev,
74973
- [provName]: { status: "failed", error: `proxy: ${msg}`, ms }
76481
+ [provName]: { status: "failed", error: `proxy: ${msg2}`, ms }
74974
76482
  }));
74975
76483
  }
74976
76484
  }, []);
@@ -76237,14 +77745,14 @@ import {
76237
77745
  existsSync as existsSync28,
76238
77746
  mkdirSync as mkdirSync17,
76239
77747
  openSync as openSync5,
76240
- readFileSync as readFileSync26,
77748
+ readFileSync as readFileSync27,
76241
77749
  readdirSync as readdirSync6,
76242
77750
  statSync as statSync5,
76243
77751
  unlinkSync as unlinkSync10,
76244
77752
  writeFileSync as writeFileSync19
76245
77753
  } from "fs";
76246
- import { homedir as homedir32, tmpdir as tmpdir2 } from "os";
76247
- 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";
76248
77756
  import { isatty } from "tty";
76249
77757
  function releaseTerminalIsolation() {
76250
77758
  if (!restoreTerminal)
@@ -76279,14 +77787,14 @@ function isProxyAuthMode(config3) {
76279
77787
  }
76280
77788
  function managedSettingsPath() {
76281
77789
  if (isWindows2()) {
76282
- return join34(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
77790
+ return join35(process.env.PROGRAMDATA || "C:\\ProgramData", "ClaudeCode", "managed-settings.json");
76283
77791
  }
76284
77792
  if (process.platform === "darwin") {
76285
77793
  return "/Library/Application Support/ClaudeCode/managed-settings.json";
76286
77794
  }
76287
77795
  return "/etc/claude-code/managed-settings.json";
76288
77796
  }
76289
- function managedSettingsForcesClaudeAi(readFile3 = readFileSync26) {
77797
+ function managedSettingsForcesClaudeAi(readFile3 = readFileSync27) {
76290
77798
  try {
76291
77799
  const raw2 = readFile3(managedSettingsPath(), "utf-8");
76292
77800
  const parsed = JSON.parse(raw2);
@@ -76300,9 +77808,9 @@ function isWindows2() {
76300
77808
  }
76301
77809
  function createStatusLineScript(tokenFilePath) {
76302
77810
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
76303
- const claudishDir = join34(homeDir, ".claudish");
77811
+ const claudishDir = join35(homeDir, ".claudish");
76304
77812
  const timestamp = Date.now();
76305
- const scriptPath = join34(claudishDir, `status-${timestamp}.js`);
77813
+ const scriptPath = join35(claudishDir, `status-${timestamp}.js`);
76306
77814
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
76307
77815
  const script = `
76308
77816
  const fs = require('fs');
@@ -76466,7 +77974,7 @@ function cleanupStaleTokenFiles(dir, now = Date.now(), maxAgeMs = STALE_TOKEN_FI
76466
77974
  if (!name.startsWith("tokens-") || !name.endsWith(".json"))
76467
77975
  continue;
76468
77976
  scanned++;
76469
- const full = join34(dir, name);
77977
+ const full = join35(dir, name);
76470
77978
  try {
76471
77979
  if (statSync5(full).mtimeMs >= cutoff)
76472
77980
  continue;
@@ -76483,7 +77991,7 @@ function parseSettingsArg(value) {
76483
77991
  if (value.trimStart().startsWith("{")) {
76484
77992
  return JSON.parse(value);
76485
77993
  }
76486
- return JSON.parse(readFileSync26(value, "utf-8"));
77994
+ return JSON.parse(readFileSync27(value, "utf-8"));
76487
77995
  }
76488
77996
  function parseSettingsArgSafe(value) {
76489
77997
  try {
@@ -76495,9 +78003,9 @@ function parseSettingsArgSafe(value) {
76495
78003
  }
76496
78004
  function userSettingsFileCandidates(cwd) {
76497
78005
  return [
76498
- join34(homedir32(), ".claude", "settings.json"),
76499
- join34(cwd, ".claude", "settings.json"),
76500
- 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")
76501
78009
  ];
76502
78010
  }
76503
78011
  function discoverUserStatusLineCommand(claudeArgs = [], cwd = process.cwd()) {
@@ -76538,13 +78046,13 @@ function buildChainedStatusCommand(userCommand, claudishBody, claudishSegment) {
76538
78046
  }
76539
78047
  function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLineCommand) {
76540
78048
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
76541
- const claudishDir = join34(homeDir, ".claudish");
78049
+ const claudishDir = join35(homeDir, ".claudish");
76542
78050
  try {
76543
78051
  mkdirSync17(claudishDir, { recursive: true });
76544
78052
  } catch {}
76545
78053
  const timestamp = Date.now();
76546
- const tempPath = join34(claudishDir, `settings-${timestamp}.json`);
76547
- const tokenFilePath = join34(claudishDir, `tokens-${port}.json`);
78054
+ const tempPath = join35(claudishDir, `settings-${timestamp}.json`);
78055
+ const tokenFilePath = join35(claudishDir, `tokens-${port}.json`);
76548
78056
  cleanupStaleTokenFiles(claudishDir);
76549
78057
  initializeTokenFile(tokenFilePath);
76550
78058
  let statusCommand;
@@ -76817,8 +78325,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
76817
78325
  console.error("Install it from: https://claude.com/claude-code");
76818
78326
  console.error(`
76819
78327
  Or set CLAUDE_PATH to your custom installation:`);
76820
- const home = homedir32();
76821
- 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");
76822
78330
  console.error(` export CLAUDE_PATH=${localPath}`);
76823
78331
  process.exit(1);
76824
78332
  }
@@ -76902,16 +78410,16 @@ async function findClaudeBinary() {
76902
78410
  return process.env.CLAUDE_PATH;
76903
78411
  }
76904
78412
  }
76905
- const home = homedir32();
76906
- 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");
76907
78415
  if (existsSync28(localPath)) {
76908
78416
  return localPath;
76909
78417
  }
76910
78418
  if (isWindows3) {
76911
78419
  const windowsPaths = [
76912
- join34(home, "AppData", "Roaming", "npm", "claude.cmd"),
76913
- join34(home, ".npm-global", "claude.cmd"),
76914
- 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")
76915
78423
  ];
76916
78424
  for (const path2 of windowsPaths) {
76917
78425
  if (existsSync28(path2)) {
@@ -76922,11 +78430,11 @@ async function findClaudeBinary() {
76922
78430
  const commonPaths = [
76923
78431
  "/usr/local/bin/claude",
76924
78432
  "/opt/homebrew/bin/claude",
76925
- join34(home, ".npm-global/bin/claude"),
76926
- join34(home, ".local/bin/claude"),
76927
- 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"),
76928
78436
  "/data/data/com.termux/files/usr/bin/claude",
76929
- join34(home, "../usr/bin/claude")
78437
+ join35(home, "../usr/bin/claude")
76930
78438
  ];
76931
78439
  for (const path2 of commonPaths) {
76932
78440
  if (existsSync28(path2)) {
@@ -76990,17 +78498,17 @@ __export(exports_diag_output, {
76990
78498
  LogFileDiagOutput: () => LogFileDiagOutput
76991
78499
  });
76992
78500
  import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync18, unlinkSync as unlinkSync11, writeFileSync as writeFileSync20 } from "fs";
76993
- import { homedir as homedir33 } from "os";
76994
- import { join as join35 } from "path";
78501
+ import { homedir as homedir34 } from "os";
78502
+ import { join as join36 } from "path";
76995
78503
  function getClaudishDir() {
76996
- const dir = join35(homedir33(), ".claudish");
78504
+ const dir = join36(homedir34(), ".claudish");
76997
78505
  try {
76998
78506
  mkdirSync18(dir, { recursive: true });
76999
78507
  } catch {}
77000
78508
  return dir;
77001
78509
  }
77002
78510
  function getDiagLogPath() {
77003
- return join35(getClaudishDir(), `diag-${process.pid}.log`);
78511
+ return join36(getClaudishDir(), `diag-${process.pid}.log`);
77004
78512
  }
77005
78513
 
77006
78514
  class LogFileDiagOutput {
@@ -77015,9 +78523,9 @@ class LogFileDiagOutput {
77015
78523
  this.stream = createWriteStream3(this.logPath, { flags: "a" });
77016
78524
  this.stream.on("error", () => {});
77017
78525
  }
77018
- write(msg) {
78526
+ write(msg2) {
77019
78527
  const timestamp = new Date().toISOString();
77020
- const line = `[${timestamp}] ${msg}
78528
+ const line = `[${timestamp}] ${msg2}
77021
78529
  `;
77022
78530
  try {
77023
78531
  this.stream.write(line);
@@ -77211,9 +78719,9 @@ __export(exports_team_grid, {
77211
78719
  });
77212
78720
  import { spawn as spawn5 } from "child_process";
77213
78721
  import { execSync as execSync2 } from "child_process";
77214
- 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";
77215
78723
  import { connect as netConnect } from "net";
77216
- import { dirname as dirname13, join as join36 } from "path";
78724
+ import { dirname as dirname13, join as join37 } from "path";
77217
78725
  import { setTimeout as wait } from "timers/promises";
77218
78726
  import { fileURLToPath as fileURLToPath3 } from "url";
77219
78727
  function resolveRouteInfo(modelId) {
@@ -77307,17 +78815,17 @@ function buildPaneHeader(model, prompt, bg) {
77307
78815
  function findMagmuxBinary() {
77308
78816
  const thisFile = fileURLToPath3(import.meta.url);
77309
78817
  const thisDir = dirname13(thisFile);
77310
- const pkgRoot = join36(thisDir, "..");
78818
+ const pkgRoot = join37(thisDir, "..");
77311
78819
  const platform3 = process.platform;
77312
78820
  const arch = process.arch;
77313
- const bundledMagmux = join36(pkgRoot, "native", `magmux-${platform3}-${arch}`);
78821
+ const bundledMagmux = join37(pkgRoot, "native", `magmux-${platform3}-${arch}`);
77314
78822
  if (existsSync29(bundledMagmux))
77315
78823
  return bundledMagmux;
77316
78824
  try {
77317
78825
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
77318
78826
  let searchDir = pkgRoot;
77319
78827
  for (let i = 0;i < 5; i++) {
77320
- const candidate = join36(searchDir, "node_modules", pkgName, "bin", "magmux");
78828
+ const candidate = join37(searchDir, "node_modules", pkgName, "bin", "magmux");
77321
78829
  if (existsSync29(candidate))
77322
78830
  return candidate;
77323
78831
  const parent = dirname13(searchDir);
@@ -77424,9 +78932,9 @@ async function runWithGrid(sessionPath, models, input, opts) {
77424
78932
  const keep = opts?.keep ?? false;
77425
78933
  const manifest = setupSession(sessionPath, models, input);
77426
78934
  const startedAt = new Date().toISOString();
77427
- const gridfilePath = join36(sessionPath, "gridfile.txt");
77428
- const prompt = readFileSync27(join36(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
77429
- 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");
77430
78938
  const usedBannerColors = new Set;
77431
78939
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
77432
78940
  const model = manifest.models[anonId].model;
@@ -77457,7 +78965,7 @@ async function runWithGrid(sessionPath, models, input, opts) {
77457
78965
  });
77458
78966
  const [{ results: results2 }] = await Promise.all([subscription, procExit]);
77459
78967
  const status = buildTeamStatus(manifest, startedAt, results2?.panes ?? null);
77460
- const statusPath = join36(sessionPath, "status.json");
78968
+ const statusPath = join37(sessionPath, "status.json");
77461
78969
  writeFileSync21(statusPath, JSON.stringify(status, null, 2), "utf-8");
77462
78970
  return status;
77463
78971
  }
@@ -77481,8 +78989,8 @@ var init_team_grid = __esm(() => {
77481
78989
  init_op_source();
77482
78990
  init_startup_trace();
77483
78991
  var import_dotenv3 = __toESM(require_main(), 1);
77484
- import { existsSync as existsSync30, readFileSync as readFileSync28 } from "fs";
77485
- 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";
77486
78994
  import_dotenv3.config({ quiet: true });
77487
78995
  function classifyStartupKind() {
77488
78996
  const argv = process.argv.slice(2);
@@ -77729,14 +79237,14 @@ async function runCli() {
77729
79237
  if (cliConfig.team && cliConfig.team.length > 0) {
77730
79238
  let prompt = cliConfig.claudeArgs.join(" ");
77731
79239
  if (cliConfig.inputFile) {
77732
- prompt = readFileSync28(cliConfig.inputFile, "utf-8");
79240
+ prompt = readFileSync29(cliConfig.inputFile, "utf-8");
77733
79241
  }
77734
79242
  if (!prompt.trim()) {
77735
79243
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
77736
79244
  process.exit(1);
77737
79245
  }
77738
79246
  const mode = cliConfig.teamMode ?? "default";
77739
- const sessionPath = join37(process.cwd(), `.claudish-team-${Date.now()}`);
79247
+ const sessionPath = join38(process.cwd(), `.claudish-team-${Date.now()}`);
77740
79248
  if (mode === "json") {
77741
79249
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
77742
79250
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -77746,9 +79254,9 @@ async function runCli() {
77746
79254
  });
77747
79255
  const result = { ...status2, responses: {} };
77748
79256
  for (const anonId of Object.keys(status2.models)) {
77749
- const responsePath = join37(sessionPath, `response-${anonId}.md`);
79257
+ const responsePath = join38(sessionPath, `response-${anonId}.md`);
77750
79258
  try {
77751
- const raw2 = readFileSync28(responsePath, "utf-8").trim();
79259
+ const raw2 = readFileSync29(responsePath, "utf-8").trim();
77752
79260
  try {
77753
79261
  result.responses[anonId] = JSON.parse(raw2);
77754
79262
  } catch {