UNPKG

strategic-intelligence-mcp

Version:

Strategic Intelligence MCP Server - connecting technical progress to business outcomes with systematic strategic planning

217 lines 9.52 kB
export class JSONStorageAdapter { dataPath; cache = null; constructor(dataPath = './strategic-data.json') { // For ES modules, we'll use process.cwd() + relative path resolution if (!dataPath.startsWith('/')) { this.dataPath = `${process.cwd()}/${dataPath}`; } else { this.dataPath = dataPath; } console.error(`Strategic Intelligence MCP: Storage adapter initialized with path: ${this.dataPath}`); } async save(data) { try { const fs = await import('fs/promises'); const path = await import('path'); // Ensure directory exists const dir = path.dirname(this.dataPath); await fs.mkdir(dir, { recursive: true }); // Write data atomically with backup const tempPath = `${this.dataPath}.tmp`; await fs.writeFile(tempPath, JSON.stringify(data, null, 2)); await fs.rename(tempPath, this.dataPath); this.cache = data; console.error(`Strategic Intelligence MCP: Data saved successfully to ${this.dataPath}`); } catch (error) { console.error(`Strategic Intelligence MCP: Failed to save data to ${this.dataPath}:`, error); throw new Error(`Failed to save strategic data: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async load() { if (this.cache) { console.error(`Strategic Intelligence MCP: Using cached data from ${this.dataPath}`); return this.cache; } try { console.error(`Strategic Intelligence MCP: Loading data from ${this.dataPath}`); const fs = await import('fs/promises'); const path = await import('path'); // Check if file exists try { await fs.access(this.dataPath); console.error(`Strategic Intelligence MCP: Data file exists at ${this.dataPath}`); } catch (accessError) { console.error(`Strategic Intelligence MCP: Data file does not exist at ${this.dataPath}, will create new one`); throw accessError; // Re-throw to trigger empty database creation } const fileContent = await fs.readFile(this.dataPath, 'utf-8'); console.error(`Strategic Intelligence MCP: File content loaded, size: ${fileContent.length} bytes`); // Validate JSON let parsedData; try { parsedData = JSON.parse(fileContent); console.error(`Strategic Intelligence MCP: JSON parsed successfully`); } catch (parseError) { console.error(`Strategic Intelligence MCP: JSON parse error:`, parseError); throw new Error(`Invalid JSON in strategic data file: ${parseError instanceof Error ? parseError.message : 'Unknown parse error'}`); } // Validate data structure if (!parsedData || typeof parsedData !== 'object') { throw new Error('Invalid strategic data structure: not an object'); } // Ensure required properties exist if (!parsedData.conversations) parsedData.conversations = {}; if (!parsedData.goals) parsedData.goals = {}; if (!parsedData.alignments) parsedData.alignments = {}; if (!parsedData.insights) parsedData.insights = {}; if (!parsedData.metadata) { parsedData.metadata = { version: '1.0.0', lastUpdated: new Date().toISOString(), totalConversations: Object.keys(parsedData.conversations).length, totalGoals: Object.keys(parsedData.goals).length, totalInsights: Object.keys(parsedData.insights).length }; } this.cache = parsedData; console.error(`Strategic Intelligence MCP: Data loaded successfully with ${Object.keys(parsedData.conversations).length} conversations, ${Object.keys(parsedData.goals).length} goals`); return this.cache; } catch (error) { console.error(`Strategic Intelligence MCP: Failed to load data from ${this.dataPath}:`, error); console.error(`Strategic Intelligence MCP: Creating new empty database`); // Return empty database if file doesn't exist or is corrupted const emptyDatabase = { conversations: {}, goals: {}, alignments: {}, insights: {}, metadata: { version: '1.0.0', lastUpdated: new Date().toISOString(), totalConversations: 0, totalGoals: 0, totalInsights: 0 } }; try { await this.save(emptyDatabase); console.error(`Strategic Intelligence MCP: Empty database created and saved successfully`); } catch (saveError) { console.error(`Strategic Intelligence MCP: Failed to save empty database:`, saveError); // Continue with in-memory database if we can't save this.cache = emptyDatabase; } return emptyDatabase; } } async findConversationsByType(type) { const data = await this.load(); return Object.values(data.conversations).filter(conv => conv.type === type); } async findConversationsByDateRange(from, to) { const data = await this.load(); const fromDate = new Date(from); const toDate = new Date(to); return Object.values(data.conversations).filter(conv => { const convDate = new Date(conv.timestamp); return convDate >= fromDate && convDate <= toDate; }); } async getGoalsByStatus(status) { const data = await this.load(); return Object.values(data.goals).filter(goal => goal.status === status); } async getGoalsByCategory(category) { const data = await this.load(); return Object.values(data.goals).filter(goal => goal.category === category); } async searchInsights(query, category) { const data = await this.load(); const searchTerm = query.toLowerCase(); return Object.values(data.insights).filter(insight => { const matchesSearch = insight.content.toLowerCase().includes(searchTerm); const matchesCategory = !category || insight.category === category; return matchesSearch && matchesCategory; }); } async getInsightsByImpact(impact) { const data = await this.load(); return Object.values(data.insights).filter(insight => insight.impact === impact); } async getAlignmentsByTechnicalFeature(feature) { const data = await this.load(); const searchTerm = feature.toLowerCase(); return Object.values(data.alignments).filter(alignment => alignment.technicalFeature.toLowerCase().includes(searchTerm)); } async getAlignmentsByBusinessGoal(goalId) { const data = await this.load(); return Object.values(data.alignments).filter(alignment => alignment.businessValue.primaryGoals.includes(goalId)); } async getConversationInsightCounts() { const data = await this.load(); return Object.values(data.conversations).map(conv => ({ conversationId: conv.id, insightCount: conv.insights.length })); } async getGoalProgressSummary() { const data = await this.load(); return Object.values(data.goals).map(goal => { const latestProgress = goal.progressHistory[goal.progressHistory.length - 1]; return { goalId: goal.id, completion: latestProgress?.completion || 0, confidence: goal.confidence }; }); } async getRecentActivity(days) { const data = await this.load(); const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - days); const activity = []; // Add conversations Object.values(data.conversations).forEach(conv => { if (new Date(conv.timestamp) >= cutoffDate) { activity.push({ type: 'conversation', id: conv.id, timestamp: conv.timestamp }); } }); // Add goals Object.values(data.goals).forEach(goal => { if (new Date(goal.lastUpdated) >= cutoffDate) { activity.push({ type: 'goal', id: goal.id, timestamp: goal.lastUpdated }); } }); // Add insights Object.values(data.insights).forEach(insight => { if (new Date(insight.timestamp) >= cutoffDate) { activity.push({ type: 'insight', id: insight.id, timestamp: insight.timestamp }); } }); return activity.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); } } //# sourceMappingURL=StorageAdapter.js.map