@codragraph/cli 1.6.2 → 1.6.4
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 +16 -16
- package/dist/cli/ai-context.js +2 -2
- package/dist/cli/analyze.js +4 -4
- package/dist/cli/index.js +1 -4
- package/dist/cli/setup.js +53 -18
- package/dist/cli/skill-gen.js +1 -1
- package/dist/config/ignore-service.js +1 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +1 -12
- package/dist/core/ingestion/call-processor.js +2 -2
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
- package/dist/core/ingestion/cobol/jcl-parser.d.ts +1 -1
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol-processor.d.ts +1 -1
- package/dist/core/ingestion/cobol-processor.js +1 -1
- package/dist/core/ingestion/heritage-extractors/generic.js +1 -1
- package/dist/core/ingestion/heritage-processor.js +1 -1
- package/dist/core/ingestion/import-processor.js +1 -1
- package/dist/core/ingestion/mro-processor.js +1 -1
- package/dist/core/ingestion/parsing-processor.js +1 -1
- package/dist/core/ingestion/type-extractors/c-cpp.js +1 -1
- package/dist/core/ingestion/type-extractors/python.js +1 -1
- package/dist/core/ingestion/type-extractors/shared.js +0 -3
- package/dist/core/lbug/lbug-adapter.js +4 -4
- package/dist/core/lbug/pool-adapter.js +51 -44
- package/dist/core/search/bm25-index.js +90 -1
- package/dist/core/wiki/generator.js +4 -4
- package/dist/mcp/resources.js +2 -3
- package/hooks/claude/codragraph-hook.cjs +13 -3
- package/hooks/claude/pre-tool-use.sh +6 -1
- package/package.json +4 -4
- package/skills/codragraph-cli.md +5 -5
- package/skills/codragraph-debugging.md +1 -1
- package/skills/codragraph-exploring.md +1 -1
- package/skills/codragraph-guide.md +1 -1
- package/skills/codragraph-impact-analysis.md +1 -1
- package/skills/codragraph-pr-review.md +1 -1
- package/skills/codragraph-refactoring.md +1 -1
package/README.md
CHANGED
|
@@ -18,12 +18,12 @@ AI coding tools don't understand your codebase structure. They edit a function w
|
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
# Index your repo (run from repo root)
|
|
21
|
-
npx codragraph analyze
|
|
21
|
+
npx @codragraph/cli analyze
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
That's it. This indexes the codebase, installs agent skills, registers Claude Code hooks, and creates `AGENTS.md` / `CLAUDE.md` context files — all in one command.
|
|
25
25
|
|
|
26
|
-
To configure MCP for your editor, run `npx codragraph setup` once — or set it up manually below.
|
|
26
|
+
To configure MCP for your editor, run `npx @codragraph/cli setup` once — or set it up manually below.
|
|
27
27
|
|
|
28
28
|
`codragraph setup` auto-detects your editors and writes the correct global MCP config. You only need to run it once.
|
|
29
29
|
|
|
@@ -53,16 +53,16 @@ If you prefer to configure manually instead of using `codragraph setup`:
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
# macOS / Linux
|
|
56
|
-
claude mcp add codragraph -- npx -y codragraph@latest mcp
|
|
56
|
+
claude mcp add codragraph -- npx -y @codragraph/cli@latest mcp
|
|
57
57
|
|
|
58
58
|
# Windows
|
|
59
|
-
claude mcp add codragraph -- cmd /c npx -y codragraph@latest mcp
|
|
59
|
+
claude mcp add codragraph -- cmd /c npx -y @codragraph/cli@latest mcp
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
### Codex (full support — MCP + skills)
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
codex mcp add codragraph -- npx -y codragraph@latest mcp
|
|
65
|
+
codex mcp add codragraph -- npx -y @codragraph/cli@latest mcp
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
### Cursor / Windsurf
|
|
@@ -74,7 +74,7 @@ Add to `~/.cursor/mcp.json` (global — works for all projects):
|
|
|
74
74
|
"mcpServers": {
|
|
75
75
|
"codragraph": {
|
|
76
76
|
"command": "npx",
|
|
77
|
-
"args": ["-y", "codragraph@latest", "mcp"]
|
|
77
|
+
"args": ["-y", "@codragraph/cli@latest", "mcp"]
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
@@ -89,7 +89,7 @@ Add to `~/.config/opencode/config.json`:
|
|
|
89
89
|
"mcp": {
|
|
90
90
|
"codragraph": {
|
|
91
91
|
"command": "npx",
|
|
92
|
-
"args": ["-y", "codragraph@latest", "mcp"]
|
|
92
|
+
"args": ["-y", "@codragraph/cli@latest", "mcp"]
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -244,9 +244,9 @@ merges are skipped.)
|
|
|
244
244
|
|
|
245
245
|
```bash
|
|
246
246
|
# Try the latest release candidate (pre-stable — may change at any time)
|
|
247
|
-
npm install -g codragraph@rc
|
|
247
|
+
npm install -g @codragraph/cli@rc
|
|
248
248
|
# — or —
|
|
249
|
-
npx codragraph@rc analyze
|
|
249
|
+
npx @codragraph/cli@rc analyze
|
|
250
250
|
```
|
|
251
251
|
|
|
252
252
|
Release-candidate versions follow the standard semver prerelease format
|
|
@@ -265,9 +265,9 @@ certain npm/arborist versions ([npm/cli#8126](https://github.com/npm/cli/issues/
|
|
|
265
265
|
It is fixed in **codragraph v1.6.2+**. Upgrade to the latest version:
|
|
266
266
|
|
|
267
267
|
```bash
|
|
268
|
-
npx codragraph@latest analyze # always uses the newest release
|
|
268
|
+
npx @codragraph/cli@latest analyze # always uses the newest release
|
|
269
269
|
# — or —
|
|
270
|
-
npm install -g codragraph@latest # upgrade a global install
|
|
270
|
+
npm install -g @codragraph/cli@latest # upgrade a global install
|
|
271
271
|
```
|
|
272
272
|
|
|
273
273
|
If you still hit npm install issues after upgrading, these generic workarounds
|
|
@@ -282,7 +282,7 @@ npm cache clean --force # clear a possibly corrupt cache
|
|
|
282
282
|
|
|
283
283
|
Some optional language grammars (Dart, Kotlin, Swift) require native compilation. If they fail, CodraGraph still works — those languages will be skipped.
|
|
284
284
|
|
|
285
|
-
If `npm install -g codragraph` fails on native modules:
|
|
285
|
+
If `npm install -g @codragraph/cli` fails on native modules:
|
|
286
286
|
|
|
287
287
|
```bash
|
|
288
288
|
# Ensure build tools are available (Linux/macOS)
|
|
@@ -290,7 +290,7 @@ If `npm install -g codragraph` fails on native modules:
|
|
|
290
290
|
# macOS: xcode-select --install
|
|
291
291
|
|
|
292
292
|
# Retry installation
|
|
293
|
-
npm install -g codragraph
|
|
293
|
+
npm install -g @codragraph/cli
|
|
294
294
|
```
|
|
295
295
|
|
|
296
296
|
### Analysis runs out of memory
|
|
@@ -299,7 +299,7 @@ For very large repositories:
|
|
|
299
299
|
|
|
300
300
|
```bash
|
|
301
301
|
# Increase Node.js heap size
|
|
302
|
-
NODE_OPTIONS="--max-old-space-size=16384" npx codragraph analyze
|
|
302
|
+
NODE_OPTIONS="--max-old-space-size=16384" npx @codragraph/cli analyze
|
|
303
303
|
|
|
304
304
|
# Exclude large directories
|
|
305
305
|
echo "vendor/" >> .codragraphignore
|
|
@@ -312,11 +312,11 @@ By default the walker skips files larger than **512 KB** (see log line `Skipped
|
|
|
312
312
|
|
|
313
313
|
```bash
|
|
314
314
|
# CLI flag (takes precedence over the env var)
|
|
315
|
-
npx codragraph analyze --max-file-size 2048 # skip only files > 2 MB
|
|
315
|
+
npx @codragraph/cli analyze --max-file-size 2048 # skip only files > 2 MB
|
|
316
316
|
|
|
317
317
|
# Environment variable (persists across commands)
|
|
318
318
|
export CODRAGRAPH_MAX_FILE_SIZE=2048
|
|
319
|
-
npx codragraph analyze
|
|
319
|
+
npx @codragraph/cli analyze
|
|
320
320
|
```
|
|
321
321
|
|
|
322
322
|
Values above **32768 KB (32 MB)** are clamped to the tree-sitter parser ceiling; invalid values fall back to the 512 KB default with a one-time warning. When an override is active, `analyze` prints the effective threshold in its startup banner (e.g. `CODRAGRAPH_MAX_FILE_SIZE: effective threshold 2048KB (default 512KB)`).
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -86,7 +86,7 @@ function generateCodraGraphContent(projectName, stats, generatedSkills, groupNam
|
|
|
86
86
|
|
|
87
87
|
This project is indexed by CodraGraph as **${projectName}**${noStats ? '' : ` (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows)`}. Use the CodraGraph MCP tools to understand code, assess impact, and navigate safely.
|
|
88
88
|
|
|
89
|
-
> If any CodraGraph tool warns the index is stale, run \`npx codragraph analyze\` in terminal first.
|
|
89
|
+
> If any CodraGraph tool warns the index is stale, run \`npx @codragraph/cli analyze\` in terminal first.
|
|
90
90
|
|
|
91
91
|
## Always Do
|
|
92
92
|
|
|
@@ -115,7 +115,7 @@ This project is indexed by CodraGraph as **${projectName}**${noStats ? '' : ` ($
|
|
|
115
115
|
${groupNames && groupNames.length > 0
|
|
116
116
|
? `## Cross-Repo Groups
|
|
117
117
|
|
|
118
|
-
This repository is listed under CodraGraph **group(s): ${groupNames.join(', ')}** (see \`~/.codragraph/groups/\`). For cross-repo analysis, use MCP tools \`impact\`, \`query\`, and \`context\` with \`repo\` set to \`@<groupName>\` or \`@<groupName>/<memberPath>\` (paths match keys in that group’s \`group.yaml\`). Use \`group_list\` / \`group_sync\` for membership and sync. From the terminal: \`npx codragraph group list\`, \`npx codragraph group sync <name>\`, \`npx codragraph group impact <name> --target <symbol> --repo <group-path>\`.
|
|
118
|
+
This repository is listed under CodraGraph **group(s): ${groupNames.join(', ')}** (see \`~/.codragraph/groups/\`). For cross-repo analysis, use MCP tools \`impact\`, \`query\`, and \`context\` with \`repo\` set to \`@<groupName>\` or \`@<groupName>/<memberPath>\` (paths match keys in that group’s \`group.yaml\`). Use \`group_list\` / \`group_sync\` for membership and sync. From the terminal: \`npx @codragraph/cli group list\`, \`npx @codragraph/cli group sync <name>\`, \`npx @codragraph/cli group impact <name> --target <symbol> --repo <group-path>\`.
|
|
119
119
|
|
|
120
120
|
`
|
|
121
121
|
: ''}## CLI
|
package/dist/cli/analyze.js
CHANGED
|
@@ -289,8 +289,8 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
289
289
|
console.error(' Suggestions:');
|
|
290
290
|
console.error(' 1. Clear the npm cache: npm cache clean --force');
|
|
291
291
|
console.error(' 2. Update npm: npm install -g npm@latest');
|
|
292
|
-
console.error(' 3. Reinstall codragraph: npm install -g codragraph@latest');
|
|
293
|
-
console.error(' 4. Or try npx directly: npx codragraph@latest analyze');
|
|
292
|
+
console.error(' 3. Reinstall codragraph: npm install -g @codragraph/cli@latest');
|
|
293
|
+
console.error(' 4. Or try npx directly: npx @codragraph/cli@latest analyze');
|
|
294
294
|
console.error('');
|
|
295
295
|
}
|
|
296
296
|
else if (msg.includes('MODULE_NOT_FOUND') ||
|
|
@@ -298,8 +298,8 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
298
298
|
msg.includes('ERR_MODULE_NOT_FOUND')) {
|
|
299
299
|
console.error(' A required module could not be loaded. The installation may be corrupt.');
|
|
300
300
|
console.error(' Suggestions:');
|
|
301
|
-
console.error(' 1. Reinstall: npm install -g codragraph@latest');
|
|
302
|
-
console.error(' 2. Clear cache: npm cache clean --force && npx codragraph@latest analyze');
|
|
301
|
+
console.error(' 1. Reinstall: npm install -g @codragraph/cli@latest');
|
|
302
|
+
console.error(' 2. Clear cache: npm cache clean --force && npx @codragraph/cli@latest analyze');
|
|
303
303
|
console.error('');
|
|
304
304
|
}
|
|
305
305
|
process.exitCode = 1;
|
package/dist/cli/index.js
CHANGED
|
@@ -8,10 +8,7 @@ import { registerGroupCommands } from './group.js';
|
|
|
8
8
|
const _require = createRequire(import.meta.url);
|
|
9
9
|
const pkg = _require('../../package.json');
|
|
10
10
|
const program = new Command();
|
|
11
|
-
program
|
|
12
|
-
.name('@codragraph/cli')
|
|
13
|
-
.description('CodraGraph local CLI and MCP server')
|
|
14
|
-
.version(pkg.version);
|
|
11
|
+
program.name('codragraph').description('CodraGraph local CLI and MCP server').version(pkg.version);
|
|
15
12
|
program
|
|
16
13
|
.command('setup')
|
|
17
14
|
.description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode, Codex')
|
package/dist/cli/setup.js
CHANGED
|
@@ -18,20 +18,38 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
18
18
|
const __dirname = path.dirname(__filename);
|
|
19
19
|
const execFileAsync = promisify(execFile);
|
|
20
20
|
/**
|
|
21
|
-
* Resolve the absolute path to the
|
|
21
|
+
* Resolve the absolute path to the `codragraph` binary if it's installed
|
|
22
22
|
* globally (or via npm -g / yarn global). Returns null when not found.
|
|
23
|
+
*
|
|
24
|
+
* Note: the npm package is `@codragraph/cli`, but the executable it installs
|
|
25
|
+
* is `codragraph` (see package.json `bin`). PATH lookup must use the bin name.
|
|
26
|
+
*
|
|
27
|
+
* Windows specifics: `where codragraph` returns every PATH entry, in order:
|
|
28
|
+
* the extensionless Unix shim npm creates first (a sh script — Node's
|
|
29
|
+
* spawn/execFile cannot launch it on Windows), then `codragraph.cmd`,
|
|
30
|
+
* then `codragraph.ps1`. We must pick the .cmd / .exe / .bat entry; writing
|
|
31
|
+
* the extensionless path into a downstream MCP config produces a launcher
|
|
32
|
+
* that fails on every spawn.
|
|
23
33
|
*/
|
|
24
34
|
function resolveCodragraphBin() {
|
|
25
35
|
try {
|
|
26
36
|
const cmd = process.platform === 'win32' ? 'where' : 'which';
|
|
27
|
-
const
|
|
37
|
+
const stdout = execFileSync(cmd, ['codragraph'], {
|
|
28
38
|
encoding: 'utf-8',
|
|
29
39
|
timeout: 5000,
|
|
30
40
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
.
|
|
34
|
-
|
|
41
|
+
});
|
|
42
|
+
const lines = stdout
|
|
43
|
+
.split('\n')
|
|
44
|
+
.map((l) => l.trim())
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
if (process.platform === 'win32') {
|
|
47
|
+
// Prefer a Windows-executable shim. If none is on PATH, return null so
|
|
48
|
+
// the caller falls through to the `cmd /c npx -y @codragraph/cli` path.
|
|
49
|
+
const exe = lines.find((l) => /\.(cmd|exe|bat)$/i.test(l));
|
|
50
|
+
return exe ?? null;
|
|
51
|
+
}
|
|
52
|
+
return lines[0] ?? null;
|
|
35
53
|
}
|
|
36
54
|
catch {
|
|
37
55
|
return null;
|
|
@@ -40,28 +58,38 @@ function resolveCodragraphBin() {
|
|
|
40
58
|
/**
|
|
41
59
|
* The MCP server entry for all editors.
|
|
42
60
|
*
|
|
43
|
-
* Prefers the globally-installed
|
|
44
|
-
* `npx -y codragraph@latest` (cold-cache install of native deps can take
|
|
61
|
+
* Prefers the globally-installed `codragraph` binary (starts in ~1 s) over
|
|
62
|
+
* `npx -y @codragraph/cli@latest` (cold-cache install of native deps can take
|
|
45
63
|
* >60 s, exceeding Claude Code's 30 s MCP connection timeout).
|
|
46
64
|
*
|
|
47
65
|
* Falls back to npx when the binary isn't on PATH — e.g. first-time
|
|
48
|
-
* users who ran `npx codragraph analyze` but haven't done `npm i -g`.
|
|
66
|
+
* users who ran `npx @codragraph/cli analyze` but haven't done `npm i -g`.
|
|
67
|
+
*
|
|
68
|
+
* Windows note: even when the bin is on PATH, we launch via `cmd /c codragraph
|
|
69
|
+
* mcp` rather than writing the resolved path. Reason: `where codragraph`
|
|
70
|
+
* returns the extensionless Unix shim before `codragraph.cmd`, and Node's
|
|
71
|
+
* spawn/execFile cannot launch the extensionless shim on Windows. Letting
|
|
72
|
+
* cmd resolve via PATHEXT is the only reliable path that works for npm-,
|
|
73
|
+
* pnpm-, and yarn-installed shims alike.
|
|
49
74
|
*/
|
|
50
75
|
function getMcpEntry() {
|
|
51
76
|
const bin = resolveCodragraphBin();
|
|
52
77
|
if (bin) {
|
|
78
|
+
if (process.platform === 'win32') {
|
|
79
|
+
return { command: 'cmd', args: ['/c', 'codragraph', 'mcp'] };
|
|
80
|
+
}
|
|
53
81
|
return { command: bin, args: ['mcp'] };
|
|
54
82
|
}
|
|
55
83
|
// Fallback: npx (works without a global install, but slow cold-start)
|
|
56
84
|
if (process.platform === 'win32') {
|
|
57
85
|
return {
|
|
58
86
|
command: 'cmd',
|
|
59
|
-
args: ['/c', 'npx', '-y', 'codragraph@latest', 'mcp'],
|
|
87
|
+
args: ['/c', 'npx', '-y', '@codragraph/cli@latest', 'mcp'],
|
|
60
88
|
};
|
|
61
89
|
}
|
|
62
90
|
return {
|
|
63
91
|
command: 'npx',
|
|
64
|
-
args: ['-y', 'codragraph@latest', 'mcp'],
|
|
92
|
+
args: ['-y', '@codragraph/cli@latest', 'mcp'],
|
|
65
93
|
};
|
|
66
94
|
}
|
|
67
95
|
/**
|
|
@@ -71,12 +99,18 @@ function getMcpEntry() {
|
|
|
71
99
|
function getOpenCodeMcpEntry() {
|
|
72
100
|
const bin = resolveCodragraphBin();
|
|
73
101
|
if (bin) {
|
|
102
|
+
if (process.platform === 'win32') {
|
|
103
|
+
return { type: 'local', command: ['cmd', '/c', 'codragraph', 'mcp'] };
|
|
104
|
+
}
|
|
74
105
|
return { type: 'local', command: [bin, 'mcp'] };
|
|
75
106
|
}
|
|
76
107
|
if (process.platform === 'win32') {
|
|
77
|
-
return {
|
|
108
|
+
return {
|
|
109
|
+
type: 'local',
|
|
110
|
+
command: ['cmd', '/c', 'npx', '-y', '@codragraph/cli@latest', 'mcp'],
|
|
111
|
+
};
|
|
78
112
|
}
|
|
79
|
-
return { type: 'local', command: ['npx', '-y', 'codragraph@latest', 'mcp'] };
|
|
113
|
+
return { type: 'local', command: ['npx', '-y', '@codragraph/cli@latest', 'mcp'] };
|
|
80
114
|
}
|
|
81
115
|
/**
|
|
82
116
|
* Merge codragraph entry into an existing MCP config JSON object.
|
|
@@ -239,7 +273,7 @@ async function installClaudeCodeHooks(result) {
|
|
|
239
273
|
// Source hooks bundled within the codragraph package (hooks/claude/)
|
|
240
274
|
const pluginHooksPath = path.join(__dirname, '..', '..', 'hooks', 'claude');
|
|
241
275
|
// Copy unified hook script to ~/.claude/hooks/codragraph/
|
|
242
|
-
const destHooksDir = path.join(claudeDir, 'hooks', '
|
|
276
|
+
const destHooksDir = path.join(claudeDir, 'hooks', 'codragraph');
|
|
243
277
|
try {
|
|
244
278
|
await fs.mkdir(destHooksDir, { recursive: true });
|
|
245
279
|
const src = path.join(pluginHooksPath, 'codragraph-hook.cjs');
|
|
@@ -291,7 +325,7 @@ async function setupOpenCode(result) {
|
|
|
291
325
|
}
|
|
292
326
|
const configPath = path.join(opencodeDir, 'opencode.json');
|
|
293
327
|
try {
|
|
294
|
-
const ok = await mergeJsoncFile(configPath, ['mcp', '
|
|
328
|
+
const ok = await mergeJsoncFile(configPath, ['mcp', 'codragraph'], getOpenCodeMcpEntry());
|
|
295
329
|
if (ok) {
|
|
296
330
|
result.configured.push('OpenCode');
|
|
297
331
|
}
|
|
@@ -339,9 +373,10 @@ async function setupCodex(result) {
|
|
|
339
373
|
}
|
|
340
374
|
try {
|
|
341
375
|
const entry = getMcpEntry();
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
376
|
+
// On Windows, npm-installed CLIs ship as .cmd shims that Node's execFile
|
|
377
|
+
// can only invoke when the file extension is explicit (no PATHEXT lookup).
|
|
378
|
+
const codexBin = process.platform === 'win32' ? 'codex.cmd' : 'codex';
|
|
379
|
+
await execFileAsync(codexBin, ['mcp', 'add', 'codragraph', '--', entry.command, ...entry.args]);
|
|
345
380
|
result.configured.push('Codex');
|
|
346
381
|
return;
|
|
347
382
|
}
|
package/dist/cli/skill-gen.js
CHANGED
|
@@ -103,7 +103,7 @@ export const generateSkillFiles = async (repoPath, projectName, pipelineResult)
|
|
|
103
103
|
* @param {string} repoPath - Repository root for path normalization
|
|
104
104
|
* @returns {CommunityNode[]} Synthetic community nodes built from membership data
|
|
105
105
|
*/
|
|
106
|
-
const buildCommunitiesFromMemberships = (memberships, graph,
|
|
106
|
+
const buildCommunitiesFromMemberships = (memberships, graph, _repoPath) => {
|
|
107
107
|
// Group memberships by communityId
|
|
108
108
|
const groups = new Map();
|
|
109
109
|
for (const m of memberships) {
|
|
@@ -285,7 +285,7 @@ export const shouldIgnorePath = (filePath) => {
|
|
|
285
285
|
// Ignore hidden files (starting with .)
|
|
286
286
|
if (fileName.startsWith('.') && fileName !== '.') {
|
|
287
287
|
// But allow some important config files
|
|
288
|
-
const
|
|
288
|
+
const _allowedDotFiles = ['.env', '.gitignore']; // Already in IGNORED_FILES, so this is redundant
|
|
289
289
|
// Actually, let's NOT ignore all dot files - many are important configs
|
|
290
290
|
// Just rely on the explicit lists above
|
|
291
291
|
}
|
|
@@ -31,7 +31,6 @@ if (ProtoGrammar) {
|
|
|
31
31
|
// test runners (vitest forks) when SyntaxNode isn't fully initialized
|
|
32
32
|
// yet. Catching that here ensures `PROTO_GRPC_PLUGIN` stays null and
|
|
33
33
|
// the orchestrator falls back to the manual parser.
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
34
|
const _Parser = _require('tree-sitter');
|
|
36
35
|
// Smoke-test: parse + setLanguage to verify the grammar is
|
|
37
36
|
// end-to-end compatible with this tree-sitter runtime.
|
|
@@ -72,24 +71,14 @@ if (ProtoGrammar) {
|
|
|
72
71
|
}
|
|
73
72
|
}
|
|
74
73
|
function buildPlugin() {
|
|
75
|
-
if (!ProtoGrammar || !
|
|
74
|
+
if (!ProtoGrammar || !SERVICE_PATTERNS)
|
|
76
75
|
return null;
|
|
77
|
-
const pkgPatterns = PACKAGE_PATTERNS;
|
|
78
76
|
const svcPatterns = SERVICE_PATTERNS;
|
|
79
77
|
return {
|
|
80
78
|
name: 'proto-grpc',
|
|
81
79
|
language: ProtoGrammar,
|
|
82
80
|
scan(tree) {
|
|
83
81
|
const out = [];
|
|
84
|
-
// Extract `package` declaration (first match wins).
|
|
85
|
-
let pkg = '';
|
|
86
|
-
for (const match of runCompiledPatterns(pkgPatterns, tree)) {
|
|
87
|
-
const pkgNode = match.captures.pkg;
|
|
88
|
-
if (pkgNode) {
|
|
89
|
-
pkg = pkgNode.text;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
82
|
// Extract `service → rpc` pairs. The query returns one match per
|
|
94
83
|
// (service, rpc) combination thanks to the nested structure.
|
|
95
84
|
for (const match of runCompiledPatterns(svcPatterns, tree)) {
|
|
@@ -616,7 +616,7 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
616
616
|
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
617
617
|
});
|
|
618
618
|
}
|
|
619
|
-
catch (
|
|
619
|
+
catch (_parseError) {
|
|
620
620
|
continue;
|
|
621
621
|
}
|
|
622
622
|
astCache.set(file.path, tree);
|
|
@@ -704,7 +704,7 @@ importedRawReturnTypesMap, heritageMap, bindingAccumulator) => {
|
|
|
704
704
|
// loop above, so verifyConstructorBindings sees all provider bindings
|
|
705
705
|
// regardless of file processing order.
|
|
706
706
|
for (let i = 0; i < prepared.length; i++) {
|
|
707
|
-
const { file, language, provider, tree, matches, parentMap, typeEnv } = prepared[i];
|
|
707
|
+
const { file, language, provider, tree: _tree, matches, parentMap, typeEnv } = prepared[i];
|
|
708
708
|
enclosingFnExtractCache.clear();
|
|
709
709
|
onProgress?.(i + 1, files.length);
|
|
710
710
|
if (i % 20 === 0)
|
|
@@ -1404,7 +1404,7 @@ export function extractCobolSymbolsWithRegex(content, _filePath) {
|
|
|
1404
1404
|
if (anonRedefMatch) {
|
|
1405
1405
|
// Check it's truly anonymous: the second capture is not a valid data name
|
|
1406
1406
|
// followed by more clauses — it's the REDEFINES target directly after level
|
|
1407
|
-
const
|
|
1407
|
+
const _level = parseInt(anonRedefMatch[1], 10);
|
|
1408
1408
|
// Only skip if this is genuinely "NN REDEFINES target" with no name between
|
|
1409
1409
|
// We detect this by checking the full data item regex does NOT match
|
|
1410
1410
|
// (because RE_DATA_ITEM expects a name before any clauses)
|
|
@@ -65,4 +65,4 @@ export interface JclParseResults {
|
|
|
65
65
|
* @param filePath - Path for diagnostics (not used in extraction)
|
|
66
66
|
* @returns Parsed JCL results
|
|
67
67
|
*/
|
|
68
|
-
export declare function parseJcl(content: string,
|
|
68
|
+
export declare function parseJcl(content: string, _filePath: string): JclParseResults;
|
|
@@ -73,7 +73,7 @@ function extractDisp(params) {
|
|
|
73
73
|
* @param filePath - Path for diagnostics (not used in extraction)
|
|
74
74
|
* @returns Parsed JCL results
|
|
75
75
|
*/
|
|
76
|
-
export function parseJcl(content,
|
|
76
|
+
export function parseJcl(content, _filePath) {
|
|
77
77
|
const results = {
|
|
78
78
|
jobs: [],
|
|
79
79
|
steps: [],
|
|
@@ -50,5 +50,5 @@ export declare function isJclFile(filePath: string): boolean;
|
|
|
50
50
|
* @param allPathSet - Set of all file paths in the repository
|
|
51
51
|
* @returns Summary of what was extracted
|
|
52
52
|
*/
|
|
53
|
-
export declare const processCobol: (graph: KnowledgeGraph, files: CobolFile[],
|
|
53
|
+
export declare const processCobol: (graph: KnowledgeGraph, files: CobolFile[], _allPathSet: ReadonlySet<string>) => CobolProcessResult;
|
|
54
54
|
export {};
|
|
@@ -47,7 +47,7 @@ function isCopybook(filePath) {
|
|
|
47
47
|
* @param allPathSet - Set of all file paths in the repository
|
|
48
48
|
* @returns Summary of what was extracted
|
|
49
49
|
*/
|
|
50
|
-
export const processCobol = (graph, files,
|
|
50
|
+
export const processCobol = (graph, files, _allPathSet) => {
|
|
51
51
|
const result = {
|
|
52
52
|
programs: 0,
|
|
53
53
|
paragraphs: 0,
|
|
@@ -12,7 +12,7 @@ export function createHeritageExtractor(config) {
|
|
|
12
12
|
const callNameSet = actualConfig.callBasedHeritage?.callNames;
|
|
13
13
|
return {
|
|
14
14
|
language: actualConfig.language,
|
|
15
|
-
extract(captureMap,
|
|
15
|
+
extract(captureMap, _context) {
|
|
16
16
|
const classNode = captureMap['heritage.class'];
|
|
17
17
|
if (!classNode)
|
|
18
18
|
return [];
|
|
@@ -151,7 +151,7 @@ export const processHeritage = async (graph, files, astCache, ctx, onProgress) =
|
|
|
151
151
|
bufferSize: getTreeSitterBufferSize(file.content.length),
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
|
-
catch (
|
|
154
|
+
catch (_parseError) {
|
|
155
155
|
// Skip files that can't be parsed
|
|
156
156
|
continue;
|
|
157
157
|
}
|
|
@@ -316,7 +316,7 @@ function parameterTypesMatch(a, b, aParamCount, bParamCount) {
|
|
|
316
316
|
*/
|
|
317
317
|
function emitMethodImplementsEdges(graph, parentMap, methodMap, parentEdgeType, ancestorsMap, edgeTypesMap) {
|
|
318
318
|
let edgeCount = 0;
|
|
319
|
-
for (const [classId,
|
|
319
|
+
for (const [classId, _parentIds] of parentMap) {
|
|
320
320
|
const classNode = graph.getNode(classId);
|
|
321
321
|
if (!classNode)
|
|
322
322
|
continue;
|
|
@@ -273,7 +273,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
273
273
|
bufferSize: getTreeSitterBufferSize(parseContent.length),
|
|
274
274
|
});
|
|
275
275
|
}
|
|
276
|
-
catch (
|
|
276
|
+
catch (_parseError) {
|
|
277
277
|
console.warn(`Skipping unparseable file: ${file.path}`);
|
|
278
278
|
continue;
|
|
279
279
|
}
|
|
@@ -479,7 +479,7 @@ const inferLiteralType = (node) => {
|
|
|
479
479
|
};
|
|
480
480
|
/** C++: detect constructor type from smart pointer factory calls (make_shared<Dog>()).
|
|
481
481
|
* Extracts the template type argument as the constructor type for virtual dispatch. */
|
|
482
|
-
const detectCppConstructorType = (node,
|
|
482
|
+
const detectCppConstructorType = (node, _classNames) => {
|
|
483
483
|
// Navigate to the initializer value in the declaration
|
|
484
484
|
const declarator = node.childForFieldName('declarator');
|
|
485
485
|
const initDecl = declarator?.type === 'init_declarator' ? declarator : undefined;
|
|
@@ -149,7 +149,7 @@ const scanConstructorBinding = (node) => {
|
|
|
149
149
|
};
|
|
150
150
|
const FOR_LOOP_NODE_TYPES = new Set(['for_statement']);
|
|
151
151
|
/** Python function/method node types that carry a parameters list. */
|
|
152
|
-
const
|
|
152
|
+
const _PY_FUNCTION_NODE_TYPES = new Set(['function_definition', 'decorated_definition']);
|
|
153
153
|
/**
|
|
154
154
|
* Extract element type from a Python type annotation AST node.
|
|
155
155
|
* Handles:
|
|
@@ -564,16 +564,13 @@ export function extractElementTypeFromString(typeStr, pos = 'last') {
|
|
|
564
564
|
const openAngle = typeStr.indexOf('<');
|
|
565
565
|
const openSquare = typeStr.indexOf('[');
|
|
566
566
|
let openIdx = -1;
|
|
567
|
-
let openChar = '';
|
|
568
567
|
let closeChar = '';
|
|
569
568
|
if (openAngle >= 0 && (openSquare < 0 || openAngle < openSquare)) {
|
|
570
569
|
openIdx = openAngle;
|
|
571
|
-
openChar = '<';
|
|
572
570
|
closeChar = '>';
|
|
573
571
|
}
|
|
574
572
|
else if (openSquare >= 0) {
|
|
575
573
|
openIdx = openSquare;
|
|
576
|
-
openChar = '[';
|
|
577
574
|
closeChar = ']';
|
|
578
575
|
}
|
|
579
576
|
if (openIdx < 0)
|
|
@@ -322,7 +322,7 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
322
322
|
try {
|
|
323
323
|
await conn.query(copyQuery);
|
|
324
324
|
}
|
|
325
|
-
catch (
|
|
325
|
+
catch (_err) {
|
|
326
326
|
try {
|
|
327
327
|
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
328
328
|
await conn.query(retryQuery);
|
|
@@ -360,7 +360,7 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
360
360
|
try {
|
|
361
361
|
await conn.query(copyQuery);
|
|
362
362
|
}
|
|
363
|
-
catch (
|
|
363
|
+
catch (_err) {
|
|
364
364
|
try {
|
|
365
365
|
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
366
366
|
await conn.query(retryQuery);
|
|
@@ -671,7 +671,7 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
|
|
|
671
671
|
await tempConn.query(query);
|
|
672
672
|
inserted++;
|
|
673
673
|
}
|
|
674
|
-
catch (
|
|
674
|
+
catch (_e) {
|
|
675
675
|
// Don't console.error here - it corrupts MCP JSON-RPC on stderr
|
|
676
676
|
failed++;
|
|
677
677
|
}
|
|
@@ -991,7 +991,7 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
|
|
|
991
991
|
deletedNodes += count;
|
|
992
992
|
}
|
|
993
993
|
}
|
|
994
|
-
catch (
|
|
994
|
+
catch (_e) {
|
|
995
995
|
// Some tables may not support this query, skip
|
|
996
996
|
}
|
|
997
997
|
}
|
|
@@ -280,29 +280,18 @@ async function doInitLbug(repoId, dbPath) {
|
|
|
280
280
|
finally {
|
|
281
281
|
preWarmActive = false;
|
|
282
282
|
}
|
|
283
|
-
// Load FTS
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// Load VECTOR extension once per shared Database for semantic search support.
|
|
296
|
-
if (!shared.vectorLoaded) {
|
|
297
|
-
try {
|
|
298
|
-
await available[0].query('INSTALL VECTOR');
|
|
299
|
-
await available[0].query('LOAD EXTENSION VECTOR');
|
|
300
|
-
shared.vectorLoaded = true;
|
|
301
|
-
}
|
|
302
|
-
catch {
|
|
303
|
-
// VECTOR extension may not be available
|
|
304
|
-
}
|
|
305
|
-
}
|
|
283
|
+
// Load FTS + VECTOR extensions on EVERY connection in the pool.
|
|
284
|
+
//
|
|
285
|
+
// CRITICAL: LadybugDB's extension state is per-connection on macOS (and
|
|
286
|
+
// possibly other platforms) — loading on `available[0]` does NOT propagate
|
|
287
|
+
// to the other connections. Since checkout pops from the end of the array,
|
|
288
|
+
// queries would otherwise hit unloaded connections and `QUERY_FTS_INDEX`
|
|
289
|
+
// would silently return 0 rows (catch in queryFTSViaExecutor swallows the
|
|
290
|
+
// "extension not loaded" error). That broke every search on macOS.
|
|
291
|
+
//
|
|
292
|
+
// Load on all connections concurrently, but BEFORE the pool is registered
|
|
293
|
+
// so no checkout can race the load.
|
|
294
|
+
await loadExtensionsOnConnections(available, shared);
|
|
306
295
|
// Register pool entry only after all connections are pre-warmed and FTS is
|
|
307
296
|
// loaded. Concurrent executeQuery calls see either "not initialized"
|
|
308
297
|
// (and throw cleanly) or a fully ready pool — never a half-built one.
|
|
@@ -317,6 +306,42 @@ async function doInitLbug(repoId, dbPath) {
|
|
|
317
306
|
});
|
|
318
307
|
ensureIdleTimer();
|
|
319
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Load FTS + VECTOR extensions on every connection in the pool.
|
|
311
|
+
* Per-connection load is required because LadybugDB's extension state is
|
|
312
|
+
* not always shared across connections of the same Database (observed on
|
|
313
|
+
* macOS native bindings — silent FTS failures otherwise).
|
|
314
|
+
*/
|
|
315
|
+
async function loadExtensionsOnConnections(conns, shared) {
|
|
316
|
+
// FTS: every connection needs `LOAD EXTENSION fts` independently.
|
|
317
|
+
await Promise.all(conns.map(async (c) => {
|
|
318
|
+
try {
|
|
319
|
+
await c.query('LOAD EXTENSION fts');
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// already-loaded / not-installed — FTS queries fail gracefully if missing
|
|
323
|
+
}
|
|
324
|
+
}));
|
|
325
|
+
shared.ftsLoaded = true;
|
|
326
|
+
// VECTOR: install once on the Database (idempotent), then LOAD on every
|
|
327
|
+
// connection. INSTALL is a no-op after the first call but we run it on
|
|
328
|
+
// conn[0] to guarantee the package is present before fanning out LOADs.
|
|
329
|
+
try {
|
|
330
|
+
await conns[0].query('INSTALL VECTOR');
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
/* not available — semantic search will be a no-op */
|
|
334
|
+
}
|
|
335
|
+
await Promise.all(conns.map(async (c) => {
|
|
336
|
+
try {
|
|
337
|
+
await c.query('LOAD EXTENSION VECTOR');
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
/* not available — semantic search will be a no-op */
|
|
341
|
+
}
|
|
342
|
+
}));
|
|
343
|
+
shared.vectorLoaded = true;
|
|
344
|
+
}
|
|
320
345
|
/**
|
|
321
346
|
* Initialize a pool entry from a pre-existing Database object.
|
|
322
347
|
*
|
|
@@ -354,27 +379,9 @@ export async function initLbugWithDb(repoId, existingDb, dbPath) {
|
|
|
354
379
|
finally {
|
|
355
380
|
preWarmActive = false;
|
|
356
381
|
}
|
|
357
|
-
// Load FTS
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
await available[0].query('LOAD EXTENSION fts');
|
|
361
|
-
shared.ftsLoaded = true;
|
|
362
|
-
}
|
|
363
|
-
catch {
|
|
364
|
-
// Extension may already be loaded or not installed
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
// Load VECTOR extension for semantic search support
|
|
368
|
-
if (!shared.vectorLoaded) {
|
|
369
|
-
try {
|
|
370
|
-
await available[0].query('INSTALL VECTOR');
|
|
371
|
-
await available[0].query('LOAD EXTENSION VECTOR');
|
|
372
|
-
shared.vectorLoaded = true;
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
// VECTOR extension may not be available
|
|
376
|
-
}
|
|
377
|
-
}
|
|
382
|
+
// Load FTS + VECTOR on every connection (see loadExtensionsOnConnections
|
|
383
|
+
// for why per-connection load is required on macOS native bindings).
|
|
384
|
+
await loadExtensionsOnConnections(available, shared);
|
|
378
385
|
pool.set(repoId, {
|
|
379
386
|
db: existingDb,
|
|
380
387
|
available,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* small repos / CI runners) at the cost of paying that overhead on the
|
|
11
11
|
* first `query`/`context` call in a session.
|
|
12
12
|
*/
|
|
13
|
-
import { queryFTS, ensureFTSIndex } from '../lbug/lbug-adapter.js';
|
|
13
|
+
import { queryFTS, ensureFTSIndex, executeQuery as executeCoreQuery, } from '../lbug/lbug-adapter.js';
|
|
14
14
|
/**
|
|
15
15
|
* FTS schema served by `searchFTSFromLbug`. Centralised so that both the
|
|
16
16
|
* CLI/pipeline path and the MCP pool path use identical (table, index,
|
|
@@ -23,6 +23,13 @@ const FTS_INDEXES = [
|
|
|
23
23
|
{ table: 'Method', indexName: 'method_fts', properties: ['name', 'content'] },
|
|
24
24
|
{ table: 'Interface', indexName: 'interface_fts', properties: ['name', 'content'] },
|
|
25
25
|
];
|
|
26
|
+
const FALLBACK_SCAN_LIMIT = 50_000;
|
|
27
|
+
const BOOLEAN_QUERY_TOKENS = new Set(['and', 'or', 'not']);
|
|
28
|
+
const FALLBACK_FIELD_WEIGHTS = {
|
|
29
|
+
name: 4,
|
|
30
|
+
content: 2,
|
|
31
|
+
description: 1,
|
|
32
|
+
};
|
|
26
33
|
/**
|
|
27
34
|
* Per-process cache for the MCP pool path: tracks which `(repoId, table)`
|
|
28
35
|
* pairs have been ensured. The CLI/pipeline path gets its own cache inside
|
|
@@ -122,6 +129,68 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
|
|
|
122
129
|
return [];
|
|
123
130
|
}
|
|
124
131
|
}
|
|
132
|
+
function searchTerms(query) {
|
|
133
|
+
const terms = query
|
|
134
|
+
.toLowerCase()
|
|
135
|
+
.match(/[\p{L}\p{N}_]+/gu)
|
|
136
|
+
?.filter((term) => term.length > 1 && !BOOLEAN_QUERY_TOKENS.has(term));
|
|
137
|
+
return [...new Set(terms ?? [])];
|
|
138
|
+
}
|
|
139
|
+
function scoreFallbackNode(node, query, properties) {
|
|
140
|
+
const terms = searchTerms(query);
|
|
141
|
+
if (terms.length === 0)
|
|
142
|
+
return 0;
|
|
143
|
+
const phrase = query.trim().toLowerCase();
|
|
144
|
+
let score = 0;
|
|
145
|
+
for (const property of properties) {
|
|
146
|
+
const raw = node[property];
|
|
147
|
+
if (raw === null || raw === undefined)
|
|
148
|
+
continue;
|
|
149
|
+
const value = String(raw).toLowerCase();
|
|
150
|
+
if (!value)
|
|
151
|
+
continue;
|
|
152
|
+
const weight = FALLBACK_FIELD_WEIGHTS[property] ?? 1;
|
|
153
|
+
if (phrase.length > 1 && value.includes(phrase)) {
|
|
154
|
+
score += weight * (terms.length + 1);
|
|
155
|
+
}
|
|
156
|
+
for (const term of terms) {
|
|
157
|
+
if (value.includes(term))
|
|
158
|
+
score += weight;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return score;
|
|
162
|
+
}
|
|
163
|
+
async function queryFallbackViaExecutor(executor, tableName, properties, query, limit) {
|
|
164
|
+
try {
|
|
165
|
+
const rows = await executor(`
|
|
166
|
+
MATCH (node:${tableName})
|
|
167
|
+
RETURN node
|
|
168
|
+
LIMIT ${FALLBACK_SCAN_LIMIT}
|
|
169
|
+
`);
|
|
170
|
+
return rows
|
|
171
|
+
.map((row) => {
|
|
172
|
+
const node = row.node || row[0] || {};
|
|
173
|
+
return {
|
|
174
|
+
filePath: node.filePath || '',
|
|
175
|
+
score: scoreFallbackNode(node, query, properties),
|
|
176
|
+
nodeId: node.nodeId || node.id || '',
|
|
177
|
+
};
|
|
178
|
+
})
|
|
179
|
+
.filter((result) => result.filePath && result.score > 0)
|
|
180
|
+
.sort((a, b) => b.score - a.score)
|
|
181
|
+
.slice(0, limit);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function fallbackSearchAllTables(executor, query, limit) {
|
|
188
|
+
const results = [];
|
|
189
|
+
for (const { table, properties } of FTS_INDEXES) {
|
|
190
|
+
results.push(await queryFallbackViaExecutor(executor, table, properties, query, limit));
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
125
194
|
/**
|
|
126
195
|
* Search using LadybugDB's built-in FTS (always fresh, reads from disk)
|
|
127
196
|
*
|
|
@@ -134,6 +203,8 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
|
|
|
134
203
|
* @returns Ranked search results from FTS indexes
|
|
135
204
|
*/
|
|
136
205
|
export const searchFTSFromLbug = async (query, limit = 20, repoId) => {
|
|
206
|
+
if (!query.trim() || limit <= 0)
|
|
207
|
+
return [];
|
|
137
208
|
let fileResults, functionResults, classResults, methodResults, interfaceResults;
|
|
138
209
|
if (repoId) {
|
|
139
210
|
// Use MCP connection pool via dynamic import
|
|
@@ -157,6 +228,15 @@ export const searchFTSFromLbug = async (query, limit = 20, repoId) => {
|
|
|
157
228
|
classResults = await queryFTSViaExecutor(executor, 'Class', 'class_fts', query, limit);
|
|
158
229
|
methodResults = await queryFTSViaExecutor(executor, 'Method', 'method_fts', query, limit);
|
|
159
230
|
interfaceResults = await queryFTSViaExecutor(executor, 'Interface', 'interface_fts', query, limit);
|
|
231
|
+
if (fileResults.length +
|
|
232
|
+
functionResults.length +
|
|
233
|
+
classResults.length +
|
|
234
|
+
methodResults.length +
|
|
235
|
+
interfaceResults.length ===
|
|
236
|
+
0) {
|
|
237
|
+
[fileResults, functionResults, classResults, methodResults, interfaceResults] =
|
|
238
|
+
await fallbackSearchAllTables(executor, query, limit);
|
|
239
|
+
}
|
|
160
240
|
}
|
|
161
241
|
else {
|
|
162
242
|
// Use core lbug adapter (CLI / pipeline context) — also sequential for safety.
|
|
@@ -169,6 +249,15 @@ export const searchFTSFromLbug = async (query, limit = 20, repoId) => {
|
|
|
169
249
|
classResults = await queryFTS('Class', 'class_fts', query, limit, false).catch(() => []);
|
|
170
250
|
methodResults = await queryFTS('Method', 'method_fts', query, limit, false).catch(() => []);
|
|
171
251
|
interfaceResults = await queryFTS('Interface', 'interface_fts', query, limit, false).catch(() => []);
|
|
252
|
+
if (fileResults.length +
|
|
253
|
+
functionResults.length +
|
|
254
|
+
classResults.length +
|
|
255
|
+
methodResults.length +
|
|
256
|
+
interfaceResults.length ===
|
|
257
|
+
0) {
|
|
258
|
+
[fileResults, functionResults, classResults, methodResults, interfaceResults] =
|
|
259
|
+
await fallbackSearchAllTables(executeCoreQuery, query, limit);
|
|
260
|
+
}
|
|
172
261
|
}
|
|
173
262
|
// Collect all node scores per filePath to track which nodes actually matched
|
|
174
263
|
const fileNodeScores = new Map();
|
|
@@ -221,7 +221,7 @@ export class WikiGenerator {
|
|
|
221
221
|
reportProgress(node.name);
|
|
222
222
|
return 1;
|
|
223
223
|
}
|
|
224
|
-
catch (
|
|
224
|
+
catch (_err) {
|
|
225
225
|
this.failedModules.push(node.name);
|
|
226
226
|
reportProgress(`Failed: ${node.name}`);
|
|
227
227
|
return 0;
|
|
@@ -239,7 +239,7 @@ export class WikiGenerator {
|
|
|
239
239
|
pagesGenerated++;
|
|
240
240
|
reportProgress(node.name);
|
|
241
241
|
}
|
|
242
|
-
catch (
|
|
242
|
+
catch (_err) {
|
|
243
243
|
this.failedModules.push(node.name);
|
|
244
244
|
reportProgress(`Failed: ${node.name}`);
|
|
245
245
|
}
|
|
@@ -607,7 +607,7 @@ export class WikiGenerator {
|
|
|
607
607
|
this.onProgress('incremental', percent, `${incProcessed}/${affectedNodes.length} — ${node.name}`);
|
|
608
608
|
return 1;
|
|
609
609
|
}
|
|
610
|
-
catch (
|
|
610
|
+
catch (_err) {
|
|
611
611
|
this.failedModules.push(node.name);
|
|
612
612
|
incProcessed++;
|
|
613
613
|
return 0;
|
|
@@ -807,7 +807,7 @@ export class WikiGenerator {
|
|
|
807
807
|
let activeConcurrency = this.concurrency;
|
|
808
808
|
let running = 0;
|
|
809
809
|
let idx = 0;
|
|
810
|
-
return new Promise((resolve,
|
|
810
|
+
return new Promise((resolve, _reject) => {
|
|
811
811
|
const next = () => {
|
|
812
812
|
while (running < activeConcurrency && idx < items.length) {
|
|
813
813
|
const item = items[idx++];
|
package/dist/mcp/resources.js
CHANGED
|
@@ -318,7 +318,7 @@ async function getContextResource(backend, repoName) {
|
|
|
318
318
|
lines.push(' - cypher: Raw graph queries');
|
|
319
319
|
lines.push(' - list_repos: Discover all indexed repositories');
|
|
320
320
|
lines.push('');
|
|
321
|
-
lines.push('re_index: Run `npx codragraph analyze` in terminal if data is stale');
|
|
321
|
+
lines.push('re_index: Run `npx @codragraph/cli analyze` in terminal if data is stale');
|
|
322
322
|
lines.push('');
|
|
323
323
|
lines.push('resources_available:');
|
|
324
324
|
lines.push(' - codragraph://repos: All indexed repositories');
|
|
@@ -520,7 +520,7 @@ async function getProcessDetailResource(name, backend, repoName) {
|
|
|
520
520
|
async function getSetupResource(backend) {
|
|
521
521
|
const repos = await backend.listRepos();
|
|
522
522
|
if (repos.length === 0) {
|
|
523
|
-
return '# CodraGraph\n\nNo repositories indexed. Run: `npx codragraph analyze` in a repository.';
|
|
523
|
+
return '# CodraGraph\n\nNo repositories indexed. Run: `npx @codragraph/cli analyze` in a repository.';
|
|
524
524
|
}
|
|
525
525
|
const sections = [];
|
|
526
526
|
for (const repo of repos) {
|
|
@@ -625,7 +625,6 @@ async function getRecipesResource(backend, repoName, taskFamily) {
|
|
|
625
625
|
let result;
|
|
626
626
|
try {
|
|
627
627
|
const harnessModuleId = '@codragraph/harness/mcp/handler';
|
|
628
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
629
628
|
const mod = (await import(/* @vite-ignore */ harnessModuleId));
|
|
630
629
|
result = await mod.handleHarnessRecipesList({
|
|
631
630
|
task_family: taskFamily,
|
|
@@ -133,8 +133,18 @@ function runCodraGraphCli(cliPath, args, cwd, timeout) {
|
|
|
133
133
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
|
-
//
|
|
137
|
-
|
|
136
|
+
// npx fallback: on Windows, Node 22's spawn refuses to launch `npx.cmd`
|
|
137
|
+
// directly (returns EINVAL), so route through `cmd /c` and let PATHEXT
|
|
138
|
+
// resolve the shim. POSIX direct-spawn is fine.
|
|
139
|
+
if (isWin) {
|
|
140
|
+
return spawnSync('cmd', ['/c', 'npx', '-y', '@codragraph/cli', ...args], {
|
|
141
|
+
encoding: 'utf-8',
|
|
142
|
+
timeout: timeout + 5000,
|
|
143
|
+
cwd,
|
|
144
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return spawnSync('npx', ['-y', '@codragraph/cli', ...args], {
|
|
138
148
|
encoding: 'utf-8',
|
|
139
149
|
timeout: timeout + 5000,
|
|
140
150
|
cwd,
|
|
@@ -239,7 +249,7 @@ function handlePostToolUse(input) {
|
|
|
239
249
|
// If HEAD matches last indexed commit, no reindex needed
|
|
240
250
|
if (currentHead && currentHead === lastCommit) return;
|
|
241
251
|
|
|
242
|
-
const analyzeCmd = `npx codragraph analyze${hadEmbeddings ? ' --embeddings' : ''}`;
|
|
252
|
+
const analyzeCmd = `npx @codragraph/cli analyze${hadEmbeddings ? ' --embeddings' : ''}`;
|
|
243
253
|
sendHookResponse(
|
|
244
254
|
'PostToolUse',
|
|
245
255
|
`CodraGraph index is stale (last indexed: ${lastCommit ? lastCommit.slice(0, 7) : 'never'}). ` +
|
|
@@ -64,7 +64,12 @@ fi
|
|
|
64
64
|
|
|
65
65
|
# Run codragraph augment — must be fast (<500ms target)
|
|
66
66
|
# augment writes to stderr (KuzuDB captures stdout at OS level), so capture stderr and discard stdout
|
|
67
|
-
|
|
67
|
+
# Prefer the global bin if present; fall back to npx (npm package is @codragraph/cli, bin is `codragraph`)
|
|
68
|
+
if command -v codragraph >/dev/null 2>&1; then
|
|
69
|
+
RESULT=$(cd "$CWD" && codragraph augment "$PATTERN" 2>&1 1>/dev/null)
|
|
70
|
+
else
|
|
71
|
+
RESULT=$(cd "$CWD" && npx -y @codragraph/cli augment "$PATTERN" 2>&1 1>/dev/null)
|
|
72
|
+
fi
|
|
68
73
|
|
|
69
74
|
if [ -n "$RESULT" ]; then
|
|
70
75
|
ESCAPED=$(echo "$RESULT" | jq -Rs .)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codragraph/cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Anit Chaudhary",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"claude",
|
|
18
18
|
"codex",
|
|
19
19
|
"ai-agent",
|
|
20
|
-
"
|
|
20
|
+
"codragraph",
|
|
21
21
|
"static-analysis",
|
|
22
22
|
"codebase-indexing"
|
|
23
23
|
],
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"bin": {
|
|
36
|
-
"
|
|
36
|
+
"codragraph": "dist/cli/index.js"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
39
|
"dist",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@huggingface/transformers": "^4.1.0",
|
|
60
60
|
"@ladybugdb/core": "^0.15.2",
|
|
61
61
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
62
|
-
"@codragraph/graphstore": "
|
|
62
|
+
"@codragraph/graphstore": "^0.1.1",
|
|
63
63
|
"@scarf/scarf": "^1.4.0",
|
|
64
64
|
"cli-progress": "^3.12.0",
|
|
65
65
|
"commander": "^14.0.3",
|
package/skills/codragraph-cli.md
CHANGED
|
@@ -12,7 +12,7 @@ All commands work via `npx` — no global install required.
|
|
|
12
12
|
### analyze — Build or refresh the index
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npx codragraph analyze
|
|
15
|
+
npx @codragraph/cli analyze
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.codragraph/`, and generates CLAUDE.md / AGENTS.md context files.
|
|
@@ -27,7 +27,7 @@ Run from the project root. This parses all source files, builds the knowledge gr
|
|
|
27
27
|
### status — Check index freshness
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npx codragraph status
|
|
30
|
+
npx @codragraph/cli status
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
Shows whether the current repo has a CodraGraph index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed.
|
|
@@ -35,7 +35,7 @@ Shows whether the current repo has a CodraGraph index, when it was last updated,
|
|
|
35
35
|
### clean — Delete the index
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
npx codragraph clean
|
|
38
|
+
npx @codragraph/cli clean
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Deletes the `.codragraph/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing CodraGraph from a project.
|
|
@@ -48,7 +48,7 @@ Deletes the `.codragraph/` directory and unregisters the repo from the global re
|
|
|
48
48
|
### wiki — Generate documentation from the graph
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
npx codragraph wiki
|
|
51
|
+
npx @codragraph/cli wiki
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.codragraph/config.json` on first use).
|
|
@@ -65,7 +65,7 @@ Generates repository documentation from the knowledge graph using an LLM. Requir
|
|
|
65
65
|
### list — Show all indexed repos
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
npx codragraph list
|
|
68
|
+
npx @codragraph/cli list
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
Lists all repositories registered in `~/.codragraph/registry.json`. The MCP `list_repos` tool provides the same information.
|
|
@@ -22,7 +22,7 @@ description: "Use when the user is debugging a bug, tracing an error, or asking
|
|
|
22
22
|
4. codragraph_cypher({query: "MATCH path..."}) → Custom traces if needed
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
> If "Index is stale" → run `npx codragraph analyze` in terminal.
|
|
25
|
+
> If "Index is stale" → run `npx @codragraph/cli analyze` in terminal.
|
|
26
26
|
|
|
27
27
|
## Checklist
|
|
28
28
|
|
|
@@ -23,7 +23,7 @@ description: "Use when the user asks how code works, wants to understand archite
|
|
|
23
23
|
5. READ codragraph://repo/{name}/process/{name} → Trace full execution flow
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
> If step 2 says "Index is stale" → run `npx codragraph analyze` in terminal.
|
|
26
|
+
> If step 2 says "Index is stale" → run `npx @codragraph/cli analyze` in terminal.
|
|
27
27
|
|
|
28
28
|
## Checklist
|
|
29
29
|
|
|
@@ -15,7 +15,7 @@ For any task involving code understanding, debugging, impact analysis, or refact
|
|
|
15
15
|
2. **Match your task to a skill below** and **read that skill file**
|
|
16
16
|
3. **Follow the skill's workflow and checklist**
|
|
17
17
|
|
|
18
|
-
> If step 1 warns the index is stale, run `npx codragraph analyze` in the terminal first.
|
|
18
|
+
> If step 1 warns the index is stale, run `npx @codragraph/cli analyze` in the terminal first.
|
|
19
19
|
|
|
20
20
|
## Skills
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ description: "Use when the user wants to know what will break if they change som
|
|
|
23
23
|
4. Assess risk and report to user
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
> If "Index is stale" → run `npx codragraph analyze` in terminal.
|
|
26
|
+
> If "Index is stale" → run `npx @codragraph/cli analyze` in terminal.
|
|
27
27
|
|
|
28
28
|
## Checklist
|
|
29
29
|
|
|
@@ -26,7 +26,7 @@ description: "Use when the user wants to review a pull request, understand what
|
|
|
26
26
|
6. Summarize findings with risk assessment
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
> If "Index is stale" → run `npx codragraph analyze` in terminal before reviewing.
|
|
29
|
+
> If "Index is stale" → run `npx @codragraph/cli analyze` in terminal before reviewing.
|
|
30
30
|
|
|
31
31
|
## Checklist
|
|
32
32
|
|
|
@@ -22,7 +22,7 @@ description: "Use when the user wants to rename, extract, split, move, or restru
|
|
|
22
22
|
4. Plan update order: interfaces → implementations → callers → tests
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
> If "Index is stale" → run `npx codragraph analyze` in terminal.
|
|
25
|
+
> If "Index is stale" → run `npx @codragraph/cli analyze` in terminal.
|
|
26
26
|
|
|
27
27
|
## Checklists
|
|
28
28
|
|