批准 GDD 预填建造指令
新增固定 GDD 建造说明并与参考附件联合预填 保持点击做成游戏不自动创建项目或启动 Agent 补充首页提交链路回归测试并同步技术方案与决策记录
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<HomeAttachmentDraft[]> =
|
||||
@@ -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 (
|
||||
<OnChangePlugin
|
||||
@@ -281,7 +300,8 @@ export default function RichInputArea(props: RichInputAreaProps) {
|
||||
onChange={props.onChange}
|
||||
onEnter={props.onEnter}
|
||||
initialAttachments={props.initialAttachments}
|
||||
onInitialAttachmentsApplied={props.onInitialAttachmentsApplied}
|
||||
initialPrompt={props.initialPrompt}
|
||||
onInitialPrefillApplied={props.onInitialPrefillApplied}
|
||||
/>
|
||||
</LexicalComposer>
|
||||
);
|
||||
|
||||
@@ -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();
|
||||
}}
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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;用户主动提交后,固定文字与附件才作为现有做游戏链路的输入。
|
||||
|
||||
@@ -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 审批卡
|
||||
|
||||
|
||||
Reference in New Issue
Block a user