6981648796
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m56s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 3m48s
Project CI / Native shell tests (pull_request) Failing after 45s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / Frontend tests (pull_request) Failing after 1m52s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m42s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 6m57s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 8m1s
- 解决 refactor/split-direct-project 与 origin/master 在 App.tsx、立项策划聊天视图、Direct composer/引用输入区、styles.css、Rust direct user item 与 appSurface 用例上的冲突,按「Supervisor 永久退役」口径保留 DirectProject 独立聊天容器与 Design Agent 两条产品路径 - 采纳 master 的策划 Agent V1/V2 退役:删除 GDD 审批卡、策划输入卡、planningLane、planningSessionV2、planningSessionContract、规划展示适配与 Rust planning_*_v2 命令、模块、契约及对应用例,不保留兼容别名或双跑路径 - 把 master「折叠思考显示单行预览」的目的落到当前结构:新增共享表现 chat/components/AgentReasoning/AgentReasoning.tsx(折叠态单行纯文本预览 + 箭头、展开态安全 Markdown),DirectProject 回合与策划回合共用,删掉两处写死的 pre 折叠实现 - 把 master「策划入口可选模型 / 推理档」的目的接到当前策划输入盒:复用 ConversationModelSelect 与 ComposerReasoningEffortSelect,配置写回仍走客户端配置通道 - App.tsx 删除只服务退役 Supervisor / 策划 V2 的 state、ref、effect、回调与死参数,并删除两条读路径都退役后的 workspaceProjectKind;openWorkspace 的工程类型入参保留为未使用契约 - Rust 侧保留本分支 canonical→wire 投影、无审计 Direct 回合与 direct user item 严格校验,并入 master 的 prepare_new_web_project_at 前置复核 - 更新 ADR 与 shared-memory 决策记录:策划当前只有 Design Agent、两条路径的共享表现清单,以及本次合并的口径、代价与验证证据 - 验证:AGC 与仓库 typecheck、check:encoding、check:doc-index、git diff --check、改动文件 eslint 0 error;AGC vitest 168 个文件中除 5 个 jsdom localStorage 环境失败文件与本分支既有 resourceTagStatsRefresh 失败外全绿,appSurface 198 passed / 13 skipped;Rust 定向用例 direct_codex_user_item、skill_pack、sessions 全过(整套分片在本容器受 /sbin -> usr/bin 触发沙箱预检失败,与本合并无关)
114 lines
3.6 KiB
TypeScript
114 lines
3.6 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',
|
|
);
|
|
// 回调执行只换 ref 里的实现,发布次数与清理次数都不能变。
|
|
expect(publications).toHaveLength(1);
|
|
expect(cleanups).toBe(0);
|
|
rendered.unmount();
|
|
expect(cleanups).toBe(1);
|
|
} finally {
|
|
homeProjectOverride.openProject = null;
|
|
rendered.unmount();
|
|
}
|
|
});
|