@futdevpro/fdp-agent-memory 1.1.30 → 1.1.113

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 (81) hide show
  1. package/build/package.json +1 -1
  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 +160 -6
  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/_enums/fam-rule-scope.type-enum.js +25 -0
  21. package/build/src/_models/data-models/fam-entry.data-model.js +29 -0
  22. package/build/src/_models/data-models/fam-memory.data-model.js +5 -0
  23. package/build/src/_models/data-models/fam-rules.data-model.js +24 -0
  24. package/build/src/_models/data-models/fam-scan-job.data-model.js +73 -0
  25. package/build/src/_models/data-models/fam-scope.data-model.js +9 -0
  26. package/build/src/_modules/embedding/_services/fam-dedup-warn.control-service.js +40 -0
  27. package/build/src/_modules/embedding/_services/fam-duplicate-scan.control-service.js +74 -16
  28. package/build/src/_modules/embedding/_services/fam-embedding-bootstrap.control-service.js +50 -0
  29. package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +31 -5
  30. package/build/src/_modules/embedding/_services/fam-embedding.control-service.js +142 -9
  31. package/build/src/_modules/embedding/_services/fam-entry.data-service.js +9 -0
  32. package/build/src/_modules/embedding/_services/fam-hydration-coordinator.control-service.js +159 -0
  33. package/build/src/_modules/embedding/_services/fam-lmstudio-embedding.provider.js +41 -4
  34. package/build/src/_modules/embedding/_services/fam-vector-search.control-service.js +67 -12
  35. package/build/src/_modules/embedding/index.js +5 -1
  36. package/build/src/_modules/ingest/_collections/fam-file-routing.util.js +10 -0
  37. package/build/src/_modules/ingest/_collections/fam-frontmatter.util.js +134 -0
  38. package/build/src/_modules/ingest/_collections/fam-project-identity.util.js +30 -0
  39. package/build/src/_modules/ingest/_collections/fam-scan-progress.util.js +5 -2
  40. package/build/src/_modules/ingest/_collections/fam-scan-summary.util.js +55 -29
  41. package/build/src/_modules/ingest/_collections/fam-split-chunker.util.js +139 -0
  42. package/build/src/_modules/ingest/_models/interfaces/fam-scan-job.interface.js +2 -0
  43. package/build/src/_modules/ingest/_services/fam-chunker.control-service.js +10 -0
  44. package/build/src/_modules/ingest/_services/fam-delta-compare.util.js +68 -1
  45. package/build/src/_modules/ingest/_services/fam-ingest-run.data-service.js +1 -1
  46. package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +173 -37
  47. package/build/src/_modules/ingest/_services/fam-scan-job.control-service.js +429 -0
  48. package/build/src/_modules/ingest/_services/fam-scan-job.data-service.js +34 -0
  49. package/build/src/_modules/ingest/_services/fam-scan.control-service.js +6 -4
  50. package/build/src/_modules/ingest/index.js +6 -1
  51. package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +151 -8
  52. package/build/src/_modules/mcp/_services/fam-read-tool.service.js +70 -0
  53. package/build/src/_modules/mcp/_services/fam-write-tool.service.js +36 -0
  54. package/build/src/_modules/retrieval/_collections/fam-lexical-match.util.js +69 -0
  55. package/build/src/_modules/retrieval/_collections/fam-memory-activation.util.js +66 -0
  56. package/build/src/_modules/retrieval/_collections/fam-rule-injection.util.js +125 -0
  57. package/build/src/_modules/retrieval/_collections/fam-rule-propagation.util.js +95 -0
  58. package/build/src/_modules/retrieval/_collections/fam-rule-scope-context.util.js +74 -0
  59. package/build/src/_modules/retrieval/_services/fam-global-rule.control-service.js +82 -0
  60. package/build/src/_modules/retrieval/_services/fam-memory-cold-search.control-service.js +121 -0
  61. package/build/src/_modules/retrieval/_services/fam-memory-dormancy.control-service.js +99 -0
  62. package/build/src/_modules/retrieval/_services/fam-memory-reactivation.control-service.js +68 -0
  63. package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +15 -2
  64. package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +216 -5
  65. package/build/src/_modules/retrieval/_services/fam-rule-injection.control-service.js +102 -0
  66. package/build/src/_modules/retrieval/index.js +12 -1
  67. package/build/src/_modules/scope-reference/_collections/fam-scope-maintenance.util.js +76 -0
  68. package/build/src/_modules/scope-reference/_services/fam-scope-maintenance.control-service.js +233 -0
  69. package/build/src/_modules/scope-reference/_services/fam-scope.data-service.js +25 -0
  70. package/build/src/_routes/server/api/api.controller.js +270 -0
  71. package/build/src/_routes/server/api/fam-doctor.control-service.js +156 -0
  72. package/build/src/app.server.js +13 -10
  73. package/client-dist/{chunk-YXHWCJ5O.js → chunk-GF3FJP7E.js} +71 -71
  74. package/client-dist/chunk-NMUCMQY6.js +1 -0
  75. package/client-dist/favicon.ico +0 -0
  76. package/client-dist/index.html +3 -3
  77. package/client-dist/main-YK4YIVAQ.js +2 -0
  78. package/package.json +1 -1
  79. package/build/src/_cli/_collections/fam-project-discovery.util.js +0 -98
  80. package/client-dist/chunk-I77GXVAQ.js +0 -1
  81. package/client-dist/main-PJPEDVJT.js +0 -2
@@ -9,6 +9,7 @@ const app_server_1 = require("../app.server");
9
9
  const package_json_1 = require("../../package.json");
10
10
  const mcp_1 = require("../_modules/mcp");
11
11
  const fam_client_service_1 = require("../_cli/_services/fam-client.service");
12
+ const serve_command_1 = require("../_cli/_commands/serve.command");
12
13
  const register_commands_1 = require("../_cli/register-commands");
13
14
  const fam_console_util_1 = require("./fam-console.util");
14
15
  const fam_mcp_bridge_util_1 = require("./fam-mcp-bridge.util");
@@ -92,6 +93,23 @@ class FAM_EntryBootstrap_Util {
92
93
  fsm_dynamo_1.DyFM_Log.warn(`[FAM] már fut egy egészséges FAM-primary (${client.getBaseUrl()}${versionTag}) — a második REST-boot kihagyva.${versionNote}`);
93
94
  return;
94
95
  }
