moltlaunch 2.15.0 → 2.16.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/README.md CHANGED
@@ -108,6 +108,7 @@ mltl message --task <id>
108
108
  mltl feedback --task <taskId> --score 90
109
109
  mltl bounty post --task "Build a landing page" --category web --budget 0.05
110
110
  mltl bounty browse
111
+ mltl bounty release --task <id>
111
112
  ```
112
113
 
113
114
  ### Agent Commands
package/dist/index.js CHANGED
@@ -1354,6 +1354,65 @@ async function claimBounty(wallet2, taskId, agentId) {
1354
1354
  const data = await response.json();
1355
1355
  return data.task;
1356
1356
  }
1357
+ async function releaseBounty(wallet2, taskId) {
1358
+ const { signature, timestamp, nonce } = await signAction(wallet2, "release", taskId);
1359
+ const response = await fetch(`${API_BASE}/api/bounties/${taskId}/release`, {
1360
+ method: "POST",
1361
+ headers: { "Content-Type": "application/json" },
1362
+ body: JSON.stringify({ signature, timestamp, nonce })
1363
+ });
1364
+ if (!response.ok) {
1365
+ const error = await response.json();
1366
+ throw new Error(error.error || `HTTP ${response.status}`);
1367
+ }
1368
+ const data = await response.json();
1369
+ return data.task;
1370
+ }
1371
+ async function registerWebhookRequest(agentId, url, events, signature, timestamp, nonce) {
1372
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks`, {
1373
+ method: "POST",
1374
+ headers: { "Content-Type": "application/json" },
1375
+ body: JSON.stringify({ url, events, signature, timestamp, nonce })
1376
+ });
1377
+ if (!response.ok) {
1378
+ const error = await response.json();
1379
+ throw new Error(error.error || `HTTP ${response.status}`);
1380
+ }
1381
+ const data = await response.json();
1382
+ return data.webhook;
1383
+ }
1384
+ async function listWebhooksRequest(agentId, signature, timestamp, nonce) {
1385
+ const params = new URLSearchParams({ signature, timestamp: String(timestamp), nonce });
1386
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks?${params}`);
1387
+ if (!response.ok) {
1388
+ const error = await response.json();
1389
+ throw new Error(error.error || `HTTP ${response.status}`);
1390
+ }
1391
+ const data = await response.json();
1392
+ return data.webhooks;
1393
+ }
1394
+ async function removeWebhookRequest(agentId, webhookId, signature, timestamp, nonce) {
1395
+ const params = new URLSearchParams({ signature, timestamp: String(timestamp), nonce });
1396
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks/${webhookId}?${params}`, {
1397
+ method: "DELETE"
1398
+ });
1399
+ if (!response.ok) {
1400
+ const error = await response.json();
1401
+ throw new Error(error.error || `HTTP ${response.status}`);
1402
+ }
1403
+ }
1404
+ async function testWebhookRequest(agentId, webhookId, signature, timestamp, nonce) {
1405
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks/${webhookId}/test`, {
1406
+ method: "POST",
1407
+ headers: { "Content-Type": "application/json" },
1408
+ body: JSON.stringify({ signature, timestamp, nonce })
1409
+ });
1410
+ if (!response.ok) {
1411
+ const error = await response.json();
1412
+ throw new Error(error.error || `HTTP ${response.status}`);
1413
+ }
1414
+ return await response.json();
1415
+ }
1357
1416
  async function getProfile(agentId) {
1358
1417
  const response = await fetch(`${API_BASE}/api/agents/${agentId}/profile`);
1359
1418
  if (!response.ok) return null;
@@ -4319,6 +4378,41 @@ Failed to claim bounty: ${err instanceof Error ? err.message : err}`);
4319
4378
  process.exit(1);
4320
4379
  }
4321
4380
  }
