@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.
Files changed (3) hide show
  1. package/dist/cli.js +276 -122
  2. package/dist/index.js +241 -87
  3. 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 homedir7 } from "os";
93575
- import { join as join10 } from "path";
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 join10(STORE_DIR, `responses-${iso}.jsonl`);
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(join10(STORE_DIR, name));
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 = join10(homedir7(), ".openclaw", "blockrun", "responses");
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 homedir8 } from "os";
95305
- import { join as join11 } from "path";
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, existsSync as existsSync2 } from "fs";
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 = join11(IMAGE_DIR, filename);
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 = join11(AUDIO_DIR, filename);
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 = join11(VIDEO_DIR, filename);
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(join11(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
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(join11(IMAGE_DIR, filename), buf);
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 fetch(val, { signal: clientAbort.signal });
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] = readImageFileAsDataUri(val);
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(join11(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
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(join11(IMAGE_DIR, filename), buf);
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(join11(AUDIO_DIR, filename), buf);
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(join11(VIDEO_DIR, filename), buf);
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 = readImageFileAsDataUri(imagePath);
98298
- if (maskPath) maskDataUri = readImageFileAsDataUri(maskPath);
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 ?? join11(homedir8(), ".clawrouter-desktop", "service-token");
100045
- IMAGE_DIR = join11(homedir8(), ".openclaw", "blockrun", "images");
100046
- AUDIO_DIR = join11(homedir8(), ".openclaw", "blockrun", "audio");
100047
- VIDEO_DIR = join11(homedir8(), ".openclaw", "blockrun", "videos");
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
- if (!normalized.startsWith("/pm/") || normalized.includes("..")) {
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 join12 } from "path";
101497
- import { homedir as homedir9 } from "os";
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(join12(LOG_DIR3, file), "utf8");
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 = join12(homedir9(), ".openclaw", "blockrun", "logs");
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 homedir10 } from "os";
122661
- import { join as join13 } from "path";
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 = join13(homedir10(), ".openclaw", "blockrun", "wallet.key");
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 existsSync4,
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 homedir15 } from "os";
233262
+ import { homedir as homedir16 } from "os";
233112
233263
  import { randomUUID } from "crypto";
233113
- import { join as join18 } from "path";
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 (existsSync4(temporary)) unlinkSync(temporary);
233284
+ if (existsSync3(temporary)) unlinkSync(temporary);
233134
233285
  }
233135
233286
  }
