UNPKG

lanonasis-memory

Version:

Memory as a Service integration - AI-powered memory management with semantic search (Compatible with CLI v3.0.6+)

353 lines 15.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.MemorySidebarProvider = void 0; const vscode = __importStar(require("vscode")); const EnhancedMemoryService_1 = require("../services/EnhancedMemoryService"); const os = __importStar(require("os")); class MemorySidebarProvider { constructor(_extensionUri, memoryService) { this._extensionUri = _extensionUri; this.memoryService = memoryService; this._cachedMemories = []; this._cacheTimestamp = 0; this.CACHE_DURATION = 30000; // 30 seconds this.userLabel = this.getUserLabel(); } resolveWebviewView(webviewView, _context, _token) { console.log('[Lanonasis] MemorySidebarProvider.resolveWebviewView called'); try { const activationChannel = vscode.window.createOutputChannel('Lanonasis Activation'); activationChannel.appendLine('[Lanonasis] MemorySidebarProvider.resolveWebviewView called'); } catch { // ignore in tests } try { this._view = webviewView; // Restrict resource access to only necessary directories webviewView.webview.options = { enableScripts: true, localResourceRoots: [ vscode.Uri.joinPath(this._extensionUri, 'media'), vscode.Uri.joinPath(this._extensionUri, 'out'), vscode.Uri.joinPath(this._extensionUri, 'images') ] }; webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); // Handle messages from the webview webviewView.webview.onDidReceiveMessage(async (data) => { try { switch (data.type) { case 'authenticate': await vscode.commands.executeCommand('lanonasis.authenticate', data.mode); break; case 'searchMemories': await this.handleSearch(data.query); break; case 'createMemory': await vscode.commands.executeCommand('lanonasis.createMemory'); break; case 'openMemory': await vscode.commands.executeCommand('lanonasis.openMemory', data.memory); break; case 'refresh': await this.refresh(true); // Force refresh when user clicks refresh button break; case 'showSettings': await vscode.commands.executeCommand('workbench.action.openSettings', 'lanonasis'); break; case 'getApiKey': await vscode.env.openExternal(vscode.Uri.parse('https://api.lanonasis.com')); break; case 'openCommandPalette': await vscode.commands.executeCommand('workbench.action.quickOpen', '>Lanonasis: Authenticate'); break; } } catch (error) { console.error('[Lanonasis] Error handling webview message:', error); this._view?.webview.postMessage({ type: 'error', message: `Action failed: ${error instanceof Error ? error.message : String(error)}` }); } }); // Initial load with error handling and delay for auth settlement setTimeout(async () => { try { // Give auth time to settle await new Promise(resolve => setTimeout(resolve, 1000)); await this.refresh(); } catch (error) { console.error('[Lanonasis] Failed to load sidebar:', error); this._view?.webview.postMessage({ type: 'error', message: 'Failed to load Lanonasis Memory. Please try refreshing or check authentication.' }); } }, 500); } catch (error) { console.error('[Lanonasis] Fatal error in resolveWebviewView:', error); vscode.window.showErrorMessage(`Lanonasis extension failed to load: ${error instanceof Error ? error.message : String(error)}`); } } async refresh(forceRefresh = false) { if (this._view) { try { const authenticated = this.memoryService.isAuthenticated(); // Show loading only if not using cache const now = Date.now(); const useCache = !forceRefresh && this._cachedMemories.length > 0 && (now - this._cacheTimestamp) < this.CACHE_DURATION; if (useCache) { // Use cached data immediately const enhancedInfo = this.memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService ? this.memoryService.getCapabilities() : null; this._view.webview.postMessage({ type: 'updateState', state: { authenticated: authenticated, memories: this._cachedMemories, loading: false, enhancedMode: enhancedInfo?.cliAvailable || false, cliVersion: enhancedInfo?.version || null, cached: true, brandIcon: this.brandIconUri, userName: this.userLabel } }); return; } this._view.webview.postMessage({ type: 'updateState', state: { loading: true } }); if (!authenticated) { this._cachedMemories = []; this._cacheTimestamp = 0; this._view.webview.postMessage({ type: 'updateState', state: { authenticated: false, memories: [], loading: false, enhancedMode: false, cliVersion: null, brandIcon: this.brandIconUri, userName: this.userLabel } }); return; } const memories = await this.memoryService.listMemories(50); const enhancedInfo = this.memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService ? this.memoryService.getCapabilities() : null; // Update cache this._cachedMemories = memories; this._cacheTimestamp = Date.now(); this._view.webview.postMessage({ type: 'updateState', state: { authenticated: authenticated, memories, loading: false, enhancedMode: enhancedInfo?.cliAvailable || false, cliVersion: enhancedInfo?.version || null, cached: false, brandIcon: this.brandIconUri, userName: this.userLabel } }); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); // Check for specific error types if (errorMsg.includes('Not authenticated') || errorMsg.includes('401')) { this._cachedMemories = []; this._cacheTimestamp = 0; this._view.webview.postMessage({ type: 'updateState', state: { authenticated: false, memories: [], loading: false } }); return; } // If we have cached data, show it with an error message if (this._cachedMemories.length > 0) { this._view.webview.postMessage({ type: 'error', message: `Failed to refresh: ${errorMsg}. Showing cached data.` }); const enhancedInfo = this.memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService ? this.memoryService.getCapabilities() : null; this._view.webview.postMessage({ type: 'updateState', state: { authenticated: true, memories: this._cachedMemories, loading: false, enhancedMode: enhancedInfo?.cliAvailable || false, cliVersion: enhancedInfo?.version || null, cached: true, brandIcon: this.brandIconUri, userName: this.userLabel } }); } else { // Network/timeout errors if (errorMsg.includes('fetch') || errorMsg.includes('timeout') || errorMsg.includes('Network')) { this._view.webview.postMessage({ type: 'error', message: `Connection failed: ${errorMsg}. Check your network and API endpoint configuration.` }); } else { this._view.webview.postMessage({ type: 'error', message: `Failed to load memories: ${errorMsg}` }); } this._view.webview.postMessage({ type: 'updateState', state: { loading: false } }); } } } } clearCache() { this._cachedMemories = []; this._cacheTimestamp = 0; } async handleSearch(query) { if (!this._view) return; if (!this.memoryService.isAuthenticated()) { this._view.webview.postMessage({ type: 'updateState', state: { authenticated: false, memories: [], loading: false } }); return; } try { this._view.webview.postMessage({ type: 'updateState', state: { loading: true } }); const results = await this.memoryService.searchMemories(query); this._view.webview.postMessage({ type: 'searchResults', results, query }); } catch (error) { this._view.webview.postMessage({ type: 'error', message: error instanceof Error ? error.message : 'Search failed' }); } finally { this._view.webview.postMessage({ type: 'updateState', state: { loading: false } }); } } _getHtmlForWebview(webview) { const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'sidebar.css')); const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'sidebar.js')); this.brandIconUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'images', 'brand-icon.svg')).toString(); // Get CSP const nonce = getNonce(); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}'; img-src ${webview.cspSource} https:; font-src ${webview.cspSource};"> <link href="${styleUri}" rel="stylesheet"> <title>Lanonasis Memory</title> </head> <body> <div id="root" data-brand-icon="${this.brandIconUri}" data-user-name="${this.userLabel}"> <div class="loading-state"> <div class="spinner"></div> <p>Loading Lanonasis Memory...</p> </div> </div> <script nonce="${nonce}" src="${scriptUri}"></script> </body> </html>`; } getUserLabel() { try { const userInfo = os.userInfo(); if (userInfo?.username) { return userInfo.username; } } catch { // ignore lookup errors } return vscode.env.appName || 'creator'; } } exports.MemorySidebarProvider = MemorySidebarProvider; MemorySidebarProvider.viewType = 'lanonasis.sidebar'; function getNonce() { let text = ''; const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < 32; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; } //# sourceMappingURL=MemorySidebarProvider.js.map