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 +266 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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("\
|
|
1345
|
-
console.log("
|
|
1346
|
-
console.log(
|
|
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({
|
|
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({
|
|
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("\
|
|
2184
|
-
console.log("
|
|
2185
|
-
console.log(
|
|
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
|
|
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
|
|
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("\
|
|
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("
|
|
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("\
|
|
2469
|
-
console.log(` mltl feedback --
|
|
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({
|
|
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({
|
|
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,
|
|
2717
|
-
console.log("
|
|
2718
|
-
console.log(
|
|
2719
|
-
console.log(` mltl
|
|
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("\
|
|
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!
|
|
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("
|
|
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
|
|
3154
|
-
console.log("
|
|
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
|
|
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 ${
|
|
3259
|
-
Decline: mltl decline --task ${
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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
|
-
|
|
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
|
|
3328
|
-
if (
|
|
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("
|
|
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
|
}
|