@tasknet-protocol/cli 0.2.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 ADDED
@@ -0,0 +1,1299 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+ import chalk4 from "chalk";
6
+
7
+ // src/config.ts
8
+ import Conf from "conf";
9
+ var defaults = {
10
+ apiUrl: "http://localhost:3000",
11
+ network: "testnet",
12
+ outputFormat: "table"
13
+ };
14
+ var config = new Conf({
15
+ projectName: "tasknet-cli",
16
+ projectVersion: "0.2.0",
17
+ defaults,
18
+ schema: {
19
+ apiUrl: { type: "string" },
20
+ apiKey: { type: "string" },
21
+ network: { type: "string", enum: ["mainnet", "testnet", "devnet", "localnet"] },
22
+ rpcUrl: { type: "string" },
23
+ packageId: { type: "string" },
24
+ walrusAggregator: { type: "string" },
25
+ walrusPublisher: { type: "string" },
26
+ agentId: { type: "string" },
27
+ agentName: { type: "string" },
28
+ outputFormat: { type: "string", enum: ["table", "json"] }
29
+ }
30
+ });
31
+ function getConfig() {
32
+ return {
33
+ apiUrl: config.get("apiUrl"),
34
+ apiKey: config.get("apiKey"),
35
+ network: config.get("network"),
36
+ rpcUrl: config.get("rpcUrl"),
37
+ packageId: config.get("packageId"),
38
+ walrusAggregator: config.get("walrusAggregator"),
39
+ walrusPublisher: config.get("walrusPublisher"),
40
+ agentId: config.get("agentId"),
41
+ agentName: config.get("agentName"),
42
+ outputFormat: config.get("outputFormat")
43
+ };
44
+ }
45
+ function setConfig(key, value) {
46
+ config.set(key, value);
47
+ }
48
+ function clearConfig() {
49
+ config.clear();
50
+ }
51
+ function getConfigPath() {
52
+ return config.path;
53
+ }
54
+
55
+ // src/utils.ts
56
+ import chalk from "chalk";
57
+ import ora from "ora";
58
+ var colors = {
59
+ primary: chalk.cyan,
60
+ success: chalk.green,
61
+ warning: chalk.yellow,
62
+ error: chalk.red,
63
+ muted: chalk.gray,
64
+ highlight: chalk.bold.white
65
+ };
66
+ function log(message) {
67
+ console.log(message);
68
+ }
69
+ function success(message) {
70
+ console.log(colors.success("\u2713"), message);
71
+ }
72
+ function error(message) {
73
+ console.error(colors.error("\u2717"), message);
74
+ }
75
+ function spinner(text) {
76
+ return ora({ text, color: "cyan" });
77
+ }
78
+ function formatAddress(address, length = 8) {
79
+ if (address.length <= length * 2 + 2) return address;
80
+ return `${address.slice(0, length + 2)}...${address.slice(-length)}`;
81
+ }
82
+ function formatUsdc(amount) {
83
+ const value = typeof amount === "string" ? BigInt(amount) : amount;
84
+ const usdc = Number(value) / 1e6;
85
+ return `${usdc.toFixed(2)} USDC`;
86
+ }
87
+ function formatTimestamp(timestamp) {
88
+ const ms = typeof timestamp === "bigint" ? Number(timestamp) : Number(timestamp);
89
+ return new Date(ms).toLocaleString();
90
+ }
91
+ function formatDuration(seconds) {
92
+ if (seconds < 60) return `${seconds}s`;
93
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
94
+ if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
95
+ return `${Math.floor(seconds / 86400)}d`;
96
+ }
97
+ function formatPercent(value) {
98
+ if (value === null || value === void 0) return "-";
99
+ return `${(value * 100).toFixed(1)}%`;
100
+ }
101
+ function table(headers, rows, options = {}) {
102
+ const maxWidth = options.maxWidth ?? 20;
103
+ const widths = headers.map(
104
+ (h, i) => Math.min(
105
+ maxWidth,
106
+ Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length))
107
+ )
108
+ );
109
+ const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(" ");
110
+ const separator = widths.map((w) => "-".repeat(w)).join(" ");
111
+ const rowLines = rows.map(
112
+ (row) => row.map((cell, i) => (cell ?? "").padEnd(widths[i])).join(" ")
113
+ );
114
+ return [
115
+ colors.muted(headerLine),
116
+ colors.muted(separator),
117
+ ...rowLines
118
+ ].join("\n");
119
+ }
120
+ function jsonOutput(data) {
121
+ console.log(JSON.stringify(data, null, 2));
122
+ }
123
+ function output(data, tableFormatter) {
124
+ const config2 = getConfig();
125
+ if (config2.outputFormat === "json") {
126
+ jsonOutput(data);
127
+ } else if (tableFormatter) {
128
+ log(tableFormatter());
129
+ } else {
130
+ jsonOutput(data);
131
+ }
132
+ }
133
+
134
+ // src/commands/config.ts
135
+ function registerConfigCommands(program2) {
136
+ const configCmd = program2.command("config").description("Manage CLI configuration");
137
+ configCmd.command("show").description("Show current configuration").option("--json", "Output as JSON").action((options) => {
138
+ const config2 = getConfig();
139
+ if (options.json) {
140
+ console.log(JSON.stringify(config2, null, 2));
141
+ return;
142
+ }
143
+ log(colors.primary("\nTaskNet CLI Configuration\n"));
144
+ log(colors.muted(`Config file: ${getConfigPath()}
145
+ `));
146
+ const rows = Object.entries(config2).map(([key, value]) => [
147
+ colors.highlight(key),
148
+ value !== void 0 ? String(value) : colors.muted("(not set)")
149
+ ]);
150
+ log(table(["Key", "Value"], rows));
151
+ log("");
152
+ });
153
+ configCmd.command("get <key>").description("Get a configuration value").action((key) => {
154
+ const config2 = getConfig();
155
+ const value = config2[key];
156
+ if (value === void 0) {
157
+ error(`Configuration key "${key}" is not set`);
158
+ process.exit(1);
159
+ }
160
+ log(String(value));
161
+ });
162
+ configCmd.command("set <key> <value>").description("Set a configuration value").action((key, value) => {
163
+ const validKeys = [
164
+ "apiUrl",
165
+ "apiKey",
166
+ "network",
167
+ "rpcUrl",
168
+ "packageId",
169
+ "walrusAggregator",
170
+ "walrusPublisher",
171
+ "agentId",
172
+ "agentName",
173
+ "outputFormat"
174
+ ];
175
+ if (!validKeys.includes(key)) {
176
+ error(`Invalid configuration key: ${key}`);
177
+ log(`
178
+ Valid keys: ${validKeys.join(", ")}`);
179
+ process.exit(1);
180
+ }
181
+ if (key === "network") {
182
+ const validNetworks = ["mainnet", "testnet", "devnet", "localnet"];
183
+ if (!validNetworks.includes(value)) {
184
+ error(`Invalid network: ${value}`);
185
+ log(`Valid networks: ${validNetworks.join(", ")}`);
186
+ process.exit(1);
187
+ }
188
+ }
189
+ if (key === "outputFormat") {
190
+ const validFormats = ["table", "json"];
191
+ if (!validFormats.includes(value)) {
192
+ error(`Invalid output format: ${value}`);
193
+ log(`Valid formats: ${validFormats.join(", ")}`);
194
+ process.exit(1);
195
+ }
196
+ }
197
+ setConfig(key, value);
198
+ success(`Set ${key} = ${value}`);
199
+ });
200
+ configCmd.command("unset <key>").description("Unset a configuration value").action((key) => {
201
+ setConfig(key, void 0);
202
+ success(`Unset ${key}`);
203
+ });
204
+ configCmd.command("reset").description("Reset all configuration to defaults").option("-y, --yes", "Skip confirmation").action(async (options) => {
205
+ if (!options.yes) {
206
+ const prompts = await import("prompts");
207
+ const { confirm } = await prompts.default({
208
+ type: "confirm",
209
+ name: "confirm",
210
+ message: "Reset all configuration to defaults?",
211
+ initial: false
212
+ });
213
+ if (!confirm) {
214
+ log("Cancelled");
215
+ return;
216
+ }
217
+ }
218
+ clearConfig();
219
+ success("Configuration reset to defaults");
220
+ });
221
+ configCmd.command("path").description("Show configuration file path").action(() => {
222
+ log(getConfigPath());
223
+ });
224
+ }
225
+
226
+ // src/client.ts
227
+ import { TaskNetClient } from "@tasknet-protocol/sdk";
228
+ var clientInstance = null;
229
+ function getClient() {
230
+ if (clientInstance) return clientInstance;
231
+ const config2 = getConfig();
232
+ clientInstance = new TaskNetClient({
233
+ apiUrl: config2.apiUrl,
234
+ apiKey: config2.apiKey,
235
+ network: config2.network,
236
+ rpcUrl: config2.rpcUrl,
237
+ packageId: config2.packageId,
238
+ walrusAggregator: config2.walrusAggregator,
239
+ walrusPublisher: config2.walrusPublisher,
240
+ agentId: config2.agentId
241
+ });
242
+ return clientInstance;
243
+ }
244
+
245
+ // src/commands/agent.ts
246
+ function registerAgentCommands(program2) {
247
+ const agentCmd = program2.command("agent").description("Manage agents");
248
+ agentCmd.command("list").description("List all agents").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Items per page", "20").action(async (options) => {
249
+ const spin = spinner("Fetching agents...").start();
250
+ try {
251
+ const client = getClient();
252
+ const result = await client.api.listAgents({
253
+ page: parseInt(options.page),
254
+ limit: parseInt(options.limit)
255
+ });
256
+ spin.stop();
257
+ output(result, () => {
258
+ const rows = result.data.map((agent) => [
259
+ formatAddress(agent.id),
260
+ formatAddress(agent.owner),
261
+ String(agent.skills_count),
262
+ String(agent.tasks_as_worker),
263
+ formatPercent(agent.stats?.completion_rate)
264
+ ]);
265
+ return `
266
+ ${colors.primary("Agents")} (${result.pagination.total} total)
267
+
268
+ ` + table(["ID", "Owner", "Skills", "Tasks Done", "Success"], rows) + `
269
+
270
+ Page ${result.pagination.page}/${result.pagination.pages}`;
271
+ });
272
+ } catch (err) {
273
+ spin.stop();
274
+ error(`Failed to list agents: ${err.message}`);
275
+ process.exit(1);
276
+ }
277
+ });
278
+ agentCmd.command("info [id]").description("Get agent details (uses configured agent if no ID)").action(async (id) => {
279
+ const agentId = id ?? getConfig().agentId;
280
+ if (!agentId) {
281
+ error("No agent ID provided. Set one with: tasknet config set agentId <id>");
282
+ process.exit(1);
283
+ }
284
+ const spin = spinner("Fetching agent...").start();
285
+ try {
286
+ const client = getClient();
287
+ const agent = await client.api.getAgent(agentId);
288
+ spin.stop();
289
+ output(agent, () => {
290
+ let output2 = `
291
+ ${colors.primary("Agent Details")}
292
+
293
+ `;
294
+ output2 += `${colors.muted("ID:")} ${agent.id}
295
+ `;
296
+ output2 += `${colors.muted("Owner:")} ${agent.owner}
297
+ `;
298
+ output2 += `${colors.muted("Created:")} ${formatTimestamp(agent.created_at)}
299
+ `;
300
+ output2 += `${colors.muted("Metadata:")} ${agent.metadata_uri ?? "(none)"}
301
+ `;
302
+ if (agent.skills.length > 0) {
303
+ output2 += `
304
+ ${colors.primary("Skills")} (${agent.skills.length})
305
+
306
+ `;
307
+ const skillRows = agent.skills.map((s) => [
308
+ s.name,
309
+ s.version,
310
+ formatUsdc(s.base_price_usdc)
311
+ ]);
312
+ output2 += table(["Name", "Version", "Price"], skillRows);
313
+ }
314
+ if (agent.badges.length > 0) {
315
+ output2 += `
316
+
317
+ ${colors.primary("Badges")} (${agent.badges.length})
318
+
319
+ `;
320
+ const badgeRows = agent.badges.map((b) => [
321
+ b.badge_type,
322
+ `Tier ${b.tier}`,
323
+ formatTimestamp(b.earned_at)
324
+ ]);
325
+ output2 += table(["Type", "Tier", "Earned"], badgeRows);
326
+ }
327
+ return output2;
328
+ });
329
+ } catch (err) {
330
+ spin.stop();
331
+ error(`Failed to get agent: ${err.message}`);
332
+ process.exit(1);
333
+ }
334
+ });
335
+ agentCmd.command("stats [id]").description("Get agent statistics").action(async (id) => {
336
+ const agentId = id ?? getConfig().agentId;
337
+ if (!agentId) {
338
+ error("No agent ID provided");
339
+ process.exit(1);
340
+ }
341
+ const spin = spinner("Fetching stats...").start();
342
+ try {
343
+ const client = getClient();
344
+ const stats = await client.api.getAgentStats(agentId);
345
+ spin.stop();
346
+ output(stats, () => {
347
+ let output2 = `
348
+ ${colors.primary("Agent Statistics")}
349
+
350
+ `;
351
+ output2 += `${colors.highlight("Worker Stats")}
352
+ `;
353
+ output2 += ` Tasks Completed: ${stats.workerTasksCompleted}
354
+ `;
355
+ output2 += ` Tasks Failed: ${stats.workerTasksFailed}
356
+ `;
357
+ output2 += ` Tasks Expired: ${stats.workerTasksExpired}
358
+ `;
359
+ output2 += ` Total Earned: ${formatUsdc(stats.workerTotalEarnedUsdc)}
360
+ `;
361
+ output2 += ` Completion Rate: ${formatPercent(stats.completionRate)}
362
+ `;
363
+ output2 += `
364
+ ${colors.highlight("Requester Stats")}
365
+ `;
366
+ output2 += ` Tasks Posted: ${stats.requesterTasksPosted}
367
+ `;
368
+ output2 += ` Tasks Settled: ${stats.requesterTasksSettled}
369
+ `;
370
+ output2 += ` Tasks Cancelled: ${stats.requesterTasksCancelled}
371
+ `;
372
+ output2 += ` Tasks Rejected: ${stats.requesterTasksRejected}
373
+ `;
374
+ output2 += ` Total Spent: ${formatUsdc(stats.requesterTotalSpentUsdc)}
375
+ `;
376
+ output2 += ` Rejection Rate: ${formatPercent(stats.rejectionRate)}
377
+ `;
378
+ output2 += `
379
+ ${colors.highlight("Metrics")}
380
+ `;
381
+ output2 += ` Unique Partners: ${stats.uniqueCounterparties}
382
+ `;
383
+ output2 += ` Flagged: ${stats.flaggedForAbuse ? colors.error("Yes") : colors.success("No")}
384
+ `;
385
+ return output2;
386
+ });
387
+ } catch (err) {
388
+ spin.stop();
389
+ error(`Failed to get stats: ${err.message}`);
390
+ process.exit(1);
391
+ }
392
+ });
393
+ agentCmd.command("use <id>").description("Set the current agent for commands").option("-n, --name <name>", "Agent name for display").action((id, options) => {
394
+ setConfig("agentId", id);
395
+ if (options.name) {
396
+ setConfig("agentName", options.name);
397
+ }
398
+ success(`Now using agent: ${formatAddress(id)}`);
399
+ });
400
+ agentCmd.command("current").description("Show current agent").action(() => {
401
+ const config2 = getConfig();
402
+ if (!config2.agentId) {
403
+ log("No agent configured. Use: tasknet agent use <id>");
404
+ return;
405
+ }
406
+ log(`
407
+ Current Agent:`);
408
+ log(` ID: ${config2.agentId}`);
409
+ if (config2.agentName) {
410
+ log(` Name: ${config2.agentName}`);
411
+ }
412
+ log("");
413
+ });
414
+ }
415
+
416
+ // src/commands/skill.ts
417
+ function registerSkillCommands(program2) {
418
+ const skillCmd = program2.command("skill").alias("skills").description("Manage skills");
419
+ skillCmd.command("list").description("List available skills").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Items per page", "20").option("-n, --name <name>", "Filter by name").option("-a, --agent <id>", "Filter by agent ID").option("-v, --verification <type>", "Filter by verification type (0-2)").option("--deprecated", "Include deprecated skills").option("-s, --sort <field>", "Sort by: published_at, name, price", "published_at").option("-o, --order <dir>", "Sort order: asc, desc", "desc").action(async (options) => {
420
+ const spin = spinner("Fetching skills...").start();
421
+ try {
422
+ const client = getClient();
423
+ const result = await client.api.listSkills({
424
+ page: parseInt(options.page),
425
+ limit: parseInt(options.limit),
426
+ name: options.name,
427
+ agentId: options.agent,
428
+ verificationType: options.verification ? parseInt(options.verification) : void 0,
429
+ includeDeprecated: options.deprecated,
430
+ sortBy: options.sort,
431
+ sortOrder: options.order
432
+ });
433
+ spin.stop();
434
+ output(result, () => {
435
+ const rows = result.data.map((skill) => [
436
+ skill.name,
437
+ skill.version,
438
+ formatUsdc(skill.base_price_usdc),
439
+ skill.verification_type_label,
440
+ formatDuration(skill.timeout_seconds),
441
+ String(skill.tasks_count)
442
+ ]);
443
+ return `
444
+ ${colors.primary("Skills")} (${result.pagination.total} total)
445
+
446
+ ` + table(["Name", "Version", "Price", "Verification", "Timeout", "Tasks"], rows) + `
447
+
448
+ Page ${result.pagination.page}/${result.pagination.pages}`;
449
+ });
450
+ } catch (err) {
451
+ spin.stop();
452
+ error(`Failed to list skills: ${err.message}`);
453
+ process.exit(1);
454
+ }
455
+ });
456
+ skillCmd.command("info <id>").description("Get skill details").action(async (id) => {
457
+ const spin = spinner("Fetching skill...").start();
458
+ try {
459
+ const client = getClient();
460
+ const skill = await client.api.getSkill(id);
461
+ spin.stop();
462
+ output(skill, () => {
463
+ let output2 = `
464
+ ${colors.primary("Skill Details")}
465
+
466
+ `;
467
+ output2 += `${colors.muted("ID:")} ${skill.id}
468
+ `;
469
+ output2 += `${colors.muted("Name:")} ${skill.name}
470
+ `;
471
+ output2 += `${colors.muted("Version:")} ${skill.version}
472
+ `;
473
+ output2 += `${colors.muted("Agent:")} ${formatAddress(skill.agent.id)}
474
+ `;
475
+ output2 += `${colors.muted("Price:")} ${formatUsdc(skill.base_price_usdc)}
476
+ `;
477
+ output2 += `${colors.muted("Worker Bond:")} ${formatUsdc(skill.worker_bond_usdc)}
478
+ `;
479
+ output2 += `${colors.muted("Verification:")} ${skill.verification_type_label}
480
+ `;
481
+ output2 += `${colors.muted("Timeout:")} ${formatDuration(skill.timeout_seconds)}
482
+ `;
483
+ output2 += `${colors.muted("Published:")} ${formatTimestamp(skill.published_at)}
484
+ `;
485
+ output2 += `${colors.muted("Deprecated:")} ${skill.deprecated ? colors.error("Yes") : colors.success("No")}
486
+ `;
487
+ if (skill.input_schema_hash) {
488
+ output2 += `${colors.muted("Input Schema:")} ${skill.input_schema_hash.slice(0, 16)}...
489
+ `;
490
+ }
491
+ if (skill.output_schema_hash) {
492
+ output2 += `${colors.muted("Output Schema:")} ${skill.output_schema_hash.slice(0, 16)}...
493
+ `;
494
+ }
495
+ output2 += `
496
+ ${colors.primary("Priority Multipliers")}
497
+ `;
498
+ const multipliers = skill.priority_multipliers;
499
+ output2 += ` Standard: ${(multipliers[0] / 1e4).toFixed(1)}x
500
+ `;
501
+ output2 += ` Priority: ${(multipliers[1] / 1e4).toFixed(1)}x
502
+ `;
503
+ output2 += ` Urgent: ${(multipliers[2] / 1e4).toFixed(1)}x
504
+ `;
505
+ output2 += `
506
+ ${colors.primary("Statistics")}
507
+ `;
508
+ output2 += ` Total Tasks: ${skill.stats.total_tasks}
509
+ `;
510
+ output2 += ` Templates: ${skill.stats.templates_count}
511
+ `;
512
+ if (Object.keys(skill.stats.tasks_by_status).length > 0) {
513
+ output2 += `
514
+ ${colors.highlight("Tasks by Status:")}
515
+ `;
516
+ for (const [status, count] of Object.entries(skill.stats.tasks_by_status)) {
517
+ output2 += ` ${status}: ${count}
518
+ `;
519
+ }
520
+ }
521
+ if (skill.certifications.length > 0) {
522
+ output2 += `
523
+ ${colors.primary("Certifications")} (${skill.certifications.length})
524
+
525
+ `;
526
+ const certRows = skill.certifications.map((c) => [
527
+ c.certification_type,
528
+ formatAddress(c.certifier_id),
529
+ formatTimestamp(c.certified_at)
530
+ ]);
531
+ output2 += table(["Type", "Certifier", "Certified"], certRows);
532
+ }
533
+ return output2;
534
+ });
535
+ } catch (err) {
536
+ spin.stop();
537
+ error(`Failed to get skill: ${err.message}`);
538
+ process.exit(1);
539
+ }
540
+ });
541
+ skillCmd.command("search <query>").description("Search skills by name").option("-l, --limit <number>", "Max results", "10").action(async (query, options) => {
542
+ const spin = spinner("Searching...").start();
543
+ try {
544
+ const client = getClient();
545
+ const result = await client.api.listSkills({
546
+ name: query,
547
+ limit: parseInt(options.limit)
548
+ });
549
+ spin.stop();
550
+ if (result.data.length === 0) {
551
+ log(`
552
+ No skills found matching "${query}"
553
+ `);
554
+ return;
555
+ }
556
+ output(result, () => {
557
+ const rows = result.data.map((skill) => [
558
+ skill.name,
559
+ skill.version,
560
+ formatUsdc(skill.base_price_usdc),
561
+ skill.verification_type_label,
562
+ formatAddress(skill.id)
563
+ ]);
564
+ return `
565
+ ${colors.primary("Search Results")} for "${query}"
566
+
567
+ ` + table(["Name", "Version", "Price", "Verification", "ID"], rows);
568
+ });
569
+ } catch (err) {
570
+ spin.stop();
571
+ error(`Search failed: ${err.message}`);
572
+ process.exit(1);
573
+ }
574
+ });
575
+ }
576
+
577
+ // src/commands/task.ts
578
+ import { STATUS } from "@tasknet-protocol/shared";
579
+ function registerTaskCommands(program2) {
580
+ const taskCmd = program2.command("task").alias("tasks").description("Manage tasks");
581
+ taskCmd.command("list").description("List tasks").option("-p, --page <number>", "Page number", "1").option("-l, --limit <number>", "Items per page", "20").option("-s, --status <status>", "Filter by status (0-9)").option("--skill <id>", "Filter by skill ID").option("--requester <id>", "Filter by requester agent ID").option("--worker <id>", "Filter by worker agent ID").option("--mine", "Show my tasks (as requester or worker)").option("--available", "Show only available tasks (Posted status)").option("--sort <field>", "Sort by: created_at, expires_at, payment, priority", "created_at").option("-o, --order <dir>", "Sort order: asc, desc", "desc").action(async (options) => {
582
+ const spin = spinner("Fetching tasks...").start();
583
+ try {
584
+ const client = getClient();
585
+ const config2 = getConfig();
586
+ let requesterId;
587
+ let workerId;
588
+ let status;
589
+ if (options.mine && config2.agentId) {
590
+ requesterId = config2.agentId;
591
+ } else {
592
+ requesterId = options.requester;
593
+ workerId = options.worker;
594
+ }
595
+ if (options.available) {
596
+ status = STATUS.POSTED;
597
+ } else if (options.status !== void 0) {
598
+ status = parseInt(options.status);
599
+ }
600
+ const result = await client.api.listTasks({
601
+ page: parseInt(options.page),
602
+ limit: parseInt(options.limit),
603
+ status,
604
+ skillId: options.skill,
605
+ requesterId,
606
+ workerId,
607
+ sortBy: options.sort,
608
+ sortOrder: options.order
609
+ });
610
+ spin.stop();
611
+ output(result, () => {
612
+ const rows = result.data.map((task) => [
613
+ formatAddress(task.id),
614
+ task.skill.name,
615
+ task.status_label,
616
+ task.priority_label,
617
+ formatUsdc(task.payment_amount_usdc),
618
+ formatTimestamp(task.expires_at)
619
+ ]);
620
+ return `
621
+ ${colors.primary("Tasks")} (${result.pagination.total} total)
622
+
623
+ ` + table(["ID", "Skill", "Status", "Priority", "Payment", "Expires"], rows) + `
624
+
625
+ Page ${result.pagination.page}/${result.pagination.pages}`;
626
+ });
627
+ } catch (err) {
628
+ spin.stop();
629
+ error(`Failed to list tasks: ${err.message}`);
630
+ process.exit(1);
631
+ }
632
+ });
633
+ taskCmd.command("info <id>").description("Get task details").action(async (id) => {
634
+ const spin = spinner("Fetching task...").start();
635
+ try {
636
+ const client = getClient();
637
+ const task = await client.api.getTask(id);
638
+ spin.stop();
639
+ output(task, () => {
640
+ let output2 = `
641
+ ${colors.primary("Task Details")}
642
+
643
+ `;
644
+ output2 += `${colors.muted("ID:")} ${task.id}
645
+ `;
646
+ output2 += `${colors.muted("Skill:")} ${task.skill.name} v${task.skill.version}
647
+ `;
648
+ output2 += `${colors.muted("Status:")} ${getStatusColor(task.status)(task.status_label)}
649
+ `;
650
+ output2 += `${colors.muted("Priority:")} ${task.priority_label}
651
+ `;
652
+ output2 += `${colors.muted("Verification:")} ${task.verification_type_label}
653
+ `;
654
+ output2 += `${colors.muted("Payment:")} ${formatUsdc(task.payment_amount_usdc)}
655
+ `;
656
+ output2 += `${colors.muted("Worker Bond:")} ${formatUsdc(task.worker_bond_amount)}
657
+ `;
658
+ output2 += `
659
+ ${colors.primary("Participants")}
660
+ `;
661
+ output2 += `${colors.muted("Requester:")} ${formatAddress(task.requester.id)}
662
+ `;
663
+ if (task.worker) {
664
+ output2 += `${colors.muted("Worker:")} ${formatAddress(task.worker.id)}
665
+ `;
666
+ }
667
+ output2 += `
668
+ ${colors.primary("Payload")}
669
+ `;
670
+ output2 += `${colors.muted("Input Ref:")} ${task.input_payload_ref}
671
+ `;
672
+ if (task.expected_output_hash) {
673
+ output2 += `${colors.muted("Expected Hash:")} ${task.expected_output_hash.slice(0, 32)}...
674
+ `;
675
+ }
676
+ if (task.output_ref) {
677
+ output2 += `${colors.muted("Output Ref:")} ${task.output_ref}
678
+ `;
679
+ }
680
+ if (task.output_hash) {
681
+ output2 += `${colors.muted("Output Hash:")} ${task.output_hash.slice(0, 32)}...
682
+ `;
683
+ }
684
+ output2 += `
685
+ ${colors.primary("Timestamps")}
686
+ `;
687
+ output2 += `${colors.muted("Created:")} ${formatTimestamp(task.timestamps.created_at)}
688
+ `;
689
+ output2 += `${colors.muted("Expires:")} ${formatTimestamp(task.timestamps.expires_at)}
690
+ `;
691
+ if (task.timestamps.reserved_at) {
692
+ output2 += `${colors.muted("Reserved:")} ${formatTimestamp(task.timestamps.reserved_at)}
693
+ `;
694
+ }
695
+ if (task.timestamps.accepted_at) {
696
+ output2 += `${colors.muted("Accepted:")} ${formatTimestamp(task.timestamps.accepted_at)}
697
+ `;
698
+ }
699
+ if (task.timestamps.submitted_at) {
700
+ output2 += `${colors.muted("Submitted:")} ${formatTimestamp(task.timestamps.submitted_at)}
701
+ `;
702
+ }
703
+ if (task.timestamps.verified_at) {
704
+ output2 += `${colors.muted("Verified:")} ${formatTimestamp(task.timestamps.verified_at)}
705
+ `;
706
+ }
707
+ if (task.timestamps.settled_at) {
708
+ output2 += `${colors.muted("Settled:")} ${formatTimestamp(task.timestamps.settled_at)}
709
+ `;
710
+ }
711
+ if (task.events.length > 0) {
712
+ output2 += `
713
+ ${colors.primary("Recent Events")}
714
+
715
+ `;
716
+ const eventRows = task.events.slice(0, 5).map((e) => [
717
+ e.type,
718
+ formatTimestamp(e.timestamp_ms),
719
+ formatAddress(e.tx_digest)
720
+ ]);
721
+ output2 += table(["Event", "Time", "TX"], eventRows);
722
+ }
723
+ return output2;
724
+ });
725
+ } catch (err) {
726
+ spin.stop();
727
+ error(`Failed to get task: ${err.message}`);
728
+ process.exit(1);
729
+ }
730
+ });
731
+ taskCmd.command("watch").description("Watch for new available tasks").option("--skill <id>", "Filter by skill ID").option("-i, --interval <seconds>", "Poll interval", "30").action(async (options) => {
732
+ log(`
733
+ ${colors.primary("Watching for tasks...")} (Ctrl+C to stop)
734
+ `);
735
+ const interval = parseInt(options.interval) * 1e3;
736
+ let seenTasks = /* @__PURE__ */ new Set();
737
+ const poll = async () => {
738
+ try {
739
+ const client = getClient();
740
+ const result = await client.api.listTasks({
741
+ status: STATUS.POSTED,
742
+ skillId: options.skill,
743
+ limit: 20,
744
+ sortBy: "created_at",
745
+ sortOrder: "desc"
746
+ });
747
+ for (const task of result.data) {
748
+ if (!seenTasks.has(task.id)) {
749
+ seenTasks.add(task.id);
750
+ log(
751
+ `${colors.success("NEW")} ${task.skill.name} | ${formatUsdc(task.payment_amount_usdc)} | ${formatAddress(task.id)}`
752
+ );
753
+ }
754
+ }
755
+ } catch (err) {
756
+ error(`Poll failed: ${err.message}`);
757
+ }
758
+ };
759
+ await poll();
760
+ setInterval(poll, interval);
761
+ });
762
+ }
763
+ function getStatusColor(status) {
764
+ switch (status) {
765
+ case STATUS.POSTED:
766
+ case STATUS.RESERVED:
767
+ return colors.primary;
768
+ case STATUS.ACCEPTED:
769
+ case STATUS.IN_PROGRESS:
770
+ case STATUS.SUBMITTED:
771
+ return colors.warning;
772
+ case STATUS.VERIFIED:
773
+ case STATUS.SETTLED:
774
+ return colors.success;
775
+ case STATUS.CANCELLED:
776
+ case STATUS.EXPIRED:
777
+ case STATUS.FAILED:
778
+ return colors.error;
779
+ default:
780
+ return colors.muted;
781
+ }
782
+ }
783
+
784
+ // src/commands/health.ts
785
+ function registerHealthCommand(program2) {
786
+ program2.command("health").description("Check API health status").action(async () => {
787
+ const spin = spinner("Checking health...").start();
788
+ try {
789
+ const client = getClient();
790
+ const health = await client.api.health();
791
+ spin.stop();
792
+ output(health, () => {
793
+ const statusColor = health.status === "healthy" ? colors.success : health.status === "degraded" ? colors.warning : colors.error;
794
+ let output2 = `
795
+ ${colors.primary("TaskNet API Health")}
796
+
797
+ `;
798
+ output2 += `${colors.muted("Status:")} ${statusColor(health.status.toUpperCase())}
799
+ `;
800
+ output2 += `${colors.muted("API Version:")} ${health.apiVersion}
801
+ `;
802
+ output2 += `${colors.muted("Last Sync:")} ${formatTimestamp(health.lastSyncTimestamp)}
803
+ `;
804
+ output2 += `${colors.muted("Sync Age:")} ${(health.syncAgeMs / 1e3).toFixed(0)}s
805
+ `;
806
+ output2 += `${colors.muted("Blocks Behind:")} ${health.blocksBehind}
807
+ `;
808
+ output2 += `${colors.muted("Events Total:")} ${health.eventsProcessedTotal}
809
+ `;
810
+ if (health.stats) {
811
+ output2 += `
812
+ ${colors.primary("Statistics")}
813
+ `;
814
+ output2 += `${colors.muted("Agents:")} ${health.stats.agents}
815
+ `;
816
+ output2 += `${colors.muted("Skills:")} ${health.stats.skills}
817
+ `;
818
+ output2 += `${colors.muted("Tasks:")} ${health.stats.tasks}
819
+ `;
820
+ }
821
+ return output2;
822
+ });
823
+ } catch (err) {
824
+ spin.stop();
825
+ error(`Health check failed: ${err.message}`);
826
+ process.exit(1);
827
+ }
828
+ });
829
+ }
830
+
831
+ // src/commands/claim.ts
832
+ import chalk2 from "chalk";
833
+ import ora2 from "ora";
834
+ import { CLAIM_LABELS } from "@tasknet-protocol/shared";
835
+ function registerClaimCommands(program2) {
836
+ const claim = program2.command("claim").description("Manage identity claims and verification");
837
+ claim.command("generate").description("Generate a verification code for identity claims").option(
838
+ "-t, --type <type>",
839
+ "Claim type: x, github, moltbook, wallet",
840
+ "wallet"
841
+ ).action(async (options) => {
842
+ const spin = ora2("Generating claim...").start();
843
+ try {
844
+ const client = getClient();
845
+ const typeMap = {
846
+ x: 1,
847
+ twitter: 1,
848
+ moltbook: 2,
849
+ github: 3,
850
+ wallet: 4
851
+ };
852
+ const claimType = typeMap[options.type.toLowerCase()] ?? 0;
853
+ const result = await client.api.generateClaim(claimType);
854
+ spin.succeed("Claim generated successfully");
855
+ output(result, () => {
856
+ let out = `
857
+ ${colors.primary("Claim Details")}
858
+
859
+ `;
860
+ out += `${colors.muted("ID:")} ${result.claim.id}
861
+ `;
862
+ out += `${colors.muted("Type:")} ${getClaimTypeLabel(result.claim.claim_type)}
863
+ `;
864
+ out += `${colors.muted("Status:")} ${chalk2.yellow(result.claim.status)}
865
+ `;
866
+ out += `${colors.muted("Created:")} ${result.claim.created_at}
867
+ `;
868
+ out += `
869
+ ${colors.primary("Verification Code")}
870
+ `;
871
+ out += `${chalk2.cyan(result.claim.verification_code)}
872
+ `;
873
+ out += `
874
+ ${colors.primary("Instructions")}
875
+ `;
876
+ out += `${result.instructions}
877
+ `;
878
+ return out;
879
+ });
880
+ } catch (error2) {
881
+ spin.fail(chalk2.red("Failed to generate claim"));
882
+ const err = error2;
883
+ console.error(chalk2.red(err.message));
884
+ process.exit(1);
885
+ }
886
+ });
887
+ claim.command("verify <claimId>").description("Verify a claim with proof").option("-u, --url <url>", "Proof URL (for X, GitHub, Moltbook)").option("-s, --signature <sig>", "Wallet signature (for wallet claims)").action(async (claimId, options) => {
888
+ const spin = ora2("Verifying claim...").start();
889
+ try {
890
+ const client = getClient();
891
+ const result = await client.api.verifyClaim({
892
+ claimId,
893
+ proofUrl: options.url,
894
+ signature: options.signature
895
+ });
896
+ spin.succeed("Claim verified successfully");
897
+ output(result, () => {
898
+ let out = `
899
+ ${colors.primary("Verified Claim")}
900
+
901
+ `;
902
+ out += `${colors.muted("ID:")} ${result.claim.id}
903
+ `;
904
+ out += `${colors.muted("Type:")} ${result.claim.claim_type_label}
905
+ `;
906
+ out += `${colors.muted("Status:")} ${chalk2.green(result.claim.status)}
907
+ `;
908
+ out += `${colors.muted("Claimed By:")} ${result.claim.claimed_by ?? "N/A"}
909
+ `;
910
+ out += `${colors.muted("Verified At:")} ${result.claim.verified_at ?? "N/A"}
911
+ `;
912
+ return out;
913
+ });
914
+ } catch (error2) {
915
+ spin.fail(chalk2.red("Failed to verify claim"));
916
+ const err = error2;
917
+ console.error(chalk2.red(err.message));
918
+ process.exit(1);
919
+ }
920
+ });
921
+ claim.command("get <claimId>").description("Get details of a specific claim").action(async (claimId) => {
922
+ const spin = ora2("Fetching claim...").start();
923
+ try {
924
+ const client = getClient();
925
+ const claimData = await client.api.getClaim(claimId);
926
+ spin.succeed("Claim fetched");
927
+ output(claimData, () => {
928
+ let out = `
929
+ ${colors.primary("Claim Details")}
930
+
931
+ `;
932
+ out += `${colors.muted("ID:")} ${claimData.id}
933
+ `;
934
+ out += `${colors.muted("Agent ID:")} ${formatAddress(claimData.agent_id)}
935
+ `;
936
+ out += `${colors.muted("Type:")} ${claimData.claim_type_label}
937
+ `;
938
+ out += `${colors.muted("Status:")} ${getStatusColor2(claimData.status)}
939
+ `;
940
+ out += `${colors.muted("Verification Code:")} ${claimData.verification_code.slice(0, 30)}...
941
+ `;
942
+ out += `${colors.muted("Claimed By:")} ${claimData.claimed_by ?? "N/A"}
943
+ `;
944
+ out += `${colors.muted("Created At:")} ${claimData.created_at}
945
+ `;
946
+ out += `${colors.muted("Verified At:")} ${claimData.verified_at ?? "N/A"}
947
+ `;
948
+ out += `
949
+ ${colors.primary("Agent")}
950
+ `;
951
+ out += `${colors.muted("ID:")} ${claimData.agent.id}
952
+ `;
953
+ out += `${colors.muted("Owner:")} ${formatAddress(claimData.agent.owner)}
954
+ `;
955
+ return out;
956
+ });
957
+ } catch (error2) {
958
+ spin.fail(chalk2.red("Failed to fetch claim"));
959
+ const err = error2;
960
+ console.error(chalk2.red(err.message));
961
+ process.exit(1);
962
+ }
963
+ });
964
+ claim.command("revoke <claimId>").description("Revoke a verified claim").action(async (claimId) => {
965
+ const spin = ora2("Revoking claim...").start();
966
+ try {
967
+ const client = getClient();
968
+ await client.api.revokeClaim(claimId);
969
+ spin.succeed("Claim revoked successfully");
970
+ } catch (error2) {
971
+ spin.fail(chalk2.red("Failed to revoke claim"));
972
+ const err = error2;
973
+ console.error(chalk2.red(err.message));
974
+ process.exit(1);
975
+ }
976
+ });
977
+ claim.command("list").description("List claims for the current agent").action(async () => {
978
+ const spin = ora2("Fetching claims...").start();
979
+ try {
980
+ const client = getClient();
981
+ const agentId = client.getAgentId();
982
+ if (!agentId) {
983
+ spin.fail("No active agent set. Use 'tasknet config set agentId <id>'");
984
+ process.exit(1);
985
+ }
986
+ const agent = await client.api.getAgent(agentId);
987
+ spin.succeed(`Found ${agent.claims.length} claims`);
988
+ output(agent.claims, () => {
989
+ if (agent.claims.length === 0) {
990
+ return `
991
+ ${chalk2.yellow("No claims found.")}
992
+ Generate a claim with: tasknet claim generate -t wallet
993
+ `;
994
+ }
995
+ let out = `
996
+ ${colors.primary("Claims")}
997
+
998
+ `;
999
+ out += `${colors.muted("ID".padEnd(20))} ${colors.muted("Type".padEnd(15))} ${colors.muted("Claimed By".padEnd(22))} ${colors.muted("Verified At")}
1000
+ `;
1001
+ out += `${colors.muted("-".repeat(20))} ${colors.muted("-".repeat(15))} ${colors.muted("-".repeat(22))} ${colors.muted("-".repeat(20))}
1002
+ `;
1003
+ for (const c of agent.claims) {
1004
+ const id = c.id.slice(0, 18) + "..";
1005
+ const type = getClaimTypeLabel(c.claim_type).padEnd(15);
1006
+ const claimedBy = (c.claimed_by?.slice(0, 20) ?? "N/A").padEnd(22);
1007
+ const verifiedAt = c.verified_at ?? chalk2.yellow("Pending");
1008
+ out += `${id} ${type} ${claimedBy} ${verifiedAt}
1009
+ `;
1010
+ }
1011
+ return out;
1012
+ });
1013
+ } catch (error2) {
1014
+ spin.fail(chalk2.red("Failed to fetch claims"));
1015
+ const err = error2;
1016
+ console.error(chalk2.red(err.message));
1017
+ process.exit(1);
1018
+ }
1019
+ });
1020
+ }
1021
+ function getClaimTypeLabel(type) {
1022
+ return CLAIM_LABELS[type] ?? `Type ${type}`;
1023
+ }
1024
+ function getStatusColor2(status) {
1025
+ switch (status) {
1026
+ case "verified":
1027
+ return chalk2.green(status);
1028
+ case "pending":
1029
+ return chalk2.yellow(status);
1030
+ case "revoked":
1031
+ return chalk2.red(status);
1032
+ default:
1033
+ return status;
1034
+ }
1035
+ }
1036
+
1037
+ // src/commands/badge.ts
1038
+ import chalk3 from "chalk";
1039
+ import ora3 from "ora";
1040
+ import { BADGE_TIER } from "@tasknet-protocol/shared";
1041
+ function registerBadgeCommands(program2) {
1042
+ const badge = program2.command("badge").description("View agent reputation badges");
1043
+ badge.command("list [agentId]").description("List badges for an agent (defaults to current agent)").action(async (agentId) => {
1044
+ const spin = ora3("Fetching badges...").start();
1045
+ try {
1046
+ const client = getClient();
1047
+ const targetId = agentId ?? client.getAgentId();
1048
+ if (!targetId) {
1049
+ spin.fail("No agent specified. Use an agent ID or set an active agent.");
1050
+ process.exit(1);
1051
+ }
1052
+ const agent = await client.api.getAgent(targetId);
1053
+ spin.succeed(`Found ${agent.badges.length} badges`);
1054
+ output(agent.badges, () => {
1055
+ if (agent.badges.length === 0) {
1056
+ return `
1057
+ ${chalk3.yellow("No badges earned yet.")}
1058
+ Complete tasks and verify your identity to earn badges!
1059
+ `;
1060
+ }
1061
+ let out = `
1062
+ ${colors.primary(`Badges for ${targetId.slice(0, 16)}...`)}
1063
+
1064
+ `;
1065
+ out += `${colors.muted("Badge".padEnd(22))} ${colors.muted("Tier".padEnd(10))} ${colors.muted("Earned At")}
1066
+ `;
1067
+ out += `${colors.muted("-".repeat(22))} ${colors.muted("-".repeat(10))} ${colors.muted("-".repeat(20))}
1068
+ `;
1069
+ for (const b of agent.badges) {
1070
+ const badge2 = (getBadgeIcon(b.badge_type) + " " + formatBadgeType(b.badge_type)).padEnd(22);
1071
+ const tier = getTierDisplay(b.tier).padEnd(10);
1072
+ const earnedAt = new Date(b.earned_at).toLocaleDateString();
1073
+ out += `${badge2} ${tier} ${earnedAt}
1074
+ `;
1075
+ }
1076
+ const tierCounts = { bronze: 0, silver: 0, gold: 0, platinum: 0 };
1077
+ for (const b of agent.badges) {
1078
+ const tierName = getTierName(b.tier);
1079
+ if (tierName in tierCounts) {
1080
+ tierCounts[tierName]++;
1081
+ }
1082
+ }
1083
+ out += `
1084
+ ${colors.primary("Summary")}
1085
+ `;
1086
+ out += ` ${chalk3.hex("#CD7F32")("\u25CF")} Bronze: ${tierCounts.bronze} `;
1087
+ out += `${chalk3.gray("\u25CF")} Silver: ${tierCounts.silver} `;
1088
+ out += `${chalk3.yellow("\u25CF")} Gold: ${tierCounts.gold} `;
1089
+ out += `${chalk3.magenta("\u25CF")} Platinum: ${tierCounts.platinum}
1090
+ `;
1091
+ return out;
1092
+ });
1093
+ } catch (error2) {
1094
+ spin.fail(chalk3.red("Failed to fetch badges"));
1095
+ const err = error2;
1096
+ console.error(chalk3.red(err.message));
1097
+ process.exit(1);
1098
+ }
1099
+ });
1100
+ badge.command("types").description("Show available badge types and how to earn them").action(async () => {
1101
+ let out = `
1102
+ ${colors.primary("Available Badges")}
1103
+
1104
+ `;
1105
+ const badges = [
1106
+ {
1107
+ type: "verified_identity",
1108
+ icon: "\u2713",
1109
+ description: "Verified identity via social or wallet",
1110
+ howToEarn: "Verify your identity using X, GitHub, or wallet signature"
1111
+ },
1112
+ {
1113
+ type: "first_task",
1114
+ icon: "\u{1F3AF}",
1115
+ description: "Completed first task",
1116
+ howToEarn: "Complete your first task as a worker"
1117
+ },
1118
+ {
1119
+ type: "task_completer",
1120
+ icon: "\u{1F4E6}",
1121
+ description: "Task completion milestone",
1122
+ howToEarn: "Complete 10/50/200 tasks for Bronze/Silver/Gold"
1123
+ },
1124
+ {
1125
+ type: "reliable_worker",
1126
+ icon: "\u2B50",
1127
+ description: "High completion rate",
1128
+ howToEarn: "Maintain 90%+ completion rate with 20+ tasks"
1129
+ },
1130
+ {
1131
+ type: "high_earner",
1132
+ icon: "\u{1F4B0}",
1133
+ description: "High earnings milestone",
1134
+ howToEarn: "Earn $100/$1K/$10K USDC total"
1135
+ },
1136
+ {
1137
+ type: "task_creator",
1138
+ icon: "\u{1F4DD}",
1139
+ description: "Task creation milestone",
1140
+ howToEarn: "Post 10/50/200 tasks for Bronze/Silver/Gold"
1141
+ },
1142
+ {
1143
+ type: "big_spender",
1144
+ icon: "\u{1F48E}",
1145
+ description: "High spending milestone",
1146
+ howToEarn: "Spend $100/$1K/$10K USDC total"
1147
+ },
1148
+ {
1149
+ type: "networker",
1150
+ icon: "\u{1F310}",
1151
+ description: "Network growth",
1152
+ howToEarn: "Work with 5/25/100 unique counterparties"
1153
+ }
1154
+ ];
1155
+ for (const b of badges) {
1156
+ out += ` ${b.icon} ${chalk3.bold(formatBadgeType(b.type))}
1157
+ `;
1158
+ out += ` ${chalk3.gray(b.description)}
1159
+ `;
1160
+ out += ` ${chalk3.cyan("How to earn:")} ${b.howToEarn}
1161
+
1162
+ `;
1163
+ }
1164
+ out += `${colors.primary("Tiers")}
1165
+ `;
1166
+ out += ` ${chalk3.hex("#CD7F32")("\u25CF")} Bronze - Entry level
1167
+ `;
1168
+ out += ` ${chalk3.gray("\u25CF")} Silver - Intermediate
1169
+ `;
1170
+ out += ` ${chalk3.yellow("\u25CF")} Gold - Advanced
1171
+ `;
1172
+ out += ` ${chalk3.magenta("\u25CF")} Platinum - Expert
1173
+ `;
1174
+ console.log(out);
1175
+ });
1176
+ badge.command("showcase [agentId]").description("Display badges in a showcase format").action(async (agentId) => {
1177
+ const spin = ora3("Loading showcase...").start();
1178
+ try {
1179
+ const client = getClient();
1180
+ const targetId = agentId ?? client.getAgentId();
1181
+ if (!targetId) {
1182
+ spin.fail("No agent specified.");
1183
+ process.exit(1);
1184
+ }
1185
+ const agent = await client.api.getAgent(targetId);
1186
+ spin.stop();
1187
+ if (agent.badges.length === 0) {
1188
+ console.log(chalk3.yellow("\nNo badges to showcase yet."));
1189
+ return;
1190
+ }
1191
+ const byTier = {};
1192
+ for (const b of agent.badges) {
1193
+ if (!byTier[b.tier]) byTier[b.tier] = [];
1194
+ byTier[b.tier].push(b);
1195
+ }
1196
+ let out = `
1197
+ ${chalk3.bold.underline("\u{1F3C6} Badge Showcase")}
1198
+
1199
+ `;
1200
+ for (const tier of [3, 2, 1, 0]) {
1201
+ const tierBadges = byTier[tier];
1202
+ if (!tierBadges || tierBadges.length === 0) continue;
1203
+ const tierName = getTierName(tier);
1204
+ const tierColor = getTierColor(tier);
1205
+ out += tierColor(chalk3.bold(`\u2501\u2501\u2501 ${tierName.toUpperCase()} \u2501\u2501\u2501`)) + "\n\n";
1206
+ for (const b of tierBadges) {
1207
+ out += ` ${getBadgeIcon(b.badge_type)} ${formatBadgeType(b.badge_type)}
1208
+ `;
1209
+ }
1210
+ out += "\n";
1211
+ }
1212
+ const stats = await client.api.getAgentStats(targetId);
1213
+ out += `${colors.primary("Agent Stats")}
1214
+ `;
1215
+ out += ` Tasks Completed: ${stats.workerTasksCompleted}
1216
+ `;
1217
+ out += ` Tasks Posted: ${stats.requesterTasksPosted}
1218
+ `;
1219
+ if (stats.completionRate !== void 0) {
1220
+ out += ` Completion Rate: ${formatPercent(stats.completionRate)}
1221
+ `;
1222
+ }
1223
+ console.log(out);
1224
+ } catch (error2) {
1225
+ spin.fail(chalk3.red("Failed to load showcase"));
1226
+ const err = error2;
1227
+ console.error(chalk3.red(err.message));
1228
+ process.exit(1);
1229
+ }
1230
+ });
1231
+ }
1232
+ function formatBadgeType(type) {
1233
+ return type.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1234
+ }
1235
+ function getBadgeIcon(type) {
1236
+ const icons = {
1237
+ verified_identity: "\u2713",
1238
+ first_task: "\u{1F3AF}",
1239
+ task_completer: "\u{1F4E6}",
1240
+ reliable_worker: "\u2B50",
1241
+ high_earner: "\u{1F4B0}",
1242
+ task_creator: "\u{1F4DD}",
1243
+ big_spender: "\u{1F48E}",
1244
+ networker: "\u{1F310}",
1245
+ fast_worker: "\u26A1",
1246
+ top_performer: "\u{1F3C6}"
1247
+ };
1248
+ return icons[type] ?? "\u{1F3C5}";
1249
+ }
1250
+ function getTierName(tier) {
1251
+ const names = ["bronze", "silver", "gold", "platinum"];
1252
+ return names[tier] ?? "unknown";
1253
+ }
1254
+ function getTierDisplay(tier) {
1255
+ const tierName = getTierName(tier);
1256
+ const color = getTierColor(tier);
1257
+ return color(tierName.charAt(0).toUpperCase() + tierName.slice(1));
1258
+ }
1259
+ function getTierColor(tier) {
1260
+ switch (tier) {
1261
+ case BADGE_TIER.BRONZE:
1262
+ return chalk3.hex("#CD7F32");
1263
+ case BADGE_TIER.SILVER:
1264
+ return chalk3.gray;
1265
+ case BADGE_TIER.GOLD:
1266
+ return chalk3.yellow;
1267
+ case 3:
1268
+ return chalk3.magenta;
1269
+ default:
1270
+ return chalk3.white;
1271
+ }
1272
+ }
1273
+
1274
+ // src/index.ts
1275
+ var program = new Command();
1276
+ var banner = chalk4.cyan(`
1277
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
1278
+ \u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D
1279
+ \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551
1280
+ \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551
1281
+ \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551
1282
+ \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D
1283
+ `);
1284
+ program.name("tasknet").description("CLI for TaskNet Protocol - Agent-to-Agent Skills Marketplace").version("0.2.0").addHelpText("beforeAll", banner).option("--json", "Output as JSON").hook("preAction", (thisCommand) => {
1285
+ const opts = thisCommand.opts();
1286
+ if (opts.json) {
1287
+ const config2 = getConfig();
1288
+ process.env.TASKNET_OUTPUT_FORMAT = "json";
1289
+ }
1290
+ });
1291
+ registerConfigCommands(program);
1292
+ registerAgentCommands(program);
1293
+ registerSkillCommands(program);
1294
+ registerTaskCommands(program);
1295
+ registerClaimCommands(program);
1296
+ registerBadgeCommands(program);
1297
+ registerHealthCommand(program);
1298
+ program.parse();
1299
+ //# sourceMappingURL=index.js.map