feat(FN-3078): merge fusion/fn-3078

This merge lands four features: a `/clear` command for Chat and Quick Chat with session banner fixes (FN-3062), a todo view redesign with restructured rows and improved styling (FN-3063), deterministic peer exchange shutdown with dashboard improvements (FN-3040), and a summary Q&A disclosure feature

Fusion-Task-Id: FN-3078
This commit is contained in:
Fusion
2026-05-01 13:37:03 -07:00
committed by gsxdsm
parent 8b7f20f207
commit 0188da703b
9 changed files with 156 additions and 14 deletions

View File

@@ -963,6 +963,134 @@ describe("PlanningModeModal", () => {
});
describe("Conversation history", () => {
it("hides completed-session Q&A by default behind a summary disclosure", async () => {
const resumedSummary: PlanningSummary = {
title: "Summary with hidden history",
description: "Recovered summary description",
suggestedSize: "M",
suggestedDependencies: [],
keyDeliverables: ["Deliverable A"],
};
const restoredHistory = [
{
question: {
id: "q1",
type: "single_select",
question: "What scope do you need?",
options: [
{ id: "small", label: "Small" },
{ id: "medium", label: "Medium" },
],
},
response: { q1: "medium" },
thinkingOutput: "Reasoning for scope question",
},
];
mockFetchAiSession.mockResolvedValueOnce({
id: "session-complete-with-history",
type: "planning",
status: "complete",
title: resumedSummary.title,
inputPayload: JSON.stringify({ initialPlan: "Build planning history restore" }),
conversationHistory: JSON.stringify(restoredHistory),
currentQuestion: null,
result: JSON.stringify(resumedSummary),
thinkingOutput: "",
error: null,
projectId: null,
createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z",
});
render(
<PlanningModeModal
isOpen={true}
onClose={mockOnClose}
onTaskCreated={mockOnTaskCreated}
onTasksCreated={vi.fn()}
tasks={mockTasks}
resumeSessionId="session-complete-with-history"
/>,
);
await waitFor(() => {
expect(screen.getByText("Planning Complete!")).toBeDefined();
});
expect(screen.getByRole("button", { name: "Show user Q&A" })).toBeDefined();
expect(screen.queryByTestId("conversation-history")).toBeNull();
expect(screen.queryByText("What scope do you need?")).toBeNull();
expect(screen.queryByText("Medium")).toBeNull();
});
it("reveals completed-session Q&A when summary disclosure is expanded", async () => {
const resumedSummary: PlanningSummary = {
title: "Summary with expandable history",
description: "Recovered summary description",
suggestedSize: "M",
suggestedDependencies: [],
keyDeliverables: ["Deliverable A"],
};
const restoredHistory = [
{
question: {
id: "q1",
type: "single_select",
question: "What scope do you need?",
options: [
{ id: "small", label: "Small" },
{ id: "medium", label: "Medium" },
],
},
response: { q1: "medium" },
thinkingOutput: "Reasoning for scope question",
},
];
mockFetchAiSession.mockResolvedValueOnce({
id: "session-complete-with-history-2",
type: "planning",
status: "complete",
title: resumedSummary.title,
inputPayload: JSON.stringify({ initialPlan: "Build planning history restore" }),
conversationHistory: JSON.stringify(restoredHistory),
currentQuestion: null,
result: JSON.stringify(resumedSummary),
thinkingOutput: "",
error: null,
projectId: null,
createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z",
});
render(
<PlanningModeModal
isOpen={true}
onClose={mockOnClose}
onTaskCreated={mockOnTaskCreated}
onTasksCreated={vi.fn()}
tasks={mockTasks}
resumeSessionId="session-complete-with-history-2"
/>,
);
await waitFor(() => {
expect(screen.getByText("Planning Complete!")).toBeDefined();
});
fireEvent.click(screen.getByRole("button", { name: "Show user Q&A" }));
await waitFor(() => {
expect(screen.getByTestId("conversation-history")).toBeDefined();
});
expect(screen.getByText("What scope do you need?")).toBeDefined();
expect(within(screen.getByTestId("conversation-history")).getByText("Medium")).toBeDefined();
});
it("restores all persisted Q&A pairs when resuming a session", async () => {
mockConnectPlanningStream.mockImplementationOnce(() => ({
close: vi.fn(),