opencrowd 0.7.0 → 0.8.0

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/README.md CHANGED
@@ -84,6 +84,18 @@ There is one wallet: AgentCash's. OpenCrowd shows public addresses,
84
84
  balances, and funding links (`/wallet`, `/fund`) and never manages, copies,
85
85
  or exports keys. See [SECURITY.md](SECURITY.md) for the enforcement model.
86
86
 
87
+ Paid services settle in USDC on the network you prefer when they offer it:
88
+ x402 on Base (the default) or Solana, MPP on Tempo, and x402 on Monad when
89
+ you choose it. Solana uses AgentCash's separate Solana address
90
+ (`~/.agentcash/solana-wallet.json`); `opencrowd wallet accounts` lists every
91
+ network's address and balance. When a service does not offer your preferred
92
+ network, the first of Base, Solana and Tempo whose balance covers the price is
93
+ used.
94
+
95
+ ```sh
96
+ opencrowd config set payment-network solana # or --payment-network solana per run
97
+ ```
98
+
87
99
  ## Spending limits
88
100
 
89
101
  By default, each model or paid tool call can spend up to **$1** automatically,
@@ -137,6 +149,7 @@ opencrowd run --budget 1.00 "Find a service and summarize options"
137
149
  opencrowd run --session <session-id> "Follow up on the previous result"
138
150
  opencrowd config show
139
151
  opencrowd wallet balance
152
+ opencrowd wallet accounts
140
153
  opencrowd doctor
141
154
  opencrowd evals gaia --tier smoke --harness opencrowd,claude,codex
142
155
  opencrowd evals suite --set all --tag baseline --model openai/gpt-5.6-luna --subagent-model off
