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.
Files changed (48) hide show
  1. package/README.md +40 -6
  2. package/STIGMERGY.md +10 -0
  3. package/package.json +19 -5
  4. package/scripts/preuninstall.js +10 -0
  5. package/src/adapters/claude/install_claude_integration.js +21 -21
  6. package/src/adapters/codebuddy/install_codebuddy_integration.js +54 -51
  7. package/src/adapters/codex/install_codex_integration.js +27 -28
  8. package/src/adapters/gemini/install_gemini_integration.js +60 -60
  9. package/src/adapters/iflow/install_iflow_integration.js +72 -72
  10. package/src/adapters/qoder/install_qoder_integration.js +64 -64
  11. package/src/adapters/qwen/install_qwen_integration.js +7 -7
  12. package/src/cli/router.js +581 -175
  13. package/src/commands/skill-bridge.js +39 -0
  14. package/src/commands/skill-handler.js +150 -0
  15. package/src/commands/skill.js +127 -0
  16. package/src/core/cli_path_detector.js +573 -0
  17. package/src/core/cli_tools.js +72 -1
  18. package/src/core/coordination/nodejs/AdapterManager.js +29 -1
  19. package/src/core/directory_permission_manager.js +568 -0
  20. package/src/core/enhanced_cli_installer.js +609 -0
  21. package/src/core/installer.js +232 -88
  22. package/src/core/multilingual/language-pattern-manager.js +78 -50
  23. package/src/core/persistent_shell_configurator.js +468 -0
  24. package/src/core/skills/StigmergySkillManager.js +357 -0
  25. package/src/core/skills/__tests__/SkillInstaller.test.js +275 -0
  26. package/src/core/skills/__tests__/SkillParser.test.js +202 -0
  27. package/src/core/skills/__tests__/SkillReader.test.js +189 -0
  28. package/src/core/skills/cli-command-test.js +201 -0
  29. package/src/core/skills/comprehensive-e2e-test.js +473 -0
  30. package/src/core/skills/e2e-test.js +267 -0
  31. package/src/core/skills/embedded-openskills/SkillInstaller.js +438 -0
  32. package/src/core/skills/embedded-openskills/SkillParser.js +123 -0
  33. package/src/core/skills/embedded-openskills/SkillReader.js +143 -0
  34. package/src/core/skills/integration-test.js +248 -0
  35. package/src/core/skills/package.json +6 -0
  36. package/src/core/skills/regression-test.js +285 -0
  37. package/src/core/skills/run-all-tests.js +129 -0
  38. package/src/core/skills/sync-test.js +210 -0
  39. package/src/core/skills/test-runner.js +242 -0
  40. package/src/utils/helpers.js +3 -20
  41. package/src/auth.js +0 -173
  42. package/src/auth_command.js +0 -208
  43. package/src/calculator.js +0 -313
  44. package/src/core/enhanced_installer.js +0 -479
  45. package/src/core/enhanced_uninstaller.js +0 -638
  46. package/src/data_encryption.js +0 -143
  47. package/src/data_structures.js +0 -440
  48. package/src/deploy.js +0 -55
