wendkeep 0.60.0 → 0.61.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.
@@ -1,128 +1 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { validateMemoryEvent, validateSharedMemory } from '../hooks/memory-schema.mjs';
4
- import { assertVaultPathSafe } from '../hooks/vault-path-safety.mjs';
5
- import { validateCore } from './validate-core.mjs';
6
-
7
- function failedComponent(errors, extra = {}) {
8
- return { ok: false, errors: Array.isArray(errors) ? errors : [errors], warnings: [], ...extra };
9
- }
10
-
11
- function readRequired(vaultBase, path, label) {
12
- let checked;
13
- try {
14
- checked = assertVaultPathSafe(vaultBase, path, {
15
- expectedType: 'file', label: `artefato ${label}`,
16
- });
17
- } catch (error) {
18
- return { ok: false, error: `${label} inseguro: ${error?.message || error}` };
19
- }
20
- if (!checked.exists) return { ok: false, error: `${label} ausente: ${path}` };
21
- try {
22
- // Deliberately adjacent to the open performed by readFileSync.
23
- checked = assertVaultPathSafe(vaultBase, checked.target, {
24
- allowMissing: false, expectedType: 'file', label: `artefato ${label}`,
25
- });
26
- return { ok: true, content: readFileSync(checked.target, 'utf8') };
27
- } catch (error) {
28
- return { ok: false, error: `${label} ilegível: ${error?.message || error}` };
29
- }
30
- }
31
-
32
- export function readProjectForValidation(vaultBase) {
33
- const path = join(vaultBase, '.brain', 'PROJECT.json');
34
- const read = readRequired(vaultBase, path, 'PROJECT.json');
35
- if (!read.ok) return failedComponent(read.error, { projectId: '', path });
36
- try {
37
- const marker = JSON.parse(read.content);
38
- if (!marker || typeof marker.projectId !== 'string' || !marker.projectId) {
39
- return failedComponent('PROJECT.json inválido: projectId ausente.', { projectId: '', path });
40
- }
41
- return { ok: true, errors: [], warnings: [], projectId: marker.projectId, marker, path };
42
- } catch (error) {
43
- return failedComponent(`PROJECT.json contém JSON inválido: ${error?.message || error}`, { projectId: '', path });
44
- }
45
- }
46
-
47
- /** Read and validate the append-only JSONL authority without repairing or mutating it. */
48
- export function readLedgerForValidation(vaultBase, { projectId } = {}) {
49
- const path = join(vaultBase, '.brain', 'MEMORY_EVENTS.jsonl');
50
- const read = readRequired(vaultBase, path, 'MEMORY_EVENTS.jsonl');
51
- if (!read.ok) return failedComponent(read.error, { events: [], eventIds: new Set(), path });
52
-
53
- const errors = [];
54
- const warnings = [];
55
- const events = [];
56
- const eventIds = new Set();
57
- const normalized = read.content.replace(/\r\n/g, '\n');
58
- const lines = normalized.split('\n');
59
- const logicalLines = normalized === '' ? [] : (normalized.endsWith('\n') ? lines.slice(0, -1) : lines);
60
- logicalLines.forEach((line, index) => {
61
- if (!line.trim()) {
62
- errors.push(`MEMORY_EVENTS.jsonl linha ${index + 1} está vazia no meio do ledger.`);
63
- return;
64
- }
65
- let event;
66
- try {
67
- event = JSON.parse(line);
68
- } catch (error) {
69
- errors.push(`MEMORY_EVENTS.jsonl linha ${index + 1} contém JSON inválido/parcial: ${error?.message || error}`);
70
- return;
71
- }
72
- const validation = validateMemoryEvent(event, projectId ? { projectId } : {});
73
- for (const error of validation.errors) errors.push(`MEMORY_EVENTS.jsonl linha ${index + 1}: ${error}`);
74
- for (const warning of validation.warnings) warnings.push(`MEMORY_EVENTS.jsonl linha ${index + 1}: ${warning}`);
75
- if (typeof event?.event_id === 'string' && event.event_id) {
76
- if (eventIds.has(event.event_id)) errors.push(`MEMORY_EVENTS.jsonl event_id duplicado: ${event.event_id}.`);
77
- eventIds.add(event.event_id);
78
- }
79
- events.push(event);
80
- });
81
-
82
- return {
83
- ok: errors.length === 0,
84
- errors,
85
- warnings,
86
- events,
87
- eventIds,
88
- lineCount: logicalLines.length,
89
- path,
90
- };
91
- }
92
-
93
- function validateCoreArtifact(vaultBase) {
94
- const path = join(vaultBase, '.brain', 'CORE.md');
95
- const read = readRequired(vaultBase, path, 'CORE.md');
96
- if (!read.ok) return failedComponent(read.error, { lineCount: 0, path });
97
- return { ...validateCore(read.content), path, content: read.content };
98
- }
99
-
100
- function validateSharedArtifact(vaultBase, eventIds) {
101
- const path = join(vaultBase, '.brain', 'SHARED_MEMORY.md');
102
- const read = readRequired(vaultBase, path, 'SHARED_MEMORY.md');
103
- if (!read.ok) return failedComponent(read.error, { path });
104
- return { ...validateSharedMemory(read.content, { eventIds }), path, content: read.content };
105
- }
106
-
107
- export function combineMemoryResults({ project, core, ledger, shared }) {
108
- const components = { project, core, ledger, shared };
109
- const errors = [];
110
- const warnings = [];
111
- for (const [name, result] of Object.entries(components)) {
112
- for (const error of result?.errors || []) errors.push(`${name}: ${error}`);
113
- for (const warning of result?.warnings || []) warnings.push(`${name}: ${warning}`);
114
- }
115
- return { ok: errors.length === 0, errors, warnings, ...components };
116
- }
117
-
118
- /**
119
- * Validate the v2 local memory bundle as a read-only composition. Missing/corrupt
120
- * artifacts remain explicit failures; they are never silently treated as empty.
121
- */
122
- export function validateMemoryBundle(vaultBase) {
123
- const project = readProjectForValidation(vaultBase);
124
- const core = validateCoreArtifact(vaultBase);
125
- const ledger = readLedgerForValidation(vaultBase, { projectId: project.projectId });
126
- const shared = validateSharedArtifact(vaultBase, ledger.eventIds);
127
- return combineMemoryResults({ project, core, ledger, shared });
128
- }
1
+ export * from '../packages/vault/src/validate-memory.mjs';