Files
paseo/packages/app/e2e/rewind-flow.shared.ts
Mohamed Boudra 132e572d6e Rewind chat or files from any user message (#1154)
* Add Pi extension-launch plumbing for in-process tree primitives

* Add Rewind controls for agent sessions

* Preserve SDK checkpoint env var so Claude file rewind works

The SDK injects CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING=true when file checkpointing is enabled. The earlier parent-env stripping from c4782ec71c was too broad and removed that child flag along with real parent-session markers.

Keep stripping parent markers, but preserve the checkpoint flag so the SDK rewind path can run directly. With that boundary fixed, the JSONL file-rewind fallback is no longer needed.

* Update OpenCode history replay tests for rewind state

* Show Rewind actions in an adaptive sheet

* Fix rewind semantics across providers

* Refactor Pi IDs through extension capture

* Restore user message to composer after rewind

* Fix Claude rewind tool result mapping

* Fix Claude rewind session switch roundtrip

* Fix rewind and optimistic message regressions

* Tighten rewind test discipline

* Fix OpenCode optimistic message reconciliation

* Reconcile optimistic user messages by marker

* Reorder user message actions

* Unify provider user message contract

* Add Claude rewind flow Playwright contract

* Add Codex rewind flow Playwright contract

* Add OpenCode rewind flow Playwright contract

* Add Pi rewind flow Playwright contract

* Remove real-provider rewind Playwright contracts

* Gate real-provider rewind specs from CI Playwright
2026-05-25 17:11:34 +08:00

89 lines
2.7 KiB
TypeScript

import { mkdtempSync, realpathSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { test } from "./fixtures";
import {
assertChatTranscript,
assertComposerIdle,
assertFileContains,
assertFileExists,
assertFileMissing,
cleanupRewindFlow,
launchAgent,
rewindMessage,
sendMessage,
type AgentHandle,
type RewindFlowMode,
type RewindFlowProvider,
} from "./helpers/rewind-flow";
const FILE_PROMPT = "Use the Write tool to create ./qa.txt with the exact content: PASEO_QA_TOKEN";
interface RewindFlowCase {
provider: RewindFlowProvider;
initialRewindMode?: RewindFlowMode;
rewindMode: RewindFlowMode;
fileReverted: boolean;
}
export function defineRewindFlowSpec(input: RewindFlowCase): void {
test.describe(`rewind flow - ${input.provider}`, () => {
test.setTimeout(600_000);
test("rewinds conversation and file-write turns without transcript drift", async ({ page }) => {
const cwd = realpathSync(
mkdtempSync(path.join(tmpdir(), `paseo-rewind-flow-${input.provider}-`)),
);
let handle: AgentHandle | undefined;
try {
handle = await launchAgent({
page,
provider: input.provider,
cwd,
mode: "full-access",
});
await sendMessage(handle, "hello");
await assertChatTranscript(handle, [
{ role: "user", text: "hello" },
{ role: "assistant", text: /.+/ },
]);
await rewindMessage(handle, 0, input.initialRewindMode ?? "conversation");
await assertChatTranscript(handle, []);
await assertComposerIdle(handle);
await sendMessage(handle, "hello");
await assertChatTranscript(handle, [
{ role: "user", text: "hello" },
{ role: "assistant", text: /.+/ },
]);
await sendMessage(handle, FILE_PROMPT);
await assertFileContains(path.join(cwd, "qa.txt"), "PASEO_QA_TOKEN");
await assertChatTranscript(handle, [
{ role: "user", text: "hello" },
{ role: "assistant", text: /.+/ },
{ role: "user", text: /Use the Write tool/ },
{ role: "assistant", text: /.+/ },
]);
await rewindMessage(handle, 1, input.rewindMode);
if (input.fileReverted) {
await assertFileMissing(path.join(cwd, "qa.txt"));
} else {
await assertFileExists(path.join(cwd, "qa.txt"));
}
await assertChatTranscript(handle, [
{ role: "user", text: "hello" },
{ role: "assistant", text: /.+/ },
]);
await assertComposerIdle(handle);
} finally {
await cleanupRewindFlow({ handle, cwd });
}
});
});
}