@@ -0,0 +1,568 @@
1
+ /**
2
+ * Directory Permission Manager
3
+ *
4
+ * Handles automatic detection and resolution of directory permission issues
5
+ * for Stigmergy CLI installations, particularly for macOS/Linux users
6
+ * who start terminals in system directories without write permissions.
7
+ */
8
+
9
+ const fs = require('fs').promises;
10
+ const path = require('path');
11
+ const os = require('os');
12
+ const { execSync } = require('child_process');
13
+
14
+ class DirectoryPermissionManager {
15
+ constructor(options = {}) {
16
+ this.options = {
17
+ verbose: options.verbose || false,
18
+ fallbackDir: options.fallbackDir || null,
19
+ createStigmergyDir: options.createStigmergyDir !== false,
20
+ ...options
21
+ };
22
+
23
+ this.results = {
24
+ originalDir: process.cwd(),
25
+ workingDir: null,
26
+ hasWritePermission: false,
27
+ createdDirectories: [],
28
+ npmConfigured: false
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Log messages based on verbosity setting
34
+ */
35
+ log(level, message, data = null) {
36
+ const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
37
+ const prefix = `[${level.toUpperCase()}] ${timestamp}`;
38
+
39
+ if (level === 'error') {
40
+ console.error(`${prefix} ${message}`);
41
+ } else if (level === 'warn') {
42
+ console.warn(`${prefix} ${message}`);
43
+ } else if (this.options.verbose || level === 'info' || level === 'success') {
44
+ console.log(`${prefix} ${message}`);
45
+ }
46
+
47
+ if (data && this.options.verbose) {
48
+ console.log(' Data:', JSON.stringify(data, null, 2));
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Check if current directory has write permission
54
+ */
55
+ async checkWritePermission(dir = process.cwd()) {
56
+ try {
57
+ const testFile = path.join(dir, '.stigmergy-permission-test');
58
+ await fs.writeFile(testFile, 'test', { flag: 'w' });
59
+ await fs.unlink(testFile);
60
+ return true;
61
+ } catch (error) {
62
+ this.log('debug', `Write permission check failed for ${dir}: ${error.message}`);
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Get home directory with fallback (Windows + Unix support)
69
+ */
70
+ getHomeDirectory() {
71
+ const homeDir = os.homedir();
72
+
73
+ // Windows-specific fallbacks
74
+ if (process.platform === 'win32') {
75
+ if (!homeDir) {
76
+ // Try Windows-specific user directories
77
+ const windowsFallbacks = [
78
+ process.env.USERPROFILE,
79
+ path.join('C:', 'Users', process.env.USERNAME || 'Default'),
80
+ path.join('C:', 'Users', 'Public', 'Documents'),
81
+ path.join(process.env.LOCALAPPDATA || 'C:\\temp'),
82
+ process.env.TEMP || process.env.TMP || 'C:\\temp'
83
+ ];
84
+
85
+ for (const dir of windowsFallbacks) {
86
+ try {
87
+ if (dir && fs.existsSync(dir)) {
88
+ this.log('debug', `Windows fallback found: ${dir}`);
89
+ return dir;
90
+ }
91
+ } catch (error) {
92
+ continue;
93
+ }
94
+ }
95
+ }
96
+ return homeDir;
97
+ }
98
+
99
+ // Unix/Linux/macOS fallbacks
100
+ if (!homeDir || homeDir === '/') {
101
+ const unixFallbacks = [
102
+ path.join('/Users', process.env.USER || 'user'),
103
+ path.join('/home', process.env.USER || 'user'),
104
+ '/tmp',
105
+ os.tmpdir()
106
+ ];
107
+
108
+ for (const dir of unixFallbacks) {
109
+ try {
110
+ if (fs.existsSync(dir)) {
111
+ return dir;
112
+ }
113
+ } catch (error) {
114
+ continue;
115
+ }
116
+ }
117
+ }
118
+
119
+ return homeDir;
120
+ }
121
+
122
+ /**
123
+ * Find the nearest directory with write permission (Windows + Unix)
124
+ */
125
+ async findWritableDirectory(startDir = process.cwd()) {
126
+ this.log('info', `Checking write permissions starting from: ${startDir}`);
127
+
128
+ // Check current directory first
129
+ if (await this.checkWritePermission(startDir)) {
130
+ this.log('success', `Current directory has write permission: ${startDir}`);
131
+ return { dir: startDir, created: false, reason: 'current_directory' };
132
+ }
133
+
134
+ // Platform-specific directory search
135
+ let userDirs = [];
136
+
137
+ if (process.platform === 'win32') {
138
+ // Windows-specific directories
139
+ const homeDir = this.getHomeDirectory();
140
+ userDirs = [
141
+ homeDir,
142
+ path.join(homeDir, 'Desktop'),
143
+ path.join(homeDir, 'Documents'),
144
+ path.join(homeDir, 'Downloads'),
145
+ path.join(homeDir, 'Projects'),
146
+ path.join(homeDir, 'Development'),
147
+ path.join(process.env.LOCALAPPDATA || '', 'Temp'),
148
+ process.env.TEMP || process.env.TMP,
149
+ path.join('C:', 'temp'),
150
+ path.join('C:', 'Users', process.env.USERNAME || 'Default', 'Documents'),
151
+ path.join(homeDir, 'AppData', 'Local'),
152
+ os.tmpdir()
153
+ ];
154
+ } else {
155
+ // Unix/Linux/macOS directories
156
+ const homeDir = this.getHomeDirectory();
157
+ userDirs = [
158
+ homeDir,
159
+ path.join(homeDir, 'Desktop'),
160
+ path.join(homeDir, 'Documents'),
161
+ path.join(homeDir, 'Downloads'),
162
+ path.join(homeDir, 'Projects'),
163
+ path.join(homeDir, 'Development'),
164
+ os.tmpdir(),
165
+ '/tmp',
166
+ '/var/tmp'
167
+ ];
168
+ }
169
+
170
+ for (const dir of userDirs) {
171
+ try {
172
+ // Check if directory exists
173
+ await fs.access(dir);
174
+
175
+ if (await this.checkWritePermission(dir)) {
176
+ this.log('success', `Found writable directory: ${dir}`);
177
+ return { dir, created: false, reason: 'existing_directory' };
178
+ }
179
+ } catch (error) {
180
+ this.log('debug', `Directory not accessible: ${dir} - ${error.message}`);
181
+ continue;
182
+ }
183
+ }
184
+
185
+ // Try to create a working directory in home
186
+ const homeDir = this.getHomeDirectory();
187
+ if (homeDir && homeDir !== '/') {
188
+ const stigmergyDir = path.join(homeDir, 'stigmergy-workspace');
189
+
190
+ try {
191
+ await fs.mkdir(stigmergyDir, { recursive: true });
192
+
193
+ if (await this.checkWritePermission(stigmergyDir)) {
194
+ this.log('success', `Created working directory: ${stigmergyDir}`);
195
+ this.results.createdDirectories.push(stigmergyDir);
196
+ return { dir: stigmergyDir, created: true, reason: 'created_directory' };
197
+ }
198
+ } catch (error) {
199
+ this.log('error', `Failed to create working directory: ${error.message}`);
200
+ }
201
+ }
202
+
203
+ // Last resort: use system temp directory
204
+ const tempDir = os.tmpdir();
205
+ try {
206
+ const randomDir = path.join(tempDir, `stigmergy-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`);
207
+ await fs.mkdir(randomDir, { recursive: true });
208
+
209
+ if (await this.checkWritePermission(randomDir)) {
210
+ this.log('warn', `Using temporary directory: ${randomDir}`);
211
+ this.results.createdDirectories.push(randomDir);
212
+ return { dir: randomDir, created: true, reason: 'temporary_directory' };
213
+ }
214
+ } catch (error) {
215
+ this.log('error', `Failed to create temporary directory: ${error.message}`);
216
+ }
217
+
218
+ throw new Error('Could not find or create any writable directory');
219
+ }
220
+
221
+ /**
222
+ * Configure npm to use a directory with write permission
223
+ */
224
+ async configureNpmPrefix(writableDir) {
225
+ this.log('info', 'Configuring npm global prefix...');
226
+
227
+ try {
228
+ // Create npm global directory in writable location
229
+ const npmGlobalDir = path.join(writableDir, '.npm-global');
230
+
231
+ try {
232
+ await fs.mkdir(npmGlobalDir, { recursive: true });
233
+ this.log('success', `Created npm global directory: ${npmGlobalDir}`);
234
+ this.results.createdDirectories.push(npmGlobalDir);
235
+ } catch (error) {
236
+ this.log('debug', `npm global directory may already exist: ${error.message}`);
237
+ }
238
+
239
+ // Set npm prefix for current session
240
+ process.env.npm_config_prefix = npmGlobalDir;
241
+
242
+ // Add to PATH if not already present
243
+ const npmBinDir = path.join(npmGlobalDir, 'bin');
244
+ if (process.env.PATH && !process.env.PATH.includes(npmBinDir)) {
245
+ process.env.PATH = `${npmBinDir}:${process.env.PATH}`;
246
+ }
247
+
248
+ this.results.npmConfigured = true;
249
+ this.log('success', `npm configured to use: ${npmGlobalDir}`);
250
+
251
+ return {
252
+ npmGlobalDir,
253
+ npmBinDir,
254
+ exportCommand: `export npm_config_prefix="${npmGlobalDir}"`,
255
+ pathCommand: `export PATH="${npmBinDir}:$PATH"`
256
+ };
257
+ } catch (error) {
258
+ this.log('error', `Failed to configure npm: ${error.message}`);
259
+ throw error;
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Change to writable directory and configure environment
265
+ */
266
+ async setupWorkingDirectory() {
267
+ this.log('info', 'Setting up working directory with proper permissions...');
268
+
269
+ try {
270
+ // Find writable directory
271
+ const writableResult = await this.findWritableDirectory();
272
+ const { dir: writableDir, created, reason } = writableResult;
273
+
274
+ // Change working directory
275
+ process.chdir(writableDir);
276
+ this.results.workingDir = writableDir;
277
+ this.results.hasWritePermission = true;
278
+
279
+ this.log('info', `Changed working directory to: ${writableDir} (reason: ${reason})`);
280
+
281
+ // Configure npm if needed
282
+ const npmConfig = await this.configureNpmPrefix(writableDir);
283
+
284
+ // Create shell setup instructions
285
+ const setupInstructions = this.generateSetupInstructions(npmConfig);
286
+
287
+ return {
288
+ success: true,
289
+ originalDir: this.results.originalDir,
290
+ workingDir: writableDir,
291
+ created,
292
+ reason,
293
+ npmConfig,
294
+ setupInstructions
295
+ };
296
+
297
+ } catch (error) {
298
+ this.log('error', `Failed to setup working directory: ${error.message}`);
299
+ return {
300
+ success: false,
301
+ error: error.message,
302
+ originalDir: this.results.originalDir
303
+ };
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Generate shell setup instructions (Windows + Unix)
309
+ */
310
+ generateSetupInstructions(npmConfig) {
311
+ const { npmGlobalDir, npmBinDir } = npmConfig;
312
+
313
+ const shellType = this.detectShell();
314
+ const profileFile = this.getShellProfileFile(shellType);
315
+
316
+ let instructions = [];
317
+
318
+ instructions.push('# Stigmergy CLI Environment Setup');
319
+
320
+ // Windows PowerShell instructions
321
+ if (shellType === 'powershell') {
322
+ instructions.push('# PowerShell commands:');
323
+ instructions.push('');
324
+ instructions.push('# Set npm global prefix');
325
+ instructions.push(`$env:npm_config_prefix = "${npmGlobalDir.replace(/\\/g, '\\\\')}"`);
326
+ instructions.push('');
327
+ instructions.push('# Add npm global bin to PATH');
328
+ instructions.push(`$env:PATH = "${npmBinDir.replace(/\\/g, '\\\\')};$env:PATH"`);
329
+ instructions.push('');
330
+ instructions.push('# Make persistent (add to PowerShell profile):');
331
+ instructions.push('# Run these commands manually or copy to your PowerShell profile:');
332
+ instructions.push('');
333
+ instructions.push(`$env:npm_config_prefix = "${npmGlobalDir.replace(/\\/g, '\\\\')}"`);
334
+ instructions.push(`$env:PATH = "${npmBinDir.replace(/\\/g, '\\\\')};$env:PATH"`);
335
+ instructions.push('');
336
+ instructions.push('# To make permanent, add to PowerShell profile:');
337
+ instructions.push(`# Add-Content -Path $PROFILE -Value '$env:npm_config_prefix = "${npmGlobalDir.replace(/\\/g, '\\\\')}"'`);
338
+ instructions.push(`# Add-Content -Path $PROFILE -Value '$env:PATH = "${npmBinDir.replace(/\\/g, '\\\\')};$env:PATH"'`);
339
+ instructions.push('');
340
+ instructions.push('# Reload PowerShell profile:');
341
+ instructions.push('. $PROFILE');
342
+ return instructions.join('\n');
343
+ }
344
+
345
+ // Windows Command Prompt instructions
346
+ if (shellType === 'cmd') {
347
+ instructions.push('# Command Prompt commands:');
348
+ instructions.push('');
349
+ instructions.push('# Set npm global prefix');
350
+ instructions.push(`set npm_config_prefix=${npmGlobalDir}`);
351
+ instructions.push('');
352
+ instructions.push('# Add npm global bin to PATH');
353
+ instructions.push(`set PATH=${npmBinDir};%PATH%`);
354
+ instructions.push('');
355
+ instructions.push('# Make persistent (add to system environment variables):');
356
+ instructions.push('# 1. Open System Properties -> Environment Variables');
357
+ instructions.push(`# 2. Add npm_config_prefix: ${npmGlobalDir}`);
358
+ instructions.push(`# 3. Add to PATH: ${npmBinDir}`);
359
+ instructions.push('');
360
+ instructions.push('# Or run one-time commands:');
361
+ instructions.push(`setx npm_config_prefix "${npmGlobalDir}"`);
362
+ instructions.push(`setx PATH "%PATH%;${npmBinDir}"`);
363
+ return instructions.join('\n');
364
+ }
365
+
366
+ // Unix/Linux/macOS instructions
367
+ instructions.push('# Unix/Linux/macOS commands:');
368
+ instructions.push('');
369
+ instructions.push('# Set npm global prefix');
370
+ instructions.push(`export npm_config_prefix="${npmGlobalDir}"`);
371
+ instructions.push('');
372
+ instructions.push('# Add npm global bin to PATH');
373
+ instructions.push(`export PATH="${npmBinDir}:$PATH"`);
374
+ instructions.push('');
375
+
376
+ if (profileFile) {
377
+ instructions.push(`# Add to ${profileFile}:`);
378
+ instructions.push(`echo 'export npm_config_prefix="${npmGlobalDir}"' >> ${profileFile}`);
379
+ instructions.push(`echo 'export PATH="${npmBinDir}:$PATH"' >> ${profileFile}`);
380
+ instructions.push(`source ${profileFile}`);
381
+ instructions.push('');
382
+ }
383
+
384
+ instructions.push('# Or run this one-time command:');
385
+ if (profileFile) {
386
+ instructions.push(`echo 'export npm_config_prefix="${npmGlobalDir}"\\nexport PATH="${npmBinDir}:$PATH"' >> ${profileFile} && source ${profileFile}`);
387
+ } else {
388
+ instructions.push(`export npm_config_prefix="${npmGlobalDir}"`);
389
+ instructions.push(`export PATH="${npmBinDir}:$PATH"`);
390
+ }
391
+
392
+ return instructions.join('\n');
393
+ }
394
+
395
+ /**
396
+ * Detect current shell (Windows + Unix)
397
+ */
398
+ detectShell() {
399
+ // Windows-specific detection
400
+ if (process.platform === 'win32') {
401
+ // Check for PowerShell
402
+ if (process.env.PSModulePath) return 'powershell';
403
+
404
+ // Check for Command Prompt (cmd)
405
+ if (process.env.COMSPEC && process.env.COMSPEC.includes('cmd.exe')) return 'cmd';
406
+
407
+ // Check for Git Bash on Windows
408
+ if (process.env.SHELL && process.env.SHELL.includes('bash')) return 'bash';
409
+
410
+ // Check for WSL
411
+ if (process.env.WSL_DISTRO_NAME) {
412
+ const shell = process.env.SHELL;
413
+ if (shell && shell.includes('zsh')) return 'zsh';
414
+ if (shell && shell.includes('bash')) return 'bash';
415
+ return 'wsl';
416
+ }
417
+
418
+ return 'powershell'; // Default to PowerShell on Windows
419
+ }
420
+
421
+ // Unix/Linux/macOS detection
422
+ const shell = process.env.SHELL;
423
+ if (!shell) return 'unknown';
424
+
425
+ if (shell.includes('zsh')) return 'zsh';
426
+ if (shell.includes('bash')) return 'bash';
427
+ if (shell.includes('fish')) return 'fish';
428
+ if (shell.includes('csh')) return 'csh';
429
+ if (shell.includes('tcsh')) return 'tcsh';
430
+
431
+ return 'unknown';
432
+ }
433
+
434
+ /**
435
+ * Get shell profile file path (Windows + Unix)
436
+ */
437
+ getShellProfileFile(shellType) {
438
+ const homeDir = this.getHomeDirectory();
439
+
440
+ switch (shellType) {
441
+ case 'powershell':
442
+ // PowerShell profile locations
443
+ return path.join(homeDir, 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1');
444
+
445
+ case 'cmd':
446
+ // Command Prompt doesn't really have profile files, but we can suggest registry or environment
447
+ return null;
448
+
449
+ case 'wsl':
450
+ // WSL uses Linux-style shells
451
+ const shell = process.env.SHELL;
452
+ if (shell && shell.includes('zsh')) return path.join(os.homedir(), '.zshrc');
453
+ if (shell && shell.includes('bash')) return path.join(os.homedir(), '.bashrc');
454
+ return null;
455
+
456
+ case 'zsh':
457
+ return path.join(homeDir, '.zshrc');
458
+
459
+ case 'bash':
460
+ // Check for .bash_profile first, then .bashrc
461
+ if (process.platform === 'win32') {
462
+ // Git Bash on Windows
463
+ return path.join(homeDir, '.bashrc');
464
+ } else {
465
+ // Unix/Linux/macOS
466
+ const bashProfile = path.join(homeDir, '.bash_profile');
467
+ if (fs.existsSync(bashProfile)) {
468
+ return bashProfile;
469
+ }
470
+ return path.join(homeDir, '.bashrc');
471
+ }
472
+
473
+ case 'fish':
474
+ return path.join(homeDir, '.config/fish/config.fish');
475
+
476
+ case 'csh':
477
+ return path.join(homeDir, '.cshrc');
478
+
479
+ case 'tcsh':
480
+ return path.join(homeDir, '.tcshrc');
481
+
482
+ default:
483
+ return null;
484
+ }
485
+ }
486
+
487
+ /**
488
+ * Get system information for debugging
489
+ */
490
+ getSystemInfo() {
491
+ return {
492
+ platform: os.platform(),
493
+ arch: os.arch(),
494
+ nodeVersion: process.version,
495
+ originalDir: this.results.originalDir,
496
+ workingDir: this.results.workingDir,
497
+ hasWritePermission: this.results.hasWritePermission,
498
+ shell: this.detectShell(),
499
+ homeDir: this.getHomeDirectory(),
500
+ env: {
501
+ USER: process.env.USER,
502
+ HOME: process.env.HOME,
503
+ PWD: process.env.PWD,
504
+ SHELL: process.env.SHELL
505
+ }
506
+ };
507
+ }
508
+
509
+ /**
510
+ * Display results and next steps
511
+ */
512
+ displayResults(result) {
513
+ if (!result.success) {
514
+ console.log('\nāŒ Setup failed');
515
+ console.log(`Error: ${result.error}`);
516
+ console.log('\nšŸ’” Suggestions:');
517
+ console.log('1. Run from your home directory: cd ~');
518
+ console.log('2. Try creating a project directory: mkdir ~/stigmergy && cd ~/stigmergy');
519
+ console.log('3. Use enhanced installer with explicit directory');
520
+ return;
521
+ }
522
+
523
+ console.log('\nāœ… Working directory setup completed successfully!');
524
+ console.log(`šŸ“ Original directory: ${result.originalDir}`);
525
+ console.log(`šŸ“ Working directory: ${result.workingDir}`);
526
+ console.log(`šŸ“ Reason: ${result.reason}`);
527
+
528
+ if (result.created) {
529
+ console.log('šŸ†• Created new directory for you');
530
+ }
531
+
532
+ console.log('\nšŸ“¦ npm Configuration:');
533
+ console.log(`šŸ“ Global prefix: ${result.npmConfig.npmGlobalDir}`);
534
+ console.log(`šŸ“ Bin directory: ${result.npmConfig.npmBinDir}`);
535
+
536
+ console.log('\nšŸ”§ Setup Instructions:');
537
+ console.log(result.setupInstructions);
538
+
539
+ console.log('\nšŸ’” Next Steps:');
540
+ console.log('1. Apply the shell configuration above');
541
+ console.log('2. Run: npm install -g stigmergy');
542
+ console.log('3. Run: stigmergy install');
543
+
544
+ const systemInfo = this.getSystemInfo();
545
+ if (this.options.verbose) {
546
+ console.log('\nšŸ” System Information:');
547
+ console.log(JSON.stringify(systemInfo, null, 2));
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Clean up created directories
553
+ */
554
+ async cleanup() {
555
+ this.log('info', 'Cleaning up created directories...');
556
+
557
+ for (const dir of this.results.createdDirectories) {
558
+ try {
559
+ await fs.rmdir(dir, { recursive: true });
560
+ this.log('debug', `Cleaned up: ${dir}`);
561
+ } catch (error) {
562
+ this.log('warn', `Failed to clean up ${dir}: ${error.message}`);
563
+ }
564
+ }
565
+ }
566
+ }
567
+
568
+ module.exports = DirectoryPermissionManager;