@sdsrs/code-graph 0.24.0 → 0.24.1

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.24.0",
7
+ "version": "0.24.1",
8
8
  "keywords": [
9
9
  "code-graph",
10
10
  "ast",
@@ -33,9 +33,16 @@ function readAdoptedBy(filePath) {
33
33
  // scratch dirs, mixed repos). Per-type variants live in `buildIndexLine` and
34
34
  // are computed per-cwd at adopt + needsRefresh time. Adopted-project receives
35
35
  // the typed variant; everyone else falls back to this canonical line.
36
+ // Tags MUST be ≥4 chars and topic-specific (per claudemd §11-EXT Tag-specificity).
37
+ // Generic single-word English tags (impact / refs / overview / semantic / deps /
38
+ // trace / route / similar) substring-match release-notes / commit-message prose
39
+ // via the §11 read-the-file hook regex (word-boundary + 0–2 declension chars),
40
+ // producing false-positive denies. Each tag below aligns with its MCP tool name
41
+ // (impact_analysis / find_references / module_overview / …) so hyphenated literals
42
+ // never collide with natural prose.
36
43
  const INDEX_LINE =
37
44
  '- [code-graph-mcp](plugin_code_graph_mcp.md) ' +
38
- '[impact, callgraph, refs, overview, semantic, ast-search, dead-code, similar, deps, trace] — ' +
45
+ '[impact-analysis, callgraph, find-references, module-overview, semantic-search, ast-search, dead-code, find-similar-code, dependency-graph, trace-http-chain] — ' +
39
46
  '改 X 影响面/谁调用 X/X 被谁用/看 X 源码/Y 模块长啥样/概念查询 优先于 Grep;字面匹配走 Grep。' +
40
47
  '核心 7(get_call_graph/module_overview/semantic_code_search/ast_search/find_references/get_ast_node/project_map)' +
41
48
  '+ 进阶 5(impact_analysis/trace_http_chain/dependency_graph/find_similar_code/find_dead_code),决策表见全文';
@@ -235,12 +242,12 @@ function buildIndexLine(projectType = 'generic') {
235
242
  case 'web-py':
236
243
  case 'web-go':
237
244
  return prefix +
238
- '[trace, route, callgraph, impact, refs, overview, semantic, deps] — ' +
245
+ '[trace-http-chain, http-route, callgraph, impact-analysis, find-references, module-overview, semantic-search, dependency-graph] — ' +
239
246
  'HTTP 路由→handler 链路用 trace_http_chain(或 get_call_graph route_path=);改 handler 影响面用 impact;' +
240
247
  '其他结构化查询同上 优先于 Grep。' + coreSuffix;
241
248
  case 'frontend':
242
249
  return prefix +
243
- '[refs, overview, semantic, callgraph, impact, ast-search] — ' +
250
+ '[find-references, module-overview, semantic-search, callgraph, impact-analysis, ast-search] — ' +
244
251
  '组件重命名/重构用 find_references(含 imports/inherits);模块层级用 module_overview;' +
245
252
  '改 props/接口前用 impact 看下游;HTTP route 通常不适用。' + coreSuffix;
246
253
  case 'rust':
@@ -248,7 +255,7 @@ function buildIndexLine(projectType = 'generic') {
248
255
  case 'python':
249
256
  case 'node':
250
257
  return prefix +
251
- '[callgraph, impact, refs, overview, semantic, ast-search, dead-code, deps] — ' +
258
+ '[callgraph, impact-analysis, find-references, module-overview, semantic-search, ast-search, dead-code, dependency-graph] — ' +
252
259
  '改 X 影响面/谁调用 X/Y 模块 优先于 Grep;HTTP route 追踪通常不适用(无 web 框架);' +
253
260
  '字面匹配走 Grep。' + coreSuffix;
254
261
  case 'generic':
@@ -648,7 +648,7 @@ test('buildIndexLine generic returns the canonical INDEX_LINE byte-for-byte', ()
648
648
 
649
649
  test('buildIndexLine web-rs prepends route/trace tags + handler-focused lead', () => {
650
650
  const line = buildIndexLine('web-rs');
651
- assert.match(line, /\[trace, route,/, 'web-rs index line should lead with trace/route tags');
651
+ assert.match(line, /\[trace-http-chain, http-route,/, 'web-rs index line should lead with trace-http-chain/http-route tags');
652
652
  assert.match(line, /HTTP 路由/, 'lead sentence should mention HTTP routes');
653
653
  });
654
654
 
@@ -675,6 +675,57 @@ test('adopt + needsRefresh agree on typed INDEX_LINE — no spurious refresh in
675
675
  } finally { sb.cleanup(); }
676
676
  });
677
677
 
678
+ test('stale INDEX_LINE → adopt rewrites in place without duplicating sentinel blocks', () => {
679
+ // Regression for the v0.24+ tag-rename fix (feedback_adoption_tag_specificity).
680
+ // If a user's MEMORY.md was written by an older code-graph-mcp (pre-rename),
681
+ // SessionStart → maybeAutoAdopt → needsRefresh must detect the drift,
682
+ // stripSentinelBlock must locate the old v1 block by sentinel marker, and
683
+ // the rewrite must end with exactly one BEGIN/END pair. Breaks if anyone
684
+ // bumps SENTINEL_BEGIN without teaching stripSentinelBlock to also match
685
+ // the prior version — would leave an orphan v1 block plus a new v2 block.
686
+ const sb = makeSandbox();
687
+ try {
688
+ fs.writeFileSync(path.join(sb.cwd, 'Cargo.toml'), '[package]\nname="x"\n');
689
+ // Plant pre-rename MEMORY.md: well-formed v1 sentinel + an obsolete tag
690
+ // line that no current buildIndexLine variant produces. Exact prior bytes
691
+ // don't matter — only that it differs from today's desiredBlock.
692
+ const stalePayload =
693
+ '- [code-graph-mcp](plugin_code_graph_mcp.md) [obsolete-tag, another-stale] — stale lead sentence kept for drift detection.';
694
+ const indexPath = path.join(sb.dir, 'MEMORY.md');
695
+ const neighbor = '- [user_profile.md](user_profile.md) — neighbor (must survive)';
696
+ fs.writeFileSync(
697
+ indexPath,
698
+ `# Memory Index\n\n${neighbor}\n\n${SENTINEL_BEGIN}\n${stalePayload}\n${SENTINEL_END}\n`
699
+ );
700
+ // Plant target file so isAdopted/needsRefresh treat this as a real prior
701
+ // adoption (body bytewise-identical to shipped template — drift is only
702
+ // in MEMORY.md, not the template body).
703
+ const tplBody = fs.readFileSync(TEMPLATE_PATH);
704
+ const marker = Buffer.from(`<!-- adopted-by: ${sb.cwd} -->\n`);
705
+ fs.writeFileSync(path.join(sb.dir, TARGET_NAME), Buffer.concat([marker, tplBody]));
706
+
707
+ assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), true,
708
+ 'precondition: planted state should look adopted');
709
+ assert.strictEqual(needsRefresh({ cwd: sb.cwd, home: sb.home }), true,
710
+ 'tag-list drift must trigger refresh');
711
+
712
+ adopt({ cwd: sb.cwd, home: sb.home });
713
+
714
+ const after = fs.readFileSync(indexPath, 'utf8');
715
+ const escBegin = SENTINEL_BEGIN.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
716
+ const escEnd = SENTINEL_END.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
717
+ const beginHits = (after.match(new RegExp(escBegin, 'g')) || []).length;
718
+ const endHits = (after.match(new RegExp(escEnd, 'g')) || []).length;
719
+ assert.strictEqual(beginHits, 1, 'exactly one sentinel BEGIN after rewrite (no duplicate blocks)');
720
+ assert.strictEqual(endHits, 1, 'exactly one sentinel END after rewrite');
721
+ assert.ok(!after.includes('obsolete-tag'), 'stale tag list must be gone');
722
+ assert.ok(!after.includes('another-stale'), 'stale tag list must be gone');
723
+ assert.ok(after.includes(neighbor), 'neighbor entry preserved');
724
+ assert.strictEqual(needsRefresh({ cwd: sb.cwd, home: sb.home }), false,
725
+ 'post-refresh needsRefresh must be false (no SessionStart refresh loop)');
726
+ } finally { sb.cleanup(); }
727
+ });
728
+
678
729
  // 2A — false-positive hardening: comment-strip + section-aware scan.
679
730
 
680
731
  test('detectProjectType ignores commented-out web-framework deps in Cargo.toml', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdsrs/code-graph",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
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.24.0",
39
- "@sdsrs/code-graph-linux-arm64": "0.24.0",
40
- "@sdsrs/code-graph-darwin-x64": "0.24.0",
41
- "@sdsrs/code-graph-darwin-arm64": "0.24.0",
42
- "@sdsrs/code-graph-win32-x64": "0.24.0"
38
+ "@sdsrs/code-graph-linux-x64": "0.24.1",
39
+ "@sdsrs/code-graph-linux-arm64": "0.24.1",
40
+ "@sdsrs/code-graph-darwin-x64": "0.24.1",
41
+ "@sdsrs/code-graph-darwin-arm64": "0.24.1",
42
+ "@sdsrs/code-graph-win32-x64": "0.24.1"
43
43
  }
44
44
  }