mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 21:23:04 +00:00
fix(terminal): preserve visible replay history defaults
This commit is contained in:
@@ -13,15 +13,24 @@ import {
|
||||
|
||||
describe("terminal restore policy", () => {
|
||||
test("resolves bounded restore snapshot options", () => {
|
||||
expect(resolveTerminalRestoreSnapshotOptions({ mode: "live" })).toBeNull();
|
||||
expect(resolveTerminalRestoreSnapshotOptions({ mode: "full-snapshot" })).toBeUndefined();
|
||||
expect(resolveTerminalRestoreSnapshotOptions({ mode: "visible-snapshot" })).toEqual({
|
||||
expect(
|
||||
resolveTerminalRestoreSnapshotOptions({ restore: { mode: "live" }, chunked: false }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
resolveTerminalRestoreSnapshotOptions({ restore: { mode: "full-snapshot" }, chunked: false }),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
resolveTerminalRestoreSnapshotOptions({
|
||||
restore: { mode: "visible-snapshot" },
|
||||
chunked: false,
|
||||
}),
|
||||
).toEqual({
|
||||
scrollbackLines: 200,
|
||||
});
|
||||
expect(
|
||||
resolveTerminalRestoreSnapshotOptions({
|
||||
mode: "visible-snapshot",
|
||||
scrollbackLines: 999,
|
||||
restore: { mode: "visible-snapshot", scrollbackLines: 999 },
|
||||
chunked: false,
|
||||
}),
|
||||
).toEqual({ scrollbackLines: 500 });
|
||||
});
|
||||
|
||||
@@ -33,18 +33,25 @@ export function resolveRestoreAfterOutputOverflow(
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveTerminalRestoreSnapshotOptions(
|
||||
restore: TerminalRestoreOptions,
|
||||
): TerminalReplayOptions | null | undefined {
|
||||
export function resolveTerminalRestoreSnapshotOptions({
|
||||
restore,
|
||||
chunked,
|
||||
}: {
|
||||
restore: TerminalRestoreOptions;
|
||||
chunked: boolean;
|
||||
}): TerminalReplayOptions | null | undefined {
|
||||
if (restore.mode === "live") {
|
||||
return null;
|
||||
}
|
||||
if (restore.mode === "visible-snapshot") {
|
||||
return {
|
||||
scrollbackLines: resolveVisibleRestoreScrollbackLines(restore.scrollbackLines),
|
||||
};
|
||||
if (restore.mode === "full-snapshot") {
|
||||
return chunked ? { scrollbackLines: restore.scrollbackLines } : undefined;
|
||||
}
|
||||
return undefined;
|
||||
const scrollbackLines = restore.scrollbackLines ?? DEFAULT_VISIBLE_RESTORE_SCROLLBACK_LINES;
|
||||
return {
|
||||
scrollbackLines: chunked
|
||||
? scrollbackLines
|
||||
: Math.min(scrollbackLines, MAX_VISIBLE_RESTORE_SCROLLBACK_LINES),
|
||||
};
|
||||
}
|
||||
|
||||
export function encodeTerminalRestoreFrame(input: { slot: number; data: Uint8Array }): Uint8Array {
|
||||
@@ -55,13 +62,6 @@ export function encodeTerminalRestoreFrame(input: { slot: number; data: Uint8Arr
|
||||
});
|
||||
}
|
||||
|
||||
function resolveVisibleRestoreScrollbackLines(value: number | undefined): number {
|
||||
if (typeof value !== "number") {
|
||||
return DEFAULT_VISIBLE_RESTORE_SCROLLBACK_LINES;
|
||||
}
|
||||
return Math.min(Math.max(0, value), MAX_VISIBLE_RESTORE_SCROLLBACK_LINES);
|
||||
}
|
||||
|
||||
/** The daemon's only old-app adapter. Capable delivery never assembles the replay. */
|
||||
export function createTerminalRestoreDelivery(input: {
|
||||
slot: number;
|
||||
|
||||
@@ -782,10 +782,49 @@ describe("terminal-session-controller backpressure snapshot fallback", () => {
|
||||
};
|
||||
}
|
||||
|
||||
test.each([false, true])(
|
||||
"preserves visible history defaults and explicit requests across delivery (chunked=%s)",
|
||||
async (chunked) => {
|
||||
const replayOpcodes = chunked
|
||||
? [
|
||||
TerminalStreamOpcode.ReplayBegin,
|
||||
TerminalStreamOpcode.ReplayData,
|
||||
TerminalStreamOpcode.ReplayEnd,
|
||||
]
|
||||
: [TerminalStreamOpcode.Restore];
|
||||
for (const [restore, expected] of [
|
||||
[{ mode: "visible-snapshot" }, [{ scrollbackLines: 200 }]],
|
||||
[{ mode: "visible-snapshot", scrollbackLines: 0 }, [{ scrollbackLines: 0 }]],
|
||||
[{ mode: "visible-snapshot", scrollbackLines: 5 }, [{ scrollbackLines: 5 }]],
|
||||
[{ mode: "visible-snapshot", scrollbackLines: 500 }, [{ scrollbackLines: 500 }]],
|
||||
[
|
||||
{ mode: "visible-snapshot", scrollbackLines: 10000 },
|
||||
[{ scrollbackLines: chunked ? 10000 : 500 }],
|
||||
],
|
||||
[{ mode: "full-snapshot" }, [chunked ? { scrollbackLines: undefined } : undefined]],
|
||||
[{ mode: "live" }, []],
|
||||
] as const) {
|
||||
const fixture = await setup(() => 0, chunked, undefined, restore);
|
||||
expect(fixture.replayOptions).toEqual(expected);
|
||||
fixture.ready();
|
||||
await waitForCoalescerFlush();
|
||||
expect(fixture.replayOptions).toEqual([...expected, ...expected]);
|
||||
expect(fixture.frames.map((frame) => frame.opcode)).toEqual(
|
||||
restore.mode === "live" ? [] : replayOpcodes,
|
||||
);
|
||||
fixture.pushOutput("after-restore");
|
||||
await waitForCoalescerFlush();
|
||||
expect(fixture.frames.at(-1)?.opcode).toBe(TerminalStreamOpcode.Output);
|
||||
expect(new TextDecoder().decode(fixture.frames.at(-1)!.payload)).toBe("after-restore");
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test.each([false, true])(
|
||||
"bounds recovery without changing attach demand (chunked=%s)",
|
||||
async (chunked) => {
|
||||
for (const [restore, history] of [
|
||||
[{ mode: "visible-snapshot" }, 500],
|
||||
[{ mode: "visible-snapshot", scrollbackLines: 10000 }, 500],
|
||||
[{ mode: "full-snapshot" }, 500],
|
||||
[{ mode: "visible-snapshot", scrollbackLines: 5 }, 5],
|
||||
|
||||
@@ -1085,10 +1085,7 @@ export class TerminalSessionController {
|
||||
restore: TerminalRestoreOptions,
|
||||
): Promise<SnapshotSendResult> {
|
||||
const chunked = this.options.supportsChunkedReplay?.(activeStream.owner.source) === true;
|
||||
const snapshotOptions =
|
||||
chunked && restore.mode !== "live"
|
||||
? { scrollbackLines: restore.scrollbackLines }
|
||||
: resolveTerminalRestoreSnapshotOptions(restore);
|
||||
const snapshotOptions = resolveTerminalRestoreSnapshotOptions({ restore, chunked });
|
||||
if (snapshotOptions === null) {
|
||||
return { shouldContinue: true, replay: null };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user