Task configuration:
{"task_id": "20", "task_name": "modify_note_title", "description": "\u5728Joplin\u4e2d\u4fee\u6539\u6307\u5b9a\u7b14\u8bb0\u7684\u6807\u9898", "application_info": {"name": "joplin", "executable_path": "/workspace/PC-Canary/apps/joplin/Joplin-3.3.12.AppImage", "args": ["--env", "dev", "--profile", "/workspace/PC-Canary/apps/joplin/joplindev-desktop"]}, "task_parameters": {"notebook_name": "hello", "old_note_name": "hi", "new_note_name": "hello world"}, "instruction_template": "\u5728Joplin\u4e2d\u5c06\u7b14\u8bb0\u672c ${notebook_name} \u4e0b\u7684\u7b14\u8bb0 ${old_note_name} \u7684\u6807\u9898\u4fee\u6539\u4e3a ${new_note_name}", "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": 1, "preconditions": {"joplin_running": true}, "events": {"evaluate_on_completion": {"description": "\u5728\u4efb\u52a1\u7ed3\u675f\u65f6\u5224\u65ad\u6307\u5b9a\u7b14\u8bb0\u7684\u6807\u9898\u662f\u5426\u5df2\u4fee\u6539", "is_key_step": true, "key_step_index": 1, "key_step_name": "\u7b14\u8bb0\u6807\u9898\u4fee\u6539\u5b8c\u6210"}}, "mcp_servers": [{"command": "/home/user/.local/bin/uv", "args": ["--directory", "/home/user/Desktop/joplin-mcp-server", "run", "src/mcp/joplin_mcp.py"]}]}

Hook script:
// 使用 Joplin 插件 API 来处理通信
joplin.plugins.register({
    onStart: async function() {
        console.log('Joplin plugin started');
        
        // 监听 evaluate 事件
        socket.on("evaluate", async () => {
            try {
                // 获取所有笔记本
                const notebooks = await joplin.data.get(['folders']);
                const notebookList = notebooks.items;
                
                // 获取所有笔记
                const notes = await joplin.data.get(['notes']);
                const noteList = notes.items;
                
                // 获取当前笔记本名称和笔记名称
                const currentNotebookName = notebookList.map(notebook => notebook.title);
                const currentNoteName = noteList.map(note => note.title);
                
                console.log('Current notebooks:', currentNotebookName);
                console.log('Current notes:', currentNoteName);
                
                const notebookMap = {};  // 存储笔记本ID和名称的对应关系
                notebookList.forEach(notebook => {
                    notebookMap[notebook.id] = notebook.title;
                });

                // 使用 postMessage 发送评估消息
                window.postMessage({
                    "event_type": "evaluate_on_completion",
                    "message": "当前笔记本列表: " + currentNotebookName.join(', ') + "\n当前笔记列表: " + currentNoteName.join(', '),
                    "data": {
                        "notebooks": currentNotebookName,
                        "notes": currentNoteName,
                        "notebook_notes": noteList.map(note => ({
                            "note_title": note.title,
                            "parent_id": note.parent_id,
                            "parent_name": notebookMap[note.parent_id]  // 添加笔记本名称
                        }))
                    }
                }, '*');
                console.log('Evaluation result sent via postMessage');
            } catch (error) {
                console.error('Error in evaluate handler:', error);
            }
        });
    }
}); 

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

"""
joplin修改笔记标题的事件处理器
负责处理钩子脚本产生的事件并更新评估指标
"""

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.get('message'))
    
    if event_type == "evaluate_on_completion":
        data = message.get("data", {})
        notebook_list = data.get("notebooks", [])
        notebook_notes = data.get("notebook_notes", [])
        
        expected_notebook = task_parameter.get('notebook_name', "hello")
        old_note_name = task_parameter.get('old_note_name', "hi")
        new_note_name = task_parameter.get('new_note_name', "hello world")
        
        # 检查笔记本是否存在
        if expected_notebook not in notebook_list:
            return [{"status": "error", "type": "evaluate_on_completion", "message": f"笔记本 {expected_notebook} 不存在"}]
        
        # 获取指定笔记本下的所有笔记
        notebook_notes_in_target = [
            note for note in notebook_notes
            if note["parent_name"] == expected_notebook
        ]
        
        # 检查笔记是否已修改为新的标题
        found_new_title = False
        found_old_title = False
        
        for note in notebook_notes_in_target:
            if note["note_title"] == new_note_name:
                found_new_title = True
            if note["note_title"] == old_note_name:
                found_old_title = True
        
        if found_new_title and not found_old_title:
            return [
                {"status": "key_step", "index": 1},
                {"status": "success", "reason": f"成功将笔记本 {expected_notebook} 下的笔记 {old_note_name} 的标题修改为 {new_note_name}"}
            ]
        elif found_old_title:
            return [{"status": "error", "type": "evaluate_on_completion", 
                    "message": f"笔记标题未成功修改，原标题 {old_note_name} 仍然存在"}]
        else:
            return [{"status": "error", "type": "evaluate_on_completion", 
                    "message": f"在笔记本 {expected_notebook} 下没有找到标题为 {new_note_name} 的笔记"}]
    return None