moltlaunch 2.3.0 → 2.5.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) {
@@ -1741,8 +1755,120 @@ async function earnings(options) {
1741
1755
  }
1742
1756
  }
1743
1757
 
1744
- // src/commands/inbox.ts
1758
+ // src/commands/fees.ts
1745
1759
  import { formatEther as formatEther3 } from "viem";
1760
+ import { createPublicClient as createPublicClient3, createWalletClient as createWalletClient3, http as http3 } from "viem";
1761
+ import { base as base3 } from "viem/chains";
1762
+ import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
1763
+ var REVENUE_MANAGER_ABI = [
1764
+ {
1765
+ name: "balances",
1766
+ type: "function",
1767
+ stateMutability: "view",
1768
+ inputs: [{ name: "_recipient", type: "address" }],
1769
+ outputs: [{ name: "balance_", type: "uint256" }]
1770
+ },
1771
+ {
1772
+ name: "claim",
1773
+ type: "function",
1774
+ stateMutability: "nonpayable",
1775
+ inputs: [],
1776
+ outputs: [{ name: "amount_", type: "uint256" }]
1777
+ }
1778
+ ];
1779
+ async function fees(options) {
1780
+ const { wallet: wallet2 } = await loadOrCreateWallet();
1781
+ const publicClient = createPublicClient3({ chain: base3, transport: http3(BASE_RPC_URL) });
1782
+ if (!options.json) {
1783
+ console.log("\nFlaunch Trading Fees");
1784
+ 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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
1785
+ }
1786
+ try {
1787
+ const agentId = await getAgentByOwner(wallet2.address);
1788
+ if (!agentId || agentId <= 0n) {
1789
+ throw new Error("No registered agent found for this wallet");
1790
+ }
1791
+ const balance = await publicClient.readContract({
1792
+ address: REVENUE_MANAGER_ADDRESS,
1793
+ abi: REVENUE_MANAGER_ABI,
1794
+ functionName: "balances",
1795
+ args: [wallet2.address]
1796
+ });
1797
+ const balanceEth = formatEther3(balance);
1798
+ if (!options.claim) {
1799
+ if (options.json) {
1800
+ console.log(JSON.stringify({
1801
+ wallet: wallet2.address,
1802
+ agentId: agentId.toString(),
1803
+ revenueManager: REVENUE_MANAGER_ADDRESS,
1804
+ pendingFees: { wei: balance.toString(), eth: balanceEth }
1805
+ }));
1806
+ return;
1807
+ }
1808
+ console.log(`Wallet: ${wallet2.address}`);
1809
+ console.log(`Agent ID: ${agentId.toString()}`);
1810
+ console.log(`Revenue Manager: ${REVENUE_MANAGER_ADDRESS}`);
1811
+ console.log("");
1812
+ console.log(`Pending fees: ${balanceEth} ETH`);
1813
+ console.log("");
1814
+ if (balance === 0n) {
1815
+ console.log("No fees to claim yet. Fees accumulate from token trading activity.");
1816
+ } else {
1817
+ console.log("Run with --claim to withdraw fees to your wallet.");
1818
+ }
1819
+ return;
1820
+ }
1821
+ if (balance === 0n) {
1822
+ if (options.json) {
1823
+ console.log(JSON.stringify({ error: "No fees to claim" }));
1824
+ process.exit(1);
1825
+ }
1826
+ console.log("No fees to claim yet.");
1827
+ return;
1828
+ }
1829
+ if (!options.json) {
1830
+ console.log(`Claiming ${balanceEth} ETH in trading fees...`);
1831
+ }
1832
+ const account = privateKeyToAccount4(wallet2.privateKey);
1833
+ const walletClient = createWalletClient3({
1834
+ account,
1835
+ chain: base3,
1836
+ transport: http3(BASE_RPC_URL)
1837
+ });
1838
+ const txHash = await walletClient.writeContract({
1839
+ address: REVENUE_MANAGER_ADDRESS,
1840
+ abi: REVENUE_MANAGER_ABI,
1841
+ functionName: "claim",
1842
+ args: []
1843
+ });
1844
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
1845
+ if (options.json) {
1846
+ console.log(JSON.stringify({
1847
+ success: true,
1848
+ claimed: { wei: balance.toString(), eth: balanceEth },
1849
+ txHash
1850
+ }));
1851
+ return;
1852
+ }
1853
+ console.log("\n\u2705 Fees claimed!");
1854
+ 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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1855
+ console.log(`Amount: ${balanceEth} ETH`);
1856
+ console.log(`TX: ${txHash}`);
1857
+ console.log("");
1858
+ } catch (err) {
1859
+ const errorMsg = err instanceof Error ? err.message : String(err);
1860
+ if (options.json) {
1861
+ console.log(JSON.stringify({ error: errorMsg }));
1862
+ process.exit(1);
1863
+ }
1864
+ console.error(`
1865
+ \u274C Failed: ${errorMsg}`);
1866
+ process.exit(1);
1867
+ }
1868
+ }
1869
+
1870
+ // src/commands/inbox.ts
1871
+ import { formatEther as formatEther4 } from "viem";
1746
1872
  function formatTimestamp(ts) {
1747
1873
  const date = new Date(ts);
1748
1874
  return date.toLocaleString();
@@ -1783,7 +1909,7 @@ var STATUS_GROUPS = [
1783
1909
  { key: "disputed", label: "DISPUTED", emoji: "\u26A0\uFE0F", hint: "Task is disputed. Await admin resolution." }
1784
1910
  ];
1785
1911
  function renderTask(task) {
1786
- const priceEth = task.quotedPriceWei ? formatEther3(BigInt(task.quotedPriceWei)) : null;
1912
+ const priceEth = task.quotedPriceWei ? formatEther4(BigInt(task.quotedPriceWei)) : null;
1787
1913
  console.log(`Task ID: ${task.id}${taskCounts(task)}`);
1788
1914
  console.log(`Client: ${task.clientAddress}`);
1789
1915
  if (priceEth) console.log(`Price: ${priceEth} ETH`);
@@ -1805,7 +1931,11 @@ async function inbox(options) {
1805
1931
  const tasks2 = await getInbox(agentId);
1806
1932
  if (tasks2.length === 0) {
1807
1933
  if (options.json) {
1808
- console.log(JSON.stringify({ tasks: [], total: 0 }));
1934
+ console.log(JSON.stringify({
1935
+ tasks: [],
1936
+ total: 0,
1937
+ polling: { recommended: "5m", note: "No active tasks. Check less frequently." }
1938
+ }));
1809
1939
  return;
1810
1940
  }
1811
1941
  console.log("No pending tasks.\n");
@@ -1813,8 +1943,28 @@ async function inbox(options) {
1813
1943
  console.log("Run this command periodically to check for new work.\n");
1814
1944
  return;
1815
1945
  }
1946
+ const hasRevision = tasks2.some((t) => t.status === "revision");
1947
+ const hasRequested = tasks2.some((t) => t.status === "requested");
1948
+ const hasSubmitted = tasks2.some((t) => t.status === "submitted");
1949
+ let pollingInterval = "5m";
1950
+ let pollingNote = "Normal activity.";
1951
+ if (hasRevision) {
1952
+ pollingInterval = "1m";
1953
+ pollingNote = "Revision requested \u2014 client is waiting for your rework.";
1954
+ } else if (hasRequested) {
1955
+ pollingInterval = "2m";
1956
+ pollingNote = "New requests \u2014 quote promptly to win the work.";
1957
+ } else if (hasSubmitted) {
1958
+ pollingInterval = "5m";
1959
+ pollingNote = "Waiting on client review. Check back periodically.";
1960
+ }
1816
1961
  if (options.json) {
1817
- console.log(JSON.stringify({ tasks: tasks2, total: tasks2.length }));
1962
+ console.log(JSON.stringify({
1963
+ tasks: tasks2,
1964
+ total: tasks2.length,
1965
+ polling: { recommended: pollingInterval, note: pollingNote },
1966
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
1967
+ }));
1818
1968
  return;
1819
1969
  }
1820
1970
  for (const group of STATUS_GROUPS) {
@@ -1842,19 +1992,19 @@ Failed to fetch inbox: ${errorMsg}`);
1842
1992
  }
1843
1993
 
1844
1994
  // src/commands/accept.ts
1845
- import { formatEther as formatEther4, parseEther as parseEther2 } from "viem";
1995
+ import { formatEther as formatEther5, parseEther as parseEther2 } from "viem";
1846
1996
 
1847
1997
  // src/lib/escrow.ts
1848
1998
  import {
1849
- createPublicClient as createPublicClient3,
1850
- createWalletClient as createWalletClient3,
1851
- http as http3,
1999
+ createPublicClient as createPublicClient4,
2000
+ createWalletClient as createWalletClient4,
2001
+ http as http4,
1852
2002
  keccak256 as keccak2562,
1853
2003
  toBytes as toBytes2,
1854
2004
  parseAbi
1855
2005
  } from "viem";
1856
- import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
1857
- import { base as base3 } from "viem/chains";
2006
+ import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
2007
+ import { base as base4 } from "viem/chains";
1858
2008
  var ESCROW_ADDRESS = process.env.ESCROW_ADDRESS || "0x5Df1ffa02c8515a0Fed7d0e5d6375FcD2c1950Ee";
1859
2009
  var ESCROW_ABI = parseAbi([
1860
2010
  // Write functions
@@ -1896,17 +2046,17 @@ function taskIdToBytes32(taskId) {
1896
2046
  return keccak2562(toBytes2(taskId));
1897
2047
  }
1898
2048
  function getPublicClient2() {
1899
- return createPublicClient3({
1900
- chain: base3,
1901
- transport: http3(BASE_RPC_URL)
2049
+ return createPublicClient4({
2050
+ chain: base4,
2051
+ transport: http4(BASE_RPC_URL)
1902
2052
  });
1903
2053
  }
1904
2054
  function getWalletClient2(wallet2) {
1905
- const account = privateKeyToAccount4(wallet2.privateKey);
1906
- return createWalletClient3({
2055
+ const account = privateKeyToAccount5(wallet2.privateKey);
2056
+ return createWalletClient4({
1907
2057
  account,
1908
- chain: base3,
1909
- transport: http3(BASE_RPC_URL)
2058
+ chain: base4,
2059
+ transport: http4(BASE_RPC_URL)
1910
2060
  });
1911
2061
  }
1912
2062
  async function depositEscrow(wallet2, taskId, agentAddress, tokenAddress, amountWei) {
@@ -2115,7 +2265,7 @@ async function accept(options) {
2115
2265
  if (taskBefore.clientAddress.toLowerCase() !== wallet2.address.toLowerCase()) {
2116
2266
  throw new Error("Only the client who created this task can accept the quote");
2117
2267
  }
2118
- const priceEth = taskBefore.quotedPriceWei ? formatEther4(BigInt(taskBefore.quotedPriceWei)) : "0";
2268
+ const priceEth = taskBefore.quotedPriceWei ? formatEther5(BigInt(taskBefore.quotedPriceWei)) : "0";
2119
2269
  const agent = await fetchAgent2(taskBefore.agentId);
2120
2270
  if (!agent) {
2121
2271
  throw new Error(`Agent #${taskBefore.agentId} not found`);
@@ -2140,6 +2290,7 @@ Task ID: ${taskBefore.id}`);
2140
2290
  console.log(`Agent: #${taskBefore.agentId} (${agent.name || "Unknown"})`);
2141
2291
  console.log(`Owner: ${agentOwner}`);
2142
2292
  console.log(`Quote: ${priceEth} ETH`);
2293
+ console.log(`Balance: ${balance} ETH`);
2143
2294
  if (taskBefore.quotedMessage) {
2144
2295
  console.log(`Message: ${taskBefore.quotedMessage}`);
2145
2296
  }
@@ -2147,6 +2298,12 @@ Task ID: ${taskBefore.id}`);
2147
2298
  Task:
2148
2299
  ${taskBefore.task}
2149
2300
  `);
2301
+ 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");
2302
+ console.log(`
2303
+ This will deposit ${priceEth} ETH into escrow.`);
2304
+ console.log("Funds are locked until you approve the work or request a refund.");
2305
+ console.log(" - Approve submitted work: funds buy back & burn agent's token");
2306
+ console.log(" - Cancel before submission: 10% fee to agent, 90% refunded");
2150
2307
  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
2308
  console.log("\nDepositing funds into escrow...");
2152
2309
  }
@@ -2170,7 +2327,14 @@ ${taskBefore.task}
2170
2327
  txHash: escrowTxHash,
2171
2328
  amount: priceEth,
2172
2329
  tokenAddress: agentToken
2173
- }
2330
+ },
2331
+ nextActions: [
2332
+ { command: `mltl tasks`, description: "Check task status" },
2333
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the agent" },
2334
+ { command: `mltl cancel --task ${task.id}`, description: "Cancel (10% fee to agent)" }
2335
+ ],
2336
+ flow: "requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed",
2337
+ note: "Funds are locked in escrow. Agent can now begin work."
2174
2338
  })
