Task configuration:
{"task_id": "08", "task_name": "start_cpp_debug", "description": "\u5728\u5f53\u524d\u5de5\u4f5c\u533a\u4e2d\u6253\u5f00\u6587\u4ef6, \u5728\u7279\u5b9a\u4f4d\u7f6e\u6dfb\u52a0\u65ad\u70b9, \u5f00\u542fdebug\u4f1a\u8bdd", "application_info": {"name": "vscode", "executable_path": "/usr/share/code/code", "args": ["--no-sandbox", "--user-data-dir=/root/vscode_user_data_dir/"]}, "task_parameters": {"file_name": "/root/C-Plus-Plus/sorting/bubble_sort.cpp", "breakpoints": {"78": "i==2", "80": "None", "98": "None"}, "hit_file": "/root/C-Plus-Plus/sorting/bubble_sort.cpp", "hit_line": 98, "expected_program": "/root/C-Plus-Plus/sorting/bubble_sort"}, "instruction_template": "\u5728\u5f53\u524d\u5df2\u7ecf\u6253\u5f00\u7684vscode\u5de5\u4f5c\u533a\u4e2d\u6253\u5f00\u540d\u4e3a ${file_name} \u7684\u6587\u4ef6, \u65ad\u70b9\u7684\u884c\u53f7\u548c\u65ad\u70b9\u7684\u6761\u4ef6\u5206\u522b\u4e3a\u5982\u4e0b\u5bf9\u5e94\u5173\u7cfb: ${breakpoints}, \u5e76\u4e14\u4f7f\u7528\u540d\u4e3a'c++ debug'\u7684debug\u914d\u7f6e\u5f00\u542fdebug\u4f1a\u8bdd", "evaluation_setup": {"scripts": [{"role": "hook", "path": "hooker.js"}, {"role": "handler", "path": "handler.py"}], "timeout": 120, "evaluator_type": "IpcInjector", "evaluate_on_completion": true}, "total_key_steps": 6, "preconditions": {"vscode_running": true}, "events": {"open_file": {"description": "\u6210\u529f\u6253\u5f00\u76ee\u6807\u6587\u4ef6", "is_key_step": true, "key_step_index": 1, "key_step_name": "\u6253\u5f00\u6587\u4ef6"}, "breakpoint_change_78": {"description": "\u6dfb\u52a0\u6216\u8005\u4fee\u653978\u884c\u65ad\u70b9\u4fe1\u606f", "is_key_step": true, "key_step_index": 2, "key_step_name": "\u6210\u529f\u6dfb\u52a0\u6216\u8005\u4fee\u653978\u884c\u65ad\u70b9\u4fe1\u606f"}, "breakpoint_change_80": {"description": "\u6dfb\u52a0\u6216\u8005\u4fee\u653980\u884c\u65ad\u70b9\u4fe1\u606f", "is_key_step": true, "key_step_index": 3, "key_step_name": "\u6210\u529f\u6dfb\u52a0\u6216\u8005\u4fee\u653980\u884c\u65ad\u70b9\u4fe1\u606f"}, "breakpoint_change_98": {"description": "\u6dfb\u52a0\u6216\u8005\u4fee\u653998\u884c\u65ad\u70b9\u4fe1\u606f", "is_key_step": true, "key_step_index": 4, "key_step_name": "\u6210\u529f\u6dfb\u52a0\u6216\u8005\u4fee\u653998\u884c\u65ad\u70b9\u4fe1\u606f"}, "debug_session_start": {"description": "\u5f00\u542fdebug\u4f1a\u8bdd", "is_key_step": true, "key_step_index": 5, "key_step_name": "\u6210\u529f\u5f00\u542fdebug\u4f1a\u8bdd"}, "evaluate_on_completion": {"description": "\u5728\u4efb\u52a1\u5b8c\u6210\u65f6\u68c0\u67e5debug\u4f1a\u8bdd\u7684\u72b6\u6001", "is_key_step": true, "key_step_index": 6, "key_step_name": "\u4efb\u52a1\u6210\u529f\u5b8c\u6210"}}, "mcp_servers": [{"command": "mcp-proxy", "args": ["http://127.0.0.1:6010/sse"]}], "context_data": [{"from": "tests/context_data/vscode/user_data", "to": "/root/vscode_user_data_dir"}, {"from": "tests/context_data/vscode/extensions", "to": "/root/.vscode/"}, {"from": "tests/context_data/vscode/C-Plus-Plus", "to": "/root/C-Plus-Plus"}]}

