@futdevpro/fdp-agent-memory 0.1.0
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/README.md +345 -0
- package/build/package.json +96 -0
- package/build/src/_assets/mcp-client-config/README.md +29 -0
- package/build/src/_assets/mcp-client-config/claude_desktop_config.json +15 -0
- package/build/src/_assets/mcp-client-config/mcp.json +15 -0
- package/build/src/_collections/config-catalog.const.js +180 -0
- package/build/src/_collections/config-error-codes.const.js +30 -0
- package/build/src/_collections/config-presets.const.js +25 -0
- package/build/src/_collections/error-banners.const.js +100 -0
- package/build/src/_collections/error-codes.const.js +150 -0
- package/build/src/_collections/fam-db-models.const.js +37 -0
- package/build/src/_collections/fam-entry-bootstrap.util.js +80 -0
- package/build/src/_collections/fam-error-context.util.js +90 -0
- package/build/src/_collections/fam-error-factory.util.js +64 -0
- package/build/src/_enums/fam-config-level.type-enum.js +15 -0
- package/build/src/_enums/fam-table.type-enum.js +20 -0
- package/build/src/_integration-tests/_helpers/fam-integration-test-setup.util.js +105 -0
- package/build/src/_models/data-models/fam-codebase.data-model.js +51 -0
- package/build/src/_models/data-models/fam-coding-patterns.data-model.js +58 -0
- package/build/src/_models/data-models/fam-config.data-model.js +68 -0
- package/build/src/_models/data-models/fam-documents.data-model.js +53 -0
- package/build/src/_models/data-models/fam-entry-base-properties.const.js +43 -0
- package/build/src/_models/data-models/fam-entry.data-model.js +81 -0
- package/build/src/_models/data-models/fam-error.data-model.js +88 -0
- package/build/src/_models/data-models/fam-ingest-run.data-model.js +74 -0
- package/build/src/_models/data-models/fam-knowledge.data-model.js +48 -0
- package/build/src/_models/data-models/fam-memory.data-model.js +55 -0
- package/build/src/_models/data-models/fam-reference.data-model.js +67 -0
- package/build/src/_models/data-models/fam-rules.data-model.js +51 -0
- package/build/src/_models/data-models/fam-scope.data-model.js +52 -0
- package/build/src/_models/interfaces/fam-common.interface.js +23 -0
- package/build/src/_models/interfaces/fam-config.interface.js +2 -0
- package/build/src/_models/interfaces/fam-error.interface.js +2 -0
- package/build/src/_modules/embedding/_collections/fam-embedding-pricing.const.js +22 -0
- package/build/src/_modules/embedding/_collections/fam-store-registry.const.js +63 -0
- package/build/src/_modules/embedding/_models/interfaces/fam-embedding-cost.interface.js +10 -0
- package/build/src/_modules/embedding/_models/interfaces/fam-embedding-provider.interface.js +2 -0
- package/build/src/_modules/embedding/_models/interfaces/fam-resolved-provider.interface.js +2 -0
- package/build/src/_modules/embedding/_services/fam-embedding-bootstrap.control-service.js +52 -0
- package/build/src/_modules/embedding/_services/fam-embedding-cost.control-service.js +175 -0
- package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +202 -0
- package/build/src/_modules/embedding/_services/fam-embedding-preset.control-service.js +66 -0
- package/build/src/_modules/embedding/_services/fam-embedding.control-service.js +253 -0
- package/build/src/_modules/embedding/_services/fam-entry.data-service.js +64 -0
- package/build/src/_modules/embedding/_services/fam-lmstudio-embedding.provider.js +112 -0
- package/build/src/_modules/embedding/_services/fam-mock-embedding.provider.js +64 -0
- package/build/src/_modules/embedding/_services/fam-openai-embedding.provider.js +64 -0
- package/build/src/_modules/embedding/_services/fam-vector-search.control-service.js +244 -0
- package/build/src/_modules/embedding/index.js +40 -0
- package/build/src/_modules/ingest/_collections/fam-content-hash.util.js +35 -0
- package/build/src/_modules/ingest/_collections/fam-file-routing.util.js +95 -0
- package/build/src/_modules/ingest/_collections/fam-glob-match.util.js +84 -0
- package/build/src/_modules/ingest/_collections/fam-md-chunker.util.js +164 -0
- package/build/src/_modules/ingest/_collections/fam-scan-path.util.js +91 -0
- package/build/src/_modules/ingest/_collections/fam-secret-exclude.util.js +54 -0
- package/build/src/_modules/ingest/_collections/fam-sliding-chunker.util.js +76 -0
- package/build/src/_modules/ingest/_collections/fam-ts-chunker.util.js +316 -0
- package/build/src/_modules/ingest/_models/interfaces/fam-ingest.interface.js +2 -0
- package/build/src/_modules/ingest/_services/fam-chunker.control-service.js +114 -0
- package/build/src/_modules/ingest/_services/fam-delta-compare.util.js +74 -0
- package/build/src/_modules/ingest/_services/fam-ingest-run.data-service.js +85 -0
- package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +384 -0
- package/build/src/_modules/ingest/_services/fam-scan.control-service.js +211 -0
- package/build/src/_modules/ingest/index.js +46 -0
- package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +186 -0
- package/build/src/_modules/mcp/_models/interfaces/fam-mcp.interface.js +31 -0
- package/build/src/_modules/mcp/_services/fam-capabilities-tool.service.js +111 -0
- package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +1180 -0
- package/build/src/_modules/mcp/_services/fam-mcp-adapter.service.js +123 -0
- package/build/src/_modules/mcp/_services/fam-mcp-server.service.js +69 -0
- package/build/src/_modules/mcp/_services/fam-read-tool.service.js +99 -0
- package/build/src/_modules/mcp/_services/fam-write-tool.service.js +460 -0
- package/build/src/_modules/mcp/index.js +35 -0
- package/build/src/_modules/migration/_collections/fam-claude-mem-normalize.util.js +166 -0
- package/build/src/_modules/migration/_collections/fam-import-content-hash.util.js +38 -0
- package/build/src/_modules/migration/_collections/fam-target-mapping.util.js +90 -0
- package/build/src/_modules/migration/_enums/fam-claude-mem-source.type-enum.js +20 -0
- package/build/src/_modules/migration/_models/interfaces/fam-claude-mem.interface.js +26 -0
- package/build/src/_modules/migration/_services/fam-claude-mem-export-reader.service.js +134 -0
- package/build/src/_modules/migration/_services/fam-claude-mem-import.control-service.js +533 -0
- package/build/src/_modules/migration/_services/fam-claude-mem-sqlite-reader.service.js +144 -0
- package/build/src/_modules/migration/_services/fam-claude-mem-worker-reader.service.js +115 -0
- package/build/src/_modules/migration/_services/fam-import-dedup.data-service.js +102 -0
- package/build/src/_modules/migration/index.js +38 -0
- package/build/src/_modules/retrieval/_models/interfaces/fam-retrieval.interface.js +2 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +67 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval-suggestions.util.js +182 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +282 -0
- package/build/src/_modules/retrieval/index.js +22 -0
- package/build/src/_modules/scope-reference/_collections/fam-fuzzy-match.util.js +86 -0
- package/build/src/_modules/scope-reference/_collections/fam-scope-normalize.util.js +47 -0
- package/build/src/_modules/scope-reference/_models/interfaces/fam-reference-resolution.interface.js +2 -0
- package/build/src/_modules/scope-reference/_models/interfaces/fam-resolution-trace.interface.js +2 -0
- package/build/src/_modules/scope-reference/_services/fam-reference.data-service.js +179 -0
- package/build/src/_modules/scope-reference/_services/fam-scope-resolver.control-service.js +473 -0
- package/build/src/_modules/scope-reference/_services/fam-scope.data-service.js +215 -0
- package/build/src/_modules/scope-reference/index.js +26 -0
- package/build/src/_routes/server/api/api.controller.js +400 -0
- package/build/src/_routes/server/client-app/client-app.control-service.js +132 -0
- package/build/src/_routes/server/client-app/client-app.controller.js +35 -0
- package/build/src/_routes/server/config/config.control-service.js +476 -0
- package/build/src/_routes/server/config/config.data-service.js +49 -0
- package/build/src/_routes/server/errors/errors.control-service.js +123 -0
- package/build/src/_routes/server/errors/errors.controller.js +65 -0
- package/build/src/_routes/server/errors/errors.data-service.js +80 -0
- package/build/src/_routes/server/server-status/server-status.control-service.js +19 -0
- package/build/src/_routes/server/server-status/server-status.controller.js +39 -0
- package/build/src/app.server.js +122 -0
- package/build/src/environments/environment.js +20 -0
- package/build/src/index.js +18 -0
- package/client-dist/chunk-GHKRM4SM.js +1 -0
- package/client-dist/chunk-LMTL7GA3.js +575 -0
- package/client-dist/index.html +17 -0
- package/client-dist/main-2KWB3QYK.js +2 -0
- package/client-dist/polyfills-HGDOEU5L.js +2 -0
- package/client-dist/styles-3J7JD5YE.css +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_WriteTool_Service = void 0;
|
|
4
|
+
const error_codes_const_1 = require("../../../_collections/error-codes.const");
|
|
5
|
+
const fam_error_factory_util_1 = require("../../../_collections/fam-error-factory.util");
|
|
6
|
+
const fam_entry_data_model_1 = require("../../../_models/data-models/fam-entry.data-model");
|
|
7
|
+
const embedding_1 = require("../../embedding");
|
|
8
|
+
const ingest_1 = require("../../ingest");
|
|
9
|
+
const migration_1 = require("../../migration");
|
|
10
|
+
const scope_reference_1 = require("../../scope-reference");
|
|
11
|
+
const fam_mcp_interface_1 = require("../_models/interfaces/fam-mcp.interface");
|
|
12
|
+
/**
|
|
13
|
+
* `FAM_WriteTool_Service` (SP-6.3, dsgn-003 §3) — a `write` core-tool **döntési kapuja**. Singleton.
|
|
14
|
+
* **MINDIG pontosan 1 `table`**; a scope KÖTELEZŐ minden tartalom-műveletnél (`create`/`scan-*`/
|
|
15
|
+
* `import`, dsgn-002 §3.2). EGY belépési pont (`handle`), amit MIND az MCP-tool, MIND a REST `POST
|
|
16
|
+
* /write` hív (transport-paritás, SP-6.5).
|
|
17
|
+
*
|
|
18
|
+
* A handler egy **operation-router** — NEM implementál CRUD/scan/embed logikát, csak validál + scope-ot
|
|
19
|
+
* old fel + a már megépített rétegekre delegál:
|
|
20
|
+
* - `create`/`update`/`delete` → MP-1 CRUD (`FAM_Entry_DataService`; `delete` = soft-delete default),
|
|
21
|
+
* - `scan-file`/`scan-folder`/`scan-project` → MP-4 (`FAM_Ingest_ControlService`),
|
|
22
|
+
* - `re-embed` → MP-2 (`FAM_EmbeddingPipeline_ControlService`),
|
|
23
|
+
* - `import` → **MP-11** (`FAM_ClaudeMemImport_ControlService.run` thin-wrapper, dsgn-009 — NEM vak bulk-insert).
|
|
24
|
+
*
|
|
25
|
+
* **FIGYELEM (memory: dynts_dataservice_eager_resolve):** NEM tartunk élő DataService mezőt; minden
|
|
26
|
+
* DB-művelet előtt lazy `new FAM_Entry_DataService`.
|
|
27
|
+
*/
|
|
28
|
+
class FAM_WriteTool_Service {
|
|
29
|
+
static _instance;
|
|
30
|
+
/** Default issuer (a validációs / scope hibák issuer-éhez; dsgn-008). */
|
|
31
|
+
issuer = 'FAM_WriteTool_Service';
|
|
32
|
+
static getInstance() {
|
|
33
|
+
if (!FAM_WriteTool_Service._instance) {
|
|
34
|
+
FAM_WriteTool_Service._instance = new FAM_WriteTool_Service();
|
|
35
|
+
}
|
|
36
|
+
return FAM_WriteTool_Service._instance;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A `write` core-handler (dsgn-003 §3). Validál (pontosan 1 table) → operation-router. A dobott
|
|
40
|
+
* `DyFM_Error` (validáció / scope / réteg-hiba) az adaptor/REST-rétegen át strukturált hibává
|
|
41
|
+
* fordul; a részleges scan-hiba a kimenet `scan.status='partial-failed'`-ban látszik (nem dob).
|
|
42
|
+
*/
|
|
43
|
+
async handle(input) {
|
|
44
|
+
this.validate(input);
|
|
45
|
+
switch (input.operation) {
|
|
46
|
+
case fam_mcp_interface_1.FAM_WriteOperation.create:
|
|
47
|
+
return this.handleCreate(input);
|
|
48
|
+
case fam_mcp_interface_1.FAM_WriteOperation.update:
|
|
49
|
+
return this.handleUpdate(input);
|
|
50
|
+
case fam_mcp_interface_1.FAM_WriteOperation.delete:
|
|
51
|
+
return this.handleDelete(input);
|
|
52
|
+
case fam_mcp_interface_1.FAM_WriteOperation.scanFile:
|
|
53
|
+
case fam_mcp_interface_1.FAM_WriteOperation.scanFolder:
|
|
54
|
+
case fam_mcp_interface_1.FAM_WriteOperation.scanProject:
|
|
55
|
+
return this.handleScan(input);
|
|
56
|
+
case fam_mcp_interface_1.FAM_WriteOperation.reEmbed:
|
|
57
|
+
return this.handleReEmbed(input);
|
|
58
|
+
case fam_mcp_interface_1.FAM_WriteOperation.import:
|
|
59
|
+
return this.handleImport(input);
|
|
60
|
+
default:
|
|
61
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
62
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
63
|
+
message: `Ismeretlen write-operation: '${input.operation}'. Megengedett: create | update | `
|
|
64
|
+
+ 'delete | scan-file | scan-folder | scan-project | re-embed | import.',
|
|
65
|
+
issuer: this.issuer,
|
|
66
|
+
context: { operation: 'write-validate' },
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// =========================================================================
|
|
71
|
+
// Validáció (dsgn-003 §3.1 / §6.3)
|
|
72
|
+
// =========================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Alap-validáció (DB-független, a delegálás ELŐTT): a `table` + az `operation` kötelező (a
|
|
75
|
+
* pontos-1-table a típus garantálja); az `update`/`delete` `target`-et igényel. Így a precíz
|
|
76
|
+
* validációs kód (`FAM-VAL-WRITE-003`) MIELŐTT bármilyen data-service / DB-művelet fut.
|
|
77
|
+
*/
|
|
78
|
+
validate(input) {
|
|
79
|
+
if (!input || !input.table) {
|
|
80
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
81
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
82
|
+
message: 'A `write` PONTOSAN egy `table`-t igényel (a 6 fő tár vagy `reference`).',
|
|
83
|
+
issuer: this.issuer,
|
|
84
|
+
context: { operation: 'write-validate' },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (!input.operation) {
|
|
88
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
89
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
90
|
+
message: 'A `write` `operation`-t igényel (create | update | delete | scan-* | re-embed | import).',
|
|
91
|
+
issuer: this.issuer,
|
|
92
|
+
context: { operation: 'write-validate', table: input.table },
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const needsTarget = input.operation === fam_mcp_interface_1.FAM_WriteOperation.update || input.operation === fam_mcp_interface_1.FAM_WriteOperation.delete;
|
|
96
|
+
if (needsTarget && (!input.target || !input.target.by || !input.target.value)) {
|
|
97
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
98
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteTargetAmbiguous,
|
|
99
|
+
message: 'Az `update`/`delete` művelethez `target` kötelező ({ by: id|sourceFilePath|query, value }).',
|
|
100
|
+
issuer: this.issuer,
|
|
101
|
+
context: { operation: 'write-validate', table: input.table },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// =========================================================================
|
|
106
|
+
// create / update / delete → MP-1 CRUD (FAM_Entry_DataService)
|
|
107
|
+
// =========================================================================
|
|
108
|
+
/**
|
|
109
|
+
* `create` (dsgn-003 §3.1) → MP-1 insert + MP-2 embed. A scope KÖTELEZŐ (MP-3 `resolveForWrite`);
|
|
110
|
+
* a `content` kötelező. A persist UTÁN auto-embed (`embedAndPersist`) — az embed-hiba az entry-t
|
|
111
|
+
* `error`-státuszba teszi + persistál (no-silent-failure, NEM dob ide).
|
|
112
|
+
*/
|
|
113
|
+
async handleCreate(input) {
|
|
114
|
+
if (!input.content || !input.content.trim().length) {
|
|
115
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
116
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
117
|
+
message: 'A `create` művelethez `content` kötelező (a vektorizálandó, ember-olvasható szöveg).',
|
|
118
|
+
issuer: this.issuer,
|
|
119
|
+
context: { operation: 'write-create', table: input.table },
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const resolve = await this.resolveScope(input);
|
|
123
|
+
const registryEntry = this.requireRegistryEntry(input.table, 'write-create');
|
|
124
|
+
const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: this.issuer });
|
|
125
|
+
const entry = new fam_entry_data_model_1.FAM_Entry({
|
|
126
|
+
table: input.table,
|
|
127
|
+
kind: input.kind,
|
|
128
|
+
tags: input.tags ?? [],
|
|
129
|
+
content: input.content,
|
|
130
|
+
scopePath: resolve.scopePath,
|
|
131
|
+
weight: input.weight,
|
|
132
|
+
importance: input.importance,
|
|
133
|
+
embeddingStatus: 'pending',
|
|
134
|
+
addedBy: 'agent-write',
|
|
135
|
+
source: this.agentSource(),
|
|
136
|
+
...(input.fields ?? {}),
|
|
137
|
+
});
|
|
138
|
+
const saved = await dataService.saveData(entry);
|
|
139
|
+
const createdId = saved._id ?? '';
|
|
140
|
+
const embedOutcome = await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().embedAndPersist({
|
|
141
|
+
table: input.table, entry: saved, callType: 'embed-write',
|
|
142
|
+
});
|
|
143
|
+
const warnings = embedOutcome.status === 'error'
|
|
144
|
+
? ['Az entry mentve, de az embedding sikertelen (érdemes ellenőrizni az embedding-providert; `re-embed`).']
|
|
145
|
+
: [];
|
|
146
|
+
return this.baseOutput({
|
|
147
|
+
operation: input.operation, table: input.table, scopePath: resolve.scopePath,
|
|
148
|
+
uncertaintyNotes: resolve.uncertaintyNotes, created: createdId ? [createdId] : [], warnings: warnings,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* `update` (dsgn-003 §3.1) → MP-1 modify + (ha content változott) MP-2 re-embed. A `target`
|
|
153
|
+
* kötelező (`id`/`sourceFilePath`/`query`). A scope opcionális update-nél (a meglévő entry scope-ja
|
|
154
|
+
* marad, ha nincs új). A content-frissítés UTÁN auto-embed.
|
|
155
|
+
*/
|
|
156
|
+
async handleUpdate(input) {
|
|
157
|
+
const registryEntry = this.requireRegistryEntry(input.table, 'write-update');
|
|
158
|
+
const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: this.issuer });
|
|
159
|
+
const targetEntry = await this.resolveTarget(input, dataService, 'write-update');
|
|
160
|
+
// Mező-frissítés (csak a megadott mezők; a content-változás re-embedet vált).
|
|
161
|
+
const contentChanged = input.content !== undefined && input.content !== targetEntry.content;
|
|
162
|
+
if (input.content !== undefined) {
|
|
163
|
+
targetEntry.content = input.content;
|
|
164
|
+
targetEntry.embeddingStatus = 'pending';
|
|
165
|
+
}
|
|
166
|
+
if (input.kind !== undefined) {
|
|
167
|
+
targetEntry.kind = input.kind;
|
|
168
|
+
}
|
|
169
|
+
if (input.tags !== undefined) {
|
|
170
|
+
targetEntry.tags = input.tags;
|
|
171
|
+
}
|
|
172
|
+
if (input.weight !== undefined) {
|
|
173
|
+
targetEntry.weight = input.weight;
|
|
174
|
+
}
|
|
175
|
+
if (input.importance !== undefined) {
|
|
176
|
+
targetEntry.importance = input.importance;
|
|
177
|
+
}
|
|
178
|
+
if (input.fields) {
|
|
179
|
+
Object.assign(targetEntry, input.fields);
|
|
180
|
+
}
|
|
181
|
+
const saved = await dataService.saveData(targetEntry);
|
|
182
|
+
const updatedId = saved._id ?? '';
|
|
183
|
+
const warnings = [];
|
|
184
|
+
if (contentChanged) {
|
|
185
|
+
const embedOutcome = await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().embedAndPersist({
|
|
186
|
+
table: input.table, entry: saved, callType: 'embed-write',
|
|
187
|
+
});
|
|
188
|
+
if (embedOutcome.status === 'error') {
|
|
189
|
+
warnings.push('Az entry frissítve, de a re-embed sikertelen (ellenőrizd az embedding-providert).');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return this.baseOutput({
|
|
193
|
+
operation: input.operation, table: input.table,
|
|
194
|
+
scopePath: (saved.scopePath ?? []),
|
|
195
|
+
uncertaintyNotes: [], updated: updatedId ? [updatedId] : [], warnings: warnings,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* `delete` (dsgn-003 §3.1) → MP-1 **soft-delete** (default; a hard-delete csak admin-capability,
|
|
200
|
+
* NEM érhető el a `write` tool-ról). A `target` kötelező. A `DyNTS_DataService.deleteData(id)` az
|
|
201
|
+
* `absolute=false` alapértékkel soft-delete-et végez (archív → history).
|
|
202
|
+
*/
|
|
203
|
+
async handleDelete(input) {
|
|
204
|
+
const registryEntry = this.requireRegistryEntry(input.table, 'write-delete');
|
|
205
|
+
const dataService = new embedding_1.FAM_Entry_DataService({ dataParams: registryEntry.dataParams, issuer: this.issuer });
|
|
206
|
+
const targetEntry = await this.resolveTarget(input, dataService, 'write-delete');
|
|
207
|
+
const deletedId = targetEntry._id ?? '';
|
|
208
|
+
if (deletedId) {
|
|
209
|
+
// absolute=false → soft-delete (a Dynamo-konvenció: a _deleted marker, archív collection).
|
|
210
|
+
await dataService.deleteData(deletedId, false);
|
|
211
|
+
}
|
|
212
|
+
return this.baseOutput({
|
|
213
|
+
operation: input.operation, table: input.table,
|
|
214
|
+
scopePath: (targetEntry.scopePath ?? []),
|
|
215
|
+
uncertaintyNotes: [], deleted: deletedId ? [deletedId] : [], warnings: [],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// =========================================================================
|
|
219
|
+
// scan-* → MP-4 (FAM_Ingest_ControlService)
|
|
220
|
+
// =========================================================================
|
|
221
|
+
/**
|
|
222
|
+
* `scan-file`/`scan-folder`/`scan-project` (dsgn-003 §3.1) → MP-4 ingest-pipeline. A scope
|
|
223
|
+
* KÖTELEZŐ + a `scan.path` kötelező; a per-fájl hiba NEM buktatja a run-t (`status:'partial-failed'`).
|
|
224
|
+
* A scope-resolve-ot az ingest-orchestrátor MAGA végzi (a raw scopePath-ot kapja).
|
|
225
|
+
*/
|
|
226
|
+
async handleScan(input) {
|
|
227
|
+
const scopePath = this.requireScope(input, 'write-scan');
|
|
228
|
+
const scan = this.requireScan(input);
|
|
229
|
+
const request = {
|
|
230
|
+
path: scan.path,
|
|
231
|
+
scopePath: scopePath,
|
|
232
|
+
include: scan.include,
|
|
233
|
+
exclude: scan.exclude,
|
|
234
|
+
dryRun: scan.dryRun,
|
|
235
|
+
issuer: this.issuer,
|
|
236
|
+
};
|
|
237
|
+
let summary;
|
|
238
|
+
if (input.operation === fam_mcp_interface_1.FAM_WriteOperation.scanFile) {
|
|
239
|
+
summary = await ingest_1.FAM_Ingest_ControlService.getInstance().scanFile(request);
|
|
240
|
+
}
|
|
241
|
+
else if (input.operation === fam_mcp_interface_1.FAM_WriteOperation.scanFolder) {
|
|
242
|
+
summary = await ingest_1.FAM_Ingest_ControlService.getInstance().scanFolder(request);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
summary = await ingest_1.FAM_Ingest_ControlService.getInstance().scanProject(request);
|
|
246
|
+
}
|
|
247
|
+
const warnings = summary.status === 'failed'
|
|
248
|
+
? ['A scan a fájl-bejárás előtt megállt (lásd a hibákat a `list_errors`-ban).']
|
|
249
|
+
: summary.status === 'partial-failed'
|
|
250
|
+
? ['A scan részben sikerült — egyes fájlok kihagyva (lásd `list_errors`).']
|
|
251
|
+
: [];
|
|
252
|
+
return {
|
|
253
|
+
operation: input.operation, table: input.table, ok: summary.status !== 'failed',
|
|
254
|
+
created: [], updated: [], deleted: [], scopePath: summary.scopePath,
|
|
255
|
+
scan: {
|
|
256
|
+
filesProcessed: summary.filesProcessed, chunks: summary.chunkCount,
|
|
257
|
+
verdicts: summary.verdicts, status: summary.status,
|
|
258
|
+
},
|
|
259
|
+
ingestRunId: summary.ingestRunId, uncertaintyNotes: [], warnings: warnings,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
// =========================================================================
|
|
263
|
+
// re-embed → MP-2 (FAM_EmbeddingPipeline_ControlService)
|
|
264
|
+
// =========================================================================
|
|
265
|
+
/**
|
|
266
|
+
* `re-embed` (dsgn-003 §3.1) → MP-2. A `table` (és opc. `scopePath`) minden chunkját újra-embeddeli
|
|
267
|
+
* az AKTUÁLIS modellel. Ha scope adott → `reEmbedScope` (a raw scope-ot feloldjuk canonical-ra),
|
|
268
|
+
* egyébként `reEmbedTable` (teljes tár).
|
|
269
|
+
*/
|
|
270
|
+
async handleReEmbed(input) {
|
|
271
|
+
this.requireRegistryEntry(input.table, 'write-re-embed');
|
|
272
|
+
let result;
|
|
273
|
+
let canonicalScope = [];
|
|
274
|
+
let uncertaintyNotes = [];
|
|
275
|
+
if (input.scopePath && input.scopePath.length) {
|
|
276
|
+
const resolve = await scope_reference_1.FAM_ScopeResolver_ControlService.getInstance().resolveForWrite(input.scopePath);
|
|
277
|
+
canonicalScope = resolve.scopePath;
|
|
278
|
+
uncertaintyNotes = resolve.uncertaintyNotes;
|
|
279
|
+
result = await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().reEmbedScope(input.table, canonicalScope);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
result = await embedding_1.FAM_EmbeddingPipeline_ControlService.getInstance().reEmbedTable(input.table);
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
operation: input.operation, table: input.table, ok: result.failed === 0,
|
|
286
|
+
created: [], updated: [], deleted: [], scopePath: canonicalScope,
|
|
287
|
+
reEmbed: {
|
|
288
|
+
total: result.total, reembedded: result.reembedded, skipped: result.skipped, failed: result.failed,
|
|
289
|
+
},
|
|
290
|
+
ingestRunId: null, uncertaintyNotes: uncertaintyNotes,
|
|
291
|
+
warnings: result.failed ? [`${result.failed} chunk re-embedje sikertelen (lásd \`list_errors\`).`] : [],
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
// =========================================================================
|
|
295
|
+
// import → MP-11 thin-wrapper (claude-mem migráció; dsgn-009)
|
|
296
|
+
// =========================================================================
|
|
297
|
+
/**
|
|
298
|
+
* `import` (dsgn-003 §3.1, dsgn-009) → a MP-11 migrációs engine **thin-wrapper**-e. SOSEM vak
|
|
299
|
+
* bulk-insert (dsgn-003 §4.2): a `FAM_ClaudeMemImport_ControlService.run`-t hívja (a teljes
|
|
300
|
+
* preview→map→run folyamat `run`-fázisa: dedup-skip + map + persist + embed egy batchId alatt). A
|
|
301
|
+
* finomhangolt preview/map/rollback a capabilities import-katalógusán érhető el; ez a write-belépés
|
|
302
|
+
* az alapértelmezett, egylépéses import. **Egyirányú** (dsgn-009 §7) — nincs reverse.
|
|
303
|
+
*
|
|
304
|
+
* A `run` eredményét a `write` kimenetre képezi: az `ingested` az `created`-ben (a batchId mint
|
|
305
|
+
* összegző), a `batchId` az `ingestRunId`-ben; a `failed>0` a `warnings`-ban + a `status` az
|
|
306
|
+
* `ok`-ban. A strukturált `errors[]` a `run`-ban MÁR persistált (no-silent-failure).
|
|
307
|
+
*/
|
|
308
|
+
async handleImport(input) {
|
|
309
|
+
const importOptions = input.import;
|
|
310
|
+
if (!importOptions || !importOptions.source) {
|
|
311
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
312
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.impSource,
|
|
313
|
+
message: 'Az `import` művelethez `import` blokk kötelező ({ source, from?, path? }) — a forrás '
|
|
314
|
+
+ '(MVP1: `claude-mem`) + a csatorna (`export-json`/`sqlite`/`worker-api`) + az útvonal.',
|
|
315
|
+
issuer: this.issuer,
|
|
316
|
+
context: { operation: 'write-import', table: input.table },
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
const request = {
|
|
320
|
+
source: importOptions.source,
|
|
321
|
+
from: this.toImportFrom(importOptions.from),
|
|
322
|
+
path: importOptions.path,
|
|
323
|
+
};
|
|
324
|
+
const result = await migration_1.FAM_ClaudeMemImport_ControlService.getInstance().run(request);
|
|
325
|
+
const warnings = [];
|
|
326
|
+
if (result.failed) {
|
|
327
|
+
warnings.push(`${result.failed} rekord importja sikertelen (lásd \`list_errors\`); a batch `
|
|
328
|
+
+ `${result.status}. batchId='${result.batchId}' (visszavonható: \`rollback_import\`).`);
|
|
329
|
+
}
|
|
330
|
+
if (result.skipped) {
|
|
331
|
+
warnings.push(`${result.skipped} rekord dedup-skip-elve (már importált / duplikált tartalom) — `
|
|
332
|
+
+ 'nem keletkezett duplikátum, nem embeddelődtek újra.');
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
operation: input.operation, table: input.table, ok: result.ok,
|
|
336
|
+
created: [], updated: [], deleted: [], scopePath: [],
|
|
337
|
+
ingestRunId: result.batchId,
|
|
338
|
+
uncertaintyNotes: result.uncertaintyNotes, warnings: warnings,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
/** Egy `from` string → `FAM_ClaudeMemSource_Type` (vagy undefined → a engine default export-json). */
|
|
342
|
+
toImportFrom(from) {
|
|
343
|
+
return from
|
|
344
|
+
? Object.values(migration_1.FAM_ClaudeMemSource_Type).find((source) => source === from)
|
|
345
|
+
: undefined;
|
|
346
|
+
}
|
|
347
|
+
// =========================================================================
|
|
348
|
+
// helpers
|
|
349
|
+
// =========================================================================
|
|
350
|
+
/**
|
|
351
|
+
* A scope-resolve (MP-3 `resolveForWrite`) a tartalom-műveletekhez (`create`). A scope KÖTELEZŐ
|
|
352
|
+
* (üres → `FAM-SCOPE-WRITE-001` az engine-ben). Van-match-bizonytalan → `uncertaintyNotes` (nem hiba).
|
|
353
|
+
*/
|
|
354
|
+
async resolveScope(input) {
|
|
355
|
+
const scopePath = this.requireScope(input, 'write-resolve');
|
|
356
|
+
return scope_reference_1.FAM_ScopeResolver_ControlService.getInstance().resolveForWrite(scopePath);
|
|
357
|
+
}
|
|
358
|
+
/** A scope-kötelezőség enforcement (create/scan/import) — hiánya → `FAM-SCOPE-WRITE-001`. */
|
|
359
|
+
requireScope(input, operation) {
|
|
360
|
+
if (!input.scopePath || !input.scopePath.length) {
|
|
361
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
362
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.scopeWriteRequired,
|
|
363
|
+
message: 'A scope KÖTELEZŐ a tartalom-műveleteknél (create/scan-*/import) — adj meg legalább '
|
|
364
|
+
+ 'egy layert (pl. organization/project) a `scopePath`-ban.',
|
|
365
|
+
issuer: this.issuer,
|
|
366
|
+
context: { operation: operation, table: input.table },
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return input.scopePath;
|
|
370
|
+
}
|
|
371
|
+
/** A `scan` blokk kötelezőség-enforcement (scan-* esetén). */
|
|
372
|
+
requireScan(input) {
|
|
373
|
+
if (!input.scan || !input.scan.path) {
|
|
374
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
375
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
376
|
+
message: 'A `scan-*` művelethez `scan.path` kötelező (a scan-gyökér file/folder/project).',
|
|
377
|
+
issuer: this.issuer,
|
|
378
|
+
context: { operation: 'write-scan', table: input.table },
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return input.scan;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Az update/delete cél-entry feloldása (`target`: `id`/`sourceFilePath`/`query`). A `query`-mód
|
|
385
|
+
* MVP1-ben sourceFilePath/exact-content helyett egyszerű (a vektor-keresés a `read` dolga) — a
|
|
386
|
+
* `query` itt a `content` substring-jét keresi. Nem egyértelmű cél → `FAM-VAL-WRITE-003`.
|
|
387
|
+
*/
|
|
388
|
+
async resolveTarget(input, dataService, operation) {
|
|
389
|
+
const target = input.target;
|
|
390
|
+
if (!target || !target.by || !target.value) {
|
|
391
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
392
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteTargetAmbiguous,
|
|
393
|
+
message: 'Az `update`/`delete` művelethez `target` kötelező ({ by: id|sourceFilePath|query, value }).',
|
|
394
|
+
issuer: this.issuer,
|
|
395
|
+
context: { operation: operation, table: input.table },
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (target.by === 'id') {
|
|
399
|
+
const byId = await dataService.findData({ _id: target.value }, true);
|
|
400
|
+
if (!byId || !byId._id) {
|
|
401
|
+
throw this.targetNotFound(input, target, operation);
|
|
402
|
+
}
|
|
403
|
+
return byId;
|
|
404
|
+
}
|
|
405
|
+
const filter = target.by === 'sourceFilePath'
|
|
406
|
+
? { sourceFilePath: target.value }
|
|
407
|
+
: { content: target.value };
|
|
408
|
+
const matches = await dataService.findDataList(filter);
|
|
409
|
+
if (!matches.length) {
|
|
410
|
+
throw this.targetNotFound(input, target, operation);
|
|
411
|
+
}
|
|
412
|
+
if (matches.length > 1) {
|
|
413
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
414
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteTargetAmbiguous,
|
|
415
|
+
message: `A '${target.by}'='${target.value}' cél több (${matches.length}) entry-re illeszkedik — `
|
|
416
|
+
+ 'pontosíts (`by:id` egyedi azonosítóval).',
|
|
417
|
+
issuer: this.issuer,
|
|
418
|
+
context: { operation: operation, table: input.table },
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return matches[0];
|
|
422
|
+
}
|
|
423
|
+
/** A cél nem található → `FAM-VAL-WRITE-003` (deskriptív). */
|
|
424
|
+
targetNotFound(input, target, operation) {
|
|
425
|
+
return fam_error_factory_util_1.FAM_Error_Util.create({
|
|
426
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteTargetAmbiguous,
|
|
427
|
+
message: `A '${target.by}'='${target.value}' cél nem található a(z) '${input.table}' tárban.`,
|
|
428
|
+
issuer: this.issuer,
|
|
429
|
+
context: { operation: operation, table: input.table },
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/** A `table` store-registry bejegyzése (a 6 fő tárra). Hiányzó (pl. `reference`) → leíró hiba. */
|
|
433
|
+
requireRegistryEntry(table, operation) {
|
|
434
|
+
const registryEntry = embedding_1.FAM_StoreRegistry_Util.getEntry(table);
|
|
435
|
+
if (!registryEntry) {
|
|
436
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
437
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteReferenceContent,
|
|
438
|
+
message: `A(z) '${table}' tár nem fogad tartalom-CRUD-ot ezen az úton (a 6 fő tár: rules/documents/`
|
|
439
|
+
+ 'codebase/knowledge/coding_patterns/memory). A `reference` helper-tár külön capability-n kezelt.',
|
|
440
|
+
issuer: this.issuer,
|
|
441
|
+
context: { operation: operation, table: table },
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
return registryEntry;
|
|
445
|
+
}
|
|
446
|
+
/** Az agent-write provenance (a `write` tool minden create-je `agent`-forrású). */
|
|
447
|
+
agentSource() {
|
|
448
|
+
return { type: 'agent' };
|
|
449
|
+
}
|
|
450
|
+
/** A `write` kimenet alap-burka (a per-operation handlerek ezt töltik ki). */
|
|
451
|
+
baseOutput(set) {
|
|
452
|
+
return {
|
|
453
|
+
operation: set.operation, table: set.table, ok: true,
|
|
454
|
+
created: set.created ?? [], updated: set.updated ?? [], deleted: set.deleted ?? [],
|
|
455
|
+
scopePath: set.scopePath, ingestRunId: null,
|
|
456
|
+
uncertaintyNotes: set.uncertaintyNotes, warnings: set.warnings,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
exports.FAM_WriteTool_Service = FAM_WriteTool_Service;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `mcp` modul barrel (MP-6, dsgn-003) — az MCP-szerver + a 3 core-tool + a capability-registry
|
|
4
|
+
* publikus felülete. A fogyasztók: az `index.ts` (CLI entry: `fam start` → `FAM_McpServer_Service`),
|
|
5
|
+
* a REST-réteg (`_routes/server/api`, SP-6.5: a transport-agnosztikus core `FAM_*Tool_Service`-ek a
|
|
6
|
+
* REST-mirrorhoz), és a contract-tesztek (advertised-tool + diszjunkció).
|
|
7
|
+
*
|
|
8
|
+
* Boundary (dsgn-003 §5, BFR-AM-003): a `FAM_Mcp_Adapter` az EGYETLEN choke-pont a hivatalos
|
|
9
|
+
* `@modelcontextprotocol/sdk` köré — a bedrock `DyNTS_Mcp_*` (MP-15) csere itt non-breaking. A 3
|
|
10
|
+
* core-tool + a capability-registry transport-agnosztikus (MCP stdio + REST UGYANEZT hívja).
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.FAM_WriteOperation = exports.FAM_CapabilityCategory = exports.FAM_CapabilityRegistry = exports.FAM_CapabilitiesTool_Service = exports.FAM_WriteTool_Service = exports.FAM_ReadTool_Service = exports.FAM_CORE_TOOLS = exports.FAM_McpServer_Service = exports.FAM_Mcp_Adapter = void 0;
|
|
14
|
+
// SP-6.1 — MCP infra (adaptor + szerver-orchestrátor)
|
|
15
|
+
var fam_mcp_adapter_service_1 = require("./_services/fam-mcp-adapter.service");
|
|
16
|
+
Object.defineProperty(exports, "FAM_Mcp_Adapter", { enumerable: true, get: function () { return fam_mcp_adapter_service_1.FAM_Mcp_Adapter; } });
|
|
17
|
+
var fam_mcp_server_service_1 = require("./_services/fam-mcp-server.service");
|
|
18
|
+
Object.defineProperty(exports, "FAM_McpServer_Service", { enumerable: true, get: function () { return fam_mcp_server_service_1.FAM_McpServer_Service; } });
|
|
19
|
+
var fam_core_tools_const_1 = require("./_collections/fam-core-tools.const");
|
|
20
|
+
Object.defineProperty(exports, "FAM_CORE_TOOLS", { enumerable: true, get: function () { return fam_core_tools_const_1.FAM_CORE_TOOLS; } });
|
|
21
|
+
// SP-6.2 — `read` core-handler (transport-agnosztikus; REST + MCP UGYANEZT hívja)
|
|
22
|
+
var fam_read_tool_service_1 = require("./_services/fam-read-tool.service");
|
|
23
|
+
Object.defineProperty(exports, "FAM_ReadTool_Service", { enumerable: true, get: function () { return fam_read_tool_service_1.FAM_ReadTool_Service; } });
|
|
24
|
+
// SP-6.3 — `write` core-handler (operation-router; transport-agnosztikus)
|
|
25
|
+
var fam_write_tool_service_1 = require("./_services/fam-write-tool.service");
|
|
26
|
+
Object.defineProperty(exports, "FAM_WriteTool_Service", { enumerable: true, get: function () { return fam_write_tool_service_1.FAM_WriteTool_Service; } });
|
|
27
|
+
// SP-6.4 — `capabilities` core-handler + special-tool registry
|
|
28
|
+
var fam_capabilities_tool_service_1 = require("./_services/fam-capabilities-tool.service");
|
|
29
|
+
Object.defineProperty(exports, "FAM_CapabilitiesTool_Service", { enumerable: true, get: function () { return fam_capabilities_tool_service_1.FAM_CapabilitiesTool_Service; } });
|
|
30
|
+
var fam_capability_registry_service_1 = require("./_services/fam-capability-registry.service");
|
|
31
|
+
Object.defineProperty(exports, "FAM_CapabilityRegistry", { enumerable: true, get: function () { return fam_capability_registry_service_1.FAM_CapabilityRegistry; } });
|
|
32
|
+
// shared vokabulár (a REST-réteg + a contract-tesztek fogyasztják)
|
|
33
|
+
var fam_mcp_interface_1 = require("./_models/interfaces/fam-mcp.interface");
|
|
34
|
+
Object.defineProperty(exports, "FAM_CapabilityCategory", { enumerable: true, get: function () { return fam_mcp_interface_1.FAM_CapabilityCategory; } });
|
|
35
|
+
Object.defineProperty(exports, "FAM_WriteOperation", { enumerable: true, get: function () { return fam_mcp_interface_1.FAM_WriteOperation; } });
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_ClaudeMemNormalize_Util = void 0;
|
|
4
|
+
const fam_claude_mem_interface_1 = require("../_models/interfaces/fam-claude-mem.interface");
|
|
5
|
+
/**
|
|
6
|
+
* `FAM_ClaudeMemNormalize_Util` (SP-11.1) — a nyers forrás-rekordokat (observations / summaries /
|
|
7
|
+
* prompts / sessions) a KÖZÖS `FAM_ClaudeMemRecord` köztes shape-re normalizálja. MINDEN reader
|
|
8
|
+
* (export-JSON / SQLite / worker-api) ezt hívja, így a 3 forrás UGYANARRA a tartalomra UGYANAZT a
|
|
9
|
+
* normalizált rekordot adja (paritás — dsgn-009 §9.2). Statikus util (nincs DB-/external-függőség).
|
|
10
|
+
*
|
|
11
|
+
* A `sessions` rekordok NEM normalizálódnak entry-vé (dsgn-009 §2) — metaadatként mennek tovább
|
|
12
|
+
* (`project`→scope + sessionId/runId hidratálás). A `prompts` CSAK `includePrompts:true` esetén
|
|
13
|
+
* kerülnek a normalizált halmazba. A defenzív parse a hiányzó/drift-elt mezőket warning-gal jelzi
|
|
14
|
+
* (nem-néma drop, nem crash — dsgn-009 §9 acceptance).
|
|
15
|
+
*/
|
|
16
|
+
class FAM_ClaudeMemNormalize_Util {
|
|
17
|
+
/**
|
|
18
|
+
* A teljes forrás-halmaz normalizálása (SP-11.1). Az observation-ök + summary-k (+ opc. prompt-ok)
|
|
19
|
+
* a normalizált rekord-listába; a session-ök metaadatként; a nyers counts + defenzív warning-ok.
|
|
20
|
+
*/
|
|
21
|
+
static normalizeAll(set) {
|
|
22
|
+
const records = [];
|
|
23
|
+
const warnings = [];
|
|
24
|
+
for (const observation of set.observations) {
|
|
25
|
+
const record = FAM_ClaudeMemNormalize_Util.normalizeObservation(observation, warnings);
|
|
26
|
+
if (record) {
|
|
27
|
+
records.push(record);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const summary of set.summaries) {
|
|
31
|
+
const record = FAM_ClaudeMemNormalize_Util.normalizeSummary(summary, warnings);
|
|
32
|
+
if (record) {
|
|
33
|
+
records.push(record);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// user_prompts CSAK includePrompts:true esetén (default OFF — dsgn-009 §2 / §9.7).
|
|
37
|
+
if (set.includePrompts) {
|
|
38
|
+
for (const prompt of set.prompts) {
|
|
39
|
+
const record = FAM_ClaudeMemNormalize_Util.normalizePrompt(prompt, warnings);
|
|
40
|
+
if (record) {
|
|
41
|
+
records.push(record);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
from: set.from,
|
|
47
|
+
records: records,
|
|
48
|
+
sessions: set.sessions,
|
|
49
|
+
counts: {
|
|
50
|
+
observations: set.observations.length,
|
|
51
|
+
summaries: set.summaries.length,
|
|
52
|
+
prompts: set.prompts.length,
|
|
53
|
+
sessions: set.sessions.length,
|
|
54
|
+
},
|
|
55
|
+
warnings: warnings,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Egy observation normalizálása. A `id` hiányában nincs ELSŐDLEGES dedup-kulcs → warning + drop
|
|
60
|
+
* (a `contentHash` fallback nélküli rekord dedup-ja megbízhatatlan lenne). A `type` hiánya warning,
|
|
61
|
+
* de NEM drop (a default-mapping `change`-re esik vissza a mapperben).
|
|
62
|
+
*/
|
|
63
|
+
static normalizeObservation(raw, warnings) {
|
|
64
|
+
const sourceRowId = FAM_ClaudeMemNormalize_Util.toStringId(raw.id);
|
|
65
|
+
if (!sourceRowId) {
|
|
66
|
+
warnings.push('Egy observation `id` nélkül érkezett (nincs elsődleges dedup-kulcs) — kihagyva.');
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (!raw.type) {
|
|
70
|
+
warnings.push(`Az observation '${sourceRowId}' 'type' nélkül érkezett — a default-mapping 'change'-re esik vissza.`);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
entity: fam_claude_mem_interface_1.FAM_ClaudeMemEntity_Type.observation,
|
|
74
|
+
sourceRowId: sourceRowId,
|
|
75
|
+
sessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.session_id),
|
|
76
|
+
sdkSessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.sdk_session_id),
|
|
77
|
+
claudeSessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.claude_session_id),
|
|
78
|
+
project: FAM_ClaudeMemNormalize_Util.cleanString(raw.project),
|
|
79
|
+
title: FAM_ClaudeMemNormalize_Util.cleanString(raw.title),
|
|
80
|
+
subtitle: FAM_ClaudeMemNormalize_Util.cleanString(raw.subtitle),
|
|
81
|
+
narrative: FAM_ClaudeMemNormalize_Util.cleanString(raw.narrative),
|
|
82
|
+
text: FAM_ClaudeMemNormalize_Util.cleanString(raw.text),
|
|
83
|
+
facts: FAM_ClaudeMemNormalize_Util.cleanString(raw.facts),
|
|
84
|
+
concepts: FAM_ClaudeMemNormalize_Util.cleanStringArray(raw.concepts),
|
|
85
|
+
type: FAM_ClaudeMemNormalize_Util.cleanString(raw.type),
|
|
86
|
+
filesRead: FAM_ClaudeMemNormalize_Util.cleanStringArray(raw.files_read),
|
|
87
|
+
filesModified: FAM_ClaudeMemNormalize_Util.cleanStringArray(raw.files_modified),
|
|
88
|
+
createdAtEpoch: typeof raw.created_at_epoch === 'number' ? raw.created_at_epoch : undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Egy session_summary normalizálása. A `importSourceId` kulcsa az `sdk_session_id`
|
|
93
|
+
* (`session_summaries:<sdk_session_id>`, dsgn-009 §3 tábla); hiányában a `id`-re esik vissza.
|
|
94
|
+
*/
|
|
95
|
+
static normalizeSummary(raw, warnings) {
|
|
96
|
+
const sourceRowId = FAM_ClaudeMemNormalize_Util.cleanString(raw.sdk_session_id)
|
|
97
|
+
?? FAM_ClaudeMemNormalize_Util.toStringId(raw.id);
|
|
98
|
+
if (!sourceRowId) {
|
|
99
|
+
warnings.push('Egy session_summary `sdk_session_id`/`id` nélkül érkezett — kihagyva.');
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const text = FAM_ClaudeMemNormalize_Util.cleanString(raw.summary) ?? FAM_ClaudeMemNormalize_Util.cleanString(raw.text);
|
|
103
|
+
return {
|
|
104
|
+
entity: fam_claude_mem_interface_1.FAM_ClaudeMemEntity_Type.sessionSummary,
|
|
105
|
+
sourceRowId: sourceRowId,
|
|
106
|
+
sdkSessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.sdk_session_id),
|
|
107
|
+
claudeSessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.claude_session_id),
|
|
108
|
+
project: FAM_ClaudeMemNormalize_Util.cleanString(raw.project),
|
|
109
|
+
title: FAM_ClaudeMemNormalize_Util.cleanString(raw.title),
|
|
110
|
+
text: text,
|
|
111
|
+
concepts: [],
|
|
112
|
+
filesRead: [],
|
|
113
|
+
filesModified: [],
|
|
114
|
+
createdAtEpoch: typeof raw.created_at_epoch === 'number' ? raw.created_at_epoch : undefined,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Egy user_prompt normalizálása (csak `includePrompts:true`). A `importSourceId` kulcsa a
|
|
119
|
+
* `claude_session_id`+`prompt_number` (`user_prompts:<claude_session_id>:<prompt_number>`).
|
|
120
|
+
*/
|
|
121
|
+
static normalizePrompt(raw, warnings) {
|
|
122
|
+
const claudeSessionId = FAM_ClaudeMemNormalize_Util.cleanString(raw.claude_session_id);
|
|
123
|
+
const promptNumber = typeof raw.prompt_number === 'number' ? raw.prompt_number : undefined;
|
|
124
|
+
const sourceRowId = claudeSessionId !== undefined && promptNumber !== undefined
|
|
125
|
+
? `${claudeSessionId}:${promptNumber}`
|
|
126
|
+
: FAM_ClaudeMemNormalize_Util.toStringId(raw.id);
|
|
127
|
+
if (!sourceRowId) {
|
|
128
|
+
warnings.push('Egy user_prompt azonosító nélkül érkezett — kihagyva.');
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
entity: fam_claude_mem_interface_1.FAM_ClaudeMemEntity_Type.userPrompt,
|
|
133
|
+
sourceRowId: sourceRowId,
|
|
134
|
+
sdkSessionId: FAM_ClaudeMemNormalize_Util.cleanString(raw.sdk_session_id),
|
|
135
|
+
claudeSessionId: claudeSessionId,
|
|
136
|
+
project: FAM_ClaudeMemNormalize_Util.cleanString(raw.project),
|
|
137
|
+
promptNumber: promptNumber,
|
|
138
|
+
title: FAM_ClaudeMemNormalize_Util.cleanString(raw.title),
|
|
139
|
+
text: FAM_ClaudeMemNormalize_Util.cleanString(raw.text),
|
|
140
|
+
concepts: [],
|
|
141
|
+
filesRead: [],
|
|
142
|
+
filesModified: [],
|
|
143
|
+
createdAtEpoch: typeof raw.created_at_epoch === 'number' ? raw.created_at_epoch : undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Egy id (string vagy number) string-re — üres/undefined → ''. */
|
|
147
|
+
static toStringId(id) {
|
|
148
|
+
if (id === undefined || id === null) {
|
|
149
|
+
return '';
|
|
150
|
+
}
|
|
151
|
+
return String(id).trim();
|
|
152
|
+
}
|
|
153
|
+
/** Egy érték trim-elt string-ként (üres/nem-string → undefined). */
|
|
154
|
+
static cleanString(value) {
|
|
155
|
+
return typeof value === 'string' && value.trim().length ? value.trim() : undefined;
|
|
156
|
+
}
|
|
157
|
+
/** Egy érték string-tömbként (a nem-string elemek kiszűrve; nem-tömb → []). */
|
|
158
|
+
static cleanStringArray(value) {
|
|
159
|
+
if (!Array.isArray(value)) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
return value.filter((item) => typeof item === 'string' && item.trim().length > 0)
|
|
163
|
+
.map((item) => item.trim());
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.FAM_ClaudeMemNormalize_Util = FAM_ClaudeMemNormalize_Util;
|