合并 origin/master 到资源工作台 V3 分支:解 4 处冲突并保留两侧行为
- WorkspaceLauncher.tsx:保留本分支清单快照 CAS 拒收提示(manifestMergeNotice 提示条、data-manifest-merge-* 观察点、recoverRejectedManifestSnapshot「重新读取清单」)与 activeVersionId/onActiveVersionChange 版本口径,并入 master 的策划/游戏运行态切换(onMakeGame + switchToGameRuntime、suppressInitialGameTurn 抑制首轮、supervisor key 带 agentRuntimeMode、onSwitchToGameRuntime),planningStartMode 统一取 master 的派生值(上下文 startMode 为 planning 且未切到 game 运行时) - ProjectSupervisorView.tsx:props 同时保留本分支 versions/activeVersionId 与 master 的 designView/onDesignApprove/onDesignClarify/onDesignRetry,DesignAgentSurface 审批链路与本分支资源引用输入区并存;directCodex 输入区保留本分支 @ 引用按钮 + 模型选择 + 发送按钮控制条,发送按钮禁用条件并入 master 的 designView 审批待定口径,模型选择沿用 master 的「对话中可切换」口径 - styles.css:本分支追加的资源画布/输入区样式块与 master 追加的 .design-agent-reasoning 样式块都保留,并补上本分支最后一条规则的收尾大括号 - view/project-development/index.tsx:保留本分支的 image-editor 引用(ImageCanvasProjectAssetPickerDialog、ImageCanvasQuickEditPanelView、ImageCanvasSelectedLayerToolbarView、useImageCanvasFloatingOptionDismiss),去掉 master 对已退役 features/asset-canvas 的 import(本分支已由 resource-canvas 取代),保留 master 的 DesignWorkspacePanel 与 planningStartMode 策划工作台分支 - tests/workspaceLauncherManifestMerge.test.tsx:补 master 新引入的 get_design_agent_runtime_mode mock(返回 null,与 master 各套件同口径),拒收提示断言不变 - tests/appSurface/design-agent.suite.ts:审批待定禁用输入的断言改用本分支 Lexical 输入区的禁用口径(容器 data-disabled + editor.setEditable(false)),断言意图不变 - 验证:npm run typecheck 通过;apps/ai-game-creator-shell typecheck 通过;apps/ai-game-creator-shell/tests 96 个测试文件 1380 通过 4 跳过 0 失败;全仓 vitest 297 通过 2 失败(scripts 下两例为 Windows 权限语义导致的既有失败,相关文件与实现均未参与本次合并);npm run check:encoding 与 git diff --check 通过
This commit is contained in:
@@ -64,6 +64,13 @@ export function WorkspaceLauncherShell({
|
||||
title: string;
|
||||
message: string;
|
||||
} | null>(null);
|
||||
// 「做成游戏」切换记录按项目上下文(路径 + createdAt)定位。运行模式必须随
|
||||
// currentProjectContext 同步派生,不能靠 effect 后置修正:首帧挂错 lane 会先
|
||||
// 以游戏运行时挂载并消耗首轮 claim,重挂后的策划实例再也发不出首轮。
|
||||
const [gameRuntimeSwitch, setGameRuntimeSwitch] = useState<{
|
||||
projectPath: string;
|
||||
createdAt: number;
|
||||
} | null>(null);
|
||||
const developerAgent = useDeveloperAgentPanel(launcherView);
|
||||
const homeProject = useHomeProjectCreation({
|
||||
setStatus,
|
||||
@@ -87,6 +94,17 @@ export function WorkspaceLauncherShell({
|
||||
createHomeDraftAutomatically,
|
||||
openProject,
|
||||
} = homeProject;
|
||||
const switchedToGameRuntime =
|
||||
gameRuntimeSwitch !== null &&
|
||||
currentProjectContext !== null &&
|
||||
gameRuntimeSwitch.projectPath === currentProjectContext.projectPath &&
|
||||
gameRuntimeSwitch.createdAt === currentProjectContext.createdAt;
|
||||
const planningStartMode =
|
||||
currentProjectContext?.startMode === 'planning' && !switchedToGameRuntime;
|
||||
const agentRuntimeMode: 'design' | 'game' = planningStartMode
|
||||
? 'design'
|
||||
: 'game';
|
||||
const suppressInitialGameTurn = switchedToGameRuntime;
|
||||
const activeProjectContextRef = useRef(currentProjectContext);
|
||||
const manifestMergeRef = useRef<ProjectManifestMergeState | null>(null);
|
||||
activeProjectContextRef.current = currentProjectContext;
|
||||
@@ -418,6 +436,19 @@ export function WorkspaceLauncherShell({
|
||||
});
|
||||
}
|
||||
|
||||
async function switchToGameRuntime(nextProjectPath: string) {
|
||||
const invoke = resolveTauriInvoke();
|
||||
if (!invoke) throw new Error('需要在陶泥儿客户端内运行');
|
||||
await invoke('set_design_agent_runtime_mode', {
|
||||
projectPath: nextProjectPath,
|
||||
activeRuntime: 'game',
|
||||
});
|
||||
setGameRuntimeSwitch({
|
||||
projectPath: nextProjectPath,
|
||||
createdAt: currentProjectContext?.createdAt ?? 0,
|
||||
});
|
||||
}
|
||||
|
||||
const currentHelpTitle =
|
||||
launcherView === 'guide'
|
||||
? '使用指南'
|
||||
@@ -557,30 +588,43 @@ export function WorkspaceLauncherShell({
|
||||
preview={activeProjectPreview}
|
||||
agentRuntimeSummaries={activeProjectAgentRuntimeSummaries}
|
||||
agentResults={activeProjectAgentResults}
|
||||
planningStartMode={currentProjectContext.startMode === 'planning'}
|
||||
planningStartMode={planningStartMode}
|
||||
activeVersionId={activeVersionId}
|
||||
onActiveVersionChange={setActiveVersionId}
|
||||
onPlay={() =>
|
||||
requestCurrentProjectPlay(currentProjectContext.projectPath)
|
||||
}
|
||||
onMakeGame={() =>
|
||||
void switchToGameRuntime(currentProjectContext.projectPath)
|
||||
}
|
||||
onManifestChange={syncActiveProjectManifest}
|
||||
onHomeOpen={() => setLauncherView('home')}
|
||||
onProjectsOpen={() => setLauncherView('projects')}
|
||||
supervisor={
|
||||
<ProjectSupervisor
|
||||
key={currentProjectContext.projectPath}
|
||||
key={`${currentProjectContext.projectPath}:${agentRuntimeMode}`}
|
||||
initialProjectPath={currentProjectContext.projectPath}
|
||||
initialProjectManifest={currentProjectContext.manifest}
|
||||
initialProjectKind={currentProjectContext.projectKind}
|
||||
initialSupervisorMessage={currentProjectContext.initialPrompt}
|
||||
initialCreationType={currentProjectContext.creationType}
|
||||
initialAttachments={currentProjectContext.attachments}
|
||||
initialSupervisorMessage={
|
||||
!suppressInitialGameTurn
|
||||
? currentProjectContext.initialPrompt
|
||||
: ''
|
||||
}
|
||||
initialCreationType={
|
||||
!suppressInitialGameTurn
|
||||
? currentProjectContext.creationType
|
||||
: null
|
||||
}
|
||||
initialAttachments={
|
||||
!suppressInitialGameTurn
|
||||
? currentProjectContext.attachments
|
||||
: []
|
||||
}
|
||||
activeVersionId={activeVersionId}
|
||||
orchestrationMode="single-supervisor"
|
||||
projectSupervisorOnly
|
||||
planningStartMode={
|
||||
currentProjectContext.startMode === 'planning'
|
||||
}
|
||||
planningStartMode={planningStartMode}
|
||||
playRequest={playRequest}
|
||||
onPlayRequestHandled={handlePlayRequestHandled}
|
||||
onManifestChange={syncActiveProjectManifest}
|
||||
@@ -590,6 +634,7 @@ export function WorkspaceLauncherShell({
|
||||
}
|
||||
onAgentResultsChange={setActiveProjectAgentResults}
|
||||
onMakeGameFromApprovedGdd={startGameFromApprovedGdd}
|
||||
onSwitchToGameRuntime={switchToGameRuntime}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -61,6 +61,7 @@ export type ProjectSupervisorComponentProps = {
|
||||
) => void;
|
||||
onAgentResultsChange?: (results: ProjectAgentResultSummary[]) => void;
|
||||
onMakeGameFromApprovedGdd?: (projectPath: string) => Promise<void>;
|
||||
onSwitchToGameRuntime?: (projectPath: string) => Promise<void>;
|
||||
};
|
||||
|
||||
export type WorkspaceLauncherShellProps = WorkspaceLauncherProps & {
|
||||
|
||||
@@ -274,6 +274,12 @@ export function useHomeProjectCreation({
|
||||
attachments: HomeAttachmentDraft[],
|
||||
startMode: ProjectStartMode,
|
||||
) {
|
||||
if (startMode === 'planning') {
|
||||
await invoke('set_design_agent_runtime_mode', {
|
||||
projectPath: result.projectPath,
|
||||
activeRuntime: 'design',
|
||||
});
|
||||
}
|
||||
const importedAttachments = await importHomeAttachments(
|
||||
invoke,
|
||||
result.projectPath,
|
||||
@@ -499,6 +505,11 @@ export function useHomeProjectCreation({
|
||||
setStatus('这不是已初始化的 AI 游戏项目,请使用新建项目。');
|
||||
return;
|
||||
}
|
||||
const runtimeMode = await invoke<{
|
||||
activeRuntime: 'design' | 'game';
|
||||
} | null>('get_design_agent_runtime_mode', {
|
||||
projectPath: trimmedProjectPath,
|
||||
});
|
||||
setStatus('已打开项目');
|
||||
await enterProjectDevelopment({
|
||||
projectPath: trimmedProjectPath,
|
||||
@@ -516,7 +527,7 @@ export function useHomeProjectCreation({
|
||||
trimmedProjectPath,
|
||||
),
|
||||
creationType: null,
|
||||
startMode: null,
|
||||
startMode: runtimeMode?.activeRuntime === 'design' ? 'planning' : null,
|
||||
initialPrompt: '',
|
||||
attachments: [],
|
||||
recentRunStatus: directoryStatus.recentRunStatus,
|
||||
@@ -620,6 +631,7 @@ export function useHomeProjectCreation({
|
||||
'create_automatic_local_game_project',
|
||||
{
|
||||
name: suggestedName,
|
||||
planning: startMode === 'planning',
|
||||
},
|
||||
);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user