ghostterm 1.2.0 → 1.2.1
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/CHANGELOG.md +6 -0
- package/bin/ghostterm.js +62 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1 (2026-03-17)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
- **Windows background mode** — fixed node-pty crash in detached mode by using `windowsHide` instead of raw detach
|
|
7
|
+
- **Supervisor crash loop** — fixed `--supervisor` arg being caught by "already running" check
|
|
8
|
+
|
|
3
9
|
## 1.2.0 (2026-03-17)
|
|
4
10
|
|
|
5
11
|
### Features
|
package/bin/ghostterm.js
CHANGED
|
@@ -486,8 +486,8 @@ function handleSubcommand() {
|
|
|
486
486
|
process.exit(0);
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
// No subcommand = start in background (unless already daemonized via --daemon)
|
|
490
|
-
if (arg !== '--daemon') {
|
|
489
|
+
// No subcommand = start in background (unless already daemonized via --daemon or --supervisor)
|
|
490
|
+
if (arg !== '--daemon' && arg !== '--supervisor') {
|
|
491
491
|
// Check if already running
|
|
492
492
|
if (fs.existsSync(PID_FILE)) {
|
|
493
493
|
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
|
|
@@ -505,18 +505,35 @@ function handleSubcommand() {
|
|
|
505
505
|
return 'foreground-first-login';
|
|
506
506
|
}
|
|
507
507
|
|
|
508
|
-
// Spawn self as
|
|
509
|
-
const { spawn } = require('child_process');
|
|
508
|
+
// Spawn self as supervisor in background
|
|
509
|
+
const { spawn, execSync } = require('child_process');
|
|
510
510
|
const out = fs.openSync(LOG_FILE, 'a');
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
511
|
+
|
|
512
|
+
if (os.platform() === 'win32') {
|
|
513
|
+
// Windows: spawn with hidden window (windowsHide) but NOT detached
|
|
514
|
+
// node-pty requires a console; detached:true removes the console and crashes
|
|
515
|
+
// windowsHide:true creates a hidden console window
|
|
516
|
+
const child = spawn(process.execPath, [__filename, '--supervisor'], {
|
|
517
|
+
detached: true,
|
|
518
|
+
windowsHide: true,
|
|
519
|
+
stdio: ['ignore', out, out],
|
|
520
|
+
env: { ...process.env },
|
|
521
|
+
});
|
|
522
|
+
child.unref();
|
|
523
|
+
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
524
|
+
} else {
|
|
525
|
+
// macOS/Linux: detached works fine
|
|
526
|
+
const child = spawn(process.execPath, [__filename, '--supervisor'], {
|
|
527
|
+
detached: true,
|
|
528
|
+
stdio: ['ignore', out, out],
|
|
529
|
+
env: { ...process.env },
|
|
530
|
+
});
|
|
531
|
+
child.unref();
|
|
532
|
+
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
533
|
+
}
|
|
534
|
+
const pid = fs.existsSync(PID_FILE) ? fs.readFileSync(PID_FILE, 'utf8').trim() : '?';
|
|
518
535
|
console.log('');
|
|
519
|
-
console.log(` ✅ GhostTerm running in background (PID: ${
|
|
536
|
+
console.log(` ✅ GhostTerm running in background (PID: ${pid})`);
|
|
520
537
|
console.log(' 📱 Open: ghostterm.pages.dev');
|
|
521
538
|
console.log(' 🛑 Stop: npx ghostterm stop');
|
|
522
539
|
console.log(' 📋 Logs: npx ghostterm logs');
|
|
@@ -524,8 +541,35 @@ function handleSubcommand() {
|
|
|
524
541
|
process.exit(0);
|
|
525
542
|
}
|
|
526
543
|
|
|
544
|
+
// --supervisor: watchdog that restarts worker on crash
|
|
545
|
+
if (arg === '--supervisor') {
|
|
546
|
+
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
547
|
+
const { spawn } = require('child_process');
|
|
548
|
+
let restartCount = 0;
|
|
549
|
+
|
|
550
|
+
function spawnWorker() {
|
|
551
|
+
const logFd = fs.openSync(LOG_FILE, 'a');
|
|
552
|
+
const worker = spawn(process.execPath, [__filename, '--daemon'], {
|
|
553
|
+
stdio: ['ignore', logFd, logFd],
|
|
554
|
+
env: { ...process.env },
|
|
555
|
+
});
|
|
556
|
+
worker.on('exit', (code) => {
|
|
557
|
+
if (code === 0) {
|
|
558
|
+
// Clean exit (e.g. from stop command), don't restart
|
|
559
|
+
process.exit(0);
|
|
560
|
+
}
|
|
561
|
+
restartCount++;
|
|
562
|
+
const delay = Math.min(restartCount * 3000, 30000); // 3s, 6s, 9s... max 30s
|
|
563
|
+
console.log(` [supervisor] Worker exited (code ${code}), restarting in ${delay / 1000}s... (restart #${restartCount})`);
|
|
564
|
+
setTimeout(spawnWorker, delay);
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
spawnWorker();
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
527
572
|
// --daemon: write PID file and continue to main()
|
|
528
|
-
fs.writeFileSync(PID_FILE, String(process.pid));
|
|
529
573
|
return 'daemon';
|
|
530
574
|
}
|
|
531
575
|
|
|
@@ -547,23 +591,13 @@ async function main() {
|
|
|
547
591
|
console.log(' Will use pairing code instead');
|
|
548
592
|
}
|
|
549
593
|
|
|
550
|
-
// First login done in foreground — now restart
|
|
594
|
+
// First login done in foreground — now restart in background
|
|
551
595
|
if (mode === 'foreground-first-login' && googleToken) {
|
|
552
596
|
console.log('');
|
|
553
|
-
console.log(' Login successful!
|
|
554
|
-
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
detached: true,
|
|
558
|
-
stdio: ['ignore', out, out],
|
|
559
|
-
env: { ...process.env },
|
|
560
|
-
});
|
|
561
|
-
child.unref();
|
|
562
|
-
fs.writeFileSync(PID_FILE, String(child.pid));
|
|
563
|
-
console.log(` ✅ GhostTerm running in background (PID: ${child.pid})`);
|
|
564
|
-
console.log(' 📱 Open: ghostterm.pages.dev');
|
|
565
|
-
console.log(' 🛑 Stop: npx ghostterm stop');
|
|
566
|
-
console.log('');
|
|
597
|
+
console.log(' Login successful! Starting in background...');
|
|
598
|
+
// Re-run ourselves which will take the normal background start path
|
|
599
|
+
const { execSync } = require('child_process');
|
|
600
|
+
execSync(`"${process.execPath}" "${__filename}"`, { stdio: 'inherit' });
|
|
567
601
|
process.exit(0);
|
|
568
602
|
}
|
|
569
603
|
|