lanonasis-memory
Version:
Memory as a Service integration - AI-powered memory management with semantic search (Compatible with CLI v3.0.6+)
1,171 lines (1,132 loc) • 50.2 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.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const MemoryTreeProvider_1 = require("./providers/MemoryTreeProvider");
const MemoryCompletionProvider_1 = require("./providers/MemoryCompletionProvider");
const ApiKeyTreeProvider_1 = require("./providers/ApiKeyTreeProvider");
const MemorySidebarProvider_1 = require("./panels/MemorySidebarProvider");
const MemoryService_1 = require("./services/MemoryService");
const EnhancedMemoryService_1 = require("./services/EnhancedMemoryService");
const ApiKeyService_1 = require("./services/ApiKeyService");
const SecureApiKeyService_1 = require("./services/SecureApiKeyService");
const diagnostics_1 = require("./utils/diagnostics");
async function activate(context) {
console.log('Lanonasis Memory Extension is now active');
const outputChannel = vscode.window.createOutputChannel('Lanonasis');
const secureApiKeyService = new SecureApiKeyService_1.SecureApiKeyService(context, outputChannel);
await secureApiKeyService.initialize();
let memoryService;
try {
memoryService = new EnhancedMemoryService_1.EnhancedMemoryService(secureApiKeyService);
console.log('Using Enhanced Memory Service with CLI integration');
}
catch (error) {
console.warn('Enhanced Memory Service not available, using basic service:', error);
memoryService = new MemoryService_1.MemoryService(secureApiKeyService);
}
const apiKeyService = new ApiKeyService_1.ApiKeyService(secureApiKeyService);
const sidebarProvider = new MemorySidebarProvider_1.MemorySidebarProvider(context.extensionUri, memoryService);
context.subscriptions.push(vscode.window.registerWebviewViewProvider(MemorySidebarProvider_1.MemorySidebarProvider.viewType, sidebarProvider));
const memoryTreeProvider = new MemoryTreeProvider_1.MemoryTreeProvider(memoryService);
const apiKeyTreeProvider = new ApiKeyTreeProvider_1.ApiKeyTreeProvider(apiKeyService);
context.subscriptions.push(vscode.window.registerTreeDataProvider('lanonasisMemories', memoryTreeProvider), vscode.window.registerTreeDataProvider('lanonasisApiKeys', apiKeyTreeProvider));
const completionProvider = new MemoryCompletionProvider_1.MemoryCompletionProvider(memoryService);
context.subscriptions.push(vscode.languages.registerCompletionItemProvider({ scheme: 'file' }, completionProvider, '@', '#', '//'));
const configuration = vscode.workspace.getConfiguration('lanonasis');
await vscode.commands.executeCommand('setContext', 'lanonasis.enabled', true);
await vscode.commands.executeCommand('setContext', 'lanonasis.enableApiKeyManagement', configuration.get('enableApiKeyManagement', true));
await vscode.commands.executeCommand('setContext', 'lanonasis.authenticated', false);
memoryTreeProvider.setAuthenticated(false);
apiKeyTreeProvider.setAuthenticated(false);
const refreshServices = async () => {
try {
await memoryService.refreshClient();
}
catch (error) {
outputChannel.appendLine(`[Auth] Failed to refresh memory service: ${error instanceof Error ? error.message : String(error)}`);
}
try {
apiKeyService.refreshConfig();
}
catch (error) {
outputChannel.appendLine(`[Auth] Failed to refresh API key service: ${error instanceof Error ? error.message : String(error)}`);
}
};
const applyAuthenticationState = async (authenticated) => {
await vscode.commands.executeCommand('setContext', 'lanonasis.authenticated', authenticated);
memoryTreeProvider.setAuthenticated(authenticated);
apiKeyTreeProvider.setAuthenticated(authenticated);
await sidebarProvider.refresh();
};
const announceEnhancedCapabilities = () => {
if (!(memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService)) {
return;
}
const capabilities = memoryService.getCapabilities();
if (capabilities?.cliAvailable && capabilities.goldenContract) {
vscode.window.showInformationMessage('🚀 Lanonasis Memory: CLI v1.5.2+ detected! Enhanced performance active.', 'Show Details').then(selection => {
if (selection === 'Show Details') {
vscode.commands.executeCommand('lanonasis.showConnectionInfo');
}
});
}
};
const handleAuthenticationSuccess = async () => {
await refreshServices();
await applyAuthenticationState(true);
announceEnhancedCapabilities();
};
const handleAuthenticationCleared = async () => {
try {
await memoryService.refreshClient();
}
catch (error) {
outputChannel.appendLine(`[ClearAuth] Failed to refresh memory service: ${error instanceof Error ? error.message : String(error)}`);
}
await applyAuthenticationState(false);
};
// Register authentication command FIRST before any other code tries to call it
const authenticateCommand = vscode.commands.registerCommand('lanonasis.authenticate', async (mode) => {
try {
let apiKey = null;
if (mode === 'oauth') {
apiKey = await secureApiKeyService.authenticateWithOAuthFlow();
}
else if (mode === 'apikey') {
apiKey = await secureApiKeyService.promptForApiKeyEntry();
}
else {
apiKey = await secureApiKeyService.promptForAuthentication();
}
if (apiKey) {
await handleAuthenticationSuccess();
vscode.window.showInformationMessage('✅ Successfully authenticated with Lanonasis Memory');
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
vscode.window.showErrorMessage(`Authentication failed: ${message}`);
outputChannel.appendLine(`[Auth] Error: ${message}`);
}
});
const promptForAuthenticationIfMissing = async () => {
const selection = await vscode.window.showInformationMessage('Lanonasis Memory: No authentication configured. Choose how you would like to connect.', 'Connect in Browser', 'Enter API Key', 'Maybe Later');
if (selection === 'Connect in Browser') {
vscode.commands.executeCommand('lanonasis.authenticate', 'oauth');
}
else if (selection === 'Enter API Key') {
vscode.commands.executeCommand('lanonasis.authenticate', 'apikey');
}
};
const commands = [
authenticateCommand,
vscode.commands.registerCommand('lanonasis.searchMemory', async () => {
await searchMemories(memoryService);
}),
vscode.commands.registerCommand('lanonasis.createMemory', async () => {
await createMemoryFromSelection(memoryService);
}),
vscode.commands.registerCommand('lanonasis.createMemoryFromFile', async () => {
await createMemoryFromFile(memoryService);
}),
// Note: lanonasis.authenticate is registered earlier (line 125) to prevent timing issues
vscode.commands.registerCommand('lanonasis.refreshMemories', async () => {
memoryTreeProvider.refresh();
await sidebarProvider.refresh();
}),
vscode.commands.registerCommand('lanonasis.openMemory', (memory) => {
openMemoryInEditor(memory);
}),
vscode.commands.registerCommand('lanonasis.switchMode', async () => {
await switchConnectionMode(memoryService, apiKeyService);
memoryTreeProvider.refresh();
await sidebarProvider.refresh();
}),
vscode.commands.registerCommand('lanonasis.manageApiKeys', async () => {
await manageApiKeys(apiKeyService);
}),
vscode.commands.registerCommand('lanonasis.createProject', async () => {
await createProject(apiKeyService, apiKeyTreeProvider);
}),
vscode.commands.registerCommand('lanonasis.viewProjects', async () => {
await viewProjects(apiKeyService);
}),
vscode.commands.registerCommand('lanonasis.refreshApiKeys', async () => {
apiKeyTreeProvider.refresh(true);
}),
// Context menu commands for API Keys tree
vscode.commands.registerCommand('lanonasis.viewProjectDetails', async (item) => {
if (item && item.project) {
await showProjectDetails(item.project, apiKeyService);
}
}),
vscode.commands.registerCommand('lanonasis.viewApiKeyDetails', async (item) => {
if (item && item.apiKey) {
await showApiKeyDetails(item.apiKey);
}
}),
vscode.commands.registerCommand('lanonasis.createApiKey', async (item) => {
if (item && item.project) {
await createApiKeyForProject(item.project, apiKeyService, apiKeyTreeProvider);
}
else {
await createApiKey(apiKeyService, apiKeyTreeProvider);
}
}),
vscode.commands.registerCommand('lanonasis.rotateApiKey', async (item) => {
if (item && item.apiKey) {
await rotateApiKey(item.apiKey, apiKeyService, apiKeyTreeProvider);
}
}),
vscode.commands.registerCommand('lanonasis.deleteApiKey', async (item) => {
if (item && item.apiKey) {
await deleteApiKey(item.apiKey, apiKeyService, apiKeyTreeProvider);
}
}),
vscode.commands.registerCommand('lanonasis.deleteProject', async (item) => {
if (item && item.project) {
await deleteProject(item.project, apiKeyService, apiKeyTreeProvider);
}
}),
vscode.commands.registerCommand('lanonasis.showConnectionInfo', async () => {
if (memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService) {
await memoryService.showConnectionInfo();
}
else {
vscode.window.showInformationMessage('Connection info available in Enhanced Memory Service. Upgrade to CLI integration for more details.');
}
}),
vscode.commands.registerCommand('lanonasis.configureApiKey', async (mode) => {
await vscode.commands.executeCommand('lanonasis.authenticate', mode);
}),
vscode.commands.registerCommand('lanonasis.clearApiKey', async () => {
try {
const hasApiKey = await secureApiKeyService.hasApiKey();
if (!hasApiKey) {
vscode.window.showInformationMessage('No API key is currently configured.');
return;
}
const confirmed = await vscode.window.showWarningMessage('Are you sure you want to clear your API key? This will require re-authentication.', { modal: true }, 'Clear API Key');
if (confirmed === 'Clear API Key') {
await secureApiKeyService.deleteApiKey();
vscode.window.showInformationMessage('API key cleared successfully.');
outputChannel.appendLine('[ClearApiKey] API key removed from secure storage');
await handleAuthenticationCleared();
await promptForAuthenticationIfMissing();
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
vscode.window.showErrorMessage(`Failed to clear API key: ${message}`);
outputChannel.appendLine(`[ClearApiKey] Error: ${message}`);
}
}),
vscode.commands.registerCommand('lanonasis.checkApiKeyStatus', async () => {
try {
const hasApiKey = await secureApiKeyService.hasApiKey();
const status = hasApiKey ? '✅ Configured and stored securely' : '❌ Not configured';
if (hasApiKey) {
vscode.window.showInformationMessage(`API Key Status: ${status}`, 'Test Connection', 'View Security Info').then(async (selection) => {
if (selection === 'Test Connection') {
vscode.commands.executeCommand('lanonasis.testConnection');
}
else if (selection === 'View Security Info') {
vscode.env.openExternal(vscode.Uri.parse('https://docs.lanonasis.com/security/api-keys'));
}
});
}
else {
vscode.window.showInformationMessage(`API Key Status: ${status}`, 'Connect in Browser', 'Enter API Key').then((selection) => {
if (selection === 'Connect in Browser') {
vscode.commands.executeCommand('lanonasis.authenticate', 'oauth');
}
else if (selection === 'Enter API Key') {
vscode.commands.executeCommand('lanonasis.authenticate', 'apikey');
}
});
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
vscode.window.showErrorMessage(`Failed to check API key status: ${message}`);
outputChannel.appendLine(`[CheckApiKeyStatus] Error: ${message}`);
}
}),
vscode.commands.registerCommand('lanonasis.testConnection', async () => {
try {
const hasApiKey = await secureApiKeyService.hasApiKey();
if (!hasApiKey) {
vscode.window.showWarningMessage('❌ No API key configured.');
return;
}
await memoryService.testConnection();
vscode.window.showInformationMessage('✅ Connection test successful!');
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
vscode.window.showErrorMessage(`Connection test failed: ${message}`);
outputChannel.appendLine(`[TestConnection] Error: ${message}`);
}
}),
vscode.commands.registerCommand('lanonasis.runDiagnostics', async () => {
try {
outputChannel.show();
outputChannel.appendLine('Running comprehensive diagnostics...\n');
const health = await (0, diagnostics_1.runDiagnostics)(context, secureApiKeyService, memoryService, outputChannel);
const report = (0, diagnostics_1.formatDiagnosticResults)(health);
// Show report in a new document
const doc = await vscode.workspace.openTextDocument({
content: report,
language: 'markdown'
});
await vscode.window.showTextDocument(doc);
// Show summary notification
const statusEmoji = {
healthy: '✅',
degraded: '⚠️',
critical: '❌'
};
const message = `${statusEmoji[health.overall]} System Health: ${health.overall.toUpperCase()}`;
if (health.overall === 'healthy') {
vscode.window.showInformationMessage(message, 'View Report').then(action => {
if (action === 'View Report') {
outputChannel.show();
}
});
}
else if (health.overall === 'degraded') {
vscode.window.showWarningMessage(message, 'View Report', 'Fix Issues').then(action => {
if (action === 'View Report') {
outputChannel.show();
}
});
}
else {
vscode.window.showErrorMessage(message, 'View Report', 'Get Help').then(action => {
if (action === 'View Report') {
outputChannel.show();
}
else if (action === 'Get Help') {
vscode.env.openExternal(vscode.Uri.parse('https://docs.lanonasis.com/troubleshooting'));
}
});
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
vscode.window.showErrorMessage(`Diagnostics failed: ${message}`);
outputChannel.appendLine(`[Diagnostics] Fatal error: ${message}`);
}
}),
vscode.commands.registerCommand('lanonasis.showLogs', () => {
outputChannel.show();
})
];
context.subscriptions.push(...commands);
if (memoryService instanceof EnhancedMemoryService_1.EnhancedMemoryService) {
context.subscriptions.push(memoryService);
}
const hasStoredKey = await secureApiKeyService.hasApiKey();
if (hasStoredKey) {
await handleAuthenticationSuccess();
}
else {
await applyAuthenticationState(false);
}
const isFirstTime = context.globalState.get('lanonasis.firstTime', true);
if (isFirstTime) {
showWelcomeMessage();
await context.globalState.update('lanonasis.firstTime', false);
}
if (!hasStoredKey && !isFirstTime) {
await promptForAuthenticationIfMissing();
}
}
async function searchMemories(memoryService) {
const query = await vscode.window.showInputBox({
prompt: 'Search memories',
placeHolder: 'Enter search query...'
});
if (!query)
return;
try {
vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Searching memories...',
cancellable: false
}, async () => {
const results = await memoryService.searchMemories(query);
await showSearchResults(results, query);
});
}
catch (error) {
vscode.window.showErrorMessage(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function showSearchResults(results, query) {
if (results.length === 0) {
vscode.window.showInformationMessage(`No memories found for "${query}"`);
return;
}
const items = results.map(memory => ({
label: memory.title,
description: memory.memory_type,
detail: `${memory.content.substring(0, 100)}${memory.content.length > 100 ? '...' : ''}`,
memory
}));
const selected = await vscode.window.showQuickPick(items, {
placeHolder: `Found ${results.length} memories for "${query}"`
});
if (selected) {
openMemoryInEditor(selected.memory);
}
}
async function createMemoryFromSelection(memoryService) {
const editor = vscode.window.activeTextEditor;
if (!editor || editor.selection.isEmpty) {
vscode.window.showWarningMessage('Please select some text to create a memory');
return;
}
const selectedText = editor.document.getText(editor.selection);
const fileName = editor.document.fileName;
const lineNumber = editor.selection.start.line + 1;
const title = await vscode.window.showInputBox({
prompt: 'Memory title',
value: `Code from ${fileName}:${lineNumber}`
});
if (!title)
return;
const config = vscode.workspace.getConfiguration('lanonasis');
const defaultType = config.get('defaultMemoryType', 'context');
try {
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Creating memory...',
cancellable: false
}, async () => {
await memoryService.createMemory({
title,
content: selectedText,
memory_type: defaultType,
tags: ['vscode', 'selection'],
metadata: {
source: 'vscode',
fileName,
lineNumber: lineNumber.toString()
}
});
});
vscode.window.showInformationMessage(`Memory "${title}" created successfully`);
vscode.commands.executeCommand('lanonasis.refreshMemories');
}
catch (error) {
vscode.window.showErrorMessage(`Failed to create memory: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function createMemoryFromFile(memoryService) {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showWarningMessage('No active editor');
return;
}
const content = editor.document.getText();
const fileName = editor.document.fileName;
const title = await vscode.window.showInputBox({
prompt: 'Memory title',
value: `File: ${fileName.split('/').pop()}`
});
if (!title)
return;
const config = vscode.workspace.getConfiguration('lanonasis');
const defaultType = config.get('defaultMemoryType', 'context');
try {
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Creating memory from file...',
cancellable: false
}, async () => {
await memoryService.createMemory({
title,
content,
memory_type: defaultType,
tags: ['vscode', 'file'],
metadata: {
source: 'vscode-file',
fileName,
fullPath: fileName
}
});
});
vscode.window.showInformationMessage(`Memory "${title}" created from file`);
vscode.commands.executeCommand('lanonasis.refreshMemories');
}
catch (error) {
vscode.window.showErrorMessage(`Failed to create memory: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
function openMemoryInEditor(memory) {
const content = `# ${memory.title}\n\n**Type:** ${memory.memory_type}\n**Created:** ${new Date(memory.created_at).toLocaleString()}\n\n---\n\n${memory.content}`;
vscode.workspace.openTextDocument({
content,
language: 'markdown'
}).then(doc => {
vscode.window.showTextDocument(doc);
});
}
async function checkEnhancedAuthenticationStatus(enhancedService) {
const config = vscode.workspace.getConfiguration('lanonasis');
const apiKey = config.get('apiKey');
const authenticated = !!apiKey && apiKey.trim().length > 0;
vscode.commands.executeCommand('setContext', 'lanonasis.authenticated', authenticated);
if (!authenticated) {
const result = await vscode.window.showInformationMessage('Lanonasis Memory: No API key configured. Would you like to set it up now?', 'Configure', 'Later');
if (result === 'Configure') {
vscode.commands.executeCommand('lanonasis.authenticate');
}
return;
}
// Check CLI capabilities
const capabilities = enhancedService.getCapabilities();
if (capabilities?.cliAvailable && capabilities.goldenContract) {
vscode.window.showInformationMessage('🚀 Lanonasis Memory: CLI v1.5.2+ detected! Enhanced performance active.', 'Show Details').then(selection => {
if (selection === 'Show Details') {
vscode.commands.executeCommand('lanonasis.showConnectionInfo');
}
});
}
}
function showWelcomeMessage() {
const message = `🎉 Welcome to Lanonasis Memory Assistant!
Your AI-powered memory management system is ready. Let's get you started!`;
vscode.window.showInformationMessage(message, 'Connect in Browser', 'Enter API Key', 'Get API Key', 'Learn More').then(selection => {
if (selection === 'Connect in Browser') {
vscode.commands.executeCommand('lanonasis.authenticate', 'oauth');
}
else if (selection === 'Enter API Key') {
vscode.commands.executeCommand('lanonasis.authenticate', 'apikey');
}
else if (selection === 'Get API Key') {
vscode.env.openExternal(vscode.Uri.parse('https://api.lanonasis.com'));
}
else if (selection === 'Learn More') {
showOnboardingGuide();
}
});
}
function showOnboardingGuide() {
const guide = `# 🧠 Lanonasis Memory Assistant - Quick Start Guide
Welcome to your AI-powered memory management system! This guide will help you get started in just a few minutes.
## 🚀 Getting Started
### Step 1: Authenticate
Choose one of two authentication methods:
**Option A: Browser Authentication (Recommended)**
1. Click the Lanonasis icon in the sidebar
2. Click "Continue in Browser"
3. Sign in with your Lanonasis account
4. Authorize the extension
**Option B: API Key Authentication**
1. Visit https://api.lanonasis.com to get your API key
2. Click the Lanonasis icon in the sidebar
3. Click "Enter API Key"
4. Paste your API key when prompted
### Step 2: Create Your First Memory
There are multiple ways to create memories:
**From Selected Text:**
1. Select any text in your editor
2. Press \`Ctrl+Shift+Alt+M\` (or \`Cmd+Shift+Alt+M\` on Mac)
3. Give your memory a title
4. Done! Your memory is saved
**From Current File:**
1. Open any file
2. Run command: \`Lanonasis: Create Memory from Current File\`
3. Give your memory a title
4. The entire file content is saved as a memory
**From Sidebar:**
1. Click the Lanonasis icon in the sidebar
2. Click the "Create" button
3. Select text first, then click to save
### Step 3: Search Your Memories
**Quick Search:**
- Press \`Ctrl+Shift+M\` (or \`Cmd+Shift+M\` on Mac)
- Type your search query
- Select a memory to open it
**Sidebar Search:**
- Open the Lanonasis sidebar
- Use the search box at the top
- Results appear instantly
## 🎯 Key Features
### Memory Types
Memories are automatically organized by type:
- **Context**: Code snippets and contextual information
- **Project**: Project-specific notes and documentation
- **Knowledge**: General knowledge and learnings
- **Reference**: Reference materials and guides
- **Conversation**: Discussion notes and meeting summaries
### CLI Integration
If you have \`@lanonasis/cli\` v3.0.6+ installed, you'll get:
- ⚡ Faster performance
- 🔄 Enhanced caching
- 🚀 Advanced features
Install with: \`npm install -g @lanonasis/cli\`
### API Key Management
Manage multiple API keys for different projects:
- Press \`Ctrl+Shift+K\` (or \`Cmd+Shift+K\` on Mac)
- Create, view, and organize API keys
- Support for different environments (dev, staging, prod)
## 🛠️ Useful Commands
Open the Command Palette (\`Ctrl+Shift+P\` or \`Cmd+Shift+P\`) and try:
- \`Lanonasis: Search Memories\` - Search your memories
- \`Lanonasis: Create Memory from Selection\` - Save selected text
- \`Lanonasis: Manage API Keys\` - Manage your API keys
- \`Lanonasis: Run System Diagnostics\` - Check system health
- \`Lanonasis: Show Extension Logs\` - View detailed logs
- \`Lanonasis: Test Connection\` - Test your connection
- \`Lanonasis: Switch Gateway/Direct API Mode\` - Change connection mode
## 🔧 Troubleshooting
### Connection Issues?
1. Run: \`Lanonasis: Run System Diagnostics\`
2. Check the diagnostics report for issues
3. Follow recommended actions
### Authentication Problems?
1. Run: \`Lanonasis: Check API Key Status\`
2. Clear and re-enter your API key if needed
3. Try OAuth authentication as an alternative
### Need Help?
- 📚 Documentation: https://docs.lanonasis.com
- 🐛 Report Issues: https://github.com/lanonasis/lanonasis-maas/issues
- 💬 Community: https://discord.gg/lanonasis
## ⚙️ Settings
Configure the extension to your liking:
1. Go to: \`File > Preferences > Settings\`
2. Search for: \`Lanonasis\`
3. Customize:
- API URLs
- Default memory types
- Search limits
- Performance options
- And more!
## 🎓 Tips & Tricks
1. **Use Keyboard Shortcuts**: Master the shortcuts for faster workflow
2. **Tag Your Memories**: Add tags during creation for better organization
3. **Regular Backups**: Export important memories regularly
4. **CLI Integration**: Install the CLI for best performance
5. **Organize by Project**: Use project-specific memories for better context
## 🎉 You're All Set!
You're now ready to use Lanonasis Memory Assistant. Start by:
1. Authenticating (if you haven't already)
2. Creating your first memory
3. Searching and exploring
Happy memory management! 🧠✨
---
**Quick Reference:**
- Search: \`Ctrl+Shift+M\` / \`Cmd+Shift+M\`
- Create from Selection: \`Ctrl+Shift+Alt+M\` / \`Cmd+Shift+Alt+M\`
- Manage API Keys: \`Ctrl+Shift+K\` / \`Cmd+Shift+K\`
`;
vscode.workspace.openTextDocument({
content: guide,
language: 'markdown'
}).then(doc => {
vscode.window.showTextDocument(doc);
});
}
async function switchConnectionMode(memoryService, apiKeyService) {
const config = vscode.workspace.getConfiguration('lanonasis');
const currentUseGateway = config.get('useGateway', true);
const options = [
{
label: '🌐 Gateway Mode (Recommended)',
description: 'Use Onasis Gateway for optimized routing and caching',
picked: currentUseGateway,
value: true
},
{
label: '🔗 Direct API Mode',
description: 'Connect directly to memory service',
picked: !currentUseGateway,
value: false
}
];
const selected = await vscode.window.showQuickPick(options, {
placeHolder: 'Choose connection mode',
ignoreFocusOut: true
});
if (!selected)
return;
try {
await config.update('useGateway', selected.value, vscode.ConfigurationTarget.Global);
await memoryService.refreshClient();
apiKeyService.refreshConfig();
const modeName = selected.value ? 'Gateway' : 'Direct API';
vscode.window.showInformationMessage(`Switched to ${modeName} mode. Testing connection...`);
// Test the new connection
await memoryService.testConnection();
vscode.window.showInformationMessage(`✅ ${modeName} mode active and connected`);
vscode.commands.executeCommand('lanonasis.refreshMemories');
}
catch (error) {
vscode.window.showErrorMessage(`Failed to switch mode: ${error instanceof Error ? error.message : 'Unknown error'}`);
// Revert the setting
await config.update('useGateway', currentUseGateway, vscode.ConfigurationTarget.Global);
await memoryService.refreshClient();
apiKeyService.refreshConfig();
}
}
// ============================================================================
// API KEY MANAGEMENT FUNCTIONS
// ============================================================================
async function manageApiKeys(apiKeyService) {
const quickPickItems = [
{
label: '$(key) View API Keys',
description: 'View all API keys across projects',
command: 'view'
},
{
label: '$(add) Create API Key',
description: 'Create a new API key',
command: 'create'
},
{
label: '$(folder) Manage Projects',
description: 'Create and manage API key projects',
command: 'projects'
},
{
label: '$(refresh) Refresh',
description: 'Refresh API key data',
command: 'refresh'
}
];
const selected = await vscode.window.showQuickPick(quickPickItems, {
placeHolder: 'Choose an API key management action'
});
if (!selected)
return;
switch (selected.command) {
case 'view':
await viewApiKeys(apiKeyService);
break;
case 'create':
await createApiKey(apiKeyService);
break;
case 'projects':
await viewProjects(apiKeyService);
break;
case 'refresh':
vscode.commands.executeCommand('lanonasis.refreshApiKeys');
break;
}
}
async function viewApiKeys(apiKeyService) {
try {
vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Loading API keys...',
cancellable: false
}, async () => {
const apiKeys = await apiKeyService.getApiKeys();
if (apiKeys.length === 0) {
vscode.window.showInformationMessage('No API keys found. Create your first API key to get started.');
return;
}
const items = apiKeys.map(key => ({
label: key.name,
description: `${key.environment} • ${key.keyType} • ${key.accessLevel}`,
detail: `Project: ${key.projectId} | Created: ${new Date(key.createdAt).toLocaleDateString()}`,
apiKey: key
}));
const selected = await vscode.window.showQuickPick(items, {
placeHolder: `Select an API key (${apiKeys.length} found)`
});
if (selected) {
await showApiKeyDetails(selected.apiKey);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to load API keys: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function createApiKey(apiKeyService, apiKeyTreeProvider) {
try {
// Get projects first
const projects = await apiKeyService.getProjects();
if (projects.length === 0) {
const createProjectResponse = await vscode.window.showInformationMessage('No projects found. You need to create a project first.', 'Create Project', 'Cancel');
if (createProjectResponse === 'Create Project') {
await createProject(apiKeyService, undefined);
}
return;
}
// Select project
const projectItems = projects.map(p => ({
label: p.name,
description: p.description || 'No description',
project: p
}));
const selectedProject = await vscode.window.showQuickPick(projectItems, {
placeHolder: 'Select a project for the API key'
});
if (!selectedProject)
return;
// Get key details
const name = await vscode.window.showInputBox({
prompt: 'API Key Name',
placeHolder: 'Enter a name for your API key'
});
if (!name)
return;
const value = await vscode.window.showInputBox({
prompt: 'API Key Value',
placeHolder: 'Enter the API key value',
password: true
});
if (!value)
return;
const keyTypes = [
{ label: 'API Key', value: 'api_key' },
{ label: 'Database URL', value: 'database_url' },
{ label: 'OAuth Token', value: 'oauth_token' },
{ label: 'Certificate', value: 'certificate' },
{ label: 'SSH Key', value: 'ssh_key' },
{ label: 'Webhook Secret', value: 'webhook_secret' },
{ label: 'Encryption Key', value: 'encryption_key' }
];
const selectedKeyType = await vscode.window.showQuickPick(keyTypes, {
placeHolder: 'Select key type'
});
if (!selectedKeyType)
return;
// Environment selection
const config = vscode.workspace.getConfiguration('lanonasis');
const defaultEnv = config.get('defaultEnvironment', 'development');
const environments = [
{ label: 'Development', value: 'development', picked: defaultEnv === 'development' },
{ label: 'Staging', value: 'staging', picked: defaultEnv === 'staging' },
{ label: 'Production', value: 'production', picked: defaultEnv === 'production' }
];
const selectedEnvironment = await vscode.window.showQuickPick(environments, {
placeHolder: 'Select environment'
});
if (!selectedEnvironment)
return;
// Create the API key
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Creating API key...',
cancellable: false
}, async () => {
await apiKeyService.createApiKey({
name,
value,
keyType: selectedKeyType.value,
environment: selectedEnvironment.value,
accessLevel: 'team',
projectId: selectedProject.project.id
});
});
vscode.window.showInformationMessage(`API key "${name}" created successfully`);
vscode.commands.executeCommand('lanonasis.refreshApiKeys');
}
catch (error) {
vscode.window.showErrorMessage(`Failed to create API key: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function createProject(apiKeyService, apiKeyTreeProvider) {
try {
const name = await vscode.window.showInputBox({
prompt: 'Project Name',
placeHolder: 'Enter a name for your project'
});
if (!name)
return;
const description = await vscode.window.showInputBox({
prompt: 'Project Description (optional)',
placeHolder: 'Enter a description for your project'
});
const config = vscode.workspace.getConfiguration('lanonasis');
let organizationId = config.get('organizationId');
if (!organizationId) {
const orgId = await vscode.window.showInputBox({
prompt: 'Organization ID',
placeHolder: 'Enter your organization ID'
});
if (!orgId)
return;
await config.update('organizationId', orgId, vscode.ConfigurationTarget.Global);
organizationId = orgId;
}
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Creating project...',
cancellable: false
}, async () => {
const project = await apiKeyService.createProject({
name,
description,
organizationId: organizationId
});
if (apiKeyTreeProvider) {
await apiKeyTreeProvider.addProject(project);
}
});
vscode.window.showInformationMessage(`Project "${name}" created successfully`);
vscode.commands.executeCommand('lanonasis.refreshApiKeys');
}
catch (error) {
vscode.window.showErrorMessage(`Failed to create project: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function viewProjects(apiKeyService) {
try {
vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Loading projects...',
cancellable: false
}, async () => {
const projects = await apiKeyService.getProjects();
if (projects.length === 0) {
const createProjectResponse = await vscode.window.showInformationMessage('No projects found. Create your first project to get started.', 'Create Project', 'Cancel');
if (createProjectResponse === 'Create Project') {
await createProject(apiKeyService, undefined);
}
return;
}
const items = projects.map(project => ({
label: project.name,
description: project.description || 'No description',
detail: `Organization: ${project.organizationId} | Created: ${new Date(project.createdAt).toLocaleDateString()}`,
project
}));
const selected = await vscode.window.showQuickPick(items, {
placeHolder: `Select a project (${projects.length} found)`
});
if (selected) {
await showProjectDetails(selected.project, apiKeyService);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to load projects: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function showApiKeyDetails(apiKey) {
const content = `# API Key: ${apiKey.name}
**Type:** ${apiKey.keyType}
**Environment:** ${apiKey.environment}
**Access Level:** ${apiKey.accessLevel}
**Project ID:** ${apiKey.projectId}
**Created:** ${new Date(apiKey.createdAt).toLocaleString()}
${apiKey.expiresAt ? `**Expires:** ${new Date(apiKey.expiresAt).toLocaleString()}` : '**Expires:** Never'}
## Tags
${apiKey.tags.length > 0 ? apiKey.tags.map((tag) => `- ${tag}`).join('\n') : 'No tags'}
## Metadata
\`\`\`json
${JSON.stringify(apiKey.metadata, null, 2)}
\`\`\``;
vscode.workspace.openTextDocument({
content,
language: 'markdown'
}).then((doc) => {
vscode.window.showTextDocument(doc);
});
}
async function showProjectDetails(project, apiKeyService) {
try {
const apiKeys = await apiKeyService.getApiKeys(project.id);
const content = `# Project: ${project.name}
**Description:** ${project.description || 'No description'}
**Organization ID:** ${project.organizationId}
**Created:** ${new Date(project.createdAt).toLocaleString()}
**Team Members:** ${project.teamMembers.length}
## API Keys (${apiKeys.length})
${apiKeys.length > 0 ?
apiKeys.map((key) => `- **${key.name}** (${key.keyType}, ${key.environment})`).join('\n') :
'No API keys found in this project'}
## Settings
\`\`\`json
${JSON.stringify(project.settings, null, 2)}
\`\`\``;
vscode.workspace.openTextDocument({
content,
language: 'markdown'
}).then((doc) => {
vscode.window.showTextDocument(doc);
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to load project details: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function createApiKeyForProject(project, apiKeyService, apiKeyTreeProvider) {
try {
const name = await vscode.window.showInputBox({
prompt: 'API Key Name',
placeHolder: 'Enter a name for your API key'
});
if (!name)
return;
const value = await vscode.window.showInputBox({
prompt: 'API Key Value',
placeHolder: 'Enter the API key value',
password: true
});
if (!value)
return;
const keyTypes = [
{ label: 'API Key', value: 'api_key' },
{ label: 'Database URL', value: 'database_url' },
{ label: 'OAuth Token', value: 'oauth_token' },
{ label: 'Certificate', value: 'certificate' },
{ label: 'SSH Key', value: 'ssh_key' },
{ label: 'Webhook Secret', value: 'webhook_secret' },
{ label: 'Encryption Key', value: 'encryption_key' }
];
const selectedKeyType = await vscode.window.showQuickPick(keyTypes, {
placeHolder: 'Select key type'
});
if (!selectedKeyType)
return;
const environments = [
{ label: 'Development', description: 'For development use' },
{ label: 'Staging', description: 'For staging/testing' },
{ label: 'Production', description: 'For production use' }
];
const selectedEnv = await vscode.window.showQuickPick(environments, {
placeHolder: 'Select environment'
});
if (!selectedEnv)
return;
const accessLevels = [
{ label: 'Public', description: 'Publicly accessible' },
{ label: 'Authenticated', description: 'Requires authentication' },
{ label: 'Team', description: 'Team members only' },
{ label: 'Admin', description: 'Administrators only' },
{ label: 'Enterprise', description: 'Enterprise level access' }
];
const selectedAccess = await vscode.window.showQuickPick(accessLevels, {
placeHolder: 'Select access level'
});
if (!selectedAccess)
return;
const request = {
name,
value,
keyType: selectedKeyType.value,
environment: selectedEnv.label.toLowerCase(),
accessLevel: selectedAccess.label.toLowerCase(),
projectId: project.id
};
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Creating API key...',
cancellable: false
}, async () => {
const apiKey = await apiKeyService.createApiKey(request);
vscode.window.showInformationMessage(`API key "${apiKey.name}" created successfully!`);
if (apiKeyTreeProvider) {
await apiKeyTreeProvider.addApiKey(project.id, apiKey);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to create API key: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function rotateApiKey(apiKey, apiKeyService, apiKeyTreeProvider) {
try {
const confirmed = await vscode.window.showWarningMessage(`Are you sure you want to rotate API key "${apiKey.name}"? The old key will be invalidated.`, { modal: true }, 'Rotate Key');
if (confirmed !== 'Rotate Key')
return;
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Rotating API key...',
cancellable: false
}, async () => {
const rotated = await apiKeyService.rotateApiKey(apiKey.id);
vscode.window.showInformationMessage(`API key "${rotated.name}" rotated successfully!`);
if (apiKeyTreeProvider) {
await apiKeyTreeProvider.updateApiKey(apiKey.projectId, rotated);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to rotate API key: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function deleteApiKey(apiKey, apiKeyService, apiKeyTreeProvider) {
try {
const confirmed = await vscode.window.showWarningMessage(`Are you sure you want to delete API key "${apiKey.name}"? This action cannot be undone.`, { modal: true }, 'Delete');
if (confirmed !== 'Delete')
return;
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Deleting API key...',
cancellable: false
}, async () => {
await apiKeyService.deleteApiKey(apiKey.id);
vscode.window.showInformationMessage(`API key "${apiKey.name}" deleted successfully.`);
if (apiKeyTreeProvider) {
await apiKeyTreeProvider.removeApiKey(apiKey.projectId, apiKey.id);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to delete API key: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async function deleteProject(project, apiKeyService, apiKeyTreeProvider) {
try {
const confirmed = await vscode.window.showWarningMessage(`Are you sure you want to delete project "${project.name}"? All API keys in this project will also be deleted. This action cannot be undone.`, { modal: true }, 'Delete');
if (confirmed !== 'Delete')
return;
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'Deleting project...',
cancellable: false
}, async () => {
await apiKeyService.deleteProject(project.id);
vscode.window.showInformationMessage(`Project "${project.name}" deleted successfully.`);
if (apiKeyTreeProvider) {
await apiKeyTreeProvider.removeProject(project.id);
}
});
}
catch (error) {
vscode.window.showErrorMessage(`Failed to delete project: ${error instanc