gm-skill 2.0.1440 → 2.0.1442

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
@@ -158,6 +158,8 @@ Orchestration state is tracked via marker files in `.gm/` instead of hook events
158
158
 
159
159
  **Dead-watcher recovery prefers `bun x gm-plugkit@latest spool`, not direct-node boot**: when the watcher is dead and you reboot, use `bun x gm-plugkit@latest spool` (the npm-fetch path) rather than `node ~/.gm-tools/plugkit-wasm-wrapper.js spool`. The direct-node form runs the installed wrapper as-is and skips `ensureWrapperInstalled`, so a just-published wrapper fix stays undeployed, the running watcher carries stale wrapper code even though npm has the fix. The `bun x` path sha-checks and refreshes the installed wrapper before booting. After any wrapper-level fix is published, verify deployment by grepping the installed `~/.gm-tools/plugkit-wasm-wrapper.js` for the new code, not just the npm version, npm-published is not the same as installed-and-running.
160
160
 
161
+ **The first verb after any multi-minute wait is `instruction`, to reset the long-gap clock**: a version transition (kill + `bun x gm-plugkit@latest spool` downloads a ~149MB wasm, minutes of idle), a long CI watch, or any wait that exceeds the 300s `long_gap_threshold_ms` leaves the gap clock run out, so the very next non-`instruction` verb (`memorize-fire`, `learn`, `browser`, …) trips `deviation.long-gap-no-instruction` from `rs-plugkit/gates`. The gate is correct, the deviation is yours, and it is fully predictable: after waiting out a version transition or any multi-minute pause, dispatch `instruction` FIRST (it resets `last_instruction_ts`), then proceed. Recovering verb-by-verb after each gate denial works but emits a burst of deviations; pre-empting with one `instruction` dispatch emits zero.
162
+
161
163
  **A stop-hook firing on a terminal chain does not authorize re-polling**: when a stop-hook or unsatisfiable condition fires while the chain is already at `phase=COMPLETE` AND `prd_pending_count=0`, re-dispatching `instruction` or `phase-status` to "re-confirm" terminality is itself a deviation, it emits `deviation.complete-chain-poll` (`instructions/mod.rs`) and marks the agent as polling a closed chain. COMPLETE already authorizes the prose-only turn; the hook cannot be satisfied by more poll dispatches over elapsed work, and re-running already-committed work to manufacture skill-driven activity is the fabrication `Nothing Fake` forbids. Two admissible responses only: (a) a prose-only turn (the COMPLETE pronouncement is in hand), or (b) genuinely new planned work opened with a FRESH `{"prompt":...}` body, which resets phase to PLAN and is driven through the skill from inception. Repeatedly answering the same already-acknowledged hook is a loop; state the terminal facts once and stop, or open new work.
162
164
 
163
165
  **Session lifecycle**: Session-end kills background tasks via `killSessionTasks` RPC on real-exit reasons (clear/logout/prompt_input_exit). Every possible browser session and background task persists across turn-stops, cleanup happens exclusively on real-exit reasons. Residual-scan fires when PRD is empty/missing AND no open browser sessions AND no running tasks; agent either expands PRD with in-spirit residuals or explicitly states none.
@@ -1 +1 @@
1
- 0.1.581
1
+ 0.1.582
@@ -1 +1 @@
1
- 4046ba34646fa5639610b5ab9a6a9276531bea8b90a968d901c3f0b8cb417552 plugkit.wasm
1
+ e2e1c3833f428925bd7c52f79dad706c9fe23ced05871f75532b273d00370a75 plugkit.wasm
@@ -879,13 +879,32 @@ function probeUnsupervisedWatcher(spoolDir) {
879
879
  } catch (_) {}
880
880
  }
881
881
 