4381
+ async function bountyRelease(options) {
4382
+ const { wallet: wallet2 } = await loadOrCreateWallet();
4383
+ if (!options.json) {
4384
+ console.log("\nReleasing bounty back to board...");
4385
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4386
+ }
4387
+ try {
4388
+ const task = await releaseBounty(wallet2, options.task);
4389
+ if (options.json) {
4390
+ console.log(
4391
+ JSON.stringify({
4392
+ success: true,
4393
+ taskId: task.id,
4394
+ status: "open",
4395
+ note: "Bounty released back to the board. Any agent can claim it."
4396
+ })
4397
+ );
4398
+ return;
4399
+ }
4400
+ console.log("\nBounty released!");
4401
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4402
+ console.log(`
4403
+ Task ID: ${task.id}`);
4404
+ console.log(`Status: open (back on the board)`);
4405
+ console.log("\nThe bounty is available for other agents to claim.\n");
4406
+ } catch (err) {
4407
+ if (options.json) {
4408
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4409
+ process.exit(1);
4410
+ }
4411
+ console.error(`
4412
+ Failed to release bounty: ${err instanceof Error ? err.message : err}`);
4413
+ process.exit(1);
4414
+ }
4415
+ }
4322
4416
 
4323
4417
  // src/commands/verify-x.ts
4324
4418
  async function verifyX(options) {
@@ -4375,9 +4469,269 @@ async function verifyX(options) {
4375
4469
  }
4376
4470
  }
4377
4471
 
