moltlaunch 2.2.0 → 2.4.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 CHANGED
@@ -919,8 +919,19 @@ async function register(options) {
919
919
  if (regRes.ok) {
920
920
  const regData = await regRes.json();
921
921
  registrationStatus = regData.status === "approved" ? "approved" : "pending";
922
+ } else {
923
+ const errData = await regRes.json().catch(() => ({ error: "Unknown error" }));
924
+ if (!options.json) {
925
+ console.log(`
926
+ \u26A0\uFE0F Marketplace registration failed: ${errData.error || regRes.status}`);
927
+ console.log(" Your agent is registered on-chain but may not appear in the marketplace yet.");
928
+ console.log(" Contact admin or try: mltl register --token <address> to re-register.");
929
+ }
922
930
  }
923
931
  } catch {
932
+ if (!options.json) {
933
+ console.log("\n\u26A0\uFE0F Could not reach marketplace API. Agent is registered on-chain.");
934
+ }
924
935
  }
925
936
  if (options.json) {
926
937
  console.log(
@@ -1021,14 +1032,18 @@ Provide an image with: --image <path>`);
1021
1032
 
1022
1033
  // src/lib/tasks.ts
1023
1034
  var API_BASE = APIS.MOLTLAUNCH;
1024
- async function createTask(agentId, clientAddress, taskDescription) {
1035
+ async function createTask(wallet2, agentId, clientAddress, taskDescription) {
1036
+ const { signature, timestamp, nonce } = await signAction(wallet2, "create", agentId);
1025
1037
  const response = await fetch(`${API_BASE}/api/tasks`, {
1026
1038
  method: "POST",
1027
1039
  headers: { "Content-Type": "application/json" },
1028
1040
  body: JSON.stringify({
1029
1041
  agentId,
1030
1042
  clientAddress,
1031
- task: taskDescription
1043
+ task: taskDescription,
1044
+ signature,
1045
+ timestamp,
1046
+ nonce
1032
1047
  })
1033
1048
  });
1034
1049
  if (!response.ok) {
@@ -1310,7 +1325,7 @@ Task: ${options.task}
1310
1325
  `);
1311
1326
  console.log("Creating task request...");
1312
1327
  }
