gm-skill 2.0.1468 → 2.0.1469
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/AGENTS.md +1 -1
- package/bin/bootstrap.js +20 -160
- package/gm-plugkit/bootstrap.js +2 -12
- package/gm-plugkit/package.json +1 -1
- package/gm.json +1 -1
- package/package.json +1 -1
- package/bin/rtk.sha256 +0 -6
package/AGENTS.md
CHANGED
|
@@ -40,7 +40,7 @@ Agents dispatch verbs by writing to `.gm/exec-spool/in/<verb>/<N>.txt` (request
|
|
|
40
40
|
|
|
41
41
|
**git verbs**: `git_status` returns `{dirty, modified, untracked, deleted, staged}` from `git status --porcelain`. `branch_status` returns `{branch, ahead, behind, remote}`, the `remote-pushed` witness. `git_push` is the ONLY admissible push surface, it gates on `git_porcelain()` non-empty (refuses dirty), emits `deviation.push-dirty` on attempt, and shells the push only when clean. A raw `git push` via Bash bypasses the gate and is itself a deviation; ccsniff `--git-discipline` flags it.
|
|
42
42
|
|
|
43
|
-
**filter verb**: pure stdout → compact-stdout transformation. Body `{kind, input, ...opts}` where kind is one of `grep`, `ls`, `tree`, `json`, `diff`, `git-status`, `log`. Returns `{output, stats:{bytes_in, bytes_out, saved_pct, ...}}`. Pipe raw command output through filter before letting it enter context,
|
|
43
|
+
**filter verb**: pure stdout → compact-stdout transformation. Body `{kind, input, ...opts}` where kind is one of `grep`, `ls`, `tree`, `json`, `diff`, `git-status`, `log`. Returns `{output, stats:{bytes_in, bytes_out, saved_pct, ...}}`. Pipe raw command output through filter before letting it enter context, in-wasm, no subprocess. The bootstrap fetches only `plugkit.wasm`, there is no separate filter/rtk binary download.
|
|
44
44
|
|
|
45
45
|
## Documentation Policy
|
|
46
46
|
|
package/bin/bootstrap.js
CHANGED
|
@@ -187,11 +187,6 @@ function obsEvent(subsystem, event, fields) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
function rtkBinaryName() {
|
|
191
|
-
const key = platformKey();
|
|
192
|
-
return key.startsWith('win32') ? `rtk-${key}.exe` : `rtk-${key}`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
190
|
function cacheRoot() {
|
|
196
191
|
const home = os.homedir();
|
|
197
192
|
if (process.env.PLUGKIT_CACHE_DIR) return process.env.PLUGKIT_CACHE_DIR;
|
|
@@ -256,12 +251,6 @@ function readVersionFile(wrapperDir) {
|
|
|
256
251
|
return fs.readFileSync(p, 'utf8').trim();
|
|
257
252
|
}
|
|
258
253
|
|
|
259
|
-
function readRtkVersion(wrapperDir) {
|
|
260
|
-
const p = path.join(wrapperDir, 'rtk.version');
|
|
261
|
-
if (!fs.existsSync(p)) return null;
|
|
262
|
-
const v = fs.readFileSync(p, 'utf8').trim();
|
|
263
|
-
return v || null;
|
|
264
|
-
}
|
|
265
254
|
|
|
266
255
|
function sha256OfFileSync(filePath) {
|
|
267
256
|
const h = crypto.createHash('sha256');
|
|
@@ -432,15 +421,12 @@ function isLockStale(lockPath) {
|
|
|
432
421
|
return false;
|
|
433
422
|
}
|
|
434
423
|
|
|
435
|
-
function pruneOldVersions(root, keepVersion
|
|
424
|
+
function pruneOldVersions(root, keepVersion) {
|
|
436
425
|
try {
|
|
437
426
|
const entries = fs.readdirSync(root);
|
|
438
427
|
for (const e of entries) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (!isPlugkit && !isRtk) continue;
|
|
442
|
-
if (isPlugkit && e === `v${keepVersion}`) continue;
|
|
443
|
-
if (isRtk && keepRtkVersion && e === `rtk-v${keepRtkVersion}`) continue;
|
|
428
|
+
if (!e.startsWith('v')) continue;
|
|
429
|
+
if (e === `v${keepVersion}`) continue;
|
|
444
430
|
const dir = path.join(root, e);
|
|
445
431
|
const lock = path.join(dir, '.lock');
|
|
446
432
|
if (fs.existsSync(lock) && !isLockStale(lock)) continue;
|
|
@@ -502,7 +488,6 @@ async function bootstrap(opts) {
|
|
|
502
488
|
|
|
503
489
|
if (healIfShaMatches(wasmFinalPath, wasmExpectedSha, wasmOkSentinel, wasmPartialPath, 'wasm')) {
|
|
504
490
|
obsEvent('bootstrap', 'decision.heal', { reason: 'sha-match', path: wasmFinalPath });
|
|
505
|
-
spawnDetachedRtkFetch(wrapperDir);
|
|
506
491
|
copyWasmToGmTools(wasmFinalPath, wrapperDir, version);
|
|
507
492
|
clearBootstrapError();
|
|
508
493
|
return wasmFinalPath;
|
|
@@ -519,7 +504,6 @@ async function bootstrap(opts) {
|
|
|
519
504
|
}
|
|
520
505
|
if (healIfShaMatches(wasmFinalPath, wasmExpectedSha, wasmOkSentinel, wasmPartialPath, 'wasm')) {
|
|
521
506
|
obsEvent('bootstrap', 'decision.heal', { reason: 'sha-match-under-lock', path: wasmFinalPath });
|
|
522
|
-
spawnDetachedRtkFetch(wrapperDir);
|
|
523
507
|
copyWasmToGmTools(wasmFinalPath, wrapperDir, version);
|
|
524
508
|
clearBootstrapError();
|
|
525
509
|
return wasmFinalPath;
|
|
@@ -574,8 +558,7 @@ async function bootstrap(opts) {
|
|
|
574
558
|
fs.writeFileSync(wasmOkSentinel, new Date().toISOString());
|
|
575
559
|
log(`decision: fetch reason: install-complete (${wasmFinalPath})`);
|
|
576
560
|
obsEvent('bootstrap', 'install.done', { path: wasmFinalPath, version, kind: 'wasm' });
|
|
577
|
-
pruneOldVersions(root, version
|
|
578
|
-
spawnDetachedRtkFetch(wrapperDir);
|
|
561
|
+
pruneOldVersions(root, version);
|
|
579
562
|
copyWasmToGmTools(wasmFinalPath, wrapperDir, version);
|
|
580
563
|
|
|
581
564
|
clearBootstrapError();
|
|
@@ -585,109 +568,6 @@ async function bootstrap(opts) {
|
|
|
585
568
|
}
|
|
586
569
|
}
|
|
587
570
|
|
|
588
|
-
function spawnDetachedRtkFetch(wrapperDir) {
|
|
589
|
-
try {
|
|
590
|
-
const { spawn } = require('child_process');
|
|
591
|
-
const child = spawn(process.execPath, [__filename, '--rtk-only', '--wrapper-dir', wrapperDir], {
|
|
592
|
-
detached: true,
|
|
593
|
-
stdio: 'ignore',
|
|
594
|
-
windowsHide: true,
|
|
595
|
-
});
|
|
596
|
-
child.unref();
|
|
597
|
-
obsEvent('bootstrap', 'rtk.detached.spawned', { pid: child.pid, wrapperDir });
|
|
598
|
-
} catch (err) {
|
|
599
|
-
log(`rtk detach spawn failed: ${err.message}`);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
function rtkCacheDir(root, wrapperDir, plugkitVerDir) {
|
|
604
|
-
const rtkVer = readRtkVersion(wrapperDir);
|
|
605
|
-
if (!rtkVer) return plugkitVerDir;
|
|
606
|
-
const dir = path.join(root, `rtk-v${rtkVer}`);
|
|
607
|
-
ensureDir(dir);
|
|
608
|
-
return dir;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
async function bootstrapRtk(plugkitVerDir, plugkitVersion, wrapperDir, silent, root) {
|
|
612
|
-
const rtkName = rtkBinaryName();
|
|
613
|
-
const cacheDir = rtkCacheDir(root || cacheRoot(), wrapperDir, plugkitVerDir);
|
|
614
|
-
const rtkPath = path.join(cacheDir, rtkName);
|
|
615
|
-
const rtkOk = path.join(cacheDir, '.rtk-ok');
|
|
616
|
-
if (fs.existsSync(rtkPath) && fs.existsSync(rtkOk)) {
|
|
617
|
-
if (!silent) log(`rtk cache hit: ${rtkPath}`);
|
|
618
|
-
return rtkPath;
|
|
619
|
-
}
|
|
620
|
-
const rtkSha = readShaManifest(wrapperDir, 'rtk.sha256');
|
|
621
|
-
const expected = rtkSha ? rtkSha[rtkName] : null;
|
|
622
|
-
const tmp = `${rtkPath}.partial`;
|
|
623
|
-
if (healIfShaMatches(rtkPath, expected, rtkOk, tmp, 'rtk')) {
|
|
624
|
-
if (!silent) log(`rtk cache heal (sha match): ${rtkPath}`);
|
|
625
|
-
return rtkPath;
|
|
626
|
-
}
|
|
627
|
-
const RTKS_RELEASE_REPO = 'AnEntrypoint/plugkit-bin';
|
|
628
|
-
const url = `https://github.com/${RTKS_RELEASE_REPO}/releases/download/v${plugkitVersion}/${rtkName}`;
|
|
629
|
-
const startMs = Date.now();
|
|
630
|
-
let lastErr;
|
|
631
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
632
|
-
try {
|
|
633
|
-
log(`rtk download attempt ${attempt}/${MAX_ATTEMPTS}: ${url}`);
|
|
634
|
-
const result = spawnSync(
|
|
635
|
-
'curl',
|
|
636
|
-
['-fSL', '--max-time', String(Math.floor(ATTEMPT_TIMEOUT_MS / 1000)), '-o', tmp, url],
|
|
637
|
-
{ stdio: 'pipe', timeout: ATTEMPT_TIMEOUT_MS + 5000, windowsHide: true }
|
|
638
|
-
);
|
|
639
|
-
if (result.error) throw result.error;
|
|
640
|
-
if (result.status !== 0) throw new Error(`curl failed with status ${result.status}`);
|
|
641
|
-
break;
|
|
642
|
-
} catch (err) {
|
|
643
|
-
lastErr = err;
|
|
644
|
-
log(`rtk attempt ${attempt} failed: ${err.message}`);
|
|
645
|
-
obsEvent('bootstrap', 'rtk.download.attempt_failed', { attempt, max: MAX_ATTEMPTS, err: String(err.message || err) });
|
|
646
|
-
if (attempt < MAX_ATTEMPTS) {
|
|
647
|
-
const wait = BACKOFF_MS[attempt - 1] || 120000;
|
|
648
|
-
log(`backing off ${wait}ms`);
|
|
649
|
-
await new Promise(r => setTimeout(r, wait));
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
if (lastErr) throw lastErr;
|
|
654
|
-
if (expected) {
|
|
655
|
-
const got = await sha256OfFile(tmp);
|
|
656
|
-
if (got !== expected) {
|
|
657
|
-
try { fs.unlinkSync(tmp); } catch (_) {}
|
|
658
|
-
throw new Error(`rtk sha256 mismatch: expected ${expected}, got ${got}`);
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
try { fs.renameSync(tmp, rtkPath); }
|
|
662
|
-
catch (err) {
|
|
663
|
-
if (err.code === 'EEXIST' || err.code === 'EPERM') {
|
|
664
|
-
try { fs.unlinkSync(rtkPath); } catch (_) {}
|
|
665
|
-
fs.renameSync(tmp, rtkPath);
|
|
666
|
-
} else throw err;
|
|
667
|
-
}
|
|
668
|
-
if (os.platform() !== 'win32') { try { fs.chmodSync(rtkPath, 0o755); } catch (_) {} }
|
|
669
|
-
fs.writeFileSync(rtkOk, new Date().toISOString());
|
|
670
|
-
log(`installed ${rtkPath}`);
|
|
671
|
-
obsEvent('bootstrap', 'install.done', { path: rtkPath, plugkit_version: plugkitVersion, rtk_version: readRtkVersion(wrapperDir) || plugkitVersion, kind: 'rtk', dur_ms: Date.now() - startMs });
|
|
672
|
-
return rtkPath;
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
function resolveCachedRtk(opts) {
|
|
676
|
-
opts = opts || {};
|
|
677
|
-
const wrapperDir = opts.wrapperDir || __dirname;
|
|
678
|
-
const version = opts.version || readVersionFile(wrapperDir);
|
|
679
|
-
const root = (() => {
|
|
680
|
-
try { const r = cacheRoot(); ensureDir(r); return r; }
|
|
681
|
-
catch (_) { const r = fallbackCacheRoot(); ensureDir(r); return r; }
|
|
682
|
-
})();
|
|
683
|
-
const plugkitVerDir = path.join(root, `v${version}`);
|
|
684
|
-
const cacheDir = rtkCacheDir(root, wrapperDir, plugkitVerDir);
|
|
685
|
-
const rtkPath = path.join(cacheDir, rtkBinaryName());
|
|
686
|
-
const rtkOk = path.join(cacheDir, '.rtk-ok');
|
|
687
|
-
if (fs.existsSync(rtkPath) && fs.existsSync(rtkOk)) return rtkPath;
|
|
688
|
-
return null;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
571
|
function getWasmPath(opts) {
|
|
692
572
|
opts = opts || {};
|
|
693
573
|
const wrapperDir = opts.wrapperDir || __dirname;
|
|
@@ -801,44 +681,24 @@ function killStaleDaemonIfVersionChanged(wrapperDir) {
|
|
|
801
681
|
writeDaemonVersion(currentVersion);
|
|
802
682
|
}
|
|
803
683
|
|
|
804
|
-
module.exports = { bootstrap, getWasmPath,
|
|
684
|
+
module.exports = { bootstrap, getWasmPath, cacheRoot, obsEvent, killRunningDaemons, killStaleDaemonIfVersionChanged, killSpoolWatcherInCwd, proactiveKillForNewInstall };
|
|
805
685
|
|
|
806
686
|
if (require.main === module) {
|
|
807
687
|
const argv = process.argv.slice(2);
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
688
|
+
bootstrap({ silent: false })
|
|
689
|
+
.then(p => { process.stdout.write(p + '\n'); process.exit(0); })
|
|
690
|
+
.catch(err => {
|
|
691
|
+
log(`FATAL: ${err.message}`);
|
|
692
|
+
obsEvent('bootstrap', 'fatal', { err: String(err.message || err) });
|
|
812
693
|
try {
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
process.exit(1);
|
|
824
|
-
}
|
|
825
|
-
})();
|
|
826
|
-
} else {
|
|
827
|
-
bootstrap({ silent: false })
|
|
828
|
-
.then(p => { process.stdout.write(p + '\n'); process.exit(0); })
|
|
829
|
-
.catch(err => {
|
|
830
|
-
log(`FATAL: ${err.message}`);
|
|
831
|
-
obsEvent('bootstrap', 'fatal', { err: String(err.message || err) });
|
|
832
|
-
try {
|
|
833
|
-
const pinned = (() => { try { return readVersionFile(__dirname); } catch (_) { return null; } })();
|
|
834
|
-
writeBootstrapError({
|
|
835
|
-
expected_version: pinned,
|
|
836
|
-
cached_version: null,
|
|
837
|
-
error_phase: 'fatal',
|
|
838
|
-
error_message: String(err && err.message || err),
|
|
839
|
-
});
|
|
840
|
-
} catch (_) {}
|
|
841
|
-
process.exit(1);
|
|
842
|
-
});
|
|
843
|
-
}
|
|
694
|
+
const pinned = (() => { try { return readVersionFile(__dirname); } catch (_) { return null; } })();
|
|
695
|
+
writeBootstrapError({
|
|
696
|
+
expected_version: pinned,
|
|
697
|
+
cached_version: null,
|
|
698
|
+
error_phase: 'fatal',
|
|
699
|
+
error_message: String(err && err.message || err),
|
|
700
|
+
});
|
|
701
|
+
} catch (_) {}
|
|
702
|
+
process.exit(1);
|
|
703
|
+
});
|
|
844
704
|
}
|
package/gm-plugkit/bootstrap.js
CHANGED
|
@@ -329,14 +329,6 @@ async function extractNpmPackageWithRetry(destPath, version) {
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
|
|
332
|
-
function platformKey() {
|
|
333
|
-
const p = os.platform();
|
|
334
|
-
const a = os.arch();
|
|
335
|
-
if (p === 'win32') return a === 'arm64' ? 'win32-arm64' : 'win32-x64';
|
|
336
|
-
if (p === 'darwin') return a === 'arm64' ? 'darwin-arm64' : 'darwin-x64';
|
|
337
|
-
return (a === 'arm64' || a === 'aarch64') ? 'linux-arm64' : 'linux-x64';
|
|
338
|
-
}
|
|
339
|
-
|
|
340
332
|
function healIfShaMatches(binPath, expectedSha, sentinelPath, partialPath, kind) {
|
|
341
333
|
if (!fs.existsSync(binPath)) return false;
|
|
342
334
|
if (partialPath) { try { if (fs.existsSync(partialPath)) fs.unlinkSync(partialPath); } catch (_) {} }
|
|
@@ -428,10 +420,8 @@ function pruneOldVersions(root, keepVersion) {
|
|
|
428
420
|
try {
|
|
429
421
|
const entries = fs.readdirSync(root);
|
|
430
422
|
for (const e of entries) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (!isPlugkit && !isRtk) continue;
|
|
434
|
-
if (isPlugkit && e === `v${keepVersion}`) continue;
|
|
423
|
+
if (!e.startsWith('v')) continue;
|
|
424
|
+
if (e === `v${keepVersion}`) continue;
|
|
435
425
|
const dir = path.join(root, e);
|
|
436
426
|
const lock = path.join(dir, '.lock');
|
|
437
427
|
if (fs.existsSync(lock) && !isLockStale(lock)) continue;
|
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.1469",
|
|
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": {
|
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.1469",
|
|
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/bin/rtk.sha256
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
53224d66572e937507a8d2877c768e4e6cc3da66aa6f8d0f132afaab2edc2a10 rtk-win32-x64.exe
|
|
2
|
-
dedabc1d89641c60c91f09570353b6270dba4f5d53f8597018a708e515265d53 rtk-win32-arm64.exe
|
|
3
|
-
cf3190554b82c7395948b7a478c78bbe2241549b00777e660deff4cbb9e0c4b6 rtk-darwin-x64
|
|
4
|
-
c815bad459b4eaccc8be4a5d74dba397fdfe7d3716e0b6023b188d2351128b82 rtk-darwin-arm64
|
|
5
|
-
7d60dd5abc15f6d46ffd89b5de7253a067e2a3ef6f1cd8ae5a236eda05a504f4 rtk-linux-x64
|
|
6
|
-
cd5dd78035845eef4b362927c61f61e23925af3c12779131024d8334bad87a6b rtk-linux-arm64
|