96
+ if (isStart && !serverAlreadyRunning) {
97
+ // AUTO-ENSURE (user-FR 2026-06-22: „minden fam funkciónak gondoskodnia kell a fam elindításáról"). Az MCP-
98
+ // stdio process NE a heavy REST-primary-t bootolja IN-PROCESS (az OOM-nál MEGHAL → a Claude-reconnect crash-
99
+ // loop-ol), hanem húzzon fel egy LEVÁLASZTOTT primary-t (túléli a reconnectet) és BRIDGE-eljen hozzá. A
100
+ // `waitMs:1` csak a spawn-t INDÍTJA (nem várja a teljes pool-bootot) → az MCP-handshake (ListTools, ami nem
101
+ // igényli a primary-t) AZONNAL kész; a tool-CALL-ok a bridge-önhealen várnak/retry-znek a boot-ra.
102
+ const ensured = await serve_command_1.FAM_Serve_Util.ensureRunning({ waitMs: 1 });
103
+ const spawnUnavailable = ensured.reason === 'no-entry' || ensured.reason === 'spawn-failed' || ensured.reason === 'remote-unreachable';
104
+ if (!spawnUnavailable) {
105
+ fsm_dynamo_1.DyFM_Log.info(`[FAM] auto-ensure: leválasztott primary (${ensured.reason}, ${ensured.url}) → MCP-stdio BRIDGE `
106
+ + '(a primary a háttérben bootol; a tool-hívások önhealnek).');
107
+ await fam_mcp_bridge_util_1.FAM_McpBridge_Util.start({ name: MCP_SERVER_NAME, version: package_json_1.version });
108
+ return;
109
+ }
110
+ // A leválasztott spawn nem indítható (nincs belépő / spawn-hiba / remote-URL) → VISSZA a bevált in-process PRIMARY-ra.
111
+ fsm_dynamo_1.DyFM_Log.warn(`[FAM] auto-ensure: a leválasztott primary nem indítható (${ensured.reason}) → in-process PRIMARY boot (fallback).`);
112
+ }
95
113
  // PRIMARY-jelölt (nincs egészséges futó primary). Port pre-flight: ha a portot MÁS tartja (egy nem-FAM
96
114
  // process, VAGY egy fél-halott FAM-szerver, ami már nem válaszol a `/api/health`-en), a kötés EADDRINUSE-
97
115
  // szal bukna egy nyers stack-kel. Ehelyett TISZTA, akcióképes hibát adunk és kilépünk (nem crashelünk).
@@ -105,14 +123,10 @@ class FAM_EntryBootstrap_Util {
105
123
  }
106
124
  // PRIMARY (nincs futó szerver, a port szabad) — a teljes szerver felhúzása.
107
125
  fsm_dynamo_1.DyFM_Log.info(`[FAM] PRIMARY mód: nincs futó FAM-primary → teljes szerver felhúzása (REST :${SERVER_PORT}`
108
- + `${isStart ? ' + MCP stdio' : ''}). Activity-monitor: ${fam_console_util_1.FAM_Console_Util.isEnabled() ? 'ON' : 'OFF'}`
109
- + `${fam_console_util_1.FAM_Console_Util.isEnabled() ? ` (${fam_console_util_1.FAM_Console_Util.isVerbose() ? 'VERBOSE — minden log' : 'kurált'})` : ''}.`);
126
+ + `${isStart ? ' + MCP stdio' : ''}).`);
110
127
  // File-log (FAM_LOG_FILE): a `fam serve` ezt állítja be → a detached szerver logjai (köztük az
111
- // import-progress) FÁJLBÓL OLVASHATÓK (tail), a monitor-ablak nélkül is. Fail-safe, env-gated.
128
+ // import-progress) FÁJLBÓL OLVASHATÓK (tail) a látható szerver-ablak MELLETT. Fail-safe, env-gated.
112
129
  fam_console_util_1.FAM_Console_Util.installFileLog();
113
- // (FEAT-001) A PRIMARY egy KÜLÖN, látható activity-konzol-ablakot nyit (env-gated, fail-safe,
114
- // docker-ben OFF). Az MCP-stdio JSON-RPC csatornát NEM érinti (külön monitor-process tail-el).
115
- fam_console_util_1.FAM_Console_Util.openActivityConsole({ port: SERVER_PORT });
116
130
  // (1) REST szerver felhúzása (a DyNTS_App ctor indítja a connect + setup + postProcess láncot;
117
131
  // a DyNTS_App a side-effect-konstruktor mintát követi — az `index.ts` is így indít).
118
132
  FAM_EntryBootstrap_Util.startRestApp();
@@ -37,6 +37,7 @@ class FAM_ErrorContext_Util {
37
37
  FAM_ErrorContext_Util.setNumber(snapshot, 'chunkIndex', input.chunkIndex);
38
38
  FAM_ErrorContext_Util.setString(snapshot, 'query', input.query);
39
39
  FAM_ErrorContext_Util.setString(snapshot, 'provider', input.provider);
40
+ FAM_ErrorContext_Util.setString(snapshot, 'failedSample', input.failedSample);
40
41
  // Ha minden mező hiányzott, NINCS snapshot (a rekordon nem jelenik meg üres objektum).
41
42
  return Object.keys(snapshot).length ? snapshot : undefined;
42
43
  }
@@ -4,6 +4,7 @@ exports.FAM_McpBridge_Util = void 0;
4
4
  const fam_core_tools_const_1 = require("../_modules/mcp/_collections/fam-core-tools.const");
5
5
  const fam_mcp_adapter_service_1 = require("../_modules/mcp/_services/fam-mcp-adapter.service");
6
6
  const fam_client_service_1 = require("../_cli/_services/fam-client.service");