1313
- const task = await createTask(agentId, wallet2.address, options.task);
1328
+ const task = await createTask(wallet2, agentId, wallet2.address, options.task);
1314
1329
  if (options.json) {
1315
1330
  console.log(
1316
1331
  JSON.stringify({
@@ -1318,7 +1333,14 @@ Task: ${options.task}
1318
1333
  taskId: task.id,
1319
1334
  agentId,
1320
1335
  status: task.status,
1321
- task: task.task
1336
+ task: task.task,
1337
+ nextActions: [
1338
+ { command: `mltl tasks`, description: "Check task status and quotes" },
1339
+ { command: `mltl view --task ${task.id}`, description: "View task details" },
1340
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Add details for the agent" }
1341
+ ],
1342
+ flow: "[requested] \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed",
1343
+ note: "No funds committed. The agent will quote a price. You decide whether to accept."
1322
1344
  })
1323
1345
  );
1324
1346
  return;
@@ -1330,9 +1352,12 @@ Task ID: ${task.id}`);
1330
1352
  console.log(`Agent: ${name} (#${agentId})`);
1331
1353
  console.log(`Status: ${task.status}`);
1332
1354
  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");
1333
- console.log("\nThe agent will review your request and quote a price.");
1334
- console.log("Check status with:");
1335
- console.log(` mltl tasks
1355
+ console.log("\nNo funds committed yet. The agent will review and quote a price.");
1356
+ console.log("You can accept, negotiate, or walk away at no cost.\n");
1357
+ console.log("Next steps:");
1358
+ console.log(` Check for quotes: mltl tasks`);
1359
+ console.log(` View details: mltl view --task ${task.id}`);
1360
+ console.log(` Add context: mltl message --task ${task.id} --content "..."
1336
1361
  `);
1337
1362
  } catch (err) {
1338
1363
  if (options.json) {
@@ -1794,7 +1819,11 @@ async function inbox(options) {
1794
1819
  const tasks2 = await getInbox(agentId);
1795
1820
  if (tasks2.length === 0) {
1796
1821
  if (options.json) {
1797
- console.log(JSON.stringify({ tasks: [], total: 0 }));
1822
+ console.log(JSON.stringify({
1823
+ tasks: [],
1824
+ total: 0,
1825
+ polling: { recommended: "5m", note: "No active tasks. Check less frequently." }
1826
+ }));
1798
1827
  return;
1799
1828
  }
1800
1829
  console.log("No pending tasks.\n");
@@ -1802,8 +1831,28 @@ async function inbox(options) {
1802
1831
  console.log("Run this command periodically to check for new work.\n");
1803
1832
  return;
1804
1833
  }
1834
+ const hasRevision = tasks2.some((t) => t.status === "revision");
1835
+ const hasRequested = tasks2.some((t) => t.status === "requested");
1836
+ const hasSubmitted = tasks2.some((t) => t.status === "submitted");
1837
+ let pollingInterval = "5m";
1838
+ let pollingNote = "Normal activity.";
1839
+ if (hasRevision) {
1840
+ pollingInterval = "1m";
1841
+ pollingNote = "Revision requested \u2014 client is waiting for your rework.";
1842
+ } else if (hasRequested) {
1843
+ pollingInterval = "2m";
1844
+ pollingNote = "New requests \u2014 quote promptly to win the work.";
1845
+ } else if (hasSubmitted) {
1846
+ pollingInterval = "5m";
1847
+ pollingNote = "Waiting on client review. Check back periodically.";
1848
+ }
1805
1849
  if (options.json) {
1806
- console.log(JSON.stringify({ tasks: tasks2, total: tasks2.length }));
1850
+ console.log(JSON.stringify({
1851
+ tasks: tasks2,
1852
+ total: tasks2.length,
1853
+ polling: { recommended: pollingInterval, note: pollingNote },
1854
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
1855
+ }));
1807
1856
  return;
1808
1857
  }
1809
1858
  for (const group of STATUS_GROUPS) {
@@ -2129,6 +2178,7 @@ Task ID: ${taskBefore.id}`);
2129
2178
  console.log(`Agent: #${taskBefore.agentId} (${agent.name || "Unknown"})`);
2130
2179
  console.log(`Owner: ${agentOwner}`);
2131
2180
  console.log(`Quote: ${priceEth} ETH`);
2181
+ console.log(`Balance: ${balance} ETH`);
2132
2182
  if (taskBefore.quotedMessage) {
2133
2183
  console.log(`Message: ${taskBefore.quotedMessage}`);
2134
2184
  }
@@ -2136,6 +2186,12 @@ Task ID: ${taskBefore.id}`);
2136
2186
  Task:
2137
2187
  ${taskBefore.task}
2138
2188
  `);
2189
+ 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");
2190
+ console.log(`
2191
+ This will deposit ${priceEth} ETH into escrow.`);
2192
+ console.log("Funds are locked until you approve the work or request a refund.");
2193
+ console.log(" - Approve submitted work: funds buy back & burn agent's token");
2194
+ console.log(" - Cancel before submission: 10% fee to agent, 90% refunded");
2139
2195
  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");
2140
2196
  console.log("\nDepositing funds into escrow...");
2141
2197
  }
@@ -2159,7 +2215,14 @@ ${taskBefore.task}
2159
2215
  txHash: escrowTxHash,
2160
2216
  amount: priceEth,
2161
2217
  tokenAddress: agentToken
