@mrxkun/mcfast-mcp 4.0.6 → 4.0.12

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrxkun/mcfast-mcp",
3
- "version": "4.0.6",
3
+ "version": "4.0.12",
4
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.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -41,6 +41,10 @@ import {
41
41
  import { safeEdit } from './utils/backup.js';
42
42
  import { formatError } from './utils/error-formatter.js';
43
43
  import { MemoryEngine } from './memory/index.js';
44
+ import { getAuditQueue } from './utils/audit-queue.js';
45
+ import { getIntelligenceCache } from './utils/intelligence-cache.js';
46
+ import { getContextPrefetcher } from './utils/context-prefetcher.js';
47
+ import { parallelMemorySearch } from './utils/parallel-search.js';
44
48
 
45
49
  const execAsync = promisify(exec);
46
50
 
@@ -108,6 +112,62 @@ async function searchMemoryContext(instruction, maxResults = 5) {
108
112
  }
109
113
  }
110
114
 
115
+ /**
116
+ * Auto-trigger intelligence tools after successful edit
117
+ * Runs async in background to not block user
118
+ */
119
+ async function autoTriggerIntelligence(filePath, instruction) {
120
+ try {
121
+ // Only trigger if intelligence is enabled
122
+ if (process.env.MCFAST_INTELLIGENCE_AUTO !== 'true') {
123
+ return;
124
+ }
125
+
126
+ const engine = await getMemoryEngine();
127
+ const cache = getIntelligenceCache();
128
+
129
+ // 1. Detect patterns (cached for 5 minutes)
130
+ const patternCacheKey = { file: filePath, type: 'patterns' };
131
+ let patterns = cache.get('patterns', patternCacheKey);
132
+
133
+ if (!patterns) {
134
+ patterns = await engine.detectPatterns();
135
+ if (patterns && patterns.length > 0) {
136
+ cache.set('patterns', patternCacheKey, patterns);
137
+ console.error(`${colors.cyan}[Intelligence]${colors.reset} 💡 Detected ${patterns.length} patterns`);
138
+
139
+ // Log high-confidence patterns
140
+ patterns.filter(p => p.confidence > 0.8).forEach(p => {
141
+ console.error(`${colors.yellow}[Pattern]${colors.reset} ${p.type}: ${p.message}`);
142
+ });
143
+ }
144
+ }
145
+
146
+ // 2. Get suggestions (cached for 5 minutes)
147
+ const suggestionCacheKey = { file: filePath, type: 'suggestions' };
148
+ let suggestions = cache.get('suggestions', suggestionCacheKey);
149
+
150
+ if (!suggestions) {
151
+ suggestions = await engine.getSuggestions({ currentFile: filePath });
152
+ if (suggestions && suggestions.length > 0) {
153
+ cache.set('suggestions', suggestionCacheKey, suggestions);
154
+ console.error(`${colors.cyan}[Intelligence]${colors.reset} 💡 ${suggestions.length} suggestions available`);
155
+
156
+ // Show top suggestions
157
+ suggestions.slice(0, 3).forEach(s => {
158
+ console.error(`${colors.yellow}[Suggestion]${colors.reset} ${s.type}: ${s.message}`);
159
+ });
160
+ }
161
+ }
162
+
163
+ } catch (error) {
164
+ // Silent fail - intelligence should not break the tool
165
+ if (VERBOSE) {
166
+ console.error(`${colors.yellow}[Intelligence]${colors.reset} Auto-trigger failed: ${error.message}`);
167
+ }
168
+ }
169
+ }
170
+
111
171
  /**
112
172
  * Log edit to memory after successful edit
113
173
  */
