From 90a414ebf3ff734e9c56527ce74662df1e0f246c Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Mon, 28 Sep 2026 22:55:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=85=E7=90=86=E9=9A=8F=E5=8C=85=20Codex=20?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E9=87=8C=E7=9A=84=E6=97=A7=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E6=AE=8B=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src-tauri/build.rs:stage_codex_target 拷贝前调用新增的 prune_stale_codex_components,删掉不在本轮布局也不在 manifest.json/NOTICE.md 白名单里的文件并收掉空目录 - 复验:重建后 resources/codex/win-x64 根目录那份 0.147.0 codex.exe 与临时备份被清除,六个声明组件、manifest.json 与 NOTICE.md 保留;同一二进制下 loopback 夹具仍跑到 requests=3、markers.ready=true - 文档:DirectProject 里程碑本轮核对细化第二层问题(不是 codex 版本漂移、不是 stdin;指向 Drop for ExecutionBinding 的收尾竞态,需插桩),并说明两条运行时验收本质要真实客户端窗口;pitfalls 记录该环境陷阱与修复 --- apps/ai-game-creator-shell/src-tauri/build.rs | 40 +++++++++++++++++++ ...碑】DirectProject聊天真相源收敛-2026-09-16.md | 2 +- docs/project-memory/shared-memory/pitfalls.md | 3 +- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/build.rs b/apps/ai-game-creator-shell/src-tauri/build.rs index cd69f8180..892ec4600 100644 --- a/apps/ai-game-creator-shell/src-tauri/build.rs +++ b/apps/ai-game-creator-shell/src-tauri/build.rs @@ -115,6 +115,10 @@ fn stage_codex_target(manifest_dir: &std::path::Path, target: &str) { panic!("内置 Codex CLI 第三方声明缺失:{}", notice.display()); } fs::create_dir_all(&target_dir).expect("创建内置 Codex CLI 资源目录失败"); + // 这份目录是随包资源(Windows:`resources/codex/win-x64/**` → `coding-agent/win-x64/**`), + // 只能包含本轮布局声明的组件。上一版布局留下的旧二进制(例如包根目录那份 0.147.0 + // `codex.exe`)会长期留在原地:既误导本地核对与夹具,也让「随包内容」与清单不一致。 + prune_stale_codex_components(&target_dir, layout.files); let mut file_hashes = serde_json::Map::new(); for relative in layout.files { let source_path = source.join(relative); @@ -174,6 +178,42 @@ fn stage_codex_target(manifest_dir: &std::path::Path, target: &str) { } } +/// 删除 `target_dir` 下不在本轮布局内的残留文件;空目录一并收掉。 +fn prune_stale_codex_components(target_dir: &std::path::Path, files: &[&str]) { + const ALWAYS_KEEP: &[&str] = &["manifest.json", "NOTICE.md"]; + fn walk(root: &std::path::Path, directory: &std::path::Path, files: &[&str], keep: &[&str]) { + let Ok(entries) = fs::read_dir(directory) else { + return; + }; + for entry in entries.flatten() { + let path = entry.path(); + let Ok(kind) = entry.file_type() else { + continue; + }; + if kind.is_dir() { + walk(root, &path, files, keep); + if fs::read_dir(&path) + .map(|mut remaining| remaining.next().is_none()) + .unwrap_or(false) + { + let _ = fs::remove_dir(&path); + } + continue; + } + let Ok(relative) = path.strip_prefix(root) else { + continue; + }; + let relative = relative.to_string_lossy().replace('\\', "/"); + if files.contains(&relative.as_str()) || keep.contains(&relative.as_str()) { + continue; + } + eprintln!("cargo:warning=清理内置 Codex 组件残留:{relative}"); + let _ = fs::remove_file(&path); + } + } + walk(target_dir, target_dir, files, ALWAYS_KEEP); +} + fn seed_task_group_id( group: &shared_contracts::game_creation_app::GameCreationAppAgentGroup, ) -> &'static str { diff --git a/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md b/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md index 5e2d24ac7..18032d98f 100644 --- a/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md +++ b/docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md @@ -81,4 +81,4 @@ AGC 项目开发对话的显示与恢复只依赖两项输入:**项目对话 - **缺陷**:全新项目的第一次对话直接失败。夹具 `--cases completed` 下 AGC 进程 4 秒退出、`requests=[]`,stderr 只有 `Codex app-server JSON-RPC 失败:items must not be empty`。根因是 `thread_created` 时无条件发 `thread/inject_items`,而空项目没有 `.agent/conversations/project.jsonl`,载荷成了 `items: []`;codex app-server 0.155.1 起把空数组当协议错误。GUI 路径没暴露是因为前端会先写用户消息,CLI / 无前端宿主是裸的。 - **修复**:`build_direct_project_history_injection_params()` 在历史为空时返回 `Ok(None)`,调用方跳过注入;新增单测「空历史不得构造载荷」「有历史仍构造 1 条」。`cargo test … direct_project_history_wire`(3 passed)与 `cargo fmt --check` 通过。 - **复验**:同一条命令下夹具从「4 秒失败」变成「走到 loopback Provider:`requests=3`、`markers.ready=true`、AGC exit=0」,说明第一层已经修通。 -- **仍未完成(第二层)**:同一用例仍断言失败,执行账本落在 `phase=interrupted`(期望 `completed`),stderr 为 `agent.runner.failed: Codex app-server 连接终止 … stderrBytes=1242`,CLI 回执是「执行通道已断开,不能自动重放未确认操作」。现象指向 CLI 收尾阶段的关闭竞态,需要先拿到 app-server 的 stderr 原文(当前只落字节数与 sha256)。两条运行时验收**继续未勾选**。 +- **仍未完成(第二层)**:修好第一层后,夹具的**全部 6 个用例**都走到 loopback Provider(`requests=3`、`markers.ready=true`、exit=0),但统一失败在账本阶段——`phase=interrupted`(期望 `completed`/`exhausted`),stderr 为 `agent.runner.failed: Codex app-server 连接终止 … stderrBytes=1242`,CLI 回执是「执行通道已断开,不能自动重放未确认操作」。本轮排除:① 不是 codex 版本漂移(换 0.147.0 结果相同);② 不是 stdin 被忽略(改成 `pipe` 结果相同)。可疑路径是主机收尾竞态:`codex_app_server/execution.rs:70` 的 `Drop for ExecutionBinding` 在 `!background_done && !closed` 时补一次 `cancel_from_host()`(`execution.rs:706`,写的就是账本里那句「本轮已由宿主终止…」),同文件 750 行的通道断开处置又会先记一条 transport 失败。**结论:两条运行时验收本质上要真实客户端窗口**(夹具只能证历史持久化,证不了「界面不显示忙碌态」),因此这两条继续未勾选;CLI 收尾竞态作为独立问题记进 pitfalls,动它之前先插桩(抓 app-server stderr 原文 + Drop/transport 时序日志)。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index ce79fd386..de93fd498 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -6113,4 +6113,5 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **根因**:`codex_app_server/mod.rs` 在 `thread_created` 时无条件调用 `thread/inject_items`,载荷由 `build_direct_project_history_injection_params()` 从 `.agent/conversations/project.jsonl` 构造;**全新项目该文件不存在 → `items: []`**,而 codex app-server 0.155.1 起把空数组当协议错误拒绝。GUI 路径之所以没暴露:前端会先调 `append_direct_project_conversation_message` 把用户消息写进历史,注入时至少有 1 条;`--direct-codex-chat` 这类无前端宿主(以及任何直接调用 `run_direct_game_creator_turn_at` 的夹具/CLI)没有这一步。 - **处理(2026-09-28 已修)**:`build_direct_project_history_injection_params()` 在历史为空时返回 `Ok(None)`,调用方跳过 `thread/inject_items`;新增两条单测(空历史不得构造载荷、有历史仍构造 1 条)。 - **复验**:同一条夹具命令下,AGC 进程从「4 秒失败、`requests=[]`」变成「走到 loopback Provider、`requests=3`、`markers.ready=true`、exit=0」——第一层缺陷确实修掉了。 -- **仍未解决(第二层,另一个问题)**:同一个夹具的 `completed` 用例仍断言失败,原因是执行账本 `phase=interrupted`(期望 `completed`),stderr 为 `agent.runner.failed: Codex app-server 连接终止 … exitStatus=unknown;stderrBytes=1242`,CLI 回执文本也是「执行通道已断开,不能自动重放未确认操作」。看起来是 CLI 收尾阶段的关闭竞态(账本被记成宿主终止),与空历史注入不是同一件事;要动它需要先抓 app-server 的 stderr 内容(应用目前只记字节数与摘要,不落原文)。 +- **仍未解决(第二层,另一个问题)**:同一个夹具的全部 6 个用例(`completed/passes/mcp/mcp-write/native/deadline`)在修好第一层后都走到 loopback Provider,但**统一**失败在账本阶段:`phase=interrupted`(期望 `completed`/`exhausted`),stderr 为 `agent.runner.failed: Codex app-server 连接终止 … exitStatus=unknown;stderrBytes=1242`,CLI 回执文本为「执行通道已断开,不能自动重放未确认操作」。本轮已排除两种可能:① 不是 codex 版本漂移——把 `resources/codex/win-x64/bin/codex.exe` 换成 0.147.0(仓库里那份 root 残留)后结果完全相同;② 不是 stdin 被忽略——把夹具的 `stdio[0]` 从 `ignore` 改成 `pipe` 后同样 `interrupted`。定位到的可疑路径是主机收尾竞态:`agent/codex_app_server/execution.rs:70` 的 `Drop for ExecutionBinding` 在 `!background_done && !closed` 时补一次 `cancel_from_host()`,而该函数(`execution.rs:706-716`)会写「本轮已由宿主终止;正在收束执行器,未完成项保留。」——账本里的 `terminalReport` 正是这句;同文件 `execution.rs:750` 的通道断开处置又会先记一条 transport 失败事实。下一步要动它得先做插桩(抓 app-server 的 stderr 原文、给 Drop 与 transport 记账加时序日志),不要在没插桩前猜着改守卫。 +- **顺带记一条环境陷阱(2026-09-28 已修)**:`apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/` 下曾有两个 codex 二进制——`bin/codex.exe` 是**真正被解析**的那份(0.155.1),而包根目录那份 `codex.exe` 是 0.147.0 的旧残留(tauri 的 Windows 资源映射只引用 `bin/` 等路径),检查都查不出来,却会让本地核对误判「应用跑的是 0.147.0」。根因是 `src-tauri/build.rs` 的 `stage_codex_target()` 只按布局拷贝、从不清理目录,旧布局的组件会永久留在随包资源目录里。现在加了 `prune_stale_codex_components()`:拷贝前删掉不在本轮布局、也不在 `manifest.json`/`NOTICE.md` 白名单里的文件并收掉空目录;实测重建后根目录 `codex.exe` 被清掉、六个声明组件与清单/声明保留。