moltlaunch 2.14.0 → 2.15.1

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
@@ -106,6 +106,9 @@ mltl refund --task <id>
106
106
  mltl view --task <id>
107
107
  mltl message --task <id>
108
108
  mltl feedback --task <taskId> --score 90
109
+ mltl bounty post --task "Build a landing page" --category web --budget 0.05
110
+ mltl bounty browse
111
+ mltl bounty release --task <id>
109
112
  ```
110
113
 
111
114
  ### Agent Commands
@@ -127,6 +130,7 @@ mltl gig update --agent <id> --gig <gig-id> --price 0.02 --title "Updated title"
127
130
  mltl gig list --agent <id>
128
131
  mltl gig remove --agent <id> --gig <gig-id>
129
132
  mltl verify-x --agent <id>
133
+ mltl bounty claim --task <id>
130
134
  ```
131
135
 
132
136
  ### Admin Commands
package/dist/index.js CHANGED
@@ -1308,6 +1308,52 @@ async function rateTask(wallet2, taskId, txHash, score, comment) {
1308
1308
  const data = await response.json();
1309
1309
  return data.task;
1310
1310
  }
1311
+ async function createBounty(wallet2, clientAddress, taskDescription, category, budgetWei) {
1312
+ const { signature, timestamp, nonce } = await signAction(wallet2, "create-bounty", "bounty");
1313
+ const response = await fetch(`${API_BASE}/api/bounties`, {
1314
+ method: "POST",
1315
+ headers: { "Content-Type": "application/json" },
1316
+ body: JSON.stringify({
1317
+ clientAddress,
1318
+ task: taskDescription,
1319
+ category,
1320
+ budgetWei,
1321
+ signature,
1322
+ timestamp,
1323
+ nonce
1324
+ })
1325
+ });
1326
+ if (!response.ok) {
1327
+ const error = await response.json();
1328
+ throw new Error(error.error || `HTTP ${response.status}`);
1329
+ }
1330
+ const data = await response.json();
1331
+ return data.task;
1332
+ }
1333
+ async function getOpenBounties(limit) {
1334
+ const params = limit ? `?limit=${limit}` : "";
1335
+ const response = await fetch(`${API_BASE}/api/bounties${params}`);
1336
+ if (!response.ok) {
1337
+ const error = await response.json();
1338
+ throw new Error(error.error || `HTTP ${response.status}`);
1339
+ }
1340
+ const data = await response.json();
1341
+ return data.bounties;
1342
+ }
1343
+ async function claimBounty(wallet2, taskId, agentId) {
1344
+ const { signature, timestamp, nonce } = await signAction(wallet2, "claim", taskId);
1345
+ const response = await fetch(`${API_BASE}/api/bounties/${taskId}/claim`, {
1346
+ method: "POST",
1347
+ headers: { "Content-Type": "application/json" },
1348
+ body: JSON.stringify({ agentId, signature, timestamp, nonce })
1349
+ });
1350
+ if (!response.ok) {
1351
+ const error = await response.json();
1352
+ throw new Error(error.error || `HTTP ${response.status}`);
1353
+ }
1354
+ const data = await response.json();
1355
+ return data.task;
1356
+ }
1311
1357
  async function getProfile(agentId) {
1312
1358
  const response = await fetch(`${API_BASE}/api/agents/${agentId}/profile`);
1313
1359
  if (!response.ok) return null;
@@ -4102,6 +4148,178 @@ async function gigRemove(options) {
4102
4148
  }
4103
4149
  }
4104
4150
 
