@sdsrs/code-graph 0.8.3 → 0.8.4
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/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/scripts/auto-update.js +14 -8
- package/claude-plugin/scripts/auto-update.test.js +10 -8
- package/claude-plugin/scripts/lifecycle.e2e.test.js +6 -4
- package/claude-plugin/scripts/lifecycle.test.js +13 -10
- package/claude-plugin/scripts/session-init.test.js +2 -1
- package/claude-plugin/scripts/version-utils.test.js +12 -10
- package/package.json +6 -6
|
@@ -310,11 +310,18 @@ async function checkForUpdate() {
|
|
|
310
310
|
if (isDevMode()) return null;
|
|
311
311
|
|
|
312
312
|
const state = readState();
|
|
313
|
+
// manifest.version is authoritative — /plugin update writes it directly and
|
|
314
|
+
// bypasses auto-update.js, so re-sync state.installedVersion every call.
|
|
315
|
+
const installedVersion = readManifest().version || '0.0.0';
|
|
313
316
|
|
|
314
317
|
// Time-based throttle
|
|
315
318
|
if (!shouldCheck(state)) {
|
|
316
|
-
if (state.
|
|
317
|
-
|
|
319
|
+
if (state.installedVersion !== installedVersion) {
|
|
320
|
+
saveState({ ...state, installedVersion });
|
|
321
|
+
}
|
|
322
|
+
if (state.updateAvailable && state.latestVersion
|
|
323
|
+
&& compareVersions(state.latestVersion, installedVersion) > 0) {
|
|
324
|
+
return { updateAvailable: true, from: installedVersion, to: state.latestVersion };
|
|
318
325
|
}
|
|
319
326
|
return null;
|
|
320
327
|
}
|
|
@@ -322,21 +329,19 @@ async function checkForUpdate() {
|
|
|
322
329
|
// Check GitHub for latest release
|
|
323
330
|
const latest = await fetchLatestRelease();
|
|
324
331
|
if (!latest) {
|
|
325
|
-
saveState({ ...state, lastCheck: new Date().toISOString() });
|
|
332
|
+
saveState({ ...state, installedVersion, lastCheck: new Date().toISOString() });
|
|
326
333
|
return null;
|
|
327
334
|
}
|
|
328
335
|
|
|
329
336
|
// Compare versions
|
|
330
|
-
const
|
|
331
|
-
const currentVersion = manifest.version || '0.0.0';
|
|
332
|
-
const hasUpdate = compareVersions(latest.version, currentVersion) > 0;
|
|
337
|
+
const hasUpdate = compareVersions(latest.version, installedVersion) > 0;
|
|
333
338
|
|
|
334
339
|
if (hasUpdate) {
|
|
335
340
|
const result = await downloadAndInstall(latest);
|
|
336
341
|
const success = result.pluginUpdated;
|
|
337
342
|
const newState = {
|
|
338
343
|
lastCheck: new Date().toISOString(),
|
|
339
|
-
installedVersion: success ? latest.version :
|
|
344
|
+
installedVersion: success ? latest.version : installedVersion,
|
|
340
345
|
latestVersion: latest.version,
|
|
341
346
|
updateAvailable: !success,
|
|
342
347
|
lastUpdate: success ? new Date().toISOString() : state.lastUpdate,
|
|
@@ -349,7 +354,7 @@ async function checkForUpdate() {
|
|
|
349
354
|
updateAvailable: !success,
|
|
350
355
|
updated: success,
|
|
351
356
|
binaryUpdated: result.binaryUpdated,
|
|
352
|
-
from:
|
|
357
|
+
from: installedVersion,
|
|
353
358
|
to: latest.version,
|
|
354
359
|
};
|
|
355
360
|
}
|
|
@@ -357,6 +362,7 @@ async function checkForUpdate() {
|
|
|
357
362
|
// No update needed
|
|
358
363
|
saveState({
|
|
359
364
|
...state,
|
|
365
|
+
installedVersion,
|
|
360
366
|
lastCheck: new Date().toISOString(),
|
|
361
367
|
latestVersion: latest.version,
|
|
362
368
|
updateAvailable: false,
|
|
@@ -14,12 +14,14 @@ const {
|
|
|
14
14
|
promoteVerifiedBinary,
|
|
15
15
|
} = require('./auto-update');
|
|
16
16
|
|
|
17
|
-
function mkDir(prefix) {
|
|
18
|
-
|
|
17
|
+
function mkDir(t, prefix) {
|
|
18
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
19
|
+
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
20
|
+
return dir;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
test('getExtractedPluginVersion reads extracted plugin manifest version', () => {
|
|
22
|
-
const root = mkDir('code-graph-plugin-');
|
|
23
|
+
test('getExtractedPluginVersion reads extracted plugin manifest version', (t) => {
|
|
24
|
+
const root = mkDir(t, 'code-graph-plugin-');
|
|
23
25
|
const manifest = path.join(root, '.claude-plugin', 'plugin.json');
|
|
24
26
|
fs.mkdirSync(path.dirname(manifest), { recursive: true });
|
|
25
27
|
fs.writeFileSync(manifest, JSON.stringify({ version: '1.2.3' }, null, 2));
|
|
@@ -41,8 +43,8 @@ function writeFakeBinary(filePath, version) {
|
|
|
41
43
|
fs.chmodSync(filePath, 0o755);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
test('promoteVerifiedBinary accepts a runnable binary with the expected version', () => {
|
|
45
|
-
const dir = mkDir('code-graph-bin-');
|
|
46
|
+
test('promoteVerifiedBinary accepts a runnable binary with the expected version', (t) => {
|
|
47
|
+
const dir = mkDir(t, 'code-graph-bin-');
|
|
46
48
|
const tmp = path.join(dir, 'code-graph-mcp.tmp');
|
|
47
49
|
const dst = path.join(dir, 'code-graph-mcp');
|
|
48
50
|
writeFakeBinary(tmp, '1.2.3');
|
|
@@ -53,8 +55,8 @@ test('promoteVerifiedBinary accepts a runnable binary with the expected version'
|
|
|
53
55
|
assert.equal(fs.existsSync(dst), true);
|
|
54
56
|
});
|
|
55
57
|
|
|
56
|
-
test('promoteVerifiedBinary rejects binaries with mismatched version', () => {
|
|
57
|
-
const dir = mkDir('code-graph-bin-');
|
|
58
|
+
test('promoteVerifiedBinary rejects binaries with mismatched version', (t) => {
|
|
59
|
+
const dir = mkDir(t, 'code-graph-bin-');
|
|
58
60
|
const tmp = path.join(dir, 'code-graph-mcp.tmp');
|
|
59
61
|
const dst = path.join(dir, 'code-graph-mcp');
|
|
60
62
|
writeFakeBinary(tmp, '1.2.2');
|
|
@@ -12,8 +12,10 @@ const lifecycleCli = path.join(__dirname, 'lifecycle.js');
|
|
|
12
12
|
const compositeCli = path.join(__dirname, 'statusline-composite.js');
|
|
13
13
|
const currentVersion = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8')).version;
|
|
14
14
|
|
|
15
|
-
function mkHome() {
|
|
16
|
-
|
|
15
|
+
function mkHome(t) {
|
|
16
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'code-graph-e2e-'));
|
|
17
|
+
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
18
|
+
return dir;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
function writeJson(filePath, value) {
|
|
@@ -38,8 +40,8 @@ function runScript(homeDir, scriptPath, args = [], options = {}) {
|
|
|
38
40
|
}).toString();
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
test('lifecycle CLI handles install, disable self-heal, re-enable, and uninstall', () => {
|
|
42
|
-
const homeDir = mkHome();
|
|
43
|
+
test('lifecycle CLI handles install, disable self-heal, re-enable, and uninstall', (t) => {
|
|
44
|
+
const homeDir = mkHome(t);
|
|
43
45
|
const settingsPath = path.join(homeDir, '.claude', 'settings.json');
|
|
44
46
|
const installedPath = path.join(homeDir, '.claude', 'plugins', 'installed_plugins.json');
|
|
45
47
|
const registryPath = path.join(homeDir, '.cache', 'code-graph', 'statusline-registry.json');
|
|
@@ -9,8 +9,10 @@ const { execFileSync } = require('child_process');
|
|
|
9
9
|
const lifecyclePath = path.join(__dirname, 'lifecycle.js');
|
|
10
10
|
const statuslinePath = path.join(__dirname, 'statusline.js');
|
|
11
11
|
|
|
12
|
-
function mkHome() {
|
|
13
|
-
|
|
12
|
+
function mkHome(t) {
|
|
13
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'code-graph-home-'));
|
|
14
|
+
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
15
|
+
return dir;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
function writeJson(filePath, value) {
|
|
@@ -48,8 +50,8 @@ function seedOrphanedComposite(homeDir) {
|
|
|
48
50
|
return { settingsPath, registryPath };
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
test('cleanupDisabledStatusline restores previous statusline and removes registry', () => {
|
|
52
|
-
const homeDir = mkHome();
|
|
53
|
+
test('cleanupDisabledStatusline restores previous statusline and removes registry', (t) => {
|
|
54
|
+
const homeDir = mkHome(t);
|
|
53
55
|
const { settingsPath, registryPath } = seedDisabledComposite(homeDir);
|
|
54
56
|
|
|
55
57
|
const out = execFileSync(process.execPath, ['-e', `
|
|
@@ -63,10 +65,11 @@ test('cleanupDisabledStatusline restores previous statusline and removes registr
|
|
|
63
65
|
assert.equal(fs.existsSync(registryPath), false);
|
|
64
66
|
});
|
|
65
67
|
|
|
66
|
-
test('statusline exits cleanly and self-heals when plugin is disabled', () => {
|
|
67
|
-
const homeDir = mkHome();
|
|
68
|
+
test('statusline exits cleanly and self-heals when plugin is disabled', (t) => {
|
|
69
|
+
const homeDir = mkHome(t);
|
|
68
70
|
const { settingsPath, registryPath } = seedDisabledComposite(homeDir);
|
|
69
71
|
const projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'code-graph-project-'));
|
|
72
|
+
t.after(() => fs.rmSync(projectDir, { recursive: true, force: true }));
|
|
70
73
|
fs.mkdirSync(path.join(projectDir, '.code-graph'), { recursive: true });
|
|
71
74
|
fs.writeFileSync(path.join(projectDir, '.code-graph', 'index.db'), '');
|
|
72
75
|
|
|
@@ -81,8 +84,8 @@ test('statusline exits cleanly and self-heals when plugin is disabled', () => {
|
|
|
81
84
|
assert.equal(fs.existsSync(registryPath), false);
|
|
82
85
|
});
|
|
83
86
|
|
|
84
|
-
test('cleanupDisabledStatusline also heals orphaned statusline after uninstall', () => {
|
|
85
|
-
const homeDir = mkHome();
|
|
87
|
+
test('cleanupDisabledStatusline also heals orphaned statusline after uninstall', (t) => {
|
|
88
|
+
const homeDir = mkHome(t);
|
|
86
89
|
const { settingsPath, registryPath } = seedOrphanedComposite(homeDir);
|
|
87
90
|
|
|
88
91
|
const out = execFileSync(process.execPath, ['-e', `
|
|
@@ -175,8 +178,8 @@ test('removeHooksFromSettings strips our entries but keeps unrelated hooks', ()
|
|
|
175
178
|
assert.ok(!s.hooks.PostToolUse, 'empty event key should be deleted');
|
|
176
179
|
});
|
|
177
180
|
|
|
178
|
-
test('install() removes legacy code-graph hooks from settings.json without re-registering', () => {
|
|
179
|
-
const homeDir = mkHome();
|
|
181
|
+
test('install() removes legacy code-graph hooks from settings.json without re-registering', (t) => {
|
|
182
|
+
const homeDir = mkHome(t);
|
|
180
183
|
const settingsPath = path.join(homeDir, '.claude', 'settings.json');
|
|
181
184
|
writeJson(settingsPath, {
|
|
182
185
|
statusLine: { type: 'command', command: 'echo previous-status' },
|
|
@@ -83,9 +83,10 @@ test('consistencyCheck returns empty array when binary version matches plugin',
|
|
|
83
83
|
assert.ok(Array.isArray(result));
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
test('consistencyCheck returns version-mismatch when versions differ', () => {
|
|
86
|
+
test('consistencyCheck returns version-mismatch when versions differ', (t) => {
|
|
87
87
|
const os = require('os');
|
|
88
88
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-'));
|
|
89
|
+
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
89
90
|
const bin = path.join(dir, 'code-graph-mcp');
|
|
90
91
|
fs.writeFileSync(bin, [
|
|
91
92
|
'#!/usr/bin/env bash',
|
|
@@ -5,15 +5,17 @@ const fs = require('fs');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
|
|
8
|
-
function mkDir(prefix) {
|
|
9
|
-
|
|
8
|
+
function mkDir(t, prefix) {
|
|
9
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
10
|
+
t.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
11
|
+
return dir;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
// ── readBinaryVersion ──
|
|
13
15
|
|
|
14
|
-
test('readBinaryVersion returns version from valid binary', () => {
|
|
16
|
+
test('readBinaryVersion returns version from valid binary', (t) => {
|
|
15
17
|
const { readBinaryVersion } = require('./version-utils');
|
|
16
|
-
const dir = mkDir('vu-');
|
|
18
|
+
const dir = mkDir(t, 'vu-');
|
|
17
19
|
const bin = path.join(dir, 'code-graph-mcp');
|
|
18
20
|
fs.writeFileSync(bin, [
|
|
19
21
|
'#!/usr/bin/env bash',
|
|
@@ -32,9 +34,9 @@ test('readBinaryVersion returns null for non-existent binary', () => {
|
|
|
32
34
|
assert.equal(readBinaryVersion('/tmp/does-not-exist-binary'), null);
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
test('readBinaryVersion returns null for binary with unexpected output', () => {
|
|
37
|
+
test('readBinaryVersion returns null for binary with unexpected output', (t) => {
|
|
36
38
|
const { readBinaryVersion } = require('./version-utils');
|
|
37
|
-
const dir = mkDir('vu-');
|
|
39
|
+
const dir = mkDir(t, 'vu-');
|
|
38
40
|
const bin = path.join(dir, 'code-graph-mcp');
|
|
39
41
|
fs.writeFileSync(bin, '#!/usr/bin/env bash\necho "something else"');
|
|
40
42
|
fs.chmodSync(bin, 0o755);
|
|
@@ -56,9 +58,9 @@ test('getNewestMtime returns 0 for non-existent directory', () => {
|
|
|
56
58
|
assert.equal(getNewestMtime('/tmp/no-such-dir-xyz'), 0);
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
test('getNewestMtime finds newest .rs file mtime', () => {
|
|
61
|
+
test('getNewestMtime finds newest .rs file mtime', (t) => {
|
|
60
62
|
const { getNewestMtime } = require('./version-utils');
|
|
61
|
-
const dir = mkDir('vu-mtime-');
|
|
63
|
+
const dir = mkDir(t, 'vu-mtime-');
|
|
62
64
|
const sub = path.join(dir, 'sub');
|
|
63
65
|
fs.mkdirSync(sub);
|
|
64
66
|
|
|
@@ -75,9 +77,9 @@ test('getNewestMtime finds newest .rs file mtime', () => {
|
|
|
75
77
|
assert.equal(result, newerMtime, 'should return exactly the newest file mtime');
|
|
76
78
|
});
|
|
77
79
|
|
|
78
|
-
test('getNewestMtime ignores non-matching extensions', () => {
|
|
80
|
+
test('getNewestMtime ignores non-matching extensions', (t) => {
|
|
79
81
|
const { getNewestMtime } = require('./version-utils');
|
|
80
|
-
const dir = mkDir('vu-ext-');
|
|
82
|
+
const dir = mkDir(t, 'vu-ext-');
|
|
81
83
|
fs.writeFileSync(path.join(dir, 'file.js'), 'hello');
|
|
82
84
|
assert.equal(getNewestMtime(dir, '.rs'), 0);
|
|
83
85
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
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": {
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"node": ">=16"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@sdsrs/code-graph-linux-x64": "0.8.
|
|
38
|
-
"@sdsrs/code-graph-linux-arm64": "0.8.
|
|
39
|
-
"@sdsrs/code-graph-darwin-x64": "0.8.
|
|
40
|
-
"@sdsrs/code-graph-darwin-arm64": "0.8.
|
|
41
|
-
"@sdsrs/code-graph-win32-x64": "0.8.
|
|
37
|
+
"@sdsrs/code-graph-linux-x64": "0.8.4",
|
|
38
|
+
"@sdsrs/code-graph-linux-arm64": "0.8.4",
|
|
39
|
+
"@sdsrs/code-graph-darwin-x64": "0.8.4",
|
|
40
|
+
"@sdsrs/code-graph-darwin-arm64": "0.8.4",
|
|
41
|
+
"@sdsrs/code-graph-win32-x64": "0.8.4"
|
|
42
42
|
}
|
|
43
43
|
}
|