dank-ai 1.0.12 → 1.0.14
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/lib/docker/manager.js +175 -10
- package/package.json +1 -1
package/lib/docker/manager.js
CHANGED
|
@@ -132,16 +132,108 @@ class DockerManager {
|
|
|
132
132
|
async installDockerMacOS() {
|
|
133
133
|
this.logger.info('Installing Docker Desktop for macOS...');
|
|
134
134
|
|
|
135
|
-
// Check if Homebrew is available
|
|
135
|
+
// Check if Homebrew is available with multiple methods
|
|
136
|
+
let homebrewAvailable = false;
|
|
137
|
+
let homebrewPath = 'brew';
|
|
138
|
+
|
|
136
139
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await this.runCommand('brew install --cask docker', 'Installing Docker Desktop via Homebrew');
|
|
142
|
-
|
|
140
|
+
// Try different ways to detect Homebrew
|
|
141
|
+
await execAsync('brew --version');
|
|
142
|
+
homebrewAvailable = true;
|
|
143
|
+
homebrewPath = 'brew';
|
|
143
144
|
} catch (error) {
|
|
145
|
+
try {
|
|
146
|
+
// Try with full path (Apple Silicon Macs)
|
|
147
|
+
await execAsync('/opt/homebrew/bin/brew --version');
|
|
148
|
+
homebrewAvailable = true;
|
|
149
|
+
homebrewPath = '/opt/homebrew/bin/brew';
|
|
150
|
+
} catch (error2) {
|
|
151
|
+
try {
|
|
152
|
+
// Try with usr/local path (Intel Macs)
|
|
153
|
+
await execAsync('/usr/local/bin/brew --version');
|
|
154
|
+
homebrewAvailable = true;
|
|
155
|
+
homebrewPath = '/usr/local/bin/brew';
|
|
156
|
+
} catch (error3) {
|
|
157
|
+
// Try to find brew in PATH
|
|
158
|
+
try {
|
|
159
|
+
const { stdout } = await execAsync('which brew');
|
|
160
|
+
if (stdout.trim()) {
|
|
161
|
+
await execAsync(`${stdout.trim()} --version`);
|
|
162
|
+
homebrewAvailable = true;
|
|
163
|
+
homebrewPath = stdout.trim();
|
|
164
|
+
}
|
|
165
|
+
} catch (error4) {
|
|
166
|
+
// Homebrew not found
|
|
167
|
+
this.logger.debug('Homebrew detection failed:', error4.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (homebrewAvailable) {
|
|
174
|
+
this.logger.info(`Using Homebrew to install Docker Desktop (found at: ${homebrewPath})...`);
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// First, try to update Homebrew to ensure it's working
|
|
178
|
+
this.logger.info('Updating Homebrew...');
|
|
179
|
+
try {
|
|
180
|
+
await this.runCommandWithEnv(`${homebrewPath} update`, 'Updating Homebrew');
|
|
181
|
+
} catch (updateError) {
|
|
182
|
+
this.logger.warn('Homebrew update failed, continuing with installation...');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Try different installation approaches
|
|
186
|
+
let installSuccess = false;
|
|
187
|
+
|
|
188
|
+
// Approach 1: Direct installation
|
|
189
|
+
try {
|
|
190
|
+
this.logger.info('Attempting direct installation...');
|
|
191
|
+
await this.runCommandWithEnv(`${homebrewPath} install --cask docker`, 'Installing Docker Desktop via Homebrew');
|
|
192
|
+
installSuccess = true;
|
|
193
|
+
} catch (error1) {
|
|
194
|
+
this.logger.warn('Direct installation failed, trying alternative approach...');
|
|
195
|
+
|
|
196
|
+
// Approach 2: Try with --force flag
|
|
197
|
+
try {
|
|
198
|
+
this.logger.info('Attempting installation with --force flag...');
|
|
199
|
+
await this.runCommandWithEnv(`${homebrewPath} install --cask --force docker`, 'Installing Docker Desktop via Homebrew (force)');
|
|
200
|
+
installSuccess = true;
|
|
201
|
+
} catch (error2) {
|
|
202
|
+
this.logger.warn('Force installation failed, trying with --no-quarantine flag...');
|
|
203
|
+
|
|
204
|
+
// Approach 3: Try with --no-quarantine flag
|
|
205
|
+
try {
|
|
206
|
+
this.logger.info('Attempting installation with --no-quarantine flag...');
|
|
207
|
+
await this.runCommandWithEnv(`${homebrewPath} install --cask --no-quarantine docker`, 'Installing Docker Desktop via Homebrew (no-quarantine)');
|
|
208
|
+
installSuccess = true;
|
|
209
|
+
} catch (error3) {
|
|
210
|
+
this.logger.error('All installation approaches failed');
|
|
211
|
+
throw error3;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (installSuccess) {
|
|
217
|
+
// Try to start Docker Desktop
|
|
218
|
+
this.logger.info('Starting Docker Desktop...');
|
|
219
|
+
try {
|
|
220
|
+
await this.runCommandWithEnv('open -a Docker', 'Starting Docker Desktop');
|
|
221
|
+
} catch (startError) {
|
|
222
|
+
this.logger.warn('Could not start Docker Desktop automatically. Please start it manually from Applications.');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
} catch (error) {
|
|
227
|
+
this.logger.warn('Homebrew found but installation failed. Please install Docker Desktop manually from https://www.docker.com/products/docker-desktop/');
|
|
228
|
+
this.logger.error(`Installation error: ${error.message}`);
|
|
229
|
+
this.logger.info('You can also try installing Docker Desktop manually:');
|
|
230
|
+
this.logger.info('1. Download from: https://www.docker.com/products/docker-desktop/');
|
|
231
|
+
this.logger.info('2. Or try: brew install --cask docker');
|
|
232
|
+
throw new Error('Docker Desktop installation via Homebrew failed. Please install manually from https://www.docker.com/products/docker-desktop/');
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
144
235
|
this.logger.warn('Homebrew not found. Please install Docker Desktop manually from https://www.docker.com/products/docker-desktop/');
|
|
236
|
+
this.logger.info('You can install Homebrew by running: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
|
|
145
237
|
throw new Error('Docker Desktop installation requires manual intervention. Please install from https://www.docker.com/products/docker-desktop/');
|
|
146
238
|
}
|
|
147
239
|
}
|
|
@@ -171,7 +263,7 @@ class DockerManager {
|
|
|
171
263
|
// Install Docker
|
|
172
264
|
await this.runCommand('sudo apt-get install -y docker-ce docker-ce-cli containerd.io', 'Installing Docker');
|
|
173
265
|
|
|
174
|
-
// Add current user to docker
|
|
266
|
+
// Add current user to docker groupl
|
|
175
267
|
await this.runCommand('sudo usermod -aG docker $USER', 'Adding user to docker group');
|
|
176
268
|
|
|
177
269
|
this.logger.info('Docker installation completed. You may need to log out and back in for group changes to take effect.');
|
|
@@ -258,6 +350,7 @@ class DockerManager {
|
|
|
258
350
|
*/
|
|
259
351
|
async runCommand(command, description) {
|
|
260
352
|
this.logger.info(`${description}...`);
|
|
353
|
+
this.logger.debug(`Executing command: ${command}`);
|
|
261
354
|
|
|
262
355
|
return new Promise((resolve, reject) => {
|
|
263
356
|
const child = spawn('sh', ['-c', command], {
|
|
@@ -269,11 +362,79 @@ class DockerManager {
|
|
|
269
362
|
let stderr = '';
|
|
270
363
|
|
|
271
364
|
child.stdout.on('data', (data) => {
|
|
272
|
-
|
|
365
|
+
const output = data.toString();
|
|
366
|
+
stdout += output;
|
|
367
|
+
// Log output in debug mode
|
|
368
|
+
this.logger.debug(`STDOUT: ${output.trim()}`);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
child.stderr.on('data', (data) => {
|
|
372
|
+
const output = data.toString();
|
|
373
|
+
stderr += output;
|
|
374
|
+
// Log stderr in debug mode
|
|
375
|
+
this.logger.debug(`STDERR: ${output.trim()}`);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
child.on('close', (code) => {
|
|
379
|
+
if (code === 0) {
|
|
380
|
+
this.logger.info(`${description} completed successfully`);
|
|
381
|
+
resolve({ stdout, stderr });
|
|
382
|
+
} else {
|
|
383
|
+
const error = new Error(`Command failed with exit code ${code}: ${stderr}`);
|
|
384
|
+
this.logger.error(`${description} failed: ${error.message}`);
|
|
385
|
+
this.logger.error(`Command: ${command}`);
|
|
386
|
+
this.logger.error(`STDOUT: ${stdout}`);
|
|
387
|
+
this.logger.error(`STDERR: ${stderr}`);
|
|
388
|
+
reject(error);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
child.on('error', (error) => {
|
|
393
|
+
this.logger.error(`${description} failed: ${error.message}`);
|
|
394
|
+
this.logger.error(`Command: ${command}`);
|
|
395
|
+
reject(error);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Run a command with proper environment setup for Homebrew
|
|
402
|
+
*/
|
|
403
|
+
async runCommandWithEnv(command, description) {
|
|
404
|
+
this.logger.info(`${description}...`);
|
|
405
|
+
this.logger.debug(`Executing command: ${command}`);
|
|
406
|
+
|
|
407
|
+
return new Promise((resolve, reject) => {
|
|
408
|
+
// Set up environment for Homebrew
|
|
409
|
+
const env = {
|
|
410
|
+
...process.env,
|
|
411
|
+
PATH: process.env.PATH,
|
|
412
|
+
HOMEBREW_NO_AUTO_UPDATE: '1', // Prevent auto-update during installation
|
|
413
|
+
HOMEBREW_NO_INSTALL_CLEANUP: '1' // Keep installation files
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// Use bash instead of sh for better environment support
|
|
417
|
+
const child = spawn('bash', ['-c', command], {
|
|
418
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
419
|
+
shell: true,
|
|
420
|
+
env: env
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
let stdout = '';
|
|
424
|
+
let stderr = '';
|
|
425
|
+
|
|
426
|
+
child.stdout.on('data', (data) => {
|
|
427
|
+
const output = data.toString();
|
|
428
|
+
stdout += output;
|
|
429
|
+
// Log output in debug mode
|
|
430
|
+
this.logger.debug(`STDOUT: ${output.trim()}`);
|
|
273
431
|
});
|
|
274
432
|
|
|
275
433
|
child.stderr.on('data', (data) => {
|
|
276
|
-
|
|
434
|
+
const output = data.toString();
|
|
435
|
+
stderr += output;
|
|
436
|
+
// Log stderr in debug mode
|
|
437
|
+
this.logger.debug(`STDERR: ${output.trim()}`);
|
|
277
438
|
});
|
|
278
439
|
|
|
279
440
|
child.on('close', (code) => {
|
|
@@ -283,12 +444,16 @@ class DockerManager {
|
|
|
283
444
|
} else {
|
|
284
445
|
const error = new Error(`Command failed with exit code ${code}: ${stderr}`);
|
|
285
446
|
this.logger.error(`${description} failed: ${error.message}`);
|
|
447
|
+
this.logger.error(`Command: ${command}`);
|
|
448
|
+
this.logger.error(`STDOUT: ${stdout}`);
|
|
449
|
+
this.logger.error(`STDERR: ${stderr}`);
|
|
286
450
|
reject(error);
|
|
287
451
|
}
|
|
288
452
|
});
|
|
289
453
|
|
|
290
454
|
child.on('error', (error) => {
|
|
291
455
|
this.logger.error(`${description} failed: ${error.message}`);
|
|
456
|
+
this.logger.error(`Command: ${command}`);
|
|
292
457
|
reject(error);
|
|
293
458
|
});
|
|
294
459
|
});
|