Files
pi-goals/test/intercom.test.ts
T
wassname 47cc054582 Send incremental worker views with direction and tracked job state
Borrow the provider tracker queries from cecb1e9. Keep unavailable state unknown, bind incremental views to acknowledged source entries, reset after compaction, bound serialized payloads, and recheck tracked work at sign-off.
2026-09-08 16:41:47 +08:00

76 lines
3.6 KiB
TypeScript

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { describe, expect, it, vi } from "vitest";
import { GoalIntercom } from "../src/intercom.js";
import { intercomFixture } from "./intercom-fixture.js";
function setup(role: "worker" | "supervisor", entries: any[] = []) {
const fixture = intercomFixture();
const hooks = new Map<string, any>();
const ctx = { sessionManager: { getEntries: () => entries }, ui: { notify: vi.fn() } };
const api = { events: fixture.events, on: (name: string, hook: any) => hooks.set(name, hook), appendEntry: (customType: string, data: unknown) => entries.push({ type: "custom", customType, data }) };
const link = new GoalIntercom(api as unknown as ExtensionAPI);
link.configure("binding", role, ctx as any);
return { link, fixture, entries, ctx, hooks };
}
describe("pi-intercom transport", () => {
it("receives exact advice once, acknowledges it and rejects unrelated peers", async () => {
const runtime = setup("worker");
await runtime.link.waitReady();
const instruction = "Check the Modal dependency.\nKeep the local queue paused.";
const delivered = vi.fn();
runtime.link.onSteer = delivered;
const message = { binding: "binding", role: "supervisor", kind: "steer", id: "instruction", text: instruction };
runtime.fixture.receive({ ...message, binding: "other" });
runtime.fixture.receive(message, "wrong-peer");
expect(delivered).not.toHaveBeenCalled();
runtime.fixture.receive(message);
runtime.fixture.receive(message);
expect(delivered).toHaveBeenCalledExactlyOnceWith(instruction);
expect(runtime.fixture.sent.filter(message => message.kind === "received")).toHaveLength(2);
await runtime.hooks.get("session_shutdown")();
runtime.fixture.receive({ ...message, id: "late" });
expect(delivered).toHaveBeenCalledTimes(1);
});
it("restores an unacknowledged steer on reconnect and stops replay after acknowledgment", async () => {
const first = setup("supervisor");
first.link.markReady();
await first.link.waitReady();
const id = first.link.steer("Read the full output.");
await first.hooks.get("session_shutdown")();
const resumed = setup("supervisor", [...first.entries]);
resumed.link.markReady();
await resumed.link.waitReady();
expect(resumed.fixture.sent.filter(message => message.kind === "steer")).toMatchObject([{ id, text: "Read the full output." }]);
resumed.fixture.receive({ binding: "binding", role: "worker", kind: "received", id });
resumed.fixture.connect(false);
expect(resumed.link.connected).toBe(false);
expect(() => resumed.link.steer("Must not send.")).toThrow("disconnected");
resumed.fixture.connect(true);
await resumed.link.waitReady();
expect(resumed.fixture.sent.filter(message => message.kind === "steer")).toHaveLength(1);
});
it("advances the incremental overview only after acknowledgment", async () => {
const runtime = setup("worker");
await runtime.link.waitReady();
const view = runtime.link.view("The worker stopped.", "settled", "entry-1", true);
expect(runtime.link.acknowledgedEntry).toBeUndefined();
runtime.fixture.receive({ binding: "binding", role: "supervisor", kind: "received", id: view.id });
expect(runtime.link.acknowledgedEntry).toBe("entry-1");
const resumed = setup("worker", [...runtime.entries]);
expect(resumed.link.acknowledgedEntry).toBe("entry-1");
});
it("cancels a readiness wait on shutdown", async () => {
const runtime = setup("worker");
await runtime.link.waitReady();
runtime.fixture.connect(false);
const wait = runtime.link.waitReady();
const rejection = expect(wait).rejects.toThrow("Session ended");
await runtime.hooks.get("session_shutdown")();
await rejection;
});
});