gm-skill 2.0.1531 → 2.0.1533

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
@@ -28,7 +28,7 @@ This repo IS the published `gm-skill` npm package. The repo root is the package
28
28
 
29
29
  The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` under Node/bun. No native binaries are built, downloaded, or published. The shipped `plugkit.wasm` (~149MB, embeds bge-small-en-v1.5 for offline in-wasm embeddings) is fetched at bootstrap from `plugkit-wasm` npm / `plugkit-bin` gh-releases, sha256-pinned, not bundled in `gm-skill`. Full size/embedding mechanics in rs-learn (`recall: WASM-only plugkit size mechanics`).
30
30
 
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`).
31
+ **Every wasm host-import `extern "C"` block carries `#[link(wasm_import_module = "env")]`.** Holds in rs-plugkit AND every dep crate linked into the cdylib (rs-learn) AND any sibling that builds wasm (rs-exec, rs-search) -- add a host import anywhere and the block carries the attribute or the cascade goes dark. The trap (bare block links on non-Linux hosts so `cargo check`/`build --release` pass while strict Linux `rust-lld` in CI fails `undefined symbol: host_*`; only a Linux release link reproduces) + the full host-fn `env` enumeration live in rs-learn (`recall: cascade outage wasm import module link`).
32
32
 
33
33
  **`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()` (throws silently under bun's ESM inside `catch(_){}`).** Full incident in rs-learn (`recall: wrapper require not defined under bun`).
34
34
 
@@ -120,13 +120,13 @@ Every possible skill's `allowed-tools:` frontmatter is reduced to `Skill, Read,
120
120
 
121
121
  **Push is part of COMPLETE, never optional, never asked**: every possible session that mutates tracked files ends with commit + push to origin. Asking the user "do you want me to push?" is a deviation, the push IS the validation dispatch (`verify.rs`: "The push you make IS the validation dispatch"). The chain is not COMPLETE until the remote reflects HEAD. ccsniff `--git-discipline` and a pending `deviation.complete-without-push` event flag sessions that close without pushing.
122
122
 
123
- **Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain` returns empty, and the porcelain probe must be its own Bash tool-use event before the push, a separate `Bash(...)` call, not a `&&`-chained shell command within the push event. ccsniff `--git-discipline` scans the last 20 Bash **tool-use events** (not shell commands inside those events) for an explicit porcelain probe; `add && commit && push` in one Bash call counts as one event with no porcelain witness even when the worktree is clean by construction. A push from a dirty tree orphans the unstaged delta and breaks the next session's first read. Enforced in `lib/spool-dispatch.js::checkDispatchGates(sessionId, 'git', {...})` which runs the porcelain probe via `spawnSync('git', ['status', '--porcelain'])` and refuses dirty trees; the rs-plugkit `gates.rs` COMPLETE branch enforces the same invariant for the transition-to-COMPLETE path; instruction prose (`verify.rs`, `update_docs.rs`) restates it imperatively; `residual.rs` skips the scan when dirty so the four-observation window cannot be claimed past an unwitnessed delta. ccsniff `--git-discipline` flags the deviation post-hoc, true positives now that ccsniff 1.1.8+ strips quoted commit-message bodies before regex match.
123
+ **Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain` returns empty, and the porcelain probe must be its own Bash tool-use event before the push, never a `&&`-chained shell command within the push event (`add && commit && push` in one Bash call = one event with no porcelain witness). A push from a dirty tree orphans the unstaged delta and breaks the next session's first read. Enforcement-location enumeration (spool-dispatch.js gate, gates.rs COMPLETE branch, verify.rs/update_docs.rs prose, residual.rs dirty-skip, ccsniff --git-discipline) in rs-learn (`recall: push clean worktree enforcement locations`).
124
124
 
125
125
  **memorize dispatch manages CLAUDE.md / AGENTS.md**: Do not inline-edit. Dispatch via spool: write `.gm/exec-spool/in/memorize/<N>.txt` with the fact text; the wasm orchestrator embeds and persists it. Classifier rejects changelog-shaped facts from AGENTS.md ingestion (rs-learn store still accepts them).
126
126
 
127
- **Behavioral discipline lives in plugkit's `instruction` verb**: Three-Layer Admission Filter (L1 cost, L2 bounds, L3 direction), maturity-first emit, response-not-mutation-surface, structural recognition of closure anti-shapes, code invariants (state-space minimization, hardware-reality, flat-structure, vertical-slice, async-boundary, naming-by-scale, fail-fast, binary-transport, single-focus). Dispatch `instruction` for the live prose; do not duplicate it here.
127
+ **Behavioral discipline lives in plugkit's `instruction` verb**: dispatch `instruction` for the live phase-specific prose (Three-Layer Admission Filter, maturity-first emit, closure anti-shapes, code invariants); do not duplicate it here. Full enumeration in rs-learn (`recall: instruction-verb behavioral discipline invariants`).
128
128
 
129
- **The agent IS the LLM rs-learn calls; every judgment rs-learn needs is the agent deciding on the spot**: rs-learn never reaches out to a model for a quality score, a relevance call, a prune decision, a route outcome, or a loss signal. plugkit IS the harness and the agent IS the model it dispatched, so each of those is a decision the agent makes inline, from its knowledge of the current situation, and reports back through the spool. The MicroLoRA adapter trains from a trajectory-quality the agent self-reports (`learn{feedback, embedding, payload:{quality}}`, a rank-2 learned scoring head that reads a bge-small embedding and emits a per-target logit `B - (A - embedding)`, sona-style -- it scores targets from embeddings, it does not reshape the vector; consuming its score in recall re-ranking is the open integration. Distinct from the FastGRNN model-selection router, which takes `learn{record_outcome, target:<model id>, quality}`); bad-memory pruning is the agent judging a recall hit stale and dispatching `memorize-prune{key}`; the deep core takes the agent's `record_loss`; the attention takes `nudge_relation`. None of these wait on a signal the host must expose, because the agent already holds it. Encourage heavy `recall` and `learn` use so the on-the-spot judgments are grounded in prior context, not guessed -- every mutable resolution is already a memorization run, and the same recall-first reflex should inform every quality/prune/optimization call. The instruction prose names where each self-report fires (VERIFY closes the training loop); the principle here is the load-bearing one: there is no separate judge model, the agent is it, and it decides now.
129
+ **The agent IS the LLM rs-learn calls; every judgment rs-learn needs is the agent deciding on the spot**: rs-learn never reaches out to a separate judge model for a quality score, relevance call, prune decision, route outcome, or loss signal -- plugkit IS the harness and the agent IS the model it dispatched, so each is a decision the agent makes inline and reports through the spool. Encourage heavy `recall`+`learn` so judgments are grounded, not guessed. Per-core internals (MicroLoRA self-report logit, FastGRNN router, deep-core record_loss, attention nudge_relation, memorize-prune) in rs-learn (`recall: rs-learn self-report core internals`).
130
130
 
131
131
  **host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error); long subprocesses block the watcher; no async/background exec under wasm. Mechanism detail in rs-learn (`recall: host_exec_js synchronous`).
