stigmergy 1.0.89 → 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 +11 -5
- 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 +179 -35
- 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,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test for postinstall behavior and error handling
|
|
5
|
+
* This test verifies that the npm postinstall script works correctly
|
|
6
|
+
* and provides graceful degradation when problems occur
|
|
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
|
+
class PostInstallTester {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.testResults = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Test 1: Verify postinstall script exists and is correct
|
|
20
|
+
async testPostInstallScript() {
|
|
21
|
+
console.log('[TEST 1] Verifying postinstall script configuration...');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Read package.json
|
|
25
|
+
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
26
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
27
|
+
|
|
28
|
+
// Check if postinstall script exists
|
|
29
|
+
if (!packageJson.scripts || !packageJson.scripts.postinstall) {
|
|
30
|
+
console.log(' ✗ postinstall script not found in package.json');
|
|
31
|
+
this.testResults.push({
|
|
32
|
+
name: 'Postinstall Script Configuration',
|
|
33
|
+
passed: false,
|
|
34
|
+
details: 'postinstall script not found in package.json'
|
|
35
|
+
});
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const postinstallScript = packageJson.scripts.postinstall;
|
|
40
|
+
console.log(` Postinstall script: ${postinstallScript}`);
|
|
41
|
+
|
|
42
|
+
// Check if it calls the auto-install command
|
|
43
|
+
const hasAutoInstall = postinstallScript.includes('auto-install');
|
|
44
|
+
const hasMainScript = postinstallScript.includes('src/main_english.js');
|
|
45
|
+
|
|
46
|
+
if (hasAutoInstall && hasMainScript) {
|
|
47
|
+
console.log(' ✓ postinstall script correctly configured for auto-install');
|
|
48
|
+
} else {
|
|
49
|
+
console.log(' ✗ postinstall script missing auto-install configuration');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.testResults.push({
|
|
53
|
+
name: 'Postinstall Script Configuration',
|
|
54
|
+
passed: hasAutoInstall && hasMainScript,
|
|
55
|
+
details: hasAutoInstall && hasMainScript ?
|
|
56
|
+
'Correctly configured for auto-install' :
|
|
57
|
+
'Missing auto-install configuration'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return hasAutoInstall && hasMainScript;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.log(` ✗ Failed to check postinstall script: ${error.message}`);
|
|
63
|
+
this.testResults.push({
|
|
64
|
+
name: 'Postinstall Script Configuration',
|
|
65
|
+
passed: false,
|
|
66
|
+
details: `Failed to check: ${error.message}`
|
|
67
|
+
});
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Test 2: Verify auto-install command exists
|
|
73
|
+
async testAutoInstallCommand() {
|
|
74
|
+
console.log('\n[TEST 2] Verifying auto-install command implementation...');
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
// Read main script
|
|
78
|
+
const mainScriptPath = path.join(__dirname, '..', 'src', 'main_english.js');
|
|
79
|
+
const mainScript = await fs.readFile(mainScriptPath, 'utf8');
|
|
80
|
+
|
|
81
|
+
// Check if auto-install case exists
|
|
82
|
+
const hasAutoInstallCase = mainScript.includes('case \'auto-install\':') ||
|
|
83
|
+
mainScript.includes('case "auto-install":');
|
|
84
|
+
|
|
85
|
+
if (hasAutoInstallCase) {
|
|
86
|
+
console.log(' ✓ auto-install command implemented');
|
|
87
|
+
} else {
|
|
88
|
+
console.log(' ✗ auto-install command not implemented');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Check if it includes error handling
|
|
92
|
+
const hasErrorHandling = mainScript.includes('try {') && mainScript.includes('catch');
|
|
93
|
+
|
|
94
|
+
this.testResults.push({
|
|
95
|
+
name: 'Auto-Install Command Implementation',
|
|
96
|
+
passed: hasAutoInstallCase,
|
|
97
|
+
details: hasAutoInstallCase ?
|
|
98
|
+
'auto-install command implemented' :
|
|
99
|
+
'auto-install command not implemented'
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return hasAutoInstallCase;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.log(` ✗ Failed to check auto-install command: ${error.message}`);
|
|
105
|
+
this.testResults.push({
|
|
106
|
+
name: 'Auto-Install Command Implementation',
|
|
107
|
+
passed: false,
|
|
108
|
+
details: `Failed to check: ${error.message}`
|
|
109
|
+
});
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Test 3: Verify graceful degradation and user guidance
|
|
115
|
+
async testGracefulDegradation() {
|
|
116
|
+
console.log('\n[TEST 3] Verifying graceful degradation and user guidance...');
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// Read main script
|
|
120
|
+
const mainScriptPath = path.join(__dirname, '..', 'src', 'main_english.js');
|
|
121
|
+
const mainScript = await fs.readFile(mainScriptPath, 'utf8');
|
|
122
|
+
|
|
123
|
+
// Check if auto-install includes user guidance
|
|
124
|
+
const hasUserGuidance = mainScript.includes('For full functionality') ||
|
|
125
|
+
mainScript.includes('please run') ||
|
|
126
|
+
mainScript.includes('stigmergy install') ||
|
|
127
|
+
mainScript.includes('stigmergy setup');
|
|
128
|
+
|
|
129
|
+
if (hasUserGuidance) {
|
|
130
|
+
console.log(' ✓ User guidance messages found in auto-install');
|
|
131
|
+
} else {
|
|
132
|
+
console.log(' ✗ User guidance messages not found in auto-install');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check if it handles missing tools gracefully
|
|
136
|
+
const hasMissingToolsHandling = mainScript.includes('Skipping automatic installation') ||
|
|
137
|
+
mainScript.includes('missing AI CLI tools') ||
|
|
138
|
+
mainScript.includes('autoMissing');
|
|
139
|
+
|
|
140
|
+
if (hasMissingToolsHandling) {
|
|
141
|
+
console.log(' ✓ Missing tools handling found in auto-install');
|
|
142
|
+
} else {
|
|
143
|
+
console.log(' ✗ Missing tools handling not found in auto-install');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check if it shows success message
|
|
147
|
+
const hasSuccessMessage = mainScript.includes('SUCCESS') &&
|
|
148
|
+
mainScript.includes('installed successfully');
|
|
149
|
+
|
|
150
|
+
this.testResults.push({
|
|
151
|
+
name: 'Graceful Degradation and Guidance',
|
|
152
|
+
passed: hasUserGuidance && hasMissingToolsHandling && hasSuccessMessage,
|
|
153
|
+
details: `User guidance: ${hasUserGuidance}, Missing tools handling: ${hasMissingToolsHandling}, Success message: ${hasSuccessMessage}`
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return hasUserGuidance && hasMissingToolsHandling && hasSuccessMessage;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.log(` ✗ Failed to check graceful degradation: ${error.message}`);
|
|
159
|
+
this.testResults.push({
|
|
160
|
+
name: 'Graceful Degradation and Guidance',
|
|
161
|
+
passed: false,
|
|
162
|
+
details: `Failed to check: ${error.message}`
|
|
163
|
+
});
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Test 4: Verify error handling in auto-install
|
|
169
|
+
async testErrorHandling() {
|
|
170
|
+
console.log('\n[TEST 4] Verifying error handling in auto-install...');
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
// Read main script
|
|
174
|
+
const mainScriptPath = path.join(__dirname, '..', 'src', 'main_english.js');
|
|
175
|
+
const mainScript = await fs.readFile(mainScriptPath, 'utf8');
|
|
176
|
+
|
|
177
|
+
// Check if main function has error handling
|
|
178
|
+
const hasMainErrorHandling = mainScript.includes('main().catch') ||
|
|
179
|
+
mainScript.includes('try {') && mainScript.includes('catch');
|
|
180
|
+
|
|
181
|
+
if (hasMainErrorHandling) {
|
|
182
|
+
console.log(' ✓ Main function has error handling');
|
|
183
|
+
} else {
|
|
184
|
+
console.log(' ✗ Main function missing error handling');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check if auto-install has specific error handling
|
|
188
|
+
const autoInstallSection = mainScript.split('case \'auto-install\':')[1] ||
|
|
189
|
+
mainScript.split('case "auto-install":')[1] || '';
|
|
190
|
+
|
|
191
|
+
const hasAutoInstallErrorHandling = autoInstallSection.includes('try {') &&
|
|
192
|
+
autoInstallSection.includes('catch');
|
|
193
|
+
|
|
194
|
+
this.testResults.push({
|
|
195
|
+
name: 'Error Handling',
|
|
196
|
+
passed: hasMainErrorHandling,
|
|
197
|
+
details: `Main error handling: ${hasMainErrorHandling}, Auto-install error handling: ${hasAutoInstallErrorHandling}`
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return hasMainErrorHandling;
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.log(` ✗ Failed to check error handling: ${error.message}`);
|
|
203
|
+
this.testResults.push({
|
|
204
|
+
name: 'Error Handling',
|
|
205
|
+
passed: false,
|
|
206
|
+
details: `Failed to check: ${error.message}`
|
|
207
|
+
});
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Run all tests
|
|
213
|
+
async runAllTests() {
|
|
214
|
+
console.log('Postinstall Behavior and Error Handling Test');
|
|
215
|
+
console.log('='.repeat(50));
|
|
216
|
+
|
|
217
|
+
await this.testPostInstallScript();
|
|
218
|
+
await this.testAutoInstallCommand();
|
|
219
|
+
await this.testGracefulDegradation();
|
|
220
|
+
await this.testErrorHandling();
|
|
221
|
+
|
|
222
|
+
// Summary
|
|
223
|
+
console.log('\n' + '='.repeat(50));
|
|
224
|
+
console.log('Postinstall Test Summary:');
|
|
225
|
+
console.log('='.repeat(50));
|
|
226
|
+
|
|
227
|
+
let passedTests = 0;
|
|
228
|
+
this.testResults.forEach(result => {
|
|
229
|
+
console.log(`${result.name}: ${result.passed ? '✓ PASS' : '✗ FAIL'} - ${result.details}`);
|
|
230
|
+
if (result.passed) passedTests++;
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
console.log(`\nOverall Result: ${passedTests}/${this.testResults.length} tests passed`);
|
|
234
|
+
|
|
235
|
+
if (passedTests === this.testResults.length) {
|
|
236
|
+
console.log('✓ All postinstall tests passed! Package should work correctly.');
|
|
237
|
+
} else if (passedTests > 0) {
|
|
238
|
+
console.log('⚠ Some postinstall tests failed. Package may need improvements.');
|
|
239
|
+
} else {
|
|
240
|
+
console.log('✗ All postinstall tests failed. Package needs significant improvements.');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
totalTests: this.testResults.length,
|
|
245
|
+
passedTests: passedTests,
|
|
246
|
+
results: this.testResults
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Run the tests
|
|
252
|
+
async function runPostInstallTests() {
|
|
253
|
+
const tester = new PostInstallTester();
|
|
254
|
+
const results = await tester.runAllTests();
|
|
255
|
+
return results;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Export for use in other modules
|
|
259
|
+
module.exports = { PostInstallTester };
|
|
260
|
+
|
|
261
|
+
// Run if called directly
|
|
262
|
+
if (require.main === module) {
|
|
263
|
+
runPostInstallTests().then(results => {
|
|
264
|
+
process.exit(results.passedTests === results.totalTests ? 0 : 1);
|
|
265
|
+
}).catch(error => {
|
|
266
|
+
console.error('[Test Failed]:', error.message);
|
|
267
|
+
process.exit(1);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple iFlow Hook Detection Test
|
|
5
|
+
* This script tests if iFlow can detect the Stigmergy hook configuration
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs').promises;
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const { spawn } = require('child_process');
|
|
12
|
+
|
|
13
|
+
async function testIFlowHookDetection() {
|
|
14
|
+
console.log('Simple iFlow Hook Detection Test');
|
|
15
|
+
console.log('='.repeat(40));
|
|
16
|
+
|
|
17
|
+
// Check if the hook configuration file exists and is properly formatted
|
|
18
|
+
const hookConfigPath = path.join(os.homedir(), '.config', 'iflow', 'hooks.yml');
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(hookConfigPath);
|
|
22
|
+
console.log('✓ Hook configuration file exists');
|
|
23
|
+
|
|
24
|
+
const configContent = await fs.readFile(hookConfigPath, 'utf8');
|
|
25
|
+
console.log('✓ Configuration file is readable');
|
|
26
|
+
|
|
27
|
+
// Check if it contains the expected Stigmergy configuration
|
|
28
|
+
if (configContent.includes('CrossCLIHookAdapter')) {
|
|
29
|
+
console.log('✓ Stigmergy CrossCLIHookAdapter found in configuration');
|
|
30
|
+
} else {
|
|
31
|
+
console.log('✗ Stigmergy CrossCLIHookAdapter not found in configuration');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (configContent.includes('cross_cli_enabled: true')) {
|
|
35
|
+
console.log('✓ Cross-CLI functionality is enabled');
|
|
36
|
+
} else {
|
|
37
|
+
console.log('✗ Cross-CLI functionality is not enabled');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Parse the YAML to verify structure
|
|
41
|
+
try {
|
|
42
|
+
const yaml = await import('js-yaml');
|
|
43
|
+
const parsedConfig = yaml.load(configContent);
|
|
44
|
+
|
|
45
|
+
if (parsedConfig && parsedConfig.plugins && Array.isArray(parsedConfig.plugins)) {
|
|
46
|
+
console.log('✓ Configuration has valid plugin structure');
|
|
47
|
+
|
|
48
|
+
const stigmergyPlugin = parsedConfig.plugins.find(plugin =>
|
|
49
|
+
plugin.name === 'CrossCLIHookAdapter'
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (stigmergyPlugin) {
|
|
53
|
+
console.log('✓ Stigmergy plugin found in parsed configuration');
|
|
54
|
+
console.log(' Plugin details:');
|
|
55
|
+
console.log(` Name: ${stigmergyPlugin.name}`);
|
|
56
|
+
console.log(` Module: ${stigmergyPlugin.module}`);
|
|
57
|
+
console.log(` Enabled: ${stigmergyPlugin.enabled}`);
|
|
58
|
+
console.log(` Supported CLIs: ${stigmergyPlugin.config?.supported_clis?.join(', ') || 'None'}`);
|
|
59
|
+
} else {
|
|
60
|
+
console.log('✗ Stigmergy plugin not found in parsed configuration');
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
console.log('✗ Configuration does not have valid plugin structure');
|
|
64
|
+
}
|
|
65
|
+
} catch (parseError) {
|
|
66
|
+
console.log('⚠ Could not parse YAML configuration:', parseError.message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.log('✗ Hook configuration file not found or not accessible');
|
|
71
|
+
console.log(' Path:', hookConfigPath);
|
|
72
|
+
console.log(' Error:', error.message);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Test if iFlow can load the configuration by running a simple command
|
|
77
|
+
console.log('\n[Test] Running iFlow with debug mode to check hook loading...');
|
|
78
|
+
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
const child = spawn('iflow', ['--debug', '--prompt', 'echo "test"'], {
|
|
81
|
+
stdio: 'pipe',
|
|
82
|
+
timeout: 15000
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
let output = '';
|
|
86
|
+
let errorOutput = '';
|
|
87
|
+
|
|
88
|
+
child.stdout.on('data', (data) => {
|
|
89
|
+
output += data.toString();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
child.stderr.on('data', (data) => {
|
|
93
|
+
errorOutput += data.toString();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
child.on('close', (code) => {
|
|
97
|
+
const fullOutput = output + errorOutput;
|
|
98
|
+
|
|
99
|
+
console.log(`Exit code: ${code}`);
|
|
100
|
+
|
|
101
|
+
// Look for hook-related messages in the output
|
|
102
|
+
if (fullOutput.includes('hook') || fullOutput.includes('Hook') || fullOutput.includes('plugin')) {
|
|
103
|
+
console.log('✓ Hook/plugin related messages found in iFlow output');
|
|
104
|
+
|
|
105
|
+
// Look specifically for Stigmergy-related messages
|
|
106
|
+
if (fullOutput.includes('stigmergy') || fullOutput.includes('Stigmergy') ||
|
|
107
|
+
fullOutput.includes('CrossCLI') || fullOutput.includes('cross')) {
|
|
108
|
+
console.log('✓ Stigmergy-related messages found in iFlow output');
|
|
109
|
+
} else {
|
|
110
|
+
console.log('ℹ Stigmergy-specific messages not found, but hooks are mentioned');
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
console.log('ℹ No hook/plugin messages found in iFlow output');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Show a preview of the output
|
|
117
|
+
const preview = fullOutput.substring(0, 500);
|
|
118
|
+
console.log('\nOutput preview:');
|
|
119
|
+
console.log(preview + (fullOutput.length > 500 ? '...' : ''));
|
|
120
|
+
|
|
121
|
+
resolve(true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
child.on('error', (error) => {
|
|
125
|
+
console.log('✗ Failed to run iFlow:', error.message);
|
|
126
|
+
resolve(false);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Run the test
|
|
132
|
+
testIFlowHookDetection().then(() => {
|
|
133
|
+
console.log('\n' + '='.repeat(40));
|
|
134
|
+
console.log('Test completed');
|
|
135
|
+
}).catch(error => {
|
|
136
|
+
console.error('Test failed:', error.message);
|
|
137
|
+
});
|