gm-skill 2.0.1335 → 2.0.1337

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.
@@ -1 +1 @@
1
- 0.1.500
1
+ 0.1.501
@@ -1 +1 @@
1
- 6661c56bb5f57b4fe9545dcb2ca5cc6ffa6e57cbac2ef3f77f03133fd55b69ae plugkit.wasm
1
+ 242f4e3fa2b916e509aefb360e49558d7684bdbb34f3ae55e1febdaa04350a6b plugkit.wasm
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1335",
3
+ "version": "2.0.1337",
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": {
@@ -2518,9 +2518,60 @@ async function runSpoolWatcher(instance, spoolDir) {
2518
2518
 
2519
2519
  const UPDATE_AVAILABLE_PATH = path.join(spoolDir, '.update-available.json');
2520
2520
  const UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000;
2521
+ const UPDATE_CHECK_SHARED_CACHE = path.join(GM_TOOLS_ROOT, '.update-check-cache.json');
2522
+ const UPDATE_CHECK_CACHE_TTL_MS = 4 * 60 * 1000;
2521
2523
  let _lastKnownDrift = null;
2524
+ function readSharedUpdateCache() {
2525
+ try {
2526
+ const content = fs.readFileSync(UPDATE_CHECK_SHARED_CACHE, 'utf-8');
2527
+ const parsed = JSON.parse(content);
2528
+ if (parsed && parsed.ts && parsed.latest && (Date.now() - parsed.ts) < UPDATE_CHECK_CACHE_TTL_MS) {
2529
+ return parsed;
2530
+ }
2531
+ } catch (_) {}
2532
+ return null;
2533
+ }
2534
+ function writeSharedUpdateCache(latest, status) {
2535
+ try {
2536
+ fs.mkdirSync(path.dirname(UPDATE_CHECK_SHARED_CACHE), { recursive: true });
2537
+ const tmp = UPDATE_CHECK_SHARED_CACHE + '.tmp.' + process.pid;
2538
+ fs.writeFileSync(tmp, JSON.stringify({ ts: Date.now(), latest, status, by_pid: process.pid }));
2539
+ fs.renameSync(tmp, UPDATE_CHECK_SHARED_CACHE);
2540
+ } catch (_) {}
2541
+ }
2542
+ function applyUpdateCheckResult(installed, latest, statusCode) {
2543
+ if (statusCode !== 200) {
2544
+ logEvent('plugkit', 'update.check.error', { installed, status: statusCode });
2545
+ return;
2546
+ }
2547
+ if (!latest) return;
2548
+ if (latest === installed) {
2549
+ try { fs.unlinkSync(UPDATE_AVAILABLE_PATH); } catch (_) {}
2550
+ if (_lastKnownDrift) {
2551
+ logEvent('plugkit', 'update.cleared', { installed, was: _lastKnownDrift });
2552
+ _lastKnownDrift = null;
2553
+ }
2554
+ return;
2555
+ }
2556
+ const isDrift = latest !== installed;
2557
+ if (isDrift && _lastKnownDrift !== latest) {
2558
+ try {
2559
+ fs.writeFileSync(UPDATE_AVAILABLE_PATH, JSON.stringify({
2560
+ installed, latest, ts: Date.now(),
2561
+ update_url: `https://github.com/AnEntrypoint/plugkit-bin/releases/tag/v${latest}`,
2562
+ }));
2563
+ } catch (_) {}
2564
+ logEvent('plugkit', 'update.available', { installed, latest });
2565
+ _lastKnownDrift = latest;
2566
+ }
2567
+ }
2522
2568
  function checkForUpdate() {
2523
2569
  const installed = resolveVersion(instance);
2570
+ const cached = readSharedUpdateCache();
2571
+ if (cached) {
2572
+ applyUpdateCheckResult(installed, cached.latest, cached.status || 200);
2573
+ return;
2574
+ }
2524
2575
  const req = https.get({
2525
2576
  host: 'api.github.com',
2526
2577
  path: '/repos/AnEntrypoint/plugkit-bin/releases/latest',
@@ -2529,7 +2580,8 @@ async function runSpoolWatcher(instance, spoolDir) {
2529
2580
  }, (res) => {
2530
2581
  if (res.statusCode !== 200) {
2531
2582
  res.resume();
2532
- logEvent('plugkit', 'update.check.error', { installed, status: res.statusCode });
2583
+ writeSharedUpdateCache(null, res.statusCode);
2584
+ applyUpdateCheckResult(installed, null, res.statusCode);
2533
2585
  return;
2534
2586
  }
2535
2587
  const chunks = [];
@@ -2540,6 +2592,7 @@ async function runSpoolWatcher(instance, spoolDir) {
2540
2592
  const tag = rel && rel.tag_name;
2541
2593
  if (!tag) return;
2542
2594
  const latest = tag.replace(/^v/, '');
2595
+ writeSharedUpdateCache(latest, 200);
2543
2596
  if (latest === installed) {
2544
2597
  try { fs.unlinkSync(UPDATE_AVAILABLE_PATH); } catch (_) {}
2545
2598
  if (_lastKnownDrift) {
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1335",
3
+ "version": "2.0.1337",
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.500"
20
+ "plugkitVersion": "0.1.501"
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.1335",
3
+ "version": "2.0.1337",
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",
@@ -18,6 +18,8 @@ Every turn: dispatch `instruction` (you are the one dispatching it), read the re
18
18
 
19
19
  **Once `phase=COMPLETE` AND `prd_pending_count=0`, the chain is closed and you stop dispatching.** Polling `instruction` on a terminal chain returns the same UPDATE-DOCS prose every time and produces `turn.end dispatches:1 verbs:{instruction:1}` events in gmsniff that mark the agent as polling rather than walking. The user reactivates the chain by sending a new prompt; that prompt resets phase to PLAN on the next instruction dispatch carrying a fresh `{"prompt": "..."}` body.
20
20
 
21
+ **Client-side edits are gated by Browser Witness (paper §23, hard rule).** If you Write or Edit any file with a client-side extension — `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.mjs`, `.css`, or anything loaded from an HTML entry — you dispatch the `browser` verb in the **same turn** with a `page.evaluate` body that asserts the invariant the edit establishes. The transition gate refuses `transition to=COMPLETE` until `.turn-browser-witnessed` covers every entry in `.turn-browser-edits.json` with matching sha; absence or mismatch fires `deviation.client-edit-no-witness`. There is no "validate later" — later does not arrive in the chain you are walking; the same response that contains the client-side Write/Edit also contains the `browser` Write + Read.
22
+
21
23
  **Boot before dispatching. Always check first.** Writing to `.gm/exec-spool/in/instruction/N.txt` while the watcher is dead is the canonical cold-start failure — the request sits forever, you read no response, you fabricate the chain from memory of the prose. The spool directory's existence does NOT mean the watcher is alive; `.status.json` mtime within the last 15s does. The leftover `.status.json` from yesterday's dead watcher is the most common trap.
22
24
 
23
25
  Your first tool call of every session is the boot probe, in one Bash invocation: