合并 master(bba4f0eb2):DirectProject 聊天三态与快照文档并入运行页入口收口
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
- 只冲突两份共享记忆的尾部追加(pitfalls / decision-log):保留双方新增条目,直接合并非取舍 - App.tsx / styles.css 自动合并通过;本分支的运行页入口收口与 onRunNotice 通道未受影响
This commit is contained in:
@@ -51,5 +51,7 @@ AGC 项目开发聊天框当前同时从三处取数据:Direct 回合事件(
|
||||
- 旧项目磁盘上遗留的 `turn-stream.jsonl` / `tool-calls.jsonl` 保留不动,不迁移、不清理、不再由 DirectProject 聊天框读取。
|
||||
- 工具卡片的脱敏与截断必须在读取期执行一次,不能因为"原始条目已在磁盘"就把未脱敏内容直接渲染到界面。
|
||||
- 回合结束语义务必由 `turn.completed` 判定;缺少该事件的残留回合不得被渲染成运行中。
|
||||
- 「活动回合的唯一判据」约束的是**原生回合**:界面上的「本地已发出、原生还没认领」是投影的展示态(`DirectChatTurn.state = 'awaiting-start'`),由本地在途用户条目身份派生,不构成第二套原生生命周期,也不参与 `turnRunning` 的判定。
|
||||
- 三层数据流、变量归属与一次发送的时序写在代码里:`apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts` 的模块注释;回合三态的定义与判据真值表在 `apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directTurnPresentation.ts` 的 `DirectChatTurnState`。改判据时同步这两处与对应测试。
|
||||
- 验收证据是端到端行为,不是单元测试:回合进行中杀掉应用进程后重开项目,应看到部分文本与工具卡片按原顺序出现且不显示忙碌;正常结束后重进应与实时渲染一致;文件系统不得再新增 `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 会话核对仍列为运行时验收项。
|
||||
|
||||
@@ -38,6 +38,6 @@ Parent Milestone: `【里程碑】AGC项目定时快照上传-2026-09-17.md`
|
||||
## 风险与回滚
|
||||
|
||||
- 上传体积与带宽:首轮全量可能很大,先设单文件与单次同步总量上限并把超限项记入跳过清单;不静默截断。
|
||||
- 数据出境边界:只上传项目目录内普通文件,排除 `.agent/runtime`、`.agent/logs`、`.git`、构建产物与临时文件;凭据类文件不在白名单内。
|
||||
- 数据出境边界(2026-09-22 修订):只上传项目目录内普通文件。`.agent` 承载项目身份与 Agent 状态,整目录上传(含 conversations、logs、runtime、checkpoint、`agent.db`);`.git`、构建产物、临时文件与凭据类文件仍不在白名单内。该修订只作用于快照同步,项目索引与 checkpoint 继续排除整个 `.agent`。
|
||||
- 服务端未配置 bucket 时客户端必须失败关闭,不能把本地索引推进成"已同步",否则后续同步会漏传。
|
||||
- 回滚:客户端可停用触发接线(保留模块与测试)即可回到无上传行为;服务端路由与配置项可单独移除,不影响既有 OSS 前缀与错误报告链路。
|
||||
|
||||
@@ -17,7 +17,7 @@ AGC 在项目打开期间按周期把用户项目增量上传到 OSS `agc-dev`
|
||||
- 目标 bucket 配置:`GENARRATIVE_AGC_PROJECT_SNAPSHOT_OSS_*`,默认 `agc-dev`。
|
||||
- 契约:`shared-contracts::agc_project_snapshots` 新增请求/响应 DTO 与项目 ID、相对路径、摘要校验函数。
|
||||
- 客户端增量索引:`<AppData>/project-snapshots/<projectId>/index.json`,按用户身份判等,换号后按冷启动全量重算。
|
||||
- 排除口径:复用 `should_skip_project_snapshot_path`(整个 `.agent`、`.git`、构建与依赖目录、凭据目录、敏感后缀、符号链接与重解析点)。
|
||||
- 排除口径:快照同步使用 `should_skip_project_snapshot_sync_path`(2026-09-22 起)。`.agent` 承载项目身份与 Agent 状态,整目录同步;`.git`、构建与依赖目录、凭据目录、敏感后缀、符号链接与重解析点仍然排除。项目索引、checkpoint、Agent 上下文与 git 检查继续沿用 `should_skip_project_snapshot_path` 的整个 `.agent` 排除口径。
|
||||
|
||||
## 不做
|
||||
|
||||
@@ -32,7 +32,7 @@ AGC 在项目打开期间按周期把用户项目增量上传到 OSS `agc-dev`
|
||||
1. 首次同步上传项目内全部符合条件的普通文件;再次同步在无改动时上传 0 个文件。
|
||||
2. 只修改一个文件时,差异集合恰好包含一个修改项;删除一个文件时上传集合为空且清单中不再包含该文件。
|
||||
3. `(字节数, 修改时间)` 未变的文件复用已存摘要,不重复读取内容计算摘要。
|
||||
4. 排除规则命中项(`.agent/runtime`、`.agent/logs`、`.git`、`node_modules`、构建产物、临时文件、符号链接)与超限文件进入跳过清单,不进入上传集合。
|
||||
4. 项目内 `.agent` 的全部普通文件(`manifest.json`、`agent.db` 与其 WAL/SHM、`.manifest.json.lock`、`project.lock`、conversations、logs、runtime、checkpoint、workbench)进入上传集合;`.git`、`node_modules`、构建产物、凭据目录与敏感后缀仍不进入;超限文件进入跳过或延后清单,不静默丢弃。
|
||||
5. 任一次同步失败(非鉴权类)不推进本地索引,下一次触发重算并重试;鉴权/权限类失败不自动重试。
|
||||
6. 同一项目的并发触发串行执行,不产生两路重复上传。
|
||||
7. 工作区窗口关闭与应用退出都会触发一次同步,且关闭路径不因同步失败而阻塞退出超过超时上限。
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
- [ ] 未单独配置快照目标时仍使用 agc-dev,只复用资源存储凭据;显式快照目标保持有效,不迁移现存对象。
|
||||
- [ ] 后台列表按部署渠道查询,显示项目名/ID、用户(昵称 + 陶泥号)、同步时间、文件数、体积和完整性,支持刷新与游标分页(每页 20/50/100 + 上一页/下一页)。
|
||||
- [ ] ZIP 按清单还原相对路径;不含对象存储摘要目录;空文件可上传与导出。
|
||||
- [ ] `.agent` 承载项目身份与 Agent 状态,整目录随快照上传,并在后台 ZIP 中按原相对路径还原;归档因此可用于还原项目身份与 AGC 对话历史。凭据、版本库与构建产物仍不进快照。
|
||||
- [ ] 清单名称/完整性变化在无内容差异时也提交,partial 可恢复 ready,历史缺字段不冒充 ready。
|
||||
- [ ] 缺失、损坏、越界路径和非完整清单失败关闭;历史未声明完整性的清单明确标记,允许导出已有文件但不称为完整工程。
|
||||
- [ ] 无后台权限不能读取项目或 ZIP;不泄漏凭据;ZIP 构建有体积、并发和临时文件清理边界。
|
||||
@@ -39,6 +40,10 @@
|
||||
| 层次 | 结果 |
|
||||
| --- | --- |
|
||||
| 客户端 Rust `project_snapshot` | 22 通过、1 忽略(写入式真实上传 smoke 未运行);含排队退出等待回归 |
|
||||
| `.agent` 全量上传口径(2026-09-22 修订) | `project_snapshot` 定向 24 通过、1 忽略;新增扫描纳入 `.agent` 与策略单测,覆盖 `.agent` 内凭据、版本库、`.env*` 继续排除,以及项目索引 / checkpoint 口径不变 |
|
||||
| `.agent` 真实样本复核 | 对 15 个本地 AppData 项目的 487 个 `.agent` 普通文件按新规则复算,0 个仍落在排除集;该复算是脚本复刻规则,不是 Rust 运行时证据 |
|
||||
| `.agent` 客户端链路运行时 smoke(2026-09-22) | 用真实项目副本(`.agent` 164 个文件 / 5.61 MiB,项目 `gameagent-agentsmoke1`)走真实差异引擎 → 本地 api-server → 真实 OSS:首轮 `synced`、`uploaded=179` / `18,991,590` 字节、跳过与失败均为 0;紧接着第二轮 `no-op` / 上传 0 个文件。`uploaded=179` 恰好等于原口径的 15 个项目文件加 164 个 `.agent` 文件 |
|
||||
| `.agent` 存储与后台归档(2026-09-22) | 只读 GET 真实 OSS 清单对象(`agc/project-snapshots/v1/<user>/gameagent-agentsmoke1/manifest.json`,26,356 字节):`files=179`、其中 `.agent/**` 164 条、`pendingFiles=0`、合计 18,991,590 字节;按清单里的 `大小-摘要` 构造对象键 HEAD 命中 `.agent/manifest.json`(18,319)、`.agent/agent.db`(9,353)、`.agent/conversations/project.jsonl`(1,422,226) 与 `game/package.json`(227)。后台 `download` 返回的 ZIP 解压出 179 条目、164 条在 `.agent/` 下,抽样 6 个文件(含 `agent.db`、会话、运行态文件)与本地 SHA-256 完全一致;正在运行的 dev api-server 列表显示同一项目 `files=179 status=ready` |
|
||||
| 客户端前端生命周期与启动器 | 3 文件、10 测试通过;完整 AGC typecheck、skill-pack、check-config 通过 |
|
||||
| 后台页面、API client、路由与样式 | 44 测试通过;admin-web typecheck/build 通过 |
|
||||
| 后端快照与权限 | 14 定向测试通过;未认证路由矩阵与页签映射 2 测试通过 |
|
||||
@@ -53,3 +58,5 @@
|
||||
`npm run dev:api-server -- --api-port 4198 --bgfilter-worker-port 4199 --api-timeout-seconds 600` 编译成功,但当前工作区配置的本地数据库 `xushi-p4wfr` 在 `127.0.0.1:3101` 返回 404,启动认证投影无法完成,故 `/healthz` 及完整 HTTP smoke 未通过。仅本任务启动的 API/worker 已停止;没有清库、迁移数据库、改 `.env` 或替换其它项目的验证目标。
|
||||
|
||||
尚未替换安装版、构建新客户端发布包或部署;提交推送按用户本轮授权执行。当前条款已有上述自动化与只读存储证据,最终验收仍等待当前工作区数据库就绪后的 HTTP 联调,以及新客户端的隔离实机自动上传验证;完成后再关闭里程碑并清理两份计划。
|
||||
|
||||
`.agent` 全量口径已在上表取得真实上传、真实 OSS 清单与后台 ZIP 三层运行时证据。两点边界仍需记住:① 本次 smoke 用的是真实项目的可丢弃副本,其 `projectId` 改成 `gameagent-agentsmoke1`、走 dev 专用账号上传,历史真实项目在下一个同步周期前仍是旧口径清单(不含 `.agent`);② 本地 `api-server.exe` 构建于 2026-09-21 14:06,早于渠道分区提交 `4951b71d7`(2026-09-21 16:57),因此本次对象键仍是 `agc/project-snapshots/v1/` 布局、`GET /admin/api/project-snapshots/channels` 在本地返回 404;升级到 v2 键布局需要重建并重启本地 api-server。
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# 决策记录
|
||||
|
||||
## 2026-09-22 AGC release 增加每日调度,dev 调度保持双平台
|
||||
|
||||
- 背景:原有 `Genarrative-Scheduled-Revision-Trigger` 每小时跟随 revision 发布 dev 客户端,但没有对应的 release 渠道自动入口;Mac 节点此前已纳入小时 dev 调度,需要避免新增 release 调度时再退回 Windows-only。
|
||||
- 决策:新增 `Genarrative-Scheduled-Release-Trigger`,每天 04:00 检查 `SOURCE_BRANCH`,使用独立的 `.jenkins-last-release-revision` 与客户端相关路径白名单;上一轮 release 调度后有客户端变更时,先经 `Genarrative-Agc-Global-Version-Issue` 发统一总号,再以同一固定 `COMMIT_HASH` 触发 `Genarrative-Agc-Windows-Build` 与 `Genarrative-Agc-MacOS-Build` 的 `AGC_UPDATE_CHANNEL=release` 分区,Mac 继续带 `SKIP_IF_SUPERSEDED=true`。小时 dev 调度保持同时触发 Windows 与 macOS dev。
|
||||
- 原因:release 与 dev 是不同渠道和发布节奏,不能靠同一个小时 Job 隐式切换;独立 Job 能分别去重、记录状态和审计发号。release 调度不触发 Full Build,避免把桌面客户端发布与线上全栈部署绑定。
|
||||
- 影响范围:`jenkins/Jenkinsfile.scheduled-release-trigger`、`jenkins/scheduled-release-trigger-job-config.xml`、`jenkins/Jenkinsfile.agc-global-version-issue`、`scripts/check-production-ops-guardrails.mjs`、开发运维文档、共享开发工作流与 AGC 总版本号技术方案。
|
||||
- 验证方式:`npm run check:production-ops` 校验 release Job 的 cron、发号、双平台 release 参数、Mac 让位和 Copy Artifact 授权;`npm run check:encoding` 与 `git diff --check` 校验文件与补丁。
|
||||
|
||||
## 2026-09-22 项目快照 `.agent` 全量上传:远端工程包要能还原项目身份与 Agent 历史
|
||||
|
||||
- 背景:快照上传此前复用 `should_skip_project_snapshot_path`,把整个 `.agent`(`manifest.json`、`agent.db`、conversations、logs、runtime、checkpoint、workbench、`project.lock`)排除在上传集合之外。后台“项目工程”的「下载完整工程」是按清单逐文件打包的,于是导出的 ZIP 里没有项目身份与对话历史,用户在 AGC 里恢复不出同一个项目。
|
||||
- 决策:快照同步改用独立口径 `should_skip_project_snapshot_sync_path`(`apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs`)。它与原口径共用同一份组件与后缀规则(提取为 `PROJECT_SNAPSHOT_EXCLUDED_COMPONENTS` / `PROJECT_SNAPSHOT_EXCLUDED_SUFFIXES`),只额外放行两点:`.agent` 组件本身,以及 `.agent` 内的 Agent 状态数据库后缀 `.db`/`.db-wal`/`.db-shm`(`agent.db` 是项目状态而不是凭据转储)。扫描入口 `src-tauri/src/project_snapshot/scan.rs` 切到新口径。
|
||||
- 边界:`.agent` 内部的版本库 / 依赖 / 构建目录、凭据目录(`.ssh`、`credentials`、`secrets` 等)、`.env*` 与 `.pem`/`.key`/`.sql` 等敏感后缀继续排除;符号链接与重解析点照旧在扫描阶段跳过;单文件 64 MiB、单次 512 MiB、单项目 2 GiB 上限不变。项目索引、checkpoint、Agent 上下文与 git 检查继续使用 `should_skip_project_snapshot_path`(仍排除整个 `.agent`)——本变更只放开快照同步。
|
||||
- 代价与取舍:`.agent` 里的会话记录、运行日志与诊断快照会随项目离机并写入该用户自己的私有前缀,这是“可还原”的代价,属于本轮产品决定。服务端不需要改动:快照路径校验只检查路径形状,后台归档按清单逐文件打包,都不含 `.agent` 特判。模板包导入门禁(`IMPORT_FORBIDDEN_SEGMENTS`)与 CLI 模板发布门禁继续拒绝 `.agent`,不会因为这份 ZIP 而放宽。
|
||||
- 影响范围:`apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs`、`src-tauri/src/project_snapshot/{scan.rs,tests.rs}`;主规范 `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-17 AGC 项目定时快照上传”与“后台工程列表与下载”两节;`docs/project-memory/plans/` 的两份里程碑与实施计划。
|
||||
- 验证方式:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot`(24 passed、0 failed、1 ignored),新增用例覆盖 `.agent` 整目录进入候选集、`.agent` 内凭据与 `.env*` 仍被排除、项目索引与 checkpoint 口径不变;另用同一份规则复算 15 个本机 AppData 项目的 487 个 `.agent` 普通文件,0 个仍落在排除集。
|
||||
- 运行时证据(2026-09-22):真实项目副本(`.agent` 164 文件 / 5.61 MiB,`projectId=gameagent-agentsmoke1`)经真实差异引擎 → 本地 api-server → 真实 OSS `agc-dev`:`uploaded=179`(= 原口径 15 个项目文件 + 164 个 `.agent` 文件)/18,991,590 字节、`synced` 后第二轮 `no-op`;只读 GET 远端 `agc/project-snapshots/v1/<user>/gameagent-agentsmoke1/manifest.json` 得 `files=179`(`.agent/**` 164 条)、HEAD 命中 `agent.db` 等对象;后台 download 的 ZIP 含 179 条目(164 条 `.agent/`),抽样文件 SHA-256 与本地一致。注意该 bucket 仍是 `v1/` 键布局:本地 `api-server.exe`(2026-09-21 14:06)早于渠道分区提交 `4951b71d7`(16:57),重建重启后才会写 `v2/{channel}/`。
|
||||
|
||||
## 2026-09-21 合并 origin/master:Supervisor 永久退役,策划 V1V2 退役落到当前两条产品路径
|
||||
|
||||
- 背景:`refactor/split-direct-project`(DirectProject 独立聊天容器)与 `origin/master`(#355 退役策划 Agent V1/V2)在 2026-09-18 之后各走一条线:本分支删掉 Supervisor 前端链路、把立项策划收敛到 `view/project-development/planning/`,master 删掉整套策划 V1/V2(前端会话 / 审批卡 / 适配器 / 类型与 Rust `planning_*_v2` 命令、`planning_gdd_model.rs`、`planning_policy_v2.rs`、`planning_session_v2.rs`)只保留 Design Agent。两边都在删 Supervisor,冲突集中在 `App.tsx`、聊天视图(`PlanningChatView`、`DirectProjectTurn`、`ToolCallGroup`)、Direct composer / 引用输入区、`styles.css`、Rust direct user item 与 appSurface 用例。
|
||||
@@ -9323,3 +9341,30 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 边界:预览的**启动与切换**仍然只走内置运行画面、不自动开系统浏览器——`scripts/check-native-shells.mjs` 那条负向守卫保持原样,本轮只补「浏览器入口只有顶栏这一枚按钮」的正向断言。
|
||||
- 影响面:`apps/ai-game-creator-shell/src/{App.tsx,styles.css,view/project-development/index.tsx,features/app-shell/*,features/resource-canvas/*}`;用例新增 `tests/runPreviewBrowserOpen.test.tsx`、`tests/runNoticeToast.test.tsx`、`tests/runNoticeShellWiring.test.tsx`(外壳级:替身聊天发提示 → 壳真的渲染浮层)、`tests/gameRunToolbarActionsStyle.test.ts`,改写 `tests/previewActivation.test.tsx`(原断言「聊天里出现已载入运行视图」的地方改为断言 toast 通道 + 对话容器里没有这类提示,并补一条「启动失败走失败色提示且不写对话区」)与 `tests/appSurface/project-development.suite.ts` 的生成任务入口用例。
|
||||
- 验证:`appSurface` 全量、AGC 壳目录全量、`npm run typecheck`、`check:native-shells:contract`、`check:encoding`、`git diff --check` 全绿;真机观感未复验。
|
||||
|
||||
## 2026-09-22 DirectProject 聊天状态显式化:回合三态 + 「在跑吗」唯一派生入口 + 数据流地图
|
||||
|
||||
- 背景:DirectProject 聊天框只有三份真相源(`project.jsonl` 历史切片、Thread Manager 运行态事件、本地乐观消息),但「这一轮在跑吗」在四层里各叫一个名字——reducer 的 `turnRunning`、controller 的 `turnBusy`、视图里手拼的 `busy`、投影里的 `active`。定位发送后空窗缺陷时,读代码无法判断某个窗口期的界面表现是否有依据,也说不清谁该信谁。
|
||||
- 决策(三态取代布尔):`DirectChatTurn.active` 改为 `DirectChatTurn.state: 'running' | 'awaiting-start' | 'finished'`。`running` 只由 reducer 的 `turnRunning` 决定;`awaiting-start` 由「最新一轮的用户条目身份 = 本地在途的 `pendingUserItemId`(`direct-codex:{clientTurnId}:user`)、且本轮还没有明确终态」决定;其余是 `finished`。判据是身份不是时间戳,`pendingUserItemId` 由 controller 在 `beginTurnCommand()` / `endTurnCommand()` 里与 `turnBusy` 同生共死。
|
||||
- 决策(单一派生入口):新增 `useDirectProjectTurnStatus()`,返回 `{ nativeRunning, commandInFlight, displayBusy, latestTurnState }`。header / composer 只读 `displayBusy`(两者并集,语义与原来的 `turnBusy || directTurnRunning` 完全一致),「陶泥儿正在处理」卡片只读 `nativeRunning`。约定:新增「忙 / 在跑」类判据先落进这里,不在组件里另拼布尔。
|
||||
- 决策(地图落代码):三层数据流、三份原始输入、一次发送的时序(含空窗步骤)与状态变量归属写进 `apps/ai-game-creator-shell/src/view/project-development/chat/controller/useDirectProjectChatController.ts` 的模块注释;回合三态的定义与判据真值表写进 `.../conversation/directTurnPresentation.ts` 的 `DirectChatTurnState`。不另开技术方案文档——这套说明是给改这块代码的人看的,放代码里才不会与实现脱节。ADR 补一条「活动回合唯一判据约束的是**原生回合**」的澄清与代码指针。
|
||||
- 口径更正(2026-09-22,同日第二条):本条记录的「`awaiting-start` 暂时与 `finished` 同渲染」已由随后的三态接入渲染改动修掉,见下面那条。
|
||||
- 边界(本次不修):`awaiting-start` 暂时与 `finished` 同渲染,所以空窗期内仍会显示「本轮结束于 <用户发送时间> · 耗时 0.0秒」;`Math.max(turn.endedAt, turn.startedAt)` 的兜底与 `DirectProjectTurnUsage` 的渲染条件都没动。同源的第二条缺陷也记录在案:`turnEndedAt` 只是会话内展示缓存,页面重进后所有已结束回合都会走同一条兜底显示 0.0 秒(临时渲染用例实测确认,用例未入库)。修法与证据要求见下面那条(三态接入渲染)以及 `DirectProjectTurn.tsx` 里标注未修范围的注释。
|
||||
- 验证:`npx vitest run` 定向 `directTurnPresentation`(17 条,新增 4 条三态用例)、`directProjectTurnStatus`(4 条)、`directHistoryPaging`(9 条)全绿;`appSurface.test.ts` 202 passed / 13 skipped;`tsc -p apps/ai-game-creator-shell/tsconfig.json --noEmit`、`npm run check:encoding`、`npm run check:doc-index`、`git diff --check` 通过。真实客户端观感与窗口期表现未在客户端复核。
|
||||
|
||||
## 2026-09-22 空窗期不再谎报「本轮结束」:DirectProject 三态接入渲染
|
||||
|
||||
- 背景:上一条只把回合三态显式化,渲染层仍按 `state === 'running'` 判断,于是「本地已发出、宿主还没回 `turn.started`」的窗口里 `awaiting-start` 被当成 `finished` 渲染,显示「本轮结束于 <用户发送时间> · 耗时 0.0秒」(用户现场反馈的现象)。
|
||||
- 决策(判据分两类,不许对调):**否定式**判断(不要说它结束、不要折叠过程、不要显示终态文案)读 `state !== 'finished'`;**肯定式**判断(哪段正文在流式、「陶泥儿正在处理」卡片与滚动已耗时)读 `state === 'running'`。理由是 `awaiting-start` 能支持"还没结束",但不能支持"宿主已经在跑"——后者只有 `turn.started` 能证明。
|
||||
- 决策(卡片口径取保守):`DirectProjectConversation` 的「正在处理」卡片与 `activeTurnStartedAt` 仍只认 `turnStatus.nativeRunning`,窗口期不出现这张卡片。文案是「陶泥儿正在处理」,在 `turn.started` 之前无法断言宿主已经开始,这与空窗缺陷是同一个病根(把"本地已发出"当成"宿主已在跑");窗口期用户看到的是"消息已发出 + 输入框忙",语义诚实。若将来改成窗口期也显示卡片,`running` 在渲染层就没有消费者了,那时应把投影压成 `unfinished: boolean`,不要留一个没人读的状态成员。
|
||||
- 边界(A 仍未修):`DirectProjectTurnUsage` 的 `Math.max(turn.endedAt, turn.startedAt)` 兜底没动,所以两类 `finished` 回合仍显示「耗时 0.0秒」——① 页面重进后读回来的历史回合(`turnEndedAt` 只是会话内展示缓存);② 发送后没有产生任何原生事件 / 发送失败的本地回合。为什么会有这两类、修法与要产品确认的口径都写在代码里(`DirectProjectTurn.tsx` 的 `DirectProjectTurnUsage` 注释与 `directTurnPresentation.ts` 的 `DirectChatTurnState` 注释),改完删掉那段注释。
|
||||
- 验证:`tests/directProjectTurn.test.tsx`(新增 3 条渲染契约:`awaiting-start` 与 `running` 不显示终态文案且不折叠、`finished` 有终态时显示结束时间与耗时);`tests/appSurface/chat-composer.suite.ts` 新增 `does not report a finished turn while the host has not acknowledged the send yet`(invoke 挂起、无任何原生事件时断言不出现「本轮结束于」);变异验证:把 `state !== 'finished'` 退回 `state === 'running'` 后渲染契约用例变红,恢复即绿。定向 vitest、`appSurface.test.ts`(203 passed / 13 skipped)、`tsc`、ESLint、Prettier、`check:encoding`、`check:doc-index`、`git diff --check` 通过。真实客户端观感未复核。
|
||||
|
||||
## 2026-09-22 宿主崩掉不再留下永远开着的回合:本地命令失败时按身份兜底收口
|
||||
|
||||
- 背景:`turn.started` / `turn.completed` 是原生回合唯一的开闭配对,界面上的「正在处理」卡片与输入盒忙态都读 reducer 的 `turnRunning`。但 app-server 崩了、回合任务被中止或 panic 时没人补终态事件,事件流里就留一条永远开着的 `turn.started`:界面一直显示「陶泥儿正在处理」、输入盒一直排队(用户现场反馈)。
|
||||
- 决策(本地命令返回即这一轮在宿主那边收场):`chat_with_game_creator_direct_codex` 以真失败返回时,controller 按本轮身份调用 `stopDirectThreadTurn`,只放掉「是否在跑」,**不写终态时间**——命令返回不等于知道这一轮真正的结束时刻,编一个只会让耗时变成假数。用户主动终止与「正在跑的是另一轮」两条不适用:前者宿主必然补终态,后者不是这一轮(不能顺手抹掉别人的回合)。
|
||||
- 决策(身份作用域 + 不复活):`stopDirectThreadTurn` 只在 reducer 里的运行身份相同或为空时生效;收口记进 `commandClosedTurnUserItemId`,同身份迟到的 `turn.started` 不再把这一轮拉回运行态(迟到的 `turn.completed` 例外放行,仍要拿它补上真正的结束时间)。身份按 clientTurnId 唯一,所以这条记忆只挡它自己那一轮。
|
||||
- 影响面:`apps/ai-game-creator-shell/src/view/project-development/chat/{conversation/directThreadChat.ts,controller/useDirectThreadChatSubscription.ts,controller/useDirectProjectChatController.ts}` 与 `apps/ai-game-creator-shell/tests/{directThreadChat.test.ts,appSurface/chat-composer.suite.ts}`。
|
||||
- 验证:reducer 新增 2 条用例(兜底收口后同名 `turn.started` 不复活且真终态仍能补上结束时间;身份不同的回合不动),appSurface 新增 `stops claiming the turn is running when a failed send left turn.started open`;变异验证:拿掉 controller 里的兜底收口调用后该用例变红(界面仍显示「陶泥儿正在处理」),恢复即绿。
|
||||
- 边界(未做):根因仍在宿主侧——要在进程内保证开闭配对,应由 Rust 在回合函数退出(含 panic / 任务中止)时补一条终态事件(drop 守卫);本次只做到前端不再跟着说谎。另:兜底收口的回合没有终态时间,仍会落进「`finished` 但拿不到终态时间」那个已知缺口(终态文案要不要藏,见 `DirectProjectTurn.tsx` 与 `DirectChatTurnState` 注释里的 A 项)。
|
||||
|
||||
@@ -92,7 +92,7 @@ SpacetimeDB 任务统一先读取 `.codex/skills/genarrative-spacetimedb/SKILL.m
|
||||
|
||||
## Jenkins 定时版本调度
|
||||
|
||||
定时与版本比较只保留在 `Genarrative-Scheduled-Revision-Trigger` 一处:每小时用 `git ls-remote` 解析 `SOURCE_BRANCH` 远端 HEAD,与上一次触发过的 revision 比较,变化时才把同一个 `COMMIT_HASH` 传给 `Genarrative-Full-Build-And-Deploy`,并先经 `Genarrative-Agc-Global-Version-Issue` 发号、再把同一个总版本号透传给 `Genarrative-Agc-Windows-Build` 与 `Genarrative-Agc-MacOS-Build`,保证两个客户端的平台分区发布同一个版本。这三个下游 Job 都不得自带 `triggers` / `cron`,也不得在管线内再做一套版本去重;`npm run check:production-ops` 会拦住这两类回退。macOS 节点是日常办公机,调度触发它时置 `SKIP_IF_SUPERSEDED=true`:节点离线期间排队的旧构建在恢复后会自行让位,不发布过期版本。调度状态与生效步骤见 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
定时与版本比较收口到两条调度器:`Genarrative-Scheduled-Revision-Trigger` 每小时处理 dev 渠道,变化时触发 Full Build、AGC Windows/macOS dev,并让两个客户端平台共用同一个总版本号;`Genarrative-Scheduled-Release-Trigger` 每天 04:00 处理 AGC release 渠道,只在上一轮 release 调度后出现客户端相关路径变化时,经 `Genarrative-Agc-Global-Version-Issue` 发同一个总号并触发 AGC Windows/macOS release。各下游 Job 都不得自带 `triggers` / `cron`,也不得在管线内再做一套版本去重;`npm run check:production-ops` 会拦住回退。macOS 节点是日常办公机,两条调度触发它时都置 `SKIP_IF_SUPERSEDED=true`:节点离线期间排队的旧构建在恢复后会自行让位,不发布过期版本。调度状态与生效步骤见 `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。
|
||||
|
||||
## Gitea CI 依赖闭合
|
||||
|
||||
|
||||
@@ -5455,7 +5455,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- 原因:tauri-bundler 的 `download_and_verify` 现场从 GitHub 取 NSIS 工具链,只有一次机会、没有重试;响应体被截断即报 `io: unexpected end of file`,看起来像打包错误其实是网络问题。Checkout 阶段的 `git clean -fdx` 每次都会清掉 `target/.tauri`,所以每个构建都要重新下载,在受限网络下必然反复失败。
|
||||
- 处理:新增 `apps/ai-game-creator-shell/scripts/nsis-toolset.mjs` 与 `ensure-nsis-toolset.mjs`,在 `buildRelease`(Windows 目标且需要打包时)与 Jenkins `Tauri NSIS toolchain` 阶段按固定 SHA1 预置 `target/.tauri/NSIS`:原始归档带 4 次重试,缓存在工作区外的 `%ProgramData%\genarrative\tauri-nsis-cache`(可用 `AGC_TAURI_NSIS_CACHE_DIR` 覆盖),镜像开关沿用 bundler 的 `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE` / `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR`。该阶段同时执行 `makensis.exe -VERSION`,把 2026-09-02 记录的缓存目录不可执行问题也提前到编译之前暴露。Checkout 阶段改为 `git clean -fdx -e apps/ai-game-creator-shell/src-tauri/target/.tauri`:Tauri 的工具缓存位于工作区内,裸 `git clean -fdx` 会连它一起删,排除后同一节点的稳态构建不再需要联网,只有冷缓存(新节点、工作区重建)才下载。
|
||||
- 验证:`node --test apps/ai-game-creator-shell/scripts/nsis-toolset.test.mjs`(已就绪零下载复用、缓存离线还原、失败重试、哈希不符与归档越界失败关闭)与 `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs`;真实节点上该阶段必须早于 Rust 编译失败关闭。
|
||||
- 注意:不要改回 `bundle.useLocalToolsDir: false` 去用 `%LOCALAPPDATA%`,也不要依赖 PATH 里预装的 `makensis`;升级 `@tauri-apps/cli` 时同步核对归档 URL、SHA1 与必需文件清单。
|
||||
- 注意:不要改回 `bundle.useLocalToolsDir: false` 去用 `%LOCALAPPDATA%`,也不要依赖 PATH 里预装的 `makensis`;升级 `@tauri-apps/cli` 时同步核对归档 URL、SHA1 与必需文件清单。回归测试自身也必须跨平台:仓库根目录用 `fileURLToPath(new URL(...))` / `defaultAppRoot()` 解析,不能用 `URL.pathname` 得到 `/C:/...` 后再 `path.resolve`;模拟 Windows 与 POSIX 缓存路径时要分别使用 `path.win32` 与 `path.posix`,不要用当前节点的原生分隔符断言另一平台。
|
||||
|
||||
## AGC 登录态续期必须同步本地运行时
|
||||
|
||||
@@ -5951,6 +5951,10 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **验证**:`npm ci` 后 `cargo build --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml` 通过,不再触发该 panic。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/build.rs`、`apps/ai-game-creator-shell/src-tauri/build_support/codex_bundle.rs`、`package-lock.json`。
|
||||
|
||||
## 策划聊天不能按可选子节点序号分配消息高度
|
||||
|
||||
策划与开发 Agent 共用聊天类名,但布局合同不同。策划新增状态条后,按第二个子节点分配 `1fr` 会把空白给状态条、让消息框随回复增长;只给 `.is-direct-codex` 的状态样式也不会覆盖策划。策划使用纵向 Flex,仅消息列表伸缩,阶段/待处理区域限高滚动;改共用样式时同时核对两种入口。jsdom 交互通过不代表布局正确,须匹配完整 CSS 层叠并用真实浏览器核对空/短/长消息与长待办。窄屏上下堆叠必须在固定外壳内提供工作台滚动容器,两块面板明确限高;低优先级的 `height: auto` 不能覆盖外壳后代规则的 `height: 100%`。布局夹具必须包含窗口外壳与启动器层级,并实际滚动验证输入框可见可操作,不能只检查输入框在聊天面板内部。实时正文/思考不更新持久消息数组,滚动跟随必须覆盖这些独立状态并保留用户上滚门禁;历史消息缺失的时间不得用读取时刻填补。详见 AGC 实施计划的“策划 Agent 对话显示与滚动合同”。
|
||||
|
||||
## 2026-09-22 Rust 对象快照必须对齐 CI 编译目录和 Cargo 环境
|
||||
|
||||
- 现象:sccache 快照已包含数百 MiB 对象,但全新 target 的“热缓存”仍然全部 miss,甚至比直接 rustc 更慢。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AGC 总版本号与发号
|
||||
|
||||
更新时间:`2026-09-20`
|
||||
更新时间:`2026-09-22`
|
||||
|
||||
## 背景
|
||||
|
||||
@@ -18,7 +18,7 @@ AGC 客户端此前按「渠道各自比高水位自增」发号:`dev-win` 与
|
||||
|
||||
- `next = 总号 + 1`;总号不存在时先一次性播种,见下节。
|
||||
- 顺序固定为「先写总号 → 再构建 → 再发渠道清单」;任何一步失败都不回滚,只烧号。
|
||||
- 统一构建:发一次号,通过 `AGC_RELEASE_VERSION` 同时传给 `dev-win`、`dev-mac`(以及后续渠道),各渠道共用同一个号。
|
||||
- 统一构建:发一次号,通过 `AGC_RELEASE_VERSION` 同时传给同一渠道组的两个平台;dev 调度写 `dev-win` / `dev-mac`,每日 release 调度写 `release-win` / `release-mac`,组内共用同一个号。
|
||||
- 单渠道热修:发一次号,只传给该渠道;其他渠道清单保持原值。
|
||||
- 显式传入 `AGC_RELEASE_VERSION` 的构建不再自行发号,只做高水位断言。
|
||||
|
||||
@@ -39,8 +39,8 @@ AGC 客户端此前按「渠道各自比高水位自增」发号:`dev-win` 与
|
||||
- 发号模块:`apps/ai-game-creator-shell/scripts/agc-global-version.mjs`(读总号 / 播种 / 发号 / 写后回读 / 渠道高水位断言 / dry-run 预览)。
|
||||
- 发号入口:`apps/ai-game-creator-shell/scripts/issue-global-version.mjs`(CI 与本地共用,输出固定为 `AGC_GLOBAL_VERSION=<version>`)。
|
||||
- 构建侧:`build-release.mjs` 的 `prepareReleaseVersion()` 优先采用传入总号,未传入时现场发号;`resolveRemoteHighWaterVersion()` 降级为断言来源,只用于「请求号低于本渠道清单版本即失败关闭」。
|
||||
- CI:`jenkins/Jenkinsfile.agc-global-version-issue` + `jenkins/agc-global-version-issue-job-config.xml`;调度管线 `jenkins/Jenkinsfile.scheduled-revision-trigger` 与手动管线先调发号 Job,再把号透传给 AGC Build。
|
||||
- 发号 Job 的 Copy Artifact 采用生产权限模式,`options` 里的 `copyArtifactPermission(...)` 必须显式列出**全部**消费者:定时调度 `Genarrative-Scheduled-Revision-Trigger` 与手动发布 `Genarrative-Manual-Build-And-Deploy`。用户触发的构建按「认证用户」判权(SYSTEM 定时构建短路放行),漏列时手动发布会报 `Unable to find project for artifact copy: Genarrative-Agc-Global-Version-Issue`,且失败点在发号之后。改完该 `options` 后必须先单独跑一次发号 Job,让 Declarative Pipeline 把 Job property 写回 Jenkins。
|
||||
- CI:`jenkins/Jenkinsfile.agc-global-version-issue` + `jenkins/agc-global-version-issue-job-config.xml`;dev 调度管线 `jenkins/Jenkinsfile.scheduled-revision-trigger`、每日 release 调度管线 `jenkins/Jenkinsfile.scheduled-release-trigger` 与手动管线先调发号 Job,再把号透传给 AGC Build。
|
||||
- 发号 Job 的 Copy Artifact 采用生产权限模式,`options` 里的 `copyArtifactPermission(...)` 必须显式列出**全部**消费者:小时 dev 调度 `Genarrative-Scheduled-Revision-Trigger`、每日 release 调度 `Genarrative-Scheduled-Release-Trigger` 与手动发布 `Genarrative-Manual-Build-And-Deploy`。用户触发的构建按「认证用户」判权(SYSTEM 定时构建短路放行),漏列时手动发布会报 `Unable to find project for artifact copy: Genarrative-Agc-Global-Version-Issue`,且失败点在发号之后。改完该 `options` 后必须先单独跑一次发号 Job,让 Declarative Pipeline 把 Job property 写回 Jenkins。
|
||||
|
||||
## 不改的东西
|
||||
|
||||
|
||||
@@ -241,6 +241,25 @@ Rust 侧在 `server-rs/crates/shared-contracts` 维护唯一权威 `GameCreation
|
||||
|
||||
Rust 分片日志在失败时输出有界 stdout 尾部中的失败段,保留 panic 位置、断言详情和 Rust 汇总;selected 只表示该分片选中的用例数量。成功分片保留简短摘要。定向验证使用相关 Rust 用例与 `node --test apps/ai-game-creator-shell/scripts/run-rust-shell-test-shards.test.mjs`。
|
||||
|
||||
## 策划 Agent 对话显示与滚动合同
|
||||
|
||||
策划工作台的对话区保留阶段状态、工作区状态、消息、可选确认/澄清和输入区。面板高度由工作台和视口决定;空消息、短回复和流式长回复不能改变消息区域的上下边界。阶段、状态条、输入区按内容排列,消息区独占剩余空间并内部滚动;待处理卡片出现时只让出其实际所需且有上限的空间,不依赖可选节点的序号分配伸缩高度。
|
||||
|
||||
- 工作区状态条复用现有聊天状态条的字号、间距和状态点。长项目名允许换行,不能撑宽面板;长错误、澄清和批量文件导入结果在受限区域内完整可读,不能挤走输入框。输入编辑器保留原有高度上限,模型/推理菜单继续允许弹出面板。
|
||||
- 已在消息底部时,实时正文与思考增高后继续跟随;用户主动上滚阅读历史后不自动抢回底部,发送新消息后恢复跟随。阶段/待处理卡片改变消息可用高度时,仍遵守同一跟随意图。滚动仅为临时 UI 状态,不写入正式会话。
|
||||
- 历史消息只有收到真实发送时间才能显示时间。现有策划持久消息不含逐消息时间,读取或刷新时保持未知,不以当前时刻补造。当前会话刚提交的乐观消息可以显示已知发送时间;正式快照覆盖后不补造或猜配旧消息时间。
|
||||
- ≤760px 时资源区与对话区单列排列,策划工作台在固定外壳内纵向滚动,用户向下滚动可到达输入区。布局使用内容高度,并以同等或更高选择器优先级覆盖外壳的 `height: 100%`;资源区明确为 560px,对话区高度为 `clamp(560px, calc(100dvh - 154px), 900px)`。文件树与消息列表各自内部滚动,长内容不增加两块面板高度。>760px 继续共用外壳剩余高度,不启用工作台整体滚动。正式主窗最小宽度不变,窄屏验收覆盖浏览器响应式布局。
|
||||
- 审批、澄清、导入期间禁用、错误重试、项目归属和发送权限沿用现有行为。此次调整不改变 Runtime、API、持久协议或数据库,无数据迁移;不重做开发 Agent 的对话布局。
|
||||
|
||||
验收使用策划组件与现有界面测试覆盖流式/历史跟随、未知时间、审批澄清和导入禁用;使用真实浏览器与当前样式核对桌面/窄屏的空、短、长消息,长项目名、长错误与长澄清,以及输入框和菜单位置。布局验收必须包含 `window-chrome → window-chrome__content → launcher-shell → launcher-main → game-project-workbench` 的完整外壳层级,覆盖 390px、760px、761px 和桌面尺寸;窄屏实际滚动工作台后,输入框须进入可视范围且可操作,长文件树、长消息和待确认内容不能使面板失去高度边界。不能只断言输入框位于聊天面板内部。开发 Agent 的既有布局回归同批执行。真实 Provider 请求不作为纯展示修复的前置条件,验证记录须区分模拟事件与真实 Provider。
|
||||
|
||||
| 验收面 | 对应证据 |
|
||||
| --- | --- |
|
||||
| 策划与开发 Agent 布局隔离、伸缩与窄屏滚动可达 | `chatDialogFrameLayout.test.ts` 包含外壳的选择器层叠回归;Chrome 实际组件、完整外壳与完整样式的 390px/760px/761px/桌面几何、滚动和输入操作检查 |
|
||||
| 实时正文/思考跟随、上滚停留、发送恢复 | `appSurface/design-agent.suite.ts` 的实时事件与发送恢复用例;还原旧滚动依赖时新增用例失败 |
|
||||
| 历史未知时间与乐观发送时间 | 同套界面测试覆盖读取、乐观发送和正式快照覆盖;恢复 `Date.now()` 补造时新增用例失败 |
|
||||
| 审批/澄清、文件导入禁用及共用控件 | `appSurface.test.ts` 现有交互回归与 Chrome 模型菜单位置检查;不改变原生调用和业务状态 |
|
||||
|
||||
## 策划 Agent 批量局部修改
|
||||
|
||||
`patch_file` 的所有 edits 均匹配同一份原文件,参数顺序不影响结果。完成唯一匹配与不重叠校验后,按原文起点升序拼接未修改片段与替换文本,最后一次性写入;任一校验失败时不写文件。回归用例覆盖乱序 edits、中文内容与替换长度增减,并核对完整落盘内容。此行为仅属于策划 Agent 文件工具。
|
||||
@@ -1805,7 +1824,8 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
- 失败关闭:单个文件失败不推进该文件的索引项,失败文件与剩余文件在下一次周期或下次关闭时重试。鉴权失败(401/403)与格式类拒绝(400/413)是确定性失败,停止本轮剩余请求并等待用户处理后重试;服务端配额或频率拒绝(429)与传输类失败按可重试处理。
|
||||
- 配额与限流:单文件 64 MiB、单次同步上传预算 512 MiB(超出部分延后到下一次)、单项目常驻上限 2 GiB(客户端在扫描后先判,超限直接给出明确失败;服务端按清单累计体积复核并返回 413);服务端按用户做进程内小时配额(文件 3000 次、清单 120 次)并对同一项目强制 5 秒最小清单间隔,超限返回 429 且带 `Retry-After`。进程内配额只用于抑制异常客户端与失控重试,跨节点配额由"单项目上限 + 清单引用回收"保证。
|
||||
- 生命周期:同步有界超时(单文件与整次同步分别设上限),项目关闭与应用退出路径不因同步失败而阻塞或延迟退出超过超时上限。
|
||||
- 上传内容边界:复用项目索引与 checkpoint 同一份 `should_skip_project_snapshot_path` 口径——整个 `.agent`(含 runtime、logs、checkpoint、manifest、project.lock)、版本控制目录、`node_modules`/`target`/`dist`/`build`/`coverage`/`.cache`、凭据目录与 `.pem`/`.key` 等敏感后缀都不参与同步;符号链接与重解析点同样跳过。单文件(64 MiB)与单次同步总量(512 MiB)各有上限,超限文件进入跳过或延后清单而不是静默丢弃。
|
||||
- 上传内容边界:`.agent` 是项目身份与 Agent 状态的权威位置,**整目录参与同步**(`manifest.json`、`agent.db` 及其 WAL/SHM、conversations、logs、checkpoint、workbench、`project.lock`、`.manifest.json.lock`)。因此快照同步使用独立口径 `should_skip_project_snapshot_sync_path`:它与 `should_skip_project_snapshot_path` 共用同一份组件与后缀规则,只额外放行 `.agent` 组件本身,以及 `.agent` 内的 Agent 状态数据库后缀(`.db`/`.db-wal`/`.db-shm`)。其余排除项在 `.agent` 内同样生效——版本控制目录、`node_modules`/`target`/`dist`/`build`/`coverage`/`.cache`、凭据目录、`.pem`/`.key`/`.sql` 等敏感后缀与 `.env*` 都不参与同步;符号链接与重解析点在扫描阶段跳过(不能被当作普通文件传输)。单文件(64 MiB)与单次同步总量(512 MiB)各有上限,超限文件进入跳过或延后清单而不是静默丢弃。
|
||||
- 该口径只对快照同步生效:项目索引、checkpoint、Agent 上下文与 git 检查继续排除整个 `.agent`。收录 `.agent` 意味着会话记录、运行日志与诊断快照随项目离机并写入该用户自己的私有前缀,这是本轮产品决定(远端工程包要能还原项目身份与 AGC 历史),不是遗漏。
|
||||
|
||||
### 契约与兼容
|
||||
|
||||
@@ -1829,7 +1849,7 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
- `GET /admin/api/project-snapshots/{userId}/{projectId}/download` 只读取该用户/项目的固定清单与其引用对象,返回 `application/zip` 附件。ZIP 中路径直接使用原始相对路径,不包含 userId、摘要目录或 OSS 前缀;名称使用经过安全处理的项目名和 revision。下载固定本次读到的清单,远端并发回收导致对象缺失则整体失败,不能静默遗漏。
|
||||
- `partial` 快照下载返回 409;`unverified` 历史快照可导出已同步文件,列表明确显示“完整性未知”,动作称“下载已存文件”。`ready` 才显示“下载完整工程”。ZIP 构建核验每一文件的长度与 fnv1a64 摘要,拒绝穿越、绝对路径、重复/大小写冲突路径、非法项目身份;缺失或损坏整体失败,不返回成功的残缺 ZIP。
|
||||
- ZIP 使用服务端临时文件并限制并发,不将 2 GiB 工程整体驻留内存;成功、失败、客户端取消均清理临时文件。单文件、总量、文件数沿用上传上限,超限明确拒绝。零字节工程文件可以上传和导出。OSS 凭据与签名不下发浏览器,列表失败保留错误而非伪造空列表。
|
||||
- 工程归档范围与上传策略一致:源码、素材及引擎配置按原路径保存,依赖/构建缓存、凭据、`.agent` 会话与运行日志排除;此 ZIP 不声明能恢复 AGC 对话历史。后台读取需要目标前缀的 ListObjects 与 GetObject 权限,不新增数据库表,不改 External API。
|
||||
- 工程归档范围与上传策略一致:源码、素材、引擎配置与 `.agent`(含会话、运行日志、checkpoint、`agent.db`)都按原相对路径保存,依赖/构建缓存与凭据排除;因此该 ZIP 可以还原项目身份与 AGC 对话历史(归档只保证字节还原,不承诺跨机器可用性)。后台读取需要目标前缀的 ListObjects 与 GetObject 权限,不新增数据库表,不改 External API。
|
||||
- 验收覆盖真实单窗口生命周期登记、首次/增量/零字节上传、后台列表分页和权限、ZIP 解压目录及摘要、部分/历史清单、缺失对象、路径拒绝、下载取消清理,并分别报告定向测试和真实环境证据。
|
||||
|
||||
### 未决问题
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user