Files
openclaw/extensions/acpx/src/runtime.test.ts
T
Bob f6124f3e17 ACP: harden Discord recovery and reset flow (#62132)
* ACP: harden Discord recovery and reset flow

* CI: harden bundled vitest excludes

* ACP: fix Claude launch and reset recovery

* Discord: use follow-up replies after slash defer

* ACP: route bound resets through gateway service

* ACP: unify bound reset authority

* ACPX: update OpenClaw branch to 0.5.2

* ACP: fix rebuilt branch replay fallout

* ACP: fix CI regressions after ACPX 0.5.2 update

---------

Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
2026-04-07 12:23:50 +02:00

102 lines
3.2 KiB
TypeScript

import type { AcpSessionStore } from "acpx/runtime";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { AcpRuntime } from "../runtime-api.js";
import { AcpxRuntime } from "./runtime.js";
function makeRuntime(baseStore: AcpSessionStore): {
runtime: AcpxRuntime;
wrappedStore: AcpSessionStore & { markFresh: (sessionKey: string) => void };
delegate: { close: AcpRuntime["close"] };
} {
const runtime = new AcpxRuntime({
cwd: "/tmp",
sessionStore: baseStore,
agentRegistry: {
resolve: () => "codex",
list: () => ["codex"],
},
permissionMode: "approve-reads",
});
return {
runtime,
wrappedStore: (
runtime as unknown as {
sessionStore: AcpSessionStore & { markFresh: (sessionKey: string) => void };
}
).sessionStore,
delegate: (runtime as unknown as { delegate: { close: AcpRuntime["close"] } }).delegate,
};
}
describe("AcpxRuntime fresh reset wrapper", () => {
beforeEach(() => {
vi.restoreAllMocks();
});
it("keeps stale persistent loads hidden until a fresh record is saved", async () => {
const baseStore: AcpSessionStore = {
load: vi.fn(async () => ({ acpxRecordId: "stale" }) as never),
save: vi.fn(async () => {}),
};
const { runtime, wrappedStore } = makeRuntime(baseStore);
expect(await wrappedStore.load("agent:codex:acp:binding:test")).toEqual({
acpxRecordId: "stale",
});
expect(baseStore.load).toHaveBeenCalledTimes(1);
await runtime.prepareFreshSession({
sessionKey: "agent:codex:acp:binding:test",
});
expect(await wrappedStore.load("agent:codex:acp:binding:test")).toBeUndefined();
expect(baseStore.load).toHaveBeenCalledTimes(1);
expect(await wrappedStore.load("agent:codex:acp:binding:test")).toBeUndefined();
expect(baseStore.load).toHaveBeenCalledTimes(1);
await wrappedStore.save({
acpxRecordId: "fresh-record",
name: "agent:codex:acp:binding:test",
} as never);
expect(await wrappedStore.load("agent:codex:acp:binding:test")).toEqual({
acpxRecordId: "stale",
});
expect(baseStore.load).toHaveBeenCalledTimes(2);
});
it("marks the session fresh after discardPersistentState close", async () => {
const baseStore: AcpSessionStore = {
load: vi.fn(async () => ({ acpxRecordId: "stale" }) as never),
save: vi.fn(async () => {}),
};
const { runtime, wrappedStore, delegate } = makeRuntime(baseStore);
const close = vi.spyOn(delegate, "close").mockResolvedValue(undefined);
await runtime.close({
handle: {
sessionKey: "agent:codex:acp:binding:test",
backend: "acpx",
runtimeSessionName: "agent:codex:acp:binding:test",
},
reason: "new-in-place-reset",
discardPersistentState: true,
});
expect(close).toHaveBeenCalledWith({
handle: {
sessionKey: "agent:codex:acp:binding:test",
backend: "acpx",
runtimeSessionName: "agent:codex:acp:binding:test",
},
reason: "new-in-place-reset",
discardPersistentState: true,
});
expect(await wrappedStore.load("agent:codex:acp:binding:test")).toBeUndefined();
expect(baseStore.load).not.toHaveBeenCalled();
});
});