routstrd 0.1.7 → 0.1.9

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.
@@ -28662,7 +28662,7 @@ var require_file_uri_to_path = __commonJS((exports, module) => {
28662
28662
 
28663
28663
  // ../routstr-chat/node_modules/bindings/bindings.js
28664
28664
  var require_bindings = __commonJS((exports, module) => {
28665
- var __filename = "/Users/r/projects/routstr_main/routstr-chat/node_modules/bindings/bindings.js";
28665
+ var __filename = "/Users/r/projects/routstr_main/screaming-bug/routstr-chat/node_modules/bindings/bindings.js";
28666
28666
  var fs2 = __require("fs");
28667
28667
  var path = __require("path");
28668
28668
  var fileURLToPath = require_file_uri_to_path();
@@ -29413,6 +29413,9 @@ __export(exports_dist, {
29413
29413
  BalanceManager: () => BalanceManager
29414
29414
  });
29415
29415
  import { Transform, Readable } from "stream";
29416
+ import * as fs2 from "fs";
29417
+ import * as path from "path";
29418
+ import * as os2 from "os";
29416
29419
  function isNetworkErrorMessage(message) {
29417
29420
  return message.includes("NetworkError when attempting to fetch resource") || message.includes("Failed to fetch") || message.includes("Load failed") || message.includes("ERR_TLS_CERT_ALTNAME_INVALID") || message.includes("ERR_TLS_CERT_NOT_YET_VALID") || message.includes("ERR_TLS_CERT_EXPIRED") || message.includes("UNABLE_TO_VERIFY_LEAF_SIGNATURE") || message.includes("SELF_SIGNED_CERT_IN_CHAIN");
29418
29421
  }
@@ -29475,17 +29478,49 @@ function extractResponseId(body) {
29475
29478
  return trimmed.length > 0 ? trimmed : undefined;
29476
29479
  }
29477
29480
  function extractUsageFromSSEJson(parsed, fallbackSatsCost = 0) {
29478
- if (!parsed || typeof parsed !== "object" || !parsed.usage) {
29481
+ if (!parsed || typeof parsed !== "object") {
29482
+ return null;
29483
+ }
29484
+ if (!parsed.usage && parsed.cost && typeof parsed.cost === "object") {
29485
+ const costObj = parsed.cost;
29486
+ const msats2 = costObj.total_msats ?? 0;
29487
+ const cost2 = costObj.total_usd ?? 0;
29488
+ if (msats2 === 0 && cost2 === 0)
29489
+ return null;
29490
+ return {
29491
+ promptTokens: Number(costObj.input_tokens ?? 0),
29492
+ completionTokens: Number(costObj.output_tokens ?? 0),
29493
+ totalTokens: Number((costObj.input_tokens ?? 0) + (costObj.output_tokens ?? 0)),
29494
+ cost: Number(cost2),
29495
+ satsCost: msats2 > 0 ? msats2 / 1000 : fallbackSatsCost
29496
+ };
29497
+ }
29498
+ if (!parsed.usage) {
29479
29499
  return null;
29480
29500
  }
29481
29501
  const usage = parsed.usage;
29482
29502
  const usageCost = usage.cost;
29483
- const cost = typeof usageCost === "number" ? usageCost : usageCost?.total_usd ?? parsed.metadata?.routstr?.cost?.total_usd ?? 0;
29484
- const msats = parsed.metadata?.routstr?.cost?.total_msats ?? (typeof usage.cost_sats === "number" ? usage.cost_sats * 1000 : 0);
29503
+ let cost = 0;
29504
+ let msats = 0;
29505
+ if (typeof usageCost === "number") {
29506
+ cost = usageCost;
29507
+ } else if (usageCost && typeof usageCost === "object") {
29508
+ cost = usageCost.total_usd ?? 0;
29509
+ msats = usageCost.total_msats ?? 0;
29510
+ }
29511
+ if (cost === 0) {
29512
+ cost = parsed.metadata?.routstr?.cost?.total_usd ?? 0;
29513
+ }
29514
+ if (msats === 0) {
29515
+ msats = parsed.metadata?.routstr?.cost?.total_msats ?? (typeof usage.cost_sats === "number" ? usage.cost_sats * 1000 : 0);
29516
+ }
29517
+ const promptTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
29518
+ const completionTokens = Number(usage.completion_tokens ?? usage.output_tokens ?? 0);
29519
+ const totalTokens = Number(usage.total_tokens ?? promptTokens + completionTokens);
29485
29520
  const result = {
29486
- promptTokens: Number(usage.prompt_tokens ?? 0),
29487
- completionTokens: Number(usage.completion_tokens ?? 0),
29488
- totalTokens: Number(usage.total_tokens ?? 0),
29521
+ promptTokens,
29522
+ completionTokens,
29523
+ totalTokens,
29489
29524
  cost: Number(cost ?? 0),
29490
29525
  satsCost: msats > 0 ? msats / 1000 : fallbackSatsCost
29491
29526
  };
@@ -29651,73 +29686,104 @@ async function createBunSqliteDriver(dbPath) {
29651
29686
  }
29652
29687
  function createSSEParserTransform(onUsage, onResponseId) {
29653
29688
  let buffer = "";
29654
- let usageCaptured = false;
29689
+ let capturedUsage = null;
29655
29690
  let responseIdCaptured = false;
29656
- const maybeCaptureUsageFromJson = (jsonText) => {
29691
+ const mergeUsage = (previous, next) => {
29692
+ if (!previous)
29693
+ return next;
29694
+ return {
29695
+ promptTokens: next.promptTokens > 0 ? next.promptTokens : previous.promptTokens,
29696
+ completionTokens: next.completionTokens > 0 ? next.completionTokens : previous.completionTokens,
29697
+ totalTokens: next.totalTokens > 0 ? next.totalTokens : previous.totalTokens,
29698
+ cost: next.cost > 0 ? next.cost : previous.cost,
29699
+ satsCost: next.satsCost > 0 ? next.satsCost : previous.satsCost
29700
+ };
29701
+ };
29702
+ const hasUsageChanged = (previous, next) => {
29703
+ if (!previous)
29704
+ return true;
29705
+ return previous.promptTokens !== next.promptTokens || previous.completionTokens !== next.completionTokens || previous.totalTokens !== next.totalTokens || previous.cost !== next.cost || previous.satsCost !== next.satsCost;
29706
+ };
29707
+ const inspectDataPayload = (jsonText) => {
29708
+ if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
29709
+ return;
29710
+ }
29711
+ const trimmed = jsonText.trim();
29712
+ if (!trimmed || trimmed === "[DONE]")
29713
+ return;
29714
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("["))
29715
+ return;
29657
29716
  try {
29658
- const data = JSON.parse(jsonText);
29659
- const responseId = data.id;
29660
- if (typeof responseId === "string" && responseId.trim().length > 0) {
29661
- onResponseId?.(responseId.trim());
29662
- responseIdCaptured = true;
29717
+ const data = JSON.parse(trimmed);
29718
+ if (!responseIdCaptured) {
29719
+ const responseId = data?.id;
29720
+ if (typeof responseId === "string" && responseId.trim().length > 0) {
29721
+ onResponseId?.(responseId.trim());
29722
+ responseIdCaptured = true;
29723
+ }
29663
29724
  }
29664
29725
  const usage = extractUsageFromSSEJson(data);
29665
29726
  if (usage) {
29666
- onUsage(usage);
29667
- usageCaptured = true;
29727
+ const mergedUsage = mergeUsage(capturedUsage, usage);
29728
+ if (hasUsageChanged(capturedUsage, mergedUsage)) {
29729
+ capturedUsage = mergedUsage;
29730
+ onUsage(mergedUsage);
29731
+ }
29668
29732
  }
29669
29733
  } catch {}
29670
29734
  };
29671
- const processLine = (self, line) => {
29672
- const trimmed = line.trim();
29673
- if (!trimmed) {
29735
+ const inspectEventBlock = (eventBlock) => {
29736
+ if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
29674
29737
  return;
29675
29738
  }
29676
- if (trimmed === "data: [DONE]" || trimmed === "[DONE]") {
29677
- self.push(`data: [DONE]
29678
-
29679
- `);
29680
- return;
29681
- }
29682
- if (trimmed.startsWith("data:")) {
29683
- const dataStr = trimmed.startsWith("data: ") ? trimmed.slice(6) : trimmed.slice(5).trimStart();
29684
- if (dataStr === "[DONE]") {
29685
- self.push(`data: [DONE]
29686
-
29687
- `);
29688
- return;
29739
+ const lines = eventBlock.split(/\r?\n/);
29740
+ const dataParts = [];
29741
+ for (const line of lines) {
29742
+ if (!line || line.startsWith(":"))
29743
+ continue;
29744
+ if (line.startsWith("data:")) {
29745
+ const value = line.startsWith("data: ") ? line.slice(6) : line.slice(5);
29746
+ dataParts.push(value);
29689
29747
  }
29690
- maybeCaptureUsageFromJson(dataStr);
29691
- self.push(`data: ${dataStr}
29692
-
29693
- `);
29694
- return;
29695
29748
  }
29696
- if (trimmed.startsWith("{")) {
29697
- maybeCaptureUsageFromJson(trimmed);
29698
- self.push(`data: ${trimmed}
29699
-
29749
+ if (dataParts.length === 0)
29750
+ return;
29751
+ const payload = dataParts.join(`
29700
29752
  `);
29753
+ inspectDataPayload(payload);
29754
+ };
29755
+ const emitEventBlock = (self, eventBlock) => {
29756
+ if (eventBlock.length === 0)
29701
29757
  return;
29702
- }
29703
- self.push(line + `
29758
+ inspectEventBlock(eventBlock);
29759
+ self.push(eventBlock + `
29760
+
29704
29761
  `);
29705
29762
  };
29706
29763
  return new Transform({
29707
- transform(chunk, encoding, callback) {
29764
+ transform(chunk, _encoding, callback) {
29708
29765
  buffer += chunk.toString();
29709
- const lines = buffer.split(/\r?\n/);
29710
- buffer = lines.pop() || "";
29711
- for (const line of lines) {
29712
- processLine(this, line);
29766
+ const terminator = /\r?\n\r?\n/g;
29767
+ let lastIndex = 0;
29768
+ let match;
29769
+ while ((match = terminator.exec(buffer)) !== null) {
29770
+ const block = buffer.slice(lastIndex, match.index);
29771
+ lastIndex = match.index + match[0].length;
29772
+ emitEventBlock(this, block);
29773
+ }
29774
+ if (lastIndex > 0) {
29775
+ buffer = buffer.slice(lastIndex);
29713
29776
  }
29714
29777
  callback();
29715
29778
  },
29716
29779
  flush(callback) {
29717
- if (buffer.trim()) {
29718
- processLine(this, buffer);
29780
+ if (buffer.length > 0) {
29781
+ const tail = buffer.replace(/\r?\n+$/, "");
29782
+ if (tail.length > 0) {
29783
+ emitEventBlock(this, tail);
29784
+ }
29785
+ buffer = "";
29719
29786
  }
29720
- buffer = "";
29721
29787
  callback();
29722
29788
  }
29723
29789
  });
@@ -29726,7 +29792,7 @@ async function resolveRouteRequestContext(options) {
29726
29792
  const {
29727
29793
  modelId,
29728
29794
  requestBody,
29729
- path = "/v1/chat/completions",
29795
+ path: path2 = "/v1/chat/completions",
29730
29796
  headers = {},
29731
29797
  forcedProvider,
29732
29798
  walletAdapter,
@@ -29814,17 +29880,17 @@ async function resolveRouteRequestContext(options) {
29814
29880
  client: client2,
29815
29881
  baseUrl,
29816
29882
  mintUrl,
29817
- path,
29883
+ path: path2,
29818
29884
  headers,
29819
29885
  modelId,
29820
29886
  proxiedBody
29821
29887
  };
29822
29888
  }
29823
29889
  async function routeRequests(options) {
29824
- const { client: client2, baseUrl, mintUrl, path, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
29890
+ const { client: client2, baseUrl, mintUrl, path: path2, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
29825
29891
  try {
29826
29892
  const response = await client2.routeRequest({
29827
- path,
29893
+ path: path2,
29828
29894
  method: "POST",
29829
29895
  body: proxiedBody,
29830
29896
  headers,
@@ -29845,10 +29911,10 @@ async function routeRequests(options) {
29845
29911
  }
29846
29912
  async function routeRequestsToNodeResponse(options) {
29847
29913
  const { res } = options;
29848
- const { client: client2, baseUrl, mintUrl, path, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
29914
+ const { client: client2, baseUrl, mintUrl, path: path2, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
29849
29915
  try {
29850
29916
  await client2.routeRequestToNodeResponse({
29851
- path,
29917
+ path: path2,
29852
29918
  method: "POST",
29853
29919
  body: proxiedBody,
29854
29920
  headers,
@@ -30362,10 +30428,10 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
30362
30428
  `;
30363
30429
  if (typeof window === "undefined") {
30364
30430
  try {
30365
- const fs2 = await import("fs");
30366
- const path = await import("path");
30367
- const logPath = path.join(process.cwd(), "audit.log");
30368
- fs2.appendFileSync(logPath, logLine);
30431
+ const fs22 = await import("fs");
30432
+ const path2 = await import("path");
30433
+ const logPath = path2.join(process.cwd(), "audit.log");
30434
+ fs22.appendFileSync(logPath, logLine);
30369
30435
  } catch (error) {
30370
30436
  console.error("[AuditLogger] Failed to write to file:", error);
30371
30437
  }
@@ -31428,11 +31494,14 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
31428
31494
  if (parsed.choices?.[0]?.delta?.reasoning) {
31429
31495
  result.reasoning = parsed.choices[0].delta.reasoning;
31430
31496
  }
31431
- if (parsed.usage) {
31432
- result.usage = toUsageStats(extractUsageFromSSEJson(parsed)) ?? {
31433
- total_tokens: parsed.usage.total_tokens,
31434
- prompt_tokens: parsed.usage.prompt_tokens,
31435
- completion_tokens: parsed.usage.completion_tokens
31497
+ const extractedUsage = extractUsageFromSSEJson(parsed);
31498
+ if (extractedUsage) {
31499
+ result.usage = toUsageStats(extractedUsage);
31500
+ } else if (parsed.usage) {
31501
+ result.usage = {
31502
+ total_tokens: parsed.usage.total_tokens ?? parsed.usage.input_tokens + parsed.usage.output_tokens,
31503
+ prompt_tokens: parsed.usage.prompt_tokens ?? parsed.usage.input_tokens,
31504
+ completion_tokens: parsed.usage.completion_tokens ?? parsed.usage.output_tokens
31436
31505
  };
31437
31506
  }
31438
31507
  if (parsed.id) {
@@ -31626,6 +31695,10 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
31626
31695
  const isExpired = age >= _ProviderManager.COOLDOWN_DURATION_MS;
31627
31696
  if (isExpired) {
31628
31697
  console.log(`[cleanupExpiredCooldowns:${this.instanceId}] Removing expired cooldown for ${url2} (age: ${age}ms, cooldown: ${_ProviderManager.COOLDOWN_DURATION_MS}ms)`);
31698
+ this.failedProviders.delete(url2);
31699
+ if (this.store) {
31700
+ this.store.getState().removeFailedProvider(url2);
31701
+ }
31629
31702
  }
31630
31703
  return !isExpired;
31631
31704
  });
@@ -31725,23 +31798,39 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
31725
31798
  try {
31726
31799
  const torMode = isTorContext();
31727
31800
  const disabledProviders = new Set(this.providerRegistry.getDisabledProviders());
31801
+ console.log(`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`);
31802
+ console.log(`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`);
31803
+ console.log(`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url2]) => url2)}`);
31728
31804
  const allProviders = this.providerRegistry.getAllProvidersModels();
31805
+ console.log(`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`);
31729
31806
  const candidates = [];
31730
31807
  for (const [baseUrl, models] of Object.entries(allProviders)) {
31731
- if (baseUrl === currentBaseUrl || this.failedProviders.has(baseUrl) || disabledProviders.has(baseUrl) || this.isOnCooldown(baseUrl)) {
31808
+ if (baseUrl === currentBaseUrl) {
31809
+ console.log(`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`);
31810
+ continue;
31811
+ }
31812
+ if (disabledProviders.has(baseUrl)) {
31813
+ continue;
31814
+ }
31815
+ if (this.isOnCooldown(baseUrl)) {
31732
31816
  continue;
31733
31817
  }
31734
31818
  if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
31735
31819
  continue;
31736
31820
  }
31737
31821
  const model2 = models.find((m2) => m2.id === modelId);
31738
- if (!model2)
31822
+ if (!model2) {
31739
31823
  continue;
31824
+ }
31740
31825
  const cost = model2.sats_pricing?.completion ?? 0;
31741
31826
  candidates.push({ baseUrl, model: model2, cost });
31742
31827
  }
31743
31828
  candidates.sort((a, b) => a.cost - b.cost);
31744
- return candidates.length > 0 ? candidates[0].baseUrl : null;
31829
+ if (candidates.length > 0) {
31830
+ return candidates[0].baseUrl;
31831
+ } else {
31832
+ return null;
31833
+ }
31745
31834
  } catch (error) {
31746
31835
  console.error("Error finding next best provider:", error);
31747
31836
  return null;
@@ -33417,7 +33506,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33417
33506
  }
33418
33507
  async _prepareRoutedRequest(params) {
33419
33508
  const {
33420
- path,
33509
+ path: requestPath,
33421
33510
  method,
33422
33511
  body,
33423
33512
  headers = {},
@@ -33452,7 +33541,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33452
33541
  const baseHeaders = this._buildBaseHeaders();
33453
33542
  const requestHeaders = this._withAuthHeader(baseHeaders, token);
33454
33543
  const response = await this._makeRequest({
33455
- path,
33544
+ path: requestPath,
33456
33545
  method,
33457
33546
  body: method === "GET" ? undefined : requestBody,
33458
33547
  baseUrl,
@@ -33471,7 +33560,21 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33471
33560
  let capturedUsage;
33472
33561
  let capturedResponseId;
33473
33562
  if (contentType.includes("text/event-stream") && response.body) {
33563
+ const logDir = path.join(os2.homedir(), ".routstrd", "stream-response");
33564
+ if (!fs2.existsSync(logDir)) {
33565
+ fs2.mkdirSync(logDir, { recursive: true });
33566
+ }
33567
+ const logFile = path.join(logDir, `${Date.now()}.jsonl`);
33568
+ const logStream = fs2.createWriteStream(logFile);
33474
33569
  const nodeReadable = Readable.fromWeb(response.body);
33570
+ const loggingTransform = new Transform({
33571
+ transform(chunk, encoding, callback) {
33572
+ const raw = chunk.toString();
33573
+ logStream.write(JSON.stringify({ raw, timestamp: Date.now() }) + `
33574
+ `);
33575
+ callback(null, chunk);
33576
+ }
33577
+ });
33475
33578
  const sseParser = createSSEParserTransform((usage) => {
33476
33579
  capturedUsage = usage;
33477
33580
  processedResponse.usage = usage;
@@ -33479,7 +33582,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33479
33582
  capturedResponseId = responseId;
33480
33583
  processedResponse.requestId = responseId;
33481
33584
  });
33482
- const transformed = nodeReadable.pipe(sseParser, { end: true });
33585
+ const transformed = nodeReadable.pipe(loggingTransform).pipe(sseParser, { end: true });
33483
33586
  const webStream = Readable.toWeb(transformed);
33484
33587
  processedResponse = new Response(webStream, {
33485
33588
  status: response.status,
@@ -33536,7 +33639,6 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33536
33639
  callbacks.onTokenCreated?.(this._getPendingCashuTokenAmount());
33537
33640
  const baseHeaders = this._buildBaseHeaders(headers);
33538
33641
  const requestHeaders = this._withAuthHeader(baseHeaders, token);
33539
- this.providerManager.resetFailedProviders();
33540
33642
  const providerInfo = await this.providerRegistry.getProviderInfo(baseUrl);
33541
33643
  const providerVersion = providerInfo?.version ?? "";
33542
33644
  let modelIdForRequest = selectedModel.id;
@@ -33624,9 +33726,9 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33624
33726
  }
33625
33727
  }
33626
33728
  async _makeRequest(params) {
33627
- const { path, method, body, baseUrl, token, headers } = params;
33729
+ const { path: path2, method, body, baseUrl, token, headers } = params;
33628
33730
  try {
33629
- const url2 = `${baseUrl.replace(/\/$/, "")}${path}`;
33731
+ const url2 = `${baseUrl.replace(/\/$/, "")}${path2}`;
33630
33732
  if (this.mode === "xcashu")
33631
33733
  this._log("DEBUG", "HEADERS,", headers);
33632
33734
  const response = await fetch(url2, {
@@ -33658,9 +33760,10 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33658
33760
  }
33659
33761
  async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
33660
33762
  const MAX_RETRIES_PER_PROVIDER = 2;
33661
- const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
33763
+ const { path: path2, method, body, selectedModel, baseUrl, mintUrl } = params;
33662
33764
  let tryNextProvider = false;
33663
- this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}`);
33765
+ const errorMessage = responseBody;
33766
+ this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}, errorMessage=${errorMessage}`);
33664
33767
  this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: Attempting to receive/restore token for ${baseUrl}`);
33665
33768
  if (params.token.startsWith("cashu")) {
33666
33769
  const receiveResult = await this.cashuSpender.receiveToken(params.token);
@@ -33823,7 +33926,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
33823
33926
  });
33824
33927
  return this._makeRequest({
33825
33928
  ...params,
33826
- path,
33929
+ path: path2,
33827
33930
  method,
33828
33931
  body,
33829
33932
  baseUrl: nextProvider,
@@ -34297,7 +34400,7 @@ var init_dist3 = __esm(() => {
34297
34400
  // src/daemon/index.ts
34298
34401
  init_dist3();
34299
34402
  import { createServer } from "http";
34300
- import { existsSync as existsSync6 } from "fs";
34403
+ import { existsSync as existsSync8 } from "fs";
34301
34404
 
34302
34405
  // src/utils/config.ts
34303
34406
  var HOME = process.env.HOME || process.env.USERPROFILE || "";
@@ -34316,19 +34419,19 @@ var DEFAULT_CONFIG = {
34316
34419
 
34317
34420
  // src/utils/logger.ts
34318
34421
  import { appendFile, mkdir } from "fs/promises";
34319
- import { existsSync } from "fs";
34320
- import { join as join3 } from "path";
34422
+ import { existsSync as existsSync2 } from "fs";
34423
+ import { join as join4 } from "path";
34321
34424
  var HOME2 = process.env.HOME || process.env.USERPROFILE || "";
34322
34425
  var LOG_DIR = process.env.ROUTSTRD_DIR || `${HOME2}/.routstrd`;
34323
- var LOGS_DIR2 = join3(LOG_DIR, "logs");
34426
+ var LOGS_DIR2 = join4(LOG_DIR, "logs");
34324
34427
  function getLogFileForDate(date = new Date) {
34325
34428
  const year = date.getFullYear();
34326
34429
  const month = String(date.getMonth() + 1).padStart(2, "0");
34327
34430
  const day = String(date.getDate()).padStart(2, "0");
34328
- return join3(LOGS_DIR2, `${year}-${month}-${day}.log`);
34431
+ return join4(LOGS_DIR2, `${year}-${month}-${day}.log`);
34329
34432
  }
34330
34433
  async function ensureLogDir() {
34331
- if (!existsSync(LOGS_DIR2)) {
34434
+ if (!existsSync2(LOGS_DIR2)) {
34332
34435
  await mkdir(LOGS_DIR2, { recursive: true });
34333
34436
  }
34334
34437
  }
@@ -34388,7 +34491,7 @@ function parseArgs(argv) {
34388
34491
 
34389
34492
  // src/daemon/config-store.ts
34390
34493
  import { mkdir as mkdir2 } from "fs/promises";
34391
- import { existsSync as existsSync2 } from "fs";
34494
+ import { existsSync as existsSync3 } from "fs";
34392
34495
  var REQUESTS_DIR = `${CONFIG_DIR}/requests`;
34393
34496
  async function ensureDirs() {
34394
34497
  try {
@@ -34398,7 +34501,7 @@ async function ensureDirs() {
34398
34501
  }
34399
34502
  async function loadDaemonConfig() {
34400
34503
  try {
34401
- if (existsSync2(CONFIG_FILE)) {
34504
+ if (existsSync3(CONFIG_FILE)) {
34402
34505
  const content2 = await Bun.file(CONFIG_FILE).text();
34403
34506
  return { ...DEFAULT_CONFIG, ...JSON.parse(content2) };
34404
34507
  }
@@ -34710,7 +34813,7 @@ function alphabet3(letters) {
34710
34813
  }
34711
34814
  };
34712
34815
  }
34713
- function join4(separator = "") {
34816
+ function join5(separator = "") {
34714
34817
  astr2("join", separator);
34715
34818
  return {
34716
34819
  encode: (from7) => {
@@ -34913,12 +35016,12 @@ function checksum2(len, fn) {
34913
35016
  }
34914
35017
  };
34915
35018
  }
34916
- var base163 = chain3(radix23(4), alphabet3("0123456789ABCDEF"), join4(""));
34917
- var base323 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding3(5), join4(""));
34918
- var base32nopad2 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), join4(""));
34919
- var base32hex3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding3(5), join4(""));
34920
- var base32hexnopad2 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"), join4(""));
34921
- var base32crockford3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHJKMNPQRSTVWXYZ"), join4(""), normalize3((s) => s.toUpperCase().replace(/O/g, "0").replace(/[IL]/g, "1")));
35019
+ var base163 = chain3(radix23(4), alphabet3("0123456789ABCDEF"), join5(""));
35020
+ var base323 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding3(5), join5(""));
35021
+ var base32nopad2 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), join5(""));
35022
+ var base32hex3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding3(5), join5(""));
35023
+ var base32hexnopad2 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"), join5(""));
35024
+ var base32crockford3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHJKMNPQRSTVWXYZ"), join5(""), normalize3((s) => s.toUpperCase().replace(/O/g, "0").replace(/[IL]/g, "1")));
34922
35025
  var hasBase64Builtin2 = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")();
34923
35026
  var decodeBase64Builtin2 = (s, isUrl) => {
34924
35027
  astr2("base64", s);
@@ -34936,8 +35039,8 @@ var base643 = hasBase64Builtin2 ? {
34936
35039
  decode(s) {
34937
35040
  return decodeBase64Builtin2(s, false);
34938
35041
  }
34939
- } : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding3(6), join4(""));
34940
- var base64nopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), join4(""));
35042
+ } : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding3(6), join5(""));
35043
+ var base64nopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), join5(""));
34941
35044
  var base64url3 = hasBase64Builtin2 ? {
34942
35045
  encode(b) {
34943
35046
  abytes4(b);
@@ -34946,14 +35049,14 @@ var base64url3 = hasBase64Builtin2 ? {
34946
35049
  decode(s) {
34947
35050
  return decodeBase64Builtin2(s, true);
34948
35051
  }
34949
- } : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding3(6), join4(""));
34950
- var base64urlnopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), join4(""));
34951
- var genBase583 = (abc) => chain3(radix5(58), alphabet3(abc), join4(""));
35052
+ } : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding3(6), join5(""));
35053
+ var base64urlnopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), join5(""));
35054
+ var genBase583 = (abc) => chain3(radix5(58), alphabet3(abc), join5(""));
34952
35055
  var base583 = genBase583("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
34953
35056
  var base58flickr3 = genBase583("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
34954
35057
  var base58xrp3 = genBase583("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");
34955
35058
  var createBase58check2 = (sha2565) => chain3(checksum2(4, (data) => sha2565(sha2565(data))), base583);
34956
- var BECH_ALPHABET3 = chain3(alphabet3("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join4(""));
35059
+ var BECH_ALPHABET3 = chain3(alphabet3("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join5(""));
34957
35060
  var POLYMOD_GENERATORS3 = [996825010, 642813549, 513874426, 1027748829, 705979059];
34958
35061
  function bech32Polymod3(pre) {
34959
35062
  const b = pre >> 25;
@@ -35057,7 +35160,7 @@ var hexBuiltin2 = {
35057
35160
  return Uint8Array.fromHex(s);
35058
35161
  }
35059
35162
  };
35060
- var hex3 = hasHexBuiltin3 ? hexBuiltin2 : chain3(radix23(4), alphabet3("0123456789abcdef"), join4(""), normalize3((s) => {
35163
+ var hex3 = hasHexBuiltin3 ? hexBuiltin2 : chain3(radix23(4), alphabet3("0123456789abcdef"), join5(""), normalize3((s) => {
35061
35164
  if (typeof s !== "string" || s.length % 2 !== 0)
35062
35165
  throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
35063
35166
  return s.toLowerCase();
@@ -37913,14 +38016,14 @@ class HDKey2 {
37913
38016
  }
37914
38017
  this.pubHash = hash1602(this._publicKey);
37915
38018
  }
37916
- derive(path) {
37917
- if (!/^[mM]'?/.test(path)) {
38019
+ derive(path2) {
38020
+ if (!/^[mM]'?/.test(path2)) {
37918
38021
  throw new Error('Path must start with "m" or "M"');
37919
38022
  }
37920
- if (/^[mM]'?$/.test(path)) {
38023
+ if (/^[mM]'?$/.test(path2)) {
37921
38024
  return this;
37922
38025
  }
37923
- const parts = path.replace(/^[mM]'?\//, "").split("/");
38026
+ const parts = path2.replace(/^[mM]'?\//, "").split("/");
37924
38027
  let child = this;
37925
38028
  for (const c of parts) {
37926
38029
  const m2 = /^(\d+)('?)$/.exec(c);
@@ -38279,7 +38382,7 @@ function bt(s, t) {
38279
38382
  case 2:
38280
38383
  return is(s, t, r);
38281
38384
  case 3:
38282
- return os2(s, t, r);
38385
+ return os3(s, t, r);
38283
38386
  case 4:
38284
38387
  return as2(s, t, r);
38285
38388
  case 5:
@@ -38330,7 +38433,7 @@ function is(s, t, e) {
38330
38433
  throw new Error("Byte string length exceeds data length");
38331
38434
  return { value: new Uint8Array(s.buffer, s.byteOffset + r, n), offset: r + n };
38332
38435
  }
38333
- function os2(s, t, e) {
38436
+ function os3(s, t, e) {
38334
38437
  const { value: n, offset: r } = ot2(s, t, e);
38335
38438
  if (r + n > s.byteLength)
38336
38439
  throw new Error("String length exceeds data length");
@@ -40100,25 +40203,25 @@ function createCocodClient(options = {}) {
40100
40203
  return proc;
40101
40204
  });
40102
40205
  let startPromise = null;
40103
- async function fetchJson(path, init = {}) {
40206
+ async function fetchJson(path2, init = {}) {
40104
40207
  const method = init.method || "GET";
40105
40208
  const requestInit = {
40106
40209
  ...init,
40107
40210
  unix: socketPath
40108
40211
  };
40109
- const response = await fetchImpl(`http://localhost${path}`, requestInit);
40212
+ const response = await fetchImpl(`http://localhost${path2}`, requestInit);
40110
40213
  const rawText = await response.text();
40111
40214
  if (!rawText.trim()) {
40112
- throw new CocodHttpError(response.ok ? 502 : response.status, `Empty response from cocod for ${method} ${path}`);
40215
+ throw new CocodHttpError(response.ok ? 502 : response.status, `Empty response from cocod for ${method} ${path2}`);
40113
40216
  }
40114
40217
  let data;
40115
40218
  try {
40116
40219
  data = JSON.parse(rawText);
40117
40220
  } catch {
40118
- throw new CocodHttpError(response.ok ? 502 : response.status, `Invalid JSON response from cocod for ${method} ${path}`);
40221
+ throw new CocodHttpError(response.ok ? 502 : response.status, `Invalid JSON response from cocod for ${method} ${path2}`);
40119
40222
  }
40120
40223
  if (!data || typeof data !== "object") {
40121
- throw new CocodHttpError(response.ok ? 502 : response.status, `Unexpected response shape from cocod for ${method} ${path}`);
40224
+ throw new CocodHttpError(response.ok ? 502 : response.status, `Unexpected response shape from cocod for ${method} ${path2}`);
40122
40225
  }
40123
40226
  const errorMessage = toErrorText(data.error);
40124
40227
  if (errorMessage) {
@@ -40169,13 +40272,13 @@ function createCocodClient(options = {}) {
40169
40272
  }
40170
40273
  await startPromise;
40171
40274
  }
40172
- async function callDaemon(path, init = {}) {
40275
+ async function callDaemon(path2, init = {}) {
40173
40276
  await ensureDaemonRunning();
40174
- const response = await fetchJson(path, init);
40277
+ const response = await fetchJson(path2, init);
40175
40278
  return response.output;
40176
40279
  }
40177
- function post(path, body) {
40178
- return callDaemon(path, {
40280
+ function post(path2, body) {
40281
+ return callDaemon(path2, {
40179
40282
  method: "POST",
40180
40283
  headers: { "Content-Type": "application/json" },
40181
40284
  body: JSON.stringify(body)
@@ -40293,7 +40396,7 @@ async function createWalletAdapter(options = {}) {
40293
40396
  return { success: true, amount, unit, message };
40294
40397
  } catch (error) {
40295
40398
  const errorMessage = error instanceof Error ? error.message : String(error);
40296
- logger3.error("Error in walletAdapter receiveToken:", error);
40399
+ logger3.error("Error in walletAdapter receiveToken:", errorMessage);
40297
40400
  return { success: false, amount: 0, unit: "sat", message: errorMessage };
40298
40401
  }
40299
40402
  }
@@ -40972,173 +41075,6 @@ function createDaemonRequestHandler(deps) {
40972
41075
  }
40973
41076
  return;
40974
41077
  }
40975
- if (req.method === "POST" && url2.pathname === "/providers/disable") {
40976
- try {
40977
- const bodyText = await readBody(req);
40978
- const body = bodyText ? JSON.parse(bodyText) : {};
40979
- const indices = body.indices;
40980
- if (!Array.isArray(indices)) {
40981
- res.writeHead(400, { "Content-Type": "application/json" });
40982
- res.end(JSON.stringify({
40983
- error: "Missing or invalid 'indices' field (expected number[])."
40984
- }));
40985
- return;
40986
- }
40987
- const state = deps.store.getState();
40988
- const baseUrlsList = state.baseUrlsList || [];
40989
- const disabledProviders = [
40990
- ...state.disabledProviders || []
40991
- ];
40992
- const toDisable = [];
40993
- for (const idx of indices) {
40994
- if (typeof idx === "number" && idx >= 0 && idx < baseUrlsList.length) {
40995
- const baseUrl = baseUrlsList[idx];
40996
- if (!disabledProviders.includes(baseUrl)) {
40997
- disabledProviders.push(baseUrl);
40998
- toDisable.push(baseUrl);
40999
- }
41000
- }
41001
- }
41002
- deps.store.getState().setDisabledProviders(disabledProviders);
41003
- res.writeHead(200, { "Content-Type": "application/json" });
41004
- res.end(JSON.stringify({
41005
- output: {
41006
- message: `Disabled ${toDisable.length} provider(s)`,
41007
- disabled: toDisable
41008
- }
41009
- }));
41010
- } catch (error) {
41011
- res.writeHead(500, { "Content-Type": "application/json" });
41012
- res.end(JSON.stringify({ error: String(error) }));
41013
- }
41014
- return;
41015
- }
41016
- if (req.method === "POST" && url2.pathname === "/providers/enable") {
41017
- try {
41018
- const bodyText = await readBody(req);
41019
- const body = bodyText ? JSON.parse(bodyText) : {};
41020
- const indices = body.indices;
41021
- if (!Array.isArray(indices)) {
41022
- res.writeHead(400, { "Content-Type": "application/json" });
41023
- res.end(JSON.stringify({
41024
- error: "Missing or invalid 'indices' field (expected number[])."
41025
- }));
41026
- return;
41027
- }
41028
- const state = deps.store.getState();
41029
- const baseUrlsList = state.baseUrlsList || [];
41030
- const disabledProviders = [
41031
- ...state.disabledProviders || []
41032
- ];
41033
- const toEnable = [];
41034
- for (const idx of indices) {
41035
- if (typeof idx === "number" && idx >= 0 && idx < baseUrlsList.length) {
41036
- const baseUrl = baseUrlsList[idx];
41037
- const pos = disabledProviders.indexOf(baseUrl);
41038
- if (pos !== -1) {
41039
- disabledProviders.splice(pos, 1);
41040
- toEnable.push(baseUrl);
41041
- }
41042
- }
41043
- }
41044
- deps.store.getState().setDisabledProviders(disabledProviders);
41045
- res.writeHead(200, { "Content-Type": "application/json" });
41046
- res.end(JSON.stringify({
41047
- output: {
41048
- message: `Enabled ${toEnable.length} provider(s)`,
41049
- enabled: toEnable
41050
- }
41051
- }));
41052
- } catch (error) {
41053
- res.writeHead(500, { "Content-Type": "application/json" });
41054
- res.end(JSON.stringify({ error: String(error) }));
41055
- }
41056
- return;
41057
- }
41058
- if (req.method === "GET" && url2.pathname === "/clients") {
41059
- try {
41060
- const state = deps.store.getState();
41061
- const clientIds = state.clientIds || [];
41062
- const clients = clientIds.map((c) => ({
41063
- id: c.clientId,
41064
- name: c.name,
41065
- apiKey: c.apiKey,
41066
- createdAt: c.createdAt,
41067
- lastUsed: c.lastUsed
41068
- }));
41069
- res.writeHead(200, { "Content-Type": "application/json" });
41070
- res.end(JSON.stringify({
41071
- output: {
41072
- clients,
41073
- totalCount: clients.length
41074
- }
41075
- }));
41076
- } catch (error) {
41077
- res.writeHead(500, { "Content-Type": "application/json" });
41078
- res.end(JSON.stringify({ error: String(error) }));
41079
- }
41080
- return;
41081
- }
41082
- if (req.method === "POST" && url2.pathname === "/clients/add") {
41083
- try {
41084
- const bodyText = await readBody(req);
41085
- const body = bodyText ? JSON.parse(bodyText) : {};
41086
- const name = body.name;
41087
- if (!name || typeof name !== "string" || name.trim() === "") {
41088
- res.writeHead(400, { "Content-Type": "application/json" });
41089
- res.end(JSON.stringify({
41090
- error: "Missing required 'name' field (must be a non-empty string)."
41091
- }));
41092
- return;
41093
- }
41094
- const clientId = name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
41095
- if (!clientId) {
41096
- res.writeHead(400, { "Content-Type": "application/json" });
41097
- res.end(JSON.stringify({
41098
- error: "Invalid client name. Must contain alphanumeric characters."
41099
- }));
41100
- return;
41101
- }
41102
- const state = deps.store.getState();
41103
- const existingClients = state.clientIds || [];
41104
- const existingClient = existingClients.find((c) => c.clientId === clientId);
41105
- if (existingClient) {
41106
- res.writeHead(409, { "Content-Type": "application/json" });
41107
- res.end(JSON.stringify({
41108
- error: `Client with id '${clientId}' already exists.`
41109
- }));
41110
- return;
41111
- }
41112
- const apiKey = generateApiKey();
41113
- const newClient = {
41114
- clientId,
41115
- name: name.trim(),
41116
- apiKey,
41117
- createdAt: Date.now()
41118
- };
41119
- deps.store.getState().setClientIds((prev) => [
41120
- ...prev || [],
41121
- newClient
41122
- ]);
41123
- logger3.log(`Added client '${name}' with id '${clientId}'`);
41124
- res.writeHead(200, { "Content-Type": "application/json" });
41125
- res.end(JSON.stringify({
41126
- output: {
41127
- message: `Client '${name}' added successfully`,
41128
- client: {
41129
- id: clientId,
41130
- name: name.trim(),
41131
- apiKey,
41132
- createdAt: newClient.createdAt
41133
- }
41134
- }
41135
- }));
41136
- } catch (error) {
41137
- res.writeHead(500, { "Content-Type": "application/json" });
41138
- res.end(JSON.stringify({ error: String(error) }));
41139
- }
41140
- return;
41141
- }
41142
41078
  if (req.method === "GET" && url2.pathname === "/usage") {
41143
41079
  try {
41144
41080
  const output4 = await deps.usageTrackingDriver.list({
@@ -41260,16 +41196,16 @@ function createDaemonRequestHandler(deps) {
41260
41196
  }
41261
41197
 
41262
41198
  // src/integrations/opencode.ts
41263
- import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
41264
- import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
41265
- import { dirname as dirname3 } from "path";
41199
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
41200
+ import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
41201
+ import { dirname as dirname4 } from "path";
41266
41202
 
41267
41203
  // src/integrations/registry.ts
41268
41204
  import { randomBytes as randomBytes6 } from "crypto";
41269
- import { join as join5 } from "path";
41205
+ import { join as join6 } from "path";
41270
41206
 
41271
41207
  // src/integrations/pi.ts
41272
- import { existsSync as existsSync3, mkdirSync } from "fs";
41208
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
41273
41209
  import { readFile, writeFile } from "fs/promises";
41274
41210
  import { dirname } from "path";
41275
41211
  async function installPiIntegration(config, store, integrationConfig) {
@@ -41299,7 +41235,7 @@ Installing routstr models in pi models.json...`);
41299
41235
  }
41300
41236
  let piConfig = {};
41301
41237
  try {
41302
- if (existsSync3(configPath)) {
41238
+ if (existsSync4(configPath)) {
41303
41239
  const content2 = await readFile(configPath, "utf-8");
41304
41240
  piConfig = JSON.parse(content2);
41305
41241
  }
@@ -41310,7 +41246,7 @@ Installing routstr models in pi models.json...`);
41310
41246
  piConfig.providers = {};
41311
41247
  }
41312
41248
  try {
41313
- mkdirSync(dirname(configPath), { recursive: true });
41249
+ mkdirSync2(dirname(configPath), { recursive: true });
41314
41250
  const response = await fetch(`http://localhost:${port}/models`);
41315
41251
  const data = await response.json();
41316
41252
  const models = data.output?.models || [];
@@ -41335,7 +41271,7 @@ Installing routstr models in pi models.json...`);
41335
41271
  }
41336
41272
 
41337
41273
  // src/integrations/openclaw.ts
41338
- import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
41274
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
41339
41275
  import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
41340
41276
  import { dirname as dirname2 } from "path";
41341
41277
  var OPENCLAW_PROVIDER_ID = "routstr";
@@ -41367,7 +41303,7 @@ Installing routstr models in openclaw.json...`);
41367
41303
  }
41368
41304
  let openclawConfig = {};
41369
41305
  try {
41370
- if (existsSync4(configPath)) {
41306
+ if (existsSync5(configPath)) {
41371
41307
  const content2 = await readFile2(configPath, "utf-8");
41372
41308
  openclawConfig = JSON.parse(content2);
41373
41309
  }
@@ -41387,7 +41323,7 @@ Installing routstr models in openclaw.json...`);
41387
41323
  openclawConfig.agents.defaults = {};
41388
41324
  }
41389
41325
  try {
41390
- mkdirSync2(dirname2(configPath), { recursive: true });
41326
+ mkdirSync3(dirname2(configPath), { recursive: true });
41391
41327
  const response = await fetch(`http://localhost:${port}/models`);
41392
41328
  const data = await response.json();
41393
41329
  const models = data.output?.models || [];
@@ -41427,6 +41363,60 @@ Installing routstr models in openclaw.json...`);
41427
41363
  }
41428
41364
  }
41429
41365
 
41366
+ // src/integrations/claudecode.ts
41367
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
41368
+ import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
41369
+ import { dirname as dirname3 } from "path";
41370
+ async function installClaudeCodeIntegration(config, store, integrationConfig) {
41371
+ const { clientId, name, configPath } = integrationConfig;
41372
+ logger3.log(`
41373
+ Installing routstr configuration in ${configPath}...`);
41374
+ const port = config.port || 8008;
41375
+ const state = store.getState();
41376
+ const existingClient = (state.clientIds || []).find((c) => c.clientId === clientId);
41377
+ let apiKey;
41378
+ if (existingClient) {
41379
+ apiKey = existingClient.apiKey;
41380
+ logger3.log(`Using existing API key for ${name}`);
41381
+ } else {
41382
+ apiKey = generateApiKey2();
41383
+ store.getState().setClientIds((prev) => [
41384
+ ...prev || [],
41385
+ {
41386
+ clientId,
41387
+ name,
41388
+ apiKey,
41389
+ createdAt: Date.now()
41390
+ }
41391
+ ]);
41392
+ logger3.log(`Created new API key for ${name}`);
41393
+ }
41394
+ let settings = {};
41395
+ try {
41396
+ if (existsSync6(configPath)) {
41397
+ const content2 = await readFile3(configPath, "utf-8");
41398
+ settings = JSON.parse(content2);
41399
+ }
41400
+ } catch (error) {
41401
+ logger3.error(`Error reading ${configPath}, creating new one.`);
41402
+ }
41403
+ if (!settings.env) {
41404
+ settings.env = {};
41405
+ }
41406
+ settings.env["ANTHROPIC_AUTH_TOKEN"] = apiKey;
41407
+ settings.env["ANTHROPIC_BASE_URL"] = `http://localhost:${port}`;
41408
+ settings.env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = "gpt-5.4";
41409
+ settings.env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = "claude-opus-4.7";
41410
+ settings.env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = "minimax-m2.7";
41411
+ try {
41412
+ mkdirSync4(dirname3(configPath), { recursive: true });
41413
+ await writeFile3(configPath, JSON.stringify(settings, null, 2));
41414
+ logger3.log(`Successfully updated ${configPath} with routstr settings.`);
41415
+ } catch (error) {
41416
+ logger3.error(`Failed to write to ${configPath}:`, error);
41417
+ }
41418
+ }
41419
+
41430
41420
  // src/integrations/registry.ts
41431
41421
  function generateApiKey2() {
41432
41422
  const bytes4 = randomBytes6(24);
@@ -41436,23 +41426,29 @@ var CLIENT_CONFIGS = {
41436
41426
  opencode: {
41437
41427
  clientId: "opencode",
41438
41428
  name: "OpenCode",
41439
- configPath: join5(process.env.HOME || "", ".config/opencode/opencode.json")
41429
+ configPath: join6(process.env.HOME || "", ".config/opencode/opencode.json")
41440
41430
  },
41441
41431
  "pi-agent": {
41442
41432
  clientId: "pi-agent",
41443
41433
  name: "Pi Agent",
41444
- configPath: join5(process.env.HOME || "", ".pi/agent/models.json")
41434
+ configPath: join6(process.env.HOME || "", ".pi/agent/models.json")
41445
41435
  },
41446
41436
  openclaw: {
41447
41437
  clientId: "openclaw",
41448
41438
  name: "OpenClaw",
41449
- configPath: join5(process.env.HOME || "", ".openclaw/openclaw.json")
41439
+ configPath: join6(process.env.HOME || "", ".openclaw/openclaw.json")
41440
+ },
41441
+ "claude-code": {
41442
+ clientId: "claude-code",
41443
+ name: "Claude Code",
41444
+ configPath: join6(process.env.HOME || "", ".claude/settings.json")
41450
41445
  }
41451
41446
  };
41452
41447
  var CLIENT_INTEGRATIONS = {
41453
41448
  opencode: installOpencodeIntegration,
41454
41449
  "pi-agent": installPiIntegration,
41455
- openclaw: installOpenClawIntegration
41450
+ openclaw: installOpenClawIntegration,
41451
+ "claude-code": installClaudeCodeIntegration
41456
41452
  };
41457
41453
  async function runIntegrationsForClients(clientIds, config, store) {
41458
41454
  for (const client2 of clientIds) {
@@ -41496,8 +41492,8 @@ Installing routstr models in opencode.json...`);
41496
41492
  }
41497
41493
  let opencodeConfig;
41498
41494
  try {
41499
- if (existsSync5(configPath)) {
41500
- const content2 = await readFile3(configPath, "utf-8");
41495
+ if (existsSync7(configPath)) {
41496
+ const content2 = await readFile4(configPath, "utf-8");
41501
41497
  opencodeConfig = JSON.parse(content2);
41502
41498
  } else {
41503
41499
  opencodeConfig = { provider: {} };
@@ -41509,7 +41505,7 @@ Installing routstr models in opencode.json...`);
41509
41505
  opencodeConfig.provider = {};
41510
41506
  }
41511
41507
  try {
41512
- mkdirSync3(dirname3(configPath), { recursive: true });
41508
+ mkdirSync5(dirname4(configPath), { recursive: true });
41513
41509
  const response = await fetch(`http://localhost:${port}/models`);
41514
41510
  const data = await response.json();
41515
41511
  const models = data.output?.models || [];
@@ -41532,7 +41528,7 @@ Installing routstr models in opencode.json...`);
41532
41528
  models: modelsObj
41533
41529
  };
41534
41530
  opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
41535
- await writeFile3(configPath, JSON.stringify(opencodeConfig, null, 2));
41531
+ await writeFile4(configPath, JSON.stringify(opencodeConfig, null, 2));
41536
41532
  logger3.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
41537
41533
  } catch (error) {
41538
41534
  logger3.error("Failed to install models in opencode.json:", error);
@@ -41587,7 +41583,7 @@ async function main() {
41587
41583
  }));
41588
41584
  Bun.write(PID_FILE, String(process.pid));
41589
41585
  try {
41590
- if (existsSync6(SOCKET_PATH)) {
41586
+ if (existsSync8(SOCKET_PATH)) {
41591
41587
  Bun.spawn(["rm", SOCKET_PATH]);
41592
41588
  }
41593
41589
  } catch {}