@orcapt/cli 1.0.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/LICENSE +22 -0
- package/QUICK_START.md +241 -0
- package/README.md +949 -0
- package/bin/orca.js +406 -0
- package/package.json +58 -0
- package/src/commands/db.js +248 -0
- package/src/commands/fetch-doc.js +220 -0
- package/src/commands/kickstart-node.js +431 -0
- package/src/commands/kickstart-python.js +360 -0
- package/src/commands/lambda.js +736 -0
- package/src/commands/login.js +277 -0
- package/src/commands/storage.js +911 -0
- package/src/commands/ui.js +286 -0
- package/src/config.js +62 -0
- package/src/utils/docker-helper.js +357 -0
- package/src/utils/index.js +349 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kickstart command for Node.js - Quick setup for a new Orca Node.js project
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs').promises;
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const inquirer = require('inquirer');
|
|
9
|
+
const ora = require('ora');
|
|
10
|
+
const simpleGit = require('simple-git');
|
|
11
|
+
const {
|
|
12
|
+
commandExists,
|
|
13
|
+
spawnBackground,
|
|
14
|
+
ensurePortAvailable,
|
|
15
|
+
print
|
|
16
|
+
} = require('../utils');
|
|
17
|
+
const { GITHUB_REPOS } = require('../config');
|
|
18
|
+
|
|
19
|
+
const REPO_URL = GITHUB_REPOS.NODE_STARTER;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check all prerequisites for Node.js
|
|
23
|
+
*/
|
|
24
|
+
async function checkPrerequisites() {
|
|
25
|
+
const spinner = ora('Checking prerequisites...').start();
|
|
26
|
+
const missing = [];
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// Check Node.js
|
|
30
|
+
spinner.start('Checking Node.js...');
|
|
31
|
+
if (await commandExists('node')) {
|
|
32
|
+
spinner.succeed(chalk.green('Node.js found'));
|
|
33
|
+
} else {
|
|
34
|
+
missing.push('Node.js');
|
|
35
|
+
spinner.warn(chalk.yellow('Node.js not found'));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check npm
|
|
39
|
+
spinner.start('Checking npm...');
|
|
40
|
+
if (await commandExists('npm')) {
|
|
41
|
+
spinner.succeed(chalk.green('npm found'));
|
|
42
|
+
} else {
|
|
43
|
+
missing.push('npm');
|
|
44
|
+
spinner.warn(chalk.yellow('npm not found'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check Git
|
|
48
|
+
spinner.start('Checking Git...');
|
|
49
|
+
if (await commandExists('git')) {
|
|
50
|
+
spinner.succeed(chalk.green('Git found'));
|
|
51
|
+
} else {
|
|
52
|
+
missing.push('Git');
|
|
53
|
+
spinner.warn(chalk.yellow('Git not found'));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check npx
|
|
57
|
+
spinner.start('Checking npx...');
|
|
58
|
+
if (await commandExists('npx')) {
|
|
59
|
+
spinner.succeed(chalk.green('npx found'));
|
|
60
|
+
} else {
|
|
61
|
+
missing.push('npx');
|
|
62
|
+
spinner.warn(chalk.yellow('npx not found'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (missing.length > 0) {
|
|
66
|
+
spinner.stop();
|
|
67
|
+
print.error('Missing prerequisites:');
|
|
68
|
+
missing.forEach(item => console.log(` - ${item}`));
|
|
69
|
+
console.log();
|
|
70
|
+
print.info('Please install the missing prerequisites:');
|
|
71
|
+
console.log(' - Node.js: https://nodejs.org/');
|
|
72
|
+
console.log(' - Git: https://git-scm.com/downloads\n');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
spinner.stop();
|
|
77
|
+
return true;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
spinner.fail('Failed to check prerequisites');
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Clone repository
|
|
86
|
+
*/
|
|
87
|
+
async function cloneRepository(directory) {
|
|
88
|
+
const spinner = ora('Cloning Orca Node.js starter kit from GitHub...').start();
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const git = simpleGit();
|
|
92
|
+
await git.clone(REPO_URL, directory);
|
|
93
|
+
spinner.succeed(chalk.green('Repository cloned successfully'));
|
|
94
|
+
} catch (error) {
|
|
95
|
+
spinner.fail('Failed to clone repository');
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Fix package.json to use npm packages instead of local file references
|
|
102
|
+
*/
|
|
103
|
+
async function fixPackageJson(projectPath) {
|
|
104
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
105
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
106
|
+
|
|
107
|
+
// Replace local file reference with npm package
|
|
108
|
+
if (packageJson.dependencies && packageJson.dependencies['@orca/sdk']) {
|
|
109
|
+
if (packageJson.dependencies['@orca/sdk'].startsWith('file:')) {
|
|
110
|
+
packageJson.dependencies['@orca/sdk'] = '^1.0.0';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create memory directory with required files (not tracked by git)
|
|
119
|
+
*/
|
|
120
|
+
async function createMemoryModule(projectPath) {
|
|
121
|
+
const memoryDir = path.join(projectPath, 'memory');
|
|
122
|
+
await fs.mkdir(memoryDir, { recursive: true });
|
|
123
|
+
|
|
124
|
+
// Create index.js
|
|
125
|
+
const indexContent = `const { ConversationManager } = require('./conversation_manager');
|
|
126
|
+
|
|
127
|
+
module.exports = {
|
|
128
|
+
ConversationManager
|
|
129
|
+
};
|
|
130
|
+
`;
|
|
131
|
+
await fs.writeFile(path.join(memoryDir, 'index.js'), indexContent);
|
|
132
|
+
|
|
133
|
+
// Create conversation_manager.js
|
|
134
|
+
const conversationManagerContent = `/**
|
|
135
|
+
* Conversation Manager
|
|
136
|
+
* Handles conversation history and thread management
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
class ConversationManager {
|
|
140
|
+
constructor() {
|
|
141
|
+
this.conversations = new Map();
|
|
142
|
+
this.maxHistory = 20;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getConversation(threadId) {
|
|
146
|
+
if (!this.conversations.has(threadId)) {
|
|
147
|
+
this.conversations.set(threadId, []);
|
|
148
|
+
}
|
|
149
|
+
return this.conversations.get(threadId);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
addMessage(threadId, role, content) {
|
|
153
|
+
const conversation = this.getConversation(threadId);
|
|
154
|
+
conversation.push({ role, content });
|
|
155
|
+
|
|
156
|
+
// Keep only last maxHistory messages
|
|
157
|
+
if (conversation.length > this.maxHistory) {
|
|
158
|
+
conversation.splice(0, conversation.length - this.maxHistory);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
clearConversation(threadId) {
|
|
163
|
+
this.conversations.delete(threadId);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getAllConversations() {
|
|
167
|
+
return Array.from(this.conversations.keys());
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = { ConversationManager };
|
|
172
|
+
`;
|
|
173
|
+
await fs.writeFile(path.join(memoryDir, 'conversation_manager.js'), conversationManagerContent);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Install Node.js dependencies
|
|
178
|
+
*/
|
|
179
|
+
async function installDependencies(projectPath) {
|
|
180
|
+
const spinner = ora('Installing Node.js dependencies...').start();
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
// Fix package.json first
|
|
184
|
+
await fixPackageJson(projectPath);
|
|
185
|
+
|
|
186
|
+
// Note: memory module is now included in the GitHub repo, no need to create it
|
|
187
|
+
|
|
188
|
+
const { spawn } = require('cross-spawn');
|
|
189
|
+
|
|
190
|
+
await new Promise((resolve, reject) => {
|
|
191
|
+
const npmProcess = spawn('npm', ['install'], {
|
|
192
|
+
cwd: projectPath,
|
|
193
|
+
stdio: 'pipe',
|
|
194
|
+
shell: false
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
let output = '';
|
|
198
|
+
let errorOutput = '';
|
|
199
|
+
|
|
200
|
+
npmProcess.stdout.on('data', (data) => {
|
|
201
|
+
output += data.toString();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
npmProcess.stderr.on('data', (data) => {
|
|
205
|
+
errorOutput += data.toString();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
npmProcess.on('close', (code) => {
|
|
209
|
+
if (code === 0) {
|
|
210
|
+
resolve();
|
|
211
|
+
} else {
|
|
212
|
+
reject(new Error(errorOutput || output));
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
npmProcess.on('error', (error) => {
|
|
217
|
+
reject(error);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
spinner.succeed(chalk.green('Dependencies installed'));
|
|
222
|
+
} catch (error) {
|
|
223
|
+
spinner.fail('Failed to install dependencies');
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Start Node.js agent server
|
|
230
|
+
*/
|
|
231
|
+
async function startAgent(projectPath, agentPort) {
|
|
232
|
+
const spinner = ora(`Starting agent server on port ${agentPort}...`).start();
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const agentProcess = spawnBackground('node', ['main.js', '--dev'], {
|
|
236
|
+
cwd: projectPath,
|
|
237
|
+
env: { ...process.env, PORT: agentPort }
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Wait a bit for the server to start
|
|
241
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
242
|
+
|
|
243
|
+
// Check if process is still running
|
|
244
|
+
if (agentProcess.exitCode !== null) {
|
|
245
|
+
throw new Error('Agent process exited immediately');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
spinner.succeed(chalk.green(`Agent started (PID: ${agentProcess.pid})`));
|
|
249
|
+
return agentProcess;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
spinner.fail('Failed to start agent');
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Start Orca-UI frontend server
|
|
258
|
+
*/
|
|
259
|
+
async function startUI(projectPath, port, agentPort) {
|
|
260
|
+
const spinner = ora(`Starting Orca-UI server on port ${port}...`).start();
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const uiProcess = spawnBackground('npx', [
|
|
264
|
+
'-y',
|
|
265
|
+
'@orca/ui',
|
|
266
|
+
'orca',
|
|
267
|
+
`--port=${port}`,
|
|
268
|
+
`--agent-port=${agentPort}`
|
|
269
|
+
], {
|
|
270
|
+
cwd: projectPath
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Wait for UI to start
|
|
274
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
275
|
+
|
|
276
|
+
// Check if process is still running
|
|
277
|
+
if (uiProcess.exitCode !== null) {
|
|
278
|
+
throw new Error('Orca-UI process exited immediately');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
spinner.succeed(chalk.green(`Orca-UI started (PID: ${uiProcess.pid})`));
|
|
282
|
+
return uiProcess;
|
|
283
|
+
} catch (error) {
|
|
284
|
+
spinner.fail('Failed to start Orca-UI');
|
|
285
|
+
throw error;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Main kickstart command for Node.js
|
|
291
|
+
*/
|
|
292
|
+
async function kickstartNode(options) {
|
|
293
|
+
try {
|
|
294
|
+
const { directory, port, agentPort, start } = options;
|
|
295
|
+
|
|
296
|
+
print.title('🚀 Orca Kickstart - Node.js');
|
|
297
|
+
|
|
298
|
+
// Check prerequisites
|
|
299
|
+
await checkPrerequisites();
|
|
300
|
+
|
|
301
|
+
// Check if directory exists
|
|
302
|
+
const projectPath = path.resolve(process.cwd(), directory);
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
await fs.access(projectPath);
|
|
306
|
+
print.error(`Directory '${directory}' already exists`);
|
|
307
|
+
|
|
308
|
+
const { shouldRemove } = await inquirer.prompt([
|
|
309
|
+
{
|
|
310
|
+
type: 'confirm',
|
|
311
|
+
name: 'shouldRemove',
|
|
312
|
+
message: 'Do you want to remove it and continue?',
|
|
313
|
+
default: false
|
|
314
|
+
}
|
|
315
|
+
]);
|
|
316
|
+
|
|
317
|
+
if (!shouldRemove) {
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
await fs.rm(projectPath, { recursive: true, force: true });
|
|
322
|
+
} catch (error) {
|
|
323
|
+
// Directory doesn't exist, which is fine
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Create directory
|
|
327
|
+
print.step(`Creating directory: ${directory}`);
|
|
328
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
329
|
+
print.success(`Created directory: ${projectPath}`);
|
|
330
|
+
|
|
331
|
+
// Clone repository
|
|
332
|
+
await cloneRepository(projectPath);
|
|
333
|
+
|
|
334
|
+
// Install dependencies
|
|
335
|
+
await installDependencies(projectPath);
|
|
336
|
+
|
|
337
|
+
// Setup complete
|
|
338
|
+
print.title('✓ Setup completed successfully!');
|
|
339
|
+
|
|
340
|
+
// Ask to start servers
|
|
341
|
+
const shouldStart = start !== false ? await inquirer.prompt([
|
|
342
|
+
{
|
|
343
|
+
type: 'confirm',
|
|
344
|
+
name: 'start',
|
|
345
|
+
message: 'Do you want to start the agent and Orca-UI servers now?',
|
|
346
|
+
default: true
|
|
347
|
+
}
|
|
348
|
+
]).then(answers => answers.start) : false;
|
|
349
|
+
|
|
350
|
+
if (!shouldStart) {
|
|
351
|
+
console.log();
|
|
352
|
+
print.info('To start manually:');
|
|
353
|
+
console.log(chalk.gray(` cd ${directory}`));
|
|
354
|
+
console.log(chalk.gray(` node main.js --dev`));
|
|
355
|
+
console.log(chalk.gray(` # In another terminal:`));
|
|
356
|
+
console.log(chalk.gray(` npx -y @orca/ui orca --port=${port} --agent-port=${agentPort}`));
|
|
357
|
+
console.log();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Start servers
|
|
362
|
+
console.log();
|
|
363
|
+
// Ensure ports are available before starting
|
|
364
|
+
await ensurePortAvailable(agentPort, 'Agent');
|
|
365
|
+
await ensurePortAvailable(port, 'UI');
|
|
366
|
+
|
|
367
|
+
const agentProcess = await startAgent(projectPath, agentPort);
|
|
368
|
+
const uiProcess = await startUI(projectPath, port, agentPort);
|
|
369
|
+
|
|
370
|
+
// Display success message
|
|
371
|
+
print.title('🎉 Orca is running!');
|
|
372
|
+
print.url('Orca-UI', `http://localhost:${port}`);
|
|
373
|
+
print.url('Agent ', `http://localhost:${agentPort}`);
|
|
374
|
+
console.log();
|
|
375
|
+
print.warning('Press Ctrl+C to stop both servers');
|
|
376
|
+
console.log();
|
|
377
|
+
|
|
378
|
+
// Handle graceful shutdown
|
|
379
|
+
const shutdown = () => {
|
|
380
|
+
console.log();
|
|
381
|
+
print.step('Shutting down servers...');
|
|
382
|
+
|
|
383
|
+
if (agentProcess && !agentProcess.killed) {
|
|
384
|
+
agentProcess.kill();
|
|
385
|
+
}
|
|
386
|
+
if (uiProcess && !uiProcess.killed) {
|
|
387
|
+
uiProcess.kill();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
setTimeout(() => {
|
|
391
|
+
print.success('Servers stopped');
|
|
392
|
+
process.exit(0);
|
|
393
|
+
}, 1000);
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
process.on('SIGINT', shutdown);
|
|
397
|
+
process.on('SIGTERM', shutdown);
|
|
398
|
+
|
|
399
|
+
// Monitor processes
|
|
400
|
+
agentProcess.on('exit', (code) => {
|
|
401
|
+
if (code !== 0 && code !== null) {
|
|
402
|
+
print.error('Agent stopped unexpectedly');
|
|
403
|
+
if (uiProcess && !uiProcess.killed) {
|
|
404
|
+
uiProcess.kill();
|
|
405
|
+
}
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
uiProcess.on('exit', (code) => {
|
|
411
|
+
if (code !== 0 && code !== null) {
|
|
412
|
+
print.error('Orca-UI stopped unexpectedly');
|
|
413
|
+
if (agentProcess && !agentProcess.killed) {
|
|
414
|
+
agentProcess.kill();
|
|
415
|
+
}
|
|
416
|
+
process.exit(1);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Keep process alive
|
|
421
|
+
await new Promise(() => {});
|
|
422
|
+
|
|
423
|
+
} catch (error) {
|
|
424
|
+
print.error(`Failed: ${error.message}`);
|
|
425
|
+
console.error(error);
|
|
426
|
+
process.exit(1);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
module.exports = kickstartNode;
|
|
431
|
+
|