gm-skill 2.0.1489 → 2.0.1491

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1489",
3
+ "version": "2.0.1491",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform binary, verifies SHA256, and starts the spool watcher daemon. Includes plugkit-wasm-wrapper for WASM-based spool watching.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -677,15 +677,24 @@ function isProfileLocked(profileDir) {
677
677
  return true;
678
678
  }
679
679
 
680
- function acquireProfileDir(cwd) {
680
+ function sessionProfileSlug(claudeSessionId) {
681
+ const s = String(claudeSessionId || 'default').replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 64);
682
+ return s || 'default';
683
+ }
684
+
685
+ function sessionProfileDir(cwd, claudeSessionId) {
686
+ return path.join(cwd, '.gm', `browser-profile-${sessionProfileSlug(claudeSessionId)}`);
687
+ }
688
+
689
+ function acquireProfileDir(cwd, claudeSessionId) {
681
690
  const gmDir = path.join(cwd, '.gm');
682
691
  try { fs.mkdirSync(gmDir, { recursive: true }); } catch (_) {}
683
- const primary = path.join(gmDir, 'browser-profile');
684
692
  ensureGitignored(cwd, '.gm/browser-profile/');
685
693
  ensureGitignored(cwd, '.gm/browser-profile-*/');
694
+ const primary = sessionProfileDir(cwd, claudeSessionId);
686
695
  try { fs.mkdirSync(primary, { recursive: true }); } catch (_) {}
687
696
  if (!isProfileLocked(primary)) return primary;
688
- const fallback = path.join(gmDir, `browser-profile-${process.pid}`);
697
+ const fallback = path.join(gmDir, `browser-profile-${sessionProfileSlug(claudeSessionId)}-${process.pid}`);
689
698
  try { fs.mkdirSync(fallback, { recursive: true }); } catch (_) {}
690
699
  return fallback;
691
700
  }
@@ -696,15 +705,21 @@ function cleanDeadProfileFragments(cwd) {
696
705
  if (!fs.existsSync(gmDir)) return { cleaned: 0 };
697
706
  let cleaned = 0;
698
707
  for (const name of fs.readdirSync(gmDir)) {
699
- const m = name.match(/^browser-profile-(\d+)$/);
700
- if (!m) continue;
701
- const pid = parseInt(m[1], 10);
702
- if (!isProcessAliveSync(pid)) {
703
- try {
704
- fs.rmSync(path.join(gmDir, name), { recursive: true, force: true });
705
- cleaned++;
706
- } catch (_) {}
708
+ if (!/^browser-profile($|-)/.test(name)) continue;
709
+ const dir = path.join(gmDir, name);
710
+ const pidM = name.match(/-(\d+)$/);
711
+ if (pidM) {
712
+ if (!isProcessAliveSync(parseInt(pidM[1], 10))) {
713
+ try { fs.rmSync(dir, { recursive: true, force: true }); cleaned++; } catch (_) {}
714
+ }
715
+ continue;
707
716
  }
717
+ try {
718
+ if (fs.existsSync(dir) && !isProfileLocked(dir)) {
719
+ fs.rmSync(dir, { recursive: true, force: true });
720
+ cleaned++;
721
+ }
722
+ } catch (_) {}
708
723
  }
709
724
  if (cleaned > 0) {
710
725
  logEvent('bootstrap', 'browser-profile.hygiene', { cwd, cleaned });
@@ -982,9 +997,9 @@ function getOrCreateBrowserSession(cwd, claudeSessionId, pw) {
982
997
  const sessions = readJsonFile(sessionsFile, {});
983
998
  const existing = ports[claudeSessionId];
984
999
  if (existing && existing.pid && existing.wsEndpoint) {
985
- const wantProfile = path.join(cwd, '.gm', 'browser-profile');
1000
+ const wantProfile = sessionProfileDir(cwd, claudeSessionId);
986
1001
  const pidOk = isProcessAliveSync(existing.pid);
987
- const profileOk = !existing.profileDir || existing.profileDir === wantProfile || existing.profileDir.startsWith(path.join(cwd, '.gm', 'browser-profile'));
1002
+ const profileOk = !existing.profileDir || existing.profileDir === wantProfile || existing.profileDir.startsWith(wantProfile);
988
1003
  const cdpOk = pidOk && !!fetchJsonSync(`http://127.0.0.1:${existing.port}/json/version`, 1000);
989
1004
  if (pidOk && profileOk && cdpOk) {
990
1005
  const pwIds = sessions[claudeSessionId] || [];
@@ -1033,7 +1048,7 @@ function getOrCreateBrowserSession(cwd, claudeSessionId, pw) {
1033
1048
  }
1034
1049
  }
1035
1050
  cleanDeadProfileFragments(cwd);
1036
- const profileDir = acquireProfileDir(cwd);
1051
+ const profileDir = acquireProfileDir(cwd, claudeSessionId);
1037
1052
  const aliveCdpForProfile = (() => {
1038
1053
  for (const key of Object.keys(ports)) {
1039
1054
  const ent = ports[key];
@@ -145,15 +145,18 @@ function spawnWatcher(bootReason) {
145
145
  const reason = shutdownReason && shutdownReason.reason;
146
146
  const idleClean = reason === 'idle';
147
147
  const lockRejected = code === 75;
148
- const plannedReasons = new Set(['idle', 'sigterm', 'version-change', 'wrapper-change', 'peer-stale-takeover', 'external-planned']);
149
- const isPlanned = plannedReasons.has(reason) || lockRejected;
148
+ const cleanExit = code === 0;
149
+ const plannedReasons = new Set(['idle', 'sigterm', 'version-change', 'wrapper-change', 'peer-stale-takeover', 'external-planned', 'process-exit']);
150
+ const isPlanned = plannedReasons.has(reason) || lockRejected || cleanExit;
150
151
  const eventName = idleClean
151
152
  ? 'supervisor.watcher-exited-idle'
152
153
  : reason === 'version-change'
153
154
  ? 'supervisor.watcher-exited-for-update'
154
155
  : lockRejected
155
156
  ? 'supervisor.watcher-exited-lock-rejected'
156
- : 'supervisor.watcher-exited-unexpectedly';
157
+ : cleanExit
158
+ ? 'supervisor.watcher-exited-clean'
159
+ : 'supervisor.watcher-exited-unexpectedly';
157
160
  logEvent(eventName, {
158
161
  watcher_pid: currentChildPid,
159
162
  exit_code: code,
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1489",
3
+ "version": "2.0.1491",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1489",
3
+ "version": "2.0.1491",
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",