gm-skill 2.0.1222 → 2.0.1223
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 +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +95 -5
- package/gm.json +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ An earlier generation fanned out fifteen per-platform downstream repos (gm-cc, g
|
|
|
35
35
|
|
|
36
36
|
## Version
|
|
37
37
|
|
|
38
|
-
`2.0.
|
|
38
|
+
`2.0.1223` — auto-bumped from the canonical `gm` repo. Every push to `AnEntrypoint/gm` (or any cascading sibling crate) republishes this package.
|
|
39
39
|
|
|
40
40
|
## Source of truth
|
|
41
41
|
|
|
@@ -651,9 +651,48 @@ function ensureGitignored(cwd, entry) {
|
|
|
651
651
|
} catch (_) {}
|
|
652
652
|
}
|
|
653
653
|
|
|
654
|
+
function isProcessAliveSync(pid) {
|
|
655
|
+
if (!pid || typeof pid !== 'number' || pid <= 0) return false;
|
|
656
|
+
try {
|
|
657
|
+
process.kill(pid, 0);
|
|
658
|
+
return true;
|
|
659
|
+
} catch (e) {
|
|
660
|
+
return e && e.code === 'EPERM';
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function readSingletonLockPid(profileDir) {
|
|
665
|
+
const lock = path.join(profileDir, 'SingletonLock');
|
|
666
|
+
try {
|
|
667
|
+
let target;
|
|
668
|
+
try {
|
|
669
|
+
target = fs.readlinkSync(lock);
|
|
670
|
+
} catch (_) {
|
|
671
|
+
try { target = fs.readFileSync(lock, 'utf-8'); } catch (__) { return null; }
|
|
672
|
+
}
|
|
673
|
+
if (!target) return null;
|
|
674
|
+
const m = String(target).match(/-(\d+)\s*$/);
|
|
675
|
+
if (m) return parseInt(m[1], 10);
|
|
676
|
+
const m2 = String(target).match(/(\d+)/);
|
|
677
|
+
if (m2) return parseInt(m2[1], 10);
|
|
678
|
+
} catch (_) {}
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
|
|
654
682
|
function isProfileLocked(profileDir) {
|
|
655
683
|
const lock = path.join(profileDir, 'SingletonLock');
|
|
656
|
-
|
|
684
|
+
if (!fs.existsSync(lock)) return false;
|
|
685
|
+
const holderPid = readSingletonLockPid(profileDir);
|
|
686
|
+
if (holderPid != null && !isProcessAliveSync(holderPid)) {
|
|
687
|
+
try { fs.unlinkSync(lock); } catch (_) {}
|
|
688
|
+
try { fs.unlinkSync(path.join(profileDir, 'SingletonCookie')); } catch (_) {}
|
|
689
|
+
try { fs.unlinkSync(path.join(profileDir, 'SingletonSocket')); } catch (_) {}
|
|
690
|
+
logEvent('bootstrap', 'browser-profile.lock-cleared', {
|
|
691
|
+
profileDir, dead_pid: holderPid,
|
|
692
|
+
});
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
return true;
|
|
657
696
|
}
|
|
658
697
|
|
|
659
698
|
function acquireProfileDir(cwd) {
|
|
@@ -669,6 +708,31 @@ function acquireProfileDir(cwd) {
|
|
|
669
708
|
return fallback;
|
|
670
709
|
}
|
|
671
710
|
|
|
711
|
+
function cleanDeadProfileFragments(cwd) {
|
|
712
|
+
try {
|
|
713
|
+
const gmDir = path.join(cwd, '.gm');
|
|
714
|
+
if (!fs.existsSync(gmDir)) return { cleaned: 0 };
|
|
715
|
+
let cleaned = 0;
|
|
716
|
+
for (const name of fs.readdirSync(gmDir)) {
|
|
717
|
+
const m = name.match(/^browser-profile-(\d+)$/);
|
|
718
|
+
if (!m) continue;
|
|
719
|
+
const pid = parseInt(m[1], 10);
|
|
720
|
+
if (!isProcessAliveSync(pid)) {
|
|
721
|
+
try {
|
|
722
|
+
fs.rmSync(path.join(gmDir, name), { recursive: true, force: true });
|
|
723
|
+
cleaned++;
|
|
724
|
+
} catch (_) {}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (cleaned > 0) {
|
|
728
|
+
logEvent('bootstrap', 'browser-profile.hygiene', { cwd, cleaned });
|
|
729
|
+
}
|
|
730
|
+
return { cleaned };
|
|
731
|
+
} catch (_) {
|
|
732
|
+
return { cleaned: 0 };
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
672
736
|
function findFreePortSync() {
|
|
673
737
|
const r = spawnSync(process.execPath, ['-e', `
|
|
674
738
|
const net = require('net');
|
|
@@ -722,10 +786,31 @@ function getOrCreateBrowserSession(cwd, claudeSessionId, pw) {
|
|
|
722
786
|
const ports = readJsonFile(portsFile, {});
|
|
723
787
|
const sessions = readJsonFile(sessionsFile, {});
|
|
724
788
|
const existing = ports[claudeSessionId];
|
|
725
|
-
if (existing && existing.port
|
|
726
|
-
const
|
|
727
|
-
|
|
789
|
+
if (existing && existing.port) {
|
|
790
|
+
const wantProfile = path.join(cwd, '.gm', 'browser-profile');
|
|
791
|
+
const pidOk = existing.pid && isProcessAliveSync(existing.pid);
|
|
792
|
+
const profileOk = !existing.profileDir || existing.profileDir === wantProfile || existing.profileDir.startsWith(path.join(cwd, '.gm', 'browser-profile'));
|
|
793
|
+
const portOk = isPortAliveSync(existing.port);
|
|
794
|
+
if (pidOk && profileOk && portOk) {
|
|
795
|
+
const pwIds = sessions[claudeSessionId] || [];
|
|
796
|
+
if (pwIds.length > 0) return pwIds[0];
|
|
797
|
+
} else {
|
|
798
|
+
const reason = !pidOk ? 'pid-dead' : !profileOk ? 'profile-drift' : 'port-dead';
|
|
799
|
+
logEvent('hook', 'deviation.browser-profile-collision', {
|
|
800
|
+
sid: claudeSessionId,
|
|
801
|
+
stale_pid: existing.pid || null,
|
|
802
|
+
stale_port: existing.port || null,
|
|
803
|
+
stale_profile: existing.profileDir || null,
|
|
804
|
+
want_profile: wantProfile,
|
|
805
|
+
reason,
|
|
806
|
+
});
|
|
807
|
+
delete ports[claudeSessionId];
|
|
808
|
+
delete sessions[claudeSessionId];
|
|
809
|
+
try { writeJsonFile(portsFile, ports); } catch (_) {}
|
|
810
|
+
try { writeJsonFile(sessionsFile, sessions); } catch (_) {}
|
|
811
|
+
}
|
|
728
812
|
}
|
|
813
|
+
cleanDeadProfileFragments(cwd);
|
|
729
814
|
const chrome = findChrome();
|
|
730
815
|
if (!chrome) throw new Error('Chrome not found. Please install Google Chrome.');
|
|
731
816
|
const profileDir = acquireProfileDir(cwd);
|
|
@@ -1385,7 +1470,12 @@ function makeHostFunctions(instanceRef) {
|
|
|
1385
1470
|
});
|
|
1386
1471
|
}
|
|
1387
1472
|
const pwSessionId = getOrCreateBrowserSession(cwd, sessionId, pw);
|
|
1388
|
-
const
|
|
1473
|
+
const portsAfter = readJsonFile(browserPortsFile(cwd), {});
|
|
1474
|
+
const livePort = portsAfter[sessionId] && portsAfter[sessionId].port;
|
|
1475
|
+
const directArgs = (livePort && isPortAliveSync(livePort))
|
|
1476
|
+
? [`--direct=localhost:${livePort}`]
|
|
1477
|
+
: [];
|
|
1478
|
+
const r = runPlaywriter(pw, ['-s', pwSessionId, '--timeout', '14000', ...directArgs, '-e', body], 60000);
|
|
1389
1479
|
return writeWasmJson(instanceRef.value, {
|
|
1390
1480
|
ok: r.status === 0,
|
|
1391
1481
|
stdout: scrubBrowserRunnerText(r.stdout || ''),
|
package/gm.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-skill",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1223",
|
|
4
4
|
"description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
|
|
5
5
|
"author": "AnEntrypoint",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"gm.json"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"gm-plugkit": "^2.0.
|
|
42
|
+
"gm-plugkit": "^2.0.1223"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=16.0.0"
|