@sdsrs/code-graph 0.56.0 → 0.56.2
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: code-explorer
|
|
3
3
|
description: Deep code understanding expert using AST knowledge graph. Use when exploring unfamiliar code, tracing complex relationships, or understanding module architecture.
|
|
4
|
-
tools: ["Read", "Grep", "Glob", "Bash", "mcp__code-graph__semantic_code_search", "mcp__code-graph__get_call_graph", "mcp__code-graph__get_ast_node", "mcp__code-
|
|
4
|
+
tools: ["Read", "Grep", "Glob", "Bash", "mcp__code-graph__semantic_code_search", "mcp__code-graph__get_call_graph", "mcp__code-graph__get_ast_node", "mcp__code-graph__project_map", "mcp__code-graph__module_overview", "mcp__code-graph__ast_search", "mcp__code-graph__find_references"]
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -9,10 +9,10 @@ You are a code exploration specialist with access to an AST knowledge graph.
|
|
|
9
9
|
|
|
10
10
|
## Strategy
|
|
11
11
|
|
|
12
|
-
1. **Start with semantic_code_search** to locate relevant code by meaning
|
|
13
|
-
2. **Use get_call_graph** to understand function relationships and call chains
|
|
14
|
-
3. **Use get_ast_node** to get symbol metadata,
|
|
15
|
-
4. **Use
|
|
12
|
+
1. **Start with semantic_code_search** to locate relevant code by meaning, or **module_overview** / **project_map** to map an unfamiliar directory or the whole repo
|
|
13
|
+
2. **Use get_call_graph** to understand function relationships and call chains (pass `route_path='GET /api/x'` to trace an HTTP handler downstream)
|
|
14
|
+
3. **Use get_ast_node** to get symbol metadata, source, and callers/callees (`context_lines` for surrounding source, `include_impact` for blast radius)
|
|
15
|
+
4. **Use find_references** for rename/remove audits and **ast_search** to enumerate symbols by type / return / params
|
|
16
16
|
5. **Fall back to Grep/Read** only when code-graph tools lack coverage (e.g., config files, non-code assets)
|
|
17
17
|
|
|
18
18
|
## Rules
|
|
@@ -141,3 +141,39 @@ test('lifecycle install writes to CLAUDE_CONFIG_DIR instead of ~/.claude when se
|
|
|
141
141
|
'default ~/.claude/settings.json must not be written when override is set');
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
test('composite expands a leading ~ in a _previous command instead of dropping it (issue #24)', (t) => {
|
|
145
|
+
// A user whose prior statusline used a leading ~ (valid in settings.json, which
|
|
146
|
+
// Claude Code runs through a shell). install() captures it verbatim as _previous.
|
|
147
|
+
// The composite runs providers via execFileSync (no shell), so without tilde
|
|
148
|
+
// expansion the command throws ENOENT and is silently swallowed — the user's
|
|
149
|
+
// original statusline vanishes.
|
|
150
|
+
const homeDir = mkHome(t);
|
|
151
|
+
const prevScript = path.join(homeDir, '.claude', 'utils', 'statusline.sh');
|
|
152
|
+
fs.mkdirSync(path.dirname(prevScript), { recursive: true });
|
|
153
|
+
fs.writeFileSync(prevScript, '#!/bin/sh\necho "PREV-STATUSLINE-OK"\n');
|
|
154
|
+
fs.chmodSync(prevScript, 0o755);
|
|
155
|
+
|
|
156
|
+
const registryPath = path.join(homeDir, '.cache', 'code-graph', 'statusline-registry.json');
|
|
157
|
+
writeJson(registryPath, [
|
|
158
|
+
{ id: '_previous', command: '~/.claude/utils/statusline.sh', needsStdin: true },
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
const out = runScript(homeDir, compositeCli, [], { input: '{}' });
|
|
162
|
+
assert.match(out, /PREV-STATUSLINE-OK/,
|
|
163
|
+
'a _previous command using a leading ~ must be tilde-expanded, not silently dropped');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('expandTilde mirrors shell tilde expansion (only a leading ~ / ~/)', () => {
|
|
167
|
+
const composite = require('./statusline-composite');
|
|
168
|
+
const home = os.homedir();
|
|
169
|
+
assert.equal(composite.expandTilde('~'), home);
|
|
170
|
+
assert.equal(composite.expandTilde('~/.claude/utils/statusline.sh'),
|
|
171
|
+
path.join(home, '.claude', 'utils', 'statusline.sh'));
|
|
172
|
+
assert.equal(composite.expandTilde('/abs/path/script.sh'), '/abs/path/script.sh');
|
|
173
|
+
assert.equal(composite.expandTilde('node'), 'node');
|
|
174
|
+
assert.equal(composite.expandTilde('~user/script.sh'), '~user/script.sh',
|
|
175
|
+
'other-user home dirs are not resolved');
|
|
176
|
+
assert.equal(composite.expandTilde('a~/b'), 'a~/b',
|
|
177
|
+
'only a leading ~ expands, not a mid-string ~');
|
|
178
|
+
});
|
|
179
|
+
|
|
@@ -7,22 +7,28 @@
|
|
|
7
7
|
*/
|
|
8
8
|
const { execFileSync } = require('child_process');
|
|
9
9
|
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
10
11
|
const lifecycle = require('./lifecycle');
|
|
11
12
|
const { readRegistry } = lifecycle;
|
|
12
13
|
const cleanupDisabledStatusline = lifecycle.cleanupDisabledStatusline || (() => ({ cleaned: false }));
|
|
13
14
|
|
|
14
15
|
const SEPARATOR = ' \x1b[2m|\x1b[0m ';
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
function main() {
|
|
18
|
+
const disabledCleanup = cleanupDisabledStatusline();
|
|
19
|
+
if (disabledCleanup.cleaned) process.exit(0);
|
|
18
20
|
|
|
19
|
-
// Collect stdin (Claude Code pipes JSON context)
|
|
20
|
-
let stdinData = '';
|
|
21
|
-
let ran = false;
|
|
22
|
-
const stdinTimeout = setTimeout(() => { if (!ran) { ran = true; run(''); } }, 2000);
|
|
23
|
-
process.stdin.setEncoding('utf8');
|
|
24
|
-
process.stdin.on('data', (chunk) => { stdinData += chunk; });
|
|
25
|
-
process.stdin.on('end', () => { clearTimeout(stdinTimeout); if (!ran) { ran = true; run(stdinData); } });
|
|
21
|
+
// Collect stdin (Claude Code pipes JSON context)
|
|
22
|
+
let stdinData = '';
|
|
23
|
+
let ran = false;
|
|
24
|
+
const stdinTimeout = setTimeout(() => { if (!ran) { ran = true; run(''); } }, 2000);
|
|
25
|
+
process.stdin.setEncoding('utf8');
|
|
26
|
+
process.stdin.on('data', (chunk) => { stdinData += chunk; });
|
|
27
|
+
process.stdin.on('end', () => { clearTimeout(stdinTimeout); if (!ran) { ran = true; run(stdinData); } });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Only run the statusline when invoked as a CLI; `require()` (tests) just imports helpers.
|
|
31
|
+
if (require.main === module) main();
|
|
26
32
|
|
|
27
33
|
function run(stdin) {
|
|
28
34
|
const registry = readRegistry();
|
|
@@ -58,7 +64,14 @@ function runProvider(command, needsStdin, stdin) {
|
|
|
58
64
|
const parts = parseCommand(command);
|
|
59
65
|
if (!parts) return null;
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
// Claude Code runs statusLine.command through a shell, so a leading `~`
|
|
68
|
+
// (e.g. `~/.claude/utils/statusline.sh`) is expanded natively. execFileSync
|
|
69
|
+
// does NOT use a shell, so we must expand `~/` ourselves on every word —
|
|
70
|
+
// otherwise a `_previous` command captured verbatim throws ENOENT and gets
|
|
71
|
+
// swallowed below, silently dropping the user's original statusline.
|
|
72
|
+
const argv = parts.map(expandTilde);
|
|
73
|
+
|
|
74
|
+
const out = execFileSync(argv[0], argv.slice(1), {
|
|
62
75
|
timeout: 3000,
|
|
63
76
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
64
77
|
input: needsStdin ? stdin : '',
|
|
@@ -81,9 +94,19 @@ function parseCommand(cmd) {
|
|
|
81
94
|
return parts.length > 0 ? parts : null;
|
|
82
95
|
}
|
|
83
96
|
|
|
97
|
+
// Expand a leading `~` / `~/` to the home directory, mirroring shell tilde
|
|
98
|
+
// expansion (which Claude Code applies when it runs statusLine.command, but
|
|
99
|
+
// execFileSync does not). Only a bare `~` or a `~/`-prefixed word is expanded;
|
|
100
|
+
// `~user` and mid-string `~` are left untouched (we don't resolve other users).
|
|
101
|
+
function expandTilde(p) {
|
|
102
|
+
if (p === '~') return os.homedir();
|
|
103
|
+
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
|
|
104
|
+
return p;
|
|
105
|
+
}
|
|
106
|
+
|
|
84
107
|
function codeGraphCommand() {
|
|
85
108
|
// Always derive from __dirname — CLAUDE_PLUGIN_ROOT can leak from other plugins
|
|
86
109
|
return `node "${path.join(__dirname, 'statusline.js')}"`;
|
|
87
110
|
}
|
|
88
111
|
|
|
89
|
-
module.exports = { run };
|
|
112
|
+
module.exports = { run, runProvider, parseCommand, expandTilde };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.56.
|
|
3
|
+
"version": "0.56.2",
|
|
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.56.
|
|
39
|
-
"@sdsrs/code-graph-linux-arm64": "0.56.
|
|
40
|
-
"@sdsrs/code-graph-darwin-x64": "0.56.
|
|
41
|
-
"@sdsrs/code-graph-darwin-arm64": "0.56.
|
|
42
|
-
"@sdsrs/code-graph-win32-x64": "0.56.
|
|
38
|
+
"@sdsrs/code-graph-linux-x64": "0.56.2",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.56.2",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.56.2",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.56.2",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.56.2"
|
|
43
43
|
}
|
|
44
44
|
}
|