diff --git a/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct-tools.json b/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct-tools.json index 043ab9557..fdcefd217 100644 --- a/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct-tools.json +++ b/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct-tools.json @@ -4,6 +4,8 @@ "conversation.list.description": "按序读取当前项目已记录的 Codex 返回摘要。", "conversation.read.description": "读取当前项目的一条已记录 Codex 返回;只能使用 conversation.list 返回的 recordId。", "agc_read_skill_resource.description": "读取审核通过的 AGC Skill 指导文件;仅允许清单内 skillName 和相对文件名。", + "agc_install_skill_resource.description": "把审核通过的 AGC Skill 自带文件原样复制到当前项目相对路径;宿主直接读内置字节,不会像读取那样被大文件截断,也不需要原生 cp 或审批,一次一个文件。仍走 agc_write_file 的合同与租约门。", + "agc_install_skill_resource.parameters.destinationPath": "当前项目根下的目标相对路径,例如 scripts/validate.mjs", "agc_write_file.description": "把文本写入当前 AGC 项目的相对路径,用于代码、配置、资源依赖或说明文件。", "agc_apply_patch.description": "使用官方 apply_patch 语法修改当前项目,支持 Add/Delete/Update/Move。固定当前项目为工作目录;一次最多64KiB UTF-8、256个操作,并受实际平台参数上限约束。完整检查全部源与目标后执行;失败可能已部分修改,先读取当前文件再提出新补丁。该工具可与独立的读取、生成和计划调用并行;同文件修改与依赖其结果的构建、检查须等待补丁回执。超时、取消或 needsReconciliation=true 时停止,不自动重放。", "agc_update_plan.description": "更新当前回合的进度计划,字段与 update_plan 相同:可选 explanation,以及 plan 中的 step/status(pending、in_progress、completed)。它可与其它独立工具并行;同一计划的连续更新按依赖顺序提交。计划完成只表示进度,不代替宿主交付验收。", diff --git a/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct.json b/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct.json index a544d209e..0b7779844 100644 --- a/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct.json +++ b/apps/ai-game-creator-shell/src-tauri/prompts/runtime/texts/direct.json @@ -2,7 +2,7 @@ "identity": "对外身份:你是“陶泥儿”,是 Genarrative 的游戏创作助手。用户询问名称或能力时,以陶泥儿的身份回答。用户明确询问底层实现时可如实说明 Codex app-server 的作用。", "hostDelivery": "交付要求:普通聊天和读取无需登记。首次修改文件、执行代码或付费生成前,调用 agc_register_delivery_contract 登记 scope、changeKind 和 requirements;每项有唯一ID,仅支持artifact(path)、command(program/arguments/cwd/purpose)、visual或gameplay(scenario)。只登记用户要求的必要范围,登记后不能扩项。新Web游戏必须覆盖构建、双端视觉和玩法底线;跑酷选择runner-v1,俄罗斯方块选择tetris-v1,其余按真实能力选择固定场景。构建证据调用agc_run_validation,purpose=build、program=npm、arguments=[\"run\",\"build\"]、cwd=game或实际包目录;测试用purpose=test。现有文件的存在不等于本轮修改完成,必须给出真实修改与验证证据。不能提交passed、改写验证JSON或降低已登记要求。要求满足后停止新增润色或付费请求。需要诊断未满足项时读取agc_delivery_status。", "deliveryFeedback": "本轮验收尚未通过。读取agc_delivery_status,仅补齐已登记要求;未登记则先调用agc_register_delivery_contract。不得扩项、提交passed或改写证据。使用agc_run_validation purpose=build保存构建证明,再执行必要的定点测试和固定双端场景。原用户目标与本轮登记要求保持不变。\n\n未满足项:\n{detail}", - "engineering": "AGC 工程要求:当前 cwd 是用户选择的项目目录。先读取适用的 AGENTS.md、README 或项目说明,识别实际引擎与工程结构。用户明确指定编辑器或引擎,而当前目录缺少对应工程结构时,先说明不匹配并澄清;用户确认继续当前工程或提供匹配目录后再执行。Cocos Creator 项目优先通过 `agc_cocos_execute` 或 `cocos.editor.execute` 操作已打开的编辑器。新 Web 游戏使用 npm + Vite;二维游戏使用 Phaser 4.2.1,以 `import Phaser from 'phaser'` 导入;三维游戏自行选择合适的三维技术栈。依赖统一使用 npm 包。Phaser 迁移:读取已有 game/index.html,将状态、输入、敌人/守卫、波次、胜负、重开和画布绘制迁移到 Phaser Scene/GameObject/update;写入 game/package.json、package-lock.json、vite.config.js(输出 game/dist)、game/game.js、game/style.css,先调用 project.bootstrap {cwd:game},再调用 project.verify {cwd:game,script:build,expectedCommand:从 game/package.json 原样读取},确认 game/dist/index.html 后启动 preview.start,并分别 preview.validate 桌面与移动视口。Phaser 画布由单一机制居中:使用 Scale.FIT 与 autoCenter CENTER_BOTH 时,canvas 直接父容器使用尺寸明确的普通 block;使用 CSS 居中时,Phaser autoCenter 设为 NO_CENTER。外围布局可使用 flex/grid。预览偏移先检查并修正项目自身的 CSS 与 Phaser 配置。布局修改后按项目 scripts 构建 dist,在桌面、移动视口和 resize 后确认 canvas 相对父容器的中心误差不超过 1 CSS px、无溢出。简单修改聚焦用户要求及不可替代的最小验证;安装依赖、构建和试玩按此范围执行。源码和命令优先使用 cwd 相对路径,依赖安装与构建使用项目 npm scripts;原生文件读取、搜索、命令和图片查看按当前工具目录使用。源码局部补丁调用 `agc_apply_patch`,支持官方 Add/Delete/Update/Move 语法并固定当前项目目录;多步骤进度调用 `agc_update_plan`,计划状态不代替验收证据。完整文本写入可使用 `agc_write_file`,content 仅填写目标文件的完整原始 UTF-8 正文。可用能力包括原生文件、搜索、命令、图片查看、Skill、`agc_tools` 和用户已启用的第三方 MCP;用户指定工具时先查当前可用工具并调用,缺失时如实说明。资源工具按当前 schema 使用;Skill references 按需读取。完整新游戏或按策划案实现时执行 agc-game-production-workflow,依次完成“策划定界 → 项目/资源盘点 → 美术生成或复用 → 游戏实现 → 构建验证 → 桌面/移动试玩 → 交付报告”。需要视觉素材时执行 taonier-art-assets:检查已登记资源,缺少或不适用时调用生图/编辑工具,读取结果的相对路径和登记身份,将真实素材接入源码并验证显示后再交付。你负责推进任务和按范围试玩。", + "engineering": "AGC 工程要求:当前 cwd 是用户选择的项目目录。先读取适用的 AGENTS.md、README 或项目说明,识别实际引擎与工程结构。用户明确指定编辑器或引擎,而当前目录缺少对应工程结构时,先说明不匹配并澄清;用户确认继续当前工程或提供匹配目录后再执行。Cocos Creator 项目优先通过 `agc_cocos_execute` 或 `cocos.editor.execute` 操作已打开的编辑器。新 Web 游戏使用 npm + Vite;二维游戏使用 Phaser 4.2.1,以 `import Phaser from 'phaser'` 导入;三维游戏自行选择合适的三维技术栈。依赖统一使用 npm 包。Phaser 迁移:读取已有 game/index.html,将状态、输入、敌人/守卫、波次、胜负、重开和画布绘制迁移到 Phaser Scene/GameObject/update;写入 game/package.json、package-lock.json、vite.config.js(输出 game/dist)、game/game.js、game/style.css,先调用 project.bootstrap {cwd:game},再调用 project.verify {cwd:game,script:build,expectedCommand:从 game/package.json 原样读取},确认 game/dist/index.html 后启动 preview.start,并分别 preview.validate 桌面与移动视口。Phaser 画布由单一机制居中:使用 Scale.FIT 与 autoCenter CENTER_BOTH 时,canvas 直接父容器使用尺寸明确的普通 block;使用 CSS 居中时,Phaser autoCenter 设为 NO_CENTER。外围布局可使用 flex/grid。预览偏移先检查并修正项目自身的 CSS 与 Phaser 配置。布局修改后按项目 scripts 构建 dist,在桌面、移动视口和 resize 后确认 canvas 相对父容器的中心误差不超过 1 CSS px、无溢出。简单修改聚焦用户要求及不可替代的最小验证;安装依赖、构建和试玩按此范围执行。源码和命令优先使用 cwd 相对路径,依赖安装与构建使用项目 npm scripts;原生文件读取、搜索、命令和图片查看按当前工具目录使用。源码局部补丁调用 `agc_apply_patch`,支持官方 Add/Delete/Update/Move 语法并固定当前项目目录;多步骤进度调用 `agc_update_plan`,计划状态不代替验收证据。完整文本写入可使用 `agc_write_file`,content 仅填写目标文件的完整原始 UTF-8 正文。复制 Skill 自带文件(脚本、配置、参考文档)进项目时改用 `agc_install_skill_resource`,一次一个文件、`destinationPath` 为目标相对路径;不要用 `agc_write_file` 重抄大文件正文,也不要依赖原生 `cp`。可用能力包括原生文件、搜索、命令、图片查看、Skill、`agc_tools` 和用户已启用的第三方 MCP;用户指定工具时先查当前可用工具并调用,缺失时如实说明。资源工具按当前 schema 使用;Skill references 按需读取。完整新游戏或按策划案实现时执行 agc-game-production-workflow,依次完成“策划定界 → 项目/资源盘点 → 美术生成或复用 → 游戏实现 → 构建验证 → 桌面/移动试玩 → 交付报告”。需要视觉素材时执行 taonier-art-assets:检查已登记资源,缺少或不适用时调用生图/编辑工具,读取结果的相对路径和登记身份,将真实素材接入源码并验证显示后再交付。你负责推进任务和按范围试玩。", "unityPlugin": "Unity 编辑器能力由 agc_unity_execute(Runtime 工具名 unity.editor.execute)提供。当前工程是 Unity 时使用该工具执行 C#,先读取实际场景与对象再修改。仅提交 code;缺少工具时报告该能力不可用,不要自行安装或改写插件。结果待人工核对、超时或断线时,禁止自动重发、重启插件或切换项目以绕过阻断。只有真实 completed 回执才可报告成功。", "godotPlugin": "Godot 编辑器能力由 agc_godot_execute(Runtime 工具名 godot.editor.execute)提供。当前工程是 Godot 时使用该工具执行支持 return/await 的 GDScript 函数体,先读取真实场景再修改;不改写为 Phaser。不要自行安装插件、写入库文件或描述文件。仅提交 code,不提供项目、进程、端口、令牌或库路径;缺少工具时报告该能力不可用。编译或确定运行失败可修正代码;结果待人工核对、超时或断线时禁止自动重发、重启插件或切换项目绕过阻断。只有真实 completed 回执才可报告成功。", "editorGuide": "常用编辑器操作:Unity 先读 agc-unity-editor,Godot 先读 agc-godot-editor。可用原生 Skill 读取,或调用 agc_read_skill_resource,skillName 为对应名称、relativePath 为 SKILL.md,再按入口读取操作参考。指南提供场景、对象/节点、资源、UI、保存和撤销示例;只读说明不代表编辑器工具已可用,实际执行仍检查当前工具。", diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs index 28aded7d3..60693ebe6 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs @@ -245,6 +245,25 @@ fn direct_tools_mcp_specs_for_plugins( "additionalProperties": false } }), + json!({ + "name": "agc_install_skill_resource", + "description": prompt_text!("directTools.agc_install_skill_resource.description"), + "inputSchema": { + "type": "object", + "properties": { + "skillName": { "type": "string", "minLength": 1, "maxLength": 120 }, + "relativePath": { "type": "string", "minLength": 1, "maxLength": 240 }, + "destinationPath": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": prompt_text!("directTools.agc_install_skill_resource.parameters.destinationPath") + } + }, + "required": ["skillName", "relativePath", "destinationPath"], + "additionalProperties": false + } + }), json!({ "name": "agc_write_file", "description": prompt_text!("directTools.agc_write_file.description"), @@ -1039,11 +1058,7 @@ fn call_agc_read_skill_resource(arguments: &Value) -> Value { Ok(value) => value, Err(error) => return mcp_tool_result(error, Vec::new(), true), }; - if Path::new(&relative).is_absolute() - || relative.contains("..") - || relative.contains(':') - || relative.contains('\\') - { + if skill_resource_relative_path_is_unsafe(&relative) { return mcp_tool_result("Skill 资源路径不安全".to_string(), Vec::new(), true); } match read_agc_skill_resource(&format!("{skill}/{relative}")) { @@ -1052,6 +1067,40 @@ fn call_agc_read_skill_resource(arguments: &Value) -> Value { } } +/// Skill 资源相对路径的安全边界:`agc_read_skill_resource` 与 +/// `agc_install_skill_resource` 共用同一份判定。 +fn skill_resource_relative_path_is_unsafe(relative: &str) -> bool { + Path::new(relative).is_absolute() + || relative.contains("..") + || relative.contains(':') + || relative.contains('\\') +} + +/// 组装 `agc_install_skill_resource` 的落盘请求:宿主侧直接读已审核的内置字节, +/// 再复用 `agc_write_file` 的入参规则(项目相对路径 + 内容边界),写入仍走同一条合同 lease 门。 +/// +/// 正文不经过模型上下文,因此既不会被大文件截断,也不依赖原生 `cp` 及其审批。 +fn install_skill_resource_write_arguments(arguments: &Value) -> Result { + validate_tool_object_fields(arguments, &["skillName", "relativePath", "destinationPath"])?; + let skill = bounded_tool_string(arguments, "skillName", 120)?; + let relative = bounded_tool_string(arguments, "relativePath", 240)?; + if skill_resource_relative_path_is_unsafe(&relative) { + return Err("Skill 资源路径不安全".to_string()); + } + let destination = bounded_tool_string(arguments, "destinationPath", 512)?; + let content = read_agc_skill_resource(&format!("{skill}/{relative}"))?; + let write_arguments = json!({ "path": destination, "content": content }); + validate_write_file_arguments(&write_arguments)?; + Ok(write_arguments) +} + +async fn call_agc_install_skill_resource(arguments: &Value) -> Value { + match install_skill_resource_write_arguments(arguments) { + Ok(write_arguments) => call_client_tool_bridge("agc_write_file", &write_arguments).await, + Err(error) => mcp_tool_result(error, Vec::new(), true), + } +} + async fn call_agc_web_search_with_enabled(arguments: &Value, enabled: bool) -> Value { if !enabled { return mcp_tool_result("AGC 受控联网搜索未启用".to_string(), Vec::new(), true); @@ -1536,6 +1585,7 @@ async fn handle_direct_tools_mcp_request(root: &Path, request: Value) -> Option< .await } "agc_write_file" => call_agc_write_file(&arguments).await, + "agc_install_skill_resource" => call_agc_install_skill_resource(&arguments).await, #[cfg(all(windows, feature = "cocos-editor-execute"))] "agc_cocos_execute" => call_agc_cocos_execute(&arguments).await, #[cfg(all(windows, target_arch = "x86_64", feature = "unity-editor-execute"))] @@ -2752,6 +2802,7 @@ mod tests { "conversation.list", "conversation.read", "agc_read_skill_resource", + "agc_install_skill_resource", "agc_write_file", "taonier_prepare_game_art", "agc_generate_image", @@ -3259,6 +3310,66 @@ mod tests { assert_eq!(denied_windows_absolute["isError"], true); } + #[test] + fn install_skill_resource_rewrites_reviewed_bytes_into_one_write_arguments() { + let write = install_skill_resource_write_arguments(&json!({ + "skillName": "agc-project-structure", + "relativePath": "references/structure-contract.md", + "destinationPath": "scripts/structure-contract.md" + })) + .expect("reviewed skill resource composes a write"); + assert_eq!(write["path"], "scripts/structure-contract.md"); + assert_eq!( + write["content"], + read_agc_skill_resource("agc-project-structure/references/structure-contract.md") + .expect("reviewed bytes") + ); + // 只暴露 agc_write_file 的两个入参,模型自带的正文没有旁路通道。 + assert_eq!(write.as_object().expect("object").len(), 2); + } + + #[test] + fn install_skill_resource_rejects_unreviewed_or_unsafe_targets() { + for arguments in [ + // 未登记的资源 + json!({ + "skillName": "agc-project-structure", + "relativePath": "references/not-in-manifest.md", + "destinationPath": "scripts/x.md" + }), + // 资源路径穿越 + json!({ + "skillName": "agc-project-structure", + "relativePath": "../../auth.json", + "destinationPath": "scripts/x.md" + }), + // Windows 绝对路径 + json!({ + "skillName": "agc-project-structure", + "relativePath": r"C:\temp\SKILL.md", + "destinationPath": "scripts/x.md" + }), + // 目标路径越出项目根 + json!({ + "skillName": "agc-project-structure", + "relativePath": "references/structure-contract.md", + "destinationPath": "../outside.md" + }), + // 模型自带正文的旁路字段 + json!({ + "skillName": "agc-project-structure", + "relativePath": "references/structure-contract.md", + "destinationPath": "scripts/x.md", + "content": "model-supplied" + }), + ] { + assert!( + install_skill_resource_write_arguments(&arguments).is_err(), + "{arguments} must be rejected before any bridge call" + ); + } + } + #[test] fn editor_guides_are_available_through_the_existing_skill_resource_tool() { for (skill, engine) in [("agc-unity-editor", "Unity"), ("agc-godot-editor", "Godot")] { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 3aee2bb5a..d52084c5e 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -1,5 +1,13 @@ # 决策记录 +## 2026-10-06 新增 agc_install_skill_resource:Skill 附件由宿主直接落盘,不走模型正文 + +- 背景:`vite-export-xhs-minitool` 等审核 Skill 要把自带脚本(`scripts/validate.mjs` 约 40 KB、`pack.mjs`、`vite.config.*.mjs`)原样复制进用户项目。`agc_read_skill_resource` 的大文件正文会被模型上下文截断,重抄必然失真;原生 `cp` 在 DirectProject 只读沙箱下被审批闸门拒绝。两条路都走不通。 +- 决策:新增内置 MCP 工具 `agc_install_skill_resource`,入参 `skillName` / `relativePath` / `destinationPath`。宿主在 MCP 进程内直接读 `AGC_SKILL_PACK_FILES` 里已审核的内置字节(复用 `read_agc_skill_resource` 的清单校验与路径拒绝口径),组装成 `agc_write_file` 的 `{path, content}` 转发给客户端受控工具桥。写入因此走与 `agc_write_file` 相同的合同、lease、项目写锁与保护面校验;正文不经过模型上下文,没有截断,也不需要原生 `cp` 及其审批。 +- 边界:工具只暴露 `agc_write_file` 的两个入参,模型无法自带正文旁路审核;一次调用落一个文件,不打包、不改写、不建目录以外的副作用。DirectProject 的只读原生沙箱与 #439 审批口径不变,本工具是替代 `cp` 的受控通道,不是放开沙箱。 +- 影响范围:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs`(工具目录、分发、`install_skill_resource_write_arguments`)、`prompts/runtime/texts/direct-tools.json`、`prompts/runtime/texts/direct.json`,权威说明同步到技术方案。 +- 验证:`cargo test --offline -p genarrative-ai-game-creator-shell --bin genarrative-ai-game-creator-shell agent::`(736 passed,含新增 `install_skill_resource_*` 两条与 `tool_catalog_preserves_reviewed_resource_contracts`)、`npm run check:encoding`、`git diff --check`。 + ## 2026-10-06 小红书导出 skill:dist 收尾归 Vite 插件,pack 只读打 zip - 背景:`vite-export-xhs-minitool` 的 `pack.mjs` 之前会就地改写 dist(相对路径 / 去 `type="module"` / `crossorigin` / 脚本移到 body 末尾 / 清空目录 / 兜底复制 icon)再打 zip;dist 只有在跑完 pack 后才合规,`validate.mjs` 看到的是中间态,打包脚本也因此同时承担「整理产物」与「打 zip」两件事。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 3806ab765..6b2b95a25 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -1522,7 +1522,7 @@ game-project/ - 首页提供“做游戏 / 做方案”两个创作类型(`game` / `doc`),默认“做游戏”;“做素材”入口已退役,素材生成在项目内按实际工作流触发。每次首页提交自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|doc` 作为受限结构化首轮上下文传给同一 Codex thread;持久草稿里遗留的 `art` 按 `game` 处理(`effectiveCreationType` 映射),不再产生第三种首轮上下文。 - 「策划补全」是“做游戏”专属的提交前勾选(2026-09-15 起):勾选时该档提交 `planning`,未勾选时提交 `direct-build`;“做方案”始终走立项策划链路,与本勾选无关。复选框只在“做游戏”档渲染;切换创作类型时首页表面整体重挂,勾选状态随之清除,切回来必须是未勾选——这条可观察契约由 `appSurface` 的「scopes the 策划补全 option to the game entry」与「submits the game entry with planning when 策划补全 is checked」两条用例钉住,实现侧不额外维护重置逻辑。 - 2026-09-23 清理了未注册的 DirectHome 用户对话命令及旧附件 sidecar 渲染链;首页仍先创建项目再进入 DirectProject,不恢复无项目对话。自动项目命名和提示润色仍调用内部 `direct_game_creator_home_codex_chat`,其 DirectHome 只读隔离通道与测试继续保留。附件作为 canonical `userItem.content` 中的 `agc_attachment_reference` 携带名称、媒体类型、大小、项目相对路径及状态,经现役 validation/wire 校验与投影;路径映射不等于灌入全文,也不按 GDD 特判。附件清洗与数量上限继续复用 `direct_codex_attachments.rs`,旧 sidecar DTO、header、专属 prompt key 和测试不再是保留合同。 -- `agc-skill-pack.v1` 包含完整游戏交付流程、项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影、Unity/Godot 编辑器常用操作、平台抽象收口和小红书小工具导出十项审核 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;审核文本按 UTF-8 读取并将 CRLF 规范为 LF 后计算指纹和安装,避免混合换行造成 Windows / Linux 构建结果漂移,语义内容变化时必须同步重算对应清单指纹并提升版本。同步统一运行 `npm run agc:skill-pack:sync`,只读校验由 AGC `typecheck` 和 release build 自动执行,发现漂移时直接列出 Skill 与实际摘要,不让失配内容进入构建产物。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。Skill 目录里以 `.` 开头的文件和目录是本地开发辅助(例如 `vite-export-xhs-minitool/.selective_rule.txt`、`scripts/.pack.test.mjs`):不写进清单、不参与指纹、不安装,也不能经 `agc_read_skill_resource` 读取;JS 清单工具 `isHiddenSkillEntryName` 与 Rust `is_hidden_skill_entry_name` 共用同一拒绝口径,新增 Skill 时无需为它们补 `include_bytes!`。 +- `agc-skill-pack.v1` 包含完整游戏交付流程、项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影、Unity/Godot 编辑器常用操作、平台抽象收口和小红书小工具导出十项审核 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;审核文本按 UTF-8 读取并将 CRLF 规范为 LF 后计算指纹和安装,避免混合换行造成 Windows / Linux 构建结果漂移,语义内容变化时必须同步重算对应清单指纹并提升版本。同步统一运行 `npm run agc:skill-pack:sync`,只读校验由 AGC `typecheck` 和 release build 自动执行,发现漂移时直接列出 Skill 与实际摘要,不让失配内容进入构建产物。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown;把 Skill 自带脚本或配置原样复制进项目时用 `agc_install_skill_resource`(skillName/relativePath/destinationPath),宿主直接读内置审核字节并按 `agc_write_file` 的入参规则与合同 lease 写盘,正文不经过模型上下文,避免大文件截断和原生 `cp` 审批。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。Skill 目录里以 `.` 开头的文件和目录是本地开发辅助(例如 `vite-export-xhs-minitool/.selective_rule.txt`、`scripts/.pack.test.mjs`):不写进清单、不参与指纹、不安装,也不能经 `agc_read_skill_resource` 读取;JS 清单工具 `isHiddenSkillEntryName` 与 Rust `is_hidden_skill_entry_name` 共用同一拒绝口径,新增 Skill 时无需为它们补 `include_bytes!`。 - DirectProject 连接客户端内置的 `agc_tools` STDIO MCP,并在启动时接入客户端扩展仓库中用户已启用的独立第三方 STDIO/HTTP MCP 配置。内置工具包括审核引用读取、图片生成、标准陶泥儿美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive 语义生成、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`。内置 MCP 进程负责协议;真实浏览器、付费平台调用与受控搜索通过随机 loopback 地址回到客户端主进程,GUI 登录态、开发者 Key、项目路径、revision、operation 与幂等键由客户端持有并隔离于模型上下文。内置与用户启用的第三方 MCP 工具沿用 DirectProject 自动批准方式;付费资源工具由客户端绑定稳定回合身份、串行执行并优先恢复匹配账本。`llm.webSearchEnabled` 控制 DirectProject 的 AGC 受控搜索工具暴露与执行。原生工具与审批权限以下方“DirectProject Codex 完整访问覆盖”为准。 - 陶泥儿生成复用持久幂等账本、operation 恢复、来源/下载/PNG 解码和 manifest 登记;普通客户端使用当前 AGC 登录会话及账号路由,受控的 ExternalDeveloper 发布模式在客户端内部使用按服务器 origin 隔离的私有 Key。凭据失效、来源不明或结果未知时失败关闭,不能自动换 Key 或重新扣费。 - 自定义 LLM API Key 路由在 DirectProject 及内部 DirectHome 辅助调用中经 loopback `/responses` 流式代理转发。代理使用请求自带的 Bearer,并剥离开发网关错误携带的 `X-Codex-*` ChatGPT 账户额度头,按实际 API Provider 响应判断请求结果。