@futdevpro/fdp-agent-memory 0.1.0 → 1.1.12

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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -7
  3. package/build/package.json +6 -5
  4. package/build/src/_cli/_collections/fam-arg.util.js +48 -0
  5. package/build/src/_cli/_collections/fam-cli.const.js +40 -0
  6. package/build/src/_cli/_collections/fam-output.util.js +86 -0
  7. package/build/src/_cli/_collections/fam-project-discovery.util.js +98 -0
  8. package/build/src/_cli/_commands/capture.command.js +73 -0
  9. package/build/src/_cli/_commands/config.command.js +93 -0
  10. package/build/src/_cli/_commands/doctor.command.js +124 -0
  11. package/build/src/_cli/_commands/errors.command.js +66 -0
  12. package/build/src/_cli/_commands/export.command.js +65 -0
  13. package/build/src/_cli/_commands/find-duplicates.command.js +97 -0
  14. package/build/src/_cli/_commands/import.command.js +136 -0
  15. package/build/src/_cli/_commands/init.command.js +147 -0
  16. package/build/src/_cli/_commands/read.command.js +109 -0
  17. package/build/src/_cli/_commands/scan-projects.command.js +138 -0
  18. package/build/src/_cli/_commands/scan.command.js +98 -0
  19. package/build/src/_cli/_commands/seed.command.js +40 -0
  20. package/build/src/_cli/_commands/serve.command.js +350 -0
  21. package/build/src/_cli/_commands/start.command.js +134 -0
  22. package/build/src/_cli/_commands/stats.command.js +54 -0
  23. package/build/src/_cli/_commands/write.command.js +103 -0
  24. package/build/src/_cli/_models/interfaces/fam-cli-global-options.interface.js +2 -0
  25. package/build/src/_cli/_models/interfaces/fam-cli-output.interface.js +9 -0
  26. package/build/src/_cli/_models/interfaces/fam-client-result.interface.js +2 -0
  27. package/build/src/_cli/_services/fam-client.service.js +140 -0
  28. package/build/src/_cli/register-commands.js +86 -0
  29. package/build/src/_collections/config-catalog.const.js +67 -1
  30. package/build/src/_collections/fam-console.util.js +367 -0
  31. package/build/src/_collections/fam-entry-bootstrap.util.js +158 -4
  32. package/build/src/_collections/fam-error-factory.util.js +0 -9
  33. package/build/src/_collections/fam-mcp-bridge.util.js +49 -0
  34. package/build/src/_collections/fam-reference-code.util.js +105 -0
  35. package/build/src/_collections/fam-version.const.js +10 -0
  36. package/build/src/_models/data-models/fam-entry-base-properties.const.js +1 -0
  37. package/build/src/_models/data-models/fam-entry.data-model.js +6 -0
  38. package/build/src/_models/data-models/fam-ingest-run.data-model.js +3 -1
  39. package/build/src/_models/data-models/fam-reference.data-model.js +7 -0
  40. package/build/src/_modules/capture/_collections/fam-capture.const.js +11 -0
  41. package/build/src/_modules/capture/_services/fam-auto-capture.control-service.js +87 -0
  42. package/build/src/_modules/capture/index.js +8 -0
  43. package/build/src/_modules/embedding/_collections/fam-embedding-prefix.util.js +77 -0
  44. package/build/src/_modules/embedding/_services/fam-duplicate-scan.control-service.js +202 -0
  45. package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +33 -9
  46. package/build/src/_modules/embedding/_services/fam-embedding.control-service.js +21 -2
  47. package/build/src/_modules/embedding/_services/fam-entry.data-service.js +135 -0
  48. package/build/src/_modules/embedding/_services/fam-vector-search.control-service.js +42 -32
  49. package/build/src/_modules/embedding/index.js +4 -1
  50. package/build/src/_modules/export/_collections/fam-export.const.js +22 -0
  51. package/build/src/_modules/export/_services/fam-export.control-service.js +64 -0
  52. package/build/src/_modules/export/index.js +8 -0
  53. package/build/src/_modules/ingest/_collections/fam-famignore.util.js +83 -0
  54. package/build/src/_modules/ingest/_collections/fam-file-routing.util.js +59 -48
  55. package/build/src/_modules/ingest/_collections/fam-project-identity.util.js +134 -0
  56. package/build/src/_modules/ingest/_collections/fam-scan-progress.util.js +57 -0
  57. package/build/src/_modules/ingest/_collections/fam-scan-summary.util.js +60 -0
  58. package/build/src/_modules/ingest/_collections/fam-scan-weight.util.js +53 -0
  59. package/build/src/_modules/ingest/_collections/fam-secret-exclude.util.js +37 -14
  60. package/build/src/_modules/ingest/_collections/fam-sliding-chunker.util.js +34 -0
  61. package/build/src/_modules/ingest/_collections/fam-ts-chunker.util.js +200 -14
  62. package/build/src/_modules/ingest/_services/fam-delta-compare.util.js +4 -1
  63. package/build/src/_modules/ingest/_services/fam-ingest-run.data-service.js +7 -4
  64. package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +346 -17
  65. package/build/src/_modules/ingest/_services/fam-scan.control-service.js +25 -2
  66. package/build/src/_modules/ingest/index.js +3 -1
  67. package/build/src/_modules/mcp/_collections/fam-active-rules.util.js +56 -0
  68. package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +47 -6
  69. package/build/src/_modules/mcp/_services/fam-capabilities-tool.service.js +4 -4
  70. package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +224 -18
  71. package/build/src/_modules/mcp/_services/fam-mcp-adapter.service.js +4 -4
  72. package/build/src/_modules/mcp/_services/fam-mcp-server.service.js +4 -4
  73. package/build/src/_modules/mcp/_services/fam-read-tool.service.js +53 -1
  74. package/build/src/_modules/mcp/_services/fam-write-tool.service.js +104 -8
  75. package/build/src/_modules/mcp/index.js +4 -4
  76. package/build/src/_modules/migration/_collections/fam-claude-mem-normalize.util.js +66 -3
  77. package/build/src/_modules/migration/_collections/fam-prompt-aggregate.util.js +143 -0
  78. package/build/src/_modules/migration/_collections/fam-target-mapping.util.js +19 -0
  79. package/build/src/_modules/migration/_enums/fam-claude-mem-source.type-enum.js +6 -0
  80. package/build/src/_modules/migration/_models/interfaces/fam-claude-mem.interface.js +5 -0
  81. package/build/src/_modules/migration/_services/fam-agent-memory-reader.service.js +125 -0
  82. package/build/src/_modules/migration/_services/fam-claude-mem-import.control-service.js +101 -18
  83. package/build/src/_modules/migration/_services/fam-import-dedup.data-service.js +53 -0
  84. package/build/src/_modules/migration/index.js +3 -1
  85. package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +78 -4
  86. package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +293 -50
  87. package/build/src/_modules/scope-reference/_collections/fam-scope-normalize.util.js +6 -3
  88. package/build/src/_modules/scope-reference/_services/fam-reference.data-service.js +18 -0
  89. package/build/src/_modules/scope-reference/_services/fam-scope-resolver.control-service.js +79 -20
  90. package/build/src/_routes/server/api/api.controller.js +34 -2
  91. package/build/src/_routes/server/client-app/client-app.control-service.js +1 -1
  92. package/build/src/_routes/server/server-status/server-status.controller.js +2 -1
  93. package/build/src/app.server.js +13 -1
  94. package/build/src/environments/environment.js +1 -1
  95. package/build/src/index.js +1 -1
  96. package/client-dist/{chunk-GHKRM4SM.js → chunk-I77GXVAQ.js} +1 -1
  97. package/client-dist/{chunk-LMTL7GA3.js → chunk-YXHWCJ5O.js} +1 -1
  98. package/client-dist/index.html +1 -1
  99. package/client-dist/{main-2KWB3QYK.js → main-PJPEDVJT.js} +1 -1
  100. package/package.json +6 -5
