Skip to main content
Glama
double-echo-and-missing-prompt-bug-reproduction.test.ts12 kB
/** * Double Command Echo and Missing Initial Prompt Bug Reproduction Tests * * This test file reproduces two critical terminal display issues: * 1. Double command echo - commands appear twice in terminal * 2. Missing initial prompt - terminal history doesn't show initial prompt * * Uses Terminal History Testing Framework to capture exact WebSocket messages * and identify the source of these display problems. */ import { JestTestUtilities } from './integration/terminal-history-framework/jest-test-utilities.js'; describe('Terminal Display Bug Reproduction', () => { let testUtils: JestTestUtilities; beforeAll(async () => { testUtils = JestTestUtilities.setupJestEnvironment('double-echo-bug-reproduction'); }, 60000); beforeEach(async () => { if (testUtils) { await testUtils.setupTest(); } }); afterEach(async () => { if (testUtils) { await testUtils.cleanupTest(); } }); describe('Double Command Echo Issue', () => { test('should reproduce double command echo bug', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-fixed-terminal", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "test-fixed-terminal", "command": "echo hello"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"sessionName": "test-fixed-terminal", "command": "ls"}'} ], workflowTimeout: 30000, sessionName: 'test-fixed-terminal' }; const result = await testUtils.runTerminalHistoryTest(config); console.log('\n=== DOUBLE ECHO ANALYSIS ==='); console.log('Raw WebSocket Messages:'); console.log(result.concatenatedResponses); // Parse individual messages to analyze command echo patterns const messages = result.concatenatedResponses.split('\n') .filter(line => line.trim()) .map(line => { try { return JSON.parse(line); } catch { return null; } }) .filter(msg => msg && msg.type === 'terminal_output'); console.log('\n=== TERMINAL OUTPUT MESSAGES ==='); messages.forEach((msg, index) => { console.log(`Message ${index + 1}:`); console.log(` Data: ${JSON.stringify(msg.data)}`); console.log(` Source: ${msg.source}`); console.log(` Timestamp: ${msg.timestamp}`); }); // Check for command echo patterns const echoCommands = messages .map(msg => msg.data) .filter(data => data === 'echo hello' || data === 'ls'); console.log('\n=== ECHO COMMAND ANALYSIS ==='); console.log('Commands that appear as standalone output:', echoCommands); console.log('Echo count for "echo hello":', echoCommands.filter(cmd => cmd === 'echo hello').length); console.log('Echo count for "ls":', echoCommands.filter(cmd => cmd === 'ls').length); // FAILING ASSERTION: We expect NO standalone command echoes // Currently this will fail because commands are being echoed expect(echoCommands.length).toBe(0); // `Expected no standalone command echoes, but found: ${JSON.stringify(echoCommands)}` }, 60000); test('should identify source of command echo in WebSocket messages', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-echo-source", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"sessionName": "test-echo-source", "command": "whoami"}'} ], workflowTimeout: 30000, sessionName: 'test-echo-source' }; const result = await testUtils.runTerminalHistoryTest(config); // Analyze message sequence to identify when command echo occurs const lines = result.concatenatedResponses.split('\n').filter(line => line.trim()); let beforeCommand = []; let duringCommand = []; let afterCommand = []; let phase = 'before'; for (const line of lines) { try { const msg = JSON.parse(line); if (msg.type === 'terminal_output') { if (msg.data.includes('whoami') && phase === 'before') { phase = 'during'; } else if (msg.data.includes('jsbattig') && phase === 'during') { phase = 'after'; } if (phase === 'before') beforeCommand.push(msg); else if (phase === 'during') duringCommand.push(msg); else afterCommand.push(msg); } } catch { // Skip invalid JSON } } console.log('\n=== COMMAND EXECUTION PHASES ==='); console.log('Before command execution:'); beforeCommand.forEach(msg => console.log(` "${msg.data}" (source: ${msg.source})`)); console.log('During command execution (potential echo phase):'); duringCommand.forEach(msg => console.log(` "${msg.data}" (source: ${msg.source})`)); console.log('After command execution:'); afterCommand.forEach(msg => console.log(` "${msg.data}" (source: ${msg.source})`)); // FAILING ASSERTION: Command should not appear as standalone output const echoMessages = duringCommand.filter(msg => msg.data.trim() === 'whoami'); expect(echoMessages.length).toBe(0); // `Expected no command echo, but found ${echoMessages.length} echo messages: ${JSON.stringify(echoMessages)}` }, 60000); }); describe('Missing Initial Prompt Issue', () => { test('should reproduce missing initial prompt in terminal history', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-prompt-missing", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}', // No commands - just establish connection ], postWebSocketCommands: [ // First WebSocket command to see if initial prompt is present 'ssh_exec {"sessionName": "test-prompt-missing", "command": "pwd"}' ], workflowTimeout: 30000, sessionName: 'test-prompt-missing' }; const result = await testUtils.runTerminalHistoryTest(config); console.log('\n=== INITIAL PROMPT ANALYSIS ==='); console.log('Raw WebSocket Messages:'); console.log(result.concatenatedResponses); // Parse messages to find initial prompt const messages = result.concatenatedResponses.split('\n') .filter(line => line.trim()) .map(line => { try { return JSON.parse(line); } catch { return null; } }) .filter(msg => msg && msg.type === 'terminal_output') .sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); console.log('\n=== CHRONOLOGICAL TERMINAL MESSAGES ==='); messages.forEach((msg, index) => { console.log(`Message ${index + 1} (${msg.timestamp}):`); console.log(` Data: ${JSON.stringify(msg.data)}`); console.log(` Source: ${msg.source}`); }); // Check for bracket format prompt pattern const promptPattern = /\[[\w-]+@[\w.-]+\s+[\w/.-]+\]\$/; const initialPromptMessages = messages.filter(msg => promptPattern.test(msg.data)); console.log('\n=== PROMPT DETECTION ==='); console.log('Bracket format prompt pattern:', promptPattern); console.log('Messages containing prompts:'); initialPromptMessages.forEach(msg => { console.log(` "${msg.data}" at ${msg.timestamp}`); }); // FAILING ASSERTION: First message should be initial prompt expect(messages.length).toBeGreaterThan(0); // 'Expected at least one terminal message' if (messages.length > 0) { const firstMessage = messages[0]; console.log('\nFirst terminal message:', JSON.stringify(firstMessage.data)); // FAILING ASSERTION: First message should contain initial prompt expect(promptPattern.test(firstMessage.data)).toBe(true); // `Expected first message to be initial prompt matching ${promptPattern}, but got: "${firstMessage.data}"` } }, 60000); test('should verify initial prompt is included in terminal history replay', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-history-replay", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "test-history-replay", "command": "echo setup-complete"}' ], postWebSocketCommands: [ // Simulating a new browser connecting - should get history replay ], workflowTimeout: 30000, sessionName: 'test-history-replay' }; const result = await testUtils.runTerminalHistoryTest(config); // Find all prompt-related messages in history replay const messages = result.concatenatedResponses.split('\n') .filter(line => line.trim()) .map(line => { try { return JSON.parse(line); } catch { return null; } }) .filter(msg => msg && msg.type === 'terminal_output'); const promptPattern = /\[[\w-]+@[\w.-]+\s+[\w/.-]+\]\$/; const promptMessages = messages.filter(msg => promptPattern.test(msg.data)); console.log('\n=== TERMINAL HISTORY REPLAY ANALYSIS ==='); console.log('Total terminal output messages:', messages.length); console.log('Prompt messages found:', promptMessages.length); promptMessages.forEach((msg, index) => { console.log(`Prompt ${index + 1}: "${msg.data}" at ${msg.timestamp}`); }); // FAILING ASSERTION: Should have at least initial prompt expect(promptMessages.length).toBeGreaterThanOrEqual(1); // `Expected at least one prompt in terminal history, but found ${promptMessages.length}` // FAILING ASSERTION: History should start with initial prompt if (messages.length > 0) { const sortedMessages = messages.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); const firstNonEmptyMessage = sortedMessages.find(msg => msg.data.trim() !== ''); if (firstNonEmptyMessage) { expect(promptPattern.test(firstNonEmptyMessage.data)).toBe(true); // `Expected terminal history to start with prompt, but started with: "${firstNonEmptyMessage.data}"` } } }, 60000); }); describe('Combined Analysis', () => { test('should capture complete message flow for both issues', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-combined-analysis", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}' ], postWebSocketCommands: [ {initiator: 'mcp-client', command: 'ssh_exec {"sessionName": "test-combined-analysis", "command": "echo test"}'}, {initiator: 'mcp-client', command: 'ssh_exec {"sessionName": "test-combined-analysis", "command": "pwd"}'} ], workflowTimeout: 30000, sessionName: 'test-combined-analysis' }; const result = await testUtils.runTerminalHistoryTest(config); console.log('\n=== COMPLETE MESSAGE FLOW ANALYSIS ==='); console.log('Full WebSocket message sequence:'); console.log(result.concatenatedResponses); // This test documents the current behavior for analysis // No assertions - just capture data for debugging expect(result.concatenatedResponses).toBeDefined(); expect(result.concatenatedResponses.length).toBeGreaterThan(0); }, 60000); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/LightspeedDMS/ssh-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server