diff --git a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx index fcfb11a50..33c664552 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx +++ b/apps/ai-game-creator-shell/src/features/app-shell/WorkspaceLauncher.tsx @@ -78,7 +78,8 @@ export function WorkspaceLauncherShell({ setAgentResults: setActiveProjectAgentResults, resetLauncherHomeDraft, homePrefillAttachments, - clearHomePrefillAttachments, + homePrefillPrompt, + clearHomePrefill, prepareHomeGameFromApprovedGdd, createHomeDraftAutomatically, openProject, @@ -263,7 +264,7 @@ export function WorkspaceLauncherShell({ currentUser={currentUser} onLogout={() => { resetLauncherHomeDraft(); - clearHomePrefillAttachments(); + clearHomePrefill(); accountWallet.resetWalletBalance(); onLogout(); }} @@ -298,7 +299,8 @@ export function WorkspaceLauncherShell({ recentProjectRows={recentProjectRows} onCreateDraftAutomatically={createHomeDraftAutomatically} initialAttachments={homePrefillAttachments} - onInitialAttachmentsApplied={clearHomePrefillAttachments} + initialPrompt={homePrefillPrompt} + onInitialPrefillApplied={clearHomePrefill} onProjectsOpen={() => setLauncherView('projects')} onProjectOpen={(path) => { setProjectPath(path); diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts index dd6b1e94e..a8dba6259 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts @@ -49,6 +49,14 @@ type UseHomeProjectCreationOptions = { rememberRecentWorkspace: (projectPath: string) => void; }; +const APPROVED_GDD_HOME_PROMPT = [ + '请按照附件中的已批准 GDD 开始建造这款游戏。', + '', + '这份 GDD 已覆盖游戏定位与一句话概念、类型与美术方向、游戏支柱、核心循环、目标用户、平台与输入事实、MVP 系统、暂不纳入范围、创作者提示和原型验证项。', + '', + '请先阅读并理解附件中的 fast_gdd.md,以它作为本次建造的主要依据,优先实现其中 MVP 范围内的可运行游戏原型。', +].join('\n'); + export function useHomeProjectCreation({ setStatus, setLauncherView, @@ -84,6 +92,7 @@ export function useHomeProjectCreation({ const [homePrefillAttachments, setHomePrefillAttachments] = useState< HomeAttachmentDraft[] >([]); + const [homePrefillPrompt, setHomePrefillPrompt] = useState(''); function validateProjectPath(nextProjectPath: string) { const trimmedProjectPath = nextProjectPath.trim(); @@ -124,6 +133,7 @@ export function useHomeProjectCreation({ resetLauncherHomeDraft(); setHomeCreationType('game'); + setHomePrefillPrompt(APPROVED_GDD_HOME_PROMPT); setHomePrefillAttachments([ { id: `approved-gdd-${Date.now().toString(36)}`, @@ -644,7 +654,11 @@ export function useHomeProjectCreation({ pendingNonEmptyProject, resetLauncherHomeDraft, homePrefillAttachments, - clearHomePrefillAttachments: () => setHomePrefillAttachments([]), + homePrefillPrompt, + clearHomePrefill: () => { + setHomePrefillAttachments([]); + setHomePrefillPrompt(''); + }, prepareHomeGameFromApprovedGdd, createHomeDraft, createHomeDraftAutomatically, diff --git a/apps/ai-game-creator-shell/src/view/home/components/RichInputArea/index.tsx b/apps/ai-game-creator-shell/src/view/home/components/RichInputArea/index.tsx index e412756b0..d6997be68 100644 --- a/apps/ai-game-creator-shell/src/view/home/components/RichInputArea/index.tsx +++ b/apps/ai-game-creator-shell/src/view/home/components/RichInputArea/index.tsx @@ -29,7 +29,8 @@ type RichInputAreaProps = { onChange: (value: Draft) => void; onEnter: () => void; initialAttachments?: readonly HomeAttachmentDraft[]; - onInitialAttachmentsApplied?: () => void; + initialPrompt?: string; + onInitialPrefillApplied?: () => void; children?: React.ReactNode; }; const INSERT_ATTACHMENTS_COMMAND: LexicalCommand = @@ -107,13 +108,18 @@ function EditorPlugins({ onChange, onEnter, initialAttachments = [], - onInitialAttachmentsApplied, + initialPrompt = '', + onInitialPrefillApplied, }: Pick< RichInputAreaProps, - 'onChange' | 'onEnter' | 'initialAttachments' | 'onInitialAttachmentsApplied' + | 'onChange' + | 'onEnter' + | 'initialAttachments' + | 'initialPrompt' + | 'onInitialPrefillApplied' >) { const [editor] = useLexicalComposerContext(); - const initialAttachmentsAppliedRef = useRef(false); + const initialPrefillAppliedRef = useRef(false); useEffect( () => @@ -198,16 +204,29 @@ function EditorPlugins({ useEffect(() => { if ( - initialAttachmentsAppliedRef.current || - initialAttachments.length === 0 + initialPrefillAppliedRef.current || + (initialPrompt.trim().length === 0 && initialAttachments.length === 0) ) { return; } - initialAttachmentsAppliedRef.current = true; - editor.dispatchCommand(INSERT_ATTACHMENTS_COMMAND, [...initialAttachments]); + initialPrefillAppliedRef.current = true; + if (initialPrompt.length > 0) { + editor.dispatchCommand(INSERT_CLIPBOARD_TEXT_COMMAND, initialPrompt); + } + if (initialAttachments.length > 0) { + editor.dispatchCommand(INSERT_ATTACHMENTS_COMMAND, [ + ...initialAttachments, + ]); + } onChange(editor.getEditorState()); - onInitialAttachmentsApplied?.(); - }, [editor, initialAttachments, onChange, onInitialAttachmentsApplied]); + onInitialPrefillApplied?.(); + }, [ + editor, + initialAttachments, + initialPrompt, + onChange, + onInitialPrefillApplied, + ]); return ( ); diff --git a/apps/ai-game-creator-shell/src/view/home/index.tsx b/apps/ai-game-creator-shell/src/view/home/index.tsx index 9a6a33447..7416e02e1 100644 --- a/apps/ai-game-creator-shell/src/view/home/index.tsx +++ b/apps/ai-game-creator-shell/src/view/home/index.tsx @@ -105,7 +105,8 @@ type HomeViewProps = { onProjectOpen: (path: string) => void; onProjectPick: () => void; initialAttachments?: readonly HomeAttachmentDraft[]; - onInitialAttachmentsApplied?: () => void; + initialPrompt?: string; + onInitialPrefillApplied?: () => void; }; export default function HomeView({ @@ -117,7 +118,8 @@ export default function HomeView({ onProjectOpen, onProjectPick, initialAttachments = [], - onInitialAttachmentsApplied, + initialPrompt = '', + onInitialPrefillApplied, }: HomeViewProps) { const homeCreationType = useLauncherHomeDraftStore( (state) => state.creationType, @@ -240,7 +242,8 @@ export default function HomeView({ placeholder={activeCreationType.placeholder} onChange={setHomeRichText} initialAttachments={initialAttachments} - onInitialAttachmentsApplied={onInitialAttachmentsApplied} + initialPrompt={initialPrompt} + onInitialPrefillApplied={onInitialPrefillApplied} onEnter={() => { void createFromHome(); }} diff --git a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts index 8a4ae3e9b..852c86e45 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts @@ -61,7 +61,8 @@ function ApprovedGddHomeBridgeHarness({ onProjectOpen: () => undefined, onProjectPick: () => undefined, initialAttachments: controller.homePrefillAttachments, - onInitialAttachmentsApplied: controller.clearHomePrefillAttachments, + initialPrompt: controller.homePrefillPrompt, + onInitialPrefillApplied: controller.clearHomePrefill, }); } @@ -1575,6 +1576,14 @@ export function registerHomeProjectCreationTests() { ); await screen.findByText('fast_gdd.md'); + await waitFor(() => { + expect(screen.getByLabelText('创作想法').textContent).toContain( + '请按照附件中的已批准 GDD 开始建造这款游戏。', + ); + }); + expect(screen.getByLabelText('创作想法').textContent).toContain( + '这份 GDD 已覆盖游戏定位与一句话概念、类型与美术方向、游戏支柱、核心循环、目标用户、平台与输入事实、MVP 系统、暂不纳入范围、创作者提示和原型验证项。', + ); const creationTypes = screen.getByRole('group', { name: '创作类型' }); expect( within(creationTypes) @@ -1598,6 +1607,20 @@ export function registerHomeProjectCreationTests() { 'chat_with_game_creator_direct_codex', expect.anything(), ); + + fireEvent.click(screen.getByRole('button', { name: '开启创作' })); + await waitFor(() => { + expect(onCreateDraftAutomatically).toHaveBeenCalledTimes(1); + }); + const submittedDraft = onCreateDraftAutomatically.mock.calls[0]?.[0] as + | HomeDraft + | undefined; + expect(submittedDraft?.prompt).toContain( + '请按照附件中的已批准 GDD 开始建造这款游戏。', + ); + expect(submittedDraft?.attachments.map(({ file }) => file.name)).toEqual([ + 'fast_gdd.md', + ]); }); it('keeps the home composer out of chat mode while automatic project creation is pending', async () => { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 425c837bb..63b19733e 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -7835,3 +7835,9 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在 - `autonomous-game-build` 中,manifest `dependencies` 只作为上下文,不阻塞 ready;代码、设计、美术、音频和发布任务允许并行启动,child 不依赖固定回执顺序或固定 run 身份才能推进。 - 任务最终状态不再提前绑定平台画布、preview、static smoke 或发布产物检查;这些内容不参与该档位的完成判定,也不会因缺失而重置已完成任务。父 run 在任务图进入终态后直接收束并回复。 - 本档位仍沿用现有项目根和工具权限边界;本次调整只解除流程编排与平台产物验收前置,不新增第二套任务系统。 + +## 2026-08-30 批准 GDD 回填建造指令 + +- “做成游戏”回首页时,除了把当前有效的 `game/fast_gdd.md` 作为 `text/markdown` 参考附件预填,还要在首页输入框预填固定建造指令。 +- 固定指令只说明 GDD 覆盖的栏目(定位、类型与美术、支柱、核心循环、目标用户、平台与输入、MVP 系统、范围边界、创作者提示、原型验证),不读取具体 GDD 做总结或缩写。 +- 预填动作仍不创建项目、不发送首页需求、不启动 Agent;用户主动提交后,固定文字与附件才作为现有做游戏链路的输入。 diff --git a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md index 3756b7afc..c6ba3a37e 100644 --- a/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md +++ b/docs/technical/【技术方案】立项策划Agent(Fast GDD)-2026-08-10.md @@ -1518,8 +1518,8 @@ type PlanningBaselineInput = - 仅首页“做方案”新建项目提交 `standard + project-supervisor-plan`(2026-08-13 按 D11 更正,旧值 `project-supervisor-plan-chat` 作废);“做游戏”和“做素材”保持 `autonomous-game-build` 直接开建。前端只提交 Supervisor 根 run 的身份,**不提交也不感知策划子 Agent**——后者由 Supervisor 在服务端通过 `agent.delegate` 派生,页面侧不得直接创建或引用它。 - 项目页新建、打开既有项目和 Godot 导入不新增“进入立项策划”入口,保持现行构建/打开语义;只有已存在 planning sidecar 或 active plan lineage 的项目恢复原有策划链路。 - 策划阶段聊天输入属于当前 run:有活跃决策卡/审批卡时,输入回到该卡片对应 action;无 active run 时才可创建新的 plan continuation。 -- approved 后显示“做成游戏”。点击后读取当前有效的 `game/fast_gdd.md`,回到首页并把它作为 `text/markdown` 参考附件预填到“做游戏”输入框;该动作不创建新项目、不发送首页需求、不启动 `autonomous-game-build`。 -- 用户随后主动提交首页输入时,才沿现有做游戏链路创建新的自动项目、导入附件并启动 Direct Codex。这里的附件是参考材料,不把原项目的 `approvedGddRef` 复制到新项目。 +- approved 后显示“做成游戏”。点击后读取当前有效的 `game/fast_gdd.md`,回到首页并把它作为 `text/markdown` 参考附件预填到“做游戏”输入框,同时预填固定的建造指令:说明 GDD 覆盖的栏目,并要求 Agent 先阅读附件、按 GDD 的 MVP 范围开始建造;这段文字不根据具体 GDD 内容生成。该动作不创建新项目、不发送首页需求、不启动 `autonomous-game-build`。 +- 用户随后主动提交首页输入时,才沿现有做游戏链路创建新的自动项目、导入附件并启动 Direct Codex。这里的附件和预填文字都是本次建造的输入,不把原项目的 `approvedGddRef` 复制到新项目。 ### 18.2 GDD 审批卡