flowseeker 0.1.8 → 0.1.9
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 +12 -0
- package/dist/chat/nativeChatParticipant.js +1 -1
- package/dist/cli/main.js +19 -3
- package/dist/cli/runEvaluation.js +103 -0
- package/dist/eval/accuracyV2.js +483 -0
- package/dist/eval/goldenTask.js +192 -0
- package/dist/framework/laravel.js +177 -0
- package/dist/index/semanticChunkIndex.js +388 -0
- package/dist/index/workspaceIndex.js +339 -29
- package/dist/mcp/mcpTools.js +1627 -2
- package/dist/pipeline/contextBlueprint.js +15 -2
- package/dist/pipeline/fileScanner.js +116 -1
- package/dist/pipeline/fusionTrace.js +149 -0
- package/dist/pipeline/nodeScan.js +13 -2
- package/dist/pipeline/roleRefinement.js +62 -0
- package/dist/pipeline/runHeadless.js +25 -5
- package/dist/pipeline/runPipeline.js +2 -2
- package/dist/pipeline/solvePacket.js +112 -6
- package/dist/pipeline/taskUnderstanding.js +2 -2
- package/dist/ui/chatViewProvider.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,177 @@
|
|
|
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.laravelSlotMapping = void 0;
|
|
37
|
+
exports.detectLaravelFramework = detectLaravelFramework;
|
|
38
|
+
exports.classifyLaravelTask = classifyLaravelTask;
|
|
39
|
+
exports.laravelCategoryRequiredSlots = laravelCategoryRequiredSlots;
|
|
40
|
+
exports.laravelMissingLinkHints = laravelMissingLinkHints;
|
|
41
|
+
exports.applyLaravelTemplate = applyLaravelTemplate;
|
|
42
|
+
const fs = __importStar(require("fs/promises"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const laravelSignals = [
|
|
45
|
+
{ path: "artisan", weight: 8, label: "artisan" },
|
|
46
|
+
{ path: "routes/web.php", weight: 6, label: "routes/web.php" },
|
|
47
|
+
{ path: "routes/api.php", weight: 5, label: "routes/api.php" },
|
|
48
|
+
{ path: "app/Http/Controllers", weight: 5, label: "app/Http/Controllers" },
|
|
49
|
+
{ path: "app/Models", weight: 4, label: "app/Models" },
|
|
50
|
+
{ path: "resources/views", weight: 4, label: "resources/views" },
|
|
51
|
+
{ path: "config/app.php", weight: 3, label: "config/app.php" },
|
|
52
|
+
{ path: "bootstrap/app.php", weight: 3, label: "bootstrap/app.php" },
|
|
53
|
+
{ path: "app/Providers", weight: 2, label: "app/Providers" },
|
|
54
|
+
{ path: "app/Http/Middleware", weight: 2, label: "app/Http/Middleware" },
|
|
55
|
+
{ path: "database/migrations", weight: 2, label: "database/migrations" },
|
|
56
|
+
{ path: "app/Console", weight: 2, label: "app/Console" },
|
|
57
|
+
{ path: "vite.config.js", weight: 1, label: "vite.config.js" },
|
|
58
|
+
];
|
|
59
|
+
const minScoreForLaravel = 12;
|
|
60
|
+
async function detectLaravelFramework(rootPath) {
|
|
61
|
+
const signals = [];
|
|
62
|
+
let score = 0;
|
|
63
|
+
for (const signal of laravelSignals) {
|
|
64
|
+
try {
|
|
65
|
+
await fs.access(path.join(rootPath, signal.path));
|
|
66
|
+
score += signal.weight;
|
|
67
|
+
signals.push(signal.label);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// path doesn't exist
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Check composer.json for laravel/framework dependency
|
|
74
|
+
try {
|
|
75
|
+
const composerRaw = await fs.readFile(path.join(rootPath, "composer.json"), "utf8");
|
|
76
|
+
const composer = JSON.parse(composerRaw);
|
|
77
|
+
const deps = { ...(composer.require ?? {}), ...(composer["require-dev"] ?? {}) };
|
|
78
|
+
if (deps["laravel/framework"]) {
|
|
79
|
+
score += 10;
|
|
80
|
+
signals.push("composer:laravel/framework");
|
|
81
|
+
}
|
|
82
|
+
const illuminateDeps = Object.keys(deps).filter((k) => k.startsWith("illuminate/"));
|
|
83
|
+
if (illuminateDeps.length > 0) {
|
|
84
|
+
score += Math.min(5, illuminateDeps.length);
|
|
85
|
+
signals.push(`composer:illuminate(${illuminateDeps.length})`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// no composer.json
|
|
90
|
+
}
|
|
91
|
+
const confidence = Math.min(1, score / 25);
|
|
92
|
+
return {
|
|
93
|
+
isLaravel: score >= minScoreForLaravel,
|
|
94
|
+
confidence,
|
|
95
|
+
signals,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// ── Laravel slot → directory mapping ──────────────────────────────────────────
|
|
99
|
+
exports.laravelSlotMapping = {
|
|
100
|
+
entry: ["routes/*.php"],
|
|
101
|
+
handler: ["app/Http/Controllers/**"],
|
|
102
|
+
domain: ["app/Services/**", "app/Actions/**", "app/Exports/**", "app/Imports/**"],
|
|
103
|
+
data: ["app/Models/**", "app/Repositories/**", "database/migrations/**"],
|
|
104
|
+
validation: ["app/Http/Requests/**"],
|
|
105
|
+
permission: ["app/Policies/**", "app/Http/Middleware/**"],
|
|
106
|
+
config: ["config/**", ".env", ".env.example"],
|
|
107
|
+
side_effect: ["app/Jobs/**", "app/Events/**", "app/Listeners/**", "app/Mail/**", "app/Notifications/**"],
|
|
108
|
+
ui: ["resources/views/**"],
|
|
109
|
+
tests: ["tests/**"],
|
|
110
|
+
docs: [],
|
|
111
|
+
unknown: [],
|
|
112
|
+
};
|
|
113
|
+
function classifyLaravelTask(normalizedTask) {
|
|
114
|
+
const t = normalizedTask.toLowerCase();
|
|
115
|
+
if (/\bimport\b/.test(t) || /\bupload\b/.test(t))
|
|
116
|
+
return "import";
|
|
117
|
+
if (/\b(export|download|excel|csv|report|pdf)\b/.test(t))
|
|
118
|
+
return "export_report";
|
|
119
|
+
if (/\b(auth|login|logout|register|permission|role|policy|guard)\b/.test(t))
|
|
120
|
+
return "auth_permission";
|
|
121
|
+
if (/\b(payment|invoice|billing|checkout|refund|gateway)\b/.test(t))
|
|
122
|
+
return "payment_invoice";
|
|
123
|
+
if (/\b(email|notification|notify|mail|job|event|listener|dispatch)\b/.test(t))
|
|
124
|
+
return "notification_email";
|
|
125
|
+
if (/\b(view|display|page|blade|layout|render|frontend|ui|modal)\b/.test(t))
|
|
126
|
+
return "view_display";
|
|
127
|
+
return "generic";
|
|
128
|
+
}
|
|
129
|
+
function laravelCategoryRequiredSlots(category) {
|
|
130
|
+
const mapping = {
|
|
131
|
+
export_report: ["entry", "handler", "domain", "data", "side_effect", "tests"],
|
|
132
|
+
import: ["entry", "handler", "domain", "validation", "data", "tests"],
|
|
133
|
+
auth_permission: ["entry", "handler", "permission", "domain", "data", "tests"],
|
|
134
|
+
payment_invoice: ["entry", "handler", "domain", "data", "side_effect", "tests"],
|
|
135
|
+
notification_email: ["entry", "handler", "side_effect", "data", "tests"],
|
|
136
|
+
view_display: ["entry", "handler", "ui", "data", "tests"],
|
|
137
|
+
generic: ["entry", "handler", "domain", "data", "tests"],
|
|
138
|
+
};
|
|
139
|
+
return mapping[category] ?? mapping.generic;
|
|
140
|
+
}
|
|
141
|
+
// ── Missing-link hints ────────────────────────────────────────────────────────
|
|
142
|
+
function laravelMissingLinkHints(missingSlots) {
|
|
143
|
+
const hints = [];
|
|
144
|
+
for (const slot of missingSlots) {
|
|
145
|
+
const dirs = exports.laravelSlotMapping[slot];
|
|
146
|
+
if (dirs && dirs.length > 0) {
|
|
147
|
+
hints.push(`missing ${slot}: check ${dirs.join(", ")}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return hints;
|
|
151
|
+
}
|
|
152
|
+
async function applyLaravelTemplate(rootPath, normalizedTask, existingRequiredSlots) {
|
|
153
|
+
const detection = await detectLaravelFramework(rootPath);
|
|
154
|
+
if (!detection.isLaravel) {
|
|
155
|
+
return {
|
|
156
|
+
detected: false,
|
|
157
|
+
confidence: detection.confidence,
|
|
158
|
+
category: "generic",
|
|
159
|
+
suggestedRequiredSlots: [],
|
|
160
|
+
missingLinkHints: [],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const category = classifyLaravelTask(normalizedTask);
|
|
164
|
+
const templateSlots = laravelCategoryRequiredSlots(category);
|
|
165
|
+
const existing = new Set(existingRequiredSlots);
|
|
166
|
+
const suggested = templateSlots.filter((s) => !existing.has(s));
|
|
167
|
+
const missing = templateSlots.filter((s) => !existing.has(s));
|
|
168
|
+
const hints = laravelMissingLinkHints(missing);
|
|
169
|
+
return {
|
|
170
|
+
detected: true,
|
|
171
|
+
confidence: detection.confidence,
|
|
172
|
+
category,
|
|
173
|
+
suggestedRequiredSlots: suggested,
|
|
174
|
+
missingLinkHints: hints,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=laravel.js.map
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Semantic Chunk Index — Phase 18A, report-only.
|
|
3
|
+
// Provides typed diagnostics and a fake/test provider path.
|
|
4
|
+
// Does not change default deterministic retrieval ranking.
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.buildSemanticChunkDiagnostic = buildSemanticChunkDiagnostic;
|
|
40
|
+
exports.computeSemanticChunkDiagnostics = computeSemanticChunkDiagnostics;
|
|
41
|
+
exports.generateSlotQueries = generateSlotQueries;
|
|
42
|
+
exports.computeSlotHits = computeSlotHits;
|
|
43
|
+
exports.buildContributionReport = buildContributionReport;
|
|
44
|
+
exports.buildHybridPromotionReport = buildHybridPromotionReport;
|
|
45
|
+
const crypto = __importStar(require("crypto"));
|
|
46
|
+
// ── Safe hashing ──────────────────────────────────────────────────────
|
|
47
|
+
function hashChunk(text) {
|
|
48
|
+
return crypto.createHash("sha256").update(text, "utf8").digest("hex").substring(0, 16);
|
|
49
|
+
}
|
|
50
|
+
// ── Cache key ──────────────────────────────────────────────────────────
|
|
51
|
+
function cacheKey(base, provider, model, dims, chunkId, chunkHash) {
|
|
52
|
+
return [base, provider, model, String(dims), chunkId, chunkHash, "v18a-1"].join(":");
|
|
53
|
+
}
|
|
54
|
+
// ── Diagnostics builder ────────────────────────────────────────────────
|
|
55
|
+
function buildSemanticChunkDiagnostic(config, results) {
|
|
56
|
+
const enabled = config?.index?.semanticEnabled === true;
|
|
57
|
+
const provider = config?.index?.semanticProvider || "";
|
|
58
|
+
const model = config?.index?.semanticModel || "";
|
|
59
|
+
let readiness = "disabled";
|
|
60
|
+
if (enabled) {
|
|
61
|
+
if (!provider || !model)
|
|
62
|
+
readiness = "unavailable";
|
|
63
|
+
else if (!results.providerReady)
|
|
64
|
+
readiness = "unavailable";
|
|
65
|
+
else
|
|
66
|
+
readiness = "configured";
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
enabled,
|
|
70
|
+
provider,
|
|
71
|
+
model,
|
|
72
|
+
readiness,
|
|
73
|
+
chunksConsidered: results.chunksConsidered,
|
|
74
|
+
cacheHits: results.cacheHits,
|
|
75
|
+
cacheMisses: results.cacheMisses,
|
|
76
|
+
candidatesFound: results.candidatesFound,
|
|
77
|
+
candidatesAccepted: results.candidatesAccepted,
|
|
78
|
+
candidatesRejected: results.candidatesRejected,
|
|
79
|
+
topKContribution: results.topK,
|
|
80
|
+
reportOnly: true,
|
|
81
|
+
warnings: results.providerError ? [results.providerError] : [],
|
|
82
|
+
slotQueries: results.slotQueries || [],
|
|
83
|
+
slotHits: results.slotHits || [],
|
|
84
|
+
contributionReport: results.contributionReport,
|
|
85
|
+
hybridPromotionReport: results.hybridPromotionReport,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ── Entry point: compute semantic chunk diagnostics (report-only) ────
|
|
89
|
+
async function computeSemanticChunkDiagnostics(workspaceRoot, config, provider, taskText, chunkTexts) {
|
|
90
|
+
// Early return: semantic disabled must never call provider
|
|
91
|
+
if (!config?.index?.semanticEnabled) {
|
|
92
|
+
return {
|
|
93
|
+
diagnostic: buildSemanticChunkDiagnostic(config, {
|
|
94
|
+
chunksConsidered: 0, cacheHits: 0, cacheMisses: 0,
|
|
95
|
+
candidatesFound: 0, candidatesAccepted: 0, candidatesRejected: 0,
|
|
96
|
+
topK: 0, providerReady: false,
|
|
97
|
+
contributionReport: buildContributionReport(false, false, 0, 0),
|
|
98
|
+
hybridPromotionReport: buildHybridPromotionReport(false, false, [], [], []),
|
|
99
|
+
}),
|
|
100
|
+
hits: [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const chunksConsidered = chunkTexts.length;
|
|
104
|
+
let cacheHits = 0;
|
|
105
|
+
let cacheMisses = 0;
|
|
106
|
+
let candidatesFound = 0;
|
|
107
|
+
const hits = [];
|
|
108
|
+
if (!provider) {
|
|
109
|
+
return {
|
|
110
|
+
diagnostic: buildSemanticChunkDiagnostic(config, {
|
|
111
|
+
chunksConsidered, cacheHits, cacheMisses, candidatesFound,
|
|
112
|
+
candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
|
|
113
|
+
providerReady: false, providerError: "No embedding provider configured",
|
|
114
|
+
contributionReport: buildContributionReport(true, false, 0, 0),
|
|
115
|
+
hybridPromotionReport: buildHybridPromotionReport(true, false, [], [], []),
|
|
116
|
+
}),
|
|
117
|
+
hits: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Compute embeddings (fake or real)
|
|
121
|
+
try {
|
|
122
|
+
const texts = chunkTexts.map(c => c.text);
|
|
123
|
+
const taskEmbedding = await provider.embedTexts([taskText]);
|
|
124
|
+
const chunkEmbeddings = await provider.embedTexts(texts);
|
|
125
|
+
// Cosine similarity
|
|
126
|
+
for (let i = 0; i < chunkEmbeddings.length; i++) {
|
|
127
|
+
const sim = cosineSimilarity(taskEmbedding[0], chunkEmbeddings[i]);
|
|
128
|
+
if (sim > 0.5) {
|
|
129
|
+
candidatesFound++;
|
|
130
|
+
hits.push({
|
|
131
|
+
filePath: chunkTexts[i].filePath,
|
|
132
|
+
chunkId: chunkTexts[i].id,
|
|
133
|
+
startLine: chunkTexts[i].startLine,
|
|
134
|
+
endLine: chunkTexts[i].endLine,
|
|
135
|
+
kind: chunkTexts[i].kind,
|
|
136
|
+
slot: chunkTexts[i].slot,
|
|
137
|
+
similarity: parseFloat(sim.toFixed(4)),
|
|
138
|
+
rank: i + 1,
|
|
139
|
+
reason: `semantic similarity ${sim.toFixed(3)}`,
|
|
140
|
+
contentPreview: chunkTexts[i].text.substring(0, 100),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
cacheMisses = chunksConsidered;
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
return {
|
|
148
|
+
diagnostic: buildSemanticChunkDiagnostic(config, {
|
|
149
|
+
chunksConsidered, cacheHits, cacheMisses, candidatesFound,
|
|
150
|
+
candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
|
|
151
|
+
providerReady: false, providerError: e?.message || String(e),
|
|
152
|
+
contributionReport: buildContributionReport(true, false, 0, 0),
|
|
153
|
+
hybridPromotionReport: buildHybridPromotionReport(true, false, [], [], []),
|
|
154
|
+
}),
|
|
155
|
+
hits: [],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const diagnostic = buildSemanticChunkDiagnostic(config, {
|
|
159
|
+
chunksConsidered, cacheHits: 0, cacheMisses: chunksConsidered, candidatesFound,
|
|
160
|
+
candidatesAccepted: 0, candidatesRejected: 0, topK: 0,
|
|
161
|
+
providerReady: true,
|
|
162
|
+
contributionReport: buildContributionReport(true, true, candidatesFound, 0),
|
|
163
|
+
hybridPromotionReport: buildHybridPromotionReport(true, true, hits, [], []),
|
|
164
|
+
});
|
|
165
|
+
return { diagnostic, hits };
|
|
166
|
+
}
|
|
167
|
+
// ── Slot query generation ────────────────────────────────────────────
|
|
168
|
+
var slotSearchTerms = {
|
|
169
|
+
entry: ["route", "routes", "router", "endpoint", "api", "page", "screen", "loader", "action"],
|
|
170
|
+
handler: ["controller", "handler", "action", "resolver", "listener", "job", "worker", "consumer", "command", "commands"],
|
|
171
|
+
domain: ["service", "usecase", "use_case", "repository", "manager", "processor", "model", "entity", "store", "stores", "hook", "hooks"],
|
|
172
|
+
data: ["model", "models", "schema", "migration", "database", "table", "query", "entity", "orm", "prisma"],
|
|
173
|
+
validation: ["request", "validator", "validation", "rule", "rules", "dto", "formrequest", "schema"],
|
|
174
|
+
permission: ["policy", "permission", "role", "guard", "middleware", "authorize", "auth", "acl"],
|
|
175
|
+
config: ["config", "env", "setting", "settings", "feature", "flag", "yaml", "json"],
|
|
176
|
+
side_effect: ["event", "listener", "job", "queue", "mail", "email", "notification", "webhook", "cache", "dispatch"],
|
|
177
|
+
ui: ["component", "page", "view", "screen", "template", "form", "button", "modal", "layout", "responsive", "grid", "drawer", "sidebar", "toast", "chart"],
|
|
178
|
+
tests: ["test", "tests", "spec", "expect", "assert", "fixture", "fixtures"],
|
|
179
|
+
docs: ["readme", "docs", "documentation", "markdown", "guide"],
|
|
180
|
+
unknown: []
|
|
181
|
+
};
|
|
182
|
+
function generateSlotQueries(taskText, requiredSlots, optionalSlots) {
|
|
183
|
+
var queries = [];
|
|
184
|
+
var seen = {};
|
|
185
|
+
function canonicalSlot(slot) {
|
|
186
|
+
if (slot === "tests")
|
|
187
|
+
return "test";
|
|
188
|
+
return slot;
|
|
189
|
+
}
|
|
190
|
+
function add(slot, required) {
|
|
191
|
+
var canon = canonicalSlot(slot);
|
|
192
|
+
if (seen[canon])
|
|
193
|
+
return;
|
|
194
|
+
seen[canon] = true;
|
|
195
|
+
// Lookup terms by original slot name
|
|
196
|
+
var terms = slotSearchTerms[slot] || [];
|
|
197
|
+
if (terms.length === 0)
|
|
198
|
+
return;
|
|
199
|
+
queries.push({
|
|
200
|
+
slot: canon,
|
|
201
|
+
query: taskText + " " + terms.join(" "),
|
|
202
|
+
source: "task_blueprint",
|
|
203
|
+
required: required,
|
|
204
|
+
weight: required ? 1.0 : 0.5,
|
|
205
|
+
reasons: [(required ? "required" : "optional") + " slot: " + canon]
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
for (var r = 0; r < requiredSlots.length; r++)
|
|
209
|
+
add(requiredSlots[r], true);
|
|
210
|
+
for (var o = 0; o < optionalSlots.length; o++)
|
|
211
|
+
add(optionalSlots[o], false);
|
|
212
|
+
return queries;
|
|
213
|
+
}
|
|
214
|
+
async function computeSlotHits(provider, slotQueries, chunkTexts) {
|
|
215
|
+
if (!provider || slotQueries.length === 0)
|
|
216
|
+
return [];
|
|
217
|
+
try {
|
|
218
|
+
var slotHits = [];
|
|
219
|
+
for (var sq = 0; sq < slotQueries.length; sq++) {
|
|
220
|
+
var sqObj = slotQueries[sq];
|
|
221
|
+
var qEmb = await provider.embedTexts([sqObj.query]);
|
|
222
|
+
var chunkEmbs = await provider.embedTexts(chunkTexts.map(function (c) { return c.text; }));
|
|
223
|
+
var slotCandidates = [];
|
|
224
|
+
for (var ci = 0; ci < chunkEmbs.length; ci++) {
|
|
225
|
+
var sim = cosineSimilarity(qEmb[0], chunkEmbs[ci]);
|
|
226
|
+
if (sim > 0.4) {
|
|
227
|
+
slotCandidates.push({
|
|
228
|
+
filePath: chunkTexts[ci].filePath, chunkId: chunkTexts[ci].id,
|
|
229
|
+
startLine: chunkTexts[ci].startLine, endLine: chunkTexts[ci].endLine,
|
|
230
|
+
kind: chunkTexts[ci].kind, slot: chunkTexts[ci].slot,
|
|
231
|
+
similarity: parseFloat(sim.toFixed(4)), rank: ci + 1,
|
|
232
|
+
reason: "slot " + sqObj.slot + " sim " + sim.toFixed(3),
|
|
233
|
+
contentPreview: chunkTexts[ci].text.substring(0, 80),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
var hitCount = slotCandidates.length;
|
|
238
|
+
var recoveryStatus = hitCount >= 3 ? "recovered" : hitCount > 0 ? "not_recovered" : "not_evaluated";
|
|
239
|
+
slotHits.push({
|
|
240
|
+
slot: sqObj.slot, query: sqObj.query.substring(0, 80),
|
|
241
|
+
hits: hitCount, hitCount: hitCount,
|
|
242
|
+
recoveryStatus: recoveryStatus,
|
|
243
|
+
missingBeforeSemantic: hitCount === 0,
|
|
244
|
+
recoveredBySemantic: hitCount >= 3,
|
|
245
|
+
topCandidates: slotCandidates.slice(0, 3)
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return slotHits;
|
|
249
|
+
}
|
|
250
|
+
catch (e) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// ── Contribution report builder ──────────────────────────────────────
|
|
255
|
+
function buildContributionReport(semanticEnabled, providerReady, hitsFound, deterministicTopCount) {
|
|
256
|
+
if (!semanticEnabled) {
|
|
257
|
+
return {
|
|
258
|
+
addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
|
|
259
|
+
semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
|
|
260
|
+
noOp: true, regressionRisk: "none",
|
|
261
|
+
reasons: ["semantic disabled"],
|
|
262
|
+
status: "disabled",
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (!providerReady) {
|
|
266
|
+
return {
|
|
267
|
+
addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
|
|
268
|
+
semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
|
|
269
|
+
noOp: true, regressionRisk: "none",
|
|
270
|
+
reasons: ["provider unavailable"],
|
|
271
|
+
status: "unavailable",
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (hitsFound === 0) {
|
|
275
|
+
return {
|
|
276
|
+
addedCandidates: 0, acceptedCandidates: 0, rejectedCandidates: 0,
|
|
277
|
+
semanticOnlyCandidates: 0, deterministicOverlap: 0, topKDelta: 0,
|
|
278
|
+
noOp: true, regressionRisk: "none",
|
|
279
|
+
reasons: ["no semantic hits found"],
|
|
280
|
+
status: "no_hits",
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
addedCandidates: hitsFound,
|
|
285
|
+
acceptedCandidates: hitsFound,
|
|
286
|
+
rejectedCandidates: 0,
|
|
287
|
+
semanticOnlyCandidates: hitsFound,
|
|
288
|
+
deterministicOverlap: 0,
|
|
289
|
+
topKDelta: hitsFound,
|
|
290
|
+
noOp: false,
|
|
291
|
+
regressionRisk: hitsFound > 5 ? "low" : "none",
|
|
292
|
+
reasons: ["report-only: contribution measured, no ranking change"],
|
|
293
|
+
status: "report_only",
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// ── Hybrid-safe promotion (diagnostic only) ─────────────────────────
|
|
297
|
+
var ALLOWED_GUARDS = ["deterministic_anchor_overlap", "missing_slot_recovery", "strong_path_evidence"];
|
|
298
|
+
var BLOCKING_GUARDS = ["avoid_or_noise_block", "semantic_unavailable_block", "report_only_guard"];
|
|
299
|
+
function buildHybridPromotionReport(semanticEnabled, providerReady, hits, deterministicAnchors, missingSlots) {
|
|
300
|
+
var guardExplanations = {};
|
|
301
|
+
var promoted = [];
|
|
302
|
+
var blocked = [];
|
|
303
|
+
if (!semanticEnabled || !providerReady) {
|
|
304
|
+
guardExplanations["semantic_unavailable_block"] = "semantic is disabled or provider unavailable";
|
|
305
|
+
guardExplanations["report_only_guard"] = "promotion is report-only in Sprint 18D";
|
|
306
|
+
var guardResults = [];
|
|
307
|
+
BLOCKING_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: g }); });
|
|
308
|
+
ALLOWED_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: "semantic unavailable" }); });
|
|
309
|
+
return {
|
|
310
|
+
totalDiscovered: 0, promotedCandidates: 0, blockedCandidates: 0,
|
|
311
|
+
guardExplanations, guardResults, promoted, blocked,
|
|
312
|
+
promotionReasons: [], blockReasons: ["semantic_unavailable_block"],
|
|
313
|
+
mode: "disabled", safeForDefaultRanking: false,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
var anchorSet = {};
|
|
317
|
+
for (var a = 0; a < deterministicAnchors.length; a++)
|
|
318
|
+
anchorSet[deterministicAnchors[a]] = true;
|
|
319
|
+
var slotSet = {};
|
|
320
|
+
for (var ms = 0; ms < missingSlots.length; ms++)
|
|
321
|
+
slotSet[missingSlots[ms]] = true;
|
|
322
|
+
for (var hi = 0; hi < hits.length; hi++) {
|
|
323
|
+
var hit = hits[hi];
|
|
324
|
+
var canPromote = false;
|
|
325
|
+
var reason = "";
|
|
326
|
+
// Check deterministic anchor overlap
|
|
327
|
+
if (anchorSet[hit.filePath]) {
|
|
328
|
+
canPromote = true;
|
|
329
|
+
reason = "deterministic_anchor_overlap";
|
|
330
|
+
}
|
|
331
|
+
// Check missing slot recovery
|
|
332
|
+
else if (slotSet[hit.slot]) {
|
|
333
|
+
canPromote = true;
|
|
334
|
+
reason = "missing_slot_recovery";
|
|
335
|
+
}
|
|
336
|
+
// Check strong path evidence
|
|
337
|
+
else if (hit.similarity > 0.7) {
|
|
338
|
+
canPromote = true;
|
|
339
|
+
reason = "strong_path_evidence";
|
|
340
|
+
}
|
|
341
|
+
// Block with explanation
|
|
342
|
+
else {
|
|
343
|
+
reason = "avoid_or_noise_block";
|
|
344
|
+
}
|
|
345
|
+
if (canPromote) {
|
|
346
|
+
promoted.push({ filePath: hit.filePath, reason: reason });
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
blocked.push({ filePath: hit.filePath, reason: reason });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
guardExplanations["report_only_guard"] = "promotion is report-only in Sprint 18D; ranking unchanged";
|
|
353
|
+
ALLOWED_GUARDS.forEach(function (g) { guardExplanations[g] = "allowed: " + g; });
|
|
354
|
+
BLOCKING_GUARDS.forEach(function (g) { guardExplanations[g] = g; });
|
|
355
|
+
var guardResults = [];
|
|
356
|
+
BLOCKING_GUARDS.forEach(function (g) { guardResults.push({ guard: g, passed: false, reason: g }); });
|
|
357
|
+
ALLOWED_GUARDS.forEach(function (g) {
|
|
358
|
+
var p = promoted.some(function (p) { return p.reason === g; });
|
|
359
|
+
guardResults.push({ guard: g, passed: p, reason: p ? g + " matched " + promoted.filter(function (x) { return x.reason === g; }).length + " candidate(s)" : "no " + g + " candidates found" });
|
|
360
|
+
});
|
|
361
|
+
var promotionReasons = promoted.map(function (p) { return p.reason; }).filter(function (r, i, arr) { return arr.indexOf(r) === i; });
|
|
362
|
+
var blockReasons = blocked.map(function (b) { return b.reason; }).filter(function (r, i, arr) { return arr.indexOf(r) === i; });
|
|
363
|
+
return {
|
|
364
|
+
totalDiscovered: hits.length,
|
|
365
|
+
promotedCandidates: promoted.length,
|
|
366
|
+
blockedCandidates: blocked.length,
|
|
367
|
+
guardExplanations: guardExplanations,
|
|
368
|
+
guardResults: guardResults,
|
|
369
|
+
promoted: promoted,
|
|
370
|
+
blocked: blocked,
|
|
371
|
+
promotionReasons: promotionReasons,
|
|
372
|
+
blockReasons: blockReasons,
|
|
373
|
+
mode: "report_only",
|
|
374
|
+
safeForDefaultRanking: false,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function cosineSimilarity(a, b) {
|
|
378
|
+
let dot = 0, normA = 0, normB = 0;
|
|
379
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
380
|
+
dot += a[i] * b[i];
|
|
381
|
+
normA += a[i] * a[i];
|
|
382
|
+
normB += b[i] * b[i];
|
|
383
|
+
}
|
|
384
|
+
if (normA === 0 || normB === 0)
|
|
385
|
+
return 0;
|
|
386
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=semanticChunkIndex.js.map
|