gm-skill 2.0.2467 → 2.0.2468

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
@@ -50,7 +50,7 @@ Dispatch = Write `.gm/exec-spool/in/<verb>/<N>.txt`, Read `.gm/exec-spool/out/<v
50
50
  - **Wasm-direct verbs**: fs/kv/exec/fetch/env, recall, codesearch, memorize(+prune), health, filter, full git verb family. Enumeration in the recall store (`recall: wasm-direct plugkit verbs full list`).
51
51
  - **Host-native verb**: `background-convert` (`{verb, task}`) detaches an already-in-flight dispatch so the daemon worker stops waiting on it -- agent-initiated only, never routed to gm.wasm. Detail: `.gm/daemon-config-reference.md`.
52
52
  - **memorize-prune**: prune bad/superseded memories; two-mode spec (key-remove vs query-review) in the recall store (`recall: memorize-prune verb two-mode spec`).
53
- - **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface, `git_push` the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Per-verb shapes + host_git `.exe` resolution in the recall store (`recall: git verbs rs-plugkit spool surface`). `git_finalize` also runs `ci-status` inline right after push and auto-writes `.gm/exec-spool/.ci-validated` on a green result -- no separate poll-then-marker dispatch needed. The `ci-validated-fresh` COMPLETE gate compares that marker's `head_sha` against current HEAD and names `ci-status` as its `next_dispatch` on denial.
53
+ - **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface, `git_push` the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Per-verb shapes + host_git `.exe` resolution in the recall store (`recall: git verbs rs-plugkit spool surface`). `git_finalize` also runs `ci-status` inline right after push and auto-writes `.gm/exec-spool/.ci-validated` on a green result -- no separate poll-then-marker dispatch needed. The `ci-validated-fresh` COMPLETE gate compares that marker's `head_sha` against current HEAD and names `ci-status` as its `next_dispatch` on denial. An async git host (one that answers host_git with `{pending,token}` and parks the terminal result in kv ns `outbox`) is served by the `git_poll {token}` verb: `git_status`/`git_add`/`git_commit`/`git_log`/`git_diff` return pending envelopes there, and the caller repeats `git_poll` until a non-pending envelope comes back -- that envelope is the verb's terminal result, plan-resumed across dispatches for compound verbs.
54
54
  - **filter**: pure stdout -> compact-stdout transform, in-wasm. Spec + usage (pipe raw command output through it before context) in the recall store (`recall: filter verb rs-plugkit spool spec`).
55
55
 
56
56
  ## Documentation Policy
@@ -792,6 +792,95 @@ function getBinaryPath() {
792
792
  return getWasmPath();
793
793
  }
794
794
 
795
+ function agentplugRunnerAssetName() {
796
+ const plat = process.platform;
797
+ const arch = process.arch;
798
+ if (plat === 'win32') {
799
+ if (arch === 'x64') return 'agentplug-runner-windows-x64.exe';
800
+ if (arch === 'arm64') return 'agentplug-runner-windows-arm64.exe';
801
+ return null;
802
+ }
803
+ if (plat === 'darwin') {
804
+ if (arch === 'x64') return 'agentplug-runner-macos-x64';
805
+ if (arch === 'arm64') return 'agentplug-runner-macos-arm64';
806
+ return null;
807
+ }
808
+ if (plat === 'linux') {
809
+ if (arch === 'x64') return 'agentplug-runner-linux-x64';
810
+ if (arch === 'arm64') return 'agentplug-runner-linux-arm64';
811
+ return null;
812
+ }
813
+ return null;
814
+ }
815
+
816
+ function compareDottedSemverAscending(a, b) {
817
+ const pa = a.replace(/^v/, '').split('.').map(Number);
818
+ const pb = b.replace(/^v/, '').split('.').map(Number);
819
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
820
+ const d = (pa[i] || 0) - (pb[i] || 0);
821
+ if (d !== 0) return d;
822
+ }
823
+ return 0;
824
+ }
825
+
826
+ function latestAgentplugRunnerTagViaGitLsRemote() {
827
+ const { execFileSync } = require('child_process');
828
+ const out = execFileSync('git', ['ls-remote', '--tags', '--refs', 'https://github.com/AnEntrypoint/agentplug-bin.git'], {
829
+ encoding: 'utf8',
830
+ stdio: ['ignore', 'pipe', 'ignore'],
831
+ });
832
+ const tags = out.split('\n')
833
+ .map(line => line.match(/refs\/tags\/(.+)$/))
834
+ .filter(Boolean)
835
+ .map(m => m[1]);
836
+ if (tags.length === 0) return null;
837
+ tags.sort(compareDottedSemverAscending);
838
+ return tags[tags.length - 1];
839
+ }
840
+
841
+ // The sole loader has to exist before startSpoolDaemon can do anything --
842
+ // a project that never ran `gm-skill install` (or whose install predates
843
+ // agentplug-runner) hit a hard "not installed" failure here even though
844
+ // the sha256-verified download this needs is the same one bin/install.js
845
+ // already performs. Attempting it inline means a bare `spool` boot recovers
846
+ // on its own instead of requiring a separate manual install step first.
847
+ async function ensureAgentplugRunnerInstalled(destPath) {
848
+ const assetName = agentplugRunnerAssetName();
849
+ if (!assetName) return false;
850
+ const destDir = gmToolsDir();
851
+ try {
852
+ let tag;
853
+ try {
854
+ const releaseInfo = JSON.parse((await httpGetBuffer('https://api.github.com/repos/AnEntrypoint/agentplug-bin/releases/latest', 15000)).toString('utf8'));
855
+ tag = releaseInfo && releaseInfo.tag_name;
856
+ } catch (apiErr) {
857
+ try {
858
+ tag = latestAgentplugRunnerTagViaGitLsRemote();
859
+ } catch (_) {
860
+ return false;
861
+ }
862
+ }
863
+ if (!tag) return false;
864
+ const base = `https://github.com/AnEntrypoint/agentplug-bin/releases/download/${tag}`;
865
+ const [binBuf, shaBuf] = await Promise.all([
866
+ httpGetBuffer(`${base}/${assetName}`, 60000),
867
+ httpGetBuffer(`${base}/${assetName}.sha256`, 15000),
868
+ ]);
869
+ const expectedSha = shaBuf.toString('utf8').trim().split(/\s+/)[0];
870
+ const actualSha = sha256Hex(binBuf);
871
+ if (!expectedSha || actualSha.toLowerCase() !== expectedSha.toLowerCase()) return false;
872
+ fs.mkdirSync(destDir, { recursive: true });
873
+ const tmp = destPath + '.tmp' + process.pid;
874
+ fs.writeFileSync(tmp, binBuf);
875
+ if (process.platform !== 'win32') { try { fs.chmodSync(tmp, 0o755); } catch (_) {} }
876
+ fs.renameSync(tmp, destPath);
877
+ fs.writeFileSync(path.join(destDir, 'agentplug-runner.version'), tag);
878
+ return true;
879
+ } catch (_) {
880
+ return false;
881
+ }
882
+ }
883
+
795
884
  function startSpoolDaemon() {
796
885
  try {
797
886
  const runnerName = process.platform === 'win32' ? 'agentplug-runner.exe' : 'agentplug-runner';
@@ -805,6 +894,7 @@ function startSpoolDaemon() {
805
894
  `which downloads the sha256-verified native runner from AnEntrypoint/agentplug-bin for this platform ` +
806
895
  `(${process.platform}/${process.arch}). If no binary is published for this platform yet, there is no ` +
807
896
  `loader available -- file an issue at https://github.com/AnEntrypoint/agentplug-bin so a binary is built for it.`,
897
+ needsRunnerInstall: true,
808
898
  };
809
899
  }
810
900
  const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
@@ -846,6 +936,7 @@ module.exports = {
846
936
  getWasmPath,
847
937
  getBinaryPath,
848
938
  startSpoolDaemon,
939
+ ensureAgentplugRunnerInstalled,
849
940
  isReady,
850
941
  cacheRoot,
851
942
  obsEvent,
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, isReady, getWasmPath, readPinnedGmPlugkitVersion, spawnPinnedBoot, resolveProjectRoot } = require('./bootstrap');
8
+ const { ensureReady, startSpoolDaemon, ensureAgentplugRunnerInstalled, gmToolsDir, readVersionFile, ensureGmPlugkitVersionFresh, ensureSkillMdFresh, isReady, getWasmPath, readPinnedGmPlugkitVersion, spawnPinnedBoot, resolveProjectRoot } = require('./bootstrap');
9
9
  const { pidAliveSync, waitForPidDeath } = require('./gm-process');
10
10
 
11
11
  function getWasmPathSafe() {
@@ -24,7 +24,7 @@ function spawnBackgroundFreshnessCheck(reason) {
24
24
  } catch (_) {}
25
25
  }
26
26
 
27
- function spawnDaemonOrExit(version, binaryPath, message) {
27
+ async function spawnDaemonOrExit(version, binaryPath, message) {
28
28
  let daemon;
29
29
  try {
30
30
  daemon = startSpoolDaemon();
@@ -33,6 +33,21 @@ function spawnDaemonOrExit(version, binaryPath, message) {
33
33
  console.error('Daemon start failed:', err.message);
34
34
  process.exit(1);
35
35
  }
36
+ if (daemon && !daemon.ok && daemon.needsRunnerInstall) {
37
+ const runnerName = process.platform === 'win32' ? 'agentplug-runner.exe' : 'agentplug-runner';
38
+ const runnerPath = path.join(gmToolsDir(), runnerName);
39
+ console.error('agentplug-runner not found -- attempting sha256-verified download from AnEntrypoint/agentplug-bin before failing...');
40
+ const installed = await ensureAgentplugRunnerInstalled(runnerPath);
41
+ if (installed) {
42
+ try {
43
+ daemon = startSpoolDaemon();
44
+ } catch (err) {
45
+ writeCliError('start-daemon', err);
46
+ console.error('Daemon start failed:', err.message);
47
+ process.exit(1);
48
+ }
49
+ }
50
+ }
36
51
  if (!daemon || !daemon.ok) {
37
52
  const errMsg = (daemon && daemon.error) || 'startSpoolDaemon returned non-ok';
38
53
  writeCliError('start-daemon', new Error(errMsg));
@@ -207,7 +222,7 @@ function tryDelegateToRunner(args) {
207
222
  try { installedVersion = readVersionFile(); } catch (_) { installedVersion = null; }
208
223
  writeCliStatus({ phase: 'bootstrapped', version: installedVersion, binary: getWasmPathSafe() });
209
224
  spawnBackgroundFreshnessCheck(versionDrifted ? 'version-drift-respawn' : 'fast-path-spawn');
210
- spawnDaemonOrExit(
225
+ await spawnDaemonOrExit(
211
226
  installedVersion,
212
227
  getWasmPathSafe(),
213
228
  'plugkit daemon spawned from existing local install, not yet confirmed serving -- check .gm/exec-spool/.status.json for heartbeat freshness; remote freshness check running in background'
@@ -231,7 +246,7 @@ function tryDelegateToRunner(args) {
231
246
  }
232
247
 
233
248
  writeCliStatus({ phase: 'bootstrapped', version: bootstrapResult.version, binary: bootstrapResult.binaryPath });
234
- spawnDaemonOrExit(
249
+ await spawnDaemonOrExit(
235
250
  bootstrapResult.version,
236
251
  bootstrapResult.binaryPath,
237
252
  'plugkit daemon spawned, not yet confirmed serving -- check .gm/exec-spool/.status.json for heartbeat freshness'
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.2467",
3
+ "version": "2.0.2468",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.2467",
3
+ "version": "2.0.2468",
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.2467",
3
+ "version": "2.0.2468",
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",