@lumenflow/memory 1.0.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/LICENSE +190 -0
- package/README.md +181 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/mem-checkpoint-core.d.ts +91 -0
- package/dist/mem-checkpoint-core.d.ts.map +1 -0
- package/dist/mem-checkpoint-core.js +175 -0
- package/dist/mem-checkpoint-core.js.map +1 -0
- package/dist/mem-cleanup-core.d.ts +202 -0
- package/dist/mem-cleanup-core.d.ts.map +1 -0
- package/dist/mem-cleanup-core.js +364 -0
- package/dist/mem-cleanup-core.js.map +1 -0
- package/dist/mem-create-core.d.ts +93 -0
- package/dist/mem-create-core.d.ts.map +1 -0
- package/dist/mem-create-core.js +369 -0
- package/dist/mem-create-core.js.map +1 -0
- package/dist/mem-id.d.ts +91 -0
- package/dist/mem-id.d.ts.map +1 -0
- package/dist/mem-id.js +136 -0
- package/dist/mem-id.js.map +1 -0
- package/dist/mem-init-core.d.ts +91 -0
- package/dist/mem-init-core.d.ts.map +1 -0
- package/dist/mem-init-core.js +138 -0
- package/dist/mem-init-core.js.map +1 -0
- package/dist/mem-ready-core.d.ts +56 -0
- package/dist/mem-ready-core.d.ts.map +1 -0
- package/dist/mem-ready-core.js +232 -0
- package/dist/mem-ready-core.js.map +1 -0
- package/dist/mem-signal-core.d.ts +132 -0
- package/dist/mem-signal-core.d.ts.map +1 -0
- package/dist/mem-signal-core.js +249 -0
- package/dist/mem-signal-core.js.map +1 -0
- package/dist/mem-start-core.d.ts +76 -0
- package/dist/mem-start-core.d.ts.map +1 -0
- package/dist/mem-start-core.js +133 -0
- package/dist/mem-start-core.js.map +1 -0
- package/dist/mem-summarize-core.d.ts +105 -0
- package/dist/mem-summarize-core.d.ts.map +1 -0
- package/dist/mem-summarize-core.js +263 -0
- package/dist/mem-summarize-core.js.map +1 -0
- package/dist/mem-triage-core.d.ts +127 -0
- package/dist/mem-triage-core.d.ts.map +1 -0
- package/dist/mem-triage-core.js +332 -0
- package/dist/mem-triage-core.js.map +1 -0
- package/dist/memory-schema.d.ts +150 -0
- package/dist/memory-schema.d.ts.map +1 -0
- package/dist/memory-schema.js +149 -0
- package/dist/memory-schema.js.map +1 -0
- package/dist/memory-store.d.ts +108 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/memory-store.js +234 -0
- package/dist/memory-store.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Triage Core (WU-1470)
|
|
3
|
+
*
|
|
4
|
+
* Review discovery nodes and promote to WUs or archive.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - List open discovery nodes with deterministic ordering
|
|
8
|
+
* - Promote discovery to WU (integrates with wu:create)
|
|
9
|
+
* - Archive discovery without promotion
|
|
10
|
+
*
|
|
11
|
+
* @see {@link tools/mem-triage.mjs} - CLI wrapper
|
|
12
|
+
* @see {@link tools/__tests__/mem-triage.test.mjs} - Tests
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs/promises';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { loadMemory, appendNode } from './memory-store.js';
|
|
17
|
+
import { validateLaneFormat } from '@lumenflow/core/dist/lane-checker.js';
|
|
18
|
+
/**
|
|
19
|
+
* Memory directory path relative to base
|
|
20
|
+
*/
|
|
21
|
+
const MEMORY_DIR = '.beacon/memory';
|
|
22
|
+
/**
|
|
23
|
+
* WU directory path relative to base
|
|
24
|
+
*/
|
|
25
|
+
const WU_DIR = 'docs/04-operations/tasks/wu';
|
|
26
|
+
/**
|
|
27
|
+
* Relationships file name
|
|
28
|
+
*/
|
|
29
|
+
const RELATIONSHIPS_FILE_NAME = 'relationships.jsonl';
|
|
30
|
+
/**
|
|
31
|
+
* Default priority for promoted WUs
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_PRIORITY = 'P2';
|
|
34
|
+
/**
|
|
35
|
+
* Maximum WU title length
|
|
36
|
+
*/
|
|
37
|
+
const MAX_TITLE_LENGTH = 80;
|
|
38
|
+
/**
|
|
39
|
+
* Priority ranking for deterministic ordering.
|
|
40
|
+
* Lower rank = higher priority.
|
|
41
|
+
*/
|
|
42
|
+
const PRIORITY_RANK = {
|
|
43
|
+
P0: 0,
|
|
44
|
+
P1: 1,
|
|
45
|
+
P2: 2,
|
|
46
|
+
P3: 3,
|
|
47
|
+
};
|
|
48
|
+
/** Default rank for nodes without priority (lowest priority) */
|
|
49
|
+
const DEFAULT_PRIORITY_RANK = 999;
|
|
50
|
+
/**
|
|
51
|
+
* Gets the priority rank for a node.
|
|
52
|
+
*
|
|
53
|
+
* @param node - Memory node
|
|
54
|
+
* @returns Priority rank
|
|
55
|
+
*/
|
|
56
|
+
function getPriorityRank(node) {
|
|
57
|
+
const priority = node.metadata?.priority;
|
|
58
|
+
if (!priority) {
|
|
59
|
+
return DEFAULT_PRIORITY_RANK;
|
|
60
|
+
}
|
|
61
|
+
return PRIORITY_RANK[priority] ?? DEFAULT_PRIORITY_RANK;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Comparator for deterministic ordering: priority first, then createdAt, then ID.
|
|
65
|
+
*
|
|
66
|
+
* @param a - First node
|
|
67
|
+
* @param b - Second node
|
|
68
|
+
* @returns Comparison result
|
|
69
|
+
*/
|
|
70
|
+
function compareNodes(a, b) {
|
|
71
|
+
const priorityDiff = getPriorityRank(a) - getPriorityRank(b);
|
|
72
|
+
if (priorityDiff !== 0) {
|
|
73
|
+
return priorityDiff;
|
|
74
|
+
}
|
|
75
|
+
const aTime = new Date(a.created_at).getTime();
|
|
76
|
+
const bTime = new Date(b.created_at).getTime();
|
|
77
|
+
if (aTime !== bTime) {
|
|
78
|
+
return aTime - bTime;
|
|
79
|
+
}
|
|
80
|
+
return a.id.localeCompare(b.id);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Load relationships from relationships.jsonl
|
|
84
|
+
*
|
|
85
|
+
* @param memoryDir - Memory directory path
|
|
86
|
+
* @returns Array of relationship objects
|
|
87
|
+
*/
|
|
88
|
+
async function loadRelationships(memoryDir) {
|
|
89
|
+
const filePath = path.join(memoryDir, RELATIONSHIPS_FILE_NAME);
|
|
90
|
+
try {
|
|
91
|
+
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
|
|
92
|
+
const lines = content.split('\n');
|
|
93
|
+
const relationships = [];
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
const trimmed = line.trim();
|
|
96
|
+
if (!trimmed)
|
|
97
|
+
continue;
|
|
98
|
+
try {
|
|
99
|
+
relationships.push(JSON.parse(trimmed));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return relationships;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
const error = err;
|
|
109
|
+
if (error.code === 'ENOENT') {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a set of node IDs that are blocked by relationships
|
|
117
|
+
*
|
|
118
|
+
* @param relationships - Relationship objects
|
|
119
|
+
* @returns Set of blocked node IDs
|
|
120
|
+
*/
|
|
121
|
+
function buildBlockedSet(relationships) {
|
|
122
|
+
const blocked = new Set();
|
|
123
|
+
for (const rel of relationships) {
|
|
124
|
+
if (rel.type === 'blocks') {
|
|
125
|
+
blocked.add(rel.to_id);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return blocked;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if a node is blocked
|
|
132
|
+
*
|
|
133
|
+
* @param node - Memory node
|
|
134
|
+
* @param blockedByRelationships - Set of IDs blocked by relationships
|
|
135
|
+
* @returns True if node is blocked
|
|
136
|
+
*/
|
|
137
|
+
function isBlocked(node, blockedByRelationships) {
|
|
138
|
+
if (blockedByRelationships.has(node.id)) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const blockedBy = node.metadata?.blocked_by;
|
|
142
|
+
if (Array.isArray(blockedBy) && blockedBy.length > 0) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if a node is closed/archived
|
|
149
|
+
*
|
|
150
|
+
* @param node - Memory node
|
|
151
|
+
* @returns True if node is closed
|
|
152
|
+
*/
|
|
153
|
+
function isClosed(node) {
|
|
154
|
+
const status = node.metadata?.status;
|
|
155
|
+
if (status === 'closed' || status === 'archived') {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
if (node.lifecycle === 'ephemeral') {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* List open discovery nodes.
|
|
165
|
+
*
|
|
166
|
+
* Returns unblocked, non-archived discovery nodes in deterministic order.
|
|
167
|
+
*
|
|
168
|
+
* @param baseDir - Base directory
|
|
169
|
+
* @param options - Filter options
|
|
170
|
+
* @returns Open discovery nodes
|
|
171
|
+
*/
|
|
172
|
+
export async function listOpenDiscoveries(baseDir, options = {}) {
|
|
173
|
+
const memoryDir = path.join(baseDir, MEMORY_DIR);
|
|
174
|
+
const memory = await loadMemory(memoryDir);
|
|
175
|
+
const relationships = await loadRelationships(memoryDir);
|
|
176
|
+
const blockedByRelationships = buildBlockedSet(relationships);
|
|
177
|
+
// Filter to discovery type only
|
|
178
|
+
let nodes = memory.nodes.filter((node) => node.type === 'discovery');
|
|
179
|
+
// Filter out blocked nodes
|
|
180
|
+
nodes = nodes.filter((node) => !isBlocked(node, blockedByRelationships));
|
|
181
|
+
// Filter out closed/archived nodes
|
|
182
|
+
nodes = nodes.filter((node) => !isClosed(node));
|
|
183
|
+
// Apply WU filter
|
|
184
|
+
if (options.wuId) {
|
|
185
|
+
if (options.wuId === 'unlinked') {
|
|
186
|
+
nodes = nodes.filter((node) => !node.wu_id);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
nodes = nodes.filter((node) => node.wu_id === options.wuId);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Apply tag filter
|
|
193
|
+
if (options.tag) {
|
|
194
|
+
const filterTag = options.tag;
|
|
195
|
+
nodes = nodes.filter((node) => node.tags?.includes(filterTag));
|
|
196
|
+
}
|
|
197
|
+
// Sort deterministically
|
|
198
|
+
return nodes.sort(compareNodes);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Archive a discovery node without promotion.
|
|
202
|
+
*
|
|
203
|
+
* Sets metadata.status to 'archived' and records the reason.
|
|
204
|
+
*
|
|
205
|
+
* @param baseDir - Base directory
|
|
206
|
+
* @param options - Archive options
|
|
207
|
+
* @returns Archive result
|
|
208
|
+
* @throws If node not found, not a discovery, or already archived
|
|
209
|
+
*/
|
|
210
|
+
export async function archiveDiscovery(baseDir, options) {
|
|
211
|
+
const { nodeId, reason } = options;
|
|
212
|
+
const memoryDir = path.join(baseDir, MEMORY_DIR);
|
|
213
|
+
const memory = await loadMemory(memoryDir);
|
|
214
|
+
const node = memory.byId.get(nodeId);
|
|
215
|
+
if (!node) {
|
|
216
|
+
throw new Error(`Node not found: ${nodeId}`);
|
|
217
|
+
}
|
|
218
|
+
if (node.type !== 'discovery') {
|
|
219
|
+
throw new Error(`Node ${nodeId} is not a discovery (type: ${node.type})`);
|
|
220
|
+
}
|
|
221
|
+
if (node.metadata?.status === 'archived' || node.metadata?.status === 'closed') {
|
|
222
|
+
throw new Error(`Node ${nodeId} is already archived/closed`);
|
|
223
|
+
}
|
|
224
|
+
// Create updated node with archive metadata
|
|
225
|
+
const archivedNode = {
|
|
226
|
+
...node,
|
|
227
|
+
metadata: {
|
|
228
|
+
...node.metadata,
|
|
229
|
+
status: 'archived',
|
|
230
|
+
archive_reason: reason,
|
|
231
|
+
archived_at: new Date().toISOString(),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
// Append updated node (JSONL append-only model)
|
|
235
|
+
// Note: This creates a new entry - in production, we'd need deduplication on load
|
|
236
|
+
// Cast is safe here because the node came from loadMemory which validates the schema
|
|
237
|
+
await appendNode(memoryDir, archivedNode);
|
|
238
|
+
return {
|
|
239
|
+
success: true,
|
|
240
|
+
nodeId,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get next available WU ID by scanning existing WUs.
|
|
245
|
+
*
|
|
246
|
+
* @param baseDir - Base directory
|
|
247
|
+
* @returns Next WU ID (e.g., 'WU-1502')
|
|
248
|
+
*/
|
|
249
|
+
async function getNextWuId(baseDir) {
|
|
250
|
+
const wuDir = path.join(baseDir, WU_DIR);
|
|
251
|
+
let maxId = 0;
|
|
252
|
+
try {
|
|
253
|
+
const files = await fs.readdir(wuDir);
|
|
254
|
+
for (const file of files) {
|
|
255
|
+
const match = file.match(/^WU-(\d+)\.yaml$/);
|
|
256
|
+
if (match && match[1]) {
|
|
257
|
+
const id = parseInt(match[1], 10);
|
|
258
|
+
if (id > maxId) {
|
|
259
|
+
maxId = id;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
const error = err;
|
|
266
|
+
if (error.code !== 'ENOENT') {
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return `WU-${maxId + 1}`;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Truncate content to max title length.
|
|
274
|
+
*
|
|
275
|
+
* @param content - Content to truncate
|
|
276
|
+
* @returns Truncated title
|
|
277
|
+
*/
|
|
278
|
+
function truncateToTitle(content) {
|
|
279
|
+
// Take first sentence or up to max length
|
|
280
|
+
const parts = content.split(/[.!?]/);
|
|
281
|
+
const firstSentence = (parts[0] ?? '').trim();
|
|
282
|
+
if (firstSentence.length <= MAX_TITLE_LENGTH) {
|
|
283
|
+
return firstSentence;
|
|
284
|
+
}
|
|
285
|
+
return firstSentence.substring(0, MAX_TITLE_LENGTH - 3) + '...';
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Promote a discovery node to a WU.
|
|
289
|
+
*
|
|
290
|
+
* @param baseDir - Base directory
|
|
291
|
+
* @param options - Promote options
|
|
292
|
+
* @returns Promotion result
|
|
293
|
+
* @throws If node not found, not a discovery, or already closed
|
|
294
|
+
*/
|
|
295
|
+
export async function promoteDiscovery(baseDir, options) {
|
|
296
|
+
const { nodeId, lane, title, wuId, priority, dryRun: _dryRun = false } = options;
|
|
297
|
+
const memoryDir = path.join(baseDir, MEMORY_DIR);
|
|
298
|
+
// Validate lane format
|
|
299
|
+
try {
|
|
300
|
+
validateLaneFormat(lane);
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
304
|
+
throw new Error(`Invalid lane format: ${errMsg}`);
|
|
305
|
+
}
|
|
306
|
+
const memory = await loadMemory(memoryDir);
|
|
307
|
+
const node = memory.byId.get(nodeId);
|
|
308
|
+
if (!node) {
|
|
309
|
+
throw new Error(`Node not found: ${nodeId}`);
|
|
310
|
+
}
|
|
311
|
+
if (node.type !== 'discovery') {
|
|
312
|
+
throw new Error(`Node ${nodeId} is not a discovery (type: ${node.type})`);
|
|
313
|
+
}
|
|
314
|
+
if (node.metadata?.status === 'archived' || node.metadata?.status === 'closed') {
|
|
315
|
+
throw new Error(`Node ${nodeId} is already archived/closed`);
|
|
316
|
+
}
|
|
317
|
+
// Generate WU spec
|
|
318
|
+
const resolvedWuId = wuId || (await getNextWuId(baseDir));
|
|
319
|
+
const resolvedTitle = title || truncateToTitle(node.content);
|
|
320
|
+
const resolvedPriority = priority || node.metadata?.priority || DEFAULT_PRIORITY;
|
|
321
|
+
const wuSpec = {
|
|
322
|
+
id: resolvedWuId,
|
|
323
|
+
title: resolvedTitle,
|
|
324
|
+
lane,
|
|
325
|
+
priority: resolvedPriority,
|
|
326
|
+
notes: `Promoted from discovery ${nodeId}`,
|
|
327
|
+
};
|
|
328
|
+
return {
|
|
329
|
+
success: true,
|
|
330
|
+
wuSpec,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-triage-core.js","sourceRoot":"","sources":["../src/mem-triage-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Schema (WU-1462)
|
|
3
|
+
*
|
|
4
|
+
* Zod schema for runtime validation of memory node structure.
|
|
5
|
+
* Foundation for the entire memory layer (INIT-007 Phase 1).
|
|
6
|
+
*
|
|
7
|
+
* Defines schemas for:
|
|
8
|
+
* - Memory nodes (5 types: session, discovery, checkpoint, note, summary)
|
|
9
|
+
* - Lifecycles (4 levels: ephemeral, session, wu, project)
|
|
10
|
+
* - Relationships (4 types: blocks, parent_child, related, discovered_from)
|
|
11
|
+
*
|
|
12
|
+
* @see {@link tools/lib/__tests__/memory-schema.test.mjs} - Tests
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
/**
|
|
16
|
+
* Memory node types
|
|
17
|
+
*
|
|
18
|
+
* - session: Session-level context (agent startup, context snapshot)
|
|
19
|
+
* - discovery: Found information (file locations, code patterns)
|
|
20
|
+
* - checkpoint: Progress marker (task milestone, state save)
|
|
21
|
+
* - note: Free-form annotation (observation, decision rationale)
|
|
22
|
+
* - summary: Condensed context (session summary, WU summary)
|
|
23
|
+
*/
|
|
24
|
+
export declare const MEMORY_NODE_TYPES: readonly ["session", "discovery", "checkpoint", "note", "summary"];
|
|
25
|
+
/**
|
|
26
|
+
* Memory lifecycle durations
|
|
27
|
+
*
|
|
28
|
+
* - ephemeral: Discarded immediately after use (scratch pad)
|
|
29
|
+
* - session: Lives for current agent session only
|
|
30
|
+
* - wu: Lives for WU duration (cleared on wu:done)
|
|
31
|
+
* - project: Persists across WUs (architectural knowledge)
|
|
32
|
+
*/
|
|
33
|
+
export declare const MEMORY_LIFECYCLES: readonly ["ephemeral", "session", "wu", "project"];
|
|
34
|
+
/**
|
|
35
|
+
* Relationship types between memory nodes
|
|
36
|
+
*
|
|
37
|
+
* - blocks: This node blocks another (dependency)
|
|
38
|
+
* - parent_child: Hierarchical relationship (session contains discoveries)
|
|
39
|
+
* - related: Semantic similarity or topical connection
|
|
40
|
+
* - discovered_from: Source attribution (discovered from another node)
|
|
41
|
+
*/
|
|
42
|
+
export declare const RELATIONSHIP_TYPES: readonly ["blocks", "parent_child", "related", "discovered_from"];
|
|
43
|
+
/**
|
|
44
|
+
* Regex patterns for memory validation
|
|
45
|
+
*/
|
|
46
|
+
export declare const MEMORY_PATTERNS: {
|
|
47
|
+
/** Memory ID format: mem-[a-z0-9]{4} */
|
|
48
|
+
MEMORY_ID: RegExp;
|
|
49
|
+
/** WU ID format (reused from wu-schema) */
|
|
50
|
+
WU_ID: RegExp;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Zod schema for Memory Node
|
|
54
|
+
*
|
|
55
|
+
* Validates memory nodes against the memory layer requirements.
|
|
56
|
+
* All memory operations should validate against this schema.
|
|
57
|
+
*/
|
|
58
|
+
export declare const MemoryNodeSchema: z.ZodObject<{
|
|
59
|
+
id: z.ZodString;
|
|
60
|
+
type: z.ZodEnum<{
|
|
61
|
+
session: "session";
|
|
62
|
+
discovery: "discovery";
|
|
63
|
+
checkpoint: "checkpoint";
|
|
64
|
+
note: "note";
|
|
65
|
+
summary: "summary";
|
|
66
|
+
}>;
|
|
67
|
+
lifecycle: z.ZodEnum<{
|
|
68
|
+
session: "session";
|
|
69
|
+
ephemeral: "ephemeral";
|
|
70
|
+
wu: "wu";
|
|
71
|
+
project: "project";
|
|
72
|
+
}>;
|
|
73
|
+
content: z.ZodString;
|
|
74
|
+
created_at: z.ZodString;
|
|
75
|
+
updated_at: z.ZodOptional<z.ZodString>;
|
|
76
|
+
wu_id: z.ZodOptional<z.ZodString>;
|
|
77
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
78
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
79
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
/**
|
|
82
|
+
* Zod schema for Relationship between memory nodes
|
|
83
|
+
*
|
|
84
|
+
* Validates relationships between memory nodes.
|
|
85
|
+
* Used for building the memory graph.
|
|
86
|
+
*/
|
|
87
|
+
export declare const RelationshipSchema: z.ZodObject<{
|
|
88
|
+
from_id: z.ZodString;
|
|
89
|
+
to_id: z.ZodString;
|
|
90
|
+
type: z.ZodEnum<{
|
|
91
|
+
blocks: "blocks";
|
|
92
|
+
parent_child: "parent_child";
|
|
93
|
+
related: "related";
|
|
94
|
+
discovered_from: "discovered_from";
|
|
95
|
+
}>;
|
|
96
|
+
created_at: z.ZodOptional<z.ZodString>;
|
|
97
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
/**
|
|
100
|
+
* TypeScript types inferred from schemas
|
|
101
|
+
*/
|
|
102
|
+
export type MemoryNode = z.infer<typeof MemoryNodeSchema>;
|
|
103
|
+
export type Relationship = z.infer<typeof RelationshipSchema>;
|
|
104
|
+
/**
|
|
105
|
+
* Validates memory node data against schema
|
|
106
|
+
*
|
|
107
|
+
* @param data - Data to validate
|
|
108
|
+
* @returns Validation result
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const result = validateMemoryNode(nodeData);
|
|
112
|
+
* if (!result.success) {
|
|
113
|
+
* result.error.issues.forEach(issue => {
|
|
114
|
+
* console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
115
|
+
* });
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
export declare function validateMemoryNode(data: unknown): z.ZodSafeParseResult<{
|
|
119
|
+
id: string;
|
|
120
|
+
type: "session" | "discovery" | "checkpoint" | "note" | "summary";
|
|
121
|
+
lifecycle: "session" | "ephemeral" | "wu" | "project";
|
|
122
|
+
content: string;
|
|
123
|
+
created_at: string;
|
|
124
|
+
updated_at?: string;
|
|
125
|
+
wu_id?: string;
|
|
126
|
+
session_id?: string;
|
|
127
|
+
metadata?: Record<string, unknown>;
|
|
128
|
+
tags?: string[];
|
|
129
|
+
}>;
|
|
130
|
+
/**
|
|
131
|
+
* Validates relationship data against schema
|
|
132
|
+
*
|
|
133
|
+
* @param data - Data to validate
|
|
134
|
+
* @returns Validation result
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const result = validateRelationship(relData);
|
|
138
|
+
* if (!result.success) {
|
|
139
|
+
* result.error.issues.forEach(issue => {
|
|
140
|
+
* console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
141
|
+
* });
|
|
142
|
+
* }
|
|
143
|
+
*/
|
|
144
|
+
export declare function validateRelationship(data: unknown): z.ZodSafeParseResult<{
|
|
145
|
+
from_id: string;
|
|
146
|
+
to_id: string;
|
|
147
|
+
type: "blocks" | "parent_child" | "related" | "discovered_from";
|
|
148
|
+
created_at?: string;
|
|
149
|
+
metadata?: Record<string, unknown>;
|
|
150
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-schema.d.ts","sourceRoot":"","sources":["../src/memory-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,UAA4D,CAAC;AAE3F;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,UAA4C,CAAC;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,UAA2D,CAAC;AAE3F;;GAEG;AACH,eAAO,MAAM,eAAe;IAC1B,wCAAwC;;IAGxC,2CAA2C;;CAE5C,CAAC;AAeF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;IAC3B,+CAA+C;;IAG/C,+BAA+B;;IAK/B,yBAAyB;;IAKzB,yCAAyC;;IAGzC,6CAA6C;;IAG7C,0DAA0D;;IAG1D,kCAAkC;;IAMlC,uDAAuD;;IAGvD,oCAAoC;;IAGpC,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;EAEzC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;IAC7B,uCAAuC;;IAGvC,uCAAuC;;IAGvC,wBAAwB;;IAKxB,uDAAuD;;IAGvD,oCAAoC;;;;;;;;;;;;;;EAEpC,CAAC;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,KAAA;;;;;;;;;;;;;;;;;;;;;;GAEtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,KAAA;;;;;;;;;;;;GAExC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Schema (WU-1462)
|
|
3
|
+
*
|
|
4
|
+
* Zod schema for runtime validation of memory node structure.
|
|
5
|
+
* Foundation for the entire memory layer (INIT-007 Phase 1).
|
|
6
|
+
*
|
|
7
|
+
* Defines schemas for:
|
|
8
|
+
* - Memory nodes (5 types: session, discovery, checkpoint, note, summary)
|
|
9
|
+
* - Lifecycles (4 levels: ephemeral, session, wu, project)
|
|
10
|
+
* - Relationships (4 types: blocks, parent_child, related, discovered_from)
|
|
11
|
+
*
|
|
12
|
+
* @see {@link tools/lib/__tests__/memory-schema.test.mjs} - Tests
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
/**
|
|
16
|
+
* Memory node types
|
|
17
|
+
*
|
|
18
|
+
* - session: Session-level context (agent startup, context snapshot)
|
|
19
|
+
* - discovery: Found information (file locations, code patterns)
|
|
20
|
+
* - checkpoint: Progress marker (task milestone, state save)
|
|
21
|
+
* - note: Free-form annotation (observation, decision rationale)
|
|
22
|
+
* - summary: Condensed context (session summary, WU summary)
|
|
23
|
+
*/
|
|
24
|
+
export const MEMORY_NODE_TYPES = ['session', 'discovery', 'checkpoint', 'note', 'summary'];
|
|
25
|
+
/**
|
|
26
|
+
* Memory lifecycle durations
|
|
27
|
+
*
|
|
28
|
+
* - ephemeral: Discarded immediately after use (scratch pad)
|
|
29
|
+
* - session: Lives for current agent session only
|
|
30
|
+
* - wu: Lives for WU duration (cleared on wu:done)
|
|
31
|
+
* - project: Persists across WUs (architectural knowledge)
|
|
32
|
+
*/
|
|
33
|
+
export const MEMORY_LIFECYCLES = ['ephemeral', 'session', 'wu', 'project'];
|
|
34
|
+
/**
|
|
35
|
+
* Relationship types between memory nodes
|
|
36
|
+
*
|
|
37
|
+
* - blocks: This node blocks another (dependency)
|
|
38
|
+
* - parent_child: Hierarchical relationship (session contains discoveries)
|
|
39
|
+
* - related: Semantic similarity or topical connection
|
|
40
|
+
* - discovered_from: Source attribution (discovered from another node)
|
|
41
|
+
*/
|
|
42
|
+
export const RELATIONSHIP_TYPES = ['blocks', 'parent_child', 'related', 'discovered_from'];
|
|
43
|
+
/**
|
|
44
|
+
* Regex patterns for memory validation
|
|
45
|
+
*/
|
|
46
|
+
export const MEMORY_PATTERNS = {
|
|
47
|
+
/** Memory ID format: mem-[a-z0-9]{4} */
|
|
48
|
+
MEMORY_ID: /^mem-[a-z0-9]{4}$/,
|
|
49
|
+
/** WU ID format (reused from wu-schema) */
|
|
50
|
+
WU_ID: /^WU-\d+$/,
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Error messages for schema validation
|
|
54
|
+
*/
|
|
55
|
+
const ERROR_MESSAGES = {
|
|
56
|
+
MEMORY_ID: 'ID must match pattern mem-[a-z0-9]{4} (e.g., mem-abc1)',
|
|
57
|
+
NODE_TYPE: `Type must be one of: ${MEMORY_NODE_TYPES.join(', ')}`,
|
|
58
|
+
LIFECYCLE: `Lifecycle must be one of: ${MEMORY_LIFECYCLES.join(', ')}`,
|
|
59
|
+
RELATIONSHIP_TYPE: `Type must be one of: ${RELATIONSHIP_TYPES.join(', ')}`,
|
|
60
|
+
WU_ID: 'WU ID must match pattern WU-XXX (e.g., WU-1462)',
|
|
61
|
+
CONTENT_REQUIRED: 'Content is required',
|
|
62
|
+
DATETIME_REQUIRED: 'Created timestamp is required',
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Zod schema for Memory Node
|
|
66
|
+
*
|
|
67
|
+
* Validates memory nodes against the memory layer requirements.
|
|
68
|
+
* All memory operations should validate against this schema.
|
|
69
|
+
*/
|
|
70
|
+
export const MemoryNodeSchema = z.object({
|
|
71
|
+
/** Memory node identifier (mem-[a-z0-9]{4}) */
|
|
72
|
+
id: z.string().regex(MEMORY_PATTERNS.MEMORY_ID, { message: ERROR_MESSAGES.MEMORY_ID }),
|
|
73
|
+
/** Node type classification */
|
|
74
|
+
type: z.enum(MEMORY_NODE_TYPES, {
|
|
75
|
+
error: ERROR_MESSAGES.NODE_TYPE,
|
|
76
|
+
}),
|
|
77
|
+
/** Lifecycle duration */
|
|
78
|
+
lifecycle: z.enum(MEMORY_LIFECYCLES, {
|
|
79
|
+
error: ERROR_MESSAGES.LIFECYCLE,
|
|
80
|
+
}),
|
|
81
|
+
/** Node content (required, non-empty) */
|
|
82
|
+
content: z.string().min(1, { message: ERROR_MESSAGES.CONTENT_REQUIRED }),
|
|
83
|
+
/** Creation timestamp (ISO 8601 datetime) */
|
|
84
|
+
created_at: z.string().datetime({ message: ERROR_MESSAGES.DATETIME_REQUIRED }),
|
|
85
|
+
/** Last update timestamp (optional, ISO 8601 datetime) */
|
|
86
|
+
updated_at: z.string().datetime().optional(),
|
|
87
|
+
/** Associated WU ID (optional) */
|
|
88
|
+
wu_id: z.string().regex(MEMORY_PATTERNS.WU_ID, { message: ERROR_MESSAGES.WU_ID }).optional(),
|
|
89
|
+
/** Session ID this node belongs to (optional, UUID) */
|
|
90
|
+
session_id: z.string().uuid().optional(),
|
|
91
|
+
/** Arbitrary metadata (optional) */
|
|
92
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
93
|
+
/** Tags for categorization (optional) */
|
|
94
|
+
tags: z.array(z.string()).optional(),
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* Zod schema for Relationship between memory nodes
|
|
98
|
+
*
|
|
99
|
+
* Validates relationships between memory nodes.
|
|
100
|
+
* Used for building the memory graph.
|
|
101
|
+
*/
|
|
102
|
+
export const RelationshipSchema = z.object({
|
|
103
|
+
/** Source node ID (mem-[a-z0-9]{4}) */
|
|
104
|
+
from_id: z.string().regex(MEMORY_PATTERNS.MEMORY_ID, { message: ERROR_MESSAGES.MEMORY_ID }),
|
|
105
|
+
/** Target node ID (mem-[a-z0-9]{4}) */
|
|
106
|
+
to_id: z.string().regex(MEMORY_PATTERNS.MEMORY_ID, { message: ERROR_MESSAGES.MEMORY_ID }),
|
|
107
|
+
/** Relationship type */
|
|
108
|
+
type: z.enum(RELATIONSHIP_TYPES, {
|
|
109
|
+
error: ERROR_MESSAGES.RELATIONSHIP_TYPE,
|
|
110
|
+
}),
|
|
111
|
+
/** Creation timestamp (optional, ISO 8601 datetime) */
|
|
112
|
+
created_at: z.string().datetime().optional(),
|
|
113
|
+
/** Arbitrary metadata (optional) */
|
|
114
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* Validates memory node data against schema
|
|
118
|
+
*
|
|
119
|
+
* @param data - Data to validate
|
|
120
|
+
* @returns Validation result
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* const result = validateMemoryNode(nodeData);
|
|
124
|
+
* if (!result.success) {
|
|
125
|
+
* result.error.issues.forEach(issue => {
|
|
126
|
+
* console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
127
|
+
* });
|
|
128
|
+
* }
|
|
129
|
+
*/
|
|
130
|
+
export function validateMemoryNode(data) {
|
|
131
|
+
return MemoryNodeSchema.safeParse(data);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Validates relationship data against schema
|
|
135
|
+
*
|
|
136
|
+
* @param data - Data to validate
|
|
137
|
+
* @returns Validation result
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* const result = validateRelationship(relData);
|
|
141
|
+
* if (!result.success) {
|
|
142
|
+
* result.error.issues.forEach(issue => {
|
|
143
|
+
* console.error(`${issue.path.join('.')}: ${issue.message}`);
|
|
144
|
+
* });
|
|
145
|
+
* }
|
|
146
|
+
*/
|
|
147
|
+
export function validateRelationship(data) {
|
|
148
|
+
return RelationshipSchema.safeParse(data);
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-schema.js","sourceRoot":"","sources":["../src/memory-schema.ts"],"names":[],"mappings":"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"}
|