gm-skill 2.0.1514 → 2.0.1516

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 CHANGED
@@ -30,6 +30,8 @@ The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` unde
30
30
 
31
31
  **Every wasm host-import `extern "C"` block carries `#[link(wasm_import_module = "env")]`.** The host provides every possible host fn (host_kv_get/put/query, host_vec_search, host_git, host_log, host_now_ms, host_fs_*, host_env_get, host_exec_js, host_random_fill, …) under the `env` import module (`plugkit-wasm-wrapper.js` `importObject.env`). A bare `extern "C"` block links only because lenient linkers tolerate the unresolved module; the strict Linux release `rust-lld` in CI errors `undefined symbol: host_*` and Build-WASM fails. This holds in rs-plugkit AND every dep crate linked into the cdylib (rs-learn) AND any sibling that builds wasm (rs-exec, rs-search). The trap: `cargo check` and even `cargo build --release` on a non-Linux host both pass while CI fails — the linker differs by host, so the only reproduction is a Linux release link; the CI job log is admin-gated, so Build-WASM echoes `::error::` annotations to surface the lld error publicly. Add a host import anywhere and the block carries the attribute or the cascade goes dark. Full incident in rs-learn (`recall: cascade outage wasm import module link`).
32
32
 
33
+ **`plugkit-wasm-wrapper.js` is ESM; never use inline `require()` for a node builtin — import it at module scope.** The wrapper runs under both node and bun, and the supervisor's `resolveRuntime()` prefers bun. Under bun's ESM, `require` is not a global, so an inline `const x = require('crypto'|'net'|'http'|'https'|'child_process')` throws `require is not defined` — and because those calls sit in `catch(_){}` blocks, the failure is silent: it broke `_ownWrapperSha12` (status.wrapper_sha stayed null, leaving the supervisor wrapper-sha-drift recycle inert), `_wrapperShaAtBoot` and its self-drift-restart, the synthetic-session cwd-hash, and the file-index sha — all only under the bun watcher, which is why it hid for so long (node-run watchers have `require` via CJS interop). Every node builtin is imported once at the top (`import crypto from 'crypto'`, etc.); inline `require` of a builtin is forbidden. Full incident in rs-learn (`recall: wrapper require not defined under bun`).
34
+
33
35
  ## Spool dispatch ABI
34
36
 
35
37
  Agents dispatch verbs by writing to `.gm/exec-spool/in/<verb>/<N>.txt` (request body) and reading the response from `.gm/exec-spool/out/<verb>-<N>.json` (nested verbs) or `.gm/exec-spool/out/<N>.json` (root verbs). The wasm orchestrator services every possible verb; the harness never executes side effects directly.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1514",
3
+ "version": "2.0.1516",
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": {
@@ -3,9 +3,14 @@ import path from 'path';
3
3
  import os from 'os';
4
4
  import crypto from 'crypto';
5
5
  import https from 'https';
6
+ import http from 'http';
6
7
  import { watch } from 'fs';
8
+ import * as _childProcess from 'child_process';
7
9
  import { spawn as _rawSpawn, spawnSync as _rawSpawnSync } from 'child_process';
8
10
  import net from 'net';
11
+ const _netModule = net;
12
+ const _httpModule = http;
13
+ const _httpsModule = https;
9
14
  import { fileURLToPath } from 'url';
10
15
 
11
16
  // Set by the spool watcher's writeStatus closure once it is live. Lets long synchronous verbs
