driftdetect 0.9.39 → 0.9.41
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/dist/bin/drift.js +31 -1
- package/dist/bin/drift.js.map +1 -1
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +377 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +21 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/memory.d.ts +25 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +1833 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/setup.d.ts +23 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +888 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/services/backup-service.d.ts +2 -0
- package/dist/services/backup-service.d.ts.map +1 -0
- package/dist/services/backup-service.js +2 -0
- package/dist/services/backup-service.js.map +1 -0
- package/dist/ui/project-indicator.d.ts +42 -0
- package/dist/ui/project-indicator.d.ts.map +1 -0
- package/dist/ui/project-indicator.js +114 -0
- package/dist/ui/project-indicator.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,1833 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Command - drift memory
|
|
3
|
+
*
|
|
4
|
+
* Enterprise-grade CLI for managing Cortex V2 memories.
|
|
5
|
+
* Provides full CRUD operations, search, learning, health monitoring,
|
|
6
|
+
* validation, consolidation, and integration with the drift ecosystem.
|
|
7
|
+
*
|
|
8
|
+
* Memory Types:
|
|
9
|
+
* - core: Project identity and preferences (never decays)
|
|
10
|
+
* - tribal: Institutional knowledge, gotchas, warnings (365 day half-life)
|
|
11
|
+
* - procedural: How-to knowledge, step-by-step procedures (180 day half-life)
|
|
12
|
+
* - semantic: Consolidated knowledge from episodic memories (90 day half-life)
|
|
13
|
+
* - episodic: Interaction records, raw material for consolidation (7 day half-life)
|
|
14
|
+
* - pattern_rationale: Why patterns exist in the codebase (180 day half-life)
|
|
15
|
+
* - constraint_override: Approved exceptions to constraints (90 day half-life)
|
|
16
|
+
* - decision_context: Human context for architectural decisions (180 day half-life)
|
|
17
|
+
* - code_smell: Patterns to avoid, anti-patterns (90 day half-life)
|
|
18
|
+
*/
|
|
19
|
+
import * as fs from 'node:fs/promises';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import chalk from 'chalk';
|
|
22
|
+
import { Command } from 'commander';
|
|
23
|
+
import { createSpinner } from '../ui/spinner.js';
|
|
24
|
+
const DRIFT_DIR = '.drift';
|
|
25
|
+
const MEMORY_DIR = 'memory';
|
|
26
|
+
const MEMORY_DB = 'cortex.db';
|
|
27
|
+
const MEMORY_TYPES = {
|
|
28
|
+
core: { name: 'core', icon: '🏠', description: 'Project identity and preferences', halfLife: '∞' },
|
|
29
|
+
tribal: { name: 'tribal', icon: '⚠️', description: 'Institutional knowledge, gotchas', halfLife: '365d' },
|
|
30
|
+
procedural: { name: 'procedural', icon: '📋', description: 'How-to knowledge, procedures', halfLife: '180d' },
|
|
31
|
+
semantic: { name: 'semantic', icon: '💡', description: 'Consolidated knowledge', halfLife: '90d' },
|
|
32
|
+
episodic: { name: 'episodic', icon: '💭', description: 'Interaction records', halfLife: '7d' },
|
|
33
|
+
pattern_rationale: { name: 'pattern_rationale', icon: '🎯', description: 'Why patterns exist', halfLife: '180d' },
|
|
34
|
+
constraint_override: { name: 'constraint_override', icon: '✅', description: 'Approved exceptions', halfLife: '90d' },
|
|
35
|
+
decision_context: { name: 'decision_context', icon: '📝', description: 'Decision context', halfLife: '180d' },
|
|
36
|
+
code_smell: { name: 'code_smell', icon: '🚫', description: 'Patterns to avoid', halfLife: '90d' },
|
|
37
|
+
};
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Cortex Integration
|
|
40
|
+
// ============================================================================
|
|
41
|
+
/**
|
|
42
|
+
* Get Cortex instance (lazy loaded)
|
|
43
|
+
*/
|
|
44
|
+
async function getCortex(rootDir) {
|
|
45
|
+
try {
|
|
46
|
+
const { getCortex: getGlobalCortex } = await import('driftdetect-cortex');
|
|
47
|
+
// Ensure memory directory exists
|
|
48
|
+
const memoryDir = path.join(rootDir, DRIFT_DIR, MEMORY_DIR);
|
|
49
|
+
await fs.mkdir(memoryDir, { recursive: true });
|
|
50
|
+
// Configure cortex with the project's database
|
|
51
|
+
const dbPath = path.join(memoryDir, MEMORY_DB);
|
|
52
|
+
return await getGlobalCortex({
|
|
53
|
+
storage: { type: 'sqlite', sqlitePath: dbPath },
|
|
54
|
+
autoInitialize: true,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new Error(`Failed to initialize Cortex: ${error}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if memory system is initialized
|
|
63
|
+
*/
|
|
64
|
+
async function memoryExists(rootDir) {
|
|
65
|
+
try {
|
|
66
|
+
await fs.access(path.join(rootDir, DRIFT_DIR, MEMORY_DIR, MEMORY_DB));
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Show helpful message when no memories exist
|
|
75
|
+
*/
|
|
76
|
+
function showNoMemoriesMessage() {
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.yellow('⚠️ Memory system not initialized.'));
|
|
79
|
+
console.log();
|
|
80
|
+
console.log(chalk.gray('Initialize the memory system:'));
|
|
81
|
+
console.log();
|
|
82
|
+
console.log(chalk.cyan(' drift memory init'));
|
|
83
|
+
console.log();
|
|
84
|
+
console.log(chalk.gray('Or add your first memory:'));
|
|
85
|
+
console.log();
|
|
86
|
+
console.log(chalk.cyan(' drift memory add tribal "Always use bcrypt for password hashing"'));
|
|
87
|
+
console.log();
|
|
88
|
+
}
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Formatters
|
|
91
|
+
// ============================================================================
|
|
92
|
+
function getTypeIcon(type) {
|
|
93
|
+
return MEMORY_TYPES[type]?.icon ?? '📦';
|
|
94
|
+
}
|
|
95
|
+
function getConfidenceColor(confidence) {
|
|
96
|
+
const percent = Math.round(confidence * 100);
|
|
97
|
+
if (confidence >= 0.8)
|
|
98
|
+
return chalk.green(`${percent}%`);
|
|
99
|
+
if (confidence >= 0.5)
|
|
100
|
+
return chalk.yellow(`${percent}%`);
|
|
101
|
+
return chalk.red(`${percent}%`);
|
|
102
|
+
}
|
|
103
|
+
function getHealthColor(score) {
|
|
104
|
+
if (score >= 80)
|
|
105
|
+
return chalk.green(`${score}/100 (healthy)`);
|
|
106
|
+
if (score >= 50)
|
|
107
|
+
return chalk.yellow(`${score}/100 (warning)`);
|
|
108
|
+
return chalk.red(`${score}/100 (critical)`);
|
|
109
|
+
}
|
|
110
|
+
function getImportanceColor(importance) {
|
|
111
|
+
switch (importance) {
|
|
112
|
+
case 'critical': return chalk.red(importance);
|
|
113
|
+
case 'high': return chalk.yellow(importance);
|
|
114
|
+
case 'normal': return chalk.white(importance);
|
|
115
|
+
case 'low': return chalk.gray(importance);
|
|
116
|
+
default: return importance;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function formatMemoryBrief(memory) {
|
|
120
|
+
const icon = getTypeIcon(memory.type);
|
|
121
|
+
const confidence = getConfidenceColor(memory.confidence ?? 1);
|
|
122
|
+
const id = memory.id ?? 'unknown';
|
|
123
|
+
console.log(` ${icon} ${chalk.cyan(id.slice(0, 8))}... ${confidence}`);
|
|
124
|
+
console.log(` ${chalk.white(memory.summary ?? 'No summary')}`);
|
|
125
|
+
if (memory.tags?.length > 0) {
|
|
126
|
+
console.log(chalk.gray(` Tags: ${memory.tags.join(', ')}`));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function formatMemoryDetailed(memory, related = []) {
|
|
130
|
+
const icon = getTypeIcon(memory.type);
|
|
131
|
+
console.log();
|
|
132
|
+
console.log(chalk.bold(`${icon} ${memory.type.toUpperCase()}`));
|
|
133
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
134
|
+
console.log();
|
|
135
|
+
// Basic info
|
|
136
|
+
console.log(chalk.bold('Details'));
|
|
137
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
138
|
+
console.log(` ID: ${chalk.cyan(memory.id)}`);
|
|
139
|
+
console.log(` Type: ${memory.type}`);
|
|
140
|
+
console.log(` Confidence: ${getConfidenceColor(memory.confidence)}`);
|
|
141
|
+
console.log(` Importance: ${getImportanceColor(memory.importance)}`);
|
|
142
|
+
console.log(` Created: ${new Date(memory.createdAt).toLocaleString()}`);
|
|
143
|
+
console.log(` Updated: ${new Date(memory.updatedAt).toLocaleString()}`);
|
|
144
|
+
console.log(` Accessed: ${memory.accessCount} times`);
|
|
145
|
+
console.log();
|
|
146
|
+
// Summary
|
|
147
|
+
console.log(chalk.bold('Summary'));
|
|
148
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
149
|
+
console.log(` ${memory.summary}`);
|
|
150
|
+
console.log();
|
|
151
|
+
// Type-specific content
|
|
152
|
+
switch (memory.type) {
|
|
153
|
+
case 'tribal':
|
|
154
|
+
console.log(chalk.bold('Knowledge'));
|
|
155
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
156
|
+
console.log(` Topic: ${memory.topic}`);
|
|
157
|
+
console.log(` Severity: ${memory.severity}`);
|
|
158
|
+
console.log(` ${memory.knowledge}`);
|
|
159
|
+
if (memory.warnings?.length > 0) {
|
|
160
|
+
console.log();
|
|
161
|
+
console.log(chalk.bold('Warnings'));
|
|
162
|
+
for (const w of memory.warnings) {
|
|
163
|
+
console.log(` ⚠️ ${w}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
case 'procedural':
|
|
168
|
+
console.log(chalk.bold('Procedure'));
|
|
169
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
170
|
+
console.log(` Name: ${memory.name}`);
|
|
171
|
+
if (memory.steps?.length > 0) {
|
|
172
|
+
console.log();
|
|
173
|
+
console.log(chalk.bold('Steps'));
|
|
174
|
+
for (const step of memory.steps) {
|
|
175
|
+
console.log(` ${step.order}. ${step.action}`);
|
|
176
|
+
if (step.details)
|
|
177
|
+
console.log(chalk.gray(` ${step.details}`));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case 'pattern_rationale':
|
|
182
|
+
console.log(chalk.bold('Pattern'));
|
|
183
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
184
|
+
console.log(` Pattern: ${memory.patternName}`);
|
|
185
|
+
console.log(` Category: ${memory.patternCategory}`);
|
|
186
|
+
console.log();
|
|
187
|
+
console.log(chalk.bold('Rationale'));
|
|
188
|
+
console.log(` ${memory.rationale}`);
|
|
189
|
+
if (memory.businessContext) {
|
|
190
|
+
console.log();
|
|
191
|
+
console.log(chalk.bold('Business Context'));
|
|
192
|
+
console.log(` ${memory.businessContext}`);
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
case 'code_smell':
|
|
196
|
+
console.log(chalk.bold('Code Smell'));
|
|
197
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
198
|
+
console.log(` Name: ${memory.name}`);
|
|
199
|
+
console.log(` Severity: ${memory.severity}`);
|
|
200
|
+
console.log(` Reason: ${memory.reason}`);
|
|
201
|
+
if (memory.suggestion) {
|
|
202
|
+
console.log();
|
|
203
|
+
console.log(chalk.bold('Suggestion'));
|
|
204
|
+
console.log(` ${memory.suggestion}`);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case 'decision_context':
|
|
208
|
+
console.log(chalk.bold('Decision'));
|
|
209
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
210
|
+
console.log(` Summary: ${memory.decisionSummary}`);
|
|
211
|
+
console.log(` Still Valid: ${memory.stillValid ? chalk.green('Yes') : chalk.red('No')}`);
|
|
212
|
+
if (memory.businessContext) {
|
|
213
|
+
console.log();
|
|
214
|
+
console.log(chalk.bold('Business Context'));
|
|
215
|
+
console.log(` ${memory.businessContext}`);
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
// Links
|
|
220
|
+
if (memory.linkedFiles?.length > 0 || memory.linkedPatterns?.length > 0) {
|
|
221
|
+
console.log();
|
|
222
|
+
console.log(chalk.bold('Links'));
|
|
223
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
224
|
+
if (memory.linkedFiles?.length > 0) {
|
|
225
|
+
console.log(` Files: ${memory.linkedFiles.join(', ')}`);
|
|
226
|
+
}
|
|
227
|
+
if (memory.linkedPatterns?.length > 0) {
|
|
228
|
+
console.log(` Patterns: ${memory.linkedPatterns.join(', ')}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Tags
|
|
232
|
+
if (memory.tags?.length > 0) {
|
|
233
|
+
console.log();
|
|
234
|
+
console.log(chalk.bold('Tags'));
|
|
235
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
236
|
+
console.log(` ${memory.tags.join(', ')}`);
|
|
237
|
+
}
|
|
238
|
+
// Related memories
|
|
239
|
+
if (related.length > 0) {
|
|
240
|
+
console.log();
|
|
241
|
+
console.log(chalk.bold('Related Memories'));
|
|
242
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
243
|
+
for (const r of related.slice(0, 5)) {
|
|
244
|
+
console.log(` ${getTypeIcon(r.type)} ${chalk.cyan(r.id.slice(0, 8))}... ${r.summary}`);
|
|
245
|
+
}
|
|
246
|
+
if (related.length > 5) {
|
|
247
|
+
console.log(chalk.gray(` ... and ${related.length - 5} more`));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
console.log();
|
|
251
|
+
}
|
|
252
|
+
// ============================================================================
|
|
253
|
+
// Subcommand Actions
|
|
254
|
+
// ============================================================================
|
|
255
|
+
/**
|
|
256
|
+
* Init subcommand - initialize memory system
|
|
257
|
+
*/
|
|
258
|
+
async function initAction(options) {
|
|
259
|
+
const rootDir = process.cwd();
|
|
260
|
+
const format = options.format ?? 'text';
|
|
261
|
+
const isTextFormat = format === 'text';
|
|
262
|
+
if (isTextFormat) {
|
|
263
|
+
console.log();
|
|
264
|
+
console.log(chalk.bold('🧠 Initializing Memory System'));
|
|
265
|
+
console.log(chalk.gray('═'.repeat(50)));
|
|
266
|
+
}
|
|
267
|
+
const spinner = isTextFormat ? createSpinner('Creating memory database...') : null;
|
|
268
|
+
spinner?.start();
|
|
269
|
+
try {
|
|
270
|
+
const cortex = await getCortex(rootDir);
|
|
271
|
+
await cortex.storage.close();
|
|
272
|
+
spinner?.stop();
|
|
273
|
+
if (format === 'json') {
|
|
274
|
+
console.log(JSON.stringify({
|
|
275
|
+
success: true,
|
|
276
|
+
path: path.join(DRIFT_DIR, MEMORY_DIR, MEMORY_DB)
|
|
277
|
+
}));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(chalk.green.bold('✓ Memory system initialized'));
|
|
282
|
+
console.log();
|
|
283
|
+
console.log(chalk.gray(`Database: ${path.join(DRIFT_DIR, MEMORY_DIR, MEMORY_DB)}`));
|
|
284
|
+
console.log();
|
|
285
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
286
|
+
console.log(chalk.bold('📌 Next Steps:'));
|
|
287
|
+
console.log(chalk.gray(` • drift memory add tribal "..." ${chalk.white('Add tribal knowledge')}`));
|
|
288
|
+
console.log(chalk.gray(` • drift memory status ${chalk.white('View memory statistics')}`));
|
|
289
|
+
console.log(chalk.gray(` • drift memory import <file> ${chalk.white('Import memories from file')}`));
|
|
290
|
+
console.log();
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
spinner?.stop();
|
|
294
|
+
if (format === 'json') {
|
|
295
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
console.log(chalk.red(`\n❌ Error: ${error}`));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Status subcommand - show memory system status
|
|
304
|
+
*/
|
|
305
|
+
async function statusAction(options) {
|
|
306
|
+
const rootDir = process.cwd();
|
|
307
|
+
const format = options.format ?? 'text';
|
|
308
|
+
if (!(await memoryExists(rootDir))) {
|
|
309
|
+
if (format === 'json') {
|
|
310
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
showNoMemoriesMessage();
|
|
314
|
+
}
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const spinner = format === 'text' ? createSpinner('Loading memory statistics...') : null;
|
|
318
|
+
spinner?.start();
|
|
319
|
+
try {
|
|
320
|
+
const cortex = await getCortex(rootDir);
|
|
321
|
+
// Get statistics
|
|
322
|
+
const countByType = await cortex.storage.countByType();
|
|
323
|
+
const total = Object.values(countByType).reduce((sum, count) => sum + count, 0);
|
|
324
|
+
// Get sample of memories for analysis
|
|
325
|
+
const memories = await cortex.storage.search({ limit: 500 });
|
|
326
|
+
let confidenceSum = 0;
|
|
327
|
+
let lowConfidenceCount = 0;
|
|
328
|
+
let recentlyAccessed = 0;
|
|
329
|
+
const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
330
|
+
for (const memory of memories) {
|
|
331
|
+
confidenceSum += memory.confidence ?? 1;
|
|
332
|
+
if ((memory.confidence ?? 1) < 0.5)
|
|
333
|
+
lowConfidenceCount++;
|
|
334
|
+
if (memory.lastAccessed && new Date(memory.lastAccessed) > oneWeekAgo) {
|
|
335
|
+
recentlyAccessed++;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const avgConfidence = memories.length > 0 ? confidenceSum / memories.length : 0;
|
|
339
|
+
// Get pending consolidation count
|
|
340
|
+
const pendingConsolidation = await cortex.storage.count({
|
|
341
|
+
types: ['episodic'],
|
|
342
|
+
consolidationStatus: 'pending',
|
|
343
|
+
});
|
|
344
|
+
// Calculate health score
|
|
345
|
+
let healthScore = 100;
|
|
346
|
+
if (avgConfidence < 0.5)
|
|
347
|
+
healthScore -= 20;
|
|
348
|
+
if (lowConfidenceCount > total * 0.3)
|
|
349
|
+
healthScore -= 15;
|
|
350
|
+
if (pendingConsolidation > 50)
|
|
351
|
+
healthScore -= 10;
|
|
352
|
+
if (total > 1000)
|
|
353
|
+
healthScore -= 5;
|
|
354
|
+
healthScore = Math.max(0, healthScore);
|
|
355
|
+
await cortex.storage.close();
|
|
356
|
+
spinner?.stop();
|
|
357
|
+
if (format === 'json') {
|
|
358
|
+
console.log(JSON.stringify({
|
|
359
|
+
total,
|
|
360
|
+
byType: countByType,
|
|
361
|
+
avgConfidence,
|
|
362
|
+
lowConfidenceCount,
|
|
363
|
+
recentlyAccessed,
|
|
364
|
+
pendingConsolidation,
|
|
365
|
+
healthScore,
|
|
366
|
+
}, null, 2));
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
console.log();
|
|
370
|
+
console.log(chalk.bold('🧠 Memory System Status'));
|
|
371
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
372
|
+
console.log();
|
|
373
|
+
// Overview
|
|
374
|
+
console.log(chalk.bold('📊 Overview'));
|
|
375
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
376
|
+
console.log(` Total Memories: ${chalk.cyan.bold(total)}`);
|
|
377
|
+
console.log(` Avg Confidence: ${getConfidenceColor(avgConfidence)}`);
|
|
378
|
+
console.log(` Low Confidence: ${lowConfidenceCount > 0 ? chalk.yellow(lowConfidenceCount) : chalk.green('0')}`);
|
|
379
|
+
console.log(` Recently Accessed: ${chalk.cyan(recentlyAccessed)} (last 7 days)`);
|
|
380
|
+
console.log(` Pending Consolidation: ${pendingConsolidation > 0 ? chalk.yellow(pendingConsolidation) : chalk.green('0')}`);
|
|
381
|
+
console.log();
|
|
382
|
+
// By Type
|
|
383
|
+
console.log(chalk.bold('📋 By Type'));
|
|
384
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
385
|
+
for (const [type, count] of Object.entries(countByType)) {
|
|
386
|
+
if (count > 0) {
|
|
387
|
+
const typeInfo = MEMORY_TYPES[type];
|
|
388
|
+
console.log(` ${typeInfo?.icon ?? '📦'} ${type.padEnd(20)} ${chalk.cyan(count)} ${chalk.gray(`(${typeInfo?.halfLife ?? '?'} half-life)`)}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
console.log();
|
|
392
|
+
// Health
|
|
393
|
+
console.log(chalk.bold('💚 Health'));
|
|
394
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
395
|
+
console.log(` Score: ${getHealthColor(healthScore)}`);
|
|
396
|
+
if (lowConfidenceCount > total * 0.3) {
|
|
397
|
+
console.log(chalk.yellow(` ⚠️ ${lowConfidenceCount} memories have low confidence`));
|
|
398
|
+
}
|
|
399
|
+
if (pendingConsolidation > 50) {
|
|
400
|
+
console.log(chalk.yellow(` ⚠️ ${pendingConsolidation} episodic memories pending consolidation`));
|
|
401
|
+
}
|
|
402
|
+
if (total > 1000) {
|
|
403
|
+
console.log(chalk.yellow(` ⚠️ Large memory count - consider running consolidation`));
|
|
404
|
+
}
|
|
405
|
+
console.log();
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
spinner?.stop();
|
|
409
|
+
if (format === 'json') {
|
|
410
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Add subcommand - add a new memory
|
|
419
|
+
*/
|
|
420
|
+
async function addAction(type, content, options) {
|
|
421
|
+
const rootDir = process.cwd();
|
|
422
|
+
const format = options.format ?? 'text';
|
|
423
|
+
// Validate type
|
|
424
|
+
if (!MEMORY_TYPES[type]) {
|
|
425
|
+
const validTypes = Object.keys(MEMORY_TYPES).join(', ');
|
|
426
|
+
if (format === 'json') {
|
|
427
|
+
console.log(JSON.stringify({ error: `Invalid type. Valid types: ${validTypes}` }));
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
console.log(chalk.red(`Invalid memory type: ${type}`));
|
|
431
|
+
console.log(chalk.gray(`Valid types: ${validTypes}`));
|
|
432
|
+
}
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
// Some types shouldn't be manually added
|
|
436
|
+
const manuallyAddableTypes = ['tribal', 'procedural', 'pattern_rationale', 'code_smell', 'decision_context', 'constraint_override'];
|
|
437
|
+
if (!manuallyAddableTypes.includes(type)) {
|
|
438
|
+
if (format === 'json') {
|
|
439
|
+
console.log(JSON.stringify({ error: `Type '${type}' cannot be manually added. Use: ${manuallyAddableTypes.join(', ')}` }));
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
console.log(chalk.red(`Type '${type}' cannot be manually added.`));
|
|
443
|
+
console.log(chalk.gray(`Manually addable types: ${manuallyAddableTypes.join(', ')}`));
|
|
444
|
+
if (type === 'episodic') {
|
|
445
|
+
console.log(chalk.gray('Episodic memories are created automatically from interactions.'));
|
|
446
|
+
}
|
|
447
|
+
else if (type === 'semantic') {
|
|
448
|
+
console.log(chalk.gray('Semantic memories are created through consolidation.'));
|
|
449
|
+
}
|
|
450
|
+
else if (type === 'core') {
|
|
451
|
+
console.log(chalk.gray('Core memory is created during initialization.'));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
// Validate content
|
|
457
|
+
if (!content || content.trim().length === 0) {
|
|
458
|
+
if (format === 'json') {
|
|
459
|
+
console.log(JSON.stringify({ error: 'Content cannot be empty' }));
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
console.log(chalk.red('Content cannot be empty'));
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
const cortex = await getCortex(rootDir);
|
|
468
|
+
// Parse tags
|
|
469
|
+
const tags = options.tags ? options.tags.split(',').map(t => t.trim()) : undefined;
|
|
470
|
+
const importance = (options.importance ?? 'normal');
|
|
471
|
+
// Build memory object based on type
|
|
472
|
+
const memory = {
|
|
473
|
+
type,
|
|
474
|
+
confidence: 1.0,
|
|
475
|
+
importance,
|
|
476
|
+
tags,
|
|
477
|
+
summary: content.length > 100 ? content.slice(0, 97) + '...' : content,
|
|
478
|
+
};
|
|
479
|
+
// Type-specific fields
|
|
480
|
+
switch (type) {
|
|
481
|
+
case 'tribal':
|
|
482
|
+
memory.topic = options.topic ?? extractTopic(content);
|
|
483
|
+
memory.knowledge = content;
|
|
484
|
+
memory.severity = options.severity ?? 'warning';
|
|
485
|
+
memory.source = { type: 'manual' };
|
|
486
|
+
break;
|
|
487
|
+
case 'procedural':
|
|
488
|
+
memory.name = options.topic ?? extractTopic(content);
|
|
489
|
+
memory.description = content;
|
|
490
|
+
memory.triggers = [options.topic ?? extractTopic(content)];
|
|
491
|
+
memory.steps = [{ order: 1, action: content }];
|
|
492
|
+
memory.usageCount = 0;
|
|
493
|
+
break;
|
|
494
|
+
case 'semantic':
|
|
495
|
+
memory.topic = options.topic ?? extractTopic(content);
|
|
496
|
+
memory.knowledge = content;
|
|
497
|
+
memory.supportingEvidence = 1;
|
|
498
|
+
memory.contradictingEvidence = 0;
|
|
499
|
+
break;
|
|
500
|
+
case 'pattern_rationale':
|
|
501
|
+
memory.patternId = options.pattern ?? 'manual';
|
|
502
|
+
memory.patternName = options.topic ?? extractTopic(content);
|
|
503
|
+
memory.patternCategory = 'manual';
|
|
504
|
+
memory.rationale = content;
|
|
505
|
+
break;
|
|
506
|
+
case 'code_smell':
|
|
507
|
+
memory.name = options.topic ?? extractTopic(content);
|
|
508
|
+
memory.description = content;
|
|
509
|
+
memory.reason = content;
|
|
510
|
+
memory.suggestion = 'Review and fix';
|
|
511
|
+
memory.severity = options.severity ?? 'warning';
|
|
512
|
+
memory.autoDetect = false;
|
|
513
|
+
break;
|
|
514
|
+
case 'decision_context':
|
|
515
|
+
memory.decisionId = 'manual';
|
|
516
|
+
memory.decisionSummary = options.topic ?? extractTopic(content);
|
|
517
|
+
memory.businessContext = content;
|
|
518
|
+
memory.stillValid = true;
|
|
519
|
+
break;
|
|
520
|
+
case 'constraint_override':
|
|
521
|
+
memory.constraintId = options.pattern ?? 'manual';
|
|
522
|
+
memory.constraintName = options.topic ?? extractTopic(content);
|
|
523
|
+
memory.scope = { type: 'global', target: '*' };
|
|
524
|
+
memory.reason = content;
|
|
525
|
+
memory.permanent = false;
|
|
526
|
+
memory.usageCount = 0;
|
|
527
|
+
break;
|
|
528
|
+
default:
|
|
529
|
+
memory.content = content;
|
|
530
|
+
}
|
|
531
|
+
const id = await cortex.add(memory);
|
|
532
|
+
// Link to file if specified
|
|
533
|
+
if (options.file) {
|
|
534
|
+
await cortex.storage.linkToFile(id, options.file);
|
|
535
|
+
}
|
|
536
|
+
// Link to pattern if specified
|
|
537
|
+
if (options.pattern) {
|
|
538
|
+
await cortex.storage.linkToPattern(id, options.pattern);
|
|
539
|
+
}
|
|
540
|
+
await cortex.storage.close();
|
|
541
|
+
if (format === 'json') {
|
|
542
|
+
console.log(JSON.stringify({ success: true, id, type }));
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
console.log();
|
|
546
|
+
console.log(chalk.green.bold('✓ Memory added'));
|
|
547
|
+
console.log();
|
|
548
|
+
console.log(` ${getTypeIcon(type)} ${chalk.bold('ID:')} ${chalk.cyan(id)}`);
|
|
549
|
+
console.log(` ${chalk.bold('Type:')} ${type}`);
|
|
550
|
+
console.log(` ${chalk.bold('Importance:')} ${importance}`);
|
|
551
|
+
if (tags) {
|
|
552
|
+
console.log(` ${chalk.bold('Tags:')} ${tags.join(', ')}`);
|
|
553
|
+
}
|
|
554
|
+
if (options.file) {
|
|
555
|
+
console.log(` ${chalk.bold('Linked to:')} ${options.file}`);
|
|
556
|
+
}
|
|
557
|
+
console.log();
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
if (format === 'json') {
|
|
561
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* List subcommand - list memories
|
|
570
|
+
*/
|
|
571
|
+
async function listAction(options) {
|
|
572
|
+
const rootDir = process.cwd();
|
|
573
|
+
const format = options.format ?? 'text';
|
|
574
|
+
const limit = parseInt(options.limit ?? '20', 10);
|
|
575
|
+
if (!(await memoryExists(rootDir))) {
|
|
576
|
+
if (format === 'json') {
|
|
577
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
showNoMemoriesMessage();
|
|
581
|
+
}
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
try {
|
|
585
|
+
const cortex = await getCortex(rootDir);
|
|
586
|
+
const query = { limit };
|
|
587
|
+
if (options.type) {
|
|
588
|
+
query.types = [options.type];
|
|
589
|
+
}
|
|
590
|
+
if (options.minConfidence) {
|
|
591
|
+
query.minConfidence = parseFloat(options.minConfidence);
|
|
592
|
+
}
|
|
593
|
+
if (options.importance) {
|
|
594
|
+
query.importance = [options.importance];
|
|
595
|
+
}
|
|
596
|
+
const memories = await cortex.storage.search(query);
|
|
597
|
+
await cortex.storage.close();
|
|
598
|
+
if (format === 'json') {
|
|
599
|
+
console.log(JSON.stringify({ memories, total: memories.length }, null, 2));
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
console.log();
|
|
603
|
+
console.log(chalk.bold('🧠 Memories'));
|
|
604
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
605
|
+
console.log();
|
|
606
|
+
if (memories.length === 0) {
|
|
607
|
+
console.log(chalk.yellow('No memories match the filters.'));
|
|
608
|
+
console.log();
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
// Group by type
|
|
612
|
+
const byType = new Map();
|
|
613
|
+
for (const m of memories) {
|
|
614
|
+
const list = byType.get(m.type) ?? [];
|
|
615
|
+
list.push(m);
|
|
616
|
+
byType.set(m.type, list);
|
|
617
|
+
}
|
|
618
|
+
for (const [type, mems] of byType) {
|
|
619
|
+
const typeInfo = MEMORY_TYPES[type];
|
|
620
|
+
console.log(chalk.bold(`${typeInfo?.icon ?? '📦'} ${type.toUpperCase()}`));
|
|
621
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
622
|
+
for (const m of mems.slice(0, 10)) {
|
|
623
|
+
formatMemoryBrief(m);
|
|
624
|
+
}
|
|
625
|
+
if (mems.length > 10) {
|
|
626
|
+
console.log(chalk.gray(` ... and ${mems.length - 10} more`));
|
|
627
|
+
}
|
|
628
|
+
console.log();
|
|
629
|
+
}
|
|
630
|
+
console.log(chalk.gray(`Showing ${memories.length} memories`));
|
|
631
|
+
console.log();
|
|
632
|
+
}
|
|
633
|
+
catch (error) {
|
|
634
|
+
if (format === 'json') {
|
|
635
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Show subcommand - show memory details
|
|
644
|
+
*/
|
|
645
|
+
async function showAction(id, options) {
|
|
646
|
+
const rootDir = process.cwd();
|
|
647
|
+
const format = options.format ?? 'text';
|
|
648
|
+
try {
|
|
649
|
+
const cortex = await getCortex(rootDir);
|
|
650
|
+
const memory = await cortex.get(id);
|
|
651
|
+
if (!memory) {
|
|
652
|
+
await cortex.storage.close();
|
|
653
|
+
if (format === 'json') {
|
|
654
|
+
console.log(JSON.stringify({ error: 'Memory not found' }));
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
console.log(chalk.red(`Memory not found: ${id}`));
|
|
658
|
+
}
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
// Get related memories
|
|
662
|
+
const related = await cortex.storage.getRelated(id);
|
|
663
|
+
// Get decay factors
|
|
664
|
+
const decay = cortex.calculateDecay(memory);
|
|
665
|
+
await cortex.storage.close();
|
|
666
|
+
if (format === 'json') {
|
|
667
|
+
console.log(JSON.stringify({ memory, related, decay }, null, 2));
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
formatMemoryDetailed(memory, related);
|
|
671
|
+
// Show decay info
|
|
672
|
+
console.log(chalk.bold('📉 Decay'));
|
|
673
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
674
|
+
console.log(` Current Confidence: ${getConfidenceColor(memory.confidence)}`);
|
|
675
|
+
const effectiveConf = isNaN(decay.finalConfidence) ? memory.confidence : decay.finalConfidence;
|
|
676
|
+
const ageFactor = isNaN(decay.temporalDecay) ? 1 : decay.temporalDecay;
|
|
677
|
+
const usageFactor = isNaN(decay.usageBoost) ? 1 : decay.usageBoost;
|
|
678
|
+
console.log(` Effective Confidence: ${getConfidenceColor(effectiveConf)}`);
|
|
679
|
+
console.log(` Age Factor: ${(ageFactor * 100).toFixed(1)}%`);
|
|
680
|
+
console.log(` Usage Factor: ${(usageFactor * 100).toFixed(1)}%`);
|
|
681
|
+
console.log();
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
if (format === 'json') {
|
|
685
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Search subcommand - search memories
|
|
694
|
+
*/
|
|
695
|
+
async function searchAction(query, options) {
|
|
696
|
+
const rootDir = process.cwd();
|
|
697
|
+
const format = options.format ?? 'text';
|
|
698
|
+
const limit = parseInt(options.limit ?? '20', 10);
|
|
699
|
+
if (!(await memoryExists(rootDir))) {
|
|
700
|
+
if (format === 'json') {
|
|
701
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
showNoMemoriesMessage();
|
|
705
|
+
}
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
const spinner = format === 'text' ? createSpinner('Searching...') : null;
|
|
709
|
+
spinner?.start();
|
|
710
|
+
try {
|
|
711
|
+
const cortex = await getCortex(rootDir);
|
|
712
|
+
// Try semantic search first, fall back to text search
|
|
713
|
+
let results = [];
|
|
714
|
+
try {
|
|
715
|
+
const embedding = await cortex.embeddings.embed(query);
|
|
716
|
+
results = await cortex.storage.similaritySearch(embedding, limit);
|
|
717
|
+
}
|
|
718
|
+
catch {
|
|
719
|
+
// Similarity search failed
|
|
720
|
+
}
|
|
721
|
+
// If semantic search returned no results, fall back to text-based search
|
|
722
|
+
if (results.length === 0) {
|
|
723
|
+
const allMemories = await cortex.storage.search({ limit: 1000 });
|
|
724
|
+
const queryLower = query.toLowerCase();
|
|
725
|
+
results = allMemories.filter((m) => {
|
|
726
|
+
const searchText = `${m.summary} ${m.type} ${m.knowledge ?? ''} ${m.topic ?? ''}`.toLowerCase();
|
|
727
|
+
return searchText.includes(queryLower);
|
|
728
|
+
}).slice(0, limit);
|
|
729
|
+
}
|
|
730
|
+
// Filter by type if specified
|
|
731
|
+
if (options.type) {
|
|
732
|
+
results = results.filter(m => m.type === options.type);
|
|
733
|
+
}
|
|
734
|
+
await cortex.storage.close();
|
|
735
|
+
spinner?.stop();
|
|
736
|
+
if (format === 'json') {
|
|
737
|
+
console.log(JSON.stringify({ query, results, total: results.length }, null, 2));
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
console.log();
|
|
741
|
+
console.log(chalk.bold(`🔍 Search Results for "${query}"`));
|
|
742
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
743
|
+
console.log();
|
|
744
|
+
if (results.length === 0) {
|
|
745
|
+
console.log(chalk.yellow('No memories found matching your query.'));
|
|
746
|
+
console.log();
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
for (const m of results) {
|
|
750
|
+
formatMemoryBrief(m);
|
|
751
|
+
}
|
|
752
|
+
console.log();
|
|
753
|
+
console.log(chalk.gray(`Found ${results.length} memories`));
|
|
754
|
+
console.log();
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
spinner?.stop();
|
|
758
|
+
if (format === 'json') {
|
|
759
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Extract topic from content
|
|
768
|
+
*/
|
|
769
|
+
function extractTopic(content) {
|
|
770
|
+
// Extract first few words as topic
|
|
771
|
+
const words = content.split(/\s+/).slice(0, 3);
|
|
772
|
+
return words.join(' ');
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Update subcommand - update a memory
|
|
776
|
+
*/
|
|
777
|
+
async function updateAction(id, options) {
|
|
778
|
+
const rootDir = process.cwd();
|
|
779
|
+
const format = options.format ?? 'text';
|
|
780
|
+
try {
|
|
781
|
+
const cortex = await getCortex(rootDir);
|
|
782
|
+
// Verify memory exists
|
|
783
|
+
const existing = await cortex.get(id);
|
|
784
|
+
if (!existing) {
|
|
785
|
+
await cortex.storage.close();
|
|
786
|
+
if (format === 'json') {
|
|
787
|
+
console.log(JSON.stringify({ error: 'Memory not found' }));
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
console.log(chalk.red(`Memory not found: ${id}`));
|
|
791
|
+
}
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
// Build updates
|
|
795
|
+
const updates = {};
|
|
796
|
+
if (options.confidence) {
|
|
797
|
+
updates.confidence = parseFloat(options.confidence);
|
|
798
|
+
}
|
|
799
|
+
if (options.importance) {
|
|
800
|
+
updates.importance = options.importance;
|
|
801
|
+
}
|
|
802
|
+
if (options.tags) {
|
|
803
|
+
updates.tags = options.tags.split(',').map(t => t.trim());
|
|
804
|
+
}
|
|
805
|
+
if (options.summary) {
|
|
806
|
+
updates.summary = options.summary;
|
|
807
|
+
}
|
|
808
|
+
await cortex.update(id, updates);
|
|
809
|
+
await cortex.storage.close();
|
|
810
|
+
if (format === 'json') {
|
|
811
|
+
console.log(JSON.stringify({ success: true, id, updates }));
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
console.log();
|
|
815
|
+
console.log(chalk.green.bold('✓ Memory updated'));
|
|
816
|
+
console.log();
|
|
817
|
+
console.log(` ID: ${chalk.cyan(id)}`);
|
|
818
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
819
|
+
console.log(` ${key}: ${value}`);
|
|
820
|
+
}
|
|
821
|
+
console.log();
|
|
822
|
+
}
|
|
823
|
+
catch (error) {
|
|
824
|
+
if (format === 'json') {
|
|
825
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Delete subcommand - delete a memory
|
|
834
|
+
*/
|
|
835
|
+
async function deleteAction(id, options) {
|
|
836
|
+
const rootDir = process.cwd();
|
|
837
|
+
const format = options.format ?? 'text';
|
|
838
|
+
try {
|
|
839
|
+
const cortex = await getCortex(rootDir);
|
|
840
|
+
// Verify memory exists
|
|
841
|
+
const existing = await cortex.get(id);
|
|
842
|
+
if (!existing) {
|
|
843
|
+
await cortex.storage.close();
|
|
844
|
+
if (format === 'json') {
|
|
845
|
+
console.log(JSON.stringify({ error: 'Memory not found' }));
|
|
846
|
+
}
|
|
847
|
+
else {
|
|
848
|
+
console.log(chalk.red(`Memory not found: ${id}`));
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
await cortex.delete(id);
|
|
853
|
+
await cortex.storage.close();
|
|
854
|
+
if (format === 'json') {
|
|
855
|
+
console.log(JSON.stringify({ success: true, id }));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
console.log();
|
|
859
|
+
console.log(chalk.green.bold('✓ Memory deleted'));
|
|
860
|
+
console.log(` ID: ${chalk.cyan(id)}`);
|
|
861
|
+
console.log();
|
|
862
|
+
}
|
|
863
|
+
catch (error) {
|
|
864
|
+
if (format === 'json') {
|
|
865
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Learn subcommand - learn from a correction
|
|
874
|
+
*/
|
|
875
|
+
async function learnAction(correction, options) {
|
|
876
|
+
const rootDir = process.cwd();
|
|
877
|
+
const format = options.format ?? 'text';
|
|
878
|
+
// The correction is the main argument, original is optional context
|
|
879
|
+
const feedback = correction;
|
|
880
|
+
const original = options.original ?? 'Previous approach';
|
|
881
|
+
const spinner = format === 'text' ? createSpinner('Learning from correction...') : null;
|
|
882
|
+
spinner?.start();
|
|
883
|
+
try {
|
|
884
|
+
const cortex = await getCortex(rootDir);
|
|
885
|
+
// Check if CortexV2 learn method is available
|
|
886
|
+
let result;
|
|
887
|
+
if ('learn' in cortex) {
|
|
888
|
+
result = await cortex.learn(original, feedback, options.code, { activeFile: options.file });
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
// Fallback: create a tribal memory
|
|
892
|
+
const id = await cortex.add({
|
|
893
|
+
type: 'tribal',
|
|
894
|
+
topic: 'Learned correction',
|
|
895
|
+
knowledge: original !== 'Previous approach'
|
|
896
|
+
? `Original: ${original}\nCorrection: ${feedback}`
|
|
897
|
+
: feedback,
|
|
898
|
+
severity: 'warning',
|
|
899
|
+
source: { type: 'manual' },
|
|
900
|
+
summary: feedback.length > 50 ? `${feedback.slice(0, 47)}...` : feedback,
|
|
901
|
+
confidence: 0.8,
|
|
902
|
+
importance: 'normal',
|
|
903
|
+
});
|
|
904
|
+
result = {
|
|
905
|
+
success: true,
|
|
906
|
+
createdMemories: [id],
|
|
907
|
+
principles: [{ statement: feedback }],
|
|
908
|
+
category: 'correction',
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
await cortex.storage.close();
|
|
912
|
+
spinner?.stop();
|
|
913
|
+
if (format === 'json') {
|
|
914
|
+
console.log(JSON.stringify(result, null, 2));
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
console.log();
|
|
918
|
+
console.log(chalk.green.bold('✓ Learned from correction'));
|
|
919
|
+
console.log();
|
|
920
|
+
if (result.createdMemories?.length > 0) {
|
|
921
|
+
console.log(chalk.bold('📝 Memories Created:'));
|
|
922
|
+
for (const memId of result.createdMemories) {
|
|
923
|
+
console.log(` ${chalk.cyan(memId)}`);
|
|
924
|
+
}
|
|
925
|
+
console.log();
|
|
926
|
+
}
|
|
927
|
+
if (result.principles?.length > 0) {
|
|
928
|
+
console.log(chalk.bold('💡 Extracted Principles:'));
|
|
929
|
+
for (const p of result.principles) {
|
|
930
|
+
console.log(` • ${p.statement}`);
|
|
931
|
+
}
|
|
932
|
+
console.log();
|
|
933
|
+
}
|
|
934
|
+
console.log(`Category: ${result.category}`);
|
|
935
|
+
console.log();
|
|
936
|
+
}
|
|
937
|
+
catch (error) {
|
|
938
|
+
spinner?.stop();
|
|
939
|
+
if (format === 'json') {
|
|
940
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Feedback subcommand - provide feedback on a memory
|
|
949
|
+
*/
|
|
950
|
+
async function feedbackAction(id, action, options) {
|
|
951
|
+
const rootDir = process.cwd();
|
|
952
|
+
const format = options.format ?? 'text';
|
|
953
|
+
if (!['confirm', 'reject', 'modify'].includes(action)) {
|
|
954
|
+
if (format === 'json') {
|
|
955
|
+
console.log(JSON.stringify({ error: 'Action must be: confirm, reject, or modify' }));
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
console.log(chalk.red('Action must be: confirm, reject, or modify'));
|
|
959
|
+
}
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
try {
|
|
963
|
+
const cortex = await getCortex(rootDir);
|
|
964
|
+
const memory = await cortex.get(id);
|
|
965
|
+
if (!memory) {
|
|
966
|
+
await cortex.storage.close();
|
|
967
|
+
if (format === 'json') {
|
|
968
|
+
console.log(JSON.stringify({ error: 'Memory not found' }));
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
console.log(chalk.red(`Memory not found: ${id}`));
|
|
972
|
+
}
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
const previousConfidence = memory.confidence;
|
|
976
|
+
let newConfidence;
|
|
977
|
+
switch (action) {
|
|
978
|
+
case 'confirm':
|
|
979
|
+
newConfidence = Math.min(1.0, previousConfidence + 0.1);
|
|
980
|
+
break;
|
|
981
|
+
case 'reject':
|
|
982
|
+
newConfidence = Math.max(0.1, previousConfidence - 0.3);
|
|
983
|
+
break;
|
|
984
|
+
case 'modify':
|
|
985
|
+
newConfidence = Math.max(0.3, previousConfidence - 0.1);
|
|
986
|
+
break;
|
|
987
|
+
default:
|
|
988
|
+
newConfidence = previousConfidence;
|
|
989
|
+
}
|
|
990
|
+
await cortex.update(id, {
|
|
991
|
+
confidence: newConfidence,
|
|
992
|
+
lastAccessed: new Date().toISOString(),
|
|
993
|
+
accessCount: memory.accessCount + 1,
|
|
994
|
+
});
|
|
995
|
+
await cortex.storage.close();
|
|
996
|
+
if (format === 'json') {
|
|
997
|
+
console.log(JSON.stringify({
|
|
998
|
+
success: true,
|
|
999
|
+
id,
|
|
1000
|
+
action,
|
|
1001
|
+
previousConfidence,
|
|
1002
|
+
newConfidence,
|
|
1003
|
+
}));
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
console.log();
|
|
1007
|
+
console.log(chalk.green.bold(`✓ Feedback recorded: ${action}`));
|
|
1008
|
+
console.log();
|
|
1009
|
+
console.log(` Memory: ${chalk.cyan(id)}`);
|
|
1010
|
+
console.log(` Previous Confidence: ${getConfidenceColor(previousConfidence)}`);
|
|
1011
|
+
console.log(` New Confidence: ${getConfidenceColor(newConfidence)}`);
|
|
1012
|
+
console.log();
|
|
1013
|
+
}
|
|
1014
|
+
catch (error) {
|
|
1015
|
+
if (format === 'json') {
|
|
1016
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Validate subcommand - validate memories
|
|
1025
|
+
*/
|
|
1026
|
+
async function validateAction(options) {
|
|
1027
|
+
const rootDir = process.cwd();
|
|
1028
|
+
const format = options.format ?? 'text';
|
|
1029
|
+
const autoHeal = options.autoHeal !== false;
|
|
1030
|
+
const minConfidence = parseFloat(options.minConfidence ?? '0.2');
|
|
1031
|
+
if (!(await memoryExists(rootDir))) {
|
|
1032
|
+
if (format === 'json') {
|
|
1033
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1034
|
+
}
|
|
1035
|
+
else {
|
|
1036
|
+
showNoMemoriesMessage();
|
|
1037
|
+
}
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const spinner = format === 'text' ? createSpinner('Validating memories...') : null;
|
|
1041
|
+
spinner?.start();
|
|
1042
|
+
try {
|
|
1043
|
+
const cortex = await getCortex(rootDir);
|
|
1044
|
+
const startTime = Date.now();
|
|
1045
|
+
// Get memories based on scope
|
|
1046
|
+
let memories;
|
|
1047
|
+
switch (options.scope) {
|
|
1048
|
+
case 'all':
|
|
1049
|
+
memories = await cortex.storage.search({ limit: 1000 });
|
|
1050
|
+
break;
|
|
1051
|
+
case 'recent':
|
|
1052
|
+
memories = await cortex.storage.search({ limit: 100 });
|
|
1053
|
+
break;
|
|
1054
|
+
case 'high_importance':
|
|
1055
|
+
memories = await cortex.storage.search({
|
|
1056
|
+
importance: ['high', 'critical'],
|
|
1057
|
+
limit: 500,
|
|
1058
|
+
});
|
|
1059
|
+
break;
|
|
1060
|
+
case 'stale':
|
|
1061
|
+
default:
|
|
1062
|
+
memories = await cortex.storage.search({
|
|
1063
|
+
maxConfidence: 0.5,
|
|
1064
|
+
limit: 500,
|
|
1065
|
+
});
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
const healingStats = {
|
|
1069
|
+
confidenceAdjusted: 0,
|
|
1070
|
+
summariesFixed: 0,
|
|
1071
|
+
memoriesRemoved: 0,
|
|
1072
|
+
};
|
|
1073
|
+
const issues = [];
|
|
1074
|
+
let valid = 0;
|
|
1075
|
+
let stale = 0;
|
|
1076
|
+
let healed = 0;
|
|
1077
|
+
for (const memory of memories) {
|
|
1078
|
+
let hasIssue = false;
|
|
1079
|
+
// Check for missing summary
|
|
1080
|
+
if (!memory.summary || memory.summary.trim() === '') {
|
|
1081
|
+
hasIssue = true;
|
|
1082
|
+
if (autoHeal) {
|
|
1083
|
+
await cortex.update(memory.id, { summary: `Memory ${memory.id.slice(0, 8)}...` });
|
|
1084
|
+
healingStats.summariesFixed++;
|
|
1085
|
+
healed++;
|
|
1086
|
+
}
|
|
1087
|
+
issues.push({ memoryId: memory.id, issue: 'Missing summary', healed: autoHeal });
|
|
1088
|
+
}
|
|
1089
|
+
// Check for invalid confidence
|
|
1090
|
+
if (memory.confidence < 0 || memory.confidence > 1) {
|
|
1091
|
+
hasIssue = true;
|
|
1092
|
+
if (autoHeal) {
|
|
1093
|
+
const fixed = Math.max(0, Math.min(1, memory.confidence));
|
|
1094
|
+
await cortex.update(memory.id, { confidence: fixed });
|
|
1095
|
+
healingStats.confidenceAdjusted++;
|
|
1096
|
+
healed++;
|
|
1097
|
+
}
|
|
1098
|
+
issues.push({ memoryId: memory.id, issue: 'Invalid confidence', healed: autoHeal });
|
|
1099
|
+
}
|
|
1100
|
+
// Check for very low confidence
|
|
1101
|
+
if (memory.confidence < minConfidence) {
|
|
1102
|
+
hasIssue = true;
|
|
1103
|
+
stale++;
|
|
1104
|
+
if (options.removeInvalid) {
|
|
1105
|
+
await cortex.delete(memory.id);
|
|
1106
|
+
healingStats.memoriesRemoved++;
|
|
1107
|
+
healed++;
|
|
1108
|
+
}
|
|
1109
|
+
issues.push({ memoryId: memory.id, issue: 'Very low confidence', healed: options.removeInvalid ?? false });
|
|
1110
|
+
}
|
|
1111
|
+
if (!hasIssue) {
|
|
1112
|
+
valid++;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
const duration = Date.now() - startTime;
|
|
1116
|
+
await cortex.storage.close();
|
|
1117
|
+
spinner?.stop();
|
|
1118
|
+
if (format === 'json') {
|
|
1119
|
+
console.log(JSON.stringify({
|
|
1120
|
+
summary: { total: memories.length, valid, stale, healed },
|
|
1121
|
+
healingStats,
|
|
1122
|
+
duration,
|
|
1123
|
+
issues: issues.slice(0, 50),
|
|
1124
|
+
}, null, 2));
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
console.log();
|
|
1128
|
+
console.log(chalk.bold('🔍 Validation Results'));
|
|
1129
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
1130
|
+
console.log();
|
|
1131
|
+
console.log(chalk.bold('📊 Summary'));
|
|
1132
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1133
|
+
console.log(` Total Validated: ${chalk.cyan(memories.length)}`);
|
|
1134
|
+
console.log(` Valid: ${chalk.green(valid)}`);
|
|
1135
|
+
console.log(` Stale: ${stale > 0 ? chalk.yellow(stale) : chalk.green('0')}`);
|
|
1136
|
+
console.log(` Healed: ${healed > 0 ? chalk.cyan(healed) : '0'}`);
|
|
1137
|
+
console.log(` Duration: ${duration}ms`);
|
|
1138
|
+
console.log();
|
|
1139
|
+
if (healingStats.summariesFixed > 0 || healingStats.confidenceAdjusted > 0 || healingStats.memoriesRemoved > 0) {
|
|
1140
|
+
console.log(chalk.bold('🔧 Healing Stats'));
|
|
1141
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1142
|
+
if (healingStats.summariesFixed > 0) {
|
|
1143
|
+
console.log(` Summaries Fixed: ${healingStats.summariesFixed}`);
|
|
1144
|
+
}
|
|
1145
|
+
if (healingStats.confidenceAdjusted > 0) {
|
|
1146
|
+
console.log(` Confidence Adjusted: ${healingStats.confidenceAdjusted}`);
|
|
1147
|
+
}
|
|
1148
|
+
if (healingStats.memoriesRemoved > 0) {
|
|
1149
|
+
console.log(` Memories Removed: ${healingStats.memoriesRemoved}`);
|
|
1150
|
+
}
|
|
1151
|
+
console.log();
|
|
1152
|
+
}
|
|
1153
|
+
if (issues.length > 0 && options.verbose) {
|
|
1154
|
+
console.log(chalk.bold('⚠️ Issues'));
|
|
1155
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1156
|
+
for (const issue of issues.slice(0, 10)) {
|
|
1157
|
+
const icon = issue.healed ? chalk.green('✓') : chalk.yellow('⚠');
|
|
1158
|
+
console.log(` ${icon} ${chalk.cyan(issue.memoryId.slice(0, 8))}... ${issue.issue}`);
|
|
1159
|
+
}
|
|
1160
|
+
if (issues.length > 10) {
|
|
1161
|
+
console.log(chalk.gray(` ... and ${issues.length - 10} more`));
|
|
1162
|
+
}
|
|
1163
|
+
console.log();
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
catch (error) {
|
|
1167
|
+
spinner?.stop();
|
|
1168
|
+
if (format === 'json') {
|
|
1169
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1170
|
+
}
|
|
1171
|
+
else {
|
|
1172
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Consolidate subcommand - consolidate episodic memories
|
|
1178
|
+
*/
|
|
1179
|
+
async function consolidateAction(options) {
|
|
1180
|
+
const rootDir = process.cwd();
|
|
1181
|
+
const format = options.format ?? 'text';
|
|
1182
|
+
const dryRun = options.dryRun ?? false;
|
|
1183
|
+
if (!(await memoryExists(rootDir))) {
|
|
1184
|
+
if (format === 'json') {
|
|
1185
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
showNoMemoriesMessage();
|
|
1189
|
+
}
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
const spinner = format === 'text' ? createSpinner(dryRun ? 'Analyzing consolidation...' : 'Consolidating memories...') : null;
|
|
1193
|
+
spinner?.start();
|
|
1194
|
+
try {
|
|
1195
|
+
const cortex = await getCortex(rootDir);
|
|
1196
|
+
const result = await cortex.consolidate(dryRun);
|
|
1197
|
+
await cortex.storage.close();
|
|
1198
|
+
spinner?.stop();
|
|
1199
|
+
if (format === 'json') {
|
|
1200
|
+
console.log(JSON.stringify({ dryRun, ...result }, null, 2));
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
console.log();
|
|
1204
|
+
console.log(chalk.bold(dryRun ? '🔍 Consolidation Preview' : '✓ Consolidation Complete'));
|
|
1205
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
1206
|
+
console.log();
|
|
1207
|
+
console.log(chalk.bold('📊 Results'));
|
|
1208
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1209
|
+
console.log(` Episodes Processed: ${chalk.cyan(result.episodesProcessed)}`);
|
|
1210
|
+
console.log(` Memories Created: ${chalk.green(result.memoriesCreated)}`);
|
|
1211
|
+
console.log(` Memories Updated: ${chalk.cyan(result.memoriesUpdated)}`);
|
|
1212
|
+
console.log(` Memories Pruned: ${result.memoriesPruned > 0 ? chalk.yellow(result.memoriesPruned) : '0'}`);
|
|
1213
|
+
console.log(` Tokens Freed: ${chalk.cyan(result.tokensFreed)}`);
|
|
1214
|
+
console.log(` Duration: ${result.duration}ms`);
|
|
1215
|
+
console.log();
|
|
1216
|
+
if (dryRun) {
|
|
1217
|
+
console.log(chalk.gray('This was a dry run. Run without --dry-run to apply changes.'));
|
|
1218
|
+
console.log();
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
catch (error) {
|
|
1222
|
+
spinner?.stop();
|
|
1223
|
+
if (format === 'json') {
|
|
1224
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1225
|
+
}
|
|
1226
|
+
else {
|
|
1227
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Warnings subcommand - show active warnings
|
|
1233
|
+
*/
|
|
1234
|
+
async function warningsAction(options) {
|
|
1235
|
+
const rootDir = process.cwd();
|
|
1236
|
+
const format = options.format ?? 'text';
|
|
1237
|
+
if (!(await memoryExists(rootDir))) {
|
|
1238
|
+
if (format === 'json') {
|
|
1239
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
showNoMemoriesMessage();
|
|
1243
|
+
}
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
try {
|
|
1247
|
+
const cortex = await getCortex(rootDir);
|
|
1248
|
+
// Get tribal warnings
|
|
1249
|
+
const tribal = await cortex.search({
|
|
1250
|
+
types: ['tribal'],
|
|
1251
|
+
importance: ['high', 'critical'],
|
|
1252
|
+
limit: 50,
|
|
1253
|
+
});
|
|
1254
|
+
// Get code smells
|
|
1255
|
+
const smells = await cortex.search({
|
|
1256
|
+
types: ['code_smell'],
|
|
1257
|
+
limit: 50,
|
|
1258
|
+
});
|
|
1259
|
+
await cortex.storage.close();
|
|
1260
|
+
const warnings = [];
|
|
1261
|
+
// Process tribal warnings
|
|
1262
|
+
for (const mem of tribal) {
|
|
1263
|
+
if (options.severity === 'critical' && mem.severity !== 'critical')
|
|
1264
|
+
continue;
|
|
1265
|
+
if (options.focus && !mem.topic?.toLowerCase().includes(options.focus.toLowerCase()))
|
|
1266
|
+
continue;
|
|
1267
|
+
warnings.push({
|
|
1268
|
+
type: 'tribal',
|
|
1269
|
+
severity: mem.severity,
|
|
1270
|
+
message: mem.knowledge,
|
|
1271
|
+
source: mem.topic,
|
|
1272
|
+
confidence: mem.confidence,
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
// Process code smells
|
|
1276
|
+
for (const mem of smells) {
|
|
1277
|
+
if (options.focus && !mem.name?.toLowerCase().includes(options.focus.toLowerCase()))
|
|
1278
|
+
continue;
|
|
1279
|
+
warnings.push({
|
|
1280
|
+
type: 'code_smell',
|
|
1281
|
+
severity: mem.severity,
|
|
1282
|
+
message: `${mem.name}: ${mem.reason}`,
|
|
1283
|
+
source: mem.name,
|
|
1284
|
+
confidence: mem.confidence,
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
// Sort by severity
|
|
1288
|
+
const severityOrder = { critical: 0, error: 1, warning: 2, info: 3 };
|
|
1289
|
+
warnings.sort((a, b) => (severityOrder[a.severity] ?? 4) - (severityOrder[b.severity] ?? 4));
|
|
1290
|
+
if (format === 'json') {
|
|
1291
|
+
console.log(JSON.stringify({
|
|
1292
|
+
warnings,
|
|
1293
|
+
total: warnings.length,
|
|
1294
|
+
bySeverity: {
|
|
1295
|
+
critical: warnings.filter(w => w.severity === 'critical').length,
|
|
1296
|
+
warning: warnings.filter(w => w.severity === 'warning').length,
|
|
1297
|
+
info: warnings.filter(w => w.severity === 'info').length,
|
|
1298
|
+
},
|
|
1299
|
+
}, null, 2));
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
console.log();
|
|
1303
|
+
console.log(chalk.bold('⚠️ Active Warnings'));
|
|
1304
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
1305
|
+
console.log();
|
|
1306
|
+
if (warnings.length === 0) {
|
|
1307
|
+
console.log(chalk.green('No active warnings.'));
|
|
1308
|
+
console.log();
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
for (const w of warnings) {
|
|
1312
|
+
const icon = w.severity === 'critical' ? chalk.red('🚨') :
|
|
1313
|
+
w.severity === 'warning' ? chalk.yellow('⚠️') :
|
|
1314
|
+
chalk.blue('ℹ️');
|
|
1315
|
+
const severityColor = w.severity === 'critical' ? chalk.red :
|
|
1316
|
+
w.severity === 'warning' ? chalk.yellow :
|
|
1317
|
+
chalk.gray;
|
|
1318
|
+
console.log(`${icon} ${severityColor(`[${w.severity.toUpperCase()}]`)} ${w.source}`);
|
|
1319
|
+
console.log(` ${w.message}`);
|
|
1320
|
+
console.log(chalk.gray(` Confidence: ${getConfidenceColor(w.confidence)}`));
|
|
1321
|
+
console.log();
|
|
1322
|
+
}
|
|
1323
|
+
console.log(chalk.gray(`Total: ${warnings.length} warnings`));
|
|
1324
|
+
console.log();
|
|
1325
|
+
}
|
|
1326
|
+
catch (error) {
|
|
1327
|
+
if (format === 'json') {
|
|
1328
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1329
|
+
}
|
|
1330
|
+
else {
|
|
1331
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Why subcommand - get context for a task
|
|
1337
|
+
*/
|
|
1338
|
+
async function whyAction(focus, options) {
|
|
1339
|
+
const rootDir = process.cwd();
|
|
1340
|
+
const format = options.format ?? 'text';
|
|
1341
|
+
const intent = (options.intent ?? 'understand_code');
|
|
1342
|
+
const maxTokens = parseInt(options.maxTokens ?? '2000', 10);
|
|
1343
|
+
if (!(await memoryExists(rootDir))) {
|
|
1344
|
+
if (format === 'json') {
|
|
1345
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1346
|
+
}
|
|
1347
|
+
else {
|
|
1348
|
+
showNoMemoriesMessage();
|
|
1349
|
+
}
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
const spinner = format === 'text' ? createSpinner('Gathering context...') : null;
|
|
1353
|
+
spinner?.start();
|
|
1354
|
+
try {
|
|
1355
|
+
const cortex = await getCortex(rootDir);
|
|
1356
|
+
const result = await cortex.retrieval.retrieve({
|
|
1357
|
+
intent,
|
|
1358
|
+
focus,
|
|
1359
|
+
maxTokens,
|
|
1360
|
+
});
|
|
1361
|
+
await cortex.storage.close();
|
|
1362
|
+
spinner?.stop();
|
|
1363
|
+
// Organize by type
|
|
1364
|
+
const byType = {};
|
|
1365
|
+
for (const m of result.memories) {
|
|
1366
|
+
const type = m.memory.type;
|
|
1367
|
+
if (!byType[type])
|
|
1368
|
+
byType[type] = [];
|
|
1369
|
+
byType[type].push(m);
|
|
1370
|
+
}
|
|
1371
|
+
if (format === 'json') {
|
|
1372
|
+
console.log(JSON.stringify({
|
|
1373
|
+
focus,
|
|
1374
|
+
intent,
|
|
1375
|
+
tokensUsed: result.tokensUsed,
|
|
1376
|
+
totalCandidates: result.totalCandidates,
|
|
1377
|
+
retrievalTime: result.retrievalTime,
|
|
1378
|
+
memories: result.memories.map((m) => ({
|
|
1379
|
+
id: m.memory.id,
|
|
1380
|
+
type: m.memory.type,
|
|
1381
|
+
summary: m.memory.summary,
|
|
1382
|
+
relevanceScore: m.relevanceScore,
|
|
1383
|
+
})),
|
|
1384
|
+
}, null, 2));
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
console.log();
|
|
1388
|
+
console.log(chalk.bold(`🔍 Context for "${focus}"`));
|
|
1389
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
1390
|
+
console.log();
|
|
1391
|
+
console.log(chalk.gray(`Intent: ${intent} | Tokens: ${result.tokensUsed}/${maxTokens} | Time: ${result.retrievalTime}ms`));
|
|
1392
|
+
console.log();
|
|
1393
|
+
if (result.memories.length === 0) {
|
|
1394
|
+
console.log(chalk.yellow('No relevant memories found.'));
|
|
1395
|
+
console.log();
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
// Show by type
|
|
1399
|
+
for (const [type, memories] of Object.entries(byType)) {
|
|
1400
|
+
const typeInfo = MEMORY_TYPES[type];
|
|
1401
|
+
console.log(chalk.bold(`${typeInfo?.icon ?? '📦'} ${type.toUpperCase()}`));
|
|
1402
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
1403
|
+
for (const m of memories.slice(0, 5)) {
|
|
1404
|
+
console.log(` ${chalk.cyan(m.memory.id.slice(0, 8))}... ${m.memory.summary}`);
|
|
1405
|
+
console.log(chalk.gray(` Relevance: ${(m.relevanceScore * 100).toFixed(0)}%`));
|
|
1406
|
+
}
|
|
1407
|
+
if (memories.length > 5) {
|
|
1408
|
+
console.log(chalk.gray(` ... and ${memories.length - 5} more`));
|
|
1409
|
+
}
|
|
1410
|
+
console.log();
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
catch (error) {
|
|
1414
|
+
spinner?.stop();
|
|
1415
|
+
if (format === 'json') {
|
|
1416
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Export subcommand - export memories to JSON
|
|
1425
|
+
*/
|
|
1426
|
+
async function exportAction(output, options) {
|
|
1427
|
+
const rootDir = process.cwd();
|
|
1428
|
+
const format = options.format ?? 'text';
|
|
1429
|
+
if (!(await memoryExists(rootDir))) {
|
|
1430
|
+
if (format === 'json') {
|
|
1431
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
showNoMemoriesMessage();
|
|
1435
|
+
}
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
const spinner = format === 'text' ? createSpinner('Exporting memories...') : null;
|
|
1439
|
+
spinner?.start();
|
|
1440
|
+
try {
|
|
1441
|
+
const cortex = await getCortex(rootDir);
|
|
1442
|
+
const query = { limit: 10000 };
|
|
1443
|
+
if (options.type) {
|
|
1444
|
+
query.types = [options.type];
|
|
1445
|
+
}
|
|
1446
|
+
if (options.minConfidence) {
|
|
1447
|
+
query.minConfidence = parseFloat(options.minConfidence);
|
|
1448
|
+
}
|
|
1449
|
+
if (options.includeArchived) {
|
|
1450
|
+
query.includeArchived = true;
|
|
1451
|
+
}
|
|
1452
|
+
const memories = await cortex.search(query);
|
|
1453
|
+
await cortex.storage.close();
|
|
1454
|
+
const exportData = {
|
|
1455
|
+
exportedAt: new Date().toISOString(),
|
|
1456
|
+
version: '1.0.0',
|
|
1457
|
+
count: memories.length,
|
|
1458
|
+
memories,
|
|
1459
|
+
};
|
|
1460
|
+
await fs.writeFile(output, JSON.stringify(exportData, null, 2));
|
|
1461
|
+
spinner?.stop();
|
|
1462
|
+
if (format === 'json') {
|
|
1463
|
+
console.log(JSON.stringify({ success: true, count: memories.length, output }));
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
console.log();
|
|
1467
|
+
console.log(chalk.green.bold(`✓ Exported ${memories.length} memories to ${output}`));
|
|
1468
|
+
console.log();
|
|
1469
|
+
}
|
|
1470
|
+
catch (error) {
|
|
1471
|
+
spinner?.stop();
|
|
1472
|
+
if (format === 'json') {
|
|
1473
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1474
|
+
}
|
|
1475
|
+
else {
|
|
1476
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Import subcommand - import memories from JSON
|
|
1482
|
+
*/
|
|
1483
|
+
async function importAction(input, options) {
|
|
1484
|
+
const rootDir = process.cwd();
|
|
1485
|
+
const format = options.format ?? 'text';
|
|
1486
|
+
const overwrite = options.overwrite ?? false;
|
|
1487
|
+
const spinner = format === 'text' ? createSpinner('Importing memories...') : null;
|
|
1488
|
+
spinner?.start();
|
|
1489
|
+
try {
|
|
1490
|
+
const cortex = await getCortex(rootDir);
|
|
1491
|
+
const content = await fs.readFile(input, 'utf-8');
|
|
1492
|
+
const data = JSON.parse(content);
|
|
1493
|
+
const memories = data.memories ?? data;
|
|
1494
|
+
let imported = 0;
|
|
1495
|
+
let skipped = 0;
|
|
1496
|
+
let errors = 0;
|
|
1497
|
+
for (const memory of memories) {
|
|
1498
|
+
try {
|
|
1499
|
+
const existing = await cortex.get(memory.id);
|
|
1500
|
+
if (existing && !overwrite) {
|
|
1501
|
+
skipped++;
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if (existing) {
|
|
1505
|
+
await cortex.update(memory.id, memory);
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
await cortex.add(memory);
|
|
1509
|
+
}
|
|
1510
|
+
imported++;
|
|
1511
|
+
}
|
|
1512
|
+
catch {
|
|
1513
|
+
errors++;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
await cortex.storage.close();
|
|
1517
|
+
spinner?.stop();
|
|
1518
|
+
if (format === 'json') {
|
|
1519
|
+
console.log(JSON.stringify({ imported, skipped, errors, total: memories.length }));
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
console.log();
|
|
1523
|
+
console.log(chalk.green.bold('✓ Import complete'));
|
|
1524
|
+
console.log();
|
|
1525
|
+
console.log(` Imported: ${chalk.green(imported)}`);
|
|
1526
|
+
console.log(` Skipped: ${skipped > 0 ? chalk.yellow(skipped) : '0'}`);
|
|
1527
|
+
console.log(` Errors: ${errors > 0 ? chalk.red(errors) : '0'}`);
|
|
1528
|
+
console.log(` Total: ${memories.length}`);
|
|
1529
|
+
console.log();
|
|
1530
|
+
}
|
|
1531
|
+
catch (error) {
|
|
1532
|
+
spinner?.stop();
|
|
1533
|
+
if (format === 'json') {
|
|
1534
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1535
|
+
}
|
|
1536
|
+
else {
|
|
1537
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Health subcommand - comprehensive health report
|
|
1543
|
+
*/
|
|
1544
|
+
async function healthAction(options) {
|
|
1545
|
+
const rootDir = process.cwd();
|
|
1546
|
+
const format = options.format ?? 'text';
|
|
1547
|
+
if (!(await memoryExists(rootDir))) {
|
|
1548
|
+
if (format === 'json') {
|
|
1549
|
+
console.log(JSON.stringify({ error: 'Memory system not initialized' }));
|
|
1550
|
+
}
|
|
1551
|
+
else {
|
|
1552
|
+
showNoMemoriesMessage();
|
|
1553
|
+
}
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
const spinner = format === 'text' ? createSpinner('Analyzing memory health...') : null;
|
|
1557
|
+
spinner?.start();
|
|
1558
|
+
try {
|
|
1559
|
+
const cortex = await getCortex(rootDir);
|
|
1560
|
+
// Get memory statistics
|
|
1561
|
+
const countByType = await cortex.storage.countByType();
|
|
1562
|
+
const total = Object.values(countByType).reduce((sum, count) => sum + count, 0);
|
|
1563
|
+
// Get sample of memories for analysis
|
|
1564
|
+
const memories = await cortex.storage.search({ limit: 500 });
|
|
1565
|
+
let confidenceSum = 0;
|
|
1566
|
+
let lowConfidenceCount = 0;
|
|
1567
|
+
let recentlyAccessed = 0;
|
|
1568
|
+
const oneWeekAgo = new Date();
|
|
1569
|
+
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
|
1570
|
+
for (const memory of memories) {
|
|
1571
|
+
confidenceSum += memory.confidence;
|
|
1572
|
+
if (memory.confidence < 0.5) {
|
|
1573
|
+
lowConfidenceCount++;
|
|
1574
|
+
}
|
|
1575
|
+
if (memory.lastAccessed && new Date(memory.lastAccessed) > oneWeekAgo) {
|
|
1576
|
+
recentlyAccessed++;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
const avgConfidence = memories.length > 0 ? confidenceSum / memories.length : 0;
|
|
1580
|
+
// Identify issues
|
|
1581
|
+
const issues = [];
|
|
1582
|
+
const recommendations = [];
|
|
1583
|
+
if (avgConfidence < 0.5) {
|
|
1584
|
+
issues.push({
|
|
1585
|
+
severity: 'high',
|
|
1586
|
+
message: `Average memory confidence is low (${Math.round(avgConfidence * 100)}%)`,
|
|
1587
|
+
recommendation: 'Run validation to confirm or remove low-confidence memories',
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
if (lowConfidenceCount > memories.length * 0.3) {
|
|
1591
|
+
issues.push({
|
|
1592
|
+
severity: 'medium',
|
|
1593
|
+
message: `${lowConfidenceCount} memories (${Math.round(lowConfidenceCount / memories.length * 100)}%) have low confidence`,
|
|
1594
|
+
recommendation: 'Review and validate these memories',
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
if (total > 1000) {
|
|
1598
|
+
issues.push({
|
|
1599
|
+
severity: 'low',
|
|
1600
|
+
message: `Large memory count (${total}) may impact performance`,
|
|
1601
|
+
recommendation: 'Consider running consolidation to merge similar memories',
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
if (recentlyAccessed < memories.length * 0.1) {
|
|
1605
|
+
issues.push({
|
|
1606
|
+
severity: 'low',
|
|
1607
|
+
message: 'Most memories have not been accessed recently',
|
|
1608
|
+
recommendation: 'Consider pruning unused memories',
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
// Generate recommendations
|
|
1612
|
+
if (lowConfidenceCount > 10) {
|
|
1613
|
+
recommendations.push('Run `drift memory validate` to clean up low-confidence memories');
|
|
1614
|
+
}
|
|
1615
|
+
if (total > 500) {
|
|
1616
|
+
recommendations.push('Run `drift memory consolidate` to merge similar memories');
|
|
1617
|
+
}
|
|
1618
|
+
if (avgConfidence < 0.7) {
|
|
1619
|
+
recommendations.push('Use `drift memory feedback` to confirm accurate memories');
|
|
1620
|
+
}
|
|
1621
|
+
if (recommendations.length === 0) {
|
|
1622
|
+
recommendations.push('Memory system is healthy. Continue using as normal.');
|
|
1623
|
+
}
|
|
1624
|
+
// Calculate overall score
|
|
1625
|
+
let overallScore = 100;
|
|
1626
|
+
for (const issue of issues) {
|
|
1627
|
+
switch (issue.severity) {
|
|
1628
|
+
case 'critical':
|
|
1629
|
+
overallScore -= 30;
|
|
1630
|
+
break;
|
|
1631
|
+
case 'high':
|
|
1632
|
+
overallScore -= 20;
|
|
1633
|
+
break;
|
|
1634
|
+
case 'medium':
|
|
1635
|
+
overallScore -= 10;
|
|
1636
|
+
break;
|
|
1637
|
+
case 'low':
|
|
1638
|
+
overallScore -= 5;
|
|
1639
|
+
break;
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
overallScore = Math.max(0, overallScore);
|
|
1643
|
+
await cortex.storage.close();
|
|
1644
|
+
spinner?.stop();
|
|
1645
|
+
if (format === 'json') {
|
|
1646
|
+
console.log(JSON.stringify({
|
|
1647
|
+
overallScore,
|
|
1648
|
+
status: overallScore >= 80 ? 'healthy' : overallScore >= 50 ? 'warning' : 'critical',
|
|
1649
|
+
memoryStats: {
|
|
1650
|
+
total,
|
|
1651
|
+
byType: countByType,
|
|
1652
|
+
avgConfidence,
|
|
1653
|
+
lowConfidenceCount,
|
|
1654
|
+
recentlyAccessed,
|
|
1655
|
+
},
|
|
1656
|
+
issues,
|
|
1657
|
+
recommendations,
|
|
1658
|
+
}, null, 2));
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
console.log();
|
|
1662
|
+
console.log(chalk.bold('🏥 Memory Health Report'));
|
|
1663
|
+
console.log(chalk.gray('═'.repeat(60)));
|
|
1664
|
+
console.log();
|
|
1665
|
+
console.log(chalk.bold('📊 Overall Health'));
|
|
1666
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1667
|
+
console.log(` Score: ${getHealthColor(overallScore)}`);
|
|
1668
|
+
console.log();
|
|
1669
|
+
console.log(chalk.bold('📈 Statistics'));
|
|
1670
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1671
|
+
console.log(` Total Memories: ${chalk.cyan(total)}`);
|
|
1672
|
+
console.log(` Avg Confidence: ${getConfidenceColor(avgConfidence)}`);
|
|
1673
|
+
console.log(` Low Confidence: ${lowConfidenceCount > 0 ? chalk.yellow(lowConfidenceCount) : chalk.green('0')}`);
|
|
1674
|
+
console.log(` Recently Accessed: ${chalk.cyan(recentlyAccessed)}`);
|
|
1675
|
+
console.log();
|
|
1676
|
+
if (issues.length > 0) {
|
|
1677
|
+
console.log(chalk.bold('⚠️ Issues'));
|
|
1678
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1679
|
+
for (const issue of issues) {
|
|
1680
|
+
const icon = issue.severity === 'high' ? chalk.red('●') :
|
|
1681
|
+
issue.severity === 'medium' ? chalk.yellow('●') :
|
|
1682
|
+
chalk.gray('●');
|
|
1683
|
+
console.log(` ${icon} ${issue.message}`);
|
|
1684
|
+
console.log(chalk.gray(` → ${issue.recommendation}`));
|
|
1685
|
+
}
|
|
1686
|
+
console.log();
|
|
1687
|
+
}
|
|
1688
|
+
console.log(chalk.bold('💡 Recommendations'));
|
|
1689
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1690
|
+
for (const rec of recommendations) {
|
|
1691
|
+
console.log(` • ${rec}`);
|
|
1692
|
+
}
|
|
1693
|
+
console.log();
|
|
1694
|
+
}
|
|
1695
|
+
catch (error) {
|
|
1696
|
+
spinner?.stop();
|
|
1697
|
+
if (format === 'json') {
|
|
1698
|
+
console.log(JSON.stringify({ error: String(error) }));
|
|
1699
|
+
}
|
|
1700
|
+
else {
|
|
1701
|
+
console.log(chalk.red(`Error: ${error}`));
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
// ============================================================================
|
|
1706
|
+
// Command Registration
|
|
1707
|
+
// ============================================================================
|
|
1708
|
+
export function createMemoryCommand() {
|
|
1709
|
+
const cmd = new Command('memory')
|
|
1710
|
+
.description('Manage Cortex V2 memories - institutional knowledge, procedures, patterns, and more')
|
|
1711
|
+
.option('-f, --format <format>', 'Output format (text, json)', 'text')
|
|
1712
|
+
.option('-v, --verbose', 'Enable verbose output');
|
|
1713
|
+
// Initialize
|
|
1714
|
+
cmd
|
|
1715
|
+
.command('init')
|
|
1716
|
+
.description('Initialize the memory system')
|
|
1717
|
+
.action(() => initAction(cmd.opts()));
|
|
1718
|
+
// Status
|
|
1719
|
+
cmd
|
|
1720
|
+
.command('status')
|
|
1721
|
+
.description('Show memory system status and health')
|
|
1722
|
+
.action(() => statusAction(cmd.opts()));
|
|
1723
|
+
// Add
|
|
1724
|
+
cmd
|
|
1725
|
+
.command('add <type> <content>')
|
|
1726
|
+
.description('Add a new memory (types: tribal, procedural, pattern_rationale, code_smell, decision_context, constraint_override)')
|
|
1727
|
+
.option('-t, --topic <topic>', 'Topic or name for the memory')
|
|
1728
|
+
.option('-s, --severity <severity>', 'Severity level (info, warning, critical)', 'warning')
|
|
1729
|
+
.option('-i, --importance <importance>', 'Importance level (low, normal, high, critical)', 'normal')
|
|
1730
|
+
.option('--tags <tags>', 'Comma-separated tags')
|
|
1731
|
+
.option('--file <file>', 'Link to a file')
|
|
1732
|
+
.option('--pattern <pattern>', 'Link to a pattern ID')
|
|
1733
|
+
.action((type, content, opts) => addAction(type, content, { ...cmd.opts(), ...opts }));
|
|
1734
|
+
// List
|
|
1735
|
+
cmd
|
|
1736
|
+
.command('list')
|
|
1737
|
+
.description('List memories')
|
|
1738
|
+
.option('-t, --type <type>', 'Filter by memory type')
|
|
1739
|
+
.option('-i, --importance <importance>', 'Filter by importance')
|
|
1740
|
+
.option('-l, --limit <number>', 'Maximum results', '20')
|
|
1741
|
+
.option('--min-confidence <number>', 'Minimum confidence threshold')
|
|
1742
|
+
.action((opts) => listAction({ ...cmd.opts(), ...opts }));
|
|
1743
|
+
// Show
|
|
1744
|
+
cmd
|
|
1745
|
+
.command('show <id>')
|
|
1746
|
+
.description('Show memory details')
|
|
1747
|
+
.action((id) => showAction(id, cmd.opts()));
|
|
1748
|
+
// Search
|
|
1749
|
+
cmd
|
|
1750
|
+
.command('search <query>')
|
|
1751
|
+
.description('Search memories')
|
|
1752
|
+
.option('-t, --type <type>', 'Filter by memory type')
|
|
1753
|
+
.option('-l, --limit <number>', 'Maximum results', '20')
|
|
1754
|
+
.action((query, opts) => searchAction(query, { ...cmd.opts(), ...opts }));
|
|
1755
|
+
// Update
|
|
1756
|
+
cmd
|
|
1757
|
+
.command('update <id>')
|
|
1758
|
+
.description('Update a memory')
|
|
1759
|
+
.option('-c, --confidence <number>', 'New confidence value (0-1)')
|
|
1760
|
+
.option('-i, --importance <importance>', 'New importance level')
|
|
1761
|
+
.option('--tags <tags>', 'New comma-separated tags')
|
|
1762
|
+
.option('--summary <summary>', 'New summary')
|
|
1763
|
+
.action((id, opts) => updateAction(id, { ...cmd.opts(), ...opts }));
|
|
1764
|
+
// Delete
|
|
1765
|
+
cmd
|
|
1766
|
+
.command('delete <id>')
|
|
1767
|
+
.description('Delete a memory (soft delete)')
|
|
1768
|
+
.action((id) => deleteAction(id, cmd.opts()));
|
|
1769
|
+
// Learn
|
|
1770
|
+
cmd
|
|
1771
|
+
.command('learn <correction>')
|
|
1772
|
+
.description('Learn from a correction (e.g., "Always use bcrypt with cost factor 12")')
|
|
1773
|
+
.option('-o, --original <text>', 'What was originally done (optional context)')
|
|
1774
|
+
.option('-c, --code <code>', 'Corrected code example')
|
|
1775
|
+
.option('--file <file>', 'Related file')
|
|
1776
|
+
.action((correction, opts) => learnAction(correction, { ...cmd.opts(), ...opts }));
|
|
1777
|
+
// Feedback
|
|
1778
|
+
cmd
|
|
1779
|
+
.command('feedback <id> <action>')
|
|
1780
|
+
.description('Provide feedback on a memory (actions: confirm, reject, modify)')
|
|
1781
|
+
.option('-d, --details <text>', 'Additional details')
|
|
1782
|
+
.action((id, action, opts) => feedbackAction(id, action, { ...cmd.opts(), ...opts }));
|
|
1783
|
+
// Validate
|
|
1784
|
+
cmd
|
|
1785
|
+
.command('validate')
|
|
1786
|
+
.description('Validate memories and optionally heal issues')
|
|
1787
|
+
.option('-s, --scope <scope>', 'Scope: all, stale, recent, high_importance', 'stale')
|
|
1788
|
+
.option('--auto-heal', 'Automatically heal minor issues', true)
|
|
1789
|
+
.option('--remove-invalid', 'Remove memories that cannot be healed')
|
|
1790
|
+
.option('--min-confidence <number>', 'Minimum confidence to keep', '0.2')
|
|
1791
|
+
.action((opts) => validateAction({ ...cmd.opts(), ...opts }));
|
|
1792
|
+
// Consolidate
|
|
1793
|
+
cmd
|
|
1794
|
+
.command('consolidate')
|
|
1795
|
+
.description('Consolidate episodic memories into semantic knowledge')
|
|
1796
|
+
.option('--dry-run', 'Preview without making changes')
|
|
1797
|
+
.action((opts) => consolidateAction({ ...cmd.opts(), ...opts }));
|
|
1798
|
+
// Warnings
|
|
1799
|
+
cmd
|
|
1800
|
+
.command('warnings')
|
|
1801
|
+
.description('Show active warnings from tribal knowledge and code smells')
|
|
1802
|
+
.option('--focus <focus>', 'Filter by focus area')
|
|
1803
|
+
.option('--severity <severity>', 'Filter by severity (all, critical, warning)', 'all')
|
|
1804
|
+
.action((opts) => warningsAction({ ...cmd.opts(), ...opts }));
|
|
1805
|
+
// Why
|
|
1806
|
+
cmd
|
|
1807
|
+
.command('why <focus>')
|
|
1808
|
+
.description('Get context for a task - patterns, decisions, tribal knowledge')
|
|
1809
|
+
.option('-i, --intent <intent>', 'Intent: add_feature, fix_bug, refactor, security_audit, understand_code, add_test', 'understand_code')
|
|
1810
|
+
.option('--max-tokens <number>', 'Maximum tokens to use', '2000')
|
|
1811
|
+
.action((focus, opts) => whyAction(focus, { ...cmd.opts(), ...opts }));
|
|
1812
|
+
// Export
|
|
1813
|
+
cmd
|
|
1814
|
+
.command('export <output>')
|
|
1815
|
+
.description('Export memories to JSON file')
|
|
1816
|
+
.option('-t, --type <type>', 'Filter by memory type')
|
|
1817
|
+
.option('--min-confidence <number>', 'Minimum confidence threshold')
|
|
1818
|
+
.option('--include-archived', 'Include archived memories')
|
|
1819
|
+
.action((output, opts) => exportAction(output, { ...cmd.opts(), ...opts }));
|
|
1820
|
+
// Import
|
|
1821
|
+
cmd
|
|
1822
|
+
.command('import <input>')
|
|
1823
|
+
.description('Import memories from JSON file')
|
|
1824
|
+
.option('--overwrite', 'Overwrite existing memories with same ID')
|
|
1825
|
+
.action((input, opts) => importAction(input, { ...cmd.opts(), ...opts }));
|
|
1826
|
+
// Health
|
|
1827
|
+
cmd
|
|
1828
|
+
.command('health')
|
|
1829
|
+
.description('Get comprehensive health report')
|
|
1830
|
+
.action(() => healthAction(cmd.opts()));
|
|
1831
|
+
return cmd;
|
|
1832
|
+
}
|
|
1833
|
+
//# sourceMappingURL=memory.js.map
|