Hook script:
/**
 * Inspects the current C++ debug session and returns breakpoint and stop location information
 * @returns {Promise<{breakpoints: Array, currentFile: string, currentLine: string}> | null} Debug information or null if invalid session
 */
async function inspectCppDebugSession() {
    try {
        // Check if C/C++ extension is installed
        const cpptoolsExtension = vscode.extensions.getExtension('ms-vscode.cpptools');
        if (!cpptoolsExtension) {
            throw new Error('C/C++ extension (ms-vscode.cpptools) is not installed');
        }

        // Check if a debug session is active
        if (!vscode.debug.activeDebugSession) {
            throw new Error('No active debug session found');
        }

        // Verify if the debug session is using cpptools
        const debugType = vscode.debug.activeDebugSession.type;
        if (debugType !== 'cppdbg' && debugType !== 'cppvsdbg') {
            throw new Error('Current debug session is not using C/C++ debugger');
        }

        // Get all breakpoints
        const breakpoints = vscode.debug.breakpoints;
        let breakpointDetails = [];
        
        for (const bp of breakpoints) {
            if (bp instanceof vscode.SourceBreakpoint) {
                const location = bp.location;
                breakpointDetails.push({
                    file: location.uri.fsPath,
                    line: location.range.start.line + 1,
                    enabled: bp.enabled,
                    condition: bp.condition || 'None'
                });
            }
        }

        // Get current stack frame to determine stopped location
        let currentLine = 'Unknown';
        let currentFile = 'Unknown';
        
        try {
            // First, check if the session is stopped
            const threads = await vscode.debug.activeDebugSession.customRequest('threads');
            if (threads && threads.threads && threads.threads.length > 0) {
                // Get the first stopped thread
                const stoppedThread = threads.threads.find(thread => thread.id);
                if (stoppedThread) {
                    const stackFrames = await vscode.debug.activeDebugSession.customRequest('stackTrace', {
                        threadId: stoppedThread.id,
                        startFrame: 0,
                        levels: 1
                    });
                    
                    if (stackFrames.stackFrames && stackFrames.stackFrames.length > 0) {
                        const topFrame = stackFrames.stackFrames[0];
                        currentLine = topFrame.line;
                        currentFile = topFrame.source?.path || 'Unknown';
                    } else {
                        console.log('No stack frames available');
                    }
                } else {
                    console.log('No stopped threads found');
                }
            } else {
                console.log('No threads available');
            }
        } catch (error) {
            console.error('Error fetching stack trace:', error);
        }

        return {
            breakpoints: breakpointDetails,
            currentFile,
            currentLine
        };
    } catch (error) {
        socket.emit("send", {
            'event_type': "error",
            'message': "在获取debug会话时出现错误"
        });
        console.error('Inspection error:', error);
        throw error;
    }
}

// Listen for 'evaluate' event
socket.on('evaluate', async () => {
    const debugInfo = await inspectCppDebugSession();
    // vscode.window.showInformationMessage(message);
    socket.emit("send", {
        'event_type': "evaluate_on_completion",
        'message': "任务结束时获取到debug会话的状态",
        'breakpoints': debugInfo.breakpoints,
        'current_file': debugInfo.currentFile,
        'current_line': debugInfo.currentLine
    });
});

// Register a listener for when a text document is opened
vscode.workspace.onDidOpenTextDocument(async (document) => {
    const filePath = document.uri.fsPath;
    socket.emit("send", {
        event_type: "open_file",
        message: "打开文件",
        path: filePath,
        scheme: document.uri.scheme
    });
});

