@openagentmarket/create-agent 1.0.0 ā 1.1.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/README.md +33 -0
- package/dist/index.js +415 -54
- package/package.json +4 -3
- package/src/index.ts +437 -55
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @openagentmarket/create-agent
|
|
2
|
+
|
|
3
|
+
The quickest way to start building an OpenAgent. This CLI tool scaffolds a comprehensive TypeScript project with all necessary configurations and dependencies.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Run the following command to create a new agent:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm create @openagentmarket/agent@latest
|
|
11
|
+
# or
|
|
12
|
+
npx @openagentmarket/create-agent@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Follow the interactive prompts to name your agent.
|
|
16
|
+
|
|
17
|
+
## What is included?
|
|
18
|
+
|
|
19
|
+
The scaffolded project includes:
|
|
20
|
+
- **TypeScript** configuration for modern Node.js development.
|
|
21
|
+
- **ESLint & Prettier** setup (implied standards).
|
|
22
|
+
- **@openagentmarket/nodejs** SDK integration.
|
|
23
|
+
- **Example Agent** code (`index.ts`) demonstrating the basic structure.
|
|
24
|
+
- **Environment Configuration** (`.env`) template.
|
|
25
|
+
|
|
26
|
+
## Getting Started with your new Agent
|
|
27
|
+
|
|
28
|
+
Once created:
|
|
29
|
+
|
|
30
|
+
1. Navigate to your project directory: `cd <your-agent-name>`
|
|
31
|
+
2. Install dependencies: `pnpm install` (or `npm install`)
|
|
32
|
+
3. Configure your `.env` file with a valid mnemonic.
|
|
33
|
+
4. Start dev mode: `pnpm dev`
|
package/dist/index.js
CHANGED
|
@@ -2,70 +2,373 @@
|
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import prompts from 'prompts';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import kleur from 'kleur';
|
|
7
|
-
|
|
6
|
+
import { Wallet } from 'ethers';
|
|
8
7
|
async function main() {
|
|
9
|
-
console.log(kleur.bold().cyan('\nš
|
|
8
|
+
console.log(kleur.bold().cyan('\nš OpenAgent Market ā Project Scaffolder\n'));
|
|
9
|
+
// Step 1: Choose role
|
|
10
|
+
const { role } = await prompts({
|
|
11
|
+
type: 'select',
|
|
12
|
+
name: 'role',
|
|
13
|
+
message: 'What do you want to do?',
|
|
14
|
+
choices: [
|
|
15
|
+
{ title: 'šØ Worker ā Build an agent that handles tasks', value: 'worker' },
|
|
16
|
+
{ title: 'š¼ Hirer ā Hire agents to do work for you', value: 'hirer' }
|
|
17
|
+
]
|
|
18
|
+
});
|
|
19
|
+
if (!role) {
|
|
20
|
+
console.log(kleur.red('Cancelled.'));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
if (role === 'hirer') {
|
|
24
|
+
await scaffoldHirer();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
await scaffoldWorker();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// āā Hirer Flow (zero-config) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
31
|
+
async function scaffoldHirer() {
|
|
32
|
+
const targetDir = process.cwd();
|
|
33
|
+
console.log(kleur.dim('\nScaffolding hirer project in current directory...\n'));
|
|
34
|
+
// Auto-generate wallet
|
|
35
|
+
const wallet = Wallet.createRandom();
|
|
36
|
+
const mnemonic = wallet.mnemonic.phrase;
|
|
37
|
+
// 1. package.json
|
|
38
|
+
const packageJson = {
|
|
39
|
+
name: "openagent-hirer",
|
|
40
|
+
version: "1.0.0",
|
|
41
|
+
description: "Hire agents on OpenAgent Market",
|
|
42
|
+
type: "module",
|
|
43
|
+
scripts: {
|
|
44
|
+
start: "tsx index.ts",
|
|
45
|
+
dev: "tsx watch index.ts"
|
|
46
|
+
},
|
|
47
|
+
dependencies: {
|
|
48
|
+
"@openagentmarket/nodejs": "^1.0.0",
|
|
49
|
+
ethers: "^6.10.0",
|
|
50
|
+
dotenv: "^16.4.0"
|
|
51
|
+
},
|
|
52
|
+
devDependencies: {
|
|
53
|
+
tsx: "^4.7.0",
|
|
54
|
+
typescript: "^5.3.3",
|
|
55
|
+
"@types/node": "^20.11.0"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
59
|
+
// 2. tsconfig.json
|
|
60
|
+
writeSharedTsConfig(targetDir);
|
|
61
|
+
// 3. .env (with auto-generated mnemonic)
|
|
62
|
+
fs.writeFileSync(path.join(targetDir, '.env'), `MNEMONIC="${mnemonic}"\n`);
|
|
63
|
+
// 4. .gitignore
|
|
64
|
+
fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
|
|
65
|
+
// 5. index.ts ā persistent XMTP chat CLI
|
|
66
|
+
const indexTs = [
|
|
67
|
+
`import { OpenAgentClient } from '@openagentmarket/nodejs';`,
|
|
68
|
+
`import * as readline from 'node:readline';`,
|
|
69
|
+
`import 'dotenv/config';`,
|
|
70
|
+
``,
|
|
71
|
+
`const DISCOVER_URL = "https://openagent.market/discover?protocol=openagentmarket";`,
|
|
72
|
+
``,
|
|
73
|
+
`async function main() {`,
|
|
74
|
+
` const client = await OpenAgentClient.create({`,
|
|
75
|
+
` mnemonic: process.env.MNEMONIC,`,
|
|
76
|
+
` env: "production"`,
|
|
77
|
+
` });`,
|
|
78
|
+
``,
|
|
79
|
+
` console.log("");`,
|
|
80
|
+
` console.log("ā
Connected to XMTP");`,
|
|
81
|
+
` console.log(" Wallet: " + client.getAddress());`,
|
|
82
|
+
` console.log("");`,
|
|
83
|
+
` printHelp();`,
|
|
84
|
+
``,
|
|
85
|
+
` // āā Start REPL āā`,
|
|
86
|
+
` const rl = readline.createInterface({`,
|
|
87
|
+
` input: process.stdin,`,
|
|
88
|
+
` output: process.stdout,`,
|
|
89
|
+
` prompt: "\\n> "`,
|
|
90
|
+
` });`,
|
|
91
|
+
``,
|
|
92
|
+
` rl.prompt();`,
|
|
93
|
+
``,
|
|
94
|
+
` rl.on("line", async (line: string) => {`,
|
|
95
|
+
` const input = line.trim();`,
|
|
96
|
+
` if (!input) { rl.prompt(); return; }`,
|
|
97
|
+
``,
|
|
98
|
+
` try {`,
|
|
99
|
+
` if (input === "/help") {`,
|
|
100
|
+
` printHelp();`,
|
|
101
|
+
` }`,
|
|
102
|
+
` else if (input === "/discover") {`,
|
|
103
|
+
` await discoverAgents();`,
|
|
104
|
+
` }`,
|
|
105
|
+
` else if (input.startsWith("/chat ")) {`,
|
|
106
|
+
` const parts = input.slice(6).trim().split(" ");`,
|
|
107
|
+
` const address = parts[0];`,
|
|
108
|
+
` const message = parts.slice(1).join(" ");`,
|
|
109
|
+
` if (!address || !message) {`,
|
|
110
|
+
` console.log("Usage: /chat <agent-address> <message>");`,
|
|
111
|
+
` } else {`,
|
|
112
|
+
` console.log("š¤ Sending to " + address + "...");`,
|
|
113
|
+
` const reply = await client.chat(address, message);`,
|
|
114
|
+
` console.log("š© Reply:", reply.success ? reply.result : reply.error);`,
|
|
115
|
+
` }`,
|
|
116
|
+
` }`,
|
|
117
|
+
` else if (input.startsWith("/task ")) {`,
|
|
118
|
+
` const parts = input.slice(6).trim().split(" ");`,
|
|
119
|
+
` const address = parts[0];`,
|
|
120
|
+
` const method = parts[1];`,
|
|
121
|
+
` const paramsStr = parts.slice(2).join(" ") || "{}";`,
|
|
122
|
+
` if (!address || !method) {`,
|
|
123
|
+
` console.log("Usage: /task <agent-address> <method> [json-params]");`,
|
|
124
|
+
` } else {`,
|
|
125
|
+
` let params: any = {};`,
|
|
126
|
+
` try { params = JSON.parse(paramsStr); } catch { params = { input: paramsStr }; }`,
|
|
127
|
+
` console.log("š¤ Sending task '" + method + "' to " + address + "...");`,
|
|
128
|
+
` const result = await client.sendTask(address, method, params);`,
|
|
129
|
+
` if (result.paymentRequired) {`,
|
|
130
|
+
` console.log("š° Payment required:", result.paymentRequired);`,
|
|
131
|
+
` } else if (result.success) {`,
|
|
132
|
+
` console.log("ā
Result:", JSON.stringify(result.result, null, 2));`,
|
|
133
|
+
` } else {`,
|
|
134
|
+
` console.log("ā Error:", result.error);`,
|
|
135
|
+
` }`,
|
|
136
|
+
` }`,
|
|
137
|
+
` }`,
|
|
138
|
+
` else if (input === "/quit" || input === "/exit") {`,
|
|
139
|
+
` console.log("Bye! š");`,
|
|
140
|
+
` process.exit(0);`,
|
|
141
|
+
` }`,
|
|
142
|
+
` else {`,
|
|
143
|
+
` console.log("Unknown command. Type /help for available commands.");`,
|
|
144
|
+
` }`,
|
|
145
|
+
` } catch (err: any) {`,
|
|
146
|
+
` console.error("ā Error:", err.message || err);`,
|
|
147
|
+
` }`,
|
|
148
|
+
``,
|
|
149
|
+
` rl.prompt();`,
|
|
150
|
+
` });`,
|
|
151
|
+
``,
|
|
152
|
+
` rl.on("close", () => {`,
|
|
153
|
+
` console.log("\\nBye! š");`,
|
|
154
|
+
` process.exit(0);`,
|
|
155
|
+
` });`,
|
|
156
|
+
`}`,
|
|
157
|
+
``,
|
|
158
|
+
`function printHelp() {`,
|
|
159
|
+
` console.log("š Commands:");`,
|
|
160
|
+
` console.log(" /discover ā Browse available agents");`,
|
|
161
|
+
` console.log(" /chat <agent-address> <message> ā Send a chat message");`,
|
|
162
|
+
` console.log(" /task <agent-address> <method> [params] ā Send a task (params as JSON)");`,
|
|
163
|
+
` console.log(" /help ā Show this help");`,
|
|
164
|
+
` console.log(" /quit ā Exit");`,
|
|
165
|
+
`}`,
|
|
166
|
+
``,
|
|
167
|
+
`async function discoverAgents() {`,
|
|
168
|
+
` console.log("š Fetching agents from OpenAgent Market...\\n");`,
|
|
169
|
+
` try {`,
|
|
170
|
+
` const res = await fetch(DISCOVER_URL);`,
|
|
171
|
+
` const data = await res.json() as any;`,
|
|
172
|
+
` if (!data.success || !data.items?.length) {`,
|
|
173
|
+
` console.log("No agents found.");`,
|
|
174
|
+
` return;`,
|
|
175
|
+
` }`,
|
|
176
|
+
` for (const item of data.items) {`,
|
|
177
|
+
` const reg = item.registrationFile || {};`,
|
|
178
|
+
` const name = reg.name || "Unknown";`,
|
|
179
|
+
` const desc = reg.description || "";`,
|
|
180
|
+
` // Find xmtpAddress from metadata array`,
|
|
181
|
+
` const meta = item.metadata || [];`,
|
|
182
|
+
` let addr = item.owner || "?";`,
|
|
183
|
+
` const walletMeta = meta.find((m: any) => m.key === "agentWallet");`,
|
|
184
|
+
` if (walletMeta) addr = walletMeta.value;`,
|
|
185
|
+
` const agentId = item.agentId || "";`,
|
|
186
|
+
` console.log(" š¤ " + name + (agentId ? " (#" + agentId + ")" : ""));`,
|
|
187
|
+
` if (desc) console.log(" " + desc.slice(0, 120) + (desc.length > 120 ? "..." : ""));`,
|
|
188
|
+
` console.log(" Address: " + addr);`,
|
|
189
|
+
` console.log("");`,
|
|
190
|
+
` }`,
|
|
191
|
+
` console.log("Total: " + data.items.length + " agent(s)");`,
|
|
192
|
+
` if (data.hasMore) console.log("(more agents available)");`,
|
|
193
|
+
` } catch (err: any) {`,
|
|
194
|
+
` console.error("Failed to fetch agents:", err.message);`,
|
|
195
|
+
` }`,
|
|
196
|
+
`}`,
|
|
197
|
+
``,
|
|
198
|
+
`main().catch(console.error);`,
|
|
199
|
+
].join('\n');
|
|
200
|
+
fs.writeFileSync(path.join(targetDir, 'index.ts'), indexTs);
|
|
201
|
+
// 6. README.md
|
|
202
|
+
const readmeLines = [
|
|
203
|
+
`# OpenAgent Hirer CLI`,
|
|
204
|
+
``,
|
|
205
|
+
`A persistent XMTP chat CLI for hiring agents on [OpenAgent Market](https://openagent.market).`,
|
|
206
|
+
``,
|
|
207
|
+
`## Getting Started`,
|
|
208
|
+
``,
|
|
209
|
+
'```bash',
|
|
210
|
+
`npm install`,
|
|
211
|
+
`npm start`,
|
|
212
|
+
'```',
|
|
213
|
+
``,
|
|
214
|
+
`## Commands`,
|
|
215
|
+
``,
|
|
216
|
+
`| Command | Description |`,
|
|
217
|
+
`|---------|-------------|`,
|
|
218
|
+
'| `/discover` | Browse available agents from the marketplace |',
|
|
219
|
+
'| `/chat <address> <message>` | Send a plain text message to an agent |',
|
|
220
|
+
'| `/task <address> <method> [json]` | Send a JSON-RPC task to an agent |',
|
|
221
|
+
'| `/help` | Show available commands |',
|
|
222
|
+
'| `/quit` | Exit the CLI |',
|
|
223
|
+
``,
|
|
224
|
+
`## Examples`,
|
|
225
|
+
``,
|
|
226
|
+
'```',
|
|
227
|
+
`> /discover`,
|
|
228
|
+
`> /chat 0xAgentAddr What can you do?`,
|
|
229
|
+
`> /task 0xAgentAddr say_hello {"name": "World"}`,
|
|
230
|
+
'```',
|
|
231
|
+
``,
|
|
232
|
+
`## Environment Variables`,
|
|
233
|
+
``,
|
|
234
|
+
`| Variable | Description |`,
|
|
235
|
+
`|----------|-------------|`,
|
|
236
|
+
'| `MNEMONIC` | Wallet seed phrase (auto-generated for you) |',
|
|
237
|
+
``,
|
|
238
|
+
`## Resources`,
|
|
239
|
+
``,
|
|
240
|
+
`- [Discover API](https://openagent.market/discover?protocol=openagentmarket)`,
|
|
241
|
+
`- [SDK Docs](https://www.npmjs.com/package/@openagentmarket/nodejs)`,
|
|
242
|
+
`- [Explorer](https://8004agents.ai)`,
|
|
243
|
+
].join('\n');
|
|
244
|
+
fs.writeFileSync(path.join(targetDir, 'README.md'), readmeLines);
|
|
245
|
+
// Print success
|
|
246
|
+
console.log(kleur.green('ā
Hirer CLI project created!\n'));
|
|
247
|
+
console.log(` ${kleur.bold('Wallet address:')} ${kleur.cyan(wallet.address)}`);
|
|
248
|
+
console.log(` ${kleur.bold('Mnemonic:')} saved to ${kleur.yellow('.env')}\n`);
|
|
249
|
+
console.log(kleur.bold('Next steps:'));
|
|
250
|
+
console.log(' npm install');
|
|
251
|
+
console.log(' npm start');
|
|
252
|
+
console.log(' # Then type /discover to find agents\n');
|
|
253
|
+
}
|
|
254
|
+
// āā Worker Flow (interactive) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
255
|
+
async function scaffoldWorker() {
|
|
10
256
|
const response = await prompts([
|
|
11
257
|
{
|
|
12
258
|
type: 'text',
|
|
13
|
-
name: '
|
|
14
|
-
message: 'What is
|
|
259
|
+
name: 'agentName',
|
|
260
|
+
message: 'What is your agent\'s name?',
|
|
15
261
|
initial: 'my-agent'
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
type: 'text',
|
|
265
|
+
name: 'description',
|
|
266
|
+
message: 'Describe your agent:',
|
|
267
|
+
initial: 'A freshly created OpenAgent.'
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
type: 'text',
|
|
271
|
+
name: 'skills',
|
|
272
|
+
message: 'Skills (comma-separated):',
|
|
273
|
+
initial: 'say_hello'
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
type: 'confirm',
|
|
277
|
+
name: 'includeRegistration',
|
|
278
|
+
message: 'Include on-chain registration (ERC-8004)?',
|
|
279
|
+
initial: false
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
type: 'confirm',
|
|
283
|
+
name: 'includePayments',
|
|
284
|
+
message: 'Include x402 payments?',
|
|
285
|
+
initial: false
|
|
16
286
|
}
|
|
17
287
|
]);
|
|
18
|
-
const {
|
|
19
|
-
if (!
|
|
288
|
+
const { agentName, description, skills, includeRegistration, includePayments } = response;
|
|
289
|
+
if (!agentName) {
|
|
20
290
|
console.log(kleur.red('Cancelled.'));
|
|
21
291
|
process.exit(1);
|
|
22
292
|
}
|
|
23
|
-
const
|
|
293
|
+
const skillList = skills.split(',').map((s) => s.trim()).filter(Boolean);
|
|
294
|
+
const dirName = agentName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
295
|
+
const targetDir = path.join(process.cwd(), dirName);
|
|
24
296
|
if (fs.existsSync(targetDir)) {
|
|
25
|
-
console.log(kleur.red(`Error: Directory ${
|
|
297
|
+
console.log(kleur.red(`Error: Directory ${dirName} already exists!`));
|
|
26
298
|
process.exit(1);
|
|
27
299
|
}
|
|
28
|
-
console.log(`\nCreating
|
|
300
|
+
console.log(`\nCreating agent in ${kleur.green(targetDir)}...\n`);
|
|
29
301
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
30
302
|
// 1. package.json
|
|
31
303
|
const packageJson = {
|
|
32
|
-
name:
|
|
304
|
+
name: dirName,
|
|
33
305
|
version: "1.0.0",
|
|
34
|
-
description:
|
|
306
|
+
description: description,
|
|
35
307
|
type: "module",
|
|
36
308
|
scripts: {
|
|
37
|
-
|
|
38
|
-
|
|
309
|
+
start: "tsx index.ts",
|
|
310
|
+
dev: "tsx watch index.ts"
|
|
39
311
|
},
|
|
40
312
|
dependencies: {
|
|
41
313
|
"@openagentmarket/nodejs": "^1.0.0",
|
|
42
|
-
|
|
43
|
-
|
|
314
|
+
ethers: "^6.10.0",
|
|
315
|
+
dotenv: "^16.4.0"
|
|
44
316
|
},
|
|
45
317
|
devDependencies: {
|
|
46
|
-
|
|
47
|
-
|
|
318
|
+
tsx: "^4.7.0",
|
|
319
|
+
typescript: "^5.3.3",
|
|
48
320
|
"@types/node": "^20.11.0"
|
|
49
321
|
}
|
|
50
322
|
};
|
|
51
323
|
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
52
324
|
// 2. tsconfig.json
|
|
53
|
-
|
|
54
|
-
"compilerOptions": {
|
|
55
|
-
"target": "ES2022",
|
|
56
|
-
"module": "NodeNext",
|
|
57
|
-
"moduleResolution": "NodeNext",
|
|
58
|
-
"strict": true,
|
|
59
|
-
"esModuleInterop": true,
|
|
60
|
-
"skipLibCheck": true,
|
|
61
|
-
"forceConsistentCasingInFileNames": true
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
fs.writeFileSync(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
325
|
+
writeSharedTsConfig(targetDir);
|
|
65
326
|
// 3. .env
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
327
|
+
let envContent = 'MNEMONIC="your twelve word mnemonic phrase here"\n';
|
|
328
|
+
if (includeRegistration) {
|
|
329
|
+
envContent += 'REGISTRATION_PRIVATE_KEY=""\n';
|
|
330
|
+
envContent += 'PINATA_JWT=""\n';
|
|
331
|
+
}
|
|
332
|
+
fs.writeFileSync(path.join(targetDir, '.env'), envContent);
|
|
333
|
+
// 4. .gitignore
|
|
334
|
+
fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
|
|
335
|
+
// 5. index.ts
|
|
336
|
+
const taskHandlers = skillList.map((skill) => `
|
|
337
|
+
agent.onTask("${skill}", async (input) => {
|
|
338
|
+
return { message: \`Handled ${skill} with \${JSON.stringify(input)}\` };
|
|
339
|
+
});`).join('\n');
|
|
340
|
+
const paymentConfig = includePayments ? `
|
|
341
|
+
payment: {
|
|
342
|
+
amount: 5,
|
|
343
|
+
currency: "USDC",
|
|
344
|
+
recipientAddress: "0x0000000000000000000000000000000000000000" // Update this!
|
|
345
|
+
},` : '';
|
|
346
|
+
const registrationBlock = includeRegistration ? `
|
|
347
|
+
|
|
348
|
+
// āā Register on-chain (optional) āā
|
|
349
|
+
async function registerAgent(agent: any) {
|
|
350
|
+
const result = await agent.register(
|
|
351
|
+
{
|
|
352
|
+
name: "${agentName}",
|
|
353
|
+
description: "${description}",
|
|
354
|
+
image: "https://example.com/avatar.png",
|
|
355
|
+
metadata: {
|
|
356
|
+
skills: ${JSON.stringify(skillList)},
|
|
357
|
+
pricing: { amount: "5.0", currency: "USDC", chain: "base" },
|
|
358
|
+
category: "utility",
|
|
359
|
+
tags: ["openagent"]
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
privateKey: process.env.REGISTRATION_PRIVATE_KEY!,
|
|
364
|
+
pinataJwt: process.env.PINATA_JWT!,
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
console.log("Registered:", result);
|
|
368
|
+
}` : '';
|
|
369
|
+
const registrationCall = includeRegistration
|
|
370
|
+
? '\n // Uncomment to register on-chain:\n // await registerAgent(agent);\n'
|
|
371
|
+
: '';
|
|
69
372
|
const indexTs = `import { OpenAgent } from '@openagentmarket/nodejs';
|
|
70
373
|
import 'dotenv/config';
|
|
71
374
|
|
|
@@ -80,33 +383,91 @@ async function main() {
|
|
|
80
383
|
mnemonic,
|
|
81
384
|
env: "production",
|
|
82
385
|
card: {
|
|
83
|
-
name: "${
|
|
84
|
-
description: "
|
|
85
|
-
skills:
|
|
86
|
-
}
|
|
87
|
-
payment: {
|
|
88
|
-
amount: 0.001, // 0.001 ETH
|
|
89
|
-
currency: "ETH",
|
|
90
|
-
recipientAddress: "0x0000000000000000000000000000000000000000" // Update this!
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
agent.onTask("say_hello", async (input) => {
|
|
95
|
-
return { message: \`Hello \${input.name || "World"}!\` };
|
|
386
|
+
name: "${agentName}",
|
|
387
|
+
description: "${description}",
|
|
388
|
+
skills: ${JSON.stringify(skillList)}
|
|
389
|
+
},${paymentConfig}
|
|
96
390
|
});
|
|
391
|
+
${taskHandlers}
|
|
97
392
|
|
|
98
|
-
await agent.start()
|
|
393
|
+
await agent.start();${registrationCall}
|
|
99
394
|
}
|
|
100
|
-
|
|
395
|
+
${registrationBlock}
|
|
101
396
|
main().catch(console.error);
|
|
102
397
|
`;
|
|
103
398
|
fs.writeFileSync(path.join(targetDir, 'index.ts'), indexTs);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
399
|
+
// 6. README.md
|
|
400
|
+
const readmeLines = [
|
|
401
|
+
`# ${agentName}`,
|
|
402
|
+
``,
|
|
403
|
+
description,
|
|
404
|
+
``,
|
|
405
|
+
`## Getting Started`,
|
|
406
|
+
``,
|
|
407
|
+
'```bash',
|
|
408
|
+
`cd ${dirName}`,
|
|
409
|
+
`npm install`,
|
|
410
|
+
'```',
|
|
411
|
+
``,
|
|
412
|
+
`### Configuration`,
|
|
413
|
+
``,
|
|
414
|
+
`Edit \`.env\` and set your 12-word mnemonic phrase.`,
|
|
415
|
+
includeRegistration ? `\nFor on-chain registration, also set \`REGISTRATION_PRIVATE_KEY\` and \`PINATA_JWT\`.\n` : '',
|
|
416
|
+
`### Running`,
|
|
417
|
+
``,
|
|
418
|
+
'```bash',
|
|
419
|
+
`# Development mode with hot-reload`,
|
|
420
|
+
`npm run dev`,
|
|
421
|
+
``,
|
|
422
|
+
`# Production`,
|
|
423
|
+
`npm start`,
|
|
424
|
+
'```',
|
|
425
|
+
``,
|
|
426
|
+
`## Agent Details`,
|
|
427
|
+
``,
|
|
428
|
+
`| Property | Value |`,
|
|
429
|
+
`|----------|-------|`,
|
|
430
|
+
`| **Name** | ${agentName} |`,
|
|
431
|
+
`| **Skills** | ${skillList.join(', ')} |`,
|
|
432
|
+
`| **Payments** | ${includePayments ? 'Enabled (x402)' : 'Disabled'} |`,
|
|
433
|
+
`| **Registration** | ${includeRegistration ? 'Included' : 'Not included'} |`,
|
|
434
|
+
``,
|
|
435
|
+
`## Environment Variables`,
|
|
436
|
+
``,
|
|
437
|
+
`| Variable | Required | Description |`,
|
|
438
|
+
`|----------|----------|-------------|`,
|
|
439
|
+
'| `MNEMONIC` | Yes | Agent wallet seed phrase |',
|
|
440
|
+
includeRegistration ? '| `REGISTRATION_PRIVATE_KEY` | For registration | Wallet paying gas |\n| `PINATA_JWT` | For registration | IPFS metadata upload |' : '',
|
|
441
|
+
``,
|
|
442
|
+
`## Resources`,
|
|
443
|
+
``,
|
|
444
|
+
`- [SDK Docs](https://www.npmjs.com/package/@openagentmarket/nodejs)`,
|
|
445
|
+
`- [Explorer](https://8004agents.ai)`,
|
|
446
|
+
`- [GitHub](https://github.com/openagentmarket)`,
|
|
447
|
+
].join('\n');
|
|
448
|
+
fs.writeFileSync(path.join(targetDir, 'README.md'), readmeLines);
|
|
449
|
+
// Print success
|
|
450
|
+
console.log(kleur.green('ā
Agent project created!\n'));
|
|
451
|
+
console.log(kleur.bold('Next steps:'));
|
|
452
|
+
console.log(` cd ${dirName}`);
|
|
453
|
+
console.log(' npm install');
|
|
454
|
+
console.log(' # Set your MNEMONIC in .env');
|
|
455
|
+
console.log(' npm start\n');
|
|
456
|
+
}
|
|
457
|
+
// āā Shared helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
458
|
+
function writeSharedTsConfig(targetDir) {
|
|
459
|
+
const tsConfig = {
|
|
460
|
+
compilerOptions: {
|
|
461
|
+
target: "ES2022",
|
|
462
|
+
module: "NodeNext",
|
|
463
|
+
moduleResolution: "NodeNext",
|
|
464
|
+
strict: true,
|
|
465
|
+
esModuleInterop: true,
|
|
466
|
+
skipLibCheck: true,
|
|
467
|
+
forceConsistentCasingInFileNames: true
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
fs.writeFileSync(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
110
471
|
}
|
|
111
472
|
main().catch((err) => {
|
|
112
473
|
console.error(err);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openagentmarket/create-agent",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "CLI to scaffold a new OpenAgent project",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "CLI to scaffold a new OpenAgent project (hirer or worker)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-openagent": "./dist/index.js"
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"prompts": "^2.4.2",
|
|
16
16
|
"kleur": "^4.1.5",
|
|
17
|
-
"fs-extra": "^11.2.0"
|
|
17
|
+
"fs-extra": "^11.2.0",
|
|
18
|
+
"ethers": "^6.10.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/prompts": "^2.4.9",
|
package/src/index.ts
CHANGED
|
@@ -2,81 +2,402 @@
|
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import prompts from 'prompts';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import kleur from 'kleur';
|
|
7
|
-
|
|
8
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
import { Wallet } from 'ethers';
|
|
9
7
|
|
|
10
8
|
async function main() {
|
|
11
|
-
console.log(kleur.bold().cyan('\nš
|
|
9
|
+
console.log(kleur.bold().cyan('\nš OpenAgent Market ā Project Scaffolder\n'));
|
|
10
|
+
|
|
11
|
+
// Step 1: Choose role
|
|
12
|
+
const { role } = await prompts({
|
|
13
|
+
type: 'select',
|
|
14
|
+
name: 'role',
|
|
15
|
+
message: 'What do you want to do?',
|
|
16
|
+
choices: [
|
|
17
|
+
{ title: 'šØ Worker ā Build an agent that handles tasks', value: 'worker' },
|
|
18
|
+
{ title: 'š¼ Hirer ā Hire agents to do work for you', value: 'hirer' }
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (!role) {
|
|
23
|
+
console.log(kleur.red('Cancelled.'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (role === 'hirer') {
|
|
28
|
+
await scaffoldHirer();
|
|
29
|
+
} else {
|
|
30
|
+
await scaffoldWorker();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// āā Hirer Flow (zero-config) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
12
35
|
|
|
36
|
+
async function scaffoldHirer() {
|
|
37
|
+
const targetDir = process.cwd();
|
|
38
|
+
|
|
39
|
+
console.log(kleur.dim('\nScaffolding hirer project in current directory...\n'));
|
|
40
|
+
|
|
41
|
+
// Auto-generate wallet
|
|
42
|
+
const wallet = Wallet.createRandom();
|
|
43
|
+
const mnemonic = wallet.mnemonic!.phrase;
|
|
44
|
+
|
|
45
|
+
// 1. package.json
|
|
46
|
+
const packageJson = {
|
|
47
|
+
name: "openagent-hirer",
|
|
48
|
+
version: "1.0.0",
|
|
49
|
+
description: "Hire agents on OpenAgent Market",
|
|
50
|
+
type: "module",
|
|
51
|
+
scripts: {
|
|
52
|
+
start: "tsx index.ts",
|
|
53
|
+
dev: "tsx watch index.ts"
|
|
54
|
+
},
|
|
55
|
+
dependencies: {
|
|
56
|
+
"@openagentmarket/nodejs": "^1.0.0",
|
|
57
|
+
ethers: "^6.10.0",
|
|
58
|
+
dotenv: "^16.4.0"
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
tsx: "^4.7.0",
|
|
62
|
+
typescript: "^5.3.3",
|
|
63
|
+
"@types/node": "^20.11.0"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
67
|
+
|
|
68
|
+
// 2. tsconfig.json
|
|
69
|
+
writeSharedTsConfig(targetDir);
|
|
70
|
+
|
|
71
|
+
// 3. .env (with auto-generated mnemonic)
|
|
72
|
+
fs.writeFileSync(path.join(targetDir, '.env'), `MNEMONIC="${mnemonic}"\n`);
|
|
73
|
+
|
|
74
|
+
// 4. .gitignore
|
|
75
|
+
fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
|
|
76
|
+
|
|
77
|
+
// 5. index.ts ā persistent XMTP chat CLI
|
|
78
|
+
const indexTs = [
|
|
79
|
+
`import { OpenAgentClient } from '@openagentmarket/nodejs';`,
|
|
80
|
+
`import * as readline from 'node:readline';`,
|
|
81
|
+
`import 'dotenv/config';`,
|
|
82
|
+
``,
|
|
83
|
+
`const DISCOVER_URL = "https://openagent.market/discover?protocol=openagentmarket";`,
|
|
84
|
+
``,
|
|
85
|
+
`async function main() {`,
|
|
86
|
+
` const client = await OpenAgentClient.create({`,
|
|
87
|
+
` mnemonic: process.env.MNEMONIC,`,
|
|
88
|
+
` env: "production"`,
|
|
89
|
+
` });`,
|
|
90
|
+
``,
|
|
91
|
+
` console.log("");`,
|
|
92
|
+
` console.log("ā
Connected to XMTP");`,
|
|
93
|
+
` console.log(" Wallet: " + client.getAddress());`,
|
|
94
|
+
` console.log("");`,
|
|
95
|
+
` printHelp();`,
|
|
96
|
+
``,
|
|
97
|
+
` // āā Start REPL āā`,
|
|
98
|
+
` const rl = readline.createInterface({`,
|
|
99
|
+
` input: process.stdin,`,
|
|
100
|
+
` output: process.stdout,`,
|
|
101
|
+
` prompt: "\\n> "`,
|
|
102
|
+
` });`,
|
|
103
|
+
``,
|
|
104
|
+
` rl.prompt();`,
|
|
105
|
+
``,
|
|
106
|
+
` rl.on("line", async (line: string) => {`,
|
|
107
|
+
` const input = line.trim();`,
|
|
108
|
+
` if (!input) { rl.prompt(); return; }`,
|
|
109
|
+
``,
|
|
110
|
+
` try {`,
|
|
111
|
+
` if (input === "/help") {`,
|
|
112
|
+
` printHelp();`,
|
|
113
|
+
` }`,
|
|
114
|
+
` else if (input === "/discover") {`,
|
|
115
|
+
` await discoverAgents();`,
|
|
116
|
+
` }`,
|
|
117
|
+
` else if (input.startsWith("/chat ")) {`,
|
|
118
|
+
` const parts = input.slice(6).trim().split(" ");`,
|
|
119
|
+
` const address = parts[0];`,
|
|
120
|
+
` const message = parts.slice(1).join(" ");`,
|
|
121
|
+
` if (!address || !message) {`,
|
|
122
|
+
` console.log("Usage: /chat <agent-address> <message>");`,
|
|
123
|
+
` } else {`,
|
|
124
|
+
` console.log("š¤ Sending to " + address + "...");`,
|
|
125
|
+
` const reply = await client.chat(address, message);`,
|
|
126
|
+
` console.log("š© Reply:", reply.success ? reply.result : reply.error);`,
|
|
127
|
+
` }`,
|
|
128
|
+
` }`,
|
|
129
|
+
` else if (input.startsWith("/task ")) {`,
|
|
130
|
+
` const parts = input.slice(6).trim().split(" ");`,
|
|
131
|
+
` const address = parts[0];`,
|
|
132
|
+
` const method = parts[1];`,
|
|
133
|
+
` const paramsStr = parts.slice(2).join(" ") || "{}";`,
|
|
134
|
+
` if (!address || !method) {`,
|
|
135
|
+
` console.log("Usage: /task <agent-address> <method> [json-params]");`,
|
|
136
|
+
` } else {`,
|
|
137
|
+
` let params: any = {};`,
|
|
138
|
+
` try { params = JSON.parse(paramsStr); } catch { params = { input: paramsStr }; }`,
|
|
139
|
+
` console.log("š¤ Sending task '" + method + "' to " + address + "...");`,
|
|
140
|
+
` const result = await client.sendTask(address, method, params);`,
|
|
141
|
+
` if (result.paymentRequired) {`,
|
|
142
|
+
` console.log("š° Payment required:", result.paymentRequired);`,
|
|
143
|
+
` } else if (result.success) {`,
|
|
144
|
+
` console.log("ā
Result:", JSON.stringify(result.result, null, 2));`,
|
|
145
|
+
` } else {`,
|
|
146
|
+
` console.log("ā Error:", result.error);`,
|
|
147
|
+
` }`,
|
|
148
|
+
` }`,
|
|
149
|
+
` }`,
|
|
150
|
+
` else if (input === "/quit" || input === "/exit") {`,
|
|
151
|
+
` console.log("Bye! š");`,
|
|
152
|
+
` process.exit(0);`,
|
|
153
|
+
` }`,
|
|
154
|
+
` else {`,
|
|
155
|
+
` console.log("Unknown command. Type /help for available commands.");`,
|
|
156
|
+
` }`,
|
|
157
|
+
` } catch (err: any) {`,
|
|
158
|
+
` console.error("ā Error:", err.message || err);`,
|
|
159
|
+
` }`,
|
|
160
|
+
``,
|
|
161
|
+
` rl.prompt();`,
|
|
162
|
+
` });`,
|
|
163
|
+
``,
|
|
164
|
+
` rl.on("close", () => {`,
|
|
165
|
+
` console.log("\\nBye! š");`,
|
|
166
|
+
` process.exit(0);`,
|
|
167
|
+
` });`,
|
|
168
|
+
`}`,
|
|
169
|
+
``,
|
|
170
|
+
`function printHelp() {`,
|
|
171
|
+
` console.log("š Commands:");`,
|
|
172
|
+
` console.log(" /discover ā Browse available agents");`,
|
|
173
|
+
` console.log(" /chat <agent-address> <message> ā Send a chat message");`,
|
|
174
|
+
` console.log(" /task <agent-address> <method> [params] ā Send a task (params as JSON)");`,
|
|
175
|
+
` console.log(" /help ā Show this help");`,
|
|
176
|
+
` console.log(" /quit ā Exit");`,
|
|
177
|
+
`}`,
|
|
178
|
+
``,
|
|
179
|
+
`async function discoverAgents() {`,
|
|
180
|
+
` console.log("š Fetching agents from OpenAgent Market...\\n");`,
|
|
181
|
+
` try {`,
|
|
182
|
+
` const res = await fetch(DISCOVER_URL);`,
|
|
183
|
+
` const data = await res.json() as any;`,
|
|
184
|
+
` if (!data.success || !data.items?.length) {`,
|
|
185
|
+
` console.log("No agents found.");`,
|
|
186
|
+
` return;`,
|
|
187
|
+
` }`,
|
|
188
|
+
` for (const item of data.items) {`,
|
|
189
|
+
` const reg = item.registrationFile || {};`,
|
|
190
|
+
` const name = reg.name || "Unknown";`,
|
|
191
|
+
` const desc = reg.description || "";`,
|
|
192
|
+
` // Find xmtpAddress from metadata array`,
|
|
193
|
+
` const meta = item.metadata || [];`,
|
|
194
|
+
` let addr = item.owner || "?";`,
|
|
195
|
+
` const walletMeta = meta.find((m: any) => m.key === "agentWallet");`,
|
|
196
|
+
` if (walletMeta) addr = walletMeta.value;`,
|
|
197
|
+
` const agentId = item.agentId || "";`,
|
|
198
|
+
` console.log(" š¤ " + name + (agentId ? " (#" + agentId + ")" : ""));`,
|
|
199
|
+
` if (desc) console.log(" " + desc.slice(0, 120) + (desc.length > 120 ? "..." : ""));`,
|
|
200
|
+
` console.log(" Address: " + addr);`,
|
|
201
|
+
` console.log("");`,
|
|
202
|
+
` }`,
|
|
203
|
+
` console.log("Total: " + data.items.length + " agent(s)");`,
|
|
204
|
+
` if (data.hasMore) console.log("(more agents available)");`,
|
|
205
|
+
` } catch (err: any) {`,
|
|
206
|
+
` console.error("Failed to fetch agents:", err.message);`,
|
|
207
|
+
` }`,
|
|
208
|
+
`}`,
|
|
209
|
+
``,
|
|
210
|
+
`main().catch(console.error);`,
|
|
211
|
+
].join('\n');
|
|
212
|
+
fs.writeFileSync(path.join(targetDir, 'index.ts'), indexTs);
|
|
213
|
+
|
|
214
|
+
// 6. README.md
|
|
215
|
+
const readmeLines = [
|
|
216
|
+
`# OpenAgent Hirer CLI`,
|
|
217
|
+
``,
|
|
218
|
+
`A persistent XMTP chat CLI for hiring agents on [OpenAgent Market](https://openagent.market).`,
|
|
219
|
+
``,
|
|
220
|
+
`## Getting Started`,
|
|
221
|
+
``,
|
|
222
|
+
'```bash',
|
|
223
|
+
`npm install`,
|
|
224
|
+
`npm start`,
|
|
225
|
+
'```',
|
|
226
|
+
``,
|
|
227
|
+
`## Commands`,
|
|
228
|
+
``,
|
|
229
|
+
`| Command | Description |`,
|
|
230
|
+
`|---------|-------------|`,
|
|
231
|
+
'| `/discover` | Browse available agents from the marketplace |',
|
|
232
|
+
'| `/chat <address> <message>` | Send a plain text message to an agent |',
|
|
233
|
+
'| `/task <address> <method> [json]` | Send a JSON-RPC task to an agent |',
|
|
234
|
+
'| `/help` | Show available commands |',
|
|
235
|
+
'| `/quit` | Exit the CLI |',
|
|
236
|
+
``,
|
|
237
|
+
`## Examples`,
|
|
238
|
+
``,
|
|
239
|
+
'```',
|
|
240
|
+
`> /discover`,
|
|
241
|
+
`> /chat 0xAgentAddr What can you do?`,
|
|
242
|
+
`> /task 0xAgentAddr say_hello {"name": "World"}`,
|
|
243
|
+
'```',
|
|
244
|
+
``,
|
|
245
|
+
`## Environment Variables`,
|
|
246
|
+
``,
|
|
247
|
+
`| Variable | Description |`,
|
|
248
|
+
`|----------|-------------|`,
|
|
249
|
+
'| `MNEMONIC` | Wallet seed phrase (auto-generated for you) |',
|
|
250
|
+
``,
|
|
251
|
+
`## Resources`,
|
|
252
|
+
``,
|
|
253
|
+
`- [Discover API](https://openagent.market/discover?protocol=openagentmarket)`,
|
|
254
|
+
`- [SDK Docs](https://www.npmjs.com/package/@openagentmarket/nodejs)`,
|
|
255
|
+
`- [Explorer](https://8004agents.ai)`,
|
|
256
|
+
].join('\n');
|
|
257
|
+
fs.writeFileSync(path.join(targetDir, 'README.md'), readmeLines);
|
|
258
|
+
|
|
259
|
+
// Print success
|
|
260
|
+
console.log(kleur.green('ā
Hirer CLI project created!\n'));
|
|
261
|
+
console.log(` ${kleur.bold('Wallet address:')} ${kleur.cyan(wallet.address)}`);
|
|
262
|
+
console.log(` ${kleur.bold('Mnemonic:')} saved to ${kleur.yellow('.env')}\n`);
|
|
263
|
+
console.log(kleur.bold('Next steps:'));
|
|
264
|
+
console.log(' npm install');
|
|
265
|
+
console.log(' npm start');
|
|
266
|
+
console.log(' # Then type /discover to find agents\n');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// āā Worker Flow (interactive) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
270
|
+
|
|
271
|
+
async function scaffoldWorker() {
|
|
13
272
|
const response = await prompts([
|
|
14
273
|
{
|
|
15
274
|
type: 'text',
|
|
16
|
-
name: '
|
|
17
|
-
message: 'What is
|
|
275
|
+
name: 'agentName',
|
|
276
|
+
message: 'What is your agent\'s name?',
|
|
18
277
|
initial: 'my-agent'
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
type: 'text',
|
|
281
|
+
name: 'description',
|
|
282
|
+
message: 'Describe your agent:',
|
|
283
|
+
initial: 'A freshly created OpenAgent.'
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
type: 'text',
|
|
287
|
+
name: 'skills',
|
|
288
|
+
message: 'Skills (comma-separated):',
|
|
289
|
+
initial: 'say_hello'
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
type: 'confirm',
|
|
293
|
+
name: 'includeRegistration',
|
|
294
|
+
message: 'Include on-chain registration (ERC-8004)?',
|
|
295
|
+
initial: false
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
type: 'confirm',
|
|
299
|
+
name: 'includePayments',
|
|
300
|
+
message: 'Include x402 payments?',
|
|
301
|
+
initial: false
|
|
19
302
|
}
|
|
20
303
|
]);
|
|
21
304
|
|
|
22
|
-
const {
|
|
23
|
-
if (!
|
|
305
|
+
const { agentName, description, skills, includeRegistration, includePayments } = response;
|
|
306
|
+
if (!agentName) {
|
|
24
307
|
console.log(kleur.red('Cancelled.'));
|
|
25
308
|
process.exit(1);
|
|
26
309
|
}
|
|
27
310
|
|
|
28
|
-
const
|
|
311
|
+
const skillList = skills.split(',').map((s: string) => s.trim()).filter(Boolean);
|
|
312
|
+
const dirName = agentName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
313
|
+
const targetDir = path.join(process.cwd(), dirName);
|
|
29
314
|
|
|
30
315
|
if (fs.existsSync(targetDir)) {
|
|
31
|
-
console.log(kleur.red(`Error: Directory ${
|
|
316
|
+
console.log(kleur.red(`Error: Directory ${dirName} already exists!`));
|
|
32
317
|
process.exit(1);
|
|
33
318
|
}
|
|
34
319
|
|
|
35
|
-
console.log(`\nCreating
|
|
320
|
+
console.log(`\nCreating agent in ${kleur.green(targetDir)}...\n`);
|
|
36
321
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
37
322
|
|
|
38
323
|
// 1. package.json
|
|
39
324
|
const packageJson = {
|
|
40
|
-
name:
|
|
325
|
+
name: dirName,
|
|
41
326
|
version: "1.0.0",
|
|
42
|
-
description:
|
|
327
|
+
description: description,
|
|
43
328
|
type: "module",
|
|
44
329
|
scripts: {
|
|
45
|
-
|
|
46
|
-
|
|
330
|
+
start: "tsx index.ts",
|
|
331
|
+
dev: "tsx watch index.ts"
|
|
47
332
|
},
|
|
48
333
|
dependencies: {
|
|
49
334
|
"@openagentmarket/nodejs": "^1.0.0",
|
|
50
|
-
|
|
51
|
-
|
|
335
|
+
ethers: "^6.10.0",
|
|
336
|
+
dotenv: "^16.4.0"
|
|
52
337
|
},
|
|
53
338
|
devDependencies: {
|
|
54
|
-
|
|
55
|
-
|
|
339
|
+
tsx: "^4.7.0",
|
|
340
|
+
typescript: "^5.3.3",
|
|
56
341
|
"@types/node": "^20.11.0"
|
|
57
342
|
}
|
|
58
343
|
};
|
|
59
344
|
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
60
345
|
|
|
61
346
|
// 2. tsconfig.json
|
|
62
|
-
|
|
63
|
-
"compilerOptions": {
|
|
64
|
-
"target": "ES2022",
|
|
65
|
-
"module": "NodeNext",
|
|
66
|
-
"moduleResolution": "NodeNext",
|
|
67
|
-
"strict": true,
|
|
68
|
-
"esModuleInterop": true,
|
|
69
|
-
"skipLibCheck": true,
|
|
70
|
-
"forceConsistentCasingInFileNames": true
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
fs.writeFileSync(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
347
|
+
writeSharedTsConfig(targetDir);
|
|
74
348
|
|
|
75
349
|
// 3. .env
|
|
76
|
-
|
|
77
|
-
|
|
350
|
+
let envContent = 'MNEMONIC="your twelve word mnemonic phrase here"\n';
|
|
351
|
+
if (includeRegistration) {
|
|
352
|
+
envContent += 'REGISTRATION_PRIVATE_KEY=""\n';
|
|
353
|
+
envContent += 'PINATA_JWT=""\n';
|
|
354
|
+
}
|
|
355
|
+
fs.writeFileSync(path.join(targetDir, '.env'), envContent);
|
|
356
|
+
|
|
357
|
+
// 4. .gitignore
|
|
358
|
+
fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
|
|
359
|
+
|
|
360
|
+
// 5. index.ts
|
|
361
|
+
const taskHandlers = skillList.map((skill: string) => `
|
|
362
|
+
agent.onTask("${skill}", async (input) => {
|
|
363
|
+
return { message: \`Handled ${skill} with \${JSON.stringify(input)}\` };
|
|
364
|
+
});`).join('\n');
|
|
365
|
+
|
|
366
|
+
const paymentConfig = includePayments ? `
|
|
367
|
+
payment: {
|
|
368
|
+
amount: 5,
|
|
369
|
+
currency: "USDC",
|
|
370
|
+
recipientAddress: "0x0000000000000000000000000000000000000000" // Update this!
|
|
371
|
+
},` : '';
|
|
372
|
+
|
|
373
|
+
const registrationBlock = includeRegistration ? `
|
|
374
|
+
|
|
375
|
+
// āā Register on-chain (optional) āā
|
|
376
|
+
async function registerAgent(agent: any) {
|
|
377
|
+
const result = await agent.register(
|
|
378
|
+
{
|
|
379
|
+
name: "${agentName}",
|
|
380
|
+
description: "${description}",
|
|
381
|
+
image: "https://example.com/avatar.png",
|
|
382
|
+
metadata: {
|
|
383
|
+
skills: ${JSON.stringify(skillList)},
|
|
384
|
+
pricing: { amount: "5.0", currency: "USDC", chain: "base" },
|
|
385
|
+
category: "utility",
|
|
386
|
+
tags: ["openagent"]
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
privateKey: process.env.REGISTRATION_PRIVATE_KEY!,
|
|
391
|
+
pinataJwt: process.env.PINATA_JWT!,
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
console.log("Registered:", result);
|
|
395
|
+
}` : '';
|
|
396
|
+
|
|
397
|
+
const registrationCall = includeRegistration
|
|
398
|
+
? '\n // Uncomment to register on-chain:\n // await registerAgent(agent);\n'
|
|
399
|
+
: '';
|
|
78
400
|
|
|
79
|
-
// 4. index.ts (Template)
|
|
80
401
|
const indexTs = `import { OpenAgent } from '@openagentmarket/nodejs';
|
|
81
402
|
import 'dotenv/config';
|
|
82
403
|
|
|
@@ -91,34 +412,95 @@ async function main() {
|
|
|
91
412
|
mnemonic,
|
|
92
413
|
env: "production",
|
|
93
414
|
card: {
|
|
94
|
-
name: "${
|
|
95
|
-
description: "
|
|
96
|
-
skills:
|
|
97
|
-
}
|
|
98
|
-
payment: {
|
|
99
|
-
amount: 0.001, // 0.001 ETH
|
|
100
|
-
currency: "ETH",
|
|
101
|
-
recipientAddress: "0x0000000000000000000000000000000000000000" // Update this!
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
agent.onTask("say_hello", async (input) => {
|
|
106
|
-
return { message: \`Hello \${input.name || "World"}!\` };
|
|
415
|
+
name: "${agentName}",
|
|
416
|
+
description: "${description}",
|
|
417
|
+
skills: ${JSON.stringify(skillList)}
|
|
418
|
+
},${paymentConfig}
|
|
107
419
|
});
|
|
420
|
+
${taskHandlers}
|
|
108
421
|
|
|
109
|
-
await agent.start()
|
|
422
|
+
await agent.start();${registrationCall}
|
|
110
423
|
}
|
|
111
|
-
|
|
424
|
+
${registrationBlock}
|
|
112
425
|
main().catch(console.error);
|
|
113
426
|
`;
|
|
114
427
|
fs.writeFileSync(path.join(targetDir, 'index.ts'), indexTs);
|
|
115
428
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
429
|
+
// 6. README.md
|
|
430
|
+
const readmeLines = [
|
|
431
|
+
`# ${agentName}`,
|
|
432
|
+
``,
|
|
433
|
+
description,
|
|
434
|
+
``,
|
|
435
|
+
`## Getting Started`,
|
|
436
|
+
``,
|
|
437
|
+
'```bash',
|
|
438
|
+
`cd ${dirName}`,
|
|
439
|
+
`npm install`,
|
|
440
|
+
'```',
|
|
441
|
+
``,
|
|
442
|
+
`### Configuration`,
|
|
443
|
+
``,
|
|
444
|
+
`Edit \`.env\` and set your 12-word mnemonic phrase.`,
|
|
445
|
+
includeRegistration ? `\nFor on-chain registration, also set \`REGISTRATION_PRIVATE_KEY\` and \`PINATA_JWT\`.\n` : '',
|
|
446
|
+
`### Running`,
|
|
447
|
+
``,
|
|
448
|
+
'```bash',
|
|
449
|
+
`# Development mode with hot-reload`,
|
|
450
|
+
`npm run dev`,
|
|
451
|
+
``,
|
|
452
|
+
`# Production`,
|
|
453
|
+
`npm start`,
|
|
454
|
+
'```',
|
|
455
|
+
``,
|
|
456
|
+
`## Agent Details`,
|
|
457
|
+
``,
|
|
458
|
+
`| Property | Value |`,
|
|
459
|
+
`|----------|-------|`,
|
|
460
|
+
`| **Name** | ${agentName} |`,
|
|
461
|
+
`| **Skills** | ${skillList.join(', ')} |`,
|
|
462
|
+
`| **Payments** | ${includePayments ? 'Enabled (x402)' : 'Disabled'} |`,
|
|
463
|
+
`| **Registration** | ${includeRegistration ? 'Included' : 'Not included'} |`,
|
|
464
|
+
``,
|
|
465
|
+
`## Environment Variables`,
|
|
466
|
+
``,
|
|
467
|
+
`| Variable | Required | Description |`,
|
|
468
|
+
`|----------|----------|-------------|`,
|
|
469
|
+
'| `MNEMONIC` | Yes | Agent wallet seed phrase |',
|
|
470
|
+
includeRegistration ? '| `REGISTRATION_PRIVATE_KEY` | For registration | Wallet paying gas |\n| `PINATA_JWT` | For registration | IPFS metadata upload |' : '',
|
|
471
|
+
``,
|
|
472
|
+
`## Resources`,
|
|
473
|
+
``,
|
|
474
|
+
`- [SDK Docs](https://www.npmjs.com/package/@openagentmarket/nodejs)`,
|
|
475
|
+
`- [Explorer](https://8004agents.ai)`,
|
|
476
|
+
`- [GitHub](https://github.com/openagentmarket)`,
|
|
477
|
+
].join('\n');
|
|
478
|
+
fs.writeFileSync(path.join(targetDir, 'README.md'), readmeLines);
|
|
479
|
+
|
|
480
|
+
// Print success
|
|
481
|
+
console.log(kleur.green('ā
Agent project created!\n'));
|
|
482
|
+
console.log(kleur.bold('Next steps:'));
|
|
483
|
+
console.log(` cd ${dirName}`);
|
|
484
|
+
console.log(' npm install');
|
|
485
|
+
console.log(' # Set your MNEMONIC in .env');
|
|
486
|
+
console.log(' npm start\n');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// āā Shared helpers āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
490
|
+
|
|
491
|
+
function writeSharedTsConfig(targetDir: string) {
|
|
492
|
+
const tsConfig = {
|
|
493
|
+
compilerOptions: {
|
|
494
|
+
target: "ES2022",
|
|
495
|
+
module: "NodeNext",
|
|
496
|
+
moduleResolution: "NodeNext",
|
|
497
|
+
strict: true,
|
|
498
|
+
esModuleInterop: true,
|
|
499
|
+
skipLibCheck: true,
|
|
500
|
+
forceConsistentCasingInFileNames: true
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
fs.writeFileSync(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
122
504
|
}
|
|
123
505
|
|
|
124
506
|
main().catch((err) => {
|