@lucid-agents/taskmarket 1.19.1 → 1.20.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-ICT56PNO.js";
17
+ } from "./chunk-SQFNRMEN.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-M7WD6A2T.js";
39
+ } from "./chunk-2YFJNXXA.js";
40
40
  import {
41
41
  MPP_TEMPO_DEFAULT_VALIDITY_SECONDS,
42
42
  X402PayError,
@@ -58,15 +58,16 @@ import {
58
58
  signSponsoredTempoTransfer,
59
59
  signTaskmarketFeePayment,
60
60
  signTypedData
61
- } from "./chunk-NRKTRQEA.js";
61
+ } from "./chunk-SCZPZWRF.js";
62
62
  import {
63
63
  AgentMessageEnvelopeSchema,
64
64
  ApiError,
65
65
  BUG_REPORT_SEVERITIES,
66
66
  BUG_REPORT_STATUSES,
67
+ BUG_REPORT_VISIBILITIES,
68
+ BugReportMessageBodySchema,
67
69
  DEFAULT_EVALUATION_WINDOW_HOURS,
68
70
  DEFAULT_TERMS_BOUNDS,
69
- GetBugReportInputSchema,
70
71
  IntentStatusResponseSchema,
71
72
  LegalAcceptanceResponseSchema,
72
73
  LegalBundleSchema,
@@ -74,7 +75,9 @@ import {
74
75
  LegalStatusResponseSchema,
75
76
  NETWORKS,
76
77
  NETWORK_NAMES,
78
+ PUBLIC_BUG_REPORT_SORTS,
77
79
  PenaltyTo,
80
+ PostBugReportMessageInputSchema,
78
81
  READ_AUTH_ADDRESS_HEADER,
79
82
  READ_AUTH_SIGNATURE_HEADER,
80
83
  REDACTED,
@@ -140,6 +143,7 @@ import {
140
143
  isInFlightApiError,
141
144
  isPendingApiError,
142
145
  isRecordingPendingResponse,
146
+ isTaskmarketChainId,
143
147
  isTerminalWalletBridgeStatus,
144
148
  keystoreExists,
145
149
  loadKeystore,
@@ -158,17 +162,18 @@ import {
158
162
  settlementActionExpiresAt,
159
163
  settlementActionRequiresExpiry,
160
164
  taskmarketChain,
165
+ taskmarketCommandFor,
161
166
  usdcToBaseUnits,
162
167
  withErrorContext,
163
168
  withIdempotentWrite
164
- } from "./chunk-X7AUWPZV.js";
169
+ } from "./chunk-F7HVOUHY.js";
165
170
  import {
166
171
  channelLines
167
172
  } from "./chunk-XJOB4NMV.js";
168
173
  import "./chunk-S7SJMJ2I.js";
169
174
 
170
175
  // src/index.ts
171
- import { Command as Command104 } from "commander";
176
+ import { Command as Command109 } from "commander";
172
177
  import { createRequire } from "module";
173
178
 
174
179
  // src/commands/init.ts
@@ -3436,7 +3441,7 @@ async function runAgentCommand(options) {
3436
3441
  try {
3437
3442
  const { assertAgentCompatibility } = await import("./compatibility-636WJOEX.js");
3438
3443
  const pi = assertAgentCompatibility();
3439
- const { runAgent } = await import("./launch-ZSZURLR6.js");
3444
+ const { runAgent } = await import("./launch-CXG3JSD7.js");
3440
3445
  result = await runAgent({
3441
3446
  model: options.model,
3442
3447
  pi,
@@ -3495,13 +3500,13 @@ function agentManagementCommands() {
3495
3500
  const status = new Command48("status").description(
3496
3501
  "Show the agent channels (locked, charged, refundable), purchases with an unknown outcome, the sandbox and compute credit. Reads only."
3497
3502
  ).option("--json", "Print the versioned JSON envelope").action(async (options) => {
3498
- const { collectAgentStatus, statusLines } = await import("./status-BXL2F4LY.js");
3503
+ const { collectAgentStatus, statusLines } = await import("./status-ITMQZ4W6.js");
3499
3504
  await run(options, () => collectAgentStatus(), statusLines);
3500
3505
  });
3501
3506
  const doctor = new Command48("doctor").description(
3502
3507
  "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."
3503
3508
  ).option("--json", "Print the versioned JSON envelope").action(async (options) => {
3504
- const { runDoctor, doctorLines } = await import("./doctor-MBM7WQHI.js");
3509
+ const { runDoctor, doctorLines } = await import("./doctor-DO2R6HK7.js");
3505
3510
  const report = await run(options, () => runDoctor(), doctorLines);
3506
3511
  if (report && !report.ok) process.exitCode = 1;
3507
3512
  });
@@ -3512,7 +3517,7 @@ function agentManagementCommands() {
3512
3517
  "Reconcile the open purchases of this channel, as status lists it; also reaches retired channels"
3513
3518
  ).option("--json", "Print the versioned JSON envelope").action(
3514
3519
  async (invocationId, options) => {
3515
- const { reconcileChannelPurchases, reconcileInvocation } = await import("./reconcile-4HIIA426.js");
3520
+ const { reconcileChannelPurchases, reconcileInvocation } = await import("./reconcile-LB2ZRNG5.js");
3516
3521
  const choice = { rail: options.rail, channel: options.channel };
3517
3522
  if (invocationId !== void 0) {
3518
3523
  await run(
@@ -3570,7 +3575,7 @@ function agentManagementCommands() {
3570
3575
  `Not a USDC amount: ${options.amount} (digits, at most 6 decimals)`
3571
3576
  );
3572
3577
  }
3573
- const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-7DEGKHO5.js");
3578
+ const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-A57K7BP6.js");
3574
3579
  const { rails } = await openAgentChannels();
3575
3580
  const result = await requestTopUp(selectRail(rails, options.rail), amount);
3576
3581
  return {
@@ -3594,8 +3599,8 @@ function agentManagementCommands() {
3594
3599
  async () => {
3595
3600
  await requireExperimental();
3596
3601
  const { AGENT_VIEW_VERSION } = await import("./budget-view-J6L7X6EY.js");
3597
- const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-7DEGKHO5.js");
3598
- const { reconcileLeasedPurchase } = await import("./reconcile-4HIIA426.js");
3602
+ const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-A57K7BP6.js");
3603
+ const { reconcileLeasedPurchase } = await import("./reconcile-LB2ZRNG5.js");
3599
3604
  const opened = await openAgentChannels();
3600
3605
  const { rail, retired } = selectChannel(opened, options);
3601
3606
  const result = await closeChannel(
@@ -3666,7 +3671,7 @@ function agentManagementCommands() {
3666
3671
  options,
3667
3672
  async () => {
3668
3673
  await requireExperimental();
3669
- const { runPull } = await import("./sync-pull-HL2YS3EL.js");
3674
+ const { runPull } = await import("./sync-pull-U3WGVKDX.js");
3670
3675
  const { terminalPrompter } = await import("./prompter-LSICEYSQ.js");
3671
3676
  return runPull(options, {
3672
3677
  interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY) && !options.json,
@@ -3947,27 +3952,51 @@ import { Command as Command56 } from "commander";
3947
3952
 
3948
3953
  // src/lib/withdrawal-pin.ts
3949
3954
  var WithdrawalAddressMismatchError = class extends Error {
3950
- constructor(pinned, server) {
3955
+ constructor(pinned, server, chainId) {
3951
3956
  super(
3952
- `Refusing to sign: the server reports withdrawal address ${server}, but this CLI has ${pinned} pinned locally. Nothing was signed or sent. If you changed the withdrawal address yourself (for example on the web with your account recovery code), accept the new address with: taskmarket wallet sync-withdrawal-address`
3957
+ `Refusing to sign: the server reports withdrawal address ${server} on chain ${chainId}, but this CLI has ${pinned} pinned locally for that chain. Nothing was signed or sent. If you changed the withdrawal address yourself (for example with \`taskmarket wallet change-withdrawal-address\` from another machine), accept the new address with: ${taskmarketCommandFor(chainId)} wallet sync-withdrawal-address`
3953
3958
  );
3954
3959
  this.pinned = pinned;
3955
3960
  this.server = server;
3961
+ this.chainId = chainId;
3956
3962
  this.name = "WithdrawalAddressMismatchError";
3957
3963
  }
3958
3964
  };
3959
- async function pinWithdrawalAddress(keystore, address) {
3960
- await saveKeystore({ ...keystore, withdrawalAddress: address });
3965
+ function pinnedWithdrawalAddress(keystore, chainId) {
3966
+ return keystore.withdrawalAddresses?.[String(chainId)] ?? keystore.withdrawalAddress;
3967
+ }
3968
+ async function pinWithdrawalAddress(keystore, chainId, address) {
3969
+ await saveKeystore({
3970
+ ...keystore,
3971
+ withdrawalAddresses: { ...keystore.withdrawalAddresses, [String(chainId)]: address }
3972
+ });
3961
3973
  }
3962
- async function verifyWithdrawalAddress(keystore, serverAddress, log = (line) => process.stderr.write(line + "\n")) {
3963
- const pinned = keystore.withdrawalAddress;
3974
+ function serverChainMismatch(requested, answered) {
3975
+ if (answered === void 0 || answered === requested) return void 0;
3976
+ return `Refusing to continue: the server answered for chain ${answered}, but this CLI asked for chain ${requested}. Nothing was pinned.`;
3977
+ }
3978
+ async function fetchWithdrawalAddress(address, chainId) {
3979
+ const response = await apiGet(
3980
+ `/api/wallet/withdrawal-address?address=${address}&chainId=${chainId}`
3981
+ );
3982
+ const mismatch = serverChainMismatch(chainId, response.chainId);
3983
+ if (mismatch) throw new Error(mismatch);
3984
+ return { withdrawalAddress: response.withdrawalAddress, chainId };
3985
+ }
3986
+ function noWithdrawalAddressMessage(chainId) {
3987
+ return `No withdrawal address set on chain ${chainId}. The withdrawal address is per chain; run: ${taskmarketCommandFor(chainId)} wallet set-withdrawal-address <address>`;
3988
+ }
3989
+ async function verifyWithdrawalAddress(keystore, chainId, serverAddress, log = (line) => process.stderr.write(line + "\n")) {
3990
+ const pinned = pinnedWithdrawalAddress(keystore, chainId);
3964
3991
  if (!pinned) {
3965
- await pinWithdrawalAddress(keystore, serverAddress);
3966
- log(`Note: pinned withdrawal address ${serverAddress} in the local keystore.`);
3992
+ await pinWithdrawalAddress(keystore, chainId, serverAddress);
3993
+ log(
3994
+ `Note: pinned withdrawal address ${serverAddress} for chain ${chainId} in the local keystore.`
3995
+ );
3967
3996
  return serverAddress;
3968
3997
  }
3969
3998
  if (pinned.toLowerCase() !== serverAddress.toLowerCase()) {
3970
- throw new WithdrawalAddressMismatchError(pinned, serverAddress);
3999
+ throw new WithdrawalAddressMismatchError(pinned, serverAddress, chainId);
3971
4000
  }
3972
4001
  return pinned;
3973
4002
  }
@@ -3992,7 +4021,9 @@ var SIGNATURE_TTL_SECONDS = 5 * 60;
3992
4021
  function isValidAddress(addr) {
3993
4022
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
3994
4023
  }
3995
- var setWithdrawalAddressCommand = new Command56("set-withdrawal-address").description("Set a withdrawal address for payment-token withdrawals (one-time, free)").argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
4024
+ var setWithdrawalAddressCommand = new Command56("set-withdrawal-address").description(
4025
+ "Set the withdrawal address for payment-token withdrawals on the selected network (once per chain, free)"
4026
+ ).argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
3996
4027
  if (!isValidAddress(address)) {
3997
4028
  printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
3998
4029
  return;
@@ -4024,12 +4055,19 @@ var setWithdrawalAddressCommand = new Command56("set-withdrawal-address").descri
4024
4055
  expiresAt,
4025
4056
  chainId
4026
4057
  });
4027
- await pinWithdrawalAddress(keystore, result.withdrawalAddress);
4058
+ const mismatch = serverChainMismatch(chainId, result.chainId);
4059
+ if (mismatch) {
4060
+ printError(mismatch);
4061
+ return;
4062
+ }
4063
+ const actedOn = chainId;
4064
+ await pinWithdrawalAddress(keystore, actedOn, result.withdrawalAddress);
4028
4065
  printResult(
4029
4066
  {
4067
+ chainId: actedOn,
4030
4068
  withdrawalAddress: result.withdrawalAddress,
4031
4069
  accountRecoveryCode: result.accountRecoveryCode,
4032
- warning: "SAVE THIS ACCOUNT RECOVERY CODE NOW. It will never be shown again, and there is no way to recover it if lost -- the 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)."
4070
+ 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).`
4033
4071
  },
4034
4072
  { idempotencyKey }
4035
4073
  );
@@ -4037,14 +4075,19 @@ var setWithdrawalAddressCommand = new Command56("set-withdrawal-address").descri
4037
4075
 
4038
4076
  // src/commands/wallet/get-withdrawal-address.ts
4039
4077
  import { Command as Command57 } from "commander";
4040
- var getWithdrawalAddressCommand = new Command57("get-withdrawal-address").description("Show the currently registered withdrawal address, if any").option("--address <addr>", "Wallet address to check (defaults to own wallet)").action(async (opts) => {
4078
+ var getWithdrawalAddressCommand = new Command57("get-withdrawal-address").description(
4079
+ "Show the withdrawal address registered on the selected network, if any (the address is per chain)"
4080
+ ).option("--address <addr>", "Wallet address to check (defaults to own wallet)").action(async (opts) => {
4041
4081
  let address = opts.address;
4042
4082
  if (!address) {
4043
4083
  const keystore = await loadKeystore();
4044
4084
  address = keystore.walletAddress;
4045
4085
  }
4046
- const result = await apiGet(`/api/wallet/withdrawal-address?address=${address}`);
4047
- printResult(result);
4086
+ const { chainId } = selectedNetwork();
4087
+ const result = await apiGet(
4088
+ `/api/wallet/withdrawal-address?address=${address}&chainId=${chainId}`
4089
+ );
4090
+ printResult({ ...result, chainId: result.chainId ?? chainId });
4048
4091
  });
4049
4092
 
4050
4093
  // src/commands/wallet/change-withdrawal-address.ts
@@ -4055,7 +4098,9 @@ function isValidAddress2(addr) {
4055
4098
  function isValidRecoveryCode(code) {
4056
4099
  return /^\d{8}$/.test(code);
4057
4100
  }
4058
- var changeWithdrawalAddressCommand = new Command58("change-withdrawal-address").description("Change the withdrawal address using the account recovery code (RFC-0012)").argument("<recovery-code>", "The 8-digit account recovery code from set-withdrawal-address").argument("<new-address>", "New Ethereum address to receive withdrawals").action(async (recoveryCode, newAddress) => {
4101
+ var changeWithdrawalAddressCommand = new Command58("change-withdrawal-address").description(
4102
+ "Change the selected network's withdrawal address using that chain's account recovery code (RFC-0012)"
4103
+ ).argument("<recovery-code>", "The 8-digit account recovery code from set-withdrawal-address").argument("<new-address>", "New Ethereum address to receive withdrawals").action(async (recoveryCode, newAddress) => {
4059
4104
  if (!isValidRecoveryCode(recoveryCode)) {
4060
4105
  printError("Invalid account recovery code: must be 8 digits");
4061
4106
  return;
@@ -4071,17 +4116,26 @@ var changeWithdrawalAddressCommand = new Command58("change-withdrawal-address").
4071
4116
  printError("No keystore found. Run `taskmarket init` first.");
4072
4117
  return;
4073
4118
  }
4119
+ const { chainId } = selectedNetwork();
4074
4120
  const { data: result, idempotencyKey } = await apiPost("/api/wallet/change-withdrawal-address", {
4075
4121
  address: keystore.walletAddress,
4076
4122
  accountRecoveryCode: recoveryCode,
4077
- newWithdrawalAddress: newAddress
4123
+ newWithdrawalAddress: newAddress,
4124
+ chainId
4078
4125
  });
4079
- await pinWithdrawalAddress(keystore, result.withdrawalAddress);
4126
+ const mismatch = serverChainMismatch(chainId, result.chainId);
4127
+ if (mismatch) {
4128
+ printError(mismatch);
4129
+ return;
4130
+ }
4131
+ const actedOn = chainId;
4132
+ await pinWithdrawalAddress(keystore, actedOn, result.withdrawalAddress);
4080
4133
  printResult(
4081
4134
  {
4135
+ chainId: actedOn,
4082
4136
  withdrawalAddress: result.withdrawalAddress,
4083
4137
  accountRecoveryCode: result.accountRecoveryCode,
4084
- warning: "SAVE THIS NEW ACCOUNT RECOVERY CODE NOW. The code you just used is no longer valid. 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)."
4138
+ 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).`
4085
4139
  },
4086
4140
  { idempotencyKey }
4087
4141
  );
@@ -4090,7 +4144,7 @@ var changeWithdrawalAddressCommand = new Command58("change-withdrawal-address").
4090
4144
  // src/commands/wallet/sync-withdrawal-address.ts
4091
4145
  import { Command as Command59 } from "commander";
4092
4146
  var syncWithdrawalAddressCommand = new Command59("sync-withdrawal-address").description(
4093
- "Accept the withdrawal address registered on the server as the locally pinned one (after a change made elsewhere, e.g. on the web)"
4147
+ "Accept the selected network's withdrawal address registered on the server as the locally pinned one (after a change made elsewhere, e.g. on the web)"
4094
4148
  ).action(async () => {
4095
4149
  let keystore;
4096
4150
  try {
@@ -4099,18 +4153,22 @@ var syncWithdrawalAddressCommand = new Command59("sync-withdrawal-address").desc
4099
4153
  printError("No keystore found. Run `taskmarket init` first.");
4100
4154
  return;
4101
4155
  }
4102
- const { withdrawalAddress } = await apiGet(
4103
- `/api/wallet/withdrawal-address?address=${keystore.walletAddress}`
4104
- );
4156
+ const { chainId } = selectedNetwork();
4157
+ let withdrawalAddress;
4158
+ try {
4159
+ ({ withdrawalAddress } = await fetchWithdrawalAddress(keystore.walletAddress, chainId));
4160
+ } catch (err) {
4161
+ renderFailure(err);
4162
+ return;
4163
+ }
4105
4164
  if (!withdrawalAddress) {
4106
- printError(
4107
- "No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
4108
- );
4165
+ printError(noWithdrawalAddressMessage(chainId));
4109
4166
  return;
4110
4167
  }
4111
- const previous = keystore.withdrawalAddress ?? null;
4112
- await pinWithdrawalAddress(keystore, withdrawalAddress);
4168
+ const previous = pinnedWithdrawalAddress(keystore, chainId) ?? null;
4169
+ await pinWithdrawalAddress(keystore, chainId, withdrawalAddress);
4113
4170
  printResult({
4171
+ chainId,
4114
4172
  previousWithdrawalAddress: previous,
4115
4173
  withdrawalAddress,
4116
4174
  changed: previous === null || previous.toLowerCase() !== withdrawalAddress.toLowerCase()
@@ -4119,7 +4177,9 @@ var syncWithdrawalAddressCommand = new Command59("sync-withdrawal-address").desc
4119
4177
 
4120
4178
  // src/commands/wallet/reveal-recovery-code.ts
4121
4179
  import { Command as Command60 } from "commander";
4122
- var revealRecoveryCodeCommand = new Command60("reveal-recovery-code").description("One-time reveal of your account recovery code, if one has not been generated yet").action(async () => {
4180
+ var revealRecoveryCodeCommand = new Command60("reveal-recovery-code").description(
4181
+ "One-time reveal of the selected network's account recovery code, if one has not been generated yet"
4182
+ ).action(async () => {
4123
4183
  let keystore;
4124
4184
  try {
4125
4185
  keystore = await loadKeystore();
@@ -4128,16 +4188,20 @@ var revealRecoveryCodeCommand = new Command60("reveal-recovery-code").descriptio
4128
4188
  return;
4129
4189
  }
4130
4190
  const address = keystore.walletAddress;
4131
- const message = buildRevealAccountRecoveryCodeMessage(address);
4191
+ const { chainId } = selectedNetwork();
4192
+ const message = buildRevealAccountRecoveryCodeMessage(address, chainId);
4132
4193
  const signature = await signMessage(message, keystore);
4133
4194
  const { data: result, idempotencyKey } = await apiPost("/api/wallet/reveal-backfilled-recovery-code", {
4134
4195
  address,
4135
- signature
4196
+ signature,
4197
+ chainId
4136
4198
  });
4199
+ const actedOn = result.chainId ?? chainId;
4137
4200
  printResult(
4138
4201
  {
4202
+ chainId: actedOn,
4139
4203
  accountRecoveryCode: result.accountRecoveryCode,
4140
- warning: "SAVE THIS ACCOUNT RECOVERY CODE NOW. It will never be shown again, and there is no way to recover it if lost -- the 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)."
4204
+ 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).`
4141
4205
  },
4142
4206
  { idempotencyKey }
4143
4207
  );
@@ -4185,30 +4249,42 @@ var withdrawDreamsCommand = new Command62("withdraw-dreams").description("Withdr
4185
4249
  printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
4186
4250
  return;
4187
4251
  }
4188
- if (!destination) {
4189
- const addressResponse = await apiGet(
4190
- `/api/wallet/withdrawal-address?address=${workerAddress}`
4252
+ const balance = await apiGet(
4253
+ `/api/wallet/dreams-balance?address=${workerAddress}`
4254
+ );
4255
+ if (!balance.hookAddress || balance.chainId === void 0) {
4256
+ printError("DREAMS rewards are not configured on this server");
4257
+ return;
4258
+ }
4259
+ if (!isTaskmarketChainId(balance.chainId)) {
4260
+ printError(
4261
+ `Refusing to sign: the server reports the DREAMS reward hook on unknown chain ${balance.chainId}`
4191
4262
  );
4263
+ return;
4264
+ }
4265
+ if (!destination) {
4266
+ let addressResponse;
4267
+ try {
4268
+ addressResponse = await fetchWithdrawalAddress(workerAddress, balance.chainId);
4269
+ } catch (err) {
4270
+ renderFailure(err);
4271
+ return;
4272
+ }
4192
4273
  if (!addressResponse.withdrawalAddress) {
4193
- printError(
4194
- "No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
4195
- );
4274
+ printError(noWithdrawalAddressMessage(balance.chainId));
4196
4275
  return;
4197
4276
  }
4198
4277
  try {
4199
- destination = await verifyWithdrawalAddress(keystore, addressResponse.withdrawalAddress);
4278
+ destination = await verifyWithdrawalAddress(
4279
+ keystore,
4280
+ balance.chainId,
4281
+ addressResponse.withdrawalAddress
4282
+ );
4200
4283
  } catch (err) {
4201
4284
  renderFailure(err);
4202
4285
  return;
4203
4286
  }
4204
4287
  }
4205
- const balance = await apiGet(
4206
- `/api/wallet/dreams-balance?address=${workerAddress}`
4207
- );
4208
- if (!balance.hookAddress || balance.chainId === void 0) {
4209
- printError("DREAMS rewards are not configured on this server");
4210
- return;
4211
- }
4212
4288
  const nonce = toHex(crypto.getRandomValues(new Uint8Array(32)));
4213
4289
  const validBefore = String(Math.floor(Date.now() / 1e3) + AUTHORIZATION_VALIDITY_SECONDS);
4214
4290
  const message = buildWithdrawDreamsMessage({
@@ -4504,26 +4580,23 @@ var withdrawCommand = new Command65("withdraw").description(
4504
4580
  return;
4505
4581
  }
4506
4582
  const from = keystore.walletAddress;
4507
- const addressResponse = await apiGet(
4508
- `/api/wallet/withdrawal-address?address=${from}`
4509
- );
4583
+ const { chainId } = selectedNetwork();
4584
+ const addressResponse = await fetchWithdrawalAddress(from, chainId);
4510
4585
  if (!addressResponse.withdrawalAddress) {
4511
- printError(
4512
- "No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
4513
- );
4586
+ printError(noWithdrawalAddressMessage(chainId));
4514
4587
  return;
4515
4588
  }
4516
4589
  let withdrawalAddress;
4517
4590
  try {
4518
4591
  withdrawalAddress = await verifyWithdrawalAddress(
4519
4592
  keystore,
4593
+ chainId,
4520
4594
  addressResponse.withdrawalAddress
4521
4595
  );
4522
4596
  } catch (err) {
4523
4597
  renderFailure(err);
4524
4598
  return;
4525
4599
  }
4526
- const { chainId } = selectedNetwork();
4527
4600
  if (paymentProtocolOf(chainId) === "mpp") {
4528
4601
  const { data: result2, idempotencyKey: idempotencyKey2 } = await withdrawOnTempo({
4529
4602
  keystore,
@@ -6169,11 +6242,150 @@ emailCommand.addCommand(addressCommand2);
6169
6242
  emailCommand.addCommand(markReadCommand);
6170
6243
 
6171
6244
  // src/commands/bug/index.ts
6172
- import { Command as Command82 } from "commander";
6245
+ import { Command as Command87 } from "commander";
6173
6246
 
6174
- // src/commands/bug/list.ts
6247
+ // src/commands/bug/browse.ts
6175
6248
  import { Command as Command79 } from "commander";
6176
- var listCommand = new Command79("list").description("List the bug reports you submitted and their status").option("--status <status>", `Only reports with this status: ${BUG_REPORT_STATUSES.join(", ")}`).option("--limit <n>", "Maximum reports to return (1-100)", "50").action(async (opts) => {
6249
+ var browseCommand = new Command79("browse").description(
6250
+ "Browse public bug reports, to check whether a bug is already known; no wallet needed"
6251
+ ).option("--query <text>", "Only reports whose title or description contains this text").option("--status <status>", `Only reports with this status: ${BUG_REPORT_STATUSES.join(", ")}`).option("--sort <order>", `Order: ${PUBLIC_BUG_REPORT_SORTS.join(", ")}`, "newest").option("--limit <n>", "Maximum reports to return (1-100)", "50").option("--offset <n>", "Skip this many reports, for paging", "0").action(
6252
+ async (opts) => {
6253
+ if (opts.status && !BUG_REPORT_STATUSES.includes(opts.status)) {
6254
+ printError(`--status must be one of ${BUG_REPORT_STATUSES.join(", ")}`);
6255
+ return;
6256
+ }
6257
+ if (!PUBLIC_BUG_REPORT_SORTS.includes(opts.sort)) {
6258
+ printError(`--sort must be one of ${PUBLIC_BUG_REPORT_SORTS.join(", ")}`);
6259
+ return;
6260
+ }
6261
+ const limit = Number(opts.limit);
6262
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
6263
+ printError("--limit must be an integer from 1 to 100");
6264
+ return;
6265
+ }
6266
+ const offset = Number(opts.offset);
6267
+ if (!Number.isInteger(offset) || offset < 0) {
6268
+ printError("--offset must be a whole number");
6269
+ return;
6270
+ }
6271
+ const query2 = opts.query?.trim();
6272
+ if (query2 !== void 0 && (query2.length === 0 || query2.length > 200)) {
6273
+ printError("--query must be 1 to 200 characters");
6274
+ return;
6275
+ }
6276
+ const params = new URLSearchParams({
6277
+ sort: opts.sort,
6278
+ limit: String(limit),
6279
+ offset: String(offset)
6280
+ });
6281
+ if (opts.status) params.set("status", opts.status);
6282
+ if (query2) params.set("query", query2);
6283
+ try {
6284
+ printResult(await apiGet(`/api/bug-tracker?${params.toString()}`));
6285
+ } catch (error) {
6286
+ return renderFailure(error);
6287
+ }
6288
+ }
6289
+ );
6290
+
6291
+ // src/commands/bug/comment.ts
6292
+ import { Command as Command80 } from "commander";
6293
+
6294
+ // src/lib/stdin.ts
6295
+ var STDIN_FIRST_BYTE_MS = 5e3;
6296
+ async function readStdin(firstByteMs) {
6297
+ const chunks = [];
6298
+ const iterator = process.stdin[Symbol.asyncIterator]();
6299
+ let timer;
6300
+ const first = await Promise.race([
6301
+ iterator.next(),
6302
+ ...firstByteMs === void 0 ? [] : [new Promise((resolve) => timer = setTimeout(() => resolve(null), firstByteMs))]
6303
+ ]);
6304
+ clearTimeout(timer);
6305
+ if (first === null) {
6306
+ process.stdin.destroy();
6307
+ return null;
6308
+ }
6309
+ if (!first.done) {
6310
+ chunks.push(Buffer.from(first.value));
6311
+ for await (const chunk of { [Symbol.asyncIterator]: () => iterator }) {
6312
+ chunks.push(Buffer.from(chunk));
6313
+ }
6314
+ }
6315
+ return Buffer.concat(chunks).toString("utf8");
6316
+ }
6317
+ async function textOrStdin(value) {
6318
+ if (value !== void 0 && value !== "-") return value;
6319
+ if (process.stdin.isTTY) return null;
6320
+ return readStdin(value === "-" ? void 0 : STDIN_FIRST_BYTE_MS);
6321
+ }
6322
+
6323
+ // src/commands/bug/report-ref.ts
6324
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6325
+ var NUMBER = /^#?(\d+)$/;
6326
+ function parseBugReportRef(value) {
6327
+ if (UUID.test(value)) return { kind: "id", id: value.toLowerCase() };
6328
+ const match = NUMBER.exec(value);
6329
+ if (match) {
6330
+ const number = Number(match[1]);
6331
+ if (Number.isSafeInteger(number) && number > 0) return { kind: "number", number };
6332
+ }
6333
+ return null;
6334
+ }
6335
+ var BUG_REPORT_REF_HELP = "Bug report: its public number (#N) or its id";
6336
+ var BUG_REPORT_REF_ERROR = "Name the bug report by its public number (#12) or its id";
6337
+ async function fetchPublicBugReport(number, headers) {
6338
+ return await apiGet(`/api/bug-tracker/${number}`, { headers });
6339
+ }
6340
+ async function resolveBugReportId(ref) {
6341
+ if (ref.kind === "id") return ref.id;
6342
+ return (await fetchPublicBugReport(ref.number)).id;
6343
+ }
6344
+
6345
+ // src/commands/bug/comment.ts
6346
+ var commentCommand = new Command80("comment").description(
6347
+ "Comment on a public bug report. Comments are public: never include keys, seed phrases or other private data"
6348
+ ).argument("<report>", BUG_REPORT_REF_HELP).argument("[message]", 'Your comment; read from stdin when omitted or "-"').option("--agent <id>", "Your agent id, shown with the comment").action(async (report, message, opts) => {
6349
+ const ref = parseBugReportRef(report);
6350
+ if (!ref) {
6351
+ printError(BUG_REPORT_REF_ERROR);
6352
+ return;
6353
+ }
6354
+ const text = await textOrStdin(message);
6355
+ if (text === null) {
6356
+ printError("Pass the comment as an argument, or pipe it on stdin");
6357
+ return;
6358
+ }
6359
+ const body = BugReportMessageBodySchema.safeParse(text);
6360
+ if (!body.success) {
6361
+ printError(`Invalid comment: ${body.error.issues[0].message}`);
6362
+ return;
6363
+ }
6364
+ if (opts.agent !== void 0 && (opts.agent.length === 0 || opts.agent.length > 128)) {
6365
+ printError("--agent must be 1 to 128 characters");
6366
+ return;
6367
+ }
6368
+ const auth = await signReadAuth();
6369
+ if (!auth || Object.keys(auth.headers).length === 0) {
6370
+ printError("Commenting on a bug report needs a wallet. Run `taskmarket init` first.");
6371
+ return;
6372
+ }
6373
+ try {
6374
+ const id = await resolveBugReportId(ref);
6375
+ const { data, idempotencyKey } = await apiPost(
6376
+ `/api/bug-reports/${id}/comments`,
6377
+ { body: body.data, ...opts.agent ? { agentId: opts.agent } : {} },
6378
+ { headers: auth.headers }
6379
+ );
6380
+ printResult(data, { idempotencyKey });
6381
+ } catch (error) {
6382
+ return renderFailure(error);
6383
+ }
6384
+ });
6385
+
6386
+ // src/commands/bug/list.ts
6387
+ import { Command as Command81 } from "commander";
6388
+ var listCommand = new Command81("list").description("List the bug reports you submitted and their status").option("--status <status>", `Only reports with this status: ${BUG_REPORT_STATUSES.join(", ")}`).option("--limit <n>", "Maximum reports to return (1-100)", "50").action(async (opts) => {
6177
6389
  if (opts.status && !BUG_REPORT_STATUSES.includes(opts.status)) {
6178
6390
  printError(`--status must be one of ${BUG_REPORT_STATUSES.join(", ")}`);
6179
6391
  return;
@@ -6199,27 +6411,98 @@ var listCommand = new Command79("list").description("List the bug reports you su
6199
6411
  }
6200
6412
  });
6201
6413
 
6202
- // src/commands/bug/show.ts
6203
- import { Command as Command80 } from "commander";
6204
- var showCommand = new Command80("show").description("Show one of your bug reports, its status and any linked GitHub issue").argument("<id>", "Bug report id").action(async (id) => {
6205
- if (!GetBugReportInputSchema.safeParse({ id }).success) {
6206
- printError("Bug report id must be a UUID");
6414
+ // src/commands/bug/me-too.ts
6415
+ import { Command as Command82 } from "commander";
6416
+ var meTooCommand = new Command82("me-too").description("Say you hit a public bug report too; counted once per wallet").argument("<report>", BUG_REPORT_REF_HELP).action(async (report) => {
6417
+ const ref = parseBugReportRef(report);
6418
+ if (!ref) {
6419
+ printError(BUG_REPORT_REF_ERROR);
6207
6420
  return;
6208
6421
  }
6209
6422
  const auth = await signReadAuth();
6210
6423
  if (!auth || Object.keys(auth.headers).length === 0) {
6211
- printError("Reading a bug report needs a wallet. Run `taskmarket init` first.");
6424
+ printError("Saying you have this bug too needs a wallet. Run `taskmarket init` first.");
6212
6425
  return;
6213
6426
  }
6214
6427
  try {
6215
- printResult(await apiGet(`/api/bug-reports/${id}`, { headers: auth.headers }));
6428
+ const id = await resolveBugReportId(ref);
6429
+ const { data, idempotencyKey } = await apiPost(
6430
+ `/api/bug-reports/${id}/affected`,
6431
+ {},
6432
+ { headers: auth.headers }
6433
+ );
6434
+ printResult(data, { idempotencyKey });
6435
+ } catch (error) {
6436
+ return renderFailure(error);
6437
+ }
6438
+ });
6439
+
6440
+ // src/commands/bug/reply.ts
6441
+ import { Command as Command83 } from "commander";
6442
+ var replyCommand2 = new Command83("reply").description(
6443
+ "Reply to Taskmarket staff on one of your bug reports; a reply does not change its status"
6444
+ ).argument("<id>", "Bug report id").argument("[message]", 'Your reply; read from stdin when omitted or "-"').action(async (id, message) => {
6445
+ const body = await textOrStdin(message);
6446
+ if (body === null) {
6447
+ printError("Pass the reply as an argument, or pipe it on stdin");
6448
+ return;
6449
+ }
6450
+ const parsed = PostBugReportMessageInputSchema.safeParse({ id, body });
6451
+ if (!parsed.success) {
6452
+ const issue = parsed.error.issues[0];
6453
+ printError(
6454
+ issue.path[0] === "id" ? "Bug report id must be a UUID" : `Invalid reply: ${issue.path.join(".") || "input"}: ${issue.message}`
6455
+ );
6456
+ return;
6457
+ }
6458
+ const auth = await signReadAuth();
6459
+ if (!auth || Object.keys(auth.headers).length === 0) {
6460
+ printError("Replying to a bug report needs a wallet. Run `taskmarket init` first.");
6461
+ return;
6462
+ }
6463
+ try {
6464
+ const { data, idempotencyKey } = await apiPost(
6465
+ `/api/bug-reports/${id}/messages`,
6466
+ { body: parsed.data.body },
6467
+ { headers: auth.headers }
6468
+ );
6469
+ printResult(data, { idempotencyKey });
6470
+ } catch (error) {
6471
+ return renderFailure(error);
6472
+ }
6473
+ });
6474
+
6475
+ // src/commands/bug/show.ts
6476
+ import { Command as Command84 } from "commander";
6477
+ var showCommand = new Command84("show").description(
6478
+ "Show a public bug report by its number (#N, no wallet needed), or one of your own by its id with messages from staff"
6479
+ ).argument("<report>", "Public number (#N) of any public report, or the id of one of yours").action(async (report) => {
6480
+ const ref = parseBugReportRef(report);
6481
+ if (!ref) {
6482
+ printError(BUG_REPORT_REF_ERROR);
6483
+ return;
6484
+ }
6485
+ const auth = await signReadAuth();
6486
+ const signed = auth && Object.keys(auth.headers).length > 0 ? auth.headers : void 0;
6487
+ try {
6488
+ if (ref.kind === "number") {
6489
+ printResult(await fetchPublicBugReport(ref.number, signed));
6490
+ return;
6491
+ }
6492
+ if (!signed) {
6493
+ printError(
6494
+ "Reading your bug report by id needs a wallet. Run `taskmarket init` first, or use its public number."
6495
+ );
6496
+ return;
6497
+ }
6498
+ printResult(await apiGet(`/api/bug-reports/${ref.id}`, { headers: signed }));
6216
6499
  } catch (error) {
6217
6500
  return renderFailure(error);
6218
6501
  }
6219
6502
  });
6220
6503
 
6221
6504
  // src/commands/bug/submit.ts
6222
- import { Command as Command81 } from "commander";
6505
+ import { Command as Command85 } from "commander";
6223
6506
 
6224
6507
  // src/commands/bug/context.ts
6225
6508
  import os from "os";
@@ -6242,47 +6525,20 @@ function cliVersionOf(command) {
6242
6525
  // src/commands/bug/submit.ts
6243
6526
  var LAST_COMMAND_MAX_CHARS = 2048;
6244
6527
  var LAST_ERROR_MAX_CHARS = 16 * 1024;
6245
- var STDIN_FIRST_BYTE_MS = 5e3;
6246
- async function readStdin(firstByteMs) {
6247
- const chunks = [];
6248
- const iterator = process.stdin[Symbol.asyncIterator]();
6249
- let timer;
6250
- const first = await Promise.race([
6251
- iterator.next(),
6252
- ...firstByteMs === void 0 ? [] : [new Promise((resolve) => timer = setTimeout(() => resolve(null), firstByteMs))]
6253
- ]);
6254
- clearTimeout(timer);
6255
- if (first === null) {
6256
- process.stdin.destroy();
6257
- return null;
6258
- }
6259
- if (!first.done) {
6260
- chunks.push(Buffer.from(first.value));
6261
- for await (const chunk of { [Symbol.asyncIterator]: () => iterator }) {
6262
- chunks.push(Buffer.from(chunk));
6263
- }
6264
- }
6265
- return Buffer.concat(chunks).toString("utf8");
6266
- }
6267
- var submitCommand = new Command81("submit").description("Report a Taskmarket bug; CLI version, OS, Node version and network are attached").requiredOption("--title <text>", "Short summary (at most 200 characters)").option(
6528
+ var PUBLIC_NOTICE = "This report is public: anyone can read it, with your wallet and agent id. Never include keys, seed phrases or other private data. Make it private with `taskmarket bug visibility <id> private`.";
6529
+ var submitCommand = new Command85("submit").description(
6530
+ "Report a Taskmarket bug; CLI version, OS, Node version and network are attached. Reports are public unless --private"
6531
+ ).requiredOption("--title <text>", "Short summary (at most 200 characters)").option(
6268
6532
  "--description <text>",
6269
6533
  'What happened and how to reproduce it; read from stdin when omitted or "-"'
6270
- ).option("--severity <level>", `How bad it is: ${BUG_REPORT_SEVERITIES.join(", ")}`, "medium").option("--task <id>", "Task the bug happened on").option("--tx <hash>", "Transaction hash involved").option(
6534
+ ).option("--severity <level>", `How bad it is: ${BUG_REPORT_SEVERITIES.join(", ")}`, "medium").option("--task <id>", "Task the bug happened on").option("--tx <hash>", "Transaction hash involved").option("--private", "Keep the report private: only you and Taskmarket staff can see it").option(
6271
6535
  "--include-last-error",
6272
6536
  "Attach the last failed taskmarket command and its error (secrets already removed)"
6273
6537
  ).action(async function(opts) {
6274
- let description = opts.description;
6275
- if (description === void 0 || description === "-") {
6276
- if (process.stdin.isTTY) {
6277
- printError("Pass --description or pipe the description on stdin");
6278
- return;
6279
- }
6280
- const read = await readStdin(description === "-" ? void 0 : STDIN_FIRST_BYTE_MS);
6281
- if (read === null) {
6282
- printError("Pass --description, or pipe the description on stdin");
6283
- return;
6284
- }
6285
- description = read;
6538
+ const description = await textOrStdin(opts.description);
6539
+ if (description === null) {
6540
+ printError("Pass --description, or pipe the description on stdin");
6541
+ return;
6286
6542
  }
6287
6543
  const context = collectBugContext(cliVersionOf(this), { taskId: opts.task, txHash: opts.tx });
6288
6544
  if (opts.includeLastError) {
@@ -6310,7 +6566,8 @@ var submitCommand = new Command81("submit").description("Report a Taskmarket bug
6310
6566
  description,
6311
6567
  severity: opts.severity,
6312
6568
  source: "cli",
6313
- context
6569
+ context,
6570
+ visibility: opts.private ? "private" : "public"
6314
6571
  });
6315
6572
  if (!parsed.success) {
6316
6573
  const issue = parsed.error.issues[0];
@@ -6328,6 +6585,45 @@ var submitCommand = new Command81("submit").description("Report a Taskmarket bug
6328
6585
  parsed.data,
6329
6586
  { headers: auth.headers }
6330
6587
  );
6588
+ printResult(
6589
+ {
6590
+ ...data,
6591
+ visibility: parsed.data.visibility,
6592
+ ...parsed.data.visibility === "public" ? { notice: PUBLIC_NOTICE } : {}
6593
+ },
6594
+ { idempotencyKey }
6595
+ );
6596
+ } catch (error) {
6597
+ return renderFailure(error);
6598
+ }
6599
+ });
6600
+
6601
+ // src/commands/bug/visibility.ts
6602
+ import { Command as Command86 } from "commander";
6603
+ var visibilityCommand = new Command86("visibility").description(
6604
+ "Make one of your bug reports public or private; a private report is seen only by you and staff"
6605
+ ).argument("<report>", `${BUG_REPORT_REF_HELP}; a private report only by its id`).argument("<visibility>", BUG_REPORT_VISIBILITIES.join(" or ")).action(async (report, visibility) => {
6606
+ const ref = parseBugReportRef(report);
6607
+ if (!ref) {
6608
+ printError(BUG_REPORT_REF_ERROR);
6609
+ return;
6610
+ }
6611
+ if (!BUG_REPORT_VISIBILITIES.includes(visibility)) {
6612
+ printError(`Visibility must be ${BUG_REPORT_VISIBILITIES.join(" or ")}`);
6613
+ return;
6614
+ }
6615
+ const auth = await signReadAuth();
6616
+ if (!auth || Object.keys(auth.headers).length === 0) {
6617
+ printError("Changing a bug report needs a wallet. Run `taskmarket init` first.");
6618
+ return;
6619
+ }
6620
+ try {
6621
+ const id = await resolveBugReportId(ref);
6622
+ const { data, idempotencyKey } = await apiPost(
6623
+ `/api/bug-reports/${id}/visibility`,
6624
+ { visibility },
6625
+ { headers: auth.headers }
6626
+ );
6331
6627
  printResult(data, { idempotencyKey });
6332
6628
  } catch (error) {
6333
6629
  return renderFailure(error);
@@ -6335,19 +6631,24 @@ var submitCommand = new Command81("submit").description("Report a Taskmarket bug
6335
6631
  });
6336
6632
 
6337
6633
  // src/commands/bug/index.ts
6338
- var bugCommand = new Command82("bug").description(
6339
- "Report Taskmarket bugs and follow their status"
6634
+ var bugCommand = new Command87("bug").description(
6635
+ "Report Taskmarket bugs, browse public reports, follow their status and reply to staff"
6340
6636
  );
6341
6637
  bugCommand.addCommand(submitCommand);
6342
6638
  bugCommand.addCommand(listCommand);
6343
6639
  bugCommand.addCommand(showCommand);
6640
+ bugCommand.addCommand(replyCommand2);
6641
+ bugCommand.addCommand(browseCommand);
6642
+ bugCommand.addCommand(meTooCommand);
6643
+ bugCommand.addCommand(commentCommand);
6644
+ bugCommand.addCommand(visibilityCommand);
6344
6645
 
6345
6646
  // src/commands/requester/index.ts
6346
- import { Command as Command84 } from "commander";
6647
+ import { Command as Command89 } from "commander";
6347
6648
 
6348
6649
  // src/commands/requester/stats.ts
6349
- import { Command as Command83 } from "commander";
6350
- var requesterStatsCmd = new Command83("stats").description("Get requester reputation stats for an address").argument("<address>", "Wallet address of the requester").action(async (address) => {
6650
+ import { Command as Command88 } from "commander";
6651
+ var requesterStatsCmd = new Command88("stats").description("Get requester reputation stats for an address").argument("<address>", "Wallet address of the requester").action(async (address) => {
6351
6652
  if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
6352
6653
  printError("Address must be a 0x-prefixed 20-byte hex string");
6353
6654
  return;
@@ -6361,13 +6662,13 @@ var requesterStatsCmd = new Command83("stats").description("Get requester reputa
6361
6662
  });
6362
6663
 
6363
6664
  // src/commands/requester/index.ts
6364
- var requesterCmd = new Command84("requester").description("Requester reputation commands").addCommand(requesterStatsCmd);
6665
+ var requesterCmd = new Command89("requester").description("Requester reputation commands").addCommand(requesterStatsCmd);
6365
6666
 
6366
6667
  // src/commands/x402/index.ts
6367
- import { Command as Command88 } from "commander";
6668
+ import { Command as Command93 } from "commander";
6368
6669
 
6369
6670
  // src/commands/x402/payments.ts
6370
- import { Command as Command85, Option as Option4 } from "commander";
6671
+ import { Command as Command90, Option as Option4 } from "commander";
6371
6672
  import { createInterface as createInterface4 } from "readline";
6372
6673
  var PAYMENT_STATES = [
6373
6674
  "reserved",
@@ -6393,7 +6694,7 @@ async function confirmManualResolution() {
6393
6694
  readline.close();
6394
6695
  return answer.trim().toLowerCase() === "resolve";
6395
6696
  }
6396
- var x402PaymentsCommand = new Command85("payments").description(
6697
+ var x402PaymentsCommand = new Command90("payments").description(
6397
6698
  "Inspect and reconcile X402 Pay payment records"
6398
6699
  );
6399
6700
  x402PaymentsCommand.command("list").description("List current payment records").addOption(new Option4("--state <state>", "Filter by state").choices(PAYMENT_STATES)).action(async (options) => {
@@ -6422,7 +6723,7 @@ x402PaymentsCommand.command("resolve").description("Manually record an externall
6422
6723
 
6423
6724
  // src/commands/x402/policy.ts
6424
6725
  import { promises as fs4 } from "fs";
6425
- import { Command as Command86 } from "commander";
6726
+ import { Command as Command91 } from "commander";
6426
6727
  import { createInterface as createInterface5 } from "readline";
6427
6728
  async function confirmUnattendedRule(rule) {
6428
6729
  if (!process.stdin.isTTY) {
@@ -6448,7 +6749,7 @@ async function confirmUnattendedRule(rule) {
6448
6749
  readline.close();
6449
6750
  return answer.trim().toLowerCase() === "authorize";
6450
6751
  }
6451
- var x402PolicyCommand = new Command86("policy").description(
6752
+ var x402PolicyCommand = new Command91("policy").description(
6452
6753
  "Manage local X402 Pay spending policy"
6453
6754
  );
6454
6755
  x402PolicyCommand.command("init").description("Create a deny-all policy file").action(async () => {
@@ -6484,14 +6785,14 @@ for (const enabled of [true, false]) {
6484
6785
  }
6485
6786
 
6486
6787
  // src/commands/x402/request.ts
6487
- import { Command as Command87, Option as Option5 } from "commander";
6788
+ import { Command as Command92, Option as Option5 } from "commander";
6488
6789
  function collect3(value, previous) {
6489
6790
  return [...previous, value];
6490
6791
  }
6491
6792
  function confirm(lines) {
6492
6793
  return confirmAtTerminal(lines, "use --non-interactive with policy");
6493
6794
  }
6494
- var x402RequestCommand = new Command87("request").description("Request and pay for a direct x402 HTTP resource (X402 Pay)").argument("<url>", "HTTPS resource URL").addOption(new Option5("--method <method>", "HTTP method").choices(["GET", "POST"]).default("GET")).option("--json <json>", "Inline JSON POST body").option("--body-file <path>", "Read JSON POST body from a file").option("--headers-file <path>", "Read request headers from an owner-only JSON file").option(
6795
+ var x402RequestCommand = new Command92("request").description("Request and pay for a direct x402 HTTP resource (X402 Pay)").argument("<url>", "HTTPS resource URL").addOption(new Option5("--method <method>", "HTTP method").choices(["GET", "POST"]).default("GET")).option("--json <json>", "Inline JSON POST body").option("--body-file <path>", "Read JSON POST body from a file").option("--headers-file <path>", "Read request headers from an owner-only JSON file").option(
6495
6796
  "--header-env <header=ENV_VAR>",
6496
6797
  "Read one request header from an environment variable (repeatable)",
6497
6798
  collect3,
@@ -6539,7 +6840,7 @@ var x402RequestCommand = new Command87("request").description("Request and pay f
6539
6840
  );
6540
6841
 
6541
6842
  // src/commands/x402/index.ts
6542
- var x402Command = new Command88("x402").description(
6843
+ var x402Command = new Command93("x402").description(
6543
6844
  "Pay x402 services with local spending policies (X402 Pay)"
6544
6845
  );
6545
6846
  x402Command.addCommand(x402RequestCommand);
@@ -6547,10 +6848,10 @@ x402Command.addCommand(x402PolicyCommand);
6547
6848
  x402Command.addCommand(x402PaymentsCommand);
6548
6849
 
6549
6850
  // src/commands/sponsored-task/index.ts
6550
- import { Command as Command103 } from "commander";
6851
+ import { Command as Command108 } from "commander";
6551
6852
 
6552
6853
  // src/commands/sponsored-task/create.ts
6553
- import { Command as Command89 } from "commander";
6854
+ import { Command as Command94 } from "commander";
6554
6855
  import { toHex as toHex4 } from "viem";
6555
6856
 
6556
6857
  // ../../packages/contracts/abi/generated/SponsoredTasksVault.ts
@@ -9772,7 +10073,7 @@ async function approveSponsoredTaskSpend(input) {
9772
10073
  function isValidAddress4(addr) {
9773
10074
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
9774
10075
  }
9775
- var sponsoredTaskCreateCommand = new Command89("create").description("Create a new Sponsored Task vault for a project token").requiredOption("--factory <address>", "SponsoredTaskFactory contract address").requiredOption("--chain-id <id>", "Chain id the factory is deployed on").requiredOption("--token <address>", "Project ERC-20 token address to fund the vault with").option("--owner <address>", "Vault owner (defaults to your own wallet)").action(async (opts) => {
10076
+ var sponsoredTaskCreateCommand = new Command94("create").description("Create a new Sponsored Task vault for a project token").requiredOption("--factory <address>", "SponsoredTaskFactory contract address").requiredOption("--chain-id <id>", "Chain id the factory is deployed on").requiredOption("--token <address>", "Project ERC-20 token address to fund the vault with").option("--owner <address>", "Vault owner (defaults to your own wallet)").action(async (opts) => {
9776
10077
  if (!isValidAddress4(opts.factory) || !isValidAddress4(opts.token)) {
9777
10078
  printError("Invalid Ethereum address for --factory or --token");
9778
10079
  return;
@@ -9809,11 +10110,11 @@ var sponsoredTaskCreateCommand = new Command89("create").description("Create a n
9809
10110
  });
9810
10111
 
9811
10112
  // src/commands/sponsored-task/fund.ts
9812
- import { Command as Command90 } from "commander";
10113
+ import { Command as Command95 } from "commander";
9813
10114
  function isValidAddress5(addr) {
9814
10115
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
9815
10116
  }
9816
- var sponsoredTaskFundCommand = new Command90("fund").description("Fund a Sponsored Task vault with its project token (base units)").requiredOption("--vault <address>", "Vault address").requiredOption("--token <address>", "Project ERC-20 token address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to fund, in the token base units").action(async (opts) => {
10117
+ var sponsoredTaskFundCommand = new Command95("fund").description("Fund a Sponsored Task vault with its project token (base units)").requiredOption("--vault <address>", "Vault address").requiredOption("--token <address>", "Project ERC-20 token address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to fund, in the token base units").action(async (opts) => {
9817
10118
  if (!isValidAddress5(opts.vault) || !isValidAddress5(opts.token)) {
9818
10119
  printError("Invalid Ethereum address for --vault or --token");
9819
10120
  return;
@@ -9852,7 +10153,7 @@ var sponsoredTaskFundCommand = new Command90("fund").description("Fund a Sponsor
9852
10153
  });
9853
10154
 
9854
10155
  // src/commands/sponsored-task/managers.ts
9855
- import { Command as Command91 } from "commander";
10156
+ import { Command as Command96 } from "commander";
9856
10157
  function isValidAddress6(addr) {
9857
10158
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
9858
10159
  }
@@ -9898,7 +10199,7 @@ async function configure(opts) {
9898
10199
  });
9899
10200
  printResult({ txHash, manager: opts.manager, spendCap: cap.toString(), active: opts.active });
9900
10201
  }
9901
- var sponsoredTaskManagersCommand = new Command91("managers").description(
10202
+ var sponsoredTaskManagersCommand = new Command96("managers").description(
9902
10203
  "Manage authorized managers for a Sponsored Task vault"
9903
10204
  );
9904
10205
  sponsoredTaskManagersCommand.command("add").description("Authorize a manager with a token-denominated spend cap").requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--manager <address>", "Manager address to authorize").requiredOption("--cap <baseUnits>", "Spend cap, in the project token base units").action((opts) => configure({ ...opts, active: true }));
@@ -9909,8 +10210,8 @@ sponsoredTaskManagersCommand.command("list").description("List a vault authorize
9909
10210
  });
9910
10211
 
9911
10212
  // src/commands/sponsored-task/managed.ts
9912
- import { Command as Command92 } from "commander";
9913
- var sponsoredTaskManagedCommand = new Command92("managed").description(
10213
+ import { Command as Command97 } from "commander";
10214
+ var sponsoredTaskManagedCommand = new Command97("managed").description(
9914
10215
  "List the active Sponsored Task vaults an address can fund tasks from as an active manager (defaults to your wallet)"
9915
10216
  ).option("--address <address>", "Manager address (defaults to your wallet)").option("--limit <n>", "Max vaults to return (1-100)", "50").option("--cursor <vaultId>", "Pagination cursor from a previous nextCursor").action(async (opts) => {
9916
10217
  let address = opts.address;
@@ -9940,7 +10241,7 @@ var sponsoredTaskManagedCommand = new Command92("managed").description(
9940
10241
  });
9941
10242
 
9942
10243
  // src/commands/sponsored-task/fee-bank.ts
9943
- import { Command as Command93 } from "commander";
10244
+ import { Command as Command98 } from "commander";
9944
10245
  function isValidAddress7(addr) {
9945
10246
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
9946
10247
  }
@@ -9952,7 +10253,7 @@ async function requireKeystore2() {
9952
10253
  return null;
9953
10254
  }
9954
10255
  }
9955
- var sponsoredTaskFeeBankCommand = new Command93("fee-bank").description(
10256
+ var sponsoredTaskFeeBankCommand = new Command98("fee-bank").description(
9956
10257
  "Manage a manager USDC credit balance, charged by the Sponsored Task hook at task creation"
9957
10258
  );
9958
10259
  sponsoredTaskFeeBankCommand.command("deposit").description("Deposit USDC credit for creating sponsored tasks").requiredOption("--fee-bank <address>", "SponsoredTaskFeeBank contract address").requiredOption("--usdc <address>", "USDC token address").requiredOption("--chain-id <id>", "Chain id the fee bank is deployed on").requiredOption("--amount <baseUnits>", "Amount to deposit, in USDC base units (6 decimals)").action(async (opts) => {
@@ -10036,8 +10337,8 @@ sponsoredTaskFeeBankCommand.command("withdraw").description("Withdraw unused USD
10036
10337
  );
10037
10338
 
10038
10339
  // src/commands/sponsored-task/list.ts
10039
- import { Command as Command94 } from "commander";
10040
- var sponsoredTaskListCommand = new Command94("list").description("List Sponsored Task vaults").option("--limit <n>", "Max vaults to return", "50").option("--cursor <vaultId>", "Pagination cursor").option("--include-unverified", "Include vaults not yet curator-approved", false).action(async (opts) => {
10340
+ import { Command as Command99 } from "commander";
10341
+ var sponsoredTaskListCommand = new Command99("list").description("List Sponsored Task vaults").option("--limit <n>", "Max vaults to return", "50").option("--cursor <vaultId>", "Pagination cursor").option("--include-unverified", "Include vaults not yet curator-approved", false).action(async (opts) => {
10041
10342
  const params = new URLSearchParams({ limit: opts.limit });
10042
10343
  if (opts.cursor) params.set("cursor", opts.cursor);
10043
10344
  if (opts.includeUnverified) params.set("includeUnverified", "true");
@@ -10046,8 +10347,8 @@ var sponsoredTaskListCommand = new Command94("list").description("List Sponsored
10046
10347
  });
10047
10348
 
10048
10349
  // src/commands/sponsored-task/settlements.ts
10049
- import { Command as Command95 } from "commander";
10050
- var sponsoredTaskSettlementsCommand = new Command95("settlements").description("List the settlements a Sponsored Task vault has installed, newest first").argument("<vaultId>", "Vault id").option("--limit <n>", "Max settlements to return (1-100)", "25").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(async (vaultId, opts) => {
10350
+ import { Command as Command100 } from "commander";
10351
+ var sponsoredTaskSettlementsCommand = new Command100("settlements").description("List the settlements a Sponsored Task vault has installed, newest first").argument("<vaultId>", "Vault id").option("--limit <n>", "Max settlements to return (1-100)", "25").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(async (vaultId, opts) => {
10051
10352
  const limit = Number(opts.limit);
10052
10353
  if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
10053
10354
  printError("--limit must be an integer from 1 to 100");
@@ -10062,17 +10363,17 @@ var sponsoredTaskSettlementsCommand = new Command95("settlements").description("
10062
10363
  });
10063
10364
 
10064
10365
  // src/commands/sponsored-task/show.ts
10065
- import { Command as Command96 } from "commander";
10066
- var sponsoredTaskShowCommand = new Command96("show").description("Show a Sponsored Task vault by id").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10366
+ import { Command as Command101 } from "commander";
10367
+ var sponsoredTaskShowCommand = new Command101("show").description("Show a Sponsored Task vault by id").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10067
10368
  const result = await apiGet(`/api/sponsored-task-vaults/${vaultId}`);
10068
10369
  printResult(result);
10069
10370
  });
10070
10371
 
10071
10372
  // src/commands/sponsored-task/request-review.ts
10072
10373
  import { randomBytes as randomBytes3 } from "crypto";
10073
- import { Command as Command97 } from "commander";
10374
+ import { Command as Command102 } from "commander";
10074
10375
  var REQUEST_TTL_SECONDS = 5 * 60;
10075
- var sponsoredTaskRequestReviewCommand = new Command97("request-review").description("Ask Taskmarket curators to review a Sponsored Task vault (vault owner only)").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10376
+ var sponsoredTaskRequestReviewCommand = new Command102("request-review").description("Ask Taskmarket curators to review a Sponsored Task vault (vault owner only)").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10076
10377
  let keystore;
10077
10378
  try {
10078
10379
  keystore = await loadKeystore();
@@ -10129,18 +10430,18 @@ var sponsoredTaskRequestReviewCommand = new Command97("request-review").descript
10129
10430
  });
10130
10431
 
10131
10432
  // src/commands/sponsored-task/balance.ts
10132
- import { Command as Command98 } from "commander";
10133
- var sponsoredTaskBalanceCommand = new Command98("balance").description("Show a Sponsored Task vault funded/available/reserved balances").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10433
+ import { Command as Command103 } from "commander";
10434
+ var sponsoredTaskBalanceCommand = new Command103("balance").description("Show a Sponsored Task vault funded/available/reserved balances").argument("<vaultId>", "Vault id").action(async (vaultId) => {
10134
10435
  const result = await apiGet(`/api/sponsored-task-vaults/${vaultId}/balance`);
10135
10436
  printResult(result);
10136
10437
  });
10137
10438
 
10138
10439
  // src/commands/sponsored-task/withdraw.ts
10139
- import { Command as Command99 } from "commander";
10440
+ import { Command as Command104 } from "commander";
10140
10441
  function isValidAddress8(addr) {
10141
10442
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
10142
10443
  }
10143
- var sponsoredTaskWithdrawCommand = new Command99("withdraw").description("Withdraw unreserved project tokens from a vault (owner only)").requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to withdraw, in the project token base units").option("--recipient <address>", "Recipient (defaults to your own wallet)").action(async (opts) => {
10444
+ var sponsoredTaskWithdrawCommand = new Command104("withdraw").description("Withdraw unreserved project tokens from a vault (owner only)").requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to withdraw, in the project token base units").option("--recipient <address>", "Recipient (defaults to your own wallet)").action(async (opts) => {
10144
10445
  if (!isValidAddress8(opts.vault) || opts.recipient && !isValidAddress8(opts.recipient)) {
10145
10446
  printError("Invalid Ethereum address for --vault or --recipient");
10146
10447
  return;
@@ -10170,11 +10471,11 @@ var sponsoredTaskWithdrawCommand = new Command99("withdraw").description("Withdr
10170
10471
  });
10171
10472
 
10172
10473
  // src/commands/sponsored-task/exit.ts
10173
- import { Command as Command100 } from "commander";
10474
+ import { Command as Command105 } from "commander";
10174
10475
  function isValidAddress9(addr) {
10175
10476
  return /^0x[a-fA-F0-9]{40}$/.test(addr);
10176
10477
  }
10177
- var sponsoredTaskExitCommand = new Command100("exit").description(
10478
+ var sponsoredTaskExitCommand = new Command105("exit").description(
10178
10479
  "Terminally exit a vault: sweeps every reserved and unclaimed token back to you, invalidating every outstanding reservation, claim signature, and Merkle proof at once. There is no undo and no per-allocation revoke -- a worker with a pending but unclaimed entitlement gets nothing once this runs."
10179
10480
  ).requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").option("--recipient <address>", "Recipient (defaults to your own wallet)").option("--yes", "Skip the confirmation prompt", false).action(async (opts) => {
10180
10481
  if (!isValidAddress9(opts.vault) || opts.recipient && !isValidAddress9(opts.recipient)) {
@@ -10210,7 +10511,7 @@ var sponsoredTaskExitCommand = new Command100("exit").description(
10210
10511
  });
10211
10512
 
10212
10513
  // src/commands/sponsored-task/claim.ts
10213
- import { Command as Command101 } from "commander";
10514
+ import { Command as Command106 } from "commander";
10214
10515
  var CLAIM_TO_TYPES = {
10215
10516
  ClaimTo: [
10216
10517
  { name: "vaultId", type: "bytes32" },
@@ -10245,7 +10546,7 @@ async function postClaimWithRetry(path3, body, options = {}) {
10245
10546
  }
10246
10547
  }
10247
10548
  }
10248
- var sponsoredTaskClaimCommand = new Command101("claim").description("Claim your unclaimed Sponsored Task reward for a vault task").argument("<vaultId>", "Vault id").option(
10549
+ var sponsoredTaskClaimCommand = new Command106("claim").description("Claim your unclaimed Sponsored Task reward for a vault task").argument("<vaultId>", "Vault id").option(
10249
10550
  "--task-id <id>",
10250
10551
  "Claim the entitlement for a specific task (defaults to the first unclaimed one)"
10251
10552
  ).action(async (vaultId, opts) => {
@@ -10257,18 +10558,25 @@ var sponsoredTaskClaimCommand = new Command101("claim").description("Claim your
10257
10558
  return;
10258
10559
  }
10259
10560
  const workerAddress = keystore.walletAddress;
10260
- const addressResponse = await apiGet(
10261
- `/api/wallet/withdrawal-address?address=${workerAddress}`
10262
- );
10561
+ const vault = await apiGet(`/api/sponsored-task-vaults/${vaultId}`);
10562
+ let addressResponse;
10563
+ try {
10564
+ addressResponse = await fetchWithdrawalAddress(workerAddress, vault.chainId);
10565
+ } catch (err) {
10566
+ renderFailure(err);
10567
+ return;
10568
+ }
10263
10569
  if (!addressResponse.withdrawalAddress) {
10264
- printError(
10265
- "No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
10266
- );
10570
+ printError(noWithdrawalAddressMessage(vault.chainId));
10267
10571
  return;
10268
10572
  }
10269
10573
  let destination;
10270
10574
  try {
10271
- destination = await verifyWithdrawalAddress(keystore, addressResponse.withdrawalAddress);
10575
+ destination = await verifyWithdrawalAddress(
10576
+ keystore,
10577
+ vault.chainId,
10578
+ addressResponse.withdrawalAddress
10579
+ );
10272
10580
  } catch (err) {
10273
10581
  renderFailure(err);
10274
10582
  return;
@@ -10281,7 +10589,6 @@ var sponsoredTaskClaimCommand = new Command101("claim").description("Claim your
10281
10589
  printError("No unclaimed entitlement found for this wallet in this vault.");
10282
10590
  return;
10283
10591
  }
10284
- const vault = await apiGet(`/api/sponsored-task-vaults/${vaultId}`);
10285
10592
  const { nonce } = await apiGet(
10286
10593
  `/api/sponsored-task-vaults/${vaultId}/claim-nonce?workerAddress=${workerAddress}`
10287
10594
  );
@@ -10331,10 +10638,10 @@ var sponsoredTaskClaimCommand = new Command101("claim").description("Claim your
10331
10638
  });
10332
10639
 
10333
10640
  // src/commands/sponsored-task/rewards.ts
10334
- import { Command as Command102 } from "commander";
10641
+ import { Command as Command107 } from "commander";
10335
10642
  var REWARD_STATES = SponsoredTaskRewardStateSchema.options;
10336
10643
  var CLAIM_STATUSES = SponsoredTaskWorkerRewardClaimStatusSchema.options;
10337
- var sponsoredTaskRewardsCommand = new Command102("rewards").description("List Sponsored Task rewards across every vault (defaults to your wallet)").option("--address <address>", "Worker address (defaults to your wallet)").option("--state <state>", `Reward state: ${REWARD_STATES.join(", ")}`).option("--claim-status <status>", `Claim status: ${CLAIM_STATUSES.join(", ")}`).option("--limit <n>", "Max rewards to return (1-100)", "50").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(
10644
+ var sponsoredTaskRewardsCommand = new Command107("rewards").description("List Sponsored Task rewards across every vault (defaults to your wallet)").option("--address <address>", "Worker address (defaults to your wallet)").option("--state <state>", `Reward state: ${REWARD_STATES.join(", ")}`).option("--claim-status <status>", `Claim status: ${CLAIM_STATUSES.join(", ")}`).option("--limit <n>", "Max rewards to return (1-100)", "50").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(
10338
10645
  async (opts) => {
10339
10646
  let address = opts.address;
10340
10647
  if (address === void 0) {
@@ -10374,7 +10681,7 @@ var sponsoredTaskRewardsCommand = new Command102("rewards").description("List Sp
10374
10681
  );
10375
10682
 
10376
10683
  // src/commands/sponsored-task/index.ts
10377
- var sponsoredTaskCommand = new Command103("sponsored-task").description(
10684
+ var sponsoredTaskCommand = new Command108("sponsored-task").description(
10378
10685
  "Sponsored Task vault administration and reward claims"
10379
10686
  );
10380
10687
  sponsoredTaskCommand.addCommand(sponsoredTaskCreateCommand);
@@ -10395,7 +10702,7 @@ sponsoredTaskCommand.addCommand(sponsoredTaskRewardsCommand);
10395
10702
  // src/index.ts
10396
10703
  var require2 = createRequire(import.meta.url);
10397
10704
  var { version } = require2("../package.json");
10398
- var program = new Command104();
10705
+ var program = new Command109();
10399
10706
  setLastErrorCliVersion(version);
10400
10707
  program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
10401
10708
  program.option(