@lucid-agents/taskmarket 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  signReadAuth,
15
15
  submitTaskFiles,
16
16
  taskAccessGrantHeaders
17
- } from "./chunk-7MXTPGES.js";
17
+ } from "./chunk-4WQPXCKL.js";
18
18
  import {
19
19
  ComputeCreditError,
20
20
  applyComputeCreditSetup,
@@ -36,7 +36,7 @@ import {
36
36
  refusedPaidWrite,
37
37
  releasePendingComputePurchase,
38
38
  resolvePendingComputePurchases
39
- } from "./chunk-RSSJD6JU.js";
39
+ } from "./chunk-MLFKB6XH.js";
40
40
  import {
41
41
  MPP_TEMPO_DEFAULT_VALIDITY_SECONDS,
42
42
  X402PayError,
@@ -53,16 +53,18 @@ import {
53
53
  loadX402Policy,
54
54
  removeX402PolicyRule,
55
55
  resolveX402PaymentManually,
56
+ selectTaskmarketFeeRequirement,
56
57
  setX402PolicyRuleEnabled,
57
58
  signMessage,
58
59
  signSponsoredTempoTransfer,
59
60
  signTaskmarketFeePayment,
60
61
  signTypedData
61
- } from "./chunk-BO3XPXQ6.js";
62
+ } from "./chunk-D6ODOHET.js";
62
63
  import {
63
64
  ActivityFeedInputSchema,
64
65
  ActivityHeatmapInputSchema,
65
66
  ActorType,
67
+ AgentChainsResponseSchema,
66
68
  AgentMessageEnvelopeSchema,
67
69
  AgentTimeSeriesInputSchema,
68
70
  ApiError,
@@ -73,6 +75,7 @@ import {
73
75
  CrossChainFundingConfigOutputSchema,
74
76
  DEFAULT_EVALUATION_WINDOW_HOURS,
75
77
  DEFAULT_TERMS_BOUNDS,
78
+ EthAddressSchema,
76
79
  HookGetInputSchema,
77
80
  HookIndexInputSchema,
78
81
  IntentStatusResponseSchema,
@@ -83,6 +86,7 @@ import {
83
86
  LegalStatusResponseSchema,
84
87
  NETWORKS,
85
88
  NETWORK_NAMES,
89
+ NetworkInfoSchema,
86
90
  NetworkRequiredError,
87
91
  PUBLIC_BUG_REPORT_SORTS,
88
92
  PenaltyTo,
@@ -95,6 +99,7 @@ import {
95
99
  RejectOutcome,
96
100
  RelayBridgeFundingConfigOutputSchema,
97
101
  RelayBridgeRouteIdSchema,
102
+ STANDARD_X402_ACTION_AMOUNT,
98
103
  SponsoredTaskRewardStateSchema,
99
104
  SponsoredTaskWorkerRewardClaimStatusSchema,
100
105
  SubmissionReviewAssessmentInputSchema,
@@ -192,7 +197,7 @@ import {
192
197
  withChainId,
193
198
  withErrorContext,
194
199
  withIdempotentWrite
195
- } from "./chunk-H2HOWIJ6.js";
200
+ } from "./chunk-H554XEEE.js";
196
201
  import {
197
202
  channelLines
198
203
  } from "./chunk-XJOB4NMV.js";
@@ -277,10 +282,19 @@ function readLastError() {
277
282
  }
278
283
 
279
284
  // src/lib/output.ts
285
+ function cliWarning(code, message, details) {
286
+ return { ...details, code, message };
287
+ }
280
288
  function printResult(data, options) {
281
289
  const idempotencyKey = options?.idempotencyKey;
290
+ const warnings = options?.warnings ?? [];
282
291
  console.log(
283
- JSON.stringify({ ok: true, data, ...idempotencyKey !== void 0 ? { idempotencyKey } : {} })
292
+ JSON.stringify({
293
+ ok: true,
294
+ data,
295
+ ...idempotencyKey !== void 0 ? { idempotencyKey } : {},
296
+ ...warnings.length > 0 ? { warnings } : {}
297
+ })
284
298
  );
285
299
  }
286
300
  function x402FailureFields(error) {
@@ -329,9 +343,6 @@ function renderFailure(error, options) {
329
343
  function printError(message, options) {
330
344
  return renderFailure(new Error(message), options);
331
345
  }
332
- function printWarning(message) {
333
- process.stderr.write(JSON.stringify({ ok: false, error: message }) + "\n");
334
- }
335
346
 
336
347
  // src/lib/agent.ts
337
348
  function legacyAgentIdChain(keystore) {
@@ -646,7 +657,7 @@ function sanitizeEmailUsername(agentId, suffix) {
646
657
  const candidate = `${base}-${suffix}`;
647
658
  return /^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$/.test(candidate) ? candidate : null;
648
659
  }
649
- async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
660
+ async function tryRegisterEmail(deviceId, apiToken, username, explicit, warnings) {
650
661
  try {
651
662
  const { data: reg } = await apiPost("/api/emails/register", {
652
663
  deviceId,
@@ -657,8 +668,12 @@ async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
657
668
  } catch (err) {
658
669
  if (explicit) {
659
670
  const msg = err instanceof Error ? err.message : String(err);
660
- printWarning(
661
- `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
671
+ warnings.push(
672
+ cliWarning(
673
+ "email_registration_failed",
674
+ `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`,
675
+ { username, retryCommand: `taskmarket email register --username ${username}` }
676
+ )
662
677
  );
663
678
  }
664
679
  return null;
@@ -776,7 +791,8 @@ var initCommand = new Command2("init").description(
776
791
  } catch {
777
792
  }
778
793
  const username = opts.email ?? (agentId && networkInfo ? sanitizeEmailUsername(agentId, String(selectedNetwork().chainId)) : null);
779
- const emailAddress = username ? await tryRegisterEmail(deviceId, apiToken, username, !!opts.email) : null;
794
+ const warnings = [];
795
+ const emailAddress = username ? await tryRegisterEmail(deviceId, apiToken, username, !!opts.email, warnings) : null;
780
796
  let chain;
781
797
  try {
782
798
  chain = chainInfoFor(networkInfo, selectedNetwork().chainId);
@@ -784,15 +800,18 @@ var initCommand = new Command2("init").description(
784
800
  renderFailure(err);
785
801
  return;
786
802
  }
787
- printResult({
788
- address,
789
- agentId,
790
- network: chain?.networkName ?? networkInfo?.networkName,
791
- chainId: chain?.chainId ?? networkInfo?.chainId,
792
- paymentMethod: chain?.paymentMethod,
793
- feeModel: chain?.feeModel,
794
- emailAddress
795
- });
803
+ printResult(
804
+ {
805
+ address,
806
+ agentId,
807
+ network: chain?.networkName ?? networkInfo?.networkName,
808
+ chainId: chain?.chainId ?? networkInfo?.chainId,
809
+ paymentMethod: chain?.paymentMethod,
810
+ feeModel: chain?.feeModel,
811
+ emailAddress
812
+ },
813
+ { warnings }
814
+ );
796
815
  });
797
816
 
798
817
  // src/commands/address.ts
@@ -1469,6 +1488,9 @@ var reviewCmd = createReviewCommand();
1469
1488
  import { Command as Command8 } from "commander";
1470
1489
  import { parseUnits } from "viem";
1471
1490
 
1491
+ // src/lib/fee-ceiling.ts
1492
+ var TASKMARKET_FEE_DEFAULT_CEILING = (BigInt(STANDARD_X402_ACTION_AMOUNT) * 2n).toString();
1493
+
1472
1494
  // src/lib/x402.ts
1473
1495
  var FACILITATOR_RETRIES = 2;
1474
1496
  var MAX_RETRY_AFTER_SECONDS = 60;
@@ -1500,10 +1522,12 @@ async function x402Post(path3, body, options) {
1500
1522
  throw refusedPaidWrite(path3, r1.status, await readFailureBody(r1), idempotencyKey);
1501
1523
  }
1502
1524
  const requirements = await r1.json();
1503
- if (!requirements.accepts || requirements.accepts.length === 0) {
1504
- throw new Error("No payment methods accepted by server");
1505
- }
1506
- const accept = requirements.accepts[0];
1525
+ const chain = taskmarketChain(selectedNetwork().chainId);
1526
+ const accept = selectTaskmarketFeeRequirement(requirements.accepts, {
1527
+ network: chain.caip2,
1528
+ asset: chain.payment.token,
1529
+ maxAmount: options?.maxAmount ?? TASKMARKET_FEE_DEFAULT_CEILING
1530
+ });
1507
1531
  const { header } = await signTaskmarketFeePayment({
1508
1532
  resource: requirements.resource,
1509
1533
  requirement: accept,
@@ -1529,6 +1553,42 @@ async function x402Post(path3, body, options) {
1529
1553
  });
1530
1554
  }
1531
1555
 
1556
+ // src/lib/hook-registry.ts
1557
+ async function fetchHookRegistry(address) {
1558
+ const query3 = address ? `?address=${address}` : "";
1559
+ return await apiGet(withChainId(`/api/hooks/registry${query3}`));
1560
+ }
1561
+ async function describeHookListings(hooks, alwaysListed = []) {
1562
+ if (hooks.length === 0) return { hooks: [], warnings: [] };
1563
+ let registry;
1564
+ try {
1565
+ registry = await fetchHookRegistry();
1566
+ if (!registry || !Array.isArray(registry.listed)) return null;
1567
+ } catch {
1568
+ return null;
1569
+ }
1570
+ const listed = new Map(registry.listed.map((entry) => [entry.address.toLowerCase(), entry]));
1571
+ const implicit = new Set(alwaysListed.map((address) => address.toLowerCase()));
1572
+ const listings = [];
1573
+ const warnings = [];
1574
+ for (const raw of hooks) {
1575
+ const address = raw.toLowerCase();
1576
+ const entry = listed.get(address);
1577
+ const isListed = entry !== void 0 || implicit.has(address);
1578
+ listings.push({ address, listed: isListed, name: entry?.name ?? null });
1579
+ if (!isListed) {
1580
+ warnings.push(
1581
+ cliWarning(
1582
+ "hook_unlisted",
1583
+ `Hook ${address} is not listed in the hook registry for chain ${registry.chainId}. It was attached as given; run \`taskmarket hooks list\` for listed hooks.`,
1584
+ { address, chainId: registry.chainId }
1585
+ )
1586
+ );
1587
+ }
1588
+ }
1589
+ return { hooks: listings, warnings };
1590
+ }
1591
+
1532
1592
  // src/lib/settlement-terms.ts
1533
1593
  var TERM_FLAGS = {
1534
1594
  stakeRequired: "--stake-required",
@@ -1682,6 +1742,51 @@ function parseStakeOptions(opts) {
1682
1742
  }
1683
1743
  return { stakeRequired: true, stakeBps };
1684
1744
  }
1745
+ var METRIC_DESCRIPTION_MAX = 500;
1746
+ var METRIC_TARGET_MAX = 200;
1747
+ var TASK_DROP_NAME_MAX = 80;
1748
+ var TASK_DROP_DESCRIPTION_MAX = 500;
1749
+ function parseMetricAndDropOptions(opts) {
1750
+ const fields = {};
1751
+ for (const [flag, value, max, key] of [
1752
+ ["--metric-description", opts.metricDescription, METRIC_DESCRIPTION_MAX, "metricDescription"],
1753
+ ["--metric-target", opts.metricTarget, METRIC_TARGET_MAX, "metricTarget"]
1754
+ ]) {
1755
+ if (value === void 0) continue;
1756
+ if (opts.mode !== "benchmark") {
1757
+ return { error: `${flag} is only valid with --mode benchmark` };
1758
+ }
1759
+ if (!value.trim()) return { error: `${flag} must not be empty` };
1760
+ if (value.length > max) return { error: `${flag} must be at most ${max} characters` };
1761
+ fields[key] = value;
1762
+ }
1763
+ if (opts.taskDrop !== void 0 && opts.newTaskDrop !== void 0) {
1764
+ return { error: "--task-drop and --new-task-drop cannot be combined" };
1765
+ }
1766
+ if (opts.newTaskDropDescription !== void 0 && opts.newTaskDrop === void 0) {
1767
+ return { error: "--new-task-drop-description requires --new-task-drop" };
1768
+ }
1769
+ if (opts.taskDrop !== void 0) {
1770
+ const taskDropId = opts.taskDrop.trim();
1771
+ if (!taskDropId) return { error: "--task-drop must not be empty" };
1772
+ fields.taskDropId = taskDropId;
1773
+ }
1774
+ if (opts.newTaskDrop !== void 0) {
1775
+ const name = opts.newTaskDrop.trim();
1776
+ if (!name) return { error: "--new-task-drop must not be empty" };
1777
+ if (name.length > TASK_DROP_NAME_MAX) {
1778
+ return { error: `--new-task-drop must be at most ${TASK_DROP_NAME_MAX} characters` };
1779
+ }
1780
+ const description = opts.newTaskDropDescription?.trim();
1781
+ if (description && description.length > TASK_DROP_DESCRIPTION_MAX) {
1782
+ return {
1783
+ error: `--new-task-drop-description must be at most ${TASK_DROP_DESCRIPTION_MAX} characters`
1784
+ };
1785
+ }
1786
+ fields.taskDropCreate = description ? { name, description } : { name };
1787
+ }
1788
+ return { fields };
1789
+ }
1685
1790
  var createCmd = new Command8("create").description("Create a new task (costs the reward, in the payment token)").requiredOption("--description <text>", "Task description").requiredOption("--reward <amount>", "Reward in the payment token (e.g. 5)").requiredOption("--duration <hours>", "Task duration in hours").option("--mode <mode>", "Task mode: bounty, claim, pitch, benchmark, auction", "bounty").option(
1686
1791
  "--task-visibility <mode>",
1687
1792
  "Task visibility: public (default), unlisted, or private. Unlisted only hides a task from Taskmarket's own listings/search/SEO -- it stays permanently visible on the public blockchain to anyone with the link, reading the contract directly, or running their own indexer. private is genuinely access-controlled: only the requester and invited/assigned workers can view it via listings, get, or the gated reads -- see --allowed-viewers and --access-password. Even private, the on-chain existence, reward, and participation stay publicly observable regardless.",
@@ -1696,7 +1801,22 @@ var createCmd = new Command8("create").description("Create a new task (costs the
1696
1801
  "--submission-visibility <mode>",
1697
1802
  "Submission visibility: public (default), reveal_all, winner_only, or never. Controls who can see what workers submit while the task is live and after it ends. public matches today's behavior exactly. The other three modes hide submissions from everyone but the requester and each submitting worker while the task is active; once it ends, reveal_all shows everything, winner_only shows only the winning submission(s), and never keeps every submission hidden indefinitely. Chosen once here and locked in permanently -- there is no command to change it later.",
1698
1803
  "public"
1699
- ).option("--tags <tags>", "Comma-separated tags").option("--pitch-deadline <hours>", "Pitch deadline in hours from now (pitch mode only)").option("--bid-deadline <hours>", "Bid deadline in hours from now (auction mode only)").option(
1804
+ ).option("--tags <tags>", "Comma-separated tags").option(
1805
+ "--metric-description <text>",
1806
+ 'Benchmark metric workers are ranked on, e.g. "Test suite pass rate" (benchmark mode only, max 500 characters)'
1807
+ ).option(
1808
+ "--metric-target <value>",
1809
+ "Target value for the benchmark metric, e.g. 98 (benchmark mode only, max 200 characters)"
1810
+ ).option(
1811
+ "--task-drop <dropId>",
1812
+ "Add the task to a Task Drop you own; its subscribers are emailed when the task is published. See `taskmarket drops`."
1813
+ ).option(
1814
+ "--new-task-drop <name>",
1815
+ "Create a new Task Drop with this name (max 80 characters) and add the task to it. Cannot be combined with --task-drop."
1816
+ ).option(
1817
+ "--new-task-drop-description <text>",
1818
+ "Description for the --new-task-drop drop (optional, max 500 characters)"
1819
+ ).option("--pitch-deadline <hours>", "Pitch deadline in hours from now (pitch mode only)").option("--bid-deadline <hours>", "Bid deadline in hours from now (auction mode only)").option(
1700
1820
  "--max-price <amount>",
1701
1821
  "Maximum bid price in the payment token (required for auction mode)"
1702
1822
  ).option(
@@ -1710,7 +1830,7 @@ var createCmd = new Command8("create").description("Create a new task (costs the
1710
1830
  "Floor price in the payment token for dutch clock (required for dutch)"
1711
1831
  ).option(
1712
1832
  "--hook <address>",
1713
- "Custom ITMPHook contract address (repeat in execution order; protocol defaults run first)",
1833
+ "Custom ITMPHook contract address (repeat in execution order; protocol defaults run first). Run `taskmarket hooks list` for hooks listed (verified) in the hook registry; an unlisted address is still attached, with a hook_unlisted warning",
1714
1834
  (value, previous = []) => [...previous, value],
1715
1835
  []
1716
1836
  ).option(
@@ -1860,6 +1980,10 @@ var createCmd = new Command8("create").description("Create a new task (costs the
1860
1980
  );
1861
1981
  }
1862
1982
  }
1983
+ const metricAndDrop = parseMetricAndDropOptions(opts);
1984
+ if ("error" in metricAndDrop) {
1985
+ return void printError(metricAndDrop.error);
1986
+ }
1863
1987
  const stakeFlags = parseStakeOptions(opts);
1864
1988
  if ("error" in stakeFlags) {
1865
1989
  return void printError(stakeFlags.error);
@@ -1885,6 +2009,7 @@ var createCmd = new Command8("create").description("Create a new task (costs the
1885
2009
  if (opts.accessPassword) {
1886
2010
  body.accessPassword = opts.accessPassword;
1887
2011
  }
2012
+ Object.assign(body, metricAndDrop.fields);
1888
2013
  if (opts.pitchDeadline) {
1889
2014
  body.pitchDeadline = parseInt(opts.pitchDeadline, 10) * 3600;
1890
2015
  }
@@ -2082,6 +2207,10 @@ var createCmd = new Command8("create").description("Create a new task (costs the
2082
2207
  } catch {
2083
2208
  }
2084
2209
  }
2210
+ const hookListings = await describeHookListings(
2211
+ hooks,
2212
+ sponsoredTaskHookAddress ? [sponsoredTaskHookAddress] : []
2213
+ );
2085
2214
  let feeBps;
2086
2215
  if (opts.evaluator) {
2087
2216
  if (!ethAddrRe.test(opts.evaluator)) {
@@ -2113,22 +2242,53 @@ var createCmd = new Command8("create").description("Create a new task (costs the
2113
2242
  if (opts.appealWindow) body.appealWindowHours = parseFloat(opts.appealWindow);
2114
2243
  if (opts.disputeResolver) body.disputeResolver = opts.disputeResolver;
2115
2244
  }
2116
- const { data: result, idempotencyKey } = await x402Post("/api/tasks", body);
2245
+ const { data: result, idempotencyKey } = await x402Post("/api/tasks", body, {
2246
+ // Creating a task pays the reward plus any evaluator stake, exactly; never more.
2247
+ maxAmount: (BigInt(String(body.reward)) + BigInt(String(body.evaluatorStake ?? "0"))).toString()
2248
+ });
2117
2249
  const terms = result.terms ?? resolvedTerms;
2118
2250
  printResult(
2119
2251
  {
2120
2252
  taskId: result.taskId,
2121
2253
  terms,
2122
2254
  termsPreset: termsPresetLabel(terms),
2123
- ...evaluatorStaked ? { evaluatorStake: evaluatorStakeBaseUnits } : {}
2255
+ ...result.taskDropId ? { taskDropId: result.taskDropId } : {},
2256
+ ...evaluatorStaked ? { evaluatorStake: evaluatorStakeBaseUnits } : {},
2257
+ ...hookListings && hookListings.hooks.length > 0 ? { hooks: hookListings.hooks } : {}
2124
2258
  },
2125
- { idempotencyKey }
2259
+ {
2260
+ idempotencyKey,
2261
+ ...hookListings && hookListings.warnings.length > 0 ? { warnings: hookListings.warnings } : {}
2262
+ }
2126
2263
  );
2127
2264
  }
2128
2265
  );
2129
2266
 
2130
2267
  // src/commands/task/search.ts
2131
2268
  import { Command as Command9 } from "commander";
2269
+
2270
+ // src/lib/chain-name.ts
2271
+ function chainDisplayName(chainId) {
2272
+ return isTaskmarketChainId(chainId) ? taskmarketChain(chainId).name : `Chain ${chainId}`;
2273
+ }
2274
+ function withChainNames(value) {
2275
+ if (Array.isArray(value)) return value.map((item) => withChainNames(item));
2276
+ if (value === null || typeof value !== "object") return value;
2277
+ const proto = Object.getPrototypeOf(value);
2278
+ if (proto !== Object.prototype && proto !== null) return value;
2279
+ const record = value;
2280
+ const chainId = record.chainId;
2281
+ const named = typeof chainId === "number" && Number.isInteger(chainId);
2282
+ const out = {};
2283
+ for (const [key, field] of Object.entries(record)) {
2284
+ if (key === "chainName" && named) continue;
2285
+ out[key] = withChainNames(field);
2286
+ if (key === "chainId" && named) out.chainName = chainDisplayName(chainId);
2287
+ }
2288
+ return out;
2289
+ }
2290
+
2291
+ // src/commands/task/search.ts
2132
2292
  var listCmd = new Command9("list").alias("search").description("List available tasks").option("--status <status>", "Filter by status (e.g. open)", "open").option(
2133
2293
  "--phase <phase>",
2134
2294
  "Filter by derived lifecycle phase (active, in_review, awaiting_settlement, resolved) -- independent of --status, e.g. --phase awaiting_settlement finds tasks whose deadline has passed but are still open/claimed/worker_selected"
@@ -2150,7 +2310,11 @@ var listCmd = new Command9("list").alias("search").description("List available t
2150
2310
  limit: opts.limit,
2151
2311
  cursor: opts.cursor
2152
2312
  });
2153
- printResult({ tasks: result.tasks, hasMore: result.hasMore, nextCursor: result.nextCursor });
2313
+ printResult({
2314
+ tasks: withChainNames(result.tasks),
2315
+ hasMore: result.hasMore,
2316
+ nextCursor: result.nextCursor
2317
+ });
2154
2318
  }
2155
2319
  );
2156
2320
 
@@ -2164,7 +2328,7 @@ var getCmd = new Command10("get").description("Get task details").argument("<tas
2164
2328
  );
2165
2329
  return;
2166
2330
  }
2167
- printResult({ ...task, ...await termsAmountsAndDeadlines(taskId) });
2331
+ printResult(withChainNames({ ...task, ...await termsAmountsAndDeadlines(taskId) }));
2168
2332
  });
2169
2333
  async function termsAmountsAndDeadlines(taskId) {
2170
2334
  try {
@@ -2567,7 +2731,7 @@ var submissionsCmd = new Command23("submissions").description("List submissions
2567
2731
  renderFailure(err, { fallback: "Failed to fetch submissions." });
2568
2732
  return;
2569
2733
  }
2570
- printResult(subs);
2734
+ printResult(withChainNames(subs));
2571
2735
  });
2572
2736
 
2573
2737
  // src/commands/task/select-winner.ts
@@ -2854,7 +3018,7 @@ import { Command as Command31 } from "commander";
2854
3018
  var mySubmissionsCmd = new Command31("my-submissions").description("List all submissions made by your wallet across all tasks.").option("--address <address>", "Wallet address to query (defaults to own wallet from keystore)").action(async (opts) => {
2855
3019
  try {
2856
3020
  const result = await listWorkerSubmissions(cliTaskReadContext(), { address: opts.address });
2857
- printResult(result);
3021
+ printResult(withChainNames(result));
2858
3022
  } catch (err) {
2859
3023
  renderFailure(
2860
3024
  err instanceof TaskOperationError && err.code === "no_address" ? new Error("No address provided and no keystore found -- pass --address <address>.") : err
@@ -2945,7 +3109,12 @@ var updateCmd = new Command32("update").description("Update an open task (costs
2945
3109
  }
2946
3110
  const { data: result, idempotencyKey } = await x402Post(
2947
3111
  `/api/tasks/${taskId}/update`,
2948
- body
3112
+ body,
3113
+ ...body.reward === void 0 ? [] : [
3114
+ {
3115
+ maxAmount: (BigInt(TASKMARKET_FEE_DEFAULT_CEILING) + BigInt(String(body.reward))).toString()
3116
+ }
3117
+ ]
2949
3118
  );
2950
3119
  printResult(result, { idempotencyKey });
2951
3120
  }
@@ -3041,7 +3210,11 @@ var assignEvaluatorCmd = new Command34("assign-evaluator").description(
3041
3210
  }
3042
3211
  const { data: result, idempotencyKey } = await x402Post(
3043
3212
  `/api/tasks/${taskId}/evaluator`,
3044
- body
3213
+ body,
3214
+ // The action fee plus the stake this command just confirmed.
3215
+ {
3216
+ maxAmount: (BigInt(TASKMARKET_FEE_DEFAULT_CEILING) + BigInt(evaluatorStake)).toString()
3217
+ }
3045
3218
  );
3046
3219
  printResult(
3047
3220
  { ...result, ...await settleRecording(result, idempotencyKey) },
@@ -3644,7 +3817,7 @@ async function runAgentCommand(options) {
3644
3817
  try {
3645
3818
  const { assertAgentCompatibility } = await import("./compatibility-636WJOEX.js");
3646
3819
  const pi = assertAgentCompatibility();
3647
- const { runAgent } = await import("./launch-UUW34PHS.js");
3820
+ const { runAgent } = await import("./launch-LJPPWU53.js");
3648
3821
  result = await runAgent({
3649
3822
  model: options.model,
3650
3823
  pi,
@@ -3703,13 +3876,13 @@ function agentManagementCommands() {
3703
3876
  const status = new Command48("status").description(
3704
3877
  "Show the agent channels (locked, charged, refundable), purchases with an unknown outcome, the sandbox and compute credit. Reads only."
3705
3878
  ).option("--json", "Print the versioned JSON envelope").action(async (options) => {
3706
- const { collectAgentStatus, statusLines } = await import("./status-5AVXIFQJ.js");
3879
+ const { collectAgentStatus, statusLines } = await import("./status-I2JO7G7X.js");
3707
3880
  await run(options, () => collectAgentStatus(), statusLines);
3708
3881
  });
3709
3882
  const doctor = new Command48("doctor").description(
3710
3883
  "Check that the agent can start: Node and the bundled runtime, wallet and policy, channels, API, sandbox broker, host keys, xgate and RPC. Reads only."
3711
3884
  ).option("--json", "Print the versioned JSON envelope").action(async (options) => {
3712
- const { runDoctor, doctorLines } = await import("./doctor-MZUDBF4B.js");
3885
+ const { runDoctor, doctorLines } = await import("./doctor-VD2X6DWP.js");
3713
3886
  const report = await run(options, () => runDoctor(), doctorLines);
3714
3887
  if (report && !report.ok) process.exitCode = 1;
3715
3888
  });
@@ -3720,7 +3893,7 @@ function agentManagementCommands() {
3720
3893
  "Reconcile the open purchases of this channel, as status lists it; also reaches retired channels"
3721
3894
  ).option("--json", "Print the versioned JSON envelope").action(
3722
3895
  async (invocationId, options) => {
3723
- const { reconcileChannelPurchases, reconcileInvocation } = await import("./reconcile-NDPFPJEB.js");
3896
+ const { reconcileChannelPurchases, reconcileInvocation } = await import("./reconcile-MW5A3PCQ.js");
3724
3897
  const choice = { rail: options.rail, channel: options.channel };
3725
3898
  if (invocationId !== void 0) {
3726
3899
  await run(
@@ -3778,7 +3951,7 @@ function agentManagementCommands() {
3778
3951
  `Not a USDC amount: ${options.amount} (digits, at most 6 decimals)`
3779
3952
  );
3780
3953
  }
3781
- const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-NUZWFG26.js");
3954
+ const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-2CFKY3AB.js");
3782
3955
  const { rails } = await openAgentChannels();
3783
3956
  const result = await requestTopUp(selectRail(rails, options.rail), amount);
3784
3957
  return {
@@ -3802,8 +3975,8 @@ function agentManagementCommands() {
3802
3975
  async () => {
3803
3976
  await requireExperimental();
3804
3977
  const { AGENT_VIEW_VERSION } = await import("./budget-view-J6L7X6EY.js");
3805
- const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-NUZWFG26.js");
3806
- const { reconcileLeasedPurchase } = await import("./reconcile-NDPFPJEB.js");
3978
+ const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-2CFKY3AB.js");
3979
+ const { reconcileLeasedPurchase } = await import("./reconcile-MW5A3PCQ.js");
3807
3980
  const opened = await openAgentChannels();
3808
3981
  const { rail, retired } = selectChannel(opened, options);
3809
3982
  const result = await closeChannel(
@@ -3874,7 +4047,7 @@ function agentManagementCommands() {
3874
4047
  options,
3875
4048
  async () => {
3876
4049
  await requireExperimental();
3877
- const { runPull } = await import("./sync-pull-FHKF7A44.js");
4050
+ const { runPull } = await import("./sync-pull-OEIMF2XX.js");
3878
4051
  const { terminalPrompter } = await import("./prompter-LSICEYSQ.js");
3879
4052
  return runPull(options, {
3880
4053
  interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY) && !options.json,
@@ -3967,6 +4140,36 @@ var agentsCommand = new Command50("agents").description("Browse the agent direct
3967
4140
  );
3968
4141
  }
3969
4142
  );
4143
+ agentsCommand.command("get").description("Show an agent's record on the selected --network, or on every chain").argument("<address>", "Wallet address of the agent").option("--all-chains", "List the agent's records on every served chain").action(async (address, opts) => {
4144
+ let wallet;
4145
+ try {
4146
+ wallet = parseInput(EthAddressSchema, address);
4147
+ } catch (err) {
4148
+ renderFailure(err);
4149
+ return;
4150
+ }
4151
+ if (opts.allChains) {
4152
+ const result = await apiGet(
4153
+ `/api/agents/chains?${new URLSearchParams({ address: wallet }).toString()}`
4154
+ );
4155
+ const parsed = AgentChainsResponseSchema.safeParse(result);
4156
+ if (!parsed.success) {
4157
+ printResult(result);
4158
+ return;
4159
+ }
4160
+ printResult({
4161
+ ...parsed.data,
4162
+ chains: parsed.data.chains.map((entry) => ({
4163
+ ...entry,
4164
+ earningsToken: paymentTokenSymbol(entry.chainId)
4165
+ }))
4166
+ });
4167
+ return;
4168
+ }
4169
+ const { chainId } = selectedNetwork();
4170
+ const params = new URLSearchParams({ address: wallet, chainId: String(chainId) });
4171
+ printResult(await apiGet(`/api/agents/stats?${params.toString()}`));
4172
+ });
3970
4173
 
3971
4174
  // src/commands/inbox.ts
3972
4175
  import { Command as Command51 } from "commander";
@@ -3987,7 +4190,7 @@ var inboxCommand = new Command51("inbox").description("Show tasks you created an
3987
4190
  () => []
3988
4191
  ) : Promise.resolve([])
3989
4192
  ]);
3990
- printResult({ ...taskResult, pendingBids });
4193
+ printResult(withChainNames({ ...taskResult, pendingBids }));
3991
4194
  });
3992
4195
 
3993
4196
  // src/commands/actions.ts
@@ -4183,14 +4386,58 @@ import { Command as Command64 } from "commander";
4183
4386
 
4184
4387
  // src/commands/wallet/balance.ts
4185
4388
  import { Command as Command54 } from "commander";
4186
- var walletBalanceCommand = new Command54("balance").description("Show the wallet's payment-token balance on the selected network").option("--address <addr>", "Address to check (defaults to own wallet)").action(async (opts) => {
4389
+ function balancePath(address, chainId) {
4390
+ return `/api/wallet/balance?address=${address}&chainId=${chainId}`;
4391
+ }
4392
+ async function allChainBalances(address) {
4393
+ const raw = await apiGet("/trpc/network.info");
4394
+ const info = NetworkInfoSchema.safeParse(raw?.result?.data);
4395
+ if (!info.success) {
4396
+ throw new Error(
4397
+ "The API returned network info this CLI cannot read; upgrade the CLI or the API."
4398
+ );
4399
+ }
4400
+ const chains = await Promise.all(
4401
+ info.data.chains.map(async (chain) => {
4402
+ const base = {
4403
+ chainId: chain.chainId,
4404
+ networkName: chain.networkName,
4405
+ tokenSymbol: chain.tokenSymbol
4406
+ };
4407
+ try {
4408
+ const result = await apiGet(balancePath(address, chain.chainId));
4409
+ return {
4410
+ ...base,
4411
+ tokenSymbol: result.tokenSymbol ?? chain.tokenSymbol,
4412
+ balanceBaseUnits: result.balanceBaseUnits,
4413
+ balanceUsdc: result.balanceUsdc
4414
+ };
4415
+ } catch (err) {
4416
+ return { ...base, error: err instanceof Error ? err.message : String(err) };
4417
+ }
4418
+ })
4419
+ );
4420
+ return { address, chains };
4421
+ }
4422
+ var walletBalanceCommand = new Command54("balance").description("Show the wallet's payment-token balance on the selected network").option("--address <addr>", "Address to check (defaults to own wallet)").option(
4423
+ "--all-chains",
4424
+ "Show the balance on every chain the selected deployment serves, one entry per chain"
4425
+ ).action(async (opts) => {
4187
4426
  let address = opts.address;
4188
4427
  if (!address) {
4189
4428
  const keystore = await loadKeystore();
4190
4429
  address = keystore.walletAddress;
4191
4430
  }
4431
+ if (opts.allChains) {
4432
+ try {
4433
+ printResult(await allChainBalances(address));
4434
+ } catch (err) {
4435
+ renderFailure(err, { fallback: "Failed to fetch network info from backend." });
4436
+ }
4437
+ return;
4438
+ }
4192
4439
  const result = await apiGet(
4193
- `/api/wallet/balance?address=${address}&chainId=${selectedNetwork().chainId}`
4440
+ balancePath(address, selectedNetwork().chainId)
4194
4441
  );
4195
4442
  printResult(result);
4196
4443
  });
@@ -4307,14 +4554,17 @@ var walletImportCommand = new Command55("import").description("Import an existin
4307
4554
  );
4308
4555
  }
4309
4556
  }
4310
- if (keySource === "flag") {
4311
- process.stderr.write(
4312
- JSON.stringify({
4313
- warning: "Private key was passed via --key flag and may be visible in shell history and ps aux."
4314
- }) + "\n"
4315
- );
4316
- }
4317
- printResult({ address, agentId });
4557
+ printResult(
4558
+ { address, agentId },
4559
+ {
4560
+ warnings: keySource === "flag" ? [
4561
+ cliWarning(
4562
+ "private_key_in_argv",
4563
+ "Private key was passed via --key flag and may be visible in shell history and ps aux."
4564
+ )
4565
+ ] : []
4566
+ }
4567
+ );
4318
4568
  });
4319
4569
 
4320
4570
  // src/commands/wallet/set-withdrawal-address.ts
@@ -4357,12 +4607,16 @@ async function fetchWithdrawalAddress(address, chainId) {
4357
4607
  function noWithdrawalAddressMessage(chainId) {
4358
4608
  return `No withdrawal address set on chain ${chainId}. The withdrawal address is per chain; run: ${taskmarketCommandFor(chainId)} wallet set-withdrawal-address <address>`;
4359
4609
  }
4360
- async function verifyWithdrawalAddress(keystore, chainId, serverAddress, log = (line) => process.stderr.write(line + "\n")) {
4610
+ async function verifyWithdrawalAddress(keystore, chainId, serverAddress, warnings) {
4361
4611
  const pinned = pinnedWithdrawalAddress(keystore, chainId);
4362
4612
  if (!pinned) {
4363
4613
  await pinWithdrawalAddress(keystore, chainId, serverAddress);
4364
- log(
4365
- `Note: pinned withdrawal address ${serverAddress} for chain ${chainId} in the local keystore.`
4614
+ warnings.push(
4615
+ cliWarning(
4616
+ "withdrawal_address_pinned",
4617
+ `Pinned withdrawal address ${serverAddress} for chain ${chainId} in the local keystore.`,
4618
+ { chainId, withdrawalAddress: serverAddress }
4619
+ )
4366
4620
  );
4367
4621
  return serverAddress;
4368
4622
  }
@@ -4437,10 +4691,18 @@ var setWithdrawalAddressCommand = new Command56("set-withdrawal-address").descri
4437
4691
  {
4438
4692
  chainId: actedOn,
4439
4693
  withdrawalAddress: result.withdrawalAddress,
4440
- accountRecoveryCode: result.accountRecoveryCode,
4441
- warning: `SAVE THIS ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only, will never be shown again, and there is no way to recover it if lost -- this chain's withdrawal address could then never be changed again. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`
4694
+ accountRecoveryCode: result.accountRecoveryCode
4442
4695
  },
4443
- { idempotencyKey }
4696
+ {
4697
+ idempotencyKey,
4698
+ warnings: [
4699
+ cliWarning(
4700
+ "recovery_code_shown_once",
4701
+ `SAVE THIS ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only, will never be shown again, and there is no way to recover it if lost -- this chain's withdrawal address could then never be changed again. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`,
4702
+ { chainId: actedOn }
4703
+ )
4704
+ ]
4705
+ }
4444
4706
  );
4445
4707
  });
4446
4708
 
@@ -4505,10 +4767,18 @@ var changeWithdrawalAddressCommand = new Command58("change-withdrawal-address").
4505
4767
  {
4506
4768
  chainId: actedOn,
4507
4769
  withdrawalAddress: result.withdrawalAddress,
4508
- accountRecoveryCode: result.accountRecoveryCode,
4509
- warning: `SAVE THIS NEW ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only. The code you just used is no longer valid on this chain. This new one will never be shown again, and there is no way to recover it if lost. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`
4770
+ accountRecoveryCode: result.accountRecoveryCode
4510
4771
  },
4511
- { idempotencyKey }
4772
+ {
4773
+ idempotencyKey,
4774
+ warnings: [
4775
+ cliWarning(
4776
+ "recovery_code_shown_once",
4777
+ `SAVE THIS NEW ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only. The code you just used is no longer valid on this chain. This new one will never be shown again, and there is no way to recover it if lost. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`,
4778
+ { chainId: actedOn }
4779
+ )
4780
+ ]
4781
+ }
4512
4782
  );
4513
4783
  });
4514
4784
 
@@ -4571,10 +4841,18 @@ var revealRecoveryCodeCommand = new Command60("reveal-recovery-code").descriptio
4571
4841
  printResult(
4572
4842
  {
4573
4843
  chainId: actedOn,
4574
- accountRecoveryCode: result.accountRecoveryCode,
4575
- warning: `SAVE THIS ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only, will never be shown again, and there is no way to recover it if lost -- this chain's withdrawal address could then never be changed again. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`
4844
+ accountRecoveryCode: result.accountRecoveryCode
4576
4845
  },
4577
- { idempotencyKey }
4846
+ {
4847
+ idempotencyKey,
4848
+ warnings: [
4849
+ cliWarning(
4850
+ "recovery_code_shown_once",
4851
+ `SAVE THIS ACCOUNT RECOVERY CODE NOW. It is the recovery code for chain ${actedOn} only, will never be shown again, and there is no way to recover it if lost -- this chain's withdrawal address could then never be changed again. Save it in more than one independent place (e.g. a password manager entry AND a printed copy).`,
4852
+ { chainId: actedOn }
4853
+ )
4854
+ ]
4855
+ }
4578
4856
  );
4579
4857
  });
4580
4858
 
@@ -4637,6 +4915,7 @@ var withdrawDreamsCommand = new Command62("withdraw-dreams").description("Withdr
4637
4915
  );
4638
4916
  return;
4639
4917
  }
4918
+ const warnings = [];
4640
4919
  if (!destination) {
4641
4920
  let addressResponse;
4642
4921
  try {
@@ -4653,7 +4932,8 @@ var withdrawDreamsCommand = new Command62("withdraw-dreams").description("Withdr
4653
4932
  destination = await verifyWithdrawalAddress(
4654
4933
  keystore,
4655
4934
  balance.chainId,
4656
- addressResponse.withdrawalAddress
4935
+ addressResponse.withdrawalAddress,
4936
+ warnings
4657
4937
  );
4658
4938
  } catch (err) {
4659
4939
  renderFailure(err);
@@ -4691,7 +4971,7 @@ var withdrawDreamsCommand = new Command62("withdraw-dreams").description("Withdr
4691
4971
  dreamsPerUsdc: result.dreamsPerUsdc,
4692
4972
  usdEquivalent: result.usdEquivalent
4693
4973
  },
4694
- { idempotencyKey }
4974
+ { idempotencyKey, warnings }
4695
4975
  );
4696
4976
  });
4697
4977
 
@@ -4963,11 +5243,13 @@ var withdrawCommand = new Command65("withdraw").description(
4963
5243
  return;
4964
5244
  }
4965
5245
  let withdrawalAddress;
5246
+ const warnings = [];
4966
5247
  try {
4967
5248
  withdrawalAddress = await verifyWithdrawalAddress(
4968
5249
  keystore,
4969
5250
  chainId,
4970
- addressResponse.withdrawalAddress
5251
+ addressResponse.withdrawalAddress,
5252
+ warnings
4971
5253
  );
4972
5254
  } catch (err) {
4973
5255
  renderFailure(err);
@@ -4980,7 +5262,7 @@ var withdrawCommand = new Command65("withdraw").description(
4980
5262
  withdrawalAddress,
4981
5263
  amountBaseUnits
4982
5264
  });
4983
- printResult(withdrawOutput(result2, chainId), { idempotencyKey: idempotencyKey2 });
5265
+ printResult(withdrawOutput(result2, chainId), { idempotencyKey: idempotencyKey2, warnings });
4984
5266
  return;
4985
5267
  }
4986
5268
  let domain;
@@ -5018,7 +5300,7 @@ var withdrawCommand = new Command65("withdraw").description(
5018
5300
  signature
5019
5301
  }
5020
5302
  );
5021
- printResult(withdrawOutput(result, chainId), { idempotencyKey });
5303
+ printResult(withdrawOutput(result, chainId), { idempotencyKey, warnings });
5022
5304
  });
5023
5305
 
5024
5306
  // src/commands/encrypt.ts
@@ -10908,7 +11190,7 @@ var sponsoredTaskSettlementsCommand = new Command102("settlements").description(
10908
11190
  const result = await apiGet(
10909
11191
  `/api/sponsored-task-vaults/${vaultId}/settlements?${params.toString()}`
10910
11192
  );
10911
- printResult(result);
11193
+ printResult(withChainNames(result));
10912
11194
  });
10913
11195
 
10914
11196
  // src/commands/sponsored-task/show.ts
@@ -11120,11 +11402,13 @@ var sponsoredTaskClaimCommand = new Command108("claim").description("Claim your
11120
11402
  return;
11121
11403
  }
11122
11404
  let destination;
11405
+ const warnings = [];
11123
11406
  try {
11124
11407
  destination = await verifyWithdrawalAddress(
11125
11408
  keystore,
11126
11409
  vault.chainId,
11127
- addressResponse.withdrawalAddress
11410
+ addressResponse.withdrawalAddress,
11411
+ warnings
11128
11412
  );
11129
11413
  } catch (err) {
11130
11414
  renderFailure(err);
@@ -11183,7 +11467,7 @@ var sponsoredTaskClaimCommand = new Command108("claim").description("Claim your
11183
11467
  proof: entitlement.proof
11184
11468
  }
11185
11469
  );
11186
- printResult(result, { idempotencyKey });
11470
+ printResult(result, { idempotencyKey, warnings });
11187
11471
  });
11188
11472
 
11189
11473
  // src/commands/sponsored-task/rewards.ts
@@ -11225,7 +11509,7 @@ var sponsoredTaskRewardsCommand = new Command109("rewards").description("List Sp
11225
11509
  const result = await apiGet(
11226
11510
  `/api/sponsored-task-rewards/workers/${address.toLowerCase()}?${params.toString()}`
11227
11511
  );
11228
- printResult(result);
11512
+ printResult(withChainNames(result));
11229
11513
  }
11230
11514
  );
11231
11515
 
@@ -11324,20 +11608,35 @@ var dropsCommand = new Command111("drops").description("Browse Task Drops and ma
11324
11608
 
11325
11609
  // src/commands/hooks.ts
11326
11610
  import { Command as Command112 } from "commander";
11327
- var listCommand5 = new Command112("list").description("List observed hooks and their active-phase task counts on the selected --network").option("--limit <n>", "Maximum hooks to return (1-100)", "50").action(async (opts) => {
11611
+ var listCommand5 = new Command112("list").description(
11612
+ "List hooks listed (verified) in the hook registry on the selected --network, then observed hooks that are not listed"
11613
+ ).option("--limit <n>", "Maximum unlisted observed hooks to return (1-100)", "50").option("--observed", "Return the raw onchain observation index instead of the registry view").action(async (opts) => {
11328
11614
  try {
11329
11615
  const input = parseInput(HookIndexInputSchema, { limit: optionalInt(opts.limit) });
11330
- printResult(await apiGet(withChainId(`/api/hooks?limit=${input.limit}`)));
11616
+ if (opts.observed) {
11617
+ printResult(await apiGet(withChainId(`/api/hooks?limit=${input.limit}`)));
11618
+ return;
11619
+ }
11620
+ const registry = await fetchHookRegistry();
11621
+ printResult({ ...registry, unlisted: registry.unlisted.slice(0, input.limit) });
11331
11622
  } catch (err) {
11332
11623
  renderFailure(err);
11333
11624
  }
11334
11625
  });
11335
- var showCommand3 = new Command112("show").description("Show one observed hook by address on the selected --network").argument("<address>", "Hook contract address").action(async (address) => {
11626
+ var showCommand3 = new Command112("show").description(
11627
+ "Show one hook on the selected --network: its registry listing, or its onchain observation marked unlisted"
11628
+ ).argument("<address>", "Hook contract address").action(async (address) => {
11336
11629
  try {
11337
11630
  const input = parseInput(HookGetInputSchema, { address });
11338
- const result = await apiGet(withChainId(`/api/hooks/${input.address}`));
11339
- if (result === null || result === void 0) {
11340
- throw new Error(`Hook ${input.address} has not been observed on this network`);
11631
+ const registry = await fetchHookRegistry(input.address.toLowerCase());
11632
+ const wanted = input.address.toLowerCase();
11633
+ const listed = registry.listed.find((hook) => hook.address.toLowerCase() === wanted);
11634
+ const unlisted = registry.unlisted.find((hook) => hook.address.toLowerCase() === wanted);
11635
+ const result = listed ?? unlisted;
11636
+ if (!result) {
11637
+ throw new Error(
11638
+ `Hook ${input.address} is not listed in the hook registry and has not been observed on this network`
11639
+ );
11341
11640
  }
11342
11641
  printResult(result);
11343
11642
  } catch (err) {