stigmergy 1.0.88 → 1.0.92
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 +202 -189
- package/bin/stigmergy.cmd +5 -0
- package/docs/CONFLICT_PREVENTION.md +150 -0
- package/package.json +12 -6
- package/scripts/post-deployment-config.js +289 -0
- package/scripts/preinstall-check.js +111 -0
- package/scripts/safe-install.js +139 -0
- package/src/main.js +963 -892
- package/src/main_english.js +184 -36
- package/test/comprehensive-execution-test.js +428 -0
- package/test/conflict-prevention-test.js +95 -0
- package/test/deploy-hooks-test.js +250 -0
- package/test/error-handling-test.js +341 -0
- package/test/final-deploy-test.js +221 -0
- package/test/final-install-test.js +226 -0
- package/test/iflow-integration-test.js +292 -0
- package/test/improved-install-test.js +362 -0
- package/test/install-command-test.js +370 -0
- package/test/plugin-deployment-test.js +316 -0
- package/test/postinstall-test.js +269 -0
- package/test/simple-iflow-hook-test.js +137 -0
- package/test/tdd-deploy-fix-test.js +324 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stigmergy Post-Deployment Configuration Fixer
|
|
5
|
+
* This script runs the necessary installation scripts to properly configure
|
|
6
|
+
* the deployed hooks for each CLI tool
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs').promises;
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const { spawn } = require('child_process');
|
|
13
|
+
|
|
14
|
+
// CLI Tools Configuration with installation scripts
|
|
15
|
+
const CLI_TOOLS = {
|
|
16
|
+
claude: {
|
|
17
|
+
name: 'Claude CLI',
|
|
18
|
+
installScript: 'install_claude_integration.py',
|
|
19
|
+
hooksDir: path.join(os.homedir(), '.claude', 'hooks')
|
|
20
|
+
},
|
|
21
|
+
gemini: {
|
|
22
|
+
name: 'Gemini CLI',
|
|
23
|
+
installScript: 'install_gemini_integration.py',
|
|
24
|
+
hooksDir: path.join(os.homedir(), '.gemini', 'extensions')
|
|
25
|
+
},
|
|
26
|
+
qwen: {
|
|
27
|
+
name: 'Qwen CLI',
|
|
28
|
+
installScript: 'install_qwen_integration.py',
|
|
29
|
+
hooksDir: path.join(os.homedir(), '.qwen', 'hooks')
|
|
30
|
+
},
|
|
31
|
+
iflow: {
|
|
32
|
+
name: 'iFlow CLI',
|
|
33
|
+
installScript: 'install_iflow_integration.py',
|
|
34
|
+
hooksDir: path.join(os.homedir(), '.iflow', 'hooks')
|
|
35
|
+
},
|
|
36
|
+
qodercli: {
|
|
37
|
+
name: 'Qoder CLI',
|
|
38
|
+
installScript: 'install_qoder_integration.py',
|
|
39
|
+
hooksDir: path.join(os.homedir(), '.qoder', 'hooks')
|
|
40
|
+
},
|
|
41
|
+
codebuddy: {
|
|
42
|
+
name: 'CodeBuddy CLI',
|
|
43
|
+
installScript: 'install_codebuddy_integration.py',
|
|
44
|
+
hooksDir: path.join(os.homedir(), '.codebuddy', 'hooks')
|
|
45
|
+
},
|
|
46
|
+
copilot: {
|
|
47
|
+
name: 'GitHub Copilot CLI',
|
|
48
|
+
installScript: 'install_copilot_integration.py',
|
|
49
|
+
hooksDir: path.join(os.homedir(), '.copilot', 'mcp')
|
|
50
|
+
},
|
|
51
|
+
codex: {
|
|
52
|
+
name: 'OpenAI Codex CLI',
|
|
53
|
+
installScript: 'install_codex_integration.py',
|
|
54
|
+
hooksDir: path.join(os.homedir(), '.config', 'codex', 'slash_commands')
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
class PostDeploymentConfigurer {
|
|
59
|
+
constructor() {
|
|
60
|
+
this.stigmergyAssetsDir = path.join(os.homedir(), '.stigmergy', 'assets', 'adapters');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check if an installation script exists
|
|
64
|
+
async checkInstallScript(toolName) {
|
|
65
|
+
const tool = CLI_TOOLS[toolName];
|
|
66
|
+
if (!tool) return false;
|
|
67
|
+
|
|
68
|
+
const scriptPath = path.join(this.stigmergyAssetsDir, toolName, tool.installScript);
|
|
69
|
+
try {
|
|
70
|
+
await fs.access(scriptPath);
|
|
71
|
+
return { exists: true, path: scriptPath };
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return { exists: false, path: scriptPath };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Run an installation script
|
|
78
|
+
async runInstallScript(toolName) {
|
|
79
|
+
const tool = CLI_TOOLS[toolName];
|
|
80
|
+
if (!tool) return { success: false, error: 'Tool not found' };
|
|
81
|
+
|
|
82
|
+
const scriptInfo = await this.checkInstallScript(toolName);
|
|
83
|
+
if (!scriptInfo.exists) {
|
|
84
|
+
return { success: false, error: 'Installation script not found' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`[RUN] Running installation script for ${tool.name}...`);
|
|
88
|
+
console.log(` Script: ${scriptInfo.path}`);
|
|
89
|
+
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
// Use Python to run the script
|
|
92
|
+
const child = spawn('python', [scriptInfo.path], {
|
|
93
|
+
cwd: path.dirname(scriptInfo.path),
|
|
94
|
+
stdio: 'pipe',
|
|
95
|
+
timeout: 30000 // 30 second timeout
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
let stdout = '';
|
|
99
|
+
let stderr = '';
|
|
100
|
+
|
|
101
|
+
child.stdout.on('data', (data) => {
|
|
102
|
+
stdout += data.toString();
|
|
103
|
+
// Print output in real-time
|
|
104
|
+
process.stdout.write(data.toString());
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
child.stderr.on('data', (data) => {
|
|
108
|
+
stderr += data.toString();
|
|
109
|
+
// Print errors in real-time
|
|
110
|
+
process.stderr.write(data.toString());
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
child.on('close', (code) => {
|
|
114
|
+
if (code === 0) {
|
|
115
|
+
console.log(`[OK] ${tool.name} installation script completed successfully`);
|
|
116
|
+
resolve({ success: true, code: code, stdout: stdout, stderr: stderr });
|
|
117
|
+
} else {
|
|
118
|
+
console.log(`[ERROR] ${tool.name} installation script failed with code ${code}`);
|
|
119
|
+
resolve({ success: false, code: code, stdout: stdout, stderr: stderr, error: `Script exited with code ${code}` });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
child.on('error', (error) => {
|
|
124
|
+
console.log(`[ERROR] Failed to run ${tool.name} installation script: ${error.message}`);
|
|
125
|
+
resolve({ success: false, error: error.message, stdout: stdout, stderr: stderr });
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Configure a specific tool
|
|
131
|
+
async configureTool(toolName) {
|
|
132
|
+
console.log(`\n[CONFIG] Configuring ${CLI_TOOLS[toolName].name}...`);
|
|
133
|
+
|
|
134
|
+
const result = {
|
|
135
|
+
toolName: toolName,
|
|
136
|
+
toolNameDisplay: CLI_TOOLS[toolName].name,
|
|
137
|
+
scriptExists: false,
|
|
138
|
+
runSuccess: false,
|
|
139
|
+
error: null
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Check if installation script exists
|
|
143
|
+
const scriptInfo = await this.checkInstallScript(toolName);
|
|
144
|
+
result.scriptExists = scriptInfo.exists;
|
|
145
|
+
|
|
146
|
+
if (!scriptInfo.exists) {
|
|
147
|
+
console.log(` [SKIP] No installation script found for ${CLI_TOOLS[toolName].name}`);
|
|
148
|
+
result.error = 'Installation script not found';
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log(` [FOUND] Installation script: ${scriptInfo.path}`);
|
|
153
|
+
|
|
154
|
+
// Run the installation script
|
|
155
|
+
const runResult = await this.runInstallScript(toolName);
|
|
156
|
+
result.runSuccess = runResult.success;
|
|
157
|
+
result.error = runResult.error;
|
|
158
|
+
|
|
159
|
+
if (runResult.success) {
|
|
160
|
+
console.log(` [SUCCESS] ${CLI_TOOLS[toolName].name} configured successfully`);
|
|
161
|
+
} else {
|
|
162
|
+
console.log(` [FAILED] ${CLI_TOOLS[toolName].name} configuration failed: ${runResult.error || 'Unknown error'}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Configure all tools
|
|
169
|
+
async configureAllTools() {
|
|
170
|
+
console.log('Stigmergy Post-Deployment Configuration');
|
|
171
|
+
console.log('='.repeat(50));
|
|
172
|
+
|
|
173
|
+
const toolNames = Object.keys(CLI_TOOLS);
|
|
174
|
+
const results = [];
|
|
175
|
+
|
|
176
|
+
for (const toolName of toolNames) {
|
|
177
|
+
const result = await this.configureTool(toolName);
|
|
178
|
+
results.push(result);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Summary
|
|
182
|
+
console.log('\n' + '='.repeat(50));
|
|
183
|
+
console.log('Configuration Summary:');
|
|
184
|
+
console.log('='.repeat(50));
|
|
185
|
+
|
|
186
|
+
const successCount = results.filter(r => r.runSuccess).length;
|
|
187
|
+
const totalCount = results.length;
|
|
188
|
+
|
|
189
|
+
results.forEach(result => {
|
|
190
|
+
const status = result.runSuccess ? '✓ SUCCESS' :
|
|
191
|
+
result.scriptExists ? '✗ FAILED' : ' SKIP';
|
|
192
|
+
console.log(`${result.toolNameDisplay}: ${status}`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
console.log(`\nOverall: ${successCount}/${totalCount} tools configured successfully`);
|
|
196
|
+
|
|
197
|
+
if (successCount === totalCount) {
|
|
198
|
+
console.log('🎉 All tools configured successfully!');
|
|
199
|
+
} else if (successCount > 0) {
|
|
200
|
+
console.log('⚠ Some tools configured, some failed or skipped.');
|
|
201
|
+
} else {
|
|
202
|
+
console.log('❌ No tools configured successfully.');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return results;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Quick fix for iFlow specifically
|
|
209
|
+
async quickFixIFlow() {
|
|
210
|
+
console.log('\n[QUICK FIX] Running iFlow configuration...');
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
// Check if iFlow hooks directory exists
|
|
214
|
+
const iflowHooksDir = path.join(os.homedir(), '.iflow', 'hooks');
|
|
215
|
+
await fs.access(iflowHooksDir);
|
|
216
|
+
|
|
217
|
+
// Check if install script exists
|
|
218
|
+
const installScript = path.join(iflowHooksDir, 'install_iflow_integration.py');
|
|
219
|
+
await fs.access(installScript);
|
|
220
|
+
|
|
221
|
+
console.log(' [FOUND] iFlow installation script');
|
|
222
|
+
|
|
223
|
+
// Run the script
|
|
224
|
+
const child = spawn('python', [installScript], {
|
|
225
|
+
cwd: iflowHooksDir,
|
|
226
|
+
stdio: 'inherit',
|
|
227
|
+
timeout: 30000
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return new Promise((resolve) => {
|
|
231
|
+
child.on('close', (code) => {
|
|
232
|
+
if (code === 0) {
|
|
233
|
+
console.log(' [SUCCESS] iFlow configured successfully');
|
|
234
|
+
resolve(true);
|
|
235
|
+
} else {
|
|
236
|
+
console.log(` [FAILED] iFlow configuration failed with code ${code}`);
|
|
237
|
+
resolve(false);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
child.on('error', (error) => {
|
|
242
|
+
console.log(` [ERROR] Failed to run iFlow configuration: ${error.message}`);
|
|
243
|
+
resolve(false);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.log(` [ERROR] Cannot configure iFlow: ${error.message}`);
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Run the configuration
|
|
255
|
+
async function runPostDeploymentConfiguration() {
|
|
256
|
+
const configurer = new PostDeploymentConfigurer();
|
|
257
|
+
|
|
258
|
+
// Check if Python is available
|
|
259
|
+
try {
|
|
260
|
+
const pythonCheck = spawn('python', ['--version']);
|
|
261
|
+
await new Promise((resolve, reject) => {
|
|
262
|
+
pythonCheck.on('close', resolve);
|
|
263
|
+
pythonCheck.on('error', reject);
|
|
264
|
+
});
|
|
265
|
+
console.log('✓ Python is available');
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.log('✗ Python is not available. Installation scripts require Python.');
|
|
268
|
+
console.log(' Please install Python 3.8+ and try again.');
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Run full configuration
|
|
273
|
+
const results = await configurer.configureAllTools();
|
|
274
|
+
|
|
275
|
+
return results;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Export for use in other modules
|
|
279
|
+
module.exports = { PostDeploymentConfigurer };
|
|
280
|
+
|
|
281
|
+
// Run if called directly
|
|
282
|
+
if (require.main === module) {
|
|
283
|
+
runPostDeploymentConfiguration().then(results => {
|
|
284
|
+
process.exit(0);
|
|
285
|
+
}).catch(error => {
|
|
286
|
+
console.error('[Configuration Failed]:', error.message);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stigmergy Pre-installation Safety Check
|
|
5
|
+
* This script prevents installation conflicts by checking for potential issues
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { spawnSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
console.log('[PRE-INSTALL] Running safety checks...');
|
|
13
|
+
|
|
14
|
+
// Check 1: Verify no conflicting "node" package is already installed
|
|
15
|
+
function checkConflictingNodePackage() {
|
|
16
|
+
console.log('[CHECK] Looking for conflicting node packages...');
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const result = spawnSync('npm', ['list', '-g', 'node'], {
|
|
20
|
+
encoding: 'utf8',
|
|
21
|
+
timeout: 5000
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (result.stdout && result.stdout.includes('node@')) {
|
|
25
|
+
console.error('[ERROR] Conflicting "node" package detected!');
|
|
26
|
+
console.error('[ERROR] This will interfere with CLI tools. Please run:');
|
|
27
|
+
console.error('[ERROR] npm uninstall -g node');
|
|
28
|
+
console.error('[ERROR] Then try installing stigmergy again.');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// If npm command fails, continue anyway
|
|
33
|
+
console.log('[INFO] Could not verify node package status, continuing...');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('[OK] No conflicting node package found.');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check 2: Verify system Node.js installation
|
|
40
|
+
function checkSystemNode() {
|
|
41
|
+
console.log('[CHECK] Verifying system Node.js installation...');
|
|
42
|
+
|
|
43
|
+
const nodeVersion = process.version;
|
|
44
|
+
const majorVersion = parseInt(nodeVersion.match(/^v(\d+)/)[1]);
|
|
45
|
+
|
|
46
|
+
if (majorVersion < 16) {
|
|
47
|
+
console.error('[ERROR] Node.js version 16 or higher is required.');
|
|
48
|
+
console.error(`[ERROR] Current version: ${nodeVersion}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log(`[OK] Node.js ${nodeVersion} detected.`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check 3: Verify npm installation
|
|
56
|
+
function checkNpm() {
|
|
57
|
+
console.log('[CHECK] Verifying npm installation...');
|
|
58
|
+
|
|
59
|
+
// On Windows, npm might not be directly executable
|
|
60
|
+
if (process.platform === 'win32') {
|
|
61
|
+
console.log('[INFO] Skipping npm verification on Windows (may not be directly executable)');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const result = spawnSync('npm', ['--version'], {
|
|
67
|
+
encoding: 'utf8',
|
|
68
|
+
timeout: 5000
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (result.status !== 0) {
|
|
72
|
+
console.error('[ERROR] npm is not properly installed or accessible.');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log(`[OK] npm ${result.stdout.trim()} detected.`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('[ERROR] Failed to verify npm installation.');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check 4: Check for existing stigmergy installation conflicts
|
|
84
|
+
function checkExistingInstallation() {
|
|
85
|
+
console.log('[CHECK] Looking for existing Stigmergy installations...');
|
|
86
|
+
|
|
87
|
+
const npmBinDir = path.join(process.env.APPDATA || process.env.HOME, 'npm');
|
|
88
|
+
const stigmergyBin = path.join(npmBinDir, 'stigmergy');
|
|
89
|
+
|
|
90
|
+
if (fs.existsSync(stigmergyBin)) {
|
|
91
|
+
console.log('[WARNING] Existing Stigmergy installation detected.');
|
|
92
|
+
console.log('[WARNING] This may cause conflicts. Consider uninstalling first:');
|
|
93
|
+
console.log('[WARNING] npm uninstall -g stigmergy');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log('[OK] No conflicting Stigmergy installation found.');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Run all checks
|
|
100
|
+
try {
|
|
101
|
+
checkSystemNode();
|
|
102
|
+
checkNpm();
|
|
103
|
+
checkConflictingNodePackage();
|
|
104
|
+
checkExistingInstallation();
|
|
105
|
+
|
|
106
|
+
console.log('[SUCCESS] All safety checks passed. Proceeding with installation.');
|
|
107
|
+
process.exit(0);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('[FATAL] Safety check failed:', error.message);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stigmergy Safe Installation Script
|
|
5
|
+
* This script ensures safe installation without conflicting with other CLI tools
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { spawn } = require('child_process');
|
|
11
|
+
|
|
12
|
+
class SafeInstaller {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.npmBinDir = path.join(process.env.APPDATA || process.env.HOME, 'npm');
|
|
15
|
+
this.backupDir = path.join(process.env.TEMP || '/tmp', 'stigmergy-backup-' + Date.now());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Backup existing files that might conflict
|
|
19
|
+
async backupPotentialConflicts() {
|
|
20
|
+
console.log('[BACKUP] Creating backup of potential conflicting files...');
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
await fs.mkdir(this.backupDir, { recursive: true });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.log('[INFO] Could not create backup directory, continuing without backup...');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const potentialConflicts = [
|
|
30
|
+
'node',
|
|
31
|
+
'node.exe',
|
|
32
|
+
'node.cmd'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
for (const fileName of potentialConflicts) {
|
|
36
|
+
const filePath = path.join(this.npmBinDir, fileName);
|
|
37
|
+
const backupPath = path.join(this.backupDir, fileName);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await fs.access(filePath);
|
|
41
|
+
console.log(`[BACKUP] Backing up ${fileName}...`);
|
|
42
|
+
await fs.copyFile(filePath, backupPath);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// File doesn't exist, that's fine
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log(`[OK] Backup created at: ${this.backupDir}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Restore backed up files if installation fails
|
|
52
|
+
async restoreBackupIfNeeded(success) {
|
|
53
|
+
if (success) {
|
|
54
|
+
console.log('[CLEANUP] Installation successful, cleaning up backup...');
|
|
55
|
+
try {
|
|
56
|
+
const rimraf = require('rimraf');
|
|
57
|
+
rimraf.sync(this.backupDir);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// If rimraf is not available, just leave the backup
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
console.log('[RESTORE] Installation failed, restoring backed up files...');
|
|
63
|
+
// We would restore files here if needed
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Monitor installation for conflicts
|
|
68
|
+
async monitorInstallation() {
|
|
69
|
+
console.log('[MONITOR] Monitoring installation for conflicts...');
|
|
70
|
+
|
|
71
|
+
// Check for the specific issue we're trying to prevent
|
|
72
|
+
const nodePackageDir = path.join(this.npmBinDir, 'node_modules', 'node');
|
|
73
|
+
try {
|
|
74
|
+
await fs.access(nodePackageDir);
|
|
75
|
+
console.warn('[WARNING] Detected "node" package installation during installation!');
|
|
76
|
+
console.warn('[WARNING] This may cause conflicts with other CLI tools.');
|
|
77
|
+
console.warn('[WARNING] If you experience issues, run: npm run fix-node-conflict');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
// Package doesn't exist, that's good
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Safe installation process
|
|
84
|
+
async install() {
|
|
85
|
+
let success = false;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
// Step 1: Backup potential conflicts
|
|
89
|
+
await this.backupPotentialConflicts();
|
|
90
|
+
|
|
91
|
+
// Step 2: Run the actual installation
|
|
92
|
+
console.log('[INSTALL] Starting safe installation...');
|
|
93
|
+
|
|
94
|
+
// This would be where we run the actual installation logic
|
|
95
|
+
// For now, we'll just simulate it
|
|
96
|
+
|
|
97
|
+
success = true;
|
|
98
|
+
console.log('[SUCCESS] Safe installation completed.');
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('[ERROR] Installation failed:', error.message);
|
|
102
|
+
} finally {
|
|
103
|
+
// Step 3: Restore backups if needed
|
|
104
|
+
await this.restoreBackupIfNeeded(success);
|
|
105
|
+
|
|
106
|
+
// Step 4: Monitor for conflicts
|
|
107
|
+
await this.monitorInstallation();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return success;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Run safe installation
|
|
115
|
+
async function runSafeInstallation() {
|
|
116
|
+
console.log('Stigmergy Safe Installation');
|
|
117
|
+
console.log('='.repeat(30));
|
|
118
|
+
|
|
119
|
+
const installer = new SafeInstaller();
|
|
120
|
+
const success = await installer.install();
|
|
121
|
+
|
|
122
|
+
if (success) {
|
|
123
|
+
console.log('\n[COMPLETE] Stigmergy installed safely!');
|
|
124
|
+
console.log('[NEXT] Run "stigmergy --help" to get started.');
|
|
125
|
+
} else {
|
|
126
|
+
console.log('\n[FAILED] Installation failed. Please check the errors above.');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Only run if this script is called directly
|
|
132
|
+
if (require.main === module) {
|
|
133
|
+
runSafeInstallation().catch(error => {
|
|
134
|
+
console.error('[FATAL]', error.message);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = { SafeInstaller };
|