@@ -4,13 +4,23 @@ exports.FAM_Ingest_ControlService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const crypto = tslib_1.__importStar(require("crypto"));
6
6
  const fs = tslib_1.__importStar(require("fs"));
7
+ const path = tslib_1.__importStar(require("path"));
7
8
  const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
9
+ const fam_table_type_enum_1 = require("../../../_enums/fam-table.type-enum");
8
10
  const error_codes_const_1 = require("../../../_collections/error-codes.const");
9
11
  const errors_control_service_1 = require("../../../_routes/server/errors/errors.control-service");
10
12
  const config_control_service_1 = require("../../../_routes/server/config/config.control-service");
11
13
  const fam_entry_data_model_1 = require("../../../_models/data-models/fam-entry.data-model");
14
+ const fam_reference_code_util_1 = require("../../../_collections/fam-reference-code.util");
12
15
  const embedding_1 = require("../../embedding");
13
16
  const scope_reference_1 = require("../../scope-reference");
17
+ const fam_content_hash_util_1 = require("../_collections/fam-content-hash.util");
18
+ const fam_project_identity_util_1 = require("../_collections/fam-project-identity.util");
19
+ const fam_scan_path_util_1 = require("../_collections/fam-scan-path.util");
20
+ const fam_scan_progress_util_1 = require("../_collections/fam-scan-progress.util");
21
+ const fam_scan_summary_util_1 = require("../_collections/fam-scan-summary.util");
22
+ const scope_reference_2 = require("../../scope-reference");
23
+ const fam_reference_data_model_1 = require("../../../_models/data-models/fam-reference.data-model");
14
24
  const fam_chunker_control_service_1 = require("./fam-chunker.control-service");
15
25
  const fam_delta_compare_util_1 = require("./fam-delta-compare.util");
16
26
  const fam_ingest_run_data_service_1 = require("./fam-ingest-run.data-service");
@@ -36,6 +46,15 @@ const fam_scan_control_service_1 = require("./fam-scan.control-service");
36
46
  */
