@yamo/memory-mesh 2.0.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/bin/memory_mesh.js +69 -0
  4. package/bin/scrubber.js +81 -0
  5. package/index.d.ts +111 -0
  6. package/lib/adapters/index.js +3 -0
  7. package/lib/embeddings/factory.js +150 -0
  8. package/lib/embeddings/index.js +2 -0
  9. package/lib/embeddings/service.js +586 -0
  10. package/lib/index.js +18 -0
  11. package/lib/lancedb/client.js +631 -0
  12. package/lib/lancedb/config.js +215 -0
  13. package/lib/lancedb/errors.js +144 -0
  14. package/lib/lancedb/index.js +4 -0
  15. package/lib/lancedb/schema.js +197 -0
  16. package/lib/memory/index.js +3 -0
  17. package/lib/memory/memory-context-manager.js +388 -0
  18. package/lib/memory/memory-mesh.js +910 -0
  19. package/lib/memory/memory-translator.js +130 -0
  20. package/lib/memory/migrate-memory.js +227 -0
  21. package/lib/memory/migrate-to-v2.js +120 -0
  22. package/lib/memory/scorer.js +85 -0
  23. package/lib/memory/vector-memory.js +364 -0
  24. package/lib/privacy/audit-logger.js +176 -0
  25. package/lib/privacy/dlp-redactor.js +72 -0
  26. package/lib/privacy/index.js +10 -0
  27. package/lib/reporting/skill-report-generator.js +283 -0
  28. package/lib/scrubber/.gitkeep +1 -0
  29. package/lib/scrubber/config/defaults.js +62 -0
  30. package/lib/scrubber/errors/scrubber-error.js +43 -0
  31. package/lib/scrubber/index.js +25 -0
  32. package/lib/scrubber/scrubber.js +130 -0
  33. package/lib/scrubber/stages/chunker.js +103 -0
  34. package/lib/scrubber/stages/metadata-annotator.js +74 -0
  35. package/lib/scrubber/stages/normalizer.js +59 -0
  36. package/lib/scrubber/stages/semantic-filter.js +61 -0
  37. package/lib/scrubber/stages/structural-cleaner.js +82 -0
  38. package/lib/scrubber/stages/validator.js +66 -0
  39. package/lib/scrubber/telemetry.js +66 -0
  40. package/lib/scrubber/utils/hash.js +39 -0
  41. package/lib/scrubber/utils/html-parser.js +45 -0
  42. package/lib/scrubber/utils/pattern-matcher.js +63 -0
  43. package/lib/scrubber/utils/token-counter.js +31 -0
  44. package/lib/search/filter.js +275 -0
  45. package/lib/search/hybrid.js +137 -0
  46. package/lib/search/index.js +3 -0
  47. package/lib/search/pattern-miner.js +160 -0
  48. package/lib/utils/error-sanitizer.js +84 -0
  49. package/lib/utils/handoff-validator.js +85 -0
  50. package/lib/utils/index.js +4 -0
  51. package/lib/utils/spinner.js +190 -0
  52. package/lib/utils/streaming-client.js +128 -0
  53. package/package.json +39 -0
  54. package/skills/SKILL.md +462 -0
  55. package/skills/skill-scrubber.yamo +41 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YAMO Protocol
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # MemoryMesh
2
+
3
+ Portable, semantic memory system for AI agents with automatic Layer 0 sanitization.
4
+
5
+ ## Features
6
+
7
+ - **Persistent Vector Storage**: Powered by LanceDB.
8
+ - **Layer 0 Scrubber**: Automatically sanitizes, deduplicates, and cleans content.
9
+ - **Local Embeddings**: Runs 100% locally using ONNX (no API keys required).
10
+ - **Portable CLI**: Simple JSON-based interface for any agent or language.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @yamo/memory-mesh
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### CLI
21
+
22
+ ```bash
23
+ # Store a memory (automatically scrubbed & embedded)
24
+ memory-mesh store "My important memory" '{"tag":"test"}'
25
+
26
+ # Search memories
27
+ memory-mesh search "query" 5
28
+
29
+ # Scrub content only
30
+ scrubber scrub "Raw text content"
31
+ ```
32
+
33
+ ### Node.js API
34
+
35
+ ```javascript
36
+ import { MemoryMesh } from '@yamo/memory-mesh';
37
+
38
+ const mesh = new MemoryMesh();
39
+ await mesh.add('Content', { meta: 'data' });
40
+ const results = await mesh.search('query');
41
+ ```
42
+
43
+ ## Using in a Project
44
+
45
+ To use MemoryMesh with your Claude Code skills (like `yamo-super`) in a new project:
46
+
47
+ ### 1. Install the Package
48
+ This installs the heavy dependencies (LanceDB, ONNX) and binaries.
49
+
50
+ ```bash
51
+ npm install @yamo/memory-mesh
52
+ # Or install locally if developing:
53
+ # npm install /path/to/memory-mesh
54
+ ```
55
+
56
+ ### 2. Setup the CLI Adapter
57
+ YAMO skills learn how to use the memory system by reading the source code of the CLI adapter. You must ensure `tools/memory_mesh.js` exists in your project so the agent can "see" the interface.
58
+
59
+ **Quick Setup:**
60
+ ```bash
61
+ mkdir -p tools
62
+ cp node_modules/@yamo/memory-mesh/bin/memory_mesh.js tools/memory_mesh.js
63
+ ```
64
+
65
+ ### 3. Run Your Skill
66
+ Your `yamo-super` skill (or any skill referencing `memory_script;tools/memory_mesh.js`) will now work automatically.
67
+
68
+ ```bash
69
+ claude "Run yamo-super task='Setup CI pipeline'"
70
+ ```
71
+
72
+ The agent will read `tools/memory_mesh.js`, understand how to call it, and execute memory operations which are handled by the installed `@yamo/memory-mesh` package.
73
+
74
+ ## Docker
75
+
76
+ ```bash
77
+ docker run -v $(pwd)/data:/app/runtime/data \
78
+ yamo/memory-mesh store "Content"
79
+ ```
80
+
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MemoryMesh CLI Adapter
5
+ * Provides a portable interface for skills to interact with the MemoryMesh system.
6
+ *
7
+ * Usage:
8
+ * node tools/memory_mesh.js store <content_string_or_json> [metadata_json]
9
+ * node tools/memory_mesh.js search <query_string> [limit]
10
+ */
11
+
12
+ import { MemoryMesh } from '../lib/memory/memory-mesh.js';
13
+ import path from 'path';
14
+
15
+ // Parse arguments
16
+ const args = process.argv.slice(2);
17
+ const command = args[0];
18
+
19
+ async function main() {
20
+ try {
21
+ const mesh = new MemoryMesh();
22
+ // Wait for initialization if necessary (MemoryMesh constructor usually doesn't await,
23
+ // but operations might need internal init. We assume standard usage.)
24
+
25
+ if (command === 'store') {
26
+ const content = args[1];
27
+ let metadata = {};
28
+ if (args[2]) {
29
+ try {
30
+ metadata = JSON.parse(args[2]);
31
+ } catch (e) {
32
+ console.error(JSON.stringify({ error: "Invalid metadata JSON" }));
33
+ process.exit(1);
34
+ }
35
+ }
36
+
37
+ if (!content) {
38
+ console.error(JSON.stringify({ error: "Content required for store command" }));
39
+ process.exit(1);
40
+ }
41
+
42
+ const result = await mesh.add(content, metadata);
43
+ console.log(JSON.stringify({ success: true, id: result.id, message: "Memory stored successfully" }));
44
+
45
+ } else if (command === 'search') {
46
+ const query = args[1];
47
+ const limit = parseInt(args[2]) || 5;
48
+
49
+ if (!query) {
50
+ console.error(JSON.stringify({ error: "Query required for search command" }));
51
+ process.exit(1);
52
+ }
53
+
54
+ const results = await mesh.search(query, { limit });
55
+ console.log(JSON.stringify({ success: true, results: results }));
56
+
57
+ } else {
58
+ console.error(JSON.stringify({ error: `Unknown command: ${command}` }));
59
+ console.error("Usage: node tools/memory_mesh.js [store|search] ...");
60
+ process.exit(1);
61
+ }
62
+
63
+ } catch (error) {
64
+ console.error(JSON.stringify({ error: error.message }));
65
+ process.exit(1);
66
+ }
67
+ }
68
+
69
+ main();
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Scrubber CLI Tool
5
+ *
6
+ * A portable CLI wrapper for the S-MORA Layer 0 Scrubber.
7
+ * Sanitizes, deduplicates, and cleans text content.
8
+ *
9
+ * Usage:
10
+ * node tools/scrubber.js scrub "some text content"
11
+ * node tools/scrubber.js scrub-file path/to/file.md
12
+ *
13
+ * Output:
14
+ * JSON object with { success, cleaned_content, metadata }
15
+ */
16
+
17
+ import { Scrubber } from '../lib/smora/scrubber/scrubber.js';
18
+ import fs from 'fs';
19
+ import path from 'path';
20
+
21
+ const args = process.argv.slice(2);
22
+ const command = args[0];
23
+ const input = args[1];
24
+
25
+ async function main() {
26
+ // Initialize with default aggressive cleaning
27
+ const scrubber = new Scrubber({
28
+ enabled: true,
29
+ structural: { stripHTML: true, normalizeMarkdown: true },
30
+ semantic: { removeBoilerplate: true },
31
+ chunking: { minTokens: 1 } // Allow short inputs
32
+ });
33
+
34
+ try {
35
+ let content = '';
36
+ let source = 'cli-input';
37
+ let type = 'txt';
38
+
39
+ if (command === 'scrub') {
40
+ if (!input) throw new Error('Content argument required');
41
+ content = input;
42
+ } else if (command === 'scrub-file') {
43
+ if (!input) throw new Error('File path argument required');
44
+ if (!fs.existsSync(input)) throw new Error(`File not found: ${input}`);
45
+ content = fs.readFileSync(input, 'utf8');
46
+ source = path.basename(input);
47
+ type = path.extname(input).replace('.', '') || 'txt';
48
+ } else {
49
+ console.error(JSON.stringify({ error: `Unknown command: ${command}` }));
50
+ console.error('Usage: node tools/scrubber.js [scrub|scrub-file] <input>');
51
+ process.exit(1);
52
+ }
53
+
54
+ const result = await scrubber.process({
55
+ content,
56
+ source,
57
+ type
58
+ });
59
+
60
+ // Reassemble chunks for simple return
61
+ const cleanedContent = result.chunks.map(c => c.text).join('\n\n');
62
+
63
+ console.log(JSON.stringify({
64
+ success: true,
65
+ original_length: content.length,
66
+ cleaned_length: cleanedContent.length,
67
+ cleaned_content: cleanedContent,
68
+ chunks: result.chunks.length,
69
+ metadata: result.metadata
70
+ }));
71
+
72
+ } catch (error) {
73
+ console.error(JSON.stringify({
74
+ success: false,
75
+ error: error.message
76
+ }));
77
+ process.exit(1);
78
+ }
79
+ }
80
+
81
+ main();
package/index.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ export declare class MemoryMesh {
2
+ constructor();
3
+ init(): Promise<void>;
4
+ add(content: string, metadata?: Record<string, any>): Promise<{
5
+ id: string;
6
+ content: string;
7
+ metadata: Record<string, any>;
8
+ created_at: string;
9
+ }>;
10
+ addBatch(entries: Array<{
11
+ content: string;
12
+ metadata?: Record<string, any>;
13
+ }>): Promise<{
14
+ count: number;
15
+ success: boolean;
16
+ ids: string[];
17
+ }>;
18
+ search(query: string, options?: {
19
+ limit?: number;
20
+ filter?: string;
21
+ useCache?: boolean;
22
+ }): Promise<Array<{
23
+ id: string;
24
+ content: string;
25
+ metadata: Record<string, any>;
26
+ score: number;
27
+ created_at: string;
28
+ }>>;
29
+ get(id: string): Promise<{
30
+ id: string;
31
+ content: string;
32
+ metadata: Record<string, any>;
33
+ created_at: string;
34
+ updated_at: string;
35
+ } | null>;
36
+ getAll(options?: {
37
+ limit?: number;
38
+ }): Promise<Array<any>>;
39
+ update(id: string, content: string, metadata?: Record<string, any>): Promise<{
40
+ id: string;
41
+ content: string;
42
+ success: boolean;
43
+ }>;
44
+ delete(id: string): Promise<{
45
+ deleted: string;
46
+ success: boolean;
47
+ }>;
48
+ stats(): Promise<{
49
+ count: number;
50
+ tableName: string;
51
+ uri: string;
52
+ isConnected: boolean;
53
+ embedding: any;
54
+ }>;
55
+ healthCheck(): Promise<{
56
+ status: string;
57
+ timestamp: string;
58
+ checks: Record<string, any>;
59
+ }>;
60
+ }
61
+
62
+ export declare class Scrubber {
63
+ constructor(config?: ScrubberConfig);
64
+ process(document: {
65
+ content: string;
66
+ source: string;
67
+ type: 'html' | 'md' | 'txt';
68
+ }): Promise<ScrubberResult>;
69
+ }
70
+
71
+ export interface ScrubberConfig {
72
+ enabled?: boolean;
73
+ structural?: {
74
+ stripHTML?: boolean;
75
+ normalizeMarkdown?: boolean;
76
+ collapseWhitespace?: boolean;
77
+ removeScripts?: boolean;
78
+ removeStyles?: boolean;
79
+ };
80
+ semantic?: {
81
+ removeDuplicates?: boolean;
82
+ removeBoilerplate?: boolean;
83
+ minSignalRatio?: number;
84
+ };
85
+ chunking?: {
86
+ maxTokens?: number;
87
+ minTokens?: number;
88
+ splitOnHeadings?: boolean;
89
+ };
90
+ validation?: {
91
+ enforceMinLength?: boolean;
92
+ };
93
+ }
94
+
95
+ export interface ScrubberResult {
96
+ chunks: Array<{
97
+ text: string;
98
+ metadata: Record<string, any>;
99
+ }>;
100
+ metadata: {
101
+ source: string;
102
+ type: string;
103
+ processingTimestamp: string;
104
+ };
105
+ telemetry: {
106
+ totalDuration: number;
107
+ stages: Record<string, any>;
108
+ };
109
+ success: boolean;
110
+ error?: string;
111
+ }
@@ -0,0 +1,3 @@
1
+ // Adapters module - placeholder for future adapter implementations
2
+ // TODO: Implement adapters for external system integrations (databases, APIs, message queues)
3
+ export {};
@@ -0,0 +1,150 @@
1
+ /**
2
+ * EmbeddingFactory - Multi-provider embedding with automatic fallback
3
+ * Manages primary and fallback embedding services
4
+ */
5
+
6
+ import EmbeddingService from "./service.js";
7
+ import { ConfigurationError, EmbeddingError } from "../lancedb/errors.js";
8
+
9
+ class EmbeddingFactory {
10
+ constructor() {
11
+ this.primaryService = null;
12
+ this.fallbackServices = [];
13
+ this.configured = false;
14
+ }
15
+
16
+ /**
17
+ * Configure embedding services with fallback chain
18
+ * @param {Array} configs - Array of { modelType, modelName, priority, apiKey }
19
+ * @returns {Object} Success status
20
+ */
21
+ configure(configs) {
22
+ // Sort by priority (lower = higher priority)
23
+ configs.sort((a, b) => a.priority - b.priority);
24
+
25
+ this.primaryService = new EmbeddingService(configs[0]);
26
+
27
+ if (configs.length > 1) {
28
+ this.fallbackServices = configs.slice(1).map(c => new EmbeddingService(c));
29
+ }
30
+
31
+ this.configured = true;
32
+ return { success: true };
33
+ }
34
+
35
+ /**
36
+ * Initialize all configured services
37
+ * @returns {Promise<Object>} Initialization status
38
+ */
39
+ async init() {
40
+ if (!this.configured) {
41
+ throw new ConfigurationError('EmbeddingFactory not configured. Call configure() first.');
42
+ }
43
+
44
+ // Initialize primary service
45
+ if (this.primaryService && !this.primaryService.initialized) {
46
+ await this.primaryService.init();
47
+ }
48
+
49
+ // Initialize fallback services lazily (on first use)
50
+ return {
51
+ success: true,
52
+ primary: this.primaryService ? this.primaryService.modelName : null,
53
+ fallbacks: this.fallbackServices.map(s => s.modelName)
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Generate embedding with automatic fallback
59
+ * @param {string} text - Text to embed
60
+ * @param {Object} options - Options
61
+ * @returns {Promise<number[]>} Embedding vector
62
+ */
63
+ async embed(text, options = {}) {
64
+ if (!this.configured || !this.primaryService) {
65
+ throw new ConfigurationError('EmbeddingFactory not configured');
66
+ }
67
+
68
+ // Try primary service
69
+ try {
70
+ if (!this.primaryService.initialized) {
71
+ await this.primaryService.init();
72
+ }
73
+ return await this.primaryService.embed(text, options);
74
+ } catch (error) {
75
+ const errorMessage = error instanceof Error ? error.message : String(error);
76
+ console.warn(`[EmbeddingFactory] Primary service failed: ${errorMessage}`);
77
+
78
+ // Try fallback services in order
79
+ for (const fallback of this.fallbackServices) {
80
+ try {
81
+ if (!fallback.initialized) {
82
+ await fallback.init();
83
+ }
84
+ console.log(`[EmbeddingFactory] Using fallback: ${fallback.modelName}`);
85
+ return await fallback.embed(text, options);
86
+ } catch (fallbackError) {
87
+ const fallbackErrorMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
88
+ console.warn(`[EmbeddingFactory] Fallback ${fallback.modelName} failed: ${fallbackErrorMessage}`);
89
+ }
90
+ }
91
+
92
+ throw new EmbeddingError('All embedding services failed', {
93
+ primaryError: errorMessage,
94
+ fallbackCount: this.fallbackServices.length
95
+ });
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Generate embeddings for batch of texts
101
+ * @param {string[]} texts - Texts to embed
102
+ * @param {Object} options - Options
103
+ * @returns {Promise<number[][]>} Array of embedding vectors
104
+ */
105
+ async embedBatch(texts, options = {}) {
106
+ if (!this.configured || !this.primaryService) {
107
+ throw new ConfigurationError('EmbeddingFactory not configured');
108
+ }
109
+
110
+ // Try primary service
111
+ try {
112
+ if (!this.primaryService.initialized) {
113
+ await this.primaryService.init();
114
+ }
115
+ return await this.primaryService.embedBatch(texts, options);
116
+ } catch (error) {
117
+ const errorMessage = error instanceof Error ? error.message : String(error);
118
+ console.warn(`[EmbeddingFactory] Primary batch failed: ${errorMessage}`);
119
+ // Fallback to individual embedding with fallback services
120
+ const results = [];
121
+ for (const text of texts) {
122
+ results.push(await this.embed(text, options));
123
+ }
124
+ return results;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Get factory statistics
130
+ * @returns {Object} Statistics
131
+ */
132
+ getStats() {
133
+ const stats = {
134
+ configured: this.configured,
135
+ primary: this.primaryService?.getStats() || null,
136
+ fallbacks: this.fallbackServices.map(s => s.getStats())
137
+ };
138
+ return stats;
139
+ }
140
+
141
+ /**
142
+ * Clear all caches
143
+ */
144
+ clearCache() {
145
+ this.primaryService?.clearCache();
146
+ this.fallbackServices.forEach(s => s.clearCache());
147
+ }
148
+ }
149
+
150
+ export default EmbeddingFactory;
@@ -0,0 +1,2 @@
1
+ export { default as EmbeddingService } from './service.js';
2
+ export { default as EmbeddingFactory } from './factory.js';