mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-10 03:30:59 +00:00
## Summary This branch improves several run-management surfaces that agents and users rely on: archived runs now stay visible and ordered correctly in the board view, pair-session messages appear in the stage Thread tab, and the `fabro_run_create` MCP tool accepts the workflow-string shorthand it advertises. ## Changes - Updates the web board cache invalidation and archived-column handling so archive/unarchive actions refresh both active and archived board queries and keep archived runs in a predictable column position. - Adds pair user/system message events to stage activity parsing, Thread rendering, search, details, and DNA timeline items. - Aligns `fabro_run_create` MCP runtime deserialization and `tools/list` schema so each run entry may be either a workflow string or a full create spec object. ## Test Plan - `cargo nextest run -p fabro-tool -p fabro-mcp-server` - `cargo nextest run -p fabro-cli stdio_server_initializes_and_lists_run_tools mcp_create_string_shorthand_deserializes_before_auth mcp_create_validation_errors_happen_before_auth_or_network mcp_create_and_search_manage_real_runs_with_cli_auth` - `cargo +nightly-2026-04-14 fmt --check --all` --- [](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with GPT-5 via [Codex](https://openai.com/codex) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import { describe, expect, mock, test, beforeEach } from "bun:test";
|
|
|
|
import { queryKeys } from "./query-keys";
|
|
|
|
const mutateMock = mock((..._args: unknown[]) => Promise.resolve(undefined));
|
|
let lastMutationOptions: { onSuccess?: (result: unknown) => void } | null = null;
|
|
|
|
const useSWRMutationMock = mock((_key: unknown, _fetcher: unknown, options: unknown) => {
|
|
lastMutationOptions = options as { onSuccess?: (result: unknown) => void };
|
|
return {};
|
|
});
|
|
|
|
mock.module("swr", () => ({
|
|
useSWRConfig: () => ({ mutate: mutateMock }),
|
|
}));
|
|
|
|
mock.module("swr/mutation", () => ({
|
|
default: useSWRMutationMock,
|
|
}));
|
|
|
|
mock.module("./api-client", () => ({
|
|
apiData: mock(),
|
|
authApi: {},
|
|
humanInTheLoopApi: {},
|
|
runsApi: {},
|
|
}));
|
|
|
|
mock.module("./run-actions", () => ({
|
|
archiveRun: mock(),
|
|
cancelRun: mock(),
|
|
isLifecycleActionError: () => false,
|
|
unarchiveRun: mock(),
|
|
}));
|
|
|
|
const { useArchiveRun } = await import("./mutations");
|
|
|
|
beforeEach(() => {
|
|
mutateMock.mockClear();
|
|
useSWRMutationMock.mockClear();
|
|
lastMutationOptions = null;
|
|
});
|
|
|
|
describe("lifecycle mutations", () => {
|
|
test("successful archive invalidates both board run caches", () => {
|
|
useArchiveRun("run-1");
|
|
|
|
lastMutationOptions?.onSuccess?.({
|
|
intent: "archive",
|
|
ok: true,
|
|
run: {},
|
|
});
|
|
|
|
const keys = mutateMock.mock.calls.map((call) => call[0]);
|
|
expect(keys).toContainEqual(queryKeys.boards.runs(false));
|
|
expect(keys).toContainEqual(queryKeys.boards.runs(true));
|
|
});
|
|
});
|