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.
- package/README.md +20 -0
- package/bin/stigmergy +37 -12
- package/docs/HASH_TABLE.md +83 -0
- package/docs/WEATHER_PROCESSOR_API.md +230 -0
- package/docs/best_practices.md +135 -0
- package/docs/development_guidelines.md +392 -0
- package/docs/http-request-handler.md +289 -0
- package/docs/json-parser.md +102 -0
- package/docs/requirements_specification.md +148 -0
- package/docs/rest_client.md +144 -0
- package/docs/system_design.md +314 -0
- package/docs/tdd_implementation_plan.md +384 -0
- package/docs/test_report.md +49 -0
- package/examples/calculator-example.js +72 -0
- package/examples/encryption-example.js +67 -0
- package/examples/json-parser-example.js +120 -0
- package/examples/json-validation-example.js +64 -0
- package/examples/rest-client-example.js +52 -0
- package/examples/rest_client_example.js +54 -0
- package/package.json +26 -21
- package/scripts/post-deployment-config.js +9 -2
- package/src/auth.js +173 -0
- package/src/auth_command.js +208 -0
- package/src/calculator.js +313 -0
- package/src/core/cli_help_analyzer.js +674 -563
- package/src/core/cli_parameter_handler.js +127 -0
- package/src/core/cli_tools.js +89 -0
- package/src/core/error_handler.js +406 -0
- package/src/core/memory_manager.js +83 -0
- package/src/core/rest_client.js +160 -0
- package/src/core/smart_router.js +146 -0
- package/src/data_encryption.js +143 -0
- package/src/data_structures.js +440 -0
- package/src/deploy.js +56 -0
- package/src/index.js +9 -9
- package/src/main.js +889 -752
- package/src/main_english.js +1305 -977
- package/src/main_fixed.js +1172 -0
- package/src/utils.js +916 -0
- package/src/weatherProcessor.js +228 -0
- package/test/calculator.test.js +215 -0
- package/test/collision-test.js +26 -0
- package/test/csv-processing-test.js +36 -0
- package/test/e2e/claude-cli-test.js +128 -0
- package/test/e2e/collaboration-test.js +75 -0
- package/test/e2e/comprehensive-test.js +431 -0
- package/test/e2e/error-handling-test.js +90 -0
- package/test/e2e/individual-tool-test.js +143 -0
- package/test/e2e/other-cli-test.js +130 -0
- package/test/e2e/qoder-cli-test.js +128 -0
- package/test/e2e/run-e2e-tests.js +73 -0
- package/test/e2e/test-data.js +88 -0
- package/test/e2e/test-utils.js +222 -0
- package/test/encryption-simple-test.js +110 -0
- package/test/encryption.test.js +129 -0
- package/test/hash-table-demo.js +33 -0
- package/test/hash-table-test.js +26 -0
- package/test/hash_table_test.js +114 -0
- package/test/json-parser-test.js +161 -0
- package/test/json-validation-test.js +164 -0
- package/test/rest-client-test.js +56 -0
- package/test/rest_client.test.js +85 -0
- package/test/unit/calculator-full.test.js +191 -0
- package/test/unit/calculator-simple.test.js +96 -0
- package/test/unit/calculator.test.js +97 -0
- package/test/unit/cli_parameter_handler.test.js +116 -0
- package/test/weather-processor.test.js +104 -0
package/src/main_english.js
CHANGED
|
@@ -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.
|
|
6
|
+
* Version: 1.0.94
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
134
|
-
|
|
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
|
-
|
|
143
|
-
|
|
224
|
+
async scanCLI() {
|
|
225
|
+
console.log("[SCAN] Scanning for AI CLI tools...");
|
|
226
|
+
const available = {};
|
|
227
|
+
const missing = {};
|
|
144
228
|
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
215
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
//
|
|
574
|
+
// Execute post-deployment configuration
|
|
286
575
|
try {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
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
|
-
|
|
395
|
-
|
|
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
|
-
|
|
398
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
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
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
|
|
930
|
+
// Step 1: Download required assets
|
|
931
|
+
await installer.downloadRequiredAssets();
|
|
422
932
|
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
434
|
-
|
|
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
|
-
|
|
440
|
-
|
|
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
|
-
|
|
445
|
-
|
|
960
|
+
// Step 6: Initialize configuration
|
|
961
|
+
await installer.initializeConfig();
|
|
446
962
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
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
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
|
|
554
|
-
|
|
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
|
-
|
|
597
|
-
|
|
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
|
-
|
|
602
|
-
async safetyCheck() {
|
|
603
|
-
console.log('[SAFETY] Running conflict prevention check...');
|
|
604
|
-
|
|
1005
|
+
break;
|
|
1006
|
+
|
|
1007
|
+
case "scan":
|
|
605
1008
|
try {
|
|
606
|
-
|
|
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
|
-
|
|
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
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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
|
-
|
|
659
|
-
console.log('\n[DEPLOY] Deploying project documentation...');
|
|
660
|
-
|
|
1044
|
+
case "deploy":
|
|
661
1045
|
try {
|
|
662
|
-
|
|
663
|
-
|
|
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
|
-
|
|
692
|
-
|
|
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
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
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
|
-
|
|
750
|
-
}
|
|
1062
|
+
handleRegister(args[1], args[2]);
|
|
1063
|
+
break;
|
|
751
1064
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
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
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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
|
-
|
|
816
|
-
|
|
1077
|
+
case "auth-status":
|
|
1078
|
+
handleStatus();
|
|
1079
|
+
break;
|
|
817
1080
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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
|
-
|
|
844
|
-
|
|
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
|
-
//
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
|
|
1095
|
+
console.log(`[CALL] Routing to ${route.tool}: ${route.prompt}`);
|
|
906
1096
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
-
|
|
945
|
-
|
|
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
|
-
|
|
1233
|
+
try {
|
|
1234
|
+
// Step 1: Download required assets
|
|
1235
|
+
try {
|
|
1236
|
+
console.log("[STEP] Downloading required assets...");
|
|
948
1237
|
await installer.downloadRequiredAssets();
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
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
|
-
|
|
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
|
-
|
|
966
|
-
|
|
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
|
-
|
|
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
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
1360
|
+
// Function to find maximum of two numbers
|
|
1361
|
+
function maxOfTwo(a, b) {
|
|
1362
|
+
return a > b ? a : b;
|
|
1363
|
+
}
|
|
983
1364
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
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
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
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 = {
|
|
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
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
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
|
+
}
|