gm-skill 2.0.1840 → 2.0.1842
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/gm-plugkit/bootstrap.js
CHANGED
package/gm-plugkit/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const cp = require('child_process');
|
|
8
|
-
const { ensureReady, startSpoolDaemon, gmToolsDir, readVersionFile, ensureGmPlugkitVersionFresh, ensureSkillMdFresh } = require('./bootstrap');
|
|
8
|
+
const { ensureReady, startSpoolDaemon, gmToolsDir, readVersionFile, ensureGmPlugkitVersionFresh, ensureSkillMdFresh, ensureWrapperFresh } = require('./bootstrap');
|
|
9
9
|
|
|
10
10
|
function readUpdateAvailableMarker(dir) {
|
|
11
11
|
try {
|
|
@@ -217,6 +217,8 @@ function writeCliError(phase, err) {
|
|
|
217
217
|
try { ensureGmPlugkitVersionFresh(); } catch (_) {}
|
|
218
218
|
let skillRefresh = null;
|
|
219
219
|
try { skillRefresh = ensureSkillMdFresh(); } catch (_) {}
|
|
220
|
+
let wrapperRefreshed = false;
|
|
221
|
+
try { wrapperRefreshed = ensureWrapperFresh(); } catch (_) {}
|
|
220
222
|
writeCliStatus({ phase: 'ready', already_serving: true, watcher_pid: already.pid });
|
|
221
223
|
console.log(JSON.stringify({
|
|
222
224
|
ok: true,
|
|
@@ -224,7 +226,10 @@ function writeCliError(phase, err) {
|
|
|
224
226
|
watcher_pid: already.pid,
|
|
225
227
|
version: already.version,
|
|
226
228
|
skills_refreshed: skillRefresh && skillRefresh.refreshed || [],
|
|
227
|
-
|
|
229
|
+
wrapper_refreshed: wrapperRefreshed,
|
|
230
|
+
message: wrapperRefreshed
|
|
231
|
+
? 'plugkit already serving; wrapper file on disk was stale and has been refreshed -- restart the watcher to load it'
|
|
232
|
+
: 'plugkit already serving, no bootstrap/spawn needed',
|
|
228
233
|
}));
|
|
229
234
|
process.exit(0);
|
|
230
235
|
}
|
|
@@ -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
|
package/gm-plugkit/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gm-plugkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1842",
|
|
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(
|
|
1373
|
-
try {
|
|
1374
|
-
|
|
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
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
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) {
|
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.1842",
|
|
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",
|
package/skills/gm/SKILL.md
CHANGED
|
@@ -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.
|