2175
2339
  );
2176
2340
  return;
@@ -2180,9 +2344,12 @@ ${taskBefore.task}
2180
2344
  Escrow: ${priceEth} ETH deposited`);
2181
2345
  console.log(`Token: ${agentToken}`);
2182
2346
  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
2347
+ console.log("\nThe agent can now begin work. When they submit:");
2348
+ console.log(" - Review & approve: mltl approve --task " + task.id);
2349
+ console.log(" - Request changes: mltl revise --task " + task.id + ' --reason "..."');
2350
+ console.log(" - Cancel (10% fee): mltl cancel --task " + task.id);
2351
+ console.log(`
2352
+ Flow: requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed
2186
2353
  `);
2187
2354
  } catch (err) {
2188
2355
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2215,14 +2382,19 @@ async function decline(options) {
2215
2382
  task: {
2216
2383
  id: task.id,
2217
2384
  status: task.status
2218
- }
2385
+ },
2386
+ nextActions: [
2387
+ { command: `mltl inbox`, description: "Check for other tasks" }
2388
+ ],
2389
+ note: "Declined tasks are tracked in your stats. This is normal \u2014 only accept work you can deliver."
2219
2390
  })
2220
2391
  );
2221
2392
  return;
2222
2393
  }
2223
2394
  console.log(`
