@futdevpro/fdp-agent-memory 1.1.130 → 1.1.134
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/build/package.json +1 -1
- package/build/src/_collections/config-catalog.const.js +12 -0
- package/build/src/_collections/error-codes.const.js +2 -0
- package/build/src/_collections/fam-db-models.const.js +2 -0
- package/build/src/_collections/fam-error-context.util.js +1 -0
- package/build/src/_models/data-models/fam-dup-audit.data-model.js +72 -0
- package/build/src/_modules/embedding/_collections/fam-dup-file-rollup.util.js +48 -0
- package/build/src/_modules/embedding/_collections/fam-dup-fork-pair.util.js +86 -0
- package/build/src/_modules/embedding/_services/fam-dup-audit-scheduler.control-service.js +140 -0
- package/build/src/_modules/embedding/_services/fam-dup-audit.control-service.js +141 -0
- package/build/src/_modules/embedding/_services/fam-dup-audit.data-service.js +66 -0
- package/build/src/_modules/embedding/_services/fam-dup-coverage.control-service.js +123 -0
- package/build/src/_modules/embedding/_services/fam-duplicate-scan.control-service.js +63 -10
- package/build/src/_modules/embedding/_services/fam-embedding-bootstrap.control-service.js +9 -0
- package/build/src/_modules/embedding/_services/fam-exact-duplication.control-service.js +309 -0
- package/build/src/_modules/embedding/index.js +16 -1
- package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +67 -0
- package/build/src/_modules/retrieval/_collections/fam-rule-propagation.util.js +1 -1
- package/build/src/app.server.js +52 -0
- package/client-dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_DupCoverage_ControlService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
|
|
6
|
+
const fam_table_type_enum_1 = require("../../../_enums/fam-table.type-enum");
|
|
7
|
+
const fam_scope_data_service_1 = require("../../scope-reference/_services/fam-scope.data-service");
|
|
8
|
+
const fam_store_registry_const_1 = require("../_collections/fam-store-registry.const");
|
|
9
|
+
const fam_entry_data_service_1 = require("./fam-entry.data-service");
|
|
10
|
+
/**
|
|
11
|
+
* `FAM_DupCoverage_ControlService` (dup-v2, task #20) — a duplikáció-mérés **lefedettség-preflight**-je. A
|
|
12
|
+
* dup-eredmény csak akkor értelmezhető flotta-szinten, ha tudjuk, MELY projektek korpusza hiányzik (0 entry)
|
|
13
|
+
* vagy elavult (régen szkennelt) — különben a „nincs duplikáció X-szel" néma hamis-negatív. A riport a scope-fa
|
|
14
|
+
* project-layer listáját veti össze a tár per-projekt entry-számával + a legfrissebb entry korával. Read-only.
|
|
15
|
+
*/
|
|
16
|
+
class FAM_DupCoverage_ControlService {
|
|
17
|
+
static _instance;
|
|
18
|
+
issuer = 'FAM_DupCoverage_ControlService';
|
|
19
|
+
/** Az elavultság-küszöb napban: a heti re-scan (7 nap) + 1 nap türelem. */
|
|
20
|
+
static STALE_WARN_DAYS = 8;
|
|
21
|
+
static getInstance() {
|
|
22
|
+
if (!FAM_DupCoverage_ControlService._instance) {
|
|
23
|
+
FAM_DupCoverage_ControlService._instance = new FAM_DupCoverage_ControlService();
|
|
24
|
+
}
|
|
25
|
+
return FAM_DupCoverage_ControlService._instance;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A lefedettség-riport egy tárra (default `codebase`). A scope-fa project-layer listája + egy per-projekt
|
|
29
|
+
* `$group` aggregáció (aktív entry-szám + max lastModified), majd a PURE `joinCoverage` join. Üres tár /
|
|
30
|
+
* üres scope-fa → deskriptív riport (nem dob).
|
|
31
|
+
*/
|
|
32
|
+
async report(table = fam_table_type_enum_1.FAM_Table.codebase) {
|
|
33
|
+
const registryEntry = fam_store_registry_const_1.FAM_StoreRegistry_Util.getEntry(table);
|
|
34
|
+
// A scope-fa project-layer canonical nevei (a „mit KELLENE lefedni" referencia-lista).
|
|
35
|
+
const scope_DS = new fam_scope_data_service_1.FAM_Scope_DataService({ issuer: this.issuer });
|
|
36
|
+
const scopes = await scope_DS.findAllActive();
|
|
37
|
+
const projectNames = [...new Set(scopes
|
|
38
|
+
.filter((scope) => scope.layer === 'project' && scope.canonicalName)
|
|
39
|
+
.map((scope) => scope.canonicalName))].sort();
|
|
40
|
+
// Per-projekt aggregáció a RAW collection-ön (aktív = `_deleted:null`; a lastModified a `__lastModified`
|
|
41
|
+
// vagy fallback a `__created`). A contentVector SOHA nem kerül a pipeline-ba (memória-védelem).
|
|
42
|
+
let rows = [];
|
|
43
|
+
if (registryEntry) {
|
|
44
|
+
const collection = this.entryCollection(registryEntry);
|
|
45
|
+
rows = await collection.aggregate([
|
|
46
|
+
{ $match: { _deleted: null } },
|
|
47
|
+
{
|
|
48
|
+
$project: {
|
|
49
|
+
project: {
|
|
50
|
+
$arrayElemAt: [{
|
|
51
|
+
$map: {
|
|
52
|
+
input: {
|
|
53
|
+
$filter: {
|
|
54
|
+
input: { $ifNull: ['$scopePath', []] },
|
|
55
|
+
as: 'ref',
|
|
56
|
+
cond: { $eq: ['$$ref.layer', 'project'] },
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
as: 'ref',
|
|
60
|
+
in: '$$ref.canonicalName',
|
|
61
|
+
},
|
|
62
|
+
}, 0],
|
|
63
|
+
},
|
|
64
|
+
lm: { $ifNull: ['$__lastModified', '$__created'] },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{ $group: { _id: '$project', entryCount: { $sum: 1 }, lastModified: { $max: '$lm' } } },
|
|
68
|
+
], { allowDiskUse: true }).toArray();
|
|
69
|
+
}
|
|
70
|
+
return FAM_DupCoverage_ControlService.joinCoverage({
|
|
71
|
+
table: table, projectNames: projectNames, rows: rows, nowMs: Date.now(),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* **PURE** join: a scope-fa projekt-listája × a per-projekt aggregáció-sorok → lefedettség-riport
|
|
76
|
+
* (zero-entry + stale jelzésekkel + warnings). Determinista → unit-tesztelhető DB nélkül.
|
|
77
|
+
*/
|
|
78
|
+
static joinCoverage(set) {
|
|
79
|
+
const staleThresholdMs = FAM_DupCoverage_ControlService.STALE_WARN_DAYS * 24 * 3600000;
|
|
80
|
+
const byProject = new Map();
|
|
81
|
+
for (const row of set.rows) {
|
|
82
|
+
if (row._id) {
|
|
83
|
+
byProject.set(row._id, row);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const projects = set.projectNames.map((project) => {
|
|
87
|
+
const row = byProject.get(project);
|
|
88
|
+
const lastModifiedMs = row?.lastModified ? new Date(row.lastModified).getTime() : 0;
|
|
89
|
+
return {
|
|
90
|
+
project: project,
|
|
91
|
+
entryCount: row?.entryCount ?? 0,
|
|
92
|
+
lastModifiedMs: lastModifiedMs,
|
|
93
|
+
stale: Boolean(row?.entryCount) && (set.nowMs - lastModifiedMs) > staleThresholdMs,
|
|
94
|
+
};
|
|
95
|
+
}).sort((left, right) => right.entryCount - left.entryCount || left.project.localeCompare(right.project));
|
|
96
|
+
const zeroEntryProjects = projects.filter((row) => !row.entryCount).map((row) => row.project);
|
|
97
|
+
const staleProjects = projects.filter((row) => row.stale).map((row) => row.project);
|
|
98
|
+
const warnings = [];
|
|
99
|
+
if (zeroEntryProjects.length) {
|
|
100
|
+
warnings.push(`${zeroEntryProjects.length} projekt 0 entry-vel a '${set.table}' tárban — ezek a dup-mérésből `
|
|
101
|
+
+ `NÉMÁN kimaradnak (futtass scant): ${zeroEntryProjects.join(', ')}`);
|
|
102
|
+
}
|
|
103
|
+
if (staleProjects.length) {
|
|
104
|
+
warnings.push(`${staleProjects.length} projekt korpusza elavult (> ${FAM_DupCoverage_ControlService.STALE_WARN_DAYS} `
|
|
105
|
+
+ `nap): ${staleProjects.join(', ')}`);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
table: set.table,
|
|
109
|
+
generatedAt: set.nowMs,
|
|
110
|
+
projectsTotal: set.projectNames.length,
|
|
111
|
+
zeroEntryProjects: zeroEntryProjects,
|
|
112
|
+
staleProjects: staleProjects,
|
|
113
|
+
projects: projects,
|
|
114
|
+
warnings: warnings,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/** Egy fő RAG-tár mongoose-collection-je (a DS-példányosítás regisztrálja a modellt; onnan a valós collection). */
|
|
118
|
+
entryCollection(registryEntry) {
|
|
119
|
+
new fam_entry_data_service_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: this.issuer });
|
|
120
|
+
return mongoose_1.default.models[registryEntry.dataParams.dataName].collection;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.FAM_DupCoverage_ControlService = FAM_DupCoverage_ControlService;
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FAM_DuplicateScan_ControlService = void 0;
|
|
4
4
|
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
|
+
const fam_dup_fork_pair_util_1 = require("../_collections/fam-dup-fork-pair.util");
|
|
6
|
+
const fam_dup_file_rollup_util_1 = require("../_collections/fam-dup-file-rollup.util");
|
|
5
7
|
const fam_store_registry_const_1 = require("../_collections/fam-store-registry.const");
|
|
8
|
+
const fam_dup_coverage_control_service_1 = require("./fam-dup-coverage.control-service");
|
|
6
9
|
const fam_entry_data_service_1 = require("./fam-entry.data-service");
|
|
7
10
|
const fam_vector_search_control_service_1 = require("./fam-vector-search.control-service");
|
|
8
11
|
/**
|
|
@@ -44,12 +47,15 @@ class FAM_DuplicateScan_ControlService {
|
|
|
44
47
|
const search = fam_vector_search_control_service_1.FAM_VectorSearch_ControlService.getInstance();
|
|
45
48
|
const totalInPool = registryEntry ? search.getPoolSize(input.table) : 0;
|
|
46
49
|
const filtered = FAM_DuplicateScan_ControlService.hasCandidateFilter(input);
|
|
47
|
-
const empty = {
|
|
48
|
-
table: input.table, threshold: threshold, totalInPool: totalInPool, scanned: 0,
|
|
49
|
-
capped: false, filtered: filtered, clusterCount: 0, duplicateEntryCount: 0, clusters: [],
|
|
50
|
-
};
|
|
51
50
|
if (!registryEntry || !totalInPool) {
|
|
52
|
-
|
|
51
|
+
// Üres pool → üres eredmény, DE a coverage-preflight ITT IS beágyazva (a „miért üres?" — pl. 0-entry
|
|
52
|
+
// projektek — ne legyen néma; dup-v2 edge-case).
|
|
53
|
+
return {
|
|
54
|
+
table: input.table, threshold: threshold, totalInPool: totalInPool, scanned: 0,
|
|
55
|
+
capped: false, filtered: filtered, clusterCount: 0, duplicateEntryCount: 0, clusters: [],
|
|
56
|
+
fileRollup: [], forkPairs: { pairs: [], suspectedForkCount: 0 }, suppressedClusters: 0,
|
|
57
|
+
coverage: registryEntry ? await this.maybeCoverage(input) : undefined,
|
|
58
|
+
};
|
|
53
59
|
}
|
|
54
60
|
// 1. A (capolt) (id, vektor) halmaz lean-streamelése (NEM a teljes content — csak a vektorok).
|
|
55
61
|
// A szűrő-mezők Mongo-prefilterként MÁR ITT szűkítik a jelölt-halmazt (célzott scan a nagy táron).
|
|
@@ -95,7 +101,7 @@ class FAM_DuplicateScan_ControlService {
|
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
const metaById = await this.fetchMeta(dataService, clusteredIds);
|
|
98
|
-
// 5. Cluster-ek építése (tag-dúsítás + projekt-lefedettség) + a `minProjects` cross-project szűrő +
|
|
104
|
+
// 5. Cluster-ek építése (tag-dúsítás + projekt-/repo-lefedettség) + a `minProjects` cross-project szűrő +
|
|
99
105
|
// rendezés (legszélesebb projekt-lefedettség, majd méret, majd score elöl) + output-cap.
|
|
100
106
|
const minProjects = input.minProjects ?? 0;
|
|
101
107
|
const clusters = components
|
|
@@ -106,6 +112,7 @@ class FAM_DuplicateScan_ControlService {
|
|
|
106
112
|
snippet: metaById.get(id)?.snippet,
|
|
107
113
|
sourceFilePath: metaById.get(id)?.sourceFilePath,
|
|
108
114
|
project: metaById.get(id)?.project,
|
|
115
|
+
repoName: metaById.get(id)?.repoName,
|
|
109
116
|
}));
|
|
110
117
|
const projects = FAM_DuplicateScan_ControlService.distinctProjects(members);
|
|
111
118
|
return {
|
|
@@ -114,6 +121,7 @@ class FAM_DuplicateScan_ControlService {
|
|
|
114
121
|
minScore: component.minScore,
|
|
115
122
|
projects: projects,
|
|
116
123
|
projectCount: projects.length,
|
|
124
|
+
repoNames: FAM_DuplicateScan_ControlService.distinctRepoNames(members),
|
|
117
125
|
members: members,
|
|
118
126
|
};
|
|
119
127
|
})
|
|
@@ -121,7 +129,24 @@ class FAM_DuplicateScan_ControlService {
|
|
|
121
129
|
.sort((left, right) => right.projectCount - left.projectCount
|
|
122
130
|
|| right.size - left.size
|
|
123
131
|
|| right.maxScore - left.maxScore);
|
|
124
|
-
|
|
132
|
+
// 6. Fork-pár statisztika (dup-v2): a súly itt a cluster-MÉRET (a near-scannek nincs wasted-char fogalma —
|
|
133
|
+
// a `wastedShare` így méret-részarány; a JSDoc-olt szemantika a FAM_DupForkPair_Util-ban). Opt-in
|
|
134
|
+
// szuppresszió: CSAK a kimeneti cluster-listát szűri (a felderítés ténye nem vész el — `suppressedClusters`).
|
|
135
|
+
const forkRows = clusters.map((cluster) => ({
|
|
136
|
+
projects: cluster.projects, wasted: cluster.size, repoNames: cluster.repoNames,
|
|
137
|
+
}));
|
|
138
|
+
const totalWeight = clusters.reduce((sum, cluster) => sum + cluster.size, 0);
|
|
139
|
+
const forkPairs = fam_dup_fork_pair_util_1.FAM_DupForkPair_Util.buildReport(forkRows, totalWeight);
|
|
140
|
+
let finalClusters = clusters;
|
|
141
|
+
let suppressedClusters = 0;
|
|
142
|
+
if (input.suppressForkPairs) {
|
|
143
|
+
const suspected = forkPairs.pairs.filter((pair) => pair.suspectedFork);
|
|
144
|
+
finalClusters = clusters.filter((cluster) => !fam_dup_fork_pair_util_1.FAM_DupForkPair_Util.shouldSuppress({ projects: cluster.projects, repoNames: cluster.repoNames }, suspected));
|
|
145
|
+
suppressedClusters = clusters.length - finalClusters.length;
|
|
146
|
+
}
|
|
147
|
+
const duplicateEntryCount = finalClusters.reduce((sum, cluster) => sum + cluster.size, 0);
|
|
148
|
+
// 7. Output-cap + fájl-rollup a CAP-ELT (visszaadott) clusterekből (a clusterRefs indexei konzisztensek).
|
|
149
|
+
const cappedClusters = finalClusters.slice(0, maxClusters);
|
|
125
150
|
return {
|
|
126
151
|
table: input.table,
|
|
127
152
|
threshold: threshold,
|
|
@@ -129,15 +154,33 @@ class FAM_DuplicateScan_ControlService {
|
|
|
129
154
|
scanned: scanned,
|
|
130
155
|
capped: capped,
|
|
131
156
|
filtered: filtered,
|
|
132
|
-
clusterCount:
|
|
157
|
+
clusterCount: finalClusters.length,
|
|
133
158
|
duplicateEntryCount: duplicateEntryCount,
|
|
134
|
-
clusters:
|
|
159
|
+
clusters: cappedClusters,
|
|
160
|
+
fileRollup: fam_dup_file_rollup_util_1.FAM_DupFileRollup_Util.build(cappedClusters),
|
|
161
|
+
forkPairs: forkPairs,
|
|
162
|
+
suppressedClusters: suppressedClusters,
|
|
163
|
+
coverage: await this.maybeCoverage(input),
|
|
135
164
|
};
|
|
136
165
|
}
|
|
166
|
+
/** A coverage-preflight beágyazása (`includeCoverage !== false`); a coverage-hiba NEM dönti a scant (best-effort). */
|
|
167
|
+
async maybeCoverage(input) {
|
|
168
|
+
if (input.includeCoverage === false) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
return await fam_dup_coverage_control_service_1.FAM_DupCoverage_ControlService.getInstance().report(input.table);
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
fsm_dynamo_1.DyFM_Log.warn(`[FAM dup-scan] coverage-preflight sikertelen (best-effort): ${error?.message}`);
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
137
179
|
/** Van-e AKTÍV jelölt-szűrő az inputban (→ Mongo-prefilter + candidateIds-szűkített keresés)? Tiszta. */
|
|
138
180
|
static hasCandidateFilter(input) {
|
|
139
181
|
return Boolean(input.pathRegex || input.excludePathRegex || input.excludeRootRegex
|
|
140
|
-
|| input.projects?.length || input.excludeProjects?.length
|
|
182
|
+
|| input.projects?.length || input.excludeProjects?.length
|
|
183
|
+
|| (input.minContentLength ?? 0) > 0);
|
|
141
184
|
}
|
|
142
185
|
/**
|
|
143
186
|
* A jelölt-halmaz Mongo-prefilterének összeállítása az input szűrő-mezőiből. Tiszta (side-effect-mentes) →
|
|
@@ -160,6 +203,11 @@ class FAM_DuplicateScan_ControlService {
|
|
|
160
203
|
if (input.excludeProjects?.length) {
|
|
161
204
|
conditions.push({ scopePath: { $not: { $elemMatch: { layer: 'project', canonicalName: { $in: input.excludeProjects } } } } });
|
|
162
205
|
}
|
|
206
|
+
if ((input.minContentLength ?? 0) > 0) {
|
|
207
|
+
// Rövid boilerplate-zaj kizárása MÁR a prefilterben (dup-v2): a content karakter-hossza (`$strLenCP`)
|
|
208
|
+
// legalább `minContentLength` legyen (hiányzó content → 0 hossz → kiesik).
|
|
209
|
+
conditions.push({ $expr: { $gte: [{ $strLenCP: { $ifNull: ['$content', ''] } }, input.minContentLength] } });
|
|
210
|
+
}
|
|
163
211
|
return (conditions.length === 1 ? conditions[0] : { $and: conditions });
|
|
164
212
|
}
|
|
165
213
|
/** Egy entry projekt-neve a scopePath project-layer eleméből (nincs → undefined). Tiszta. */
|
|
@@ -170,6 +218,10 @@ class FAM_DuplicateScan_ControlService {
|
|
|
170
218
|
static distinctProjects(members) {
|
|
171
219
|
return [...new Set(members.map((member) => member.project).filter((project) => Boolean(project)))].sort();
|
|
172
220
|
}
|
|
221
|
+
/** A cluster-tagok KÜLÖNBÖZŐ (nem-üres) repo-nevei rendezve (fork-pár evidencia — dup-v2). Tiszta. */
|
|
222
|
+
static distinctRepoNames(members) {
|
|
223
|
+
return [...new Set(members.map((member) => member.repoName).filter((repo) => Boolean(repo)))].sort();
|
|
224
|
+
}
|
|
173
225
|
/**
|
|
174
226
|
* **Tiszta union-find**: a hasonlóság-élekből összefüggő komponensek (méret ≥ 2). Minden komponens id-i
|
|
175
227
|
* rendezve + a komponens score-tartománya (min/max él-score). Determinista (azonos input → azonos output).
|
|
@@ -252,6 +304,7 @@ class FAM_DuplicateScan_ControlService {
|
|
|
252
304
|
snippet: content.replace(/\s+/g, ' ').trim().slice(0, FAM_DuplicateScan_ControlService.SNIPPET_LENGTH),
|
|
253
305
|
sourceFilePath: entry.sourceFilePath,
|
|
254
306
|
project: FAM_DuplicateScan_ControlService.projectOf(entry.scopePath),
|
|
307
|
+
repoName: entry.source?.repoName,
|
|
255
308
|
});
|
|
256
309
|
}
|
|
257
310
|
return metaById;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FAM_EmbeddingBootstrap_ControlService = void 0;
|
|
4
4
|
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
5
|
const config_control_service_1 = require("../../../_routes/server/config/config.control-service");
|
|
6
|
+
const fam_dup_audit_scheduler_control_service_1 = require("./fam-dup-audit-scheduler.control-service");
|
|
6
7
|
const fam_hydration_coordinator_control_service_1 = require("./fam-hydration-coordinator.control-service");
|
|
7
8
|
const fam_vector_search_control_service_1 = require("./fam-vector-search.control-service");
|
|
8
9
|
const fam_scope_maintenance_control_service_1 = require("../../scope-reference/_services/fam-scope-maintenance.control-service");
|
|
@@ -56,6 +57,14 @@ class FAM_EmbeddingBootstrap_ControlService {
|
|
|
56
57
|
catch (error) {
|
|
57
58
|
fsm_dynamo_1.DyFM_Log.warn(`[FAM bootstrap] heti re-scan scheduler telepítése sikertelen: ${error?.message}`);
|
|
58
59
|
}
|
|
60
|
+
// HETI DUP-ŐRJÁRAT (dup-v2, task #20): a scheduler telepítése UGYANITT, a hydrateAll await ELŐTT (boot-timer
|
|
61
|
+
// TILOS await mögé!) — a tick maga kapuzza magát (a heti re-scan lefutása + single-flight + enabled-flag).
|
|
62
|
+
try {
|
|
63
|
+
fam_dup_audit_scheduler_control_service_1.FAM_DupAuditScheduler_ControlService.getInstance().install();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
fsm_dynamo_1.DyFM_Log.warn(`[FAM bootstrap] dup-őrjárat scheduler telepítése sikertelen: ${error?.message}`);
|
|
67
|
+
}
|
|
59
68
|
// A readiness-coordinator hidratálás-bevárás time-outja a `read.hydrationWaitMs` config-ból (a hidratálás
|
|
60
69
|
// ELŐTT, hogy a `beginBoot` után érkező read-ek már a helyes időkorláttal várjanak). Best-effort (default 180s).
|
|
61
70
|
try {
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_ExactDuplication_ControlService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
|
|
6
|
+
const error_codes_const_1 = require("../../../_collections/error-codes.const");
|
|
7
|
+
const fam_error_factory_util_1 = require("../../../_collections/fam-error-factory.util");
|
|
8
|
+
const fam_table_type_enum_1 = require("../../../_enums/fam-table.type-enum");
|
|
9
|
+
const fam_dup_fork_pair_util_1 = require("../_collections/fam-dup-fork-pair.util");
|
|
10
|
+
const fam_store_registry_const_1 = require("../_collections/fam-store-registry.const");
|
|
11
|
+
const fam_dup_coverage_control_service_1 = require("./fam-dup-coverage.control-service");
|
|
12
|
+
const fam_duplicate_scan_control_service_1 = require("./fam-duplicate-scan.control-service");
|
|
13
|
+
const fam_entry_data_service_1 = require("./fam-entry.data-service");
|
|
14
|
+
/**
|
|
15
|
+
* `FAM_ExactDuplication_ControlService` (dup-v2, task #20) — **EXACT (contentHash-azonos) duplikáció-mérő**
|
|
16
|
+
* capability-motor. A near-dup scannel (`FAM_DuplicateScan_ControlService`) szemben NEM vektor-alapú: egyetlen
|
|
17
|
+
* Mongo-aggregáció (`$group` by contentHash) a TELJES szűrt halmazon → a 300k-s codebase táron is fut, cap
|
|
18
|
+
* nélkül, memória-robbanás nélkül (`allowDiskUse` + korai `$project`; a `contentVector` SOSEM kerül a
|
|
19
|
+
* pipeline-ba). Read-only — csak felderít, nem töröl.
|
|
20
|
+
*
|
|
21
|
+
* **Szűrő-konzisztencia:** a user-szűrők (path/root/projekt) a near-dup `buildScanFilter`-rel AZONOS feltételek
|
|
22
|
+
* (REUSE — a két capability ugyanazt a halmazt érti a szűrő alatt, beleértve az `embeddingStatus:'completed'`
|
|
23
|
+
* feltételt is: a mért korpusz = a retrieval-képes korpusz).
|
|
24
|
+
*
|
|
25
|
+
* **16MB-jegyzet (`$addToSet files`):** egy csoport fájl-listája elvileg nőhet nagyra, de a reális eloszlásnál
|
|
26
|
+
* (egy hash tipikusan < pár száz fájl) a 16MB dokumentum-limit messze van; a top-ágon a `$slice` cap-el, a
|
|
27
|
+
* pairSource/multiProject ág nem viszi a `files`-t.
|
|
28
|
+
*/
|
|
29
|
+
class FAM_ExactDuplication_ControlService {
|
|
30
|
+
static _instance;
|
|
31
|
+
issuer = 'FAM_ExactDuplication_ControlService';
|
|
32
|
+
/** Default visszaadott csoport-szám. */
|
|
33
|
+
static DEFAULT_MAX_GROUPS = 100;
|
|
34
|
+
/** A visszaadott csoport-szám hard cap-je (context-védelem). */
|
|
35
|
+
static HARD_MAX_GROUPS = 500;
|
|
36
|
+
/** Default per-csoport fájl-cap. */
|
|
37
|
+
static DEFAULT_MAX_FILES_PER_GROUP = 20;
|
|
38
|
+
/** A pár-forrás facet sor-cap-je (a pár-statisztika bounded marad extrém dup-eloszlásnál is). */
|
|
39
|
+
static PAIR_SOURCE_LIMIT = 50000;
|
|
40
|
+
static getInstance() {
|
|
41
|
+
if (!FAM_ExactDuplication_ControlService._instance) {
|
|
42
|
+
FAM_ExactDuplication_ControlService._instance = new FAM_ExactDuplication_ControlService();
|
|
43
|
+
}
|
|
44
|
+
return FAM_ExactDuplication_ControlService._instance;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Az exact dup-mérés futtatása (read-only). Üres tábla / 0 csoport → 0-default totals (nem dob).
|
|
48
|
+
* Érvénytelen user-regex → deskriptív FAM_Error (nem Mongo-mélyhiba).
|
|
49
|
+
*/
|
|
50
|
+
async run(input) {
|
|
51
|
+
const normalized = FAM_ExactDuplication_ControlService.normalize(input);
|
|
52
|
+
this.assertValidRegexes(normalized);
|
|
53
|
+
const registryEntry = fam_store_registry_const_1.FAM_StoreRegistry_Util.getEntry(normalized.table);
|
|
54
|
+
if (!registryEntry) {
|
|
55
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
56
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.mcpDispatchUnknownCapability,
|
|
57
|
+
message: `A 'detect_exact_duplication' csak fő RAG-táron fut — a(z) '${normalized.table}' nem az `
|
|
58
|
+
+ '(a `reference` helper nem vektorizált fő tár).',
|
|
59
|
+
issuer: this.issuer,
|
|
60
|
+
context: { operation: 'capability-invoke:detect_exact_duplication' },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// Egyetlen aggregáció a RAW collection-ön (allowDiskUse a nagy $group/$sort miatt).
|
|
64
|
+
const collection = this.entryCollection(registryEntry);
|
|
65
|
+
const pipeline = FAM_ExactDuplication_ControlService.buildPipeline(normalized);
|
|
66
|
+
const facetRows = await collection
|
|
67
|
+
.aggregate(pipeline, { allowDiskUse: true }).toArray();
|
|
68
|
+
// Coverage-preflight beágyazás (a hiányzó/elavult projekt-korpusz NE legyen néma hamis-negatív).
|
|
69
|
+
const coverage = normalized.includeCoverage
|
|
70
|
+
? await fam_dup_coverage_control_service_1.FAM_DupCoverage_ControlService.getInstance().report(normalized.table)
|
|
71
|
+
: undefined;
|
|
72
|
+
return FAM_ExactDuplication_ControlService.toResult(facetRows[0], normalized, coverage);
|
|
73
|
+
}
|
|
74
|
+
/** A nyers input default-olása + cap-elése. Tiszta. */
|
|
75
|
+
static normalize(input) {
|
|
76
|
+
const maxGroups = Math.min(Math.max(input.maxGroups ?? FAM_ExactDuplication_ControlService.DEFAULT_MAX_GROUPS, 1), FAM_ExactDuplication_ControlService.HARD_MAX_GROUPS);
|
|
77
|
+
return {
|
|
78
|
+
table: input.table ?? fam_table_type_enum_1.FAM_Table.codebase,
|
|
79
|
+
pathRegex: input.pathRegex,
|
|
80
|
+
excludePathRegex: input.excludePathRegex,
|
|
81
|
+
excludeRootRegex: input.excludeRootRegex,
|
|
82
|
+
projects: input.projects?.length ? input.projects : undefined,
|
|
83
|
+
excludeProjects: input.excludeProjects?.length ? input.excludeProjects : undefined,
|
|
84
|
+
minProjects: Math.max(input.minProjects ?? 1, 0),
|
|
85
|
+
minContentLength: Math.max(input.minContentLength ?? 0, 0),
|
|
86
|
+
maxGroups: maxGroups,
|
|
87
|
+
maxFilesPerGroup: Math.max(input.maxFilesPerGroup ?? FAM_ExactDuplication_ControlService.DEFAULT_MAX_FILES_PER_GROUP, 1),
|
|
88
|
+
suppressForkPairs: input.suppressForkPairs === true,
|
|
89
|
+
includeCoverage: input.includeCoverage !== false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* A `$match` stage összeállítása: explicit `_deleted:null` (raw-path aktív-szűrő) + `contentHash` string +
|
|
94
|
+
* a near-dup `buildScanFilter`-rel AZONOS user-szűrő feltételek (REUSE) + opcionális `$strLenCP` hossz-kapu.
|
|
95
|
+
* Tiszta.
|
|
96
|
+
*/
|
|
97
|
+
static buildMatchStage(input) {
|
|
98
|
+
const conditions = [
|
|
99
|
+
// RAW collection-t olvasunk (nem a Dynamo DataService-t) → a soft-delete kizárás EXPLICIT kötelező.
|
|
100
|
+
{ _deleted: null },
|
|
101
|
+
{ contentHash: { $type: 'string', $ne: '' } },
|
|
102
|
+
];
|
|
103
|
+
// A user-szűrők a near-dup scan-nel AZONOS feltétel-készletből (REUSE — nincs drift a két capability közt).
|
|
104
|
+
const scanFilter = fam_duplicate_scan_control_service_1.FAM_DuplicateScan_ControlService.buildScanFilter({
|
|
105
|
+
table: input.table,
|
|
106
|
+
pathRegex: input.pathRegex,
|
|
107
|
+
excludePathRegex: input.excludePathRegex,
|
|
108
|
+
excludeRootRegex: input.excludeRootRegex,
|
|
109
|
+
projects: input.projects,
|
|
110
|
+
excludeProjects: input.excludeProjects,
|
|
111
|
+
});
|
|
112
|
+
const scanConditions = Array.isArray(scanFilter.$and)
|
|
113
|
+
? scanFilter.$and
|
|
114
|
+
: [scanFilter];
|
|
115
|
+
conditions.push(...scanConditions);
|
|
116
|
+
if (input.minContentLength > 0) {
|
|
117
|
+
conditions.push({ $expr: { $gte: [{ $strLenCP: { $ifNull: ['$content', ''] } }, input.minContentLength] } });
|
|
118
|
+
}
|
|
119
|
+
return { $and: conditions };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A teljes aggregáció-pipeline (korai `$project` — a `contentVector` és a `content` szöveg NEM utazik a
|
|
123
|
+
* `$group`-ba, csak a hossz) + `$facet` a 4 kimeneti ággal (totals / top / pairSource / multiProject). Tiszta.
|
|
124
|
+
*/
|
|
125
|
+
static buildPipeline(input) {
|
|
126
|
+
return [
|
|
127
|
+
{ $match: FAM_ExactDuplication_ControlService.buildMatchStage(input) },
|
|
128
|
+
// Korai projekció: csak a csoportosításhoz szükséges skalárok (hossz + projekt + repo + fájl-út).
|
|
129
|
+
{
|
|
130
|
+
$project: {
|
|
131
|
+
contentHash: 1,
|
|
132
|
+
sourceFilePath: 1,
|
|
133
|
+
len: { $strLenCP: { $ifNull: ['$content', ''] } },
|
|
134
|
+
project: {
|
|
135
|
+
$arrayElemAt: [{
|
|
136
|
+
$map: {
|
|
137
|
+
input: {
|
|
138
|
+
$filter: {
|
|
139
|
+
input: { $ifNull: ['$scopePath', []] },
|
|
140
|
+
as: 'ref',
|
|
141
|
+
cond: { $eq: ['$$ref.layer', 'project'] },
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
as: 'ref',
|
|
145
|
+
in: '$$ref.canonicalName',
|
|
146
|
+
},
|
|
147
|
+
}, 0],
|
|
148
|
+
},
|
|
149
|
+
repoName: '$source.repoName',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
$group: {
|
|
154
|
+
_id: '$contentHash',
|
|
155
|
+
copies: { $sum: 1 },
|
|
156
|
+
contentLen: { $first: '$len' },
|
|
157
|
+
projects: { $addToSet: '$project' },
|
|
158
|
+
repoNames: { $addToSet: '$repoName' },
|
|
159
|
+
files: { $addToSet: '$sourceFilePath' },
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{ $match: { copies: { $gte: 2 } } },
|
|
163
|
+
// A project-layer nélküli entry-k null-ja kikerül a halmazokból (a copies/wasted számít, a lefedettség nem).
|
|
164
|
+
{
|
|
165
|
+
$addFields: {
|
|
166
|
+
projects: { $setDifference: ['$projects', [null]] },
|
|
167
|
+
repoNames: { $setDifference: ['$repoNames', [null]] },
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{ $match: { $expr: { $gte: [{ $size: '$projects' }, input.minProjects] } } },
|
|
171
|
+
{
|
|
172
|
+
$addFields: {
|
|
173
|
+
wasted: { $multiply: ['$contentLen', { $subtract: ['$copies', 1] }] },
|
|
174
|
+
projectCount: { $size: '$projects' },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{ $sort: { wasted: -1 } },
|
|
178
|
+
{
|
|
179
|
+
$facet: {
|
|
180
|
+
totals: [{
|
|
181
|
+
$group: {
|
|
182
|
+
_id: null,
|
|
183
|
+
totalGroups: { $sum: 1 },
|
|
184
|
+
redundantCopies: { $sum: { $subtract: ['$copies', 1] } },
|
|
185
|
+
wastedChars: { $sum: '$wasted' },
|
|
186
|
+
},
|
|
187
|
+
}],
|
|
188
|
+
top: [
|
|
189
|
+
{ $limit: input.maxGroups },
|
|
190
|
+
{
|
|
191
|
+
$project: {
|
|
192
|
+
_id: 0,
|
|
193
|
+
contentHash: '$_id',
|
|
194
|
+
copies: 1,
|
|
195
|
+
projects: 1,
|
|
196
|
+
projectCount: 1,
|
|
197
|
+
repoNames: 1,
|
|
198
|
+
files: { $slice: ['$files', input.maxFilesPerGroup] },
|
|
199
|
+
filesTruncated: { $gt: [{ $size: '$files' }, input.maxFilesPerGroup] },
|
|
200
|
+
contentLen: 1,
|
|
201
|
+
wasted: 1,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
pairSource: [
|
|
206
|
+
{ $match: { projectCount: { $gte: 2 } } },
|
|
207
|
+
{ $project: { _id: 0, projects: 1, wasted: 1, repoNames: 1 } },
|
|
208
|
+
{ $limit: FAM_ExactDuplication_ControlService.PAIR_SOURCE_LIMIT },
|
|
209
|
+
],
|
|
210
|
+
multiProject: [
|
|
211
|
+
{ $match: { projectCount: { $gte: 4 } } },
|
|
212
|
+
{ $project: { _id: 1 } },
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* A `$facet` nyers kimenete → strukturált eredmény: 0-default totals (üres tábla nem dob), rendezett
|
|
220
|
+
* projekt-/repo-listák, fork-pár riport + (opt-in) csoport-szuppresszió. Tiszta.
|
|
221
|
+
*/
|
|
222
|
+
static toResult(facetRow, input, coverage) {
|
|
223
|
+
const totalsRow = facetRow?.totals?.[0];
|
|
224
|
+
const totals = {
|
|
225
|
+
totalGroups: totalsRow?.totalGroups ?? 0,
|
|
226
|
+
redundantCopies: totalsRow?.redundantCopies ?? 0,
|
|
227
|
+
wastedChars: totalsRow?.wastedChars ?? 0,
|
|
228
|
+
};
|
|
229
|
+
// Fork-pár statisztika a pár-forrás ágból (a wastedShare nevezője a TELJES pazarlás).
|
|
230
|
+
const pairSource = (facetRow?.pairSource ?? []).map((row) => ({
|
|
231
|
+
projects: row.projects ?? [], wasted: row.wasted ?? 0, repoNames: row.repoNames ?? [],
|
|
232
|
+
}));
|
|
233
|
+
const forkPairs = fam_dup_fork_pair_util_1.FAM_DupForkPair_Util.buildReport(pairSource, totals.wastedChars);
|
|
234
|
+
// A top-csoportok normalizálása (distinct/null-mentes/rendezett projektek — a $setDifference után a
|
|
235
|
+
// null már kint van, itt csak a determinista rendezés a dolgunk).
|
|
236
|
+
let groups = (facetRow?.top ?? []).map((row) => ({
|
|
237
|
+
contentHash: row.contentHash,
|
|
238
|
+
copies: row.copies,
|
|
239
|
+
projects: (row.projects ?? []).filter((project) => Boolean(project)).sort(),
|
|
240
|
+
projectCount: row.projectCount ?? 0,
|
|
241
|
+
repoNames: (row.repoNames ?? []).filter((repo) => Boolean(repo)).sort(),
|
|
242
|
+
// Az explicit `sourceFilePath:null` entry null-t adhat a halmazba — a riportban nem hordoz információt.
|
|
243
|
+
files: (row.files ?? []).filter((file) => Boolean(file)),
|
|
244
|
+
filesTruncated: Boolean(row.filesTruncated),
|
|
245
|
+
contentLen: row.contentLen ?? 0,
|
|
246
|
+
wasted: row.wasted ?? 0,
|
|
247
|
+
}));
|
|
248
|
+
// Opt-in fork-pár szuppresszió: CSAK a visszaadott csoport-listát szűri (a totals a mért valóság marad —
|
|
249
|
+
// a szuppresszió láthatóság-kontroll, nem mérés-hamisítás).
|
|
250
|
+
let suppressedGroups = 0;
|
|
251
|
+
if (input.suppressForkPairs) {
|
|
252
|
+
const suspected = forkPairs.pairs.filter((pair) => pair.suspectedFork);
|
|
253
|
+
const kept = groups.filter((group) => !fam_dup_fork_pair_util_1.FAM_DupForkPair_Util.shouldSuppress({ projects: group.projects, repoNames: group.repoNames }, suspected));
|
|
254
|
+
suppressedGroups = groups.length - kept.length;
|
|
255
|
+
groups = kept;
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
table: input.table,
|
|
259
|
+
filters: {
|
|
260
|
+
pathRegex: input.pathRegex,
|
|
261
|
+
excludePathRegex: input.excludePathRegex,
|
|
262
|
+
excludeRootRegex: input.excludeRootRegex,
|
|
263
|
+
projects: input.projects,
|
|
264
|
+
excludeProjects: input.excludeProjects,
|
|
265
|
+
minProjects: input.minProjects,
|
|
266
|
+
minContentLength: input.minContentLength,
|
|
267
|
+
},
|
|
268
|
+
totals: totals,
|
|
269
|
+
truncated: totals.totalGroups > input.maxGroups,
|
|
270
|
+
groups: groups,
|
|
271
|
+
suppressedGroups: suppressedGroups,
|
|
272
|
+
forkPairs: forkPairs,
|
|
273
|
+
multiProjectGroupHashes: (facetRow?.multiProject ?? []).map((row) => String(row._id)),
|
|
274
|
+
coverage: coverage,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/** Az user-regexek elő-validálása (érvénytelen minta → deskriptív hiba, nem Mongo-mélyhiba). */
|
|
278
|
+
assertValidRegexes(input) {
|
|
279
|
+
const candidates = [
|
|
280
|
+
{ name: 'pathRegex', pattern: input.pathRegex },
|
|
281
|
+
{ name: 'excludePathRegex', pattern: input.excludePathRegex },
|
|
282
|
+
{ name: 'excludeRootRegex', pattern: input.excludeRootRegex },
|
|
283
|
+
];
|
|
284
|
+
for (const candidate of candidates) {
|
|
285
|
+
if (!candidate.pattern) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
new RegExp(candidate.pattern);
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
293
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.mcpDispatchUnknownCapability,
|
|
294
|
+
message: `A 'detect_exact_duplication' '${candidate.name}' regexe érvénytelen: `
|
|
295
|
+
+ `'${candidate.pattern}' — ${error?.message}`,
|
|
296
|
+
issuer: this.issuer,
|
|
297
|
+
cause: error,
|
|
298
|
+
context: { operation: 'capability-invoke:detect_exact_duplication' },
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/** Egy fő RAG-tár mongoose-collection-je (a DS-példányosítás regisztrálja a modellt; onnan a valós collection). */
|
|
304
|
+
entryCollection(registryEntry) {
|
|
305
|
+
new fam_entry_data_service_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: this.issuer });
|
|
306
|
+
return mongoose_1.default.models[registryEntry.dataParams.dataName].collection;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
exports.FAM_ExactDuplication_ControlService = FAM_ExactDuplication_ControlService;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* (BFR-AM-002/008); a bedrock-csere (MP-15) a `FAM_EmbeddingProvider` interfész mögött non-breaking.
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.FAM_EmbeddingBootstrap_ControlService = exports.FAM_DuplicateScan_ControlService = exports.FAM_EmbeddingCost_ControlService = exports.FAM_EmbeddingPipeline_ControlService = exports.FAM_EmbeddingPreset_ControlService = exports.FAM_StoreRegistry_Util = exports.FAM_STORE_REGISTRY = exports.FAM_DedupWarn_ControlService = exports.FAM_Entry_DataService = exports.FAM_HydrationCoordinator_ControlService = exports.FAM_VectorSearch_ControlService = exports.FAM_MOCK_EMBEDDING_DIMS = exports.FAM_Mock_EmbeddingProvider = exports.FAM_LMStudio_EmbeddingProvider = exports.FAM_OpenAI_EmbeddingProvider = exports.FAM_Embedding_ControlService = void 0;
|
|
11
|
+
exports.FAM_EmbeddingBootstrap_ControlService = exports.FAM_DupAuditScheduler_ControlService = exports.FAM_DupAudit_DataService = exports.FAM_DupAudit_ControlService = exports.FAM_DupFileRollup_Util = exports.FAM_DupForkPair_Util = exports.FAM_DupCoverage_ControlService = exports.FAM_ExactDuplication_ControlService = exports.FAM_DuplicateScan_ControlService = exports.FAM_EmbeddingCost_ControlService = exports.FAM_EmbeddingPipeline_ControlService = exports.FAM_EmbeddingPreset_ControlService = exports.FAM_StoreRegistry_Util = exports.FAM_STORE_REGISTRY = exports.FAM_DedupWarn_ControlService = exports.FAM_Entry_DataService = exports.FAM_HydrationCoordinator_ControlService = exports.FAM_VectorSearch_ControlService = exports.FAM_MOCK_EMBEDDING_DIMS = exports.FAM_Mock_EmbeddingProvider = exports.FAM_LMStudio_EmbeddingProvider = exports.FAM_OpenAI_EmbeddingProvider = exports.FAM_Embedding_ControlService = void 0;
|
|
12
12
|
// SP-2.1 — provider-dispatch kapu + providerek
|
|
13
13
|
var fam_embedding_control_service_1 = require("./_services/fam-embedding.control-service");
|
|
14
14
|
Object.defineProperty(exports, "FAM_Embedding_ControlService", { enumerable: true, get: function () { return fam_embedding_control_service_1.FAM_Embedding_ControlService; } });
|
|
@@ -42,6 +42,21 @@ Object.defineProperty(exports, "FAM_EmbeddingCost_ControlService", { enumerable:
|
|
|
42
42
|
// near-duplikátum FELDERÍTŐ (read-only; user-direktíva 2026-06-21)
|
|
43
43
|
var fam_duplicate_scan_control_service_1 = require("./_services/fam-duplicate-scan.control-service");
|
|
44
44
|
Object.defineProperty(exports, "FAM_DuplicateScan_ControlService", { enumerable: true, get: function () { return fam_duplicate_scan_control_service_1.FAM_DuplicateScan_ControlService; } });
|
|
45
|
+
// dup-v2 (task #20): exact-duplikáció + coverage-preflight + fork-pár + fájl-rollup + heti dup-őrjárat
|
|
46
|
+
var fam_exact_duplication_control_service_1 = require("./_services/fam-exact-duplication.control-service");
|
|
47
|
+
Object.defineProperty(exports, "FAM_ExactDuplication_ControlService", { enumerable: true, get: function () { return fam_exact_duplication_control_service_1.FAM_ExactDuplication_ControlService; } });
|
|
48
|
+
var fam_dup_coverage_control_service_1 = require("./_services/fam-dup-coverage.control-service");
|
|
49
|
+
Object.defineProperty(exports, "FAM_DupCoverage_ControlService", { enumerable: true, get: function () { return fam_dup_coverage_control_service_1.FAM_DupCoverage_ControlService; } });
|
|
50
|
+
var fam_dup_fork_pair_util_1 = require("./_collections/fam-dup-fork-pair.util");
|
|
51
|
+
Object.defineProperty(exports, "FAM_DupForkPair_Util", { enumerable: true, get: function () { return fam_dup_fork_pair_util_1.FAM_DupForkPair_Util; } });
|
|
52
|
+
var fam_dup_file_rollup_util_1 = require("./_collections/fam-dup-file-rollup.util");
|
|
53
|
+
Object.defineProperty(exports, "FAM_DupFileRollup_Util", { enumerable: true, get: function () { return fam_dup_file_rollup_util_1.FAM_DupFileRollup_Util; } });
|
|
54
|
+
var fam_dup_audit_control_service_1 = require("./_services/fam-dup-audit.control-service");
|
|
55
|
+
Object.defineProperty(exports, "FAM_DupAudit_ControlService", { enumerable: true, get: function () { return fam_dup_audit_control_service_1.FAM_DupAudit_ControlService; } });
|
|
56
|
+
var fam_dup_audit_data_service_1 = require("./_services/fam-dup-audit.data-service");
|
|
57
|
+
Object.defineProperty(exports, "FAM_DupAudit_DataService", { enumerable: true, get: function () { return fam_dup_audit_data_service_1.FAM_DupAudit_DataService; } });
|
|
58
|
+
var fam_dup_audit_scheduler_control_service_1 = require("./_services/fam-dup-audit-scheduler.control-service");
|
|
59
|
+
Object.defineProperty(exports, "FAM_DupAuditScheduler_ControlService", { enumerable: true, get: function () { return fam_dup_audit_scheduler_control_service_1.FAM_DupAuditScheduler_ControlService; } });
|
|
45
60
|
// boot-hook (App.postProcess)
|
|
46
61
|
var fam_embedding_bootstrap_control_service_1 = require("./_services/fam-embedding-bootstrap.control-service");
|
|
47
62
|
Object.defineProperty(exports, "FAM_EmbeddingBootstrap_ControlService", { enumerable: true, get: function () { return fam_embedding_bootstrap_control_service_1.FAM_EmbeddingBootstrap_ControlService; } });
|