7
+ const serve_command_1 = require("../_cli/_commands/serve.command");
7
8
  /**
8
9
  * `FAM_McpBridge_Util` (FEAT-002, topology „egy szerver, sok bridge") — ha `fam start`-kor MÁR fut egy
9
10
  * FAM-szerver (primary, REST a 39265-ön), az új process NEM bootol második szervert (port-ütközés +
@@ -31,7 +32,20 @@ class FAM_McpBridge_Util {
31
32
  description: tool.description,
32
33
  inputSchema: tool.inputSchema,
33
34
  handler: async (args) => {
34
- const result = await client.post(`/api/${tool.name}`, args ?? {});
35
+ let result = await client.post(`/api/${tool.name}`, args ?? {});
36
+ // ÖNHEAL (user-FR 2026-06-22): ha a primary időközben leesett (`unreachable`), NE bukjunk némán —
37
+ // automatikusan felhúzzuk a leválasztott primary-t (`ensureRunning`) és EGYSZER újrapróbáljuk. Ha a
38
+ // primary épp bootol (pool-hidratálás), tiszta „indul, próbáld újra" hibát adunk (a következő hívás megy).
39
+ if (!result.ok && result.unreachable) {
40
+ const ensured = await serve_command_1.FAM_Serve_Util.ensureRunning();
41
+ if (ensured.running) {
42
+ result = await client.post(`/api/${tool.name}`, args ?? {});
43
+ }
44
+ else if (ensured.reason === 'boot-timeout') {
45
+ throw new Error('FAM-MCP-BRIDGE-002: A FAM primary most indul (pool-hidratálás folyamatban) — '
46
+ + 'próbáld újra pár másodperc múlva. (Az auto-indítás már elindult, leválasztva.)');
47
+ }
48
+ }
35
49
  if (!result.ok) {
36
50
  // A primary hibáját MCP-hibaként felszínre hozzuk (NEM némítjuk; dsgn-008).
37
51
  const code = result.error?.errorCode ?? 'FAM-MCP-BRIDGE-001';
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_OperationQueue_Service = void 0;
4
+ /**
5
+ * `FAM_OperationQueue_Service` (FEAT-008, user-FR 2026-06-22) — **szerver-oldali soros/limitált-konkurrencia QUEUE**
6
+ * a NEHÉZ műveletekhez (scan/import/re-embed). A user-direktíva: a SZERVER vezérelje, hogy egyszerre NE fusson túl
7
+ * sok nehéz művelet — ha több agenttől egyidejű write-parancsok érkeznek, a szerver SORBA rakja (FIFO) és úgy
8
+ * dolgozza fel, NEM párhuzamosan. (Ez okozta a `war-factory`/`warbots` átfedést: a kliens-oldali orchestráció
9
+ * desync-elt — a kliens timeout-olt egy hosszú scant és elindította a következőt, miközben a szerver az elsőt még
10
+ * darálta. Ezzel a queue-val a 2. write MEGVÁRJA az elsőt → soros, átfedés-mentes feldolgozás a kliens-káosztól
11
+ * függetlenül.)
12
+ *
13
+ * Egyszerű async-szemafór: `maxConcurrency` default **1** (teljes szerializáció a nehéz ops-ra). A könnyű ops
14
+ * (create/update/delete/read) NEM mennek ezen át (gyorsak, nincs korrupciós kockázat). Statikus singleton —
15
+ * process-szintű (egy szerver = egy queue). Bukott task is felszabadít (finally) → nem akad meg a queue.
16
+ */
17
+ class FAM_OperationQueue_Service {
18
+ /** A process-szintű singleton. */
19
+ static instance;
20
+ /** A singleton elérése (lazy). */
21
+ static getInstance() {
22
+ if (!FAM_OperationQueue_Service.instance) {
23
+ FAM_OperationQueue_Service.instance = new FAM_OperationQueue_Service();
24
+ }
25
+ return FAM_OperationQueue_Service.instance;
26
+ }
27
+ /** A konkurrencia-plafon (≥1). Default 1 = teljes szerializáció (egyszerre egy nehéz művelet). */
28
+ maxConcurrency = 1;
29
+ /** Hány task fut épp. */
30
+ running = 0;
31
+ /** A szabad slot-ra várók resolver-ei (FIFO sor). */
32
+ waiters = [];
33
+ /** A konkurrencia-plafon állítása (≥1). Növelésnél azonnal besorolja a várakozókat. */
34
+ setMaxConcurrency(value) {
35
+ this.maxConcurrency = Math.max(1, Math.floor(value));
36
+ this.drain();
37
+ }
38
+ /** Observability (a `/health`-be / progress-be köthető): hány fut + hány vár + a plafon. */
39
+ stats() {
40
+ return { running: this.running, queued: this.waiters.length, maxConcurrency: this.maxConcurrency };
41
+ }
42
+ /**
43
+ * A `task` BESOROLÁSA: megvárja a szabad slot-ot (FIFO), lefuttatja, majd felszabadít. A hiba is felszabadít
44
+ * (`finally`) — egy bukott task NEM akasztja meg a queue-t. A visszatérés a task eredménye (átlátszó wrapper).
45
+ */
46
+ async enqueue(task) {
47
+ await this.acquire();
48
+ try {
49
+ return await task();
50
+ }
51
+ finally {
52
+ this.release();
53
+ }
54
+ }
55
+ /** Slot-foglalás: ha van szabad → azonnal; különben FIFO-sorba (a resolver a `drain`-ben fut le). */
56
+ acquire() {
57
+ if (this.running < this.maxConcurrency) {
58
+ this.running++;
59
+ return Promise.resolve();
60
+ }
61
+ return new Promise((resolve) => {
62
+ this.waiters.push(resolve);
63
+ });
64
+ }
65
+ /** Slot-felszabadítás + a következő várakozó besorolása. */
66
+ release() {
67
+ this.running = Math.max(0, this.running - 1);
68
+ this.drain();
69
+ }
70
+ /** A szabad slot-okra besorol a várakozókból (FIFO), amíg van hely ÉS van várakozó. */
71
+ drain() {
72
+ while (this.running < this.maxConcurrency && this.waiters.length > 0) {
73
+ const next = this.waiters.shift();
74
+ if (next) {
75
+ this.running++;
76
+ next();
77
+ }
78
+ }
79
+ }
80
+ /** TESZT-only: a singleton eldobása (friss állapot a spec-ekhez). */
81
+ static resetForTest() {
82
+ FAM_OperationQueue_Service.instance = undefined;
83
+ }
84
+ }
85
+ exports.FAM_OperationQueue_Service = FAM_OperationQueue_Service;
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_ProjectDiscovery_Util = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const fam_famignore_util_1 = require("../_modules/ingest/_collections/fam-famignore.util");
7
+ const fam_glob_match_util_1 = require("../_modules/ingest/_collections/fam-glob-match.util");
8
+ /**
9
+ * `FAM_ProjectDiscovery_Util` (FEAT-008: a szerver-oldali scan-orchestráció magja, áthelyezve `_cli`→`_collections`)
10
+ * — projekt-gyökerek **auto-felderítése** egy mappa alatt + a config JSON-lista parse-je. PURE (fs-olvasás, nincs
11
+ * hálózat). A scope-nevet a `package.json` `name`-jéből deriválja, fallback a dir-név.
12
+ *
13
+ * **Felderítés-szabály:** egy könyvtár PROJEKT-GYÖKÉR, ha van `package.json` VAGY `.git`. Ott MEGÁLLUNK — EGY SCOPE
14
+ * PER REPO (user-decision 2026-06-24): a monorepo (`server`/`client`/`cli`/`e2e`) MIND egy közös repo-scope-ba kerül,
15
+ * NEM bontjuk al-csomag-scope-okra. A scope NEVE: monorepónál (van saját-markerű al-csomag) a REPO-DIR neve (a root
16
+ * `package.json` neve félrevezető lehet — pl. `@futdevpro/ccap` a `ccap-revisioned` monorepóra); egy-csomagos LEAF
17
+ * projektnél a `package.json` `name` bare alakja (a természetes identitás). A `node_modules` + rejtett mappák +
18
+ * `SKIP_DIRS` + `.fdpfamignore` kihagyva.
19
+ */
20
+ class FAM_ProjectDiscovery_Util {
21
+ /** A projekt-gyökér markerek (bármelyik megléte → projekt). */
22
+ static MARKERS = ['package.json', '.git'];
23
+ /**
24
+ * A felderítésből MINDIG KIHAGYOTT könyvtárnevek (user-direktíva 2026-06-24, KRITIKUS — „SEMMIT nem akarunk
25
+ * szkennelni, ami a Stale-ben van!!!"). A `.fdpfamignore`-tól FÜGGETLEN, GARANTÁLT hard-skip: a `STALE-projects/`
26
+ * (archív/elavult projektek, pl. `fury` — 18757 fájl, „mind új" → halálra terheli az embedding-providert) +
27
+ * a `TEMPLATE-projects/` (`{{PROJECT_NAME}}` sablon-junk) + a `logs/` SOHA nem felderítendők. A `.`-mappák +
28
+ * `node_modules` külön (a startsWith('.') feltétel). Case-SENSITIVE (a workspace mappanevek pontos alakja).
29
+ */
30
+ static SKIP_DIRS = new Set([
31
+ 'node_modules', 'STALE-projects', 'TEMPLATE-projects', 'logs',
32
+ ]);
33
+ /** Projekt-gyökér-e a könyvtár (van `package.json` vagy `.git`). */
34
+ static isProjectRoot(dir) {
35
+ return FAM_ProjectDiscovery_Util.MARKERS.some((marker) => (0, fs_1.existsSync)((0, path_1.join)(dir, marker)));
36
+ }
37
+ /** A scope leaf-név: a `package.json` `name` bare alakja (`@scope/x` → `x`), vagy a dir-név. */
38
+ static projectName(dir) {
39
+ try {
40
+ const pkgPath = (0, path_1.join)(dir, 'package.json');
41
+ if ((0, fs_1.existsSync)(pkgPath)) {
42
+ const name = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf-8')).name;
43
+ if (typeof name === 'string' && name.trim()) {
44
+ return name.trim().replace(/^@[^/]+\//, '');
45
+ }
46
+ }
47
+ }
48
+ catch {
49
+ // fallback a dir-névre
50
+ }
51
+ return (0, path_1.basename)(dir);
52
+ }
53
+ /**
54
+ * Projekt-gyökerek felderítése `root` alatt `maxDepth`-ig. Ha a `root` maga projekt → csak az. Egyébként
55
+ * rekurzívan a nem-rejtett alkönyvtárakban (egy projekt-gyökérnél MEGÁLL). Determinisztikus (név szerint rendezett).
56
+ */
57
+ static discover(root, maxDepth, defaults) {
58
+ const result = [];
59
+ // A `.fdpfamignore` a FELDERÍTÉSRE is érvényes (user-FR 2026-06-22 — KRITIKUS bugfix): a famignore-olt mappákba
60
+ // (pl. a `Stale`-archív) NEM megyünk be, így a bennük lévő projekteket (pl. `fury`) NEM is fedezzük fel. A globok
61
+ // ROOT-relatívak (a `loadFromDir` baseDir-prefixe); a root + a nested famignore akkumulálódik a leszálláskor.
62
+ const relRoot = (dir) => (0, path_1.relative)(root, dir).replace(/\\/g, '/');
63
+ // A `dir` szűrt (nem-rejtett, nem-SKIP_DIRS, nem-famignore-olt) közvetlen al-KÖNYVTÁRAI (nevek). A
64
+ // monorepo-al-csomag-kereséshez ÉS a nem-projekt-leszálláshoz közös.
65
+ const filteredChildDirs = (dir, allGlobs) => {
66
+ let entries;
67
+ try {
68
+ entries = (0, fs_1.readdirSync)(dir).sort();
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ const dirs = [];
74
+ for (const name of entries) {
75
+ if (name.startsWith('.') || FAM_ProjectDiscovery_Util.SKIP_DIRS.has(name)) {
76
+ continue;
77
+ }
78
+ const child = (0, path_1.join)(dir, name);
79
+ try {
80
+ if (!(0, fs_1.statSync)(child).isDirectory()) {
81
+ continue;
82
+ }
83
+ }
84
+ catch {
85
+ continue; // olvashatatlan bejegyzés → kihagyjuk
86
+ }
87
+ // FAMIGNORE-szűrés: a root-relatív útvonal VAGY a puszta mappanév egy ignore-globra illeszkedik → kihagyjuk.
88
+ const childRel = relRoot(child);
89
+ if (fam_glob_match_util_1.FAM_GlobMatch_Util.matchesAny(childRel, allGlobs) || fam_glob_match_util_1.FAM_GlobMatch_Util.matchesAny(name, allGlobs)) {
90
+ continue;
91
+ }
92
+ dirs.push(name);
93
+ }
94
+ return dirs;
95
+ };
96
+ const visit = (dir, depth, ignoreGlobs) => {
97
+ if (depth > maxDepth) {
98
+ return;
99
+ }
100
+ // E könyvtár saját `.fdpfamignore`-ja (a root-relatív base-szel) → akkumulálva a leszármazottakra (a
101
+ // projekt-gyökérre IS, hogy a monorepo-leszálláskor + az al-csomag-keresésnél is érvényesüljön).
102
+ const localGlobs = fam_famignore_util_1.FAM_FamIgnore_Util.loadFromDir(dir, depth === 0 ? '' : relRoot(dir));
103
+ const allGlobs = localGlobs.length ? [...ignoreGlobs, ...localGlobs] : ignoreGlobs;
104
+ const childDirs = filteredChildDirs(dir, allGlobs);
105
+ if (FAM_ProjectDiscovery_Util.isProjectRoot(dir)) {
106
+ // ONE SCOPE PER REPO (user-decision 2026-06-24): a projekt-gyökeret EGY scope-ként vesszük fel, és NEM
107
+ // megyünk beljebb — a monorepo (server/client/cli/e2e) MIND egy közös repo-scope-ba kerül (nincs
108
+ // al-csomag-split, nincs lumpolás-aggály: szándékosan EGY repo = EGY scope). A scope NEVE: ha a gyökér
109
+ // alatt VAN saját-markerű al-csomag (FDP-monorepo), akkor a REPO-DIR neve — mert a root `package.json`
110
+ // neve félrevezető lehet (pl. `@futdevpro/ccap` a `ccap-revisioned` monorepóra → bare `ccap` → a téves
111
+ // `ccap-client` scope-ra oldódott). Egy-csomagos LEAF projektnél a `package.json` `name` (a természetes
112
+ // identitás → az NPM-package-ek scope-jai NEM neveződnek át). A monorepo-detekció depth-független
113
+ // (egy szinttel lejjebb nézünk; nem descend-elünk, ezért a maxDepth itt nem korlát).
114
+ const hasSubPackage = childDirs.some((name) => FAM_ProjectDiscovery_Util.isProjectRoot((0, path_1.join)(dir, name)));
115
+ result.push({
116
+ path: dir,
117
+ project: hasSubPackage ? (0, path_1.basename)(dir) : FAM_ProjectDiscovery_Util.projectName(dir),
118
+ org: defaults?.org, table: defaults?.table,
119
+ });
120
+ return; // one scope per repo: nem megyünk beljebb
121
+ }
122
+ for (const name of childDirs) {
123
+ visit((0, path_1.join)(dir, name), depth + 1, allGlobs);
124
+ }
125
+ };
126
+ visit(root, 0, []);
127
+ return result;
128
+ }
129
+ /** A config JSON-lista → projekt-spec-ek (validálva: `path` + `project` kötelező soronként). */
130
+ static parseConfig(content) {
131
+ const parsed = JSON.parse(content);
132
+ if (!Array.isArray(parsed)) {
133
+ throw new Error('A scan-projects config egy JSON-tömb legyen: [{ "path": "...", "project": "..." }, ...]');
134
+ }
135
+ return parsed.map((raw, index) => {
136
+ const entry = (raw && typeof raw === 'object') ? raw : {};
137
+ if (typeof entry.path !== 'string' || typeof entry.project !== 'string') {
138
+ throw new Error(`A config[${index}] hiányos: a 'path' és a 'project' (string) kötelező.`);
139
+ }
140
+ return {
141
+ path: entry.path, project: entry.project,
142
+ org: typeof entry.org === 'string' ? entry.org : undefined,
143
+ table: typeof entry.table === 'string' ? entry.table : undefined,
144
+ };
145
+ });
146
+ }
147
+ }
148
+ exports.FAM_ProjectDiscovery_Util = FAM_ProjectDiscovery_Util;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_RequestOrigin_Util = void 0;
4
+ /**
5
+ * `FAM_RequestOrigin_Util` (user-FR 2026-06-25) — egy FAM-esemény INDÍTÓJÁNAK aláírását (`FAM_AgentOrigin`) oldja fel a
6
+ * HTTP-kérésből: az `X-FAM-Session` / `X-FAM-Agent` / `X-FAM-Workspace` / `X-FAM-Label` headerekből VAGY a body `origin`
7
+ * mezőjéből (a body PER-MEZŐ felülír — explicit > header). Így a hívó (hook / `fam` CLI / agent) ALÁÍRJA az általa
8
+ * indított eseményt → több, EGYIDEJŰ workspace-session is megkülönböztethető. Aláírás teljes hiányában `agent:'unknown'`.
9
+ *
10
+ * A szerver NEM tudja kitalálni az identitást (a lokál portot minden session azonos forrásból éri el) — ezért a
11
+ * SZERZŐDÉS: a hívó adja meg. A FDP-agentek konvenciója: a CC `session_id`-t küldik az `X-FAM-Session` headerben.
12
+ */
13
+ class FAM_RequestOrigin_Util {
14
+ /** A támogatott aláírás-headerek (kisbetűs — az Express így adja a `req.headers`-t). */
15
+ static HEADERS = [
16
+ { key: 'sessionId', header: 'x-fam-session' },
17
+ { key: 'agent', header: 'x-fam-agent' },
18
+ { key: 'workspace', header: 'x-fam-workspace' },
19
+ { key: 'label', header: 'x-fam-label' },
20
+ ];
21
+ /** A kérés (header + opcionális body-`origin`) → feloldott `FAM_AgentOrigin` (body felülír; üresnél `agent:'unknown'`). */
22
+ static fromRequest(req, bodyOrigin) {
23
+ const merged = {};
24
+ for (const entry of FAM_RequestOrigin_Util.HEADERS) {
25
+ const fromBody = bodyOrigin ? bodyOrigin[entry.key] : undefined;
26
+ const value = (fromBody && fromBody.trim()) ? fromBody.trim() : FAM_RequestOrigin_Util.header(req, entry.header);
27
+ if (value) {
28
+ merged[entry.key] = value;
29
+ }
30
+ }
31
+ const hasAny = Object.values(merged).some((value) => !!value);
32
+ return hasAny ? merged : { agent: 'unknown' };
33
+ }
34
+ /** Egy header string-értéke (trimmelve), vagy `undefined`. Tömb-header (ritka) első eleme. */
35
+ static header(req, name) {
36
+ const raw = req.headers[name];
37
+ const value = Array.isArray(raw) ? raw[0] : raw;
38
+ return value && value.trim() ? value.trim() : undefined;
39
+ }
40
+ }
41
+ exports.FAM_RequestOrigin_Util = FAM_RequestOrigin_Util;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_Retry_Util = void 0;
4
+ /**
5
+ * `FAM_Retry_Util` — általános, ÚJRAHASZNÁLHATÓ retry-exponenciális-backoff helper a TRANZIENS hibákra
6
+ * (stresszteszt-lelet 2026-06-22: konkurrens terhelés alatt a remote embedding-provider ritkán megakadt → a
7
+ * teljes read elbukott egyetlen tranziens hibán). Pure-vezérelt (a `fn` async művelet + opciók), így a backoff
8
+ * `baseBackoffMs:0`-val determinisztikusan + gyorsan unit-tesztelhető.
9
+ *
10
+ * Az `isRetryable` predikátum dönti el, mi tranziens: a determinisztikus hibák (pl. validáció, dimenzió-mismatch)
11
+ * NEM retry-zhetők (azonnal dobnak), csak a hálózati/provider-átmenetiek. Az `onRetry` callback observability-re
12
+ * (warn-log) — a util maga NEM logol (függőség-mentes).
13
+ */
14
+ class FAM_Retry_Util {
15
+ /**
16
+ * A `fn` futtatása `maxAttempts`-szor, exponenciális backoff-fal (`baseBackoffMs × 2^(n-1)`, `maxBackoffMs`-re
17
+ * kapozva) a próbálkozások KÖZÖTT. Siker → az eredmény. Ha az `isRetryable` `false`-t ad egy hibára → AZONNAL
18
+ * dobja (nincs további próba). A próbálkozások kimerülése → az UTOLSÓ hibát dobja (no-silent-failure).
19
+ */
20
+ static async withRetry(fn, options) {
21
+ const maxAttempts = Math.max(1, Math.floor(options.maxAttempts));
22
+ const base = options.baseBackoffMs ?? 250;
23
+ const cap = options.maxBackoffMs ?? 1000;
24
+ let lastError;
25
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
26
+ try {
27
+ return await fn();
28
+ }
29
+ catch (error) {
30
+ lastError = error;
31
+ if (options.isRetryable && !options.isRetryable(error)) {
32
+ throw error;
33
+ }
34
+ if (attempt < maxAttempts) {
35
+ const backoffMs = Math.min(cap, base * 2 ** (attempt - 1));
36
+ if (options.onRetry) {
37
+ options.onRetry(attempt, backoffMs, error);
38
+ }
39
+ if (backoffMs > 0) {
40
+ await new Promise((resolveSleep) => setTimeout(resolveSleep, backoffMs));
41
+ }
42
+ }
43
+ }
44
+ }
45
+ throw lastError;
46
+ }
47
+ }
48
+ exports.FAM_Retry_Util = FAM_Retry_Util;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_ScanProgress_Sink = void 0;
4
+ /**
5
+ * `FAM_ScanProgress_Sink` (FEAT-008 sub-progress, user-FR 2026-06-22) — a LEGUTÓBBI projekten-belüli haladás
6
+ * process-szintű holder-e. Mivel az operation-queue szerializál (egyszerre EGY projekt ingestál), egyetlen „latest"
7
+ * elég. Az ingest a throttle-olt progress-emitkor frissíti; a scan-job a `getStatus`-ban beolvassa → a thin-CLI
8
+ * poll is látja a within-project haladást (nem csak a per-projekt befejezést). Statikus, állapot-minimal.
9
+ */
10
+ class FAM_ScanProgress_Sink {
11
+ /** A legutóbbi haladás-pillanatkép (vagy undefined, ha még nem volt / törölve). */
12
+ static latest;
13
+ /** A legutóbbi haladás beállítása (az ingest hívja a progress-emitnél). */
14
+ static set(progress) {
15
+ FAM_ScanProgress_Sink.latest = progress;
16
+ }
17
+ /** A legutóbbi haladás (a scan-job status-hoz). */
18
+ static get() {
19
+ return FAM_ScanProgress_Sink.latest;
20
+ }
21
+ /** A holder ürítése (teszt / projekt-váltás). */
22
+ static clear() {
23
+ FAM_ScanProgress_Sink.latest = undefined;
24
+ }
25
+ }
26
+ exports.FAM_ScanProgress_Sink = FAM_ScanProgress_Sink;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_RuleScope = void 0;
4
+ /**
5
+ * `FAM_RuleScope` (Rules-Management System, MP-1) — egy szabály ALKALMAZHATÓSÁGI osztálya: HOL érvényes + injektálódik.
6
+ * (Megkülönböztetve a `scopePath`-tól, ami a scope-ENTITÁS-lánc — itt a rule always-apply TIER-jéről van szó.)
7
+ *
8
+ * - `global` — univerzális; MINDEN rendszerre (FDP + nem-FDP), root ÉS in-project. Mindig injektált.
9
+ * - `fdpGlobal` — FDP-ökoszisztéma-specifikus (FDP CLI, Keystore, bedrock, Dynamo/NTS, FAM, @futdevpro). Csak FDP-repóban.
10
+ * - `workspaceRoot` — CSAK a multi-projekt workspace root-szinten (orchestráció / cross-project / devops).
11
+ * - `projectInternal` — minden projektben, amikor az agent a projekt-workspace-en belül dolgozik.
12
+ * - `projectType` — projekt-TÍPUS szerint (a `ruleScopeTopic` adja a típust, pl. `ngx`/`nts`/`server`/`client`).
13
+ * - `trigger` — on-demand, kontextus/téma szerint (a `ruleScopeTopic` a téma; a rule-fetch-reflex hozza elő).
14
+ *
15
+ * Konvenció: `keyNameIsCamelCase = 'value-is-kebab-case'`.
16
+ */
17
+ var FAM_RuleScope;
18
+ (function (FAM_RuleScope) {
19
+ FAM_RuleScope["global"] = "global";
20
+ FAM_RuleScope["fdpGlobal"] = "fdp-global";
21
+ FAM_RuleScope["workspaceRoot"] = "workspace-root";
22
+ FAM_RuleScope["projectInternal"] = "project-internal";
23
+ FAM_RuleScope["projectType"] = "project-type";
24
+ FAM_RuleScope["trigger"] = "trigger";
25
+ })(FAM_RuleScope || (exports.FAM_RuleScope = FAM_RuleScope = {}));
@@ -22,6 +22,14 @@ class FAM_Entry extends fsm_dynamo_1.DyFM_Metadata {
22
22
  kind;
23
23
  /** Többes kategorizálás (dsgn-001 §3); per-tár ajánlott vokabulár, de szabadon bővül. */
24
24
  tags = [];
25
+ /**
26
+ * **GLOBÁLIS HARD-RULE** jelölő (user-FR 2026-06-22 — a FAM egyik fő feature-je): ha `true`, ez a (jellemzően
27
+ * `rules`-táras) bejegyzés MINDEN scope-szűrt lekérdezésbe BEKERÜL, scope-tól FÜGGETLENÜL — a workspace-szintű
28
+ * hard-rules (pl. E2E-hard-rule, always-master, naming/import-konvenciók) így öröklődnek MINDEN al-scope rule-
29
+ * lekérdezésébe. A retrieval candidate-prefilter `$or`-ral húzza be (`scopePath.scopeId $in subtree` VAGY
30
+ * `globalRule:true`). Default `false` (a legtöbb rule scope-specifikus); a hard-rules EXPLICIT jelölést kapnak.
31
+ */
32
+ globalRule;
25
33
  // --- tartalom + embedding ---
26
34
  /** A vektorizált, ember-olvasható szöveg (kanonikus mező — dsgn-001 §2). */
27
35
  content;
@@ -49,6 +57,27 @@ class FAM_Entry extends fsm_dynamo_1.DyFM_Metadata {
49
57
  weight = 1;
50
58
  /** Opcionális kvalitatív hangsúly (0..1). */
51
59
  importance;
60
+ // --- Memory Activation Model (dsgn-013, CSAK a `memory` táron értelmezett) ---
61
+ /**
62
+ * Az utolsó FELIDÉZÉS (recall) epoch-ms-e — a lazy recency-decay bemenete (dsgn-013 §2). A `read` által
63
+ * visszaadott top-K memory-hitre frissül (F2). Default a létrehozás ideje (cold-start kegyelmi idő: egy
64
+ * frissen-szkennelt RÉGI memória ne tűnjön azonnal dormant-nak). NEM-memory táron értelmetlen (decayFactor=1).
65
+ */
66
+ lastRecalledAt;
67
+ /** Hányszor lett FELIDÉZVE (dsgn-013 §2) — a telítődő frequency-megerősítés bemenete (`1 + log2(1+recallCount)`). */
68
+ recallCount = 0;
69
+ /**
70
+ * ALVÓ-e (dsgn-013 §5): a degradáció-küszöb alá esett, régóta nem-felidézett memória — NEM hidratálódik a hot
71
+ * LVS-poolba (RAM-/boot-spórolás), de Mongo-oldali COLD kereséssel elérhető (+ megtalálásakor reaktiválódik).
72
+ * SOHA nem jelent törlést (a tartalom megmarad). Indexelt a `memory` data-paramsban (a hidratálás-szűrőhöz).
73
+ */
74
+ dormant;
75
+ /**
76
+ * LEVÁLTOTT-e (superseded, dsgn-013 §6, MAM F4): egy additív (`memory`) fájl RÉGI tartalma, amit egy újabb
77
+ * szken átírt/kivett (pl. kompaktálás). NEM törlés — megőrizve + cold-kereshető, de a ranking penalizálja
78
+ * (`memory.supersededPenalty`), így a friss verzió fölébe kerül. A content-addressed additív delta jelöli.
79
+ */
80
+ superseded;
52
81
  // --- forrás / pozíció (scan/import esetén) ---
53
82
  /** Provenance (dsgn-001 §6). */
54
83
  source;
@@ -51,5 +51,10 @@ exports.famMemory_dataParams = new fsm_dynamo_1.DyFM_DataModel_Params({
51
51
  runId: { type: 'string', index: true },
52
52
  instanceId: { type: 'string', index: true },
53
53
  summarizedEntryIds: { type: 'string[]', default: [] },
54
+ // Memory Activation Model (dsgn-013) — CSAK a memory táron perzisztált. `dormant` indexelt a hidratálás-szűrőhöz.
55
+ lastRecalledAt: { type: 'number' },
56
+ recallCount: { type: 'number', default: 0 },
57
+ dormant: { type: 'boolean', index: true },
58
+ superseded: { type: 'boolean', index: true },
54
59
  },
55
60
  });
@@ -10,6 +10,14 @@ const fam_entry_data_model_1 = require("./fam-entry.data-model");
10
10
  * A `FAM_Entry` bázisra épül; per-tár mezők: `category` (== `kind`), `isActive` (inaktív szabály
11
11
  * NEM retrieve-elődik), `applicableScopes` (üres = globális), `dimensions`.
12
12
  * `kind` default `'rule'`, `isActive` default `true` (dsgn-001 §4).
13
+ *
14
+ * **Rules-Management System (MP-1)** — injektálás-aware mezők:
15
+ * - `ruleScope`/`ruleScopeTopic` — always-apply TIER (lásd `FAM_RuleScope`); a `<topic>` suffix a
16
+ * `projectType`/`trigger` esetén külön (`ruleScopeTopic`, pl. `'ngx'` / `'docker'`).
17
+ * - `userApproved` — a user EGYESÉVEL jóváhagyta-e (a curated-core hard-rule gate-je).
18
+ * - `ruleId` — stabil, ember-olvasható azonosító (pl. `'G-trace'`, `'PI3'`) — propagáció/dedup kulcs.
19
+ * - `derivedFrom` — ha propagált/származtatott: a kanonikus forrás-`ruleId` (dedup → 1 canonical + N provenance).
20
+ * - `importance` (a bázison) a rules-rendszerben **0–100** skálán rangsorol injektáláskor (MP-2).
13
21
  */
14
22
  class FAM_Rules_DataModel extends fam_entry_data_model_1.FAM_Entry {
15
23
  /** Kategória (== `kind`; pl. `'coding'` / `'project'` / `'naming'`). */
@@ -20,6 +28,16 @@ class FAM_Rules_DataModel extends fam_entry_data_model_1.FAM_Entry {
20
28
  applicableScopes = [];
21
29
  /** Dimenziók (`server`|`client`|`fullstack`|`devops`|`testing`). */
22
30
  dimensions = [];
31
+ /** Always-apply TIER osztály (MP-1; `FAM_RuleScope`). Üres = nincs besorolva (legacy / nem-tier). */
32
+ ruleScope;
33
+ /** A `projectType`/`trigger` TIER témája (pl. `'ngx'` / `'docker'`); más tier-eknél üres. */
34
+ ruleScopeTopic;
35
+ /** A user EGYESÉVEL approve-olta-e (curated-core hard-rule gate). */
36
+ userApproved = false;
37
+ /** Stabil, ember-olvasható azonosító (pl. `'G-trace'`, `'PI3'`) — propagáció/dedup kulcs. */
38
+ ruleId;
39
+ /** Propagált/származtatott szabálynál a kanonikus forrás-`ruleId` (dedup-provenance). */
40
+ derivedFrom;
23
41
  constructor(set) {
24
42
  super(set);
25
43
  if (set) {
@@ -45,7 +63,13 @@ exports.famRules_dataParams = new fsm_dynamo_1.DyFM_DataModel_Params({
45
63
  },
46
64
  category: { type: 'string', index: true },
47
65
  isActive: { type: 'boolean', index: true, default: true },
66
+ globalRule: { type: 'boolean', index: true },
48
67
  applicableScopes: { type: 'array', default: [] },
49
68
  dimensions: { type: 'string[]', index: true, default: [] },
69
+ ruleScope: { type: 'string', index: true },
70
+ ruleScopeTopic: { type: 'string', index: true },
71
+ userApproved: { type: 'boolean', index: true, default: false },
72
+ ruleId: { type: 'string', index: true },
73
+ derivedFrom: { type: 'string', index: true },
50
74
  },
51
75
  });
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.famScanJob_dataParams = exports.FAM_ScanJob_DataModel = void 0;
4
+ const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
5
+ /**
6
+ * `FAM_ScanJob_DataModel` (FEAT-008 Phase 4, user-FR 2026-06-22) — egy szerver-oldali scan-job DURABLE pillanatképe
7
+ * a `fam_scan_jobs` collection-ben. Cél: a job (per-projekt állapottal) TÚLÉLJE a server-restart/crash/close-t, és a
8
+ * szerver **AUTO-RESUME-olja a megszakítási ponttól** (a már `ok` projekteket átugorva). A `projects[]` a per-projekt
9
+ * checkpoint (státusz + eredmény); a `specs[]` az újrafuttatáshoz kell (path/project/org/table). `extends DyFM_Metadata`.
10
+ *
11
+ * A `jobId` a UUID (mező, indexelt) — NEM a `_id` (a Dynamo a `_id`-t ObjectId-ra cast-olja, a client-UUID nem fér).
12
+ */
13
+ class FAM_ScanJob_DataModel extends fsm_dynamo_1.DyFM_Metadata {
14
+ /** A job UUID-ja (a getStatus/resume ezen keres). */
15
+ jobId;
16
+ /** A globális státusz. */
17
+ status;
18
+ /** A projektek száma. */
19
+ total;
20
+ /** A jelenleg feldolgozott projekt indexe. */
21
+ currentIndex;
22
+ /** A sikeres projektek száma. */
23
+ okCount;
24
+ /** A projektek közti cooldown (ms). */
25
+ cooldownMs;
26
+ /** A feltételes cooldown küszöbe. */
27
+ cooldownMinChunks;
28
+ /** Indítás epoch-ms. */
29
+ startedAt;
30
+ /** Befejezés epoch-ms (ha kész). */
31
+ finishedAt;
32
+ /** Per-projekt checkpoint (státusz + eredmény) — a resume ebből tudja, mi van már kész. */
33
+ projects = [];
34
+ /** A scan-specifikációk (a resume újrafuttatásához: path/project/org/table). */
35
+ specs = [];
36
+ /** A hívó (CLI) start/source location-je — a resume-kori path-feloldáshoz. */
37
+ sourceLocation;
38
+ /** Hányszor lett már auto-resume-olva (FEAT-008 Phase 5) — a resume-loop elleni cap (`scan.maxResumeCount`) bemenete. */
39
+ resumeCount;
40
+ /** Terminál ok-szöveg (pl. „resume-cap túllépve") — `failed`/`cancelled` job-on, a diagnózishoz. */
41
+ failureReason;
42
+ constructor(set) {
43
+ super(set);
44
+ if (set) {
45
+ fsm_dynamo_1.DyFM_Object.cleanAssign(this, set);
46
+ }
47
+ }
48
+ }
49
+ exports.FAM_ScanJob_DataModel = FAM_ScanJob_DataModel;
50
+ /**
51
+ * MongoDB data-params a `fam_scan_jobs` collection-höz (FEAT-008 Phase 4). Nincs vektor-mező (a job nem retrieve-elhető
52
+ * tartalom). A `jobId` + `status` indexelt (a getStatus + a resume-lekérdezés gyors útja).
53
+ */
54
+ exports.famScanJob_dataParams = new fsm_dynamo_1.DyFM_DataModel_Params({
55
+ dataName: 'fam_scan_jobs',
56
+ addArchive: true,
57
+ properties: {
58
+ jobId: { type: 'string', index: true },
59
+ status: { type: 'string', index: true },
60
+ total: { type: 'number' },
61
+ currentIndex: { type: 'number' },
62
+ okCount: { type: 'number' },
63
+ cooldownMs: { type: 'number' },
64
+ cooldownMinChunks: { type: 'number' },
65
+ startedAt: { type: 'number' },
66
+ finishedAt: { type: 'number' },
67
+ projects: { type: 'array', default: [] },
68
+ specs: { type: 'array', default: [] },
69
+ sourceLocation: { type: 'string' },
70
+ resumeCount: { type: 'number' },
71
+ failureReason: { type: 'string' },
72
+ },
73
+ });