132
132
 
@@ -148,13 +148,7 @@ Push to any rs-* sibling triggers `cascade.yml` -> rs-plugkit `release.yml` -> s
148
148
 
149
149
  Three npm packages publish from this repo: `gm-skill` (the skill harness), `gm-plugkit` (bootstrap + watcher), `plugkit-wasm` (wasm binary). publish.yml + the rs-plugkit cascade ships all three on every version-bump commit. The legacy 15 downstream repos are archived on GitHub, no further releases, no orphan-commit publish step.
150
150
 
151
- **Repos involved (push to every possible one triggers cascade):**
152
- - `AnEntrypoint/rs-exec`, exec runner, browser sessions, idle cleanup, session task isolation
153
- - `AnEntrypoint/rs-codeinsight`, code search backend, symbol indexing
154
- - `AnEntrypoint/rs-search`, file search backend, embedding and sweep
155
- - `AnEntrypoint/rs-plugkit`, CLI entry point, spool watcher dispatcher; version source of truth in `Cargo.toml`
156
- - `AnEntrypoint/rs-learn`, memory backend, recall/ingest via HTTP RPC
157
- - `AnEntrypoint/gm`, `gm.json` holds `plugkitVersion`; CI publishes the single `gm-skill` npm package
151
+ **Repos involved (push to any triggers cascade):** `AnEntrypoint/{rs-exec, rs-codeinsight, rs-search, rs-plugkit, rs-learn, gm}` — rs-plugkit Cargo.toml is the version source-of-truth, gm.json holds plugkitVersion. Per-repo roles in rs-learn (`recall: cascade repos involved roles`).
158
152
 
