@yamo/memory-mesh 3.1.4 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/memory_mesh.js +107 -186
  2. package/package.json +5 -2
@@ -1,23 +1,36 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * YAMO MemoryMesh CLI - Protocol-Native Edition (v3.1.0)
4
+ * YAMO MemoryMesh CLI - Singularity Edition (v3.2.0)
5
5
  *
6
- * Enforces the "Zero JSON" mandate by using standard CLI flags.
7
- * Machines don't parse YAMO; they execute commands.
6
+ * State-of-the-art interface for semantic memory orchestration.
7
+ * Features: Interactive progress, beautiful formatting, and bulk ingestion.
8
8
  */
9
9
 
10
10
  import { Command } from 'commander';
11
11
  import { MemoryMesh } from '../lib/memory/index.js';
12
12
  import { createLogger } from '../lib/utils/logger.js';
13
+ import pc from 'picocolors';
14
+ import cliProgress from 'cli-progress';
15
+ import fs from 'fs';
16
+ import path from 'path';
17
+ import { glob } from 'glob';
13
18
 
14
- const logger = createLogger('memory-mesh-cli');
15
19
  const program = new Command();
16
20
 
17
21
  program
18
22
  .name('memory-mesh')
19
- .description('Portable semantic memory subconscious for YAMO agents')
20
- .version('3.1.0');
23
+ .description('YAMO Semantic Subconscious - Protocol-Native CLI')
24
+ .version('3.2.0');
25
+
26
+ // Helper for beautiful logging
27
+ const ui = {
28
+ info: (msg) => console.log(`${pc.blue('ℹ')} ${pc.white(msg)}`),
29
+ success: (msg) => console.log(`${pc.green('✔')} ${pc.green(msg)}`),
30
+ warn: (msg) => console.log(`${pc.yellow('⚠')} ${pc.yellow(msg)}`),
31
+ error: (msg) => console.error(`${pc.red('✖')} ${pc.red(msg)}`),
32
+ header: (msg) => console.log(`\n${pc.bold(pc.cyan('── ' + msg + ' ' + '─'.repeat(50 - msg.length - 4)))}\n`)
33
+ };
21
34
 
22
35
  // 1. Store/Ingest Command
23
36
  program
@@ -28,83 +41,89 @@ program
28
41
  .option('-t, --type <type>', 'Memory type (e.g., insight, decision, error)', 'event')
29
42
  .option('-r, --rationale <text>', 'The constitutional rationale for this memory')
30
43
  .option('-h, --hypothesis <text>', 'The associated hypothesis')
31
- .option('--metadata <json>', 'Additional metadata (as flat flags or optional JSON)', '{}')
32
44
  .action(async (options) => {
33
45
  const mesh = new MemoryMesh();
34
46
  try {
35
- let metadata = {};
36
- try {
37
- metadata = JSON.parse(options.metadata);
38
- } catch (_e) {
39
- // Fallback to empty if invalid JSON
40
- }
41
-
42
- if (options.type) metadata.type = options.type;
43
- if (options.rationale) metadata.rationale = options.rationale;
44
- if (options.hypothesis) metadata.hypothesis = options.hypothesis;
47
+ ui.info(`Ingesting into subconscious...`);
48
+ const metadata = {
49
+ type: options.type,
50
+ rationale: options.rationale,
51
+ hypothesis: options.hypothesis,
52
+ source: 'cli-manual'
53
+ };
45
54
 
46
55
  const record = await mesh.add(options.content, metadata);
47
- process.stdout.write(`[MemoryMesh] Ingested record ${record.id}\n`);
56
+ ui.success(`Ingested record ${pc.bold(record.id)}`);
48
57
  } catch (err) {
49
- console.error(`❌ Error: ${err.message}`);
58
+ ui.error(`Ingestion failed: ${err.message}`);
50
59
  process.exit(1);
51
60
  } finally {
52
61
  await mesh.close();
53
62
  }
54
63
  });
55
64
 
56
- // 2. Directory Ingest Command
65
+ // 2. Pull Command (Smart Directory Ingest)
57
66
  program
58
- .command('ingest-dir')
59
- .alias('pull')
60
- .description('Recursively ingest a directory of files (Smart Ingest)')
61
- .argument('<path>', 'Directory path to ingest')
62
- .option('-e, --extension <ext>', 'Filter by file extension', '')
67
+ .command('pull')
68
+ .description('Smart recursive repository/directory ingestion')
69
+ .argument('<path>', 'Directory path to pull')
70
+ .option('-e, --extension <ext>', 'File extensions (comma-separated)', '.yamo,.md')
63
71
  .option('-t, --type <type>', 'Memory type', 'documentation')