2162
- }
2218
+ },
2219
+ nextActions: [
2220
+ { command: `mltl tasks`, description: "Check task status" },
2221
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the agent" },
2222
+ { command: `mltl cancel --task ${task.id}`, description: "Cancel (10% fee to agent)" }
2223
+ ],
2224
+ flow: "requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed",
2225
+ note: "Funds are locked in escrow. Agent can now begin work."
2163
2226
  })
2164
2227
  );
2165
2228
  return;
@@ -2169,9 +2232,12 @@ ${taskBefore.task}
2169
2232
  Escrow: ${priceEth} ETH deposited`);
2170
2233
  console.log(`Token: ${agentToken}`);
2171
2234
  console.log(`TX: ${escrowTxHash}`);
2172
- console.log("\nWhen you approve, funds will buyback & burn the agent's token.");
2173
- console.log("Check status with:");
2174
- console.log(` mltl tasks
2235
+ console.log("\nThe agent can now begin work. When they submit:");
2236
+ console.log(" - Review & approve: mltl approve --task " + task.id);
2237
+ console.log(" - Request changes: mltl revise --task " + task.id + ' --reason "..."');
2238
+ console.log(" - Cancel (10% fee): mltl cancel --task " + task.id);
2239
+ console.log(`
2240
+ Flow: requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed
2175
2241
  `);
2176
2242
  } catch (err) {
2177
2243
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2204,14 +2270,19 @@ async function decline(options) {
2204
2270
  task: {
2205
2271
  id: task.id,
2206
2272
  status: task.status
2207
- }
2273
+ },
2274
+ nextActions: [
2275
+ { command: `mltl inbox`, description: "Check for other tasks" }
2276
+ ],
2277
+ note: "Declined tasks are tracked in your stats. This is normal \u2014 only accept work you can deliver."
2208
2278
  })
2209
2279
  );
2210
2280
  return;
2211
2281
  }
2212
2282
  console.log(`
2213
2283
  \u2705 Task ${task.id} declined.`);
2214
- console.log("\nThe client will be notified.\n");
2284
+ console.log("\nThe client will be notified.");
2285
+ console.log("Tip: Declining tasks you can't deliver is better than accepting and underdelivering.\n");
2215
2286
  } catch (err) {
2216
2287
  const errorMsg = err instanceof Error ? err.message : String(err);
2217
2288
  if (options.json) {
@@ -2317,6 +2388,13 @@ Uploading ${filePaths.length} file(s)...`);
2317
2388
  }
2318
2389
  }
2319
2390
  if (options.json) {
2391
+ const nextActions = [
2392
+ { command: `mltl view --task ${task.id}`, description: "View full task thread" },
2393
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the client" }
2394
+ ];
2395
+ if (escrowTxHash) {
2396
+ nextActions.push({ command: `mltl claim --task ${task.id}`, description: "Claim payment after 24h timeout" });
2397
+ }
2320
2398
  console.log(
2321
2399
  JSON.stringify({
2322
2400
  success: true,
@@ -2327,7 +2405,10 @@ Uploading ${filePaths.length} file(s)...`);
2327
2405
  quotedPriceWei: task.quotedPriceWei,
2328
2406
  result: task.result
2329
2407
  },
2330
- escrow: escrowTxHash ? { txHash: escrowTxHash, timeoutHours: 24 } : null
2408
+ escrow: escrowTxHash ? { txHash: escrowTxHash, timeoutHours: 24 } : null,
2409
+ nextActions,
2410
+ flow: isRevision ? "requested \u2192 quoted \u2192 accepted \u2192 revision \u2192 [submitted] \u2192 completed" : "requested \u2192 quoted \u2192 accepted \u2192 [submitted] \u2192 completed",
2411
+ note: escrowTxHash ? "24h countdown started. Client must approve, revise, or dispute within 24h \u2014 otherwise you can claim payment." : "Awaiting client review."
2331
2412
  })
2332
2413
  );
2333
2414
  return;
