gm-skill 2.0.1841 → 2.0.1843

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 +1 @@
1
- 0.1.840
1
+ 0.1.841
@@ -1 +1 @@
1
- 1c158d73707afaabe93a67270076573a4bd89a93262ff52f9c691277074b873f plugkit.wasm
1
+ d98719a4fca87818408763e4c52d56f704544f073b2a0477cadd37fd0d9a7e46 plugkit.wasm
@@ -18,6 +18,8 @@ PRD = `|F|=1` plan-item store: enumerate every node in the destructive transform
18
18
 
19
19
  **Inherited rows resume first.** `ready_wave`/`prd_pending>0` at entry = undone transform, not someone else's -- THIS cover's first slice. Resume to `prd-resolve` (witnessed) or explicit re-scope/close before any fresh row; disjoint fresh cover orphaning inherited rows = stopped mid-transform, not finished.
20
20
 
21
+ **`prd-resolve` at PLAN is bound by the same false-completion rule as VERIFY, not exempt because the row was inherited.** A `prd-resolve` whose `witness_evidence` says "deferred"/"pending next session"/"pending browser fix"/"awaits [X] recovery"/"user must refresh" is marking undone work done -- forbidden regardless of phase. Real external blockers (browser environment down, credential missing, another team's repo) keep the row `status: pending` with `blockedBy: [external, "<specific reason>"]`; they are never grounds to resolve as `completed`. A session that repeatedly hits the same external blocker (e.g. browser verb crashing every attempt) `prd-add`s a row naming the blocker itself as the thing to fix -- diagnose and repair the tool (see BROWSER discipline), not paper over it with a completed status on the original row.
22
+
21
23
  "Every possible" load-bears: apply to every noun/surface/transform/output the request reaches, each application a row. Single-digit count on non-trivial request = stopped early -- re-orient, re-enumerate. Density, not minimality, is the COMPLETE-time invariant. Inline TODO in response body violates `|F|=1`.
22
24
 
23
25
  ## Expansion
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1841",
3
+ "version": "2.0.1843",
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": {
@@ -1314,6 +1314,7 @@ function startManagedBrowser(pw, profileDir, cwd) {
1314
1314
  logEvent('plugkit', 'browser.launch-failed', { reason: 'chromium-missing' });
1315
1315
  throw err;
1316
1316
  }
1317
+ try { reapOrphanChromiums(cwd, 'pre-spawn'); } catch (_) {}
1317
1318
  const port = findFreePortSync();
1318
1319
  let noSandbox = process.env.GM_BROWSER_NO_SANDBOX === '1';
1319
1320
  let { pid, chromeLogPath } = spawnChromiumOnce(browserBin, profileDir, port, headless, noSandbox, cwd);
@@ -1366,36 +1367,47 @@ function sleepSyncMs(ms) {
1366
1367
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms | 0);
1367
1368
  }
1368
1369
 
