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,382 @@
|
|
|
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.buildSolvePacket = buildSolvePacket;
|
|
37
|
+
exports.renderSolvePacketMarkdown = renderSolvePacketMarkdown;
|
|
38
|
+
const fs = __importStar(require("fs/promises"));
|
|
39
|
+
const fileGroups_1 = require("./fileGroups");
|
|
40
|
+
const contextBlueprint_1 = require("./contextBlueprint");
|
|
41
|
+
const maxPrimaryEditFiles = 7;
|
|
42
|
+
const maxReadOnlyFiles = 7;
|
|
43
|
+
const maxVerificationFiles = 6;
|
|
44
|
+
const maxNoiseRiskFiles = 6;
|
|
45
|
+
const maxSnippetChars = 850;
|
|
46
|
+
const minSnippetBudgetChars = 9000;
|
|
47
|
+
async function buildSolvePacket(result, config) {
|
|
48
|
+
const groups = (0, fileGroups_1.aggregateEvidenceFiles)(result.units);
|
|
49
|
+
const coverageGroups = selectCoverageGroups(groups, result);
|
|
50
|
+
const primaryEditCandidates = coverageGroups.filter((group) => group.role === "edit_candidate" && group.slot !== "tests" && !group.contrastContext);
|
|
51
|
+
const verificationTargets = groups.filter((group) => group.slot === "tests" || group.role === "test");
|
|
52
|
+
const noiseRisk = detectNoiseRisk(groups, result);
|
|
53
|
+
const noisePaths = new Set(noiseRisk.map((group) => group.relativePath));
|
|
54
|
+
const primaryPaths = new Set(primaryEditCandidates.map((group) => group.relativePath));
|
|
55
|
+
const verificationPaths = new Set(verificationTargets.map((group) => group.relativePath));
|
|
56
|
+
const readOnlyContext = coverageGroups.filter((group) => !primaryPaths.has(group.relativePath) && !verificationPaths.has(group.relativePath) && !noisePaths.has(group.relativePath));
|
|
57
|
+
const snippetBudget = {
|
|
58
|
+
remainingChars: Math.max(minSnippetBudgetChars, config.pipeline.maxContextTokens * 4)
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
userTask: result.task,
|
|
62
|
+
problemHypothesis: buildHypothesis(result, groups),
|
|
63
|
+
candidateFlow: buildCandidateFlow(coverageGroups, result),
|
|
64
|
+
primaryEditCandidates: await toPacketFiles(primaryEditCandidates.slice(0, Math.min(maxPrimaryEditFiles, config.pipeline.maxCandidates)), snippetBudget, "primary"),
|
|
65
|
+
readOnlyContext: await toPacketFiles(readOnlyContext.slice(0, Math.min(maxReadOnlyFiles, config.pipeline.maxCandidates)), snippetBudget, "context"),
|
|
66
|
+
verificationTargets: await toPacketFiles(verificationTargets.slice(0, Math.min(maxVerificationFiles, config.pipeline.maxCandidates)), snippetBudget, "verification"),
|
|
67
|
+
noiseRisk: await toPacketFiles(noiseRisk.slice(0, Math.min(maxNoiseRiskFiles, config.pipeline.maxCandidates)), snippetBudget, "noise"),
|
|
68
|
+
missingLinks: detectMissingLinks(groups, result),
|
|
69
|
+
agentInstructions: defaultAgentInstructions(result)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function renderSolvePacketMarkdown(packet) {
|
|
73
|
+
const lines = [
|
|
74
|
+
"# FlowSeeker Solve Packet",
|
|
75
|
+
"",
|
|
76
|
+
"## Important Note For AI",
|
|
77
|
+
"FlowSeeker evidence is candidate context, not guaranteed truth.",
|
|
78
|
+
"Validate relevance before editing.",
|
|
79
|
+
"Drop irrelevant files.",
|
|
80
|
+
"Treat contrast/noise-risk files as read-only comparison unless you can justify editing them.",
|
|
81
|
+
"Check Missing Links before making conclusions.",
|
|
82
|
+
"Do not edit outside the approved scope unless you explain why and ask for scope expansion.",
|
|
83
|
+
"If required flow context is missing, say what is missing instead of guessing.",
|
|
84
|
+
"",
|
|
85
|
+
"## User Task",
|
|
86
|
+
packet.userTask,
|
|
87
|
+
"",
|
|
88
|
+
"## Problem Hypothesis",
|
|
89
|
+
packet.problemHypothesis
|
|
90
|
+
];
|
|
91
|
+
if (packet.candidateFlow.length > 0) {
|
|
92
|
+
lines.push("", "## Candidate Flow Coverage");
|
|
93
|
+
for (const step of packet.candidateFlow) {
|
|
94
|
+
lines.push(`### ${sectionLabel(step.section)}`, ...step.files.map((file) => `- ${file}`), "");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
lines.push("## Primary Edit Candidates", ...renderPacketFiles(packet.primaryEditCandidates));
|
|
98
|
+
lines.push("## Read-Only Context", ...renderPacketFiles(packet.readOnlyContext));
|
|
99
|
+
lines.push("## Tests / Verification", ...renderPacketFiles(packet.verificationTargets));
|
|
100
|
+
if (packet.noiseRisk.length > 0) {
|
|
101
|
+
lines.push("## Noise Risk", ...renderPacketFiles(packet.noiseRisk));
|
|
102
|
+
}
|
|
103
|
+
if (packet.missingLinks.length > 0) {
|
|
104
|
+
lines.push("## Missing Links", ...packet.missingLinks.map((link) => `- ${link}`), "");
|
|
105
|
+
}
|
|
106
|
+
lines.push("## Agent Instructions", ...packet.agentInstructions.map((instruction, index) => `${index + 1}. ${instruction}`), "");
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
|
109
|
+
function buildHypothesis(result, groups) {
|
|
110
|
+
const profile = result.profile;
|
|
111
|
+
const topGroup = groups[0];
|
|
112
|
+
const topFile = topGroup?.relativePath ?? "unknown";
|
|
113
|
+
const required = profile.blueprint.requiredSlots.map(contextBlueprint_1.contextSlotLabel).join(", ");
|
|
114
|
+
const conceptPhrase = profile.concepts.length > 0 ? ` involving ${profile.concepts.slice(0, 5).join(", ")}` : "";
|
|
115
|
+
return `This is ${taskShapeArticle(profile.taskShape)} ${profile.taskShape} task${conceptPhrase}. FlowSeeker will validate the task through required context slots: ${required || "general code context"}. The strongest current evidence points to ${topFile}, but the AI must verify slot coverage before deciding what to edit.`;
|
|
116
|
+
}
|
|
117
|
+
function taskShapeArticle(shape) {
|
|
118
|
+
return /^[aeiou]/i.test(shape) ? "an" : "a";
|
|
119
|
+
}
|
|
120
|
+
function selectCoverageGroups(groups, result) {
|
|
121
|
+
const selected = new Map();
|
|
122
|
+
const maxGroups = 18;
|
|
123
|
+
const add = (group) => {
|
|
124
|
+
if (!group || selected.has(group.relativePath) || selected.size >= maxGroups) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
selected.set(group.relativePath, group);
|
|
128
|
+
};
|
|
129
|
+
for (const group of groups.slice(0, 8)) {
|
|
130
|
+
add(group);
|
|
131
|
+
}
|
|
132
|
+
for (const slot of result.profile.blueprint.requiredSlots) {
|
|
133
|
+
add(bestGroupForSlot(groups, slot, selected));
|
|
134
|
+
}
|
|
135
|
+
for (const slot of result.profile.blueprint.optionalSlots) {
|
|
136
|
+
add(bestGroupForSlot(groups, slot, selected));
|
|
137
|
+
if (selected.size >= 13) {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (const group of groups) {
|
|
142
|
+
add(group);
|
|
143
|
+
}
|
|
144
|
+
return Array.from(selected.values());
|
|
145
|
+
}
|
|
146
|
+
function bestGroupForSlot(groups, slot, selected) {
|
|
147
|
+
return groups.find((group) => group.slot === slot && !selected.has(group.relativePath));
|
|
148
|
+
}
|
|
149
|
+
function buildCandidateFlow(groups, result) {
|
|
150
|
+
const flow = [];
|
|
151
|
+
const orderedSlots = (0, contextBlueprint_1.sortSlots)([...result.profile.blueprint.requiredSlots, ...result.profile.blueprint.optionalSlots, "unknown"]);
|
|
152
|
+
for (const slot of orderedSlots) {
|
|
153
|
+
const files = groups.filter((group) => group.slot === slot).map((group) => formatFlowFile(group, result));
|
|
154
|
+
if (files.length > 0) {
|
|
155
|
+
flow.push({
|
|
156
|
+
section: slot,
|
|
157
|
+
label: sectionLabel(slot),
|
|
158
|
+
files: files.slice(0, 4)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return flow;
|
|
163
|
+
}
|
|
164
|
+
function formatFlowFile(group, result) {
|
|
165
|
+
const required = (0, contextBlueprint_1.isRequiredSlot)(result.profile, group.slot) ? "required-slot" : "optional";
|
|
166
|
+
return `${group.relativePath} [${group.role}; ${required}; score ${group.score.toFixed(1)}]`;
|
|
167
|
+
}
|
|
168
|
+
function renderPacketFiles(files) {
|
|
169
|
+
if (files.length === 0) {
|
|
170
|
+
return ["- None identified.", ""];
|
|
171
|
+
}
|
|
172
|
+
return files.flatMap((file) => [
|
|
173
|
+
`- ${file.relativePath}`,
|
|
174
|
+
` Slot: ${file.slot ? (0, contextBlueprint_1.contextSlotLabel)(file.slot) : "Unknown"}; Role: ${file.role}; Kind: ${file.kind}; Score: ${file.score.toFixed(1)}; Tier: ${file.tier}`,
|
|
175
|
+
...(file.contextMode ? [` Context: ${contextModeLabel(file.contextMode)}${file.contextRange ? `, lines ${file.contextRange.startLine}-${file.contextRange.endLine}` : ""}`] : []),
|
|
176
|
+
...(file.reasons.length > 0 ? [` Reasons: ${file.reasons.join("; ")}`] : []),
|
|
177
|
+
...(file.snippet ? ["", "```", file.snippet, "```"] : []),
|
|
178
|
+
""
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
function sectionLabel(section) {
|
|
182
|
+
return (0, contextBlueprint_1.contextSlotLabel)(section);
|
|
183
|
+
}
|
|
184
|
+
async function toPacketFiles(groups, budget, purpose) {
|
|
185
|
+
const files = [];
|
|
186
|
+
for (const [index, group] of groups.entries()) {
|
|
187
|
+
const snippetContext = await buildSnippetContext(group, budget, maxCharsForPurpose(purpose, index));
|
|
188
|
+
files.push({
|
|
189
|
+
relativePath: group.relativePath,
|
|
190
|
+
role: group.role,
|
|
191
|
+
kind: group.kinds[0] ?? "code_region",
|
|
192
|
+
slot: group.slot,
|
|
193
|
+
contextMode: snippetContext.mode,
|
|
194
|
+
contextRange: snippetContext.range,
|
|
195
|
+
score: group.score,
|
|
196
|
+
confidence: group.confidence,
|
|
197
|
+
tier: group.tier,
|
|
198
|
+
reasons: group.reasons.slice(0, 5),
|
|
199
|
+
snippet: snippetContext.snippet
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return files;
|
|
203
|
+
}
|
|
204
|
+
function compactSnippet(snippet) {
|
|
205
|
+
if (!snippet) {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
const trimmed = snippet.trim();
|
|
209
|
+
if (trimmed.length <= maxSnippetChars) {
|
|
210
|
+
return trimmed;
|
|
211
|
+
}
|
|
212
|
+
return `${trimmed.slice(0, maxSnippetChars)}\n... [FlowSeeker truncated snippet for token budget]`;
|
|
213
|
+
}
|
|
214
|
+
async function buildSnippetContext(group, budget, preferredMaxChars) {
|
|
215
|
+
const fallbackSnippet = compactEvidenceSnippets(group);
|
|
216
|
+
if (budget.remainingChars <= 0) {
|
|
217
|
+
return { snippet: fallbackSnippet, mode: fallbackSnippet ? "evidence_snippets" : undefined };
|
|
218
|
+
}
|
|
219
|
+
const maxChars = Math.max(maxSnippetChars, Math.min(preferredMaxChars, budget.remainingChars));
|
|
220
|
+
const fileContext = await readExpandedFileContext(group, maxChars);
|
|
221
|
+
if (fileContext.snippet) {
|
|
222
|
+
budget.remainingChars -= fileContext.snippet.length;
|
|
223
|
+
return fileContext;
|
|
224
|
+
}
|
|
225
|
+
if (fallbackSnippet) {
|
|
226
|
+
const snippet = truncateToBudget(fallbackSnippet, maxChars);
|
|
227
|
+
budget.remainingChars -= snippet.length;
|
|
228
|
+
return { snippet, mode: "evidence_snippets" };
|
|
229
|
+
}
|
|
230
|
+
return {};
|
|
231
|
+
}
|
|
232
|
+
async function readExpandedFileContext(group, maxChars) {
|
|
233
|
+
try {
|
|
234
|
+
const content = await fs.readFile(group.file, "utf8");
|
|
235
|
+
if (!content.trim() || content.includes("\u0000")) {
|
|
236
|
+
return {};
|
|
237
|
+
}
|
|
238
|
+
if (content.length <= maxChars) {
|
|
239
|
+
const lines = content.split(/\r?\n/);
|
|
240
|
+
return {
|
|
241
|
+
snippet: content.trim(),
|
|
242
|
+
mode: "full_file",
|
|
243
|
+
range: { startLine: 1, endLine: lines.length }
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const range = expandedRange(group, content);
|
|
247
|
+
if (!range) {
|
|
248
|
+
return {
|
|
249
|
+
snippet: truncateToBudget(content.trim(), maxChars),
|
|
250
|
+
mode: "expanded_range",
|
|
251
|
+
range: { startLine: 1, endLine: Math.max(1, content.slice(0, maxChars).split(/\r?\n/).length) }
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const lines = content.split(/\r?\n/);
|
|
255
|
+
const selected = lines.slice(range.startLine - 1, range.endLine).join("\n").trim();
|
|
256
|
+
return {
|
|
257
|
+
snippet: truncateToBudget(selected, maxChars),
|
|
258
|
+
mode: "expanded_range",
|
|
259
|
+
range
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function expandedRange(group, content) {
|
|
267
|
+
const lines = content.split(/\r?\n/);
|
|
268
|
+
const ranges = group.ranges.filter((range) => range.startLine > 0 && range.endLine >= range.startLine);
|
|
269
|
+
if (ranges.length === 0) {
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
const firstStart = Math.min(...ranges.map((range) => range.startLine));
|
|
273
|
+
const lastEnd = Math.max(...ranges.map((range) => range.endLine));
|
|
274
|
+
const span = Math.max(1, lastEnd - firstStart + 1);
|
|
275
|
+
const padding = span <= 3 ? 40 : span <= 30 ? 25 : 12;
|
|
276
|
+
return {
|
|
277
|
+
startLine: Math.max(1, firstStart - padding),
|
|
278
|
+
endLine: Math.min(lines.length, lastEnd + padding)
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function compactEvidenceSnippets(group) {
|
|
282
|
+
const snippets = group.units
|
|
283
|
+
.map((unit) => unit.snippet?.trim())
|
|
284
|
+
.filter((snippet) => Boolean(snippet))
|
|
285
|
+
.slice(0, 3);
|
|
286
|
+
if (snippets.length === 0) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
return compactSnippet(snippets.join("\n\n--- related evidence ---\n\n"));
|
|
290
|
+
}
|
|
291
|
+
function truncateToBudget(text, maxChars) {
|
|
292
|
+
if (text.length <= maxChars) {
|
|
293
|
+
return text;
|
|
294
|
+
}
|
|
295
|
+
return `${text.slice(0, Math.max(0, maxChars - 60)).trimEnd()}\n... [FlowSeeker truncated expanded context for token budget]`;
|
|
296
|
+
}
|
|
297
|
+
function maxCharsForPurpose(purpose, index) {
|
|
298
|
+
if (purpose === "primary") {
|
|
299
|
+
return index < 3 ? 3200 : 1800;
|
|
300
|
+
}
|
|
301
|
+
if (purpose === "verification") {
|
|
302
|
+
return 1600;
|
|
303
|
+
}
|
|
304
|
+
if (purpose === "noise") {
|
|
305
|
+
return 700;
|
|
306
|
+
}
|
|
307
|
+
return 1400;
|
|
308
|
+
}
|
|
309
|
+
function contextModeLabel(mode) {
|
|
310
|
+
if (mode === "full_file") {
|
|
311
|
+
return "full file";
|
|
312
|
+
}
|
|
313
|
+
if (mode === "expanded_range") {
|
|
314
|
+
return "expanded relevant range";
|
|
315
|
+
}
|
|
316
|
+
return "evidence snippets";
|
|
317
|
+
}
|
|
318
|
+
function detectNoiseRisk(groups, result) {
|
|
319
|
+
const neededSlots = new Set((0, contextBlueprint_1.allContextSlots)(result.profile.blueprint));
|
|
320
|
+
return groups.filter((group) => isNoiseGroup(group, neededSlots)).slice(0, maxNoiseRiskFiles);
|
|
321
|
+
}
|
|
322
|
+
function isNoiseGroup(group, neededSlots) {
|
|
323
|
+
const normalized = group.relativePath.replace(/\\/g, "/").toLowerCase();
|
|
324
|
+
if (group.contrastContext) {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
if (/\b(i18n|locale|locales|translation|translations|messages|message|dictionary|dictionaries|guidance|readiness|privacy|terms|legal|static|public|assets|vendor|node_modules)\b/.test(normalized)) {
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
if (/\b(fixture|fixtures|mock|mocks|seed|seeds|smoke|e2e|snapshot)\b/.test(normalized) && group.slot !== "tests") {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
if ((group.slot === "side_effect" || group.slot === "ui" || group.slot === "docs") && !neededSlots.has(group.slot) && group.score < 70) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
function detectMissingLinks(groups, result) {
|
|
339
|
+
const missing = [];
|
|
340
|
+
const foundSlots = new Set(groups.map((group) => group.slot));
|
|
341
|
+
for (const slot of result.profile.blueprint.requiredSlots) {
|
|
342
|
+
if (!foundSlots.has(slot)) {
|
|
343
|
+
missing.push(`No ${(0, contextBlueprint_1.contextSlotLabel)(slot)} file was identified for this ${result.profile.taskShape} task.`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (isEditIntendedTask(result) && !groups.some((group) => group.role === "edit_candidate")) {
|
|
347
|
+
missing.push("No edit_candidate files were ranked with sufficient confidence. Broaden the search or relax minConfidence.");
|
|
348
|
+
}
|
|
349
|
+
if (result.stats.stoppedEarly) {
|
|
350
|
+
missing.push(`Scan stopped early: ${result.stats.stopReason ?? "budget limit reached"}. Treat coverage as partial.`);
|
|
351
|
+
}
|
|
352
|
+
return missing;
|
|
353
|
+
}
|
|
354
|
+
function isEditIntendedTask(result) {
|
|
355
|
+
return !["investigation", "unknown"].includes(result.profile.taskShape);
|
|
356
|
+
}
|
|
357
|
+
function defaultAgentInstructions(result) {
|
|
358
|
+
if (!isEditIntendedTask(result)) {
|
|
359
|
+
return [
|
|
360
|
+
"This is a read-only investigation/explanation task. Do not propose code edits unless the user explicitly asks for changes.",
|
|
361
|
+
"Explain the current behavior from the retrieved context. Separate confirmed facts from reasonable inferences.",
|
|
362
|
+
"Use the candidate flow to describe how data moves through entry, UI, domain, data, config, and side-effect files.",
|
|
363
|
+
"Drop irrelevant evidence files. Mention only files that materially explain the behavior.",
|
|
364
|
+
"If context is partial, state the confidence level and the single most useful file or endpoint to inspect next.",
|
|
365
|
+
"Do not ask for broader scope when the current packet is enough to answer the user's question.",
|
|
366
|
+
"End with concise risks or unknowns only when they affect the explanation."
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
return [
|
|
370
|
+
"First decide whether the packet has enough required context slots to answer safely.",
|
|
371
|
+
"Validate the candidate flow before editing. Confirm each file's relevance by reading its content.",
|
|
372
|
+
"Drop irrelevant evidence files. Do not reference or edit files that are noise risk unless they are actually needed.",
|
|
373
|
+
"Treat contrast/noise-risk files as behavior-to-avoid or read-only comparison unless editing them is clearly required.",
|
|
374
|
+
"Produce a reviewable plan first: what changes, why, and in which files.",
|
|
375
|
+
"Only after user approval, generate the smallest coherent set of edits within the approved scope.",
|
|
376
|
+
"If a required slot is missing, state exactly what is missing and ask for a broader search before guessing.",
|
|
377
|
+
"Update or suggest tests when the behavior of a tested unit changes.",
|
|
378
|
+
"Run focused checks (lint, typecheck, unit tests) after applying edits.",
|
|
379
|
+
"Summarize changed files, remaining risk, and verification gaps when done."
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=solvePacket.js.map
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferSubsystem = inferSubsystem;
|
|
4
|
+
exports.inferSubsystemTerms = inferSubsystemTerms;
|
|
5
|
+
exports.inferTaskSubsystemTerms = inferTaskSubsystemTerms;
|
|
6
|
+
exports.subsystemAlignmentScore = subsystemAlignmentScore;
|
|
7
|
+
exports.primarySubsystemFromUnits = primarySubsystemFromUnits;
|
|
8
|
+
const text_1 = require("../utils/text");
|
|
9
|
+
const genericSegments = new Set([
|
|
10
|
+
"api",
|
|
11
|
+
"app",
|
|
12
|
+
"apps",
|
|
13
|
+
"backend",
|
|
14
|
+
"bin",
|
|
15
|
+
"cmd",
|
|
16
|
+
"common",
|
|
17
|
+
"component",
|
|
18
|
+
"components",
|
|
19
|
+
"config",
|
|
20
|
+
"configs",
|
|
21
|
+
"constants",
|
|
22
|
+
"controller",
|
|
23
|
+
"controllers",
|
|
24
|
+
"core",
|
|
25
|
+
"data",
|
|
26
|
+
"database",
|
|
27
|
+
"db",
|
|
28
|
+
"domain",
|
|
29
|
+
"dto",
|
|
30
|
+
"dtos",
|
|
31
|
+
"entity",
|
|
32
|
+
"entities",
|
|
33
|
+
"events",
|
|
34
|
+
"frontend",
|
|
35
|
+
"handler",
|
|
36
|
+
"handlers",
|
|
37
|
+
"helper",
|
|
38
|
+
"helpers",
|
|
39
|
+
"hook",
|
|
40
|
+
"hooks",
|
|
41
|
+
"infra",
|
|
42
|
+
"infrastructure",
|
|
43
|
+
"internal",
|
|
44
|
+
"job",
|
|
45
|
+
"jobs",
|
|
46
|
+
"lib",
|
|
47
|
+
"libs",
|
|
48
|
+
"mail",
|
|
49
|
+
"middleware",
|
|
50
|
+
"migration",
|
|
51
|
+
"migrations",
|
|
52
|
+
"model",
|
|
53
|
+
"models",
|
|
54
|
+
"module",
|
|
55
|
+
"modules",
|
|
56
|
+
"page",
|
|
57
|
+
"pages",
|
|
58
|
+
"package",
|
|
59
|
+
"packages",
|
|
60
|
+
"policy",
|
|
61
|
+
"policies",
|
|
62
|
+
"public",
|
|
63
|
+
"queue",
|
|
64
|
+
"queues",
|
|
65
|
+
"repository",
|
|
66
|
+
"repositories",
|
|
67
|
+
"request",
|
|
68
|
+
"requests",
|
|
69
|
+
"resource",
|
|
70
|
+
"resources",
|
|
71
|
+
"route",
|
|
72
|
+
"routes",
|
|
73
|
+
"schema",
|
|
74
|
+
"schemas",
|
|
75
|
+
"screen",
|
|
76
|
+
"screens",
|
|
77
|
+
"server",
|
|
78
|
+
"service",
|
|
79
|
+
"services",
|
|
80
|
+
"shared",
|
|
81
|
+
"src",
|
|
82
|
+
"store",
|
|
83
|
+
"stores",
|
|
84
|
+
"template",
|
|
85
|
+
"templates",
|
|
86
|
+
"test",
|
|
87
|
+
"tests",
|
|
88
|
+
"type",
|
|
89
|
+
"types",
|
|
90
|
+
"ui",
|
|
91
|
+
"util",
|
|
92
|
+
"utils",
|
|
93
|
+
"validator",
|
|
94
|
+
"validators",
|
|
95
|
+
"view",
|
|
96
|
+
"views",
|
|
97
|
+
"web",
|
|
98
|
+
"worker",
|
|
99
|
+
"workers"
|
|
100
|
+
]);
|
|
101
|
+
const lowSignalTaskTerms = new Set([
|
|
102
|
+
"add",
|
|
103
|
+
"all",
|
|
104
|
+
"auto",
|
|
105
|
+
"bug",
|
|
106
|
+
"cache",
|
|
107
|
+
"change",
|
|
108
|
+
"check",
|
|
109
|
+
"code",
|
|
110
|
+
"config",
|
|
111
|
+
"create",
|
|
112
|
+
"data",
|
|
113
|
+
"debug",
|
|
114
|
+
"delete",
|
|
115
|
+
"display",
|
|
116
|
+
"error",
|
|
117
|
+
"file",
|
|
118
|
+
"files",
|
|
119
|
+
"find",
|
|
120
|
+
"fix",
|
|
121
|
+
"flow",
|
|
122
|
+
"form",
|
|
123
|
+
"handle",
|
|
124
|
+
"handler",
|
|
125
|
+
"input",
|
|
126
|
+
"issue",
|
|
127
|
+
"list",
|
|
128
|
+
"logic",
|
|
129
|
+
"new",
|
|
130
|
+
"page",
|
|
131
|
+
"query",
|
|
132
|
+
"request",
|
|
133
|
+
"review",
|
|
134
|
+
"route",
|
|
135
|
+
"schema",
|
|
136
|
+
"screen",
|
|
137
|
+
"service",
|
|
138
|
+
"show",
|
|
139
|
+
"status",
|
|
140
|
+
"system",
|
|
141
|
+
"table",
|
|
142
|
+
"test",
|
|
143
|
+
"type",
|
|
144
|
+
"update",
|
|
145
|
+
"user",
|
|
146
|
+
"valid",
|
|
147
|
+
"validate",
|
|
148
|
+
"view"
|
|
149
|
+
]);
|
|
150
|
+
const roleSuffixes = [
|
|
151
|
+
"api",
|
|
152
|
+
"command",
|
|
153
|
+
"component",
|
|
154
|
+
"config",
|
|
155
|
+
"configuration",
|
|
156
|
+
"controller",
|
|
157
|
+
"dto",
|
|
158
|
+
"entity",
|
|
159
|
+
"event",
|
|
160
|
+
"form",
|
|
161
|
+
"handler",
|
|
162
|
+
"helper",
|
|
163
|
+
"hook",
|
|
164
|
+
"job",
|
|
165
|
+
"listener",
|
|
166
|
+
"middleware",
|
|
167
|
+
"model",
|
|
168
|
+
"page",
|
|
169
|
+
"policy",
|
|
170
|
+
"provider",
|
|
171
|
+
"query",
|
|
172
|
+
"repository",
|
|
173
|
+
"request",
|
|
174
|
+
"resolver",
|
|
175
|
+
"route",
|
|
176
|
+
"schema",
|
|
177
|
+
"service",
|
|
178
|
+
"store",
|
|
179
|
+
"task",
|
|
180
|
+
"template",
|
|
181
|
+
"type",
|
|
182
|
+
"validator",
|
|
183
|
+
"view",
|
|
184
|
+
"worker"
|
|
185
|
+
];
|
|
186
|
+
function inferSubsystem(relativePath, symbolNames = []) {
|
|
187
|
+
return inferSubsystemTerms(relativePath, symbolNames)[0];
|
|
188
|
+
}
|
|
189
|
+
function inferSubsystemTerms(relativePath, symbolNames = []) {
|
|
190
|
+
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
191
|
+
const pathTerms = pathSubsystemTerms(normalizedPath);
|
|
192
|
+
const symbolTerms = symbolNames.flatMap((symbol) => symbolSubsystemTerms(symbol));
|
|
193
|
+
return (0, text_1.uniq)([...pathTerms, ...symbolTerms])
|
|
194
|
+
.map(text_1.normalizeText)
|
|
195
|
+
.filter((term) => isUsefulSubsystemTerm(term))
|
|
196
|
+
.slice(0, 6);
|
|
197
|
+
}
|
|
198
|
+
function inferTaskSubsystemTerms(profile) {
|
|
199
|
+
const sourceTerms = [...profile.entities, ...profile.concepts, ...profile.keywords];
|
|
200
|
+
return (0, text_1.uniq)(sourceTerms.flatMap(text_1.splitIdentifier))
|
|
201
|
+
.map(text_1.normalizeText)
|
|
202
|
+
.filter((term) => term.length > 2 && !genericSegments.has(term) && !lowSignalTaskTerms.has(term))
|
|
203
|
+
.slice(0, 10);
|
|
204
|
+
}
|
|
205
|
+
function subsystemAlignmentScore(unit, profile) {
|
|
206
|
+
const taskTerms = inferTaskSubsystemTerms(profile);
|
|
207
|
+
if (taskTerms.length === 0) {
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
const unitTerms = unit.subsystemTerms?.length
|
|
211
|
+
? unit.subsystemTerms
|
|
212
|
+
: inferSubsystemTerms(unit.relativePath, unit.symbols ?? []);
|
|
213
|
+
if (unitTerms.length === 0) {
|
|
214
|
+
return 0;
|
|
215
|
+
}
|
|
216
|
+
const matches = unitTerms.filter((term) => taskTerms.some((taskTerm) => term === taskTerm || term.includes(taskTerm) || taskTerm.includes(term)));
|
|
217
|
+
if (matches.length > 0) {
|
|
218
|
+
return 4 + Math.min(10, matches.length * 4);
|
|
219
|
+
}
|
|
220
|
+
return 0;
|
|
221
|
+
}
|
|
222
|
+
function primarySubsystemFromUnits(units) {
|
|
223
|
+
const counts = new Map();
|
|
224
|
+
for (const unit of units) {
|
|
225
|
+
if (!unit.subsystem || unit.contrastContext) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
counts.set(unit.subsystem, (counts.get(unit.subsystem) ?? 0) + Math.max(1, Math.round(unit.score / 50)));
|
|
229
|
+
}
|
|
230
|
+
return Array.from(counts.entries()).sort((left, right) => right[1] - left[1])[0]?.[0];
|
|
231
|
+
}
|
|
232
|
+
function pathSubsystemTerms(relativePath) {
|
|
233
|
+
const segments = relativePath
|
|
234
|
+
.split("/")
|
|
235
|
+
.map((segment) => segment.replace(/\.[^.]+$/, ""))
|
|
236
|
+
.flatMap(text_1.splitIdentifier)
|
|
237
|
+
.map(text_1.normalizeText)
|
|
238
|
+
.filter(Boolean);
|
|
239
|
+
const basename = relativePath.split("/").pop()?.replace(/\.[^.]+$/, "") ?? "";
|
|
240
|
+
const basenameTerms = trimRoleSuffixes((0, text_1.splitIdentifier)(basename).map(text_1.normalizeText));
|
|
241
|
+
const segmentTerms = segments.filter((segment) => isUsefulSubsystemTerm(segment));
|
|
242
|
+
return (0, text_1.uniq)([...basenameTerms, ...segmentTerms]);
|
|
243
|
+
}
|
|
244
|
+
function symbolSubsystemTerms(symbolName) {
|
|
245
|
+
return trimRoleSuffixes((0, text_1.splitIdentifier)(symbolName).map(text_1.normalizeText)).filter(isUsefulSubsystemTerm);
|
|
246
|
+
}
|
|
247
|
+
function trimRoleSuffixes(terms) {
|
|
248
|
+
const trimmed = [...terms];
|
|
249
|
+
while (trimmed.length > 1 && roleSuffixes.includes(trimmed[trimmed.length - 1])) {
|
|
250
|
+
trimmed.pop();
|
|
251
|
+
}
|
|
252
|
+
return trimmed;
|
|
253
|
+
}
|
|
254
|
+
function isUsefulSubsystemTerm(term) {
|
|
255
|
+
return term.length > 2 && !genericSegments.has(term) && !lowSignalTaskTerms.has(term) && !/^\d+$/.test(term);
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=subsystem.js.map
|