From ea62ebfbf33b43cc5c584acddda1d3391e098e9a Mon Sep 17 00:00:00 2001 From: B Harper Date: Sat, 1 Nov 2025 17:37:01 +1100 Subject: [PATCH] Add tab notification features and timeout improvements --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 5 +- ToDo.md | 0 package.json | 10 +++ response-debug.txt | 139 +++++++++++++++++++++++++++++ src/extension.ts | 23 +++-- src/mcp/server.ts | 35 +++++++- src/webview/chatWebviewProvider.ts | 23 ++--- 8 files changed, 207 insertions(+), 28 deletions(-) create mode 100644 ToDo.md create mode 100644 response-debug.txt diff --git a/.DS_Store b/.DS_Store index d520fa801c4954a0cf57472e3b67ad09fecf85fa..b9de3d462af551f6ec7c4df35a6856a9fd6e21f4 100644 GIT binary patch delta 170 zcmZoMXffEJ$`UstTbzM`frUYjA)O(Up(Hoo#U&{xKM5$t;o23G#S?zq5mi0~uY5s< zVQ_MOZUIma1H;M-lbczT7;PpmW07O~ks)xKA$;-&7Lm#KSPGeh?@bP5mE)N3yRU@> hXa|rZGP#?Ti|zLRf>@UD&9hnGF)}i2?qaVJ007o^F&F>< delta 163 zcmZoMXffEJ$`Z#Hd4Yj}frUYjA)O(Up(Hoo#U&{xKM5$tVc{dK`7i9aBdUA~UipFy z!{Frn+ybB;1_qf4lbczT7)vHEW09NuibZPjJ(fZyQNziBta2PLYeS!10U8eEh)nKg V(`sessionId-${workspaceKey}`); + let sessionId = context.globalState.get(stateKey); if (!sessionId) { // Generate new UUID-based session ID - sessionId = `session-${crypto.randomUUID()}`; + sessionId = `session-${crypto.randomUUID()}${devSuffix}`; // Store it persistently - context.globalState.update(`sessionId-${workspaceKey}`, sessionId); - console.log(`Generated new workspace session ID: ${sessionId} for ${workspaceKey}`); + context.globalState.update(stateKey, sessionId); + console.log(`Generated new workspace session ID: ${sessionId} for ${workspaceKey}${isDevHost ? ' (dev host)' : ''}`); } else { - console.log(`Retrieved existing workspace session ID: ${sessionId} for ${workspaceKey}`); + console.log(`Retrieved existing workspace session ID: ${sessionId} for ${workspaceKey}${isDevHost ? ' (dev host)' : ''}`); } return sessionId; @@ -328,6 +333,11 @@ export async function activate(context: vscode.ExtensionContext) { } }); + // Register report issue command + const reportIssueCommand = vscode.commands.registerCommand('humanagent-mcp.reportIssue', () => { + vscode.env.openExternal(vscode.Uri.parse('https://github.com/benharper/HumanAgent-MCP/issues')); + }); + // Add all disposables to context context.subscriptions.push( treeView, @@ -338,7 +348,8 @@ export async function activate(context: vscode.ExtensionContext) { startServerCommand, stopServerCommand, restartServerCommand, - configureMcpCommand + configureMcpCommand, + reportIssueCommand ); // Show welcome message diff --git a/src/mcp/server.ts b/src/mcp/server.ts index e5f78c4..b868db9 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -301,8 +301,8 @@ export class McpServer extends EventEmitter { }, timeout: { type: 'number', - description: 'Timeout in seconds to wait for human response (default: 300)', - default: 300 + description: 'Timeout in seconds to wait for human response (default: 600)', + default: 600 } }, required: ['message'] @@ -1230,6 +1230,18 @@ export class McpServer extends EventEmitter { border-bottom: 2px solid var(--vscode-button-background); } + .tab.has-new-message { + background-color: var(--vscode-button-background); + color: var(--vscode-button-foreground); + position: relative; + } + + .tab.has-new-message::after { + content: '💬'; + margin-left: 6px; + font-size: 12px; + } + .content { flex: 1; display: flex; @@ -1403,6 +1415,10 @@ export class McpServer extends EventEmitter { // Update active tab document.querySelectorAll('.tab').forEach(tab => { tab.classList.toggle('active', tab.dataset.session === sessionId); + // Remove new message indicator when switching to that tab + if (tab.dataset.session === sessionId) { + tab.classList.remove('has-new-message'); + } }); // Update active chat container @@ -1412,6 +1428,17 @@ export class McpServer extends EventEmitter { activeSessionId = sessionId; } + + // Function to highlight tabs with new messages + function highlightTabWithNewMessage(sessionId) { + // Only highlight if it's not the currently active session + if (sessionId !== activeSessionId) { + const tab = document.querySelector(\`[data-session="\${sessionId}"].tab\`); + if (tab && !tab.classList.contains('active')) { + tab.classList.add('has-new-message'); + } + } + } // Message sending document.addEventListener('click', (e) => { @@ -1706,8 +1733,12 @@ export class McpServer extends EventEmitter { // Handle different types of updates if (data.type === 'chat_message' && data.sessionId && data.message) { addMessageToUI(data.sessionId, data.message.sender, data.message.content, data.message.source, data.message.timestamp); + // Highlight tab if not currently active + highlightTabWithNewMessage(data.sessionId); } else if (data.type === 'message' && data.sessionId) { addMessageToUI(data.sessionId, data.role || 'assistant', data.content, null, null); + // Highlight tab if not currently active + highlightTabWithNewMessage(data.sessionId); } else if (data.type === 'request-state-change' && data.data) { // Handle request state changes for input control console.log('Web interface received request-state-change:', data.data); diff --git a/src/webview/chatWebviewProvider.ts b/src/webview/chatWebviewProvider.ts index e2b8c2d..85a0d28 100644 --- a/src/webview/chatWebviewProvider.ts +++ b/src/webview/chatWebviewProvider.ts @@ -82,11 +82,6 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { // AI messages are now handled by SSE events - no need to store locally this.updateWebview(); - // Play notification sound if enabled - if (this.notificationSettings.enableSound) { - await this.playNotificationSound(); - } - // Trigger flashing animation if enabled if (this.notificationSettings.enableFlashing) { this.triggerFlashingBorder(); @@ -153,10 +148,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { vscode.commands.executeCommand('humanagent-mcp.showStatus'); break; case 'playNotificationSound': - // Play sound from extension side (Node.js) when webview requests it - if (this.notificationSettings.enableSound) { - await this.playNotificationSound(); - } + // Sound removed - only play on AI tool calls break; case 'sessionNameUpdated': // Handle session name update from SSE event @@ -896,9 +888,8 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { document.body.classList.remove('flashing'); }, 2000); } else if (message.type === 'playSound') { - // Play notification sound - console.log('Playing notification sound...'); - playNotificationBeep(); + // Sound removed - only play on AI tool calls + console.log('Sound trigger removed - only playing on AI tool calls'); } else if (message.command === 'updateOverrideFileExists') { // Update override file existence and refresh cog menu window.overrideFileExists = message.exists; @@ -1053,8 +1044,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { } } - // Play notification - playNotificationBeep(); + // Sound removed - only play on AI tool calls // Flash border document.body.classList.add('flashing'); @@ -1097,10 +1087,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider { // Use unified addMessageToUI function addMessageToUI(message); - // Play notification for assistant messages - if (message.sender === 'agent') { - playNotificationBeep(); - } + // Sound removed - only play on AI tool calls } }