gm-skill 2.0.1332 → 2.0.1334

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.1332",
3
+ "version": "2.0.1334",
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": {
@@ -2344,7 +2344,29 @@ async function runSpoolWatcher(instance, spoolDir) {
2344
2344
  }
2345
2345
 
2346
2346
  try {
2347
- const content = fs.readFileSync(filePath, 'utf8');
2347
+ const rawBuf = fs.readFileSync(filePath);
2348
+ let content;
2349
+ let _detectedEncoding = 'utf-8';
2350
+ if (rawBuf.length >= 2 && rawBuf[0] === 0xFF && rawBuf[1] === 0xFE) {
2351
+ content = rawBuf.slice(2).toString('utf16le');
2352
+ _detectedEncoding = 'utf-16le-bom';
2353
+ } else if (rawBuf.length >= 2 && rawBuf[0] === 0xFE && rawBuf[1] === 0xFF) {
2354
+ const swapped = Buffer.alloc(rawBuf.length - 2);
2355
+ for (let i = 2; i + 1 < rawBuf.length; i += 2) {
2356
+ swapped[i - 2] = rawBuf[i + 1];
2357
+ swapped[i - 1] = rawBuf[i];
2358
+ }
2359
+ content = swapped.toString('utf16le');
2360
+ _detectedEncoding = 'utf-16be-bom';
2361
+ } else if (rawBuf.length >= 3 && rawBuf[0] === 0xEF && rawBuf[1] === 0xBB && rawBuf[2] === 0xBF) {
2362
+ content = rawBuf.slice(3).toString('utf8');
2363
+ _detectedEncoding = 'utf-8-bom';
2364
+ } else {
2365
+ content = rawBuf.toString('utf8');
2366
+ }
2367
+ if (_detectedEncoding !== 'utf-8') {
2368
+ try { logEvent('plugkit', 'spool.body-encoding-recoded', { task: path.basename(filePath, path.extname(filePath)), encoding: _detectedEncoding, bytes: rawBuf.length }); } catch (_) {}
2369
+ }
2348
2370
  const relPath = path.relative(inDir, filePath);
2349
2371
  const dir = path.dirname(relPath);
2350
2372
  const verb = dir === '.' ? path.basename(filePath, path.extname(filePath)) : dir;
@@ -2555,8 +2577,26 @@ async function runSpoolWatcher(instance, spoolDir) {
2555
2577
  }
2556
2578
  }, 5000);
2557
2579
 
2580
+ let _sweepErrLogged = false;
2558
2581
  setInterval(() => {
2559
2582
  try {
2583
+ if (!fs.existsSync(outDir)) {
2584
+ try {
2585
+ fs.mkdirSync(outDir, { recursive: true });
2586
+ fs.mkdirSync(inDir, { recursive: true });
2587
+ console.log(`[retention] recreated missing spool dirs: ${outDir}, ${inDir}`);
2588
+ logEvent('plugkit', 'spool.dirs-recreated', { outDir, inDir, reason: 'sweep-found-missing' });
2589
+ _sweepErrLogged = false;
2590
+ return;
2591
+ } catch (mke) {
2592
+ if (!_sweepErrLogged) {
2593
+ console.error(`[retention] cannot recreate ${outDir}: ${mke.message}`);
2594
+ logEvent('plugkit', 'spool.dirs-recreate-failed', { outDir, error: mke.message });
2595
+ _sweepErrLogged = true;
2596
+ }
2597
+ return;
2598
+ }
2599
+ }
2560
2600
  const cutoff = Date.now() - 3600_000;
2561
2601
  let swept = 0;
2562
2602
  for (const entry of fs.readdirSync(outDir)) {
@@ -2570,9 +2610,13 @@ async function runSpoolWatcher(instance, spoolDir) {
2570
2610
  console.log(`[retention] swept ${swept} out/ files older than 1h`);
2571
2611
  logEvent('plugkit', 'sweep.retention', { swept });
2572
2612
  }
2613
+ _sweepErrLogged = false;
2573
2614
  } catch (e) {
2574
- console.error(`[retention] sweep error: ${e.message}`);
2575
- logEvent('plugkit', 'sweep.retention.error', { error: String(e.message || e) });
2615
+ if (!_sweepErrLogged) {
2616
+ console.error(`[retention] sweep error: ${e.message}`);
2617
+ logEvent('plugkit', 'sweep.retention.error', { error: String(e.message || e) });
2618
+ _sweepErrLogged = true;
2619
+ }
2576
2620
  }
2577
2621
  }, 60_000);
2578
2622
 
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.1332",
3
+ "version": "2.0.1334",
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.1332",
3
+ "version": "2.0.1334",
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",
@@ -38,6 +38,8 @@ bun x gm-plugkit@latest spool > /dev/null 2>&1 &
38
38
 
39
39
  Never poll the spool dir with `sleep && ls` or `Start-Sleep && Test-Path` — plugkit is synchronous from your view; if the response is not there, the watcher is dead (re-check `.status.json` mtime) or the verb is slow (check `.gm/exec-spool/.watcher.log`), not "still processing."
40
40
 
41
+ When writing the spool input from PowerShell, pass `-Encoding utf8` (or use `[System.IO.File]::WriteAllText($path, $body)` which defaults to UTF-8 no-BOM). PowerShell 5.1's default `Out-File` / `Set-Content` write UTF-16 LE with BOM, which the watcher detects and re-decodes (`spool.body-encoding-recoded` event in gmsniff), but the deviation is a fingerprint of an instruction you missed. Use `bash -c "echo -n '...' > ..."` or `Write` tool instead when the body is structured JSON.
42
+
41
43
  First turn body must be `{"prompt":"<user request>"}` so orient_nouns and recall_hits derive from the request; subsequent turns in the same conversation may use empty body `{}`.
42
44
 
43
45
  **Batch writes, waits, and reads together.** Each agent turn costs cycles; the dispatch shape `Write request → wait → Read response` is one logical step, not three. Issue all three in a single message — the Write tool call and the Read tool call go in the same `<function_calls>` block. The Read may return "file does not exist" if plugkit is mid-verb; that's fine, retry with one more Read in the next message rather than spreading the cycle across three turns. Fan-out is the same shape — dispatching three independent verbs (`prd-add g1`, `prd-add g2`, `prd-add g3`) means three Write tool calls in one block, then three Read tool calls in one block. Serial dispatch when you could be parallel is wasted cycles. The only sequencing constraint is real data dependency: if verb B needs the response of verb A, those go in separate turns; otherwise batch.