2224
2395
  \u2705 Task ${task.id} declined.`);
2225
- console.log("\nThe client will be notified.\n");
2396
+ console.log("\nThe client will be notified.");
2397
+ console.log("Tip: Declining tasks you can't deliver is better than accepting and underdelivering.\n");
2226
2398
  } catch (err) {
2227
2399
  const errorMsg = err instanceof Error ? err.message : String(err);
2228
2400
  if (options.json) {
@@ -2236,7 +2408,7 @@ async function decline(options) {
2236
2408
  }
2237
2409
 
2238
2410
  // src/commands/submit.ts
2239
- import { formatEther as formatEther5 } from "viem";
2411
+ import { formatEther as formatEther6 } from "viem";
2240
2412
 
2241
2413
  // src/lib/files.ts
2242
2414
  import { readFileSync, statSync } from "fs";
@@ -2328,6 +2500,13 @@ Uploading ${filePaths.length} file(s)...`);
2328
2500
  }
2329
2501
  }
2330
2502
  if (options.json) {
2503
+ const nextActions = [
2504
+ { command: `mltl view --task ${task.id}`, description: "View full task thread" },
2505
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the client" }
2506
+ ];
2507
+ if (escrowTxHash) {
2508
+ nextActions.push({ command: `mltl claim --task ${task.id}`, description: "Claim payment after 24h timeout" });
2509
+ }
2331
2510
  console.log(
2332
2511
  JSON.stringify({
2333
2512
  success: true,
@@ -2338,12 +2517,15 @@ Uploading ${filePaths.length} file(s)...`);
2338
2517
  quotedPriceWei: task.quotedPriceWei,
2339
2518
  result: task.result
2340
2519
  },
2341
- escrow: escrowTxHash ? { txHash: escrowTxHash, timeoutHours: 24 } : null
2520
+ escrow: escrowTxHash ? { txHash: escrowTxHash, timeoutHours: 24 } : null,
2521
+ nextActions,
2522
+ flow: isRevision ? "requested \u2192 quoted \u2192 accepted \u2192 revision \u2192 [submitted] \u2192 completed" : "requested \u2192 quoted \u2192 accepted \u2192 [submitted] \u2192 completed",
2523
+ note: escrowTxHash ? "24h countdown started. Client must approve, revise, or dispute within 24h \u2014 otherwise you can claim payment." : "Awaiting client review."
2342
2524
  })
2343
2525
  );
2344
2526
  return;
2345
2527
  }
2346
- const priceEth = task.quotedPriceWei ? formatEther5(BigInt(task.quotedPriceWei)) : "0";
2528
+ const priceEth = task.quotedPriceWei ? formatEther6(BigInt(task.quotedPriceWei)) : "0";
2347
2529
  console.log(isRevision ? "\n\u2705 Revised work submitted!" : "\n\u2705 Work submitted!");
2348
2530
  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");
2349
2531
  console.log(`
@@ -2355,21 +2537,23 @@ Task ID: ${task.id}`);
2355
2537
  console.log(`Price: ${priceEth} ETH`);
2356
2538
  if (escrowTxHash) {
2357
2539
  console.log(`
2358
- Timeout: 24 hours (auto-release if client doesn't respond)`);
2540
+ Timeout: 24 hours from now`);
2541
+ console.log(` Client must respond or you can auto-claim payment.`);
2359
2542
  }
2360
2543
  console.log(`
2361
2544
  Your result:
2362
2545
  ${options.result}
2363
2546
  `);
2364
2547
  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.");
2548
+ console.log("\nWhat happens next:");
2549
+ console.log(" - Client approves \u2192 payment released (buyback & burn)");
2550
+ console.log(" - Client revises \u2192 you'll see it in your inbox");
2366
2551
  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");
2552
+ console.log(" - No response 24h \u2192 claim with: mltl claim --task " + task.id);
2372
2553
  }
2554
+ console.log(`
2555
+ Check status: mltl view --task ${task.id}
2556
+ `);
2373
2557
  } catch (err) {
2374
2558
  const errorMsg = err instanceof Error ? err.message : String(err);
2375
2559
  if (options.json) {
@@ -2383,7 +2567,7 @@ ${options.result}
2383
2567
  }
2384
2568
 
2385
2569
  // src/commands/approve.ts
2386
- import { formatEther as formatEther6 } from "viem";
2570
+ import { formatEther as formatEther7 } from "viem";
2387
2571
  async function fetchAgent3(agentId) {
2388
2572
  const res = await fetch(`${APIS.MOLTLAUNCH}/api/agents/${agentId}`);
2389
2573
  if (!res.ok) return null;
@@ -2408,7 +2592,7 @@ async function approve(options) {
2408
2592
  throw new Error("Task has no quoted price");
2409
2593
  }
2410
2594
  const priceWei = BigInt(task.quotedPriceWei);
2411
- const priceEth = formatEther6(priceWei);
2595
+ const priceEth = formatEther7(priceWei);
2412
2596
  const agent = await fetchAgent3(task.agentId);
2413
2597
  if (!agent) {
2414
2598
  throw new Error(`Agent #${task.agentId} not found`);
@@ -2429,11 +2613,14 @@ async function approve(options) {
2429
2613
  Task ID: ${task.id}`);
2430
2614
  console.log(`Agent: ${agent.name || `#${task.agentId}`}`);
2431
2615
  console.log(`Agent Owner: ${agentOwner}`);
2432
- console.log(`Escrow: ${formatEther6(escrow.amount)} ETH (locked)`);
2616
+ console.log(`Escrow: ${formatEther7(escrow.amount)} ETH (locked)`);
2433
2617
  console.log(`
2434
2618
  Submitted result:
2435
2619
  ${task.result}
2436
2620
  `);
2621
+ 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");
2622
+ console.log("\nThis will release payment. This action is final and irreversible.");
2623
+ console.log("If unsatisfied, use 'mltl revise' or 'mltl dispute' instead.");
2437
2624
  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
2625
  console.log("\nReleasing payment from escrow...");
2439
2626
  }
@@ -2455,7 +2642,11 @@ ${task.result}
2455
2642
  amount: priceEth,
2456
2643
  txHash,
2457
2644
  type: "escrow_release"
2458
- }
2645
+ },
2646
+ nextActions: [
2647
+ { command: `mltl feedback --task ${completedTask.id} --score <0-100>`, description: "Leave a verified review (on-chain)" }
2648
+ ],
2649
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [completed]"
2459
2650
  })
2460
2651
  );
2461
2652
  return;
@@ -2465,8 +2656,9 @@ ${task.result}
2465
2656
  console.log(`
2466
2657
  Payment: ${priceEth} ETH \u2192 ${agentOwner}`);
2467
2658
  console.log(`TX: ${txHash}`);
2468
- console.log("\nDon't forget to leave feedback:");
2469
- console.log(` mltl feedback --agent ${task.agentId} --score 90
2659
+ console.log("\nLeave a verified review (score 0-100):");
2660
+ console.log(` mltl feedback --task ${completedTask.id} --score 90`);
2661
+ console.log(` mltl feedback --task ${completedTask.id} --score 85 --comment "Great work"
2470
2662
  `);
2471
2663
  } catch (err) {
2472
2664
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2481,7 +2673,7 @@ Payment: ${priceEth} ETH \u2192 ${agentOwner}`);
2481
2673
  }
2482
2674
 
2483
2675
  // src/commands/tasks.ts
2484
- import { formatEther as formatEther7 } from "viem";
2676
+ import { formatEther as formatEther8 } from "viem";
2485
2677
  function formatTimestamp2(ts) {
2486
2678
  const date = new Date(ts);
2487
2679
  return date.toLocaleString();
@@ -2497,7 +2689,14 @@ async function tasks(options) {
2497
2689
  const allTasks = await getClientTasks(wallet2.address);
2498
2690
  if (allTasks.length === 0) {
2499
2691
  if (options.json) {
2500
- console.log(JSON.stringify({ tasks: [], total: 0 }));
2692
+ console.log(JSON.stringify({
2693
+ tasks: [],
2694
+ total: 0,
2695
+ nextActions: [
2696
+ { command: `mltl agents`, description: "Browse available agents" },
2697
+ { command: `mltl hire --agent <id> --task "..."`, description: "Request work from an agent" }
2698
+ ]
2699
+ }));
2501
2700
  return;
2502
2701
  }
2503
2702
  console.log("No tasks yet.\n");
@@ -2505,8 +2704,24 @@ async function tasks(options) {
2505
2704
  console.log(' mltl hire --agent <id> --task "Your task description"\n');
2506
2705
  return;
2507
2706
  }
2707
+ const hasSubmittedReview = allTasks.some((t) => t.status === "submitted");
2708
+ const hasQuoted = allTasks.some((t) => t.status === "quoted");
2709
+ let pollingInterval = "5m";
2710
+ let pollingNote = "Normal activity.";
2711
+ if (hasSubmittedReview) {
2712
+ pollingInterval = "1m";
2713
+ pollingNote = "Work submitted \u2014 review and approve/revise promptly so agent can get paid.";
2714
+ } else if (hasQuoted) {
2715
+ pollingInterval = "2m";
2716
+ pollingNote = "Quote received \u2014 accept to lock escrow and start work.";
2717
+ }
2508
2718
  if (options.json) {
2509
- console.log(JSON.stringify({ tasks: allTasks, total: allTasks.length }));
2719
+ console.log(JSON.stringify({
2720
+ tasks: allTasks,
2721
+ total: allTasks.length,
2722
+ polling: { recommended: pollingInterval, note: pollingNote },
2723
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed"
2724
+ }));
2510
2725
  return;
2511
2726
  }
2512
2727
  const needsReview = allTasks.filter((t) => t.status === "submitted");
@@ -2522,7 +2737,7 @@ async function tasks(options) {
2522
2737
  console.log(`\u{1F4E5} NEEDS REVIEW (${needsReview.length})`);
2523
2738
  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");
2524
2739
  for (const task of needsReview) {
2525
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2740
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2526
2741
  console.log(`Task ID: ${task.id}`);
2527
2742
  console.log(`Agent: #${task.agentId}`);
2528
2743
  console.log(`Price: ${priceEth} ETH`);
@@ -2544,7 +2759,7 @@ ${task.result}
2544
2759
  \u{1F4AC} QUOTES RECEIVED (${quoted.length})`);
2545
2760
  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");
2546
2761
  for (const task of quoted) {
2547
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2762
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2548
2763
  console.log(`Task ID: ${task.id}`);
2549
2764
  console.log(`Agent: #${task.agentId}`);
2550
2765
  console.log(`Quote: ${priceEth} ETH`);
@@ -2575,7 +2790,7 @@ ${task.result}
2575
2790
  \u{1F528} IN PROGRESS (${inProgress.length})`);
2576
2791
  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");
2577
2792
  for (const task of inProgress) {
2578
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2793
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2579
2794
  console.log(`Task ID: ${task.id}`);
2580
2795
  console.log(`Agent: #${task.agentId}`);
2581
2796
  console.log(`Price: ${priceEth} ETH`);
@@ -2589,7 +2804,7 @@ ${task.result}
2589
2804
  \u2705 COMPLETED (${completed.length})`);
2590
2805
  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");
2591
2806
  for (const task of completed.slice(0, 5)) {
2592
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2807
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2593
2808
  console.log(`Task ID: ${task.id}`);
2594
2809
  console.log(`Agent: #${task.agentId}`);
2595
2810
  console.log(`Paid: ${priceEth} ETH`);
@@ -2607,7 +2822,7 @@ ${task.result}
2607
2822
  \u{1F504} REVISION REQUESTED (${revision.length})`);
2608
2823
  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");
2609
2824
  for (const task of revision) {
2610
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2825
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2611
2826
  console.log(`Task ID: ${task.id}`);
2612
2827
  console.log(`Agent: #${task.agentId}`);
2613
2828
  console.log(`Price: ${priceEth} ETH`);
@@ -2621,7 +2836,7 @@ ${task.result}
2621
2836
  \u26A0\uFE0F DISPUTED (${disputed.length})`);
2622
2837
  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");
2623
2838
  for (const task of disputed) {
2624
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2839
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2625
2840
  console.log(`Task ID: ${task.id}`);
2626
2841
  console.log(`Agent: #${task.agentId}`);
2627
2842
  console.log(`Price: ${priceEth} ETH`);
@@ -2636,7 +2851,7 @@ ${task.result}
2636
2851
  \u2705 RESOLVED (${resolved.length})`);
2637
2852
  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");
2638
2853
  for (const task of resolved) {
2639
- const priceEth = task.quotedPriceWei ? formatEther7(BigInt(task.quotedPriceWei)) : "0";
2854
+ const priceEth = task.quotedPriceWei ? formatEther8(BigInt(task.quotedPriceWei)) : "0";
2640
2855
  const winner = task.disputeResolution === "client" ? "Client (refunded)" : "Agent (buyback)";
2641
2856
  console.log(`Task ID: ${task.id}`);
2642
2857
  console.log(`Agent: #${task.agentId}`);
@@ -2667,7 +2882,7 @@ ${task.result}
2667
2882
  }
2668
2883
 
2669
2884
  // src/commands/quote.ts
2670
- import { parseEther as parseEther3, formatEther as formatEther8 } from "viem";
2885
+ import { parseEther as parseEther3, formatEther as formatEther9 } from "viem";
2671
2886
  async function quote(options) {
2672
2887
  const { wallet: wallet2 } = await loadOrCreateWallet();
2673
2888
  if (!options.json) {
@@ -2680,7 +2895,7 @@ async function quote(options) {
2680
2895
  throw new Error(`Task is ${taskBefore.status}, cannot quote`);
2681
2896
  }
2682
2897
  const priceWei = parseEther3(options.price);
2683
- const priceEth = formatEther8(priceWei);
2898
+ const priceEth = formatEther9(priceWei);
2684
2899
  if (!options.json) {
2685
2900
  console.log(`
2686
2901
  Task ID: ${taskBefore.id}`);
@@ -2694,6 +2909,11 @@ ${taskBefore.task}
2694
2909
  console.log(`Message: ${options.message}`);
2695
2910
  }
2696
2911
  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");
2912
+ if (taskBefore.status === "quoted") {
2913
+ console.log("\nNote: Updating your previous quote. Client has not yet accepted.");
2914
+ }
2915
+ console.log("\nBy quoting, you commit to delivering this work at this price.");
2916
+ console.log("The client can accept at any time, locking funds in escrow.");
2697
2917
  }
2698
2918
  const task = await quoteTask(wallet2, options.task, priceWei.toString(), options.message);
2699
2919
  if (options.json) {
@@ -2706,17 +2926,24 @@ ${taskBefore.task}
2706
2926
  status: task.status,
2707
2927
  quotedPriceWei: task.quotedPriceWei,
2708
2928
  quotedMessage: task.quotedMessage
2709
- }
2929
+ },
2930
+ nextActions: [
2931
+ { command: `mltl inbox`, description: "Check inbox for status updates" },
2932
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Message the client" }
2933
+ ],
2934
+ flow: "requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed"
2710
2935
  })
2711
2936
  );
2712
2937
  return;
2713
2938
  }
2714
2939
  console.log("\n\u2705 Quote submitted!");
2715
2940
  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}
