refactor(agents): dedupe plugin hooks and test helpers

This commit is contained in:
Peter Steinberger
2026-02-22 07:38:24 +00:00
parent 75c1bfbae8
commit 185fba1d22
16 changed files with 661 additions and 579 deletions

View File

@@ -26,6 +26,21 @@ function createRunEntry(): SubagentRunRecord {
}
describe("emitSubagentEndedHookOnce", () => {
const createEmitParams = (
overrides?: Partial<Parameters<typeof emitSubagentEndedHookOnce>[0]>,
) => {
const entry = overrides?.entry ?? createRunEntry();
return {
entry,
reason: SUBAGENT_ENDED_REASON_COMPLETE,
sendFarewell: true,
accountId: "acct-1",
inFlightRunIds: new Set<string>(),
persist: vi.fn(),
...overrides,
};
};
beforeEach(() => {
lifecycleMocks.getGlobalHookRunner.mockReset();
lifecycleMocks.runSubagentEnded.mockClear();
@@ -37,21 +52,13 @@ describe("emitSubagentEndedHookOnce", () => {
runSubagentEnded: lifecycleMocks.runSubagentEnded,
});
const entry = createRunEntry();
const persist = vi.fn();
const emitted = await emitSubagentEndedHookOnce({
entry,
reason: SUBAGENT_ENDED_REASON_COMPLETE,
sendFarewell: true,
accountId: "acct-1",
inFlightRunIds: new Set<string>(),
persist,
});
const params = createEmitParams();
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(true);
expect(lifecycleMocks.runSubagentEnded).not.toHaveBeenCalled();
expect(typeof entry.endedHookEmittedAt).toBe("number");
expect(persist).toHaveBeenCalledTimes(1);
expect(typeof params.entry.endedHookEmittedAt).toBe("number");
expect(params.persist).toHaveBeenCalledTimes(1);
});
it("runs subagent_ended hooks when available", async () => {
@@ -60,20 +67,60 @@ describe("emitSubagentEndedHookOnce", () => {
runSubagentEnded: lifecycleMocks.runSubagentEnded,
});
const entry = createRunEntry();
const persist = vi.fn();
const emitted = await emitSubagentEndedHookOnce({
entry,
reason: SUBAGENT_ENDED_REASON_COMPLETE,
sendFarewell: true,
accountId: "acct-1",
inFlightRunIds: new Set<string>(),
persist,
});
const params = createEmitParams();
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(true);
expect(lifecycleMocks.runSubagentEnded).toHaveBeenCalledTimes(1);
expect(typeof entry.endedHookEmittedAt).toBe("number");
expect(persist).toHaveBeenCalledTimes(1);
expect(typeof params.entry.endedHookEmittedAt).toBe("number");
expect(params.persist).toHaveBeenCalledTimes(1);
});
it("returns false when runId is blank", async () => {
const params = createEmitParams({
entry: { ...createRunEntry(), runId: " " },
});
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(false);
expect(params.persist).not.toHaveBeenCalled();
expect(lifecycleMocks.runSubagentEnded).not.toHaveBeenCalled();
});
it("returns false when ended hook marker already exists", async () => {
const params = createEmitParams({
entry: { ...createRunEntry(), endedHookEmittedAt: Date.now() },
});
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(false);
expect(params.persist).not.toHaveBeenCalled();
expect(lifecycleMocks.runSubagentEnded).not.toHaveBeenCalled();
});
it("returns false when runId is already in flight", async () => {
const entry = createRunEntry();
const inFlightRunIds = new Set<string>([entry.runId]);
const params = createEmitParams({ entry, inFlightRunIds });
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(false);
expect(params.persist).not.toHaveBeenCalled();
expect(lifecycleMocks.runSubagentEnded).not.toHaveBeenCalled();
});
it("returns false when subagent hook execution throws", async () => {
lifecycleMocks.runSubagentEnded.mockRejectedValueOnce(new Error("boom"));
lifecycleMocks.getGlobalHookRunner.mockReturnValue({
hasHooks: () => true,
runSubagentEnded: lifecycleMocks.runSubagentEnded,
});
const entry = createRunEntry();
const inFlightRunIds = new Set<string>();
const params = createEmitParams({ entry, inFlightRunIds });
const emitted = await emitSubagentEndedHookOnce(params);
expect(emitted).toBe(false);
expect(params.persist).not.toHaveBeenCalled();
expect(inFlightRunIds.has(entry.runId)).toBe(false);
expect(entry.endedHookEmittedAt).toBeUndefined();
});
});