import * as vscode from 'vscode'; import { MultiStreamService } from './multiStreamService'; import { LogEntry, LogFilter } from './types'; export class LogWebviewProvider implements vscode.WebviewViewProvider { private _view?: vscode.WebviewView; private _disposables: vscode.Disposable[] = []; constructor( private readonly _extensionUri: vscode.Uri, private readonly multiStreamService: MultiStreamService ) { this.multiStreamService.onDidChangeLog(() => { this.updateWebview(); }, this, this._disposables); this.multiStreamService.onDidChangeActiveStream(() => { this.updateWebview(); }, this, this._disposables); } public resolveWebviewView( webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken ) { this._view = webviewView; webviewView.webview.options = { enableScripts: true, localResourceRoots: [this._extensionUri] }; webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); webviewView.webview.onDidReceiveMessage( message => { switch (message.type) { case 'copyLog': this.handleCopyLog(message.logId); break; case 'ready': this.updateWebview(); break; } }, null, this._disposables ); this.updateWebview(); } private handleCopyLog(logId: string) { const activeStreamId = this.multiStreamService.getActiveStreamId(); if (!activeStreamId) { return; } const logs = this.multiStreamService.getLogsByStream(activeStreamId); const log = logs.find(l => l.id === logId); if (log) { vscode.env.clipboard.writeText(log.rawText); vscode.window.showInformationMessage('Log entry copied to clipboard'); } } private updateWebview() { if (!this._view) { return; } const activeStreamId = this.multiStreamService.getActiveStreamId(); if (!activeStreamId) { this._view.webview.postMessage({ type: 'updateLogs', logs: [], filter: {} }); return; } const logs = this.multiStreamService.getLogsByStream(activeStreamId); const filter = this.multiStreamService.getFilter(activeStreamId); const filteredLogs = this.filterLogs(logs, filter); this._view.webview.postMessage({ type: 'updateLogs', logs: filteredLogs.map(log => ({ id: log.id, timestamp: log.timestamp.toISOString(), level: log.level, message: log.message, agentName: log.agentName || '', source: log.source || '', taskId: log.taskId || '', streamName: log.streamName, rawText: log.rawText })), filter }); } private filterLogs(logs: LogEntry[], filter: LogFilter): LogEntry[] { if (!filter.level && !filter.searchText) { return logs; } return logs.filter(log => { if (filter.level && log.level !== filter.level) { return false; } if (filter.searchText) { const searchLower = filter.searchText.toLowerCase(); return log.message.toLowerCase().includes(searchLower) || log.rawText.toLowerCase().includes(searchLower); } return true; }); } private _getHtmlForWebview(webview: vscode.Webview) { const nonce = getNonce(); return `