gm-qwen 2.0.968 → 2.0.970

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/bin/bootstrap.js CHANGED
@@ -27,7 +27,7 @@ function log(msg) {
27
27
  function probeBinaryVersion(binPath) {
28
28
  try {
29
29
  const { spawnSync } = require('child_process');
30
- const r = spawnSync(binPath, ['--version'], { timeout: 3000, encoding: 'utf8' });
30
+ const r = spawnSync(binPath, ['--version'], { timeout: 3000, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
31
31
  if (r.error) return null;
32
32
  const text = `${r.stdout || ''} ${r.stderr || ''}`.trim();
33
33
  const m = text.match(/(\d+\.\d+\.\d+)/);
@@ -183,7 +183,7 @@ function acquireLock(lockPath) {
183
183
  continue;
184
184
  }
185
185
  if (Date.now() - start > ATTEMPT_TIMEOUT_MS) throw new Error(`lock wait timeout: ${lockPath}`);
186
- try { const { spawnSync } = require('child_process'); spawnSync(process.execPath, ['-e', 'setTimeout(()=>{}, 2000)'], { timeout: 2500, killSignal: 'SIGKILL' }); } catch (_) {}
186
+ try { const { spawnSync } = require('child_process'); spawnSync(process.execPath, ['-e', 'setTimeout(()=>{}, 2000)'], { timeout: 2500, killSignal: 'SIGKILL', stdio: 'ignore', windowsHide: true }); } catch (_) {}
187
187
  }
188
188
  }
189
189
  }
@@ -380,7 +380,7 @@ async function bootstrap(opts) {
380
380
  if (!opts.silent) log(`cache heal (sha match): ${finalPath}${actualVersion ? ` (matches pin v${version})` : ''}`);
381
381
  proactiveKillForNewInstall(version, finalPath);
382
382
  pruneOldVersions(root, version, readRtkVersion(wrapperDir));
383
- bootstrapRtk(verDir, version, wrapperDir, opts.silent, root).catch(err => log(`rtk fetch skipped: ${err.message}`));
383
+ spawnDetachedRtkFetch(wrapperDir);
384
384
  return finalPath;
385
385
  }
386
386
  }
@@ -397,7 +397,7 @@ async function bootstrap(opts) {
397
397
  log(`cache heal (sha match) under lock: ${finalPath}`);
398
398
  proactiveKillForNewInstall(version, finalPath);
399
399
  pruneOldVersions(root, version, readRtkVersion(wrapperDir));
400
- bootstrapRtk(verDir, version, wrapperDir, opts.silent, root).catch(err => log(`rtk fetch skipped: ${err.message}`));
400
+ spawnDetachedRtkFetch(wrapperDir);
401
401
  return finalPath;
402
402
  }
403
403
 
@@ -457,14 +457,28 @@ async function bootstrap(opts) {
457
457
  obsEvent('bootstrap', 'install.done', { path: finalPath, version, kind: 'plugkit' });
458
458
  proactiveKillForNewInstall(version, finalPath);
459
459
  pruneOldVersions(root, version, readRtkVersion(wrapperDir));
460
- try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
461
- catch (err) { log(`rtk fetch skipped: ${err.message}`); }
460
+ spawnDetachedRtkFetch(wrapperDir);
462
461
  return finalPath;
463
462
  } finally {
464
463
  releaseLock(lockPath);
465
464
  }
466
465
  }
467
466
 