@@ -2344,21 +2425,23 @@ Task ID: ${task.id}`);
2344
2425
  console.log(`Price: ${priceEth} ETH`);
2345
2426
  if (escrowTxHash) {
2346
2427
  console.log(`
2347
- Timeout: 24 hours (auto-release if client doesn't respond)`);
2428
+ Timeout: 24 hours from now`);
2429
+ console.log(` Client must respond or you can auto-claim payment.`);
2348
2430
  }
2349
2431
  console.log(`
2350
2432
  Your result:
2351
2433
  ${options.result}
2352
2434
  `);
2353
2435
  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");
2354
- console.log("\nThe client will review your work.");
2436
+ console.log("\nWhat happens next:");
2437
+ console.log(" - Client approves \u2192 payment released (buyback & burn)");
2438
+ console.log(" - Client revises \u2192 you'll see it in your inbox");
2355
2439
  if (escrowTxHash) {
2356
- console.log("If they don't respond within 24h, you can claim payment with:");
2357
- console.log(` mltl claim --task ${task.id}
2358
- `);
2359
- } else {
2360
- console.log("Once approved, payment will be sent to your wallet.\n");
2440
+ console.log(" - No response 24h \u2192 claim with: mltl claim --task " + task.id);
2361
2441
  }
2442
+ console.log(`
2443
+ Check status: mltl view --task ${task.id}
2444
+ `);
2362
2445
  } catch (err) {
2363
2446
  const errorMsg = err instanceof Error ? err.message : String(err);
2364
2447
  if (options.json) {
@@ -2423,6 +2506,9 @@ Task ID: ${task.id}`);
2423
2506
  Submitted result:
2424
2507
  ${task.result}
2425
2508
  `);
2509
+ 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");
2510
+ console.log("\nThis will release payment. This action is final and irreversible.");
2511
+ console.log("If unsatisfied, use 'mltl revise' or 'mltl dispute' instead.");
2426
2512
  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");
2427
2513
  console.log("\nReleasing payment from escrow...");
2428
2514
  }
@@ -2444,7 +2530,11 @@ ${task.result}
2444
2530
  amount: priceEth,
2445
2531
  txHash,
2446
2532
  type: "escrow_release"
2447
- }
2533
+ },
2534
+ nextActions: [
2535
+ { command: `mltl feedback --task ${completedTask.id} --score <0-100>`, description: "Leave a verified review (on-chain)" }
2536
+ ],
2537
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [completed]"
2448
2538
  })
2449
2539
  );
2450
2540
  return;
@@ -2454,8 +2544,9 @@ ${task.result}
2454
2544
  console.log(`
2455
2545
  Payment: ${priceEth} ETH \u2192 ${agentOwner}`);
2456
2546
  console.log(`TX: ${txHash}`);
2457
- console.log("\nDon't forget to leave feedback:");
2458
- console.log(` mltl feedback --agent ${task.agentId} --score 90
2547
+ console.log("\nLeave a verified review (score 0-100):");
2548
+ console.log(` mltl feedback --task ${completedTask.id} --score 90`);
2549
+ console.log(` mltl feedback --task ${completedTask.id} --score 85 --comment "Great work"
2459
2550
  `);
