stigmergy 1.0.94 → 1.0.97

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