@justin0713/opspilot 1.0.6 → 1.0.8
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/bin/opspilot.js +182 -12
- package/package.json +1 -1
package/bin/opspilot.js
CHANGED
|
@@ -56,11 +56,75 @@ function tryRun(cmd) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function checkDocker() {
|
|
59
|
-
if (
|
|
59
|
+
if (tryRun('docker --version')) return; // already installed
|
|
60
|
+
|
|
61
|
+
const platform = os.platform();
|
|
62
|
+
warn('Docker is not installed. Attempting auto-install...');
|
|
63
|
+
|
|
64
|
+
if (platform === 'darwin') {
|
|
65
|
+
// macOS — prefer Colima (lightweight, no GUI, works on managed Macs)
|
|
66
|
+
if (tryRun('brew --version')) {
|
|
67
|
+
log('Installing Colima + Docker CLI via Homebrew (no Docker Desktop needed)...');
|
|
68
|
+
try {
|
|
69
|
+
run('brew install colima docker');
|
|
70
|
+
log('Starting Colima...');
|
|
71
|
+
run('colima start');
|
|
72
|
+
ok('Docker is ready via Colima.');
|
|
73
|
+
return;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
warn('Colima install failed. Trying Docker Desktop...');
|
|
76
|
+
try {
|
|
77
|
+
run('brew install --cask docker');
|
|
78
|
+
warn('Docker Desktop installed. Please open Docker Desktop from Applications,');
|
|
79
|
+
warn('wait for the whale icon in the menu bar, then run: opspilot start again.');
|
|
80
|
+
process.exit(0);
|
|
81
|
+
} catch (_) {}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// No Homebrew
|
|
60
85
|
die(
|
|
61
|
-
'Docker is
|
|
62
|
-
' Install
|
|
86
|
+
'Docker is required but could not be auto-installed.\n\n' +
|
|
87
|
+
' Option 1 — Install Homebrew first, then retry:\n' +
|
|
88
|
+
' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"\n\n' +
|
|
89
|
+
' Option 2 — Install OrbStack (lightweight Docker Desktop alternative):\n' +
|
|
90
|
+
' https://orbstack.dev\n\n' +
|
|
91
|
+
' Option 3 — Run without Docker (Python only):\n' +
|
|
92
|
+
' opspilot install-guide'
|
|
63
93
|
);
|
|
94
|
+
|
|
95
|
+
} else if (platform === 'linux') {
|
|
96
|
+
log('Installing Docker via get.docker.com...');
|
|
97
|
+
try {
|
|
98
|
+
run('curl -fsSL https://get.docker.com | sh');
|
|
99
|
+
const user = tryRun('whoami');
|
|
100
|
+
if (user && user !== 'root') {
|
|
101
|
+
try { run(`sudo usermod -aG docker ${user}`); } catch (_) {}
|
|
102
|
+
warn(`Added ${user} to docker group. You may need to log out and back in.`);
|
|
103
|
+
}
|
|
104
|
+
ok('Docker installed. Starting Docker service...');
|
|
105
|
+
try { run('sudo systemctl enable --now docker'); } catch (_) {}
|
|
106
|
+
return;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
die(
|
|
109
|
+
'Auto-install failed. Install Docker manually:\n' +
|
|
110
|
+
' https://docs.docker.com/engine/install/'
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
} else {
|
|
115
|
+
// Windows or unknown
|
|
116
|
+
die(
|
|
117
|
+
'Docker is required.\n\n' +
|
|
118
|
+
' Download Docker Desktop for Windows:\n' +
|
|
119
|
+
' https://docs.docker.com/desktop/install/windows-install/\n\n' +
|
|
120
|
+
' After installing, open Docker Desktop and wait for it to start,\n' +
|
|
121
|
+
' then run: opspilot start'
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Final check after auto-install
|
|
126
|
+
if (!tryRun('docker --version')) {
|
|
127
|
+
die('Docker still not available after install. Please reopen your terminal and try again.');
|
|
64
128
|
}
|
|
65
129
|
}
|
|
66
130
|
|
|
@@ -276,6 +340,108 @@ function cmdConfig() {
|
|
|
276
340
|
console.log(JSON.stringify(safe, null, 2));
|
|
277
341
|
}
|
|
278
342
|
|
|
343
|
+
function cmdUninstall(flags) {
|
|
344
|
+
const keepData = flags['keep-data'] || false;
|
|
345
|
+
const cfg = loadConfig();
|
|
346
|
+
const data = cfg.dataDir || 'opspilot-data';
|
|
347
|
+
|
|
348
|
+
console.log('');
|
|
349
|
+
log('Uninstalling OpsPilot Local...');
|
|
350
|
+
|
|
351
|
+
// 1. Stop + remove container
|
|
352
|
+
if (tryRun('docker --version')) {
|
|
353
|
+
const status = tryRun(`docker inspect -f "{{.State.Status}}" ${CONTAINER} 2>/dev/null`);
|
|
354
|
+
if (status) {
|
|
355
|
+
log('Stopping container...');
|
|
356
|
+
try { run(`docker stop ${CONTAINER}`, { silent: true }); } catch (_) {}
|
|
357
|
+
try { run(`docker rm -f ${CONTAINER}`, { silent: true }); } catch (_) {}
|
|
358
|
+
ok('Container removed.');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 2. Remove data volume (unless --keep-data)
|
|
362
|
+
if (!keepData) {
|
|
363
|
+
const volExists = tryRun(`docker volume inspect ${data} 2>/dev/null`);
|
|
364
|
+
if (volExists) {
|
|
365
|
+
log(`Removing data volume '${data}'...`);
|
|
366
|
+
try { run(`docker volume rm ${data}`, { silent: true }); ok('Data volume removed.'); }
|
|
367
|
+
catch (_) { warn(`Could not remove volume '${data}' — remove manually: docker volume rm ${data}`); }
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
warn(`Data volume '${data}' kept (--keep-data). Remove manually later: docker volume rm ${data}`);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 3. Remove Docker image
|
|
374
|
+
const imgExists = tryRun(`docker image inspect ${IMAGE} 2>/dev/null`);
|
|
375
|
+
if (imgExists) {
|
|
376
|
+
log(`Removing image ${IMAGE}...`);
|
|
377
|
+
try { run(`docker rmi ${IMAGE}`, { silent: true }); ok('Image removed.'); } catch (_) {}
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
warn('Docker not available — skipping container/volume cleanup.');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 4. Remove local CLI config + credentials
|
|
384
|
+
const toDelete = [CONFIG_FILE, CREDENTIALS_FILE, SETUP_TOKEN_FILE];
|
|
385
|
+
toDelete.forEach(f => {
|
|
386
|
+
try { if (fs.existsSync(f)) { fs.unlinkSync(f); } } catch (_) {}
|
|
387
|
+
});
|
|
388
|
+
// Remove config dir if empty
|
|
389
|
+
try {
|
|
390
|
+
const remaining = fs.readdirSync(CONFIG_DIR);
|
|
391
|
+
if (remaining.length === 0) fs.rmdirSync(CONFIG_DIR);
|
|
392
|
+
} catch (_) {}
|
|
393
|
+
|
|
394
|
+
ok('OpsPilot Local uninstalled.');
|
|
395
|
+
console.log('');
|
|
396
|
+
console.log(`To reinstall: ${CYAN}opspilot start --token <license-token>${RESET}`);
|
|
397
|
+
console.log(`To remove CLI: ${CYAN}npm uninstall -g @justin0713/opspilot${RESET}`);
|
|
398
|
+
console.log('');
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function cmdInstallGuide() {
|
|
402
|
+
const platform = os.platform();
|
|
403
|
+
console.log(`
|
|
404
|
+
${BOLD}${CYAN}OpsPilot Local — Docker Install Guide${RESET}
|
|
405
|
+
|
|
406
|
+
Docker is required to run OpsPilot Local.
|
|
407
|
+
The CLI will auto-install Docker when you run ${CYAN}opspilot start${RESET}.
|
|
408
|
+
|
|
409
|
+
${BOLD}Auto-install behaviour by platform:${RESET}
|
|
410
|
+
|
|
411
|
+
${BOLD}macOS${RESET}
|
|
412
|
+
• If Homebrew is installed → installs ${CYAN}Colima + Docker CLI${RESET} automatically
|
|
413
|
+
(lightweight, no Docker Desktop, works on managed/corporate Macs)
|
|
414
|
+
• If Homebrew is missing → installs Homebrew first:
|
|
415
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
416
|
+
Then retry: ${CYAN}opspilot start --token <token>${RESET}
|
|
417
|
+
|
|
418
|
+
${BOLD}Linux${RESET}
|
|
419
|
+
• Runs the official Docker install script automatically:
|
|
420
|
+
curl -fsSL https://get.docker.com | sh
|
|
421
|
+
|
|
422
|
+
${BOLD}Windows${RESET}
|
|
423
|
+
• Cannot auto-install. Download Docker Desktop:
|
|
424
|
+
https://docs.docker.com/desktop/install/windows-install/
|
|
425
|
+
|
|
426
|
+
${BOLD}Manual install options (macOS):${RESET}
|
|
427
|
+
|
|
428
|
+
1. ${CYAN}Colima${RESET} — lightweight, CLI-only, free (recommended for managed Macs)
|
|
429
|
+
brew install colima docker
|
|
430
|
+
colima start
|
|
431
|
+
|
|
432
|
+
2. ${CYAN}OrbStack${RESET} — lightweight Docker Desktop alternative
|
|
433
|
+
brew install orbstack
|
|
434
|
+
# or: https://orbstack.dev
|
|
435
|
+
|
|
436
|
+
3. ${CYAN}Docker Desktop${RESET} — official GUI app
|
|
437
|
+
brew install --cask docker
|
|
438
|
+
# or: https://www.docker.com/products/docker-desktop/
|
|
439
|
+
|
|
440
|
+
${BOLD}Current platform:${RESET} ${platform}
|
|
441
|
+
${BOLD}Docker status :${RESET} ${tryRun('docker --version') || RED + 'not found' + RESET}
|
|
442
|
+
`);
|
|
443
|
+
}
|
|
444
|
+
|
|
279
445
|
function printHelp() {
|
|
280
446
|
console.log(`
|
|
281
447
|
${BOLD}${CYAN}OpsPilot Local${RESET} — CLI v${PKG_VERSION}
|
|
@@ -284,13 +450,15 @@ ${BOLD}Usage:${RESET}
|
|
|
284
450
|
opspilot <command> [options]
|
|
285
451
|
|
|
286
452
|
${BOLD}Commands:${RESET}
|
|
287
|
-
${CYAN}start${RESET}
|
|
288
|
-
${CYAN}stop${RESET}
|
|
289
|
-
${CYAN}logs${RESET}
|
|
290
|
-
${CYAN}update${RESET}
|
|
291
|
-
${CYAN}status${RESET}
|
|
292
|
-
${CYAN}config${RESET}
|
|
293
|
-
${CYAN}password${RESET}
|
|
453
|
+
${CYAN}start${RESET} Pull image and start the container ${YELLOW}(auto-installs Docker if missing)${RESET}
|
|
454
|
+
${CYAN}stop${RESET} Stop and remove the container
|
|
455
|
+
${CYAN}logs${RESET} Show container logs (-f to follow)
|
|
456
|
+
${CYAN}update${RESET} Pull latest image and restart
|
|
457
|
+
${CYAN}status${RESET} Show container status
|
|
458
|
+
${CYAN}config${RESET} Show saved local config
|
|
459
|
+
${CYAN}password${RESET} Show first-run admin password (--clear to delete after reading)
|
|
460
|
+
${CYAN}uninstall${RESET} Remove container, image, data volume and local config
|
|
461
|
+
${CYAN}install-guide${RESET} Show Docker installation instructions for your platform
|
|
294
462
|
|
|
295
463
|
${BOLD}Start options:${RESET}
|
|
296
464
|
--token <token> License token from OpsPilot Cloud ${YELLOW}(required)${RESET}
|
|
@@ -329,8 +497,10 @@ switch (cmd) {
|
|
|
329
497
|
cmdStart(Object.assign({}, cfg, parsed.flags));
|
|
330
498
|
})();
|
|
331
499
|
break;
|
|
332
|
-
case 'status':
|
|
333
|
-
case 'config':
|
|
500
|
+
case 'status': cmdStatus(); break;
|
|
501
|
+
case 'config': cmdConfig(); break;
|
|
502
|
+
case 'uninstall': cmdUninstall(parsed.flags); break;
|
|
503
|
+
case 'install-guide': cmdInstallGuide(); break;
|
|
334
504
|
case 'password':
|
|
335
505
|
if (parsed.flags.clear) {
|
|
336
506
|
try { fs.unlinkSync(CREDENTIALS_FILE); ok('Credentials file cleared.'); }
|
package/package.json
CHANGED