gm-skill 2.0.1974 → 2.0.1976

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/bin/install.js CHANGED
@@ -199,6 +199,31 @@ function gmRunnerAssetName() {
199
199
  return null;
200
200
  }
201
201
 
202
+ // Same mapping as gmRunnerAssetName, for agentplug-runner's own CI
203
+ // (AnEntrypoint/agentplug's .github/workflows/release.yml) publishing to
204
+ // AnEntrypoint/agentplug-bin -- must stay byte-identical to that workflow's
205
+ // `artifact:` matrix values.
206
+ function agentplugRunnerAssetName() {
207
+ const plat = process.platform;
208
+ const arch = process.arch;
209
+ if (plat === 'win32') {
210
+ if (arch === 'x64') return 'agentplug-runner-windows-x64.exe';
211
+ if (arch === 'arm64') return 'agentplug-runner-windows-arm64.exe';
212
+ return null;
213
+ }
214
+ if (plat === 'darwin') {
215
+ if (arch === 'x64') return 'agentplug-runner-macos-x64';
216
+ if (arch === 'arm64') return 'agentplug-runner-macos-arm64';
217
+ return null;
218
+ }
219
+ if (plat === 'linux') {
220
+ if (arch === 'x64') return 'agentplug-runner-linux-x64';
221
+ if (arch === 'arm64') return 'agentplug-runner-linux-arm64';
222
+ return null;
223
+ }
224
+ return null;
225
+ }
226
+
202
227
  function httpsGetBuffer(url, redirectsLeft) {
203
228
  if (redirectsLeft === undefined) redirectsLeft = 5;
204
229
  return new Promise((resolve, reject) => {
@@ -285,6 +310,60 @@ async function downloadGmRunner({ silent } = {}) {
285
310
  }
286
311
  }
287
312
 
313
+ // Downloads agentplug-runner (the generic wasm plugin-host runner gm-runner
314
+ // is migrating to -- hosts gm.wasm plus optional libsql/bert/treesitter
315
+ // plugin wasm modules via a host-mediated plugin_call ABI) from
316
+ // agentplug-bin's GitHub Releases, same sha256-sidecar/atomic-rename trust
317
+ // model as downloadGmRunner. Installed ALONGSIDE gm-runner, not instead of
318
+ // it yet -- cli.js's tryDelegateToRunner prefers agentplug-runner when
319
+ // present (it's the same spool ABI, agentplug-runner is a strict superset),
320
+ // falling back to gm-runner, falling back to bun/npx, so an agentplug-bin
321
+ // download failure (new/unpublished platform, network issue) never
322
+ // regresses an install that already had a working gm-runner.
323
+ async function downloadAgentplugRunner({ silent } = {}) {
324
+ const assetName = agentplugRunnerAssetName();
325
+ if (!assetName) {
326
+ if (!silent) err(`agentplug-runner: no published binary for platform=${process.platform} arch=${process.arch}, skipping`);
327
+ return false;
328
+ }
329
+ const destDir = gmToolsDir();
330
+ const destPath = path.join(destDir, assetName.endsWith('.exe') ? 'agentplug-runner.exe' : 'agentplug-runner');
331
+ try {
332
+ const releaseInfo = JSON.parse((await httpsGetBuffer('https://api.github.com/repos/AnEntrypoint/agentplug-bin/releases/latest')).toString('utf8'));
333
+ const tag = releaseInfo && releaseInfo.tag_name;
334
+ if (!tag) { if (!silent) err('agentplug-runner: no releases published yet at AnEntrypoint/agentplug-bin, skipping'); return false; }
335
+ const base = `https://github.com/AnEntrypoint/agentplug-bin/releases/download/${tag}`;
336
+ const binUrl = `${base}/${assetName}`;
337
+ const shaUrl = `${binUrl}.sha256`;
338
+
339
+ const versionFile = path.join(destDir, 'agentplug-runner.version');
340
+ if (fs.existsSync(destPath) && fs.existsSync(versionFile)) {
341
+ const installed = fs.readFileSync(versionFile, 'utf8').trim();
342
+ if (installed === tag) { if (!silent) out(`agentplug-runner ${tag} already installed at ${destPath}`); return true; }
343
+ }
344
+
345
+ const [binBuf, shaBuf] = await Promise.all([httpsGetBuffer(binUrl), httpsGetBuffer(shaUrl)]);
346
+ const expectedSha = shaBuf.toString('utf8').trim().split(/\s+/)[0];
347
+ const actualSha = sha256Hex(binBuf);
348
+ if (!expectedSha || actualSha.toLowerCase() !== expectedSha.toLowerCase()) {
349
+ if (!silent) err(`agentplug-runner: sha256 mismatch downloading ${binUrl} (expected ${expectedSha}, got ${actualSha}), not installing`);
350
+ return false;
351
+ }
352
+
353
+ fs.mkdirSync(destDir, { recursive: true });
354
+ const tmp = destPath + '.tmp' + process.pid;
355
+ fs.writeFileSync(tmp, binBuf);
356
+ if (process.platform !== 'win32') { try { fs.chmodSync(tmp, 0o755); } catch (_) {} }
357
+ fs.renameSync(tmp, destPath);
358
+ fs.writeFileSync(versionFile, tag);
359
+ if (!silent) out(`Installed agentplug-runner ${tag} to ${destPath}`);
360
+ return true;
361
+ } catch (e) {
362
+ if (!silent) err(`agentplug-runner download skipped: ${e && e.message || e}`);
363
+ return false;
364
+ }
365
+ }
366
+
288
367
  function printHelp() {
289
368
  out('gm installer');
290
369
  out('');
@@ -336,6 +415,7 @@ async function main() {
336
415
 
337
416
  await runPlugkitBootstrap();
338
417
  await downloadGmRunner({ silent: false });
418
+ await downloadAgentplugRunner({ silent: false });
339
419
 
340
420
  out('');
341
421
  out('Done. Open Claude Code and run /gm. New top-level skill dirs may need one restart to register.');
package/gm-plugkit/cli.js CHANGED
@@ -248,21 +248,34 @@ function writeCliError(phase, err) {
248
248
  // This is the actual code-level enforcement of what was previously only a
249
249
  // documented convention (SKILL.md telling an LLM agent to manually prefer
250
250
  // gm-runner) -- with this in place bun/node are only ever exercised on a
251
- // platform gm-runner-bin has no published binary for, or during the
252
- // one-time install before gm-runner itself lands on disk.
253
- function tryDelegateToGmRunner(args) {
251
+ // platform neither runner has a published binary for, or during the
252
+ // one-time install before either runner lands on disk.
253
+ //
254
+ // agentplug-runner is tried FIRST, gm-runner second -- agentplug-runner
255
+ // serves the identical spool ABI (same in/out layout, same verb names;
256
+ // gm.wasm is just one of its loadable plugins now) so it's a strict
257
+ // superset, not an alternative; gm-runner stays as the fallback for any
258
+ // install that has it but hasn't picked up agentplug-runner yet (installer
259
+ // re-run pending, or a platform agentplug-bin hasn't published for yet
260
+ // while gm-runner-bin already has).
261
+ function tryDelegateToRunner(args) {
254
262
  if (process.env.GM_PLUGKIT_NO_RUNNER_DELEGATE === '1') return false;
255
- const exeName = process.platform === 'win32' ? 'gm-runner.exe' : 'gm-runner';
256
- const runnerPath = path.join(gmToolsDir(), exeName);
257
- if (!fs.existsSync(runnerPath)) return false;
258
- try {
259
- const result = cp.spawnSync(runnerPath, args, { stdio: 'inherit', windowsHide: true });
260
- if (result.error) return false; // exec genuinely failed to start -- fall through to bun/node path
261
- process.exit(typeof result.status === 'number' ? result.status : 0);
262
- } catch (_) {
263
- return false;
263
+ const candidates = process.platform === 'win32'
264
+ ? ['agentplug-runner.exe', 'gm-runner.exe']
265
+ : ['agentplug-runner', 'gm-runner'];
266
+ for (const exeName of candidates) {
267
+ const runnerPath = path.join(gmToolsDir(), exeName);
268
+ if (!fs.existsSync(runnerPath)) continue;
269
+ try {
270
+ const result = cp.spawnSync(runnerPath, args, { stdio: 'inherit', windowsHide: true });
271
+ if (result.error) continue; // this candidate genuinely failed to start -- try the next one
272
+ process.exit(typeof result.status === 'number' ? result.status : 0);
273
+ } catch (_) {
274
+ continue;
275
+ }
276
+ return true;
264
277
  }
265
- return true;
278
+ return false;
266
279
  }
267
280
 
268
281
  (async () => {
@@ -273,7 +286,7 @@ function tryDelegateToGmRunner(args) {
273
286
  process.exit(0);
274
287
  }
275
288
 
276
- tryDelegateToGmRunner(args);
289
+ tryDelegateToRunner(args);
277
290
 
278
291
  if (args.includes('--kill-stale-watchers')) {
279
292
  process.exit(killStaleWatchers());
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1974",
3
+ "version": "2.0.1976",
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": {
@@ -2548,6 +2548,55 @@ function hostEmbedViaGmRunner(text) {
2548
2548
  }
2549
2549
  }
2550
2550
 
2551
+ let _agentplugRunnerBinPath;
2552
+ function resolveAgentplugRunnerBin() {
2553
+ if (_agentplugRunnerBinPath !== undefined) return _agentplugRunnerBinPath;
2554
+ const exe = path.join(GM_TOOLS_ROOT, process.platform === 'win32' ? 'agentplug-runner.exe' : 'agentplug-runner');
2555
+ _agentplugRunnerBinPath = fs.existsSync(exe) ? exe : null;
2556
+ return _agentplugRunnerBinPath;
2557
+ }
2558
+
2559
+ // plugkit-core's wasm now imports env:host_plugin_call unconditionally (the
2560
+ // agentplug migration routes libsql/bert/treesitter through it instead of
2561
+ // linking them in-process) -- WITHOUT this import registered, WebAssembly.
2562
+ // instantiate throws a hard LinkError and the wasm never boots at all, not
2563
+ // just a degraded-capability fallback like host_vec_embed's absence. This
2564
+ // delegates to agentplug-runner's `dispatch <plugin> <verb> <body>` one-shot
2565
+ // subcommand (same synchronous spawnSync shape as hostEmbedViaGmRunner
2566
+ // above) when a real ~/.gm-tools/agentplug-runner(.exe) is present; when
2567
+ // absent, returns a real, typed {"ok":false,"error":"not_implemented_js_wrapper"}
2568
+ // envelope instead of a JS-side exception -- lets wasm instantiation and
2569
+ // every non-plugin-dependent verb keep working, with only the specific
2570
+ // libsql/bert/treesitter-backed verbs (sql_*, recall, memorize, codesearch)
2571
+ // failing loud and typed rather than the whole session going dark.
2572
+ function hostPluginCallViaAgentplugRunner(plugin, verb, body) {
2573
+ const bin = resolveAgentplugRunnerBin();
2574
+ if (!bin) return null;
2575
+ try {
2576
+ const r = spawnSync(bin, ['dispatch', plugin, verb, body], {
2577
+ encoding: 'utf-8',
2578
+ windowsHide: true,
2579
+ timeout: 30000,
2580
+ maxBuffer: 64 * 1024 * 1024,
2581
+ });
2582
+ if (r.error || r.status !== 0) return null;
2583
+ return r.stdout;
2584
+ } catch (_) {
2585
+ return null;
2586
+ }
2587
+ }
2588
+
2589
+ globalThis.__hostPluginCallSync = function __hostPluginCallSync(pluginPtr, pluginLen, verbPtr, verbLen, bodyPtr, bodyLen, instance) {
2590
+ const plugin = readWasmStr(instance, pluginPtr, pluginLen);
2591
+ const verb = readWasmStr(instance, verbPtr, verbLen);
2592
+ const body = readWasmStr(instance, bodyPtr, bodyLen);
2593
+ const result = hostPluginCallViaAgentplugRunner(plugin, verb, body);
2594
+ const out = result != null
2595
+ ? result
2596
+ : JSON.stringify({ ok: false, error: 'not_implemented_js_wrapper', plugin });
2597
+ return writeWasmJson(instance, JSON.parse(out));
2598
+ };
2599
+
2551
2600
  globalThis.__hostEmbedSync = function __hostEmbedSync(textPtr, textLen, outPtr, outLen, instance) {
2552
2601
  try {
2553
2602
  const text = readWasmStr(instance, textPtr, textLen);
@@ -2737,6 +2786,14 @@ function makeHostFunctions(instanceRef) {
2737
2786
  return -1;
2738
2787
  },
2739
2788
 
2789
+ host_plugin_call: (pluginPtr, pluginLen, verbPtr, verbLen, bodyPtr, bodyLen) => {
2790
+ try {
2791
+ return globalThis.__hostPluginCallSync(pluginPtr, pluginLen, verbPtr, verbLen, bodyPtr, bodyLen, instanceRef.value);
2792
+ } catch (_) {
2793
+ return 0n;
2794
+ }
2795
+ },
2796
+
2740
2797
  host_vec_search: (qPtr, qLen, k) => {
2741
2798
  try {
2742
2799
  const raw = readWasmStr(instanceRef.value, qPtr, qLen);
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1974",
3
+ "version": "2.0.1976",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1974",
3
+ "version": "2.0.1976",
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",