64
- .option('-r, --recursive', 'Ingest subdirectories', true)
65
72
  .action(async (dirPath, options) => {
66
73
  const mesh = new MemoryMesh();
67
74
  try {
75
+ ui.header(`Pulling Wisdom: ${dirPath}`);
76
+
68
77
  const absolutePath = path.resolve(dirPath);
69
78
  if (!fs.existsSync(absolutePath)) {
70
79
  throw new Error(`Directory not found: ${absolutePath}`);
71
80
  }
72
81
 
73
- const files = [];
74
- const walk = (dir) => {
75
- const entries = fs.readdirSync(dir, { withFileTypes: true });
76
- for (const entry of entries) {
77
- const fullPath = path.join(dir, entry.name);
78
- if (entry.isDirectory() && options.recursive) {
79
- walk(fullPath);
80
- } else if (entry.isFile()) {
81
- if (!options.extension || entry.name.endsWith(options.extension)) {
82
- files.push(fullPath);
83
- }
84
- }
85
- }
86
- };
82
+ // 1. Discover files
83
+ const extensions = options.extension.split(',').map(e => e.trim());
84
+ const pattern = `**/*{${extensions.join(',')}}`;
85
+
86
+ ui.info(`Scanning for ${pc.cyan(extensions.join(' ')) } files...`);
87
+
88
+ const files = await glob(pattern, { cwd: absolutePath, absolute: true, nodir: true });
89
+
90
+ if (files.length === 0) {
91
+ ui.warn('No matching files found.');
92
+ return;
93
+ }
87
94
 
88
- walk(absolutePath);
89
- process.stdout.write(`[MemoryMesh] Found ${files.length} files to ingest...\n`);
95
+ ui.info(`Found ${pc.bold(files.length)} files. Starting bulk ingestion...`);
90
96
 
97
+ // 2. Initialize Progress Bar
98
+ const bar = new cliProgress.SingleBar({
99
+ format: `${pc.cyan('Ingesting')} |${pc.cyan('{bar}')}| {percentage}% | {value}/{total} Files | {file}`,
100
+ barCompleteChar: '\u2588',
101
+ barIncompleteChar: '\u2591',
102
+ hideCursor: true
103
+ }, cliProgress.Presets.shades_classic);
104
+
105
+ bar.start(files.length, 0, { file: 'Initializing...' });
106
+
107
+ // 3. Process
91
108
  for (const file of files) {
109
+ const relativeName = path.relative(absolutePath, file);
110
+ bar.update(files.indexOf(file) + 1, { file: relativeName });
111
+
92
112
  const content = fs.readFileSync(file, 'utf-8');
93
113
  if (!content.trim()) continue;
94
114
 
95
- const metadata = {
96
- source: path.relative(process.cwd(), file),
97
- ingested_at: new Date().toISOString(),
98
- type: options.type
99
- };
100
-
101
- const record = await mesh.add(content, metadata);
102
- process.stdout.write(` ✓ Ingested: ${metadata.source} (${record.id})\n`);
115
+ await mesh.add(content, {
116
+ source: relativeName,
117
+ type: options.type,
118
+ ingest_method: 'smart-pull'
119
+ });
103
120
  }
104
121
 
105
- process.stdout.write(`[MemoryMesh] Completed bulk ingestion of ${files.length} files.\n`);
122
+ bar.stop();
123
+ ui.success(`Successfully distilled ${pc.bold(files.length)} files into memory.`);
124
+
106
125
  } catch (err) {
107
- console.error(`❌ Error: ${err.message}`);
126
+ ui.error(`Pull failed: ${err.message}`);
108
127
  process.exit(1);
109
128
  } finally {
110
129
  await mesh.close();
@@ -114,159 +133,61 @@ program
114
133
  // 3. Search Command
115
134
  program
116
135
  .command('search')
117
- .description('Perform semantic recall')
118
- .argument('<query>', 'The semantic search query')
119
- .option('-l, --limit <number>', 'Number of results', '10')
120
- .option('-f, --filter <string>', 'LanceDB SQL-style filter')
136
+ .description('Perform high-fidelity semantic recall')
137
+ .argument('<query>', 'The semantic query')
138
+ .option('-l, --limit <number>', 'Number of results', '5')
121
139
  .action(async (query, options) => {
122
140
  const mesh = new MemoryMesh();
123
141
  try {
124
- const results = await mesh.search(query, {
125
- limit: parseInt(options.limit),
126
- filter: options.filter || null
142
+ ui.info(`Searching subconscious for "${pc.italic(query)}"...`);
143
+ const results = await mesh.search(query, { limit: parseInt(options.limit) });
144
+
145
+ if (results.length === 0) {
146
+ ui.warn('No relevant memories found.');
147
+ return;
148
+ }
149
+
150
+ ui.header(`Recalled ${results.length} Memories`);
151
+
152
+ results.forEach((res, i) => {
153
+ const meta = typeof res.metadata === 'string' ? JSON.parse(res.metadata) : res.metadata;
154
+ const scoreColor = res.score > 0.8 ? pc.green : (res.score > 0.5 ? pc.yellow : pc.red);
155
+
156
+ console.log(`${pc.bold(pc.cyan('Memory ' + (i + 1)))} [Rel: ${scoreColor(res.score.toFixed(2))}]`);
157
+ console.log(`${pc.dim('ID: ' + res.id)} | ${pc.dim('Type: ' + (meta.type || 'event'))}`);
158
+ console.log(`${pc.white(res.content.substring(0, 300))}${res.content.length > 300 ? '...' : ''}`);
159
+ console.log(pc.dim('─'.repeat(40)));
127
160
  });
128
161
 
129
- process.stdout.write(`[MemoryMesh] Found ${results.length} matches.\n`);
130
- process.stdout.write(mesh.formatResults(results));
131
- process.stdout.write('\n');
132
162
  } catch (err) {
133
- console.error(`❌ Error: ${err.message}`);
163
+ ui.error(`Search failed: ${err.message}`);
134
164
  process.exit(1);
135
165
  } finally {
136
166
  await mesh.close();
137
167
  }
138
168
  });
139
169
 
140
- // 3. Stats Command
170
+ // 4. Stats Command
141
171
  program
142
172
  .command('stats')
143
- .description('Get database health and statistics')
173
+ .description('Subconscious health and database metrics')
144
174
  .action(async () => {
145
175
  const mesh = new MemoryMesh();
146
176
  try {
147
177
  const stats = await mesh.stats();
148
- process.stdout.write(`[MemoryMesh] Total Memories: ${stats.count}\n`);
149
- process.stdout.write(`[MemoryMesh] DB Path: ${stats.uri}\n`);
150
- process.stdout.write(`[MemoryMesh] Status: ${stats.isConnected ? 'Connected' : 'Disconnected'}\n`);
151
- } catch (err) {
152
- console.error(`❌ Error: ${err.message}`);
153
- process.exit(1);
154
- } finally {
155
- await mesh.close();
156
- }
157
- });
158
-
159
- // 4. Get Command
160
- program
161
- .command('get')
162
- .description('Retrieve a single memory by ID')
163
- .requiredOption('--id <id>', 'Memory record ID')
164
- .action(async (options) => {
165
- const mesh = new MemoryMesh();
166
- try {
167
- await mesh.init();
168
- const record = await mesh.get(options.id);
169
- if (!record) {
170
- process.stdout.write(`[MemoryMesh] No record found with id: ${options.id}\n`);
171
- process.exit(1);
172
- }
173
- const meta = typeof record.metadata === 'string' ? JSON.parse(record.metadata) : record.metadata;
174
- process.stdout.write(`[MemoryMesh] id: ${record.id}\n`);
175
- process.stdout.write(`[MemoryMesh] content: ${record.content}\n`);
176
- process.stdout.write(`[MemoryMesh] type: ${meta?.type ?? 'unknown'}\n`);
177
- process.stdout.write(`[MemoryMesh] created_at: ${record.created_at}\n`);
178
- process.stdout.write(`[MemoryMesh] metadata: ${JSON.stringify(meta, null, 2)}\n`);
179
- } catch (err) {
180
- console.error(`❌ Error: ${err.message}`);
181
- process.exit(1);
182
- } finally {
183
- await mesh.close();
184
- }
185
- });
186
-
187
- // 5. Delete Command
188
- program
189
- .command('delete')
190
- .description('Delete a memory by ID')
191
- .requiredOption('--id <id>', 'Memory record ID to delete')
192
- .action(async (options) => {
193
- const mesh = new MemoryMesh();
194
- try {
195
- await mesh.init();
196
- await mesh.delete(options.id);
197
- process.stdout.write(`[MemoryMesh] Deleted record ${options.id}\n`);
198
- } catch (err) {
199
- console.error(`❌ Error: ${err.message}`);
200
- process.exit(1);
201
- } finally {
202
- await mesh.close();
203
- }
204
- });
205
-
206
- // 6. Reflect Command
207
- program
208
- .command('reflect')
209
- .description('Query distilled lessons from memory (wisdom distillation)')
210
- .option('--topic <text>', 'Topic or query to reflect on', '')
211
- .option('--lookback <n>', 'Limit results to this many lessons', '10')
212
- .action(async (options) => {
213
- const mesh = new MemoryMesh();
214
- try {
215
- await mesh.init();
216
- const query = options.topic || 'lessons learned patterns errors fixes';
217
- const limit = parseInt(options.lookback) || 10;
218
- const lessons = await mesh.queryLessons(query, { limit });
219
- if (lessons.length === 0) {
220
- process.stdout.write(`[MemoryMesh] No lessons found${options.topic ? ` for topic: ${options.topic}` : ''}.\n`);
221
- } else {
222
- process.stdout.write(`[MemoryMesh] Reflecting on ${lessons.length} lesson(s):\n\n`);
223
- for (const lesson of lessons) {
224
- process.stdout.write(` scope: ${lesson.applicableScope}\n`);
225
- process.stdout.write(` rule: ${lesson.preventativeRule}\n`);
226
- process.stdout.write(` confidence: ${lesson.ruleConfidence}\n`);
227
- process.stdout.write('\n');
228
- }
229
- }
230
- } catch (err) {
231
- console.error(`❌ Error: ${err.message}`);
232
- process.exit(1);
233
- } finally {
234
- await mesh.close();
235
- }
236
- });
237
-
238
- // S-MORA command (RFC-0012)
239
- program
240
- .command('smora')
241
- .description('S-MORA enhanced retrieval: HyDE-Lite + multi-channel + heritage-aware reranking (RFC-0012)')
242
- .argument('<query>', 'The retrieval query')
243
- .option('-l, --limit <n>', 'Max results to return', '10')
244
- .option('--no-hyde', 'Disable HyDE-Lite query expansion (Layer 1)')
245
- .option('--intent <items>', 'Session intent chain for heritage bonus (comma-separated)', '')
246
- .option('--json', 'Output raw JSON response')
247
- .action(async (query, options) => {
248
- const mesh = new MemoryMesh();
249
- try {
250
- await mesh.init();
251
- const sessionIntent = options.intent
252
- ? options.intent.split(',').map((s) => s.trim()).filter(Boolean)
253
- : [];
254
- const resp = await mesh.smora(query, {
255
- limit: parseInt(options.limit) || 10,
256
- enableHyDE: options.hyde !== false,
257
- sessionIntent,
258
- });
259
- if (options.json) {
260
- process.stdout.write(JSON.stringify(resp, null, 2) + '\n');
261
- } else {
262
- const p = resp.pipeline;
263
- process.stdout.write(`[S-MORA] ${resp.results.length} result(s) | HyDE:${p.queryExpanded} heritage:${p.heritageAware} latency:${p.latencyMs}ms\n\n`);
264
- for (const r of resp.results) {
265
- process.stdout.write(` [${r.rrfRank}] score:${r.score.toFixed(3)} | ${r.content.slice(0, 100)}${r.content.length > 100 ? '...' : ''}\n`);
266
- }
267
- }
178
+ ui.header('MemoryMesh Subconscious Status');
179
+
180
+ const statusColor = stats.isConnected ? pc.green : pc.red;
181
+
182
+ console.log(`${pc.bold('Status:')} ${statusColor(stats.isConnected ? 'CONNECTED' : 'DISCONNECTED')}`);
183
+ console.log(`${pc.bold('Memories:')} ${pc.cyan(stats.count)} entries`);
184
+ console.log(`${pc.bold('Skills:')} ${pc.cyan(stats.totalSkills)} synthesized`);
185
+ console.log(`${pc.bold('Engine:')} LanceDB (Vector Index)`);
186
+ console.log(`${pc.bold('Model:')} ${pc.dim(stats.embedding.primary?.modelName || 'Unknown')}`);
187
+ console.log(`${pc.bold('Path:')} ${pc.dim(stats.uri)}`);
188
+
268
189
  } catch (err) {
269
- console.error(`❌ Error: ${err.message}`);
190
+ ui.error(`Stats failed: ${err.message}`);
270
191
  process.exit(1);
271
192
  } finally {
272
193
  await mesh.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yamo/memory-mesh",
3
- "version": "3.1.4",
3
+ "version": "3.2.0",
4
4
  "description": "Portable semantic memory system with Layer 0 Scrubber for YAMO agents (v3 Singularity Edition)",
5
5
  "type": "module",
6
6
  "main": "lib/memory/index.js",
@@ -29,7 +29,10 @@
29
29
  "commander": "^14.0.3",
30
30
  "onnxruntime-node": "^1.18.0",
31
31
  "pino": "^10.3.1",
32
- "pino-pretty": "^13.1.3"
32
+ "pino-pretty": "^13.1.3",
33
+ "cli-progress": "^3.12.0",
34
+ "picocolors": "^1.1.1",
35
+ "glob": "^11.0.1"
33
36
  },
34
37
  "author": "Soverane Labs",
35
38
  "license": "MIT",