修复AGC的macOS临时路径兼容
规范化配置回归测试的临时根路径 补充跨平台路径比较技术说明与踩坑记录
This commit is contained in:
@@ -413,6 +413,7 @@ async function runConfigWizardRegressionChecks() {
|
||||
const testRoot = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), 'genarrative-agc-config-check-'),
|
||||
);
|
||||
const canonicalTestRoot = fs.realpathSync.native(testRoot);
|
||||
try {
|
||||
const gitRoot = path.join(testRoot, 'tracked-repository');
|
||||
const trackedConfigDir = path.join(gitRoot, 'runtime-config');
|
||||
@@ -441,7 +442,7 @@ async function runConfigWizardRegressionChecks() {
|
||||
const outsideConfigDir = path.join(testRoot, 'outside-appdata');
|
||||
assert.equal(
|
||||
await assertSafeGameCreatorConfigDestination(outsideConfigDir),
|
||||
outsideConfigDir,
|
||||
path.join(canonicalTestRoot, 'outside-appdata'),
|
||||
);
|
||||
await assert.rejects(
|
||||
assertSafeGameCreatorConfigDestination(outsideConfigDir, {
|
||||
@@ -454,7 +455,7 @@ async function runConfigWizardRegressionChecks() {
|
||||
await assertSafeGameCreatorConfigDestination(dedicatedConfigDir, {
|
||||
requireDedicatedLeaf: true,
|
||||
}),
|
||||
dedicatedConfigDir,
|
||||
path.join(canonicalTestRoot, appIdentifier),
|
||||
);
|
||||
|
||||
const injectedNonGitConfigDir = path.join(testRoot, 'injected-non-git');
|
||||
@@ -467,7 +468,7 @@ async function runConfigWizardRegressionChecks() {
|
||||
'fatal: not a git repository (or any of the parent directories): .git\n',
|
||||
}),
|
||||
}),
|
||||
injectedNonGitConfigDir,
|
||||
path.join(canonicalTestRoot, 'injected-non-git'),
|
||||
);
|
||||
await assert.rejects(
|
||||
assertSafeGameCreatorConfigDestination(
|
||||
|
||||
@@ -3703,6 +3703,7 @@
|
||||
- 处理:GUI 与 `npm run agc:config` 共用系统 AppData `game-creator.config.json`,终端隐藏输入 API Key 并禁止 `--api-key`;更新时保留 `agentLlm`、`editorApi`、`mcpServers` 等其它配置,POSIX 权限维持目录 `0700` / 文件 `0600` 并原子替换。显式 `--config-dir` 必须以 `world.genarrative.ai-game-creator` 为独立叶目录,不能让向导对 `/tmp`、AppData 根或共享目录整体 chmod / 重建 DACL。隐藏输入调用 `stdin.resume()` 后必须记住原 pause 状态,在成功、取消、异常和 `SIGINT / SIGTERM / SIGHUP` 路径恢复 raw mode 并 `pause()`,信号恢复后重发;只移除 `data` listener 会让 `--configure-only`、配置检查失败或 Ctrl+C 保持活动 stdin。缺配置时仅 TTY 人工会话可询问进入向导,非 TTY 立即失败并提示配置命令。
|
||||
- Windows 密钥复制:`mode: 0o600` 和 POSIX `chmod` 在 Windows 上不能代替 DACL。隔离 AppData 目录必须先设置仅当前用户、禁止继承的 DACL;目标配置文件先以空文件创建并收紧 DACL,之后才允许把 API Key 字节写入。先 `copyFile` 再依赖 Rust 只读检查或事后收紧会留下密钥暴露窗口,也可能因继承 ACL 不满足 Runtime 合同而在首次 `--llm-status` 失败。
|
||||
- Windows PowerShell 参数:不要把 DACL 目标路径和目录标记直接追加在 `powershell.exe -Command <script>` 后;Windows Node `spawn` 会让 PowerShell 5.1 把这些值拼入命令文本,带空格的临时路径会被拆分并使 `GetFullPath($args[0])` 失败。当前实现只通过子进程私有环境变量传入路径和布尔值,并由真实 Windows `npm run agc:typecheck` 覆盖 DACL 回归。
|
||||
- 跨平台临时路径比较:macOS 的 `os.tmpdir()` 可返回 `/var/folders/...`,而 `realpath` 会返回同一目录的 `/private/var/folders/...`;Windows 也可存在驱动器号大小写、junction 或链接解析差异。测试安全路径函数时,fixture 期望值必须基于平台原生 `realpath` 后的根目录构造,不能直接与 `mkdtemp` 的逻辑路径字符串严格比较。
|
||||
- 超时与进程树:`setTimeout` 后只对直接 Cargo PID 调一次 `kill()` 不是硬超时;Cargo 启动的 CLI / Runner 仍可能持有 stdio,使 `close` 永远不返回,清理阶段也可能无界等待。POSIX 必须创建独立进程组并按负 PID 终止,Windows 必须使用 `taskkill /T`;宽限期后升级强杀,Runner shutdown 和清理另设短硬超时。重复 Ctrl+C 也必须升级,不能一直被自定义 signal handler 吞掉。
|
||||
- 模式拆分:自动化使用默认的 `agc:test:chat`,由脚本投递固定植物塔防需求;正式产物、最新 revision 静态检查和 Runtime 浏览器验收通过后立即收束并清理,不启动持续 preview。`agc:test:chat:manual` 不注入 `--task`,用于多轮 stdin 手工聊天,并保留 preview 直到显式退出;不能用 EOF 或是否存在 `game/index.html` 猜测当前模式。
|
||||
- 验证:覆盖 `--api-key` 拒绝、各平台 AppData 路径、Provider 预设、旧配置节点保留、URL 安全校验、原子写入、POSIX 权限、隐藏输入恢复 pause、Windows 写密钥前 DACL、整棵进程树超时终止、缺配置时 TTY / 非 TTY 分支,以及 `--task` 成功后不进入长期 preview、手工模式仍可持续试玩。测试和错误输出只验证“密钥已配置”状态,不读取或打印密钥本体;源码字符串断言和 Linux 上的 Windows mock 不能替代真实 Windows ACL / `taskkill` 复验。
|
||||
|
||||
@@ -762,6 +762,7 @@ game-project/
|
||||
- 验证:`npm run agc:test` 已通过确定性 loopback Provider、真实 Runtime、项目写入和浏览器链路验收:同一父 Run 下 16 个 manifest task 均只有一个 logical run、一次 start、一次 completed 和一次 manifest projection,且无 failed / cancelled;父 run 与全部子 run 完成,最终 revision 为 `11`,基础正式产物、静态 smoke、桌面 / 移动 `37/37` 试玩通过,pending、reconciliation、Provider 失败、重复和泄漏计数均为 `0`。该结果不替代独立外部 Provider 验收。
|
||||
- 2026-07-26 本轮已验证 `npm run agc:config` 的终端配置链路。向导与 GUI 使用同一 Tauri identifier 对应的系统 AppData 和同名 `game-creator.config.json` / 可选 local overlay;读取已有配置时只更新有效 LLM 层,保留 `agentLlm`、`editorApi`、`mcpServers` 等其它配置。API Key 只从隐藏输入读取,拒绝 `--api-key`、仓库内目录、Git 已跟踪配置、符号链接,以及不是以 `world.genarrative.ai-game-creator` 为独立叶目录的 `--config-dir`,防止把任意父目录整体改成私有权限。保存使用同目录 `0600` 临时文件原子替换,POSIX AppData 目录保持 `0700`,Windows 使用当前用户独占 DACL,写后复用真实 `--llm-status` 检查;隐藏输入收到 `SIGINT / SIGTERM / SIGHUP` 时先恢复 raw mode 和 pause 状态再重发原信号,向导启动的 Cargo / npm 使用独立进程组并在信号路径有界收束整棵子进程树。
|
||||
- 2026-07-27 Windows DACL 启动回归修正:`powershell.exe -Command` 后追加的位置参数会被 PowerShell 5.1 拼接进命令文本,不能用 `$args` 安全接收包含空格的 AppData / 临时目录。DACL 脚本改为从仅传给该子进程的环境变量读取目标绝对路径和目录标记;`npm run agc:typecheck` 必须在真实 Windows 上执行配置回归,保证 `npm run agc` 的 `beforeDevCommand` 不因路径解析失败退出。
|
||||
- 2026-07-31 macOS 临时路径回归修正:配置目的地安全检查返回解析过现存父目录的真实路径,回归 fixture 的期望值也必须先使用平台原生 `realpath` 规范化临时根目录。macOS 下 `/var/folders/...` 与 `/private/var/folders/...` 是同一目录身份,不得用未规范化字符串阻断 `agc:typecheck`;同一回归在 Windows 上必须使用本机真实路径结果覆盖驱动器号、大小写与链接路径差异。
|
||||
- 2026-07-27 项目总控右栏空态与持久状态水合修正:项目尚未产生 Runtime 时仍显示“尚未开始”状态块和创作入口,不把消息列表的弹性剩余空间裸露为空白;若 active Session 索引缺失但项目内已有 `project-supervisor` Runtime,工作台必须从 `read_game_creator_agent_runtimes` 的权威项目列表恢复总控 Session 与状态。`needs-reconciliation` 统一显示为“失败 / 待核对”,不能因对话索引缺失隐藏已落盘的失败事实。
|
||||
- 2026-07-28 Windows `tool-plan` 成功响应交接修正:相对目录句柄下安装 handoff 账本改用 `NtSetInformationFile(FileRenameInformation)`;`SetFileInformationByHandle(FileRenameInfo)` 不接受当前实现所需的非空 `RootDirectory`,会稳定返回 `ERROR_INVALID_PARAMETER (87)` 并让总控首轮进入 `needs-reconciliation`。实现继续绑定已验证的父目录句柄和相对 hash 文件名,不退化为绝对路径 rename;“按句柄安装”归入 `tool-plan-storage`。总控对 reconciliation 提供“已核对,结束旧任务”,取消后有 pending task 时只等待 Runner 续跑,队列为空时才允许显式 retry;自主构建 Supervisor 的 retry source 从原 Run Profile 绑定恢复并重新验证为可信 GUI / CLI 根入口,不降级成普通后台任务来源。
|
||||
- 2026-07-28 `tool-plan` 格式修复协议与 steer 审计修正:OpenAI Responses 请求按角色映射内容块,system / user 文本为 `input_text`,assistant 计划预览为 `output_text`,assistant `input_image` 在本地校验阶段拒绝,避免 repair 请求因非法 `input_text` 被上游以 HTTP 400 拒绝。tool-plan protocol / repair 审计增加 `appliedSteerCursor`,幂等键也纳入该 cursor;等待 Provider retry 期间 steer 后,同一 run / loop 可在新 cursor 下合法重用 `repair-0` 逻辑槽。旧记录缺少 cursor 时仅视为 `0`,保持升级后 replay 幂等。回归必须覆盖 Responses 多角色序列化、user 多模态,以及“无效计划 → repair retry 等待 → steer → 新 cursor repair”链路。
|
||||
|
||||
Reference in New Issue
Block a user