@mrxkun/mcfast-mcp 4.0.14 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mrxkun/mcfast-mcp",
3
- "version": "4.0.14",
4
- "description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. Optimized for AI code assistants with 80-98% latency reduction. Phase 4: ML Intelligence Layer.",
3
+ "version": "4.1.0",
4
+ "description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. Optimized for AI code assistants with 80-98% latency reduction. Phase 5: Memory v4.1.0 - Markdown source, Hybrid Search, Two-tier memory.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mcfast-mcp": "src/index.js"
@@ -0,0 +1,173 @@
1
+ /**
2
+ * AGENTS.md Bootstrap
3
+ * Tạo file AGENTS.md hướng dẫn agent cách sử dụng memory
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+
9
+ export class AgentsMdBootstrap {
10
+ constructor(options = {}) {
11
+ this.projectPath = options.projectPath || process.cwd();
12
+ this.agentsFile = path.join(this.projectPath, '.mcfast', 'AGENTS.md');
13
+ }
14
+
15
+ /**
16
+ * Check if AGENTS.md exists
17
+ */
18
+ async exists() {
19
+ try {
20
+ await fs.access(this.agentsFile);
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Create AGENTS.md if it doesn't exist
29
+ */
30
+ async bootstrap() {
31
+ if (await this.exists()) {
32
+ console.log(`[AgentsMdBootstrap] AGENTS.md already exists`);
33
+ return false;
34
+ }
35
+
36
+ await fs.mkdir(path.dirname(this.agentsFile), { recursive: true });
37
+ await fs.writeFile(this.agentsFile, this.getContent());
38
+
39
+ console.log(`[AgentsMdBootstrap] Created ${this.agentsFile}`);
40
+ return true;
41
+ }
42
+
43
+ /**
44
+ * Force regenerate AGENTS.md
45
+ */
46
+ async regenerate() {
47
+ await fs.mkdir(path.dirname(this.agentsFile), { recursive: true });
48
+ await fs.writeFile(this.agentsFile, this.getContent());
49
+
50
+ console.log(`[AgentsMdBootstrap] Regenerated ${this.agentsFile}`);
51
+ return true;
52
+ }
53
+
54
+ /**
55
+ * Get AGENTS.md content
56
+ */
57
+ getContent() {
58
+ return `# Agent Instructions
59
+
60
+ ## 🎯 Every Session - MANDATORY
61
+
62
+ Before doing anything else, you MUST:
63
+
64
+ 1. **Read Recent Context** (ALWAYS)
65
+ - Read memory/YYYY-MM-DD.md for TODAY
66
+ - Read memory/YYYY-MM-DD.md for YESTERDAY
67
+ - This gives you recent context and running notes
68
+
69
+ 2. **Read Long-term Memory** (If in main session)
70
+ - Read MEMORY.md for curated knowledge
71
+ - This contains decisions, preferences, contacts
72
+
73
+ 3. **Search Memory** (When relevant)
74
+ - Use memory_search tool when user asks about:
75
+ - Previous work or decisions
76
+ - Dates, people, preferences
77
+ - Todos or plans
78
+ - Any prior context
79
+
80
+ ## 📝 Writing to Memory
81
+
82
+ ### Daily Logs (memory/YYYY-MM-DD.md)
83
+ Write here for:
84
+ - Day-to-day activities
85
+ - Temporary notes
86
+ - Running context
87
+ - Session summaries
88
+
89
+ Example:
90
+ \`\`\`markdown
91
+ ## 2:30 PM - API Discussion
92
+ Discussed REST vs GraphQL with user.
93
+ Decision: Use REST for simplicity.
94
+ \`\`\`
95
+
96
+ ### Curated Memory (MEMORY.md)
97
+ Write here for:
98
+ - Important decisions
99
+ - User preferences
100
+ - Key contacts
101
+ - Project context
102
+ - Lessons learned
103
+
104
+ Example:
105
+ \`\`\`markdown
106
+ ## Important Decisions
107
+ - **2026-01-20:** Chose PostgreSQL for database (scales better)
108
+
109
+ ## User Preferences
110
+ - Prefers TypeScript over JavaScript
111
+ - Likes concise explanations
112
+ \`\`\`
113
+
114
+ ## 🧠 Memory Search Strategy
115
+
116
+ When user asks about past context:
117
+
118
+ 1. **ALWAYS search first**: Use memory_search tool
119
+ 2. **Read relevant files**: Use memory_get to read full content
120
+ 3. **Reference in response**: Cite the source file
121
+
122
+ Example workflow:
123
+ \`\`\`
124
+ User: "What did we decide about the API?"
125
+
126
+ Agent:
127
+ 1. memory_search({ query: "API decision REST GraphQL" })
128
+ 2. memory_get({ path: "MEMORY.md", from: 1, lines: 50 })
129
+ 3. Answer with citation: "According to MEMORY.md (line 15), we decided..."
130
+ \`\`\`
131
+
132
+ ## ⚠️ Important Rules
133
+
134
+ 1. **Don't ask permission** - Just read memory files automatically
135
+ 2. **Don't keep it in RAM** - Write important info to disk
136
+ 3. **Search before answering** - About past work, always search first
137
+ 4. **Cite your sources** - Tell user which memory file you referenced
138
+ 5. **Write proactively** - When you learn something important, write it down
139
+
140
+ ## 🔄 Memory Maintenance
141
+
142
+ - Daily logs are append-only
143
+ - Curated memory is for long-term storage
144
+ - Promote important items from daily logs to MEMORY.md
145
+ - Memory is searchable - trust the search system
146
+
147
+ ---
148
+
149
+ *This file guides the agent on how to use the memory system effectively.*
150
+ *Generated by mcfast v4.1.0*
151
+ `;
152
+ }
153
+
154
+ /**
155
+ * Read AGENTS.md content
156
+ */
157
+ async read() {
158
+ try {
159
+ return await fs.readFile(this.agentsFile, 'utf-8');
160
+ } catch (error) {
161
+ return null;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Get file path
167
+ */
168
+ getPath() {
169
+ return this.agentsFile;
170
+ }
171
+ }
172
+
173
+ export default AgentsMdBootstrap;
@@ -1,17 +1,30 @@
1
- export { MemoryDatabase } from './stores/database.js';
1
+ /**
2
+ * Memory System v4.1.0
3
+ * Export all memory components
4
+ */
5
+
6
+ // Main engine
7
+ export { MemoryEngine } from './memory-engine.js';
8
+
9
+ // Databases
10
+ export { MemoryDatabase } from './stores/memory-database.js';
11
+ export { CodebaseDatabase } from './stores/codebase-database.js';
12
+
13
+ // Watchers
2
14
  export { FileWatcher } from './watchers/file-watcher.js';
15
+
16
+ // Utils
17
+ export { MarkdownChunker } from './utils/markdown-chunker.js';
18
+ export { CodeIndexer } from './utils/indexer.js';
3
19
  export { Chunker } from './utils/chunker.js';
4
20
  export { Embedder } from './utils/embedder.js';
5
- export { SimpleEmbedder } from './utils/simple-embedder.js';
6
- export { EnhancedSimpleEmbedder } from './utils/enhanced-embedder.js';
7
- export { UltraEnhancedEmbedder } from './utils/ultra-embedder.js';
8
- export { SmartRouter } from './utils/smart-router.js';
9
- export { DashboardClient } from './utils/dashboard-client.js';
10
- export { CodeIndexer } from './utils/indexer.js';
11
- export { DailyLogs } from './utils/daily-logs.js';
12
- export { SyncEngine } from './utils/sync-engine.js';
13
- export { MemoryEngine } from './memory-engine.js';
14
- export { MemoryEngine as default } from './memory-engine.js';
15
21
 
16
- // Phase 4: Intelligence Layer
17
- export { PatternDetector, SuggestionEngine, StrategySelector } from '../intelligence/index.js';
22
+ // Two-tier memory layers
23
+ export { DailyLogs } from './layers/daily-logs.js';
24
+ export { CuratedMemory } from './layers/curated-memory.js';
25
+
26
+ // Bootstrap
27
+ export { AgentsMdBootstrap } from './bootstrap/agents-md.js';
28
+
29
+ // Legacy exports for backward compatibility
30
+ export { MemoryEngine as default } from './memory-engine.js';
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Curated Memory Layer
3
+ * Layer 2: Long-term curated knowledge
4
+ * File: MEMORY.md
5
+ */
6
+
7
+ import fs from 'fs/promises';
8
+ import path from 'path';
9
+
10
+ export class CuratedMemory {
11
+ constructor(options = {}) {
12
+ this.memoryPath = options.memoryPath || '.mcfast';
13
+ this.memoryFile = path.join(this.memoryPath, 'MEMORY.md');
14
+ this.sections = new Map();
15
+ }
16
+
17
+ /**
18
+ * Ensure memory file exists
19
+ */
20
+ async ensureFile() {
21
+ try {
22
+ await fs.access(this.memoryFile);
23
+ } catch {
24
+ // Create default MEMORY.md
25
+ const defaultContent = this.getDefaultContent();
26
+ await fs.mkdir(path.dirname(this.memoryFile), { recursive: true });
27
+ await fs.writeFile(this.memoryFile, defaultContent);
28
+ console.log(`[CuratedMemory] Created ${this.memoryFile}`);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Get default content for new MEMORY.md
34
+ */
35
+ getDefaultContent() {
36
+ return `# Long-term Memory
37
+
38
+ This file contains curated, persistent knowledge.
39
+
40
+ ## User Preferences
41
+
42
+ <!-- Add user preferences here -->
43
+
44
+ ## Important Decisions
45
+
46
+ <!-- Add important decisions here -->
47
+
48
+ ## Key Contacts
49
+
50
+ <!-- Add key contacts here -->
51
+
52
+ ## Project Context
53
+
54
+ <!-- Add project context here -->
55
+
56
+ ## Lessons Learned
57
+
58
+ <!-- Add lessons learned here -->
59
+
60
+ ---
61
+ *Last updated: ${new Date().toISOString()}*
62
+ `;
63
+ }
64
+
65
+ /**
66
+ * Read entire memory file
67
+ */
68
+ async read() {
69
+ await this.ensureFile();
70
+ return await fs.readFile(this.memoryFile, 'utf-8');
71
+ }
72
+
73
+ /**
74
+ * Read specific section
75
+ */
76
+ async readSection(sectionName) {
77
+ const content = await this.read();
78
+ const sections = this.parseSections(content);
79
+ return sections.get(sectionName) || null;
80
+ }
81
+
82
+ /**
83
+ * Add or update a section
84
+ */
85
+ async updateSection(sectionName, content, append = false) {
86
+ await this.ensureFile();
87
+
88
+ let fileContent = await this.read();
89
+ const sections = this.parseSections(fileContent);
90
+
91
+ const timestamp = new Date().toISOString();
92
+ const sectionHeader = `## ${sectionName}`;
93
+
94
+ if (sections.has(sectionName)) {
95
+ // Update existing section
96
+ const existingContent = sections.get(sectionName);
97
+ const newContent = append
98
+ ? `${existingContent}\n\n${content}\n\n*Updated: ${timestamp}*`
99
+ : `${content}\n\n*Updated: ${timestamp}*`;
100
+
101
+ fileContent = fileContent.replace(
102
+ new RegExp(`${sectionHeader}\\n[\\s\\S]*?(?=\\n## |\\n---|$)`),
103
+ `${sectionHeader}\n\n${newContent}\n`
104
+ );
105
+ } else {
106
+ // Add new section before the footer
107
+ const newSection = `${sectionHeader}\n\n${content}\n\n*Added: ${timestamp}*\n\n`;
108
+ fileContent = fileContent.replace(
109
+ /(---\n\*Last updated:.*\*)/,
110
+ `${newSection}$1`
111
+ );
112
+ }
113
+
114
+ // Update timestamp
115
+ fileContent = fileContent.replace(
116
+ /\*Last updated:.*\*/,
117
+ `*Last updated: ${timestamp}*`
118
+ );
119
+
120
+ await fs.writeFile(this.memoryFile, fileContent);
121
+ console.log(`[CuratedMemory] Updated section: ${sectionName}`);
122
+
123
+ return true;
124
+ }
125
+
126
+ /**
127
+ * Parse sections from content
128
+ */
129
+ parseSections(content) {
130
+ const sections = new Map();
131
+ const lines = content.split('\n');
132
+ let currentSection = null;
133
+ let currentContent = [];
134
+
135
+ for (const line of lines) {
136
+ const match = line.match(/^##\s+(.+)$/);
137
+
138
+ if (match) {
139
+ // Save previous section
140
+ if (currentSection) {
141
+ sections.set(currentSection, currentContent.join('\n').trim());
142
+ }
143
+
144
+ // Start new section
145
+ currentSection = match[1];
146
+ currentContent = [];
147
+ } else if (currentSection) {
148
+ currentContent.push(line);
149
+ }
150
+ }
151
+
152
+ // Don't forget the last section
153
+ if (currentSection) {
154
+ sections.set(currentSection, currentContent.join('\n').trim());
155
+ }
156
+
157
+ return sections;
158
+ }
159
+
160
+ /**
161
+ * Add user preference
162
+ */
163
+ async addUserPreference(key, value) {
164
+ const content = `- **${key}:** ${value}`;
165
+ return this.updateSection('User Preferences', content, true);
166
+ }
167
+
168
+ /**
169
+ * Add important decision
170
+ */
171
+ async addDecision(decision, context = '') {
172
+ const timestamp = new Date().toISOString().split('T')[0];
173
+ let content = `- **${timestamp}:** ${decision}`;
174
+ if (context) {
175
+ content += `\n - Context: ${context}`;
176
+ }
177
+ return this.updateSection('Important Decisions', content, true);
178
+ }
179
+
180
+ /**
181
+ * Add contact
182
+ */
183
+ async addContact(name, info, role = '') {
184
+ let content = `- **${name}**`;
185
+ if (role) content += ` (${role})`;
186
+ content += `: ${info}`;
187
+ return this.updateSection('Key Contacts', content, true);
188
+ }
189
+
190
+ /**
191
+ * Add project context
192
+ */
193
+ async addProjectContext(key, value) {
194
+ const content = `- **${key}:** ${value}`;
195
+ return this.updateSection('Project Context', content, true);
196
+ }
197
+
198
+ /**
199
+ * Add lesson learned
200
+ */
201
+ async addLesson(lesson, context = '') {
202
+ const timestamp = new Date().toISOString().split('T')[0];
203
+ let content = `- **${timestamp}:** ${lesson}`;
204
+ if (context) {
205
+ content += `\n - Context: ${context}`;
206
+ }
207
+ return this.updateSection('Lessons Learned', content, true);
208
+ }
209
+
210
+ /**
211
+ * Add curated memory entry
212
+ * Smart routing to appropriate section
213
+ */
214
+ async addEntry(type, title, content) {
215
+ switch (type.toLowerCase()) {
216
+ case 'preference':
217
+ case 'pref':
218
+ return this.addUserPreference(title, content);
219
+
220
+ case 'decision':
221
+ return this.addDecision(title, content);
222
+
223
+ case 'contact':
224
+ return this.addContact(title, content);
225
+
226
+ case 'project':
227
+ case 'context':
228
+ return this.addProjectContext(title, content);
229
+
230
+ case 'lesson':
231
+ case 'learned':
232
+ return this.addLesson(title, content);
233
+
234
+ default:
235
+ // Add to custom section
236
+ return this.updateSection(title, content);
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Search in memory file
242
+ * Simple text search (not using FTS5 here - that's handled by MemoryDatabase)
243
+ */
244
+ async search(query) {
245
+ const content = await this.read();
246
+ const lines = content.split('\n');
247
+ const matches = [];
248
+
249
+ const lowerQuery = query.toLowerCase();
250
+
251
+ lines.forEach((line, index) => {
252
+ if (line.toLowerCase().includes(lowerQuery)) {
253
+ matches.push({
254
+ line: index + 1,
255
+ content: line,
256
+ context: this.getContext(lines, index)
257
+ });
258
+ }
259
+ });
260
+
261
+ return matches;
262
+ }
263
+
264
+ /**
265
+ * Get context around a line
266
+ */
267
+ getContext(lines, index, contextSize = 2) {
268
+ const start = Math.max(0, index - contextSize);
269
+ const end = Math.min(lines.length, index + contextSize + 1);
270
+ return lines.slice(start, end).join('\n');
271
+ }
272
+
273
+ /**
274
+ * Get all sections
275
+ */
276
+ async getSections() {
277
+ const content = await this.read();
278
+ const sections = this.parseSections(content);
279
+ return Array.from(sections.keys());
280
+ }
281
+
282
+ /**
283
+ * Check if file exists
284
+ */
285
+ async exists() {
286
+ try {
287
+ await fs.access(this.memoryFile);
288
+ return true;
289
+ } catch {
290
+ return false;
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Get file stats
296
+ */
297
+ async getStats() {
298
+ await this.ensureFile();
299
+ const stats = await fs.stat(this.memoryFile);
300
+ const content = await this.read();
301
+ const sections = this.parseSections(content);
302
+
303
+ return {
304
+ path: this.memoryFile,
305
+ size: stats.size,
306
+ lastModified: stats.mtime,
307
+ sections: sections.size,
308
+ sectionNames: Array.from(sections.keys())
309
+ };
310
+ }
311
+
312
+ /**
313
+ * Promote entry from daily log to curated memory
314
+ */
315
+ async promoteFromDailyLog(date, entryTitle, sectionName) {
316
+ // This would require reading from daily log file
317
+ // Implementation depends on DailyLogs integration
318
+ console.log(`[CuratedMemory] Promote: ${entryTitle} from ${date} to ${sectionName}`);
319
+ // TODO: Implement promotion logic
320
+ return true;
321
+ }
322
+ }
323
+
324
+ export default CuratedMemory;