467
+ function spawnDetachedRtkFetch(wrapperDir) {
468
+ try {
469
+ const { spawn } = require('child_process');
470
+ const child = spawn(process.execPath, [__filename, '--rtk-only', '--wrapper-dir', wrapperDir], {
471
+ detached: true,
472
+ stdio: 'ignore',
473
+ windowsHide: true,
474
+ });
475
+ child.unref();
476
+ obsEvent('bootstrap', 'rtk.detached.spawned', { pid: child.pid, wrapperDir });
477
+ } catch (err) {
478
+ log(`rtk detach spawn failed: ${err.message}`);
479
+ }
480
+ }
481
+
468
482
  function rtkCacheDir(root, wrapperDir, plugkitVerDir) {
469
483
  const rtkVer = readRtkVersion(wrapperDir);
470
484
  if (!rtkVer) return plugkitVerDir;
@@ -609,7 +623,7 @@ function listRunningPlugkitImagePaths() {
609
623
  if (os.platform() === 'win32') {
610
624
  let parsed = null;
611
625
  try {
612
- const p = spawnSync('powershell', ['-NoProfile', '-NonInteractive', '-Command', "Get-Process plugkit* -ErrorAction SilentlyContinue | Select-Object Id,Path | ConvertTo-Json -Compress"], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL' });
626
+ const p = spawnSync('powershell', ['-NoProfile', '-NonInteractive', '-Command', "Get-Process plugkit* -ErrorAction SilentlyContinue | Select-Object Id,Path | ConvertTo-Json -Compress"], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL', stdio: ['ignore', 'pipe', 'pipe'] });
613
627
  const text = ((p && p.stdout) || '').trim();
614
628
  if (text) {
615
629
  const j = JSON.parse(text);
@@ -624,7 +638,7 @@ function listRunningPlugkitImagePaths() {
624
638
  out.push({ pid, path: (item.Path || '').trim() });
625
639
  }
626
640
  } else {
627
- const r = spawnSync('tasklist', ['/FI', 'IMAGENAME eq plugkit*', '/FO', 'CSV', '/NH'], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL' });
641
+ const r = spawnSync('tasklist', ['/FI', 'IMAGENAME eq plugkit*', '/FO', 'CSV', '/NH'], { windowsHide: true, encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL', stdio: ['ignore', 'pipe', 'pipe'] });
628
642
  const text = (r && r.stdout) || '';
629
643
  const seen = new Set();
630
644
  for (const line of text.split(/\r?\n/)) {
@@ -650,7 +664,7 @@ function listRunningPlugkitImagePaths() {
650
664
  out.push({ pid, path: imagePath });
651
665
  }
652
666
  } else {
653
- const r = spawnSync('ps', ['-axo', 'pid=,comm='], { encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL' });
667
+ const r = spawnSync('ps', ['-axo', 'pid=,comm='], { encoding: 'utf8', timeout: 5000, killSignal: 'SIGKILL', stdio: ['ignore', 'pipe', 'pipe'] });
654
668
  const text = (r && r.stdout) || '';
655
669
  for (const line of text.split(/\r?\n/)) {
656
670
  const m = line.match(/^\s*(\d+)\s+(.+?)\s*$/);
@@ -659,7 +673,7 @@ function listRunningPlugkitImagePaths() {
659
673
  const pid = parseInt(m[1], 10);
660
674
  let imagePath = '';
661
675
  try {
662
- const p = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8', timeout: 3000, killSignal: 'SIGKILL' });
676
+ const p = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8', timeout: 3000, killSignal: 'SIGKILL', stdio: ['ignore', 'pipe', 'pipe'] });
663
677
  imagePath = ((p && p.stdout) || '').trim().split(/\s+/)[0] || '';
664
678
  } catch (_) {}
665
679
  out.push({ pid, path: imagePath });
@@ -728,7 +742,28 @@ function killStaleDaemonIfVersionChanged(wrapperDir) {
728
742
  module.exports = { bootstrap, resolveCachedBinary, resolveCachedRtk, platformKey, binaryName, rtkBinaryName, cacheRoot, obsEvent, killRunningDaemons, killStaleDaemonIfVersionChanged, killSpoolWatcherInCwd, proactiveKillForNewInstall };
729
743
 
730
744
  if (require.main === module) {
731
- bootstrap({ silent: false })
732
- .then(p => { process.stdout.write(p + '\n'); process.exit(0); })
733
- .catch(err => { log(`FATAL: ${err.message}`); obsEvent('bootstrap', 'fatal', { err: String(err.message || err) }); process.exit(1); });
745
+ const argv = process.argv.slice(2);
746
+ if (argv.includes('--rtk-only')) {
747
+ const wIdx = argv.indexOf('--wrapper-dir');
748
+ const wrapperDir = wIdx >= 0 ? argv[wIdx + 1] : __dirname;
749
+ (async () => {
750
+ try {
751
+ const version = readVersionFile(wrapperDir);
752
+ let root = cacheRoot();
753
+ try { ensureDir(root); }
754
+ catch (_) { root = fallbackCacheRoot(); ensureDir(root); }
755
+ const verDir = path.join(root, `v${version}`);
756
+ ensureDir(verDir);
757
+ await bootstrapRtk(verDir, version, wrapperDir, true, root);
758
+ process.exit(0);
759
+ } catch (err) {
760
+ obsEvent('bootstrap', 'rtk.detached.failed', { err: String(err.message || err) });
761
+ process.exit(1);
762
+ }
763
+ })();
764
+ } else {
765
+ bootstrap({ silent: false })
766
+ .then(p => { process.stdout.write(p + '\n'); process.exit(0); })
767
+ .catch(err => { log(`FATAL: ${err.message}`); obsEvent('bootstrap', 'fatal', { err: String(err.message || err) }); process.exit(1); });
768
+ }
734
769
  }
@@ -1,6 +1,6 @@
1
- 85d3e85d5d08c18daa09a464d33983c68cd0b27987e4b8e756adc6cc0e75c0a2 plugkit-win32-x64.exe
2
- 1a7f46d9782042b8174fe3b194b7588da6e8e4c6f7e680e5fc1fed21f2ca653d plugkit-win32-arm64.exe
3
- 29bea04a25c0bb03dc66acf6a157d5fa230e019b1e968a8c133d23ea34e7c03a plugkit-darwin-x64
4
- 1e66a080f6290967b363a8df7f1c76317788af8fc0a4ce61e343211326079416 plugkit-darwin-arm64
5
- 704f0f3b342ed9dcd3576df32964c21b697c99c2b38f66c3e7ef153ec8711101 plugkit-linux-x64
6
- f753df6fc9ca77c0935f25fb732fa5b83950c03c2d755528dea5e1727b566434 plugkit-linux-arm64
1
+ 9427573afbaae71c2c80f914928bf3fa0083f9fd5dc028fe63e993ba7067aad3 plugkit-win32-x64.exe
2
+ 9a77ff2f5def8cb3fb3073a6077bdb9b9dfc4b47bf5efd2256ad26ad04bae767 plugkit-win32-arm64.exe
3
+ 6e1d0aebc9d038242fbfb633f5818503e1dc8d06010e83f4c4cb42632eef2f15 plugkit-darwin-x64
4
+ 4b77cae443f4aa20b37a45f147f0ce98af508b7d9da79c57e4dcda7b9e1371fc plugkit-darwin-arm64
5
+ c6b4cce4c41158fbed405e18f2bdd06da8efa2424d5cf2bf1a834c62002e37b9 plugkit-linux-x64
6
+ 749cb83fb32d49d43709552f8394edb328a99d635d564b6b0c7fc764b7090597 plugkit-linux-arm64
@@ -1 +1 @@
1
- 0.1.328
1
+ 0.1.329
package/bin/rtk.sha256 CHANGED
@@ -1,5 +1,5 @@
1
- 259d302669a780501f1829d346719bdf751c67b2dbc91b8ebce0cbd55361d039 rtk-win32-x64.exe
2
- bdfd114d14aab47032bbb9858cc177f154d4c7e5372e798a3d11a3b070ea20fd rtk-win32-arm64.exe
1
+ 0d6f3fe935836264e55c08bb258c413978996799d67114c9f006237945249cbc rtk-win32-x64.exe
2
+ 9f7be4ce1974055f8fd4237f8421b713e13f80486afdb4ec5ecff24410a0d9d7 rtk-win32-arm64.exe
3
3
  1b1e792767ed0e1e6ca0e2f0a8de02e77b06dea2f5ae667278b94baf239fcdc3 rtk-darwin-x64
4
4
  9717978d9d6216ea50c94444e00e359479b6315a17bd48c16064b267c8b0b60d rtk-darwin-arm64
5
5
  a100d3defac54194144e5723aec57e6f286b42298c67145c8428815246c9ee56 rtk-linux-x64
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.968",
3
+ "version": "2.0.970",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -23,5 +23,5 @@
23
23
  "publishConfig": {
24
24
  "access": "public"
25
25
  },
26
- "plugkitVersion": "0.1.328"
26
+ "plugkitVersion": "0.1.329"
27
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-qwen",
3
- "version": "2.0.968",
3
+ "version": "2.0.970",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -50,13 +50,17 @@ One subagent per fact, fan out in parallel — batching dilutes the signal. The
50
50
 
51
51
  ## Execution order
52
52
 
53
- 1. Recall (`exec:recall` via Bash) cheapest
54
- 2. Code execution — write to `.gm/exec-spool/in/<lang>/<N>.<ext>` (nodejs, python, bash, typescript, go, rust, c, cpp, java, deno); spool watcher runs and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr), with `out/<N>.json` metadata sidecar at completion
55
- 3. Codebase search (`exec:codesearch` via Bash) — 90% of lookups
53
+ The spool is the universal dispatch surface. Write a file to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>`; the watcher executes and streams `out/<N>.out` + `out/<N>.err` + `out/<N>.json`. Languages: nodejs, python, bash, typescript, go, rust, c, cpp, java, deno. Verbs: codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health.
54
+
55
+ Order of cheapness:
56
+
57
+ 1. Recall — `in/recall/<N>.txt` with the query
58
+ 2. Codebase search — `in/codesearch/<N>.txt` with two-word query, 90% of lookups
59
+ 3. Code execution — `in/<lang>/<N>.<ext>`
56
60
  4. Web (`WebFetch`, `WebSearch`) — env facts not in codebase
57
61
  5. User — last resort
58
62
 
59
- Bash accepts ONLY git commands and utility verbs (`exec:recall`, `exec:codesearch`, `exec:memorize`, `exec:wait`, `exec:browser`, etc.). All code execution goes via the spool. Never `Bash(node/npm/npx/bun)`. `git push` triggers auto CI watch via Stop hook.
63
+ Bash accepts ONLY git commands directly (`git status`, `git commit`, `git push`, `git log`, `gh ...`). Everything else — code AND every utility verb — dispatches via the spool. Never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`. `git push` triggers auto CI watch via Stop hook.
60
64
 
61
65
  Skill chain: `planning` → `gm-execute` → `gm-emit` → `gm-complete` → `update-docs`.
62
66
 
@@ -54,7 +54,7 @@ Long-running probes split into navigate-call → `exec:wait N` → probe-call to
54
54
 
55
55
  Exempt only when: change is server-only with zero browser-facing surface, OR the repository has no browser surface at all (pure CLI / library). Exemption requires explicit tag in the response: `BROWSER EXEMPT: <reason — must reference diff paths showing zero browser-facing surface>`. Default posture is NOT exempt — burden is on the agent to prove exemption with diff evidence.
56
56
 
57
- Pre-flight: run `git diff --name-only origin/main..HEAD` and grep for `client/|docs/|\.html$|\.glsl$|\.frag$|\.vert$`. Any hit AND no `exec:browser` block in this session → mandatory regression to `gm-execute`.
57
+ Pre-flight: run `git diff --name-only origin/main..HEAD` directly via Bash, then dispatch a nodejs spool file that reads the diff list and filters lines matching `client/|docs/|\.html$|\.glsl$|\.frag$|\.vert$`. Any hit AND no `exec:browser` block in this session → mandatory regression to `gm-execute`.
58
58
 
59
59
  ## Integration test gate
60
60
 
@@ -40,13 +40,13 @@ Spend on `.prd` items in descending order of consequence-if-wrong × distance-fr
40
40
 
41
41
  ## Code execution
42
42
 
43
- Code runs through the file-spool, not Bash. Write a file to `.gm/exec-spool/in/<lang>/<N>.<ext>` (e.g. `in/nodejs/42.js`, `in/python/43.py`, `in/bash/44.sh`); the spool watcher executes and streams stdout to `out/<N>.out`, stderr to `out/<N>.err`, then writes `out/<N>.json` metadata sidecar at completion (taskId, lang, ok, exitCode, durationMs, timedOut, startedAt, endedAt). Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. Languages: nodejs (default), bash, python, typescript, go, rust, c, cpp, java, deno. File I/O via a nodejs spool file + `require('fs')`. Git directly in Bash. Utility verbs (`exec:recall`, `exec:codesearch`, `exec:memorize`, `exec:wait`, `exec:sleep`, `exec:browser`, etc.) DO run via Bash with the verb on line 1 and arg on line 2. Never `Bash(node/npm/npx/bun)`.
43
+ Code AND utility verbs both run through the file-spool. Write a file to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>` — language stems (`in/nodejs/42.js`, `in/python/43.py`, `in/bash/44.sh`, plus typescript, go, rust, c, cpp, java, deno) or verb stems (`in/codesearch/45.txt`, `in/recall/46.txt`, `in/memorize/47.md`, plus wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher executes and streams stdout to `out/<N>.out`, stderr to `out/<N>.err`, then writes `out/<N>.json` metadata sidecar at completion (taskId, lang, ok, exitCode, durationMs, timedOut, startedAt, endedAt). Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. File I/O via a nodejs spool file + `require('fs')`. Only `git` and `gh` run directly in Bash. Never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`.
44
44
 
45
- Pack runs: `Promise.allSettled`, each idea own try/catch, under 12s per call. Runner: `exec:runner\n{start|stop|status}`.
45
+ Pack runs: `Promise.allSettled`, each idea own try/catch, under 12s per call. Runner: write `in/runner/<N>.txt` with body `start` | `stop` | `status`.
46
46
 
47
47
  Every exec daemonizes. The hook tails the task logfile up to 30s wall-clock and returns whatever is there — short tasks complete inside the window and look synchronous; long tasks return a task_id with partial output. Continue with `exec:tail` (drain, bounded), `exec:watch` (resume blocking until match or timeout), or `exec:close` (terminate). Never re-spawn a long task to check on it — that orphans the first one. `exec:wait` is a pure timer; `exec:sleep` blocks on a specific task's output; `exec:watch` is the match-or-timeout primitive. Every execution-platform RPC returns the live list of running tasks for this session — close stragglers via `exec:close\n<id>` so the list stays scannable. Session-end (clear/logout/prompt_input_exit) kills the session's tasks; compaction/handoff preserves them.
48
48
 
49
- Utility verbs (`exec:wait`, `exec:sleep`, `exec:status`, `exec:close`, `exec:pause`, `exec:type`, `exec:runner`, `exec:kill-port`, `exec:recall`, `exec:memorize`, `exec:forget`) take their argument on the next line. Inline form (`exec:status <id>`) is denied by the hook.
49
+ Every utility verb dispatches via `in/<verb>/<N>.txt`; the body of the file is the verb's argument. There is no inline form and no Bash-prefix form both are denied by the hook.
50
50
 
51
51
  ## Codebase search
52
52
 
@@ -103,7 +103,7 @@ The 200 lines are a *budget* for maximum surface coverage, not a target. Subsyst
103
103
 
104
104
  ## Execution norms encoded in the plan
105
105
 
106
- Code execution writes to `.gm/exec-spool/in/<lang>/<N>.<ext>`; the spool watcher runs the file and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr) line-by-line, then writes `out/<N>.json` metadata (exitCode, durationMs, timedOut, startedAt, endedAt) at completion. Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. `in/` and `out/` are wiped at session start and at real-exit session end. Utility verbs (`exec:recall`, `exec:codesearch`, `exec:memorize`, `exec:wait`, etc.) and `git` run directly via Bash. Never `Bash(node/npm/npx/bun)`. Spool paths in nodejs files are platform-literal — use `os.tmpdir()` and `path.join`. The spool enforces per-task timeouts; on timeout, partial output is preserved and the watcher emits `[exec timed out after Nms; partial output above]`.
106
+ Code execution AND utility verbs both write to `.gm/exec-spool/in/<lang-or-verb>/<N>.<ext>`. Languages live under `in/<lang>/` (nodejs, python, bash, typescript, go, rust, c, cpp, java, deno); verbs live under `in/<verb>/` (codesearch, recall, memorize, wait, sleep, status, close, browser, runner, type, kill-port, forget, feedback, learn-status, learn-debug, learn-build, discipline, pause, health). The spool watcher runs the file and streams to `out/<N>.out` (stdout) + `out/<N>.err` (stderr) line-by-line, then writes `out/<N>.json` metadata (exitCode, durationMs, timedOut, startedAt, endedAt) at completion. Both streams return as systemMessage with `--- stdout ---` / `--- stderr ---` separators. `in/` and `out/` are wiped at session start and at real-exit session end. Only `git` (and `gh`) run directly via Bash; never `Bash(node/npm/npx/bun)`, never `Bash(exec:<anything>)`. Spool paths in nodejs files are platform-literal — use `os.tmpdir()` and `path.join`. The spool enforces per-task timeouts; on timeout, partial output is preserved and the watcher emits `[exec timed out after Nms; partial output above]`.
107
107
 
108
108
  `exec:codesearch` only — Grep/Glob/Find/Explore are hook-blocked. Start two words, change/add one per pass, minimum four attempts before concluding absent.
109
109