37
47
  class FAM_Ingest_ControlService {
38
48
  static _instance;
49
+ /**
50
+ * Bináris-tartalom heurisztika (FAM-REV-064): egy NUL-karakter (U+0000) az első ~8KB-ban → bináris
51
+ * (a UTF-8 szöveg sosem tartalmaz NUL-t). A denylist-en átcsúszott, ismeretlen-kiterjesztésű bináris
52
+ * fájl szűrője — így nem kerül szemét-chunk a generic chunkerbe. Pure + statikus (tesztelhető).
53
+ */
54
+ static isLikelyBinary(content) {
55
+ const sample = content.length > 8192 ? content.slice(0, 8192) : content;
56
+ return sample.indexOf(String.fromCharCode(0)) !== -1;
57
+ }
39
58
  /** Default issuer az ingest-műveletekhez. */
40
59
  issuer = 'FAM_Ingest_ControlService';
41
60
  static getInstance() {
@@ -90,6 +109,8 @@ class FAM_Ingest_ControlService {
90
109
  for (const chunk of chunks) {
91
110
  if (chunk._id) {
92
111
  await dataService.deleteData(chunk._id);
112
+ // Pool-coherence (FAM-REV-046): a vektort az in-memory LVS-pool-ból is kivesszük.
113
+ embedding_1.FAM_VectorSearch_ControlService.getInstance().removeVector(registryEntry.table, chunk._id);
93
114
  deleted++;
94
115
  }
95
116
  }
@@ -106,7 +127,9 @@ class FAM_Ingest_ControlService {
106
127
  */
107
128
  async runScan(request) {
108
129
  const issuer = request.issuer ?? this.issuer;
109
- const runId = crypto.randomUUID();
130
+ // A pre-open (scope-resolve / discovery) hiba-summary-khoz kell egy id MIELŐTT a run-rekord
131
+ // megnyílna; a sikeres `open` UTÁN ezt a Dynamo-generált `_id`-re cseréljük (lásd lentebb).
132
+ let runId = crypto.randomUUID();
110
133
  const startedAt = Date.now();
111
134
  // (1) Scope reference-resolve (MP-3 `resolveForWrite`) — KÖTELEZŐ. Hiba → run `failed`.
112
135
  let canonicalScope;
@@ -132,6 +155,7 @@ class FAM_Ingest_ControlService {
132
155
  include: request.include,
133
156
  exclude: request.exclude,
134
157
  tableOverride: request.tableOverride,
158
+ weights: request.weights,
135
159
  });
136
160
  }
137
161
  catch (error) {
@@ -140,25 +164,34 @@ class FAM_Ingest_ControlService {
140
164
  error: error, scopePath: canonicalScope,
141
165
  });
142
166
  }
143
- // (3) A run megnyitása (a chunkok ezzel az `ingestRunId`-vel hivatkoznak rá).
167
+ // (3) A run megnyitása (a chunkok ezzel az `ingestRunId`-vel hivatkoznak rá). A `_id`-t a Dynamo
168
+ // generálja (Mongo ObjectId — a `FAM_Scope` mintája; a client-generált UUID nem cast-olható
169
+ // `findById`-dal). Innentől a Dynamo-`_id` a runId.
144
170
  const runDataService = new fam_ingest_run_data_service_1.FAM_IngestRun_DataService({ issuer: issuer });
145
- await runDataService.open({
146
- runId: runId,
171
+ const openedRun = await runDataService.open({
147
172
  trigger: request.operation,
148
173
  table: discovery.tables,
149
174
  scopePath: canonicalScope,
150
175
  rootPath: request.path,
151
176
  });
177
+ runId = openedRun._id ?? runId;
152
178
  // (4) Per-fájl feldolgozás (flow-limit kötegekben; a per-fájl hiba NEM buktatja a run-t).
153
179
  const verdicts = { new: 0, modified: 0, equal: 0, deleted: 0 };
154
180
  const errors = [];
155
181
  let chunkCount = 0;
156
182
  const flowLimit = await this.resolveFlowLimit(canonicalScope);
157
- for (let i = 0; i < discovery.routedFiles.length; i += flowLimit) {
183
+ const isDryRun = request.dryRun ?? false;
184
+ const total = discovery.routedFiles.length;
185
+ // Futás-közbeni progress (descriptive user feedback): a NAGY (workspace-szintű) scan haladását
186
+ // throttle-olt `[famIngest]` sorokkal jelezzük a konzolon (a `dryRun` NEM embeddel → ott nincs progress).
187
+ const progressIntervalMs = await this.resolveScanNumber('scan.progressIntervalMs', canonicalScope, 2000);
188
+ let lastProgressAt = startedAt;
189
+ for (let i = 0; i < total; i += flowLimit) {
158
190
  const batch = discovery.routedFiles.slice(i, i + flowLimit);
159
191
  const results = await Promise.all(batch.map((file) => this.processFile({
160
192
  file: file, runId: runId, scopePath: canonicalScope,
161
- dryRun: request.dryRun ?? false, issuer: issuer, errors: errors,
193
+ resolvedRoot: discovery.resolvedRoot,
194
+ dryRun: isDryRun, issuer: issuer, errors: errors,
162
195
  })));
163
196
  for (const result of results) {
164
197
  if (!result) {
@@ -167,6 +200,42 @@ class FAM_Ingest_ControlService {
167
200
  chunkCount += result.chunkCount;
168
201
  this.tallyVerdicts(verdicts, result.deltaItems);
169
202
  }
203
+ // Throttle-olt progress-jelzés (a min. időköz a config; a végső 100% MINDIG kibocsátódik). dryRun-on
204
+ // kihagyva (nincs valódi embed-munka, a becslést a summary.estimate adja).
205
+ const processed = Math.min(i + flowLimit, total);
206
+ const now = Date.now();
207
+ if (!isDryRun && (processed >= total || now - lastProgressAt >= progressIntervalMs)) {
208
+ lastProgressAt = now;
209
+ fsm_dynamo_1.DyFM_Log.info(fam_scan_progress_util_1.FAM_ScanProgress_Util.progressLine({
210
+ processed: processed, total: total, chunkCount: chunkCount,
211
+ verdicts: verdicts, elapsedSeconds: (now - startedAt) / 1000,
212
+ }));
213
+ }
214
+ }
215
+ // (4b) Törölt-fájl reconciliation (whole-file orphan) — CSAK folder/project scan (a `scan-file`
216
+ // egyetlen fájlt céloz, nem reconciliál). A lemezről eltűnt fájlok chunkjai soft-delete-elődnek; a
217
+ // számuk a `verdicts.deleted`-be (a per-fájl, fájlon-belüli `deleted`-ek mellé).
218
+ if (request.operation !== 'scan-file') {
219
+ verdicts.deleted += await this.reconcileDeletedFiles({
220
+ discovery: discovery, scopePath: canonicalScope, issuer: issuer, dryRun: request.dryRun ?? false,
221
+ });
222
+ }
223
+ // (4c) File-rendszer összefoglaló (knowledge) — generált „mi van a projektben" entry a mappastruktúrából
224
+ // (folder/project scan, non-dryRun, van route-olt fájl). Best-effort: a hiba NEM buktatja a scant.
225
+ if (!isDryRun && request.operation !== 'scan-file' && discovery.routedFiles.length) {
226
+ try {
227
+ await this.persistScanSummary({ discovery: discovery, scopePath: canonicalScope, runId: runId, issuer: issuer });
228
+ }
229
+ catch (error) {
230
+ fsm_dynamo_1.DyFM_Log.warn(`[famIngest] fs-summary generálás sikertelen (a scan kész): ${error?.message}`);
231
+ }
232
+ // (4d) Projekt-identitás (git + package.json) → kereshető knowledge entry + reference-alias. Best-effort.
233
+ try {
234
+ await this.persistProjectIdentity({ discovery: discovery, scopePath: canonicalScope, runId: runId, issuer: issuer });
235
+ }
236
+ catch (error) {
237
+ fsm_dynamo_1.DyFM_Log.warn(`[famIngest] project-identity generálás sikertelen (a scan kész): ${error?.message}`);
238
+ }
170
239
  }
171
240
  // (5) A run lezárása (atomikus `$set`) + MON-esemény.
172
241
  const status = errors.length ? 'partial-failed' : 'ok';
@@ -182,6 +251,15 @@ class FAM_Ingest_ControlService {
182
251
  filesProcessed: discovery.routedFiles.length, filesSkipped: discovery.skippedFiles.length,
183
252
  chunkCount: chunkCount, verdicts: verdicts, durationMs: durationMs, status: status, errors: errors,
184
253
  };
254
+ // Pre-scan idő-becslés CSAK dryRun-on (descriptive user feedback): mennyi lesz a TÉNYLEGES scan embed-ideje.
255
+ if (isDryRun) {
256
+ const msPerChunk = await this.resolveScanNumber('scan.estimateMsPerChunk', canonicalScope, 250);
257
+ summary.estimate = fam_scan_progress_util_1.FAM_ScanProgress_Util.estimate({
258
+ chunksToEmbed: verdicts.new + verdicts.modified, msPerChunk: msPerChunk,
259
+ });
260
+ fsm_dynamo_1.DyFM_Log.info(`[famIngest] dryRun kész: ${total} fájl, ${chunkCount} chunk, `
261
+ + `${verdicts.new + verdicts.modified} embeddelendő → becsült idő ${summary.estimate.note}`);
262
+ }
185
263
  this.emitMonEvent(summary);
186
264
  return summary;
187
265
  }
@@ -194,6 +272,11 @@ class FAM_Ingest_ControlService {
194
272
  const table = set.file.route;
195
273
  try {
196
274
  const content = fs.readFileSync(set.file.absolutePath, 'utf-8');
275
+ // FAM-REV-064 bináris-tartalom guard: a denylist-en átcsúszott, ismeretlen-kiterjesztésű bináris
276
+ // (null-byte az első ~8KB-ban) NE kerüljön a generic chunkerbe (szemét-chunk ellen). Skip → 0 chunk.
277
+ if (FAM_Ingest_ControlService.isLikelyBinary(content)) {
278
+ return null;
279
+ }
197
280
  const chunks = await fam_chunker_control_service_1.FAM_Chunker_ControlService.getInstance().chunkFile({
198
281
  content: content, relativePath: set.file.relativePath, table: table, scopePath: set.scopePath,
199
282
  });
@@ -202,13 +285,14 @@ class FAM_Ingest_ControlService {
202
285
  throw new Error(`No store-registry entry for table '${table}'.`);
203
286
  }
204
287
  const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: set.issuer });
205
- // Existing-by-key betöltés (a fájl nem soft-deleted chunkjai, scope-szűkítve).
206
- const existing = await this.loadExistingChunks(dataService, set.file.relativePath, set.scopePath);
288
+ // Existing-by-key betöltés a KANONIKUS abszolút útvonalon (FAM-REV-050) a scan-root-független
289
+ // fájl-identitás, így a delta bármely scan-gyökérről ugyanazt a fájlt matcheli (nincs duplikáció).
290
+ const existing = await this.loadExistingChunks(dataService, set.file.absolutePath, set.scopePath);
207
291
  const deltaItems = fam_delta_compare_util_1.FAM_DeltaCompare_Util.compare(chunks, existing);
208
292
  if (!set.dryRun) {
209
293
  await this.applyVerdicts({
210
294
  deltaItems: deltaItems, file: set.file, table: table, runId: set.runId,
211
- scopePath: set.scopePath, dataService: dataService,
295
+ scopePath: set.scopePath, root: set.resolvedRoot, dataService: dataService,
212
296
  });
213
297
  }
214
298
  return {
@@ -247,11 +331,47 @@ class FAM_Ingest_ControlService {
247
331
  async applyVerdicts(set) {
248
332
  for (const item of set.deltaItems) {
249
333
  if (item.verdict === 'equal') {
334
+ // Metaadat-backfill (FAM-REV-048 + FEAT-003): az equal-content entry `source.root`-ja ÉS
335
+ // `referenceCodes`-a frissül, ha eltér — a re-scan így a TELJES korpuszt root-tudatossá teszi
336
+ // (reconciliation-lefedettség) ÉS a kód-index-frissítést (pl. Tailwind-denylist-bővítés) a régi
337
+ // chunkokra is alkalmazza, RE-EMBED NÉLKÜL. Mindkettő FELTÉTELES (no-op, ha már stimmel),
338
+ // best-effort: a hiba NEM buktatja a scan-t (a content már naprakész).
339
+ if (item.existingId) {
340
+ try {
341
+ if (set.root) {
342
+ await set.dataService.backfillSourceRoot(item.existingId, set.root);
343
+ }
344
+ // A default display-relatív út a friss scan-gyökérhez igazodjon (FAM-REV-050) —
345
+ // egy korábban más root-reprezentációval (pl. scan-file basename) ingestelt chunk konzisztenssé.
346
+ await set.dataService.backfillSourceFilePath(item.existingId, set.file.relativePath);
347
+ if (item.chunk) {
348
+ await set.dataService.backfillReferenceCodes(item.existingId, fam_reference_code_util_1.FAM_ReferenceCode_Util.extract(item.chunk.content));
349
+ // Pozíció-backfill (FAM-REV-061): a chunker pozíció-fix a régi equal-chunkokra is,
350
+ // re-embed nélkül (a friss chunk charStart/charEnd/sor-pozíciója felülír, ha eltér).
351
+ await set.dataService.backfillPosition(item.existingId, item.chunk.position);
352
+ }
353
+ }
354
+ catch {
355
+ // best-effort metaadat-frissítés — a content már naprakész (equal), nem eszkaláljuk.
356
+ }
357
+ // FAM-REV-066: ha a meglévő equal-chunk NEM completed (transient embed-`error`/`pending`,
358
+ // pl. LM Studio HTTP 500 alatt), ÚJRA-embeddeljük (a content egyezik, csak a vektor hiányzik)
359
+ // → a tranziens embed-hibák a következő re-scankor AUTO-GYÓGYULNAK (nincs beragadt error).
360
+ if (item.chunk && item.existingEmbeddingStatus && item.existingEmbeddingStatus !== 'completed') {
361
+ await this.persistAndEmbed({
362
+ chunk: item.chunk, existingId: item.existingId, contentHash: item.contentHash,
363
+ file: set.file, table: set.table, runId: set.runId, scopePath: set.scopePath,
364
+ root: set.root, dataService: set.dataService,
365
+ });
366
+ }
367
+ }
250
368
  continue;
251
369
  }
252
370
  if (item.verdict === 'deleted') {
253
371
  if (item.existingId) {
254
372
  await set.dataService.deleteData(item.existingId);
373
+ // Pool-coherence (FAM-REV-046): a törölt chunk vektora is ki a pool-ból.
374
+ embedding_1.FAM_VectorSearch_ControlService.getInstance().removeVector(set.table, item.existingId);
255
375
  }
256
376
  continue;
257
377
  }
@@ -260,7 +380,7 @@ class FAM_Ingest_ControlService {
260
380
  await this.persistAndEmbed({
261
381
  chunk: item.chunk, existingId: item.existingId, contentHash: item.contentHash,
262
382
  file: set.file, table: set.table, runId: set.runId, scopePath: set.scopePath,
263
- dataService: set.dataService,
383
+ root: set.root, dataService: set.dataService,
264
384
  });
265
385
  }
266
386
  }
@@ -278,13 +398,17 @@ class FAM_Ingest_ControlService {
278
398
  contentHash: set.contentHash,
279
399
  embeddingStatus: 'pending',
280
400
  scopePath: set.scopePath,
401
+ // Súly-kiemelés (FAM-REV-055): a scan-`weights`-ből feloldott fájl-súly (undefined → a tár model-default).
402
+ weight: set.file.weight,
281
403
  sourceFilePath: set.file.relativePath,
282
404
  chunkIndex: set.chunk.chunkIndex,
283
405
  chunkTotal: set.chunk.chunkTotal,
284
406
  chunkType: set.chunk.chunkType,
285
407
  position: set.chunk.position,
286
408
  headingPath: set.chunk.headingPath,
287
- source: { type: 'scan', path: set.file.relativePath },
409
+ source: {
410
+ type: 'scan', path: set.file.relativePath, root: set.root, absolutePath: set.file.absolutePath,
411
+ },
288
412
  addedBy: 'scan',
289
413
  ingestRunId: set.runId,
290
414
  });
@@ -296,22 +420,218 @@ class FAM_Ingest_ControlService {
296
420
  table: set.table, entry: saved, callType: 'embed-write',
297
421
  });
298
422
  }
423
+ /**
424
+ * A file-rendszer-összefoglaló (`knowledge`, kind `fs-summary`) generálása + idempotens upsert-je a scan után.
425
+ * A `FAM_ScanSummary_Util` a mappastruktúrából építi a kereshető „mi van a projektben" szöveget. **Identitás:**
426
+ * `source.type='scan-summary'` + `source.absolutePath=<scan-gyökér>` + a levél-scope → re-scankor a MEGLÉVŐ-t
427
+ * frissíti (nincs duplikáció). **Idempotencia:** ha a `contentHash` változatlan (ugyanaz a fájl-lista), NO-OP
428
+ * (nincs fölös re-embed). A `scan-summary` source-type-ot a reconciliation (ami `scan`-t szűr) sosem érinti.
429
+ */
430
+ async persistScanSummary(set) {
431
+ const registryEntry = embedding_1.FAM_StoreRegistry_Util.getEntry(fam_table_type_enum_1.FAM_Table.knowledge);
432
+ if (!registryEntry) {
433
+ return;
434
+ }
435
+ const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: set.issuer });
436
+ const scopeLabel = set.scopePath.map((ref) => ref.canonicalName).join(' > ') || '(globális)';
437
+ const content = fam_scan_summary_util_1.FAM_ScanSummary_Util.build({
438
+ scopeLabel: scopeLabel,
439
+ root: set.discovery.resolvedRoot,
440
+ relativePaths: set.discovery.routedFiles.map((file) => file.relativePath),
441
+ skippedCount: set.discovery.skippedFiles.length,
442
+ tables: set.discovery.tables.map((table) => String(table)),
443
+ });
444
+ const contentHash = fam_content_hash_util_1.FAM_ContentHash_Util.hash(content);
445
+ // Meglévő összefoglaló a (source-type + scan-gyökér + levél-scope) identitáson.
446
+ const leafScopeId = set.scopePath.length ? set.scopePath[set.scopePath.length - 1].scopeId : undefined;
447
+ const filter = {};
448
+ filter['source.type'] = fam_scan_summary_util_1.FAM_ScanSummary_Util.SOURCE_TYPE;
449
+ filter['source.absolutePath'] = set.discovery.resolvedRoot;
450
+ filter.kind = fam_scan_summary_util_1.FAM_ScanSummary_Util.KIND; // ne ütközzön a project-identity-vel (azonos source-type + root + scope)
451
+ if (leafScopeId) {
452
+ filter['scopePath.scopeId'] = leafScopeId;
453
+ }
454
+ const existing = await dataService.findHydratableList(filter);
455
+ const existingEntry = existing[0];
456
+ // Változatlan fájl-lista → NO-OP (nincs fölös re-embed).
457
+ if (existingEntry && existingEntry.contentHash === contentHash) {
458
+ return;
459
+ }
460
+ const entry = new fam_entry_data_model_1.FAM_Entry({
461
+ _id: existingEntry?._id,
462
+ table: fam_table_type_enum_1.FAM_Table.knowledge,
463
+ content: content,
464
+ contentHash: contentHash,
465
+ embeddingStatus: 'pending',
466
+ scopePath: set.scopePath,
467
+ kind: fam_scan_summary_util_1.FAM_ScanSummary_Util.KIND,
468
+ tags: ['fs-summary', 'filesystem', 'scan-summary'],
469
+ weight: 2,
470
+ source: {
471
+ type: 'scan-summary', root: set.discovery.resolvedRoot, absolutePath: set.discovery.resolvedRoot,
472
+ },
473
+ addedBy: 'scan',
474
+ ingestRunId: set.runId,
475
+ });
476
+ const saved = await dataService.saveData(entry);
477
+ await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().embedAndPersist({
478
+ table: fam_table_type_enum_1.FAM_Table.knowledge, entry: saved, callType: 'embed-write',
479
+ });
480
+ fsm_dynamo_1.DyFM_Log.info(`[famIngest] fs-summary ${existingEntry ? 'frissítve' : 'létrehozva'} `
481
+ + `(${scopeLabel}): ${set.discovery.routedFiles.length} fájl, ${set.discovery.tables.length} tár`);
482
+ }
483
+ /**
484
+ * A scan-gyökér PROJEKT-IDENTITÁSA (git + `package.json`) → (a) kereshető `knowledge` „project-identity"
485
+ * entry (név/verzió/leírás/függőségek/git-repo), (b) reference-alias (a package-név + rövid alakok → a
486
+ * projekt scope-ja). Idempotens (a knowledge a contentHash-en; a reference a scope-on). Best-effort.
487
+ */
488
+ async persistProjectIdentity(set) {
489
+ const identity = fam_project_identity_util_1.FAM_ProjectIdentity_Util.detect(set.discovery.resolvedRoot);
490
+ if (!fam_project_identity_util_1.FAM_ProjectIdentity_Util.hasIdentity(identity)) {
491
+ return;
492
+ }
493
+ const scopeLabel = set.scopePath.map((ref) => ref.canonicalName).join(' > ') || '(globális)';
494
+ const leaf = set.scopePath.length ? set.scopePath[set.scopePath.length - 1] : undefined;
495
+ // (a) knowledge „project-identity" entry — idempotens (kind + source-type + root + scope; contentHash-skip).
496
+ const registryEntry = embedding_1.FAM_StoreRegistry_Util.getEntry(fam_table_type_enum_1.FAM_Table.knowledge);
497
+ if (registryEntry) {
498
+ const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: set.issuer });
499
+ const content = fam_project_identity_util_1.FAM_ProjectIdentity_Util.buildContent(identity, scopeLabel, set.discovery.resolvedRoot);
500
+ const contentHash = fam_content_hash_util_1.FAM_ContentHash_Util.hash(content);
501
+ const filter = {};
502
+ filter['source.type'] = fam_scan_summary_util_1.FAM_ScanSummary_Util.SOURCE_TYPE;
503
+ filter['source.absolutePath'] = set.discovery.resolvedRoot;
504
+ filter.kind = fam_project_identity_util_1.FAM_ProjectIdentity_Util.KIND;
505
+ if (leaf) {
506
+ filter['scopePath.scopeId'] = leaf.scopeId;
507
+ }
508
+ const existing = await dataService.findHydratableList(filter);
509
+ const existingEntry = existing[0];
510
+ if (!existingEntry || existingEntry.contentHash !== contentHash) {
511
+ const entry = new fam_entry_data_model_1.FAM_Entry({
512
+ _id: existingEntry?._id,
513
+ table: fam_table_type_enum_1.FAM_Table.knowledge,
514
+ content: content,
515
+ contentHash: contentHash,
516
+ embeddingStatus: 'pending',
517
+ scopePath: set.scopePath,
518
+ kind: fam_project_identity_util_1.FAM_ProjectIdentity_Util.KIND,
519
+ tags: ['project-identity', 'package', ...(identity.isGit ? ['git'] : [])],
520
+ weight: 3,
521
+ source: {
522
+ type: 'scan-summary', root: set.discovery.resolvedRoot, absolutePath: set.discovery.resolvedRoot,
523
+ },
524
+ addedBy: 'scan',
525
+ ingestRunId: set.runId,
526
+ });
527
+ const saved = await dataService.saveData(entry);
528
+ await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().embedAndPersist({
529
+ table: fam_table_type_enum_1.FAM_Table.knowledge, entry: saved, callType: 'embed-write',
530
+ });
531
+ }
532
+ }
533
+ // (b) reference-alias (a package-név + rövid alakok → a projekt scope-ja) — string/exact-match feloldás.
534
+ if (leaf) {
535
+ await this.persistProjectReference(identity, leaf, set.discovery.resolvedRoot, set.issuer);
536
+ }
537
+ fsm_dynamo_1.DyFM_Log.info(`[famIngest] project-identity (${scopeLabel}): `
538
+ + `${identity.packageName ?? '(nincs package.json)'}${identity.isGit ? ' [git]' : ''}`
539
+ + `${identity.gitRepo ? ` ${identity.gitRepo}` : ''}, ${identity.dependencies.length} függőség`);
540
+ }
541
+ /**
542
+ * A projekt reference-aliasának idempotens upsert-je (a package-név + rövid alakok + repo → a projekt
543
+ * scope-ja, `category:'project-identity'`). A meglévőt a `canonicalScopeRef.scopeId`-n találja (re-scankor
544
+ * frissít, nem duplikál). A package-nevek exact/string-match-en oldódnak (nincs szükség embed-re).
545
+ */
546
+ async persistProjectReference(identity, leaf, dirRoot, issuer) {
547
+ const referenceDataService = new scope_reference_2.FAM_Reference_DataService({ issuer: issuer });
548
+ const filter = { category: 'project-identity' };
549
+ filter['canonicalScopeRef.scopeId'] = leaf.scopeId;
550
+ const existing = await referenceDataService.findDataList(filter);
551
+ const model = new fam_reference_data_model_1.FAM_Reference_DataModel({
552
+ _id: existing[0]?._id,
553
+ canonicalTerm: identity.packageName ?? leaf.canonicalName,
554
+ aliasTerms: fam_project_identity_util_1.FAM_ProjectIdentity_Util.buildAliases(identity, path.basename(dirRoot), leaf.canonicalName),
555
+ description: identity.description
556
+ ?? `A(z) '${leaf.canonicalName}' projekt (${identity.packageName ?? 'nincs package.json'}).`,
557
+ category: 'project-identity',
558
+ scopeLayer: leaf.layer,
559
+ canonicalScopeRef: leaf,
560
+ });
561
+ await referenceDataService.saveData(model);
562
+ }
299
563
  // =========================================================================
300
564
  // helpers
301
565
  // =========================================================================
302
566
  /**
303
567
  * A fájl meglévő (nem soft-deleted) chunkjai a táron + scope-on belül (`Map`-elésre a delta-
304
568
  * kulcshoz, SP-4.3). A `findHydratableList` az aktívakat adja (a soft-delete-elteket kihagyja).
305
- * A scope-szűkítés a LEVÉL scopeId-jára (a write-path canonical scopePath-ot ír az entry-re).
569
+ * A fájl-identitás a KANONIKUS `source.absolutePath` (FAM-REV-050) scan-root-független, így a
570
+ * delta bármely scan-gyökérről ugyanazt a fájlt matcheli. A scope-szűkítés a LEVÉL scopeId-jára.
306
571
  */
307
- async loadExistingChunks(dataService, sourceFilePath, scopePath) {
308
- const filter = { sourceFilePath: sourceFilePath };
572
+ async loadExistingChunks(dataService, absolutePath, scopePath) {
573
+ const filter = {};
574
+ filter['source.absolutePath'] = absolutePath;
309
575
  if (scopePath.length) {
310
576
  const leaf = scopePath[scopePath.length - 1];
311
577
  filter['scopePath.scopeId'] = leaf.scopeId;
312
578
  }
313
579
  return dataService.findHydratableList(filter);
314
580
  }
581
+ /**
582
+ * Törölt-fájl reconciliation (whole-file orphan, dsgn-004 §4.3 kiterjesztés). A scan-folder/scan-project
583
+ * UTÁN a táron maradt, de a lemezről ELTŰNT fájlok chunkjait soft-delete-eli (+ pool-removeVector). A
584
+ * fájlon-BELÜLi chunk-törlést a `FAM_DeltaCompare_Util` `deleted` verdiktje kezeli; EZ a teljes fájl
585
+ * eltűnését (amit az újra-scan különben sosem látna, mert a bejárás csak a meglévő fájlokat találja).
586
+ *
587
+ * **Subtree-tudatos a KANONIKUS abszolút úton (FAM-REV-050):** a present-set a most bejárt fájlok
588
+ * `absolutePath`-jai; orphan = az a `scan`-forrású, aktív entry, aminek az `source.absolutePath`-ja a
589
+ * jelen scan-gyökér (`resolvedRoot`) ALATT van (`isInside`), DE NINCS a present-set-ben → a fájl eltűnt
590
+ * a gyökér alól. A subtree-szűkítés MOST az absolutePath-on (`isInside`), NEM a `source.root`-egyezésen —
591
+ * így egy al-mappa scan a tágabb gyökérről ingestelt, de a saját subtree-jébe eső fájlokat is helyesen
592
+ * reconciliálja (és kívülre sosem nyúl). Az `absolutePath` nélküli (régi, migrálatlan) entry-ket kihagyja
593
+ * (no-migration safe). `dryRun` → csak számol. Visszaadja a reconciliált (soft-deleted) chunkok számát.
594
+ */
595
+ async reconcileDeletedFiles(set) {
596
+ const presentPaths = new Set();
597
+ for (const routed of set.discovery.routedFiles) {
598
+ presentPaths.add(routed.absolutePath);
599
+ }
600
+ for (const skipped of set.discovery.skippedFiles) {
601
+ presentPaths.add(skipped.absolutePath);
602
+ }
603
+ const leafScopeId = set.scopePath.length ? set.scopePath[set.scopePath.length - 1].scopeId : undefined;
604
+ let reconciled = 0;
605
+ for (const table of set.discovery.tables) {
606
+ const registryEntry = embedding_1.FAM_StoreRegistry_Util.getEntry(table);
607
+ if (!registryEntry) {
608
+ continue;
609
+ }
610
+ const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: set.issuer });
611
+ const filter = {};
612
+ filter['source.type'] = 'scan';
613
+ if (leafScopeId) {
614
+ filter['scopePath.scopeId'] = leafScopeId;
615
+ }
616
+ const entries = await dataService.findHydratableList(filter);
617
+ for (const entry of entries) {
618
+ const absolutePath = entry.source?.absolutePath;
619
+ // Migrálatlan (absolutePath nélküli) entry → kihagyjuk; csak a jelen gyökér ALATTI fájlokat nézzük.
620
+ if (!entry._id || !absolutePath
621
+ || !fam_scan_path_util_1.FAM_ScanPath_Util.isInside(set.discovery.resolvedRoot, absolutePath)
622
+ || presentPaths.has(absolutePath)) {
623
+ continue;
624
+ }
625
+ // Orphan: a forrásfájl eltűnt a gyökér alól → soft-delete + pool-kivétel (FAM-REV-046 coherence).
626
+ if (!set.dryRun) {
627
+ await dataService.deleteData(entry._id);
628
+ embedding_1.FAM_VectorSearch_ControlService.getInstance().removeVector(table, entry._id);
629
+ }
630
+ reconciled++;
631
+ }
632
+ }
633
+ return reconciled;
634
+ }
315
635
  /** A verdikt-számok aggregálása a `FAM_IngestRun.verdicts`-be. */
316
636
  tallyVerdicts(verdicts, items) {
317
637
  for (const item of items) {
@@ -328,6 +648,11 @@ class FAM_Ingest_ControlService {
328
648
  const value = typeof resolved.value === 'number' ? resolved.value : 20;
329
649
  return Math.min(Math.max(value, 1), 200);
330
650
  }
651
+ /** Egy scan-szám-config feloldása a scope-kontextussal + fallback-kel (a `scan.estimateMsPerChunk` / `scan.progressIntervalMs`-hez). */
652
+ async resolveScanNumber(key, scopePath, fallback) {
653
+ const resolved = await config_control_service_1.FAM_Config_ControlService.getInstance().resolve(key, { scopePath: scopePath });
654
+ return typeof resolved.value === 'number' ? resolved.value : fallback;
655
+ }
331
656
  /**
332
657
  * A `failed` run-summary (a scope-resolve / felderítés bukásakor). A run rekord-mentés best-effort
333
658
  * (a hiba MÁR persistált); a hívónak a `failed` summary jelzi, hogy a scan nem futott le.
@@ -343,12 +668,16 @@ class FAM_Ingest_ControlService {
343
668
  };
344
669
  try {
345
670
  const runDataService = new fam_ingest_run_data_service_1.FAM_IngestRun_DataService({ issuer: this.issuer });
346
- await runDataService.open({
347
- runId: set.runId, trigger: set.request.operation, table: [],
671
+ // A `_id`-t a Dynamo generálja (ObjectId); a persistált run-rekordra a Dynamo-`_id`-vel
672
+ // hivatkozunk a `close`-ban (a client-UUID `findById`-dal nem cast-olható).
673
+ const openedRun = await runDataService.open({
674
+ trigger: set.request.operation, table: [],
348
675
  scopePath: set.scopePath, rootPath: set.request.path,
349
676
  });
677
+ const persistedRunId = openedRun._id ?? set.runId;
678
+ summary.ingestRunId = persistedRunId;
350
679
  await runDataService.close({
351
- runId: set.runId, table: [], filesProcessed: 0, filesSkipped: 0, chunkCount: 0,
680
+ runId: persistedRunId, table: [], filesProcessed: 0, filesSkipped: 0, chunkCount: 0,
352
681
  verdicts: summary.verdicts, durationMs: summary.durationMs, status: 'failed', errors: summary.errors,
353
682
  });
354
683
  }
@@ -4,11 +4,14 @@ exports.FAM_Scan_ControlService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs = tslib_1.__importStar(require("fs"));
6
6
  const path = tslib_1.__importStar(require("path"));
7
+ const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
7
8
  const config_catalog_const_1 = require("../../../_collections/config-catalog.const");
8
9
  const config_control_service_1 = require("../../../_routes/server/config/config.control-service");
10
+ const fam_famignore_util_1 = require("../_collections/fam-famignore.util");
9
11
  const fam_file_routing_util_1 = require("../_collections/fam-file-routing.util");
10
12
  const fam_glob_match_util_1 = require("../_collections/fam-glob-match.util");
11
13
  const fam_scan_path_util_1 = require("../_collections/fam-scan-path.util");
14
+ const fam_scan_weight_util_1 = require("../_collections/fam-scan-weight.util");
12
15
  const fam_secret_exclude_util_1 = require("../_collections/fam-secret-exclude.util");
13
16
  /**
14
17
  * `FAM_Scan_ControlService` (SP-4.1, dsgn-004 §1/§2/§6) — a `write(scan-*)` fájl-felderítő + routing
@@ -41,9 +44,17 @@ class FAM_Scan_ControlService {
41
44
  */
42
45
  async discover(set) {
43
46
  const resolvedRoot = fam_scan_path_util_1.FAM_ScanPath_Util.resolveRoot(set.path, this.issuer);
44
- const ignorePatterns = await this.resolveIgnorePatterns(set.scopePath, set.exclude);
47
+ // Effektív ignore: config `scan.ignorePatterns` + input `exclude` + a scan-GYÖKÉR `.fdpfamignore`-ja
48
+ // (in-repo, gitignore-szerű; folder/project scan-nél — a scan-file egyetlen explicit fájlt céloz). HOZZÁADÓDIK.
49
+ const baseIgnore = await this.resolveIgnorePatterns(set.scopePath, set.exclude);
50
+ const famIgnore = set.operation === 'scan-file' ? [] : fam_famignore_util_1.FAM_FamIgnore_Util.loadFromDir(resolvedRoot);
51
+ if (famIgnore.length) {
52
+ fsm_dynamo_1.DyFM_Log.info(`[famIngest] .fdpfamignore betöltve (${resolvedRoot}): ${famIgnore.length / 2} minta-sor`);
53
+ }
54
+ const ignorePatterns = [...baseIgnore, ...famIgnore];
45
55
  const maxFileSizeBytes = await this.resolveMaxFileSize(set.scopePath);
46
56
  const followSymlinks = await this.resolveFollowSymlinks(set.scopePath);
57
+ const testFileWeight = await this.resolveTestFileWeight(set.scopePath);
47
58
  const routedFiles = [];
48
59
  const skippedFiles = [];
49
60
  // A felderített abszolút fájlok (file = 1 db; folder/project = rekurzív bejárás).
@@ -61,6 +72,8 @@ class FAM_Scan_ControlService {
61
72
  includePatterns: set.include,
62
73
  maxFileSizeBytes: maxFileSizeBytes,
63
74
  tableOverride: set.tableOverride,
75
+ weights: set.weights,
76
+ testFileWeight: testFileWeight,
64
77
  });
65
78
  if (routed.route === 'skip') {
66
79
  skippedFiles.push(routed);
@@ -108,7 +121,12 @@ class FAM_Scan_ControlService {
108
121
  if (route === 'skip') {
109
122
  return { ...base, route: 'skip', skipReason: 'unrouted file-type' };
110
123
  }
111
- return { ...base, route: route };
124
+ // (6) Súly-kiemelés (FAM-REV-055/058): explicit scan-`weights` → az; különben teszt-/spec-fájl → a default
125
+ // `scan.testFileWeight` (a próza-nehéz specek ne rangsoroljanak az implementáció fölé); különben model-default.
126
+ return {
127
+ ...base, route: route,
128
+ weight: fam_scan_weight_util_1.FAM_ScanWeight_Util.resolveWithDefault(set.relativePath, set.weights, set.testFileWeight),
129
+ };
112
130
  }
113
131
  /**
114
132
  * Rekurzív könyvtár-bejárás (a `scan-folder`/`scan-project` felderítője). Az ignore-patterns a
@@ -207,5 +225,10 @@ class FAM_Scan_ControlService {
207
225
  const resolved = await config_control_service_1.FAM_Config_ControlService.getInstance().resolve('scan.followSymlinks', { scopePath: scopePath });
208
226
  return typeof resolved.value === 'boolean' ? resolved.value : false;
209
227
  }
228
+ /** A teszt-/spec-fájlok default súlya a config-ból (`scan.testFileWeight`, default 0.5 — FAM-REV-058). */
229
+ async resolveTestFileWeight(scopePath) {
230
+ const resolved = await config_control_service_1.FAM_Config_ControlService.getInstance().resolve('scan.testFileWeight', { scopePath: scopePath });
231
+ return typeof resolved.value === 'number' ? resolved.value : 0.5;
232
+ }
210
233
  }
211
234
  exports.FAM_Scan_ControlService = FAM_Scan_ControlService;
@@ -12,7 +12,7 @@
12
12
  * (MVP1 csak fájlnév-/útvonal-alapú secret-exclude).
13
13
  */
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.FAM_IngestRun_DataService = exports.FAM_ContentHash_Util = exports.FAM_DeltaCompare_Util = exports.FAM_SlidingChunker_Util = exports.FAM_MdChunker_Util = exports.FAM_TsChunker_Util = exports.FAM_Chunker_ControlService = exports.FAM_GlobMatch_Util = exports.FAM_SecretExclude_Util = exports.FAM_ScanPath_Util = exports.FAM_FileRouting_Util = exports.FAM_Scan_ControlService = exports.FAM_Ingest_ControlService = void 0;
15
+ exports.FAM_IngestRun_DataService = exports.FAM_ContentHash_Util = exports.FAM_DeltaCompare_Util = exports.FAM_SlidingChunker_Util = exports.FAM_MdChunker_Util = exports.FAM_TsChunker_Util = exports.FAM_Chunker_ControlService = exports.FAM_GlobMatch_Util = exports.FAM_SecretExclude_Util = exports.FAM_ScanPath_Util = exports.FAM_ScanProgress_Util = exports.FAM_FileRouting_Util = exports.FAM_Scan_ControlService = exports.FAM_Ingest_ControlService = void 0;
16
16
  // SP-4.4 — ingest-orchestrátor (a `write(scan-*)` belépési pontja + group-by-run/delete-run)
17
17
  var fam_ingest_control_service_1 = require("./_services/fam-ingest.control-service");
18
18
  Object.defineProperty(exports, "FAM_Ingest_ControlService", { enumerable: true, get: function () { return fam_ingest_control_service_1.FAM_Ingest_ControlService; } });
@@ -21,6 +21,8 @@ var fam_scan_control_service_1 = require("./_services/fam-scan.control-service")
21
21
  Object.defineProperty(exports, "FAM_Scan_ControlService", { enumerable: true, get: function () { return fam_scan_control_service_1.FAM_Scan_ControlService; } });
22
22
  var fam_file_routing_util_1 = require("./_collections/fam-file-routing.util");
23
23
  Object.defineProperty(exports, "FAM_FileRouting_Util", { enumerable: true, get: function () { return fam_file_routing_util_1.FAM_FileRouting_Util; } });
24
+ var fam_scan_progress_util_1 = require("./_collections/fam-scan-progress.util");
25
+ Object.defineProperty(exports, "FAM_ScanProgress_Util", { enumerable: true, get: function () { return fam_scan_progress_util_1.FAM_ScanProgress_Util; } });
24
26
  var fam_scan_path_util_1 = require("./_collections/fam-scan-path.util");
25
27
  Object.defineProperty(exports, "FAM_ScanPath_Util", { enumerable: true, get: function () { return fam_scan_path_util_1.FAM_ScanPath_Util; } });
26
28
  var fam_secret_exclude_util_1 = require("./_collections/fam-secret-exclude.util");