opencrowd 0.16.3 → 0.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bundle/opencrowd.js +592 -189
  2. package/package.json +1 -1
@@ -16176,7 +16176,7 @@ var init_context = __esm({
16176
16176
  };
16177
16177
  CONTEXT_COST_BUDGET_USD = 0.02;
16178
16178
  CONTEXT_MIN_HISTORY_TOKENS = 24e3;
16179
- centsPer1kToUsdPerMillion = (cents) => typeof cents === "number" && Number.isFinite(cents) && cents > 0 ? cents * 10 : void 0;
16179
+ centsPer1kToUsdPerMillion = (cents2) => typeof cents2 === "number" && Number.isFinite(cents2) && cents2 > 0 ? cents2 * 10 : void 0;
16180
16180
  }
16181
16181
  });
16182
16182
 
@@ -16506,7 +16506,7 @@ async function reserveBudget(state, amountCents, action) {
16506
16506
  assertCents(amountCents, "reservation");
16507
16507
  if (state.query) {
16508
16508
  const committed = state.spentCents - state.query.startSpentCents + state.reservedCents;
16509
- const atomic2 = (cents) => String(Math.round(cents * 1e4));
16509
+ const atomic2 = (cents2) => String(Math.round(cents2 * 1e4));
16510
16510
  const check3 = spendingDecision({
16511
16511
  amount: atomic2(amountCents),
16512
16512
  perCall: atomic2(state.perCallCents ?? 100),
@@ -17151,6 +17151,8 @@ function summarizeToolInput(name, args) {
17151
17151
  return pick3({ url: text(args.url), method: text(args.method), max_cost_cents: text(args.max_cost_cents) });
17152
17152
  case "review_paid_service":
17153
17153
  return pick3({ purchase_id: text(args.purchase_id), rating: text(args.rating) });
17154
+ case "plan_funding":
17155
+ return pick3({ calls: text(Array.isArray(args.calls) ? args.calls.map((call2) => call2?.url).filter((url3) => typeof url3 === "string").join(" ") : void 0) });
17154
17156
  case "bridge_usdc":
17155
17157
  return pick3({
17156
17158
  from: text(args.from),
@@ -55927,13 +55929,13 @@ var init_approve = __esm({
55927
55929
  });
55928
55930
  }
55929
55931
  approve2.estimateGas = estimateGas2;
55930
- async function simulate(client, parameters) {
55932
+ async function simulate2(client, parameters) {
55931
55933
  return simulateContract(client, {
55932
55934
  ...pickWriteParameters(parameters),
55933
55935
  ...approve2.call(client, parameters)
55934
55936
  });
55935
55937
  }
55936
- approve2.simulate = simulate;
55938
+ approve2.simulate = simulate2;
55937
55939
  function extractEvent(logs) {
55938
55940
  const [log] = parseEventLogs({
55939
55941
  abi: erc20Abi,
@@ -56408,13 +56410,13 @@ var init_transfer = __esm({
56408
56410
  });
56409
56411
  }
56410
56412
  transfer2.estimateGas = estimateGas2;
56411
- async function simulate(client, parameters) {
56413
+ async function simulate2(client, parameters) {
56412
56414
  return simulateContract(client, {
56413
56415
  ...pickWriteParameters(parameters),
56414
56416
  ...transfer2.call(client, parameters)
56415
56417
  });
56416
56418
  }
56417
- transfer2.simulate = simulate;
56419
+ transfer2.simulate = simulate2;
56418
56420
  function extractEvent(logs) {
56419
56421
  const [log] = parseEventLogs({
56420
56422
  abi: erc20Abi,
@@ -57752,7 +57754,8 @@ function classifyOffer(option) {
57752
57754
  protocol,
57753
57755
  rail,
57754
57756
  ...price_usd !== void 0 ? { price_usd } : {},
57755
- ...typeof option?.payTo === "string" ? { pay_to: option.payTo } : {}
57757
+ ...typeof option?.payTo === "string" ? { pay_to: option.payTo } : {},
57758
+ ...protocol === "mpp" && rail === "mppx" && price_usd === 0 ? { free: true } : {}
57756
57759
  };
57757
57760
  }
57758
57761
  function selectOffer(offers, selection) {
@@ -57914,8 +57917,10 @@ var init_discovery = __esm({
57914
57917
  network: candidate.network_name ?? candidate.network,
57915
57918
  protocol: candidate.protocol,
57916
57919
  price_usd: candidate.price_usd,
57917
- payable: payable.includes(candidate)
57920
+ payable: payable.includes(candidate),
57921
+ ...candidate.free ? { free: true } : {}
57918
57922
  })) } : {},
57923
+ ...offer?.free ? { free: true } : {},
57919
57924
  input_schema: advisory.inputSchema,
57920
57925
  output_schema: advisory.outputSchema,
57921
57926
  description: advisory.summary,
@@ -57935,13 +57940,20 @@ var init_discovery = __esm({
57935
57940
  }
57936
57941
  note(offers, offer) {
57937
57942
  const quote = "Inspect with sample_body for the exact quote.";
57943
+ if (offer?.free)
57944
+ return `Free: this endpoint asks only for proof of which wallet is calling (a zero-amount MPP challenge on ${offer.network_name ?? "Tempo"}). Calling it signs that proof; nothing is paid and no balance is needed on ${offer.network_name ?? "that network"} or anywhere else, so never move funds for it. Call it with call_paid_service.`;
57938
57945
  if (!offer) {
57939
57946
  const offered = [...new Set(offers.map(networkLabel))];
57940
57947
  return `${offered.length ? `This service offers ${offered.join(", ")}` : "This service advertises no recognised payment option"}; payable here: ${describeRails(this.rails)}. ${quote}`;
57941
57948
  }
57942
57949
  if (this.options.negotiated) {
57943
- const networks = payableNetworks(offers, this.rails).map((name) => networkLabel({ ...offer, network_name: name, rail: "x402-base" }));
57944
- 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}`;
57950
+ const payable = offers.filter((candidate) => candidate.rail !== "unsupported" && this.rails.includes(candidate.rail));
57951
+ const networks = payableNetworks(offers, this.rails).map((name) => {
57952
+ const price = payable.filter((candidate) => candidate.network_name === name).map((candidate) => candidate.price_usd ?? 0).sort((a, b) => a - b)[0];
57953
+ return `${networkLabel({ ...offer, network_name: name, rail: "x402-base" })}${price !== void 0 ? ` ($${price.toFixed(price < 0.01 ? 4 : 2)})` : ""}`;
57954
+ });
57955
+ const one = networks.length > 1 ? " Any one of these networks covering the price is enough: no move is needed while one of them does." : "";
57956
+ return `Payable on ${networks.join(", ")}. The hosted gateway pays the cheapest of them that your spendable balance on that network covers, Base first on a tie; price_usd is the ceiling across them.${one} ${quote}`;
57945
57957
  }
57946
57958
  const preferred = this.options.paymentNetwork ?? "base";
57947
57959
  const reason = payableNetworks(offers, this.rails).includes(preferred) ? `your ${preferred} balance does not cover it` : `${preferred} is not offered`;
@@ -58013,14 +58025,14 @@ var init_discovery = __esm({
58013
58025
  */
58014
58026
  async search(query, options = {}) {
58015
58027
  const limit = Math.min(20, Math.max(1, options.limit ?? 8));
58016
- const { rank, ...searchOptions } = options;
58028
+ const { rank: rank2, ...searchOptions } = options;
58017
58029
  const [result, balances] = await Promise.all([
58018
58030
  bounded(() => this.searchApi(query, { ...searchOptions, limit: Math.min(50, limit * 3) }), CATALOG_DEADLINE_MS, "AgentCash search"),
58019
- rank && this.options.balances ? withDeadline(() => this.options.balances(), CATALOG_DEADLINE_MS, "wallet balance read").catch(() => void 0) : Promise.resolve(void 0)
58031
+ rank2 && this.options.balances ? withDeadline(() => this.options.balances(), CATALOG_DEADLINE_MS, "wallet balance read").catch(() => void 0) : Promise.resolve(void 0)
58020
58032
  ]);
58021
58033
  const candidates = result.ok ? searchResults(result.data) : [];
58022
- if (rank) {
58023
- const ranking = await bounded(() => rank({
58034
+ if (rank2) {
58035
+ const ranking = await bounded(() => rank2({
58024
58036
  query,
58025
58037
  networks: this.networks(),
58026
58038
  ...balances ? { balances } : {},
@@ -58039,7 +58051,7 @@ var init_discovery = __esm({
58039
58051
  const verified = await this.verified(candidates, limit);
58040
58052
  return { ok: true, data: {
58041
58053
  services: verified.services,
58042
- note: `AgentCash discovery${rank ? " (CrowdCode ranking unavailable)" : ""}, verified ${describeRails(this.rails)}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.${this.partialNote(verified.incomplete)}`
58054
+ note: `AgentCash discovery${rank2 ? " (CrowdCode ranking unavailable)" : ""}, verified ${describeRails(this.rails)}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.${this.partialNote(verified.incomplete)}`
58043
58055
  } };
58044
58056
  }
58045
58057
  async discoverEndpoints(origin) {
@@ -58477,9 +58489,82 @@ var init_crowdcode = __esm({
58477
58489
  }
58478
58490
  });
58479
58491
 
58492
+ // ../../packages/economy/dist/follow-ups.js
58493
+ import { readFile as readFile8, writeFile as writeFile4 } from "node:fs/promises";
58494
+ import { join as join10 } from "node:path";
58495
+ function findFollowUpTokens(body) {
58496
+ const found = [];
58497
+ const walk4 = (value, path3, depth) => {
58498
+ if (!value || typeof value !== "object" || Array.isArray(value) || depth > MAX_DEPTH)
58499
+ return;
58500
+ for (const [key, child] of Object.entries(value)) {
58501
+ if (typeof child === "string" && TOKEN_FIELD.test(key) && child.length > 0 && child.length <= MAX_TOKEN_CHARS)
58502
+ found.push({ field: [...path3, key].join("."), value: child });
58503
+ else
58504
+ walk4(child, [...path3, key], depth + 1);
58505
+ }
58506
+ };
58507
+ walk4(body, [], 0);
58508
+ return found;
58509
+ }
58510
+ function matchesTemplate(template, path3) {
58511
+ const pattern = template.split("/").map((part) => /^\{[^}]+\}$/.test(part) ? "[^/]+" : part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("/");
58512
+ return new RegExp(`^${pattern}/?$`).test(path3);
58513
+ }
58514
+ function documentedHeader(openapi, url3, method, field) {
58515
+ const paths2 = openapi?.paths;
58516
+ if (!paths2 || typeof paths2 !== "object")
58517
+ return void 0;
58518
+ const { pathname } = new URL(url3);
58519
+ const leaf = field.split(".").pop().toLowerCase();
58520
+ for (const [template, item] of Object.entries(paths2)) {
58521
+ if (!matchesTemplate(template, pathname))
58522
+ continue;
58523
+ const operation = item?.[method.toLowerCase()] ?? {};
58524
+ const parameters = [...item.parameters ?? [], ...operation.parameters ?? []].filter((p) => !!p && typeof p === "object" && p.in === "header" && typeof p.name === "string");
58525
+ const named = parameters.find((p) => (p.description ?? "").toLowerCase().includes(leaf)) ?? parameters.find((p) => /unlock|re-?read/i.test(p.name));
58526
+ if (named && /^[A-Za-z0-9-]{1,64}$/.test(named.name) && !/^(authorization|cookie|payment-signature|x-payment)$/i.test(named.name))
58527
+ return named.name;
58528
+ }
58529
+ return void 0;
58530
+ }
58531
+ async function loadFollowUps(session) {
58532
+ try {
58533
+ const parsed = JSON.parse(await readFile8(storePath(session), "utf8"));
58534
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
58535
+ } catch {
58536
+ return {};
58537
+ }
58538
+ }
58539
+ async function saveFollowUp(session, key, credential) {
58540
+ const all = await loadFollowUps(session);
58541
+ all[key] = credential;
58542
+ await writeFile4(storePath(session), JSON.stringify(all, null, 2), { mode: 384 });
58543
+ }
58544
+ async function sellerOpenApi(origin, fetchJson) {
58545
+ for (const path3 of OPENAPI_PATHS) {
58546
+ const document = await fetchJson(`${origin}${path3}`).catch(() => void 0);
58547
+ if (document && typeof document === "object" && "paths" in document)
58548
+ return document;
58549
+ }
58550
+ return void 0;
58551
+ }
58552
+ var TOKEN_FIELD, MAX_DEPTH, MAX_TOKEN_CHARS, OPENAPI_PATHS, storePath, followUpKey;
58553
+ var init_follow_ups = __esm({
58554
+ "../../packages/economy/dist/follow-ups.js"() {
58555
+ "use strict";
58556
+ TOKEN_FIELD = /^(unlock|re-?read|access|entitlement)[_-]?token$/i;
58557
+ MAX_DEPTH = 4;
58558
+ MAX_TOKEN_CHARS = 4096;
58559
+ OPENAPI_PATHS = ["/openapi.json", "/.well-known/openapi.json"];
58560
+ storePath = (session) => join10(session.sessionDir, "follow-up-credentials.json");
58561
+ followUpKey = (method, url3) => `${method.toUpperCase()} ${url3}`;
58562
+ }
58563
+ });
58564
+
58480
58565
  // ../../packages/economy/dist/crowdcode-preferences.js
58481
- import { mkdir as mkdir8, readFile as readFile8, rename as rename2, writeFile as writeFile4 } from "node:fs/promises";
58482
- import { dirname as dirname8, join as join10 } from "node:path";
58566
+ import { mkdir as mkdir8, readFile as readFile9, rename as rename2, writeFile as writeFile5 } from "node:fs/promises";
58567
+ import { dirname as dirname8, join as join11 } from "node:path";
58483
58568
  import { randomUUID as randomUUID4 } from "node:crypto";
58484
58569
  var CrowdCodePreferences;
58485
58570
  var init_crowdcode_preferences = __esm({
@@ -58491,11 +58576,11 @@ var init_crowdcode_preferences = __esm({
58491
58576
  this.session = session;
58492
58577
  }
58493
58578
  path(scope) {
58494
- return join10(scope === "session" ? this.session.sessionDir : this.session.workspaceRoot, "crowdcode-preferences.json");
58579
+ return join11(scope === "session" ? this.session.sessionDir : this.session.workspaceRoot, "crowdcode-preferences.json");
58495
58580
  }
58496
58581
  async read(scope) {
58497
58582
  try {
58498
- const value = JSON.parse(await readFile8(this.path(scope), "utf8"));
58583
+ const value = JSON.parse(await readFile9(this.path(scope), "utf8"));
58499
58584
  return typeof value.enabled === "boolean" ? value.enabled : void 0;
58500
58585
  } catch (error53) {
58501
58586
  if (error53.code === "ENOENT")
@@ -58511,7 +58596,7 @@ var init_crowdcode_preferences = __esm({
58511
58596
  async write(scope, enabled) {
58512
58597
  const path3 = this.path(scope), temporary = `${path3}.${randomUUID4()}.tmp`;
58513
58598
  await mkdir8(dirname8(path3), { recursive: true });
58514
- await writeFile4(temporary, JSON.stringify({ enabled }) + "\n", { mode: 384 });
58599
+ await writeFile5(temporary, JSON.stringify({ enabled }) + "\n", { mode: 384 });
58515
58600
  await rename2(temporary, path3);
58516
58601
  }
58517
58602
  async set(enabled, scope) {
@@ -58635,11 +58720,11 @@ var init_media = __esm({
58635
58720
  });
58636
58721
 
58637
58722
  // ../../packages/economy/dist/purchases.js
58638
- import { appendFile as appendFile3, mkdir as mkdir9, readFile as readFile9 } from "node:fs/promises";
58639
- import { dirname as dirname9, join as join11 } from "node:path";
58723
+ import { appendFile as appendFile3, mkdir as mkdir9, readFile as readFile10 } from "node:fs/promises";
58724
+ import { dirname as dirname9, join as join12 } from "node:path";
58640
58725
  import { randomUUID as randomUUID5 } from "node:crypto";
58641
58726
  function purchasesPath(session) {
58642
- return join11(session.sessionDir, "purchases.jsonl");
58727
+ return join12(session.sessionDir, "purchases.jsonl");
58643
58728
  }
58644
58729
  function newPurchaseId() {
58645
58730
  return `pur_${randomUUID5().slice(0, 12)}`;
@@ -58676,7 +58761,7 @@ async function appendPurchaseEvent(session, event) {
58676
58761
  async function listPurchases(session) {
58677
58762
  let text;
58678
58763
  try {
58679
- text = await readFile9(purchasesPath(session), "utf8");
58764
+ text = await readFile10(purchasesPath(session), "utf8");
58680
58765
  } catch (error53) {
58681
58766
  if (error53.code === "ENOENT") {
58682
58767
  return [];
@@ -58745,8 +58830,8 @@ var init_purchases = __esm({
58745
58830
  });
58746
58831
 
58747
58832
  // ../../packages/economy/dist/gateway.js
58748
- import { readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
58749
- import { join as join12 } from "node:path";
58833
+ import { readFile as readFile11, writeFile as writeFile6 } from "node:fs/promises";
58834
+ import { join as join13 } from "node:path";
58750
58835
  async function boundResponse(session, data) {
58751
58836
  return capStrings(await extractMedia(session, data), MAX_EXTERNAL_STRING_CHARS);
58752
58837
  }
@@ -58847,6 +58932,7 @@ var init_gateway = __esm({
58847
58932
  init_dist();
58848
58933
  init_dist2();
58849
58934
  init_offers();
58935
+ init_follow_ups();
58850
58936
  init_approvals();
58851
58937
  init_purchases();
58852
58938
  GATEWAY_TOOL_NAMES = [
@@ -58878,14 +58964,14 @@ var init_gateway = __esm({
58878
58964
  this.options = options;
58879
58965
  }
58880
58966
  get inspectionsPath() {
58881
- return join12(this.options.session.sessionDir, "inspections.json");
58967
+ return join13(this.options.session.sessionDir, "inspections.json");
58882
58968
  }
58883
58969
  async loadInspections() {
58884
58970
  if (this.inspections)
58885
58971
  return this.inspections;
58886
58972
  const map3 = /* @__PURE__ */ new Map();
58887
58973
  try {
58888
- const stored = JSON.parse(await readFile10(this.inspectionsPath, "utf8"));
58974
+ const stored = JSON.parse(await readFile11(this.inspectionsPath, "utf8"));
58889
58975
  for (const [key, value] of Object.entries(stored))
58890
58976
  map3.set(key, value);
58891
58977
  } catch {
@@ -58896,7 +58982,7 @@ var init_gateway = __esm({
58896
58982
  async rememberInspection(key, inspection) {
58897
58983
  const map3 = await this.loadInspections();
58898
58984
  map3.set(key, inspection);
58899
- await writeFile5(this.inspectionsPath, JSON.stringify(Object.fromEntries(map3)), "utf8");
58985
+ await writeFile6(this.inspectionsPath, JSON.stringify(Object.fromEntries(map3)), "utf8");
58900
58986
  }
58901
58987
  definitions() {
58902
58988
  return GATEWAY_TOOL_DEFINITIONS;
@@ -58997,8 +59083,8 @@ var init_gateway = __esm({
58997
59083
  }
58998
59084
  if (query) {
58999
59085
  const findServices = this.options.crowdcode.findServices?.bind(this.options.crowdcode);
59000
- const rank = findServices && await this.crowdcodeEnabled().catch(() => false) ? findServices : void 0;
59001
- const result = await this.options.agentcash.search(query, { limit: intArg(args.limit), ...rank ? { rank } : {} });
59086
+ const rank2 = findServices && await this.crowdcodeEnabled().catch(() => false) ? findServices : void 0;
59087
+ const result = await this.options.agentcash.search(query, { limit: intArg(args.limit), ...rank2 ? { rank: rank2 } : {} });
59002
59088
  return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
59003
59089
  }
59004
59090
  return { ok: false, error: "find_paid_service requires `origin` (known origin) or `query` (capability search)" };
@@ -59019,7 +59105,8 @@ var init_gateway = __esm({
59019
59105
  }
59020
59106
  const evidence = await this.serviceEvidence(endpoint);
59021
59107
  const rail = railFromSchema(schema.data);
59022
- const priceCeilingCents = priceCeilingFromSchema(schema.data);
59108
+ const free = schema.data?.free === true;
59109
+ const priceCeilingCents = free ? 0 : priceCeilingFromSchema(schema.data);
59023
59110
  const payTo = schema.data && typeof schema.data === "object" && typeof schema.data.pay_to === "string" ? schema.data.pay_to : void 0;
59024
59111
  await this.rememberInspection(inspectionKey(endpoint, method), {
59025
59112
  endpoint,
@@ -59037,6 +59124,8 @@ var init_gateway = __esm({
59037
59124
  method,
59038
59125
  rail,
59039
59126
  price_ceiling_cents: priceCeilingCents,
59127
+ // A free, signed call is the one thing never to move funds for; say it first.
59128
+ ...free ? { free: true, note: schema.data.note } : {},
59040
59129
  schema: schema.data,
59041
59130
  reputation: evidence.ok ? {
59042
59131
  score: evidence.score,
@@ -59080,6 +59169,9 @@ var init_gateway = __esm({
59080
59169
  error: `this endpoint offers no payment rail this agent can pay automatically (payable: ${describeRails(rails)})`
59081
59170
  };
59082
59171
  }
59172
+ const reread = await this.followUpRead(target, method, body);
59173
+ if (reread)
59174
+ return reread;
59083
59175
  const requestedCostCents = intArg(args.max_cost_cents) ?? inspection.priceCeilingCents;
59084
59176
  let quotedCostCents = requestedCostCents;
59085
59177
  let quoteIdentity;
@@ -59200,6 +59292,7 @@ var init_gateway = __esm({
59200
59292
  ].join(" ")
59201
59293
  };
59202
59294
  }
59295
+ const followUp = result.ok && paid ? await this.keepFollowUp(target, method, result.data, purchaseId) : void 0;
59203
59296
  return {
59204
59297
  ok: result.ok,
59205
59298
  data: {
@@ -59211,12 +59304,84 @@ var init_gateway = __esm({
59211
59304
  review_required: record3.review_required,
59212
59305
  review_available: true,
59213
59306
  ...result.note ? { note: result.note } : {},
59307
+ ...followUp ? { follow_up: followUp } : {},
59214
59308
  data: result.data,
59215
59309
  ...result.ok ? {} : { error: result.error }
59216
59310
  },
59217
59311
  ...result.ok ? {} : { error: result.error }
59218
59312
  };
59219
59313
  }
59314
+ /**
59315
+ * Keep a follow-up token a paid answer carried, with the request header its
59316
+ * seller documents for it, and tell the model what it is for.
59317
+ */
59318
+ async keepFollowUp(url3, method, data, purchaseId) {
59319
+ const tokens2 = findFollowUpTokens(data);
59320
+ if (!tokens2.length)
59321
+ return void 0;
59322
+ const fetchFree = this.options.agentcash.fetchFree?.bind(this.options.agentcash);
59323
+ const openapi = fetchFree ? await sellerOpenApi(originOf2(url3), async (address2) => {
59324
+ const response = await fetchFree({ url: address2, method: "GET" });
59325
+ return response.ok ? response.data : void 0;
59326
+ }).catch(() => void 0) : void 0;
59327
+ for (const token of tokens2) {
59328
+ const header = openapi ? documentedHeader(openapi, url3, method, token.field) : void 0;
59329
+ if (!header)
59330
+ continue;
59331
+ await saveFollowUp(this.options.session, followUpKey(method, url3), { header, value: token.value, field: token.field, purchaseId, savedAt: (/* @__PURE__ */ new Date()).toISOString() });
59332
+ return {
59333
+ header,
59334
+ token_field: token.field,
59335
+ saved: true,
59336
+ note: `The seller issued a follow-up token (${token.field}) and documents the ${header} request header for it. It is saved: calling this same URL again with call_paid_service sends ${header} automatically, and a seller that honours it answers without charging.`
59337
+ };
59338
+ }
59339
+ return {
59340
+ token_field: tokens2[0].field,
59341
+ saved: false,
59342
+ note: `This answer carries a follow-up token (${tokens2[0].field}), but the seller's OpenAPI names no request header for it. Check the seller's documentation before paying for the same request again.`
59343
+ };
59344
+ }
59345
+ /** The same request again with a saved follow-up token, unpaid. */
59346
+ async followUpRead(url3, method, body) {
59347
+ const fetchFree = this.options.agentcash.fetchFree?.bind(this.options.agentcash);
59348
+ if (!fetchFree)
59349
+ return void 0;
59350
+ const credential = (await loadFollowUps(this.options.session))[followUpKey(method, url3)];
59351
+ if (!credential)
59352
+ return void 0;
59353
+ const result = await fetchFree({
59354
+ url: url3,
59355
+ method,
59356
+ body: typeof body === "string" ? body : body === void 0 ? void 0 : JSON.stringify(body),
59357
+ headers: { [credential.header]: credential.value }
59358
+ }).catch(() => void 0);
59359
+ if (!result?.ok || result.status === 402 || result.data === void 0)
59360
+ return void 0;
59361
+ const data = await boundResponse(this.options.session, result.data);
59362
+ const artifact = await saveArtifact(this.options.session, `service-calls/${Date.now()}-${slugUrl(url3)}.json`, JSON.stringify({ status: result.status, body: data }, null, 2), { endpoint: url3, method });
59363
+ await appendLedgerEntry(this.options.session.ledgerPath, {
59364
+ session_id: this.options.session.sessionId,
59365
+ type: "service_call",
59366
+ resource_url: url3,
59367
+ method,
59368
+ quoted_cost_cents: 0,
59369
+ charged_cost_cents: 0,
59370
+ status: "ok",
59371
+ approval_mode: this.options.session.approvalMode,
59372
+ artifact_path: artifact?.path,
59373
+ notes: `free follow-up with ${credential.header} from purchase ${credential.purchaseId ?? "?"}`
59374
+ });
59375
+ return { ok: true, data: {
59376
+ outcome: "free",
59377
+ status: result.status,
59378
+ charged_cost_cents: 0,
59379
+ artifact_path: artifact?.path,
59380
+ review_required: false,
59381
+ note: `Free re-read: sent the ${credential.header} token this seller issued with your earlier purchase${credential.purchaseId ? ` ${credential.purchaseId}` : ""}; nothing was paid. This is the same content that purchase bought.`,
59382
+ data
59383
+ } };
59384
+ }
59220
59385
  async resolveApproval(endpoint, method, quotedCostCents, evidence) {
59221
59386
  const origin = originOf2(endpoint);
59222
59387
  const rules = await loadApprovalRules(this.options.approvalRulesPath);
@@ -59771,6 +59936,7 @@ var init_dist4 = __esm({
59771
59936
  init_agentcash2();
59772
59937
  init_approvals();
59773
59938
  init_crowdcode();
59939
+ init_follow_ups();
59774
59940
  init_gateway();
59775
59941
  init_mcp();
59776
59942
  init_media();
@@ -59785,7 +59951,7 @@ var init_dist4 = __esm({
59785
59951
 
59786
59952
  // ../../packages/agent-runtime/dist/context.js
59787
59953
  import { createHash as createHash3 } from "node:crypto";
59788
- import { relative as relative3, join as join13 } from "node:path";
59954
+ import { relative as relative3, join as join14 } from "node:path";
59789
59955
  function requestMessages(messages, state) {
59790
59956
  if (state.trailingMessage)
59791
59957
  return [...messages, state.trailingMessage];
@@ -59897,14 +60063,14 @@ async function compactContext(session, messages, options) {
59897
60063
  return { tokensBefore, tokensAfter: tokensBefore };
59898
60064
  const raw = messages.map((message) => JSON.stringify(message)).join("\n") + "\n";
59899
60065
  const digest = createHash3("sha256").update(raw).digest("hex");
59900
- const dir = await containedPath(session.sessionDir, join13("context", digest));
59901
- const path3 = join13(dir, "transcript.jsonl");
60066
+ const dir = await containedPath(session.sessionDir, join14("context", digest));
60067
+ const path3 = join14(dir, "transcript.jsonl");
59902
60068
  await atomicWrite(path3, raw);
59903
60069
  const archivePath = relative3(session.sessionDir, path3).split("\\").join("/");
59904
60070
  const ref = (index2) => `${relative3(session.sessionDir, dir).split("\\").join("/")}/message-${index2 + 1}.txt`;
59905
60071
  const saved = /* @__PURE__ */ new Set();
59906
60072
  const externalize = async (message, index2) => {
59907
- await atomicWrite(join13(dir, `message-${index2 + 1}.txt`), messages[index2].content);
60073
+ await atomicWrite(join14(dir, `message-${index2 + 1}.txt`), messages[index2].content);
59908
60074
  saved.add(index2);
59909
60075
  const preview = message.role === "user" ? ` It began: "${oneLine(messages[index2].content, EXTERNALIZE_PREVIEW_CHARS)}"` : "";
59910
60076
  return `[Full ${message.role} message saved verbatim to ${ref(index2)}. Use rg/grep and sed/head/tail to read relevant portions before proceeding; do not load the entire file.${preview}]`;
@@ -60029,8 +60195,8 @@ var init_context2 = __esm({
60029
60195
  });
60030
60196
 
60031
60197
  // ../../packages/agent-runtime/dist/knowledge.js
60032
- import { access, cp, mkdir as mkdir10, readFile as readFile11, writeFile as writeFile6 } from "node:fs/promises";
60033
- import { dirname as dirname10, join as join14, resolve as resolve4 } from "node:path";
60198
+ import { access, cp, mkdir as mkdir10, readFile as readFile12, writeFile as writeFile7 } from "node:fs/promises";
60199
+ import { dirname as dirname10, join as join15, resolve as resolve4 } from "node:path";
60034
60200
  import { fileURLToPath } from "node:url";
60035
60201
  function bundledKnowledgeDir() {
60036
60202
  return resolve4(dirname10(fileURLToPath(import.meta.url)), "..", "knowledge");
@@ -60049,7 +60215,7 @@ async function resolveKnowledgeDir(options = {}) {
60049
60215
  }
60050
60216
  const bundled = bundledKnowledgeDir();
60051
60217
  try {
60052
- await access(join14(bundled, "L0.md"));
60218
+ await access(join15(bundled, "L0.md"));
60053
60219
  return bundled;
60054
60220
  } catch {
60055
60221
  return void 0;
@@ -60062,12 +60228,12 @@ async function loadKnowledgeTree(session, options = {}) {
60062
60228
  }
60063
60229
  let l0;
60064
60230
  try {
60065
- l0 = (await readFile11(join14(dir, "L0.md"), "utf8")).trim();
60231
+ l0 = (await readFile12(join15(dir, "L0.md"), "utf8")).trim();
60066
60232
  } catch {
60067
60233
  return void 0;
60068
60234
  }
60069
60235
  const version6 = await readVersion(dir, l0);
60070
- const target = join14(session.artifactsDir, "knowledge");
60236
+ const target = join15(session.artifactsDir, "knowledge");
60071
60237
  if (await currentVersion(target) !== version6) {
60072
60238
  await mkdir10(session.artifactsDir, { recursive: true });
60073
60239
  await cp(dir, target, {
@@ -60075,7 +60241,7 @@ async function loadKnowledgeTree(session, options = {}) {
60075
60241
  force: true,
60076
60242
  filter: (source) => !source.endsWith("proposal.raw.txt")
60077
60243
  });
60078
- await writeFile6(join14(target, VERSION_FILE), `${version6}
60244
+ await writeFile7(join15(target, VERSION_FILE), `${version6}
60079
60245
  `, "utf8");
60080
60246
  }
60081
60247
  if (session.knowledge?.version !== version6 || session.knowledge?.source !== dir) {
@@ -60093,7 +60259,7 @@ function renderCapabilityIndex(l0) {
60093
60259
  }
60094
60260
  async function readVersion(dir, l0) {
60095
60261
  try {
60096
- const meta4 = JSON.parse(await readFile11(join14(dir, "meta.json"), "utf8"));
60262
+ const meta4 = JSON.parse(await readFile12(join15(dir, "meta.json"), "utf8"));
60097
60263
  if (typeof meta4.content_hash === "string" && meta4.content_hash) {
60098
60264
  return meta4.id ? `${meta4.id}@${meta4.content_hash}` : meta4.content_hash;
60099
60265
  }
@@ -60104,7 +60270,7 @@ async function readVersion(dir, l0) {
60104
60270
  }
60105
60271
  async function currentVersion(target) {
60106
60272
  try {
60107
- return (await readFile11(join14(target, VERSION_FILE), "utf8")).trim();
60273
+ return (await readFile12(join15(target, VERSION_FILE), "utf8")).trim();
60108
60274
  } catch {
60109
60275
  return void 0;
60110
60276
  }
@@ -87223,8 +87389,8 @@ var init_economy_tools = __esm({
87223
87389
  });
87224
87390
 
87225
87391
  // ../../packages/agent-runtime/dist/runtime.js
87226
- import { readFile as readFile12, rm as rm2 } from "node:fs/promises";
87227
- import { join as join19 } from "node:path";
87392
+ import { readFile as readFile13, rm as rm2 } from "node:fs/promises";
87393
+ import { join as join20 } from "node:path";
87228
87394
  import { randomUUID as randomUUID6 } from "node:crypto";
87229
87395
  function createOpenCrowdRuntime(options) {
87230
87396
  const storage = options.storage ?? localRuntimeStorage;
@@ -87257,10 +87423,10 @@ function createOpenCrowdRuntime(options) {
87257
87423
  };
87258
87424
  }
87259
87425
  async function execute2(session, task, runOptions = {}) {
87260
- const path3 = join19(session.sessionDir, "query-checkpoint.json");
87426
+ const path3 = join20(session.sessionDir, "query-checkpoint.json");
87261
87427
  let persisted;
87262
87428
  try {
87263
- persisted = JSON.parse(await readFile12(path3, "utf8"));
87429
+ persisted = JSON.parse(await readFile13(path3, "utf8"));
87264
87430
  } catch (error53) {
87265
87431
  if (error53.code !== "ENOENT")
87266
87432
  throw error53;
@@ -87545,9 +87711,180 @@ var init_hosted_provider = __esm({
87545
87711
  }
87546
87712
  });
87547
87713
 
87714
+ // ../../packages/agent-runtime/dist/funding-plan.js
87715
+ function spendable(funds) {
87716
+ return Math.max(0, funds.availableUsd - (funds.keepUsd ?? 0));
87717
+ }
87718
+ function simulate(calls, start) {
87719
+ const left = new Map(start);
87720
+ const assigned = [];
87721
+ for (const call2 of calls) {
87722
+ const free = call2.offers.find((offer) => offer.free);
87723
+ if (free) {
87724
+ assigned.push({ url: call2.url, method: call2.method, count: call2.count, network: free.network, priceUsd: 0, totalUsd: 0, free: true });
87725
+ continue;
87726
+ }
87727
+ if (!call2.offers.length) {
87728
+ assigned.push({ url: call2.url, method: call2.method, count: call2.count, totalUsd: 0, unpaid: true, error: call2.error ?? "no payable offer" });
87729
+ continue;
87730
+ }
87731
+ for (let i = 0; i < call2.count; i++) {
87732
+ const offer = [...call2.offers].filter((candidate) => (left.get(candidate.network) ?? 0) + 1e-9 >= candidate.priceUsd).sort((a, b) => a.priceUsd - b.priceUsd || rank(a.network) - rank(b.network))[0];
87733
+ const previous = assigned[assigned.length - 1];
87734
+ const sameAsPrevious = i > 0 && previous && previous.network === offer?.network && !previous.unpaid;
87735
+ if (offer)
87736
+ left.set(offer.network, (left.get(offer.network) ?? 0) - offer.priceUsd);
87737
+ if (sameAsPrevious) {
87738
+ previous.count += 1;
87739
+ previous.totalUsd = cents(previous.totalUsd + offer.priceUsd);
87740
+ continue;
87741
+ }
87742
+ const cheapest = [...call2.offers].sort((a, b) => a.priceUsd - b.priceUsd || rank(a.network) - rank(b.network))[0];
87743
+ assigned.push(offer ? { url: call2.url, method: call2.method, count: 1, network: offer.network, priceUsd: offer.priceUsd, totalUsd: offer.priceUsd } : { url: call2.url, method: call2.method, count: 1, priceUsd: cheapest.priceUsd, totalUsd: cheapest.priceUsd, unpaid: true });
87744
+ }
87745
+ }
87746
+ const merged = [];
87747
+ for (const call2 of assigned) {
87748
+ const last = merged[merged.length - 1];
87749
+ if (last && last.unpaid && call2.unpaid && last.url === call2.url && last.method === call2.method && !last.error && !call2.error) {
87750
+ last.count += call2.count;
87751
+ last.totalUsd = cents(last.totalUsd + call2.totalUsd);
87752
+ } else
87753
+ merged.push({ ...call2 });
87754
+ }
87755
+ return { calls: merged, left, unpaid: merged.some((call2) => call2.unpaid && !call2.error) };
87756
+ }
87757
+ function planTaskFunding(calls, funds) {
87758
+ const start = new Map(funds.map((entry) => [entry.network, headroom(entry)]));
87759
+ const report = (planned, moves, outcome, short) => ({
87760
+ outcome,
87761
+ calls: planned.calls,
87762
+ moves,
87763
+ ...short ? { short } : {},
87764
+ networks: funds.map((entry) => {
87765
+ const moved = moves.reduce((sum, move) => sum + (move.to === entry.network ? move.amountUsd - PLAN_FEE_ALLOWANCE_USD : 0) - (move.from === entry.network ? move.amountUsd : 0), 0);
87766
+ const plannedUsd = planned.calls.filter((call2) => call2.network === entry.network && !call2.unpaid).reduce((sum, call2) => sum + call2.totalUsd, 0);
87767
+ return {
87768
+ network: entry.network,
87769
+ availableUsd: cents(entry.availableUsd),
87770
+ hostingOwedUsd: cents(entry.hostingOwedUsd ?? 0),
87771
+ keepUsd: cents(entry.keepUsd ?? 0),
87772
+ spendableUsd: cents(spendable(entry)),
87773
+ plannedUsd: cents(plannedUsd),
87774
+ afterUsd: cents(headroom(entry) + moved - plannedUsd)
87775
+ };
87776
+ })
87777
+ });
87778
+ const now = simulate(calls, start);
87779
+ if (!now.unpaid)
87780
+ return report(now, [], "no_move");
87781
+ const targets = [...new Set(now.calls.filter((call2) => call2.unpaid && !call2.error).flatMap((call2) => calls.find((c) => c.url === call2.url && c.method === call2.method)?.offers.map((offer) => offer.network) ?? []))];
87782
+ let best;
87783
+ let closest;
87784
+ for (const target of targets.sort((a, b) => rank(a) - rank(b))) {
87785
+ const unlimited = simulate(calls, new Map([...start, [target, Number.MAX_SAFE_INTEGER]]));
87786
+ if (unlimited.unpaid)
87787
+ continue;
87788
+ const used = /* @__PURE__ */ new Map();
87789
+ for (const call2 of unlimited.calls)
87790
+ if (call2.network && !call2.unpaid)
87791
+ used.set(call2.network, (used.get(call2.network) ?? 0) + call2.totalUsd);
87792
+ const arrive = Math.max(0, (used.get(target) ?? 0) - (start.get(target) ?? 0));
87793
+ const amountUsd = up(arrive + PLAN_FEE_ALLOWANCE_USD);
87794
+ const sources = funds.filter((entry) => entry.network !== target).map((entry) => ({ network: entry.network, spare: (start.get(entry.network) ?? 0) - (used.get(entry.network) ?? 0) })).sort((a, b) => b.spare - a.spare);
87795
+ const source = sources[0];
87796
+ const gap = source ? amountUsd - source.spare : amountUsd;
87797
+ if (!closest || gap < closest.amountUsd)
87798
+ closest = { network: target, amountUsd: up(Math.max(0, gap)) };
87799
+ if (!source || source.spare + 1e-9 < amountUsd)
87800
+ continue;
87801
+ const move = { from: source.network, to: target, amountUsd };
87802
+ const after = simulate(calls, new Map([...start, [target, (start.get(target) ?? 0) + arrive], [source.network, (start.get(source.network) ?? 0) - amountUsd]]));
87803
+ if (after.unpaid)
87804
+ continue;
87805
+ if (!best || amountUsd < best.move.amountUsd)
87806
+ best = { move, planned: after };
87807
+ }
87808
+ if (best)
87809
+ return report(best.planned, [best.move], "one_move");
87810
+ const direct = targets.map((network) => {
87811
+ const unlimited = simulate(calls, new Map([...start, [network, Number.MAX_SAFE_INTEGER]]));
87812
+ const used = unlimited.calls.filter((call2) => call2.network === network && !call2.unpaid).reduce((sum, call2) => sum + call2.totalUsd, 0);
87813
+ return { network, amountUsd: up(Math.max(0, used - (start.get(network) ?? 0))) };
87814
+ }).sort((a, b) => a.amountUsd - b.amountUsd || rank(a.network) - rank(b.network))[0];
87815
+ return report(now, [], "short", direct ?? closest);
87816
+ }
87817
+ function describePlan(plan) {
87818
+ const money = (usd3) => `$${usd3.toFixed(2)}`;
87819
+ const steps = plan.calls.map((call2) => call2.free ? `${call2.method} ${call2.url}: free (a signed wallet-identity proof on ${call2.network}; nothing moves, no balance needed)` : call2.error ? `${call2.method} ${call2.url}: ${call2.error}` : call2.unpaid ? `${call2.count}\xD7 ${call2.method} ${call2.url}: not payable with these funds (${money(call2.totalUsd)})` : `${call2.count}\xD7 ${call2.method} ${call2.url}: pays ${money(call2.totalUsd)} on ${call2.network}`);
87820
+ const move = plan.moves[0];
87821
+ const instruction = plan.outcome === "no_move" ? "No move is needed: every planned call is payable where the funds already are. Do not call bridge_usdc for this task." : plan.outcome === "one_move" ? `Make exactly this one move, once, before the first purchase: bridge_usdc {"from":"${move.from}","to":"${move.to}","amount_usd":${move.amountUsd}} (about $0.03 of it is the fee). Then make the calls; do not move funds again, and never back the other way, in this run.` : `These funds cannot pay for the whole task with one move. Do the part that is payable without any move if it is worth doing alone, and tell the owner the exact gap: add ${money(plan.short?.amountUsd ?? 0)} on ${plan.short?.network ?? "the network the service is sold on"}. Do not move funds back and forth to make up the difference.`;
87822
+ return {
87823
+ outcome: plan.outcome,
87824
+ steps,
87825
+ moves: plan.moves.map((m) => ({ from: m.from, to: m.to, amount_usd: m.amountUsd })),
87826
+ ...plan.short ? { short: { network: plan.short.network, amount_usd: plan.short.amountUsd } } : {},
87827
+ networks: plan.networks.map((n) => ({
87828
+ network: n.network,
87829
+ available_usd: n.availableUsd,
87830
+ hosting_owed_usd: n.hostingOwedUsd,
87831
+ kept_usd: n.keepUsd,
87832
+ spendable_usd: n.spendableUsd,
87833
+ planned_usd: n.plannedUsd,
87834
+ left_after_usd: n.afterUsd
87835
+ })),
87836
+ instruction,
87837
+ note: `spendable = available (balance less payment holds and, on Base, hosting owed) less what is kept: the $${HOSTING_RESERVE_USD.toFixed(2)} hosting reserve, and $${PLAN_INFERENCE_ALLOWANCE_USD.toFixed(2)} on Base for this run's own model calls.`
87838
+ };
87839
+ }
87840
+ var GATEWAY_PREFERENCE, PLAN_FEE_ALLOWANCE_USD, PLAN_INFERENCE_ALLOWANCE_USD, HOSTING_RESERVE_USD, cents, up, rank, headroom, PLAN_FUNDING_TOOL;
87841
+ var init_funding_plan = __esm({
87842
+ "../../packages/agent-runtime/dist/funding-plan.js"() {
87843
+ "use strict";
87844
+ GATEWAY_PREFERENCE = ["base", "solana", "tempo"];
87845
+ PLAN_FEE_ALLOWANCE_USD = 0.05;
87846
+ PLAN_INFERENCE_ALLOWANCE_USD = 0.25;
87847
+ HOSTING_RESERVE_USD = 0.1;
87848
+ cents = (usd3) => Math.round(usd3 * 100) / 100;
87849
+ up = (usd3) => Math.ceil(usd3 * 100 - 1e-9) / 100;
87850
+ rank = (network) => {
87851
+ const index2 = GATEWAY_PREFERENCE.indexOf(network);
87852
+ return index2 < 0 ? GATEWAY_PREFERENCE.length : index2;
87853
+ };
87854
+ headroom = (funds) => funds.availableUsd - (funds.keepUsd ?? 0);
87855
+ PLAN_FUNDING_TOOL = {
87856
+ name: "plan_funding",
87857
+ description: "Plan a task's funding once, before its first purchase, whenever the task will make more than one paid call or a call on a network you hold little on. List every call you intend to make (url, method, how many times). It reads every network and protocol each endpoint accepts \u2014 including free calls that only need a signed wallet-identity proof \u2014 and what each of your networks can really spend (balance less holds, hosting owed, the hosting reserve and an allowance for your own model calls), then says which network will pay each call and the at most one bridge_usdc move the task needs, sized to it. Read-only: nothing is paid or moved.",
87858
+ parameters: {
87859
+ type: "object",
87860
+ properties: {
87861
+ calls: {
87862
+ type: "array",
87863
+ minItems: 1,
87864
+ maxItems: 12,
87865
+ items: {
87866
+ type: "object",
87867
+ properties: {
87868
+ url: { type: "string", description: "Exact endpoint URL, as you will call it" },
87869
+ method: { type: "string", enum: ["GET", "POST"] },
87870
+ count: { type: "integer", minimum: 1, maximum: 20, description: "How many times you will call it (default 1)" },
87871
+ sample_body: { type: "object", description: "For POST: a representative body, for the exact quote" }
87872
+ },
87873
+ required: ["url"],
87874
+ additionalProperties: false
87875
+ }
87876
+ }
87877
+ },
87878
+ required: ["calls"],
87879
+ additionalProperties: false
87880
+ }
87881
+ };
87882
+ }
87883
+ });
87884
+
87548
87885
  // ../../packages/agent-runtime/dist/hosted-economy.js
87549
87886
  import { randomUUID as randomUUID7, createHash as createHash4 } from "node:crypto";
87550
- import { join as join20 } from "node:path";
87887
+ import { join as join21 } from "node:path";
87551
87888
  function describeTransferError(reply) {
87552
87889
  return reply.code ? `${reply.error ?? "transfer refused"} (${reply.code})` : reply.error ?? "transfer refused";
87553
87890
  }
@@ -87573,31 +87910,53 @@ function createHostedEconomy(options) {
87573
87910
  const fetcher = options.fetcher ?? fetch;
87574
87911
  const socket = { socketPath: options.socketPath, runId: options.runId, sessionId: options.sessionId };
87575
87912
  const directory = new ServiceDirectory(fetcher, (options.crowdcodeBase ?? DEFAULT_CROWDCODE_BASE).replace(/\/+$/, ""));
87576
- return new EconomyGateway({
87913
+ const agentcash = new HostedAgentCashAdapter(directory, socket, fetcher, options.reconcileDelayMs, options.transferWait);
87914
+ const gateway = new EconomyGateway({
87577
87915
  session: options.session,
87578
- agentcash: new HostedAgentCashAdapter(directory, socket, fetcher, options.reconcileDelayMs, options.transferWait),
87916
+ agentcash,
87579
87917
  crowdcode: new HostedCrowdCodeAdapter(directory, socket),
87580
87918
  approvalMode: "auto",
87581
87919
  hostedSpending: true,
87582
87920
  minServiceScore: 2,
87583
87921
  paymentRails: HOSTED_RAILS,
87584
87922
  // Hosted rules live with the agent's session, never in a user config dir.
87585
- approvalRulesPath: join20(options.session.sessionDir, "approval-rules.json")
87923
+ approvalRulesPath: join21(options.session.sessionDir, "approval-rules.json")
87586
87924
  });
87925
+ return Object.assign(gateway, { planFunding: (args) => agentcash.planFunding(args) });
87587
87926
  }
87588
87927
  function hostedDynamicTools(economy) {
87589
87928
  const tools = economyTools(economy);
87590
- return { ...tools, definitions: tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet: the total across networks, each network's balance (Base, Solana, Tempo), and authoritative current-run inference spending, service spending, transfer fees, payment holds and authorized budget. A payment on a network needs that network's balance. Read-only." } : tool.name === "bridge_usdc" ? HOSTED_BRIDGE_TOOL : tool) };
87929
+ const plan = economy.planFunding;
87930
+ const definitions = tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet: the total across networks, each network's balance (Base, Solana, Tempo), what each can spend after payment holds and (on Base) hosting owed, and authoritative current-run inference spending, service spending, transfer fees, payment holds and authorized budget. A payment on a network needs that network's spendable balance. Read-only." } : tool.name === "bridge_usdc" ? HOSTED_BRIDGE_TOOL : tool);
87931
+ return {
87932
+ ...tools,
87933
+ definitions: plan ? [...definitions, PLAN_FUNDING_TOOL] : definitions,
87934
+ execute: async (name, args, operationId) => name === "plan_funding" && plan ? plan(args) : tools.execute(name, args, operationId)
87935
+ };
87936
+ }
87937
+ function walletFunds(data) {
87938
+ const wallet = objectValue5(data);
87939
+ const networks = Array.isArray(wallet?.networks) ? wallet.networks : [];
87940
+ const owed = numberValue6(wallet?.hosting_owed_usd) ?? 0;
87941
+ const reserve = numberValue6(wallet?.hosting_reserve_usd) ?? HOSTING_RESERVE_USD;
87942
+ return networks.map(objectValue5).flatMap((row) => {
87943
+ const network = networkName(row?.network) ?? networkName(row?.caip2) ?? stringValue5(row?.network);
87944
+ const available = numberValue6(row?.available_usd ?? row?.balance_usd);
87945
+ if (!network || available === void 0)
87946
+ return [];
87947
+ const base2 = network === "base";
87948
+ return [{ network, availableUsd: available, hostingOwedUsd: base2 ? numberValue6(row?.hosting_owed_usd) ?? owed : 0, keepUsd: base2 ? reserve + PLAN_INFERENCE_ALLOWANCE_USD : 0 }];
87949
+ });
87591
87950
  }
87592
87951
  function planFundingMove(target, priceUsd, available) {
87593
- const cents = (usd3) => Math.floor(usd3 * 100) / 100;
87952
+ const cents2 = (usd3) => Math.floor(usd3 * 100) / 100;
87594
87953
  const needed = Math.ceil((priceUsd + MOVE_FEE_ALLOWANCE_USD) * 100) / 100;
87595
87954
  const source = available.filter((n) => n.network !== target).sort((a, b) => b.usd - a.usd)[0];
87596
87955
  if (!source)
87597
87956
  return void 0;
87598
87957
  const reserve = source.network === "base" ? BASE_WORKING_RESERVE_USD : 0;
87599
- const spare = cents(Math.max(0, source.usd - reserve));
87600
- const ceiling = Math.min(Math.max(needed, spare), cents(source.usd));
87958
+ const spare = cents2(Math.max(0, source.usd - reserve));
87959
+ const ceiling = Math.min(Math.max(needed, spare), cents2(source.usd));
87601
87960
  const amount = Math.min(Math.max(PREFERRED_MOVE_USD, needed), ceiling);
87602
87961
  if (amount < needed)
87603
87962
  return void 0;
@@ -87676,6 +88035,7 @@ var init_hosted_economy = __esm({
87676
88035
  init_dist4();
87677
88036
  init_dist();
87678
88037
  init_hosted_provider();
88038
+ init_funding_plan();
87679
88039
  init_economy_tools();
87680
88040
  DEFAULT_CROWDCODE_BASE = "https://crowdcode-backend.onrender.com";
87681
88041
  LIST_CACHE_MS = 6e4;
@@ -87865,6 +88225,18 @@ var init_hosted_economy = __esm({
87865
88225
  note: "This is your own service, so CrowdCode ran this call as a free owner test: nothing was paid or earned. Buyers pay the listed price as usual."
87866
88226
  };
87867
88227
  }
88228
+ if (data.outcome === "free_proof") {
88229
+ const ok4 = status !== void 0 && status < 400;
88230
+ return {
88231
+ ok: ok4,
88232
+ ambiguous: false,
88233
+ status,
88234
+ data: decodeBody(data.body, data.content_type),
88235
+ authMode: "free",
88236
+ error: ok4 ? void 0 : `the service answered HTTP ${status ?? "?"} to a signed identity proof`,
88237
+ note: `Free: the service asked only for proof of which wallet is calling (a zero-amount MPP challenge on ${stringValue5(data.network) ?? "tempo"}). CrowdCode signed it; no USDC moved and no balance was needed on any network, so never move funds for a call like this.`
88238
+ };
88239
+ }
87868
88240
  const outcome = data.outcome === "paid_success" ? "paid_success" : "paid_failure";
87869
88241
  const paidAtomic = numberValue6(data.amount_atomic);
87870
88242
  const network = stringValue5(data.network);
@@ -87922,6 +88294,10 @@ var init_hosted_economy = __esm({
87922
88294
  return void 0;
87923
88295
  }
87924
88296
  }
88297
+ /** An unpaid request with extra headers: a seller's documented follow-up, or its OpenAPI. */
88298
+ fetchFree(request2) {
88299
+ return this.fetchUnpaid(request2.url, request2.method.toUpperCase(), request2.body, request2.headers);
88300
+ }
87925
88301
  /** The supervisor found no 402: the endpoint is free, so the worker fetches it itself. */
87926
88302
  async fetchUnpaid(url3, method, body, headers) {
87927
88303
  try {
@@ -87953,12 +88329,12 @@ var init_hosted_economy = __esm({
87953
88329
  */
87954
88330
  async fundingHint(request2) {
87955
88331
  const wallet = await this.getBalance().catch(() => void 0);
87956
- const networks = Array.isArray(wallet?.data?.networks) ? wallet.data.networks : [];
87957
- const available = networks.map((n) => ({ network: stringValue5(n.network) ?? "?", usd: numberValue6(n.available_usd ?? n.balance_usd) })).filter((n) => n.usd !== void 0);
88332
+ const available = walletFunds(wallet?.data).map((n) => ({ network: n.network, usd: n.availableUsd, owed: n.hostingOwedUsd ?? 0 }));
87958
88333
  if (!available.length)
87959
88334
  return " Check get_wallet_status for where your USDC is.";
87960
88335
  const total = available.reduce((sum, n) => sum + n.usd, 0);
87961
- const line = ` Your available USDC: ${available.map((n) => `${n.network} ${n.usd.toFixed(2)}`).join(", ")} (total ${total.toFixed(2)}).`;
88336
+ const owed = available.filter((n) => n.owed > 0).map((n) => `; ${n.network} is net of $${n.owed.toFixed(2)} owed for hosting`).join("");
88337
+ const line = ` Your spendable USDC: ${available.map((n) => `${n.network} ${n.usd.toFixed(2)}`).join(", ")} (total ${total.toFixed(2)}${owed}). If this task makes more paid calls, call plan_funding with all of them before moving anything: one move sized to the whole task, not one per call.`;
87962
88338
  const target = RAIL_NETWORK2[request2.rail];
87963
88339
  const funded = available.filter((n) => n.network !== target && n.usd >= request2.maxAmountUsd).map((n) => n.network);
87964
88340
  const elsewhere = funded.length ? ` First look for an equivalent service you can already pay: find_paid_service lists every result's networks, and one on ${funded.join(" or ")} costs you no transfer fee.` : "";
@@ -87970,6 +88346,32 @@ var init_hosted_economy = __esm({
87970
88346
  return `${line}${elsewhere} Moving funds is the other way, but the most ${move.from} can spare is ${size5}, and a fee of ${cost} is ${Math.round(move.feeShare * 100)}% of that \u2014 too much to spend without asking. If no equivalent service fits, say exactly that to the owner: this service is sold only on ${target}, moving ${size5} there would cost ${cost} in fees, and ask whether to do it.`;
87971
88347
  return `${line}${elsewhere} Otherwise move the funds yourself and retry \u2014 a move this size is within the policy and is not something to ask the owner about, any more than paying for the call is: bridge_usdc {"from":"${move.from}","to":"${target}","amount_usd":${move.amount}} (fee ${cost}, counted as spending; the spending guard pauses it for approval by itself if the owner's mode requires that), then retry this call.`;
87972
88348
  }
88349
+ /**
88350
+ * plan_funding: probe every planned call for every network it accepts, read
88351
+ * what each network can spend, and plan the task's funding once
88352
+ * (funding-plan.ts). Read-only; the probes are unpaid.
88353
+ */
88354
+ async planFunding(args) {
88355
+ const raw = Array.isArray(args.calls) ? args.calls.slice(0, 12) : [];
88356
+ const wanted = raw.map(objectValue5).filter((call2) => !!call2 && !!stringValue5(call2.url));
88357
+ if (!wanted.length)
88358
+ return { ok: false, error: "plan_funding needs calls: [{url, method, count}]" };
88359
+ const [calls, wallet] = await Promise.all([
88360
+ Promise.all(wanted.map(async (call2) => {
88361
+ const url3 = stringValue5(call2.url), method = (stringValue5(call2.method) ?? "GET").toUpperCase();
88362
+ const count = Math.min(20, Math.max(1, Math.floor(numberValue6(call2.count) ?? 1)));
88363
+ const probe = await this.discovery.inspect({ url: url3, method, body: objectValue5(call2.sample_body) }).catch((error53) => ({ ok: false, error: error53.message, data: void 0 }));
88364
+ const offers = Array.isArray(probe.data?.offers) ? probe.data.offers : [];
88365
+ const payable = offers.filter((offer) => offer.payable === true && numberValue6(offer.price_usd) !== void 0).map((offer) => ({ network: stringValue5(offer.network) ?? "?", priceUsd: numberValue6(offer.price_usd), ...offer.free === true ? { free: true } : {} }));
88366
+ return { url: url3, method, count, offers: payable, ...probe.ok ? payable.length ? {} : { error: "the endpoint offers nothing this wallet can pay" } : { error: probe.error ?? "the endpoint could not be probed" } };
88367
+ })),
88368
+ this.getBalance().catch(() => void 0)
88369
+ ]);
88370
+ const funds = walletFunds(wallet?.data);
88371
+ if (!funds.length)
88372
+ return { ok: false, error: "the wallet's balances could not be read; nothing was planned. Try again shortly." };
88373
+ return { ok: true, data: describePlan(planTaskFunding(calls, funds)) };
88374
+ }
87973
88375
  /**
87974
88376
  * Moves this agent's own USDC between its networks through the supervisor:
87975
88377
  * a quote, or an executed move keyed by the tool call that waits for the
@@ -88121,7 +88523,7 @@ var init_hosted_economy = __esm({
88121
88523
  };
88122
88524
  HOSTED_BRIDGE_TOOL = {
88123
88525
  name: "bridge_usdc",
88124
- description: "Move your own USDC between your networks (base, solana, tempo); it always arrives at your own address. Use it when the owner asks, or when a paid call failed with funding_required and no equivalent service is sold on a network you already fund. quote_only shows the fee and expected amount without moving. Executing re-quotes, applies the owner's approval policy to the fee (it may pause for approval) and waits for the funds to arrive, usually within a minute. Fees are about $0.02-0.03 and count as spending, so aim for about $1 and one fee funds many calls; when the wallet holds less, move what the call needs plus the fee, as long as the fee stays under about a fifth of what moves (roughly $0.15 and up). A move within that rule needs no permission from the owner: the spending guard applies their approval mode to the fee by itself. Below the rule, quote_only first and ask, rather than spending most of the move on its fee. Pass transfer_id alone to check a pending move.",
88526
+ description: "Move your own USDC between your networks (base, solana, tempo); it always arrives at your own address. Use it when the owner asks, when plan_funding lists a move, or when a paid call failed with funding_required and no equivalent service is sold on a network you already fund. A run moves into each network at most once and never back the other way: plan a multi-call task with plan_funding first, then make its one move. quote_only shows the fee and expected amount without moving. Executing re-quotes, applies the owner's approval policy to the fee (it may pause for approval) and waits for the funds to arrive, usually within a minute. Fees are about $0.02-0.03 and count as spending, so aim for about $1 and one fee funds many calls; when the wallet holds less, move what the call needs plus the fee, as long as the fee stays under about a fifth of what moves (roughly $0.15 and up). A move within that rule needs no permission from the owner: the spending guard applies their approval mode to the fee by itself. Below the rule, quote_only first and ask, rather than spending most of the move on its fee. Pass transfer_id alone to check a pending move.",
88125
88527
  parameters: {
88126
88528
  type: "object",
88127
88529
  properties: {
@@ -88176,8 +88578,8 @@ var init_tool_deadlines = __esm({
88176
88578
  });
88177
88579
 
88178
88580
  // ../../packages/agent-runtime/dist/worker.js
88179
- import { readFile as readFile13, mkdir as mkdir11 } from "node:fs/promises";
88180
- import { join as join21 } from "node:path";
88581
+ import { readFile as readFile14, mkdir as mkdir11 } from "node:fs/promises";
88582
+ import { join as join22 } from "node:path";
88181
88583
  import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
88182
88584
  function isWaiting(outcome) {
88183
88585
  return ["waiting_for_approval", "waiting_for_funds", "waiting_for_delegation", "payment_unknown"].includes(outcome);
@@ -88236,13 +88638,13 @@ var init_worker = __esm({
88236
88638
  constructor(options) {
88237
88639
  this.options = options;
88238
88640
  this.paths = resolveAgentPaths({ agentHome: options.agentHome });
88239
- this.statePath = join21(this.paths.metadata, "worker.json");
88641
+ this.statePath = join22(this.paths.metadata, "worker.json");
88240
88642
  }
88241
88643
  async initialize() {
88242
88644
  await containedPath(this.paths.home, "metadata/worker.json");
88243
88645
  await mkdir11(this.paths.metadata, { recursive: true });
88244
88646
  try {
88245
- const raw = await readFile13(this.statePath, "utf8");
88647
+ const raw = await readFile14(this.statePath, "utf8");
88246
88648
  this.state = JSON.parse(raw);
88247
88649
  if (this.state.version !== 1 || !Number.isSafeInteger(this.state.seq) || !this.state.commands || !this.state.runs) {
88248
88650
  throw new Error("worker checkpoint version or shape is invalid");
@@ -88417,13 +88819,13 @@ var init_worker = __esm({
88417
88819
  } catch (error53) {
88418
88820
  if (error53.code !== "ENOENT" || run.start.payload.session.kind === "existing")
88419
88821
  throw error53;
88420
- const cents = BigInt(run.start.payload.budget.limit) / 10000n;
88421
- if (cents > BigInt(Number.MAX_SAFE_INTEGER))
88822
+ const cents2 = BigInt(run.start.payload.budget.limit) / 10000n;
88823
+ if (cents2 > BigInt(Number.MAX_SAFE_INTEGER))
88422
88824
  throw new Error("budget exceeds local accounting range");
88423
88825
  session = await createSession({
88424
88826
  workspaceRoot: this.paths.workspace,
88425
88827
  sessionId: run.sessionId,
88426
- budgetCents: Number(cents),
88828
+ budgetCents: Number(cents2),
88427
88829
  approvalMode: run.start.payload.approvalMode,
88428
88830
  shellEnabled: true
88429
88831
  });
@@ -88595,7 +88997,7 @@ var init_worker = __esm({
88595
88997
  run.checkpoint = checkpoint;
88596
88998
  run.checkpointId = randomUUID8();
88597
88999
  });
88598
- await atomicWrite(join21(session.sessionDir, "messages.jsonl"), checkpoint.messages.filter((m) => m.role !== "system").map((message) => JSON.stringify({ type: "message", timestamp: (/* @__PURE__ */ new Date()).toISOString(), message }) + "\n").join(""));
89000
+ await atomicWrite(join22(session.sessionDir, "messages.jsonl"), checkpoint.messages.filter((m) => m.role !== "system").map((message) => JSON.stringify({ type: "message", timestamp: (/* @__PURE__ */ new Date()).toISOString(), message }) + "\n").join(""));
88599
89001
  },
88600
89002
  onMessage: async (message) => {
88601
89003
  const content = message.role === "assistant" && !message.housekeeping ? stripReasoning(message.content) : "";
@@ -88658,7 +89060,7 @@ var init_worker = __esm({
88658
89060
  }
88659
89061
  async history(session) {
88660
89062
  try {
88661
- return (await readFile13(join21(session.sessionDir, "messages.jsonl"), "utf8")).split("\n").filter(Boolean).map((line) => JSON.parse(line).message).filter(Boolean);
89063
+ return (await readFile14(join22(session.sessionDir, "messages.jsonl"), "utf8")).split("\n").filter(Boolean).map((line) => JSON.parse(line).message).filter(Boolean);
88662
89064
  } catch (error53) {
88663
89065
  if (error53.code === "ENOENT")
88664
89066
  return [];
@@ -88696,7 +89098,7 @@ var init_worker = __esm({
88696
89098
  });
88697
89099
 
88698
89100
  // ../../packages/agent-runtime/dist/inbox.js
88699
- import { readFile as readFile14 } from "node:fs/promises";
89101
+ import { readFile as readFile15 } from "node:fs/promises";
88700
89102
  var FileSteeringInbox;
88701
89103
  var init_inbox = __esm({
88702
89104
  "../../packages/agent-runtime/dist/inbox.js"() {
@@ -88710,7 +89112,7 @@ var init_inbox = __esm({
88710
89112
  }
88711
89113
  async read() {
88712
89114
  try {
88713
- return JSON.parse(await readFile14(this.path, "utf8"));
89115
+ return JSON.parse(await readFile15(this.path, "utf8"));
88714
89116
  } catch (e6) {
88715
89117
  if (e6.code === "ENOENT")
88716
89118
  return [];
@@ -88755,8 +89157,8 @@ var init_non_answer = __esm({
88755
89157
 
88756
89158
  // ../../packages/agent-runtime/dist/index.js
88757
89159
  import { createHash as createHash6 } from "node:crypto";
88758
- import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "node:fs/promises";
88759
- import { join as join22 } from "node:path";
89160
+ import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile16 } from "node:fs/promises";
89161
+ import { join as join23 } from "node:path";
88760
89162
  function lastUserMessageIndex(messages) {
88761
89163
  for (let index2 = messages.length - 1; index2 >= 0; index2 -= 1) {
88762
89164
  if (messages[index2].role === "user") {
@@ -88890,13 +89292,13 @@ function chargedCostCents(usage, modelId, catalog) {
88890
89292
  }
88891
89293
  const model = catalog?.find((candidate) => candidate.id === modelId);
88892
89294
  if (model && (model.inputCostCentsPer1k !== void 0 || model.outputCostCentsPer1k !== void 0) && (usage.inputTokens !== void 0 || usage.outputTokens !== void 0)) {
88893
- const cents = (usage.inputTokens ?? 0) / 1e3 * (model.inputCostCentsPer1k ?? 0) + (usage.outputTokens ?? 0) / 1e3 * (model.outputCostCentsPer1k ?? 0);
88894
- return Math.max(0, roundCents(cents));
89295
+ const cents2 = (usage.inputTokens ?? 0) / 1e3 * (model.inputCostCentsPer1k ?? 0) + (usage.outputTokens ?? 0) / 1e3 * (model.outputCostCentsPer1k ?? 0);
89296
+ return Math.max(0, roundCents(cents2));
88895
89297
  }
88896
89298
  return 0;
88897
89299
  }
88898
- function roundCents(cents) {
88899
- return Math.round(cents * 1e4) / 1e4;
89300
+ function roundCents(cents2) {
89301
+ return Math.round(cents2 * 1e4) / 1e4;
88900
89302
  }
88901
89303
  function usageMetricsNote(completion) {
88902
89304
  const usage = completion.usage;
@@ -88960,7 +89362,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
88960
89362
  if (options.dynamicTools) {
88961
89363
  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: a call that never reached the seller is never the seller's fault. funding_required means your USDC is on the wrong network, a cap or a declined approval means the owner's policy stopped you, and an unpayable rail means you could not pay at all \u2014 in every one of those the service was never asked, so it gets no review and certainly not a low rating. Fix the cause and call it again instead; the gateway refuses those reviews, and trying anyway wastes a turn. A platform judge, not you, writes the public score and text of a paid review from the platform's record of the call; your rating and notes are evidence it reads, so report accurately and never try to talk it into a rating.", `Choosing a service: find_paid_service with a short capability query (for example "web search" or "object storage", not the task's subject) searches every catalog (AgentCash, Coinbase's x402 catalog, the MPP catalog and CrowdCode's reviews) across Base, Solana and Tempo and returns services you can pay, ranked best first by CrowdCode: quality (score and verified reviews), then effective price on the service's best network, including about $0.03 to move USDC between your own networks when that network's balance is short, then your balance there. Prefer the highest-ranked service that fits the task, whatever its network; a better or cheaper service on Solana or Tempo beats a Base default. Each result also lists \`networks\`, the networks it can be paid on; between services that fit the task equally well, one you can pay from a balance you already hold beats one that needs a transfer first, because a move costs about $0.03. When the chosen service is marked transfer_needed, move USDC between your own networks first if you have a tool for that; otherwise tell the user which network needs funds. When the ranking is unavailable, compare candidates yourself with inspect_paid_service (reputation, price and network) against your per-network balances.`, ...options.hosted ? [
88962
89364
  "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.",
88963
- "funding_required means your USDC is on the wrong network, not that you are out of money, and a wallet with money in it finishes the job. First go back to find_paid_service and look for an equivalent service sold on a network you already hold USDC on \u2014 every result lists its `networks`, and paying from an existing balance costs no transfer fee. If none fits, move funds with bridge_usdc and retry the same call: aim for about $1 so one fee funds many later calls, and when the wallet holds less than that, move what the call needs plus the fee, as long as the fee stays under about a fifth of what moves (roughly $0.15 and up at a $0.03 fee). A move inside that rule is ordinary work, not a decision for the owner: make it and retry, exactly as you would pay for the call itself. The spending guard applies the owner's approval mode to the fee by itself and pauses the run if it has to, so you never need permission before calling bridge_usdc. Stopping to ask whether you may spend three cents moving the owner's own money to the network a seller wants is the dead end this rule exists to prevent. Only below that threshold is a move not worth making on your own: quote_only it, then ask. When the owner asks you to move funds, quote first, state the fee, then execute and report both transaction ids and the amount received. Moves follow the owner's approval mode like payments; never move funds without a reason.",
89365
+ "funding_required means your USDC is on the wrong network, not that you are out of money, and a wallet with money in it finishes the job. First go back to find_paid_service and look for an equivalent service sold on a network you already hold USDC on \u2014 every result lists its `networks`, and paying from an existing balance costs no transfer fee. If none fits, move funds with bridge_usdc and retry the same call: move what plan_funding says, or, for a single call, about $1 so one fee funds many later calls, and when the wallet holds less than that, move what the call needs plus the fee, as long as the fee stays under about a fifth of what moves (roughly $0.15 and up at a $0.03 fee). A move inside that rule is ordinary work, not a decision for the owner: make it and retry, exactly as you would pay for the call itself. The spending guard applies the owner's approval mode to the fee by itself and pauses the run if it has to, so you never need permission before calling bridge_usdc. Stopping to ask whether you may spend three cents moving the owner's own money to the network a seller wants is the dead end this rule exists to prevent. Only below that threshold is a move not worth making on your own: quote_only it, then ask. When the owner asks you to move funds, quote first, state the fee, then execute and report both transaction ids and the amount received. Moves follow the owner's approval mode like payments; never move funds without a reason.",
89366
+ "Plan a task's funding once, before its first purchase. When a task will make more than one paid call, or call a service sold on a network you hold little on, call plan_funding with every call you intend to make. One seller can need two networks for one task \u2014 articles paid on Base, a free search that only asks a signed wallet proof on Tempo \u2014 and plan_funding reads every network each endpoint accepts against what each of your networks can really spend (balance less holds, hosting owed and what is kept for hosting and your own model calls). Make exactly the moves it lists, at most one into any network, and never move funds back the other way in the same run: a round trip pays two fees for nothing. A call whose offer is free (price 0, marked free) needs no balance on any network; never move funds for it. When a paid answer carries a follow-up token (for example a free re-read), the runtime saves it and sends it on the next call to the same URL, so a repeat costs nothing; never pay twice for content you already bought.",
88964
89367
  "When money is what blocks a task, say exactly that and nothing else: which network the service is sold on, what you hold where, and the single thing you need \u2014 permission for a move you have quoted, or USDC added on that network. Never dress a funding problem up as the service being unsuitable or unavailable, never imply your wallet is empty when it is not, and never offer a recorded request_service as though it were the answer the owner asked for."
88965
89368
  ] : [], 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 (input, output, problem, price_per_call), unless CrowdCode is off. Never invent a purchase or demand.", "Generated media never reaches you as base64 you can read: when a service returns audio, an image, video or a PDF, the runtime has already written the bytes to a file and handed you {artifact_path, bytes, media_type} instead. Work from that path with run_shell \u2014 ffmpeg, python3 and node are installed, so converting a wav to the mp3 the owner asked for is one command \u2014 and leave the deliverable under artifacts/ in the format they asked for. Never pay a second time for a file you already hold.", "Each tool result includes the budget before and after that tool call. Never ask for wallet private keys or secrets.", ...options.promptSections ?? []);
88966
89369
  } else {
@@ -89421,8 +89824,8 @@ async function runSubagentTask(session, args, subagent, index2, parentOptions, o
89421
89824
  return { ok: false, error: "spawn_subagent requires a task" };
89422
89825
  }
89423
89826
  const subagentId = `${session.sessionId}#sub${index2}`;
89424
- const trajectoryDir = join22(session.sessionDir, "subagents", operationKey ?? String(index2));
89425
- const trajectoryPath = join22(trajectoryDir, "messages.jsonl");
89827
+ const trajectoryDir = join23(session.sessionDir, "subagents", operationKey ?? String(index2));
89828
+ const trajectoryPath = join23(trajectoryDir, "messages.jsonl");
89426
89829
  await mkdir12(trajectoryDir, { recursive: true });
89427
89830
  const record3 = async (message) => {
89428
89831
  await appendFile4(trajectoryPath, `${JSON.stringify({ type: "message", timestamp: (/* @__PURE__ */ new Date()).toISOString(), message })}
@@ -89453,11 +89856,11 @@ async function runSubagentTask(session, args, subagent, index2, parentOptions, o
89453
89856
  ].filter(Boolean).join("\n\n")
89454
89857
  }
89455
89858
  ];
89456
- const statePath = join22(trajectoryDir, "checkpoint.json");
89859
+ const statePath = join23(trajectoryDir, "checkpoint.json");
89457
89860
  let saved;
89458
89861
  if (operationKey)
89459
89862
  try {
89460
- saved = JSON.parse(await readFile15(statePath, "utf8"));
89863
+ saved = JSON.parse(await readFile16(statePath, "utf8"));
89461
89864
  } catch (e6) {
89462
89865
  if (e6.code !== "ENOENT")
89463
89866
  throw e6;
@@ -89909,8 +90312,8 @@ function truncateMiddle(value, maxLength) {
89909
90312
  const tail = Math.floor((maxLength - 1) / 2);
89910
90313
  return `${value.slice(0, head)}\u2026${value.slice(value.length - tail)}`;
89911
90314
  }
89912
- function formatCents(cents) {
89913
- return `$${(cents / 100).toFixed(cents > 0 && cents < 1 ? 4 : 2)}`;
90315
+ function formatCents(cents2) {
90316
+ return `$${(cents2 / 100).toFixed(cents2 > 0 && cents2 < 1 ? 4 : 2)}`;
89914
90317
  }
89915
90318
  function sumCents2(rows) {
89916
90319
  const total = rows.reduce((sum, row) => {
@@ -90189,7 +90592,7 @@ var init_dist6 = __esm({
90189
90592
 
90190
90593
  // src/shared.ts
90191
90594
  import { readdir } from "node:fs/promises";
90192
- import { join as join23, resolve as resolve5 } from "node:path";
90595
+ import { join as join24, resolve as resolve5 } from "node:path";
90193
90596
  import { stdout as output } from "node:process";
90194
90597
  function renderKeyValues(value) {
90195
90598
  return Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => ` ${style(key, "muted").padEnd(24)} ${formatCell(item, 80, key)}`).join("\n");
@@ -90222,9 +90625,9 @@ function formatCell(value, maxLength, key = "") {
90222
90625
  return "-";
90223
90626
  }
90224
90627
  if ((typeof value === "number" || typeof value === "string") && /cost|cents|spend|remaining|budget|max/i.test(key)) {
90225
- const cents = Number(value);
90226
- if (Number.isFinite(cents)) {
90227
- return formatCents2(cents);
90628
+ const cents2 = Number(value);
90629
+ if (Number.isFinite(cents2)) {
90630
+ return formatCents2(cents2);
90228
90631
  }
90229
90632
  }
90230
90633
  if (typeof value === "number" && Number.isFinite(value) && /_cents$/.test(key)) {
@@ -90249,8 +90652,8 @@ function shortUrl(value) {
90249
90652
  return truncateMiddle2(value, 48);
90250
90653
  }
90251
90654
  }
90252
- function formatCents2(cents) {
90253
- return `$${(cents / 100).toFixed(cents > 0 && cents < 1 ? 4 : 2)}`;
90655
+ function formatCents2(cents2) {
90656
+ return `$${(cents2 / 100).toFixed(cents2 > 0 && cents2 < 1 ? 4 : 2)}`;
90254
90657
  }
90255
90658
  function terminalWidth() {
90256
90659
  return Math.max(60, Math.min(140, output.columns ?? 100));
@@ -90311,7 +90714,7 @@ function isConsumedOption(args, index2, options) {
90311
90714
  return options.includes(args[index2]) || index2 > 0 && options.includes(args[index2 - 1]);
90312
90715
  }
90313
90716
  async function latestSessionId(workspaceRoot) {
90314
- const sessionsDir = join23(resolve5(workspaceRoot), "sessions");
90717
+ const sessionsDir = join24(resolve5(workspaceRoot), "sessions");
90315
90718
  try {
90316
90719
  const entries = await readdir(sessionsDir, { withFileTypes: true });
90317
90720
  return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().at(-1);
@@ -90481,8 +90884,8 @@ var init_doctor = __esm({
90481
90884
  });
90482
90885
 
90483
90886
  // ../../packages/evals/dist/gaia.js
90484
- import { mkdir as mkdir13, readFile as readFile16, writeFile as writeFile7, access as access2 } from "node:fs/promises";
90485
- import { dirname as dirname12, join as join25 } from "node:path";
90887
+ import { mkdir as mkdir13, readFile as readFile17, writeFile as writeFile8, access as access2 } from "node:fs/promises";
90888
+ import { dirname as dirname12, join as join26 } from "node:path";
90486
90889
  import { homedir as homedir7 } from "node:os";
90487
90890
  function isUnsupportedModality(fileName) {
90488
90891
  if (!fileName) {
@@ -90492,18 +90895,18 @@ function isUnsupportedModality(fileName) {
90492
90895
  return UNSUPPORTED_EXTENSIONS.some((extension2) => lower.endsWith(extension2));
90493
90896
  }
90494
90897
  function defaultGaiaCacheDir() {
90495
- return process.env.OPENCROWD_GAIA_CACHE_DIR ?? join25(homedir7(), ".cache", "opencrowd", "gaia", "2023", "validation");
90898
+ return process.env.OPENCROWD_GAIA_CACHE_DIR ?? join26(homedir7(), ".cache", "opencrowd", "gaia", "2023", "validation");
90496
90899
  }
90497
90900
  async function fetchGaiaValidation(options = {}) {
90498
90901
  const cacheDir = options.cacheDir ?? defaultGaiaCacheDir();
90499
90902
  await mkdir13(cacheDir, { recursive: true });
90500
- const metadataPath = join25(cacheDir, "metadata.jsonl");
90903
+ const metadataPath = join26(cacheDir, "metadata.jsonl");
90501
90904
  let metadataText;
90502
90905
  try {
90503
- metadataText = await readFile16(metadataPath, "utf8");
90906
+ metadataText = await readFile17(metadataPath, "utf8");
90504
90907
  } catch {
90505
90908
  metadataText = await fetchValidationRows(options);
90506
- await writeFile7(metadataPath, metadataText, "utf8");
90909
+ await writeFile8(metadataPath, metadataText, "utf8");
90507
90910
  }
90508
90911
  return metadataText.split(/\r?\n/).filter(Boolean).map((line) => parseGaiaRecord(JSON.parse(line)));
90509
90912
  }
@@ -90552,7 +90955,7 @@ async function ensureGaiaAttachments(questions, options = {}) {
90552
90955
  const cacheDir = options.cacheDir ?? defaultGaiaCacheDir();
90553
90956
  for (const question of questions) {
90554
90957
  if (question.file_name && !isUnsupportedModality(question.file_name)) {
90555
- const filePath = join25(cacheDir, question.file_name);
90958
+ const filePath = join26(cacheDir, question.file_name);
90556
90959
  await cachedDownload(filePath, `${GAIA_BASE_URL}/${encodeURIComponent(question.file_name)}`, options, true);
90557
90960
  question.file_path = filePath;
90558
90961
  }
@@ -90582,7 +90985,7 @@ function parseGaiaRecord(record3) {
90582
90985
  async function cachedDownload(path3, url3, options, binary = false) {
90583
90986
  try {
90584
90987
  await access2(path3);
90585
- return binary ? "" : await readFile16(path3, "utf8");
90988
+ return binary ? "" : await readFile17(path3, "utf8");
90586
90989
  } catch {
90587
90990
  }
90588
90991
  options.log?.(`fetching ${url3}`);
@@ -90604,11 +91007,11 @@ async function cachedDownload(path3, url3, options, binary = false) {
90604
91007
  await mkdir13(dirname12(path3), { recursive: true });
90605
91008
  if (binary) {
90606
91009
  const buffer2 = Buffer.from(await response.arrayBuffer());
90607
- await writeFile7(path3, buffer2);
91010
+ await writeFile8(path3, buffer2);
90608
91011
  return "";
90609
91012
  }
90610
91013
  const text = await response.text();
90611
- await writeFile7(path3, text, "utf8");
91014
+ await writeFile8(path3, text, "utf8");
90612
91015
  return text;
90613
91016
  }
90614
91017
  var GAIA_BASE_URL, GAIA_ROWS_URL, GAIA_TIERS, UNSUPPORTED_EXTENSIONS;
@@ -90642,9 +91045,9 @@ var init_gaia = __esm({
90642
91045
  });
90643
91046
 
90644
91047
  // ../../packages/evals/dist/grader.js
90645
- import { readFile as readFile17 } from "node:fs/promises";
91048
+ import { readFile as readFile18 } from "node:fs/promises";
90646
91049
  async function gradeTrajectoryFile(path3) {
90647
- const text = await readFile17(path3, "utf8");
91050
+ const text = await readFile18(path3, "utf8");
90648
91051
  const entries = text.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
90649
91052
  return gradeTrajectory(entries);
90650
91053
  }
@@ -90777,8 +91180,8 @@ var init_grader = __esm({
90777
91180
  // ../../packages/evals/dist/harnesses.js
90778
91181
  import { execFile } from "node:child_process";
90779
91182
  import { promisify } from "node:util";
90780
- import { copyFile, mkdir as mkdir14, readFile as readFile18 } from "node:fs/promises";
90781
- import { basename, join as join26 } from "node:path";
91183
+ import { copyFile, mkdir as mkdir14, readFile as readFile19 } from "node:fs/promises";
91184
+ import { basename, join as join27 } from "node:path";
90782
91185
  function resolveHarness(name) {
90783
91186
  switch (name) {
90784
91187
  case "opencrowd":
@@ -90807,7 +91210,7 @@ function gaiaPrompt(question, attachmentNote) {
90807
91210
  }
90808
91211
  async function countPaidPurchases(path3) {
90809
91212
  try {
90810
- const text = await readFile18(path3, "utf8");
91213
+ const text = await readFile19(path3, "utf8");
90811
91214
  return text.split(/\r?\n/).filter(Boolean).filter((line) => {
90812
91215
  const entry = asRecord3(parseJson4(line));
90813
91216
  const outcome = asRecord3(entry.record).outcome ?? entry.outcome;
@@ -90822,7 +91225,7 @@ async function comparatorPrompt(context) {
90822
91225
  return context.prompt;
90823
91226
  }
90824
91227
  const name = basename(context.attachmentPath);
90825
- await copyFile(context.attachmentPath, join26(context.runDir, name));
91228
+ await copyFile(context.attachmentPath, join27(context.runDir, name));
90826
91229
  return `${context.prompt}
90827
91230
 
90828
91231
  An input file is available in the working directory at ./${name}`;
@@ -90917,10 +91320,10 @@ var init_harnesses = __esm({
90917
91320
  if (context.attachmentPath) {
90918
91321
  const name = basename(context.attachmentPath);
90919
91322
  await mkdir14(session.artifactsDir, { recursive: true });
90920
- await copyFile(context.attachmentPath, join26(session.artifactsDir, name));
91323
+ await copyFile(context.attachmentPath, join27(session.artifactsDir, name));
90921
91324
  prompt = `${prompt}
90922
91325
 
90923
- An input file is available at the session artifact path \`${name}\` (use read_file, or run_shell against ${join26(session.artifactsDir, name)}).`;
91326
+ An input file is available at the session artifact path \`${name}\` (use read_file, or run_shell against ${join27(session.artifactsDir, name)}).`;
90924
91327
  }
90925
91328
  const llm = context.testMode ? void 0 : await resolveLlmRuntime(session, {
90926
91329
  model: context.model,
@@ -90951,7 +91354,7 @@ An input file is available at the session artifact path \`${name}\` (use read_fi
90951
91354
  onMessage: (message) => appendConversationMessage(session, message)
90952
91355
  });
90953
91356
  const budget = asRecord3(result.summary.budget);
90954
- const trajectoryPath = join26(session.sessionDir, "messages.jsonl");
91357
+ const trajectoryPath = join27(session.sessionDir, "messages.jsonl");
90955
91358
  return {
90956
91359
  final_message: String(result.summary.final_message ?? ""),
90957
91360
  turns: result.turns,
@@ -90962,7 +91365,7 @@ An input file is available at the session artifact path \`${name}\` (use read_fi
90962
91365
  knowledge_version: session.knowledge?.version,
90963
91366
  session_dir: session.sessionDir,
90964
91367
  artifacts_dir: session.artifactsDir,
90965
- paid_calls: await countPaidPurchases(join26(session.sessionDir, "purchases.jsonl")),
91368
+ paid_calls: await countPaidPurchases(join27(session.sessionDir, "purchases.jsonl")),
90966
91369
  model_policy: llm?.models,
90967
91370
  compliance: await gradeTrajectoryFile(trajectoryPath).catch(() => void 0)
90968
91371
  };
@@ -91165,8 +91568,8 @@ var init_scorer = __esm({
91165
91568
  });
91166
91569
 
91167
91570
  // ../../packages/evals/dist/runner.js
91168
- import { appendFile as appendFile5, mkdir as mkdir15, writeFile as writeFile8 } from "node:fs/promises";
91169
- import { join as join27, resolve as resolve6 } from "node:path";
91571
+ import { appendFile as appendFile5, mkdir as mkdir15, writeFile as writeFile9 } from "node:fs/promises";
91572
+ import { join as join28, resolve as resolve6 } from "node:path";
91170
91573
  async function runGaiaBenchmark(options) {
91171
91574
  const log = options.log ?? (() => void 0);
91172
91575
  const harnesses = options.harnesses.map(resolveHarness);
@@ -91193,7 +91596,7 @@ async function runGaiaBenchmark(options) {
91193
91596
  const runId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
91194
91597
  const resultsDir = resolve6(options.workspaceRoot, "evals", "gaia", runId);
91195
91598
  await mkdir15(resultsDir, { recursive: true });
91196
- const resultsPath = join27(resultsDir, "results.jsonl");
91599
+ const resultsPath = join28(resultsDir, "results.jsonl");
91197
91600
  log(`GAIA ${options.tier}: ${runnable.length} questions, ${skipped.length} skipped (unsupported modality), results in ${resultsDir}`);
91198
91601
  const parallel = Math.max(1, options.parallel ?? 4);
91199
91602
  const rows = [];
@@ -91219,12 +91622,12 @@ async function runGaiaBenchmark(options) {
91219
91622
  harnesses: harnesses.map((harness) => summarizeHarness(harness, rows.filter((row) => row.harness === harness.name))),
91220
91623
  rows
91221
91624
  };
91222
- await writeFile8(join27(resultsDir, "report.json"), `${JSON.stringify(report, null, 2)}
91625
+ await writeFile9(join28(resultsDir, "report.json"), `${JSON.stringify(report, null, 2)}
91223
91626
  `, "utf8");
91224
91627
  return report;
91225
91628
  }
91226
91629
  async function runOneQuestion(harness, question, resultsDir, options) {
91227
- const runDir = join27(resultsDir, harness.name, question.task_id);
91630
+ const runDir = join28(resultsDir, harness.name, question.task_id);
91228
91631
  await mkdir15(runDir, { recursive: true });
91229
91632
  const prompt = gaiaPrompt(question);
91230
91633
  const started = Date.now();
@@ -91356,9 +91759,9 @@ var init_runner = __esm({
91356
91759
  });
91357
91760
 
91358
91761
  // ../../packages/evals/dist/tasks.js
91359
- import { readFile as readFile19 } from "node:fs/promises";
91762
+ import { readFile as readFile20 } from "node:fs/promises";
91360
91763
  import { createHash as createHash7 } from "node:crypto";
91361
- import { dirname as dirname13, join as join28 } from "node:path";
91764
+ import { dirname as dirname13, join as join29 } from "node:path";
91362
91765
  import { fileURLToPath as fileURLToPath2 } from "node:url";
91363
91766
  import { homedir as homedir8 } from "node:os";
91364
91767
  async function loadTaskSet(name, options = {}) {
@@ -91380,10 +91783,10 @@ async function loadTaskSet(name, options = {}) {
91380
91783
  }
91381
91784
  }
91382
91785
  function tasksDir() {
91383
- return join28(dirname13(fileURLToPath2(import.meta.url)), "..", "tasks");
91786
+ return join29(dirname13(fileURLToPath2(import.meta.url)), "..", "tasks");
91384
91787
  }
91385
91788
  async function loadUsageTasks() {
91386
- const raw = JSON.parse(await readFile19(join28(tasksDir(), "usage.json"), "utf8"));
91789
+ const raw = JSON.parse(await readFile20(join29(tasksDir(), "usage.json"), "utf8"));
91387
91790
  return raw.tasks.map((task) => ({
91388
91791
  task_id: String(task.id),
91389
91792
  suite: "usage",
@@ -91395,7 +91798,7 @@ async function loadUsageTasks() {
91395
91798
  capability: typeof task.capability === "string" ? task.capability : void 0,
91396
91799
  expect_paid: task.expect_paid,
91397
91800
  file_name: typeof task.attachment === "string" ? task.attachment : void 0,
91398
- file_path: typeof task.attachment === "string" ? join28(tasksDir(), "attachments", task.attachment) : void 0
91801
+ file_path: typeof task.attachment === "string" ? join29(tasksDir(), "attachments", task.attachment) : void 0
91399
91802
  }));
91400
91803
  }
91401
91804
  async function loadGaiaHard(options = {}) {
@@ -91421,13 +91824,13 @@ function gaiaToTask(question) {
91421
91824
  };
91422
91825
  }
91423
91826
  function defaultAssistantBenchCachePath() {
91424
- return process.env.OPENCROWD_ASSISTANTBENCH_CACHE ?? join28(homedir8(), ".cache", "opencrowd", "assistantbench", "validation.jsonl");
91827
+ return process.env.OPENCROWD_ASSISTANTBENCH_CACHE ?? join29(homedir8(), ".cache", "opencrowd", "assistantbench", "validation.jsonl");
91425
91828
  }
91426
91829
  async function loadAssistantBench(options = {}) {
91427
91830
  const cachePath = defaultAssistantBenchCachePath();
91428
91831
  let text;
91429
91832
  try {
91430
- text = await readFile19(cachePath, "utf8");
91833
+ text = await readFile20(cachePath, "utf8");
91431
91834
  } catch {
91432
91835
  options.log?.(`fetching ${ASSISTANTBENCH_ROWS_URL}`);
91433
91836
  const headers = options.hfToken ? { authorization: `Bearer ${options.hfToken}` } : {};
@@ -91438,9 +91841,9 @@ async function loadAssistantBench(options = {}) {
91438
91841
  const body = await response.json();
91439
91842
  text = `${(body.rows ?? []).map((item) => JSON.stringify(item.row)).join("\n")}
91440
91843
  `;
91441
- const { mkdir: mkdir21, writeFile: writeFile13 } = await import("node:fs/promises");
91844
+ const { mkdir: mkdir21, writeFile: writeFile14 } = await import("node:fs/promises");
91442
91845
  await mkdir21(dirname13(cachePath), { recursive: true });
91443
- await writeFile13(cachePath, text, "utf8");
91846
+ await writeFile14(cachePath, text, "utf8");
91444
91847
  }
91445
91848
  const rows = text.split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line));
91446
91849
  const selected = seededSample(rows, ASSISTANTBENCH_COUNT, `${options.seed ?? DEFAULT_SEED}:assistantbench`, (row) => String(row.id));
@@ -91496,9 +91899,9 @@ var init_tasks = __esm({
91496
91899
  });
91497
91900
 
91498
91901
  // ../../packages/evals/dist/scoring.js
91499
- import { readFile as readFile20, stat } from "node:fs/promises";
91902
+ import { readFile as readFile21, stat } from "node:fs/promises";
91500
91903
  import { resolve as resolveDns } from "node:dns/promises";
91501
- import { join as join29 } from "node:path";
91904
+ import { join as join30 } from "node:path";
91502
91905
  async function scoreTask(task, finalMessage, context = {}) {
91503
91906
  const answer = extractAnswerText(finalMessage);
91504
91907
  const spec = task.scorer;
@@ -91543,7 +91946,7 @@ async function scoreTask(task, finalMessage, context = {}) {
91543
91946
  return { score: 0, correct: false, detail: "no artifacts dir" };
91544
91947
  }
91545
91948
  for (const name of spec.names) {
91546
- const path3 = join29(context.artifactsDir, name);
91949
+ const path3 = join30(context.artifactsDir, name);
91547
91950
  let size5;
91548
91951
  try {
91549
91952
  size5 = (await stat(path3)).size;
@@ -91553,7 +91956,7 @@ async function scoreTask(task, finalMessage, context = {}) {
91553
91956
  if (spec.min_bytes !== void 0 && size5 < spec.min_bytes) {
91554
91957
  return { score: 0, correct: false, detail: `${name} too small (${size5} bytes)` };
91555
91958
  }
91556
- const buffer2 = await readFile20(path3);
91959
+ const buffer2 = await readFile21(path3);
91557
91960
  if (spec.image && !looksLikeImage(buffer2)) {
91558
91961
  return { score: 0, correct: false, detail: `${name} is not a PNG/JPEG/WebP` };
91559
91962
  }
@@ -91740,8 +92143,8 @@ var init_scoring = __esm({
91740
92143
  });
91741
92144
 
91742
92145
  // ../../packages/evals/dist/suite.js
91743
- import { appendFile as appendFile6, mkdir as mkdir16, writeFile as writeFile9 } from "node:fs/promises";
91744
- import { join as join30, resolve as resolve7 } from "node:path";
92146
+ import { appendFile as appendFile6, mkdir as mkdir16, writeFile as writeFile10 } from "node:fs/promises";
92147
+ import { join as join31, resolve as resolve7 } from "node:path";
91745
92148
  async function runSuite(options) {
91746
92149
  const log = options.log ?? (() => void 0);
91747
92150
  const harness = resolveHarness(options.harness ?? "opencrowd");
@@ -91756,7 +92159,7 @@ async function runSuite(options) {
91756
92159
  const runId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}${options.tag ? `-${slug(options.tag)}` : ""}`;
91757
92160
  const resultsDir = resolve7(options.resultsRoot, runId);
91758
92161
  await mkdir16(resultsDir, { recursive: true });
91759
- const resultsPath = join30(resultsDir, "results.jsonl");
92162
+ const resultsPath = join31(resultsDir, "results.jsonl");
91760
92163
  log(`suite ${options.set}${options.tag ? ` [${options.tag}]` : ""}: ${tasks.length} tasks, knowledge=${options.knowledgeDir ?? "none"}, results in ${resultsDir}`);
91761
92164
  const limit = createLimiter3(Math.max(1, options.parallel ?? 3));
91762
92165
  const rows = await Promise.all(tasks.map((task, index2) => limit(async () => {
@@ -91780,14 +92183,14 @@ async function runSuite(options) {
91780
92183
  summary: summarize(rows),
91781
92184
  rows
91782
92185
  };
91783
- await writeFile9(join30(resultsDir, "report.json"), `${JSON.stringify(report, null, 2)}
92186
+ await writeFile10(join31(resultsDir, "report.json"), `${JSON.stringify(report, null, 2)}
91784
92187
  `, "utf8");
91785
- await writeFile9(join30(resultsDir, "report.md"), `${renderSuiteReport(report)}
92188
+ await writeFile10(join31(resultsDir, "report.md"), `${renderSuiteReport(report)}
91786
92189
  `, "utf8");
91787
92190
  return report;
91788
92191
  }
91789
92192
  async function runOneTask(harnessName, harness, task, resultsDir, runId, options) {
91790
- const runDir = join30(resultsDir, harnessName, task.task_id);
92193
+ const runDir = join31(resultsDir, harnessName, task.task_id);
91791
92194
  await mkdir16(runDir, { recursive: true });
91792
92195
  const started = Date.now();
91793
92196
  let run;
@@ -91947,13 +92350,13 @@ var init_suite = __esm({
91947
92350
  });
91948
92351
 
91949
92352
  // ../../packages/evals/dist/evidence.js
91950
- import { mkdir as mkdir17, readFile as readFile21, writeFile as writeFile10 } from "node:fs/promises";
92353
+ import { mkdir as mkdir17, readFile as readFile22, writeFile as writeFile11 } from "node:fs/promises";
91951
92354
  import { dirname as dirname14 } from "node:path";
91952
92355
  async function fetchCrowdCodeEvidence(options = {}) {
91953
92356
  const cachePath = options.cachePath;
91954
92357
  if (cachePath && options.useCache !== false) {
91955
92358
  try {
91956
- return JSON.parse(await readFile21(cachePath, "utf8"));
92359
+ return JSON.parse(await readFile22(cachePath, "utf8"));
91957
92360
  } catch {
91958
92361
  }
91959
92362
  }
@@ -91966,7 +92369,7 @@ async function fetchCrowdCodeEvidence(options = {}) {
91966
92369
  if (exported) {
91967
92370
  if (cachePath) {
91968
92371
  await mkdir17(dirname14(cachePath), { recursive: true });
91969
- await writeFile10(cachePath, `${JSON.stringify(exported, null, 1)}
92372
+ await writeFile11(cachePath, `${JSON.stringify(exported, null, 1)}
91970
92373
  `, "utf8");
91971
92374
  }
91972
92375
  return exported;
@@ -91997,7 +92400,7 @@ async function fetchCrowdCodeEvidence(options = {}) {
91997
92400
  };
91998
92401
  if (cachePath) {
91999
92402
  await mkdir17(dirname14(cachePath), { recursive: true });
92000
- await writeFile10(cachePath, `${JSON.stringify(bundle, null, 1)}
92403
+ await writeFile11(cachePath, `${JSON.stringify(bundle, null, 1)}
92001
92404
  `, "utf8");
92002
92405
  }
92003
92406
  return bundle;
@@ -92144,8 +92547,8 @@ var init_evidence = __esm({
92144
92547
 
92145
92548
  // ../../packages/evals/dist/knowledge.js
92146
92549
  import { createHash as createHash8 } from "node:crypto";
92147
- import { mkdir as mkdir18, readdir as readdir2, readFile as readFile22, writeFile as writeFile11 } from "node:fs/promises";
92148
- import { dirname as dirname15, join as join31, relative as relative4 } from "node:path";
92550
+ import { mkdir as mkdir18, readdir as readdir2, readFile as readFile23, writeFile as writeFile12 } from "node:fs/promises";
92551
+ import { dirname as dirname15, join as join32, relative as relative4 } from "node:path";
92149
92552
  function approxTokens(text) {
92150
92553
  return Math.ceil(text.length / 4);
92151
92554
  }
@@ -92236,30 +92639,30 @@ function validateTree(tree, evidence) {
92236
92639
  async function writeTree(dir, tree, meta4) {
92237
92640
  await mkdir18(dir, { recursive: true });
92238
92641
  for (const [name, content] of Object.entries(tree)) {
92239
- const path3 = join31(dir, name);
92642
+ const path3 = join32(dir, name);
92240
92643
  await mkdir18(dirname15(path3), { recursive: true });
92241
- await writeFile11(path3, content.endsWith("\n") ? content : `${content}
92644
+ await writeFile12(path3, content.endsWith("\n") ? content : `${content}
92242
92645
  `, "utf8");
92243
92646
  }
92244
- await writeFile11(join31(dir, "meta.json"), `${JSON.stringify(meta4, null, 2)}
92647
+ await writeFile12(join32(dir, "meta.json"), `${JSON.stringify(meta4, null, 2)}
92245
92648
  `, "utf8");
92246
92649
  }
92247
92650
  async function readTree(dir) {
92248
92651
  const tree = {};
92249
92652
  const walk4 = async (current) => {
92250
92653
  for (const entry of await readdir2(current, { withFileTypes: true })) {
92251
- const path3 = join31(current, entry.name);
92654
+ const path3 = join32(current, entry.name);
92252
92655
  if (entry.isDirectory()) {
92253
92656
  await walk4(path3);
92254
92657
  } else if (entry.name.endsWith(".md")) {
92255
- tree[relative4(dir, path3)] = await readFile22(path3, "utf8");
92658
+ tree[relative4(dir, path3)] = await readFile23(path3, "utf8");
92256
92659
  }
92257
92660
  }
92258
92661
  };
92259
92662
  await walk4(dir);
92260
92663
  let meta4;
92261
92664
  try {
92262
- meta4 = JSON.parse(await readFile22(join31(dir, "meta.json"), "utf8"));
92665
+ meta4 = JSON.parse(await readFile23(join32(dir, "meta.json"), "utf8"));
92263
92666
  } catch {
92264
92667
  meta4 = void 0;
92265
92668
  }
@@ -92267,7 +92670,7 @@ async function readTree(dir) {
92267
92670
  }
92268
92671
  async function updateTreeMeta(dir, patch) {
92269
92672
  const { meta: meta4 } = await readTree(dir);
92270
- await writeFile11(join31(dir, "meta.json"), `${JSON.stringify({ ...meta4 ?? {}, ...patch }, null, 2)}
92673
+ await writeFile12(join32(dir, "meta.json"), `${JSON.stringify({ ...meta4 ?? {}, ...patch }, null, 2)}
92271
92674
  `, "utf8");
92272
92675
  }
92273
92676
  async function proposeTree(options) {
@@ -92383,23 +92786,23 @@ var init_knowledge2 = __esm({
92383
92786
  });
92384
92787
 
92385
92788
  // ../../packages/evals/dist/evolve.js
92386
- import { mkdir as mkdir19, readFile as readFile23, writeFile as writeFile12 } from "node:fs/promises";
92387
- import { join as join32, resolve as resolve8 } from "node:path";
92789
+ import { mkdir as mkdir19, readFile as readFile24, writeFile as writeFile13 } from "node:fs/promises";
92790
+ import { join as join33, resolve as resolve8 } from "node:path";
92388
92791
  async function runEvolution(options) {
92389
92792
  const log = options.log ?? (() => void 0);
92390
92793
  const root = resolve8(options.resultsRoot);
92391
- const treesDir = join32(root, "trees");
92392
- const runsDir = join32(root, "runs");
92794
+ const treesDir = join33(root, "trees");
92795
+ const runsDir = join33(root, "runs");
92393
92796
  await mkdir19(treesDir, { recursive: true });
92394
92797
  await mkdir19(runsDir, { recursive: true });
92395
- const evidencePath = options.evidencePath ?? join32(root, "evidence", "crowdcode-evidence.json");
92798
+ const evidencePath = options.evidencePath ?? join33(root, "evidence", "crowdcode-evidence.json");
92396
92799
  const evidence = await fetchCrowdCodeEvidence({ cachePath: evidencePath, useCache: !options.refreshEvidence, log });
92397
92800
  const digest = renderEvidenceDigest(evidence, { detailTop: 90, maxPointsPerService: 9 });
92398
92801
  const evidenceHash = hashContent(digest);
92399
92802
  log(`evidence: ${evidence.stats.services} services, ${evidence.stats.reviews} reviews, digest ~${Math.round(digest.length / 4)} tokens`);
92400
92803
  const heldin = await loadTaskSet("heldin", { hfToken: options.hfToken, log });
92401
92804
  const proposer = await buildProposerProviders(root, options.proposerModels);
92402
- const archivePath = join32(root, "archive.json");
92805
+ const archivePath = join33(root, "archive.json");
92403
92806
  const archive = await readArchive(archivePath) ?? {
92404
92807
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
92405
92808
  agent_model: options.agentModel,
@@ -92407,9 +92810,9 @@ async function runEvolution(options) {
92407
92810
  entries: []
92408
92811
  };
92409
92812
  const save = async () => {
92410
- await writeFile12(archivePath, `${JSON.stringify(archive, null, 2)}
92813
+ await writeFile13(archivePath, `${JSON.stringify(archive, null, 2)}
92411
92814
  `, "utf8");
92412
- await writeFile12(join32(root, "frontier.md"), `${renderArchive(archive)}
92815
+ await writeFile13(join33(root, "frontier.md"), `${renderArchive(archive)}
92413
92816
  `, "utf8");
92414
92817
  };
92415
92818
  const evaluate = async (entry, knowledgeDir) => {
@@ -92436,7 +92839,7 @@ async function runEvolution(options) {
92436
92839
  if (!archive.entries.some((entry) => entry.id === "baseline")) {
92437
92840
  const baseline = { id: "baseline", generation: 0, children: 0, status: "evaluated" };
92438
92841
  if (options.baselineReport) {
92439
- const report = JSON.parse(await readFile23(options.baselineReport, "utf8"));
92842
+ const report = JSON.parse(await readFile24(options.baselineReport, "utf8"));
92440
92843
  const rows = report.rows.filter((row) => row.suite === "usage");
92441
92844
  baseline.report_dir = report.results_dir;
92442
92845
  baseline.metrics = metricsOfRows(rows);
@@ -92517,7 +92920,7 @@ async function runEvolution(options) {
92517
92920
  }
92518
92921
  const best = bestEntry(archive);
92519
92922
  if (best?.dir) {
92520
- await writeFile12(join32(root, "BEST"), `${best.dir}
92923
+ await writeFile13(join33(root, "BEST"), `${best.dir}
92521
92924
  `, "utf8");
92522
92925
  }
92523
92926
  await save();
@@ -92550,9 +92953,9 @@ async function proposeCandidate(input2) {
92550
92953
  log: input2.log
92551
92954
  });
92552
92955
  const validation = validateTree(proposal.tree, input2.evidence);
92553
- const dir = join32(input2.treesDir, id);
92956
+ const dir = join33(input2.treesDir, id);
92554
92957
  await mkdir19(dir, { recursive: true });
92555
- await writeFile12(join32(dir, "proposal.raw.txt"), proposal.rawResponse, "utf8");
92958
+ await writeFile13(join33(dir, "proposal.raw.txt"), proposal.rawResponse, "utf8");
92556
92959
  if (!validation.ok) {
92557
92960
  errors = validation.errors;
92558
92961
  input2.log(`${id}: invalid (${validation.errors.join("; ")})`);
@@ -92639,7 +93042,7 @@ function metricsOfRows(rows) {
92639
93042
  };
92640
93043
  }
92641
93044
  async function casesFromReport(reportDir) {
92642
- const report = JSON.parse(await readFile23(join32(reportDir, "report.json"), "utf8"));
93045
+ const report = JSON.parse(await readFile24(join33(reportDir, "report.json"), "utf8"));
92643
93046
  const cases = [];
92644
93047
  for (const row of report.rows) {
92645
93048
  cases.push({
@@ -92660,7 +93063,7 @@ async function casesFromReport(reportDir) {
92660
93063
  async function summarizeTrajectory(path3) {
92661
93064
  let text;
92662
93065
  try {
92663
- text = await readFile23(path3, "utf8");
93066
+ text = await readFile24(path3, "utf8");
92664
93067
  } catch {
92665
93068
  return void 0;
92666
93069
  }
@@ -92692,7 +93095,7 @@ async function summarizeTrajectory(path3) {
92692
93095
  return steps.length > 0 ? steps.join(" -> ") : void 0;
92693
93096
  }
92694
93097
  async function buildProposerProviders(root, models) {
92695
- const session = await createOpenCrowdSession({ workspaceRoot: join32(root, "proposer"), approvalMode: "auto", shellEnabled: false });
93098
+ const session = await createOpenCrowdSession({ workspaceRoot: join33(root, "proposer"), approvalMode: "auto", shellEnabled: false });
92696
93099
  const providers = /* @__PURE__ */ new Map();
92697
93100
  for (const model of new Set(models)) {
92698
93101
  const llm = await resolveLlmRuntime(session, { model, subagentModel: "off", nonInteractive: true });
@@ -92709,7 +93112,7 @@ async function buildProposerProviders(root, models) {
92709
93112
  }
92710
93113
  async function readArchive(path3) {
92711
93114
  try {
92712
- return JSON.parse(await readFile23(path3, "utf8"));
93115
+ return JSON.parse(await readFile24(path3, "utf8"));
92713
93116
  } catch {
92714
93117
  return void 0;
92715
93118
  }
@@ -92854,8 +93257,8 @@ init_dist2();
92854
93257
  init_dist4();
92855
93258
  init_dist6();
92856
93259
  init_shared();
92857
- import { copyFile as copyFile2, mkdir as mkdir20, readFile as readFile24, rm as rm3 } from "node:fs/promises";
92858
- import { basename as basename2, join as join33 } from "node:path";
93260
+ import { copyFile as copyFile2, mkdir as mkdir20, readFile as readFile25, rm as rm3 } from "node:fs/promises";
93261
+ import { basename as basename2, join as join34 } from "node:path";
92859
93262
  import { createInterface as createInterface2 } from "node:readline/promises";
92860
93263
  import { stdin as input, stdout as output2 } from "node:process";
92861
93264
 
@@ -93228,14 +93631,14 @@ function parseUsdCents(data) {
93228
93631
  var BASE_USDC_CONTRACT = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
93229
93632
  var BASE_CHAIN_ID2 = 8453;
93230
93633
  var SUGGESTED_FUND_CENTS = 2e3;
93231
- function usdcUnits(cents) {
93232
- return BigInt(Math.max(0, Math.round(cents))) * 10000n;
93634
+ function usdcUnits(cents2) {
93635
+ return BigInt(Math.max(0, Math.round(cents2))) * 10000n;
93233
93636
  }
93234
- function usdcTransferUri(address2, cents) {
93235
- return `ethereum:${BASE_USDC_CONTRACT}@${BASE_CHAIN_ID2}/transfer?address=${address2}&uint256=${usdcUnits(cents)}`;
93637
+ function usdcTransferUri(address2, cents2) {
93638
+ return `ethereum:${BASE_USDC_CONTRACT}@${BASE_CHAIN_ID2}/transfer?address=${address2}&uint256=${usdcUnits(cents2)}`;
93236
93639
  }
93237
- function metamaskDeepLink(address2, cents) {
93238
- return `https://metamask.app.link/send/${BASE_USDC_CONTRACT}@${BASE_CHAIN_ID2}/transfer?address=${address2}&uint256=${usdcUnits(cents)}`;
93640
+ function metamaskDeepLink(address2, cents2) {
93641
+ return `https://metamask.app.link/send/${BASE_USDC_CONTRACT}@${BASE_CHAIN_ID2}/transfer?address=${address2}&uint256=${usdcUnits(cents2)}`;
93239
93642
  }
93240
93643
  async function qrTerminal(text) {
93241
93644
  const { toString: toString3 } = await import("qrcode");
@@ -93612,7 +94015,7 @@ function indent(text) {
93612
94015
 
93613
94016
  // src/tui/app.tsx
93614
94017
  init_dist2();
93615
- import { join as join24 } from "node:path";
94018
+ import { join as join25 } from "node:path";
93616
94019
  import { randomUUID as randomUUID9 } from "node:crypto";
93617
94020
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
93618
94021
  import { Box, render, Static, Text, useApp, useInput, usePaste, useStdout } from "ink";
@@ -93652,7 +94055,7 @@ function App({ session: initialSession, initialTestMode, initialTestSeed, defaul
93652
94055
  const runningRef = useRef(false);
93653
94056
  const inboxPausedRef = useRef(false);
93654
94057
  const [inboxRevision, setInboxRevision] = useState(0);
93655
- const inbox = useMemo(() => new FileSteeringInbox(join24(session.sessionDir, "inbox.json")), [session.sessionDir]);
94058
+ const inbox = useMemo(() => new FileSteeringInbox(join25(session.sessionDir, "inbox.json")), [session.sessionDir]);
93656
94059
  const [activity, setActivity] = useState("");
93657
94060
  const [spinnerFrame, setSpinnerFrame] = useState(0);
93658
94061
  const [modal, setModal] = useState(null);
@@ -93729,11 +94132,11 @@ function App({ session: initialSession, initialTestMode, initialTestSeed, defaul
93729
94132
  const poll2 = async () => {
93730
94133
  try {
93731
94134
  const summary = await walletSummary();
93732
- const cents = summary.totalCents ?? Number.NaN;
93733
- if (cancelled || !Number.isFinite(cents)) {
94135
+ const cents2 = summary.totalCents ?? Number.NaN;
94136
+ if (cancelled || !Number.isFinite(cents2)) {
93734
94137
  return;
93735
94138
  }
93736
- if (cents > 0) {
94139
+ if (cents2 > 0) {
93737
94140
  const budgetCents = session.budgetCents;
93738
94141
  if (!cancelled) {
93739
94142
  setWizard({ step: "done", funded: true, budgetCents });
@@ -93741,7 +94144,7 @@ function App({ session: initialSession, initialTestMode, initialTestSeed, defaul
93741
94144
  }
93742
94145
  return;
93743
94146
  }
93744
- setWizard((current) => current?.step === "fund" ? { ...current, balanceCents: Math.max(0, cents) } : current);
94147
+ setWizard((current) => current?.step === "fund" ? { ...current, balanceCents: Math.max(0, cents2) } : current);
93745
94148
  } catch {
93746
94149
  }
93747
94150
  };
@@ -94030,9 +94433,9 @@ function App({ session: initialSession, initialTestMode, initialTestSeed, defaul
94030
94433
  if (modal.budget !== void 0) {
94031
94434
  if (isReturn) {
94032
94435
  try {
94033
- const cents = parseUsd(modal.budget);
94034
- if (cents <= modal.request.queryLimitCents || cents < modal.request.projectedCents) throw new Error("Enter a higher budget covering this call and committed spending.");
94035
- modal.resolve({ decision: "approve", queryBudgetCents: cents });
94436
+ const cents2 = parseUsd(modal.budget);
94437
+ if (cents2 <= modal.request.queryLimitCents || cents2 < modal.request.projectedCents) throw new Error("Enter a higher budget covering this call and committed spending.");
94438
+ modal.resolve({ decision: "approve", queryBudgetCents: cents2 });
94036
94439
  } catch (e6) {
94037
94440
  push({ kind: "error", text: e6.message });
94038
94441
  }
@@ -94511,7 +94914,7 @@ async function main(argv) {
94511
94914
  case "--version":
94512
94915
  case "-v":
94513
94916
  case "version": {
94514
- const pkg2 = JSON.parse(await readFile24(new URL("../package.json", import.meta.url), "utf8"));
94917
+ const pkg2 = JSON.parse(await readFile25(new URL("../package.json", import.meta.url), "utf8"));
94515
94918
  console.log(pkg2.version);
94516
94919
  return;
94517
94920
  }
@@ -94617,10 +95020,10 @@ async function headlessRunCommand(args) {
94617
95020
  if (attach) {
94618
95021
  const attachmentName = basename2(attach);
94619
95022
  await mkdir20(session.artifactsDir, { recursive: true });
94620
- await copyFile2(attach, join33(session.artifactsDir, attachmentName));
95023
+ await copyFile2(attach, join34(session.artifactsDir, attachmentName));
94621
95024
  task = `${prompt}
94622
95025
 
94623
- An input file is available at the session artifact path \`${attachmentName}\` (use read_file, or run_shell against ${join33(session.artifactsDir, attachmentName)}).`;
95026
+ An input file is available at the session artifact path \`${attachmentName}\` (use read_file, or run_shell against ${join34(session.artifactsDir, attachmentName)}).`;
94624
95027
  }
94625
95028
  const result = await runPersistentAgentTaskDetailed(session, task, {
94626
95029
  model: readOption(args, "--model"),
@@ -94644,7 +95047,7 @@ An input file is available at the session artifact path \`${attachmentName}\` (u
94644
95047
  final_message: result.summary.final_message ?? null,
94645
95048
  session_id: session.sessionId,
94646
95049
  session_dir: session.sessionDir,
94647
- trajectory_path: join33(session.sessionDir, "messages.jsonl"),
95050
+ trajectory_path: join34(session.sessionDir, "messages.jsonl"),
94648
95051
  turns: result.turns,
94649
95052
  model_policy: session.models ?? null,
94650
95053
  usdc_spent_cents: {
@@ -94736,7 +95139,7 @@ async function ledgerCommand(args) {
94736
95139
  if (!sessionId) {
94737
95140
  throw new Error("no local sessions found");
94738
95141
  }
94739
- const rows = await readLedger(join33(process.cwd(), "sessions", sessionId, "ledger.csv"));
95142
+ const rows = await readLedger(join34(process.cwd(), "sessions", sessionId, "ledger.csv"));
94740
95143
  printValue("Ledger", rows, {
94741
95144
  json: json3,
94742
95145
  pretty: renderTable(rows.map(asRecord), [
@@ -94773,7 +95176,7 @@ async function resumeCommand(args) {
94773
95176
  } catch (e6) {
94774
95177
  if (!(e6 instanceof SpendingDeclined)) throw e6;
94775
95178
  }
94776
- await rm3(join33(session.sessionDir, "query-checkpoint.json"), { force: true });
95179
+ await rm3(join34(session.sessionDir, "query-checkpoint.json"), { force: true });
94777
95180
  console.log("Query declined. Nothing was paid for the pending call.");
94778
95181
  return;
94779
95182
  }
@@ -94925,7 +95328,7 @@ async function evalsSuiteCommand(rest) {
94925
95328
  const report = await runSuite2({
94926
95329
  set: set3,
94927
95330
  harness: readOption(rest, "--harness") ?? "opencrowd",
94928
- resultsRoot: readOption(rest, "--out") ?? join33(process.cwd(), "evals", "suite"),
95331
+ resultsRoot: readOption(rest, "--out") ?? join34(process.cwd(), "evals", "suite"),
94929
95332
  tag: readOption(rest, "--tag"),
94930
95333
  knowledgeDir: readOption(rest, "--knowledge"),
94931
95334
  hfToken: readOption(rest, "--hf-token") ?? process.env.HF_TOKEN,
@@ -94944,7 +95347,7 @@ async function evalsSuiteCommand(rest) {
94944
95347
  async function evalsEvolveCommand(rest) {
94945
95348
  const { runEvolution: runEvolution2, renderArchive: renderArchive2 } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
94946
95349
  const { archive, best } = await runEvolution2({
94947
- resultsRoot: readOption(rest, "--out") ?? join33(process.cwd(), "evals", "evolve"),
95350
+ resultsRoot: readOption(rest, "--out") ?? join34(process.cwd(), "evals", "evolve"),
94948
95351
  evidencePath: readOption(rest, "--evidence"),
94949
95352
  refreshEvidence: rest.includes("--refresh-evidence"),
94950
95353
  generations: Number(readOption(rest, "--generations") ?? 2),