/** * @file Main extension file for AgentHub VSCode extension * Sets up the extension, registers commands, and manages the status bar item. * Implements a dynamic dashboard view that checks for active servers on ports 5173 and 4820. * Provides real-time status updates in the sidebar and status bar with background polling. * * @author Nguyễn Ngọc Trí Vĩ */ const vscode = require("vscode"); const http = require("http"); const { DashboardWebviewProvider } = require("./sidebar"); let statusBarItem; let outputChannel; function activate(context) { outputChannel = vscode.window.createOutputChannel("Claude Code Monitor"); outputChannel.appendLine("[activate] " + new Date().toISOString()); context.subscriptions.push(outputChannel); const statusProvider = new DashboardWebviewProvider(context, outputChannel); context.subscriptions.push( vscode.window.registerWebviewViewProvider("claude-code-monitor-view", statusProvider, { webviewOptions: { retainContextWhenHidden: true }, }) ); statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); statusBarItem.command = "claude-code-agent-monitor.openDashboard"; context.subscriptions.push(statusBarItem); updateStatusBar(); const statusInterval = setInterval(() => { updateStatusBar(); }, 5000); // Auto-refresh every 5 seconds let openDashboard = vscode.commands.registerCommand( "claude-code-agent-monitor.openDashboard", async (target) => { const panel = vscode.window.createWebviewPanel( "agentMonitor", "AgentHub", vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true } ); const updateWebview = async () => { const ports = [5173, 4820]; let activePort = null; for (const port of ports) { if (await checkPort(port)) { activePort = port; break; } } if (activePort) { let suffix = ""; if (target) { suffix = target.includes("-") ? `/sessions/${target}` : `/${target}`; } panel.webview.html = getDashboardHtml(activePort, suffix); } else { panel.webview.html = getErrorHtml(); } }; panel.webview.onDidReceiveMessage((m) => { if (m.command === "retry") updateWebview(); }); await updateWebview(); } ); let openInBrowser = vscode.commands.registerCommand( "claude-code-agent-monitor.openInBrowser", async () => { const isDevUp = await checkPort(5173); const url = isDevUp ? "http://localhost:5173" : "http://localhost:4820"; vscode.env.openExternal(vscode.Uri.parse(url)); } ); let refreshStatus = vscode.commands.registerCommand( "claude-code-agent-monitor.refreshStatus", () => { statusProvider.refresh(); updateStatusBar(); vscode.window.showInformationMessage("Claude Code Monitor refreshed."); } ); let clearHistory = vscode.commands.registerCommand( "claude-code-agent-monitor.clearHistory", async () => { if ( (await vscode.window.showWarningMessage("Clear all history?", { modal: true }, "Yes")) === "Yes" ) { try { const res = await request("DELETE", 4820, "/api/sessions"); if (res.statusCode === 200) { statusProvider.refresh(); updateStatusBar(); vscode.window.showInformationMessage("History cleared."); } } catch (e) { vscode.window.showErrorMessage("Failed to clear history."); } } } ); context.subscriptions.push(openDashboard, openInBrowser, refreshStatus, clearHistory); context.subscriptions.push({ dispose: () => clearInterval(statusInterval) }); } async function updateStatusBar() { try { const stats = await fetchJson(4820, "/api/stats"); if (stats) { statusBarItem.text = `$(pulse) Claude: ${stats.sessions || 0}s | ${stats.agents || 0}a`; statusBarItem.show(); } else statusBarItem.hide(); } catch (e) { statusBarItem.hide(); } } function checkPort(port) { return new Promise((r) => { const req = http.get({ hostname: "localhost", port, path: "/", timeout: 500 }, (res) => { r(true); res.resume(); }); req.on("error", () => r(false)); }); } function fetchJson(port, path) { return new Promise((res, rej) => { const req = http.get({ hostname: "localhost", port, path, timeout: 800 }, (r) => { let d = ""; r.on("data", (c) => (d += c)); r.on("end", () => { try { res(JSON.parse(d)); } catch (e) { rej(e); } }); }); req.on("error", rej); }); } function request(method, port, path) { return new Promise((res, rej) => { const req = http.request({ hostname: "localhost", port, path, method }, res); req.on("error", rej); req.end(); }); } function getDashboardHtml(port, suffix) { return `
Live Dashboard: ${suffix || "/"}
localhost:${port}
`; } function getErrorHtml() { return `

Dashboard Offline

Unable to connect to the Claude Code Monitor server

Quick Setup Guide

Initialize Repository
git clone https://git.smartgift.io.vn/Smartgift-AI/AgentHub.git cd AgentHub npm run setup
Launch Dashboard
npm run dev

Troubleshooting

Ensure no other services are occupying ports 5173 or 4820. If the problem persists, check the documentation.

View Documentation
`; } function deactivate() { if (statusBarItem) statusBarItem.dispose(); } module.exports = { activate, deactivate };