gm-skill 2.0.1515 → 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.1515",
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,8 @@ 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
- try { logEvent('plugkit', 'watcher.own-wrapper-sha', { sha: _ownWrapperSha12, wrapper_path: _wp }); } catch (_) {}
2092
+ _ownWrapperSha12 = crypto.createHash('sha256').update(fs.readFileSync(_wp)).digest('hex').slice(0, 12);
2090
2093
  } catch (e) {
2091
2094
  try { logEvent('plugkit', 'watcher.own-wrapper-sha-failed', { error: String(e && e.message || e), gm_tools_root: GM_TOOLS_ROOT }); } catch (_) {}
2092
2095
  }
@@ -2350,7 +2353,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2350
2353
  try { own = JSON.parse(fs.readFileSync(ownPkgJsonFile, 'utf-8')).version; } catch (_) {}
2351
2354
  }
2352
2355
  if (!own) return;
2353
- const https = require('https');
2356
+ const https = _httpsModule;
2354
2357
  let _probeErrored = false;
2355
2358
  const req = https.get('https://registry.npmjs.org/gm-plugkit/latest', { timeout: 10000, headers: { 'user-agent': 'plugkit-watcher' } }, (res) => {
2356
2359
  let body = '';
@@ -2384,7 +2387,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2384
2387
  try { logEvent('plugkit', 'gm-plugkit.self-stale', { running_version: own, latest_version: latest, detected_by: 'watcher-periodic-probe' }); } catch (_) {}
2385
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`);
2386
2389
  try {
2387
- const cp = require('child_process');
2390
+ const cp = _childProcess;
2388
2391
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2389
2392
  const child = cp.spawn(bunPath, ['x', `gm-plugkit@${latest}`, 'spool'], {
2390
2393
  cwd: process.cwd(),
@@ -2475,7 +2478,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2475
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`);
2476
2479
  let spawnOk = false;
2477
2480
  try {
2478
- const cp = require('child_process');
2481
+ const cp = _childProcess;
2479
2482
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2480
2483
  const child = cp.spawn(bunPath, ['x', 'gm-plugkit@latest', 'spool'], {
2481
2484
  cwd: process.cwd(),
@@ -2550,15 +2553,13 @@ async function runSpoolWatcher(instance, spoolDir) {
2550
2553
  const _wrapperPathInstalled = path.join(GM_TOOLS_ROOT, 'plugkit-wasm-wrapper.js');
2551
2554
  let _wrapperShaAtBoot = '';
2552
2555
  try {
2553
- const _crypto = require('crypto');
2554
- _wrapperShaAtBoot = _crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2556
+ _wrapperShaAtBoot = crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2555
2557
  } catch (_) {}
2556
2558
  let _wrapperDriftLoggedOnce = false;
2557
2559
  setInterval(() => {
2558
2560
  try {
2559
2561
  if (!_wrapperShaAtBoot) return;
2560
- const _crypto = require('crypto');
2561
- const cur = _crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2562
+ const cur = crypto.createHash('sha256').update(fs.readFileSync(_wrapperPathInstalled)).digest('hex');
2562
2563
  if (cur === _wrapperShaAtBoot) return;
2563
2564
  const bootReason = process.env.PLUGKIT_BOOT_REASON || 'unknown';
2564
2565
  const unsupervised = bootReason === 'direct-no-supervisor';
@@ -2573,7 +2574,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2573
2574
  });
2574
2575
  console.error(`[plugkit-wasm] wrapper.js drift detected — spawning replacement directly from installed wrapper then exiting`);
2575
2576
  try {
2576
- const cp = require('child_process');
2577
+ const cp = _childProcess;
2577
2578
  const child = cp.spawn(process.execPath, [_wrapperPathInstalled, 'spool'], {
2578
2579
  cwd: process.cwd(),
2579
2580
  detached: true,
@@ -2585,7 +2586,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2585
2586
  } catch (e) {
2586
2587
  console.error(`[plugkit-wasm] direct node spawn failed: ${e.message}; falling back to bun x`);
2587
2588
  try {
2588
- const cp = require('child_process');
2589
+ const cp = _childProcess;
2589
2590
  const bunPath = process.env.GM_BUN_PATH || 'bun';
2590
2591
  const child = cp.spawn(bunPath, ['x', 'gm-plugkit@latest', 'spool'], {
2591
2592
  cwd: process.cwd(),
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1515",
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.1515",
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",