flowseeker 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +111 -0
- package/COMPATIBILITY.md +281 -0
- package/LICENSE +21 -0
- package/README.md +375 -0
- package/dist/adapters/frameworkEdges.js +586 -0
- package/dist/agent/approvalPolicy.js +81 -0
- package/dist/agent/commandRunner.js +166 -0
- package/dist/agent/flowCommandRunner.js +124 -0
- package/dist/agent/mcpToolRunner.js +167 -0
- package/dist/auth/githubAuth.js +71 -0
- package/dist/auth/modelList.js +127 -0
- package/dist/auth/oauthHandler.js +377 -0
- package/dist/chat/nativeChatParticipant.js +616 -0
- package/dist/cli/mcpServer.js +383 -0
- package/dist/cli/runEvaluation.js +789 -0
- package/dist/cli/runReplay.js +481 -0
- package/dist/commands/checkHostCompatibility.js +149 -0
- package/dist/commands/copyAgentPrompt.js +52 -0
- package/dist/commands/copyContext.js +54 -0
- package/dist/commands/explainSelectionRelevance.js +57 -0
- package/dist/commands/findRelevantContext.js +127 -0
- package/dist/commands/openEvidence.js +49 -0
- package/dist/commands/openMcpConfig.js +81 -0
- package/dist/commands/openRelatedTests.js +54 -0
- package/dist/commands/rebuildIndex.js +45 -0
- package/dist/commands/runEvaluationSuite.js +323 -0
- package/dist/commands/runReplaySuite.js +228 -0
- package/dist/config/defaultConfig.js +72 -0
- package/dist/config/loadConfig.js +84 -0
- package/dist/config/loadConfigFromPath.js +60 -0
- package/dist/extension.js +513 -0
- package/dist/gateway/agentPrompts.js +176 -0
- package/dist/gateway/aiGateway.js +1255 -0
- package/dist/gateway/aiProviders.js +901 -0
- package/dist/gateway/contextExpansion.js +331 -0
- package/dist/gateway/editProposalStore.js +238 -0
- package/dist/gateway/planProposalStore.js +28 -0
- package/dist/index/cacheStore.js +51 -0
- package/dist/index/chunker.js +45 -0
- package/dist/index/dependencyExtractor.js +107 -0
- package/dist/index/fileDiscovery.js +177 -0
- package/dist/index/structuredExtractor.js +256 -0
- package/dist/index/workspaceIndex.js +518 -0
- package/dist/mcp/mcpConfig.js +154 -0
- package/dist/mcp/mcpProvider.js +109 -0
- package/dist/mcp/mcpTools.js +215 -0
- package/dist/pipeline/agentPrompt.js +79 -0
- package/dist/pipeline/agentPromptHeadless.js +85 -0
- package/dist/pipeline/contextBlueprint.js +346 -0
- package/dist/pipeline/contextPack.js +80 -0
- package/dist/pipeline/diffPreview.js +79 -0
- package/dist/pipeline/evaluationMetrics.js +154 -0
- package/dist/pipeline/evidenceGraph.js +389 -0
- package/dist/pipeline/feedback.js +215 -0
- package/dist/pipeline/fileGroups.js +84 -0
- package/dist/pipeline/fileScanner.js +866 -0
- package/dist/pipeline/nodeScan.js +219 -0
- package/dist/pipeline/ranker.js +563 -0
- package/dist/pipeline/responseLanguage.js +39 -0
- package/dist/pipeline/retrievalPlan.js +163 -0
- package/dist/pipeline/runHeadless.js +54 -0
- package/dist/pipeline/runPipeline.js +114 -0
- package/dist/pipeline/solvePacket.js +382 -0
- package/dist/pipeline/subsystem.js +257 -0
- package/dist/pipeline/taskUnderstanding.js +453 -0
- package/dist/pipeline/tokenSavings.js +146 -0
- package/dist/pipeline/universalScan.js +216 -0
- package/dist/pipeline/verifyAfterApply.js +233 -0
- package/dist/runtime/capabilities.js +71 -0
- package/dist/runtime/hostDetect.js +98 -0
- package/dist/runtime/hostTier.js +68 -0
- package/dist/runtime/statusBar.js +80 -0
- package/dist/skills/skillRegistry.js +208 -0
- package/dist/types.js +3 -0
- package/dist/ui/chatViewProvider.js +3899 -0
- package/dist/ui/resultTreeProvider.js +174 -0
- package/dist/usage/quotaTracker.js +358 -0
- package/dist/utils/async.js +30 -0
- package/dist/utils/logger.js +64 -0
- package/dist/utils/text.js +364 -0
- package/dist/utils/updateChecker.js +140 -0
- package/package.json +561 -0
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.scanTextFile = scanTextFile;
|
|
37
|
+
exports.getWeightedTerms = getWeightedTerms;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const chunker_1 = require("../index/chunker");
|
|
40
|
+
const dependencyExtractor_1 = require("../index/dependencyExtractor");
|
|
41
|
+
const structuredExtractor_1 = require("../index/structuredExtractor");
|
|
42
|
+
const text_1 = require("../utils/text");
|
|
43
|
+
const contextBlueprint_1 = require("./contextBlueprint");
|
|
44
|
+
const subsystem_1 = require("./subsystem");
|
|
45
|
+
const MAX_MATCHED_LINES_PER_FILE = 160;
|
|
46
|
+
const MAX_CHUNKS_PER_FILE = 12;
|
|
47
|
+
const MAX_CHUNK_LINES = 120;
|
|
48
|
+
const MAX_SEARCHABLE_LINE_CHARS = 12000;
|
|
49
|
+
const MAX_STRUCTURED_MATCHED_LINES = 80;
|
|
50
|
+
const MAX_STRUCTURED_SCAN_BYTES = 220000;
|
|
51
|
+
function scanTextFile(input) {
|
|
52
|
+
if (input.content.includes("\u0000")) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const weightedTerms = getWeightedTerms(input.profile);
|
|
56
|
+
const pathScore = scorePath(input.relativePath, weightedTerms);
|
|
57
|
+
const matchedLines = findMatchedLines(input.content, weightedTerms, MAX_MATCHED_LINES_PER_FILE);
|
|
58
|
+
const hasOversizedLine = containsLineLongerThan(input.content, MAX_SEARCHABLE_LINE_CHARS);
|
|
59
|
+
const headContent = input.content.slice(0, 200000);
|
|
60
|
+
const imports = (0, dependencyExtractor_1.extractImports)(headContent).map((item) => item.source).slice(0, 30);
|
|
61
|
+
const language = (0, structuredExtractor_1.detectLanguage)(input.relativePath);
|
|
62
|
+
const canExtractStructuredNodes = language &&
|
|
63
|
+
input.config.index.enableTreeSitter &&
|
|
64
|
+
input.size <= MAX_STRUCTURED_SCAN_BYTES &&
|
|
65
|
+
matchedLines.size <= MAX_STRUCTURED_MATCHED_LINES &&
|
|
66
|
+
!hasOversizedLine &&
|
|
67
|
+
(matchedLines.size > 0 || pathScore > 0);
|
|
68
|
+
const structuredNodes = canExtractStructuredNodes ? (0, structuredExtractor_1.extractStructuredNodes)(headContent, language) : [];
|
|
69
|
+
const fileMetadata = buildEvidenceMetadata(input.relativePath, structuredNodes, weightedTerms);
|
|
70
|
+
const units = [];
|
|
71
|
+
if (matchedLines.size > 0) {
|
|
72
|
+
const lineNumbers = Array.from(matchedLines.keys());
|
|
73
|
+
const chunks = (0, chunker_1.chunkAroundLines)(input.content, lineNumbers, 14, MAX_CHUNK_LINES).slice(0, MAX_CHUNKS_PER_FILE);
|
|
74
|
+
for (const chunk of chunks) {
|
|
75
|
+
const evidenceText = `${input.relativePath}\n${chunk.text}`;
|
|
76
|
+
const matchedTerms = collectMatchedTerms(evidenceText, weightedTerms);
|
|
77
|
+
const retrievalPasses = collectRetrievalPasses(evidenceText, input.profile, input.relativePath);
|
|
78
|
+
const score = pathScore + scoreSnippet(chunk.text, matchedTerms) + kindBonus(input.relativePath, chunk.text) + pathIntentModifier(input.relativePath, chunk.text, input.profile);
|
|
79
|
+
const kind = detectKind(input.relativePath, chunk.text);
|
|
80
|
+
const role = detectRole(kind, score, input.profile, input.relativePath, chunk.text);
|
|
81
|
+
units.push(toEvidenceUnit(input.file, input.relativePath, kind, role, chunk.range, score, matchedTerms, retrievalPasses, imports, reasonsFor(input.relativePath, kind, matchedTerms, retrievalPasses, imports, pathScore, chunk.text), chunk.text, fileMetadata));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (pathScore > 0 && units.length === 0) {
|
|
85
|
+
const firstChunk = (0, chunker_1.chunkFile)(input.content, input.config.index.chunkSizeLines, input.config.index.chunkOverlapLines)[0];
|
|
86
|
+
const kind = detectKind(input.relativePath, firstChunk?.text ?? "");
|
|
87
|
+
const evidenceText = `${input.relativePath}\n${firstChunk?.text ?? ""}`;
|
|
88
|
+
const matchedTerms = collectMatchedTerms(evidenceText, weightedTerms);
|
|
89
|
+
const retrievalPasses = collectRetrievalPasses(evidenceText, input.profile, input.relativePath);
|
|
90
|
+
const score = pathScore + kindBonus(input.relativePath, firstChunk?.text ?? "") + pathIntentModifier(input.relativePath, firstChunk?.text ?? "", input.profile);
|
|
91
|
+
units.push(toEvidenceUnit(input.file, input.relativePath, kind, detectRole(kind, score, input.profile, input.relativePath, firstChunk?.text ?? ""), firstChunk?.range, score, matchedTerms, retrievalPasses, imports, reasonsFor(input.relativePath, kind, matchedTerms, retrievalPasses, imports, pathScore, firstChunk?.text ?? ""), firstChunk?.text, fileMetadata));
|
|
92
|
+
}
|
|
93
|
+
if (structuredNodes.length > 0 && language) {
|
|
94
|
+
units.push(...buildStructuredEvidence(input, structuredNodes, weightedTerms, imports, pathScore, fileMetadata, language));
|
|
95
|
+
}
|
|
96
|
+
return dedupeUnitsPerFile(units, 6);
|
|
97
|
+
}
|
|
98
|
+
function getWeightedTerms(profile) {
|
|
99
|
+
const byTerm = new Map();
|
|
100
|
+
const fallbackTerms = profile.keywords.map((term) => ({ term, weight: 1.5, source: "concept" }));
|
|
101
|
+
for (const term of profile.passes.flatMap((pass) => pass.terms).concat(fallbackTerms)) {
|
|
102
|
+
const normalized = (0, text_1.normalizeText)(term.term);
|
|
103
|
+
const existing = byTerm.get(normalized);
|
|
104
|
+
if (!existing || term.weight > existing.weight) {
|
|
105
|
+
byTerm.set(normalized, { ...term, term: normalized });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return Array.from(byTerm.values());
|
|
109
|
+
}
|
|
110
|
+
function scorePath(relativePath, terms) {
|
|
111
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
112
|
+
const pathTokens = (0, text_1.splitIdentifier)(relativePath);
|
|
113
|
+
let score = 0;
|
|
114
|
+
for (const term of terms) {
|
|
115
|
+
if (normalizedPath.includes(term.term)) {
|
|
116
|
+
score += (pathTokens.includes(term.term) ? 5 : 3) * term.weight;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return score;
|
|
120
|
+
}
|
|
121
|
+
function findMatchedLines(content, terms, maxMatches) {
|
|
122
|
+
const lines = content.split(/\r?\n/);
|
|
123
|
+
const matches = new Map();
|
|
124
|
+
const highSignalKeywords = terms.map((term) => term.term).filter(isHighSignalSearchTerm);
|
|
125
|
+
const broadKeywords = terms.map((term) => term.term).filter((term) => !highSignalKeywords.includes(term));
|
|
126
|
+
collectLineMatches(lines, highSignalKeywords, matches, maxMatches);
|
|
127
|
+
collectLineMatches(lines, broadKeywords, matches, maxMatches);
|
|
128
|
+
return matches;
|
|
129
|
+
}
|
|
130
|
+
function collectLineMatches(lines, keywords, matches, maxMatches) {
|
|
131
|
+
if (keywords.length === 0 || matches.size >= maxMatches) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (let index = 0; index < lines.length && matches.size < maxMatches; index += 1) {
|
|
135
|
+
const line = lines[index];
|
|
136
|
+
if (line.length === 0) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const normalizedLine = (0, text_1.normalizeText)(line.length > MAX_SEARCHABLE_LINE_CHARS ? line.slice(0, MAX_SEARCHABLE_LINE_CHARS) : line);
|
|
140
|
+
const lineMatches = keywords.filter((keyword) => normalizedLine.includes(keyword));
|
|
141
|
+
if (lineMatches.length > 0) {
|
|
142
|
+
matches.set(index + 1, Array.from(new Set([...(matches.get(index + 1) ?? []), ...lineMatches])));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function isHighSignalSearchTerm(term) {
|
|
147
|
+
return isSpecificCompoundTerm(term) || (term.length >= 14 && !term.includes(" "));
|
|
148
|
+
}
|
|
149
|
+
function containsLineLongerThan(content, maxChars) {
|
|
150
|
+
let currentLength = 0;
|
|
151
|
+
for (let index = 0; index < content.length; index += 1) {
|
|
152
|
+
const char = content.charCodeAt(index);
|
|
153
|
+
if (char === 10 || char === 13) {
|
|
154
|
+
currentLength = 0;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
currentLength += 1;
|
|
158
|
+
if (currentLength > maxChars) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
function scoreSnippet(snippet, matchedTerms) {
|
|
165
|
+
const normalizedSnippet = (0, text_1.normalizeText)(snippet);
|
|
166
|
+
let score = matchedTerms.length * 2;
|
|
167
|
+
for (const term of matchedTerms) {
|
|
168
|
+
const occurrences = normalizedSnippet.split(term).length - 1;
|
|
169
|
+
score += Math.min(occurrences, 8);
|
|
170
|
+
if (isSpecificCompoundTerm(term)) {
|
|
171
|
+
score += 8;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (/\b(class|function|def|public|private|route|router|controller|service|repository|handler|listener|job|worker|schema|migration)\b/i.test(snippet)) {
|
|
175
|
+
score += 4;
|
|
176
|
+
}
|
|
177
|
+
if (/\b(describe|it|test)\s*\(|\bexpect\s*\(|\bassert[.(]/i.test(snippet)) {
|
|
178
|
+
score += 2;
|
|
179
|
+
}
|
|
180
|
+
return score;
|
|
181
|
+
}
|
|
182
|
+
function isSpecificCompoundTerm(term) {
|
|
183
|
+
return term.length >= 10 && (term.includes("_") || /[a-z][0-9]/.test(term)) && (0, text_1.splitIdentifier)(term).length >= 3;
|
|
184
|
+
}
|
|
185
|
+
function collectMatchedTerms(text, terms) {
|
|
186
|
+
const normalizedText = (0, text_1.normalizeText)(text);
|
|
187
|
+
const matched = terms
|
|
188
|
+
.filter((term) => normalizedText.includes(term.term))
|
|
189
|
+
.sort((left, right) => retrievalTermPriority(right) - retrievalTermPriority(left))
|
|
190
|
+
.map((term) => term.term);
|
|
191
|
+
return Array.from(new Set(matched)).slice(0, 12);
|
|
192
|
+
}
|
|
193
|
+
function retrievalTermPriority(term) {
|
|
194
|
+
return term.weight * 10 + (isHighSignalSearchTerm(term.term) ? 40 : 0) + Math.min(12, term.term.length / 2);
|
|
195
|
+
}
|
|
196
|
+
function collectRetrievalPasses(text, profile, relativePath) {
|
|
197
|
+
const normalizedText = (0, text_1.normalizeText)(text);
|
|
198
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
199
|
+
return profile.passes
|
|
200
|
+
.filter((pass) => {
|
|
201
|
+
if (pass.purpose === "find_tests" && !isTestPath(normalizedPath)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return pass.terms.some((term) => normalizedText.includes((0, text_1.normalizeText)(term.term)));
|
|
205
|
+
})
|
|
206
|
+
.map((pass) => pass.label);
|
|
207
|
+
}
|
|
208
|
+
function detectKind(relativePath, snippet) {
|
|
209
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
210
|
+
const normalizedSnippet = (0, text_1.normalizeText)(snippet);
|
|
211
|
+
const ext = path.extname(relativePath).toLowerCase();
|
|
212
|
+
if (isTestPath(normalizedPath) || /\b(describe|it|test)\s*\(|\bexpect\s*\(|\bassert[.(]/.test(normalizedSnippet)) {
|
|
213
|
+
return "test";
|
|
214
|
+
}
|
|
215
|
+
if (/\b(migration|migrations|database)\b/.test(normalizedPath) || [".sql", ".prisma"].includes(ext)) {
|
|
216
|
+
return "migration";
|
|
217
|
+
}
|
|
218
|
+
if (/\b(schema|model|models)\b/.test(normalizedPath) || [".graphql", ".gql"].includes(ext)) {
|
|
219
|
+
return "schema";
|
|
220
|
+
}
|
|
221
|
+
if (/\b(config|env|settings|properties)\b/.test(normalizedPath) || [".env", ".ini", ".toml", ".yaml", ".yml", ".xml", ".json", ".properties"].includes(ext)) {
|
|
222
|
+
return "config";
|
|
223
|
+
}
|
|
224
|
+
if ([".md", ".mdx", ".txt", ".rst"].includes(ext)) {
|
|
225
|
+
return "doc";
|
|
226
|
+
}
|
|
227
|
+
if (isI18nPath(normalizedPath)) {
|
|
228
|
+
return "template";
|
|
229
|
+
}
|
|
230
|
+
if (isFrontendRoutePath(normalizedPath) || /\b(route|routes|router)\b/.test(normalizedPath) || /(@getmapping|@postmapping|route::|router\.|app\.get|app\.post|urlpatterns)/.test(normalizedSnippet)) {
|
|
231
|
+
return "route";
|
|
232
|
+
}
|
|
233
|
+
if ([".html", ".vue", ".svelte", ".blade.php", ".twig", ".erb", ".hbs", ".ejs", ".tsx", ".jsx"].some((suffix) => relativePath.toLowerCase().endsWith(suffix))) {
|
|
234
|
+
return "template";
|
|
235
|
+
}
|
|
236
|
+
return "code_region";
|
|
237
|
+
}
|
|
238
|
+
function detectRole(kind, score, profile, relativePath, snippet) {
|
|
239
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
240
|
+
const normalizedSnippet = (0, text_1.normalizeText)(snippet);
|
|
241
|
+
if (kind === "test") {
|
|
242
|
+
return "test";
|
|
243
|
+
}
|
|
244
|
+
if (kind === "doc") {
|
|
245
|
+
return "read_context";
|
|
246
|
+
}
|
|
247
|
+
if (isI18nPath(normalizedPath)) {
|
|
248
|
+
return "read_context";
|
|
249
|
+
}
|
|
250
|
+
if (isStaticContentPath(normalizedPath)) {
|
|
251
|
+
return "read_context";
|
|
252
|
+
}
|
|
253
|
+
if (/\b(smoke|e2e|fixture|mock|seed)\b/.test(normalizedPath)) {
|
|
254
|
+
return "verify";
|
|
255
|
+
}
|
|
256
|
+
if (isGuidanceOrReadinessPath(normalizedPath)) {
|
|
257
|
+
return "read_context";
|
|
258
|
+
}
|
|
259
|
+
if (isReadOnlyInvestigationTask(profile)) {
|
|
260
|
+
return "read_context";
|
|
261
|
+
}
|
|
262
|
+
if (isInfrastructurePath(normalizedPath)) {
|
|
263
|
+
return score >= 18 && isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) && hasStrongRuntimeSignal(normalizedSnippet) ? "impact" : "read_context";
|
|
264
|
+
}
|
|
265
|
+
if (isAdminSurfacePath(normalizedPath) && !isRuntimeFlowPath(normalizedPath, normalizedSnippet)) {
|
|
266
|
+
return "impact";
|
|
267
|
+
}
|
|
268
|
+
if (kind === "route" || kind === "template") {
|
|
269
|
+
const primaryRuntime = isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) && isRuntimeFlowPath(normalizedPath, normalizedSnippet);
|
|
270
|
+
const primaryUi = isPrimaryUiFlowPath(normalizedPath, normalizedSnippet, profile);
|
|
271
|
+
const primaryEntry = kind === "route" && isFrameworkEntryPath(normalizedPath) && hasTaskTermSignal(profile, normalizedPath, normalizedSnippet);
|
|
272
|
+
const stateStatusUi = taskTargetsStateOrStatus(profile) && isUiSurfacePath(normalizedPath) && hasTaskTermSignal(profile, normalizedPath, normalizedSnippet);
|
|
273
|
+
return (primaryRuntime || primaryUi || primaryEntry || stateStatusUi) && score >= 14 ? "edit_candidate" : "impact";
|
|
274
|
+
}
|
|
275
|
+
if (kind === "config" || kind === "schema" || kind === "migration") {
|
|
276
|
+
if (kind === "schema" && isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) && score >= 10) {
|
|
277
|
+
return "edit_candidate";
|
|
278
|
+
}
|
|
279
|
+
return shouldEditDataOrConfig(kind, profile) ? "edit_candidate" : "read_context";
|
|
280
|
+
}
|
|
281
|
+
if (isUiSurfacePath(normalizedPath) && !isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile)) {
|
|
282
|
+
return score >= 18 ? "impact" : "read_context";
|
|
283
|
+
}
|
|
284
|
+
if (isFrontendStatePath(normalizedPath) && isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) && score >= 10) {
|
|
285
|
+
return "edit_candidate";
|
|
286
|
+
}
|
|
287
|
+
if (isRuntimeFlowPath(normalizedPath, normalizedSnippet) && isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) && score >= 10) {
|
|
288
|
+
return "edit_candidate";
|
|
289
|
+
}
|
|
290
|
+
if (score >= 18) {
|
|
291
|
+
return isRuntimePath(normalizedPath) || hasStrongRuntimeSignal(normalizedSnippet) ? "edit_candidate" : "read_context";
|
|
292
|
+
}
|
|
293
|
+
if (score >= 8) {
|
|
294
|
+
return isRuntimePath(normalizedPath) ? "impact" : "read_context";
|
|
295
|
+
}
|
|
296
|
+
if (score >= 5) {
|
|
297
|
+
return "read_context";
|
|
298
|
+
}
|
|
299
|
+
return "unknown";
|
|
300
|
+
}
|
|
301
|
+
function kindBonus(relativePath, snippet) {
|
|
302
|
+
const kind = detectKind(relativePath, snippet);
|
|
303
|
+
const bonus = {
|
|
304
|
+
file: 0,
|
|
305
|
+
code_region: 2,
|
|
306
|
+
symbol: 4,
|
|
307
|
+
callsite: 3,
|
|
308
|
+
route: 4,
|
|
309
|
+
config: 3,
|
|
310
|
+
schema: 3,
|
|
311
|
+
migration: 3,
|
|
312
|
+
template: 2,
|
|
313
|
+
test: 3,
|
|
314
|
+
doc: 1,
|
|
315
|
+
asset: 0
|
|
316
|
+
};
|
|
317
|
+
return bonus[kind];
|
|
318
|
+
}
|
|
319
|
+
function pathIntentModifier(relativePath, snippet, profile) {
|
|
320
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
321
|
+
const normalizedSnippet = (0, text_1.normalizeText)(snippet);
|
|
322
|
+
let modifier = 0;
|
|
323
|
+
const pathTermHits = countTaskTermHits(normalizedPath, profile.concepts);
|
|
324
|
+
const snippetTermHits = countTaskTermHits(normalizedSnippet, profile.concepts);
|
|
325
|
+
const keywordPathHits = countTaskTermHits(normalizedPath, profile.keywords);
|
|
326
|
+
const focusedPathHits = countTaskTermHits(normalizedPath, focusedPathTerms(profile));
|
|
327
|
+
const focusedKeywordPathHits = countTaskTermHits(normalizedPath, focusedKeywordPathTerms(profile));
|
|
328
|
+
const primaryFocusedPathHits = countTaskTermHits(normalizedPath, primaryFocusedPathTerms(profile));
|
|
329
|
+
const domainEntityTerms = focusedEntityPathTerms(profile);
|
|
330
|
+
const entityPathHits = countTaskTermHits(normalizedPath, domainEntityTerms);
|
|
331
|
+
if (isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile)) {
|
|
332
|
+
modifier += 12;
|
|
333
|
+
}
|
|
334
|
+
if (entityPathHits > 0) {
|
|
335
|
+
modifier += 28 + Math.min(28, entityPathHits * 10);
|
|
336
|
+
}
|
|
337
|
+
if (taskTargetsUi(profile) && isUiSurfacePath(normalizedPath)) {
|
|
338
|
+
const focusedSnippetHits = countTaskTermHits(normalizedSnippet, focusedPathTerms(profile));
|
|
339
|
+
modifier += 8;
|
|
340
|
+
if (focusedPathHits > 0) {
|
|
341
|
+
modifier += 18 + Math.min(36, focusedPathHits * 10);
|
|
342
|
+
}
|
|
343
|
+
if (focusedPathHits >= 2) {
|
|
344
|
+
modifier += 18;
|
|
345
|
+
}
|
|
346
|
+
if (isFrontendRoutePath(normalizedPath)) {
|
|
347
|
+
modifier += focusedPathHits > 0 ? 16 : 4;
|
|
348
|
+
}
|
|
349
|
+
if (focusedSnippetHits >= 2 && hasFormOrDisplaySignal(normalizedSnippet)) {
|
|
350
|
+
modifier += 28 + Math.min(28, focusedSnippetHits * 6);
|
|
351
|
+
}
|
|
352
|
+
if (taskTargetsSettings(profile) && /\bsettings?\b/.test(normalizedPath)) {
|
|
353
|
+
modifier += 178;
|
|
354
|
+
}
|
|
355
|
+
if (matchesRequestedUiPrimitive(profile, normalizedPath)) {
|
|
356
|
+
modifier += 152;
|
|
357
|
+
}
|
|
358
|
+
if (isFrontendRouteScriptPath(normalizedPath) && (taskTargetsUrlOrRoute(profile) || focusedSnippetHits >= 2)) {
|
|
359
|
+
modifier += focusedPathHits > 0 ? 42 : 18;
|
|
360
|
+
}
|
|
361
|
+
if (isFrontendRouteScriptPath(normalizedPath) && focusedPathHits > 0) {
|
|
362
|
+
modifier += primaryFocusedPathHits > 0 ? 64 : focusedPathHits >= 2 ? 44 : 16;
|
|
363
|
+
}
|
|
364
|
+
if (isComponentPath(normalizedPath)) {
|
|
365
|
+
modifier += focusedPathHits > 0 ? 16 : 4;
|
|
366
|
+
if (focusedPathHits >= 2) {
|
|
367
|
+
modifier += 18;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (isFrontendStatePath(normalizedPath) && focusedPathHits > 0) {
|
|
372
|
+
modifier += 18 + Math.min(24, focusedPathHits * 8);
|
|
373
|
+
}
|
|
374
|
+
if (isValidationPath(normalizedPath) && taskTargetsValidation(profile)) {
|
|
375
|
+
modifier += 18 + Math.min(18, Math.max(focusedPathHits, 1) * 6);
|
|
376
|
+
}
|
|
377
|
+
if (taskTargetsData(profile) && isGenericDataPath(normalizedPath) && focusedPathHits > 0) {
|
|
378
|
+
modifier += 38 + Math.min(36, focusedPathHits * 10);
|
|
379
|
+
}
|
|
380
|
+
if (taskTargetsSecurity(profile) && taskTargetsAdmin(profile)) {
|
|
381
|
+
if (isAdminSurfacePath(normalizedPath) && (focusedPathHits > 0 || snippetTermHits > 0)) {
|
|
382
|
+
modifier += 46;
|
|
383
|
+
}
|
|
384
|
+
if (isFrameworkEntryPath(normalizedPath) && snippetTermHits > 0) {
|
|
385
|
+
modifier += 34;
|
|
386
|
+
}
|
|
387
|
+
if (isPermissionPath(normalizedPath) && !/\b(login|reset|forgot)\b/.test(normalizedPath)) {
|
|
388
|
+
modifier += 24;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (isRuntimeFlowPath(normalizedPath, normalizedSnippet)) {
|
|
392
|
+
modifier += 4;
|
|
393
|
+
modifier += Math.min(10, pathTermHits * 3 + snippetTermHits);
|
|
394
|
+
}
|
|
395
|
+
if (taskTargetsConfig(profile) && isConfigPath(normalizedPath)) {
|
|
396
|
+
modifier += 46 + Math.min(36, Math.max(keywordPathHits, focusedKeywordPathHits, focusedPathHits) * 10);
|
|
397
|
+
if (/\b(settings?|config|cache|env|environment|properties)\b/.test(normalizedPath)) {
|
|
398
|
+
modifier += 18;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if ((isBackendOnlyPath(normalizedPath) || isRuntimePath(normalizedPath)) && !isUiSurfacePath(normalizedPath) && focusedKeywordPathHits > 0) {
|
|
402
|
+
modifier += 40 + Math.min(24, focusedKeywordPathHits * 8);
|
|
403
|
+
}
|
|
404
|
+
if (domainEntityTerms.length > 0 && entityPathHits === 0 && (isRuntimePath(normalizedPath) || isBackendOnlyPath(normalizedPath)) && !isFrameworkEntryPath(normalizedPath)) {
|
|
405
|
+
modifier -= 18;
|
|
406
|
+
}
|
|
407
|
+
if (keywordPathHits > 0 && isRuntimePath(normalizedPath)) {
|
|
408
|
+
modifier += Math.min(8, keywordPathHits * 2);
|
|
409
|
+
}
|
|
410
|
+
if (hasActionSignal(normalizedSnippet, profile)) {
|
|
411
|
+
modifier += 4;
|
|
412
|
+
}
|
|
413
|
+
if (isI18nPath(normalizedPath)) {
|
|
414
|
+
modifier -= taskTargetsCopyOrI18n(profile) ? 0 : 24;
|
|
415
|
+
}
|
|
416
|
+
if (isUiSurfacePath(normalizedPath) && !taskTargetsUi(profile) && !isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile)) {
|
|
417
|
+
modifier -= 10;
|
|
418
|
+
}
|
|
419
|
+
if (isUiSurfacePath(normalizedPath) && taskTargetsSecurity(profile) && !taskTargetsUi(profile)) {
|
|
420
|
+
modifier -= 34;
|
|
421
|
+
}
|
|
422
|
+
if (taskTargetsConfig(profile) && !taskTargetsSecurity(profile) && isPermissionPath(normalizedPath) && focusedPathHits === 0) {
|
|
423
|
+
modifier -= 20;
|
|
424
|
+
}
|
|
425
|
+
if (taskTargetsUi(profile) && !taskTargetsBackend(profile) && isBackendOnlyPath(normalizedPath) && focusedPathHits === 0) {
|
|
426
|
+
modifier -= 30;
|
|
427
|
+
}
|
|
428
|
+
if (!taskTargetsData(profile) && isGenericDataPath(normalizedPath) && focusedPathHits === 0) {
|
|
429
|
+
modifier -= taskTargetsUi(profile) ? 26 : 10;
|
|
430
|
+
}
|
|
431
|
+
if (isGenericUtilityPath(normalizedPath) && !taskTargetsUtility(profile)) {
|
|
432
|
+
modifier -= taskTargetsUi(profile) ? 24 : focusedPathHits === 0 ? 24 : 14;
|
|
433
|
+
}
|
|
434
|
+
if (isMaintenanceCommandPath(normalizedPath) && !taskTargetsMaintenanceCommand(profile)) {
|
|
435
|
+
modifier -= 42;
|
|
436
|
+
}
|
|
437
|
+
if (isGuidanceOrReadinessPath(normalizedPath)) {
|
|
438
|
+
modifier -= 16;
|
|
439
|
+
}
|
|
440
|
+
if (isStaticContentPath(normalizedPath)) {
|
|
441
|
+
modifier -= 24;
|
|
442
|
+
}
|
|
443
|
+
if (isAdminSurfacePath(normalizedPath) && !taskTargetsAdmin(profile) && !isRuntimeFlowPath(normalizedPath, normalizedSnippet)) {
|
|
444
|
+
modifier -= 8;
|
|
445
|
+
}
|
|
446
|
+
if (/\b(smoke|fixture|mock|seed)\b/.test(normalizedPath)) {
|
|
447
|
+
modifier -= 8;
|
|
448
|
+
}
|
|
449
|
+
if (/(^|\/)\.flowseeker(\/|$)|(^|\/)_gen[^/]*\.(py|sh)$|(^|\/)_bulk_write\.js$/.test(normalizedPath)) {
|
|
450
|
+
modifier -= 80;
|
|
451
|
+
}
|
|
452
|
+
return modifier;
|
|
453
|
+
}
|
|
454
|
+
function reasonsFor(relativePath, kind, matchedTerms, retrievalPasses, imports, pathScore, snippet) {
|
|
455
|
+
const reasons = [];
|
|
456
|
+
if (pathScore > 0) {
|
|
457
|
+
reasons.push(`path matches: ${matchedTerms.join(", ")}`);
|
|
458
|
+
}
|
|
459
|
+
if (matchedTerms.length > 0) {
|
|
460
|
+
reasons.push(`content matches: ${matchedTerms.join(", ")}`);
|
|
461
|
+
}
|
|
462
|
+
if (retrievalPasses.length > 0) {
|
|
463
|
+
reasons.push(`retrieval passes: ${retrievalPasses.join(", ")}`);
|
|
464
|
+
}
|
|
465
|
+
if (imports.length > 0) {
|
|
466
|
+
reasons.push(`dependency imports: ${imports.slice(0, 4).join(", ")}`);
|
|
467
|
+
}
|
|
468
|
+
if (kind !== "code_region") {
|
|
469
|
+
reasons.push(`detected as ${kind}`);
|
|
470
|
+
}
|
|
471
|
+
if (isTestPath((0, text_1.normalizeText)(relativePath)) || /\b(describe|it|test)\s*\(|\bexpect\s*\(|\bassert[.(]/i.test(snippet)) {
|
|
472
|
+
reasons.push("test-related evidence");
|
|
473
|
+
}
|
|
474
|
+
if (/\b(route|router|controller|handler|listener|job|worker|queue)\b/i.test(`${relativePath}\n${snippet}`)) {
|
|
475
|
+
reasons.push("flow/control-path evidence");
|
|
476
|
+
}
|
|
477
|
+
return Array.from(new Set(reasons));
|
|
478
|
+
}
|
|
479
|
+
function isTestPath(normalizedPath) {
|
|
480
|
+
return /(^|[/\\])(__tests__|tests?|specs?|fixtures?|mocks?)([/\\]|$)|(^|[/\\])(test_|spec_)[^/\\]+\.[a-z0-9]+$|(^|[/\\])[^/\\]+_(test|spec)\.[a-z0-9]+$|(^|[/\\])(tests?|specs?)\.[a-z0-9]+$|\.(test|spec)\./.test(normalizedPath);
|
|
481
|
+
}
|
|
482
|
+
function isI18nPath(normalizedPath) {
|
|
483
|
+
return /(^|[/\\])(i18n|locales?|translations?|dictionaries|messages)([/\\]|$)|dictionary|dictionaries/.test(normalizedPath);
|
|
484
|
+
}
|
|
485
|
+
function isStaticContentPath(normalizedPath) {
|
|
486
|
+
return /(^|[/\\])(privacy-policy|terms|terms-of-service|cookie-policy|legal|about|contact)(\.|[/\\]|$)/.test(normalizedPath);
|
|
487
|
+
}
|
|
488
|
+
function isUiSurfacePath(normalizedPath) {
|
|
489
|
+
return /(^|[/\\])(app|pages|routes|components|views|screens|dashboard|admin)([/\\]|$)|\.(tsx|jsx|vue|svelte|blade\.php|twig|erb)$/.test(normalizedPath);
|
|
490
|
+
}
|
|
491
|
+
function isAdminSurfacePath(normalizedPath) {
|
|
492
|
+
return /(^|[/\\])(admin|dashboard)([/\\]|$)|admin|dashboard/.test(normalizedPath);
|
|
493
|
+
}
|
|
494
|
+
function isGuidanceOrReadinessPath(normalizedPath) {
|
|
495
|
+
return /\b(guidance|readiness|dictionary|dictionaries|i18n|locale|locales|translation|translations|message|messages|copy|content)\b/.test(normalizedPath);
|
|
496
|
+
}
|
|
497
|
+
function isRuntimeFlowPath(normalizedPath, normalizedSnippet) {
|
|
498
|
+
return isRuntimePath(normalizedPath) && hasRuntimeCodeSignal(normalizedSnippet);
|
|
499
|
+
}
|
|
500
|
+
function isRuntimePath(normalizedPath) {
|
|
501
|
+
return /\b(service|services|provider|providers|handler|handlers|listener|listeners|job|jobs|worker|workers|queue|queues|controller|controllers|action|actions|usecase|usecases|use-case|command|commands|consumer|consumers|producer|producers|resolver|resolvers|middleware|policy|policies|guard|guards|processor|processors|notification|notifications|repository|repositories|store|stores|hook|hooks|validator|validators|composable|composables)\b/.test(normalizedPath);
|
|
502
|
+
}
|
|
503
|
+
function hasRuntimeCodeSignal(normalizedSnippet) {
|
|
504
|
+
const normalizedCode = normalizedSnippet.replace(/[^a-z0-9_\s=]+/g, " ");
|
|
505
|
+
return /\b(class|function|def|async function|export async|export function|public|private|protected|const [a-z0-9_]+\s*=\s*async|dispatch|emit|publish|subscribe|handle|execute|process|run|send|create|update|delete|validate|verify|approve|reject)\b/.test(normalizedCode);
|
|
506
|
+
}
|
|
507
|
+
function hasStrongRuntimeSignal(normalizedSnippet) {
|
|
508
|
+
const normalizedCode = normalizedSnippet.replace(/[^a-z0-9_\s=]+/g, " ");
|
|
509
|
+
return /\b(class\s+\w+|function\s+\w+|def\s+\w+|async function\s+\w+|export async function\s+\w+|export function\s+\w+|public\s+(async\s+)?\w+\s*\(|protected\s+(async\s+)?\w+\s*\(|private\s+(async\s+)?\w+\s*\(|dispatch\s*\(|emit\s*\(|publish\s*\(|subscribe\s*\(|handle\s*\(|execute\s*\(|process\s*\(|run\s*\(|const\s+\w+\s*=\s*async\s*\()\b/.test(normalizedCode);
|
|
510
|
+
}
|
|
511
|
+
function isInfrastructurePath(normalizedPath) {
|
|
512
|
+
return (/\b(extension|plugin|manifest|package)\.(ts|js|py|rb|php)$/.test(normalizedPath) ||
|
|
513
|
+
/\b(register|registration|bootstrap|setup|init|activate|deactivate)\b/.test(normalizedPath) ||
|
|
514
|
+
/\b(configuration|settings?|preferences?)\b/.test(normalizedPath) && !/\b(service|handler|controller|usecase|command)\b/.test(normalizedPath));
|
|
515
|
+
}
|
|
516
|
+
function hasActionSignal(normalizedSnippet, profile) {
|
|
517
|
+
if (profile.actions.length === 0) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
return profile.actions.some((action) => normalizedSnippet.includes((0, text_1.normalizeText)(action)));
|
|
521
|
+
}
|
|
522
|
+
function countTaskTermHits(text, terms) {
|
|
523
|
+
return terms.filter((term) => text.includes((0, text_1.normalizeText)(term))).length;
|
|
524
|
+
}
|
|
525
|
+
function hasTaskTermSignal(profile, normalizedPath, normalizedSnippet) {
|
|
526
|
+
const terms = profile.concepts.length > 0 ? profile.concepts : profile.keywords;
|
|
527
|
+
return countTaskTermHits(normalizedPath, terms) > 0 || countTaskTermHits(normalizedSnippet, terms) > 0;
|
|
528
|
+
}
|
|
529
|
+
function taskTargetsUi(profile) {
|
|
530
|
+
return hasAnyConcept(profile, ["ui", "frontend", "client", "browser", "page", "screen", "component", "view", "form", "button", "modal", "table", "layout", "responsive", "grid", "drawer", "sidebar", "toast", "chart", "gallery", "avatar", "badge", "bar", "input", "suggestion", "suggestions", "autocomplete", "dropdown", "image", "photo", "zoom", "giao", "dien", "hien", "thi", "nut", "anh", "display", "displayed", "render", "rendered", "show", "visible", "hide"]);
|
|
531
|
+
}
|
|
532
|
+
function taskTargetsAdmin(profile) {
|
|
533
|
+
return hasAnyConcept(profile, ["admin", "dashboard", "backoffice", "console"]);
|
|
534
|
+
}
|
|
535
|
+
function taskTargetsCopyOrI18n(profile) {
|
|
536
|
+
return hasAnyConcept(profile, ["copy", "text", "label", "message", "translation", "i18n", "locale", "wording", "content"]);
|
|
537
|
+
}
|
|
538
|
+
function isPrimaryFlowPath(normalizedPath, normalizedSnippet, profile) {
|
|
539
|
+
return hasTaskTermSignal(profile, normalizedPath, normalizedSnippet) && (isRuntimePath(normalizedPath) || hasRuntimeCodeSignal(normalizedSnippet)) && !isI18nPath(normalizedPath);
|
|
540
|
+
}
|
|
541
|
+
function isPrimaryUiFlowPath(normalizedPath, normalizedSnippet, profile) {
|
|
542
|
+
if (!taskTargetsUi(profile) || !isUiSurfacePath(normalizedPath)) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
return countTaskTermHits(normalizedPath, focusedPathTerms(profile)) > 0 || hasTaskTermSignal(profile, normalizedPath, normalizedSnippet);
|
|
546
|
+
}
|
|
547
|
+
function hasAnyConcept(profile, values) {
|
|
548
|
+
const terms = new Set(profile.keywords.map(text_1.normalizeText));
|
|
549
|
+
return values.some((value) => terms.has((0, text_1.normalizeText)(value)));
|
|
550
|
+
}
|
|
551
|
+
function taskTargetsBackend(profile) {
|
|
552
|
+
return hasAnyConcept(profile, ["api", "endpoint", "route", "router", "controller", "handler", "server", "backend", "job", "worker", "queue", "webhook", "event", "listener"]);
|
|
553
|
+
}
|
|
554
|
+
function taskTargetsData(profile) {
|
|
555
|
+
return hasAnyConcept(profile, ["schema", "migration", "database", "table", "db", "model", "query", "queries", "join", "repository", "prisma", "orm"]);
|
|
556
|
+
}
|
|
557
|
+
function taskTargetsValidation(profile) {
|
|
558
|
+
return hasAnyConcept(profile, ["validate", "validation", "validator", "validators", "request", "rule", "rules", "input", "form"]);
|
|
559
|
+
}
|
|
560
|
+
function taskTargetsSecurity(profile) {
|
|
561
|
+
return profile.intent === "security" || hasAnyConcept(profile, ["permission", "policy", "authorize", "auth", "guard", "middleware", "acl", "role"]);
|
|
562
|
+
}
|
|
563
|
+
function taskTargetsConfig(profile) {
|
|
564
|
+
return profile.blueprint.requiredSlots.includes("config") || hasAnyConcept(profile, ["config", "env", "environment", "setting", "settings", "property", "properties", "feature", "flag"]);
|
|
565
|
+
}
|
|
566
|
+
function taskTargetsUrlOrRoute(profile) {
|
|
567
|
+
if (hasAnyConcept(profile, ["route", "path", "href", "link", "slug", "param", "params", "lookup", "id"])) {
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
return hasAnyConcept(profile, ["url"]) && !taskTargetsConfig(profile);
|
|
571
|
+
}
|
|
572
|
+
function taskTargetsStateOrStatus(profile) {
|
|
573
|
+
return hasAnyConcept(profile, ["state", "status", "transition", "changes", "changed", "change", "shipped", "completed", "pending", "approved"]);
|
|
574
|
+
}
|
|
575
|
+
function taskTargetsSettings(profile) {
|
|
576
|
+
return hasAnyConcept(profile, ["settings", "setting", "preferences", "profile", "organization", "org"]);
|
|
577
|
+
}
|
|
578
|
+
function taskTargetsUtility(profile) {
|
|
579
|
+
return hasAnyConcept(profile, ["format", "formatter", "utility", "utils", "helper", "helpers", "api", "client"]);
|
|
580
|
+
}
|
|
581
|
+
function taskTargetsMaintenanceCommand(profile) {
|
|
582
|
+
return hasAnyConcept(profile, ["command", "cli", "console", "cron", "schedule", "scheduler", "maintenance", "batch", "digest", "cleanup", "job", "worker", "queue"]);
|
|
583
|
+
}
|
|
584
|
+
function isReadOnlyInvestigationTask(profile) {
|
|
585
|
+
if (profile.intent !== "investigation") {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
return !profile.actions.some((action) => ["fix", "sua", "update", "change", "doi", "add", "them", "create", "tao", "remove", "delete", "xoa", "refactor", "rename"].includes(action));
|
|
589
|
+
}
|
|
590
|
+
const genericPathTerms = new Set([
|
|
591
|
+
"add",
|
|
592
|
+
"create",
|
|
593
|
+
"new",
|
|
594
|
+
"update",
|
|
595
|
+
"change",
|
|
596
|
+
"fix",
|
|
597
|
+
"remove",
|
|
598
|
+
"delete",
|
|
599
|
+
"refactor",
|
|
600
|
+
"implement",
|
|
601
|
+
"should",
|
|
602
|
+
"server",
|
|
603
|
+
"side",
|
|
604
|
+
"client",
|
|
605
|
+
"api",
|
|
606
|
+
"page",
|
|
607
|
+
"route",
|
|
608
|
+
"routes",
|
|
609
|
+
"screen",
|
|
610
|
+
"component",
|
|
611
|
+
"valid",
|
|
612
|
+
"code",
|
|
613
|
+
"data",
|
|
614
|
+
"logic",
|
|
615
|
+
"flow",
|
|
616
|
+
"use",
|
|
617
|
+
"using",
|
|
618
|
+
"include",
|
|
619
|
+
"includes",
|
|
620
|
+
"show",
|
|
621
|
+
"hide",
|
|
622
|
+
"display",
|
|
623
|
+
"render"
|
|
624
|
+
]);
|
|
625
|
+
function focusedPathTerms(profile) {
|
|
626
|
+
const base = profile.concepts.length > 0 ? profile.concepts : profile.keywords;
|
|
627
|
+
return base.map(text_1.normalizeText).filter((term) => term.length > 2 && !genericPathTerms.has(term));
|
|
628
|
+
}
|
|
629
|
+
function focusedKeywordPathTerms(profile) {
|
|
630
|
+
return profile.keywords.map(text_1.normalizeText).filter((term) => term.length > 2 && !genericPathTerms.has(term));
|
|
631
|
+
}
|
|
632
|
+
function primaryFocusedPathTerms(profile) {
|
|
633
|
+
return focusedPathTerms(profile).slice(0, 6);
|
|
634
|
+
}
|
|
635
|
+
const lowSignalEntityTerms = new Set(["user", "account", "member", "admin", "file", "document", "submission", "attachment"]);
|
|
636
|
+
function focusedEntityPathTerms(profile) {
|
|
637
|
+
return profile.entities.map(text_1.normalizeText).filter((term) => term.length > 2 && !lowSignalEntityTerms.has(term));
|
|
638
|
+
}
|
|
639
|
+
function isFrameworkEntryPath(normalizedPath) {
|
|
640
|
+
return /(^|[/\\])(routes?|router)([/\\]|$)|(^|[/\\])urls\.py$|(^|[/\\])web\.php$|(^|[/\\])api\.php$/.test(normalizedPath);
|
|
641
|
+
}
|
|
642
|
+
function isFrontendRoutePath(normalizedPath) {
|
|
643
|
+
return /(^|[/\\])routes?([/\\]|$).*(^|[/\\])\+(page|layout|server)\.(ts|js|svelte)$|(^|[/\\])(app|pages)([/\\]|$).*\b(page|layout|route)\.(ts|tsx|js|jsx|svelte)$/.test(normalizedPath);
|
|
644
|
+
}
|
|
645
|
+
function isFrontendRouteScriptPath(normalizedPath) {
|
|
646
|
+
return /(^|[/\\])routes?([/\\]|$).*(^|[/\\])\+(page|layout|server)\.(ts|js)$|(^|[/\\])(app|pages)([/\\]|$).*\b(page|layout|route)\.(ts|tsx|js|jsx)$/.test(normalizedPath);
|
|
647
|
+
}
|
|
648
|
+
function isComponentPath(normalizedPath) {
|
|
649
|
+
return /(^|[/\\])components?([/\\]|$)|\.(svelte|vue|tsx|jsx)$/.test(normalizedPath);
|
|
650
|
+
}
|
|
651
|
+
function isFrontendStatePath(normalizedPath) {
|
|
652
|
+
return /(^|[/\\])(store|stores|hooks?|composables?)([/\\]|$)|(^|[/\\])hooks?\.(client|server)?\.(ts|js)$/.test(normalizedPath);
|
|
653
|
+
}
|
|
654
|
+
function isValidationPath(normalizedPath) {
|
|
655
|
+
return /\b(validators?|validation|rules?|request|dto|schema)\b/.test(normalizedPath);
|
|
656
|
+
}
|
|
657
|
+
function hasFormOrDisplaySignal(normalizedSnippet) {
|
|
658
|
+
return /\b(form|input|field|label|onchange|value|error|dialog|modal|display|render|show|visible|address|href|link|params?)\b/.test(normalizedSnippet);
|
|
659
|
+
}
|
|
660
|
+
function matchesRequestedUiPrimitive(profile, normalizedPath) {
|
|
661
|
+
return (hasAnyConcept(profile, ["input", "field"]) && /(^|[/\\])input\.(tsx|jsx|ts|js|vue|svelte)$/.test(normalizedPath)) || (hasAnyConcept(profile, ["modal", "dialog", "confirmation", "confirm"]) && /(^|[/\\])(modal|dialog)\.(tsx|jsx|ts|js|vue|svelte)$/.test(normalizedPath)) || (hasAnyConcept(profile, ["form"]) && /(^|[/\\])form\.(tsx|jsx|ts|js|vue|svelte)$/.test(normalizedPath));
|
|
662
|
+
}
|
|
663
|
+
function isConfigPath(normalizedPath) {
|
|
664
|
+
return /\b(config|configs|settings?|environment|environments|properties)\b/.test(normalizedPath) || /\.(env|ini|toml|ya?ml|xml|json|properties)$/.test(normalizedPath);
|
|
665
|
+
}
|
|
666
|
+
function isPermissionPath(normalizedPath) {
|
|
667
|
+
return /\b(policies?|permissions?|roles?|guards?|middleware|auth|acl|authorize)\b/.test(normalizedPath);
|
|
668
|
+
}
|
|
669
|
+
function isBackendOnlyPath(normalizedPath) {
|
|
670
|
+
return /(^|[/\\])apps[/\\](api|server|backend|worker)([/\\]|$)|(^|[/\\])(server|backend|api|controllers?|handlers?|jobs?|workers?|queues?|middleware|policies|mail|notifications?)([/\\]|$)/.test(normalizedPath);
|
|
671
|
+
}
|
|
672
|
+
function isGenericDataPath(normalizedPath) {
|
|
673
|
+
return /(^|[/\\])(db|database|schema|models?|repositories?)(\.|[/\\]|$)|(^|[/\\])(db|database)\.(ts|js|py|rb|php|go|rs|cs)$/.test(normalizedPath);
|
|
674
|
+
}
|
|
675
|
+
function isGenericUtilityPath(normalizedPath) {
|
|
676
|
+
return (/(^|[/\\])helpers?([/\\]|$)/.test(normalizedPath) ||
|
|
677
|
+
/(^|[/\\])(helpers?|utils?)\.(ts|js|tsx|jsx|py|rb|php|go|rs|cs)$/.test(normalizedPath) ||
|
|
678
|
+
/(^|[/\\])(utils?|helpers?|lib)([/\\]|$).*(^|[/\\])(format|formats|formatter|api|client|http|request|requests|common|shared)\.(ts|js|tsx|jsx|py|rb|php|go|rs|cs)$/.test(normalizedPath));
|
|
679
|
+
}
|
|
680
|
+
function isMaintenanceCommandPath(normalizedPath) {
|
|
681
|
+
return /(^|[/\\])(management[/\\]commands|console[/\\]commands|commands?|cli|scripts?|tasks?)([/\\]|$)/.test(normalizedPath);
|
|
682
|
+
}
|
|
683
|
+
function shouldEditDataOrConfig(kind, profile) {
|
|
684
|
+
if (kind === "migration" || kind === "schema") {
|
|
685
|
+
return profile.blueprint.requiredSlots.includes("data") || profile.intent === "migration" || hasAnyConcept(profile, ["schema", "migration", "database", "table", "db"]);
|
|
686
|
+
}
|
|
687
|
+
if (kind === "config") {
|
|
688
|
+
return hasAnyConcept(profile, ["config", "env", "environment", "setting", "settings", "property", "properties", "feature", "flag"]) || taskChangesLiteralValue(profile);
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
function taskChangesLiteralValue(profile) {
|
|
693
|
+
if (!profile.actions.some((action) => ["change", "update", "doi", "sua", "fix"].includes(action))) {
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
return profile.concepts.some((term) => term.includes("@") || term.includes("://"));
|
|
697
|
+
}
|
|
698
|
+
function toEvidenceUnit(file, relativePath, kind, role, range, score, matchedTerms, retrievalPasses, imports, reasons, snippet, metadata) {
|
|
699
|
+
const confidence = (0, text_1.clamp)(score / 24, 0.1, 0.98);
|
|
700
|
+
const id = `${relativePath}:${range?.startLine ?? 1}:${range?.endLine ?? 1}:${kind}`;
|
|
701
|
+
const slot = (0, contextBlueprint_1.detectContextSlot)(relativePath, kind, role, snippet);
|
|
702
|
+
return {
|
|
703
|
+
id,
|
|
704
|
+
kind,
|
|
705
|
+
role,
|
|
706
|
+
file,
|
|
707
|
+
relativePath,
|
|
708
|
+
range,
|
|
709
|
+
language: (0, text_1.languageFromPath)(relativePath),
|
|
710
|
+
slot,
|
|
711
|
+
score,
|
|
712
|
+
confidence,
|
|
713
|
+
tier: confidence >= 0.75 ? "high" : confidence >= 0.45 ? "medium" : "low",
|
|
714
|
+
reasons,
|
|
715
|
+
snippet,
|
|
716
|
+
matchedTerms,
|
|
717
|
+
retrievalPasses,
|
|
718
|
+
imports,
|
|
719
|
+
...metadata
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function buildStructuredEvidence(input, nodes, weightedTerms, imports, pathScore, fileMetadata, language) {
|
|
723
|
+
const units = [];
|
|
724
|
+
const relevantNodes = nodes.filter((node) => {
|
|
725
|
+
if (node.kind === "string_literal" || node.kind === "comment") {
|
|
726
|
+
const normalizedText = (0, text_1.normalizeText)(node.text);
|
|
727
|
+
return weightedTerms.some((term) => normalizedText.includes(term.term));
|
|
728
|
+
}
|
|
729
|
+
if (node.kind === "declaration" || node.kind === "call") {
|
|
730
|
+
const normalizedName = node.name ? (0, text_1.normalizeText)(node.name) : "";
|
|
731
|
+
return normalizedName.length > 0 && weightedTerms.some((term) => normalizedName.includes(term.term));
|
|
732
|
+
}
|
|
733
|
+
return false;
|
|
734
|
+
});
|
|
735
|
+
const fileKind = detectKind(input.relativePath, input.content.slice(0, 500));
|
|
736
|
+
const maxCallsitesPerFile = 4;
|
|
737
|
+
let callsiteCount = 0;
|
|
738
|
+
for (const node of relevantNodes.slice(0, 12)) {
|
|
739
|
+
const nodeKind = fileKind !== "code_region" ? fileKind : structuredKindToEvidenceKind(node.kind);
|
|
740
|
+
if (nodeKind === "callsite") {
|
|
741
|
+
callsiteCount += 1;
|
|
742
|
+
if (callsiteCount > maxCallsitesPerFile) {
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
const snippet = getNodeSnippet(input.content, node, 3, language);
|
|
747
|
+
const evidenceText = `${input.relativePath}\n${snippet}`;
|
|
748
|
+
const matchedTerms = collectMatchedTerms(evidenceText, weightedTerms);
|
|
749
|
+
const retrievalPasses = collectRetrievalPasses(evidenceText, input.profile, input.relativePath);
|
|
750
|
+
const nodeScore = pathScore + scoreSnippet(snippet, matchedTerms) + kindBonus(input.relativePath, snippet) + pathIntentModifier(input.relativePath, snippet, input.profile) + (node.kind === "declaration" ? 8 : 4);
|
|
751
|
+
const role = detectRole(nodeKind, nodeScore, input.profile, input.relativePath, snippet);
|
|
752
|
+
units.push(toEvidenceUnit(input.file, input.relativePath, nodeKind, role, node.range, nodeScore, matchedTerms, retrievalPasses, imports, reasonsFor(input.relativePath, nodeKind, matchedTerms, retrievalPasses, imports, pathScore, snippet), snippet, {
|
|
753
|
+
...fileMetadata,
|
|
754
|
+
symbolMatches: collectSymbolMatches([node.name ?? "", ...(fileMetadata.symbols ?? [])], weightedTerms)
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
return units;
|
|
758
|
+
}
|
|
759
|
+
function structuredKindToEvidenceKind(kind) {
|
|
760
|
+
switch (kind) {
|
|
761
|
+
case "declaration":
|
|
762
|
+
return "symbol";
|
|
763
|
+
case "call":
|
|
764
|
+
return "callsite";
|
|
765
|
+
case "string_literal":
|
|
766
|
+
case "comment":
|
|
767
|
+
return "code_region";
|
|
768
|
+
case "import":
|
|
769
|
+
return "code_region";
|
|
770
|
+
case "annotation":
|
|
771
|
+
return "code_region";
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function getNodeSnippet(content, node, contextLines, language) {
|
|
775
|
+
const lines = content.split(/\r?\n/);
|
|
776
|
+
const scopedRange = node.kind === "declaration" ? inferScopeRange(lines, node.range.startLine, language) : node.range;
|
|
777
|
+
const start = Math.max(0, scopedRange.startLine - 1 - contextLines);
|
|
778
|
+
const end = Math.min(lines.length, scopedRange.endLine + contextLines);
|
|
779
|
+
return lines.slice(start, end).join("\n");
|
|
780
|
+
}
|
|
781
|
+
function buildEvidenceMetadata(relativePath, nodes, weightedTerms) {
|
|
782
|
+
const symbols = nodes
|
|
783
|
+
.filter((node) => node.kind === "declaration" && node.name)
|
|
784
|
+
.map((node) => node.name ?? "")
|
|
785
|
+
.slice(0, 40);
|
|
786
|
+
const subsystemTerms = (0, subsystem_1.inferSubsystemTerms)(relativePath, symbols);
|
|
787
|
+
return {
|
|
788
|
+
symbols,
|
|
789
|
+
symbolMatches: collectSymbolMatches(symbols, weightedTerms),
|
|
790
|
+
subsystem: subsystemTerms[0],
|
|
791
|
+
subsystemTerms
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function collectSymbolMatches(symbols, weightedTerms) {
|
|
795
|
+
const normalizedTerms = weightedTerms.map((term) => (0, text_1.normalizeText)(term.term));
|
|
796
|
+
return Array.from(new Set(symbols
|
|
797
|
+
.map(text_1.normalizeText)
|
|
798
|
+
.filter((symbol) => symbol.length > 0 && normalizedTerms.some((term) => symbol.includes(term) || term.includes(symbol))))).slice(0, 8);
|
|
799
|
+
}
|
|
800
|
+
function inferScopeRange(lines, startLine, language) {
|
|
801
|
+
if (language === "python" || language === "ruby") {
|
|
802
|
+
return inferIndentScopeRange(lines, startLine);
|
|
803
|
+
}
|
|
804
|
+
return inferBraceScopeRange(lines, startLine);
|
|
805
|
+
}
|
|
806
|
+
function inferIndentScopeRange(lines, startLine) {
|
|
807
|
+
const startIndex = Math.max(0, startLine - 1);
|
|
808
|
+
const startIndent = leadingWhitespace(lines[startIndex] ?? "").length;
|
|
809
|
+
let endLine = startLine;
|
|
810
|
+
for (let index = startIndex + 1; index < lines.length; index += 1) {
|
|
811
|
+
const line = lines[index];
|
|
812
|
+
if (line.trim().length === 0) {
|
|
813
|
+
endLine = index + 1;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
const indent = leadingWhitespace(line).length;
|
|
817
|
+
if (indent <= startIndent) {
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
endLine = index + 1;
|
|
821
|
+
if (endLine - startLine >= MAX_CHUNK_LINES) {
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return { startLine, endLine };
|
|
826
|
+
}
|
|
827
|
+
function inferBraceScopeRange(lines, startLine) {
|
|
828
|
+
let depth = 0;
|
|
829
|
+
let seenOpenBrace = false;
|
|
830
|
+
let endLine = startLine;
|
|
831
|
+
for (let index = Math.max(0, startLine - 1); index < lines.length; index += 1) {
|
|
832
|
+
const line = lines[index];
|
|
833
|
+
for (const char of line) {
|
|
834
|
+
if (char === "{") {
|
|
835
|
+
depth += 1;
|
|
836
|
+
seenOpenBrace = true;
|
|
837
|
+
}
|
|
838
|
+
else if (char === "}") {
|
|
839
|
+
depth = Math.max(0, depth - 1);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
endLine = index + 1;
|
|
843
|
+
if (seenOpenBrace && depth === 0) {
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
if (endLine - startLine >= MAX_CHUNK_LINES) {
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return { startLine, endLine };
|
|
851
|
+
}
|
|
852
|
+
function leadingWhitespace(value) {
|
|
853
|
+
return value.match(/^\s*/)?.[0] ?? "";
|
|
854
|
+
}
|
|
855
|
+
function dedupeUnitsPerFile(units, maxPerFile) {
|
|
856
|
+
const counts = new Map();
|
|
857
|
+
return units.filter((unit) => {
|
|
858
|
+
const count = counts.get(unit.relativePath) ?? 0;
|
|
859
|
+
if (count >= maxPerFile) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
counts.set(unit.relativePath, count + 1);
|
|
863
|
+
return true;
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
//# sourceMappingURL=fileScanner.js.map
|