@sdsrs/code-graph 0.104.1 → 0.106.0

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/README.md CHANGED
@@ -367,6 +367,39 @@ lazily on first use. To control that in a restricted environment:
367
367
  | `CODE_GRAPH_MODEL_DIR=<dir>` | Load `model.safetensors` from `<dir>` instead of downloading (highest-priority lookup). If the file isn't there, it warns and falls back to the normal search paths. |
368
368
  | `CODE_GRAPH_DISABLE_MODEL_DOWNLOAD=1` | Disable the automatic background model download. An already-cached model is still loaded and used; the server otherwise stays in FTS5-only mode. |
369
369
 
370
+ ### Installing the model by hand
371
+
372
+ `CODE_GRAPH_MODEL_DIR` is the supported manual route. Hand-populating the
373
+ *default* cache dir (`<platform cache>/code-graph/models`) does **not** work:
374
+ that dir is only trusted once `extract_and_promote` has written a `.model-id`
375
+ marker, so a manually filled copy is treated as not-current and re-downloaded.
376
+
377
+ ```bash
378
+ # Download + verify against the published checksum, then extract flat
379
+ # (the archive has no wrapping folder: model.safetensors, tokenizer.json, config.json).
380
+ curl -sL -o models.tar.gz \
381
+ https://github.com/sdsrss/code-graph-mcp/releases/download/v<version>/models.tar.gz
382
+ curl -sL https://github.com/sdsrss/code-graph-mcp/releases/download/v<version>/models.tar.gz.sha256
383
+ sha256sum -c models.tar.gz.sha256
384
+ mkdir -p ~/.cache/code-graph/models-manual
385
+ tar -xzf models.tar.gz -C ~/.cache/code-graph/models-manual
386
+ export CODE_GRAPH_MODEL_DIR=~/.cache/code-graph/models-manual
387
+ ```
388
+
389
+ On Windows use `%LOCALAPPDATA%\code-graph\models-manual`, and give `tar` a POSIX
390
+ path for `-C` (`/c/Users/<you>/...`) — `tar -C C:\...` fails with
391
+ "Cannot connect to C: resolve failed". The model is pinned by content hash, so
392
+ a manual install must be redone on each version bump.
393
+
394
+ ### Diagnosing a model that never downloads
395
+
396
+ `code-graph-mcp doctor` reports the last download outcome, distinguishing
397
+ "no download has been attempted" from "download FAILED after N attempt(s): …"
398
+ with the underlying error. The raw record is
399
+ `<platform cache>/code-graph/model-download.json`. On a network that performs
400
+ TLS inspection, the download retries automatically against the OS certificate
401
+ store after the bundled roots are rejected.
402
+
370
403
  ## Storage
371
404
 
372
405
  Uses SQLite with:
@@ -4,7 +4,7 @@
4
4
  "author": {
5
5
  "name": "sdsrs"
6
6
  },
