Task configuration:
{"task_id": "18", "task_name": "create_new_file", "description": "\u5728vscode\u4e2d\u5b89\u88c5\u63d2\u4ef6, \u5e76\u4e14\u8fdb\u884c\u8bbe\u7f6e", "application_info": {"name": "vscode", "executable_path": "/usr/share/code/code", "args": ["--no-sandbox", "--user-data-dir=/root/vscode_user_data_dir/"]}, "task_parameters": {"plugin_name": "TODO Highlight", "instruction": "\u914d\u7f6e\u63d2\u4ef6\u4e3a\u5927\u5c0f\u5199\u4e0d\u654f\u611f", "value": false}, "instruction_template": "\u5728vscode\u4e2d\u5b89\u88c5\u540d\u4e3a ${plugin_name} \u63d2\u4ef6, \u5e76\u4e14 ${instruction}", "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": 2, "preconditions": {"vscode_running": true}, "events": {"evaluate_on_completion": {"description": "\u5728\u4efb\u52a1\u7ed3\u675f\u65f6\u68c0\u67e5\u4efb\u52a1\u662f\u5426\u5b8c\u6210", "is_key_step": true, "key_step_index": 2, "key_step_name": "\u4efb\u52a1\u6210\u529f\u5b8c\u6210"}, "plugin_installed": {"description": "\u5728\u4efb\u52a1\u7ed3\u675f\u65f6\u68c0\u67e5\u63d2\u4ef6\u662f\u5426\u5b89\u88c5", "is_key_step": true, "key_step_index": 1, "key_step_name": "\u63d2\u4ef6\u6210\u529f\u5b89\u88c5"}}, "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/task18/extensions", "to": "/root/.vscode/"}, {"from": "tests/context_data/vscode/C-Plus-Plus", "to": "/root/C-Plus-Plus"}]}

Hook script:
/**
 * 异步获取所有已安装的扩展名称
 * @returns Promise<扩展名称数组>
 */
async function getInstalledExtensionNames() {
    return new Promise((resolve) => {
        const extensions = vscode.extensions.all;
        const extensionNames = extensions
            .filter(ext => !ext.id.startsWith('vscode.')) // 过滤掉内置扩展
            .map(ext => ext.packageJSON.displayName || ext.id);
        resolve(extensionNames);
    });
}

async function readTodoHighlightConfig() {
    const config = vscode.workspace.getConfiguration('todohighlight');
    const isCaseSensitive = config.get('isCaseSensitive');
    console.log('isCaseSensitive:', isCaseSensitive);
    return isCaseSensitive;
}

socket.on('evaluate', async () => {
    const info = await readTodoHighlightConfig();
    const names = await getInstalledExtensionNames();
    // vscode.window.showInformationMessage(message);
    socket.emit("send", {
        'event_type': "evaluate_on_completion",
        'message': "任务结束时检查插件是否配置成功",
        'info': info,
        'names': names
    });
});

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

from typing import Dict, Any, Optional, 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_value = task_parameter.get("info", False)
    expected_name = task_parameter.get("plugin_name", "TODO Highlight")
    if event_type == "evaluate_on_completion":
        if expected_value == message.get('info', None) and expected_name in message.get('names', []):
            return [
                {"status": "key_step", "index": 1},
                {"status": "key_step", "index": 2},
                {"status": "success", "reason": f"任务成功完成"}
            ]
        elif expected_name in message.get('names', []):
            return [
                {"status": "key_step", "index": 1},
                {"status": "error", "type": "evaluate_on_completion", "message": "任务没有完成"}
            ]
        else:
            return [
                {"status": "error", "type": "evaluate_on_completion", "message": "任务没有完成"}
            ]
    return None