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,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;
|