@@ -50,7 +50,7 @@ var __toESM = (mod4, isNodeMode, target) => (target = mod4 != null ? __create(__
50
50
 
51
51
  // ../../packages/core/dist/agentcash.js
52
52
  import { readFile } from "node:fs/promises";
53
- import { join } from "node:path";
53
+ import { dirname, join } from "node:path";
54
54
  import { homedir } from "node:os";
55
55
  function agentCashWalletPath() {
56
56
  return process.env.AGENTCASH_WALLET_PATH ?? join(homedir(), ".agentcash", "wallet.json");
@@ -65,6 +65,14 @@ async function readAgentCashWallet() {
65
65
  return void 0;
66
66
  }
67
67
  }
68
+ async function readAgentCashSolanaAddress() {
69
+ try {
70
+ const parsed = JSON.parse(await readFile(join(dirname(agentCashWalletPath()), "solana-wallet.json"), "utf8"));
71
+ return typeof parsed.address === "string" && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(parsed.address) ? parsed.address : void 0;
72
+ } catch {
73
+ return void 0;
74
+ }
75
+ }
68
76
  async function requireAgentCashWallet() {
69
77
  const wallet = await readAgentCashWallet();
70
78
  if (!wallet) {
@@ -80,9 +88,9 @@ var init_agentcash = __esm({
80
88
 
81
89
  // ../../packages/core/dist/ledger.js
82
90
  import { appendFile, mkdir, readFile as readFile2, writeFile } from "node:fs/promises";
83
- import { dirname } from "node:path";
91
+ import { dirname as dirname2 } from "node:path";
84
92
  async function ensureLedger(path3) {
85
- await mkdir(dirname(path3), { recursive: true });
93
+ await mkdir(dirname2(path3), { recursive: true });
86
94
  try {
87
95
  await readFile2(path3, "utf8");
88
96
  } catch (error53) {
@@ -182,7 +190,7 @@ var init_ledger = __esm({
182
190
  // ../../packages/core/dist/paths.js
183
191
  import { lstat, mkdir as mkdir2, open, rename, rm } from "node:fs/promises";
184
192
  import { homedir as homedir2 } from "node:os";
185
- import { dirname as dirname2, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
193
+ import { dirname as dirname3, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
186
194
  import { randomUUID } from "node:crypto";
187
195
  function resolveAgentPaths(options = {}) {
188
196
  if (options.agentHome) {
@@ -218,7 +226,7 @@ async function containedPath(root, requested) {
218
226
  if (error53.code !== "ENOENT")
219
227
  throw error53;
220
228
  }
221
- const parent = dirname2(current);
229
+ const parent = dirname3(current);
222
230
  if (parent === current)
223
231
  break;
224
232
  current = parent;
@@ -226,7 +234,7 @@ async function containedPath(root, requested) {
226
234
  return target;
227
235
  }
228
236
  async function atomicWrite(path3, content) {
229
- await mkdir2(dirname2(path3), { recursive: true });
237
+ await mkdir2(dirname3(path3), { recursive: true });
230
238
  const temp = `${path3}.${randomUUID()}.tmp`;
231
239
  const handle = await open(temp, "wx", 384);
232
240
  try {
@@ -237,7 +245,7 @@ async function atomicWrite(path3, content) {
237
245
  }
238
246
  try {
239
247
  await rename(temp, path3);
240
- const dir = await open(dirname2(path3), "r");
248
+ const dir = await open(dirname3(path3), "r");
241
249
  try {
242
250
  await dir.sync();
243
251
  } finally {
@@ -255,10 +263,10 @@ var init_paths = __esm({
255
263
 
256
264
  // ../../packages/core/dist/artifacts.js
257
265
  import { mkdir as mkdir3, readFile as readFile3 } from "node:fs/promises";
258
- import { dirname as dirname3, join as join3, relative as relative2 } from "node:path";
266
+ import { dirname as dirname4, join as join3, relative as relative2 } from "node:path";
259
267
  async function saveArtifact(state, path3, content, metadata) {
260
268
  const target = await safeArtifactPath(state, path3);
261
- await mkdir3(dirname3(target), { recursive: true });
269
+ await mkdir3(dirname4(target), { recursive: true });
262
270
  await atomicWrite(target, content);
263
271
  const rel = relative2(state.sessionDir, target);
264
272
  await appendLedgerEntry(state.ledgerPath, {
@@ -16115,12 +16123,49 @@ var init_spending = __esm({
16115
16123
  });
16116
16124
 
16117
16125
  // ../../packages/protocol/dist/financial-state.js
16118
- var usdc, FinancialStateSchema;
16126
+ function atomicUsdc(value) {
16127
+ const amount = BigInt(value);
16128
+ return `${amount / 1000000n}.${(amount % 1000000n).toString().padStart(6, "0")}`;
16129
+ }
16130
+ function parseNetworkBalances(raw) {
16131
+ if (!Array.isArray(raw))
16132
+ return void 0;
16133
+ const rows = raw.flatMap((entry) => {
16134
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
16135
+ return [];
16136
+ const row = entry;
16137
+ const balance = decimal(row.balance_usdc) ?? atomic(row.balance_atomic ?? row.balanceAtomic);
16138
+ const reserved = decimal(row.reserved_usdc) ?? atomic(row.reserved_atomic ?? row.reservedAtomic);
16139
+ const available = decimal(row.available_usdc) ?? atomic(row.available_atomic ?? row.availableAtomic);
16140
+ const status = row.balance_status ?? row.status;
16141
+ const parsed = NetworkBalanceSchema.safeParse({
16142
+ network: row.network,
16143
+ ...typeof row.caip2 === "string" ? { caip2: row.caip2 } : {},
16144
+ ...typeof row.address === "string" || row.address === null ? { address: row.address } : {},
16145
+ balance_status: status === "available" || status === "unavailable" || status === "no_address" ? status : balance ? "available" : "unavailable",
16146
+ balance_usdc: balance ?? null,
16147
+ ...reserved ? { reserved_usdc: reserved } : {},
16148
+ ...available ? { available_usdc: available } : {}
16149
+ });
16150
+ return parsed.success ? [parsed.data] : [];
16151
+ });
16152
+ return rows.length ? rows : void 0;
16153
+ }
16154
+ var usdc, NetworkBalanceSchema, FinancialStateSchema, atomic, decimal;
16119
16155
  var init_financial_state = __esm({
16120
16156
  "../../packages/protocol/dist/financial-state.js"() {
16121
16157
  "use strict";
16122
16158
  init_zod();
16123
16159
  usdc = external_exports.string().regex(/^\d+\.\d{6}$/);
16160
+ NetworkBalanceSchema = external_exports.object({
16161
+ network: external_exports.string().min(1).max(40),
16162
+ caip2: external_exports.string().max(100).optional(),
16163
+ address: external_exports.string().max(100).nullable().optional(),
16164
+ balance_status: external_exports.enum(["available", "unavailable", "no_address"]),
16165
+ balance_usdc: usdc.nullable(),
16166
+ reserved_usdc: usdc.optional(),
16167
+ available_usdc: usdc.nullable().optional()
16168
+ });
16124
16169
  FinancialStateSchema = external_exports.discriminatedUnion("status", [
16125
16170
  external_exports.object({
16126
16171
  status: external_exports.literal("available"),
@@ -16131,7 +16176,8 @@ var init_financial_state = __esm({
16131
16176
  balance_status: external_exports.enum(["available", "unavailable"]),
16132
16177
  balance_usdc: usdc.nullable(),
16133
16178
  reserved_usdc: usdc,
16134
- available_usdc: usdc.nullable()
16179
+ available_usdc: usdc.nullable(),
16180
+ networks: external_exports.array(NetworkBalanceSchema).max(16).optional()
16135
16181
  }),
16136
16182
  current_run: external_exports.object({
16137
16183
  inference_spent_usdc: usdc,
@@ -16146,6 +16192,8 @@ var init_financial_state = __esm({
16146
16192
  }),
16147
16193
  external_exports.object({ status: external_exports.literal("unavailable"), reason: external_exports.string() })
16148
16194
  ]);
16195
+ atomic = (value) => typeof value === "string" && /^\d+$/.test(value) ? atomicUsdc(value) : typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? atomicUsdc(BigInt(value)) : void 0;
16196
+ decimal = (value) => typeof value === "string" && /^\d+\.\d{6}$/.test(value) ? value : void 0;
16149
16197
  }
16150
16198
  });
16151
16199
 
@@ -16316,12 +16364,12 @@ async function reserveBudget(state, amountCents, action) {
16316
16364
  assertCents(amountCents, "reservation");
16317
16365
  if (state.query) {
16318
16366
  const committed = state.spentCents - state.query.startSpentCents + state.reservedCents;
16319
- const atomic = (cents) => String(Math.round(cents * 1e4));
16367
+ const atomic2 = (cents) => String(Math.round(cents * 1e4));
16320
16368
  const check3 = spendingDecision({
16321
- amount: atomic(amountCents),
16322
- perCall: atomic(state.perCallCents ?? 100),
16323
- queryLimit: atomic(state.query.limitCents),
16324
- queryCommitted: atomic(committed)
16369
+ amount: atomic2(amountCents),
16370
+ perCall: atomic2(state.perCallCents ?? 100),
16371
+ queryLimit: atomic2(state.query.limitCents),
16372
+ queryCommitted: atomic2(committed)
16325
16373
  });
16326
16374
  const id = createHash("sha256").update(JSON.stringify([state.query.id, action?.identity ?? "call", amountCents])).digest("hex");
16327
16375
  const approved = state.query.approved?.[id] !== void 0 && state.query.approved[id] >= amountCents;
@@ -16412,7 +16460,7 @@ var init_budget = __esm({
16412
16460
 
16413
16461
  // ../../packages/core/dist/config.js
16414
16462
  import { mkdir as mkdir5, readFile as readFile5 } from "node:fs/promises";
16415
- import { dirname as dirname4, join as join5 } from "node:path";
16463
+ import { dirname as dirname5, join as join5 } from "node:path";
16416
16464
  function configDir(paths2) {
16417
16465
  return (paths2 ?? resolveAgentPaths()).config;
16418
16466
  }
@@ -16431,7 +16479,7 @@ async function loadConfig(paths2) {
16431
16479
  }
16432
16480
  }
16433
16481
  async function saveConfig(config4, paths2) {
16434
- await mkdir5(dirname4(configPath(paths2)), { recursive: true });
16482
+ await mkdir5(dirname5(configPath(paths2)), { recursive: true });
16435
16483
  await atomicWrite(configPath(paths2), `${JSON.stringify(config4, null, 2)}
16436
16484
  `);
16437
16485
  }
@@ -16447,7 +16495,7 @@ function normalizeConfig(value) {
16447
16495
  const proxyDefaults = providerDefaults(raw["openrouter-x402-proxy"] ?? raw.x402, DEFAULT_CONFIG["openrouter-x402-proxy"]);
16448
16496
  const mcpServers = recordValue(raw.mcpServers);
16449
16497
  const servers = { ...DEFAULT_CONFIG.mcpServers, ...mcpServers };
16450
- if (servers.crowdcode?.command === "npx" && ["0.5", "0.5.2", "0.5.3", "0.6.0"].some((version6) => JSON.stringify(servers.crowdcode.args) === JSON.stringify(["--yes", `crowdcode-mcp@${version6}`]))) {
16498
+ if (servers.crowdcode?.command === "npx" && ["0.5", "0.5.2", "0.5.3", "0.6.0", "0.7.0"].some((version6) => JSON.stringify(servers.crowdcode.args) === JSON.stringify(["--yes", `crowdcode-mcp@${version6}`]))) {
16451
16499
  servers.crowdcode = { ...servers.crowdcode, args: [...DEFAULT_CONFIG.mcpServers.crowdcode.args] };
16452
16500
  }
16453
16501
  return {
@@ -16471,6 +16519,8 @@ function parsePaymentNetwork(value) {
16471
16519
  const normalized = typeof value === "string" ? value.trim().toLowerCase() : void 0;
16472
16520
  if (normalized === "monad" || normalized === "eip155:143")
16473
16521
  return "monad";
16522
+ if (normalized === "solana" || normalized === "solana:5eykt4usfv8p8njdtrepy1vzqkqzkvdp")
16523
+ return "solana";
16474
16524
  if (normalized === "base" || normalized === "eip155:8453")
16475
16525
  return "base";
16476
16526
  return void 0;
@@ -16480,7 +16530,7 @@ function resolvePaymentNetwork(config4) {
16480
16530
  if (env !== void 0 && env.trim() !== "") {
16481
16531
  const parsed = parsePaymentNetwork(env);
16482
16532
  if (!parsed)
16483
- throw new Error("OPENCROWD_PAYMENT_NETWORK must be base or monad");
16533
+ throw new Error(`OPENCROWD_PAYMENT_NETWORK must be ${PAYMENT_NETWORKS.join(", ")}`);
16484
16534
  return parsed;
16485
16535
  }
16486
16536
  return config4?.paymentNetwork ?? DEFAULT_CONFIG.paymentNetwork;
@@ -16506,17 +16556,18 @@ function stringValue(value) {
16506
16556
  function numberValue(value) {
16507
16557
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
16508
16558
  }
16509
- var DEFAULT_CONFIG;
16559
+ var PAYMENT_NETWORKS, DEFAULT_CONFIG;
16510
16560
  var init_config = __esm({
16511
16561
  "../../packages/core/dist/config.js"() {
16512
16562
  "use strict";
16513
16563
  init_dist();
16514
16564
  init_paths();
16565
+ PAYMENT_NETWORKS = ["base", "solana", "monad"];
16515
16566
  DEFAULT_CONFIG = {
16516
16567
  configVersion: 3,
16517
16568
  mcpServers: {
16518
16569
  agentcash: { command: "npx", args: ["--yes", "agentcash@0.17"] },
16519
- crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.7.0"] }
16570
+ crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.8.0"] }
16520
16571
  },
16521
16572
  // GAIA provider benchmark (2026-08-25): same-model BlockRun matched the
16522
16573
  // current route's accuracy and completed the sample 6.7x faster. The
@@ -16544,7 +16595,7 @@ var init_config = __esm({
16544
16595
 
16545
16596
  // ../../packages/core/dist/conversation.js
16546
16597
  import { appendFile as appendFile2, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile2 } from "node:fs/promises";
16547
- import { dirname as dirname5, join as join6 } from "node:path";
16598
+ import { dirname as dirname6, join as join6 } from "node:path";
16548
16599
  function conversationPath(session) {
16549
16600
  return join6(session.sessionDir, CONVERSATION_FILE);
16550
16601
  }
@@ -16557,7 +16608,7 @@ async function appendConversationMessage(session, message) {
16557
16608
  }
16558
16609
  async function appendConversationEntry(session, entry) {
16559
16610
  const path3 = conversationPath(session);
16560
- await mkdir6(dirname5(path3), { recursive: true });
16611
+ await mkdir6(dirname6(path3), { recursive: true });
16561
16612
  await appendFile2(path3, `${JSON.stringify(entry)}
16562
16613
  `, "utf8");
16563
16614
  }
@@ -16600,7 +16651,7 @@ async function clearConversation(session) {
16600
16651
  }
16601
16652
  const archivePath = join6("context", `cleared-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.jsonl`);
16602
16653
  const absoluteArchivePath = join6(session.sessionDir, archivePath);
16603
- await mkdir6(dirname5(absoluteArchivePath), { recursive: true });
16654
+ await mkdir6(dirname6(absoluteArchivePath), { recursive: true });
16604
16655
  await writeFile2(absoluteArchivePath, messages.map((message) => `${JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), message })}
16605
16656
  `).join(""), "utf8");
16606
16657
  await writeFile2(conversationPath(session), `${JSON.stringify({ type: "clear", timestamp: (/* @__PURE__ */ new Date()).toISOString(), archive_path: archivePath })}
@@ -17021,9 +17072,17 @@ async function executeTool(name, args, context) {
17021
17072
  return ok({ content: await readArtifact(context.session, requiredString(args.path, "path")) });
17022
17073
  case "list_files":
17023
17074
  return ok(await listArtifacts(context.session, optionalString(args.prefix, "prefix") ?? ""));
17024
- case "run_shell":
17075
+ case "run_shell": {
17025
17076
  context.onProgress?.({ type: "running_shell", message: "Running gated shell command" });
17026
- return ok(await runShell(context.session, requiredString(args.command, "command"), optionalString(args.cwd, "cwd") ?? context.session.workspaceRoot, shellTimeoutMs(args.timeout_ms), { signal: context.signal }));
17077
+ const result = await runShell(context.session, requiredString(args.command, "command"), optionalString(args.cwd, "cwd") ?? context.session.workspaceRoot, shellTimeoutMs(args.timeout_ms), { signal: context.signal });
17078
+ if (result.timed_out || result.exit_code !== 0)
17079
+ return {
17080
+ ok: false,
17081
+ error: result.timed_out ? "Shell command timed out; inspect partial output before retrying." : result.exit_code === null ? "Shell command was terminated; inspect stderr and resource limits before retrying." : `Shell command exited with code ${result.exit_code}; inspect stderr and partial output before choosing the next approach.`,
17082
+ data: result
17083
+ };
17084
+ return ok(result);
17085
+ }
17027
17086
  case "spawn_subagent":
17028
17087
  case "check_subagents":
17029
17088
  return {
@@ -46189,7 +46248,7 @@ async function getCallsStatus(client, parameters) {
46189
46248
  params: [id]
46190
46249
  });
46191
46250
  }
46192
- const { atomic = false, chainId, receipts, version: version6 = "2.0.0", ...response } = await getStatus(parameters.id);
46251
+ const { atomic: atomic2 = false, chainId, receipts, version: version6 = "2.0.0", ...response } = await getStatus(parameters.id);
46193
46252
  const [status, statusCode] = (() => {
46194
46253
  const statusCode2 = response.status;
46195
46254
  if (statusCode2 >= 100 && statusCode2 < 200)
@@ -46206,7 +46265,7 @@ async function getCallsStatus(client, parameters) {
46206
46265
  })();
46207
46266
  return {
46208
46267
  ...response,
46209
- atomic,
46268
+ atomic: atomic2,
46210
46269
  // @ts-expect-error: for backwards compatibility
46211
46270
  chainId: chainId ? hexToNumber(chainId) : void 0,
46212
46271
  receipts: receipts?.map((receipt) => ({
@@ -56964,23 +57023,123 @@ var init_monad = __esm({
56964
57023
  }
56965
57024
  });
56966
57025
 
57026
+ // ../../packages/economy/dist/offers.js
57027
+ function localRails(preferred = "base") {
57028
+ return preferred === "monad" ? ["x402-base", "x402-solana", "mppx", "x402-monad"] : ["x402-base", "x402-solana", "mppx"];
57029
+ }
57030
+ function describeRails(rails) {
57031
+ const labels = rails.filter((rail) => rail !== "unsupported").map((rail) => NETWORK_LABEL[RAIL_NETWORK[rail]]);
57032
+ return labels.length > 1 ? `${labels.slice(0, -1).join(", ")} or ${labels.at(-1)}` : labels[0] ?? "nothing";
57033
+ }
57034
+ function networkLabel(offer) {
57035
+ if (!offer.network_name)
57036
+ return `${offer.protocol} on ${offer.network || "an unknown network"}`;
57037
+ return offer.rail === "unsupported" ? `${offer.protocol} on ${offer.network_name} (unsupported token or scheme)` : NETWORK_LABEL[offer.network_name];
57038
+ }
57039
+ function networkName(value) {
57040
+ const network = typeof value === "string" ? value.trim().toLowerCase() : "";
57041
+ if (network === BASE_NETWORK || network === "base")
57042
+ return "base";
57043
+ if (network === SOLANA_NETWORK.toLowerCase() || network === "solana" || network === "solana:mainnet")
57044
+ return "solana";
57045
+ if (network === TEMPO_NETWORK || network === "tempo" || network === "tempo:4217" || network === "tempo:mainnet")
57046
+ return "tempo";
57047
+ if (network === MONAD_NETWORK || network === "monad")
57048
+ return "monad";
57049
+ return void 0;
57050
+ }
57051
+ function railForNetwork(value) {
57052
+ const name = networkName(value);
57053
+ return name ? NETWORK_RAIL[name] : void 0;
57054
+ }
57055
+ function classifyOffer(option) {
57056
+ const protocol = option?.protocol === "mpp" ? "mpp" : "x402";
57057
+ const network = String(option?.network ?? "");
57058
+ const name = networkName(network);
57059
+ const asset = String(option?.asset ?? "");
57060
+ const atomic2 = Number(option?.amount ?? option?.maxAmountRequired);
57061
+ const decimals = typeof option?.decimals === "number" ? option.decimals : 6;
57062
+ const price_usd = Number.isFinite(atomic2) && atomic2 >= 0 ? atomic2 / 10 ** decimals : void 0;
57063
+ const scheme = option?.scheme;
57064
+ let rail = "unsupported";
57065
+ if (protocol === "x402" && name === "base" && asset.toLowerCase() === BASE_USDC)
57066
+ rail = "x402-base";
57067
+ else if (protocol === "x402" && name === "solana" && asset === SOLANA_USDC && (scheme === void 0 || scheme === "exact"))
57068
+ rail = "x402-solana";
57069
+ else if (protocol === "x402" && name === "monad" && asset.toLowerCase() === MONAD_USDC.toLowerCase() && (scheme === void 0 || scheme === "exact"))
57070
+ rail = "x402-monad";
57071
+ else if (protocol === "mpp" && name === "tempo" && asset.toLowerCase() === TEMPO_USDC && (option.paymentMethod === void 0 || option.paymentMethod === "tempo") && (option.intent === void 0 || option.intent === "charge"))
57072
+ rail = "mppx";
57073
+ return {
57074
+ network,
57075
+ ...name ? { network_name: name } : {},
57076
+ protocol,
57077
+ rail,
57078
+ ...price_usd !== void 0 ? { price_usd } : {},
57079
+ ...typeof option?.payTo === "string" ? { pay_to: option.payTo } : {}
57080
+ };
57081
+ }
57082
+ function selectOffer(offers, selection) {
57083
+ const preferred = selection.preferred ?? "base";
57084
+ const payable = offers.filter((offer) => offer.rail !== "unsupported" && selection.rails.includes(offer.rail));
57085
+ const cheapest = (name) => payable.filter((offer) => offer.network_name === name).sort((a, b) => (a.price_usd ?? Infinity) - (b.price_usd ?? Infinity))[0];
57086
+ const order = [preferred, ...FALLBACK_ORDER.filter((name) => name !== preferred)];
57087
+ const first = cheapest(preferred);
57088
+ if (first)
57089
+ return first;
57090
+ const candidates = order.map(cheapest).filter((offer) => offer !== void 0);
57091
+ const balances = selection.balances;
57092
+ return balances && candidates.find((offer) => (balances[offer.network_name] ?? 0) >= (offer.price_usd ?? 0)) || candidates[0];
57093
+ }
57094
+ function payableNetworks(offers, rails) {
57095
+ return [...new Set(offers.filter((offer) => offer.rail !== "unsupported" && rails.includes(offer.rail)).map((offer) => offer.network_name))];
57096
+ }
57097
+ var BASE_NETWORK, BASE_USDC, SOLANA_NETWORK, SOLANA_USDC, TEMPO_NETWORK, TEMPO_USDC, RAIL_NETWORK, NETWORK_CAIP2, NETWORK_RAIL, NETWORK_LABEL, FALLBACK_ORDER, HOSTED_RAILS;
57098
+ var init_offers = __esm({
57099
+ "../../packages/economy/dist/offers.js"() {
57100
+ "use strict";
57101
+ init_monad();
57102
+ BASE_NETWORK = "eip155:8453";
57103
+ BASE_USDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
57104
+ SOLANA_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
57105
+ SOLANA_USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
57106
+ TEMPO_NETWORK = "eip155:4217";
57107
+ TEMPO_USDC = "0x20c000000000000000000000b9537d11c60e8b50";
57108
+ RAIL_NETWORK = {
57109
+ "x402-base": "base",
57110
+ "x402-solana": "solana",
57111
+ "x402-monad": "monad",
57112
+ mppx: "tempo"
57113
+ };
57114
+ NETWORK_CAIP2 = { base: BASE_NETWORK, solana: SOLANA_NETWORK, tempo: TEMPO_NETWORK, monad: MONAD_NETWORK };
57115
+ NETWORK_RAIL = { base: "x402-base", solana: "x402-solana", monad: "x402-monad", tempo: "mppx" };
57116
+ NETWORK_LABEL = {
57117
+ base: "x402 USDC on Base",
57118
+ solana: "x402 USDC on Solana",
57119
+ tempo: "MPP USDC.e on Tempo",
57120
+ monad: "x402 USDC on Monad"
57121
+ };
57122
+ FALLBACK_ORDER = ["base", "solana", "tempo", "monad"];
57123
+ HOSTED_RAILS = ["x402-base", "x402-solana", "mppx"];
57124
+ }
57125
+ });
57126
+
56967
57127
  // ../../packages/economy/dist/discovery.js
56968
- var BASE_USDC, BASE_NETWORK, isBaseOffer, BaseServiceDiscovery;
57128
+ var BaseServiceDiscovery;
56969
57129
  var init_discovery = __esm({
56970
57130
  "../../packages/economy/dist/discovery.js"() {
56971
57131
  "use strict";
56972
57132
  init_dist3();
56973
- init_monad();
56974
- BASE_USDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
56975
- BASE_NETWORK = "eip155:8453";
56976
- isBaseOffer = (offer) => offer?.protocol === "x402" && [BASE_NETWORK, "base"].includes(offer.network) && String(offer.asset).toLowerCase() === BASE_USDC;
57133
+ init_offers();
56977
57134
  BaseServiceDiscovery = class {
56978
57135
  searchApi;
56979
57136
  options;
56980
57137
  cache = /* @__PURE__ */ new Map();
57138
+ rails;
56981
57139
  constructor(searchApi, options = {}) {
56982
57140
  this.searchApi = searchApi;
56983
57141
  this.options = options;
57142
+ this.rails = options.rails ?? localRails(options.paymentNetwork);
56984
57143
  }
56985
57144
  async inspect(input2) {
56986
57145
  const key = `${input2.method ?? "POST"} ${input2.url}`;
@@ -56998,26 +57157,55 @@ var init_discovery = __esm({
56998
57157
  const advisory = result.advisories.find((a) => a.method === (input2.method ?? "POST").toUpperCase());
56999
57158
  if (!advisory)
57000
57159
  return { ok: false, error: "The endpoint does not advertise this method" };
57001
- const monadOffer = this.options.paymentNetwork === "monad" ? advisory.paymentOptions?.find(isMonadOffer) : void 0;
57002
- const offer = monadOffer ?? advisory.paymentOptions?.find(isBaseOffer);
57160
+ const offers = (advisory.paymentOptions ?? []).map((option) => classifyOffer(option));
57161
+ const offer = await this.select(offers);
57162
+ const payable = offers.filter((candidate) => candidate.rail !== "unsupported" && this.rails.includes(candidate.rail));
57163
+ const ceiling = this.options.negotiated && offer ? Math.max(...payable.map((candidate) => candidate.price_usd ?? 0)) : offer?.price_usd;
57003
57164
  const read = ["siwx", "unprotected"].includes(advisory.authMode ?? "");
57004
57165
  const data = {
57005
57166
  endpoint: input2.url,
57006
57167
  method: advisory.method,
57007
- rail: monadOffer ? "x402-monad" : offer || read ? "x402-base" : "unsupported",
57168
+ rail: offer ? offer.rail : read ? "x402-base" : "unsupported",
57008
57169
  payable: !!offer,
57009
57170
  authMode: advisory.authMode,
57010
- network: monadOffer ? MONAD_NETWORK : offer ? BASE_NETWORK : void 0,
57011
- price_usd: offer ? Number("amount" in offer ? offer.amount : "maxAmountRequired" in offer ? offer.maxAmountRequired : 0) / 1e6 : read ? 0 : void 0,
57171
+ network: offer?.network_name ? NETWORK_CAIP2[offer.network_name] : void 0,
57172
+ price_usd: offer ? ceiling ?? 0 : read ? 0 : void 0,
57173
+ ...offers.length ? { offers: offers.map((candidate) => ({
57174
+ network: candidate.network_name ?? candidate.network,
57175
+ protocol: candidate.protocol,
57176
+ price_usd: candidate.price_usd,
57177
+ payable: payable.includes(candidate)
57178
+ })) } : {},
57012
57179
  input_schema: advisory.inputSchema,
57013
57180
  output_schema: advisory.outputSchema,
57014
57181
  description: advisory.summary,
57015
- note: read ? "Read with read_service; wallet authentication is automatic. Never resubmit a pending generation job." : monadOffer ? "Pays x402 USDC on Monad (eip155:143). Inspect with sample_body for the exact quote." : `Only x402 USDC on Base${this.options.paymentNetwork === "monad" ? " or Monad" : ""} is enabled. Inspect with sample_body for the exact quote.`
57182
+ note: read ? "Read with read_service; wallet authentication is automatic. Never resubmit a pending generation job." : this.note(offers, offer)
57016
57183
  };
57017
57184
  if (input2.body === void 0)
57018
57185
  this.cache.set(key, { until: Date.now() + 6e4, data });
57019
57186
  return { ok: true, data };
57020
57187
  }
57188
+ /** Balances are read only when they can change the choice: the preferred network is absent and several are payable. */
57189
+ async select(offers) {
57190
+ const selection = { preferred: this.options.paymentNetwork, rails: this.rails };
57191
+ const networks = payableNetworks(offers, this.rails);
57192
+ const needsBalances = !this.options.negotiated && this.options.balances && networks.length > 1 && !networks.includes(this.options.paymentNetwork ?? "base");
57193
+ const balances = needsBalances ? await this.options.balances().catch(() => void 0) : void 0;
57194
+ return selectOffer(offers, { ...selection, balances });
57195
+ }
57196
+ note(offers, offer) {
57197
+ const quote = "Inspect with sample_body for the exact quote.";
57198
+ if (!offer) {
57199
+ const offered = [...new Set(offers.map(networkLabel))];
57200
+ return `${offered.length ? `This service offers ${offered.join(", ")}` : "This service advertises no recognised payment option"}; payable here: ${describeRails(this.rails)}. ${quote}`;
57201
+ }
57202
+ if (this.options.negotiated) {
57203
+ const networks = payableNetworks(offers, this.rails).map((name) => networkLabel({ ...offer, network_name: name, rail: "x402-base" }));
57204
+ return `The hosted gateway pays the cheapest of ${networks.join(", ")} that your balance on that network covers; price_usd is the ceiling across them. ${quote}`;
57205
+ }
57206
+ const preferred = this.options.paymentNetwork ?? "base";
57207
+ return `Pays ${networkLabel(offer)}${offer.network_name === preferred ? "" : ` (${preferred} is not offered)`}. ${quote}`;
57208
+ }
57021
57209
  async verified(candidates, limit) {
57022
57210
  const services = [];
57023
57211
  for (let i = 0; i < candidates.length && services.length < limit; i += 4) {
@@ -57031,7 +57219,7 @@ var init_discovery = __esm({
57031
57219
  method: c.method ?? "POST",
57032
57220
  name: c.summary ?? c.name,
57033
57221
  price_usd: schema.price_usd,
57034
- payment_provider: "x402",
57222
+ payment_provider: schema.rail === "mppx" ? "mppx" : "x402",
57035
57223
  network: schema.network ?? BASE_NETWORK,
57036
57224
  payable: true
57037
57225
  } : void 0;
@@ -57053,14 +57241,14 @@ var init_discovery = __esm({
57053
57241
  const candidates = Array.isArray(body?.results) ? body.results : Array.isArray(body?.services) ? body.services : [];
57054
57242
  return { ok: true, data: {
57055
57243
  services: await this.verified(candidates, limit),
57056
- note: `AgentCash discovery, verified x402 USDC on ${this.options.paymentNetwork === "monad" ? "Monad or Base" : "Base"}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.`
57244
+ note: `AgentCash discovery, verified ${describeRails(this.rails)}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.`
57057
57245
  } };
57058
57246
  }
57059
57247
  async discoverEndpoints(origin) {
57060
57248
  const result = await discoverOriginSchema({ target: origin, signal: AbortSignal.timeout(1e4) });
57061
57249
  if (!result.found)
57062
57250
  return { ok: false, error: result.message ?? "Provider discovery failed" };
57063
- const candidates = result.endpoints.filter((e6) => e6.protocols?.includes("x402")).map((e6) => ({ ...e6, origin: result.origin }));
57251
+ const candidates = result.endpoints.filter((e6) => e6.protocols?.some((protocol) => protocol === "x402" || protocol === "mpp")).map((e6) => ({ ...e6, origin: result.origin }));
57064
57252
  return { ok: true, data: {
57065
57253
  services: await this.verified(candidates, 50),
57066
57254
  guidance: result.guidance,
@@ -57154,15 +57342,32 @@ function parsePaymentEvidence(record3, requestedRail) {
57154
57342
  }
57155
57343
  const network = stringValue2(payment?.network ?? record3.network ?? receipt?.network)?.toLowerCase();
57156
57344
  const protocol = stringValue2(payment?.protocol ?? record3.protocol ?? record3.paymentProtocol)?.toLowerCase();
57157
- const rail = network === "tempo" || protocol === "mpp" || protocol === "mppx" ? "mppx" : network === "base" || network === "eip155:8453" || protocol === "x402" ? "x402-base" : network === void 0 && protocol === void 0 ? requestedRail : "unsupported";
57345
+ const named = networkName(network);
57346
+ const rail = named === "tempo" || protocol === "mpp" || protocol === "mppx" ? "mppx" : named === "solana" ? "x402-solana" : named === "base" || network === void 0 && protocol === "x402" ? requestedRail === "x402-solana" && named === void 0 ? "x402-solana" : "x402-base" : network === void 0 && protocol === void 0 ? requestedRail : "unsupported";
57347
+ if (rail === "x402-solana" && !reference.startsWith("x402:"))
57348
+ reference = `x402:solana:${reference}`;
57158
57349
  return {
57159
57350
  paidUsd,
57160
57351
  rail,
57161
57352
  reference,
57353
+ payer: stringValue2(payment?.payer ?? receipt?.payer),
57162
57354
  proof,
57163
57355
  payTo: stringValue2(payment?.payTo ?? payment?.pay_to ?? payment?.recipient ?? receipt?.payTo ?? receipt?.pay_to ?? receipt?.recipient ?? receipt?.payee)
57164
57356
  };
57165
57357
  }
57358
+ function parseWalletAccounts(data) {
57359
+ const record3 = objectValue3(data);
57360
+ const rows = Array.isArray(data) ? data : Array.isArray(record3?.accounts) ? record3.accounts : [];
57361
+ return rows.map(objectValue3).filter((row) => row !== void 0 && stringValue2(row.network) !== void 0).map((row) => {
57362
+ const usdc2 = numberValue2(row.balance ?? row.usdc ?? row.balanceUsd);
57363
+ return {
57364
+ network: stringValue2(row.network),
57365
+ ...stringValue2(row.address) ? { address: stringValue2(row.address) } : {},
57366
+ ...usdc2 !== void 0 ? { usdc: usdc2 } : {},
57367
+ ...stringValue2(row.depositLink) ? { depositLink: stringValue2(row.depositLink) } : {}
57368
+ };
57369
+ });
57370
+ }
57166
57371
  function normalizedHeaders(value) {
57167
57372
  const headers = objectValue3(value) ?? {};
57168
57373
  return Object.fromEntries(Object.entries(headers).map(([key, child]) => [key.toLowerCase(), child]));
@@ -57207,34 +57412,71 @@ function moneyValue(value) {
57207
57412
  const cleaned = value.replace(/[$,\s]|usd(c?)/gi, "");
57208
57413
  return cleaned === "" ? void 0 : numberValue2(cleaned);
57209
57414
  }
57210
- var McpAgentCashAdapter;
57415
+ var ACCOUNTS_TTL_MS, McpAgentCashAdapter;
57211
57416
  var init_agentcash2 = __esm({
57212
57417
  "../../packages/economy/dist/agentcash.js"() {
57213
57418
  "use strict";
57214
57419
  init_discovery();
57215
57420
  init_dist2();
57216
57421
  init_monad();
57422
+ init_offers();
57423
+ ACCOUNTS_TTL_MS = 3e4;
57217
57424
  McpAgentCashAdapter = class {
57218
57425
  connection;
57219
57426
  options;
57220
57427
  discovery;
57221
57428
  monad;
57429
+ accountsCache;
57222
57430
  constructor(connection, options = {}) {
57223
57431
  this.connection = connection;
57224
57432
  this.options = options;
57225
- this.discovery = new BaseServiceDiscovery((query, options2) => this.connection.call("search", { query, ...options2 }), { paymentNetwork: options.paymentNetwork });
57433
+ this.discovery = new BaseServiceDiscovery((query, options2) => this.connection.call("search", { query, ...options2 }), { paymentNetwork: options.paymentNetwork, balances: () => this.networkBalances() });
57226
57434
  this.monad = options.monad ?? new MonadX402Payer();
57227
57435
  }
57228
57436
  read(url3) {
57229
57437
  return this.connection.call("fetch", { url: url3, method: "GET", maxAmount: 1e-9, paymentNetwork: "base", paymentProtocol: "x402" });
57230
57438
  }
57231
57439
  async getBalance() {
57232
- const [result, monad] = await Promise.all([this.connection.call("get_balance", {}), this.monadBalance()]);
57440
+ const [result, monad, accounts] = await Promise.all([
57441
+ this.connection.call("get_balance", {}),
57442
+ this.monadBalance(),
57443
+ this.accounts(true).catch(() => void 0)
57444
+ ]);
57233
57445
  if (!result.ok)
57234
57446
  return { ok: false, data: result.data, error: result.error };
57235
- const data = result.data && typeof result.data === "object" && !Array.isArray(result.data) ? { ...result.data, monad } : { agentcash: result.data, monad };
57447
+ const data = result.data && typeof result.data === "object" && !Array.isArray(result.data) ? { ...result.data, ...accounts ? { accounts } : {}, monad } : { agentcash: result.data, ...accounts ? { accounts } : {}, monad };
57236
57448
  return { ok: true, data };
57237
57449
  }
57450
+ /** AgentCash's per-network accounts (`list_accounts`), briefly cached for offer selection. */
57451
+ accounts(refresh = false) {
57452
+ if (!refresh && this.accountsCache && this.accountsCache.until > Date.now())
57453
+ return this.accountsCache.accounts;
57454
+ const accounts = this.connection.call("list_accounts", {}).then((result) => {
57455
+ if (!result.ok)
57456
+ throw new Error(result.error ?? "list_accounts failed");
57457
+ return parseWalletAccounts(result.data);
57458
+ });
57459
+ this.accountsCache = { until: Date.now() + ACCOUNTS_TTL_MS, accounts };
57460
+ accounts.catch(() => {
57461
+ this.accountsCache = void 0;
57462
+ });
57463
+ return accounts;
57464
+ }
57465
+ /** Spendable USDC per network, for choosing among a service's offers. */
57466
+ async networkBalances() {
57467
+ const balances = {};
57468
+ for (const account of await this.accounts()) {
57469
+ const name = networkName(account.network);
57470
+ if (name && account.usdc !== void 0)
57471
+ balances[name] = (balances[name] ?? 0) + account.usdc;
57472
+ }
57473
+ if (this.options.paymentNetwork === "monad") {
57474
+ const monad = await this.monadBalance();
57475
+ if (typeof monad.usdc === "number")
57476
+ balances.monad = monad.usdc;
57477
+ }
57478
+ return balances;
57479
+ }
57238
57480
  async monadBalance() {
57239
57481
  const preferred = this.options.paymentNetwork === "monad";
57240
57482
  try {
@@ -57259,7 +57501,7 @@ var init_agentcash2 = __esm({
57259
57501
  async fetch(request2) {
57260
57502
  if (request2.rail === "x402-monad")
57261
57503
  return this.monad.fetch(request2);
57262
- const railParams = request2.rail === "mppx" ? { paymentNetwork: "tempo", paymentProtocol: "mpp" } : { paymentNetwork: "base", paymentProtocol: "x402" };
57504
+ const railParams = request2.rail === "mppx" ? { paymentNetwork: "tempo", paymentProtocol: "mpp" } : request2.rail === "x402-solana" ? { paymentNetwork: "solana", paymentProtocol: "x402" } : { paymentNetwork: "base", paymentProtocol: "x402" };
57263
57505
  const result = await this.connection.call("fetch", {
57264
57506
  url: request2.url,
57265
57507
  method: request2.method,
@@ -57289,7 +57531,7 @@ var init_agentcash2 = __esm({
57289
57531
 
57290
57532
  // ../../packages/economy/dist/approvals.js
57291
57533
  import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile3 } from "node:fs/promises";
57292
- import { dirname as dirname6, join as join9 } from "node:path";
57534
+ import { dirname as dirname7, join as join9 } from "node:path";
57293
57535
  function isApprovalMode(value) {
57294
57536
  return value === "ask" || value === "auto" || value === "off";
57295
57537
  }
@@ -57308,7 +57550,7 @@ async function loadApprovalRules(path3 = approvalRulesPath()) {
57308
57550
  }
57309
57551
  }
57310
57552
  async function saveApprovalRules(rules, path3 = approvalRulesPath()) {
57311
- await mkdir7(dirname6(path3), { recursive: true });
57553
+ await mkdir7(dirname7(path3), { recursive: true });
57312
57554
  await writeFile3(path3, `${JSON.stringify({ services: rules }, null, 2)}
57313
57555
  `, "utf8");
57314
57556
  }
@@ -57421,6 +57663,8 @@ var init_crowdcode = __esm({
57421
57663
  ...review.paymentProvider ? { payment_provider: review.paymentProvider } : {},
57422
57664
  ...review.paymentProof ? { payment_proof: review.paymentProof } : {},
57423
57665
  ...review.paymentTargetRef ? { payment_target_ref: review.paymentTargetRef } : {},
57666
+ ...review.payer ? { payer: review.payer } : {},
57667
+ ...review.payerSignature ? { payer_signature: review.payerSignature } : {},
57424
57668
  ...review.taskContext ? { task_context: review.taskContext } : {}
57425
57669
  });
57426
57670
  const payload = result.data && typeof result.data === "object" ? result.data : {};
@@ -57433,7 +57677,7 @@ var init_crowdcode = __esm({
57433
57677
 
57434
57678
  // ../../packages/economy/dist/crowdcode-preferences.js
57435
57679
  import { mkdir as mkdir8, readFile as readFile8, rename as rename2, writeFile as writeFile4 } from "node:fs/promises";
57436
- import { dirname as dirname7, join as join10 } from "node:path";
57680
+ import { dirname as dirname8, join as join10 } from "node:path";
57437
57681
  import { randomUUID as randomUUID4 } from "node:crypto";
57438
57682
  var CrowdCodePreferences;
57439
57683
  var init_crowdcode_preferences = __esm({
@@ -57464,7 +57708,7 @@ var init_crowdcode_preferences = __esm({
57464
57708
  }
57465
57709
  async write(scope, enabled) {
57466
57710
  const path3 = this.path(scope), temporary = `${path3}.${randomUUID4()}.tmp`;
57467
- await mkdir8(dirname7(path3), { recursive: true });
57711
+ await mkdir8(dirname8(path3), { recursive: true });
57468
57712
  await writeFile4(temporary, JSON.stringify({ enabled }) + "\n", { mode: 384 });
57469
57713
  await rename2(temporary, path3);
57470
57714
  }
@@ -57510,7 +57754,7 @@ var init_media = __esm({
57510
57754
 
57511
57755
  // ../../packages/economy/dist/purchases.js
57512
57756
  import { appendFile as appendFile3, mkdir as mkdir9, readFile as readFile9 } from "node:fs/promises";
57513
- import { dirname as dirname8, join as join11 } from "node:path";
57757
+ import { dirname as dirname9, join as join11 } from "node:path";
57514
57758
  import { randomUUID as randomUUID5 } from "node:crypto";
57515
57759
  function purchasesPath(session) {
57516
57760
  return join11(session.sessionDir, "purchases.jsonl");
@@ -57538,7 +57782,7 @@ async function skipPendingReviews(session) {
57538
57782
  }
57539
57783
  async function appendPurchaseEvent(session, event) {
57540
57784
  const path3 = purchasesPath(session);
57541
- await mkdir9(dirname8(path3), { recursive: true });
57785
+ await mkdir9(dirname9(path3), { recursive: true });
57542
57786
  await appendFile3(path3, `${JSON.stringify(event)}
57543
57787
  `, "utf8");
57544
57788
  }
@@ -57672,13 +57916,14 @@ function numberArg(value) {
57672
57916
  function slugUrl(url3) {
57673
57917
  return url3.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").slice(0, 80) || "service";
57674
57918
  }
57675
- var GATEWAY_TOOL_NAMES, EconomyGateway, GATEWAY_TOOL_DEFINITIONS;
57919
+ var GATEWAY_TOOL_NAMES, VERIFIED_RAILS, EconomyGateway, GATEWAY_TOOL_DEFINITIONS;
57676
57920
  var init_gateway = __esm({
57677
57921
  "../../packages/economy/dist/gateway.js"() {
57678
57922
  "use strict";
57679
57923
  init_crowdcode_preferences();
57680
57924
  init_media();
57681
57925
  init_dist2();
57926
+ init_offers();
57682
57927
  init_approvals();
57683
57928
  init_purchases();
57684
57929
  GATEWAY_TOOL_NAMES = [
@@ -57695,6 +57940,7 @@ var init_gateway = __esm({
57695
57940
  "review_paid_service",
57696
57941
  "bridge_usdc"
57697
57942
  ];
57943
+ VERIFIED_RAILS = ["x402-base", "x402-solana", "x402-monad", "mppx"];
57698
57944
  EconomyGateway = class {
57699
57945
  options;
57700
57946
  /**
@@ -57888,10 +58134,11 @@ var init_gateway = __esm({
57888
58134
  if (!inspection) {
57889
58135
  return { ok: false, error: `inspect_paid_service must run for ${method} ${endpoint} before call_paid_service` };
57890
58136
  }
57891
- if (inspection.rail !== "x402-base" && inspection.rail !== "x402-monad") {
58137
+ const rails = this.options.paymentRails ?? VERIFIED_RAILS;
58138
+ if (!rails.includes(inspection.rail)) {
57892
58139
  return {
57893
58140
  ok: false,
57894
- error: "this endpoint settles on a payment rail OpenCrowd does not support for automatic payment (allowed: x402 USDC on Base or Monad)"
58141
+ error: `this endpoint offers no payment rail this agent can pay automatically (payable: ${describeRails(rails)})`
57895
58142
  };
57896
58143
  }
57897
58144
  const requestedCostCents = intArg(args.max_cost_cents) ?? inspection.priceCeilingCents;
@@ -57955,7 +58202,7 @@ var init_gateway = __esm({
57955
58202
  const artifact = result.ambiguityReason === "transport" ? void 0 : await saveArtifact(session, `service-calls/${Date.now()}-${slugUrl(endpoint)}.json`, JSON.stringify({ status: result.status, body: result.data }, null, 2), { endpoint, method });
57956
58203
  const purchaseId = newPurchaseId();
57957
58204
  const railUsed = result.payment?.rail ?? inspection.rail;
57958
- const supportedRail = railUsed === "x402-base" || railUsed === "x402-monad" || railUsed === "mppx";
58205
+ const supportedRail = VERIFIED_RAILS.includes(railUsed);
57959
58206
  const record3 = {
57960
58207
  purchase_id: purchaseId,
57961
58208
  session_id: session.sessionId,
@@ -58119,6 +58366,8 @@ var init_gateway = __esm({
58119
58366
  paymentProvider: evidence?.reference ? state.record.rail === "mppx" ? "mppx" : "x402" : void 0,
58120
58367
  paymentProof: evidence?.proof,
58121
58368
  paymentTargetRef: evidence?.reference ? evidence.payTo : void 0,
58369
+ // Solana pays from a different address than the EVM reviewer key.
58370
+ ...state.record.rail === "x402-solana" && evidence?.payer ? { payer: evidence.payer } : {},
58122
58371
  taskContext: stringArg(args.task_context)
58123
58372
  });
58124
58373
  if (!result.ok) {
@@ -58528,6 +58777,7 @@ var init_dist4 = __esm({
58528
58777
  init_purchases();
58529
58778
  init_runtime();
58530
58779
  init_discovery();
58780
+ init_offers();
58531
58781
  }
58532
58782
  });
58533
58783
 
@@ -58660,10 +58910,10 @@ var init_context2 = __esm({
58660
58910
 
58661
58911
  // ../../packages/agent-runtime/dist/knowledge.js
58662
58912
  import { access, cp, mkdir as mkdir10, readFile as readFile11, writeFile as writeFile6 } from "node:fs/promises";
58663
- import { dirname as dirname9, join as join14, resolve as resolve4 } from "node:path";
58913
+ import { dirname as dirname10, join as join14, resolve as resolve4 } from "node:path";
58664
58914
  import { fileURLToPath } from "node:url";
58665
58915
  function bundledKnowledgeDir() {
58666
- return resolve4(dirname9(fileURLToPath(import.meta.url)), "..", "knowledge");
58916
+ return resolve4(dirname10(fileURLToPath(import.meta.url)), "..", "knowledge");
58667
58917
  }
58668
58918
  function knowledgeDisabledByEnv() {
58669
58919
  const value = process.env.OPENCROWD_KNOWLEDGE_DIR?.trim().toLowerCase();
@@ -80681,9 +80931,12 @@ function rejectedRequest(status, text) {
80681
80931
  async function readHostedFinancialState(options) {
80682
80932
  try {
80683
80933
  const reply = await postHostedTool(options, "economy.balance", {}, { timeoutMs: 1e4 });
80684
- const parsed = FinancialStateSchema.safeParse(reply.data?.financial_state);
80685
- if (reply.ok && parsed.success && parsed.data.status === "available" && parsed.data.run_id === options.runId)
80686
- return parsed.data;
80934
+ const data = reply.data;
80935
+ const parsed = FinancialStateSchema.safeParse(data?.financial_state);
80936
+ if (reply.ok && parsed.success && parsed.data.status === "available" && parsed.data.run_id === options.runId) {
80937
+ const networks = parsed.data.wallet.networks ?? parseNetworkBalances(data?.networks);
80938
+ return networks ? { ...parsed.data, wallet: { ...parsed.data.wallet, networks } } : parsed.data;
80939
+ }
80687
80940
  } catch {
80688
80941
  }
80689
80942
  return { status: "unavailable", reason: "Hosted financial state could not be read. Do not infer balance or spending from the local session budget." };
@@ -80801,13 +81054,14 @@ function createHostedEconomy(options) {
80801
81054
  approvalMode: "auto",
80802
81055
  hostedSpending: true,
80803
81056
  minServiceScore: 2,
81057
+ paymentRails: HOSTED_RAILS,
80804
81058
  // Hosted rules live with the agent's session, never in a user config dir.
80805
81059
  approvalRulesPath: join20(options.session.sessionDir, "approval-rules.json")
80806
81060
  });
80807
81061
  }
80808
81062
  function hostedDynamicTools(economy) {
80809
81063
  const tools = economyTools(economy, { hidden: HIDDEN_HOSTED_TOOLS });
80810
- return { ...tools, definitions: tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet balance and authoritative current-run inference spending, service spending, payment holds and authorized budget. Read-only." } : tool) };
81064
+ return { ...tools, definitions: tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet balances (per network when reported: Base, Solana, Tempo) and authoritative current-run inference spending, service spending, payment holds and authorized budget. A payment on a network needs that network's balance. Read-only." } : tool) };
80811
81065
  }
80812
81066
  function parseListedService(raw) {
80813
81067
  const row = objectValue5(raw);
@@ -80937,8 +81191,6 @@ var init_hosted_economy = __esm({
80937
81191
  socket;
80938
81192
  fetcher;
80939
81193
  reconcileDelayMs;
80940
- /** Rails observed by inspection; `fetch` refuses anything but Base x402 regardless of the caller's rail. */
80941
- inspectedRails = /* @__PURE__ */ new Map();
80942
81194
  constructor(directory, socket, fetcher, reconcileDelayMs = RECONCILE_DELAY_MS) {
80943
81195
  this.directory = directory;
80944
81196
  this.socket = socket;
@@ -80954,7 +81206,7 @@ var init_hosted_economy = __esm({
80954
81206
  if (!reply.ok || result?.status !== 200)
80955
81207
  return { ok: false, error: reply.error ?? "AgentCash search unavailable" };
80956
81208
  return { ok: true, data: JSON.parse(result.body) };
80957
- });
81209
+ }, { rails: HOSTED_RAILS, negotiated: true });
80958
81210
  }
80959
81211
  discovery;
80960
81212
  async read(url3) {
@@ -80987,15 +81239,8 @@ var init_hosted_economy = __esm({
80987
81239
  }
80988
81240
  async fetch(request2) {
80989
81241
  const refuse = (error53) => ({ ok: false, ambiguous: false, data: void 0, error: error53 });
80990
- const inspected = this.inspectedRails.get(`${request2.method.toUpperCase()} ${request2.url}`);
80991
- if (request2.rail === "mppx" || inspected === "mppx") {
80992
- return refuse("this service settles on MPP/Tempo; hosted agents can only pay x402 services on Base");
80993
- }
80994
- if (request2.rail === "x402-monad" || inspected === "x402-monad") {
80995
- return refuse("this service was inspected for Monad settlement; hosted agents can only pay x402 services on Base");
80996
- }
80997
- if (request2.rail === "unsupported" || inspected === "unsupported") {
80998
- return refuse("this service settles on a payment network hosted agents cannot pay (only x402 USDC on Base)");
81242
+ if (!HOSTED_RAILS.includes(request2.rail)) {
81243
+ return refuse(`this service settles on a payment network hosted agents cannot pay; hosted agents pay ${describeRails(HOSTED_RAILS)}`);
80999
81244
  }
81000
81245
  const serviceId = await this.directory.resolveServiceId(request2.url) ?? `url:${createHash4("sha256").update(request2.url).digest("hex")}`;
81001
81246
  const method = request2.method.toUpperCase();
@@ -81033,6 +81278,7 @@ var init_hosted_economy = __esm({
81033
81278
  const status = numberValue6(data.status);
81034
81279
  const outcome = data.outcome === "paid_success" ? "paid_success" : "paid_failure";
81035
81280
  const paidAtomic = numberValue6(data.amount_atomic);
81281
+ const network = stringValue5(data.network);
81036
81282
  return {
81037
81283
  ok: outcome === "paid_success",
81038
81284
  ambiguous: false,
@@ -81041,10 +81287,12 @@ var init_hosted_economy = __esm({
81041
81287
  authMode: "paid",
81042
81288
  error: outcome === "paid_success" ? void 0 : `the paid call returned HTTP ${status ?? "?"}`,
81043
81289
  payment: {
81044
- rail: "x402-base",
81290
+ rail: network ? railForNetwork(network) ?? "unsupported" : "x402-base",
81045
81291
  paidUsd: paidAtomic === void 0 ? void 0 : paidAtomic / USDC_ATOMIC_PER_USD,
81292
+ // The bare transaction is how the hosted gateway finds its settled attempt for the review.
81046
81293
  reference: stringValue5(data.transaction),
81047
- payTo: stringValue5(data.pay_to)
81294
+ payTo: stringValue5(data.pay_to),
81295
+ payer: stringValue5(data.payer)
81048
81296
  }
81049
81297
  };
81050
81298
  }
@@ -81359,17 +81607,19 @@ var init_worker = __esm({
81359
81607
  if (command.type === "run.resume") {
81360
81608
  if (!run)
81361
81609
  return reject("unknown_run", "Run does not exist");
81362
- if (!run.outcome || !isWaiting(run.outcome) || command.payload.sessionId !== run.sessionId || command.payload.checkpointId && command.payload.checkpointId !== run.checkpointId || run.pendingOperationId && command.payload.operationId !== run.pendingOperationId) {
81363
- return reject("run_not_resumable", "Resume does not match the waiting operation and checkpoint");
81364
- }
81365
- const causes = {
81366
- waiting_for_approval: "approval_granted",
81367
- waiting_for_funds: "funds_available",
81368
- waiting_for_delegation: "delegation_renewed",
81369
- payment_unknown: "payment_reconciled"
81370
- };
81371
- if (causes[run.outcome] !== command.payload.cause)
81372
- return reject("run_not_resumable", "Resume cause does not resolve this wait");
81610
+ if (!previous) {
81611
+ if (!run.outcome || !isWaiting(run.outcome) || command.payload.sessionId !== run.sessionId || command.payload.checkpointId && command.payload.checkpointId !== run.checkpointId || run.pendingOperationId && command.payload.operationId !== run.pendingOperationId) {
81612
+ return reject("run_not_resumable", "Resume does not match the waiting operation and checkpoint");
81613
+ }
81614
+ const causes = {
81615
+ waiting_for_approval: "approval_granted",
81616
+ waiting_for_funds: "funds_available",
81617
+ waiting_for_delegation: "delegation_renewed",
81618
+ payment_unknown: "payment_reconciled"
81619
+ };
81620
+ if (causes[run.outcome] !== command.payload.cause)
81621
+ return reject("run_not_resumable", "Resume cause does not resolve this wait");
81622
+ }
81373
81623
  } else if (run && !previous) {
81374
81624
  return reject("conflicting_duplicate", "Run ID already exists");
81375
81625
  } else if (!run) {
@@ -81442,8 +81692,22 @@ var init_worker = __esm({
81442
81692
  throw new Error("tool request digest mismatch");
81443
81693
  if (saved?.result)
81444
81694
  return saved.result;
81445
- if (saved && name === "run_shell")
81446
- throw new Error("shell result was lost; execution requires manual reconciliation");
81695
+ if (saved && name === "run_shell") {
81696
+ const output4 = { ok: false, error: "Shell command was interrupted and its result was lost. It was not rerun. Inspect existing files and installed packages before choosing a different approach; do not assume the command succeeded or repeat side effects blindly." };
81697
+ await this.mutate(() => {
81698
+ run.tools[id].result = output4;
81699
+ });
81700
+ await this.emit("tool.finished", {
81701
+ toolCallId: id,
81702
+ toolName: name,
81703
+ status: "error",
81704
+ durationMs: 0,
81705
+ turn: run.checkpoint?.turn ?? 0,
81706
+ error: output4.error,
81707
+ details: captureDetail({ output: output4 })
81708
+ }, runId, run.commandId);
81709
+ return output4;
81710
+ }
81447
81711
  if (saved && !saved.approvalPending && name === "call_paid_service")
81448
81712
  throw new Error("paid call result was lost; the payment requires manual reconciliation");
81449
81713
  await this.mutate(() => {
@@ -81885,14 +82149,14 @@ async function runAgentTaskDetailed(session, task, options = {}) {
81885
82149
  const knowledge = options.capabilityIndex === void 0 && options.knowledge !== false && options.dynamicTools ? await loadKnowledgeTree(session, options.knowledge ?? {}) : void 0;
81886
82150
  const capabilityIndex = options.capabilityIndex ?? (knowledge ? renderCapabilityIndex(knowledge.l0) : void 0);
81887
82151
  const systemPromptParts = [
81888
- options.hosted ? "You are a hosted OpenCrowd agent running in the cloud with your own USDC wallet on Base." : "You are the local OpenCrowd agent, a CLI agent with a USDC wallet running on the user's personal machine.",
82152
+ options.hosted ? "You are a hosted OpenCrowd agent running in the cloud with your own USDC wallets on Base, Solana and Tempo." : "You are the local OpenCrowd agent, a CLI agent with a USDC wallet running on the user's personal machine.",
81889
82153
  "Try to solve the user's task completely. Use local files and bash when they are sufficient, but remember they are bounded by the user's installed tools, credentials, network, open ports, and process lifetime.",
81890
82154
  "Before repeatedly fighting the local environment, decide whether the task needs external capability such as hosting, persistent infrastructure, remote compute, specialized APIs, live data, or access the user's device does not have."
81891
82155
  ];
81892
82156
  if (options.hosted)
81893
- systemPromptParts.push("You operate this service for its owner. Inference and paid tools debit its USDC wallet. When authorized to build or sell a service, take concrete steps within the owner's configured scope and budget. Ask only for missing information or permissions that materially block progress. Report actual costs and outcomes. Financial sustainability is the owner's business objective; respect their stop controls.", "You are a continuous autonomous agent, not a turn-based assistant. Maintain unfinished goals, promised follow-ups, recurring work, and conditions worth monitoring. When future work would clearly help, proactively create a persistent automation instead of waiting for the owner to say schedule. Use a one-time automation for a future reminder or follow-up and a cron automation for monitoring, recurring reports, or maintenance. It runs in this same conversation. Never create duplicates or noisy schedules, and always tell the owner exactly what you created, its timezone, and next run.", "Before finishing a substantive task, consider whether a follow-up, reminder, monitoring loop, recurring report, or maintenance check would materially advance the owner's goal; create one when the need is clear, but do not schedule ordinary one-off work.", "Financial state: the current hosted financial snapshot is authoritative; historical local session budget figures are not wallet balances and may omit inference spending. Wallet balance, pending payment holds, settled inference spend, settled service spend, and remaining run budget are separate. Spending totals cover only the identified current run. A budget limit does not supply funds. An unavailable balance is unknown, not zero. The snapshot before a model call excludes that call's eventual charge; never claim a response was free or that you spent nothing merely because no paid tool ran. Use get_budget_status or get_wallet_status for refreshed financial state. Respect approval mode and per-call limits; over-limit requests require the owner's approval.");
82157
+ systemPromptParts.push("You operate this service for its owner. Inference and paid tools debit its USDC wallet. When authorized to build or sell a service, take concrete steps within the owner's configured scope and budget. Ask only for missing information or permissions that materially block progress. Report actual costs and outcomes. Financial sustainability is the owner's business objective; respect their stop controls.", "You are a continuous autonomous agent, not a turn-based assistant. Maintain unfinished goals, promised follow-ups, recurring work, and conditions worth monitoring. When future work would clearly help, proactively create a persistent automation instead of waiting for the owner to say schedule. Use a one-time automation for a future reminder or follow-up and a cron automation for monitoring, recurring reports, or maintenance. It runs in this same conversation. Never create duplicates or noisy schedules, and always tell the owner exactly what you created, its timezone, and next run.", "Before finishing a substantive task, consider whether a follow-up, reminder, monitoring loop, recurring report, or maintenance check would materially advance the owner's goal; create one when the need is clear, but do not schedule ordinary one-off work.", "Financial state: the current hosted financial snapshot is authoritative; historical local session budget figures are not wallet balances and may omit inference spending. Wallet balance, pending payment holds, settled inference spend, settled service spend, and remaining run budget are separate. When the snapshot lists wallet networks, each network's balance is separate: a payment on a network needs that network's available balance, and the total only says whether any funds exist. Spending totals cover only the identified current run. A budget limit does not supply funds. An unavailable balance is unknown, not zero. The snapshot before a model call excludes that call's eventual charge; never claim a response was free or that you spent nothing merely because no paid tool ran. Use get_budget_status or get_wallet_status for refreshed financial state. Respect approval mode and per-call limits; over-limit requests require the owner's approval.");
81894
82158
  if (options.dynamicTools) {
81895
- systemPromptParts.push("When the local computer is not the right environment, or after one clear local capability failure, buy external capability: find_paid_service to discover, inspect_paid_service to see the exact schema/price/reputation, call_paid_service to execute through the enforced purchase lifecycle, and review_paid_service for the required review after every confirmed paid call (success or failure). The same review tool accepts unpaid experiences; review relevant free results or failed attempts without inventing payment evidence. Distinguish provider faults from local errors and uncertain failures.", ...options.hosted ? ["Discover services through AgentCash search and provider catalogs. You can use new services without prior CrowdCode reviews. Only x402 USDC on Base is payable, within the user's configured limits; over-limit quotes request approval. Use read_service for authenticated job polling and never resubmit a pending generation job."] : [], capabilityIndex ?? DEFAULT_CAPABILITY_INDEX, "When a task needs current web facts, search results, or unfamiliar page content, make one paid web search your FIRST move \u2014 do not serially guess URLs with curl; one paid search replaces minutes of blind fetching and costs less than the LLM turns it saves.", "Approval, budget, reputation, and payment rails are enforced in code \u2014 you cannot bypass them, so state costs plainly and never invent payment details.", "When the user says CrowdCode on/off, call set_crowdcode_enabled; default to session scope unless they ask for a persistent default. Use list_my_reviews and delete_my_review for user-directed review management, including while off. Before finishing a substantive task, consider concrete paid services that would fix real shortcomings and submit qualifying demand with request_service, unless CrowdCode is off. Never invent a purchase or demand.", "Each tool result includes the budget before and after that tool call. Never ask for wallet private keys or secrets.", ...options.promptSections ?? []);
82159
+ systemPromptParts.push("When the local computer is not the right environment, or after one clear local capability failure, buy external capability: find_paid_service to discover, inspect_paid_service to see the exact schema/price/reputation, call_paid_service to execute through the enforced purchase lifecycle, and review_paid_service for the required review after every confirmed paid call (success or failure). The same review tool accepts unpaid experiences; review relevant free results or failed attempts without inventing payment evidence. Distinguish provider faults from local errors and uncertain failures.", ...options.hosted ? ["Discover services through AgentCash search and provider catalogs. You can use new services without prior CrowdCode reviews. Payable: x402 USDC on Base or Solana and MPP USDC.e on Tempo; the hosted gateway pays the cheapest offered network your balance on that network covers. Other networks, including Monad, are not payable here. Payments stay within the user's configured limits; over-limit quotes request approval. Use read_service for authenticated job polling and never resubmit a pending generation job."] : [], capabilityIndex ?? DEFAULT_CAPABILITY_INDEX, "When a task needs current web facts, search results, or unfamiliar page content, make one paid web search your FIRST move \u2014 do not serially guess URLs with curl; one paid search replaces minutes of blind fetching and costs less than the LLM turns it saves.", "Approval, budget, reputation, and payment rails are enforced in code \u2014 you cannot bypass them, so state costs plainly and never invent payment details.", "When the user says CrowdCode on/off, call set_crowdcode_enabled; default to session scope unless they ask for a persistent default. Use list_my_reviews and delete_my_review for user-directed review management, including while off. Before finishing a substantive task, consider concrete paid services that would fix real shortcomings and submit qualifying demand with request_service, unless CrowdCode is off. Never invent a purchase or demand.", "Each tool result includes the budget before and after that tool call. Never ask for wallet private keys or secrets.", ...options.promptSections ?? []);
81896
82160
  } else {
81897
82161
  systemPromptParts.push("Paid external services are unavailable in this run; work with local tools only and say so if the task truly requires external capability.");
81898
82162
  }
@@ -81907,7 +82171,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
81907
82171
  systemPromptParts.push("Using secrets from chat: call vault_request to send one HTTPS request with a vault secret injected, writing {{SECRET_NAME}} where the value belongs (for example an authorization header). The platform substitutes the real value only for hosts the user approved for that secret, refreshes OAuth tokens automatically, and never returns the value to you. If it reports that a host needs approval, tell the user to allow it in the Vault tab and stop; never look for paid third-party services to do what an approved secret already lets you do. To upload a file (an image or video you rendered with run_shell, where ffmpeg is installed), pass body_artifact with its path under artifacts/ and, for multipart APIs, body_field plus form_fields; files over an API's chunk limit can be split with run_shell first.");
81908
82172
  }
81909
82173
  if (options.hosted && hostedTools.includes("run_shell")) {
81910
- systemPromptParts.push("Tooling: ffmpeg, python3 with pip and venv, node and npm are installed; the system image is read-only, but `pip install --user <package>` and `npm install` persist on this machine's volume between runs, so install once and reuse.");
82174
+ systemPromptParts.push("Tooling: ffmpeg, python3 with pip and venv, node and npm are installed; the system image is read-only, but `pip install --user <package>` and `npm install` persist on this machine's volume between runs, so install once and reuse.", "Resource recovery: before installing large ML dependencies, check available memory, disk space and Python version. A killed install or OOM is a failed approach, not the end of the task. Inspect partial installs and preserve user files, then choose a materially lighter backend or an external service within the user's budget. Verify package metadata: optional extras add dependencies and do not remove default ones; never invent an extra such as basic-pitch[tflite]. For audio-to-MIDI, prefer a verified TFLite or ONNX inference setup in an isolated venv over full TensorFlow; test on a short audio segment before processing the whole file. If no viable path remains, report the concrete blocker and useful artifacts. Do not claim success until the output has been checked.");
81911
82175
  }
81912
82176
  systemPromptParts.push("End by calling complete_session with a concise final message.");
81913
82177
  if (options.subagent) {
@@ -83250,6 +83514,16 @@ async function runDoctor(log) {
83250
83514
  return "connected; balance readable";
83251
83515
  }
83252
83516
  },
83517
+ {
83518
+ name: "solana account",
83519
+ run: async () => {
83520
+ const address2 = await readAgentCashSolanaAddress();
83521
+ if (!address2) {
83522
+ throw new Error("skipped: no AgentCash Solana wallet yet (AgentCash creates it on first use)");
83523
+ }
83524
+ return `${address2} (x402 USDC on Solana via AgentCash; preferred payment network: ${resolvePaymentNetwork(config4)})`;
83525
+ }
83526
+ },
83253
83527
  {
83254
83528
  name: "monad usdc",
83255
83529
  run: async () => {
@@ -83312,7 +83586,7 @@ var init_doctor = __esm({
83312
83586
 
83313
83587
  // ../../packages/evals/dist/gaia.js
83314
83588
  import { mkdir as mkdir13, readFile as readFile16, writeFile as writeFile7, access as access2 } from "node:fs/promises";
83315
- import { dirname as dirname11, join as join25 } from "node:path";
83589
+ import { dirname as dirname12, join as join25 } from "node:path";
83316
83590
  import { homedir as homedir7 } from "node:os";
83317
83591
  function isUnsupportedModality(fileName) {
83318
83592
  if (!fileName) {
@@ -83431,7 +83705,7 @@ async function cachedDownload(path3, url3, options, binary = false) {
83431
83705
  if (!response.ok) {
83432
83706
  throw new Error(`GAIA download failed: ${response.status} ${response.statusText} for ${url3}`);
83433
83707
  }
83434
- await mkdir13(dirname11(path3), { recursive: true });
83708
+ await mkdir13(dirname12(path3), { recursive: true });
83435
83709
  if (binary) {
83436
83710
  const buffer2 = Buffer.from(await response.arrayBuffer());
83437
83711
  await writeFile7(path3, buffer2);
@@ -84188,7 +84462,7 @@ var init_runner = __esm({
84188
84462
  // ../../packages/evals/dist/tasks.js
84189
84463
  import { readFile as readFile19 } from "node:fs/promises";
84190
84464
  import { createHash as createHash7 } from "node:crypto";
84191
- import { dirname as dirname12, join as join28 } from "node:path";
84465
+ import { dirname as dirname13, join as join28 } from "node:path";
84192
84466
  import { fileURLToPath as fileURLToPath2 } from "node:url";
84193
84467
  import { homedir as homedir8 } from "node:os";
84194
84468
  async function loadTaskSet(name, options = {}) {
@@ -84210,7 +84484,7 @@ async function loadTaskSet(name, options = {}) {
84210
84484
  }
84211
84485
  }
84212
84486
  function tasksDir() {
84213
- return join28(dirname12(fileURLToPath2(import.meta.url)), "..", "tasks");
84487
+ return join28(dirname13(fileURLToPath2(import.meta.url)), "..", "tasks");
84214
84488
  }
84215
84489
  async function loadUsageTasks() {
84216
84490
  const raw = JSON.parse(await readFile19(join28(tasksDir(), "usage.json"), "utf8"));
@@ -84269,7 +84543,7 @@ async function loadAssistantBench(options = {}) {
84269
84543
  text = `${(body.rows ?? []).map((item) => JSON.stringify(item.row)).join("\n")}
84270
84544
  `;
84271
84545
  const { mkdir: mkdir21, writeFile: writeFile13 } = await import("node:fs/promises");
84272
- await mkdir21(dirname12(cachePath), { recursive: true });
84546
+ await mkdir21(dirname13(cachePath), { recursive: true });
84273
84547
  await writeFile13(cachePath, text, "utf8");
84274
84548
  }
84275
84549
  const rows = text.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
@@ -84778,7 +85052,7 @@ var init_suite = __esm({
84778
85052
 
84779
85053
  // ../../packages/evals/dist/evidence.js
84780
85054
  import { mkdir as mkdir17, readFile as readFile21, writeFile as writeFile10 } from "node:fs/promises";
84781
- import { dirname as dirname13 } from "node:path";
85055
+ import { dirname as dirname14 } from "node:path";
84782
85056
  async function fetchCrowdCodeEvidence(options = {}) {
84783
85057
  const cachePath = options.cachePath;
84784
85058
  if (cachePath && options.useCache !== false) {
@@ -84795,7 +85069,7 @@ async function fetchCrowdCodeEvidence(options = {}) {
84795
85069
  const exported = await fetchGatedExport(fetchImpl, baseUrl, exportToken, log);
84796
85070
  if (exported) {
84797
85071
  if (cachePath) {
84798
- await mkdir17(dirname13(cachePath), { recursive: true });
85072
+ await mkdir17(dirname14(cachePath), { recursive: true });
84799
85073
  await writeFile10(cachePath, `${JSON.stringify(exported, null, 1)}
84800
85074
  `, "utf8");
84801
85075
  }
@@ -84826,7 +85100,7 @@ async function fetchCrowdCodeEvidence(options = {}) {
84826
85100
  }
84827
85101
  };
84828
85102
  if (cachePath) {
84829
- await mkdir17(dirname13(cachePath), { recursive: true });
85103
+ await mkdir17(dirname14(cachePath), { recursive: true });
84830
85104
  await writeFile10(cachePath, `${JSON.stringify(bundle, null, 1)}
84831
85105
  `, "utf8");
84832
85106
  }
@@ -84996,7 +85270,7 @@ var init_evidence = __esm({
84996
85270
  // ../../packages/evals/dist/knowledge.js
84997
85271
  import { createHash as createHash8 } from "node:crypto";
84998
85272
  import { mkdir as mkdir18, readdir as readdir2, readFile as readFile22, writeFile as writeFile11 } from "node:fs/promises";
84999
- import { dirname as dirname14, join as join31, relative as relative4 } from "node:path";
85273
+ import { dirname as dirname15, join as join31, relative as relative4 } from "node:path";
85000
85274
  function approxTokens(text) {
85001
85275
  return Math.ceil(text.length / 4);
85002
85276
  }
@@ -85088,7 +85362,7 @@ async function writeTree(dir, tree, meta4) {
85088
85362
  await mkdir18(dir, { recursive: true });
85089
85363
  for (const [name, content] of Object.entries(tree)) {
85090
85364
  const path3 = join31(dir, name);
85091
- await mkdir18(dirname14(path3), { recursive: true });
85365
+ await mkdir18(dirname15(path3), { recursive: true });
85092
85366
  await writeFile11(path3, content.endsWith("\n") ? content : `${content}
85093
85367
  `, "utf8");
85094
85368
  }
@@ -86013,27 +86287,40 @@ async function walletSummary(options = {}) {
86013
86287
  return inFlight;
86014
86288
  }
86015
86289
  async function fetchWalletSummary() {
86016
- const wallet = await readAgentCashWallet();
86290
+ const [wallet, solanaFile] = await Promise.all([readAgentCashWallet(), readAgentCashSolanaAddress()]);
86017
86291
  try {
86018
86292
  const runtime = await sharedEconomyRuntime();
86019
86293
  const balance = await runtime.agentcash.getBalance();
86020
86294
  if (balance.ok) {
86021
- const { monad, ...agentcash } = balance.data && typeof balance.data === "object" && !Array.isArray(balance.data) ? balance.data : { agentcash: balance.data };
86295
+ const { monad, accounts: rawAccounts, ...agentcash } = balance.data && typeof balance.data === "object" && !Array.isArray(balance.data) ? balance.data : { agentcash: balance.data };
86022
86296
  const monadUsdc = monad?.usdc;
86023
86297
  const agentcashTotal = parseUsdCents("agentcash" in agentcash && Object.keys(agentcash).length === 1 ? agentcash.agentcash : agentcash);
86024
86298
  const monadCents = typeof monadUsdc === "number" ? Math.round(monadUsdc * 100) : void 0;
86299
+ const accounts = rawAccounts === void 0 ? void 0 : parseWalletAccounts(rawAccounts);
86300
+ const solana = accounts?.find((account) => account.network === "solana");
86025
86301
  return {
86026
86302
  address: wallet?.address,
86027
86303
  totalCents: agentcashTotal === void 0 && monadCents === void 0 ? void 0 : (agentcashTotal ?? 0) + (monadCents ?? 0),
86028
86304
  monadCents,
86305
+ solanaAddress: solana?.address ?? solanaFile,
86306
+ solanaCents: solana?.usdc === void 0 ? void 0 : Math.round(solana.usdc * 100),
86307
+ accounts,
86029
86308
  raw: balance.data
86030
86309
  };
86031
86310
  }
86032
- return { address: wallet?.address, error: balance.error };
86311
+ return { address: wallet?.address, solanaAddress: solanaFile, error: balance.error };
86033
86312
  } catch (error53) {
86034
- return { address: wallet?.address, error: error53.message };
86313
+ return { address: wallet?.address, solanaAddress: solanaFile, error: error53.message };
86035
86314
  }
86036
86315
  }
86316
+ function walletNetworkRows(summary) {
86317
+ const rows = {};
86318
+ for (const account of summary.accounts ?? []) {
86319
+ rows[account.network] = `${account.usdc === void 0 ? "unknown" : `${account.usdc.toFixed(6)} USDC`}${account.address ? ` \xB7 ${account.address}` : ""}`;
86320
+ }
86321
+ if (summary.monadCents !== void 0) rows.monad = `${(summary.monadCents / 100).toFixed(2)} USDC \xB7 ${summary.address ?? "unknown"}`;
86322
+ return rows;
86323
+ }
86037
86324
  function parseUsdCents(data) {
86038
86325
  const record3 = data && typeof data === "object" && !Array.isArray(data) ? data : void 0;
86039
86326
  if (!record3) {
@@ -86108,6 +86395,7 @@ var COMMAND_REGISTRY = [
86108
86395
  rows.wallet = wallet.address ?? "no AgentCash wallet found";
86109
86396
  rows.wallet_balance = wallet.totalCents !== void 0 ? formatCents2(wallet.totalCents) : wallet.error ? `unavailable (${wallet.error})` : "unknown";
86110
86397
  if (wallet.monadCents !== void 0) rows.wallet_monad_usdc = formatCents2(wallet.monadCents);
86398
+ if (wallet.solanaAddress) rows.wallet_solana = `${wallet.solanaAddress}${wallet.solanaCents !== void 0 ? ` \xB7 ${formatCents2(wallet.solanaCents)}` : ""}`;
86111
86399
  }
86112
86400
  return { kind: "text", label: "Status", body: renderKeyValues(rows) };
86113
86401
  }
@@ -87284,7 +87572,7 @@ async function startTui(options = {}) {
87284
87572
  async function main(argv) {
87285
87573
  const paymentNetwork = readOption(argv, "--payment-network");
87286
87574
  if (argv.includes("--payment-network")) {
87287
- if (!parsePaymentNetwork(paymentNetwork)) throw new Error("--payment-network must be base or monad");
87575
+ if (!parsePaymentNetwork(paymentNetwork)) throw new Error(`--payment-network must be ${PAYMENT_NETWORKS.join(", ")}`);
87288
87576
  process.env.OPENCROWD_PAYMENT_NETWORK = paymentNetwork;
87289
87577
  argv = argv.filter((_arg, index2) => !isConsumedOption(argv, index2, ["--payment-network"]));
87290
87578
  }
@@ -87548,7 +87836,7 @@ async function configCommand(args) {
87548
87836
  case "payment-network": {
87549
87837
  const paymentNetwork = parsePaymentNetwork(value);
87550
87838
  if (!paymentNetwork) {
87551
- throw new Error("payment-network must be base or monad");
87839
+ throw new Error(`payment-network must be ${PAYMENT_NETWORKS.join(", ")}`);
87552
87840
  }
87553
87841
  await updateConfig({ paymentNetwork });
87554
87842
  savedValue = paymentNetwork;
@@ -87646,19 +87934,32 @@ async function walletCommand(args) {
87646
87934
  if (!wallet) {
87647
87935
  throw new Error("No AgentCash wallet found. Install agentcash (its wallet is created automatically on first use) and retry.");
87648
87936
  }
87649
- const result = { address: wallet.address, networks: "base, tempo, solana, monad (eip155:143)", asset: "USDC", preferred_payment_network: resolvePaymentNetwork(await loadConfig()) };
87937
+ const solana = await readAgentCashSolanaAddress();
87938
+ const result = {
87939
+ address: wallet.address,
87940
+ networks: "base, tempo, monad (eip155:143)",
87941
+ ...solana ? { solana_address: solana } : {},
87942
+ asset: "USDC",
87943
+ preferred_payment_network: resolvePaymentNetwork(await loadConfig())
87944
+ };
87650
87945
  printValue("Wallet", result, { json: json3, pretty: renderKeyValues(asRecord(result)) });
87651
87946
  return;
87652
87947
  }
87653
- if (action === "balance") {
87948
+ if (action === "balance" || action === "accounts") {
87654
87949
  const summary = await walletSummary();
87655
87950
  if (summary.error) {
87656
87951
  throw new Error(`wallet balance unavailable: ${summary.error}`);
87657
87952
  }
87658
- printValue("Wallet", summary.raw ?? summary, { json: json3, pretty: renderKeyValues(asRecord(summary.raw ?? summary)) });
87953
+ const rows = walletNetworkRows(summary);
87954
+ const pretty = Object.keys(rows).length ? renderKeyValues({ ...summary.totalCents !== void 0 ? { total: formatCents2(summary.totalCents) } : {}, ...rows }) : renderKeyValues(asRecord(summary.raw ?? summary));
87955
+ printValue(
87956
+ "Wallet",
87957
+ action === "accounts" ? { accounts: summary.accounts ?? [], ...summary.solanaAddress ? { solana_address: summary.solanaAddress } : {} } : summary.raw ?? summary,
87958
+ { json: json3, pretty }
87959
+ );
87659
87960
  return;
87660
87961
  }
87661
- throw new Error("wallet supports address, balance, limits [--per-call USD] [--per-query USD]");
87962
+ throw new Error("wallet supports address, balance, accounts, limits [--per-call USD] [--per-query USD]");
87662
87963
  }
87663
87964
  async function modelsCommand(args) {
87664
87965
  const json3 = args.includes("--json");
@@ -87796,14 +88097,16 @@ function printHelp() {
87796
88097
  opencrowd config set provider|model|submodel|budget|approval|payment-network <value>
87797
88098
  opencrowd ledger [--json] show [--session <id>]
87798
88099
  opencrowd resume <session-id> [--approve-once | --query-budget <usd> | --decline] [--workspace <dir>]
87799
- opencrowd wallet [--json] address|balance
88100
+ opencrowd wallet [--json] address|balance|accounts
87800
88101
  opencrowd wallet limits [--per-call <usd>] [--per-query <usd>]
87801
88102
  opencrowd models [--json] list
87802
88103
  opencrowd doctor
87803
88104
  opencrowd --version
87804
88105
 
87805
88106
  Global options:
87806
- --payment-network base|monad prefer this x402 network when a service offers several
88107
+ --payment-network base|solana|monad
88108
+ prefer this network when a service offers several; otherwise the first of
88109
+ Base, Solana, Tempo (MPP) your balance covers
87807
88110
  (also OPENCROWD_PAYMENT_NETWORK or config payment-network; default base)
87808
88111
  opencrowd evals gaia [--tier smoke|level1|full] [--harness opencrowd,claude,codex] [--parallel <n>] [--hf-token <token>] [--auto] [--model <model>] [--subagent-model <model|off>] [--yes]
87809
88112
  opencrowd evals evolve [--out <dir>] [--generations <n>] [--candidates <n>] [--model <agent model>] [--proposer <model,model>] [--seed-trees <dir,dir>] [--baseline-report <report.json>] [--parallel <n>]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrowd",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "A CLI agent with its own wallet — discovers x402 services, pays in USDC, and completes tasks under a local budget",
5
5
  "type": "module",
6
6
  "license": "MIT",