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
JavaScript
"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