#!/usr/bin/env node
/**
* Debug Script: Choose-Next Tool
*
* Simulates choose-next MCP tool behavior for UI development.
* Starts a mock server, sends a realistic decision workflow with options,
* waits for response, then outputs the formatted result that would be sent to the LLM.
*/
import { MockServer } from './shared/mock-server.js';
import { ResponseSimulator } from './shared/response-simulator.js';
import { mockChooseNextData, mockResponses } from './shared/mock-data.js';
async function runDebugChooseNext(): Promise<void> {
const server = new MockServer(3000);
const simulator = new ResponseSimulator(server, {
responseDelay: 6000, // 6 seconds for decision workflows
simulateTyping: false
});
try {
// Start the mock server
await server.start();
console.error('[Debug] Choose-Next debug server started');
console.error('[Debug] Open http://localhost:3000 in your browser to see the UI');
console.error('[Debug] Waiting for UI connection...');
// Wait a moment for potential UI connection
await new Promise(resolve => setTimeout(resolve, 2000));
// Create the mock request
const requestId = `choose-next-${Date.now()}`;
const mockRequest = {
id: requestId,
type: 'choose-next',
data: {
...mockChooseNextData,
timestamp: new Date().toISOString(),
context: {
debugMode: true,
workflow: 'decision-tree',
expectedOutcome: 'strategic-direction'
}
},
timestamp: new Date().toISOString()
};
// Add the request (this triggers SSE to UI)
server.addRequest(mockRequest);
console.error(`[Debug] Sent choose-next request: ${requestId}`);
console.error(`[Debug] Decision: "${mockChooseNextData.title}"`);
console.error(`[Debug] Options: ${mockChooseNextData.options.length} strategic choices`);
// Set up response handler
const responsePromise = new Promise<any>((resolve) => {
server.once('response', (data) => {
resolve(data.response);
});
});
// Auto-simulate response after delay if no UI response
const autoResponsePromise = new Promise<any>(async (resolve) => {
await new Promise(r => setTimeout(r, 15000)); // Wait 15 seconds for decision workflows
if (server.hasPendingRequests()) {
console.error('[Debug] No UI response received, using mock response');
const mockResponse = await simulator.simulateResponse(mockRequest);
resolve(mockResponse);
}
});
// Wait for either UI response or auto-response
const humanResponse = await Promise.race([responsePromise, autoResponsePromise]);
// Format the final result as it would be sent to LLM
const llmResult = formatChooseNextResult(mockRequest, humanResponse);
// Output the result to stdout (this is what the LLM would receive)
console.log('='.repeat(80));
console.log('FORMATTED RESULT FOR LLM:');
console.log('='.repeat(80));
console.log(llmResult);
console.log('='.repeat(80));
} catch (error) {
console.error('[Debug] Error:', error);
process.exit(1);
} finally {
await server.stop();
console.error('[Debug] Choose-Next debug session completed');
process.exit(0);
}
}
/**
* Format the choose-next result as it would be returned to the LLM
*/
function formatChooseNextResult(request: any, response: any): string {
const title = request.data.title;
const description = request.data.description;
const options = request.data.options || [];
const action = response.action;
const message = response.message || '';
let result = `# Human Decision from Workflow\n\n`;
// Original decision context
result += `## Decision Context\n\n`;
result += `**${title}**\n\n`;
result += `${description}\n\n`;
// Available options
result += `## Available Options\n\n`;
options.forEach((option: any, index: number) => {
result += `${index + 1}. **${option.icon || ''} ${option.title}**\n`;
result += ` - ID: \`${option.id}\`\n`;
result += ` - ${option.description}\n\n`;
});
// Human decision
result += `## Human Decision\n\n`;
switch (action) {
case 'selected':
const selectedOption = response.selectedOption;
if (selectedOption) {
result += `### ✅ OPTION SELECTED\n\n`;
result += `**Chosen Path:** ${selectedOption.icon || ''} ${selectedOption.title}\n\n`;
result += `**Option ID:** \`${selectedOption.id}\`\n\n`;
result += `**Description:** ${selectedOption.description}\n\n`;
if (message) {
result += `### Decision Reasoning\n\n`;
result += `${message}\n\n`;
}
result += `### Next Steps\n\n`;
result += `✅ **Proceed with implementing "${selectedOption.title}"**\n\n`;
result += `The human has chosen this path forward. Begin execution according to the selected option's requirements and the reasoning provided.\n\n`;
}
break;
case 'abort':
result += `### ⛔ DECISION ABORTED\n\n`;
if (message) {
result += `**Reason for Aborting:**\n\n${message}\n\n`;
}
result += `### Next Steps\n\n`;
result += `🛑 **STOP the current workflow**\n\n`;
result += `The human has decided not to proceed with any of the presented options. You should:\n`;
result += `- Re-evaluate the approach\n`;
result += `- Consider gathering more information\n`;
result += `- Present different options\n`;
result += `- Ask clarifying questions about the decision criteria\n\n`;
break;
case 'new-ideas':
result += `### 💡 REQUEST FOR NEW IDEAS\n\n`;
if (message) {
result += `**Feedback on Current Options:**\n\n${message}\n\n`;
}
result += `### Next Steps\n\n`;
result += `🔄 **Generate new, different options**\n\n`;
result += `The human is not satisfied with the current options. You should:\n`;
result += `- Brainstorm alternative approaches\n`;
result += `- Consider different perspectives or criteria\n`;
result += `- Use ask-one-question to gather specific requirements\n`;
result += `- Think outside the conventional solutions\n\n`;
result += `Focus on generating fresh ideas that address the feedback provided.\n\n`;
break;
default:
result += `### ❓ UNCLEAR RESPONSE\n\n`;
result += `Action: ${action}\n\n`;
if (message) {
result += `Message: ${message}\n\n`;
}
break;
}
// Workflow metadata
result += `## Workflow Summary\n\n`;
result += `- **Decision Type:** Choose-next workflow\n`;
result += `- **Options Presented:** ${options.length}\n`;
result += `- **Human Action:** ${action}\n`;
result += `- **Selected Option:** ${action === 'selected' ? response.selectedOption?.id || 'none' : 'none'}\n`;
result += `- **Session:** demo\n`;
result += `- **Timestamp:** ${new Date().toISOString()}\n\n`;
// Context preservation
const context = request.data.context;
if (context && Object.keys(context).length > 0) {
result += `## Original Context\n\n`;
Object.entries(context).forEach(([key, value]) => {
if (key !== 'debugMode' && value) {
result += `- **${key}:** ${value}\n`;
}
});
result += `\n`;
}
result += `---\n\n`;
if (action === 'selected') {
result += `**Note:** The human has made a clear decision. Proceed with implementation according to their choice and reasoning.`;
} else if (action === 'abort') {
result += `**Note:** The human has aborted this decision path. Reassess the situation before proposing new options.`;
} else if (action === 'new-ideas') {
result += `**Note:** The human wants different options. Focus on creative alternatives that address their feedback.`;
}
return result;
}
// CLI execution
if (require.main === module) {
console.error('[Debug] Starting Choose-Next debug session...');
runDebugChooseNext().catch(error => {
console.error('[Debug] Fatal error:', error);
process.exit(1);
});
}
export { runDebugChooseNext, formatChooseNextResult };