stigmergy 1.0.89 → 1.0.93

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/src/main.js CHANGED
@@ -1,893 +1,964 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System
5
- * International Version - Pure ANSI Characters Only
6
- * Version: 1.0.76
7
- */
8
-
9
- const { spawn, spawnSync } = require('child_process');
10
- const path = require('path');
11
- const fs = require('fs/promises');
12
- const os = require('os');
13
-
14
- // AI CLI Tools Configuration
15
- const CLI_TOOLS = {
16
- claude: {
17
- name: 'Claude CLI',
18
- version: 'claude --version',
19
- install: 'npm install -g @anthropic-ai/claude-cli',
20
- hooksDir: path.join(os.homedir(), '.claude', 'hooks'),
21
- config: path.join(os.homedir(), '.claude', 'config.json')
22
- },
23
- gemini: {
24
- name: 'Gemini CLI',
25
- version: 'gemini --version',
26
- install: 'npm install -g @google/generative-ai-cli',
27
- hooksDir: path.join(os.homedir(), '.gemini', 'extensions'),
28
- config: path.join(os.homedir(), '.gemini', 'config.json')
29
- },
30
- qwen: {
31
- name: 'Qwen CLI',
32
- version: 'qwen --version',
33
- install: 'npm install -g @alibaba/qwen-cli',
34
- hooksDir: path.join(os.homedir(), '.qwen', 'hooks'),
35
- config: path.join(os.homedir(), '.qwen', 'config.json')
36
- },
37
- iflow: {
38
- name: 'iFlow CLI',
39
- version: 'iflow --version',
40
- install: 'npm install -g iflow-cli',
41
- hooksDir: path.join(os.homedir(), '.iflow', 'hooks'),
42
- config: path.join(os.homedir(), '.iflow', 'config.json')
43
- },
44
- qoder: {
45
- name: 'Qoder CLI',
46
- version: 'qodercli --version',
47
- install: 'npm install -g @qoder-ai/qodercli',
48
- hooksDir: path.join(os.homedir(), '.qoder', 'hooks'),
49
- config: path.join(os.homedir(), '.qoder', 'config.json')
50
- },
51
- codebuddy: {
52
- name: 'CodeBuddy CLI',
53
- version: 'codebuddy --version',
54
- install: 'npm install -g codebuddy-cli',
55
- hooksDir: path.join(os.homedir(), '.codebuddy', 'hooks'),
56
- config: path.join(os.homedir(), '.codebuddy', 'config.json')
57
- },
58
- copilot: {
59
- name: 'GitHub Copilot CLI',
60
- version: 'copilot --version',
61
- install: 'npm install -g @github/copilot-cli',
62
- hooksDir: path.join(os.homedir(), '.copilot', 'mcp'),
63
- config: path.join(os.homedir(), '.copilot', 'config.json')
64
- },
65
- codex: {
66
- name: 'OpenAI Codex CLI',
67
- version: 'codex --version',
68
- install: 'npm install -g openai-codex-cli',
69
- hooksDir: path.join(os.homedir(), '.config', 'codex', 'slash_commands'),
70
- config: path.join(os.homedir(), '.codex', 'config.json')
71
- }
72
- };
73
-
74
- class SmartRouter {
75
- constructor() {
76
- this.tools = CLI_TOOLS;
77
- this.routeKeywords = ['use', 'help', 'please', 'write', 'generate', 'explain', 'analyze', 'translate', 'code', 'article'];
78
- this.defaultTool = 'claude';
79
- }
80
-
81
- shouldRoute(userInput) {
82
- return this.routeKeywords.some(keyword =>
83
- userInput.toLowerCase().includes(keyword.toLowerCase())
84
- );
85
- }
86
-
87
- smartRoute(userInput) {
88
- const input = userInput.trim();
89
-
90
- // Detect tool-specific keywords
91
- for (const [toolName, toolInfo] of Object.entries(this.tools)) {
92
- for (const keyword of this.extractKeywords(toolName)) {
93
- if (input.toLowerCase().includes(keyword.toLowerCase())) {
94
- // Extract clean parameters
95
- const cleanInput = input
96
- .replace(new RegExp(`.*${keyword}\\s*`, 'gi'), '')
97
- .replace(/^(用|帮我|请|麻烦|给我|帮我写|帮我生成)\s*/i, '')
98
- .trim();
99
- return { tool: toolName, prompt: cleanInput };
100
- }
101
- }
102
- }
103
-
104
- // Default routing
105
- const cleanInput = input
106
- .replace(/^(用|帮我|请|麻烦|给我|帮我写|帮我生成)\s*/i, '')
107
- .trim();
108
- return { tool: this.defaultTool, prompt: cleanInput };
109
- }
110
-
111
- extractKeywords(toolName) {
112
- const keywordMap = {
113
- claude: ['claude', 'anthropic'],
114
- gemini: ['gemini', 'google', '谷歌'],
115
- qwen: ['qwen', '通义', '阿里'],
116
- iflow: ['iflow', '心流', 'intelligent'],
117
- qoder: ['qoder', 'qodercli'],
118
- codebuddy: ['codebuddy', 'buddy'],
119
- copilot: ['copilot', 'github'],
120
- codex: ['codex', 'openai']
121
- };
122
- return keywordMap[toolName] || [toolName];
123
- }
124
-
125
- async executeTool(toolName, prompt) {
126
- const tool = this.tools[toolName];
127
- if (!tool) {
128
- return { success: false, error: `Unknown tool: ${toolName}` };
129
- }
130
-
131
- if (!this.checkCLI(toolName)) {
132
- return { success: false, error: `${tool.name} is not available` };
133
- }
134
-
135
- try {
136
- const result = spawnSync(toolName, [prompt], {
137
- encoding: 'utf8',
138
- timeout: 30000
139
- });
140
-
141
- return {
142
- success: result.status === 0,
143
- output: result.stdout,
144
- error: result.stderr
145
- };
146
- } catch (error) {
147
- return { success: false, error: error.message };
148
- }
149
- }
150
-
151
- checkCLI(toolName) {
152
- try {
153
- const tool = this.tools[toolName];
154
- const command = tool.version.split(' ')[0];
155
- const args = tool.version.split(' ').slice(1);
156
-
157
- const result = spawnSync(command, args, {
158
- stdio: 'ignore',
159
- timeout: 10000,
160
- env: { ...process.env }
161
- });
162
- return result.status === 0;
163
- } catch (error) {
164
- return false;
165
- }
166
- }
167
-
168
- async analyzeCLIHelp(toolName) {
169
- const tool = this.tools[toolName];
170
- if (!tool) return null;
171
-
172
- try {
173
- const result = spawnSync(toolName, ['--help'], {
174
- encoding: 'utf8',
175
- timeout: 15000
176
- });
177
-
178
- if (result.status === 0) {
179
- return this.parseHelpOutput(result.stdout);
180
- }
181
- return null;
182
- } catch (error) {
183
- return null;
184
- }
185
- }
186
-
187
- parseHelpOutput(helpText) {
188
- const capabilities = {
189
- commands: [],
190
- options: [],
191
- examples: [],
192
- features: []
193
- };
194
-
195
- // Extract commands
196
- const commandMatches = helpText.match(/^\s{0,4}([a-z][a-z0-9_-]+)\s+.+$/gm);
197
- if (commandMatches) {
198
- capabilities.commands = commandMatches.map(match => match.trim());
199
- }
200
-
201
- // Extract options
202
- const optionMatches = helpText.match(/--[a-z-]+/g);
203
- if (optionMatches) {
204
- capabilities.options = [...new Set(optionMatches)];
205
- }
206
-
207
- // Extract examples
208
- const exampleMatches = helpText.match(/(example|Usage|用法)[::]\s*\n([\s\S]*?)(?=\n\n|\n[A-Z]|\n$)/gi);
209
- if (exampleMatches) {
210
- capabilities.examples = exampleMatches.map(match => match.replace(/^(example|Usage|用法)[::]\s*/i, '').trim());
211
- }
212
-
213
- return capabilities;
214
- }
215
- }
216
-
217
- class StigmergyInstaller {
218
- constructor() {
219
- this.homeDir = os.homedir();
220
- this.stigmergyDir = path.join(this.homeDir, '.stigmergy');
221
- this.projectDir = process.cwd();
222
- }
223
-
224
- async ensureDirectory(dirPath) {
225
- try {
226
- await fs.mkdir(dirPath, { recursive: true });
227
- return true;
228
- } catch (error) {
229
- return false;
230
- }
231
- }
232
-
233
- checkCLI(toolName) {
234
- try {
235
- const tool = CLI_TOOLS[toolName];
236
- const command = tool.version.split(' ')[0];
237
- const args = tool.version.split(' ').slice(1);
238
-
239
- const result = spawnSync(command, args, {
240
- stdio: 'ignore',
241
- timeout: 10000,
242
- env: { ...process.env }
243
- });
244
- return result.status === 0;
245
- } catch (error) {
246
- return false;
247
- }
248
- }
249
-
250
- async scanAvailableTools() {
251
- const results = {
252
- total: Object.keys(CLI_TOOLS).length,
253
- available: [],
254
- unavailable: [],
255
- details: []
256
- };
257
-
258
- console.log('[SCAN] Scanning for AI CLI tools on your system...');
259
- console.log('='.repeat(60));
260
-
261
- for (const [key, tool] of Object.entries(CLI_TOOLS)) {
262
- const isAvailable = this.checkCLI(key);
263
-
264
- if (isAvailable) {
265
- results.available.push(key);
266
- console.log(`[OK] ${tool.name}: Available (${tool.version})`);
267
- results.details.push({
268
- key,
269
- name: tool.name,
270
- status: 'Available',
271
- install: tool.install,
272
- hooksDir: tool.hooksDir
273
- });
274
- } else {
275
- results.unavailable.push(key);
276
- console.log(`[X] ${tool.name}: Not Available`);
277
- results.details.push({
278
- key,
279
- name: tool.name,
280
- status: 'Not Available',
281
- install: tool.install,
282
- hooksDir: tool.hooksDir
283
- });
284
- }
285
- }
286
-
287
- console.log('='.repeat(60));
288
- console.log(`[SUMMARY] ${results.available.length}/${results.total} tools available`);
289
- console.log('');
290
-
291
- return results;
292
- }
293
-
294
- async promptForInstallation(scanResults) {
295
- if (scanResults.unavailable.length === 0) {
296
- console.log('[SUCCESS] All AI CLI tools are already installed!');
297
- return [];
298
- }
299
-
300
- console.log('[INSTALL] The following AI CLI tools can be automatically installed:');
301
- console.log('');
302
-
303
- scanResults.unavailable.forEach((toolKey, index) => {
304
- const tool = CLI_TOOLS[toolKey];
305
- console.log(` ${index + 1}. ${tool.name}`);
306
- console.log(` Install: ${tool.install}`);
307
- console.log('');
308
- });
309
-
310
- console.log('[OPTIONS] Installation Options:');
311
- console.log(' - Enter numbers separated by spaces (e.g: 1 3 5)');
312
- console.log(' - Enter "all" to install all missing tools');
313
- console.log(' - Enter "skip" to skip CLI installation');
314
-
315
- return new Promise((resolve) => {
316
- process.stdout.write('\n[SELECT] Select tools to install: ');
317
-
318
- process.stdin.once('data', (data) => {
319
- const input = data.toString().trim();
320
-
321
- if (input === '' || input.toLowerCase() === 'skip') {
322
- resolve([]);
323
- } else if (input.toLowerCase() === 'all') {
324
- resolve(scanResults.unavailable);
325
- } else {
326
- const numbers = input.split(/\s+/).map(n => parseInt(n) - 1);
327
- const selected = numbers
328
- .filter(n => n >= 0 && n < scanResults.unavailable.length)
329
- .map(n => scanResults.unavailable[n]);
330
- resolve(selected);
331
- }
332
- });
333
- });
334
- }
335
-
336
- async installTools(toolKeys) {
337
- if (toolKeys.length === 0) {
338
- console.log('[SKIP] Skipping CLI tool installation.');
339
- return;
340
- }
341
-
342
- console.log(`\n[INSTALL] Installing ${toolKeys.length} AI CLI tools...`);
343
- console.log('='.repeat(60));
344
-
345
- for (const toolKey of toolKeys) {
346
- const tool = CLI_TOOLS[toolKey];
347
- console.log(`\n[INSTALLING] Installing ${tool.name}...`);
348
-
349
- try {
350
- const packageInstall = spawn('npm', ['install', '-g'].concat(tool.install.split(' ').slice(3)), {
351
- stdio: 'inherit',
352
- shell: true
353
- });
354
-
355
- await new Promise((resolve, reject) => {
356
- packageInstall.on('close', (code) => {
357
- if (code === 0) {
358
- console.log(`[OK] ${tool.name} installed successfully!`);
359
- resolve();
360
- } else {
361
- console.log(`[ERROR] Failed to install ${tool.name}`);
362
- reject(new Error(`Installation failed with code ${code}`));
363
- }
364
- });
365
- });
366
- } catch (error) {
367
- console.log(`[ERROR] Error installing ${tool.name}:`, error.message);
368
- }
369
- }
370
-
371
- console.log('\n[VERIFY] CLI Installation completed! Verifying...');
372
- await this.verifyInstallation(toolKeys);
373
- }
374
-
375
- async verifyInstallation(toolKeys) {
376
- console.log('='.repeat(60));
377
- let successCount = 0;
378
-
379
- for (const toolKey of toolKeys) {
380
- const tool = CLI_TOOLS[toolKey];
381
- if (this.checkCLI(toolKey)) {
382
- console.log(`[OK] ${tool.name}: Successfully installed and functional!`);
383
- successCount++;
384
- } else {
385
- console.log(`[FAIL] ${tool.name}: Installation verification failed`);
386
- }
387
- }
388
-
389
- console.log(`\n[RESULT] Installation Result: ${successCount}/${toolKeys.length} tools successfully installed`);
390
-
391
- if (successCount === toolKeys.length) {
392
- console.log('[SUCCESS] All selected CLI tools are now ready to use!');
393
- }
394
- }
395
-
396
- async deployHooks(availableTools) {
397
- if (availableTools.length === 0) {
398
- console.log('[SKIP] No CLI tools available for hook deployment.');
399
- return;
400
- }
401
-
402
- console.log(`\n[DEPLOY] Deploying Stigmergy hooks to ${availableTools.length} CLI tools...`);
403
- console.log('='.repeat(60));
404
-
405
- const hookTemplate = `#!/usr/bin/env node
406
-
407
- /**
408
- * Stigmergy Hook - ${new Date().toISOString()}
409
- * Generated by Stigmergy CLI
410
- */
411
-
412
- const { spawn } = require('child_process');
413
-
414
- // Stigmergy Hook Implementation
415
- class StigmergyHook {
416
- constructor() {
417
- this.processArgs();
418
- }
419
-
420
- processArgs() {
421
- const args = process.argv.slice(2);
422
- if (args.length === 0) {
423
- this.showHelp();
424
- return;
425
- }
426
-
427
- const command = args[0];
428
- switch (command) {
429
- case 'collaborate':
430
- this.handleCollaborate(args.slice(1));
431
- break;
432
- case 'status':
433
- this.showStatus();
434
- break;
435
- case 'init':
436
- this.initProject(args.slice(1));
437
- break;
438
- default:
439
- this.showHelp();
440
- }
441
- }
442
-
443
- handleCollaborate(args) {
444
- console.log('[COLLAB] Stigmergy Collaboration System');
445
- console.log('Available AI CLI tools:', Object.keys(CLI_TOOLS).join(', '));
446
- }
447
-
448
- showStatus() {
449
- console.log('[STATUS] Stigmergy Hook Status: Active');
450
- console.log('Configuration: Loaded successfully');
451
- }
452
-
453
- initProject(projectName) {
454
- console.log('[INIT] Initializing Stigmergy project:', projectName || 'current');
455
- console.log('[OK] Project configuration created');
456
- }
457
-
458
- showHelp() {
459
- console.log('Stigmergy Hook - Multi-AI CLI Collaboration');
460
- console.log('');
461
- console.log('Commands:');
462
- console.log(' collaborate [options] Start collaboration with other AI CLI tools');
463
- console.log(' status Show hook status');
464
- console.log(' init [project] Initialize Stigmergy project');
465
- console.log(' help Show this help message');
466
- console.log('');
467
- console.log('Examples:');
468
- console.log(' stigmergy-hook collaborate claude gemini');
469
- console.log(' stigmergy-hook status');
470
- console.log(' stigmergy-hook init my-project');
471
- }
472
- }
473
-
474
- // Initialize hook
475
- const hook = new StigmergyHook();
476
- `;
477
-
478
- let deployedCount = 0;
479
-
480
- for (const toolKey of availableTools) {
481
- const tool = CLI_TOOLS[toolKey];
482
- const hooksDir = tool.hooksDir;
483
-
484
- await this.ensureDirectory(hooksDir);
485
-
486
- const hookFile = path.join(hooksDir, 'stigmergy-hook.cjs');
487
- try {
488
- await fs.writeFile(hookFile, hookTemplate, 'utf8');
489
-
490
- if (process.platform !== 'win32') {
491
- const { spawn } = require('child_process');
492
- spawn('chmod', ['+x', hookFile], { stdio: 'ignore' });
493
- }
494
-
495
- console.log(`[OK] ${tool.name}: Hook deployed to ${hooksDir}`);
496
- deployedCount++;
497
- } catch (error) {
498
- console.log(`[FAIL] ${tool.name}: Failed to deploy hook - ${error.message}`);
499
- }
500
- }
501
-
502
- console.log('\n[RESULT] Hook Deployment Result: ' + deployedCount + '/' + availableTools.length + ' hooks deployed');
503
- }
504
-
505
- async setupGlobalConfiguration(availableTools = []) {
506
- await this.ensureDirectory(this.stigmergyDir);
507
-
508
- const globalConfig = {
509
- version: '1.0.77',
510
- installed: new Date().toISOString(),
511
- projectPath: this.projectDir,
512
- availableTools: availableTools,
513
- deployedHooks: availableTools,
514
- collaboration: {
515
- enabled: true,
516
- protocols: [
517
- 'Use {cli} to {task}',
518
- 'Call {cli} to {task}',
519
- 'Ask {cli} for {task}',
520
- 'Get {cli} to {task}',
521
- 'Have {cli} {task}'
522
- ],
523
- examples: [
524
- 'Use claude to help debug this code',
525
- 'Call gemini to analyze the file',
526
- 'Ask qwen to translate this text'
527
- ]
528
- }
529
- };
530
-
531
- const configPath = path.join(this.stigmergyDir, 'config.json');
532
- try {
533
- await fs.writeFile(configPath, JSON.stringify(globalConfig, null, 2));
534
- console.log('[CONFIG] Global configuration saved to:', configPath);
535
- } catch (error) {
536
- console.log('[WARN] Warning: Could not save global configuration');
537
- }
538
-
539
- const projectDocs = path.join(this.projectDir, 'STIGMERGY.md');
540
- const docsTemplate = `# Stigmergy Multi-AI CLI Collaboration
541
-
542
- This project is configured for Stigmergy-based multi-AI CLI collaboration.
543
-
544
- ## Available AI CLI Tools
545
-
546
- ${availableTools.map(tool => `- **${CLI_TOOLS[tool].name}**: \`stigmergy call ${tool}\``).join('\n')}
547
-
548
- ## Usage Examples
549
-
550
- ### Cross-CLI Collaboration
551
- \`\`\`bash
552
- # Use Claude to analyze code
553
- stigmergy call claude "analyze this function"
554
-
555
- # Use Gemini for documentation
556
- stigmergy call gemini "generate docs for this file"
557
-
558
- # Use Qwen for translation
559
- stigmergy call qwen "translate to English"
560
- \`\`\`
561
-
562
- ### Project Initialization
563
- \`\`\`bash
564
- # Initialize with Claude as primary AI
565
- stigmergy init --primary claude
566
-
567
- # Initialize with multiple AI tools
568
- stigmergy init --all-tools
569
- \`\`\`
570
-
571
- ## Configuration
572
-
573
- Global configuration: \`~/.stigmergy/config.json\`
574
-
575
- ## Getting Started
576
-
577
- 1. Run \`stigmergy status\` to verify setup
578
- 2. Use \`stigmergy call <ai-tool> "<prompt>"\` to collaborate with AI CLI tools
579
- 3. Check project-specific configurations in individual CLI tool directories
580
-
581
- For more information: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents
582
- `;
583
-
584
- try {
585
- await fs.writeFile(projectDocs, docsTemplate, 'utf8');
586
- console.log('[DOCS] Project documentation created: STIGMERGY.md');
587
- } catch (error) {
588
- console.log('[WARN] Warning: Could not create project documentation');
589
- }
590
- }
591
-
592
- async showUsageInstructions() {
593
- console.log('\n' + '='.repeat(60));
594
- console.log('[SUCCESS] Stigmergy Installation and Deployment Complete!');
595
- console.log('='.repeat(60));
596
- console.log('');
597
- console.log('[NEXT] Next Steps:');
598
- console.log('');
599
- console.log('1. Verify Installation:');
600
- console.log(' stigmergy status');
601
- console.log('');
602
- console.log('2. Check Available Tools:');
603
- console.log(' stigmergy scan');
604
- console.log('');
605
- console.log('3. Start Using AI CLI Collaboration:');
606
- console.log(' stigmergy call claude "help me debug this code"');
607
- console.log(' stigmergy call gemini "generate documentation"');
608
- console.log(' stigmergy call qwen "translate to English"');
609
- console.log('');
610
- console.log('4. Initialize New Projects:');
611
- console.log(' stigmergy init --primary claude');
612
- console.log('');
613
- console.log('[INFO] Documentation:');
614
- console.log(' - Global Config: ~/.stigmergy/config.json');
615
- console.log(' - Project Docs: ./STIGMERGY.md');
616
- console.log(' - GitHub: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
617
- console.log('');
618
- console.log('[END] Happy collaborating with multiple AI CLI tools!');
619
- }
620
- }
621
-
622
- // Main CLI functionality
623
- async function main() {
624
- const args = process.argv.slice(2);
625
- const installer = new StigmergyInstaller();
626
-
627
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
628
- console.log('Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System');
629
- console.log('Version: 1.0.78');
630
- console.log('');
631
- console.log('[SYSTEM] Automated Installation and Deployment System');
632
- console.log('');
633
- console.log('Usage: stigmergy [command] [options]');
634
- console.log('');
635
- console.log('Commands:');
636
- console.log(' help, --help Show this help message');
637
- console.log(' version, --version Show version information');
638
- console.log(' status Check CLI tools status');
639
- console.log(' scan Scan for available AI CLI tools');
640
- console.log(' install Auto-install missing CLI tools');
641
- console.log(' deploy Deploy hooks to installed tools');
642
- console.log(' setup Complete setup and configuration');
643
- console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
644
- console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
645
- console.log('');
646
- console.log('[WORKFLOW] Automated Workflow:');
647
- console.log(' 1. npm install -g stigmergy # Install Stigmergy');
648
- console.log(' 2. stigmergy install # Auto-scan & install CLI tools');
649
- console.log(' 3. stigmergy setup # Deploy hooks & config');
650
- console.log(' 4. stigmergy call <ai> <prompt> # Start collaborating');
651
- console.log('');
652
- console.log('For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
653
- return;
654
- }
655
-
656
- if (args.includes('--version') || args.includes('version')) {
657
- console.log('1.0.77');
658
- return;
659
- }
660
-
661
- // Auto-install mode for postinstall script
662
- if (args.includes('auto-install')) {
663
- console.log('[AUTO-INSTALL] Stigmergy CLI - Automated Installation and Deployment');
664
- console.log('Multi-AI CLI Tools Collaboration System v1.0.77');
665
- console.log('='.repeat(60));
666
-
667
- const originalPrompt = installer.promptForInstallation;
668
- installer.promptForInstallation = async () => {
669
- console.log('[AUTO-INSTALL] Skipping interactive CLI installation in postinstall mode');
670
- console.log('[AUTO-INSTALL] You can run "stigmergy" manually to install CLI tools interactively');
671
- return [];
672
- };
673
-
674
- console.log('\n[STEP 1] Scanning for AI CLI tools...');
675
- const scanResults = await installer.scanAvailableTools();
676
-
677
- console.log('\n[STEP 2] Deploying Stigmergy hooks...');
678
- await installer.deployHooks(scanResults.available);
679
-
680
- console.log('\n[STEP 3] Setting up configuration...');
681
- await installer.setupGlobalConfiguration(scanResults.available);
682
-
683
- console.log('\n[AUTO-INSTALL] Stigmergy automated setup completed!');
684
- console.log('[AUTO-INSTALL] Run "stigmergy" to start interactive CLI tool installation');
685
- return;
686
- }
687
-
688
- // Define valid commands
689
- const validCommands = ['help', '--help', '-h', 'version', '--version', 'status', 'scan', 'install', 'deploy', 'setup', 'auto-install', 'call'];
690
-
691
- // Handle call command
692
- if (args[0] === 'call') {
693
- return await handleCallCommand(args.slice(1));
694
- }
695
-
696
- // Check for invalid commands
697
- const hasValidCommand = args.some(arg => validCommands.includes(arg));
698
- if (!hasValidCommand && args.length > 0) {
699
- console.log('[ERROR] Invalid command:', args[0]);
700
- console.log('');
701
- console.log('Usage: stigmergy [command] [options]');
702
- console.log('');
703
- console.log('Available commands:');
704
- console.log(' help, --help Show this help message');
705
- console.log(' version, --version Show version information');
706
- console.log(' status Check CLI tools status');
707
- console.log(' scan Scan for available AI CLI tools');
708
- console.log(' install Auto-install missing CLI tools');
709
- console.log(' deploy Deploy hooks to installed tools');
710
- console.log(' setup Complete setup and configuration');
711
- console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
712
- console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
713
- console.log('');
714
- console.log('Run "stigmergy --help" for more information.');
715
- process.exit(1);
716
- }
717
-
718
- // Start automated installation and deployment
719
- console.log('[START] Stigmergy CLI - Automated Installation and Deployment');
720
- console.log('Multi-AI CLI Tools Collaboration System v1.0.77');
721
- console.log('='.repeat(60));
722
-
723
- console.log('\n[STEP 1] Scanning for AI CLI tools...');
724
- const scanResults = await installer.scanAvailableTools();
725
-
726
- if (scanResults.unavailable.length > 0) {
727
- console.log('\n[STEP 2] CLI Tool Installation');
728
- const selectedTools = await installer.promptForInstallation(scanResults);
729
- await installer.installTools(selectedTools);
730
-
731
- if (selectedTools.length > 0) {
732
- console.log('\n[RESCAN] Re-scanning after installation...');
733
- scanResults.available = scanResults.available.concat(selectedTools.filter(tool => installer.checkCLI(tool)));
734
- scanResults.unavailable = scanResults.unavailable.filter(tool => !selectedTools.includes(tool));
735
- }
736
- } else {
737
- console.log('\n[STEP 2] All CLI tools already available!');
738
- }
739
-
740
- console.log('\n[STEP 3] Deploying Stigmergy hooks...');
741
- await installer.deployHooks(scanResults.available);
742
-
743
- console.log('\n[STEP 4] Setting up configuration...');
744
- await installer.setupGlobalConfiguration(scanResults.available);
745
-
746
- await installer.showUsageInstructions();
747
- }
748
-
749
- // Memory Management System
750
- class MemoryManager {
751
- constructor(stigmergyDir) {
752
- this.memoryDir = path.join(stigmergyDir, 'memory');
753
- this.globalMemoryFile = path.join(this.memoryDir, 'global.json');
754
- this.projectMemoryFile = path.join(process.cwd(), '.stigmergy-memory.json');
755
- }
756
-
757
- async ensureDirectory() {
758
- await fs.mkdir(this.memoryDir, { recursive: true });
759
- }
760
-
761
- async saveGlobalMemory(data) {
762
- await this.ensureDirectory();
763
- await fs.writeFile(this.globalMemoryFile, JSON.stringify({
764
- lastUpdated: new Date().toISOString(),
765
- ...data
766
- }, null, 2));
767
- }
768
-
769
- async loadGlobalMemory() {
770
- try {
771
- await this.ensureDirectory();
772
- const data = await fs.readFile(this.globalMemoryFile, 'utf8');
773
- return JSON.parse(data);
774
- } catch (error) {
775
- return {};
776
- }
777
- }
778
-
779
- async saveProjectMemory(data) {
780
- const memory = await this.loadProjectMemory();
781
- await fs.writeFile(this.projectMemoryFile, JSON.stringify({
782
- ...memory,
783
- lastUpdated: new Date().toISOString(),
784
- ...data
785
- }, null, 2));
786
- }
787
-
788
- async loadProjectMemory() {
789
- try {
790
- const data = await fs.readFile(this.projectMemoryFile, 'utf8');
791
- return JSON.parse(data);
792
- } catch (error) {
793
- return {
794
- projectName: path.basename(process.cwd()),
795
- createdAt: new Date().toISOString(),
796
- interactions: []
797
- };
798
- }
799
- }
800
-
801
- async addInteraction(tool, prompt, response) {
802
- const interaction = {
803
- timestamp: new Date().toISOString(),
804
- tool,
805
- prompt,
806
- response,
807
- duration: Date.now() - new Date().getTime()
808
- };
809
-
810
- await this.saveProjectMemory({
811
- lastInteraction: interaction,
812
- interactions: (await this.loadProjectMemory()).interactions.concat(interaction).slice(-100) // Keep last 100
813
- });
814
- }
815
- }
816
-
817
- // Call Command Handler
818
- async function handleCallCommand(args) {
819
- const router = new SmartRouter();
820
- const memoryManager = new MemoryManager(path.join(os.homedir(), '.stigmergy'));
821
-
822
- if (args.length === 0) {
823
- console.log('[ERROR] Call command requires a tool name and/or prompt');
824
- console.log('');
825
- console.log('Usage: stigmergy call <tool> <prompt>');
826
- console.log(' stigmergy call <prompt> (auto-route to best tool)');
827
- console.log('');
828
- console.log('Available tools:', Object.keys(CLI_TOOLS).join(', '));
829
- return;
830
- }
831
-
832
- let toolName, prompt;
833
-
834
- // Check if first argument is a valid tool
835
- if (CLI_TOOLS[args[0]]) {
836
- toolName = args[0];
837
- prompt = args.slice(1).join(' ');
838
- } else {
839
- // Auto-route based on keywords
840
- const routeResult = router.smartRoute(args.join(' '));
841
- toolName = routeResult.tool;
842
- prompt = routeResult.prompt || args.join(' ');
843
- }
844
-
845
- if (!prompt) {
846
- console.log('[ERROR] Prompt is required');
847
- return;
848
- }
849
-
850
- console.log(`[CALL] Routing to: ${CLI_TOOLS[toolName].name}`);
851
- console.log(`[PROMPT] ${prompt}`);
852
- console.log('='.repeat(60));
853
-
854
- const result = await router.executeTool(toolName, prompt);
855
-
856
- if (result.success) {
857
- console.log('[SUCCESS] Execution completed');
858
- if (result.output) {
859
- console.log('[OUTPUT]');
860
- console.log(result.output);
861
- }
862
-
863
- // Save to memory
864
- await memoryManager.addInteraction(toolName, prompt, result.output || 'Success');
865
- console.log(`[MEMORY] Interaction saved to project memory`);
866
- } else {
867
- console.log('[ERROR] Execution failed');
868
- if (result.error) {
869
- console.log('[ERROR]', result.error);
870
- }
871
-
872
- // Save failed interaction to memory
873
- await memoryManager.addInteraction(toolName, prompt, result.error || 'Failed');
874
- }
875
-
876
- console.log('');
877
- console.log('[INFO] For help with CLI usage: stigmergy help');
878
- }
879
-
880
- // Setup stdin for interactive prompts
881
- if (require.main === module) {
882
- if (process.stdin.isTTY) {
883
- process.stdin.resume();
884
- process.stdin.setEncoding('utf8');
885
- }
886
-
887
- main().catch(error => {
888
- console.error('[ERROR] Error:', error.message);
889
- process.exit(1);
890
- });
891
- }
892
-
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System
5
+ * International Version - Pure ANSI Characters Only
6
+ * Version: 1.0.76
7
+ */
8
+
9
+ const { spawn, spawnSync } = require('child_process');
10
+ const path = require('path');
11
+ const fs = require('fs/promises');
12
+ const os = require('os');
13
+
14
+ // AI CLI Tools Configuration
15
+ const CLI_TOOLS = {
16
+ claude: {
17
+ name: 'Claude CLI',
18
+ version: 'claude --version',
19
+ install: 'npm install -g @anthropic-ai/claude-cli',
20
+ hooksDir: path.join(os.homedir(), '.claude', 'hooks'),
21
+ config: path.join(os.homedir(), '.claude', 'config.json')
22
+ },
23
+ gemini: {
24
+ name: 'Gemini CLI',
25
+ version: 'gemini --version',
26
+ install: 'npm install -g @google/generative-ai-cli',
27
+ hooksDir: path.join(os.homedir(), '.gemini', 'extensions'),
28
+ config: path.join(os.homedir(), '.gemini', 'config.json')
29
+ },
30
+ qwen: {
31
+ name: 'Qwen CLI',
32
+ version: 'qwen --version',
33
+ install: 'npm install -g @alibaba/qwen-cli',
34
+ hooksDir: path.join(os.homedir(), '.qwen', 'hooks'),
35
+ config: path.join(os.homedir(), '.qwen', 'config.json')
36
+ },
37
+ iflow: {
38
+ name: 'iFlow CLI',
39
+ version: 'iflow --version',
40
+ install: 'npm install -g iflow-cli',
41
+ hooksDir: path.join(os.homedir(), '.iflow', 'hooks'),
42
+ config: path.join(os.homedir(), '.iflow', 'config.json')
43
+ },
44
+ qoder: {
45
+ name: 'Qoder CLI',
46
+ version: 'qodercli --version',
47
+ install: 'npm install -g @qoder-ai/qodercli',
48
+ hooksDir: path.join(os.homedir(), '.qoder', 'hooks'),
49
+ config: path.join(os.homedir(), '.qoder', 'config.json')
50
+ },
51
+ codebuddy: {
52
+ name: 'CodeBuddy CLI',
53
+ version: 'codebuddy --version',
54
+ install: 'npm install -g codebuddy-cli',
55
+ hooksDir: path.join(os.homedir(), '.codebuddy', 'hooks'),
56
+ config: path.join(os.homedir(), '.codebuddy', 'config.json')
57
+ },
58
+ copilot: {
59
+ name: 'GitHub Copilot CLI',
60
+ version: 'copilot --version',
61
+ install: 'npm install -g @github/copilot-cli',
62
+ hooksDir: path.join(os.homedir(), '.copilot', 'mcp'),
63
+ config: path.join(os.homedir(), '.copilot', 'config.json')
64
+ },
65
+ codex: {
66
+ name: 'OpenAI Codex CLI',
67
+ version: 'codex --version',
68
+ install: 'npm install -g openai-codex-cli',
69
+ hooksDir: path.join(os.homedir(), '.config', 'codex', 'slash_commands'),
70
+ config: path.join(os.homedir(), '.codex', 'config.json')
71
+ }
72
+ };
73
+
74
+ class SmartRouter {
75
+ constructor() {
76
+ this.tools = CLI_TOOLS;
77
+ this.routeKeywords = ['use', 'help', 'please', 'write', 'generate', 'explain', 'analyze', 'translate', 'code', 'article'];
78
+ this.defaultTool = 'claude';
79
+ }
80
+
81
+ shouldRoute(userInput) {
82
+ return this.routeKeywords.some(keyword =>
83
+ userInput.toLowerCase().includes(keyword.toLowerCase())
84
+ );
85
+ }
86
+
87
+ smartRoute(userInput) {
88
+ const input = userInput.trim();
89
+
90
+ // Detect tool-specific keywords
91
+ for (const [toolName, toolInfo] of Object.entries(this.tools)) {
92
+ for (const keyword of this.extractKeywords(toolName)) {
93
+ if (input.toLowerCase().includes(keyword.toLowerCase())) {
94
+ // Extract clean parameters
95
+ const cleanInput = input
96
+ .replace(new RegExp(`.*${keyword}\\s*`, 'gi'), '')
97
+ .replace(/^(用|帮我|请|麻烦|给我|帮我写|帮我生成)\s*/i, '')
98
+ .trim();
99
+ return { tool: toolName, prompt: cleanInput };
100
+ }
101
+ }
102
+ }
103
+
104
+ // Default routing
105
+ const cleanInput = input
106
+ .replace(/^(用|帮我|请|麻烦|给我|帮我写|帮我生成)\s*/i, '')
107
+ .trim();
108
+ return { tool: this.defaultTool, prompt: cleanInput };
109
+ }
110
+
111
+ extractKeywords(toolName) {
112
+ const keywordMap = {
113
+ claude: ['claude', 'anthropic'],
114
+ gemini: ['gemini', 'google', '谷歌'],
115
+ qwen: ['qwen', '通义', '阿里'],
116
+ iflow: ['iflow', '心流', 'intelligent'],
117
+ qoder: ['qoder', 'qodercli'],
118
+ codebuddy: ['codebuddy', 'buddy'],
119
+ copilot: ['copilot', 'github'],
120
+ codex: ['codex', 'openai']
121
+ };
122
+ return keywordMap[toolName] || [toolName];
123
+ }
124
+
125
+ async executeTool(toolName, prompt) {
126
+ const tool = this.tools[toolName];
127
+ if (!tool) {
128
+ return { success: false, error: `Unknown tool: ${toolName}` };
129
+ }
130
+
131
+ if (!this.checkCLI(toolName)) {
132
+ return { success: false, error: `${tool.name} is not available` };
133
+ }
134
+
135
+ try {
136
+ const result = spawnSync(toolName, [prompt], {
137
+ encoding: 'utf8',
138
+ timeout: 30000
139
+ });
140
+
141
+ return {
142
+ success: result.status === 0,
143
+ output: result.stdout,
144
+ error: result.stderr
145
+ };
146
+ } catch (error) {
147
+ return { success: false, error: error.message };
148
+ }
149
+ }
150
+
151
+ checkCLI(toolName) {
152
+ try {
153
+ const tool = this.tools[toolName];
154
+ const command = tool.version.split(' ')[0];
155
+ const args = tool.version.split(' ').slice(1);
156
+
157
+ const result = spawnSync(command, args, {
158
+ stdio: 'ignore',
159
+ timeout: 10000,
160
+ env: { ...process.env }
161
+ });
162
+ return result.status === 0;
163
+ } catch (error) {
164
+ return false;
165
+ }
166
+ }
167
+
168
+ async analyzeCLIHelp(toolName) {
169
+ const tool = this.tools[toolName];
170
+ if (!tool) return null;
171
+
172
+ try {
173
+ const result = spawnSync(toolName, ['--help'], {
174
+ encoding: 'utf8',
175
+ timeout: 15000
176
+ });
177
+
178
+ if (result.status === 0) {
179
+ return this.parseHelpOutput(result.stdout);
180
+ }
181
+ return null;
182
+ } catch (error) {
183
+ return null;
184
+ }
185
+ }
186
+
187
+ parseHelpOutput(helpText) {
188
+ const capabilities = {
189
+ commands: [],
190
+ options: [],
191
+ examples: [],
192
+ features: []
193
+ };
194
+
195
+ // Extract commands
196
+ const commandMatches = helpText.match(/^\s{0,4}([a-z][a-z0-9_-]+)\s+.+$/gm);
197
+ if (commandMatches) {
198
+ capabilities.commands = commandMatches.map(match => match.trim());
199
+ }
200
+
201
+ // Extract options
202
+ const optionMatches = helpText.match(/--[a-z-]+/g);
203
+ if (optionMatches) {
204
+ capabilities.options = [...new Set(optionMatches)];
205
+ }
206
+
207
+ // Extract examples
208
+ const exampleMatches = helpText.match(/(example|Usage|用法)[::]\s*\n([\s\S]*?)(?=\n\n|\n[A-Z]|\n$)/gi);
209
+ if (exampleMatches) {
210
+ capabilities.examples = exampleMatches.map(match => match.replace(/^(example|Usage|用法)[::]\s*/i, '').trim());
211
+ }
212
+
213
+ return capabilities;
214
+ }
215
+ }
216
+
217
+ class StigmergyInstaller {
218
+ constructor() {
219
+ this.homeDir = os.homedir();
220
+ this.stigmergyDir = path.join(this.homeDir, '.stigmergy');
221
+ this.projectDir = process.cwd();
222
+ }
223
+
224
+ async ensureDirectory(dirPath) {
225
+ try {
226
+ await fs.mkdir(dirPath, { recursive: true });
227
+ return true;
228
+ } catch (error) {
229
+ return false;
230
+ }
231
+ }
232
+
233
+ checkCLI(toolName) {
234
+ try {
235
+ const tool = CLI_TOOLS[toolName];
236
+ const command = tool.version.split(' ')[0];
237
+ const args = tool.version.split(' ').slice(1);
238
+
239
+ const result = spawnSync(command, args, {
240
+ stdio: 'ignore',
241
+ timeout: 10000,
242
+ env: { ...process.env }
243
+ });
244
+ return result.status === 0;
245
+ } catch (error) {
246
+ return false;
247
+ }
248
+ }
249
+
250
+ async scanAvailableTools() {
251
+ const results = {
252
+ total: Object.keys(CLI_TOOLS).length,
253
+ available: [],
254
+ unavailable: [],
255
+ details: []
256
+ };
257
+
258
+ console.log('[SCAN] Scanning for AI CLI tools on your system...');
259
+ console.log('='.repeat(60));
260
+
261
+ for (const [key, tool] of Object.entries(CLI_TOOLS)) {
262
+ const isAvailable = this.checkCLI(key);
263
+
264
+ if (isAvailable) {
265
+ results.available.push(key);
266
+ console.log(`[OK] ${tool.name}: Available (${tool.version})`);
267
+ results.details.push({
268
+ key,
269
+ name: tool.name,
270
+ status: 'Available',
271
+ install: tool.install,
272
+ hooksDir: tool.hooksDir
273
+ });
274
+ } else {
275
+ results.unavailable.push(key);
276
+ console.log(`[X] ${tool.name}: Not Available`);
277
+ results.details.push({
278
+ key,
279
+ name: tool.name,
280
+ status: 'Not Available',
281
+ install: tool.install,
282
+ hooksDir: tool.hooksDir
283
+ });
284
+ }
285
+ }
286
+
287
+ console.log('='.repeat(60));
288
+ console.log(`[SUMMARY] ${results.available.length}/${results.total} tools available`);
289
+ console.log('');
290
+
291
+ return results;
292
+ }
293
+
294
+ async promptForInstallation(scanResults) {
295
+ if (scanResults.unavailable.length === 0) {
296
+ console.log('[SUCCESS] All AI CLI tools are already installed!');
297
+ return [];
298
+ }
299
+
300
+ console.log('[INSTALL] The following AI CLI tools can be automatically installed:');
301
+ console.log('');
302
+
303
+ scanResults.unavailable.forEach((toolKey, index) => {
304
+ const tool = CLI_TOOLS[toolKey];
305
+ console.log(` ${index + 1}. ${tool.name}`);
306
+ console.log(` Install: ${tool.install}`);
307
+ console.log('');
308
+ });
309
+
310
+ console.log('[OPTIONS] Installation Options:');
311
+ console.log(' - Enter numbers separated by spaces (e.g: 1 3 5)');
312
+ console.log(' - Enter "all" to install all missing tools');
313
+ console.log(' - Enter "skip" to skip CLI installation');
314
+
315
+ return new Promise((resolve) => {
316
+ process.stdout.write('\n[SELECT] Select tools to install: ');
317
+
318
+ process.stdin.once('data', (data) => {
319
+ const input = data.toString().trim();
320
+
321
+ if (input === '' || input.toLowerCase() === 'skip') {
322
+ resolve([]);
323
+ } else if (input.toLowerCase() === 'all') {
324
+ resolve(scanResults.unavailable);
325
+ } else {
326
+ const numbers = input.split(/\s+/).map(n => parseInt(n) - 1);
327
+ const selected = numbers
328
+ .filter(n => n >= 0 && n < scanResults.unavailable.length)
329
+ .map(n => scanResults.unavailable[n]);
330
+ resolve(selected);
331
+ }
332
+ });
333
+ });
334
+ }
335
+
336
+ async installTools(toolKeys) {
337
+ if (toolKeys.length === 0) {
338
+ console.log('[SKIP] Skipping CLI tool installation.');
339
+ return;
340
+ }
341
+
342
+ console.log(`\n[INSTALL] Installing ${toolKeys.length} AI CLI tools...`);
343
+ console.log('='.repeat(60));
344
+
345
+ for (const toolKey of toolKeys) {
346
+ const tool = CLI_TOOLS[toolKey];
347
+ console.log(`\n[INSTALLING] Installing ${tool.name}...`);
348
+
349
+ try {
350
+ const packageInstall = spawn('npm', ['install', '-g'].concat(tool.install.split(' ').slice(3)), {
351
+ stdio: 'inherit',
352
+ shell: true
353
+ });
354
+
355
+ await new Promise((resolve, reject) => {
356
+ packageInstall.on('close', (code) => {
357
+ if (code === 0) {
358
+ console.log(`[OK] ${tool.name} installed successfully!`);
359
+ resolve();
360
+ } else {
361
+ console.log(`[ERROR] Failed to install ${tool.name}`);
362
+ reject(new Error(`Installation failed with code ${code}`));
363
+ }
364
+ });
365
+ });
366
+ } catch (error) {
367
+ console.log(`[ERROR] Error installing ${tool.name}:`, error.message);
368
+ }
369
+ }
370
+
371
+ console.log('\n[VERIFY] CLI Installation completed! Verifying...');
372
+ await this.verifyInstallation(toolKeys);
373
+ }
374
+
375
+ async verifyInstallation(toolKeys) {
376
+ console.log('='.repeat(60));
377
+ let successCount = 0;
378
+
379
+ for (const toolKey of toolKeys) {
380
+ const tool = CLI_TOOLS[toolKey];
381
+ if (this.checkCLI(toolKey)) {
382
+ console.log(`[OK] ${tool.name}: Successfully installed and functional!`);
383
+ successCount++;
384
+ } else {
385
+ console.log(`[FAIL] ${tool.name}: Installation verification failed`);
386
+ }
387
+ }
388
+
389
+ console.log(`\n[RESULT] Installation Result: ${successCount}/${toolKeys.length} tools successfully installed`);
390
+
391
+ if (successCount === toolKeys.length) {
392
+ console.log('[SUCCESS] All selected CLI tools are now ready to use!');
393
+ }
394
+ }
395
+
396
+ async deployHooks(availableTools) {
397
+ if (availableTools.length === 0) {
398
+ console.log('[SKIP] No CLI tools available for hook deployment.');
399
+ return;
400
+ }
401
+
402
+ console.log(`\n[DEPLOY] Deploying Stigmergy hooks to ${availableTools.length} CLI tools...`);
403
+ console.log('='.repeat(60));
404
+
405
+ const hookTemplate = `#!/usr/bin/env node
406
+
407
+ /**
408
+ * Stigmergy Hook - ${new Date().toISOString()}
409
+ * Generated by Stigmergy CLI
410
+ */
411
+
412
+ const { spawn } = require('child_process');
413
+
414
+ // Stigmergy Hook Implementation
415
+ class StigmergyHook {
416
+ constructor() {
417
+ this.processArgs();
418
+ }
419
+
420
+ processArgs() {
421
+ const args = process.argv.slice(2);
422
+ if (args.length === 0) {
423
+ this.showHelp();
424
+ return;
425
+ }
426
+
427
+ const command = args[0];
428
+ switch (command) {
429
+ case 'collaborate':
430
+ this.handleCollaborate(args.slice(1));
431
+ break;
432
+ case 'status':
433
+ this.showStatus();
434
+ break;
435
+ case 'init':
436
+ this.initProject(args.slice(1));
437
+ break;
438
+ default:
439
+ this.showHelp();
440
+ }
441
+ }
442
+
443
+ handleCollaborate(args) {
444
+ console.log('[COLLAB] Stigmergy Collaboration System');
445
+ console.log('Available AI CLI tools:', Object.keys(CLI_TOOLS).join(', '));
446
+ }
447
+
448
+ showStatus() {
449
+ console.log('[STATUS] Stigmergy Hook Status: Active');
450
+ console.log('Configuration: Loaded successfully');
451
+ }
452
+
453
+ initProject(projectName) {
454
+ console.log('[INIT] Initializing Stigmergy project:', projectName || 'current');
455
+ console.log('[OK] Project configuration created');
456
+ }
457
+
458
+ showHelp() {
459
+ console.log('Stigmergy Hook - Multi-AI CLI Collaboration');
460
+ console.log('');
461
+ console.log('Commands:');
462
+ console.log(' collaborate [options] Start collaboration with other AI CLI tools');
463
+ console.log(' status Show hook status');
464
+ console.log(' init [project] Initialize Stigmergy project');
465
+ console.log(' help Show this help message');
466
+ console.log('');
467
+ console.log('Examples:');
468
+ console.log(' stigmergy-hook collaborate claude gemini');
469
+ console.log(' stigmergy-hook status');
470
+ console.log(' stigmergy-hook init my-project');
471
+ }
472
+ }
473
+
474
+ // Initialize hook
475
+ const hook = new StigmergyHook();
476
+ `;
477
+
478
+ let deployedCount = 0;
479
+
480
+ for (const toolKey of availableTools) {
481
+ const tool = CLI_TOOLS[toolKey];
482
+ const hooksDir = tool.hooksDir;
483
+
484
+ await this.ensureDirectory(hooksDir);
485
+
486
+ const hookFile = path.join(hooksDir, 'stigmergy-hook.cjs');
487
+ try {
488
+ await fs.writeFile(hookFile, hookTemplate, 'utf8');
489
+
490
+ if (process.platform !== 'win32') {
491
+ const { spawn } = require('child_process');
492
+ spawn('chmod', ['+x', hookFile], { stdio: 'ignore' });
493
+ }
494
+
495
+ console.log(`[OK] ${tool.name}: Hook deployed to ${hooksDir}`);
496
+ deployedCount++;
497
+ } catch (error) {
498
+ console.log(`[FAIL] ${tool.name}: Failed to deploy hook - ${error.message}`);
499
+ }
500
+ }
501
+
502
+ console.log('\n[RESULT] Hook Deployment Result: ' + deployedCount + '/' + availableTools.length + ' hooks deployed');
503
+ }
504
+
505
+ async removeHooks() {
506
+ console.log('\n[REMOVE] Removing Stigmergy hooks from CLI tools...');
507
+ console.log('='.repeat(60));
508
+
509
+ let removedCount = 0;
510
+ let errorCount = 0;
511
+
512
+ // Iterate through all CLI tools and remove hooks
513
+ for (const [toolKey, toolInfo] of Object.entries(CLI_TOOLS)) {
514
+ console.log(`\n[REMOVE] Removing hooks for ${toolInfo.name}...`);
515
+
516
+ try {
517
+ // Remove the stigmergy hook file
518
+ const hookFile = path.join(toolInfo.hooksDir, 'stigmergy-hook.cjs');
519
+
520
+ // Check if the hook file exists
521
+ try {
522
+ await fs.access(hookFile);
523
+ // Remove the hook file
524
+ await fs.unlink(hookFile);
525
+ console.log(`[OK] Removed hook file from ${toolInfo.name}`);
526
+ removedCount++;
527
+ } catch (accessError) {
528
+ // Hook file doesn't exist, that's fine
529
+ console.log(`[INFO] No hook file found for ${toolInfo.name}`);
530
+ }
531
+
532
+ // Try to remove the hooks directory if it's empty
533
+ try {
534
+ const files = await fs.readdir(toolInfo.hooksDir);
535
+ if (files.length === 0) {
536
+ await fs.rmdir(toolInfo.hooksDir);
537
+ console.log(`[OK] Removed empty hooks directory for ${toolInfo.name}`);
538
+ } else {
539
+ console.log(`[INFO] Hooks directory for ${toolInfo.name} not empty, keeping it`);
540
+ }
541
+ } catch (dirError) {
542
+ // Directory might not exist or have other files, that's fine
543
+ console.log(`[INFO] Hooks directory for ${toolInfo.name} not removed: ${dirError.message}`);
544
+ }
545
+
546
+ } catch (error) {
547
+ console.log(`[ERROR] Failed to remove hooks for ${toolInfo.name}: ${error.message}`);
548
+ errorCount++;
549
+ }
550
+ }
551
+
552
+ console.log('\n[RESULT] Hook Removal Result: ' + removedCount + ' hooks removed, ' + errorCount + ' errors');
553
+ console.log('[SUCCESS] Stigmergy hooks removal completed!');
554
+
555
+ // Also remove global configuration
556
+ try {
557
+ const configPath = path.join(this.stigmergyDir, 'config.json');
558
+ await fs.unlink(configPath);
559
+ console.log('[OK] Removed global configuration file');
560
+ } catch (error) {
561
+ console.log('[INFO] Global configuration file not found or already removed');
562
+ }
563
+
564
+ console.log('\n[NEXT] To completely uninstall Stigmergy:');
565
+ console.log(' 1. Run: npm uninstall -g stigmergy');
566
+ console.log(' 2. Manually check and clean up any remaining files if needed');
567
+ }
568
+
569
+ async setupGlobalConfiguration(availableTools = []) {
570
+ await this.ensureDirectory(this.stigmergyDir);
571
+
572
+ const globalConfig = {
573
+ version: '1.0.77',
574
+ installed: new Date().toISOString(),
575
+ projectPath: this.projectDir,
576
+ availableTools: availableTools,
577
+ deployedHooks: availableTools,
578
+ collaboration: {
579
+ enabled: true,
580
+ protocols: [
581
+ 'Use {cli} to {task}',
582
+ 'Call {cli} to {task}',
583
+ 'Ask {cli} for {task}',
584
+ 'Get {cli} to {task}',
585
+ 'Have {cli} {task}'
586
+ ],
587
+ examples: [
588
+ 'Use claude to help debug this code',
589
+ 'Call gemini to analyze the file',
590
+ 'Ask qwen to translate this text'
591
+ ]
592
+ }
593
+ };
594
+
595
+ const configPath = path.join(this.stigmergyDir, 'config.json');
596
+ try {
597
+ await fs.writeFile(configPath, JSON.stringify(globalConfig, null, 2));
598
+ console.log('[CONFIG] Global configuration saved to:', configPath);
599
+ } catch (error) {
600
+ console.log('[WARN] Warning: Could not save global configuration');
601
+ }
602
+
603
+ const projectDocs = path.join(this.projectDir, 'STIGMERGY.md');
604
+ const docsTemplate = `# Stigmergy Multi-AI CLI Collaboration
605
+
606
+ This project is configured for Stigmergy-based multi-AI CLI collaboration.
607
+
608
+ ## Available AI CLI Tools
609
+
610
+ ${availableTools.map(tool => `- **${CLI_TOOLS[tool].name}**: \`stigmergy call ${tool}\``).join('\n')}
611
+
612
+ ## Usage Examples
613
+
614
+ ### Cross-CLI Collaboration
615
+ \`\`\`bash
616
+ # Use Claude to analyze code
617
+ stigmergy call claude "analyze this function"
618
+
619
+ # Use Gemini for documentation
620
+ stigmergy call gemini "generate docs for this file"
621
+
622
+ # Use Qwen for translation
623
+ stigmergy call qwen "translate to English"
624
+ \`\`\`
625
+
626
+ ### Project Initialization
627
+ \`\`\`bash
628
+ # Initialize with Claude as primary AI
629
+ stigmergy init --primary claude
630
+
631
+ # Initialize with multiple AI tools
632
+ stigmergy init --all-tools
633
+ \`\`\`
634
+
635
+ ## Configuration
636
+
637
+ Global configuration: \`~/.stigmergy/config.json\`
638
+
639
+ ## Getting Started
640
+
641
+ 1. Run \`stigmergy status\` to verify setup
642
+ 2. Use \`stigmergy call <ai-tool> "<prompt>"\` to collaborate with AI CLI tools
643
+ 3. Check project-specific configurations in individual CLI tool directories
644
+
645
+ For more information: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents
646
+ `;
647
+
648
+ try {
649
+ await fs.writeFile(projectDocs, docsTemplate, 'utf8');
650
+ console.log('[DOCS] Project documentation created: STIGMERGY.md');
651
+ } catch (error) {
652
+ console.log('[WARN] Warning: Could not create project documentation');
653
+ }
654
+ }
655
+
656
+ async showUsageInstructions() {
657
+ console.log('\n' + '='.repeat(60));
658
+ console.log('[SUCCESS] Stigmergy Installation and Deployment Complete!');
659
+ console.log('='.repeat(60));
660
+ console.log('');
661
+ console.log('[NEXT] Next Steps:');
662
+ console.log('');
663
+ console.log('1. Verify Installation:');
664
+ console.log(' stigmergy status');
665
+ console.log('');
666
+ console.log('2. Check Available Tools:');
667
+ console.log(' stigmergy scan');
668
+ console.log('');
669
+ console.log('3. Start Using AI CLI Collaboration:');
670
+ console.log(' stigmergy call claude "help me debug this code"');
671
+ console.log(' stigmergy call gemini "generate documentation"');
672
+ console.log(' stigmergy call qwen "translate to English"');
673
+ console.log('');
674
+ console.log('4. Initialize New Projects:');
675
+ console.log(' stigmergy init --primary claude');
676
+ console.log('');
677
+ console.log('[INFO] Documentation:');
678
+ console.log(' - Global Config: ~/.stigmergy/config.json');
679
+ console.log(' - Project Docs: ./STIGMERGY.md');
680
+ console.log(' - GitHub: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
681
+ console.log('');
682
+ console.log('[END] Happy collaborating with multiple AI CLI tools!');
683
+ }
684
+ }
685
+
686
+ // Main CLI functionality
687
+ async function main() {
688
+ const args = process.argv.slice(2);
689
+ const installer = new StigmergyInstaller();
690
+
691
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
692
+ console.log('Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System');
693
+ console.log('Version: 1.0.78');
694
+ console.log('');
695
+ console.log('[SYSTEM] Automated Installation and Deployment System');
696
+ console.log('');
697
+ console.log('Usage: stigmergy [command] [options]');
698
+ console.log('');
699
+ console.log('Commands:');
700
+ console.log(' help, --help Show this help message');
701
+ console.log(' version, --version Show version information');
702
+ console.log(' status Check CLI tools status');
703
+ console.log(' scan Scan for available AI CLI tools');
704
+ console.log(' install Auto-install missing CLI tools');
705
+ console.log(' deploy Deploy hooks to installed tools');
706
+ console.log(' remove Remove all Stigmergy hooks from installed tools');
707
+ console.log(' setup Complete setup and configuration');
708
+ console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
709
+ console.log('');
710
+ console.log('[WORKFLOW] Automated Workflow:');
711
+ console.log(' 1. npm install -g stigmergy # Install Stigmergy');
712
+ console.log(' 2. stigmergy install # Auto-scan & install CLI tools');
713
+ console.log(' 3. stigmergy setup # Deploy hooks & config');
714
+ console.log(' 4. stigmergy call <ai> <prompt> # Start collaborating');
715
+ console.log('');
716
+ console.log('For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
717
+ return;
718
+ }
719
+
720
+ if (args.includes('--version') || args.includes('version')) {
721
+ console.log('1.0.77');
722
+ return;
723
+ }
724
+
725
+ // Auto-install mode for postinstall script
726
+ if (args.includes('auto-install')) {
727
+ console.log('[AUTO-INSTALL] Stigmergy CLI - Automated Installation and Deployment');
728
+ console.log('Multi-AI CLI Tools Collaboration System v1.0.77');
729
+ console.log('='.repeat(60));
730
+
731
+ const originalPrompt = installer.promptForInstallation;
732
+ installer.promptForInstallation = async () => {
733
+ console.log('[AUTO-INSTALL] Skipping interactive CLI installation in postinstall mode');
734
+ console.log('[AUTO-INSTALL] You can run "stigmergy" manually to install CLI tools interactively');
735
+ return [];
736
+ };
737
+
738
+ console.log('\n[STEP 1] Scanning for AI CLI tools...');
739
+ const scanResults = await installer.scanAvailableTools();
740
+
741
+ console.log('\n[STEP 2] Deploying Stigmergy hooks...');
742
+ await installer.deployHooks(scanResults.available);
743
+
744
+ console.log('\n[STEP 3] Setting up configuration...');
745
+ await installer.setupGlobalConfiguration(scanResults.available);
746
+
747
+ console.log('\n[AUTO-INSTALL] Stigmergy automated setup completed!');
748
+ console.log('[AUTO-INSTALL] Run "stigmergy" to start interactive CLI tool installation');
749
+ return;
750
+ }
751
+
752
+ // Define valid commands
753
+ const validCommands = ['help', '--help', '-h', 'version', '--version', 'status', 'scan', 'install', 'deploy', 'remove', 'setup', 'auto-install', 'call'];
754
+
755
+ // Handle remove command
756
+ if (args[0] === 'remove') {
757
+ console.log('[REMOVE] Removing Stigmergy hooks from all installed CLI tools...');
758
+ await installer.removeHooks();
759
+ return;
760
+ }
761
+
762
+ // Handle call command
763
+ if (args[0] === 'call') {
764
+ return await handleCallCommand(args.slice(1));
765
+ }
766
+
767
+ // Check for invalid commands
768
+ const hasValidCommand = args.some(arg => validCommands.includes(arg));
769
+ if (!hasValidCommand && args.length > 0) {
770
+ console.log('[ERROR] Invalid command:', args[0]);
771
+ console.log('');
772
+ console.log('Usage: stigmergy [command] [options]');
773
+ console.log('');
774
+ console.log('Available commands:');
775
+ console.log(' help, --help Show this help message');
776
+ console.log(' version, --version Show version information');
777
+ console.log(' status Check CLI tools status');
778
+ console.log(' scan Scan for available AI CLI tools');
779
+ console.log(' install Auto-install missing CLI tools');
780
+ console.log(' deploy Deploy hooks to installed tools');
781
+ console.log(' setup Complete setup and configuration');
782
+ console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
783
+ console.log(' call <tool> Execute prompt with specified or auto-routed AI CLI');
784
+ console.log('');
785
+ console.log('Run "stigmergy --help" for more information.');
786
+ process.exit(1);
787
+ }
788
+
789
+ // Start automated installation and deployment
790
+ console.log('[START] Stigmergy CLI - Automated Installation and Deployment');
791
+ console.log('Multi-AI CLI Tools Collaboration System v1.0.77');
792
+ console.log('='.repeat(60));
793
+
794
+ console.log('\n[STEP 1] Scanning for AI CLI tools...');
795
+ const scanResults = await installer.scanAvailableTools();
796
+
797
+ if (scanResults.unavailable.length > 0) {
798
+ console.log('\n[STEP 2] CLI Tool Installation');
799
+ const selectedTools = await installer.promptForInstallation(scanResults);
800
+ await installer.installTools(selectedTools);
801
+
802
+ if (selectedTools.length > 0) {
803
+ console.log('\n[RESCAN] Re-scanning after installation...');
804
+ scanResults.available = scanResults.available.concat(selectedTools.filter(tool => installer.checkCLI(tool)));
805
+ scanResults.unavailable = scanResults.unavailable.filter(tool => !selectedTools.includes(tool));
806
+ }
807
+ } else {
808
+ console.log('\n[STEP 2] All CLI tools already available!');
809
+ }
810
+
811
+ console.log('\n[STEP 3] Deploying Stigmergy hooks...');
812
+ await installer.deployHooks(scanResults.available);
813
+
814
+ console.log('\n[STEP 4] Setting up configuration...');
815
+ await installer.setupGlobalConfiguration(scanResults.available);
816
+
817
+ await installer.showUsageInstructions();
818
+ }
819
+
820
+ // Memory Management System
821
+ class MemoryManager {
822
+ constructor(stigmergyDir) {
823
+ this.memoryDir = path.join(stigmergyDir, 'memory');
824
+ this.globalMemoryFile = path.join(this.memoryDir, 'global.json');
825
+ this.projectMemoryFile = path.join(process.cwd(), '.stigmergy-memory.json');
826
+ }
827
+
828
+ async ensureDirectory() {
829
+ await fs.mkdir(this.memoryDir, { recursive: true });
830
+ }
831
+
832
+ async saveGlobalMemory(data) {
833
+ await this.ensureDirectory();
834
+ await fs.writeFile(this.globalMemoryFile, JSON.stringify({
835
+ lastUpdated: new Date().toISOString(),
836
+ ...data
837
+ }, null, 2));
838
+ }
839
+
840
+ async loadGlobalMemory() {
841
+ try {
842
+ await this.ensureDirectory();
843
+ const data = await fs.readFile(this.globalMemoryFile, 'utf8');
844
+ return JSON.parse(data);
845
+ } catch (error) {
846
+ return {};
847
+ }
848
+ }
849
+
850
+ async saveProjectMemory(data) {
851
+ const memory = await this.loadProjectMemory();
852
+ await fs.writeFile(this.projectMemoryFile, JSON.stringify({
853
+ ...memory,
854
+ lastUpdated: new Date().toISOString(),
855
+ ...data
856
+ }, null, 2));
857
+ }
858
+
859
+ async loadProjectMemory() {
860
+ try {
861
+ const data = await fs.readFile(this.projectMemoryFile, 'utf8');
862
+ return JSON.parse(data);
863
+ } catch (error) {
864
+ return {
865
+ projectName: path.basename(process.cwd()),
866
+ createdAt: new Date().toISOString(),
867
+ interactions: []
868
+ };
869
+ }
870
+ }
871
+
872
+ async addInteraction(tool, prompt, response) {
873
+ const interaction = {
874
+ timestamp: new Date().toISOString(),
875
+ tool,
876
+ prompt,
877
+ response,
878
+ duration: Date.now() - new Date().getTime()
879
+ };
880
+
881
+ await this.saveProjectMemory({
882
+ lastInteraction: interaction,
883
+ interactions: (await this.loadProjectMemory()).interactions.concat(interaction).slice(-100) // Keep last 100
884
+ });
885
+ }
886
+ }
887
+
888
+ // Call Command Handler
889
+ async function handleCallCommand(args) {
890
+ const router = new SmartRouter();
891
+ const memoryManager = new MemoryManager(path.join(os.homedir(), '.stigmergy'));
892
+
893
+ if (args.length === 0) {
894
+ console.log('[ERROR] Call command requires a tool name and/or prompt');
895
+ console.log('');
896
+ console.log('Usage: stigmergy call <tool> <prompt>');
897
+ console.log(' stigmergy call <prompt> (auto-route to best tool)');
898
+ console.log('');
899
+ console.log('Available tools:', Object.keys(CLI_TOOLS).join(', '));
900
+ return;
901
+ }
902
+
903
+ let toolName, prompt;
904
+
905
+ // Check if first argument is a valid tool
906
+ if (CLI_TOOLS[args[0]]) {
907
+ toolName = args[0];
908
+ prompt = args.slice(1).join(' ');
909
+ } else {
910
+ // Auto-route based on keywords
911
+ const routeResult = router.smartRoute(args.join(' '));
912
+ toolName = routeResult.tool;
913
+ prompt = routeResult.prompt || args.join(' ');
914
+ }
915
+
916
+ if (!prompt) {
917
+ console.log('[ERROR] Prompt is required');
918
+ return;
919
+ }
920
+
921
+ console.log(`[CALL] Routing to: ${CLI_TOOLS[toolName].name}`);
922
+ console.log(`[PROMPT] ${prompt}`);
923
+ console.log('='.repeat(60));
924
+
925
+ const result = await router.executeTool(toolName, prompt);
926
+
927
+ if (result.success) {
928
+ console.log('[SUCCESS] Execution completed');
929
+ if (result.output) {
930
+ console.log('[OUTPUT]');
931
+ console.log(result.output);
932
+ }
933
+
934
+ // Save to memory
935
+ await memoryManager.addInteraction(toolName, prompt, result.output || 'Success');
936
+ console.log(`[MEMORY] Interaction saved to project memory`);
937
+ } else {
938
+ console.log('[ERROR] Execution failed');
939
+ if (result.error) {
940
+ console.log('[ERROR]', result.error);
941
+ }
942
+
943
+ // Save failed interaction to memory
944
+ await memoryManager.addInteraction(toolName, prompt, result.error || 'Failed');
945
+ }
946
+
947
+ console.log('');
948
+ console.log('[INFO] For help with CLI usage: stigmergy help');
949
+ }
950
+
951
+ // Setup stdin for interactive prompts
952
+ if (require.main === module) {
953
+ if (process.stdin.isTTY) {
954
+ process.stdin.resume();
955
+ process.stdin.setEncoding('utf8');
956
+ }
957
+
958
+ main().catch(error => {
959
+ console.error('[ERROR] Error:', error.message);
960
+ process.exit(1);
961
+ });
962
+ }
963
+
893
964
  module.exports = { main, StigmergyInstaller, CLI_TOOLS, SmartRouter, MemoryManager };