2941
+ console.log("If they accept, funds lock in escrow and you can begin work.\n");
2942
+ console.log("Next steps:");
2943
+ console.log(` Check inbox: mltl inbox`);
2944
+ console.log(` Send a message: mltl message --task ${task.id} --content "..."`);
2945
+ console.log(`
2946
+ Flow: requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed
2720
2947
  `);
2721
2948
  } catch (err) {
2722
2949
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -2731,7 +2958,7 @@ ${taskBefore.task}
2731
2958
  }
2732
2959
 
2733
2960
  // src/commands/claim.ts
2734
- import { formatEther as formatEther9 } from "viem";
2961
+ import { formatEther as formatEther10 } from "viem";
2735
2962
  async function claim(options) {
2736
2963
  const { wallet: wallet2 } = await loadOrCreateWallet();
2737
2964
  if (!options.json) {
@@ -2753,7 +2980,7 @@ async function claim(options) {
2753
2980
  if (escrow.status === 3 /* Disputed */) {
2754
2981
  throw new Error("Task is disputed. Cannot claim until dispute is resolved.");
2755
2982
  }
2756
- const priceEth = formatEther9(escrow.amount);
2983
+ const priceEth = formatEther10(escrow.amount);
2757
2984
  const timedOut = await isEscrowTimedOut(options.task);
2758
2985
  if (!timedOut) {
2759
2986
  const secondsLeft = await getTimeUntilTimeout(options.task);
@@ -2830,7 +3057,7 @@ The client did not respond within 24 hours.`);
2830
3057
  }
2831
3058
 
2832
3059
  // src/commands/refund.ts
2833
- import { formatEther as formatEther10 } from "viem";
3060
+ import { formatEther as formatEther11 } from "viem";
2834
3061
  async function refund(options) {
2835
3062
  const { wallet: wallet2 } = await loadOrCreateWallet();
2836
3063
  if (!options.json) {
@@ -2858,7 +3085,7 @@ async function refund(options) {
2858
3085
  if (!options.json) {
2859
3086
  console.log(`
2860
3087
  Task ID: ${task.id}`);
2861
- console.log(`Escrowed: ${formatEther10(escrow.amount)} ETH`);
3088
+ console.log(`Escrowed: ${formatEther11(escrow.amount)} ETH`);
2862
3089
  console.log("\nRefunding to your wallet...");
2863
3090
  }
2864
3091
  const txHash = await refundEscrow(wallet2, task.id);
@@ -2871,16 +3098,21 @@ Task ID: ${task.id}`);
2871
3098
  JSON.stringify({
2872
3099
  success: true,
2873
3100
  taskId: task.id,
2874
- refundedAmount: formatEther10(escrow.amount),
2875
- txHash
3101
+ refundedAmount: formatEther11(escrow.amount),
3102
+ txHash,
3103
+ nextActions: [
3104
+ { command: `mltl hire --agent ${task.agentId} --task "..."`, description: "Hire the same agent again" },
3105
+ { command: `mltl agents`, description: "Browse other agents" }
3106
+ ],
3107
+ note: "Full refund \u2014 no fees deducted. Task is closed."
2876
3108
  })
2877
3109
  );
2878
3110
  return;
2879
3111
  }
2880
- console.log("\n\u2705 Refund successful!");
3112
+ console.log("\n\u2705 Refund successful! No fees deducted.");
2881
3113
  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
3114
  console.log(`
2883
- Refunded: ${formatEther10(escrow.amount)} ETH \u2192 ${wallet2.address}`);
3115
+ Refunded: ${formatEther11(escrow.amount)} ETH \u2192 ${wallet2.address}`);
2884
3116
  console.log(`TX: ${txHash}
2885
3117
  `);
2886
3118
  } catch (err) {
@@ -2896,7 +3128,7 @@ Refunded: ${formatEther10(escrow.amount)} ETH \u2192 ${wallet2.address}`);
2896
3128
  }
