gm-codex 2.0.951 → 2.0.953
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/.codex-plugin/plugin.json +1 -1
- package/bin/bootstrap.js +98 -14
- package/gm.json +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
package/bin/bootstrap.js
CHANGED
|
@@ -299,7 +299,7 @@ function pruneOldVersions(root, keepVersion, keepRtkVersion) {
|
|
|
299
299
|
if (fs.existsSync(lock) && !isLockStale(lock)) continue;
|
|
300
300
|
if (fs.existsSync(lock)) { try { fs.unlinkSync(lock); } catch (_) {} }
|
|
301
301
|
try {
|
|
302
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
302
|
+
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 1, retryDelay: 50 });
|
|
303
303
|
log(`pruned ${dir}`);
|
|
304
304
|
} catch (err) { log(`prune skip ${dir}: ${err.message}`); }
|
|
305
305
|
}
|
|
@@ -327,12 +327,14 @@ async function bootstrap(opts) {
|
|
|
327
327
|
|
|
328
328
|
if (fs.existsSync(finalPath) && fs.existsSync(okSentinel)) {
|
|
329
329
|
if (!opts.silent) log(`cache hit: ${finalPath}`);
|
|
330
|
+
proactiveKillForNewInstall(version, finalPath);
|
|
330
331
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
331
332
|
return finalPath;
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
if (healIfShaMatches(finalPath, expectedSha, okSentinel, partialPath, 'plugkit')) {
|
|
335
336
|
if (!opts.silent) log(`cache heal (sha match): ${finalPath}`);
|
|
337
|
+
proactiveKillForNewInstall(version, finalPath);
|
|
336
338
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
337
339
|
try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
|
|
338
340
|
catch (err) { log(`rtk fetch skipped: ${err.message}`); }
|
|
@@ -343,11 +345,13 @@ async function bootstrap(opts) {
|
|
|
343
345
|
acquireLock(lockPath);
|
|
344
346
|
try {
|
|
345
347
|
if (fs.existsSync(finalPath) && fs.existsSync(okSentinel)) {
|
|
348
|
+
proactiveKillForNewInstall(version, finalPath);
|
|
346
349
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
347
350
|
return finalPath;
|
|
348
351
|
}
|
|
349
352
|
if (healIfShaMatches(finalPath, expectedSha, okSentinel, partialPath, 'plugkit')) {
|
|
350
353
|
log(`cache heal (sha match) under lock: ${finalPath}`);
|
|
354
|
+
proactiveKillForNewInstall(version, finalPath);
|
|
351
355
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
352
356
|
try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
|
|
353
357
|
catch (err) { log(`rtk fetch skipped: ${err.message}`); }
|
|
@@ -392,8 +396,8 @@ async function bootstrap(opts) {
|
|
|
392
396
|
fs.writeFileSync(okSentinel, new Date().toISOString());
|
|
393
397
|
log(`installed ${finalPath}`);
|
|
394
398
|
obsEvent('bootstrap', 'install.done', { path: finalPath, version, kind: 'plugkit' });
|
|
399
|
+
proactiveKillForNewInstall(version, finalPath);
|
|
395
400
|
pruneOldVersions(root, version, readRtkVersion(wrapperDir));
|
|
396
|
-
proactiveKillForNewInstall(version);
|
|
397
401
|
try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
|
|
398
402
|
catch (err) { log(`rtk fetch skipped: ${err.message}`); }
|
|
399
403
|
return finalPath;
|
|
@@ -515,7 +519,7 @@ function killPid(pid) {
|
|
|
515
519
|
if (os.platform() === 'win32' && pidAlive(pid)) {
|
|
516
520
|
try {
|
|
517
521
|
const { spawnSync } = require('child_process');
|
|
518
|
-
spawnSync('taskkill', ['/F', '/PID', String(pid)], { stdio: 'ignore', windowsHide: true });
|
|
522
|
+
spawnSync('taskkill', ['/F', '/PID', String(pid)], { stdio: 'ignore', windowsHide: true, timeout: 3000, killSignal: 'SIGKILL' });
|
|
519
523
|
} catch (_) {}
|
|
520
524
|
}
|
|
521
525
|
return true;
|
|
@@ -539,6 +543,73 @@ function killRunningDaemons(reason) {
|
|
|
539
543
|
return killedPids;
|
|
540
544
|
}
|
|
541
545
|
|
|
546
|
+
function listRunningPlugkitImagePaths() {
|
|
547
|
+
const out = [];
|
|
548
|
+
try {
|
|
549
|
+
const { spawnSync } = require('child_process');
|
|
550
|
+
if (os.platform() === 'win32') {
|
|
551
|
+
let parsed = null;
|
|
552
|
+
try {
|
|
553
|
+
const p = spawnSync('powershell', ['-NoProfile', '-NonInteractive', '-Command', "Get-Process plugkit* -ErrorAction SilentlyContinue | Select-Object Id,Path | ConvertTo-Json -Compress"], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL' });
|
|
554
|
+
const text = ((p && p.stdout) || '').trim();
|
|
555
|
+
if (text) {
|
|
556
|
+
const j = JSON.parse(text);
|
|
557
|
+
parsed = Array.isArray(j) ? j : [j];
|
|
558
|
+
}
|
|
559
|
+
} catch (_) {}
|
|
560
|
+
if (parsed) {
|
|
561
|
+
for (const item of parsed) {
|
|
562
|
+
if (!item) continue;
|
|
563
|
+
const pid = parseInt(item.Id, 10);
|
|
564
|
+
if (!Number.isFinite(pid)) continue;
|
|
565
|
+
out.push({ pid, path: (item.Path || '').trim() });
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
const r = spawnSync('tasklist', ['/FI', 'IMAGENAME eq plugkit*', '/FO', 'CSV', '/NH'], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL' });
|
|
569
|
+
const text = (r && r.stdout) || '';
|
|
570
|
+
const seen = new Set();
|
|
571
|
+
for (const line of text.split(/\r?\n/)) {
|
|
572
|
+
const m = line.match(/^"([^"]+)","(\d+)"/);
|
|
573
|
+
if (!m) continue;
|
|
574
|
+
const pid = parseInt(m[2], 10);
|
|
575
|
+
if (!Number.isFinite(pid) || seen.has(pid)) continue;
|
|
576
|
+
seen.add(pid);
|
|
577
|
+
out.push({ pid, path: '' });
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
} else if (os.platform() === 'linux') {
|
|
581
|
+
let entries = [];
|
|
582
|
+
try { entries = fs.readdirSync('/proc'); } catch (_) {}
|
|
583
|
+
for (const e of entries) {
|
|
584
|
+
if (!/^\d+$/.test(e)) continue;
|
|
585
|
+
const pid = parseInt(e, 10);
|
|
586
|
+
let comm = '';
|
|
587
|
+
try { comm = fs.readFileSync(`/proc/${pid}/comm`, 'utf8').trim(); } catch (_) { continue; }
|
|
588
|
+
if (!/^plugkit/i.test(comm)) continue;
|
|
589
|
+
let imagePath = '';
|
|
590
|
+
try { imagePath = fs.readlinkSync(`/proc/${pid}/exe`); } catch (_) {}
|
|
591
|
+
out.push({ pid, path: imagePath });
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
const r = spawnSync('ps', ['-axo', 'pid=,comm='], { encoding: 'utf8' });
|
|
595
|
+
const text = (r && r.stdout) || '';
|
|
596
|
+
for (const line of text.split(/\r?\n/)) {
|
|
597
|
+
const m = line.match(/^\s*(\d+)\s+(.+?)\s*$/);
|
|
598
|
+
if (!m) continue;
|
|
599
|
+
if (!/plugkit/i.test(m[2])) continue;
|
|
600
|
+
const pid = parseInt(m[1], 10);
|
|
601
|
+
let imagePath = '';
|
|
602
|
+
try {
|
|
603
|
+
const p = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8' });
|
|
604
|
+
imagePath = ((p && p.stdout) || '').trim().split(/\s+/)[0] || '';
|
|
605
|
+
} catch (_) {}
|
|
606
|
+
out.push({ pid, path: imagePath });
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
} catch (_) {}
|
|
610
|
+
return out;
|
|
611
|
+
}
|
|
612
|
+
|
|
542
613
|
function killSpoolWatcherInCwd(reason) {
|
|
543
614
|
try {
|
|
544
615
|
const pidPath = path.join(process.cwd(), '.gm', 'exec-spool', '.watcher.pid');
|
|
@@ -554,19 +625,27 @@ function killSpoolWatcherInCwd(reason) {
|
|
|
554
625
|
return null;
|
|
555
626
|
}
|
|
556
627
|
|
|
557
|
-
function proactiveKillForNewInstall(installedVersion) {
|
|
628
|
+
function proactiveKillForNewInstall(installedVersion, finalPath) {
|
|
558
629
|
try {
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
if (
|
|
567
|
-
if (
|
|
568
|
-
|
|
630
|
+
const reason = `install:v${installedVersion}`;
|
|
631
|
+
const target = finalPath ? path.resolve(finalPath).toLowerCase() : null;
|
|
632
|
+
const cacheRootNorm = (() => {
|
|
633
|
+
try { return path.resolve(cacheRoot()).toLowerCase(); } catch (_) { return null; }
|
|
634
|
+
})();
|
|
635
|
+
const procs = listRunningPlugkitImagePaths();
|
|
636
|
+
for (const { pid, path: imagePath } of procs) {
|
|
637
|
+
if (!Number.isFinite(pid) || pid === process.pid) continue;
|
|
638
|
+
if (!imagePath) continue;
|
|
639
|
+
const norm = path.resolve(imagePath).toLowerCase();
|
|
640
|
+
if (target && norm === target) continue;
|
|
641
|
+
if (!cacheRootNorm || !norm.startsWith(cacheRootNorm + path.sep.toLowerCase())) continue;
|
|
642
|
+
if (killPid(pid)) {
|
|
643
|
+
try { process.stderr.write(`[bootstrap] killed stale daemon pid=${pid} path=${imagePath} (current install: v${installedVersion})\n`); } catch (_) {}
|
|
644
|
+
obsEvent('bootstrap', 'daemon.killed', { pid, oldPath: imagePath, installedVersion, mechanism: 'process-path' });
|
|
645
|
+
}
|
|
569
646
|
}
|
|
647
|
+
killRunningDaemons(reason);
|
|
648
|
+
killSpoolWatcherInCwd(reason);
|
|
570
649
|
writeDaemonVersion(installedVersion);
|
|
571
650
|
} catch (_) {}
|
|
572
651
|
}
|
|
@@ -576,6 +655,11 @@ function proactiveKillForNewInstall(installedVersion) {
|
|
|
576
655
|
function killStaleDaemonIfVersionChanged(wrapperDir) {
|
|
577
656
|
let currentVersion;
|
|
578
657
|
try { currentVersion = readVersionFile(wrapperDir); } catch (_) { return; }
|
|
658
|
+
const cached = resolveCachedBinary({ wrapperDir, version: currentVersion });
|
|
659
|
+
if (cached) {
|
|
660
|
+
proactiveKillForNewInstall(currentVersion, cached);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
579
663
|
const recorded = readDaemonVersion();
|
|
580
664
|
if (recorded === currentVersion) return;
|
|
581
665
|
if (recorded) killRunningDaemons(`version_change:${recorded}->${currentVersion}`);
|
package/gm.json
CHANGED
package/package.json
CHANGED