@blockrun/clawrouter 0.12.256 → 0.12.257

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/index.js CHANGED
@@ -29310,8 +29310,8 @@ var init_parseUtil = __esm({
29310
29310
  init_errors4();
29311
29311
  init_en();
29312
29312
  makeIssue = (params) => {
29313
- const { data, path: path6, errorMaps, issueData } = params;
29314
- const fullPath = [...path6, ...issueData.path || []];
29313
+ const { data, path: path5, errorMaps, issueData } = params;
29314
+ const fullPath = [...path5, ...issueData.path || []];
29315
29315
  const fullIssue = {
29316
29316
  ...issueData,
29317
29317
  path: fullPath
@@ -29622,11 +29622,11 @@ var init_types = __esm({
29622
29622
  init_parseUtil();
29623
29623
  init_util();
29624
29624
  ParseInputLazyPath = class {
29625
- constructor(parent, value, path6, key2) {
29625
+ constructor(parent, value, path5, key2) {
29626
29626
  this._cachedPath = [];
29627
29627
  this.parent = parent;
29628
29628
  this.data = value;
29629
- this._path = path6;
29629
+ this._path = path5;
29630
29630
  this._key = key2;
29631
29631
  }
29632
29632
  get path() {
@@ -34035,6 +34035,613 @@ var init_max_tokens = __esm({
34035
34035
  }
34036
34036
  });
34037
34037
 
34038
+ // src/fs-read.ts
34039
+ import { open } from "fs/promises";
34040
+ import { openSync, readSync, closeSync, fstatSync } from "fs";
34041
+ async function readTextFile(filePath) {
34042
+ const fh = await open(filePath, "r");
34043
+ try {
34044
+ const size5 = (await fh.stat()).size;
34045
+ const buf = Buffer.alloc(size5);
34046
+ let offset = 0;
34047
+ while (offset < size5) {
34048
+ const { bytesRead } = await fh.read(buf, offset, size5 - offset, offset);
34049
+ if (bytesRead === 0) break;
34050
+ offset += bytesRead;
34051
+ }
34052
+ return buf.subarray(0, offset).toString("utf-8");
34053
+ } finally {
34054
+ await fh.close();
34055
+ }
34056
+ }
34057
+ function readTextFileSync(filePath) {
34058
+ const fd = openSync(filePath, "r");
34059
+ try {
34060
+ const size5 = fstatSync(fd).size;
34061
+ const buf = Buffer.alloc(size5);
34062
+ let offset = 0;
34063
+ while (offset < size5) {
34064
+ const bytesRead = readSync(fd, buf, offset, size5 - offset, offset);
34065
+ if (bytesRead === 0) break;
34066
+ offset += bytesRead;
34067
+ }
34068
+ return buf.subarray(0, offset).toString("utf-8");
34069
+ } finally {
34070
+ closeSync(fd);
34071
+ }
34072
+ }
34073
+ var init_fs_read = __esm({
34074
+ "src/fs-read.ts"() {
34075
+ "use strict";
34076
+ }
34077
+ });
34078
+
34079
+ // src/spend-control.ts
34080
+ import * as fs from "fs";
34081
+ import * as path from "path";
34082
+ import { homedir } from "os";
34083
+ function normalizePayee(value) {
34084
+ return EVM_ADDRESS.test(value) ? value.toLowerCase() : value;
34085
+ }
34086
+ function isAddressList(list) {
34087
+ return ADDRESS_LISTS.includes(list);
34088
+ }
34089
+ function normalizePolicyValues(list, values) {
34090
+ return isAddressList(list) ? values.map(normalizePayee) : [...values];
34091
+ }
34092
+ function isValidPolicyValues(values) {
34093
+ return Array.isArray(values) && values.every((v) => typeof v === "string" && v.length > 0);
34094
+ }
34095
+ function isPolicyList(value) {
34096
+ return POLICY_LISTS.includes(value);
34097
+ }
34098
+ function cloneLimits(limits) {
34099
+ const clone = { ...limits };
34100
+ for (const key2 of POLICY_LISTS) {
34101
+ const val = limits[key2];
34102
+ if (val !== void 0) {
34103
+ clone[key2] = [...val];
34104
+ }
34105
+ }
34106
+ return clone;
34107
+ }
34108
+ function parseQuotedAmountUsd(selected) {
34109
+ const raw = selected.amount ?? selected.maxAmountRequired;
34110
+ if (typeof raw !== "string" || !CANONICAL_AMOUNT.test(raw)) {
34111
+ return void 0;
34112
+ }
34113
+ const micros = Number(raw);
34114
+ if (!Number.isSafeInteger(micros)) {
34115
+ return void 0;
34116
+ }
34117
+ return micros / 1e6;
34118
+ }
34119
+ function assertSpendPolicyAllows(control, selected) {
34120
+ const quoted = parseQuotedAmountUsd(selected);
34121
+ if (quoted === void 0 && control.hasAmountLimits()) {
34122
+ throw new SpendPolicyError(
34123
+ `Payment quote carries no usable amount (${JSON.stringify(
34124
+ selected.amount ?? selected.maxAmountRequired
34125
+ )}); refusing to sign against a configured spend limit`
34126
+ );
34127
+ }
34128
+ const estimatedCost2 = quoted ?? 0;
34129
+ const result = control.check(estimatedCost2, {
34130
+ payTo: selected.payTo,
34131
+ network: selected.network,
34132
+ asset: selected.asset
34133
+ });
34134
+ if (!result.allowed) {
34135
+ throw new SpendPolicyError(result.reason ?? "blocked by spend policy", {
34136
+ blockedBy: result.blockedBy,
34137
+ blockedByPolicy: result.blockedByPolicy
34138
+ });
34139
+ }
34140
+ if (!control.hasAggregateLimits()) {
34141
+ return void 0;
34142
+ }
34143
+ return control.reserve(estimatedCost2);
34144
+ }
34145
+ function registerSpendPolicyHook(x402, control) {
34146
+ const reservations = /* @__PURE__ */ new WeakMap();
34147
+ x402.onBeforePaymentCreation(async (ctx) => {
34148
+ const selected = ctx.selectedRequirements;
34149
+ const reservationId = assertSpendPolicyAllows(control, selected);
34150
+ if (reservationId !== void 0) {
34151
+ reservations.set(ctx.selectedRequirements, reservationId);
34152
+ }
34153
+ });
34154
+ x402.onAfterPaymentCreation(async (ctx) => {
34155
+ const key2 = ctx.selectedRequirements;
34156
+ const id2 = reservations.get(key2);
34157
+ if (id2 !== void 0) {
34158
+ reservations.delete(key2);
34159
+ control.settleReservation(id2, { action: "x402 payment" });
34160
+ }
34161
+ });
34162
+ x402.onPaymentCreationFailure(async (ctx) => {
34163
+ const key2 = ctx.selectedRequirements;
34164
+ const id2 = reservations.get(key2);
34165
+ if (id2 !== void 0) {
34166
+ reservations.delete(key2);
34167
+ control.releaseReservation(id2);
34168
+ }
34169
+ });
34170
+ }
34171
+ function formatDuration(seconds) {
34172
+ if (seconds < 60) {
34173
+ return `${seconds}s`;
34174
+ } else if (seconds < 3600) {
34175
+ const mins = Math.ceil(seconds / 60);
34176
+ return `${mins} min`;
34177
+ } else {
34178
+ const hours = Math.floor(seconds / 3600);
34179
+ const mins = Math.ceil(seconds % 3600 / 60);
34180
+ return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
34181
+ }
34182
+ }
34183
+ var WALLET_DIR, HOUR_MS, DAY_MS, CAIP2_BASE, CAIP2_SOLANA_MAINNET, POLICY_LISTS, ADDRESS_LISTS, EVM_ADDRESS, MalformedSpendPolicyError, FileSpendControlStorage, InMemorySpendControlStorage, RESERVATION_TTL_MS, SpendControl, SpendPolicyError, CANONICAL_AMOUNT;
34184
+ var init_spend_control = __esm({
34185
+ "src/spend-control.ts"() {
34186
+ "use strict";
34187
+ init_fs_read();
34188
+ WALLET_DIR = path.join(homedir(), ".openclaw", "blockrun");
34189
+ HOUR_MS = 60 * 60 * 1e3;
34190
+ DAY_MS = 24 * HOUR_MS;
34191
+ CAIP2_BASE = "eip155:8453";
34192
+ CAIP2_SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
34193
+ POLICY_LISTS = [
34194
+ "allowedPayees",
34195
+ "blockedPayees",
34196
+ "allowedNetworks",
34197
+ "allowedAssets"
34198
+ ];
34199
+ ADDRESS_LISTS = ["allowedPayees", "blockedPayees", "allowedAssets"];
34200
+ EVM_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
34201
+ MalformedSpendPolicyError = class extends Error {
34202
+ constructor(key2) {
34203
+ super(
34204
+ `[ClawRouter] refusing to load spending.json: ${key2} is malformed; a corrupted policy file must not widen what the agent may pay`
34205
+ );
34206
+ this.name = "MalformedSpendPolicyError";
34207
+ }
34208
+ };
34209
+ FileSpendControlStorage = class {
34210
+ spendingFile;
34211
+ constructor() {
34212
+ this.spendingFile = path.join(WALLET_DIR, "spending.json");
34213
+ }
34214
+ load() {
34215
+ try {
34216
+ if (fs.existsSync(this.spendingFile)) {
34217
+ const data = JSON.parse(readTextFileSync(this.spendingFile));
34218
+ const rawLimits = data.limits ?? {};
34219
+ const rawHistory = data.history ?? [];
34220
+ const limits = {};
34221
+ for (const key2 of ["perRequest", "hourly", "daily", "session"]) {
34222
+ const val = rawLimits[key2];
34223
+ if (typeof val === "number" && val > 0 && Number.isFinite(val)) {
34224
+ limits[key2] = val;
34225
+ }
34226
+ }
34227
+ for (const key2 of POLICY_LISTS) {
34228
+ if (!Object.prototype.hasOwnProperty.call(rawLimits, key2)) continue;
34229
+ const val = rawLimits[key2];
34230
+ if (!isValidPolicyValues(val)) {
34231
+ throw new MalformedSpendPolicyError(key2);
34232
+ }
34233
+ if (val.length === 0) continue;
34234
+ limits[key2] = normalizePolicyValues(key2, val);
34235
+ }
34236
+ const history = [];
34237
+ if (Array.isArray(rawHistory)) {
34238
+ for (const r2 of rawHistory) {
34239
+ if (typeof r2?.timestamp === "number" && typeof r2?.amount === "number" && Number.isFinite(r2.timestamp) && Number.isFinite(r2.amount) && r2.amount >= 0) {
34240
+ history.push({
34241
+ timestamp: r2.timestamp,
34242
+ amount: r2.amount,
34243
+ model: typeof r2.model === "string" ? r2.model : void 0,
34244
+ action: typeof r2.action === "string" ? r2.action : void 0
34245
+ });
34246
+ }
34247
+ }
34248
+ }
34249
+ return { limits, history };
34250
+ }
34251
+ } catch (err) {
34252
+ if (err instanceof MalformedSpendPolicyError) {
34253
+ throw err;
34254
+ }
34255
+ console.error(
34256
+ `[ClawRouter] Failed to load spending data, starting fresh (any configured spend policy is NOT in effect until this file is repaired): ${err}`
34257
+ );
34258
+ }
34259
+ return null;
34260
+ }
34261
+ save(data) {
34262
+ try {
34263
+ if (!fs.existsSync(WALLET_DIR)) {
34264
+ fs.mkdirSync(WALLET_DIR, { recursive: true, mode: 448 });
34265
+ }
34266
+ const tmp = `${this.spendingFile}.${process.pid}.tmp`;
34267
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
34268
+ fs.renameSync(tmp, this.spendingFile);
34269
+ } catch (err) {
34270
+ console.error(`[ClawRouter] Failed to save spending data: ${err}`);
34271
+ }
34272
+ }
34273
+ /**
34274
+ * Persist history while leaving the stored limits exactly as they are on
34275
+ * disk. Recording spend must not rewrite policy: the proxy reads limits once
34276
+ * at startup, so writing its in-memory copy back on every payment would
34277
+ * erase an operator's hand-edit to spending.json seconds after they made it.
34278
+ */
34279
+ saveHistory(history) {
34280
+ let storedLimits = {};
34281
+ try {
34282
+ const current = this.load();
34283
+ if (current) storedLimits = current.limits;
34284
+ } catch {
34285
+ return;
34286
+ }
34287
+ this.save({ limits: storedLimits, history });
34288
+ }
34289
+ };
34290
+ InMemorySpendControlStorage = class {
34291
+ data = null;
34292
+ load() {
34293
+ return this.data ? {
34294
+ limits: cloneLimits(this.data.limits),
34295
+ history: this.data.history.map((r2) => ({ ...r2 }))
34296
+ } : null;
34297
+ }
34298
+ save(data) {
34299
+ this.data = {
34300
+ limits: cloneLimits(data.limits),
34301
+ history: data.history.map((r2) => ({ ...r2 }))
34302
+ };
34303
+ }
34304
+ };
34305
+ RESERVATION_TTL_MS = 2 * 60 * 1e3;
34306
+ SpendControl = class {
34307
+ limits = {};
34308
+ history = [];
34309
+ sessionSpent = 0;
34310
+ sessionCalls = 0;
34311
+ pending = /* @__PURE__ */ new Map();
34312
+ reservationSeq = 0;
34313
+ /** Limits we loaded and have not changed; history-only saves must not clobber operator edits. */
34314
+ limitsDirty = false;
34315
+ /** Set when spending.json held an unusable policy list: refuse every payment. */
34316
+ policyFileBroken;
34317
+ storage;
34318
+ now;
34319
+ constructor(options) {
34320
+ this.storage = options?.storage ?? new FileSpendControlStorage();
34321
+ this.now = options?.now ?? (() => Date.now());
34322
+ this.load();
34323
+ }
34324
+ setLimit(window2, amount) {
34325
+ if (!Number.isFinite(amount) || amount <= 0) {
34326
+ throw new Error("Limit must be a finite positive number");
34327
+ }
34328
+ this.limits[window2] = amount;
34329
+ this.limitsDirty = true;
34330
+ this.save();
34331
+ }
34332
+ clearLimit(window2) {
34333
+ delete this.limits[window2];
34334
+ this.limitsDirty = true;
34335
+ this.save();
34336
+ }
34337
+ setPolicy(list, values) {
34338
+ if (!isPolicyList(list)) {
34339
+ throw new Error(`Unknown policy list: ${String(list)}`);
34340
+ }
34341
+ if (!isValidPolicyValues(values) || values.length === 0) {
34342
+ throw new Error("Policy list must be a non-empty array of non-empty strings");
34343
+ }
34344
+ this.limits[list] = normalizePolicyValues(list, values);
34345
+ this.limitsDirty = true;
34346
+ this.save();
34347
+ }
34348
+ clearPolicy(list) {
34349
+ if (!isPolicyList(list)) {
34350
+ throw new Error(`Unknown policy list: ${String(list)}`);
34351
+ }
34352
+ delete this.limits[list];
34353
+ this.limitsDirty = true;
34354
+ this.save();
34355
+ }
34356
+ getLimits() {
34357
+ return cloneLimits(this.limits);
34358
+ }
34359
+ check(estimatedCost2, counterparty) {
34360
+ if (this.policyFileBroken !== void 0) {
34361
+ return {
34362
+ allowed: false,
34363
+ reason: `Spend policy is unreadable, refusing all payments: ${this.policyFileBroken}`
34364
+ };
34365
+ }
34366
+ const payeePolicySet = this.limits.blockedPayees && this.limits.blockedPayees.length > 0 || this.limits.allowedPayees && this.limits.allowedPayees.length > 0;
34367
+ if (payeePolicySet) {
34368
+ if (counterparty?.payTo === void 0) {
34369
+ return {
34370
+ allowed: false,
34371
+ blockedByPolicy: this.limits.blockedPayees?.length ? "blockedPayees" : "allowedPayees",
34372
+ reason: "Payee policy is configured but no payTo was provided to check()"
34373
+ };
34374
+ }
34375
+ const payTo = normalizePayee(counterparty.payTo);
34376
+ if (this.limits.blockedPayees?.includes(payTo)) {
34377
+ return {
34378
+ allowed: false,
34379
+ blockedByPolicy: "blockedPayees",
34380
+ reason: `Payee is blocked by policy: ${counterparty.payTo}`
34381
+ };
34382
+ }
34383
+ if (this.limits.allowedPayees && this.limits.allowedPayees.length > 0 && !this.limits.allowedPayees.includes(payTo)) {
34384
+ return {
34385
+ allowed: false,
34386
+ blockedByPolicy: "allowedPayees",
34387
+ reason: `Payee is not in the configured allowlist: ${counterparty.payTo}`
34388
+ };
34389
+ }
34390
+ }
34391
+ if (this.limits.allowedNetworks && this.limits.allowedNetworks.length > 0) {
34392
+ if (counterparty?.network === void 0) {
34393
+ return {
34394
+ allowed: false,
34395
+ blockedByPolicy: "allowedNetworks",
34396
+ reason: "Network policy is configured but no network was provided to check()"
34397
+ };
34398
+ }
34399
+ if (!this.limits.allowedNetworks.includes(counterparty.network)) {
34400
+ return {
34401
+ allowed: false,
34402
+ blockedByPolicy: "allowedNetworks",
34403
+ reason: `Network is not in the configured allowlist: ${counterparty.network}`
34404
+ };
34405
+ }
34406
+ }
34407
+ if (this.limits.allowedAssets && this.limits.allowedAssets.length > 0) {
34408
+ if (counterparty?.asset === void 0) {
34409
+ return {
34410
+ allowed: false,
34411
+ blockedByPolicy: "allowedAssets",
34412
+ reason: "Asset policy is configured but no asset was provided to check()"
34413
+ };
34414
+ }
34415
+ if (!this.limits.allowedAssets.includes(normalizePayee(counterparty.asset))) {
34416
+ return {
34417
+ allowed: false,
34418
+ blockedByPolicy: "allowedAssets",
34419
+ reason: `Asset is not in the configured allowlist: ${counterparty.asset}`
34420
+ };
34421
+ }
34422
+ }
34423
+ const now2 = this.now();
34424
+ if (this.limits.perRequest !== void 0) {
34425
+ if (estimatedCost2 > this.limits.perRequest) {
34426
+ return {
34427
+ allowed: false,
34428
+ blockedBy: "perRequest",
34429
+ remaining: this.limits.perRequest,
34430
+ reason: `Per-request limit exceeded: $${estimatedCost2.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
34431
+ };
34432
+ }
34433
+ }
34434
+ if (this.limits.hourly !== void 0) {
34435
+ const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
34436
+ const remaining = this.limits.hourly - hourlySpent;
34437
+ if (estimatedCost2 > remaining) {
34438
+ const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - HOUR_MS);
34439
+ const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now2) / 1e3) : 0;
34440
+ return {
34441
+ allowed: false,
34442
+ blockedBy: "hourly",
34443
+ remaining,
34444
+ reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost2).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
34445
+ resetIn
34446
+ };
34447
+ }
34448
+ }
34449
+ if (this.limits.daily !== void 0) {
34450
+ const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
34451
+ const remaining = this.limits.daily - dailySpent;
34452
+ if (estimatedCost2 > remaining) {
34453
+ const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - DAY_MS);
34454
+ const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + DAY_MS - now2) / 1e3) : 0;
34455
+ return {
34456
+ allowed: false,
34457
+ blockedBy: "daily",
34458
+ remaining,
34459
+ reason: `Daily limit exceeded: $${(dailySpent + estimatedCost2).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
34460
+ resetIn
34461
+ };
34462
+ }
34463
+ }
34464
+ if (this.limits.session !== void 0) {
34465
+ const sessionSpent = this.sessionSpent + this.pendingTotal();
34466
+ const remaining = this.limits.session - sessionSpent;
34467
+ if (estimatedCost2 > remaining) {
34468
+ return {
34469
+ allowed: false,
34470
+ blockedBy: "session",
34471
+ remaining,
34472
+ reason: `Session limit exceeded: $${(sessionSpent + estimatedCost2).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
34473
+ };
34474
+ }
34475
+ }
34476
+ return { allowed: true };
34477
+ }
34478
+ record(amount, metadata) {
34479
+ if (!Number.isFinite(amount) || amount < 0) {
34480
+ throw new Error("Record amount must be a non-negative finite number");
34481
+ }
34482
+ const record = {
34483
+ timestamp: this.now(),
34484
+ amount,
34485
+ model: metadata?.model,
34486
+ action: metadata?.action
34487
+ };
34488
+ this.history.push(record);
34489
+ this.sessionSpent += amount;
34490
+ this.sessionCalls += 1;
34491
+ this.cleanup();
34492
+ this.save();
34493
+ }
34494
+ /** True when any window that this module can compare an amount against is set. */
34495
+ hasAmountLimits() {
34496
+ return this.limits.perRequest !== void 0 || this.limits.hourly !== void 0 || this.limits.daily !== void 0 || this.limits.session !== void 0;
34497
+ }
34498
+ /** True when a window spans more than one request, so reservations matter. */
34499
+ hasAggregateLimits() {
34500
+ return this.limits.hourly !== void 0 || this.limits.daily !== void 0 || this.limits.session !== void 0;
34501
+ }
34502
+ /**
34503
+ * Hold `amount` against the aggregate windows before a payment is signed.
34504
+ *
34505
+ * Reservations live in memory only and are never persisted: an unsettled
34506
+ * reservation is not spend, and writing it to disk is what made a failed
34507
+ * signer permanently consume budget. They expire on their own so a caller
34508
+ * that never settles or releases (process killed mid-payment, a transport
34509
+ * that hangs past the payment timeout) cannot wedge the window shut.
34510
+ */
34511
+ reserve(amount) {
34512
+ if (!Number.isFinite(amount) || amount < 0) {
34513
+ throw new Error("Reservation amount must be a non-negative finite number");
34514
+ }
34515
+ const id2 = `${this.now()}-${this.reservationSeq += 1}`;
34516
+ this.pending.set(id2, { amount, expiresAt: this.now() + RESERVATION_TTL_MS });
34517
+ return id2;
34518
+ }
34519
+ /** Convert a reservation into recorded spend (the payment was signed). */
34520
+ settleReservation(id2, metadata) {
34521
+ const held = this.pending.get(id2);
34522
+ if (!held) return;
34523
+ this.pending.delete(id2);
34524
+ this.record(held.amount, metadata);
34525
+ }
34526
+ /** Drop a reservation without recording spend (the payment was never signed). */
34527
+ releaseReservation(id2) {
34528
+ this.pending.delete(id2);
34529
+ }
34530
+ /** Total currently held but not yet settled. */
34531
+ pendingTotal() {
34532
+ this.expireReservations();
34533
+ let total = 0;
34534
+ for (const held of this.pending.values()) {
34535
+ total += held.amount;
34536
+ }
34537
+ return total;
34538
+ }
34539
+ expireReservations() {
34540
+ const now2 = this.now();
34541
+ for (const [id2, held] of this.pending) {
34542
+ if (held.expiresAt <= now2) {
34543
+ this.pending.delete(id2);
34544
+ }
34545
+ }
34546
+ }
34547
+ getSpendingInWindow(from15, to) {
34548
+ const recorded = this.history.filter((r2) => r2.timestamp >= from15 && r2.timestamp <= to).reduce((sum, r2) => sum + r2.amount, 0);
34549
+ return recorded + (to >= this.now() ? this.pendingTotal() : 0);
34550
+ }
34551
+ getSpending(window2) {
34552
+ const now2 = this.now();
34553
+ switch (window2) {
34554
+ case "hourly":
34555
+ return this.getSpendingInWindow(now2 - HOUR_MS, now2);
34556
+ case "daily":
34557
+ return this.getSpendingInWindow(now2 - DAY_MS, now2);
34558
+ case "session":
34559
+ return this.sessionSpent + this.pendingTotal();
34560
+ }
34561
+ }
34562
+ getRemaining(window2) {
34563
+ const limit = this.limits[window2];
34564
+ if (limit === void 0) return null;
34565
+ return Math.max(0, limit - this.getSpending(window2));
34566
+ }
34567
+ getStatus() {
34568
+ const now2 = this.now();
34569
+ const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
34570
+ const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
34571
+ return {
34572
+ limits: cloneLimits(this.limits),
34573
+ spending: {
34574
+ hourly: hourlySpent,
34575
+ daily: dailySpent,
34576
+ session: this.sessionSpent
34577
+ },
34578
+ remaining: {
34579
+ hourly: this.limits.hourly !== void 0 ? this.limits.hourly - hourlySpent : null,
34580
+ daily: this.limits.daily !== void 0 ? this.limits.daily - dailySpent : null,
34581
+ session: this.limits.session !== void 0 ? this.limits.session - (this.sessionSpent + this.pendingTotal()) : null
34582
+ },
34583
+ calls: this.sessionCalls
34584
+ };
34585
+ }
34586
+ getHistory(limit) {
34587
+ const records = [...this.history].reverse();
34588
+ return limit ? records.slice(0, limit) : records;
34589
+ }
34590
+ resetSession() {
34591
+ this.sessionSpent = 0;
34592
+ this.sessionCalls = 0;
34593
+ }
34594
+ cleanup() {
34595
+ const cutoff = this.now() - DAY_MS;
34596
+ this.history = this.history.filter((r2) => r2.timestamp >= cutoff);
34597
+ }
34598
+ save() {
34599
+ if (this.policyFileBroken !== void 0) {
34600
+ return;
34601
+ }
34602
+ if (!this.limitsDirty && this.storage.saveHistory) {
34603
+ this.storage.saveHistory([...this.history]);
34604
+ return;
34605
+ }
34606
+ this.storage.save({
34607
+ limits: cloneLimits(this.limits),
34608
+ history: [...this.history]
34609
+ });
34610
+ }
34611
+ load() {
34612
+ let data;
34613
+ try {
34614
+ data = this.storage.load();
34615
+ } catch (err) {
34616
+ if (!(err instanceof MalformedSpendPolicyError)) throw err;
34617
+ this.policyFileBroken = err.message;
34618
+ console.error(`[ClawRouter] ${err.message}`);
34619
+ console.error(
34620
+ "[ClawRouter] All paid requests will be refused until spending.json is repaired. Free models are unaffected."
34621
+ );
34622
+ return;
34623
+ }
34624
+ if (data) {
34625
+ this.limits = cloneLimits(data.limits);
34626
+ this.history = data.history;
34627
+ this.cleanup();
34628
+ }
34629
+ }
34630
+ };
34631
+ SpendPolicyError = class extends Error {
34632
+ blockedBy;
34633
+ blockedByPolicy;
34634
+ constructor(reason, blocked) {
34635
+ super(`Payment creation aborted: ${reason}`);
34636
+ this.name = "SpendPolicyError";
34637
+ this.blockedBy = blocked?.blockedBy;
34638
+ this.blockedByPolicy = blocked?.blockedByPolicy;
34639
+ }
34640
+ };
34641
+ CANONICAL_AMOUNT = /^\d+$/;
34642
+ }
34643
+ });
34644
+
34038
34645
  // src/payment-preauth.ts
34039
34646
  function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, options) {
34040
34647
  const httpClient = new x402HTTPClient(client);
@@ -34079,8 +34686,11 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
34079
34686
  return response2;
34080
34687
  }
34081
34688
  cache2.delete(cacheKey2);
34082
- } catch {
34689
+ } catch (err) {
34083
34690
  cache2.delete(cacheKey2);
34691
+ if (err instanceof SpendPolicyError) {
34692
+ throw err;
34693
+ }
34084
34694
  }
34085
34695
  }
34086
34696
  const clonedRequest = request2.clone();
@@ -34124,6 +34734,7 @@ var init_payment_preauth = __esm({
34124
34734
  "use strict";
34125
34735
  init_esm4();
34126
34736
  init_max_tokens();
34737
+ init_spend_control();
34127
34738
  DEFAULT_TTL_MS = 36e5;
34128
34739
  }
34129
34740
  });
@@ -38823,8 +39434,8 @@ var init_router = __esm({
38823
39434
 
38824
39435
  // src/logger.ts
38825
39436
  import { appendFile, mkdir } from "fs/promises";
38826
- import { join as join2 } from "path";
38827
- import { homedir } from "os";
39437
+ import { join as join3 } from "path";
39438
+ import { homedir as homedir2 } from "os";
38828
39439
  async function ensureDir() {
38829
39440
  if (dirReady) return;
38830
39441
  await mkdir(LOG_DIR, { recursive: true });
@@ -38834,7 +39445,7 @@ async function logUsage(entry) {
38834
39445
  try {
38835
39446
  await ensureDir();
38836
39447
  const date = entry.timestamp.slice(0, 10);
38837
- const file = join2(LOG_DIR, `usage-${date}.jsonl`);
39448
+ const file = join3(LOG_DIR, `usage-${date}.jsonl`);
38838
39449
  await appendFile(file, JSON.stringify(entry) + "\n");
38839
39450
  } catch {
38840
39451
  }
@@ -38843,56 +39454,15 @@ var LOG_DIR, dirReady;
38843
39454
  var init_logger = __esm({
38844
39455
  "src/logger.ts"() {
38845
39456
  "use strict";
38846
- LOG_DIR = join2(homedir(), ".openclaw", "blockrun", "logs");
39457
+ LOG_DIR = join3(homedir2(), ".openclaw", "blockrun", "logs");
38847
39458
  dirReady = false;
38848
39459
  }
38849
39460
  });
38850
39461
 
38851
- // src/fs-read.ts
38852
- import { open } from "fs/promises";
38853
- import { openSync, readSync, closeSync, fstatSync } from "fs";
38854
- async function readTextFile(filePath) {
38855
- const fh = await open(filePath, "r");
38856
- try {
38857
- const size5 = (await fh.stat()).size;
38858
- const buf = Buffer.alloc(size5);
38859
- let offset = 0;
38860
- while (offset < size5) {
38861
- const { bytesRead } = await fh.read(buf, offset, size5 - offset, offset);
38862
- if (bytesRead === 0) break;
38863
- offset += bytesRead;
38864
- }
38865
- return buf.subarray(0, offset).toString("utf-8");
38866
- } finally {
38867
- await fh.close();
38868
- }
38869
- }
38870
- function readTextFileSync(filePath) {
38871
- const fd = openSync(filePath, "r");
38872
- try {
38873
- const size5 = fstatSync(fd).size;
38874
- const buf = Buffer.alloc(size5);
38875
- let offset = 0;
38876
- while (offset < size5) {
38877
- const bytesRead = readSync(fd, buf, offset, size5 - offset, offset);
38878
- if (bytesRead === 0) break;
38879
- offset += bytesRead;
38880
- }
38881
- return buf.subarray(0, offset).toString("utf-8");
38882
- } finally {
38883
- closeSync(fd);
38884
- }
38885
- }
38886
- var init_fs_read = __esm({
38887
- "src/fs-read.ts"() {
38888
- "use strict";
38889
- }
38890
- });
38891
-
38892
39462
  // src/version.ts
38893
39463
  import { createRequire } from "module";
38894
39464
  import { fileURLToPath } from "url";
38895
- import { dirname, join as join3 } from "path";
39465
+ import { dirname, join as join4 } from "path";
38896
39466
  function clientTag() {
38897
39467
  const raw = (process.env.CLAWROUTER_CLIENT ?? "").trim();
38898
39468
  if (!raw) return "";
@@ -38906,7 +39476,7 @@ var init_version4 = __esm({
38906
39476
  __filename2 = fileURLToPath(import.meta.url);
38907
39477
  __dirname = dirname(__filename2);
38908
39478
  require2 = createRequire(import.meta.url);
38909
- pkg = require2(join3(__dirname, "..", "package.json"));
39479
+ pkg = require2(join4(__dirname, "..", "package.json"));
38910
39480
  VERSION = pkg.version;
38911
39481
  USER_AGENT = `clawrouter/${VERSION}${clientTag()}`;
38912
39482
  }
@@ -38914,8 +39484,8 @@ var init_version4 = __esm({
38914
39484
 
38915
39485
  // src/stats.ts
38916
39486
  import { readdir, unlink } from "fs/promises";
38917
- import { join as join4 } from "path";
38918
- import { homedir as homedir2 } from "os";
39487
+ import { join as join5 } from "path";
39488
+ import { homedir as homedir3 } from "os";
38919
39489
  async function parseLogFile(filePath) {
38920
39490
  try {
38921
39491
  const content = await readTextFile(filePath);
@@ -38987,7 +39557,7 @@ async function getStats(days = 7) {
38987
39557
  let totalLatency = 0;
38988
39558
  for (const file of filesToRead) {
38989
39559
  const date = file.replace("usage-", "").replace(".jsonl", "");
38990
- const filePath = join4(LOG_DIR2, file);
39560
+ const filePath = join5(LOG_DIR2, file);
38991
39561
  const entries = await parseLogFile(filePath);
38992
39562
  if (entries.length === 0) continue;
38993
39563
  const dayStats = aggregateDay(date, entries);
@@ -39105,7 +39675,7 @@ async function clearStats() {
39105
39675
  try {
39106
39676
  const files = await readdir(LOG_DIR2);
39107
39677
  const logFiles = files.filter((f) => f.startsWith("usage-") && f.endsWith(".jsonl"));
39108
- await Promise.all(logFiles.map((f) => unlink(join4(LOG_DIR2, f))));
39678
+ await Promise.all(logFiles.map((f) => unlink(join5(LOG_DIR2, f))));
39109
39679
  return { deletedFiles: logFiles.length };
39110
39680
  } catch {
39111
39681
  return { deletedFiles: 0 };
@@ -39117,7 +39687,7 @@ var init_stats = __esm({
39117
39687
  "use strict";
39118
39688
  init_fs_read();
39119
39689
  init_version4();
39120
- LOG_DIR2 = join4(homedir2(), ".openclaw", "blockrun", "logs");
39690
+ LOG_DIR2 = join5(homedir3(), ".openclaw", "blockrun", "logs");
39121
39691
  }
39122
39692
  });
39123
39693
 
@@ -42936,7 +43506,7 @@ function alphabet2(letters) {
42936
43506
  };
42937
43507
  }
42938
43508
  // @__NO_SIDE_EFFECTS__
42939
- function join5(separator = "") {
43509
+ function join6(separator = "") {
42940
43510
  astr2("join", separator);
42941
43511
  return {
42942
43512
  encode: (from15) => {
@@ -43046,7 +43616,7 @@ var genBase58, base58, createBase58check;
43046
43616
  var init_base3 = __esm({
43047
43617
  "node_modules/@scure/base/index.js"() {
43048
43618
  "use strict";
43049
- genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain2(/* @__PURE__ */ radix3(58), /* @__PURE__ */ alphabet2(abc), /* @__PURE__ */ join5(""));
43619
+ genBase58 = /* @__NO_SIDE_EFFECTS__ */ (abc) => /* @__PURE__ */ chain2(/* @__PURE__ */ radix3(58), /* @__PURE__ */ alphabet2(abc), /* @__PURE__ */ join6(""));
43050
43620
  base58 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ genBase58("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"));
43051
43621
  createBase58check = (sha25610) => {
43052
43622
  afn2(sha25610);
@@ -43195,14 +43765,14 @@ var init_bip32 = __esm({
43195
43765
  }
43196
43766
  this.pubHash = hash160(this._publicKey);
43197
43767
  }
43198
- derive(path6) {
43199
- if (!/^[mM]'?/.test(path6)) {
43768
+ derive(path5) {
43769
+ if (!/^[mM]'?/.test(path5)) {
43200
43770
  throw new Error('Path must start with "m" or "M"');
43201
43771
  }
43202
- if (/^[mM]'?$/.test(path6)) {
43772
+ if (/^[mM]'?$/.test(path5)) {
43203
43773
  return this;
43204
43774
  }
43205
- const parts = path6.replace(/^[mM]'?\//, "").split("/");
43775
+ const parts = path5.replace(/^[mM]'?\//, "").split("/");
43206
43776
  let child = this;
43207
43777
  for (const c of parts) {
43208
43778
  const m = /^(\d+)('?)$/.exec(c);
@@ -51492,14 +52062,14 @@ function createSolanaJsonRpcIntegerOverflowError(methodName, keyPath, value) {
51492
52062
  } else {
51493
52063
  argumentLabel = `\`${keyPath[0].toString()}\``;
51494
52064
  }
51495
- const path6 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
52065
+ const path5 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
51496
52066
  const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
51497
52067
  argumentLabel,
51498
52068
  keyPath,
51499
52069
  methodName,
51500
- optionalPathLabel: path6 ? ` at path \`${path6}\`` : "",
52070
+ optionalPathLabel: path5 ? ` at path \`${path5}\`` : "",
51501
52071
  value,
51502
- ...path6 !== void 0 ? { path: path6 } : void 0
52072
+ ...path5 !== void 0 ? { path: path5 } : void 0
51503
52073
  });
51504
52074
  safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError);
51505
52075
  return error;
@@ -56163,14 +56733,14 @@ function createSolanaJsonRpcIntegerOverflowError2(methodName, keyPath, value) {
56163
56733
  } else {
56164
56734
  argumentLabel = `\`${keyPath[0].toString()}\``;
56165
56735
  }
56166
- const path6 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
56736
+ const path5 = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
56167
56737
  const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
56168
56738
  argumentLabel,
56169
56739
  keyPath,
56170
56740
  methodName,
56171
- optionalPathLabel: path6 ? ` at path \`${path6}\`` : "",
56741
+ optionalPathLabel: path5 ? ` at path \`${path5}\`` : "",
56172
56742
  value,
56173
- ...path6 !== void 0 ? { path: path6 } : void 0
56743
+ ...path5 !== void 0 ? { path: path5 } : void 0
56174
56744
  });
56175
56745
  safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError2);
56176
56746
  return error;
@@ -58238,8 +58808,8 @@ var init_wallet2 = __esm({
58238
58808
 
58239
58809
  // src/auth.ts
58240
58810
  import { writeFile, mkdir as mkdir2 } from "fs/promises";
58241
- import { join as join6 } from "path";
58242
- import { homedir as homedir3 } from "os";
58811
+ import { join as join7 } from "path";
58812
+ import { homedir as homedir4 } from "os";
58243
58813
  async function loadSavedWallet() {
58244
58814
  try {
58245
58815
  const key2 = (await readTextFile(WALLET_FILE)).trim();
@@ -58288,7 +58858,7 @@ async function loadMnemonic() {
58288
58858
  return void 0;
58289
58859
  }
58290
58860
  async function saveMnemonic(mnemonic) {
58291
- await mkdir2(WALLET_DIR, { recursive: true });
58861
+ await mkdir2(WALLET_DIR2, { recursive: true });
58292
58862
  await writeFile(MNEMONIC_FILE, mnemonic + "\n", { mode: 384 });
58293
58863
  }
58294
58864
  async function generateAndSaveWallet() {
@@ -58307,7 +58877,7 @@ Then run: npx @blockrun/clawrouter`
58307
58877
  }
58308
58878
  const mnemonic = generateWalletMnemonic();
58309
58879
  const derived = deriveAllKeys(mnemonic);
58310
- await mkdir2(WALLET_DIR, { recursive: true });
58880
+ await mkdir2(WALLET_DIR2, { recursive: true });
58311
58881
  await writeFile(WALLET_FILE, derived.evmPrivateKey + "\n", { mode: 384 });
58312
58882
  await writeFile(MNEMONIC_FILE, mnemonic + "\n", { mode: 384 });
58313
58883
  try {
@@ -58429,7 +58999,7 @@ async function setupSolana() {
58429
58999
  return { mnemonic, solanaPrivateKeyBytes: solanaKeyBytes };
58430
59000
  }
58431
59001
  async function savePaymentChain(chain3) {
58432
- await mkdir2(WALLET_DIR, { recursive: true });
59002
+ await mkdir2(WALLET_DIR2, { recursive: true });
58433
59003
  await writeFile(CHAIN_FILE, chain3 + "\n", { mode: 384 });
58434
59004
  }
58435
59005
  async function loadPaymentChain() {
@@ -58446,17 +59016,17 @@ async function resolvePaymentChain() {
58446
59016
  if (process["env"].CLAWROUTER_PAYMENT_CHAIN === "base") return "base";
58447
59017
  return loadPaymentChain();
58448
59018
  }
58449
- var WALLET_DIR, WALLET_FILE, MNEMONIC_FILE, CHAIN_FILE;
59019
+ var WALLET_DIR2, WALLET_FILE, MNEMONIC_FILE, CHAIN_FILE;
58450
59020
  var init_auth = __esm({
58451
59021
  "src/auth.ts"() {
58452
59022
  "use strict";
58453
59023
  init_fs_read();
58454
59024
  init_accounts();
58455
59025
  init_wallet2();
58456
- WALLET_DIR = join6(homedir3(), ".openclaw", "blockrun");
58457
- WALLET_FILE = join6(WALLET_DIR, "wallet.key");
58458
- MNEMONIC_FILE = join6(WALLET_DIR, "mnemonic");
58459
- CHAIN_FILE = join6(WALLET_DIR, "payment-chain");
59026
+ WALLET_DIR2 = join7(homedir4(), ".openclaw", "blockrun");
59027
+ WALLET_FILE = join7(WALLET_DIR2, "wallet.key");
59028
+ MNEMONIC_FILE = join7(WALLET_DIR2, "mnemonic");
59029
+ CHAIN_FILE = join7(WALLET_DIR2, "payment-chain");
58460
59030
  }
58461
59031
  });
58462
59032
 
@@ -58615,7 +59185,7 @@ function generateCodebookHeader(usedCodes, pathMap = {}) {
58615
59185
  parts.push(`[Dict: ${codeEntries}]`);
58616
59186
  }
58617
59187
  if (Object.keys(pathMap).length > 0) {
58618
- const pathEntries = Object.entries(pathMap).map(([code, path6]) => `${code}=${path6}`).join(", ");
59188
+ const pathEntries = Object.entries(pathMap).map(([code, path5]) => `${code}=${path5}`).join(", ");
58619
59189
  parts.push(`[Paths: ${pathEntries}]`);
58620
59190
  }
58621
59191
  return parts.join("\n");
@@ -58763,8 +59333,8 @@ function extractPaths(messages) {
58763
59333
  }
58764
59334
  function findFrequentPrefixes(paths) {
58765
59335
  const prefixCounts = /* @__PURE__ */ new Map();
58766
- for (const path6 of paths) {
58767
- const parts = path6.split("/").filter(Boolean);
59336
+ for (const path5 of paths) {
59337
+ const parts = path5.split("/").filter(Boolean);
58768
59338
  for (let i = 2; i < parts.length; i++) {
58769
59339
  const prefix = "/" + parts.slice(0, i).join("/") + "/";
58770
59340
  prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);
@@ -59548,9 +60118,9 @@ var init_updater = __esm({
59548
60118
  });
59549
60119
 
59550
60120
  // src/exclude-models.ts
59551
- import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
59552
- import { join as join7, dirname as dirname2 } from "path";
59553
- import { homedir as homedir4 } from "os";
60121
+ import { readFileSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, statSync } from "fs";
60122
+ import { join as join8, dirname as dirname2 } from "path";
60123
+ import { homedir as homedir5 } from "os";
59554
60124
  function loadExcludeList(filePath = DEFAULT_FILE_PATH) {
59555
60125
  try {
59556
60126
  const mtimeMs = statSync(filePath).mtimeMs;
@@ -59571,8 +60141,8 @@ function loadExcludeList(filePath = DEFAULT_FILE_PATH) {
59571
60141
  function saveExcludeList(set, filePath) {
59572
60142
  const sorted = [...set].sort();
59573
60143
  const dir = dirname2(filePath);
59574
- mkdirSync(dir, { recursive: true });
59575
- writeFileSync(filePath, JSON.stringify(sorted, null, 2) + "\n", "utf-8");
60144
+ mkdirSync2(dir, { recursive: true });
60145
+ writeFileSync2(filePath, JSON.stringify(sorted, null, 2) + "\n", "utf-8");
59576
60146
  loadCache.delete(filePath);
59577
60147
  }
59578
60148
  function addExclusion(model, filePath = DEFAULT_FILE_PATH) {
@@ -59599,7 +60169,7 @@ var init_exclude_models = __esm({
59599
60169
  "src/exclude-models.ts"() {
59600
60170
  "use strict";
59601
60171
  init_models();
59602
- DEFAULT_FILE_PATH = join7(homedir4(), ".openclaw", "blockrun", "exclude-models.json");
60172
+ DEFAULT_FILE_PATH = join8(homedir5(), ".openclaw", "blockrun", "exclude-models.json");
59603
60173
  loadCache = /* @__PURE__ */ new Map();
59604
60174
  }
59605
60175
  });
@@ -60904,14 +61474,14 @@ var require_util = __commonJS({
60904
61474
  }
60905
61475
  const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
60906
61476
  let origin2 = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
60907
- let path6 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
61477
+ let path5 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
60908
61478
  if (origin2[origin2.length - 1] === "/") {
60909
61479
  origin2 = origin2.slice(0, origin2.length - 1);
60910
61480
  }
60911
- if (path6 && path6[0] !== "/") {
60912
- path6 = `/${path6}`;
61481
+ if (path5 && path5[0] !== "/") {
61482
+ path5 = `/${path5}`;
60913
61483
  }
60914
- return new URL(`${origin2}${path6}`);
61484
+ return new URL(`${origin2}${path5}`);
60915
61485
  }
60916
61486
  if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
60917
61487
  throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
@@ -61782,9 +62352,9 @@ var require_diagnostics = __commonJS({
61782
62352
  "undici:client:sendHeaders",
61783
62353
  (evt) => {
61784
62354
  const {
61785
- request: { method, path: path6, origin: origin2 }
62355
+ request: { method, path: path5, origin: origin2 }
61786
62356
  } = evt;
61787
- debugLog("sending request to %s %s%s", method, origin2, path6);
62357
+ debugLog("sending request to %s %s%s", method, origin2, path5);
61788
62358
  }
61789
62359
  );
61790
62360
  }
@@ -61802,14 +62372,14 @@ var require_diagnostics = __commonJS({
61802
62372
  "undici:request:headers",
61803
62373
  (evt) => {
61804
62374
  const {
61805
- request: { method, path: path6, origin: origin2 },
62375
+ request: { method, path: path5, origin: origin2 },
61806
62376
  response: { statusCode }
61807
62377
  } = evt;
61808
62378
  debugLog(
61809
62379
  "received response to %s %s%s - HTTP %d",
61810
62380
  method,
61811
62381
  origin2,
61812
- path6,
62382
+ path5,
61813
62383
  statusCode
61814
62384
  );
61815
62385
  }
@@ -61818,23 +62388,23 @@ var require_diagnostics = __commonJS({
61818
62388
  "undici:request:trailers",
61819
62389
  (evt) => {
61820
62390
  const {
61821
- request: { method, path: path6, origin: origin2 }
62391
+ request: { method, path: path5, origin: origin2 }
61822
62392
  } = evt;
61823
- debugLog("trailers received from %s %s%s", method, origin2, path6);
62393
+ debugLog("trailers received from %s %s%s", method, origin2, path5);
61824
62394
  }
61825
62395
  );
61826
62396
  diagnosticsChannel.subscribe(
61827
62397
  "undici:request:error",
61828
62398
  (evt) => {
61829
62399
  const {
61830
- request: { method, path: path6, origin: origin2 },
62400
+ request: { method, path: path5, origin: origin2 },
61831
62401
  error
61832
62402
  } = evt;
61833
62403
  debugLog(
61834
62404
  "request to %s %s%s errored - %s",
61835
62405
  method,
61836
62406
  origin2,
61837
- path6,
62407
+ path5,
61838
62408
  error.message
61839
62409
  );
61840
62410
  }
@@ -61989,7 +62559,7 @@ var require_request = __commonJS({
61989
62559
  };
61990
62560
  var Request2 = class {
61991
62561
  constructor(origin2, {
61992
- path: path6,
62562
+ path: path5,
61993
62563
  method,
61994
62564
  body,
61995
62565
  headers,
@@ -62006,11 +62576,11 @@ var require_request = __commonJS({
62006
62576
  maxRedirections,
62007
62577
  typeOfService
62008
62578
  }, handler) {
62009
- if (typeof path6 !== "string") {
62579
+ if (typeof path5 !== "string") {
62010
62580
  throw new InvalidArgumentError("path must be a string");
62011
- } else if (path6[0] !== "/" && !(path6.startsWith("http://") || path6.startsWith("https://")) && method !== "CONNECT") {
62581
+ } else if (path5[0] !== "/" && !(path5.startsWith("http://") || path5.startsWith("https://")) && method !== "CONNECT") {
62012
62582
  throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
62013
- } else if (invalidPathRegex.test(path6)) {
62583
+ } else if (invalidPathRegex.test(path5)) {
62014
62584
  throw new InvalidArgumentError("invalid request path");
62015
62585
  }
62016
62586
  if (typeof method !== "string") {
@@ -62085,7 +62655,7 @@ var require_request = __commonJS({
62085
62655
  this.completed = false;
62086
62656
  this.aborted = false;
62087
62657
  this.upgrade = upgrade || null;
62088
- this.path = query ? serializePathWithQuery(path6, query) : path6;
62658
+ this.path = query ? serializePathWithQuery(path5, query) : path5;
62089
62659
  this.origin = origin2;
62090
62660
  this.protocol = getProtocolFromUrlString(origin2);
62091
62661
  this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" || method === "QUERY" : idempotent;
@@ -67171,7 +67741,7 @@ var require_client_h1 = __commonJS({
67171
67741
  }
67172
67742
  }
67173
67743
  function writeH1(client, request2) {
67174
- const { method, path: path6, host, upgrade, blocking, reset } = request2;
67744
+ const { method, path: path5, host, upgrade, blocking, reset } = request2;
67175
67745
  let { body, headers, contentLength } = request2;
67176
67746
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
67177
67747
  if (util5.isFormDataLike(body)) {
@@ -67247,7 +67817,7 @@ var require_client_h1 = __commonJS({
67247
67817
  socket[kBlocking] = true;
67248
67818
  }
67249
67819
  setTypeOfService(socket, request2);
67250
- let header = `${method} ${path6} HTTP/1.1\r
67820
+ let header = `${method} ${path5} HTTP/1.1\r
67251
67821
  `;
67252
67822
  if (typeof host === "string") {
67253
67823
  header += `host: ${host}\r
@@ -68328,7 +68898,7 @@ var require_client_h2 = __commonJS({
68328
68898
  const headersTimeout = request2.headersTimeout ?? client[kHeadersTimeout];
68329
68899
  const bodyTimeout = request2.bodyTimeout ?? client[kBodyTimeout];
68330
68900
  const session = client[kHTTP2Session];
68331
- const { method, path: path6, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
68901
+ const { method, path: path5, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2;
68332
68902
  if (upgrade != null && upgrade !== "websocket") {
68333
68903
  util5.errorRequest(client, request2, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
68334
68904
  return false;
@@ -68391,7 +68961,7 @@ var require_client_h2 = __commonJS({
68391
68961
  }
68392
68962
  headers[HTTP2_HEADER_METHOD] = "CONNECT";
68393
68963
  headers[HTTP2_HEADER_PROTOCOL] = "websocket";
68394
- headers[HTTP2_HEADER_PATH] = path6;
68964
+ headers[HTTP2_HEADER_PATH] = path5;
68395
68965
  if (protocol === "ws:" || protocol === "wss:") {
68396
68966
  headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
68397
68967
  } else {
@@ -68413,7 +68983,7 @@ var require_client_h2 = __commonJS({
68413
68983
  setupUpgradeStream(stream4, state);
68414
68984
  return true;
68415
68985
  }
68416
- headers[HTTP2_HEADER_PATH] = path6;
68986
+ headers[HTTP2_HEADER_PATH] = path5;
68417
68987
  headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
68418
68988
  const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
68419
68989
  let body = state.body;
@@ -71083,10 +71653,10 @@ var require_proxy_agent = __commonJS({
71083
71653
  };
71084
71654
  const {
71085
71655
  origin: origin2,
71086
- path: path6 = "/",
71656
+ path: path5 = "/",
71087
71657
  headers = {}
71088
71658
  } = opts;
71089
- opts.path = origin2 + path6;
71659
+ opts.path = origin2 + path5;
71090
71660
  if (!("host" in headers) && !("Host" in headers)) {
71091
71661
  const { host } = new URL(origin2);
71092
71662
  headers.host = host;
@@ -73351,20 +73921,20 @@ var require_mock_utils = __commonJS({
73351
73921
  }
73352
73922
  return normalizedQp;
73353
73923
  }
73354
- function safeUrl(path6) {
73355
- if (typeof path6 !== "string") {
73356
- return path6;
73924
+ function safeUrl(path5) {
73925
+ if (typeof path5 !== "string") {
73926
+ return path5;
73357
73927
  }
73358
- const pathSegments = path6.split("?", 3);
73928
+ const pathSegments = path5.split("?", 3);
73359
73929
  if (pathSegments.length !== 2) {
73360
- return path6;
73930
+ return path5;
73361
73931
  }
73362
73932
  const qp = new URLSearchParams(pathSegments.pop());
73363
73933
  qp.sort();
73364
73934
  return [...pathSegments, qp.toString()].join("?");
73365
73935
  }
73366
- function matchKey(mockDispatch2, { path: path6, method, body, headers }) {
73367
- const pathMatch = matchValue(mockDispatch2.path, path6);
73936
+ function matchKey(mockDispatch2, { path: path5, method, body, headers }) {
73937
+ const pathMatch = matchValue(mockDispatch2.path, path5);
73368
73938
  const methodMatch = matchValue(mockDispatch2.method, method);
73369
73939
  const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
73370
73940
  const headersMatch = matchHeaders(mockDispatch2, headers);
@@ -73391,8 +73961,8 @@ var require_mock_utils = __commonJS({
73391
73961
  const basePath = key2.query ? serializePathWithQuery(key2.path, key2.query) : key2.path;
73392
73962
  const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
73393
73963
  const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
73394
- let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path6, ignoreTrailingSlash }) => {
73395
- return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path6)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path6), resolvedPath);
73964
+ let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path5, ignoreTrailingSlash }) => {
73965
+ return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path5)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path5), resolvedPath);
73396
73966
  });
73397
73967
  if (matchedMockDispatches.length === 0) {
73398
73968
  throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
@@ -73431,22 +74001,22 @@ var require_mock_utils = __commonJS({
73431
74001
  mockDispatches.splice(index2, 1);
73432
74002
  }
73433
74003
  }
73434
- function removeTrailingSlash(path6) {
73435
- if (typeof path6 !== "string") {
73436
- return path6;
74004
+ function removeTrailingSlash(path5) {
74005
+ if (typeof path5 !== "string") {
74006
+ return path5;
73437
74007
  }
73438
- while (path6.endsWith("/")) {
73439
- path6 = path6.slice(0, -1);
74008
+ while (path5.endsWith("/")) {
74009
+ path5 = path5.slice(0, -1);
73440
74010
  }
73441
- if (path6.length === 0) {
73442
- path6 = "/";
74011
+ if (path5.length === 0) {
74012
+ path5 = "/";
73443
74013
  }
73444
- return path6;
74014
+ return path5;
73445
74015
  }
73446
74016
  function buildKey(opts) {
73447
- const { path: path6, method, body, headers, query } = opts;
74017
+ const { path: path5, method, body, headers, query } = opts;
73448
74018
  return {
73449
- path: path6,
74019
+ path: path5,
73450
74020
  method,
73451
74021
  body,
73452
74022
  headers,
@@ -74317,10 +74887,10 @@ var require_pending_interceptors_formatter = __commonJS({
74317
74887
  }
74318
74888
  format(pendingInterceptors) {
74319
74889
  const withPrettyHeaders = pendingInterceptors.map(
74320
- ({ method, path: path6, data: { statusCode }, persist, times, timesInvoked, origin: origin2 }) => ({
74890
+ ({ method, path: path5, data: { statusCode }, persist, times, timesInvoked, origin: origin2 }) => ({
74321
74891
  Method: method,
74322
74892
  Origin: origin2,
74323
- Path: path6,
74893
+ Path: path5,
74324
74894
  "Status code": statusCode,
74325
74895
  Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
74326
74896
  Invocations: timesInvoked,
@@ -74402,9 +74972,9 @@ var require_mock_agent = __commonJS({
74402
74972
  const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
74403
74973
  const dispatchOpts = { ...opts };
74404
74974
  if (acceptNonStandardSearchParameters && dispatchOpts.path) {
74405
- const [path6, searchParams] = dispatchOpts.path.split("?");
74975
+ const [path5, searchParams] = dispatchOpts.path.split("?");
74406
74976
  const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
74407
- dispatchOpts.path = `${path6}?${normalizedSearchParams}`;
74977
+ dispatchOpts.path = `${path5}?${normalizedSearchParams}`;
74408
74978
  }
74409
74979
  return this[kAgent].dispatch(dispatchOpts, handler);
74410
74980
  }
@@ -74820,12 +75390,12 @@ var require_snapshot_recorder = __commonJS({
74820
75390
  * @return {Promise<void>} - Resolves when snapshots are loaded
74821
75391
  */
74822
75392
  async loadSnapshots(filePath) {
74823
- const path6 = filePath || this.#snapshotPath;
74824
- if (!path6) {
75393
+ const path5 = filePath || this.#snapshotPath;
75394
+ if (!path5) {
74825
75395
  throw new InvalidArgumentError("Snapshot path is required");
74826
75396
  }
74827
75397
  try {
74828
- const data = await readFile3(resolve(path6), "utf8");
75398
+ const data = await readFile3(resolve(path5), "utf8");
74829
75399
  const parsed = JSON.parse(data);
74830
75400
  if (Array.isArray(parsed)) {
74831
75401
  this.#snapshots.clear();
@@ -74839,7 +75409,7 @@ var require_snapshot_recorder = __commonJS({
74839
75409
  if (error.code === "ENOENT") {
74840
75410
  this.#snapshots.clear();
74841
75411
  } else {
74842
- throw new UndiciError(`Failed to load snapshots from ${path6}`, { cause: error });
75412
+ throw new UndiciError(`Failed to load snapshots from ${path5}`, { cause: error });
74843
75413
  }
74844
75414
  }
74845
75415
  }
@@ -74850,11 +75420,11 @@ var require_snapshot_recorder = __commonJS({
74850
75420
  * @returns {Promise<void>} - Resolves when snapshots are saved
74851
75421
  */
74852
75422
  async saveSnapshots(filePath) {
74853
- const path6 = filePath || this.#snapshotPath;
74854
- if (!path6) {
75423
+ const path5 = filePath || this.#snapshotPath;
75424
+ if (!path5) {
74855
75425
  throw new InvalidArgumentError("Snapshot path is required");
74856
75426
  }
74857
- const resolvedPath = resolve(path6);
75427
+ const resolvedPath = resolve(path5);
74858
75428
  await mkdir5(dirname5(resolvedPath), { recursive: true });
74859
75429
  const data = Array.from(this.#snapshots.entries()).map(([hash5, snapshot]) => ({
74860
75430
  hash: hash5,
@@ -75491,15 +76061,15 @@ var require_redirect_handler = __commonJS({
75491
76061
  return;
75492
76062
  }
75493
76063
  const { origin: origin2, pathname, search } = util5.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
75494
- const path6 = search ? `${pathname}${search}` : pathname;
75495
- const redirectUrlString = `${origin2}${path6}`;
76064
+ const path5 = search ? `${pathname}${search}` : pathname;
76065
+ const redirectUrlString = `${origin2}${path5}`;
75496
76066
  for (const historyUrl of this.history) {
75497
76067
  if (historyUrl.toString() === redirectUrlString) {
75498
76068
  throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin2}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
75499
76069
  }
75500
76070
  }
75501
76071
  this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin2, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect);
75502
- this.opts.path = path6;
76072
+ this.opts.path = path5;
75503
76073
  this.opts.origin = origin2;
75504
76074
  this.opts.query = null;
75505
76075
  }
@@ -77327,10 +77897,10 @@ var require_cache_handler = __commonJS({
77327
77897
  }
77328
77898
  return locationUrl.pathname + locationUrl.search;
77329
77899
  }
77330
- function deleteCachedUri(store, cacheKey2, path6) {
77900
+ function deleteCachedUri(store, cacheKey2, path5) {
77331
77901
  deleteCachedValue(store, {
77332
77902
  ...cacheKey2,
77333
- path: path6
77903
+ path: path5
77334
77904
  });
77335
77905
  for (let i = 0; i < util5.safeHTTPMethods.length; i++) {
77336
77906
  const method = util5.safeHTTPMethods[i];
@@ -77338,7 +77908,7 @@ var require_cache_handler = __commonJS({
77338
77908
  deleteCachedValue(store, {
77339
77909
  ...cacheKey2,
77340
77910
  method,
77341
- path: path6
77911
+ path: path5
77342
77912
  });
77343
77913
  }
77344
77914
  }
@@ -77349,9 +77919,9 @@ var require_cache_handler = __commonJS({
77349
77919
  }
77350
77920
  const values = Array.isArray(headerValue) ? headerValue : [headerValue];
77351
77921
  for (let i = 0; i < values.length; i++) {
77352
- const path6 = getSameOriginPath(cacheKey2, values[i]);
77353
- if (path6 !== void 0) {
77354
- deleteCachedUri(store, cacheKey2, path6);
77922
+ const path5 = getSameOriginPath(cacheKey2, values[i]);
77923
+ if (path5 !== void 0) {
77924
+ deleteCachedUri(store, cacheKey2, path5);
77355
77925
  }
77356
77926
  }
77357
77927
  }
@@ -82348,13 +82918,13 @@ var require_fetch = __commonJS({
82348
82918
  function dispatch({ body }) {
82349
82919
  const url2 = requestCurrentURL(request2);
82350
82920
  const agent = fetchParams.controller.dispatcher;
82351
- const path6 = url2.pathname + url2.search;
82921
+ const path5 = url2.pathname + url2.search;
82352
82922
  const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
82353
82923
  return dispatchWithProtocolPreference(body);
82354
82924
  function dispatchWithProtocolPreference(body2, allowH2) {
82355
82925
  return new Promise((resolve, reject) => agent.dispatch(
82356
82926
  {
82357
- path: hasTrailingQuestionMark ? `${path6}?` : path6,
82927
+ path: hasTrailingQuestionMark ? `${path5}?` : path5,
82358
82928
  origin: url2.origin,
82359
82929
  method: request2.method,
82360
82930
  body: agent.isMockActive ? request2.body && (request2.body.source || request2.body.stream) : body2,
@@ -83266,9 +83836,9 @@ var require_util4 = __commonJS({
83266
83836
  }
83267
83837
  }
83268
83838
  }
83269
- function validateCookiePath(path6) {
83270
- for (let i = 0; i < path6.length; ++i) {
83271
- const code = path6.charCodeAt(i);
83839
+ function validateCookiePath(path5) {
83840
+ for (let i = 0; i < path5.length; ++i) {
83841
+ const code = path5.charCodeAt(i);
83272
83842
  if (code < 32 || // exclude CTLs (0-31)
83273
83843
  code > 126 || // exclude non-ascii and DEL
83274
83844
  code === 59) {
@@ -86640,11 +87210,11 @@ var require_undici = __commonJS({
86640
87210
  if (typeof opts.path !== "string") {
86641
87211
  throw new InvalidArgumentError("invalid opts.path");
86642
87212
  }
86643
- let path6 = opts.path;
87213
+ let path5 = opts.path;
86644
87214
  if (!opts.path.startsWith("/")) {
86645
- path6 = `/${path6}`;
87215
+ path5 = `/${path5}`;
86646
87216
  }
86647
- url2 = new URL(util5.parseOrigin(url2).origin + path6);
87217
+ url2 = new URL(util5.parseOrigin(url2).origin + path5);
86648
87218
  } else {
86649
87219
  if (!opts) {
86650
87220
  opts = typeof url2 === "object" ? url2 : {};
@@ -87190,8 +87760,8 @@ var init_textual_tool_calls = __esm({
87190
87760
 
87191
87761
  // src/response-store.ts
87192
87762
  import { appendFile as appendFile2, mkdir as mkdir3, readFile, readdir as readdir2 } from "fs/promises";
87193
- import { homedir as homedir5 } from "os";
87194
- import { join as join8 } from "path";
87763
+ import { homedir as homedir6 } from "os";
87764
+ import { join as join9 } from "path";
87195
87765
  import { randomBytes as randomBytes7 } from "crypto";
87196
87766
  function isEnabled() {
87197
87767
  const v = process.env.BLOCKRUN_RESPONSE_STORE;
@@ -87204,7 +87774,7 @@ async function ensureDir2() {
87204
87774
  }
87205
87775
  function dailyFile(date = /* @__PURE__ */ new Date()) {
87206
87776
  const iso = date.toISOString().slice(0, 10);
87207
- return join8(STORE_DIR, `responses-${iso}.jsonl`);
87777
+ return join9(STORE_DIR, `responses-${iso}.jsonl`);
87208
87778
  }
87209
87779
  function genId() {
87210
87780
  return `resp_${Date.now()}_${randomBytes7(3).toString("hex")}`;
@@ -87254,7 +87824,7 @@ async function listRecent(limit = 20, daysBack = 7) {
87254
87824
  d.setUTCDate(d.getUTCDate() - i);
87255
87825
  const iso = d.toISOString().slice(0, 10);
87256
87826
  const name = `responses-${iso}.jsonl`;
87257
- if (files.includes(name)) candidateFiles.push(join8(STORE_DIR, name));
87827
+ if (files.includes(name)) candidateFiles.push(join9(STORE_DIR, name));
87258
87828
  }
87259
87829
  const all3 = [];
87260
87830
  for (const f of candidateFiles) {
@@ -87283,7 +87853,7 @@ var STORE_DIR, dirReady2;
87283
87853
  var init_response_store = __esm({
87284
87854
  "src/response-store.ts"() {
87285
87855
  "use strict";
87286
- STORE_DIR = join8(homedir5(), ".openclaw", "blockrun", "responses");
87856
+ STORE_DIR = join9(homedir6(), ".openclaw", "blockrun", "responses");
87287
87857
  dirReady2 = false;
87288
87858
  }
87289
87859
  });
@@ -88933,10 +89503,10 @@ var init_client3 = __esm({
88933
89503
  import { AsyncLocalStorage } from "async_hooks";
88934
89504
  import { createServer } from "http";
88935
89505
  import { finished } from "stream";
88936
- import { homedir as homedir6 } from "os";
88937
- import { join as join9 } from "path";
89506
+ import { homedir as homedir7 } from "os";
89507
+ import { join as join10 } from "path";
88938
89508
  import { mkdir as mkdir4, writeFile as writeFile2, readFile as readFile2, stat as fsStat } from "fs/promises";
88939
- import { readFileSync as readFileSync2, existsSync } from "fs";
89509
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
88940
89510
  function pickFreeModel(excludeList) {
88941
89511
  for (const m of FREE_MODELS) {
88942
89512
  if (!excludeList?.has(m)) return m;
@@ -89702,8 +90272,8 @@ async function proxyPaidApiRequest(req, res, apiBase, payFetch, getActualPayment
89702
90272
  });
89703
90273
  }
89704
90274
  function readImageFileAsDataUri(filePath) {
89705
- const resolved = filePath.startsWith("~/") ? join9(homedir6(), filePath.slice(2)) : filePath;
89706
- if (!existsSync(resolved)) {
90275
+ const resolved = filePath.startsWith("~/") ? join10(homedir7(), filePath.slice(2)) : filePath;
90276
+ if (!existsSync2(resolved)) {
89707
90277
  throw new Error(`Image file not found: ${resolved}`);
89708
90278
  }
89709
90279
  const ext = resolved.split(".").pop()?.toLowerCase() ?? "png";
@@ -89817,6 +90387,8 @@ async function startProxy(options) {
89817
90387
  const evmPublicClient = createPublicClient({ chain: base, transport: http() });
89818
90388
  const evmSigner = toClientEvmSigner(account, evmPublicClient);
89819
90389
  const x402 = new x402Client();
90390
+ const spendControl = options.spendControl ?? new SpendControl();
90391
+ registerSpendPolicyHook(x402, spendControl);
89820
90392
  registerExactEvmScheme(x402, { signer: evmSigner });
89821
90393
  let solanaAddress;
89822
90394
  if (solanaPrivateKeyBytes) {
@@ -89985,8 +90557,8 @@ async function startProxy(options) {
89985
90557
  if (req.url?.startsWith("/share") && req.method === "GET") {
89986
90558
  try {
89987
90559
  const url2 = new URL(req.url, "http://localhost");
89988
- const path6 = url2.pathname;
89989
- if (path6 === "/share/list") {
90560
+ const path5 = url2.pathname;
90561
+ if (path5 === "/share/list") {
89990
90562
  const limit = Math.min(parseInt(url2.searchParams.get("limit") || "20", 10), 100);
89991
90563
  const entries = await listRecent(limit);
89992
90564
  res.writeHead(200, { "Content-Type": "application/json" });
@@ -90004,7 +90576,7 @@ async function startProxy(options) {
90004
90576
  );
90005
90577
  return;
90006
90578
  }
90007
- if (path6 === "/share/last") {
90579
+ if (path5 === "/share/last") {
90008
90580
  const sessionId = url2.searchParams.get("sessionId") || void 0;
90009
90581
  const entry = await getLast(sessionId);
90010
90582
  if (!entry) {
@@ -90033,7 +90605,7 @@ async function startProxy(options) {
90033
90605
  res.end(JSON.stringify(entry));
90034
90606
  return;
90035
90607
  }
90036
- const idMatch = path6.match(/^\/share\/(resp_[A-Za-z0-9_]+)(?:\/render)?$/);
90608
+ const idMatch = path5.match(/^\/share\/(resp_[A-Za-z0-9_]+)(?:\/render)?$/);
90037
90609
  if (idMatch) {
90038
90610
  const id2 = idMatch[1];
90039
90611
  const entry = await getById(id2);
@@ -90079,7 +90651,7 @@ async function startProxy(options) {
90079
90651
  res.end("Bad request");
90080
90652
  return;
90081
90653
  }
90082
- const filePath = join9(IMAGE_DIR, filename);
90654
+ const filePath = join10(IMAGE_DIR, filename);
90083
90655
  try {
90084
90656
  const s3 = await fsStat(filePath);
90085
90657
  if (!s3.isFile()) throw new Error("not a file");
@@ -90110,7 +90682,7 @@ async function startProxy(options) {
90110
90682
  res.end("Bad request");
90111
90683
  return;
90112
90684
  }
90113
- const filePath = join9(AUDIO_DIR, filename);
90685
+ const filePath = join10(AUDIO_DIR, filename);
90114
90686
  try {
90115
90687
  const s3 = await fsStat(filePath);
90116
90688
  if (!s3.isFile()) throw new Error("not a file");
@@ -90140,7 +90712,7 @@ async function startProxy(options) {
90140
90712
  res.end("Bad request");
90141
90713
  return;
90142
90714
  }
90143
- const filePath = join9(VIDEO_DIR, filename);
90715
+ const filePath = join10(VIDEO_DIR, filename);
90144
90716
  try {
90145
90717
  const s3 = await fsStat(filePath);
90146
90718
  if (!s3.isFile()) throw new Error("not a file");
@@ -90281,7 +90853,7 @@ async function startProxy(options) {
90281
90853
  const [, mimeType, b64] = dataUriMatch;
90282
90854
  const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
90283
90855
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90284
- await writeFile2(join9(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90856
+ await writeFile2(join10(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90285
90857
  img.url = `http://localhost:${port2}/images/${filename}`;
90286
90858
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90287
90859
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
@@ -90292,7 +90864,7 @@ async function startProxy(options) {
90292
90864
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
90293
90865
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90294
90866
  const buf = Buffer.from(await imgResp.arrayBuffer());
90295
- await writeFile2(join9(IMAGE_DIR, filename), buf);
90867
+ await writeFile2(join10(IMAGE_DIR, filename), buf);
90296
90868
  img.url = `http://localhost:${port2}/images/${filename}`;
90297
90869
  console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
90298
90870
  }
@@ -90404,7 +90976,7 @@ async function startProxy(options) {
90404
90976
  const [, mimeType, b64] = dataUriMatch;
90405
90977
  const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
90406
90978
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90407
- await writeFile2(join9(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90979
+ await writeFile2(join10(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
90408
90980
  img.url = `http://localhost:${port2}/images/${filename}`;
90409
90981
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90410
90982
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
@@ -90415,7 +90987,7 @@ async function startProxy(options) {
90415
90987
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
90416
90988
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90417
90989
  const buf = Buffer.from(await imgResp.arrayBuffer());
90418
- await writeFile2(join9(IMAGE_DIR, filename), buf);
90990
+ await writeFile2(join10(IMAGE_DIR, filename), buf);
90419
90991
  img.url = `http://localhost:${port2}/images/${filename}`;
90420
90992
  console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
90421
90993
  }
@@ -90501,7 +91073,7 @@ async function startProxy(options) {
90501
91073
  const ext = contentType.includes("wav") ? "wav" : "mp3";
90502
91074
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90503
91075
  const buf = Buffer.from(await audioResp.arrayBuffer());
90504
- await writeFile2(join9(AUDIO_DIR, filename), buf);
91076
+ await writeFile2(join10(AUDIO_DIR, filename), buf);
90505
91077
  track.url = `http://localhost:${port2}/audio/${filename}`;
90506
91078
  console.log(`[ClawRouter] Audio saved \u2192 ${track.url}`);
90507
91079
  }
@@ -90661,7 +91233,7 @@ async function startProxy(options) {
90661
91233
  const ext = contentType.includes("webm") ? "webm" : contentType.includes("quicktime") ? "mov" : "mp4";
90662
91234
  const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
90663
91235
  const buf = Buffer.from(await videoResp.arrayBuffer());
90664
- await writeFile2(join9(VIDEO_DIR, filename), buf);
91236
+ await writeFile2(join10(VIDEO_DIR, filename), buf);
90665
91237
  clip.url = `http://localhost:${port2}/videos/${filename}`;
90666
91238
  console.log(`[ClawRouter] Video saved \u2192 ${clip.url}`);
90667
91239
  }
@@ -91001,6 +91573,17 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
91001
91573
  return { success: true, response };
91002
91574
  } catch (err) {
91003
91575
  const errorMsg = err instanceof Error ? err.message : String(err);
91576
+ if (err instanceof SpendPolicyError) {
91577
+ return {
91578
+ success: false,
91579
+ errorBody: JSON.stringify({
91580
+ error: { message: errorMsg, type: "spend_policy_denied", status: 403 }
91581
+ }),
91582
+ errorStatus: 403,
91583
+ isProviderError: false,
91584
+ errorCategory: "payment_error"
91585
+ };
91586
+ }
91004
91587
  return {
91005
91588
  success: false,
91006
91589
  errorBody: errorMsg,
@@ -93187,6 +93770,7 @@ var init_proxy = __esm({
93187
93770
  init_response_cache();
93188
93771
  init_balance();
93189
93772
  init_auth();
93773
+ init_spend_control();
93190
93774
  init_compression();
93191
93775
  init_version4();
93192
93776
  init_session();
@@ -93202,9 +93786,9 @@ var init_proxy = __esm({
93202
93786
  paymentStore = new AsyncLocalStorage();
93203
93787
  BLOCKRUN_API = "https://blockrun.ai/api";
93204
93788
  BLOCKRUN_SOLANA_API = "https://sol.blockrun.ai/api";
93205
- IMAGE_DIR = join9(homedir6(), ".openclaw", "blockrun", "images");
93206
- AUDIO_DIR = join9(homedir6(), ".openclaw", "blockrun", "audio");
93207
- VIDEO_DIR = join9(homedir6(), ".openclaw", "blockrun", "videos");
93789
+ IMAGE_DIR = join10(homedir7(), ".openclaw", "blockrun", "images");
93790
+ AUDIO_DIR = join10(homedir7(), ".openclaw", "blockrun", "audio");
93791
+ VIDEO_DIR = join10(homedir7(), ".openclaw", "blockrun", "videos");
93208
93792
  AUTO_MODEL = "blockrun/auto";
93209
93793
  ROUTING_PROFILES = /* @__PURE__ */ new Set([
93210
93794
  "blockrun/eco",
@@ -94540,7 +95124,7 @@ function buildTool(service, proxyBaseUrl) {
94540
95124
  required
94541
95125
  },
94542
95126
  execute: async (_toolCallId, params) => {
94543
- let path6;
95127
+ let path5;
94544
95128
  const leftoverParams = {};
94545
95129
  let dynamicMethod = "GET";
94546
95130
  let dynamicBody = void 0;
@@ -94552,7 +95136,7 @@ function buildTool(service, proxyBaseUrl) {
94552
95136
  `predexon_endpoint_call: invalid path '${rawPath}' \u2014 must begin with '/pm/' and contain no '..'`
94553
95137
  );
94554
95138
  }
94555
- path6 = `/v1${normalized}`;
95139
+ path5 = `/v1${normalized}`;
94556
95140
  if (typeof params.method === "string") {
94557
95141
  const upper = params.method.toUpperCase();
94558
95142
  if (upper !== "GET" && upper !== "POST") {
@@ -94601,19 +95185,19 @@ function buildTool(service, proxyBaseUrl) {
94601
95185
  }
94602
95186
  }
94603
95187
  } else {
94604
- path6 = `/v1${service.proxyPath}`;
95188
+ path5 = `/v1${service.proxyPath}`;
94605
95189
  for (const [key2, value] of Object.entries(params)) {
94606
95190
  if (value === void 0 || value === null) continue;
94607
95191
  const placeholder = `:${key2}`;
94608
- if (path6.includes(placeholder)) {
94609
- path6 = path6.replace(placeholder, encodeURIComponent(String(value)));
95192
+ if (path5.includes(placeholder)) {
95193
+ path5 = path5.replace(placeholder, encodeURIComponent(String(value)));
94610
95194
  } else {
94611
95195
  leftoverParams[key2] = value;
94612
95196
  }
94613
95197
  }
94614
95198
  }
94615
95199
  const effectiveMethod = service.proxyPath === "/pm/__dynamic__" ? dynamicMethod : service.method;
94616
- let url2 = `${proxyBaseUrl}${path6}`;
95200
+ let url2 = `${proxyBaseUrl}${path5}`;
94617
95201
  if (effectiveMethod === "GET" && Object.keys(leftoverParams).length > 0) {
94618
95202
  const qs = new URLSearchParams();
94619
95203
  for (const [key2, value] of Object.entries(leftoverParams)) {
@@ -106021,11 +106605,11 @@ var require_mime_types = __commonJS({
106021
106605
  }
106022
106606
  return exts[0];
106023
106607
  }
106024
- function lookup(path6) {
106025
- if (!path6 || typeof path6 !== "string") {
106608
+ function lookup(path5) {
106609
+ if (!path5 || typeof path5 !== "string") {
106026
106610
  return false;
106027
106611
  }
106028
- var extension3 = extname("x." + path6).toLowerCase().substr(1);
106612
+ var extension3 = extname("x." + path5).toLowerCase().substr(1);
106029
106613
  if (!extension3) {
106030
106614
  return false;
106031
106615
  }
@@ -107140,7 +107724,7 @@ var require_form_data = __commonJS({
107140
107724
  "use strict";
107141
107725
  var CombinedStream = require_combined_stream();
107142
107726
  var util5 = __require("util");
107143
- var path6 = __require("path");
107727
+ var path5 = __require("path");
107144
107728
  var http5 = __require("http");
107145
107729
  var https2 = __require("https");
107146
107730
  var parseUrl3 = __require("url").parse;
@@ -107271,11 +107855,11 @@ var require_form_data = __commonJS({
107271
107855
  FormData3.prototype._getContentDisposition = function(value, options) {
107272
107856
  var filename;
107273
107857
  if (typeof options.filepath === "string") {
107274
- filename = path6.normalize(options.filepath).replace(/\\/g, "/");
107858
+ filename = path5.normalize(options.filepath).replace(/\\/g, "/");
107275
107859
  } else if (options.filename || value && (value.name || value.path)) {
107276
- filename = path6.basename(options.filename || value && (value.name || value.path));
107860
+ filename = path5.basename(options.filename || value && (value.name || value.path));
107277
107861
  } else if (value && value.readable && hasOwn(value, "httpVersion")) {
107278
- filename = path6.basename(value.client._httpMessage.path || "");
107862
+ filename = path5.basename(value.client._httpMessage.path || "");
107279
107863
  }
107280
107864
  if (filename) {
107281
107865
  return 'filename="' + escapeHeaderParam(filename) + '"';
@@ -107489,9 +108073,9 @@ function isVisitable(thing) {
107489
108073
  function removeBrackets(key2) {
107490
108074
  return utils_default.endsWith(key2, "[]") ? key2.slice(0, -2) : key2;
107491
108075
  }
107492
- function renderKey(path6, key2, dots) {
107493
- if (!path6) return key2;
107494
- return path6.concat(key2).map(function each(token, i) {
108076
+ function renderKey(path5, key2, dots) {
108077
+ if (!path5) return key2;
108078
+ return path5.concat(key2).map(function each(token, i) {
107495
108079
  token = removeBrackets(token);
107496
108080
  return !dots && i ? "[" + token + "]" : token;
107497
108081
  }).join(dots ? "." : "");
@@ -107574,13 +108158,13 @@ function toFormData(obj, formData, options) {
107574
108158
  return currentValue;
107575
108159
  });
107576
108160
  }
107577
- function defaultVisitor(value, key2, path6) {
108161
+ function defaultVisitor(value, key2, path5) {
107578
108162
  let arr = value;
107579
108163
  if (utils_default.isReactNative(formData) && utils_default.isReactNativeBlob(value)) {
107580
- formData.append(renderKey(path6, key2, dots), convertValue(value));
108164
+ formData.append(renderKey(path5, key2, dots), convertValue(value));
107581
108165
  return false;
107582
108166
  }
107583
- if (value && !path6 && typeof value === "object") {
108167
+ if (value && !path5 && typeof value === "object") {
107584
108168
  if (utils_default.endsWith(key2, "{}")) {
107585
108169
  key2 = metaTokens ? key2 : key2.slice(0, -2);
107586
108170
  value = stringifyWithDepthLimit(value, 1);
@@ -107599,7 +108183,7 @@ function toFormData(obj, formData, options) {
107599
108183
  if (isVisitable(value)) {
107600
108184
  return true;
107601
108185
  }
107602
- formData.append(renderKey(path6, key2, dots), convertValue(value));
108186
+ formData.append(renderKey(path5, key2, dots), convertValue(value));
107603
108187
  return false;
107604
108188
  }
107605
108189
  const exposedHelpers = Object.assign(predicates, {
@@ -107607,17 +108191,17 @@ function toFormData(obj, formData, options) {
107607
108191
  convertValue,
107608
108192
  isVisitable
107609
108193
  });
107610
- function build(value, path6, depth = 0) {
108194
+ function build(value, path5, depth = 0) {
107611
108195
  if (utils_default.isUndefined(value)) return;
107612
108196
  throwIfMaxDepthExceeded(depth);
107613
108197
  if (stack.indexOf(value) !== -1) {
107614
- throw new Error("Circular reference detected in " + path6.join("."));
108198
+ throw new Error("Circular reference detected in " + path5.join("."));
107615
108199
  }
107616
108200
  stack.push(value);
107617
108201
  utils_default.forEach(value, function each(el, key2) {
107618
- const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(formData, el, utils_default.isString(key2) ? key2.trim() : key2, path6, exposedHelpers);
108202
+ const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(formData, el, utils_default.isString(key2) ? key2.trim() : key2, path5, exposedHelpers);
107619
108203
  if (result === true) {
107620
- build(el, path6 ? path6.concat(key2) : [key2], depth + 1);
108204
+ build(el, path5 ? path5.concat(key2) : [key2], depth + 1);
107621
108205
  }
107622
108206
  });
107623
108207
  stack.pop();
@@ -107896,7 +108480,7 @@ var init_platform = __esm({
107896
108480
  // node_modules/axios/lib/helpers/toURLEncodedForm.js
107897
108481
  function toURLEncodedForm(data, options) {
107898
108482
  return toFormData_default(data, new platform_default.classes.URLSearchParams(), {
107899
- visitor: function(value, key2, path6, helpers) {
108483
+ visitor: function(value, key2, path5, helpers) {
107900
108484
  if (platform_default.isNode && utils_default.isBuffer(value)) {
107901
108485
  this.append(key2, value.toString("base64"));
107902
108486
  return false;
@@ -107925,14 +108509,14 @@ function throwIfDepthExceeded(index2) {
107925
108509
  }
107926
108510
  }
107927
108511
  function parsePropPath(name) {
107928
- const path6 = [];
108512
+ const path5 = [];
107929
108513
  const pattern = /[^.[\]]+|\[([^.[\]]*)]/g;
107930
108514
  let match;
107931
108515
  while ((match = pattern.exec(name)) !== null) {
107932
- throwIfDepthExceeded(path6.length);
107933
- path6.push(match[0] === "[]" ? "" : match[1] || match[0]);
108516
+ throwIfDepthExceeded(path5.length);
108517
+ path5.push(match[0] === "[]" ? "" : match[1] || match[0]);
107934
108518
  }
107935
- return path6;
108519
+ return path5;
107936
108520
  }
107937
108521
  function arrayToObject(arr) {
107938
108522
  const obj = {};
@@ -107947,12 +108531,12 @@ function arrayToObject(arr) {
107947
108531
  return obj;
107948
108532
  }
107949
108533
  function formDataToJSON(formData) {
107950
- function buildPath(path6, value, target, index2) {
108534
+ function buildPath(path5, value, target, index2) {
107951
108535
  throwIfDepthExceeded(index2);
107952
- let name = path6[index2++];
108536
+ let name = path5[index2++];
107953
108537
  if (name === "__proto__") return true;
107954
108538
  const isNumericKey = Number.isFinite(+name);
107955
- const isLast = index2 >= path6.length;
108539
+ const isLast = index2 >= path5.length;
107956
108540
  name = !name && utils_default.isArray(target) ? target.length : name;
107957
108541
  if (isLast) {
107958
108542
  if (utils_default.hasOwnProp(target, name)) {
@@ -107965,7 +108549,7 @@ function formDataToJSON(formData) {
107965
108549
  if (!utils_default.hasOwnProp(target, name) || !utils_default.isObject(target[name])) {
107966
108550
  target[name] = [];
107967
108551
  }
107968
- const result = buildPath(path6, value, target[name], index2);
108552
+ const result = buildPath(path5, value, target[name], index2);
107969
108553
  if (result && utils_default.isArray(target[name])) {
107970
108554
  target[name] = arrayToObject(target[name]);
107971
108555
  }
@@ -111512,9 +112096,9 @@ var init_http4 = __esm({
111512
112096
  auth = urlUsername + ":" + urlPassword;
111513
112097
  }
111514
112098
  auth && headers.delete("authorization");
111515
- let path6;
112099
+ let path5;
111516
112100
  try {
111517
- path6 = buildURL(
112101
+ path5 = buildURL(
111518
112102
  parsed.pathname + parsed.search,
111519
112103
  own2("params"),
111520
112104
  own2("paramsSerializer")
@@ -111533,7 +112117,7 @@ var init_http4 = __esm({
111533
112117
  false
111534
112118
  );
111535
112119
  const options = Object.assign(/* @__PURE__ */ Object.create(null), {
111536
- path: path6,
112120
+ path: path5,
111537
112121
  method,
111538
112122
  headers: toByteStringHeaderObject(headers),
111539
112123
  agents: { http: httpAgent, https: httpsAgent },
@@ -111950,14 +112534,14 @@ var init_cookies = __esm({
111950
112534
  cookies_default = platform_default.hasStandardBrowserEnv ? (
111951
112535
  // Standard browser envs support document.cookie
111952
112536
  {
111953
- write(name, value, expires, path6, domain, secure, sameSite) {
112537
+ write(name, value, expires, path5, domain, secure, sameSite) {
111954
112538
  if (typeof document === "undefined") return;
111955
112539
  const cookie = [`${name}=${encodeURIComponent(value)}`];
111956
112540
  if (utils_default.isNumber(expires)) {
111957
112541
  cookie.push(`expires=${new Date(expires).toUTCString()}`);
111958
112542
  }
111959
- if (utils_default.isString(path6)) {
111960
- cookie.push(`path=${path6}`);
112543
+ if (utils_default.isString(path5)) {
112544
+ cookie.push(`path=${path5}`);
111961
112545
  }
111962
112546
  if (utils_default.isString(domain)) {
111963
112547
  cookie.push(`domain=${domain}`);
@@ -115386,15 +115970,15 @@ var init_constants3 = __esm({
115386
115970
  });
115387
115971
 
115388
115972
  // src/polymarket/wallet-adapter.ts
115389
- import fs from "fs";
115390
- import { homedir as homedir7 } from "os";
115391
- import { join as join10 } from "path";
115973
+ import fs2 from "fs";
115974
+ import { homedir as homedir8 } from "os";
115975
+ import { join as join11 } from "path";
115392
115976
  function getOrCreateWalletKey() {
115393
115977
  const envKey = process.env.BLOCKRUN_WALLET_KEY?.trim();
115394
115978
  if (envKey && /^0x[0-9a-fA-F]{64}$/.test(envKey)) return envKey;
115395
115979
  let key2;
115396
115980
  try {
115397
- key2 = fs.readFileSync(WALLET_FILE2, "utf-8").trim();
115981
+ key2 = fs2.readFileSync(WALLET_FILE2, "utf-8").trim();
115398
115982
  } catch (err) {
115399
115983
  if (err.code === "ENOENT") {
115400
115984
  throw new Error(
@@ -115436,7 +116020,7 @@ var init_wallet_adapter = __esm({
115436
116020
  init_esm();
115437
116021
  init_chains();
115438
116022
  init_constants3();
115439
- WALLET_FILE2 = join10(homedir7(), ".openclaw", "blockrun", "wallet.key");
116023
+ WALLET_FILE2 = join11(homedir8(), ".openclaw", "blockrun", "wallet.key");
115440
116024
  BASE_RPC_URLS = [
115441
116025
  "https://mainnet.base.org",
115442
116026
  "https://base.llamarpc.com",
@@ -115447,21 +116031,21 @@ var init_wallet_adapter = __esm({
115447
116031
  });
115448
116032
 
115449
116033
  // src/polymarket/creds.ts
115450
- import fs2 from "fs";
115451
- import path from "path";
116034
+ import fs3 from "fs";
116035
+ import path2 from "path";
115452
116036
  import os from "os";
115453
116037
  function readJsonFile(file) {
115454
116038
  try {
115455
- if (!fs2.existsSync(file)) return null;
115456
- const raw = fs2.readFileSync(file, "utf-8").trim();
116039
+ if (!fs3.existsSync(file)) return null;
116040
+ const raw = fs3.readFileSync(file, "utf-8").trim();
115457
116041
  return raw ? JSON.parse(raw) : null;
115458
116042
  } catch {
115459
116043
  return null;
115460
116044
  }
115461
116045
  }
115462
116046
  function writeJsonFile(file, value) {
115463
- fs2.mkdirSync(BLOCKRUN_DIR, { recursive: true });
115464
- fs2.writeFileSync(file, JSON.stringify(value, null, 2), { mode: 384 });
116047
+ fs3.mkdirSync(BLOCKRUN_DIR, { recursive: true });
116048
+ fs3.writeFileSync(file, JSON.stringify(value, null, 2), { mode: 384 });
115465
116049
  }
115466
116050
  function credsKey(address2, sigType) {
115467
116051
  return `${address2.toLowerCase()}:${sigType}`;
@@ -115513,10 +116097,10 @@ var BLOCKRUN_DIR, CREDS_FILE, BUILDER_CREDS_FILE, STATE_FILE;
115513
116097
  var init_creds = __esm({
115514
116098
  "src/polymarket/creds.ts"() {
115515
116099
  "use strict";
115516
- BLOCKRUN_DIR = path.join(os.homedir(), ".openclaw", "blockrun");
115517
- CREDS_FILE = path.join(BLOCKRUN_DIR, ".polymarket-creds");
115518
- BUILDER_CREDS_FILE = path.join(BLOCKRUN_DIR, ".polymarket-builder-creds");
115519
- STATE_FILE = path.join(BLOCKRUN_DIR, ".polymarket.json");
116100
+ BLOCKRUN_DIR = path2.join(os.homedir(), ".openclaw", "blockrun");
116101
+ CREDS_FILE = path2.join(BLOCKRUN_DIR, ".polymarket-creds");
116102
+ BUILDER_CREDS_FILE = path2.join(BLOCKRUN_DIR, ".polymarket-builder-creds");
116103
+ STATE_FILE = path2.join(BLOCKRUN_DIR, ".polymarket.json");
115520
116104
  }
115521
116105
  });
115522
116106
 
@@ -116698,13 +117282,13 @@ function __disposeResources(env) {
116698
117282
  }
116699
117283
  return next();
116700
117284
  }
116701
- function __rewriteRelativeImportExtension(path6, preserveJsx) {
116702
- if (typeof path6 === "string" && /^\.\.?\//.test(path6)) {
116703
- return path6.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
117285
+ function __rewriteRelativeImportExtension(path5, preserveJsx) {
117286
+ if (typeof path5 === "string" && /^\.\.?\//.test(path5)) {
117287
+ return path5.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
116704
117288
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
116705
117289
  });
116706
117290
  }
116707
- return path6;
117291
+ return path5;
116708
117292
  }
116709
117293
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
116710
117294
  var init_tslib_es6 = __esm({
@@ -149001,9 +149585,9 @@ var require_setupKzg = __commonJS({
149001
149585
  Object.defineProperty(exports, "__esModule", { value: true });
149002
149586
  exports.setupKzg = setupKzg;
149003
149587
  var defineKzg_js_1 = require_defineKzg();
149004
- function setupKzg(parameters, path6) {
149588
+ function setupKzg(parameters, path5) {
149005
149589
  try {
149006
- parameters.loadTrustedSetup(path6);
149590
+ parameters.loadTrustedSetup(path5);
149007
149591
  } catch (e7) {
149008
149592
  const error = e7;
149009
149593
  if (!error.message.includes("trusted setup is already loaded"))
@@ -197088,12 +197672,12 @@ var init_fragments = __esm({
197088
197672
  // node_modules/@ethersproject/abi/lib.esm/coders/abstract-coder.js
197089
197673
  function checkResultErrors(result) {
197090
197674
  const errors = [];
197091
- const checkErrors = function(path6, object) {
197675
+ const checkErrors = function(path5, object) {
197092
197676
  if (!Array.isArray(object)) {
197093
197677
  return;
197094
197678
  }
197095
197679
  for (let key2 in object) {
197096
- const childPath = path6.slice();
197680
+ const childPath = path5.slice();
197097
197681
  childPath.push(key2);
197098
197682
  try {
197099
197683
  checkErrors(childPath, object[key2]);
@@ -202911,8 +203495,8 @@ function createCommonjsModule(fn, basedir, module) {
202911
203495
  return module = {
202912
203496
  path: basedir,
202913
203497
  exports: {},
202914
- require: function(path6, base3) {
202915
- return commonjsRequire(path6, base3 === void 0 || base3 === null ? module.path : base3);
203498
+ require: function(path5, base3) {
203499
+ return commonjsRequire(path5, base3 === void 0 || base3 === null ? module.path : base3);
202916
203500
  }
202917
203501
  }, fn(module, module.exports), module.exports;
202918
203502
  }
@@ -206762,9 +207346,9 @@ var init_lib23 = __esm({
206762
207346
  if (index2 > 4294967295) {
206763
207347
  throw new Error("invalid index - " + String(index2));
206764
207348
  }
206765
- let path6 = this.path;
206766
- if (path6) {
206767
- path6 += "/" + (index2 & ~HardenedBit);
207349
+ let path5 = this.path;
207350
+ if (path5) {
207351
+ path5 += "/" + (index2 & ~HardenedBit);
206768
207352
  }
206769
207353
  const data = new Uint8Array(37);
206770
207354
  if (index2 & HardenedBit) {
@@ -206772,8 +207356,8 @@ var init_lib23 = __esm({
206772
207356
  throw new Error("cannot derive child of neutered node");
206773
207357
  }
206774
207358
  data.set(arrayify(this.privateKey), 1);
206775
- if (path6) {
206776
- path6 += "'";
207359
+ if (path5) {
207360
+ path5 += "'";
206777
207361
  }
206778
207362
  } else {
206779
207363
  data.set(arrayify(this.publicKey));
@@ -206792,21 +207376,21 @@ var init_lib23 = __esm({
206792
207376
  const ek = new SigningKey(hexlify(IL));
206793
207377
  Ki = ek._addPoint(this.publicKey);
206794
207378
  }
206795
- let mnemonicOrPath = path6;
207379
+ let mnemonicOrPath = path5;
206796
207380
  const srcMnemonic = this.mnemonic;
206797
207381
  if (srcMnemonic) {
206798
207382
  mnemonicOrPath = Object.freeze({
206799
207383
  phrase: srcMnemonic.phrase,
206800
- path: path6,
207384
+ path: path5,
206801
207385
  locale: srcMnemonic.locale || "en"
206802
207386
  });
206803
207387
  }
206804
207388
  return new _HDNode(_constructorGuard4, ki, Ki, this.fingerprint, bytes32(IR), index2, this.depth + 1, mnemonicOrPath);
206805
207389
  }
206806
- derivePath(path6) {
206807
- const components = path6.split("/");
207390
+ derivePath(path5) {
207391
+ const components = path5.split("/");
206808
207392
  if (components.length === 0 || components[0] === "m" && this.depth !== 0) {
206809
- throw new Error("invalid path - " + path6);
207393
+ throw new Error("invalid path - " + path5);
206810
207394
  }
206811
207395
  if (components[0] === "m") {
206812
207396
  components.shift();
@@ -207541,9 +208125,9 @@ function getPassword(password) {
207541
208125
  }
207542
208126
  return arrayify(password);
207543
208127
  }
207544
- function searchPath(object, path6) {
208128
+ function searchPath(object, path5) {
207545
208129
  let currentChild = object;
207546
- const comps = path6.toLowerCase().split("/");
208130
+ const comps = path5.toLowerCase().split("/");
207547
208131
  for (let i = 0; i < comps.length; i++) {
207548
208132
  let matchingChild = null;
207549
208133
  for (const key2 in currentChild) {
@@ -208192,12 +208776,12 @@ function _getAccount(data, key2) {
208192
208776
  const mnemonicIv = looseArrayify(searchPath(data, "x-ethers/mnemonicCounter"));
208193
208777
  const mnemonicCounter = new import_aes_js2.default.Counter(mnemonicIv);
208194
208778
  const mnemonicAesCtr = new import_aes_js2.default.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter);
208195
- const path6 = searchPath(data, "x-ethers/path") || defaultPath;
208779
+ const path5 = searchPath(data, "x-ethers/path") || defaultPath;
208196
208780
  const locale = searchPath(data, "x-ethers/locale") || "en";
208197
208781
  const entropy = arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext));
208198
208782
  try {
208199
208783
  const mnemonic = entropyToMnemonic2(entropy, locale);
208200
- const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path6);
208784
+ const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path5);
208201
208785
  if (node.privateKey != account.privateKey) {
208202
208786
  throw new Error("mnemonic mismatch");
208203
208787
  }
@@ -208297,12 +208881,12 @@ function encrypt(account, password, options, progressCallback) {
208297
208881
  const privateKey = arrayify(account.privateKey);
208298
208882
  const passwordBytes = getPassword(password);
208299
208883
  let entropy = null;
208300
- let path6 = null;
208884
+ let path5 = null;
208301
208885
  let locale = null;
208302
208886
  if (hasMnemonic(account)) {
208303
208887
  const srcMnemonic = account.mnemonic;
208304
208888
  entropy = arrayify(mnemonicToEntropy2(srcMnemonic.phrase, srcMnemonic.locale || "en"));
208305
- path6 = srcMnemonic.path || defaultPath;
208889
+ path5 = srcMnemonic.path || defaultPath;
208306
208890
  locale = srcMnemonic.locale || "en";
208307
208891
  }
208308
208892
  let client = options.client;
@@ -208388,7 +208972,7 @@ function encrypt(account, password, options, progressCallback) {
208388
208972
  gethFilename: "UTC--" + timestamp + "--" + data.address,
208389
208973
  mnemonicCounter: hexlify(mnemonicIv).substring(2),
208390
208974
  mnemonicCiphertext: hexlify(mnemonicCiphertext).substring(2),
208391
- path: path6,
208975
+ path: path5,
208392
208976
  locale,
208393
208977
  version: "0.1"
208394
208978
  };
@@ -208682,11 +209266,11 @@ var init_lib26 = __esm({
208682
209266
  static fromEncryptedJsonSync(json, password) {
208683
209267
  return new _Wallet(decryptJsonWalletSync(json, password));
208684
209268
  }
208685
- static fromMnemonic(mnemonic, path6, wordlist3) {
208686
- if (!path6) {
208687
- path6 = defaultPath;
209269
+ static fromMnemonic(mnemonic, path5, wordlist3) {
209270
+ if (!path5) {
209271
+ path5 = defaultPath;
208688
209272
  }
208689
- return new _Wallet(HDNode.fromMnemonic(mnemonic, null, wordlist3).derivePath(path6));
209273
+ return new _Wallet(HDNode.fromMnemonic(mnemonic, null, wordlist3).derivePath(path5));
208690
209274
  }
208691
209275
  };
208692
209276
  }
@@ -214682,21 +215266,21 @@ var init_web3_provider = __esm({
214682
215266
  if (provider == null) {
214683
215267
  logger43.throwArgumentError("missing provider", "provider", provider);
214684
215268
  }
214685
- let path6 = null;
215269
+ let path5 = null;
214686
215270
  let jsonRpcFetchFunc = null;
214687
215271
  let subprovider = null;
214688
215272
  if (typeof provider === "function") {
214689
- path6 = "unknown:";
215273
+ path5 = "unknown:";
214690
215274
  jsonRpcFetchFunc = provider;
214691
215275
  } else {
214692
- path6 = provider.host || provider.path || "";
214693
- if (!path6 && provider.isMetaMask) {
214694
- path6 = "metamask";
215276
+ path5 = provider.host || provider.path || "";
215277
+ if (!path5 && provider.isMetaMask) {
215278
+ path5 = "metamask";
214695
215279
  }
214696
215280
  subprovider = provider;
214697
215281
  if (provider.request) {
214698
- if (path6 === "") {
214699
- path6 = "eip-1193:";
215282
+ if (path5 === "") {
215283
+ path5 = "eip-1193:";
214700
215284
  }
214701
215285
  jsonRpcFetchFunc = buildEip1193Fetcher(provider);
214702
215286
  } else if (provider.sendAsync) {
@@ -214706,11 +215290,11 @@ var init_web3_provider = __esm({
214706
215290
  } else {
214707
215291
  logger43.throwArgumentError("unsupported provider", "provider", provider);
214708
215292
  }
214709
- if (!path6) {
214710
- path6 = "unknown:";
215293
+ if (!path5) {
215294
+ path5 = "unknown:";
214711
215295
  }
214712
215296
  }
214713
- super(path6, network);
215297
+ super(path5, network);
214714
215298
  defineReadOnly(this, "jsonRpcFetchFunc", jsonRpcFetchFunc);
214715
215299
  defineReadOnly(this, "provider", subprovider);
214716
215300
  }
@@ -215548,7 +216132,7 @@ var require_axios = __commonJS({
215548
216132
  var https2 = __require("https");
215549
216133
  var http23 = __require("http2");
215550
216134
  var util5 = __require("util");
215551
- var path6 = __require("path");
216135
+ var path5 = __require("path");
215552
216136
  var followRedirects2 = require_follow_redirects();
215553
216137
  var zlib2 = __require("zlib");
215554
216138
  var stream4 = __require("stream");
@@ -216616,9 +217200,9 @@ var require_axios = __commonJS({
216616
217200
  function removeBrackets2(key2) {
216617
217201
  return utils$1.endsWith(key2, "[]") ? key2.slice(0, -2) : key2;
216618
217202
  }
216619
- function renderKey2(path7, key2, dots) {
216620
- if (!path7) return key2;
216621
- return path7.concat(key2).map(function each(token, i) {
217203
+ function renderKey2(path6, key2, dots) {
217204
+ if (!path6) return key2;
217205
+ return path6.concat(key2).map(function each(token, i) {
216622
217206
  token = removeBrackets2(token);
216623
217207
  return !dots && i ? "[" + token + "]" : token;
216624
217208
  }).join(dots ? "." : "");
@@ -216696,13 +217280,13 @@ var require_axios = __commonJS({
216696
217280
  return currentValue;
216697
217281
  });
216698
217282
  }
216699
- function defaultVisitor(value, key2, path7) {
217283
+ function defaultVisitor(value, key2, path6) {
216700
217284
  let arr = value;
216701
217285
  if (utils$1.isReactNative(formData) && utils$1.isReactNativeBlob(value)) {
216702
- formData.append(renderKey2(path7, key2, dots), convertValue(value));
217286
+ formData.append(renderKey2(path6, key2, dots), convertValue(value));
216703
217287
  return false;
216704
217288
  }
216705
- if (value && !path7 && typeof value === "object") {
217289
+ if (value && !path6 && typeof value === "object") {
216706
217290
  if (utils$1.endsWith(key2, "{}")) {
216707
217291
  key2 = metaTokens ? key2 : key2.slice(0, -2);
216708
217292
  value = stringifyWithDepthLimit(value, 1);
@@ -216721,7 +217305,7 @@ var require_axios = __commonJS({
216721
217305
  if (isVisitable2(value)) {
216722
217306
  return true;
216723
217307
  }
216724
- formData.append(renderKey2(path7, key2, dots), convertValue(value));
217308
+ formData.append(renderKey2(path6, key2, dots), convertValue(value));
216725
217309
  return false;
216726
217310
  }
216727
217311
  const exposedHelpers = Object.assign(predicates2, {
@@ -216729,17 +217313,17 @@ var require_axios = __commonJS({
216729
217313
  convertValue,
216730
217314
  isVisitable: isVisitable2
216731
217315
  });
216732
- function build(value, path7, depth = 0) {
217316
+ function build(value, path6, depth = 0) {
216733
217317
  if (utils$1.isUndefined(value)) return;
216734
217318
  throwIfMaxDepthExceeded(depth);
216735
217319
  if (stack.indexOf(value) !== -1) {
216736
- throw new Error("Circular reference detected in " + path7.join("."));
217320
+ throw new Error("Circular reference detected in " + path6.join("."));
216737
217321
  }
216738
217322
  stack.push(value);
216739
217323
  utils$1.forEach(value, function each(el, key2) {
216740
- const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key2) ? key2.trim() : key2, path7, exposedHelpers);
217324
+ const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key2) ? key2.trim() : key2, path6, exposedHelpers);
216741
217325
  if (result === true) {
216742
- build(el, path7 ? path7.concat(key2) : [key2], depth + 1);
217326
+ build(el, path6 ? path6.concat(key2) : [key2], depth + 1);
216743
217327
  }
216744
217328
  });
216745
217329
  stack.pop();
@@ -216928,7 +217512,7 @@ var require_axios = __commonJS({
216928
217512
  };
216929
217513
  function toURLEncodedForm2(data, options) {
216930
217514
  return toFormData3(data, new platform.classes.URLSearchParams(), {
216931
- visitor: function(value, key2, path7, helpers) {
217515
+ visitor: function(value, key2, path6, helpers) {
216932
217516
  if (platform.isNode && utils$1.isBuffer(value)) {
216933
217517
  this.append(key2, value.toString("base64"));
216934
217518
  return false;
@@ -216945,14 +217529,14 @@ var require_axios = __commonJS({
216945
217529
  }
216946
217530
  }
216947
217531
  function parsePropPath2(name) {
216948
- const path7 = [];
217532
+ const path6 = [];
216949
217533
  const pattern = /[^.[\]]+|\[([^.[\]]*)]/g;
216950
217534
  let match;
216951
217535
  while ((match = pattern.exec(name)) !== null) {
216952
- throwIfDepthExceeded2(path7.length);
216953
- path7.push(match[0] === "[]" ? "" : match[1] || match[0]);
217536
+ throwIfDepthExceeded2(path6.length);
217537
+ path6.push(match[0] === "[]" ? "" : match[1] || match[0]);
216954
217538
  }
216955
- return path7;
217539
+ return path6;
216956
217540
  }
216957
217541
  function arrayToObject2(arr) {
216958
217542
  const obj = {};
@@ -216967,12 +217551,12 @@ var require_axios = __commonJS({
216967
217551
  return obj;
216968
217552
  }
216969
217553
  function formDataToJSON2(formData) {
216970
- function buildPath(path7, value, target, index2) {
217554
+ function buildPath(path6, value, target, index2) {
216971
217555
  throwIfDepthExceeded2(index2);
216972
- let name = path7[index2++];
217556
+ let name = path6[index2++];
216973
217557
  if (name === "__proto__") return true;
216974
217558
  const isNumericKey = Number.isFinite(+name);
216975
- const isLast = index2 >= path7.length;
217559
+ const isLast = index2 >= path6.length;
216976
217560
  name = !name && utils$1.isArray(target) ? target.length : name;
216977
217561
  if (isLast) {
216978
217562
  if (utils$1.hasOwnProp(target, name)) {
@@ -216985,7 +217569,7 @@ var require_axios = __commonJS({
216985
217569
  if (!utils$1.hasOwnProp(target, name) || !utils$1.isObject(target[name])) {
216986
217570
  target[name] = [];
216987
217571
  }
216988
- const result = buildPath(path7, value, target[name], index2);
217572
+ const result = buildPath(path6, value, target[name], index2);
216989
217573
  if (result && utils$1.isArray(target[name])) {
216990
217574
  target[name] = arrayToObject2(target[name]);
216991
217575
  }
@@ -218596,8 +219180,8 @@ var require_axios = __commonJS({
218596
219180
  const allowedSocketPaths = own3("allowedSocketPaths");
218597
219181
  if (allowedSocketPaths != null) {
218598
219182
  const allowed = Array.isArray(allowedSocketPaths) ? allowedSocketPaths : [allowedSocketPaths];
218599
- const resolvedSocket = path6.resolve(socketPath);
218600
- const isAllowed = allowed.some((entry) => typeof entry === "string" && path6.resolve(entry) === resolvedSocket);
219183
+ const resolvedSocket = path5.resolve(socketPath);
219184
+ const isAllowed = allowed.some((entry) => typeof entry === "string" && path5.resolve(entry) === resolvedSocket);
218601
219185
  if (!isAllowed) {
218602
219186
  return reject(new AxiosError3(`socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError3.ERR_BAD_OPTION_VALUE, config));
218603
219187
  }
@@ -218896,14 +219480,14 @@ var require_axios = __commonJS({
218896
219480
  var cookies = platform.hasStandardBrowserEnv ? (
218897
219481
  // Standard browser envs support document.cookie
218898
219482
  {
218899
- write(name, value, expires, path7, domain, secure, sameSite) {
219483
+ write(name, value, expires, path6, domain, secure, sameSite) {
218900
219484
  if (typeof document === "undefined") return;
218901
219485
  const cookie = [`${name}=${encodeURIComponent(value)}`];
218902
219486
  if (utils$1.isNumber(expires)) {
218903
219487
  cookie.push(`expires=${new Date(expires).toUTCString()}`);
218904
219488
  }
218905
- if (utils$1.isString(path7)) {
218906
- cookie.push(`path=${path7}`);
219489
+ if (utils$1.isString(path6)) {
219490
+ cookie.push(`path=${path6}`);
218907
219491
  }
218908
219492
  if (utils$1.isString(domain)) {
218909
219493
  cookie.push(`domain=${domain}`);
@@ -223392,18 +223976,18 @@ var require_client2 = __commonJS({
223392
223976
  }
223393
223977
  console.log(`Transaction not found or not in given states, timing out!`);
223394
223978
  }
223395
- async sendAuthedRequest(method, path6, body) {
223979
+ async sendAuthedRequest(method, path5, body) {
223396
223980
  if (this.canBuilderAuth()) {
223397
- const builderHeaders = await this._generateBuilderHeaders(method, path6, body);
223981
+ const builderHeaders = await this._generateBuilderHeaders(method, path5, body);
223398
223982
  if (builderHeaders !== void 0) {
223399
- return this.send(path6, method, { headers: builderHeaders, data: body });
223983
+ return this.send(path5, method, { headers: builderHeaders, data: body });
223400
223984
  }
223401
223985
  }
223402
- return this.send(path6, method, { data: body });
223986
+ return this.send(path5, method, { data: body });
223403
223987
  }
223404
- async _generateBuilderHeaders(method, path6, body) {
223988
+ async _generateBuilderHeaders(method, path5, body) {
223405
223989
  if (this.builderConfig !== void 0) {
223406
- const builderHeaders = await this.builderConfig.generateBuilderHeaders(method, path6, body);
223990
+ const builderHeaders = await this.builderConfig.generateBuilderHeaders(method, path5, body);
223407
223991
  if (builderHeaders == void 0) {
223408
223992
  return void 0;
223409
223993
  }
@@ -223494,12 +224078,12 @@ var require_signer = __commonJS({
223494
224078
  constructor(creds) {
223495
224079
  this.creds = creds;
223496
224080
  }
223497
- createBuilderHeaderPayload(method, path6, body, timestamp) {
224081
+ createBuilderHeaderPayload(method, path5, body, timestamp) {
223498
224082
  let ts = Math.floor(Date.now() / 1e3);
223499
224083
  if (timestamp !== void 0) {
223500
224084
  ts = timestamp;
223501
224085
  }
223502
- const builderSig = (0, signing_1.buildHmacSignature)(this.creds.secret, ts, method, path6, body);
224086
+ const builderSig = (0, signing_1.buildHmacSignature)(this.creds.secret, ts, method, path5, body);
223503
224087
  return {
223504
224088
  POLY_BUILDER_API_KEY: this.creds.key,
223505
224089
  POLY_BUILDER_PASSPHRASE: this.creds.passphrase,
@@ -223588,17 +224172,17 @@ var require_config2 = __commonJS({
223588
224172
  * @param path
223589
224173
  * @param body
223590
224174
  */
223591
- async generateBuilderHeaders(method, path6, body, timestamp) {
224175
+ async generateBuilderHeaders(method, path5, body, timestamp) {
223592
224176
  this.ensureValid();
223593
224177
  const builderType = this.getBuilderType();
223594
224178
  if (builderType == types_1.BuilderType.LOCAL) {
223595
- return Promise.resolve(this.signer?.createBuilderHeaderPayload(method, path6, body, timestamp));
224179
+ return Promise.resolve(this.signer?.createBuilderHeaderPayload(method, path5, body, timestamp));
223596
224180
  }
223597
224181
  if (builderType == types_1.BuilderType.REMOTE) {
223598
224182
  const url2 = this.remoteBuilderConfig.url;
223599
224183
  const payload = {
223600
224184
  method,
223601
- path: path6,
224185
+ path: path5,
223602
224186
  body,
223603
224187
  timestamp
223604
224188
  };
@@ -224380,11 +224964,11 @@ var init_withdraw = __esm({
224380
224964
  });
224381
224965
 
224382
224966
  // node_modules/@blockrun/llm/dist/index.js
224383
- import * as path2 from "path";
224967
+ import * as path3 from "path";
224384
224968
  import * as os2 from "os";
224385
224969
  import * as path22 from "path";
224386
224970
  import * as os22 from "os";
224387
- import * as path3 from "path";
224971
+ import * as path32 from "path";
224388
224972
  import * as os3 from "os";
224389
224973
  import * as path4 from "path";
224390
224974
  import * as os4 from "os";
@@ -224558,7 +225142,7 @@ function resolveDefaultTimeout() {
224558
225142
  function sleep2(ms) {
224559
225143
  return new Promise((r2) => setTimeout(r2, ms));
224560
225144
  }
224561
- var BlockrunError, PaymentError, APIError, BASE_CHAIN_ID2, USDC_BASE2, USDC_DOMAIN, TRANSFER_TYPES, BLOCKRUN_SERVICE_CODE2, LOCALHOST_DOMAINS, BLOCKRUN_DIR2, COST_LOG_FILE, SDK_VERSION, USER_AGENT2, DEFAULT_TIMEOUT, PHONE_PRICES, DEFAULT_API_URL13, DEFAULT_TIMEOUT13, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_BUDGET_MS, MAX_SIGNED_AUTH_SECONDS, BlockrunClient, WALLET_DIR2, WALLET_FILE3, WALLET_DIR22, SOLANA_WALLET_FILE, CACHE_DIR, DATA_DIR, COST_LOG_FILE2, DEFAULT_TTL;
225145
+ var BlockrunError, PaymentError, APIError, BASE_CHAIN_ID2, USDC_BASE2, USDC_DOMAIN, TRANSFER_TYPES, BLOCKRUN_SERVICE_CODE2, LOCALHOST_DOMAINS, BLOCKRUN_DIR2, COST_LOG_FILE, SDK_VERSION, USER_AGENT2, DEFAULT_TIMEOUT, PHONE_PRICES, DEFAULT_API_URL13, DEFAULT_TIMEOUT13, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_BUDGET_MS, MAX_SIGNED_AUTH_SECONDS, BlockrunClient, WALLET_DIR3, WALLET_FILE3, WALLET_DIR22, SOLANA_WALLET_FILE, CACHE_DIR, DATA_DIR, COST_LOG_FILE2, DEFAULT_TTL;
224562
225146
  var init_dist7 = __esm({
224563
225147
  "node_modules/@blockrun/llm/dist/index.js"() {
224564
225148
  "use strict";
@@ -224606,8 +225190,8 @@ var init_dist7 = __esm({
224606
225190
  };
224607
225191
  BLOCKRUN_SERVICE_CODE2 = "blockrun";
224608
225192
  LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
224609
- BLOCKRUN_DIR2 = path2.join(os2.homedir(), ".blockrun");
224610
- COST_LOG_FILE = path2.join(BLOCKRUN_DIR2, "cost_log.jsonl");
225193
+ BLOCKRUN_DIR2 = path3.join(os2.homedir(), ".blockrun");
225194
+ COST_LOG_FILE = path3.join(BLOCKRUN_DIR2, "cost_log.jsonl");
224611
225195
  SDK_VERSION = "3.10.0";
224612
225196
  USER_AGENT2 = `blockrun-ts/${SDK_VERSION}`;
224613
225197
  DEFAULT_TIMEOUT = resolveDefaultTimeout();
@@ -224652,15 +225236,15 @@ var init_dist7 = __esm({
224652
225236
  * `/api` is tolerated and stripped). Query params are URL-encoded; arrays
224653
225237
  * become repeated keys (`?a=1&a=2`); undefined/null are dropped.
224654
225238
  */
224655
- async get(path52, params) {
224656
- const url2 = this.buildUrl(path52, params);
225239
+ async get(path5, params) {
225240
+ const url2 = this.buildUrl(path5, params);
224657
225241
  return this.requestWithPayment(url2, "GET");
224658
225242
  }
224659
225243
  /**
224660
225244
  * POST a BlockRun endpoint with a JSON body.
224661
225245
  */
224662
- async post(path52, body) {
224663
- const url2 = this.buildUrl(path52);
225246
+ async post(path5, body) {
225247
+ const url2 = this.buildUrl(path5);
224664
225248
  return this.requestWithPayment(url2, "POST", body);
224665
225249
  }
224666
225250
  /**
@@ -224675,8 +225259,8 @@ var init_dist7 = __esm({
224675
225259
  * short-circuits and returns the body. Most long-running endpoints (image,
224676
225260
  * video, music, voice) return 202 with a poll_url.
224677
225261
  */
224678
- async poll(path52, body, options) {
224679
- const submitUrl = this.buildUrl(path52);
225262
+ async poll(path5, body, options) {
225263
+ const submitUrl = this.buildUrl(path5);
224680
225264
  const budgetMs = options?.budgetMs ?? DEFAULT_POLL_BUDGET_MS;
224681
225265
  const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
224682
225266
  const resp402 = await this.fetchWithTimeout(submitUrl, {
@@ -224775,8 +225359,8 @@ var init_dist7 = __esm({
224775
225359
  * process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
224776
225360
  * }
224777
225361
  */
224778
- async *stream(path52, body) {
224779
- const url2 = this.buildUrl(path52);
225362
+ async *stream(path5, body) {
225363
+ const url2 = this.buildUrl(path5);
224780
225364
  const requestBody = JSON.stringify(body ?? {});
224781
225365
  const resp402 = await this.fetchWithTimeout(url2, {
224782
225366
  method: "POST",
@@ -224842,8 +225426,8 @@ var init_dist7 = __esm({
224842
225426
  // --------------------------------------------------------------------
224843
225427
  // Internal: shared infrastructure
224844
225428
  // --------------------------------------------------------------------
224845
- buildUrl(path52, params) {
224846
- let normalized = path52.startsWith("/") ? path52 : `/${path52}`;
225429
+ buildUrl(path5, params) {
225430
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
224847
225431
  if (normalized.startsWith("/api/")) {
224848
225432
  normalized = normalized.slice(4);
224849
225433
  }
@@ -224991,10 +225575,10 @@ var init_dist7 = __esm({
224991
225575
  return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
224992
225576
  }
224993
225577
  };
224994
- WALLET_DIR2 = path22.join(os22.homedir(), ".blockrun");
224995
- WALLET_FILE3 = path22.join(WALLET_DIR2, ".session");
224996
- WALLET_DIR22 = path3.join(os3.homedir(), ".blockrun");
224997
- SOLANA_WALLET_FILE = path3.join(WALLET_DIR22, ".solana-session");
225578
+ WALLET_DIR3 = path22.join(os22.homedir(), ".blockrun");
225579
+ WALLET_FILE3 = path22.join(WALLET_DIR3, ".session");
225580
+ WALLET_DIR22 = path32.join(os3.homedir(), ".blockrun");
225581
+ SOLANA_WALLET_FILE = path32.join(WALLET_DIR22, ".solana-session");
224998
225582
  CACHE_DIR = path4.join(os4.homedir(), ".blockrun", "cache");
224999
225583
  DATA_DIR = path4.join(os4.homedir(), ".blockrun", "data");
225000
225584
  COST_LOG_FILE2 = path4.join(os4.homedir(), ".blockrun", "cost_log.jsonl");
@@ -225490,261 +226074,6 @@ var init_mcp_config = __esm({
225490
226074
  }
225491
226075
  });
225492
226076
 
225493
- // src/spend-control.ts
225494
- import * as fs3 from "fs";
225495
- import * as path5 from "path";
225496
- import { homedir as homedir12 } from "os";
225497
- function formatDuration(seconds) {
225498
- if (seconds < 60) {
225499
- return `${seconds}s`;
225500
- } else if (seconds < 3600) {
225501
- const mins = Math.ceil(seconds / 60);
225502
- return `${mins} min`;
225503
- } else {
225504
- const hours = Math.floor(seconds / 3600);
225505
- const mins = Math.ceil(seconds % 3600 / 60);
225506
- return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
225507
- }
225508
- }
225509
- var WALLET_DIR3, HOUR_MS, DAY_MS, FileSpendControlStorage, InMemorySpendControlStorage, SpendControl;
225510
- var init_spend_control = __esm({
225511
- "src/spend-control.ts"() {
225512
- "use strict";
225513
- init_fs_read();
225514
- WALLET_DIR3 = path5.join(homedir12(), ".openclaw", "blockrun");
225515
- HOUR_MS = 60 * 60 * 1e3;
225516
- DAY_MS = 24 * HOUR_MS;
225517
- FileSpendControlStorage = class {
225518
- spendingFile;
225519
- constructor() {
225520
- this.spendingFile = path5.join(WALLET_DIR3, "spending.json");
225521
- }
225522
- load() {
225523
- try {
225524
- if (fs3.existsSync(this.spendingFile)) {
225525
- const data = JSON.parse(readTextFileSync(this.spendingFile));
225526
- const rawLimits = data.limits ?? {};
225527
- const rawHistory = data.history ?? [];
225528
- const limits = {};
225529
- for (const key2 of ["perRequest", "hourly", "daily", "session"]) {
225530
- const val = rawLimits[key2];
225531
- if (typeof val === "number" && val > 0 && Number.isFinite(val)) {
225532
- limits[key2] = val;
225533
- }
225534
- }
225535
- const history = [];
225536
- if (Array.isArray(rawHistory)) {
225537
- for (const r2 of rawHistory) {
225538
- if (typeof r2?.timestamp === "number" && typeof r2?.amount === "number" && Number.isFinite(r2.timestamp) && Number.isFinite(r2.amount) && r2.amount >= 0) {
225539
- history.push({
225540
- timestamp: r2.timestamp,
225541
- amount: r2.amount,
225542
- model: typeof r2.model === "string" ? r2.model : void 0,
225543
- action: typeof r2.action === "string" ? r2.action : void 0
225544
- });
225545
- }
225546
- }
225547
- }
225548
- return { limits, history };
225549
- }
225550
- } catch (err) {
225551
- console.error(`[ClawRouter] Failed to load spending data, starting fresh: ${err}`);
225552
- }
225553
- return null;
225554
- }
225555
- save(data) {
225556
- try {
225557
- if (!fs3.existsSync(WALLET_DIR3)) {
225558
- fs3.mkdirSync(WALLET_DIR3, { recursive: true, mode: 448 });
225559
- }
225560
- fs3.writeFileSync(this.spendingFile, JSON.stringify(data, null, 2), {
225561
- mode: 384
225562
- });
225563
- } catch (err) {
225564
- console.error(`[ClawRouter] Failed to save spending data: ${err}`);
225565
- }
225566
- }
225567
- };
225568
- InMemorySpendControlStorage = class {
225569
- data = null;
225570
- load() {
225571
- return this.data ? {
225572
- limits: { ...this.data.limits },
225573
- history: this.data.history.map((r2) => ({ ...r2 }))
225574
- } : null;
225575
- }
225576
- save(data) {
225577
- this.data = {
225578
- limits: { ...data.limits },
225579
- history: data.history.map((r2) => ({ ...r2 }))
225580
- };
225581
- }
225582
- };
225583
- SpendControl = class {
225584
- limits = {};
225585
- history = [];
225586
- sessionSpent = 0;
225587
- sessionCalls = 0;
225588
- storage;
225589
- now;
225590
- constructor(options) {
225591
- this.storage = options?.storage ?? new FileSpendControlStorage();
225592
- this.now = options?.now ?? (() => Date.now());
225593
- this.load();
225594
- }
225595
- setLimit(window2, amount) {
225596
- if (!Number.isFinite(amount) || amount <= 0) {
225597
- throw new Error("Limit must be a finite positive number");
225598
- }
225599
- this.limits[window2] = amount;
225600
- this.save();
225601
- }
225602
- clearLimit(window2) {
225603
- delete this.limits[window2];
225604
- this.save();
225605
- }
225606
- getLimits() {
225607
- return { ...this.limits };
225608
- }
225609
- check(estimatedCost2) {
225610
- const now2 = this.now();
225611
- if (this.limits.perRequest !== void 0) {
225612
- if (estimatedCost2 > this.limits.perRequest) {
225613
- return {
225614
- allowed: false,
225615
- blockedBy: "perRequest",
225616
- remaining: this.limits.perRequest,
225617
- reason: `Per-request limit exceeded: $${estimatedCost2.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
225618
- };
225619
- }
225620
- }
225621
- if (this.limits.hourly !== void 0) {
225622
- const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
225623
- const remaining = this.limits.hourly - hourlySpent;
225624
- if (estimatedCost2 > remaining) {
225625
- const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - HOUR_MS);
225626
- const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now2) / 1e3) : 0;
225627
- return {
225628
- allowed: false,
225629
- blockedBy: "hourly",
225630
- remaining,
225631
- reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost2).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
225632
- resetIn
225633
- };
225634
- }
225635
- }
225636
- if (this.limits.daily !== void 0) {
225637
- const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
225638
- const remaining = this.limits.daily - dailySpent;
225639
- if (estimatedCost2 > remaining) {
225640
- const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - DAY_MS);
225641
- const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + DAY_MS - now2) / 1e3) : 0;
225642
- return {
225643
- allowed: false,
225644
- blockedBy: "daily",
225645
- remaining,
225646
- reason: `Daily limit exceeded: $${(dailySpent + estimatedCost2).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
225647
- resetIn
225648
- };
225649
- }
225650
- }
225651
- if (this.limits.session !== void 0) {
225652
- const remaining = this.limits.session - this.sessionSpent;
225653
- if (estimatedCost2 > remaining) {
225654
- return {
225655
- allowed: false,
225656
- blockedBy: "session",
225657
- remaining,
225658
- reason: `Session limit exceeded: $${(this.sessionSpent + estimatedCost2).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
225659
- };
225660
- }
225661
- }
225662
- return { allowed: true };
225663
- }
225664
- record(amount, metadata) {
225665
- if (!Number.isFinite(amount) || amount < 0) {
225666
- throw new Error("Record amount must be a non-negative finite number");
225667
- }
225668
- const record = {
225669
- timestamp: this.now(),
225670
- amount,
225671
- model: metadata?.model,
225672
- action: metadata?.action
225673
- };
225674
- this.history.push(record);
225675
- this.sessionSpent += amount;
225676
- this.sessionCalls += 1;
225677
- this.cleanup();
225678
- this.save();
225679
- }
225680
- getSpendingInWindow(from15, to) {
225681
- return this.history.filter((r2) => r2.timestamp >= from15 && r2.timestamp <= to).reduce((sum, r2) => sum + r2.amount, 0);
225682
- }
225683
- getSpending(window2) {
225684
- const now2 = this.now();
225685
- switch (window2) {
225686
- case "hourly":
225687
- return this.getSpendingInWindow(now2 - HOUR_MS, now2);
225688
- case "daily":
225689
- return this.getSpendingInWindow(now2 - DAY_MS, now2);
225690
- case "session":
225691
- return this.sessionSpent;
225692
- }
225693
- }
225694
- getRemaining(window2) {
225695
- const limit = this.limits[window2];
225696
- if (limit === void 0) return null;
225697
- return Math.max(0, limit - this.getSpending(window2));
225698
- }
225699
- getStatus() {
225700
- const now2 = this.now();
225701
- const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
225702
- const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
225703
- return {
225704
- limits: { ...this.limits },
225705
- spending: {
225706
- hourly: hourlySpent,
225707
- daily: dailySpent,
225708
- session: this.sessionSpent
225709
- },
225710
- remaining: {
225711
- hourly: this.limits.hourly !== void 0 ? this.limits.hourly - hourlySpent : null,
225712
- daily: this.limits.daily !== void 0 ? this.limits.daily - dailySpent : null,
225713
- session: this.limits.session !== void 0 ? this.limits.session - this.sessionSpent : null
225714
- },
225715
- calls: this.sessionCalls
225716
- };
225717
- }
225718
- getHistory(limit) {
225719
- const records = [...this.history].reverse();
225720
- return limit ? records.slice(0, limit) : records;
225721
- }
225722
- resetSession() {
225723
- this.sessionSpent = 0;
225724
- this.sessionCalls = 0;
225725
- }
225726
- cleanup() {
225727
- const cutoff = this.now() - DAY_MS;
225728
- this.history = this.history.filter((r2) => r2.timestamp >= cutoff);
225729
- }
225730
- save() {
225731
- this.storage.save({
225732
- limits: { ...this.limits },
225733
- history: [...this.history]
225734
- });
225735
- }
225736
- load() {
225737
- const data = this.storage.load();
225738
- if (data) {
225739
- this.limits = data.limits;
225740
- this.history = data.history;
225741
- this.cleanup();
225742
- }
225743
- }
225744
- };
225745
- }
225746
- });
225747
-
225748
226077
  // src/retry.ts
225749
226078
  function sleep3(ms) {
225750
226079
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -225814,7 +226143,7 @@ import {
225814
226143
  readdirSync,
225815
226144
  mkdirSync as mkdirSync3,
225816
226145
  copyFileSync,
225817
- renameSync
226146
+ renameSync as renameSync2
225818
226147
  } from "fs";
225819
226148
  import { readFile as readFileAsync } from "fs/promises";
225820
226149
  import { homedir as homedir13 } from "os";
@@ -226092,7 +226421,7 @@ function injectModelsConfig(logger48, options = {}) {
226092
226421
  try {
226093
226422
  const tmpPath = `${configPath}.tmp.${process.pid}`;
226094
226423
  writeFileSync3(tmpPath, JSON.stringify(config, null, 2));
226095
- renameSync(tmpPath, configPath);
226424
+ renameSync2(tmpPath, configPath);
226096
226425
  logger48.info("Smart routing enabled (blockrun/auto)");
226097
226426
  } catch (err) {
226098
226427
  logger48.info(`Failed to write config: ${err instanceof Error ? err.message : String(err)}`);
@@ -226128,7 +226457,7 @@ function syncAgentModelCache(logger48, options = {}) {
226128
226457
  entry.models = VISIBLE_OPENCLAW_MODELS;
226129
226458
  const tmpPath = `${cachePath}.tmp.${process.pid}`;
226130
226459
  writeFileSync3(tmpPath, JSON.stringify(cache2, null, 2));
226131
- renameSync(tmpPath, cachePath);
226460
+ renameSync2(tmpPath, cachePath);
226132
226461
  logger48.info(
226133
226462
  `Repaired ${agent} model cache: ${staleCount} \u2192 ${expectedIds.length} BlockRun models`
226134
226463
  );
@@ -227491,7 +227820,7 @@ ${errText}`
227491
227820
  }
227492
227821
  const tmpPath = `${configPath}.tmp.${process.pid}`;
227493
227822
  writeFileSync3(tmpPath, JSON.stringify(config, null, 2));
227494
- renameSync(tmpPath, configPath);
227823
+ renameSync2(tmpPath, configPath);
227495
227824
  api.logger.info("ClawRouter config cleaned up");
227496
227825
  }
227497
227826
  } catch (err) {
@@ -227527,6 +227856,8 @@ export {
227527
227856
  BALANCE_THRESHOLDS,
227528
227857
  BLOCKRUN_MODELS,
227529
227858
  BalanceMonitor,
227859
+ CAIP2_BASE,
227860
+ CAIP2_SOLANA_MAINNET,
227530
227861
  DEFAULT_RETRY_CONFIG,
227531
227862
  DEFAULT_ROUTING_CONFIG,
227532
227863
  DEFAULT_SESSION_CONFIG,
@@ -227535,6 +227866,7 @@ export {
227535
227866
  InMemorySpendControlStorage,
227536
227867
  InsufficientFundsError2 as InsufficientFundsError,
227537
227868
  MODEL_ALIASES,
227869
+ MalformedSpendPolicyError,
227538
227870
  OPENCLAW_MODELS,
227539
227871
  PARTNER_SERVICES,
227540
227872
  RequestDeduplicator,
@@ -227543,6 +227875,7 @@ export {
227543
227875
  SessionStore,
227544
227876
  SolanaBalanceMonitor,
227545
227877
  SpendControl,
227878
+ SpendPolicyError,
227546
227879
  VISIBLE_OPENCLAW_MODELS,
227547
227880
  blockrunProvider,
227548
227881
  buildImageGenerationProvider,
@@ -227582,6 +227915,7 @@ export {
227582
227915
  loadPaymentChain,
227583
227916
  logUsage,
227584
227917
  parseCallArgs,
227918
+ registerSpendPolicyHook,
227585
227919
  resolveModelAlias,
227586
227920
  resolvePaymentChain,
227587
227921
  route,