7
- "version": "0.104.1",
7
+ "version": "0.106.0",
8
8
  "keywords": [
9
9
  "code-graph",
10
10
  "ast",
@@ -34,8 +34,15 @@ function classifyEmbeddings(hc) {
34
34
  return { name: 'Embeddings', status: 'ok', detail: 'no embeddable nodes' };
35
35
  }
36
36
  if (!done) {
37
+ // `model_download` carries the LAST recorded download outcome (issue #35).
38
+ // Without it this printed the same optimistic "retry shortly" on every run,
39
+ // so a machine whose download can never succeed read as "be patient"
40
+ // forever instead of "this is broken". Absent field = never attempted,
41
+ // which is itself a distinct diagnosis, not a reason to advise waiting.
37
42
  const why = (hc && hc.embedding_status === 'pending')
38
- ? 'model not downloaded/loaded yet — auto-downloads in background on first search; retry shortly or restart the MCP server'
43
+ ? (hc.model_download
44
+ ? `last model download: ${hc.model_download}`
45
+ : 'model not loaded and NO download has ever been attempted on this machine — restart the MCP server, or set CODE_GRAPH_MODEL_DIR to a manually populated model dir (see README → Offline usage)')
39
46
  : `embedding_status=${(hc && hc.embedding_status) || 'unknown'}`;
40
47
  return { name: 'Embeddings', status: 'warn',
41
48
  detail: `vector INACTIVE — ${total} embeddable nodes, 0 embedded; semantic search is FTS5-only (${why})` };
@@ -21,15 +21,46 @@ const MARKER = '<!-- code-graph-impact-review -->';
21
21
  const SPAWN_TIMEOUT_MS = 60_000;
22
22
  const TOP_AFFECTED = 15;
23
23
 
24
- /// File-level test classifier — mirrors `domain::is_test_path` (Rust). Kept in
25
- /// sync deliberately; see feedback_test_classifier_dual_sources.md.
24
+ /// Constant lists mirroring `domain::PASCAL_TEST_*` / `INFIX_TEST_EXTS`. Both
25
+ /// sides are generated from their lists rather than transcribed, so adding an
26
+ /// ecosystem is one edit here and one in domain.rs — not a hunt through
27
+ /// hand-written boolean chains.
28
+ const PASCAL_TEST_EXTS = ['cs', 'vb', 'fs', 'java', 'kt', 'scala', 'swift', 'php'];
29
+ const PASCAL_TEST_STEMS = ['Test', 'Tests', 'Spec'];
30
+ const INFIX_TEST_EXTS = ['go', 'rs', 'py', 'dart'];
31
+
32
+ /// File-level test classifier — mirrors `domain::is_test_path` (Rust). This is
33
+ /// one of several deliberately-synchronized copies; `domain.rs` carries the
34
+ /// "Five sites must agree" note, and two of those sites are intentionally
35
+ /// divergent. Widening only the Rust side breaks the parity contract asserted
36
+ /// by `isTestPath mirrors domain::is_test_path patterns` in the test file, and
37
+ /// makes the "test gaps" section report every Java/C# test as uncovered
38
+ /// production code.
26
39
  function isTestPath(p) {
40
+ // Case-insensitive `test`/`tests` DIRECTORY segment at any depth: xUnit/NUnit
41
+ // put suites under `src/Tests/<Project>/…` and Maven/Gradle under
42
+ // `src/test/java/…` (issue #36). Note `toLowerCase()` is Unicode-aware where
43
+ // Rust uses `to_ascii_lowercase()`; they agree on ASCII paths.
44
+ const lower = p.toLowerCase();
45
+ if (
46
+ lower.startsWith('tests/') || lower.startsWith('test/') ||
47
+ lower.includes('/tests/') || lower.includes('/test/')
48
+ ) return true;
49
+ // PascalCase test-class convention. Case-SENSITIVE and pinned to a known
50
+ // extension so `src/latest.cs` and `src/mytests.rs` stay production.
51
+ if (PASCAL_TEST_STEMS.some((stem) => PASCAL_TEST_EXTS.some((ext) => p.endsWith(`${stem}.${ext}`)))) {
52
+ return true;
53
+ }
54
+ if (INFIX_TEST_EXTS.some((ext) => p.endsWith(`_test.${ext}`))) return true;
55
+ // pytest naming conventions.
56
+ if (lower.endsWith('.py') &&
57
+ (lower.startsWith('test_') || lower.includes('/test_') || lower.endsWith('conftest.py'))) {
58
+ return true;
59
+ }
27
60
  return (
28
- p.startsWith('tests/') || p.startsWith('test/') ||
29
61
  p.startsWith('benches/') || p.startsWith('bench/') ||
30
62
  p.includes('__tests__/') ||
31
63
  p.endsWith('/tests.rs') ||
32
- p.endsWith('_test.go') || p.endsWith('_test.rs') ||
33
64
  p.endsWith('.test.ts') || p.endsWith('.test.js') ||
34
65
  p.endsWith('.test.tsx') || p.endsWith('.test.jsx') ||
35
66
  p.endsWith('.spec.ts') || p.endsWith('.spec.js') ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdsrs/code-graph",
3
- "version": "0.104.1",
3
+ "version": "0.106.0",
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": {
@@ -36,10 +36,10 @@
36
36
  "node": ">=16"
37
37
  },
38
38
  "optionalDependencies": {
39
- "@sdsrs/code-graph-linux-x64": "0.104.1",
40
- "@sdsrs/code-graph-linux-arm64": "0.104.1",
41
- "@sdsrs/code-graph-darwin-x64": "0.104.1",
42
- "@sdsrs/code-graph-darwin-arm64": "0.104.1",
43
- "@sdsrs/code-graph-win32-x64": "0.104.1"
39
+ "@sdsrs/code-graph-linux-x64": "0.106.0",
40
+ "@sdsrs/code-graph-linux-arm64": "0.106.0",
41
+ "@sdsrs/code-graph-darwin-x64": "0.106.0",
42
+ "@sdsrs/code-graph-darwin-arm64": "0.106.0",
43
+ "@sdsrs/code-graph-win32-x64": "0.106.0"
44
44
  }
45
45
  }