@futdevpro/fdp-agent-memory 0.1.0 → 1.1.14

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