stigmergy 1.0.95 → 1.0.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/bin/stigmergy +11 -0
- package/docs/http-request-handler.md +289 -0
- package/docs/json-parser.md +102 -0
- package/docs/rest_client.md +144 -0
- package/examples/encryption-example.js +67 -0
- package/examples/json-parser-example.js +120 -0
- package/examples/rest_client_example.js +54 -0
- package/package.json +6 -5
- package/src/auth.js +19 -17
- package/src/auth_command.js +47 -34
- package/src/calculator.js +96 -3
- package/src/core/cli_help_analyzer.js +615 -567
- package/src/core/cli_parameter_handler.js +109 -103
- package/src/core/cli_tools.js +73 -73
- package/src/core/error_handler.js +136 -37
- package/src/core/memory_manager.js +67 -60
- package/src/core/rest_client.js +160 -0
- package/src/core/smart_router.js +127 -114
- package/src/data_encryption.js +143 -0
- package/src/data_structures.js +440 -0
- package/src/deploy.js +34 -28
- package/src/index.js +9 -9
- package/src/main.js +877 -740
- package/src/main_english.js +1275 -875
- package/src/utils.js +441 -54
- package/src/weatherProcessor.js +51 -28
- package/test/encryption-simple-test.js +110 -0
- package/test/encryption.test.js +129 -0
- package/test/hash_table_test.js +114 -0
- package/test/json-parser-test.js +161 -0
- package/test/rest_client.test.js +85 -0
- package/src/main_fixed.js +0 -1035
package/src/main_english.js
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* Version: 1.0.94
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
if (process.env.DEBUG === 'true') {
|
|
10
|
+
console.log('[DEBUG] Stigmergy CLI script started...');
|
|
11
|
+
}
|
|
10
12
|
|
|
11
13
|
const { spawn, spawnSync } = require('child_process');
|
|
12
14
|
const path = require('path');
|
|
@@ -22,515 +24,617 @@ const SmartRouter = require('./core/smart_router');
|
|
|
22
24
|
const CLIHelpAnalyzer = require('./core/cli_help_analyzer');
|
|
23
25
|
const { CLI_TOOLS } = require('./core/cli_tools');
|
|
24
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();
|
|
25
40
|
|
|
26
41
|
class MemoryManager {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
+
};
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
try {
|
|
61
|
+
// Add to global memory
|
|
62
|
+
await this.saveGlobalMemory(interaction);
|
|
44
63
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
);
|
|
50
72
|
}
|
|
73
|
+
}
|
|
51
74
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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}`);
|
|
64
93
|
}
|
|
94
|
+
}
|
|
65
95
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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}`);
|
|
77
113
|
}
|
|
114
|
+
}
|
|
78
115
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
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
|
+
};
|
|
90
126
|
}
|
|
127
|
+
}
|
|
91
128
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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`;
|
|
103
154
|
}
|
|
104
155
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
+
});
|
|
110
162
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
+
}
|
|
174
|
+
}
|
|
118
175
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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,
|
|
124
205
|
});
|
|
125
206
|
|
|
126
|
-
|
|
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
|
+
}
|
|
127
219
|
}
|
|
128
220
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async scanCLI() {
|
|
225
|
+
console.log('[SCAN] Scanning for AI CLI tools...');
|
|
226
|
+
const available = {};
|
|
227
|
+
const missing = {};
|
|
228
|
+
|
|
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
|
+
}
|
|
136
252
|
}
|
|
137
|
-
}
|
|
138
253
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.router = new SmartRouter();
|
|
142
|
-
this.memory = new MemoryManager();
|
|
143
|
-
this.configDir = path.join(os.homedir(), '.stigmergy');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async checkCLI(toolName) {
|
|
147
|
-
const tool = this.router.tools[toolName];
|
|
148
|
-
if (!tool) return false;
|
|
149
|
-
|
|
150
|
-
// Try multiple ways to check if CLI is available
|
|
151
|
-
const checks = [
|
|
152
|
-
// Method 1: Try version command
|
|
153
|
-
{ args: ['--version'], expected: 0 },
|
|
154
|
-
// Method 2: Try help command
|
|
155
|
-
{ args: ['--help'], expected: 0 },
|
|
156
|
-
// Method 3: Try help command with -h
|
|
157
|
-
{ args: ['-h'], expected: 0 },
|
|
158
|
-
// Method 4: Try just the command (help case)
|
|
159
|
-
{ args: [], expected: 0 },
|
|
160
|
-
];
|
|
161
|
-
|
|
162
|
-
for (const check of checks) {
|
|
163
|
-
try {
|
|
164
|
-
const result = spawnSync(toolName, check.args, {
|
|
165
|
-
encoding: 'utf8',
|
|
166
|
-
timeout: 5000,
|
|
167
|
-
shell: true
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// Check if command executed successfully or at least didn't fail with "command not found"
|
|
171
|
-
if (result.status === check.expected ||
|
|
172
|
-
(result.status !== 127 && result.status !== 9009)) { // 127 = command not found on Unix, 9009 = command not found on Windows
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
} catch (error) {
|
|
176
|
-
// Continue to next check method
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
254
|
+
return { available, missing };
|
|
255
|
+
}
|
|
180
256
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
console.log('[SCAN] Scanning for AI CLI tools...');
|
|
186
|
-
const available = {};
|
|
187
|
-
const missing = {};
|
|
188
|
-
|
|
189
|
-
for (const [toolName, toolInfo] of Object.entries(this.router.tools)) {
|
|
190
|
-
try {
|
|
191
|
-
console.log(`[SCAN] Checking ${toolInfo.name}...`);
|
|
192
|
-
const isAvailable = await this.checkCLI(toolName);
|
|
193
|
-
|
|
194
|
-
if (isAvailable) {
|
|
195
|
-
console.log(`[OK] ${toolInfo.name} is available`);
|
|
196
|
-
available[toolName] = toolInfo;
|
|
197
|
-
} else {
|
|
198
|
-
console.log(`[MISSING] ${toolInfo.name} is not installed`);
|
|
199
|
-
missing[toolName] = toolInfo;
|
|
200
|
-
}
|
|
201
|
-
} catch (error) {
|
|
202
|
-
await errorHandler.logError(error, 'WARN', `StigmergyInstaller.scanCLI.${toolName}`);
|
|
203
|
-
console.log(`[ERROR] Failed to check ${toolInfo.name}: ${error.message}`);
|
|
204
|
-
missing[toolName] = toolInfo;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
257
|
+
async installTools(selectedTools, missingTools) {
|
|
258
|
+
console.log(
|
|
259
|
+
`\n[INSTALL] Installing ${selectedTools.length} AI CLI tools...`,
|
|
260
|
+
);
|
|
207
261
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
for (const toolName of selectedTools) {
|
|
215
|
-
const toolInfo = missingTools[toolName];
|
|
216
|
-
if (!toolInfo) {
|
|
217
|
-
console.log(`[SKIP] Tool ${toolName} not found in missing tools list`);
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
console.log(`\n[INSTALL] Installing ${toolInfo.name}...`);
|
|
223
|
-
console.log(`[CMD] ${toolInfo.install}`);
|
|
224
|
-
|
|
225
|
-
const result = spawnSync(toolInfo.install, {
|
|
226
|
-
shell: true,
|
|
227
|
-
stdio: 'inherit'
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
if (result.status === 0) {
|
|
231
|
-
console.log(`[OK] ${toolInfo.name} installed successfully`);
|
|
232
|
-
} else {
|
|
233
|
-
console.log(`[ERROR] Failed to install ${toolInfo.name} (exit code: ${result.status})`);
|
|
234
|
-
if (result.error) {
|
|
235
|
-
console.log(`[ERROR] Installation error: ${result.error.message}`);
|
|
236
|
-
}
|
|
237
|
-
console.log(`[INFO] Please run manually: ${toolInfo.install}`);
|
|
238
|
-
}
|
|
239
|
-
} catch (error) {
|
|
240
|
-
await errorHandler.logError(error, 'ERROR', `StigmergyInstaller.installTools.${toolName}`);
|
|
241
|
-
console.log(`[ERROR] Failed to install ${toolInfo.name}: ${error.message}`);
|
|
242
|
-
console.log(`[INFO] Please run manually: ${toolInfo.install}`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
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
|
+
}
|
|
245
268
|
|
|
246
|
-
|
|
247
|
-
|
|
269
|
+
try {
|
|
270
|
+
console.log(`\n[INSTALL] Installing ${toolInfo.name}...`);
|
|
271
|
+
console.log(`[CMD] ${toolInfo.install}`);
|
|
248
272
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
await this.safetyCheck();
|
|
254
|
-
|
|
255
|
-
try {
|
|
256
|
-
// Create local assets directory
|
|
257
|
-
const assetsDir = path.join(os.homedir(), '.stigmergy', 'assets');
|
|
258
|
-
await fs.mkdir(assetsDir, { recursive: true });
|
|
259
|
-
|
|
260
|
-
// Copy template files from package
|
|
261
|
-
const packageTemplatesDir = path.join(__dirname, '..', 'templates', 'project-docs');
|
|
262
|
-
const localTemplatesDir = path.join(assetsDir, 'templates');
|
|
263
|
-
|
|
264
|
-
if (await this.fileExists(packageTemplatesDir)) {
|
|
265
|
-
await fs.mkdir(localTemplatesDir, { recursive: true });
|
|
266
|
-
|
|
267
|
-
// Copy all template files
|
|
268
|
-
const templateFiles = await fs.readdir(packageTemplatesDir);
|
|
269
|
-
for (const file of templateFiles) {
|
|
270
|
-
const srcPath = path.join(packageTemplatesDir, file);
|
|
271
|
-
const dstPath = path.join(localTemplatesDir, file);
|
|
272
|
-
await fs.copyFile(srcPath, dstPath);
|
|
273
|
-
console.log(`[OK] Copied template: ${file}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Download/copy CLI adapters
|
|
278
|
-
const adaptersDir = path.join(__dirname, '..', 'src', 'adapters');
|
|
279
|
-
const localAdaptersDir = path.join(assetsDir, 'adapters');
|
|
280
|
-
|
|
281
|
-
if (await this.fileExists(adaptersDir)) {
|
|
282
|
-
await fs.mkdir(localAdaptersDir, { recursive: true });
|
|
283
|
-
|
|
284
|
-
// Copy all adapter directories
|
|
285
|
-
const adapterDirs = await fs.readdir(adaptersDir);
|
|
286
|
-
for (const dir of adapterDirs) {
|
|
287
|
-
// Skip non-directory items
|
|
288
|
-
const dirPath = path.join(adaptersDir, dir);
|
|
289
|
-
const stat = await fs.stat(dirPath);
|
|
290
|
-
if (!stat.isDirectory()) continue;
|
|
291
|
-
|
|
292
|
-
// Skip __pycache__ directories
|
|
293
|
-
if (dir === '__pycache__') continue;
|
|
294
|
-
|
|
295
|
-
const dstPath = path.join(localAdaptersDir, dir);
|
|
296
|
-
await this.copyDirectory(dirPath, dstPath);
|
|
297
|
-
console.log(`[OK] Copied adapter: ${dir}`);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
console.log('[OK] All required assets downloaded successfully');
|
|
302
|
-
return true;
|
|
303
|
-
|
|
304
|
-
} catch (error) {
|
|
305
|
-
await errorHandler.logError(error, 'ERROR', 'StigmergyInstaller.downloadRequiredAssets');
|
|
306
|
-
console.log(`[ERROR] Failed to download required assets: ${error.message}`);
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
273
|
+
const result = spawnSync(toolInfo.install, {
|
|
274
|
+
shell: true,
|
|
275
|
+
stdio: 'inherit',
|
|
276
|
+
});
|
|
310
277
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
'surge',
|
|
322
|
-
'now'
|
|
323
|
-
];
|
|
324
|
-
|
|
325
|
-
// Check for globally installed conflicting packages
|
|
326
|
-
try {
|
|
327
|
-
const result = spawnSync('npm', ['list', '-g', '--depth=0'], {
|
|
328
|
-
encoding: 'utf8',
|
|
329
|
-
timeout: 10000
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (result.status === 0) {
|
|
333
|
-
const installedPackages = result.stdout;
|
|
334
|
-
const conflicts = [];
|
|
335
|
-
|
|
336
|
-
for (const pkg of conflictingPackages) {
|
|
337
|
-
if (installedPackages.includes(pkg)) {
|
|
338
|
-
conflicts.push(pkg);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (conflicts.length > 0) {
|
|
343
|
-
console.log(`[WARN] Potential conflicting packages detected: ${conflicts.join(', ')}`);
|
|
344
|
-
console.log('[INFO] These packages may interfere with Stigmergy CLI functionality');
|
|
345
|
-
} else {
|
|
346
|
-
console.log('[OK] No conflicting packages detected');
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
} catch (error) {
|
|
350
|
-
console.log(`[WARN] Unable to perform safety check: ${error.message}`);
|
|
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}`);
|
|
351
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
|
+
}
|
|
352
300
|
}
|
|
353
301
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
await fs.mkdir(dest, { recursive: true });
|
|
357
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
358
|
-
|
|
359
|
-
for (const entry of entries) {
|
|
360
|
-
const srcPath = path.join(src, entry.name);
|
|
361
|
-
const destPath = path.join(dest, entry.name);
|
|
362
|
-
|
|
363
|
-
if (entry.isDirectory()) {
|
|
364
|
-
// Skip __pycache__ directories
|
|
365
|
-
if (entry.name === '__pycache__') continue;
|
|
366
|
-
await this.copyDirectory(srcPath, destPath);
|
|
367
|
-
} else {
|
|
368
|
-
await fs.copyFile(srcPath, destPath);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
} catch (error) {
|
|
372
|
-
await errorHandler.logError(error, 'WARN', 'StigmergyInstaller.copyDirectory');
|
|
373
|
-
console.log(`[WARN] Failed to copy directory ${src} to ${dest}: ${error.message}`);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
376
304
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
await fs.access(filePath);
|
|
380
|
-
return true;
|
|
381
|
-
} catch {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
305
|
+
async downloadRequiredAssets() {
|
|
306
|
+
console.log('\n[DOWNLOAD] Downloading required assets and plugins...');
|
|
385
307
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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}`);
|
|
390
335
|
}
|
|
336
|
+
}
|
|
391
337
|
|
|
392
|
-
|
|
393
|
-
|
|
338
|
+
// Download/copy CLI adapters
|
|
339
|
+
const adaptersDir = path.join(__dirname, '..', 'src', 'adapters');
|
|
340
|
+
const localAdaptersDir = path.join(assetsDir, 'adapters');
|
|
394
341
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
name: `${toolInfo.name} (${toolName}) - ${toolInfo.install}`,
|
|
398
|
-
value: toolName,
|
|
399
|
-
checked: true
|
|
400
|
-
});
|
|
401
|
-
}
|
|
342
|
+
if (await this.fileExists(adaptersDir)) {
|
|
343
|
+
await fs.mkdir(localAdaptersDir, { recursive: true });
|
|
402
344
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
]);
|
|
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;
|
|
412
352
|
|
|
413
|
-
|
|
414
|
-
|
|
353
|
+
// Skip __pycache__ directories
|
|
354
|
+
if (dir === '__pycache__') continue;
|
|
415
355
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
356
|
+
const dstPath = path.join(localAdaptersDir, dir);
|
|
357
|
+
await this.copyDirectory(dirPath, dstPath);
|
|
358
|
+
console.log(`[OK] Copied adapter: ${dir}`);
|
|
419
359
|
}
|
|
360
|
+
}
|
|
420
361
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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;
|
|
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
|
+
}
|
|
432
408
|
}
|
|
433
409
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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');
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} catch (error) {
|
|
422
|
+
console.log(`[WARN] Unable to perform safety check: ${error.message}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
440
425
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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);
|
|
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
|
+
}
|
|
450
454
|
|
|
451
|
-
|
|
455
|
+
async fileExists(filePath) {
|
|
456
|
+
try {
|
|
457
|
+
await fs.access(filePath);
|
|
458
|
+
return true;
|
|
459
|
+
} catch {
|
|
460
|
+
return false;
|
|
452
461
|
}
|
|
462
|
+
}
|
|
453
463
|
|
|
454
|
-
|
|
455
|
-
|
|
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
|
+
}
|
|
456
469
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const configurer = new PostDeploymentConfigurer();
|
|
470
|
+
console.log('\n[INSTALL] Missing AI CLI tools detected:');
|
|
471
|
+
const choices = [];
|
|
460
472
|
|
|
461
|
-
|
|
462
|
-
|
|
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
|
+
});
|
|
479
|
+
}
|
|
463
480
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (await this.fileExists(assetsAdaptersDir)) {
|
|
483
|
-
await this.copyDirectory(assetsAdaptersDir, toolInfo.hooksDir);
|
|
484
|
-
console.log(`[OK] Copied adapter files for ${toolInfo.name}`);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Execute post-deployment configuration
|
|
488
|
-
try {
|
|
489
|
-
await configurer.configureTool(toolName);
|
|
490
|
-
console.log(`[OK] Post-deployment configuration completed for ${toolInfo.name}`);
|
|
491
|
-
successCount++;
|
|
492
|
-
} catch (configError) {
|
|
493
|
-
await errorHandler.logError(configError, 'WARN', `StigmergyInstaller.deployHooks.${toolName}.config`);
|
|
494
|
-
console.log(`[WARN] Post-deployment configuration failed for ${toolInfo.name}: ${configError.message}`);
|
|
495
|
-
// Continue with other tools even if one fails
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
} catch (error) {
|
|
499
|
-
await errorHandler.logError(error, 'ERROR', `StigmergyInstaller.deployHooks.${toolName}`);
|
|
500
|
-
console.log(`[ERROR] Failed to deploy hooks for ${toolInfo.name}: ${error.message}`);
|
|
501
|
-
console.log('[INFO] Continuing with other tools...');
|
|
502
|
-
}
|
|
503
|
-
}
|
|
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 [];
|
|
498
|
+
}
|
|
504
499
|
|
|
505
|
-
|
|
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;
|
|
506
511
|
}
|
|
507
512
|
|
|
508
|
-
|
|
509
|
-
|
|
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}`);
|
|
572
|
+
}
|
|
510
573
|
|
|
574
|
+
// Execute post-deployment configuration
|
|
511
575
|
try {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
} catch (error) {
|
|
528
|
-
console.log(`[ERROR] Failed to deploy project documentation: ${error.message}`);
|
|
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
|
|
529
591
|
}
|
|
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
|
+
}
|
|
530
603
|
}
|
|
531
604
|
|
|
532
|
-
|
|
533
|
-
|
|
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}`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
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
|
|
534
638
|
|
|
535
639
|
## Project Information
|
|
536
640
|
- **Project Name**: ${path.basename(process.cwd())}
|
|
@@ -550,10 +654,10 @@ No collaboration history yet.
|
|
|
550
654
|
*This file is automatically managed by Stigmergy CLI*
|
|
551
655
|
*Last updated: ${new Date().toISOString()}*
|
|
552
656
|
`;
|
|
553
|
-
|
|
657
|
+
}
|
|
554
658
|
|
|
555
|
-
|
|
556
|
-
|
|
659
|
+
generateProjectReadme() {
|
|
660
|
+
return `# ${path.basename(process.cwd())}
|
|
557
661
|
|
|
558
662
|
This project uses Stigmergy CLI for AI-assisted development.
|
|
559
663
|
|
|
@@ -574,448 +678,744 @@ See [STIGMERGY.md](STIGMERGY.md) for interaction history and collaboration recor
|
|
|
574
678
|
---
|
|
575
679
|
*Generated by Stigmergy CLI*
|
|
576
680
|
`;
|
|
577
|
-
|
|
681
|
+
}
|
|
578
682
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
try {
|
|
583
|
-
// Create config directory
|
|
584
|
-
const configDir = path.join(os.homedir(), '.stigmergy');
|
|
585
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
586
|
-
|
|
587
|
-
// Create initial configuration
|
|
588
|
-
const config = {
|
|
589
|
-
version: '1.0.94',
|
|
590
|
-
initialized: true,
|
|
591
|
-
createdAt: new Date().toISOString(),
|
|
592
|
-
lastUpdated: new Date().toISOString(),
|
|
593
|
-
defaultCLI: 'claude',
|
|
594
|
-
enableCrossCLI: true,
|
|
595
|
-
enableMemory: true,
|
|
596
|
-
tools: {}
|
|
597
|
-
};
|
|
598
|
-
|
|
599
|
-
// Save configuration
|
|
600
|
-
const configPath = path.join(configDir, 'config.json');
|
|
601
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
602
|
-
|
|
603
|
-
console.log('[OK] Configuration initialized successfully');
|
|
604
|
-
} catch (error) {
|
|
605
|
-
console.log(`[ERROR] Failed to initialize configuration: ${error.message}`);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
683
|
+
async initializeConfig() {
|
|
684
|
+
console.log('\n[CONFIG] Initializing Stigmergy configuration...');
|
|
608
685
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
+
);
|
|
626
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
|
+
}
|
|
627
739
|
}
|
|
628
740
|
|
|
629
741
|
// Main CLI functionality
|
|
630
742
|
async function main() {
|
|
743
|
+
if (process.env.DEBUG === 'true') {
|
|
631
744
|
console.log('[DEBUG] Main function called with args:', process.argv);
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
745
|
+
}
|
|
746
|
+
const args = process.argv.slice(2);
|
|
747
|
+
const installer = new StigmergyInstaller();
|
|
748
|
+
|
|
749
|
+
// Handle case when no arguments are provided
|
|
750
|
+
if (args.length === 0) {
|
|
751
|
+
console.log(
|
|
752
|
+
'Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System',
|
|
753
|
+
);
|
|
754
|
+
console.log('Version: 1.0.94');
|
|
755
|
+
console.log('');
|
|
756
|
+
console.log('[SYSTEM] Automated Installation and Deployment System');
|
|
757
|
+
console.log('');
|
|
758
|
+
console.log('Usage: stigmergy [command] [options]');
|
|
759
|
+
console.log('');
|
|
760
|
+
console.log('Commands:');
|
|
761
|
+
console.log(' help, --help Show this help message');
|
|
762
|
+
console.log(' version, --version Show version information');
|
|
763
|
+
console.log(' status Check CLI tools status');
|
|
764
|
+
console.log(' scan Scan for available AI CLI tools');
|
|
765
|
+
console.log(' install Auto-install missing CLI tools');
|
|
766
|
+
console.log(
|
|
767
|
+
' deploy Deploy hooks and integration to installed tools',
|
|
768
|
+
);
|
|
769
|
+
console.log(' setup Complete setup and configuration');
|
|
770
|
+
console.log(
|
|
771
|
+
' init Initialize Stigmergy configuration (alias for setup)',
|
|
772
|
+
);
|
|
773
|
+
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
774
|
+
console.log(' errors Display error report and statistics');
|
|
775
|
+
console.log(
|
|
776
|
+
' register <username> <password> Register a new user account',
|
|
777
|
+
);
|
|
778
|
+
console.log(' login <username> <password> Log in to your account');
|
|
779
|
+
console.log(' logout Log out of your account');
|
|
780
|
+
console.log(
|
|
781
|
+
' auth-status Check authentication status',
|
|
782
|
+
);
|
|
783
|
+
console.log('');
|
|
784
|
+
console.log('Authentication Commands:');
|
|
785
|
+
console.log(
|
|
786
|
+
' Register a new account: stigmergy register <username> <password>',
|
|
787
|
+
);
|
|
788
|
+
console.log(
|
|
789
|
+
' Log in to your account: stigmergy login <username> <password>',
|
|
790
|
+
);
|
|
791
|
+
console.log(' Check auth status: stigmergy auth-status');
|
|
792
|
+
console.log(' Log out of your account: stigmergy logout');
|
|
793
|
+
console.log('');
|
|
794
|
+
console.log('[WORKFLOW] Automated Workflow:');
|
|
795
|
+
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
796
|
+
console.log(
|
|
797
|
+
' 2. stigmergy install # Auto-scan & install CLI tools',
|
|
798
|
+
);
|
|
799
|
+
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
800
|
+
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
801
|
+
console.log('');
|
|
802
|
+
console.log('[INFO] For first-time setup, run: stigmergy setup');
|
|
803
|
+
console.log(
|
|
804
|
+
'[INFO] To scan and install AI tools, run: stigmergy install',
|
|
805
|
+
);
|
|
806
|
+
console.log('');
|
|
807
|
+
console.log(
|
|
808
|
+
'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
|
|
809
|
+
);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Handle help commands
|
|
814
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
815
|
+
console.log(
|
|
816
|
+
'Stigmergy CLI - Multi-Agents Cross-AI CLI Tools Collaboration System',
|
|
817
|
+
);
|
|
818
|
+
console.log('Version: 1.0.94');
|
|
819
|
+
console.log('');
|
|
820
|
+
console.log('[SYSTEM] Automated Installation and Deployment System');
|
|
821
|
+
console.log('');
|
|
822
|
+
console.log('Usage: stigmergy [command] [options]');
|
|
823
|
+
console.log('');
|
|
824
|
+
console.log('Commands:');
|
|
825
|
+
console.log(' help, --help Show this help message');
|
|
826
|
+
console.log(' version, --version Show version information');
|
|
827
|
+
console.log(' status Check CLI tools status');
|
|
828
|
+
console.log(' scan Scan for available AI CLI tools');
|
|
829
|
+
console.log(' install Auto-install missing CLI tools');
|
|
830
|
+
console.log(
|
|
831
|
+
' deploy Deploy hooks and integration to installed tools',
|
|
832
|
+
);
|
|
833
|
+
console.log(' setup Complete setup and configuration');
|
|
834
|
+
console.log(
|
|
835
|
+
' init Initialize Stigmergy configuration (alias for setup)',
|
|
836
|
+
);
|
|
837
|
+
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
838
|
+
console.log(' errors Display error report and statistics');
|
|
839
|
+
console.log(
|
|
840
|
+
' register <username> <password> Register a new user account',
|
|
841
|
+
);
|
|
842
|
+
console.log(' login <username> <password> Log in to your account');
|
|
843
|
+
console.log(' logout Log out of your account');
|
|
844
|
+
console.log(
|
|
845
|
+
' auth-status Check authentication status',
|
|
846
|
+
);
|
|
847
|
+
console.log('');
|
|
848
|
+
console.log('Authentication Commands:');
|
|
849
|
+
console.log(
|
|
850
|
+
' Register a new account: stigmergy register <username> <password>',
|
|
851
|
+
);
|
|
852
|
+
console.log(
|
|
853
|
+
' Log in to your account: stigmergy login <username> <password>',
|
|
854
|
+
);
|
|
855
|
+
console.log(' Check auth status: stigmergy auth-status');
|
|
856
|
+
console.log(' Log out of your account: stigmergy logout');
|
|
857
|
+
console.log('');
|
|
858
|
+
console.log('[WORKFLOW] Automated Workflow:');
|
|
859
|
+
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
860
|
+
console.log(
|
|
861
|
+
' 2. stigmergy install # Auto-scan & install CLI tools',
|
|
862
|
+
);
|
|
863
|
+
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
864
|
+
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
865
|
+
console.log('');
|
|
866
|
+
console.log(
|
|
867
|
+
'For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents',
|
|
868
|
+
);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const command = args[0];
|
|
873
|
+
|
|
874
|
+
// Define protected commands that require authentication
|
|
875
|
+
const protectedCommands = ['call', 'setup', 'deploy', 'install'];
|
|
876
|
+
|
|
877
|
+
// Check if command requires authentication
|
|
878
|
+
if (
|
|
879
|
+
protectedCommands.includes(command) &&
|
|
880
|
+
command !== 'version' &&
|
|
881
|
+
command !== '--version'
|
|
882
|
+
) {
|
|
883
|
+
if (!isAuthenticated()) {
|
|
884
|
+
console.log('[ERROR] Authentication required. Please log in first.');
|
|
885
|
+
console.log(
|
|
886
|
+
'[INFO] Run "stigmergy login <username> <password>" to log in.',
|
|
887
|
+
);
|
|
888
|
+
process.exit(1);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
switch (command) {
|
|
893
|
+
case 'version':
|
|
894
|
+
case '--version': {
|
|
895
|
+
// Use the version from configuration instead of hardcoding
|
|
896
|
+
const config = {
|
|
897
|
+
version: '1.0.94',
|
|
898
|
+
initialized: true,
|
|
899
|
+
createdAt: new Date().toISOString(),
|
|
900
|
+
lastUpdated: new Date().toISOString(),
|
|
901
|
+
defaultCLI: 'claude',
|
|
902
|
+
enableCrossCLI: true,
|
|
903
|
+
enableMemory: true,
|
|
904
|
+
};
|
|
905
|
+
console.log(`Stigmergy CLI v${config.version}`);
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
|
|
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);
|
|
919
|
+
}
|
|
920
|
+
break;
|
|
921
|
+
|
|
922
|
+
case 'init':
|
|
923
|
+
// Alias for setup command
|
|
924
|
+
console.log('[INIT] Initializing Stigmergy CLI...');
|
|
925
|
+
// Fall through to setup case
|
|
926
|
+
|
|
927
|
+
case 'setup':
|
|
928
|
+
try {
|
|
929
|
+
console.log('[SETUP] Starting complete Stigmergy setup...\n');
|
|
930
|
+
|
|
931
|
+
// Step 1: Download required assets
|
|
932
|
+
await installer.downloadRequiredAssets();
|
|
933
|
+
|
|
934
|
+
// Step 2: Scan for CLI tools
|
|
935
|
+
const { available: setupAvailable, missing: setupMissing } =
|
|
936
|
+
await installer.scanCLI();
|
|
937
|
+
const setupOptions = await installer.showInstallOptions(setupMissing);
|
|
938
|
+
|
|
939
|
+
// Step 3: Install missing CLI tools if user chooses
|
|
940
|
+
if (setupOptions.length > 0) {
|
|
941
|
+
const selectedTools = await installer.getUserSelection(
|
|
942
|
+
setupOptions,
|
|
943
|
+
setupMissing,
|
|
944
|
+
);
|
|
945
|
+
if (selectedTools.length > 0) {
|
|
946
|
+
console.log(
|
|
947
|
+
'\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...',
|
|
948
|
+
);
|
|
949
|
+
await installer.installTools(selectedTools, setupMissing);
|
|
950
|
+
}
|
|
951
|
+
} else {
|
|
952
|
+
console.log('\n[INFO] All required tools are already installed!');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Step 4: Deploy hooks to available CLI tools
|
|
956
|
+
await installer.deployHooks(setupAvailable);
|
|
957
|
+
|
|
958
|
+
// Step 5: Deploy project documentation
|
|
959
|
+
await installer.deployProjectDocumentation();
|
|
960
|
+
|
|
961
|
+
// Step 6: Initialize configuration
|
|
962
|
+
await installer.initializeConfig();
|
|
963
|
+
|
|
964
|
+
// Step 7: Show usage instructions
|
|
965
|
+
installer.showUsageInstructions();
|
|
966
|
+
} catch (error) {
|
|
967
|
+
await errorHandler.logError(error, 'ERROR', 'main.setup');
|
|
968
|
+
console.log(`[ERROR] Setup failed: ${error.message}`);
|
|
969
|
+
console.log('\n[TROUBLESHOOTING] To manually complete setup:');
|
|
970
|
+
console.log('1. Run: stigmergy deploy # Deploy hooks manually');
|
|
971
|
+
console.log('2. Run: stigmergy setup # Try setup again');
|
|
972
|
+
process.exit(1);
|
|
973
|
+
}
|
|
974
|
+
break;
|
|
975
|
+
|
|
976
|
+
case 'status':
|
|
635
977
|
try {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
console.log('');
|
|
645
|
-
console.log('Commands:');
|
|
646
|
-
console.log(' help, --help Show this help message');
|
|
647
|
-
console.log(' version, --version Show version information');
|
|
648
|
-
console.log(' status Check CLI tools status');
|
|
649
|
-
console.log(' scan Scan for available AI CLI tools');
|
|
650
|
-
console.log(' install Auto-install missing CLI tools');
|
|
651
|
-
console.log(' deploy Deploy hooks and integration to installed tools');
|
|
652
|
-
console.log(' setup Complete setup and configuration');
|
|
653
|
-
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
654
|
-
console.log('');
|
|
655
|
-
console.log('[WORKFLOW] Automated Workflow:');
|
|
656
|
-
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
657
|
-
console.log(' 2. stigmergy install # Auto-scan & install CLI tools');
|
|
658
|
-
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
659
|
-
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
660
|
-
console.log('');
|
|
661
|
-
console.log('[INFO] For first-time setup, run: stigmergy setup');
|
|
662
|
-
console.log('[INFO] To scan and install AI tools, run: stigmergy install');
|
|
663
|
-
console.log('');
|
|
664
|
-
console.log('For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
|
|
665
|
-
return;
|
|
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})`);
|
|
666
986
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
console.log('');
|
|
675
|
-
console.log('Usage: stigmergy [command] [options]');
|
|
676
|
-
console.log('');
|
|
677
|
-
console.log('Commands:');
|
|
678
|
-
console.log(' help, --help Show this help message');
|
|
679
|
-
console.log(' version, --version Show version information');
|
|
680
|
-
console.log(' status Check CLI tools status');
|
|
681
|
-
console.log(' scan Scan for available AI CLI tools');
|
|
682
|
-
console.log(' install Auto-install missing CLI tools');
|
|
683
|
-
console.log(' deploy Deploy hooks and integration to installed tools');
|
|
684
|
-
console.log(' setup Complete setup and configuration');
|
|
685
|
-
console.log(' call "<prompt>" Execute prompt with auto-routed AI CLI');
|
|
686
|
-
console.log('');
|
|
687
|
-
console.log('[WORKFLOW] Automated Workflow:');
|
|
688
|
-
console.log(' 1. npm install -g stigmergy # Install Stigmergy');
|
|
689
|
-
console.log(' 2. stigmergy install # Auto-scan & install CLI tools');
|
|
690
|
-
console.log(' 3. stigmergy setup # Deploy hooks & config');
|
|
691
|
-
console.log(' 4. stigmergy call "<prompt>" # Start collaborating');
|
|
692
|
-
console.log('');
|
|
693
|
-
console.log('For more information, visit: https://github.com/ptreezh/stigmergy-CLI-Multi-Agents');
|
|
694
|
-
return;
|
|
987
|
+
}
|
|
988
|
+
|
|
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}`);
|
|
695
994
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
console.log(`\n[SUMMARY] ${Object.keys(available).length} available, ${Object.keys(missing).length} missing`);
|
|
736
|
-
} catch (error) {
|
|
737
|
-
await errorHandler.logError(error, 'ERROR', 'main.status');
|
|
738
|
-
console.log(`[ERROR] Failed to get status: ${error.message}`);
|
|
739
|
-
process.exit(1);
|
|
740
|
-
}
|
|
741
|
-
break;
|
|
742
|
-
|
|
743
|
-
case 'scan':
|
|
744
|
-
try {
|
|
745
|
-
await installer.scanCLI();
|
|
746
|
-
} catch (error) {
|
|
747
|
-
await errorHandler.logError(error, 'ERROR', 'main.scan');
|
|
748
|
-
console.log(`[ERROR] Failed to scan CLI tools: ${error.message}`);
|
|
749
|
-
process.exit(1);
|
|
750
|
-
}
|
|
751
|
-
break;
|
|
752
|
-
|
|
753
|
-
case 'install':
|
|
754
|
-
try {
|
|
755
|
-
console.log('[INSTALL] Starting AI CLI tools installation...');
|
|
756
|
-
const { missing: missingTools } = await installer.scanCLI();
|
|
757
|
-
const options = await installer.showInstallOptions(missingTools);
|
|
758
|
-
|
|
759
|
-
if (options.length > 0) {
|
|
760
|
-
const selectedTools = await installer.getUserSelection(options, missingTools);
|
|
761
|
-
if (selectedTools.length > 0) {
|
|
762
|
-
console.log('\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...');
|
|
763
|
-
await installer.installTools(selectedTools, missingTools);
|
|
764
|
-
}
|
|
765
|
-
} else {
|
|
766
|
-
console.log('\n[INFO] All required tools are already installed!');
|
|
767
|
-
}
|
|
768
|
-
} catch (error) {
|
|
769
|
-
await errorHandler.logError(error, 'ERROR', 'main.install');
|
|
770
|
-
console.log(`[ERROR] Installation failed: ${error.message}`);
|
|
771
|
-
process.exit(1);
|
|
772
|
-
}
|
|
773
|
-
break;
|
|
774
|
-
|
|
775
|
-
case 'deploy':
|
|
776
|
-
try {
|
|
777
|
-
const { available: deployedTools } = await installer.scanCLI();
|
|
778
|
-
await installer.deployHooks(deployedTools);
|
|
779
|
-
} catch (error) {
|
|
780
|
-
await errorHandler.logError(error, 'ERROR', 'main.deploy');
|
|
781
|
-
console.log(`[ERROR] Deployment failed: ${error.message}`);
|
|
782
|
-
process.exit(1);
|
|
783
|
-
}
|
|
784
|
-
break;
|
|
785
|
-
|
|
786
|
-
case 'setup':
|
|
787
|
-
try {
|
|
788
|
-
console.log('[SETUP] Starting complete Stigmergy setup...\n');
|
|
789
|
-
|
|
790
|
-
// Step 1: Download required assets
|
|
791
|
-
await installer.downloadRequiredAssets();
|
|
792
|
-
|
|
793
|
-
// Step 2: Scan for CLI tools
|
|
794
|
-
const { available: setupAvailable, missing: setupMissing } = await installer.scanCLI();
|
|
795
|
-
const setupOptions = await installer.showInstallOptions(setupMissing);
|
|
796
|
-
|
|
797
|
-
// Step 3: Install missing CLI tools if user chooses
|
|
798
|
-
if (setupOptions.length > 0) {
|
|
799
|
-
const selectedTools = await installer.getUserSelection(setupOptions, setupMissing);
|
|
800
|
-
if (selectedTools.length > 0) {
|
|
801
|
-
console.log('\n[INFO] Installing selected tools (this may take several minutes for tools that download binaries)...');
|
|
802
|
-
await installer.installTools(selectedTools, setupMissing);
|
|
803
|
-
}
|
|
804
|
-
} else {
|
|
805
|
-
console.log('\n[INFO] All required tools are already installed!');
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Step 4: Deploy hooks to available CLI tools
|
|
809
|
-
await installer.deployHooks(setupAvailable);
|
|
810
|
-
|
|
811
|
-
// Step 5: Deploy project documentation
|
|
812
|
-
await installer.deployProjectDocumentation();
|
|
813
|
-
|
|
814
|
-
// Step 6: Initialize configuration
|
|
815
|
-
await installer.initializeConfig();
|
|
816
|
-
|
|
817
|
-
// Step 7: Show usage instructions
|
|
818
|
-
installer.showUsageInstructions();
|
|
819
|
-
} catch (error) {
|
|
820
|
-
await errorHandler.logError(error, 'ERROR', 'main.setup');
|
|
821
|
-
console.log(`[ERROR] Setup failed: ${error.message}`);
|
|
822
|
-
console.log('\n[TROUBLESHOOTING] To manually complete setup:');
|
|
823
|
-
console.log('1. Run: stigmergy deploy # Deploy hooks manually');
|
|
824
|
-
console.log('2. Run: stigmergy setup # Try setup again');
|
|
825
|
-
process.exit(1);
|
|
826
|
-
}
|
|
827
|
-
break;
|
|
828
|
-
|
|
829
|
-
case 'call':
|
|
830
|
-
if (args.length < 2) {
|
|
831
|
-
console.log('[ERROR] Usage: stigmergy call "<prompt>"');
|
|
832
|
-
process.exit(1);
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// Get the prompt (everything after the command)
|
|
836
|
-
const prompt = args.slice(1).join(' ');
|
|
837
|
-
|
|
838
|
-
// Use smart router to determine which tool to use
|
|
839
|
-
const router = new SmartRouter();
|
|
840
|
-
await router.initialize(); // Initialize the router first
|
|
841
|
-
const route = await router.smartRoute(prompt);
|
|
842
|
-
|
|
843
|
-
console.log(`[CALL] Routing to ${route.tool}: ${route.prompt}`);
|
|
844
|
-
|
|
845
|
-
// Execute the routed command
|
|
846
|
-
try {
|
|
847
|
-
// Get the actual executable path for the tool
|
|
848
|
-
const toolPath = route.tool;
|
|
849
|
-
console.log(`[DEBUG] Tool path: ${toolPath}, Prompt: ${route.prompt}`);
|
|
850
|
-
|
|
851
|
-
// For different tools, we need to pass the prompt differently
|
|
852
|
-
// Use unified parameter handler for better parameter handling
|
|
853
|
-
let toolArgs = [];
|
|
854
|
-
|
|
855
|
-
try {
|
|
856
|
-
// Get CLI pattern for this tool
|
|
857
|
-
const cliPattern = await router.analyzer.getCLIPattern(route.tool);
|
|
858
|
-
|
|
859
|
-
// Use the unified CLI parameter handler
|
|
860
|
-
const CLIParameterHandler = require('./core/cli_parameter_handler');
|
|
861
|
-
toolArgs = CLIParameterHandler.generateArguments(route.tool, route.prompt, cliPattern);
|
|
862
|
-
} catch (patternError) {
|
|
863
|
-
// Fallback to original logic if pattern analysis fails
|
|
864
|
-
if (route.tool === 'claude') {
|
|
865
|
-
// Claude CLI expects the prompt with -p flag for non-interactive mode
|
|
866
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
867
|
-
} else if (route.tool === 'qodercli' || route.tool === 'iflow') {
|
|
868
|
-
// Qoder CLI and iFlow expect the prompt with -p flag
|
|
869
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
870
|
-
} else if (route.tool === 'codex') {
|
|
871
|
-
// Codex CLI needs 'exec' subcommand for non-interactive mode
|
|
872
|
-
toolArgs = ['exec', '-p', `"${route.prompt}"`];
|
|
873
|
-
} else {
|
|
874
|
-
// For other tools, pass the prompt with -p flag
|
|
875
|
-
toolArgs = ['-p', `"${route.prompt}"`];
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// Use the correct way to spawn the process
|
|
880
|
-
const child = spawn(toolPath, toolArgs, {
|
|
881
|
-
stdio: 'inherit',
|
|
882
|
-
shell: true
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
child.on('close', (code) => {
|
|
886
|
-
if (code !== 0) {
|
|
887
|
-
console.log(`[WARN] ${route.tool} exited with code ${code}`);
|
|
888
|
-
}
|
|
889
|
-
process.exit(code);
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
child.on('error', async (error) => {
|
|
893
|
-
const cliError = await errorHandler.handleCLIError(route.tool, error, toolArgs.join(' '));
|
|
894
|
-
console.log(`[ERROR] Failed to execute ${route.tool}:`, cliError.message);
|
|
895
|
-
process.exit(1);
|
|
896
|
-
});
|
|
897
|
-
} catch (error) {
|
|
898
|
-
const cliError = await errorHandler.handleCLIError(route.tool, error, prompt);
|
|
899
|
-
console.log(`[ERROR] Failed to execute ${route.tool}:`, cliError.message);
|
|
900
|
-
process.exit(1);
|
|
901
|
-
}
|
|
902
|
-
break;
|
|
903
|
-
|
|
904
|
-
case 'auto-install':
|
|
905
|
-
// Auto-install mode for npm postinstall - NON-INTERACTIVE
|
|
906
|
-
console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
|
|
907
|
-
console.log('='.repeat(60));
|
|
908
|
-
|
|
909
|
-
try {
|
|
910
|
-
// Step 1: Download required assets
|
|
911
|
-
try {
|
|
912
|
-
console.log('[STEP] Downloading required assets...');
|
|
913
|
-
await installer.downloadRequiredAssets();
|
|
914
|
-
console.log('[OK] Assets downloaded successfully');
|
|
915
|
-
} catch (error) {
|
|
916
|
-
console.log(`[WARN] Failed to download assets: ${error.message}`);
|
|
917
|
-
console.log('[INFO] Continuing with installation...');
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// Step 2: Scan for CLI tools
|
|
921
|
-
let autoAvailable = {}, autoMissing = {};
|
|
922
|
-
try {
|
|
923
|
-
console.log('[STEP] Scanning for CLI tools...');
|
|
924
|
-
const scanResult = await installer.scanCLI();
|
|
925
|
-
autoAvailable = scanResult.available;
|
|
926
|
-
autoMissing = scanResult.missing;
|
|
927
|
-
console.log('[OK] CLI tools scanned successfully');
|
|
928
|
-
} catch (error) {
|
|
929
|
-
console.log(`[WARN] Failed to scan CLI tools: ${error.message}`);
|
|
930
|
-
console.log('[INFO] Continuing with installation...');
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// Step 3: Show summary to user after installation
|
|
934
|
-
try {
|
|
935
|
-
if (Object.keys(autoMissing).length > 0) {
|
|
936
|
-
console.log('\n[INFO] Found ' + Object.keys(autoMissing).length + ' missing AI CLI tools:');
|
|
937
|
-
for (const [toolName, toolInfo] of Object.entries(autoMissing)) {
|
|
938
|
-
console.log(` - ${toolInfo.name} (${toolName})`);
|
|
939
|
-
}
|
|
940
|
-
console.log('\n[INFO] Auto-install mode detected. Skipping automatic installation of missing tools.');
|
|
941
|
-
console.log('[INFO] For full functionality, please run "stigmergy install" after installation completes.');
|
|
942
|
-
} else {
|
|
943
|
-
console.log('\n[INFO] All AI CLI tools are already installed! No additional tools required.');
|
|
944
|
-
}
|
|
945
|
-
} catch (error) {
|
|
946
|
-
console.log(`[WARN] Failed to show tool summary: ${error.message}`);
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// Step 4: Deploy hooks to available CLI tools
|
|
950
|
-
try {
|
|
951
|
-
console.log('[STEP] Deploying hooks to available CLI tools...');
|
|
952
|
-
await installer.deployHooks(autoAvailable);
|
|
953
|
-
console.log('[OK] Hooks deployed successfully');
|
|
954
|
-
} catch (error) {
|
|
955
|
-
console.log(`[ERROR] Failed to deploy hooks: ${error.message}`);
|
|
956
|
-
console.log('[INFO] You can manually deploy hooks later by running: stigmergy deploy');
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
// Step 5: Deploy project documentation
|
|
960
|
-
try {
|
|
961
|
-
console.log('[STEP] Deploying project documentation...');
|
|
962
|
-
await installer.deployProjectDocumentation();
|
|
963
|
-
console.log('[OK] Documentation deployed successfully');
|
|
964
|
-
} catch (error) {
|
|
965
|
-
console.log(`[WARN] Failed to deploy documentation: ${error.message}`);
|
|
966
|
-
console.log('[INFO] Continuing with installation...');
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
// Step 6: Initialize configuration
|
|
970
|
-
try {
|
|
971
|
-
console.log('[STEP] Initializing configuration...');
|
|
972
|
-
await installer.initializeConfig();
|
|
973
|
-
console.log('[OK] Configuration initialized successfully');
|
|
974
|
-
} catch (error) {
|
|
975
|
-
console.log(`[ERROR] Failed to initialize configuration: ${error.message}`);
|
|
976
|
-
console.log('[INFO] You can manually initialize configuration later by running: stigmergy setup');
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
// Step 7: Show final message to guide users
|
|
980
|
-
console.log('\n[SUCCESS] Stigmergy CLI installed successfully!');
|
|
981
|
-
console.log('[USAGE] Run "stigmergy setup" to complete full configuration and install missing AI CLI tools.');
|
|
982
|
-
console.log('[USAGE] Run "stigmergy install" to install only missing AI CLI tools.');
|
|
983
|
-
console.log('[USAGE] Run "stigmergy --help" to see all available commands.');
|
|
984
|
-
} catch (fatalError) {
|
|
985
|
-
await errorHandler.logError(fatalError, 'ERROR', 'main.auto-install');
|
|
986
|
-
console.error('[FATAL] Auto-install process failed:', fatalError.message);
|
|
987
|
-
console.log('\n[TROUBLESHOOTING] To manually complete installation:');
|
|
988
|
-
console.log('1. Run: stigmergy setup # Complete setup');
|
|
989
|
-
console.log('2. Run: stigmergy install # Install missing tools');
|
|
990
|
-
console.log('3. Run: stigmergy deploy # Deploy hooks manually');
|
|
991
|
-
process.exit(1);
|
|
992
|
-
}
|
|
993
|
-
break;
|
|
994
|
-
|
|
995
|
-
default:
|
|
996
|
-
console.log(`[ERROR] Unknown command: ${command}`);
|
|
997
|
-
console.log('[INFO] Run "stigmergy --help" for usage information');
|
|
998
|
-
process.exit(1);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
console.log(
|
|
998
|
+
`\n[SUMMARY] ${Object.keys(available).length} available, ${Object.keys(missing).length} missing`,
|
|
999
|
+
);
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
await errorHandler.logError(error, 'ERROR', 'main.status');
|
|
1002
|
+
console.log(`[ERROR] Failed to get status: ${error.message}`);
|
|
1003
|
+
process.exit(1);
|
|
1004
|
+
}
|
|
1005
|
+
break;
|
|
1006
|
+
|
|
1007
|
+
case 'scan':
|
|
1008
|
+
try {
|
|
1009
|
+
await installer.scanCLI();
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
await errorHandler.logError(error, 'ERROR', 'main.scan');
|
|
1012
|
+
console.log(`[ERROR] Failed to scan CLI tools: ${error.message}`);
|
|
1013
|
+
process.exit(1);
|
|
1014
|
+
}
|
|
1015
|
+
break;
|
|
1016
|
+
|
|
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);
|
|
999
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);
|
|
1041
|
+
}
|
|
1042
|
+
break;
|
|
1043
|
+
|
|
1044
|
+
case 'deploy':
|
|
1045
|
+
try {
|
|
1046
|
+
const { available: deployedTools } = await installer.scanCLI();
|
|
1047
|
+
await installer.deployHooks(deployedTools);
|
|
1000
1048
|
} catch (error) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1049
|
+
await errorHandler.logError(error, 'ERROR', 'main.deploy');
|
|
1050
|
+
console.log(`[ERROR] Deployment failed: ${error.message}`);
|
|
1051
|
+
process.exit(1);
|
|
1052
|
+
}
|
|
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);
|
|
1061
|
+
}
|
|
1062
|
+
handleRegister(args[1], args[2]);
|
|
1063
|
+
break;
|
|
1064
|
+
|
|
1065
|
+
case 'login':
|
|
1066
|
+
if (args.length < 3) {
|
|
1067
|
+
console.log('[ERROR] Usage: stigmergy login <username> <password>');
|
|
1068
|
+
process.exit(1);
|
|
1069
|
+
}
|
|
1070
|
+
handleLogin(args[1], args[2]);
|
|
1071
|
+
break;
|
|
1072
|
+
|
|
1073
|
+
case 'logout':
|
|
1074
|
+
handleLogout();
|
|
1075
|
+
break;
|
|
1076
|
+
|
|
1077
|
+
case 'auth-status':
|
|
1078
|
+
handleStatus();
|
|
1079
|
+
break;
|
|
1080
|
+
|
|
1081
|
+
case 'call': {
|
|
1082
|
+
if (args.length < 2) {
|
|
1083
|
+
console.log('[ERROR] Usage: stigmergy call "<prompt>"');
|
|
1084
|
+
process.exit(1);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Get the prompt (everything after the command)
|
|
1088
|
+
const prompt = args.slice(1).join(' ');
|
|
1089
|
+
|
|
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);
|
|
1094
|
+
|
|
1095
|
+
console.log(`[CALL] Routing to ${route.tool}: ${route.prompt}`);
|
|
1096
|
+
|
|
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);
|
|
1170
|
+
} else {
|
|
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}`);
|
|
1200
|
+
}
|
|
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('==================================================');
|
|
1211
|
+
|
|
1003
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;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
case 'auto-install':
|
|
1230
|
+
// Auto-install mode for npm postinstall - NON-INTERACTIVE
|
|
1231
|
+
console.log('[AUTO-INSTALL] Stigmergy CLI automated setup');
|
|
1232
|
+
console.log('='.repeat(60));
|
|
1233
|
+
|
|
1234
|
+
try {
|
|
1235
|
+
// Step 1: Download required assets
|
|
1236
|
+
try {
|
|
1237
|
+
console.log('[STEP] Downloading required assets...');
|
|
1238
|
+
await installer.downloadRequiredAssets();
|
|
1239
|
+
console.log('[OK] Assets downloaded successfully');
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
console.log(`[WARN] Failed to download assets: ${error.message}`);
|
|
1242
|
+
console.log('[INFO] Continuing with installation...');
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// Step 2: Scan for CLI tools
|
|
1246
|
+
let autoAvailable = {},
|
|
1247
|
+
autoMissing = {};
|
|
1248
|
+
try {
|
|
1249
|
+
console.log('[STEP] Scanning for CLI tools...');
|
|
1250
|
+
const scanResult = await installer.scanCLI();
|
|
1251
|
+
autoAvailable = scanResult.available;
|
|
1252
|
+
autoMissing = scanResult.missing;
|
|
1253
|
+
console.log('[OK] CLI tools scanned successfully');
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
console.log(`[WARN] Failed to scan CLI tools: ${error.message}`);
|
|
1256
|
+
console.log('[INFO] Continuing with installation...');
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// Step 3: Show summary to user after installation
|
|
1260
|
+
try {
|
|
1261
|
+
if (Object.keys(autoMissing).length > 0) {
|
|
1262
|
+
console.log(
|
|
1263
|
+
'\n[INFO] Found ' +
|
|
1264
|
+
Object.keys(autoMissing).length +
|
|
1265
|
+
' missing AI CLI tools:',
|
|
1266
|
+
);
|
|
1267
|
+
for (const [toolName, toolInfo] of Object.entries(autoMissing)) {
|
|
1268
|
+
console.log(` - ${toolInfo.name} (${toolName})`);
|
|
1269
|
+
}
|
|
1270
|
+
console.log(
|
|
1271
|
+
'\n[INFO] Auto-install mode detected. Skipping automatic installation of missing tools.',
|
|
1272
|
+
);
|
|
1273
|
+
console.log(
|
|
1274
|
+
'[INFO] For full functionality, please run "stigmergy install" after installation completes.',
|
|
1275
|
+
);
|
|
1276
|
+
} else {
|
|
1277
|
+
console.log(
|
|
1278
|
+
'\n[INFO] All AI CLI tools are already installed! No additional tools required.',
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
} catch (error) {
|
|
1282
|
+
console.log(`[WARN] Failed to show tool summary: ${error.message}`);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// Step 4: Deploy hooks to available CLI tools
|
|
1286
|
+
try {
|
|
1287
|
+
console.log('[STEP] Deploying hooks to available CLI tools...');
|
|
1288
|
+
await installer.deployHooks(autoAvailable);
|
|
1289
|
+
console.log('[OK] Hooks deployed successfully');
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
console.log(`[ERROR] Failed to deploy hooks: ${error.message}`);
|
|
1292
|
+
console.log(
|
|
1293
|
+
'[INFO] You can manually deploy hooks later by running: stigmergy deploy',
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Step 5: Deploy project documentation
|
|
1298
|
+
try {
|
|
1299
|
+
console.log('[STEP] Deploying project documentation...');
|
|
1300
|
+
await installer.deployProjectDocumentation();
|
|
1301
|
+
console.log('[OK] Documentation deployed successfully');
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
console.log(
|
|
1304
|
+
`[WARN] Failed to deploy documentation: ${error.message}`,
|
|
1305
|
+
);
|
|
1306
|
+
console.log('[INFO] Continuing with installation...');
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
// Step 6: Initialize configuration
|
|
1310
|
+
try {
|
|
1311
|
+
console.log('[STEP] Initializing configuration...');
|
|
1312
|
+
await installer.initializeConfig();
|
|
1313
|
+
console.log('[OK] Configuration initialized successfully');
|
|
1314
|
+
} catch (error) {
|
|
1315
|
+
console.log(
|
|
1316
|
+
`[ERROR] Failed to initialize configuration: ${error.message}`,
|
|
1317
|
+
);
|
|
1318
|
+
console.log(
|
|
1319
|
+
'[INFO] You can manually initialize configuration later by running: stigmergy setup',
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Step 7: Show final message to guide users
|
|
1324
|
+
console.log('\n[SUCCESS] Stigmergy CLI installed successfully!');
|
|
1325
|
+
console.log(
|
|
1326
|
+
'[USAGE] Run "stigmergy setup" to complete full configuration and install missing AI CLI tools.',
|
|
1327
|
+
);
|
|
1328
|
+
console.log(
|
|
1329
|
+
'[USAGE] Run "stigmergy install" to install only missing AI CLI tools.',
|
|
1330
|
+
);
|
|
1331
|
+
console.log(
|
|
1332
|
+
'[USAGE] Run "stigmergy --help" to see all available commands.',
|
|
1333
|
+
);
|
|
1334
|
+
} catch (fatalError) {
|
|
1335
|
+
await errorHandler.logError(fatalError, 'ERROR', 'main.auto-install');
|
|
1336
|
+
console.error(
|
|
1337
|
+
'[FATAL] Auto-install process failed:',
|
|
1338
|
+
fatalError.message,
|
|
1339
|
+
);
|
|
1340
|
+
console.log('\n[TROUBLESHOOTING] To manually complete installation:');
|
|
1341
|
+
console.log('1. Run: stigmergy setup # Complete setup');
|
|
1342
|
+
console.log('2. Run: stigmergy install # Install missing tools');
|
|
1343
|
+
console.log('3. Run: stigmergy deploy # Deploy hooks manually');
|
|
1344
|
+
process.exit(1);
|
|
1004
1345
|
}
|
|
1346
|
+
break;
|
|
1347
|
+
|
|
1348
|
+
default:
|
|
1349
|
+
console.log(`[ERROR] Unknown command: ${command}`);
|
|
1350
|
+
console.log('[INFO] Run "stigmergy --help" for usage information');
|
|
1351
|
+
process.exit(1);
|
|
1352
|
+
}
|
|
1005
1353
|
}
|
|
1006
1354
|
|
|
1007
1355
|
// Function to find maximum of two numbers
|
|
1008
1356
|
function maxOfTwo(a, b) {
|
|
1009
|
-
|
|
1357
|
+
return a > b ? a : b;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Function to check if user is authenticated
|
|
1361
|
+
function isAuthenticated() {
|
|
1362
|
+
try {
|
|
1363
|
+
const authenticator = new UserAuthenticator();
|
|
1364
|
+
// Load authentication data
|
|
1365
|
+
const authFile = path.join(
|
|
1366
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
1367
|
+
'.stigmergy',
|
|
1368
|
+
'auth.json',
|
|
1369
|
+
);
|
|
1370
|
+
|
|
1371
|
+
if (!fsSync.existsSync(authFile)) {
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// Load the authentication data into the authenticator
|
|
1376
|
+
const data = JSON.parse(fsSync.readFileSync(authFile, 'utf8'));
|
|
1377
|
+
if (data.sessions) {
|
|
1378
|
+
for (const [token, sessionData] of Object.entries(data.sessions)) {
|
|
1379
|
+
authenticator._sessions.set(token, sessionData);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// Read the current session token
|
|
1384
|
+
const sessionFile = path.join(
|
|
1385
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
1386
|
+
'.stigmergy',
|
|
1387
|
+
'session.token',
|
|
1388
|
+
);
|
|
1389
|
+
|
|
1390
|
+
if (!fsSync.existsSync(sessionFile)) {
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
const token = fsSync.readFileSync(sessionFile, 'utf8').trim();
|
|
1395
|
+
const username = authenticator.validateSession(token);
|
|
1396
|
+
|
|
1397
|
+
return !!username;
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
return false;
|
|
1400
|
+
}
|
|
1010
1401
|
}
|
|
1011
1402
|
|
|
1012
1403
|
// Export for testing
|
|
1013
|
-
module.exports = {
|
|
1404
|
+
module.exports = {
|
|
1405
|
+
StigmergyInstaller,
|
|
1406
|
+
SmartRouter,
|
|
1407
|
+
MemoryManager,
|
|
1408
|
+
CLI_TOOLS,
|
|
1409
|
+
maxOfTwo,
|
|
1410
|
+
};
|
|
1014
1411
|
|
|
1015
1412
|
// Run main function
|
|
1016
1413
|
if (require.main === module) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1414
|
+
main().catch((error) => {
|
|
1415
|
+
console.error(
|
|
1416
|
+
'[FATAL] Stigmergy CLI encountered an unhandled error:',
|
|
1417
|
+
error,
|
|
1418
|
+
);
|
|
1419
|
+
process.exit(1);
|
|
1420
|
+
});
|
|
1021
1421
|
}
|