lsp-intelligence 0.1.2 → 0.2.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 +12 -7
- package/dist/analysis/pattern/collectSearchFiles.d.ts +5 -0
- package/dist/analysis/pattern/collectSearchFiles.js +38 -0
- package/dist/analysis/pattern/collectSearchFiles.js.map +1 -0
- package/dist/analysis/pattern/runPatternSearch.d.ts +17 -0
- package/dist/analysis/pattern/runPatternSearch.js +63 -0
- package/dist/analysis/pattern/runPatternSearch.js.map +1 -0
- package/dist/analysis/ts/extractDeclarations.d.ts +7 -0
- package/dist/analysis/ts/extractDeclarations.js +93 -0
- package/dist/analysis/ts/extractDeclarations.js.map +1 -0
- package/dist/analysis/ts/extractUsages.d.ts +7 -0
- package/dist/analysis/ts/extractUsages.js +120 -0
- package/dist/analysis/ts/extractUsages.js.map +1 -0
- package/dist/analysis/ts/parseSourceFile.d.ts +10 -0
- package/dist/analysis/ts/parseSourceFile.js +28 -0
- package/dist/analysis/ts/parseSourceFile.js.map +1 -0
- package/dist/analysis/ts/snippets.d.ts +14 -0
- package/dist/analysis/ts/snippets.js +29 -0
- package/dist/analysis/ts/snippets.js.map +1 -0
- package/dist/analysis/ts/structuralPredicates.d.ts +10 -0
- package/dist/analysis/ts/structuralPredicates.js +170 -0
- package/dist/analysis/ts/structuralPredicates.js.map +1 -0
- package/dist/ast/diffDeclarationShapes.d.ts +16 -0
- package/dist/ast/diffDeclarationShapes.js +179 -0
- package/dist/ast/diffDeclarationShapes.js.map +1 -0
- package/dist/ast/extractExportDeclarations.d.ts +21 -0
- package/dist/ast/extractExportDeclarations.js +218 -0
- package/dist/ast/extractExportDeclarations.js.map +1 -0
- package/dist/ast/findNodeAtPosition.d.ts +12 -0
- package/dist/ast/findNodeAtPosition.js +75 -0
- package/dist/ast/findNodeAtPosition.js.map +1 -0
- package/dist/ast/parseFile.d.ts +10 -0
- package/dist/ast/parseFile.js +29 -0
- package/dist/ast/parseFile.js.map +1 -0
- package/dist/engine/waitForDiagnostics.d.ts +7 -0
- package/dist/engine/waitForDiagnostics.js +16 -0
- package/dist/engine/waitForDiagnostics.js.map +1 -0
- package/dist/git/getBaseFileContent.d.ts +5 -0
- package/dist/git/getBaseFileContent.js +16 -0
- package/dist/git/getBaseFileContent.js.map +1 -0
- package/dist/git/getChangedFiles.d.ts +4 -0
- package/dist/git/getChangedFiles.js +21 -0
- package/dist/git/getChangedFiles.js.map +1 -0
- package/dist/git/getChangedHunks.d.ts +13 -0
- package/dist/git/getChangedHunks.js +51 -0
- package/dist/git/getChangedHunks.js.map +1 -0
- package/dist/git/getMergeBase.d.ts +5 -0
- package/dist/git/getMergeBase.js +23 -0
- package/dist/git/getMergeBase.js.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/resolve/searchScope.d.ts +11 -0
- package/dist/resolve/searchScope.js +52 -0
- package/dist/resolve/searchScope.js.map +1 -0
- package/dist/resolve/targetResolver.d.ts +33 -0
- package/dist/resolve/targetResolver.js +84 -0
- package/dist/resolve/targetResolver.js.map +1 -0
- package/dist/search/families/behaviorFamilies.d.ts +22 -0
- package/dist/search/families/behaviorFamilies.js +90 -0
- package/dist/search/families/behaviorFamilies.js.map +1 -0
- package/dist/search/index/declarationIndex.d.ts +6 -0
- package/dist/search/index/declarationIndex.js +13 -0
- package/dist/search/index/declarationIndex.js.map +1 -0
- package/dist/search/index/types.d.ts +1 -0
- package/dist/search/index/types.js +2 -0
- package/dist/search/index/types.js.map +1 -0
- package/dist/search/index/usageIndex.d.ts +6 -0
- package/dist/search/index/usageIndex.js +13 -0
- package/dist/search/index/usageIndex.js.map +1 -0
- package/dist/search/index/workspaceIndex.d.ts +8 -0
- package/dist/search/index/workspaceIndex.js +91 -0
- package/dist/search/index/workspaceIndex.js.map +1 -0
- package/dist/search/query/parseQuery.d.ts +9 -0
- package/dist/search/query/parseQuery.js +244 -0
- package/dist/search/query/parseQuery.js.map +1 -0
- package/dist/search/query/planQuery.d.ts +9 -0
- package/dist/search/query/planQuery.js +58 -0
- package/dist/search/query/planQuery.js.map +1 -0
- package/dist/search/ranking/assessConfidence.d.ts +6 -0
- package/dist/search/ranking/assessConfidence.js +25 -0
- package/dist/search/ranking/assessConfidence.js.map +1 -0
- package/dist/search/ranking/mergeCandidates.d.ts +10 -0
- package/dist/search/ranking/mergeCandidates.js +46 -0
- package/dist/search/ranking/mergeCandidates.js.map +1 -0
- package/dist/search/ranking/rankCandidates.d.ts +12 -0
- package/dist/search/ranking/rankCandidates.js +58 -0
- package/dist/search/ranking/rankCandidates.js.map +1 -0
- package/dist/search/retrievers/behaviorRetriever.d.ts +7 -0
- package/dist/search/retrievers/behaviorRetriever.js +91 -0
- package/dist/search/retrievers/behaviorRetriever.js.map +1 -0
- package/dist/search/retrievers/identifierRetriever.d.ts +7 -0
- package/dist/search/retrievers/identifierRetriever.js +66 -0
- package/dist/search/retrievers/identifierRetriever.js.map +1 -0
- package/dist/search/retrievers/structuralRetriever.d.ts +11 -0
- package/dist/search/retrievers/structuralRetriever.js +141 -0
- package/dist/search/retrievers/structuralRetriever.js.map +1 -0
- package/dist/search/types.d.ts +121 -0
- package/dist/search/types.js +11 -0
- package/dist/search/types.js.map +1 -0
- package/dist/tools/composites/apiGuard.d.ts +1 -0
- package/dist/tools/composites/apiGuard.js +194 -0
- package/dist/tools/composites/apiGuard.js.map +1 -0
- package/dist/tools/composites/explainError.js +3 -2
- package/dist/tools/composites/explainError.js.map +1 -1
- package/dist/tools/composites/findCode.d.ts +1 -0
- package/dist/tools/composites/findCode.js +68 -0
- package/dist/tools/composites/findCode.js.map +1 -0
- package/dist/tools/composites/findPattern.d.ts +5 -0
- package/dist/tools/composites/findPattern.js +41 -0
- package/dist/tools/composites/findPattern.js.map +1 -0
- package/dist/tools/composites/rootCauseTrace.d.ts +1 -0
- package/dist/tools/composites/rootCauseTrace.js +213 -0
- package/dist/tools/composites/rootCauseTrace.js.map +1 -0
- package/dist/tools/composites/semanticDiff.js +24 -77
- package/dist/tools/composites/semanticDiff.js.map +1 -1
- package/dist/tools/live/liveDiagnostics.js +3 -2
- package/dist/tools/live/liveDiagnostics.js.map +1 -1
- package/dist/tools/primitives/diagnostics.js +2 -2
- package/dist/tools/primitives/diagnostics.js.map +1 -1
- package/dist/tools/registry.d.ts +10 -2
- package/dist/tools/registry.js +7 -2
- package/dist/tools/registry.js.map +1 -1
- package/package.json +8 -4
- package/dist/tools/primitives/typeHierarchy.d.ts +0 -1
- package/dist/tools/primitives/typeHierarchy.js +0 -55
- package/dist/tools/primitives/typeHierarchy.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Query IR — the parsed representation of a user's search query
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/**
|
|
5
|
+
* Deduplication key for candidates.
|
|
6
|
+
* Uses match identity, not just symbol name.
|
|
7
|
+
*/
|
|
8
|
+
export function candidateKey(c) {
|
|
9
|
+
return `${c.candidateType}:${c.filePath}:${c.line}:${c.column ?? 0}:${c.matchedIdentifier ?? c.symbol ?? ''}`;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,gEAAgE;AAChE,+EAA+E;AAwF/E;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAgB;IAC3C,OAAO,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;AAChH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const apiGuard: import("../registry.js").ToolDef;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { defineTool } from '../registry.js';
|
|
5
|
+
import { relativePath, uriToPath, getPackageName } from '../../engine/positions.js';
|
|
6
|
+
import { parseSource } from '../../ast/parseFile.js';
|
|
7
|
+
import { extractExportDeclarations } from '../../ast/extractExportDeclarations.js';
|
|
8
|
+
import { diffExportDeclarations } from '../../ast/diffDeclarationShapes.js';
|
|
9
|
+
import { getMergeBase } from '../../git/getMergeBase.js';
|
|
10
|
+
import { getChangedFiles } from '../../git/getChangedFiles.js';
|
|
11
|
+
import { getBaseFileContent } from '../../git/getBaseFileContent.js';
|
|
12
|
+
import { LspError, LspErrorCode, DEFAULT_TIMEOUTS, SKIP_DIRS } from '../../engine/types.js';
|
|
13
|
+
// --- Helper: collect all TS files under a dir ---
|
|
14
|
+
function collectTsFiles(dir, max) {
|
|
15
|
+
const files = [];
|
|
16
|
+
const walk = (d, depth) => {
|
|
17
|
+
if (depth > 6 || files.length >= max)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
for (const entry of fs.readdirSync(d)) {
|
|
21
|
+
if (SKIP_DIRS.has(entry))
|
|
22
|
+
continue;
|
|
23
|
+
const full = path.join(d, entry);
|
|
24
|
+
if (fs.statSync(full).isDirectory())
|
|
25
|
+
walk(full, depth + 1);
|
|
26
|
+
else if ((entry.endsWith('.ts') || entry.endsWith('.tsx')) && !entry.endsWith('.d.ts')) {
|
|
27
|
+
files.push(full);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch { }
|
|
32
|
+
};
|
|
33
|
+
walk(dir, 0);
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
export const apiGuard = defineTool({
|
|
37
|
+
name: 'api_guard',
|
|
38
|
+
description: 'Detect public API contract changes: what exports changed, how they changed structurally, who consumes them, and the semver impact. Use before merging to catch accidental breaking changes.',
|
|
39
|
+
schema: z.object({
|
|
40
|
+
base: z.string().optional().describe('Git base ref. Defaults to merge-base with main.'),
|
|
41
|
+
scope: z.enum(['changed', 'all']).default('changed').describe('"changed" = only diff-modified files, "all" = scan all source files'),
|
|
42
|
+
symbol: z.string().optional().describe('Optional: narrow to a specific export name'),
|
|
43
|
+
file_path: z.string().optional().describe('Optional: narrow to a specific file'),
|
|
44
|
+
}),
|
|
45
|
+
async handler(params, engine) {
|
|
46
|
+
if (!engine.gitAvailable && params.scope === 'changed') {
|
|
47
|
+
throw new LspError(LspErrorCode.GIT_UNAVAILABLE, 'Git required for scope "changed". Use scope "all" instead.');
|
|
48
|
+
}
|
|
49
|
+
const timeout = DEFAULT_TIMEOUTS.composite;
|
|
50
|
+
const warnings = [];
|
|
51
|
+
let astUsed = false;
|
|
52
|
+
// Step 0: Resolve base ref
|
|
53
|
+
const base = engine.gitAvailable ? getMergeBase(engine.workspaceRoot, params.base) : undefined;
|
|
54
|
+
// Step 1: Get files in scope
|
|
55
|
+
let scopeFiles;
|
|
56
|
+
if (params.file_path) {
|
|
57
|
+
scopeFiles = [params.file_path];
|
|
58
|
+
}
|
|
59
|
+
else if (params.scope === 'changed' && base) {
|
|
60
|
+
scopeFiles = getChangedFiles(engine.workspaceRoot, base);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
scopeFiles = collectTsFiles(engine.workspaceRoot, 500);
|
|
64
|
+
}
|
|
65
|
+
if (scopeFiles.length === 0) {
|
|
66
|
+
return { summary: { exportsChecked: 0, changedExports: 0, breaking: 0, risky: 0, safe: 0, recommendedSemver: 'patch' }, entries: [], stats: { astUsed: false, filesParsed: 0, baseUsed: !!base, partialResult: false }, warnings: ['No files in scope'] };
|
|
67
|
+
}
|
|
68
|
+
// Step 2+3: Parse exports, diff
|
|
69
|
+
const entries = [];
|
|
70
|
+
let filesParsed = 0;
|
|
71
|
+
let totalExportsChecked = 0;
|
|
72
|
+
for (const filePath of scopeFiles) {
|
|
73
|
+
try {
|
|
74
|
+
const currentContent = fs.readFileSync(filePath, 'utf-8');
|
|
75
|
+
const currentRoot = parseSource(currentContent, filePath.endsWith('.tsx'));
|
|
76
|
+
const currentExports = currentRoot
|
|
77
|
+
? (astUsed = true, extractExportDeclarations(currentRoot, currentContent))
|
|
78
|
+
: extractExportDeclarations(null, currentContent);
|
|
79
|
+
totalExportsChecked += currentExports.length;
|
|
80
|
+
// Get base exports
|
|
81
|
+
let baseExports = extractExportDeclarations(null, '');
|
|
82
|
+
if (base) {
|
|
83
|
+
const baseContent = getBaseFileContent(filePath, base, engine.workspaceRoot);
|
|
84
|
+
if (baseContent) {
|
|
85
|
+
const baseRoot = parseSource(baseContent, filePath.endsWith('.tsx'));
|
|
86
|
+
baseExports = baseRoot
|
|
87
|
+
? extractExportDeclarations(baseRoot, baseContent)
|
|
88
|
+
: extractExportDeclarations(null, baseContent);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const diffs = diffExportDeclarations(baseExports, currentExports);
|
|
92
|
+
for (const d of diffs) {
|
|
93
|
+
if (params.symbol && d.name !== params.symbol)
|
|
94
|
+
continue;
|
|
95
|
+
entries.push({
|
|
96
|
+
exportName: d.name,
|
|
97
|
+
filePath,
|
|
98
|
+
line: d.currentDecl?.line ?? d.baseDecl?.line,
|
|
99
|
+
declarationKind: d.baseDecl?.declarationKind ?? d.currentDecl?.declarationKind,
|
|
100
|
+
kind: d.kind,
|
|
101
|
+
risk: d.risk,
|
|
102
|
+
reason: d.reason,
|
|
103
|
+
currentSignature: d.currentDecl?.signatureText,
|
|
104
|
+
baseSignature: d.baseDecl?.signatureText,
|
|
105
|
+
structuralDiff: d.structuralDiff,
|
|
106
|
+
consumers: { samePackage: 0, crossPackage: 0, sampleFiles: [] },
|
|
107
|
+
evidence: [],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
filesParsed++;
|
|
111
|
+
}
|
|
112
|
+
catch { }
|
|
113
|
+
}
|
|
114
|
+
// Step 4: Find consumers using declaration line data (no raw text rescanning)
|
|
115
|
+
let consumerChecks = 0;
|
|
116
|
+
for (const entry of entries.filter((e) => e.risk !== 'safe')) {
|
|
117
|
+
if (consumerChecks >= 15) {
|
|
118
|
+
warnings.push('Consumer lookup capped at 15 entries');
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const { uri } = await engine.prepareFile(entry.filePath);
|
|
123
|
+
const exportLine0 = Math.max(0, (entry.line ?? 1) - 1);
|
|
124
|
+
const refs = await engine.request('textDocument/references', {
|
|
125
|
+
textDocument: { uri },
|
|
126
|
+
position: { line: exportLine0, character: 0 },
|
|
127
|
+
context: { includeDeclaration: false },
|
|
128
|
+
}, timeout).catch((err) => { warnings.push(`Consumer lookup failed for ${entry.exportName}: ${err instanceof Error ? err.message : String(err)}`); return null; });
|
|
129
|
+
if (refs) {
|
|
130
|
+
const currentPkg = getPackageName(entry.filePath);
|
|
131
|
+
const samePackage = refs.filter((r) => getPackageName(uriToPath(r.uri)) === currentPkg).length;
|
|
132
|
+
const crossPackage = refs.length - samePackage;
|
|
133
|
+
const sampleFiles = [...new Set(refs.map((r) => relativePath(uriToPath(r.uri), engine.workspaceRoot)))].slice(0, 5);
|
|
134
|
+
entry.consumers = { samePackage, crossPackage, sampleFiles };
|
|
135
|
+
entry.evidence.push(`${crossPackage} cross-package, ${samePackage} same-package consumers`);
|
|
136
|
+
// Populate diagnosticsInConsumers (sample up to 3 consumer files)
|
|
137
|
+
let diagCount = 0;
|
|
138
|
+
for (const fp of sampleFiles.slice(0, 3)) {
|
|
139
|
+
try {
|
|
140
|
+
const abs = fp.startsWith('/') ? fp : `${engine.workspaceRoot}/${fp}`;
|
|
141
|
+
const { uri: consumerUri } = await engine.prepareFile(abs);
|
|
142
|
+
const { waitForDiagnostics: waitDiag } = await import('../../engine/waitForDiagnostics.js');
|
|
143
|
+
await waitDiag(engine.docManager, consumerUri, 500);
|
|
144
|
+
diagCount += engine.docManager.getCachedDiagnostics(consumerUri).filter((d) => d.severity === 1).length;
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
warnings.push(`Consumer diagnostics failed for ${fp}: ${err instanceof Error ? err.message : String(err)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
entry.diagnosticsInConsumers = diagCount;
|
|
151
|
+
// Downgrade risk if no cross-package consumers
|
|
152
|
+
if (crossPackage === 0 && entry.risk === 'risky') {
|
|
153
|
+
entry.risk = 'safe';
|
|
154
|
+
entry.reason += ' (no cross-package consumers)';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
consumerChecks++;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
warnings.push(`Consumer analysis failed for ${entry.exportName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Step 5: Classify and summarize
|
|
164
|
+
const breaking = entries.filter((e) => e.risk === 'breaking').length;
|
|
165
|
+
const risky = entries.filter((e) => e.risk === 'risky').length;
|
|
166
|
+
const safe = entries.filter((e) => e.risk === 'safe').length;
|
|
167
|
+
// Semver: breaking → major, additive-only → minor, else patch
|
|
168
|
+
const hasAdditive = entries.some((e) => e.kind === 'added' && e.risk === 'safe');
|
|
169
|
+
const semver = breaking > 0 ? 'major' : hasAdditive ? 'minor' : 'patch';
|
|
170
|
+
const result = {
|
|
171
|
+
summary: {
|
|
172
|
+
exportsChecked: totalExportsChecked,
|
|
173
|
+
changedExports: entries.length,
|
|
174
|
+
breaking,
|
|
175
|
+
risky,
|
|
176
|
+
safe,
|
|
177
|
+
recommendedSemver: semver,
|
|
178
|
+
},
|
|
179
|
+
entries: entries.sort((a, b) => {
|
|
180
|
+
const riskOrder = { breaking: 0, risky: 1, safe: 2 };
|
|
181
|
+
return riskOrder[a.risk] - riskOrder[b.risk];
|
|
182
|
+
}),
|
|
183
|
+
stats: {
|
|
184
|
+
astUsed,
|
|
185
|
+
filesParsed,
|
|
186
|
+
baseUsed: !!base,
|
|
187
|
+
partialResult: consumerChecks >= 15,
|
|
188
|
+
},
|
|
189
|
+
warnings,
|
|
190
|
+
};
|
|
191
|
+
return result;
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
//# sourceMappingURL=apiGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiGuard.js","sourceRoot":"","sources":["../../../src/tools/composites/apiGuard.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,9 @@ export const explainError = defineTool({
|
|
|
14
14
|
async handler(params, engine) {
|
|
15
15
|
const { uri } = await engine.prepareFile(params.file_path);
|
|
16
16
|
const timeout = DEFAULT_TIMEOUTS.composite;
|
|
17
|
-
// Wait for diagnostics
|
|
18
|
-
|
|
17
|
+
// Wait for diagnostics (poll instead of fixed sleep)
|
|
18
|
+
const { waitForDiagnostics } = await import('../../engine/waitForDiagnostics.js');
|
|
19
|
+
await waitForDiagnostics(engine.docManager, uri, 800);
|
|
19
20
|
const diags = engine.docManager.getCachedDiagnostics(uri);
|
|
20
21
|
// Find diagnostic at or near the specified line
|
|
21
22
|
const targetLine = params.line - 1; // 0-indexed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explainError.js","sourceRoot":"","sources":["../../../src/tools/composites/explainError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAa,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;IACrC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,kJAAkJ;IAC/J,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QACzE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QAC/D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,yCAAyC,CAAC;KAC7F,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM;QAC1B,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC;QAE3C,
|
|
1
|
+
{"version":3,"file":"explainError.js","sourceRoot":"","sources":["../../../src/tools/composites/explainError.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const findCode: import("../registry.js").ToolDef;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineTool } from '../registry.js';
|
|
3
|
+
import { resolveSearchScope } from '../../resolve/searchScope.js';
|
|
4
|
+
import { parseQuery } from '../../search/query/parseQuery.js';
|
|
5
|
+
import { planQuery } from '../../search/query/planQuery.js';
|
|
6
|
+
import { getWorkspaceIndex } from '../../search/index/workspaceIndex.js';
|
|
7
|
+
import { retrieveBehaviorCandidates } from '../../search/retrievers/behaviorRetriever.js';
|
|
8
|
+
import { retrieveIdentifierCandidates } from '../../search/retrievers/identifierRetriever.js';
|
|
9
|
+
import { retrieveStructuralCandidates } from '../../search/retrievers/structuralRetriever.js';
|
|
10
|
+
import { mergeCandidates } from '../../search/ranking/mergeCandidates.js';
|
|
11
|
+
import { rankCandidates } from '../../search/ranking/rankCandidates.js';
|
|
12
|
+
import { assessConfidence } from '../../search/ranking/assessConfidence.js';
|
|
13
|
+
export const findCode = defineTool({
|
|
14
|
+
name: 'find_code',
|
|
15
|
+
description: 'High-level code search: behavior discovery, identifier/API usage search, and structural queries. The agent does not need to choose the backend — the tool routes automatically based on the query.',
|
|
16
|
+
schema: z.object({
|
|
17
|
+
query: z.string().describe('Natural-language or code-oriented query'),
|
|
18
|
+
paths: z.array(z.string()).optional().describe('Directories/files to narrow search'),
|
|
19
|
+
max_results: z.number().default(10),
|
|
20
|
+
mode: z.enum(['auto', 'behavior', 'identifier', 'structural', 'mixed']).default('auto'),
|
|
21
|
+
family: z.enum(['auth', 'validation', 'fetching', 'errors', 'state', 'flags', 'retry', 'caching']).optional().describe('Optional family override'),
|
|
22
|
+
include_tests: z.boolean().default(false),
|
|
23
|
+
}),
|
|
24
|
+
async handler(params, engine) {
|
|
25
|
+
const startTime = Date.now();
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const scope = resolveSearchScope(engine.workspaceRoot, params.paths, params.include_tests);
|
|
28
|
+
const ir = parseQuery(params.query, {
|
|
29
|
+
forcedMode: params.mode === 'auto' ? undefined : params.mode,
|
|
30
|
+
forcedFamily: params.family,
|
|
31
|
+
});
|
|
32
|
+
const plan = planQuery(ir);
|
|
33
|
+
const index = getWorkspaceIndex(scope);
|
|
34
|
+
const behavior = plan.retrievers.includes('behavior')
|
|
35
|
+
? retrieveBehaviorCandidates(ir, scope, index)
|
|
36
|
+
: [];
|
|
37
|
+
const identifier = plan.retrievers.includes('identifier')
|
|
38
|
+
? retrieveIdentifierCandidates(ir, scope, index)
|
|
39
|
+
: [];
|
|
40
|
+
const structural = plan.retrievers.includes('structural')
|
|
41
|
+
? retrieveStructuralCandidates(ir, scope, index)
|
|
42
|
+
: [];
|
|
43
|
+
const merged = mergeCandidates({ behavior, identifier, structural });
|
|
44
|
+
const ranked = await rankCandidates(merged, { ir, plan, engine, scope });
|
|
45
|
+
const confidence = assessConfidence(ranked, ir, plan);
|
|
46
|
+
const topResults = ranked.slice(0, params.max_results);
|
|
47
|
+
const lspEnriched = ranked.filter((c) => c.sources.includes('lsp')).length;
|
|
48
|
+
const result = {
|
|
49
|
+
query: params.query,
|
|
50
|
+
ir,
|
|
51
|
+
plan,
|
|
52
|
+
confidence,
|
|
53
|
+
candidates: topResults,
|
|
54
|
+
stats: {
|
|
55
|
+
filesIndexed: index.files.size,
|
|
56
|
+
declarationHits: behavior.length,
|
|
57
|
+
usageHits: identifier.length,
|
|
58
|
+
structuralHits: structural.length,
|
|
59
|
+
lspEnriched,
|
|
60
|
+
elapsedMs: Date.now() - startTime,
|
|
61
|
+
partialResult: false,
|
|
62
|
+
},
|
|
63
|
+
warnings,
|
|
64
|
+
};
|
|
65
|
+
return result;
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=findCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findCode.js","sourceRoot":"","sources":["../../../src/tools/composites/findCode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { defineTool } from '../registry.js';
|
|
3
|
+
import { resolveSearchScope } from '../../resolve/searchScope.js';
|
|
4
|
+
import { runPatternSearch } from '../../analysis/pattern/runPatternSearch.js';
|
|
5
|
+
/**
|
|
6
|
+
* Thin wrapper over runPatternSearch().
|
|
7
|
+
* No duplicated file collection or parse loops.
|
|
8
|
+
*/
|
|
9
|
+
export const findPattern = defineTool({
|
|
10
|
+
name: 'find_pattern',
|
|
11
|
+
description: 'Search for AST structural patterns across the codebase using ast-grep. Use $VAR for single node, $$$ for multiple nodes. Example: "useEffect($$$)" finds all useEffect calls.',
|
|
12
|
+
schema: z.object({
|
|
13
|
+
pattern: z.string().describe('ast-grep pattern. Use $VAR for single node, $$$ for any sequence.'),
|
|
14
|
+
language: z.enum(['typescript', 'tsx', 'javascript']).default('typescript'),
|
|
15
|
+
paths: z.array(z.string()).optional().describe('Limit search to specific directories (absolute paths)'),
|
|
16
|
+
max_results: z.number().default(50),
|
|
17
|
+
context_lines: z.number().default(1),
|
|
18
|
+
include_tests: z.boolean().default(true).describe('Include test/spec files in results'),
|
|
19
|
+
}),
|
|
20
|
+
async handler(params, engine) {
|
|
21
|
+
const scope = resolveSearchScope(engine.workspaceRoot, params.paths, params.include_tests);
|
|
22
|
+
const { filesScanned, matches, warnings } = runPatternSearch({
|
|
23
|
+
pattern: params.pattern,
|
|
24
|
+
language: params.language,
|
|
25
|
+
scope,
|
|
26
|
+
maxResults: params.max_results,
|
|
27
|
+
contextLines: params.context_lines,
|
|
28
|
+
workspaceRoot: engine.workspaceRoot,
|
|
29
|
+
});
|
|
30
|
+
const result = {
|
|
31
|
+
pattern: params.pattern,
|
|
32
|
+
language: params.language,
|
|
33
|
+
filesScanned,
|
|
34
|
+
matchCount: matches.length,
|
|
35
|
+
matches,
|
|
36
|
+
warnings,
|
|
37
|
+
};
|
|
38
|
+
return result;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=findPattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findPattern.js","sourceRoot":"","sources":["../../../src/tools/composites/findPattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAG9E;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;IACpC,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,+KAA+K;IACjL,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;QACjG,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;QAC3E,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;QACvG,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACpC,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACxF,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM;QAC1B,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAE3F,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC;YAC3D,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK;YACL,UAAU,EAAE,MAAM,CAAC,WAAW;YAC9B,YAAY,EAAE,MAAM,CAAC,aAAa;YAClC,aAAa,EAAE,MAAM,CAAC,aAAa;SACpC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAsB;YAChC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,YAAY;YACZ,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,OAAO;YACP,QAAQ;SACT,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const rootCauseTrace: import("../registry.js").ToolDef;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { defineTool } from '../registry.js';
|
|
4
|
+
import { relativePath, uriToPath, pathToUri, fromPosition } from '../../engine/positions.js';
|
|
5
|
+
import { formatHover } from '../../format/markdown.js';
|
|
6
|
+
import { parseFile, parseSource } from '../../ast/parseFile.js';
|
|
7
|
+
import { classifyErrorSite } from '../../ast/findNodeAtPosition.js';
|
|
8
|
+
import { extractExportDeclarations } from '../../ast/extractExportDeclarations.js';
|
|
9
|
+
import { diffExportDeclarations } from '../../ast/diffDeclarationShapes.js';
|
|
10
|
+
import { getMergeBase } from '../../git/getMergeBase.js';
|
|
11
|
+
import { getBaseFileContent } from '../../git/getBaseFileContent.js';
|
|
12
|
+
import { fileChangedInBranch } from '../../git/getChangedHunks.js';
|
|
13
|
+
import { resolveTarget, pickDiagnostic } from '../../resolve/targetResolver.js';
|
|
14
|
+
import { DEFAULT_TIMEOUTS } from '../../engine/types.js';
|
|
15
|
+
export const rootCauseTrace = defineTool({
|
|
16
|
+
name: 'root_cause_trace',
|
|
17
|
+
description: 'Trace the root cause of a TypeScript error. Accepts symbol name, file+line, or file+diagnostic_code. Identifies the originating declaration change with evidence chain.',
|
|
18
|
+
schema: z.object({
|
|
19
|
+
symbol: z.string().optional().describe('Symbol at or near the error site'),
|
|
20
|
+
file_path: z.string().optional().describe('File containing the error'),
|
|
21
|
+
line: z.number().optional().describe('1-indexed line number'),
|
|
22
|
+
diagnostic_code: z.string().optional().describe('Diagnostic code, e.g. TS2345'),
|
|
23
|
+
base: z.string().optional().describe('Git base ref'),
|
|
24
|
+
}),
|
|
25
|
+
async handler(params, engine) {
|
|
26
|
+
const timeout = DEFAULT_TIMEOUTS.composite;
|
|
27
|
+
const warnings = [];
|
|
28
|
+
let astUsed = false;
|
|
29
|
+
// Step 1: Resolve target via shared resolver (symbol-first)
|
|
30
|
+
let target;
|
|
31
|
+
try {
|
|
32
|
+
target = await resolveTarget(params, engine);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return { errorSite: {}, candidates: [], stats: { candidatesConsidered: 0, callerFilesChecked: 0, astUsed: false, baseUsed: false, partialResult: false }, warnings: [`Target resolution failed: ${err instanceof Error ? err.message : String(err)}`] };
|
|
36
|
+
}
|
|
37
|
+
const { filePath, uri, position: targetPosition, symbol: symbolName } = target;
|
|
38
|
+
// Step 2: Anchor the diagnostic (poll for readiness instead of fixed sleep)
|
|
39
|
+
const { waitForDiagnostics } = await import('../../engine/waitForDiagnostics.js');
|
|
40
|
+
await waitForDiagnostics(engine.docManager, uri, 800);
|
|
41
|
+
const allDiags = engine.docManager.getCachedDiagnostics(uri);
|
|
42
|
+
const targetDiag = pickDiagnostic(allDiags, targetPosition, params.diagnostic_code);
|
|
43
|
+
if (!targetDiag) {
|
|
44
|
+
return { errorSite: { symbol: symbolName }, candidates: [], stats: { candidatesConsidered: 0, callerFilesChecked: 0, astUsed: false, baseUsed: false, partialResult: false }, warnings: [`No error diagnostic in ${relativePath(filePath, engine.workspaceRoot)}`] };
|
|
45
|
+
}
|
|
46
|
+
const base = engine.gitAvailable ? getMergeBase(engine.workspaceRoot, params.base) : undefined;
|
|
47
|
+
const errorPosition = targetDiag.range.start;
|
|
48
|
+
const diagPos = fromPosition(errorPosition);
|
|
49
|
+
// Step 3: Error site — LSP + AST (with proper error handling)
|
|
50
|
+
const [hoverResult, defResult] = await Promise.all([
|
|
51
|
+
engine.request('textDocument/hover', { textDocument: { uri }, position: errorPosition }, timeout)
|
|
52
|
+
.catch((err) => { warnings.push(`Hover failed: ${err instanceof Error ? err.message : String(err)}`); return null; }),
|
|
53
|
+
engine.request('textDocument/definition', { textDocument: { uri }, position: errorPosition }, timeout)
|
|
54
|
+
.catch((err) => { warnings.push(`Definition lookup failed: ${err instanceof Error ? err.message : String(err)}`); return null; }),
|
|
55
|
+
]);
|
|
56
|
+
let localPattern = null;
|
|
57
|
+
try {
|
|
58
|
+
const root = parseFile(filePath);
|
|
59
|
+
if (root) {
|
|
60
|
+
astUsed = true;
|
|
61
|
+
localPattern = classifyErrorSite(root, errorPosition.line);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
warnings.push(`AST classification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
|
+
}
|
|
67
|
+
const hoverSummary = hoverResult ? formatHover(hoverResult).substring(0, 200) : undefined;
|
|
68
|
+
const defLocation = defResult ? uriToPath(Array.isArray(defResult) ? defResult[0].uri : defResult.uri) : undefined;
|
|
69
|
+
const errorSite = {
|
|
70
|
+
symbol: symbolName,
|
|
71
|
+
definitionFile: defLocation ? relativePath(defLocation, engine.workspaceRoot) : undefined,
|
|
72
|
+
enclosingNodeKind: localPattern ?? undefined,
|
|
73
|
+
localPattern: localPattern ?? undefined,
|
|
74
|
+
hoverSummary,
|
|
75
|
+
};
|
|
76
|
+
// Step 4: Collect candidates
|
|
77
|
+
const candidates = [];
|
|
78
|
+
// Candidate A: definition site
|
|
79
|
+
if (defLocation && defLocation !== filePath) {
|
|
80
|
+
candidates.push(await buildCandidate(defLocation, 'definition-site', 5, base, engine, warnings));
|
|
81
|
+
}
|
|
82
|
+
// Candidate B: type definition
|
|
83
|
+
try {
|
|
84
|
+
const typeDef = await engine.request('textDocument/typeDefinition', { textDocument: { uri }, position: errorPosition }, timeout);
|
|
85
|
+
if (typeDef) {
|
|
86
|
+
const typeDefPath = uriToPath(Array.isArray(typeDef) ? typeDef[0].uri : typeDef.uri);
|
|
87
|
+
if (typeDefPath !== filePath && typeDefPath !== defLocation) {
|
|
88
|
+
candidates.push(await buildCandidate(typeDefPath, 'type-definition', 4, base, engine, warnings));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
warnings.push(`Type definition lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
94
|
+
}
|
|
95
|
+
// Candidate C: upstream callers (cap at 5)
|
|
96
|
+
let callerFilesChecked = 0;
|
|
97
|
+
try {
|
|
98
|
+
const items = await engine.request('textDocument/prepareCallHierarchy', { textDocument: { uri }, position: errorPosition }, timeout);
|
|
99
|
+
if (items?.length) {
|
|
100
|
+
const incomingCalls = await engine.request('callHierarchy/incomingCalls', { item: items[0] }, timeout);
|
|
101
|
+
for (const call of (incomingCalls ?? []).slice(0, 5)) {
|
|
102
|
+
const callerPath = uriToPath(call.from.uri);
|
|
103
|
+
if (callerPath === filePath)
|
|
104
|
+
continue;
|
|
105
|
+
try {
|
|
106
|
+
const changed = base ? fileChangedInBranch(callerPath, base, engine.workspaceRoot) : false;
|
|
107
|
+
await engine.prepareFile(callerPath);
|
|
108
|
+
await waitForDiagnostics(engine.docManager, pathToUri(callerPath), 500);
|
|
109
|
+
const callerDiags = engine.docManager.getCachedDiagnostics(pathToUri(callerPath)).filter((d) => d.severity === 1).length;
|
|
110
|
+
let score = 2;
|
|
111
|
+
const evidence = [`upstream-caller: ${relativePath(callerPath, engine.workspaceRoot)}`];
|
|
112
|
+
if (changed) {
|
|
113
|
+
score += 6;
|
|
114
|
+
evidence.push('changed-in-branch');
|
|
115
|
+
}
|
|
116
|
+
if (callerDiags > 0) {
|
|
117
|
+
score += 3;
|
|
118
|
+
evidence.push(`caller-has-errors: ${callerDiags}`);
|
|
119
|
+
}
|
|
120
|
+
candidates.push({
|
|
121
|
+
symbol: call.from.name, filePath: callerPath,
|
|
122
|
+
reason: changed ? `Upstream caller changed${callerDiags ? ` (${callerDiags} errors)` : ''}` : `Upstream caller${callerDiags ? ` with ${callerDiags} errors` : ''}`,
|
|
123
|
+
confidence: changed && callerDiags > 0 ? 'high' : 'low',
|
|
124
|
+
score, evidence, changedInBranch: changed, diagnosticsNearby: callerDiags,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
warnings.push(`Caller analysis failed for ${call.from.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
129
|
+
}
|
|
130
|
+
callerFilesChecked++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
warnings.push(`Call hierarchy failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
136
|
+
}
|
|
137
|
+
// Step 5: Rank + impact
|
|
138
|
+
const sorted = candidates.sort((a, b) => b.score - a.score);
|
|
139
|
+
const topCandidate = sorted[0];
|
|
140
|
+
if (topCandidate) {
|
|
141
|
+
try {
|
|
142
|
+
if (topCandidate.symbol) {
|
|
143
|
+
const resolved = await engine.resolveSymbol(topCandidate.symbol, topCandidate.filePath);
|
|
144
|
+
const refs = await engine.request('textDocument/references', { textDocument: { uri: resolved.uri }, position: resolved.position, context: { includeDeclaration: false } }, timeout);
|
|
145
|
+
if (refs)
|
|
146
|
+
topCandidate.impactSummary = { affectedFiles: new Set(refs.map((r) => uriToPath(r.uri))).size };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
warnings.push(`Impact analysis failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
151
|
+
}
|
|
152
|
+
if (localPattern === 'unhandled_enum_member')
|
|
153
|
+
topCandidate.suggestedFix = 'Add a case for the new enum member';
|
|
154
|
+
else if (localPattern === 'bad_call_argument')
|
|
155
|
+
topCandidate.suggestedFix = 'Check function signature — a parameter type may have changed';
|
|
156
|
+
else if (localPattern === 'missing_property_access')
|
|
157
|
+
topCandidate.suggestedFix = 'A property may have been removed or renamed';
|
|
158
|
+
else if (localPattern === 'incompatible_assignment')
|
|
159
|
+
topCandidate.suggestedFix = 'Source type may have changed — check the definition';
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
diagnostic: { code: targetDiag.code ? `TS${targetDiag.code}` : undefined, message: targetDiag.message, filePath, line: diagPos.line },
|
|
163
|
+
errorSite,
|
|
164
|
+
candidates: sorted,
|
|
165
|
+
topCandidate,
|
|
166
|
+
nextVerificationStep: topCandidate ? `Run impact_trace on ${relativePath(topCandidate.filePath, engine.workspaceRoot)}` : undefined,
|
|
167
|
+
stats: { candidatesConsidered: candidates.length, callerFilesChecked, astUsed, baseUsed: !!base, partialResult: callerFilesChecked >= 5 },
|
|
168
|
+
warnings,
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
async function buildCandidate(candidatePath, source, baseScore, base, engine, warnings) {
|
|
173
|
+
const changed = base ? fileChangedInBranch(candidatePath, base, engine.workspaceRoot) : false;
|
|
174
|
+
let score = baseScore;
|
|
175
|
+
const evidence = [`${source}: ${relativePath(candidatePath, engine.workspaceRoot)}`];
|
|
176
|
+
let structuralChange;
|
|
177
|
+
if (changed) {
|
|
178
|
+
score += 8;
|
|
179
|
+
evidence.push('changed-in-branch');
|
|
180
|
+
if (base) {
|
|
181
|
+
try {
|
|
182
|
+
const sc = classifyDeclarationChange(candidatePath, base, engine.workspaceRoot);
|
|
183
|
+
if (sc) {
|
|
184
|
+
score += 5;
|
|
185
|
+
evidence.push(`structural-change: ${sc}`);
|
|
186
|
+
structuralChange = sc;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
warnings.push(`Structural classification failed for ${relativePath(candidatePath, engine.workspaceRoot)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
filePath: candidatePath,
|
|
196
|
+
reason: changed ? `${source} changed in this branch` : `${source} — trace upstream`,
|
|
197
|
+
confidence: changed ? 'high' : source === 'definition-site' ? 'medium' : 'low',
|
|
198
|
+
score, evidence, changedInBranch: changed, structuralChange,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function classifyDeclarationChange(filePath, base, workspaceRoot) {
|
|
202
|
+
const baseContent = getBaseFileContent(filePath, base, workspaceRoot);
|
|
203
|
+
if (!baseContent)
|
|
204
|
+
return null;
|
|
205
|
+
const currentContent = fs.readFileSync(filePath, 'utf-8');
|
|
206
|
+
const baseRoot = parseSource(baseContent, filePath.endsWith('.tsx'));
|
|
207
|
+
const currentRoot = parseSource(currentContent, filePath.endsWith('.tsx'));
|
|
208
|
+
const baseExports = extractExportDeclarations(baseRoot, baseContent);
|
|
209
|
+
const currentExports = extractExportDeclarations(currentRoot, currentContent);
|
|
210
|
+
const diffs = diffExportDeclarations(baseExports, currentExports);
|
|
211
|
+
return diffs.length > 0 ? diffs.map((d) => `${d.kind}: ${d.name}`).join(', ') : null;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=rootCauseTrace.js.map
|