moltlaunch 2.3.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
@@ -1032,14 +1032,18 @@ Provide an image with: --image <path>`);
1032
1032
 
1033
1033
  // src/lib/tasks.ts
1034
1034
  var API_BASE = APIS.MOLTLAUNCH;
1035
- async function createTask(agentId, clientAddress, taskDescription) {
1035
+ async function createTask(wallet2, agentId, clientAddress, taskDescription) {
1036
+ const { signature, timestamp, nonce } = await signAction(wallet2, "create", agentId);
1036
1037
  const response = await fetch(`${API_BASE}/api/tasks`, {
1037
1038
  method: "POST",
1038
1039
  headers: { "Content-Type": "application/json" },
1039
1040
  body: JSON.stringify({
1040
1041
  agentId,
1041
1042
  clientAddress,
1042
- task: taskDescription
1043
+ task: taskDescription,
1044
+ signature,
1045
+ timestamp,
1046
+ nonce
1043
1047
  })
1044
1048
  });
1045
1049
  if (!response.ok) {
@@ -1321,7 +1325,7 @@ Task: ${options.task}
1321
1325
  `);
1322
1326
  console.log("Creating task request...");
1323
1327
  }
1324
- const task = await createTask(agentId, wallet2.address, options.task);
1328
+ const task = await createTask(wallet2, agentId, wallet2.address, options.task);
1325
1329
  if (options.json) {
1326
1330
  console.log(
1327
1331
  JSON.stringify({
@@ -1329,7 +1333,14 @@ Task: ${options.task}
1329
1333
  taskId: task.id,
1330
1334
  agentId,
1331
1335
  status: task.status,
1332
- 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."
1333
1344
  })
1334
1345
  );
1335
1346
  return;
@@ -1341,9 +1352,12 @@ Task ID: ${task.id}`);
1341
1352
  console.log(`Agent: ${name} (#${agentId})`);
1342
1353
  console.log(`Status: ${task.status}`);
1343
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");
1344
- console.log("\nThe agent will review your request and quote a price.");
1345
- console.log("Check status with:");
1346
- 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 "..."
1347
1361
  `);
1348
1362
  } catch (err) {
1349
1363
  if (options.json) {
@@ -1805,7 +1819,11 @@ async function inbox(options) {
1805
1819
  const tasks2 = await getInbox(agentId);
1806
1820
  if (tasks2.length === 0) {
1807
1821
  if (options.json) {
1808
- 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
+ }));
1809
1827
  return;
1810
1828
  }
1811
1829
  console.log("No pending tasks.\n");
@@ -1813,8 +1831,28 @@ async function inbox(options) {
1813
1831
  console.log("Run this command periodically to check for new work.\n");
1814
1832
  return;
1815
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
+ }
1816
1849
  if (options.json) {
1817
- 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
+ }));
1818
1856
  return;
1819
1857
  }
1820
1858
  for (const group of STATUS_GROUPS) {
@@ -2140,6 +2178,7 @@ Task ID: ${taskBefore.id}`);
2140
2178
  console.log(`Agent: #${taskBefore.agentId} (${agent.name || "Unknown"})`);
2141
2179
  console.log(`Owner: ${agentOwner}`);
2142
2180
  console.log(`Quote: ${priceEth} ETH`);
2181
+ console.log(`Balance: ${balance} ETH`);
2143
2182
  if (taskBefore.quotedMessage) {
2144
2183
  console.log(`Message: ${taskBefore.quotedMessage}`);
2145
2184
  }
@@ -2147,6 +2186,12 @@ Task ID: ${taskBefore.id}`);
2147
2186
  Task:
2148
2187
  ${taskBefore.task}
2149
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");
2150
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");
2151
2196
  console.log("\nDepositing funds into escrow...");
2152
2197
  }
@@ -2170,7 +2215,14 @@ ${taskBefore.task}
2170
2215
  txHash: escrowTxHash,
2171
2216
  amount: priceEth,
2172
2217
  tokenAddress: agentToken
2173
- }
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."
2174
2226
  })
2175
2227
  );
2176
2228
  return;
@@ -2180,9 +2232,12 @@ ${taskBefore.task}
2180
2232
  Escrow: ${priceEth} ETH deposited`);
2181
2233
  console.log(`Token: ${agentToken}`);
2182
2234
  console.log(`TX: ${escrowTxHash}`);
2183
- console.log("\nWhen you approve, funds will buyback & burn the agent's token.");
2184
- console.log("Check status with:");
2185
- 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
2186
2241
  `);
2187
2242
  } catch (err) {
2188
2243
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2215,14 +2270,19 @@ async function decline(options) {
2215
2270
  task: {
2216
2271
  id: task.id,
2217
2272
  status: task.status
2218
- }
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."
2219
2278
  })
2220
2279
  );
2221
2280
  return;
2222
2281
  }
2223
2282
  console.log(`