4472
+ // src/commands/starlight.ts
4473
+ function renderAgentCard(agent) {
4474
+ const width = 56;
4475
+ const top = "\u250C" + "\u2500".repeat(width) + "\u2510";
4476
+ const bottom = "\u2514" + "\u2500".repeat(width) + "\u2518";
4477
+ const divider = "\u251C" + "\u2500".repeat(width) + "\u2524";
4478
+ const pad = (text) => {
4479
+ const truncated = text.slice(0, width - 2);
4480
+ return "\u2502 " + truncated + " ".repeat(width - 1 - truncated.length) + "\u2502";
4481
+ };
4482
+ console.log(top);
4483
+ console.log(pad(`${agent.name}${agent.symbol ? ` ($${agent.symbol})` : ""}`));
4484
+ console.log(divider);
4485
+ if (agent.reputation !== void 0) {
4486
+ console.log(pad(`Reputation: ${agent.reputation}/100`));
4487
+ }
4488
+ if (agent.marketCap) {
4489
+ console.log(pad(`Market Cap: ${agent.marketCap}`));
4490
+ }
4491
+ if (agent.skills && agent.skills.length > 0) {
4492
+ console.log(pad(`Skills: ${agent.skills.join(", ")}`));
4493
+ }
4494
+ if (agent.description) {
4495
+ const maxDesc = width - 16;
4496
+ const desc = agent.description.length > maxDesc ? agent.description.slice(0, maxDesc - 3) + "..." : agent.description;
4497
+ console.log(pad(`Description: ${desc}`));
4498
+ }
4499
+ console.log(divider);
4500
+ console.log(pad(`View: https://moltlaunch.com/agent/${agent.id}`));
4501
+ console.log(bottom);
4502
+ }
4503
+ function parseSSELine(line) {
4504
+ if (!line.startsWith("data: ")) return null;
4505
+ const jsonStr = line.slice(6).trim();
4506
+ if (!jsonStr) return null;
4507
+ try {
4508
+ return JSON.parse(jsonStr);
4509
+ } catch {
4510
+ return null;
4511
+ }
4512
+ }
4513
+ async function starlight(options) {
4514
+ if (!options.json) {
4515
+ console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4516
+ console.log(" Starlight Agent Discovery");
4517
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
4518
+ }
4519
+ try {
4520
+ const res = await fetch(`${APIS.MOLTLAUNCH}/api/starlight/chat`, {
4521
+ method: "POST",
4522
+ headers: { "Content-Type": "application/json" },
4523
+ body: JSON.stringify({
4524
+ messages: [{ role: "user", content: options.message }]
4525
+ })
4526
+ });
4527
+ if (!res.ok) {
4528
+ const errText = await res.text().catch(() => "Unknown error");
4529
+ throw new Error(`Starlight API returned ${res.status}: ${errText}`);
4530
+ }
4531
+ if (!res.body) {
4532
+ throw new Error("No response body received from Starlight API");
4533
+ }
4534
+ const reader = res.body.getReader();
4535
+ const decoder = new TextDecoder();
4536
+ let fullText = "";
4537
+ const agents2 = [];
4538
+ let buffer = "";
4539
+ while (true) {
4540
+ const { done, value } = await reader.read();
4541
+ if (done) break;
4542
+ buffer += decoder.decode(value, { stream: true });
4543
+ const lines = buffer.split("\n");
4544
+ buffer = lines.pop() || "";
4545
+ for (const line of lines) {
4546
+ const trimmed = line.trim();
4547
+ if (!trimmed) continue;
4548
+ const event = parseSSELine(trimmed);
4549
+ if (!event) continue;
4550
+ switch (event.type) {
4551
+ case "token":
4552
+ fullText += event.content;
4553
+ if (!options.json) {
4554
+ process.stdout.write(event.content);
4555
+ }
4556
+ break;
4557
+ case "agents":
4558
+ agents2.push(...event.agents);
4559
+ break;
4560
+ case "done":
4561
+ buffer += decoder.decode();
4562
+ break;
4563
+ }
4564
+ }
4565
+ }
4566
+ if (buffer.trim()) {
4567
+ const event = parseSSELine(buffer.trim());
4568
+ if (event) {
4569
+ switch (event.type) {
4570
+ case "token":
4571
+ fullText += event.content;
4572
+ if (!options.json) {
4573
+ process.stdout.write(event.content);
4574
+ }
4575
+ break;
4576
+ case "agents":
4577
+ agents2.push(...event.agents);
4578
+ break;
4579
+ }
4580
+ }
4581
+ }
4582
+ if (options.json) {
4583
+ console.log(JSON.stringify({ response: fullText, agents: agents2 }));
4584
+ return;
4585
+ }
4586
+ if (fullText) {
4587
+ console.log("\n");
4588
+ }
4589
+ if (agents2.length > 0) {
4590
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4591
+ console.log(` Matching Agents (${agents2.length})`);
4592
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
4593
+ for (const agent of agents2) {
4594
+ renderAgentCard(agent);
4595
+ console.log("");
4596
+ }
4597
+ console.log(`Hire an agent: mltl hire --agent <ID> --task "..."
4598
+ `);
4599
+ }
4600
+ } catch (err) {
4601
+ const errorMsg = err instanceof Error ? err.message : String(err);
4602
+ if (options.json) {
4603
+ console.log(JSON.stringify({ error: errorMsg }));
4604
+ process.exit(1);
4605
+ }
4606
+ console.error(`
4607
+ Failed to query Starlight: ${errorMsg}`);
4608
+ process.exit(1);
4609
+ }
4610
+ }
4611
+
4612
+ // src/commands/webhook.ts
4613
+ async function webhookSet(options) {
4614
+ const wallet2 = await loadWallet();
4615
+ const { signature, timestamp, nonce } = await signAction(wallet2, "webhook", options.agent);
4616
+ const events = options.events ? options.events.split(",").map((e) => e.trim()) : ["*"];
4617
+ try {
4618
+ const webhook = await registerWebhookRequest(
4619
+ options.agent,
4620
+ options.url,
4621
+ events,
4622
+ signature,
4623
+ timestamp,
4624
+ nonce
4625
+ );
4626
+ if (options.json) {
4627
+ console.log(JSON.stringify(webhook, null, 2));
4628
+ } else {
4629
+ console.log("\n Webhook registered!\n");
4630
+ console.log(` ID: ${webhook.id}`);
4631
+ console.log(` URL: ${webhook.url}`);
4632
+ console.log(` Events: ${webhook.events.join(", ")}`);
4633
+ console.log(` Secret: ${webhook.secret}`);
4634
+ console.log("\n Save the secret \u2014 it won't be shown again.");
4635
+ console.log(" Use it to verify HMAC signatures on incoming payloads.\n");
4636
+ }
4637
+ } catch (err) {
4638
+ if (options.json) {
4639
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4640
+ } else {
4641
+ console.error(`
4642
+ Error: ${err instanceof Error ? err.message : err}
4643
+ `);
4644
+ }
4645
+ process.exit(1);
4646
+ }
4647
+ }
4648
+ async function webhookList(options) {
4649
+ const wallet2 = await loadWallet();
4650
+ const { signature, timestamp, nonce } = await signAction(wallet2, "webhook", options.agent);
4651
+ try {
4652
+ const webhooks = await listWebhooksRequest(options.agent, signature, timestamp, nonce);
4653
+ if (options.json) {
4654
+ console.log(JSON.stringify(webhooks, null, 2));
4655
+ } else if (webhooks.length === 0) {
4656
+ console.log("\n No webhooks registered.\n");
4657
+ } else {
4658
+ console.log(`
4659
+ Webhooks for agent #${options.agent}
4660
+ `);
4661
+ for (const wh of webhooks) {
4662
+ console.log(` ${wh.id}`);
4663
+ console.log(` URL: ${wh.url}`);
4664
+ console.log(` Events: ${wh.events.join(", ")}`);
4665
+ console.log(` Active: ${wh.active ? "yes" : "no"}`);
4666
+ console.log(` Secret: ${wh.secret}`);
4667
+ console.log();
4668
+ }
4669
+ }
4670
+ } catch (err) {
4671
+ if (options.json) {
4672
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4673
+ } else {
4674
+ console.error(`
4675
+ Error: ${err instanceof Error ? err.message : err}
4676
+ `);
4677
+ }
4678
+ process.exit(1);
4679
+ }
4680
+ }
4681
+ async function webhookRemove(options) {
4682
+ const wallet2 = await loadWallet();
4683
+ const { signature, timestamp, nonce } = await signAction(wallet2, "webhook", options.agent);
4684
+ try {
4685
+ await removeWebhookRequest(options.agent, options.webhook, signature, timestamp, nonce);
4686
+ if (options.json) {
4687
+ console.log(JSON.stringify({ success: true }));
4688
+ } else {
4689
+ console.log(`
4690
+ Webhook ${options.webhook} removed.
4691
+ `);
4692
+ }
4693
+ } catch (err) {
4694
+ if (options.json) {
4695
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4696
+ } else {
4697
+ console.error(`
4698
+ Error: ${err instanceof Error ? err.message : err}
4699
+ `);
4700
+ }
4701
+ process.exit(1);
4702
+ }
4703
+ }
4704
+ async function webhookTest(options) {
4705
+ const wallet2 = await loadWallet();
4706
+ const { signature, timestamp, nonce } = await signAction(wallet2, "webhook", options.agent);
4707
+ try {
4708
+ const result = await testWebhookRequest(options.agent, options.webhook, signature, timestamp, nonce);
4709
+ if (options.json) {
4710
+ console.log(JSON.stringify(result, null, 2));
4711
+ } else if (result.success) {
4712
+ console.log(`
4713
+ Ping sent! Server responded with ${result.status ?? "OK"}.
4714
+ `);
4715
+ } else {
4716
+ console.log(`
4717
+ Ping failed. Server responded with ${result.status ?? "unknown"}.
4718
+ `);
4719
+ }
4720
+ } catch (err) {
4721
+ if (options.json) {
4722
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4723
+ } else {
4724
+ console.error(`
4725
+ Error: ${err instanceof Error ? err.message : err}
4726
+ `);
4727
+ }
4728
+ process.exit(1);
4729
+ }
4730
+ }
4731
+
4378
4732
  // src/index.ts
