gitnexus 1.4.5 → 1.4.7
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/dist/cli/eval-server.js +13 -5
- package/dist/cli/index.js +0 -0
- package/dist/cli/tool.d.ts +3 -2
- package/dist/cli/tool.js +48 -13
- package/dist/core/graph/types.d.ts +2 -2
- package/dist/core/ingestion/call-processor.d.ts +7 -2
- package/dist/core/ingestion/call-processor.js +308 -235
- package/dist/core/ingestion/call-routing.d.ts +17 -2
- package/dist/core/ingestion/call-routing.js +21 -0
- package/dist/core/ingestion/parsing-processor.d.ts +2 -1
- package/dist/core/ingestion/parsing-processor.js +37 -8
- package/dist/core/ingestion/pipeline.js +5 -1
- package/dist/core/ingestion/symbol-table.d.ts +19 -3
- package/dist/core/ingestion/symbol-table.js +41 -2
- package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -12
- package/dist/core/ingestion/tree-sitter-queries.js +200 -0
- package/dist/core/ingestion/type-env.js +126 -18
- package/dist/core/ingestion/type-extractors/c-cpp.js +28 -3
- package/dist/core/ingestion/type-extractors/csharp.js +61 -7
- package/dist/core/ingestion/type-extractors/go.js +86 -10
- package/dist/core/ingestion/type-extractors/jvm.js +122 -23
- package/dist/core/ingestion/type-extractors/php.js +172 -7
- package/dist/core/ingestion/type-extractors/python.js +107 -21
- package/dist/core/ingestion/type-extractors/ruby.js +18 -3
- package/dist/core/ingestion/type-extractors/rust.js +61 -14
- package/dist/core/ingestion/type-extractors/shared.d.ts +13 -0
- package/dist/core/ingestion/type-extractors/shared.js +243 -4
- package/dist/core/ingestion/type-extractors/types.d.ts +57 -12
- package/dist/core/ingestion/type-extractors/typescript.js +52 -8
- package/dist/core/ingestion/utils.d.ts +25 -0
- package/dist/core/ingestion/utils.js +160 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -7
- package/dist/core/ingestion/workers/parse-worker.js +73 -28
- package/dist/core/lbug/lbug-adapter.d.ts +2 -0
- package/dist/core/lbug/lbug-adapter.js +2 -0
- package/dist/core/lbug/schema.d.ts +1 -1
- package/dist/core/lbug/schema.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +22 -0
- package/dist/mcp/core/lbug-adapter.js +167 -23
- package/dist/mcp/local/local-backend.d.ts +1 -0
- package/dist/mcp/local/local-backend.js +25 -3
- package/dist/mcp/resources.js +11 -0
- package/dist/mcp/server.js +26 -4
- package/dist/mcp/tools.js +15 -5
- package/hooks/claude/gitnexus-hook.cjs +0 -0
- package/hooks/claude/pre-tool-use.sh +0 -0
- package/hooks/claude/session-start.sh +0 -0
- package/package.json +6 -5
- package/scripts/patch-tree-sitter-swift.cjs +0 -0
|
@@ -37,7 +37,7 @@ export const VALID_NODE_LABELS = new Set([
|
|
|
37
37
|
'Record', 'Delegate', 'Annotation', 'Constructor', 'Template', 'Module',
|
|
38
38
|
]);
|
|
39
39
|
/** Valid relation types for impact analysis filtering */
|
|
40
|
-
export const VALID_RELATION_TYPES = new Set(['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']);
|
|
40
|
+
export const VALID_RELATION_TYPES = new Set(['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'OVERRIDES', 'ACCESSES']);
|
|
41
41
|
/** Regex to detect write operations in user-supplied Cypher queries */
|
|
42
42
|
export const CYPHER_WRITE_RE = /\b(CREATE|DELETE|SET|MERGE|REMOVE|DROP|ALTER|COPY|DETACH)\b/i;
|
|
43
43
|
/** Check if a Cypher query contains write operations */
|
|
@@ -788,14 +788,14 @@ export class LocalBackend {
|
|
|
788
788
|
// Categorized incoming refs
|
|
789
789
|
const incomingRows = await executeParameterized(repo.id, `
|
|
790
790
|
MATCH (caller)-[r:CodeRelation]->(n {id: $symId})
|
|
791
|
-
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
|
|
791
|
+
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'OVERRIDES', 'ACCESSES']
|
|
792
792
|
RETURN r.type AS relType, caller.id AS uid, caller.name AS name, caller.filePath AS filePath, labels(caller)[0] AS kind
|
|
793
793
|
LIMIT 30
|
|
794
794
|
`, { symId });
|
|
795
795
|
// Categorized outgoing refs
|
|
796
796
|
const outgoingRows = await executeParameterized(repo.id, `
|
|
797
797
|
MATCH (n {id: $symId})-[r:CodeRelation]->(target)
|
|
798
|
-
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS']
|
|
798
|
+
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'OVERRIDES', 'ACCESSES']
|
|
799
799
|
RETURN r.type AS relType, target.id AS uid, target.name AS name, target.filePath AS filePath, labels(target)[0] AS kind
|
|
800
800
|
LIMIT 30
|
|
801
801
|
`, { symId });
|
|
@@ -1189,6 +1189,22 @@ export class LocalBackend {
|
|
|
1189
1189
|
};
|
|
1190
1190
|
}
|
|
1191
1191
|
async impact(repo, params) {
|
|
1192
|
+
try {
|
|
1193
|
+
return await this._impactImpl(repo, params);
|
|
1194
|
+
}
|
|
1195
|
+
catch (err) {
|
|
1196
|
+
// Return structured error instead of crashing (#321)
|
|
1197
|
+
return {
|
|
1198
|
+
error: (err instanceof Error ? err.message : String(err)) || 'Impact analysis failed',
|
|
1199
|
+
target: { name: params.target },
|
|
1200
|
+
direction: params.direction,
|
|
1201
|
+
impactedCount: 0,
|
|
1202
|
+
risk: 'UNKNOWN',
|
|
1203
|
+
suggestion: 'The graph query failed — try gitnexus context <symbol> as a fallback',
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
async _impactImpl(repo, params) {
|
|
1192
1208
|
await this.ensureInitialized(repo.id);
|
|
1193
1209
|
const { target, direction } = params;
|
|
1194
1210
|
const maxDepth = params.maxDepth || 3;
|
|
@@ -1213,6 +1229,7 @@ export class LocalBackend {
|
|
|
1213
1229
|
const impacted = [];
|
|
1214
1230
|
const visited = new Set([symId]);
|
|
1215
1231
|
let frontier = [symId];
|
|
1232
|
+
let traversalComplete = true;
|
|
1216
1233
|
for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {
|
|
1217
1234
|
const nextFrontier = [];
|
|
1218
1235
|
// Batch frontier nodes into a single Cypher query per depth level
|
|
@@ -1244,6 +1261,10 @@ export class LocalBackend {
|
|
|
1244
1261
|
}
|
|
1245
1262
|
catch (e) {
|
|
1246
1263
|
logQueryError('impact:depth-traversal', e);
|
|
1264
|
+
// Break out of depth loop on query failure but return partial results
|
|
1265
|
+
// collected so far, rather than silently swallowing the error (#321)
|
|
1266
|
+
traversalComplete = false;
|
|
1267
|
+
break;
|
|
1247
1268
|
}
|
|
1248
1269
|
frontier = nextFrontier;
|
|
1249
1270
|
}
|
|
@@ -1321,6 +1342,7 @@ export class LocalBackend {
|
|
|
1321
1342
|
direction,
|
|
1322
1343
|
impactedCount: impacted.length,
|
|
1323
1344
|
risk,
|
|
1345
|
+
...(!traversalComplete && { partial: true }),
|
|
1324
1346
|
summary: {
|
|
1325
1347
|
direct: directCount,
|
|
1326
1348
|
processes_affected: processCount,
|
package/dist/mcp/resources.js
CHANGED
|
@@ -271,6 +271,13 @@ nodes:
|
|
|
271
271
|
|
|
272
272
|
additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Namespace, Trait, Impl, TypeAlias, Const, Static, Property, Record, Delegate, Annotation, Constructor, Template, Module (use backticks in queries: \`Struct\`, \`Enum\`, etc.)"
|
|
273
273
|
|
|
274
|
+
node_properties:
|
|
275
|
+
common: "name (STRING), filePath (STRING), startLine (INT32), endLine (INT32)"
|
|
276
|
+
Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL)"
|
|
277
|
+
Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL)"
|
|
278
|
+
Property: "declaredType (STRING) — the field's type annotation (e.g., 'Address', 'City'). Used for field-access chain resolution."
|
|
279
|
+
Constructor: "parameterCount (INT32)"
|
|
280
|
+
|
|
274
281
|
relationships:
|
|
275
282
|
- CONTAINS: File/Folder contains child
|
|
276
283
|
- DEFINES: File defines a symbol
|
|
@@ -278,6 +285,10 @@ relationships:
|
|
|
278
285
|
- IMPORTS: Module imports
|
|
279
286
|
- EXTENDS: Class inheritance
|
|
280
287
|
- IMPLEMENTS: Interface implementation
|
|
288
|
+
- HAS_METHOD: Class/Struct/Interface owns a Method
|
|
289
|
+
- HAS_PROPERTY: Class/Struct/Interface owns a Property (field)
|
|
290
|
+
- ACCESSES: Function/Method reads or writes a Property (reason: 'read' or 'write')
|
|
291
|
+
- OVERRIDES: Method overrides another Method (MRO)
|
|
281
292
|
- MEMBER_OF: Symbol belongs to community
|
|
282
293
|
- STEP_IN_PROCESS: Symbol is step N in process
|
|
283
294
|
|
package/dist/mcp/server.js
CHANGED
|
@@ -15,6 +15,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
15
15
|
import { CompatibleStdioServerTransport } from './compatible-stdio-transport.js';
|
|
16
16
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
17
17
|
import { GITNEXUS_TOOLS } from './tools.js';
|
|
18
|
+
import { realStdoutWrite } from './core/lbug-adapter.js';
|
|
18
19
|
import { getResourceDefinitions, getResourceTemplates, readResource } from './resources.js';
|
|
19
20
|
/**
|
|
20
21
|
* Next-step hints appended to tool responses.
|
|
@@ -237,12 +238,22 @@ Follow these steps:
|
|
|
237
238
|
*/
|
|
238
239
|
export async function startMCPServer(backend) {
|
|
239
240
|
const server = createMCPServer(backend);
|
|
240
|
-
//
|
|
241
|
-
|
|
241
|
+
// Use the shared stdout reference captured at module-load time by the
|
|
242
|
+
// lbug-adapter. Avoids divergence if anything patches stdout between
|
|
243
|
+
// module load and server start.
|
|
244
|
+
const _safeStdout = new Proxy(process.stdout, {
|
|
245
|
+
get(target, prop, receiver) {
|
|
246
|
+
if (prop === 'write')
|
|
247
|
+
return realStdoutWrite;
|
|
248
|
+
const val = Reflect.get(target, prop, receiver);
|
|
249
|
+
return typeof val === 'function' ? val.bind(target) : val;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const transport = new CompatibleStdioServerTransport(process.stdin, _safeStdout);
|
|
242
253
|
await server.connect(transport);
|
|
243
254
|
// Graceful shutdown helper
|
|
244
255
|
let shuttingDown = false;
|
|
245
|
-
const shutdown = async () => {
|
|
256
|
+
const shutdown = async (exitCode = 0) => {
|
|
246
257
|
if (shuttingDown)
|
|
247
258
|
return;
|
|
248
259
|
shuttingDown = true;
|
|
@@ -254,11 +265,22 @@ export async function startMCPServer(backend) {
|
|
|
254
265
|
await server.close();
|
|
255
266
|
}
|
|
256
267
|
catch { }
|
|
257
|
-
process.exit(
|
|
268
|
+
process.exit(exitCode);
|
|
258
269
|
};
|
|
259
270
|
// Handle graceful shutdown
|
|
260
271
|
process.on('SIGINT', shutdown);
|
|
261
272
|
process.on('SIGTERM', shutdown);
|
|
273
|
+
// Log crashes to stderr so they aren't silently lost.
|
|
274
|
+
// uncaughtException is fatal — shut down.
|
|
275
|
+
// unhandledRejection is logged but kept non-fatal (availability-first):
|
|
276
|
+
// killing the server for one missed catch would be worse than logging it.
|
|
277
|
+
process.on('uncaughtException', (err) => {
|
|
278
|
+
process.stderr.write(`GitNexus MCP uncaughtException: ${err?.stack || err}\n`);
|
|
279
|
+
shutdown(1);
|
|
280
|
+
});
|
|
281
|
+
process.on('unhandledRejection', (reason) => {
|
|
282
|
+
process.stderr.write(`GitNexus MCP unhandledRejection: ${reason?.stack || reason}\n`);
|
|
283
|
+
});
|
|
262
284
|
// Handle stdio errors — stdin close means the parent process is gone
|
|
263
285
|
process.stdin.on('end', shutdown);
|
|
264
286
|
process.stdin.on('error', () => shutdown());
|
package/dist/mcp/tools.js
CHANGED
|
@@ -61,7 +61,7 @@ SCHEMA:
|
|
|
61
61
|
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process
|
|
62
62
|
- Multi-language nodes (use backticks): \`Struct\`, \`Enum\`, \`Trait\`, \`Impl\`, etc.
|
|
63
63
|
- All edges via single CodeRelation table with 'type' property
|
|
64
|
-
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, OVERRIDES, MEMBER_OF, STEP_IN_PROCESS
|
|
64
|
+
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES, OVERRIDES, MEMBER_OF, STEP_IN_PROCESS
|
|
65
65
|
- Edge properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)
|
|
66
66
|
|
|
67
67
|
EXAMPLES:
|
|
@@ -77,6 +77,12 @@ EXAMPLES:
|
|
|
77
77
|
• Find all methods of a class:
|
|
78
78
|
MATCH (c:Class {name: "UserService"})-[r:CodeRelation {type: 'HAS_METHOD'}]->(m:Method) RETURN m.name, m.parameterCount, m.returnType
|
|
79
79
|
|
|
80
|
+
• Find all properties of a class:
|
|
81
|
+
MATCH (c:Class {name: "User"})-[r:CodeRelation {type: 'HAS_PROPERTY'}]->(p:Property) RETURN p.name, p.declaredType
|
|
82
|
+
|
|
83
|
+
• Find all writers of a field:
|
|
84
|
+
MATCH (f:Function)-[r:CodeRelation {type: 'ACCESSES', reason: 'write'}]->(p:Property) WHERE p.name = "address" RETURN f.name, f.filePath
|
|
85
|
+
|
|
80
86
|
• Find method overrides (MRO resolution):
|
|
81
87
|
MATCH (winner:Method)-[r:CodeRelation {type: 'OVERRIDES'}]->(loser:Method) RETURN winner.name, winner.filePath, loser.filePath, r.reason
|
|
82
88
|
|
|
@@ -102,12 +108,14 @@ TIPS:
|
|
|
102
108
|
{
|
|
103
109
|
name: 'context',
|
|
104
110
|
description: `360-degree view of a single code symbol.
|
|
105
|
-
Shows categorized incoming/outgoing references (calls, imports, extends, implements), process participation, and file location.
|
|
111
|
+
Shows categorized incoming/outgoing references (calls, imports, extends, implements, methods, properties, overrides), process participation, and file location.
|
|
106
112
|
|
|
107
113
|
WHEN TO USE: After query() to understand a specific symbol in depth. When you need to know all callers, callees, and what execution flows a symbol participates in.
|
|
108
114
|
AFTER THIS: Use impact() if planning changes, or READ gitnexus://repo/{name}/process/{processName} for full execution trace.
|
|
109
115
|
|
|
110
|
-
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results
|
|
116
|
+
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results.
|
|
117
|
+
|
|
118
|
+
NOTE: ACCESSES edges (field read/write tracking) are included in context results with reason 'read' or 'write'. CALLS edges resolve through field access chains and method-call chains (e.g., user.address.getCity().save() produces CALLS edges at each step).`,
|
|
111
119
|
inputSchema: {
|
|
112
120
|
type: 'object',
|
|
113
121
|
properties: {
|
|
@@ -183,7 +191,9 @@ Depth groups:
|
|
|
183
191
|
- d=2: LIKELY AFFECTED (indirect)
|
|
184
192
|
- d=3: MAY NEED TESTING (transitive)
|
|
185
193
|
|
|
186
|
-
|
|
194
|
+
TIP: Default traversal uses CALLS/IMPORTS/EXTENDS/IMPLEMENTS. For class members, include HAS_METHOD and HAS_PROPERTY in relationTypes. For field access analysis, include ACCESSES in relationTypes.
|
|
195
|
+
|
|
196
|
+
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, OVERRIDES, ACCESSES
|
|
187
197
|
Confidence: 1.0 = certain, <0.8 = fuzzy match`,
|
|
188
198
|
inputSchema: {
|
|
189
199
|
type: 'object',
|
|
@@ -191,7 +201,7 @@ Confidence: 1.0 = certain, <0.8 = fuzzy match`,
|
|
|
191
201
|
target: { type: 'string', description: 'Name of function, class, or file to analyze' },
|
|
192
202
|
direction: { type: 'string', description: 'upstream (what depends on this) or downstream (what this depends on)' },
|
|
193
203
|
maxDepth: { type: 'number', description: 'Max relationship depth (default: 3)', default: 3 },
|
|
194
|
-
relationTypes: { type: 'array', items: { type: 'string' }, description: 'Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, OVERRIDES (default: usage-based)' },
|
|
204
|
+
relationTypes: { type: 'array', items: { type: 'string' }, description: 'Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, OVERRIDES, ACCESSES (default: usage-based, ACCESSES excluded by default)' },
|
|
195
205
|
includeTests: { type: 'boolean', description: 'Include test files (default: false)' },
|
|
196
206
|
minConfidence: { type: 'number', description: 'Minimum confidence 0-1 (default: 0.7)' },
|
|
197
207
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitnexus",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
@@ -39,13 +39,14 @@
|
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc",
|
|
41
41
|
"dev": "tsx watch src/cli/index.ts",
|
|
42
|
-
"test": "vitest run
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:unit": "vitest run test/unit",
|
|
43
44
|
"test:integration": "vitest run test/integration",
|
|
44
|
-
"test:all": "vitest run",
|
|
45
45
|
"test:watch": "vitest",
|
|
46
46
|
"test:coverage": "vitest run --coverage",
|
|
47
47
|
"prepare": "npm run build",
|
|
48
|
-
"postinstall": "node scripts/patch-tree-sitter-swift.cjs"
|
|
48
|
+
"postinstall": "node scripts/patch-tree-sitter-swift.cjs",
|
|
49
|
+
"prepack": "npm run build && chmod +x dist/cli/index.js"
|
|
49
50
|
},
|
|
50
51
|
"dependencies": {
|
|
51
52
|
"@huggingface/transformers": "^3.0.0",
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
"graphology": "^0.25.4",
|
|
59
60
|
"graphology-indices": "^0.17.0",
|
|
60
61
|
"graphology-utils": "^2.3.0",
|
|
61
|
-
"@ladybugdb/core": "^0.15.
|
|
62
|
+
"@ladybugdb/core": "^0.15.2",
|
|
62
63
|
"ignore": "^7.0.5",
|
|
63
64
|
"lru-cache": "^11.0.0",
|
|
64
65
|
"mnemonist": "^0.39.0",
|
|
File without changes
|