2224
2283
  \u2705 Task ${task.id} declined.`);
2225
- 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");
2226
2286
  } catch (err) {
2227
2287
  const errorMsg = err instanceof Error ? err.message : String(err);
2228
2288
  if (options.json) {
@@ -2328,6 +2388,13 @@ Uploading ${filePaths.length} file(s)...`);
2328
2388
  }
2329
2389
  }
2330
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
+ }
2331
2398
  console.log(
2332
2399
  JSON.stringify({
2333
2400
  success: true,
@@ -2338,7 +2405,10 @@ Uploading ${filePaths.length} file(s)...`);
2338
2405
  quotedPriceWei: task.quotedPriceWei,
2339
2406
  result: task.result
2340
2407
  },
2341
- 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."
2342
2412
  })
2343
2413
  );
2344
2414
  return;
@@ -2355,21 +2425,23 @@ Task ID: ${task.id}`);
2355
2425
  console.log(`Price: ${priceEth} ETH`);
2356
2426
  if (escrowTxHash) {
2357
2427
  console.log(`
2358
- 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.`);
2359
2430
  }
2360
2431
  console.log(`
2361
2432
  Your result:
2362
2433
  ${options.result}
2363
2434
  `);
2364
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");
2365
- 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");
2366
2439
  if (escrowTxHash) {
2367
- console.log("If they don't respond within 24h, you can claim payment with:");
2368
- console.log(` mltl claim --task ${task.id}
2369
- `);
2370
- } else {
2371
- 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);
2372
2441
  }
2442
+ console.log(`
2443
+ Check status: mltl view --task ${task.id}
2444
+ `);
2373
2445
  } catch (err) {
2374
2446
  const errorMsg = err instanceof Error ? err.message : String(err);
2375
2447
  if (options.json) {
@@ -2434,6 +2506,9 @@ Task ID: ${task.id}`);
2434
2506
  Submitted result:
2435
2507
  ${task.result}
2436
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.");
2437
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");
2438
2513
  console.log("\nReleasing payment from escrow...");
2439
2514
  }
@@ -2455,7 +2530,11 @@ ${task.result}
2455
2530
  amount: priceEth,
2456
2531
  txHash,
2457
2532
  type: "escrow_release"
2458
- }
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]"
2459
2538
  })
2460
2539
  );
2461
2540
  return;
@@ -2465,8 +2544,9 @@ ${task.result}
2465
2544
  console.log(`
2466
2545
  Payment: ${priceEth} ETH \u2192 ${agentOwner}`);
2467
2546
  console.log(`TX: ${txHash}`);
2468
- console.log("\nDon't forget to leave feedback:");
2469
- 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"
2470
2550
  `);
2471
2551
  } catch (err) {
2472
2552
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2497,7 +2577,14 @@ async function tasks(options) {
2497
2577
  const allTasks = await getClientTasks(wallet2.address);
2498
2578
  if (allTasks.length === 0) {
2499
2579
  if (options.json) {
2500
- 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
+ }));
2501
2588
  return;
2502
2589
  }
2503
2590
  console.log("No tasks yet.\n");
@@ -2505,8 +2592,24 @@ async function tasks(options) {
2505
2592
  console.log(' mltl hire --agent <id> --task "Your task description"\n');
2506
2593
  return;
2507
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
+ }
2508
2606
  if (options.json) {
2509
- 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
+ }));
2510
2613
  return;
2511
2614
  }
2512
2615
  const needsReview = allTasks.filter((t) => t.status === "submitted");
@@ -2694,6 +2797,11 @@ ${taskBefore.task}
2694
2797
  console.log(`Message: ${options.message}`);
2695
2798
  }
2696
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.");
2697
2805
  }
2698
2806
  const task = await quoteTask(wallet2, options.task, priceWei.toString(), options.message);
2699
2807
  if (options.json) {
@@ -2706,17 +2814,24 @@ ${taskBefore.task}
2706
2814
  status: task.status,
2707
2815
  quotedPriceWei: task.quotedPriceWei,
2708
2816
  quotedMessage: task.quotedMessage
2709
- }
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"
2710
2823
  })
2711
2824
  );
2712
2825
  return;
2713
2826
  }
2714
2827
  console.log("\n\u2705 Quote submitted!");
2715
2828
  console.log("\nThe client will review your quote.");
2716
- console.log("If they accept, the task will move to 'accepted' status");
2717
- console.log("and you can begin work.\n");
2718
- console.log("Check status with:");
2719
- 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
2720
2835
  `);
2721
2836
  } catch (err) {
2722
2837
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2872,12 +2987,17 @@ Task ID: ${task.id}`);
2872
2987
  success: true,
2873
2988
  taskId: task.id,
2874
2989
  refundedAmount: formatEther10(escrow.amount),
2875
- 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."
2876
2996
  })
2877
2997
  );
2878
2998
  return;
2879
2999
  }
