@gopherhole/cli 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/README.md +76 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +396 -0
- package/package.json +39 -0
- package/src/index.ts +451 -0
- package/tsconfig.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# 🐿️ GopherHole CLI
|
|
2
|
+
|
|
3
|
+
Connect AI agents to the world.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Use with npx (no install required)
|
|
9
|
+
npx gopherhole init
|
|
10
|
+
|
|
11
|
+
# Or install globally
|
|
12
|
+
npm install -g gopherhole
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Initialize a new agent in your project
|
|
19
|
+
npx gopherhole init
|
|
20
|
+
|
|
21
|
+
# This will:
|
|
22
|
+
# 1. Log you in (or create an account)
|
|
23
|
+
# 2. Create an agent
|
|
24
|
+
# 3. Save your API key to .env
|
|
25
|
+
# 4. Generate example code
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
### Authentication
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gopherhole login # Log in to GopherHole
|
|
34
|
+
gopherhole signup # Create a new account
|
|
35
|
+
gopherhole logout # Log out
|
|
36
|
+
gopherhole whoami # Show current user
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Agent Management
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gopherhole agents list # List your agents
|
|
43
|
+
gopherhole agents create # Create a new agent (interactive)
|
|
44
|
+
gopherhole agents create -n mybot # Create with name
|
|
45
|
+
gopherhole agents delete <id> # Delete an agent
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Project Setup
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
gopherhole init # Initialize GopherHole in current directory
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Testing
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
gopherhole send <agentId> "Hello!" # Send a test message
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
The CLI stores configuration in:
|
|
63
|
+
- **macOS**: `~/Library/Preferences/gopherhole-nodejs/`
|
|
64
|
+
- **Linux**: `~/.config/gopherhole-nodejs/`
|
|
65
|
+
- **Windows**: `%APPDATA%/gopherhole-nodejs/`
|
|
66
|
+
|
|
67
|
+
## Links
|
|
68
|
+
|
|
69
|
+
- Website: https://gopherhole.ai
|
|
70
|
+
- Dashboard: https://gopherhole.ai/dashboard
|
|
71
|
+
- Docs: https://gopherhole.ai/docs
|
|
72
|
+
- GitHub: https://github.com/gopherhole
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const conf_1 = __importDefault(require("conf"));
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
const ora_1 = __importDefault(require("ora"));
|
|
12
|
+
const config = new conf_1.default({ projectName: 'gopherhole' });
|
|
13
|
+
const API_URL = 'https://gopherhole.ai/api';
|
|
14
|
+
const program = new commander_1.Command();
|
|
15
|
+
program
|
|
16
|
+
.name('gopherhole')
|
|
17
|
+
.description('🐿️ GopherHole CLI - Connect AI agents to the world')
|
|
18
|
+
.version('0.1.0');
|
|
19
|
+
// ========== AUTH COMMANDS ==========
|
|
20
|
+
program
|
|
21
|
+
.command('login')
|
|
22
|
+
.description('Log in to GopherHole')
|
|
23
|
+
.action(async () => {
|
|
24
|
+
const { email, password } = await inquirer_1.default.prompt([
|
|
25
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
26
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
27
|
+
]);
|
|
28
|
+
const spinner = (0, ora_1.default)('Logging in...').start();
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch(`${API_URL}/auth/login`, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
body: JSON.stringify({ email, password }),
|
|
34
|
+
});
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
const err = await res.json();
|
|
37
|
+
throw new Error(err.error || 'Login failed');
|
|
38
|
+
}
|
|
39
|
+
const data = await res.json();
|
|
40
|
+
config.set('sessionId', data.sessionId);
|
|
41
|
+
config.set('user', data.user);
|
|
42
|
+
config.set('tenant', data.tenant);
|
|
43
|
+
spinner.succeed(`Logged in as ${chalk_1.default.green(data.user.email)}`);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
program
|
|
51
|
+
.command('signup')
|
|
52
|
+
.description('Create a new GopherHole account')
|
|
53
|
+
.action(async () => {
|
|
54
|
+
const { name, email, password } = await inquirer_1.default.prompt([
|
|
55
|
+
{ type: 'input', name: 'name', message: 'Name:' },
|
|
56
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
57
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
58
|
+
]);
|
|
59
|
+
const spinner = (0, ora_1.default)('Creating account...').start();
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetch(`${API_URL}/auth/signup`, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
body: JSON.stringify({ name, email, password }),
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
const err = await res.json();
|
|
68
|
+
throw new Error(err.error || 'Signup failed');
|
|
69
|
+
}
|
|
70
|
+
const data = await res.json();
|
|
71
|
+
config.set('sessionId', data.sessionId);
|
|
72
|
+
config.set('user', data.user);
|
|
73
|
+
config.set('tenant', data.tenant);
|
|
74
|
+
spinner.succeed(`Account created! Logged in as ${chalk_1.default.green(data.user.email)}`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
program
|
|
82
|
+
.command('logout')
|
|
83
|
+
.description('Log out of GopherHole')
|
|
84
|
+
.action(() => {
|
|
85
|
+
config.clear();
|
|
86
|
+
console.log(chalk_1.default.green('Logged out successfully'));
|
|
87
|
+
});
|
|
88
|
+
program
|
|
89
|
+
.command('whoami')
|
|
90
|
+
.description('Show current logged in user')
|
|
91
|
+
.action(() => {
|
|
92
|
+
const user = config.get('user');
|
|
93
|
+
if (!user) {
|
|
94
|
+
console.log(chalk_1.default.yellow('Not logged in. Run: gopherhole login'));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
console.log(`Logged in as ${chalk_1.default.green(user.email)} (${user.name})`);
|
|
98
|
+
});
|
|
99
|
+
// ========== AGENT COMMANDS ==========
|
|
100
|
+
const agents = program.command('agents').description('Manage agents');
|
|
101
|
+
agents
|
|
102
|
+
.command('list')
|
|
103
|
+
.description('List your agents')
|
|
104
|
+
.action(async () => {
|
|
105
|
+
const sessionId = config.get('sessionId');
|
|
106
|
+
if (!sessionId) {
|
|
107
|
+
console.log(chalk_1.default.yellow('Not logged in. Run: gopherhole login'));
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const spinner = (0, ora_1.default)('Fetching agents...').start();
|
|
111
|
+
try {
|
|
112
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
113
|
+
headers: { 'X-Session-ID': sessionId },
|
|
114
|
+
});
|
|
115
|
+
if (!res.ok)
|
|
116
|
+
throw new Error('Failed to fetch agents');
|
|
117
|
+
const data = await res.json();
|
|
118
|
+
spinner.stop();
|
|
119
|
+
if (data.agents.length === 0) {
|
|
120
|
+
console.log(chalk_1.default.yellow('No agents yet. Create one with: gopherhole agents create'));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
console.log(chalk_1.default.bold('\nYour Agents:\n'));
|
|
124
|
+
for (const agent of data.agents) {
|
|
125
|
+
const status = agent.status === 'active' ? chalk_1.default.green('●') : chalk_1.default.red('●');
|
|
126
|
+
console.log(` ${status} ${chalk_1.default.bold(agent.name)} (${agent.id})`);
|
|
127
|
+
if (agent.description) {
|
|
128
|
+
console.log(` ${chalk_1.default.gray(agent.description)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
console.log('');
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
agents
|
|
139
|
+
.command('create')
|
|
140
|
+
.description('Create a new agent')
|
|
141
|
+
.option('-n, --name <name>', 'Agent name')
|
|
142
|
+
.option('-d, --description <description>', 'Agent description')
|
|
143
|
+
.action(async (options) => {
|
|
144
|
+
const sessionId = config.get('sessionId');
|
|
145
|
+
if (!sessionId) {
|
|
146
|
+
console.log(chalk_1.default.yellow('Not logged in. Run: gopherhole login'));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
let { name, description } = options;
|
|
150
|
+
if (!name) {
|
|
151
|
+
const answers = await inquirer_1.default.prompt([
|
|
152
|
+
{ type: 'input', name: 'name', message: 'Agent name:' },
|
|
153
|
+
{ type: 'input', name: 'description', message: 'Description (optional):' },
|
|
154
|
+
]);
|
|
155
|
+
name = answers.name;
|
|
156
|
+
description = answers.description;
|
|
157
|
+
}
|
|
158
|
+
const spinner = (0, ora_1.default)('Creating agent...').start();
|
|
159
|
+
try {
|
|
160
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
headers: {
|
|
163
|
+
'Content-Type': 'application/json',
|
|
164
|
+
'X-Session-ID': sessionId,
|
|
165
|
+
},
|
|
166
|
+
body: JSON.stringify({ name, description }),
|
|
167
|
+
});
|
|
168
|
+
if (!res.ok) {
|
|
169
|
+
const err = await res.json();
|
|
170
|
+
throw new Error(err.error || 'Failed to create agent');
|
|
171
|
+
}
|
|
172
|
+
const data = await res.json();
|
|
173
|
+
spinner.succeed(`Agent created: ${chalk_1.default.green(data.agent.name)}`);
|
|
174
|
+
console.log('');
|
|
175
|
+
console.log(` ${chalk_1.default.bold('Agent ID:')} ${data.agent.id}`);
|
|
176
|
+
console.log(` ${chalk_1.default.bold('API Key:')} ${chalk_1.default.cyan(data.apiKey)}`);
|
|
177
|
+
console.log('');
|
|
178
|
+
console.log(chalk_1.default.gray('Save this API key - it won\'t be shown again!'));
|
|
179
|
+
console.log('');
|
|
180
|
+
console.log(chalk_1.default.bold('Quick start:'));
|
|
181
|
+
console.log(chalk_1.default.gray(`
|
|
182
|
+
import { GopherHole } from '@gopherhole/sdk';
|
|
183
|
+
|
|
184
|
+
const hub = new GopherHole('${data.apiKey}');
|
|
185
|
+
await hub.connect();
|
|
186
|
+
|
|
187
|
+
hub.on('message', (msg) => {
|
|
188
|
+
console.log('Received:', msg);
|
|
189
|
+
});
|
|
190
|
+
`));
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
agents
|
|
198
|
+
.command('delete <agentId>')
|
|
199
|
+
.description('Delete an agent')
|
|
200
|
+
.action(async (agentId) => {
|
|
201
|
+
const sessionId = config.get('sessionId');
|
|
202
|
+
if (!sessionId) {
|
|
203
|
+
console.log(chalk_1.default.yellow('Not logged in. Run: gopherhole login'));
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
207
|
+
{
|
|
208
|
+
type: 'confirm',
|
|
209
|
+
name: 'confirm',
|
|
210
|
+
message: `Are you sure you want to delete agent ${agentId}?`,
|
|
211
|
+
default: false,
|
|
212
|
+
},
|
|
213
|
+
]);
|
|
214
|
+
if (!confirm) {
|
|
215
|
+
console.log('Cancelled');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const spinner = (0, ora_1.default)('Deleting agent...').start();
|
|
219
|
+
try {
|
|
220
|
+
const res = await fetch(`${API_URL}/agents/${agentId}`, {
|
|
221
|
+
method: 'DELETE',
|
|
222
|
+
headers: { 'X-Session-ID': sessionId },
|
|
223
|
+
});
|
|
224
|
+
if (!res.ok)
|
|
225
|
+
throw new Error('Failed to delete agent');
|
|
226
|
+
spinner.succeed('Agent deleted');
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
// ========== INIT COMMAND ==========
|
|
234
|
+
program
|
|
235
|
+
.command('init')
|
|
236
|
+
.description('Initialize GopherHole in current directory')
|
|
237
|
+
.action(async () => {
|
|
238
|
+
console.log(chalk_1.default.bold('\n🐿️ GopherHole Init\n'));
|
|
239
|
+
let sessionId = config.get('sessionId');
|
|
240
|
+
// Check if logged in
|
|
241
|
+
if (!sessionId) {
|
|
242
|
+
console.log('First, let\'s log you in (or create an account).\n');
|
|
243
|
+
const { action } = await inquirer_1.default.prompt([
|
|
244
|
+
{
|
|
245
|
+
type: 'list',
|
|
246
|
+
name: 'action',
|
|
247
|
+
message: 'Do you have a GopherHole account?',
|
|
248
|
+
choices: [
|
|
249
|
+
{ name: 'Yes, log me in', value: 'login' },
|
|
250
|
+
{ name: 'No, create one', value: 'signup' },
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
]);
|
|
254
|
+
if (action === 'signup') {
|
|
255
|
+
const { name, email, password } = await inquirer_1.default.prompt([
|
|
256
|
+
{ type: 'input', name: 'name', message: 'Name:' },
|
|
257
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
258
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
259
|
+
]);
|
|
260
|
+
const spinner = (0, ora_1.default)('Creating account...').start();
|
|
261
|
+
const res = await fetch(`${API_URL}/auth/signup`, {
|
|
262
|
+
method: 'POST',
|
|
263
|
+
headers: { 'Content-Type': 'application/json' },
|
|
264
|
+
body: JSON.stringify({ name, email, password }),
|
|
265
|
+
});
|
|
266
|
+
if (!res.ok) {
|
|
267
|
+
spinner.fail('Signup failed');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
const data = await res.json();
|
|
271
|
+
config.set('sessionId', data.sessionId);
|
|
272
|
+
config.set('user', data.user);
|
|
273
|
+
config.set('tenant', data.tenant);
|
|
274
|
+
sessionId = data.sessionId;
|
|
275
|
+
spinner.succeed('Account created!');
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
const { email, password } = await inquirer_1.default.prompt([
|
|
279
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
280
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
281
|
+
]);
|
|
282
|
+
const spinner = (0, ora_1.default)('Logging in...').start();
|
|
283
|
+
const res = await fetch(`${API_URL}/auth/login`, {
|
|
284
|
+
method: 'POST',
|
|
285
|
+
headers: { 'Content-Type': 'application/json' },
|
|
286
|
+
body: JSON.stringify({ email, password }),
|
|
287
|
+
});
|
|
288
|
+
if (!res.ok) {
|
|
289
|
+
spinner.fail('Login failed');
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
const data = await res.json();
|
|
293
|
+
config.set('sessionId', data.sessionId);
|
|
294
|
+
config.set('user', data.user);
|
|
295
|
+
config.set('tenant', data.tenant);
|
|
296
|
+
sessionId = data.sessionId;
|
|
297
|
+
spinner.succeed('Logged in!');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
console.log('');
|
|
301
|
+
// Create agent
|
|
302
|
+
const { agentName, agentDesc } = await inquirer_1.default.prompt([
|
|
303
|
+
{ type: 'input', name: 'agentName', message: 'Agent name:', default: 'my-agent' },
|
|
304
|
+
{ type: 'input', name: 'agentDesc', message: 'Description (optional):' },
|
|
305
|
+
]);
|
|
306
|
+
const spinner = (0, ora_1.default)('Creating agent...').start();
|
|
307
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
308
|
+
method: 'POST',
|
|
309
|
+
headers: {
|
|
310
|
+
'Content-Type': 'application/json',
|
|
311
|
+
'X-Session-ID': sessionId,
|
|
312
|
+
},
|
|
313
|
+
body: JSON.stringify({ name: agentName, description: agentDesc }),
|
|
314
|
+
});
|
|
315
|
+
if (!res.ok) {
|
|
316
|
+
spinner.fail('Failed to create agent');
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
const data = await res.json();
|
|
320
|
+
spinner.succeed('Agent created!');
|
|
321
|
+
// Write .env file
|
|
322
|
+
const fs = await import('fs');
|
|
323
|
+
fs.writeFileSync('.env', `GOPHERHOLE_API_KEY=${data.apiKey}\n`);
|
|
324
|
+
console.log(chalk_1.default.green('✓ Created .env with API key'));
|
|
325
|
+
// Write example code
|
|
326
|
+
const exampleCode = `import { GopherHole } from '@gopherhole/sdk';
|
|
327
|
+
|
|
328
|
+
const hub = new GopherHole(process.env.GOPHERHOLE_API_KEY);
|
|
329
|
+
|
|
330
|
+
async function main() {
|
|
331
|
+
await hub.connect();
|
|
332
|
+
console.log('🐿️ Connected to GopherHole!');
|
|
333
|
+
|
|
334
|
+
hub.on('message', async (msg) => {
|
|
335
|
+
console.log(\`Message from \${msg.from}:\`, msg.payload);
|
|
336
|
+
|
|
337
|
+
// Reply to the message
|
|
338
|
+
await hub.sendText(msg.from, 'Hello back!');
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
main().catch(console.error);
|
|
343
|
+
`;
|
|
344
|
+
fs.writeFileSync('agent.ts', exampleCode);
|
|
345
|
+
console.log(chalk_1.default.green('✓ Created agent.ts example'));
|
|
346
|
+
console.log('');
|
|
347
|
+
console.log(chalk_1.default.bold('Next steps:'));
|
|
348
|
+
console.log('');
|
|
349
|
+
console.log(' 1. Install the SDK:');
|
|
350
|
+
console.log(chalk_1.default.cyan(' npm install @gopherhole/sdk'));
|
|
351
|
+
console.log('');
|
|
352
|
+
console.log(' 2. Run your agent:');
|
|
353
|
+
console.log(chalk_1.default.cyan(' npx ts-node agent.ts'));
|
|
354
|
+
console.log('');
|
|
355
|
+
console.log(chalk_1.default.gray(`Dashboard: https://gopherhole.ai/dashboard`));
|
|
356
|
+
console.log('');
|
|
357
|
+
});
|
|
358
|
+
// ========== SEND COMMAND ==========
|
|
359
|
+
program
|
|
360
|
+
.command('send <agentId> <message>')
|
|
361
|
+
.description('Send a message to an agent (for testing)')
|
|
362
|
+
.action(async (agentId, message) => {
|
|
363
|
+
const sessionId = config.get('sessionId');
|
|
364
|
+
if (!sessionId) {
|
|
365
|
+
console.log(chalk_1.default.yellow('Not logged in. Run: gopherhole login'));
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
const spinner = (0, ora_1.default)('Sending message...').start();
|
|
369
|
+
try {
|
|
370
|
+
const res = await fetch(`${API_URL}/../a2a`, {
|
|
371
|
+
method: 'POST',
|
|
372
|
+
headers: {
|
|
373
|
+
'Content-Type': 'application/json',
|
|
374
|
+
'X-Session-ID': sessionId,
|
|
375
|
+
},
|
|
376
|
+
body: JSON.stringify({
|
|
377
|
+
jsonrpc: '2.0',
|
|
378
|
+
method: 'message/send',
|
|
379
|
+
params: {
|
|
380
|
+
message: { role: 'user', parts: [{ kind: 'text', text: message }] },
|
|
381
|
+
configuration: { agentId },
|
|
382
|
+
},
|
|
383
|
+
id: 1,
|
|
384
|
+
}),
|
|
385
|
+
});
|
|
386
|
+
const data = await res.json();
|
|
387
|
+
spinner.succeed('Message sent!');
|
|
388
|
+
console.log(chalk_1.default.gray(JSON.stringify(data, null, 2)));
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
spinner.fail(chalk_1.default.red(err.message));
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
// Parse and run
|
|
396
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gopherhole/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "GopherHole CLI - Connect AI agents to the world",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gopherhole": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "ts-node src/index.ts",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"a2a",
|
|
16
|
+
"ai",
|
|
17
|
+
"agents",
|
|
18
|
+
"gopherhole",
|
|
19
|
+
"cli"
|
|
20
|
+
],
|
|
21
|
+
"author": "GopherHole",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"chalk": "^5.3.0",
|
|
25
|
+
"commander": "^12.0.0",
|
|
26
|
+
"conf": "^12.0.0",
|
|
27
|
+
"inquirer": "^9.2.0",
|
|
28
|
+
"open": "^10.0.0",
|
|
29
|
+
"ora": "^8.0.0",
|
|
30
|
+
"ws": "^8.16.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/inquirer": "^9.0.7",
|
|
34
|
+
"@types/node": "^20.11.0",
|
|
35
|
+
"@types/ws": "^8.5.10",
|
|
36
|
+
"ts-node": "^10.9.2",
|
|
37
|
+
"typescript": "^5.3.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import Conf from 'conf';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import open from 'open';
|
|
8
|
+
|
|
9
|
+
const config = new Conf({ projectName: 'gopherhole' });
|
|
10
|
+
const API_URL = 'https://gopherhole.ai/api';
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name('gopherhole')
|
|
16
|
+
.description('🐿️ GopherHole CLI - Connect AI agents to the world')
|
|
17
|
+
.version('0.1.0');
|
|
18
|
+
|
|
19
|
+
// ========== AUTH COMMANDS ==========
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command('login')
|
|
23
|
+
.description('Log in to GopherHole')
|
|
24
|
+
.action(async () => {
|
|
25
|
+
const { email, password } = await inquirer.prompt([
|
|
26
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
27
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const spinner = ora('Logging in...').start();
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(`${API_URL}/auth/login`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: { 'Content-Type': 'application/json' },
|
|
36
|
+
body: JSON.stringify({ email, password }),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
const err = await res.json();
|
|
41
|
+
throw new Error(err.error || 'Login failed');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const data = await res.json();
|
|
45
|
+
config.set('sessionId', data.sessionId);
|
|
46
|
+
config.set('user', data.user);
|
|
47
|
+
config.set('tenant', data.tenant);
|
|
48
|
+
|
|
49
|
+
spinner.succeed(`Logged in as ${chalk.green(data.user.email)}`);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
program
|
|
57
|
+
.command('signup')
|
|
58
|
+
.description('Create a new GopherHole account')
|
|
59
|
+
.action(async () => {
|
|
60
|
+
const { name, email, password } = await inquirer.prompt([
|
|
61
|
+
{ type: 'input', name: 'name', message: 'Name:' },
|
|
62
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
63
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
const spinner = ora('Creating account...').start();
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch(`${API_URL}/auth/signup`, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify({ name, email, password }),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const err = await res.json();
|
|
77
|
+
throw new Error(err.error || 'Signup failed');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const data = await res.json();
|
|
81
|
+
config.set('sessionId', data.sessionId);
|
|
82
|
+
config.set('user', data.user);
|
|
83
|
+
config.set('tenant', data.tenant);
|
|
84
|
+
|
|
85
|
+
spinner.succeed(`Account created! Logged in as ${chalk.green(data.user.email)}`);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
program
|
|
93
|
+
.command('logout')
|
|
94
|
+
.description('Log out of GopherHole')
|
|
95
|
+
.action(() => {
|
|
96
|
+
config.clear();
|
|
97
|
+
console.log(chalk.green('Logged out successfully'));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
program
|
|
101
|
+
.command('whoami')
|
|
102
|
+
.description('Show current logged in user')
|
|
103
|
+
.action(() => {
|
|
104
|
+
const user = config.get('user') as { email: string; name: string } | undefined;
|
|
105
|
+
if (!user) {
|
|
106
|
+
console.log(chalk.yellow('Not logged in. Run: gopherhole login'));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
console.log(`Logged in as ${chalk.green(user.email)} (${user.name})`);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// ========== AGENT COMMANDS ==========
|
|
113
|
+
|
|
114
|
+
const agents = program.command('agents').description('Manage agents');
|
|
115
|
+
|
|
116
|
+
agents
|
|
117
|
+
.command('list')
|
|
118
|
+
.description('List your agents')
|
|
119
|
+
.action(async () => {
|
|
120
|
+
const sessionId = config.get('sessionId') as string;
|
|
121
|
+
if (!sessionId) {
|
|
122
|
+
console.log(chalk.yellow('Not logged in. Run: gopherhole login'));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const spinner = ora('Fetching agents...').start();
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
130
|
+
headers: { 'X-Session-ID': sessionId },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (!res.ok) throw new Error('Failed to fetch agents');
|
|
134
|
+
|
|
135
|
+
const data = await res.json();
|
|
136
|
+
spinner.stop();
|
|
137
|
+
|
|
138
|
+
if (data.agents.length === 0) {
|
|
139
|
+
console.log(chalk.yellow('No agents yet. Create one with: gopherhole agents create'));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(chalk.bold('\nYour Agents:\n'));
|
|
144
|
+
for (const agent of data.agents) {
|
|
145
|
+
const status = agent.status === 'active' ? chalk.green('●') : chalk.red('●');
|
|
146
|
+
console.log(` ${status} ${chalk.bold(agent.name)} (${agent.id})`);
|
|
147
|
+
if (agent.description) {
|
|
148
|
+
console.log(` ${chalk.gray(agent.description)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
console.log('');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
agents
|
|
159
|
+
.command('create')
|
|
160
|
+
.description('Create a new agent')
|
|
161
|
+
.option('-n, --name <name>', 'Agent name')
|
|
162
|
+
.option('-d, --description <description>', 'Agent description')
|
|
163
|
+
.action(async (options) => {
|
|
164
|
+
const sessionId = config.get('sessionId') as string;
|
|
165
|
+
if (!sessionId) {
|
|
166
|
+
console.log(chalk.yellow('Not logged in. Run: gopherhole login'));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let { name, description } = options;
|
|
171
|
+
|
|
172
|
+
if (!name) {
|
|
173
|
+
const answers = await inquirer.prompt([
|
|
174
|
+
{ type: 'input', name: 'name', message: 'Agent name:' },
|
|
175
|
+
{ type: 'input', name: 'description', message: 'Description (optional):' },
|
|
176
|
+
]);
|
|
177
|
+
name = answers.name;
|
|
178
|
+
description = answers.description;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const spinner = ora('Creating agent...').start();
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
185
|
+
method: 'POST',
|
|
186
|
+
headers: {
|
|
187
|
+
'Content-Type': 'application/json',
|
|
188
|
+
'X-Session-ID': sessionId,
|
|
189
|
+
},
|
|
190
|
+
body: JSON.stringify({ name, description }),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (!res.ok) {
|
|
194
|
+
const err = await res.json();
|
|
195
|
+
throw new Error(err.error || 'Failed to create agent');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const data = await res.json();
|
|
199
|
+
spinner.succeed(`Agent created: ${chalk.green(data.agent.name)}`);
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log(` ${chalk.bold('Agent ID:')} ${data.agent.id}`);
|
|
202
|
+
console.log(` ${chalk.bold('API Key:')} ${chalk.cyan(data.apiKey)}`);
|
|
203
|
+
console.log('');
|
|
204
|
+
console.log(chalk.gray('Save this API key - it won\'t be shown again!'));
|
|
205
|
+
console.log('');
|
|
206
|
+
console.log(chalk.bold('Quick start:'));
|
|
207
|
+
console.log(chalk.gray(`
|
|
208
|
+
import { GopherHole } from '@gopherhole/sdk';
|
|
209
|
+
|
|
210
|
+
const hub = new GopherHole('${data.apiKey}');
|
|
211
|
+
await hub.connect();
|
|
212
|
+
|
|
213
|
+
hub.on('message', (msg) => {
|
|
214
|
+
console.log('Received:', msg);
|
|
215
|
+
});
|
|
216
|
+
`));
|
|
217
|
+
} catch (err) {
|
|
218
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
agents
|
|
224
|
+
.command('delete <agentId>')
|
|
225
|
+
.description('Delete an agent')
|
|
226
|
+
.action(async (agentId) => {
|
|
227
|
+
const sessionId = config.get('sessionId') as string;
|
|
228
|
+
if (!sessionId) {
|
|
229
|
+
console.log(chalk.yellow('Not logged in. Run: gopherhole login'));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const { confirm } = await inquirer.prompt([
|
|
234
|
+
{
|
|
235
|
+
type: 'confirm',
|
|
236
|
+
name: 'confirm',
|
|
237
|
+
message: `Are you sure you want to delete agent ${agentId}?`,
|
|
238
|
+
default: false,
|
|
239
|
+
},
|
|
240
|
+
]);
|
|
241
|
+
|
|
242
|
+
if (!confirm) {
|
|
243
|
+
console.log('Cancelled');
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const spinner = ora('Deleting agent...').start();
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
const res = await fetch(`${API_URL}/agents/${agentId}`, {
|
|
251
|
+
method: 'DELETE',
|
|
252
|
+
headers: { 'X-Session-ID': sessionId },
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
if (!res.ok) throw new Error('Failed to delete agent');
|
|
256
|
+
|
|
257
|
+
spinner.succeed('Agent deleted');
|
|
258
|
+
} catch (err) {
|
|
259
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// ========== INIT COMMAND ==========
|
|
265
|
+
|
|
266
|
+
program
|
|
267
|
+
.command('init')
|
|
268
|
+
.description('Initialize GopherHole in current directory')
|
|
269
|
+
.action(async () => {
|
|
270
|
+
console.log(chalk.bold('\n🐿️ GopherHole Init\n'));
|
|
271
|
+
|
|
272
|
+
let sessionId = config.get('sessionId') as string;
|
|
273
|
+
|
|
274
|
+
// Check if logged in
|
|
275
|
+
if (!sessionId) {
|
|
276
|
+
console.log('First, let\'s log you in (or create an account).\n');
|
|
277
|
+
|
|
278
|
+
const { action } = await inquirer.prompt([
|
|
279
|
+
{
|
|
280
|
+
type: 'list',
|
|
281
|
+
name: 'action',
|
|
282
|
+
message: 'Do you have a GopherHole account?',
|
|
283
|
+
choices: [
|
|
284
|
+
{ name: 'Yes, log me in', value: 'login' },
|
|
285
|
+
{ name: 'No, create one', value: 'signup' },
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
]);
|
|
289
|
+
|
|
290
|
+
if (action === 'signup') {
|
|
291
|
+
const { name, email, password } = await inquirer.prompt([
|
|
292
|
+
{ type: 'input', name: 'name', message: 'Name:' },
|
|
293
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
294
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
295
|
+
]);
|
|
296
|
+
|
|
297
|
+
const spinner = ora('Creating account...').start();
|
|
298
|
+
const res = await fetch(`${API_URL}/auth/signup`, {
|
|
299
|
+
method: 'POST',
|
|
300
|
+
headers: { 'Content-Type': 'application/json' },
|
|
301
|
+
body: JSON.stringify({ name, email, password }),
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (!res.ok) {
|
|
305
|
+
spinner.fail('Signup failed');
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const data = await res.json();
|
|
310
|
+
config.set('sessionId', data.sessionId);
|
|
311
|
+
config.set('user', data.user);
|
|
312
|
+
config.set('tenant', data.tenant);
|
|
313
|
+
sessionId = data.sessionId;
|
|
314
|
+
spinner.succeed('Account created!');
|
|
315
|
+
} else {
|
|
316
|
+
const { email, password } = await inquirer.prompt([
|
|
317
|
+
{ type: 'input', name: 'email', message: 'Email:' },
|
|
318
|
+
{ type: 'password', name: 'password', message: 'Password:' },
|
|
319
|
+
]);
|
|
320
|
+
|
|
321
|
+
const spinner = ora('Logging in...').start();
|
|
322
|
+
const res = await fetch(`${API_URL}/auth/login`, {
|
|
323
|
+
method: 'POST',
|
|
324
|
+
headers: { 'Content-Type': 'application/json' },
|
|
325
|
+
body: JSON.stringify({ email, password }),
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
if (!res.ok) {
|
|
329
|
+
spinner.fail('Login failed');
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const data = await res.json();
|
|
334
|
+
config.set('sessionId', data.sessionId);
|
|
335
|
+
config.set('user', data.user);
|
|
336
|
+
config.set('tenant', data.tenant);
|
|
337
|
+
sessionId = data.sessionId;
|
|
338
|
+
spinner.succeed('Logged in!');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
console.log('');
|
|
343
|
+
|
|
344
|
+
// Create agent
|
|
345
|
+
const { agentName, agentDesc } = await inquirer.prompt([
|
|
346
|
+
{ type: 'input', name: 'agentName', message: 'Agent name:', default: 'my-agent' },
|
|
347
|
+
{ type: 'input', name: 'agentDesc', message: 'Description (optional):' },
|
|
348
|
+
]);
|
|
349
|
+
|
|
350
|
+
const spinner = ora('Creating agent...').start();
|
|
351
|
+
|
|
352
|
+
const res = await fetch(`${API_URL}/agents`, {
|
|
353
|
+
method: 'POST',
|
|
354
|
+
headers: {
|
|
355
|
+
'Content-Type': 'application/json',
|
|
356
|
+
'X-Session-ID': sessionId,
|
|
357
|
+
},
|
|
358
|
+
body: JSON.stringify({ name: agentName, description: agentDesc }),
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
if (!res.ok) {
|
|
362
|
+
spinner.fail('Failed to create agent');
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const data = await res.json();
|
|
367
|
+
spinner.succeed('Agent created!');
|
|
368
|
+
|
|
369
|
+
// Write .env file
|
|
370
|
+
const fs = await import('fs');
|
|
371
|
+
fs.writeFileSync('.env', `GOPHERHOLE_API_KEY=${data.apiKey}\n`);
|
|
372
|
+
console.log(chalk.green('✓ Created .env with API key'));
|
|
373
|
+
|
|
374
|
+
// Write example code
|
|
375
|
+
const exampleCode = `import { GopherHole } from '@gopherhole/sdk';
|
|
376
|
+
|
|
377
|
+
const hub = new GopherHole(process.env.GOPHERHOLE_API_KEY);
|
|
378
|
+
|
|
379
|
+
async function main() {
|
|
380
|
+
await hub.connect();
|
|
381
|
+
console.log('🐿️ Connected to GopherHole!');
|
|
382
|
+
|
|
383
|
+
hub.on('message', async (msg) => {
|
|
384
|
+
console.log(\`Message from \${msg.from}:\`, msg.payload);
|
|
385
|
+
|
|
386
|
+
// Reply to the message
|
|
387
|
+
await hub.sendText(msg.from, 'Hello back!');
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
main().catch(console.error);
|
|
392
|
+
`;
|
|
393
|
+
fs.writeFileSync('agent.ts', exampleCode);
|
|
394
|
+
console.log(chalk.green('✓ Created agent.ts example'));
|
|
395
|
+
|
|
396
|
+
console.log('');
|
|
397
|
+
console.log(chalk.bold('Next steps:'));
|
|
398
|
+
console.log('');
|
|
399
|
+
console.log(' 1. Install the SDK:');
|
|
400
|
+
console.log(chalk.cyan(' npm install @gopherhole/sdk'));
|
|
401
|
+
console.log('');
|
|
402
|
+
console.log(' 2. Run your agent:');
|
|
403
|
+
console.log(chalk.cyan(' npx ts-node agent.ts'));
|
|
404
|
+
console.log('');
|
|
405
|
+
console.log(chalk.gray(`Dashboard: https://gopherhole.ai/dashboard`));
|
|
406
|
+
console.log('');
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// ========== SEND COMMAND ==========
|
|
410
|
+
|
|
411
|
+
program
|
|
412
|
+
.command('send <agentId> <message>')
|
|
413
|
+
.description('Send a message to an agent (for testing)')
|
|
414
|
+
.action(async (agentId, message) => {
|
|
415
|
+
const sessionId = config.get('sessionId') as string;
|
|
416
|
+
if (!sessionId) {
|
|
417
|
+
console.log(chalk.yellow('Not logged in. Run: gopherhole login'));
|
|
418
|
+
process.exit(1);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const spinner = ora('Sending message...').start();
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const res = await fetch(`${API_URL}/../a2a`, {
|
|
425
|
+
method: 'POST',
|
|
426
|
+
headers: {
|
|
427
|
+
'Content-Type': 'application/json',
|
|
428
|
+
'X-Session-ID': sessionId,
|
|
429
|
+
},
|
|
430
|
+
body: JSON.stringify({
|
|
431
|
+
jsonrpc: '2.0',
|
|
432
|
+
method: 'message/send',
|
|
433
|
+
params: {
|
|
434
|
+
message: { role: 'user', parts: [{ kind: 'text', text: message }] },
|
|
435
|
+
configuration: { agentId },
|
|
436
|
+
},
|
|
437
|
+
id: 1,
|
|
438
|
+
}),
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const data = await res.json();
|
|
442
|
+
spinner.succeed('Message sent!');
|
|
443
|
+
console.log(chalk.gray(JSON.stringify(data, null, 2)));
|
|
444
|
+
} catch (err) {
|
|
445
|
+
spinner.fail(chalk.red((err as Error).message));
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Parse and run
|
|
451
|
+
program.parse();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|