接入 AGC 内置插件宿主并补齐 Cocos 编辑器能力 (#338)
Project CI / Repository checks (push) Successful in 2m45s
Project CI / Frontend tests (push) Successful in 3m27s
Project CI / Backend tests (push) Successful in 6m18s
Project CI / Native shell tests (push) Failing after 13m52s

客户端新增随包提供的插件宿主和 Cocos Creator 集成:识别并导入 Cocos 项目,通过内置桥接操作已打开的编辑器,无需安装项目 MCP 扩展。DirectProject 现在公开 36 个独立 cocos_* 工具,保留通用 JavaScript 执行入口。

- 通用插件 SDK、命令/能力/面板注册、编辑器适配器和跨进程内置插件开关。
- Cocos 场景、节点、组件、Prefab、UI、Layout/Widget、资源、保存、撤销、日志与预览调试;目录和实现由 JS/native 共用。
- 编辑事务回读、失败回滚、后续手动修改保护及不确定结果禁止重放;预览截图通过 MCP image 返回。
- DirectProject 跳过无关专业 Agent 历史,将项目打开和历史读取中的同步 I/O 移出窗口线程,消除 Cocos 执行与项目文件锁的错误耦合。

验证:
- 合并 master 后:类型/配置检查、编码检查、Rust 格式检查和提交钩子通过。
- 合并 master 后:Cocos 项目打开、插件面板和开发启动定向测试 10 通过、2 跳过;DirectProject MCP 测试 17 通过、1 项真实 Creator opt-in 忽略;插件宿主测试 9/9。
- 插件行为测试 17/17;native 测试 20/20,4 项 opt-in 测试默认忽略。
- 真实 Creator 3.8.8 的 36/36 操作 smoke,以及客户端 MCP tools/list、tools/call、UI/撤销和预览截图,在功能实现阶段已验证通过;本次 master 合并后未重复真实 GUI smoke。

验证边界:发行安装包和远端 CI 尚未验收。

Reviewed-on: #338
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
This commit was merged in pull request #338.
This commit is contained in:
2026-09-13 14:48:55 +08:00
committed by 段舒康
parent b12a81e9c2
commit 4a46f89c9b
117 changed files with 15158 additions and 320 deletions
@@ -0,0 +1,148 @@
# AGC Cocos Creator 编辑器桥接模块
## 2026-09-13 内置操作目录实施合同
- 交付:在插件包内实现 36 个 `cocos_*` 操作,以同一份 JSON Schema 目录供插件宿主和 DirectProject `agc_tools` 使用;保留通用 execute。目录与实现一起随客户端编译分发,不依赖项目扩展或开发机目录。
- 实现:`src/operations/` 保存操作目录、主进程编排、场景运行时和预览运行时;JS 入口与 native crate 复用同一代码构造器。DirectProject 在现有执行权限和结果不确定阻断之下调用,不引入第二套连接或项目写锁。
- 身份:场景查询返回真实 UUID 和本次 Creator 场景会话内的 NID;场景切换后旧 NID 不复用。默认写操作先校验,再读取结果;只有确实完成回读才返回 verified。
- 事务:普通节点/组件操作和批量 UI 保存变更前后的场景序列化状态,失败恢复变更前状态;MCP 撤销只接受场景当前状态仍等于对应操作的后状态,避免覆盖用户后续修改。编辑器 undo 仍走官方撤销。
- UI:支持 64 个节点、12 层、Label/Sprite/Button/持久 Shape、Layout/Widget/九宫格,超限在写入前拒绝;首次场景保存可指定 assets 下新路径。模板资产由 AssetDB 导入,禁止手工写场景 JSON。
- 预览:插件托管独立 Electron BrowserWindow,收集控制台/JS 异常和网络失败、截图并关闭自有窗口;仅允许当前项目本地预览地址,不附着或终止用户浏览器。
- 验收:插件行为测试、native 目录/构造器一致性测试、DirectProject tools/list 与 tools/call 开关测试、真实 Creator 查询/创建/组件/UI/回滚/撤销/保存/预览验证分开报告。桌面集成测试只构建测试目标,避免覆盖运行中的客户端 EXE。
## 目标
用户打开 Cocos Creator 项目后,AGC 在正确的 Creator 主进程内安装随包 JavaScript bootstrap;用户无需手动安装项目扩展。核心位于 `plugins/agc-cocos-editor/native/cocos-editor-bridge`,通过 Node Inspector 引导、通过 named pipe 执行业务代码。
## 2026-09-12 冷启动连接合同
`cocos-editor-execute` 同时启用 `windows-bootstrap`:DirectProject、Runtime 和插件适配器的 execute 在发送业务代码前统一验证项目/PID,复用已就绪 pipe,否则通过目标进程的 Node Inspector 安装编译进 crate 的 bootstrap。引导只允许目标 PID 所有的回环 Inspector;再次检查 Inspector 返回的 PID、可执行文件、项目路径和 Creator 版本。Windows 调试 handler 必须位于目标可执行映像的可执行内存中,不允许任意地址、外部端口或 DLL 输入。
bootstrap 安装与业务 execute 分离,安装只发送一次,随后等待带正确身份的 `ping` 回执。`connect` 仅在该握手成功后保存连接并返回 `connected: true`。本次开启的 Inspector 在断开 WebSocket 后通过 pipe 关闭;已有 Inspector 保持原状。bootstrap 超时或握手失败不得发送业务代码;已发送业务代码的超时仍按原有 `needs-reconciliation` 合同禁止重放。
Windows 开发和发行构建均默认启用 `cocos-editor-execute`,明确的 feature 参数或开发 feature 环境覆盖仍受尊重。验收必须分别覆盖默认/启用 feature 编译、协议回归、真实 Creator 无预装桥的首次连接与后续执行;fixture 通过不等同于真实编辑器验收。
插件宿主的普通 RPC 保持 10 秒写入/响应期限;声明编辑器适配器的插件响应期限为 90 秒,写入仍限 10 秒。Cocos 插件内部期限为 85 秒,覆盖最长 15 秒引导与 60 秒命令,先于宿主截止。DirectProject 与 Runtime 继续使用自身的工具期限和不确定结果阻断。
## 边界
Cocos Creator 3.x 是 Electron/Node 编辑器,不能复用 Unity Mono 的 CoreCLR/Roslyn 进程内调用方式。Core crate 只负责:
1. 读取 Creator 主进程的 PID、父 PID、可执行文件和 `--project` 参数;Electron renderer、GPU、utility、crashpad 子进程被排除。
2. 对 PID、项目目录和 payload 做同一目标校验。项目目录必须是绝对路径、可解析目录并包含 `package.json`;Creator 版本只从 `package.json.creator.version` 读取。
3. 在 `windows-bootstrap` 下,按内核 TCP 表选择目标 PID 的回环 Inspector,必要时激活目标主映像内的 Node debug handler。跨进程命名互斥锁串行化同一 PID 的引导,避免 GUI、Runner 和插件同时安装。
4. 提供 `ping/status/execute` 协议、Windows pipe 客户端和编译进 crate 的 `payload/bootstrap.cjs`。bootstrap 在 Node 主上下文调用 `install(Editor)`,不写入项目扩展目录。Rust 的 `\\?\` 盘符和 UNC 路径在进入 Node `realpathSync` 前转换为普通路径。
单独的 `windows-injection` DLL 实验入口仍只返回 `injected-unverified`,不能作为正式连接或验收依据。其中 `RequestInterrupt → Script::Run` 不满足 V8 中断回调约束;标准开发、发行、connect 和 execute 均使用 Inspector 引导,不启用该实验入口。
## Feature 开关
crate 默认不启用任何宿主集成:
```toml
cocos-editor-bridge = { path = ".../plugins/agc-cocos-editor/native/cocos-editor-bridge", default-features = false, features = ["process-discovery"] }
```
- `process-discovery`:启用 Windows Creator 主进程发现;不加载 Windows 注入 API。
- `windows-transport`:在已注入 payload 后启用本机 named pipe 的 `ping/status/execute` 命令传输。
- `windows-bootstrap`:启用 `windows-transport` 和 Windows x64 Node Inspector 引导;仅桌面目标引入 HTTP/WebSocket 和进程 API。
- `windows-injection`:隐含启用 `windows-transport`,并启用 Windows native DLL 注入实现。
标准 Windows 客户端使用 `windows-bootstrap`;服务端和非桌面构建保持 `default-features = false`。
AGC 不再内置 Cocos 专属 Tauri 命令。适配器 `cocos-editor` 由插件包 `plugins/agc-cocos-editor` 提供,实现通用 `EditorAdapter`(`prepare` / `inject` / `ping` / `status` / `execute` / `detect` / `connect` / `disconnect`),由宿主按 manifest 的 `adapter` 字段注册;插件入口通过 `host.rpc` 触发这些操作,宿主校验 `editor.rpc` 权限后路由到 native 模块。
插件宿主提供 `cocos.editor.execute` 和 `cocos.editor.operation`;DirectProject 的 `agc_tools` 从插件目录注册全部 36 个独立 `cocos_*` 工具,保留 `agc_cocos_execute`。两条入口使用同一份 `src/operations/catalog.json` 和 JS 源码,native crate 以 include_str 编译进客户端。版本指纹由源码与构造模板共同决定,JS/Rust 构造器测试保证一致。目标 PID 由当前项目唯一匹配;权限检查、禁用开关和不确定结果阻断共用现有链路。执行中的第二个操作会立即被拒绝,不积压稍后发送的写请求。
## 插件包形态
```text
plugins/agc-cocos-editor/
├─ plugin.json Agent Plugins 清单 + AGC Runtime 扩展(adapter=cocos-editor)
├─ src/entry.mjs 运行时入口:注册命令 / 能力 / 面板,转发 host.rpc
├─ src/cocos-editor-adapter.mjs 通用请求 → 编辑器请求的翻译与入参校验
├─ panels/cocos-editor.html 自包含面板
└─ native/cocos-editor-bridge/ native 模块:进程发现、pipe 协议、注入、EditorAdapter 实现
```
宿主按 `AGC_PLUGIN_WORKSPACE`、随包 `<resource_dir>/plugins`、开发构建仓库 `plugins/` 的顺序解析工作区;插件包内的 `native/payload` 由构建脚本随包映射,生成的 DLL 不入库。插件协议、权限和面板挂载全部复用通用宿主,Cocos 专属逻辑只存在于本插件包:进程名与 `--project` 解析、Creator 版本校验、named pipe 协议和 Windows 注入。
该插件是**内置插件**:随客户端分发、不能卸载,只能通过 `set_agc_plugin_enabled` 控制是否可用。禁用后插件进程停止且不能启动,通用 execute 和全部 `cocos_*` 工具从 Agent 目录消失;直接请求隐藏工具也会在宿主执行前被拒绝。开关状态保存在 AppData `extensions/builtin-plugins.json`,隔离 MCP 每次 tools/list 都向绑定宿主询问当前状态。
## AGC 项目打开入口
AGC 识别根目录同时存在 `package.json.creator.version` 与普通 `assets/` 目录的
Cocos Creator 项目,并将其标记为 `cocos` 项目类型。选择目录后通过
`import_local_cocos_project` 建立最小 `.agent/` 运行记录,不创建 Phaser/Web
脚手架;工作区上下文同步到内置 `agc-cocos-editor` 插件,开发态默认启用
`cocos-editor-execute` feature。若目录不是已支持的 AGC、Godot 或 Cocos 项目,
入口必须显示明确错误,不再静默返回。
## 第一阶段命令协议
DirectProject 与插件宿主都构造受控 JS 并调用 native executor。通用 execute 维持原期限,目录操作期限为 60 秒,涵盖资源导入和预览加载。客户端在 blocking worker 内执行,检查项目权限但不获取 `.agent/project.lock`。截图提取为 MCP image block,不能截断 base64;失败、回滚或需要核对不能因底层 JS 正常返回而被改写为 completed。
场景运行时只定位绑定 Creator 中唯一 `packages://scene/` WebView,使用 `require('cc')` 完整模块及当前场景管理器,不安装或读取项目扩展。事务保存前后序列化快照;MCP 撤销只在当前状态与事务后状态相同时恢复,已保存事务同步写回。对用户后续手动修改不做覆盖;场景切换和 Creator 重启不保留历史。
首次保存将官方序列化结果交给 AssetDB 创建新资源,等待导入可查询后标记原快照已保存,再通过官方 open-scene 读取该资源;不直接更改 UUID,不对未命名场景调用会弹对话框的 save-scene。UI 先等待 SpriteFrame 可加载,再开始场景事务;模板 PNG 保留在 assets/agc-ui-shapes 供后续复用。
注入 payload 在目标 Creator 主进程内监听 `\\.\pipe\genarrative-cocos-editor-{pid}`,使用换行分隔的 JSON。crate 只生成三种操作:
```json
{"schemaVersion":"game-creator-cocos-editor-bridge.v1","requestId":"cocos-42-...","processId":42,"projectPath":"C:\\demo","command":{"op":"ping"}}
{"schemaVersion":"game-creator-cocos-editor-bridge.v1","requestId":"cocos-42-...","processId":42,"projectPath":"C:\\demo","command":{"op":"status"}}
{"schemaVersion":"game-creator-cocos-editor-bridge.v1","requestId":"cocos-42-...","processId":42,"projectPath":"C:\\demo","command":{"op":"execute","code":"return Editor.Project.path"}}
```
回执必须回传相同的 `schemaVersion/requestId/processId`。`execute.code` 是支持 `await` 和 `return` 的 JavaScript 函数体,上限为 128 KiB,单次回执上限为 2 MiB;bootstrap 通过 `AsyncFunction('Editor', 'require', code)` 在 Creator 主进程事件循环串行执行,并返回可序列化 JSON。它使用 Creator/Node 的现有权限,不是代码沙箱;目录操作按自身 schema 验证参数,通用 execute 仍允许自定义 JS。
Rust 客户端在写入前通过 `GetNamedPipeServerProcessId` 验证 pipe 属于目标 PID,读写使用 overlapped I/O 和 deadline。execute 开始写入后遇到断线、超时或无可信回执,返回 `ExecutionUncertain`,Runtime 进入 `needs-reconciliation`,不得自动重放。客户端超时不等于 JavaScript 已取消,bootstrap 保持同一串行队列直到原执行结束;同步死循环仍可能阻塞 Creator,需要真实集成阶段提供运行时中断方案。
插件 `EditorAdapter` 将执行结果不确定保留为结构化 `status=needs-reconciliation / retryAllowed=false / ok=false`,并在适配器实例中阻断后续 execute;断开连接、重新连接、插件进程重载或切换项目均不清除此阻断。必须由用户核对编辑器状态后重启客户端,不能自动恢复或重试。发送前的校验/连接失败仍为可修正的普通失败。插件入口同样在宿主 RPC 超时、断线或收到不确定结果时停止发送后续 execute,并保留结构化状态。
## 安全与失败关闭
- PowerShell 查询脚本为固定常量,用户输入不拼接进 shell。
- 目标 PID 必须是没有 Electron `--type` 参数的 `CocosCreator.exe`,且其 `--project` 与请求目录规范化后相同;不能仅凭进程名注入。
- bridge DLL 必须是绝对路径、普通文件、非符号链接、`.dll` 扩展名且大小不超过 64 MiB。AGC adapter 还必须把路径限制在签名/随包资源目录;core 不接受任意下载 URL。
- 注入超时不会释放仍可能被远程线程使用的内存,并返回人工核对错误,避免在不确定状态下破坏目标进程。
- 非 Windows、feature 未启用、目标不存在、身份不匹配或 payload 不合规均直接失败,不启动 Cocos、不关闭 Cocos、不修改项目文件。
## 验收
正式引导由 Rust 调用 Win32、HTTP 和 WebSocket 完成,不额外启动 Node 助手。执行 `cargo test --manifest-path plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml --features windows-bootstrap` 验证身份、路径、状态与协议。追加 `-- --ignored` 实际运行自有 Node 进程的冷启动、保留已有 Inspector 和 pipe 超时回归;fixture 进程由测试独占并回收。
真实 Creator 使用 `cargo run --manifest-path plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml --features windows-bootstrap --example creator_smoke -- <已打开的项目绝对路径>`。该入口只返回 PID、项目、版本和 Inspector 状态,验证首次执行、复用和 connect/ping,不写项目文件。初始 `before=NotReady` 才证明冷启动;后续只有 warm 成功不能替代冷启动验收。源码编译、真实 Creator smoke、发行包构建与安装包 smoke 分别报告。
## Inspector 注入调研(2026-09-10)
### 入口与执行链
Node 20.15.1 的 Windows 调试信号初始化会创建 `node-debug-handler-{pid}` 命名共享内存,其中存放目标进程自身 `StartIoThreadProc` 的函数地址。`process._debugProcess(pid)` 的内部实现是 `OpenProcess → OpenFileMappingW(FILE_MAP_READ) → MapViewOfFile → CreateRemoteThread(目标 handler)`。handler 通过 Node 自己的 libuv/interrupt 调度启动 Inspector,宿主无需写入 DLL、修改机器指令或猜测 V8 对象布局。
接入次序:
1. 校验 Creator 主进程、项目身份、位数和调试入口是否可用;共享内存给出的入口应与目标进程已加载的可执行映像匹配,不能仅信任一个带 PID 的对象名。
2. 如已有目标 Inspector,复用且记录原有状态;否则激活目标 handler。只连接属于该 PID 的回环监听端口,随后再次核对 `process.pid`、`Editor.Project.path` 和运行版本。已有进程通常使用默认调试端口;端口被其它进程占用时应失败,不连接其它目标。AGC 自己启动的 Creator 可预设 `--inspect-port=127.0.0.1:0`,该参数本身不启用 Inspector。
3. 使用 Inspector `Runtime.evaluate` 在 Node 主上下文求值 CommonJS 包装器,把 `require` 显式传给 bootstrap,并调用 `install(Editor)`。不增加业务工具列表。
4. 等待 bootstrap 的 pipe 就绪,按既有身份合同验证 `ping`,再开放 `execute`。
5. 如 Inspector 是本次引导开启的,先断开 Inspector WebSocket,再从 pipe 执行 `require('node:inspector').close()`;已有用户调试会话保持原状态。之后持续命令全部走 pipe。
### 已验证与限制
- 使用本机 Creator 3.8.8 的真实 GUI 主进程和由官方 Empty(3D) 模板创建的临时项目,未安装项目扩展。运行时为 Electron 31.3.1、Node 20.15.1、V8 12.6.228.28-electron.0。
- 在进程启动后激活 Inspector,注入当前 `payload/bootstrap.cjs`,实际 `ping`、`execute` 返回目标 PID、真实项目路径和 Creator 版本。
- 编辑器就绪后,`Editor.Message.request('scene', 'query-node-tree')` 成功返回 `null`:空白项目未打开场景。这证明消息调用链可用,不代表已验证非空场景的读取或修改。
- 关闭 Inspector 后,pipe 的 `execute` 仍成功;验证结束正常退出临时 Creator。用户原有 Creator 仅做共享内存入口和监听端口的只读检查。
- 本次真实 Electron Inspector 对 `awaitPromise: true` 曾返回 `Promise was collected`。验证改为同步 evaluate 启动安装、保存就绪状态并轮询;异步业务代码由 pipe 内的 Node 队列执行。不要把单次 Inspector 异常当作 bootstrap 未执行并自动重放。
- Inspector 的命令行 API `require` 在求值之外不保证可访问;异步闭包须捕获或显式传入该函数,不能假设 `globalThis.require` 存在。
- 本机二进制的 `EnableNodeCliInspectArguments` fuse 开启,当前已打开的 Creator 也存在调试 handler。其它版本或 fuse 被关闭的发行包不能推断支持;入口缺失应失败,不能修改 fuse 或回退到未验证的函数打补丁。
### 上游依据
- [Node 20.15.1:Windows DebugProcess](https://github.com/nodejs/node/blob/v20.15.1/src/node_process_methods.cc#L377-L448)
- [Node 20.15.1:注册目标调试 handler](https://github.com/nodejs/node/blob/v20.15.1/src/inspector_agent.cc#L143-L197)
- [Electron 31.3.1:NodeBindings 与 Inspector fuse](https://github.com/electron/electron/blob/v31.3.1/shell/common/node_bindings.cc)
- [Electron Inspector fuse 说明](https://github.com/electron/electron/blob/v31.3.1/docs/tutorial/fuses.md#nodecliinspect)
- [V8 12.6:RequestInterrupt 的回调禁止重入 isolate](https://github.com/v8/v8/blob/12.6.228/include/v8-isolate.h)
- [Node inspector.close:等待现有连接关闭后停用 Inspector](https://github.com/nodejs/node/blob/v20.15.1/doc/api/inspector.md#inspectorclose)
@@ -0,0 +1,131 @@
# AGC 通用插件宿主与编辑器适配
更新时间:`2026-09-09`
## 目标与边界
AGC 插件系统由一个通用宿主和一个通用 SDK 组成。宿主统一负责插件扫描、manifest 校验、进程启停与热重载、行分隔 JSON-RPC、UI 面板挂载/卸载、Capability Registry、权限检查和审计;编辑器差异只进入 `editor_adapter`。
现役代码位置:
```text
apps/ai-game-creator-shell/src-tauri/src/plugin_host.rs
apps/ai-game-creator-shell/src-tauri/src/editor_adapter/mod.rs
apps/ai-game-creator-shell/src-tauri/src/editor_adapters.rs
packages/agc-plugin-sdk/src/index.ts
server-rs/crates/editor-adapter-api/src/lib.rs
plugins/agc-cocos-editor/ (第一个编辑器插件包)
```
现有 DirectProject 的 Skill/MCP 导入仍保留。它们是 Codex 扩展注入链路,不等同于本宿主管理的可运行 AGC Plugin。
## 插件目录和 manifest
插件来源统一存放在客户端 AppData 的 `extensions/sources/` 下,由既有扩展索引登记;每个来源目录最多包含一个 Plugin。宿主优先接受 OpenAI Agent Plugins 标准的根目录 `plugin.json`,同时兼容 `.codex-plugin/plugin.json`。标准 Plugin 可以只包含 `skills/` 与 `mcp.json`,不要求本地可执行入口;带 `extensions.world.genarrative.agc.entry` 的 AGC Runtime Plugin 才由通用宿主启停。入口必须是插件目录内的普通文件,不能是符号链接、绝对路径或带 `..` 的路径。
OpenAI 的标准模型是“Plugin 作为可安装包,组合 Skills、可选 MCP Server 和可选 UI”。因此 AGC 的统一扩展目录会把一个 Plugin 及其 `skills/`、`mcp.json` 子项放进同一 catalog;Skill 继续交给 Codex 原生 Skill loader,MCP 继续交给现有 MCP transport,Runtime Plugin 才使用本页的子进程 JSON-RPC。这样三种能力共享来源、启停状态和审计,不要求它们共享错误的执行方式。
带 AGC Runtime 入口的 manifest:
```json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "editor-tools",
"version": "1.0.0",
"extensions": {
"com.openai": { "interface": { "displayName": "编辑器工具" } },
"world.genarrative.agc": {
"apiVersion": "v1",
"entry": "./index.js",
"adapter": "target-editor",
"permissions": ["ui.register", "capability.register", "editor.rpc"],
"panels": [{ "id": "scene", "title": "场景工具", "entry": "./panel.html", "placement": "sidebar" }]
}
}
}
```
只打包 Skill/MCP 的标准 Plugin 可以使用 OpenAI 的 portable 形态:
```json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "editor-workflows",
"version": "1.0.0",
"description": "编辑器工作流",
"extensions": { "com.openai": { "interface": { "displayName": "编辑器工作流" } } }
}
```
其中 `skills/<skill-name>/SKILL.md` 和根目录 `mcp.json` 由统一 catalog 发现;`.codex-plugin/plugin.json` 仅作为兼容回退。
当前允许的权限为 `events.subscribe`、`project.read`、`editor.rpc`、`ui.register` 和 `capability.register`。未知权限、重复面板 id、非法入口和不支持的 API/适配器会使插件进入 `invalid` 状态,不启动进程。
### plugins/ 工作区
除 AppData 导入外,宿主还扫描 `plugins/` 工作区:每个含根目录 `plugin.json` 的一级子目录是一个插件包。解析顺序为环境变量 `AGC_PLUGIN_WORKSPACE`、随包资源目录 `<resource_dir>/plugins`、开发构建的仓库 `plugins/`。仓库工作区约定见 [`plugins/README.md`](../../../plugins/README.md)。
### 内置插件与可用开关
`plugins/` 工作区里的插件是**内置插件**:随客户端分发,用户不能卸载或删除,只能通过可用开关控制是否生效。开关状态持久化在 AppData `extensions/builtin-plugins.json`(`schemaVersion = agc.builtin-plugins.v1`,`enabled` 是 id 到布尔的映射);文件缺失按插件 manifest 的 `enabled` 处理,坏文件失败关闭。内置插件优先级高于同名导入插件,AppData 里的同名 Plugin 不会覆盖或间接卸载它。
开关同时驱动两处行为:
1. 插件宿主:禁用时先停止运行中的插件进程,状态变为 `disabled`,`start_agc_plugin` 返回“插件已禁用”。内置插件在 `PluginSummary` / `AgcExtensionSummary` 里带 `builtin: true`,前端只显示可用开关,不显示重命名和卸载入口。
2. Agent 工具面:禁用后对应 Runtime 工具从 `agent_runtime_executable_tools()` 里移除,因此不再进入工具策略快照(`autoTools` / `confirmTools` / `allowedTools`)、原生函数目录和系统提示词中的工具目录;DirectProject 的 `agc_tools` 规格同步移除,bridge 执行入口也会拒绝。启用后立即恢复,不需要重启客户端。
唯一的开关入口是 Tauri 命令 `set_agc_plugin_enabled`,它只接受登记过的内置插件 id;导入扩展继续使用既有 `set_client_extension_enabled`。
开关文件是跨进程权威:GUI、Runner 与 CLI 在查询和执行时读取其绑定 AppData 下的当前文件;未知配置根、文件损坏或版本不支持时关闭能力,成功保存有效开关后立即恢复。隔离的 MCP 子进程通过现有客户端工具桥查询可用工具,不获得 AppData 路径或目录权限;查询失败按空插件工具集处理。开关变化进入 app-server pool identity,使后续回合重建工具目录;已发给模型的上下文不回撤,执行入口仍实时拒绝已禁用工具。
## 运行和 RPC
宿主以已安装插件目录为 cwd 启动入口;JavaScript 入口使用系统 `node` 执行,其它入口直接执行。环境先清空,再保留 PATH、Windows 系统目录和临时目录等必要变量,并注入插件身份和协议版本;不继承客户端凭据。Windows 复用进程模块的 Job Object,Unix 使用独立进程组,停止/卸载时回收自有进程。
stdin/stdout 使用一行一个 JSON-RPC 2.0 消息,单条消息限制 2 MiB,队列和并发请求有上限;独立消息循环持续处理注册请求、事件和响应。普通 RPC 写入与响应共享 10 秒期限;声明编辑器适配器的插件允许 90 秒响应期限以覆盖连接引导与编辑器执行,写入仍限 10 秒。写入阻塞只终止对应运行实例。宿主 API 权限用于约束 `host.*` 调用;Runtime Plugin 是用户主动启动的本地程序,这不是 OS 沙箱。
SDK 对插件暴露稳定的通用 API:
```ts
host.registerCommand(command)
host.registerPanel(panel)
host.registerCapability(capability)
host.events.subscribe(type, listener)
host.project.read(path)
host.rpc(method, params)
```
注册函数返回卸载函数;命令与能力可附带 RPC handler,`createJsonRpcStdioTransport` 提供双向 stdio 传输。`PluginPanelRegistry` 提供订阅、列表和卸载,客户端通过受控读取命令加载自包含 HTML,并在独立弹窗的隔离 iframe 中展示。关闭面板或停止插件会卸载 iframe;面板不获得 Tauri API、同源存储或任意网络权限。
当前本地面板是 AGC 扩展能力,尚未实现 MCP Apps UI 消息桥。Agent Plugins 核心包格式、Skill 和 MCP transport 是当前兼容范围;OpenAI 注册应用映射、hooks、公开市场发布和完整 MCP Apps UI 不在本次宿主实现中。
## 编辑器适配器扩展点
`EditorAdapter` 契约位于通用 crate `server-rs/crates/editor-adapter-api`,只定义 `detect`、`connect`、`disconnect`、`translate_rpc` 和原生 `rpc`。宿主只保存适配器 registry,并把插件声明的适配器名称路由到对应实现;具体编辑器如何查找进程、校验 PID/项目/版本、建立连接和翻译编辑器消息,由插件包自带模块实现。
宿主源码不包含编辑器专属进程名、注入逻辑或 Tauri 命令。第一个适配器 `cocos-editor` 由 `plugins/agc-cocos-editor` 提供:native 模块实现 `EditorAdapter`,由 `editor_adapters.rs` 在启动时按编译期链接注册。新增适配器不会改变 Plugin 生命周期、SDK 或权限协议。
当前 native 适配器仍由宿主在编译期链接(Cargo path 依赖);动态加载插件 native 模块不在本次范围,插件包格式与宿主协议不受此限制。
## Tauri 命令
`list_agc_extensions` 返回统一的 Plugin/Skill/MCP catalog;`list_agc_plugins`、`refresh_agc_plugins`、`start_agc_plugin`、`stop_agc_plugin`、`reload_agc_plugin`、`call_agc_plugin` 和 `read_agc_plugin_panel` 提供 Runtime Plugin 管理入口;`set_agc_plugin_project_path` 设置当前项目的受控上下文。编辑器适配器通过宿主 registry 和 Plugin RPC 使用,不增加编辑器专属 Tauri 命令。
编辑器操作统一走 `host.rpc`:插件用 `extensions.world.genarrative.agc.adapter` 或显式 `adapter` 参数选择适配器,宿主校验 `editor.rpc` 权限后调用 `EditorAdapter::rpc`。项目上下文通过 `host.events.subscribe` 的响应和 `project.changed` 事件 payload 下发,插件不需要自己扫描目录。
每次启停、RPC 成功/失败和权限拒绝都追加到 AppData `extensions/audit.jsonl`,日志只写插件 id、动作、结果和固定错误摘要,不写 API Key、Cookie、Token 或宿主绝对路径。
## 验收门禁
OpenAI 官方 Plugins 文档将 Skills、MCP Server 和可选 UI 定义为同一 Plugin 包的组成部分;AGC 以该组合模型为兼容目标:
- [Plugin architecture](https://developers.openai.com/plugins/concepts/plugins)
- [Package your plugin](https://developers.openai.com/plugins/build/plugins)
- Rust:manifest 路径/权限校验、目录扫描、权限拒绝和通用适配器 registry 边界单测;`cargo check --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml`。
- 前端:`agc-plugin-sdk` TypeScript 编译、宿主服务类型检查,以及 `PluginPanelHost` 的挂载/卸载测试。
- 内置插件开关:`builtin_plugins` 单测覆盖默认值、持久化往返、坏文件失败关闭,以及“禁用后工具目录里不再出现该工具”;`plugin_host` 单测覆盖禁用后不能启动、启用后回到 stopped。
- 插件工作区:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml` 覆盖工作区扫描与 manifest 启用状态;`cargo test --manifest-path plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml` 覆盖 Cocos 适配器;`node --test plugins/agc-cocos-editor/src/entry.test.mjs` 覆盖插件入口协议与 manifest 一致性。
- 通用仓库门禁:`npm run check:encoding`、`git diff --check`;发布前仍需单独执行 AGC package smoke 和安装包 smoke。
当前版本完成统一扩展 catalog、通用宿主、SDK、面板宿主、通用 EditorAdapter registry 和 `plugins/` 工作区;`agc-cocos-editor` 是第一个插件包。真实编辑器验收仍按 Cocos 方案文档单独执行,不用未验证的连接状态替代。
@@ -1,5 +1,15 @@
# AI 游戏创作智能体 App 实施计划
## 2026-09-12 已有项目打开响应性
DirectProject 工作区只恢复自身对话,不按专业 Agent 默认任务占位行批量读取旧会话或生成专业 Agent 文本回执。专业 Agent 结果加载 effect 必须以当前 Runtime 模式为边界,并在模式切换时清空旧结果。仍供开发入口使用的 `read_local_conversation` 在 blocking worker 内完整执行权限校验、会话目录解析和历史读取,避免文件访问或锁等待阻塞 Tauri 窗口线程。
项目打开链路的目录检查、manifest 读取、项目 revision 读取和 Planning V2 hydrate 也必须通过 blocking worker 执行;它们可能碰到项目写锁,不能在 Tauri 窗口线程同步等待。
DirectProject 自身的 `read_direct_project_conversation` 也必须在 blocking worker 中执行权限校验、JSONL 历史解析和消息投影,不能因为它只读取一份项目历史就保留同步 Tauri command。
验收覆盖实际 Launcher 打开已有项目:恢复 DirectProject 对话且不调用 `read_local_conversation`;后台读取仍遵守项目权限策略。原生客户端重复打开同一已有项目时验证窗口响应,IPC 测量只记录命令名和耗时,不记录会话内容。
## 图片生成恢复与测试边界
已有持久生成账本的 Provider 待执行动作恢复时,若动作省略了旧视觉 Agent 自动补齐的参数,只在 Agent、动作身份、生成种类和冻结提示词均匹配旧合同后补齐缺省参数;显式参数不得被覆盖。新请求继续按当前自由图片合同执行,不能重新引入固定视觉产物门禁。恢复复用原 operation 与幂等账本,不因默认值变化重复提交已受理请求。
@@ -184,7 +194,7 @@ Supervisor 认领该回执后,由父 run 自己为每个原 delivery 逐一创
## 目标
在 Genarrative 内建设独立桌面 App:普通用户通过项目开发工作台中的陶泥儿对话、资源画布、运行状态和确认操作,让平台生成保存在本地的可运行 Web 游戏原型,并通过本地 HTTP server 预览;主窗口提供运行时配置入口,用于保存发布版 AppData / Tauri 配置目录里的 LLM 配置及受控开发者 External Editor 配置,设置弹窗同时提供独立“关于”页并显示从客户端构建版本注入的版本号。普通客户素材画布使用平台登录态调用内部编辑器 API,不展示或要求填写画板 Base URL / API Key。任务明细、原始文件、命令日志和专业 Agent 调试控制只通过显式开发调试入口查看,不随普通客户端启动额外打开窗口。v1 的生成闭环仍以 Web 小游戏为主,同时允许用户打开已有 Godot 项目:用户选择的目录始终作为工作区根,`.agent/`、Session、Runtime、文件工具和外围资料都留在该根;客户端检查根目录及一层直接子目录中的普通文件 `project.godot`,将唯一命中的实际目录以工作区相对 `godotProjectRoot` 记录到 manifest。Agent 使用标准运行档继续修改,不创建 `game/`、`assets/`、`memory/`、`exports/` 平行目录;本期不扩展 Unity、Godot 内嵌预览、云同步或插件市场。
在 Genarrative 内建设独立桌面 App:普通用户通过项目开发工作台中的陶泥儿对话、资源画布、运行状态和确认操作,让平台生成保存在本地的可运行 Web 游戏原型,并通过本地 HTTP server 预览;主窗口提供运行时配置入口,用于保存发布版 AppData / Tauri 配置目录里的 LLM 配置及受控开发者 External Editor 配置,设置弹窗同时提供独立“关于”页并显示从客户端构建版本注入的版本号。普通客户素材画布使用平台登录态调用内部编辑器 API,不展示或要求填写画板 Base URL / API Key。任务明细、原始文件、命令日志和专业 Agent 调试控制只通过显式开发调试入口查看,不随普通客户端启动额外打开窗口。v1 的生成闭环仍以 Web 小游戏为主,同时允许用户打开已有 Godot 项目:用户选择的目录始终作为工作区根,`.agent/`、Session、Runtime、文件工具和外围资料都留在该根;客户端检查根目录及一层直接子目录中的普通文件 `project.godot`,将唯一命中的实际目录以工作区相对 `godotProjectRoot` 记录到 manifest。Agent 使用标准运行档继续修改,不创建 `game/`、`assets/`、`memory/`、`exports/` 平行目录;本期不扩展 Unity、Godot 内嵌预览、云同步或插件市场。新增的 Cocos Creator bridge 核心独立为插件 `plugins/agc-cocos-editor`(native 模块位于其 `native/cocos-editor-bridge`),AGC 仅通过通用插件宿主和 feature 转发桌面进程发现、受控 execute 和 Windows 注入能力;它不改变服务端路线,也不把原始 pipe、句柄或未绑定项目身份的代码执行面暴露给 Agent。
## 技术选择
@@ -1,16 +1,16 @@
# DirectProject 客户端 Skill 与 MCP 扩展导入方案
更新时间:`2026-08-31`
更新时间:`2026-09-10`
## 1. 文档定位
本方案是 DirectProject 客户端第三方 Skill、MCP 和 Plugin 导入能力的当前实现依据。它描述客户端侧的导入、拆分、命名、启用和 DirectProject 启动注入边界,不改变 AGC 内置 Skill Pack、`agc_tools` MCP、项目文件工具和现有 Runtime 权威。
本方案是 DirectProject 客户端第三方 Skill、MCP 和 OpenAI Agent Plugin 导入能力的当前实现依据。它描述统一扩展目录中的来源登记、拆分、命名、启用和 DirectProject 启动注入边界;可执行 AGC Runtime Plugin 的生命周期、JSON-RPC、UI 和 Capability 由通用 Plugin Host 承接,见 `AGC通用插件宿主与编辑器适配-2026-09-09.md`。
本方案只覆盖客户端安装和下一次 Codex 启动时接入。第三方扩展不是安装到全局运行时 Codex,也不要求用户把市面上的扩展重新打包为 AGC 自定义格式。
## 2. 一句话交付结果
客户端提供一个全局“扩展”入口,直接接受文件、目录、zip 和标准 Plugin;导入后把其中发现的每个 Skill 和每个 MCP Server 拆成独立扩展项,用户可以分别重命名、启用、禁用和删除;DirectProject 启动 Codex 时只注入已启用的独立项。
客户端提供一个全局“扩展”入口,直接接受文件、目录、zip 和标准 Plugin;Plugin 自身登记为一个父级扩展项,内部发现的 Skill/MCP 同时登记为同一来源的子项。用户可管理 Plugin 开关和 Runtime 生命周期,也可分别管理 Skill/MCP;DirectProject 启动 Codex 时只注入有效启用的 Skill/MCP。
## 3. 已确定的产品边界
@@ -23,7 +23,7 @@
- 扩展内容保存在 AGC 客户端的扩展仓库。
- 不把扩展永久安装到用户的全局 `CODEX_HOME`。
- DirectProject 创建或复用 app-server 时,读取客户端当前已启用的扩展并生成本次运行的临时 Skill root 与 MCP 配置。
- 导入、启用、禁用和重命名不热更新正在运行的 Codex;变更从下一次 DirectProject 启动生效。
- Skill/MCP 的导入、启用、禁用和重命名不热更新正在运行的 Codex;变更从下一次 DirectProject 启动生效。Runtime Plugin 的启停/重载由通用宿主立即执行。
- 扩展默认对客户端内所有 DirectProject 生效,不做项目级启用映射。
### 3.2 用户信任和最小处理
@@ -45,16 +45,15 @@
- 单个 `.exe`、`.py`、`.js` 或其它可执行文件/脚本由用户手动指定为 MCP 入口;
- 根据 README 或文件后缀猜测如何启动普通程序;
- 完整 Codex Plugin Runtime;
- Plugin hooks、apps、remote plugin 和依赖这些能力的运行时行为;
- Codex 原生 hooks、apps、remote plugin 和其它不属于 AGC Host 的运行时行为;
- 自定义扩展 manifest、审核清单或自定义安装包格式;
- Skill/MCP 行为安全扫描、脚本沙箱和网络白名单;
- 项目级扩展配置;
- 热更新、后台扩展服务、在线市场、版本历史、回滚和自动升级。
- Codex Skill/MCP 热更新、扩展自动后台启动、在线市场、版本历史、回滚和自动升级。
## 4. 导入与拆分模型
目录、zip 和 Plugin 是“导入来源”,不是管理对象。一个来源中识别出的每个 Skill 和每个 MCP Server 都独立成为客户端扩展项。
目录和 zip 是导入来源;Plugin 是可管理对象。Plugin、Skill 和 MCP 子项共享 source_id,并进入统一扩展 catalog。
```text
导入来源
@@ -121,9 +120,9 @@ filesystem
### 4.3 Plugin 处理
存在 `.codex-plugin/plugin.json` 时,将目录或 zip 识别为标准 Plugin 导入来源。
存在带 Agent Plugins schema 的根目录 `plugin.json` 时,将目录或 zip 识别为标准 Plugin 包;`.codex-plugin/plugin.json` 作为兼容输入。zip 可包含一层包目录。
本期只提取其中可识别的 Skill 和 MCP,并分别创建独立扩展项:
包自身及其中可识别的 Skill/MCP 分别登记到同一扩展索引:
```text
Plugin
@@ -132,7 +131,7 @@ Plugin
└── MCP C → 独立 MCP 项
```
Plugin 自身不生成父级列表项,也不提供 Plugin 级开关。hooks、apps、remote plugin 以及依赖完整 Plugin Runtime 的内容忽略;如果没有任何可支持的 Skill/MCP,则来源保留为未知内容。
Plugin 自身生成一个父级列表项并提供统一启用开关。hooks、apps、remote plugin 仍不由 DirectProject 注入;AGC Runtime Plugin 仅由通用 Plugin Host 管理。没有可支持组件且没有 AGC Runtime 入口时,来源保留为未知内容。
### 4.4 未知输入
@@ -223,7 +222,7 @@ ImportedSource
ExtensionItem
├── id
├── source_id
├── type: skill | mcp | unknown
├── type: plugin | skill | mcp | unknown
├── name
├── original_name
├── source_relative_path
@@ -232,7 +231,7 @@ ExtensionItem
└── last_error
```
`source_id` 只用于来源溯源和清理,不形成可操作的父级扩展项,也不产生父子级联启用状态。
`source_id` 用于来源溯源和清理;Plugin 父项与同来源 Skill/MCP 子项形成级联启用状态,父项禁用时子项不会注入 DirectProject。
对于目录或 zip:
@@ -263,9 +262,12 @@ ExtensionItem
- 删除操作;
- 必要时的一行启动错误。
一个目录、zip 或 Plugin 中的多个内容直接平铺显示,不显示父级包和父级开关:
Plugin 父项和子项在同一列表显示,父项开关控制其运行组件:
```text
my-plugin
Plugin · 来自 my-plugin.zip 已启用
art-skill
Skill · 来自 my-plugin.zip 已启用
@@ -421,7 +423,7 @@ remove_client_extension(id)
- 名称统一使用原生标识;
- 重复导入自动追加后缀;
- 已识别内容默认启用;
- Plugin 只作为导入容器;
- Plugin 登记为父级扩展项,Skill/MCP 登记为子项;
- 单个可执行文件/脚本不作为 MCP 入口;
- 客户端全局生效。
@@ -476,7 +478,7 @@ remove_client_extension(id)
### 阶段 3:MCP 和 Plugin 部分闭环
当前实施状态:已完成。客户端会在 DirectProject 启动前读取所有已启用 MCP 独立项,把可转换的 STDIO/HTTP 原生字段合并进本次隔离 `CODEX_HOME/config.toml`,再由现有启动参数单独注入内置 `agc_tools`。第三方项固定为非 required,结构错误或启动失败只更新对应扩展项的 `last_error`;Codex app-server 的 `mcpServer/startupStatus/updated` 通知用于清除或记录单项启动状态。已启用 MCP 的名称、来源相对路径和内容指纹已纳入 app-server pool key。Plugin 样例已覆盖同一来源中的 Skill/MCP 独立提取,不开启 Plugin Runtime。
当前实施状态:已完成。客户端会在 DirectProject 启动前读取统一 catalog 中有效启用的 MCP 子项,把可转换的 STDIO/HTTP 原生字段合并进本次隔离 `CODEX_HOME/config.toml`,再由现有启动参数单独注入内置 `agc_tools`。第三方项固定为非 required,结构错误或启动失败只更新对应扩展项的 `last_error`;Codex app-server 的 `mcpServer/startupStatus/updated` 通知用于清除或记录单项启动状态。已启用 MCP 的名称、来源相对路径和内容指纹已纳入 app-server pool key。Plugin Host 同时管理带 AGC Runtime 入口的父项。
完成:
@@ -492,7 +494,7 @@ remove_client_extension(id)
- 一个 MCP 配置包含多个 Server 时,列表出现多个独立项;
- 每个 MCP 可以单独启用、禁用和重命名;
- 重名 Server 能生成稳定的唯一 key;
- Plugin 不会开启 hooks、apps 或完整 Plugin Runtime;
- Plugin 不会向 DirectProject 开启 Codex hooks/apps;带 AGC Runtime 入口的 Plugin 由独立通用 Host 启停;
- 单个可执行文件/脚本仍不会自动作为 MCP 入口。
## 11. 最小验证范围
@@ -23,6 +23,7 @@ Genarrative 的 JavaScript 工程统一使用 npm workspaces。仓库只提交
"apps/preview-deployer-web",
"packages/image-canvas-core",
"packages/image-canvas-react",
"packages/agc-plugin-sdk",
"packages/shared",
"tools/spine-json-export-validator"
]
@@ -38,6 +39,7 @@ Genarrative 的 JavaScript 工程统一使用 npm workspaces。仓库只提交
- `apps/preview-deployer-web`
- `packages/image-canvas-core`
- `packages/image-canvas-react`
- `packages/agc-plugin-sdk`
- `packages/shared`
- `tools/spine-json-export-validator`