Feat/适配小红书小工具导出 #630

Merged
k88936 merged 158 commits from feat/adapt-xhs-skill into master 2026-10-07 10:09:38 +08:00
Member
No description provided.
k88936 added 5 commits 2026-10-05 15:15:50 +08:00
- 新增 platform-abstract 与 vite-export-xhs-minitool 两项审核 Skill
- agc-skill-pack.v1 清单版本升至 2026-08-26.40,两个新条目 sha256 现场重算
- skill-pack 工具新增隐藏文件规则:. 前缀文件/目录不写清单、不参与指纹、不安装、不可读取
- JS 与 Rust 白名单同步扩到 10 项,AGC_SKILL_PACK_FILES 增加 13 条 include_bytes!
- codex_app_server 三条 skills/list 测试夹具补齐两个新 Skill 名
- 补充隐藏路径拒绝与收集器忽略隐藏文件的 JS/Rust 测试
- 修掉 pack.mjs / validate.mjs 的 eslint 问题与三处空白,使其通过 pre-commit 与 git diff --check
- 同步更新技术方案与决策记录
- .eslintrc.cjs 的 ignorePatterns 增加 apps/ai-game-creator-shell/src-tauri/resources/agc-skills/**
- 审核 Skill 脚本按 SHA-256 定址并用 include_bytes! 编进客户端,eslint --fix 改写会导致 manifest 指纹漂移
- .prettierignore 本已排除该目录,eslint 补齐同一口径
- 更新决策记录
新增 project-development/export 全屏导出面板:目标大卡、等宽下划线 tab、小红书工作台分栏与第二 subscriber 会话。

面板状态提升到 usePanel 根,tab 页可卸载;输入草稿提升到面板层,切 tab 不丢字。

抽出 DirectProjectChatBox,主聊天与导出会话复用同一套对话盒,不再另写版式。

DirectProjectChatHeader 增加「导出」入口,App.tsx 条件挂载全屏面板。

DirectProjectComposer 增加 referencesEnabled 与 draft/onDraftChange,导出输入区关闭素材引用。

新增 tests/artifactsPanel.test.tsx 覆盖卡片、tab、关闭与对话盒复用。
新增 packages/shared/src/icons/rednote.png 与 taptap.png 两个真实图标。

TargetIcon 按 Target 一处收口图源:陶泥儿用 IP 图,小红书用 RedNote,TapTap 用 TapTap logo。

TapTap 是横向 logo,卡片与 tab 的图标盒改为矩形配 object-contain,宽图按宽度贴满、方图按高度贴满。
导出面板图标盒恒为正方形
Project CI / Backend tests (pull_request) Failing after 15s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m3s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m26s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 3m47s
Project CI / Repository checks (pull_request) Failing after 26s
Project CI / Frontend tests (pull_request) Successful in 3m17s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m31s
Project CI / Native shell tests (pull_request) Successful in 8m18s
bef4151b10
卡片图标盒改回 aspect-square、tab 图标盒改回 size-5,只用 object-contain 等比缩放。

TapTap 横向 logo 在方盒里按宽度居中留白,不再用矩形盒。
k88936 added 57 commits 2026-10-06 17:25:45 +08:00
- 主规范在 docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md 新增「2026-10-05 导出产物面板与小红书小工具导出」一节:宿主只做读写注册表、校验表单与脚本、跑项目脚本、交付产物四件确定性的事,适配与打包归 code agent。
- 新增【里程碑】导出产物面板与小红书小工具导出-2026-10-05.md:范围、非目标、依赖与 9 条验收标准。
- 新增【实施计划】导出产物面板与小红书小工具导出-2026-10-05.md:修改边界、实现顺序、验证命令、风险与回滚点。
- docs/project-memory/shared-memory/decision-log.md 记录边界、注册表无状态字段、内容 hash 冲突模型、.export flat 工作目录、复用 command.exec 权限且不拿写锁、prompt 归前端六条决策。
- docs/README.md 的 AI 游戏创作与 Agent Runtime 区补入口。
- 新增 apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:注册表 JSON 的自动创建、严格解析、临时文件原子替换与原始字节 SHA-256 指纹,不认任何 target。
- 改写 apps/ai-game-creator-shell/src-tauri/src/export/mod.rs:写清导出模块边界,重导出注册表原语,说明 .export 工作目录的 flat 约定与不进快照的后果。
- src-tauri/src/main.rs 注册 pub mod export;。
- 删除上一轮「共享命令目录」残留的空壳 src-tauri/src/export/command/,命令落点改为 per-target commands.rs。
- registry.rs 覆盖自动创建且重读指纹稳定、非法 JSON fail closed 不覆写、未知字段拒绝、保存返回新指纹四条单测。
- 新增 src-tauri/src/export/draft/xhs_minitool/dto.rs:XHSMiniToolExportForm / Field / State / RunResult 的线上形状;表单 deny_unknown_fields,TS 由 ts-rs 生成。
- 新增 error.rs:命令边界 typed 失败七变体(registryMalformed、formInvalid、buildScriptMissing、saveConflict、commandFailed、artifactMissing、exportUnavailable),带载荷变体持具名结构体,保证前端拿到可判别联合类型。
- 新增 layout.rs:.export/ 下 xhs-minitool.json 与 xhs-minitool.zip 的契约常量、npm 脚本名 build:xhs-minitool 与路径推导。
- 新增 validation.rs:名称与简介按 Unicode 字符数不超过 14 且非空,icon 必须是项目内普通文件、非符号链接、png/jpg/jpeg 且不超过 5 MiB,首个错误即返回。
- 改写 xhs_minitool/mod.rs 为模块声明与重导出,删除上一轮 xhx-* 草案常量与 xhx-minitool 拼写。
- 生成 src/view/project-development/export/generated/ 下 12 份 ts-rs 绑定。
- scripts/check-generated-bindings.mjs 把 export/generated 纳入 AGC 目标的覆盖目录。
- .prettierignore 增加 apps/ai-game-creator-shell/src/view/project-development/export/generated/,与其余四个 ts-rs 生成目录同口径:一律以原始输出提交,禁止 prettier 二次改写,否则生成绑定校验会误报内容变化。
- 重新生成 export/generated 下 12 份绑定,覆盖上一提交中被 prettier 改写过的内容。
- 新增 src-tauri/src/export/draft/xhs_minitool/build.rs:以既有 command.exec 边界运行项目声明的 build:xhs-minitool(复用 run_project_verification_with_commit_at,脚本白名单、expectedCommand 反漂移、沙箱与 300 秒超时都在那里),跑完确认 .export/xhs-minitool.zip 是非空普通文件,失败输出只回尾部 4000 字符。
- 新增 commands.rs:read_xhs_minitool_export / save_xhs_minitool_export_form / run_xhs_minitool_export_build 三个 per-target 命令;hasScript 每次现算,project_path 先过 validate_project_root,不拿项目写锁、不推进 revision。
- src-tauri/src/desktop.rs 把三个命令注册进 generate_handler!。
- xhs_minitool/mod.rs 收敛为模块声明,不再对外重导出内部类型。
- 实施计划把 XHSMiniToolExportRunResult 的字段名从 stderrTail 修正为 outputTail:输出是 stdout 与 stderr 合并清洗后的尾部。
- Rust 定向测试新增脚本缺失前置失败与输出截断两例。
- 新增 state/xhsMinitoolApi.ts:三个命令的 JS 入口(命令名与 camelCase 参数名唯一收口),结构化失败装成 XhsMinitoolFailure,真 Error 原样抛出。
- 新增 state/xhsMinitoolInstruction.ts:首次适配与按失败修复两段指令正文 + 契约常量(脚本名、产物路径、注册表形状、要显式拷贝的示例脚本与落点),每条都能在 Rust 侧找到对应硬校验。
- 新增 state/xhsMinitoolFailure.ts:七个失败变体各一句人话与下一步动作,穷尽性由 expectNever 在编译期钉住。
- 新增 state/xhsMinitoolFields.ts:三个字段的标签、占位与字数上限;字段身份直接用 ts-rs 的 XHSMiniToolExportField,与表单键一一对应。
- 新增 state/xhsMinitoolDownload.ts:icon / zip 经原生保存对话框落盘,复用素材保存命令的既有门禁。
- 新增 state/useXhsMinitoolExport.ts:读现场、防抖自动保存(带 baseHash)、字段级冲突、每次重新导出,以及只有用户显式点「适配 / 让 agent 修」才入队的指令发送。
- .eslintrc.cjs 把 export/generated 加入 ignorePatterns,与其余 ts-rs 生成目录同口径,禁止 eslint --fix 二次改写。
- 新增 tabs/xiaohongshu/ArtifactsPane.tsx:替换原来的留白占位,落平台表单、交付产物与「适配 / 导出 / 刷新」三颗按钮;没有脚本时导出不可点并说明要去适配。
- 新增 FormCard.tsx:三个字段都能复制,icon 行多一颗下载;红字是宿主校验结果的投影,前端不自己判规则。
- 新增 ConflictCard.tsx:只列真的不一样的字段,逐个二选一(默认「我的」),按选择合并后带回上层,绝不静默覆盖。
- 新增 FailureCard.tsx:宿主失败的原文加现场(输出尾部等),按变体给「让 code agent 修」或「重试」。
- 新增 PaneButton.tsx 与 CopyButton.tsx:按钮语气与复制反馈各收一处。
- Page.tsx / useXiaohongshuTab.ts / usePanel.ts 接线:导出状态挂在面板根,只有真的点进过小红书 tab 才打开注册表读写(进别的目标不在用户项目里补 .export/)。
- 新增 apps/ai-game-creator-shell/tests/xhsMinitoolExport.test.tsx:十例覆盖指令正文(三条硬契约、示例脚本落点、修复现场)、失败变体到人话与动作的映射、字段复制、icon 与 zip 的下载链路、三颗按钮的职责、冲突逐字段二选一、失败卡片下一步,以及状态 hook 的自动保存(baseHash 带回宿主)与「适配把指令当一条用户消息入队」。
- pack.mjs 新增 --zip-out <path>:相对当前工作目录解析、父目录自动创建,供「产物必须落在项目根 .export/ 下」的调用方指定落点;原 --zip <name> 默认行为不变。
- SKILL.md 增加「被 AGC 导出面板调用时」一节:三条硬契约(脚本名 build:xhs-minitool、非空 .export/xhs-minitool.zip、--out-dir 只指向构建输出目录)与拷贝到 .export/ 后如何定位项目根。
- vite.config.xhs-minitool.mjs 的注释点明 build.outDir 与 pack 的 --out-dir 必须一致,配错会删源码。
- manifest.json 同步 sha256 与版本 2026-08-26.41(文件清单不变,仍 36 个)。
- filesystem.rs 新增 PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS(当前只有 .export):导出注册表、打包脚本拷贝、icon 与 zip 产物都能从项目源码重跑出来,不进项目快照同步。
- 刻意不并入通用排除列表:那份列表同时是 Agent 的写入门禁(agent/direct_patch.rs 直接拿它拒绝路径,agc_apply_patch 报「不得修改受保护或排除路径」),并进去会让 code agent 写不了 .export/ 下的适配脚本。
- project_snapshot 测试补齐两侧口径:.export/* 必须被同步排除,且不得被通用口径排除。
- 里程碑:Status 改为 implemented-awaiting-runtime-acceptance,九条验收标准勾选,证据要求补已落的自动化证据(Rust export:: 18 例、bindings 117 个文件、前端 vitest 14 例、skill-pack 2026-08-26.41)并明确真实 vite 项目首轮适配是唯一未验证项。
- 实施计划:状态、前端文件落点(state/xhsMinitoolInstruction.ts 等)、pack.mjs 的 --zip-out、快照排除的两侧口径与提交清单逐项对齐实现。
- 主规范与决策记录:把「整个 .export/ 排除出快照」改为精确表述——只排除在快照同步之外,不得并进通用排除口径(那份列表同时是 Agent 的写入门禁,并进去 agc_apply_patch 就拒绝 .export/);skill 落点、prompt 归属与入队链路的文件/函数名同步为实际实现。
- build.rs 把「脚本跑完之后算不算数」抽成 conclude(root, exit_code, timed_out, output):非零退出与超时收成 commandFailed(带退出码与输出尾部),退出码 0 但产物不在或为空文件收成 artifactMissing,产物在才算成功。
- 补 5 例确定性用例覆盖这条判据(非零退出、超时无退出码、产物缺失、空产物不算、成功),不再只靠"真的跑一遍 npm"才能碰到这些分支。
- XHSMiniToolExportRunResult 去掉 exit_code:能走到成功出口的退出码必然是 0,带回来只是死字段;失败侧 CommandFailed 自己带退出码。成功时改为回构建输出尾部(打包脚本会把 zip 条目数与体积打在那里)。
- 同步重生成 XHSMiniToolExportRunResult.ts。
- useXhsMinitoolExport 的导出成功提示改为「已重新产出 .export/xhs-minitool.zip」加宿主的构建输出尾部:打包脚本会把 zip 的条目数与体积打在那里,正是上传前要核对的数字。
- ArtifactsPane 的状态行改为保留换行,多行输出不再挤成一行。
- 新增一例前端用例:导出调用只带 projectPath,成功后 notice 同时含产物路径与脚本输出尾部。
- 里程碑证据:Rust export:: 改为 49 例(export::draft::xhs_minitool 33 例)、export_bindings 115 例、前端 vitest 15 例,并把构建收尾判据的六条映射逐条列出(此前把「脚本非零退出/产物缺失」写成已有测试覆盖,实际只有代码分支,现补齐)。
- 实施计划:命令 DTO 口径改为 XHSMiniToolExportRunResult { outputTail } 并说明成功出口不带 exitCode 的理由;提交清单与已验证命令更新到最新;验收文案的「stderr 尾部」改为「输出尾部」(stdout 与 stderr 已合并)。
- build.rs 新增 executes_the_project_script_and_requires_a_non_empty_artifact_each_time(#[ignore]):造一个声明 build:xhs-minitool 的 npm 包,真跑一遍 run(),覆盖「脚本产出 zip 并回带 stdout → 删掉产物再跑必须重新产出 → 脚本成功但没产出报 artifactMissing」。常规单测里没有真实进程,这条链路此前只有"脚本缺失"这一侧被覆盖。
- 用例默认不跑:它要本机 node/npm 与可用命令沙箱。本次在本机尝试被容器环境挡下——沙箱里解析到的 npm 是 fnm 包装脚本、却由另一个 node 版本执行(Cannot find module '../lib/cli.js',Node.js v26.10.0);同一脚本在普通 shell 里 npm run build:xhs-minitool 正常产出 zip,因此不是代码问题。
- 实施计划与里程碑记录该用例的一键复跑命令、观察到的环境现象,并把「真实 vite 项目首轮适配」明确为本里程碑唯一开口项。
- 适配与修复指令的产物契约补一句:路径相对项目根,而 npm 包根通常是 game/ 子目录,所以落点参数要写成 ../.export/xhs-minitool.zip(相对路径按脚本的工作目录解析)。缺这句时 agent 会把 zip 写到 game/.export/ 下,宿主只能报产物缺失,白跑一轮修复。
- 两例前端用例各加一条断言钉住这个落点。
- skill 的 AGC 契约不再给出 <项目根>/.export/xhs-minitool.zip 这个只在包根等于项目根时才成立的写法,改为只声明产物位置并把相对路径的解析规则指回 `node pack.mjs --help`;manifest 同步到 2026-08-26.42。
- xhsMinitoolDownload 自己从 relativePath 取最后一段当默认文件名(取不到才用调用方给的兜底名),参数名随之改为 fallbackFileName;/ 与 \ 两种分隔符统一交给既有的 resourceFileNameFromPath,不再在面板里写第二份取文件名实现。
- ArtifactsPane 只传兜底名,不再自己拼默认文件名,视图层也就不必跨到 features/resource-canvas 去 import。
- 说明子进程输出里的 running 1 test 是命令沙箱垫片的预期现象:垫片就是当前可执行文件,编译到测试态时参数换成 --exact ...trampoline_child_fixture,所以垫片进程是测试二进制在跑那个 fixture 用例。
- 真正失败的是沙箱里解析到的 npm(fnm 包装脚本被另一个 node 版本执行),并写明同一脚本在普通 shell 里能正常产出 zip,避免后人把它当成产品缺陷。
- load() 在读盘前就把 dirty 归零:原来要等读回来的那一刻才归零,若这次读得比停止输入的 600ms 还慢,等待中的自动保存会先到点,把用户手里那份旧值写回注册表,随后刷新又用读到的内容盖掉界面,两边都不一致。
- 新增一例回归用例:第二次读(点刷新那次)故意慢 1200ms,越过自动保存的延时后断言没有发出 save_xhs_minitool_export_form,且界面回到磁盘上的值。已验证去掉修复后这例失败。
- 实施计划补 1b7741ac6 / f8ed4e898 / 90f651ddf 三条提交,前端 vitest 口径改为 16 例(新增 12 + 既有 4)。
- 里程碑把前端 12 例覆盖的内容逐项列出,便于验收时对照。
- 未适配提示从一句话改成一张卡片:说明和「交给 code agent 适配」那颗按钮放在一起,用户不用按照提示去别处找按钮;按钮行里就不再重复一颗,同一屏同一件事只有一个入口。
- 这条提示的判据补上 form 与 failure:hasScript 初值是 false,注册表还没读回来(或读失败)时不能替项目下「还没适配」的结论;失败卡片带着宿主的现场和同一颗按钮,两张卡一起出现就是同一件事两个入口。
- 失败变体的 action 从两向扩成三向 adapt / repair / retry:buildScriptMissing 归 adapt(首次适配该发适配指令,原来发修复指令会让 agent 去读一份还不存在的适配说明),commandFailed / artifactMissing / registryMalformed 归 repair,其余仍是 retry。
- 前端用例 12 → 14:钉住「未适配时按钮行里没有适配按钮、卡片那颗只调 adapt」「读回来之前不下结论、读失败时保留按钮行的适配入口」,并把失败卡片用例扩成适配 / 修 / 重试三种变体。
- 主规范:说明未适配结论只在注册表读回来之后下、提示卡片自带入队按钮、失败卡片按 action 分派适配/修/重试,同一时刻只有一张卡片一个入口。
- 实施计划与里程碑:补提交、前端 vitest 口径改为 18 例(新增 14 + 既有 4),并把 14 例覆盖到的内容逐项列出。
- read_xhs_minitool_export 只回内容(form + hasScript),新增 read_xhs_minitool_export_hash 单独回注册表指纹;save_xhs_minitool_export_form 成功后回新的指纹。
- XHSMiniToolExportState 去掉 contentHash:它是写回时的同步细节,混在「面板渲染的内容」里会让自动刷新顺手换掉写回基线,把两次刷新之间的外部改动认成自己的基线、静默吞掉冲突。
- 分两条命令之后,刷新这条高频路径在类型上就碰不到基线;指纹只在进编辑会话或重读到的内容真的被采纳时取一次。
- 待办标注:这条命令切分也让「面板不再显示任何同步状态」在类型上成立(前端不必拿到指纹就能渲染)。
- 面板只剩「适配 / 导出」两颗显式按钮:脚本判据与内容每 2 秒自动重读一次(窗口在后台时跳过),agent 回合结束后导出按钮自己亮起来,用户不用先点刷新再核对状态。
- 自动重读把两条事实分开:hasScript 是宿主的现算事实,任何时刻都采纳;表单是用户的编辑对象,只有用户手上没有未保存输入(也不在冲突里)时才覆盖,否则只更新 hasScript,绝不覆盖正在打的字。
- 只有重读到的内容真的变了才去取指纹:指纹与内容必须配套,取早了会把外部改动认成自己的基线(改动前是「刷新以磁盘为准、顺手撤掉待保存输入」,那条路径连同它的回归用例一并消失,改为「轮询不撤掉待保存的输入」)。
- 同步细节退出对外状态与界面:contentHash、saving、dirty、load 都不再对外,面板也不再显示「保存中 / 改动会在停手后自动保存」。
- 前端用例 14 → 15:改为钉「指纹与内容分两条命令、保存带回读到的 baseHash」「用户有未保存输入时轮询只更新脚本判据、不动表单(去掉该判据即失败)」「agent 事后改注册表或加脚本,轮询自动带回来」。
- 主规范:四条命令与内容/指纹的切分理由、自动重读的两条采纳规则(hasScript 随时采纳、表单只在用户没在编辑时采纳)、指纹不进对外状态、验收项补「自动重读不覆盖未保存输入」。
- 实施计划与里程碑:命令清单改 4 条、面板改两颗按钮、运行时验收去掉「点刷新」一步、前端 vitest 口径 19 例(新增 15 + 既有 4),并说明刷新撤掉待保存输入那条行为已被取代。
- 指令正文不再写死任何契约字符串:工作目录、产物、注册表、三个脚本落点全从常量组合(原先 .export/xhs-minitool.pack.mjs 在正文里硬编码了三处,常量形同注释)。
- 前端用例不再抄一份字面量:期望值一律从契约常量推——拷贝清单改成遍历 XHS_MINITOOL_COPIED_SCRIPTS(漏列一条就红),game/ 落点写成 ../${ARTIFACT},下载相对路径、打包输出、提示匹配器同理。
- 新增 tests/xhsMinitoolContract.test.ts:读 Rust 的 export/mod.rs 与 draft/xhs_minitool/layout.rs,逐条要求前端常量等于权威值。副本没有校验就是会漂移的注释——改 Rust 漏改前端时,两边的用例原本各自都还绿。
- 两边都验过钉得住:把 Rust 的 ARTIFACT_FILE_NAME 改成 xhs-minitool-v2.zip、把前端 EXPORT_WORK_RELATIVE_DIR 改成 .exports,这条用例各自报出具体哪个常量对不上。
- ts-rs 不能绑 const 的结论在这里落成实际方案:值只由 Rust 说,前端副本的存在性由契约用例说,正文有没有用上常量由指令用例说。
- 实施计划:补「Rust 是权威、前端副本由 xhsMinitoolContract 钉住」这条边界,前端 vitest 口径 21 例(新增 15 + 契约 2 + 既有 4),并说明指令正文与用例的期望值都从常量组合。
- 里程碑:证据里加 tests/xhsMinitoolContract.test.ts 这条(读 layout.rs / export/mod.rs 逐条比对)。
- 权限点位改用 typed 的 enforce_project_permission_policy_rejection:Denied 映射成新变体 commandDenied,PolicyUnavailable 仍映射 exportUnavailable,调用方才有「该不该上报」的分流依据
- CommandFailed 与 XHSMiniToolExportRunResult 增加 omittedCharacters;tail() 只回尾部原文,不再由宿主拼「省略前 N 个字符」这句用户可见文案
- 同步 ts-rs 绑定:新增 CommandDenied.ts,生成文件 117 → 118
- 新增 state/xhsMinitoolOutputTail.ts:宿主只回尾部原文与省略量,「已省略前 N 个字符」这句话在前端拼,失败卡片与成功提示共用
- xhsMinitoolFailure.ts 接住新变体 commandDenied(策略拒绝是预期拒绝,句子在前端拼),commandFailed 的现场改走尾部说明
- useXhsMinitoolExport 的三处 catch:认不出形状的拒绝与 exportUnavailable 先给现场再原样抛出进错误池,按指纹去重(面板 2 秒一轮重读,不会把报告池 count 刷成轮询次数),不再把裸 message 当业务提示
- CopyButton 改用 Tauri 剪贴板插件并显示失败态:原来的 navigator.clipboard 在 WebView 里可能根本没有、失败还被吞掉
- 用例 18 → 19 例:省略说明由前端拼、未分类拒绝原样抛出、宿主故障先给卡片再抛一次、复制失败可见
- decision-log 新增一条:同步细节不进对外状态(内容与指纹两条命令)、自动重读取代刷新按钮、失败通道按 ADR 两道口子分流、宿主不预拼用户可见文案、契约常量以 Rust 为唯一权威并用跨语言测试钉住;顺带修掉上一条里「只有 3 个 per-target 命令」的过时说法
- 主规范导出一节补失败通道与文案归属;README 的状态从「未实现」改成已实现待运行时验收
- 里程碑与实施计划的证据口径同步:export:: 50 例(xhs_minitool 34 例)、export_bindings 116 例、生成文件 118、前端 25 例(19 + 契约 2 + 既有 4);记下本机 check:rust:shell 唯一失败是 4 个 process_session 真 PTY 用例(既有环境噪声),并补上 dffe4de55 / df3a6826b 两条提交
- 原来的 artifact_relative_path_stays_inside_the_export_directory 断言的是 format!("{EXPORT_WORK_RELATIVE_DIR}/{ARTIFACT_FILE_NAME}") 本身,只重复实现、挡不住任何真实改动
- 改成:前端字符串相对路径与宿主 PathBuf 必须指向同一文件;相对路径必须项目内、单层、无 .. 且不出现反斜杠(跨平台的线上字符串);注册表与产物共用一个项目根锚定的 flat 目录;脚本名保住 build:<后缀> 形式且不许退化成裸 build(否则跑掉的是项目自己的构建)
- 逐条反证:把产物路径改成 .export/xhs-minitool/ 子目录、把 export_dir 挪进子目录、把 SCRIPT_NAME 改成 build,对应用例分别变红;export:: 50 → 53 例
- getBy* / findBy* 找不到元素就抛,外面那层 expect(...).not.toBeNull() 永远不会失败:删掉它,等待出现改用 findBy*,需要对照的用 queryBy* + toBeNull()
- 能写成行为的就别写成存在:有脚本时点按钮行的「适配」看 adapt 是否被调用;读失败时同样点一下证明入口没变成摆设;切 tab 后补一条「卡片没有重新长回来」的负向断言
- artifactsPanel 三个目标改用 role=button(可点入口,不是三行说明文字),保留 querySelector 那几条(它们真的会返回 null)
- team-conventions 记下这条断言口径,并给「不建立固定频率轮询」补上导出面板对 .export/ 的显式例外(那两件事实没有事件源,只能现读)
- 四个用例里三个是「元素渲染出来了」:三个目标卡片、切 tab 后的文案、tablist 存在;关闭按钮只是把 onClose 转发一次
- 唯一有内容的那条「挂载的是主聊天同一个 .project-chat-surface」已由 chatDialogFrameLayout.test.ts 覆盖,不是唯一防线
- 面板真实行为(表单、冲突、失败卡片、自动重读、入队)由 xhsMinitoolExport.test.tsx 覆盖;前端 vitest 25 → 21 例,里程碑与实施计划的证据口径同步
- 启动恢复登录态前先读取落盘的服务器选择,用自定义 origin 调用 read_client_auth_state
- 删除与认证恢复竞态的独立服务器选择水合 effect,登录表单状态改由认证恢复链路统一设置
- 新增回归测试,断言自定义服务器会话恢复提交的 expectedApiBaseUrl 不再落到渠道默认地址
- 新增 useTaonierTab:接管试玩包导出、发布灰度、构建进度与阻断反馈、发布资料面板开关,状态挂在导出面板根上,切 tab 不丢
- usePanel 接入 taonier slice,TAB_PAGES 把 taonier state 交给 TaonierPage
- 重写 tabs/taonier/Page.tsx:渲染「发布到游戏广场」入口,并按 state 挂发布资料面板与进度/阻断弹窗
- useDirectProjectManifest 额外返回完整 manifest,供陶泥儿 tab 复用
- App.tsx 移除发布相关 state、灰度 effect、requestGamePublish、发布面板与两条弹窗的挂载,以及 export_local_project_package invoke
- 移除 DirectProjectChatHeader 的「发布到游戏广场」按钮,并删掉 DirectProjectChatView / DirectProjectChatBox 的 onRequestGamePublish 透传
- gamePublishFeedback 用例改为从导出面板陶泥儿 tab 进入发布;directProjectChatHeader 用例改为覆盖导出入口与「不再有发布入口」
- 同步权威合同文档:发布入口位置由聊天头改为导出产物面板陶泥儿 tab
- `XHSMiniToolExportError` 一个大枚举拆成读 / 存 / 构建三份,每条命令只承载自己出得了的变体;
- 三条命令的返回类型跟着换成本命令那份,策略拒绝(`commandDenied`)与宿主故障(`exportUnavailable`)在各自主语里分开;
- 关键分支补 `app_log!`:命令入口、策略拒绝、脚本非零退出、产物缺失、注册表坏都留一行现场,出错时不必只靠前端转述;
- 重新生成 ts-rs 绑定:删掉 `XHSMiniToolExportError.ts`,新增 `XHSMiniToolExport{Read,Save,Build}Error.ts`。
- `xhsMinitoolApi` / `xhsMinitoolFailure` 改成读三份载体,`expectNever` 钉死穷尽性,仍不对任何文案做判断;
- 失败卡片与冲突面板按变体分派按钮,文案改成用户看得懂的说法(注册表 → 这份导出信息、文件里的 → 项目里的);
- 输出尾部与另存为的句子不再出现实现词,复制按钮的成功 / 失败仍是按钮自己说。
- `usePanel` 的注册表开关改成「进过小红书 tab」或「当前目标就是小红书」两个条件取或:从 tab 条切过来的路径原本既不开开关、也不发生一次文件访问,面板于是永远等不到第一次读取;
- 两条入口(点目标大卡、点 tab 条)合并到同一个 `enterTarget`,不再各写一份;
- `visited` 单独留着,是为了离开 tab 之后仍保有开关,表单自动保存的 600ms 窗口不被切 tab 掐掉;
- 新增 `tests/xhsMinitoolPanelTargets.test.tsx`,三条入口各钉一条。
- 「打包」不再因为没有脚本判据就变灰:有没有脚本是点下去那一刻才成立的事实,灰着等于把判断推给用户,而他手上没有办法核对;
- 点下去先现算一次,没有脚本就把适配弹窗递过去(`AdaptPromptDialog`),两条出路摆在一起:让陶泥儿调通 / 先放着;
- 面板读不到导出信息时不拿空表单糊弄,读失败与读取中分开显示,并照旧每 2 秒重试;
- `PaneButton` 增加 `brand` 语气与 `hero` 尺寸,打包那颗按钮整行宽、小红书红,是这一页唯一的主行动。
- 表单标题行加「帮我填」:先把用户手上没保存的输入落盘(落盘就是这次自动保存),再把改注册表的指令交给同一个项目会话,改完由每 2 秒的自动重读带回界面;
- 指令正文只给整份 `.export/xhs-minitool.json` 的形状示意,值的位置写每一项的要求;不重复当前值、不写项目根——agent 自己会读文件、本来就工作在项目根里;
- 示意类型钉在 ts-rs 生成的注册表类型上,`XHSMiniToolExportRegistry` 补 ts-rs 导出:Rust 侧加键、改名,前端这份示意会在 typecheck 里当场对不上;
- 图标一格去掉手填入口与空态提示,路径不外露,左边缩略图放大到 24,没选图时不摆一行废话;
- 新增 `ICON_IMPORTER_SETTINGS`:本地项目与云端素材库都能选,单张、png/jpg/jpeg、≤5 MiB,与宿主 `validate_icon` 对齐。
- `xhsMinitoolExport`:删掉对生成文案的恒真断言(`toContain('…')` 那批)与只为它们存在的用例,改成行为断言与 IPC 调用断言;
- 新增「帮我填」两条:落盘一定发生在把指令交给 agent 之前(顺序用调用表钉住)、表单不合法也照样交出去(agent 正是来收拾这份表单的);
- 打包那颗按钮的用例按新行为改:没有脚本时点下去要开适配弹窗,而不是变灰;
- `xhsMinitoolContract` 只留一条:工作目录、脚本名、注册表与产物路径与 Rust 权威逐条一致。
- `validate.mjs` 新增 `findUnsupportedFiles`:只挑出产物目录里白名单之外的文件,**不修改磁盘**;
- `pack.mjs` 改成先预检再动手,发现不支持的类型就整体失败并列出相对路径,不再像旧实现那样就地删除(指向源码目录时会静默删掉用户代码);
- `SKILL.md` 把目标、假设与默认项重写成一页能直接照做的说明,去掉「被 AGC 导出面板调用时」那三条宿主契约;
- 同步 `manifest.json` 指纹(version=2026-08-26.44)——之前脚本改了但指纹没跟上,宿主启动即报「内置 AGC Skill vite-export-xhs-minitool 内容指纹不匹配」。
- 删两份 ADR:`AGC命令错误结构化与错误报告口径`、`AGC认证失败的JS侧载体与抛出时机`;错误通道的现行口径只留在代码与该专题技术方案里;
- 删导出面板的【实施计划】与【里程碑】两份计划,落地情况回到技术方案里一句话;
- `docs/README.md` 去掉对上述四份的链接,技术方案里的失败通道段落跟着删;
- `decision-log` 去掉 2026-10-01 那一段,2026-10-05 那段的标题与四条决策改成「同步细节与文案归属」;`pitfalls` 去掉两份 ADR 的引用。
- `SKILL.md` 的 vite 项目目录假设写的是 `games/`,实际是 `game/`;
- 默认参数都按「cwd 就是 vite 项目根」给,非标准目录结构要显式指 `--vite-built-dir`;
- `pack.mjs --help` 里 `--skip-validate` / `--no-strict` 原先只在用法行里出现、没有说明,补上;
- `SKILL.md` 新增「脚本参数」一节,列出三个脚本各自的参数(与 `--help` 里同一份);
- 同步 manifest 指纹(version=2026-08-26.46)。
- `SKILL.md` 的 vite 项目目录假设写的是 `games/`,实际是 `game/`;默认参数都按「cwd 就是 vite 项目根」给,非标准目录结构用 `--vite-built-dir` 指全路径;
- `pack.mjs` 删掉打包后调用 `validate.mjs` 的那一步,连带 `--skip-validate` / `--no-strict`:校验归 `validate.mjs` 与项目构建脚本,pack 只管整理产物、写 zip、按体积门禁审计;
- `pack.mjs` 删掉 `--zip` 与它专用的 `readPackageName()`(默认文件名):落点统一由 `--zip-out` 指定;`--vite-built-dir` 保留;
- 参数解析改成「只认 `--vite-built-dir` / `--zip-out`」:不认识的参数、缺值、缺 `--zip-out` 都当场打印用法并退出 2,打包本身失败仍退出 1,不再有静默退回默认目录的路径;
- `SKILL.md` 新增「脚本参数」一节,列出三个脚本各自的参数;
- `pack.mjs` 的用例改成「CLI 拒绝不认识的参数,且不写出 zip」;
- 同步 manifest 指纹(version=2026-08-26.49)。
- 「假设和默认项」合并成一条:各工具(含示例 vite 配置)的默认参数都按「cwd 就是 vite 项目根」给,非标准目录结构用显式参数适应;
- 「脚本参数」表去掉多余的引导句、对齐列宽,三个脚本的参数不变;
- 同步 manifest 指纹(version=2026-08-26.50)。
- `command.exec` 在 sandbox-ready 失败时先取走子进程 stdout/stderr,再终止受控进程组,避免 `Child` 回收时丢掉 bwrap/trampoline 的真实报错;
- 采集结果在有界时间(2s)和字节(8 KiB/流)内读空;新增 `sanitize_diagnostic_message_preserving_paths`、`append_application_log_line_preserving_paths` 与 `app_log_with_paths!`,只做凭据脱敏、保留绝对路径(bwrap `Can't find source path` 的路径就是唯一证据),写入宿主 `application.log`;
- 默认 `sanitize_diagnostic_message` 仍整行脱敏绝对路径,新增项按 `target_os = "linux"` 门控;诊断只进宿主诊断包,不进入模型可见错误、command log、receipt 或 Agent DB;
- 新增 `sandbox_launch_diagnostics_keep_source_paths_and_redact_secrets`,覆盖源路径保留、凭据脱敏与空白流不产出行;
- `pitfalls.md` 记录 sandbox 启动失败丢弃子进程 stderr 的排障经验。
- 回退 6311bb583:移除 sandbox 启动失败时采集子进程 stdout/stderr 的宿主日志及保留绝对路径的变体;
- application.log 恢复对所有行统一脱敏绝对路径的既有行为;
- 真实 npm 启动故障改从宿主 Node 环境修复,不改日志代码。
- 一键适配、帮我填不再铺一句「已让陶泥儿帮你调通导出 / 来填这三项」:这两个动作就是用户刚点的那颗按钮,右侧会话就摆在旁边,复述只是噪音;
- 打包现算发现没有脚本时,只把适配弹窗重新武装起来,状态行不再重复「项目还没配置好导出…」;
- 失败修复的回执只留出错原因,去掉「已让陶泥儿来修。」这句叙述(失败卡片收掉后,原因仍是唯一说明「刚才为什么开这一轮」的地方);
- `notice` 的语义写进注释:读不到内容、打包结果、指令没发出去、失败修复的原因;用户刚点的动作不回执;
- 用例跟着改:没脚本时 `notice` 为空。
- 失败现场从就地卡片改成阻断弹窗(`FailureDialog` 取代 `FailureCard`):左半本来就矮,卡片会被滚出视野,而失败是用户必须看见的东西;
- 弹窗按「谁有能力修」给按钮:项目还没适配给「让陶泥儿帮我调通」,适配过但这次没跑通给「让陶泥儿来修」,改不动的(权限策略拉黑 `command.exec`、宿主没跑起来)不给陶泥儿入口;每条都带「关闭」,关掉的现场记进 `dismissedFailure`,同一个现场不会因为下一次重读又跳回来——没有「重试」,关掉回面板点「打包」是同一件事;
- 一键适配也清掉失败现场:从「还没配置好导出」那条弹窗进来的就是同一个 `buildScriptMissing`,不清它弹窗关不上;
- 删掉通知行(那段 `role="status"`)与整个 `notice` 状态:保存产物、打包结果、入队结果都不再在导出面板里回执;读不到内容仍由那段占位文案交代,真故障仍走错误池;
- 保存产物不再返回「已保存到 …」:落点与结果都是用户在原生对话框里亲手给的,失败只留一条控制台痕迹;
- 输出尾部的拼句模块 `xhsMinitoolOutputTail.ts` 随之删除(唯一调用方就是那条通知);
- 用例跟着改:删掉截断拼句那条,失败相关改称弹窗并断言 `role="dialog"`,补一条「关掉同一个现场不再弹」。
- 新增 `xhsMinitoolArtifactPlugin`(`apply: 'build'` + `enforce: 'post'` 的 `closeBundle`):相对路径改写、去 `type="module"` / `crossorigin`、脚本移到 body 末尾、清空空目录、`copyPublicDir: false` 时的 icon 兜底都在构建收尾做完,dist 出来即合规;
- `pack.mjs` 只做白名单预检与打 zip,不再改写 dist:validate 看到的不再是「只有跑过 pack 才合规」的中间态;
- 新增 `.vite-config.test.mjs`:真跑一遍 `vite build` 断言上述收尾,并覆盖 icon 兜底、构建失败不留半成品 dist、`pruneEmptyDirs` 只删空目录;`.pack.test.mjs` 补断言 pack 不改写 index.html;
- SKILL.md 写清两段构建、以及「项目已有 vite.config 时要单独把插件加进 plugins」;`.selective_rule.txt` 记下这次职责归位的原因与验证口径;
- manifest 指纹同步(version=2026-08-26.51)。
- 隐藏测试 .vite-config.test.mjs 重命名为 .vite.config.xhs-minitool.test.mjs,与 pack.mjs → .pack.test.mjs、validate.mjs → .validate.test.mjs 的命名口径一致;
- .selective_rule.txt 去掉日期段落,把「二次清理」的条目并进 SKILL.md / zip-artifact-spec.md 对应条目,恢复为逐文件「删除与去处」清单;
- decision-log 补记 dist 收尾归 Vite 插件、pack 只读打 zip 的决策、失败语义与验证口径;
- skill-pack 指纹无需重算:本次改动均为隐藏文件与文档,manifest 仍为 2026-08-26.51。
- SKILL.md 回到精简版:删掉「构建分两段 / pack 只读 / 手动加 xhsMinitoolArtifactPlugin」这些正文说明,插件行为只写在 vite.config.xhs-minitool.mjs 注释里;
- defineMinitoolConfig 在 mergeConfig 之后按插件名去重再追加 xhsMinitoolArtifactPlugin:展开 minitoolBaseConfig 再覆盖 plugins 也挤不掉它,收尾插件固定排最后且只跑一次;
- 隐藏测试补一条:overrides 的插件与内置插件共存、不重复、收尾插件在最后;
- manifest 指纹同步(2026-08-26.53 → 2026-08-26.54)。
- manifest 指纹同步(2026-08-26.54 → 2026-08-26.55);
- SKILL.md 追加脚本配置复制说明,明确引入 `agc_install_skill_resource` 的操作指引。
- 新增内置 MCP 工具 agc_install_skill_resource(skillName/relativePath/destinationPath),宿主直接读 AGC_SKILL_PACK_FILES 已审核字节
- 组装成 agc_write_file 的 {path,content} 转发客户端工具桥,复用同一份合同、lease、项目写锁与保护面校验
- read/install 共用 skill_resource_relative_path_is_unsafe;模型自带正文无旁路,正文不过模型上下文,不依赖原生 cp 审批
- direct-tools.json 增补工具描述与 destinationPath,direct.json engineering 指引改用本工具复制 Skill 文件
- 新增两条 install_skill_resource 测试并登记工具目录;同步技术方案与 decision-log
- validate.mjs:scanJsSyntax 先 stripJsNoise 剥注释与字符串,`"#e8f4ff"` / `'#hit'` 不再误判为 ES2018
- validate.mjs:删除 MODERN_RUNTIME_API、CSS_MODERN_PATTERNS / CSS_MODERN_FEATURE 与 --strict,退出码只由 ERROR 决定
- pack.mjs:--zip-out 相对 cwd 且落在 <cwd>/.export/ 时打 workdir 警告,打印 cwd 与绝对落点
- SKILL.md:产物为项目根 .export/xhs-minitool.zip,game/ 子工程写 ../.export/...;参数表去掉 --strict
- 测试:增强层放行、JS 噪音不误报、真私有字段仍报、warning 也退出 0、workdir 预警
- manifest:vite-export-xhs-minitool 指纹与 version 同步到 2026-08-26.56
- decision-log.md:记录本次 validate/pack 收敛
AGC 小红书导出 SKILL:参数表去掉 defineMinitoolConfig 说明
Project CI / Backend tests (pull_request) Failing after 25s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m42s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m21s
Project CI / Repository checks (pull_request) Failing after 23s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m48s
Project CI / Frontend tests (pull_request) Successful in 3m8s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m17s
Project CI / Native shell tests (pull_request) Successful in 7m52s
30a0f05c11
- SKILL.md:vite 配置行只保留 build.outDir,删除「项目已有 vite.config 时用它合并」的误导说明(helper 仍留在配置代码里作为默认导出构造器)
- SKILL.md:同步当前排版(步骤 3 换行、pack 行说明收进步骤 3)
- manifest:vite-export-xhs-minitool 指纹与 version 同步到 2026-08-26.59
Author
Member
  • 1. scripts/check-generated-bindings.mjs:56(documentation·low)

    • 现状:文件头写「覆盖两套 crate、四个目录」,AGC 侧只列了 chat/generated + services/generated + features/ui-editor/types。
    • 问题:targets 实际是 5 个目录(shared 1 个 + AGC 4 个,含 export/generated);而第 75 行又写「五个生成目录」,头部与实现、与自身下游注释都矛盾。
    • 建议:把头部改为五个目录并补上 export/generated。
    • 已处理:按建议更新头部说明。commit 677c477f3
  • 2. apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs:504(performance·medium)

    • 现状:.export 只登记在(原)PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS,索引、checkpoint、git 检查走的是通用口径,看不到它。
    • 问题:索引把多 MB 的 zip 整份读进内存算 checksum;checkpoint 把派生文件复制进 .agent/checkpoints/.../files/;git_inspect 把 .export 当未跟踪文件、变成可提交内容。
    • 建议:在索引 / checkpoint / git 消费者上显式排除 .export,而不是只从同步路径排除;同时保留 Agent 的可读写(写入门禁不能一起拒)。
    • 已处理:新增 should_skip_project_derived_path(快照口径 + .export),索引、checkpoint 恢复与清单、git_inspect 两处过滤全部改用它;常量改名 PROJECT_DERIVED_EXCLUDED_COMPONENTS;project_snapshot 测试补断言——写入门禁仍放行 .export,索引 / checkpoint / 数据口径排除它。commit 065a193e4
  • 3. apps/ai-game-creator-shell/src/App.tsx:1763-1767(maintainability·low)

    • 现状:导出开关用真值判断 localProject?.projectPath || projectPath,面板 prop 用空值判断 ?? projectPath ?? null;两处判据不一致。
    • 问题:纯空白路径(例如异常 initial URL 带进来的)是真值,按钮会亮、面板会开;下游发布链路又用 Boolean(projectPath) / .trim() 当有效判据,会出现「能打开但用不了」的半开状态。
    • 建议:只解析一次裁剪后的路径,开关和 prop 共用,例如 (localProject?.projectPath ?? projectPath ?? '').trim() || null。
    • 已处理:新增 exportProjectPath,onRequestExport 与 ArtifactsPanel 的 projectPath 都用它(DirectProjectChatView 的 prop 保持原样,避免动聊天容器)。commit 411771af2
  • 4. apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs:46-49(bug·medium)

    • 现状:save 先 load_or_create 读当前内容、比较 base_hash,再调共享的 crate::export::save 无条件写回;比较与写入是两步,无锁。
    • 问题:两个并发写者拿着同一个陈旧 base_hash(用户保存 vs code agent 改 .export/xhs-minitool.json)都能通过比较,后一个 rename 静默盖掉前一个。
    • 建议:把 expected-hash 比较下沉进共享 save,或按项目文件串行化读改写。
    • 已处理(按你的决定:这个场景可接受,不重构):在 save 的读与写之间加注释,写明这是「用户手动触发、且明知 code agent 在改」的已知窗口,明确接受、不做 CAS;并写明不做 CAS 的成本原因(会改所有导出目标的写契约)。commit 158fae587
  • 5. apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs:154-155(maintainability·low)

    • 现状:log_failure 用 format!("{error:?}") 把完整 Debug 落进 app_log!,并原样存进 LAST_FAILURE 去重表。
    • 问题:CommandFailed 的 Debug 里带最多 4,000 字符的脚本输出尾部,一次失败就能把 AppData 日志撑大 4KB;去重表也长期留这份长字符串。
    • 建议:只记「变体名 + 关键字段」的有界摘要,而不是带用户输出的完整 Debug。
    • 已处理:改成落盘前经 bounded_for_log 按字符截到 512 并补省略号(保证不切坏 UTF-8),保留原有「同一失败只记一次」语义。commit 9722b4269
  • 6. apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs:31-34(performance·low)

    • 现状:三条读 / 存命令都是 async fn,但内部 read_content / read_content_hash / save_form 直接做同步文件 IO。
    • 问题:读命令每 2 秒被轮询一次,这些小块阻塞 IO 会占用 Tokio worker 线程。
    • 建议:包进 spawn_blocking(或异步 fs)。
    • 已处理:新增 offload,用 tokio::task::spawn_blocking 包住三个同步函数;JoinError 收口成 ExportUnavailable,走各命令既有失败表,不需要新失败变体 / 不需要改 ts-rs 绑定。commit 63b7ef366
  • 7. apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:148-154(bug·medium)

    • 现状:临时文件名是 .{name}.{pid}.tmp,同进程内所有并发写共用同一个临时文件。
    • 问题:前端自动保存的防抖 persist 与「打包」前的 flush 可能同时在写同一个注册表:一个任务会截断另一个正在写的临时文件,rename 也会互相抢(甚至移走半截内容)。
    • 建议:临时名必须每次写都不同(原子计数器 / 线程 id),或把同一注册表的读改写串行化。
    • 已处理:在 pid 之外加入进程内原子自增序号(.{name}.{pid}.{seq}.tmp)。串行化属于第 4 条,留给你。commit 32d77a0cc
  • 8. apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:67-69(bug·low)

    • 现状:fs::read_to_string 对非 UTF-8 字节返回 ErrorKind::InvalidData,落到 load_or_create 的通用 Io 分支。
    • 问题:字节损坏的注册表被报成 ExportUnavailable(宿主 / 路径故障),而契约上「内容不是期望形状」应该是 fail-closed 的 Malformed;这会把用户和 agent 往「查权限」方向带。
    • 建议:把 InvalidData 映射成 RegistryError::Malformed。
    • 已处理:新增 InvalidData 分支返回 Malformed,并补 rejects_non_utf8_content_as_malformed 用例。commit c9d2ed041
  • 9. apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:139-145(bug·low)

    • 现状:write_atomically 只对临时文件 sync_all,随后 rename 换名,但没有 fsync 父目录。
    • 问题:rename 只改目录条目;崩溃后数据虽然在磁盘上,目录条目可能还是旧的(甚至没有),注释里声称「已关掉崩溃窗口」并不成立。
    • 建议:rename 之后 fsync 父目录。
    • 已处理:rename 成功后 File::open(parent) 再 sync_all(Windows 打不开目录句柄,if let Ok 自然跳过)。commit 9c48db76b
  • 10. apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx:229(bug·low)

    • 现状:hydrateClientServerSelection() 在 withAuthCheckTimeout 起 15s 时钟之前被 await;它自己吞异常、不会 reject。
    • 问题:这次 read_workspace_preferences invoke 一旦卡住,认证 UI 会永远停在「刷新登录状态」,既无超时提示也无重试路径。
    • 建议:把它也用 withAuthCheckTimeout 围起来。
    • 已处理:包进 withAuthCheckTimeout(..., AUTH_CHECK_REQUEST_TIMEOUT_MS, '读取服务器偏好超时,请重试或重启客户端')。commit e96d38a01
  • 11. apps/ai-game-creator-shell/src/view/project-development/export/components/TargetTabs.tsx:29-30(other·low)

    • 现状:tab 条用了 role="tablist" / role="tab" / aria-selected,但导出目录里没有任何 role="tabpanel" / aria-controls / 方向键 / roving tabIndex。
    • 问题:读屏播报一个找不到面板的 tab;键盘不符合 tab 惯例。
    • 建议:二选一——(a) 补全 ARIA tab 模式;(b) 去掉 tablist / tab 角色,退回普通按钮。
    • 已处理(按你的决定做 b):去掉 tablist / tab 角色,容器改 role="group",选中态改 aria-current;Tab/Enter 行为不变。commit c76296061
  • 12. apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:127(security·low)

    • 现状:临时名完全可预测(file 名字 + pid),且用 fs::File::create 打开——它会跟随符号链接。
    • 问题:第三方项目可以预置指向项目外文件的同名链接(或本地攻击者抢跑),打开 / 保存注册表时会把那个外部文件截断成注册表 JSON。
    • 建议:临时名不可复用,并用 create_new(true)(O_EXCL)打开,遇到已存在条目(链接或残留)直接失败。
    • 已处理:改用 OpenOptions::new().write(true).create_new(true)。配合第 7 条的序号,正常路径不会误撞。commit 07cc0aa5f
  • 14. apps/ai-game-creator-shell/src/view/project-development/chat/components/DirectProjectChatHeader/DirectProjectChatHeader.tsx:31-38(bug·medium)

    • 现状:改名前的「发布到游戏广场」按钮带 disabled={busy};改成 onRequestExport 后这道门丢了。
    • 问题:DirectProject 回合在途时也能打开 / 启动导出,导出与回合的文件写入可能并发。
    • 建议:确认会争抢就恢复 disabled={busy}。
    • 已处理(按你确认的行为变更):给导出按钮恢复 disabled={busy};设置入口不受影响,禁用样式沿用现有 .project-chat-publish-trigger:disabled。commit 226a339ce
  • 15. apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:236-239(bug·high)

    • 现状:重置 effect 以 manifest?.projectId 为依赖,但只重置文本字段;cover / screenshots / uploadedAssetCacheRef / objectUrlsRef 会跨项目存活。
    • 问题:面板根不随项目切换卸载,于是为项目 A 上传的封面 / 截图可能跟着项目 B 的发布请求提交出去(给新游戏发错公开物料)。
    • 建议:在同一处重置媒体态,回收 object URL 并清空素材缓存。
    • 已处理:重置 effect 里清空 cover / screenshots / 上传缓存,并回收全部登记过的预览地址;抽出 revokeTrackedObjectUrls 供重置与卸载共用。commit 3061762aa
  • 16. apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:577-578(bug·low)

    • 现状:handlePackageAndPublish 里 pkg = await onEnsurePackage() 没有 try/catch。
    • 问题:视图用 void handlePackageAndPublish() 调用;回调一旦 reject 就是未处理的 promise rejection,用户只看到按钮弹回、没有任何失败说明,与文档承诺的「失败留在表单」不符(现有实现恰好自己吞错,但契约没保证)。
    • 建议:catch 住并把它送进表单错误出口。
    • 已处理:加 try/catch,异常走 reportError(...)。这里故意没用评审建议的 setError:新架构里左栏内联红字已退役,「发布提示」弹窗才是错误出口,reportError 才会驱动它。commit f4b1a6ad9
  • 17. apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:349-350(bug·low)

    • 现状:换封面、setCover(null) 移除封面、AI 生成覆盖,都没有释放上一张的 URL.createObjectURL 预览地址;只有截图删除和卸载会 revoke。
    • 问题:常驻的内联表单每换一次封面就泄漏一个 blob URL,直到卸载才回收。
    • 建议:替换 / 移除封面之前 revoke 上一张的预览地址。
    • 已处理:没有按评审在 handleCoverSelected 里单点打补丁,而是新增 previousCoverRef + 跟随 cover 的 effect,统一覆盖「换 / 移除 / AI 覆盖」三条路径;只回收确实登记在 objectUrlsRef 里的 blob 地址。commit 10ca2341a
  • 18. apps/ai-game-creator-shell/src/components/game-distribution/GameDistributionPublishFormView.tsx:118-122(maintainability·low)

    • 现状:简介 / 分类提示语是三层嵌套三元。
    • 问题:三态选路埋在 JSX 里,读的人要自己还原状态机。
    • 建议:抽 resolveMetadataHint(pending, ready) 或在 return 前先算好。
    • 已处理:新增模块级 resolveMetadataHint 纯函数。commit a3af8a60a
  • 19. apps/ai-game-creator-shell/src/components/game-distribution/GameDistributionPublishFormView.tsx:399-409(maintainability·low)

    • 现状:主行动按钮文案是五层嵌套三元(打包 / 上传 / 生成封面 / 上传截图 / 上传素材 / 常态)。
    • 问题:优先级关系只能靠缩进猜,改成 flat 判断很难。
    • 建议:抽 resolvePublishActionLabel(...)。
    • 已处理:新增模块级 resolvePublishActionLabel 纯函数(if/else 从上到下即优先级)。commit 2b8bcd68c
  • 20. apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs:79-83(bug·medium)

    • 现状:产物判据只看 .export/xhs-minitool.zip 是否存在且非空,不验证是不是这一次跑出来的。
    • 问题:上一次导出残留的 zip 会让「退出码 0 但什么都没写」的脚本被判成功,用户上传的是旧产物;集成测试甚至要手动 remove_file 才能让 no-op 用例失败。
    • 建议:启动脚本前 best-effort 删掉旧产物(忽略 NotFound),或记录本次开始时间并比较 mtime。
    • 已处理:run() 在跑脚本前删除旧产物;不存在则跳过,其它删除失败则 fail closed(留着旧产物继续判成功更糟)。conclude 仍是纯函数,原有单测不受影响。commit dc639d571
  • 21. apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs:81(maintainability·low)

    • 现状:std::fs::metadata 会跟随符号链接,与本模块其它地方(script.rs、validation.rs、resolve_local_project_path)的 fail-closed symlink_metadata 口径不一致。
    • 问题:指向任意非空文件的链接会被判成「已产出」,直到下载路径才因为拒收链接而报错,问题现场被推后。
    • 建议:改用 symlink_metadata 并拒绝链接 / 非普通文件。
    • 已处理:改用 symlink_metadata,并要求 is_file() && !is_symlink(),补 a_symlinked_artifact_does_not_count(仅 unix)用例。commit eee12b280
  • 22. apps/ai-game-creator-shell/src/view/project-development/export/tabs/common/PaneButton.tsx:30-35(maintainability·low)

    • 现状:语气类名用嵌套三元选。
    • 问题:加第四种语气要再嵌一层,也难看出全部映射。
    • 建议:按 variant 建查表。
    • 已处理:模块级 TONE_CLASS,const tone = TONE_CLASS[variant]。commit 761dced56
  • 23. apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts:203-208(bug·medium)

    • 现状:ensurePackage 的 await 回来后只检查 mountedRef.current。
    • 问题:面板跨项目切换不卸载,旧项目在途的 export_local_project_package 仍会把 setPackageResult / setProgress 写进当前面板,发布表单会消费错项目的包。
    • 建议:参照 useDirectProjectManifest.refresh,用 projectPathRef 把捕获的路径和当前路径对账。
    • 已处理:新增 projectPathRef 与 isCurrentProject(),成功与失败两条路径都先对账再写状态。commit 6c540e067
  • 24. apps/ai-game-creator-shell/src/view/project-development/export/tabs/common/PaneButton.tsx:36-41(maintainability·low)

    • 现状:尺寸类名同样用嵌套三元选。
    • 问题:评审说它「violates the no-nested-ternary rule」——这条不准确:.eslintrc.cjs 里并没有 no-nested-ternary 规则(我查过 rules 段)。可读性问题本身成立。
    • 建议:按 size 建查表。
    • 已处理:模块级 SIZING_CLASS,const sizing = SIZING_CLASS[size]。commit b77ebbc1b
  • 25. apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:189-194(bug·medium)

    • 现状:refresh 先 setForm(content.form) 再取指纹;内容读成功、指纹读失败时 baselineRef 留在旧值,而下一次轮询因 sameForm 早返回,指纹永远补不上。
    • 问题:之后保存带着陈旧(或空)baseHash,被宿主当成外部改动——要么假 saveConflict,要么字段恰好相同被静默吸收。
    • 建议:把基线标成 pending 并在后续轮询重读指纹。
    • 已处理:新增 hashPendingRef;指纹读失败置真并原样 rethrow(失败仍照常上报),早返回条件加 !needsHashRetry(hashPending && adoptable),下一次轮询跳过它把配套指纹补上,用户打字中(adoptable 为 false)仍不覆盖输入;保存命令的返回值直接落定基线并清 pending。补一条回归测试:指纹失败后重读补上,保存带回新 hash-2。commit fba3805af
  • 26. apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:344-352(maintainability·low)

    • 现状:runExport 由 hook 返回但生产侧无人调用(失败弹窗刻意没有重试按钮),只有 xhsMinitoolExport.test.tsx 在调;且它 setRunning(true) 前不查重入。
    • 问题:评审「dead code」的说法部分成立(生产侧确实没人用),但直接删会红掉多个测试用例。
    • 建议:要么连同测试一起退役,要么保留并补真正的重入 guard。
    • 已处理(按你的决定:整个删掉):删除 runExport 与返回项,buildOnce 现在只由 packageAll 调用(packageAll 自己持有 running 门);测试改用 packageAll() 驱动构建路径,删掉对应 mock 与断言。commit 91b664b66
  • 27. apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolFields.ts:47-52(maintainability·low)

    • 现状:XHS_MINITOOL_FIELD_LABELS 全仓没有任何 import,只被定义;标签又与 XHS_MINITOOL_FORM_FIELDS 重复。
    • 问题:两份标签会漂移,而且这份是死代码。
    • 建议:删掉,或从字段数组派生。
    • 已处理:按仓库「无现役调用方直接清理」的口径删除(评审给的派生写法也行,但没人用就不必再留一份导出)。commit 5a202b091
  • 28. apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolInstruction.ts:91(style·low)

    • 现状:「帮我填表单」指令里,${JSON.stringify(...)} 之后多一个逗号,输出成 JSON 块与下一条要点之间单独一行 ,。
    • 问题:不影响执行,但看起来像 JSON / Markdown 写坏了,可能带偏模型。
    • 建议:去掉逗号。
    • 已处理:删除尾随逗号。commit ee8ad27c2
  • 29. apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolDownload.ts:48-50(other·low)

    • 现状:saveXhsMinitoolFileToDisk 把 save_local_project_asset_file 的失败只用 console.warn 吞掉,写盘失败与用户取消在返回值上无法区分。
    • 问题:导出可能看起来「保存成功」其实没落盘。
    • 建议:让 helper 返回结果或接受 notice 回调,让下载按钮能报错。
    • 已处理(按你的决定):helper 返回 'saved' | 'cancelled' | 'failed';ArtifactsPane 在 'failed' 时于表单上方给一行可重试提示,成功与取消保持静默;补一条「宿主拒绝写盘时提示可见」测试。commit 7f9c686b3
  • 30. apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/FailureDialog.tsx:45-47(maintainability·low)

    • 现状:先用嵌套三元算出中文文案 '让陶泥儿帮我调通' | '让陶泥儿来修',后面又用 agentAction === '让陶泥儿帮我调通' ? onAdapt : onRepair 反查 handler。
    • 问题:文案一改,按钮就会静默接错动作(该调通时去修,或反之)。
    • 建议:把文案与 handler 一起算出来。
    • 已处理:agentAction 改为 { label, onClick },点击直接用 agentAction.onClick。commit 01b068dec
  • 31. apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/ConflictCard.tsx:116-122(other·low)

    • 现状:同一字段的两个 radio 没有 name,只靠受控 checked 工作。
    • 问题:原生单选组不成立,方向键在选项间移动、读屏分组播报都会退化。
    • 建议:把字段身份作为 name 传进 Choice。
    • 已处理:Choice 新增 name prop 并透传给 input,同字段两个选项共用 meta.field。commit 433baadb4
  • 32. apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/FormCard.tsx:124-126(maintainability·low)

    • 现状:FieldRow 声明、解构并渲染 action?: ReactNode,但本文件没有任何调用方传它。
    • 问题:扩展点与 ReactNode 导入都是死重量,还会诱使后来者以为有现成插槽。
    • 建议:在有真实调用方之前删掉。
    • 已处理:移除 action prop、渲染分支与 ReactNode 导入。commit f27aface7
  • 33. apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts:92-97(bug·high)

    • 现状:packageResult / progress / blockedMessage 在 projectPath 变化时从不重置,而面板跨项目切换不卸载。
    • 问题:项目 A 的 packageResult 会活到项目 B;发布表单复用现成的 packageResult、不再调 onEnsurePackage,于是项目 B 可能被用项目 A 的 packageRelativePath 发布;旧项目的进度 / 阻断弹窗也会继续挂着。
    • 建议:加一个以 projectPath 为依赖的 effect 清掉这三项,和上面的灰度重置同一口径。
    • 已处理:新增对应 effect。它和第 23 条是配套的:只重置不足以挡住「旧请求晚到又写回来」,所以两条都要。commit abd27834d
  • 34. apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/ArtifactsPane.tsx:85-88(maintainability·medium)

    • 现状:左半顶部是 form ? <FormCard/> : !readSettled ? <p>正在读取…</p> : failure ? null : <p>没能读到…</p> 的四路链式三元。
    • 问题:三个分支形状差异大(整张表单 / 一行状态 / 什么都不放),控制流难读。
    • 建议:在 return 之前用 if/else 算好 formSlot,JSX 里只留 {formSlot}。
    • 已处理:抽出 formSlot(if / else if 四路),JSX 只剩一个插槽。
      注:这条原本因为该文件当时有你未提交的本地改动而打算留给你;你在 19:02 把它提交成 499b24723 之后工作区干净了,我就按建议补做了。commit 1897bf54d
  • 35. apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/CopyButton.tsx:30(style·low)

    • 现状:无障碍名是 ${text}${label},例如「已复制小工具名称」。
    • 问题:状态词与目标字段连读成一句,读屏用户分不清「已复制」和字段名。
    • 建议:中间加分隔符。
    • 已处理:改成 ${text} ${label},并同步更新 xhsMinitoolExport.test.tsx 里 6 处无障碍名断言(否则 3 个用例会红)。commit b9c0cd369
  • 36. apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:408-410(bug·medium)

    • 现状:createPanelScreenshotEntry 直接调 buildPanelImagePreviewUrl(file),不像封面路径那样 objectUrlsRef.current.add(previewUrl)。
    • 问题:removeScreenshot 里的 revoke 分支永远命中不了,卸载清理也只遍历 objectUrlsRef——截图 blob URL 会泄漏到页面关闭。
    • 建议:创建条目时登记 URL,让删除与卸载能和封面一致地回收。
    • 已处理:创建时 if (previewUrl) objectUrlsRef.current.add(previewUrl)。commit 49d6f8db2
  • 37. apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:189-194(bug·medium)

    • 现状:refresh 的早返回跳过了紧随其后的 setFailure(null);读来源的失败(registryMalformed / exportUnavailable)只有采纳表单时才会清。
    • 问题:注册表 / 宿主恢复、表单值又没变时,失败弹窗会一直卡在已经好了的现场上。
    • 建议:每次读成功都清掉读来源的失败(放在早返回之前),构建类失败仍交给下一次构建。
    • 已处理:在 setHasScript 之后用函数式更新 setFailure((previous) => ...) 只清 registryMalformed / exportUnavailable;用 previous 避开「读 failure 会闭包过期」,不必加 ref、也不用改 deps,构建类失败不受影响。补一条回归测试:读恢复后失败就地清掉(构造「表单值不变」的早返回路径,确保不是被构建顺带清掉的)。commit fba3805af
- [x] 1. `scripts/check-generated-bindings.mjs:56`(documentation·low) - 现状:文件头写「覆盖两套 crate、四个目录」,AGC 侧只列了 `chat/generated` + `services/generated` + `features/ui-editor/types`。 - 问题:`targets` 实际是 5 个目录(shared 1 个 + AGC 4 个,含 `export/generated`);而第 75 行又写「五个生成目录」,头部与实现、与自身下游注释都矛盾。 - 建议:把头部改为五个目录并补上 `export/generated`。 - 已处理:按建议更新头部说明。commit `677c477f3` - [x] 2. `apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs:504`(performance·medium) - 现状:`.export` 只登记在(原)`PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS`,索引、checkpoint、git 检查走的是通用口径,看不到它。 - 问题:索引把多 MB 的 zip 整份读进内存算 checksum;checkpoint 把派生文件复制进 `.agent/checkpoints/.../files/`;`git_inspect` 把 `.export` 当未跟踪文件、变成可提交内容。 - 建议:在索引 / checkpoint / git 消费者上显式排除 `.export`,而不是只从同步路径排除;同时保留 Agent 的可读写(写入门禁不能一起拒)。 - 已处理:新增 `should_skip_project_derived_path`(快照口径 + `.export`),索引、checkpoint 恢复与清单、`git_inspect` 两处过滤全部改用它;常量改名 `PROJECT_DERIVED_EXCLUDED_COMPONENTS`;`project_snapshot` 测试补断言——写入门禁仍放行 `.export`,索引 / checkpoint / 数据口径排除它。commit `065a193e4` - [x] 3. `apps/ai-game-creator-shell/src/App.tsx:1763-1767`(maintainability·low) - 现状:导出开关用真值判断 `localProject?.projectPath || projectPath`,面板 prop 用空值判断 `?? projectPath ?? null`;两处判据不一致。 - 问题:纯空白路径(例如异常 initial URL 带进来的)是真值,按钮会亮、面板会开;下游发布链路又用 `Boolean(projectPath)` / `.trim()` 当有效判据,会出现「能打开但用不了」的半开状态。 - 建议:只解析一次裁剪后的路径,开关和 prop 共用,例如 `(localProject?.projectPath ?? projectPath ?? '').trim() || null`。 - 已处理:新增 `exportProjectPath`,`onRequestExport` 与 `ArtifactsPanel` 的 `projectPath` 都用它(`DirectProjectChatView` 的 prop 保持原样,避免动聊天容器)。commit `411771af2` - [x] 4. `apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs:46-49`(bug·medium) - 现状:`save` 先 `load_or_create` 读当前内容、比较 `base_hash`,再调共享的 `crate::export::save` **无条件**写回;比较与写入是两步,无锁。 - 问题:两个并发写者拿着同一个陈旧 `base_hash`(用户保存 vs code agent 改 `.export/xhs-minitool.json`)都能通过比较,后一个 `rename` 静默盖掉前一个。 - 建议:把 expected-hash 比较下沉进共享 `save`,或按项目文件串行化读改写。 - 已处理(按你的决定:这个场景可接受,不重构):在 `save` 的读与写之间加注释,写明这是「用户手动触发、且明知 code agent 在改」的已知窗口,明确接受、不做 CAS;并写明不做 CAS 的成本原因(会改所有导出目标的写契约)。commit `158fae587` - [x] 5. `apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs:154-155`(maintainability·low) - 现状:`log_failure` 用 `format!("{error:?}")` 把完整 Debug 落进 `app_log!`,并原样存进 `LAST_FAILURE` 去重表。 - 问题:`CommandFailed` 的 Debug 里带最多 4,000 字符的脚本输出尾部,一次失败就能把 AppData 日志撑大 4KB;去重表也长期留这份长字符串。 - 建议:只记「变体名 + 关键字段」的有界摘要,而不是带用户输出的完整 Debug。 - 已处理:改成落盘前经 `bounded_for_log` 按**字符**截到 512 并补省略号(保证不切坏 UTF-8),保留原有「同一失败只记一次」语义。commit `9722b4269` - [x] 6. `apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs:31-34`(performance·low) - 现状:三条读 / 存命令都是 `async fn`,但内部 `read_content` / `read_content_hash` / `save_form` 直接做同步文件 IO。 - 问题:读命令每 2 秒被轮询一次,这些小块阻塞 IO 会占用 Tokio worker 线程。 - 建议:包进 `spawn_blocking`(或异步 fs)。 - 已处理:新增 `offload`,用 `tokio::task::spawn_blocking` 包住三个同步函数;`JoinError` 收口成 `ExportUnavailable`,走各命令既有失败表,**不需要新失败变体 / 不需要改 ts-rs 绑定**。commit `63b7ef366` - [x] 7. `apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:148-154`(bug·medium) - 现状:临时文件名是 `.{name}.{pid}.tmp`,同进程内所有并发写共用同一个临时文件。 - 问题:前端自动保存的防抖 `persist` 与「打包」前的 flush 可能同时在写同一个注册表:一个任务会截断另一个正在写的临时文件,`rename` 也会互相抢(甚至移走半截内容)。 - 建议:临时名必须每次写都不同(原子计数器 / 线程 id),或把同一注册表的读改写串行化。 - 已处理:在 pid 之外加入进程内原子自增序号(`.{name}.{pid}.{seq}.tmp`)。串行化属于第 4 条,留给你。commit `32d77a0cc` - [x] 8. `apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:67-69`(bug·low) - 现状:`fs::read_to_string` 对非 UTF-8 字节返回 `ErrorKind::InvalidData`,落到 `load_or_create` 的通用 `Io` 分支。 - 问题:字节损坏的注册表被报成 `ExportUnavailable`(宿主 / 路径故障),而契约上「内容不是期望形状」应该是 fail-closed 的 `Malformed`;这会把用户和 agent 往「查权限」方向带。 - 建议:把 `InvalidData` 映射成 `RegistryError::Malformed`。 - 已处理:新增 `InvalidData` 分支返回 `Malformed`,并补 `rejects_non_utf8_content_as_malformed` 用例。commit `c9d2ed041` - [x] 9. `apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:139-145`(bug·low) - 现状:`write_atomically` 只对临时文件 `sync_all`,随后 `rename` 换名,但没有 fsync 父目录。 - 问题:`rename` 只改目录条目;崩溃后数据虽然在磁盘上,目录条目可能还是旧的(甚至没有),注释里声称「已关掉崩溃窗口」并不成立。 - 建议:`rename` 之后 fsync 父目录。 - 已处理:`rename` 成功后 `File::open(parent)` 再 `sync_all`(Windows 打不开目录句柄,`if let Ok` 自然跳过)。commit `9c48db76b` - [x] 10. `apps/ai-game-creator-shell/src/app/AuthenticatedClient.tsx:229`(bug·low) - 现状:`hydrateClientServerSelection()` 在 `withAuthCheckTimeout` 起 15s 时钟之前被 await;它自己吞异常、不会 reject。 - 问题:这次 `read_workspace_preferences` invoke 一旦卡住,认证 UI 会永远停在「刷新登录状态」,既无超时提示也无重试路径。 - 建议:把它也用 `withAuthCheckTimeout` 围起来。 - 已处理:包进 `withAuthCheckTimeout(..., AUTH_CHECK_REQUEST_TIMEOUT_MS, '读取服务器偏好超时,请重试或重启客户端')`。commit `e96d38a01` - [x] 11. `apps/ai-game-creator-shell/src/view/project-development/export/components/TargetTabs.tsx:29-30`(other·low) - 现状:tab 条用了 `role="tablist"` / `role="tab"` / `aria-selected`,但导出目录里没有任何 `role="tabpanel"` / `aria-controls` / 方向键 / roving `tabIndex`。 - 问题:读屏播报一个找不到面板的 tab;键盘不符合 tab 惯例。 - 建议:二选一——(a) 补全 ARIA tab 模式;(b) 去掉 `tablist` / `tab` 角色,退回普通按钮。 - 已处理(按你的决定做 b):去掉 tablist / tab 角色,容器改 `role="group"`,选中态改 `aria-current`;Tab/Enter 行为不变。commit `c76296061` - [x] 12. `apps/ai-game-creator-shell/src-tauri/src/export/registry.rs:127`(security·low) - 现状:临时名完全可预测(`file` 名字 + pid),且用 `fs::File::create` 打开——它会跟随符号链接。 - 问题:第三方项目可以预置指向项目外文件的同名链接(或本地攻击者抢跑),打开 / 保存注册表时会把那个外部文件截断成注册表 JSON。 - 建议:临时名不可复用,并用 `create_new(true)`(O_EXCL)打开,遇到已存在条目(链接或残留)直接失败。 - 已处理:改用 `OpenOptions::new().write(true).create_new(true)`。配合第 7 条的序号,正常路径不会误撞。commit `07cc0aa5f` - [x] 14. `apps/ai-game-creator-shell/src/view/project-development/chat/components/DirectProjectChatHeader/DirectProjectChatHeader.tsx:31-38`(bug·medium) - 现状:改名前的「发布到游戏广场」按钮带 `disabled={busy}`;改成 `onRequestExport` 后这道门丢了。 - 问题:DirectProject 回合在途时也能打开 / 启动导出,导出与回合的文件写入可能并发。 - 建议:确认会争抢就恢复 `disabled={busy}`。 - 已处理(按你确认的行为变更):给导出按钮恢复 `disabled={busy}`;设置入口不受影响,禁用样式沿用现有 `.project-chat-publish-trigger:disabled`。commit `226a339ce` - [x] 15. `apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:236-239`(bug·high) - 现状:重置 effect 以 `manifest?.projectId` 为依赖,但只重置文本字段;`cover` / `screenshots` / `uploadedAssetCacheRef` / `objectUrlsRef` 会跨项目存活。 - 问题:面板根不随项目切换卸载,于是为项目 A 上传的封面 / 截图可能跟着项目 B 的发布请求提交出去(给新游戏发错公开物料)。 - 建议:在同一处重置媒体态,回收 object URL 并清空素材缓存。 - 已处理:重置 effect 里清空 `cover` / `screenshots` / 上传缓存,并回收全部登记过的预览地址;抽出 `revokeTrackedObjectUrls` 供重置与卸载共用。commit `3061762aa` - [x] 16. `apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:577-578`(bug·low) - 现状:`handlePackageAndPublish` 里 `pkg = await onEnsurePackage()` 没有 try/catch。 - 问题:视图用 `void handlePackageAndPublish()` 调用;回调一旦 reject 就是未处理的 promise rejection,用户只看到按钮弹回、没有任何失败说明,与文档承诺的「失败留在表单」不符(现有实现恰好自己吞错,但契约没保证)。 - 建议:catch 住并把它送进表单错误出口。 - 已处理:加 try/catch,异常走 `reportError(...)`。这里**故意没用**评审建议的 `setError`:新架构里左栏内联红字已退役,「发布提示」弹窗才是错误出口,`reportError` 才会驱动它。commit `f4b1a6ad9` - [x] 17. `apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:349-350`(bug·low) - 现状:换封面、`setCover(null)` 移除封面、AI 生成覆盖,都没有释放上一张的 `URL.createObjectURL` 预览地址;只有截图删除和卸载会 revoke。 - 问题:常驻的内联表单每换一次封面就泄漏一个 blob URL,直到卸载才回收。 - 建议:替换 / 移除封面之前 revoke 上一张的预览地址。 - 已处理:没有按评审在 `handleCoverSelected` 里单点打补丁,而是新增 `previousCoverRef` + 跟随 `cover` 的 effect,统一覆盖「换 / 移除 / AI 覆盖」三条路径;只回收确实登记在 `objectUrlsRef` 里的 blob 地址。commit `10ca2341a` - [x] 18. `apps/ai-game-creator-shell/src/components/game-distribution/GameDistributionPublishFormView.tsx:118-122`(maintainability·low) - 现状:简介 / 分类提示语是三层嵌套三元。 - 问题:三态选路埋在 JSX 里,读的人要自己还原状态机。 - 建议:抽 `resolveMetadataHint(pending, ready)` 或在 return 前先算好。 - 已处理:新增模块级 `resolveMetadataHint` 纯函数。commit `a3af8a60a` - [x] 19. `apps/ai-game-creator-shell/src/components/game-distribution/GameDistributionPublishFormView.tsx:399-409`(maintainability·low) - 现状:主行动按钮文案是五层嵌套三元(打包 / 上传 / 生成封面 / 上传截图 / 上传素材 / 常态)。 - 问题:优先级关系只能靠缩进猜,改成 flat 判断很难。 - 建议:抽 `resolvePublishActionLabel(...)`。 - 已处理:新增模块级 `resolvePublishActionLabel` 纯函数(if/else 从上到下即优先级)。commit `2b8bcd68c` - [x] 20. `apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs:79-83`(bug·medium) - 现状:产物判据只看 `.export/xhs-minitool.zip` 是否存在且非空,不验证是不是**这一次**跑出来的。 - 问题:上一次导出残留的 zip 会让「退出码 0 但什么都没写」的脚本被判成功,用户上传的是旧产物;集成测试甚至要手动 `remove_file` 才能让 no-op 用例失败。 - 建议:启动脚本前 best-effort 删掉旧产物(忽略 `NotFound`),或记录本次开始时间并比较 mtime。 - 已处理:`run()` 在跑脚本前删除旧产物;不存在则跳过,其它删除失败则 fail closed(留着旧产物继续判成功更糟)。`conclude` 仍是纯函数,原有单测不受影响。commit `dc639d571` - [x] 21. `apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs:81`(maintainability·low) - 现状:`std::fs::metadata` 会跟随符号链接,与本模块其它地方(`script.rs`、`validation.rs`、`resolve_local_project_path`)的 fail-closed `symlink_metadata` 口径不一致。 - 问题:指向任意非空文件的链接会被判成「已产出」,直到下载路径才因为拒收链接而报错,问题现场被推后。 - 建议:改用 `symlink_metadata` 并拒绝链接 / 非普通文件。 - 已处理:改用 `symlink_metadata`,并要求 `is_file() && !is_symlink()`,补 `a_symlinked_artifact_does_not_count`(仅 unix)用例。commit `eee12b280` - [x] 22. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/common/PaneButton.tsx:30-35`(maintainability·low) - 现状:语气类名用嵌套三元选。 - 问题:加第四种语气要再嵌一层,也难看出全部映射。 - 建议:按 `variant` 建查表。 - 已处理:模块级 `TONE_CLASS`,`const tone = TONE_CLASS[variant]`。commit `761dced56` - [x] 23. `apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts:203-208`(bug·medium) - 现状:`ensurePackage` 的 `await` 回来后只检查 `mountedRef.current`。 - 问题:面板跨项目切换不卸载,旧项目在途的 `export_local_project_package` 仍会把 `setPackageResult` / `setProgress` 写进当前面板,发布表单会消费错项目的包。 - 建议:参照 `useDirectProjectManifest.refresh`,用 `projectPathRef` 把捕获的路径和当前路径对账。 - 已处理:新增 `projectPathRef` 与 `isCurrentProject()`,成功与失败两条路径都先对账再写状态。commit `6c540e067` - [x] 24. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/common/PaneButton.tsx:36-41`(maintainability·low) - 现状:尺寸类名同样用嵌套三元选。 - 问题:评审说它「violates the no-nested-ternary rule」——**这条不准确**:`.eslintrc.cjs` 里并没有 `no-nested-ternary` 规则(我查过 rules 段)。可读性问题本身成立。 - 建议:按 `size` 建查表。 - 已处理:模块级 `SIZING_CLASS`,`const sizing = SIZING_CLASS[size]`。commit `b77ebbc1b` - [x] 25. `apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:189-194`(bug·medium) - 现状:`refresh` 先 `setForm(content.form)` 再取指纹;内容读成功、指纹读失败时 `baselineRef` 留在旧值,而下一次轮询因 `sameForm` 早返回,指纹永远补不上。 - 问题:之后保存带着陈旧(或空)`baseHash`,被宿主当成外部改动——要么假 `saveConflict`,要么字段恰好相同被静默吸收。 - 建议:把基线标成 pending 并在后续轮询重读指纹。 - 已处理:新增 `hashPendingRef`;指纹读失败置真并原样 rethrow(失败仍照常上报),早返回条件加 `!needsHashRetry`(`hashPending && adoptable`),下一次轮询跳过它把配套指纹补上,用户打字中(`adoptable` 为 false)仍不覆盖输入;保存命令的返回值直接落定基线并清 pending。补一条回归测试:指纹失败后重读补上,保存带回新 `hash-2`。commit `fba3805af` - [x] 26. `apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:344-352`(maintainability·low) - 现状:`runExport` 由 hook 返回但生产侧无人调用(失败弹窗刻意没有重试按钮),只有 `xhsMinitoolExport.test.tsx` 在调;且它 `setRunning(true)` 前不查重入。 - 问题:评审「dead code」的说法部分成立(生产侧确实没人用),但直接删会红掉多个测试用例。 - 建议:要么连同测试一起退役,要么保留并补真正的重入 guard。 - 已处理(按你的决定:整个删掉):删除 `runExport` 与返回项,`buildOnce` 现在只由 `packageAll` 调用(`packageAll` 自己持有 running 门);测试改用 `packageAll()` 驱动构建路径,删掉对应 mock 与断言。commit `91b664b66` - [x] 27. `apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolFields.ts:47-52`(maintainability·low) - 现状:`XHS_MINITOOL_FIELD_LABELS` 全仓没有任何 import,只被定义;标签又与 `XHS_MINITOOL_FORM_FIELDS` 重复。 - 问题:两份标签会漂移,而且这份是死代码。 - 建议:删掉,或从字段数组派生。 - 已处理:按仓库「无现役调用方直接清理」的口径删除(评审给的派生写法也行,但没人用就不必再留一份导出)。commit `5a202b091` - [x] 28. `apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolInstruction.ts:91`(style·low) - 现状:「帮我填表单」指令里,`${JSON.stringify(...)}` 之后多一个逗号,输出成 JSON 块与下一条要点之间单独一行 `,`。 - 问题:不影响执行,但看起来像 JSON / Markdown 写坏了,可能带偏模型。 - 建议:去掉逗号。 - 已处理:删除尾随逗号。commit `ee8ad27c2` - [x] 29. `apps/ai-game-creator-shell/src/view/project-development/export/state/xhsMinitoolDownload.ts:48-50`(other·low) - 现状:`saveXhsMinitoolFileToDisk` 把 `save_local_project_asset_file` 的失败只用 `console.warn` 吞掉,写盘失败与用户取消在返回值上无法区分。 - 问题:导出可能看起来「保存成功」其实没落盘。 - 建议:让 helper 返回结果或接受 notice 回调,让下载按钮能报错。 - 已处理(按你的决定):helper 返回 `'saved' | 'cancelled' | 'failed'`;`ArtifactsPane` 在 `'failed'` 时于表单上方给一行可重试提示,成功与取消保持静默;补一条「宿主拒绝写盘时提示可见」测试。commit `7f9c686b3` - [x] 30. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/FailureDialog.tsx:45-47`(maintainability·low) - 现状:先用嵌套三元算出中文文案 `'让陶泥儿帮我调通' | '让陶泥儿来修'`,后面又用 `agentAction === '让陶泥儿帮我调通' ? onAdapt : onRepair` 反查 handler。 - 问题:文案一改,按钮就会静默接错动作(该调通时去修,或反之)。 - 建议:把文案与 handler 一起算出来。 - 已处理:`agentAction` 改为 `{ label, onClick }`,点击直接用 `agentAction.onClick`。commit `01b068dec` - [x] 31. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/ConflictCard.tsx:116-122`(other·low) - 现状:同一字段的两个 radio 没有 `name`,只靠受控 `checked` 工作。 - 问题:原生单选组不成立,方向键在选项间移动、读屏分组播报都会退化。 - 建议:把字段身份作为 `name` 传进 `Choice`。 - 已处理:`Choice` 新增 `name` prop 并透传给 `input`,同字段两个选项共用 `meta.field`。commit `433baadb4` - [x] 32. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/FormCard.tsx:124-126`(maintainability·low) - 现状:`FieldRow` 声明、解构并渲染 `action?: ReactNode`,但本文件没有任何调用方传它。 - 问题:扩展点与 `ReactNode` 导入都是死重量,还会诱使后来者以为有现成插槽。 - 建议:在有真实调用方之前删掉。 - 已处理:移除 `action` prop、渲染分支与 `ReactNode` 导入。commit `f27aface7` - [x] 33. `apps/ai-game-creator-shell/src/view/project-development/export/state/useTaonierTab.ts:92-97`(bug·high) - 现状:`packageResult` / `progress` / `blockedMessage` 在 `projectPath` 变化时从不重置,而面板跨项目切换不卸载。 - 问题:项目 A 的 `packageResult` 会活到项目 B;发布表单复用现成的 `packageResult`、不再调 `onEnsurePackage`,于是项目 B 可能被用项目 A 的 `packageRelativePath` 发布;旧项目的进度 / 阻断弹窗也会继续挂着。 - 建议:加一个以 `projectPath` 为依赖的 effect 清掉这三项,和上面的灰度重置同一口径。 - 已处理:新增对应 effect。它和第 23 条是配套的:只重置不足以挡住「旧请求晚到又写回来」,所以两条都要。commit `abd27834d` - [x] 34. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/ArtifactsPane.tsx:85-88`(maintainability·medium) - 现状:左半顶部是 `form ? <FormCard/> : !readSettled ? <p>正在读取…</p> : failure ? null : <p>没能读到…</p>` 的四路链式三元。 - 问题:三个分支形状差异大(整张表单 / 一行状态 / 什么都不放),控制流难读。 - 建议:在 `return` 之前用 `if/else` 算好 `formSlot`,JSX 里只留 `{formSlot}`。 - 已处理:抽出 `formSlot`(`if / else if` 四路),JSX 只剩一个插槽。 注:这条原本因为该文件当时有你未提交的本地改动而打算留给你;你在 19:02 把它提交成 `499b24723` 之后工作区干净了,我就按建议补做了。commit `1897bf54d` - [x] 35. `apps/ai-game-creator-shell/src/view/project-development/export/tabs/xiaohongshu/CopyButton.tsx:30`(style·low) - 现状:无障碍名是 `${text}${label}`,例如「已复制小工具名称」。 - 问题:状态词与目标字段连读成一句,读屏用户分不清「已复制」和字段名。 - 建议:中间加分隔符。 - 已处理:改成 `${text} ${label}`,并同步更新 `xhsMinitoolExport.test.tsx` 里 6 处无障碍名断言(否则 3 个用例会红)。commit `b9c0cd369` - [x] 36. `apps/ai-game-creator-shell/src/components/game-distribution/useGameDistributionPublishForm.ts:408-410`(bug·medium) - 现状:`createPanelScreenshotEntry` 直接调 `buildPanelImagePreviewUrl(file)`,不像封面路径那样 `objectUrlsRef.current.add(previewUrl)`。 - 问题:`removeScreenshot` 里的 revoke 分支永远命中不了,卸载清理也只遍历 `objectUrlsRef`——截图 blob URL 会泄漏到页面关闭。 - 建议:创建条目时登记 URL,让删除与卸载能和封面一致地回收。 - 已处理:创建时 `if (previewUrl) objectUrlsRef.current.add(previewUrl)`。commit `49d6f8db2` - [x] 37. `apps/ai-game-creator-shell/src/view/project-development/export/state/useXhsMinitoolExport.ts:189-194`(bug·medium) - 现状:`refresh` 的早返回跳过了紧随其后的 `setFailure(null)`;读来源的失败(`registryMalformed` / `exportUnavailable`)只有采纳表单时才会清。 - 问题:注册表 / 宿主恢复、表单值又没变时,失败弹窗会一直卡在已经好了的现场上。 - 建议:每次读成功都清掉读来源的失败(放在早返回之前),构建类失败仍交给下一次构建。 - 已处理:在 `setHasScript` 之后用**函数式更新** `setFailure((previous) => ...)` 只清 `registryMalformed` / `exportUnavailable`;用 `previous` 避开「读 `failure` 会闭包过期」,不必加 ref、也不用改 deps,构建类失败不受影响。补一条回归测试:读恢复后失败就地清掉(构造「表单值不变」的早返回路径,确保不是被构建顺带清掉的)。commit `fba3805af`
k88936 added 49 commits 2026-10-06 20:02:00 +08:00
- pack.mjs:--zip-out 默认 ../.export/xhs-minitool.zip(假设 cwd 是 game/ 子工程,落到项目根 .export/),仍可显式覆盖;USAGE 同步
- SKILL.md:步骤 3 写明默认落点与 game/ 假设
- .pack.test.mjs:补默认落点用例(cwd=game/ 时 zip 落在项目根 .export/)
- manifest:vite-export-xhs-minitool 指纹与 version 同步到 2026-08-26.61
- 把 PaneButton 从 tabs/xiaohongshu 移到 tabs/common,供小红书与陶泥儿共用

- 新增 common/ChatPane,统一第二个会话 chatbox 的挂载与状态投影

- 小红书 chat Pane 改为委托 common/ChatPane,五个卡片组件导入路径同步更新
- 陶泥儿 tab 改为左右两栏:左半内联发布资料表单,右半第二个会话 chatbox

- 去掉「发布到游戏广场」二次跳转与弹窗表单,主行动改为内容末尾的橙色「打包并发布」

- 打包并发布一次点击先按需构建打包(沿用进度 / 阻断弹窗),成功后直接提交发布

- 抽出 useGameDistributionPublishForm 与 GameDistributionPublishFormView,弹窗与内联共用同一份表单

- 发布表单状态提升到面板根 useTaonierTab,切 tab 不丢已填资料;只在首次进入陶泥儿 tab 时初始化

- 同步更新发布反馈用例与玩法链路文档
- 「打包并发布」只在打包 / 上传进行中禁用,不再因为名称或简介为空而变灰

- 文案必填项在打包前就地校验,封面与在途上传在打包成功后校验,错误都留在表单里

- 简介兜底改用 ||,项目 goal 为空时不再留下空简介把唯一入口卡死

- 用户一改名称 / 简介即清除上一次的校验错误

- 补「项目还没起名时按钮仍可点并给出必填提示」的回归用例
- validate.mjs 恢复 CSS_UNSUPPORTED_PATTERNS / MODERN_RUNTIME_API,命中判 ERROR
- 删除「基线层 + 增强层」写法,references 明确 Chrome 61 为硬基线
- pack.mjs 复制白名单与遍历实现,不再 import validate.mjs
- SKILL.md 参数表补 validate / pack / vite.config 的默认值
- 修正 decision-log 中与本次相反的旧结论
- SKILL.md 改为「何时读命中时必须读」
- zip-artifact-spec 行点名改源码硬约束:viewport-fit=cover、不用 base、不自建 CSP meta
- 流程里加一条:写/改 index.html 前先读 zip-artifact-spec §3/§5
- 同步 manifest 指纹(version=2026-08-26.63)
- zip-artifact-spec.md §5 删 viewport / <base> / CSP meta 三行(validate 已判 ERROR)
- SKILL.md 去掉对应的枚举,只保留「何时读命中时必须读」措辞
- .selective_rule.txt 记录删除项与对应的 validate 检查码
- 同步 manifest 指纹(version=2026-08-26.64)
- 表单必填项(名称 / 简介 / 封面 / 在途上传)在点击「打包并发布」时先于构建校验,不通过直接弹「发布提示」,不再先弹一次打包进度

- 表单错误统一经 onError 交给面板根已有的 GamePublishBlockedDialog,左栏不再铺内联红字

- 简介兜底改用默认文案,项目 goal 为空不再把入口卡死

- 补齐封面后打包的回归用例,新增「未选封面不打包、不出进度弹窗」用例
- 删除已无现役调用方的 GameDistributionPublishPanel,发布资料表单只保留内联形态

- useGameDistributionPublishForm 去掉 inline 开关与 handleSubmit,onError 改为必填

- GameDistributionPublishFormView 去掉弹窗分支与 open / onClose 入参,只渲染内联布局

- 原专属测试迁移到内联表单并改名为 gameDistributionPublishForm.test.tsx
- check-generated-bindings.mjs 文件头从「两套 crate、四个目录」更新为「五个目录」,补上 AGC export/generated
- App.tsx 新增 exportProjectPath,对 localProject/projectPath 做一次 trim,空白即视作无项目

- onRequestExport 开关与 ArtifactsPanel 的 projectPath 都改用该值,避免纯空白路径照开门
- registry.rs 的 temp_path 在 pid 之外加入进程内原子自增序号,同一注册表路径的并发写不再共用同一个 .tmp 文件
- registry.rs 的 load_or_create 单独处理 ErrorKind::InvalidData,返回 RegistryError::Malformed,不再落进通用 Io 被报成路径/权限故障

- 新增 rejects_non_utf8_content_as_malformed 用例
- registry.rs 的 write_atomically 在原子替换后同步父目录,崩溃时目录条目不再可能回退到旧文件
- registry.rs 的 write_atomically 不再用会跟随符号链接的 File::create,改用 O_EXCL 打开临时文件,已存在的链接/残留文件直接失败
- build.rs 的 run 在启动项目脚本前删除 .export/xhs-minitool.zip(不存在则跳过,删不掉则 fail closed)

- 避免 no-op 脚本靠上一轮残留的 zip 被判成功
- build.rs 的 conclude 不再跟随符号链接,链接与非普通文件不计入「已产出」

- 新增 a_symlinked_artifact_does_not_count 用例(仅 unix)
- commands.rs 的 log_failure 落盘前经 bounded_for_log 截到 512 字符,CommandFailed 的 4KB 脚本输出不再整段写进 AppData 日志与去重表

- 新增 bounded_for_log 的短文本与中文边界用例
- AuthenticatedClient 的 hydrateClientServerSelection 改走 withAuthCheckTimeout,IPC 卡住时不再让界面无限停在「刷新登录状态」
- useGameDistributionPublishForm 的重置 effect 现在清空 cover / screenshots / 上传缓存,并回收已登记的预览 blob 地址

- 抽出 revokeTrackedObjectUrls 供重置与卸载共用
- useGameDistributionPublishForm 的 handlePackageAndPublish 用 try/catch 包住 onEnsurePackage,异常经 reportError 走发布提示弹窗,不再变成未处理的 promise rejection
- useGameDistributionPublishForm 新增 previousCoverRef 与跟随 cover 的 effect,换封面 / 移除封面 / AI 生成覆盖时释放上一张的 blob 地址
- useGameDistributionPublishForm 的 createPanelScreenshotEntry 把生成的 blob 地址加入 objectUrlsRef,删除截图与卸载时的回收分支终于能命中
- GameDistributionPublishFormView 抽出 resolveMetadataHint(生成中 / AI 已生成 / 本地兜底),替换原来的三层嵌套三元
- GameDistributionPublishFormView 抽出 resolvePublishActionLabel(打包 / 上传 / 生成封面 / 上传截图 / 上传素材 / 常态),替换原来的五层嵌套三元
- export/tabs/common/PaneButton.tsx 用 TONE_CLASS 映射替换 tone 的嵌套三元
- export/tabs/common/PaneButton.tsx 用 SIZING_CLASS 映射替换 sizing 的嵌套三元
- useTaonierTab 新增 projectPathRef 与 isCurrentProject 判据,ensurePackage 的 await 返回后只有仍是当前项目才写 progress / packageResult,失败路径同样对账
- useTaonierTab 新增以 projectPath 为依赖的 effect,清空 packageResult / progress / blockedMessage,新项目不再复用旧项目的试玩包
- export/state/xhsMinitoolFields.ts 移除与 XHS_MINITOOL_FORM_FIELDS 重复且全仓无引用的标签表
- export/state/xhsMinitoolInstruction.ts 的 buildXhsMinitoolFormFillInstruction 去掉形状示意后的尾随逗号,不再在 JSON 与下一条要点之间留一行 ','
- FailureDialog 的 agentAction 改为 { label, onClick },不再按中文文案反查 onAdapt / onRepair
- ConflictCard 的 Choice 接收 name(取字段身份),同一字段的两个 radio 成为同一原生单选组,恢复方向键切换与读屏分组播报
- export/tabs/xiaohongshu/FormCard.tsx 的 FieldRow 移除 action prop 及其渲染分支与 ReactNode 导入
- export/tabs/xiaohongshu/CopyButton.tsx 的 aria-label 在状态词与字段名之间补空格,不再读成「已复制小工具名称」这类连读短语
- export/tabs/xiaohongshu/ArtifactsPane.tsx 新增「前往小红书发布/更新」外链,点击经 opener 插件的 openUrl 交给系统默认浏览器打开小红书创作平台,失败时留 console 痕迹
- 该外链改用主题陶泥儿橙 #c7653d 与常驻下划线,并补齐 hover、active 与键盘焦点态,按下有反馈且不再用蓝色
- 「下载代码包」标签与发布外链各自居中,下载按钮仍与「打包」同宽
- ArtifactsPane 把表单 / 读取中 / 读失败留白 / 自动重试的四路链式三元抽成 formSlot,JSX 只剩一个插槽
- filesystem 新增 should_skip_project_derived_path(快照口径 + .export),索引改用它
- checkpoint 恢复与清单过滤改用新口径,.export 不再进 checkpoint
- git_inspect 的提交路径校验与工作区路径过滤改用新口径,.export 不再算未跟踪/可提交
- 常量改名 PROJECT_DERIVED_EXCLUDED_COMPONENTS,project_snapshot 测试补双向断言
- registry::save 在读与写之间加注释:保存由用户手动触发、明知 code agent 在改,接受后写覆盖先写
- 说明不做 CAS 的原因:把 expected_hash 下沉进共享 save 会改所有导出目标的写契约
- commands 新增 offload:用 tokio::task::spawn_blocking 包住同步文件 IO
- read / readHash / save 三条命令改走 offload,JoinError 收口成 ExportUnavailable
- TargetTabs 去掉没有配套 tabpanel 的 tablist/tab 角色,容器改 role=group
- 选中态改用 aria-current 表达,Tab/Enter 操作不变
- DirectProjectChatHeader 给导出按钮恢复 disabled={busy},与旧发布入口一致
- 设置入口不受影响,禁用样式沿用现有 .project-chat-publish-trigger:disabled
- useXhsMinitoolExport 移除 runExport 与返回项,构建只经 packageAll 到达 buildOnce
- 测试改用 packageAll 驱动构建路径,删掉 runExport 的 mock 与断言
- xhsMinitoolDownload 返回 saved/cancelled/failed,调用方能区分用户取消与落盘失败
- ArtifactsPane 失败时在表单上方给一行重试提示,成功与取消保持静默
- 补一条测试:宿主拒绝写盘时提示可见
- useXhsMinitoolExport 加 hashPendingRef:指纹读失败后表单已换、基线还欠着,下一次重读跳过早返回把配套指纹补上,不再把旧 baseHash 留给新表单
- 保存命令的返回值直接落定基线并清掉 pending,不必再补读
- 每次内容读成功都在早返回之前清掉读来源的失败(registryMalformed / exportUnavailable),用函数式 setFailure 避免闭包过期;构建类失败不受影响
- 补两条回归测试:指纹失败后重读补上并带回新 baseHash;读恢复后失败就地清掉
合并 origin/master 到 feat/adapt-xhs-skill:发布入口迁入导出产物面板并吸收发布绑定、内部版本与上传进度
Project CI / Backend tests (pull_request) Failing after 18s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m18s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m28s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m20s
Project CI / Repository checks (pull_request) Failing after 33s
Project CI / Frontend tests (pull_request) Successful in 3m7s
Project CI / AI game creator shell web tests (pull_request) Failing after 2m55s
Project CI / Native shell tests (pull_request) Successful in 8m39s
3e6d0f39e5
- 陶泥儿 tab 发布面板去掉前端灰度:删除 readGamePublishAvailability 调用、发布权限占位与对应测试 mock,与 master 删除原生灰度命令保持一致,只在项目清单就绪前显示「正在读取项目清单」
- App.tsx 保留本分支导出产物面板架构,发布入口不再挂 Direct 聊天头;useTaonierTab 收敛 allowed/availabilityPending 状态并同步注释
- 发布表单 hook 合并本分支表单状态与 master 的发布绑定回读、AGC 工程内部版本派生、线上最近提交与上传进度阶段
- GameDistributionPublishFormView 接入发布状态面板、只读「项目版本」标签、发布阶段步骤与「更新游戏」等文案
- 合并发布表单与发布反馈测试:恢复封面/试玩包断言,补 readGameDistributionPublication mock
- agc-skills/manifest.json 取本分支新增的 platform-abstract、vite-export-xhs-minitool 与 master 的三处 sha256,version 提升到 2026-08-26.66
- decision-log.md 保留双方新增条目;技术方案文档补回双方新增章节;玩法链路文档取 master 重写后的发行合同
k88936 added 43 commits 2026-10-06 23:16:35 +08:00
project/filesystem.rs:派生目录判定改用 eq_ignore_ascii_case 原地比较,不再为每个路径组件分配一个新 String。
project/filesystem.rs:文档注释把 PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS 改成实际使用的 PROJECT_DERIVED_EXCLUDED_COMPONENTS。
App.tsx:resetChatState 一并重置 exportPanelOpen,避免面板跨项目切换后重绑到新项目。
useGameDistributionPublishForm.ts:重置效果一并清掉 publicationState/publicationBinding/publicationRefreshed/publicationMessage/latestVersionNumber/publishPhase,堵住旧项目绑定在新项目回读落定前可提交的窗口。
useGameDistributionPublishForm.ts:发布状态未就绪与封面缺少素材三处 setError 改成 reportError,让面板根的发布提示弹窗能显示出来。
useGameDistributionPublishForm.ts:重置效果调用 revokeTrackedObjectUrls,清掉 objectUrlsRef 里累计的截图预览 blob 地址。
export/draft/xhs_minitool/commands.rs:LAST_FAILURE 的键从命令名改为(命令名, 项目路径),避免不同项目的同一句失败被静默吞掉。
useGameDistributionPublishForm.ts:超限报错里的 6 改用 MAX_AGC_GAME_SCREENSHOTS,避免与常量脱节。
GameDistributionPublishFormView.tsx:新增 resolvePublicationStatusLabel,替掉四层嵌套三元。
GameDistributionPublishFormView.tsx:新增 resolveScreenshotPickLabel,替掉嵌套三元并把「截图已满 6 张」改成 MAX_AGC_GAME_SCREENSHOTS。
xiaohongshu/CopyButton.tsx:用 COPY_STATE_TEXT 查表替掉嵌套三元。
xiaohongshu/FailureDialog.tsx:嵌套三元改成 if 块,保持「文案与 handler 一起定」不变。
xiaohongshu/ArtifactsPane.tsx:把创作平台发布页 URL 提到模块常量 XHS_PUBLISH_URL。
export/state/xhsMinitoolApi.ts:guardStructuredFailure 在装 wrapper 前校验对象至少带字符串 type,否则原样抛出交给错误池。
export/state/useTaonierTab.ts:换项目重置效果补上 setDraft([]) 与 setRuntimeNotice(''),旧项目没发出去的输入不再出现在新项目输入框。
export/state/useXiaohongshuTab.ts:新增按 projectPath 的重置效果,清空 draft 与 runtimeNotice。
xiaohongshu/FormCard.tsx:used 改用 Array.from(...).length,避免补充平面字符被按 UTF-16 码元多算。
export/state/xhsMinitoolFields.ts:14 提成 TEXT_MAX_CHARS,占位文案与 maxChars 共用。
export/registry.rs:temp_path 在 pid 与序号之外再带纳秒时间戳,避免崩溃残骸被同 pid 新进程撞上导致 create_new 误失败。
export/registry.rs:在 load_or_create 注释里写明 NotFound 到原子写入之间被并发覆盖的窗口属于明确接受,与 xhs_minitool::registry::save 的口径一致。
export/registry.rs:新增 RegistryErrorCause,io/serde 失败保留原始错误类型(拿不到类型时用 Message 兜底),RegistryError 与 Cause 都实现 std::error::Error::source,Display 文案不变。
export/draft/xhs_minitool/error.rs:只在命令边界把 cause 转成 String,配合新增测试锁定 io::ErrorKind 可透出。
export/draft/xhs_minitool/build.rs:把找脚本、判权限、清旧产物抽成同步的 prepare,连同收尾判产物的 symlink_metadata 一起走 offload。
export/draft/xhs_minitool/commands.rs:offload 放宽到 pub(super),供同级 build 模块复用。
project/filesystem.rs:should_skip_project_derived_path 与快照同步判定改为只看第一个路径组件,源码里的嵌套 game/.export 不再被误排。
project_snapshot/tests.rs:补测试区分根 .export 与嵌套 .export。
GameDistributionPublishFormView.tsx:封面确认与截图预览两个 panelStyle 提取为模块级常量,不再每次渲染新建对象;按仓库约定保持内联样式,不新建 CSS 文件。
vite-export-xhs-minitool/scripts/pack.mjs:抽出 encodeZip,makeZip 先把条目与字节算完并通过 index.html / 禁止条目 / 体积校验,最后才写 zip,失败时不再留半成品。
scripts/.pack.test.mjs:补测试覆盖 makeZip 内部校验失败时不留 zip。
resources/agc-skills/manifest.json:同步该 Skill 的内容指纹与 pack 版本。
components/modal/FullscreenSubpage.tsx:新增共享全屏子页,portal + 焦点陷阱 + role=dialog/aria-modal,Esc 不关闭、只能由内容自己的按钮退出。
components/modal/windowChrome.ts:把标题栏放行判据从 ThemedModal 抽出,供两种模态复用。
components/modal/ThemedModal.tsx:改为引用抽出的判据。
view/project-development/export/index.tsx:导出面板改用 FullscreenSubpage,删掉自写的 portal 包裹。
export/draft/xhs_minitool/build.rs:conclude 增加 script_launched 判据,用 target_exec != established 区分「根本没跑起来」与「跑了被信号杀掉」;前者报 exportUnavailable,由前端既有路径抛进错误池上报,后者维持 commandFailed。补对应单测。
components/game-distribution/useGameDistributionPublishForm.ts:新增 coverRequestRef,选择封面与 AI 生成在 await 回来后先比对请求序号再写封面 state,收尾也只由最新一次请求执行;换项目重置时作废在途请求并清掉上传中提示。
tests/gameDistributionPublishForm.test.tsx:补「换项目后旧项目在途的封面上传不再写回新项目」用例。
resources/agc-skills/vite-export-xhs-minitool/scripts/pack.mjs:collectZipEntries 补注释,说明它用 statSync 且不跳 SKIP_DIRS、与预检 walkArtifactFiles 的 lstatSync/跳过目录不一致,属于已评审并决定暂不统一的取舍。
resources/agc-skills/manifest.json:同步 xhs 技能指纹并递增版本。
resources/agc-skills/vite-export-xhs-minitool/scripts/validate.mjs:scanCode 对 .js 用剥掉注释/字符串的副本匹配 API 名规则,避免注释里的 fetch( 误报;三条要匹配字符串参数的规则标记为扫原文;外部 URL 始终扫原文,CSS 的 url(https://…) 不再被 // 当行注释抹掉。
resources/agc-skills/vite-export-xhs-minitool/scripts/.validate.test.mjs:补注释/字符串不误报、字符串参数规则仍生效、CSS 与 JS 外部 URL 仍报错三个用例。
resources/agc-skills/manifest.json:同步 xhs 技能指纹并递增版本。
view/project-development/export/state/xhsMinitoolInstruction.ts:buildXhsMinitoolErrorFixInstruction 的文档注释不再承诺「要求 agent 先复现再修」,改成与实现一致——正文只有 error 现场,怎么修由 agent 自行判断。
view/project-development/export/state/useXiaohongshuTab.ts 与 useTaonierTab.ts:在 turns 派生处补注释,说明这段与另一 tab 的重复是有意保留——两个 tab 以后可能各自订阅不同会话/线程,等形状真分叉再抽公共 helper。
export/draft/xhs_minitool/registry.rs:模块注释补一段已知取舍,说明这里读写注册表不检查符号链接、与产物/脚本/图标的拒链口径不同,属于已评审并决定保留的行为。
view/project-development/export/state/useXhsMinitoolExport.ts:refresh 与 buildOnce 遇到 exportUnavailable 不再 setFailure,直接抛给全局错误池上报;persist 同样只上报不落卡片。
tests/xhsMinitoolExport.test.tsx:更新为断言 failure 始终为空、同一个故障只抛一次。
view/project-development/export/state/useXhsMinitoolExport.ts:新增 projectPath 重置效果,把表单/判据/冲突/产物状态与全部本地基线清回初值;读内容、取指纹、保存、构建各处在 await 回来后用 projectPathRef 校验结果仍属于当前项目,过时就丢弃,不再写回新项目。
tests/xhsMinitoolExport.test.tsx:补换项目后表单与产物判据清空、并读回新项目内容的用例。
view/project-development/export/state/formSaveLock.ts:新增写盘锁,串行执行保存,并按进入时的编辑版本判断这次写的是不是最后一版。
view/project-development/export/state/useXhsMinitoolExport.ts:persist 走锁,写盘期间又有编辑时不清 dirty,让已排队的自动保存接着写最新一版;updateField 与 resolveConflict 记编辑版本。
tests/formSaveLock.test.ts:覆盖串行、被后来的编辑超过、最后一版、失败不卡队列。
tests/xhsMinitoolExport.test.tsx:补「保存期间继续输入,最后一版仍会落盘」的回归用例。
src-tauri/src/project/asset_export.rs:新增按保存同一条路径门禁解析产物位置的能力,供文件管理器定位复用。
src-tauri/src/commands/desktop.rs:新增 reveal_local_project_asset_file 命令,用系统文件管理器定位项目内产物。
src-tauri/src/desktop.rs:注册新命令。
view/project-development/export/state/xhsMinitoolDownload.ts:保存结果改为带失败原因,新增在文件管理器里定位原件的兜底调用。
view/project-development/export/tabs/xiaohongshu/DownloadFailureDialog.tsx:新增下载失败弹窗,给「关闭」与「在文件管理器中打开」两条路。
view/project-development/export/tabs/xiaohongshu/ArtifactsPane.tsx:下载失败改用弹窗与兜底出口,去掉会被滚出视野的一行小字。
tests/xhsMinitoolExport.test.tsx:覆盖失败弹窗、定位命令参数与定位失败留在弹窗。
- 保存命令不再校验表单:`save_form` 只判 baseHash 冲突并写盘,删掉 `validation` 模块与它的必填 / 字数 / icon 约束
- `FormInvalid` 与 `XHSMiniToolExportField` 从 Rust 失败表和 DTO 退役,ts-rs 同步删掉两个生成类型
- 前端新增 `validateXhsMinitoolForm`(必填 + 14 字上限,按码点算),`persist` 先过它再落盘
- `fieldError` 改用本地 `XhsMinitoolFieldError`,`save` 守卫与失败卡片分流同步移除 `formInvalid`
- 测试:新增 `xhsMinitoolFields.test.ts`,改写两处依赖宿主 `formInvalid` 的用例为前端校验
- `Shell` 的米色页面渐变改用 `bg-(image:--platform-body-fill)`
- 文案 / 强调 / 描边换成 `--platform-text-strong` / `-base` / `-soft` / `-muted`、`--platform-accent`、`--platform-surface-border` 与 `--platform-surface-hover-border`
- 卡片与输入底色换成 `--platform-panel-fill` / `--platform-input-fill` / `--platform-neutral-bg`,冲突卡底换成 `--platform-warm-bg`
- 硬编码阴影换成 `--platform-panel-shadow` 与 `--platform-profile-action-shadow`
- 小红书品牌红 `#ff2442` 不在 `--platform-*` 调色板里,按原值保留并加注释
- registry.rs 模块注释写明决定不改的理由:注册表是用户项目里的草稿,要挡的是把项目内容交给打包链的入口
- pack.mjs 的 collectZipEntries 注释写明决定不改的理由:链接算不算合法产物还没定论,预检对链接是静默跳过

- manifest.json 同步 vite-export-xhs-minitool 的 sha256 与版本
- xhsMinitoolFailure.ts 的 commandFailed 在 exitCode 为 null 时改说「导出中途被中断了」:脚本没启动已归到 exportUnavailable

- xhsMinitoolExport.test.tsx 同步这两条措辞断言
表单字段逐项报错并可交给陶泥儿处理
Project CI / Backend tests (pull_request) Failing after 22s
Project CI / Native shell tests (pull_request) Failing after 4m6s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m30s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m17s
Project CI / AI game creator shell web tests (pull_request) Failing after 35s
Project CI / Frontend tests (pull_request) Successful in 1m56s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m2s
157b4eb861
- xhsMinitoolFields.ts 的 validateXhsMinitoolForm 一次返回全部出错字段

- xhsMinitoolInstruction.ts 新增字段红字指令,示意里的字数上限改用 XHS_MINITOOL_TEXT_MAX_CHARS

- useXhsMinitoolExport.ts 的 fieldError 改为 fieldErrors,新增 handFieldErrorsToAgent:交接后清红字与 dirty,让自动重读能采纳 agent 的修正

- FormCard.tsx 每个出错字段各挂红框与红字,标题下新增「交给陶泥儿」入口

- ArtifactsPane.tsx 接上新字段与新动作

- 补 xhsMinitoolFields / xhsMinitoolExport 测试覆盖多字段报错与交接
k88936 added 1 commit 2026-10-06 23:29:52 +08:00
合并 origin/master 到 feat/adapt-xhs-skill:发布表单吸收平台版本号与买断定价,并合入播放会话网关与导出 Skill 更新
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m56s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m16s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m24s
Project CI / Repository checks (pull_request) Failing after 59s
Project CI / Backend tests (pull_request) Successful in 8m46s
Project CI / Frontend tests (pull_request) Successful in 2m31s
Project CI / AI game creator shell web tests (pull_request) Failing after 2m27s
Project CI / Native shell tests (pull_request) Successful in 6m17s
7bcef53494
- 发布表单 hook 保留本分支的 hook + 视图拆分,移植 master 的平台版本号回读(nextVersionNumber)、买断定价状态与提交校验,删除由工程内部版本派生的 projectVersion
- GameDistributionPublishFormView 接入只读「项目版本」与共享 PlatformGamePricingField,版本号未知时禁用提交
- DirectProjectComposer 同时保留本分支的草稿回填 / 回写 props 与 master 的 actionsPortalTarget 挂点
- 发布表单测试改用平台版本号 mock(nextVersionNumber: 1),补齐买断定价与缺省版本号禁用用例,并修正 Promise 类型标注
- decision-log.md 保留双方新增条目(小红书导出与 Skill 安装工具 + 播放会话前缀清 Cookie)
k88936 marked the pull request as ready for review 2026-10-06 23:30:03 +08:00
k88936 added 2 commits 2026-10-06 23:58:20 +08:00
- 删除 tests/gamePublishFeedback.test.tsx:发布入口迁入导出产物面板、发布表单拆成 hook + 视图后,该套 App 级反馈用例已失效
- 移除 tests/chatDialogFrameLayout.test.ts 中扫描 DirectProjectChatView 会话块顺序的用例(该 DOM 已迁到 DirectProjectChatBox),并删除不再使用的 CHAT_VIEW_PATH / CHAT_CONVERSATION_PATH
修复遗留 Rust 代码的 rustfmt 格式
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m51s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m4s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m6s
Project CI / Backend tests (pull_request) Successful in 8m49s
Project CI / Frontend tests (pull_request) Successful in 3m19s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m57s
Project CI / Repository checks (pull_request) Failing after 5m28s
Project CI / Native shell tests (pull_request) Successful in 6m57s
d9f0951391
- xhs_minitool/build.rs:拆分超长的 conclude 调用断言行
- project/filesystem.rs:project_snapshot_path_is_excluded 的闭包改用 rustfmt 期望的换行
k88936 added 1 commit 2026-10-07 00:44:12 +08:00
修复 export/generated 未豁免行尾空白检查
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m56s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m4s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m5s
Project CI / Backend tests (pull_request) Successful in 9m19s
Project CI / Frontend tests (pull_request) Successful in 3m23s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m6s
Project CI / Repository checks (pull_request) Successful in 7m7s
Project CI / Native shell tests (pull_request) Successful in 8m35s
e35e179df1
.gitattributes 补登 apps/ai-game-creator-shell/src/view/project-development/export/generated/** 的 whitespace=-trailing-space,与其余 ts-rs 生成目录保持一致
k88936 merged commit a8ae817205 into master 2026-10-07 10:09:38 +08:00
k88936 deleted branch feat/adapt-xhs-skill 2026-10-07 10:09:38 +08:00
Sign in to join this conversation.