@lucid-agents/taskmarket 0.8.0 → 1.0.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 +1092 -132
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
9
|
+
import { Command as Command52 } from "commander";
|
|
10
10
|
import { createRequire } from "module";
|
|
11
11
|
|
|
12
12
|
// src/commands/init.ts
|
|
@@ -73,7 +73,7 @@ async function keystoreExists(keystorePath) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// src/lib/api.ts
|
|
76
|
-
var API_URL = process.env.TASKMARKET_API_URL ?? "https://api
|
|
76
|
+
var API_URL = process.env.TASKMARKET_API_URL ?? "https://api.taskmarket.dev";
|
|
77
77
|
async function apiGet(path3, options) {
|
|
78
78
|
const res = await fetch(`${API_URL}${path3}`, {
|
|
79
79
|
method: "GET",
|
|
@@ -198,7 +198,47 @@ function decryptWithPrivateKey(fileBuffer, privateKeyHex) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
// src/commands/init.ts
|
|
201
|
-
|
|
201
|
+
function sanitizeEmailUsername(agentId, suffix) {
|
|
202
|
+
const maxBase = 30 - 1 - suffix.length;
|
|
203
|
+
if (maxBase < 2) return null;
|
|
204
|
+
const base = agentId.toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, maxBase).replace(/-+$/, "");
|
|
205
|
+
if (base.length < 2) return null;
|
|
206
|
+
const candidate = `${base}-${suffix}`;
|
|
207
|
+
return /^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$/.test(candidate) ? candidate : null;
|
|
208
|
+
}
|
|
209
|
+
async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
210
|
+
try {
|
|
211
|
+
const reg = await apiPost("/api/emails/register", {
|
|
212
|
+
deviceId,
|
|
213
|
+
apiToken,
|
|
214
|
+
username
|
|
215
|
+
});
|
|
216
|
+
return reg.emailAddress;
|
|
217
|
+
} catch (err) {
|
|
218
|
+
if (explicit) {
|
|
219
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
220
|
+
process.stderr.write(
|
|
221
|
+
JSON.stringify({
|
|
222
|
+
ok: false,
|
|
223
|
+
error: `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
224
|
+
}) + "\n"
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
var initCommand = new Command("init").description("Create and register a new agent wallet (safe to re-run)").option(
|
|
231
|
+
"--email <username>",
|
|
232
|
+
"Claim a custom email username (default: auto-generated from agent ID)"
|
|
233
|
+
).action(async (opts) => {
|
|
234
|
+
if (opts.email) {
|
|
235
|
+
const check = await apiGet(
|
|
236
|
+
`/api/emails/check-username?username=${encodeURIComponent(opts.email)}`
|
|
237
|
+
);
|
|
238
|
+
if (!check.available) {
|
|
239
|
+
printError(`Email username "${opts.email}" is not available.`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
202
242
|
if (await keystoreExists()) {
|
|
203
243
|
const keystore = await loadKeystore();
|
|
204
244
|
let agentId2 = keystore.agentId;
|
|
@@ -214,11 +254,29 @@ var initCommand = new Command("init").description("Create and register a new age
|
|
|
214
254
|
networkInfo2 = response.result.data;
|
|
215
255
|
} catch {
|
|
216
256
|
}
|
|
257
|
+
let emailAddress2 = null;
|
|
258
|
+
try {
|
|
259
|
+
const existing = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
260
|
+
emailAddress2 = existing.emailAddress ?? null;
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
if (!emailAddress2) {
|
|
264
|
+
const username2 = opts.email ?? (agentId2 && networkInfo2 ? sanitizeEmailUsername(agentId2, String(networkInfo2.chainId)) : null);
|
|
265
|
+
if (username2) {
|
|
266
|
+
emailAddress2 = await tryRegisterEmail(
|
|
267
|
+
keystore.deviceId,
|
|
268
|
+
keystore.apiToken,
|
|
269
|
+
username2,
|
|
270
|
+
!!opts.email
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
217
274
|
printResult({
|
|
218
275
|
address: keystore.walletAddress,
|
|
219
276
|
agentId: agentId2,
|
|
220
277
|
network: networkInfo2?.networkName,
|
|
221
|
-
chainId: networkInfo2?.chainId
|
|
278
|
+
chainId: networkInfo2?.chainId,
|
|
279
|
+
emailAddress: emailAddress2
|
|
222
280
|
});
|
|
223
281
|
return;
|
|
224
282
|
}
|
|
@@ -241,7 +299,14 @@ var initCommand = new Command("init").description("Create and register a new age
|
|
|
241
299
|
} = await res.json();
|
|
242
300
|
const encryptedKey = encryptPrivateKey(deviceEncryptionKey, privateKey);
|
|
243
301
|
let agentId = initialAgentId;
|
|
244
|
-
await saveKeystore({
|
|
302
|
+
await saveKeystore({
|
|
303
|
+
encryptedKey,
|
|
304
|
+
walletAddress: address,
|
|
305
|
+
deviceId,
|
|
306
|
+
apiToken,
|
|
307
|
+
agentId,
|
|
308
|
+
keyServerUrl: API_URL
|
|
309
|
+
});
|
|
245
310
|
if (!agentId) {
|
|
246
311
|
agentId = await pollAgentId(address);
|
|
247
312
|
if (agentId) {
|
|
@@ -255,11 +320,14 @@ var initCommand = new Command("init").description("Create and register a new age
|
|
|
255
320
|
networkInfo = response.result.data;
|
|
256
321
|
} catch {
|
|
257
322
|
}
|
|
323
|
+
const username = opts.email ?? (agentId && networkInfo ? sanitizeEmailUsername(agentId, String(networkInfo.chainId)) : null);
|
|
324
|
+
const emailAddress = username ? await tryRegisterEmail(deviceId, apiToken, username, !!opts.email) : null;
|
|
258
325
|
printResult({
|
|
259
326
|
address,
|
|
260
327
|
agentId,
|
|
261
328
|
network: networkInfo?.networkName,
|
|
262
|
-
chainId: networkInfo?.chainId
|
|
329
|
+
chainId: networkInfo?.chainId,
|
|
330
|
+
emailAddress
|
|
263
331
|
});
|
|
264
332
|
});
|
|
265
333
|
|
|
@@ -276,8 +344,9 @@ import { Command as Command3 } from "commander";
|
|
|
276
344
|
// src/lib/signer.ts
|
|
277
345
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
278
346
|
import { toHex } from "viem";
|
|
279
|
-
async function fetchDeviceKey(deviceId, apiToken) {
|
|
280
|
-
const
|
|
347
|
+
async function fetchDeviceKey(deviceId, apiToken, keyServerUrl) {
|
|
348
|
+
const base = keyServerUrl ?? API_URL;
|
|
349
|
+
const res = await fetch(`${base}/api/devices/${deviceId}/key`, {
|
|
281
350
|
method: "POST",
|
|
282
351
|
headers: { "Content-Type": "application/json" },
|
|
283
352
|
body: JSON.stringify({ deviceId, apiToken })
|
|
@@ -300,7 +369,7 @@ async function signMessage(message, keystore) {
|
|
|
300
369
|
return sig;
|
|
301
370
|
}
|
|
302
371
|
async function createWalletAccountFromKeystore(keystore) {
|
|
303
|
-
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
372
|
+
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken, keystore.keyServerUrl);
|
|
304
373
|
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
305
374
|
return privateKeyToAccount2(privateKey);
|
|
306
375
|
}
|
|
@@ -414,21 +483,53 @@ var statsCommand = new Command4("stats").description("View agent statistics").op
|
|
|
414
483
|
completedTasks: result.completedTasks,
|
|
415
484
|
ratedTasks: result.ratedTasks,
|
|
416
485
|
averageRating: result.averageRating,
|
|
486
|
+
credibility: result.credibility,
|
|
417
487
|
totalEarnings: result.totalEarnings,
|
|
418
488
|
skills: result.skills,
|
|
489
|
+
emailAddress: result.emailAddress,
|
|
419
490
|
recentRatings: result.recentRatings
|
|
420
491
|
});
|
|
421
492
|
});
|
|
422
493
|
|
|
423
494
|
// src/commands/task/index.ts
|
|
424
|
-
import { Command as
|
|
495
|
+
import { Command as Command29 } from "commander";
|
|
425
496
|
|
|
426
497
|
// src/commands/task/create.ts
|
|
427
498
|
import { Command as Command5 } from "commander";
|
|
428
|
-
var createCmd = new Command5("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)").
|
|
499
|
+
var createCmd = new Command5("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(
|
|
500
|
+
"--auction-type <type>",
|
|
501
|
+
"Auction subtype: dutch, english, reverse_dutch, reverse_english (required for auction mode)"
|
|
502
|
+
).option(
|
|
503
|
+
"--auction-start-price <usdc>",
|
|
504
|
+
"Starting clock price in USDC for reverse_dutch (required for reverse_dutch)"
|
|
505
|
+
).option(
|
|
506
|
+
"--auction-floor-price <usdc>",
|
|
507
|
+
"Floor price in USDC for dutch clock (optional, defaults to 0)"
|
|
508
|
+
).option("--hook <address>", "ITaskHook contract address (optional)").option(
|
|
509
|
+
"--hook-data <hex>",
|
|
510
|
+
"Hook config bytes forwarded to checkFund; encode uint32 as 4 big-endian bytes (e.g. 0x000006b4 for a 1800s TWAP window)"
|
|
511
|
+
).option("--evaluator <address>", "Evaluator address (optional)").option("--evaluator-fee-bps <bps>", "Evaluator fee in basis points (optional)").option("--evaluation-window <hours>", "Evaluation window in hours (default: 24)").option("--appeal-window <hours>", "Appeal window in hours (default: 24)").option("--dispute-resolver <address>", "Dispute resolver address (optional)").action(
|
|
429
512
|
async (opts) => {
|
|
430
|
-
if (opts.mode === "auction"
|
|
431
|
-
|
|
513
|
+
if (opts.mode === "auction") {
|
|
514
|
+
if (!opts.maxPrice) {
|
|
515
|
+
return void printError("--max-price is required for auction mode");
|
|
516
|
+
}
|
|
517
|
+
if (!opts.auctionType) {
|
|
518
|
+
return void printError(
|
|
519
|
+
"--auction-type is required for auction mode (dutch, english, reverse_dutch, reverse_english)"
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
const validTypes = ["dutch", "english", "reverse_dutch", "reverse_english"];
|
|
523
|
+
if (!validTypes.includes(opts.auctionType)) {
|
|
524
|
+
return void printError(
|
|
525
|
+
`--auction-type must be one of: ${validTypes.join(", ")}. Got: ${opts.auctionType}`
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
if (opts.auctionType === "reverse_dutch" && !opts.auctionStartPrice) {
|
|
529
|
+
return void printError(
|
|
530
|
+
"--auction-start-price is required for reverse_dutch auction type"
|
|
531
|
+
);
|
|
532
|
+
}
|
|
432
533
|
}
|
|
433
534
|
const rewardBaseUnits = String(Math.round(parseFloat(opts.reward) * 1e6));
|
|
434
535
|
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [];
|
|
@@ -450,6 +551,52 @@ var createCmd = new Command5("create").description("Create a new task (costs rew
|
|
|
450
551
|
if (opts.maxPrice) {
|
|
451
552
|
body.maxPrice = String(Math.round(parseFloat(opts.maxPrice) * 1e6));
|
|
452
553
|
}
|
|
554
|
+
if (opts.auctionType) {
|
|
555
|
+
body.auctionType = opts.auctionType;
|
|
556
|
+
}
|
|
557
|
+
if (opts.auctionStartPrice) {
|
|
558
|
+
body.auctionStartPrice = String(Math.round(parseFloat(opts.auctionStartPrice) * 1e6));
|
|
559
|
+
}
|
|
560
|
+
if (opts.auctionFloorPrice) {
|
|
561
|
+
body.auctionFloorPrice = String(Math.round(parseFloat(opts.auctionFloorPrice) * 1e6));
|
|
562
|
+
}
|
|
563
|
+
const ethAddrRe = /^0x[0-9a-fA-F]{40}$/;
|
|
564
|
+
if (opts.hook && !ethAddrRe.test(opts.hook)) {
|
|
565
|
+
return void printError("--hook must be a valid Ethereum address (0x + 40 hex chars)");
|
|
566
|
+
}
|
|
567
|
+
if (opts.hookData && !/^0x(?:[0-9a-fA-F]{2})*$/.test(opts.hookData)) {
|
|
568
|
+
return void printError(
|
|
569
|
+
"--hook-data must be a 0x-prefixed hex string with an even number of hex digits"
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
let feeBps;
|
|
573
|
+
if (opts.evaluator) {
|
|
574
|
+
if (!ethAddrRe.test(opts.evaluator)) {
|
|
575
|
+
return void printError(
|
|
576
|
+
"--evaluator must be a valid Ethereum address (0x + 40 hex chars)"
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
if (opts.evaluatorFeeBps) {
|
|
580
|
+
feeBps = Number(opts.evaluatorFeeBps);
|
|
581
|
+
if (!Number.isInteger(feeBps) || feeBps < 0 || feeBps > 1e4) {
|
|
582
|
+
return void printError("--evaluator-fee-bps must be an integer between 0 and 10000");
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (opts.disputeResolver && !ethAddrRe.test(opts.disputeResolver)) {
|
|
586
|
+
return void printError(
|
|
587
|
+
"--dispute-resolver must be a valid Ethereum address (0x + 40 hex chars)"
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (opts.hook) body.hookContract = opts.hook;
|
|
592
|
+
if (opts.hookData) body.hookData = opts.hookData;
|
|
593
|
+
if (opts.evaluator) {
|
|
594
|
+
body.evaluator = opts.evaluator;
|
|
595
|
+
if (feeBps !== void 0) body.evaluatorFeeBps = feeBps;
|
|
596
|
+
if (opts.evaluationWindow) body.evaluationWindowHours = parseFloat(opts.evaluationWindow);
|
|
597
|
+
if (opts.appealWindow) body.appealWindowHours = parseFloat(opts.appealWindow);
|
|
598
|
+
if (opts.disputeResolver) body.disputeResolver = opts.disputeResolver;
|
|
599
|
+
}
|
|
453
600
|
const result = await x402Post("/api/tasks", body);
|
|
454
601
|
printResult({ taskId: result.taskId });
|
|
455
602
|
}
|
|
@@ -457,11 +604,15 @@ var createCmd = new Command5("create").description("Create a new task (costs rew
|
|
|
457
604
|
|
|
458
605
|
// src/commands/task/search.ts
|
|
459
606
|
import { Command as Command6 } from "commander";
|
|
460
|
-
var listCmd = new Command6("list").alias("search").description("List available tasks").option("--status <status>", "Filter by status (e.g. open)", "open").option("--mode <mode>", "Filter by mode (bounty, claim, pitch, benchmark, auction)").option(
|
|
607
|
+
var listCmd = new Command6("list").alias("search").description("List available tasks").option("--status <status>", "Filter by status (e.g. open)", "open").option("--mode <mode>", "Filter by mode (bounty, claim, pitch, benchmark, auction)").option(
|
|
608
|
+
"--auction-type <type>",
|
|
609
|
+
"Filter auction tasks by subtype (dutch, english, reverse_dutch, reverse_english)"
|
|
610
|
+
).option("--tags <tags>", "Comma-separated tags to filter by").option("--skill <skill>", "Filter by skill tag (comma-separated, alias for --tags)").option("--reward-min <n>", "Minimum reward in USDC").option("--reward-max <n>", "Maximum reward in USDC").option("--deadline-hours <n>", "Only tasks expiring within this many hours").option("--limit <n>", "Maximum results to return", "20").option("--cursor <cursor>", "Cursor from previous page (nextCursor in JSON output)").action(
|
|
461
611
|
async (opts) => {
|
|
462
612
|
const params = new URLSearchParams();
|
|
463
613
|
if (opts.status) params.set("status", opts.status);
|
|
464
614
|
if (opts.mode) params.set("mode", opts.mode);
|
|
615
|
+
if (opts.auctionType) params.set("auctionType", opts.auctionType);
|
|
465
616
|
const tagsValue = opts.tags ?? opts.skill;
|
|
466
617
|
if (tagsValue) params.set("tags", tagsValue);
|
|
467
618
|
if (opts.rewardMin)
|
|
@@ -489,48 +640,170 @@ var getCmd = new Command7("get").description("Get task details").argument("<task
|
|
|
489
640
|
// src/commands/task/submit.ts
|
|
490
641
|
import { Command as Command8 } from "commander";
|
|
491
642
|
import { promises as fs2 } from "fs";
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
643
|
+
import { basename, extname } from "path";
|
|
644
|
+
function collectFile(value, previous) {
|
|
645
|
+
return [...previous, value];
|
|
646
|
+
}
|
|
647
|
+
function mimeTypeForPath(filePath) {
|
|
648
|
+
switch (extname(filePath).toLowerCase()) {
|
|
649
|
+
case ".png":
|
|
650
|
+
return "image/png";
|
|
651
|
+
case ".jpg":
|
|
652
|
+
case ".jpeg":
|
|
653
|
+
return "image/jpeg";
|
|
654
|
+
case ".webp":
|
|
655
|
+
return "image/webp";
|
|
656
|
+
case ".gif":
|
|
657
|
+
return "image/gif";
|
|
658
|
+
case ".svg":
|
|
659
|
+
return "image/svg+xml";
|
|
660
|
+
case ".pdf":
|
|
661
|
+
return "application/pdf";
|
|
662
|
+
case ".mp4":
|
|
663
|
+
return "video/mp4";
|
|
664
|
+
case ".webm":
|
|
665
|
+
return "video/webm";
|
|
666
|
+
case ".mp3":
|
|
667
|
+
return "audio/mpeg";
|
|
668
|
+
case ".wav":
|
|
669
|
+
return "audio/wav";
|
|
670
|
+
case ".md":
|
|
671
|
+
return "text/markdown";
|
|
672
|
+
case ".txt":
|
|
673
|
+
return "text/plain";
|
|
674
|
+
case ".json":
|
|
675
|
+
return "application/json";
|
|
676
|
+
case ".zip":
|
|
677
|
+
return "application/zip";
|
|
678
|
+
default:
|
|
679
|
+
return "application/octet-stream";
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
var submitCmd = new Command8("submit").description("Submit work for a task").argument("<taskId>", "Task ID (0x-prefixed hex)").option("--file <path>", "Path to a submission file (repeatable)", collectFile, []).action(async (taskId, opts) => {
|
|
683
|
+
try {
|
|
684
|
+
if (!opts.file || opts.file.length === 0) {
|
|
685
|
+
printError("--file is required");
|
|
686
|
+
}
|
|
687
|
+
const keystore = await loadKeystore();
|
|
688
|
+
const signature = await signMessage(`taskmarket:submit:${taskId}`, keystore);
|
|
689
|
+
const body = {
|
|
690
|
+
workerAddress: keystore.walletAddress,
|
|
691
|
+
signature,
|
|
692
|
+
artifacts: await Promise.all(
|
|
693
|
+
opts.file.map(async (filePath) => {
|
|
694
|
+
const fileContent = await fs2.readFile(filePath);
|
|
695
|
+
return {
|
|
696
|
+
fileName: basename(filePath),
|
|
697
|
+
mimeType: mimeTypeForPath(filePath),
|
|
698
|
+
role: "attachment",
|
|
699
|
+
file: fileContent.toString("base64")
|
|
700
|
+
};
|
|
701
|
+
})
|
|
702
|
+
)
|
|
703
|
+
};
|
|
704
|
+
const result = await apiPost(`/api/tasks/${taskId}/submissions`, {
|
|
705
|
+
...body
|
|
706
|
+
});
|
|
707
|
+
printResult({ submissionId: result.submissionId });
|
|
708
|
+
} finally {
|
|
709
|
+
submitCmd.setOptionValue("file", []);
|
|
710
|
+
}
|
|
503
711
|
});
|
|
504
712
|
|
|
505
713
|
// src/commands/task/accept.ts
|
|
506
714
|
import { Command as Command9 } from "commander";
|
|
507
|
-
var acceptCmd = new Command9("accept").description("Accept a submission (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <addr>", "Worker wallet address").
|
|
715
|
+
var acceptCmd = new Command9("accept").description("Accept a submission (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <addr>", "Worker wallet address").option(
|
|
716
|
+
"--deliverable <hash>",
|
|
717
|
+
"Deliverable hash to commit on-chain (32-byte hex). Backend will look it up from the submission if omitted."
|
|
718
|
+
).action(async (taskId, opts) => {
|
|
719
|
+
if (opts.deliverable && !/^0x[0-9a-fA-F]{64}$/.test(opts.deliverable)) {
|
|
720
|
+
throw new Error("--deliverable must be a 0x-prefixed 32-byte hex string (0x + 64 hex chars)");
|
|
721
|
+
}
|
|
508
722
|
await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
509
723
|
taskId,
|
|
510
|
-
worker: opts.worker
|
|
724
|
+
worker: opts.worker,
|
|
725
|
+
...opts.deliverable ? { deliverable: opts.deliverable } : {}
|
|
511
726
|
});
|
|
512
727
|
printResult({ accepted: true });
|
|
513
728
|
});
|
|
514
729
|
|
|
515
|
-
// src/commands/task/
|
|
730
|
+
// src/commands/task/accept-submissions.ts
|
|
516
731
|
import { Command as Command10 } from "commander";
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
if (
|
|
520
|
-
|
|
732
|
+
function parseWinner(spec) {
|
|
733
|
+
const parts = spec.split(":");
|
|
734
|
+
if (parts.length < 2 || parts.length > 4) {
|
|
735
|
+
throw new Error(
|
|
736
|
+
`Invalid --winner value "${spec}". Expected <addr>:<share>[:<submissionId>][:<deliverable>]`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
const [worker, shareStr, submissionId, deliverable] = parts;
|
|
740
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(worker)) {
|
|
741
|
+
throw new Error(`Invalid worker address in "${spec}"`);
|
|
742
|
+
}
|
|
743
|
+
const share = parseInt(shareStr, 10);
|
|
744
|
+
if (Number.isNaN(share) || share < 1 || share > 1e4) {
|
|
745
|
+
throw new Error(`Invalid share in "${spec}" \u2014 must be integer 1..10000 (basis points)`);
|
|
746
|
+
}
|
|
747
|
+
if (deliverable && !/^0x[0-9a-fA-F]{64}$/.test(deliverable)) {
|
|
748
|
+
throw new Error(`Invalid deliverable hash in "${spec}" \u2014 must be 0x + 64 hex chars`);
|
|
749
|
+
}
|
|
750
|
+
return {
|
|
751
|
+
worker,
|
|
752
|
+
share,
|
|
753
|
+
...submissionId ? { submissionId } : {},
|
|
754
|
+
...deliverable ? { deliverable } : {}
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
var acceptSubmissionsCmd = new Command10("accept-submissions").description(
|
|
758
|
+
"Accept N submissions for a Bounty/Benchmark task with explicit share basis points (costs 0.001 USDC).\nShares must sum to 10000. The backend resolves each winner's deliverable from the submission row\nif --winner omits the explicit hash.\n\nFor ranked payouts, pass winners in rank order \u2014 workers[0] is the primary winner.\n\nExamples:\n task accept-submissions 0x\u2026 --winner 0xAlice:5000 --winner 0xBob:3000 --winner 0xCarol:2000\n task accept-submissions 0x\u2026 --winner 0xAlice:5000:sub-uuid --winner 0xBob:5000:sub-uuid2"
|
|
759
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption(
|
|
760
|
+
"--winner <spec...>",
|
|
761
|
+
"Winner spec <addr>:<share>[:<submissionId>][:<deliverable>]. Pass multiple times."
|
|
762
|
+
).action(async (taskId, opts) => {
|
|
763
|
+
let winners;
|
|
764
|
+
try {
|
|
765
|
+
winners = opts.winner.map(parseWinner);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
768
|
+
return;
|
|
521
769
|
}
|
|
522
|
-
const
|
|
770
|
+
const sum = winners.reduce((a, w) => a + w.share, 0);
|
|
771
|
+
if (sum !== 1e4) {
|
|
772
|
+
printError(`Winner shares must sum to 10000 basis points (got ${sum})`);
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const result = await x402Post(`/api/tasks/${taskId}/accept-submissions`, {
|
|
523
776
|
taskId,
|
|
524
|
-
|
|
525
|
-
rating,
|
|
526
|
-
...opts.feedback ? { feedbackText: opts.feedback } : {}
|
|
777
|
+
winners
|
|
527
778
|
});
|
|
528
|
-
printResult({
|
|
779
|
+
printResult({ accepted: result.success, winners: winners.length });
|
|
529
780
|
});
|
|
530
781
|
|
|
531
|
-
// src/commands/task/
|
|
782
|
+
// src/commands/task/rate.ts
|
|
532
783
|
import { Command as Command11 } from "commander";
|
|
533
|
-
var
|
|
784
|
+
var rateCmd = new Command11("rate").description("Rate a worker (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <addr>", "Worker wallet address").requiredOption("--rating <n>", "Rating 0-100").option("--feedback <text>", "Optional feedback text").option(
|
|
785
|
+
"--rater-agent-id <id>",
|
|
786
|
+
"ERC-8004 agent ID of the requester (overrides server-side lookup)"
|
|
787
|
+
).action(
|
|
788
|
+
async (taskId, opts) => {
|
|
789
|
+
const rating = parseInt(opts.rating, 10);
|
|
790
|
+
if (rating < 0 || rating > 100) {
|
|
791
|
+
printError("Rating must be between 0 and 100");
|
|
792
|
+
}
|
|
793
|
+
const result = await x402Post(`/api/tasks/${taskId}/rate`, {
|
|
794
|
+
taskId,
|
|
795
|
+
worker: opts.worker,
|
|
796
|
+
rating,
|
|
797
|
+
...opts.feedback ? { feedbackText: opts.feedback } : {},
|
|
798
|
+
...opts.raterAgentId ? { raterAgentId: parseInt(opts.raterAgentId, 10) } : {}
|
|
799
|
+
});
|
|
800
|
+
printResult({ feedbackId: result.feedbackId });
|
|
801
|
+
}
|
|
802
|
+
);
|
|
803
|
+
|
|
804
|
+
// src/commands/task/claim.ts
|
|
805
|
+
import { Command as Command12 } from "commander";
|
|
806
|
+
var claimCmd = new Command12("claim").description("Claim a task as a worker").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
534
807
|
const keystore = await loadKeystore();
|
|
535
808
|
const message = `taskmarket:claim:${taskId}`;
|
|
536
809
|
const signature = await signMessage(message, keystore);
|
|
@@ -542,11 +815,12 @@ var claimCmd = new Command11("claim").description("Claim a task as a worker").ar
|
|
|
542
815
|
});
|
|
543
816
|
|
|
544
817
|
// src/commands/task/pitch.ts
|
|
545
|
-
import { Command as
|
|
546
|
-
var pitchCmd = new
|
|
818
|
+
import { Command as Command13 } from "commander";
|
|
819
|
+
var pitchCmd = new Command13("pitch").description("Submit a pitch for a task (costs 0.001 USDC, anchors hash on-chain)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--text <text>", "Pitch text").option("--duration <hours>", "Estimated duration in hours").action(async (taskId, opts) => {
|
|
547
820
|
const keystore = await loadKeystore();
|
|
548
821
|
const signature = await signMessage(`taskmarket:pitch:${taskId}`, keystore);
|
|
549
|
-
const result = await
|
|
822
|
+
const result = await x402Post(`/api/tasks/${taskId}/pitches`, {
|
|
823
|
+
taskId,
|
|
550
824
|
workerAddress: keystore.walletAddress,
|
|
551
825
|
pitchText: opts.text,
|
|
552
826
|
...opts.duration ? { estimatedDuration: parseInt(opts.duration, 10) } : {},
|
|
@@ -556,9 +830,9 @@ var pitchCmd = new Command12("pitch").description("Submit a pitch for a task").a
|
|
|
556
830
|
});
|
|
557
831
|
|
|
558
832
|
// src/commands/task/select-worker.ts
|
|
559
|
-
import { Command as
|
|
833
|
+
import { Command as Command14 } from "commander";
|
|
560
834
|
import { keccak256, toBytes } from "viem";
|
|
561
|
-
var selectWorkerCmd = new
|
|
835
|
+
var selectWorkerCmd = new Command14("select-worker").description("Select a worker from pitches (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--pitch <pitchId>", "Pitch ID to select").requiredOption("--worker <address>", "Worker wallet address to assign").action(async (taskId, opts) => {
|
|
562
836
|
const keystore = await loadKeystore();
|
|
563
837
|
const hash = keccak256(toBytes(taskId + opts.pitch + opts.worker));
|
|
564
838
|
const signature = await signMessage(hash, keystore);
|
|
@@ -572,11 +846,12 @@ var selectWorkerCmd = new Command13("select-worker").description("Select a worke
|
|
|
572
846
|
});
|
|
573
847
|
|
|
574
848
|
// src/commands/task/proof.ts
|
|
575
|
-
import { Command as
|
|
576
|
-
var proofCmd = new
|
|
849
|
+
import { Command as Command15 } from "commander";
|
|
850
|
+
var proofCmd = new Command15("proof").description("Submit a benchmark proof (costs 0.001 USDC, anchors hash on-chain)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--data <data>", "Proof data").requiredOption("--type <type>", "Proof type").option("--metric <val>", "Metric value").action(async (taskId, opts) => {
|
|
577
851
|
const keystore = await loadKeystore();
|
|
578
852
|
const signature = await signMessage(`taskmarket:proof:${taskId}`, keystore);
|
|
579
|
-
const result = await
|
|
853
|
+
const result = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
854
|
+
taskId,
|
|
580
855
|
workerAddress: keystore.walletAddress,
|
|
581
856
|
proofData: opts.data,
|
|
582
857
|
proofType: opts.type,
|
|
@@ -587,8 +862,8 @@ var proofCmd = new Command14("proof").description("Submit a proof for a task").a
|
|
|
587
862
|
});
|
|
588
863
|
|
|
589
864
|
// src/commands/task/bid.ts
|
|
590
|
-
import { Command as
|
|
591
|
-
var bidCmd = new
|
|
865
|
+
import { Command as Command16 } from "commander";
|
|
866
|
+
var bidCmd = new Command16("bid").description("Submit a bid on an auction task").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--price <usdc>", "Bid price in USDC (e.g. 3 or 1.5)").action(async (taskId, opts) => {
|
|
592
867
|
const priceBaseUnits = String(Math.round(parseFloat(opts.price) * 1e6));
|
|
593
868
|
const result = await x402Post(`/api/tasks/${taskId}/bids`, {
|
|
594
869
|
taskId,
|
|
@@ -597,9 +872,32 @@ var bidCmd = new Command15("bid").description("Submit a bid on an auction task")
|
|
|
597
872
|
printResult({ bidId: result.bidId });
|
|
598
873
|
});
|
|
599
874
|
|
|
875
|
+
// src/commands/task/auction-accept.ts
|
|
876
|
+
import { Command as Command17 } from "commander";
|
|
877
|
+
var auctionAcceptCmd = new Command17("auction-accept").description("Accept current clock price on a dutch or reverse_dutch auction task").argument("<taskId>", "Task ID (0x-prefixed hex)").option(
|
|
878
|
+
"--min-price <usdc>",
|
|
879
|
+
"Reject if current clock price is below this value (price floor guard)"
|
|
880
|
+
).action(async (taskId, opts) => {
|
|
881
|
+
const body = { taskId };
|
|
882
|
+
if (opts.minPrice) {
|
|
883
|
+
const [intPart = "0", fracPart = ""] = opts.minPrice.trim().split(".");
|
|
884
|
+
if (!/^\d+$/.test(intPart) || fracPart && !/^\d+$/.test(fracPart)) {
|
|
885
|
+
throw new Error(`--min-price: invalid number "${opts.minPrice}"`);
|
|
886
|
+
}
|
|
887
|
+
const padded = fracPart.slice(0, 6).padEnd(6, "0");
|
|
888
|
+
body.minPrice = (BigInt(intPart) * 1000000n + BigInt(padded)).toString();
|
|
889
|
+
}
|
|
890
|
+
const result = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
891
|
+
printResult({
|
|
892
|
+
acceptedPrice: result.acceptedPrice,
|
|
893
|
+
acceptedPriceUsdc: (Number(result.acceptedPrice) / 1e6).toFixed(6),
|
|
894
|
+
workerAddress: result.workerAddress
|
|
895
|
+
});
|
|
896
|
+
});
|
|
897
|
+
|
|
600
898
|
// src/commands/task/submissions.ts
|
|
601
|
-
import { Command as
|
|
602
|
-
var submissionsCmd = new
|
|
899
|
+
import { Command as Command18 } from "commander";
|
|
900
|
+
var submissionsCmd = new Command18("submissions").description("List submissions for a task").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
603
901
|
let subs;
|
|
604
902
|
try {
|
|
605
903
|
subs = await apiGet(`/api/tasks/${taskId}/submissions`);
|
|
@@ -611,8 +909,8 @@ var submissionsCmd = new Command16("submissions").description("List submissions
|
|
|
611
909
|
});
|
|
612
910
|
|
|
613
911
|
// src/commands/task/select-winner.ts
|
|
614
|
-
import { Command as
|
|
615
|
-
var selectWinnerCmd = new
|
|
912
|
+
import { Command as Command19 } from "commander";
|
|
913
|
+
var selectWinnerCmd = new Command19("select-winner").description("Select lowest bidder after auction deadline (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
616
914
|
let result;
|
|
617
915
|
try {
|
|
618
916
|
result = await apiPost(`/api/tasks/${taskId}/bids/select-winner`, {
|
|
@@ -626,56 +924,296 @@ var selectWinnerCmd = new Command17("select-winner").description("Select lowest
|
|
|
626
924
|
});
|
|
627
925
|
|
|
628
926
|
// src/commands/task/download.ts
|
|
629
|
-
import { Command as
|
|
927
|
+
import { Command as Command20 } from "commander";
|
|
630
928
|
import { writeFileSync } from "fs";
|
|
631
|
-
var downloadCmd = new
|
|
632
|
-
|
|
633
|
-
|
|
929
|
+
var downloadCmd = new Command20("download").description("Download a submission file (requester or worker)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--submission <id>", "Submission ID (from `task submissions`)").option("--artifact <id>", "Artifact ID for multi-artifact submissions").option("--output <path>", "Save to file instead of printing to stdout").action(
|
|
930
|
+
async (taskId, opts) => {
|
|
931
|
+
const keystore = await loadKeystore();
|
|
932
|
+
let presignedUrl;
|
|
933
|
+
try {
|
|
934
|
+
const body = {
|
|
935
|
+
taskId,
|
|
936
|
+
submissionId: opts.submission,
|
|
937
|
+
deviceId: keystore.deviceId,
|
|
938
|
+
apiToken: keystore.apiToken
|
|
939
|
+
};
|
|
940
|
+
if (opts.artifact) {
|
|
941
|
+
body.artifactId = opts.artifact;
|
|
942
|
+
}
|
|
943
|
+
const result = await apiPost(
|
|
944
|
+
`/api/tasks/${taskId}/submissions/${opts.submission}/preview`,
|
|
945
|
+
body
|
|
946
|
+
);
|
|
947
|
+
presignedUrl = result.presignedUrl;
|
|
948
|
+
} catch (err) {
|
|
949
|
+
const msg = err instanceof Error ? err.message : "Failed to get download URL.";
|
|
950
|
+
printError(msg);
|
|
951
|
+
}
|
|
952
|
+
const res = await fetch(presignedUrl);
|
|
953
|
+
if (!res.ok) {
|
|
954
|
+
printError(`Failed to download file: ${res.status}`);
|
|
955
|
+
}
|
|
956
|
+
const content = Buffer.from(await res.arrayBuffer());
|
|
957
|
+
if (opts.output) {
|
|
958
|
+
writeFileSync(opts.output, content);
|
|
959
|
+
process.stdout.write(JSON.stringify({ ok: true, data: { savedTo: opts.output } }) + "\n");
|
|
960
|
+
} else {
|
|
961
|
+
process.stdout.write(content);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
);
|
|
965
|
+
|
|
966
|
+
// src/commands/task/cancel.ts
|
|
967
|
+
import { Command as Command21 } from "commander";
|
|
968
|
+
var cancelCmd = new Command21("cancel").description("Cancel an open task and refund the escrowed reward (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
969
|
+
const result = await x402Post(`/api/tasks/${taskId}/cancel`, { taskId });
|
|
970
|
+
printResult(result);
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
// src/commands/task/update.ts
|
|
974
|
+
import { Command as Command22 } from "commander";
|
|
975
|
+
function toBaseUnits(humanUsdc) {
|
|
976
|
+
const [intPart = "0", fracPart = ""] = humanUsdc.trim().split(".");
|
|
977
|
+
const padded = fracPart.slice(0, 6).padEnd(6, "0");
|
|
978
|
+
return (BigInt(intPart) * 1000000n + BigInt(padded)).toString();
|
|
979
|
+
}
|
|
980
|
+
var updateCmd = new Command22("update").description("Update an open task (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").option("--reward <usdc>", 'New reward in USDC (human units, e.g. "50")').option("--extend-expiry <seconds>", "Extend expiry by this many seconds").option("--bid-deadline <iso>", "New bid deadline (ISO 8601)").option("--pitch-deadline <iso>", "New pitch deadline (ISO 8601)").option("--auction-floor-price <usdc>", "New auction floor price in USDC").option("--auction-start-price <usdc>", "New auction start price in USDC").option("--description <text>", "New description").option("--tags <csv>", "New tags (comma-separated)").option("--metric-description <text>", "New metric description").action(
|
|
981
|
+
async (taskId, opts) => {
|
|
982
|
+
const body = { taskId };
|
|
983
|
+
if (opts.reward !== void 0) {
|
|
984
|
+
body.reward = toBaseUnits(opts.reward);
|
|
985
|
+
}
|
|
986
|
+
if (opts.extendExpiry !== void 0) {
|
|
987
|
+
const delta = parseInt(opts.extendExpiry, 10);
|
|
988
|
+
if (!Number.isFinite(delta) || delta < 0) {
|
|
989
|
+
printError(`--extend-expiry must be a non-negative integer, got: ${opts.extendExpiry}`);
|
|
990
|
+
}
|
|
991
|
+
const task = await apiGet(`/api/tasks/${taskId}`);
|
|
992
|
+
if (!task) {
|
|
993
|
+
printError(`Task not found: ${taskId}`);
|
|
994
|
+
}
|
|
995
|
+
const currentExpiry = Math.floor(new Date(task.expiryTime).getTime() / 1e3);
|
|
996
|
+
body.expiryTime = currentExpiry + delta;
|
|
997
|
+
}
|
|
998
|
+
if (opts.bidDeadline !== void 0) {
|
|
999
|
+
const ts = Math.floor(new Date(opts.bidDeadline).getTime() / 1e3);
|
|
1000
|
+
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
1001
|
+
printError("--bid-deadline must be in the future");
|
|
1002
|
+
} else {
|
|
1003
|
+
body.bidDeadline = ts;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (opts.pitchDeadline !== void 0) {
|
|
1007
|
+
const ts = Math.floor(new Date(opts.pitchDeadline).getTime() / 1e3);
|
|
1008
|
+
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
1009
|
+
printError("--pitch-deadline must be in the future");
|
|
1010
|
+
} else {
|
|
1011
|
+
body.pitchDeadline = ts;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (opts.auctionFloorPrice !== void 0) {
|
|
1015
|
+
body.auctionFloorPrice = toBaseUnits(opts.auctionFloorPrice);
|
|
1016
|
+
}
|
|
1017
|
+
if (opts.auctionStartPrice !== void 0) {
|
|
1018
|
+
body.auctionStartPrice = toBaseUnits(opts.auctionStartPrice);
|
|
1019
|
+
}
|
|
1020
|
+
if (opts.description !== void 0) {
|
|
1021
|
+
body.description = opts.description;
|
|
1022
|
+
}
|
|
1023
|
+
if (opts.tags !== void 0) {
|
|
1024
|
+
body.tags = opts.tags.split(",").map((t) => t.trim()).filter(Boolean);
|
|
1025
|
+
}
|
|
1026
|
+
if (opts.metricDescription !== void 0) {
|
|
1027
|
+
body.metricDescription = opts.metricDescription;
|
|
1028
|
+
}
|
|
1029
|
+
const result = await x402Post(`/api/tasks/${taskId}/update`, body);
|
|
1030
|
+
printResult(result);
|
|
1031
|
+
}
|
|
1032
|
+
);
|
|
1033
|
+
|
|
1034
|
+
// src/commands/task/forfeit.ts
|
|
1035
|
+
import { Command as Command23 } from "commander";
|
|
1036
|
+
var forfeitCmd = new Command23("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) => {
|
|
634
1037
|
try {
|
|
635
|
-
const
|
|
1038
|
+
const keystore = await loadKeystore();
|
|
1039
|
+
const message = `taskmarket:forfeit:${taskId}`;
|
|
1040
|
+
const signature = await signMessage(message, keystore);
|
|
1041
|
+
const result = await apiPost(`/api/tasks/${taskId}/forfeit`, {
|
|
636
1042
|
taskId,
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
apiToken: keystore.apiToken
|
|
1043
|
+
requesterAddress: keystore.walletAddress,
|
|
1044
|
+
signature
|
|
640
1045
|
});
|
|
641
|
-
|
|
1046
|
+
printResult(result);
|
|
642
1047
|
} catch (err) {
|
|
643
|
-
|
|
644
|
-
printError(msg);
|
|
1048
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
645
1049
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
// src/commands/task/evaluate.ts
|
|
1053
|
+
import { Command as Command24 } from "commander";
|
|
1054
|
+
var evaluateCmd = new Command24("evaluate").description("Submit an evaluation verdict for a task in Review state").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict: approve, reject, or partial").option("--score <n>", "Score 0-1000 (default: 1000)", "1000").option("--confidence <n>", "Confidence 0-1000 (default: 1000)", "1000").option("--evidence-hash <hash>", "Evidence hash (32-byte hex)").option(
|
|
1055
|
+
"--award <worker:amount:rank>",
|
|
1056
|
+
"Award entry (repeatable): worker:amountUSDC:rank",
|
|
1057
|
+
collect,
|
|
1058
|
+
[]
|
|
1059
|
+
).action(
|
|
1060
|
+
async (taskId, opts) => {
|
|
1061
|
+
const validVerdicts = ["approve", "reject", "partial"];
|
|
1062
|
+
if (!validVerdicts.includes(opts.verdict)) {
|
|
1063
|
+
return void printError(`--verdict must be one of: ${validVerdicts.join(", ")}`);
|
|
1064
|
+
}
|
|
1065
|
+
const awards = [];
|
|
1066
|
+
for (const entry of opts.award) {
|
|
1067
|
+
const parts = entry.split(":");
|
|
1068
|
+
if (parts.length < 3 || !parts[0] || !parts[1] || !parts[2]) {
|
|
1069
|
+
return void printError(
|
|
1070
|
+
`Invalid award format '${entry}'. Expected worker:amountUSDC:rank`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
const [worker, amountUSDC, rankStr] = parts;
|
|
1074
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(worker)) {
|
|
1075
|
+
return void printError(
|
|
1076
|
+
`Invalid worker address in '${entry}': must be 0x-prefixed 40-char hex`
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
const parsedAmount = Number(amountUSDC);
|
|
1080
|
+
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
|
|
1081
|
+
return void printError(`Invalid amount in '${entry}': must be a positive number`);
|
|
1082
|
+
}
|
|
1083
|
+
const microUnits = Math.round(parsedAmount * 1e6);
|
|
1084
|
+
if (!Number.isFinite(microUnits) || microUnits > Number.MAX_SAFE_INTEGER) {
|
|
1085
|
+
return void printError(`Amount in '${entry}' is too large to convert to micro-units`);
|
|
1086
|
+
}
|
|
1087
|
+
const parsedRank = Number(rankStr);
|
|
1088
|
+
if (!Number.isInteger(parsedRank) || parsedRank < 1) {
|
|
1089
|
+
return void printError(`Invalid rank in '${entry}': must be a positive integer`);
|
|
1090
|
+
}
|
|
1091
|
+
awards.push({ worker, amount: String(microUnits), rank: parsedRank });
|
|
1092
|
+
}
|
|
1093
|
+
const body = {
|
|
1094
|
+
taskId,
|
|
1095
|
+
verdict: opts.verdict,
|
|
1096
|
+
score: parseInt(opts.score, 10),
|
|
1097
|
+
confidence: parseInt(opts.confidence, 10),
|
|
1098
|
+
awards
|
|
1099
|
+
};
|
|
1100
|
+
if (opts.evidenceHash) {
|
|
1101
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(opts.evidenceHash)) {
|
|
1102
|
+
return void printError(
|
|
1103
|
+
"--evidence-hash must be a 0x-prefixed 32-byte hex string (0x + 64 hex chars)"
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
body.evidenceHash = opts.evidenceHash;
|
|
1107
|
+
}
|
|
1108
|
+
const result = await x402Post(`/api/tasks/${taskId}/evaluate`, body);
|
|
1109
|
+
printResult({ txHash: result.txHash });
|
|
649
1110
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
1111
|
+
);
|
|
1112
|
+
function collect(val, prev) {
|
|
1113
|
+
return prev.concat([val]);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/commands/task/appeal.ts
|
|
1117
|
+
import { Command as Command25 } from "commander";
|
|
1118
|
+
var appealCmd = new Command25("appeal").description("Appeal an evaluator verdict while in Appealing state").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1119
|
+
const result = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
1120
|
+
printResult({ txHash: result.txHash });
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
// src/commands/task/evaluator-timeout.ts
|
|
1124
|
+
import { Command as Command26 } from "commander";
|
|
1125
|
+
var evaluatorTimeoutCmd = new Command26("evaluator-timeout").description("Trigger evaluator timeout after the evaluation window expires (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1126
|
+
const result = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
1127
|
+
printResult({ txHash: result.txHash });
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
// src/commands/task/finalize-verdict.ts
|
|
1131
|
+
import { Command as Command27 } from "commander";
|
|
1132
|
+
var finalizeVerdictCmd = new Command27("finalize-verdict").description("Finalize an evaluator verdict after the appeal window expires (permissionless)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1133
|
+
const result = await x402Post(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
1134
|
+
printResult({ txHash: result.txHash });
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
// src/commands/task/resolve-dispute.ts
|
|
1138
|
+
import { Command as Command28 } from "commander";
|
|
1139
|
+
function parseAward(spec) {
|
|
1140
|
+
const parts = spec.split(":");
|
|
1141
|
+
if (parts.length !== 3) {
|
|
1142
|
+
throw new Error(`Invalid --award value "${spec}". Expected <addr>:<amount_usdc>:<rank>`);
|
|
1143
|
+
}
|
|
1144
|
+
const [worker, amountStr, rankStr] = parts;
|
|
1145
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(worker)) {
|
|
1146
|
+
throw new Error(`Invalid worker address in "${spec}"`);
|
|
1147
|
+
}
|
|
1148
|
+
const amount = parseFloat(amountStr);
|
|
1149
|
+
if (Number.isNaN(amount) || amount <= 0) {
|
|
1150
|
+
throw new Error(`Invalid amount in "${spec}" \u2014 must be a positive number`);
|
|
1151
|
+
}
|
|
1152
|
+
const rank = parseInt(rankStr, 10);
|
|
1153
|
+
if (!Number.isInteger(rank) || rank < 1) {
|
|
1154
|
+
throw new Error(`Invalid rank in "${spec}" \u2014 must be an integer >= 1`);
|
|
1155
|
+
}
|
|
1156
|
+
return {
|
|
1157
|
+
worker,
|
|
1158
|
+
amount: String(Math.round(amount * 1e6)),
|
|
1159
|
+
rank
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
var resolveDisputeCmd = new Command28("resolve-dispute").description(
|
|
1163
|
+
"Resolve a disputed task as the designated dispute resolver (X402 required).\n\nExamples:\n task resolve-dispute 0x\u2026 --verdict approve --award 0xAlice:5:1\n task resolve-dispute 0x\u2026 --verdict partial --award 0xAlice:3:1 --award 0xBob:2:2"
|
|
1164
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict type: approve or partial").requiredOption(
|
|
1165
|
+
"--award <spec...>",
|
|
1166
|
+
"Award spec <addr>:<amount_usdc>:<rank>. Pass multiple times."
|
|
1167
|
+
).action(async (taskId, opts) => {
|
|
1168
|
+
if (opts.verdict !== "approve" && opts.verdict !== "partial") {
|
|
1169
|
+
printError('--verdict must be "approve" or "partial"');
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
let awards;
|
|
1173
|
+
try {
|
|
1174
|
+
awards = opts.award.map(parseAward);
|
|
1175
|
+
} catch (err) {
|
|
1176
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
1177
|
+
return;
|
|
656
1178
|
}
|
|
1179
|
+
const result = await x402Post(`/api/tasks/${taskId}/resolve-dispute`, {
|
|
1180
|
+
taskId,
|
|
1181
|
+
verdict: opts.verdict,
|
|
1182
|
+
awards
|
|
1183
|
+
});
|
|
1184
|
+
printResult({ txHash: result.txHash });
|
|
657
1185
|
});
|
|
658
1186
|
|
|
659
1187
|
// src/commands/task/index.ts
|
|
660
|
-
var taskCommand = new
|
|
1188
|
+
var taskCommand = new Command29("task").description("Manage tasks");
|
|
661
1189
|
taskCommand.addCommand(createCmd);
|
|
662
1190
|
taskCommand.addCommand(listCmd);
|
|
663
1191
|
taskCommand.addCommand(getCmd);
|
|
664
1192
|
taskCommand.addCommand(submitCmd);
|
|
665
1193
|
taskCommand.addCommand(acceptCmd);
|
|
1194
|
+
taskCommand.addCommand(acceptSubmissionsCmd);
|
|
666
1195
|
taskCommand.addCommand(rateCmd);
|
|
667
1196
|
taskCommand.addCommand(claimCmd);
|
|
668
1197
|
taskCommand.addCommand(pitchCmd);
|
|
669
1198
|
taskCommand.addCommand(selectWorkerCmd);
|
|
670
1199
|
taskCommand.addCommand(proofCmd);
|
|
671
1200
|
taskCommand.addCommand(bidCmd);
|
|
1201
|
+
taskCommand.addCommand(auctionAcceptCmd);
|
|
672
1202
|
taskCommand.addCommand(submissionsCmd);
|
|
673
1203
|
taskCommand.addCommand(selectWinnerCmd);
|
|
674
1204
|
taskCommand.addCommand(downloadCmd);
|
|
1205
|
+
taskCommand.addCommand(cancelCmd);
|
|
1206
|
+
taskCommand.addCommand(updateCmd);
|
|
1207
|
+
taskCommand.addCommand(forfeitCmd);
|
|
1208
|
+
taskCommand.addCommand(evaluateCmd);
|
|
1209
|
+
taskCommand.addCommand(appealCmd);
|
|
1210
|
+
taskCommand.addCommand(evaluatorTimeoutCmd);
|
|
1211
|
+
taskCommand.addCommand(finalizeVerdictCmd);
|
|
1212
|
+
taskCommand.addCommand(resolveDisputeCmd);
|
|
675
1213
|
|
|
676
1214
|
// src/commands/agents.ts
|
|
677
|
-
import { Command as
|
|
678
|
-
var agentsCommand = new
|
|
1215
|
+
import { Command as Command30 } from "commander";
|
|
1216
|
+
var agentsCommand = new Command30("agents").description("Browse the agent directory").option("--sort <order>", "Sort order: reputation or tasks", "reputation").option("--skill <tag>", "Filter by skill tag").option("--search <query>", "Search by agentId or wallet address").option("--limit <n>", "Maximum results to return", "20").action(async (opts) => {
|
|
679
1217
|
const params = new URLSearchParams();
|
|
680
1218
|
if (opts.sort) params.set("sort", opts.sort);
|
|
681
1219
|
if (opts.skill) params.set("skill", opts.skill);
|
|
@@ -686,8 +1224,8 @@ var agentsCommand = new Command20("agents").description("Browse the agent direct
|
|
|
686
1224
|
});
|
|
687
1225
|
|
|
688
1226
|
// src/commands/inbox.ts
|
|
689
|
-
import { Command as
|
|
690
|
-
var inboxCommand = new
|
|
1227
|
+
import { Command as Command31 } from "commander";
|
|
1228
|
+
var inboxCommand = new Command31("inbox").description("Show tasks you created and tasks you are working on").action(async () => {
|
|
691
1229
|
let address;
|
|
692
1230
|
try {
|
|
693
1231
|
address = await getWalletAddress();
|
|
@@ -695,15 +1233,26 @@ var inboxCommand = new Command21("inbox").description("Show tasks you created an
|
|
|
695
1233
|
const msg = err instanceof Error ? err.message : "No keystore found. Run `taskmarket init` first.";
|
|
696
1234
|
printError(msg);
|
|
697
1235
|
}
|
|
698
|
-
const
|
|
1236
|
+
const taskResult = await apiGet(
|
|
699
1237
|
`/api/agents/inbox?address=${encodeURIComponent(address)}`
|
|
700
1238
|
);
|
|
701
|
-
|
|
1239
|
+
let pendingBids = [];
|
|
1240
|
+
try {
|
|
1241
|
+
const keystore = await loadKeystore();
|
|
1242
|
+
if (keystore.deviceId && keystore.apiToken) {
|
|
1243
|
+
const params = new URLSearchParams({ deviceId: keystore.deviceId });
|
|
1244
|
+
pendingBids = await apiGet(`/api/bids/my?${params.toString()}`, {
|
|
1245
|
+
headers: { "x-taskmarket-api-token": keystore.apiToken }
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
printResult({ ...taskResult, pendingBids });
|
|
702
1251
|
});
|
|
703
1252
|
|
|
704
1253
|
// src/commands/deposit.ts
|
|
705
|
-
import { Command as
|
|
706
|
-
var depositCommand = new
|
|
1254
|
+
import { Command as Command32 } from "commander";
|
|
1255
|
+
var depositCommand = new Command32("deposit").description("Show wallet address and network info for funding").action(async () => {
|
|
707
1256
|
let address;
|
|
708
1257
|
try {
|
|
709
1258
|
address = await getWalletAddress();
|
|
@@ -730,11 +1279,11 @@ var depositCommand = new Command22("deposit").description("Show wallet address a
|
|
|
730
1279
|
});
|
|
731
1280
|
|
|
732
1281
|
// src/commands/wallet/index.ts
|
|
733
|
-
import { Command as
|
|
1282
|
+
import { Command as Command37 } from "commander";
|
|
734
1283
|
|
|
735
1284
|
// src/commands/wallet/balance.ts
|
|
736
|
-
import { Command as
|
|
737
|
-
var walletBalanceCommand = new
|
|
1285
|
+
import { Command as Command33 } from "commander";
|
|
1286
|
+
var walletBalanceCommand = new Command33("balance").description("Show USDC balance").option("--address <addr>", "Address to check (defaults to own wallet)").action(async (opts) => {
|
|
738
1287
|
let address = opts.address;
|
|
739
1288
|
if (!address) {
|
|
740
1289
|
const keystore = await loadKeystore();
|
|
@@ -745,7 +1294,7 @@ var walletBalanceCommand = new Command23("balance").description("Show USDC balan
|
|
|
745
1294
|
});
|
|
746
1295
|
|
|
747
1296
|
// src/commands/wallet/import.ts
|
|
748
|
-
import { Command as
|
|
1297
|
+
import { Command as Command34 } from "commander";
|
|
749
1298
|
import { createInterface } from "readline";
|
|
750
1299
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
751
1300
|
function normalizePrivateKey(raw) {
|
|
@@ -780,7 +1329,7 @@ function promptHiddenInput(prompt) {
|
|
|
780
1329
|
});
|
|
781
1330
|
});
|
|
782
1331
|
}
|
|
783
|
-
var walletImportCommand = new
|
|
1332
|
+
var walletImportCommand = new Command34("import").description("Import an existing private key as the agent wallet").option("--key <privateKey>", "Private key to import (64 hex chars, with or without 0x prefix)").action(async (opts) => {
|
|
784
1333
|
if (await keystoreExists()) {
|
|
785
1334
|
const keystore = await loadKeystore();
|
|
786
1335
|
printResult({ address: keystore.walletAddress, agentId: keystore.agentId });
|
|
@@ -819,7 +1368,14 @@ var walletImportCommand = new Command24("import").description("Import an existin
|
|
|
819
1368
|
} = await res.json();
|
|
820
1369
|
const encryptedKey = encryptPrivateKey(deviceEncryptionKey, privateKey);
|
|
821
1370
|
let agentId = initialAgentId;
|
|
822
|
-
await saveKeystore({
|
|
1371
|
+
await saveKeystore({
|
|
1372
|
+
encryptedKey,
|
|
1373
|
+
walletAddress: address,
|
|
1374
|
+
deviceId,
|
|
1375
|
+
apiToken,
|
|
1376
|
+
agentId,
|
|
1377
|
+
keyServerUrl: API_URL
|
|
1378
|
+
});
|
|
823
1379
|
if (!agentId) {
|
|
824
1380
|
agentId = await pollAgentId(address);
|
|
825
1381
|
if (agentId) {
|
|
@@ -838,11 +1394,11 @@ var walletImportCommand = new Command24("import").description("Import an existin
|
|
|
838
1394
|
});
|
|
839
1395
|
|
|
840
1396
|
// src/commands/wallet/set-withdrawal-address.ts
|
|
841
|
-
import { Command as
|
|
1397
|
+
import { Command as Command35 } from "commander";
|
|
842
1398
|
function isValidAddress(addr) {
|
|
843
1399
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
844
1400
|
}
|
|
845
|
-
var setWithdrawalAddressCommand = new
|
|
1401
|
+
var setWithdrawalAddressCommand = new Command35("set-withdrawal-address").description("Set a withdrawal address for USDC withdrawals (one-time, free)").argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
|
|
846
1402
|
if (!isValidAddress(address)) {
|
|
847
1403
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
848
1404
|
}
|
|
@@ -864,8 +1420,8 @@ var setWithdrawalAddressCommand = new Command25("set-withdrawal-address").descri
|
|
|
864
1420
|
});
|
|
865
1421
|
|
|
866
1422
|
// src/commands/wallet/publish-key.ts
|
|
867
|
-
import { Command as
|
|
868
|
-
var publishKeyCommand = new
|
|
1423
|
+
import { Command as Command36 } from "commander";
|
|
1424
|
+
var publishKeyCommand = new Command36("publish-key").description("Publish your secp256k1 public key so others can encrypt files for you").action(async () => {
|
|
869
1425
|
let keystore;
|
|
870
1426
|
try {
|
|
871
1427
|
keystore = await loadKeystore();
|
|
@@ -884,14 +1440,14 @@ var publishKeyCommand = new Command26("publish-key").description("Publish your s
|
|
|
884
1440
|
});
|
|
885
1441
|
|
|
886
1442
|
// src/commands/wallet/index.ts
|
|
887
|
-
var walletCommand = new
|
|
1443
|
+
var walletCommand = new Command37("wallet").description("Wallet management commands");
|
|
888
1444
|
walletCommand.addCommand(walletBalanceCommand);
|
|
889
1445
|
walletCommand.addCommand(walletImportCommand);
|
|
890
1446
|
walletCommand.addCommand(setWithdrawalAddressCommand);
|
|
891
1447
|
walletCommand.addCommand(publishKeyCommand);
|
|
892
1448
|
|
|
893
1449
|
// src/commands/withdraw.ts
|
|
894
|
-
import { Command as
|
|
1450
|
+
import { Command as Command38 } from "commander";
|
|
895
1451
|
import { toHex as toHex2 } from "viem";
|
|
896
1452
|
var USDC_TYPES = {
|
|
897
1453
|
TransferWithAuthorization: [
|
|
@@ -903,7 +1459,7 @@ var USDC_TYPES = {
|
|
|
903
1459
|
{ name: "nonce", type: "bytes32" }
|
|
904
1460
|
]
|
|
905
1461
|
};
|
|
906
|
-
var withdrawCommand = new
|
|
1462
|
+
var withdrawCommand = new Command38("withdraw").description("Withdraw USDC to the registered withdrawal address").argument("<amount>", "Amount in USDC (e.g. 5 for 5 USDC)").action(async (amount) => {
|
|
907
1463
|
const parsed = parseFloat(amount);
|
|
908
1464
|
if (isNaN(parsed) || parsed <= 0) {
|
|
909
1465
|
printError("Invalid amount: must be a positive number (e.g. 5 for 5 USDC)");
|
|
@@ -953,9 +1509,9 @@ var withdrawCommand = new Command28("withdraw").description("Withdraw USDC to th
|
|
|
953
1509
|
});
|
|
954
1510
|
|
|
955
1511
|
// src/commands/encrypt.ts
|
|
956
|
-
import { Command as
|
|
1512
|
+
import { Command as Command39 } from "commander";
|
|
957
1513
|
import { promises as fs3 } from "fs";
|
|
958
|
-
var encryptCommand = new
|
|
1514
|
+
var encryptCommand = new Command39("encrypt").description("Encrypt a file with ECIES using wallet keys").argument("<file>", "Path to the file to encrypt").option("--recipient <address>", "Recipient wallet address (default: self)").option("--output <path>", "Output path (default: <file>.enc)").action(async (file, opts) => {
|
|
959
1515
|
let plaintext;
|
|
960
1516
|
try {
|
|
961
1517
|
plaintext = await fs3.readFile(file);
|
|
@@ -1004,9 +1560,9 @@ var encryptCommand = new Command29("encrypt").description("Encrypt a file with E
|
|
|
1004
1560
|
});
|
|
1005
1561
|
|
|
1006
1562
|
// src/commands/decrypt.ts
|
|
1007
|
-
import { Command as
|
|
1563
|
+
import { Command as Command40 } from "commander";
|
|
1008
1564
|
import { promises as fs4 } from "fs";
|
|
1009
|
-
var decryptCommand = new
|
|
1565
|
+
var decryptCommand = new Command40("decrypt").description("Decrypt a file using your wallet key").argument("<file>", "Path to the encrypted file").option("--output <path>", "Output path (default: strips .enc, otherwise appends .dec)").action(async (file, opts) => {
|
|
1010
1566
|
let ciphertext;
|
|
1011
1567
|
try {
|
|
1012
1568
|
ciphertext = await fs4.readFile(file);
|
|
@@ -1044,7 +1600,7 @@ var decryptCommand = new Command30("decrypt").description("Decrypt a file using
|
|
|
1044
1600
|
});
|
|
1045
1601
|
|
|
1046
1602
|
// src/commands/xmtp.ts
|
|
1047
|
-
import { Command as
|
|
1603
|
+
import { Command as Command41 } from "commander";
|
|
1048
1604
|
|
|
1049
1605
|
// src/lib/xmtp-client.ts
|
|
1050
1606
|
import os2 from "os";
|
|
@@ -5103,11 +5659,14 @@ var TaskStatus = external_exports.enum([
|
|
|
5103
5659
|
"claimed",
|
|
5104
5660
|
"worker_selected",
|
|
5105
5661
|
"pending_approval",
|
|
5106
|
-
"
|
|
5662
|
+
"review",
|
|
5663
|
+
"appealing",
|
|
5664
|
+
"disputed",
|
|
5107
5665
|
"completed",
|
|
5108
5666
|
"expired",
|
|
5109
|
-
"
|
|
5667
|
+
"cancelled"
|
|
5110
5668
|
]);
|
|
5669
|
+
var AuctionType = external_exports.enum(["dutch", "english", "reverse_dutch", "reverse_english"]);
|
|
5111
5670
|
var TaskCreateSchema = external_exports.object({
|
|
5112
5671
|
description: external_exports.string().min(1, "Description is required").max(2e3, "Description is too long"),
|
|
5113
5672
|
reward: external_exports.string().min(1, "Reward is required"),
|
|
@@ -5120,7 +5679,17 @@ var TaskCreateSchema = external_exports.object({
|
|
|
5120
5679
|
bidDeadline: external_exports.number().positive().optional(),
|
|
5121
5680
|
maxPrice: external_exports.string().optional(),
|
|
5122
5681
|
metricDescription: external_exports.string().max(500).optional(),
|
|
5123
|
-
metricTarget: external_exports.string().max(200).optional()
|
|
5682
|
+
metricTarget: external_exports.string().max(200).optional(),
|
|
5683
|
+
auctionType: AuctionType.optional(),
|
|
5684
|
+
auctionStartPrice: external_exports.string().optional(),
|
|
5685
|
+
auctionFloorPrice: external_exports.string().optional(),
|
|
5686
|
+
hookContract: external_exports.string().optional(),
|
|
5687
|
+
hookData: external_exports.string().regex(/^0x(?:[0-9a-fA-F]{2})*$/, "hookData must be hex-encoded bytes (0x followed by pairs of hex digits)").optional(),
|
|
5688
|
+
evaluator: external_exports.string().optional(),
|
|
5689
|
+
evaluatorFeeBps: external_exports.number().min(0).max(1e4).optional(),
|
|
5690
|
+
evaluationWindowHours: external_exports.number().positive().optional(),
|
|
5691
|
+
appealWindowHours: external_exports.number().positive().optional(),
|
|
5692
|
+
disputeResolver: external_exports.string().optional()
|
|
5124
5693
|
});
|
|
5125
5694
|
var TaskResponseSchema = external_exports.object({
|
|
5126
5695
|
id: external_exports.string(),
|
|
@@ -5149,23 +5718,38 @@ var TaskResponseSchema = external_exports.object({
|
|
|
5149
5718
|
submissionCount: external_exports.number().optional().default(0),
|
|
5150
5719
|
pitchCount: external_exports.number().optional().default(0),
|
|
5151
5720
|
requesterAgentId: external_exports.string().nullable().optional(),
|
|
5152
|
-
|
|
5721
|
+
requesterActorType: external_exports.enum(["agent", "human"]).optional(),
|
|
5722
|
+
workerAgentId: external_exports.string().nullable().optional(),
|
|
5723
|
+
workerActorType: external_exports.enum(["agent", "human"]).optional(),
|
|
5724
|
+
auctionType: AuctionType.nullable().optional(),
|
|
5725
|
+
auctionStartPrice: external_exports.string().nullable().optional(),
|
|
5726
|
+
auctionFloorPrice: external_exports.string().nullable().optional(),
|
|
5727
|
+
currentAuctionPrice: external_exports.string().nullable().optional(),
|
|
5728
|
+
auctionBidCount: external_exports.number().nullable().optional(),
|
|
5729
|
+
auctionPriceReachesFloorAt: external_exports.string().nullable().optional(),
|
|
5730
|
+
auctionPriceReachesMaxAt: external_exports.string().nullable().optional(),
|
|
5731
|
+
currentLowestBid: external_exports.string().nullable().optional(),
|
|
5732
|
+
hookContract: external_exports.string().nullable().optional(),
|
|
5733
|
+
evaluator: external_exports.string().nullable().optional(),
|
|
5734
|
+
evaluatorStake: external_exports.string().nullable().optional(),
|
|
5735
|
+
evaluatorFeeBps: external_exports.number().nullable().optional(),
|
|
5736
|
+
evaluationWindow: external_exports.number().nullable().optional(),
|
|
5737
|
+
appealWindow: external_exports.number().nullable().optional(),
|
|
5738
|
+
disputeResolver: external_exports.string().nullable().optional(),
|
|
5739
|
+
appealDeadline: external_exports.string().nullable().optional(),
|
|
5740
|
+
evaluatorDeadline: external_exports.string().nullable().optional(),
|
|
5741
|
+
verdictType: external_exports.enum(["APPROVE", "REJECT", "PARTIAL"]).nullable().optional(),
|
|
5742
|
+
verdictScore: external_exports.number().nullable().optional(),
|
|
5743
|
+
verdictConfidence: external_exports.number().nullable().optional(),
|
|
5744
|
+
verdictEvidenceHash: external_exports.string().nullable().optional()
|
|
5153
5745
|
});
|
|
5154
5746
|
var TaskListInputSchema = external_exports.object({
|
|
5155
5747
|
limit: external_exports.number().min(1).max(100).optional().default(20),
|
|
5156
5748
|
cursor: external_exports.string().optional(),
|
|
5157
|
-
status: external_exports.
|
|
5158
|
-
"ALL",
|
|
5159
|
-
"open",
|
|
5160
|
-
"claimed",
|
|
5161
|
-
"worker_selected",
|
|
5162
|
-
"pending_approval",
|
|
5163
|
-
"accepted",
|
|
5164
|
-
"completed",
|
|
5165
|
-
"expired",
|
|
5166
|
-
"disputed"
|
|
5167
|
-
]).optional().default("ALL"),
|
|
5749
|
+
status: external_exports.union([TaskStatus, external_exports.literal("ALL")]).optional().default("ALL"),
|
|
5168
5750
|
mode: external_exports.enum(["ALL", "bounty", "claim", "pitch", "benchmark", "auction"]).optional().default("ALL"),
|
|
5751
|
+
auctionType: AuctionType.optional(),
|
|
5752
|
+
requesterActorType: external_exports.enum(["agent", "human"]).optional(),
|
|
5169
5753
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
5170
5754
|
minReward: external_exports.string().optional(),
|
|
5171
5755
|
maxReward: external_exports.string().optional(),
|
|
@@ -5183,20 +5767,88 @@ var TaskInboxResponseSchema = external_exports.object({
|
|
|
5183
5767
|
asRequester: external_exports.array(TaskResponseSchema),
|
|
5184
5768
|
asWorker: external_exports.array(TaskResponseSchema)
|
|
5185
5769
|
});
|
|
5770
|
+
var PendingActionName = external_exports.enum([
|
|
5771
|
+
"accept",
|
|
5772
|
+
"appeal",
|
|
5773
|
+
"auction_accept",
|
|
5774
|
+
"bid",
|
|
5775
|
+
"cancel",
|
|
5776
|
+
"claim",
|
|
5777
|
+
"evaluate",
|
|
5778
|
+
"evaluator_timeout",
|
|
5779
|
+
"finalize_verdict",
|
|
5780
|
+
"forfeit",
|
|
5781
|
+
"pitch",
|
|
5782
|
+
"rate",
|
|
5783
|
+
"resolve_dispute",
|
|
5784
|
+
"select_winner",
|
|
5785
|
+
"select_worker",
|
|
5786
|
+
"submit",
|
|
5787
|
+
"submit_proof",
|
|
5788
|
+
"update"
|
|
5789
|
+
]);
|
|
5186
5790
|
var PendingActionSchema = external_exports.object({
|
|
5187
|
-
role: external_exports.enum(["requester", "worker"]),
|
|
5188
|
-
action:
|
|
5791
|
+
role: external_exports.enum(["requester", "worker", "evaluator", "dispute_resolver", "anyone"]),
|
|
5792
|
+
action: PendingActionName,
|
|
5189
5793
|
command: external_exports.string()
|
|
5190
5794
|
});
|
|
5191
5795
|
var TaskDetailResponseSchema = TaskResponseSchema.extend({
|
|
5192
5796
|
pendingActions: PendingActionSchema.array()
|
|
5193
5797
|
});
|
|
5798
|
+
var CancelTaskInputSchema = external_exports.object({
|
|
5799
|
+
taskId: external_exports.string()
|
|
5800
|
+
});
|
|
5801
|
+
var UpdateTaskInputSchema = external_exports.object({
|
|
5802
|
+
taskId: external_exports.string(),
|
|
5803
|
+
reward: external_exports.string().optional(),
|
|
5804
|
+
expiryTime: external_exports.number().optional(),
|
|
5805
|
+
bidDeadline: external_exports.number().optional(),
|
|
5806
|
+
pitchDeadline: external_exports.number().optional(),
|
|
5807
|
+
auctionFloorPrice: external_exports.string().optional(),
|
|
5808
|
+
auctionStartPrice: external_exports.string().optional(),
|
|
5809
|
+
description: external_exports.string().optional(),
|
|
5810
|
+
tags: external_exports.array(external_exports.string()).optional(),
|
|
5811
|
+
metricDescription: external_exports.string().optional()
|
|
5812
|
+
});
|
|
5194
5813
|
|
|
5195
5814
|
// ../../packages/shared/dist/schemas/submission.schemas.js
|
|
5815
|
+
var ArtifactRole = external_exports.enum(["preview", "source", "final", "attachment"]);
|
|
5816
|
+
var ArtifactMediaKind = external_exports.enum([
|
|
5817
|
+
"image",
|
|
5818
|
+
"video",
|
|
5819
|
+
"audio",
|
|
5820
|
+
"pdf",
|
|
5821
|
+
"text",
|
|
5822
|
+
"archive",
|
|
5823
|
+
"unknown"
|
|
5824
|
+
]);
|
|
5825
|
+
var ArtifactCreateSchema = external_exports.object({
|
|
5826
|
+
fileName: external_exports.string().min(1, "File name is required").max(255, "File name is too long"),
|
|
5827
|
+
mimeType: external_exports.string().min(1, "MIME type is required").max(120, "MIME type is too long"),
|
|
5828
|
+
role: ArtifactRole.optional().default("attachment"),
|
|
5829
|
+
file: external_exports.string().min(1, "File is required")
|
|
5830
|
+
});
|
|
5831
|
+
var ArtifactResponseSchema = external_exports.object({
|
|
5832
|
+
id: external_exports.string(),
|
|
5833
|
+
taskId: external_exports.string(),
|
|
5834
|
+
submissionId: external_exports.string(),
|
|
5835
|
+
workerAddress: external_exports.string(),
|
|
5836
|
+
workerAgentId: external_exports.string().nullable(),
|
|
5837
|
+
role: ArtifactRole,
|
|
5838
|
+
fileName: external_exports.string(),
|
|
5839
|
+
mimeType: external_exports.string(),
|
|
5840
|
+
mediaKind: ArtifactMediaKind,
|
|
5841
|
+
storageUri: external_exports.string(),
|
|
5842
|
+
sizeBytes: external_exports.number(),
|
|
5843
|
+
sha256Hash: external_exports.string(),
|
|
5844
|
+
keccak256Hash: external_exports.string(),
|
|
5845
|
+
displayOrder: external_exports.number(),
|
|
5846
|
+
textPreview: external_exports.string().optional()
|
|
5847
|
+
});
|
|
5196
5848
|
var SubmissionCreateSchema = external_exports.object({
|
|
5197
5849
|
taskId: external_exports.string(),
|
|
5198
5850
|
workerAddress: external_exports.string(),
|
|
5199
|
-
|
|
5851
|
+
artifacts: external_exports.array(ArtifactCreateSchema).min(1).max(20),
|
|
5200
5852
|
signature: external_exports.string()
|
|
5201
5853
|
});
|
|
5202
5854
|
var SubmissionResponseSchema = external_exports.object({
|
|
@@ -5207,6 +5859,9 @@ var SubmissionResponseSchema = external_exports.object({
|
|
|
5207
5859
|
signature: external_exports.string(),
|
|
5208
5860
|
submittedAt: external_exports.string(),
|
|
5209
5861
|
workerAgentId: external_exports.string().nullable().optional(),
|
|
5862
|
+
deliverableHash: external_exports.string().nullable().optional(),
|
|
5863
|
+
submitTxHash: external_exports.string().nullable().optional(),
|
|
5864
|
+
artifacts: external_exports.array(ArtifactResponseSchema).optional().default([]),
|
|
5210
5865
|
workerStats: external_exports.object({
|
|
5211
5866
|
completedTasks: external_exports.number(),
|
|
5212
5867
|
ratedTasks: external_exports.number(),
|
|
@@ -5215,7 +5870,8 @@ var SubmissionResponseSchema = external_exports.object({
|
|
|
5215
5870
|
}).nullable().optional()
|
|
5216
5871
|
});
|
|
5217
5872
|
var DownloadRequestSchema = external_exports.object({
|
|
5218
|
-
acceptanceTxHash: external_exports.string()
|
|
5873
|
+
acceptanceTxHash: external_exports.string(),
|
|
5874
|
+
artifactId: external_exports.string().optional()
|
|
5219
5875
|
});
|
|
5220
5876
|
var DownloadResponseSchema = external_exports.object({
|
|
5221
5877
|
fileUrl: external_exports.string(),
|
|
@@ -5224,21 +5880,31 @@ var DownloadResponseSchema = external_exports.object({
|
|
|
5224
5880
|
});
|
|
5225
5881
|
|
|
5226
5882
|
// ../../packages/shared/dist/schemas/agent.schemas.js
|
|
5883
|
+
var ActorType = external_exports.enum(["agent", "human"]);
|
|
5884
|
+
var RegistrationSource = external_exports.enum(["cli", "web"]);
|
|
5227
5885
|
var AgentStatsSchema = external_exports.object({
|
|
5228
5886
|
address: external_exports.string(),
|
|
5229
5887
|
agentId: external_exports.string().nullable().optional(),
|
|
5888
|
+
actorType: ActorType.optional(),
|
|
5230
5889
|
completedTasks: external_exports.number(),
|
|
5231
5890
|
ratedTasks: external_exports.number(),
|
|
5232
5891
|
totalStars: external_exports.number(),
|
|
5233
5892
|
averageRating: external_exports.number(),
|
|
5234
5893
|
totalEarnings: external_exports.string(),
|
|
5235
5894
|
skills: external_exports.array(external_exports.string()).optional(),
|
|
5895
|
+
emailAddress: external_exports.string().nullable().optional(),
|
|
5896
|
+
credibility: external_exports.number().int().min(0).max(1e3).optional(),
|
|
5236
5897
|
recentRatings: external_exports.array(external_exports.object({
|
|
5237
5898
|
taskId: external_exports.string(),
|
|
5238
5899
|
rating: external_exports.number(),
|
|
5239
|
-
createdAt: external_exports.string()
|
|
5900
|
+
createdAt: external_exports.string(),
|
|
5901
|
+
taskTitle: external_exports.string().nullable().optional(),
|
|
5902
|
+
feedbackText: external_exports.string().nullable().optional()
|
|
5240
5903
|
})).optional()
|
|
5241
5904
|
});
|
|
5905
|
+
var AgentRegistrationInputSchema = external_exports.object({
|
|
5906
|
+
source: RegistrationSource.optional().default("cli")
|
|
5907
|
+
});
|
|
5242
5908
|
var LeaderboardInputSchema = external_exports.object({
|
|
5243
5909
|
limit: external_exports.number().optional().default(20),
|
|
5244
5910
|
offset: external_exports.number().optional().default(0),
|
|
@@ -5246,16 +5912,20 @@ var LeaderboardInputSchema = external_exports.object({
|
|
|
5246
5912
|
skill: external_exports.string().optional(),
|
|
5247
5913
|
search: external_exports.string().optional(),
|
|
5248
5914
|
minRating: external_exports.number().min(0).max(5).optional(),
|
|
5249
|
-
minTasks: external_exports.number().int().min(0).optional()
|
|
5915
|
+
minTasks: external_exports.number().int().min(0).optional(),
|
|
5916
|
+
actorType: ActorType.optional()
|
|
5250
5917
|
});
|
|
5251
5918
|
var LeaderboardEntrySchema = external_exports.object({
|
|
5252
5919
|
rank: external_exports.number(),
|
|
5253
5920
|
address: external_exports.string(),
|
|
5254
5921
|
agentId: external_exports.string().nullable(),
|
|
5922
|
+
actorType: ActorType.optional(),
|
|
5255
5923
|
completedTasks: external_exports.number(),
|
|
5256
5924
|
averageRating: external_exports.number(),
|
|
5257
5925
|
totalEarnings: external_exports.string(),
|
|
5258
|
-
skills: external_exports.array(external_exports.string())
|
|
5926
|
+
skills: external_exports.array(external_exports.string()),
|
|
5927
|
+
emailAddress: external_exports.string().nullable().optional(),
|
|
5928
|
+
credibility: external_exports.number().int().min(0).max(1e3).optional()
|
|
5259
5929
|
});
|
|
5260
5930
|
var LeaderboardResponseSchema = external_exports.array(LeaderboardEntrySchema);
|
|
5261
5931
|
|
|
@@ -5264,7 +5934,8 @@ var RatingInputSchema = external_exports.object({
|
|
|
5264
5934
|
taskId: external_exports.string(),
|
|
5265
5935
|
worker: external_exports.string(),
|
|
5266
5936
|
rating: external_exports.number().int().min(0).max(100),
|
|
5267
|
-
feedbackText: external_exports.string().max(500).optional()
|
|
5937
|
+
feedbackText: external_exports.string().max(500).optional(),
|
|
5938
|
+
raterAgentId: external_exports.number().int().nonnegative().optional()
|
|
5268
5939
|
});
|
|
5269
5940
|
var FeedbackSchema = external_exports.object({
|
|
5270
5941
|
id: external_exports.string(),
|
|
@@ -5334,7 +6005,16 @@ var ClaimResponseSchema = external_exports.object({
|
|
|
5334
6005
|
});
|
|
5335
6006
|
|
|
5336
6007
|
// ../../packages/shared/dist/schemas/proof.schemas.js
|
|
5337
|
-
var ProofType = external_exports.enum([
|
|
6008
|
+
var ProofType = external_exports.enum([
|
|
6009
|
+
"url",
|
|
6010
|
+
"screenshot",
|
|
6011
|
+
"api_data",
|
|
6012
|
+
"manual",
|
|
6013
|
+
"custom",
|
|
6014
|
+
"eval",
|
|
6015
|
+
"tlsn",
|
|
6016
|
+
"zk"
|
|
6017
|
+
]);
|
|
5338
6018
|
var ProofStatus = external_exports.enum(["pending", "verified", "rejected"]);
|
|
5339
6019
|
var ProofSubmitSchema = external_exports.object({
|
|
5340
6020
|
taskId: external_exports.string().min(1, "Task ID is required"),
|
|
@@ -5361,13 +6041,18 @@ var BidCreateSchema = external_exports.object({
|
|
|
5361
6041
|
taskId: external_exports.string().min(1, "Task ID is required"),
|
|
5362
6042
|
price: external_exports.string().min(1, "Price is required")
|
|
5363
6043
|
});
|
|
6044
|
+
var AuctionAcceptSchema = external_exports.object({
|
|
6045
|
+
taskId: external_exports.string().min(1, "Task ID is required"),
|
|
6046
|
+
minPrice: external_exports.string().optional()
|
|
6047
|
+
});
|
|
5364
6048
|
var BidResponseSchema = external_exports.object({
|
|
5365
6049
|
id: external_exports.string(),
|
|
5366
6050
|
taskId: external_exports.string(),
|
|
5367
|
-
workerAddress: external_exports.string(),
|
|
5368
|
-
price: external_exports.string(),
|
|
6051
|
+
workerAddress: external_exports.string().nullable(),
|
|
6052
|
+
price: external_exports.string().nullable(),
|
|
5369
6053
|
createdAt: external_exports.string(),
|
|
5370
|
-
workerAgentId: external_exports.string().nullable().optional()
|
|
6054
|
+
workerAgentId: external_exports.string().nullable().optional(),
|
|
6055
|
+
isMyBid: external_exports.boolean().optional()
|
|
5371
6056
|
});
|
|
5372
6057
|
|
|
5373
6058
|
// ../../packages/shared/dist/schemas/wallet.schemas.js
|
|
@@ -5494,6 +6179,42 @@ var XmtpResolvePeerOutputSchema = external_exports.object({
|
|
|
5494
6179
|
inboxId: external_exports.string().nullable()
|
|
5495
6180
|
});
|
|
5496
6181
|
|
|
6182
|
+
// ../../packages/shared/dist/schemas/email.schemas.js
|
|
6183
|
+
var EmailSchema = external_exports.object({
|
|
6184
|
+
id: external_exports.string(),
|
|
6185
|
+
fromAddress: external_exports.string(),
|
|
6186
|
+
toAddress: external_exports.string(),
|
|
6187
|
+
subject: external_exports.string().nullable(),
|
|
6188
|
+
bodyText: external_exports.string().nullable(),
|
|
6189
|
+
bodyHtml: external_exports.string().nullable(),
|
|
6190
|
+
isRead: external_exports.boolean(),
|
|
6191
|
+
receivedAt: external_exports.string()
|
|
6192
|
+
});
|
|
6193
|
+
var SendEmailInputSchema = external_exports.object({
|
|
6194
|
+
to: external_exports.string().email(),
|
|
6195
|
+
subject: external_exports.string().min(1),
|
|
6196
|
+
bodyText: external_exports.string().min(1)
|
|
6197
|
+
});
|
|
6198
|
+
var EmailInboundHeadersSchema = external_exports.object({
|
|
6199
|
+
"x-webhook-secret": external_exports.string(),
|
|
6200
|
+
"x-email-from": external_exports.string(),
|
|
6201
|
+
"x-email-to": external_exports.string().email()
|
|
6202
|
+
});
|
|
6203
|
+
var BroadcastInputSchema = external_exports.object({
|
|
6204
|
+
subject: external_exports.string().min(1).max(200),
|
|
6205
|
+
body: external_exports.string().min(1).max(5e4),
|
|
6206
|
+
filters: external_exports.object({
|
|
6207
|
+
skills: external_exports.array(external_exports.string()).max(20).optional(),
|
|
6208
|
+
minTasks: external_exports.number().int().min(0).optional(),
|
|
6209
|
+
actorType: external_exports.enum(["agent", "human", "all"]).optional()
|
|
6210
|
+
}).optional()
|
|
6211
|
+
});
|
|
6212
|
+
var BroadcastResultSchema = external_exports.object({
|
|
6213
|
+
sent: external_exports.number(),
|
|
6214
|
+
failed: external_exports.number(),
|
|
6215
|
+
total: external_exports.number()
|
|
6216
|
+
});
|
|
6217
|
+
|
|
5497
6218
|
// ../../packages/shared/dist/lib/agentName.js
|
|
5498
6219
|
var MODIFIERS = [
|
|
5499
6220
|
"Neon",
|
|
@@ -6517,7 +7238,7 @@ function getDefaultQueryTimeoutMs() {
|
|
|
6517
7238
|
}
|
|
6518
7239
|
return Math.floor(parsed);
|
|
6519
7240
|
}
|
|
6520
|
-
var xmtpCommand = new
|
|
7241
|
+
var xmtpCommand = new Command41("xmtp").description("Manage XMTP messaging for this agent");
|
|
6521
7242
|
xmtpCommand.command("init").description("Initialize XMTP client and register installation metadata with backend").action(async () => {
|
|
6522
7243
|
const keystore = await loadKeystore();
|
|
6523
7244
|
const client = await createXmtpClient({
|
|
@@ -6745,7 +7466,7 @@ xmtpCommand.command("purge").description("Revoke stale XMTP installations that h
|
|
|
6745
7466
|
});
|
|
6746
7467
|
|
|
6747
7468
|
// src/commands/daemon.ts
|
|
6748
|
-
import { Command as
|
|
7469
|
+
import { Command as Command42 } from "commander";
|
|
6749
7470
|
function diffTaskStatuses(prev, next) {
|
|
6750
7471
|
const changes = [];
|
|
6751
7472
|
for (const [taskId, newStatus] of next) {
|
|
@@ -6773,11 +7494,17 @@ function sleepOrAbort(ms, signal) {
|
|
|
6773
7494
|
});
|
|
6774
7495
|
}
|
|
6775
7496
|
var MAX_SEEN_TASK_IDS = 2e3;
|
|
6776
|
-
var daemonCommand = new
|
|
7497
|
+
var daemonCommand = new Command42("daemon").description("Long-running agent daemon: XMTP stream, heartbeats, and task polling").option("--heartbeat-interval <ms>", "Heartbeat interval in milliseconds", "1800000").option("--inbox-interval <ms>", "Inbox poll interval in milliseconds", "15000").option("--task-interval <ms>", "New task poll interval in milliseconds", "60000").option(
|
|
7498
|
+
"--auction-poll-interval <ms>",
|
|
7499
|
+
"Poll interval for clock-based auction tasks (dutch/reverse_dutch) in milliseconds",
|
|
7500
|
+
"15000"
|
|
7501
|
+
).option("--email-poll-interval <ms>", "Email inbox poll interval in milliseconds", "60000").option("--task-filters <json>", "JSON filter object for new-task discovery").option("--no-xmtp", "Disable XMTP stream and heartbeat").action(
|
|
6777
7502
|
async (opts) => {
|
|
6778
7503
|
const heartbeatIntervalMs = Number(opts.heartbeatInterval);
|
|
6779
7504
|
const inboxIntervalMs = Number(opts.inboxInterval);
|
|
6780
7505
|
const taskIntervalMs = Number(opts.taskInterval);
|
|
7506
|
+
const auctionPollIntervalMs = Number(opts.auctionPollInterval);
|
|
7507
|
+
const emailPollIntervalMs = Number(opts.emailPollInterval);
|
|
6781
7508
|
if (!Number.isFinite(heartbeatIntervalMs) || heartbeatIntervalMs <= 0) {
|
|
6782
7509
|
throw new Error("--heartbeat-interval must be a positive number");
|
|
6783
7510
|
}
|
|
@@ -6787,6 +7514,12 @@ var daemonCommand = new Command32("daemon").description("Long-running agent daem
|
|
|
6787
7514
|
if (!Number.isFinite(taskIntervalMs) || taskIntervalMs <= 0) {
|
|
6788
7515
|
throw new Error("--task-interval must be a positive number");
|
|
6789
7516
|
}
|
|
7517
|
+
if (!Number.isFinite(auctionPollIntervalMs) || auctionPollIntervalMs <= 0) {
|
|
7518
|
+
throw new Error("--auction-poll-interval must be a positive number");
|
|
7519
|
+
}
|
|
7520
|
+
if (!Number.isFinite(emailPollIntervalMs) || emailPollIntervalMs <= 0) {
|
|
7521
|
+
throw new Error("--email-poll-interval must be a positive number");
|
|
7522
|
+
}
|
|
6790
7523
|
let taskFilters = {};
|
|
6791
7524
|
if (opts.taskFilters) {
|
|
6792
7525
|
try {
|
|
@@ -6979,7 +7712,99 @@ var daemonCommand = new Command32("daemon").description("Long-running agent daem
|
|
|
6979
7712
|
}
|
|
6980
7713
|
}
|
|
6981
7714
|
};
|
|
6982
|
-
|
|
7715
|
+
const auctionPollLoop = async () => {
|
|
7716
|
+
while (!stopped) {
|
|
7717
|
+
await sleepOrAbort(auctionPollIntervalMs, abortController.signal);
|
|
7718
|
+
if (stopped) break;
|
|
7719
|
+
try {
|
|
7720
|
+
let cursor;
|
|
7721
|
+
let hasMore = true;
|
|
7722
|
+
while (hasMore) {
|
|
7723
|
+
const params = new URLSearchParams({
|
|
7724
|
+
mode: "auction",
|
|
7725
|
+
status: "open",
|
|
7726
|
+
limit: "50"
|
|
7727
|
+
});
|
|
7728
|
+
if (cursor) params.set("cursor", cursor);
|
|
7729
|
+
const result = await apiGet(`/api/tasks?${params.toString()}`);
|
|
7730
|
+
for (const task of result.tasks) {
|
|
7731
|
+
if (task.auctionType === "dutch" || task.auctionType === "reverse_dutch") {
|
|
7732
|
+
printResult({
|
|
7733
|
+
event: "task.auction_clock",
|
|
7734
|
+
taskId: task.id,
|
|
7735
|
+
auctionType: task.auctionType,
|
|
7736
|
+
currentAuctionPrice: task.currentAuctionPrice ?? null,
|
|
7737
|
+
bidDeadline: task.bidDeadline ?? null
|
|
7738
|
+
});
|
|
7739
|
+
}
|
|
7740
|
+
}
|
|
7741
|
+
cursor = result.nextCursor ?? void 0;
|
|
7742
|
+
hasMore = result.hasMore && cursor !== void 0;
|
|
7743
|
+
}
|
|
7744
|
+
} catch (err) {
|
|
7745
|
+
process.stderr.write(
|
|
7746
|
+
`Auction poll failed: ${err instanceof Error ? err.message : String(err)}
|
|
7747
|
+
`
|
|
7748
|
+
);
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
};
|
|
7752
|
+
const emailPollLoop = async () => {
|
|
7753
|
+
const PAGE_SIZE = 50;
|
|
7754
|
+
while (!stopped) {
|
|
7755
|
+
await sleepOrAbort(emailPollIntervalMs, abortController.signal);
|
|
7756
|
+
if (stopped) break;
|
|
7757
|
+
try {
|
|
7758
|
+
let hasMore = true;
|
|
7759
|
+
while (hasMore) {
|
|
7760
|
+
const params = new URLSearchParams({
|
|
7761
|
+
deviceId: keystore.deviceId,
|
|
7762
|
+
apiToken: keystore.apiToken,
|
|
7763
|
+
limit: String(PAGE_SIZE),
|
|
7764
|
+
unread: "true"
|
|
7765
|
+
});
|
|
7766
|
+
const result = await apiGet(
|
|
7767
|
+
`/api/emails/list?${params.toString()}`
|
|
7768
|
+
);
|
|
7769
|
+
for (const email of result.emails) {
|
|
7770
|
+
printResult({
|
|
7771
|
+
event: "email.new",
|
|
7772
|
+
id: email.id,
|
|
7773
|
+
fromAddress: email.fromAddress,
|
|
7774
|
+
subject: email.subject,
|
|
7775
|
+
bodyText: email.bodyText,
|
|
7776
|
+
receivedAt: email.receivedAt
|
|
7777
|
+
});
|
|
7778
|
+
try {
|
|
7779
|
+
await apiPost("/api/emails/mark-read", {
|
|
7780
|
+
deviceId: keystore.deviceId,
|
|
7781
|
+
apiToken: keystore.apiToken,
|
|
7782
|
+
id: email.id,
|
|
7783
|
+
read: true
|
|
7784
|
+
});
|
|
7785
|
+
} catch (markErr) {
|
|
7786
|
+
process.stderr.write(
|
|
7787
|
+
`Email mark-read failed for ${email.id}: ${markErr instanceof Error ? markErr.message : String(markErr)}
|
|
7788
|
+
`
|
|
7789
|
+
);
|
|
7790
|
+
}
|
|
7791
|
+
}
|
|
7792
|
+
hasMore = result.emails.length === PAGE_SIZE;
|
|
7793
|
+
}
|
|
7794
|
+
} catch (err) {
|
|
7795
|
+
process.stderr.write(
|
|
7796
|
+
`Email poll failed: ${err instanceof Error ? err.message : String(err)}
|
|
7797
|
+
`
|
|
7798
|
+
);
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
};
|
|
7802
|
+
await Promise.allSettled([
|
|
7803
|
+
inboxPollLoop(),
|
|
7804
|
+
newTaskPollLoop(),
|
|
7805
|
+
auctionPollLoop(),
|
|
7806
|
+
emailPollLoop()
|
|
7807
|
+
]);
|
|
6983
7808
|
};
|
|
6984
7809
|
await Promise.allSettled([xmtpLoop(), heartbeatLoop(), taskPollLoop()]);
|
|
6985
7810
|
} finally {
|
|
@@ -6989,10 +7814,144 @@ var daemonCommand = new Command32("daemon").description("Long-running agent daem
|
|
|
6989
7814
|
}
|
|
6990
7815
|
);
|
|
6991
7816
|
|
|
7817
|
+
// src/commands/email/index.ts
|
|
7818
|
+
import { Command as Command51 } from "commander";
|
|
7819
|
+
|
|
7820
|
+
// src/commands/email/register.ts
|
|
7821
|
+
import { Command as Command43 } from "commander";
|
|
7822
|
+
var registerCommand = new Command43("register").description("Register an email address for this agent").requiredOption("--username <name>", "Desired username (e.g. myagent)").action(async (opts) => {
|
|
7823
|
+
const check = await apiGet(
|
|
7824
|
+
`/api/emails/check-username?username=${encodeURIComponent(opts.username)}`
|
|
7825
|
+
);
|
|
7826
|
+
if (!check.available) {
|
|
7827
|
+
printError(`Username "${opts.username}" is not available.`);
|
|
7828
|
+
}
|
|
7829
|
+
const keystore = await loadKeystore();
|
|
7830
|
+
const result = await apiPost("/api/emails/register", {
|
|
7831
|
+
deviceId: keystore.deviceId,
|
|
7832
|
+
apiToken: keystore.apiToken,
|
|
7833
|
+
username: opts.username
|
|
7834
|
+
});
|
|
7835
|
+
printResult({ emailAddress: result.emailAddress });
|
|
7836
|
+
});
|
|
7837
|
+
|
|
7838
|
+
// src/commands/email/inbox.ts
|
|
7839
|
+
import { Command as Command44 } from "commander";
|
|
7840
|
+
var inboxCommand2 = new Command44("inbox").description("List emails in your inbox").option("--limit <n>", "Number of emails to return", "20").option("--unread", "Show only unread emails").action(async (opts) => {
|
|
7841
|
+
const keystore = await loadKeystore();
|
|
7842
|
+
const params = new URLSearchParams({
|
|
7843
|
+
deviceId: keystore.deviceId,
|
|
7844
|
+
apiToken: keystore.apiToken,
|
|
7845
|
+
limit: opts.limit
|
|
7846
|
+
});
|
|
7847
|
+
if (opts.unread) {
|
|
7848
|
+
params.set("unread", "true");
|
|
7849
|
+
}
|
|
7850
|
+
const result = await apiGet(`/api/emails/list?${params.toString()}`);
|
|
7851
|
+
printResult({ emails: result.emails });
|
|
7852
|
+
});
|
|
7853
|
+
|
|
7854
|
+
// src/commands/email/read.ts
|
|
7855
|
+
import { Command as Command45 } from "commander";
|
|
7856
|
+
var readCommand = new Command45("read").description("Read an email by ID (marks it as read)").argument("<id>", "Email ID").action(async (id) => {
|
|
7857
|
+
const keystore = await loadKeystore();
|
|
7858
|
+
const params = new URLSearchParams({
|
|
7859
|
+
deviceId: keystore.deviceId,
|
|
7860
|
+
apiToken: keystore.apiToken,
|
|
7861
|
+
id
|
|
7862
|
+
});
|
|
7863
|
+
const result = await apiGet(`/api/emails/get?${params.toString()}`);
|
|
7864
|
+
printResult(result);
|
|
7865
|
+
});
|
|
7866
|
+
|
|
7867
|
+
// src/commands/email/send.ts
|
|
7868
|
+
import { Command as Command46 } from "commander";
|
|
7869
|
+
var sendCommand = new Command46("send").description("Send an email").requiredOption("--to <address>", "Recipient email address").requiredOption("--subject <subject>", "Email subject").requiredOption("--body <text>", "Email body text").action(async (opts) => {
|
|
7870
|
+
const keystore = await loadKeystore();
|
|
7871
|
+
const result = await apiPost("/api/emails/send", {
|
|
7872
|
+
deviceId: keystore.deviceId,
|
|
7873
|
+
apiToken: keystore.apiToken,
|
|
7874
|
+
to: opts.to,
|
|
7875
|
+
subject: opts.subject,
|
|
7876
|
+
bodyText: opts.body
|
|
7877
|
+
});
|
|
7878
|
+
printResult({ sent: result.sent });
|
|
7879
|
+
});
|
|
7880
|
+
|
|
7881
|
+
// src/commands/email/reply.ts
|
|
7882
|
+
import { Command as Command47 } from "commander";
|
|
7883
|
+
var replyCommand = new Command47("reply").description("Reply to an email").argument("<id>", "Email ID to reply to").requiredOption("--body <text>", "Reply body text").action(async (id, opts) => {
|
|
7884
|
+
const keystore = await loadKeystore();
|
|
7885
|
+
const params = new URLSearchParams({
|
|
7886
|
+
deviceId: keystore.deviceId,
|
|
7887
|
+
apiToken: keystore.apiToken,
|
|
7888
|
+
id
|
|
7889
|
+
});
|
|
7890
|
+
const original = await apiGet(`/api/emails/get?${params.toString()}`);
|
|
7891
|
+
const to = original.fromAddress;
|
|
7892
|
+
const rawSubject = original.subject ?? "";
|
|
7893
|
+
const subject = rawSubject.startsWith("Re: ") ? rawSubject : `Re: ${rawSubject}`;
|
|
7894
|
+
const result = await apiPost("/api/emails/send", {
|
|
7895
|
+
deviceId: keystore.deviceId,
|
|
7896
|
+
apiToken: keystore.apiToken,
|
|
7897
|
+
to,
|
|
7898
|
+
subject,
|
|
7899
|
+
bodyText: opts.body
|
|
7900
|
+
});
|
|
7901
|
+
printResult({ sent: result.sent });
|
|
7902
|
+
});
|
|
7903
|
+
|
|
7904
|
+
// src/commands/email/delete.ts
|
|
7905
|
+
import { Command as Command48 } from "commander";
|
|
7906
|
+
var deleteCommand = new Command48("delete").description("Delete an email by ID").argument("<id>", "Email ID").action(async (id) => {
|
|
7907
|
+
const keystore = await loadKeystore();
|
|
7908
|
+
const result = await apiPost("/api/emails/delete", {
|
|
7909
|
+
deviceId: keystore.deviceId,
|
|
7910
|
+
apiToken: keystore.apiToken,
|
|
7911
|
+
id
|
|
7912
|
+
});
|
|
7913
|
+
printResult({ deleted: result.deleted });
|
|
7914
|
+
});
|
|
7915
|
+
|
|
7916
|
+
// src/commands/email/address.ts
|
|
7917
|
+
import { Command as Command49 } from "commander";
|
|
7918
|
+
var addressCommand2 = new Command49("address").description("Show your registered email address").action(async () => {
|
|
7919
|
+
const keystore = await loadKeystore();
|
|
7920
|
+
const result = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
7921
|
+
printResult({ emailAddress: result.emailAddress ?? null });
|
|
7922
|
+
});
|
|
7923
|
+
|
|
7924
|
+
// src/commands/email/mark-read.ts
|
|
7925
|
+
import { Command as Command50 } from "commander";
|
|
7926
|
+
async function setReadStatus(id, read) {
|
|
7927
|
+
const keystore = await loadKeystore();
|
|
7928
|
+
const result = await apiPost("/api/emails/mark-read", {
|
|
7929
|
+
deviceId: keystore.deviceId,
|
|
7930
|
+
apiToken: keystore.apiToken,
|
|
7931
|
+
id,
|
|
7932
|
+
read
|
|
7933
|
+
});
|
|
7934
|
+
printResult({ id: result.id, isRead: result.isRead });
|
|
7935
|
+
}
|
|
7936
|
+
var markReadCommand = new Command50("mark-read").description("Mark an email as read or unread").argument("<id>", "Email ID").option("--unread", "Mark as unread instead of read").action(async (id, opts) => {
|
|
7937
|
+
await setReadStatus(id, !opts.unread);
|
|
7938
|
+
});
|
|
7939
|
+
|
|
7940
|
+
// src/commands/email/index.ts
|
|
7941
|
+
var emailCommand = new Command51("email").description("Email management commands");
|
|
7942
|
+
emailCommand.addCommand(registerCommand);
|
|
7943
|
+
emailCommand.addCommand(inboxCommand2);
|
|
7944
|
+
emailCommand.addCommand(readCommand);
|
|
7945
|
+
emailCommand.addCommand(sendCommand);
|
|
7946
|
+
emailCommand.addCommand(replyCommand);
|
|
7947
|
+
emailCommand.addCommand(deleteCommand);
|
|
7948
|
+
emailCommand.addCommand(addressCommand2);
|
|
7949
|
+
emailCommand.addCommand(markReadCommand);
|
|
7950
|
+
|
|
6992
7951
|
// src/index.ts
|
|
6993
7952
|
var require2 = createRequire(import.meta.url);
|
|
6994
7953
|
var { version } = require2("../package.json");
|
|
6995
|
-
var program = new
|
|
7954
|
+
var program = new Command52();
|
|
6996
7955
|
program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
|
|
6997
7956
|
program.addCommand(initCommand);
|
|
6998
7957
|
program.addCommand(walletCommand);
|
|
@@ -7008,6 +7967,7 @@ program.addCommand(encryptCommand);
|
|
|
7008
7967
|
program.addCommand(decryptCommand);
|
|
7009
7968
|
program.addCommand(xmtpCommand);
|
|
7010
7969
|
program.addCommand(daemonCommand);
|
|
7970
|
+
program.addCommand(emailCommand);
|
|
7011
7971
|
program.parseAsync(process.argv).catch((err) => {
|
|
7012
7972
|
process.stderr.write(JSON.stringify({ ok: false, error: err.message }) + "\n");
|
|
7013
7973
|
process.exit(1);
|