@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,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Summarize Core (WU-1471)
|
|
3
|
+
*
|
|
4
|
+
* Rollup older memory nodes into summary nodes for compaction.
|
|
5
|
+
* Implements forgetting as first-class feature.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Aggregate checkpoint/note/discovery nodes into summaries
|
|
9
|
+
* - Mark originals for cleanup after summary creation
|
|
10
|
+
* - Respect lifecycle TTL (ephemeral, session, wu, project)
|
|
11
|
+
* - Support dry-run mode for preview
|
|
12
|
+
*
|
|
13
|
+
* @see {@link tools/mem-summarize.mjs} - CLI wrapper
|
|
14
|
+
* @see {@link tools/__tests__/mem-summarize.test.mjs} - Tests
|
|
15
|
+
*/
|
|
16
|
+
import { loadMemory, appendNode } from './memory-store.js';
|
|
17
|
+
import { generateMemId } from './mem-id.js';
|
|
18
|
+
import { validateMemoryNode } from './memory-schema.js';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
/**
|
|
21
|
+
* Memory directory path relative to base directory
|
|
22
|
+
*/
|
|
23
|
+
const MEMORY_DIR = '.beacon/memory';
|
|
24
|
+
/**
|
|
25
|
+
* Node types that can be summarized
|
|
26
|
+
*/
|
|
27
|
+
const SUMMARIZABLE_TYPES = ['discovery', 'checkpoint', 'note', 'session'];
|
|
28
|
+
/**
|
|
29
|
+
* Lifecycles that should NOT be marked for cleanup after summarization
|
|
30
|
+
* Project-level nodes persist across WUs (architectural knowledge)
|
|
31
|
+
*/
|
|
32
|
+
const PROTECTED_LIFECYCLES = ['project'];
|
|
33
|
+
/**
|
|
34
|
+
* Filter nodes that can be summarized for a given WU.
|
|
35
|
+
*
|
|
36
|
+
* Excludes:
|
|
37
|
+
* - Nodes from different WUs
|
|
38
|
+
* - Ephemeral lifecycle nodes (already transient)
|
|
39
|
+
* - Already-summarized nodes (have summarized_into metadata)
|
|
40
|
+
* - Summary nodes themselves
|
|
41
|
+
*
|
|
42
|
+
* @param nodes - All memory nodes
|
|
43
|
+
* @param wuId - WU ID to filter by
|
|
44
|
+
* @returns Summarizable nodes
|
|
45
|
+
*/
|
|
46
|
+
export function filterSummarizableNodes(nodes, wuId) {
|
|
47
|
+
return nodes.filter((node) => {
|
|
48
|
+
// Must belong to the specified WU
|
|
49
|
+
if (node.wu_id !== wuId) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Exclude ephemeral lifecycle (already transient)
|
|
53
|
+
if (node.lifecycle === 'ephemeral') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
// Exclude already-summarized nodes
|
|
57
|
+
if (node.metadata?.summarized_into) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
// Exclude summary nodes themselves
|
|
61
|
+
if (node.type === 'summary') {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// Include all summarizable types
|
|
65
|
+
return SUMMARIZABLE_TYPES.includes(node.type);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Calculate compaction ratio (source nodes / summary nodes).
|
|
70
|
+
*
|
|
71
|
+
* @param sourceCount - Number of source nodes
|
|
72
|
+
* @param summaryCount - Number of summary nodes created
|
|
73
|
+
* @returns Compaction ratio (0 if invalid input)
|
|
74
|
+
*/
|
|
75
|
+
export function getCompactionRatio(sourceCount, summaryCount) {
|
|
76
|
+
if (sourceCount === 0 || summaryCount === 0) {
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
return sourceCount / summaryCount;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Group nodes by type for organized summary content.
|
|
83
|
+
*
|
|
84
|
+
* @param nodes - Nodes to group
|
|
85
|
+
* @returns Nodes grouped by type
|
|
86
|
+
*/
|
|
87
|
+
function groupNodesByType(nodes) {
|
|
88
|
+
const groups = new Map();
|
|
89
|
+
for (const node of nodes) {
|
|
90
|
+
if (!groups.has(node.type)) {
|
|
91
|
+
groups.set(node.type, []);
|
|
92
|
+
}
|
|
93
|
+
const typeGroup = groups.get(node.type);
|
|
94
|
+
if (typeGroup) {
|
|
95
|
+
typeGroup.push(node);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return groups;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Generate aggregated summary content from source nodes.
|
|
102
|
+
*
|
|
103
|
+
* Organizes content by node type with clear sections.
|
|
104
|
+
*
|
|
105
|
+
* @param nodes - Source nodes to aggregate
|
|
106
|
+
* @param wuId - WU ID for the summary
|
|
107
|
+
* @returns Aggregated content
|
|
108
|
+
*/
|
|
109
|
+
function generateSummaryContent(nodes, wuId) {
|
|
110
|
+
const groups = groupNodesByType(nodes);
|
|
111
|
+
const sections = [];
|
|
112
|
+
sections.push(`# Summary for ${wuId}`);
|
|
113
|
+
sections.push(`Aggregated from ${nodes.length} node(s)`);
|
|
114
|
+
// Process each type in order
|
|
115
|
+
const typeOrder = ['discovery', 'checkpoint', 'note', 'session'];
|
|
116
|
+
for (const type of typeOrder) {
|
|
117
|
+
const typeNodes = groups.get(type);
|
|
118
|
+
if (!typeNodes || typeNodes.length === 0) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
sections.push(`## ${type.charAt(0).toUpperCase() + type.slice(1)}(s)`);
|
|
122
|
+
for (const node of typeNodes) {
|
|
123
|
+
// Bullet point with content, truncated if very long
|
|
124
|
+
const content = node.content.length > 200 ? `${node.content.slice(0, 197)}...` : node.content;
|
|
125
|
+
sections.push(`- ${content}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return sections.join('\n');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Filter nodes that should be marked for cleanup.
|
|
132
|
+
*
|
|
133
|
+
* Project-lifecycle nodes are protected from cleanup as they
|
|
134
|
+
* contain architectural knowledge that should persist.
|
|
135
|
+
*
|
|
136
|
+
* @param nodes - Source nodes
|
|
137
|
+
* @returns Nodes to mark for cleanup
|
|
138
|
+
*/
|
|
139
|
+
function filterNodesForCleanup(nodes) {
|
|
140
|
+
return nodes.filter((node) => !PROTECTED_LIFECYCLES.includes(node.lifecycle));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a summary node from source nodes.
|
|
144
|
+
*
|
|
145
|
+
* @param sourceNodes - Source nodes to summarize
|
|
146
|
+
* @param wuId - WU ID for the summary
|
|
147
|
+
* @returns Summary node (not yet persisted)
|
|
148
|
+
*/
|
|
149
|
+
function createSummaryNode(sourceNodes, wuId) {
|
|
150
|
+
const timestamp = new Date().toISOString();
|
|
151
|
+
const content = generateSummaryContent(sourceNodes, wuId);
|
|
152
|
+
const id = generateMemId(`summary-${wuId}-${timestamp}`);
|
|
153
|
+
const summary = {
|
|
154
|
+
id,
|
|
155
|
+
type: 'summary',
|
|
156
|
+
lifecycle: 'project', // Summaries persist across WUs
|
|
157
|
+
content,
|
|
158
|
+
created_at: timestamp,
|
|
159
|
+
wu_id: wuId,
|
|
160
|
+
metadata: {
|
|
161
|
+
source_nodes: sourceNodes.map((n) => n.id),
|
|
162
|
+
source_count: sourceNodes.length,
|
|
163
|
+
summarized_at: timestamp,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
// Validate the summary node
|
|
167
|
+
const validation = validateMemoryNode(summary);
|
|
168
|
+
if (!validation.success) {
|
|
169
|
+
const issues = validation.error.issues
|
|
170
|
+
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
171
|
+
.join(', ');
|
|
172
|
+
throw new Error(`Summary node validation failed: ${issues}`);
|
|
173
|
+
}
|
|
174
|
+
return summary;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Create cleanup marker nodes for original nodes.
|
|
178
|
+
*
|
|
179
|
+
* Adds summarized_into metadata to mark nodes as incorporated
|
|
180
|
+
* into a summary, making them eligible for cleanup.
|
|
181
|
+
*
|
|
182
|
+
* @param nodes - Nodes to mark
|
|
183
|
+
* @param summaryId - ID of the summary node
|
|
184
|
+
* @returns Updated nodes with cleanup markers
|
|
185
|
+
*/
|
|
186
|
+
function createCleanupMarkers(nodes, summaryId) {
|
|
187
|
+
const timestamp = new Date().toISOString();
|
|
188
|
+
return nodes.map((node) => ({
|
|
189
|
+
...node,
|
|
190
|
+
updated_at: timestamp,
|
|
191
|
+
metadata: {
|
|
192
|
+
...node.metadata,
|
|
193
|
+
summarized_into: summaryId,
|
|
194
|
+
summarized_at: timestamp,
|
|
195
|
+
},
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Summarize memory nodes for a closed WU.
|
|
200
|
+
*
|
|
201
|
+
* Aggregates checkpoint, note, and discovery nodes into a single
|
|
202
|
+
* summary node. Original nodes are marked for cleanup (unless
|
|
203
|
+
* they have project lifecycle).
|
|
204
|
+
*
|
|
205
|
+
* @param baseDir - Base directory containing .beacon/memory/
|
|
206
|
+
* @param options - Summarization options
|
|
207
|
+
* @returns Result with summary and cleanup info
|
|
208
|
+
* @throws If no summarizable nodes found for WU
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* // Summarize nodes for a completed WU
|
|
212
|
+
* const result = await summarizeWu(baseDir, { wuId: 'WU-1234' });
|
|
213
|
+
* console.log(`Created summary ${result.summary.id}`);
|
|
214
|
+
* console.log(`Compaction ratio: ${result.compactionRatio}:1`);
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* // Preview without modifications
|
|
218
|
+
* const preview = await summarizeWu(baseDir, {
|
|
219
|
+
* wuId: 'WU-1234',
|
|
220
|
+
* dryRun: true,
|
|
221
|
+
* });
|
|
222
|
+
*/
|
|
223
|
+
export async function summarizeWu(baseDir, options) {
|
|
224
|
+
const { wuId, dryRun = false } = options;
|
|
225
|
+
const memoryDir = path.join(baseDir, MEMORY_DIR);
|
|
226
|
+
// Load existing memory
|
|
227
|
+
const memory = await loadMemory(memoryDir);
|
|
228
|
+
// Filter summarizable nodes
|
|
229
|
+
const summarizable = filterSummarizableNodes(memory.nodes, wuId);
|
|
230
|
+
if (summarizable.length === 0) {
|
|
231
|
+
throw new Error(`No summarizable nodes found for ${wuId}`);
|
|
232
|
+
}
|
|
233
|
+
// Create summary node
|
|
234
|
+
const summary = createSummaryNode(summarizable, wuId);
|
|
235
|
+
// Determine which nodes to mark for cleanup
|
|
236
|
+
const cleanupNodes = filterNodesForCleanup(summarizable);
|
|
237
|
+
const markedForCleanup = cleanupNodes.map((n) => n.id);
|
|
238
|
+
// Calculate compaction ratio
|
|
239
|
+
const compactionRatio = getCompactionRatio(summarizable.length, 1);
|
|
240
|
+
// If dry-run, return preview without modifications
|
|
241
|
+
if (dryRun) {
|
|
242
|
+
return {
|
|
243
|
+
success: true,
|
|
244
|
+
summary,
|
|
245
|
+
markedForCleanup,
|
|
246
|
+
dryRun: true,
|
|
247
|
+
compactionRatio,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
// Persist summary node - cast is safe as summary conforms to MemoryNode schema
|
|
251
|
+
await appendNode(memoryDir, summary);
|
|
252
|
+
// Mark original nodes for cleanup
|
|
253
|
+
const cleanupMarkers = createCleanupMarkers(cleanupNodes, summary.id);
|
|
254
|
+
for (const marker of cleanupMarkers) {
|
|
255
|
+
await appendNode(memoryDir, marker);
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
summary,
|
|
260
|
+
markedForCleanup,
|
|
261
|
+
compactionRatio,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-summarize-core.js","sourceRoot":"","sources":["../src/mem-summarize-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
/**
|
|
15
|
+
* Memory node structure for triage operations
|
|
16
|
+
*/
|
|
17
|
+
interface TriageMemoryNode {
|
|
18
|
+
id: string;
|
|
19
|
+
type: string;
|
|
20
|
+
lifecycle: string;
|
|
21
|
+
content: string;
|
|
22
|
+
created_at: string;
|
|
23
|
+
updated_at?: string;
|
|
24
|
+
wu_id?: string;
|
|
25
|
+
session_id?: string;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
tags?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Options for listing discoveries
|
|
31
|
+
*/
|
|
32
|
+
export interface ListOptions {
|
|
33
|
+
/** Filter by WU ID (or 'unlinked' for nodes without wu_id) */
|
|
34
|
+
wuId?: string;
|
|
35
|
+
/** Filter by tag */
|
|
36
|
+
tag?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* List open discovery nodes.
|
|
40
|
+
*
|
|
41
|
+
* Returns unblocked, non-archived discovery nodes in deterministic order.
|
|
42
|
+
*
|
|
43
|
+
* @param baseDir - Base directory
|
|
44
|
+
* @param options - Filter options
|
|
45
|
+
* @returns Open discovery nodes
|
|
46
|
+
*/
|
|
47
|
+
export declare function listOpenDiscoveries(baseDir: string, options?: ListOptions): Promise<TriageMemoryNode[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Options for archiving a discovery
|
|
50
|
+
*/
|
|
51
|
+
export interface ArchiveOptions {
|
|
52
|
+
/** Node ID to archive */
|
|
53
|
+
nodeId: string;
|
|
54
|
+
/** Archive reason */
|
|
55
|
+
reason: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Result of archiving a discovery
|
|
59
|
+
*/
|
|
60
|
+
export interface ArchiveResult {
|
|
61
|
+
/** Whether archiving succeeded */
|
|
62
|
+
success: boolean;
|
|
63
|
+
/** Archived node ID */
|
|
64
|
+
nodeId: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Archive a discovery node without promotion.
|
|
68
|
+
*
|
|
69
|
+
* Sets metadata.status to 'archived' and records the reason.
|
|
70
|
+
*
|
|
71
|
+
* @param baseDir - Base directory
|
|
72
|
+
* @param options - Archive options
|
|
73
|
+
* @returns Archive result
|
|
74
|
+
* @throws If node not found, not a discovery, or already archived
|
|
75
|
+
*/
|
|
76
|
+
export declare function archiveDiscovery(baseDir: string, options: ArchiveOptions): Promise<ArchiveResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Options for promoting a discovery to a WU
|
|
79
|
+
*/
|
|
80
|
+
export interface PromoteOptions {
|
|
81
|
+
/** Node ID to promote */
|
|
82
|
+
nodeId: string;
|
|
83
|
+
/** WU lane */
|
|
84
|
+
lane: string;
|
|
85
|
+
/** Custom WU title (defaults to discovery content) */
|
|
86
|
+
title?: string;
|
|
87
|
+
/** Explicit WU ID (defaults to next available) */
|
|
88
|
+
wuId?: string;
|
|
89
|
+
/** Priority override */
|
|
90
|
+
priority?: string;
|
|
91
|
+
/** If true, return spec without creating WU */
|
|
92
|
+
dryRun?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* WU specification generated from promotion
|
|
96
|
+
*/
|
|
97
|
+
export interface WUSpec {
|
|
98
|
+
/** WU ID */
|
|
99
|
+
id: string;
|
|
100
|
+
/** WU title */
|
|
101
|
+
title: string;
|
|
102
|
+
/** WU lane */
|
|
103
|
+
lane: string;
|
|
104
|
+
/** WU priority */
|
|
105
|
+
priority: string;
|
|
106
|
+
/** WU notes with provenance */
|
|
107
|
+
notes: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Result of promoting a discovery
|
|
111
|
+
*/
|
|
112
|
+
export interface PromoteResult {
|
|
113
|
+
/** Whether promotion succeeded */
|
|
114
|
+
success: boolean;
|
|
115
|
+
/** Generated WU specification */
|
|
116
|
+
wuSpec: WUSpec;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Promote a discovery node to a WU.
|
|
120
|
+
*
|
|
121
|
+
* @param baseDir - Base directory
|
|
122
|
+
* @param options - Promote options
|
|
123
|
+
* @returns Promotion result
|
|
124
|
+
* @throws If node not found, not a discovery, or already closed
|
|
125
|
+
*/
|
|
126
|
+
export declare function promoteDiscovery(baseDir: string, options: PromoteOptions): Promise<PromoteResult>;
|
|
127
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-triage-core.d.ts","sourceRoot":"","sources":["../src/mem-triage-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA6KH;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,KAAA,EAAE,OAAO,KAAK,kBAgC9D;AAED;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,KAAA,EAAE,OAAO,KAAA;;;GAsCtD;AAwED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,KAAA,EAAE,OAAO,KAAA;;;;;;;;;GA2CtD"}
|