refactor: consolidate chat state and task bridges

Centralize session scope, chat projections and typed task bridges.
Keep historical interaction replies authoritative and publish terminal state to subscribers. Validate Server contracts before replacing generated artifacts.
This commit is contained in:
2026-11-09 17:55:00 +08:00
parent addc81e106
commit 6279a4b555
31 changed files with 849 additions and 522 deletions
+39
View File
@@ -0,0 +1,39 @@
import { expect, it } from "bun:test";
import { createHash } from "node:crypto";
import { copyFile, mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { astToString, COMMENT_HEADER, default as openapiTS } from "openapi-typescript";
it.each(["valid", "invalid-schema", "invalid-digest"])("synchronizes the complete artifact group or preserves it (%s)", async (scenario) => {
const root = await mkdtemp(join(tmpdir(), "server-contract-sync-"));
try {
for (const directory of ["scripts", "openapi", "src/generated", "upstream"]) await mkdir(join(root, directory), { recursive: true });
await copyFile(new URL("../../scripts/server-contract.ts", import.meta.url), join(root, "scripts/server-contract.ts"));
await symlink(new URL("../../node_modules", import.meta.url).pathname, join(root, "node_modules"), "dir");
const targets = ["openapi/openapi.json", "openapi/server-manifest.json", "src/generated/server-api.d.ts"];
for (const target of targets) await writeFile(join(root, target), `original:${target}`);
const schema = { openapi: scenario === "invalid-schema" ? "9.9.9" : "3.1.0", info: { title: "Fixture", version: "1" }, paths: {} };
const raw = JSON.stringify(schema);
const manifest = { contracts: { server: { sha256: scenario === "invalid-digest" ? "incorrect" : createHash("sha256").update(raw).digest("hex") } } };
await writeFile(join(root, "upstream/schema.json"), raw);
await writeFile(join(root, "upstream/manifest.json"), JSON.stringify(manifest));
const child = Bun.spawn([process.execPath, "scripts/server-contract.ts", "--sync", "--upstream", "upstream/schema.json"], {
cwd: root, stdout: "pipe", stderr: "pipe",
});
const [code, stderr] = await Promise.all([child.exited, new Response(child.stderr).text()]);
if (scenario === "valid") {
expect(code).toBe(0);
expect(await readFile(join(root, targets[0]), "utf8")).toBe(raw);
expect(JSON.parse(await readFile(join(root, targets[1]), "utf8"))).toEqual(manifest);
expect(await readFile(join(root, targets[2]), "utf8")).toBe(COMMENT_HEADER + astToString(await openapiTS(schema)));
} else {
expect(code).not.toBe(0);
expect(stderr).toContain(scenario === "invalid-schema" ? "Unsupported OpenAPI version" : "contract digest differs");
for (const target of targets) expect(await readFile(join(root, target), "utf8")).toBe(`original:${target}`);
}
expect((await readdir(join(root, "openapi"))).sort()).toEqual(["openapi.json", "server-manifest.json"]);
} finally {
await rm(root, { recursive: true, force: true });
}
});