233136
233287
  function hasConfiguredWallet() {
233137
233288
  return Boolean(
233138
- process["env"].BLOCKRUN_WALLET_KEY || existsSync4(CORE_WALLET_FILE) || existsSync4(WALLET_FILE)
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
- join18(homedir15(), ".openclaw", "extensions", "clawrouter"),
233157
- join18(homedir15(), ".openclaw", "npm", "node_modules", "@blockrun", "clawrouter")
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(join18(dir, "package.json")));
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 = join18(homedir15(), ".openclaw");
233169
- const configPath = join18(configDir, "openclaw.json");
233319
+ const configDir = join19(homedir16(), ".openclaw");
233320
+ const configPath = join19(configDir, "openclaw.json");
233170
233321
  let config = {};
233171
233322
  let needsWrite = false;
233172
- if (!existsSync4(configDir)) {
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 (existsSync4(configPath)) {
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 = join18(homedir15(), ".openclaw", "agents");
233391
- if (!existsSync4(agentsDir)) return;
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 = join18(agentsDir, agent, "agent", "models.json");
233401
- if (!existsSync4(cachePath)) continue;
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 = join18(homedir15(), ".openclaw", "agents");
233430
- if (!existsSync4(agentsDir)) {
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 = join18(agentsDir, agentId, "agent");
233447
- const authPath = join18(authDir, "auth-profiles.json");
233448
- const sqlitePath = join18(authDir, "openclaw-agent.sqlite");
233449
- if (existsSync4(sqlitePath)) {
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 (!existsSync4(authDir)) {
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 (existsSync4(authPath)) {
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 (!existsSync4(authPath)) return;
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 = join18(IMAGE_DIR2, filename);
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 = join18(AUDIO_DIR2, filename);
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 = join18(VIDEO_DIR2, filename);
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 (existsSync4(MNEMONIC_FILE)) {
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 (existsSync4(MNEMONIC_FILE)) {
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 = join18(homedir15(), ".openclaw", "blockrun", "images");
234450
- AUDIO_DIR2 = join18(homedir15(), ".openclaw", "blockrun", "audio");
234451
- VIDEO_DIR2 = join18(homedir15(), ".openclaw", "blockrun", "videos");
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
- requireAuth: false,
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
- requireAuth: false,
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
- requireAuth: false,
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 = join18(homedir15(), ".openclaw", "openclaw.json");
234890
- if (existsSync4(configPath)) {
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 = join18(homedir15(), ".openclaw", "agents");
234932
- if (existsSync4(agentsDir)) {
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 = join18(agentsDir, entry.name, "agent", "auth-profiles.json");
234936
- if (!existsSync4(authPath)) continue;
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 existsSync3, readFileSync as readFileSync3 } from "fs";
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 (!existsSync3(MNEMONIC_FILE)) {
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: existsSync5,
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: join19 } = await import("path");
236050
- const { homedir: homedir16 } = await import("os");
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(join19(process.env.npm_config_prefix, "bin", "openclaw"));
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(join19(dirname5(dirname5(npmRoot)), "bin", "openclaw"));
236226
+ if (npmRoot) candidates.push(join20(dirname5(dirname5(npmRoot)), "bin", "openclaw"));
236073
236227
  } catch {
236074
236228
  }
236075
236229
  candidates.push(
236076
- join19(homedir16(), ".npm-global", "bin", "openclaw"),
236077
- join19(homedir16(), ".local", "bin", "openclaw"),
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) => existsSync5(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 = join19(homedir16(), ".openclaw", "openclaw.json");
236090
- const configInitiallyExisted = existsSync5(configPath);
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 = join19(homedir16(), ".openclaw");
236251
+ const openclawRoot = join20(homedir17(), ".openclaw");
236098
236252
  const findManagedBlockRunInstalls = () => {
236099
236253
  const candidates = [
236100
- join19(openclawRoot, "extensions", BLOCKRUN_PLUGIN_ID2),
236101
- join19(openclawRoot, "extensions", "clawrouter"),
236102
- join19(openclawRoot, "npm", "node_modules", "@blockrun", "clawrouter")
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 = join19(openclawRoot, "npm", "projects");
236258
+ const projectsDir = join20(openclawRoot, "npm", "projects");
236105
236259
  try {
236106
236260
  for (const project of readdirSync2(projectsDir)) {
236107
- candidates.push(join19(projectsDir, project, "node_modules", "@blockrun", "clawrouter"));
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(join19(candidate, "package.json"), "utf8"));
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 = join19(
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 = join19(setupRollbackRoot, String(index2));
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 && existsSync5(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 && existsSync5(configPath)) {
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 (!existsSync5(backup)) continue;
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 (existsSync5(configPath)) {
236327
+ if (existsSync4(configPath)) {
236174
236328
  try {
236175
236329
  const config = JSON.parse(readFileSync4(configPath, "utf8"));
236176
- const legacyPackagePath = join19(
236177
- homedir16(),
236330
+ const legacyPackagePath = join20(
236331
+ homedir17(),
236178
236332
  ".openclaw",
236179
236333
  "extensions",
236180
236334
  "clawrouter",
236181
236335
  "package.json"
236182
236336
  );
236183
- if (existsSync5(legacyPackagePath)) {
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 (existsSync5(configPath)) {
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 (existsSync5(configPath)) ensureConfigRollbackBackup();
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 && existsSync5(configRollbackBackup)) {
236471
+ if (configRollbackBackup && existsSync4(configRollbackBackup)) {
236318
236472
  unlinkSync2(configRollbackBackup);
236319
236473
  }
236320
236474
  console.log("\nNext: restart the gateway to load ClawRouter:");