@@ -437,7 +442,7 @@ function readCurrentSess() {
437
442
  let resolved = found || process.env.CLAUDE_SESSION_ID || process.env.GM_SESSION_ID || '';
438
443
  if (!resolved) {
439
444
  if (!__sessCache.syntheticSess) {
440
- const cwdHash = require('crypto').createHash('sha1').update(process.cwd()).digest('hex').slice(0, 8);
445
+ const cwdHash = crypto.createHash('sha1').update(process.cwd()).digest('hex').slice(0, 8);
441
446
  __sessCache.syntheticSess = `cwd-${cwdHash}-pid${process.pid}`;
442
447
  }
443
448
  resolved = __sessCache.syntheticSess;
@@ -488,7 +493,7 @@ function autoRecordBrowserEditsFromBody(body, cwd, taskBase, verb) {
488
493
  try { st = fs.statSync(abs); } catch (_) { continue; }
489
494
  if (!st.isFile()) continue;
490
495
  let hash = '';
491
- try { hash = require('crypto').createHash('sha256').update(fs.readFileSync(abs)).digest('hex').slice(0, 12); } catch (_) {}
496
+ try { hash = crypto.createHash('sha256').update(fs.readFileSync(abs)).digest('hex').slice(0, 12); } catch (_) {}
492
497
  const idx = list.findIndex(e => e && e.file === rel);
493
498
  const entry = { file: rel, ts: Date.now(), hash, source_verb: verb, source_task: taskBase };
494
499
  if (idx === -1) { list.push(entry); added++; } else { list[idx] = entry; }
@@ -823,7 +828,7 @@ function resolveWindowsExeLocal(cmd) {
823
828
 
824
829
  function isPortReachableSync(host, port, timeoutMs) {
825
830
  const r = spawnSync(process.execPath, ['-e', `
826
- const net = require('net');
831
+ const net = _netModule;
827
832
  const s = net.connect({ port: ${port}, host: ${JSON.stringify(host)} });
828
833
  let done = false;
829
834
  s.on('connect', () => { done = true; s.destroy(); process.exit(0); });
@@ -835,7 +840,7 @@ function isPortReachableSync(host, port, timeoutMs) {
835
840
 
836
841
  function findFreePortSync() {
837
842
  const r = spawnSync(process.execPath, ['-e', `
838
- const net = require('net');
843
+ const net = _netModule;
839
844
  const srv = net.createServer();
840
845
  srv.listen(0, '127.0.0.1', () => { const p = srv.address().port; srv.close(() => { process.stdout.write(String(p)); }); });
841
846
  srv.on('error', e => { process.stderr.write(e.message); process.exit(1); });
@@ -846,7 +851,7 @@ function findFreePortSync() {
846
851
 
847
852
  function isPortAliveSync(port) {
848
853
  const r = spawnSync(process.execPath, ['-e', `
849
- const net = require('net');
854
+ const net = _netModule;
850
855
  const s = net.connect({ port: ${port}, host: '127.0.0.1' });
851
856
  s.on('connect', () => { s.destroy(); process.exit(0); });
852
857
  s.on('error', () => process.exit(1));
@@ -944,7 +949,7 @@ function findInstalledChromiumBinary() {
944
949
 
945
950
  function fetchJsonSync(url, timeoutMs) {
946
951
  const r = spawnSync(process.execPath, ['-e', `
947
- const http = require('http');
952
+ const http = _httpModule;
948
953
  const req = http.get(${JSON.stringify(url)}, (res) => {
949
954
  let buf = '';
950
955
  res.on('data', d => buf += d);
@@ -1052,7 +1057,7 @@ function gracefulCloseBrowser(entry, reason) {
1052
1057
  const info = fetchJsonSync(`http://127.0.0.1:${port}/json/version`, 600);
1053
1058
  if (info && info.webSocketDebuggerUrl) {
1054
1059
  spawnSync(process.execPath, ['-e', `
1055
- const http = require('http');
1060
+ const http = _httpModule;
1056
1061
  const req = http.request({host:'127.0.0.1',port:${port},path:'/json/close/browser',method:'GET',timeout:1500},
1057
1062
  res => { res.resume(); res.on('end', () => process.exit(0)); });
1058
1063
  req.on('error', () => process.exit(1));
@@ -2083,10 +2088,11 @@ async function runSpoolWatcher(instance, spoolDir) {
2083
2088
 
2084
2089
  const LOCK_PATH = path.join(spoolDir, '.watcher.lock');
2085
2090
  try {
2086
- const _crypto = require('crypto');
2087
2091
  const _wp = path.join(GM_TOOLS_ROOT, 'plugkit-wasm-wrapper.js');
2088
- _ownWrapperSha12 = _crypto.createHash('sha256').update(fs.readFileSync(_wp)).digest('hex').slice(0, 12);
2089
- } catch (_) {}
2092
+ _ownWrapperSha12 = crypto.createHash('sha256').update(fs.readFileSync(_wp)).digest('hex').slice(0, 12);
2093
+ } catch (e) {
2094
+ try { logEvent('plugkit', 'watcher.own-wrapper-sha-failed', { error: String(e && e.message || e), gm_tools_root: GM_TOOLS_ROOT }); } catch (_) {}
2095
+ }
2090
2096
  function lockBody() { return `${process.pid}|${Date.now()}|${_ownWrapperSha12}`; }
2091
2097
  function acquireLock() {
2092
2098
  try {
@@ -2347,7 +2353,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2347
2353
  try { own = JSON.parse(fs.readFileSync(ownPkgJsonFile, 'utf-8')).version; } catch (_) {}
2348
2354
  }
2349
2355
  if (!own) return;
2350
- const https = require('https');
2356
+ const https = _httpsModule;
2351
2357
  let _probeErrored = false;
2352
2358
  const req = https.get('https://registry.npmjs.org/gm-plugkit/latest', { timeout: 10000, headers: { 'user-agent': 'plugkit-watcher' } }, (res) => {
2353
2359
  let body = '';
@@ -2381,7 +2387,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2381
2387
  try { logEvent('plugkit', 'gm-plugkit.self-stale', { running_version: own, latest_version: latest, detected_by: 'watcher-periodic-probe' }); } catch (_) {}
2382
2388
  console.error(`[plugkit-wasm] gm-plugkit self-stale: running ${own}, latest npm ${latest} -> spawning replacement via bun x gm-plugkit@latest spool and exiting`);
2383
2389
  try {
2384
- const cp = require('child_process');
2390
+ const cp = _childProcess;
2385
2391
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2386
2392
  const child = cp.spawn(bunPath, ['x', `gm-plugkit@${latest}`, 'spool'], {
2387
2393
  cwd: process.cwd(),
@@ -2472,7 +2478,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2472
2478
  console.error(`[plugkit-wasm] version drift detected: instance=${instV} file=${fileV} — spawning replacement via bun x gm-plugkit@latest spool, waiting for its heartbeat before exiting`);
2473
2479
  let spawnOk = false;
2474
2480
  try {
2475
- const cp = require('child_process');
2481
+ const cp = _childProcess;
2476
2482
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2477
2483
  const child = cp.spawn(bunPath, ['x', 'gm-plugkit@latest', 'spool'], {
2478
2484
  cwd: process.cwd(),
@@ -2547,15 +2553,13 @@ async function runSpoolWatcher(instance, spoolDir) {
2547
2553
  const _wrapperPathInstalled = path.join(GM_TOOLS_ROOT, 'plugkit-wasm-wrapper.js');
2548
2554
  let _wrapperShaAtBoot = '';
2549
2555
  try {
2550
- const _crypto = require('crypto');
2551
- _wrapperShaAtBoot = _crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2556
+ _wrapperShaAtBoot = crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2552
2557
  } catch (_) {}
2553
2558
  let _wrapperDriftLoggedOnce = false;
2554
2559
  setInterval(() => {
2555
2560
  try {
2556
2561
  if (!_wrapperShaAtBoot) return;
2557
- const _crypto = require('crypto');
2558
- const cur = _crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2562
+ const cur = crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2559
2563
  if (cur === _wrapperShaAtBoot) return;
2560
2564
  const bootReason = process.env.PLUGKIT_BOOT_REASON || 'unknown';
2561
2565
  const unsupervised = bootReason === 'direct-no-supervisor';
@@ -2570,7 +2574,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2570
2574
  });
2571
2575
  console.error(`[plugkit-wasm] wrapper.js drift detected — spawning replacement directly from installed wrapper then exiting`);
2572
2576
  try {
2573
- const cp = require('child_process');
2577
+ const cp = _childProcess;
2574
2578
  const child = cp.spawn(process.execPath, [_wrapperPathInstalled, 'spool'], {
2575
2579
  cwd: process.cwd(),
2576
2580
  detached: true,
@@ -2582,7 +2586,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2582
2586
  } catch (e) {
2583
2587
  console.error(`[plugkit-wasm] direct node spawn failed: ${e.message}; falling back to bun x`);
2584
2588
  try {
2585
- const cp = require('child_process');
2589
+ const cp = _childProcess;
2586
2590
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2587
2591
  const child = cp.spawn(bunPath, ['x', 'gm-plugkit@latest', 'spool'], {
2588
2592
  cwd: process.cwd(),
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1514",
3
+ "version": "2.0.1516",
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.1514",
3
+ "version": "2.0.1516",
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",