create-polyclaw-agent 0.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/dist/api.d.ts +15 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +39 -0
- package/dist/api.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/scaffold.d.ts +16 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +543 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +25 -0
- package/src/api.ts +61 -0
- package/src/index.ts +211 -0
- package/src/scaffold.ts +570 -0
- package/tsconfig.json +11 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* create-polyclaw-agent
|
|
5
|
+
*
|
|
6
|
+
* Interactive CLI to set up a Polyclaw AI trading agent.
|
|
7
|
+
* Generates a sea creature name, registers the agent, and scaffolds a bot project.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import prompts from 'prompts';
|
|
12
|
+
import { generateName, registerAgent, getLinkUrl } from './api.js';
|
|
13
|
+
import { scaffoldProject, nameToDir } from './scaffold.js';
|
|
14
|
+
|
|
15
|
+
const LOBSTER = '\u{1F99E}';
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log();
|
|
19
|
+
console.log(chalk.bold(' Welcome to Polyclaw!'));
|
|
20
|
+
console.log();
|
|
21
|
+
|
|
22
|
+
// Step 1: Generate and pick a name
|
|
23
|
+
let agentName: string;
|
|
24
|
+
try {
|
|
25
|
+
agentName = await pickName();
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(chalk.red(' Failed to connect to Polyclaw API.'));
|
|
29
|
+
console.log(chalk.dim(' Make sure you have an internet connection and try again.'));
|
|
30
|
+
console.log();
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!agentName) {
|
|
35
|
+
console.log();
|
|
36
|
+
console.log(chalk.dim(' Cancelled.'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Step 2: Ask for owner name (optional)
|
|
41
|
+
console.log();
|
|
42
|
+
const ownerResponse = await prompts({
|
|
43
|
+
type: 'text',
|
|
44
|
+
name: 'ownerName',
|
|
45
|
+
message: 'Your name (shown on leaderboard, press Enter to skip)',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const ownerName = ownerResponse.ownerName?.trim() || undefined;
|
|
49
|
+
|
|
50
|
+
// Step 3: Register the agent
|
|
51
|
+
console.log();
|
|
52
|
+
process.stdout.write(chalk.dim(` Registering ${chalk.white(agentName)}... `));
|
|
53
|
+
|
|
54
|
+
let credentials;
|
|
55
|
+
try {
|
|
56
|
+
credentials = await registerAgent(agentName, { ownerName });
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log(chalk.red('failed'));
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.red(` Error: ${(err as Error).message}`));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(chalk.green('done'));
|
|
65
|
+
|
|
66
|
+
// Step 3: Choose language
|
|
67
|
+
console.log();
|
|
68
|
+
const langResponse = await prompts({
|
|
69
|
+
type: 'select',
|
|
70
|
+
name: 'language',
|
|
71
|
+
message: 'Choose your language',
|
|
72
|
+
choices: [
|
|
73
|
+
{ title: 'Python', value: 'python' },
|
|
74
|
+
{ title: 'TypeScript', value: 'typescript' },
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!langResponse.language) {
|
|
79
|
+
console.log(chalk.dim(' Cancelled.'));
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const language = langResponse.language as 'python' | 'typescript';
|
|
84
|
+
|
|
85
|
+
// Step 4: Ask for AI provider
|
|
86
|
+
console.log();
|
|
87
|
+
const aiResponse = await prompts({
|
|
88
|
+
type: 'select',
|
|
89
|
+
name: 'aiProvider',
|
|
90
|
+
message: 'Which AI powers your agent?',
|
|
91
|
+
choices: [
|
|
92
|
+
{ title: 'Anthropic (Claude)', value: 'anthropic' },
|
|
93
|
+
{ title: 'OpenAI (GPT)', value: 'openai' },
|
|
94
|
+
{ title: 'None / I\'ll add my own later', value: 'none' },
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!aiResponse.aiProvider) {
|
|
99
|
+
console.log(chalk.dim(' Cancelled.'));
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const aiProvider = aiResponse.aiProvider as 'anthropic' | 'openai' | 'none';
|
|
104
|
+
|
|
105
|
+
let aiApiKey: string | undefined;
|
|
106
|
+
if (aiProvider !== 'none') {
|
|
107
|
+
const providerName = aiProvider === 'anthropic' ? 'Anthropic' : 'OpenAI';
|
|
108
|
+
const keyResponse = await prompts({
|
|
109
|
+
type: 'text',
|
|
110
|
+
name: 'apiKey',
|
|
111
|
+
message: `${providerName} API key`,
|
|
112
|
+
});
|
|
113
|
+
aiApiKey = keyResponse.apiKey?.trim() || undefined;
|
|
114
|
+
|
|
115
|
+
if (!aiApiKey) {
|
|
116
|
+
console.log(chalk.dim(` No key provided. You can add it to .env later.`));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Step 5: Scaffold the project
|
|
121
|
+
const dirName = nameToDir(agentName);
|
|
122
|
+
console.log();
|
|
123
|
+
console.log(chalk.dim(` Creating ${chalk.white(dirName)}/`));
|
|
124
|
+
|
|
125
|
+
const projectDir = scaffoldProject({
|
|
126
|
+
name: agentName,
|
|
127
|
+
dirName,
|
|
128
|
+
apiKey: credentials.apiKey,
|
|
129
|
+
apiSecret: credentials.apiSecret,
|
|
130
|
+
language,
|
|
131
|
+
aiProvider,
|
|
132
|
+
aiApiKey,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Show created files
|
|
136
|
+
if (language === 'python') {
|
|
137
|
+
console.log(chalk.dim(' .env API credentials saved'));
|
|
138
|
+
console.log(chalk.dim(' bot.py Trading bot template'));
|
|
139
|
+
console.log(chalk.dim(' requirements.txt Dependencies'));
|
|
140
|
+
} else {
|
|
141
|
+
console.log(chalk.dim(' .env API credentials saved'));
|
|
142
|
+
console.log(chalk.dim(' bot.ts Trading bot template'));
|
|
143
|
+
console.log(chalk.dim(' package.json Dependencies'));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Step 5: Success!
|
|
147
|
+
const linkUrl = getLinkUrl(credentials.linkToken);
|
|
148
|
+
|
|
149
|
+
const installCmd = language === 'python'
|
|
150
|
+
? 'python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt'
|
|
151
|
+
: 'npm install';
|
|
152
|
+
|
|
153
|
+
const runCmd = language === 'python'
|
|
154
|
+
? 'python bot.py'
|
|
155
|
+
: 'npm start';
|
|
156
|
+
|
|
157
|
+
console.log();
|
|
158
|
+
console.log(chalk.bold.green(` ${LOBSTER} ${agentName} is ready!`));
|
|
159
|
+
console.log();
|
|
160
|
+
console.log(chalk.bold(' Step 1: Link your wallet'));
|
|
161
|
+
console.log();
|
|
162
|
+
console.log(` Open this link in your browser:`);
|
|
163
|
+
console.log();
|
|
164
|
+
console.log(` ${chalk.cyan(linkUrl)}`);
|
|
165
|
+
console.log();
|
|
166
|
+
console.log(chalk.bold(' Step 2: Start your bot'));
|
|
167
|
+
console.log();
|
|
168
|
+
console.log(` ${chalk.white(`cd ${dirName}`)}`);
|
|
169
|
+
console.log(` ${chalk.white(installCmd)}`);
|
|
170
|
+
console.log(` ${chalk.white(runCmd)}`);
|
|
171
|
+
console.log();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function pickName(): Promise<string> {
|
|
175
|
+
let name = await generateName();
|
|
176
|
+
|
|
177
|
+
while (true) {
|
|
178
|
+
console.log(` Your agent: ${chalk.bold.white(name)}`);
|
|
179
|
+
console.log();
|
|
180
|
+
|
|
181
|
+
const response = await prompts({
|
|
182
|
+
type: 'select',
|
|
183
|
+
name: 'action',
|
|
184
|
+
message: 'Choose an action',
|
|
185
|
+
choices: [
|
|
186
|
+
{ title: `Accept "${name}"`, value: 'accept' },
|
|
187
|
+
{ title: 'Re-roll (get a new name)', value: 'reroll' },
|
|
188
|
+
{ title: 'Cancel', value: 'cancel' },
|
|
189
|
+
],
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (!response.action || response.action === 'cancel') {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (response.action === 'accept') {
|
|
197
|
+
return name;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Re-roll
|
|
201
|
+
process.stdout.write(chalk.dim(' Generating new name... '));
|
|
202
|
+
name = await generateName();
|
|
203
|
+
console.log(chalk.green('done'));
|
|
204
|
+
console.log();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
main().catch((err) => {
|
|
209
|
+
console.error(chalk.red(`Unexpected error: ${err.message}`));
|
|
210
|
+
process.exit(1);
|
|
211
|
+
});
|