2460
2551
  } catch (err) {
2461
2552
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2486,7 +2577,14 @@ async function tasks(options) {
2486
2577
  const allTasks = await getClientTasks(wallet2.address);
2487
2578
  if (allTasks.length === 0) {
2488
2579
  if (options.json) {
2489
- console.log(JSON.stringify({ tasks: [], total: 0 }));
2580
+ console.log(JSON.stringify({
2581
+ tasks: [],
2582
+ total: 0,
2583
+ nextActions: [
2584
+ { command: `mltl agents`, description: "Browse available agents" },
2585
+ { command: `mltl hire --agent <id> --task "..."`, description: "Request work from an agent" }
2586
+ ]
2587
+ }));
2490
2588
  return;
2491
2589
  }
2492
2590
  console.log("No tasks yet.\n");
@@ -2494,8 +2592,24 @@ async function tasks(options) {
2494
2592
  console.log(' mltl hire --agent <id> --task "Your task description"\n');
2495
2593
  return;
2496
2594
  }
2595
+ const hasSubmittedReview = allTasks.some((t) => t.status === "submitted");
2596
+ const hasQuoted = allTasks.some((t) => t.status === "quoted");
2597
+ let pollingInterval = "5m";
2598
+ let pollingNote = "Normal activity.";
2599
+ if (hasSubmittedReview) {
2600
+ pollingInterval = "1m";
2601
+ pollingNote = "Work submitted \u2014 review and approve/revise promptly so agent can get paid.";
2602
+ } else if (hasQuoted) {
2603
+ pollingInterval = "2m";
2604
+ pollingNote = "Quote received \u2014 accept to lock escrow and start work.";
2605
+ }
2497
2606
  if (options.json) {
2498
- console.log(JSON.stringify({ tasks: allTasks, total: allTasks.length }));
2607
+ console.log(JSON.stringify({
2608
+ tasks: allTasks,
2609
+ total: allTasks.length,
2610
+ polling: { recommended: pollingInterval, note: pollingNote },
2611
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
2612
+ }));
2499
2613
  return;
2500
2614
  }
2501
2615
  const needsReview = allTasks.filter((t) => t.status === "submitted");
@@ -2683,6 +2797,11 @@ ${taskBefore.task}
2683
2797
  console.log(`Message: ${options.message}`);
2684
2798
  }
2685
2799
  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");
2800
+ if (taskBefore.status === "quoted") {
2801
+ console.log("\nNote: Updating your previous quote. Client has not yet accepted.");
2802
+ }
2803
+ console.log("\nBy quoting, you commit to delivering this work at this price.");
2804
+ console.log("The client can accept at any time, locking funds in escrow.");
2686
2805
  }
2687
2806
  const task = await quoteTask(wallet2, options.task, priceWei.toString(), options.message);
2688
2807
  if (options.json) {
@@ -2695,17 +2814,24 @@ ${taskBefore.task}
2695
2814
  status: task.status,
2696
2815
  quotedPriceWei: task.quotedPriceWei,
2697
2816
  quotedMessage: task.quotedMessage
2698
- }
2817
+ },
2818
+ nextActions: [
2819
+ { command: `mltl inbox`, description: "Check inbox for status updates" },
2820
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the client" }
2821
+ ],
2822
+ flow: "requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed"
2699
2823
  })
2700
2824
  );
2701
2825
  return;
2702
2826
  }
2703
2827
  console.log("\n\u2705 Quote submitted!");
2704
2828
  console.log("\nThe client will review your quote.");
2705
- console.log("If they accept, the task will move to 'accepted' status");
2706
- console.log("and you can begin work.\n");
2707
- console.log("Check status with:");
2708
- console.log(` mltl inbox --agent ${task.agentId}
2829
+ console.log("If they accept, funds lock in escrow and you can begin work.\n");
2830
+ console.log("Next steps:");
2831
+ console.log(` Check inbox: mltl inbox`);
2832
+ console.log(` Send a message: mltl message --task ${task.id} --content "..."`);
2833
+ console.log(`
2834
+ Flow: requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed
2709
2835
  `);
2710
2836
  } catch (err) {
2711
2837
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2861,12 +2987,17 @@ Task ID: ${task.id}`);
2861
2987
  success: true,
2862
2988
  taskId: task.id,
2863
2989
  refundedAmount: formatEther10(escrow.amount),
2864
- txHash
2990
+ txHash,
2991
+ nextActions: [
2992
+ { command: `mltl hire --agent ${task.agentId} --task "..."`, description: "Hire the same agent again" },
2993
+ { command: `mltl agents`, description: "Browse other agents" }
2994
+ ],
2995
+ note: "Full refund \u2014 no fees deducted. Task is closed."
2865
2996
  })
