gm-skill 2.0.1374 → 2.0.1376

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,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.1374",
3
+ "version": "2.0.1376",
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": {
@@ -359,6 +359,38 @@ function readCurrentSess() {
359
359
 
360
360
  const __lockRejectedEmitAt = new Map();
361
361
 
362
+ function autoRecordBrowserEditsFromBody(body, cwd, taskBase, verb) {
363
+ if (!body || typeof body !== 'string') return;
364
+ const BROWSER_EXT_RE = /[\w.\-/\\]+\.(?:html?|tsx?|jsx?|mjs|cjs|vue|svelte|css|scss|sass)\b/gi;
365
+ const matches = body.match(BROWSER_EXT_RE);
366
+ if (!matches || matches.length === 0) return;
367
+ const seen = new Set();
368
+ const editsFile = path.join(cwd, '.gm', 'exec-spool', '.turn-browser-edits.json');
369
+ let list = [];
370
+ try { list = JSON.parse(fs.readFileSync(editsFile, 'utf8')); if (!Array.isArray(list)) list = []; } catch (_) {}
371
+ let added = 0;
372
+ for (const raw of matches) {
373
+ let rel = String(raw).replace(/^["'`(]+|["'`)]+$/g, '').replace(/\\/g, '/');
374
+ if (rel.startsWith('http://') || rel.startsWith('https://') || rel.startsWith('//')) continue;
375
+ if (rel.includes('node_modules/') || rel.startsWith('.gm/') || rel.includes('/.gm/')) continue;
376
+ if (seen.has(rel)) continue;
377
+ seen.add(rel);
378
+ const abs = path.isAbsolute(rel) ? rel : path.join(cwd, rel);
379
+ let st;
380
+ try { st = fs.statSync(abs); } catch (_) { continue; }
381
+ if (!st.isFile()) continue;
382
+ let hash = '';
383
+ try { hash = require('crypto').createHash('sha256').update(fs.readFileSync(abs)).digest('hex').slice(0, 12); } catch (_) {}
384
+ const idx = list.findIndex(e => e && e.file === rel);
385
+ const entry = { file: rel, ts: Date.now(), hash, source_verb: verb, source_task: taskBase };
386
+ if (idx === -1) { list.push(entry); added++; } else { list[idx] = entry; }
387
+ }
388
+ if (added > 0) {
389
+ try { fs.mkdirSync(path.dirname(editsFile), { recursive: true }); fs.writeFileSync(editsFile, JSON.stringify(list)); } catch (_) {}
390
+ logEvent('plugkit', 'browser.edits-autorecorded', { verb, task: taskBase, files: list.slice(-added).map(e => e.file), added });
391
+ }
392
+ }
393
+
362
394
  function logEvent(sub, event, fields) {
363
395
  if (process.env.GM_LOG_DISABLE) return;
364
396
  try {
@@ -2156,14 +2188,32 @@ async function runSpoolWatcher(instance, spoolDir) {
2156
2188
  if (unsupervised) {
2157
2189
  if (_driftLoggedOnce) return;
2158
2190
  _driftLoggedOnce = true;
2159
- logEvent('plugkit', 'version.drift-detected-no-exit', {
2191
+ logEvent('plugkit', 'version.drift-self-respawn', {
2160
2192
  instance_version: instV,
2161
2193
  file_version: fileV,
2162
- action: 'suppress-exit',
2163
- reason: 'no-supervisor-to-respawn',
2194
+ action: 'spawn-replacement-and-exit',
2164
2195
  boot_reason: bootReason,
2165
2196
  });
2166
- console.error(`[plugkit-wasm] version drift detected: instance=${instV} file=${fileV} — exit SUPPRESSED (boot_reason=${bootReason}; no supervisor to respawn)`);
2197
+ console.error(`[plugkit-wasm] version drift detected: instance=${instV} file=${fileV} — spawning replacement via bun x gm-plugkit@latest spool then exiting`);
2198
+ try {
2199
+ const cp = require('child_process');
2200
+ const bunPath = process.env.GM_BUN_PATH || 'bun';
2201
+ const child = cp.spawn(bunPath, ['x', 'gm-plugkit@latest', 'spool'], {
2202
+ cwd: process.cwd(),
2203
+ detached: true,
2204
+ stdio: 'ignore',
2205
+ windowsHide: true,
2206
+ env: { ...process.env, PLUGKIT_BOOT_REASON: 'self-respawn-from-drift' },
2207
+ });
2208
+ child.unref();
2209
+ } catch (e) {
2210
+ console.error(`[plugkit-wasm] failed to spawn replacement: ${e.message}; exiting anyway so next agent dispatch boots fresh`);
2211
+ }
2212
+ try { fs.writeFileSync(path.join(spoolDir, '.shutdown-reason.json'), JSON.stringify({ reason: 'version-change-unsupervised', ts: Date.now(), pid: process.pid, instance_version: instV, file_version: fileV })); } catch (_) {}
2213
+ try { releaseLock(); } catch (_) {}
2214
+ try { fs.unlinkSync(STATUS_PATH_FOR_TEARDOWN); } catch (_) {}
2215
+ try { clearBootActive(); } catch (_) {}
2216
+ setTimeout(() => process.exit(0), 2000);
2167
2217
  return;
2168
2218
  }
2169
2219
  logEvent('plugkit', 'version.drift', {
@@ -2535,6 +2585,10 @@ async function runSpoolWatcher(instance, spoolDir) {
2535
2585
  console.log(`[dispatch] → verb=${verb} task=${taskBase} body=${bodyBytes.length}b`);
2536
2586
  logEvent('plugkit', 'dispatch.start', { verb, task: taskBase, body_bytes: bodyBytes.length, cwd: process.cwd() });
2537
2587
 
2588
+ if (verb === 'memorize-fire' || verb === 'transition' || verb === 'prd-resolve' || verb === 'mutable-resolve') {
2589
+ try { autoRecordBrowserEditsFromBody(body, process.cwd(), taskBase, verb); } catch (_) {}
2590
+ }
2591
+
2538
2592
  let autoRecallPayload = null;
2539
2593
  if (verb === 'instruction') {
2540
2594
  const sessForRecall = readCurrentSess();
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1374",
3
+ "version": "2.0.1376",
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.1374",
3
+ "version": "2.0.1376",
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",