1ff1a9965b
- controller 删 `pendingUserItemId` / `beginTurnCommand` / `endTurnCommand`:忙态改由 `beginTurnBusy` / `endTurnBusy` 持有,宿主认领判据 = `turnRunning` 或收口计数变过(一轮在同一次 consume 里开始并结束) - controller 删 `startTurn` 的乐观追加与 `messageAppended` 重跑参数、`DirectProjectTurnInput.messageText` 与首轮的 `directInitialTurnText`;controller 不再需要 `assets` - 投影删 `awaiting-start` 展示态(只剩 `running` / `finished`)、`localSentTimes` / `sameIdentitySentAt`、本地用户气泡与它开回合的路径;带身份的拒单提示在会话末尾自成一组,不挂进上一轮,也不开运行态标记 - 时间口径:起点只认 `turn.started.at`、终点只认 `turn.completed.at`,用户气泡时钟取宿主落盘 / 观测时间;两边都空的回合整条「本轮结束于 … 」隐藏,不再出现 0.0 秒 - 用例:改造 `directTurnPresentation`(本地用户消息不进回合、拒单提示自成一组、两态判据、失败说明按身份归位)、`directProjectTurn` / `directProjectTurnStatus` / appSurface 窗口期用例,`directProjectTurn` 补 `afterEach(cleanup)` - 注释与文档:ADR「命令接单化」后续更新、实施计划新增「删掉本地乐观用户气泡」、decision-log 与 pitfalls 同日条目、Codex 原始历史方案的口径句、`codex_app_server` 用户条目时间注释
79 lines
2.2 KiB
TypeScript
79 lines
2.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { deriveDirectProjectTurnStatus } from '../src/view/project-development/chat/controller/useDirectProjectTurnStatus';
|
|
import type { DirectChatTurn } from '../src/view/project-development/chat/conversation/directTurnPresentation';
|
|
|
|
const turn = (key: string, state: DirectChatTurn['state']): DirectChatTurn => ({
|
|
key,
|
|
users: [],
|
|
process: [],
|
|
finals: [],
|
|
state,
|
|
startedAt: 1_800_000_000_000,
|
|
endedAt: 0,
|
|
});
|
|
|
|
describe('DirectProject 回合状态派生', () => {
|
|
it('displayBusy 是原生真相与本地命令在飞的并集', () => {
|
|
expect(
|
|
deriveDirectProjectTurnStatus({
|
|
turnRunning: true,
|
|
turnBusy: false,
|
|
turns: [],
|
|
}).displayBusy,
|
|
).toBe(true);
|
|
expect(
|
|
deriveDirectProjectTurnStatus({
|
|
turnRunning: false,
|
|
turnBusy: true,
|
|
turns: [],
|
|
}).displayBusy,
|
|
).toBe(true);
|
|
expect(
|
|
deriveDirectProjectTurnStatus({
|
|
turnRunning: false,
|
|
turnBusy: false,
|
|
turns: [],
|
|
}).displayBusy,
|
|
).toBe(false);
|
|
});
|
|
|
|
it('两个来源各自独立暴露,不被并集吃掉', () => {
|
|
const status = deriveDirectProjectTurnStatus({
|
|
turnRunning: true,
|
|
turnBusy: true,
|
|
turns: [],
|
|
});
|
|
expect(status.nativeRunning).toBe(true);
|
|
expect(status.commandInFlight).toBe(true);
|
|
});
|
|
|
|
it('latestTurnState 取最新一轮的两态;没有回合时为 null', () => {
|
|
expect(
|
|
deriveDirectProjectTurnStatus({
|
|
turnRunning: false,
|
|
turnBusy: false,
|
|
turns: [turn('u1', 'finished'), turn('u2', 'running')],
|
|
}).latestTurnState,
|
|
).toBe('running');
|
|
expect(
|
|
deriveDirectProjectTurnStatus({
|
|
turnRunning: false,
|
|
turnBusy: false,
|
|
turns: [],
|
|
}).latestTurnState,
|
|
).toBeNull();
|
|
});
|
|
|
|
it('本地命令在飞不等于原生在跑', () => {
|
|
const status = deriveDirectProjectTurnStatus({
|
|
turnRunning: false,
|
|
turnBusy: true,
|
|
turns: [turn('u1', 'finished')],
|
|
});
|
|
expect(status.nativeRunning).toBe(false);
|
|
expect(status.commandInFlight).toBe(true);
|
|
expect(status.latestTurnState).toBe('finished');
|
|
});
|
|
});
|