gitnexus 1.5.3 → 1.6.0
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 +10 -0
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +3 -1
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/mro-strategy.d.ts +19 -0
- package/dist/_shared/mro-strategy.d.ts.map +1 -0
- package/dist/_shared/mro-strategy.js +2 -0
- package/dist/_shared/mro-strategy.js.map +1 -0
- package/dist/cli/ai-context.d.ts +1 -0
- package/dist/cli/ai-context.js +28 -4
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +2 -1
- package/dist/cli/group.d.ts +2 -0
- package/dist/cli/group.js +233 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/serve.js +4 -1
- package/dist/cli/setup.js +34 -3
- package/dist/config/ignore-service.js +8 -3
- package/dist/core/augmentation/engine.js +1 -1
- package/dist/core/git-staleness.d.ts +13 -0
- package/dist/core/git-staleness.js +29 -0
- package/dist/core/group/bridge-db.d.ts +82 -0
- package/dist/core/group/bridge-db.js +460 -0
- package/dist/core/group/bridge-schema.d.ts +27 -0
- package/dist/core/group/bridge-schema.js +55 -0
- package/dist/core/group/config-parser.d.ts +3 -0
- package/dist/core/group/config-parser.js +83 -0
- package/dist/core/group/contract-extractor.d.ts +7 -0
- package/dist/core/group/contract-extractor.js +1 -0
- package/dist/core/group/extractors/grpc-extractor.d.ts +16 -0
- package/dist/core/group/extractors/grpc-extractor.js +264 -0
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +428 -0
- package/dist/core/group/extractors/topic-extractor.d.ts +9 -0
- package/dist/core/group/extractors/topic-extractor.js +234 -0
- package/dist/core/group/matching.d.ts +13 -0
- package/dist/core/group/matching.js +198 -0
- package/dist/core/group/normalization.d.ts +3 -0
- package/dist/core/group/normalization.js +115 -0
- package/dist/core/group/service-boundary-detector.d.ts +8 -0
- package/dist/core/group/service-boundary-detector.js +155 -0
- package/dist/core/group/service.d.ts +46 -0
- package/dist/core/group/service.js +160 -0
- package/dist/core/group/storage.d.ts +9 -0
- package/dist/core/group/storage.js +91 -0
- package/dist/core/group/sync.d.ts +21 -0
- package/dist/core/group/sync.js +148 -0
- package/dist/core/group/types.d.ts +130 -0
- package/dist/core/group/types.js +1 -0
- package/dist/core/ingestion/binding-accumulator.d.ts +207 -0
- package/dist/core/ingestion/binding-accumulator.js +332 -0
- package/dist/core/ingestion/call-processor.d.ts +155 -24
- package/dist/core/ingestion/call-processor.js +1129 -247
- package/dist/core/ingestion/class-extractors/generic.d.ts +2 -0
- package/dist/core/ingestion/class-extractors/generic.js +135 -0
- package/dist/core/ingestion/class-types.d.ts +34 -0
- package/dist/core/ingestion/class-types.js +1 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -0
- package/dist/core/ingestion/entry-point-scoring.js +1 -0
- package/dist/core/ingestion/field-types.d.ts +2 -2
- package/dist/core/ingestion/filesystem-walker.js +8 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +1 -0
- package/dist/core/ingestion/heritage-processor.d.ts +8 -15
- package/dist/core/ingestion/heritage-processor.js +15 -28
- package/dist/core/ingestion/import-processor.d.ts +1 -11
- package/dist/core/ingestion/import-processor.js +0 -12
- package/dist/core/ingestion/import-resolvers/utils.js +1 -0
- package/dist/core/ingestion/import-resolvers/vue.d.ts +8 -0
- package/dist/core/ingestion/import-resolvers/vue.js +9 -0
- package/dist/core/ingestion/language-provider.d.ts +6 -3
- package/dist/core/ingestion/languages/c-cpp.js +168 -1
- package/dist/core/ingestion/languages/csharp.js +20 -0
- package/dist/core/ingestion/languages/dart.js +26 -4
- package/dist/core/ingestion/languages/go.js +22 -0
- package/dist/core/ingestion/languages/index.d.ts +1 -0
- package/dist/core/ingestion/languages/index.js +2 -0
- package/dist/core/ingestion/languages/java.js +17 -0
- package/dist/core/ingestion/languages/kotlin.js +24 -1
- package/dist/core/ingestion/languages/php.js +23 -11
- package/dist/core/ingestion/languages/python.js +9 -0
- package/dist/core/ingestion/languages/ruby.js +28 -0
- package/dist/core/ingestion/languages/rust.js +38 -0
- package/dist/core/ingestion/languages/swift.js +31 -0
- package/dist/core/ingestion/languages/typescript.d.ts +1 -0
- package/dist/core/ingestion/languages/typescript.js +52 -3
- package/dist/core/ingestion/languages/vue.d.ts +13 -0
- package/dist/core/ingestion/languages/vue.js +81 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +5 -1
- package/dist/core/ingestion/method-extractors/configs/dart.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +376 -0
- package/dist/core/ingestion/method-extractors/configs/go.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/go.js +176 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +13 -4
- package/dist/core/ingestion/method-extractors/configs/php.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/php.js +304 -0
- package/dist/core/ingestion/method-extractors/configs/python.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/python.js +309 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/ruby.js +285 -0
- package/dist/core/ingestion/method-extractors/configs/rust.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/rust.js +195 -0
- package/dist/core/ingestion/method-extractors/configs/swift.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +277 -0
- package/dist/core/ingestion/method-extractors/configs/typescript-javascript.js +85 -8
- package/dist/core/ingestion/method-extractors/generic.js +38 -15
- package/dist/core/ingestion/method-types.d.ts +25 -0
- package/dist/core/ingestion/model/field-registry.d.ts +18 -0
- package/dist/core/ingestion/model/field-registry.js +22 -0
- package/dist/core/ingestion/model/heritage-map.d.ts +70 -0
- package/dist/core/ingestion/model/heritage-map.js +159 -0
- package/dist/core/ingestion/model/index.d.ts +20 -0
- package/dist/core/ingestion/model/index.js +41 -0
- package/dist/core/ingestion/model/method-registry.d.ts +62 -0
- package/dist/core/ingestion/model/method-registry.js +130 -0
- package/dist/core/ingestion/model/registration-table.d.ts +139 -0
- package/dist/core/ingestion/model/registration-table.js +224 -0
- package/dist/core/ingestion/model/resolution-context.d.ts +93 -0
- package/dist/core/ingestion/model/resolution-context.js +337 -0
- package/dist/core/ingestion/model/resolve.d.ts +56 -0
- package/dist/core/ingestion/model/resolve.js +242 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +86 -0
- package/dist/core/ingestion/model/semantic-model.js +120 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +222 -0
- package/dist/core/ingestion/model/symbol-table.js +206 -0
- package/dist/core/ingestion/model/type-registry.d.ts +39 -0
- package/dist/core/ingestion/model/type-registry.js +62 -0
- package/dist/core/ingestion/mro-processor.d.ts +4 -3
- package/dist/core/ingestion/mro-processor.js +310 -106
- package/dist/core/ingestion/parsing-processor.d.ts +5 -4
- package/dist/core/ingestion/parsing-processor.js +210 -85
- package/dist/core/ingestion/pipeline.d.ts +2 -0
- package/dist/core/ingestion/pipeline.js +192 -68
- package/dist/core/ingestion/tree-sitter-queries.d.ts +5 -5
- package/dist/core/ingestion/tree-sitter-queries.js +21 -0
- package/dist/core/ingestion/type-env.d.ts +15 -2
- package/dist/core/ingestion/type-env.js +163 -102
- package/dist/core/ingestion/type-extractors/csharp.js +17 -0
- package/dist/core/ingestion/type-extractors/jvm.js +11 -0
- package/dist/core/ingestion/type-extractors/php.js +0 -55
- package/dist/core/ingestion/type-extractors/ruby.js +0 -32
- package/dist/core/ingestion/type-extractors/swift.js +13 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +8 -8
- package/dist/core/ingestion/type-extractors/typescript.js +66 -69
- package/dist/core/ingestion/utils/ast-helpers.d.ts +33 -43
- package/dist/core/ingestion/utils/ast-helpers.js +129 -572
- package/dist/core/ingestion/utils/method-props.d.ts +32 -0
- package/dist/core/ingestion/utils/method-props.js +147 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +44 -0
- package/dist/core/ingestion/vue-sfc-extractor.js +94 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +31 -19
- package/dist/core/ingestion/workers/parse-worker.js +463 -198
- package/dist/core/lbug/lbug-adapter.d.ts +6 -0
- package/dist/core/lbug/lbug-adapter.js +68 -3
- package/dist/core/lbug/pool-adapter.d.ts +76 -0
- package/dist/core/lbug/pool-adapter.js +522 -0
- package/dist/core/run-analyze.d.ts +2 -0
- package/dist/core/run-analyze.js +1 -1
- package/dist/core/search/bm25-index.js +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -0
- package/dist/core/wiki/graph-queries.js +1 -1
- package/dist/mcp/core/embedder.js +6 -5
- package/dist/mcp/core/lbug-adapter.d.ts +3 -63
- package/dist/mcp/core/lbug-adapter.js +3 -484
- package/dist/mcp/local/local-backend.d.ts +31 -2
- package/dist/mcp/local/local-backend.js +255 -46
- package/dist/mcp/resources.js +5 -4
- package/dist/mcp/staleness.d.ts +3 -13
- package/dist/mcp/staleness.js +2 -31
- package/dist/mcp/tools.js +80 -4
- package/dist/server/analyze-job.d.ts +2 -0
- package/dist/server/analyze-job.js +4 -0
- package/dist/server/api.d.ts +20 -1
- package/dist/server/api.js +306 -71
- package/dist/server/git-clone.d.ts +2 -1
- package/dist/server/git-clone.js +98 -5
- package/dist/storage/git.d.ts +13 -0
- package/dist/storage/git.js +25 -0
- package/dist/storage/repo-manager.js +1 -1
- package/package.json +8 -2
- package/scripts/patch-tree-sitter-swift.cjs +78 -0
- package/dist/core/ingestion/named-binding-processor.d.ts +0 -18
- package/dist/core/ingestion/named-binding-processor.js +0 -42
- package/dist/core/ingestion/resolution-context.d.ts +0 -58
- package/dist/core/ingestion/resolution-context.js +0 -135
- package/dist/core/ingestion/symbol-table.d.ts +0 -79
- package/dist/core/ingestion/symbol-table.js +0 -115
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import path from 'path';
|
|
10
|
-
import { initLbug, executeQuery, executeParameterized, closeLbug, isLbugReady, isWriteQuery, } from '
|
|
10
|
+
import { initLbug, executeQuery, executeParameterized, closeLbug, isLbugReady, isWriteQuery, } from '../../core/lbug/pool-adapter.js';
|
|
11
11
|
export { isWriteQuery };
|
|
12
12
|
// Embedding imports are lazy (dynamic import) to avoid loading onnxruntime-node
|
|
13
13
|
// at MCP server startup — crashes on unsupported Node ABI versions (#89)
|
|
14
14
|
// git utilities available if needed
|
|
15
15
|
// import { isGitRepo, getCurrentCommit, getGitRoot } from '../../storage/git.js';
|
|
16
|
+
import { parseDiffHunks } from '../../storage/git.js';
|
|
16
17
|
import { listRegisteredRepos, cleanupOldKuzuFiles, } from '../../storage/repo-manager.js';
|
|
18
|
+
import { GroupService } from '../../core/group/service.js';
|
|
17
19
|
// AI context generation is CLI-only (gitnexus analyze)
|
|
18
20
|
// import { generateAIContextFiles } from '../../cli/ai-context.js';
|
|
19
21
|
/**
|
|
@@ -78,7 +80,9 @@ export const VALID_RELATION_TYPES = new Set([
|
|
|
78
80
|
'IMPLEMENTS',
|
|
79
81
|
'HAS_METHOD',
|
|
80
82
|
'HAS_PROPERTY',
|
|
81
|
-
'
|
|
83
|
+
'METHOD_OVERRIDES',
|
|
84
|
+
'OVERRIDES', // Legacy alias — dual-read for pre-rename indexes
|
|
85
|
+
'METHOD_IMPLEMENTS',
|
|
82
86
|
'ACCESSES',
|
|
83
87
|
'HANDLES_ROUTE',
|
|
84
88
|
'FETCHES',
|
|
@@ -98,7 +102,8 @@ export const VALID_RELATION_TYPES = new Set([
|
|
|
98
102
|
* CALLS / IMPORTS – direct, strongly-typed references → 0.9
|
|
99
103
|
* EXTENDS – class hierarchy, statically verifiable → 0.85
|
|
100
104
|
* IMPLEMENTS – interface contract, statically verifiable → 0.85
|
|
101
|
-
*
|
|
105
|
+
* METHOD_OVERRIDES – method override, statically verifiable → 0.85
|
|
106
|
+
* METHOD_IMPLEMENTS – interface method implementation, statically verifiable → 0.85
|
|
102
107
|
* HAS_METHOD – structural containment → 0.95
|
|
103
108
|
* HAS_PROPERTY – structural containment → 0.95
|
|
104
109
|
* ACCESSES – field read/write, may be indirect → 0.8
|
|
@@ -110,7 +115,8 @@ export const IMPACT_RELATION_CONFIDENCE = {
|
|
|
110
115
|
IMPORTS: 0.9,
|
|
111
116
|
EXTENDS: 0.85,
|
|
112
117
|
IMPLEMENTS: 0.85,
|
|
113
|
-
|
|
118
|
+
METHOD_OVERRIDES: 0.85,
|
|
119
|
+
METHOD_IMPLEMENTS: 0.85,
|
|
114
120
|
HAS_METHOD: 0.95,
|
|
115
121
|
HAS_PROPERTY: 0.95,
|
|
116
122
|
ACCESSES: 0.8,
|
|
@@ -132,6 +138,26 @@ export class LocalBackend {
|
|
|
132
138
|
initializedRepos = new Set();
|
|
133
139
|
reinitPromises = new Map();
|
|
134
140
|
lastStalenessCheck = new Map();
|
|
141
|
+
groupToolSvc = null;
|
|
142
|
+
/**
|
|
143
|
+
* Cross-repo group tools (CLI). Shares logic with MCP `group_*` handlers.
|
|
144
|
+
*/
|
|
145
|
+
getGroupService() {
|
|
146
|
+
if (!this.groupToolSvc) {
|
|
147
|
+
const port = {
|
|
148
|
+
resolveRepo: (p) => this.resolveRepo(p),
|
|
149
|
+
impact: (r, p) => this.impact(r, p),
|
|
150
|
+
query: (r, p) => this.query(r, p),
|
|
151
|
+
impactByUid: (id, uid, d, o) => this.impactByUid(id, uid, d, o),
|
|
152
|
+
};
|
|
153
|
+
this.groupToolSvc = new GroupService(port);
|
|
154
|
+
}
|
|
155
|
+
return this.groupToolSvc;
|
|
156
|
+
}
|
|
157
|
+
/** Close all pooled LadybugDB connections (CLI one-shot; optional for long-lived MCP). */
|
|
158
|
+
async dispose() {
|
|
159
|
+
await closeLbug();
|
|
160
|
+
}
|
|
135
161
|
// ─── Initialization ──────────────────────────────────────────────
|
|
136
162
|
/**
|
|
137
163
|
* Initialize from the global registry.
|
|
@@ -364,6 +390,9 @@ export class LocalBackend {
|
|
|
364
390
|
if (method === 'list_repos') {
|
|
365
391
|
return this.listRepos();
|
|
366
392
|
}
|
|
393
|
+
if (method.startsWith('group_')) {
|
|
394
|
+
return this.handleGroupTool(method, params || {});
|
|
395
|
+
}
|
|
367
396
|
// Resolve repo from optional param (re-reads registry on miss)
|
|
368
397
|
const repo = await this.resolveRepo(params?.repo);
|
|
369
398
|
switch (method) {
|
|
@@ -974,7 +1003,7 @@ export class LocalBackend {
|
|
|
974
1003
|
// Categorized incoming refs
|
|
975
1004
|
const incomingRows = await executeParameterized(repo.id, `
|
|
976
1005
|
MATCH (caller)-[r:CodeRelation]->(n {id: $symId})
|
|
977
|
-
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'OVERRIDES', 'ACCESSES']
|
|
1006
|
+
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'METHOD_OVERRIDES', 'OVERRIDES', 'METHOD_IMPLEMENTS', 'ACCESSES']
|
|
978
1007
|
RETURN r.type AS relType, caller.id AS uid, caller.name AS name, caller.filePath AS filePath, labels(caller)[0] AS kind
|
|
979
1008
|
LIMIT 30
|
|
980
1009
|
`, { symId });
|
|
@@ -1045,7 +1074,7 @@ export class LocalBackend {
|
|
|
1045
1074
|
// Categorized outgoing refs
|
|
1046
1075
|
const outgoingRows = await executeParameterized(repo.id, `
|
|
1047
1076
|
MATCH (n {id: $symId})-[r:CodeRelation]->(target)
|
|
1048
|
-
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'OVERRIDES', 'ACCESSES']
|
|
1077
|
+
WHERE r.type IN ['CALLS', 'IMPORTS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'HAS_PROPERTY', 'METHOD_OVERRIDES', 'OVERRIDES', 'METHOD_IMPLEMENTS', 'ACCESSES']
|
|
1049
1078
|
RETURN r.type AS relType, target.id AS uid, target.name AS name, target.filePath AS filePath, labels(target)[0] AS kind
|
|
1050
1079
|
LIMIT 30
|
|
1051
1080
|
`, { symId });
|
|
@@ -1077,16 +1106,50 @@ export class LocalBackend {
|
|
|
1077
1106
|
}
|
|
1078
1107
|
return cats;
|
|
1079
1108
|
};
|
|
1109
|
+
// Method/Function/Constructor enrichment: fetch method-specific properties
|
|
1110
|
+
const symKind = isClassLike ? resolvedLabel || 'Class' : sym.type || sym[2];
|
|
1111
|
+
const isMethodLike = symKind === 'Method' || symKind === 'Function' || symKind === 'Constructor';
|
|
1112
|
+
let methodMetadata;
|
|
1113
|
+
if (isMethodLike) {
|
|
1114
|
+
try {
|
|
1115
|
+
const metaRows = await executeParameterized(repo.id, `
|
|
1116
|
+
MATCH (n {id: $symId})
|
|
1117
|
+
RETURN n.visibility AS visibility, n.isStatic AS isStatic, n.isAbstract AS isAbstract,
|
|
1118
|
+
n.isFinal AS isFinal, n.isVirtual AS isVirtual, n.isOverride AS isOverride,
|
|
1119
|
+
n.isAsync AS isAsync, n.isPartial AS isPartial, n.returnType AS returnType,
|
|
1120
|
+
n.parameterCount AS parameterCount, n.isVariadic AS isVariadic,
|
|
1121
|
+
n.requiredParameterCount AS requiredParameterCount,
|
|
1122
|
+
n.parameterTypes AS parameterTypes, n.annotations AS annotations
|
|
1123
|
+
LIMIT 1
|
|
1124
|
+
`, { symId });
|
|
1125
|
+
if (metaRows.length > 0) {
|
|
1126
|
+
const row = metaRows[0];
|
|
1127
|
+
const meta = {};
|
|
1128
|
+
// Only include defined properties to distinguish "not applicable" from "not enriched"
|
|
1129
|
+
for (const key of Object.keys(row)) {
|
|
1130
|
+
const val = row[key];
|
|
1131
|
+
if (val !== null && val !== undefined)
|
|
1132
|
+
meta[key] = val;
|
|
1133
|
+
}
|
|
1134
|
+
if (Object.keys(meta).length > 0)
|
|
1135
|
+
methodMetadata = meta;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
catch {
|
|
1139
|
+
/* method metadata unavailable — omit silently */
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1080
1142
|
return {
|
|
1081
1143
|
status: 'found',
|
|
1082
1144
|
symbol: {
|
|
1083
1145
|
uid: sym.id || sym[0],
|
|
1084
1146
|
name: sym.name || sym[1],
|
|
1085
|
-
kind:
|
|
1147
|
+
kind: symKind,
|
|
1086
1148
|
filePath: sym.filePath || sym[3],
|
|
1087
1149
|
startLine: sym.startLine || sym[4],
|
|
1088
1150
|
endLine: sym.endLine || sym[5],
|
|
1089
1151
|
...(include_content && (sym.content || sym[6]) ? { content: sym.content || sym[6] } : {}),
|
|
1152
|
+
...(methodMetadata ? { methodMetadata } : {}),
|
|
1090
1153
|
},
|
|
1091
1154
|
incoming: categorize(incomingRows),
|
|
1092
1155
|
outgoing: categorize(outgoingRows),
|
|
@@ -1197,33 +1260,30 @@ export class LocalBackend {
|
|
|
1197
1260
|
let diffArgs;
|
|
1198
1261
|
switch (scope) {
|
|
1199
1262
|
case 'staged':
|
|
1200
|
-
diffArgs = ['diff', '--staged', '
|
|
1263
|
+
diffArgs = ['diff', '--staged', '-U0'];
|
|
1201
1264
|
break;
|
|
1202
1265
|
case 'all':
|
|
1203
|
-
diffArgs = ['diff', 'HEAD', '
|
|
1266
|
+
diffArgs = ['diff', 'HEAD', '-U0'];
|
|
1204
1267
|
break;
|
|
1205
1268
|
case 'compare':
|
|
1206
1269
|
if (!params.base_ref)
|
|
1207
1270
|
return { error: 'base_ref is required for "compare" scope' };
|
|
1208
|
-
diffArgs = ['diff', params.base_ref, '
|
|
1271
|
+
diffArgs = ['diff', params.base_ref, '-U0'];
|
|
1209
1272
|
break;
|
|
1210
1273
|
case 'unstaged':
|
|
1211
1274
|
default:
|
|
1212
|
-
diffArgs = ['diff', '
|
|
1275
|
+
diffArgs = ['diff', '-U0'];
|
|
1213
1276
|
break;
|
|
1214
1277
|
}
|
|
1215
|
-
let
|
|
1278
|
+
let diffOutput;
|
|
1216
1279
|
try {
|
|
1217
|
-
|
|
1218
|
-
changedFiles = output
|
|
1219
|
-
.trim()
|
|
1220
|
-
.split('\n')
|
|
1221
|
-
.filter((f) => f.length > 0);
|
|
1280
|
+
diffOutput = execFileSync('git', diffArgs, { cwd: repo.repoPath, encoding: 'utf-8' });
|
|
1222
1281
|
}
|
|
1223
1282
|
catch (err) {
|
|
1224
1283
|
return { error: `Git diff failed: ${err.message}` };
|
|
1225
1284
|
}
|
|
1226
|
-
|
|
1285
|
+
const fileDiffs = parseDiffHunks(diffOutput);
|
|
1286
|
+
if (fileDiffs.length === 0) {
|
|
1227
1287
|
return {
|
|
1228
1288
|
summary: {
|
|
1229
1289
|
changed_count: 0,
|
|
@@ -1235,23 +1295,36 @@ export class LocalBackend {
|
|
|
1235
1295
|
affected_processes: [],
|
|
1236
1296
|
};
|
|
1237
1297
|
}
|
|
1238
|
-
// Map
|
|
1298
|
+
// Map diff hunks to indexed symbols via range overlap
|
|
1239
1299
|
const changedSymbols = [];
|
|
1240
|
-
for (const
|
|
1241
|
-
|
|
1300
|
+
for (const fileDiff of fileDiffs) {
|
|
1301
|
+
if (fileDiff.hunks.length === 0)
|
|
1302
|
+
continue;
|
|
1303
|
+
// Build range overlap conditions for all hunks in this file
|
|
1304
|
+
const overlapConditions = fileDiff.hunks
|
|
1305
|
+
.map((_, i) => `(n.startLine <= $hunkEnd${i} AND n.endLine >= $hunkStart${i})`)
|
|
1306
|
+
.join(' OR ');
|
|
1307
|
+
const queryParams = { filePath: fileDiff.filePath };
|
|
1308
|
+
fileDiff.hunks.forEach((hunk, i) => {
|
|
1309
|
+
queryParams[`hunkStart${i}`] = hunk.startLine;
|
|
1310
|
+
queryParams[`hunkEnd${i}`] = hunk.endLine;
|
|
1311
|
+
});
|
|
1312
|
+
const symbolQuery = `
|
|
1313
|
+
MATCH (n) WHERE n.filePath ENDS WITH $filePath
|
|
1314
|
+
AND n.startLine IS NOT NULL AND n.endLine IS NOT NULL
|
|
1315
|
+
AND (${overlapConditions})
|
|
1316
|
+
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type,
|
|
1317
|
+
n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
|
|
1318
|
+
`;
|
|
1242
1319
|
try {
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
|
|
1246
|
-
LIMIT 20
|
|
1247
|
-
`, { filePath: normalizedFile });
|
|
1248
|
-
for (const sym of symbols) {
|
|
1320
|
+
const rows = await executeParameterized(repo.id, symbolQuery, queryParams);
|
|
1321
|
+
for (const sym of rows) {
|
|
1249
1322
|
changedSymbols.push({
|
|
1250
1323
|
id: sym.id || sym[0],
|
|
1251
1324
|
name: sym.name || sym[1],
|
|
1252
1325
|
type: sym.type || sym[2],
|
|
1253
1326
|
filePath: sym.filePath || sym[3],
|
|
1254
|
-
change_type: '
|
|
1327
|
+
change_type: 'touched',
|
|
1255
1328
|
});
|
|
1256
1329
|
}
|
|
1257
1330
|
}
|
|
@@ -1259,28 +1332,33 @@ export class LocalBackend {
|
|
|
1259
1332
|
logQueryError('detect-changes:file-symbols', e);
|
|
1260
1333
|
}
|
|
1261
1334
|
}
|
|
1262
|
-
// Find affected processes
|
|
1335
|
+
// Find affected processes -- single batched query instead of N+1
|
|
1263
1336
|
const affectedProcesses = new Map();
|
|
1264
|
-
|
|
1337
|
+
if (changedSymbols.length > 0) {
|
|
1338
|
+
const symIds = changedSymbols.map((s) => s.id);
|
|
1339
|
+
const symNameById = new Map(changedSymbols.map((s) => [s.id, s.name]));
|
|
1265
1340
|
try {
|
|
1266
1341
|
const procs = await executeParameterized(repo.id, `
|
|
1267
|
-
MATCH (n
|
|
1268
|
-
|
|
1269
|
-
|
|
1342
|
+
MATCH (n)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
|
|
1343
|
+
WHERE n.id IN $ids
|
|
1344
|
+
RETURN n.id AS nodeId, p.id AS pid, p.heuristicLabel AS label,
|
|
1345
|
+
p.processType AS processType, p.stepCount AS stepCount, r.step AS step
|
|
1346
|
+
`, { ids: symIds });
|
|
1270
1347
|
for (const proc of procs) {
|
|
1271
|
-
const
|
|
1348
|
+
const nodeId = proc.nodeId || proc[0];
|
|
1349
|
+
const pid = proc.pid || proc[1];
|
|
1272
1350
|
if (!affectedProcesses.has(pid)) {
|
|
1273
1351
|
affectedProcesses.set(pid, {
|
|
1274
1352
|
id: pid,
|
|
1275
|
-
name: proc.label || proc[
|
|
1276
|
-
process_type: proc.processType || proc[
|
|
1277
|
-
step_count: proc.stepCount || proc[
|
|
1353
|
+
name: proc.label || proc[2],
|
|
1354
|
+
process_type: proc.processType || proc[3],
|
|
1355
|
+
step_count: proc.stepCount || proc[4],
|
|
1278
1356
|
changed_steps: [],
|
|
1279
1357
|
});
|
|
1280
1358
|
}
|
|
1281
1359
|
affectedProcesses.get(pid).changed_steps.push({
|
|
1282
|
-
symbol:
|
|
1283
|
-
step: proc.step || proc[
|
|
1360
|
+
symbol: symNameById.get(nodeId) ?? nodeId,
|
|
1361
|
+
step: proc.step || proc[5],
|
|
1284
1362
|
});
|
|
1285
1363
|
}
|
|
1286
1364
|
}
|
|
@@ -1300,7 +1378,7 @@ export class LocalBackend {
|
|
|
1300
1378
|
summary: {
|
|
1301
1379
|
changed_count: changedSymbols.length,
|
|
1302
1380
|
affected_count: processCount,
|
|
1303
|
-
changed_files:
|
|
1381
|
+
changed_files: fileDiffs.length,
|
|
1304
1382
|
risk_level: risk,
|
|
1305
1383
|
},
|
|
1306
1384
|
changed_symbols: changedSymbols,
|
|
@@ -1494,14 +1572,32 @@ export class LocalBackend {
|
|
|
1494
1572
|
await this.ensureInitialized(repo.id);
|
|
1495
1573
|
const { target, direction } = params;
|
|
1496
1574
|
const maxDepth = params.maxDepth || 3;
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1575
|
+
// Map legacy relation type names before filtering (backward compat for OVERRIDES → METHOD_OVERRIDES)
|
|
1576
|
+
const mappedRelTypes = params.relationTypes?.flatMap((t) => t === 'OVERRIDES' ? ['OVERRIDES', 'METHOD_OVERRIDES'] : [t]);
|
|
1577
|
+
const rawRelTypes = mappedRelTypes && mappedRelTypes.length > 0
|
|
1578
|
+
? mappedRelTypes.filter((t) => VALID_RELATION_TYPES.has(t))
|
|
1579
|
+
: [
|
|
1580
|
+
'CALLS',
|
|
1581
|
+
'IMPORTS',
|
|
1582
|
+
'EXTENDS',
|
|
1583
|
+
'IMPLEMENTS',
|
|
1584
|
+
'METHOD_OVERRIDES',
|
|
1585
|
+
'OVERRIDES',
|
|
1586
|
+
'METHOD_IMPLEMENTS',
|
|
1587
|
+
];
|
|
1588
|
+
const relationTypes = rawRelTypes.length > 0
|
|
1589
|
+
? rawRelTypes
|
|
1590
|
+
: [
|
|
1591
|
+
'CALLS',
|
|
1592
|
+
'IMPORTS',
|
|
1593
|
+
'EXTENDS',
|
|
1594
|
+
'IMPLEMENTS',
|
|
1595
|
+
'METHOD_OVERRIDES',
|
|
1596
|
+
'OVERRIDES',
|
|
1597
|
+
'METHOD_IMPLEMENTS',
|
|
1598
|
+
];
|
|
1501
1599
|
const includeTests = params.includeTests ?? false;
|
|
1502
1600
|
const minConfidence = params.minConfidence ?? 0;
|
|
1503
|
-
const relTypeFilter = relationTypes.map((t) => `'${t}'`).join(', ');
|
|
1504
|
-
const confidenceFilter = minConfidence > 0 ? ` AND r.confidence >= ${minConfidence}` : '';
|
|
1505
1601
|
// Resolve target by name, preferring Class/Interface over Constructor
|
|
1506
1602
|
// (fix #480: Java class and constructor share the same name).
|
|
1507
1603
|
// labels(n)[0] returns empty string in LadybugDB, so we use explicit
|
|
@@ -1550,6 +1646,20 @@ export class LocalBackend {
|
|
|
1550
1646
|
}
|
|
1551
1647
|
if (!sym)
|
|
1552
1648
|
return { error: `Target '${target}' not found` };
|
|
1649
|
+
return this._runImpactBFS(repo, sym, symType, direction, {
|
|
1650
|
+
maxDepth,
|
|
1651
|
+
relationTypes,
|
|
1652
|
+
includeTests,
|
|
1653
|
+
minConfidence,
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Shared BFS traversal for impact analysis (name-resolved or UID-resolved symbol).
|
|
1658
|
+
*/
|
|
1659
|
+
async _runImpactBFS(repo, sym, symType, direction, opts) {
|
|
1660
|
+
const { maxDepth, relationTypes, includeTests, minConfidence } = opts;
|
|
1661
|
+
const relTypeFilter = relationTypes.map((t) => `'${t}'`).join(', ');
|
|
1662
|
+
const confidenceFilter = minConfidence > 0 ? ` AND r.confidence >= ${minConfidence}` : '';
|
|
1553
1663
|
const symId = sym.id || sym[0];
|
|
1554
1664
|
const impacted = [];
|
|
1555
1665
|
const visited = new Set([symId]);
|
|
@@ -1891,6 +2001,105 @@ export class LocalBackend {
|
|
|
1891
2001
|
byDepth: grouped,
|
|
1892
2002
|
};
|
|
1893
2003
|
}
|
|
2004
|
+
/**
|
|
2005
|
+
* UID-based impact for cross-repo fan-out. Same result shape as `impact`.
|
|
2006
|
+
* Returns null if the repo is unknown, the UID is missing, or analysis fails.
|
|
2007
|
+
*/
|
|
2008
|
+
async impactByUid(repoId, uid, direction, opts) {
|
|
2009
|
+
try {
|
|
2010
|
+
await this.refreshRepos();
|
|
2011
|
+
await this.ensureInitialized(repoId);
|
|
2012
|
+
}
|
|
2013
|
+
catch {
|
|
2014
|
+
return null;
|
|
2015
|
+
}
|
|
2016
|
+
const repo = this.repos.get(repoId);
|
|
2017
|
+
if (!repo)
|
|
2018
|
+
return null;
|
|
2019
|
+
const dir = direction === 'downstream' ? 'downstream' : 'upstream';
|
|
2020
|
+
let rows;
|
|
2021
|
+
try {
|
|
2022
|
+
rows = await executeParameterized(repoId, `MATCH (n) WHERE n.id = $uid
|
|
2023
|
+
RETURN n.id AS id, n.name AS name, n.filePath AS filePath, labels(n)[0] AS type
|
|
2024
|
+
LIMIT 1`, { uid });
|
|
2025
|
+
}
|
|
2026
|
+
catch {
|
|
2027
|
+
return null;
|
|
2028
|
+
}
|
|
2029
|
+
if (!rows?.length)
|
|
2030
|
+
return null;
|
|
2031
|
+
const sym = rows[0];
|
|
2032
|
+
const labelRaw = sym.type ?? sym[3];
|
|
2033
|
+
const symType = typeof labelRaw === 'string' && labelRaw.trim().length > 0 ? labelRaw.trim() : '';
|
|
2034
|
+
// Map legacy relation type names (backward compat for OVERRIDES → METHOD_OVERRIDES)
|
|
2035
|
+
const mappedRelTypes = opts.relationTypes?.flatMap((t) => t === 'OVERRIDES' ? ['OVERRIDES', 'METHOD_OVERRIDES'] : [t]);
|
|
2036
|
+
const rawRelTypes = mappedRelTypes && mappedRelTypes.length > 0
|
|
2037
|
+
? mappedRelTypes.filter((t) => VALID_RELATION_TYPES.has(t))
|
|
2038
|
+
: [
|
|
2039
|
+
'CALLS',
|
|
2040
|
+
'IMPORTS',
|
|
2041
|
+
'EXTENDS',
|
|
2042
|
+
'IMPLEMENTS',
|
|
2043
|
+
'METHOD_OVERRIDES',
|
|
2044
|
+
'OVERRIDES',
|
|
2045
|
+
'METHOD_IMPLEMENTS',
|
|
2046
|
+
];
|
|
2047
|
+
const relationTypes = rawRelTypes.length > 0
|
|
2048
|
+
? rawRelTypes
|
|
2049
|
+
: [
|
|
2050
|
+
'CALLS',
|
|
2051
|
+
'IMPORTS',
|
|
2052
|
+
'EXTENDS',
|
|
2053
|
+
'IMPLEMENTS',
|
|
2054
|
+
'METHOD_OVERRIDES',
|
|
2055
|
+
'OVERRIDES',
|
|
2056
|
+
'METHOD_IMPLEMENTS',
|
|
2057
|
+
];
|
|
2058
|
+
try {
|
|
2059
|
+
return await this._runImpactBFS(repo, sym, symType, dir, {
|
|
2060
|
+
maxDepth: opts.maxDepth,
|
|
2061
|
+
relationTypes,
|
|
2062
|
+
includeTests: opts.includeTests,
|
|
2063
|
+
minConfidence: opts.minConfidence,
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
catch {
|
|
2067
|
+
return null;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
handleGroupTool(method, params) {
|
|
2071
|
+
switch (method) {
|
|
2072
|
+
case 'group_list':
|
|
2073
|
+
return this.groupList(params);
|
|
2074
|
+
case 'group_sync':
|
|
2075
|
+
return this.groupSync(params);
|
|
2076
|
+
case 'group_contracts':
|
|
2077
|
+
return this.groupContracts(params);
|
|
2078
|
+
case 'group_query':
|
|
2079
|
+
return this.groupQuery(params);
|
|
2080
|
+
case 'group_status':
|
|
2081
|
+
return this.groupStatus(params);
|
|
2082
|
+
default:
|
|
2083
|
+
throw new Error(`Unknown group tool: ${method}`);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
async groupList(params) {
|
|
2087
|
+
return this.getGroupService().groupList(params);
|
|
2088
|
+
}
|
|
2089
|
+
async groupSync(params) {
|
|
2090
|
+
return this.getGroupService().groupSync(params);
|
|
2091
|
+
}
|
|
2092
|
+
async groupContracts(params) {
|
|
2093
|
+
return this.getGroupService().groupContracts(params);
|
|
2094
|
+
}
|
|
2095
|
+
async groupQuery(params) {
|
|
2096
|
+
await this.refreshRepos();
|
|
2097
|
+
return this.getGroupService().groupQuery(params);
|
|
2098
|
+
}
|
|
2099
|
+
async groupStatus(params) {
|
|
2100
|
+
await this.refreshRepos();
|
|
2101
|
+
return this.getGroupService().groupStatus(params);
|
|
2102
|
+
}
|
|
1894
2103
|
/**
|
|
1895
2104
|
* Fetch Route nodes with their consumers in a single query.
|
|
1896
2105
|
* Shared by routeMap and shapeCheck to avoid N+1 query patterns.
|
package/dist/mcp/resources.js
CHANGED
|
@@ -281,10 +281,10 @@ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Nam
|
|
|
281
281
|
|
|
282
282
|
node_properties:
|
|
283
283
|
common: "name (STRING), filePath (STRING), startLine (INT32), endLine (INT32)"
|
|
284
|
-
Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL)"
|
|
285
|
-
Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL)"
|
|
284
|
+
Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isVirtual (BOOL), isOverride (BOOL), isAsync (BOOL), isPartial (BOOL), requiredParameterCount (INT32), parameterTypes (STRING[]), annotations (STRING[])"
|
|
285
|
+
Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isAsync (BOOL), parameterTypes (STRING[]), annotations (STRING[])"
|
|
286
286
|
Property: "declaredType (STRING) — the field's type annotation (e.g., 'Address', 'City'). Used for field-access chain resolution."
|
|
287
|
-
Constructor: "parameterCount (INT32)"
|
|
287
|
+
Constructor: "parameterCount (INT32), visibility (STRING), isStatic (BOOL), parameterTypes (STRING[])"
|
|
288
288
|
Community: "heuristicLabel (STRING), cohesion (DOUBLE), symbolCount (INT32), keywords (STRING[]), description (STRING), enrichedBy (STRING)"
|
|
289
289
|
Process: "heuristicLabel (STRING), processType (STRING — 'intra_community' or 'cross_community'), stepCount (INT32), communities (STRING[]), entryPointId (STRING), terminalId (STRING)"
|
|
290
290
|
|
|
@@ -298,7 +298,8 @@ relationships:
|
|
|
298
298
|
- HAS_METHOD: Class/Struct/Interface owns a Method
|
|
299
299
|
- HAS_PROPERTY: Class/Struct/Interface owns a Property (field)
|
|
300
300
|
- ACCESSES: Function/Method reads or writes a Property (reason: 'read' or 'write')
|
|
301
|
-
-
|
|
301
|
+
- METHOD_OVERRIDES: Method overrides another Method (MRO)
|
|
302
|
+
- METHOD_IMPLEMENTS: ConcreteMethod implements InterfaceMethod (matched by name + parameterTypes)
|
|
302
303
|
- MEMBER_OF: Symbol belongs to community
|
|
303
304
|
- STEP_IN_PROCESS: Symbol is step N in process
|
|
304
305
|
|
package/dist/mcp/staleness.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Staleness Check
|
|
3
|
-
*
|
|
4
|
-
* Checks if the GitNexus index is behind the current git HEAD.
|
|
5
|
-
* Returns a hint for the LLM to call analyze if stale.
|
|
2
|
+
* Staleness Check — re-export from core (see `core/git-staleness.ts`).
|
|
6
3
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
commitsBehind: number;
|
|
10
|
-
hint?: string;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Check how many commits the index is behind HEAD
|
|
14
|
-
*/
|
|
15
|
-
export declare function checkStaleness(repoPath: string, lastCommit: string): StalenessInfo;
|
|
4
|
+
export type { StalenessInfo } from '../core/git-staleness.js';
|
|
5
|
+
export { checkStaleness } from '../core/git-staleness.js';
|
package/dist/mcp/staleness.js
CHANGED
|
@@ -1,33 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Staleness Check
|
|
3
|
-
*
|
|
4
|
-
* Checks if the GitNexus index is behind the current git HEAD.
|
|
5
|
-
* Returns a hint for the LLM to call analyze if stale.
|
|
2
|
+
* Staleness Check — re-export from core (see `core/git-staleness.ts`).
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Check how many commits the index is behind HEAD
|
|
10
|
-
*/
|
|
11
|
-
export function checkStaleness(repoPath, lastCommit) {
|
|
12
|
-
try {
|
|
13
|
-
// Get count of commits between lastCommit and HEAD
|
|
14
|
-
const result = execFileSync('git', ['rev-list', '--count', `${lastCommit}..HEAD`], {
|
|
15
|
-
cwd: repoPath,
|
|
16
|
-
encoding: 'utf-8',
|
|
17
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
18
|
-
}).trim();
|
|
19
|
-
const commitsBehind = parseInt(result, 10) || 0;
|
|
20
|
-
if (commitsBehind > 0) {
|
|
21
|
-
return {
|
|
22
|
-
isStale: true,
|
|
23
|
-
commitsBehind,
|
|
24
|
-
hint: `⚠️ Index is ${commitsBehind} commit${commitsBehind > 1 ? 's' : ''} behind HEAD. Run analyze tool to update.`,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
return { isStale: false, commitsBehind: 0 };
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// If git command fails, assume not stale (fail open)
|
|
31
|
-
return { isStale: false, commitsBehind: 0 };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
4
|
+
export { checkStaleness } from '../core/git-staleness.js';
|
package/dist/mcp/tools.js
CHANGED
|
@@ -78,7 +78,7 @@ SCHEMA:
|
|
|
78
78
|
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process, Route, Tool
|
|
79
79
|
- Multi-language nodes (use backticks): \`Struct\`, \`Enum\`, \`Trait\`, \`Impl\`, etc.
|
|
80
80
|
- All edges via single CodeRelation table with 'type' property
|
|
81
|
-
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES,
|
|
81
|
+
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES, METHOD_OVERRIDES, METHOD_IMPLEMENTS, MEMBER_OF, STEP_IN_PROCESS, HANDLES_ROUTE, FETCHES, HANDLES_TOOL, ENTRY_POINT_OF
|
|
82
82
|
- Edge properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)
|
|
83
83
|
|
|
84
84
|
EXAMPLES:
|
|
@@ -101,7 +101,7 @@ EXAMPLES:
|
|
|
101
101
|
MATCH (f:Function)-[r:CodeRelation {type: 'ACCESSES', reason: 'write'}]->(p:Property) WHERE p.name = "address" RETURN f.name, f.filePath
|
|
102
102
|
|
|
103
103
|
• Find method overrides (MRO resolution):
|
|
104
|
-
MATCH (winner:Method)-[r:CodeRelation {type: '
|
|
104
|
+
MATCH (winner:Method)-[r:CodeRelation {type: 'METHOD_OVERRIDES'}]->(loser:Method) RETURN winner.name, winner.filePath, loser.filePath, r.reason
|
|
105
105
|
|
|
106
106
|
• Detect diamond inheritance:
|
|
107
107
|
MATCH (d:Class)-[:CodeRelation {type: 'EXTENDS'}]->(b1), (d)-[:CodeRelation {type: 'EXTENDS'}]->(b2), (b1)-[:CodeRelation {type: 'EXTENDS'}]->(a), (b2)-[:CodeRelation {type: 'EXTENDS'}]->(a) WHERE b1 <> b2 RETURN d.name, b1.name, b2.name, a.name
|
|
@@ -244,7 +244,7 @@ Depth groups:
|
|
|
244
244
|
|
|
245
245
|
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.
|
|
246
246
|
|
|
247
|
-
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY,
|
|
247
|
+
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, METHOD_OVERRIDES, METHOD_IMPLEMENTS, ACCESSES
|
|
248
248
|
Confidence: 1.0 = certain, <0.8 = fuzzy match`,
|
|
249
249
|
inputSchema: {
|
|
250
250
|
type: 'object',
|
|
@@ -262,7 +262,7 @@ Confidence: 1.0 = certain, <0.8 = fuzzy match`,
|
|
|
262
262
|
relationTypes: {
|
|
263
263
|
type: 'array',
|
|
264
264
|
items: { type: 'string' },
|
|
265
|
-
description: 'Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY,
|
|
265
|
+
description: 'Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, METHOD_OVERRIDES, METHOD_IMPLEMENTS, ACCESSES (default: usage-based, ACCESSES excluded by default)',
|
|
266
266
|
},
|
|
267
267
|
includeTests: { type: 'boolean', description: 'Include test files (default: false)' },
|
|
268
268
|
minConfidence: { type: 'number', description: 'Minimum confidence 0-1 (default: 0.7)' },
|
|
@@ -355,4 +355,80 @@ Returns: single route object when one match, or { routes: [...], total: N } for
|
|
|
355
355
|
required: [],
|
|
356
356
|
},
|
|
357
357
|
},
|
|
358
|
+
{
|
|
359
|
+
name: 'group_list',
|
|
360
|
+
description: `List all configured repository groups, or return details for one group (repos, manifest links).
|
|
361
|
+
|
|
362
|
+
WHEN TO USE: Discover groups before group_sync. Optional "name" returns a single group's config.`,
|
|
363
|
+
inputSchema: {
|
|
364
|
+
type: 'object',
|
|
365
|
+
properties: {
|
|
366
|
+
name: { type: 'string', description: 'Group name. Omit to list all groups.' },
|
|
367
|
+
},
|
|
368
|
+
required: [],
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: 'group_sync',
|
|
373
|
+
description: `Rebuild the Contract Registry (contracts.json) for a group: extract HTTP contracts, apply manifest links, exact-match cross-links.
|
|
374
|
+
|
|
375
|
+
WHEN TO USE: After changing group.yaml or re-indexing member repos.`,
|
|
376
|
+
inputSchema: {
|
|
377
|
+
type: 'object',
|
|
378
|
+
properties: {
|
|
379
|
+
name: { type: 'string', description: 'Group name' },
|
|
380
|
+
skipEmbeddings: {
|
|
381
|
+
type: 'boolean',
|
|
382
|
+
description: 'Exact + BM25 only (Demo PR: same as default exact path)',
|
|
383
|
+
},
|
|
384
|
+
exactOnly: { type: 'boolean', description: 'Exact match only in cascade' },
|
|
385
|
+
},
|
|
386
|
+
required: ['name'],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
name: 'group_contracts',
|
|
391
|
+
description: `Inspect contracts and cross-links from the group's contracts.json.
|
|
392
|
+
|
|
393
|
+
WHEN TO USE: Debug cross-repo links after group_sync.`,
|
|
394
|
+
inputSchema: {
|
|
395
|
+
type: 'object',
|
|
396
|
+
properties: {
|
|
397
|
+
name: { type: 'string', description: 'Group name' },
|
|
398
|
+
type: { type: 'string', description: 'Filter by contract type (http, topic, …)' },
|
|
399
|
+
repo: { type: 'string', description: 'Filter by group repo path (e.g. app/backend)' },
|
|
400
|
+
unmatchedOnly: { type: 'boolean', description: 'Only contracts with no cross-link' },
|
|
401
|
+
},
|
|
402
|
+
required: ['name'],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: 'group_query',
|
|
407
|
+
description: `Run the query tool across all repos in a group and merge process results via reciprocal rank fusion.
|
|
408
|
+
|
|
409
|
+
WHEN TO USE: Semantic / hybrid search across a whole product group.`,
|
|
410
|
+
inputSchema: {
|
|
411
|
+
type: 'object',
|
|
412
|
+
properties: {
|
|
413
|
+
name: { type: 'string', description: 'Group name' },
|
|
414
|
+
query: { type: 'string', description: 'Search query' },
|
|
415
|
+
subgroup: { type: 'string', description: 'Limit to repo paths under this prefix' },
|
|
416
|
+
limit: { type: 'number', description: 'Max merged results (default 5)' },
|
|
417
|
+
},
|
|
418
|
+
required: ['name', 'query'],
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: 'group_status',
|
|
423
|
+
description: `Report index staleness (commit vs HEAD) and Contract Registry staleness (indexedAt) for each repo in a group.
|
|
424
|
+
|
|
425
|
+
WHEN TO USE: Before group_sync or when agents should refresh indexes.`,
|
|
426
|
+
inputSchema: {
|
|
427
|
+
type: 'object',
|
|
428
|
+
properties: {
|
|
429
|
+
name: { type: 'string', description: 'Group name' },
|
|
430
|
+
},
|
|
431
|
+
required: ['name'],
|
|
432
|
+
},
|
|
433
|
+
},
|
|
358
434
|
];
|
|
@@ -40,6 +40,8 @@ export declare class JobManager {
|
|
|
40
40
|
repoPath?: string;
|
|
41
41
|
}): AnalyzeJob;
|
|
42
42
|
getJob(id: string): AnalyzeJob | undefined;
|
|
43
|
+
/** Return a snapshot of all tracked jobs for inspection. */
|
|
44
|
+
listJobs(): AnalyzeJob[];
|
|
43
45
|
updateJob(id: string, update: Partial<Pick<AnalyzeJob, 'status' | 'progress' | 'error' | 'repoPath' | 'repoName' | 'completedAt'>>): void;
|
|
44
46
|
/** Register a child process for a job — enables cancellation and timeout. */
|
|
45
47
|
registerChild(jobId: string, child: ChildProcess): void;
|