UNPKG

@every-env/sparkle-mcp-server

Version:

MCP server for secure Sparkle folder file access with Claude AI, including clipboard history support

100 lines 3.51 kB
import * as path from "path"; import * as os from "os"; import chokidar from "chokidar"; export class RecentActivityTracker { recentFiles = new Map(); downloadsWatcher; maxAge = 24 * 60 * 60 * 1000; // 24 hours downloadsPath; constructor() { this.downloadsPath = path.join(os.homedir(), "Downloads"); this.setupWatchers(); this.startCleanupInterval(); } setupWatchers() { // Watch Downloads folder this.downloadsWatcher = chokidar.watch(this.downloadsPath, { persistent: true, ignoreInitial: true, depth: 0, // Only watch immediate children }); this.downloadsWatcher.on("add", (filePath) => { this.addRecentFile(filePath, "download"); }); } addRecentFile(filePath, source) { console.error(`New ${source} file: ${filePath}`); this.recentFiles.set(filePath, { path: filePath, timestamp: new Date(), source, }); } startCleanupInterval() { // Clean up old files every hour setInterval(() => { this.cleanupOldFiles(); }, 60 * 60 * 1000); } cleanupOldFiles() { const now = Date.now(); for (const [path, file] of this.recentFiles.entries()) { if (now - file.timestamp.getTime() > this.maxAge) { this.recentFiles.delete(path); } } } async getRelevantFiles(query, limit) { const results = []; const queryLower = query.toLowerCase(); const queryWords = queryLower.split(/\\s+/); for (const [filePath, recentFile] of this.recentFiles.entries()) { // Calculate relevance based on filename and recency let relevance = 0; const fileName = path.basename(filePath).toLowerCase(); // Check filename matches for (const word of queryWords) { if (fileName.includes(word)) { relevance += 0.4; } } // Boost for very recent files (last hour) const hoursSinceAdded = (Date.now() - recentFile.timestamp.getTime()) / (1000 * 60 * 60); if (hoursSinceAdded < 1) { relevance += 0.3; } else if (hoursSinceAdded < 6) { relevance += 0.2; } else if (hoursSinceAdded < 24) { relevance += 0.1; } if (relevance > 0) { results.push({ path: filePath, relevance: Math.min(relevance, 0.9), // Cap at 0.9 for recent files summary: `Recent ${recentFile.source} (${this.getTimeAgo(recentFile.timestamp)})`, }); } } return results .sort((a, b) => b.relevance - a.relevance) .slice(0, limit); } getTimeAgo(date) { const seconds = Math.floor((Date.now() - date.getTime()) / 1000); if (seconds < 60) return "just now"; if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`; if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`; return `${Math.floor(seconds / 86400)} days ago`; } async cleanup() { if (this.downloadsWatcher) { await this.downloadsWatcher.close(); } } } //# sourceMappingURL=recent-activity.js.map