gm-codex 2.0.963 → 2.0.964

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-codex",
3
- "version": "2.0.963",
3
+ "version": "2.0.964",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": {
6
6
  "name": "AnEntrypoint",
package/bin/bootstrap.js CHANGED
@@ -24,6 +24,27 @@ function log(msg) {
24
24
  try { process.stderr.write(`[plugkit-bootstrap] ${msg}\n`); } catch (_) {}
25
25
  }
26
26
 
27
+ function probeBinaryVersion(binPath) {
28
+ try {
29
+ const { spawnSync } = require('child_process');
30
+ const r = spawnSync(binPath, ['--version'], { timeout: 3000, encoding: 'utf8' });
31
+ if (r.error) return null;
32
+ const text = `${r.stdout || ''} ${r.stderr || ''}`.trim();
33
+ const m = text.match(/(\d+\.\d+\.\d+)/);
34
+ return m ? m[1] : null;
35
+ } catch (_) { return null; }
36
+ }
37
+
38
+ function writeBootstrapError(spec) {
39
+ try {
40
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
41
+ const spoolDir = path.join(projectDir, '.gm', 'exec-spool');
42
+ fs.mkdirSync(spoolDir, { recursive: true });
43
+ const out = path.join(spoolDir, '.bootstrap-error.json');
44
+ fs.writeFileSync(out, JSON.stringify({ ts: new Date().toISOString(), ...spec }, null, 2));
45
+ } catch (_) {}
46
+ }
47
+
27
48
  function obsEvent(subsystem, event, fields) {
28
49
  if (process.env.GM_LOG_DISABLE) return;
29
50
  try {
@@ -326,19 +347,45 @@ async function bootstrap(opts) {
326
347
  const partialPath = `${finalPath}.partial`;
327
348
 
328
349
  if (fs.existsSync(finalPath) && fs.existsSync(okSentinel)) {
329
- if (!opts.silent) log(`cache hit: ${finalPath}`);
330
- proactiveKillForNewInstall(version, finalPath);
331
- pruneOldVersions(root, version, readRtkVersion(wrapperDir));
332
- return finalPath;
350
+ const actualVersion = probeBinaryVersion(finalPath);
351
+ if (actualVersion && actualVersion !== version) {
352
+ log(`cache version mismatch: dir=v${version} contains binary ${actualVersion} → re-fetching v${version}`);
353
+ writeBootstrapError({
354
+ expected_version: version,
355
+ cached_version: actualVersion,
356
+ error_phase: 'cache-hit-pin-mismatch',
357
+ error_message: `cached binary at ${finalPath} reports --version=${actualVersion} but cache dir pins v${version}`,
358
+ });
359
+ try { fs.unlinkSync(finalPath); } catch (_) {}
360
+ try { fs.unlinkSync(okSentinel); } catch (_) {}
361
+ } else {
362
+ if (!opts.silent) log(`cache hit: ${finalPath}${actualVersion ? ` (matches pin v${version})` : ''}`);
363
+ proactiveKillForNewInstall(version, finalPath);
364
+ pruneOldVersions(root, version, readRtkVersion(wrapperDir));
365
+ return finalPath;
366
+ }
333
367
  }
334
368
 
335
369
  if (healIfShaMatches(finalPath, expectedSha, okSentinel, partialPath, 'plugkit')) {
336
- if (!opts.silent) log(`cache heal (sha match): ${finalPath}`);
337
- proactiveKillForNewInstall(version, finalPath);
338
- pruneOldVersions(root, version, readRtkVersion(wrapperDir));
339
- try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
340
- catch (err) { log(`rtk fetch skipped: ${err.message}`); }
341
- return finalPath;
370
+ const actualVersion = probeBinaryVersion(finalPath);
371
+ if (actualVersion && actualVersion !== version) {
372
+ log(`cache heal version mismatch: dir=v${version} contains binary ${actualVersion} → re-fetching`);
373
+ writeBootstrapError({
374
+ expected_version: version,
375
+ cached_version: actualVersion,
376
+ error_phase: 'cache-heal-pin-mismatch',
377
+ error_message: `healed binary at ${finalPath} reports --version=${actualVersion} but cache dir pins v${version}`,
378
+ });
379
+ try { fs.unlinkSync(finalPath); } catch (_) {}
380
+ try { fs.unlinkSync(okSentinel); } catch (_) {}
381
+ } else {
382
+ if (!opts.silent) log(`cache heal (sha match): ${finalPath}${actualVersion ? ` (matches pin v${version})` : ''}`);
383
+ proactiveKillForNewInstall(version, finalPath);
384
+ pruneOldVersions(root, version, readRtkVersion(wrapperDir));
385
+ try { await bootstrapRtk(verDir, version, wrapperDir, opts.silent, root); }
386
+ catch (err) { log(`rtk fetch skipped: ${err.message}`); }
387
+ return finalPath;
388
+ }
342
389
  }
343
390
 
344
391
  const lockPath = path.join(verDir, '.lock');
@@ -368,12 +415,28 @@ async function bootstrap(opts) {
368
415
  } catch (_) {}
369
416
  }
370
417
  const url = `https://github.com/${RELEASE_REPO}/releases/download/v${version}/${binName}`;
371
- await downloadWithRetry(url, partialPath);
418
+ try {
419
+ await downloadWithRetry(url, partialPath);
420
+ } catch (fetchErr) {
421
+ writeBootstrapError({
422
+ expected_version: version,
423
+ cached_version: null,
424
+ error_phase: 'download',
425
+ error_message: fetchErr && fetchErr.message ? fetchErr.message : String(fetchErr),
426
+ });
427
+ throw fetchErr;
428
+ }
372
429
 
373
430
  if (expectedSha) {
374
431
  const got = await sha256OfFile(partialPath);
375
432
  if (got !== expectedSha) {
376
433
  try { fs.unlinkSync(partialPath); } catch (_) {}
434
+ writeBootstrapError({
435
+ expected_version: version,
436
+ cached_version: null,
437
+ error_phase: 'sha256-mismatch',
438
+ error_message: `sha256 mismatch for ${binName}: expected ${expectedSha}, got ${got}`,
439
+ });
377
440
  throw new Error(`sha256 mismatch for ${binName}: expected ${expectedSha}, got ${got}`);
378
441
  }
379
442
  log('sha256 verified');
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.963",
3
+ "version": "2.0.964",
4
4
  "description": "State machine agent with hooks, 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-codex",
3
- "version": "2.0.963",
3
+ "version": "2.0.964",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.963",
3
+ "version": "2.0.964",
4
4
  "description": "State machine agent with hooks, skills, and automated git enforcement",
5
5
  "author": {
6
6
  "name": "AnEntrypoint",