diff --git a/.gitignore b/.gitignore
index 8bdea99..331ad62 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-# **/dist
+**/dist
**/node_modules
**/package-lock.json
\ No newline at end of file
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
deleted file mode 100644
index 0400c54..0000000
--- a/DEVELOPMENT.md
+++ /dev/null
@@ -1,537 +0,0 @@
-# MCP Bridge 插件开发流程文档
-
-本文档记录了 MCP Bridge 插件的完整开发流程,包括核心架构设计、功能实现、测试与调试等各个阶段。
-
-## 0. 项目开发规范 (Project Rules)
-
-> [!IMPORTANT]
-> 所有贡献者必须严格遵守以下规则:
-
-1. **语言与沟通**: 所有注释、文档、计划、任务及 AI 回复必须使用 **简体中文 (Simplified Chinese)**。
-2. **技术栈**: 新脚本必须使用 **TypeScript** (`.ts`)。禁止创建新的 `.js` 文件 (除非是构建脚本或测试配置)。
-3. **文档**: 所有修改或创建的脚本必须包含详细的 JSDoc 格式注释。
-4. **架构**: 严禁引入新的架构模式或重型外部库。必须复用现有的 Cocos Creator 管理器和工具类。
-5. **隔离原则**: 保持 `main.js` (主进程) 与 `scene-script.js` (渲染进程) 的严格职责分离。即便是在主进程中,也应通过 IPC 与场景脚本交互。
-6. **主体校验规则 (Subject Validation Rule)**: 在对节点、组件或属性进行任何“写”操作之前,AI 必须先验证主体的存在性与类型正确性。严禁基于假设进行操作。
-
-## 1. 项目初始化
-
-### 1.1 目录结构搭建
-
-```
-mcp-bridge/
-├── main.js # 插件主入口
-├── scene-script.js # 场景脚本
-├── mcp-proxy.js # MCP 代理
-├── README.md # 项目说明
-├── DEVELOPMENT.md # 开发流程文档
-├── package.json # 插件配置
-└── panel/ # 面板目录
- ├── index.html # 面板界面
- └── index.js # 面板逻辑
-```
-
-### 1.2 插件配置
-
-在 `package.json` 中配置插件信息:
-
-```json
-{
- "name": "mcp-bridge",
- "version": "1.0.0",
- "description": "MCP Bridge for Cocos Creator",
- "main": "main.js",
- "panel": {
- "main": "panel/index.html",
- "type": "dockable",
- "title": "MCP Bridge",
- "width": 800,
- "height": 600
- },
- "contributions": {
- "menu": [
- {
- "path": "Packages/MCP Bridge",
- "label": "Open Test Panel",
- "message": "open-test-panel"
- }
- ]
- }
-}
-```
-
-## 2. 核心架构设计
-
-### 2.1 系统架构
-
-```
-┌────────────────────┐ HTTP ┌────────────────────┐ IPC ┌────────────────────┐
-│ 外部 AI 工具 │ ──────────> │ main.js (HTTP服务) │ ─────────> │ scene-script.js │
-│ (Cursor/VS Code) │ <──────── │ (MCP 协议处理) │ <──────── │ (场景操作执行) │
-└────────────────────┘ JSON └────────────────────┘ JSON └────────────────────┘
-```
-
-### 2.2 核心模块
-
-1. **HTTP 服务模块**:处理外部请求,解析 MCP 协议
-2. **MCP 工具模块**:实现各种操作工具
-3. **场景操作模块**:执行场景相关操作
-4. **资源管理模块**:处理脚本和资源文件
-5. **面板界面模块**:提供用户交互界面
-
-## 3. 功能模块实现
-
-### 3.1 HTTP 服务实现
-
-在 `main.js` 中实现 HTTP 服务:
-
-```javascript
-startServer(port) {
- try {
- const http = require('http');
- mcpServer = http.createServer((req, res) => {
- // 处理请求...
- });
- mcpServer.listen(port, () => {
- addLog("success", `MCP Server running at http://127.0.0.1:${port}`);
- });
- } catch (e) {
- addLog("error", `Failed to start server: ${e.message}`);
- }
-}
-```
-
-## 4. 开发历程与里程碑
-
-### 2026-02-10: Undo 系统深度修复与规范化
-
-- **问题分析**: 修复了 `TypeError: Cannot read property '_name' of null`。该错误是由于直接修改节点属性(绕过 Undo 系统)与分组事务混用导致的。
-- **重构要点**: 将 `update-node-transform` 中所有的直接赋值替换为 `scene:set-property` IPC 调用,确保所有变换修改均受撤销系统监控。
-- **缺陷修正**: 修复了 `manage_undo` 在 `begin_group` 时传递错误参数导致 "Unknown object to record" 的问题。
-- **全量汉化与文档同步**: 完成了 `main.js` 和 `scene-script.js` 的 100% 简体中文翻译。同步更新了 `README.md`、`DEVELOPMENT.md` 及 `注意事项.md`。
-
-### 2026-02-13: 新增 `open_prefab` 功能与消息协议修正
-
-- **需求实现**: 新增 `open_prefab` 工具,允许 AI 直接打开预制体进入编辑模式。
-- **协议修正**: 经过测试对比,最终确认使用 `scene:enter-prefab-edit-mode` 消息并配合 `Editor.Ipc.sendToAll` 是进入预制体编辑模式的最佳方案,解决了 `scene:open-by-uuid` 无法触发编辑状态的问题。
-- **文档深度补全**: 遵循全局开发规范,同步更新了所有技术文档,确保 100% 简体中文覆盖及详尽的 JSDoc 注释。
-
-### 2026-02-25: 修复 manage_script 路径引用错误与强制生成 Meta
-
-- **缺陷修正**: 修复了 `main.js` 中 `manageScript` 处理 `create` 动作时由于变量名解构导致 `path.dirname` 找不到 `path` 引用的问题。现已改为使用预设的 `pathModule` 模块。
-- **规范强化**: 将 `manage_script` 的工具提示(Prompt)更新为强制要求调用 `refresh_editor` 生成脚本的 `.meta` 文件,以确保新创建的脚本能够被正确挂载为组件,同时不增加整体 Token 消耗。
-
-### 3.2 MCP 工具注册
-
-在 `/list-tools` 接口中注册工具:
-
-```javascript
-const tools = [
- {
- name: "get_selected_node",
- description: "获取当前选中的节点",
- parameters: [],
- },
- // 其他工具...
-];
-```
-
-### 3.3 场景操作实现
-
-在 `scene-script.js` 中实现场景相关操作:
-
-```javascript
-const sceneScript = {
- "create-node"(params, callback) {
- // 创建节点逻辑...
- },
- "set-property"(params, callback) {
- // 设置属性逻辑...
- },
- // 其他操作...
-};
-```
-
-### 3.4 脚本管理实现
-
-在 `main.js` 中实现脚本管理功能:
-
-```javascript
-manageScript(args, callback) {
- const { action, path, content } = args;
- switch (action) {
- case "create":
- // 确保父目录存在
- const fs = require('fs');
- const pathModule = require('path');
- const absolutePath = Editor.assetdb.urlToFspath(path);
- const dirPath = pathModule.dirname(absolutePath);
- if (!fs.existsSync(dirPath)) {
- fs.mkdirSync(dirPath, { recursive: true });
- }
- // 创建 TypeScript 脚本
- Editor.assetdb.create(path, content || `const { ccclass, property } = cc._decorator;
-
-@ccclass
-export default class NewScript extends cc.Component {
- // LIFE-CYCLE CALLBACKS:
-
- onLoad () {}
-
- start () {}
-
- update (dt) {}
-}`, (err) => {
- callback(err, err ? null : `Script created at ${path}`);
- });
- break;
- // 其他操作...
- }
-}
-```
-
-### 3.5 批处理执行实现
-
-在 `main.js` 中实现批处理功能:
-
-```javascript
-batchExecute(args, callback) {
- const { operations } = args;
- const results = [];
- let completed = 0;
-
- if (!operations || operations.length === 0) {
- return callback("No operations provided");
- }
-
- operations.forEach((operation, index) => {
- this.handleMcpCall(operation.tool, operation.params, (err, result) => {
- results[index] = { tool: operation.tool, error: err, result: result };
- completed++;
-
- if (completed === operations.length) {
- callback(null, results);
- }
- });
- });
-}
-```
-
-### 3.6 资产管理实现
-
-在 `main.js` 中实现资产管理功能:
-
-```javascript
-manageAsset(args, callback) {
- const { action, path, targetPath, content } = args;
-
- switch (action) {
- case "create":
- // 确保父目录存在
- const fs = require('fs');
- const pathModule = require('path');
- const absolutePath = Editor.assetdb.urlToFspath(path);
- const dirPath = pathModule.dirname(absolutePath);
- if (!fs.existsSync(dirPath)) {
- fs.mkdirSync(dirPath, { recursive: true });
- }
- Editor.assetdb.create(path, content || '', (err) => {
- callback(err, err ? null : `Asset created at ${path}`);
- });
- break;
- // 其他操作...
- }
-}
-```
-
-### 3.7 面板界面实现
-
-在 `panel/index.html` 中实现标签页界面:
-
-```html
-
-
-
- Main
- Tool Test
-
-
-
-
-
-
-
-
-
-
-```
-
-## 4. 测试与调试
-
-### 4.1 本地测试
-
-1. **启动服务**:在面板中点击 "Start" 按钮
-2. **测试工具**:在 "Tool Test" 标签页中测试各个工具
-3. **查看日志**:在主面板中查看操作日志
-
-### 4.2 常见错误及修复
-
-#### 4.2.1 面板加载错误
-
-**错误信息**:`Panel info not found for panel mcp-bridge`
-
-**解决方案**:
-
-- 检查 `package.json` 中的面板配置
-- 确保 `panel` 字段配置正确,移除冲突的 `panels` 字段
-
-#### 4.2.2 资源创建错误
-
-**错误信息**:`Parent path ... is not exists`
-
-**解决方案**:
-
-- 在创建资源前添加目录检查和创建逻辑
-- 使用 `fs.mkdirSync(dirPath, { recursive: true })` 递归创建目录
-
-#### 4.2.3 脚本语法错误
-
-**错误信息**:`SyntaxError: Invalid or unexpected token`
-
-**解决方案**:
-
-- 使用模板字符串(反引号)处理多行字符串
-- 避免变量名冲突
-
-### 4.3 性能优化
-
-1. **批处理执行**:使用 `batch_execute` 工具减少 HTTP 请求次数
-2. **异步操作**:使用回调函数处理异步操作,避免阻塞主线程
-3. **错误处理**:完善错误处理机制,提高插件稳定性
-
-## 5. 文档编写
-
-### 5.1 README.md
-
-- 项目简介
-- 功能特性
-- 安装使用
-- API 文档
-- 技术实现
-
-### 5.2 API 文档
-
-为每个 MCP 工具编写详细的 API 文档,包括:
-
-- 工具名称
-- 功能描述
-- 参数说明
-- 返回值格式
-- 使用示例
-
-### 5.3 开发文档
-
-- 项目架构
-- 开发流程
-- 代码规范
-- 贡献指南
-
-## 6. 部署与使用
-
-### 6.1 部署方式
-
-1. **本地部署**:将插件复制到 Cocos Creator 项目的 `packages` 目录
-2. **远程部署**:通过版本控制系统管理插件代码
-
-### 6.2 使用流程
-
-1. **启动服务**:
- - 打开 Cocos Creator 编辑器
- - 选择 `Packages/MCP Bridge/Open Test Panel`
- - 点击 "Start" 按钮启动服务
-
-2. **连接 AI 编辑器**:
- - 在 AI 编辑器中配置 MCP 代理
- - 使用 `node [项目路径]/packages/mcp-bridge/mcp-proxy.js` 作为命令
-
-3. **执行操作**:
- - 通过 AI 编辑器发送 MCP 请求
- - 或在测试面板中直接测试工具
-
-### 6.3 配置选项
-
-- **端口设置**:默认 3456,可自定义
-- **自动启动**:支持编辑器启动时自动开启服务
-
-## 7. 功能扩展
-
-### 7.1 添加新工具
-
-1. **在 `main.js` 中注册工具**:
- - 在 `/list-tools` 响应中添加工具定义
- - 在 `handleMcpCall` 函数中添加处理逻辑
-
-2. **在面板中添加示例**:
- - 在 `panel/index.js` 中添加工具示例参数
- - 更新工具列表
-
-3. **更新文档**:
- - 在 `README.md` 中添加工具文档
- - 更新功能特性列表
-
-### 7.2 集成新 API
-
-1. **了解 Cocos Creator API**:
- - 查阅 Cocos Creator 编辑器 API 文档
- - 了解场景脚本 API
-
-2. **实现集成**:
- - 在 `main.js` 或 `scene-script.js` 中添加对应功能
- - 处理异步操作和错误情况
-
-3. **测试验证**:
- - 编写测试用例
- - 验证功能正确性
-
-## 8. 版本管理
-
-### 8.1 版本控制
-
-- 使用 Git 进行版本控制
-- 遵循语义化版本规范
-
-### 8.2 发布流程
-
-1. **代码审查**:检查代码质量和功能完整性
-2. **测试验证**:确保所有功能正常工作
-3. **文档更新**:更新 README 和相关文档
-4. **版本发布**:标记版本号并发布
-
-## 9. 技术栈
-
-- **JavaScript**:主要开发语言
-- **Node.js**:HTTP 服务和文件操作
-- **Cocos Creator API**:编辑器功能集成
-- **HTML/CSS**:面板界面
-- **MCP 协议**:与 AI 工具通信
-
-## 10. 最佳实践
-
-1. **代码组织**:
- - 模块化设计,职责分离
- - 合理使用回调函数处理异步操作
-
-2. **错误处理**:
- - 完善的错误捕获和处理
- - 详细的错误日志记录
-
-3. **用户体验**:
- - 直观的面板界面
- - 实时的操作反馈
- - 详细的日志信息
-
-4. **安全性**:
- - 验证输入参数
- - 防止路径遍历攻击
- - 限制服务访问范围
-
-## 11. 开发路线图 (Roadmap)
-
-### 11.1 第三阶段开发计划(已完成)
-
-| 任务 | 状态 | 描述 |
-| ---------------------- | ------- | ------------------------------------------------------------------- |
-| 编辑器管理工具实现 | ✅ 完成 | 实现 manage_editor 工具,支持编辑器状态控制和操作执行 |
-| 游戏对象查找工具实现 | ✅ 完成 | 实现 find_gameobjects 工具,支持根据条件查找场景节点 |
-| 材质和纹理管理工具实现 | ✅ 完成 | 实现 manage_material 和 manage_texture 工具,支持材质和纹理资源管理 |
-| 菜单项执行工具实现 | ✅ 完成 | 实现 execute_menu_item 工具,支持执行 Cocos Creator 菜单项 |
-| 代码编辑增强工具实现 | ✅ 完成 | 实现 apply_text_edits 工具,支持文本编辑操作应用 |
-| 控制台读取工具实现 | ✅ 完成 | 实现 read_console 工具,支持读取编辑器控制台输出 |
-| 脚本验证工具实现 | ✅ 完成 | 实现 validate_script 工具,支持脚本语法验证 |
-
-### 11.2 第四阶段开发计划(已完成)
-
-| 任务 | 状态 | 描述 |
-| ------------ | ------- | ---------------------------------------------- |
-| 测试功能实现 | ✅ 完成 | 实现 run_tests.js 脚本,支持运行自动化测试用例 |
-| 错误处理增强 | ✅ 完成 | 完善 HTTP 服务和工具调用的错误日志记录 |
-
-### 11.3 差异填补阶段(Gap Filling)- 已完成
-
-| 任务 | 状态 | 描述 |
-| -------- | ------- | ---------------------------------------------- |
-| 特效管理 | ✅ 完成 | 实现 manage_vfx 工具,支持粒子系统管理 |
-| 文件哈希 | ✅ 完成 | 实现 get_sha 工具,支持文件 SHA-256 计算 |
-| 动画管理 | ✅ 完成 | 实现 manage_animation 工具,支持动画播放与控制 |
-
-### 11.4 第六阶段:可靠性与体验优化(已完成)
-
-| 任务 | 状态 | 描述 |
-| ---------------- | ------- | -------------------------------------------------------------------------- |
-| IPC 工具增强 | ✅ 完成 | 修复 IpcManager 返回值解析,优化测试面板 (JSON 参数、筛选) |
-| 脚本可靠性修复 | ✅ 完成 | 解决脚本编译时序导致的挂载失败问题 (文档引导 + 刷新机制) |
-| 组件智能解析修复 | ✅ 完成 | 修复组件属性赋值时的 UUID 类型转换,支持压缩 UUID 及自定义组件 (`$_$ctor`) |
-
-### 11.5 第七阶段开发计划(已完成)
-
-| 任务 | 状态 | 描述 |
-| ---------- | ------- | ----------------------------------------- |
-| 插件发布 | ✅ 完成 | 准备发布,提交到 Cocos 插件商店 |
-| 文档完善 | ✅ 完成 | 完善 API 文档 ("Getting Started" 教程) |
-| 界面美化 | ✅ 完成 | 优化面板 UI 体验 |
-| 国际化支持 | ✅ 完成 | 添加多语言 (i18n) 支持 (主要是中文本地化) |
-| 工具扩展 | ✅ 完成 | 添加更多高级工具 |
-
-## 12. Unity-MCP 对比分析
-
-### 12.1 功能差距 (Gap Analysis)
-
-通过与 Unity-MCP 对比,Cocos-MCP 已实现绝大多数核心功能。
-
-| 功能类别 | Unity-MCP 功能 | Cocos-MCP 状态 | 备注 |
-| ---------------- | ----------------- | -------------- | ------------------------------------- |
-| 编辑器管理 | manage_editor | ✅ 已实现 | |
-| 游戏对象管理 | find_gameobjects | ✅ 已实现 | |
-| 材质管理 | manage_material | ✅ 已实现 | |
-| 纹理管理 | manage_texture | ✅ 已实现 | |
-| 代码编辑 | apply_text_edits | ✅ 已实现 | |
-| 全局搜索 | search_project | ✅ 已实现 | 升级版,支持正则和路径限定 |
-| 控制台 | read_console | ✅ 已实现 | |
-| 菜单执行 | execute_menu_item | ✅ 已实现 | 移除不稳定映射,推荐 delete-node:UUID |
-| 脚本验证 | validate_script | ✅ 已实现 | |
-| 撤销/重做 | undo/redo | ✅ 已实现 | |
-| VFX 管理 | manage_vfx | ✅ 已实现 | |
-| Git 集成 | get_sha | ✅ 已实现 | 虽然优先级中等,但已根据需求完成 |
-| 动画管理 | manage_animation | ✅ 已实现 | 支持播放、暂停、停止及信息获取 |
-| ScriptableObject | manage_so | ❌ 未实现 | 使用 AssetDB 替代 |
-
-## 13. 风险评估
-
-### 13.1 潜在风险
-
-| 风险 | 影响 | 缓解措施 |
-| --------------- | ------------ | ----------------------------------------- |
-| 编辑器 API 变更 | 插件功能失效 | 定期检查 Cocos 更新,适配新 API |
-| 性能问题 | 插件响应缓慢 | 优化批处理 (batch_execute),减少 IPC 通讯 |
-| 安全漏洞 | 未授权访问 | (规划中) 面板设置 IP 白名单/Token 认证 |
-| 兼容性问题 | 多版本不兼容 | 测试主流版本 (2.4.x),提供兼容层 |
-
-## 14. 结论
-
-Cocos-MCP 插件的开发计划已顺利完成多个迭代阶段。目前插件实现了包括编辑器管理、场景操作、资源管理在内的全套核心功能,并完成了针对性的可靠性加固(IPC 通信、脚本时序、组件解析)。
-
-插件功能已趋于稳定,后续工作重点将转向 **发布准备**、**文档体系建设** 以及 **用户体验优化**,力求为 Cocos Creator 开发者提供高质量的 AI 辅助开发工具。
diff --git a/README.md b/README.md
index fd972a0..1e02aaa 100644
--- a/README.md
+++ b/README.md
@@ -62,13 +62,13 @@
```
Command: node
-Args: [Cocos Creator 项目的绝对路径]/packages/mcp-bridge/mcp-proxy.js
+Args: [Cocos Creator 项目的绝对路径]/packages/mcp-bridge/src/mcp-proxy.js
```
例如,在你的项目中,完整路径应该是:
```
-Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.js
+Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/src/mcp-proxy.js
```
### 或者添加 JSON 配置:
@@ -78,13 +78,13 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
"mcpServers": {
"cocos-creator": {
"command": "node",
- "args": ["[Cocos Creator 项目的绝对路径]/packages/mcp-bridge/mcp-proxy.js"]
+ "args": ["[Cocos Creator 项目的绝对路径]/packages/mcp-bridge/src/mcp-proxy.js"]
}
}
}
```
-注意:请将上述配置中的路径替换为你自己项目中 `mcp-proxy.js` 文件的实际绝对路径。
+注意:请将上述配置中的路径替换为你自己项目中 `src/mcp-proxy.js` 文件的实际绝对路径。
## API 接口
@@ -373,8 +373,11 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
插件采用了典型的 Cocos Creator 扩展架构,包含以下几个部分:
-- **main.js**: 插件主入口,负责启动 HTTP 服务和处理 MCP 请求
-- **scene-script.js**: 场景脚本,负责实际执行节点操作
+- **src/main.js**: 插件主入口,负责启动 HTTP 服务和处理 MCP 请求
+- **src/scene-script.js**: 场景脚本,负责实际执行节点操作
+- **src/mcp-proxy.js**: MCP 代理,负责在 AI 工具和插件之间转发请求
+- **src/IpcManager.js**: IPC 消息管理器
+- **src/IpcUi.js**: IPC 测试面板 UI
- **panel/**: 面板界面,提供用户交互界面
- `index.html`: 面板 UI 结构
- `index.js`: 面板交互逻辑
@@ -393,9 +396,9 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
### 数据流
1. 外部工具发送 MCP 请求到插件的 HTTP 接口
-2. main.js 接收请求并解析参数
-3. 通过 Editor.Scene.callSceneScript 将请求转发给 scene-script.js
-4. scene-script.js 在场景线程中执行具体操作
+2. src/main.js 接收请求并解析参数
+3. 通过 Editor.Scene.callSceneScript 将请求转发给 src/scene-script.js
+4. src/scene-script.js 在场景线程中执行具体操作
5. 将结果返回给外部工具
## 开发指南
@@ -404,9 +407,9 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
要在插件中添加新的 MCP 工具,需要:
-1. 在 main.js 的 `/list-tools` 响应中添加工具定义
+1. 在 src/main.js 的 `/list-tools` 响应中添加工具定义
2. 在 handleMcpCall 函数中添加对应的处理逻辑
-3. 如需在场景线程中执行,需要在 scene-script.js 中添加对应函数
+3. 如需在场景线程中执行,需要在 src/scene-script.js 中添加对应函数
### 日志管理
@@ -439,7 +442,7 @@ Args: [你的项目所在盘符]:/[项目路径]/packages/mcp-bridge/mcp-proxy.j
## 更新日志
-请查阅 [UPDATE_LOG.md](./UPDATE_LOG.md) 了解详细的版本更新历史、功能优化与修复过程。
+请查阅 [UPDATE_LOG.md](./docs/UPDATE_LOG.md) 了解详细的版本更新历史、功能优化与修复过程。
## 贡献
diff --git a/dist/IpcManager.js b/dist/IpcManager.js
deleted file mode 100644
index 6ce3fe6..0000000
--- a/dist/IpcManager.js
+++ /dev/null
@@ -1,141 +0,0 @@
-"use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
-};
-var __generator = (this && this.__generator) || function (thisArg, body) {
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
- function verb(n) { return function (v) { return step([n, v]); }; }
- function step(op) {
- if (f) throw new TypeError("Generator is already executing.");
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
- if (y = 0, t) op = [op[0] & 2, t.value];
- switch (op[0]) {
- case 0: case 1: t = op; break;
- case 4: _.label++; return { value: op[1], done: false };
- case 5: _.label++; y = op[1]; op = [0]; continue;
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
- default:
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
- if (t[2]) _.ops.pop();
- _.trys.pop(); continue;
- }
- op = body.call(thisArg, _);
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
- }
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.IpcManager = void 0;
-// @ts-ignore
-var fs = require('fs');
-// @ts-ignore
-var path = require('path');
-/**
- * IPC 消息管理器
- * 负责解析 IPC 文档并执行消息测试
- */
-var IpcManager = /** @class */ (function () {
- function IpcManager() {
- }
- /**
- * 获取所有 IPC 消息列表
- * @returns 消息定义列表
- */
- IpcManager.getIpcMessages = function () {
- // 获取文档路径
- // @ts-ignore
- var docPath = Editor.url('packages://mcp-bridge/IPC_MESSAGES.md');
- if (!fs.existsSync(docPath)) {
- // @ts-ignore
- Editor.error("[IPC Manager] Document not found: ".concat(docPath));
- return [];
- }
- var content = fs.readFileSync(docPath, 'utf-8');
- var messages = [];
- // 正则匹配 ### `message-name`
- var regex = /### `(.*?)`\r?\n([\s\S]*?)(?=### `|$)/g;
- var match;
- while ((match = regex.exec(content)) !== null) {
- var name_1 = match[1];
- var body = match[2];
- // 解析用途
- var purposeMatch = body.match(/- \*\*用途\*\*: (.*)/);
- var description = purposeMatch ? purposeMatch[1].trim() : "无描述";
- // 解析参数
- var paramsMatch = body.match(/- \*\*参数\*\*: (.*)/);
- var params = paramsMatch ? paramsMatch[1].trim() : "无";
- // 解析返回值
- var returnMatch = body.match(/- \*\*返回值\*\*: (.*)/);
- var returns = returnMatch ? returnMatch[1].trim() : "无";
- // 解析类型
- var typeMatch = body.match(/- \*\*类型\*\*: (.*)/);
- var type = typeMatch ? typeMatch[1].trim() : "未定义";
- // 解析状态
- var statusMatch = body.match(/- \*\*状态\*\*: (.*)/);
- var status_1 = statusMatch ? statusMatch[1].trim() : "未测试";
- // 过滤掉广播事件和渲染进程监听的事件
- if (type === "广播事件" || type === "Events listened by Renderer Process" || type === "渲染进程监听") {
- continue;
- }
- messages.push({
- name: name_1,
- description: description,
- params: params,
- returns: returns,
- type: type,
- status: status_1
- });
- }
- return messages;
- };
- /**
- * 测试发送 IPC 消息
- * @param name 消息名称
- * @param args 参数
- * @returns Promise 测试结果
- */
- IpcManager.testIpcMessage = function (name_2) {
- return __awaiter(this, arguments, void 0, function (name, args) {
- if (args === void 0) { args = null; }
- return __generator(this, function (_a) {
- return [2 /*return*/, new Promise(function (resolve) {
- // 简单防呆:防止执行危险操作
- // 如果消息包含 "delete", "remove", "close", "stop" 且没有明确参数确认,则警告
- // 但用户要求"快速验证",所以我们默认允许,但如果是无参调用可能有风险
- // 这里我们尝试使用 Editor.Ipc.sendToMain 或 requestToMain
- // @ts-ignore
- // 简单的测试:只是发送看看是否报错。
- // 对于 request 类型的消息,我们期望有回调
- // Cocos Creator 2.4 API: Editor.Ipc.sendToMain(message, ...args)
- try {
- // @ts-ignore
- if (Editor.Ipc.sendToMain) {
- // @ts-ignore
- Editor.Ipc.sendToMain(name, args);
- resolve({ success: true, message: "Message sent (sendToMain)" });
- }
- else {
- resolve({ success: false, message: "Editor.Ipc.sendToMain not available" });
- }
- }
- catch (e) {
- resolve({ success: false, message: "Error: ".concat(e.message) });
- }
- })];
- });
- });
- };
- return IpcManager;
-}());
-exports.IpcManager = IpcManager;
diff --git a/dist/IpcUi.js b/dist/IpcUi.js
deleted file mode 100644
index 322c0c3..0000000
--- a/dist/IpcUi.js
+++ /dev/null
@@ -1,353 +0,0 @@
-"use strict";
-var __awaiter =
- (this && this.__awaiter) ||
- function (thisArg, _arguments, P, generator) {
- function adopt(value) {
- return value instanceof P
- ? value
- : new P(function (resolve) {
- resolve(value);
- });
- }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) {
- try {
- step(generator.next(value));
- } catch (e) {
- reject(e);
- }
- }
- function rejected(value) {
- try {
- step(generator["throw"](value));
- } catch (e) {
- reject(e);
- }
- }
- function step(result) {
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
- }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
-var __generator =
- (this && this.__generator) ||
- function (thisArg, body) {
- var _ = {
- label: 0,
- sent: function () {
- if (t[0] & 1) throw t[1];
- return t[1];
- },
- trys: [],
- ops: [],
- },
- f,
- y,
- t,
- g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
- return (
- (g.next = verb(0)),
- (g["throw"] = verb(1)),
- (g["return"] = verb(2)),
- typeof Symbol === "function" &&
- (g[Symbol.iterator] = function () {
- return this;
- }),
- g
- );
- function verb(n) {
- return function (v) {
- return step([n, v]);
- };
- }
- function step(op) {
- if (f) throw new TypeError("Generator is already executing.");
- while ((g && ((g = 0), op[0] && (_ = 0)), _))
- try {
- if (
- ((f = 1),
- y &&
- (t =
- op[0] & 2
- ? y["return"]
- : op[0]
- ? y["throw"] || ((t = y["return"]) && t.call(y), 0)
- : y.next) &&
- !(t = t.call(y, op[1])).done)
- )
- return t;
- if (((y = 0), t)) op = [op[0] & 2, t.value];
- switch (op[0]) {
- case 0:
- case 1:
- t = op;
- break;
- case 4:
- _.label++;
- return { value: op[1], done: false };
- case 5:
- _.label++;
- y = op[1];
- op = [0];
- continue;
- case 7:
- op = _.ops.pop();
- _.trys.pop();
- continue;
- default:
- if (
- !((t = _.trys), (t = t.length > 0 && t[t.length - 1])) &&
- (op[0] === 6 || op[0] === 2)
- ) {
- _ = 0;
- continue;
- }
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
- _.label = op[1];
- break;
- }
- if (op[0] === 6 && _.label < t[1]) {
- _.label = t[1];
- t = op;
- break;
- }
- if (t && _.label < t[2]) {
- _.label = t[2];
- _.ops.push(op);
- break;
- }
- if (t[2]) _.ops.pop();
- _.trys.pop();
- continue;
- }
- op = body.call(thisArg, _);
- } catch (e) {
- op = [6, e];
- y = 0;
- } finally {
- f = t = 0;
- }
- if (op[0] & 5) throw op[1];
- return { value: op[0] ? op[1] : void 0, done: true };
- }
- };
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.IpcUi = void 0;
-// @ts-ignore
-var Editor = window.Editor;
-var IpcUi = /** @class */ (function () {
- function IpcUi(root) {
- this.logArea = null;
- this.ipcList = null;
- this.allMessages = [];
- this.filterSelect = null;
- this.paramInput = null;
- this.root = root;
- this.bindEvents();
- }
- IpcUi.prototype.bindEvents = function () {
- var _this = this;
- var btnScan = this.root.querySelector("#btnScanIpc");
- var btnTest = this.root.querySelector("#btnTestIpc");
- var cbSelectAll = this.root.querySelector("#cbSelectAllIpc");
- this.logArea = this.root.querySelector("#ipcLog");
- this.ipcList = this.root.querySelector("#ipcList");
- this.filterSelect = this.root.querySelector("#ipcFilter");
- this.paramInput = this.root.querySelector("#ipcParams");
- if (btnScan) {
- btnScan.addEventListener("confirm", function () {
- return _this.scanMessages();
- });
- }
- if (btnTest) {
- btnTest.addEventListener("confirm", function () {
- return _this.testSelected();
- });
- }
- if (cbSelectAll) {
- cbSelectAll.addEventListener("change", function (e) {
- return _this.toggleAll(e.detail ? e.detail.value : e.target.value === "true" || e.target.checked);
- });
- }
- if (this.filterSelect) {
- this.filterSelect.addEventListener("change", function () {
- return _this.filterMessages();
- });
- }
- };
- IpcUi.prototype.scanMessages = function () {
- var _this = this;
- this.log("正在扫描 IPC 消息...");
- // @ts-ignore
- Editor.Ipc.sendToMain("mcp-bridge:scan-ipc-messages", function (err, msgs) {
- if (err) {
- _this.log("扫描错误: ".concat(err));
- return;
- }
- if (msgs) {
- _this.allMessages = msgs;
- _this.filterMessages();
- _this.log("找到 ".concat(msgs.length, " 条消息。"));
- } else {
- _this.log("未找到任何消息。");
- }
- });
- };
- IpcUi.prototype.filterMessages = function () {
- if (!this.allMessages) return;
- var filter = this.filterSelect ? this.filterSelect.value : "all";
- var filtered = this.allMessages;
- if (filter === "available") {
- filtered = this.allMessages.filter(function (m) {
- return m.status === "可用";
- });
- } else if (filter === "unavailable") {
- filtered = this.allMessages.filter(function (m) {
- return m.status && m.status.includes("不可用");
- });
- } else if (filter === "untested") {
- filtered = this.allMessages.filter(function (m) {
- return !m.status || m.status === "未测试";
- });
- }
- this.renderList(filtered);
- };
- IpcUi.prototype.renderList = function (msgs) {
- var _this = this;
- if (!this.ipcList) return;
- this.ipcList.innerHTML = "";
- msgs.forEach(function (msg) {
- var item = document.createElement("div");
- item.className = "ipc-item";
- item.style.padding = "4px";
- item.style.borderBottom = "1px solid #333";
- item.style.display = "flex";
- item.style.alignItems = "center";
- // Checkbox
- var checkbox = document.createElement("ui-checkbox");
- // @ts-ignore
- checkbox.value = false;
- checkbox.setAttribute("data-name", msg.name);
- checkbox.style.marginRight = "8px";
- // Content
- var content = document.createElement("div");
- content.style.flex = "1";
- content.style.fontSize = "11px";
- var statusColor = "#888"; // Untested
- if (msg.status === "可用")
- statusColor = "#4CAF50"; // Green
- else if (msg.status && msg.status.includes("不可用")) statusColor = "#F44336"; // Red
- content.innerHTML =
- '\n \n '
- .concat(msg.name, '\n ')
- .concat(
- msg.status || "未测试",
- '\n
\n ',
- )
- .concat(
- msg.description || "无描述",
- '
\n 参数: ',
- )
- .concat(msg.params || "无", "
\n ");
- // Action Button
- var btnRun = document.createElement("ui-button");
- btnRun.innerText = "执行";
- btnRun.className = "tiny";
- btnRun.style.height = "20px";
- btnRun.style.lineHeight = "20px";
- btnRun.addEventListener("confirm", function () {
- _this.runTest(msg.name);
- });
- item.appendChild(checkbox);
- item.appendChild(content);
- item.appendChild(btnRun);
- _this.ipcList.appendChild(item);
- });
- };
- IpcUi.prototype.testSelected = function () {
- return __awaiter(this, void 0, void 0, function () {
- var checkboxes, toTest, _i, toTest_1, name_1;
- return __generator(this, function (_a) {
- switch (_a.label) {
- case 0:
- checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
- toTest = [];
- checkboxes.forEach(function (cb) {
- // In Cocos 2.x, ui-checkbox value is boolean
- if (cb.checked || cb.value === true) {
- toTest.push(cb.getAttribute("data-name"));
- }
- });
- if (toTest.length === 0) {
- this.log("未选择任何消息。");
- return [2 /*return*/];
- }
- this.log("开始批量测试 ".concat(toTest.length, " 条消息..."));
- ((_i = 0), (toTest_1 = toTest));
- _a.label = 1;
- case 1:
- if (!(_i < toTest_1.length)) return [3 /*break*/, 4];
- name_1 = toTest_1[_i];
- return [4 /*yield*/, this.runTest(name_1)];
- case 2:
- _a.sent();
- _a.label = 3;
- case 3:
- _i++;
- return [3 /*break*/, 1];
- case 4:
- this.log("批量测试完成。");
- return [2 /*return*/];
- }
- });
- });
- };
- IpcUi.prototype.runTest = function (name) {
- var _this = this;
- return new Promise(function (resolve) {
- var params = null;
- if (_this.paramInput && _this.paramInput.value.trim()) {
- try {
- params = JSON.parse(_this.paramInput.value.trim());
- } catch (e) {
- _this.log("[错误] 无效的 JSON 参数: ".concat(e));
- resolve();
- return;
- }
- }
- _this.log("正在测试: ".concat(name, ",参数: ").concat(JSON.stringify(params), "..."));
- // @ts-ignore
- Editor.Ipc.sendToMain(
- "mcp-bridge:test-ipc-message",
- { name: name, params: params },
- function (err, result) {
- if (err) {
- _this.log("[".concat(name, "] 失败: ").concat(err));
- } else {
- _this.log("[".concat(name, "] 成功: ").concat(JSON.stringify(result)));
- }
- resolve();
- },
- );
- });
- };
- IpcUi.prototype.toggleAll = function (checked) {
- var checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
- checkboxes.forEach(function (cb) {
- cb.value = checked;
- });
- };
- IpcUi.prototype.log = function (msg) {
- if (this.logArea) {
- // @ts-ignore
- var time = new Date().toLocaleTimeString();
- this.logArea.value += "[".concat(time, "] ").concat(msg, "\n");
- this.logArea.scrollTop = this.logArea.scrollHeight;
- }
- };
- return IpcUi;
-})();
-exports.IpcUi = IpcUi;
diff --git a/IPC_MESSAGES.md b/docs/IPC_MESSAGES.md
similarity index 100%
rename from IPC_MESSAGES.md
rename to docs/IPC_MESSAGES.md
diff --git a/UPDATE_LOG.md b/docs/UPDATE_LOG.md
similarity index 100%
rename from UPDATE_LOG.md
rename to docs/UPDATE_LOG.md
diff --git a/注意事项.md b/docs/注意事项.md
similarity index 100%
rename from 注意事项.md
rename to docs/注意事项.md
diff --git a/package.json b/package.json
index 85ddd51..881e9d0 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,8 @@
"version": "1.0.0",
"description": "Cocos Creator MCP 桥接插件",
"author": "Firekula",
- "main": "main.js",
- "scene-script": "scene-script.js",
+ "main": "src/main.js",
+ "scene-script": "src/scene-script.js",
"main-menu": {
"MCP 桥接器/开启测试面板": {
"message": "mcp-bridge:open-test-panel"
diff --git a/panel/index.js b/panel/index.js
index b071f04..a0fb0b7 100644
--- a/panel/index.js
+++ b/panel/index.js
@@ -6,7 +6,7 @@
*/
const fs = require("fs");
-const { IpcUi } = require("../dist/IpcUi");
+const { IpcUi } = require("../src/IpcUi");
Editor.Panel.extend({
/**
@@ -87,7 +87,7 @@ Editor.Panel.extend({
}
});
- // 初始化 IPC 调试专用 UI (由 TypeScript 编写并编译到 dist)
+ // 初始化 IPC 调试专用 UI
new IpcUi(root);
// 2. 标签页切换逻辑
diff --git a/src/IpcManager.js b/src/IpcManager.js
new file mode 100644
index 0000000..082ac01
--- /dev/null
+++ b/src/IpcManager.js
@@ -0,0 +1,95 @@
+"use strict";
+
+const fs = require("fs");
+const path = require("path");
+
+/**
+ * IPC 消息管理器
+ * 负责解析 IPC 文档并执行消息测试
+ */
+class IpcManager {
+ /**
+ * 获取所有 IPC 消息列表
+ * @returns {Array} 消息定义列表
+ */
+ static getIpcMessages() {
+ // 获取文档路径
+ const docPath = Editor.url("packages://mcp-bridge/docs/IPC_MESSAGES.md");
+ if (!fs.existsSync(docPath)) {
+ Editor.error(`[IPC 管理器] 找不到文档文件: ${docPath}`);
+ return [];
+ }
+
+ const content = fs.readFileSync(docPath, "utf-8");
+ const messages = [];
+
+ // 正则匹配 ### `message-name`
+ const regex = /### `(.*?)`\r?\n([\s\S]*?)(?=### `|$)/g;
+ let match;
+
+ while ((match = regex.exec(content)) !== null) {
+ const name = match[1];
+ const body = match[2];
+
+ // 解析用途
+ const purposeMatch = body.match(/- \*\*用途\*\*: (.*)/);
+ const description = purposeMatch ? purposeMatch[1].trim() : "无描述";
+
+ // 解析参数
+ const paramsMatch = body.match(/- \*\*参数\*\*: (.*)/);
+ const params = paramsMatch ? paramsMatch[1].trim() : "无";
+
+ // 解析返回值
+ const returnMatch = body.match(/- \*\*返回值\*\*: (.*)/);
+ const returns = returnMatch ? returnMatch[1].trim() : "无";
+
+ // 解析类型
+ const typeMatch = body.match(/- \*\*类型\*\*: (.*)/);
+ const type = typeMatch ? typeMatch[1].trim() : "未定义";
+
+ // 解析状态
+ const statusMatch = body.match(/- \*\*状态\*\*: (.*)/);
+ const status = statusMatch ? statusMatch[1].trim() : "未测试";
+
+ // 过滤掉广播事件和渲染进程监听的事件
+ if (type === "广播事件" || type === "Events listened by Renderer Process" || type === "渲染进程监听") {
+ continue;
+ }
+
+ messages.push({
+ name,
+ description,
+ params,
+ returns,
+ type,
+ status,
+ });
+ }
+
+ return messages;
+ }
+
+ /**
+ * 测试发送 IPC 消息
+ * @param {string} name 消息名称
+ * @param {*} args 参数
+ * @returns {Promise} 测试结果
+ */
+ static testIpcMessage(name, args) {
+ if (args === undefined) args = null;
+ return new Promise((resolve) => {
+ try {
+ if (Editor.Ipc.sendToMain) {
+ Editor.Ipc.sendToMain(name, args);
+ resolve({ success: true, message: "消息已发送 (sendToMain)" });
+ } else {
+ resolve({ success: false, message: "Editor.Ipc.sendToMain 不可用" });
+ }
+ } catch (e) {
+ resolve({ success: false, message: `错误: ${e.message}` });
+ }
+ });
+ }
+}
+
+module.exports = { IpcManager };
diff --git a/src/IpcManager.ts b/src/IpcManager.ts
deleted file mode 100644
index 5a3a309..0000000
--- a/src/IpcManager.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-// @ts-ignore
-const fs = require("fs");
-// @ts-ignore
-const path = require("path");
-
-/**
- * IPC 消息管理器
- * 负责解析 IPC 文档并执行消息测试
- */
-export class IpcManager {
- /**
- * 获取所有 IPC 消息列表
- * @returns 消息定义列表
- */
- public static getIpcMessages(): any[] {
- // 获取文档路径
- // @ts-ignore
- const docPath = Editor.url("packages://mcp-bridge/IPC_MESSAGES.md");
- if (!fs.existsSync(docPath)) {
- // @ts-ignore
- Editor.error(`[IPC 管理器] 找不到文档文件: ${docPath}`);
- return [];
- }
-
- const content = fs.readFileSync(docPath, "utf-8");
- const messages: any[] = [];
-
- // 正则匹配 ### `message-name`
- const regex = /### `(.*?)`\r?\n([\s\S]*?)(?=### `|$)/g;
- let match;
-
- while ((match = regex.exec(content)) !== null) {
- const name = match[1];
- const body = match[2];
-
- // 解析用途
- const purposeMatch = body.match(/- \*\*用途\*\*: (.*)/);
- const description = purposeMatch ? purposeMatch[1].trim() : "无描述";
-
- // 解析参数
- const paramsMatch = body.match(/- \*\*参数\*\*: (.*)/);
- const params = paramsMatch ? paramsMatch[1].trim() : "无";
-
- // 解析返回值
- const returnMatch = body.match(/- \*\*返回值\*\*: (.*)/);
- const returns = returnMatch ? returnMatch[1].trim() : "无";
-
- // 解析类型
- const typeMatch = body.match(/- \*\*类型\*\*: (.*)/);
- const type = typeMatch ? typeMatch[1].trim() : "未定义";
-
- // 解析状态
- const statusMatch = body.match(/- \*\*状态\*\*: (.*)/);
- const status = statusMatch ? statusMatch[1].trim() : "未测试";
-
- // 过滤掉广播事件和渲染进程监听的事件
- if (type === "广播事件" || type === "Events listened by Renderer Process" || type === "渲染进程监听") {
- continue;
- }
-
- messages.push({
- name,
- description,
- params,
- returns,
- type,
- status,
- });
- }
-
- return messages;
- }
-
- /**
- * 测试发送 IPC 消息
- * @param name 消息名称
- * @param args 参数
- * @returns Promise 测试结果
- */
- public static async testIpcMessage(name: string, args: any = null): Promise {
- return new Promise((resolve) => {
- // 简单防呆:防止执行危险操作
- // 如果消息包含 "delete", "remove", "close", "stop" 且没有明确参数确认,则警告
- // 但用户要求"快速验证",所以我们默认允许,但如果是无参调用可能有风险
- // 这里我们尝试使用 Editor.Ipc.sendToMain 或 requestToMain
-
- // @ts-ignore
- // 简单的测试:只是发送看看是否报错。
- // 对于 request 类型的消息,我们期望有回调
- // Cocos Creator 2.4 API: Editor.Ipc.sendToMain(message, ...args)
-
- try {
- // @ts-ignore
- if (Editor.Ipc.sendToMain) {
- // @ts-ignore
- Editor.Ipc.sendToMain(name, args);
- resolve({ success: true, message: "消息已发送 (sendToMain)" });
- } else {
- resolve({ success: false, message: "Editor.Ipc.sendToMain 不可用" });
- }
- } catch (e: any) {
- resolve({ success: false, message: `错误: ${e.message}` });
- }
- });
- }
-}
diff --git a/src/IpcUi.js b/src/IpcUi.js
new file mode 100644
index 0000000..d5568c6
--- /dev/null
+++ b/src/IpcUi.js
@@ -0,0 +1,226 @@
+"use strict";
+
+/**
+ * IPC 测试面板 UI 管理器
+ * 负责在面板中展示和测试 IPC 消息
+ */
+class IpcUi {
+ /**
+ * 构造函数
+ * @param {ShadowRoot} root Shadow UI 根节点
+ */
+ constructor(root) {
+ this.root = root;
+ this.logArea = null;
+ this.ipcList = null;
+ this.allMessages = [];
+ this.filterSelect = null;
+ this.paramInput = null;
+ this.bindEvents();
+ }
+
+ /**
+ * 绑定 UI 事件
+ */
+ bindEvents() {
+ const btnScan = this.root.querySelector("#btnScanIpc");
+ const btnTest = this.root.querySelector("#btnTestIpc");
+ const cbSelectAll = this.root.querySelector("#cbSelectAllIpc");
+ this.logArea = this.root.querySelector("#ipcLog");
+ this.ipcList = this.root.querySelector("#ipcList");
+ this.filterSelect = this.root.querySelector("#ipcFilter");
+ this.paramInput = this.root.querySelector("#ipcParams");
+
+ if (btnScan) {
+ btnScan.addEventListener("confirm", () => this.scanMessages());
+ }
+ if (btnTest) {
+ btnTest.addEventListener("confirm", () => this.testSelected());
+ }
+ if (cbSelectAll) {
+ cbSelectAll.addEventListener("change", (e) =>
+ this.toggleAll(e.detail ? e.detail.value : e.target.value === "true" || e.target.checked),
+ );
+ }
+ if (this.filterSelect) {
+ this.filterSelect.addEventListener("change", () => this.filterMessages());
+ }
+ }
+
+ /**
+ * 扫描 IPC 消息
+ */
+ scanMessages() {
+ this.log("正在扫描 IPC 消息...");
+ Editor.Ipc.sendToMain("mcp-bridge:scan-ipc-messages", (err, msgs) => {
+ if (err) {
+ this.log(`扫描错误: ${err}`);
+ return;
+ }
+ if (msgs) {
+ this.allMessages = msgs;
+ this.filterMessages();
+ this.log(`找到 ${msgs.length} 条消息。`);
+ } else {
+ this.log("未找到任何消息。");
+ }
+ });
+ }
+
+ /**
+ * 根据当前选择器过滤消息列表
+ */
+ filterMessages() {
+ if (!this.allMessages) return;
+ const filter = this.filterSelect ? this.filterSelect.value : "all";
+
+ let filtered = this.allMessages;
+ if (filter === "available") {
+ filtered = this.allMessages.filter((m) => m.status === "可用");
+ } else if (filter === "unavailable") {
+ filtered = this.allMessages.filter((m) => m.status && m.status.includes("不可用"));
+ } else if (filter === "untested") {
+ filtered = this.allMessages.filter((m) => !m.status || m.status === "未测试");
+ }
+
+ this.renderList(filtered);
+ }
+
+ /**
+ * 渲染消息列表 UI
+ * @param {Array} msgs 消息对象数组
+ */
+ renderList(msgs) {
+ if (!this.ipcList) return;
+ this.ipcList.innerHTML = "";
+
+ msgs.forEach((msg) => {
+ const item = document.createElement("div");
+ item.className = "ipc-item";
+ item.style.padding = "4px";
+ item.style.borderBottom = "1px solid #333";
+ item.style.display = "flex";
+ item.style.alignItems = "center";
+
+ // 复选框
+ const checkbox = document.createElement("ui-checkbox");
+ checkbox.value = false;
+ checkbox.setAttribute("data-name", msg.name);
+ checkbox.style.marginRight = "8px";
+
+ // 内容区域
+ const content = document.createElement("div");
+ content.style.flex = "1";
+ content.style.fontSize = "11px";
+
+ let statusColor = "#888"; // 未测试
+ if (msg.status === "可用")
+ statusColor = "#4CAF50"; // 绿色
+ else if (msg.status && msg.status.includes("不可用")) statusColor = "#F44336"; // 红色
+
+ content.innerHTML = `
+
+ ${msg.name}
+ ${msg.status || "未测试"}
+
+ ${msg.description || "无描述"}
+ 参数: ${msg.params || "无"}
+ `;
+
+ // 执行按钮
+ const btnRun = document.createElement("ui-button");
+ btnRun.innerText = "执行";
+ btnRun.className = "tiny";
+ btnRun.style.height = "20px";
+ btnRun.style.lineHeight = "20px";
+ btnRun.addEventListener("confirm", () => {
+ this.runTest(msg.name);
+ });
+
+ item.appendChild(checkbox);
+ item.appendChild(content);
+ item.appendChild(btnRun);
+ this.ipcList.appendChild(item);
+ });
+ }
+
+ /**
+ * 测试所有选中的 IPC 消息
+ */
+ async testSelected() {
+ const checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
+ const toTest = [];
+ checkboxes.forEach((cb) => {
+ // 在 Cocos 2.x 中, ui-checkbox 的值是布尔型
+ if (cb.checked || cb.value === true) {
+ toTest.push(cb.getAttribute("data-name"));
+ }
+ });
+
+ if (toTest.length === 0) {
+ this.log("未选择任何消息。");
+ return;
+ }
+
+ this.log(`开始批量测试 ${toTest.length} 条消息...`);
+ for (const name of toTest) {
+ await this.runTest(name);
+ }
+ this.log("批量测试完成。");
+ }
+
+ /**
+ * 运行单个测试请求
+ * @param {string} name 消息名称
+ * @returns {Promise}
+ */
+ runTest(name) {
+ return new Promise((resolve) => {
+ let params = null;
+ if (this.paramInput && this.paramInput.value.trim()) {
+ try {
+ params = JSON.parse(this.paramInput.value.trim());
+ } catch (e) {
+ this.log(`[错误] 无效的 JSON 参数: ${e}`);
+ resolve();
+ return;
+ }
+ }
+
+ this.log(`正在测试: ${name},参数: ${JSON.stringify(params)}...`);
+ Editor.Ipc.sendToMain("mcp-bridge:test-ipc-message", { name, params }, (err, result) => {
+ if (err) {
+ this.log(`[${name}] 失败: ${err}`);
+ } else {
+ this.log(`[${name}] 成功: ${JSON.stringify(result)}`);
+ }
+ resolve();
+ });
+ });
+ }
+
+ /**
+ * 全选/取消全选
+ * @param {boolean} checked 是否选中
+ */
+ toggleAll(checked) {
+ const checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
+ checkboxes.forEach((cb) => {
+ cb.value = checked;
+ });
+ }
+
+ /**
+ * 输出日志到界面
+ * @param {string} msg 日志消息
+ */
+ log(msg) {
+ if (this.logArea) {
+ const time = new Date().toLocaleTimeString();
+ this.logArea.value += `[${time}] ${msg}\n`;
+ this.logArea.scrollTop = this.logArea.scrollHeight;
+ }
+ }
+}
+
+module.exports = { IpcUi };
diff --git a/src/IpcUi.ts b/src/IpcUi.ts
deleted file mode 100644
index eb23128..0000000
--- a/src/IpcUi.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-// @ts-ignore
-const Editor = window.Editor;
-
-export class IpcUi {
- private root: ShadowRoot;
- private logArea: HTMLTextAreaElement | null = null;
- private ipcList: HTMLElement | null = null;
- private allMessages: any[] = [];
- private filterSelect: HTMLSelectElement | null = null;
- private paramInput: HTMLTextAreaElement | null = null;
-
- /**
- * 构造函数
- * @param root Shadow UI 根节点
- */
- constructor(root: ShadowRoot) {
- this.root = root;
- this.bindEvents();
- }
-
- /**
- * 绑定 UI 事件
- */
- private bindEvents() {
- const btnScan = this.root.querySelector("#btnScanIpc");
- const btnTest = this.root.querySelector("#btnTestIpc");
- const cbSelectAll = this.root.querySelector("#cbSelectAllIpc");
- this.logArea = this.root.querySelector("#ipcLog") as HTMLTextAreaElement;
- this.ipcList = this.root.querySelector("#ipcList") as HTMLElement;
- this.filterSelect = this.root.querySelector("#ipcFilter") as HTMLSelectElement;
- this.paramInput = this.root.querySelector("#ipcParams") as HTMLTextAreaElement;
-
- if (btnScan) {
- btnScan.addEventListener("confirm", () => this.scanMessages());
- }
- if (btnTest) {
- btnTest.addEventListener("confirm", () => this.testSelected());
- }
- if (cbSelectAll) {
- cbSelectAll.addEventListener("change", (e: any) =>
- this.toggleAll(e.detail ? e.detail.value : e.target.value === "true" || e.target.checked),
- );
- }
- if (this.filterSelect) {
- this.filterSelect.addEventListener("change", () => this.filterMessages());
- }
- }
-
- /**
- * 扫描 IPC 消息
- */
- private scanMessages() {
- this.log("正在扫描 IPC 消息...");
- // @ts-ignore
- Editor.Ipc.sendToMain("mcp-bridge:scan-ipc-messages", (err: any, msgs: any[]) => {
- if (err) {
- this.log(`扫描错误: ${err}`);
- return;
- }
- if (msgs) {
- this.allMessages = msgs;
- this.filterMessages();
- this.log(`找到 ${msgs.length} 条消息。`);
- } else {
- this.log("未找到任何消息。");
- }
- });
- }
-
- /**
- * 根据当前选择器过滤消息列表
- */
- private filterMessages() {
- if (!this.allMessages) return;
- const filter = this.filterSelect ? this.filterSelect.value : "all";
-
- let filtered = this.allMessages;
- if (filter === "available") {
- filtered = this.allMessages.filter((m) => m.status === "可用");
- } else if (filter === "unavailable") {
- filtered = this.allMessages.filter((m) => m.status && m.status.includes("不可用"));
- } else if (filter === "untested") {
- filtered = this.allMessages.filter((m) => !m.status || m.status === "未测试");
- }
-
- this.renderList(filtered);
- }
-
- /**
- * 渲染消息列表 UI
- * @param msgs 消息对象数组
- */
- private renderList(msgs: any[]) {
- if (!this.ipcList) return;
- this.ipcList.innerHTML = "";
-
- msgs.forEach((msg) => {
- const item = document.createElement("div");
- item.className = "ipc-item";
- item.style.padding = "4px";
- item.style.borderBottom = "1px solid #333";
- item.style.display = "flex";
- item.style.alignItems = "center";
-
- // 复选框
- const checkbox = document.createElement("ui-checkbox");
- // @ts-ignore
- checkbox.value = false;
- checkbox.setAttribute("data-name", msg.name);
- checkbox.style.marginRight = "8px";
-
- // 内容区域
- const content = document.createElement("div");
- content.style.flex = "1";
- content.style.fontSize = "11px";
-
- let statusColor = "#888"; // 未测试
- if (msg.status === "可用")
- statusColor = "#4CAF50"; // 绿色
- else if (msg.status && msg.status.includes("不可用")) statusColor = "#F44336"; // 红色
-
- content.innerHTML = `
-
- ${msg.name}
- ${msg.status || "未测试"}
-
- ${msg.description || "无描述"}
- 参数: ${msg.params || "无"}
- `;
-
- // 执行按钮
- const btnRun = document.createElement("ui-button");
- btnRun.innerText = "执行";
- btnRun.className = "tiny";
- btnRun.style.height = "20px";
- btnRun.style.lineHeight = "20px";
- btnRun.addEventListener("confirm", () => {
- this.runTest(msg.name);
- });
-
- item.appendChild(checkbox);
- item.appendChild(content);
- item.appendChild(btnRun);
- this.ipcList!.appendChild(item);
- });
- }
-
- /**
- * 测试所有选中的 IPC 消息
- */
- private async testSelected() {
- const checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
- const toTest: string[] = [];
- checkboxes.forEach((cb: any) => {
- // 在 Cocos 2.x 中, ui-checkbox 的值是布尔型
- if (cb.checked || cb.value === true) {
- toTest.push(cb.getAttribute("data-name"));
- }
- });
-
- if (toTest.length === 0) {
- this.log("未选择任何消息。");
- return;
- }
-
- this.log(`开始批量测试 ${toTest.length} 条消息...`);
- for (const name of toTest) {
- await this.runTest(name);
- }
- this.log("批量测试完成。");
- }
-
- /**
- * 运行单个测试请求
- * @param name 消息名称
- */
- private runTest(name: string): Promise {
- return new Promise((resolve) => {
- let params = null;
- if (this.paramInput && this.paramInput.value.trim()) {
- try {
- params = JSON.parse(this.paramInput.value.trim());
- } catch (e) {
- this.log(`[错误] 无效的 JSON 参数: ${e}`);
- resolve();
- return;
- }
- }
-
- this.log(`正在测试: ${name},参数: ${JSON.stringify(params)}...`);
- // @ts-ignore
- Editor.Ipc.sendToMain("mcp-bridge:test-ipc-message", { name, params }, (err: any, result: any) => {
- if (err) {
- this.log(`[${name}] 失败: ${err}`);
- } else {
- this.log(`[${name}] 成功: ${JSON.stringify(result)}`);
- }
- resolve();
- });
- });
- }
-
- /**
- * 全选/取消全选
- * @param checked 是否选中
- */
- private toggleAll(checked: boolean) {
- const checkboxes = this.root.querySelectorAll("#ipcList ui-checkbox");
- checkboxes.forEach((cb: any) => {
- cb.value = checked;
- });
- }
-
- /**
- * 输出日志到界面
- * @param msg 日志消息
- */
- private log(msg: string) {
- if (this.logArea) {
- // @ts-ignore
- const time = new Date().toLocaleTimeString();
- this.logArea.value += `[${time}] ${msg}\n`;
- this.logArea.scrollTop = this.logArea.scrollHeight;
- }
- }
-}
diff --git a/main.js b/src/main.js
similarity index 99%
rename from main.js
rename to src/main.js
index f165365..8bc9ef1 100644
--- a/main.js
+++ b/src/main.js
@@ -1,5 +1,5 @@
"use strict";
-const { IpcManager } = require("./dist/IpcManager");
+const { IpcManager } = require("./IpcManager");
const http = require("http");
const pathModule = require("path");
diff --git a/mcp-proxy.js b/src/mcp-proxy.js
similarity index 100%
rename from mcp-proxy.js
rename to src/mcp-proxy.js
diff --git a/scene-script.js b/src/scene-script.js
similarity index 100%
rename from scene-script.js
rename to src/scene-script.js
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index 1255432..0000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "compilerOptions": {
- "module": "commonjs",
- "lib": [
- "dom",
- "es5",
- "es2015.promise"
- ],
- "target": "es5",
- "experimentalDecorators": true,
- "skipLibCheck": true,
- "outDir": "./dist",
- "rootDir": "./src",
- "forceConsistentCasingInFileNames": true,
- "strict": false
- },
- "include": [
- "src/**/*"
- ]
-}
\ No newline at end of file