@eduardo-afonso/codebase-intelligence 0.1.0 → 2.0.1
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 +86 -11
- package/README.pt-BR.md +88 -12
- package/dist/ai/CodebaseWithAI.d.ts +91 -0
- package/dist/ai/CodebaseWithAI.d.ts.map +1 -0
- package/dist/ai/CodebaseWithAI.js +149 -0
- package/dist/ai/CodebaseWithAI.js.map +1 -0
- package/dist/ai/RAGPipeline.d.ts +66 -0
- package/dist/ai/RAGPipeline.d.ts.map +1 -0
- package/dist/ai/RAGPipeline.js +102 -0
- package/dist/ai/RAGPipeline.js.map +1 -0
- package/dist/ai/index.d.ts +6 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/providers/NoopAIProvider.d.ts +23 -0
- package/dist/ai/providers/NoopAIProvider.d.ts.map +1 -0
- package/dist/ai/providers/NoopAIProvider.js +24 -0
- package/dist/ai/providers/NoopAIProvider.js.map +1 -0
- package/dist/cli/index.js +168 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/context/ContextEngine.d.ts +54 -0
- package/dist/context/ContextEngine.d.ts.map +1 -0
- package/dist/context/ContextEngine.js +179 -0
- package/dist/context/ContextEngine.js.map +1 -0
- package/dist/context/FileContextBuilder.d.ts +49 -0
- package/dist/context/FileContextBuilder.d.ts.map +1 -0
- package/dist/context/FileContextBuilder.js +124 -0
- package/dist/context/FileContextBuilder.js.map +1 -0
- package/dist/context/SemanticChunker.d.ts +105 -0
- package/dist/context/SemanticChunker.d.ts.map +1 -0
- package/dist/context/SemanticChunker.js +293 -0
- package/dist/context/SemanticChunker.js.map +1 -0
- package/dist/context/SignatureExtractor.d.ts +49 -0
- package/dist/context/SignatureExtractor.d.ts.map +1 -0
- package/dist/context/SignatureExtractor.js +167 -0
- package/dist/context/SignatureExtractor.js.map +1 -0
- package/dist/context/interfaces.d.ts +149 -0
- package/dist/context/interfaces.d.ts.map +1 -0
- package/dist/context/interfaces.js +13 -0
- package/dist/context/interfaces.js.map +1 -0
- package/dist/context/strategies/ContextBuildStrategy.d.ts +25 -0
- package/dist/context/strategies/ContextBuildStrategy.d.ts.map +1 -0
- package/dist/context/strategies/ContextBuildStrategy.js +3 -0
- package/dist/context/strategies/ContextBuildStrategy.js.map +1 -0
- package/dist/context/strategies/DeepStrategy.d.ts +18 -0
- package/dist/context/strategies/DeepStrategy.d.ts.map +1 -0
- package/dist/context/strategies/DeepStrategy.js +19 -0
- package/dist/context/strategies/DeepStrategy.js.map +1 -0
- package/dist/context/strategies/ShallowStrategy.d.ts +15 -0
- package/dist/context/strategies/ShallowStrategy.d.ts.map +1 -0
- package/dist/context/strategies/ShallowStrategy.js +15 -0
- package/dist/context/strategies/ShallowStrategy.js.map +1 -0
- package/dist/context/strategies/SignatureStrategy.d.ts +20 -0
- package/dist/context/strategies/SignatureStrategy.d.ts.map +1 -0
- package/dist/context/strategies/SignatureStrategy.js +59 -0
- package/dist/context/strategies/SignatureStrategy.js.map +1 -0
- package/dist/context/strategies/index.d.ts +5 -0
- package/dist/context/strategies/index.d.ts.map +1 -0
- package/dist/context/strategies/index.js +4 -0
- package/dist/context/strategies/index.js.map +1 -0
- package/dist/context/types.d.ts +136 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +8 -0
- package/dist/context/types.js.map +1 -0
- package/dist/core/Codebase.d.ts +50 -0
- package/dist/core/Codebase.d.ts.map +1 -1
- package/dist/core/Codebase.js +104 -0
- package/dist/core/Codebase.js.map +1 -1
- package/dist/diff/ChangeSetImpactAnalyzer.d.ts +19 -0
- package/dist/diff/ChangeSetImpactAnalyzer.d.ts.map +1 -0
- package/dist/diff/ChangeSetImpactAnalyzer.js +121 -0
- package/dist/diff/ChangeSetImpactAnalyzer.js.map +1 -0
- package/dist/diff/GitChangeSetProvider.d.ts +86 -0
- package/dist/diff/GitChangeSetProvider.d.ts.map +1 -0
- package/dist/diff/GitChangeSetProvider.js +297 -0
- package/dist/diff/GitChangeSetProvider.js.map +1 -0
- package/dist/diff/errors.d.ts +48 -0
- package/dist/diff/errors.d.ts.map +1 -0
- package/dist/diff/errors.js +70 -0
- package/dist/diff/errors.js.map +1 -0
- package/dist/diff/types.d.ts +159 -0
- package/dist/diff/types.d.ts.map +1 -0
- package/dist/diff/types.js +8 -0
- package/dist/diff/types.js.map +1 -0
- package/dist/explorer/SnapshotBuilder.d.ts +22 -0
- package/dist/explorer/SnapshotBuilder.d.ts.map +1 -0
- package/dist/explorer/SnapshotBuilder.js +225 -0
- package/dist/explorer/SnapshotBuilder.js.map +1 -0
- package/dist/explorer/types.d.ts +88 -0
- package/dist/explorer/types.d.ts.map +1 -0
- package/dist/explorer/types.js +12 -0
- package/dist/explorer/types.js.map +1 -0
- package/dist/explorer/ui/App.d.ts +3 -0
- package/dist/explorer/ui/App.d.ts.map +1 -0
- package/dist/explorer/ui/App.js +43 -0
- package/dist/explorer/ui/App.js.map +1 -0
- package/dist/explorer/ui/main.d.ts +2 -0
- package/dist/explorer/ui/main.d.ts.map +1 -0
- package/dist/explorer/ui/main.js +8 -0
- package/dist/explorer/ui/main.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/index-D4w3JVrv.css +1 -0
- package/dist/ui/assets/index-DBRKE5qL.js +52 -0
- package/dist/ui/index.html +13 -0
- package/package.json +50 -50
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { ShallowStrategy } from './strategies/ShallowStrategy.js';
|
|
3
|
+
import { SignatureStrategy } from './strategies/SignatureStrategy.js';
|
|
4
|
+
import { DeepStrategy } from './strategies/DeepStrategy.js';
|
|
5
|
+
import { FileContextBuilder } from './FileContextBuilder.js';
|
|
6
|
+
const DEFAULT_STRATEGY = 'signature';
|
|
7
|
+
const DEFAULT_MAX_TOKENS = 8_000;
|
|
8
|
+
/**
|
|
9
|
+
* Builds LLM-ready context payloads from an analysed `Codebase`.
|
|
10
|
+
*
|
|
11
|
+
* Consumers should obtain an instance via `codebase.context()` rather than
|
|
12
|
+
* constructing one directly.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const payload = await codebase.context().forFile('src/auth/AuthService.ts', {
|
|
17
|
+
* strategy: 'signature',
|
|
18
|
+
* maxTokens: 6000,
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class ContextEngine {
|
|
23
|
+
graph;
|
|
24
|
+
symbolIndex;
|
|
25
|
+
fileIndex;
|
|
26
|
+
codebaseRoot;
|
|
27
|
+
strategies = {
|
|
28
|
+
shallow: new ShallowStrategy(),
|
|
29
|
+
signature: new SignatureStrategy(),
|
|
30
|
+
deep: new DeepStrategy(),
|
|
31
|
+
};
|
|
32
|
+
builder = new FileContextBuilder();
|
|
33
|
+
constructor(graph, symbolIndex, fileIndex, codebaseRoot) {
|
|
34
|
+
this.graph = graph;
|
|
35
|
+
this.symbolIndex = symbolIndex;
|
|
36
|
+
this.fileIndex = fileIndex;
|
|
37
|
+
this.codebaseRoot = codebaseRoot;
|
|
38
|
+
}
|
|
39
|
+
// ---- Public API -------------------------------------------------------
|
|
40
|
+
async forFile(file, options = {}) {
|
|
41
|
+
const absolutePath = this.resolveFilePath(file);
|
|
42
|
+
const codebaseFile = this.requireFile(absolutePath);
|
|
43
|
+
return this.buildPayload(codebaseFile, options);
|
|
44
|
+
}
|
|
45
|
+
async forSymbol(symbolName, options = {}) {
|
|
46
|
+
const symbol = this.symbolIndex.findSymbol(symbolName);
|
|
47
|
+
if (!symbol) {
|
|
48
|
+
throw new Error(`ContextEngine: symbol "${symbolName}" not found in the index. ` +
|
|
49
|
+
`Make sure codebase.analyze() has been called.`);
|
|
50
|
+
}
|
|
51
|
+
const codebaseFile = this.requireFile(symbol.file);
|
|
52
|
+
return this.buildPayload(codebaseFile, options);
|
|
53
|
+
}
|
|
54
|
+
// ---- Core build logic -------------------------------------------------
|
|
55
|
+
async buildPayload(targetFile, options) {
|
|
56
|
+
const strategy = options.strategy ?? DEFAULT_STRATEGY;
|
|
57
|
+
const maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
58
|
+
// 1. Gather metadata from the graph
|
|
59
|
+
const directDeps = this.graph.dependenciesOf(targetFile.path);
|
|
60
|
+
const directDependents = this.graph.dependentsOf(targetFile.path);
|
|
61
|
+
const relatedTests = this.findRelatedTests(targetFile.path);
|
|
62
|
+
const metadata = {
|
|
63
|
+
directDependencies: directDeps,
|
|
64
|
+
directDependents,
|
|
65
|
+
relatedTests,
|
|
66
|
+
};
|
|
67
|
+
// 2. Resolve dependency CodebaseFile objects
|
|
68
|
+
const dependencyFiles = directDeps
|
|
69
|
+
.map(depPath => this.fileIndex.getByPath(depPath))
|
|
70
|
+
.filter((f) => f !== undefined);
|
|
71
|
+
// 3. Delegate to the selected strategy
|
|
72
|
+
const strategyImpl = this.strategies[strategy];
|
|
73
|
+
const strategyNodes = await strategyImpl.buildNodes(targetFile, dependencyFiles, this.symbolIndex, this.codebaseRoot);
|
|
74
|
+
// 4. Optionally include dependents (always as shallow/full-file nodes)
|
|
75
|
+
const dependentNodes = [];
|
|
76
|
+
if (options.includeDependents) {
|
|
77
|
+
for (const depPath of directDependents) {
|
|
78
|
+
const depFile = this.fileIndex.getByPath(depPath);
|
|
79
|
+
if (!depFile)
|
|
80
|
+
continue;
|
|
81
|
+
dependentNodes.push(await this.builder.buildFileNode(depFile, this.codebaseRoot));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 5. Optionally include related test files
|
|
85
|
+
const testNodes = [];
|
|
86
|
+
if (options.includeTests) {
|
|
87
|
+
for (const testPath of relatedTests) {
|
|
88
|
+
const testFile = this.fileIndex.getByPath(testPath);
|
|
89
|
+
if (!testFile)
|
|
90
|
+
continue;
|
|
91
|
+
testNodes.push(await this.builder.buildFileNode(testFile, this.codebaseRoot));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 6. Assemble: strategy nodes first, then dependents, then tests.
|
|
95
|
+
// Respect the maxTokens budget by dropping lower-priority nodes from the end.
|
|
96
|
+
const allNodes = [...strategyNodes, ...dependentNodes, ...testNodes];
|
|
97
|
+
const nodes = this.applyTokenBudget(allNodes, maxTokens);
|
|
98
|
+
const totalTokenEstimate = estimateTokens(nodes);
|
|
99
|
+
return {
|
|
100
|
+
target: targetFile.relativePath,
|
|
101
|
+
strategy,
|
|
102
|
+
nodes,
|
|
103
|
+
totalTokenEstimate,
|
|
104
|
+
metadata,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// ---- Token budget enforcement -----------------------------------------
|
|
108
|
+
/**
|
|
109
|
+
* Drops nodes from the *end* of the list (lower priority) until the
|
|
110
|
+
* total token estimate fits within the budget.
|
|
111
|
+
*
|
|
112
|
+
* The first node (the target) is NEVER dropped.
|
|
113
|
+
*/
|
|
114
|
+
applyTokenBudget(nodes, maxTokens) {
|
|
115
|
+
if (nodes.length === 0)
|
|
116
|
+
return nodes;
|
|
117
|
+
// nodes[0] is guaranteed to exist — the length check above ensures it.
|
|
118
|
+
const target = nodes[0];
|
|
119
|
+
const result = [target];
|
|
120
|
+
let tokensSoFar = estimateTokens(result);
|
|
121
|
+
for (let i = 1; i < nodes.length; i++) {
|
|
122
|
+
const candidate = nodes[i];
|
|
123
|
+
const candidateTokens = estimateTokens([candidate]);
|
|
124
|
+
if (tokensSoFar + candidateTokens <= maxTokens) {
|
|
125
|
+
result.push(candidate);
|
|
126
|
+
tokensSoFar += candidateTokens;
|
|
127
|
+
}
|
|
128
|
+
// Drop the node silently — the metadata still records it existed
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
// ---- Path resolution --------------------------------------------------
|
|
133
|
+
/**
|
|
134
|
+
* Resolves a file argument to an absolute path.
|
|
135
|
+
* Accepts both absolute paths and paths relative to the codebase root.
|
|
136
|
+
*/
|
|
137
|
+
resolveFilePath(file) {
|
|
138
|
+
if (path.isAbsolute(file))
|
|
139
|
+
return file;
|
|
140
|
+
return path.resolve(this.codebaseRoot, file);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Returns the `CodebaseFile` for the given absolute path.
|
|
144
|
+
* Throws a descriptive error if the file is not in the index.
|
|
145
|
+
*/
|
|
146
|
+
requireFile(absolutePath) {
|
|
147
|
+
const file = this.fileIndex.getByPath(absolutePath) ??
|
|
148
|
+
this.fileIndex.getByRelativePath(path.relative(this.codebaseRoot, absolutePath));
|
|
149
|
+
if (!file) {
|
|
150
|
+
throw new Error(`ContextEngine: file "${absolutePath}" is not in the codebase index. ` +
|
|
151
|
+
`Make sure codebase.analyze() has been called and the path is correct.`);
|
|
152
|
+
}
|
|
153
|
+
return file;
|
|
154
|
+
}
|
|
155
|
+
// ---- Related tests ----------------------------------------------------
|
|
156
|
+
/**
|
|
157
|
+
* Finds test files related to `filePath` by naming convention only.
|
|
158
|
+
* No graph proof is used — this mirrors the behaviour of `ImpactAnalyzer`.
|
|
159
|
+
*/
|
|
160
|
+
findRelatedTests(filePath) {
|
|
161
|
+
const basename = path.basename(filePath, path.extname(filePath));
|
|
162
|
+
const testSuffixes = ['.test.ts', '.spec.ts', '.test.js', '.spec.js'];
|
|
163
|
+
const candidates = new Set(testSuffixes.map(s => `${basename}${s}`));
|
|
164
|
+
return this.graph.nodes().filter(node => candidates.has(path.basename(node)));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Token estimation
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
/**
|
|
171
|
+
* Rough token estimate: `totalChars / 4`.
|
|
172
|
+
* Avoids a hard dependency on a tokeniser library while being accurate enough
|
|
173
|
+
* for budget planning (typical ratio for English/code text).
|
|
174
|
+
*/
|
|
175
|
+
function estimateTokens(nodes) {
|
|
176
|
+
const totalChars = nodes.reduce((sum, n) => sum + n.content.length, 0);
|
|
177
|
+
return Math.ceil(totalChars / 4);
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=ContextEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextEngine.js","sourceRoot":"","sources":["../../src/context/ContextEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ContextNode } from './types.js';
|
|
2
|
+
import type { CodebaseFile, CodeSymbol } from '../core/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reads a source file from disk and constructs a `ContextNode` of kind `'file'`
|
|
5
|
+
* that represents the full content of that file.
|
|
6
|
+
*
|
|
7
|
+
* This is the low-level primitive used by strategies. Strategies decide *which*
|
|
8
|
+
* files to pass here and how to compose the resulting nodes into a payload.
|
|
9
|
+
*/
|
|
10
|
+
export declare class FileContextBuilder {
|
|
11
|
+
/**
|
|
12
|
+
* Builds a single `ContextNode` for a whole file.
|
|
13
|
+
*
|
|
14
|
+
* @param file - The `CodebaseFile` descriptor (path, relativePath, etc.).
|
|
15
|
+
* @param codebaseRoot - Absolute path to the codebase root, used to compute
|
|
16
|
+
* `relativePath` as a fallback when `file.relativePath`
|
|
17
|
+
* is an absolute path.
|
|
18
|
+
*/
|
|
19
|
+
buildFileNode(file: CodebaseFile, codebaseRoot: string): Promise<ContextNode>;
|
|
20
|
+
/**
|
|
21
|
+
* Builds a `ContextNode` of kind `'signature'` for a given file.
|
|
22
|
+
*
|
|
23
|
+
* A signature node contains only the lines that correspond to top-level
|
|
24
|
+
* symbol declarations (class, function, interface, etc.) as extracted by
|
|
25
|
+
* the `SymbolIndex`. This gives the LLM full type information without the
|
|
26
|
+
* implementation body.
|
|
27
|
+
*
|
|
28
|
+
* When no symbols are found for the file, falls back to returning a full
|
|
29
|
+
* file node so the payload is never empty.
|
|
30
|
+
*
|
|
31
|
+
* @param file - The `CodebaseFile` descriptor.
|
|
32
|
+
* @param symbols - Symbols extracted for this file by the `SymbolIndex`.
|
|
33
|
+
* @param codebaseRoot - Absolute codebase root for relativePath computation.
|
|
34
|
+
*/
|
|
35
|
+
buildSignatureNode(file: CodebaseFile, symbols: CodeSymbol[], codebaseRoot: string): Promise<ContextNode>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns a normalised relative path for `file`, computing it from the
|
|
38
|
+
* absolute path when `file.relativePath` is itself absolute (can happen
|
|
39
|
+
* with older index builds).
|
|
40
|
+
*/
|
|
41
|
+
resolveRelativePath(file: CodebaseFile, codebaseRoot: string): string;
|
|
42
|
+
private readFile;
|
|
43
|
+
private normaliseRelativePath;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Builds a stable, unique node ID in the format `relativePath:start-end`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildNodeId(relativePath: string, start: number, end: number): string;
|
|
49
|
+
//# sourceMappingURL=FileContextBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileContextBuilder.d.ts","sourceRoot":"","sources":["../../src/context/FileContextBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B;;;;;;;OAOG;IACU,aAAa,CACxB,IAAI,EAAE,YAAY,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,CAgBtB;IAED;;;;;;;;;;;;;;OAcG;IACU,kBAAkB,CAC7B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,UAAU,EAAE,EACrB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,CA0CtB;IAID;;;;OAIG;IACI,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE3E;YAIa,QAAQ;IAUtB,OAAO,CAAC,qBAAqB;CAY9B;AAMD;;GAEG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Reads a source file from disk and constructs a `ContextNode` of kind `'file'`
|
|
5
|
+
* that represents the full content of that file.
|
|
6
|
+
*
|
|
7
|
+
* This is the low-level primitive used by strategies. Strategies decide *which*
|
|
8
|
+
* files to pass here and how to compose the resulting nodes into a payload.
|
|
9
|
+
*/
|
|
10
|
+
export class FileContextBuilder {
|
|
11
|
+
/**
|
|
12
|
+
* Builds a single `ContextNode` for a whole file.
|
|
13
|
+
*
|
|
14
|
+
* @param file - The `CodebaseFile` descriptor (path, relativePath, etc.).
|
|
15
|
+
* @param codebaseRoot - Absolute path to the codebase root, used to compute
|
|
16
|
+
* `relativePath` as a fallback when `file.relativePath`
|
|
17
|
+
* is an absolute path.
|
|
18
|
+
*/
|
|
19
|
+
async buildFileNode(file, codebaseRoot) {
|
|
20
|
+
const content = await this.readFile(file.path);
|
|
21
|
+
const lines = content.split('\n');
|
|
22
|
+
const totalLines = lines.length;
|
|
23
|
+
const relativePath = this.normaliseRelativePath(file.relativePath, file.path, codebaseRoot);
|
|
24
|
+
return {
|
|
25
|
+
id: buildNodeId(relativePath, 1, totalLines),
|
|
26
|
+
file: file.path,
|
|
27
|
+
relativePath,
|
|
28
|
+
content,
|
|
29
|
+
kind: 'file',
|
|
30
|
+
startLine: 1,
|
|
31
|
+
endLine: totalLines,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Builds a `ContextNode` of kind `'signature'` for a given file.
|
|
36
|
+
*
|
|
37
|
+
* A signature node contains only the lines that correspond to top-level
|
|
38
|
+
* symbol declarations (class, function, interface, etc.) as extracted by
|
|
39
|
+
* the `SymbolIndex`. This gives the LLM full type information without the
|
|
40
|
+
* implementation body.
|
|
41
|
+
*
|
|
42
|
+
* When no symbols are found for the file, falls back to returning a full
|
|
43
|
+
* file node so the payload is never empty.
|
|
44
|
+
*
|
|
45
|
+
* @param file - The `CodebaseFile` descriptor.
|
|
46
|
+
* @param symbols - Symbols extracted for this file by the `SymbolIndex`.
|
|
47
|
+
* @param codebaseRoot - Absolute codebase root for relativePath computation.
|
|
48
|
+
*/
|
|
49
|
+
async buildSignatureNode(file, symbols, codebaseRoot) {
|
|
50
|
+
const content = await this.readFile(file.path);
|
|
51
|
+
const lines = content.split('\n');
|
|
52
|
+
const relativePath = this.normaliseRelativePath(file.relativePath, file.path, codebaseRoot);
|
|
53
|
+
if (symbols.length === 0) {
|
|
54
|
+
// No symbols — fall back to the full file node
|
|
55
|
+
return this.buildFileNode(file, codebaseRoot);
|
|
56
|
+
}
|
|
57
|
+
// Collect only the declaration lines (startLine) of top-level symbols.
|
|
58
|
+
// Children (methods inside a class) are intentionally excluded because
|
|
59
|
+
// the class signature line already signals the class's existence.
|
|
60
|
+
const topLevelSymbols = symbols.filter(s => s.parentId === undefined);
|
|
61
|
+
const declarationLineNumbers = new Set(topLevelSymbols.map(s => s.startLine));
|
|
62
|
+
const signatureLines = lines
|
|
63
|
+
.map((line, i) => ({ line, lineNumber: i + 1 })) // 1-based
|
|
64
|
+
.filter(({ lineNumber }) => declarationLineNumbers.has(lineNumber))
|
|
65
|
+
.map(({ line }) => line);
|
|
66
|
+
// Always include import lines — they communicate the dependency surface.
|
|
67
|
+
const importLines = lines.filter(l => l.trimStart().startsWith('import '));
|
|
68
|
+
// Deduplicate (import lines may already be declaration lines for re-exports)
|
|
69
|
+
const signatureContent = [
|
|
70
|
+
...importLines,
|
|
71
|
+
...(importLines.length > 0 ? [''] : []), // blank separator
|
|
72
|
+
...signatureLines,
|
|
73
|
+
]
|
|
74
|
+
.join('\n')
|
|
75
|
+
.trim();
|
|
76
|
+
return {
|
|
77
|
+
id: buildNodeId(relativePath, 1, lines.length),
|
|
78
|
+
file: file.path,
|
|
79
|
+
relativePath,
|
|
80
|
+
content: signatureContent || content, // never return empty content
|
|
81
|
+
kind: 'signature',
|
|
82
|
+
startLine: 1,
|
|
83
|
+
endLine: lines.length,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// ---- Public helpers -----------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* Returns a normalised relative path for `file`, computing it from the
|
|
89
|
+
* absolute path when `file.relativePath` is itself absolute (can happen
|
|
90
|
+
* with older index builds).
|
|
91
|
+
*/
|
|
92
|
+
resolveRelativePath(file, codebaseRoot) {
|
|
93
|
+
return this.normaliseRelativePath(file.relativePath, file.path, codebaseRoot);
|
|
94
|
+
}
|
|
95
|
+
// ---- Private helpers ----------------------------------------------------
|
|
96
|
+
async readFile(filePath) {
|
|
97
|
+
try {
|
|
98
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
// Surface a clear error rather than a generic ENOENT stack trace.
|
|
102
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
103
|
+
throw new Error(`ContextEngine: could not read file "${filePath}": ${message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
normaliseRelativePath(relativePath, absolutePath, codebaseRoot) {
|
|
107
|
+
// If the stored relativePath happens to be an absolute path (older index
|
|
108
|
+
// versions), compute it from scratch.
|
|
109
|
+
if (path.isAbsolute(relativePath)) {
|
|
110
|
+
return path.relative(codebaseRoot, absolutePath);
|
|
111
|
+
}
|
|
112
|
+
return relativePath;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Utility
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* Builds a stable, unique node ID in the format `relativePath:start-end`.
|
|
120
|
+
*/
|
|
121
|
+
export function buildNodeId(relativePath, start, end) {
|
|
122
|
+
return `${relativePath}:${start}-${end}`;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=FileContextBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileContextBuilder.js","sourceRoot":"","sources":["../../src/context/FileContextBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { CodebaseFile, SymbolKind } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A semantically complete fragment of a source file, suitable for embedding
|
|
4
|
+
* or retrieval in a RAG pipeline.
|
|
5
|
+
*
|
|
6
|
+
* Unlike character-based splits, every `SemanticChunk` is guaranteed to
|
|
7
|
+
* correspond to a complete AST declaration (class, function, method, etc.) so
|
|
8
|
+
* it can always be understood in isolation when paired with the file header.
|
|
9
|
+
*/
|
|
10
|
+
export interface SemanticChunk {
|
|
11
|
+
/**
|
|
12
|
+
* Stable unique identifier: `<relativePath>:<startLine>-<endLine>`.
|
|
13
|
+
* Matches the format used by `ContextNode.id`.
|
|
14
|
+
*/
|
|
15
|
+
id: string;
|
|
16
|
+
/** Absolute path to the source file. */
|
|
17
|
+
file: string;
|
|
18
|
+
/** Path relative to the codebase root. */
|
|
19
|
+
relativePath: string;
|
|
20
|
+
/**
|
|
21
|
+
* The content of this chunk.
|
|
22
|
+
*
|
|
23
|
+
* For `symbolKind !== 'file'`, the content always starts with the file
|
|
24
|
+
* header (imports) so the chunk can be understood in isolation.
|
|
25
|
+
*/
|
|
26
|
+
content: string;
|
|
27
|
+
/**
|
|
28
|
+
* The granularity of this chunk:
|
|
29
|
+
* - `'file'` — the entire file (used when a small file fits in one chunk)
|
|
30
|
+
* - a `SymbolKind` — a top-level declaration or one of its methods
|
|
31
|
+
*/
|
|
32
|
+
symbolKind: SymbolKind | 'file';
|
|
33
|
+
/** Name of the top-level symbol (or the method name for sub-chunks). */
|
|
34
|
+
symbolName?: string;
|
|
35
|
+
/** 1-based start line in the source file. */
|
|
36
|
+
startLine: number;
|
|
37
|
+
/** 1-based end line in the source file. */
|
|
38
|
+
endLine: number;
|
|
39
|
+
/** Rough token estimate: `Math.ceil(content.length / 4)`. */
|
|
40
|
+
tokenEstimate: number;
|
|
41
|
+
}
|
|
42
|
+
/** Options for `SemanticChunker.chunk()`. */
|
|
43
|
+
export interface ChunkerOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Maximum token budget for a single chunk before it is split by methods.
|
|
46
|
+
* @default 512
|
|
47
|
+
*/
|
|
48
|
+
maxChunkTokens?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Whether to prepend the file header (imports + top-of-file comments) to
|
|
51
|
+
* each symbol chunk. Recommended so each chunk is self-contained.
|
|
52
|
+
* @default true
|
|
53
|
+
*/
|
|
54
|
+
includeFileHeader?: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Divides TypeScript/JavaScript source files into semantically coherent
|
|
58
|
+
* chunks using the `ts-morph` AST.
|
|
59
|
+
*
|
|
60
|
+
* Unlike character or line-based splitters, `SemanticChunker` guarantees that:
|
|
61
|
+
* - No chunk cuts across a declaration boundary.
|
|
62
|
+
* - Large symbols (classes with many methods) are split **by method**, not
|
|
63
|
+
* arbitrarily.
|
|
64
|
+
* - Each chunk includes the file header (imports) so it can be embedded
|
|
65
|
+
* and understood without additional context.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const chunker = new SemanticChunker();
|
|
70
|
+
* const chunks = await chunker.chunk(codebase.files(), { maxChunkTokens: 512 });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare class SemanticChunker {
|
|
74
|
+
private readonly project;
|
|
75
|
+
constructor();
|
|
76
|
+
/**
|
|
77
|
+
* Chunks the given list of files into semantically complete fragments.
|
|
78
|
+
*
|
|
79
|
+
* Only TypeScript and JavaScript files are processed via AST chunking.
|
|
80
|
+
* Other file types (JSON, config files) are returned as a single whole-file
|
|
81
|
+
* chunk if they fit within `maxChunkTokens`, or omitted otherwise.
|
|
82
|
+
*
|
|
83
|
+
* @param files - The list of `CodebaseFile`s to chunk.
|
|
84
|
+
* @param options - Chunking configuration.
|
|
85
|
+
* @returns Ordered list of `SemanticChunk`s across all processed files.
|
|
86
|
+
*/
|
|
87
|
+
chunk(files: CodebaseFile[], options?: ChunkerOptions): Promise<SemanticChunk[]>;
|
|
88
|
+
private chunkFile;
|
|
89
|
+
private chunksForDeclaration;
|
|
90
|
+
/**
|
|
91
|
+
* Emits the class as one chunk. If that chunk exceeds `maxChunkTokens`,
|
|
92
|
+
* falls back to per-method sub-chunking.
|
|
93
|
+
*/
|
|
94
|
+
private chunksForClass;
|
|
95
|
+
/**
|
|
96
|
+
* Splits an oversized class into one chunk per method/constructor.
|
|
97
|
+
* Properties and the class header are included in every method chunk.
|
|
98
|
+
*/
|
|
99
|
+
private subChunkByMethod;
|
|
100
|
+
private buildSymbolChunk;
|
|
101
|
+
private buildWholeFileChunk;
|
|
102
|
+
private chunkNonTsFile;
|
|
103
|
+
private buildChunk;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=SemanticChunker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SemanticChunker.d.ts","sourceRoot":"","sources":["../../src/context/SemanticChunker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMjE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;IAChC,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAElC,cASC;IAED;;;;;;;;;;OAUG;IACU,KAAK,CAChB,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,EAAE,CAAC,CAU1B;YAIa,SAAS;IA0CvB,OAAO,CAAC,oBAAoB;IAmB5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IA+BtB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA4ExB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,UAAU;CAwBnB"}
|