2866
2997
  );
2867
2998
  return;
2868
2999
  }
2869
- console.log("\n\u2705 Refund successful!");
3000
+ console.log("\n\u2705 Refund successful! No fees deducted.");
2870
3001
  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");
2871
3002
  console.log(`
2872
3003
  Refunded: ${formatEther10(escrow.amount)} ETH \u2192 ${wallet2.address}`);
@@ -2912,9 +3043,11 @@ async function cancel(options) {
2912
3043
  console.log(`
2913
3044
  Task ID: ${task.id}`);
2914
3045
  console.log(`Escrowed: ${formatEther11(escrow.amount)} ETH`);
2915
- console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent)`);
3046
+ console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent for lost opportunity)`);
2916
3047
  console.log(`You receive: ${formatEther11(escrow.amount - fee)} ETH`);
2917
- console.log("\nCancelling...");
3048
+ console.log("\nNote: If the agent hasn't started yet, consider 'mltl refund' instead (no fee).");
3049
+ console.log("Cancel is for tasks already accepted by the agent.\n");
3050
+ console.log("Cancelling...");
2918
3051
  }
2919
3052
  const txHash = await cancelEscrow(wallet2, task.id);
2920
3053
  try {
@@ -2928,7 +3061,11 @@ Task ID: ${task.id}`);
2928
3061
  taskId: task.id,
2929
3062
  cancelFee: formatEther11(fee),
2930
3063
  refundedAmount: formatEther11(escrow.amount - fee),
2931
- txHash
3064
+ txHash,
3065
+ nextActions: [
3066
+ { command: `mltl hire --agent ${task.agentId} --task "..."`, description: "Hire the same agent again" },
3067
+ { command: `mltl agents`, description: "Browse other agents" }
3068
+ ]
2932
3069
  })
2933
3070
  );
2934
3071
  return;
@@ -2981,7 +3118,12 @@ async function dispute(options) {
2981
3118
  console.log(`
2982
3119
  Task ID: ${task.id}`);
2983
3120
  console.log(`Escrow: ${formatEther12(escrow.amount)} ETH`);
2984
- console.log(`Dispute fee: ${feeEth} ETH (10% of escrow)`);
3121
+ console.log(`Dispute fee: ${feeEth} ETH (10% of escrow, non-refundable if you lose)`);
3122
+ console.log("\n\u26A0 Disputes are a last resort. Consider these alternatives first:");
3123
+ console.log(` Request revision: mltl revise --task ${task.id} --reason "..."`);
3124
+ console.log(` Message the agent: mltl message --task ${task.id} --content "..."`);
3125
+ console.log("\n If you win: escrow refunded + dispute fee returned.");
3126
+ console.log(" If you lose: agent gets paid, you lose the dispute fee.");
2985
3127
  console.log("\nOpening dispute...");
2986
3128
  }
2987
3129
  const txHash = await disputeEscrow(wallet2, task.id, feeWei);
@@ -2997,18 +3139,25 @@ Task ID: ${task.id}`);
2997
3139
  success: true,
2998
3140
  taskId: task.id,
2999
3141
  disputeFee: feeEth,
3000
- txHash
3142
+ txHash,
3143
+ note: "Timeout frozen. Admin will review. If you win: escrow + fee returned. If you lose: agent gets paid, fee lost.",
3144
+ nextActions: [
3145
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Add context for the admin" },
3146
+ { command: `mltl view --task ${task.id}`, description: "View task details" }
3147
+ ]
3001
3148
  })
3002
3149
  );
3003
3150
  return;
3004
3151
  }
3005
- console.log("\nDispute opened! Timeout is now frozen.");
3152
+ console.log("\nDispute opened! 24h timeout is now frozen.");
3006
3153
  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");
3007
3154
  console.log(`
3008
3155
  Fee paid: ${feeEth} ETH`);
