@lucid-agents/taskmarket 1.4.0 → 1.5.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.
Files changed (2) hide show
  1. package/dist/index.js +99 -33
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4054,6 +4054,7 @@ var coerce = {
4054
4054
  var NEVER = INVALID;
4055
4055
 
4056
4056
  // ../../packages/shared/dist/schemas/common.schemas.js
4057
+ var EthAddressSchema = external_exports.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address");
4057
4058
  var UsdcBaseUnitsSchema = external_exports.string().regex(/^[0-9]+$/, "Amount must be a non-negative integer in USDC base units");
4058
4059
  var PositiveUsdcBaseUnitsSchema = UsdcBaseUnitsSchema.refine(
4059
4060
  // The refine still runs when the regex check has already failed; skip the
@@ -4065,6 +4066,15 @@ var Secp256k1PublicKeySchema = external_exports.string().refine((value) => {
4065
4066
  const key = value.replace(/^0x/, "");
4066
4067
  return /^(?:02|03)[0-9a-fA-F]{64}$/.test(key) || /^04[0-9a-fA-F]{128}$/.test(key);
4067
4068
  }, "Public key must be a compressed or uncompressed secp256k1 key");
4069
+ function csvArrayQueryParam(schema = external_exports.string()) {
4070
+ return external_exports.preprocess((value) => {
4071
+ if (value === void 0 || value === "")
4072
+ return void 0;
4073
+ if (Array.isArray(value))
4074
+ return value;
4075
+ return String(value).split(",").map((v) => v.trim()).filter(Boolean);
4076
+ }, external_exports.array(schema).optional());
4077
+ }
4068
4078
 
4069
4079
  // ../../packages/shared/dist/schemas/task-drops.schemas.js
4070
4080
  var EthAddress = external_exports.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address").toLowerCase();
@@ -4171,6 +4181,7 @@ var TaskDropPageDataSchema = external_exports.object({
4171
4181
 
4172
4182
  // ../../packages/shared/dist/schemas/task.schemas.js
4173
4183
  var TaskMode = external_exports.enum(["bounty", "claim", "pitch", "benchmark", "auction"]);
4184
+ var TaskVisibility = external_exports.enum(["unlisted", "public"]);
4174
4185
  var TaskStatus = external_exports.enum([
4175
4186
  "open",
4176
4187
  "claimed",
@@ -4237,6 +4248,7 @@ var TaskCreateSchema = external_exports.object({
4237
4248
  duration: external_exports.number().positive("Duration must be positive"),
4238
4249
  tags: external_exports.array(external_exports.string()).max(10, "Maximum 10 tags allowed"),
4239
4250
  mode: TaskMode.optional().default("bounty"),
4251
+ taskVisibility: TaskVisibility.optional().default("public"),
4240
4252
  stakeRequired: external_exports.boolean().optional().default(false),
4241
4253
  stakeBps: external_exports.number().min(0).max(1e4).optional().default(0),
4242
4254
  pitchDeadline: external_exports.number().positive().optional(),
@@ -4329,6 +4341,7 @@ var TaskResponseSchema = external_exports.object({
4329
4341
  status: TaskStatus,
4330
4342
  tags: external_exports.array(external_exports.string()),
4331
4343
  mode: TaskMode,
4344
+ taskVisibility: TaskVisibility.optional().default("public"),
4332
4345
  stakeRequired: external_exports.boolean(),
4333
4346
  stakeBps: external_exports.number(),
4334
4347
  pitchDeadline: external_exports.string().nullable(),
@@ -4392,7 +4405,7 @@ var TaskListInputSchema = external_exports.object({
4392
4405
  mode: external_exports.enum(["ALL", "bounty", "claim", "pitch", "benchmark", "auction"]).optional().default("ALL"),
4393
4406
  auctionType: AuctionType.optional(),
4394
4407
  requesterActorType: external_exports.enum(["agent", "human"]).optional(),
4395
- tags: external_exports.array(external_exports.string()).optional(),
4408
+ tags: csvArrayQueryParam(),
4396
4409
  minReward: external_exports.string().optional(),
4397
4410
  maxReward: external_exports.string().optional(),
4398
4411
  deadlineHours: external_exports.number().int().positive().optional(),
@@ -4406,7 +4419,12 @@ var TaskListResponseSchema = external_exports.object({
4406
4419
  hasMore: external_exports.boolean()
4407
4420
  });
4408
4421
  var TaskInboxInputSchema = external_exports.object({
4409
- address: external_exports.string()
4422
+ address: external_exports.string(),
4423
+ // Optional proof that the caller owns `address`: a signature over
4424
+ // `taskmarket:inbox:<address>` (see ADR-0015). When present and valid, the
4425
+ // response additionally includes that address's own unlisted tasks; otherwise
4426
+ // behavior is unchanged (public tasks only, same as today, for any address).
4427
+ signature: external_exports.string().optional()
4410
4428
  });
4411
4429
  var TaskInboxResponseSchema = external_exports.object({
4412
4430
  asRequester: external_exports.array(TaskResponseSchema),
@@ -4741,10 +4759,9 @@ var BidResponseSchema = external_exports.object({
4741
4759
  });
4742
4760
 
4743
4761
  // ../../packages/shared/dist/schemas/wallet.schemas.js
4744
- var EthAddress2 = external_exports.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address");
4745
4762
  var SetWithdrawalAddressInputSchema = external_exports.object({
4746
- walletAddress: EthAddress2,
4747
- withdrawalAddress: EthAddress2,
4763
+ walletAddress: EthAddressSchema,
4764
+ withdrawalAddress: EthAddressSchema,
4748
4765
  signature: external_exports.string().min(1)
4749
4766
  });
4750
4767
  var SetWithdrawalAddressOutputSchema = external_exports.object({
@@ -4769,7 +4786,7 @@ var AuthorizationSchema = external_exports.object({
4769
4786
  nonce: external_exports.string()
4770
4787
  });
4771
4788
  var WithdrawInputSchema = external_exports.object({
4772
- from: EthAddress2,
4789
+ from: EthAddressSchema,
4773
4790
  amountBaseUnits: external_exports.string().min(1),
4774
4791
  authorization: AuthorizationSchema,
4775
4792
  signature: external_exports.string().min(1)
@@ -4783,8 +4800,8 @@ var DreamsBalanceOutputSchema = external_exports.object({
4783
4800
  claimableBaseUnits: external_exports.string()
4784
4801
  });
4785
4802
  var WithdrawDreamsInputSchema = external_exports.object({
4786
- workerAddress: EthAddress2,
4787
- destination: EthAddress2,
4803
+ workerAddress: EthAddressSchema,
4804
+ destination: EthAddressSchema,
4788
4805
  nonce: external_exports.string().min(1),
4789
4806
  validBefore: external_exports.string().min(1),
4790
4807
  signature: external_exports.string().min(1)
@@ -4803,7 +4820,6 @@ var ExchangeRateOutputSchema = external_exports.object({
4803
4820
  });
4804
4821
 
4805
4822
  // ../../packages/shared/dist/schemas/xmtp.schemas.js
4806
- var EthereumAddressSchema = external_exports.string().regex(/^0x[a-fA-F0-9]{40}$/);
4807
4823
  var XmtpPolicySchema = external_exports.enum(["allow", "deny", "quarantine"]);
4808
4824
  var XmtpPolicyModeSchema = external_exports.enum(["allowlist", "open"]);
4809
4825
  var AgentMessageEnvelopeSchema = external_exports.object({
@@ -4812,7 +4828,7 @@ var AgentMessageEnvelopeSchema = external_exports.object({
4812
4828
  requestId: external_exports.string().uuid(),
4813
4829
  replyToRequestId: external_exports.string().uuid().nullable().optional(),
4814
4830
  senderInboxId: external_exports.string().min(1),
4815
- senderAddress: EthereumAddressSchema,
4831
+ senderAddress: EthAddressSchema,
4816
4832
  sentAt: external_exports.string().datetime(),
4817
4833
  deadlineMs: external_exports.number().int().positive().optional(),
4818
4834
  payload: external_exports.record(external_exports.string(), external_exports.unknown())
@@ -4876,13 +4892,13 @@ var XmtpPeerPolicyListOutputSchema = external_exports.object({
4876
4892
  }))
4877
4893
  });
4878
4894
  var XmtpResolvePeerInputSchema = external_exports.object({
4879
- address: EthereumAddressSchema.optional(),
4895
+ address: EthAddressSchema.optional(),
4880
4896
  agentId: external_exports.string().min(1).optional()
4881
4897
  }).refine((value) => Boolean(value.address || value.agentId), {
4882
4898
  message: "Either address or agentId is required"
4883
4899
  });
4884
4900
  var XmtpResolvePeerOutputSchema = external_exports.object({
4885
- address: EthereumAddressSchema.nullable(),
4901
+ address: EthAddressSchema.nullable(),
4886
4902
  inboxId: external_exports.string().nullable()
4887
4903
  });
4888
4904
 
@@ -5068,7 +5084,7 @@ var LegalStatusResponseSchema = external_exports.object({
5068
5084
  receipt: external_exports.string().optional(),
5069
5085
  subjectType: LegalSubjectTypeSchema.optional()
5070
5086
  });
5071
- var LegalWalletAddressSchema = external_exports.string().regex(/^0x[a-fA-F0-9]{40}$/);
5087
+ var LegalWalletAddressSchema = EthAddressSchema;
5072
5088
  var LegalAffirmationsSchema = external_exports.object({
5073
5089
  acknowledgedRisk: external_exports.literal(true),
5074
5090
  agreedToAcceptableUse: external_exports.literal(true),
@@ -5401,6 +5417,30 @@ function formatDreams(baseUnits) {
5401
5417
  function buildSelectWorkerMessage(taskId, pitchId, workerAddress) {
5402
5418
  return `taskmarket:select-worker:${taskId}:${pitchId}:${workerAddress.toLowerCase()}`;
5403
5419
  }
5420
+ function buildInboxSelfAuthMessage(address) {
5421
+ return `taskmarket:inbox:${address.toLowerCase()}`;
5422
+ }
5423
+ function buildMyBidsMessage(address) {
5424
+ return `taskmarket:my-bids:${address.toLowerCase()}`;
5425
+ }
5426
+ function buildSubmitMessage(taskId) {
5427
+ return `taskmarket:submit:${taskId}`;
5428
+ }
5429
+ function buildClaimMessage(taskId) {
5430
+ return `taskmarket:claim:${taskId}`;
5431
+ }
5432
+ function buildForfeitMessage(taskId) {
5433
+ return `taskmarket:forfeit:${taskId}`;
5434
+ }
5435
+ function buildSetWithdrawalAddressMessage(withdrawalAddress) {
5436
+ return `taskmarket:set-withdrawal-address:${withdrawalAddress.toLowerCase()}`;
5437
+ }
5438
+ function buildWithdrawDreamsMessage(destination, nonce, validBefore) {
5439
+ return `taskmarket:withdraw-dreams:${destination.toLowerCase()}:${nonce}:${validBefore}`;
5440
+ }
5441
+ function buildDeviceRegisterMessage(walletAddress) {
5442
+ return `taskmarket:device-register:${walletAddress.toLowerCase()}`;
5443
+ }
5404
5444
 
5405
5445
  // ../../packages/shared/dist/legal.js
5406
5446
  var LEGAL_RECEIPT_HEADER = "X-Taskmarket-Legal-Receipt";
@@ -5954,7 +5994,11 @@ async function pollAgentId(address, maxWaitMs = 6e4) {
5954
5994
  // src/lib/device-registration.ts
5955
5995
  async function registerDevice(input) {
5956
5996
  const response = await fetch(`${API_URL}/api/devices`, {
5957
- body: JSON.stringify({ publicKey: input.publicKey, walletAddress: input.walletAddress }),
5997
+ body: JSON.stringify({
5998
+ publicKey: input.publicKey,
5999
+ signature: input.signature,
6000
+ walletAddress: input.walletAddress
6001
+ }),
5958
6002
  headers: {
5959
6003
  "Content-Type": "application/json",
5960
6004
  ...buildLegalReceiptHeaders(input.legalReceipt)
@@ -6345,6 +6389,9 @@ var initCommand = new Command2("init").description("Create and register a new ag
6345
6389
  signMessage: (message) => privateKeyToAccount3(privateKey).signMessage({ message }),
6346
6390
  walletAddress: address
6347
6391
  }) : void 0;
6392
+ const deviceRegisterSignature = await privateKeyToAccount3(
6393
+ privateKey
6394
+ ).signMessage({ message: buildDeviceRegisterMessage(address) });
6348
6395
  const {
6349
6396
  deviceId,
6350
6397
  apiToken,
@@ -6353,6 +6400,7 @@ var initCommand = new Command2("init").description("Create and register a new ag
6353
6400
  } = await registerDevice({
6354
6401
  legalReceipt: legalAcceptance?.receipt,
6355
6402
  publicKey,
6403
+ signature: deviceRegisterSignature,
6356
6404
  walletAddress: address
6357
6405
  });
6358
6406
  const encryptedKey = encryptPrivateKey(deviceEncryptionKey, privateKey);
@@ -6545,7 +6593,11 @@ function usdcToBaseUnits(value, options = {}) {
6545
6593
  }
6546
6594
 
6547
6595
  // src/commands/task/create.ts
6548
- var createCmd = new Command6("create").description("Create a new task (costs reward amount in USDC)").requiredOption("--description <text>", "Task description").requiredOption("--reward <usdc>", "Reward in USDC (e.g. 5 for 5 USDC)").requiredOption("--duration <hours>", "Task duration in hours").option("--mode <mode>", "Task mode: bounty, claim, pitch, benchmark, auction", "bounty").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("--max-price <usdc>", "Maximum bid price in USDC (required for auction mode)").option(
6596
+ var createCmd = new Command6("create").description("Create a new task (costs reward amount in USDC)").requiredOption("--description <text>", "Task description").requiredOption("--reward <usdc>", "Reward in USDC (e.g. 5 for 5 USDC)").requiredOption("--duration <hours>", "Task duration in hours").option("--mode <mode>", "Task mode: bounty, claim, pitch, benchmark, auction", "bounty").option(
6597
+ "--task-visibility <mode>",
6598
+ "Task visibility: public (default) or unlisted. 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. Not a privacy feature.",
6599
+ "public"
6600
+ ).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("--max-price <usdc>", "Maximum bid price in USDC (required for auction mode)").option(
6549
6601
  "--auction-type <type>",
6550
6602
  "Auction subtype: dutch, english, reverse_dutch, reverse_english (required for auction mode)"
6551
6603
  ).option(
@@ -6571,6 +6623,9 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
6571
6623
  if (!Number.isFinite(duration) || duration <= 0) {
6572
6624
  return void printError("--duration must be a positive number of hours");
6573
6625
  }
6626
+ if (opts.taskVisibility !== "public" && opts.taskVisibility !== "unlisted") {
6627
+ return void printError("--task-visibility must be one of: public, unlisted");
6628
+ }
6574
6629
  if (opts.mode === "auction") {
6575
6630
  if (!opts.maxPrice) {
6576
6631
  return void printError("--max-price is required for auction mode");
@@ -6614,6 +6669,7 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
6614
6669
  reward: rewardBaseUnits,
6615
6670
  duration,
6616
6671
  mode: opts.mode,
6672
+ taskVisibility: opts.taskVisibility,
6617
6673
  tags,
6618
6674
  stakeRequired: false,
6619
6675
  stakeBps: 0
@@ -6831,7 +6887,7 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
6831
6887
  printError("--file is required");
6832
6888
  }
6833
6889
  const keystore = await loadKeystore();
6834
- const signature = await signMessage(`taskmarket:submit:${taskId}`, keystore);
6890
+ const signature = await signMessage(buildSubmitMessage(taskId), keystore);
6835
6891
  const artifactInputs = await Promise.all(
6836
6892
  opts.file.map(async (filePath) => {
6837
6893
  const mimeType = mimeTypeForPath(filePath);
@@ -6973,7 +7029,7 @@ var rateCmd = new Command12("rate").description("Rate a worker (costs 0.001 USDC
6973
7029
  import { Command as Command13 } from "commander";
6974
7030
  var claimCmd = new Command13("claim").description("Claim a task as a worker").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
6975
7031
  const keystore = await loadKeystore();
6976
- const message = `taskmarket:claim:${taskId}`;
7032
+ const message = buildClaimMessage(taskId);
6977
7033
  const signature = await signMessage(message, keystore);
6978
7034
  const result = await apiPost(`/api/tasks/${taskId}/claim`, {
6979
7035
  workerAddress: keystore.walletAddress,
@@ -7362,7 +7418,7 @@ import { Command as Command30 } from "commander";
7362
7418
  var forfeitCmd = new Command30("forfeit").description("Reclaim a claim-mode task whose worker's claim has expired (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
7363
7419
  try {
7364
7420
  const keystore = await loadKeystore();
7365
- const message = `taskmarket:forfeit:${taskId}`;
7421
+ const message = buildForfeitMessage(taskId);
7366
7422
  const signature = await signMessage(message, keystore);
7367
7423
  const result = await apiPost(`/api/tasks/${taskId}/forfeit`, {
7368
7424
  taskId,
@@ -7555,27 +7611,33 @@ var agentsCommand = new Command37("agents").description("Browse the agent direct
7555
7611
  // src/commands/inbox.ts
7556
7612
  import { Command as Command38 } from "commander";
7557
7613
  var inboxCommand = new Command38("inbox").description("Show tasks you created and tasks you are working on").action(async () => {
7558
- let address;
7614
+ let keystore;
7559
7615
  try {
7560
- address = await getWalletAddress();
7616
+ keystore = await loadKeystore();
7561
7617
  } catch (err) {
7562
7618
  const msg = err instanceof Error ? err.message : "No keystore found. Run `taskmarket init` first.";
7563
7619
  printError(msg);
7564
7620
  }
7565
- const taskResult = await apiGet(
7566
- `/api/agents/inbox?address=${encodeURIComponent(address)}`
7567
- );
7568
- let pendingBids = [];
7621
+ const address = keystore.walletAddress;
7622
+ let account;
7569
7623
  try {
7570
- const keystore = await loadKeystore();
7571
- if (keystore.deviceId && keystore.apiToken) {
7572
- const params = new URLSearchParams({ deviceId: keystore.deviceId });
7573
- pendingBids = await apiGet(`/api/bids/my?${params.toString()}`, {
7574
- headers: { "x-taskmarket-api-token": keystore.apiToken }
7575
- });
7576
- }
7624
+ account = await createWalletAccountFromKeystore(keystore);
7577
7625
  } catch {
7578
7626
  }
7627
+ const [signature, bidsSignature] = await Promise.all([
7628
+ account?.signMessage({ message: buildInboxSelfAuthMessage(address) }).catch(() => void 0),
7629
+ account?.signMessage({ message: buildMyBidsMessage(address) }).catch(() => void 0)
7630
+ ]);
7631
+ const inboxParams = new URLSearchParams({ address });
7632
+ if (signature) inboxParams.set("signature", signature);
7633
+ const bidParams = new URLSearchParams({ address });
7634
+ if (bidsSignature) bidParams.set("signature", bidsSignature);
7635
+ const [taskResult, pendingBids] = await Promise.all([
7636
+ apiGet(`/api/agents/inbox?${inboxParams.toString()}`),
7637
+ bidsSignature ? apiGet(`/api/bids/my?${bidParams.toString()}`).catch(
7638
+ () => []
7639
+ ) : Promise.resolve([])
7640
+ ]);
7579
7641
  printResult({ ...taskResult, pendingBids });
7580
7642
  });
7581
7643
 
@@ -7690,6 +7752,9 @@ var walletImportCommand = new Command41("import").description("Import an existin
7690
7752
  signMessage: (message) => account.signMessage({ message }),
7691
7753
  walletAddress: address
7692
7754
  }) : void 0;
7755
+ const deviceRegisterSignature = await account.signMessage({
7756
+ message: buildDeviceRegisterMessage(address)
7757
+ });
7693
7758
  const {
7694
7759
  deviceId,
7695
7760
  apiToken,
@@ -7698,6 +7763,7 @@ var walletImportCommand = new Command41("import").description("Import an existin
7698
7763
  } = await registerDevice({
7699
7764
  legalReceipt: legalAcceptance?.receipt,
7700
7765
  publicKey,
7766
+ signature: deviceRegisterSignature,
7701
7767
  walletAddress: address
7702
7768
  });
7703
7769
  const encryptedKey = encryptPrivateKey(deviceEncryptionKey, privateKey);
@@ -7748,7 +7814,7 @@ var setWithdrawalAddressCommand = new Command42("set-withdrawal-address").descri
7748
7814
  printError("No keystore found. Run `taskmarket init` first.");
7749
7815
  }
7750
7816
  const walletAddress = keystore.walletAddress;
7751
- const message = `taskmarket:set-withdrawal-address:${address}`;
7817
+ const message = buildSetWithdrawalAddressMessage(address);
7752
7818
  const signature = await signMessage(message, keystore);
7753
7819
  const result = await apiPost("/api/wallet/set-withdrawal-address", {
7754
7820
  walletAddress,
@@ -7810,7 +7876,7 @@ var withdrawDreamsCommand = new Command44("withdraw-dreams").description("Withdr
7810
7876
  }
7811
7877
  const nonce = toHex2(crypto.getRandomValues(new Uint8Array(32)));
7812
7878
  const validBefore = String(Math.floor(Date.now() / 1e3) + AUTHORIZATION_VALIDITY_SECONDS);
7813
- const message = `taskmarket:withdraw-dreams:${destination}:${nonce}:${validBefore}`;
7879
+ const message = buildWithdrawDreamsMessage(destination, nonce, validBefore);
7814
7880
  const signature = await signMessage(message, keystore);
7815
7881
  const result = await apiPost("/api/wallet/withdraw-dreams", {
7816
7882
  workerAddress,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucid-agents/taskmarket",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "taskmarket": "./dist/index.js"