stigmergy 1.1.6 โ†’ 1.2.0

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.
@@ -21,7 +21,7 @@ const CLI_TOOLS = {
21
21
  qwen: {
22
22
  name: 'Qwen CLI',
23
23
  version: 'qwen --version',
24
- install: 'npm install -g @alibaba/qwen-cli',
24
+ install: 'npm install -g @qwen-code/qwen-code',
25
25
  hooksDir: path.join(os.homedir(), '.qwen', 'hooks'),
26
26
  config: path.join(os.homedir(), '.qwen', 'config.json'),
27
27
  },
@@ -0,0 +1,456 @@
1
+ /**
2
+ * Enhanced Stigmergy Installer
3
+ *
4
+ * Automatic cache cleaning before installation with comprehensive error handling
5
+ * and progress reporting.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+ const CacheCleaner = require('./cache_cleaner');
12
+ const StigmergyInstaller = require('./installer');
13
+
14
+ class EnhancedInstaller {
15
+ constructor(options = {}) {
16
+ this.options = {
17
+ cleanBeforeInstall: options.cleanBeforeInstall !== false, // Default true
18
+ cleanNPXCache: options.cleanNPXCache !== false,
19
+ cleanTempFiles: options.cleanTempFiles !== false,
20
+ cleanOldVersions: options.cleanOldVersions !== false,
21
+ dryRun: options.dryRun || false,
22
+ force: options.force || false,
23
+ verbose: options.verbose || false,
24
+ ...options
25
+ };
26
+
27
+ this.baseInstaller = new StigmergyInstaller();
28
+ this.cacheCleaner = new CacheCleaner({
29
+ dryRun: this.options.dryRun,
30
+ force: this.options.force,
31
+ verbose: this.options.verbose
32
+ });
33
+
34
+ this.results = {
35
+ cacheCleaning: {},
36
+ installation: {},
37
+ errors: []
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Perform enhanced installation with automatic cache cleaning
43
+ */
44
+ async enhancedInstall(options = {}) {
45
+ const config = {
46
+ cleanStigmergy: true,
47
+ cleanNPX: this.options.cleanNPXCache,
48
+ cleanNPM: this.options.cleanOldVersions,
49
+ cleanCLI: false,
50
+ cleanTemp: this.options.cleanTempFiles,
51
+ ...options
52
+ };
53
+
54
+ console.log('๐Ÿš€ Starting Enhanced Stigmergy Installation...\n');
55
+
56
+ if (this.options.dryRun) {
57
+ console.log('๐Ÿ” DRY RUN MODE - No actual changes will be made\n');
58
+ }
59
+
60
+ try {
61
+ // Step 1: Pre-installation cache cleaning
62
+ if (this.options.cleanBeforeInstall) {
63
+ await this.preInstallCacheClean(config);
64
+ }
65
+
66
+ // Step 2: Scan and prepare for installation
67
+ await this.scanAndPrepare();
68
+
69
+ // Step 3: Perform installation
70
+ if (!this.options.dryRun) {
71
+ await this.performInstallation();
72
+ }
73
+
74
+ // Step 4: Post-installation verification
75
+ await this.verifyInstallation();
76
+
77
+ // Step 5: Print summary
78
+ this.printSummary();
79
+
80
+ return this.results;
81
+
82
+ } catch (error) {
83
+ console.error('โŒ Enhanced installation failed:', error.message);
84
+ this.results.errors.push(error.message);
85
+ return this.results;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Pre-installation cache cleaning
91
+ */
92
+ async preInstallCacheClean(config) {
93
+ console.log('๐Ÿงน Pre-installation Cache Cleaning...\n');
94
+
95
+ const startTime = Date.now();
96
+
97
+ try {
98
+ // Clean caches before installation
99
+ const cacheResults = await this.cacheCleaner.cleanAllCaches(config);
100
+
101
+ const endTime = Date.now();
102
+ const duration = endTime - startTime;
103
+
104
+ this.results.cacheCleaning = {
105
+ success: true,
106
+ duration,
107
+ filesRemoved: cacheResults.filesRemoved,
108
+ directoriesRemoved: cacheResults.directoriesRemoved,
109
+ bytesFreed: cacheResults.bytesFreed,
110
+ errors: cacheResults.errors.length
111
+ };
112
+
113
+ console.log(`โœ… Cache cleaning completed in ${duration}ms`);
114
+ console.log(`๐Ÿ“Š Removed ${cacheResults.filesRemoved} files, freed ${this.formatBytes(cacheResults.bytesFreed)}\n`);
115
+
116
+ } catch (error) {
117
+ console.error('โŒ Cache cleaning failed:', error.message);
118
+ this.results.cacheCleaning = {
119
+ success: false,
120
+ error: error.message
121
+ };
122
+
123
+ if (!this.options.force) {
124
+ throw new Error(`Cache cleaning failed: ${error.message}`);
125
+ }
126
+
127
+ console.log('โš ๏ธ Continuing installation despite cache cleaning errors...\n');
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Scan system and prepare for installation
133
+ */
134
+ async scanAndPrepare() {
135
+ console.log('๐Ÿ” Scanning System for Installation...\n');
136
+
137
+ try {
138
+ // Check system requirements
139
+ await this.checkSystemRequirements();
140
+
141
+ // Scan for existing CLI tools
142
+ const scanResult = await this.baseInstaller.scanCLI();
143
+
144
+ console.log(`โœ… System scan completed`);
145
+ console.log(`๐Ÿ“Š Found ${Object.keys(scanResult.available).length} available CLI tools`);
146
+ console.log(`๐Ÿ“Š Missing ${Object.keys(scanResult.missing).length} CLI tools\n`);
147
+
148
+ this.results.scan = scanResult;
149
+
150
+ } catch (error) {
151
+ console.error('โŒ System scan failed:', error.message);
152
+ throw error;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Perform the actual installation
158
+ */
159
+ async performInstallation() {
160
+ console.log('๐Ÿ“ฆ Performing Installation...\n');
161
+
162
+ try {
163
+ // Interactive tool selection would go here
164
+ // For now, we'll use a simple approach
165
+ const missingTools = Object.keys(this.results.scan.missing);
166
+
167
+ if (missingTools.length === 0) {
168
+ console.log('โ„น๏ธ All CLI tools are already installed');
169
+ this.results.installation = {
170
+ success: true,
171
+ installed: [],
172
+ message: 'No tools needed installation'
173
+ };
174
+ return;
175
+ }
176
+
177
+ console.log(`๐Ÿ“ฆ Installing ${missingTools.length} CLI tools...`);
178
+
179
+ // Install missing tools
180
+ const installResult = await this.baseInstaller.installTools(
181
+ missingTools,
182
+ this.results.scan.missing
183
+ );
184
+
185
+ this.results.installation = {
186
+ success: true,
187
+ installed: missingTools,
188
+ result: installResult
189
+ };
190
+
191
+ console.log(`โœ… Installation completed`);
192
+
193
+ } catch (error) {
194
+ console.error('โŒ Installation failed:', error.message);
195
+ this.results.installation = {
196
+ success: false,
197
+ error: error.message
198
+ };
199
+ throw error;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Post-installation verification
205
+ */
206
+ async verifyInstallation() {
207
+ console.log('\nโœ… Post-installation Verification...');
208
+
209
+ try {
210
+ // Verify installation was successful
211
+ const postScan = await this.baseInstaller.scanCLI();
212
+
213
+ const verificationResults = {
214
+ beforeCount: Object.keys(this.results.scan.available).length,
215
+ afterCount: Object.keys(postScan.available).length,
216
+ newlyInstalled: []
217
+ };
218
+
219
+ // Find newly installed tools
220
+ for (const tool of Object.keys(postScan.available)) {
221
+ if (!this.results.scan.available[tool]) {
222
+ verificationResults.newlyInstalled.push(tool);
223
+ }
224
+ }
225
+
226
+ this.results.verification = verificationResults;
227
+
228
+ console.log(`๐Ÿ“Š CLI tools before: ${verificationResults.beforeCount}`);
229
+ console.log(`๐Ÿ“Š CLI tools after: ${verificationResults.afterCount}`);
230
+ console.log(`๐Ÿ“Š Newly installed: ${verificationResults.newlyInstalled.length}`);
231
+
232
+ if (verificationResults.newlyInstalled.length > 0) {
233
+ console.log(`โœ… Successfully installed: ${verificationResults.newlyInstalled.join(', ')}`);
234
+ }
235
+
236
+ console.log('โœ… Installation verification completed\n');
237
+
238
+ } catch (error) {
239
+ console.error('โŒ Verification failed:', error.message);
240
+ this.results.errors.push(`Verification: ${error.message}`);
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Check system requirements
246
+ */
247
+ async checkSystemRequirements() {
248
+ console.log('๐Ÿ”ง Checking System Requirements...');
249
+
250
+ // Check Node.js version
251
+ const nodeVersion = process.version;
252
+ const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
253
+
254
+ if (majorVersion < 14) {
255
+ throw new Error(`Node.js version ${nodeVersion} is not supported. Please use Node.js 14 or higher.`);
256
+ }
257
+
258
+ console.log(` โœ… Node.js: ${nodeVersion}`);
259
+
260
+ // Check npm availability
261
+ try {
262
+ const { spawnSync } = require('child_process');
263
+ const npmResult = spawnSync('npm', ['--version'], {
264
+ encoding: 'utf8',
265
+ shell: true
266
+ });
267
+
268
+ if (npmResult.status === 0) {
269
+ console.log(` โœ… npm: ${npmResult.stdout.trim()}`);
270
+ } else {
271
+ throw new Error('npm is not available');
272
+ }
273
+ } catch (error) {
274
+ throw new Error('npm is required but not found');
275
+ }
276
+
277
+ // Check available disk space (basic check)
278
+ const homeDir = os.homedir();
279
+ try {
280
+ const stats = fs.statSync(homeDir);
281
+ console.log(` โœ… Home directory accessible: ${homeDir}`);
282
+ } catch (error) {
283
+ throw new Error(`Cannot access home directory: ${homeDir}`);
284
+ }
285
+
286
+ console.log('โœ… System requirements check passed\n');
287
+ }
288
+
289
+ /**
290
+ * Create installation plan without executing
291
+ */
292
+ async createInstallationPlan() {
293
+ console.log('๐Ÿ“‹ Creating Installation Plan...\n');
294
+
295
+ const plan = {
296
+ cacheCleaning: {},
297
+ installation: {},
298
+ estimatedTime: 0,
299
+ estimatedSpace: 0
300
+ };
301
+
302
+ try {
303
+ // Check what would be cleaned
304
+ const stigmergyDir = path.join(os.homedir(), '.stigmergy');
305
+ if (fs.existsSync(stigmergyDir)) {
306
+ const cacheSize = await this.calculateDirectorySize(stigmergyDir);
307
+ plan.cacheCleaning.stigmergyCache = {
308
+ path: stigmergyDir,
309
+ size: cacheSize,
310
+ wouldClean: this.options.cleanBeforeInstall
311
+ };
312
+ plan.estimatedSpace += cacheSize;
313
+ }
314
+
315
+ // Scan for missing CLI tools
316
+ const scanResult = await this.baseInstaller.scanCLI();
317
+ const missingTools = Object.keys(scanResult.missing);
318
+
319
+ plan.installation = {
320
+ missingTools: missingTools,
321
+ toolCount: missingTools.length,
322
+ tools: missingTools.map(tool => ({
323
+ name: scanResult.missing[tool].name,
324
+ installCommand: scanResult.missing[tool].install
325
+ }))
326
+ };
327
+
328
+ // Estimate time (very rough estimate)
329
+ plan.estimatedTime = missingTools.length * 30000; // 30 seconds per tool
330
+
331
+ console.log(`๐Ÿ“Š Installation Plan Summary:`);
332
+ console.log(` ๐Ÿงน Cache cleaning: ${this.options.cleanBeforeInstall ? 'Yes' : 'No'}`);
333
+ console.log(` ๐Ÿ“ฆ Tools to install: ${missingTools.length}`);
334
+ console.log(` โฑ๏ธ Estimated time: ${Math.ceil(plan.estimatedTime / 1000)} seconds`);
335
+ console.log(` ๐Ÿ’พ Estimated space: ${this.formatBytes(plan.estimatedSpace)}`);
336
+
337
+ return plan;
338
+
339
+ } catch (error) {
340
+ console.error('โŒ Failed to create installation plan:', error.message);
341
+ throw error;
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Quick cache clean only
347
+ */
348
+ async quickCacheClean() {
349
+ console.log('โšก Quick Cache Clean Only...\n');
350
+
351
+ try {
352
+ const results = await this.cacheCleaner.cleanAllCaches({
353
+ cleanStigmergy: false, // Don't clean main config
354
+ cleanNPX: true,
355
+ cleanNPM: false,
356
+ cleanCLI: false,
357
+ cleanTemp: true
358
+ });
359
+
360
+ console.log(`โœ… Quick cache clean completed`);
361
+ console.log(`๐Ÿ“Š Removed ${results.filesRemoved} files, freed ${this.formatBytes(results.bytesFreed)}`);
362
+
363
+ return results;
364
+
365
+ } catch (error) {
366
+ console.error('โŒ Quick cache clean failed:', error.message);
367
+ throw error;
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Helper methods
373
+ */
374
+ async calculateDirectorySize(dirPath) {
375
+ let totalSize = 0;
376
+
377
+ try {
378
+ const items = fs.readdirSync(dirPath, { withFileTypes: true });
379
+
380
+ for (const item of items) {
381
+ const fullPath = path.join(dirPath, item.name);
382
+
383
+ if (item.isDirectory()) {
384
+ totalSize += await this.calculateDirectorySize(fullPath);
385
+ } else {
386
+ try {
387
+ const stat = fs.statSync(fullPath);
388
+ totalSize += stat.size;
389
+ } catch (error) {
390
+ // Skip files we can't stat
391
+ }
392
+ }
393
+ }
394
+ } catch (error) {
395
+ // Return 0 for directories we can't read
396
+ }
397
+
398
+ return totalSize;
399
+ }
400
+
401
+ formatBytes(bytes) {
402
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
403
+ if (bytes === 0) return '0 Bytes';
404
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
405
+ return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
406
+ }
407
+
408
+ printSummary() {
409
+ console.log('\n๐Ÿ“Š ENHANCED INSTALLATION SUMMARY:');
410
+ console.log('=' .repeat(50));
411
+
412
+ if (this.options.dryRun) {
413
+ console.log('๐Ÿ” DRY RUN MODE - No actual changes were made');
414
+ }
415
+
416
+ // Cache cleaning summary
417
+ if (this.results.cacheCleaning.success) {
418
+ console.log(`๐Ÿงน Cache Cleaning: โœ…`);
419
+ console.log(` Duration: ${this.results.cacheCleaning.duration}ms`);
420
+ console.log(` Files removed: ${this.results.cacheCleaning.filesRemoved}`);
421
+ console.log(` Space freed: ${this.formatBytes(this.results.cacheCleaning.bytesFreed)}`);
422
+ } else if (this.results.cacheCleaning.error) {
423
+ console.log(`๐Ÿงน Cache Cleaning: โŒ ${this.results.cacheCleaning.error}`);
424
+ }
425
+
426
+ // Installation summary
427
+ if (this.results.installation.success) {
428
+ console.log(`๐Ÿ“ฆ Installation: โœ…`);
429
+ if (this.results.installation.installed.length > 0) {
430
+ console.log(` Installed: ${this.results.installation.installed.join(', ')}`);
431
+ } else {
432
+ console.log(` Message: ${this.results.installation.message}`);
433
+ }
434
+ } else if (this.results.installation.error) {
435
+ console.log(`๐Ÿ“ฆ Installation: โŒ ${this.results.installation.error}`);
436
+ }
437
+
438
+ // Verification summary
439
+ if (this.results.verification) {
440
+ console.log(`โœ… Verification: โœ…`);
441
+ console.log(` Newly installed: ${this.results.verification.newlyInstalled.length} tools`);
442
+ }
443
+
444
+ // Errors
445
+ if (this.results.errors.length > 0) {
446
+ console.log(`\nโŒ Errors encountered: ${this.results.errors.length}`);
447
+ this.results.errors.forEach(error => {
448
+ console.log(` - ${error}`);
449
+ });
450
+ }
451
+
452
+ console.log('\n๐ŸŽ‰ Enhanced installation completed!');
453
+ }
454
+ }
455
+
456
+ module.exports = EnhancedInstaller;