882
+ function resolveNodeRuntime() {
883
+ const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
884
+ const candidates = [];
885
+ if (isNodeExe(process.env.GM_NODE_PATH)) candidates.push(process.env.GM_NODE_PATH);
886
+ if (isNodeExe(process.execPath)) candidates.push(process.execPath);
887
+ try {
888
+ const which = process.platform === 'win32' ? 'where' : 'which';
889
+ const out = require('child_process').spawnSync(which, ['node'], { encoding: 'utf8', windowsHide: true });
890
+ if (out && out.stdout) {
891
+ const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
892
+ if (first) candidates.push(first);
893
+ }
894
+ } catch (_) {}
895
+ for (const c of candidates) {
896
+ try { const r = require('child_process').spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
897
+ }
898
+ return process.execPath;
899
+ }
900
+
882
901
  function startSpoolDaemon() {
883
902
  try {
884
903
  const wrapper = path.join(gmToolsDir(), 'plugkit-wasm-wrapper.js');
885
904
  if (!fs.existsSync(wrapper)) {
886
905
  return { ok: false, error: `wrapper not at ${wrapper} — ensureReady() must run first` };
887
906
  }
888
- const runtime = process.execPath;
907
+ const runtime = resolveNodeRuntime();
889
908
  const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
890
909
  const spoolDir = path.join(projectDir, '.gm', 'exec-spool');
891
910
  fs.mkdirSync(spoolDir, { recursive: true });
@@ -919,7 +938,7 @@ function startSpoolDaemon() {
919
938
 
920
939
  const logFd = fs.openSync(logPath, 'a');
921
940
  try { fs.writeSync(logFd, `\n--- supervisor spawn ${new Date().toISOString()} parent=${process.pid} ---\n`); } catch (_) {}
922
- const child = require('child_process').spawn(process.execPath, [supervisor], {
941
+ const child = require('child_process').spawn(runtime, [supervisor], {
923
942
  detached: true,
924
943
  stdio: ['ignore', logFd, logFd],
925
944
  windowsHide: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1440",
3
+ "version": "2.0.1442",
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": {
@@ -94,15 +94,27 @@ function spawnWatcher(bootReason) {
94
94
  process.exit(3);
95
95
  }
96
96
 
97
- let runtime = process.env.PLUGKIT_RUNTIME || 'bun';
98
- let cmd = runtime;
97
+ const isNodeExe = (p) => /(^|[\\/])node(\.exe)?$/i.test(String(p || ''));
98
+ const resolveNode = () => {
99
+ const candidates = [];
100
+ if (isNodeExe(process.env.PLUGKIT_RUNTIME)) candidates.push(process.env.PLUGKIT_RUNTIME);
101
+ if (isNodeExe(process.execPath)) candidates.push(process.execPath);
102
+ if (process.env.GM_NODE_PATH) candidates.push(process.env.GM_NODE_PATH);
103
+ try {
104
+ const which = process.platform === 'win32' ? 'where' : 'which';
105
+ const out = spawnSync(which, ['node'], { encoding: 'utf8', windowsHide: true });
106
+ if (out && out.stdout) {
107
+ const first = out.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)[0];
108
+ if (first) candidates.push(first);
109
+ }
110
+ } catch (_) {}
111
+ for (const c of candidates) {
112
+ try { const r = spawnSync(c, ['--version'], { stdio: 'ignore', windowsHide: true }); if (r && r.status === 0) return c; } catch (_) {}
113
+ }
114
+ return process.execPath;
115
+ };
116
+ let cmd = resolveNode();
99
117
  let args = [wrapper, 'spool'];
100
- try {
101
- spawnSync(runtime, ['--version'], { stdio: 'ignore', windowsHide: true });
102
- } catch (_) {
103
- cmd = process.execPath;
104
- args = [wrapper, 'spool'];
105
- }
106
118
 
107
119
  let logFd = null;
108
120
  try { logFd = fs.openSync(LOG_PATH, 'a'); } catch (_) {}
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1440",
3
+ "version": "2.0.1442",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -17,5 +17,5 @@
17
17
  "publishConfig": {
18
18
  "access": "public"
19
19
  },
20
- "plugkitVersion": "0.1.581"
20
+ "plugkitVersion": "0.1.582"
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1440",
3
+ "version": "2.0.1442",
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",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gm-skill
3
3
  description: Plugkit-served instruction stream. Three-layer admission (cost, bounds, direction) over every possible mutation. Closure on first emit; partial = non-monotonic.
4
- allowed-tools: Skill, Read, Write, Bash(node *), Bash(bun *)
4
+ allowed-tools: Skill, Read, Write, Bash(bun *), Bash(npx *)
5
5
  ---
6
6
 
7
7
  # gm
@@ -10,6 +10,8 @@ allowed-tools: Skill, Read, Write, Bash(node *), Bash(bun *)
10
10
 
11
11
  **Done is what plugkit says is done, never your claim.** The COMPLETE gate is the single arbiter. If the chain is not at COMPLETE, there is a next transition to seek; idle mid-chain is a deviation.
12
12
 
13
+ **Standing approval — finish everything, every session, at maximum granularity.** Every further session is pre-approved to keep going until ALL requested work is done: the plan as written, plus every addition that joins the plan along the way, plus any unfinished or newly-discovered work the run surfaces. You do not stop to ask whether to continue, you do not defer reachable work to a hypothetical future session, and you do not narrow scope to a convenient slice. Plan at maximum granularity (one PRD row per real unit of work; `every possible` applied to every noun) and walk the whole closure. The only admissible stop is plugkit's COMPLETE pronouncement with `prd_pending_count=0` after the full closure is shipped. `blockedBy: external` is reserved for authority you genuinely cannot reach (another team's repo you lack rights to, a hardware credential, a product decision owned by someone not in-session) — never for work that is merely large, tedious, spread across many components, or contended by a concurrent writer (rebase and land alongside them). Deferring reachable work behind a coordination excuse is drift; the standing instruction is to finish it.
14
+
13
15
  **Every possible action begins and ends with `instruction`.** When in doubt, dispatch instruction. When denied, dispatch instruction. When the next move is unclear, dispatch instruction. There is no other recovery primitive and there is no situation in which improvising beats re-reading the prose.
14
16
 
15
17
  **You are the state machine.** Plugkit is the durable memory and gate-checker you write into; you are the actor that walks PLAN → EXECUTE → EMIT → VERIFY → COMPLETE. Every possible phase transition, every possible PRD resolution, every possible mutable witness, every possible residual scan is a verb YOU dispatch by writing `.gm/exec-spool/in/<verb>/<N>.txt`. Plugkit does not advance. Plugkit does not validate in the background. Plugkit does not "process" while you wait. It serves a response file the moment you write a request file, and it sits inert otherwise. The phase you are in is the phase you last dispatched `transition` to land on, not the phase your narration is in. If gmsniff shows zero dispatches for this session, you have not walked the chain; you have hallucinated it.