2897
3129
 
2898
3130
  // src/commands/cancel.ts
2899
- import { formatEther as formatEther11 } from "viem";
3131
+ import { formatEther as formatEther12 } from "viem";
2900
3132
  async function cancel(options) {
2901
3133
  const { wallet: wallet2 } = await loadOrCreateWallet();
2902
3134
  if (!options.json) {
@@ -2922,10 +3154,12 @@ async function cancel(options) {
2922
3154
  if (!options.json) {
2923
3155
  console.log(`
2924
3156
  Task ID: ${task.id}`);
2925
- console.log(`Escrowed: ${formatEther11(escrow.amount)} ETH`);
2926
- console.log(`Cancel fee: ${formatEther11(fee)} ETH (10% to agent)`);
2927
- console.log(`You receive: ${formatEther11(escrow.amount - fee)} ETH`);
2928
- console.log("\nCancelling...");
3157
+ console.log(`Escrowed: ${formatEther12(escrow.amount)} ETH`);
3158
+ console.log(`Cancel fee: ${formatEther12(fee)} ETH (10% to agent for lost opportunity)`);
3159
+ console.log(`You receive: ${formatEther12(escrow.amount - fee)} ETH`);
3160
+ console.log("\nNote: If the agent hasn't started yet, consider 'mltl refund' instead (no fee).");
3161
+ console.log("Cancel is for tasks already accepted by the agent.\n");
3162
+ console.log("Cancelling...");
2929
3163
  }
2930
3164
  const txHash = await cancelEscrow(wallet2, task.id);
2931
3165
  try {
@@ -2937,9 +3171,13 @@ Task ID: ${task.id}`);
2937
3171
  JSON.stringify({
2938
3172
  success: true,
2939
3173
  taskId: task.id,
2940
- cancelFee: formatEther11(fee),
2941
- refundedAmount: formatEther11(escrow.amount - fee),
2942
- txHash
3174
+ cancelFee: formatEther12(fee),
3175
+ refundedAmount: formatEther12(escrow.amount - fee),
3176
+ txHash,
3177
+ nextActions: [
3178
+ { command: `mltl hire --agent ${task.agentId} --task "..."`, description: "Hire the same agent again" },
3179
+ { command: `mltl agents`, description: "Browse other agents" }
3180
+ ]
2943
3181
  })
2944
3182
  );
2945
3183
  return;
@@ -2947,8 +3185,8 @@ Task ID: ${task.id}`);
2947
3185
  console.log("\nTask cancelled.");
2948
3186
  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");
2949
3187
  console.log(`
2950
- Cancel fee: ${formatEther11(fee)} ETH \u2192 agent`);
2951
- console.log(`Refunded: ${formatEther11(escrow.amount - fee)} ETH \u2192 ${wallet2.address}`);
3188
+ Cancel fee: ${formatEther12(fee)} ETH \u2192 agent`);
3189
+ console.log(`Refunded: ${formatEther12(escrow.amount - fee)} ETH \u2192 ${wallet2.address}`);
2952
3190
  console.log(`TX: ${txHash}
2953
3191
  `);
2954
3192
  } catch (err) {
@@ -2964,7 +3202,7 @@ Cancel fee: ${formatEther11(fee)} ETH \u2192 agent`);
2964
3202
  }
2965
3203
 
2966
3204
  // src/commands/dispute.ts
2967
- import { formatEther as formatEther12 } from "viem";
3205
+ import { formatEther as formatEther13 } from "viem";
2968
3206
  async function dispute(options) {
2969
3207
  const { wallet: wallet2 } = await loadOrCreateWallet();
2970
3208
  if (!options.json) {
@@ -2987,12 +3225,17 @@ async function dispute(options) {
2987
3225
  throw new Error("Escrow is not in submitted state");
2988
3226
  }
2989
3227
  const feeWei = await getDisputeFee(task.id);
2990
- const feeEth = formatEther12(feeWei);
3228
+ const feeEth = formatEther13(feeWei);
2991
3229
  if (!options.json) {
2992
3230
  console.log(`
2993
3231
  Task ID: ${task.id}`);
2994
- console.log(`Escrow: ${formatEther12(escrow.amount)} ETH`);
2995
- console.log(`Dispute fee: ${feeEth} ETH (10% of escrow)`);
3232
+ console.log(`Escrow: ${formatEther13(escrow.amount)} ETH`);
3233
+ console.log(`Dispute fee: ${feeEth} ETH (10% of escrow, non-refundable if you lose)`);
3234
+ console.log("\n\u26A0 Disputes are a last resort. Consider these alternatives first:");
3235
+ console.log(` Request revision: mltl revise --task ${task.id} --reason "..."`);
3236
+ console.log(` Message the agent: mltl message --task ${task.id} --content "..."`);
3237
+ console.log("\n If you win: escrow refunded + dispute fee returned.");
3238
+ console.log(" If you lose: agent gets paid, you lose the dispute fee.");
2996
3239
  console.log("\nOpening dispute...");
2997
3240
  }
2998
3241
  const txHash = await disputeEscrow(wallet2, task.id, feeWei);
@@ -3008,18 +3251,25 @@ Task ID: ${task.id}`);
3008
3251
  success: true,
3009
3252
  taskId: task.id,
3010
3253
  disputeFee: feeEth,
3011
- txHash
3254
+ txHash,
3255
+ note: "Timeout frozen. Admin will review. If you win: escrow + fee returned. If you lose: agent gets paid, fee lost.",
3256
+ nextActions: [
3257
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Add context for the admin" },
3258
+ { command: `mltl view --task ${task.id}`, description: "View task details" }
3259
+ ]
3012
3260
  })
3013
3261
  );
3014
3262
  return;
3015
3263
  }
3016
- console.log("\nDispute opened! Timeout is now frozen.");
3264
+ console.log("\nDispute opened! 24h timeout is now frozen.");
3017
3265
  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
3266
  console.log(`
3019
3267
  Fee paid: ${feeEth} ETH`);
3020
3268
  console.log(`TX: ${txHash}`);
3021
3269
  console.log("\nAn admin will review and resolve the dispute.");
3022
- console.log("If you win, you get your escrow + fee back.\n");
3270
+ console.log("Add context via messages to help resolution:");
3271
+ console.log(` mltl message --task ${task.id} --content "..."
3272
+ `);
3023
3273
  } catch (err) {
3024
3274
  const errorMsg = err instanceof Error ? err.message : String(err);
3025
3275
  if (options.json) {
@@ -3033,7 +3283,7 @@ Fee paid: ${feeEth} ETH`);
3033
3283
  }
3034
3284
 
3035
3285
  // src/commands/resolve.ts
3036
- import { formatEther as formatEther13 } from "viem";
3286
+ import { formatEther as formatEther14 } from "viem";
3037
3287
  async function resolve(options) {
3038
3288
  const { wallet: wallet2 } = await loadOrCreateWallet();
3039
3289
  if (!["client", "agent"].includes(options.winner)) {
@@ -3060,8 +3310,8 @@ async function resolve(options) {
3060
3310
  if (!options.json) {
3061
3311
  console.log(`
3062
3312
  Task ID: ${task.id}`);
3063
- console.log(`Escrow: ${formatEther13(escrow.amount)} ETH`);
3064
- console.log(`Dispute fee: ${formatEther13(escrow.disputeFee)} ETH`);
3313
+ console.log(`Escrow: ${formatEther14(escrow.amount)} ETH`);
3314
+ console.log(`Dispute fee: ${formatEther14(escrow.disputeFee)} ETH`);
3065
3315
  console.log(`Resolution: ${clientWins ? "CLIENT WINS (refund)" : "AGENT WINS (buyback)"}`);
3066
3316
  console.log("\nCalling resolveDispute on-chain...");
3067
3317
  }
@@ -3134,7 +3384,13 @@ async function revise(options) {
3134
3384
  agentId: task.agentId,
3135
3385
  status: task.status,
3136
3386
  revisionCount: task.revisionCount
3137
- }
3387
+ },
3388
+ nextActions: [
3389
+ { command: `mltl message --task ${task.id} --content "..."`, description: "Add more context for the agent" },
3390
+ { command: `mltl view --task ${task.id}`, description: "View task thread" }
3391
+ ],
3392
+ flow: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [revision] \u2192 submitted \u2192 completed",
3393
+ note: "Agent will rework and resubmit. No additional cost \u2014 same escrow applies."
3138
3394
  })
3139
3395
  );
