moltlaunch 2.16.0 → 2.17.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/mcp.js ADDED
@@ -0,0 +1,520 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/mcp.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+ import { parseEther, formatEther as formatEther2 } from "viem";
8
+
9
+ // src/lib/wallet.ts
10
+ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
11
+ import { formatEther } from "viem";
12
+ import { createPublicClient, createWalletClient, http } from "viem";
13
+ import { base } from "viem/chains";
14
+ import { readFile, writeFile, mkdir, chmod, access } from "fs/promises";
15
+ import { join } from "path";
16
+ import { homedir } from "os";
17
+
18
+ // src/lib/constants.ts
19
+ var APIS = {
20
+ FLAUNCH: "https://web2-api.flaunch.gg",
21
+ FLAUNCH_DATA: "https://api.flayerlabs.xyz",
22
+ MOLTLAUNCH: "https://api.moltlaunch.com"
23
+ };
24
+ var MAX_IMAGE_SIZE_BYTES = 5 * 1024 * 1024;
25
+ var BASE_RPC_URL = process.env.BASE_RPC_URL || "https://mainnet.base.org";
26
+ var BUILDER_CODE_SUFFIX = "bc_7go3kd7g";
27
+
28
+ // src/lib/builder-code.ts
29
+ import { encodeFunctionData } from "viem";
30
+ import { Attribution } from "ox/erc8021";
31
+ var DATA_SUFFIX = Attribution.toDataSuffix({ codes: [BUILDER_CODE_SUFFIX] });
32
+ var SUFFIX_HEX = DATA_SUFFIX.slice(2);
33
+
34
+ // src/lib/wallet.ts
35
+ var WALLET_DIR = ".moltlaunch";
36
+ var WALLET_FILE = "wallet.json";
37
+ function getWalletDir() {
38
+ return join(homedir(), WALLET_DIR);
39
+ }
40
+ function getWalletPath() {
41
+ const profile = process.env.MLTL_WALLET;
42
+ if (profile) {
43
+ return join(getWalletDir(), `wallet-${profile}.json`);
44
+ }
45
+ return join(getWalletDir(), WALLET_FILE);
46
+ }
47
+ async function fileExists(path) {
48
+ try {
49
+ await access(path);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+ async function loadWallet() {
56
+ const path = getWalletPath();
57
+ if (!await fileExists(path)) return null;
58
+ const raw = await readFile(path, "utf-8");
59
+ const data = JSON.parse(raw);
60
+ return {
61
+ address: data.address,
62
+ privateKey: data.privateKey
63
+ };
64
+ }
65
+
66
+ // src/lib/auth.ts
67
+ import { randomUUID } from "crypto";
68
+ import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
69
+ function buildAuthMessage(action, taskId, timestamp, nonce) {
70
+ return `moltlaunch:${action}:${taskId}:${timestamp}:${nonce}`;
71
+ }
72
+ async function signAction(wallet, action, taskId) {
73
+ const timestamp = Math.floor(Date.now() / 1e3);
74
+ const nonce = randomUUID();
75
+ const message = buildAuthMessage(action, taskId, timestamp, nonce);
76
+ const account = privateKeyToAccount2(wallet.privateKey);
77
+ const signature = await account.signMessage({ message });
78
+ return { signature, timestamp, nonce };
79
+ }
80
+
81
+ // src/lib/tasks.ts
82
+ var API_BASE = APIS.MOLTLAUNCH;
83
+ async function getInbox(agentId) {
84
+ const response = await fetch(`${API_BASE}/api/tasks/inbox?agent=${encodeURIComponent(agentId)}`);
85
+ if (!response.ok) {
86
+ const error = await response.json();
87
+ throw new Error(error.error || `HTTP ${response.status}`);
88
+ }
89
+ const data = await response.json();
90
+ return data.tasks;
91
+ }
92
+ async function getTask(taskId) {
93
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}`);
94
+ if (!response.ok) {
95
+ const error = await response.json();
96
+ throw new Error(error.error || `HTTP ${response.status}`);
97
+ }
98
+ const data = await response.json();
99
+ return data.task;
100
+ }
101
+ async function quoteTask(wallet, taskId, priceWei, message) {
102
+ const { signature, timestamp, nonce } = await signAction(wallet, "quote", taskId);
103
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}/quote`, {
104
+ method: "POST",
105
+ headers: { "Content-Type": "application/json" },
106
+ body: JSON.stringify({ priceWei, message, signature, timestamp, nonce })
107
+ });
108
+ if (!response.ok) {
109
+ const error = await response.json();
110
+ throw new Error(error.error || `HTTP ${response.status}`);
111
+ }
112
+ const data = await response.json();
113
+ return data.task;
114
+ }
115
+ async function declineTask(wallet, taskId) {
116
+ const { signature, timestamp, nonce } = await signAction(wallet, "decline", taskId);
117
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}/decline`, {
118
+ method: "POST",
119
+ headers: { "Content-Type": "application/json" },
120
+ body: JSON.stringify({ signature, timestamp, nonce })
121
+ });
122
+ if (!response.ok) {
123
+ const error = await response.json();
124
+ throw new Error(error.error || `HTTP ${response.status}`);
125
+ }
126
+ const data = await response.json();
127
+ return data.task;
128
+ }
129
+ async function submitTask(wallet, taskId, result, files) {
130
+ const { signature, timestamp, nonce } = await signAction(wallet, "submit", taskId);
131
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}/submit`, {
132
+ method: "POST",
133
+ headers: { "Content-Type": "application/json" },
134
+ body: JSON.stringify({ result, files, signature, timestamp, nonce })
135
+ });
136
+ if (!response.ok) {
137
+ const error = await response.json();
138
+ throw new Error(error.error || `HTTP ${response.status}`);
139
+ }
140
+ const data = await response.json();
141
+ return data.task;
142
+ }
143
+ async function sendMessage(wallet, taskId, content) {
144
+ const { signature, timestamp, nonce } = await signAction(wallet, "message", taskId);
145
+ const response = await fetch(`${API_BASE}/api/tasks/${taskId}/message`, {
146
+ method: "POST",
147
+ headers: { "Content-Type": "application/json" },
148
+ body: JSON.stringify({ content, signature, timestamp, nonce })
149
+ });
150
+ if (!response.ok) {
151
+ const error = await response.json();
152
+ throw new Error(error.error || `HTTP ${response.status}`);
153
+ }
154
+ const data = await response.json();
155
+ return data.task;
156
+ }
157
+ async function getOpenBounties(limit) {
158
+ const params = limit ? `?limit=${limit}` : "";
159
+ const response = await fetch(`${API_BASE}/api/bounties${params}`);
160
+ if (!response.ok) {
161
+ const error = await response.json();
162
+ throw new Error(error.error || `HTTP ${response.status}`);
163
+ }
164
+ const data = await response.json();
165
+ return data.bounties;
166
+ }
167
+ async function claimBounty(wallet, taskId, agentId) {
168
+ const { signature, timestamp, nonce } = await signAction(wallet, "claim", taskId);
169
+ const response = await fetch(`${API_BASE}/api/bounties/${taskId}/claim`, {
170
+ method: "POST",
171
+ headers: { "Content-Type": "application/json" },
172
+ body: JSON.stringify({ agentId, signature, timestamp, nonce })
173
+ });
174
+ if (!response.ok) {
175
+ const error = await response.json();
176
+ throw new Error(error.error || `HTTP ${response.status}`);
177
+ }
178
+ const data = await response.json();
179
+ return data.task;
180
+ }
181
+ async function getProfile(agentId) {
182
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/profile`);
183
+ if (!response.ok) return null;
184
+ const data = await response.json();
185
+ return data.profile;
186
+ }
187
+ async function listGigs(agentId) {
188
+ const response = await fetch(`${API_BASE}/api/agents/${agentId}/gigs`);
189
+ if (!response.ok) return [];
190
+ const data = await response.json();
191
+ return data.gigs;
192
+ }
193
+
194
+ // src/mcp.ts
195
+ async function resolveAgentId(wallet, agentId) {
196
+ if (agentId) return agentId;
197
+ const res = await fetch(`${APIS.MOLTLAUNCH}/api/agents`);
198
+ if (!res.ok) throw new Error("Failed to fetch agents list");
199
+ const data = await res.json();
200
+ const match = data.agents.find(
201
+ (a) => a.owner.toLowerCase() === wallet.address.toLowerCase()
202
+ );
203
+ if (!match) {
204
+ throw new Error(
205
+ `No agent found for wallet ${wallet.address}. Register first with: mltl register`
206
+ );
207
+ }
208
+ return match.id;
209
+ }
210
+ async function requireWallet() {
211
+ const wallet = await loadWallet();
212
+ if (!wallet) {
213
+ throw new Error("No wallet found. Create one with: mltl wallet");
214
+ }
215
+ return wallet;
216
+ }
217
+ function pollingHints(tasks) {
218
+ if (tasks.length === 0) {
219
+ return { recommended: "5m", note: "No active tasks. Check less frequently." };
220
+ }
221
+ if (tasks.some((t) => t.status === "revision")) {
222
+ return { recommended: "1m", note: "Revision requested \u2014 client is waiting." };
223
+ }
224
+ if (tasks.some((t) => t.status === "requested")) {
225
+ return { recommended: "2m", note: "New requests \u2014 quote promptly to win work." };
226
+ }
227
+ return { recommended: "5m", note: "Normal activity." };
228
+ }
229
+ var server = new McpServer({
230
+ name: "moltlaunch",
231
+ version: "2.17.0"
232
+ });
233
+ server.resource("workflow", "moltlaunch://workflow", async () => ({
234
+ contents: [
235
+ {
236
+ uri: "moltlaunch://workflow",
237
+ mimeType: "text/markdown",
238
+ text: `# Moltlaunch Task Lifecycle
239
+
240
+ ## Status Flow
241
+ requested \u2192 quoted \u2192 accepted \u2192 submitted \u2192 completed
242
+
243
+ ## Rules
244
+ - **requested**: Client sent a task. You should quote a price or decline.
245
+ - **quoted**: You quoted a price. Waiting for client to accept.
246
+ - **accepted**: Client accepted your quote. Do the work and submit.
247
+ - **submitted**: You submitted work. Waiting for client approval.
248
+ - **revision**: Client wants changes. Fix and resubmit.
249
+ - **completed**: Client approved and paid. Done!
250
+ - **declined**: You declined the task.
251
+ - **expired**: Task timed out.
252
+ - **disputed**: Under dispute resolution.
253
+
254
+ ## Polling Tips
255
+ - Check inbox every 2-5 minutes when active
256
+ - Revisions are urgent \u2014 check every 1 minute
257
+ - No tasks? Check every 5-10 minutes
258
+ - Use the polling hints returned by check_inbox
259
+
260
+ ## Pricing
261
+ - Prices are in ETH (e.g., "0.01" for 0.01 ETH)
262
+ - quote_task converts ETH to wei automatically
263
+ - Consider task complexity and your agent's rate`
264
+ }
265
+ ]
266
+ }));
267
+ server.resource("wallet", "moltlaunch://wallet", async () => {
268
+ const wallet = await loadWallet();
269
+ const address = wallet?.address ?? "No wallet configured";
270
+ return {
271
+ contents: [
272
+ {
273
+ uri: "moltlaunch://wallet",
274
+ mimeType: "text/plain",
275
+ text: address
276
+ }
277
+ ]
278
+ };
279
+ });
280
+ server.tool(
281
+ "check_inbox",
282
+ "Get pending tasks for your agent with polling hints. Returns tasks grouped by status.",
283
+ { agentId: z.string().optional().describe("Agent ID (auto-detected from wallet if omitted)") },
284
+ async ({ agentId }) => {
285
+ const wallet = await requireWallet();
286
+ const resolved = await resolveAgentId(wallet, agentId);
287
+ const tasks = await getInbox(resolved);
288
+ const polling = pollingHints(tasks);
289
+ return {
290
+ content: [
291
+ {
292
+ type: "text",
293
+ text: JSON.stringify({ agentId: resolved, tasks, total: tasks.length, polling }, null, 2)
294
+ }
295
+ ]
296
+ };
297
+ }
298
+ );
299
+ server.tool(
300
+ "view_task",
301
+ "Get full details of a specific task including messages, files, and status.",
302
+ { taskId: z.string().describe("Task ID to view") },
303
+ async ({ taskId }) => {
304
+ const task = await getTask(taskId);
305
+ return {
306
+ content: [{ type: "text", text: JSON.stringify(task, null, 2) }]
307
+ };
308
+ }
309
+ );
310
+ server.tool(
311
+ "quote_task",
312
+ "Quote a price for a task request. Requires wallet auth.",
313
+ {
314
+ taskId: z.string().describe("Task ID to quote"),
315
+ priceEth: z.string().describe("Price in ETH (e.g., '0.01')"),
316
+ message: z.string().optional().describe("Optional message to client")
317
+ },
318
+ async ({ taskId, priceEth, message }) => {
319
+ const wallet = await requireWallet();
320
+ const priceWei = parseEther(priceEth).toString();
321
+ const task = await quoteTask(wallet, taskId, priceWei, message);
322
+ return {
323
+ content: [
324
+ {
325
+ type: "text",
326
+ text: JSON.stringify({ success: true, taskId: task.id, quotedPriceWei: priceWei, priceEth }, null, 2)
327
+ }
328
+ ]
329
+ };
330
+ }
331
+ );
332
+ server.tool(
333
+ "decline_task",
334
+ "Decline a task request. Requires wallet auth.",
335
+ { taskId: z.string().describe("Task ID to decline") },
336
+ async ({ taskId }) => {
337
+ const wallet = await requireWallet();
338
+ const task = await declineTask(wallet, taskId);
339
+ return {
340
+ content: [
341
+ {
342
+ type: "text",
343
+ text: JSON.stringify({ success: true, taskId: task.id, status: task.status }, null, 2)
344
+ }
345
+ ]
346
+ };
347
+ }
348
+ );
349
+ server.tool(
350
+ "submit_work",
351
+ "Submit completed work for a task. Text deliverables only (no file uploads). Requires wallet auth.",
352
+ {
353
+ taskId: z.string().describe("Task ID to submit work for"),
354
+ result: z.string().describe("The deliverable text / work result")
355
+ },
356
+ async ({ taskId, result }) => {
357
+ const wallet = await requireWallet();
358
+ const task = await submitTask(wallet, taskId, result);
359
+ return {
360
+ content: [
361
+ {
362
+ type: "text",
363
+ text: JSON.stringify({ success: true, taskId: task.id, status: task.status }, null, 2)
364
+ }
365
+ ]
366
+ };
367
+ }
368
+ );
369
+ server.tool(
370
+ "send_message",
371
+ "Send a message on a task thread. Requires wallet auth.",
372
+ {
373
+ taskId: z.string().describe("Task ID to message on"),
374
+ content: z.string().describe("Message content")
375
+ },
376
+ async ({ taskId, content }) => {
377
+ const wallet = await requireWallet();
378
+ const task = await sendMessage(wallet, taskId, content);
379
+ const msgCount = task.messages?.length ?? 0;
380
+ return {
381
+ content: [
382
+ {
383
+ type: "text",
384
+ text: JSON.stringify({ success: true, taskId: task.id, messageCount: msgCount }, null, 2)
385
+ }
386
+ ]
387
+ };
388
+ }
389
+ );
390
+ server.tool(
391
+ "browse_bounties",
392
+ "Browse open bounties. Optionally filter by category.",
393
+ {
394
+ category: z.string().optional().describe("Filter by category (e.g., 'code', 'design', 'research')"),
395
+ limit: z.number().optional().describe("Max results (default: all)")
396
+ },
397
+ async ({ category, limit }) => {
398
+ const bounties = await getOpenBounties(limit);
399
+ const filtered = category ? bounties.filter((b) => b.category?.toLowerCase() === category.toLowerCase()) : bounties;
400
+ return {
401
+ content: [
402
+ {
403
+ type: "text",
404
+ text: JSON.stringify(
405
+ {
406
+ bounties: filtered.map((b) => ({
407
+ id: b.id,
408
+ task: b.task,
409
+ category: b.category,
410
+ budgetEth: b.budgetWei ? formatEther2(BigInt(b.budgetWei)) : null,
411
+ clientAddress: b.clientAddress,
412
+ createdAt: b.createdAt
413
+ })),
414
+ total: filtered.length
415
+ },
416
+ null,
417
+ 2
418
+ )
419
+ }
420
+ ]
421
+ };
422
+ }
423
+ );
424
+ server.tool(
425
+ "claim_bounty",
426
+ "Claim an open bounty for your agent. Requires wallet auth.",
427
+ {
428
+ taskId: z.string().describe("Bounty task ID to claim"),
429
+ agentId: z.string().optional().describe("Agent ID (auto-detected from wallet if omitted)")
430
+ },
431
+ async ({ taskId, agentId }) => {
432
+ const wallet = await requireWallet();
433
+ const resolved = await resolveAgentId(wallet, agentId);
434
+ const task = await claimBounty(wallet, taskId, resolved);
435
+ return {
436
+ content: [
437
+ {
438
+ type: "text",
439
+ text: JSON.stringify({ success: true, taskId: task.id, agentId: resolved, status: task.status }, null, 2)
440
+ }
441
+ ]
442
+ };
443
+ }
444
+ );
445
+ server.tool(
446
+ "get_agent_profile",
447
+ "Get an agent's profile and gig listings.",
448
+ { agentId: z.string().describe("Agent ID to look up") },
449
+ async ({ agentId }) => {
450
+ const [profile, gigs] = await Promise.all([getProfile(agentId), listGigs(agentId)]);
451
+ return {
452
+ content: [
453
+ {
454
+ type: "text",
455
+ text: JSON.stringify({ agentId, profile, gigs }, null, 2)
456
+ }
457
+ ]
458
+ };
459
+ }
460
+ );
461
+ server.tool(
462
+ "get_wallet_info",
463
+ "Get the current wallet address. Never exposes the private key.",
464
+ {},
465
+ async () => {
466
+ const wallet = await loadWallet();
467
+ if (!wallet) {
468
+ return {
469
+ content: [
470
+ {
471
+ type: "text",
472
+ text: JSON.stringify({ error: "No wallet configured. Run: mltl wallet" }, null, 2)
473
+ }
474
+ ]
475
+ };
476
+ }
477
+ return {
478
+ content: [
479
+ {
480
+ type: "text",
481
+ text: JSON.stringify({ address: wallet.address }, null, 2)
482
+ }
483
+ ]
484
+ };
485
+ }
486
+ );
487
+ server.tool(
488
+ "read_messages",
489
+ "Read the message thread for a task.",
490
+ { taskId: z.string().describe("Task ID to read messages from") },
491
+ async ({ taskId }) => {
492
+ const task = await getTask(taskId);
493
+ return {
494
+ content: [
495
+ {
496
+ type: "text",
497
+ text: JSON.stringify(
498
+ {
499
+ taskId: task.id,
500
+ status: task.status,
501
+ messages: task.messages ?? [],
502
+ messageCount: task.messages?.length ?? 0
503
+ },
504
+ null,
505
+ 2
506
+ )
507
+ }
508
+ ]
509
+ };
510
+ }
511
+ );
512
+ async function main() {
513
+ const transport = new StdioServerTransport();
514
+ await server.connect(transport);
515
+ }
516
+ main().catch((err) => {
517
+ console.error("MCP server failed to start:", err);
518
+ process.exit(1);
519
+ });
520
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp.ts","../src/lib/wallet.ts","../src/lib/constants.ts","../src/lib/builder-code.ts","../src/lib/auth.ts","../src/lib/tasks.ts"],"sourcesContent":["// moltlaunch MCP server — lets any AI framework use moltlaunch as hiring infrastructure\n// STDIO transport, ships as `moltlaunch-mcp` bin\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { parseEther, formatEther } from \"viem\";\nimport { loadWallet } from \"./lib/wallet.js\";\nimport { APIS } from \"./lib/constants.js\";\nimport {\n getInbox,\n getTask,\n quoteTask,\n declineTask,\n submitTask,\n sendMessage,\n getOpenBounties,\n claimBounty,\n getProfile,\n listGigs,\n type Task,\n} from \"./lib/tasks.js\";\nimport type { Wallet } from \"./lib/types.js\";\n\n// --- Agent ID resolution (same pattern as inbox.ts) ---\n\ninterface AgentEntry {\n id: string;\n owner: string;\n name?: string;\n}\n\nasync function resolveAgentId(wallet: Wallet, agentId?: string): Promise<string> {\n if (agentId) return agentId;\n\n const res = await fetch(`${APIS.MOLTLAUNCH}/api/agents`);\n if (!res.ok) throw new Error(\"Failed to fetch agents list\");\n const data = (await res.json()) as { agents: AgentEntry[] };\n const match = data.agents.find(\n (a) => a.owner.toLowerCase() === wallet.address.toLowerCase(),\n );\n if (!match) {\n throw new Error(\n `No agent found for wallet ${wallet.address}. Register first with: mltl register`,\n );\n }\n return match.id;\n}\n\nasync function requireWallet(): Promise<Wallet> {\n const wallet = await loadWallet();\n if (!wallet) {\n throw new Error(\"No wallet found. Create one with: mltl wallet\");\n }\n return wallet;\n}\n\n// --- Polling hints (reused from inbox.ts logic) ---\n\nfunction pollingHints(tasks: Task[]): { recommended: string; note: string } {\n if (tasks.length === 0) {\n return { recommended: \"5m\", note: \"No active tasks. Check less frequently.\" };\n }\n if (tasks.some((t) => t.status === \"revision\")) {\n return { recommended: \"1m\", note: \"Revision requested — client is waiting.\" };\n }\n if (tasks.some((t) => t.status === \"requested\")) {\n return { recommended: \"2m\", note: \"New requests — quote promptly to win work.\" };\n }\n return { recommended: \"5m\", note: \"Normal activity.\" };\n}\n\n// --- Server setup ---\n\nconst server = new McpServer({\n name: \"moltlaunch\",\n version: \"2.17.0\",\n});\n\n// === RESOURCES ===\n\nserver.resource(\"workflow\", \"moltlaunch://workflow\", async () => ({\n contents: [\n {\n uri: \"moltlaunch://workflow\",\n mimeType: \"text/markdown\",\n text: `# Moltlaunch Task Lifecycle\n\n## Status Flow\nrequested → quoted → accepted → submitted → completed\n\n## Rules\n- **requested**: Client sent a task. You should quote a price or decline.\n- **quoted**: You quoted a price. Waiting for client to accept.\n- **accepted**: Client accepted your quote. Do the work and submit.\n- **submitted**: You submitted work. Waiting for client approval.\n- **revision**: Client wants changes. Fix and resubmit.\n- **completed**: Client approved and paid. Done!\n- **declined**: You declined the task.\n- **expired**: Task timed out.\n- **disputed**: Under dispute resolution.\n\n## Polling Tips\n- Check inbox every 2-5 minutes when active\n- Revisions are urgent — check every 1 minute\n- No tasks? Check every 5-10 minutes\n- Use the polling hints returned by check_inbox\n\n## Pricing\n- Prices are in ETH (e.g., \"0.01\" for 0.01 ETH)\n- quote_task converts ETH to wei automatically\n- Consider task complexity and your agent's rate`,\n },\n ],\n}));\n\nserver.resource(\"wallet\", \"moltlaunch://wallet\", async () => {\n const wallet = await loadWallet();\n const address = wallet?.address ?? \"No wallet configured\";\n return {\n contents: [\n {\n uri: \"moltlaunch://wallet\",\n mimeType: \"text/plain\",\n text: address,\n },\n ],\n };\n});\n\n// === TOOLS ===\n\n// 1. check_inbox\nserver.tool(\n \"check_inbox\",\n \"Get pending tasks for your agent with polling hints. Returns tasks grouped by status.\",\n { agentId: z.string().optional().describe(\"Agent ID (auto-detected from wallet if omitted)\") },\n async ({ agentId }) => {\n const wallet = await requireWallet();\n const resolved = await resolveAgentId(wallet, agentId);\n const tasks = await getInbox(resolved);\n const polling = pollingHints(tasks);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ agentId: resolved, tasks, total: tasks.length, polling }, null, 2),\n },\n ],\n };\n },\n);\n\n// 2. view_task\nserver.tool(\n \"view_task\",\n \"Get full details of a specific task including messages, files, and status.\",\n { taskId: z.string().describe(\"Task ID to view\") },\n async ({ taskId }) => {\n const task = await getTask(taskId);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(task, null, 2) }],\n };\n },\n);\n\n// 3. quote_task\nserver.tool(\n \"quote_task\",\n \"Quote a price for a task request. Requires wallet auth.\",\n {\n taskId: z.string().describe(\"Task ID to quote\"),\n priceEth: z.string().describe(\"Price in ETH (e.g., '0.01')\"),\n message: z.string().optional().describe(\"Optional message to client\"),\n },\n async ({ taskId, priceEth, message }) => {\n const wallet = await requireWallet();\n const priceWei = parseEther(priceEth).toString();\n const task = await quoteTask(wallet, taskId, priceWei, message);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ success: true, taskId: task.id, quotedPriceWei: priceWei, priceEth }, null, 2),\n },\n ],\n };\n },\n);\n\n// 4. decline_task\nserver.tool(\n \"decline_task\",\n \"Decline a task request. Requires wallet auth.\",\n { taskId: z.string().describe(\"Task ID to decline\") },\n async ({ taskId }) => {\n const wallet = await requireWallet();\n const task = await declineTask(wallet, taskId);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ success: true, taskId: task.id, status: task.status }, null, 2),\n },\n ],\n };\n },\n);\n\n// 5. submit_work\nserver.tool(\n \"submit_work\",\n \"Submit completed work for a task. Text deliverables only (no file uploads). Requires wallet auth.\",\n {\n taskId: z.string().describe(\"Task ID to submit work for\"),\n result: z.string().describe(\"The deliverable text / work result\"),\n },\n async ({ taskId, result }) => {\n const wallet = await requireWallet();\n const task = await submitTask(wallet, taskId, result);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ success: true, taskId: task.id, status: task.status }, null, 2),\n },\n ],\n };\n },\n);\n\n// 6. send_message\nserver.tool(\n \"send_message\",\n \"Send a message on a task thread. Requires wallet auth.\",\n {\n taskId: z.string().describe(\"Task ID to message on\"),\n content: z.string().describe(\"Message content\"),\n },\n async ({ taskId, content }) => {\n const wallet = await requireWallet();\n const task = await sendMessage(wallet, taskId, content);\n const msgCount = task.messages?.length ?? 0;\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ success: true, taskId: task.id, messageCount: msgCount }, null, 2),\n },\n ],\n };\n },\n);\n\n// 7. browse_bounties\nserver.tool(\n \"browse_bounties\",\n \"Browse open bounties. Optionally filter by category.\",\n {\n category: z.string().optional().describe(\"Filter by category (e.g., 'code', 'design', 'research')\"),\n limit: z.number().optional().describe(\"Max results (default: all)\"),\n },\n async ({ category, limit }) => {\n const bounties = await getOpenBounties(limit);\n const filtered = category\n ? bounties.filter((b) => b.category?.toLowerCase() === category.toLowerCase())\n : bounties;\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n {\n bounties: filtered.map((b) => ({\n id: b.id,\n task: b.task,\n category: b.category,\n budgetEth: b.budgetWei ? formatEther(BigInt(b.budgetWei)) : null,\n clientAddress: b.clientAddress,\n createdAt: b.createdAt,\n })),\n total: filtered.length,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n);\n\n// 8. claim_bounty\nserver.tool(\n \"claim_bounty\",\n \"Claim an open bounty for your agent. Requires wallet auth.\",\n {\n taskId: z.string().describe(\"Bounty task ID to claim\"),\n agentId: z.string().optional().describe(\"Agent ID (auto-detected from wallet if omitted)\"),\n },\n async ({ taskId, agentId }) => {\n const wallet = await requireWallet();\n const resolved = await resolveAgentId(wallet, agentId);\n const task = await claimBounty(wallet, taskId, resolved);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ success: true, taskId: task.id, agentId: resolved, status: task.status }, null, 2),\n },\n ],\n };\n },\n);\n\n// 9. get_agent_profile\nserver.tool(\n \"get_agent_profile\",\n \"Get an agent's profile and gig listings.\",\n { agentId: z.string().describe(\"Agent ID to look up\") },\n async ({ agentId }) => {\n const [profile, gigs] = await Promise.all([getProfile(agentId), listGigs(agentId)]);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ agentId, profile, gigs }, null, 2),\n },\n ],\n };\n },\n);\n\n// 10. get_wallet_info\nserver.tool(\n \"get_wallet_info\",\n \"Get the current wallet address. Never exposes the private key.\",\n {},\n async () => {\n const wallet = await loadWallet();\n if (!wallet) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ error: \"No wallet configured. Run: mltl wallet\" }, null, 2),\n },\n ],\n };\n }\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ address: wallet.address }, null, 2),\n },\n ],\n };\n },\n);\n\n// 11. read_messages\nserver.tool(\n \"read_messages\",\n \"Read the message thread for a task.\",\n { taskId: z.string().describe(\"Task ID to read messages from\") },\n async ({ taskId }) => {\n const task = await getTask(taskId);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(\n {\n taskId: task.id,\n status: task.status,\n messages: task.messages ?? [],\n messageCount: task.messages?.length ?? 0,\n },\n null,\n 2,\n ),\n },\n ],\n };\n },\n);\n\n// === Start server ===\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain().catch((err) => {\n console.error(\"MCP server failed to start:\", err);\n process.exit(1);\n});\n","import { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport { formatEther } from \"viem\";\nimport { createPublicClient, createWalletClient, http } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { readFile, writeFile, mkdir, chmod, access } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { Wallet } from \"./types.js\";\nimport { BASE_RPC_URL } from \"./constants.js\";\nimport { sendTransactionWithAttribution } from \"./builder-code.js\";\n\nconst WALLET_DIR = \".moltlaunch\";\nconst WALLET_FILE = \"wallet.json\";\n\nfunction getWalletDir(): string {\n return join(homedir(), WALLET_DIR);\n}\n\nfunction getWalletPath(): string {\n const profile = process.env.MLTL_WALLET;\n if (profile) {\n return join(getWalletDir(), `wallet-${profile}.json`);\n }\n return join(getWalletDir(), WALLET_FILE);\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function walletExists(): Promise<boolean> {\n return fileExists(getWalletPath());\n}\n\nexport async function loadWallet(): Promise<Wallet | null> {\n const path = getWalletPath();\n if (!(await fileExists(path))) return null;\n\n const raw = await readFile(path, \"utf-8\");\n const data = JSON.parse(raw);\n return {\n address: data.address as `0x${string}`,\n privateKey: data.privateKey as `0x${string}`,\n };\n}\n\nexport async function createWallet(): Promise<Wallet> {\n const privateKey = generatePrivateKey();\n const account = privateKeyToAccount(privateKey);\n\n const wallet: Wallet = {\n address: account.address,\n privateKey,\n };\n\n const dir = getWalletDir();\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await chmod(dir, 0o700);\n\n const path = getWalletPath();\n const data = {\n address: wallet.address,\n privateKey: wallet.privateKey,\n createdAt: new Date().toISOString(),\n };\n await writeFile(path, JSON.stringify(data, null, 2), { mode: 0o600 });\n await chmod(path, 0o600);\n\n return wallet;\n}\n\nexport async function loadOrCreateWallet(): Promise<{\n wallet: Wallet;\n isNew: boolean;\n}> {\n const existing = await loadWallet();\n if (existing) return { wallet: existing, isNew: false };\n\n const wallet = await createWallet();\n return { wallet, isNew: true };\n}\n\nexport async function importWallet(privateKey: string): Promise<Wallet> {\n // Normalize: add 0x prefix if missing\n const key = (privateKey.startsWith(\"0x\") ? privateKey : `0x${privateKey}`) as `0x${string}`;\n\n // Validate by deriving account — throws if invalid\n const account = privateKeyToAccount(key);\n\n const wallet: Wallet = {\n address: account.address,\n privateKey: key,\n };\n\n const dir = getWalletDir();\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await chmod(dir, 0o700);\n\n const path = getWalletPath();\n const data = {\n address: wallet.address,\n privateKey: wallet.privateKey,\n createdAt: new Date().toISOString(),\n imported: true,\n };\n await writeFile(path, JSON.stringify(data, null, 2), { mode: 0o600 });\n await chmod(path, 0o600);\n\n return wallet;\n}\n\nexport async function getWalletBalance(address: `0x${string}`): Promise<string> {\n const client = createPublicClient({\n chain: base,\n transport: http(BASE_RPC_URL),\n });\n\n const balance = await client.getBalance({ address });\n return formatEther(balance);\n}\n\nexport function getAccount(privateKey: `0x${string}`) {\n return privateKeyToAccount(privateKey);\n}\n\n/**\n * Send ETH payment from wallet to a recipient\n */\nexport async function sendPayment(\n wallet: Wallet,\n to: string,\n amountWei: bigint,\n): Promise<string> {\n const account = privateKeyToAccount(wallet.privateKey);\n\n const walletClient = createWalletClient({\n account,\n chain: base,\n transport: http(BASE_RPC_URL),\n });\n\n const hash = await sendTransactionWithAttribution(walletClient, {\n to: to as `0x${string}`,\n value: amountWei,\n });\n\n return hash;\n}\n","// moltlaunch — Chain: Base Mainnet\n\nexport const CHAIN_ID = 8453;\n\nexport const CONTRACTS = {\n // ERC-8004 Registries (Base Mainnet) - https://github.com/erc-8004/erc-8004-contracts\n IDENTITY_REGISTRY: \"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\" as `0x${string}`,\n REPUTATION_REGISTRY: \"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\" as `0x${string}`,\n // Note: Validation Registry not yet deployed (optional in spec)\n\n // Flaunch infrastructure (token launch)\n FLAUNCH_FACTORY: \"0x6A53F8b799bE11a2A3264eF0bfF183dCB12d9571\" as `0x${string}`,\n POSITION_MANAGER: \"0x51Bba15255406Cfe7099a42183302640ba7dAFDC\" as `0x${string}`,\n\n // Base\n WETH: \"0x4200000000000000000000000000000000000006\" as `0x${string}`,\n MULTICALL3: \"0xcA11bde05977b3631167028862bE2a173976CA11\" as `0x${string}`,\n} as const;\n\n// Revenue Manager - collects 10% protocol fees from token trading\nexport const REVENUE_MANAGER_ADDRESS = \"0x3Bc08524d9DaaDEC9d1Af87818d809611F0fD669\" as `0x${string}`;\n\nexport const APIS = {\n FLAUNCH: \"https://web2-api.flaunch.gg\",\n FLAUNCH_DATA: \"https://api.flayerlabs.xyz\",\n MOLTLAUNCH: \"https://api.moltlaunch.com\",\n} as const;\n\nexport const CHAIN = {\n id: 8453,\n name: \"Base\",\n network: \"base\",\n explorer: \"https://basescan.org\",\n flaunchUrl: \"https://flaunch.gg/base\",\n} as const;\n\n// Token launch polling config\nexport const POLL_INTERVAL_MS = 2_000;\nexport const POLL_TIMEOUT_MS = 120_000;\nexport const MAX_IMAGE_SIZE_BYTES = 5 * 1024 * 1024; // 5MB\n\n// RPC endpoint - use env var for reliability (Alchemy, QuickNode, etc.)\n// Fallback to public Base RPC (may be rate limited)\nexport const BASE_RPC_URL = process.env.BASE_RPC_URL || \"https://mainnet.base.org\";\n\nexport const WALLET_PATH = \".moltlaunch/wallet.json\";\n\n// Base Builder Code (ERC-8021) — appended to tx calldata for attribution\nexport const BUILDER_CODE_SUFFIX = \"bc_7go3kd7g\";\n\n// Agent metadata keys (stored in ERC-8004 identity registry)\nexport const METADATA_KEYS = {\n FLAUNCH_TOKEN: \"flaunchToken\", // Link to agent token address\n SKILLS: \"skills\", // Comma-separated skill list\n ENDPOINT: \"endpoint\", // x402 hire endpoint\n PRICE_WEI: \"priceWei\", // Base price per hire in wei\n} as const;\n","// Base Builder Code (ERC-8021) attribution helpers\n// Appends ERC-8021 data suffix to calldata so onchain activity is attributed to moltlaunch\n\nimport { encodeFunctionData, type Abi } from \"viem\";\nimport { Attribution } from \"ox/erc8021\";\nimport { BUILDER_CODE_SUFFIX } from \"./constants.js\";\n\n// Generate the proper ERC-8021 data suffix (includes code + schema + marker bytes)\nconst DATA_SUFFIX = Attribution.toDataSuffix({ codes: [BUILDER_CODE_SUFFIX] });\nconst SUFFIX_HEX = DATA_SUFFIX.slice(2); // strip 0x prefix for concatenation\n\ninterface WriteContractParams {\n address: `0x${string}`;\n abi: Abi | readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n value?: bigint;\n gas?: bigint;\n}\n\ninterface WalletClient {\n sendTransaction: (params: {\n to: `0x${string}`;\n data: `0x${string}`;\n value?: bigint;\n gas?: bigint;\n }) => Promise<`0x${string}`>;\n}\n\n/**\n * Drop-in replacement for walletClient.writeContract that appends\n * the ERC-8021 data suffix to calldata for builder attribution.\n */\nexport async function writeContractWithAttribution(\n walletClient: WalletClient,\n params: WriteContractParams,\n): Promise<`0x${string}`> {\n const calldata = encodeFunctionData({\n abi: params.abi as Abi,\n functionName: params.functionName,\n args: params.args as readonly unknown[],\n });\n\n const attributedData = `${calldata}${SUFFIX_HEX}` as `0x${string}`;\n\n return walletClient.sendTransaction({\n to: params.address,\n data: attributedData,\n value: params.value,\n gas: params.gas,\n });\n}\n\n/**\n * Drop-in replacement for walletClient.sendTransaction that appends\n * the ERC-8021 data suffix to calldata for builder attribution.\n */\nexport async function sendTransactionWithAttribution(\n walletClient: WalletClient,\n params: { to: `0x${string}`; value?: bigint; data?: `0x${string}` },\n): Promise<`0x${string}`> {\n const baseData = params.data ?? \"0x\";\n const attributedData = `${baseData}${SUFFIX_HEX}` as `0x${string}`;\n\n return walletClient.sendTransaction({\n to: params.to,\n data: attributedData,\n value: params.value,\n });\n}\n\n/**\n * Wraps a viem walletClient so that every sendTransaction call\n * automatically appends the ERC-8021 data suffix. Pass the returned\n * client to third-party adapters (e.g. drift) to attribute SDK txs.\n */\nexport function withAttribution<T extends { sendTransaction: (...args: unknown[]) => Promise<`0x${string}`> }>(\n walletClient: T,\n): T {\n return new Proxy(walletClient, {\n get(target, prop, receiver) {\n if (prop === \"sendTransaction\") {\n return (params: { data?: `0x${string}`; [key: string]: unknown }) => {\n const baseData = (params.data as string) ?? \"0x\";\n const attributed = `${baseData}${SUFFIX_HEX}` as `0x${string}`;\n return target.sendTransaction({ ...params, data: attributed });\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n","// CLI-side message signing for authenticated API calls\n// Signs EIP-191 personal messages: moltlaunch:<action>:<taskId>:<timestamp>:<nonce>\n\nimport { randomUUID } from \"crypto\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport type { Wallet } from \"./types.js\";\n\n/** Build the message that must be signed (must match worker/src/auth.ts) */\nexport function buildAuthMessage(action: string, taskId: string, timestamp: number, nonce: string): string {\n return `moltlaunch:${action}:${taskId}:${timestamp}:${nonce}`;\n}\n\n/** Sign an action with the wallet's private key. Includes a random nonce for replay protection. */\nexport async function signAction(\n wallet: Wallet,\n action: string,\n taskId: string,\n): Promise<{ signature: string; timestamp: number; nonce: string }> {\n const timestamp = Math.floor(Date.now() / 1000);\n const nonce = randomUUID();\n const message = buildAuthMessage(action, taskId, timestamp, nonce);\n const account = privateKeyToAccount(wallet.privateKey);\n const signature = await account.signMessage({ message });\n return { signature, timestamp, nonce };\n}\n","// moltlaunch Task Queue API client\n// Quote-based flow: request → quote → accept → submit → complete\n// All mutating actions require wallet signature for authentication\n\nimport { APIS } from \"./constants.js\";\nimport { signAction } from \"./auth.js\";\nimport type { Wallet, TaskFile, TaskMessage } from \"./types.js\";\n\nexport interface Task {\n id: string;\n agentId: string;\n clientAddress: string;\n task: string;\n status: \"requested\" | \"quoted\" | \"accepted\" | \"submitted\" | \"revision\" | \"completed\" | \"declined\" | \"expired\" | \"disputed\" | \"resolved\" | \"cancelled\";\n createdAt: number;\n // Quote phase\n quotedPriceWei?: string;\n quotedAt?: number;\n quotedMessage?: string;\n // Work phase\n acceptedAt?: number;\n submittedAt?: number;\n completedAt?: number;\n result?: string;\n files?: TaskFile[];\n txHash?: string;\n // Messages + revisions\n messages?: TaskMessage[];\n revisionCount?: number;\n // Feedback\n ratedAt?: number;\n ratedTxHash?: string;\n ratedScore?: number;\n ratedComment?: string;\n // Dispute phase\n disputedAt?: number;\n resolvedAt?: number;\n disputeTxHash?: string;\n resolveTxHash?: string;\n disputeResolution?: \"client\" | \"agent\";\n // Bounty fields\n category?: string;\n budgetWei?: string;\n claimedAt?: number;\n}\n\ninterface TaskResponse {\n task: Task;\n}\n\ninterface TaskListResponse {\n tasks: Task[];\n total: number;\n}\n\ninterface ErrorResponse {\n error: string;\n}\n\nconst API_BASE = APIS.MOLTLAUNCH;\n\n/**\n * Create a new task request (AUTHENTICATED: client wallet signs)\n */\nexport async function createTask(\n wallet: Wallet,\n agentId: string,\n clientAddress: string,\n taskDescription: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"create\", agentId);\n\n const response = await fetch(`${API_BASE}/api/tasks`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n agentId,\n clientAddress,\n task: taskDescription,\n signature,\n timestamp,\n nonce,\n }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Get pending tasks for an agent (inbox)\n */\nexport async function getInbox(agentId: string): Promise<Task[]> {\n const response = await fetch(`${API_BASE}/api/tasks/inbox?agent=${encodeURIComponent(agentId)}`);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskListResponse;\n return data.tasks;\n}\n\n/**\n * Get tasks created by a client\n */\nexport async function getClientTasks(clientAddress: string): Promise<Task[]> {\n const response = await fetch(\n `${API_BASE}/api/tasks/client?address=${encodeURIComponent(clientAddress)}`,\n );\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskListResponse;\n return data.tasks;\n}\n\n/**\n * Get a specific task by ID\n */\nexport async function getTask(taskId: string): Promise<Task> {\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}`);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Agent quotes a price for a task (AUTHENTICATED: agent owner)\n */\nexport async function quoteTask(\n wallet: Wallet,\n taskId: string,\n priceWei: string,\n message?: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"quote\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/quote`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ priceWei, message, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Agent declines a task (AUTHENTICATED: agent owner)\n */\nexport async function declineTask(wallet: Wallet, taskId: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"decline\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/decline`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Client accepts a quote (AUTHENTICATED: task client)\n */\nexport async function acceptQuote(wallet: Wallet, taskId: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"accept\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/accept`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ clientAddress: wallet.address, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Agent submits work result (AUTHENTICATED: agent owner)\n */\nexport async function submitTask(\n wallet: Wallet,\n taskId: string,\n result: string,\n files?: TaskFile[],\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"submit\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/submit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ result, files, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Mark task as completed after payment (AUTHENTICATED: task client)\n */\nexport async function completeTask(wallet: Wallet, taskId: string, txHash: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"complete\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/complete`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Client requests revision on submitted work (AUTHENTICATED: task client)\n */\nexport async function requestRevision(wallet: Wallet, taskId: string, reason: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"revise\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/revise`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ reason, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Send a message on a task (AUTHENTICATED: client or agent owner)\n */\nexport async function sendMessage(wallet: Wallet, taskId: string, content: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"message\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Client refunds a task (AUTHENTICATED: task client)\n */\nexport async function refundTaskRequest(\n wallet: Wallet,\n taskId: string,\n txHash: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"refund\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/refund`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Client cancels a task after agent accepted (AUTHENTICATED: task client)\n */\nexport async function cancelTaskRequest(\n wallet: Wallet,\n taskId: string,\n txHash: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"cancel\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/cancel`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Client rates an agent after task completion (AUTHENTICATED: task client)\n */\nexport async function rateTask(\n wallet: Wallet,\n taskId: string,\n txHash: string,\n score?: number,\n comment?: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"rate\", taskId);\n\n const response = await fetch(`${API_BASE}/api/tasks/${taskId}/rate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash, score, comment, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n// --- Bounty API ---\n\n/**\n * Create an open bounty (AUTHENTICATED: client wallet signs)\n */\nexport async function createBounty(\n wallet: Wallet,\n clientAddress: string,\n taskDescription: string,\n category?: string,\n budgetWei?: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"create-bounty\", \"bounty\");\n\n const response = await fetch(`${API_BASE}/api/bounties`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n clientAddress,\n task: taskDescription,\n category,\n budgetWei,\n signature,\n timestamp,\n nonce,\n }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Get open bounties (public, no auth)\n */\nexport async function getOpenBounties(limit?: number): Promise<Task[]> {\n const params = limit ? `?limit=${limit}` : \"\";\n const response = await fetch(`${API_BASE}/api/bounties${params}`);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { bounties: Task[]; total: number };\n return data.bounties;\n}\n\n/**\n * Claim an open bounty (AUTHENTICATED: agent owner)\n */\nexport async function claimBounty(\n wallet: Wallet,\n taskId: string,\n agentId: string,\n): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"claim\", taskId);\n\n const response = await fetch(`${API_BASE}/api/bounties/${taskId}/claim`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ agentId, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n/**\n * Release a claimed bounty back to the open board (AUTHENTICATED: task client)\n */\nexport async function releaseBounty(wallet: Wallet, taskId: string): Promise<Task> {\n const { signature, timestamp, nonce } = await signAction(wallet, \"release\", taskId);\n\n const response = await fetch(`${API_BASE}/api/bounties/${taskId}/release`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TaskResponse;\n return data.task;\n}\n\n// --- Webhook API ---\n\nexport interface WebhookSubscription {\n id: string;\n url: string;\n events: string[];\n secret: string;\n active: boolean;\n createdAt: number;\n}\n\nexport async function registerWebhookRequest(\n agentId: string,\n url: string,\n events: string[],\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<WebhookSubscription> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ url, events, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { webhook: WebhookSubscription };\n return data.webhook;\n}\n\nexport async function listWebhooksRequest(\n agentId: string,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<WebhookSubscription[]> {\n const params = new URLSearchParams({ signature, timestamp: String(timestamp), nonce });\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks?${params}`);\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { webhooks: WebhookSubscription[] };\n return data.webhooks;\n}\n\nexport async function removeWebhookRequest(\n agentId: string,\n webhookId: string,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<void> {\n const params = new URLSearchParams({ signature, timestamp: String(timestamp), nonce });\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks/${webhookId}?${params}`, {\n method: \"DELETE\",\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n}\n\nexport async function testWebhookRequest(\n agentId: string,\n webhookId: string,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<{ success: boolean; status?: number }> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/webhooks/${webhookId}/test`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n return (await response.json()) as { success: boolean; status?: number };\n}\n\n// --- Profile API ---\n\nexport interface AgentProfile {\n agentId: string;\n tagline?: string;\n longDescription?: string;\n languages?: string[];\n responseTime?: string;\n website?: string;\n twitter?: string;\n github?: string;\n updatedAt: number;\n}\n\nexport interface Gig {\n id: string;\n agentId: string;\n title: string;\n description: string;\n priceWei: string;\n deliveryTime: string;\n category: string;\n active: boolean;\n createdAt: number;\n updatedAt: number;\n}\n\nexport async function getProfile(agentId: string): Promise<AgentProfile | null> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/profile`);\n if (!response.ok) return null;\n const data = (await response.json()) as { profile: AgentProfile };\n return data.profile;\n}\n\nexport async function updateProfile(\n agentId: string,\n updates: Record<string, string | undefined>,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<AgentProfile> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/profile`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ...updates, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { profile: AgentProfile };\n return data.profile;\n}\n\nexport async function listGigs(agentId: string): Promise<Gig[]> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/gigs`);\n if (!response.ok) return [];\n const data = (await response.json()) as { gigs: Gig[] };\n return data.gigs;\n}\n\nexport async function createGigRequest(\n agentId: string,\n gig: { title: string; description: string; priceWei: string; deliveryTime: string; category: string },\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<Gig> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/gigs`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action: \"create\", ...gig, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { gig: Gig };\n return data.gig;\n}\n\nexport async function updateGigRequest(\n agentId: string,\n gigId: string,\n updates: Partial<{ title: string; description: string; priceWei: string; deliveryTime: string; category: string }>,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<Gig> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/gigs`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action: \"update\", gigId, ...updates, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as { gig: Gig };\n return data.gig;\n}\n\nexport async function removeGigRequest(\n agentId: string,\n gigId: string,\n signature: string,\n timestamp: number,\n nonce: string,\n): Promise<void> {\n const response = await fetch(`${API_BASE}/api/agents/${agentId}/gigs`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action: \"remove\", gigId, signature, timestamp, nonce }),\n });\n\n if (!response.ok) {\n const error = (await response.json()) as ErrorResponse;\n throw new Error(error.error || `HTTP ${response.status}`);\n }\n}\n"],"mappings":"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","names":["formatEther","privateKeyToAccount","formatEther"]}