gm-skill 2.0.2024 → 2.0.2026
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 +7 -11
- package/bin/bootstrap.js +1 -1
- package/bin/install.js +31 -9
- package/bin/plugkit-slim.wasm.sha256 +1 -1
- package/bin/plugkit.version +1 -1
- package/bin/plugkit.wasm.sha256 +1 -1
- package/gm-plugkit/bootstrap.js +35 -152
- package/gm-plugkit/cli.js +31 -168
- package/gm-plugkit/package.json +3 -5
- package/gm-plugkit/plugkit-slim.wasm.sha256 +1 -1
- package/gm-plugkit/plugkit.version +1 -1
- package/gm.json +2 -2
- package/package.json +1 -3
- package/skills/gm/SKILL.md +4 -4
- package/gm-plugkit/plugkit-wasm-wrapper.js +0 -4939
- package/gm-plugkit/wrapper/cdp-eval.js +0 -123
- package/gm-plugkit/wrapper/fs-atomic.js +0 -26
- package/gm-plugkit/wrapper/kv-store.js +0 -81
- package/gm-plugkit/wrapper/task-manager.js +0 -272
- package/gm-plugkit/wrapper/wasi-shim.js +0 -377
- package/gm-plugkit/wrapper/wasm-bridge.js +0 -71
package/AGENTS.md
CHANGED
|
@@ -24,23 +24,19 @@ Skills encode environment-specific constraints that override general knowledge.
|
|
|
24
24
|
|
|
25
25
|
Repo root = package root = published `gm-skill` npm package; no factory, no separate build-output dir. Entry: `skills/gm/SKILL.md`. Orchestration lives in rs-plugkit, served on-demand via `instruction`. The 8 phase-prose files (entry/plan/execute/emit/verify/consolidate/update_docs/browser) live single-sourced inside rs-plugkit itself (`crates/plugkit-core/src/orchestrator/instructions/prose/*.md`, `include_str!`'d at build) -- a prose edit there requires a Rust rebuild via the normal cascade, no cross-repo sync step. Gate/residual text stays genuinely zero-rebuild: editable `gm-plugkit/instructions/gates/` and `gm-plugkit/instructions/residual/` in this repo, read at runtime with `prose.rs`'s per-key fallback to a compiled default (`.gm/instructions/<key>.md` per-project-overridable). Detail in the recall store (`recall: string-externalization project`).
|
|
26
26
|
|
|
27
|
-
## WASM guest,
|
|
27
|
+
## WASM guest, one native host (agentplug-runner is the sole loader)
|
|
28
28
|
|
|
29
|
-
Plugkit-core = the wasm cdylib guest (the gm brain), published as `plugkit.wasm`/`plugkit-slim.wasm` from `AnEntrypoint/plugkit-bin` by the cascade. It is host-agnostic
|
|
29
|
+
Plugkit-core = the wasm cdylib guest (the gm brain), published as `plugkit.wasm`/`plugkit-slim.wasm` from `AnEntrypoint/plugkit-bin` by the cascade. It is host-agnostic, and `agentplug-runner` is the SOLE host that loads it. The JS wasm-host (`plugkit-wasm-wrapper.js` + `gm-plugkit/wrapper/`) and the redundant `gm-runner` native host are both retired -- there is no fallback loader; agentplug-runner is required.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
2. **`gm-runner`** (rs-plugkit `crates/gm-runner/`, published to `AnEntrypoint/gm-runner-bin`) -- a native FALLBACK, tried second. Loads the same wasm as a single module with a stub `host_plugin_call` and no shared-plugin routing; strictly a subset of agentplug-runner. Its own CDP browser + task registry were ported to match agentplug. Retirement is tracked (`gm-runner-redundant-host-consolidation`).
|
|
33
|
-
3. **`plugkit-wasm-wrapper.js`** (JS/bun, in `gm-plugkit/`) -- the original JS host, tried last, only when no native runner is published for the platform. The `gm-plugkit` npm identity + `bootstrap.js` (seed/refresh) + `cli.js` (delegation) stay load-bearing as the thin launcher edge (`bun x gm-plugkit@latest spool` re-execs into the first available native runner and exits); the wrapper's own wasm-host code + `supervisor.js` only run as the pure-JS fallback.
|
|
31
|
+
**`agentplug-runner`** (repo `AnEntrypoint/agentplug`, published to `AnEntrypoint/agentplug-bin`) is a real native wasmtime binary that loads gm.wasm as one plugin among siblings (`bert`/`libsql`/`treesitter`), routing gm.wasm's `host_plugin_call`/`host_vec_embed` to those shared plugins. This is why gm fetches `plugkit-slim.wasm` (no baked-in embedding weights -- bert supplies them out-of-wasm). `.status.json` `runtime` reads `agentplug`. Browser is driven via direct CDP and task via a native process registry, both native in agentplug-host (agentplug's `crates/agentplug-host/src/browser.rs` has its own embedded `cdp_eval.js`, so the browser verb needs nothing from the retired JS wrapper).
|
|
34
32
|
|
|
35
|
-
`
|
|
33
|
+
The `gm-plugkit` npm identity stays load-bearing as the thin launcher edge only: `bun x gm-plugkit@latest spool` (`cli.js::tryDelegateToRunner`) re-execs into `~/.gm-tools/agentplug-runner` and exits; `bootstrap.js` still seeds per-project wiring and downloads `plugkit.wasm`/`plugkit-slim.wasm` (sha256-pinned) from `plugkit-bin`. `startSpoolDaemon()` launches agentplug-runner or, when it is absent, fails loudly with an actionable install message -- there is no silent no-loader state. Size + embedded-model mechanics: the recall store (`recall: WASM-only plugkit size mechanics`).
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
**`bin/install.js` hard-requires agentplug-runner.** It downloads the sha256-verified native runner from `AnEntrypoint/agentplug-bin` for the host platform, and if none is published (or the download/verify fails) it fails the install loudly with a clear message rather than leaving the user with no loader. There is no JS-host fallback to silently fall through to anymore.
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()`** (recall store: `recall: wrapper require not defined under bun`).
|
|
37
|
+
**agentplug-runner auto-updates the wasm it serves, not itself.** It polls `plugkit-bin`'s Releases API every 600s for a newer tag; on a mismatch it downloads+verifies the new wasm and a local-version-skew check triggers a clean in-process reload. The runner *executable* self-updates only via `bin/install.js` re-run (it additionally adopts a staged `.new` on the next start).
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
Wasm host-import link-module rule (`#[link(wasm_import_module="env")]` on every host-import extern block, every dep crate): the recall store (`recall: wasm host-import link-module trap`).
|
|
44
40
|
|
|
45
41
|
**Every single-instance/lock guard is atomic** (O_EXCL / atomic-rename), never check-then-act (recall store: `recall: supervisor churn TOCTOU atomic guard`).
|
|
46
42
|
|
package/bin/bootstrap.js
CHANGED
|
@@ -595,7 +595,7 @@ function pidCommandLineForKillGuard(pid) {
|
|
|
595
595
|
}
|
|
596
596
|
|
|
597
597
|
function pidIsPlugkitProcess(pid) {
|
|
598
|
-
return /
|
|
598
|
+
return /agentplug-runner(\.exe)?/i.test(pidCommandLineForKillGuard(pid));
|
|
599
599
|
}
|
|
600
600
|
|
|
601
601
|
function writeKillAttribution(targetSpoolDir, info) {
|
package/bin/install.js
CHANGED
|
@@ -176,7 +176,9 @@ function runPlugkitBootstrap() {
|
|
|
176
176
|
// agentplug-runner's CI (AnEntrypoint/agentplug's .github/workflows/release.yml)
|
|
177
177
|
// publishing to AnEntrypoint/agentplug-bin -- must stay byte-identical to that
|
|
178
178
|
// workflow's `artifact:` matrix values. Returns null for a host combination CI
|
|
179
|
-
// does not build
|
|
179
|
+
// does not build; agentplug-runner is the sole spool loader now (the JS host
|
|
180
|
+
// was retired), so a null here means there is no loader for this platform and
|
|
181
|
+
// the installer fails loudly rather than leaving a silent no-loader state.
|
|
180
182
|
function agentplugRunnerAssetName() {
|
|
181
183
|
const plat = process.platform;
|
|
182
184
|
const arch = process.arch;
|
|
@@ -231,15 +233,14 @@ function gmToolsDir() {
|
|
|
231
233
|
}
|
|
232
234
|
|
|
233
235
|
|
|
234
|
-
// Downloads agentplug-runner (the
|
|
235
|
-
//
|
|
236
|
+
// Downloads agentplug-runner (the SOLE native wasm plugin-host -- hosts gm.wasm
|
|
237
|
+
// plus the separate libsql/bert/treesitter plugin wasm modules via a
|
|
236
238
|
// host-mediated plugin_call ABI) from agentplug-bin's GitHub Releases,
|
|
237
239
|
// sha256-sidecar-verified with an atomic rename, so a corrupt/partial download
|
|
238
|
-
// is never accepted.
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
// 6-platform parity (it was a strictly-inferior single-module duplicate).
|
|
240
|
+
// is never accepted. Returns true on success, false on any failure (offline,
|
|
241
|
+
// unpublished platform, network, sha mismatch). The JS wasm-host was retired,
|
|
242
|
+
// so agentplug-runner is required: main() hard-fails the install when this
|
|
243
|
+
// returns false, rather than leaving the user with no spool loader at all.
|
|
243
244
|
async function downloadAgentplugRunner({ silent } = {}) {
|
|
244
245
|
const assetName = agentplugRunnerAssetName();
|
|
245
246
|
if (!assetName) {
|
|
@@ -350,7 +351,28 @@ async function main() {
|
|
|
350
351
|
}
|
|
351
352
|
|
|
352
353
|
await runPlugkitBootstrap();
|
|
353
|
-
|
|
354
|
+
|
|
355
|
+
// agentplug-runner is the sole spool loader (the JS wasm-host was retired).
|
|
356
|
+
// Its download is a HARD requirement -- if the platform has no published
|
|
357
|
+
// binary, or the download/verification fails, there is no loader at all, so
|
|
358
|
+
// fail loudly with an actionable message rather than silently leaving the
|
|
359
|
+
// user with an installed skill that cannot boot a spool watcher.
|
|
360
|
+
const runnerReady = await downloadAgentplugRunner({ silent: false });
|
|
361
|
+
if (!runnerReady) {
|
|
362
|
+
const asset = agentplugRunnerAssetName();
|
|
363
|
+
err('');
|
|
364
|
+
err('FATAL: agentplug-runner could not be installed, and it is the sole spool loader.');
|
|
365
|
+
if (!asset) {
|
|
366
|
+
err(`No agentplug-runner binary is published for this platform (${process.platform}/${process.arch}).`);
|
|
367
|
+
err('The JS wasm-host fallback has been retired, so there is no loader available for this platform.');
|
|
368
|
+
err('Request a build at https://github.com/AnEntrypoint/agentplug-bin/issues, or install on a supported');
|
|
369
|
+
err('platform: linux-x64, linux-arm64, macos-x64, macos-arm64, windows-x64, windows-arm64.');
|
|
370
|
+
} else {
|
|
371
|
+
err(`The download or sha256 verification of ${asset} from AnEntrypoint/agentplug-bin failed`);
|
|
372
|
+
err('(see the messages above). Check your network/proxy and re-run: npx gm-skill install');
|
|
373
|
+
}
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
354
376
|
|
|
355
377
|
out('');
|
|
356
378
|
out('Done. Open Claude Code and run /gm. New top-level skill dirs may need one restart to register.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
fc7364d869507c548db7846b67e71084c8d9c0c5a18c39a09afaf3f28155d4cd plugkit-slim.wasm
|
package/bin/plugkit.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.936
|
package/bin/plugkit.wasm.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6492759f1cf535d6b899f22d1a31c00296397ae493aa755a6c735940128d9b18 plugkit.wasm
|
package/gm-plugkit/bootstrap.js
CHANGED
|
@@ -258,19 +258,17 @@ function gmToolsDir() {
|
|
|
258
258
|
// before ever loading its wasm-embedded safetensors fallback (see
|
|
259
259
|
// rs-plugkit/crates/plugkit-core/src/embed.rs::init_ctx) -- a slim build
|
|
260
260
|
// (feature=slim, no embedded weights at all) is only safe to fetch on a host
|
|
261
|
-
// that actually answers host_vec_embed for real.
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
// no host_vec_embed answer will ever come, so fetching fat (which carries its
|
|
268
|
-
// own wasm-side embedding fallback) is the only safe choice.
|
|
261
|
+
// that actually answers host_vec_embed for real. agentplug-runner answers it
|
|
262
|
+
// via its shared bert plugin daemon; the check is gated on the runner binary
|
|
263
|
+
// existing under ~/.gm-tools so bootstrap-time artifact selection and runtime
|
|
264
|
+
// embed-delegation eligibility never disagree. Absence means no host_vec_embed
|
|
265
|
+
// answer will ever come, so fetching fat (which carries its own wasm-side
|
|
266
|
+
// embedding fallback) is the only safe choice.
|
|
269
267
|
function hasNativeEmbedRunner() {
|
|
270
268
|
const dir = gmToolsDir();
|
|
271
269
|
const names = process.platform === 'win32'
|
|
272
|
-
? ['
|
|
273
|
-
: ['
|
|
270
|
+
? ['agentplug-runner.exe']
|
|
271
|
+
: ['agentplug-runner'];
|
|
274
272
|
return names.some(n => { try { return fs.existsSync(path.join(dir, n)); } catch (_) { return false; } });
|
|
275
273
|
}
|
|
276
274
|
|
|
@@ -279,21 +277,21 @@ function hasNativeEmbedRunner() {
|
|
|
279
277
|
// agents, each `git worktree add`-ing a fresh physical directory) shares the
|
|
280
278
|
// SAME underlying repo as its main checkout but has its own separate
|
|
281
279
|
// directory tree. Every cwd-derived project-dir computation in this file and
|
|
282
|
-
// in
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
//
|
|
287
|
-
//
|
|
280
|
+
// in cli.js must funnel through this so a worktree-spawned process resolves to
|
|
281
|
+
// the SAME .gm/exec-spool/ as its main-repo sibling -- otherwise the
|
|
282
|
+
// single-instance watcher guard can never see a sibling worktree's
|
|
283
|
+
// already-running watcher, and every worktree cold-boots its own independent
|
|
284
|
+
// watcher (each loading the full embed model + running its own cold reindex of
|
|
285
|
+
// what is, conceptually, the same project). Live-measured
|
|
288
286
|
// this session under real concurrent multi-agent load: this was the actual
|
|
289
287
|
// root cause of a user-flagged "memory grows to ~2GB then clears" churn
|
|
290
288
|
// pattern -- N worktrees of one repo each independently paying full
|
|
291
289
|
// cold-embed cost instead of sharing one already-warm watcher, and the
|
|
292
290
|
// resulting CPU contention pushed genuinely-busy processes past their
|
|
293
291
|
// heartbeat deadline into a restart cycle that produces the sawtooth memory
|
|
294
|
-
// pattern.
|
|
295
|
-
//
|
|
296
|
-
//
|
|
292
|
+
// pattern. agentplug-runner roots its own browser-session state at the git
|
|
293
|
+
// common dir for the same reason (same fix, same reason, applied one layer up
|
|
294
|
+
// at the process-boot-dedup level).
|
|
297
295
|
function resolveProjectRoot(start) {
|
|
298
296
|
const resolved = path.resolve(start);
|
|
299
297
|
try {
|
|
@@ -373,23 +371,6 @@ function releaseLock(lockPath) {
|
|
|
373
371
|
try { fs.unlinkSync(lockPath); } catch (_) {}
|
|
374
372
|
}
|
|
375
373
|
|
|
376
|
-
function resolveNpxJsCli() {
|
|
377
|
-
if (process.platform !== 'win32') return null;
|
|
378
|
-
const candidates = [];
|
|
379
|
-
if (process.env.npm_config_prefix) {
|
|
380
|
-
candidates.push(path.join(process.env.npm_config_prefix, 'node_modules', 'npm', 'bin', 'npx-cli.js'));
|
|
381
|
-
}
|
|
382
|
-
const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
|
|
383
|
-
candidates.push(path.join(programFiles, 'nodejs', 'node_modules', 'npm', 'bin', 'npx-cli.js'));
|
|
384
|
-
candidates.push(path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npx-cli.js'));
|
|
385
|
-
const appdata = process.env.APPDATA;
|
|
386
|
-
if (appdata) candidates.push(path.join(appdata, 'npm', 'node_modules', 'npm', 'bin', 'npx-cli.js'));
|
|
387
|
-
for (const c of candidates) {
|
|
388
|
-
try { if (fs.existsSync(c)) return c; } catch (_) {}
|
|
389
|
-
}
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
374
|
async function extractNpmPackageWasm(destPath, version) {
|
|
394
375
|
const tempDir = path.join(path.dirname(destPath), '.npm-extract-' + Date.now());
|
|
395
376
|
try {
|
|
@@ -590,7 +571,7 @@ function pidCommandLineForKillGuard(pid) {
|
|
|
590
571
|
}
|
|
591
572
|
|
|
592
573
|
function pidIsPlugkitProcess(pid) {
|
|
593
|
-
return /
|
|
574
|
+
return /agentplug-runner(\.exe)?/i.test(pidCommandLineForKillGuard(pid));
|
|
594
575
|
}
|
|
595
576
|
|
|
596
577
|
function writeKillAttribution(targetSpoolDir, info) {
|
|
@@ -854,8 +835,6 @@ function copyWasmToGmTools(wasmPath, version) {
|
|
|
854
835
|
const dst = gmToolsDir();
|
|
855
836
|
fs.mkdirSync(dst, { recursive: true });
|
|
856
837
|
const target = path.join(dst, 'plugkit.wasm');
|
|
857
|
-
const wrapperSrc = path.join(__dirname, 'plugkit-wasm-wrapper.js');
|
|
858
|
-
const wrapperDst = path.join(dst, 'plugkit-wasm-wrapper.js');
|
|
859
838
|
|
|
860
839
|
let wasmFresh = false;
|
|
861
840
|
if (fs.existsSync(target)) {
|
|
@@ -888,17 +867,6 @@ function copyWasmToGmTools(wasmPath, version) {
|
|
|
888
867
|
}
|
|
889
868
|
} catch (_) {}
|
|
890
869
|
|
|
891
|
-
if (fs.existsSync(wrapperSrc)) {
|
|
892
|
-
let wrapperFresh = false;
|
|
893
|
-
if (fs.existsSync(wrapperDst)) {
|
|
894
|
-
try {
|
|
895
|
-
const cur = sha256OfFileSync(wrapperDst);
|
|
896
|
-
const src = sha256OfFileSync(wrapperSrc);
|
|
897
|
-
if (cur === src) wrapperFresh = true;
|
|
898
|
-
} catch (_) {}
|
|
899
|
-
}
|
|
900
|
-
if (!wrapperFresh) fs.copyFileSync(wrapperSrc, wrapperDst);
|
|
901
|
-
}
|
|
902
870
|
}
|
|
903
871
|
|
|
904
872
|
function getWasmPath() {
|
|
@@ -915,60 +883,6 @@ function isReady() {
|
|
|
915
883
|
return fs.existsSync(wasm);
|
|
916
884
|
}
|
|
917
885
|
|
|
918
|
-
function runningFromGmSourceRepo() {
|
|
919
|
-
try {
|
|
920
|
-
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
921
|
-
if (!fs.existsSync(pkgPath)) return false;
|
|
922
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
923
|
-
return pkg && pkg.name === 'gm-skill';
|
|
924
|
-
} catch (_) { return false; }
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
function ensureWrapperFresh() {
|
|
928
|
-
try {
|
|
929
|
-
const wrapperSrc = path.join(__dirname, 'plugkit-wasm-wrapper.js');
|
|
930
|
-
const wrapperDst = path.join(gmToolsDir(), 'plugkit-wasm-wrapper.js');
|
|
931
|
-
if (!fs.existsSync(wrapperSrc)) return false;
|
|
932
|
-
if (runningFromGmSourceRepo() && process.env.GM_PLUGKIT_ALLOW_DEV_WRAPPER_OVERWRITE !== '1') {
|
|
933
|
-
log(`refusing to overwrite the shared ~/.gm-tools wrapper from the gm source repo (${wrapperSrc}) -- this machine-wide install is shared by every project's watcher; set GM_PLUGKIT_ALLOW_DEV_WRAPPER_OVERWRITE=1 to opt in, or use 'bun x gm-plugkit@latest' which fetches an isolated npm copy instead`);
|
|
934
|
-
return false;
|
|
935
|
-
}
|
|
936
|
-
let same = false;
|
|
937
|
-
if (fs.existsSync(wrapperDst)) {
|
|
938
|
-
try {
|
|
939
|
-
const a = sha256OfFileSync(wrapperSrc);
|
|
940
|
-
const b = sha256OfFileSync(wrapperDst);
|
|
941
|
-
if (a === b) same = true;
|
|
942
|
-
} catch (_) {}
|
|
943
|
-
}
|
|
944
|
-
if (same) return false;
|
|
945
|
-
// Many independent per-project watchers share this one gmToolsDir() install --
|
|
946
|
-
// concurrent CLI invocations from different projects can race this copy, so
|
|
947
|
-
// it's lock-guarded (atomic O_EXCL) + tmp-write-then-rename, never a direct
|
|
948
|
-
// in-place copyFileSync another reader could observe half-written.
|
|
949
|
-
fs.mkdirSync(gmToolsDir(), { recursive: true });
|
|
950
|
-
const lockPath = wrapperDst + '.lock';
|
|
951
|
-
acquireLock(lockPath);
|
|
952
|
-
try {
|
|
953
|
-
let stillSame = false;
|
|
954
|
-
if (fs.existsSync(wrapperDst)) {
|
|
955
|
-
try {
|
|
956
|
-
const a = sha256OfFileSync(wrapperSrc);
|
|
957
|
-
const b = sha256OfFileSync(wrapperDst);
|
|
958
|
-
if (a === b) stillSame = true;
|
|
959
|
-
} catch (_) {}
|
|
960
|
-
}
|
|
961
|
-
if (stillSame) return false;
|
|
962
|
-
const tmpDst = wrapperDst + '.tmp.' + process.pid;
|
|
963
|
-
fs.copyFileSync(wrapperSrc, tmpDst);
|
|
964
|
-
fs.renameSync(tmpDst, wrapperDst);
|
|
965
|
-
return true;
|
|
966
|
-
} finally {
|
|
967
|
-
releaseLock(lockPath);
|
|
968
|
-
}
|
|
969
|
-
} catch (_) { return false; }
|
|
970
|
-
}
|
|
971
|
-
|
|
972
886
|
function ensureGmPlugkitVersionFresh() {
|
|
973
887
|
try {
|
|
974
888
|
const ownPkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
|
|
@@ -1223,10 +1137,9 @@ async function ensureReady(opts) {
|
|
|
1223
1137
|
|
|
1224
1138
|
if (isReady() && !versionDrift) {
|
|
1225
1139
|
const wasmPath = getWasmPath();
|
|
1226
|
-
const wrapperUpdated = ensureWrapperFresh();
|
|
1227
1140
|
const versionMarkerUpdated = ensureGmPlugkitVersionFresh();
|
|
1228
1141
|
ensureSkillMdFresh();
|
|
1229
|
-
return { ok: true, wasmPath, binaryPath: wasmPath, status:
|
|
1142
|
+
return { ok: true, wasmPath, binaryPath: wasmPath, status: versionMarkerUpdated ? 'version-refreshed' : 'already-ready', version: installed };
|
|
1230
1143
|
}
|
|
1231
1144
|
if (targetVersion && targetVersion !== pinnedVersion) {
|
|
1232
1145
|
try {
|
|
@@ -1243,7 +1156,6 @@ async function ensureReady(opts) {
|
|
|
1243
1156
|
if (versionDrift && isReady()) {
|
|
1244
1157
|
log(`bootstrap for ${targetVersion} failed (${bootErr.message || bootErr}); keeping running watcher on installed ${installed} (no kill, serve cached wasm)`);
|
|
1245
1158
|
const cachedPath = getWasmPath();
|
|
1246
|
-
ensureWrapperFresh();
|
|
1247
1159
|
ensureSkillMdFresh();
|
|
1248
1160
|
return { ok: true, wasmPath: cachedPath, binaryPath: cachedPath, status: 'bootstrap-failed-served-cached', version: installed };
|
|
1249
1161
|
}
|
|
@@ -1254,7 +1166,6 @@ async function ensureReady(opts) {
|
|
|
1254
1166
|
try { killSpoolWatcherInCwd(`version_drift:${installed}->${targetVersion}`); } catch (_) {}
|
|
1255
1167
|
}
|
|
1256
1168
|
|
|
1257
|
-
ensureWrapperFresh();
|
|
1258
1169
|
ensureSkillMdFresh();
|
|
1259
1170
|
return { ok: true, wasmPath, binaryPath: wasmPath, status: 'bootstrapped', version: targetVersion || installed };
|
|
1260
1171
|
}
|
|
@@ -1263,46 +1174,21 @@ function getBinaryPath() {
|
|
|
1263
1174
|
return getWasmPath();
|
|
1264
1175
|
}
|
|
1265
1176
|
|
|
1266
|
-
function resolveNodeRuntime() {
|
|
1267
|
-
const candidates = [];
|
|
1268
|
-
if (process.env.PLUGKIT_RUNTIME) candidates.push(process.env.PLUGKIT_RUNTIME);
|
|
1269
|
-
candidates.push('bun');
|
|
1270
|
-
try {
|
|
1271
|
-
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
1272
|
-
const out = require('child_process').spawnSync(which, ['bun'], { encoding: 'utf8', windowsHide: true });
|
|
1273
|
-
if (out && out.stdout) {
|
|
1274
|
-
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
1275
|
-
if (first) candidates.push(first);
|
|
1276
|
-
}
|
|
1277
|
-
} catch (_) {}
|
|
1278
|
-
for (const c of candidates) {
|
|
1279
|
-
try { const r = require('child_process').spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
1280
|
-
}
|
|
1281
|
-
const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
|
|
1282
|
-
const nodeCandidates = [];
|
|
1283
|
-
if (isNodeExe(process.env.GM_NODE_PATH)) nodeCandidates.push(process.env.GM_NODE_PATH);
|
|
1284
|
-
if (isNodeExe(process.execPath)) nodeCandidates.push(process.execPath);
|
|
1285
|
-
try {
|
|
1286
|
-
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
1287
|
-
const out = require('child_process').spawnSync(which, ['node'], { encoding: 'utf8', windowsHide: true });
|
|
1288
|
-
if (out && out.stdout) {
|
|
1289
|
-
const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
|
|
1290
|
-
if (first) nodeCandidates.push(first);
|
|
1291
|
-
}
|
|
1292
|
-
} catch (_) {}
|
|
1293
|
-
for (const c of nodeCandidates) {
|
|
1294
|
-
try { const r = require('child_process').spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
|
|
1295
|
-
}
|
|
1296
|
-
return process.execPath;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
1177
|
function startSpoolDaemon() {
|
|
1300
1178
|
try {
|
|
1301
|
-
const
|
|
1302
|
-
|
|
1303
|
-
|
|
1179
|
+
const runnerName = process.platform === 'win32' ? 'agentplug-runner.exe' : 'agentplug-runner';
|
|
1180
|
+
const runner = path.join(gmToolsDir(), runnerName);
|
|
1181
|
+
if (!fs.existsSync(runner)) {
|
|
1182
|
+
return {
|
|
1183
|
+
ok: false,
|
|
1184
|
+
error:
|
|
1185
|
+
`agentplug-runner is not installed at ${runner} and is the sole supported spool loader. ` +
|
|
1186
|
+
`The JS wasm-host has been retired. Install it with 'bun x gm-skill install' (or 'npx gm-skill install'), ` +
|
|
1187
|
+
`which downloads the sha256-verified native runner from AnEntrypoint/agentplug-bin for this platform ` +
|
|
1188
|
+
`(${process.platform}/${process.arch}). If no binary is published for this platform yet, there is no ` +
|
|
1189
|
+
`loader available -- file an issue at https://github.com/AnEntrypoint/agentplug-bin so a binary is built for it.`,
|
|
1190
|
+
};
|
|
1304
1191
|
}
|
|
1305
|
-
const runtime = resolveNodeRuntime();
|
|
1306
1192
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
1307
1193
|
const spoolDir = path.join(projectDir, '.gm', 'exec-spool');
|
|
1308
1194
|
fs.mkdirSync(spoolDir, { recursive: true });
|
|
@@ -1315,20 +1201,18 @@ function startSpoolDaemon() {
|
|
|
1315
1201
|
}
|
|
1316
1202
|
} catch (_) {}
|
|
1317
1203
|
|
|
1318
|
-
const cmd = runtime;
|
|
1319
|
-
const args = [wrapper, 'spool'];
|
|
1320
1204
|
const logFd = fs.openSync(logPath, 'a');
|
|
1321
|
-
try { fs.writeSync(logFd, `\n--- daemon spawn ${new Date().toISOString()} parent=${process.pid} (
|
|
1322
|
-
const child = require('child_process').spawn(
|
|
1205
|
+
try { fs.writeSync(logFd, `\n--- daemon spawn ${new Date().toISOString()} parent=${process.pid} (agentplug-runner) ---\n`); } catch (_) {}
|
|
1206
|
+
const child = require('child_process').spawn(runner, ['spool'], {
|
|
1323
1207
|
detached: true,
|
|
1324
1208
|
stdio: ['ignore', logFd, logFd],
|
|
1325
1209
|
windowsHide: true,
|
|
1326
|
-
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir, PLUGKIT_BOOT_REASON: '
|
|
1210
|
+
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir, PLUGKIT_BOOT_REASON: 'agentplug-runner' },
|
|
1327
1211
|
});
|
|
1328
1212
|
try { fs.closeSync(logFd); } catch (_) {}
|
|
1329
1213
|
const pid = child.pid;
|
|
1330
1214
|
child.unref();
|
|
1331
|
-
return { ok: true, pid,
|
|
1215
|
+
return { ok: true, pid, runner, logPath, supervised: false };
|
|
1332
1216
|
} catch (e) {
|
|
1333
1217
|
return { ok: false, error: e.message };
|
|
1334
1218
|
}
|
|
@@ -1356,7 +1240,6 @@ module.exports = {
|
|
|
1356
1240
|
readVersionFile,
|
|
1357
1241
|
ensureGmPlugkitVersionFresh,
|
|
1358
1242
|
ensureSkillMdFresh,
|
|
1359
|
-
ensureWrapperFresh,
|
|
1360
1243
|
readPinnedGmPlugkitVersion,
|
|
1361
1244
|
resolveBunRuntime,
|
|
1362
1245
|
spawnPinnedBoot,
|