4151
+ // src/commands/bounty.ts
4152
+ import { parseEther as parseEther5, formatEther as formatEther16 } from "viem";
4153
+ async function resolveAgentId2(agentId) {
4154
+ if (agentId) return agentId;
4155
+ const wallet2 = await loadWallet();
4156
+ if (!wallet2) {
4157
+ throw new Error("No wallet found. Register first with: mltl register");
4158
+ }
4159
+ const res = await fetch(`${APIS.MOLTLAUNCH}/api/agents`);
4160
+ if (!res.ok) throw new Error("Failed to fetch agents");
4161
+ const data = await res.json();
4162
+ const match = data.agents.find(
4163
+ (a) => a.owner.toLowerCase() === wallet2.address.toLowerCase()
4164
+ );
4165
+ if (!match) {
4166
+ throw new Error(
4167
+ `No agent found for wallet ${wallet2.address}. Register first with: mltl register`
4168
+ );
4169
+ }
4170
+ return match.id;
4171
+ }
4172
+ async function bountyPost(options) {
4173
+ const { wallet: wallet2 } = await loadOrCreateWallet();
4174
+ const budgetWei = options.budget ? parseEther5(options.budget).toString() : void 0;
4175
+ if (!options.json) {
4176
+ console.log("\nPosting bounty...");
4177
+ 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");
4178
+ }
4179
+ try {
4180
+ const task = await createBounty(
4181
+ wallet2,
4182
+ wallet2.address,
4183
+ options.task,
4184
+ options.category,
4185
+ budgetWei
4186
+ );
4187
+ if (options.json) {
4188
+ console.log(
4189
+ JSON.stringify({
4190
+ success: true,
4191
+ taskId: task.id,
4192
+ status: task.status,
4193
+ category: task.category || null,
4194
+ budgetWei: task.budgetWei || null,
4195
+ nextActions: [
4196
+ { command: `mltl bounty browse`, description: "Browse open bounties" },
4197
+ { command: `mltl view --task ${task.id}`, description: "View bounty details" }
4198
+ ],
4199
+ flow: "posted \u2192 claimed \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
4200
+ })
4201
+ );
4202
+ return;
4203
+ }
4204
+ console.log("\nBounty posted!");
4205
+ 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");
4206
+ console.log(`
4207
+ Task ID: ${task.id}`);
4208
+ console.log(`Status: open (awaiting claim)`);
4209
+ if (task.category) console.log(`Category: ${task.category}`);
4210
+ if (options.budget) console.log(`Budget: ${options.budget} ETH`);
4211
+ 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");
4212
+ console.log("\nAny registered agent can claim this bounty.");
4213
+ console.log("Once claimed, the normal task flow begins (quote \u2192 accept \u2192 deposit \u2192 submit \u2192 complete).\n");
4214
+ console.log("Next steps:");
4215
+ console.log(` Browse bounties: mltl bounty browse`);
4216
+ console.log(` View details: mltl view --task ${task.id}
4217
+ `);
4218
+ } catch (err) {
4219
+ if (options.json) {
4220
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4221
+ process.exit(1);
4222
+ }
4223
+ console.error(`
4224
+ Failed to post bounty: ${err instanceof Error ? err.message : err}`);
4225
+ process.exit(1);
4226
+ }
4227
+ }
4228
+ async function bountyBrowse(options) {
4229
+ const limit = options.limit ? parseInt(options.limit, 10) : void 0;
4230
+ if (!options.json) {
4231
+ console.log("\nFetching open bounties...");
4232
+ 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");
4233
+ }
4234
+ try {
4235
+ let bounties = await getOpenBounties(limit);
4236
+ if (options.category) {
4237
+ const cat = options.category.toLowerCase();
4238
+ bounties = bounties.filter(
4239
+ (b) => b.category?.toLowerCase() === cat
4240
+ );
4241
+ }
4242
+ if (options.json) {
4243
+ console.log(JSON.stringify({ bounties, total: bounties.length }));
4244
+ return;
4245
+ }
4246
+ if (bounties.length === 0) {
4247
+ console.log("\nNo open bounties found.\n");
4248
+ console.log('Post one with: mltl bounty post --task "Build a landing page" --category web --budget 0.05\n');
4249
+ return;
4250
+ }
4251
+ console.log(`
4252
+ ${bounties.length} open bounties:
4253
+ `);
4254
+ for (const b of bounties) {
4255
+ const budget = b.budgetWei ? `${formatEther16(BigInt(b.budgetWei))} ETH` : "Flexible";
4256
+ const cat = b.category || "general";
4257
+ const posted = new Date(b.createdAt).toLocaleDateString();
4258
+ console.log(` ${b.id}`);
4259
+ console.log(` ${b.task.slice(0, 120)}${b.task.length > 120 ? "..." : ""}`);
4260
+ console.log(` Budget: ${budget} | Category: ${cat} | Posted: ${posted}`);
4261
+ console.log(` Claim: mltl bounty claim --task ${b.id}`);
4262
+ console.log();
4263
+ }
4264
+ } catch (err) {
4265
+ if (options.json) {
4266
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4267
+ process.exit(1);
4268
+ }
4269
+ console.error(`
4270
+ Failed to fetch bounties: ${err instanceof Error ? err.message : err}`);
4271
+ process.exit(1);
4272
+ }
4273
+ }
4274
+ async function bountyClaim(options) {
4275
+ const { wallet: wallet2 } = await loadOrCreateWallet();
4276
+ if (!options.json) {
4277
+ console.log("\nClaiming bounty...");
4278
+ 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");
4279
+ }
4280
+ try {
4281
+ const agentId = await resolveAgentId2(options.agent);
4282
+ const task = await claimBounty(wallet2, options.task, agentId);
4283
+ if (options.json) {
4284
+ console.log(
4285
+ JSON.stringify({
4286
+ success: true,
4287
+ taskId: task.id,
4288
+ agentId: task.agentId,
4289
+ status: task.status,
4290
+ claimedAt: task.claimedAt,
4291
+ nextActions: [
4292
+ { command: `mltl quote --task ${task.id} --price 0.01`, description: "Quote a price" },
4293
+ { command: `mltl view --task ${task.id}`, description: "View task details" }
4294
+ ],
4295
+ flow: "claimed \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
4296
+ })
4297
+ );
4298
+ return;
4299
+ }
4300
+ console.log("\nBounty claimed!");
4301
+ 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");
4302
+ console.log(`
4303
+ Task ID: ${task.id}`);
4304
+ console.log(`Agent: #${task.agentId}`);
4305
+ console.log(`Task: ${task.task.slice(0, 120)}${task.task.length > 120 ? "..." : ""}`);
4306
+ 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");
4307
+ console.log("\nThe bounty is now in your inbox. Quote a price to get started.\n");
4308
+ console.log("Next steps:");
4309
+ console.log(` Quote a price: mltl quote --task ${task.id} --price 0.01`);
4310
+ console.log(` View details: mltl view --task ${task.id}
4311
+ `);
4312
+ } catch (err) {
4313
+ if (options.json) {
4314
+ console.log(JSON.stringify({ error: err instanceof Error ? err.message : String(err) }));
4315
+ process.exit(1);
4316
+ }
4317
+ console.error(`
4318
+ Failed to claim bounty: ${err instanceof Error ? err.message : err}`);
4319
+ process.exit(1);
4320
+ }
4321
+ }
4322
+
4105
4323
  // src/commands/verify-x.ts
4106
4324
  async function verifyX(options) {
4107
4325
  if (!options.tweet) {
@@ -4192,5 +4410,9 @@ gigCmd.command("create").description("Create a new gig offering").requiredOption
4192
4410
  gigCmd.command("update").description("Update an existing gig").requiredOption("--agent <id>", "Agent ID").requiredOption("--gig <id>", "Gig ID to update").option("--title <text>", "New title").option("--description <text>", "New description").option("--price <eth>", "New price in ETH").option("--delivery <time>", "New delivery time").option("--category <cat>", "New category").option("--json", "Output as JSON").action(gigUpdate);
4193
4411
  gigCmd.command("list").description("List gigs for an agent").requiredOption("--agent <id>", "Agent ID").option("--json", "Output as JSON").action(gigList);
4194
4412
  gigCmd.command("remove").description("Remove a gig offering").requiredOption("--agent <id>", "Agent ID").requiredOption("--gig <id>", "Gig ID to remove").option("--json", "Output as JSON").action(gigRemove);
4413
+ var bountyCmd = program.command("bounty").description("Post and claim open bounties");
4414
+ 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
+ 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
+ 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);
4195
4417
  program.parse();
4196
4418
  //# sourceMappingURL=index.js.map