3009
3156
  console.log(`TX: ${txHash}`);
3010
3157
  console.log("\nAn admin will review and resolve the dispute.");
3011
- console.log("If you win, you get your escrow + fee back.\n");
3158
+ console.log("Add context via messages to help resolution:");
3159
+ console.log(` mltl message --task ${task.id} --content "..."
3160
+ `);
3012
3161
  } catch (err) {
3013
3162
  const errorMsg = err instanceof Error ? err.message : String(err);
3014
3163
  if (options.json) {
@@ -3123,7 +3272,13 @@ async function revise(options) {
3123
3272
  agentId: task.agentId,
3124
3273
  status: task.status,
3125
3274
  revisionCount: task.revisionCount
3126
- }
3275
+ },
3276
+ nextActions: [
3277
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Add more context for the agent" },
3278
+ { command: `mltl view --task ${task.id}`, description: "View task thread" }
3279
+ ],
3280
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [revision] \u2192 submitted \u2192 completed",
3281
+ note: "Agent will rework and resubmit. No additional cost \u2014 same escrow applies."
3127
3282
  })
3128
3283
  );
3129
3284
  return;
@@ -3139,8 +3294,8 @@ Your feedback:
3139
3294
  ${options.reason}
3140
3295
  `);
3141
3296
  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");
3142
- console.log("\nThe agent will revise and resubmit their work.");
3143
- console.log("You can also send messages with:");
3297
+ console.log("\nThe agent will revise and resubmit. No additional cost.");
3298
+ console.log("Add more context:");
3144
3299
  console.log(` mltl message --task ${task.id} --content "additional details"
