@futdevpro/fdp-agent-memory 1.1.21 → 1.1.112

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 (89) hide show
  1. package/build/package.json +2 -2
  2. package/build/src/_cli/_commands/find-duplicates.command.js +41 -16
  3. package/build/src/_cli/_commands/scan-projects.command.js +113 -113
  4. package/build/src/_cli/_commands/scan.command.js +2 -0
  5. package/build/src/_cli/_commands/serve.command.js +110 -10
  6. package/build/src/_cli/_services/fam-client.service.js +25 -1
  7. package/build/src/_cli/register-commands.js +28 -0
  8. package/build/src/_collections/config-catalog.const.js +152 -33
  9. package/build/src/_collections/error-codes.const.js +2 -0
  10. package/build/src/_collections/fam-console.util.js +38 -260
  11. package/build/src/_collections/fam-db-models.const.js +2 -0
  12. package/build/src/_collections/fam-entry-bootstrap.util.js +20 -6
  13. package/build/src/_collections/fam-error-context.util.js +1 -0
  14. package/build/src/_collections/fam-mcp-bridge.util.js +15 -1
  15. package/build/src/_collections/fam-operation-queue.service.js +85 -0
  16. package/build/src/_collections/fam-project-discovery.util.js +148 -0
  17. package/build/src/_collections/fam-request-origin.util.js +41 -0
  18. package/build/src/_collections/fam-retry.util.js +48 -0
  19. package/build/src/_collections/fam-scan-progress-sink.service.js +26 -0
  20. package/build/src/_collections/title.const.js +26 -26
  21. package/build/src/_enums/fam-rule-scope.type-enum.js +25 -0
  22. package/build/src/_models/data-models/fam-entry.data-model.js +29 -0
  23. package/build/src/_models/data-models/fam-memory.data-model.js +5 -0
  24. package/build/src/_models/data-models/fam-rules.data-model.js +24 -0
  25. package/build/src/_models/data-models/fam-scan-job.data-model.js +73 -0
  26. package/build/src/_models/data-models/fam-scope.data-model.js +9 -0
  27. package/build/src/_modules/capture/_services/fam-auto-capture.control-service.js +1 -1
  28. package/build/src/_modules/embedding/_services/fam-dedup-warn.control-service.js +40 -0
  29. package/build/src/_modules/embedding/_services/fam-duplicate-scan.control-service.js +74 -16
  30. package/build/src/_modules/embedding/_services/fam-embedding-bootstrap.control-service.js +50 -0
  31. package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +32 -6
  32. package/build/src/_modules/embedding/_services/fam-embedding.control-service.js +142 -9
  33. package/build/src/_modules/embedding/_services/fam-entry.data-service.js +32 -1
  34. package/build/src/_modules/embedding/_services/fam-hydration-coordinator.control-service.js +159 -0
  35. package/build/src/_modules/embedding/_services/fam-lmstudio-embedding.provider.js +41 -4
  36. package/build/src/_modules/embedding/_services/fam-vector-search.control-service.js +67 -12
  37. package/build/src/_modules/embedding/index.js +5 -1
  38. package/build/src/_modules/ingest/_collections/fam-file-routing.util.js +10 -0
  39. package/build/src/_modules/ingest/_collections/fam-frontmatter.util.js +134 -0
  40. package/build/src/_modules/ingest/_collections/fam-project-identity.util.js +30 -0
  41. package/build/src/_modules/ingest/_collections/fam-scan-progress.util.js +5 -2
  42. package/build/src/_modules/ingest/_collections/fam-scan-summary.util.js +55 -29
  43. package/build/src/_modules/ingest/_collections/fam-split-chunker.util.js +139 -0
  44. package/build/src/_modules/ingest/_models/interfaces/fam-scan-job.interface.js +2 -0
  45. package/build/src/_modules/ingest/_services/fam-chunker.control-service.js +10 -0
  46. package/build/src/_modules/ingest/_services/fam-delta-compare.util.js +68 -1
  47. package/build/src/_modules/ingest/_services/fam-ingest-run.data-service.js +1 -1
  48. package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +177 -37
  49. package/build/src/_modules/ingest/_services/fam-scan-job.control-service.js +429 -0
  50. package/build/src/_modules/ingest/_services/fam-scan-job.data-service.js +34 -0
  51. package/build/src/_modules/ingest/_services/fam-scan.control-service.js +6 -4
  52. package/build/src/_modules/ingest/index.js +6 -1
  53. package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +1 -1
  54. package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +264 -41
  55. package/build/src/_modules/mcp/_services/fam-read-tool.service.js +71 -1
  56. package/build/src/_modules/mcp/_services/fam-write-tool.service.js +36 -0
  57. package/build/src/_modules/migration/_services/fam-claude-mem-import.control-service.js +1 -1
  58. package/build/src/_modules/retrieval/_collections/fam-lexical-match.util.js +69 -0
  59. package/build/src/_modules/retrieval/_collections/fam-memory-activation.util.js +66 -0
  60. package/build/src/_modules/retrieval/_collections/fam-rule-injection.util.js +125 -0
  61. package/build/src/_modules/retrieval/_collections/fam-rule-propagation.util.js +95 -0
  62. package/build/src/_modules/retrieval/_collections/fam-rule-scope-context.util.js +74 -0
  63. package/build/src/_modules/retrieval/_services/fam-global-rule.control-service.js +82 -0
  64. package/build/src/_modules/retrieval/_services/fam-memory-cold-search.control-service.js +121 -0
  65. package/build/src/_modules/retrieval/_services/fam-memory-dormancy.control-service.js +99 -0
  66. package/build/src/_modules/retrieval/_services/fam-memory-reactivation.control-service.js +68 -0
  67. package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +15 -2
  68. package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +197 -5
  69. package/build/src/_modules/retrieval/_services/fam-rule-injection.control-service.js +102 -0
  70. package/build/src/_modules/retrieval/index.js +12 -1
  71. package/build/src/_modules/scope-reference/_collections/fam-scope-maintenance.util.js +134 -0
  72. package/build/src/_modules/scope-reference/_services/fam-scope-maintenance.control-service.js +423 -0
  73. package/build/src/_modules/scope-reference/_services/fam-scope-resolver.control-service.js +2 -2
  74. package/build/src/_modules/scope-reference/_services/fam-scope.data-service.js +25 -0
  75. package/build/src/_modules/scope-reference/index.js +4 -1
  76. package/build/src/_routes/server/api/api.controller.js +324 -23
  77. package/build/src/_routes/server/api/fam-doctor.control-service.js +156 -0
  78. package/build/src/_routes/server/config/config.control-service.js +2 -2
  79. package/build/src/app.server.js +29 -27
  80. package/client-dist/{chunk-YXHWCJ5O.js → chunk-GF3FJP7E.js} +71 -71
  81. package/client-dist/chunk-NMUCMQY6.js +1 -0
  82. package/client-dist/favicon.ico +0 -0
  83. package/client-dist/index.html +3 -3
  84. package/client-dist/main-YK4YIVAQ.js +2 -0
  85. package/package.json +2 -2
  86. package/build/src/_cli/_collections/fam-project-discovery.util.js +0 -98
  87. package/build/src/_collections/fam-heap-guard.control-service.js +0 -176
  88. package/client-dist/chunk-I77GXVAQ.js +0 -1
  89. package/client-dist/main-PJPEDVJT.js +0 -2
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_LexicalMatch_Util = void 0;
4
+ /**
5
+ * `FAM_LexicalMatch_Util` (Hybrid Lexical Retrieval, Improvement 2) — **pure** lexikai (keyword/term-overlap) jel a
6
+ * retrieval-rangsorhoz. A tiszta-vektor `read` ELVÉTI a literal-keyword választ (eval-lelet: a „port naming" memória
7
+ * kiesett a top-12-ből, a `grep` azonnal hozta), mert az entry nyers koszinusza alacsony a query-megfogalmazásra.
8
+ * Ez a util a query DISZTINKTÍV term-jeinek átfedését méri az entry kereshető szövegével (content + heading + forrás-út),
9
+ * 0..1 skálán — a `toHit` ezt **multiplikatívan, BOOST-only** fűzi a finalScore-ba (`× (1 + keywordWeight × lexical)`),
10
+ * így a literal-match felszínre kerül, de a tiszta-szemantikus találat SOHA nem süllyed (lexical 0 → ×1).
11
+ */
12
+ class FAM_LexicalMatch_Util {
13
+ /** A heading/forrás-út egyezés extra súlya (erős „erről szól" jel): a base-átfedés MELLÉ adódik, 1-re vágva. */
14
+ static TITLE_PATH_BONUS = 0.3;
15
+ /** Minimális token-hossz (az 1-betűs/számjegyes zaj kihagyva). */
16
+ static MIN_TOKEN_LEN = 2;
17
+ /** Tömör stopword-szett (EN + HU — a korpusz Hunglish) — ezek NEM disztinktívek, kihagyva a query-termekből. */
18
+ static STOPWORDS = new Set([
19
+ // EN
20
+ 'the', 'a', 'an', 'of', 'to', 'in', 'on', 'at', 'by', 'for', 'and', 'or', 'is', 'are', 'be', 'as', 'we',
21
+ 'do', 'how', 'what', 'with', 'from', 'this', 'that', 'it', 'its', 'our', 'your', 'can', 'not', 'no', 'so',
22
+ 'if', 'then', 'else', 'into', 'out', 'up', 'down', 'about', 'which', 'who', 'when', 'where', 'why', 'use',
23
+ // HU
24
+ 'az', 'és', 'es', 'hogy', 'van', 'egy', 'nem', 'igen', 'de', 'mert', 'ami', 'amit', 'ez', 'azt', 'volt',
25
+ 'lesz', 'kell', 'meg', 'el', 'be', 'ki', 'le', 'fel', 'rá', 'ra', 'mi', 'te', 'ő', 'mit', 'hol',
26
+ ]);
27
+ /** Tokenizálás: kisbetűsít, nem-alfanumerikuson tör, stopword + rövid token kihagyva, DEDUP (Set). */
28
+ static tokenize(text) {
29
+ const terms = new Set();
30
+ if (!text) {
31
+ return terms;
32
+ }
33
+ for (const raw of text.toLowerCase().split(/[^a-z0-9]+/)) {
34
+ if (raw.length >= FAM_LexicalMatch_Util.MIN_TOKEN_LEN && !FAM_LexicalMatch_Util.STOPWORDS.has(raw)) {
35
+ terms.add(raw);
36
+ }
37
+ }
38
+ return terms;
39
+ }
40
+ /**
41
+ * Lexikai átfedés-score (0..1): a `queryTerms` hányad része van jelen az entry kereshető szövegében.
42
+ * `content`-egyezés = base-átfedés; `headingPath`/`sourceFilePath`-egyezés = + `TITLE_PATH_BONUS` súly (1-re vágva).
43
+ * Üres query-term-halmaz → 0 (nincs jel → nincs boost). PURE.
44
+ */
45
+ static score(queryTerms, entry) {
46
+ if (!queryTerms.size) {
47
+ return 0;
48
+ }
49
+ const titlePathText = `${(entry.headingPath ?? []).join(' ')} ${entry.sourceFilePath ?? ''}`;
50
+ const titlePathTerms = FAM_LexicalMatch_Util.tokenize(titlePathText);
51
+ const contentTerms = FAM_LexicalMatch_Util.tokenize(entry.content);
52
+ let baseMatched = 0;
53
+ let titleMatched = 0;
54
+ for (const term of queryTerms) {
55
+ const inTitlePath = titlePathTerms.has(term);
56
+ if (contentTerms.has(term) || inTitlePath) {
57
+ baseMatched++;
58
+ }
59
+ if (inTitlePath) {
60
+ titleMatched++;
61
+ }
62
+ }
63
+ const total = queryTerms.size;
64
+ const base = baseMatched / total;
65
+ const titleBonus = (titleMatched / total) * FAM_LexicalMatch_Util.TITLE_PATH_BONUS;
66
+ return Math.min(1, base + titleBonus);
67
+ }
68
+ }
69
+ exports.FAM_LexicalMatch_Util = FAM_LexicalMatch_Util;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_MemoryActivation_Util = void 0;
4
+ /**
5
+ * `FAM_MemoryActivation_Util` (dsgn-013 §2) — a Memory Activation Model **lazy-decay magja**, PURE. A `memory`-tár
6
+ * retrieval-rangsorához számolja a felidézés-alapú aktivációs szorzót: a frissen/gyakran felidézett memória
7
+ * felül-, a régóta érintetlen alul-rangsorol — DE sosem tűnik el (`floorWeight > 0`), csak kisebb a súlya.
8
+ *
9
+ * **Emberi-agy-analógia:** a felidézés megerősít (`frequencyBoost`, testing effect), a nem-felidézés lassan
10
+ * degradál (`recencyFactor`, Ebbinghaus-felejtési görbe). NINCS `Date.now()` a magban — a `nowMs` injektált
11
+ * (workflow-determinizmus + unit-stabilitás).
12
+ */
13
+ class FAM_MemoryActivation_Util {
14
+ /** Egy nap ms-ben. */
15
+ static MS_PER_DAY = 86_400_000;
16
+ /**
17
+ * A nyers aktiváció-összetevők (recency × frequency) egy memória-entryre. A `lastRecalledAt` hiánya → a `fallbackMs`
18
+ * (tipikusan a létrehozás ideje: cold-start kegyelmi idő). A `nowMs − lastRecalledAt` negatívra is védett (→ 0 nap).
19
+ */
20
+ static activation(set) {
21
+ const lastRecalled = typeof set.lastRecalledAt === 'number' ? set.lastRecalledAt : (set.fallbackMs ?? set.nowMs);
22
+ const ageDays = Math.max(0, set.nowMs - lastRecalled) / FAM_MemoryActivation_Util.MS_PER_DAY;
23
+ const halfLife = set.halfLifeDays > 0 ? set.halfLifeDays : 1;
24
+ const recencyFactor = Math.pow(0.5, ageDays / halfLife);
25
+ const recallCount = Math.max(0, set.recallCount ?? 0);
26
+ // CAP (eval-lelet): a nyers `1 + log2(1+recallCount)` korlátlan → plafonozzuk, hogy ne nyomja el a relevanciát.
27
+ const rawFrequencyBoost = 1 + Math.log2(1 + recallCount);
28
+ const frequencyBoost = (typeof set.maxFrequencyBoost === 'number' && set.maxFrequencyBoost > 0)
29
+ ? Math.min(rawFrequencyBoost, set.maxFrequencyBoost)
30
+ : rawFrequencyBoost;
31
+ return { recencyFactor: recencyFactor, frequencyBoost: frequencyBoost, activation: recencyFactor * frequencyBoost };
32
+ }
33
+ /**
34
+ * A retrieval-rankinghoz használt **decay-szorzó** (dsgn-013 §3): `max(floorWeight, activation)`. Ezt szorozza a
35
+ * `finalScore` a `memory`-táron (a `chunkFactor`/`sourceFactor` mellé). A `floorWeight` az alsó korlát — a régi
36
+ * memória lesüllyed, de a vektor-keresésben még megtalálható (a `weight ≤ 0 → kizárt` szabályt NEM lépi át).
37
+ */
38
+ static decayFactor(set) {
39
+ const activation = FAM_MemoryActivation_Util.activation({
40
+ lastRecalledAt: set.lastRecalledAt, recallCount: set.recallCount, nowMs: set.nowMs,
41
+ halfLifeDays: set.config.halfLifeDays, fallbackMs: set.fallbackMs,
42
+ maxFrequencyBoost: set.config.maxFrequencyBoost,
43
+ });
44
+ const raw = Math.max(set.config.floorWeight, activation.activation);
45
+ // TEMPER (eval-lelet 2026-06-25): a nyers szorzót az 1 felé húzzuk (`1 + α·(raw−1)`) → az aktiváció FINOMAN
46
+ // modulál, a koszinusz-relevancia dominál. α≥1 vagy hiányzó → változatlan (régi viselkedés, back-compat).
47
+ const alpha = set.config.activationWeight;
48
+ if (typeof alpha === 'number' && alpha >= 0 && alpha < 1) {
49
+ return 1 + alpha * (raw - 1);
50
+ }
51
+ return raw;
52
+ }
53
+ /**
54
+ * DORMANT-szabály (dsgn-013 §5.1, PURE) — egy memória ALVÓ-jelölt, ha **régóta nem-felidézett** (`ageDays ≥
55
+ * minAgeDays`) ÉS **ritkán-felidézett** (`recallCount < maxRecallCount`). A sokszor-felidézett (gyakran használt)
56
+ * memória SOHA nem dormant (a `recallCount`-gát védi). A `lastRecalledAt` hiányában a `fallbackMs` (létrehozás).
57
+ * Ez a szabály Mongo-kifejezhető (a `sweep` ugyanezt az age+recall kaput használja → konzisztens).
58
+ */
59
+ static isDormant(set) {
60
+ const lastRecalled = typeof set.lastRecalledAt === 'number' ? set.lastRecalledAt : (set.fallbackMs ?? set.nowMs);
61
+ const ageDays = Math.max(0, set.nowMs - lastRecalled) / FAM_MemoryActivation_Util.MS_PER_DAY;
62
+ const recallCount = Math.max(0, set.recallCount ?? 0);
63
+ return ageDays >= set.minAgeDays && recallCount < set.maxRecallCount;
64
+ }
65
+ }
66
+ exports.FAM_MemoryActivation_Util = FAM_MemoryActivation_Util;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_RuleInjection_Util = void 0;
4
+ const fam_rule_scope_type_enum_1 = require("../../../_enums/fam-rule-scope.type-enum");
5
+ /**
6
+ * `FAM_RuleInjection_Util` (Rules-Management MP-2) — a rule-injektálás **pure** (DB-/hálózat-mentes) magja:
7
+ * ① a kontextusból Mongo-prefilter `$or` (mely TIER-ek injektálódnak MOST), ② determinisztikus, `importance`-elsődleges
8
+ * rangsor, ③ char-budget-fit + „(…and N more rules not shown)" záró sor. A control-service végzi a DB-query-t és
9
+ * delegál ide — így a kontraktus (mely tier, milyen sorrend, hol vágunk) önállóan unit-tesztelhető.
10
+ *
11
+ * **Záró sor (user-FR):** valahányszor a budget miatt szabály marad ki, a blokk végén JELEZNI kell, hogy van több
12
+ * (NEM-aggresszív injektálás: a core befér, a többi „létezik" jelzéssel) — így az agent tudja, hogy `read`-elhet továbbiakat.
13
+ */
14
+ class FAM_RuleInjection_Util {
15
+ /** Default char-budget az injektált blokkra (a hook felül tudja írni). Tömör core ~ ennyibe fér. */
16
+ static DEFAULT_BUDGET_CHARS = 6000;
17
+ /** A `globalRule:true` legacy hard-rule effektív fontossága, ha nincs explicit `importance`. */
18
+ static LEGACY_GLOBAL_IMPORTANCE = 90;
19
+ /** Importance-default explicit érték nélkül (közepes — a globalRule-legacy fölött, nem-jelölt alatt). */
20
+ static DEFAULT_IMPORTANCE = 50;
21
+ /**
22
+ * A MOST érvényes TIER-ekhez tartozó Mongo-prefilter `$or` ágai (PURE). A `global` MINDIG; a többi a
23
+ * kontextustól függ. A legacy `globalRule:true` (MP-4 átsorolás ELŐTT) is bekerül — így a meglévő curated-core
24
+ * a migráció alatt is injektálódik. A `trigger`-tier SZÁNDÉKOSAN kimarad az always-on injektálásból (on-demand `read`).
25
+ */
26
+ static scopeOrBranches(context) {
27
+ const ors = [
28
+ { ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.global },
29
+ { globalRule: true },
30
+ ];
31
+ if (context.isFdp) {
32
+ ors.push({ ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.fdpGlobal });
33
+ }
34
+ if (context.inProject) {
35
+ ors.push({ ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.projectInternal });
36
+ if (context.projectType) {
37
+ ors.push({ ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.projectType, ruleScopeTopic: context.projectType });
38
+ }
39
+ }
40
+ else {
41
+ ors.push({ ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.workspaceRoot });
42
+ }
43
+ for (const topic of context.topics ?? []) {
44
+ ors.push({ ruleScope: fam_rule_scope_type_enum_1.FAM_RuleScope.trigger, ruleScopeTopic: topic });
45
+ }
46
+ return ors;
47
+ }
48
+ /** A teljes injektálás-prefilter (soft-delete + aktív + scope-`$or`). */
49
+ static buildFilter(context) {
50
+ return {
51
+ _deleted: null,
52
+ isActive: { $ne: false },
53
+ $or: FAM_RuleInjection_Util.scopeOrBranches(context),
54
+ };
55
+ }
56
+ /** Effektív fontosság (0–100): explicit `importance`, vagy legacy-globalRule → 90, egyébként 50. Clamp 0..100. */
57
+ static effectiveImportance(rule) {
58
+ const raw = typeof rule.importance === 'number'
59
+ ? rule.importance
60
+ : (rule.globalRule ? FAM_RuleInjection_Util.LEGACY_GLOBAL_IMPORTANCE : FAM_RuleInjection_Util.DEFAULT_IMPORTANCE);
61
+ return Math.max(0, Math.min(100, raw));
62
+ }
63
+ /**
64
+ * Determinisztikus injektálás-komparátor: effektív-importance DESC → weight DESC → category ASC →
65
+ * recency (`lastModifiedMs`) DESC → `id` ASC. A teljes lánc stabil, reprodukálható sorrendet ad.
66
+ */
67
+ static compare(a, b) {
68
+ const impDiff = FAM_RuleInjection_Util.effectiveImportance(b) - FAM_RuleInjection_Util.effectiveImportance(a);
69
+ if (impDiff !== 0) {
70
+ return impDiff;
71
+ }
72
+ const weightDiff = (b.weight ?? 1) - (a.weight ?? 1);
73
+ if (weightDiff !== 0) {
74
+ return weightDiff;
75
+ }
76
+ const catA = a.category ?? '';
77
+ const catB = b.category ?? '';
78
+ if (catA !== catB) {
79
+ return catA < catB ? -1 : 1;
80
+ }
81
+ const recA = a.lastModifiedMs ?? 0;
82
+ const recB = b.lastModifiedMs ?? 0;
83
+ if (recA !== recB) {
84
+ return recB - recA;
85
+ }
86
+ return (a.id ?? '') < (b.id ?? '') ? -1 : 1;
87
+ }
88
+ /** A jelöltek rangsorolva (új tömb; nem mutál). */
89
+ static rank(rules) {
90
+ return [...rules].sort(FAM_RuleInjection_Util.compare);
91
+ }
92
+ /**
93
+ * A rangsorolt szabályok char-budget-fit összefűzése + „(…and N more)" záró sor. Greedy: rangsor-sorrendben
94
+ * addig vesz fel, amíg a következő szabály content-je (a `separator`-ral) belefér. Ha a legelső sem fér, akkor is
95
+ * felveszi (legalább a legfontosabb core menjen). A footer csak akkor van, ha tényleg maradt ki.
96
+ */
97
+ static assemble(input) {
98
+ const budget = input.budgetChars && input.budgetChars > 0 ? input.budgetChars : FAM_RuleInjection_Util.DEFAULT_BUDGET_CHARS;
99
+ const sep = input.separator ?? '\n\n';
100
+ // CSAK a content-tel bíró szabályok a populáció — az üres-content entry NEM „budget miatt kihagyott" (nincs mit injektálni).
101
+ const ranked = FAM_RuleInjection_Util.rank(input.rules)
102
+ .filter((rule) => (rule.content ?? '').trim().length > 0);
103
+ const total = ranked.length;
104
+ const parts = [];
105
+ let used = 0;
106
+ let included = 0;
107
+ for (const rule of ranked) {
108
+ const text = (rule.content ?? '').trim();
109
+ const addLen = text.length + (parts.length ? sep.length : 0);
110
+ if (used + addLen > budget && included > 0) {
111
+ break; // budget-stop (de a legelső MINDIG befér — included>0 guard)
112
+ }
113
+ parts.push(text);
114
+ used += addLen;
115
+ included++;
116
+ }
117
+ const omitted = total - included;
118
+ const footer = omitted > 0
119
+ ? `(…and ${omitted} more rule${omitted === 1 ? '' : 's'} not shown — \`read\` the \`rules\` table for the rest.)`
120
+ : undefined;
121
+ const block = footer ? `${parts.join(sep)}${parts.length ? sep : ''}${footer}` : parts.join(sep);
122
+ return { block: block, includedCount: included, omittedCount: omitted, totalCount: total, footer: footer };
123
+ }
124
+ }
125
+ exports.FAM_RuleInjection_Util = FAM_RuleInjection_Util;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_RulePropagation_Util = void 0;
4
+ const fam_rule_scope_type_enum_1 = require("../../../_enums/fam-rule-scope.type-enum");
5
+ const fam_rule_injection_util_1 = require("./fam-rule-injection.util");
6
+ /**
7
+ * `FAM_RulePropagation_Util` (Rules-Management MP-5) — **pure** renderer + file-merger: a FAM-ban tárolt szabályokból
8
+ * egy generált, marker-keretezett blokkot képez a projekt-`CLAUDE.md`-be, hogy a **FAM-NÉLKÜLI** projekt-agentek is
9
+ * lássák a szabályokat. Dedup: `ruleId` (+ `derivedFrom` provenance) → 1 canonical entry/szabály (nem N duplikátum);
10
+ * `ruleId` nélkül content-alapú. A blokk scope szerint csoportosított + `importance` szerint rendezett.
11
+ *
12
+ * A merge IDEMPOTENS: a markerek között CSERÉL (update-if-stale), hiányzó marker → append (create-if-missing). A markeren
13
+ * KÍVÜLI kézi tartalmat sosem érinti.
14
+ */
15
+ class FAM_RulePropagation_Util {
16
+ static MARKER_START = '<!-- FAM-RULES (generated — do not edit by hand) -->';
17
+ static MARKER_END = '<!-- /FAM-RULES -->';
18
+ /** A scope-csoportok megjelenítési sorrendje + címe. */
19
+ static SCOPE_ORDER = [
20
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.global, title: 'Global (every system)' },
21
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.fdpGlobal, title: 'FDP-global (FDP ecosystem)' },
22
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.workspaceRoot, title: 'Workspace-root' },
23
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.projectInternal, title: 'Project-internal' },
24
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.projectType, title: 'Project-type' },
25
+ { scope: fam_rule_scope_type_enum_1.FAM_RuleScope.trigger, title: 'Trigger (context-specific)' },
26
+ ];
27
+ /**
28
+ * Dedup `ruleId` szerint: azonos `ruleId` → a legmagasabb effektív-importance-ű marad (a `derivedFrom`-propagált
29
+ * másolatok beolvadnak). `ruleId` nélküli szabályok content-prefix szerint deduplikálódnak. Új tömb (nem mutál).
30
+ */
31
+ static dedup(rules) {
32
+ const byKey = new Map();
33
+ for (const rule of rules) {
34
+ const key = rule.ruleId && rule.ruleId.trim().length
35
+ ? `id:${rule.ruleId.trim()}`
36
+ : `content:${(rule.content ?? '').trim().slice(0, 120)}`;
37
+ const existing = byKey.get(key);
38
+ if (!existing || fam_rule_injection_util_1.FAM_RuleInjection_Util.effectiveImportance(rule) > fam_rule_injection_util_1.FAM_RuleInjection_Util.effectiveImportance(existing)) {
39
+ byKey.set(key, rule);
40
+ }
41
+ }
42
+ return [...byKey.values()];
43
+ }
44
+ /** A generált blokk BELSŐ szövege (markerek nélkül): scope-csoportok, importance-rendezve. */
45
+ static renderBlock(rules, opts) {
46
+ const deduped = FAM_RulePropagation_Util.dedup(rules);
47
+ const lines = [];
48
+ lines.push(opts?.heading ?? '## FDP Agent Hard-Rules (synced from FAM)');
49
+ lines.push('');
50
+ lines.push('> Generated from the canonical rule set. Edit the rules in `documentations/rules/`, not here.');
51
+ for (const group of FAM_RulePropagation_Util.SCOPE_ORDER) {
52
+ const inScope = deduped
53
+ .filter((rule) => rule.ruleScope === group.scope)
54
+ .sort(fam_rule_injection_util_1.FAM_RuleInjection_Util.compare);
55
+ if (!inScope.length) {
56
+ continue;
57
+ }
58
+ lines.push('');
59
+ lines.push(`### ${group.title}`);
60
+ for (const rule of inScope) {
61
+ lines.push(FAM_RulePropagation_Util.formatRule(rule));
62
+ }
63
+ }
64
+ return lines.join('\n');
65
+ }
66
+ /** Egy szabály egy-soros bullet-je: `- **Title** (importance) — body`. */
67
+ static formatRule(rule) {
68
+ const content = (rule.content ?? '').trim();
69
+ const titleMatch = content.match(/^#{1,6}\s+(.+)$/m);
70
+ const title = titleMatch ? titleMatch[1].trim() : (rule.ruleId ?? 'rule');
71
+ const body = content.replace(/^#{1,6}\s+.+$/m, '').replace(/\s+/g, ' ').trim();
72
+ const importance = fam_rule_injection_util_1.FAM_RuleInjection_Util.effectiveImportance(rule);
73
+ return `- **${title}** (${importance})${body ? ` — ${body}` : ''}`;
74
+ }
75
+ /** A blokk marker-kerettel. */
76
+ static wrap(block) {
77
+ return `${FAM_RulePropagation_Util.MARKER_START}\n${block}\n${FAM_RulePropagation_Util.MARKER_END}`;
78
+ }
79
+ /**
80
+ * A wrapped blokk IDEMPOTENS beillesztése egy fájl-tartalomba: ha a markerek megvannak → a köztük lévő rész CSERÉL
81
+ * (a markeren kívüli kézi tartalom marad); ha nincs → a fájl VÉGÉRE fűzi (egy elválasztó üres sorral). Új string.
82
+ */
83
+ static mergeIntoFile(fileContent, wrappedBlock) {
84
+ const startIdx = fileContent.indexOf(FAM_RulePropagation_Util.MARKER_START);
85
+ const endIdx = fileContent.indexOf(FAM_RulePropagation_Util.MARKER_END);
86
+ if (startIdx >= 0 && endIdx > startIdx) {
87
+ const before = fileContent.slice(0, startIdx);
88
+ const after = fileContent.slice(endIdx + FAM_RulePropagation_Util.MARKER_END.length);
89
+ return `${before}${wrappedBlock}${after}`;
90
+ }
91
+ const base = fileContent.replace(/\s+$/, '');
92
+ return base.length ? `${base}\n\n${wrappedBlock}\n` : `${wrappedBlock}\n`;
93
+ }
94
+ }
95
+ exports.FAM_RulePropagation_Util = FAM_RulePropagation_Util;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_RuleScopeContext_Util = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const fam_project_discovery_util_1 = require("../../../_collections/fam-project-discovery.util");
7
+ /**
8
+ * `FAM_RuleScopeContext_Util` (MP-2) — a `cwd`-ből **pure** (csak fs-stat/olvasás, nincs hálózat/DB) levezeti, mely
9
+ * rule-TIER-ek érvényesek. Felfelé sétál a `cwd`-ből a legközelebbi projekt-gyökérig (`isProjectRoot`):
10
+ * - **inProject** = találtunk projekt-gyökeret a fán (a multi-projekt workspace-root NEM projekt-gyökér — nincs
11
+ * `package.json`/`.git` rajta —, így sosem téveszt projektnek).
12
+ * - **isFdp** = a legközelebbi projekt `package.json`-ja `@futdevpro` (név VAGY bármely dependency) → FDP-repo.
13
+ *
14
+ * A `projectType` SZÁNDÉKOSAN nem auto-detektált itt (a kanonikus projekt-típus-taxonómiát MP-4/MP-7 rögzíti) —
15
+ * explicit kontextusból jön. A `cwd` hiányában minden `false` (csak a `global` tier injektál → mindig helyes).
16
+ */
17
+ class FAM_RuleScopeContext_Util {
18
+ /** A felfelé-séta maximum mélysége (defenzív korlát; a tipikus projekt-mélység jóval ez alatt van). */
19
+ static MAX_WALK_UP = 12;
20
+ /** A `cwd`-ből levezetett kontextus (pure). */
21
+ static detect(cwd) {
22
+ if (!cwd || !cwd.trim()) {
23
+ return { isFdp: false, inProject: false };
24
+ }
25
+ const projectRoot = FAM_RuleScopeContext_Util.nearestProjectRoot(cwd);
26
+ if (!projectRoot) {
27
+ return { isFdp: false, inProject: false };
28
+ }
29
+ return {
30
+ isFdp: FAM_RuleScopeContext_Util.isFdpProject(projectRoot),
31
+ inProject: true,
32
+ projectName: fam_project_discovery_util_1.FAM_ProjectDiscovery_Util.projectName(projectRoot),
33
+ projectRoot: projectRoot,
34
+ };
35
+ }
36
+ /** A legközelebbi projekt-gyökér a `cwd`-ből felfelé (`isProjectRoot`), vagy `undefined`. */
37
+ static nearestProjectRoot(cwd) {
38
+ let dir = cwd;
39
+ for (let i = 0; i < FAM_RuleScopeContext_Util.MAX_WALK_UP; i++) {
40
+ if (fam_project_discovery_util_1.FAM_ProjectDiscovery_Util.isProjectRoot(dir)) {
41
+ return dir;
42
+ }
43
+ const parent = (0, path_1.dirname)(dir);
44
+ if (parent === dir) {
45
+ break; // elértük a fs-gyökeret
46
+ }
47
+ dir = parent;
48
+ }
49
+ return undefined;
50
+ }
51
+ /** FDP-projekt-e: a `package.json` `name` VAGY bármely dependency-kulcs `@futdevpro/`-val kezdődik. */
52
+ static isFdpProject(projectRoot) {
53
+ try {
54
+ const pkgPath = (0, path_1.join)(projectRoot, 'package.json');
55
+ if (!(0, fs_1.existsSync)(pkgPath)) {
56
+ return false;
57
+ }
58
+ const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8'));
59
+ if (typeof pkg.name === 'string' && pkg.name.startsWith('@futdevpro/')) {
60
+ return true;
61
+ }
62
+ return [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies].some((deps) => deps && typeof deps === 'object'
63
+ && Object.keys(deps).some((key) => key.startsWith('@futdevpro/')));
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ /** A projekt bare-neve (a `nearestProjectRoot` basenameje) — segéd a teszteknek/diagnosztikának. */
70
+ static basenameOf(path) {
71
+ return (0, path_1.basename)(path);
72
+ }
73
+ }
74
+ exports.FAM_RuleScopeContext_Util = FAM_RuleScopeContext_Util;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_GlobalRule_ControlService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
6
+ const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
7
+ const error_codes_const_1 = require("../../../_collections/error-codes.const");
8
+ const fam_error_factory_util_1 = require("../../../_collections/fam-error-factory.util");
9
+ const scope_reference_1 = require("../../scope-reference");
10
+ const embedding_1 = require("../../embedding");
11
+ const fam_rules_data_model_1 = require("../../../_models/data-models/fam-rules.data-model");
12
+ /**
13
+ * `FAM_GlobalRule_ControlService` (user-FR 2026-06-22 — a FAM fő feature-je: globális hard-rule öröklés) — a
14
+ * `rules`-bejegyzések `globalRule` flagjének BE-/KIkapcsolása. A `globalRule:true` bejegyzéseket a retrieval
15
+ * MINDEN scope-szűrt `rules`-lekérdezésbe behúzza (scope-tól függetlenül) → a workspace-szintű hard-rules
16
+ * (E2E-hard-rule, always-master, naming/import-konvenciók) öröklődnek minden al-scope-ba.
17
+ *
18
+ * A jelölés a Mongo `fam_rules`-on `updateMany` (a flag NEM érinti a vektor-poolt → nincs re-hidratálás, a
19
+ * következő lekérdezés már a frissített prefilteren megy). Szelektor: `ids` VAGY `scopeFilter` (a scope subtree
20
+ * minden rule-ja) VAGY `tags`. `dryRun` → csak az érintett-szám.
21
+ */
22
+ class FAM_GlobalRule_ControlService {
23
+ static _instance;
24
+ issuer = 'FAM_GlobalRule_ControlService';
25
+ static getInstance() {
26
+ if (!FAM_GlobalRule_ControlService._instance) {
27
+ FAM_GlobalRule_ControlService._instance = new FAM_GlobalRule_ControlService();
28
+ }
29
+ return FAM_GlobalRule_ControlService._instance;
30
+ }
31
+ /** A `globalRule` flag beállítása a szelektornak megfelelő `rules`-bejegyzéseken (`updateMany`). */
32
+ async setGlobalRule(input) {
33
+ const global = input.global !== false;
34
+ const dryRun = input.dryRun === true;
35
+ const filter = { _deleted: null };
36
+ const ors = [];
37
+ if (input.ids && input.ids.length) {
38
+ ors.push({ _id: { $in: input.ids } });
39
+ }
40
+ if (input.tags && input.tags.length) {
41
+ ors.push({ tags: { $in: input.tags } });
42
+ }
43
+ if (input.scopeFilter && input.scopeFilter.length) {
44
+ const expand = await scope_reference_1.FAM_ScopeResolver_ControlService.getInstance().expandForRead(input.scopeFilter);
45
+ if (expand.scopeIdSet && expand.scopeIdSet.length) {
46
+ ors.push({ 'scopePath.scopeId': { $in: expand.scopeIdSet } });
47
+ }
48
+ }
49
+ if (!ors.length) {
50
+ throw fam_error_factory_util_1.FAM_Error_Util.create({
51
+ errorCode: error_codes_const_1.FAM_ERROR_CODES.mcpDispatchUnknownCapability,
52
+ message: 'A `set_global_rule` szelektor KÖTELEZŐ: adj meg `ids` VAGY `scopeFilter` VAGY `tags` mezőt.',
53
+ issuer: this.issuer,
54
+ context: { operation: 'set-global-rule' },
55
+ });
56
+ }
57
+ filter.$or = ors;
58
+ const model = this.rulesModel();
59
+ if (!model) {
60
+ throw fam_error_factory_util_1.FAM_Error_Util.create({
61
+ errorCode: error_codes_const_1.FAM_ERROR_CODES.vecSearch,
62
+ message: 'A `fam_rules` model nincs regisztrálva (boot-előtt?).',
63
+ issuer: this.issuer,
64
+ context: { operation: 'set-global-rule' },
65
+ });
66
+ }
67
+ const matched = await model.countDocuments(filter);
68
+ let modified = 0;
69
+ if (!dryRun && matched > 0) {
70
+ const res = await model.updateMany(filter, { $set: { globalRule: global } });
71
+ modified = res.modifiedCount ?? 0;
72
+ fsm_dynamo_1.DyFM_Log.info(`[FAM globalRule] ${modified} rules-bejegyzés globalRule=${global} (matched ${matched}).`);
73
+ }
74
+ return { operation: 'set_global_rule', dryRun: dryRun, global: global, matched: matched, modified: modified };
75
+ }
76
+ /** A `fam_rules` mongoose-modellje (a DS-példányosítás regisztrálja). */
77
+ rulesModel() {
78
+ new embedding_1.FAM_Entry_DataService({ dataParams: fam_rules_data_model_1.famRules_dataParams, issuer: this.issuer });
79
+ return mongoose_1.default.models[fam_rules_data_model_1.famRules_dataParams.dataName];
80
+ }
81
+ }
82
+ exports.FAM_GlobalRule_ControlService = FAM_GlobalRule_ControlService;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_MemoryColdSearch_ControlService = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
6
+ const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
7
+ const embedding_1 = require("../../embedding");
8
+ const fam_memory_data_model_1 = require("../../../_models/data-models/fam-memory.data-model");
9
+ /**
10
+ * `FAM_MemoryColdSearch_ControlService` (dsgn-013 §5.3, MAM F3b) — az ALVÓ (`dormant`) memóriák COLD keresése. A
11
+ * dormant entry-k NINCSENEK a hot LVS-poolban (§5.2), ezért a normál read nem találja őket. Amikor a hot memória-
12
+ * találatok KEVESEK (a query a hot készletből nincs kielégítve), ez a szolgáltatás a dormant készleten Mongo-oldali
13
+ * koszinusz-keresést futtat (lassabb, de teljes), és a megtalált top-K-t **REAKTIVÁLJA** (`dormant=false` → a
14
+ * következő (re)hidratáláskor visszakerül a hot készletbe). „A dormant nem tűnik el, csak nincs a gyors úton."
15
+ *
16
+ * **Korlátozott:** a dormant scan a `maxCandidates`-re vágott (biztonsági memóriakorlát); a `scopeIdSet`-re szűkített.
17
+ */
18
+ class FAM_MemoryColdSearch_ControlService {
19
+ static _instance;
20
+ issuer = 'FAM_MemoryColdSearch_ControlService';
21
+ static getInstance() {
22
+ if (!FAM_MemoryColdSearch_ControlService._instance) {
23
+ FAM_MemoryColdSearch_ControlService._instance = new FAM_MemoryColdSearch_ControlService();
24
+ }
25
+ return FAM_MemoryColdSearch_ControlService._instance;
26
+ }
27
+ /**
28
+ * Cold-keresés a dormant memórián. Betölti a scope-szűrt dormant entry-ket (lean, vektorral, `maxCandidates`-ig),
29
+ * koszinusz-rangsort számol a query-vektorral, a top-K-t REAKTIVÁLJA, és visszaadja a `FAM_ColdHit`-eket. Üres
30
+ * query-vektor / nincs dormant / hiba → üres lista (best-effort, a read-et nem buktatja).
31
+ */
32
+ async search(set) {
33
+ if (!set.queryVector.length || set.topK <= 0) {
34
+ return [];
35
+ }
36
+ try {
37
+ const model = this.memoryModel();
38
+ if (!model) {
39
+ return [];
40
+ }
41
+ const filter = FAM_MemoryColdSearch_ControlService.buildColdFilter(set);
42
+ const dormant = await model.find(filter).limit(Math.max(1, set.maxCandidates)).lean().exec();
43
+ // KRITIKUS (_id-konzisztencia, ld. streamHydratableVectors): a `.lean()` NYERS ObjectId `_id`-t ad, de a
44
+ // hit-id-knak STRING-nek kell lenniük (a hot-hitek pool-/findDataList-id-jával egyezően) — különben a dedup
45
+ // (`seen.has`), a reaktiváció (`typeof id === 'string'` szűrő) és a wire-szerializáció elromlik.
46
+ for (const entry of dormant) {
47
+ if (entry._id) {
48
+ entry._id = String(entry._id);
49
+ }
50
+ }
51
+ // A reaktiváció/promóció NEM itt történik: a hívó (`reactivateReturnedMemoryHits`) a VÉGSŐ, topK-vágott
52
+ // result.hits-re fut → CSAK a ténylegesen visszaadott cold-hit promótálódik (dormant=false) + kap +1 recall,
53
+ // EGYSZER (nincs dupla-számolás, és a topK-ból kieső cold-jelölt NEM promótálódik fölöslegesen).
54
+ return FAM_MemoryColdSearch_ControlService.rankByCosine(set.queryVector, dormant, set.topK);
55
+ }
56
+ catch (error) {
57
+ fsm_dynamo_1.DyFM_Log.warn(`[FAM memoryColdSearch] cold-keresés sikertelen (best-effort): ${error?.message}`);
58
+ return [];
59
+ }
60
+ }
61
+ /**
62
+ * Koszinusz-rangsor (PURE, tesztelhető): a dimenzió-egyező vektorú entry-kre score-t számol, a 0 ≤ score-t kiejti,
63
+ * desc rendez, top-K. (A l2-normalizált vektorokon a koszinusz a valódi similarity — BFR-AM-007.)
64
+ */
65
+ static rankByCosine(queryVector, entries, topK) {
66
+ const hits = [];
67
+ for (const entry of entries) {
68
+ const vector = (entry.contentVector ?? []);
69
+ if (vector.length !== queryVector.length) {
70
+ continue;
71
+ }
72
+ const score = FAM_MemoryColdSearch_ControlService.cosineSimilarity(queryVector, vector);
73
+ if (score > 0) {
74
+ hits.push({ entry: entry, score: score });
75
+ }
76
+ }
77
+ hits.sort((a, b) => b.score - a.score);
78
+ return hits.slice(0, Math.max(0, topK));
79
+ }
80
+ /**
81
+ * A cold-keresés Mongo-filtere (PURE, tesztelhető): dormant + completed + AKTÍV (`_deleted: null`) + scope/tag/kind
82
+ * prefilter (UGYANAZ, mint a hot-path `findActiveCandidates`/`loadCandidates`). **KRITIKUS:** `_deleted: null` (NEM
83
+ * `{$ne: true}`) — a `_deleted` DATE-mező; a mongoose a boolean `true`-t nem tudja Date-re castolni ("Cast to date
84
+ * failed") → a teljes cold-keresés elhalt (live-lelet 2026-06-24). A tag/kind nélkül a cold-supplement a query által
85
+ * EXPLICIT kiszűrt entry-ket is visszahozná.
86
+ */
87
+ static buildColdFilter(set) {
88
+ const filter = { dormant: true, embeddingStatus: 'completed', _deleted: null };
89
+ if (set.scopeIdSet.length) {
90
+ filter['scopePath.scopeId'] = { $in: set.scopeIdSet };
91
+ }
92
+ if (set.tagFilter && set.tagFilter.length) {
93
+ filter.tags = { $in: set.tagFilter };
94
+ }
95
+ if (set.kindFilter) {
96
+ filter.kind = set.kindFilter;
97
+ }
98
+ return filter;
99
+ }
100
+ /** Koszinusz-similarity két azonos-dimenziójú vektor között (0..1). */
101
+ static cosineSimilarity(a, b) {
102
+ let dot = 0;
103
+ let normA = 0;
104
+ let normB = 0;
105
+ for (let i = 0; i < a.length; i++) {
106
+ dot += a[i] * b[i];
107
+ normA += a[i] * a[i];
108
+ normB += b[i] * b[i];
109
+ }
110
+ if (!normA || !normB) {
111
+ return 0;
112
+ }
113
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
114
+ }
115
+ /** A `fam_memory` mongoose-modellje (a DS-példányosítás regisztrálja). */
116
+ memoryModel() {
117
+ new embedding_1.FAM_Entry_DataService({ dataParams: fam_memory_data_model_1.famMemory_dataParams, issuer: this.issuer });
118
+ return mongoose_1.default.models[fam_memory_data_model_1.famMemory_dataParams.dataName];
119
+ }
120
+ }
121
+ exports.FAM_MemoryColdSearch_ControlService = FAM_MemoryColdSearch_ControlService;