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,346 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildTaskBlueprint = buildTaskBlueprint;
|
|
4
|
+
exports.slotSearchTerms = slotSearchTerms;
|
|
5
|
+
exports.allContextSlots = allContextSlots;
|
|
6
|
+
exports.contextSlotLabel = contextSlotLabel;
|
|
7
|
+
exports.detectContextSlot = detectContextSlot;
|
|
8
|
+
exports.isRequiredSlot = isRequiredSlot;
|
|
9
|
+
exports.computeContextCoverage = computeContextCoverage;
|
|
10
|
+
exports.sortSlots = sortSlots;
|
|
11
|
+
const text_1 = require("../utils/text");
|
|
12
|
+
const slotOrder = ["entry", "handler", "domain", "data", "validation", "permission", "config", "side_effect", "ui", "tests", "docs", "unknown"];
|
|
13
|
+
const slotTerms = {
|
|
14
|
+
entry: ["route", "routes", "router", "endpoint", "api", "page", "screen", "loader", "action"],
|
|
15
|
+
handler: ["controller", "handler", "action", "resolver", "listener", "job", "worker", "consumer", "command", "commands"],
|
|
16
|
+
domain: ["service", "usecase", "use_case", "repository", "manager", "processor", "model", "entity", "store", "stores", "hook", "hooks"],
|
|
17
|
+
data: ["model", "models", "schema", "migration", "database", "table", "query", "entity", "orm", "prisma"],
|
|
18
|
+
validation: ["request", "validator", "validation", "rule", "rules", "dto", "formrequest", "schema"],
|
|
19
|
+
permission: ["policy", "permission", "role", "guard", "middleware", "authorize", "auth", "acl"],
|
|
20
|
+
config: ["config", "env", "setting", "settings", "feature", "flag", "yaml", "json"],
|
|
21
|
+
side_effect: ["event", "listener", "job", "queue", "mail", "email", "notification", "webhook", "cache", "dispatch"],
|
|
22
|
+
ui: ["component", "page", "view", "screen", "template", "form", "button", "modal", "layout", "responsive", "grid", "drawer", "sidebar", "toast", "chart"],
|
|
23
|
+
tests: ["test", "tests", "spec", "expect", "assert", "fixture", "fixtures"],
|
|
24
|
+
docs: ["readme", "docs", "documentation", "markdown", "guide"],
|
|
25
|
+
unknown: []
|
|
26
|
+
};
|
|
27
|
+
const taskBlueprints = {
|
|
28
|
+
bugfix: {
|
|
29
|
+
requiredSlots: ["entry", "handler"],
|
|
30
|
+
optionalSlots: ["domain", "data", "validation", "permission", "config", "side_effect", "ui", "tests"]
|
|
31
|
+
},
|
|
32
|
+
feature: {
|
|
33
|
+
requiredSlots: ["entry", "handler"],
|
|
34
|
+
optionalSlots: ["domain", "data", "validation", "permission", "config", "side_effect", "ui", "tests"]
|
|
35
|
+
},
|
|
36
|
+
refactor: {
|
|
37
|
+
requiredSlots: ["handler"],
|
|
38
|
+
optionalSlots: ["entry", "domain", "data", "config", "ui", "side_effect", "tests"]
|
|
39
|
+
},
|
|
40
|
+
investigation: {
|
|
41
|
+
requiredSlots: ["entry", "handler"],
|
|
42
|
+
optionalSlots: ["domain", "data", "validation", "permission", "config", "side_effect", "ui", "tests", "docs"]
|
|
43
|
+
},
|
|
44
|
+
migration: {
|
|
45
|
+
requiredSlots: ["data", "config"],
|
|
46
|
+
optionalSlots: ["entry", "handler", "domain", "validation", "tests"]
|
|
47
|
+
},
|
|
48
|
+
performance: {
|
|
49
|
+
requiredSlots: ["entry", "handler"],
|
|
50
|
+
optionalSlots: ["domain", "data", "config", "side_effect", "ui", "tests"]
|
|
51
|
+
},
|
|
52
|
+
security: {
|
|
53
|
+
requiredSlots: ["entry", "handler", "permission", "validation"],
|
|
54
|
+
optionalSlots: ["domain", "data", "config", "side_effect", "ui", "tests"]
|
|
55
|
+
},
|
|
56
|
+
unknown: {
|
|
57
|
+
requiredSlots: ["entry", "handler"],
|
|
58
|
+
optionalSlots: ["domain", "data", "validation", "permission", "config", "side_effect", "ui", "tests", "docs"]
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function buildTaskBlueprint(input) {
|
|
62
|
+
const baseShape = input.intent === "unknown" && isReviewLike(input.normalizedTask) ? "investigation" : input.intent;
|
|
63
|
+
const template = taskBlueprints[baseShape];
|
|
64
|
+
const required = new Set(template.requiredSlots);
|
|
65
|
+
const optional = new Set(template.optionalSlots);
|
|
66
|
+
const terms = new Set(input.keywords.map(text_1.normalizeText));
|
|
67
|
+
const normalized = input.normalizedTask;
|
|
68
|
+
promoteSlots(required, optional, detectTargetedSlots(normalized, terms));
|
|
69
|
+
adaptSlotsToTaskSurface(required, optional, normalized, terms);
|
|
70
|
+
return {
|
|
71
|
+
shape: baseShape,
|
|
72
|
+
confidence: input.confidence,
|
|
73
|
+
primarySurface: detectPrimarySurface(normalized, terms),
|
|
74
|
+
negativeTerms: input.negativeTerms ?? [],
|
|
75
|
+
requiredSlots: sortSlots(Array.from(required)),
|
|
76
|
+
optionalSlots: sortSlots(Array.from(optional).filter((slot) => !required.has(slot))),
|
|
77
|
+
expansionHints: buildExpansionHints(required)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function slotSearchTerms(slot) {
|
|
81
|
+
return slotTerms[slot] ?? [];
|
|
82
|
+
}
|
|
83
|
+
function allContextSlots(blueprint) {
|
|
84
|
+
return sortSlots([...blueprint.requiredSlots, ...blueprint.optionalSlots]);
|
|
85
|
+
}
|
|
86
|
+
function contextSlotLabel(slot) {
|
|
87
|
+
const labels = {
|
|
88
|
+
entry: "Entry / Routes",
|
|
89
|
+
handler: "Handlers / Controllers",
|
|
90
|
+
domain: "Domain / Services",
|
|
91
|
+
data: "Data / Schema",
|
|
92
|
+
validation: "Validation",
|
|
93
|
+
permission: "Permissions",
|
|
94
|
+
config: "Config",
|
|
95
|
+
side_effect: "Side Effects",
|
|
96
|
+
ui: "UI / Templates",
|
|
97
|
+
tests: "Tests / Verification",
|
|
98
|
+
docs: "Docs",
|
|
99
|
+
unknown: "Other Context"
|
|
100
|
+
};
|
|
101
|
+
return labels[slot];
|
|
102
|
+
}
|
|
103
|
+
function detectContextSlot(relativePath, kind, role, snippet = "") {
|
|
104
|
+
const normalizedPath = (0, text_1.normalizeText)(relativePath);
|
|
105
|
+
const normalizedText = (0, text_1.normalizeText)(`${relativePath}\n${snippet}`);
|
|
106
|
+
if (kind === "test" || isTestPath(normalizedPath)) {
|
|
107
|
+
return "tests";
|
|
108
|
+
}
|
|
109
|
+
if (kind === "doc") {
|
|
110
|
+
return "docs";
|
|
111
|
+
}
|
|
112
|
+
if (kind === "route" || isFrontendRoutePath(normalizedPath) || /\b(route|routes|router|endpoint)\b/.test(normalizedPath)) {
|
|
113
|
+
return "entry";
|
|
114
|
+
}
|
|
115
|
+
if (kind === "template" || isFrontendTemplatePath(normalizedPath) || /\b(component|components|page|pages|screen|screens|template|templates|form|forms)\b/.test(normalizedPath) || /(^|[/\\])templates?([/\\]|$)/.test(normalizedPath)) {
|
|
116
|
+
return "ui";
|
|
117
|
+
}
|
|
118
|
+
if (/\b(request|requests|validator|validators|validation|rule|rules|dto|formrequest|form-request|serializer|serializers)\b/.test(normalizedPath)) {
|
|
119
|
+
return "validation";
|
|
120
|
+
}
|
|
121
|
+
if (kind === "config" || /\b(config|env|properties?|feature[_-]?flag)\b/.test(normalizedPath) || /(^|[/\\])settings?\.(json|ya?ml|toml|php|py|ts|js)$/.test(normalizedPath)) {
|
|
122
|
+
return "config";
|
|
123
|
+
}
|
|
124
|
+
if (kind === "schema" || kind === "migration" || /\b(schema|schemas|model|models|entity|entities|migration|migrations|database|table|query|repository|repositories|prisma|orm)\b/.test(normalizedPath)) {
|
|
125
|
+
return "data";
|
|
126
|
+
}
|
|
127
|
+
if (/\b(request|requests|validator|validators|validation|rule|rules|dto|formrequest|form-request)\b/.test(normalizedPath)) {
|
|
128
|
+
return "validation";
|
|
129
|
+
}
|
|
130
|
+
if (/\b(event|events|listener|listeners|job|jobs|worker|workers|queue|queues|mail|email|notification|notifications|webhook|cache|dispatch)\b/.test(normalizedPath)) {
|
|
131
|
+
return "side_effect";
|
|
132
|
+
}
|
|
133
|
+
if (/\b(policy|policies|permission|permissions|role|roles|guard|guards|middleware|auth|acl|authorize)\b/.test(normalizedPath)) {
|
|
134
|
+
return "permission";
|
|
135
|
+
}
|
|
136
|
+
if (/\b(controller|controllers|handler|handlers|action|actions|resolver|resolvers|consumer|consumers|producer|producers|command|commands)\b/.test(normalizedPath) || /(^|[/\\])views?\.[a-z0-9]+$/.test(normalizedPath)) {
|
|
137
|
+
return "handler";
|
|
138
|
+
}
|
|
139
|
+
if (/\b(service|services|usecase|usecases|use-case|domain|manager|processor|processors|helper|helpers|util|utils|lib|store|stores|hook|hooks|composable|composables)\b/.test(normalizedPath)) {
|
|
140
|
+
return "domain";
|
|
141
|
+
}
|
|
142
|
+
if (role === "test") {
|
|
143
|
+
return "tests";
|
|
144
|
+
}
|
|
145
|
+
if (/\b(validate|validator|validation|authorize|permission|policy|role|schema|migration|query|dispatch|emit|publish|send|notify|cache)\b/.test(normalizedText)) {
|
|
146
|
+
if (/\b(validate|validator|validation)\b/.test(normalizedText)) {
|
|
147
|
+
return "validation";
|
|
148
|
+
}
|
|
149
|
+
if (/\b(authorize|permission|policy|role)\b/.test(normalizedText)) {
|
|
150
|
+
return "permission";
|
|
151
|
+
}
|
|
152
|
+
if (/\b(schema|migration|query|table)\b/.test(normalizedText)) {
|
|
153
|
+
return "data";
|
|
154
|
+
}
|
|
155
|
+
return "side_effect";
|
|
156
|
+
}
|
|
157
|
+
return "unknown";
|
|
158
|
+
}
|
|
159
|
+
function isRequiredSlot(profile, slot) {
|
|
160
|
+
return Boolean(slot && profile.blueprint.requiredSlots.includes(slot));
|
|
161
|
+
}
|
|
162
|
+
function computeContextCoverage(profile, units) {
|
|
163
|
+
const found = new Set(units.map((unit) => unit.slot ?? "unknown"));
|
|
164
|
+
const foundRequiredSlots = profile.blueprint.requiredSlots.filter((slot) => found.has(slot));
|
|
165
|
+
const missingRequiredSlots = profile.blueprint.requiredSlots.filter((slot) => !found.has(slot));
|
|
166
|
+
const optionalSlotsFound = profile.blueprint.optionalSlots.filter((slot) => found.has(slot));
|
|
167
|
+
const requiredCoveragePercent = profile.blueprint.requiredSlots.length > 0
|
|
168
|
+
? (foundRequiredSlots.length / profile.blueprint.requiredSlots.length) * 100
|
|
169
|
+
: 100;
|
|
170
|
+
return {
|
|
171
|
+
requiredSlots: profile.blueprint.requiredSlots,
|
|
172
|
+
foundRequiredSlots,
|
|
173
|
+
missingRequiredSlots,
|
|
174
|
+
optionalSlotsFound,
|
|
175
|
+
requiredCoveragePercent
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function sortSlots(slots) {
|
|
179
|
+
const unique = Array.from(new Set(slots));
|
|
180
|
+
return unique.sort((left, right) => slotOrder.indexOf(left) - slotOrder.indexOf(right));
|
|
181
|
+
}
|
|
182
|
+
function detectTargetedSlots(normalizedTask, terms) {
|
|
183
|
+
const slots = [];
|
|
184
|
+
const hasExplicitSecuritySignal = hasAny(terms, ["auth", "authorize", "permission", "role", "policy", "login", "guard", "middleware", "acl"]) || /\b(bao mat|phan quyen|dang nhap)\b/.test(normalizedTask);
|
|
185
|
+
const hasSessionSecurityContext = hasAny(terms, ["session", "token", "jwt"]) && (hasExplicitSecuritySignal || /\b(security|login|auth|access|cannot|without|admin|role|bao mat|dang nhap)\b/.test(normalizedTask));
|
|
186
|
+
if (hasExplicitSecuritySignal || hasSessionSecurityContext) {
|
|
187
|
+
slots.push("permission", "validation");
|
|
188
|
+
}
|
|
189
|
+
if (hasAny(terms, ["schema", "migration", "database", "table", "db", "model", "query", "queries", "join", "repository", "data"])) {
|
|
190
|
+
slots.push("data");
|
|
191
|
+
}
|
|
192
|
+
if (hasAny(terms, ["config", "env", "setting", "settings", "feature", "flag"])) {
|
|
193
|
+
slots.push("config");
|
|
194
|
+
}
|
|
195
|
+
if (hasAny(terms, ["send", "mail", "queue", "job", "event", "webhook", "cache", "dispatch"])) {
|
|
196
|
+
slots.push("side_effect");
|
|
197
|
+
}
|
|
198
|
+
if (hasAny(terms, ["id", "user_id", "key", "identifier", "identified", "lookup", "email"]) && /\b(change|update|rename|from|to|doi|thay)\b/.test(normalizedTask)) {
|
|
199
|
+
slots.push("data", "domain");
|
|
200
|
+
}
|
|
201
|
+
if (hasAny(terms, ["ui", "frontend", "client", "browser", "page", "screen", "component", "view", "form", "template", "layout", "responsive", "grid", "button", "modal", "drawer", "sidebar", "toast", "chart", "gallery", "avatar", "badge", "bar", "input", "suggestion", "suggestions", "autocomplete", "dropdown", "image", "photo", "zoom", "display", "displayed", "render", "rendered", "show", "visible", "giao", "dien", "hien", "thi", "nut", "anh"]) || /\b(giao dien|trang(?!\s+thai)|man hinh|hien thi|nut)\b/.test(normalizedTask)) {
|
|
202
|
+
slots.push("ui", "entry");
|
|
203
|
+
}
|
|
204
|
+
if (hasAny(terms, ["store", "stores", "state", "localstorage", "sessionstorage", "hook", "hooks", "client", "browser"])) {
|
|
205
|
+
slots.push("domain");
|
|
206
|
+
}
|
|
207
|
+
if (hasAny(terms, ["validate", "validation", "request", "rule", "rules", "input", "invalid", "required", "field", "format", "empty", "constraint", "validator", "dto", "formrequest", "serializer", "serializers"]) || /\b(bat buoc|khong hop le|dinh dang|truong|rong)\b/.test(normalizedTask)) {
|
|
208
|
+
slots.push("validation");
|
|
209
|
+
}
|
|
210
|
+
if (hasAny(terms, ["test", "tests", "spec", "expect", "assert", "verify", "verification"])) {
|
|
211
|
+
slots.push("tests");
|
|
212
|
+
}
|
|
213
|
+
if (hasAny(terms, ["upload", "download", "export", "import", "file", "attachment", "document", "submission"])) {
|
|
214
|
+
slots.push("entry", "domain", "data", "validation");
|
|
215
|
+
}
|
|
216
|
+
return slots;
|
|
217
|
+
}
|
|
218
|
+
function adaptSlotsToTaskSurface(required, optional, normalizedTask, terms) {
|
|
219
|
+
const uiFocused = isUiFocusedTask(normalizedTask, terms);
|
|
220
|
+
const backendFocused = isBackendFocusedTask(normalizedTask, terms);
|
|
221
|
+
const dataFocused = hasAny(terms, ["schema", "migration", "database", "table", "db", "model", "query", "prisma", "orm"]);
|
|
222
|
+
if (uiFocused) {
|
|
223
|
+
required.add("entry");
|
|
224
|
+
required.add("ui");
|
|
225
|
+
optional.delete("entry");
|
|
226
|
+
optional.delete("ui");
|
|
227
|
+
if (!backendFocused) {
|
|
228
|
+
demoteSlot(required, optional, "handler");
|
|
229
|
+
}
|
|
230
|
+
if (!dataFocused) {
|
|
231
|
+
demoteSlot(required, optional, "data");
|
|
232
|
+
}
|
|
233
|
+
if (hasAny(terms, ["store", "stores", "state", "localstorage", "sessionstorage", "hook", "hooks", "client", "browser", "cart", "wishlist", "filter", "filters"])) {
|
|
234
|
+
required.add("domain");
|
|
235
|
+
optional.delete("domain");
|
|
236
|
+
}
|
|
237
|
+
if (hasAny(terms, ["api", "query", "load", "action", "fetch"])) {
|
|
238
|
+
required.add("domain");
|
|
239
|
+
optional.delete("domain");
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (!hasAny(terms, ["test", "tests", "spec", "expect", "assert", "verify", "verification"])) {
|
|
243
|
+
demoteSlot(required, optional, "tests");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function promoteSlots(required, optional, slots) {
|
|
247
|
+
for (const slot of slots) {
|
|
248
|
+
required.add(slot);
|
|
249
|
+
optional.delete(slot);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function demoteSlot(required, optional, slot) {
|
|
253
|
+
if (required.delete(slot)) {
|
|
254
|
+
optional.add(slot);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function buildExpansionHints(required) {
|
|
258
|
+
return sortSlots(Array.from(required)).map((slot) => `Find ${contextSlotLabel(slot)} context if available.`);
|
|
259
|
+
}
|
|
260
|
+
function hasAny(terms, values) {
|
|
261
|
+
return values.some((value) => terms.has((0, text_1.normalizeText)(value)));
|
|
262
|
+
}
|
|
263
|
+
function isUiFocusedTask(normalizedTask, terms) {
|
|
264
|
+
return hasAny(terms, [
|
|
265
|
+
"ui",
|
|
266
|
+
"frontend",
|
|
267
|
+
"client",
|
|
268
|
+
"browser",
|
|
269
|
+
"page",
|
|
270
|
+
"screen",
|
|
271
|
+
"component",
|
|
272
|
+
"view",
|
|
273
|
+
"form",
|
|
274
|
+
"layout",
|
|
275
|
+
"responsive",
|
|
276
|
+
"grid",
|
|
277
|
+
"button",
|
|
278
|
+
"modal",
|
|
279
|
+
"drawer",
|
|
280
|
+
"sidebar",
|
|
281
|
+
"toast",
|
|
282
|
+
"chart",
|
|
283
|
+
"gallery",
|
|
284
|
+
"avatar",
|
|
285
|
+
"badge",
|
|
286
|
+
"bar",
|
|
287
|
+
"input",
|
|
288
|
+
"suggestion",
|
|
289
|
+
"suggestions",
|
|
290
|
+
"autocomplete",
|
|
291
|
+
"dropdown",
|
|
292
|
+
"image",
|
|
293
|
+
"photo",
|
|
294
|
+
"zoom",
|
|
295
|
+
"giao",
|
|
296
|
+
"dien",
|
|
297
|
+
"hien",
|
|
298
|
+
"thi",
|
|
299
|
+
"nut",
|
|
300
|
+
"anh",
|
|
301
|
+
"display",
|
|
302
|
+
"render",
|
|
303
|
+
"show",
|
|
304
|
+
"hide"
|
|
305
|
+
]) || /\b(giao dien|trang(?!\s+thai)|man hinh|hien thi|nut|client side|front end)\b/.test(normalizedTask);
|
|
306
|
+
}
|
|
307
|
+
function isBackendFocusedTask(normalizedTask, terms) {
|
|
308
|
+
return hasAny(terms, [
|
|
309
|
+
"controller",
|
|
310
|
+
"handler",
|
|
311
|
+
"backend",
|
|
312
|
+
"job",
|
|
313
|
+
"worker",
|
|
314
|
+
"queue",
|
|
315
|
+
"webhook",
|
|
316
|
+
"event",
|
|
317
|
+
"listener"
|
|
318
|
+
]) || /\b(backend|controller|handler|job|worker|queue|webhook|middleware)\b/.test(normalizedTask);
|
|
319
|
+
}
|
|
320
|
+
function detectPrimarySurface(normalizedTask, terms) {
|
|
321
|
+
const frontend = isUiFocusedTask(normalizedTask, terms);
|
|
322
|
+
const backend = isBackendFocusedTask(normalizedTask, terms) || hasAny(terms, ["api", "endpoint", "server", "service", "database", "queue", "job", "worker", "webhook"]);
|
|
323
|
+
if (frontend && backend) {
|
|
324
|
+
return "fullstack";
|
|
325
|
+
}
|
|
326
|
+
if (frontend) {
|
|
327
|
+
return "frontend";
|
|
328
|
+
}
|
|
329
|
+
if (backend) {
|
|
330
|
+
return "backend";
|
|
331
|
+
}
|
|
332
|
+
return "unknown";
|
|
333
|
+
}
|
|
334
|
+
function isFrontendRoutePath(normalizedPath) {
|
|
335
|
+
return /(^|[/\\])routes?([/\\]|$).*(^|[/\\])\+(page|layout|server)\.(ts|js|svelte)$|(^|[/\\])(app|pages)([/\\]|$).*\b(page|layout|route)\.(ts|tsx|js|jsx|svelte)$/.test(normalizedPath);
|
|
336
|
+
}
|
|
337
|
+
function isFrontendTemplatePath(normalizedPath) {
|
|
338
|
+
return /\.(svelte|vue|tsx|jsx|erb|blade\.php|twig|hbs|ejs)$/.test(normalizedPath) || /(^|[/\\])(components?|views?|screens?|templates?)([/\\]|$)/.test(normalizedPath);
|
|
339
|
+
}
|
|
340
|
+
function isReviewLike(normalizedTask) {
|
|
341
|
+
return /\b(review|investigate|trace|debug|kiem tra|danh gia|ra soat|tim hieu)\b/.test(normalizedTask);
|
|
342
|
+
}
|
|
343
|
+
function isTestPath(normalizedPath) {
|
|
344
|
+
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);
|
|
345
|
+
}
|
|
346
|
+
//# sourceMappingURL=contextBlueprint.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createContextPack = createContextPack;
|
|
4
|
+
const text_1 = require("../utils/text");
|
|
5
|
+
const fileGroups_1 = require("./fileGroups");
|
|
6
|
+
const sections = [
|
|
7
|
+
{ title: "Most Likely Edit Areas", roles: ["edit_candidate"] },
|
|
8
|
+
{ title: "Read Before Editing", roles: ["read_context"] },
|
|
9
|
+
{ title: "Impact And Risk", roles: ["impact", "verify"] },
|
|
10
|
+
{ title: "Tests To Run Or Update", roles: ["test"] },
|
|
11
|
+
{ title: "Uncertain Candidates", roles: ["unknown"] }
|
|
12
|
+
];
|
|
13
|
+
function createContextPack(task, units, config) {
|
|
14
|
+
const header = [`# FlowSeeker Context`, "", `## Task`, task, ""].join("\n");
|
|
15
|
+
const output = [header];
|
|
16
|
+
let usedTokens = (0, text_1.tokenEstimate)(header);
|
|
17
|
+
const fileScope = renderFileScope(units);
|
|
18
|
+
output.push(fileScope);
|
|
19
|
+
usedTokens += (0, text_1.tokenEstimate)(fileScope);
|
|
20
|
+
const contextUnits = (0, fileGroups_1.selectDiverseEvidenceUnits)(units, 2);
|
|
21
|
+
for (const section of sections) {
|
|
22
|
+
const sectionUnits = contextUnits.filter((unit) => section.roles.includes(unit.role));
|
|
23
|
+
if (sectionUnits.length === 0) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const sectionLines = [`## ${section.title}`, ""];
|
|
27
|
+
for (const unit of sectionUnits) {
|
|
28
|
+
const block = renderUnit(unit);
|
|
29
|
+
const nextTokens = (0, text_1.tokenEstimate)(block);
|
|
30
|
+
if (usedTokens + nextTokens > config.pipeline.maxContextTokens) {
|
|
31
|
+
sectionLines.push(`- Context budget reached. ${sectionUnits.length} candidates were ranked, but lower-ranked snippets were omitted.`, "");
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
sectionLines.push(block);
|
|
35
|
+
usedTokens += nextTokens;
|
|
36
|
+
}
|
|
37
|
+
output.push(sectionLines.join("\n"));
|
|
38
|
+
}
|
|
39
|
+
output.push(`## Notes\n- AI rerank: disabled in MVP. Results are deterministic evidence ranking.\n- Confidence is heuristic and should be reviewed before editing.\n`);
|
|
40
|
+
return output.join("\n").trimEnd() + "\n";
|
|
41
|
+
}
|
|
42
|
+
function renderFileScope(units) {
|
|
43
|
+
const groups = (0, fileGroups_1.aggregateEvidenceFiles)(units).slice(0, 15);
|
|
44
|
+
if (groups.length === 0) {
|
|
45
|
+
return "## File Scope\n\n- No file-level evidence ranked.\n";
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
"## File Scope",
|
|
49
|
+
"",
|
|
50
|
+
...groups.map((group, index) => {
|
|
51
|
+
const ranges = group.ranges
|
|
52
|
+
.slice(0, 3)
|
|
53
|
+
.map((range) => `${range.startLine}-${range.endLine}`)
|
|
54
|
+
.join(", ");
|
|
55
|
+
return `${index + 1}. ${group.relativePath}${ranges ? `:${ranges}` : ""} [${group.role}] score=${group.score.toFixed(1)} evidence=${group.unitCount}`;
|
|
56
|
+
}),
|
|
57
|
+
""
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
|
60
|
+
function renderUnit(unit) {
|
|
61
|
+
const range = unit.range ? `:${unit.range.startLine}-${unit.range.endLine}` : "";
|
|
62
|
+
const reasons = unit.reasons.length > 0 ? unit.reasons.join("; ") : "ranked evidence";
|
|
63
|
+
const snippet = unit.snippet?.trim();
|
|
64
|
+
const language = unit.language ?? "text";
|
|
65
|
+
const lines = [
|
|
66
|
+
`- ${unit.relativePath}${range}`,
|
|
67
|
+
` Kind: ${unit.kind}; Confidence: ${unit.tier} (${unit.confidence.toFixed(2)}); Score: ${unit.score.toFixed(1)}`,
|
|
68
|
+
` Retrieval passes: ${unit.retrievalPasses.length > 0 ? unit.retrievalPasses.join(", ") : "seed"}`,
|
|
69
|
+
` Imports: ${unit.imports.length > 0 ? unit.imports.slice(0, 5).join(", ") : "none"}`,
|
|
70
|
+
` Reasons: ${reasons}`
|
|
71
|
+
];
|
|
72
|
+
if (snippet) {
|
|
73
|
+
lines.push("", `\`\`\`${language}`, snippet, "```", "");
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
lines.push("");
|
|
77
|
+
}
|
|
78
|
+
return lines.join("\n");
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=contextPack.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateDiff = generateDiff;
|
|
4
|
+
exports.renderDiffPreviewMarkdown = renderDiffPreviewMarkdown;
|
|
5
|
+
function generateDiff(originalContent, edits) {
|
|
6
|
+
const lines = originalContent.split(/\r?\n/);
|
|
7
|
+
const diffs = [];
|
|
8
|
+
for (const edit of edits) {
|
|
9
|
+
if (edit.replaceWholeFile) {
|
|
10
|
+
diffs.push(`\`\`\`diff\n--- a/${edit.file}\n+++ b/${edit.file}\n@@ -1,${lines.length} +1,${edit.text.split(/\r?\n/).length} @@\n${renderFullDiff(lines, edit.text)}\n\`\`\``);
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (!edit.range) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const startLine = edit.range.startLine - 1;
|
|
17
|
+
const endLine = edit.range.endLine - 1;
|
|
18
|
+
const contextBefore = Math.max(0, startLine - 3);
|
|
19
|
+
const contextAfter = Math.min(lines.length - 1, endLine + 3);
|
|
20
|
+
const oldLines = lines.slice(startLine, endLine + 1);
|
|
21
|
+
const newLines = edit.text.split(/\r?\n/);
|
|
22
|
+
const oldStart = startLine + 1;
|
|
23
|
+
const oldCount = oldLines.length;
|
|
24
|
+
const newCount = newLines.length;
|
|
25
|
+
const hunk = [
|
|
26
|
+
`\`\`\`diff`,
|
|
27
|
+
`--- a/${edit.file}`,
|
|
28
|
+
`+++ b/${edit.file}`,
|
|
29
|
+
`@@ -${oldStart},${oldCount} +${oldStart},${newCount} @@`,
|
|
30
|
+
...renderContextBefore(lines, contextBefore, startLine),
|
|
31
|
+
...oldLines.map((line) => `-${line}`),
|
|
32
|
+
...newLines.map((line) => `+${line}`),
|
|
33
|
+
...renderContextAfter(lines, endLine, contextAfter),
|
|
34
|
+
`\`\`\``
|
|
35
|
+
].join("\n");
|
|
36
|
+
diffs.push(hunk);
|
|
37
|
+
}
|
|
38
|
+
return diffs.join("\n\n");
|
|
39
|
+
}
|
|
40
|
+
function renderContextBefore(lines, contextBefore, startLine) {
|
|
41
|
+
const result = [];
|
|
42
|
+
for (let i = contextBefore; i < startLine; i++) {
|
|
43
|
+
result.push(` ${lines[i]}`);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
function renderContextAfter(lines, endLine, contextAfter) {
|
|
48
|
+
const result = [];
|
|
49
|
+
for (let i = endLine + 1; i <= contextAfter; i++) {
|
|
50
|
+
result.push(` ${lines[i]}`);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function renderFullDiff(originalLines, newText) {
|
|
55
|
+
const newLines = newText.split(/\r?\n/);
|
|
56
|
+
return [
|
|
57
|
+
...originalLines.map((line) => `-${line}`),
|
|
58
|
+
...newLines.map((line) => `+${line}`)
|
|
59
|
+
].join("\n");
|
|
60
|
+
}
|
|
61
|
+
function renderDiffPreviewMarkdown(edits) {
|
|
62
|
+
if (edits.length === 0) {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
const lines = ["## Proposed Changes", "", `**${edits.length} edit(s)** across ${new Set(edits.map((edit) => edit.file)).size} file(s):`, ""];
|
|
66
|
+
for (const edit of edits) {
|
|
67
|
+
const range = edit.range ? `:${edit.range.startLine}-${edit.range.endLine}` : " (whole file)";
|
|
68
|
+
lines.push(`### ${edit.file}${range}`, "");
|
|
69
|
+
if (edit.text.length <= 400) {
|
|
70
|
+
lines.push("```", edit.text, "```", "");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
lines.push("```", edit.text.slice(0, 400), "...", "```", "");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
lines.push("> Review each change carefully. Edits are not applied until you press **Apply Proposed Edits**.", "");
|
|
77
|
+
return lines.join("\n");
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=diffPreview.js.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QUALITY_SCORE_WEIGHTS = void 0;
|
|
4
|
+
exports.computeQualityScore = computeQualityScore;
|
|
5
|
+
exports.computeExpectedPathMetrics = computeExpectedPathMetrics;
|
|
6
|
+
exports.pathMatches = pathMatches;
|
|
7
|
+
exports.computeGroupResults = computeGroupResults;
|
|
8
|
+
exports.computeRankingQualityMetrics = computeRankingQualityMetrics;
|
|
9
|
+
const text_1 = require("../utils/text");
|
|
10
|
+
const fileGroups_1 = require("./fileGroups");
|
|
11
|
+
const subsystem_1 = require("./subsystem");
|
|
12
|
+
exports.QUALITY_SCORE_WEIGHTS = {
|
|
13
|
+
hitAt10: 0.35,
|
|
14
|
+
contextCoverage: 0.25,
|
|
15
|
+
avoidMiss: 0.2,
|
|
16
|
+
mrr: 0.1,
|
|
17
|
+
tokenReduction: 0.1
|
|
18
|
+
};
|
|
19
|
+
function clamp01(value) {
|
|
20
|
+
if (!Number.isFinite(value)) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return Math.max(0, Math.min(1, value));
|
|
24
|
+
}
|
|
25
|
+
function computeQualityScore(inputs) {
|
|
26
|
+
const hit = clamp01(inputs.hitAt10Norm);
|
|
27
|
+
const coverage = clamp01(inputs.contextCoverageNorm);
|
|
28
|
+
const avoidMiss = 1 - clamp01(inputs.avoidHitRate);
|
|
29
|
+
const mrr = clamp01(inputs.mrr);
|
|
30
|
+
const tokenReduction = clamp01(inputs.tokenReductionNorm);
|
|
31
|
+
return (exports.QUALITY_SCORE_WEIGHTS.hitAt10 * hit +
|
|
32
|
+
exports.QUALITY_SCORE_WEIGHTS.contextCoverage * coverage +
|
|
33
|
+
exports.QUALITY_SCORE_WEIGHTS.avoidMiss * avoidMiss +
|
|
34
|
+
exports.QUALITY_SCORE_WEIGHTS.mrr * mrr +
|
|
35
|
+
exports.QUALITY_SCORE_WEIGHTS.tokenReduction * tokenReduction);
|
|
36
|
+
}
|
|
37
|
+
function computeExpectedPathMetrics(units, expectedPaths, passAtK, mode = "any") {
|
|
38
|
+
if (expectedPaths.length === 0) {
|
|
39
|
+
return {
|
|
40
|
+
expectedCount: 0,
|
|
41
|
+
coverageAt5: 0,
|
|
42
|
+
coverageAt10: 0,
|
|
43
|
+
coverageAt20: 0,
|
|
44
|
+
coverageAt40: 0,
|
|
45
|
+
missingAt10: [],
|
|
46
|
+
missingAt20: [],
|
|
47
|
+
pass: "unlabeled"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const fileGroups = (0, fileGroups_1.aggregateEvidenceFiles)(units);
|
|
51
|
+
const firstUnitHitIndex = units.findIndex((unit) => expectedPaths.some((expectedPath) => pathMatches(unit.relativePath, expectedPath)));
|
|
52
|
+
const firstFileHitIndex = fileGroups.findIndex((group) => expectedPaths.some((expectedPath) => pathMatches(group.relativePath, expectedPath)));
|
|
53
|
+
const coverageAtPassK = coverageAt(fileGroups.map((group) => group.relativePath), expectedPaths, passAtK);
|
|
54
|
+
const pass = mode === "all" ? coverageAtPassK === expectedPaths.length : firstFileHitIndex >= 0 && firstFileHitIndex + 1 <= passAtK;
|
|
55
|
+
return {
|
|
56
|
+
expectedCount: expectedPaths.length,
|
|
57
|
+
firstUnitHitRank: firstUnitHitIndex >= 0 ? firstUnitHitIndex + 1 : undefined,
|
|
58
|
+
firstFileHitRank: firstFileHitIndex >= 0 ? firstFileHitIndex + 1 : undefined,
|
|
59
|
+
coverageAt5: coverageAt(fileGroups.map((group) => group.relativePath), expectedPaths, 5),
|
|
60
|
+
coverageAt10: coverageAt(fileGroups.map((group) => group.relativePath), expectedPaths, 10),
|
|
61
|
+
coverageAt20: coverageAt(fileGroups.map((group) => group.relativePath), expectedPaths, 20),
|
|
62
|
+
coverageAt40: coverageAt(fileGroups.map((group) => group.relativePath), expectedPaths, 40),
|
|
63
|
+
missingAt10: missingAt(fileGroups.map((group) => group.relativePath), expectedPaths, 10),
|
|
64
|
+
missingAt20: missingAt(fileGroups.map((group) => group.relativePath), expectedPaths, 20),
|
|
65
|
+
pass
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function pathMatches(actualPath, expectedPath) {
|
|
69
|
+
const actual = normalizePath(actualPath);
|
|
70
|
+
const expected = normalizePath(expectedPath);
|
|
71
|
+
if (expected.includes("*")) {
|
|
72
|
+
const escaped = expected.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
73
|
+
return new RegExp(`(^|/)${escaped}$`).test(actual);
|
|
74
|
+
}
|
|
75
|
+
return actual === expected || actual.endsWith(`/${expected}`) || actual.includes(expected);
|
|
76
|
+
}
|
|
77
|
+
function computeGroupResults(units, groups, passAtK = 10) {
|
|
78
|
+
const filePaths = (0, fileGroups_1.aggregateEvidenceFiles)(units).map((g) => g.relativePath);
|
|
79
|
+
return groups
|
|
80
|
+
.filter((group) => {
|
|
81
|
+
if (!Array.isArray(group.paths) || group.paths.length === 0)
|
|
82
|
+
return false;
|
|
83
|
+
if (!group.name || !group.mode)
|
|
84
|
+
return false;
|
|
85
|
+
return true;
|
|
86
|
+
})
|
|
87
|
+
.map((group) => {
|
|
88
|
+
const coveragePassK = coverageAt(filePaths, group.paths, passAtK);
|
|
89
|
+
const coverage5 = coverageAt(filePaths, group.paths, 5);
|
|
90
|
+
const coverage10 = coverageAt(filePaths, group.paths, 10);
|
|
91
|
+
const coverage20 = coverageAt(filePaths, group.paths, 20);
|
|
92
|
+
const coverage40 = coverageAt(filePaths, group.paths, 40);
|
|
93
|
+
const firstHitIndex = filePaths.findIndex((fp) => group.paths.some((ep) => pathMatches(fp, ep)));
|
|
94
|
+
const pass = group.mode === "all"
|
|
95
|
+
? coveragePassK === group.paths.length
|
|
96
|
+
: firstHitIndex >= 0 && firstHitIndex + 1 <= passAtK;
|
|
97
|
+
return {
|
|
98
|
+
name: group.name,
|
|
99
|
+
mode: group.mode,
|
|
100
|
+
expectedCount: group.paths.length,
|
|
101
|
+
firstHitRank: firstHitIndex >= 0 ? firstHitIndex + 1 : undefined,
|
|
102
|
+
passAtK,
|
|
103
|
+
coverageAtPassK: coveragePassK,
|
|
104
|
+
coverageAt5: coverage5,
|
|
105
|
+
coverageAt10: coverage10,
|
|
106
|
+
coverageAt20: coverage20,
|
|
107
|
+
coverageAt40: coverage40,
|
|
108
|
+
missingAtPassK: missingAt(filePaths, group.paths, passAtK),
|
|
109
|
+
missingAt10: missingAt(filePaths, group.paths, 10),
|
|
110
|
+
missingAt20: missingAt(filePaths, group.paths, 20),
|
|
111
|
+
passAt10: group.mode === "all" ? coverage10 === group.paths.length : firstHitIndex >= 0 && firstHitIndex + 1 <= 10,
|
|
112
|
+
pass,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function computeRankingQualityMetrics(result, topK = 10) {
|
|
117
|
+
const topUnits = result.units.slice(0, topK);
|
|
118
|
+
const uniqueTopFiles = new Set(topUnits.map((unit) => unit.relativePath)).size;
|
|
119
|
+
const duplicateEvidenceTop10 = topUnits.length - uniqueTopFiles;
|
|
120
|
+
const topGroups = (0, fileGroups_1.aggregateEvidenceFiles)(result.units).slice(0, topK);
|
|
121
|
+
const found = new Set(topGroups.map((group) => group.slot));
|
|
122
|
+
const requiredSlots = result.profile.blueprint.requiredSlots;
|
|
123
|
+
const foundRequiredSlotsTop10 = requiredSlots.filter((slot) => found.has(slot));
|
|
124
|
+
const missingRequiredSlotsTop10 = requiredSlots.filter((slot) => !found.has(slot));
|
|
125
|
+
const primarySubsystemTop10 = (0, subsystem_1.primarySubsystemFromUnits)(topGroups.flatMap((group) => group.units));
|
|
126
|
+
const subsystemFiles = topGroups.filter((group) => group.subsystem);
|
|
127
|
+
const subsystemPurityTop10 = primarySubsystemTop10 && subsystemFiles.length > 0
|
|
128
|
+
? subsystemFiles.filter((group) => group.subsystem === primarySubsystemTop10).length / subsystemFiles.length
|
|
129
|
+
: 0;
|
|
130
|
+
return {
|
|
131
|
+
uniqueTop10Files: uniqueTopFiles,
|
|
132
|
+
duplicateEvidenceTop10,
|
|
133
|
+
slotCoverageTop10: foundRequiredSlotsTop10.length,
|
|
134
|
+
requiredSlotCount: requiredSlots.length,
|
|
135
|
+
foundRequiredSlotsTop10,
|
|
136
|
+
missingRequiredSlotsTop10,
|
|
137
|
+
contrastContextTop10: topUnits.filter((unit) => unit.contrastContext).length,
|
|
138
|
+
primarySubsystemTop10,
|
|
139
|
+
subsystemPurityTop10,
|
|
140
|
+
symbolEvidenceTop10: topUnits.filter((unit) => (unit.symbolMatches?.length ?? 0) > 0 || unit.kind === "symbol").length
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function coverageAt(actualPaths, expectedPaths, k) {
|
|
144
|
+
const topPaths = actualPaths.slice(0, k);
|
|
145
|
+
return expectedPaths.filter((expectedPath) => topPaths.some((actualPath) => pathMatches(actualPath, expectedPath))).length;
|
|
146
|
+
}
|
|
147
|
+
function missingAt(actualPaths, expectedPaths, k) {
|
|
148
|
+
const topPaths = actualPaths.slice(0, k);
|
|
149
|
+
return expectedPaths.filter((expectedPath) => !topPaths.some((actualPath) => pathMatches(actualPath, expectedPath)));
|
|
150
|
+
}
|
|
151
|
+
function normalizePath(value) {
|
|
152
|
+
return (0, text_1.normalizeText)(value).replace(/\\/g, "/").replace(/^\/+/, "");
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=evaluationMetrics.js.map
|