stigmergy 1.0.99 → 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 +17 -0
- package/bin/stigmergy +1 -1
- package/bin/stigmergy.cmd +1 -1
- package/docs/NATIVE_INTEGRATION_GUIDE.md +1155 -1190
- package/docs/PROJECT_STRUCTURE.md +283 -303
- package/package.json +10 -7
- package/src/cli/router.js +460 -0
- package/src/core/coordination/index.js +16 -0
- package/src/core/coordination/nodejs/AdapterManager.js +89 -0
- package/src/core/coordination/nodejs/CLCommunication.js +59 -0
- package/src/core/coordination/nodejs/CLIIntegrationManager.js +236 -0
- package/src/core/coordination/nodejs/HealthChecker.js +77 -0
- package/src/core/coordination/nodejs/HookDeploymentManager.js +256 -0
- package/src/core/coordination/nodejs/StatisticsCollector.js +71 -0
- package/src/core/coordination/nodejs/index.js +72 -0
- package/src/core/coordination/nodejs/utils/Logger.js +29 -0
- package/src/core/installer.js +374 -0
- package/src/index.js +25 -4
- package/src/main.js +1068 -831
- package/src/utils/helpers.js +35 -0
- package/test/cross-cli-detection-test.js +33 -0
- package/test/python-plugins-test.js +259 -0
- package/test/remaining-adapters-test.js +256 -0
- package/test/system-compatibility-test.js +466 -446
- package/test/tool-selection-integration-test.js +157 -156
- package/src/main_english.js +0 -1338
package/src/main_english.js
DELETED
|
@@ -1,1338 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System
|
|
5
|
-
* International Version - Pure English & ANSI Only
|
|
6
|
-
* Version: 1.0.94
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
if (process.env.DEBUG === 'true') {
|
|
10
|
-
console.log('[DEBUG] Stigmergy CLI script started...');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { spawn, spawnSync } = require('child_process');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const fs = require('fs/promises');
|
|
16
|
-
const os = require('os');
|
|
17
|
-
const { Command } = require('commander');
|
|
18
|
-
const inquirer = require('inquirer');
|
|
19
|
-
const chalk = require('chalk');
|
|
20
|
-
const yaml = require('js-yaml');
|
|
21
|
-
|
|
22
|
-
// Import our custom modules
|
|
23
|
-
const SmartRouter = require('./core/smart_router');
|
|
24
|
-
const CLIHelpAnalyzer = require('./core/cli_help_analyzer');
|
|
25
|
-
const { CLI_TOOLS } = require('./core/cli_tools');
|
|
26
|
-
const { errorHandler } = require('./core/error_handler');
|
|
27
|
-
const { executeCommand, executeJSFile } = require('./utils');
|
|
28
|
-
|
|
29
|
-
const { UserAuthenticator } = require('./auth');
|
|
30
|
-
const fsSync = require('fs');
|
|
31
|
-
|
|
32
|
-
// Set up global error handlers using our error handler module
|
|
33
|
-
const { setupGlobalErrorHandlers } = require('./core/error_handler');
|
|
34
|
-
setupGlobalErrorHandlers();
|
|
35
|
-
|
|
36
|
-
class MemoryManager {
|
|
37
|
-
constructor() {
|
|
38
|
-
this.globalMemoryFile = path.join(
|
|
39
|
-
os.homedir(),
|
|
40
|
-
'.stigmergy',
|
|
41
|
-
'memory.json',
|
|
42
|
-
);
|
|
43
|
-
this.projectMemoryFile = path.join(process.cwd(), 'STIGMERGY.md');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async addInteraction(tool, prompt, response) {
|
|
47
|
-
const interaction = {
|
|
48
|
-
timestamp: new Date().toISOString(),
|
|
49
|
-
tool,
|
|
50
|
-
prompt,
|
|
51
|
-
response,
|
|
52
|
-
duration: Date.now() - new Date().getTime(),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
// Add to global memory
|
|
57
|
-
await this.saveGlobalMemory(interaction);
|
|
58
|
-
|
|
59
|
-
// Add to project memory
|
|
60
|
-
await this.saveProjectMemory(interaction);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
await errorHandler.logError(
|
|
63
|
-
error,
|
|
64
|
-
'ERROR',
|
|
65
|
-
'MemoryManager.addInteraction',
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async saveGlobalMemory(interaction) {
|
|
71
|
-
try {
|
|
72
|
-
const memory = await this.loadGlobalMemory();
|
|
73
|
-
memory.interactions = memory.interactions.concat(interaction).slice(-100); // Keep last 100
|
|
74
|
-
memory.lastInteraction = interaction;
|
|
75
|
-
|
|
76
|
-
await fs.mkdir(path.dirname(this.globalMemoryFile), { recursive: true });
|
|
77
|
-
await fs.writeFile(
|
|
78
|
-
this.globalMemoryFile,
|
|
79
|
-
JSON.stringify(memory, null, 2),
|
|
80
|
-
);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
await errorHandler.logError(
|
|
83
|
-
error,
|
|
84
|
-
'ERROR',
|
|
85
|
-
'MemoryManager.saveGlobalMemory',
|
|
86
|
-
);
|
|
87
|
-
console.error(`[MEMORY] Failed to save global memory: ${error.message}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async saveProjectMemory(interaction) {
|
|
92
|
-
try {
|
|
93
|
-
const memory = await this.loadProjectMemory();
|
|
94
|
-
memory.interactions = memory.interactions.concat(interaction).slice(-50); // Keep last 50
|
|
95
|
-
memory.lastInteraction = interaction;
|
|
96
|
-
|
|
97
|
-
await fs.writeFile(
|
|
98
|
-
this.projectMemoryFile,
|
|
99
|
-
this.formatProjectMemory(memory),
|
|
100
|
-
);
|
|
101
|
-
} catch (error) {
|
|
102
|
-
await errorHandler.logError(
|
|
103
|
-
error,
|
|
104
|
-
'ERROR',
|
|
105
|
-
'MemoryManager.saveProjectMemory',
|
|
106
|
-
);
|
|
107
|
-
console.error(`[MEMORY] Failed to save project memory: ${error.message}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async loadGlobalMemory() {
|
|
112
|
-
try {
|
|
113
|
-
const data = await fs.readFile(this.globalMemoryFile, 'utf8');
|
|
114
|
-
return JSON.parse(data);
|
|
115
|
-
} catch {
|
|
116
|
-
return {
|
|
117
|
-
projectName: 'Global Stigmergy Memory',
|
|
118
|
-
interactions: [],
|
|
119
|
-
createdAt: new Date().toISOString(),
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async loadProjectMemory() {
|
|
125
|
-
try {
|
|
126
|
-
const data = await fs.readFile(this.projectMemoryFile, 'utf8');
|
|
127
|
-
return this.parseProjectMemory(data);
|
|
128
|
-
} catch {
|
|
129
|
-
return {
|
|
130
|
-
projectName: path.basename(process.cwd()),
|
|
131
|
-
interactions: [],
|
|
132
|
-
createdAt: new Date().toISOString(),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
formatProjectMemory(memory) {
|
|
138
|
-
let content = '# Stigmergy Project Memory\n\n';
|
|
139
|
-
content += `**Project**: ${memory.projectName}\n`;
|
|
140
|
-
content += `**Created**: ${memory.createdAt}\n`;
|
|
141
|
-
content += `**Last Updated**: ${new Date().toISOString()}\n\n`;
|
|
142
|
-
|
|
143
|
-
if (memory.lastInteraction) {
|
|
144
|
-
content += '## Last Interaction\n\n';
|
|
145
|
-
content += `- **Tool**: ${memory.lastInteraction.tool}\n`;
|
|
146
|
-
content += `- **Timestamp**: ${memory.lastInteraction.timestamp}\n`;
|
|
147
|
-
content += `- **Prompt**: ${memory.lastInteraction.prompt}\n`;
|
|
148
|
-
content += `- **Response**: ${memory.lastInteraction.response.substring(0, 200)}...\n\n`;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
content += `## Recent Interactions (${memory.interactions.length})\n\n`;
|
|
152
|
-
memory.interactions.slice(-10).forEach((interaction, index) => {
|
|
153
|
-
content += `### ${index + 1}. ${interaction.tool} - ${interaction.timestamp}\n\n`;
|
|
154
|
-
content += `**Prompt**: ${interaction.prompt}\n\n`;
|
|
155
|
-
content += `**Response**: ${interaction.response.substring(0, 200)}...\n\n`;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return content;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
parseProjectMemory(_) {
|
|
162
|
-
// Simple parser for project memory
|
|
163
|
-
return {
|
|
164
|
-
projectName: 'Project',
|
|
165
|
-
interactions: [],
|
|
166
|
-
createdAt: new Date().toISOString(),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
class StigmergyInstaller {
|
|
172
|
-
constructor() {
|
|
173
|
-
this.router = new SmartRouter();
|
|
174
|
-
this.memory = new MemoryManager();
|
|
175
|
-
this.configDir = path.join(os.homedir(), '.stigmergy');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async checkCLI(toolName) {
|
|
179
|
-
const tool = this.router.tools[toolName];
|
|
180
|
-
if (!tool) return false;
|
|
181
|
-
|
|
182
|
-
// Try multiple ways to check if CLI is available
|
|
183
|
-
const checks = [
|
|
184
|
-
// Method 1: Try version command
|
|
185
|
-
{ args: ['--version'], expected: 0 },
|
|
186
|
-
// Method 2: Try help command
|
|
187
|
-
{ args: ['--help'], expected: 0 },
|
|
188
|
-
// Method 3: Try help command with -h
|
|
189
|
-
{ args: ['-h'], expected: 0 },
|
|
190
|
-
// Method 4: Try just the command (help case)
|
|
191
|
-
{ args: [], expected: 0 },
|
|
192
|
-
];
|
|
193
|
-
|
|
194
|
-
for (const check of checks) {
|
|
195
|
-
try {
|
|
196
|
-
const result = spawnSync(toolName, check.args, {
|
|
197
|
-
encoding: 'utf8',
|
|
198
|
-
timeout: 5000,
|
|
199
|
-
shell: true,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Check if command executed successfully or at least didn't fail with "command not found"
|
|
203
|
-
if (
|
|
204
|
-
result.status === check.expected ||
|
|
205
|
-
(result.status !== 127 && result.status !== 9009)
|
|
206
|
-
) {
|
|
207
|
-
// 127 = command not found on Unix, 9009 = command not found on Windows
|
|
208
|
-
return true;
|
|
209
|
-
}
|
|
210
|
-
} catch (error) {
|
|
211
|
-
// Continue to next check method
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async scanCLI() {
|
|
220
|
-
console.log('[SCAN] Scanning for AI CLI tools...');
|
|
221
|
-
const available = {};
|
|
222
|
-
const missing = {};
|
|
223
|
-
|
|
224
|
-
for (const [toolName, toolInfo] of Object.entries(this.router.tools)) {
|
|
225
|
-
try {
|
|
226
|
-
console.log(`[SCAN] Checking ${toolInfo.name}...`);
|
|
227
|
-
const isAvailable = await this.checkCLI(toolName);
|
|
228
|
-
|
|
229
|
-
if (isAvailable) {
|
|
230
|
-
console.log(`[OK] ${toolInfo.name} is available`);
|
|
231
|
-
available[toolName] = toolInfo;
|
|
232
|
-
} else {
|
|
233
|
-
console.log(`[MISSING] ${toolInfo.name} is not installed`);
|
|
234
|
-
missing[toolName] = toolInfo;
|
|
235
|
-
}
|
|
236
|
-
} catch (error) {
|
|
237
|
-
await errorHandler.logError(
|
|
238
|
-
error,
|
|
239
|
-
'WARN',
|
|
240
|
-
`StigmergyInstaller.scanCLI.${toolName}`,
|
|
241
|
-
);
|
|
242
|
-
console.log(
|
|
243
|
-
`[ERROR] Failed to check ${toolInfo.name}: ${error.message}`,
|
|
244
|
-
);
|
|
245
|
-
missing[toolName] = toolInfo;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return { available, missing };
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async installTools(selectedTools, missingTools) {
|
|
253
|
-
console.log(
|
|
254
|
-
`\n[INSTALL] Installing ${selectedTools.length} AI CLI tools...`,
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
for (const toolName of selectedTools) {
|
|
258
|
-
const toolInfo = missingTools[toolName];
|
|
259
|
-
if (!toolInfo) {
|
|
260
|
-
console.log(`[SKIP] Tool ${toolName} not found in missing tools list`);
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
console.log(`\n[INSTALL] Installing ${toolInfo.name}...`);
|
|
266
|
-
console.log(`[CMD] ${toolInfo.install}`);
|
|
267
|
-
|
|
268
|
-
const result = spawnSync(toolInfo.install, {
|
|
269
|
-
shell: true,
|
|
270
|
-
stdio: 'inherit',
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
if (result.status === 0) {
|
|
274
|
-
console.log(`[OK] ${toolInfo.name} installed successfully`);
|
|
275
|
-
} else {
|
|
276
|
-
console.log(
|
|
277
|
-
`[ERROR] Failed to install ${toolInfo.name} (exit code: ${result.status})`,
|
|
278
|
-
);
|
|
279
|
-
if (result.error) {
|
|
280
|
-
console.log(`[ERROR] Installation error: ${result.error.message}`);
|
|
281
|
-
}
|
|
282
|
-
console.log(`[INFO] Please run manually: ${toolInfo.install}`);
|
|
283
|
-
}
|
|
284
|
-
} catch (error) {
|
|
285
|
-
await errorHandler.logError(
|
|
286
|
-
error,
|
|
287
|
-
'ERROR',
|
|
288
|
-
`StigmergyInstaller.installTools.${toolName}`,
|
|
289
|
-
);
|
|
290
|
-
console.log(
|
|
291
|
-
`[ERROR] Failed to install ${toolInfo.name}: ${error.message}`,
|
|
292
|
-
);
|
|
293
|
-
console.log(`[INFO] Please run manually: ${toolInfo.install}`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async downloadRequiredAssets() {
|
|
301
|
-
console.log('\n[DOWNLOAD] Downloading required assets and plugins...');
|
|
302
|
-
|
|
303
|
-
// SAFETY CHECK: Verify no conflicting packages exist
|
|
304
|
-
await this.safetyCheck();
|
|
305
|
-
|
|
306
|
-
try {
|
|
307
|
-
// Create local assets directory
|
|
308
|
-
const assetsDir = path.join(os.homedir(), '.stigmergy', 'assets');
|
|
309
|
-
await fs.mkdir(assetsDir, { recursive: true });
|
|
310
|
-
|
|
311
|
-
// Copy template files from package
|
|
312
|
-
const packageTemplatesDir = path.join(
|
|
313
|
-
__dirname,
|
|
314
|
-
'..',
|
|
315
|
-
'templates',
|
|
316
|
-
'project-docs',
|
|
317
|
-
);
|
|
318
|
-
const localTemplatesDir = path.join(assetsDir, 'templates');
|
|
319
|
-
|
|
320
|
-
if (await this.fileExists(packageTemplatesDir)) {
|
|
321
|
-
await fs.mkdir(localTemplatesDir, { recursive: true });
|
|
322
|
-
|
|
323
|
-
// Copy all template files
|
|
324
|
-
const templateFiles = await fs.readdir(packageTemplatesDir);
|
|
325
|
-
for (const file of templateFiles) {
|
|
326
|
-
const srcPath = path.join(packageTemplatesDir, file);
|
|
327
|
-
const dstPath = path.join(localTemplatesDir, file);
|
|
328
|
-
await fs.copyFile(srcPath, dstPath);
|
|
329
|
-
console.log(`[OK] Copied template: ${file}`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Download/copy CLI adapters
|
|
334
|
-
const adaptersDir = path.join(__dirname, '..', 'src', 'adapters');
|
|
335
|
-
const localAdaptersDir = path.join(assetsDir, 'adapters');
|
|
336
|
-
|
|
337
|
-
if (await this.fileExists(adaptersDir)) {
|
|
338
|
-
await fs.mkdir(localAdaptersDir, { recursive: true });
|
|
339
|
-
|
|
340
|
-
// Copy all adapter directories
|
|
341
|
-
const adapterDirs = await fs.readdir(adaptersDir);
|
|
342
|
-
for (const dir of adapterDirs) {
|
|
343
|
-
// Skip non-directory items
|
|
344
|
-
const dirPath = path.join(adaptersDir, dir);
|
|
345
|
-
const stat = await fs.stat(dirPath);
|
|
346
|
-
if (!stat.isDirectory()) continue;
|
|
347
|
-
|
|
348
|
-
// Skip __pycache__ directories
|
|
349
|
-
if (dir === '__pycache__') continue;
|
|
350
|
-
|
|
351
|
-
const dstPath = path.join(localAdaptersDir, dir);
|
|
352
|
-
await this.copyDirectory(dirPath, dstPath);
|
|
353
|
-
console.log(`[OK] Copied adapter: ${dir}`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
console.log('[OK] All required assets downloaded successfully');
|
|
358
|
-
return true;
|
|
359
|
-
} catch (error) {
|
|
360
|
-
await errorHandler.logError(
|
|
361
|
-
error,
|
|
362
|
-
'ERROR',
|
|
363
|
-
'StigmergyInstaller.downloadRequiredAssets',
|
|
364
|
-
);
|
|
365
|
-
console.log(
|
|
366
|
-
`[ERROR] Failed to download required assets: ${error.message}`,
|
|
367
|
-
);
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
async safetyCheck() {
|
|
373
|
-
console.log(
|
|
374
|
-
'\n[SAFETY] Performing safety check for conflicting packages...',
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
// List of potentially conflicting packages
|
|
378
|
-
const conflictingPackages = [
|
|
379
|
-
'@aws-amplify/cli',
|
|
380
|
-
'firebase-tools',
|
|
381
|
-
'heroku',
|
|
382
|
-
'netlify-cli',
|
|
383
|
-
'vercel',
|
|
384
|
-
'surge',
|
|
385
|
-
'now',
|
|
386
|
-
];
|
|
387
|
-
|
|
388
|
-
// Check for globally installed conflicting packages
|
|
389
|
-
try {
|
|
390
|
-
const result = spawnSync('npm', ['list', '-g', '--depth=0'], {
|
|
391
|
-
encoding: 'utf8',
|
|
392
|
-
timeout: 10000,
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
if (result.status === 0) {
|
|
396
|
-
const installedPackages = result.stdout;
|
|
397
|
-
const conflicts = [];
|
|
398
|
-
|
|
399
|
-
for (const pkg of conflictingPackages) {
|
|
400
|
-
if (installedPackages.includes(pkg)) {
|
|
401
|
-
conflicts.push(pkg);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (conflicts.length > 0) {
|
|
406
|
-
console.log(
|
|
407
|
-
`[WARN] Potential conflicting packages detected: ${conflicts.join(', ')}`,
|
|
408
|
-
);
|
|
409
|
-
console.log(
|
|
410
|
-
'[INFO] These packages may interfere with Stigmergy CLI functionality',
|
|
411
|
-
);
|
|
412
|
-
} else {
|
|
413
|
-
console.log('[OK] No conflicting packages detected');
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
} catch (error) {
|
|
417
|
-
console.log(`[WARN] Unable to perform safety check: ${error.message}`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
async copyDirectory(src, dest) {
|
|
422
|
-
try {
|
|
423
|
-
await fs.mkdir(dest, { recursive: true });
|
|
424
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
425
|
-
|
|
426
|
-
for (const entry of entries) {
|
|
427
|
-
const srcPath = path.join(src, entry.name);
|
|
428
|
-
const destPath = path.join(dest, entry.name);
|
|
429
|
-
|
|
430
|
-
if (entry.isDirectory()) {
|
|
431
|
-
// Skip __pycache__ directories
|
|
432
|
-
if (entry.name === '__pycache__') continue;
|
|
433
|
-
await this.copyDirectory(srcPath, destPath);
|
|
434
|
-
} else {
|
|
435
|
-
await fs.copyFile(srcPath, destPath);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
} catch (error) {
|
|
439
|
-
await errorHandler.logError(
|
|
440
|
-
error,
|
|
441
|
-
'WARN',
|
|
442
|
-
'StigmergyInstaller.copyDirectory',
|
|
443
|
-
);
|
|
444
|
-
console.log(
|
|
445
|
-
`[WARN] Failed to copy directory ${src} to ${dest}: ${error.message}`,
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
async fileExists(filePath) {
|
|
451
|
-
try {
|
|
452
|
-
await fs.access(filePath);
|
|
453
|
-
return true;
|
|
454
|
-
} catch {
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
async showInstallOptions(missingTools) {
|
|
460
|
-
if (Object.keys(missingTools).length === 0) {
|
|
461
|
-
console.log('[INFO] All required AI CLI tools are already installed!');
|
|
462
|
-
return [];
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
console.log('\n[INSTALL] Missing AI CLI tools detected:');
|
|
466
|
-
const choices = [];
|
|
467
|
-
|
|
468
|
-
for (const [toolName, toolInfo] of Object.entries(missingTools)) {
|
|
469
|
-
choices.push({
|
|
470
|
-
name: `${toolInfo.name} (${toolName}) - ${toolInfo.install}`,
|
|
471
|
-
value: toolName,
|
|
472
|
-
checked: true,
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const answers = await inquirer.prompt([
|
|
477
|
-
{
|
|
478
|
-
type: 'checkbox',
|
|
479
|
-
name: 'tools',
|
|
480
|
-
message:
|
|
481
|
-
'Select which tools to install (Space to select, Enter to confirm):',
|
|
482
|
-
choices: choices,
|
|
483
|
-
pageSize: 10,
|
|
484
|
-
},
|
|
485
|
-
]);
|
|
486
|
-
|
|
487
|
-
return answers.tools;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
async getUserSelection(options, missingTools) {
|
|
491
|
-
if (options.length === 0) {
|
|
492
|
-
return [];
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const answers = await inquirer.prompt([
|
|
496
|
-
{
|
|
497
|
-
type: 'confirm',
|
|
498
|
-
name: 'proceed',
|
|
499
|
-
message: `Install ${options.length} missing AI CLI tools?`,
|
|
500
|
-
default: true,
|
|
501
|
-
},
|
|
502
|
-
]);
|
|
503
|
-
|
|
504
|
-
if (answers.proceed) {
|
|
505
|
-
return options;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// If user doesn't want to install all, let them choose individually
|
|
509
|
-
const individualChoices = options.map((toolName) => ({
|
|
510
|
-
name: missingTools[toolName].name,
|
|
511
|
-
value: toolName,
|
|
512
|
-
checked: true,
|
|
513
|
-
}));
|
|
514
|
-
|
|
515
|
-
const individualAnswers = await inquirer.prompt([
|
|
516
|
-
{
|
|
517
|
-
type: 'checkbox',
|
|
518
|
-
name: 'selectedTools',
|
|
519
|
-
message: 'Select which tools to install:',
|
|
520
|
-
choices: individualChoices,
|
|
521
|
-
pageSize: 10,
|
|
522
|
-
},
|
|
523
|
-
]);
|
|
524
|
-
|
|
525
|
-
return individualAnswers.selectedTools;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
async deployHooks(available) {
|
|
529
|
-
console.log('\n[DEPLOY] Deploying cross-CLI integration hooks...');
|
|
530
|
-
|
|
531
|
-
// Import the post-deployment configurer for executing installation scripts
|
|
532
|
-
const {
|
|
533
|
-
PostDeploymentConfigurer,
|
|
534
|
-
} = require('./../scripts/post-deployment-config.js');
|
|
535
|
-
const configurer = new PostDeploymentConfigurer();
|
|
536
|
-
|
|
537
|
-
let successCount = 0;
|
|
538
|
-
let totalCount = Object.keys(available).length;
|
|
539
|
-
|
|
540
|
-
for (const [toolName, toolInfo] of Object.entries(available)) {
|
|
541
|
-
console.log(`\n[DEPLOY] Deploying hooks for ${toolInfo.name}...`);
|
|
542
|
-
|
|
543
|
-
try {
|
|
544
|
-
await fs.mkdir(toolInfo.hooksDir, { recursive: true });
|
|
545
|
-
|
|
546
|
-
// Create config directory (not the config file itself)
|
|
547
|
-
const configDir = path.dirname(toolInfo.config);
|
|
548
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
549
|
-
|
|
550
|
-
// Copy adapter files from local assets
|
|
551
|
-
// Mapping for tool names that don't match their adapter directory names
|
|
552
|
-
const toolNameToAdapterDir = {
|
|
553
|
-
qodercli: 'qoder',
|
|
554
|
-
qwencode: 'qwen',
|
|
555
|
-
};
|
|
556
|
-
const adapterDirName = toolNameToAdapterDir[toolName] || toolName;
|
|
557
|
-
const assetsAdaptersDir = path.join(
|
|
558
|
-
os.homedir(),
|
|
559
|
-
'.stigmergy',
|
|
560
|
-
'assets',
|
|
561
|
-
'adapters',
|
|
562
|
-
adapterDirName,
|
|
563
|
-
);
|
|
564
|
-
if (await this.fileExists(assetsAdaptersDir)) {
|
|
565
|
-
await this.copyDirectory(assetsAdaptersDir, toolInfo.hooksDir);
|
|
566
|
-
console.log(`[OK] Copied adapter files for ${toolInfo.name}`);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// Execute post-deployment configuration
|
|
570
|
-
try {
|
|
571
|
-
await configurer.configureTool(toolName);
|
|
572
|
-
console.log(
|
|
573
|
-
`[OK] Post-deployment configuration completed for ${toolInfo.name}`,
|
|
574
|
-
);
|
|
575
|
-
successCount++;
|
|
576
|
-
} catch (configError) {
|
|
577
|
-
await errorHandler.logError(
|
|
578
|
-
configError,
|
|
579
|
-
'WARN',
|
|
580
|
-
`StigmergyInstaller.deployHooks.${toolName}.config`,
|
|
581
|
-
);
|
|
582
|
-
console.log(
|
|
583
|
-
`[WARN] Post-deployment configuration failed for ${toolInfo.name}: ${configError.message}`,
|
|
584
|
-
);
|
|
585
|
-
// Continue with other tools even if one fails
|
|
586
|
-
}
|
|
587
|
-
} catch (error) {
|
|
588
|
-
await errorHandler.logError(
|
|
589
|
-
error,
|
|
590
|
-
'ERROR',
|
|
591
|
-
`StigmergyInstaller.deployHooks.${toolName}`,
|
|
592
|
-
);
|
|
593
|
-
console.log(
|
|
594
|
-
`[ERROR] Failed to deploy hooks for ${toolInfo.name}: ${error.message}`,
|
|
595
|
-
);
|
|
596
|
-
console.log('[INFO] Continuing with other tools...');
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
console.log(
|
|
601
|
-
`\n[SUMMARY] Hook deployment completed: ${successCount}/${totalCount} tools successful`,
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
async deployProjectDocumentation() {
|
|
606
|
-
console.log('\n[DEPLOY] Deploying project documentation...');
|
|
607
|
-
|
|
608
|
-
try {
|
|
609
|
-
// Create standard project documentation files
|
|
610
|
-
const docs = {
|
|
611
|
-
'STIGMERGY.md': this.generateProjectMemoryTemplate(),
|
|
612
|
-
'README.md': this.generateProjectReadme(),
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
for (const [filename, content] of Object.entries(docs)) {
|
|
616
|
-
const filepath = path.join(process.cwd(), filename);
|
|
617
|
-
if (!(await this.fileExists(filepath))) {
|
|
618
|
-
await fs.writeFile(filepath, content);
|
|
619
|
-
console.log(`[OK] Created ${filename}`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
console.log('[OK] Project documentation deployed successfully');
|
|
624
|
-
} catch (error) {
|
|
625
|
-
console.log(
|
|
626
|
-
`[ERROR] Failed to deploy project documentation: ${error.message}`,
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
generateProjectMemoryTemplate() {
|
|
632
|
-
return `# Stigmergy Project Memory
|
|
633
|
-
|
|
634
|
-
## Project Information
|
|
635
|
-
- **Project Name**: ${path.basename(process.cwd())}
|
|
636
|
-
- **Created**: ${new Date().toISOString()}
|
|
637
|
-
- **Stigmergy Version**: 1.0.94
|
|
638
|
-
|
|
639
|
-
## Usage Instructions
|
|
640
|
-
This file automatically tracks all interactions with AI CLI tools through the Stigmergy system.
|
|
641
|
-
|
|
642
|
-
## Recent Interactions
|
|
643
|
-
No interactions recorded yet.
|
|
644
|
-
|
|
645
|
-
## Collaboration History
|
|
646
|
-
No collaboration history yet.
|
|
647
|
-
|
|
648
|
-
---
|
|
649
|
-
*This file is automatically managed by Stigmergy CLI*
|
|
650
|
-
*Last updated: ${new Date().toISOString()}*
|
|
651
|
-
`;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
generateProjectReadme() {
|
|
655
|
-
return `# ${path.basename(process.cwd())}
|
|
656
|
-
|
|
657
|
-
This project uses Stigmergy CLI for AI-assisted development.
|
|
658
|
-
|
|
659
|
-
## Getting Started
|
|
660
|
-
1. Install Stigmergy CLI: \`npm install -g stigmergy\`
|
|
661
|
-
2. Run \`stigmergy setup\` to configure the environment
|
|
662
|
-
3. Use \`stigmergy call "<your prompt>"\` to interact with AI tools
|
|
663
|
-
|
|
664
|
-
## Available AI Tools
|
|
665
|
-
- Claude (Anthropic)
|
|
666
|
-
- Qwen (Alibaba)
|
|
667
|
-
- Gemini (Google)
|
|
668
|
-
- And others configured in your environment
|
|
669
|
-
|
|
670
|
-
## Project Memory
|
|
671
|
-
See [STIGMERGY.md](STIGMERGY.md) for interaction history and collaboration records.
|
|
672
|
-
|
|
673
|
-
---
|
|
674
|
-
*Generated by Stigmergy CLI*
|
|
675
|
-
`;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
async initializeConfig() {
|
|
679
|
-
console.log('\n[CONFIG] Initializing Stigmergy configuration...');
|
|
680
|
-
|
|
681
|
-
try {
|
|
682
|
-
// Create config directory
|
|
683
|
-
const configDir = path.join(os.homedir(), '.stigmergy');
|
|
684
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
685
|
-
|
|
686
|
-
// Create initial configuration
|
|
687
|
-
const config = {
|
|
688
|
-
version: '1.0.94',
|
|
689
|
-
initialized: true,
|
|
690
|
-
createdAt: new Date().toISOString(),
|
|
691
|
-
lastUpdated: new Date().toISOString(),
|
|
692
|
-
defaultCLI: 'claude',
|
|
693
|
-
enableCrossCLI: true,
|
|
694
|
-
enableMemory: true,
|
|
695
|
-
tools: {},
|
|
696
|
-
};
|
|
697
|
-
|
|
698
|
-
// Save configuration
|
|
699
|
-
const configPath = path.join(configDir, 'config.json');
|
|
700
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
701
|
-
|
|
702
|
-
console.log('[OK] Configuration initialized successfully');
|
|
703
|
-
} catch (error) {
|
|
704
|
-
console.log(
|
|
705
|
-
`[ERROR] Failed to initialize configuration: ${error.message}`,
|
|
706
|
-
);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
showUsageInstructions() {
|
|
711
|
-
console.log('\n' + '='.repeat(60));
|
|
712
|
-
console.log('🎉 Stigmergy CLI Setup Complete!');
|
|
713
|
-
console.log('='.repeat(60));
|
|
714
|
-
console.log('');
|
|
715
|
-
console.log('Next steps:');
|
|
716
|
-
console.log(
|
|
717
|
-
' 1. Run "stigmergy install" to scan and install AI CLI tools',
|
|
718
|
-
);
|
|
719
|
-
console.log(' 2. Run "stigmergy deploy" to set up cross-CLI integration');
|
|
720
|
-
console.log(
|
|
721
|
-
' 3. Use "stigmergy call \\"<your prompt>\\"" to start collaborating',
|
|
722
|
-
);
|
|
723
|
-
console.log('');
|
|
724
|
-
console.log('Example usage:');
|
|
725
|
-
console.log(' stigmergy call "用claude分析项目架构"');
|
|
726
|
-
console.log(' stigmergy call "用qwen写一个hello world程序"');
|
|
727
|
-
console.log(' stigmergy call "用gemini设计数据库表结构"');
|
|
728
|
-
console.log('');
|
|
729
|
-
console.log(
|
|
730
|
-
'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
|
|
731
|
-
);
|
|
732
|
-
console.log('[END] Happy collaborating with multiple AI CLI tools!');
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// Main CLI functionality
|
|
737
|
-
async function main() {
|
|
738
|
-
if (process.env.DEBUG === 'true') {
|
|
739
|
-
console.log('[DEBUG] Main function called with args:', process.argv);
|
|
740
|
-
}
|
|
741
|
-
const args = process.argv.slice(2);
|
|
742
|
-
const installer = new StigmergyInstaller();
|
|
743
|
-
|
|
744
|
-
// Handle case when no arguments are provided
|
|
745
|
-
if (args.length === 0) {
|
|
746
|
-
console.log(
|
|
747
|
-
'Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System',
|
|
748
|
-
);
|
|
749
|
-
console.log('Version: 1.0.94');
|
|
750
|
-
console.log('');
|
|
751
|
-
console.log('[SYSTEM] Automated Installation and Deployment System');
|
|
752
|
-
console.log('');
|
|
753
|
-
console.log('Usage: stigmergy [command] [options]');
|
|
754
|
-
console.log('');
|
|
755
|
-
console.log('Commands:');
|
|
756
|
-
console.log(' help, --help Show this help message');
|
|
757
|
-
console.log(' version, --version Show version information');
|
|
758
|
-
console.log(' status Check CLI tools status');
|
|
759
|
-
console.log(' scan Scan for available AI CLI tools');
|
|
760
|
-
console.log(' install Auto-install missing CLI tools');
|
|
761
|
-
console.log(
|
|
762
|
-
' deploy Deploy hooks and integration to installed tools',
|
|
763
|
-
);
|
|
764
|
-
console.log(' setup Complete setup and configuration');
|
|
765
|
-
console.log(
|
|
766
|
-
' init Initialize Stigmergy configuration (alias for setup)',
|
|
767
|
-
);
|
|
768
|
-
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
769
|
-
console.log(' errors Display error report and statistics');
|
|
770
|
-
console.log('');
|
|
771
|
-
console.log('[WORKFLOW] Automated Workflow:');
|
|
772
|
-
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
773
|
-
console.log(
|
|
774
|
-
' 2. stigmergy install # Auto-scan & install CLI tools',
|
|
775
|
-
);
|
|
776
|
-
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
777
|
-
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
778
|
-
console.log('');
|
|
779
|
-
console.log('[INFO] For first-time setup, run: stigmergy setup');
|
|
780
|
-
console.log(
|
|
781
|
-
'[INFO] To scan and install AI tools, run: stigmergy install',
|
|
782
|
-
);
|
|
783
|
-
console.log('');
|
|
784
|
-
console.log(
|
|
785
|
-
'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
|
|
786
|
-
);
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Handle help commands
|
|
791
|
-
if (args.includes('--help') || args.includes('-h')) {
|
|
792
|
-
console.log(
|
|
793
|
-
'Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System',
|
|
794
|
-
);
|
|
795
|
-
console.log('Version: 1.0.94');
|
|
796
|
-
console.log('');
|
|
797
|
-
console.log('[SYSTEM] Automated Installation and Deployment System');
|
|
798
|
-
console.log('');
|
|
799
|
-
console.log('Usage: stigmergy [command] [options]');
|
|
800
|
-
console.log('');
|
|
801
|
-
console.log('Commands:');
|
|
802
|
-
console.log(' help, --help Show this help message');
|
|
803
|
-
console.log(' version, --version Show version information');
|
|
804
|
-
console.log(' status Check CLI tools status');
|
|
805
|
-
console.log(' scan Scan for available AI CLI tools');
|
|
806
|
-
console.log(' install Auto-install missing CLI tools');
|
|
807
|
-
console.log(
|
|
808
|
-
' deploy Deploy hooks and integration to installed tools',
|
|
809
|
-
);
|
|
810
|
-
console.log(' setup Complete setup and configuration');
|
|
811
|
-
console.log(
|
|
812
|
-
' init Initialize Stigmergy configuration (alias for setup)',
|
|
813
|
-
);
|
|
814
|
-
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
815
|
-
console.log(' errors Display error report and statistics');
|
|
816
|
-
console.log('');
|
|
817
|
-
console.log('[WORKFLOW] Automated Workflow:');
|
|
818
|
-
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
819
|
-
console.log(
|
|
820
|
-
' 2. stigmergy install # Auto-scan & install CLI tools',
|
|
821
|
-
);
|
|
822
|
-
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
823
|
-
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
824
|
-
console.log('');
|
|
825
|
-
console.log(
|
|
826
|
-
'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
|
|
827
|
-
);
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
const command = args[0];
|
|
832
|
-
|
|
833
|
-
switch (command) {
|
|
834
|
-
case 'version':
|
|
835
|
-
case '--version': {
|
|
836
|
-
// Use the version from configuration instead of hardcoding
|
|
837
|
-
const config = {
|
|
838
|
-
version: '1.0.94',
|
|
839
|
-
initialized: true,
|
|
840
|
-
createdAt: new Date().toISOString(),
|
|
841
|
-
lastUpdated: new Date().toISOString(),
|
|
842
|
-
defaultCLI: 'claude',
|
|
843
|
-
enableCrossCLI: true,
|
|
844
|
-
enableMemory: true,
|
|
845
|
-
};
|
|
846
|
-
console.log(`Stigmergy CLI v${config.version}`);
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
case 'errors':
|
|
851
|
-
try {
|
|
852
|
-
console.log('[ERRORS] Generating Stigmergy CLI error report...\n');
|
|
853
|
-
await errorHandler.printErrorReport();
|
|
854
|
-
} catch (error) {
|
|
855
|
-
console.error(
|
|
856
|
-
'[ERROR] Failed to generate error report:',
|
|
857
|
-
error.message,
|
|
858
|
-
);
|
|
859
|
-
process.exit(1);
|
|
860
|
-
}
|
|
861
|
-
break;
|
|
862
|
-
|
|
863
|
-
case 'init':
|
|
864
|
-
// Alias for setup command
|
|
865
|
-
console.log('[INIT] Initializing Stigmergy CLI...');
|
|
866
|
-
// Fall through to setup case
|
|
867
|
-
|
|
868
|
-
case 'setup':
|
|
869
|
-
try {
|
|
870
|
-
console.log('[SETUP] Starting complete Stigmergy setup...\n');
|
|
871
|
-
|
|
872
|
-
// Step 1: Download required assets
|
|
873
|
-
await installer.downloadRequiredAssets();
|
|
874
|
-
|
|
875
|
-
// Step 2: Scan for CLI tools
|
|
876
|
-
const { available: setupAvailable, missing: setupMissing } =
|
|
877
|
-
await installer.scanCLI();
|
|
878
|
-
const setupOptions = await installer.showInstallOptions(setupMissing);
|
|
879
|
-
|
|
880
|
-
// Step 3: Install missing CLI tools if user chooses
|
|
881
|
-
if (setupOptions.length > 0) {
|
|
882
|
-
const selectedTools = await installer.getUserSelection(
|
|
883
|
-
setupOptions,
|
|
884
|
-
setupMissing,
|
|
885
|
-
);
|
|
886
|
-
if (selectedTools.length > 0) {
|
|
887
|
-
console.log(
|
|
888
|
-
'\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
|
|
889
|
-
);
|
|
890
|
-
await installer.installTools(selectedTools, setupMissing);
|
|
891
|
-
}
|
|
892
|
-
} else {
|
|
893
|
-
console.log('\n[INFO] All required tools are already installed!');
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// Step 4: Deploy hooks to available CLI tools
|
|
897
|
-
await installer.deployHooks(setupAvailable);
|
|
898
|
-
|
|
899
|
-
// Step 5: Deploy project documentation
|
|
900
|
-
await installer.deployProjectDocumentation();
|
|
901
|
-
|
|
902
|
-
// Step 6: Initialize configuration
|
|
903
|
-
await installer.initializeConfig();
|
|
904
|
-
|
|
905
|
-
// Step 7: Show usage instructions
|
|
906
|
-
installer.showUsageInstructions();
|
|
907
|
-
} catch (error) {
|
|
908
|
-
await errorHandler.logError(error, 'ERROR', 'main.setup');
|
|
909
|
-
console.log(`[ERROR] Setup failed: ${error.message}`);
|
|
910
|
-
console.log('\n[TROUBLESHOOTING] To manually complete setup:');
|
|
911
|
-
console.log('1. Run: stigmergy deploy # Deploy hooks manually');
|
|
912
|
-
console.log('2. Run: stigmergy setup # Try setup again');
|
|
913
|
-
process.exit(1);
|
|
914
|
-
}
|
|
915
|
-
break;
|
|
916
|
-
|
|
917
|
-
case 'status':
|
|
918
|
-
try {
|
|
919
|
-
const { available, missing } = await installer.scanCLI();
|
|
920
|
-
console.log('\n[STATUS] AI CLI Tools Status Report');
|
|
921
|
-
console.log('=====================================');
|
|
922
|
-
|
|
923
|
-
if (Object.keys(available).length > 0) {
|
|
924
|
-
console.log('\n✅ Available Tools:');
|
|
925
|
-
for (const [toolName, toolInfo] of Object.entries(available)) {
|
|
926
|
-
console.log(` - ${toolInfo.name} (${toolName})`);
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
if (Object.keys(missing).length > 0) {
|
|
931
|
-
console.log('\n❌ Missing Tools:');
|
|
932
|
-
for (const [toolName, toolInfo] of Object.entries(missing)) {
|
|
933
|
-
console.log(` - ${toolInfo.name} (${toolName})`);
|
|
934
|
-
console.log(` Install command: ${toolInfo.install}`);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
console.log(
|
|
939
|
-
`\n[SUMMARY] ${Object.keys(available).length} available, ${Object.keys(missing).length} missing`,
|
|
940
|
-
);
|
|
941
|
-
} catch (error) {
|
|
942
|
-
await errorHandler.logError(error, 'ERROR', 'main.status');
|
|
943
|
-
console.log(`[ERROR] Failed to get status: ${error.message}`);
|
|
944
|
-
process.exit(1);
|
|
945
|
-
}
|
|
946
|
-
break;
|
|
947
|
-
|
|
948
|
-
case 'scan':
|
|
949
|
-
try {
|
|
950
|
-
await installer.scanCLI();
|
|
951
|
-
} catch (error) {
|
|
952
|
-
await errorHandler.logError(error, 'ERROR', 'main.scan');
|
|
953
|
-
console.log(`[ERROR] Failed to scan CLI tools: ${error.message}`);
|
|
954
|
-
process.exit(1);
|
|
955
|
-
}
|
|
956
|
-
break;
|
|
957
|
-
|
|
958
|
-
case 'install':
|
|
959
|
-
try {
|
|
960
|
-
console.log('[INSTALL] Starting AI CLI tools installation...');
|
|
961
|
-
const { missing: missingTools } = await installer.scanCLI();
|
|
962
|
-
const options = await installer.showInstallOptions(missingTools);
|
|
963
|
-
|
|
964
|
-
if (options.length > 0) {
|
|
965
|
-
const selectedTools = await installer.getUserSelection(
|
|
966
|
-
options,
|
|
967
|
-
missingTools,
|
|
968
|
-
);
|
|
969
|
-
if (selectedTools.length > 0) {
|
|
970
|
-
console.log(
|
|
971
|
-
'\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
|
|
972
|
-
);
|
|
973
|
-
await installer.installTools(selectedTools, missingTools);
|
|
974
|
-
}
|
|
975
|
-
} else {
|
|
976
|
-
console.log('\n[INFO] All required tools are already installed!');
|
|
977
|
-
}
|
|
978
|
-
} catch (error) {
|
|
979
|
-
await errorHandler.logError(error, 'ERROR', 'main.install');
|
|
980
|
-
console.log(`[ERROR] Installation failed: ${error.message}`);
|
|
981
|
-
process.exit(1);
|
|
982
|
-
}
|
|
983
|
-
break;
|
|
984
|
-
|
|
985
|
-
case 'deploy':
|
|
986
|
-
try {
|
|
987
|
-
const { available: deployedTools } = await installer.scanCLI();
|
|
988
|
-
await installer.deployHooks(deployedTools);
|
|
989
|
-
} catch (error) {
|
|
990
|
-
await errorHandler.logError(error, 'ERROR', 'main.deploy');
|
|
991
|
-
console.log(`[ERROR] Deployment failed: ${error.message}`);
|
|
992
|
-
process.exit(1);
|
|
993
|
-
}
|
|
994
|
-
break;
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
case 'call': {
|
|
999
|
-
if (args.length < 2) {
|
|
1000
|
-
console.log('[ERROR] Usage: stigmergy call "<prompt>"');
|
|
1001
|
-
process.exit(1);
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
// Get the prompt (everything after the command)
|
|
1005
|
-
const prompt = args.slice(1).join(' ');
|
|
1006
|
-
|
|
1007
|
-
// Use smart router to determine which tool to use
|
|
1008
|
-
const router = new SmartRouter();
|
|
1009
|
-
await router.initialize(); // Initialize the router first
|
|
1010
|
-
const route = await router.smartRoute(prompt);
|
|
1011
|
-
|
|
1012
|
-
console.log(`[CALL] Routing to ${route.tool}: ${route.prompt}`);
|
|
1013
|
-
|
|
1014
|
-
// Execute the routed command
|
|
1015
|
-
try {
|
|
1016
|
-
// Get the actual executable path for the tool
|
|
1017
|
-
const toolPath = route.tool;
|
|
1018
|
-
|
|
1019
|
-
// SPECIAL TEST CASE: Simulate a non-existent tool for testing
|
|
1020
|
-
// This is for demonstration purposes only
|
|
1021
|
-
/*
|
|
1022
|
-
if (route.tool === "nonexistenttool") {
|
|
1023
|
-
toolPath = "this_tool_definitely_does_not_exist_12345";
|
|
1024
|
-
}
|
|
1025
|
-
*/
|
|
1026
|
-
|
|
1027
|
-
console.log(
|
|
1028
|
-
`[DEBUG] Tool path: ${toolPath}, Prompt: ${route.prompt}`,
|
|
1029
|
-
);
|
|
1030
|
-
|
|
1031
|
-
// For different tools, we need to pass the prompt differently
|
|
1032
|
-
// Use unified parameter handler for better parameter handling
|
|
1033
|
-
let toolArgs = [];
|
|
1034
|
-
|
|
1035
|
-
try {
|
|
1036
|
-
// Get CLI pattern for this tool
|
|
1037
|
-
const cliPattern = await router.analyzer.getCLIPattern(route.tool);
|
|
1038
|
-
|
|
1039
|
-
// Use the unified CLI parameter handler
|
|
1040
|
-
const CLIParameterHandler = require('./core/cli_parameter_handler');
|
|
1041
|
-
toolArgs = CLIParameterHandler.generateArguments(
|
|
1042
|
-
route.tool,
|
|
1043
|
-
route.prompt,
|
|
1044
|
-
cliPattern,
|
|
1045
|
-
);
|
|
1046
|
-
} catch (patternError) {
|
|
1047
|
-
// Fallback to original logic if pattern analysis fails
|
|
1048
|
-
if (route.tool === 'claude') {
|
|
1049
|
-
// Claude CLI expects the prompt with -p flag for non-interactive mode
|
|
1050
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
1051
|
-
} else if (route.tool === 'qodercli' || route.tool === 'iflow') {
|
|
1052
|
-
// Qoder CLI and iFlow expect the prompt with -p flag
|
|
1053
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
1054
|
-
} else if (route.tool === 'codex') {
|
|
1055
|
-
// Codex CLI needs 'exec' subcommand for non-interactive mode
|
|
1056
|
-
toolArgs = ['exec', '-p', `"${route.prompt}"`];
|
|
1057
|
-
} else {
|
|
1058
|
-
// For other tools, pass the prompt with -p flag
|
|
1059
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
// Use the reliable cross-platform execution function
|
|
1064
|
-
try {
|
|
1065
|
-
// Validate that the tool exists before attempting to execute
|
|
1066
|
-
if (!toolPath || typeof toolPath !== 'string') {
|
|
1067
|
-
throw new Error(`Invalid tool path: ${toolPath}`);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
// Special handling for JS files to ensure proper execution
|
|
1071
|
-
if (toolPath.endsWith('.js') || toolPath.endsWith('.cjs')) {
|
|
1072
|
-
// Use safe JS file execution
|
|
1073
|
-
console.log(
|
|
1074
|
-
`[EXEC] Safely executing JS file: ${toolPath} ${toolArgs.join(' ')}`,
|
|
1075
|
-
);
|
|
1076
|
-
const result = await executeJSFile(toolPath, toolArgs, {
|
|
1077
|
-
stdio: 'inherit',
|
|
1078
|
-
shell: true,
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
if (!result.success) {
|
|
1082
|
-
console.log(
|
|
1083
|
-
`[WARN] ${route.tool} exited with code ${result.code}`,
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
process.exit(result.code || 0);
|
|
1087
|
-
} else {
|
|
1088
|
-
// Regular command execution
|
|
1089
|
-
console.log(`[EXEC] Running: ${toolPath} ${toolArgs.join(' ')}`);
|
|
1090
|
-
const result = await executeCommand(toolPath, toolArgs, {
|
|
1091
|
-
stdio: 'inherit',
|
|
1092
|
-
shell: true,
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
if (!result.success) {
|
|
1096
|
-
console.log(
|
|
1097
|
-
`[WARN] ${route.tool} exited with code ${result.code}`,
|
|
1098
|
-
);
|
|
1099
|
-
}
|
|
1100
|
-
process.exit(result.code || 0);
|
|
1101
|
-
}
|
|
1102
|
-
} catch (executionError) {
|
|
1103
|
-
const cliError = await errorHandler.handleCLIError(
|
|
1104
|
-
route.tool,
|
|
1105
|
-
executionError.error || executionError,
|
|
1106
|
-
toolArgs.join(' '),
|
|
1107
|
-
);
|
|
1108
|
-
|
|
1109
|
-
// Provide clear ANSI English error message
|
|
1110
|
-
console.log('==================================================');
|
|
1111
|
-
console.log('ERROR: Failed to execute AI CLI tool');
|
|
1112
|
-
console.log('==================================================');
|
|
1113
|
-
console.log(`Tool: ${route.tool}`);
|
|
1114
|
-
console.log(`Error: ${cliError.message}`);
|
|
1115
|
-
if (executionError.stderr) {
|
|
1116
|
-
console.log(`Stderr: ${executionError.stderr}`);
|
|
1117
|
-
}
|
|
1118
|
-
console.log('');
|
|
1119
|
-
console.log('Possible solutions:');
|
|
1120
|
-
console.log('1. Check if the AI CLI tool is properly installed');
|
|
1121
|
-
console.log('2. Verify the tool is in your system PATH');
|
|
1122
|
-
console.log('3. Try reinstalling the tool with: stigmergy install');
|
|
1123
|
-
console.log('4. Run stigmergy status to check tool availability');
|
|
1124
|
-
console.log('');
|
|
1125
|
-
console.log('For manual execution, you can run:');
|
|
1126
|
-
console.log(`${toolPath} ${toolArgs.join(' ')}`);
|
|
1127
|
-
console.log('==================================================');
|
|
1128
|
-
|
|
1129
|
-
process.exit(1);
|
|
1130
|
-
}
|
|
1131
|
-
} catch (error) {
|
|
1132
|
-
const cliError = await errorHandler.handleCLIError(
|
|
1133
|
-
route.tool,
|
|
1134
|
-
error,
|
|
1135
|
-
prompt,
|
|
1136
|
-
);
|
|
1137
|
-
console.log(
|
|
1138
|
-
`[ERROR] Failed to execute ${route.tool}:`,
|
|
1139
|
-
cliError.message,
|
|
1140
|
-
);
|
|
1141
|
-
process.exit(1);
|
|
1142
|
-
}
|
|
1143
|
-
break;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
case 'auto-install':
|
|
1147
|
-
// Auto-install mode for npm postinstall - NON-INTERACTIVE
|
|
1148
|
-
console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
|
|
1149
|
-
console.log('='.repeat(60));
|
|
1150
|
-
|
|
1151
|
-
try {
|
|
1152
|
-
// Step 1: Download required assets
|
|
1153
|
-
try {
|
|
1154
|
-
console.log('[STEP] Downloading required assets...');
|
|
1155
|
-
await installer.downloadRequiredAssets();
|
|
1156
|
-
console.log('[OK] Assets downloaded successfully');
|
|
1157
|
-
} catch (error) {
|
|
1158
|
-
console.log(`[WARN] Failed to download assets: ${error.message}`);
|
|
1159
|
-
console.log('[INFO] Continuing with installation...');
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
// Step 2: Scan for CLI tools
|
|
1163
|
-
let autoAvailable = {},
|
|
1164
|
-
autoMissing = {};
|
|
1165
|
-
try {
|
|
1166
|
-
console.log('[STEP] Scanning for CLI tools...');
|
|
1167
|
-
const scanResult = await installer.scanCLI();
|
|
1168
|
-
autoAvailable = scanResult.available;
|
|
1169
|
-
autoMissing = scanResult.missing;
|
|
1170
|
-
console.log('[OK] CLI tools scanned successfully');
|
|
1171
|
-
} catch (error) {
|
|
1172
|
-
console.log(`[WARN] Failed to scan CLI tools: ${error.message}`);
|
|
1173
|
-
console.log('[INFO] Continuing with installation...');
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
// Step 3: Show summary to user after installation
|
|
1177
|
-
try {
|
|
1178
|
-
if (Object.keys(autoMissing).length > 0) {
|
|
1179
|
-
console.log(
|
|
1180
|
-
'\n[INFO] Found ' +
|
|
1181
|
-
Object.keys(autoMissing).length +
|
|
1182
|
-
' missing AI CLI tools:',
|
|
1183
|
-
);
|
|
1184
|
-
for (const [toolName, toolInfo] of Object.entries(autoMissing)) {
|
|
1185
|
-
console.log(` - ${toolInfo.name} (${toolName})`);
|
|
1186
|
-
}
|
|
1187
|
-
console.log(
|
|
1188
|
-
'\n[INFO] Auto-install mode detected. Skipping automatic installation of missing tools.',
|
|
1189
|
-
);
|
|
1190
|
-
console.log(
|
|
1191
|
-
'[INFO] For full functionality, please run "stigmergy install" after installation completes.',
|
|
1192
|
-
);
|
|
1193
|
-
} else {
|
|
1194
|
-
console.log(
|
|
1195
|
-
'\n[INFO] All AI CLI tools are already installed! No additional tools required.',
|
|
1196
|
-
);
|
|
1197
|
-
}
|
|
1198
|
-
} catch (error) {
|
|
1199
|
-
console.log(`[WARN] Failed to show tool summary: ${error.message}`);
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
// Step 4: Deploy hooks to available CLI tools
|
|
1203
|
-
try {
|
|
1204
|
-
console.log('[STEP] Deploying hooks to available CLI tools...');
|
|
1205
|
-
await installer.deployHooks(autoAvailable);
|
|
1206
|
-
console.log('[OK] Hooks deployed successfully');
|
|
1207
|
-
} catch (error) {
|
|
1208
|
-
console.log(`[ERROR] Failed to deploy hooks: ${error.message}`);
|
|
1209
|
-
console.log(
|
|
1210
|
-
'[INFO] You can manually deploy hooks later by running: stigmergy deploy',
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
// Step 5: Deploy project documentation
|
|
1215
|
-
try {
|
|
1216
|
-
console.log('[STEP] Deploying project documentation...');
|
|
1217
|
-
await installer.deployProjectDocumentation();
|
|
1218
|
-
console.log('[OK] Documentation deployed successfully');
|
|
1219
|
-
} catch (error) {
|
|
1220
|
-
console.log(
|
|
1221
|
-
`[WARN] Failed to deploy documentation: ${error.message}`,
|
|
1222
|
-
);
|
|
1223
|
-
console.log('[INFO] Continuing with installation...');
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
// Step 6: Initialize configuration
|
|
1227
|
-
try {
|
|
1228
|
-
console.log('[STEP] Initializing configuration...');
|
|
1229
|
-
await installer.initializeConfig();
|
|
1230
|
-
console.log('[OK] Configuration initialized successfully');
|
|
1231
|
-
} catch (error) {
|
|
1232
|
-
console.log(
|
|
1233
|
-
`[ERROR] Failed to initialize configuration: ${error.message}`,
|
|
1234
|
-
);
|
|
1235
|
-
console.log(
|
|
1236
|
-
'[INFO] You can manually initialize configuration later by running: stigmergy setup',
|
|
1237
|
-
);
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
// Step 7: Show final message to guide users
|
|
1241
|
-
console.log('\n[SUCCESS] Stigmergy CLI installed successfully!');
|
|
1242
|
-
console.log(
|
|
1243
|
-
'[USAGE] Run "stigmergy setup" to complete full configuration and install missing AI CLI tools.',
|
|
1244
|
-
);
|
|
1245
|
-
console.log(
|
|
1246
|
-
'[USAGE] Run "stigmergy install" to install only missing AI CLI tools.',
|
|
1247
|
-
);
|
|
1248
|
-
console.log(
|
|
1249
|
-
'[USAGE] Run "stigmergy --help" to see all available commands.',
|
|
1250
|
-
);
|
|
1251
|
-
} catch (fatalError) {
|
|
1252
|
-
await errorHandler.logError(fatalError, 'ERROR', 'main.auto-install');
|
|
1253
|
-
console.error(
|
|
1254
|
-
'[FATAL] Auto-install process failed:',
|
|
1255
|
-
fatalError.message,
|
|
1256
|
-
);
|
|
1257
|
-
console.log('\n[TROUBLESHOOTING] To manually complete installation:');
|
|
1258
|
-
console.log('1. Run: stigmergy setup # Complete setup');
|
|
1259
|
-
console.log('2. Run: stigmergy install # Install missing tools');
|
|
1260
|
-
console.log('3. Run: stigmergy deploy # Deploy hooks manually');
|
|
1261
|
-
process.exit(1);
|
|
1262
|
-
}
|
|
1263
|
-
break;
|
|
1264
|
-
|
|
1265
|
-
default:
|
|
1266
|
-
console.log(`[ERROR] Unknown command: ${command}`);
|
|
1267
|
-
console.log('[INFO] Run "stigmergy --help" for usage information');
|
|
1268
|
-
process.exit(1);
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
// Function to find maximum of two numbers
|
|
1273
|
-
function maxOfTwo(a, b) {
|
|
1274
|
-
return a > b ? a : b;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
// Function to check if user is authenticated
|
|
1278
|
-
function isAuthenticated() {
|
|
1279
|
-
try {
|
|
1280
|
-
const authenticator = new UserAuthenticator();
|
|
1281
|
-
// Load authentication data
|
|
1282
|
-
const authFile = path.join(
|
|
1283
|
-
process.env.HOME || process.env.USERPROFILE,
|
|
1284
|
-
'.stigmergy',
|
|
1285
|
-
'auth.json',
|
|
1286
|
-
);
|
|
1287
|
-
|
|
1288
|
-
if (!fsSync.existsSync(authFile)) {
|
|
1289
|
-
return false;
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
// Load the authentication data into the authenticator
|
|
1293
|
-
const data = JSON.parse(fsSync.readFileSync(authFile, 'utf8'));
|
|
1294
|
-
if (data.sessions) {
|
|
1295
|
-
for (const [token, sessionData] of Object.entries(data.sessions)) {
|
|
1296
|
-
authenticator._sessions.set(token, sessionData);
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
// Read the current session token
|
|
1301
|
-
const sessionFile = path.join(
|
|
1302
|
-
process.env.HOME || process.env.USERPROFILE,
|
|
1303
|
-
'.stigmergy',
|
|
1304
|
-
'session.token',
|
|
1305
|
-
);
|
|
1306
|
-
|
|
1307
|
-
if (!fsSync.existsSync(sessionFile)) {
|
|
1308
|
-
return false;
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
const token = fsSync.readFileSync(sessionFile, 'utf8').trim();
|
|
1312
|
-
const username = authenticator.validateSession(token);
|
|
1313
|
-
|
|
1314
|
-
return !!username;
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
return false;
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
// Export for testing
|
|
1321
|
-
module.exports = {
|
|
1322
|
-
StigmergyInstaller,
|
|
1323
|
-
SmartRouter,
|
|
1324
|
-
MemoryManager,
|
|
1325
|
-
CLI_TOOLS,
|
|
1326
|
-
maxOfTwo,
|
|
1327
|
-
};
|
|
1328
|
-
|
|
1329
|
-
// Run main function
|
|
1330
|
-
if (require.main === module) {
|
|
1331
|
-
main().catch((error) => {
|
|
1332
|
-
console.error(
|
|
1333
|
-
'[FATAL] Stigmergy CLI encountered an unhandled error:',
|
|
1334
|
-
error,
|
|
1335
|
-
);
|
|
1336
|
-
process.exit(1);
|
|
1337
|
-
});
|
|
1338
|
-
}
|