@sdsrs/code-graph 0.76.1 → 0.76.2

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.
@@ -4,7 +4,7 @@
4
4
  "author": {
5
5
  "name": "sdsrs"
6
6
  },
7
- "version": "0.76.1",
7
+ "version": "0.76.2",
8
8
  "keywords": [
9
9
  "code-graph",
10
10
  "ast",
@@ -393,30 +393,35 @@ async function downloadAndInstall(latest, {
393
393
  pluginUpdated = true;
394
394
  }
395
395
 
396
- // Update installed_plugins.json to point to new version
397
- const installedPath = installedPluginsPath();
398
- try {
399
- const installed = readJson(installedPath);
400
- if (installed && installed.plugins && installed.plugins[PLUGIN_ID]) {
401
- installed.plugins[PLUGIN_ID][0].installPath = pluginDst;
402
- installed.plugins[PLUGIN_ID][0].version = latest.version;
403
- installed.plugins[PLUGIN_ID][0].lastUpdated = new Date().toISOString();
404
- writeJsonAtomic(installedPath, installed);
405
- }
406
- } catch { /* not fatal */ }
407
-
408
- // Update install manifest
409
- try {
410
- const manifest = readManifest();
411
- manifest.version = latest.version;
412
- manifest.updatedAt = new Date().toISOString();
413
- writeJsonAtomic(path.join(CACHE_DIR, 'install-manifest.json'), manifest);
414
- } catch { /* not fatal */ }
415
-
416
- // Run the NEW lifecycle.js to update settings.json hooks with new paths.
417
- // Without this, settings.json hooks still point to the old version directory
418
- // until the next session's self-heal corrects them.
396
+ // Repoint state at the new version ONLY if the plugin copy actually landed.
397
+ // Guarding on pluginUpdated: when the copy above was skipped (pluginSrc absent, or
398
+ // its plugin.json version drifted from the tag — the project's version sync is known
399
+ // fragile), pluginDst was never created. Advancing installPath/manifest to it anyway
400
+ // pointed Claude Code at a nonexistent install dir while state read "up to date".
419
401
  if (pluginUpdated) {
402
+ // Update installed_plugins.json to point to new version
403
+ const installedPath = installedPluginsPath();
404
+ try {
405
+ const installed = readJson(installedPath);
406
+ if (installed && installed.plugins && installed.plugins[PLUGIN_ID]) {
407
+ installed.plugins[PLUGIN_ID][0].installPath = pluginDst;
408
+ installed.plugins[PLUGIN_ID][0].version = latest.version;
409
+ installed.plugins[PLUGIN_ID][0].lastUpdated = new Date().toISOString();
410
+ writeJsonAtomic(installedPath, installed);
411
+ }
412
+ } catch { /* not fatal */ }
413
+
414
+ // Update install manifest
415
+ try {
416
+ const manifest = readManifest();
417
+ manifest.version = latest.version;
418
+ manifest.updatedAt = new Date().toISOString();
419
+ writeJsonAtomic(path.join(CACHE_DIR, 'install-manifest.json'), manifest);
420
+ } catch { /* not fatal */ }
421
+
422
+ // Run the NEW lifecycle.js to update settings.json hooks with new paths.
423
+ // Without this, settings.json hooks still point to the old version directory
424
+ // until the next session's self-heal corrects them.
420
425
  try {
421
426
  const newLifecycle = path.join(pluginDst, 'scripts', 'lifecycle.js');
422
427
  if (fs.existsSync(newLifecycle)) {
@@ -376,3 +376,57 @@ test('downloadAndInstall wires the marketplace refresh + binary download (orches
376
376
  'code-graph-mcp', 'code-graph-mcp', '9.9.9', '.claude-plugin', 'plugin.json');
377
377
  assert.equal(fs.existsSync(dst), true, 'plugin copied into sandbox plugins cache');
378
378
  });
379
+
380
+ test('downloadAndInstall does NOT repoint install state when the plugin copy is skipped (version drift)', async (t) => {
381
+ // Guard for a silent-breakage bug: when the extracted tarball's plugin.json version
382
+ // doesn't match latest.version, the copy is skipped and pluginDst is never created.
383
+ // installed_plugins.json must NOT be advanced to that nonexistent dir, or Claude Code
384
+ // ends up pointed at a missing install while state reads "up to date".
385
+ const sandboxHome = mkDir(t, 'code-graph-dai-skip-');
386
+ const installedDir = path.join(sandboxHome, '.claude', 'plugins');
387
+ fs.mkdirSync(installedDir, { recursive: true });
388
+ const installedPath = path.join(installedDir, 'installed_plugins.json');
389
+ fs.writeFileSync(installedPath, JSON.stringify({
390
+ plugins: { 'code-graph-mcp@code-graph-mcp': [
391
+ { installPath: '/old/install/path', version: '0.0.1', lastUpdated: 'seed' },
392
+ ] },
393
+ }));
394
+
395
+ const script = `
396
+ const fs = require('fs');
397
+ const path = require('path');
398
+ const { downloadAndInstall } = require(${JSON.stringify(path.join(__dirname, 'auto-update.js'))});
399
+ const latest = { version: '9.9.9', tarballUrl: 'https://example/tar', binaryUrl: null };
400
+ const exec = (cmd, args) => {
401
+ if (cmd === 'tar') {
402
+ // Extract a claude-plugin/ whose version DRIFTS from latest → copy is skipped.
403
+ const tmpDir = args[args.indexOf('-C') + 1];
404
+ const mDir = path.join(tmpDir, 'claude-plugin', '.claude-plugin');
405
+ fs.mkdirSync(mDir, { recursive: true });
406
+ fs.writeFileSync(path.join(mDir, 'plugin.json'), JSON.stringify({ version: '0.0.0' }));
407
+ }
408
+ };
409
+ (async () => {
410
+ const result = await downloadAndInstall(latest, {
411
+ exec,
412
+ refreshMarketplace: () => true,
413
+ downloadBin: async () => true,
414
+ });
415
+ console.log(JSON.stringify({ result }));
416
+ })();
417
+ `;
418
+ const out = execGit(process.execPath, ['-e', script], {
419
+ env: { ...process.env, HOME: sandboxHome },
420
+ encoding: 'utf8',
421
+ });
422
+ const { result } = JSON.parse(out.trim().split('\n').pop());
423
+ assert.equal(result.pluginUpdated, false, 'version drift must skip the plugin copy');
424
+
425
+ // The pre-seeded record must be UNTOUCHED — not repointed to the 9.9.9 dir.
426
+ const rec = JSON.parse(fs.readFileSync(installedPath, 'utf8'))
427
+ .plugins['code-graph-mcp@code-graph-mcp'][0];
428
+ assert.equal(rec.installPath, '/old/install/path',
429
+ 'installPath must not be repointed when the copy was skipped');
430
+ assert.equal(rec.version, '0.0.1',
431
+ 'version must not be advanced when the copy was skipped');
432
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdsrs/code-graph",
3
- "version": "0.76.1",
3
+ "version": "0.76.2",
4
4
  "description": "MCP server that indexes codebases into an AST knowledge graph with semantic search, call graph traversal, and HTTP route tracing",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,10 +35,10 @@
35
35
  "node": ">=16"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@sdsrs/code-graph-linux-x64": "0.76.1",
39
- "@sdsrs/code-graph-linux-arm64": "0.76.1",
40
- "@sdsrs/code-graph-darwin-x64": "0.76.1",
41
- "@sdsrs/code-graph-darwin-arm64": "0.76.1",
42
- "@sdsrs/code-graph-win32-x64": "0.76.1"
38
+ "@sdsrs/code-graph-linux-x64": "0.76.2",
39
+ "@sdsrs/code-graph-linux-arm64": "0.76.2",
40
+ "@sdsrs/code-graph-darwin-x64": "0.76.2",
41
+ "@sdsrs/code-graph-darwin-arm64": "0.76.2",
42
+ "@sdsrs/code-graph-win32-x64": "0.76.2"
43
43
  }
44
44
  }