stigmergy 1.2.8 → 1.2.10
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 +40 -6
- package/STIGMERGY.md +10 -0
- package/package.json +19 -5
- package/scripts/preuninstall.js +10 -0
- package/src/adapters/claude/install_claude_integration.js +21 -21
- package/src/adapters/codebuddy/install_codebuddy_integration.js +54 -51
- package/src/adapters/codex/install_codex_integration.js +27 -28
- package/src/adapters/gemini/install_gemini_integration.js +60 -60
- package/src/adapters/iflow/install_iflow_integration.js +72 -72
- package/src/adapters/qoder/install_qoder_integration.js +64 -64
- package/src/adapters/qwen/install_qwen_integration.js +7 -7
- package/src/cli/router.js +581 -175
- package/src/commands/skill-bridge.js +39 -0
- package/src/commands/skill-handler.js +150 -0
- package/src/commands/skill.js +127 -0
- package/src/core/cli_path_detector.js +573 -0
- package/src/core/cli_tools.js +72 -1
- package/src/core/coordination/nodejs/AdapterManager.js +29 -1
- package/src/core/directory_permission_manager.js +568 -0
- package/src/core/enhanced_cli_installer.js +609 -0
- package/src/core/installer.js +232 -88
- package/src/core/multilingual/language-pattern-manager.js +78 -50
- package/src/core/persistent_shell_configurator.js +468 -0
- package/src/core/skills/StigmergySkillManager.js +357 -0
- package/src/core/skills/__tests__/SkillInstaller.test.js +275 -0
- package/src/core/skills/__tests__/SkillParser.test.js +202 -0
- package/src/core/skills/__tests__/SkillReader.test.js +189 -0
- package/src/core/skills/cli-command-test.js +201 -0
- package/src/core/skills/comprehensive-e2e-test.js +473 -0
- package/src/core/skills/e2e-test.js +267 -0
- package/src/core/skills/embedded-openskills/SkillInstaller.js +438 -0
- package/src/core/skills/embedded-openskills/SkillParser.js +123 -0
- package/src/core/skills/embedded-openskills/SkillReader.js +143 -0
- package/src/core/skills/integration-test.js +248 -0
- package/src/core/skills/package.json +6 -0
- package/src/core/skills/regression-test.js +285 -0
- package/src/core/skills/run-all-tests.js +129 -0
- package/src/core/skills/sync-test.js +210 -0
- package/src/core/skills/test-runner.js +242 -0
- package/src/utils/helpers.js +3 -20
- package/src/auth.js +0 -173
- package/src/auth_command.js +0 -208
- package/src/calculator.js +0 -313
- package/src/core/enhanced_installer.js +0 -479
- package/src/core/enhanced_uninstaller.js +0 -638
- package/src/data_encryption.js +0 -143
- package/src/data_structures.js +0 -440
- package/src/deploy.js +0 -55
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive End-to-End Test - Stigmergy Skills System
|
|
3
|
+
*
|
|
4
|
+
* Test Flow:
|
|
5
|
+
* 1. Clean all caches
|
|
6
|
+
* 2. Advanced uninstall
|
|
7
|
+
* 3. Uninstall partial CLI
|
|
8
|
+
* 4. Install stigmergy package
|
|
9
|
+
* 5. Test stigmergy commands one by one
|
|
10
|
+
* 6. Test CLI cross-calls
|
|
11
|
+
* 7. Test CLI skill usage
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { execSync, spawnSync } from 'child_process';
|
|
15
|
+
import fs from 'fs/promises';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import os from 'os';
|
|
18
|
+
|
|
19
|
+
class ComprehensiveE2ETestRunner {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.passed = 0;
|
|
22
|
+
this.failed = 0;
|
|
23
|
+
this.skipped = 0;
|
|
24
|
+
this.testResults = [];
|
|
25
|
+
// Fix Windows path issue
|
|
26
|
+
const filePath = new URL(import.meta.url).pathname;
|
|
27
|
+
// Windows paths need to remove leading /
|
|
28
|
+
const normalizedPath = process.platform === 'win32' && filePath.startsWith('/')
|
|
29
|
+
? filePath.substring(1)
|
|
30
|
+
: filePath;
|
|
31
|
+
this.projectRoot = path.resolve(path.dirname(normalizedPath), '../../..');
|
|
32
|
+
console.log(`[INFO] Project root: ${this.projectRoot}\n`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async test(name, fn, options = {}) {
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
38
|
+
console.log(`[LIST] Test: ${name}`);
|
|
39
|
+
console.log('='.repeat(60));
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await fn();
|
|
43
|
+
const duration = Date.now() - startTime;
|
|
44
|
+
this.passed++;
|
|
45
|
+
console.log(`[OK] Passed (${duration}ms)`);
|
|
46
|
+
this.testResults.push({
|
|
47
|
+
name,
|
|
48
|
+
status: 'passed',
|
|
49
|
+
duration,
|
|
50
|
+
category: options.category || 'general'
|
|
51
|
+
});
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const duration = Date.now() - startTime;
|
|
54
|
+
|
|
55
|
+
if (options.allowSkip && err.message.includes('SKIP')) {
|
|
56
|
+
this.skipped++;
|
|
57
|
+
console.log(`[INFO] Skipped: ${err.message}`);
|
|
58
|
+
this.testResults.push({
|
|
59
|
+
name,
|
|
60
|
+
status: 'skipped',
|
|
61
|
+
duration,
|
|
62
|
+
reason: err.message,
|
|
63
|
+
category: options.category || 'general'
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
this.failed++;
|
|
67
|
+
console.error(`[X] Failed: ${err.message}`);
|
|
68
|
+
if (options.verbose) {
|
|
69
|
+
console.error(err.stack);
|
|
70
|
+
}
|
|
71
|
+
this.testResults.push({
|
|
72
|
+
name,
|
|
73
|
+
status: 'failed',
|
|
74
|
+
duration,
|
|
75
|
+
error: err.message,
|
|
76
|
+
category: options.category || 'general'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exec(command, options = {}) {
|
|
83
|
+
console.log(` [INFO] Executing: ${command}`);
|
|
84
|
+
try {
|
|
85
|
+
const result = execSync(command, {
|
|
86
|
+
encoding: 'utf-8',
|
|
87
|
+
cwd: this.projectRoot,
|
|
88
|
+
timeout: options.timeout || 30000,
|
|
89
|
+
stdio: options.silent ? 'pipe' : 'inherit',
|
|
90
|
+
shell: true, // Ensure using shell on Windows
|
|
91
|
+
...options
|
|
92
|
+
});
|
|
93
|
+
return result;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (options.allowFail) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
summary() {
|
|
103
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
104
|
+
console.log('[LIST] Complete Test Report');
|
|
105
|
+
console.log('='.repeat(60));
|
|
106
|
+
|
|
107
|
+
const total = this.passed + this.failed + this.skipped;
|
|
108
|
+
console.log(`\nTotal: ${total} tests`);
|
|
109
|
+
console.log(`[OK] Passed: ${this.passed}`);
|
|
110
|
+
console.log(`[X] Failed: ${this.failed}`);
|
|
111
|
+
console.log(`[INFO] Skipped: ${this.skipped}`);
|
|
112
|
+
|
|
113
|
+
// Group by category
|
|
114
|
+
const byCategory = {};
|
|
115
|
+
for (const result of this.testResults) {
|
|
116
|
+
const cat = result.category;
|
|
117
|
+
if (!byCategory[cat]) {
|
|
118
|
+
byCategory[cat] = { passed: 0, failed: 0, skipped: 0 };
|
|
119
|
+
}
|
|
120
|
+
byCategory[cat][result.status]++;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log('\n[LIST] Statistics by Category:');
|
|
124
|
+
for (const [category, stats] of Object.entries(byCategory)) {
|
|
125
|
+
console.log(` ${category}: [OK]${stats.passed} [X]${stats.failed} [INFO]${stats.skipped}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log('\n' + '='.repeat(60));
|
|
129
|
+
|
|
130
|
+
return this.failed === 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function runComprehensiveTests() {
|
|
135
|
+
const runner = new ComprehensiveE2ETestRunner();
|
|
136
|
+
|
|
137
|
+
console.log('[SUCCESS] Stigmergy Skills Comprehensive End-to-End Test');
|
|
138
|
+
console.log('Test Scope: Cache Clean -> Install -> Command Test -> Cross-Call -> Skill Usage\n');
|
|
139
|
+
|
|
140
|
+
// ==================== Phase 1: Environment Preparation ====================
|
|
141
|
+
console.log('\n' + '='.repeat(60));
|
|
142
|
+
console.log('Phase 1: Environment Preparation and Cleanup');
|
|
143
|
+
console.log('='.repeat(60));
|
|
144
|
+
|
|
145
|
+
await runner.test('Clean npm cache', () => {
|
|
146
|
+
runner.exec('npm cache clean --force', { silent: true, allowFail: true });
|
|
147
|
+
}, { category: 'Environment Prep' });
|
|
148
|
+
|
|
149
|
+
await runner.test('Clean project cache', () => {
|
|
150
|
+
runner.exec('node src/index.js clean', { silent: true, allowFail: true });
|
|
151
|
+
}, { category: 'Environment Prep' });
|
|
152
|
+
|
|
153
|
+
await runner.test('Clean temporary files', async () => {
|
|
154
|
+
const tempDirs = [
|
|
155
|
+
path.join(os.tmpdir(), 'stigmergy-*'),
|
|
156
|
+
path.join(runner.projectRoot, 'temp'),
|
|
157
|
+
path.join(runner.projectRoot, 'coverage')
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
for (const pattern of tempDirs) {
|
|
161
|
+
try {
|
|
162
|
+
if (!pattern.includes('*')) {
|
|
163
|
+
await fs.rm(pattern, { recursive: true, force: true });
|
|
164
|
+
}
|
|
165
|
+
} catch (err) {
|
|
166
|
+
// Ignore non-existent directories
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}, { category: 'Environment Prep' });
|
|
170
|
+
|
|
171
|
+
// ==================== Phase 2: Core Command Testing ====================
|
|
172
|
+
console.log('\n' + '='.repeat(60));
|
|
173
|
+
console.log('Phase 2: Stigmergy Core Command Testing');
|
|
174
|
+
console.log('='.repeat(60));
|
|
175
|
+
|
|
176
|
+
await runner.test('stigmergy --version', () => {
|
|
177
|
+
const output = runner.exec('node bin/stigmergy --version', { silent: true });
|
|
178
|
+
if (!output.includes('1.2')) {
|
|
179
|
+
throw new Error('Version number incorrect');
|
|
180
|
+
}
|
|
181
|
+
}, { category: 'Core Commands' });
|
|
182
|
+
|
|
183
|
+
await runner.test('stigmergy --help', () => {
|
|
184
|
+
const output = runner.exec('node bin/stigmergy --help', { silent: true });
|
|
185
|
+
if (!output.includes('skill')) {
|
|
186
|
+
throw new Error('Help output missing skill command');
|
|
187
|
+
}
|
|
188
|
+
}, { category: 'Core Commands' });
|
|
189
|
+
|
|
190
|
+
await runner.test('stigmergy diagnostic', () => {
|
|
191
|
+
runner.exec('node bin/stigmergy d', { timeout: 60000 });
|
|
192
|
+
}, { category: 'Core Commands' });
|
|
193
|
+
|
|
194
|
+
await runner.test('stigmergy status', () => {
|
|
195
|
+
runner.exec('node bin/stigmergy status', { timeout: 60000 });
|
|
196
|
+
}, { category: 'Core Commands' });
|
|
197
|
+
|
|
198
|
+
// ==================== Phase 3: Skill System Command Testing ====================
|
|
199
|
+
console.log('\n' + '='.repeat(60));
|
|
200
|
+
console.log('Phase 3: Skill System Command Testing');
|
|
201
|
+
console.log('='.repeat(60));
|
|
202
|
+
|
|
203
|
+
await runner.test('skill list (full command)', () => {
|
|
204
|
+
runner.exec('node bin/stigmergy skill list');
|
|
205
|
+
}, { category: 'Skill Commands' });
|
|
206
|
+
|
|
207
|
+
await runner.test('skill-l (short command)', () => {
|
|
208
|
+
runner.exec('node bin/stigmergy skill-l');
|
|
209
|
+
}, { category: 'Skill Commands' });
|
|
210
|
+
|
|
211
|
+
await runner.test('skill sync (full command)', () => {
|
|
212
|
+
runner.exec('node bin/stigmergy skill sync');
|
|
213
|
+
}, { category: 'Skill Commands' });
|
|
214
|
+
|
|
215
|
+
await runner.test('skill (short command - default sync)', () => {
|
|
216
|
+
runner.exec('node bin/stigmergy skill');
|
|
217
|
+
}, { category: 'Skill Commands' });
|
|
218
|
+
|
|
219
|
+
await runner.test('skill-r (read skill)', async () => {
|
|
220
|
+
// Get skill list first
|
|
221
|
+
const listOutput = runner.exec('node bin/stigmergy skill-l', { silent: true });
|
|
222
|
+
|
|
223
|
+
// Extract first skill name
|
|
224
|
+
const match = listOutput.match(/• ([a-z-]+)/);
|
|
225
|
+
if (!match) {
|
|
226
|
+
throw new Error('SKIP: No skills installed');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const skillName = match[1];
|
|
230
|
+
console.log(` [INFO] Reading skill: ${skillName}`);
|
|
231
|
+
|
|
232
|
+
runner.exec(`node bin/stigmergy skill-r ${skillName}`, { timeout: 10000 });
|
|
233
|
+
}, { category: 'Skill Commands', allowSkip: true });
|
|
234
|
+
|
|
235
|
+
await runner.test('skill-v (validate skill)', async () => {
|
|
236
|
+
// Find first SKILL.md file
|
|
237
|
+
const skillsDir = path.join(os.homedir(), '.claude/skills');
|
|
238
|
+
try {
|
|
239
|
+
const dirs = await fs.readdir(skillsDir);
|
|
240
|
+
if (dirs.length === 0) {
|
|
241
|
+
throw new Error('SKIP: No skill directories found');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const firstSkill = dirs[0];
|
|
245
|
+
const skillPath = path.join(skillsDir, firstSkill, 'SKILL.md');
|
|
246
|
+
|
|
247
|
+
runner.exec(`node bin/stigmergy skill-v ${skillPath}`, { timeout: 10000, allowFail: true });
|
|
248
|
+
} catch (err) {
|
|
249
|
+
throw new Error('SKIP: Cannot access skills directory');
|
|
250
|
+
}
|
|
251
|
+
}, { category: 'Skill Commands', allowSkip: true });
|
|
252
|
+
|
|
253
|
+
// ==================== Phase 4: Config File Sync Verification ====================
|
|
254
|
+
console.log('\n' + '='.repeat(60));
|
|
255
|
+
console.log('Phase 4: Config File Sync Verification');
|
|
256
|
+
console.log('='.repeat(60));
|
|
257
|
+
|
|
258
|
+
const cliConfigFiles = [
|
|
259
|
+
'AGENTS.md', 'claude.md', 'qwen.md', 'gemini.md',
|
|
260
|
+
'iflow.md', 'qodercli.md', 'codebuddy.md', 'copilot.md', 'codex.md'
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const fileName of cliConfigFiles) {
|
|
264
|
+
await runner.test(`Verify ${fileName} sync`, async () => {
|
|
265
|
+
const filePath = path.join(runner.projectRoot, fileName);
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
269
|
+
|
|
270
|
+
if (!content.includes('<!-- SKILLS_START -->')) {
|
|
271
|
+
console.log(` [INFO] ${fileName} has no skills section (may not be synced yet)`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!content.includes('<!-- SKILLS_END -->')) {
|
|
276
|
+
throw new Error('Missing SKILLS_END marker');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!content.includes('<available_skills>')) {
|
|
280
|
+
throw new Error('Missing available_skills tag');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
console.log(` [OK] ${fileName} format correct`);
|
|
284
|
+
} catch (err) {
|
|
285
|
+
if (err.code === 'ENOENT') {
|
|
286
|
+
throw new Error(`SKIP: ${fileName} does not exist`);
|
|
287
|
+
}
|
|
288
|
+
throw err;
|
|
289
|
+
}
|
|
290
|
+
}, { category: 'Config Sync', allowSkip: true });
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ==================== Phase 5: CLI Tool Availability Check ====================
|
|
294
|
+
console.log('\n' + '='.repeat(60));
|
|
295
|
+
console.log('Phase 5: CLI Tool Availability Check');
|
|
296
|
+
console.log('='.repeat(60));
|
|
297
|
+
|
|
298
|
+
const cliTools = ['claude', 'qwen', 'gemini', 'iflow', 'qodercli', 'codebuddy', 'copilot', 'codex'];
|
|
299
|
+
const availableCLIs = [];
|
|
300
|
+
|
|
301
|
+
for (const tool of cliTools) {
|
|
302
|
+
await runner.test(`Check ${tool} CLI`, () => {
|
|
303
|
+
try {
|
|
304
|
+
const result = spawnSync(process.platform === 'win32' ? 'where' : 'which', [tool], {
|
|
305
|
+
encoding: 'utf-8',
|
|
306
|
+
timeout: 3000,
|
|
307
|
+
stdio: 'pipe'
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (result.status === 0 && result.stdout.trim()) {
|
|
311
|
+
console.log(` [OK] ${tool} installed: ${result.stdout.trim().split('\n')[0]}`);
|
|
312
|
+
availableCLIs.push(tool);
|
|
313
|
+
} else {
|
|
314
|
+
throw new Error(`SKIP: ${tool} not installed`);
|
|
315
|
+
}
|
|
316
|
+
} catch (err) {
|
|
317
|
+
throw new Error(`SKIP: ${tool} not installed`);
|
|
318
|
+
}
|
|
319
|
+
}, { category: 'CLI Availability', allowSkip: true });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
console.log(`\n [LIST] Available CLIs: ${availableCLIs.length}/${cliTools.length}`);
|
|
323
|
+
|
|
324
|
+
// ==================== Phase 6: Cross-Call Testing ====================
|
|
325
|
+
console.log('\n' + '='.repeat(60));
|
|
326
|
+
console.log('Phase 6: CLI Cross-Call Testing');
|
|
327
|
+
console.log('='.repeat(60));
|
|
328
|
+
|
|
329
|
+
if (availableCLIs.length === 0) {
|
|
330
|
+
console.log('[INFO] No available CLI tools, skipping cross-call tests');
|
|
331
|
+
} else {
|
|
332
|
+
for (const cli of availableCLIs.slice(0, 3)) { // Test first 3 available CLIs
|
|
333
|
+
await runner.test(`Cross-call ${cli}`, () => {
|
|
334
|
+
try {
|
|
335
|
+
// Use simple test prompt
|
|
336
|
+
const testPrompt = 'hello';
|
|
337
|
+
console.log(` [INFO] Test prompt: "${testPrompt}"`);
|
|
338
|
+
|
|
339
|
+
runner.exec(`node bin/stigmergy ${cli} "${testPrompt}"`, {
|
|
340
|
+
timeout: 30000,
|
|
341
|
+
allowFail: true,
|
|
342
|
+
stdio: 'ignore'
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
console.log(` [OK] ${cli} cross-call successful`);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
// Some CLIs may require authentication, not a failure
|
|
348
|
+
if (err.message.includes('authentication') || err.message.includes('login')) {
|
|
349
|
+
throw new Error(`SKIP: ${cli} requires authentication`);
|
|
350
|
+
}
|
|
351
|
+
throw err;
|
|
352
|
+
}
|
|
353
|
+
}, { category: 'CLI Cross-Call', allowSkip: true });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ==================== Phase 7: Skill Usage Testing ====================
|
|
358
|
+
console.log('\n' + '='.repeat(60));
|
|
359
|
+
console.log('Phase 7: Skill Usage Testing');
|
|
360
|
+
console.log('='.repeat(60));
|
|
361
|
+
|
|
362
|
+
await runner.test('Read skill from local', async () => {
|
|
363
|
+
const listOutput = runner.exec('node bin/stigmergy skill-l', { silent: true });
|
|
364
|
+
|
|
365
|
+
if (!listOutput.includes('•')) {
|
|
366
|
+
throw new Error('SKIP: No skills installed');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Extract first skill name
|
|
370
|
+
const match = listOutput.match(/• ([a-z-]+)/);
|
|
371
|
+
if (!match) {
|
|
372
|
+
throw new Error('SKIP: Cannot parse skill name');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const skillName = match[1];
|
|
376
|
+
console.log(` [INFO] Testing skill: ${skillName}`);
|
|
377
|
+
|
|
378
|
+
const readOutput = runner.exec(`node bin/stigmergy skill-r ${skillName}`, {
|
|
379
|
+
silent: true,
|
|
380
|
+
timeout: 15000
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
if (!readOutput.includes('---')) {
|
|
384
|
+
throw new Error('Skill content format incorrect');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log(` [OK] Skill read successfully, content length: ${readOutput.length} characters`);
|
|
388
|
+
}, { category: 'Skill Usage', allowSkip: true });
|
|
389
|
+
|
|
390
|
+
await runner.test('Skill install test (simulated)', async () => {
|
|
391
|
+
// Test install command syntax and parameter handling
|
|
392
|
+
try {
|
|
393
|
+
const output = runner.exec('node bin/stigmergy skill install --help', {
|
|
394
|
+
silent: true,
|
|
395
|
+
allowFail: true,
|
|
396
|
+
timeout: 5000
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
console.log(' [OK] skill install command available');
|
|
400
|
+
} catch (err) {
|
|
401
|
+
// If no --help, try empty parameters
|
|
402
|
+
try {
|
|
403
|
+
runner.exec('node bin/stigmergy skill-i', {
|
|
404
|
+
silent: true,
|
|
405
|
+
allowFail: true,
|
|
406
|
+
timeout: 5000
|
|
407
|
+
});
|
|
408
|
+
} catch (innerErr) {
|
|
409
|
+
// Expected to fail (due to missing parameters), but should not be syntax error
|
|
410
|
+
if (innerErr.message.includes('SyntaxError')) {
|
|
411
|
+
throw new Error('Command has syntax error');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
console.log(' [OK] skill-i short command available');
|
|
415
|
+
}
|
|
416
|
+
}, { category: 'Skill Usage' });
|
|
417
|
+
|
|
418
|
+
// ==================== Phase 8: Unit Test Regression ====================
|
|
419
|
+
console.log('\n' + '='.repeat(60));
|
|
420
|
+
console.log('Phase 8: Unit Test Regression');
|
|
421
|
+
console.log('='.repeat(60));
|
|
422
|
+
|
|
423
|
+
await runner.test('SkillParser unit test', () => {
|
|
424
|
+
runner.exec('node src/core/skills/test-runner.js', { timeout: 30000 });
|
|
425
|
+
}, { category: 'Unit Tests' });
|
|
426
|
+
|
|
427
|
+
await runner.test('Integration test', () => {
|
|
428
|
+
runner.exec('node src/core/skills/integration-test.js', { timeout: 60000 });
|
|
429
|
+
}, { category: 'Integration Tests' });
|
|
430
|
+
|
|
431
|
+
await runner.test('Sync functionality test', () => {
|
|
432
|
+
runner.exec('node src/core/skills/sync-test.js', { timeout: 30000 });
|
|
433
|
+
}, { category: 'Integration Tests' });
|
|
434
|
+
|
|
435
|
+
// ==================== Test Summary ====================
|
|
436
|
+
const success = runner.summary();
|
|
437
|
+
|
|
438
|
+
// Generate test report file
|
|
439
|
+
const reportPath = path.join(runner.projectRoot, `comprehensive-e2e-report-${Date.now()}.json`);
|
|
440
|
+
await fs.writeFile(
|
|
441
|
+
reportPath,
|
|
442
|
+
JSON.stringify({
|
|
443
|
+
timestamp: new Date().toISOString(),
|
|
444
|
+
summary: {
|
|
445
|
+
total: runner.passed + runner.failed + runner.skipped,
|
|
446
|
+
passed: runner.passed,
|
|
447
|
+
failed: runner.failed,
|
|
448
|
+
skipped: runner.skipped
|
|
449
|
+
},
|
|
450
|
+
availableCLIs,
|
|
451
|
+
results: runner.testResults
|
|
452
|
+
}, null, 2)
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
console.log(`\n[INFO] Detailed report saved: ${reportPath}`);
|
|
456
|
+
|
|
457
|
+
if (success) {
|
|
458
|
+
console.log('\n[SUCCESS] All critical tests passed!');
|
|
459
|
+
return 0;
|
|
460
|
+
} else {
|
|
461
|
+
console.log('\n[INFO] Some tests failed, please review detailed report');
|
|
462
|
+
return 1;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Run comprehensive tests
|
|
467
|
+
console.log('Starting comprehensive end-to-end tests...\n');
|
|
468
|
+
runComprehensiveTests()
|
|
469
|
+
.then(code => process.exit(code))
|
|
470
|
+
.catch(err => {
|
|
471
|
+
console.error('[X] Test execution failed:', err);
|
|
472
|
+
process.exit(1);
|
|
473
|
+
});
|