mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-29 06:32:28 +00:00
logging global registry
This commit is contained in:
parent
49925a6cfe
commit
18a5263396
12 changed files with 240 additions and 275 deletions
17
AGENTS.md
17
AGENTS.md
|
|
@ -3,9 +3,9 @@
|
|||
<!-- gitnexus:start -->
|
||||
# GitNexus MCP
|
||||
|
||||
This project is indexed by GitNexus as **GitnexusV2** (940 symbols, 2298 relationships, 13 clusters, 67 processes).
|
||||
This project is indexed by GitNexus as **GitnexusV2** (1023 symbols, 2503 relationships, 78 execution flows).
|
||||
|
||||
GitNexus provides a knowledge graph over this codebase — clusters, call chains, blast radius, execution flows, and semantic search.
|
||||
GitNexus provides a knowledge graph over this codebase — call chains, blast radius, execution flows, and semantic search.
|
||||
|
||||
## Always Start Here
|
||||
|
||||
|
|
@ -30,10 +30,11 @@ For any task involving code understanding, debugging, impact analysis, or refact
|
|||
|
||||
| Tool | What it gives you |
|
||||
|------|-------------------|
|
||||
| `search` | Semantic + keyword code search with cluster context |
|
||||
| `explore` | Symbol deep dive — callers, callees, cluster membership, processes |
|
||||
| `impact` | Blast radius — what breaks at depth 1/2/3 with confidence scores |
|
||||
| `overview` | All clusters and processes at a glance |
|
||||
| `query` | Process-grouped code intelligence — execution flows related to a concept |
|
||||
| `context` | 360-degree symbol view — categorized refs, processes it participates in |
|
||||
| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
|
||||
| `detect_changes` | Git-diff impact — what do your current changes affect |
|
||||
| `rename` | Multi-file coordinated rename with confidence-tagged edits |
|
||||
| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) |
|
||||
| `list_repos` | Discover indexed repos |
|
||||
|
||||
|
|
@ -44,8 +45,8 @@ Lightweight reads (~100-500 tokens) for navigation:
|
|||
| Resource | Content |
|
||||
|----------|---------|
|
||||
| `gitnexus://repo/{name}/context` | Stats, staleness check |
|
||||
| `gitnexus://repo/{name}/clusters` | All clusters with cohesion scores |
|
||||
| `gitnexus://repo/{name}/cluster/{clusterName}` | Cluster members |
|
||||
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores |
|
||||
| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members |
|
||||
| `gitnexus://repo/{name}/processes` | All execution flows |
|
||||
| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace |
|
||||
| `gitnexus://repo/{name}/schema` | Graph schema for Cypher |
|
||||
|
|
|
|||
62
CLAUDE.md
Normal file
62
CLAUDE.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<!-- gitnexus:start -->
|
||||
# GitNexus MCP
|
||||
|
||||
This project is indexed by GitNexus as **GitnexusV2** (1023 symbols, 2503 relationships, 78 execution flows).
|
||||
|
||||
GitNexus provides a knowledge graph over this codebase — call chains, blast radius, execution flows, and semantic search.
|
||||
|
||||
## Always Start Here
|
||||
|
||||
For any task involving code understanding, debugging, impact analysis, or refactoring, you must:
|
||||
|
||||
1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness
|
||||
2. **Match your task to a skill below** and **read that skill file**
|
||||
3. **Follow the skill's workflow and checklist**
|
||||
|
||||
> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first.
|
||||
|
||||
## Skills
|
||||
|
||||
| Task | Read this skill file |
|
||||
|------|---------------------|
|
||||
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/exploring/SKILL.md` |
|
||||
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/impact-analysis/SKILL.md` |
|
||||
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/debugging/SKILL.md` |
|
||||
| Rename / extract / split / refactor | `.claude/skills/gitnexus/refactoring/SKILL.md` |
|
||||
|
||||
## Tools Reference
|
||||
|
||||
| Tool | What it gives you |
|
||||
|------|-------------------|
|
||||
| `query` | Process-grouped code intelligence — execution flows related to a concept |
|
||||
| `context` | 360-degree symbol view — categorized refs, processes it participates in |
|
||||
| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
|
||||
| `detect_changes` | Git-diff impact — what do your current changes affect |
|
||||
| `rename` | Multi-file coordinated rename with confidence-tagged edits |
|
||||
| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) |
|
||||
| `list_repos` | Discover indexed repos |
|
||||
|
||||
## Resources Reference
|
||||
|
||||
Lightweight reads (~100-500 tokens) for navigation:
|
||||
|
||||
| Resource | Content |
|
||||
|----------|---------|
|
||||
| `gitnexus://repo/{name}/context` | Stats, staleness check |
|
||||
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores |
|
||||
| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members |
|
||||
| `gitnexus://repo/{name}/processes` | All execution flows |
|
||||
| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace |
|
||||
| `gitnexus://repo/{name}/schema` | Graph schema for Cypher |
|
||||
|
||||
## Graph Schema
|
||||
|
||||
**Nodes:** File, Function, Class, Interface, Method, Community, Process
|
||||
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
|
||||
|
||||
```cypher
|
||||
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
|
||||
RETURN caller.name, caller.filePath
|
||||
```
|
||||
|
||||
<!-- gitnexus:end -->
|
||||
252
gitnexus/package-lock.json
generated
252
gitnexus/package-lock.json
generated
|
|
@ -1,16 +1,17 @@
|
|||
{
|
||||
"name": "gitnexus",
|
||||
"version": "0.1.0",
|
||||
"version": "1.1.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gitnexus",
|
||||
"version": "0.1.0",
|
||||
"version": "1.1.8",
|
||||
"license": "PolyForm-Noncommercial-1.0.0",
|
||||
"dependencies": {
|
||||
"@huggingface/transformers": "^3.0.0",
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^12.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.19.2",
|
||||
|
|
@ -21,7 +22,6 @@
|
|||
"kuzu": "^0.11.3",
|
||||
"lru-cache": "^11.0.0",
|
||||
"mnemonist": "^0.39.0",
|
||||
"ora": "^8.0.0",
|
||||
"pandemonium": "^2.4.0",
|
||||
"tree-sitter": "^0.21.0",
|
||||
"tree-sitter-c": "^0.21.0",
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
"gitnexus": "dist/cli/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cli-progress": "^3.11.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.0.0",
|
||||
|
|
@ -1449,6 +1450,16 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cli-progress": {
|
||||
"version": "3.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz",
|
||||
"integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/connect": {
|
||||
"version": "3.4.38",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||
|
|
@ -1769,18 +1780,6 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
|
|
@ -1790,31 +1789,57 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-cursor": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
|
||||
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
|
||||
"node_modules/cli-progress": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz",
|
||||
"integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"restore-cursor": "^5.0.0"
|
||||
"string-width": "^4.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-spinners": {
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
|
||||
"integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
|
||||
"node_modules/cli-progress/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-progress/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cli-progress/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-progress/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
|
|
@ -2690,18 +2715,6 @@
|
|||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz",
|
||||
"integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
|
|
@ -3003,36 +3016,12 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-interactive": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
|
||||
"integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-unicode-supported": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
|
||||
"integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
|
|
@ -3105,34 +3094,6 @@
|
|||
"node-addon-api": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/log-symbols": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
|
||||
"integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"is-unicode-supported": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/log-symbols/node_modules/is-unicode-supported": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
|
||||
"integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
|
|
@ -3238,18 +3199,6 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
||||
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
|
||||
|
|
@ -3440,21 +3389,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/onetime": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
|
||||
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-function": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/onnxruntime-common": {
|
||||
"version": "1.21.0",
|
||||
"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0.tgz",
|
||||
|
|
@ -3544,52 +3478,6 @@
|
|||
"integrity": "sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ora": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
|
||||
"integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"cli-cursor": "^5.0.0",
|
||||
"cli-spinners": "^2.9.2",
|
||||
"is-interactive": "^2.0.0",
|
||||
"is-unicode-supported": "^2.0.0",
|
||||
"log-symbols": "^6.0.0",
|
||||
"stdin-discarder": "^0.2.2",
|
||||
"string-width": "^7.2.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ora/node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ora/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
|
|
@ -3815,22 +3703,6 @@
|
|||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/restore-cursor": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
||||
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"onetime": "^7.0.0",
|
||||
"signal-exit": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
|
|
@ -4177,18 +4049,6 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/stdin-discarder": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
|
||||
"integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
"dependencies": {
|
||||
"@huggingface/transformers": "^3.0.0",
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^12.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.19.2",
|
||||
|
|
@ -53,7 +54,6 @@
|
|||
"kuzu": "^0.11.3",
|
||||
"lru-cache": "^11.0.0",
|
||||
"mnemonist": "^0.39.0",
|
||||
"ora": "^8.0.0",
|
||||
"pandemonium": "^2.4.0",
|
||||
"tree-sitter": "^0.21.0",
|
||||
"tree-sitter-c": "^0.21.0",
|
||||
|
|
@ -69,6 +69,7 @@
|
|||
"uuid": "^13.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cli-progress": "^3.11.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.0.0",
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import ora from 'ora';
|
||||
import cliProgress from 'cli-progress';
|
||||
import { runPipelineFromRepo } from '../core/ingestion/pipeline.js';
|
||||
import { initKuzu, loadGraphToKuzu, getKuzuStats, executeQuery, executeWithReusedStatement, closeKuzu, createFTSIndex } from '../core/kuzu/kuzu-adapter.js';
|
||||
import { runEmbeddingPipeline } from '../core/embeddings/embedding-pipeline.js';
|
||||
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath } from '../storage/repo-manager.js';
|
||||
import { disposeEmbedder } from '../core/embeddings/embedder.js';
|
||||
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath, getGlobalDir } from '../storage/repo-manager.js';
|
||||
import { getCurrentCommit, isGitRepo, getGitRoot } from '../storage/git.js';
|
||||
import { generateAIContextFiles } from './ai-context.js';
|
||||
import fs from 'fs/promises';
|
||||
|
|
@ -19,20 +20,31 @@ export interface AnalyzeOptions {
|
|||
skipEmbeddings?: boolean;
|
||||
}
|
||||
|
||||
const PHASE_LABELS: Record<string, string> = {
|
||||
extracting: 'Scanning files',
|
||||
structure: 'Building structure',
|
||||
parsing: 'Parsing code',
|
||||
imports: 'Resolving imports',
|
||||
calls: 'Tracing calls',
|
||||
heritage: 'Extracting inheritance',
|
||||
communities: 'Detecting communities',
|
||||
processes: 'Detecting processes',
|
||||
complete: 'Complete',
|
||||
};
|
||||
|
||||
export const analyzeCommand = async (
|
||||
inputPath?: string,
|
||||
options?: AnalyzeOptions
|
||||
) => {
|
||||
const spinner = ora('Checking repository...').start();
|
||||
console.log('\n GitNexus Analyzer\n');
|
||||
|
||||
// If path provided, use it directly. Otherwise, find git root from cwd.
|
||||
let repoPath: string;
|
||||
if (inputPath) {
|
||||
repoPath = path.resolve(inputPath);
|
||||
} else {
|
||||
const gitRoot = getGitRoot(process.cwd());
|
||||
if (!gitRoot) {
|
||||
spinner.fail('Not inside a git repository');
|
||||
console.log(' ✗ Not inside a git repository\n');
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
|
@ -40,7 +52,7 @@ export const analyzeCommand = async (
|
|||
}
|
||||
|
||||
if (!isGitRepo(repoPath)) {
|
||||
spinner.fail('Not a git repository');
|
||||
console.log(' ✗ Not a git repository\n');
|
||||
process.exitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
|
@ -49,25 +61,31 @@ export const analyzeCommand = async (
|
|||
const currentCommit = getCurrentCommit(repoPath);
|
||||
const existingMeta = await loadMeta(storagePath);
|
||||
|
||||
// Skip if already indexed at same commit
|
||||
if (existingMeta && !options?.force && existingMeta.lastCommit === currentCommit) {
|
||||
spinner.succeed('Repository already up to date');
|
||||
console.log(' ✓ Repository already up to date\n');
|
||||
return;
|
||||
}
|
||||
|
||||
// Run ingestion pipeline
|
||||
spinner.text = 'Running ingestion pipeline...';
|
||||
const multibar = new cliProgress.MultiBar({
|
||||
format: ' {bar} {percentage}% | {phase}',
|
||||
barCompleteChar: '█',
|
||||
barIncompleteChar: '░',
|
||||
hideCursor: true,
|
||||
barGlue: '',
|
||||
autopadding: true,
|
||||
}, cliProgress.Presets.shades_grey);
|
||||
|
||||
const progressBar = multibar.create(100, 0, { phase: 'Initializing...' });
|
||||
|
||||
const pipelineResult = await runPipelineFromRepo(repoPath, (progress) => {
|
||||
spinner.text = `${progress.phase}: ${progress.percent}%`;
|
||||
const phaseLabel = PHASE_LABELS[progress.phase] || progress.phase;
|
||||
progressBar.update(progress.percent, { phase: phaseLabel });
|
||||
});
|
||||
|
||||
// Load graph into KuzuDB
|
||||
// Always start fresh - remove existing kuzu DB to avoid stale/corrupt data
|
||||
spinner.text = 'Loading graph into KuzuDB...';
|
||||
progressBar.update(100, { phase: 'Loading graph into KuzuDB...' });
|
||||
|
||||
await closeKuzu();
|
||||
|
||||
// Kuzu 0.11 stores databases as: <name> (main file) + <name>.wal (WAL file)
|
||||
// BOTH must be deleted or kuzu will find the orphaned WAL and corrupt the database
|
||||
const fsClean = await import('fs/promises');
|
||||
const kuzuFiles = [kuzuPath, `${kuzuPath}.wal`, `${kuzuPath}.lock`];
|
||||
for (const f of kuzuFiles) {
|
||||
|
|
@ -77,9 +95,8 @@ export const analyzeCommand = async (
|
|||
await initKuzu(kuzuPath);
|
||||
await loadGraphToKuzu(pipelineResult.graph, pipelineResult.fileContents, storagePath);
|
||||
|
||||
// Create FTS indexes for keyword search
|
||||
// Indexes searchable content on: File, Function, Class, Method
|
||||
spinner.text = 'Creating FTS indexes...';
|
||||
progressBar.update(100, { phase: 'Creating search indexes...' });
|
||||
|
||||
try {
|
||||
await createFTSIndex('File', 'file_fts', ['name', 'content']);
|
||||
await createFTSIndex('Function', 'function_fts', ['name', 'content']);
|
||||
|
|
@ -87,23 +104,20 @@ export const analyzeCommand = async (
|
|||
await createFTSIndex('Method', 'method_fts', ['name', 'content']);
|
||||
await createFTSIndex('Interface', 'interface_fts', ['name', 'content']);
|
||||
} catch (e: any) {
|
||||
// FTS index creation may fail if tables are empty (no data for that type)
|
||||
console.error('Note: Some FTS indexes may not have been created:', e.message);
|
||||
console.error(' Note: Some FTS indexes may not have been created:', e.message);
|
||||
}
|
||||
|
||||
// Generate embeddings
|
||||
if (!options?.skipEmbeddings) {
|
||||
spinner.text = 'Generating embeddings...';
|
||||
progressBar.update(100, { phase: 'Generating embeddings...' });
|
||||
await runEmbeddingPipeline(
|
||||
executeQuery,
|
||||
executeWithReusedStatement,
|
||||
(progress) => {
|
||||
spinner.text = `Embeddings: ${progress.percent}%`;
|
||||
progressBar.update(progress.percent, { phase: `Embeddings ${progress.percent}%` });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Save metadata
|
||||
const stats = await getKuzuStats();
|
||||
const meta = {
|
||||
repoPath,
|
||||
|
|
@ -119,16 +133,11 @@ export const analyzeCommand = async (
|
|||
};
|
||||
await saveMeta(storagePath, meta);
|
||||
|
||||
// Register in global registry
|
||||
await registerRepo(repoPath, meta);
|
||||
|
||||
// Add .gitnexus to .gitignore
|
||||
await addToGitignore(repoPath);
|
||||
|
||||
// Generate AI context files
|
||||
const projectName = path.basename(repoPath);
|
||||
// Compute aggregated cluster count (grouped by heuristicLabel, >=5 symbols)
|
||||
// This matches the aggregation logic in local-backend.ts for tool output consistency.
|
||||
let aggregatedClusterCount = 0;
|
||||
if (pipelineResult.communityResult?.communities) {
|
||||
const groups = new Map<string, number>();
|
||||
|
|
@ -148,24 +157,27 @@ export const analyzeCommand = async (
|
|||
processes: pipelineResult.processResult?.stats.totalProcesses,
|
||||
});
|
||||
|
||||
// Close database
|
||||
await closeKuzu();
|
||||
|
||||
spinner.succeed('Repository indexed successfully');
|
||||
console.log(` Path: ${repoPath}`);
|
||||
console.log(` Storage: ${storagePath}`);
|
||||
console.log(` Stats: ${stats.nodes} nodes, ${stats.edges} edges`);
|
||||
await disposeEmbedder();
|
||||
|
||||
multibar.stop();
|
||||
|
||||
console.log('\n ✓ Repository indexed successfully\n');
|
||||
console.log(` Path: ${repoPath}`);
|
||||
console.log(` Storage: ${storagePath}`);
|
||||
console.log(` Registry: ${getGlobalDir()}`);
|
||||
console.log(` Stats: ${stats.nodes} nodes, ${stats.edges} edges, ${pipelineResult.communityResult?.stats.totalCommunities || 0} clusters, ${pipelineResult.processResult?.stats.totalProcesses || 0} processes`);
|
||||
|
||||
if (aiContext.files.length > 0) {
|
||||
console.log(` AI Context: ${aiContext.files.join(', ')}`);
|
||||
console.log(` Context: ${aiContext.files.join(', ')}`);
|
||||
}
|
||||
|
||||
// Hint about setup if it hasn't been run
|
||||
try {
|
||||
await fs.access(getGlobalRegistryPath());
|
||||
} catch {
|
||||
// Registry didn't exist before this run — suggest setup
|
||||
console.log('');
|
||||
console.log(' Tip: Run `gitnexus setup` to configure MCP for your editor.');
|
||||
console.log('\n Tip: Run `gitnexus setup` to configure MCP for your editor.');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export const initEmbedder = async (
|
|||
// Configure transformers.js environment
|
||||
env.allowLocalModels = false;
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
if (isDev) {
|
||||
console.log(`🧠 Loading embedding model: ${finalConfig.modelId}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
EMBEDDABLE_LABELS,
|
||||
} from './types.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
/**
|
||||
* Progress callback type
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { generateId } from '../../lib/utils.js';
|
|||
import { getLanguageFromFilename, yieldToEventLoop } from './utils.js';
|
||||
import { SupportedLanguages } from '../../config/supported-languages.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
// Type: Map<FilePath, Set<ResolvedFilePath>>
|
||||
// Stores all files that a given file imports from
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { createASTCache } from './ast-cache.js';
|
|||
import { PipelineProgress, PipelineResult } from '../../types/pipeline.js';
|
||||
import { walkRepository } from './filesystem-walker.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
export const runPipelineFromRepo = async (
|
||||
repoPath: string,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { KnowledgeGraph, GraphNode, GraphRelationship, NodeLabel } from '../grap
|
|||
import { CommunityMembership } from './community-processor.js';
|
||||
import { calculateEntryPointScore, isTestFile } from './entry-point-scoring.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
// ============================================================================
|
||||
// CONFIGURATION
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
} from './schema.js';
|
||||
import { generateAllCSVs } from './csv-generator.js';
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
let db: kuzu.Database | null = null;
|
||||
let conn: kuzu.Connection | null = null;
|
||||
|
||||
|
|
@ -88,23 +90,24 @@ export const loadGraphToKuzu = async (
|
|||
const normalizedPath = normalizeCopyPath(filePath);
|
||||
const copyQuery = getCopyQuery(table, normalizedPath);
|
||||
|
||||
// Log CSV stats for diagnostics
|
||||
const csvContent = await fs.readFile(filePath, 'utf-8');
|
||||
const csvLines = csvContent.split('\n').length;
|
||||
console.log(` COPY ${table}: ${csvLines - 1} rows`);
|
||||
if (isDev) {
|
||||
const csvContent = await fs.readFile(filePath, 'utf-8');
|
||||
const csvLines = csvContent.split('\n').length;
|
||||
console.log(` COPY ${table}: ${csvLines - 1} rows`);
|
||||
}
|
||||
|
||||
try {
|
||||
await conn.query(copyQuery);
|
||||
} catch (err) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
console.warn(`⚠️ COPY failed for ${table} (${csvLines - 1} rows): ${errMsg}`);
|
||||
console.warn(`⚠️ COPY failed for ${table}: ${errMsg.slice(0, 100)}`);
|
||||
|
||||
// Retry with IGNORE_ERRORS=true to skip malformed rows
|
||||
console.log(` Retrying ${table} with IGNORE_ERRORS=true...`);
|
||||
try {
|
||||
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
||||
await conn.query(retryQuery);
|
||||
console.log(` ✅ ${table} loaded with IGNORE_ERRORS (some rows may have been skipped)`);
|
||||
if (isDev) {
|
||||
console.log(` ✅ ${table} loaded with IGNORE_ERRORS (some rows may have been skipped)`);
|
||||
}
|
||||
} catch (retryErr) {
|
||||
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
||||
console.error(`❌ COPY failed for ${table} even with IGNORE_ERRORS: ${retryMsg}`);
|
||||
|
|
@ -113,7 +116,9 @@ export const loadGraphToKuzu = async (
|
|||
}
|
||||
}
|
||||
|
||||
console.log('✅ All COPY commands succeeded. Starting relationship insertion...');
|
||||
if (isDev) {
|
||||
console.log('✅ All COPY commands succeeded. Starting relationship insertion...');
|
||||
}
|
||||
|
||||
// Build a set of valid table names for fast lookup
|
||||
const validTables = new Set<string>(NODE_TABLES as readonly string[]);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ function isTestFilePath(filePath: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
/** Valid KuzuDB node labels for safe Cypher query construction */
|
||||
const VALID_NODE_LABELS = new Set([
|
||||
'File', 'Folder', 'Function', 'Class', 'Interface', 'Method', 'CodeElement',
|
||||
'Community', 'Process', 'Struct', 'Enum', 'Macro', 'Typedef', 'Union',
|
||||
'Namespace', 'Trait', 'Impl', 'TypeAlias', 'Const', 'Static', 'Property',
|
||||
'Record', 'Delegate', 'Annotation', 'Constructor', 'Template', 'Module',
|
||||
]);
|
||||
|
||||
export interface CodebaseContext {
|
||||
projectName: string;
|
||||
stats: {
|
||||
|
|
@ -260,12 +268,16 @@ export class LocalBackend {
|
|||
max_symbols?: number;
|
||||
include_content?: boolean;
|
||||
}): Promise<any> {
|
||||
if (!params.query?.trim()) {
|
||||
return { error: 'query parameter is required and cannot be empty.' };
|
||||
}
|
||||
|
||||
await this.ensureInitialized(repo.id);
|
||||
|
||||
const processLimit = params.limit || 5;
|
||||
const maxSymbolsPerProcess = params.max_symbols || 10;
|
||||
const includeContent = params.include_content ?? false;
|
||||
const searchQuery = params.query;
|
||||
const searchQuery = params.query.trim();
|
||||
|
||||
// Step 1: Run hybrid search to get matching symbols
|
||||
const searchLimit = processLimit * maxSymbolsPerProcess; // fetch enough raw results
|
||||
|
|
@ -453,7 +465,13 @@ export class LocalBackend {
|
|||
*/
|
||||
private async bm25Search(repo: RepoHandle, query: string, limit: number): Promise<any[]> {
|
||||
const { searchFTSFromKuzu } = await import('../../core/search/bm25-index.js');
|
||||
const bm25Results = await searchFTSFromKuzu(query, limit, repo.id);
|
||||
let bm25Results;
|
||||
try {
|
||||
bm25Results = await searchFTSFromKuzu(query, limit, repo.id);
|
||||
} catch (err: any) {
|
||||
console.error('GitNexus: BM25/FTS search failed (FTS indexes may not exist) -', err.message);
|
||||
return [];
|
||||
}
|
||||
|
||||
const results: any[] = [];
|
||||
|
||||
|
|
@ -535,10 +553,14 @@ export class LocalBackend {
|
|||
const labelEndIdx = nodeId.indexOf(':');
|
||||
const label = labelEndIdx > 0 ? nodeId.substring(0, labelEndIdx) : 'Unknown';
|
||||
|
||||
// Validate label against known node types to prevent Cypher injection
|
||||
if (!VALID_NODE_LABELS.has(label)) continue;
|
||||
|
||||
try {
|
||||
const escapedId = nodeId.replace(/'/g, "''");
|
||||
const nodeQuery = label === 'File'
|
||||
? `MATCH (n:File {id: '${nodeId.replace(/'/g, "''")}'}) RETURN n.name AS name, n.filePath AS filePath`
|
||||
: `MATCH (n:${label} {id: '${nodeId.replace(/'/g, "''")}'}) RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine`;
|
||||
? `MATCH (n:File {id: '${escapedId}'}) RETURN n.name AS name, n.filePath AS filePath`
|
||||
: `MATCH (n:\`${label}\` {id: '${escapedId}'}) RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine`;
|
||||
|
||||
const nodeRows = await executeQuery(repo.id, nodeQuery);
|
||||
if (nodeRows.length > 0) {
|
||||
|
|
@ -1201,16 +1223,18 @@ export class LocalBackend {
|
|||
for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {
|
||||
const nextFrontier: string[] = [];
|
||||
|
||||
for (const nodeId of frontier) {
|
||||
const query = direction === 'upstream'
|
||||
? `MATCH (caller)-[r:CodeRelation]->(n {id: '${nodeId}'}) WHERE r.type IN [${relTypeFilter}]${confidenceFilter} RETURN caller.id AS id, caller.name AS name, labels(caller)[0] AS type, caller.filePath AS filePath, r.type AS relType, r.confidence AS confidence`
|
||||
: `MATCH (n {id: '${nodeId}'})-[r:CodeRelation]->(callee) WHERE r.type IN [${relTypeFilter}]${confidenceFilter} RETURN callee.id AS id, callee.name AS name, labels(callee)[0] AS type, callee.filePath AS filePath, r.type AS relType, r.confidence AS confidence`;
|
||||
|
||||
// Batch frontier nodes into a single Cypher query per depth level
|
||||
const idList = frontier.map(id => `'${id.replace(/'/g, "''")}'`).join(', ');
|
||||
const query = direction === 'upstream'
|
||||
? `MATCH (caller)-[r:CodeRelation]->(n) WHERE n.id IN [${idList}] AND r.type IN [${relTypeFilter}]${confidenceFilter} RETURN n.id AS sourceId, caller.id AS id, caller.name AS name, labels(caller)[0] AS type, caller.filePath AS filePath, r.type AS relType, r.confidence AS confidence`
|
||||
: `MATCH (n)-[r:CodeRelation]->(callee) WHERE n.id IN [${idList}] AND r.type IN [${relTypeFilter}]${confidenceFilter} RETURN n.id AS sourceId, callee.id AS id, callee.name AS name, labels(callee)[0] AS type, callee.filePath AS filePath, r.type AS relType, r.confidence AS confidence`;
|
||||
|
||||
try {
|
||||
const related = await executeQuery(repo.id, query);
|
||||
|
||||
for (const rel of related) {
|
||||
const relId = rel.id || rel[0];
|
||||
const filePath = rel.filePath || rel[3] || '';
|
||||
const relId = rel.id || rel[1];
|
||||
const filePath = rel.filePath || rel[4] || '';
|
||||
|
||||
if (!includeTests && isTestFilePath(filePath)) continue;
|
||||
|
||||
|
|
@ -1220,15 +1244,15 @@ export class LocalBackend {
|
|||
impacted.push({
|
||||
depth,
|
||||
id: relId,
|
||||
name: rel.name || rel[1],
|
||||
type: rel.type || rel[2],
|
||||
name: rel.name || rel[2],
|
||||
type: rel.type || rel[3],
|
||||
filePath,
|
||||
relationType: rel.relType || rel[4],
|
||||
confidence: rel.confidence || rel[5] || 1.0,
|
||||
relationType: rel.relType || rel[5],
|
||||
confidence: rel.confidence || rel[6] || 1.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch { /* query failed for this depth level */ }
|
||||
|
||||
frontier = nextFrontier;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue