diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx index 38146ff4a..13cb25887 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx +++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx @@ -6489,41 +6489,51 @@ export default function ProjectDevelopmentView({ * * 与共享 composer 的 `resetFailedDialogStatus` 同口径:提示词变了就不再是上一次 * 失败的那份请求,状态回到 idle、错误清空——同时提交侧会按新提示词重铸请求身份。 + * 比较用的草稿文本必须和输入区自己读草稿的口径一致(都带 `manifest.assets`): + * 少传素材清单会把 chip 读成 `@内部 id`,与真正写进面板的 `@显示名` 永远不等, + * 于是每次改写都再 `replaceText` 一次。 */ - const applyResourceQuickEditPrompt = useCallback((text: string) => { - const currentDraft = quickEditPromptInputRef.current?.getDraft(); - if ( - currentDraft && - directCodexContentToPromptText(currentDraft.content) !== text - ) { - quickEditPromptInputRef.current?.replaceText(text); - } - setQuickEditPanel((current) => - current - ? { - ...current, - prompt: text, - status: current.status === 'failed' ? 'idle' : current.status, - errorMessage: - current.status === 'failed' ? undefined : current.errorMessage, - } - : current, - ); - }, []); + const applyResourceQuickEditPrompt = useCallback( + (text: string) => { + const currentDraft = quickEditPromptInputRef.current?.getDraft(); + if ( + currentDraft && + directCodexContentToPromptText( + currentDraft.content, + manifest.assets, + ) !== text + ) { + quickEditPromptInputRef.current?.replaceText(text); + } + setQuickEditPanel((current) => + current + ? { + ...current, + prompt: text, + status: current.status === 'failed' ? 'idle' : current.status, + errorMessage: + current.status === 'failed' ? undefined : current.errorMessage, + } + : current, + ); + }, + [manifest.assets], + ); /** * 快速编辑提示词输入区的整体草稿(文本 + `@` 引用)。 * * 文本仍走 `applyResourceQuickEditPrompt`(失败态重置口径不变),引用单独收下来供 - * 输入区回填 chip。提交时的出站 payload 就是这份文本:与聊天 `@` 同源、同字面量。 + * 输入区回填 chip。提交时的出站 payload 就是这份文本:与聊天 `@` 同源、同字面量, + * 所以 `@` 引用必须带上 `manifest.assets` 按显示名展开。 */ const applyResourceQuickEditDraft = useCallback( (draft: ChatComposerDraft) => { applyResourceQuickEditPrompt( - directCodexContentToPromptText(draft.content), + directCodexContentToPromptText(draft.content, manifest.assets), ); }, - [applyResourceQuickEditPrompt], + [applyResourceQuickEditPrompt, manifest.assets], ); /** diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 26eacc4ae..a2fa70792 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -5624,3 +5624,11 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/` - **处理**:投影层改成「向前合并」——待写文本先攒在 `pendingText` 上,下一个文本到来时合并成同一个 `input_text`(`\n` 因此落在 `\n把这一版改成夜景` 里);攒到最后仍只有空白的(以换行结尾、两个 chip 之间只隔一个换行)不入 content,因为 Rust `validate_direct_codex_user_item` 会拒绝空 `input_text`,直接按 review 的 `text.includes('\n')` 落 part 会让「chip 换行 chip」这种输入整轮发不出去。 - **验证**:`apps/ai-game-creator-shell/tests/resourceReferenceInput.test.tsx` 新增「引用后面的段落分隔不会被吞掉」,断言 chip 后一段的 part 为 `{ type: 'input_text', text: '\n把这一版改成夜景' }`、派生文本逐字一致、且不出现纯空白 part;去掉修复后该用例变红(比对失败在 content 相等那一行)。 - **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx`(`DraftContentCollector` / `appendInputText`)、`docs/project-memory/plans/【里程碑】DirectProject canonical content严格边界-2026-09-16.md`。 + +## 2026-09-16 派生文本漏传 `manifest.assets`:`@引用` 从显示名退化成内部 id + +- **现象**:快速编辑面板里 `@` 插了素材再点「修改」,出站 `derive_local_project_resource` 的 `prompt` 是 `把夜色改成星空@source-rules`,而界面 chip 与聊天输入区显示的是 `@rules`;仓库自带的 `projectResourceLiveIntegration` 用例因此长期是红的(`expected '把夜色改成星空@rules' to be '把夜色改成星空@source-rules'`)。同一根因还让排队消息 chip 显示 `@asset:…`。 +- **原因**:`directCodexContentToPromptText(content, assets)` 的 `assets` 有默认值 `[]`,漏传不报错、只是把 `agc_resource_reference` 退化成 `${resourceId}`。`ResourceReferenceInput` 自己读草稿的四处都带了 `manifest.assets`,而它的三个消费方漏传:`chatComposerQueue.queuedChatTurnLabel`(宿主 `ComposerTurnQueue` 也没接素材清单)、`project-development/index.tsx` 的 `applyResourceQuickEditPrompt` 与 `applyResourceQuickEditDraft`;后两个的 `useCallback` 依赖里同样没有 `manifest.assets`,改完还会读到旧清单。 +- **处理**:三个消费方全部补上素材清单并进依赖数组——`queuedChatTurnLabel(turn, assets)` + `ComposerTurnQueue` 新增 `assets` 属性(由 `ProjectSupervisorView` 传 `chatProjectAssets`)、快速编辑的两处改用 `manifest.assets`。改「比较用的草稿文本」与「落进面板的文本」必须同一个口径,否则 `replaceText` 会每次输入都重跑一遍。 +- **验证**:`apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx` 的「快速编辑提示词里能 @ 出资源选择器」由红转绿(该文件 29 passed);`tests/appSurface/chat-composer.suite.ts` 新增「队列 chip 的 @ 引用按 manifest 显示名展开」;`appSurface.test.ts` 467 passed、定向 51 passed、`npm run ai-game-creator-shell:typecheck`、`npm run check:encoding` 通过。 +- **关联**:`apps/ai-game-creator-shell/src/features/project-workspace/chatComposerQueue.ts`、`ComposerControls.tsx`、`ProjectSupervisorView.tsx`、`apps/ai-game-creator-shell/src/view/project-development/index.tsx`、`apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx`。