合并 origin/master 到 feat/tribo3d-integeration:ts-rs 一律常开、Cargo 清单去重

- server-rs/Cargo.toml:删除与 workspace git 固定重复的 registry `ts-rs = "12.0.1"`,保留固定 commit 并写明「ts-rs 一律常开、绑定命令固定为 cargo test -p shared-contracts export_bindings」
- server-rs/crates/shared-contracts/Cargo.toml:删除 master 侧新增的 `ts-bindings` feature,`ts-rs` 保持常开依赖
- server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:去掉 `cfg_attr(feature = "ts-bindings", …)` 门控,derive 与字段级 `ts(...)` 无条件展开
- apps/ai-game-creator-shell/src-tauri/Cargo.toml:shared-contracts 依赖去掉 `features = ["ts-bindings"]`,继续保留本分支的 ts-rs git 固定
- apps/ai-game-creator-shell/src-tauri/Cargo.lock:按上述依赖变更同步(shared-contracts 指向 git 源 ts-rs)
- docs:同步 5 处绑定生成命令(去掉 `--features ts-bindings`),并在 decision-log 记本次合并的决策、代价与验证
- 其余暂存改动为 origin/master 带入的内容,冲突按两侧目的逐一合并

验证:cargo metadata --locked(server-rs 与 AGC 两个 workspace)、cargo test -p shared-contracts(119 + 5 + 5 + 2 + 2 全绿且无告警)、npm run contracts:model3d:generate 后 packages/shared 零 diff、cargo check -p spacetime-module --target wasm32-unknown-unknown、npm run check:encoding、npm run check:rustfmt、npm run check:spacetime-schema、git diff --check、暂存集 eslint / prettier 全过
This commit is contained in:
2026-09-22 13:12:28 +08:00
1079 changed files with 140332 additions and 77798 deletions
+15 -5
View File
@@ -25,29 +25,39 @@
## AI 游戏创作与 Agent Runtime
- [AGC 资源 kind 枚举化契约](./technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md#2026-09-15-gamecreationapp-资源-kind-枚举化当前权威口径)GameCreationApp 资源 kind 的 Rust enum、ts-rs 绑定、Unknown 可观测性和 shell 内重构边界。
- [策划 Agent 生产迁移与工作区浏览](./technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md):已完成;当前策划入口统一使用 Design Agent,采用阶段审批与用户工作区文件浏览。旧 V1/V2 会话、命令、专用展示和测试不再作为兼容目标。
- [Tripo 3D 模型 Provider 集成](<./technical/【技术方案】Tripo 3D模型Provider集成-2026-09-18.md>):实现 text-to-model、image-to-model、multiview-to-model 的 Rust provider adapter 与流式下载边界。
- [Tripo 3D 生成 API 集成](<./technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md>):把 text-to-model 与 image-to-model 接成内部 API,复用异步队列与状态查询,产物落 OSS 并登记资源,按显式泥点定价真实扣费。
- [策划 Agent 生产迁移与工作区浏览](./technical/【技术方案】策划Agent生产迁移与工作区浏览-2026-09-10.md):实施中;以自由协作原型为行为基线,复用生产基建,采用阶段审批与用户工作区文件浏览。无旧 V2 会话的策划入口切换到新设计 Agent。
- [LLM 累计额度结算](./technical/【技术方案】LLM累计额度结算-2026-09-05.md):Router 累计额度、首次基线与原子钱包结算。
- [Responses API 与 Agents SDK 迁移评估](./technical/【技术评估】Responses%20API与Agents%20SDK迁移评估-2026-09-07.md):评估 AGC 核心 Runtime 是否迁移到外部 Agent SDK 及其边界。
- [AI 游戏创作智能体 App 实施计划](./technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md):当前 DirectProject、受控语义工具、UI workflow、资源和运行时合同。
- [AGC 后端框架整理与演进路线](./technical/【技术方案】AGC后端框架整理与演进路线-2026-09-18.md):共享 Runtime、本地执行宿主、云端控制面、领域/平台适配器及分阶段收口边界。
- [AGC 异步操作可恢复闭环](./【技术方案】AGC异步操作可恢复闭环-2026-09-14.md):认证响应体、最近项目检查和首页自动创建的超时、逐项恢复与跨页防重合同。
- [AGC 客户端稳定版生命周期大切换](./【技术方案】AGC客户端稳定版生命周期大切换-2026-09-14.md):统一 operation、认证/Runner、项目入口、本地恢复和 dev-stack 身份边界。
- [策划会话 Runtime V2 接入与旧链路退役方案](./technical/【技术方案】策划会话RuntimeV2接入与旧链路退役-2026-09-03.md)新单 Agent 策划会话、GDD 策略、未来 MCP/Skill 兼容插槽、阶段任务与退役验收合同
- [策划会话 Runtime V2 接入与旧链路退役方案](./technical/【技术方案】策划会话RuntimeV2接入与旧链路退役-2026-09-03.md)历史方案,仅用于追溯 V2 的实现与退役过程,不作为当前实现依据
- [DirectProject Codex 原始历史与异常恢复](<./technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md>):原始 Responses item 持久化、线程注入与异常回合收尾。
- [DirectProject 对话历史单一事实源](./adr/【ADR】DirectProject对话历史单一事实源-2026-09-16.md):AGC 项目开发对话只以项目对话历史与运行态事件为真相源,聊天投影不落盘。
- [DirectProject 独立聊天容器与工作台钱包布局](./adr/【ADR】DirectProject独立聊天容器与工作台钱包布局-2026-09-18.md)DirectProject 与 Supervisor 等路径分容器,钱包入口由项目工作台布局独立承载。
- [GameAgent 对话工具调用卡片](./technical/【技术方案】GameAgent对话工具调用卡片-2026-09-14.md):把右侧对话里的执行命令 / 写文件投影成 Codex 风格可折叠卡片,含采集、独立历史文件、事件字段与回读契约。
- [DirectProject 客户端 Skill 与 MCP 扩展导入方案](./technical/【技术方案】DirectProject客户端Skill与MCP扩展导入方案-2026-08-31.md):客户端扩展导入、按独立 Skill/MCP 拆分、命名、启用和启动时注入边界。
- [AGC 通用插件宿主与编辑器适配](./technical/【技术方案】AGC通用插件宿主与编辑器适配-2026-09-09.md):通用插件宿主、SDK、权限审计、UI 挂载和 Cocos 编辑器适配边界。
- [AGC Unity 编辑器插件接入](./technical/【技术方案】AGC Unity编辑器插件接入-2026-09-18.md)DotCraft Attach 来源、Windows Mono 接入、项目身份、执行回执和分发边界。
- [AGC Godot 编辑器插件接入](<./technical/【技术方案】AGC Godot编辑器插件接入-2026-09-20.md>)GDExtension 聚焦加载、安装资源、受管描述文件、UID 归属、GDScript 回执与 Runner 边界。
- [AGC Cocos Creator 编辑器桥接模块](<./technical/【技术方案】AGC Cocos Creator 编辑器桥接模块-2026-09-09.md>):独立 crate、feature 开关、目标校验与 Windows 注入边界。
- [AGC 客户端更新检查与下载](./technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md):启动版本检测、OSS 清单格式和下载约定
- [AGC 客户端更新检查与下载](./technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md):启动版本检测、固定 dev 服务、OSS 清单与官网最新客户端下载
- [AGC 总版本号与发号](./technical/【技术方案】AGC总版本号与发号-2026-09-20.md):客户端版本号收口到 OSS `agc/global-version.json`,统一构建一次发号供各渠道共用,渠道高水位降级为断言。
- [AGC 模板库与模板建项](./technical/【技术方案】AGC模板库与模板建项-2026-09-17.md)`templates/` 前缀的模板库契约、下载安装与「用模板建项目」链路。
- [AGC 模板包组织指南](./【模板规范】AGC模板包组织指南-2026-09-21.md):模板 ZIP 的根目录结构、Cocos 工程保留项、禁止放入的内容、封面与体积上限、版本不可变与发布前自检。
- [DirectProject 本轮附件路径映射](./technical/【技术方案】DirectProject本轮附件路径映射-2026-08-31.md):Direct 首轮只映射附件原名与项目相对路径,不灌正文、不区别 GDD。
- [Direct 回合行为审计账本](./technical/【技术方案】Direct回合行为审计账本-2026-08-31.md)Direct GUI 回合把 native 读 / MCP / 写文件落成项目内有界时间线,用于判断有没有打开本轮附件。
- [项目开发工作台 PRD](./prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md):当前工作台页面和验收边界。
- [AGC 错误报告与诊断上传](./technical/【技术方案】AGC错误报告与诊断上传-2026-08-31.md):当前进程错误事件、应用级日志和管理员查看器合同。
- [立项策划 AgentFast GDD](<./technical/【技术方案】立项策划AgentFast GDD-2026-08-10.md>):旧 `project-supervisor-plan` / `project-planning` 历史会话的入口、审批恢复合同;V2 切换时未完成旧会话强制失败
- [立项策划 AgentFast GDD](<./technical/【技术方案】立项策划AgentFast GDD-2026-08-10.md>)历史 V1 方案,仅用于追溯;`project-supervisor-plan` / `project-planning` 入口、审批恢复和测试均已删除
- [GameAgent 资源自由画板与快速编辑](./technical/【技术方案】GameAgent资源自由画板与快速编辑-2026-08-20.md)
- [AGC 栏目画布底部工具栏入口矩阵](./technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md):栏目画布底部工具栏的入口矩阵、可用条件与验收口径。
- [AGC 资源工作台三处交互收口改动前对照图](./technical/assets/agc-resource-workbench-ui-before-20260914/README.md):任务侧栏两个关闭入口、左侧贴边折叠把手、顶部播放按钮居中悬浮三张改动前截图与问题说明。
@@ -0,0 +1,55 @@
# 【ADR】DirectProject对话历史单一事实源-2026-09-16
状态:已接受
## 背景
AGC 项目开发聊天框当前同时从三处取数据:Direct 回合事件(实时)、`turn-stream.jsonl`(文本段与工具交替顺序)、`tool-calls.jsonl`(已脱敏工具卡片),重进页面时还要额外接管活动回合快照。同一段文本和同一张工具卡片因此存在多个来源,实时与回读会互相覆盖,恢复路径也只能靠"哪个源先到"决定。
`.agent/conversations/project.jsonl` 里的 Codex 原始条目本身已经带着顺序(`function_call``function_call_output` 按写入顺序落行),顺序信息并不是协议缺陷,而是在投影层被丢弃。
## 决策
- AGC 项目开发对话的持久事实源只有 **项目对话历史**`.agent/conversations/project.jsonl` 的原始条目);消息文本、工具卡片和它们的先后顺序都从它派生。
- 运行期间的回合状态只来自 **运行态事件**Thread Manager 的 subscribe / consume / notify);`notify` 只做唤醒,不携带状态。
- **聊天投影** 在读取与渲染时生成,不落盘、不成为第二事实源;DirectProject 聊天框停止读取 `turn-stream.jsonl``tool-calls.jsonl`,也不再提供供前端读取的命令。DirectRuntime 自己那套进度事件与文件写入属于运行时账本,本轮保留不动。
- 页面重进的运行态只由 `subscribe` 的 bootstrap 事件重建,删除活动回合快照接管路径。
- 可见性判断留在前端聊天投影:后端历史分页只按原始条目切片,前端自己跳过不可显示条目并推进锚点。
- 线上模型是 **ts-rs 导出的 tagged enum**`agent/direct_thread_wire.rs`),不是"一个大结构体加一堆可空字段":`DirectThreadItem``itemType` 区分条目,`DirectThreadEvent``type` 区分事件,前端直接消费生成的 TS 类型(改完 Rust 模型跑 `cargo test export_bindings`)。条目上的毫秒时间戳标 `#[ts(as = "f64")]`,因为 ts-rs 默认把 `u64` 映射成 `bigint`,而 Tauri 的 JSON 通道传的是 `number`
- 运行态事件与历史切片使用同形条目,Rust 在两侧套同一套安全过滤(脱敏、截断、路径归一),前端只有一个「原始条目 → 视图」投影函数。
- 两侧的过滤口径必须完全一致,包含「哪些条目根本不是本项目的聊天条目」:Codex app-server 回显的用户消息(`userMessage` / 非 AGC 的 `role=user`)在落盘侧被过滤,在运行态事件侧也必须被过滤(`direct_thread_visible_item`)。少一侧就会出现「实时比历史多出两条同文本用户条目、各自开出一个耗时 0 秒的假回合,重进页面又正常」这类只有其中一侧的事实源缺陷。
- 搬运层不生成展示形状:Thread Manager 只下发脱敏原始条目(`itemType` 原样透传),工具卡片的 `kind`、标题、折叠摘要都由前端生成。
- 条目身份只有一套:进队列前归一成一个 `itemId`。工具条目在 `project.jsonl` 里带两个 id(调用 id 与 response item id,调用与输出共用前者),归一只在 Rust 边界做一次,Thread Manager 与前端都不暴露第二个 id 概念。
- 事件不带回合身份:DirectProject 同一时刻只有一个回合在跑,`turn.started` 无载荷、`turn.completed` 只带 `status`;前端 state 里只有一个 `turnRunning` 布尔,没有 `turnId``subscribe` 返回的条目、增量、请求与队列锚点都不带 turn id。
- 合并只在前端,规则只保留「先到定形、后到补空白」:第一次见到的快照决定卡片形状,后续快照只补输出与状态,不做逐字段优先级表。只有"后到信息一定更全"时才例外:正文取更长的一份、工具状态允许从 `running` 升级到终态、`updatedAt` 取较新的时间。
- 前端不保留增量缓冲:`item.delta` 直接追加到运行态条目的正文(正文只增不减)。`turn.completed` 把当前回合的运行态条目并入历史再清空,条目既不消失也不重复。
- 活动回合的唯一判据是「出现过 `turn.started` 且未出现 `turn.completed`」;进程重启后队列消失,历史里的半截回合一律按已结束渲染。
- 分页锚点取原始条目 id;一次翻页操作在前端自动连拉,直到出现可显示条目或 `hasMore=false`,上限 5 页。
- `notify` 是唯一唤醒来源:`subscribe` 的 bootstrap 事件本身就是该 subscriber 此刻要处理的事件(游标已在队尾),前端直接 reduce 它们,不需要为了取这批事件再补一次 `consume`,之后完全由 `notify` 驱动,不设低频 tick 或任何轮询兜底。唯一例外是回执竞态:Rust 侧一注册完 subscriber 就开始 `notify`,前端却要等回执才知道自己的 `subscriptionId`,这段窗口内的通知只能记成欠账,回执到达后立刻补一次 `consume` 取回,否则该回合的尾部事件会卡在队列里等一个可能永不出现的下一次通知。
- 迁移按一次干净切换落地:不做灰度、不做运行时开关、不双跑;允许提交序列里存在「新源已启用、旧代码尚未删除」的中间窗口,禁止反向的「新源未启用、旧源已删」。
- 思考过程与工具活动同样从运行态事件与历史条目推断,界面展示保持不变。
- 运行态事件必须自足:`item.started` / `item.completed` 携带与历史切片同形的完整**脱敏原始条目**,前端按归一后的 `itemId` 合并快照得到运行中与完成态;不提供按 `itemId` 单点取快照的接口。
- 思考正文以 `item.delta{kind:"reasoning"}` 流式下发(`item/reasoning/summaryTextDelta``item/reasoning/textDelta`)。这不放宽可见范围:同一段文本本来就已落进 `project.jsonl` 并在 `item.completed` 展示;plan 文本与命令输出仍只降级为活动状态。
- 首屏历史由 `subscribe` 返回的 `lastCompletedItemId` 锚定,再取最近切片;删除返回整份对话的历史命令。锚点是切片**新端(较新一侧)的边界且含该条**(命令参数 `throughItemId`):比锚点更新的条目只从运行态事件来,历史切片与实时流因此不重叠;向后翻页仍用切片返回的 `firstItemId` 作为 `beforeItemId`(不含锚点)。订阅回执到达之前不读首屏,也不退化成"取文件尾"(那会把回执之后才完成的条目也拉进历史)。
- 生命周期锚点独立于 replay 队列保存(队列会回收 `cleanable` 事件,新订阅的游标又在队尾,回收后无法反推"最新回合是 started 还是 completed"),`subscribe` 必须返回最新的一条 `turn.started` / `turn.completed`,否则新订阅无法判定回合是否仍在运行。
- 前端工具卡片形状是 `Omit<GameCreatorDirectToolCall, 'turnId'>`:聊天卡片不再有回合身份,`tool-calls.jsonl` 的持久化形状仍保留 `turnId`DirectRuntime 的账本没动)。
- 未识别 item 类型由 Rust 原样透传(只带类型与身份,Rust 侧留 TODO),当前由前端投影丢弃:哪些类型可见属于前端决策,不回 Rust 加白名单。
- 删除范围包含前端对 `read_direct_turn_stream``read_direct_tool_calls``read_direct_project_history`(整份历史)与 `game-creator-direct-turn-update` 事件的调用;保留分页用的历史切片读取(`read_direct_project_history_slice`),且该切片从文件尾反向扫描。`list_game_creator_direct_active_turns` 有意保留:它服务首页跨页面的「运行中的项目」列表,不是聊天框读路径。
- 前端删掉 `directTurnStream` / `directToolCalls` / 活动回合快照接管 / 瞬时应答文本这些并行状态,聊天视图只由 reducer 状态投影(含工具卡片)。
- 失败与中止说明只在运行期显示,不写进 `project.jsonl`;页面重进后不再出现。
- 历史切片的 `firstItemId` 是分页锚点,始终取 `project.jsonl` 里的原始 item id,与归一后的条目身份分开计算。
- 审批与提问事件本次只作为同一条事件流 pass-through,不并入聊天 reducer 驱动的状态机,迁移面收敛在历史与运行态一致性上。
## 备选方案与取舍
1. **保留 `tool-calls.jsonl` 作为"读侧已脱敏"缓存**:省一次脱敏与截断,但它成为与项目对话历史并行的第二事实源,卡片状态与顺序会和实时事件分叉。选择按读取期投影,必要时在进程内缓存。
2. **保留 Direct 回合事件作为实时传输**:迁移量小,但同一段文本仍有两条实时链路,reducer 必须处理互相覆盖,正是本次要消除的问题。
3. **让后端分页按"可显示消息数"切片**:界面能少写循环,代价是 Rust 需要理解 UI 可见性,界面规则一变就要同步改后端。
## 影响
- 旧项目磁盘上遗留的 `turn-stream.jsonl` / `tool-calls.jsonl` 保留不动,不迁移、不清理、不再由 DirectProject 聊天框读取。
- 工具卡片的脱敏与截断必须在读取期执行一次,不能因为"原始条目已在磁盘"就把未脱敏内容直接渲染到界面。
- 回合结束语义务必由 `turn.completed` 判定;缺少该事件的残留回合不得被渲染成运行中。
- 验收证据是端到端行为,不是单元测试:回合进行中杀掉应用进程后重开项目,应看到部分文本与工具卡片按原顺序出现且不显示忙碌;正常结束后重进应与实时渲染一致;文件系统不得再新增 `turn-stream.jsonl` / `tool-calls.jsonl`
- id 空间已用源码核对:codex-rs `app-server-protocol/src/protocol/thread_history.rs` 中所有工具 item 都是 `id: payload.call_id.clone()`,而 `project.jsonl` 落盘的是原始 response item。真实 app-server 会话核对仍列为运行时验收项。
@@ -0,0 +1,26 @@
# DirectProject 独立聊天容器与工作台钱包布局
状态:已接受
AGC 项目开发工作台的普通项目固定使用 DirectProject;它不再作为 `ProjectSupervisorView` 的条件分支,而由 `view/project-development/chat/` 下的 `DirectProjectChatView` 与 controller 拥有自己的订阅、历史、发送、队列、附件和中止生命周期。Supervisor 前端链路(独立调试窗口、纯聊天容器、工作台壳里的 Supervisor 运行态与专业 Agent 面板)已整体退役,项目对话只保留 DirectProject 与立项策划两条产品路径;立项策划当前只有 Design Agent(策划 Agent V1/V2 的会话、专用命令、审批卡与展示适配已于 2026-09-20 退役,见 shared-memory 决策记录)。行为中立的 Composer、消息、工具卡片和设置基础表现可以复用,但不同产品路径不共享行为容器,也不保留运行时 feature flag、兼容别名、Direct fallback 或双跑路径。
项目工作台布局拥有跨面板的账户/钱包入口。钱包不再作为 `walletEntry` 传入 DirectProject 聊天上下文或聊天设置浮层,而是在 `ProjectDevelopmentView` 的布局级头部/工具栏独立渲染;本次只改变布局归属与嵌套关系,保留钱包入口本身的可用性。
这项边界选择是为了让 DirectProject 的事实源与生命周期可以独立测试和演进,同时避免把工作台级账户状态与聊天状态耦合;一次性替换通过 Git revert 回滚,不增加运行时开关、兼容别名或条件兼容分支。
## 模块结构
公开入口只有 `view/project-development/chat/DirectProjectChatView.tsx`,内部按职责分层:
- `components/`:表现层,一个组件一个目录,组件自己的逻辑与表现同目录(`components/ToolCallGroup/``ToolCallGroup.tsx``toolCallGroupPresentation.ts``components/DirectProjectComposer/``DirectProjectComposer.tsx``ComposerControls.tsx``chatComposerQueue.ts``chatComposerVoice.ts`)。
- `controller/`:会话控制器 `useDirectProjectChatController`、项目清单订阅 `useDirectProjectManifest`,以及线程订阅与聊天 reducer 的独立 hook `useDirectThreadChatSubscription`
- `conversation/``history/`:纯模块(条目投影、历史分页、订阅锚点闸门、附件映射)。
- `generated/`Rust 侧 ts-rs 导出的 Direct 契约,不在前端手抄形状。
`useDirectThreadChatSubscription` 持有 `subscribe → consume → notify` 单飞循环与聊天 reducer 状态,是 DirectProject 运行态的唯一事实源;控制器只读它投影后的条目与回合忙态,历史分页通过同一个 reducer 并入。
工作台壳要把运行/预览这类工作台级动作的结果说给用户时,只通过 `DirectProjectChatView``ref` 句柄(`announce`)交给聊天自己的本地消息流;壳不持有 Direct 的聊天消息。
立项策划(当前只有 Design Agent)的容器与表现与 DirectProject 并列放在 `view/project-development/planning/``PlanningChatView``DesignAgentSurface`);两条产品路径共享的只有无行为真相的表现组件:输入盒的模型 / 推理档控件(`features/project-workspace/ConversationModelSelect.tsx``chat/components/DirectProjectComposer/ComposerControls.tsx``ComposerReasoningEffortSelect`)和思考折叠入口(`chat/components/AgentReasoning/AgentReasoning.tsx`,折叠态单行纯文本预览、展开态安全 Markdown)。共享的只是表现,回合、会话与配置写回仍由各自入口负责。
`game-creator-manifest-invalidated` 由工作台壳与 DirectProject 聊天各自订阅:壳做一次配对读(`revision → 清单 → revision``source: 'asset-event'`)把运行态落盘的新资源并入 `currentProjectContext`,这次刷新**不**重新检查项目目录;聊天侧仍由 `useDirectProjectManifest` 刷新自己的 `@` 引用清单。
File diff suppressed because one or more lines are too long
@@ -1,26 +0,0 @@
# AGC 对话历史分页恢复实施计划
- Date: 2026-09-16
- Status: awaiting-runtime-acceptance
- Milestone: [AGC 对话历史分页恢复](./【里程碑】AGC对话历史分页恢复-2026-09-16.md)
## 实施
1. 原生历史读取复用逐行解析,增加消息模式,过滤后分页并返回已有原始消息 ID 游标;保持原始接口默认行为和路径权限。
2. 工作台首屏与更早消息读取显式请求消息模式,消费游标;加载代次隔离、单飞与 ID 去重。
3. 合成记录测试复现原始工具页卡住的形状,覆盖旧无 ID、坏行、时间、失败/重复/切项目;临时目录只读重放用户日志。
4. 前端/原生定向测试、类型、Lint、编码、文档和差异检查通过后,更新问题表及 PR 草稿并本地提交。
5. 在临时消息投影中标记历史来源,保留 Runtime 所有权语义;刷新合并时只保留非历史来源的待回读消息。补齐「先加载旧页,再 /history,再翻页」的顺序与去重回归,保持尚未落盘用户输入的保留逻辑。
## 边界与停止条件
不调整 Direct 消息呈现归属、不修未证明的写入丢失、不上传日志、不触碰用户项目。必要 API 变化仅为本地 IPC 可选参数和游标字段;无 OpenAPI、SpacetimeDB 或持久化迁移。远程推送/PR/WIP 操作仍待额外确认。
## 验收证据
- 历史消息模型、回合呈现及分页集成共 24 个前端测试通过;包含真实 App 的首屏/更早页、单飞、失败重试、重叠消息、同项目重新加载及离开再进入的迟到响应。
- 16 个历史原生测试通过;人工日志重放用例在 CI 默认忽略,已在本地单独执行通过。
- 使用用户提供的原始日志运行修复后的原生读取:44 条现存聊天消息(含 2 条用户消息)分 3 页取回,逐项内容与顺序一致,原文件字节未变;未在仓库保存原始日志。
- 工作台/Direct 恢复与画布导航的 8 个定向回归通过。真实客户端重新进入与向上翻页尚待用户验收;本次涉及 Rust IPC,需重新构建并启动原生端。
- 与前面画布/JSON 修复联合复验:119 个前端定向测试、30 个原生测试通过;AGC TypeScript、修改文件 ESLint、编码、文档索引和差异检查通过。
- 状态只覆盖日志中已经证明的分页卡页,不据此宣称其它可能的未落盘消息也已恢复。
@@ -1,59 +0,0 @@
# AGC 模板库客户端接入实施计划
Version: 1.0
Status: active
Date: 2026-09-17
Milestone Spec: `docs/project-memory/plans/【里程碑】AGC模板库客户端接入-2026-09-17.md`
## 步骤
1. **OSS 库布局与契约**
-`agc-dev` 落地 `templates/` 前缀:`index.json``v1/<id>/{template.json,template.zip,cover.*}`
- 清单补齐 `tags``coverKey/coverWidth/coverHeight/coverSha256`,正文改为 zip(zip 根 == 项目根)。
- 模板源落在 `apps/ai-game-creator-shell/template-library/v1/<id>/{meta.json,project/**,cover.*}`zip 由 `scripts/agc-template-library-publish.mjs` 现场打包(不落仓库)。
- 交付:发布脚本(校验 + 打包 + 上传 + 回读校验,支持 `--dry-run` / `--prune`)、`templates/README.md`,以及 5 个模板(3 个空白 + 2 个起步工程)。
- 验收:匿名 `GET templates/index.json` 可读,每个 `zipKey` 回读 SHA-256 与清单一致。
2. **Rust 模板库模块**
- 新增 `src-tauri/src/template_library.rs`:清单解析与校验、受信任 base、缓存/安装目录、zip 安全解压、安装记录、由模板建项目。
- 注册命令 `fetch_game_template_library``download_game_template``create_automatic_local_game_project_from_template`
- 交付:模块内 8 项单测(schema/重复模板、键前缀、base 校验、解压逃逸、摘要与大小、安装记录、建项目与失败清理)。
- 验收:`cargo test --bin genarrative-ai-game-creator-shell template_library` 全绿。
3. **前端状态链路**
- `src/features/template-library/templateLibraryModel.ts`(类型与搜索/筛选纯函数)与 `useTemplateLibrary.ts`(拉取、下载、建项目、就地更新已下载状态)。
- `useHomeProjectCreation` 增加 `enterCreatedTemplateProject`,复用既有进项目通道。
- 交付:9 项模型单测。
- 验收:`npx vitest run src/features/template-library` 全绿。
4. **界面接入**
- 新增 `src/view/template-library/index.tsx` 全屏页;`LauncherView` 增加 `template-library`;左侧导航加模板库入口。
- 首页「灵感推荐」替换为 `TemplateRecommendations`;删除 `InspirationGallery.tsx``assets/inspiration/`
- `tauri.conf.json``img-src` 放行受信任 OSS 主机以加载封面。
- 验收:模板库页可搜索、筛选、下载、显示已下载并成功建项目;首页推荐位可跳转。
5. **文档与共享记忆**
- 主规范 `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`,并在 `docs/README.md` 建索引。
- 本里程碑与实施计划;`decision-log.md` 记录库路径、清单 schema、缓存目录与 CSP 约定。
- 验收:`node scripts/check-doc-index.mjs` 通过。
## 验证命令
```bash
cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library -- --ignored
cd apps/ai-game-creator-shell && npx tsc -p tsconfig.json --noEmit
npx vitest run apps/ai-game-creator-shell/tests/templateLibraryModel.test.ts apps/ai-game-creator-shell/tests/templateLibraryView.test.tsx
node scripts/agc-template-library-publish.mjs --source <dir> --dry-run
npm run check:encoding
node scripts/check-doc-index.mjs
git diff --check
```
## 风险与回退
- **封面走 WebView 直连**:仅放行受信任 OSS 主机;若日后改用后端签名,清单的 `coverKey` 不变。
- **模板包体积**:下载上限 512 MiB、解压文件数 4096、单文件 256 MiB;超限直接拒绝,不落盘。
- **清单漂移**:客户端只信「受信任主机 + 对象键」,清单中的地址字段不参与请求。
- **回退**:清空 `templates/` 前缀即回到空模板库;客户端保留错误与空态展示,不阻断其它功能。
@@ -0,0 +1,49 @@
# 【实施计划】AGC 渠道安装身份隔离
| 字段 | 值 |
| --- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】AGC渠道安装身份隔离-2026-09-21.md` |
| Status | ready |
| Owner | 当前 Agent |
## 修改边界
- 允许修改:
- `apps/ai-game-creator-shell/scripts/channel-identity.mjs`(新增,渠道身份单点定义)
- `apps/ai-game-creator-shell/scripts/build-release.mjs``build-macos-ci.mjs``check-config.mjs``agent-swarm-test-chat.mjs`
- `apps/ai-game-creator-shell/src-tauri/src/main.rs``src-tauri/src/windows.rs``src-tauri/src/config.rs`
- 对应测试:`build-release.test.mjs``prepare-macos-codex.test.mjs`
- 文档:AGC 更新主规范、共享记忆与本计划对
- 明确不修改:OSS 分区布局、官网下载接口与页面、Jenkins Job 参数、渠道版本发行逻辑、Apple 签名/公证、移动壳。
## 实现顺序
1. 抽出 `channel-identity.mjs`:渠道校验、渠道显示名、`resolveChannelInstallIdentity()``build-release.mjs` 复用并再导出渠道校验。
2. 渠道 `--config` 同时注入 `productName``identifier`;macOS 发布入口按发布渠道解析产品名(`.app`、updater 归档、DMG 卷名与文件名)。
3. Rust:主窗口/工作区/启动器窗口标题取构建期产品名;AGC 自有 AppData 目录的 ACL managed 识别覆盖 `<基线>``<基线>.<渠道>`
4. 门禁与测试:`check-config.mjs` 断言基线等于默认渠道身份、非默认渠道身份隔离;`build-release.test.mjs` 增补身份与首装包用例;`prepare-macos-codex.test.mjs` 改断言为消费渠道身份。
5. 文档:更新 AGC 更新主规范与共享记忆,登记决策与踩坑。
## 验证命令
1. `node --check apps/ai-game-creator-shell/scripts/channel-identity.mjs apps/ai-game-creator-shell/scripts/build-release.mjs apps/ai-game-creator-shell/scripts/build-macos-ci.mjs apps/ai-game-creator-shell/scripts/check-config.mjs`
2. `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs`
3. `node apps/ai-game-creator-shell/scripts/check-config.mjs`
4. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -- config::tests:: --test-threads=1`
5. `npm run check:encoding``npm run check:doc-index``git diff --check`
## 验证结果
- `node --test build-release.test.mjs release-oss.test.mjs prepare-macos-codex.test.mjs cargo-features.test.mjs`:64/64 通过(新增渠道身份、身份注入与渠道 DMG 首装选择三条用例)。
- `node apps/ai-game-creator-shell/scripts/check-config.mjs``npm --prefix apps/ai-game-creator-shell run typecheck`:通过。
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell -- config::private_path_elevation_policy_tests`12/12 通过。
- `AGC_UPDATE_CHANNEL=release npm --prefix apps/ai-game-creator-shell run build -- --no-bundle --debug`Tauri 接受派生的 `productName` / `identifier` 并完成构建;产物字符串实测 `陶泥儿 Release` × 1、`agc/release-win/latest.json` × 1、`world.genarrative.ai-game-creator.release` × 1、`agc/dev-win/latest.json` × 0。
- `cargo fmt --check`AGC 壳)、`npm run check:encoding``npm run check:doc-index``git diff --check`:通过。
- 未执行:真实渠道打包(需要签名私钥与发号/上传授权)、双渠道真机安装与并存、macOS 节点实跑。
## 风险与回滚点
- 风险:默认渠道身份若被改动,既有安装目录、卸载项与升级链会断。回滚点:基线 `tauri.conf.json` 与默认渠道映射不变,门禁用例钉住。
- 风险:非默认渠道首次以新身份安装,老 `dev` 用户不会自动迁移本地数据。回滚点:渠道身份只影响非默认渠道构建,撤销该渠道的构建产物即可,仓库侧无数据迁移。
- 风险:窗口标题改为构建期产品名后,标题不再等于配置里的字面量。回滚点:去掉 `main.rs` 的标题覆盖调用,行为回到配置标题。
- 风险:ACL managed 识别放宽到前缀族。回滚点:`is_game_creator_packaged_app_data_leaf` 收紧回单一直线值,但非默认渠道的提权修复会重新失败关闭。
@@ -26,19 +26,19 @@
## 问题状态
| 编号 | 问题 | 状态与证据 |
| --- | --- | --- |
| B01 | 刷新后首次进入画布元素抖动 | 已优化;用户在本轮反馈未再复现,按用户要求更新状态。不宣称所有布局/动画原因均已排除。 |
| B02 | 初次进入双指平移无效,整理后恢复 | 已优化;用户在本轮反馈未再复现,按用户要求更新状态。隔离组件连续平移通过。 |
| B03 | 快速平移触发更新深度错误 | 已修复已确认的窗口 Context 反馈循环,回归验证收敛;真实操作继续观察。 |
| B04 | 资源选中后运行不可用提示消失 | 已修复,提示与选择解耦,自动化验证通过。 |
| B05 | 对话记录偶发丢失 | 已修复日志复现的历史分页卡点:消息模式过滤后分页、原生游标与读取代次隔离。原生只读重放分 3 页取回全部 44 条现存消息,原文件未变;真实客户端待验收,不扩大为其它未落盘记录已恢复。 |
| B06 | JSON 文档未正确识别展示 | 已按用户确认完成本地修复:合法 UI State 由原生完整校验,卡片显示 UI 设计并进入现有编辑器;普通 JSON 显示 JSON 并可代码预览。自动化验证通过,待重建原生客户端验收;详见 JSON 语义识别实施计划。 |
| C01 | 右键平移,保留左键框选 | 已实现,卡片左键拖动、框选、指针取消/失焦/捕获丢失及控件边界测试通过。 |
| 编号 | 问题 | 状态与证据 |
| ---- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| B01 | 刷新后首次进入画布元素抖动 | 已优化;用户在本轮反馈未再复现,按用户要求更新状态。不宣称所有布局/动画原因均已排除。 |
| B02 | 初次进入双指平移无效,整理后恢复 | 已优化;用户在本轮反馈未再复现,按用户要求更新状态。隔离组件连续平移通过。 |
| B03 | 快速平移触发更新深度错误 | 已修复已确认的窗口 Context 反馈循环,回归验证收敛;真实操作继续观察。 |
| B04 | 资源选中后运行不可用提示消失 | 已修复,提示与选择解耦,自动化验证通过。 |
| B05 | 对话记录偶发丢失 | 已定位历史分页卡点,尚未修改。只读复验用户提供的历史:558 条合法原始记录中有 44 条聊天消息;首屏原始 20 条只投影出一条助手消息,下一页原始 20 条没有聊天消息,按消息计算的游标不推进。已存用户提问和最终回答因此无法继续翻出;不能凭该文件排除其它未落盘记录。 |
| B06 | JSON 文档未正确识别展示 | 已按用户确认完成本地修复:合法 UI State 由原生完整校验,卡片显示 UI 设计并进入现有编辑器;普通 JSON 显示 JSON 并可代码预览。自动化验证通过,待重建原生客户端验收;详见 JSON 语义识别实施计划。 |
| C01 | 右键平移,保留左键框选 | 已实现,卡片左键拖动、框选、指针取消/失焦/捕获丢失及控件边界测试通过。 |
## 已取得证据与剩余门禁
- 修复前新增回归测试能检出外壳重复发布、运行提示消失和右键无效;修复后窗口/画布定向测试通过,现有导航、框选、指针点击/取消、UI 编辑器返回平移和素材定位用例通过。
- AGC TypeScript、修改文件 ESLint、编码、文档索引及差异空白检查通过。
- 测试仍有既有 React 列表 key、旧用例 act/IPC 桩告警,未作为本批功能修复扩大范围。
- 用户反馈 B01/B02 本轮未再复现,记为已优化;右键手感与其它真实客户端细节继续观察。对话历史分页JSON 双路径已本地修复并通过定向验证,待重建原生端后真实客户端验收。本计划保持开放。
- 用户反馈 B01/B02 本轮未再复现,记为已优化;右键手感与其它真实客户端细节继续观察。对话历史分页尚未修复;JSON 双路径已本地修复并通过自动化验证,待真实客户端验收。本计划保持开放。
@@ -0,0 +1,61 @@
# 【实施计划】AGC 资源 kind Rust 枚举与 ts-rs 绑定
| 字段 | 值 |
| --- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化Rust绑定与内部收紧-2026-09-15.md` |
| Status | complete |
| Owner | Codex |
## 修改边界
允许修改:
- `server-rs/crates/shared-contracts` 内 GameCreationApp 资源 kind 的独立 Rust 模块;
- shared-contracts 的可选 ts-rs 绑定 feature
- ai-game-creator-shell 的 shared-contracts feature 引用和生成测试入口;
- shell 内生成的 GameCreationApp kind TypeScript 文件;
- 对应 Rust/TS 定向测试与文档 todo 证据。
本切片已落地:
- `GameCreationAppAssetManifestEntry.kind``String` 收紧为 `GameCreationAppAssetKind`:这是公开 Rust 类型的破坏性变更,按「不写历史兼容代码」直接改类型,不加兼容层、不做数据迁移;manifest 反序列化未知值收口为 `Unknown`
- 上传内容推断的字体写入 `Font`,未知上传类型写入 `Unknown`;图集切片 manifest 写入 `Icon`
- shell 内 manifest kind 的写入侧与读取侧统一为正式枚举成员:资源登记、字体导入、direct runtime 产物、平台美术登记与恢复、manifest 必填校验、资源编辑派生、UI 设计桥接与工作流。
- 资源编辑请求的 `sourceSubtype` 只传正式枚举成员;资源编辑内部源身份拆成「正式 kind / 项目版本 / Agent 回执」三类,项目版本与 Agent 回执不再冒充 manifest kind。
- ts-rs 绑定改由 `cargo test export_bindings` 生成:枚举自带 `#[ts(export, export_to = …/src/contracts/generated/)]`;退役的 `BindingDTO` / `BindingChange` 不再导出,手写的 `exports_ui_editor_types` 已删除。
- `packages/shared/src/contracts/generated/` 作为受控生成目录在 `.prettierrc.json` 中使用与 ts-rs 原始输出一致的格式选项,并在 `.gitattributes` 标记为 `linguist-generated`;生成文件仍参与 Prettier/ESLint 检查,`cargo test export_bindings` 可幂等复现且不再污染工作树。
- `Unknown` 表示解析边界无法判定的输入;写入方可以保留该结果,但必须明确决定拒绝写入或交由后续归类,不得把它误写成某个具体 kind。
- shell TS 资源引用边界消费生成绑定,资源 kind 集合从生成的 union 穷举派生,并为未知值保留原始值与上下文日志。
- api-server 图片快速编辑来源校验改为严格解析 `GameCreationAppAssetKind`,只允许共享枚举的静态图片成员;删除原有 legacy/兼容字符串白名单,退役值不再放行。
明确不修改:
- `category``mediaType``source.kind``source.generationKind`
- api-server 的其他资源 taxonomy、SpacetimeDB schema、OpenAPI;本切片只改图片快速编辑的 GameCreationApp manifest 来源校验。
- shared-contracts 的 canonical alias 表与读时自愈:alias 表已删除,严格解析和 `Unknown` 口径保持不变;
- `packages/shared` 中重复的资源 kind 手写契约与其余前端裸 `string` 字段(后续切片)。
## 实现顺序
1. 新建独立 kind 模块,定义当前正式成员:17 个现有 canonical kind + `font` + `Unknown`serde 使用 kebab-case。
2. 为 enum 增加可选 ts-rs derive,默认 shared-contracts 构建不引入 ts-rs。
3. 让 shell 的 shared-contracts 依赖打开绑定 feature;生成目录 2026-09-17 起收敛到 `packages/shared/src/contracts/generated/`(kind 是跨端契约,不再放 shell 私有目录)。
4. 增加 Rust serde round-trip 与 Unknown 解析/序列化测试;TS 侧不再手写生成值集合,改为从生成 union 穷举派生。
未知值通过 `parse_with_context` 收口到 `Unknown`,并把原始值与解析上下文交给壳层注册的 `app_log!` 回调(2026-09-17 起不再用 `tracing` / `kind-observability`)。
5. 运行 shared-contracts 与 shell 定向测试,并用 `export_bindings` 复现生成文件;完成后将稳定结论回写里程碑并关闭本计划。
## 验证命令
1. `cargo fmt --all -- --check`
2. `cargo test --locked -p shared-contracts game_creation_app --manifest-path server-rs/Cargo.toml`
3. `cargo test --locked -p shared-contracts export_bindings --manifest-path server-rs/Cargo.toml`(生成 `packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts`
4. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 shell 自己的 ts-rs 绑定)
5. `npx vitest run apps/ai-game-creator-shell/tests/assetKind.test.ts packages/shared/src/contracts/gameCreationApp.test.ts`(解析 Rust 源码的 `assetKindCanonicalMapping.test.ts` 2026-09-17 已删除:手写词汇表被移除后它没有比对对象)
6. `npm run check:encoding`
7. `git diff --check`
## 风险与回滚点
- 风险:ts-rs 默认生成 enum/union 形态与 serde rename 不一致;必须以生成文件和 round-trip 测试为准。
- 风险:shared-contracts 被 SpacetimeDB/WASM 使用;ts-rs 必须是 optional feature,默认构建不可依赖。
- 回滚点:本切片仅新增 enum/绑定,不改变现有 manifest JSON 解析;若生成链路不稳定,可回滚本提交而不影响现有业务。
@@ -0,0 +1,43 @@
# 【实施计划】AGC 资源 kind 词汇审计与绑定架构
| 字段 | 值 |
| --- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md` |
| Status | complete |
| Owner | Codex |
## 修改边界
允许修改:
- 主规范中的资源 kind 当前口径;
- `docs/project-memory/plans/` 下本任务的里程碑/实施计划;
- `docs/project-memory/todos/` 下本任务的扫描清单;
- 为审计提供只读扫描脚本(如确有必要,脚本也只覆盖 shell)。
明确不修改:
- 已完成的 `apps/ai-game-creator-shell` 业务收口不再属于未决范围;后续只允许按新里程碑变更;
- server-side 代码、OpenAPI、SpacetimeDB schema
- MIME、`source.kind``generationKind` 和其他字符串领域。
## 实现顺序
1. 按“manifest asset kind / 其他字段 / 仅文本同名”三类扫描 shell 的 `kind``assetKind``asset_kind` 和 manifest 构造器。
2. 对每个候选值回到调用上下文,标记生产写入、读取投影、协议输入、测试 fixture 或纯文本/路径。
3. 对照 api-server 当前有效资源 kind,排除 legacy、billing/storage synthetic taxonomy 和开放字段。
4. 记录正式候选 enum、Unknown 输入行为、保留字符串字段和后续 PR 边界。
5. 形成下一里程碑的文件级修改顺序和验证矩阵;本里程碑结束后暂停,等待验收。
## 验证命令
1. `rg -n 'kind|assetKind|asset_kind' apps/ai-game-creator-shell/src apps/ai-game-creator-shell/src-tauri/src`
2. `npm run check:doc-index`
3. `npm run check:encoding`
4. `git diff --check`
## 风险与回滚点
- 风险:同一字符串可能是 manifest kind、workflow kind 或路径名;任何未回到上下文确认的替换都禁止进入代码。
- 风险:shared-contracts 被多个 server crate 使用;ts-rs 生成必须通过 feature/独立入口隔离默认构建。
- 回滚点:本里程碑只有文档和审计清单变更;若词汇边界未能闭合,删除本计划和 todo,不进入代码里程碑。
@@ -0,0 +1,51 @@
# 【实施计划】AGC 音频生成进入后台任务账本
| 字段 | 值 |
| --- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md` |
| Status | implemented-awaiting-runtime-acceptance |
| Owner | 主 Agent(自审;本运行没有独立评审人) |
## 修改边界
- 允许修改:
- 主规范:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`(§3.10 / §7.9)、`docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md`
- AGC 原生:`apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs``commands.rs``project.rs``project/resource_editor.rs`(仅新增收口入口,不改既有派生语义)。
- AGC 前端:`apps/ai-game-creator-shell/src/features/resource-canvas/resourceCanvasAssetGenerationTaskModel.ts``resourceCanvasAssetGenerationQueue.ts``view/project-development/index.tsx`
- 定向测试:`apps/ai-game-creator-shell/tests/resourceCanvasGenerationHostLifecycle.test.tsx``resourceCanvasAssetGenerationQueue.test.ts``appSurface/project-development.suite.ts`(仅音频相关断言)。
- 明确不修改:`/api/editor/audios/*/generations``/api/external/v1` 路由、请求体、OpenAPI、共享 DTO、SpacetimeDB schema、权限命令词汇、`derive_local_project_resource` 的同步语义与其既有无源生成入参校验。
## 实现顺序
1. 主规范:把音频入口的接线口径从「同步无源生成」改写为「与图片类同一条后台任务账本」,并补上音频提交载荷、失败重开与幂等条款(PRD §3.10 / §7.9,AGC 工具栏入口矩阵文档)。
2. 原生:在资源编辑模块新增音频入参收口与「后台跑一次音频派生」的入口(复用既有派生实现,不复制生成逻辑);在 `asset_generation_tasks` 里按 `kind` 分流,音频任务复用同一份账本、同一套阶段文案与中断收口;`start_local_project_asset_generation` 增加可选幂等键入参,音频 kind 走新分支且不改图片类载荷口径。
3. 原生测试:音频任务入参收口(kind / 提示词上限 / 幂等键 / 未知 kind 拒绝)、账本记录 kind 为音频、图像载荷口径不回归。
4. 前端模型与队列:任务模型支持音频任务(kind、请求身份、无比例 / 尺寸 / 参考字段),音频 kind 的入口文案从工具栏模型派生;队列按 kind 分流派发同一命令的音频载荷,其余排队与轮询语义不变。
5. 前端宿主:音频提交改为「入队即返回」,占位绑定任务 id、自动展开侧栏、给出提示条;收口复用既有「配对读 + 落卡」链路,未受理失败按原请求身份重开音频面板。
6. 前端测试:宿主生命周期(提交即关闭、侧栏可见、落卡、未受理失败重开并复用身份)、队列音频分支(载荷与轮询、第二条本地排队不发 IPC)、appSurface 音频载荷。
7. 验证与证据矩阵:跑定向测试、类型检查、编码 / 文档索引 / `git diff --check`,按里程碑逐条填写证据。
## 验证命令
1. `npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasGenerationHostLifecycle.test.tsx apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationQueue.test.ts apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationTasksPanel.test.tsx`
2. `npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts`
3. `cargo test -p genarrative-ai-game-creator-shell asset_generation_task`
4. `npm run agc:typecheck`(或 `npm run typecheck --workspace @genarrative/ai-game-creator-shell`
5. `npm run check:encoding && npm run check:doc-index && git diff --check`
## 执行结果
1. 主规范:PRD(§3.10 / §7.9 / §7.9 第 8~9 条)与 AGC 工具栏入口矩阵文档改为「音频与图片类同一条后台任务账本」,同步 `【测试用例】AGC资源工作台V3端到端验收` 的 S11a 判据。
2. 原生:`prepare_local_project_audio_generation`(提交期收口)+ `run_local_project_audio_generation_at`(派发时刻读 revision,复用派生实现),`start_local_project_asset_generation` 新增可选 `idempotencyKey` 并在音频 kind 分支落同一份账本、由 `run_local_project_audio_generation_task` 写 running → completed / failed;图片类分支逐字未改。
3. 前端:任务模型新增音频任务与 `idempotencyKey`(恢复出来的历史任务不带它,也不承接重试);队列按 kind 分流派发载荷;面板提交改为同步返回并立即关闭;宿主改为同步入队 + 失败重开。
4. 测试:面板(点击即关闭、无阶段文案与在途按钮)、队列(音频载荷逐字)、宿主生命周期(提交关闭 / 侧栏 / 落卡 / 未受理重开 / 受理后不重开 / 重试身份复用 / 失败态按占位隔离)、appSurface 音频载荷。
5. 验证命令与结果:9 个定向 vitest 文件 73 项通过;`appSurface.test.ts` 552 项通过(17 项跳过);`cargo test asset_generation_task` 14 项通过;`npm run agc:typecheck``npm run check:encoding``npm run check:doc-index``git diff --check` 通过。
6. 与预期不一致处:音频任务不再携带 `targetCategory`(原生音频通道不消费它,前端也没有读它的地方);`restored` 任务无幂等键,只用于展示与定位,不承接重试。
7. 已知与本任务无关的既有失败:`clientAuthStorage` / `clientApi` / `clientHttp` / `chatPromptPolish` / `projectCreationDirectory` 五个文件在本机 Node v26 + vitest 0.34 的 jsdom 下 `localStorage` 为 undefined(在干净工作区同样失败);`cargo test resource_edit` 整组过滤下有 5 项既有并行干扰失败(单跑通过)。
## 风险与回滚点
- 音频任务与图片类任务共用队列:若音频任务未终态会挡住后续派发(本地排队是既有语义,接受)。回滚点是前端提交分支与原生 `kind` 分流,各自可独立回退。
- 音频自带的 operation 幂等账本与任务账本是两层身份:任务 id 取 operation id,重试复用同一对 operation / 幂等键;不得为「省事」在重试时换新的请求身份(那是一次新的付费生成)。
- 账本 `kind` 为音频时,`restore` 的入口文案若查不到工具栏模型会退化成素材名:入口文案必须由工具栏模型派生,避免恢复后文案漂移。
- 后台跑生成会让「项目 revision CAS」窗口从提交前移到派发时刻:冲突时按失败收口(不静默重试),避免把生成写到非预期基线。
@@ -0,0 +1,68 @@
# AGC 项目创建目录可选实施计划
Version: 1.0
Status: active
Date: 2026-09-17
Related Spec: `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md``docs/【技术方案】AGC异步操作可恢复闭环-2026-09-14.md`
## 目标
让用户在 AGC 里能自己选项目创建目录:首页「做游戏 / 做方案」自动建项与模板库「使用模板」建项都落在用户选定的目录下;不选时保持 AGC 管理的默认位置(`<app_data>/projects`),行为与现状一致。
## 交接结果
- `create_automatic_local_game_project``create_automatic_local_game_project_from_template` 新增可选参数 `projectsRoot`;为空时由 Rust 侧回落到默认目录。
- `pick_local_project_directory` 新增可选参数 `title`(只接受短标题,其余回退「选择游戏项目目录」)。
- 新增用户偏好「项目创建目录」:`localStorage``genarrative-ai-game-creator.project-creation-directory.v1`
- 入口在客户端设置里:侧边栏「配置」→ 设置分类「工作区」;`RuntimeConfigDialog` 内用 `useProjectCreationDirectory` 展示与改选目录,不经过首页或模板库页头。
- 首页「做游戏 / 做方案」与模板库「使用模板」建项时读取同一份偏好,用户不需要在建项前再选一次。
## 行为契约
- 允许的来源只有一个:本机原生目录选择器(`pick_local_project_directory`)。它返回的目录已在选择时按 user-selected 范围做过一次加固,构成「用户显式选择」边界。
- Rust 侧 `validate_requested_game_project_creation_root` 对传入目录要求:非空、绝对路径、无控制字符、已存在的普通目录(符号链接 / Windows reparse point / 普通文件一律拒绝),并通过 `prepare_game_creator_project_root_for_read`user-selected 范围的一次性修复)。目录不存在时不代为创建,直接失败。
- 建出的项目目录仍在所选目录下按 `gameagent-<8位短ID>` 命名,项目名、`.agent` 初始化、首轮投递与既有自动建项完全一致。
- 偏好只保存「用户意图」,不是授权凭据:存储被外部改动最坏只是回退默认位置或一次可见的建项失败,不会跳过 Rust 门禁。
- 该偏好是客户端本地设置,不写入 `read_game_creator_app_config` / 保存设置的那份运行时配置:在「工作区」里选择目录当场生效,与「保存设置」按钮无关。
- 「恢复默认位置」清空偏好即回到应用数据目录;既有项目不迁移。
## 步骤
1. **Rust 建项入口**
- `commands.rs`:新增 `validate_requested_game_project_creation_root` / `resolve_game_project_creation_root``create_automatic_local_game_project` 接受 `projects_root``pick_local_project_directory` 接受 `title`
- `template_library.rs`:模板建项复用同一解析函数。
- 交付:两条定向单测(校验矩阵、在指定创建目录下建项)。
- 验收:`cargo test --bin genarrative-ai-game-creator-shell creation_root` 全绿。
2. **前端偏好与入口**
- `features/app-shell/model.ts``normalizeProjectCreationDirectory` / `readProjectCreationDirectory` / `writeProjectCreationDirectory` / `projectCreationDirectoryLabel`
- `useProjectCreationDirectory`:选择目录、恢复默认、状态文案(失败在设置页字段内可见)。
- `RuntimeConfigDialog` 新增「工作区」设置分类,承载「项目创建目录」字段与「选择目录 / 恢复默认位置」动作。
- `useHomeProjectCreation``useTemplateLibrary` 在建项时带上 `projectsRoot`
- 交付:偏好模型 4 项单测、设置页 1 项交互测试、appSurface 1 项「设置里选目录后建项」端到端场景。
- 验收:`npx vitest run apps/ai-game-creator-shell/tests/projectCreationDirectory.test.ts apps/ai-game-creator-shell/tests/appSurface.test.ts` 全绿。
3. **文档与共享记忆**
- 本实施计划;模板库技术方案的命令表补 `projectsRoot``decision-log.md` 记录偏好键与命令参数;`pitfalls.md` 说明用户自选目录与 AGC 管理目录的关系。
- 验收:`node scripts/check-doc-index.mjs` 通过。
## 验证命令
```bash
cargo check --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell creation_root
cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell template_library
cd apps/ai-game-creator-shell && npx tsc -p tsconfig.json --noEmit
npx vitest run apps/ai-game-creator-shell/tests
npm run check:encoding
node scripts/check-doc-index.mjs
git diff --check
```
手动验收(客户端内):侧边栏「配置」→「工作区」→「选择目录」选 `F:\Projects\我的游戏`,回首页建项后项目目录应为 `F:\Projects\我的游戏\gameagent-<8位>`;模板库「使用模板」建项同样落在该目录;点「恢复默认位置」后再建项回到应用数据目录。
## 风险与回退
- **自选目录无法加固**`Documents` 等带受保护继承 ACL 的位置可能加固失败。失败发生在选择器或建项前置校验阶段,报错可见且不会留下半成品项目;用户改选其它目录或用默认位置即可。
- **偏好漂移**:偏好只是提示值,每次建项都会重新校验;存储被改坏不会绕过门禁。
- **回退**:删掉偏好键(或点「恢复默认位置」)即回到默认目录;需要彻底移除该能力时,去掉两个命令的可选参数与设置页字段即可,Rust 默认路径逻辑不变。
@@ -0,0 +1,27 @@
# 【实施计划】DirectProject Skill 提及输入提示
| 字段 | 值 |
| --------- | ----------------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject Skill提及输入提示-2026-09-15.md` |
| Status | in-progress |
| Owner | Codex |
## 代码边界
- 前端:`features/project-workspace/ResourceReferenceInput.tsx``ResourceReferenceNode.tsx``resourceReferences.ts`、生成绑定及聊天入口透传。
- Rust`agent/direct_codex_user_item/model.rs``validation.rs``wire.rs``codex_app_server/mod.rs` 与对应测试。
- 文档:父规范与本里程碑/实施计划。
## 小切片顺序
1. 先扩展前端 Skill catalog/节点/草稿 content,保持素材行为不变并补前端测试。
2. 扩展 canonical Rust part 与 ts-rs 绑定,补序列化和失败校验测试。
3. 接通 Codex wire `type: skill` 转换和受控路径解析,补历史/重放测试。
4. 完成入口透传、定向验证和文档证据;每个切片单独中文提交。
## 验证与回滚
- `npm --prefix apps/ai-game-creator-shell run typecheck`
- 相关 Vitest 与 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_codex`
- `npm run check:encoding``npm run check:doc-index``git diff --check`
- 每个切片只改计划列出的文件;若 Codex wire 协议或 Skill catalog 来源不确定,停在该切片并先更新规范。
@@ -1,10 +1,10 @@
# 【实施计划】DirectProject Thread Manager 事件订阅
| 字段 | 值 |
| --- | --- |
| 字段 | 值 |
| --------- | ---------------------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject Thread Manager事件订阅-2026-09-15.md` |
| Status | ready |
| Owner | Codex |
| Status | ready |
| Owner | Codex |
## 修改边界
@@ -0,0 +1,42 @@
# 【实施计划】DirectProject canonical content 严格边界
| 字段 | 值 |
| --------- | ------------------------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md` |
| Status | implemented |
| Owner | Codex |
## 实施顺序
1. 先把主转换函数改为原样传递 `draft.content`,并在 content-only 测试中覆盖空白 part 保留。
2. 将最终 content 有效性判断抽为纯函数,接入普通提交、队列入队和其它 Direct Codex 入口。
3. 删除 Direct Codex 的 `userItem` fallback;首页首轮和队列出队直接构造 canonical user item。
4. 收敛策略确认重试为复用同一 canonical user item;旧 Supervisor/Planning caller 加 TODO,不改变其非 Direct Codex 行为。
5. 迁移现有测试 fixture,删除旧字段构造,不增加“字段不存在”测试。
## 落地结果
- `chatComposerDraftToDirectCodexUserItem` 原样传递 `draft.content`;新增 `directCodexUserItemFromContent` 供 caller 直接构造 canonical item。
- `ChatComposerDraft` 只保留 `content``ResourceReferenceInput` 的对外草稿、`chatPromptDraftKey``QueuedChatTurn` 全部改为 content-only。
- 首页首轮、普通聊天提交、运行中队列出队、策略确认重试都携带同一个 canonical user item`executeChatAgentReply``userItem` 兜底分支已删除。
- 旧 Planner / legacy Supervisor caller 显式构造纯文本 item 并留下迁移 TODO。
## 修改边界
- 允许修改:AGC shell 前端 `resourceReferences``App`、聊天队列、Direct Codex 相关测试和当前里程碑文档。
- 不修改:Rust user item schema、附件 DTO、SpacetimeDB、HTTP API、用户已有 `.env` / `package-lock.json` 修改。
- 不引入:`text` / `references` 到 canonical Direct Codex item 的任何兼容 fallback。
## 验证命令
- `npm run test -- apps/ai-game-creator-shell/tests/resourceReferences.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx apps/ai-game-creator-shell/tests/chatPromptPolish.test.tsx apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts`
- `npm run ai-game-creator-shell:typecheck`
- `npm run check:encoding`
- `npm run check:doc-index`
- `git diff --check`
## 风险与回滚点
- 空白 `input_text` 不再前端删除,需确保最终有效性判断只拒绝全空 content,不改变其它 part。
- Direct caller 漏传 user item 时应在类型检查或明确错误分支暴露,不能静默重建。
- 共享工作树含用户未提交修改;提交时只 stage 本计划和本次代码 hunk。
@@ -0,0 +1,64 @@
# 【实施计划】DirectProject composer canonical content 闭环
| 字段 | 值 |
| --------- | --- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject composer canonical content闭环-2026-09-21.md` |
| Status | implemented |
| Owner | Codex |
## 交付结果
删除 Direct composer 的 `text + references` 回写事实源,改为完整 `content[]` 的单向读写;同时修复附件在 editor root 重建、润色回填和提交合并中的丢失窗口。Planning V2 / 快速编辑只保留明确的非 Direct adapter,不进入 Direct canonical 发送路径。
## 实施顺序
1. **锁定当前失败面**:补一个最小回归测试,先证明 `applyDraftToRoot` 对含 `agc_attachment_reference` 的 root 重建会丢附件,并记录 Direct 当前的三份并行状态与附件 sidecar 合并点。
2. **收窄编辑器接口**:把 `ChatComposerDraft` 改成 content-only;将 `ResourceReferenceInput` 的受控恢复改为 `initialContent` / `content` 语义,删除 Direct 使用的 `value` + `references` 同步 effect。保留 `ChatReference` 仅用于 picker 节点创建和只读投影。
3. **替换所有 root 写入**:删除 `buildDraftSegments` / `applyDraftToRoot` 的 Direct 调用;提供一个完整的 `applyContentToRoot`(或同等深模块接口),保留文本换写、引用和附件的顺序与字段。AI 润色改为“读取 content → 对回包文本按 token 扫描 → 原位换回真 part;被改写的 part 末尾补位”,引用与附件同一套口径。
4. **收口 Direct controller**:以 `content[]` 作为草稿事实源;上传完成的附件在一个明确的 `append`/`merge` seam 合并,不再长期维护 `chatInput``chatReferences``chatContent` 三份状态。prompt 只在调用边界派生,队列和策略重试保留原 user item。
5. **隔离非 Direct caller**Planning V2 和资源快速编辑按各自需求选择 content-only 或独立文本 adapter;不得为了兼容它们把旧字段放回共享 Direct 接口。若快速编辑只需要文本,使用不承诺引用/附件语义的窄接口。
6. **补齐验收证据并清理**:删除无调用方的旧 helper、字段和注释;更新测试 fixture、专题文档和本计划状态。完成后把稳定结论合并回功能说明/共享记忆,并删除已完成的临时计划。
## 重点修改边界
- `apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`
- `apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts`
- `apps/ai-game-creator-shell/src/features/project-workspace/usePromptPolish.ts` / `chatPromptPolish.ts`(仅在需要支持 content 变换时)
- `apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts`
- `apps/ai-game-creator-shell/src/view/project-development/chat/components/DirectProjectComposer/`
- `apps/ai-game-creator-shell/src/view/project-development/planning/PlanningChatView.tsx``App.tsx` 中 Planning adapter
- `apps/ai-game-creator-shell/src/view/project-development/index.tsx` 的快速编辑输入 adapter
- 对应 `resourceReferences``resourceReferenceInput``chatPromptPolish`、Direct composer/appSurface 测试
## 关键不变量
- `content[]` 是唯一可发送事实;任何 `prompt`、label、chip 文案都是派生值。
- `agc_attachment_reference` 不属于 `ChatReference`,不能借 `references` 传递。
- 润色回包只按 token 反解析引用与附件(`draftScanToken` 与出站 `directCodexContentToPromptText` 同口径);token 被删掉时不猜位置,只把该 part 补在末尾,保证不丢。
- Direct 初始首轮、普通提交、队列、权限确认重试都使用同一个 `DirectCodexUserItem` 语义。
## 验证命令
```bash
npm run test -- apps/ai-game-creator-shell/tests/resourceReferences.test.ts apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx apps/ai-game-creator-shell/tests/chatPromptPolish.test.tsx apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts
npm run ai-game-creator-shell:typecheck
npm run check:encoding
npm run check:doc-index
git diff --check
```
## 风险与回滚点
- `ResourceReferenceInput` 当前同时服务 Direct、Planning、快速编辑;先建立 adapter seam,再删除旧 props,避免一次性把策划链路打坏。
- 附件目前在 Direct controller 里作为待发 sidecar,若直接移入编辑器必须同步处理上传失败、移除、清空和项目切换;任何阶段都不能把附件只留在展示 chip 而未进入 user item。
- 润色服务只返回文本,不能让其响应覆盖原 content;失败时保留原 content。回滚使用 Git revert,不增加运行时开关或兼容分支。
- 工作树已有用户未提交修改,实施时只 stage 本里程碑涉及的 hunk。
## 落地结果
- 编辑器接口收窄为 content-only`ResourceReferenceInput` 只接 `initialContent` / `onChange``ChatComposerDraft` 只剩 `content``applyDraftToRoot` 与受控 `value` / `references` 同步 effect 均删除。
- 所有 root 写入统一走 `applyContentToRoot`;润色走 `applyPolishedTextToRoot`,对引用与附件做同一套 token 扫描并在原位置换回真 part,被改写的 part 末尾补位。
- Direct controller 去掉 `chatInput` / `chatReferences` / `chatContent`,附件在提交边界合成进同一份 canonical contentPlanning 与其它 legacy 消费方改用 `directCodexContentToLegacyContentDto` 单向取文本。
- 删除无调用方的 `EMPTY_CHAT_COMPOSER_DRAFT`
- 回归证据:`resourceReferenceInput`(含附件 round-trip、润色原位恢复、润色末尾补位)、`resourceReferences``chatPromptPolish``usePromptPolish``resourceCanvasAssetGenerationReferences`、全量 `appSurface`、AGC typecheck、`check:encoding``git diff --check`
- 遗留 TODO:润色服务把 token 一起删掉时无法反推原位置;需要精确恢复时由产品补带位置信息的润色协议。
@@ -1,15 +1,16 @@
# 【实施计划】DirectProject 用户 Response item 输入
| 字段 | 值 |
| --- | --- |
| 字段 | 值 |
| --------- | ------------------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject用户ResponseItem输入-2026-09-15.md` |
| Status | in-progress |
| Owner | Codex |
| Status | in-progress |
| Owner | Codex |
## 修改边界
- 允许修改:AGC 壳 Rust agent 输入合同、DirectProject 历史适配、前端聊天引用模型、ts-rs 生成配置、当前聊天素材文档。
- 明确不修改:assistant 返回协议、工具 activity、附件/图片协议、SpacetimeDB、HTTP API。
- 明确不修改:assistant 返回协议、工具 activity、附件/图片上传 DTO、SpacetimeDB、HTTP API;上传 DTO 仅在入口转换为 canonical `content[]`,不再以 sidecar 文本追加
- 本切片明确:不根据 MIME 类型判断图片,不生成 `agc_image_reference`;所有上传文件统一映射为 `agc_attachment_reference`
## 实现顺序
@@ -0,0 +1,95 @@
# 【实施计划】DirectProject 聊天模块抽离
| 字段 | 值 |
| --------- | ----------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject聊天模块抽离-2026-09-18.md` |
| Status | implemented |
| Owner | Codex |
## 修改边界
### 允许修改
- `apps/ai-game-creator-shell/src/App.tsx`:删除 DirectProject 专属状态、ref、effect、订阅/历史/发送/队列/附件/中止处理和 Direct 专属 JSX 接线;保留项目开发工作台壳与 DirectProject / 立项策划两条入口的选择。
- `apps/ai-game-creator-shell/src/view/project-development/chat/DirectProjectChatView.tsx``useDirectProjectChatController.ts``generated/`:新增 DirectProject 表现容器、controller 及其 ts-rs 契约目录;共享 reducer/分页/队列模块只引用这份 Direct 契约,不复制类型。
- `view/project-development/chat/``view/project-development/planning/`:普通项目的对话归 `DirectProjectChatView`Design Agent 与 Planning V2 归 `PlanningChatView`;行为中立的公共表现组件按需复用或抽出。
- `DirectProjectSettingsDialog``ProjectDevelopmentView`:移除聊天侧钱包注入和聊天设置中的钱包行,在工作台布局头部/工具栏独立渲染钱包入口,保留账户入口功能。
- 现有 DirectProject 测试文件:按新模块责任迁移 import、测试入口和 harness,不新增场景或断言集合。
- 当前 ADR、里程碑和实施计划文档,以及必要的 `CONTEXT.md` 术语。
### 明确不修改
- Rust、Tauri 命令、共享 DTO、Thread Manager、Codex app-server 和 `.agent/conversations/project.jsonl` / 运行态事件合同。
- DirectProject 的路由判定语义、模型配置语义、聊天投影规则、历史锚点与分页协议。
- DirectProject、Design Agent、Planning V2 的正式行为与页面入口。
- 任何运行时 feature flag、兼容别名、双跑路径或旧行为墓碑代码。
## 实现顺序
1. 以当前测试为基线,标记 DirectProject 断言归属:纯 reducer/投影/分页/附件测试归内部模块,Composer 的队列/恢复/中止断言归 Direct 容器 harness,项目开发页面只保留入口接线断言;不增加新测试场景。
2. 建立 `direct-project-chat/` 私有模块边界,复用现有 `directThreadChat``directHistoryPaging``directHistoryAnchorGate``directTurnPresentation``chatComposerQueue` 与附件映射,不复制第二套事实源或 reducer。
3. 将 DirectProject 生命周期整体搬入 `DirectProjectChat`:项目切换清理、订阅 bootstrap/notify/consume、首屏锚点、历史连拉、用户回合预写、Direct invoke、鉴权重试、FIFO 出队、附件上传、中止 released 分支和 manifest 刷新均由该容器管理。
4. 将 Direct 专属 JSX 从工作台聊天宿主移入 Direct 表现模块:Direct 回合分区、运行中过程卡、Direct Composer、队列、附件、模型/推理选择、语音、中止、Direct 设置;共享组件只保留无行为真相的视觉表现。
5. 项目开发工作台固定挂载 `DirectProjectChat`;立项策划(Design Agent、Planning V2)进入 `PlanningChatView`;删除 `directCodex` 作为共享组件行为开关及所有只服务它的 props,不保留 Direct fallback 或运行时 feature flag。
6. 将钱包从聊天树移到 `ProjectDevelopmentView` 的工作台头部/工具栏:删除 `cloneElement` 对聊天元素的注入,删除 `DirectProjectSettingsDialog` 的钱包行和 Direct 上下文字段;钱包入口仍由布局直接渲染。
7. 把现有测试按所有权迁移并运行定向验证;若发现行为差异,只修复抽离造成的回归,不扩展产品范围。完成后删除旧 Direct 分支与无 caller 的兼容代码。
## 测试迁移映射
| 现有测试 | 新归属 |
| --------------------------------------------------------------------------------------- | ------------------------------------------- |
| `directThreadChat.test.ts` | Direct 事件/历史状态模块 |
| `directHistoryPaging.test.ts` | Direct 历史分页模块 |
| `directHistoryAnchorGate.test.ts` | Direct 订阅锚点模块 |
| `directTurnPresentation.test.ts` | Direct 聊天投影表现模块 |
| `directCodexTurnAttachments.test.ts` | Direct 附件模块 |
| `chat-composer.suite.ts` 的 FIFO、恢复出队、终止与竞态用例 | Direct 容器/发送队列 harness |
| `project-development.suite.ts` 的 Direct 入口、历史、工具卡片、运行态隔离和连续回合用例 | Direct 容器接线;仅迁移测试入口,不新增场景 |
## 验证命令
1. `npx vitest run apps/ai-game-creator-shell/tests/directThreadChat.test.ts apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts apps/ai-game-creator-shell/tests/directHistoryAnchorGate.test.ts apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts apps/ai-game-creator-shell/tests/directCodexTurnAttachments.test.ts`
2. `npx vitest run apps/ai-game-creator-shell/tests/appSurface/chat-composer.suite.ts apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts`
3. `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`
4. `npm run check:doc-index`
5. `npm run check:encoding`
6. `git diff --check`
## 风险与回滚点
- **状态遗漏**:任何 Direct 专属 state/ref/effect 留在 `App.tsx` 都会形成双重所有权;以 `rg` 扫描 Direct 专属符号和 `directCodex` props 作为删除检查。
- **事实源漂移**:不得在新容器里重新维护 messages、turn-stream 或 tool-calls 副本;继续只使用项目对话历史、运行态事件和聊天投影。
- **竞态回归**:重点检查 subscribe 回执前 notify 欠账、首屏锚点闸门、`turn.completed` 与 invoke finally 的 FIFO 出队窗口、提交早于 `turn.started` 的中止以及项目切换时附件/队列清理。
- **布局回归**:钱包必须在工作台布局头部/工具栏出现,且聊天设置不再包含钱包行;账户入口功能不能因聊天抽离丢失。
- **回滚**:本次采用一次性替换;失败时整体 Git revert,不保留旧/新双路径或运行时 fallback。
## 实施记录(2026-09-19
### 模块落位
`apps/ai-game-creator-shell/src/view/project-development/chat/` 最终结构:
| 目录 | 内容 |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DirectProjectChatView.tsx` | 唯一公开入口:项目路径、入口首轮需求、两条权限门,以及对壳的 `announce` 句柄 |
| `components/` | 表现层,一个组件一个目录、逻辑与组件同目录:`DirectProjectChatHeader/``DirectProjectComposer/`(含 `ComposerControls.tsx``chatComposerQueue.ts``chatComposerVoice.ts`)、`DirectProjectConversation/`(含 `DirectProjectTurn.tsx`)、`DirectProjectSettingsDialog/``ToolCallGroup/`(含 `toolCallGroupPresentation.ts` |
| `controller/` | `useDirectProjectChatController`(发送/队列/附件/中止/历史分页)、`useDirectProjectManifest`(清单与 `projectId` 订阅)、`useDirectThreadChatSubscription``subscribe → consume → notify` 单飞循环 + 聊天 reducer 状态) |
| `conversation/` | `directThreadChat.ts`reducer)、`directThreadItemProjection.ts``directTurnPresentation.ts``directCodexConversation.ts``directCodexSession.ts``directCodexTurnAttachments.ts` |
| `history/` | `directHistoryPaging.ts``directHistoryAnchorGate.ts` |
| `generated/` | Rust ts-rs 导出的 Direct 契约 |
### 关键取舍
- 线程订阅与聊天 reducer 状态从控制器里提成独立 hook `useDirectThreadChatSubscription`:运行态事实源只有它一份,控制器只读投影结果,历史分页仍并入同一个 reducer。
- 工作台级动作(如 `game.run_local` 的预览结果)不再写 `App.tsx``messages`:壳通过 `DirectProjectChatHandle.announce` 把这句话交给聊天的本地消息流,壳不持有 Direct 聊天消息。
### 验证结果
- `npx vitest run` 五个 Direct 纯模块测试:40 通过。
- `npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts -t "direct"`:15 通过 / 4 失败,且 4 条在本次改动前(`HEAD``/tmp` worktree 基线)同样失败(用例期望 `chat_with_game_creator_direct_codex` 被调用,但 harness 未桩 `read_game_creator_app_config`,模型可用性校验把提交挡在 invoke 之前;另两条是既有交互断言)。基线同口径为 14 通过 / 5 失败,本次净增 1 条通过。
- `npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts` 全量:153 失败 / 307 通过 / 17 跳过;`HEAD` 基线同口径 155 失败 / 305 通过。
- `npx tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit``npx eslint --ext .ts,.tsx``npx prettier --check` 通过。
### 本计划外的后续项
- Supervisor 前端链路已随本计划之后的变更整体退役(Supervisor 独立调试窗口、纯聊天容器、工作台壳的 Supervisor 运行态与专业 Agent 面板、`App.tsx` 里只服务它们的 state/ref/effect/handler 全部删除),项目对话只保留 DirectProject 与立项策划两条产品路径;见 [decision-log](../shared-memory/decision-log.md) 2026-09-19 条。
@@ -0,0 +1,43 @@
# 【实施计划】DirectProject 聊天真相源收敛
| 字段 | 值 |
| --------- | ------------------------------------------------------------------------------- |
| Milestone | `docs/project-memory/plans/【里程碑】DirectProject聊天真相源收敛-2026-09-16.md` |
| Status | implemented |
| Owner | Codex |
## 修改边界
- 允许修改:`agent/direct_thread_wire.rs``agent/direct_thread_manager.rs``agent/codex_app_server/``agent/direct_project_history.rs``main.rs` 命令注册、`src/features/project-workspace/generated/`(ts-rs 生成目录)、AGC 前端订阅与聊天投影、对应测试与 `docs/`
- 明确不修改:SpacetimeDB schema 与绑定、HTTP/OpenAPI、DirectRuntime 自己的进度事件与 `turn-stream.jsonl` / `tool-calls.jsonl` 写入、Codex durable thread 行为、审批弹层现有状态来源。
- 保持 `.env` 未提交修改,不触碰个人配置。
## 实现顺序
1. Rust 只搬运:`agent/direct_thread_wire.rs` 把 Codex 原始条目挑字段、脱敏、截断后下发,事件载荷与历史切片同形,不生成卡片形状;线上模型是 ts-rs 导出的 tagged enum`DirectThreadItem` / `DirectThreadEvent` / bootstrap / consume / history slice),`at``#[ts(as = "f64")]`,改完模型跑 `cargo test export_bindings` 生成前端绑定。
2. 条目身份归一:进队列前收敛成一个 `itemId`,事件 envelope 与前端形状里都不出现第二个 id 概念;历史切片的 `firstItemId` 继续取文件里的原始 item id。
3. 删掉回合身份:`turn.started` 无载荷、`turn.completed{status}`,条目 / 增量 / 请求 / 生命周期锚点都不带 turn id;队列 `append` 直接收 `DirectThreadEvent``seq` 内部自算。
4. 思考正文流式:`item/reasoning/summaryTextDelta``item/reasoning/textDelta` 产出 `item.delta{kind:"reasoning"}`;plan 文本与命令输出保持活动状态。
5. 前端收敛为单一 reducer`subscribe` 返回的 bootstrap 事件就是已暂存的运行态,游标已经在队尾,前端直接 reduce 这批事件即可(不需要为了拿这批事件再补一次 `consume`);此后只由 notify 唤醒 `consume`。唯一例外是回执竞态:Rust 注册完 subscriber 就开始通知,而前端要等回执才知道 `subscriptionId`,这段时间到达的通知只能记欠账,回执到达后立刻补一次 `consume`(否则整轮最后一个事件之后可能再无通知,事件会卡死在队列里)。合并规则只保留"先到定形、后到补空白"(正文只增不减、工具状态允许从 running 升级到终态),`item.delta` 直接追加到运行态条目正文,删掉 `deltaText` 缓冲,`turn.completed` 把运行态条目并入历史再清空。
6. 首屏与分页:以 `lastCompletedItemId` 为锚点取最近切片,历史读取改为从文件尾反向扫描;切片的新端边界由这个锚点给出(含该条,命令参数 `throughItemId`),首屏读取等订阅回执里的锚点,回执到达前不发请求、也不退化成「取文件尾」;之后锚点按原始 item id 推进(`beforeItemId`,不含锚点)。一次翻页操作在前端连拉,直到合并后聊天投影出现新回合(新的用户气泡)或 `hasMore=false`,每个操作上限 5 页;锚点未推进(`items` 为空 / `firstItemId` 为 null / 与请求锚点相同)时立即停止。可见性口径只在 `features/project-workspace/directHistoryPaging.ts` 实现一份,首屏与「显示更早」共用。
7. App.tsx 接线:订阅 + 立即 reduce bootstrap + notify 唤醒 consume,聊天视图改由 reducer 状态投影(含工具卡片),删除 Direct 回合事件订阅与 `directTurnStream` / `directToolCalls` 状态。
8. 删除只服务旧读路径的命令与前端调用(`read_direct_project_history``read_direct_turn_stream``read_direct_tool_calls`),DirectRuntime 自己的写入保留。`list_game_creator_direct_active_turns` 是唯一的例外并有意保留:它服务首页跨页面的「运行中的项目」列表(`WorkspaceLauncher` / `directActiveTurns.ts`),不是聊天框读路径。
9. 测试与文档收口:补 reducer 单测、解锁跳过的工具卡片用例、更新主规范并把冲突的实施计划与工具卡片文档改写为当前状态。
## 验证命令
1. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_thread -- --nocapture`
2. `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml export_bindings`(生成 `src/features/project-workspace/generated/`),随后用 `prettier --write` 格式化生成目录,避免未格式化的 ts-rs 输出混进提交
3. `npm run test -- apps/ai-game-creator-shell/tests/directThreadChat.test.ts apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts apps/ai-game-creator-shell/tests/directHistoryAnchorGate.test.ts`
4. `npm run test -- apps/ai-game-creator-shell/tests/appSurface.test.ts``project-development.suite.ts` 由该入口注册,不能作为独立测试入口;同时验证现役 Design Agent 的会话恢复与审批界面。)
5. TypeScript 类型检查与 ESLint(范围同前次 DirectProject 迁移)。
6. `npm run check:encoding``npm run check:doc-index``git diff --check`
## 风险与回滚点
- 条目 id 空间不一致会让活跃条目永远收不到完成事件:第 2 步的归一必须在 Rust 出口完成;前端不得再拿到两个 id。
- 事件 payload 变大(命令输出、文件变更明细):继续沿用既有截断上限,并观察 Thread Manager 单 thread 字节上限是否被提前触发。
- 订阅过期:以重新 `subscribe` + 原子替换处理,需要单测覆盖;不引入定时轮询。
- 回执竞态:`subscribe` 回执到达前产生的 `notify` 拿不到订阅身份,必须记欠账并在回执到达后补一次 `consume`;已有专门用例 `drains a notify that lands before the subscribe receipt` 钉住,改坏会让整轮事件卡死。
- 合并规则退化为"先到定形"后,若某类条目只有输出没有调用条目,该输出不显示;这是有意取舍,先观察再决定是否补规则。
- 回滚点:每一步都保持"新源可用即不依赖旧源"的中间态可回退;不允许出现新源未启用而旧源已删除的提交。
@@ -0,0 +1,27 @@
# Mac 客户端随包运行依赖补齐实施计划
- Version: 2
- Status: awaiting-windows-acceptance
- Date: 2026-09-18
- Parent Spec: `【里程碑】Mac客户端随包运行依赖补齐-2026-09-18.md`
## 修改顺序
本轮评审修复顺序:统一 release context(覆盖 build/upload 两入口)→ 版本/端点/产物/清单的定向回归 → 宿主列表/启动/面板与前端自动启动能力门禁 → 同步单架构权威文档 → Node/Vitest/Rust/typecheck/编码/文档/diff 检查。用户随后授权同步 master、重打 0.1.67 并推送当前 PR 分支;不读取私钥、不上传安装包、不合并 PR。
1. 提取构建与运行共用的 Codex 平台布局;按 Cargo TARGET stage 锁定原生依赖并校验包元数据,保留可执行位。
2. 增加 macOS 专属 Tauri 资源映射、声明、产物忽略规则;复用插件 staging,不复制 Windows 原生 payload。
3. 修正 `.app/Contents/Resources` 定位与平台清单验证,保持外部安装回退。
4. 补目标布局、资源映射、缺失/篡改/平台身份、候选顺序与路径测试,运行定向门禁。
5. 构建 `.app`,在隔离目录做资源清点、原生二进制启动和 app-server 握手;生成 DMG 并校验。记录 GUI/真实 Provider 和 Cocos 未验收项。
## 命令与边界
- `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml agent::codex_cli::tests:: -- --test-threads=1`
- `npm run ai-game-creator-shell:typecheck`
- 定向 Node 打包契约测试、`npm run check:encoding``npm run check:doc-index``git diff --check`
- 本地 Tauri 构建关闭 updater artifact;版本按用户要求统一为 0.1.67,不读取发布私钥,不运行 release upload。
## 风险与停止条件
磁盘不足、目标包不匹配或配置测试回归时停止打包,先修正原因,不跳过验证。用户已确认 Mac 本地可用并授权提交、推送当前分支和创建草稿 PR;产物放 gitignored target,不上传发布。回滚以本次路径 diff 为边界,不恢复无关文件。保留计划等待 Windows 回归验收,证据见对应里程碑规范。
@@ -0,0 +1,14 @@
# Mac 本机构建节点接入实施计划
- Version: 1
- Status: preparing-network-required
- Date: 2026-09-18
- Parent Spec: `【里程碑】Mac本机构建节点接入-2026-09-18.md`
1. 本地准备 universal 依赖预备、CI 打包脚本和 Jenkinsfile,运行离线单测、配置门禁及编码检查。
2. 恢复内网后只读核对 Jenkins 版本、既有节点/Job、Git 凭据标识与插件;已存在对象优先核对,不重复创建。
3. 从同一控制器取得 agent.jar,以当前已有 Java 21 运行专用 inbound Agentsecret 保存在用户私有目录,LaunchAgent 参数只引用 secret 文件,不保存控制器 API Token。
4. 建立单 executor、EXCLUSIVE 的专用 Mac 节点与手动 archive-only Job。源码必须是可追溯 Git 提交,未推送改动需另行确认源码交付方式,不能默认推送。
5. 初次构建核对独立工作目录、空间、目标与依赖;在 Jenkins 实际 SUCCESS 后确认 DMG、SHA-256 和两架构 smoke 证据。
失败边界:网络不可达不启动重试服务;节点/Job 修改前保留原配置;不更改其它节点、Job 或调度。禁止把 CLI 日志、认证文件和私有路径提交 Git。未获得真实 SUCCESS 前保留活动计划。
@@ -0,0 +1,16 @@
# Mac 通用安装包实施计划
- Version: 1
- Status: awaiting-user-acceptance
- Date: 2026-09-18
- Parent Spec: `【里程碑】Mac通用安装包与构建管线-2026-09-18.md`
1. 等待当前 Intel 编译结束,避免共用 staging 并发写。
2. macOS build.rs 按白名单分别 stage 两套原生资源;共享 Layout 使用架构子目录,运行时原有 hash/版本校验不变。
3. Tauri macOS 映射双目录,发布入口接受 universal 并生成两个清单键;更新配置门禁与定向测试。
4. 安装包 smoke 支持显式选择主程序切片,验证 universal 主程序与该切片对应原生依赖。
5. 用 Tauri universal 构建 app,分别做 arm64/Rosetta smokehdiutil 生成新 universal DMG,校验并交付。
不发布、不使用私钥;依赖仅从锁定 npm tarball 下载并对照 lockfile integrity。磁盘不足停止,不擅自删除其它 target/cache。保留单架构 DMG。Jenkins 配置作为后续门禁,不混入本地包构建。
本地构建与双架构隔离验证完成,证据见对应里程碑。更新 master 时先停止旧构建,保护并恢复改动后重建;未进行 Jenkins 写操作,待确认 Mac Agent 再制定管线实施计划。
@@ -28,8 +28,7 @@ Parent Spec: `docs/technical/【技术方案】Tripo 3D生成API集成-2026-09-2
| --- | --- |
| `model3d-generation/Model3dGenerationModal.tsx` | 提交面板外壳:两个子项共用的表单、状态区、提交按钮 |
| `model3d-generation/Model3dGenerationModal.test.tsx` | 面板行为用例 |
| `model3d-generation/Model3dGenerationForm.tsx` | 子项专属字段:文生提示词、图生参考图来源 |
| `model3d-generation/Model3dGenerationForm.test.tsx` | 字段与来源菜单用例 |
| `model3d-generation/Model3dGenerationForm.tsx` | 子项专属字段:文生提示词、图生参考图来源(用例并入 `Model3dGenerationModal.test.tsx`:这些字段只在面板里出现,单独挂一个 harness 只是重复) |
| `model3d-generation/Model3dGenerationFormModel.ts` | 档位 → 六个必填参数的唯一映射、价格计算(读运行时定价缓存) |
| `model3d-generation/Model3dGenerationFormModel.test.ts` | 映射、价格、缺价不可提交的用例 |
| `model3d-generation/Model3dGenerationSubmission.ts` | 校验后的请求体组装、`target`、幂等键铸造(代次 + 内容指纹) |
@@ -0,0 +1,51 @@
# 【实施计划】UI设计文档引用代码上下文
| 字段 | 值 |
| --- | --- |
| Version | 1 |
| Status | ready |
| Owner | Codex |
| Milestone | `docs/project-memory/plans/【里程碑】UI设计文档引用代码上下文-2026-09-14.md` |
## 修改边界
允许修改:
- UI Editor persistence/resource bridge/workflow/command 中的 UI JSON 文档 kind 常量与校验。
- `packages/shared` 的 canonical kind 与 Rust 对应映射。
- `agent/direct_codex_user_item/wire.rs` 的 UI 引用 prompt 生成。
- 相关 Rust、TypeScript 测试和当前 UI workflow/AGC 文档。
- `decision-log.md` 的长期决策记录。
明确不修改:
- `ui-prototype` 图片生成和图片 workflow 语义。
- UI State schema、`render_ui_design_state_js` 输出格式和 `ui/generated-*.js` 路径规则。
- SpacetimeDB schema、External v1 OpenAPI、非 Direct Codex Supervisor 引用行为。
- 用户已有 `.env` 未提交修改。
## 实现顺序
1. 更新 UI workflow 主规范与项目决策,明确 `ui-design-doc``ui-prototype` 的身份边界。
2. 在 persistence 提取并导出 UI 文档 kind/media 常量,替换 Rust UI 文档校验。
3. 同步所有 UI JSON 资源生产者、workflow 校验、命令筛选、shared contract 与前端 bridge。
4. 在 Direct Codex 引用渲染中调用 `generate_ui_design_code_at`;成功追加生成文件相对路径,失败追加原始错误并继续发送。
5. 补充旧 kind、图片、成功、文档错误、多引用和 renderer 输出的测试。
6. 执行定向验证,复核 diff 中无 fallback、迁移或无关 `.env` 修改。
## 验证命令
1. `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check`
2. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml ui_editor::persistence`
3. `cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml direct_codex_user_item`
4. 相关 shared contract Vitest 测试与前端类型检查
5. `npm run check:doc-index`
6. `npm run check:encoding`
7. `git diff --check`
## 风险与回滚点
- `ui-prototype` 与 UI JSON 文档共用部分分类展示逻辑,需确保分类映射不会让图片进入文档分支。
- `generate_ui_design_code_at` 会持有项目写锁;多引用必须顺序调用,不能并行写同一项目。
- 生成失败继续发送是已确认语义;测试必须证明错误文本进入 prompt 而不是被转成聊天失败。
- 若发现生产者仍写入旧 `UI`,按开发阶段合同直接修生产者和 fixture,不增加运行时兼容分支。
@@ -0,0 +1,40 @@
# 后台模板上传实施计划
| 字段 | 值 |
| --- | --- |
| Version | 1.0 |
| Status | in-progress |
| Date | 2026-09-21 |
| Milestone Spec | `docs/project-memory/plans/【里程碑】后台模板上传-2026-09-21.md` |
## 修改边界与顺序
1. **领域规则(`module-assets/template_library.rs`**:新增「导入准备」函数——按 ID 合并清单条目(新增默认上架、已存在就地更新并保留 `enabled` 与未知字段),校验 ID / 版本 / entry / runtime / 显示字段上限,产出待提交的清单与 `template.json` 字节;不接触存储。
2. **存储(复用 `platform-oss/template_library.rs`**:只使用既有 `begin_publish` / `read_index` / `put_immutable` / `commit_index` / `finish`;如缺少「读单个对象作元数据基线」的能力,再补最小只读方法,不改锁与提交语义。
3. **契约(`shared-contracts/admin.rs` + `apps/admin-web/src/api/adminApiTypes.ts`**:新增导入请求(manifest)与导入结果 DTO;错误体沿用现有 `AppError` + 逐项原因结构。
4. **接口(`api-server/admin_templates.rs` + `modules/admin.rs`**:新增 multipart handler,按「解析 manifest → 校验每个 ZIP / 封面 → 取锁 → CAS → 写内容寻址对象并回读 → 提交清单 → 释放锁」顺序实现;路由套 `require_admin_auth` 与 256 MiB body 上限,并同步路由契约测试与页签权限矩阵测试。
5. **后台页面(`AdminAgcTemplatesPage.tsx` + `adminApiClient.ts`**:新增「上传模板」入口与弹窗(多选 ZIP、逐行元数据、批量提交、逐行错误、写入确认),沿用既有 `useAdminWriteConfirm` 与刷新语义。
6. **文档**:主规范新增「后台模板上传」章节;决策记录补一条;主规范中「本轮只允许…不上传 ZIP」改为指向新章节。
## 验证命令
```bash
cargo test --locked -p module-assets --manifest-path server-rs/Cargo.toml -- template_library
cargo test --locked -p api-server --manifest-path server-rs/Cargo.toml -- agc_template
cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check
npm run admin-web:typecheck
npx vitest run apps/admin-web/src/pages/AdminAgcTemplatesPage.test.tsx apps/admin-web/src/api/adminApiClient.test.ts
npm run check:encoding
npm run check:doc-index
git diff --check
```
接口 smoke`npm run dev:api-server`(本地 8082+ `npm run dev:admin-web`,先用未授权/无页签权限请求确认失败关闭,再以隔离存储替身或用户显式确认的 dev bucket 做一次真实导入。
## 时间盒与风险
- **风险:真实发布不可逆**。导入会写公共 bucket 且不提供删除,因此默认只在本地用替身验证;对 dev bucket 的写验证必须由用户显式确认,测试用模板需可在事后下架。
- **风险:ZIP 原字节发布与 CLI 确定性打包不一致**。同一模板可能被两条路径写成不同字节;由「同 ID 同版本字节必须一致」的门禁兜住,导入失败时提示改用 CLI 或递增版本。
- **风险:大文件内存**。ZIP(≤64 MiB)与封面在内存中校验,单批上限 20;需要更大模板时走 CLI。
- **风险:批量部分写入**。所有对象在清单提交前写入且不删除;中途失败时清单不变、已写对象成为未被引用的历史对象,由后续同键复用。
- **回退**:下线路由与页面入口即可停止使用;已发布内容按既有 CLI / 后台下架流程处理,历史对象保留。

Some files were not shown because too many files have changed in this diff Show More