1370
+ const __browserClosingPids = new Set();
1371
+
1369
1372
  function gracefulCloseBrowser(entry, reason) {
1370
1373
  if (!entry) return;
1371
1374
  const { pid, port, profileDir } = entry;
1372
- if (Number.isFinite(port) && port > 0) {
1373
- try {
1374
- const info = fetchJsonSync(`http://127.0.0.1:${port}/json/version`, 600);
1375
- if (info && info.webSocketDebuggerUrl) {
1376
- spawnSync(process.execPath, ['-e', `
1377
- const http = require('http');
1378
- const req = http.request({host:'127.0.0.1',port:${port},path:'/json/close/browser',method:'GET',timeout:1500},
1379
- res => { res.resume(); res.on('end', () => process.exit(0)); });
1380
- req.on('error', () => process.exit(1));
1381
- req.on('timeout', () => { req.destroy(); process.exit(1); });
1382
- req.end();
1383
- `], { timeout: 3000, windowsHide: true });
1384
- }
1385
- } catch (_) {}
1375
+ if (Number.isFinite(pid) && pid > 0 && __browserClosingPids.has(pid)) {
1376
+ try { logEvent('plugkit', 'browser.close-skipped-already-closing', { pid, reason: reason || 'close' }); } catch (_) {}
1377
+ return;
1386
1378
  }
1387
- if (Number.isFinite(pid) && pid > 0) {
1388
- if (isProcessAliveSync(pid) && !pidIsManagedChromium(pid)) {
1389
- try { logEvent('plugkit', 'browser.kill-skipped-pid-reused', { pid, reason: reason || 'close' }); } catch (_) {}
1390
- } else {
1391
- const deadline = Date.now() + 1500;
1392
- try { process.kill(pid, 'SIGTERM'); } catch (_) {}
1393
- while (Date.now() < deadline && isProcessAliveSync(pid)) sleepSyncMs(Math.min(150, deadline - Date.now()));
1394
- if (isProcessAliveSync(pid)) killPidQuiet(pid);
1379
+ if (Number.isFinite(pid) && pid > 0) __browserClosingPids.add(pid);
1380
+ try {
1381
+ if (Number.isFinite(port) && port > 0) {
1382
+ try {
1383
+ const info = fetchJsonSync(`http://127.0.0.1:${port}/json/version`, 600);
1384
+ if (info && info.webSocketDebuggerUrl) {
1385
+ spawnSync(process.execPath, ['-e', `
1386
+ const http = require('http');
1387
+ const req = http.request({host:'127.0.0.1',port:${port},path:'/json/close/browser',method:'GET',timeout:1500},
1388
+ res => { res.resume(); res.on('end', () => process.exit(0)); });
1389
+ req.on('error', () => process.exit(1));
1390
+ req.on('timeout', () => { req.destroy(); process.exit(1); });
1391
+ req.end();
1392
+ `], { timeout: 3000, windowsHide: true });
1393
+ }
1394
+ } catch (_) {}
1395
+ }
1396
+ if (Number.isFinite(pid) && pid > 0) {
1397
+ if (isProcessAliveSync(pid) && !pidIsManagedChromium(pid)) {
1398
+ try { logEvent('plugkit', 'browser.kill-skipped-pid-reused', { pid, reason: reason || 'close' }); } catch (_) {}
1399
+ } else {
1400
+ const deadline = Date.now() + 1500;
1401
+ try { process.kill(pid, 'SIGTERM'); } catch (_) {}
1402
+ while (Date.now() < deadline && isProcessAliveSync(pid)) sleepSyncMs(Math.min(150, deadline - Date.now()));
1403
+ if (isProcessAliveSync(pid)) killPidQuiet(pid);
1404
+ }
1395
1405
  }
1406
+ purgeProfileLockFiles(profileDir);
1407
+ try { logEvent('plugkit', 'browser.closed', { reason: reason || 'closed', pid, port, profileDir }); } catch (_) {}
1408
+ } finally {
1409
+ if (Number.isFinite(pid) && pid > 0) __browserClosingPids.delete(pid);
1396
1410
  }
1397
- purgeProfileLockFiles(profileDir);
1398
- try { logEvent('plugkit', 'browser.closed', { reason: reason || 'closed', pid, port, profileDir }); } catch (_) {}
1399
1411
  }
1400
1412
 
1401
1413
  function checkSessionNavigatedAway(port, claudeSessionId) {
@@ -1 +1 @@
1
- 0.1.840
1
+ 0.1.841
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1841",
3
+ "version": "2.0.1843",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -17,5 +17,5 @@
17
17
  "publishConfig": {
18
18
  "access": "public"
19
19
  },
20
- "plugkitVersion": "0.1.840"
20
+ "plugkitVersion": "0.1.841"
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1841",
3
+ "version": "2.0.1843",
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",
@@ -70,6 +70,8 @@ Spool input from PowerShell must be UTF-8 no-BOM (`-Encoding utf8` or `[System.I
70
70
 
71
71
  **EXECUTE resolves all mutables before EMIT, discovers more, resolves those too, rearchitects immediately on in-spirit discovery.** Any architectural improvement discovered mid-EXECUTE is an immediate `transition to=PLAN`, re-`prd-add` the affected row with its existing id (re-scope, never delete-and-re-add) -- maximal-effort correctness over preservation-for-its-own-sake, no deferral, no "note for later."
72
72
 
73
+ **`prd-resolve` is bound by the false-completion rule in every phase, PLAN included -- not only at VERIFY.** A row marked `status: completed` whose witness says "deferred", "pending next session", "pending browser fix", "awaits [X] recovery", "user must refresh", or any equivalent hedge is undone work labeled done -- forbidden, the same class as a mock standing in for real code. A genuinely external blocker (browser environment down, credential missing, another team's repo) keeps the row `status: pending` with `blockedBy: [external, "<specific reason>"]`; it is never grounds to resolve as completed. A blocker that recurs across sessions (the same tool crashing every attempt) becomes its own PRD row naming the tool defect to fix -- diagnose and repair it, never paper over the original row with a completed status while the real work stays undone.
74
+
73
75
  VERIFY is adversarial, never confirmatory: run the real code path and read its actual output via `exec_js` or `browser` -- a finding is only real once witnessed by execution this turn. Never assert a crash, pass, or defect from memory, prior session state, or written prose alone. A gate denial (e.g. `residual.skipped` on dirty worktree) is resolved immediately by the named recovery action (commit or revert the listed files, then re-dispatch the same verb) in the same turn -- it is never grounds to re-enter PLAN, add unrelated PRD rows, or narrate the blocker instead of clearing it.
74
76
 
75
77
  **Every residual is triaged this turn; "pre-existing" is not a stop excuse.** Non-empty `git status --porcelain`: every entry is yours now -- commit (real work), add to managed gitignore (transient runtime files), or revert (stale junk). PRD entries live in `.gm/prd.yml`. `.gm/disciplines/` and new memorize-fire JSON are tracked. `.gm/witness/` and staleness markers go in managed gitignore.