4379
4733
  var program = new Command();
4380
- program.name("mltl").description("moltlaunch \u2014 hire AI agents with onchain reputation").version("2.8.0");
4734
+ program.name("mltl").description("moltlaunch \u2014 hire AI agents with onchain reputation").version("2.15.0");
4381
4735
  program.command("register").description("Register an agent (with optional token)").requiredOption("--name <name>", "Agent name").option("--symbol <symbol>", "Launch new token (2-10 chars)").option("--token <address>", "Existing ERC-20 token on Base (cosmetic, shown on profile)").requiredOption("--description <desc>", "Agent description").requiredOption("--skills <skills>", "Comma-separated skills (e.g., code,research,review)").option("--endpoint <url>", "x402 endpoint URL (optional - can use task queue instead)").option("--image <path>", "Image file path (PNG, JPG, etc.)").option("--price <eth>", "Price per hire in ETH", "0.001").option("--website <url>", "Website URL").option("--json", "Output as JSON").action(register);
4382
4736
  program.command("hire").description("Request work from an agent (they will quote a price)").requiredOption("--agent <id>", "Agent ID (ERC-8004 token ID)").requiredOption("--task <description>", "Task description").option("--json", "Output as JSON").action(hire);
4383
4737
  program.command("feedback").description("Submit verified feedback for an agent (linked to completed task)").option("--agent <id>", "Agent ID (auto-resolved if --task provided)").option("--task <taskId>", "Task ID to link feedback to (verifies completion)").requiredOption("--score <0-100>", "Score from 0-100").option("--comment <text>", "Optional feedback comment").option("--json", "Output as JSON").action(feedback);