3145
3300
  `);
3146
3301
  } catch (err) {
@@ -3241,27 +3396,86 @@ import { formatEther as formatEther14 } from "viem";
3241
3396
  function formatTimestamp4(ts) {
3242
3397
  return new Date(ts).toLocaleString();
3243
3398
  }
3244
- function suggestedAction(task) {
3399
+ function suggestedActions(task, role) {
3400
+ const id = task.id;
3245
3401
  switch (task.status) {
3246
3402
  case "requested":
3247
- return `Quote: mltl quote --task ${task.id} --price <eth>
3248
- Decline: mltl decline --task ${task.id}`;
3403
+ if (role === "agent") return `Quote: mltl quote --task ${id} --price <eth>
3404
+ Decline: mltl decline --task ${id}`;
3405
+ if (role === "client") return `Waiting for agent to quote. You can add context:
3406
+ mltl message --task ${id} --content "..."`;
3407
+ return `Agent: mltl quote --task ${id} --price <eth>
3408
+ Agent: mltl decline --task ${id}`;
3249
3409
  case "quoted":
3250
- return `Message: mltl message --task ${task.id} --content "..."`;
3410
+ if (role === "client") return `Accept: mltl accept --task ${id} (deposits ETH into escrow)
3411
+ Message: mltl message --task ${id} --content "..."`;
3412
+ if (role === "agent") return `Waiting for client to accept your quote.
3413
+ Message: mltl message --task ${id} --content "..."`;
3414
+ return `Client: mltl accept --task ${id}
3415
+ Either: mltl message --task ${id} --content "..."`;
3251
3416
  case "accepted":
3417
+ if (role === "agent") return `Submit work when ready:
3418
+ mltl submit --task ${id} --result "..." --files file1.txt,file2.pdf`;
3419
+ if (role === "client") return `Agent is working. You can:
3420
+ Message: mltl message --task ${id} --content "..."
3421
+ Cancel: mltl cancel --task ${id} (10% fee to agent)`;
3422
+ return `Agent: mltl submit --task ${id} --result "..."`;
3252
3423
  case "revision":
3253
- return `Submit: mltl submit --task ${task.id} --result "..."`;
3424
+ if (role === "agent") return `Revision requested. Fix and resubmit:
3425
+ mltl submit --task ${id} --result "..." --files file1.txt`;
3426
+ if (role === "client") return `Waiting for agent to resubmit.
3427
+ Message: mltl message --task ${id} --content "..."`;
3428
+ return `Agent: mltl submit --task ${id} --result "..."`;
3254
3429
  case "submitted":
3255
- return `Message: mltl message --task ${task.id} --content "..."`;
3430
+ if (role === "client") return `Review the result above, then:
3431
+ Approve: mltl approve --task ${id} (releases payment, final)
3432
+ Revise: mltl revise --task ${id} --reason "..."
3433
+ Dispute: mltl dispute --task ${id} (10% fee, last resort)`;
3434
+ if (role === "agent") return `Waiting for client review. 24h timeout protects you.
3435
+ Claim: mltl claim --task ${id} (after 24h with no response)`;
3436
+ return `Client: mltl approve --task ${id}
3437
+ Client: mltl revise --task ${id} --reason "..."`;
3438
+ case "completed":
3439
+ if (role === "client") return `Leave a review:
3440
+ mltl feedback --task ${id} --score <0-100> --comment "..."`;
3441
+ return null;
3442
+ case "disputed":
3443
+ return `Awaiting admin resolution.
3444
+ Add context: mltl message --task ${id} --content "..."`;
3256
3445
  default:
3257
3446
  return null;
3258
3447
  }
3259
3448
  }
3449
+ var STATUS_FLOW = {
3450
+ requested: "[requested] \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed",
3451
+ quoted: "requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed",
3452
+ accepted: "requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed",
3453
+ revision: "requested \u2192 quoted \u2192 accepted \u2192 [revision] \u2192 submitted \u2192 completed",
3454
+ submitted: "requested \u2192 quoted \u2192 accepted \u2192 [submitted] \u2192 completed",
3455
+ completed: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [completed]",
3456
+ declined: "requested \u2192 [declined]",
3457
+ disputed: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [disputed] \u2192 resolved",
3458
+ resolved: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 disputed \u2192 [resolved]"
3459
+ };
3260
3460
  async function view(options) {
3261
3461
  try {
3262
3462
  const task = await getTask(options.task);
3463
+ let role = "unknown";
3464
+ try {
3465
+ const wallet2 = await loadWallet();
3466
+ if (wallet2) {
3467
+ const addr = wallet2.address.toLowerCase();
3468
+ if (task.clientAddress.toLowerCase() === addr) {
3469
+ role = "client";
3470
+ } else {
3471
+ role = "agent";
3472
+ }
3473
+ }
3474
+ } catch {
3475
+ }
3263
3476
  if (options.json) {
3264
- console.log(JSON.stringify({ task }));
3477
+ const flow2 = STATUS_FLOW[task.status] || null;
3478
+ console.log(JSON.stringify({ task, role, flow: flow2 }));
3265
3479
  return;
3266
3480
  }
3267
3481
  const priceEth = task.quotedPriceWei ? formatEther14(BigInt(task.quotedPriceWei)) : null;
@@ -3313,10 +3527,18 @@ async function view(options) {
3313
3527
  `);
3314
3528
  }
3315
3529
  }
3316
- const action = suggestedAction(task);
3317
- if (action) {
3530
+ const flow = STATUS_FLOW[task.status];
3531
+ if (flow) {
3318
3532
  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");
3319
- console.log(" Next Action");
3533
+ console.log(" Flow");
3534
+ 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");
3535
+ console.log(flow);
3536
+ }
3537
+ const action = suggestedActions(task, role);
3538
+ if (action) {
3539
+ const roleLabel = role === "client" ? " (you are the client)" : role === "agent" ? " (you are the agent)" : "";
3540
+ console.log("\n\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");
3541
+ console.log(` Next Action${roleLabel}`);
3320
3542
  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");
3321
3543
  console.log(action);
3322
3544
  }