@sdsrs/code-graph 0.5.25 → 0.5.27

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,6 +4,12 @@
4
4
  "author": {
5
5
  "name": "sdsrs"
6
6
  },
7
- "version": "0.5.25",
8
- "keywords": ["code-graph", "ast", "navigation", "mcp", "knowledge-graph"]
7
+ "version": "0.5.27",
8
+ "keywords": [
9
+ "code-graph",
10
+ "ast",
11
+ "navigation",
12
+ "mcp",
13
+ "knowledge-graph"
14
+ ]
9
15
  }
@@ -10,8 +10,9 @@ const { CACHE_DIR, PLUGIN_ID, MARKETPLACE_NAME, readManifest, readJson, writeJso
10
10
  const GITHUB_REPO = 'sdsrss/code-graph-mcp';
11
11
  const NPM_PACKAGE = '@sdsrs/code-graph';
12
12
  const STATE_FILE = path.join(CACHE_DIR, 'update-state.json');
13
- const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24h
14
- const RATE_LIMIT_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6h if rate-limited
13
+ const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6h (GitHub allows 60 req/h unauthenticated)
14
+ const RATE_LIMIT_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24h if rate-limited
15
+ const POST_UPDATE_INTERVAL_MS = 1 * 60 * 60 * 1000; // 1h after update (verify success)
15
16
  const FETCH_TIMEOUT_MS = 3000;
16
17
 
17
18
  // ── State Persistence ──────────────────────────────────────
@@ -42,7 +43,9 @@ function isDevMode() {
42
43
  function shouldCheck(state) {
43
44
  if (!state.lastCheck) return true;
44
45
  const elapsed = Date.now() - new Date(state.lastCheck).getTime();
45
- const interval = state.rateLimited ? RATE_LIMIT_INTERVAL_MS : CHECK_INTERVAL_MS;
46
+ let interval = CHECK_INTERVAL_MS;
47
+ if (state.rateLimited) interval = RATE_LIMIT_INTERVAL_MS;
48
+ else if (state.pendingBinaryUpdate) interval = POST_UPDATE_INTERVAL_MS;
46
49
  return elapsed >= interval;
47
50
  }
48
51
 
@@ -154,14 +157,18 @@ async function downloadAndInstall(latest) {
154
157
  } catch { /* manifest update failed — not fatal */ }
155
158
 
156
159
  // 6. Update npm binary (non-blocking, best-effort)
160
+ let binaryUpdated = false;
157
161
  try {
158
162
  execFileSync('npm', ['install', '-g', `${NPM_PACKAGE}@${latest.version}`], {
159
163
  timeout: 60000,
160
164
  stdio: 'pipe',
161
165
  });
166
+ binaryUpdated = true;
167
+ // Clear pending flag on success
168
+ try { const s = readState(); delete s.pendingBinaryUpdate; saveState(s); } catch { /* ok */ }
162
169
  } catch {
163
- // npm install failed plugin files still updated
164
- // User can manually update binary later
170
+ // npm package may not be published yet (race with CI). Record for retry.
171
+ try { const s = readState(); s.pendingBinaryUpdate = latest.version; saveState(s); } catch { /* ok */ }
165
172
  }
166
173
 
167
174
  return true;
@@ -6,10 +6,31 @@ const path = require('path');
6
6
  const os = require('os');
7
7
  const { findBinary } = require('./find-binary');
8
8
  const { install, update, readManifest, getPluginVersion, checkScopeConflict } = require('./lifecycle');
9
- const { checkForUpdate } = require('./auto-update');
9
+ const { checkForUpdate, readState: readUpdateState } = require('./auto-update');
10
10
 
11
11
  let BIN = findBinary();
12
12
 
13
+ // --- 0b. Retry pending binary update from previous failed auto-update ---
14
+ {
15
+ const updateState = readUpdateState();
16
+ if (updateState.pendingBinaryUpdate) {
17
+ const pendingVer = updateState.pendingBinaryUpdate;
18
+ try {
19
+ execFileSync('npm', ['install', '-g', `@sdsrs/code-graph@${pendingVer}`], {
20
+ timeout: 30000, stdio: 'pipe'
21
+ });
22
+ try { fs.unlinkSync(path.join(os.homedir(), '.cache', 'code-graph', 'binary-path')); } catch {}
23
+ // Clear pending flag
24
+ const { writeJsonAtomic, CACHE_DIR } = require('./lifecycle');
25
+ const s = readUpdateState();
26
+ delete s.pendingBinaryUpdate;
27
+ writeJsonAtomic(path.join(CACHE_DIR, 'update-state.json'), s);
28
+ process.stderr.write(`[code-graph] Binary retry succeeded: v${pendingVer}\n`);
29
+ BIN = findBinary(); // refresh
30
+ } catch { /* npm still not available — will retry next session */ }
31
+ }
32
+ }
33
+
13
34
  // --- 0. Auto-install binary if missing ---
14
35
  if (!BIN) {
15
36
  const version = getPluginVersion();
@@ -34,6 +55,7 @@ if (!BIN) {
34
55
  }
35
56
 
36
57
  // --- 1. Health check (always runs) ---
58
+ let healthNodes = -1;
37
59
  if (BIN) {
38
60
  try {
39
61
  const out = execFileSync(BIN, ['health-check', '--format', 'oneline'], {
@@ -41,9 +63,38 @@ if (BIN) {
41
63
  stdio: ['pipe', 'pipe', 'pipe']
42
64
  }).toString().trim();
43
65
  if (out) process.stdout.write(out);
66
+ // Parse node count for empty-index detection
67
+ const m = out.match(/(\d+)\s*nodes/);
68
+ if (m) healthNodes = parseInt(m[1], 10);
44
69
  } catch { /* timeout — silent */ }
45
70
  }
46
71
 
72
+ // --- 1a. Auto-index empty databases (fallback if MCP hasn't triggered indexing) ---
73
+ if (BIN && healthNodes === 0) {
74
+ const dbExists = fs.existsSync(path.join(process.cwd(), '.code-graph', 'index.db'));
75
+ if (dbExists) {
76
+ // DB exists but empty — MCP server likely hasn't received notifications/initialized yet.
77
+ // Trigger CLI indexing as fallback so the index is ready before first tool call.
78
+ try {
79
+ process.stderr.write('[code-graph] Empty index detected, running initial indexing...\n');
80
+ const result = execFileSync(BIN, ['incremental-index', '--quiet'], {
81
+ timeout: 15000, // 15s max (SessionStart hook has 20s budget)
82
+ stdio: ['pipe', 'pipe', 'pipe'],
83
+ }).toString().trim();
84
+ if (result) process.stderr.write(`[code-graph] ${result}\n`);
85
+ // Re-run health check to update statusline with new counts
86
+ try {
87
+ const out2 = execFileSync(BIN, ['health-check', '--format', 'oneline'], {
88
+ timeout: 2000, stdio: ['pipe', 'pipe', 'pipe']
89
+ }).toString().trim();
90
+ if (out2) process.stdout.write(`\n${out2}`);
91
+ } catch { /* ok */ }
92
+ } catch (e) {
93
+ process.stderr.write(`[code-graph] Auto-index failed: ${e.message || e}\n`);
94
+ }
95
+ }
96
+ }
97
+
47
98
  // --- 1b. Suggest project_map as first action ---
48
99
  if (BIN) {
49
100
  process.stdout.write(
@@ -66,6 +117,7 @@ if (BIN) {
66
117
  (pv[0] === bv[0] && pv[1] === bv[1] && pv[2] > bv[2]);
67
118
  if (pluginNewer) {
68
119
  process.stderr.write(`[code-graph] Binary v${binVersion} < plugin v${pluginVersion}, updating...\n`);
120
+ let binarySynced = false;
69
121
  try {
70
122
  execFileSync('npm', ['install', '-g', `@sdsrs/code-graph@${pluginVersion}`], {
71
123
  timeout: 30000, stdio: 'pipe'
@@ -73,11 +125,19 @@ if (BIN) {
73
125
  // Clear cached binary path so next lookup finds the new binary
74
126
  try { fs.unlinkSync(path.join(os.homedir(), '.cache', 'code-graph', 'binary-path')); } catch {}
75
127
  process.stderr.write(`[code-graph] Binary updated to v${pluginVersion}\n`);
128
+ binarySynced = true;
76
129
  } catch {
77
130
  process.stderr.write(
78
131
  `[code-graph] Auto-update failed. Run: npm install -g @sdsrs/code-graph@${pluginVersion}\n`
79
132
  );
80
133
  }
134
+ if (binarySynced) {
135
+ // MCP server is still running old binary — prompt user to reconnect
136
+ process.stdout.write(
137
+ `\n\u26A0\uFE0F [code-graph] Binary updated v${binVersion} \u2192 v${pluginVersion}. ` +
138
+ `Run /mcp to reconnect MCP server with new version.\n`
139
+ );
140
+ }
81
141
  }
82
142
  }
83
143
  } catch { /* version check failed — not critical */ }
@@ -107,6 +167,10 @@ if (!manifest.version) {
107
167
  const result = await checkForUpdate();
108
168
  if (result && result.updated) {
109
169
  process.stderr.write(`[code-graph] Updated: v${result.from} \u2192 v${result.to}\n`);
170
+ process.stdout.write(
171
+ `\n\uD83D\uDD04 [code-graph] Auto-updated v${result.from} \u2192 v${result.to}. ` +
172
+ `Run /mcp to use the new version.\n`
173
+ );
110
174
  } else if (result && result.updateAvailable) {
111
175
  process.stderr.write(
112
176
  `[code-graph] Update available: v${result.from} \u2192 v${result.to}. ` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdsrs/code-graph",
3
- "version": "0.5.25",
3
+ "version": "0.5.27",
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": {
@@ -33,10 +33,10 @@
33
33
  "node": ">=16"
34
34
  },
35
35
  "optionalDependencies": {
36
- "@sdsrs/code-graph-linux-x64": "0.5.25",
37
- "@sdsrs/code-graph-linux-arm64": "0.5.25",
38
- "@sdsrs/code-graph-darwin-x64": "0.5.25",
39
- "@sdsrs/code-graph-darwin-arm64": "0.5.25",
40
- "@sdsrs/code-graph-win32-x64": "0.5.25"
36
+ "@sdsrs/code-graph-linux-x64": "0.5.27",
37
+ "@sdsrs/code-graph-linux-arm64": "0.5.27",
38
+ "@sdsrs/code-graph-darwin-x64": "0.5.27",
39
+ "@sdsrs/code-graph-darwin-arm64": "0.5.27",
40
+ "@sdsrs/code-graph-win32-x64": "0.5.27"
41
41
  }
42
42
  }