diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/mod.rs index d5ccc94c4..e33bfae72 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/mod.rs @@ -5,8 +5,8 @@ mod validation; mod wire; pub(crate) use model::{ - DirectCodexUserContentPart, DirectCodexUserItem, DirectCodexUserMessageEnvelope, - DirectCodexUserMessageItem, DirectCodexUserRole, DirectCodexUserRuntimeRegionPart, + DirectCodexUserContentPart, DirectCodexUserItem, DirectCodexUserMessageItem, + DirectCodexUserRole, DirectCodexUserRuntimeRegionPart, }; pub(crate) use validation::validate_direct_codex_user_item; pub(crate) use wire::{ diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/model.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/model.rs index b46336b66..266f330cc 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/model.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/model.rs @@ -61,13 +61,6 @@ pub(crate) struct DirectCodexUserRuntimeRegionPart { pub(crate) resource_ids: Vec, } -#[derive(Clone, Debug, Deserialize, Serialize, TS)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/project-workspace/generated/"))] -pub(crate) struct DirectCodexUserMessageEnvelope { - pub(crate) item: DirectCodexUserItem, -} - #[cfg(test)] mod tests { use super::*; diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index e0c04bc0b..bfd4cb80d 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -11902,7 +11902,11 @@ export function App({ setDirectThreadChat((state) => mergeDirectHistoryItems(state, pages.items), ); - setDirectHistoryHasMore(pages.hasMore); + // 首页或中途读取失败时保留旧值:失败页没有可靠的 hasMore,不能因为 + // 一次瞬时 IO 抖动把「显示更早」按钮永久收掉。 + if (!pages.error) { + setDirectHistoryHasMore(pages.hasMore); + } directHistoryOldestItemIdRef.current = pages.firstItemId ?? directHistoryOldestItemIdRef.current; if (pages.error) { diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserContentPart.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserContentPart.ts index eec5662e2..10c4e0f5a 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserContentPart.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserContentPart.ts @@ -1,4 +1,5 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +// This file is generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + import type { DirectCodexUserRuntimeRegionPart } from './DirectCodexUserRuntimeRegionPart'; export type DirectCodexUserContentPart = diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserItem.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserItem.ts index aa1ee88dd..4c9ea8ca3 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserItem.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserItem.ts @@ -1,9 +1,5 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +// This file is generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + import type { DirectCodexUserMessageItem } from './DirectCodexUserMessageItem'; -/** - * DirectProject 本轮 user input 的唯一结构化入口。 - */ -export type DirectCodexUserItem = { - type: 'message'; -} & DirectCodexUserMessageItem; +export type DirectCodexUserItem = DirectCodexUserMessageItem; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageEnvelope.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageEnvelope.ts deleted file mode 100644 index 97e0b0dae..000000000 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageEnvelope.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { DirectCodexUserItem } from './DirectCodexUserItem'; - -export type DirectCodexUserMessageEnvelope = { item: DirectCodexUserItem }; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageItem.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageItem.ts index a1101c8cb..f7447dc5d 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageItem.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserMessageItem.ts @@ -1,9 +1,11 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +// This file is generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + import type { DirectCodexUserContentPart } from './DirectCodexUserContentPart'; import type { DirectCodexUserRole } from './DirectCodexUserRole'; export type DirectCodexUserMessageItem = { + type: 'message'; role: DirectCodexUserRole; - content: Array; + content: DirectCodexUserContentPart[]; id: string; }; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRole.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRole.ts index 0c2540122..e1dc59c59 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRole.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRole.ts @@ -1,3 +1,3 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +// This file is generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. export type DirectCodexUserRole = 'user'; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRuntimeRegionPart.ts b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRuntimeRegionPart.ts index b134fb7bc..296c0d19a 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRuntimeRegionPart.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUserRuntimeRegionPart.ts @@ -1,13 +1,13 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +// This file is generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. export type DirectCodexUserRuntimeRegionPart = { label: string; - runId: string | null; - versionId: string | null; - elementTag: string | null; - elementRole: string | null; - text: string | null; - width: number | null; - height: number | null; - resourceIds: Array; + runId?: string; + versionId?: string; + elementTag?: string; + elementRole?: string; + text?: string; + width?: number; + height?: number; + resourceIds: string[]; }; diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts b/apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts index 8b163d45a..c08fba49a 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts @@ -13,6 +13,7 @@ import { import type { DirectCodexUserContentPart, DirectCodexUserItem, + DirectCodexUserMessageItem, } from './generated'; export type ResourceReferenceSource = @@ -99,17 +100,16 @@ export function chatReferenceToContentPart( if (reference.type === 'resource') { return { type: 'agc_resource_reference', resourceId: reference.resourceId }; } - // 生成绑定里可选字段是 `T | null`(Rust `Option` 会显式序列化成 null,不是省略键)。 return { type: 'agc_runtime_region_reference', label: reference.label, - runId: reference.runId ?? null, - versionId: reference.versionId ?? null, - elementTag: reference.elementTag ?? null, - elementRole: reference.elementRole ?? null, - text: reference.text ?? null, - width: reference.width ?? null, - height: reference.height ?? null, + runId: reference.runId, + versionId: reference.versionId, + elementTag: reference.elementTag, + elementRole: reference.elementRole, + text: reference.text, + width: reference.width, + height: reference.height, resourceIds: reference.resourceIds, }; } @@ -135,7 +135,7 @@ export function chatComposerDraftToDirectCodexUserItem( role: 'user', content, id, - } satisfies DirectCodexUserItem; + } satisfies DirectCodexUserMessageItem; } export function resourceDisplayName(asset: GameCreationAppAssetManifestEntry) { diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingChange.ts b/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingChange.ts deleted file mode 100644 index 3bb2c5c4d..000000000 --- a/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingChange.ts +++ /dev/null @@ -1,6 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { NodeComponent } from "./NodeComponent"; -import type { NodeId } from "./NodeId"; -import type { StageStatus } from "./StageStatus"; - -export type BindingChange = { node_id: NodeId, component: NodeComponent, component_status: StageStatus, }; diff --git a/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingDTO.ts b/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingDTO.ts deleted file mode 100644 index beb340894..000000000 --- a/apps/ai-game-creator-shell/src/features/ui-editor/types/BindingDTO.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { BindingChange } from "./BindingChange"; - -export type BindingDTO = { changes: Array, }; diff --git a/apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts b/apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts index 50bfe55bb..6d127375d 100644 --- a/apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts +++ b/apps/ai-game-creator-shell/tests/directHistoryPaging.test.ts @@ -231,4 +231,23 @@ describe('DirectProject 历史分页连拉', () => { expect(result.hasMore).toBe(true); expect(result.error).toBe(failure); }); + + it('首页读取失败时保留首屏锚点并返回错误', async () => { + const failure = new Error('首页读取失败'); + const readSlice = vi.fn(async (_beforeItemId: string | null) => { + throw failure; + }); + + const result = await readDirectHistoryPages({ + existingEntries: [], + beforeItemId: null, + readSlice, + }); + + expect(readSlice).toHaveBeenCalledTimes(1); + expect(result.items).toEqual([]); + expect(result.firstItemId).toBeNull(); + expect(result.hasMore).toBe(false); + expect(result.error).toBe(failure); + }); }); diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 441aa11c3..f6651d3b1 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -5691,8 +5691,8 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **现象**:在 `apps/ai-game-creator-shell/src-tauri` 跑过 `cargo test` 之后,`npm run ai-game-creator-shell:typecheck` 报 10 条类型错(`src/features/project-workspace/resourceReferences.ts:106-112` 的 `string | undefined` 不能赋给 `string | null`;同文件 134 行的对象字面量带 `type: 'message'`,而 `DirectCodexUserMessageItem` 里没有该字段),`npm run ai-game-creator-shell:build` 也死在 `beforeBuildCommand` 的同一条 typecheck 上。 - **原因**:crate 里的 ts-rs 导出会按**本机依赖版本**重写 `src/features/project-workspace/generated/DirectCodexUser*.ts`:注释头变成 "This file was generated…"、字符串改双引号、`DirectCodexUserMessageItem` 丢掉 `type: 'message'` 判别字段、并多出一个 `DirectCodexUserMessageEnvelope.ts`。仓库里提交的那份是前端真正依赖的形状(前端按带 `type` 的判别联合写),重写后两边就对不上——错在生成器版本漂移,不在前端。 -- **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后先 `git checkout -- apps/ai-game-creator-shell/src/features/project-workspace/generated`,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`,然后才做 typecheck / 打包;绑定与前端形状冲突时以**已提交的绑定 + 前端**为基准排查。 -- **验证**:恢复提交版本后 `npm run ai-game-creator-shell:typecheck` exit 0(`[skill-pack] OK`);保留重写结果时同一条命令 exit 2。release 构建本身还会在 `src/features/ui-editor/types/` 落下 `BindingChange.ts` / `BindingDTO.ts` 两个无人引用的未跟踪文件,属同类生成产物。 +- **处理(现行口径)**:不要把重写结果当改动提交。跑过 `cargo test` 或构建后只恢复 `apps/ai-game-creator-shell/src/features/project-workspace/generated/DirectCodexUser*.ts` 的仓库版本,再删掉多出来的 `DirectCodexUserMessageEnvelope.ts`;不要恢复整个 `generated/` 目录,以免误删 DirectThread 的现役绑定。绑定与前端形状冲突时以**已提交的 DirectCodexUser 绑定 + 前端**为基准排查。 +- **验证**:恢复仓库版本后 `npm run ai-game-creator-shell:typecheck` exit 0(`[skill-pack] OK`);保留重写结果时同一条命令 exit 2。release 构建本身还会在 `src/features/ui-editor/types/` 落下 `BindingChange.ts` / `BindingDTO.ts` 两个无人引用的生成产物;它们不属于前端契约,发现后直接删除,不提交。 - **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/`(ts-rs 导出源)、`apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts`、`apps/ai-game-creator-shell/scripts/build-release.mjs`(`beforeBuildCommand`)。 ## 2026-09-16 Node 26 下 vitest 的 jsdom 用例拿不到 window.localStorage