routstrd 0.1.8 → 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.
- package/.claude/settings.local.json +3 -1
- package/bun.lock +2 -2
- package/dist/daemon/index.js +183 -274
- package/dist/index.js +84 -20
- package/package.json +3 -2
- package/src/daemon/http/index.ts +0 -236
- package/src/daemon/wallet/index.ts +1 -1
- package/src/integrations/claudecode.ts +77 -0
- package/src/integrations/index.ts +9 -2
- package/src/integrations/registry.ts +7 -0
package/dist/daemon/index.js
CHANGED
|
@@ -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
|
}
|
|
@@ -29683,11 +29686,28 @@ async function createBunSqliteDriver(dbPath) {
|
|
|
29683
29686
|
}
|
|
29684
29687
|
function createSSEParserTransform(onUsage, onResponseId) {
|
|
29685
29688
|
let buffer = "";
|
|
29686
|
-
let
|
|
29689
|
+
let capturedUsage = null;
|
|
29687
29690
|
let responseIdCaptured = false;
|
|
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
|
+
};
|
|
29688
29707
|
const inspectDataPayload = (jsonText) => {
|
|
29689
|
-
if (
|
|
29708
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
29690
29709
|
return;
|
|
29710
|
+
}
|
|
29691
29711
|
const trimmed = jsonText.trim();
|
|
29692
29712
|
if (!trimmed || trimmed === "[DONE]")
|
|
29693
29713
|
return;
|
|
@@ -29702,18 +29722,20 @@ function createSSEParserTransform(onUsage, onResponseId) {
|
|
|
29702
29722
|
responseIdCaptured = true;
|
|
29703
29723
|
}
|
|
29704
29724
|
}
|
|
29705
|
-
|
|
29706
|
-
|
|
29707
|
-
|
|
29708
|
-
|
|
29709
|
-
|
|
29725
|
+
const usage = extractUsageFromSSEJson(data);
|
|
29726
|
+
if (usage) {
|
|
29727
|
+
const mergedUsage = mergeUsage(capturedUsage, usage);
|
|
29728
|
+
if (hasUsageChanged(capturedUsage, mergedUsage)) {
|
|
29729
|
+
capturedUsage = mergedUsage;
|
|
29730
|
+
onUsage(mergedUsage);
|
|
29710
29731
|
}
|
|
29711
29732
|
}
|
|
29712
29733
|
} catch {}
|
|
29713
29734
|
};
|
|
29714
29735
|
const inspectEventBlock = (eventBlock) => {
|
|
29715
|
-
if (
|
|
29736
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
29716
29737
|
return;
|
|
29738
|
+
}
|
|
29717
29739
|
const lines = eventBlock.split(/\r?\n/);
|
|
29718
29740
|
const dataParts = [];
|
|
29719
29741
|
for (const line of lines) {
|
|
@@ -29770,7 +29792,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
29770
29792
|
const {
|
|
29771
29793
|
modelId,
|
|
29772
29794
|
requestBody,
|
|
29773
|
-
path = "/v1/chat/completions",
|
|
29795
|
+
path: path2 = "/v1/chat/completions",
|
|
29774
29796
|
headers = {},
|
|
29775
29797
|
forcedProvider,
|
|
29776
29798
|
walletAdapter,
|
|
@@ -29858,17 +29880,17 @@ async function resolveRouteRequestContext(options) {
|
|
|
29858
29880
|
client: client2,
|
|
29859
29881
|
baseUrl,
|
|
29860
29882
|
mintUrl,
|
|
29861
|
-
path,
|
|
29883
|
+
path: path2,
|
|
29862
29884
|
headers,
|
|
29863
29885
|
modelId,
|
|
29864
29886
|
proxiedBody
|
|
29865
29887
|
};
|
|
29866
29888
|
}
|
|
29867
29889
|
async function routeRequests(options) {
|
|
29868
|
-
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);
|
|
29869
29891
|
try {
|
|
29870
29892
|
const response = await client2.routeRequest({
|
|
29871
|
-
path,
|
|
29893
|
+
path: path2,
|
|
29872
29894
|
method: "POST",
|
|
29873
29895
|
body: proxiedBody,
|
|
29874
29896
|
headers,
|
|
@@ -29889,10 +29911,10 @@ async function routeRequests(options) {
|
|
|
29889
29911
|
}
|
|
29890
29912
|
async function routeRequestsToNodeResponse(options) {
|
|
29891
29913
|
const { res } = options;
|
|
29892
|
-
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);
|
|
29893
29915
|
try {
|
|
29894
29916
|
await client2.routeRequestToNodeResponse({
|
|
29895
|
-
path,
|
|
29917
|
+
path: path2,
|
|
29896
29918
|
method: "POST",
|
|
29897
29919
|
body: proxiedBody,
|
|
29898
29920
|
headers,
|
|
@@ -30406,10 +30428,10 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
30406
30428
|
`;
|
|
30407
30429
|
if (typeof window === "undefined") {
|
|
30408
30430
|
try {
|
|
30409
|
-
const
|
|
30410
|
-
const
|
|
30411
|
-
const logPath =
|
|
30412
|
-
|
|
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);
|
|
30413
30435
|
} catch (error) {
|
|
30414
30436
|
console.error("[AuditLogger] Failed to write to file:", error);
|
|
30415
30437
|
}
|
|
@@ -31673,6 +31695,10 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
31673
31695
|
const isExpired = age >= _ProviderManager.COOLDOWN_DURATION_MS;
|
|
31674
31696
|
if (isExpired) {
|
|
31675
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
|
+
}
|
|
31676
31702
|
}
|
|
31677
31703
|
return !isExpired;
|
|
31678
31704
|
});
|
|
@@ -31773,59 +31799,36 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
31773
31799
|
const torMode = isTorContext();
|
|
31774
31800
|
const disabledProviders = new Set(this.providerRegistry.getDisabledProviders());
|
|
31775
31801
|
console.log(`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`);
|
|
31776
|
-
console.log(`[findNextBestProvider:${this.instanceId}] currentBaseUrl: ${currentBaseUrl}`);
|
|
31777
|
-
console.log(`[findNextBestProvider:${this.instanceId}] torMode: ${torMode}`);
|
|
31778
31802
|
console.log(`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`);
|
|
31779
|
-
console.log(`[findNextBestProvider:${this.instanceId}] failedProviders: ${[...this.failedProviders]}`);
|
|
31780
31803
|
console.log(`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url2]) => url2)}`);
|
|
31781
31804
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
31782
31805
|
console.log(`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`);
|
|
31783
31806
|
const candidates = [];
|
|
31784
|
-
let skippedCurrent = 0, skippedFailed = 0, skippedDisabled = 0, skippedCooldown = 0, skippedOnion = 0, skippedNoModel = 0;
|
|
31785
31807
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
31786
31808
|
if (baseUrl === currentBaseUrl) {
|
|
31787
31809
|
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`);
|
|
31788
|
-
skippedCurrent++;
|
|
31789
|
-
continue;
|
|
31790
|
-
}
|
|
31791
|
-
if (this.failedProviders.has(baseUrl)) {
|
|
31792
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (failed): ${baseUrl}`);
|
|
31793
|
-
skippedFailed++;
|
|
31794
31810
|
continue;
|
|
31795
31811
|
}
|
|
31796
31812
|
if (disabledProviders.has(baseUrl)) {
|
|
31797
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (disabled): ${baseUrl}`);
|
|
31798
|
-
skippedDisabled++;
|
|
31799
31813
|
continue;
|
|
31800
31814
|
}
|
|
31801
31815
|
if (this.isOnCooldown(baseUrl)) {
|
|
31802
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (cooldown): ${baseUrl}`);
|
|
31803
|
-
skippedCooldown++;
|
|
31804
31816
|
continue;
|
|
31805
31817
|
}
|
|
31806
31818
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
31807
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (onion/http): ${baseUrl}`);
|
|
31808
|
-
skippedOnion++;
|
|
31809
31819
|
continue;
|
|
31810
31820
|
}
|
|
31811
31821
|
const model2 = models.find((m2) => m2.id === modelId);
|
|
31812
31822
|
if (!model2) {
|
|
31813
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (no model ${modelId}): ${baseUrl} has models: ${models.map((m2) => m2.id).join(", ")}`);
|
|
31814
|
-
skippedNoModel++;
|
|
31815
31823
|
continue;
|
|
31816
31824
|
}
|
|
31817
31825
|
const cost = model2.sats_pricing?.completion ?? 0;
|
|
31818
|
-
console.log(`[findNextBestProvider:${this.instanceId}] CANDIDATE: ${baseUrl} cost: ${cost}`);
|
|
31819
31826
|
candidates.push({ baseUrl, model: model2, cost });
|
|
31820
31827
|
}
|
|
31821
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Skipped: current=${skippedCurrent}, failed=${skippedFailed}, disabled=${skippedDisabled}, cooldown=${skippedCooldown}, onion=${skippedOnion}, noModel=${skippedNoModel}`);
|
|
31822
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Total candidates: ${candidates.length}`);
|
|
31823
31828
|
candidates.sort((a, b) => a.cost - b.cost);
|
|
31824
31829
|
if (candidates.length > 0) {
|
|
31825
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Selected provider: ${candidates[0].baseUrl} with cost: ${candidates[0].cost}`);
|
|
31826
31830
|
return candidates[0].baseUrl;
|
|
31827
31831
|
} else {
|
|
31828
|
-
console.log(`[findNextBestProvider:${this.instanceId}] No candidate providers found`);
|
|
31829
31832
|
return null;
|
|
31830
31833
|
}
|
|
31831
31834
|
} catch (error) {
|
|
@@ -33503,7 +33506,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33503
33506
|
}
|
|
33504
33507
|
async _prepareRoutedRequest(params) {
|
|
33505
33508
|
const {
|
|
33506
|
-
path,
|
|
33509
|
+
path: requestPath,
|
|
33507
33510
|
method,
|
|
33508
33511
|
body,
|
|
33509
33512
|
headers = {},
|
|
@@ -33538,7 +33541,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33538
33541
|
const baseHeaders = this._buildBaseHeaders();
|
|
33539
33542
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
33540
33543
|
const response = await this._makeRequest({
|
|
33541
|
-
path,
|
|
33544
|
+
path: requestPath,
|
|
33542
33545
|
method,
|
|
33543
33546
|
body: method === "GET" ? undefined : requestBody,
|
|
33544
33547
|
baseUrl,
|
|
@@ -33557,7 +33560,21 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33557
33560
|
let capturedUsage;
|
|
33558
33561
|
let capturedResponseId;
|
|
33559
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);
|
|
33560
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
|
+
});
|
|
33561
33578
|
const sseParser = createSSEParserTransform((usage) => {
|
|
33562
33579
|
capturedUsage = usage;
|
|
33563
33580
|
processedResponse.usage = usage;
|
|
@@ -33565,7 +33582,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33565
33582
|
capturedResponseId = responseId;
|
|
33566
33583
|
processedResponse.requestId = responseId;
|
|
33567
33584
|
});
|
|
33568
|
-
const transformed = nodeReadable.pipe(sseParser, { end: true });
|
|
33585
|
+
const transformed = nodeReadable.pipe(loggingTransform).pipe(sseParser, { end: true });
|
|
33569
33586
|
const webStream = Readable.toWeb(transformed);
|
|
33570
33587
|
processedResponse = new Response(webStream, {
|
|
33571
33588
|
status: response.status,
|
|
@@ -33622,7 +33639,6 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33622
33639
|
callbacks.onTokenCreated?.(this._getPendingCashuTokenAmount());
|
|
33623
33640
|
const baseHeaders = this._buildBaseHeaders(headers);
|
|
33624
33641
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
33625
|
-
this.providerManager.resetFailedProviders();
|
|
33626
33642
|
const providerInfo = await this.providerRegistry.getProviderInfo(baseUrl);
|
|
33627
33643
|
const providerVersion = providerInfo?.version ?? "";
|
|
33628
33644
|
let modelIdForRequest = selectedModel.id;
|
|
@@ -33710,9 +33726,9 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33710
33726
|
}
|
|
33711
33727
|
}
|
|
33712
33728
|
async _makeRequest(params) {
|
|
33713
|
-
const { path, method, body, baseUrl, token, headers } = params;
|
|
33729
|
+
const { path: path2, method, body, baseUrl, token, headers } = params;
|
|
33714
33730
|
try {
|
|
33715
|
-
const url2 = `${baseUrl.replace(/\/$/, "")}${
|
|
33731
|
+
const url2 = `${baseUrl.replace(/\/$/, "")}${path2}`;
|
|
33716
33732
|
if (this.mode === "xcashu")
|
|
33717
33733
|
this._log("DEBUG", "HEADERS,", headers);
|
|
33718
33734
|
const response = await fetch(url2, {
|
|
@@ -33744,7 +33760,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33744
33760
|
}
|
|
33745
33761
|
async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
|
|
33746
33762
|
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
33747
|
-
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
33763
|
+
const { path: path2, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
33748
33764
|
let tryNextProvider = false;
|
|
33749
33765
|
const errorMessage = responseBody;
|
|
33750
33766
|
this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}, errorMessage=${errorMessage}`);
|
|
@@ -33910,7 +33926,7 @@ var import_rxjs24, InsufficientBalanceError, ProviderError, MintUnreachableError
|
|
|
33910
33926
|
});
|
|
33911
33927
|
return this._makeRequest({
|
|
33912
33928
|
...params,
|
|
33913
|
-
path,
|
|
33929
|
+
path: path2,
|
|
33914
33930
|
method,
|
|
33915
33931
|
body,
|
|
33916
33932
|
baseUrl: nextProvider,
|
|
@@ -34384,7 +34400,7 @@ var init_dist3 = __esm(() => {
|
|
|
34384
34400
|
// src/daemon/index.ts
|
|
34385
34401
|
init_dist3();
|
|
34386
34402
|
import { createServer } from "http";
|
|
34387
|
-
import { existsSync as
|
|
34403
|
+
import { existsSync as existsSync8 } from "fs";
|
|
34388
34404
|
|
|
34389
34405
|
// src/utils/config.ts
|
|
34390
34406
|
var HOME = process.env.HOME || process.env.USERPROFILE || "";
|
|
@@ -34403,19 +34419,19 @@ var DEFAULT_CONFIG = {
|
|
|
34403
34419
|
|
|
34404
34420
|
// src/utils/logger.ts
|
|
34405
34421
|
import { appendFile, mkdir } from "fs/promises";
|
|
34406
|
-
import { existsSync } from "fs";
|
|
34407
|
-
import { join as
|
|
34422
|
+
import { existsSync as existsSync2 } from "fs";
|
|
34423
|
+
import { join as join4 } from "path";
|
|
34408
34424
|
var HOME2 = process.env.HOME || process.env.USERPROFILE || "";
|
|
34409
34425
|
var LOG_DIR = process.env.ROUTSTRD_DIR || `${HOME2}/.routstrd`;
|
|
34410
|
-
var LOGS_DIR2 =
|
|
34426
|
+
var LOGS_DIR2 = join4(LOG_DIR, "logs");
|
|
34411
34427
|
function getLogFileForDate(date = new Date) {
|
|
34412
34428
|
const year = date.getFullYear();
|
|
34413
34429
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
34414
34430
|
const day = String(date.getDate()).padStart(2, "0");
|
|
34415
|
-
return
|
|
34431
|
+
return join4(LOGS_DIR2, `${year}-${month}-${day}.log`);
|
|
34416
34432
|
}
|
|
34417
34433
|
async function ensureLogDir() {
|
|
34418
|
-
if (!
|
|
34434
|
+
if (!existsSync2(LOGS_DIR2)) {
|
|
34419
34435
|
await mkdir(LOGS_DIR2, { recursive: true });
|
|
34420
34436
|
}
|
|
34421
34437
|
}
|
|
@@ -34475,7 +34491,7 @@ function parseArgs(argv) {
|
|
|
34475
34491
|
|
|
34476
34492
|
// src/daemon/config-store.ts
|
|
34477
34493
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
34478
|
-
import { existsSync as
|
|
34494
|
+
import { existsSync as existsSync3 } from "fs";
|
|
34479
34495
|
var REQUESTS_DIR = `${CONFIG_DIR}/requests`;
|
|
34480
34496
|
async function ensureDirs() {
|
|
34481
34497
|
try {
|
|
@@ -34485,7 +34501,7 @@ async function ensureDirs() {
|
|
|
34485
34501
|
}
|
|
34486
34502
|
async function loadDaemonConfig() {
|
|
34487
34503
|
try {
|
|
34488
|
-
if (
|
|
34504
|
+
if (existsSync3(CONFIG_FILE)) {
|
|
34489
34505
|
const content2 = await Bun.file(CONFIG_FILE).text();
|
|
34490
34506
|
return { ...DEFAULT_CONFIG, ...JSON.parse(content2) };
|
|
34491
34507
|
}
|
|
@@ -34797,7 +34813,7 @@ function alphabet3(letters) {
|
|
|
34797
34813
|
}
|
|
34798
34814
|
};
|
|
34799
34815
|
}
|
|
34800
|
-
function
|
|
34816
|
+
function join5(separator = "") {
|
|
34801
34817
|
astr2("join", separator);
|
|
34802
34818
|
return {
|
|
34803
34819
|
encode: (from7) => {
|
|
@@ -35000,12 +35016,12 @@ function checksum2(len, fn) {
|
|
|
35000
35016
|
}
|
|
35001
35017
|
};
|
|
35002
35018
|
}
|
|
35003
|
-
var base163 = chain3(radix23(4), alphabet3("0123456789ABCDEF"),
|
|
35004
|
-
var base323 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding3(5),
|
|
35005
|
-
var base32nopad2 = chain3(radix23(5), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),
|
|
35006
|
-
var base32hex3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"), padding3(5),
|
|
35007
|
-
var base32hexnopad2 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHIJKLMNOPQRSTUV"),
|
|
35008
|
-
var base32crockford3 = chain3(radix23(5), alphabet3("0123456789ABCDEFGHJKMNPQRSTVWXYZ"),
|
|
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")));
|
|
35009
35025
|
var hasBase64Builtin2 = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")();
|
|
35010
35026
|
var decodeBase64Builtin2 = (s, isUrl) => {
|
|
35011
35027
|
astr2("base64", s);
|
|
@@ -35023,8 +35039,8 @@ var base643 = hasBase64Builtin2 ? {
|
|
|
35023
35039
|
decode(s) {
|
|
35024
35040
|
return decodeBase64Builtin2(s, false);
|
|
35025
35041
|
}
|
|
35026
|
-
} : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding3(6),
|
|
35027
|
-
var base64nopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),
|
|
35042
|
+
} : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding3(6), join5(""));
|
|
35043
|
+
var base64nopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), join5(""));
|
|
35028
35044
|
var base64url3 = hasBase64Builtin2 ? {
|
|
35029
35045
|
encode(b) {
|
|
35030
35046
|
abytes4(b);
|
|
@@ -35033,14 +35049,14 @@ var base64url3 = hasBase64Builtin2 ? {
|
|
|
35033
35049
|
decode(s) {
|
|
35034
35050
|
return decodeBase64Builtin2(s, true);
|
|
35035
35051
|
}
|
|
35036
|
-
} : chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"), padding3(6),
|
|
35037
|
-
var base64urlnopad2 = chain3(radix23(6), alphabet3("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),
|
|
35038
|
-
var genBase583 = (abc) => chain3(radix5(58), alphabet3(abc),
|
|
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(""));
|
|
35039
35055
|
var base583 = genBase583("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
|
35040
35056
|
var base58flickr3 = genBase583("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
|
|
35041
35057
|
var base58xrp3 = genBase583("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");
|
|
35042
35058
|
var createBase58check2 = (sha2565) => chain3(checksum2(4, (data) => sha2565(sha2565(data))), base583);
|
|
35043
|
-
var BECH_ALPHABET3 = chain3(alphabet3("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),
|
|
35059
|
+
var BECH_ALPHABET3 = chain3(alphabet3("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), join5(""));
|
|
35044
35060
|
var POLYMOD_GENERATORS3 = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
35045
35061
|
function bech32Polymod3(pre) {
|
|
35046
35062
|
const b = pre >> 25;
|
|
@@ -35144,7 +35160,7 @@ var hexBuiltin2 = {
|
|
|
35144
35160
|
return Uint8Array.fromHex(s);
|
|
35145
35161
|
}
|
|
35146
35162
|
};
|
|
35147
|
-
var hex3 = hasHexBuiltin3 ? hexBuiltin2 : chain3(radix23(4), alphabet3("0123456789abcdef"),
|
|
35163
|
+
var hex3 = hasHexBuiltin3 ? hexBuiltin2 : chain3(radix23(4), alphabet3("0123456789abcdef"), join5(""), normalize3((s) => {
|
|
35148
35164
|
if (typeof s !== "string" || s.length % 2 !== 0)
|
|
35149
35165
|
throw new TypeError(`hex.decode: expected string, got ${typeof s} with length ${s.length}`);
|
|
35150
35166
|
return s.toLowerCase();
|
|
@@ -38000,14 +38016,14 @@ class HDKey2 {
|
|
|
38000
38016
|
}
|
|
38001
38017
|
this.pubHash = hash1602(this._publicKey);
|
|
38002
38018
|
}
|
|
38003
|
-
derive(
|
|
38004
|
-
if (!/^[mM]'?/.test(
|
|
38019
|
+
derive(path2) {
|
|
38020
|
+
if (!/^[mM]'?/.test(path2)) {
|
|
38005
38021
|
throw new Error('Path must start with "m" or "M"');
|
|
38006
38022
|
}
|
|
38007
|
-
if (/^[mM]'?$/.test(
|
|
38023
|
+
if (/^[mM]'?$/.test(path2)) {
|
|
38008
38024
|
return this;
|
|
38009
38025
|
}
|
|
38010
|
-
const parts =
|
|
38026
|
+
const parts = path2.replace(/^[mM]'?\//, "").split("/");
|
|
38011
38027
|
let child = this;
|
|
38012
38028
|
for (const c of parts) {
|
|
38013
38029
|
const m2 = /^(\d+)('?)$/.exec(c);
|
|
@@ -38366,7 +38382,7 @@ function bt(s, t) {
|
|
|
38366
38382
|
case 2:
|
|
38367
38383
|
return is(s, t, r);
|
|
38368
38384
|
case 3:
|
|
38369
|
-
return
|
|
38385
|
+
return os3(s, t, r);
|
|
38370
38386
|
case 4:
|
|
38371
38387
|
return as2(s, t, r);
|
|
38372
38388
|
case 5:
|
|
@@ -38417,7 +38433,7 @@ function is(s, t, e) {
|
|
|
38417
38433
|
throw new Error("Byte string length exceeds data length");
|
|
38418
38434
|
return { value: new Uint8Array(s.buffer, s.byteOffset + r, n), offset: r + n };
|
|
38419
38435
|
}
|
|
38420
|
-
function
|
|
38436
|
+
function os3(s, t, e) {
|
|
38421
38437
|
const { value: n, offset: r } = ot2(s, t, e);
|
|
38422
38438
|
if (r + n > s.byteLength)
|
|
38423
38439
|
throw new Error("String length exceeds data length");
|
|
@@ -40187,25 +40203,25 @@ function createCocodClient(options = {}) {
|
|
|
40187
40203
|
return proc;
|
|
40188
40204
|
});
|
|
40189
40205
|
let startPromise = null;
|
|
40190
|
-
async function fetchJson(
|
|
40206
|
+
async function fetchJson(path2, init = {}) {
|
|
40191
40207
|
const method = init.method || "GET";
|
|
40192
40208
|
const requestInit = {
|
|
40193
40209
|
...init,
|
|
40194
40210
|
unix: socketPath
|
|
40195
40211
|
};
|
|
40196
|
-
const response = await fetchImpl(`http://localhost${
|
|
40212
|
+
const response = await fetchImpl(`http://localhost${path2}`, requestInit);
|
|
40197
40213
|
const rawText = await response.text();
|
|
40198
40214
|
if (!rawText.trim()) {
|
|
40199
|
-
throw new CocodHttpError(response.ok ? 502 : response.status, `Empty response from cocod for ${method} ${
|
|
40215
|
+
throw new CocodHttpError(response.ok ? 502 : response.status, `Empty response from cocod for ${method} ${path2}`);
|
|
40200
40216
|
}
|
|
40201
40217
|
let data;
|
|
40202
40218
|
try {
|
|
40203
40219
|
data = JSON.parse(rawText);
|
|
40204
40220
|
} catch {
|
|
40205
|
-
throw new CocodHttpError(response.ok ? 502 : response.status, `Invalid JSON response from cocod for ${method} ${
|
|
40221
|
+
throw new CocodHttpError(response.ok ? 502 : response.status, `Invalid JSON response from cocod for ${method} ${path2}`);
|
|
40206
40222
|
}
|
|
40207
40223
|
if (!data || typeof data !== "object") {
|
|
40208
|
-
throw new CocodHttpError(response.ok ? 502 : response.status, `Unexpected response shape from cocod for ${method} ${
|
|
40224
|
+
throw new CocodHttpError(response.ok ? 502 : response.status, `Unexpected response shape from cocod for ${method} ${path2}`);
|
|
40209
40225
|
}
|
|
40210
40226
|
const errorMessage = toErrorText(data.error);
|
|
40211
40227
|
if (errorMessage) {
|
|
@@ -40256,13 +40272,13 @@ function createCocodClient(options = {}) {
|
|
|
40256
40272
|
}
|
|
40257
40273
|
await startPromise;
|
|
40258
40274
|
}
|
|
40259
|
-
async function callDaemon(
|
|
40275
|
+
async function callDaemon(path2, init = {}) {
|
|
40260
40276
|
await ensureDaemonRunning();
|
|
40261
|
-
const response = await fetchJson(
|
|
40277
|
+
const response = await fetchJson(path2, init);
|
|
40262
40278
|
return response.output;
|
|
40263
40279
|
}
|
|
40264
|
-
function post(
|
|
40265
|
-
return callDaemon(
|
|
40280
|
+
function post(path2, body) {
|
|
40281
|
+
return callDaemon(path2, {
|
|
40266
40282
|
method: "POST",
|
|
40267
40283
|
headers: { "Content-Type": "application/json" },
|
|
40268
40284
|
body: JSON.stringify(body)
|
|
@@ -40380,7 +40396,7 @@ async function createWalletAdapter(options = {}) {
|
|
|
40380
40396
|
return { success: true, amount, unit, message };
|
|
40381
40397
|
} catch (error) {
|
|
40382
40398
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
40383
|
-
logger3.error("Error in walletAdapter receiveToken:",
|
|
40399
|
+
logger3.error("Error in walletAdapter receiveToken:", errorMessage);
|
|
40384
40400
|
return { success: false, amount: 0, unit: "sat", message: errorMessage };
|
|
40385
40401
|
}
|
|
40386
40402
|
}
|
|
@@ -41059,173 +41075,6 @@ function createDaemonRequestHandler(deps) {
|
|
|
41059
41075
|
}
|
|
41060
41076
|
return;
|
|
41061
41077
|
}
|
|
41062
|
-
if (req.method === "POST" && url2.pathname === "/providers/disable") {
|
|
41063
|
-
try {
|
|
41064
|
-
const bodyText = await readBody(req);
|
|
41065
|
-
const body = bodyText ? JSON.parse(bodyText) : {};
|
|
41066
|
-
const indices = body.indices;
|
|
41067
|
-
if (!Array.isArray(indices)) {
|
|
41068
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
41069
|
-
res.end(JSON.stringify({
|
|
41070
|
-
error: "Missing or invalid 'indices' field (expected number[])."
|
|
41071
|
-
}));
|
|
41072
|
-
return;
|
|
41073
|
-
}
|
|
41074
|
-
const state = deps.store.getState();
|
|
41075
|
-
const baseUrlsList = state.baseUrlsList || [];
|
|
41076
|
-
const disabledProviders = [
|
|
41077
|
-
...state.disabledProviders || []
|
|
41078
|
-
];
|
|
41079
|
-
const toDisable = [];
|
|
41080
|
-
for (const idx of indices) {
|
|
41081
|
-
if (typeof idx === "number" && idx >= 0 && idx < baseUrlsList.length) {
|
|
41082
|
-
const baseUrl = baseUrlsList[idx];
|
|
41083
|
-
if (!disabledProviders.includes(baseUrl)) {
|
|
41084
|
-
disabledProviders.push(baseUrl);
|
|
41085
|
-
toDisable.push(baseUrl);
|
|
41086
|
-
}
|
|
41087
|
-
}
|
|
41088
|
-
}
|
|
41089
|
-
deps.store.getState().setDisabledProviders(disabledProviders);
|
|
41090
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41091
|
-
res.end(JSON.stringify({
|
|
41092
|
-
output: {
|
|
41093
|
-
message: `Disabled ${toDisable.length} provider(s)`,
|
|
41094
|
-
disabled: toDisable
|
|
41095
|
-
}
|
|
41096
|
-
}));
|
|
41097
|
-
} catch (error) {
|
|
41098
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
41099
|
-
res.end(JSON.stringify({ error: String(error) }));
|
|
41100
|
-
}
|
|
41101
|
-
return;
|
|
41102
|
-
}
|
|
41103
|
-
if (req.method === "POST" && url2.pathname === "/providers/enable") {
|
|
41104
|
-
try {
|
|
41105
|
-
const bodyText = await readBody(req);
|
|
41106
|
-
const body = bodyText ? JSON.parse(bodyText) : {};
|
|
41107
|
-
const indices = body.indices;
|
|
41108
|
-
if (!Array.isArray(indices)) {
|
|
41109
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
41110
|
-
res.end(JSON.stringify({
|
|
41111
|
-
error: "Missing or invalid 'indices' field (expected number[])."
|
|
41112
|
-
}));
|
|
41113
|
-
return;
|
|
41114
|
-
}
|
|
41115
|
-
const state = deps.store.getState();
|
|
41116
|
-
const baseUrlsList = state.baseUrlsList || [];
|
|
41117
|
-
const disabledProviders = [
|
|
41118
|
-
...state.disabledProviders || []
|
|
41119
|
-
];
|
|
41120
|
-
const toEnable = [];
|
|
41121
|
-
for (const idx of indices) {
|
|
41122
|
-
if (typeof idx === "number" && idx >= 0 && idx < baseUrlsList.length) {
|
|
41123
|
-
const baseUrl = baseUrlsList[idx];
|
|
41124
|
-
const pos = disabledProviders.indexOf(baseUrl);
|
|
41125
|
-
if (pos !== -1) {
|
|
41126
|
-
disabledProviders.splice(pos, 1);
|
|
41127
|
-
toEnable.push(baseUrl);
|
|
41128
|
-
}
|
|
41129
|
-
}
|
|
41130
|
-
}
|
|
41131
|
-
deps.store.getState().setDisabledProviders(disabledProviders);
|
|
41132
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41133
|
-
res.end(JSON.stringify({
|
|
41134
|
-
output: {
|
|
41135
|
-
message: `Enabled ${toEnable.length} provider(s)`,
|
|
41136
|
-
enabled: toEnable
|
|
41137
|
-
}
|
|
41138
|
-
}));
|
|
41139
|
-
} catch (error) {
|
|
41140
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
41141
|
-
res.end(JSON.stringify({ error: String(error) }));
|
|
41142
|
-
}
|
|
41143
|
-
return;
|
|
41144
|
-
}
|
|
41145
|
-
if (req.method === "GET" && url2.pathname === "/clients") {
|
|
41146
|
-
try {
|
|
41147
|
-
const state = deps.store.getState();
|
|
41148
|
-
const clientIds = state.clientIds || [];
|
|
41149
|
-
const clients = clientIds.map((c) => ({
|
|
41150
|
-
id: c.clientId,
|
|
41151
|
-
name: c.name,
|
|
41152
|
-
apiKey: c.apiKey,
|
|
41153
|
-
createdAt: c.createdAt,
|
|
41154
|
-
lastUsed: c.lastUsed
|
|
41155
|
-
}));
|
|
41156
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41157
|
-
res.end(JSON.stringify({
|
|
41158
|
-
output: {
|
|
41159
|
-
clients,
|
|
41160
|
-
totalCount: clients.length
|
|
41161
|
-
}
|
|
41162
|
-
}));
|
|
41163
|
-
} catch (error) {
|
|
41164
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
41165
|
-
res.end(JSON.stringify({ error: String(error) }));
|
|
41166
|
-
}
|
|
41167
|
-
return;
|
|
41168
|
-
}
|
|
41169
|
-
if (req.method === "POST" && url2.pathname === "/clients/add") {
|
|
41170
|
-
try {
|
|
41171
|
-
const bodyText = await readBody(req);
|
|
41172
|
-
const body = bodyText ? JSON.parse(bodyText) : {};
|
|
41173
|
-
const name = body.name;
|
|
41174
|
-
if (!name || typeof name !== "string" || name.trim() === "") {
|
|
41175
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
41176
|
-
res.end(JSON.stringify({
|
|
41177
|
-
error: "Missing required 'name' field (must be a non-empty string)."
|
|
41178
|
-
}));
|
|
41179
|
-
return;
|
|
41180
|
-
}
|
|
41181
|
-
const clientId = name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
41182
|
-
if (!clientId) {
|
|
41183
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
41184
|
-
res.end(JSON.stringify({
|
|
41185
|
-
error: "Invalid client name. Must contain alphanumeric characters."
|
|
41186
|
-
}));
|
|
41187
|
-
return;
|
|
41188
|
-
}
|
|
41189
|
-
const state = deps.store.getState();
|
|
41190
|
-
const existingClients = state.clientIds || [];
|
|
41191
|
-
const existingClient = existingClients.find((c) => c.clientId === clientId);
|
|
41192
|
-
if (existingClient) {
|
|
41193
|
-
res.writeHead(409, { "Content-Type": "application/json" });
|
|
41194
|
-
res.end(JSON.stringify({
|
|
41195
|
-
error: `Client with id '${clientId}' already exists.`
|
|
41196
|
-
}));
|
|
41197
|
-
return;
|
|
41198
|
-
}
|
|
41199
|
-
const apiKey = generateApiKey();
|
|
41200
|
-
const newClient = {
|
|
41201
|
-
clientId,
|
|
41202
|
-
name: name.trim(),
|
|
41203
|
-
apiKey,
|
|
41204
|
-
createdAt: Date.now()
|
|
41205
|
-
};
|
|
41206
|
-
deps.store.getState().setClientIds((prev) => [
|
|
41207
|
-
...prev || [],
|
|
41208
|
-
newClient
|
|
41209
|
-
]);
|
|
41210
|
-
logger3.log(`Added client '${name}' with id '${clientId}'`);
|
|
41211
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41212
|
-
res.end(JSON.stringify({
|
|
41213
|
-
output: {
|
|
41214
|
-
message: `Client '${name}' added successfully`,
|
|
41215
|
-
client: {
|
|
41216
|
-
id: clientId,
|
|
41217
|
-
name: name.trim(),
|
|
41218
|
-
apiKey,
|
|
41219
|
-
createdAt: newClient.createdAt
|
|
41220
|
-
}
|
|
41221
|
-
}
|
|
41222
|
-
}));
|
|
41223
|
-
} catch (error) {
|
|
41224
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
41225
|
-
res.end(JSON.stringify({ error: String(error) }));
|
|
41226
|
-
}
|
|
41227
|
-
return;
|
|
41228
|
-
}
|
|
41229
41078
|
if (req.method === "GET" && url2.pathname === "/usage") {
|
|
41230
41079
|
try {
|
|
41231
41080
|
const output4 = await deps.usageTrackingDriver.list({
|
|
@@ -41347,16 +41196,16 @@ function createDaemonRequestHandler(deps) {
|
|
|
41347
41196
|
}
|
|
41348
41197
|
|
|
41349
41198
|
// src/integrations/opencode.ts
|
|
41350
|
-
import { existsSync as
|
|
41351
|
-
import { readFile as
|
|
41352
|
-
import { dirname as
|
|
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";
|
|
41353
41202
|
|
|
41354
41203
|
// src/integrations/registry.ts
|
|
41355
41204
|
import { randomBytes as randomBytes6 } from "crypto";
|
|
41356
|
-
import { join as
|
|
41205
|
+
import { join as join6 } from "path";
|
|
41357
41206
|
|
|
41358
41207
|
// src/integrations/pi.ts
|
|
41359
|
-
import { existsSync as
|
|
41208
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
41360
41209
|
import { readFile, writeFile } from "fs/promises";
|
|
41361
41210
|
import { dirname } from "path";
|
|
41362
41211
|
async function installPiIntegration(config, store, integrationConfig) {
|
|
@@ -41386,7 +41235,7 @@ Installing routstr models in pi models.json...`);
|
|
|
41386
41235
|
}
|
|
41387
41236
|
let piConfig = {};
|
|
41388
41237
|
try {
|
|
41389
|
-
if (
|
|
41238
|
+
if (existsSync4(configPath)) {
|
|
41390
41239
|
const content2 = await readFile(configPath, "utf-8");
|
|
41391
41240
|
piConfig = JSON.parse(content2);
|
|
41392
41241
|
}
|
|
@@ -41397,7 +41246,7 @@ Installing routstr models in pi models.json...`);
|
|
|
41397
41246
|
piConfig.providers = {};
|
|
41398
41247
|
}
|
|
41399
41248
|
try {
|
|
41400
|
-
|
|
41249
|
+
mkdirSync2(dirname(configPath), { recursive: true });
|
|
41401
41250
|
const response = await fetch(`http://localhost:${port}/models`);
|
|
41402
41251
|
const data = await response.json();
|
|
41403
41252
|
const models = data.output?.models || [];
|
|
@@ -41422,7 +41271,7 @@ Installing routstr models in pi models.json...`);
|
|
|
41422
41271
|
}
|
|
41423
41272
|
|
|
41424
41273
|
// src/integrations/openclaw.ts
|
|
41425
|
-
import { existsSync as
|
|
41274
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
41426
41275
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
41427
41276
|
import { dirname as dirname2 } from "path";
|
|
41428
41277
|
var OPENCLAW_PROVIDER_ID = "routstr";
|
|
@@ -41454,7 +41303,7 @@ Installing routstr models in openclaw.json...`);
|
|
|
41454
41303
|
}
|
|
41455
41304
|
let openclawConfig = {};
|
|
41456
41305
|
try {
|
|
41457
|
-
if (
|
|
41306
|
+
if (existsSync5(configPath)) {
|
|
41458
41307
|
const content2 = await readFile2(configPath, "utf-8");
|
|
41459
41308
|
openclawConfig = JSON.parse(content2);
|
|
41460
41309
|
}
|
|
@@ -41474,7 +41323,7 @@ Installing routstr models in openclaw.json...`);
|
|
|
41474
41323
|
openclawConfig.agents.defaults = {};
|
|
41475
41324
|
}
|
|
41476
41325
|
try {
|
|
41477
|
-
|
|
41326
|
+
mkdirSync3(dirname2(configPath), { recursive: true });
|
|
41478
41327
|
const response = await fetch(`http://localhost:${port}/models`);
|
|
41479
41328
|
const data = await response.json();
|
|
41480
41329
|
const models = data.output?.models || [];
|
|
@@ -41514,6 +41363,60 @@ Installing routstr models in openclaw.json...`);
|
|
|
41514
41363
|
}
|
|
41515
41364
|
}
|
|
41516
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
|
+
|
|
41517
41420
|
// src/integrations/registry.ts
|
|
41518
41421
|
function generateApiKey2() {
|
|
41519
41422
|
const bytes4 = randomBytes6(24);
|
|
@@ -41523,23 +41426,29 @@ var CLIENT_CONFIGS = {
|
|
|
41523
41426
|
opencode: {
|
|
41524
41427
|
clientId: "opencode",
|
|
41525
41428
|
name: "OpenCode",
|
|
41526
|
-
configPath:
|
|
41429
|
+
configPath: join6(process.env.HOME || "", ".config/opencode/opencode.json")
|
|
41527
41430
|
},
|
|
41528
41431
|
"pi-agent": {
|
|
41529
41432
|
clientId: "pi-agent",
|
|
41530
41433
|
name: "Pi Agent",
|
|
41531
|
-
configPath:
|
|
41434
|
+
configPath: join6(process.env.HOME || "", ".pi/agent/models.json")
|
|
41532
41435
|
},
|
|
41533
41436
|
openclaw: {
|
|
41534
41437
|
clientId: "openclaw",
|
|
41535
41438
|
name: "OpenClaw",
|
|
41536
|
-
configPath:
|
|
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")
|
|
41537
41445
|
}
|
|
41538
41446
|
};
|
|
41539
41447
|
var CLIENT_INTEGRATIONS = {
|
|
41540
41448
|
opencode: installOpencodeIntegration,
|
|
41541
41449
|
"pi-agent": installPiIntegration,
|
|
41542
|
-
openclaw: installOpenClawIntegration
|
|
41450
|
+
openclaw: installOpenClawIntegration,
|
|
41451
|
+
"claude-code": installClaudeCodeIntegration
|
|
41543
41452
|
};
|
|
41544
41453
|
async function runIntegrationsForClients(clientIds, config, store) {
|
|
41545
41454
|
for (const client2 of clientIds) {
|
|
@@ -41583,8 +41492,8 @@ Installing routstr models in opencode.json...`);
|
|
|
41583
41492
|
}
|
|
41584
41493
|
let opencodeConfig;
|
|
41585
41494
|
try {
|
|
41586
|
-
if (
|
|
41587
|
-
const content2 = await
|
|
41495
|
+
if (existsSync7(configPath)) {
|
|
41496
|
+
const content2 = await readFile4(configPath, "utf-8");
|
|
41588
41497
|
opencodeConfig = JSON.parse(content2);
|
|
41589
41498
|
} else {
|
|
41590
41499
|
opencodeConfig = { provider: {} };
|
|
@@ -41596,7 +41505,7 @@ Installing routstr models in opencode.json...`);
|
|
|
41596
41505
|
opencodeConfig.provider = {};
|
|
41597
41506
|
}
|
|
41598
41507
|
try {
|
|
41599
|
-
|
|
41508
|
+
mkdirSync5(dirname4(configPath), { recursive: true });
|
|
41600
41509
|
const response = await fetch(`http://localhost:${port}/models`);
|
|
41601
41510
|
const data = await response.json();
|
|
41602
41511
|
const models = data.output?.models || [];
|
|
@@ -41619,7 +41528,7 @@ Installing routstr models in opencode.json...`);
|
|
|
41619
41528
|
models: modelsObj
|
|
41620
41529
|
};
|
|
41621
41530
|
opencodeConfig.small_model = OPENCODE_SMALL_MODEL;
|
|
41622
|
-
await
|
|
41531
|
+
await writeFile4(configPath, JSON.stringify(opencodeConfig, null, 2));
|
|
41623
41532
|
logger3.log(`Added "routstr" provider with ${models.length} models to opencode.json`);
|
|
41624
41533
|
} catch (error) {
|
|
41625
41534
|
logger3.error("Failed to install models in opencode.json:", error);
|
|
@@ -41674,7 +41583,7 @@ async function main() {
|
|
|
41674
41583
|
}));
|
|
41675
41584
|
Bun.write(PID_FILE, String(process.pid));
|
|
41676
41585
|
try {
|
|
41677
|
-
if (
|
|
41586
|
+
if (existsSync8(SOCKET_PATH)) {
|
|
41678
41587
|
Bun.spawn(["rm", SOCKET_PATH]);
|
|
41679
41588
|
}
|
|
41680
41589
|
} catch {}
|