@@ -222,6 +282,28 @@ const TOOL_ALIASES = {
222
282
  'list_files_fast': 'list_files',
223
283
  'read_file': 'read',
224
284
  'goto_definition': 'search', // redirected
285
+ // VSCode MCP client adds prefixes
286
+ 'mcp--mcfast--edit': 'edit',
287
+ 'mcp--mcfast--search': 'search',
288
+ 'mcp--mcfast--read': 'read',
289
+ 'mcp--mcfast--list_files': 'list_files',
290
+ 'mcp--mcfast--reapply': 'reapply',
291
+ 'mcp--mcfast--memory_search': 'memory_search',
292
+ 'mcp--mcfast--memory_get': 'memory_get',
293
+ 'mcp--mcfast--detect_patterns': 'detect_patterns',
294
+ 'mcp--mcfast--get_suggestions': 'get_suggestions',
295
+ 'mcp--mcfast--select_strategy': 'select_strategy',
296
+ // Alternative format with double dashes
297
+ 'mcfast_edit': 'edit',
298
+ 'mcfast_search': 'search',
299
+ 'mcfast_read': 'read',
300
+ 'mcfast_list_files': 'list_files',
301
+ 'mcfast_reapply': 'reapply',
302
+ 'mcfast_memory_search': 'memory_search',
303
+ 'mcfast_memory_get': 'memory_get',
304
+ 'mcfast_detect_patterns': 'detect_patterns',
305
+ 'mcfast_get_suggestions': 'get_suggestions',
306
+ 'mcfast_select_strategy': 'select_strategy',
225
307
  };
226
308
 
227
309
  /**
@@ -728,6 +810,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
728
810
  /**
729
811
  * Report audit log to Dashboard
730
812
  * Sends operation logs to mcfast Dashboard for monitoring
813
+ * Now uses AuditQueue for batching to reduce HTTP overhead
731
814
  */