// Register a listener for when breakpoints change
vscode.debug.onDidChangeBreakpoints((event) => {
    try {
        // Process added breakpoints
        event.added.forEach((breakpoint) => {
            if (breakpoint instanceof vscode.SourceBreakpoint) {
                const location = breakpoint.location;
                socket.emit('send', {
                    'event_type': 'breakpoint_change',
                    'message': '断点添加',
                    'action': 'added',
                    'path': location.uri.fsPath,
                    'line': location.range.start.line + 1, // Convert to 1-based line number
                    'condition': breakpoint.condition || 'None',
                    'enabled': breakpoint.enabled
                });
            }
        });

        // Process removed breakpoints
        event.removed.forEach((breakpoint) => {
            if (breakpoint instanceof vscode.SourceBreakpoint) {
                const location = breakpoint.location;
                socket.emit('send', {
                    'event_type': 'breakpoint_change',
                    'message': '断点移除',
                    'action': 'removed',
                    'path': location.uri.fsPath,
                    'line': location.range.start.line + 1,
                    'condition': breakpoint.condition || 'None',
                    'enabled': breakpoint.enabled
                });
            }
        });

        // Process changed breakpoints
        event.changed.forEach((breakpoint) => {
            if (breakpoint instanceof vscode.SourceBreakpoint) {
                const location = breakpoint.location;
                socket.emit('send', {
                    'event_type': 'breakpoint_change',
                    'message': '断点修改',
                    'action': 'changed',
                    'path': location.uri.fsPath,
                    'line': location.range.start.line + 1,
                    'condition': breakpoint.condition || 'None',
                    'enabled': breakpoint.enabled
                });
            }
        });

        console.log(`Breakpoints changed: added=${event.added.length}, removed=${event.removed.length}, changed=${event.changed.length}`);
    } catch (error) {
        console.error(`Error handling breakpoint change: ${error.message}`);
    }
});

vscode.debug.onDidStartDebugSession((session) => {
    try {
        // Get the program path and working directory from the configuration
        const program = session.configuration.program || 'unknown';
        const cwd = session.configuration.cwd || session.workspaceFolder?.uri.fsPath || 'unknown';

        // Emit debug session start event via socket
        socket.emit('send', {
            'event_type': 'debug_session_start',
            'message': '调试会话开始',
            'session_name': session.name,
            'debugger_type': session.type,
            'program': program,
            'working_dir': cwd
        });

        console.log(`Debug session started: name=${session.name}, type=${session.type}, program=${program}`);
    } catch (error) {
        console.error(`Error handling debug session start: ${error.message}`);
    }
});

Evaluation handler:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from typing import Dict, Any, Optional, Callable, List

def message_handler(message: Dict[str, Any], logger, task_parameter: Dict[str, Any]) -> Optional[List[Dict[str, Any]]]:    
    event_type = message.get('event_type')
    logger.info(message)
    expected_filename = task_parameter.get("file_name", "/root/C-Plus-Plus/sorting/bubble_sort.cpp")
    expected_breakpoints = task_parameter.get("breakpoints", {
        "78": "i==2",
        "80": "None",
        "98": "None"
    })
    expected_hit_file = task_parameter.get("hit_file", "/root/C-Plus-Plus/sorting/bubble_sort.cpp")
    expected_hit_line = task_parameter.get("hit_line", 98)
    expected_program = task_parameter.get("expected_program", "/root/C-Plus-Plus/sorting/bubble_sort")
    if event_type == "evaluate_on_completion":
        breakpoints_info = message.get('breakpoints')
        current_file = message.get('current_file')
        current_line = message.get('current_line')
        for bp in breakpoints_info:
            file_name = bp['file']
            line = str(bp['line'])
            condition = bp['condition']
            enabled = bp['enabled']
            if file_name == expected_filename and line in expected_breakpoints:
                if enabled and condition == expected_breakpoints[line]:
                    # right settings
                    expected_breakpoints.pop(line)
        if len(expected_breakpoints) == 0 and expected_hit_file == current_file and expected_hit_line == current_line:
            return [
                {"status": "key_step", "index": 6},
                {"status": "success", "reason": f"任务成功完成"}
            ]
        else:
            return [{"status": "error", "type": "evaluate_on_completion", "message": "任务没有完成"}]
    elif event_type == "open_file":
        file_path = message.get("path")
        if message.get("scheme") == "git":
            file_path = file_path[:-4]
        if file_path == expected_filename:
            return [{"status": "key_step", "index": 1}]
    elif event_type == "breakpoint_change":
        bp_file_path = message.get("path")
        bp_file_line = message.get("line")
        bp_condition = message.get("condition")
        bp_enabled = message.get("enabled")
        if bp_file_path != expected_filename:
            return None
        if bp_file_line == 78 and bp_enabled and bp_condition == expected_breakpoints.get("78"):
            return [{"status": "key_step", "index": 2}]
        elif bp_file_line == 80 and bp_enabled and bp_condition == expected_breakpoints.get("80"):
            return [{"status": "key_step", "index": 3}]
        elif bp_file_line == 98 and bp_enabled and bp_condition == expected_breakpoints.get("98"):
            return [{"status": "key_step", "index": 4}]
    elif event_type == "debug_session_start":
        program = message.get("program")
        if program == expected_program:
            return [{"status": "key_step", "index": 5}]
    return None