monomind 1.17.0 → 1.17.1
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/.claude/agents/engineering/engineering-security-engineer.md +1 -1
- package/.claude/commands/mastermind/_repeat.md +4 -0
- package/.claude/commands/mastermind/master.md +52 -1
- package/.claude/scheduled_tasks.lock +1 -1
- package/.claude/skills/mastermind/_repeat.md +2 -0
- package/package.json +1 -1
- package/packages/@monomind/cli/.claude/agents/engineering/engineering-security-engineer.md +1 -1
- package/packages/@monomind/cli/.claude/commands/mastermind/_repeat.md +4 -0
- package/packages/@monomind/cli/.claude/commands/mastermind/master.md +52 -1
- package/packages/@monomind/cli/.claude/skills/mastermind/_repeat.md +2 -0
- package/packages/@monomind/cli/dist/src/__tests__/browse-analyzer.test.js +42 -59
- package/packages/@monomind/cli/dist/src/browser/dashboard/server.js +18 -0
- package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +37 -125
- package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.d.ts +17 -0
- package/packages/@monomind/cli/dist/src/commands/agent-lifecycle.js +320 -0
- package/packages/@monomind/cli/dist/src/commands/agent-ops.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/commands/agent-ops.js +329 -0
- package/packages/@monomind/cli/dist/src/commands/agent.js +5 -907
- package/packages/@monomind/cli/dist/src/commands/analyze-ast.d.ts +26 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-ast.js +284 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.d.ts +14 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-boundaries.js +295 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-diff.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-diff.js +395 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-graph.d.ts +14 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-graph.js +304 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-imports.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-imports.js +287 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-symbols.d.ts +14 -0
- package/packages/@monomind/cli/dist/src/commands/analyze-symbols.js +302 -0
- package/packages/@monomind/cli/dist/src/commands/analyze.d.ts +38 -0
- package/packages/@monomind/cli/dist/src/commands/analyze.js +12 -1827
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.d.ts +26 -0
- package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +189 -0
- package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.d.ts +19 -0
- package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.js +388 -0
- package/packages/@monomind/cli/dist/src/commands/doctor.js +51 -942
- package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.d.ts +11 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-comms.js +242 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.d.ts +35 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-helpers.js +203 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-ops.js +233 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.d.ts +12 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind-spawn.js +274 -0
- package/packages/@monomind/cli/dist/src/commands/hive-mind.js +10 -1129
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.d.ts +4 -4
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +19 -819
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-gaps.js +334 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/commands/hooks-coverage-routing.js +399 -0
- package/packages/@monomind/cli/dist/src/commands/init-subcommands.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/init-subcommands.js +156 -0
- package/packages/@monomind/cli/dist/src/commands/init-upgrade.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/commands/init-upgrade.js +203 -0
- package/packages/@monomind/cli/dist/src/commands/init-wizard.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/commands/init-wizard.js +246 -0
- package/packages/@monomind/cli/dist/src/commands/init.js +6 -623
- package/packages/@monomind/cli/dist/src/commands/memory-admin.d.ts +10 -0
- package/packages/@monomind/cli/dist/src/commands/memory-admin.js +433 -0
- package/packages/@monomind/cli/dist/src/commands/memory-crud.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/commands/memory-crud.js +342 -0
- package/packages/@monomind/cli/dist/src/commands/memory-list.d.ts +10 -0
- package/packages/@monomind/cli/dist/src/commands/memory-list.js +321 -0
- package/packages/@monomind/cli/dist/src/commands/memory-transfer.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +372 -0
- package/packages/@monomind/cli/dist/src/commands/memory.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/commands/memory.js +10 -1441
- package/packages/@monomind/cli/dist/src/commands/neural-core.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/commands/neural-core.js +274 -0
- package/packages/@monomind/cli/dist/src/commands/neural-optimize.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/commands/neural-optimize.js +332 -0
- package/packages/@monomind/cli/dist/src/commands/neural-registry.d.ts +7 -0
- package/packages/@monomind/cli/dist/src/commands/neural-registry.js +290 -0
- package/packages/@monomind/cli/dist/src/commands/neural.js +3 -974
- package/packages/@monomind/cli/dist/src/commands/platforms.js +327 -7
- package/packages/@monomind/cli/dist/src/commands/security-cve.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/commands/security-cve.js +310 -0
- package/packages/@monomind/cli/dist/src/commands/security-misc.d.ts +9 -0
- package/packages/@monomind/cli/dist/src/commands/security-misc.js +293 -0
- package/packages/@monomind/cli/dist/src/commands/security-scan.d.ts +18 -0
- package/packages/@monomind/cli/dist/src/commands/security-scan.js +328 -0
- package/packages/@monomind/cli/dist/src/commands/security.js +3 -958
- package/packages/@monomind/cli/dist/src/commands/session.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/swarm.js +23 -17
- package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +77 -0
- package/packages/@monomind/cli/dist/src/parser.js +11 -6
- package/packages/@monomind/cli/dist/src/routing/llm-caller.js +1 -2
- package/packages/@monomind/cli/package.json +2 -3
- package/packages/@monomind/cli/scripts/understand-analyze.mjs +1 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory CRUD Commands
|
|
3
|
+
* store, retrieve, search
|
|
4
|
+
*/
|
|
5
|
+
import { output } from '../output.js';
|
|
6
|
+
import { input } from '../prompt.js';
|
|
7
|
+
// Store command
|
|
8
|
+
export const storeCommand = {
|
|
9
|
+
name: 'store',
|
|
10
|
+
description: 'Store data in memory',
|
|
11
|
+
options: [
|
|
12
|
+
{
|
|
13
|
+
name: 'key',
|
|
14
|
+
short: 'k',
|
|
15
|
+
description: 'Storage key/namespace',
|
|
16
|
+
type: 'string',
|
|
17
|
+
required: true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'value',
|
|
21
|
+
// Note: No short flag - global -v is reserved for verbose
|
|
22
|
+
description: 'Value to store (use --value)',
|
|
23
|
+
type: 'string'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'namespace',
|
|
27
|
+
short: 'n',
|
|
28
|
+
description: 'Memory namespace',
|
|
29
|
+
type: 'string',
|
|
30
|
+
default: 'default'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'ttl',
|
|
34
|
+
description: 'Time to live in seconds',
|
|
35
|
+
type: 'number'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'tags',
|
|
39
|
+
description: 'Comma-separated tags',
|
|
40
|
+
type: 'string'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'vector',
|
|
44
|
+
description: 'Store as vector embedding',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
default: false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'upsert',
|
|
50
|
+
short: 'u',
|
|
51
|
+
description: 'Update if key exists (insert or replace)',
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
default: false
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
examples: [
|
|
57
|
+
{ command: 'monomind memory store -k "api/auth" -v "JWT implementation"', description: 'Store text' },
|
|
58
|
+
{ command: 'monomind memory store -k "pattern/singleton" --vector', description: 'Store vector' },
|
|
59
|
+
{ command: 'monomind memory store -k "pattern" -v "updated" --upsert', description: 'Update existing' }
|
|
60
|
+
],
|
|
61
|
+
action: async (ctx) => {
|
|
62
|
+
const key = ctx.flags.key;
|
|
63
|
+
let value = ctx.flags.value || ctx.args[0];
|
|
64
|
+
const namespace = ctx.flags.namespace;
|
|
65
|
+
const ttl = ctx.flags.ttl;
|
|
66
|
+
const tags = ctx.flags.tags ? ctx.flags.tags.split(',') : [];
|
|
67
|
+
const asVector = ctx.flags.vector;
|
|
68
|
+
const upsert = ctx.flags.upsert;
|
|
69
|
+
if (!key) {
|
|
70
|
+
output.printError('Key is required. Use --key or -k');
|
|
71
|
+
return { success: false, exitCode: 1 };
|
|
72
|
+
}
|
|
73
|
+
if (!value && ctx.interactive) {
|
|
74
|
+
value = await input({
|
|
75
|
+
message: 'Enter value to store:',
|
|
76
|
+
validate: (v) => v.length > 0 || 'Value is required'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (!value) {
|
|
80
|
+
output.printError('Value is required. Use --value');
|
|
81
|
+
return { success: false, exitCode: 1 };
|
|
82
|
+
}
|
|
83
|
+
const storeData = {
|
|
84
|
+
key,
|
|
85
|
+
namespace,
|
|
86
|
+
value,
|
|
87
|
+
ttl,
|
|
88
|
+
tags,
|
|
89
|
+
asVector,
|
|
90
|
+
storedAt: new Date().toISOString(),
|
|
91
|
+
size: Buffer.byteLength(value, 'utf8')
|
|
92
|
+
};
|
|
93
|
+
output.printInfo(`Storing in ${namespace}/${key}...`);
|
|
94
|
+
// Use direct sql.js storage with automatic embedding generation
|
|
95
|
+
try {
|
|
96
|
+
const { storeEntry } = await import('../memory/memory-initializer.js');
|
|
97
|
+
if (asVector) {
|
|
98
|
+
output.writeln(output.dim(' Generating embedding vector...'));
|
|
99
|
+
}
|
|
100
|
+
const result = await storeEntry({
|
|
101
|
+
key,
|
|
102
|
+
value,
|
|
103
|
+
namespace,
|
|
104
|
+
generateEmbeddingFlag: true, // Always generate embeddings for semantic search
|
|
105
|
+
tags,
|
|
106
|
+
ttl,
|
|
107
|
+
upsert
|
|
108
|
+
});
|
|
109
|
+
if (!result.success) {
|
|
110
|
+
output.printError(result.error || 'Failed to store');
|
|
111
|
+
return { success: false, exitCode: 1 };
|
|
112
|
+
}
|
|
113
|
+
output.writeln();
|
|
114
|
+
output.printTable({
|
|
115
|
+
columns: [
|
|
116
|
+
{ key: 'property', header: 'Property', width: 15 },
|
|
117
|
+
{ key: 'val', header: 'Value', width: 40 }
|
|
118
|
+
],
|
|
119
|
+
data: [
|
|
120
|
+
{ property: 'Key', val: key },
|
|
121
|
+
{ property: 'Namespace', val: namespace },
|
|
122
|
+
{ property: 'Size', val: `${storeData.size} bytes` },
|
|
123
|
+
{ property: 'TTL', val: ttl ? `${ttl}s` : 'None' },
|
|
124
|
+
{ property: 'Tags', val: tags.length > 0 ? tags.join(', ') : 'None' },
|
|
125
|
+
{ property: 'Vector', val: result.embedding ? `Yes (${result.embedding.dimensions}-dim)` : 'No' },
|
|
126
|
+
{ property: 'ID', val: result.id.substring(0, 20) }
|
|
127
|
+
]
|
|
128
|
+
});
|
|
129
|
+
output.writeln();
|
|
130
|
+
output.printSuccess('Data stored successfully');
|
|
131
|
+
return { success: true, data: { ...storeData, id: result.id, embedding: result.embedding } };
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
output.printError(`Failed to store: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
135
|
+
return { success: false, exitCode: 1 };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
// Retrieve command
|
|
140
|
+
export const retrieveCommand = {
|
|
141
|
+
name: 'retrieve',
|
|
142
|
+
aliases: ['get'],
|
|
143
|
+
description: 'Retrieve data from memory',
|
|
144
|
+
options: [
|
|
145
|
+
{
|
|
146
|
+
name: 'key',
|
|
147
|
+
short: 'k',
|
|
148
|
+
description: 'Storage key',
|
|
149
|
+
type: 'string'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'namespace',
|
|
153
|
+
short: 'n',
|
|
154
|
+
description: 'Memory namespace',
|
|
155
|
+
type: 'string',
|
|
156
|
+
default: 'default'
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
action: async (ctx) => {
|
|
160
|
+
const key = ctx.flags.key || ctx.args[0];
|
|
161
|
+
const namespace = ctx.flags.namespace;
|
|
162
|
+
if (!key) {
|
|
163
|
+
output.printError('Key is required');
|
|
164
|
+
return { success: false, exitCode: 1 };
|
|
165
|
+
}
|
|
166
|
+
// Use sql.js directly for consistent data access
|
|
167
|
+
try {
|
|
168
|
+
const { getEntry } = await import('../memory/memory-initializer.js');
|
|
169
|
+
const result = await getEntry({ key, namespace });
|
|
170
|
+
if (!result.success) {
|
|
171
|
+
output.printError(`Failed to retrieve: ${result.error}`);
|
|
172
|
+
return { success: false, exitCode: 1 };
|
|
173
|
+
}
|
|
174
|
+
if (!result.found || !result.entry) {
|
|
175
|
+
output.printWarning(`Key not found: ${key}`);
|
|
176
|
+
return { success: false, exitCode: 1, data: { key, found: false } };
|
|
177
|
+
}
|
|
178
|
+
const entry = result.entry;
|
|
179
|
+
if (ctx.flags.format === 'json') {
|
|
180
|
+
output.printJson(entry);
|
|
181
|
+
return { success: true, data: entry };
|
|
182
|
+
}
|
|
183
|
+
output.writeln();
|
|
184
|
+
output.printBox([
|
|
185
|
+
`Namespace: ${entry.namespace}`,
|
|
186
|
+
`Key: ${entry.key}`,
|
|
187
|
+
`Size: ${entry.content.length} bytes`,
|
|
188
|
+
`Access Count: ${entry.accessCount}`,
|
|
189
|
+
`Tags: ${entry.tags.length > 0 ? entry.tags.join(', ') : 'None'}`,
|
|
190
|
+
`Vector: ${entry.hasEmbedding ? 'Yes' : 'No'}`,
|
|
191
|
+
'',
|
|
192
|
+
output.bold('Value:'),
|
|
193
|
+
entry.content
|
|
194
|
+
].join('\n'), 'Memory Entry');
|
|
195
|
+
return { success: true, data: entry };
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
output.printError(`Failed to retrieve: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
199
|
+
return { success: false, exitCode: 1 };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
// Search command
|
|
204
|
+
export const searchCommand = {
|
|
205
|
+
name: 'search',
|
|
206
|
+
description: 'Search memory with semantic/vector search',
|
|
207
|
+
options: [
|
|
208
|
+
{
|
|
209
|
+
name: 'query',
|
|
210
|
+
short: 'q',
|
|
211
|
+
description: 'Search query',
|
|
212
|
+
type: 'string',
|
|
213
|
+
required: true
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'namespace',
|
|
217
|
+
short: 'n',
|
|
218
|
+
description: 'Memory namespace',
|
|
219
|
+
type: 'string'
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: 'limit',
|
|
223
|
+
short: 'l',
|
|
224
|
+
description: 'Maximum results',
|
|
225
|
+
type: 'number',
|
|
226
|
+
default: 10
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'threshold',
|
|
230
|
+
description: 'Similarity threshold (0-1)',
|
|
231
|
+
type: 'number',
|
|
232
|
+
default: 0.7
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: 'type',
|
|
236
|
+
short: 't',
|
|
237
|
+
description: 'Search type (semantic, keyword, hybrid)',
|
|
238
|
+
type: 'string',
|
|
239
|
+
default: 'semantic',
|
|
240
|
+
choices: ['semantic', 'keyword', 'hybrid']
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: 'build-hnsw',
|
|
244
|
+
description: 'Build/rebuild pure-JS HNSW index before searching',
|
|
245
|
+
type: 'boolean',
|
|
246
|
+
default: false
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
examples: [
|
|
250
|
+
{ command: 'monomind memory search -q "authentication patterns"', description: 'Semantic search' },
|
|
251
|
+
{ command: 'monomind memory search -q "JWT" -t keyword', description: 'Keyword search' },
|
|
252
|
+
{ command: 'monomind memory search -q "test" --build-hnsw', description: 'Build HNSW index and search' }
|
|
253
|
+
],
|
|
254
|
+
action: async (ctx) => {
|
|
255
|
+
const query = ctx.flags.query || ctx.args[0];
|
|
256
|
+
const namespace = ctx.flags.namespace || 'all';
|
|
257
|
+
const limit = ctx.flags.limit || 10;
|
|
258
|
+
const threshold = ctx.flags.threshold || 0.3;
|
|
259
|
+
const searchType = ctx.flags.type || 'semantic';
|
|
260
|
+
const buildHnsw = (ctx.flags['build-hnsw'] || ctx.flags.buildHnsw);
|
|
261
|
+
if (!query) {
|
|
262
|
+
output.printError('Query is required. Use --query or -q');
|
|
263
|
+
return { success: false, exitCode: 1 };
|
|
264
|
+
}
|
|
265
|
+
// Build/rebuild HNSW index if requested
|
|
266
|
+
if (buildHnsw) {
|
|
267
|
+
output.printInfo('Building HNSW index...');
|
|
268
|
+
try {
|
|
269
|
+
const { getHNSWIndex, getHNSWStatus } = await import('../memory/memory-initializer.js');
|
|
270
|
+
const startTime = Date.now();
|
|
271
|
+
const index = await getHNSWIndex({ forceRebuild: true });
|
|
272
|
+
const buildTime = Date.now() - startTime;
|
|
273
|
+
if (index) {
|
|
274
|
+
const status = getHNSWStatus();
|
|
275
|
+
output.printSuccess(`HNSW index built (${status.entryCount} vectors, ${buildTime}ms)`);
|
|
276
|
+
output.writeln(output.dim(` Dimensions: ${status.dimensions}, Metric: cosine`));
|
|
277
|
+
output.writeln(output.dim(` Complexity: O(log n) vs O(n) linear scan`));
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
output.printWarning('HNSW index not available');
|
|
281
|
+
}
|
|
282
|
+
output.writeln();
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
output.printWarning(`HNSW build failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
286
|
+
output.writeln(output.dim(' Falling back to brute-force search'));
|
|
287
|
+
output.writeln();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
output.printInfo(`Searching: "${query}" (${searchType})`);
|
|
291
|
+
output.writeln();
|
|
292
|
+
// Use direct sql.js search with vector similarity
|
|
293
|
+
try {
|
|
294
|
+
const { searchEntries } = await import('../memory/memory-initializer.js');
|
|
295
|
+
const searchResult = await searchEntries({
|
|
296
|
+
query,
|
|
297
|
+
namespace,
|
|
298
|
+
limit,
|
|
299
|
+
threshold
|
|
300
|
+
});
|
|
301
|
+
if (!searchResult.success) {
|
|
302
|
+
output.printError(searchResult.error || 'Search failed');
|
|
303
|
+
return { success: false, exitCode: 1 };
|
|
304
|
+
}
|
|
305
|
+
const results = searchResult.results.map(r => ({
|
|
306
|
+
key: r.key,
|
|
307
|
+
score: r.score,
|
|
308
|
+
namespace: r.namespace,
|
|
309
|
+
preview: r.content
|
|
310
|
+
}));
|
|
311
|
+
if (ctx.flags.format === 'json') {
|
|
312
|
+
output.printJson({ query, searchType, results, searchTime: `${searchResult.searchTime}ms` });
|
|
313
|
+
return { success: true, data: results };
|
|
314
|
+
}
|
|
315
|
+
// Performance stats
|
|
316
|
+
output.writeln(output.dim(` Search time: ${searchResult.searchTime}ms`));
|
|
317
|
+
output.writeln();
|
|
318
|
+
if (results.length === 0) {
|
|
319
|
+
output.printWarning('No results found');
|
|
320
|
+
output.writeln(output.dim('Try: monomind memory store -k "key" --value "data"'));
|
|
321
|
+
return { success: true, data: [] };
|
|
322
|
+
}
|
|
323
|
+
output.printTable({
|
|
324
|
+
columns: [
|
|
325
|
+
{ key: 'key', header: 'Key', width: 20 },
|
|
326
|
+
{ key: 'score', header: 'Score', width: 8, align: 'right', format: (v) => Number(v).toFixed(2) },
|
|
327
|
+
{ key: 'namespace', header: 'Namespace', width: 12 },
|
|
328
|
+
{ key: 'preview', header: 'Preview', width: 35 }
|
|
329
|
+
],
|
|
330
|
+
data: results
|
|
331
|
+
});
|
|
332
|
+
output.writeln();
|
|
333
|
+
output.printInfo(`Found ${results.length} results`);
|
|
334
|
+
return { success: true, data: results };
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
output.printError(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
338
|
+
return { success: false, exitCode: 1 };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
//# sourceMappingURL=memory-crud.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory List Commands
|
|
3
|
+
* formatRelativeTime, listCommand, editCommand, templatesCommand
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from '../types.js';
|
|
6
|
+
export declare function formatRelativeTime(isoDate: string): string;
|
|
7
|
+
export declare const listCommand: Command;
|
|
8
|
+
export declare const editCommand: Command;
|
|
9
|
+
export declare const templatesCommand: Command;
|
|
10
|
+
//# sourceMappingURL=memory-list.d.ts.map
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory List Commands
|
|
3
|
+
* formatRelativeTime, listCommand, editCommand, templatesCommand
|
|
4
|
+
*/
|
|
5
|
+
import { output } from '../output.js';
|
|
6
|
+
import { input } from '../prompt.js';
|
|
7
|
+
// Helper function to format relative time
|
|
8
|
+
export function formatRelativeTime(isoDate) {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
const date = new Date(isoDate).getTime();
|
|
11
|
+
const diff = now - date;
|
|
12
|
+
const seconds = Math.floor(diff / 1000);
|
|
13
|
+
const minutes = Math.floor(seconds / 60);
|
|
14
|
+
const hours = Math.floor(minutes / 60);
|
|
15
|
+
const days = Math.floor(hours / 24);
|
|
16
|
+
if (days > 0)
|
|
17
|
+
return `${days}d ago`;
|
|
18
|
+
if (hours > 0)
|
|
19
|
+
return `${hours}h ago`;
|
|
20
|
+
if (minutes > 0)
|
|
21
|
+
return `${minutes}m ago`;
|
|
22
|
+
return 'just now';
|
|
23
|
+
}
|
|
24
|
+
// List command
|
|
25
|
+
export const listCommand = {
|
|
26
|
+
name: 'list',
|
|
27
|
+
aliases: ['ls'],
|
|
28
|
+
description: 'List memory entries',
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
name: 'namespace',
|
|
32
|
+
short: 'n',
|
|
33
|
+
description: 'Filter by namespace',
|
|
34
|
+
type: 'string'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'tags',
|
|
38
|
+
short: 't',
|
|
39
|
+
description: 'Filter by tags (comma-separated)',
|
|
40
|
+
type: 'string'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'limit',
|
|
44
|
+
short: 'l',
|
|
45
|
+
description: 'Maximum entries',
|
|
46
|
+
type: 'number',
|
|
47
|
+
default: 20
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
action: async (ctx) => {
|
|
51
|
+
const namespace = ctx.flags.namespace;
|
|
52
|
+
const limit = ctx.flags.limit;
|
|
53
|
+
// Use sql.js directly for consistent data access
|
|
54
|
+
try {
|
|
55
|
+
const { listEntries } = await import('../memory/memory-initializer.js');
|
|
56
|
+
const listResult = await listEntries({ namespace, limit, offset: 0 });
|
|
57
|
+
if (!listResult.success) {
|
|
58
|
+
output.printError(`Failed to list: ${listResult.error}`);
|
|
59
|
+
return { success: false, exitCode: 1 };
|
|
60
|
+
}
|
|
61
|
+
// Format entries for display
|
|
62
|
+
const entries = listResult.entries.map(e => ({
|
|
63
|
+
key: e.key,
|
|
64
|
+
namespace: e.namespace,
|
|
65
|
+
size: e.size + ' B',
|
|
66
|
+
vector: e.hasEmbedding ? '✓' : '-',
|
|
67
|
+
accessCount: e.accessCount,
|
|
68
|
+
updated: formatRelativeTime(e.updatedAt)
|
|
69
|
+
}));
|
|
70
|
+
if (ctx.flags.format === 'json') {
|
|
71
|
+
output.printJson(listResult.entries);
|
|
72
|
+
return { success: true, data: listResult.entries };
|
|
73
|
+
}
|
|
74
|
+
output.writeln();
|
|
75
|
+
output.writeln(output.bold('Memory Entries'));
|
|
76
|
+
output.writeln();
|
|
77
|
+
if (entries.length === 0) {
|
|
78
|
+
output.printWarning('No entries found');
|
|
79
|
+
output.printInfo('Store data: monomind memory store -k "key" --value "data"');
|
|
80
|
+
return { success: true, data: [] };
|
|
81
|
+
}
|
|
82
|
+
output.printTable({
|
|
83
|
+
columns: [
|
|
84
|
+
{ key: 'key', header: 'Key', width: 25 },
|
|
85
|
+
{ key: 'namespace', header: 'Namespace', width: 12 },
|
|
86
|
+
{ key: 'size', header: 'Size', width: 10, align: 'right' },
|
|
87
|
+
{ key: 'vector', header: 'Vector', width: 8, align: 'center' },
|
|
88
|
+
{ key: 'accessCount', header: 'Accessed', width: 10, align: 'right' },
|
|
89
|
+
{ key: 'updated', header: 'Updated', width: 12 }
|
|
90
|
+
],
|
|
91
|
+
data: entries
|
|
92
|
+
});
|
|
93
|
+
output.writeln();
|
|
94
|
+
output.printInfo(`Showing ${entries.length} of ${listResult.total} entries`);
|
|
95
|
+
return { success: true, data: listResult.entries };
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
output.printError(`Failed to list: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
99
|
+
return { success: false, exitCode: 1 };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
// Edit command
|
|
104
|
+
export const editCommand = {
|
|
105
|
+
name: 'edit',
|
|
106
|
+
description: 'Edit a memory entry (LanceDB, Memory Palace, or knowledge chunk)',
|
|
107
|
+
options: [
|
|
108
|
+
{ name: 'key', short: 'k', description: 'Storage key', type: 'string' },
|
|
109
|
+
{ name: 'namespace', short: 'n', description: 'Memory namespace', type: 'string', default: 'default' },
|
|
110
|
+
{ name: 'value', description: 'New value/content', type: 'string' },
|
|
111
|
+
{ name: 'source', short: 's', description: 'Source to edit: lancedb, palace, knowledge', type: 'string', default: 'lancedb', choices: ['lancedb', 'palace', 'knowledge'] },
|
|
112
|
+
{ name: 'id', description: 'Entry ID (palace/knowledge)', type: 'string' }
|
|
113
|
+
],
|
|
114
|
+
examples: [
|
|
115
|
+
{ command: 'monomind memory edit -k "pattern/auth" --value "updated content"', description: 'Edit LanceDB entry' },
|
|
116
|
+
{ command: 'monomind memory edit --source palace --id "abc123" --value "new content"', description: 'Edit Memory Palace drawer' },
|
|
117
|
+
{ command: 'monomind memory edit --source knowledge --id "chunk-42" --value "updated"', description: 'Edit knowledge chunk' }
|
|
118
|
+
],
|
|
119
|
+
action: async (ctx) => {
|
|
120
|
+
const source = ctx.flags.source || 'lancedb';
|
|
121
|
+
let value = ctx.flags.value || ctx.args[0];
|
|
122
|
+
const fs = await import('fs');
|
|
123
|
+
const path = await import('path');
|
|
124
|
+
if (source === 'lancedb') {
|
|
125
|
+
const key = ctx.flags.key;
|
|
126
|
+
const namespace = ctx.flags.namespace || 'default';
|
|
127
|
+
if (!key) {
|
|
128
|
+
output.printError('Key is required for lancedb edit. Use --key or -k');
|
|
129
|
+
return { success: false, exitCode: 1 };
|
|
130
|
+
}
|
|
131
|
+
if (!value && ctx.interactive) {
|
|
132
|
+
value = await input({ message: 'Enter new value:', validate: v => v.length > 0 || 'Value required' });
|
|
133
|
+
}
|
|
134
|
+
if (!value) {
|
|
135
|
+
output.printError('Value is required. Use --value');
|
|
136
|
+
return { success: false, exitCode: 1 };
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const { storeEntry } = await import('../memory/memory-initializer.js');
|
|
140
|
+
const result = await storeEntry({ key, value, namespace, generateEmbeddingFlag: true, upsert: true });
|
|
141
|
+
if (!result.success) {
|
|
142
|
+
output.printError(result.error || 'Failed to update');
|
|
143
|
+
return { success: false, exitCode: 1 };
|
|
144
|
+
}
|
|
145
|
+
output.printSuccess(`Updated "${key}" in namespace "${namespace}"`);
|
|
146
|
+
return { success: true, data: result };
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
output.printError(`Failed to edit: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
150
|
+
return { success: false, exitCode: 1 };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// palace or knowledge — JSONL file edit
|
|
154
|
+
const id = ctx.flags.id;
|
|
155
|
+
if (!id) {
|
|
156
|
+
output.printError('Entry ID is required for palace/knowledge edit. Use --id');
|
|
157
|
+
return { success: false, exitCode: 1 };
|
|
158
|
+
}
|
|
159
|
+
if (!/^[a-zA-Z0-9_\-]{1,128}$/.test(id)) {
|
|
160
|
+
output.printError('ID must be 1-128 chars: alphanumeric, underscore, or hyphen only');
|
|
161
|
+
return { success: false, exitCode: 1 };
|
|
162
|
+
}
|
|
163
|
+
const filePath = source === 'palace'
|
|
164
|
+
? path.join(process.cwd(), '.monomind', 'palace', 'drawers.jsonl')
|
|
165
|
+
: path.join(process.cwd(), '.monomind', 'knowledge', 'chunks.jsonl');
|
|
166
|
+
if (!fs.existsSync(filePath)) {
|
|
167
|
+
output.printError(`File not found: ${filePath}`);
|
|
168
|
+
return { success: false, exitCode: 1 };
|
|
169
|
+
}
|
|
170
|
+
const MAX_MEMORY_FILE_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
171
|
+
if (fs.statSync(filePath).size > MAX_MEMORY_FILE_BYTES) {
|
|
172
|
+
output.printError(`Memory file too large (> 50 MB): ${filePath}`);
|
|
173
|
+
return { success: false, exitCode: 1 };
|
|
174
|
+
}
|
|
175
|
+
let entries;
|
|
176
|
+
try {
|
|
177
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
178
|
+
entries = [];
|
|
179
|
+
for (const line of raw.split('\n').filter(Boolean)) {
|
|
180
|
+
try {
|
|
181
|
+
entries.push(JSON.parse(line));
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
output.printError(`Malformed JSONL entry in ${source} file`);
|
|
185
|
+
return { success: false, exitCode: 1 };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
output.printError(`Failed to read ${source} file: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
191
|
+
return { success: false, exitCode: 1 };
|
|
192
|
+
}
|
|
193
|
+
const idx = entries.findIndex(e => e.id === id);
|
|
194
|
+
if (idx === -1) {
|
|
195
|
+
output.printWarning(`Entry not found with id "${id}"`);
|
|
196
|
+
return { success: false, exitCode: 1 };
|
|
197
|
+
}
|
|
198
|
+
if (!value && ctx.interactive) {
|
|
199
|
+
output.writeln(output.dim('Current content:'));
|
|
200
|
+
output.writeln(entries[idx].content || '(empty)');
|
|
201
|
+
output.writeln();
|
|
202
|
+
value = await input({ message: 'Enter new content:', validate: v => v.length > 0 || 'Content required' });
|
|
203
|
+
}
|
|
204
|
+
if (!value) {
|
|
205
|
+
output.printError('Value is required. Use --value');
|
|
206
|
+
return { success: false, exitCode: 1 };
|
|
207
|
+
}
|
|
208
|
+
entries[idx] = { ...entries[idx], content: value, ts: new Date().toISOString() };
|
|
209
|
+
try {
|
|
210
|
+
const tmpPath = filePath + '.tmp';
|
|
211
|
+
fs.writeFileSync(tmpPath, entries.map(e => JSON.stringify(e)).join('\n') + '\n');
|
|
212
|
+
fs.renameSync(tmpPath, filePath);
|
|
213
|
+
output.printSuccess(`Updated ${source} entry "${id}"`);
|
|
214
|
+
return { success: true, data: entries[idx] };
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
output.printError(`Failed to write ${source} file: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
218
|
+
return { success: false, exitCode: 1 };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
// Templates command
|
|
223
|
+
export const templatesCommand = {
|
|
224
|
+
name: 'templates',
|
|
225
|
+
description: 'Show best-practice templates for memory entries',
|
|
226
|
+
options: [
|
|
227
|
+
{ name: 'type', short: 't', description: 'Template type: user, feedback, project, reference', type: 'string', choices: ['user', 'feedback', 'project', 'reference'] }
|
|
228
|
+
],
|
|
229
|
+
examples: [
|
|
230
|
+
{ command: 'monomind memory templates', description: 'Show all templates' },
|
|
231
|
+
{ command: 'monomind memory templates -t feedback', description: 'Show feedback template only' }
|
|
232
|
+
],
|
|
233
|
+
action: async (ctx) => {
|
|
234
|
+
const filter = ctx.flags.type;
|
|
235
|
+
const templates = {
|
|
236
|
+
user: {
|
|
237
|
+
label: 'User Memory',
|
|
238
|
+
description: 'Role, goals, preferences, knowledge level',
|
|
239
|
+
example: [
|
|
240
|
+
'---',
|
|
241
|
+
'name: user_role',
|
|
242
|
+
'description: <one-line summary of user role and context>',
|
|
243
|
+
'type: user',
|
|
244
|
+
'---',
|
|
245
|
+
'',
|
|
246
|
+
'<Role and experience description. What does the user know well? What are they new to?>',
|
|
247
|
+
'Frame explanations accordingly.'
|
|
248
|
+
].join('\n')
|
|
249
|
+
},
|
|
250
|
+
feedback: {
|
|
251
|
+
label: 'Feedback Memory',
|
|
252
|
+
description: 'How to approach work — corrections and validated choices',
|
|
253
|
+
example: [
|
|
254
|
+
'---',
|
|
255
|
+
'name: feedback_<topic>',
|
|
256
|
+
'description: <one-line rule that triggers on lookup>',
|
|
257
|
+
'type: feedback',
|
|
258
|
+
'---',
|
|
259
|
+
'',
|
|
260
|
+
'<The rule itself — what to do or avoid.>',
|
|
261
|
+
'',
|
|
262
|
+
'**Why:** <Reason the user gave — past incident, strong preference, etc.>',
|
|
263
|
+
'',
|
|
264
|
+
'**How to apply:** <When does this kick in? What edge cases does it cover?>'
|
|
265
|
+
].join('\n')
|
|
266
|
+
},
|
|
267
|
+
project: {
|
|
268
|
+
label: 'Project Memory',
|
|
269
|
+
description: 'Ongoing work context, goals, decisions, deadlines',
|
|
270
|
+
example: [
|
|
271
|
+
'---',
|
|
272
|
+
'name: project_<initiative>',
|
|
273
|
+
'description: <one-line fact about the project decision or constraint>',
|
|
274
|
+
'type: project',
|
|
275
|
+
'---',
|
|
276
|
+
'',
|
|
277
|
+
'<The fact or decision — what is happening and what was decided.>',
|
|
278
|
+
'',
|
|
279
|
+
'**Why:** <Motivation — constraint, deadline, stakeholder ask, compliance issue.>',
|
|
280
|
+
'',
|
|
281
|
+
'**How to apply:** <How should this shape future suggestions and decisions?>'
|
|
282
|
+
].join('\n')
|
|
283
|
+
},
|
|
284
|
+
reference: {
|
|
285
|
+
label: 'Reference Memory',
|
|
286
|
+
description: 'Pointers to external resources and where to find information',
|
|
287
|
+
example: [
|
|
288
|
+
'---',
|
|
289
|
+
'name: reference_<resource>',
|
|
290
|
+
'description: <what this resource contains and when to use it>',
|
|
291
|
+
'type: reference',
|
|
292
|
+
'---',
|
|
293
|
+
'',
|
|
294
|
+
'<Resource name and location (URL, project name, channel, etc.)>',
|
|
295
|
+
'',
|
|
296
|
+
'Use this when: <specific scenarios where this reference is relevant>.'
|
|
297
|
+
].join('\n')
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
output.writeln();
|
|
301
|
+
output.writeln(output.bold('Memory Entry Templates'));
|
|
302
|
+
output.writeln(output.dim('Best-practice scaffolds for .claude/projects/.../memory/ entries'));
|
|
303
|
+
output.writeln();
|
|
304
|
+
const keys = filter ? [filter] : Object.keys(templates);
|
|
305
|
+
for (const key of keys) {
|
|
306
|
+
const t = templates[key];
|
|
307
|
+
if (!t) {
|
|
308
|
+
output.printError(`Unknown type: "${key}". Valid types: user, feedback, project, reference`);
|
|
309
|
+
return { success: false, exitCode: 1 };
|
|
310
|
+
}
|
|
311
|
+
output.writeln(output.bold(`── ${t.label} (--type ${key})`));
|
|
312
|
+
output.writeln(output.dim(` ${t.description}`));
|
|
313
|
+
output.writeln();
|
|
314
|
+
output.writeln(t.example);
|
|
315
|
+
output.writeln();
|
|
316
|
+
}
|
|
317
|
+
output.writeln(output.dim('Save with: monomind memory store -k "<name>" --value "<content>" --namespace auto-memory'));
|
|
318
|
+
return { success: true };
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
//# sourceMappingURL=memory-list.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Transfer Commands
|
|
3
|
+
* compressCommand, exportCommand, importCommand
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from '../types.js';
|
|
6
|
+
export declare const compressCommand: Command;
|
|
7
|
+
export declare const exportCommand: Command;
|
|
8
|
+
export declare const importCommand: Command;
|
|
9
|
+
//# sourceMappingURL=memory-transfer.d.ts.map
|