@codeledger/selector 0.1.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/LICENSE +27 -0
- package/dist/bundle.d.ts +14 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +131 -0
- package/dist/bundle.js.map +1 -0
- package/dist/candidates.d.ts +20 -0
- package/dist/candidates.d.ts.map +1 -0
- package/dist/candidates.js +305 -0
- package/dist/candidates.js.map +1 -0
- package/dist/confidence.d.ts +11 -0
- package/dist/confidence.d.ts.map +1 -0
- package/dist/confidence.js +86 -0
- package/dist/confidence.js.map +1 -0
- package/dist/deprecation.d.ts +7 -0
- package/dist/deprecation.d.ts.map +1 -0
- package/dist/deprecation.js +57 -0
- package/dist/deprecation.js.map +1 -0
- package/dist/excerpt.d.ts +8 -0
- package/dist/excerpt.d.ts.map +1 -0
- package/dist/excerpt.js +175 -0
- package/dist/excerpt.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/scorer.d.ts +24 -0
- package/dist/scorer.d.ts.map +1 -0
- package/dist/scorer.js +214 -0
- package/dist/scorer.js.map +1 -0
- package/dist/stop-rule.d.ts +9 -0
- package/dist/stop-rule.d.ts.map +1 -0
- package/dist/stop-rule.js +33 -0
- package/dist/stop-rule.js.map +1 -0
- package/dist/stubs.d.ts +9 -0
- package/dist/stubs.d.ts.map +1 -0
- package/dist/stubs.js +161 -0
- package/dist/stubs.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confidence.js","sourceRoot":"","sources":["../src/confidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DeprecationRule, DeprecationWarning } from '@codeledger/types';
|
|
2
|
+
/**
|
|
3
|
+
* Scan file content for deprecated API patterns and return warnings.
|
|
4
|
+
* Merges built-in rules with any custom rules from config.
|
|
5
|
+
*/
|
|
6
|
+
export declare function scanDeprecations(content: string, customRules?: DeprecationRule[]): DeprecationWarning[];
|
|
7
|
+
//# sourceMappingURL=deprecation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecation.d.ts","sourceRoot":"","sources":["../src/deprecation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAyB7E;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,eAAe,EAAE,GAC9B,kBAAkB,EAAE,CAkCtB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Built-in deprecation rules for common patterns across languages */
|
|
2
|
+
const BUILTIN_RULES = [
|
|
3
|
+
// Node.js / JavaScript
|
|
4
|
+
{ pattern: '\\bfs\\.exists\\b', message: 'fs.exists is deprecated — use fs.access() or fs.stat()' },
|
|
5
|
+
{ pattern: '\\bfs\\.existsSync\\b', message: 'fs.existsSync is deprecated in async contexts — prefer fs.accessSync()' },
|
|
6
|
+
{ pattern: '\\bnew Buffer\\(', message: 'Buffer() constructor is deprecated — use Buffer.from() or Buffer.alloc()' },
|
|
7
|
+
{ pattern: '\\brequire\\(\'url\'\\)\\.parse', message: 'url.parse() is deprecated — use new URL() constructor' },
|
|
8
|
+
{ pattern: '\\burl\\.parse\\(', message: 'url.parse() is deprecated — use new URL() constructor' },
|
|
9
|
+
{ pattern: '\\butil\\.isArray\\b', message: 'util.isArray is deprecated — use Array.isArray()' },
|
|
10
|
+
{ pattern: '\\butil\\.isDate\\b', message: 'util.isDate is deprecated — use instanceof Date' },
|
|
11
|
+
{ pattern: '\\butil\\.isRegExp\\b', message: 'util.isRegExp is deprecated — use instanceof RegExp' },
|
|
12
|
+
// React
|
|
13
|
+
{ pattern: '\\bcomponentWillMount\\b', message: 'componentWillMount is deprecated — use componentDidMount or useEffect' },
|
|
14
|
+
{ pattern: '\\bcomponentWillReceiveProps\\b', message: 'componentWillReceiveProps is deprecated — use getDerivedStateFromProps or useEffect' },
|
|
15
|
+
{ pattern: '\\bcomponentWillUpdate\\b', message: 'componentWillUpdate is deprecated — use getSnapshotBeforeUpdate' },
|
|
16
|
+
{ pattern: '\\bReact\\.createClass\\b', message: 'React.createClass is removed — use class components or function components' },
|
|
17
|
+
{ pattern: '\\bReactDOM\\.render\\(', message: 'ReactDOM.render is deprecated in React 18+ — use createRoot().render()' },
|
|
18
|
+
// TypeScript
|
|
19
|
+
{ pattern: '@ts-ignore', message: 'Prefer @ts-expect-error over @ts-ignore for better error tracking' },
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Scan file content for deprecated API patterns and return warnings.
|
|
23
|
+
* Merges built-in rules with any custom rules from config.
|
|
24
|
+
*/
|
|
25
|
+
export function scanDeprecations(content, customRules) {
|
|
26
|
+
const rules = [...BUILTIN_RULES, ...(customRules ?? [])];
|
|
27
|
+
const warnings = [];
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
for (let i = 0; i < lines.length; i++) {
|
|
30
|
+
const line = lines[i];
|
|
31
|
+
// Skip comments (rough heuristic — won't catch all cases but avoids
|
|
32
|
+
// false positives on documentation)
|
|
33
|
+
const trimmed = line.trim();
|
|
34
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
for (const rule of rules) {
|
|
38
|
+
let regex;
|
|
39
|
+
try {
|
|
40
|
+
regex = new RegExp(rule.pattern);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
continue; // skip invalid patterns
|
|
44
|
+
}
|
|
45
|
+
const match = regex.exec(line);
|
|
46
|
+
if (match) {
|
|
47
|
+
warnings.push({
|
|
48
|
+
line: i + 1,
|
|
49
|
+
matched: match[0],
|
|
50
|
+
message: rule.message,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return warnings;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=deprecation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deprecation.js","sourceRoot":"","sources":["../src/deprecation.ts"],"names":[],"mappings":"AAEA,sEAAsE;AACtE,MAAM,aAAa,GAAsB;IACvC,uBAAuB;IACvB,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,wDAAwD,EAAE;IACnG,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,wEAAwE,EAAE;IACvH,EAAE,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,0EAA0E,EAAE;IACpH,EAAE,OAAO,EAAE,iCAAiC,EAAE,OAAO,EAAE,uDAAuD,EAAE;IAChH,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,uDAAuD,EAAE;IAClG,EAAE,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,kDAAkD,EAAE;IAChG,EAAE,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,iDAAiD,EAAE;IAC9F,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,qDAAqD,EAAE;IAEpG,QAAQ;IACR,EAAE,OAAO,EAAE,0BAA0B,EAAE,OAAO,EAAE,uEAAuE,EAAE;IACzH,EAAE,OAAO,EAAE,iCAAiC,EAAE,OAAO,EAAE,qFAAqF,EAAE;IAC9I,EAAE,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,iEAAiE,EAAE;IACpH,EAAE,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,4EAA4E,EAAE;IAC/H,EAAE,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,wEAAwE,EAAE;IAEzH,aAAa;IACb,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,mEAAmE,EAAE;CACxG,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,WAA+B;IAE/B,MAAM,KAAK,GAAG,CAAC,GAAG,aAAa,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,oEAAoE;QACpE,oCAAoC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACpF,SAAS;QACX,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,KAAa,CAAC;YAClB,IAAI,CAAC;gBACH,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,wBAAwB;YACpC,CAAC;YAED,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,KAAK,EAAE,CAAC;gBACV,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;oBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExcerptSpan } from '@codeledger/types';
|
|
2
|
+
export interface ExcerptResult {
|
|
3
|
+
content: string;
|
|
4
|
+
spans: ExcerptSpan[] | null;
|
|
5
|
+
lineCount: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function extractExcerpt(root: string, filePath: string, keywords: string[], fullFileMaxLines: number, windowLines: number): ExcerptResult;
|
|
8
|
+
//# sourceMappingURL=excerpt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excerpt.d.ts","sourceRoot":"","sources":["../src/excerpt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,GAClB,aAAa,CA0Gf"}
|
package/dist/excerpt.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/** Maximum file size to read (10 MB) — prevents OOM on huge files */
|
|
4
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
5
|
+
export function extractExcerpt(root, filePath, keywords, fullFileMaxLines, windowLines) {
|
|
6
|
+
const absPath = join(root, filePath);
|
|
7
|
+
let content;
|
|
8
|
+
try {
|
|
9
|
+
const size = statSync(absPath).size;
|
|
10
|
+
if (size > MAX_FILE_SIZE) {
|
|
11
|
+
return { content: `// File too large (${Math.round(size / 1024)}KB), skipped`, spans: null, lineCount: 1 };
|
|
12
|
+
}
|
|
13
|
+
content = readFileSync(absPath, 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { content: '', spans: null, lineCount: 0 };
|
|
17
|
+
}
|
|
18
|
+
const lines = content.split('\n');
|
|
19
|
+
// Full file if small enough
|
|
20
|
+
if (lines.length <= fullFileMaxLines) {
|
|
21
|
+
return { content, spans: null, lineCount: lines.length };
|
|
22
|
+
}
|
|
23
|
+
// Otherwise: extract type surfaces + export signatures + keyword windows.
|
|
24
|
+
// Priority order: type surfaces first (interfaces, types, enums, function
|
|
25
|
+
// signatures), then export signatures, then keyword windows. This ensures
|
|
26
|
+
// the agent sees contracts and APIs before implementation details.
|
|
27
|
+
const spans = [];
|
|
28
|
+
const includedLines = new Set();
|
|
29
|
+
// Pass 1: Type-surface extraction — interfaces, type aliases, enums,
|
|
30
|
+
// and function/class declarations (signatures only, not bodies).
|
|
31
|
+
// These are the highest-value excerpts: they define the contract.
|
|
32
|
+
for (let i = 0; i < lines.length; i++) {
|
|
33
|
+
const line = lines[i];
|
|
34
|
+
if (isTypeSurface(line)) {
|
|
35
|
+
// Include the declaration and capture the full signature block
|
|
36
|
+
// (multi-line interfaces, type aliases with generics, etc.)
|
|
37
|
+
const start = Math.max(0, i - 1);
|
|
38
|
+
let end = Math.min(lines.length - 1, i + 1);
|
|
39
|
+
// For interface/type/enum: extend to closing brace (limited scope)
|
|
40
|
+
if (isBlockOpener(line)) {
|
|
41
|
+
end = findBlockEnd(lines, i, 20); // cap at 20 lines
|
|
42
|
+
}
|
|
43
|
+
spans.push({ start_line: start + 1, end_line: end + 1, reason: 'type_surface' });
|
|
44
|
+
for (let j = start; j <= end; j++) {
|
|
45
|
+
includedLines.add(j);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Pass 2: Export signatures (non-type exports like exported consts, functions)
|
|
50
|
+
for (let i = 0; i < lines.length; i++) {
|
|
51
|
+
const line = lines[i];
|
|
52
|
+
if (isExportSignature(line) && !includedLines.has(i)) {
|
|
53
|
+
const start = Math.max(0, i - 1);
|
|
54
|
+
const end = Math.min(lines.length - 1, i + 2);
|
|
55
|
+
spans.push({ start_line: start + 1, end_line: end + 1, reason: 'export_signature' });
|
|
56
|
+
for (let j = start; j <= end; j++) {
|
|
57
|
+
includedLines.add(j);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Pass 3: Keyword windows
|
|
62
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63
|
+
const lineLower = lines[i].toLowerCase();
|
|
64
|
+
for (const kw of keywords) {
|
|
65
|
+
if (lineLower.includes(kw)) {
|
|
66
|
+
const start = Math.max(0, i - windowLines);
|
|
67
|
+
const end = Math.min(lines.length - 1, i + windowLines);
|
|
68
|
+
spans.push({
|
|
69
|
+
start_line: start + 1,
|
|
70
|
+
end_line: end + 1,
|
|
71
|
+
reason: `keyword_match:${kw}`,
|
|
72
|
+
});
|
|
73
|
+
for (let j = start; j <= end; j++) {
|
|
74
|
+
includedLines.add(j);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Build excerpt content
|
|
81
|
+
const sortedLines = [...includedLines].sort((a, b) => a - b);
|
|
82
|
+
const excerptParts = [];
|
|
83
|
+
let lastLine = -2;
|
|
84
|
+
for (const lineNum of sortedLines) {
|
|
85
|
+
if (lineNum > lastLine + 1) {
|
|
86
|
+
excerptParts.push(`\n// ... (lines ${lastLine + 2}–${lineNum} omitted) ...\n`);
|
|
87
|
+
}
|
|
88
|
+
excerptParts.push(lines[lineNum]);
|
|
89
|
+
lastLine = lineNum;
|
|
90
|
+
}
|
|
91
|
+
const excerptContent = excerptParts.join('\n');
|
|
92
|
+
// Merge overlapping spans
|
|
93
|
+
const mergedSpans = mergeSpans(spans);
|
|
94
|
+
return {
|
|
95
|
+
content: excerptContent,
|
|
96
|
+
spans: mergedSpans,
|
|
97
|
+
lineCount: sortedLines.length,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Detect type-surface declarations: interfaces, type aliases, enums,
|
|
102
|
+
* function signatures, and class declarations — both exported and non-exported.
|
|
103
|
+
* These define the file's contract and are the highest-value excerpts.
|
|
104
|
+
*/
|
|
105
|
+
function isTypeSurface(line) {
|
|
106
|
+
const trimmed = line.trim();
|
|
107
|
+
// Remove 'export ' and 'declare ' prefixes for uniform matching
|
|
108
|
+
const normalized = trimmed
|
|
109
|
+
.replace(/^export\s+(default\s+)?/, '')
|
|
110
|
+
.replace(/^declare\s+/, '');
|
|
111
|
+
return (normalized.startsWith('interface ') ||
|
|
112
|
+
normalized.startsWith('type ') ||
|
|
113
|
+
normalized.startsWith('enum ') ||
|
|
114
|
+
// Function signatures (but not arrow functions assigned to variables)
|
|
115
|
+
(normalized.startsWith('function ') && !normalized.includes('=>')) ||
|
|
116
|
+
// Abstract class declarations
|
|
117
|
+
normalized.startsWith('abstract class ') ||
|
|
118
|
+
normalized.startsWith('class '));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Check if a line opens a block (has `{` but no closing `}` on the same line).
|
|
122
|
+
*/
|
|
123
|
+
function isBlockOpener(line) {
|
|
124
|
+
const trimmed = line.trim();
|
|
125
|
+
return trimmed.includes('{') && !trimmed.includes('}');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Find the end of a block starting at `startIdx`, capped at `maxLines` from start.
|
|
129
|
+
* Tracks brace depth to handle nested blocks.
|
|
130
|
+
*/
|
|
131
|
+
function findBlockEnd(lines, startIdx, maxLines) {
|
|
132
|
+
let depth = 0;
|
|
133
|
+
const limit = Math.min(lines.length - 1, startIdx + maxLines);
|
|
134
|
+
for (let i = startIdx; i <= limit; i++) {
|
|
135
|
+
const line = lines[i];
|
|
136
|
+
for (const ch of line) {
|
|
137
|
+
if (ch === '{')
|
|
138
|
+
depth++;
|
|
139
|
+
if (ch === '}')
|
|
140
|
+
depth--;
|
|
141
|
+
}
|
|
142
|
+
if (depth <= 0 && i > startIdx)
|
|
143
|
+
return i;
|
|
144
|
+
}
|
|
145
|
+
return limit;
|
|
146
|
+
}
|
|
147
|
+
function isExportSignature(line) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
return (trimmed.startsWith('export ') &&
|
|
150
|
+
(trimmed.includes('function ') ||
|
|
151
|
+
trimmed.includes('class ') ||
|
|
152
|
+
trimmed.includes('interface ') ||
|
|
153
|
+
trimmed.includes('type ') ||
|
|
154
|
+
trimmed.includes('const ') ||
|
|
155
|
+
trimmed.includes('enum ')));
|
|
156
|
+
}
|
|
157
|
+
function mergeSpans(spans) {
|
|
158
|
+
if (spans.length === 0)
|
|
159
|
+
return [];
|
|
160
|
+
const sorted = [...spans].sort((a, b) => a.start_line - b.start_line);
|
|
161
|
+
const merged = [sorted[0]];
|
|
162
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
163
|
+
const current = sorted[i];
|
|
164
|
+
const last = merged[merged.length - 1];
|
|
165
|
+
if (current.start_line <= last.end_line + 1) {
|
|
166
|
+
last.end_line = Math.max(last.end_line, current.end_line);
|
|
167
|
+
last.reason = `${last.reason}+${current.reason}`;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
merged.push({ ...current });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return merged;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=excerpt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excerpt.js","sourceRoot":"","sources":["../src/excerpt.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { generateCandidates, tokenizeTask, computeTokenWeights } from './candidates.js';
|
|
2
|
+
export type { CandidateResult } from './candidates.js';
|
|
3
|
+
export { computeFeatures, scoreFile, scoreAllCandidates, deriveReasons, gateTemporalFeatures } from './scorer.js';
|
|
4
|
+
export type { LedgerStats } from './scorer.js';
|
|
5
|
+
export { shouldStop, estimateTokens } from './stop-rule.js';
|
|
6
|
+
export { extractExcerpt } from './excerpt.js';
|
|
7
|
+
export { buildBundle } from './bundle.js';
|
|
8
|
+
export type { BuildBundleOptions } from './bundle.js';
|
|
9
|
+
export { assessConfidence } from './confidence.js';
|
|
10
|
+
export { generateInterfaceStubs } from './stubs.js';
|
|
11
|
+
export { scanDeprecations } from './deprecation.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACxF,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,kBAAkB,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAClH,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { generateCandidates, tokenizeTask, computeTokenWeights } from './candidates.js';
|
|
2
|
+
export { computeFeatures, scoreFile, scoreAllCandidates, deriveReasons, gateTemporalFeatures } from './scorer.js';
|
|
3
|
+
export { shouldStop, estimateTokens } from './stop-rule.js';
|
|
4
|
+
export { extractExcerpt } from './excerpt.js';
|
|
5
|
+
export { buildBundle } from './bundle.js';
|
|
6
|
+
export { assessConfidence } from './confidence.js';
|
|
7
|
+
export { generateInterfaceStubs } from './stubs.js';
|
|
8
|
+
export { scanDeprecations } from './deprecation.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAExF,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,kBAAkB,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAElH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/scorer.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { FileInfo, FileFeatures, RepoIndex, ScoredFile, SelectorWeights, ReasonCode } from '@codeledger/types';
|
|
2
|
+
export interface LedgerStats {
|
|
3
|
+
success_files: Set<string>;
|
|
4
|
+
fail_files: Set<string>;
|
|
5
|
+
}
|
|
6
|
+
export declare function computeFeatures(file: FileInfo, taskKeywords: string[], repoIndex: RepoIndex, ledgerStats?: LedgerStats, tokenWeights?: Map<string, number>): FileFeatures;
|
|
7
|
+
/**
|
|
8
|
+
* Scale temporal signals (churn, recent_touch) by keyword strength.
|
|
9
|
+
*
|
|
10
|
+
* Churn and recency are useful tie-breakers among task-relevant files, but
|
|
11
|
+
* they shouldn't let irrelevant hot files dominate. We scale temporal signals
|
|
12
|
+
* proportionally to keyword relevance:
|
|
13
|
+
*
|
|
14
|
+
* - Strong keyword (>= 0.3): full temporal signals
|
|
15
|
+
* - Weak keyword (> 0, < 0.3): half temporal signals — a tiny "api" hit
|
|
16
|
+
* shouldn't give full churn credit
|
|
17
|
+
* - No keyword but structural signal (centrality/test): quarter temporal
|
|
18
|
+
* - No signal at all: zero temporal
|
|
19
|
+
*/
|
|
20
|
+
export declare function gateTemporalFeatures(features: FileFeatures): FileFeatures;
|
|
21
|
+
export declare function scoreFile(features: FileFeatures, weights: SelectorWeights): number;
|
|
22
|
+
export declare function deriveReasons(features: FileFeatures): ReasonCode[];
|
|
23
|
+
export declare function scoreAllCandidates(candidates: Set<string>, taskKeywords: string[], repoIndex: RepoIndex, weights: SelectorWeights, ledgerStats?: LedgerStats, tokenWeights?: Map<string, number>, fanoutFiles?: Set<string>): ScoredFile[];
|
|
24
|
+
//# sourceMappingURL=scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,UAAU,EACX,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAkCD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,MAAM,EAAE,EACtB,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,WAAW,EACzB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,YAAY,CA6Gd;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAoBzE;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,eAAe,GACvB,MAAM,CAYR;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,UAAU,EAAE,CAelE;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,YAAY,EAAE,MAAM,EAAE,EACtB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,eAAe,EACxB,WAAW,CAAC,EAAE,WAAW,EACzB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,UAAU,EAAE,CA8Bd"}
|
package/dist/scorer.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/** Path/name patterns that indicate error infrastructure files */
|
|
2
|
+
const ERROR_INFRA_PATTERNS = [
|
|
3
|
+
'error', 'exception', 'validation', 'validator', 'schema',
|
|
4
|
+
];
|
|
5
|
+
/** Multiplier for keywords that match the filename stem exactly. */
|
|
6
|
+
const FILENAME_EXACT_MULT = 3.0;
|
|
7
|
+
/** Multiplier for keywords that match content identifiers (weaker than path). */
|
|
8
|
+
const CONTENT_MATCH_MULT = 0.5;
|
|
9
|
+
/** Score bonus for files pulled in via fan-out dependent expansion.
|
|
10
|
+
* Needs to be strong enough to beat generic keyword+churn files. */
|
|
11
|
+
const FANOUT_BONUS = 0.25;
|
|
12
|
+
/**
|
|
13
|
+
* Detect whether a file is error infrastructure based on naming patterns.
|
|
14
|
+
* Error infrastructure = custom error classes, validation schemas, error middleware.
|
|
15
|
+
*/
|
|
16
|
+
function detectErrorInfrastructure(file) {
|
|
17
|
+
const pathLower = file.path.toLowerCase();
|
|
18
|
+
const basename = pathLower.split('/').pop()?.replace(/\.\w+$/, '') ?? '';
|
|
19
|
+
const stems = basename.split(/[-_]/);
|
|
20
|
+
// Check if any stem matches error infrastructure patterns
|
|
21
|
+
const isErrorInfra = stems.some((stem) => ERROR_INFRA_PATTERNS.some((pat) => stem === pat || stem === pat + 's'));
|
|
22
|
+
return isErrorInfra ? 1.0 : 0;
|
|
23
|
+
}
|
|
24
|
+
export function computeFeatures(file, taskKeywords, repoIndex, ledgerStats, tokenWeights) {
|
|
25
|
+
const pathLower = file.path.toLowerCase();
|
|
26
|
+
const contentKws = file.content_keywords ?? [];
|
|
27
|
+
// Extract filename stems for exact-match boosting.
|
|
28
|
+
// Split basename on `-` and `_` for compound names:
|
|
29
|
+
// "rate-limiter.ts" -> ["rate", "limiter"]
|
|
30
|
+
// "helpers.ts" -> ["helpers"]
|
|
31
|
+
const fileBasename = pathLower.split('/').pop()?.replace(/\.\w+$/, '') ?? '';
|
|
32
|
+
const fileStems = fileBasename.split(/[-_]/);
|
|
33
|
+
// KW: keyword/path/content match score with IDF weighting + boosts.
|
|
34
|
+
//
|
|
35
|
+
// Three match tiers:
|
|
36
|
+
// 1. Filename-stem match (3x): keyword matches a basename stem exactly
|
|
37
|
+
// 2. Path match (1x): keyword appears anywhere in the file path
|
|
38
|
+
// 3. Content match (0.5x): keyword matches an identifier from file content
|
|
39
|
+
//
|
|
40
|
+
// This ensures files like jest.config.ts and package.json (which contain
|
|
41
|
+
// "test" in their content but not their path) still get discovered for
|
|
42
|
+
// test-related tasks.
|
|
43
|
+
let kwScore = 0;
|
|
44
|
+
let maxPossible = 0;
|
|
45
|
+
let _hasContentMatch = false;
|
|
46
|
+
for (const kw of taskKeywords) {
|
|
47
|
+
const w = tokenWeights?.get(kw) ?? 1;
|
|
48
|
+
if (w === 0)
|
|
49
|
+
continue; // zero-match keyword -- skip entirely
|
|
50
|
+
maxPossible += w;
|
|
51
|
+
// Check path first (stronger signal)
|
|
52
|
+
if (pathLower.includes(kw)) {
|
|
53
|
+
// Stem match with singular/plural tolerance across all stems
|
|
54
|
+
const isStemMatch = fileStems.some((stem) => stem === kw || stem === kw + 's' || kw === stem + 's');
|
|
55
|
+
kwScore += w * (isStemMatch ? FILENAME_EXACT_MULT : 1);
|
|
56
|
+
}
|
|
57
|
+
else if (contentKws.some((ck) => ck === kw || ck === kw + 's' || kw === ck + 's')) {
|
|
58
|
+
// Content match: weaker than path but still a positive signal
|
|
59
|
+
kwScore += w * CONTENT_MATCH_MULT;
|
|
60
|
+
_hasContentMatch = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const keyword = maxPossible > 0
|
|
64
|
+
? Math.min(1, kwScore / (maxPossible * 1.5))
|
|
65
|
+
: 0;
|
|
66
|
+
// CENT: graph centrality (normalized degree)
|
|
67
|
+
const imports = repoIndex.dep_graph.imports[file.path]?.length ?? 0;
|
|
68
|
+
const dependents = repoIndex.dep_graph.dependents[file.path]?.length ?? 0;
|
|
69
|
+
const totalDegree = imports + dependents;
|
|
70
|
+
const maxDegree = Math.max(1, ...repoIndex.files.map((f) => {
|
|
71
|
+
const imp = repoIndex.dep_graph.imports[f.path]?.length ?? 0;
|
|
72
|
+
const dep = repoIndex.dep_graph.dependents[f.path]?.length ?? 0;
|
|
73
|
+
return imp + dep;
|
|
74
|
+
}));
|
|
75
|
+
const centrality = totalDegree / maxDegree;
|
|
76
|
+
// CHURN: commit frequency with time-decay
|
|
77
|
+
const churnEntry = repoIndex.churn.find((c) => c.path === file.path);
|
|
78
|
+
const churn = churnEntry?.time_decayed_score ?? 0;
|
|
79
|
+
// RECENT_TOUCH: days since last touch
|
|
80
|
+
const daysSince = churnEntry?.days_since_last_touch ?? 999;
|
|
81
|
+
const recent_touch = daysSince <= 7 ? 1.0
|
|
82
|
+
: daysSince <= 14 ? 0.8
|
|
83
|
+
: daysSince <= 30 ? 0.5
|
|
84
|
+
: daysSince <= 60 ? 0.2
|
|
85
|
+
: 0;
|
|
86
|
+
// TEST_RELEV: graduated test relevance based on test file richness.
|
|
87
|
+
// Instead of binary 0/1, tests with more assertions, describe blocks, and
|
|
88
|
+
// error handling patterns score higher — they're more valuable context.
|
|
89
|
+
const testMappings = repoIndex.test_map.filter((m) => m.source_file === file.path || m.test_file === file.path);
|
|
90
|
+
let test_relevance = 0;
|
|
91
|
+
if (testMappings.length > 0) {
|
|
92
|
+
// Base score for having a test mapping
|
|
93
|
+
test_relevance = 0.5;
|
|
94
|
+
// Bonus based on number of test mappings (more coverage = higher relevance)
|
|
95
|
+
test_relevance += Math.min(0.5, testMappings.length * 0.25);
|
|
96
|
+
}
|
|
97
|
+
// SIZE_PEN: penalty for large files
|
|
98
|
+
const size_penalty = Math.max(0, Math.min(1, file.lines / 1000));
|
|
99
|
+
// SUCCESS_PRIOR / FAIL_PRIOR from ledger
|
|
100
|
+
const success_prior = ledgerStats?.success_files.has(file.path) ? 1.0 : 0;
|
|
101
|
+
const fail_prior = ledgerStats?.fail_files.has(file.path) ? 1.0 : 0;
|
|
102
|
+
// ERROR_INFRA: detect error infrastructure files (custom errors, validators, error middleware)
|
|
103
|
+
const error_infrastructure = detectErrorInfrastructure(file);
|
|
104
|
+
return {
|
|
105
|
+
keyword,
|
|
106
|
+
centrality,
|
|
107
|
+
churn,
|
|
108
|
+
recent_touch,
|
|
109
|
+
test_relevance,
|
|
110
|
+
size_penalty,
|
|
111
|
+
success_prior,
|
|
112
|
+
fail_prior,
|
|
113
|
+
error_infrastructure,
|
|
114
|
+
_hasContentMatch,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Scale temporal signals (churn, recent_touch) by keyword strength.
|
|
119
|
+
*
|
|
120
|
+
* Churn and recency are useful tie-breakers among task-relevant files, but
|
|
121
|
+
* they shouldn't let irrelevant hot files dominate. We scale temporal signals
|
|
122
|
+
* proportionally to keyword relevance:
|
|
123
|
+
*
|
|
124
|
+
* - Strong keyword (>= 0.3): full temporal signals
|
|
125
|
+
* - Weak keyword (> 0, < 0.3): half temporal signals — a tiny "api" hit
|
|
126
|
+
* shouldn't give full churn credit
|
|
127
|
+
* - No keyword but structural signal (centrality/test): quarter temporal
|
|
128
|
+
* - No signal at all: zero temporal
|
|
129
|
+
*/
|
|
130
|
+
export function gateTemporalFeatures(features) {
|
|
131
|
+
let scale;
|
|
132
|
+
if (features.keyword >= 0.3) {
|
|
133
|
+
scale = 1.0;
|
|
134
|
+
}
|
|
135
|
+
else if (features.keyword > 0) {
|
|
136
|
+
scale = 0.5;
|
|
137
|
+
}
|
|
138
|
+
else if (features.test_relevance > 0 || features.centrality > 0.1) {
|
|
139
|
+
scale = 0.4;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
scale = 0;
|
|
143
|
+
}
|
|
144
|
+
if (scale === 1.0)
|
|
145
|
+
return features;
|
|
146
|
+
return {
|
|
147
|
+
...features,
|
|
148
|
+
churn: features.churn * scale,
|
|
149
|
+
recent_touch: features.recent_touch * scale,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
export function scoreFile(features, weights) {
|
|
153
|
+
return (features.keyword * weights.keyword +
|
|
154
|
+
features.centrality * weights.centrality +
|
|
155
|
+
features.churn * weights.churn +
|
|
156
|
+
features.recent_touch * weights.recent_touch +
|
|
157
|
+
features.test_relevance * weights.test_relevance -
|
|
158
|
+
features.size_penalty * weights.size_penalty +
|
|
159
|
+
features.success_prior * weights.success_prior -
|
|
160
|
+
features.fail_prior * weights.fail_prior +
|
|
161
|
+
features.error_infrastructure * (weights.error_infrastructure ?? 0.08));
|
|
162
|
+
}
|
|
163
|
+
export function deriveReasons(features) {
|
|
164
|
+
const reasons = [];
|
|
165
|
+
if (features.keyword > 0) {
|
|
166
|
+
reasons.push('keyword_match');
|
|
167
|
+
// Distinguish pure content matches (no path hit) from path matches
|
|
168
|
+
if (features._hasContentMatch)
|
|
169
|
+
reasons.push('content_match');
|
|
170
|
+
}
|
|
171
|
+
if (features.centrality > 0.3)
|
|
172
|
+
reasons.push('dependency_neighbor');
|
|
173
|
+
if (features.churn > 0.3)
|
|
174
|
+
reasons.push('high_churn');
|
|
175
|
+
if (features.recent_touch > 0.5)
|
|
176
|
+
reasons.push('recent_touch');
|
|
177
|
+
if (features.test_relevance > 0)
|
|
178
|
+
reasons.push('test_relevant');
|
|
179
|
+
if (features.size_penalty > 0.5)
|
|
180
|
+
reasons.push('size_penalty');
|
|
181
|
+
if (features.success_prior > 0)
|
|
182
|
+
reasons.push('success_prior');
|
|
183
|
+
if (features.error_infrastructure > 0)
|
|
184
|
+
reasons.push('error_infrastructure');
|
|
185
|
+
return reasons;
|
|
186
|
+
}
|
|
187
|
+
export function scoreAllCandidates(candidates, taskKeywords, repoIndex, weights, ledgerStats, tokenWeights, fanoutFiles) {
|
|
188
|
+
const fileMap = new Map(repoIndex.files.map((f) => [f.path, f]));
|
|
189
|
+
const results = [];
|
|
190
|
+
for (const path of candidates) {
|
|
191
|
+
const file = fileMap.get(path);
|
|
192
|
+
if (!file)
|
|
193
|
+
continue;
|
|
194
|
+
const rawFeatures = computeFeatures(file, taskKeywords, repoIndex, ledgerStats, tokenWeights);
|
|
195
|
+
const gated = gateTemporalFeatures(rawFeatures);
|
|
196
|
+
// Preserve _hasContentMatch through gating for reason derivation
|
|
197
|
+
const features = { ...gated, _hasContentMatch: rawFeatures._hasContentMatch };
|
|
198
|
+
let score = scoreFile(features, weights);
|
|
199
|
+
const reasons = deriveReasons(features);
|
|
200
|
+
// Fan-out bonus: files pulled in via dependent expansion get a boost
|
|
201
|
+
// so they aren't crowded out by unrelated hot files.
|
|
202
|
+
if (fanoutFiles?.has(path)) {
|
|
203
|
+
score += FANOUT_BONUS;
|
|
204
|
+
if (!reasons.includes('dependent_neighbor')) {
|
|
205
|
+
reasons.push('dependent_neighbor');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
results.push({ path, score, features, reasons });
|
|
209
|
+
}
|
|
210
|
+
// Sort by score descending
|
|
211
|
+
results.sort((a, b) => b.score - a.score);
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Budget, BundleFile } from '@codeledger/types';
|
|
2
|
+
export declare function estimateTokens(lines: number): number;
|
|
3
|
+
export interface StopState {
|
|
4
|
+
files: BundleFile[];
|
|
5
|
+
totalTokens: number;
|
|
6
|
+
cumulativeScore: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function shouldStop(state: StopState, budget: Budget, sufficiencyThreshold: number, maxCumulativeScore: number): boolean;
|
|
9
|
+
//# sourceMappingURL=stop-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-rule.d.ts","sourceRoot":"","sources":["../src/stop-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI5D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAcD,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,oBAAoB,EAAE,MAAM,EAC5B,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAqBT"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const TOKENS_PER_LINE = 4;
|
|
2
|
+
export function estimateTokens(lines) {
|
|
3
|
+
return lines * TOKENS_PER_LINE;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Check whether a strong task-relevant signal exists in the current bundle.
|
|
7
|
+
* Prevents the sufficiency threshold from declaring "enough" when the bundle
|
|
8
|
+
* is full of noise (high-churn files with no keyword/dep/test relevance).
|
|
9
|
+
*/
|
|
10
|
+
function hasStrongSignal(files) {
|
|
11
|
+
return files.some((f) => f.reasons.includes('keyword_match') ||
|
|
12
|
+
f.reasons.includes('test_relevant'));
|
|
13
|
+
}
|
|
14
|
+
export function shouldStop(state, budget, sufficiencyThreshold, maxCumulativeScore) {
|
|
15
|
+
// Hard limits: always enforce max_files and token budget
|
|
16
|
+
if (budget.max_files && state.files.length >= budget.max_files) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (budget.tokens && state.totalTokens >= budget.tokens) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
// Sufficiency threshold: only stop if we have at least one strong seed hit.
|
|
23
|
+
// This prevents "confidently wrong" bundles where cumulative score reaches
|
|
24
|
+
// the threshold via high-churn noise without any task-relevant files.
|
|
25
|
+
if (maxCumulativeScore > 0) {
|
|
26
|
+
const ratio = state.cumulativeScore / maxCumulativeScore;
|
|
27
|
+
if (ratio >= sufficiencyThreshold && hasStrongSignal(state.files)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=stop-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop-rule.js","sourceRoot":"","sources":["../src/stop-rule.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK,GAAG,eAAe,CAAC;AACjC,CAAC;AAQD;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAmB;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACtB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;QACnC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAgB,EAChB,MAAc,EACd,oBAA4B,EAC5B,kBAA0B;IAE1B,yDAAyD;IACzD,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,2EAA2E;IAC3E,sEAAsE;IACtE,IAAI,kBAAkB,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,GAAG,kBAAkB,CAAC;QACzD,IAAI,KAAK,IAAI,oBAAoB,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|