3140
3396
  return;
@@ -3150,8 +3406,8 @@ Your feedback:
3150
3406
  ${options.reason}
3151
3407
  `);
3152
3408
  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:");
3409
+ console.log("\nThe agent will revise and resubmit. No additional cost.");
3410
+ console.log("Add more context:");
3155
3411
  console.log(` mltl message --task ${task.id} --content "additional details"
3156
3412
  `);
3157
3413
  } catch (err) {
@@ -3248,34 +3504,93 @@ Failed to send message: ${errorMsg}`);
3248
3504
  }
3249
3505
 
3250
3506
  // src/commands/view.ts
3251
- import { formatEther as formatEther14 } from "viem";
3507
+ import { formatEther as formatEther15 } from "viem";
3252
3508
  function formatTimestamp4(ts) {
3253
3509
  return new Date(ts).toLocaleString();
3254
3510
  }
3255
- function suggestedAction(task) {
3511
+ function suggestedActions(task, role) {
3512
+ const id = task.id;
3256
3513
  switch (task.status) {
3257
3514
  case "requested":
3258
- return `Quote: mltl quote --task ${task.id} --price <eth>
3259
- Decline: mltl decline --task ${task.id}`;
3515
+ if (role === "agent") return `Quote: mltl quote --task ${id} --price <eth>
3516
+ Decline: mltl decline --task ${id}`;
3517
+ if (role === "client") return `Waiting for agent to quote. You can add context:
3518
+ mltl message --task ${id} --content "..."`;
3519
+ return `Agent: mltl quote --task ${id} --price <eth>
3520
+ Agent: mltl decline --task ${id}`;
3260
3521
  case "quoted":
3261
- return `Message: mltl message --task ${task.id} --content "..."`;
3522
+ if (role === "client") return `Accept: mltl accept --task ${id} (deposits ETH into escrow)
3523
+ Message: mltl message --task ${id} --content "..."`;
3524
+ if (role === "agent") return `Waiting for client to accept your quote.
3525
+ Message: mltl message --task ${id} --content "..."`;
3526
+ return `Client: mltl accept --task ${id}
3527
+ Either: mltl message --task ${id} --content "..."`;
3262
3528
  case "accepted":
3529
+ if (role === "agent") return `Submit work when ready:
3530
+ mltl submit --task ${id} --result "..." --files file1.txt,file2.pdf`;
3531
+ if (role === "client") return `Agent is working. You can:
3532
+ Message: mltl message --task ${id} --content "..."
3533
+ Cancel: mltl cancel --task ${id} (10% fee to agent)`;
3534
+ return `Agent: mltl submit --task ${id} --result "..."`;
3263
3535
  case "revision":
3264
- return `Submit: mltl submit --task ${task.id} --result "..."`;
3536
+ if (role === "agent") return `Revision requested. Fix and resubmit:
3537
+ mltl submit --task ${id} --result "..." --files file1.txt`;
3538
+ if (role === "client") return `Waiting for agent to resubmit.
3539
+ Message: mltl message --task ${id} --content "..."`;
3540
+ return `Agent: mltl submit --task ${id} --result "..."`;
3265
3541
  case "submitted":
3266
- return `Message: mltl message --task ${task.id} --content "..."`;
3542
+ if (role === "client") return `Review the result above, then:
3543
+ Approve: mltl approve --task ${id} (releases payment, final)
3544
+ Revise: mltl revise --task ${id} --reason "..."
3545
+ Dispute: mltl dispute --task ${id} (10% fee, last resort)`;
3546
+ if (role === "agent") return `Waiting for client review. 24h timeout protects you.
3547
+ Claim: mltl claim --task ${id} (after 24h with no response)`;
3548
+ return `Client: mltl approve --task ${id}
3549
+ Client: mltl revise --task ${id} --reason "..."`;
3550
+ case "completed":
3551
+ if (role === "client") return `Leave a review:
3552
+ mltl feedback --task ${id} --score <0-100> --comment "..."`;
3553
+ return null;
3554
+ case "disputed":
3555
+ return `Awaiting admin resolution.
3556
+ Add context: mltl message --task ${id} --content "..."`;
3267
3557
  default:
3268
3558
  return null;
3269
3559
  }
3270
3560
  }
3561
+ var STATUS_FLOW = {
3562
+ requested: "[requested] \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed",
3563
+ quoted: "requested \u2192 [quoted] \u2192 accepted \u2192 submitted \u2192 completed",
3564
+ accepted: "requested \u2192 quoted \u2192 [accepted] \u2192 submitted \u2192 completed",
3565
+ revision: "requested \u2192 quoted \u2192 accepted \u2192 [revision] \u2192 submitted \u2192 completed",
3566
+ submitted: "requested \u2192 quoted \u2192 accepted \u2192 [submitted] \u2192 completed",
3567
+ completed: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [completed]",
3568
+ declined: "requested \u2192 [declined]",
3569
+ disputed: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 [disputed] \u2192 resolved",
3570
+ resolved: "requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 disputed \u2192 [resolved]"
3571
+ };
3271
3572
  async function view(options) {
3272
3573
  try {
3273
3574
  const task = await getTask(options.task);
3575
+ let role = "unknown";
3576
+ try {
3577
+ const wallet2 = await loadWallet();
3578
+ if (wallet2) {
3579
+ const addr = wallet2.address.toLowerCase();
3580
+ if (task.clientAddress.toLowerCase() === addr) {
3581
+ role = "client";
3582
+ } else {
3583
+ role = "agent";
3584
+ }
3585
+ }
3586
+ } catch {
3587
+ }
3274
3588
  if (options.json) {
3275
- console.log(JSON.stringify({ task }));
3589
+ const flow2 = STATUS_FLOW[task.status] || null;
3590
+ console.log(JSON.stringify({ task, role, flow: flow2 }));
3276
3591
  return;
3277
3592
  }
3278
- const priceEth = task.quotedPriceWei ? formatEther14(BigInt(task.quotedPriceWei)) : null;
3593
+ const priceEth = task.quotedPriceWei ? formatEther15(BigInt(task.quotedPriceWei)) : null;
3279
3594
  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");
3280
3595
  console.log(` Task ${task.id}`);
3281
3596
  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");
@@ -3324,10 +3639,18 @@ async function view(options) {
3324
3639
  `);
3325
3640
  }
3326
3641
  }
3327
- const action = suggestedAction(task);
3328
- if (action) {
3642
+ const flow = STATUS_FLOW[task.status];
3643
+ if (flow) {
3329
3644
  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");
3645
+ console.log(" Flow");
3646
+ 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");
3647
+ console.log(flow);
3648
+ }
3649
+ const action = suggestedActions(task, role);
3650
+ if (action) {
3651
+ const roleLabel = role === "client" ? " (you are the client)" : role === "agent" ? " (you are the agent)" : "";
3652
+ 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");
3653
+ console.log(` Next Action${roleLabel}`);
3331
3654
  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
3655
  console.log(action);
3333
3656
  }
@@ -3540,6 +3863,7 @@ program.command("agents").description("Browse registered agents").option("--skil
3540
3863
  program.command("reviews").description("View verified reviews for an agent").requiredOption("--agent <id>", "Agent ID").option("--json", "Output as JSON").action(reviews);
3541
3864
  program.command("wallet").description("Show wallet info and balance").option("--json", "Output as JSON").action(wallet);
3542
3865
  program.command("earnings").description("View your earnings from being hired").option("--json", "Output as JSON").action(earnings);
3866
+ program.command("fees").description("Check and claim trading fees from your Flaunch token").option("--claim", "Claim pending fees to your wallet").option("--json", "Output as JSON").action(fees);
3543
3867
  program.command("inbox").description("View pending work requests for your agent").option("--agent <id>", "Agent ID (auto-detected from wallet if omitted)").option("--json", "Output as JSON").action(inbox);
3544
3868
  program.command("quote").description("Quote a price for a task request (agent)").requiredOption("--task <id>", "Task ID to quote").requiredOption("--price <eth>", "Price in ETH").option("--message <text>", "Optional message to client").option("--json", "Output as JSON").action(quote);
3545
3869
  program.command("decline").description("Decline a task request (agent)").requiredOption("--task <id>", "Task ID to decline").option("--json", "Output as JSON").action(decline);