@futdevpro/fdp-agent-memory 1.1.14 → 1.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/package.json +2 -2
- package/build/src/_cli/_commands/config.command.js +4 -1
- package/build/src/_cli/_commands/scan-projects.command.js +27 -2
- package/build/src/_collections/config-catalog.const.js +34 -1
- package/build/src/_collections/fam-config-value-coerce.util.js +63 -0
- package/build/src/_collections/fam-cooldown.util.js +35 -0
- package/build/src/_collections/title.const.js +31 -0
- package/build/src/_modules/capture/_services/fam-auto-capture.control-service.js +1 -1
- package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +1 -1
- package/build/src/_modules/embedding/_services/fam-entry.data-service.js +23 -1
- package/build/src/_modules/ingest/_collections/fam-famignore.util.js +57 -1
- package/build/src/_modules/ingest/_collections/fam-scan-reconcile.util.js +40 -0
- package/build/src/_modules/ingest/_collections/fam-secret-content.util.js +49 -0
- package/build/src/_modules/ingest/_collections/fam-secret-exclude.util.js +12 -0
- package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +40 -9
- package/build/src/_modules/ingest/_services/fam-scan.control-service.js +77 -11
- package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +1 -1
- package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +113 -33
- package/build/src/_modules/mcp/_services/fam-read-tool.service.js +1 -1
- package/build/src/_modules/migration/_services/fam-claude-mem-import.control-service.js +1 -1
- package/build/src/_modules/scope-reference/_collections/fam-scope-maintenance.util.js +58 -0
- package/build/src/_modules/scope-reference/_services/fam-scope-maintenance.control-service.js +190 -0
- package/build/src/_modules/scope-reference/_services/fam-scope-resolver.control-service.js +2 -2
- package/build/src/_modules/scope-reference/index.js +4 -1
- package/build/src/_routes/server/api/api.controller.js +85 -18
- package/build/src/_routes/server/config/config.control-service.js +2 -2
- package/build/src/app.server.js +30 -1
- package/package.json +2 -2
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/fdp-agent-memory",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.30",
|
|
4
4
|
"description": "Local-first, vector-backed multi-table agent memory exposed as an MCP server (read/write/capabilities). Public, FDP-Templates-free, no auth.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"license": "FDP",
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@futdevpro/fsm-dynamo": "^1.16.7",
|
|
58
|
-
"@futdevpro/nts-dynamo": "^1.15.
|
|
58
|
+
"@futdevpro/nts-dynamo": "^1.15.74",
|
|
59
59
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
60
60
|
"axios": "~1.8.1",
|
|
61
61
|
"better-sqlite3": "^12.4.1",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FAM_Config_Util = void 0;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
|
+
const fam_config_value_coerce_util_1 = require("../../_collections/fam-config-value-coerce.util");
|
|
5
6
|
const fam_output_util_1 = require("../_collections/fam-output.util");
|
|
6
7
|
const fam_client_service_1 = require("../_services/fam-client.service");
|
|
7
8
|
const fam_cli_const_1 = require("../_collections/fam-cli.const");
|
|
@@ -67,9 +68,11 @@ class FAM_Config_Util {
|
|
|
67
68
|
static async runSet(command) {
|
|
68
69
|
const globals = command.optsWithGlobals();
|
|
69
70
|
const local = command.opts();
|
|
71
|
+
// A CLI `--value` mindig string; a szerver típus-szigorúan validál → a katalógus-típusra konvertáljuk
|
|
72
|
+
// (boolean/number/string[] kulcsok így CLI-ből is állíthatók — FAM_ConfigValueCoerce_Util).
|
|
70
73
|
const body = {
|
|
71
74
|
key: local.key,
|
|
72
|
-
value: local.value,
|
|
75
|
+
value: fam_config_value_coerce_util_1.FAM_ConfigValueCoerce_Util.coerce(local.key, local.value),
|
|
73
76
|
table: local.table,
|
|
74
77
|
scopeId: local.scope,
|
|
75
78
|
};
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FAM_ScanProjects_Util = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const commander_1 = require("commander");
|
|
6
|
+
const fam_cooldown_util_1 = require("../../_collections/fam-cooldown.util");
|
|
6
7
|
const fam_output_util_1 = require("../_collections/fam-output.util");
|
|
7
8
|
const fam_client_service_1 = require("../_services/fam-client.service");
|
|
8
9
|
const fam_cli_const_1 = require("../_collections/fam-cli.const");
|
|
@@ -21,11 +22,13 @@ class FAM_ScanProjects_Util {
|
|
|
21
22
|
.description('Több projekt SOROS scan-je (auto-felderítés --root-tal vagy explicit --config-gal; nincs '
|
|
22
23
|
+ 'konkurrens thrash). ⚠️ MINDEN projekt-gyökérbe előbb `.fdpfamignore` + `--dry-run` (lásd lent).')
|
|
23
24
|
.option('--root <dir>', 'projekt-gyökerek auto-felderítése e mappa alatt (package.json/.git markerek)')
|
|
24
|
-
.option('--config <file.json>', 'explicit projekt-lista
|
|
25
|
+
.option('--config <file.json>', 'explicit projekt-lista JSON — elemenként `path` + `project` (+ opcionális `org`, `table`)')
|
|
25
26
|
.option('--depth <n>', 'auto-felderítés max mélysége (default 3)', '3')
|
|
26
27
|
.option('--org <name>', 'default organization az auto-felderítéshez', 'FutDevPro')
|
|
27
28
|
.option('--table <documents|codebase>', 'default cél-tár', 'codebase')
|
|
28
29
|
.option('--dry-run', 'csak becslés MINDEN projektre, NEM ír', false)
|
|
30
|
+
.option('--cooldown <ms>', 'cooldown a projektek KÖZÉ (ms) — gép-tehermentesítő szünet nagy multi-scanhez; '
|
|
31
|
+
+ 'felülírja a `scan.projectCooldownMs` configot (default: a config, ami 0 = ki)')
|
|
29
32
|
.option('--stop-on-error', 'az első hibánál leáll (default: folytatja a többivel)', false)
|
|
30
33
|
.addHelpText('before', '\n⚠️ TISZTA MULTI-SCAN — ELŐBB minden projektbe IGNORE-FÁJL:\n'
|
|
31
34
|
+ ' Mivel ez TÖBB projektet szkennel egyszerre, a junk gyorsan elszaporodik. MINDEN érintett\n'
|
|
@@ -77,7 +80,11 @@ class FAM_ScanProjects_Util {
|
|
|
77
80
|
const client = new fam_client_service_1.FAM_CliClient_Service(globals.serverUrl);
|
|
78
81
|
const projects = [];
|
|
79
82
|
let okCount = 0;
|
|
80
|
-
|
|
83
|
+
// Projekt-cooldown (user-FR): a `--cooldown <ms>` felülírja a szerver `scan.projectCooldownMs` configját
|
|
84
|
+
// (default 0 = ki). dryRun-on nincs cooldown (nincs valódi embed-munka). A projektek KÖZÉ vár, nem az utolsó után.
|
|
85
|
+
const projectCooldownMs = local.dryRun ? 0 : await FAM_ScanProjects_Util.resolveCooldownMs(client, local.cooldown);
|
|
86
|
+
FAM_ScanProjects_Util.progress(globals, `=== ${specs.length} projekt SOROS scan-je${local.dryRun ? ' (dryRun)' : ''}`
|
|
87
|
+
+ `${projectCooldownMs > 0 ? `, cooldown ${projectCooldownMs}ms/projekt` : ''} ===`);
|
|
81
88
|
for (let i = 0; i < specs.length; i++) {
|
|
82
89
|
const spec = specs[i];
|
|
83
90
|
FAM_ScanProjects_Util.progress(globals, `[${i + 1}/${specs.length}] ${spec.project} (${spec.path})`);
|
|
@@ -109,6 +116,11 @@ class FAM_ScanProjects_Util {
|
|
|
109
116
|
break;
|
|
110
117
|
}
|
|
111
118
|
}
|
|
119
|
+
// Projekt-cooldown: a projektek KÖZÉ (NEM az utolsó után) — gép-tehermentesítő szünet nagy multi-scanhez.
|
|
120
|
+
if (projectCooldownMs > 0 && i < specs.length - 1) {
|
|
121
|
+
FAM_ScanProjects_Util.progress(globals, ` cooldown ${projectCooldownMs}ms…`);
|
|
122
|
+
await fam_cooldown_util_1.FAM_Cooldown_Util.sleep(projectCooldownMs);
|
|
123
|
+
}
|
|
112
124
|
}
|
|
113
125
|
FAM_ScanProjects_Util.progress(globals, `=== KÉSZ: ${okCount}/${specs.length} ok ===`);
|
|
114
126
|
return fam_output_util_1.FAM_Output_Util.success({
|
|
@@ -116,6 +128,19 @@ class FAM_ScanProjects_Util {
|
|
|
116
128
|
data: { total: specs.length, ok: okCount, projects: projects },
|
|
117
129
|
});
|
|
118
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* A projekt-cooldown ms feloldása: a CLI `--cooldown` felülírja a szerver `scan.projectCooldownMs` configját.
|
|
133
|
+
* Nincs CLI-érték → a szerver effektív configját kérdezi (`GET /api/config`); a config-lekérés hibája → 0 (a
|
|
134
|
+
* cooldown sosem buktatja a scant). Minden út a `FAM_Cooldown_Util.resolveMs`-en megy át (clamp + biztonság).
|
|
135
|
+
*/
|
|
136
|
+
static async resolveCooldownMs(client, cliValue) {
|
|
137
|
+
if (cliValue !== undefined) {
|
|
138
|
+
return fam_cooldown_util_1.FAM_Cooldown_Util.resolveMs(cliValue);
|
|
139
|
+
}
|
|
140
|
+
const result = await client.get('/api/config');
|
|
141
|
+
const value = result.ok ? result.data?.effective?.['scan.projectCooldownMs'] : 0;
|
|
142
|
+
return fam_cooldown_util_1.FAM_Cooldown_Util.resolveMs(value);
|
|
143
|
+
}
|
|
119
144
|
/** A scan-request body egy projekt-spec-hez (dryRun vagy valós). */
|
|
120
145
|
static body(spec, dryRun, defaults) {
|
|
121
146
|
return {
|
|
@@ -87,7 +87,7 @@ exports.CONFIG_CATALOG = {
|
|
|
87
87
|
'read.importChunkWeight': {
|
|
88
88
|
type: 'number', default: 0.4, min: 0.0, max: 1.0, levels: ALL_LEVELS,
|
|
89
89
|
description: 'Az import-only chunkok (`chunkType:"imports"`) read-idejű rangsor-szorzója (FAM-REV-060). '
|
|
90
|
-
+ 'A szimbólum-név query-knél az import-sorok (`import { X } from "./y"`) magas cosine-t kapnak, de '
|
|
90
|
+
+ 'A szimbólum-név query-knél az import-sorok (`import { X: X } from "./y"`) magas cosine-t kapnak, de '
|
|
91
91
|
+ 'alacsony az ÉRTÉKük (csak import, nem definíció) → e szorzóval a `finalScore = score × weight × '
|
|
92
92
|
+ 'importChunkWeight` a definíció-chunkok ALÁ rangsorolja őket. READ-time (nincs re-embed); a nyers '
|
|
93
93
|
+ 'cosine score (relevancia-jelzések) NEM változik, csak a ranking. 1 = nincs csökkentés.',
|
|
@@ -205,12 +205,42 @@ exports.CONFIG_CATALOG = {
|
|
|
205
205
|
type: 'boolean', default: false, levels: ALL_LEVELS,
|
|
206
206
|
description: 'Symlink-követés (path-traversal védelem, dsgn-004).',
|
|
207
207
|
},
|
|
208
|
+
'scan.nestedFamignore': {
|
|
209
|
+
type: 'boolean', default: true, levels: ALL_LEVELS,
|
|
210
|
+
description: 'A NESTED (per-alkönyvtár) `.fdpfamignore`-ok figyelembevétele a bejárás közben. `true` (default) '
|
|
211
|
+
+ '= ha egy al-projektben/al-mappában van saját `.fdpfamignore`, azt is betöltjük (a saját al-útjához '
|
|
212
|
+
+ 'horgonyozva) és alkalmazzuk arra a subtree-re — így a teljes-workspace scan tiszteletben tartja az '
|
|
213
|
+
+ 'al-projektek saját ignore-jait (eleve-tisztán-szkennelés). `false` = csak a scan-GYÖKÉR `.fdpfamignore`-ja '
|
|
214
|
+
+ 'érvényes (a régi, v1-viselkedés — ha valaki kizárólag gyökér-szintű kontrollt akar).',
|
|
215
|
+
},
|
|
216
|
+
'scan.reconcileIgnored': {
|
|
217
|
+
type: 'boolean', default: true, levels: ALL_LEVELS,
|
|
218
|
+
description: 'Re-scankor a MOST ignore-minta által kizárt (de korábban beolvasott) fájlok meglévő chunkjainak '
|
|
219
|
+
+ 'kitakarítása a tárból. `true` (default — TISZTOGATÁS) = ha utólag hozzáadsz egy ignore-/famignore-mintát, '
|
|
220
|
+
+ 'a re-scan az így kizárttá vált fájlok régi bejegyzéseit orphanként soft-delete-eli (nem ragad be, amit '
|
|
221
|
+
+ 'ignore-olni akarsz). `false` = a régi viselkedés (az ignore-skippelt fájl „jelen-lévőként" számít, a régi '
|
|
222
|
+
+ 'chunkjai BENT MARADNAK — ha valaki a korábbi beolvasást meg akarja őrizni). A lemezről ELTŰNT fájlokat '
|
|
223
|
+
+ 'mindkét beállítás reconciliálja (ez attól független).',
|
|
224
|
+
},
|
|
208
225
|
'scan.testFileWeight': {
|
|
209
226
|
type: 'number', default: 0.5, min: 0.0, max: 10.0, levels: ALL_LEVELS,
|
|
210
227
|
description: 'A teszt-/spec-fájlok (`*.spec.*` / `*.test.*`) DEFAULT retrieval-súlya (FAM-REV-058) — a próza-'
|
|
211
228
|
+ 'nehéz specek különben az IMPLEMENTÁCIÓ fölé rangsorolnak. <1 → a forrás alá; explicit scan-`weights` '
|
|
212
229
|
+ 'felülírja; 1 = nincs csökkentés.',
|
|
213
230
|
},
|
|
231
|
+
'scan.sectionCooldownMs': {
|
|
232
|
+
type: 'number', default: 0, min: 0, max: 60000, integer: true, levels: ALL_LEVELS,
|
|
233
|
+
description: 'Kikapcsolható cooldown (ms) a SZEKCIÓK (file-batch-ek) KÖZÉ egy scanen belül — a NAGY DB-k '
|
|
234
|
+
+ 'beolvasásakor ad lélegzetvételi szünetet a gépnek (CPU/embed-provider/Mongo ne terhelődjön túl). '
|
|
235
|
+
+ 'Default `0` = KIKAPCSOLVA (nincs lassítás); nagy scanre állítsd pl. 1000–3000-re. Csak a batch-ek '
|
|
236
|
+
+ 'KÖZÖTT vár (az utolsó után nem), és a `dryRun` NEM vár (nincs valódi embed-munka).',
|
|
237
|
+
},
|
|
238
|
+
'scan.projectCooldownMs': {
|
|
239
|
+
type: 'number', default: 0, min: 0, max: 60000, integer: true, levels: ALL_LEVELS,
|
|
240
|
+
description: 'Kikapcsolható cooldown (ms) a PROJEKTEK KÖZÉ a `scan-projects` soros multi-scan-jében — a sok-'
|
|
241
|
+
+ 'projektes (L2/L6) beolvasás ne thrash-elje a gépet. Default `0` = KIKAPCSOLVA; nagy futásra pl. 2000–'
|
|
242
|
+
+ '5000. A CLI `--cooldown <ms>` felülírja ezt a config-default-ot (a projektek KÖZÖTT vár, az utolsó után nem).',
|
|
243
|
+
},
|
|
214
244
|
'scan.estimateMsPerChunk': {
|
|
215
245
|
type: 'number', default: 250, min: 1, max: 10000, integer: true, levels: ALL_LEVELS,
|
|
216
246
|
description: 'A `dryRun` pre-scan idő-becsléshez: becsült embed-idő chunkonként (ms). DURVA, gép-/modell-/'
|
|
@@ -239,6 +269,9 @@ exports.CONFIG_CATALOG = {
|
|
|
239
269
|
type: 'number', default: 20, min: 1, max: 200, integer: true, levels: GLOBAL_TABLE,
|
|
240
270
|
description: 'Párhuzamos ingest flow-limit (CCAP DEFAULT_INGEST_FLOW_LIMIT=20, cap 200).',
|
|
241
271
|
},
|
|
272
|
+
// (Az OOM-hibakezelés/heap-guard configja a BEDROCK `DyNTS_global_settings.memoryGuard`-ban van — NEM FAM-config:
|
|
273
|
+
// a bedrock `DyNTS_MemoryGuard`-ot a base App auto-installálja, a FAM a thresholdokat az `overrideDynamoNTSGlobalSettings`-ben
|
|
274
|
+
// állítja. Ezért nincs FAM `memory.*` config-kulcs.)
|
|
242
275
|
'patterns.defaultWeight': {
|
|
243
276
|
type: 'number', default: 5, min: 0, levels: [fam_config_level_type_enum_1.FAM_ConfigLevel.table], tableOnly: fam_table_type_enum_1.FAM_Table.codingPatterns,
|
|
244
277
|
description: 'A coding_patterns tár default retrieval-súlya (CCAP weight 5; csak coding_patterns).',
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_ConfigValueCoerce_Util = void 0;
|
|
4
|
+
const config_catalog_const_1 = require("./config-catalog.const");
|
|
5
|
+
/**
|
|
6
|
+
* `FAM_ConfigValueCoerce_Util` — a `config set` CLI nyers `--value` STRING-jét a katalógus-kulcs típusára konvertálja
|
|
7
|
+
* (a CLI argumentum mindig string, a szerver viszont típus-szigorúan validál — boolean/number kulcsot string-ként
|
|
8
|
+
* elutasít: `FAM-CONFIG-SET-002`). Ez teszi a config-kapcsolókat (pl. `scan.nestedFamignore` / `scan.reconcileIgnored`
|
|
9
|
+
* / `scan.followSymlinks`) ténylegesen CLI-ből állíthatóvá. A `CONFIG_CATALOG[key].type` alapján:
|
|
10
|
+
*
|
|
11
|
+
* - `boolean` → `'true'`/`'false'` → bool (más → változatlan string, hogy a szerver adjon egyértelmű hibát);
|
|
12
|
+
* - `number` → `Number(raw)` (NaN → változatlan string);
|
|
13
|
+
* - `number-or-null` → `'null'`/üres → `null`, különben `Number(raw)`;
|
|
14
|
+
* - `string[]` → JSON-tömb (`[...]`) VAGY vesszős lista → `string[]`;
|
|
15
|
+
* - `string` (+ enum) → változatlan.
|
|
16
|
+
*
|
|
17
|
+
* Ismeretlen kulcs → változatlan string (a szerver `FAM-CONFIG-SET-001`-gyel utasítja el). Tisztán pure.
|
|
18
|
+
*/
|
|
19
|
+
class FAM_ConfigValueCoerce_Util {
|
|
20
|
+
/** A nyers CLI-string → a `key` katalógus-típusának megfelelő JS-érték (lásd az osztály-leírást). */
|
|
21
|
+
static coerce(key, raw) {
|
|
22
|
+
const entry = config_catalog_const_1.CONFIG_CATALOG[key];
|
|
23
|
+
if (!entry) {
|
|
24
|
+
return raw;
|
|
25
|
+
}
|
|
26
|
+
switch (entry.type) {
|
|
27
|
+
case 'boolean':
|
|
28
|
+
if (raw === 'true') {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (raw === 'false') {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return raw;
|
|
35
|
+
case 'number': {
|
|
36
|
+
const value = Number(raw);
|
|
37
|
+
return Number.isNaN(value) ? raw : value;
|
|
38
|
+
}
|
|
39
|
+
case 'number-or-null': {
|
|
40
|
+
if (raw === 'null' || raw === '') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const value = Number(raw);
|
|
44
|
+
return Number.isNaN(value) ? raw : value;
|
|
45
|
+
}
|
|
46
|
+
case 'string[]': {
|
|
47
|
+
const trimmed = raw.trim();
|
|
48
|
+
if (trimmed.startsWith('[')) {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(trimmed);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// nem valid JSON → essünk át a vesszős listára
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return trimmed.length ? trimmed.split(',').map((item) => item.trim()).filter(Boolean) : [];
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return raw;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.FAM_ConfigValueCoerce_Util = FAM_ConfigValueCoerce_Util;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_Cooldown_Util = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `FAM_Cooldown_Util` (user-FR 2026-06-21) — opcionális, **kikapcsolható** cooldown (lélegzetvételi szünet) a
|
|
6
|
+
* scan-feldolgozás közé, hogy a NAGY adatbázisok beolvasása NE terhelje túl a gépet (CPU/embed-provider/Mongo).
|
|
7
|
+
* Két ponton fogyasztva: (a) a SZEKCIÓK (file-batch-ek) között egy scanen belül (`scan.sectionCooldownMs`, szerver-
|
|
8
|
+
* oldali ingest-loop); (b) a PROJEKTEK között a `scan-projects` soros orchestrátorban (`scan.projectCooldownMs` /
|
|
9
|
+
* CLI `--cooldown`). Default **0 = kikapcsolva** (nincs lassítás) → opt-in: a user nagy scanre bekapcsolja.
|
|
10
|
+
*
|
|
11
|
+
* Tisztán: a `resolveMs` (parse + clamp) pure + külön tesztelhető; a `sleep` az egyetlen side-effect.
|
|
12
|
+
*/
|
|
13
|
+
class FAM_Cooldown_Util {
|
|
14
|
+
/** Biztonsági felső korlát egy cooldown-ra (ms) — egy elgépelt óriás-érték ne fagyassza be a scant. */
|
|
15
|
+
static MAX_MS = 60000;
|
|
16
|
+
/**
|
|
17
|
+
* Nyers config/CLI érték → biztonságos cooldown ms. Nem-szám / NaN / ≤0 → `0` (kikapcsolva); egyébként egész
|
|
18
|
+
* ms-re vágva, `[0, MAX_MS]`-re clamp-elve. Így a hibás/extrém input sosem buktatja vagy fagyasztja a scant.
|
|
19
|
+
*/
|
|
20
|
+
static resolveMs(raw) {
|
|
21
|
+
const value = typeof raw === 'number' ? raw : Number(raw);
|
|
22
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
return Math.min(Math.floor(value), FAM_Cooldown_Util.MAX_MS);
|
|
26
|
+
}
|
|
27
|
+
/** Vár `ms` ideig (≤0 → azonnal visszatér, nincs timer). A cooldown egyetlen tényleges késleltetése. */
|
|
28
|
+
static async sleep(ms) {
|
|
29
|
+
if (ms <= 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.FAM_Cooldown_Util = FAM_Cooldown_Util;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_title = void 0;
|
|
4
|
+
exports.FAM_title = `
|
|
5
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠤⠤⠤⠤⣄⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
6
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣶⡊⠉⠉⣉⣱⡷⠶⢢⣠⢴⣶⡝⠒⠉⢉⣭⡽⠟⢉⣀⡀⠹⢭⠒⢤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
7
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠔⢚⣩⡽⠿⠊⢉⣉⡂⣀⣩⠭⢴⠟⠋⠉⠉⠉⠛⠳⢦⣬⣤⡴⠞⠛⠁⠛⠳⣾⣧⠀⠟⠀⠉⠲⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
8
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⢚⠁⠀⠰⠋⢡⠄⠀⠞⣫⢟⡥⠒⠉⠹⣿⡀⠀⠀⢦⡀⠀⠀⠀⠈⠻⡧⡀⠀⠀⠀⠀⠈⠻⣗⡶⠶⠶⢤⡀⠱⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
9
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢮⣤⡾⠀⠀⣠⡴⠋⠀⡠⣚⠥⠒⢛⡲⠄⠀⠈⢻⡆⠀⠀⠻⣦⣀⠀⠀⠀⣿⠻⣦⣀⣴⠶⠂⠀⠘⣷⡄⠀⠀⢀⣴⡿⠈⠢⡀⠀⠀⠀⠀⠀⠀
|
|
10
|
+
⠀⠀⠀⠀⠀⠀⠀⡠⠖⣉⣁⡀⠀⢀⣾⠋⠴⢿⣽⠋⠀⠞⢉⣉⣽⣳⣄⣀⠀⠋⠀⠀⠀⠈⠙⣷⡄⠀⠁⠀⠙⢤⣯⡀⠀⠀⠀⣼⡇⠀⡾⠋⠁⠀⠳⣄⠘⢆⠀⠀⠀⠀⠀
|
|
11
|
+
⠀⠀⠀⠀⠀⡰⠋⠰⠛⢻⡞⢉⣠⣼⡇⢀⣴⠟⠛⠒⣴⠟⠋⠉⠀⠀⢀⣀⣀⡀⠀⠀⠀⠀⠀⣸⡇⠀⠀⠳⣄⠀⠉⢿⣄⠀⢰⣿⣧⡀⠀⣴⠶⠶⣦⡼⢧⠈⢣⠀⠀⠀⠀
|
|
12
|
+
⠀⠀⠀⢀⡞⣡⣶⡄⠀⡟⣳⠿⠋⠙⡍⡽⠁⣀⣤⣤⣿⡄⠀⠀⠀⠀⡿⡉⣀⣀⣤⣤⣤⣴⠾⠥⠽⣦⣄⠀⠉⠻⢶⡼⢻⠀⠈⠇⠘⡷⡄⠘⠂⠀⢀⡍⠻⣷⣄⡇⠀⠀⠀
|
|
13
|
+
⠀⠀⠀⠘⣺⠏⢸⢃⣼⠟⢁⡤⠀⣠⢟⡷⠟⢋⣉⣤⡿⠇⠀⠀⠀⢰⣣⠞⠋⠉⠉⠁⡀⠀⠀⠀⠀⠀⠙⢷⣄⠀⠀⢹⣾⠀⠀⠀⠀⢸⡇⠀⣀⡀⣾⠀⠀⠈⢻⡁⢦⠀⠀
|
|
14
|
+
⠀⠀⣠⢚⣵⣄⠈⣼⡇⠀⢸⠧⢞⡵⠋⠠⠚⠉⠉⠀⠀⢀⡇⠀⣰⣟⣁⣀⠀⠀⠀⠀⠉⠒⠶⣤⣤⣀⠀⠀⠙⠀⠀⢸⡇⢰⣟⠛⢶⡋⣇⠀⠉⠻⡟⡄⠀⢀⢀⣿⠀⢧⠀
|
|
15
|
+
⠀⣰⠃⢸⠁⣿⠀⠸⣧⠀⢸⢣⠋⠀⣠⣤⠶⢶⢒⣤⣔⣻⠣⢼⠟⠁⠀⠙⢷⡄⠀⠀⢀⠀⠀⠀⠈⠓⢟⢦⠀⠀⠀⢸⡇⠈⠻⣦⡀⠈⠻⣷⣄⠀⠘⣿⠀⠸⣿⣇⣀⢸⠀
|
|
16
|
+
⠀⡇⠀⠀⣼⠇⠀⢀⣿⠀⣇⣇⣴⠟⠋⢠⣾⠟⠉⠀⠀⠈⠳⣼⠀⠀⠀⠀⠀⠳⠀⠀⠈⢳⣄⠀⠀⠀⢸⣼⠀⠀⠀⠈⡟⢆⠀⠈⢻⡀⠀⠈⢻⣆⠀⣻⠃⠀⠀⢹⡟⠻⡀
|
|
17
|
+
⠀⢧⡆⣼⠏⠀⣾⠟⠁⢰⠃⡵⠃⢀⣴⡿⠁⠀⡀⠀⠀⠀⠀⠹⣧⡀⠰⣦⡀⠀⠀⠀⠀⠀⣻⢦⣀⣠⡾⣇⠀⠀⢀⣰⠟⠙⢷⣄⠀⠀⠀⠀⠀⣿⠀⠉⢠⠄⠀⣼⡇⠀⢧
|
|
18
|
+
⢀⠞⢡⡟⠀⠀⣿⠀⢀⡏⡼⠁⣴⠟⠁⠀⠀⠀⣿⠀⣀⣀⢀⣴⠘⣷⡀⠈⢻⣦⣀⠀⢀⣾⠟⠉⠀⠀⠉⠻⣷⣄⠀⠀⠀⠀⠀⠙⢷⡄⠀⠀⠀⠉⠀⣠⡟⠀⣼⣟⠀⠀⢸
|
|
19
|
+
⢸⠀⠘⣧⠀⡴⠛⠳⢸⢰⠁⢰⠏⠀⠀⠀⢀⣼⡯⠟⠋⠙⠻⣷⡀⠘⠀⠀⠀⠈⠉⠻⣿⠁⠀⠀⢰⡟⠉⠀⠈⢻⣦⠀⠀⠀⣄⠀⠀⡗⠀⢸⡇⣠⣾⠟⢀⣾⠋⠹⣷⢀⡇
|
|
20
|
+
⠈⢆⠀⠹⢷⣤⣀⣠⠎⡇⠀⠸⠀⠀⢀⣴⠟⠉⠀⠀⠀⢄⠀⠹⣧⡀⠀⠀⣀⡀⠀⠀⣿⠀⠀⠀⠘⣿⡄⠀⠀⠀⢹⣦⡀⠀⢿⣄⠀⢀⣠⡿⠽⣯⡁⠀⠸⠃⠀⠀⡏⠉⠀
|
|
21
|
+
⠀⢠⢷⣄⠀⠈⣉⣉⢢⢳⡀⠀⠀⠀⣾⡏⠀⠀⠠⣀⡤⢿⠀⠀⠙⠷⠶⠛⠉⠈⠀⣰⠟⠀⠀⠀⠀⠘⣷⡀⠀⠠⠛⠉⠉⠀⢈⣯⠗⠛⠁⠀⠀⠈⠃⠀⢀⣴⠇⢠⠇⠀⠀
|
|
22
|
+
⠀⢸⡀⠻⣧⠈⠉⠹⣏⢀⣑⠤⣀⣀⠼⠳⣄⠀⠀⠀⠙⠺⠖⣦⣤⠤⣀⡀⠀⠀⠘⠁⠀⠀⠀⠀⠀⠀⢸⢧⡀⠀⠀⢀⣀⢴⣿⣅⡀⠠⠶⢿⢦⣀⣠⣴⠟⠃⡠⠋⠀⠀⠀
|
|
23
|
+
⠀⠀⠳⡀⠘⠃⠀⡤⠸⣼⠀⠉⠛⠋⠉⠉⠙⠻⣦⣄⠀⠀⠀⠀⠈⠉⠙⠻⣦⠀⠀⠀⠀⡀⠀⠀⠀⢀⣾⠖⠚⠛⠛⠛⠋⠁⠀⠙⣷⠀⠀⣸⡴⠛⠉⢁⡤⠊⠁⠀⠀⠀⠀
|
|
24
|
+
⠀⠀⠀⠘⢦⡀⠸⣧⠀⢻⢇⠀⠳⡤⣤⠆⠀⠀⠈⢻⡇⠀⠀⠀⢰⡄⠀⠀⣿⡇⢀⡾⠛⠛⠻⡝⣲⠟⠋⠀⢀⡄⠀⠀⠀⣀⡄⠀⠋⢀⡴⣻⡄⣤⡶⡍⠀⠀⠀⠀⠀⠀⠀
|
|
25
|
+
⠀⠀⠀⠀⠀⠈⠙⠁⠉⠉⠈⠣⡀⠹⣇⠀⠀⠀⠀⠘⠀⠀⠀⢀⡾⢳⡶⠾⠋⠀⠈⠃⠀⠀⣠⠟⢄⣀⣠⡴⠋⠀⠀⠀⣼⢻⣤⣴⠶⠟⠋⣡⡷⣏⢿⡧⠀⠀⠀⠀⠀⠀⠀
|
|
26
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⢫⣲⣤⣀⣀⣀⣀⣤⣶⣻⠋⠛⠷⣦⣤⣤⣄⡤⢤⣺⠕⠋⠉⠉⠁⠀⠀⣀⣤⣾⠏⢩⠀⠀⢀⣤⣾⠛⣧⢻⣼⠀⠀⠀⠀⠀⠀⠀⠀
|
|
27
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠮⢭⣉⣉⡩⠥⠚⠈⢇⠀⢠⡄⠀⠉⠉⠙⣿⠀⢠⠶⠖⢫⣩⠟⠛⠛⠉⠀⣠⣿⣦⠶⠿⣭⣸⣇⡿⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀
|
|
28
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣌⡿⣄⠀⠒⠚⠋⠀⠀⠀⣠⡾⠃⠀⢀⣀⠴⠚⠉⠣⢍⣛⣶⡶⠝⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
29
|
+
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠒⠂⠀⠒⠒⠉⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
30
|
+
|
|
31
|
+
FDP Agent Memory - By Future Development Program Kft.`;
|
|
@@ -48,7 +48,7 @@ class FAM_AutoCapture_ControlService {
|
|
|
48
48
|
const contentHash = ingest_1.FAM_ContentHash_Util.hash(content);
|
|
49
49
|
// Dedup: van-e MÁR aktív memory-bejegyzés azonos content-hash-sel? → idempotens skip (nincs duplikátum).
|
|
50
50
|
const existing = await this.findByHash(contentHash);
|
|
51
|
-
if (existing
|
|
51
|
+
if (existing?._id) {
|
|
52
52
|
return { captured: false, skipped: 'duplicate', id: existing._id, contentHash: contentHash };
|
|
53
53
|
}
|
|
54
54
|
// Új capture → a `write` create-úton (agent-provenance, auto-embed). A `source.path` a sessionId
|
|
@@ -215,7 +215,7 @@ class FAM_EmbeddingPipeline_ControlService {
|
|
|
215
215
|
}
|
|
216
216
|
/** A scope-szűkítő filter (a `scopePath` LEVÉL scopeId-jára). Üres scope → teljes tár (`!_deleted`). */
|
|
217
217
|
buildScopeFilter(scopePath) {
|
|
218
|
-
if (scopePath
|
|
218
|
+
if (scopePath?.length) {
|
|
219
219
|
const leaf = scopePath[scopePath.length - 1];
|
|
220
220
|
const filter = { 'scopePath.scopeId': leaf.scopeId };
|
|
221
221
|
return filter;
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FAM_Entry_DataService = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const nts_dynamo_1 = require("@futdevpro/nts-dynamo");
|
|
6
5
|
const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
|
|
6
|
+
const nts_dynamo_1 = require("@futdevpro/nts-dynamo");
|
|
7
7
|
const fam_entry_data_model_1 = require("../../../_models/data-models/fam-entry.data-model");
|
|
8
8
|
/**
|
|
9
9
|
* `FAM_Entry_DataService` (SP-2.2) — egy GENERIKUS, tár-paraméteres entry-CRUD a vektor-rétegnek.
|
|
@@ -195,5 +195,27 @@ class FAM_Entry_DataService extends nts_dynamo_1.DyNTS_DataService {
|
|
|
195
195
|
filterBy['position.charStart'] = { $ne: position.charStart };
|
|
196
196
|
await this.updateData({ filterBy: filterBy, update: update });
|
|
197
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* A **git-repo provenance** (`source.repoUrl` / `repoName` / `repoRelativePath` / `repoBranch`) FELTÉTELES
|
|
200
|
+
* backfill-je (user-FR 2026-06-22) — a re-scan `equal` (változatlan-content) ágán hívva, hogy a CSAK-metaadat
|
|
201
|
+
* frissítés (a git-provenance feature ELŐTT ingestelt korpuszra) RE-EMBED NÉLKÜL megtörténjen. A hívó (ingest)
|
|
202
|
+
* adja a kiszámolt `git`-mezőket (a `FAM_GitRepo_Util`-t a control-service importálja — nincs modul-ciklus). Nem
|
|
203
|
+
* git-repo (nincs `repoUrl`) → no-op. Feltétel: a per-fájl `repoRelativePath` `$ne` (a Mongo no-op, ha már stimmel).
|
|
204
|
+
*/
|
|
205
|
+
async backfillGitProvenance(id, git) {
|
|
206
|
+
if (!git.repoUrl) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const setBlock = {
|
|
210
|
+
['source.repoUrl']: git.repoUrl,
|
|
211
|
+
['source.repoName']: git.repoName,
|
|
212
|
+
['source.repoRelativePath']: git.repoRelativePath,
|
|
213
|
+
['source.repoBranch']: git.repoBranch,
|
|
214
|
+
};
|
|
215
|
+
const update = { $set: setBlock };
|
|
216
|
+
const filterBy = { _id: id };
|
|
217
|
+
filterBy['source.repoRelativePath'] = { $ne: git.repoRelativePath };
|
|
218
|
+
await this.updateData({ filterBy: filterBy, update: update });
|
|
219
|
+
}
|
|
198
220
|
}
|
|
199
221
|
exports.FAM_Entry_DataService = FAM_Entry_DataService;
|
|
@@ -4,6 +4,7 @@ exports.FAM_FamIgnore_Util = 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 fam_glob_match_util_1 = require("./fam-glob-match.util");
|
|
7
8
|
/**
|
|
8
9
|
* `FAM_FamIgnore_Util` (descriptive user feedback / nagy-scan ergonómia) — a **`.fdpfamignore`** in-repo,
|
|
9
10
|
* gitignore-stílusú ignore-fájl támogatása. A projekt (vagy a workspace-gyökér) MAGÁBAN hordozza, mit hagyjon
|
|
@@ -13,7 +14,10 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
13
14
|
* **Szintaxis (gitignore-szerű, a `FAM_GlobMatch_Util`-ra fordítva):** soronként egy minta; `#` komment + üres
|
|
14
15
|
* sor kihagyva. `node_modules` (csupasz név) → bárhol illeszkedik; `/build` (vezető `/`) → a gyökérhez horgonyzott;
|
|
15
16
|
* `dist/` (záró `/`) → könyvtár; `src/gen` (beágyazott `/`) → gyökér-relatív; `*.tgz` → bárhol. **A `!` negáció
|
|
16
|
-
*
|
|
17
|
+
* (re-include) TÁMOGATOTT** (user-FR 2026-06-21): `parse` az ignore-sorokat, `parseNegations` a `!`-sorokat adja;
|
|
18
|
+
* a fogyasztó (scan) a fájlt akkor SKIP-eli, ha ignore-match ÉS NEM re-include-match — a könyvtár-prune pedig
|
|
19
|
+
* `dirOnReincludeLineage`-tudatos (egy ignore-olt mappát NEM vág le, ha re-included elem van rajta/alatta). Így
|
|
20
|
+
* a „ignore-mindent-kivéve-X" (pl. `ccap/` + `!ccap/client/`) helyesen működik a rekurzív bejárásban is.
|
|
17
21
|
*
|
|
18
22
|
* **v1 hatókör:** a scan-GYÖKÉR `.fdpfamignore`-ja (a teljes scanre). A NESTED (per-alkönyvtár) `.fdpfamignore`
|
|
19
23
|
* a két-fázisú felderítés (walk → classify) miatt külön kör — BACKLOG (a `baseDir` paraméter már készen áll rá).
|
|
@@ -62,9 +66,61 @@ class FAM_FamIgnore_Util {
|
|
|
62
66
|
}
|
|
63
67
|
return patterns;
|
|
64
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* A `!`-negáció (**re-include**) sorai — a vezető `!` levágva. Tisztán pure (a fordítás külön). Az `ignore`
|
|
71
|
+
* (`parse`) + a re-include (`parseNegations`) együtt adja a gitignore-szerű „ignore-mindent-kivéve" szemantikát.
|
|
72
|
+
*/
|
|
73
|
+
static parseNegations(content) {
|
|
74
|
+
const result = [];
|
|
75
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
76
|
+
const line = rawLine.trim();
|
|
77
|
+
if (line.startsWith('!') && line.length > 1) {
|
|
78
|
+
result.push(line.slice(1).trim());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A re-include (`!`) szabályok egy könyvtárból: **`globs`** (a fájl-szintű re-include-matchhez, `<base>` +
|
|
85
|
+
* `<base>/**`) + **`bases`** (a `/**` nélküli alap-utak — a KÖNYVTÁR-prune lineage-ellenőrzéséhez: egy ignore-olt
|
|
86
|
+
* könyvtárat NEM vágunk le, ha egy re-include alatta/fölötte/rajta van). Hiányzó fájl → üres. Fail-safe.
|
|
87
|
+
*/
|
|
88
|
+
static loadReincludeRules(dirAbsolutePath, baseDir = '') {
|
|
89
|
+
try {
|
|
90
|
+
const filePath = path.join(dirAbsolutePath, FAM_FamIgnore_Util.FILENAME);
|
|
91
|
+
if (!fs.existsSync(filePath)) {
|
|
92
|
+
return { globs: [], bases: [] };
|
|
93
|
+
}
|
|
94
|
+
const negations = FAM_FamIgnore_Util.parseNegations(fs.readFileSync(filePath, 'utf-8'));
|
|
95
|
+
const globs = FAM_FamIgnore_Util.toGlobPatterns(negations, baseDir);
|
|
96
|
+
const bases = [...new Set(globs.map((glob) => glob.replace(/\/\*\*$/, '')))];
|
|
97
|
+
return { globs: globs, bases: bases };
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return { globs: [], bases: [] };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* `true`, ha a `dir` (root-relatív út) NEM prune-olható egy re-include miatt: (1) maga a dir re-included (vagy
|
|
105
|
+
* egy re-included alfa alatt van) — ezt **glob-match**-csel ellenőrizzük a re-include-`globs` ellen (így a
|
|
106
|
+
* `(glob)/client` minta a `client` dir-re, a `(glob)/client/(glob)` a `client/src` dir-re is illeszkedik); VAGY
|
|
107
|
+
* (2) a dir egy **anchored** (glob-mentes) re-include base ŐSE (van alatta re-included elem) — ezt string-prefixszel.
|
|
108
|
+
* (A bare-bázisok ős-esetét az (1) fedi.) Ez teszi a negációt traversal-helyessé (a szülőt nem vágjuk le idő előtt).
|
|
109
|
+
*/
|
|
110
|
+
static dirOnReincludeLineage(dir, reincludeGlobs, reincludeBases) {
|
|
111
|
+
const d = dir.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
112
|
+
if (fam_glob_match_util_1.FAM_GlobMatch_Util.matchesAny(d, reincludeGlobs)) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return reincludeBases.some((rawBase) => {
|
|
116
|
+
const base = rawBase.replace(/\/+$/, '');
|
|
117
|
+
return !base.includes('*') && base.startsWith(`${d}/`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
65
120
|
/**
|
|
66
121
|
* A `.fdpfamignore` beolvasása + fordítása egy könyvtárból (a `dirAbsolutePath`-ban). Hiányzó / olvashatatlan
|
|
67
122
|
* fájl → `[]` (opt-in: csak ha létezik). A `baseDir` a root-relatív horgony (a gyökér-szintű hívásnál `''`).
|
|
123
|
+
* (Csak az IGNORE minták — a re-include-ot a `loadReincludeRules` adja.)
|
|
68
124
|
*/
|
|
69
125
|
static loadFromDir(dirAbsolutePath, baseDir = '') {
|
|
70
126
|
try {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_ScanReconcile_Util = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `FAM_ScanReconcile_Util` (user-FR 2026-06-21) — a re-scan **whole-file orphan reconciliation** present-set
|
|
6
|
+
* számítása. A „present" halmaz az a fájl-útvonal-készlet, amit a friss scan a lemezen MEGTALÁLT (és ezért a
|
|
7
|
+
* táron meglévő, e halmazon KÍVÜLI `scan`-entry-k orphanok → soft-delete). A finomság a **most ignore-mintával
|
|
8
|
+
* kizárt** fájlok kezelése (`scan.reconcileIgnored`):
|
|
9
|
+
*
|
|
10
|
+
* - **`reconcileIgnored = true` (default — TISZTOGATÁS):** az ignore-minta által skippelt fájl NEM számít
|
|
11
|
+
* present-nek → a korábban beolvasott, de most ignore-olttá vált fájl régi chunkjai orphanként kitakaríthatók
|
|
12
|
+
* (ne ragadjon be, amit ignore-olni akarunk). A többi skip-ok (secret / méret / unrouted / include-filter) MARAD
|
|
13
|
+
* present (a fájl a lemezen van, csak most nem ingesteljük — NEM töröljük a régi tudást).
|
|
14
|
+
* - **`reconcileIgnored = false` (régi viselkedés):** MINDEN skippelt fájl present → a régi chunkok megmaradnak.
|
|
15
|
+
*
|
|
16
|
+
* A lemezről ELTŰNT fájlok mindkét módban orphanok (eleve nincsenek a routed/skipped halmazban) — ez a beállítástól
|
|
17
|
+
* független. Tisztán pure (Set-számítás), külön tesztelhető; a `reconcileDeletedFiles` ezt hívja.
|
|
18
|
+
*/
|
|
19
|
+
class FAM_ScanReconcile_Util {
|
|
20
|
+
/**
|
|
21
|
+
* A friss scan present-path halmaza (abszolút utak). A `routedFiles` mind present; a `skippedFiles` present,
|
|
22
|
+
* KIVÉVE az ignore-minta-kizártakat (`excludedByIgnore`), ha `reconcileIgnored` — azok orphanná válnak, hogy a
|
|
23
|
+
* régi chunkjaik kitakaríthatók legyenek. Üres input → üres halmaz.
|
|
24
|
+
*/
|
|
25
|
+
static computePresentPaths(routedFiles, skippedFiles, reconcileIgnored) {
|
|
26
|
+
const present = new Set();
|
|
27
|
+
for (const routed of routedFiles) {
|
|
28
|
+
present.add(routed.absolutePath);
|
|
29
|
+
}
|
|
30
|
+
for (const skipped of skippedFiles) {
|
|
31
|
+
// A most ignore-mintával kizárt fájl NEM present (ha tisztogatunk) → a régi bejegyzése orphan → törölhető.
|
|
32
|
+
if (reconcileIgnored && skipped.excludedByIgnore) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
present.add(skipped.absolutePath);
|
|
36
|
+
}
|
|
37
|
+
return present;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.FAM_ScanReconcile_Util = FAM_ScanReconcile_Util;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_SecretContent_Util = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `FAM_SecretContent_Util` (user-FR 2026-06-21) — **tartalmi** (fájlon-BELÜLi) secret-redakció. A `FAM_SecretExclude_Util`
|
|
6
|
+
* csak fájlNÉV-alapú (a `.env`/`*.key` típusú titok-FÁJLOKAT zárja ki); de egy `.ts`/`.py` FORRÁSBA hardcode-olt
|
|
7
|
+
* API-kulcs (pl. `apiKey: 'sk-…'`) eddig beolvasódott a vektor-tárba (élő lelet 2026-06-21: 1 OpenAI-kulcs 4 config-
|
|
8
|
+
* fájlban). Ez a util a fájl-tartalmat OLVASÁSKOR redaktálja (a chunk/contentHash/embedding/tárolt szöveg MIND a
|
|
9
|
+
* redaktált változatot kapja) → a titok soha nem kerül a DB-be, és egy korábban-szivárgott fájl RE-SCANKOR
|
|
10
|
+
* auto-gyógyul (a contentHash változik a redakciótól → `modified` → a tárolt content felülíródik).
|
|
11
|
+
*
|
|
12
|
+
* **Magas-konfidenciájú, jellegzetes alakú token-minták** (alacsony false-positive): OpenAI `sk-…`, AWS `AKIA…`,
|
|
13
|
+
* GitHub `ghp_/gho_…`, Google `AIza…`, Slack `xox.-…`, privát-kulcs PEM-blokk, JWT. NEM próbál generikus
|
|
14
|
+
* `password=…`-t fogni (az túl sok forrás-konstanst redaktálna) — a cél a VALÓDI kulcs-szivárgás, nem a kód-RAG rontása.
|
|
15
|
+
*/
|
|
16
|
+
class FAM_SecretContent_Util {
|
|
17
|
+
/** A redaktált tokenek helyére kerülő jelölő (a kód-kontextus megmarad, csak a titok tűnik el). */
|
|
18
|
+
static PLACEHOLDER = '***REDACTED-SECRET***';
|
|
19
|
+
/** Magas-konfidenciájú secret-token minták (jellegzetes prefix + hossz → kevés false-positive). */
|
|
20
|
+
static PATTERNS = [
|
|
21
|
+
{ name: 'openai', re: /sk-(?:proj-)?[A-Za-z0-9_-]{32,}/g },
|
|
22
|
+
{ name: 'aws-access-key', re: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
23
|
+
{ name: 'github-token', re: /\bgh[posur]_[A-Za-z0-9]{36,}\b/g },
|
|
24
|
+
{ name: 'google-api', re: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
25
|
+
{ name: 'slack-token', re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
26
|
+
{ name: 'private-key-block', re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g },
|
|
27
|
+
{ name: 'jwt', re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{6,}\b/g },
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* A `text` magas-konfidenciájú secret-tokenjeit a `PLACEHOLDER`-re cseréli. Visszaadja a redaktált szöveget +
|
|
31
|
+
* a redakciók számát (a per-fájl audit-loghoz). Ha nincs találat → az eredeti szöveg + `count: 0` (no-op).
|
|
32
|
+
*/
|
|
33
|
+
static redact(text) {
|
|
34
|
+
let count = 0;
|
|
35
|
+
let result = text;
|
|
36
|
+
for (const pattern of FAM_SecretContent_Util.PATTERNS) {
|
|
37
|
+
result = result.replace(pattern.re, () => {
|
|
38
|
+
count++;
|
|
39
|
+
return FAM_SecretContent_Util.PLACEHOLDER;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return { text: result, count: count };
|
|
43
|
+
}
|
|
44
|
+
/** `true`, ha a `text` legalább egy magas-konfidenciájú secret-tokent tartalmaz (a `redact`-re épül, állapotmentes). */
|
|
45
|
+
static hasSecret(text) {
|
|
46
|
+
return FAM_SecretContent_Util.redact(text).count > 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.FAM_SecretContent_Util = FAM_SecretContent_Util;
|
|
@@ -45,6 +45,14 @@ class FAM_SecretExclude_Util {
|
|
|
45
45
|
/secret/i, // *secret* (csak nem-forrás kiterjesztésen)
|
|
46
46
|
/credential/i, // *credential* (csak nem-forrás kiterjesztésen)
|
|
47
47
|
];
|
|
48
|
+
/**
|
|
49
|
+
* EXPLICIT key-store fájlnevek (user-FR 2026-06-21) — kiterjesztéstől függetlenül kizárnak, mert a fájl MAGA egy
|
|
50
|
+
* kulcs-tár (élő lelet: egy OpenAI-kulcs `gpt-keys.const.ts`-ben). TIGHT lista (api/gpt/secret/access + `key(s)`)
|
|
51
|
+
* → alacsony false-positive (egy general `environment.ts`-t NEM zár ki — abban a tartalmi redaktor fogja a kulcsot).
|
|
52
|
+
*/
|
|
53
|
+
static SECRET_KEYSTORE_NAME_PATTERNS = [
|
|
54
|
+
/(^|[-_.])(api|gpt|secret|access|private|auth)[-_]?keys?([-_.]|$)/i, // gpt-keys.const.ts, api-keys.ts, apikeys.js
|
|
55
|
+
];
|
|
48
56
|
/** Ismert FORRÁS-/DOC-kiterjesztések — ezeken a SOFT névrész-minta NEM zár ki (legit kód/doc). */
|
|
49
57
|
static SOURCE_DOC_EXTENSION = /\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|md|markdown)$/i;
|
|
50
58
|
/** A secret-mappák (az útvonal BÁRMELY szegmense — pl. `secrets/`, `.ssh/`). */
|
|
@@ -67,6 +75,10 @@ class FAM_SecretExclude_Util {
|
|
|
67
75
|
if (FAM_SecretExclude_Util.HARD_SECRET_PATTERNS.some((pattern) => pattern.test(fileName))) {
|
|
68
76
|
return true;
|
|
69
77
|
}
|
|
78
|
+
// (2b) EXPLICIT key-store fájlnév (api-/gpt-/secret-keys…) — kiterjesztéstől függetlenül (a fájl maga kulcs-tár).
|
|
79
|
+
if (FAM_SecretExclude_Util.SECRET_KEYSTORE_NAME_PATTERNS.some((pattern) => pattern.test(fileName))) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
70
82
|
// (3) SOFT névrész-minta — CSAK ha NEM ismert forrás-/doc-kiterjesztés (a "secret"-nevű .ts legit kód).
|
|
71
83
|
if (FAM_SecretExclude_Util.SOURCE_DOC_EXTENSION.test(fileName)) {
|
|
72
84
|
return false;
|