@sdsrs/code-graph 0.56.0 → 0.56.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.
|
@@ -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.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.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.1",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.56.1",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.56.1",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.56.1",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.56.1"
|
|
43
43
|
}
|
|
44
44
|
}
|