@sdsrs/code-graph 0.116.0 → 0.117.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 +19 -15
- package/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/scripts/adopt.js +210 -50
- package/claude-plugin/scripts/auto-update.js +88 -6
- package/claude-plugin/scripts/doctor.js +110 -1
- package/claude-plugin/scripts/hook-emit.js +37 -9
- package/claude-plugin/scripts/lifecycle.js +169 -28
- package/claude-plugin/scripts/pr-impact-comment.js +33 -1
- package/claude-plugin/scripts/pre-edit-guide.js +16 -8
- package/claude-plugin/scripts/proc-opts.js +15 -0
- package/claude-plugin/scripts/session-init.js +44 -2
- package/claude-plugin/scripts/statusline-chain.js +17 -1
- package/claude-plugin/scripts/statusline-composite.js +3 -0
- package/claude-plugin/scripts/statusline.js +3 -0
- package/claude-plugin/templates/code-graph-snapshot.yml +8 -3
- package/claude-plugin/templates/plugin_code_graph_mcp.md +14 -6
- package/package.json +6 -6
|
@@ -609,7 +609,36 @@ function runSessionInit({ source } = {}) {
|
|
|
609
609
|
// 上下文感知默认:插件模式下首次 SessionStart 自动安装(创建/注入 CLAUDE.md 块 +
|
|
610
610
|
// .claude/ detail 文件),并清理旧 memory-dir 制品(升级自动迁移)。shipped 漂移
|
|
611
611
|
// 时刷新。三种情况发一次 stderr 提示,让用户知道发生了什么 + 如何回退。
|
|
612
|
-
|
|
612
|
+
// Adoption is OPTIONAL; the rest of this hook is not. It touches files the
|
|
613
|
+
// user owns (CLAUDE.md, .claude/) which can be unreadable, a directory, or on
|
|
614
|
+
// a read-only mount — and a throw here used to abort every remaining step
|
|
615
|
+
// (map injection, recent impact, consistency check, both hook canaries) with a
|
|
616
|
+
// raw stack trace (audit 2026-08-16 P1-16). adopt() now returns reasons rather
|
|
617
|
+
// than throwing; this is the belt to that suspenders, so a future unguarded
|
|
618
|
+
// read inside it cannot take the session down again.
|
|
619
|
+
let autoAdopt = { attempted: false, result: null };
|
|
620
|
+
if (!isRelic) {
|
|
621
|
+
try {
|
|
622
|
+
autoAdopt = maybeAutoAdopt({ scriptPath: __dirname });
|
|
623
|
+
} catch (e) {
|
|
624
|
+
autoAdopt = { attempted: true, reason: 'threw', result: null, error: (e && e.message) || String(e) };
|
|
625
|
+
process.stderr.write(
|
|
626
|
+
`[code-graph] Skipped CLAUDE.md adoption for this project (${(e && e.code) || (e && e.message) || 'unknown error'}).\n` +
|
|
627
|
+
' Everything else in this session start continues normally.\n'
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (autoAdopt.result && autoAdopt.result.ok === false &&
|
|
632
|
+
(autoAdopt.result.reason === 'claude-md-unreadable' || autoAdopt.result.reason === 'claude-md-unwritable' ||
|
|
633
|
+
autoAdopt.result.reason === 'detail-unwritable')) {
|
|
634
|
+
// A refusal is not a silent no-op: the user's steering block is NOT
|
|
635
|
+
// installed/refreshed, and only this line says so.
|
|
636
|
+
process.stderr.write(
|
|
637
|
+
`[code-graph] Could not install the CLAUDE.md steering block (${autoAdopt.result.reason}: ` +
|
|
638
|
+
`${autoAdopt.result.error || 'unknown'}). Nothing was changed.\n` +
|
|
639
|
+
' Opt out permanently: CODE_GRAPH_NO_AUTO_ADOPT=1\n'
|
|
640
|
+
);
|
|
641
|
+
}
|
|
613
642
|
const migrated = autoAdopt.migrated || {};
|
|
614
643
|
if (migrated.memoryIndexPruned || migrated.legacyDetailRemoved) {
|
|
615
644
|
process.stderr.write(
|
|
@@ -889,5 +918,18 @@ if (require.main === module) {
|
|
|
889
918
|
source = JSON.parse(fs.readFileSync(0, 'utf8')).source;
|
|
890
919
|
}
|
|
891
920
|
} catch { /* no/garbled stdin → treat as unknown source */ }
|
|
892
|
-
|
|
921
|
+
// Hooks FAIL OPEN. This one had no wrapper at all, so anything unhandled
|
|
922
|
+
// anywhere in the sequence surfaced as a node stack trace plus a non-zero exit
|
|
923
|
+
// in the user's session start — for work that is entirely optional
|
|
924
|
+
// housekeeping (audit 2026-08-16 P1-16). One `[code-graph]` line, exit 0.
|
|
925
|
+
try {
|
|
926
|
+
runSessionInit({ source });
|
|
927
|
+
} catch (e) {
|
|
928
|
+
process.stderr.write(
|
|
929
|
+
`[code-graph] SessionStart hook error (${(e && e.code) || (e && e.name) || 'Error'}): ` +
|
|
930
|
+
`${(e && e.message) || String(e)}\n` +
|
|
931
|
+
' The session continues; run `code-graph-mcp doctor` if this repeats.\n'
|
|
932
|
+
);
|
|
933
|
+
process.exit(0);
|
|
934
|
+
}
|
|
893
935
|
}
|
|
@@ -16,7 +16,21 @@
|
|
|
16
16
|
// (this plugin's own provider). Third parties should use stable ids like
|
|
17
17
|
// "gsd", "claude-mem", etc.
|
|
18
18
|
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
readRegistry, readRegistryForWrite, registerStatuslineProvider, unregisterStatuslineProvider,
|
|
21
|
+
} = require('./lifecycle');
|
|
22
|
+
|
|
23
|
+
// A registry that EXISTS but cannot be read is a refusal, not a no-op: the
|
|
24
|
+
// mutation functions leave it alone (they must — it holds the user's previous
|
|
25
|
+
// statusline and other plugins' entries), which would otherwise surface here as
|
|
26
|
+
// the cheerful "unchanged <id>" / "not-found <id>" at exit 0. A third-party
|
|
27
|
+
// installer reading that exit code would believe it is wired in.
|
|
28
|
+
function bailIfRegistryUnusable(action) {
|
|
29
|
+
const { refuse, why } = readRegistryForWrite();
|
|
30
|
+
if (!refuse) return;
|
|
31
|
+
process.stderr.write(`error: ${why} — nothing ${action}. Repair or move that file aside and retry.\n`);
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
20
34
|
|
|
21
35
|
function usage(code = 1) {
|
|
22
36
|
process.stderr.write(
|
|
@@ -34,12 +48,14 @@ function runRegister(id, command, needsStdin) {
|
|
|
34
48
|
process.exit(2);
|
|
35
49
|
}
|
|
36
50
|
if (!id || !command) usage();
|
|
51
|
+
bailIfRegistryUnusable('registered');
|
|
37
52
|
const changed = registerStatuslineProvider(id, command, needsStdin);
|
|
38
53
|
process.stdout.write(changed ? `registered ${id}\n` : `unchanged ${id}\n`);
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
function runUnregister(id) {
|
|
42
57
|
if (!id) usage();
|
|
58
|
+
bailIfRegistryUnusable('unregistered');
|
|
43
59
|
const changed = unregisterStatuslineProvider(id);
|
|
44
60
|
process.stdout.write(changed ? `unregistered ${id}\n` : `not-found ${id}\n`);
|
|
45
61
|
}
|
|
@@ -89,6 +89,9 @@ function runProvider(command, needsStdin, stdin) {
|
|
|
89
89
|
|
|
90
90
|
const out = execFileSync(argv[0], argv.slice(1), hidden({
|
|
91
91
|
timeout: 3000,
|
|
92
|
+
// SIGKILL, not the SIGTERM default: a provider that traps SIGTERM makes
|
|
93
|
+
// Node's timeout unreachable and hangs every render (audit P1-17).
|
|
94
|
+
killSignal: 'SIGKILL',
|
|
92
95
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
93
96
|
input: needsStdin ? stdin : '',
|
|
94
97
|
env,
|
|
@@ -187,6 +187,9 @@ try {
|
|
|
187
187
|
// "slow health-check" into a rendered "offline"/"updating" instead of a blank.
|
|
188
188
|
report = parseReport(execFileSync(bin, ['health-check', '--format', 'json'], hidden({
|
|
189
189
|
timeout: 1500,
|
|
190
|
+
// Render hot path: a wedged binary ignoring SIGTERM must not outlive the
|
|
191
|
+
// budget (same reasoning as the composite's provider spawn, audit P1-17).
|
|
192
|
+
killSignal: 'SIGKILL',
|
|
190
193
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
191
194
|
// Run the binary FROM the resolved root so its own project-root resolution
|
|
192
195
|
// lands on the same DB the gate above picked (a subdir cwd would otherwise
|
|
@@ -22,15 +22,20 @@ jobs:
|
|
|
22
22
|
permissions:
|
|
23
23
|
contents: write
|
|
24
24
|
steps:
|
|
25
|
-
-
|
|
25
|
+
# SHA-pinned, not `@v4`: a floating major tag is mutable, so anyone who can
|
|
26
|
+
# move it runs their code in a job that holds `contents: write` on your
|
|
27
|
+
# repo. These are the same commits code-graph-mcp's own workflows pin.
|
|
28
|
+
# Update by copying a new SHA from the action's release page, not by
|
|
29
|
+
# switching back to a tag.
|
|
30
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
26
31
|
with:
|
|
27
32
|
fetch-depth: 0
|
|
28
|
-
- uses: actions/setup-node@
|
|
33
|
+
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
|
29
34
|
with:
|
|
30
35
|
node-version: '20'
|
|
31
36
|
- name: Build snapshot
|
|
32
37
|
run: |
|
|
33
|
-
npx -y -p @sdsrs/code-graph@0.
|
|
38
|
+
npx -y -p @sdsrs/code-graph@0.117.0 code-graph-mcp snapshot create --out snapshot.db
|
|
34
39
|
zstd -9 snapshot.db -o snapshot.db.zst
|
|
35
40
|
mv snapshot.db.zst "code-graph-snapshot-${GITHUB_SHA:0:7}.db.zst"
|
|
36
41
|
- name: Upload to release
|
|
@@ -35,8 +35,12 @@ type: reference
|
|
|
35
35
|
> - `module_overview include_deps=true` / `include_dead=true`
|
|
36
36
|
> - `get_call_graph route_path="GET /api/x"`
|
|
37
37
|
>
|
|
38
|
-
>
|
|
39
|
-
>
|
|
38
|
+
> `impact_analysis` **已删除**——dispatcher 里没有这个 arm,按名调用返回
|
|
39
|
+
> `Unknown tool`。改用 `get_ast_node include_impact=true`,或 CLI `impact`。
|
|
40
|
+
> 其余旧名(`read_snippet` / `dependency_graph` / `find_similar_code` /
|
|
41
|
+
> `find_dead_code` / `trace_http_chain` + alias `find_http_route`)仍是向后兼容
|
|
42
|
+
> dispatcher 别名(raw JSON-RPC / SDK 脚本场景),但 Claude Code 内一律用上面的
|
|
43
|
+
> 新 flag 形式。CLI 子命令
|
|
40
44
|
> (`code-graph-mcp impact|similar|deps|dead-code|trace`)保持不变,给 Bash 工作流。
|
|
41
45
|
|
|
42
46
|
## 何时调用 MCP/CLI(替代多步 Grep/Read)
|
|
@@ -73,10 +77,14 @@ type: reference
|
|
|
73
77
|
### 旧名兼容 + CLI 速查(v0.18.4 fold 后)
|
|
74
78
|
|
|
75
79
|
v0.18.4 把原"进阶 5"折叠进核心 7 的 flag。**Claude Code 内**首选上表的新 flag 形式。
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
|
|
81
|
+
可按名调用的只有这 7 个:`project_map` / `semantic_code_search` / `get_call_graph` /
|
|
82
|
+
`get_ast_node` / `module_overview` / `ast_search` / `find_references`。
|
|
83
|
+
`impact_analysis` **不在其列,已从 dispatcher 删除**——按名调用返回 `Unknown tool`。
|
|
84
|
+
隐藏旧名 `read_snippet` / `dependency_graph` / `find_similar_code` / `find_dead_code` /
|
|
85
|
+
`trace_http_chain`(+ alias `find_http_route`)仍有 dispatcher arm,raw JSON-RPC / MCP
|
|
86
|
+
SDK / 既有脚本不破;但它们不在 `tools/list`,Claude Code 的 ToolSearch 不为其加载
|
|
87
|
+
schema —— 实操中一律走新 flag。CLI 子命令保持原样:
|
|
80
88
|
|
|
81
89
|
| 意图 | CLI(Bash 工作流) | 等价 MCP 新形式 |
|
|
82
90
|
|------|--------------------|------------------|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.117.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": {
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"node": ">=16"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@sdsrs/code-graph-linux-x64": "0.
|
|
39
|
-
"@sdsrs/code-graph-linux-arm64": "0.
|
|
40
|
-
"@sdsrs/code-graph-darwin-x64": "0.
|
|
41
|
-
"@sdsrs/code-graph-darwin-arm64": "0.
|
|
42
|
-
"@sdsrs/code-graph-win32-x64": "0.
|
|
38
|
+
"@sdsrs/code-graph-linux-x64": "0.117.0",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.117.0",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.117.0",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.117.0",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.117.0"
|
|
43
43
|
}
|
|
44
44
|
}
|