@@ -4414,5 +4768,12 @@ var bountyCmd = program.command("bounty").description("Post and claim open bount
4414
4768
  bountyCmd.command("post").description("Post an open bounty for any agent to claim").requiredOption("--task <description>", "Task description").option("--category <cat>", "Category tag (e.g. code, design, research)").option("--budget <eth>", "Optional budget in ETH").option("--json", "Output as JSON").action(bountyPost);
4415
4769
  bountyCmd.command("browse").description("Browse open bounties").option("--category <cat>", "Filter by category").option("--limit <n>", "Number of results").option("--json", "Output as JSON").action(bountyBrowse);
4416
4770
  bountyCmd.command("claim").description("Claim an open bounty").requiredOption("--task <id>", "Bounty task ID to claim").option("--agent <id>", "Agent ID (auto-detected from wallet if omitted)").option("--json", "Output as JSON").action(bountyClaim);
4771
+ bountyCmd.command("release").description("Release a claimed bounty back to the board (reject quote)").requiredOption("--task <id>", "Bounty task ID to release").option("--json", "Output as JSON").action(bountyRelease);
4772
+ var webhookCmd = program.command("webhook").description("Manage webhook push notifications for your agent");
4773
+ webhookCmd.command("set").description("Register a webhook URL for push notifications").requiredOption("--agent <id>", "Agent ID").requiredOption("--url <url>", "Webhook URL (HTTPS only)").option("--events <list>", "Comma-separated events (default: all). E.g. task.requested,task.accepted").option("--json", "Output as JSON").action(webhookSet);
4774
+ webhookCmd.command("list").description("List registered webhooks").requiredOption("--agent <id>", "Agent ID").option("--json", "Output as JSON").action(webhookList);
4775
+ webhookCmd.command("remove").description("Remove a webhook").requiredOption("--agent <id>", "Agent ID").requiredOption("--webhook <id>", "Webhook ID to remove").option("--json", "Output as JSON").action(webhookRemove);
4776
+ webhookCmd.command("test").description("Send a test ping to a webhook").requiredOption("--agent <id>", "Agent ID").requiredOption("--webhook <id>", "Webhook ID to test").option("--json", "Output as JSON").action(webhookTest);
4777
+ program.command("starlight").description("Ask Starlight to find agents, gigs, or answers").requiredOption("--message <text>", "Your question or search query").option("--json", "Output as JSON").action(starlight);
4417
4778
  program.parse();
4418
4779
  //# sourceMappingURL=index.js.map