876529e668
- 删除 ProjectSupervisorView、SupervisorChatOnlyView、ProjectWorkspaceChatPane、AgentConversationOverlay、DeveloperProjectPanels、DeveloperRuntimePanels 与 features/agent-runtime/panels.tsx - 删除 Supervisor 独立调试窗口:windows.rs 的 supervisor_chat_window_url / open_project_supervisor_chat_window、main.rs 的 invoke 注册、?supervisor-chat 与 ?agent-chat 前端入口、developer.json capability 和对应 Rust 用例 - 删除工作台壳的开发者 Agent 面板:DeveloperAgentPanel、useDeveloperAgentPanel、useDeveloperAgentState、developerAgentControls - App.tsx 删除只服务退役面板的 state/ref/effect/handler(agentConversation*、文件/记忆/资产/画板/预览面板处理、commandLog、llmConfigStatus、editorBaseUrl、回放历史与 trace 面板状态、selectedAgent 等)以及由此产生的空分支,并把 requestRuntimeConfigOpen 接回本地 RuntimeConfigDialog - 立项策划独立成模块:Design Agent 与 Planning V2 的容器和表现移到 view/project-development/planning/(PlanningChatView、PlanningUserInputCard、GddApprovalCard、DesignAgentSurface、PlanningLaneRuntimeStrip、planningLane、planningSessionV2、planningSessionContract) - 改名到中性概念:ProjectSupervisorComponentProps→ProjectChatComponentProps、WorkspaceLauncherShellProps.ProjectSupervisor→ProjectChat、ProjectDevelopmentView.supervisor→chat、orchestrationMode→agentDockVisible、initialSupervisorMessageClaims→initialTurnClaims、ProjectManifestSnapshotSource 'supervisor'→'chat'、CSS project-supervisor-*/project-planning-*→project-chat-* - 删除 PROJECT_SUPERVISOR_AGENT_ID 与 PROJECT_SUPERVISOR_PLAN_SOURCE 常量 - 工作台壳自己订阅 game-creator-manifest-invalidated,用 revision→清单→revision 配对读(source: asset-event)并入 currentProjectContext,且不重新检查项目目录;测试夹具改为按监听器集合广播该事件 - 删除只钉住退役界面的 appSurface 用例(旧调试窗口、开发者面板、Agent 对话浮层、运行历史面板) - 同步文档:ADR、DirectProject 聊天模块抽离实施计划与里程碑、Provider 推理里程碑、策划会话 RuntimeV2、AI 游戏创作实施计划,并在 decision-log 新增 2026-09-19 条 - 删除随退役面板失去调用方的模块与导出:projectSummaryCommands.ts(1054 行旧 Supervisor 斜杠命令处理器)、AGENT_RUN_HISTORY_* 常量、agent-runtime/model.ts 与 project-summary/agentPresentation.ts 里的死导出,以及 agentRunTrace / memoryCommands / projectCommandPolicy 中无调用方的校验与解析函数 - 更新 scripts/check-config.mjs 与 scripts/check-native-shells.mjs 的窗口与命令守卫
112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
/** @vitest-environment jsdom */
|
|
import type { ReactNode } from 'react';
|
|
import { useCallback } from 'react';
|
|
import { vi } from 'vitest';
|
|
|
|
import { WindowChrome } from '../src/components/WindowChrome';
|
|
import {
|
|
useWindowChrome,
|
|
type WindowChromeActiveProjectRuns,
|
|
WindowChromeContext,
|
|
} from '../src/components/windowChromeContext';
|
|
import { WorkspaceLauncherShell } from '../src/features/app-shell/WorkspaceLauncher';
|
|
import {
|
|
act,
|
|
expect,
|
|
it,
|
|
React,
|
|
render,
|
|
testAuthUser,
|
|
} from './appSurface/harness';
|
|
|
|
const homeProjectOverride = vi.hoisted(() => ({
|
|
openProject: null as
|
|
| null
|
|
| ((path: string, mode: 'open' | 'create') => Promise<void>),
|
|
}));
|
|
|
|
vi.mock('../src/features/app-shell/useHomeProjectCreation', async () => {
|
|
const actual = await vi.importActual<
|
|
typeof import('../src/features/app-shell/useHomeProjectCreation')
|
|
>('../src/features/app-shell/useHomeProjectCreation');
|
|
return {
|
|
...actual,
|
|
useHomeProjectCreation(
|
|
...args: Parameters<typeof actual.useHomeProjectCreation>
|
|
) {
|
|
const result = actual.useHomeProjectCreation(...args);
|
|
return homeProjectOverride.openProject
|
|
? { ...result, openProject: homeProjectOverride.openProject }
|
|
: result;
|
|
},
|
|
};
|
|
});
|
|
|
|
it('真实窗口与工作台状态同步收敛,回调读取最新处理器且卸载才清理', async () => {
|
|
const publications: WindowChromeActiveProjectRuns[] = [];
|
|
let cleanups = 0;
|
|
// 仍经过真实 WindowChrome 的 setState/Context;上限只防止回归时测试无限循环。
|
|
function BoundedWindowBridge({ children }: { children: ReactNode }) {
|
|
const chrome = useWindowChrome();
|
|
const { setActiveProjectRuns } = chrome;
|
|
const publish = useCallback(
|
|
(next: WindowChromeActiveProjectRuns | null) => {
|
|
if (next) publications.push(next);
|
|
else cleanups += 1;
|
|
if (publications.length < 12) setActiveProjectRuns(next);
|
|
},
|
|
[setActiveProjectRuns],
|
|
);
|
|
return (
|
|
<WindowChromeContext.Provider
|
|
value={{ ...chrome, setActiveProjectRuns: publish }}
|
|
>
|
|
{children}
|
|
</WindowChromeContext.Provider>
|
|
);
|
|
}
|
|
const chat = () => null;
|
|
const view = (displayName = '测试用户') => (
|
|
<WindowChrome>
|
|
<BoundedWindowBridge>
|
|
<WorkspaceLauncherShell
|
|
currentUser={{ ...testAuthUser, displayName }}
|
|
onLogout={() => undefined}
|
|
initialView="projects"
|
|
ProjectChat={chat}
|
|
/>
|
|
</BoundedWindowBridge>
|
|
</WindowChrome>
|
|
);
|
|
delete window.__TAURI__;
|
|
const rendered = render(view());
|
|
try {
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
// 无原生 invoke 时空快照引用不变,只发布一次。
|
|
expect(publications).toHaveLength(1);
|
|
expect(cleanups).toBe(0);
|
|
expect(new Set(publications.map((item) => item.onOpenProject)).size).toBe(
|
|
1,
|
|
);
|
|
const openProject = publications[0]!.onOpenProject!;
|
|
const latestOpen = vi.fn(async () => undefined);
|
|
homeProjectOverride.openProject = latestOpen;
|
|
rendered.rerender(view('更改显示名'));
|
|
expect(publications).toHaveLength(1);
|
|
act(() => openProject('/tmp/window-latest-project'));
|
|
expect(latestOpen).toHaveBeenCalledWith(
|
|
'/tmp/window-latest-project',
|
|
'open',
|
|
);
|
|
expect(publications).toHaveLength(1);
|
|
expect(cleanups).toBe(0);
|
|
rendered.unmount();
|
|
expect(cleanups).toBe(1);
|
|
} finally {
|
|
homeProjectOverride.openProject = null;
|
|
rendered.unmount();
|
|
}
|
|
});
|