159
153
  **To update every possible thing**: push to the relevant repo. No manual version bumps, no local cargo builds. Never run `cargo update` or `cargo build` locally, push and let CI build.
160
154
 
@@ -164,7 +158,7 @@ Three npm packages publish from this repo: `gm-skill` (the skill harness), `gm-p
164
158
 
165
159
  Orchestration state is tracked via marker files in `.gm/` instead of hook events. `SpoolDispatcher` reads these markers via `checkDispatchGates(sessionId, operation)` and gates tool use, writes, and git operations:
166
160
 
167
- **Marker files**: `.gm/prd.yml` (existence triggers needs-gm gate), `.gm/mutables.yml` (every possible unresolved entry blocks Write/Edit/git), `.gm/needs-gm` (written by bootstrap, read by dispatcher), `.gm/gm-fired-<sessionId>` (written by gm skill/agent, cleared at turn start), `.gm/residual-check-fired` (ensures one-shot residual-scan per stop window).
161
+ **Marker files**: `.gm/{prd.yml, mutables.yml, needs-gm, gm-fired-<sessionId>, residual-check-fired}` gate Write/Edit/git via `checkDispatchGates`. Per-marker semantics in rs-learn (`recall: spool dispatch gates marker files`).
168
162
 
169
163
  **Gate enforcement**: the CLI layer calls `checkDispatchGates()` before tool execution; marker-driven dispatch replaces the hook event pump entirely. Detail in rs-learn (`recall: gate enforcement layer`).
170
164
 
@@ -178,21 +172,15 @@ Orchestration state is tracked via marker files in `.gm/` instead of hook events
178
172
 
179
173
  **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.
180
174
 
181
- **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.
175
+ **Session lifecycle**: background tasks + browser sessions persist across turn-stops; cleanup fires only on real-exit reasons; residual-scan fires when PRD empty AND no open browser sessions AND no running tasks. Detail in rs-learn (`recall: session lifecycle killSessionTasks residual-scan`).
182
176
 
183
177
  ## Spool observability surface
184
178
 
185
- Every possible agent has a one-shot system-state probe: dispatch `plugkit health` via the file-spool (write `.gm/exec-spool/in/health/<N>.txt` empty body, read `out/<N>.json`). Returns plugkit version + pin-match, watcher liveness, runner state, rs-learn status, cache dirs, inbox/outbox counts, recent hook fires, recent errors. Use before assuming every possible component is broken.
186
-
187
- Three persistent diagnostic files at `.gm/exec-spool/` root are updated by the running stack (not the agent): `.status.json` (watcher state each tick; stale mtime = dead watcher), `.last-session-start.json` (most recent session-start spawn result), `.bootstrap-error.json` (pin-mismatch / fetch-fail surface, absent = healthy). Reading these directly via Read is allowed (runtime data exception); spool dispatch isn't needed to inspect them.
179
+ One-shot system-state probe: dispatch `plugkit health` via the file-spool before assuming any component is broken. Three runtime diagnostic files at `.gm/exec-spool/` root (`.status.json`, `.last-session-start.json`, `.bootstrap-error.json`) are readable directly via Read (runtime-data exception). Return-field enumeration + per-file semantics in rs-learn (`recall: plugkit health verb fields`).
188
180
 
189
181
  ## Site Build & Documentation
190
182
 
191
- **Navigation**: `site/content/globals/navigation.yaml` uses grouped entry format, each item is either `{label, href}` (single link) or `{label, group: [{label, href}, ...]}` (dropdown menu). Dropdowns render via `<details>/<summary>` through the flatspace `C.Topbar` primitive invoked in `site/theme.mjs`; no JS required. In-page topbars in docs/paper*.html et al. render directly on file open and must be kept in sync with the same markup.
192
-
193
- **Landing page renderer**: the deployed `/` route on https://anentrypoint.github.io/gm/ is rendered by `site/theme.mjs` from `site/content/pages/home.yaml` via flatspace. `site/index.html` + `site/main.js` build `docs/bundle.js` for non-flatspace standalone preview only. Landing edits go through `site/theme.mjs` (Hero) and `site/content/pages/home.yaml` (content), never `site/index.html`.
194
-
195
- **Mermaid render, generated docs/styles.css, and the docs/made-with.html static showcase** detail lives in rs-learn (`recall: gm site build details`).
183
+ **Site build is single-surface detail in rs-learn** (`recall: gm site build details`): navigation.yaml grouped-entry format + flatspace `C.Topbar` dropdowns, the `site/theme.mjs`+`home.yaml` landing renderer (never `site/index.html`), in-page topbar sync, Mermaid render, generated `docs/styles.css`, and the `docs/made-with.html` showcase.
196
184
 
197
185
 
198
186
  @.gm/next-step.md
@@ -282,6 +282,30 @@ function checkWatcherHealth() {
282
282
  severity: 'info',
283
283
  });
284
284
  killChild('supervisor-killed-wrapper-sha-drift');
285
+ return;
286
+ }
287
+ // The watcher reads the wasm's embedded instance_version at load and compares it to the
288
+ // plugkit.version text file (file_version), exposing version_drifted when they disagree.
289
+ // This catches a bumped version text sitting next to a stale wasm build (text claims 635
290
+ // while the binary embeds 634), which ensureReady's text-only drift check never re-downloads.
291
+ // Evict the stale cached wasm so the next bootstrap fails isReady() and redownloads, then recycle.
292
+ if (status.version_drifted === true) {
293
+ logEvent('supervisor.version-drift', {
294
+ watcher_pid: currentChildPid,
295
+ instance_version: status.instance_version || null,
296
+ file_version: status.file_version || null,
297
+ severity: 'critical',
298
+ });
299
+ try {
300
+ const home = process.env.USERPROFILE || process.env.HOME || os.homedir();
301
+ const gmTools = fs.existsSync(path.join(home, '.gm-tools'))
302
+ ? path.join(home, '.gm-tools')
303
+ : path.join(home, '.claude', 'gm-tools');
304
+ for (const f of ['plugkit.wasm', 'plugkit.version', 'plugkit.wasm.sha256']) {
305
+ try { fs.unlinkSync(path.join(gmTools, f)); } catch (_) {}
306
+ }
307
+ } catch (_) {}
308
+ killChild('supervisor-killed-version-drift');
285
309
  }
286
310
  }
287
311
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1531",
3
+ "version": "2.0.1533",
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": {
@@ -298,6 +298,35 @@ function checkWatcherHealth() {
298
298
  if (process.platform === 'win32') {
299
299
  try { spawnSync('taskkill', ['/F', '/T', '/PID', String(currentChildPid)], { stdio: 'ignore', windowsHide: true, timeout: 3000 }); } catch (_) {}
300
300
  }
301
+ return;
302
+ }
303
+ // The watcher reads the wasm's embedded instance_version at load and compares it to the
304
+ // plugkit.version text file (file_version), exposing version_drifted when they disagree.
305
+ // This catches the case where the version text was bumped (e.g. ensureReady's remote-latest
306
+ // override) but the cached plugkit.wasm bytes are a different build -- the text claims 635
307
+ // while the binary embeds 634, so ensureReady's text-only drift check never re-downloads.
308
+ // On that drift, evict the stale cached wasm so the next bootstrap fails isReady() and
309
+ // redownloads the correct build, then recycle the child to load it.
310
+ if (status.version_drifted === true) {
311
+ logEvent('supervisor.version-drift', {
312
+ watcher_pid: currentChildPid,
313
+ instance_version: status.instance_version || null,
314
+ file_version: status.file_version || null,
315
+ severity: 'critical',
316
+ });
317
+ try {
318
+ const home = process.env.USERPROFILE || process.env.HOME || require('os').homedir();
319
+ const gmTools = fs.existsSync(path.join(home, '.gm-tools'))
320
+ ? path.join(home, '.gm-tools')
321
+ : path.join(home, '.claude', 'gm-tools');
322
+ for (const f of ['plugkit.wasm', 'plugkit.version', 'plugkit.wasm.sha256']) {
323
+ try { fs.unlinkSync(path.join(gmTools, f)); } catch (_) {}
324
+ }
325
+ } catch (_) {}
326
+ try { process.kill(currentChildPid, 'SIGTERM'); } catch (_) {}
327
+ if (process.platform === 'win32') {
328
+ try { spawnSync('taskkill', ['/F', '/T', '/PID', String(currentChildPid)], { stdio: 'ignore', windowsHide: true, timeout: 3000 }); } catch (_) {}
329
+ }
301
330
  }
302
331
  }
303
332
 
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1531",
3
+ "version": "2.0.1533",
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.1531",
3
+ "version": "2.0.1533",
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",