@blockrun/clawrouter 0.12.281 → 0.12.282
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/dist/cli.js +276 -122
- package/dist/index.js +241 -87
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -66178,6 +66178,156 @@ ${lines.join("\n")}`;
|
|
|
66178
66178
|
}
|
|
66179
66179
|
});
|
|
66180
66180
|
|
|
66181
|
+
// src/local-guard.ts
|
|
66182
|
+
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readSync as readSync2, realpathSync } from "fs";
|
|
66183
|
+
import { homedir as homedir7 } from "os";
|
|
66184
|
+
import { join as join10 } from "path";
|
|
66185
|
+
function isLocalHostname(hostname) {
|
|
66186
|
+
const h = hostname.toLowerCase().replace(/\.$/, "");
|
|
66187
|
+
return h === "localhost" || h === "127.0.0.1" || h === "[::1]" || h === "::1";
|
|
66188
|
+
}
|
|
66189
|
+
function untrustedRequestReason(req) {
|
|
66190
|
+
const host = req.headers.host;
|
|
66191
|
+
if (host) {
|
|
66192
|
+
let hostname;
|
|
66193
|
+
try {
|
|
66194
|
+
hostname = new URL(`http://${host}`).hostname;
|
|
66195
|
+
} catch {
|
|
66196
|
+
return "malformed Host header";
|
|
66197
|
+
}
|
|
66198
|
+
if (!isLocalHostname(hostname)) return `non-local Host header (${hostname})`;
|
|
66199
|
+
}
|
|
66200
|
+
const origin2 = req.headers.origin;
|
|
66201
|
+
if (Array.isArray(origin2)) return "multiple Origin headers";
|
|
66202
|
+
if (origin2 !== void 0) {
|
|
66203
|
+
if (origin2 === "null") return "opaque Origin";
|
|
66204
|
+
let o3;
|
|
66205
|
+
try {
|
|
66206
|
+
o3 = new URL(origin2);
|
|
66207
|
+
} catch {
|
|
66208
|
+
return "malformed Origin header";
|
|
66209
|
+
}
|
|
66210
|
+
if (o3.protocol !== "http:" && o3.protocol !== "https:" || !isLocalHostname(o3.hostname)) {
|
|
66211
|
+
return `cross-site Origin (${origin2})`;
|
|
66212
|
+
}
|
|
66213
|
+
}
|
|
66214
|
+
const site = req.headers["sec-fetch-site"];
|
|
66215
|
+
if (site === "cross-site") return "cross-site browser request";
|
|
66216
|
+
return null;
|
|
66217
|
+
}
|
|
66218
|
+
function v4FromHex(hi, lo) {
|
|
66219
|
+
return `${hi >>> 8 & 255}.${hi & 255}.${lo >>> 8 & 255}.${lo & 255}`;
|
|
66220
|
+
}
|
|
66221
|
+
function isBlockedSsrfHost(hostname) {
|
|
66222
|
+
const h = hostname.toLowerCase().replace(/^\[/, "").replace(/\]$/, "").replace(/\.$/, "");
|
|
66223
|
+
if (!h) return true;
|
|
66224
|
+
if (h === "localhost" || h.endsWith(".localhost") || h.endsWith(".local")) return true;
|
|
66225
|
+
if (h.endsWith(".internal")) return true;
|
|
66226
|
+
if (METADATA_HOSTS.has(h)) return true;
|
|
66227
|
+
if (h.includes(":")) {
|
|
66228
|
+
if (h === "::1" || h === "::") return true;
|
|
66229
|
+
if (h.startsWith("fe80:") || h.startsWith("fc") || h.startsWith("fd")) return true;
|
|
66230
|
+
const sixToFour = h.match(/^2002:([0-9a-f]{1,4}):([0-9a-f]{1,4}):/);
|
|
66231
|
+
if (sixToFour) {
|
|
66232
|
+
return isBlockedSsrfHost(v4FromHex(parseInt(sixToFour[1], 16), parseInt(sixToFour[2], 16)));
|
|
66233
|
+
}
|
|
66234
|
+
const embedded = h.match(/^64:ff9b::(.+)$/) ?? h.match(/::ffff:(.+)$/);
|
|
66235
|
+
if (embedded) {
|
|
66236
|
+
const tail = embedded[1];
|
|
66237
|
+
if (tail.includes(".")) return isBlockedSsrfHost(tail);
|
|
66238
|
+
const seg = tail.split(":");
|
|
66239
|
+
if (seg.length === 2)
|
|
66240
|
+
return isBlockedSsrfHost(v4FromHex(parseInt(seg[0], 16), parseInt(seg[1], 16)));
|
|
66241
|
+
}
|
|
66242
|
+
return false;
|
|
66243
|
+
}
|
|
66244
|
+
const m = h.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
66245
|
+
if (m) {
|
|
66246
|
+
const a = Number(m[1]);
|
|
66247
|
+
const b = Number(m[2]);
|
|
66248
|
+
const c = Number(m[3]);
|
|
66249
|
+
if (a === 127 || a === 0 || a === 10) return true;
|
|
66250
|
+
if (a === 169 && b === 254) return true;
|
|
66251
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
66252
|
+
if (a === 192 && b === 168) return true;
|
|
66253
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
66254
|
+
if (a === 192 && b === 0 && c === 0) return true;
|
|
66255
|
+
}
|
|
66256
|
+
return false;
|
|
66257
|
+
}
|
|
66258
|
+
async function ssrfSafeFetch(url2, init2 = {}, maxHops = 5) {
|
|
66259
|
+
const { allowPrivate, ...fetchInit } = init2;
|
|
66260
|
+
let current = url2;
|
|
66261
|
+
for (let hop = 0; hop <= maxHops; hop++) {
|
|
66262
|
+
const u = new URL(current);
|
|
66263
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
66264
|
+
throw new Error(`refusing to fetch non-http(s) URL (${u.protocol})`);
|
|
66265
|
+
}
|
|
66266
|
+
if (!allowPrivate && isBlockedSsrfHost(u.hostname)) {
|
|
66267
|
+
throw new Error(`refusing to fetch a private/loopback/metadata address: ${u.hostname}`);
|
|
66268
|
+
}
|
|
66269
|
+
const res = await fetch(current, { ...fetchInit, redirect: "manual" });
|
|
66270
|
+
if (res.status >= 300 && res.status < 400) {
|
|
66271
|
+
const loc = res.headers.get("location");
|
|
66272
|
+
if (!loc) return res;
|
|
66273
|
+
current = new URL(loc, current).href;
|
|
66274
|
+
continue;
|
|
66275
|
+
}
|
|
66276
|
+
return res;
|
|
66277
|
+
}
|
|
66278
|
+
throw new Error("too many redirects");
|
|
66279
|
+
}
|
|
66280
|
+
function readLocalImageAsDataUri(filePath) {
|
|
66281
|
+
const expanded = filePath.startsWith("~/") ? join10(homedir7(), filePath.slice(2)) : filePath;
|
|
66282
|
+
const refuse = () => new Error(`Not a readable PNG, JPEG or WebP image: ${filePath}`);
|
|
66283
|
+
let fd;
|
|
66284
|
+
try {
|
|
66285
|
+
fd = openSync2(realpathSync(expanded), "r");
|
|
66286
|
+
} catch {
|
|
66287
|
+
throw refuse();
|
|
66288
|
+
}
|
|
66289
|
+
try {
|
|
66290
|
+
const st = fstatSync2(fd);
|
|
66291
|
+
if (!st.isFile() || st.size === 0 || st.size > MAX_LOCAL_IMAGE_BYTES) throw refuse();
|
|
66292
|
+
const head = Buffer.alloc(12);
|
|
66293
|
+
readSync2(fd, head, 0, 12, 0);
|
|
66294
|
+
const sig = IMAGE_SIGNATURES.find((s3) => s3.test(head));
|
|
66295
|
+
if (!sig) throw refuse();
|
|
66296
|
+
const data = Buffer.alloc(st.size);
|
|
66297
|
+
let off = 0;
|
|
66298
|
+
while (off < st.size) {
|
|
66299
|
+
const n = readSync2(fd, data, off, st.size - off, off);
|
|
66300
|
+
if (n === 0) break;
|
|
66301
|
+
off += n;
|
|
66302
|
+
}
|
|
66303
|
+
return `data:${sig.mime};base64,${data.subarray(0, off).toString("base64")}`;
|
|
66304
|
+
} finally {
|
|
66305
|
+
closeSync2(fd);
|
|
66306
|
+
}
|
|
66307
|
+
}
|
|
66308
|
+
var METADATA_HOSTS, MAX_LOCAL_IMAGE_BYTES, IMAGE_SIGNATURES;
|
|
66309
|
+
var init_local_guard = __esm({
|
|
66310
|
+
"src/local-guard.ts"() {
|
|
66311
|
+
"use strict";
|
|
66312
|
+
METADATA_HOSTS = /* @__PURE__ */ new Set(["metadata", "metadata.goog", "instance-data"]);
|
|
66313
|
+
MAX_LOCAL_IMAGE_BYTES = 25 * 1024 * 1024;
|
|
66314
|
+
IMAGE_SIGNATURES = [
|
|
66315
|
+
{
|
|
66316
|
+
mime: "image/png",
|
|
66317
|
+
test: (b) => b.length >= 8 && b.readUInt32BE(0) === 2303741511 && b.readUInt32BE(4) === 218765834
|
|
66318
|
+
},
|
|
66319
|
+
{
|
|
66320
|
+
mime: "image/jpeg",
|
|
66321
|
+
test: (b) => b.length >= 3 && b[0] === 255 && b[1] === 216 && b[2] === 255
|
|
66322
|
+
},
|
|
66323
|
+
{
|
|
66324
|
+
mime: "image/webp",
|
|
66325
|
+
test: (b) => b.length >= 12 && b.toString("ascii", 0, 4) === "RIFF" && b.toString("ascii", 8, 12) === "WEBP"
|
|
66326
|
+
}
|
|
66327
|
+
];
|
|
66328
|
+
}
|
|
66329
|
+
});
|
|
66330
|
+
|
|
66181
66331
|
// node_modules/undici/lib/core/symbols.js
|
|
66182
66332
|
var require_symbols = __commonJS({
|
|
66183
66333
|
"node_modules/undici/lib/core/symbols.js"(exports, module) {
|
|
@@ -93571,8 +93721,8 @@ var init_textual_tool_calls = __esm({
|
|
|
93571
93721
|
|
|
93572
93722
|
// src/response-store.ts
|
|
93573
93723
|
import { appendFile as appendFile2, mkdir as mkdir5, readFile, readdir as readdir2 } from "fs/promises";
|
|
93574
|
-
import { homedir as
|
|
93575
|
-
import { join as
|
|
93724
|
+
import { homedir as homedir8 } from "os";
|
|
93725
|
+
import { join as join11 } from "path";
|
|
93576
93726
|
import { randomBytes as randomBytes7 } from "crypto";
|
|
93577
93727
|
function isEnabled() {
|
|
93578
93728
|
const v = process.env.BLOCKRUN_RESPONSE_STORE;
|
|
@@ -93585,7 +93735,7 @@ async function ensureDir2() {
|
|
|
93585
93735
|
}
|
|
93586
93736
|
function dailyFile(date = /* @__PURE__ */ new Date()) {
|
|
93587
93737
|
const iso = date.toISOString().slice(0, 10);
|
|
93588
|
-
return
|
|
93738
|
+
return join11(STORE_DIR, `responses-${iso}.jsonl`);
|
|
93589
93739
|
}
|
|
93590
93740
|
function genId() {
|
|
93591
93741
|
return `resp_${Date.now()}_${randomBytes7(3).toString("hex")}`;
|
|
@@ -93635,7 +93785,7 @@ async function listRecent(limit = 20, daysBack = 7) {
|
|
|
93635
93785
|
d.setUTCDate(d.getUTCDate() - i);
|
|
93636
93786
|
const iso = d.toISOString().slice(0, 10);
|
|
93637
93787
|
const name = `responses-${iso}.jsonl`;
|
|
93638
|
-
if (files.includes(name)) candidateFiles.push(
|
|
93788
|
+
if (files.includes(name)) candidateFiles.push(join11(STORE_DIR, name));
|
|
93639
93789
|
}
|
|
93640
93790
|
const all3 = [];
|
|
93641
93791
|
for (const f of candidateFiles) {
|
|
@@ -93664,7 +93814,7 @@ var STORE_DIR, dirReady2;
|
|
|
93664
93814
|
var init_response_store = __esm({
|
|
93665
93815
|
"src/response-store.ts"() {
|
|
93666
93816
|
"use strict";
|
|
93667
|
-
STORE_DIR =
|
|
93817
|
+
STORE_DIR = join11(homedir8(), ".openclaw", "blockrun", "responses");
|
|
93668
93818
|
dirReady2 = false;
|
|
93669
93819
|
}
|
|
93670
93820
|
});
|
|
@@ -95301,10 +95451,10 @@ import { createHmac } from "crypto";
|
|
|
95301
95451
|
import { createServer } from "http";
|
|
95302
95452
|
import { finished, Readable } from "stream";
|
|
95303
95453
|
import { pipeline } from "stream/promises";
|
|
95304
|
-
import { homedir as
|
|
95305
|
-
import { join as
|
|
95454
|
+
import { homedir as homedir9 } from "os";
|
|
95455
|
+
import { join as join12 } from "path";
|
|
95306
95456
|
import { mkdir as mkdir6, writeFile as writeFile4, readFile as readFile2, stat as fsStat } from "fs/promises";
|
|
95307
|
-
import { readFileSync as readFileSync2
|
|
95457
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
95308
95458
|
async function loadGatewayCatalog(apiBase, apiKey) {
|
|
95309
95459
|
try {
|
|
95310
95460
|
const controller = new AbortController();
|
|
@@ -96198,22 +96348,6 @@ async function proxyPaidApiRequest(req, res, apiBase, payFetch, getActualPayment
|
|
|
96198
96348
|
}).catch(() => {
|
|
96199
96349
|
});
|
|
96200
96350
|
}
|
|
96201
|
-
function readImageFileAsDataUri(filePath) {
|
|
96202
|
-
const resolved = filePath.startsWith("~/") ? join11(homedir8(), filePath.slice(2)) : filePath;
|
|
96203
|
-
if (!existsSync2(resolved)) {
|
|
96204
|
-
throw new Error(`Image file not found: ${resolved}`);
|
|
96205
|
-
}
|
|
96206
|
-
const ext = resolved.split(".").pop()?.toLowerCase() ?? "png";
|
|
96207
|
-
const mimeMap = {
|
|
96208
|
-
png: "image/png",
|
|
96209
|
-
jpg: "image/jpeg",
|
|
96210
|
-
jpeg: "image/jpeg",
|
|
96211
|
-
webp: "image/webp"
|
|
96212
|
-
};
|
|
96213
|
-
const mime = mimeMap[ext] ?? "image/png";
|
|
96214
|
-
const data = readFileSync2(resolved);
|
|
96215
|
-
return `data:${mime};base64,${data.toString("base64")}`;
|
|
96216
|
-
}
|
|
96217
96351
|
async function uploadDataUriToHost(dataUri) {
|
|
96218
96352
|
const match = dataUri.match(/^data:(image\/\w+);base64,(.+)$/);
|
|
96219
96353
|
if (!match) throw new Error("Invalid data URI format");
|
|
@@ -96490,6 +96624,13 @@ async function startProxy(options) {
|
|
|
96490
96624
|
console.error(`[ClawRouter] Request finished with error: ${err.message}`);
|
|
96491
96625
|
}
|
|
96492
96626
|
});
|
|
96627
|
+
const untrusted = untrustedRequestReason(req);
|
|
96628
|
+
if (untrusted) {
|
|
96629
|
+
console.warn(`[ClawRouter] Refused request to ${req.url}: ${untrusted}`);
|
|
96630
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
96631
|
+
res.end(JSON.stringify({ error: "forbidden", details: untrusted }));
|
|
96632
|
+
return;
|
|
96633
|
+
}
|
|
96493
96634
|
if (req.url === "/health" || req.url?.startsWith("/health?")) {
|
|
96494
96635
|
const url2 = new URL(req.url, "http://localhost");
|
|
96495
96636
|
const full = url2.searchParams.get("full") === "true";
|
|
@@ -96718,7 +96859,7 @@ async function startProxy(options) {
|
|
|
96718
96859
|
res.end("Bad request");
|
|
96719
96860
|
return;
|
|
96720
96861
|
}
|
|
96721
|
-
const filePath =
|
|
96862
|
+
const filePath = join12(IMAGE_DIR, filename);
|
|
96722
96863
|
try {
|
|
96723
96864
|
const s3 = await fsStat(filePath);
|
|
96724
96865
|
if (!s3.isFile()) throw new Error("not a file");
|
|
@@ -96749,7 +96890,7 @@ async function startProxy(options) {
|
|
|
96749
96890
|
res.end("Bad request");
|
|
96750
96891
|
return;
|
|
96751
96892
|
}
|
|
96752
|
-
const filePath =
|
|
96893
|
+
const filePath = join12(AUDIO_DIR, filename);
|
|
96753
96894
|
try {
|
|
96754
96895
|
const s3 = await fsStat(filePath);
|
|
96755
96896
|
if (!s3.isFile()) throw new Error("not a file");
|
|
@@ -96779,7 +96920,7 @@ async function startProxy(options) {
|
|
|
96779
96920
|
res.end("Bad request");
|
|
96780
96921
|
return;
|
|
96781
96922
|
}
|
|
96782
|
-
const filePath =
|
|
96923
|
+
const filePath = join12(VIDEO_DIR, filename);
|
|
96783
96924
|
try {
|
|
96784
96925
|
const s3 = await fsStat(filePath);
|
|
96785
96926
|
if (!s3.isFile()) throw new Error("not a file");
|
|
@@ -96921,7 +97062,7 @@ async function startProxy(options) {
|
|
|
96921
97062
|
const [, mimeType, b64] = dataUriMatch;
|
|
96922
97063
|
const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
|
|
96923
97064
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
96924
|
-
await writeFile4(
|
|
97065
|
+
await writeFile4(join12(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
|
|
96925
97066
|
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
96926
97067
|
console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
|
|
96927
97068
|
} else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
|
|
@@ -96932,7 +97073,7 @@ async function startProxy(options) {
|
|
|
96932
97073
|
const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
|
|
96933
97074
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
96934
97075
|
const buf = Buffer.from(await imgResp.arrayBuffer());
|
|
96935
|
-
await writeFile4(
|
|
97076
|
+
await writeFile4(join12(IMAGE_DIR, filename), buf);
|
|
96936
97077
|
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
96937
97078
|
console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
|
|
96938
97079
|
}
|
|
@@ -96995,7 +97136,10 @@ async function startProxy(options) {
|
|
|
96995
97136
|
if (typeof val !== "string" || !val) continue;
|
|
96996
97137
|
if (val.startsWith("data:")) {
|
|
96997
97138
|
} else if (val.startsWith("https://") || val.startsWith("http://")) {
|
|
96998
|
-
const imgResp = await
|
|
97139
|
+
const imgResp = await ssrfSafeFetch(val, {
|
|
97140
|
+
signal: clientAbort.signal,
|
|
97141
|
+
allowPrivate: process.env.CLAWROUTER_ALLOW_PRIVATE_FETCH === "1"
|
|
97142
|
+
});
|
|
96999
97143
|
if (!imgResp.ok)
|
|
97000
97144
|
throw new Error(`Failed to download ${field} from ${val}: HTTP ${imgResp.status}`);
|
|
97001
97145
|
const contentType = imgResp.headers.get("content-type") ?? "image/png";
|
|
@@ -97005,7 +97149,7 @@ async function startProxy(options) {
|
|
|
97005
97149
|
`[ClawRouter] img2img: downloaded ${field} URL \u2192 data URI (${buf.length} bytes)`
|
|
97006
97150
|
);
|
|
97007
97151
|
} else {
|
|
97008
|
-
parsed[field] =
|
|
97152
|
+
parsed[field] = readLocalImageAsDataUri(val);
|
|
97009
97153
|
console.log(`[ClawRouter] img2img: read ${field} file \u2192 data URI`);
|
|
97010
97154
|
}
|
|
97011
97155
|
}
|
|
@@ -97054,7 +97198,7 @@ async function startProxy(options) {
|
|
|
97054
97198
|
const [, mimeType, b64] = dataUriMatch;
|
|
97055
97199
|
const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
|
|
97056
97200
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
97057
|
-
await writeFile4(
|
|
97201
|
+
await writeFile4(join12(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
|
|
97058
97202
|
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
97059
97203
|
console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
|
|
97060
97204
|
} else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
|
|
@@ -97065,7 +97209,7 @@ async function startProxy(options) {
|
|
|
97065
97209
|
const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
|
|
97066
97210
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
97067
97211
|
const buf = Buffer.from(await imgResp.arrayBuffer());
|
|
97068
|
-
await writeFile4(
|
|
97212
|
+
await writeFile4(join12(IMAGE_DIR, filename), buf);
|
|
97069
97213
|
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
97070
97214
|
console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
|
|
97071
97215
|
}
|
|
@@ -97161,7 +97305,7 @@ async function startProxy(options) {
|
|
|
97161
97305
|
const ext = contentType.includes("wav") ? "wav" : "mp3";
|
|
97162
97306
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
97163
97307
|
const buf = Buffer.from(await audioResp.arrayBuffer());
|
|
97164
|
-
await writeFile4(
|
|
97308
|
+
await writeFile4(join12(AUDIO_DIR, filename), buf);
|
|
97165
97309
|
track.url = `http://localhost:${port2}/audio/${filename}`;
|
|
97166
97310
|
console.log(`[ClawRouter] Audio saved \u2192 ${track.url}`);
|
|
97167
97311
|
}
|
|
@@ -97328,7 +97472,7 @@ async function startProxy(options) {
|
|
|
97328
97472
|
const ext = contentType.includes("webm") ? "webm" : contentType.includes("quicktime") ? "mov" : "mp4";
|
|
97329
97473
|
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
97330
97474
|
const buf = Buffer.from(await videoResp.arrayBuffer());
|
|
97331
|
-
await writeFile4(
|
|
97475
|
+
await writeFile4(join12(VIDEO_DIR, filename), buf);
|
|
97332
97476
|
clip.url = `http://localhost:${port2}/videos/${filename}`;
|
|
97333
97477
|
console.log(`[ClawRouter] Video saved \u2192 ${clip.url}`);
|
|
97334
97478
|
}
|
|
@@ -98294,8 +98438,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
98294
98438
|
let imageDataUri;
|
|
98295
98439
|
let maskDataUri;
|
|
98296
98440
|
try {
|
|
98297
|
-
imageDataUri =
|
|
98298
|
-
if (maskPath) maskDataUri =
|
|
98441
|
+
imageDataUri = readLocalImageAsDataUri(imagePath);
|
|
98442
|
+
if (maskPath) maskDataUri = readLocalImageAsDataUri(maskPath);
|
|
98299
98443
|
} catch (fileErr) {
|
|
98300
98444
|
const fileErrMsg = fileErr instanceof Error ? fileErr.message : String(fileErr);
|
|
98301
98445
|
sendImg2ImgText(`Failed to read image file: ${fileErrMsg}`);
|
|
@@ -100033,6 +100177,7 @@ var init_proxy = __esm({
|
|
|
100033
100177
|
init_outcome_memory();
|
|
100034
100178
|
init_config();
|
|
100035
100179
|
init_journal();
|
|
100180
|
+
init_local_guard();
|
|
100036
100181
|
init_upstream_proxy();
|
|
100037
100182
|
init_textual_tool_calls();
|
|
100038
100183
|
init_response_store();
|
|
@@ -100041,10 +100186,10 @@ var init_proxy = __esm({
|
|
|
100041
100186
|
paymentStore = new AsyncLocalStorage();
|
|
100042
100187
|
BLOCKRUN_API = "https://blockrun.ai/api";
|
|
100043
100188
|
BLOCKRUN_SOLANA_API = "https://sol.blockrun.ai/api";
|
|
100044
|
-
DESKTOP_SERVICE_TOKEN_FILE = process.env.CLAWROUTER_DESKTOP_TOKEN_FILE ??
|
|
100045
|
-
IMAGE_DIR =
|
|
100046
|
-
AUDIO_DIR =
|
|
100047
|
-
VIDEO_DIR =
|
|
100189
|
+
DESKTOP_SERVICE_TOKEN_FILE = process.env.CLAWROUTER_DESKTOP_TOKEN_FILE ?? join12(homedir9(), ".clawrouter-desktop", "service-token");
|
|
100190
|
+
IMAGE_DIR = join12(homedir9(), ".openclaw", "blockrun", "images");
|
|
100191
|
+
AUDIO_DIR = join12(homedir9(), ".openclaw", "blockrun", "audio");
|
|
100192
|
+
VIDEO_DIR = join12(homedir9(), ".openclaw", "blockrun", "videos");
|
|
100048
100193
|
AUTO_MODEL = "blockrun/auto";
|
|
100049
100194
|
ROUTING_PROFILES = /* @__PURE__ */ new Set([
|
|
100050
100195
|
"blockrun/eco",
|
|
@@ -101154,7 +101299,13 @@ function buildTool(service, proxyBaseUrl) {
|
|
|
101154
101299
|
if (service.proxyPath === "/pm/__dynamic__") {
|
|
101155
101300
|
const rawPath = typeof params.path === "string" ? params.path : "";
|
|
101156
101301
|
const normalized = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
101157
|
-
|
|
101302
|
+
let resolved;
|
|
101303
|
+
try {
|
|
101304
|
+
resolved = new URL(`/v1${normalized}`, "http://x").pathname;
|
|
101305
|
+
} catch {
|
|
101306
|
+
resolved = "";
|
|
101307
|
+
}
|
|
101308
|
+
if (!normalized.startsWith("/pm/") || normalized.includes("..") || /%2e|%2f|%5c|\\/i.test(normalized) || !resolved.startsWith("/v1/pm/")) {
|
|
101158
101309
|
throw new Error(
|
|
101159
101310
|
`predexon_endpoint_call: invalid path '${rawPath}' \u2014 must begin with '/pm/' and contain no '..'`
|
|
101160
101311
|
);
|
|
@@ -101493,8 +101644,8 @@ __export(reconcile_exports, {
|
|
|
101493
101644
|
reconcile: () => reconcile
|
|
101494
101645
|
});
|
|
101495
101646
|
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
101496
|
-
import { join as
|
|
101497
|
-
import { homedir as
|
|
101647
|
+
import { join as join13 } from "path";
|
|
101648
|
+
import { homedir as homedir10 } from "os";
|
|
101498
101649
|
async function loadLocalRows(since) {
|
|
101499
101650
|
let files;
|
|
101500
101651
|
try {
|
|
@@ -101507,7 +101658,7 @@ async function loadLocalRows(since) {
|
|
|
101507
101658
|
for (const file of files) {
|
|
101508
101659
|
let text;
|
|
101509
101660
|
try {
|
|
101510
|
-
text = await readFile3(
|
|
101661
|
+
text = await readFile3(join13(LOG_DIR3, file), "utf8");
|
|
101511
101662
|
} catch {
|
|
101512
101663
|
continue;
|
|
101513
101664
|
}
|
|
@@ -101665,7 +101816,7 @@ var init_reconcile = __esm({
|
|
|
101665
101816
|
"src/reconcile.ts"() {
|
|
101666
101817
|
"use strict";
|
|
101667
101818
|
init_api_key();
|
|
101668
|
-
LOG_DIR3 =
|
|
101819
|
+
LOG_DIR3 = join13(homedir10(), ".openclaw", "blockrun", "logs");
|
|
101669
101820
|
CENT_EPSILON = 1e-9;
|
|
101670
101821
|
usd = (n) => Math.abs(n) < 0.01 ? `$${n.toFixed(6)}` : `$${n.toFixed(2)}`;
|
|
101671
101822
|
}
|
|
@@ -122657,8 +122808,8 @@ var init_constants3 = __esm({
|
|
|
122657
122808
|
|
|
122658
122809
|
// src/polymarket/wallet-adapter.ts
|
|
122659
122810
|
import fs2 from "fs";
|
|
122660
|
-
import { homedir as
|
|
122661
|
-
import { join as
|
|
122811
|
+
import { homedir as homedir11 } from "os";
|
|
122812
|
+
import { join as join14 } from "path";
|
|
122662
122813
|
function getOrCreateWalletKey() {
|
|
122663
122814
|
const envKey = process.env.BLOCKRUN_WALLET_KEY?.trim();
|
|
122664
122815
|
if (envKey && /^0x[0-9a-fA-F]{64}$/.test(envKey)) return envKey;
|
|
@@ -122706,7 +122857,7 @@ var init_wallet_adapter = __esm({
|
|
|
122706
122857
|
init_esm();
|
|
122707
122858
|
init_chains();
|
|
122708
122859
|
init_constants3();
|
|
122709
|
-
WALLET_FILE2 =
|
|
122860
|
+
WALLET_FILE2 = join14(homedir11(), ".openclaw", "blockrun", "wallet.key");
|
|
122710
122861
|
BASE_RPC_URLS = [
|
|
122711
122862
|
"https://mainnet.base.org",
|
|
122712
122863
|
"https://base.llamarpc.com",
|
|
@@ -233099,7 +233250,7 @@ __export(index_exports, {
|
|
|
233099
233250
|
});
|
|
233100
233251
|
import {
|
|
233101
233252
|
writeFileSync as writeFileSync3,
|
|
233102
|
-
existsSync as
|
|
233253
|
+
existsSync as existsSync3,
|
|
233103
233254
|
readdirSync,
|
|
233104
233255
|
mkdirSync as mkdirSync3,
|
|
233105
233256
|
copyFileSync,
|
|
@@ -233108,9 +233259,9 @@ import {
|
|
|
233108
233259
|
unlinkSync
|
|
233109
233260
|
} from "fs";
|
|
233110
233261
|
import { readFile as readFileAsync } from "fs/promises";
|
|
233111
|
-
import { homedir as
|
|
233262
|
+
import { homedir as homedir16 } from "os";
|
|
233112
233263
|
import { randomUUID } from "crypto";
|
|
233113
|
-
import { join as
|
|
233264
|
+
import { join as join19 } from "path";
|
|
233114
233265
|
async function waitForProxyHealth(port, timeoutMs = 3e3) {
|
|
233115
233266
|
const start = Date.now();
|
|
233116
233267
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -233130,12 +233281,12 @@ function writePrivateJsonSync(path5, value) {
|
|
|
233130
233281
|
renameSync2(temporary, path5);
|
|
233131
233282
|
chmodSync(path5, 384);
|
|
233132
233283
|
} finally {
|
|
233133
|
-
if (
|
|
233284
|
+
if (existsSync3(temporary)) unlinkSync(temporary);
|
|
233134
233285
|
}
|
|
233135
233286
|
}
|
|
233136
233287
|
function hasConfiguredWallet() {
|
|
233137
233288
|
return Boolean(
|
|
233138
|
-
process["env"].BLOCKRUN_WALLET_KEY ||
|
|
233289
|
+
process["env"].BLOCKRUN_WALLET_KEY || existsSync3(CORE_WALLET_FILE) || existsSync3(WALLET_FILE)
|
|
233139
233290
|
);
|
|
233140
233291
|
}
|
|
233141
233292
|
function isCompletionMode() {
|
|
@@ -233153,11 +233304,11 @@ function isBlockrunWebSearchDisabled(config) {
|
|
|
233153
233304
|
}
|
|
233154
233305
|
function legacyPackageIsBlockRun() {
|
|
233155
233306
|
for (const dir of [
|
|
233156
|
-
|
|
233157
|
-
|
|
233307
|
+
join19(homedir16(), ".openclaw", "extensions", "clawrouter"),
|
|
233308
|
+
join19(homedir16(), ".openclaw", "npm", "node_modules", "@blockrun", "clawrouter")
|
|
233158
233309
|
]) {
|
|
233159
233310
|
try {
|
|
233160
|
-
const metadata = JSON.parse(readTextFileSync(
|
|
233311
|
+
const metadata = JSON.parse(readTextFileSync(join19(dir, "package.json")));
|
|
233161
233312
|
if (metadata.name === "@blockrun/clawrouter") return true;
|
|
233162
233313
|
} catch {
|
|
233163
233314
|
}
|
|
@@ -233165,11 +233316,11 @@ function legacyPackageIsBlockRun() {
|
|
|
233165
233316
|
return false;
|
|
233166
233317
|
}
|
|
233167
233318
|
function injectModelsConfig(logger48, options = {}) {
|
|
233168
|
-
const configDir =
|
|
233169
|
-
const configPath =
|
|
233319
|
+
const configDir = join19(homedir16(), ".openclaw");
|
|
233320
|
+
const configPath = join19(configDir, "openclaw.json");
|
|
233170
233321
|
let config = {};
|
|
233171
233322
|
let needsWrite = false;
|
|
233172
|
-
if (!
|
|
233323
|
+
if (!existsSync3(configDir)) {
|
|
233173
233324
|
try {
|
|
233174
233325
|
mkdirSync3(configDir, { recursive: true });
|
|
233175
233326
|
logger48.info("Created OpenClaw config directory");
|
|
@@ -233180,7 +233331,7 @@ function injectModelsConfig(logger48, options = {}) {
|
|
|
233180
233331
|
return;
|
|
233181
233332
|
}
|
|
233182
233333
|
}
|
|
233183
|
-
if (
|
|
233334
|
+
if (existsSync3(configPath)) {
|
|
233184
233335
|
try {
|
|
233185
233336
|
const content = readTextFileSync(configPath).trim();
|
|
233186
233337
|
if (content) {
|
|
@@ -233387,8 +233538,8 @@ function injectModelsConfig(logger48, options = {}) {
|
|
|
233387
233538
|
}
|
|
233388
233539
|
function syncAgentModelCache(logger48, options = {}) {
|
|
233389
233540
|
if (!isGatewayMode() && !options.forceWrite) return;
|
|
233390
|
-
const agentsDir =
|
|
233391
|
-
if (!
|
|
233541
|
+
const agentsDir = join19(homedir16(), ".openclaw", "agents");
|
|
233542
|
+
if (!existsSync3(agentsDir)) return;
|
|
233392
233543
|
let agentDirs;
|
|
233393
233544
|
try {
|
|
233394
233545
|
agentDirs = readdirSync(agentsDir);
|
|
@@ -233397,8 +233548,8 @@ function syncAgentModelCache(logger48, options = {}) {
|
|
|
233397
233548
|
}
|
|
233398
233549
|
const expectedIds = VISIBLE_OPENCLAW_MODELS.map((m) => m.id);
|
|
233399
233550
|
for (const agent of agentDirs) {
|
|
233400
|
-
const cachePath =
|
|
233401
|
-
if (!
|
|
233551
|
+
const cachePath = join19(agentsDir, agent, "agent", "models.json");
|
|
233552
|
+
if (!existsSync3(cachePath)) continue;
|
|
233402
233553
|
try {
|
|
233403
233554
|
const raw = readTextFileSync(cachePath).trim();
|
|
233404
233555
|
if (!raw) continue;
|
|
@@ -233426,8 +233577,8 @@ function syncAgentModelCache(logger48, options = {}) {
|
|
|
233426
233577
|
}
|
|
233427
233578
|
}
|
|
233428
233579
|
function injectAuthProfile(logger48) {
|
|
233429
|
-
const agentsDir =
|
|
233430
|
-
if (!
|
|
233580
|
+
const agentsDir = join19(homedir16(), ".openclaw", "agents");
|
|
233581
|
+
if (!existsSync3(agentsDir)) {
|
|
233431
233582
|
try {
|
|
233432
233583
|
mkdirSync3(agentsDir, { recursive: true });
|
|
233433
233584
|
} catch (err) {
|
|
@@ -233443,10 +233594,10 @@ function injectAuthProfile(logger48) {
|
|
|
233443
233594
|
agents = ["main", ...agents];
|
|
233444
233595
|
}
|
|
233445
233596
|
for (const agentId of agents) {
|
|
233446
|
-
const authDir =
|
|
233447
|
-
const authPath =
|
|
233448
|
-
const sqlitePath =
|
|
233449
|
-
if (
|
|
233597
|
+
const authDir = join19(agentsDir, agentId, "agent");
|
|
233598
|
+
const authPath = join19(authDir, "auth-profiles.json");
|
|
233599
|
+
const sqlitePath = join19(authDir, "openclaw-agent.sqlite");
|
|
233600
|
+
if (existsSync3(sqlitePath)) {
|
|
233450
233601
|
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
233451
233602
|
continue;
|
|
233452
233603
|
}
|
|
@@ -233454,7 +233605,7 @@ function injectAuthProfile(logger48) {
|
|
|
233454
233605
|
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
233455
233606
|
continue;
|
|
233456
233607
|
}
|
|
233457
|
-
if (!
|
|
233608
|
+
if (!existsSync3(authDir)) {
|
|
233458
233609
|
try {
|
|
233459
233610
|
mkdirSync3(authDir, { recursive: true });
|
|
233460
233611
|
} catch {
|
|
@@ -233465,7 +233616,7 @@ function injectAuthProfile(logger48) {
|
|
|
233465
233616
|
version: 1,
|
|
233466
233617
|
profiles: {}
|
|
233467
233618
|
};
|
|
233468
|
-
if (
|
|
233619
|
+
if (existsSync3(authPath)) {
|
|
233469
233620
|
try {
|
|
233470
233621
|
const existing = JSON.parse(readTextFileSync(authPath));
|
|
233471
233622
|
if (existing.version && existing.profiles) {
|
|
@@ -233498,7 +233649,7 @@ function injectAuthProfile(logger48) {
|
|
|
233498
233649
|
}
|
|
233499
233650
|
function removeInjectedAuthPlaceholder(authPath, logger48, agentId) {
|
|
233500
233651
|
try {
|
|
233501
|
-
if (!
|
|
233652
|
+
if (!existsSync3(authPath)) return;
|
|
233502
233653
|
const parsed = JSON.parse(readTextFileSync(authPath));
|
|
233503
233654
|
const profiles = parsed?.profiles;
|
|
233504
233655
|
if (!profiles || typeof profiles !== "object" || Array.isArray(profiles)) return;
|
|
@@ -233953,7 +234104,7 @@ function buildImageGenerationProvider() {
|
|
|
233953
234104
|
(result.data ?? []).map(async (img) => {
|
|
233954
234105
|
const filename = img.url?.split("/images/").pop();
|
|
233955
234106
|
if (!filename) throw new Error(`Unexpected image URL format: ${img.url}`);
|
|
233956
|
-
const filePath =
|
|
234107
|
+
const filePath = join19(IMAGE_DIR2, filename);
|
|
233957
234108
|
const buffer2 = await readFileAsync(filePath);
|
|
233958
234109
|
const ext = filename.split(".").pop()?.toLowerCase() ?? "png";
|
|
233959
234110
|
const mimeType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "webp" ? "image/webp" : "image/png";
|
|
@@ -234005,7 +234156,7 @@ function buildMusicGenerationProvider() {
|
|
|
234005
234156
|
(result.data ?? []).map(async (track) => {
|
|
234006
234157
|
const filename = track.url?.split("/audio/").pop();
|
|
234007
234158
|
if (!filename) throw new Error(`Unexpected audio URL format: ${track.url}`);
|
|
234008
|
-
const filePath =
|
|
234159
|
+
const filePath = join19(AUDIO_DIR2, filename);
|
|
234009
234160
|
const buffer2 = await readFileAsync(filePath);
|
|
234010
234161
|
const ext = filename.split(".").pop()?.toLowerCase() ?? "mp3";
|
|
234011
234162
|
const mimeType = ext === "wav" ? "audio/wav" : "audio/mpeg";
|
|
@@ -234081,7 +234232,7 @@ function buildVideoGenerationProvider() {
|
|
|
234081
234232
|
(result.data ?? []).map(async (clip) => {
|
|
234082
234233
|
const filename = clip.url?.split("/videos/").pop();
|
|
234083
234234
|
if (!filename) throw new Error(`Unexpected video URL format: ${clip.url}`);
|
|
234084
|
-
const filePath =
|
|
234235
|
+
const filePath = join19(VIDEO_DIR2, filename);
|
|
234085
234236
|
const buffer2 = await readFileAsync(filePath);
|
|
234086
234237
|
const ext = filename.split(".").pop()?.toLowerCase() ?? "mp4";
|
|
234087
234238
|
const mimeType = ext === "webm" ? "video/webm" : ext === "mov" ? "video/quicktime" : "video/mp4";
|
|
@@ -234182,7 +234333,7 @@ function createWalletCommand(api) {
|
|
|
234182
234333
|
];
|
|
234183
234334
|
let hasMnemonic3 = false;
|
|
234184
234335
|
try {
|
|
234185
|
-
if (
|
|
234336
|
+
if (existsSync3(MNEMONIC_FILE)) {
|
|
234186
234337
|
const mnemonic = readTextFileSync(MNEMONIC_FILE).trim();
|
|
234187
234338
|
if (mnemonic) {
|
|
234188
234339
|
hasMnemonic3 = true;
|
|
@@ -234253,7 +234404,7 @@ function createWalletCommand(api) {
|
|
|
234253
234404
|
].join("\n")
|
|
234254
234405
|
};
|
|
234255
234406
|
}
|
|
234256
|
-
if (
|
|
234407
|
+
if (existsSync3(MNEMONIC_FILE)) {
|
|
234257
234408
|
const existingMnemonic = readTextFileSync(MNEMONIC_FILE).trim();
|
|
234258
234409
|
if (existingMnemonic) {
|
|
234259
234410
|
await savePaymentChain("solana");
|
|
@@ -234446,9 +234597,9 @@ var init_index = __esm({
|
|
|
234446
234597
|
init_partners();
|
|
234447
234598
|
activeProxyHandle = null;
|
|
234448
234599
|
pendingConfiguredStartupApi = null;
|
|
234449
|
-
IMAGE_DIR2 =
|
|
234450
|
-
AUDIO_DIR2 =
|
|
234451
|
-
VIDEO_DIR2 =
|
|
234600
|
+
IMAGE_DIR2 = join19(homedir16(), ".openclaw", "blockrun", "images");
|
|
234601
|
+
AUDIO_DIR2 = join19(homedir16(), ".openclaw", "blockrun", "audio");
|
|
234602
|
+
VIDEO_DIR2 = join19(homedir16(), ".openclaw", "blockrun", "videos");
|
|
234452
234603
|
plugin = {
|
|
234453
234604
|
// NOT "clawrouter". OpenClaw bundles its own plugin under that id since the
|
|
234454
234605
|
// 2026.7.1 line (vendored at dist/extensions/clawrouter, provider `clawrouter/*`,
|
|
@@ -234588,7 +234739,8 @@ var init_index = __esm({
|
|
|
234588
234739
|
name: "cr-imagegen",
|
|
234589
234740
|
description: "Generate an image (BlockRun image models, paid via wallet)",
|
|
234590
234741
|
acceptsArgs: true,
|
|
234591
|
-
|
|
234742
|
+
// Paid from the wallet: only authorized senders.
|
|
234743
|
+
requireAuth: true,
|
|
234592
234744
|
handler: async (ctx) => {
|
|
234593
234745
|
const parsed = parseGenArgs(ctx.args ?? "");
|
|
234594
234746
|
if (!parsed.prompt) {
|
|
@@ -234640,7 +234792,8 @@ ${errText}`
|
|
|
234640
234792
|
name: "videogen",
|
|
234641
234793
|
description: "Generate a short video (Grok Imagine / Seedance, paid via wallet)",
|
|
234642
234794
|
acceptsArgs: true,
|
|
234643
|
-
|
|
234795
|
+
// Paid from the wallet: only authorized senders.
|
|
234796
|
+
requireAuth: true,
|
|
234644
234797
|
handler: async (ctx) => {
|
|
234645
234798
|
const parsed = parseGenArgs(ctx.args ?? "");
|
|
234646
234799
|
if (!parsed.prompt) {
|
|
@@ -234689,7 +234842,8 @@ ${errText}`
|
|
|
234689
234842
|
name: "cr-call",
|
|
234690
234843
|
description: "Place an AI voice call via BlockRun + Bland.ai (paid from wallet, $0.54/call)",
|
|
234691
234844
|
acceptsArgs: true,
|
|
234692
|
-
|
|
234845
|
+
// Paid from the wallet: only authorized senders.
|
|
234846
|
+
requireAuth: true,
|
|
234693
234847
|
handler: async (ctx) => {
|
|
234694
234848
|
const parsed = parseCallArgs(ctx.args ?? "");
|
|
234695
234849
|
if (!parsed.to || !parsed.task) {
|
|
@@ -234886,8 +235040,8 @@ ${errText}`
|
|
|
234886
235040
|
}
|
|
234887
235041
|
resetProxyStartupState();
|
|
234888
235042
|
try {
|
|
234889
|
-
const configPath =
|
|
234890
|
-
if (
|
|
235043
|
+
const configPath = join19(homedir16(), ".openclaw", "openclaw.json");
|
|
235044
|
+
if (existsSync3(configPath)) {
|
|
234891
235045
|
const config = JSON.parse(readTextFileSync(configPath));
|
|
234892
235046
|
if (config.models?.providers?.blockrun) {
|
|
234893
235047
|
delete config.models.providers.blockrun;
|
|
@@ -234928,12 +235082,12 @@ ${errText}`
|
|
|
234928
235082
|
api.logger.warn(`Config cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
234929
235083
|
}
|
|
234930
235084
|
try {
|
|
234931
|
-
const agentsDir =
|
|
234932
|
-
if (
|
|
235085
|
+
const agentsDir = join19(homedir16(), ".openclaw", "agents");
|
|
235086
|
+
if (existsSync3(agentsDir)) {
|
|
234933
235087
|
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
234934
235088
|
if (!entry.isDirectory()) continue;
|
|
234935
|
-
const authPath =
|
|
234936
|
-
if (!
|
|
235089
|
+
const authPath = join19(agentsDir, entry.name, "agent", "auth-profiles.json");
|
|
235090
|
+
if (!existsSync3(authPath)) continue;
|
|
234937
235091
|
try {
|
|
234938
235092
|
const store = JSON.parse(readTextFileSync(authPath));
|
|
234939
235093
|
if (store.profiles?.["blockrun:default"]) {
|
|
@@ -235018,7 +235172,7 @@ init_proxy();
|
|
|
235018
235172
|
init_spend_control();
|
|
235019
235173
|
init_version4();
|
|
235020
235174
|
import { platform, arch, freemem, totalmem } from "os";
|
|
235021
|
-
import { existsSync as
|
|
235175
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
235022
235176
|
function formatBytes(bytes) {
|
|
235023
235177
|
const gb = bytes / (1024 * 1024 * 1024);
|
|
235024
235178
|
return `${gb.toFixed(1)}GB`;
|
|
@@ -235388,7 +235542,7 @@ async function analyzeWithAI(diagnostics, userQuestion, model = "sonnet") {
|
|
|
235388
235542
|
const paymentChain = diagnostics.wallet.paymentChain;
|
|
235389
235543
|
if (paymentChain === "solana") {
|
|
235390
235544
|
try {
|
|
235391
|
-
if (!
|
|
235545
|
+
if (!existsSync2(MNEMONIC_FILE)) {
|
|
235392
235546
|
throw new Error(`mnemonic file missing at ${MNEMONIC_FILE}`);
|
|
235393
235547
|
}
|
|
235394
235548
|
const mnemonic = readFileSync3(MNEMONIC_FILE, "utf8").trim();
|
|
@@ -236037,7 +236191,7 @@ async function cmdSetup() {
|
|
|
236037
236191
|
const {
|
|
236038
236192
|
copyFileSync: copyFileSync2,
|
|
236039
236193
|
cpSync,
|
|
236040
|
-
existsSync:
|
|
236194
|
+
existsSync: existsSync4,
|
|
236041
236195
|
mkdirSync: mkdirSync4,
|
|
236042
236196
|
readFileSync: readFileSync4,
|
|
236043
236197
|
readdirSync: readdirSync2,
|
|
@@ -236046,8 +236200,8 @@ async function cmdSetup() {
|
|
|
236046
236200
|
unlinkSync: unlinkSync2,
|
|
236047
236201
|
writeFileSync: writeFileSync4
|
|
236048
236202
|
} = await import("fs");
|
|
236049
|
-
const { dirname: dirname5, join:
|
|
236050
|
-
const { homedir:
|
|
236203
|
+
const { dirname: dirname5, join: join20 } = await import("path");
|
|
236204
|
+
const { homedir: homedir17 } = await import("os");
|
|
236051
236205
|
const { injectModelsConfig: injectModelsConfig2, injectAuthProfile: injectAuthProfile2, syncAgentModelCache: syncAgentModelCache2, VISIBLE_OPENCLAW_MODELS: VISIBLE_OPENCLAW_MODELS2 } = await Promise.resolve().then(() => (init_index(), index_exports));
|
|
236052
236206
|
const { BLOCKRUN_PLUGIN_ID: BLOCKRUN_PLUGIN_ID2, prepareBlockRunPluginConfig: prepareBlockRunPluginConfig2 } = await Promise.resolve().then(() => (init_openclaw_plugin_config(), openclaw_plugin_config_exports));
|
|
236053
236207
|
console.log("\u{1F99E} ClawRouter setup\n");
|
|
@@ -236062,22 +236216,22 @@ async function cmdSetup() {
|
|
|
236062
236216
|
} catch {
|
|
236063
236217
|
}
|
|
236064
236218
|
if (process.env.npm_config_prefix) {
|
|
236065
|
-
candidates.push(
|
|
236219
|
+
candidates.push(join20(process.env.npm_config_prefix, "bin", "openclaw"));
|
|
236066
236220
|
}
|
|
236067
236221
|
try {
|
|
236068
236222
|
const npmRoot = execSync("npm root -g", {
|
|
236069
236223
|
encoding: "utf8",
|
|
236070
236224
|
stdio: ["ignore", "pipe", "ignore"]
|
|
236071
236225
|
}).trim();
|
|
236072
|
-
if (npmRoot) candidates.push(
|
|
236226
|
+
if (npmRoot) candidates.push(join20(dirname5(dirname5(npmRoot)), "bin", "openclaw"));
|
|
236073
236227
|
} catch {
|
|
236074
236228
|
}
|
|
236075
236229
|
candidates.push(
|
|
236076
|
-
|
|
236077
|
-
|
|
236230
|
+
join20(homedir17(), ".npm-global", "bin", "openclaw"),
|
|
236231
|
+
join20(homedir17(), ".local", "bin", "openclaw"),
|
|
236078
236232
|
"/usr/local/bin/openclaw"
|
|
236079
236233
|
);
|
|
236080
|
-
return candidates.find((candidate) =>
|
|
236234
|
+
return candidates.find((candidate) => existsSync4(candidate)) ?? "";
|
|
236081
236235
|
})();
|
|
236082
236236
|
if (!openclawPath) {
|
|
236083
236237
|
console.error(" \u2717 openclaw not found on PATH");
|
|
@@ -236086,31 +236240,31 @@ async function cmdSetup() {
|
|
|
236086
236240
|
process.exit(1);
|
|
236087
236241
|
}
|
|
236088
236242
|
console.log(` \u2713 Found openclaw at ${openclawPath}`);
|
|
236089
|
-
const configPath =
|
|
236090
|
-
const configInitiallyExisted =
|
|
236243
|
+
const configPath = join20(homedir17(), ".openclaw", "openclaw.json");
|
|
236244
|
+
const configInitiallyExisted = existsSync4(configPath);
|
|
236091
236245
|
const configRollbackBackup = configInitiallyExisted ? `${configPath}.before-${BLOCKRUN_PLUGIN_ID2}.${Date.now()}` : void 0;
|
|
236092
236246
|
if (configRollbackBackup) copyFileSync2(configPath, configRollbackBackup);
|
|
236093
236247
|
const ensureConfigRollbackBackup = () => {
|
|
236094
236248
|
return configRollbackBackup;
|
|
236095
236249
|
};
|
|
236096
236250
|
let installAttempted = false;
|
|
236097
|
-
const openclawRoot =
|
|
236251
|
+
const openclawRoot = join20(homedir17(), ".openclaw");
|
|
236098
236252
|
const findManagedBlockRunInstalls = () => {
|
|
236099
236253
|
const candidates = [
|
|
236100
|
-
|
|
236101
|
-
|
|
236102
|
-
|
|
236254
|
+
join20(openclawRoot, "extensions", BLOCKRUN_PLUGIN_ID2),
|
|
236255
|
+
join20(openclawRoot, "extensions", "clawrouter"),
|
|
236256
|
+
join20(openclawRoot, "npm", "node_modules", "@blockrun", "clawrouter")
|
|
236103
236257
|
];
|
|
236104
|
-
const projectsDir =
|
|
236258
|
+
const projectsDir = join20(openclawRoot, "npm", "projects");
|
|
236105
236259
|
try {
|
|
236106
236260
|
for (const project of readdirSync2(projectsDir)) {
|
|
236107
|
-
candidates.push(
|
|
236261
|
+
candidates.push(join20(projectsDir, project, "node_modules", "@blockrun", "clawrouter"));
|
|
236108
236262
|
}
|
|
236109
236263
|
} catch {
|
|
236110
236264
|
}
|
|
236111
236265
|
return [...new Set(candidates)].filter((candidate) => {
|
|
236112
236266
|
try {
|
|
236113
|
-
const metadata = JSON.parse(readFileSync4(
|
|
236267
|
+
const metadata = JSON.parse(readFileSync4(join20(candidate, "package.json"), "utf8"));
|
|
236114
236268
|
return metadata.name === "@blockrun/clawrouter";
|
|
236115
236269
|
} catch {
|
|
236116
236270
|
return false;
|
|
@@ -236118,7 +236272,7 @@ async function cmdSetup() {
|
|
|
236118
236272
|
});
|
|
236119
236273
|
};
|
|
236120
236274
|
const initialPluginDirs = findManagedBlockRunInstalls();
|
|
236121
|
-
const setupRollbackRoot =
|
|
236275
|
+
const setupRollbackRoot = join20(
|
|
236122
236276
|
openclawRoot,
|
|
236123
236277
|
"blockrun",
|
|
236124
236278
|
"setup-rollbacks",
|
|
@@ -236128,16 +236282,16 @@ async function cmdSetup() {
|
|
|
236128
236282
|
if (initialPluginDirs.length > 0) {
|
|
236129
236283
|
mkdirSync4(setupRollbackRoot, { recursive: true, mode: 448 });
|
|
236130
236284
|
for (const [index2, pluginDir] of initialPluginDirs.entries()) {
|
|
236131
|
-
const backup =
|
|
236285
|
+
const backup = join20(setupRollbackRoot, String(index2));
|
|
236132
236286
|
cpSync(pluginDir, backup, { recursive: true });
|
|
236133
236287
|
pluginRollbackBackups.set(pluginDir, backup);
|
|
236134
236288
|
}
|
|
236135
236289
|
}
|
|
236136
236290
|
const restoreSetupConfig = () => {
|
|
236137
|
-
if (configRollbackBackup &&
|
|
236291
|
+
if (configRollbackBackup && existsSync4(configRollbackBackup)) {
|
|
236138
236292
|
copyFileSync2(configRollbackBackup, configPath);
|
|
236139
236293
|
console.error(` \u2713 Restored original OpenClaw config from ${configRollbackBackup}`);
|
|
236140
|
-
} else if (!configInitiallyExisted &&
|
|
236294
|
+
} else if (!configInitiallyExisted && existsSync4(configPath)) {
|
|
236141
236295
|
rmSync(configPath);
|
|
236142
236296
|
console.error(" \u2713 Removed the partially created OpenClaw config");
|
|
236143
236297
|
}
|
|
@@ -236159,7 +236313,7 @@ async function cmdSetup() {
|
|
|
236159
236313
|
}
|
|
236160
236314
|
}
|
|
236161
236315
|
for (const [pluginDir, backup] of pluginRollbackBackups) {
|
|
236162
|
-
if (!
|
|
236316
|
+
if (!existsSync4(backup)) continue;
|
|
236163
236317
|
rmSync(pluginDir, { recursive: true, force: true });
|
|
236164
236318
|
mkdirSync4(dirname5(pluginDir), { recursive: true });
|
|
236165
236319
|
cpSync(backup, pluginDir, { recursive: true });
|
|
@@ -236170,17 +236324,17 @@ async function cmdSetup() {
|
|
|
236170
236324
|
};
|
|
236171
236325
|
let legacyBlockRunInstall = false;
|
|
236172
236326
|
let stagedLegacyEntry;
|
|
236173
|
-
if (
|
|
236327
|
+
if (existsSync4(configPath)) {
|
|
236174
236328
|
try {
|
|
236175
236329
|
const config = JSON.parse(readFileSync4(configPath, "utf8"));
|
|
236176
|
-
const legacyPackagePath =
|
|
236177
|
-
|
|
236330
|
+
const legacyPackagePath = join20(
|
|
236331
|
+
homedir17(),
|
|
236178
236332
|
".openclaw",
|
|
236179
236333
|
"extensions",
|
|
236180
236334
|
"clawrouter",
|
|
236181
236335
|
"package.json"
|
|
236182
236336
|
);
|
|
236183
|
-
if (
|
|
236337
|
+
if (existsSync4(legacyPackagePath)) {
|
|
236184
236338
|
try {
|
|
236185
236339
|
const legacyPackage = JSON.parse(readFileSync4(legacyPackagePath, "utf8"));
|
|
236186
236340
|
legacyBlockRunInstall = legacyPackage.name === "@blockrun/clawrouter";
|
|
@@ -236261,7 +236415,7 @@ async function cmdSetup() {
|
|
|
236261
236415
|
);
|
|
236262
236416
|
process.exit(1);
|
|
236263
236417
|
}
|
|
236264
|
-
if (
|
|
236418
|
+
if (existsSync4(configPath)) {
|
|
236265
236419
|
try {
|
|
236266
236420
|
const config = JSON.parse(readFileSync4(configPath, "utf8"));
|
|
236267
236421
|
if (stagedLegacyEntry) {
|
|
@@ -236303,7 +236457,7 @@ async function cmdSetup() {
|
|
|
236303
236457
|
info: (msg) => console.log(` ${msg}`)
|
|
236304
236458
|
};
|
|
236305
236459
|
try {
|
|
236306
|
-
if (
|
|
236460
|
+
if (existsSync4(configPath)) ensureConfigRollbackBackup();
|
|
236307
236461
|
injectModelsConfig2(setupLogger, { forceWrite: true });
|
|
236308
236462
|
syncAgentModelCache2(setupLogger, { forceWrite: true });
|
|
236309
236463
|
injectAuthProfile2(setupLogger);
|
|
@@ -236314,7 +236468,7 @@ async function cmdSetup() {
|
|
|
236314
236468
|
}
|
|
236315
236469
|
console.log("\n\u2713 Setup complete.");
|
|
236316
236470
|
rmSync(setupRollbackRoot, { recursive: true, force: true });
|
|
236317
|
-
if (configRollbackBackup &&
|
|
236471
|
+
if (configRollbackBackup && existsSync4(configRollbackBackup)) {
|
|
236318
236472
|
unlinkSync2(configRollbackBackup);
|
|
236319
236473
|
}
|
|
236320
236474
|
console.log("\nNext: restart the gateway to load ClawRouter:");
|