Skip to main content
Glama
prompt-sequencing-fix.test.ts7.58 kB
/** * TDD Tests for Terminal Prompt Sequencing Fix * * Tests the surgical fix for prompt logic inversion and state management. * These tests should FAIL initially, then pass after implementing the fix. */ import { JestTestUtilities } from './jest-test-utilities'; describe('Terminal Prompt Sequencing Fix', () => { let testUtils: JestTestUtilities; beforeEach(async () => { testUtils = new JestTestUtilities({ enableDetailedLogging: true, enableErrorDiagnostics: true, testTimeout: 60000 }); await testUtils.setupTest('prompt-sequencing-fix'); }); afterEach(async () => { if (testUtils) { await testUtils.cleanupTest(); } }); describe('Browser Command Prompt Usage', () => { test('browser-initiated command uses existing prompt (no double prompts)', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "test-session", "command": "echo setup-complete"}' ], postWebSocketCommands: [ // This simulates a browser user typing 'ls' - should use existing prompt { initiator: 'browser' as const, command: 'ls' } ], workflowTimeout: 30000, sessionName: 'test-session' }; const result = await testUtils.runTerminalHistoryTest(config); // Should NOT have double prompts before the 'ls' command // Pattern should be: [prompt]$ ls<CRLF> not [prompt]$ [prompt]$ ls<CRLF> const concatenatedOutput = result.concatenatedResponses; // Count occurrences of prompt patterns before 'ls' const promptPattern = /\[jsbattig@localhost[^\]]*\]\$/g; const lsCommandIndex = concatenatedOutput.indexOf('ls\r\n'); if (lsCommandIndex === -1) { throw new Error('ls command not found in output'); } const beforeLsOutput = concatenatedOutput.substring(0, lsCommandIndex); const promptMatches = beforeLsOutput.match(promptPattern) || []; // After setup, should have exactly ONE prompt before 'ls', not two const lastTwoPrompts = promptMatches.slice(-2); // This test should FAIL initially - will detect double prompts expect(lastTwoPrompts).toHaveLength(1); expect(concatenatedOutput).not.toMatch(/\]\$\s*\[jsbattig@localhost[^\]]*\]\$\s*ls/); }, 45000); test('MCP command consumes existing prompt correctly', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "test-session", "command": "echo initial-setup"}' ], postWebSocketCommands: [ // MCP-initiated command should consume existing prompt 'ssh_exec {"sessionName": "test-session", "command": "pwd"}' ], workflowTimeout: 30000, sessionName: 'test-session' }; const result = await testUtils.runTerminalHistoryTest(config); const concatenatedOutput = result.concatenatedResponses; // Should see: [prompt]$ pwd<CRLF>/path<CRLF>[new-prompt]$ // NOT: [prompt]$ [prompt]$ pwd<CRLF>/path<CRLF>[new-prompt]$ const pwdCommandIndex = concatenatedOutput.indexOf('pwd\r\n'); expect(pwdCommandIndex).toBeGreaterThan(-1); const beforePwdOutput = concatenatedOutput.substring(0, pwdCommandIndex); const promptPattern = /\[jsbattig@localhost[^\]]*\]\$/g; const promptMatches = beforePwdOutput.match(promptPattern) || []; // Should have exactly one prompt before 'pwd', not duplicated const lastPrompt = promptMatches[promptMatches.length - 1]; const promptIndex = beforePwdOutput.lastIndexOf(lastPrompt); const afterPrompt = beforePwdOutput.substring(promptIndex + lastPrompt.length); // This test should FAIL initially - will detect prompt duplication expect(afterPrompt).not.toMatch(/\[jsbattig@localhost[^\]]*\]\$/); }, 45000); }); describe('Command Sequence Termination', () => { test('every command sequence ends with exactly one new prompt', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}' ], postWebSocketCommands: [ 'ssh_exec {"sessionName": "test-session", "command": "echo test1"}', 'ssh_exec {"sessionName": "test-session", "command": "echo test2"}' ], workflowTimeout: 30000, sessionName: 'test-session' }; const result = await testUtils.runTerminalHistoryTest(config); const concatenatedOutput = result.concatenatedResponses; // Each command should end with exactly one ready prompt const promptPattern = /\[jsbattig@localhost[^\]]*\]\$\s*$/; // Should end with a single prompt expect(concatenatedOutput).toMatch(promptPattern); // Count total prompts - should match command count + initial const allPromptMatches = concatenatedOutput.match(/\[jsbattig@localhost[^\]]*\]\$/g) || []; // Initial + 2 commands should result in 3 total prompts (not doubled) // This test should FAIL initially with current logic expect(allPromptMatches.length).toBeLessThanOrEqual(4); // Conservative upper bound }, 45000); test('no prompt concatenation in any command scenario', async () => { const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}' ], postWebSocketCommands: [ 'ssh_exec {"sessionName": "test-session", "command": "whoami"}', { initiator: 'browser' as const, command: 'date' } ], workflowTimeout: 30000, sessionName: 'test-session' }; const result = await testUtils.runTerminalHistoryTest(config); const concatenatedOutput = result.concatenatedResponses; // Should NEVER see concatenated prompts like: ]$ [user@host dir]$ const concatenatedPromptPattern = /\]\$\s*\[jsbattig@localhost[^\]]*\]\$/; // This test should FAIL initially - will detect prompt concatenation expect(concatenatedOutput).not.toMatch(concatenatedPromptPattern); }, 45000); }); describe('Prompt State Management', () => { test('session maintains prompt state correctly across operations', async () => { // This test validates that the SessionData properly tracks prompt state // Will need the new hasActivePrompt/lastPromptContent properties const config = { preWebSocketCommands: [ 'ssh_connect {"name": "test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}' ], postWebSocketCommands: [ 'ssh_exec {"sessionName": "test-session", "command": "echo state-test"}' ], workflowTimeout: 30000, sessionName: 'test-session' }; const result = await testUtils.runTerminalHistoryTest(config); // Basic validation that state management doesn't break functionality expect(result.concatenatedResponses).toContain('state-test'); expect(result.concatenatedResponses).toContain('[jsbattig@localhost'); // This test should PASS even initially, validates basic functionality intact }, 30000); }); });

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