732
815
  async function reportAudit(data) {
733
816
  try {
@@ -755,42 +838,33 @@ async function reportAudit(data) {
755
838
  latency_ms: data.latency_ms || 0,
756
839
  instruction: data.instruction || '',
757
840
  files_count: data.files_count || 0,
841
+ diff_size: data.diff_size || 0, // ✅ Thêm diff_size
758
842
  input_tokens: data.input_tokens || 0,
759
843
  output_tokens: data.output_tokens || 0,
760
844
  strategy: data.strategy || null,
761
845
  error: data.error || null,
846
+ error_message: data.error || null, // ✅ Thêm error_message cho server
847
+ result_summary: data.result_summary || null, // ✅ Thêm result_summary
762
848
  metadata: data.metadata || {}
763
849
  };
764
850
 
765
- // Send to dashboard API
766
- const DASHBOARD_API_URL = process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app/api/v1/logs/audit';
851
+ // Use AuditQueue for batching instead of immediate send
852
+ const queue = getAuditQueue({
853
+ token: TOKEN,
854
+ apiUrl: process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app/api/v1/logs/audit',
855
+ batchSize: 5,
856
+ flushInterval: 5000,
857
+ verbose: VERBOSE
858
+ });
767
859
 
768
- if (VERBOSE) {
769
- console.error(`${colors.dim}[Audit] Sending to: ${DASHBOARD_API_URL}${colors.reset}`);
770
- console.error(`${colors.dim}[Audit] Tool: ${auditData.tool}, Status: ${auditData.status}${colors.reset}`);
771
- }
860
+ queue.add(auditData);
772
861
 
773
- const response = await fetch(DASHBOARD_API_URL, {
774
- method: 'POST',
775
- headers: {
776
- 'Content-Type': 'application/json',
777
- 'Authorization': `Bearer ${TOKEN}`
778
- },
779
- body: JSON.stringify(auditData)
780
- });
781
-
782
- if (!response.ok) {
783
- const errorText = await response.text().catch(() => 'Unknown error');
784
- if (VERBOSE) {
785
- console.error(`${colors.yellow}[Audit] Failed - HTTP ${response.status}: ${errorText}${colors.reset}`);
786
- }
787
- } else {
788
- if (VERBOSE) {
789
- console.error(`${colors.green}[Audit] Logged successfully ✓${colors.reset}`);
790
- }
862
+ if (VERBOSE) {
863
+ const stats = queue.getStats();
864
+ console.error(`${colors.dim}[Audit] Queued for batching. Queue size: ${stats.queued}${colors.reset}`);
791
865
  }
792
866
 
793
- // Also log to local file if configured
867
+ // Also log to local file if configured (immediate)
794
868
  if (process.env.MCFAST_AUDIT_FILE) {
795
869
  const logLine = JSON.stringify(auditData) + '\n';
796
870
  await fs.appendFile(process.env.MCFAST_AUDIT_FILE, logLine).catch((err) => {
@@ -1055,7 +1129,8 @@ async function handleSearchFilesystem({ query, path: searchPath, isRegex = false
1055
1129
  lines.forEach((line, idx) => {
1056
1130
  if (line.includes(query)) {
1057
1131
  matches.push({
1058
- line: idx + 1,
1132
+ file,
1133
+ lineNumber: idx + 1,
1059
1134
  content: line.trim()
1060
1135
  });
1061
1136
  }
@@ -1100,7 +1175,7 @@ async function handleSearchFilesystem({ query, path: searchPath, isRegex = false
1100
1175
  contentMatches.slice(0, 10).forEach(({ file, matches }) => {
1101
1176
  output += `\n${colors.yellow}${file}${colors.reset}\n`;
1102
1177
  matches.forEach(match => {
1103
- output += ` ${colors.dim}${match.line}:${colors.reset} ${match.content}\n`;
1178
+ output += ` ${colors.dim}${match.lineNumber}:${colors.reset} ${match.content}\n`;
1104
1179
  });
1105
1180
  });
1106
1181
  }
@@ -1631,6 +1706,12 @@ async function handleEdit({ instruction, files, code_edit, dryRun = false }) {
1631
1706
  durationMs: Date.now() - editStartTime
1632
1707
  });
1633
1708
 
1709
+ // Auto-trigger intelligence tools in background (non-blocking)
1710
+ if (!result.isError) {
1711
+ const firstFile = Object.keys(files)[0];
1712
+ autoTriggerIntelligence(firstFile, instruction).catch(() => {});
1713
+ }
1714
+
1634
1715
  return result;
1635
1716
  }
1636
1717
 
@@ -1864,7 +1945,7 @@ async function handleReadFileInternal({ path: filePath, start_line, end_line, ma
1864
1945
  } else if (startLine && currentLine >= startLine) {
1865
1946
  lines.push(line);
1866
1947
  if (max_lines && lines.length >= max_lines) break;
1867
- } else if (lines.length < (max_lines || 2000)) {
1948
+ } else if (max_lines && lines.length < max_lines) {
1868
1949
  lines.push(line);
1869
1950
  } else {
1870
1951
  break;
@@ -2155,7 +2236,7 @@ async function handleSearchCode({ query, files, regex = false, caseSensitive = f
2155
2236
  });
2156
2237
  return {
2157
2238
  content: [{ type: "text", text: `❌ Search error: ${error.message}` }],
2158
- isError: true
2239
+ isError: true,
2159
2240
  };
2160
2241
  }
2161
2242
  }
@@ -2169,7 +2250,7 @@ async function handleSearchCodeAI({ query, files, contextLines = 2 }) {
2169
2250
  if (!TOKEN) {
2170
2251
  return {
2171
2252
  content: [{ type: "text", text: "❌ Error: MCFAST_TOKEN is missing. Please set it in your MCP config." }],
2172
- isError: true
2253
+ isError: true,
2173
2254
  };
2174
2255
  }
2175
2256
  try {
@@ -2744,13 +2825,14 @@ async function handleMemorySearch({ query, type = 'all', maxResults = 6, minScor
2744
2825
  score: result.finalScore || result.score
2745
2826
  }));
2746
2827
  } else {
2747
- const searchResult = await engine.intelligentSearch(query, { limit: maxResults });
2748
- results = searchResult.results.map(result => ({
2828
+ // Use parallel search for 'all' type - faster!
2829
+ const parallelResult = await parallelMemorySearch(engine, query, maxResults);
2830
+ results = parallelResult.results.map(result => ({
2749
2831
  type: 'chunk',
2750
- content: result.code || result.content,
2751
- file: result.filePath || result.path,
2752
- score: result.finalScore || result.score,
2753
- method: searchResult.metadata?.method
2832
+ content: result.content || result.code,
2833
+ file: result.file || result.filePath || result.path,
2834
+ score: result._score || result.score || 0.5,
2835
+ method: result._source
2754
2836
  }));
2755
2837
  }
2756
2838
 
@@ -13,7 +13,6 @@ import { DailyLogs } from './utils/daily-logs.js';
13
13
  import { SyncEngine } from './utils/sync-engine.js';
14
14
  import { PatternDetector, SuggestionEngine, StrategySelector } from '../intelligence/index.js';
15
15
  import path from 'path';
16
- import os from 'os';
17
16
 
18
17
  export class MemoryEngine {
19
18
  constructor(options = {}) {
@@ -23,25 +22,19 @@ export class MemoryEngine {
23
22
  this.projectPath = null;
24
23
  this.isInitialized = false;
25
24
 
26
- // Memory path for logs
27
- this.memoryPath = options.memoryPath || path.join(os.homedir(), '.mcfast', 'memory');
25
+ // Memory path - now stored in project directory
26
+ this.memoryPath = options.memoryPath || null; // Will be set on initialize
28
27
 
29
28
  // Daily Logs - auto-generated markdown notes
30
- this.dailyLogs = new DailyLogs({
31
- memoryPath: this.memoryPath
32
- });
29
+ this.dailyLogs = null; // Will be initialized on initialize
33
30
 
34
31
  // Sync Engine - local ↔ cloud (optional, auto-detect from MCFAST_TOKEN)
35
32
  this.syncEngine = null;
36
- const hasToken = options.apiKey || process.env.MCFAST_TOKEN;
37
- if (hasToken && options.enableSync !== false) {
38
- this.syncEngine = new SyncEngine({
39
- memoryPath: this.memoryPath,
40
- apiKey: hasToken,
41
- baseUrl: options.baseUrl || process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app',
42
- syncInterval: options.syncInterval || 5 * 60 * 1000
43
- });
44
- }
33
+ this.syncEngineOptions = {
34
+ apiKey: options.apiKey || process.env.MCFAST_TOKEN,
35
+ baseUrl: options.baseUrl || process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app',
36
+ syncInterval: options.syncInterval || 5 * 60 * 1000
37
+ };
45
38
 
46
39
  // Sử dụng UltraEnhancedEmbedder cho 90% accuracy
47
40
  this.embedder = new UltraEnhancedEmbedder({
@@ -69,41 +62,38 @@ export class MemoryEngine {
69
62
  this.patternDetector = null;
70
63
  this.suggestionEngine = null;
71
64
  this.strategySelector = null;
72
-
73
- if (this.intelligenceEnabled) {
74
- this.patternDetector = new PatternDetector({ db: this.db });
75
- this.suggestionEngine = new SuggestionEngine({
76
- db: this.db,
77
- memoryEngine: this
78
- });
79
- this.strategySelector = new StrategySelector({ db: this.db });
80
- }
81
65
  }
82
66
 
83
67
  async initialize(projectPath) {
84
68
  if (this.isInitialized) return;
85
69
 
86
70
  this.projectPath = projectPath;
87
- await this.db.initialize();
88
71
 
89
- // Load smart router config from dashboard
90
- if (this.smartRoutingEnabled) {
91
- await this.smartRouter.loadConfig();
92
- console.log('[MemoryEngine] Smart router config loaded');
72
+ // Set memory path to project directory
73
+ if (!this.memoryPath) {
74
+ this.memoryPath = path.join(projectPath, '.mcfast', 'memory');
93
75
  }
94
76
 
95
- // Test dashboard connection
96
- const connectionStatus = await this.dashboardClient.testConnection();
97
- if (connectionStatus.connected) {
98
- console.log('[MemoryEngine] ✅ Connected to Dashboard');
99
- } else {
100
- console.log('[MemoryEngine] ⚠️ Dashboard connection failed, using offline mode');
77
+ // Update database path if not explicitly set
78
+ if (!this.db.dbPath) {
79
+ this.db.dbPath = path.join(this.memoryPath, 'index.db');
101
80
  }
102
81
 
82
+ await this.db.initialize();
83
+
84
+ // Initialize Daily Logs with project-specific path
85
+ this.dailyLogs = new DailyLogs({
86
+ memoryPath: this.memoryPath
87
+ });
88
+
103
89
  // Initialize Sync Engine if configured
104
- if (this.syncEngine) {
105
- await this.syncEngine.initialize();
106
- console.log('[MemoryEngine] ✅ Sync Engine initialized');
90
+ if (this.syncEngineOptions.apiKey && this.syncEngineOptions.enableSync !== false) {
91
+ this.syncEngine = new SyncEngine({
92
+ memoryPath: this.memoryPath,
93
+ apiKey: this.syncEngineOptions.apiKey,
94
+ baseUrl: this.syncEngineOptions.baseUrl,
95
+ syncInterval: this.syncEngineOptions.syncInterval
96
+ });
107
97
  }
108
98
 
109
99
  this.watcher = new FileWatcher(projectPath, this);
@@ -114,6 +104,20 @@ export class MemoryEngine {
114
104
  console.log(`[MemoryEngine] Smart Routing: ${this.smartRoutingEnabled ? 'ENABLED' : 'DISABLED'}`);
115
105
  console.log(`[MemoryEngine] Intelligence Layer: ${this.intelligenceEnabled ? 'ENABLED' : 'DISABLED'}`);
116
106
 
107
+ // Initialize intelligence engines if enabled
108
+ if (this.intelligenceEnabled) {
109
+ try {
110
+ const { PatternDetector, SuggestionEngine, StrategySelector } = await import('../intelligence/index.js');
111
+ this.patternDetector = new PatternDetector({ memoryEngine: this });
112
+ this.suggestionEngine = new SuggestionEngine({ memoryEngine: this });
113
+ this.strategySelector = new StrategySelector({ memoryEngine: this });
114
+ console.log('[MemoryEngine] Intelligence engines initialized');
115
+ } catch (error) {
116
+ console.warn('[MemoryEngine] Failed to initialize intelligence engines:', error.message);
117
+ this.intelligenceEnabled = false;
118
+ }
119
+ }
120
+
117
121
  // Load intelligence models
118
122
  if (this.intelligenceEnabled) {
119
123
  await this.patternDetector.loadModel?.();
@@ -1,15 +1,19 @@
1
1
  import Database from 'better-sqlite3';
2
2
  import path from 'path';
3
- import os from 'os';
4
3
  import fs from 'fs/promises';
5
4
 
6
5
  export class MemoryDatabase {
7
- constructor(dbPath = path.join(os.homedir(), '.mcfast', 'memory', 'index.db')) {
6
+ constructor(dbPath = null) {
8
7
  this.dbPath = dbPath;
9
8
  this.db = null;
10
9
  }
11
10
 
12
11
  async initialize() {
12
+ // If dbPath not set, create in current directory
13
+ if (!this.dbPath) {
14
+ this.dbPath = path.join(process.cwd(), '.mcfast', 'memory', 'index.db');
15
+ }
16
+
13
17
  await fs.mkdir(path.dirname(this.dbPath), { recursive: true });
14
18
  this.db = new Database(this.dbPath);
15
19
  this.db.pragma('journal_mode = WAL');
@@ -5,15 +5,15 @@
5
5
 
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
- import os from 'os';
9
8
 
10
9
  export class DailyLogs {
11
10
  constructor(options = {}) {
12
- this.memoryPath = options.memoryPath || path.join(os.homedir(), '.mcfast', 'memory');
13
- this.dateFormat = options.dateFormat || 'yyyy-MM-dd';
14
- }
15
-
16
- ensureMemoryDir() {
11
+ this.memoryPath = options.memoryPath;
12
+ if (!this.memoryPath) {
13
+ throw new Error('memoryPath is required for DailyLogs');
14
+ }
15
+
16
+ // Ensure directory exists
17
17
  if (!fs.existsSync(this.memoryPath)) {
18
18
  fs.mkdirSync(this.memoryPath, { recursive: true });
19
19
  }
@@ -47,8 +47,6 @@ export class DailyLogs {
47
47
  * Log a file creation event
48
48
  */
49
49
  logFileCreated(filePath, facts = []) {
50
- this.ensureMemoryDir();
51
-
52
50
  const content = [
53
51
  `## ${this.formatTime()} - File Created`,
54
52
  `**File:** \`${filePath}\``,
@@ -63,8 +61,6 @@ export class DailyLogs {
63
61
  * Log a file modification event
64
62
  */
65
63
  logFileModified(filePath, changes = {}) {
66
- this.ensureMemoryDir();
67
-
68
64
  const parts = [`**File:** \`${filePath}\``];
69
65
 
70
66
  if (changes.added && changes.added.length > 0) {
@@ -92,8 +88,6 @@ export class DailyLogs {
92
88
  * Log a file deletion event
93
89
  */
94
90
  logFileDeleted(filePath) {
95
- this.ensureMemoryDir();
96
-
97
91
  const content = [
98
92
  `## ${this.formatTime()} - File Deleted`,
99
93
  `**File:** \`${filePath}\``,
@@ -107,8 +101,6 @@ export class DailyLogs {
107
101
  * Log an edit session
108
102
  */
109
103
  logEdit(edit) {
110
- this.ensureMemoryDir();
111
-
112
104
  const {
113
105
  instruction,
114
106
  files = [],
@@ -139,8 +131,6 @@ export class DailyLogs {
139
131
  * Log a search query
140
132
  */
141
133
  logSearch(query, resultsCount, duration) {
142
- this.ensureMemoryDir();
143
-
144
134
  const content = [
145
135
  `## ${this.formatTime()} - Search`,
146
136
  `**Query:** "${query}"`,
@@ -156,8 +146,6 @@ export class DailyLogs {
156
146
  * Add a curated memory entry to MEMORY.md
157
147
  */
158
148
  addCuratedMemory(title, content, tags = []) {
159
- this.ensureMemoryDir();
160
-
161
149
  const memoryPath = this.getMemoryFilePath();
162
150
  const timestamp = new Date().toISOString();
163
151
 
@@ -219,8 +207,6 @@ export class DailyLogs {
219
207
  * Get logs for a date range
220
208
  */
221
209
  getLogsInRange(startDate, endDate) {
222
- this.ensureMemoryDir();
223
-
224
210
  const logs = [];
225
211
  const files = fs.readdirSync(this.memoryPath)
226
212
  .filter(f => f.match(/^\d{4}-\d{2}-\d{2}\.md$/))
@@ -241,8 +227,6 @@ export class DailyLogs {
241
227
  * Clean up old logs (keep last N days)
242
228
  */
243
229
  cleanupOldLogs(keepDays = 30) {
244
- this.ensureMemoryDir();
245
-
246
230
  const cutoffDate = new Date();
247
231
  cutoffDate.setDate(cutoffDate.getDate() - keepDays);
248
232
  const cutoffStr = cutoffDate.toISOString().split('T')[0].replace(/-/g, '');
@@ -7,6 +7,7 @@ import { parse } from '../../strategies/tree-sitter/index.js';
7
7
  import { detectLanguage } from '../../strategies/syntax-validator.js';
8
8
  import { Chunker } from './chunker.js';
9
9
  import { Embedder } from './embedder.js';
10
+ import { getQuery } from '../../strategies/tree-sitter/languages.js';
10
11
  import crypto from 'crypto';
11
12
 
12
13
  export class CodeIndexer {
@@ -58,14 +59,14 @@ export class CodeIndexer {
58
59
  const fileId = this.generateFileId(filePath);
59
60
 
60
61
  try {
61
- const { QUERIES } = await import('../../strategies/tree-sitter/queries.js');
62
- const queries = QUERIES[language];
62
+ // Use getQuery to compile the query properly
63
+ const query = await getQuery(language, 'definitions');
63
64
 
64
- if (queries?.definitions) {
65
- const captures = queries.definitions.captures(ast.rootNode);
65
+ if (query) {
66
+ const captures = query.captures(ast.rootNode);
66
67
 
67
68
  for (const capture of captures) {
68
- if (capture.name === 'name') {
69
+ if (capture.name === 'name' || capture.name === 'function') {
69
70
  facts.push({
70
71
  id: this.generateFactId(fileId, capture.node.text, 'function'),
71
72
  file_id: fileId,
@@ -6,30 +6,19 @@
6
6
 
7
7
  import fs from 'fs';
8
8
  import path from 'path';
9
- import os from 'os';
10
9
  import crypto from 'crypto';
11
10
 
12
11
  export class SyncEngine {
13
12
  constructor(options = {}) {
14
- this.memoryPath = options.memoryPath || path.join(os.homedir(), '.mcfast', 'memory');
15
-
16
- // Use Dashboard URL for sync (same as DashboardClient)
17
- this.baseUrl = options.baseUrl || process.env.MCFAST_DASHBOARD_URL || 'https://mcfast.vercel.app';
18
- this.apiKey = options.apiKey || process.env.MCFAST_TOKEN;
13
+ this.memoryPath = options.memoryPath;
14
+ if (!this.memoryPath) {
15
+ throw new Error('memoryPath is required for SyncEngine');
16
+ }
19
17
 
18
+ this.apiKey = options.apiKey;
19
+ this.baseUrl = options.baseUrl || 'https://mcfast.vercel.app';
20
20
  this.syncInterval = options.syncInterval || 5 * 60 * 1000; // 5 minutes
21
- this.lastSyncTime = null;
22
- this.syncQueue = [];
23
- this.isOnline = true;
24
- this.isSyncing = false;
25
- this.listeners = new Set();
26
-
27
- // Check online status
28
- if (typeof window !== 'undefined') {
29
- this.isOnline = navigator.onLine;
30
- window.addEventListener('online', () => this.handleOnline());
31
- window.addEventListener('offline', () => this.handleOffline());
32
- }
21
+ this.syncTimer = null;
33
22
  }
34
23
 
35
24
  /**