gm-skill 2.0.1969 → 2.0.1971
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 +60 -0
- package/gm-plugkit/cli.js +36 -1
- package/gm-plugkit/gm-process.js +1 -1
- package/gm-plugkit/package.json +1 -1
- package/gm-plugkit/plugkit-wasm-wrapper.js +66 -0
- package/gm.json +1 -1
- package/package.json +1 -1
package/gm-plugkit/bootstrap.js
CHANGED
|
@@ -849,6 +849,63 @@ function ensureGmPlugkitVersionFresh() {
|
|
|
849
849
|
} catch (_) { return false; }
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
+
const SEMVER_RE = /^\d+\.\d+\.\d+$/;
|
|
853
|
+
|
|
854
|
+
function readPinnedGmPlugkitVersion() {
|
|
855
|
+
try {
|
|
856
|
+
const p = path.join(gmToolsDir(), 'gm-plugkit.version');
|
|
857
|
+
if (!fs.existsSync(p)) return null;
|
|
858
|
+
const v = fs.readFileSync(p, 'utf-8').trim();
|
|
859
|
+
if (!v || !SEMVER_RE.test(v)) return null;
|
|
860
|
+
return v;
|
|
861
|
+
} catch (_) { return null; }
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
function resolveBunRuntime() {
|
|
865
|
+
const candidates = process.platform === 'win32' ? ['bun.exe', 'bun'] : ['bun'];
|
|
866
|
+
for (const c of candidates) {
|
|
867
|
+
try {
|
|
868
|
+
const r = spawnSync('where', [c], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true, timeout: 800 });
|
|
869
|
+
if (r.status === 0) {
|
|
870
|
+
const lines = (r.stdout || '').split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
871
|
+
const exe = lines.find(l => /\.exe$/i.test(l)) || lines[0];
|
|
872
|
+
if (exe) return exe;
|
|
873
|
+
}
|
|
874
|
+
} catch (_) {}
|
|
875
|
+
}
|
|
876
|
+
return process.platform === 'win32' ? 'bun.exe' : 'bun';
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
function spawnPinnedBoot(extraArgs) {
|
|
880
|
+
const args = Array.isArray(extraArgs) ? extraArgs : [];
|
|
881
|
+
const pinned = readPinnedGmPlugkitVersion();
|
|
882
|
+
if (!pinned) {
|
|
883
|
+
return { ok: false, reason: 'no-pin-file', fallback: '@latest' };
|
|
884
|
+
}
|
|
885
|
+
const runtime = resolveBunRuntime();
|
|
886
|
+
const bunxArgs = ['x', `gm-plugkit@${pinned}`, ...args];
|
|
887
|
+
const startedMs = Date.now();
|
|
888
|
+
let result;
|
|
889
|
+
try {
|
|
890
|
+
result = spawnSync(runtime, bunxArgs, {
|
|
891
|
+
stdio: 'inherit',
|
|
892
|
+
windowsHide: true,
|
|
893
|
+
shell: false,
|
|
894
|
+
env: { ...process.env, GM_PLUGKIT_PINNED_REEXEC: '1' },
|
|
895
|
+
});
|
|
896
|
+
} catch (e) {
|
|
897
|
+
return { ok: false, reason: 'spawn-failed', error: e.message, pinned_version: pinned, fallback: '@latest' };
|
|
898
|
+
}
|
|
899
|
+
const durationMs = Date.now() - startedMs;
|
|
900
|
+
if (result.error) {
|
|
901
|
+
return { ok: false, reason: 'spawn-error', error: result.error.message, pinned_version: pinned, fallback: '@latest' };
|
|
902
|
+
}
|
|
903
|
+
if (typeof result.status === 'number' && result.status !== 0) {
|
|
904
|
+
return { ok: false, reason: 'pinned-invocation-nonzero-exit', status: result.status, pinned_version: pinned, duration_ms: durationMs, fallback: '@latest' };
|
|
905
|
+
}
|
|
906
|
+
return { ok: true, pinned_version: pinned, duration_ms: durationMs, status: result.status };
|
|
907
|
+
}
|
|
908
|
+
|
|
852
909
|
function discoverBundledSkillsAndSources() {
|
|
853
910
|
const found = new Map();
|
|
854
911
|
found.set('gm', path.join(__dirname, 'SKILL.md'));
|
|
@@ -1213,6 +1270,9 @@ module.exports = {
|
|
|
1213
1270
|
ensureGmPlugkitVersionFresh,
|
|
1214
1271
|
ensureSkillMdFresh,
|
|
1215
1272
|
ensureWrapperFresh,
|
|
1273
|
+
readPinnedGmPlugkitVersion,
|
|
1274
|
+
resolveBunRuntime,
|
|
1275
|
+
spawnPinnedBoot,
|
|
1216
1276
|
};
|
|
1217
1277
|
|
|
1218
1278
|
if (require.main === module) {
|
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, ensureWrapperFresh, isReady, getWasmPath } = require('./bootstrap');
|
|
8
|
+
const { ensureReady, startSpoolDaemon, gmToolsDir, readVersionFile, ensureGmPlugkitVersionFresh, ensureSkillMdFresh, ensureWrapperFresh, isReady, getWasmPath, readPinnedGmPlugkitVersion, spawnPinnedBoot } = require('./bootstrap');
|
|
9
9
|
|
|
10
10
|
function getWasmPathSafe() {
|
|
11
11
|
try { return getWasmPath(); } catch (_) { return null; }
|
|
@@ -77,6 +77,22 @@ Usage:
|
|
|
77
77
|
wrapper sha differs from on-disk
|
|
78
78
|
(lets new wrapper code load on next bootstrap)
|
|
79
79
|
bun x gm-plugkit@latest --help Show this help
|
|
80
|
+
|
|
81
|
+
Opt-in pinned fast-path (skips bunx's own @latest npm-registry resolution):
|
|
82
|
+
GM_PLUGKIT_PREFER_PINNED=1 bun x gm-plugkit@latest spool
|
|
83
|
+
bun x gm-plugkit@latest spool --pinned
|
|
84
|
+
Reads ~/.gm-tools/gm-plugkit.version
|
|
85
|
+
(written by every successful boot) and
|
|
86
|
+
re-execs 'bun x gm-plugkit@<pinned-exact-version>'
|
|
87
|
+
with the remaining args -- bunx skips registry
|
|
88
|
+
resolution for an exact version once cached, so
|
|
89
|
+
this is genuinely faster than @latest on repeat
|
|
90
|
+
boots. Falls back to normal @latest-driven
|
|
91
|
+
behavior automatically when no pin file exists
|
|
92
|
+
yet (first-ever boot) or the pinned invocation
|
|
93
|
+
fails (stale/unpublished pinned version).
|
|
94
|
+
Opt-in only -- the default boot line above is
|
|
95
|
+
unaffected.
|
|
80
96
|
`;
|
|
81
97
|
|
|
82
98
|
function readDiskWasmVersion() {
|
|
@@ -238,6 +254,25 @@ function writeCliError(phase, err) {
|
|
|
238
254
|
process.exit(killStaleWatchers());
|
|
239
255
|
}
|
|
240
256
|
|
|
257
|
+
const wantsPinned = process.env.GM_PLUGKIT_PREFER_PINNED === '1' || args.includes('--pinned');
|
|
258
|
+
const alreadyReexecedPinned = process.env.GM_PLUGKIT_PINNED_REEXEC === '1';
|
|
259
|
+
if (wantsPinned && !alreadyReexecedPinned) {
|
|
260
|
+
const passArgs = args.filter(a => a !== '--pinned');
|
|
261
|
+
const pinned = readPinnedGmPlugkitVersion();
|
|
262
|
+
if (pinned) {
|
|
263
|
+
writeCliStatus({ phase: 'pinned-fast-path', pinned_version: pinned });
|
|
264
|
+
const result = spawnPinnedBoot(passArgs);
|
|
265
|
+
if (result.ok) {
|
|
266
|
+
process.exit(typeof result.status === 'number' ? result.status : 0);
|
|
267
|
+
}
|
|
268
|
+
writeCliStatus({ phase: 'pinned-fast-path-fallback', reason: result.reason, pinned_version: result.pinned_version || null });
|
|
269
|
+
console.error(`[gm-plugkit] pinned fast-path failed (${result.reason}), falling back to @latest resolution`);
|
|
270
|
+
} else {
|
|
271
|
+
writeCliStatus({ phase: 'pinned-fast-path-no-pin-file' });
|
|
272
|
+
console.error('[gm-plugkit] GM_PLUGKIT_PREFER_PINNED set but no ~/.gm-tools/gm-plugkit.version pin file yet -- falling back to @latest resolution (this boot will write the pin for next time)');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
241
276
|
ensureSpoolDir();
|
|
242
277
|
writeCliStatus({ phase: 'starting', args });
|
|
243
278
|
|
package/gm-plugkit/gm-process.js
CHANGED
|
@@ -5,7 +5,7 @@ const { spawnSync } = require('child_process');
|
|
|
5
5
|
function pidCommandLineForKillGuard(pid) {
|
|
6
6
|
try {
|
|
7
7
|
if (process.platform === 'win32') {
|
|
8
|
-
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-
|
|
8
|
+
const r = spawnSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `(Get-WmiObject Win32_Process -Filter "ProcessId=${Number(pid)}").CommandLine`], { encoding: 'utf8', windowsHide: true, timeout: 5000 });
|
|
9
9
|
return String((r && r.stdout) || '');
|
|
10
10
|
}
|
|
11
11
|
const r = spawnSync('ps', ['-p', String(pid), '-o', 'args='], { encoding: 'utf8', timeout: 5000 });
|
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.1971",
|
|
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": {
|
|
@@ -2504,6 +2504,69 @@ function hostTaskProc(action, params) {
|
|
|
2504
2504
|
}
|
|
2505
2505
|
}
|
|
2506
2506
|
|
|
2507
|
+
let _gmRunnerEmbedBinPath;
|
|
2508
|
+
function resolveGmRunnerEmbedBin() {
|
|
2509
|
+
if (_gmRunnerEmbedBinPath !== undefined) return _gmRunnerEmbedBinPath;
|
|
2510
|
+
const exe = path.join(GM_TOOLS_ROOT, process.platform === 'win32' ? 'gm-runner.exe' : 'gm-runner');
|
|
2511
|
+
_gmRunnerEmbedBinPath = fs.existsSync(exe) ? exe : null;
|
|
2512
|
+
return _gmRunnerEmbedBinPath;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
// Slim-build support: plugkit-core's embed.rs probes host_vec_embed BEFORE
|
|
2516
|
+
// ever loading the 133MB wasm-embedded safetensors fallback (see
|
|
2517
|
+
// rs-plugkit/crates/plugkit-core/src/embed.rs::init_ctx) -- if this function
|
|
2518
|
+
// returns a real embedding, the wasm-side model never loads at all. Wired
|
|
2519
|
+
// here to gm-runner's OWN native candle path (crates/gm-runner/src/embed.rs)
|
|
2520
|
+
// via its `embed-text` one-shot subcommand (stdin=text,
|
|
2521
|
+
// stdout={"embedding":[...]}), a synchronous spawnSync call so the wasm-side
|
|
2522
|
+
// caller (a synchronous extern "C" import) can block on it correctly. Used
|
|
2523
|
+
// ONLY when a real ~/.gm-tools/gm-runner(.exe) binary is present on this
|
|
2524
|
+
// host; if absent, returns null immediately and the caller (host_vec_embed
|
|
2525
|
+
// below) falls through to -1, which makes plugkit-core's own probe fail and
|
|
2526
|
+
// fall back to loading the wasm-embedded fat-build safetensors model exactly
|
|
2527
|
+
// as before -- embedding capability is never silently lost on a host with no
|
|
2528
|
+
// gm-runner installed, by design (this is the real fallback the
|
|
2529
|
+
// slim-wasm-default-flip PRD row required be live before any default-feature
|
|
2530
|
+
// flip).
|
|
2531
|
+
function hostEmbedViaGmRunner(text) {
|
|
2532
|
+
const bin = resolveGmRunnerEmbedBin();
|
|
2533
|
+
if (!bin) return null;
|
|
2534
|
+
try {
|
|
2535
|
+
const r = spawnSync(bin, ['embed-text'], {
|
|
2536
|
+
input: text,
|
|
2537
|
+
encoding: 'utf-8',
|
|
2538
|
+
windowsHide: true,
|
|
2539
|
+
timeout: 30000,
|
|
2540
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
2541
|
+
});
|
|
2542
|
+
if (r.error || r.status !== 0) return null;
|
|
2543
|
+
const parsed = JSON.parse(r.stdout || '{}');
|
|
2544
|
+
if (!Array.isArray(parsed.embedding)) return null;
|
|
2545
|
+
return parsed.embedding;
|
|
2546
|
+
} catch (_) {
|
|
2547
|
+
return null;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
globalThis.__hostEmbedSync = function __hostEmbedSync(textPtr, textLen, outPtr, outLen, instance) {
|
|
2552
|
+
try {
|
|
2553
|
+
const text = readWasmStr(instance, textPtr, textLen);
|
|
2554
|
+
if (!text) return -1;
|
|
2555
|
+
const values = hostEmbedViaGmRunner(text);
|
|
2556
|
+
if (!values || values.length === 0) return -1;
|
|
2557
|
+
const dim = Math.min(values.length, outLen >>> 0);
|
|
2558
|
+
const bytes = new Uint8Array(dim * 4);
|
|
2559
|
+
const view = new DataView(bytes.buffer);
|
|
2560
|
+
for (let i = 0; i < dim; i++) view.setFloat32(i * 4, values[i], true);
|
|
2561
|
+
const buffer = instance.exports.memory.buffer;
|
|
2562
|
+
guardWasmRange(buffer, outPtr, dim * 4, '__hostEmbedSync:write');
|
|
2563
|
+
new Uint8Array(buffer, outPtr, dim * 4).set(bytes);
|
|
2564
|
+
return dim;
|
|
2565
|
+
} catch (_) {
|
|
2566
|
+
return -1;
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2569
|
+
|
|
2507
2570
|
function makeHostFunctions(instanceRef) {
|
|
2508
2571
|
return {
|
|
2509
2572
|
host_fs_read: (pathPtr, pathLen) => {
|
|
@@ -4445,6 +4508,7 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
4445
4508
|
wasm_aborted: true,
|
|
4446
4509
|
}));
|
|
4447
4510
|
fs.renameSync(abortTmpPath, abortOutPath);
|
|
4511
|
+
try { fs.writeFileSync(abortOutPath + '.ready', ''); } catch (_) {}
|
|
4448
4512
|
try { fs.unlinkSync(filePath); } catch (_) {}
|
|
4449
4513
|
} catch (_) {}
|
|
4450
4514
|
unmarkProcessed(key);
|
|
@@ -4566,6 +4630,7 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
4566
4630
|
const outTmpPath = outPath + '.tmp.' + process.pid;
|
|
4567
4631
|
fs.writeFileSync(outTmpPath, resultStr);
|
|
4568
4632
|
fs.renameSync(outTmpPath, outPath);
|
|
4633
|
+
try { fs.writeFileSync(outPath + '.ready', ''); } catch (_) {}
|
|
4569
4634
|
const dur_ms = Date.now() - t0;
|
|
4570
4635
|
console.log(`[dispatch] <- verb=${verb} task=${taskBase} ms=${dur_ms} out=${resultStr.length}b`);
|
|
4571
4636
|
logEvent('plugkit', 'dispatch.end', { verb, task: taskBase, dur_ms, out_bytes: resultStr.length });
|
|
@@ -4611,6 +4676,7 @@ async function runSpoolWatcher(instance, spoolDir) {
|
|
|
4611
4676
|
const errTmpPath = errOutPath + '.tmp.' + process.pid;
|
|
4612
4677
|
fs.writeFileSync(errTmpPath, JSON.stringify({ ok: false, error: e.message }));
|
|
4613
4678
|
fs.renameSync(errTmpPath, errOutPath);
|
|
4679
|
+
try { fs.writeFileSync(errOutPath + '.ready', ''); } catch (_) {}
|
|
4614
4680
|
} catch (_) {}
|
|
4615
4681
|
try { fs.unlinkSync(filePath); } catch (_) {}
|
|
4616
4682
|
unmarkProcessed(key);
|
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.1971",
|
|
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",
|