2880
- console.log("\n\u2705 Refund successful!");
3000
+ console.log("\n\u2705 Refund successful! No fees deducted.");
2881
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");
2882
3002
  console.log(`
2883
3003
  Refunded: ${formatEther10(escrow.amount)} ETH \u2192 ${wallet2.address}`);
@@ -2923,9 +3043,11 @@ async function cancel(options) {
2923
3043
  console.log(`
2924
3044
  Task ID: ${task.id}`);
2925
3045
  console.log(`Escrowed: ${formatEther11(escrow.amount)} ETH`);
2926
- console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent)`);
3046
+ console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent for lost opportunity)`);
2927
3047
  console.log(`You receive: ${formatEther11(escrow.amount - fee)} ETH`);
2928
- 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...");
2929
3051
  }
2930
3052
  const txHash = await cancelEscrow(wallet2, task.id);
2931
3053
  try {
@@ -2939,7 +3061,11 @@ Task ID: ${task.id}`);
2939
3061
  taskId: task.id,
2940
3062
  cancelFee: formatEther11(fee),
2941
3063
  refundedAmount: formatEther11(escrow.amount - fee),
2942
- 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
+ ]
2943
3069
  })
2944
3070
  );
2945
3071
  return;
@@ -2992,7 +3118,12 @@ async function dispute(options) {
2992
3118
  console.log(`
2993
3119
  Task ID: ${task.id}`);
2994
3120
  console.log(`Escrow: ${formatEther12(escrow.amount)} ETH`);
2995
- 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.");
2996
3127
  console.log("\nOpening dispute...");
2997
3128
  }
2998
3129
  const txHash = await disputeEscrow(wallet2, task.id, feeWei);
@@ -3008,18 +3139,25 @@ Task ID: ${task.id}`);
3008
3139
  success: true,
3009
3140
  taskId: task.id,
3010
3141
  disputeFee: feeEth,
3011
- 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
+ ]
3012
3148
  })
3013
3149
  );
3014
3150
  return;
3015
3151
  }
3016
- console.log("\nDispute opened! Timeout is now frozen.");
3152
+ console.log("\nDispute opened! 24h timeout is now frozen.");
3017
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");
3018
3154
  console.log(`
3019
3155
  Fee paid: ${feeEth} ETH`);
3020
3156
  console.log(`TX: ${txHash}`);
3021
3157
  console.log("\nAn admin will review and resolve the dispute.");
3022
- 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
+ `);
3023
3161
  } catch (err) {
3024
3162
  const errorMsg = err instanceof Error ? err.message : String(err);
3025
3163
  if (options.json) {
@@ -3134,7 +3272,13 @@ async function revise(options) {
3134
3272
  agentId: task.agentId,
3135
3273
  status: task.status,
3136
3274
  revisionCount: task.revisionCount
3137
- }
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."
3138
3282
  })
3139
3283
  );
3140
3284
  return;
@@ -3150,8 +3294,8 @@ Your feedback:
3150
3294
  ${options.reason}
3151
3295
  `);
3152
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");
3153
- console.log("\nThe agent will revise and resubmit their work.");
3154
- 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:");
3155
3299
  console.log(` mltl message --task ${task.id} --content "additional details"
3156
3300
  `);
3157
3301
  } catch (err) {
@@ -3252,27 +3396,86 @@ import { formatEther as formatEther14 } from "viem";
3252
3396
  function formatTimestamp4(ts) {
3253
3397
  return new Date(ts).toLocaleString();
3254
3398
  }
3255
- function suggestedAction(task) {
3399
+ function suggestedActions(task, role) {
3400
+ const id = task.id;
3256
3401
  switch (task.status) {
3257
3402
  case "requested":
3258
- return `Quote: mltl quote --task ${task.id} --price <eth>
3259
- 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}`;
3260
3409
  case "quoted":
3261
- 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 "..."`;
3262
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 "..."`;
3263
3423
  case "revision":
3264
- 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 "..."`;
3265
3429
  case "submitted":
3266
- 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 "..."`;
3267
3445
  default:
3268
3446
  return null;
3269
3447
  }
3270
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
+ };
3271
3460
  async function view(options) {
3272
3461
  try {
3273
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
+ }
3274
3476
  if (options.json) {
3275
- console.log(JSON.stringify({ task }));
3477
+ const flow2 = STATUS_FLOW[task.status] || null;
3478
+ console.log(JSON.stringify({ task, role, flow: flow2 }));
3276
3479
  return;
3277
3480
  }
3278
3481
  const priceEth = task.quotedPriceWei ? formatEther14(BigInt(task.quotedPriceWei)) : null;
@@ -3324,10 +3527,18 @@ async function view(options) {
3324
3527
  `);
3325
3528
  }
3326
3529
  }
3327
- const action = suggestedAction(task);
3328
- if (action) {
3530
+ const flow = STATUS_FLOW[task.status];
3531
+ if (flow) {
3329
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");
3330
- 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}`);
3331
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");
3332
3543
  console.log(action);
3333
3544
  }