Files
fusion/plugins/fusion-plugin-compound-engineering/src/__tests__/agent-installation.test.ts
gsxdsm aa401123ea fix: make Windows updates and CE personas reliable (#2340)
## Summary

Windows installs with slow native dependencies now get five minutes to
finish, and a real timeout is reported as an actionable terminal retry
instead of a wall of preceding npm deprecation warnings. Registry
`ETIMEDOUT` errors keep their network diagnosis, including after the
legacy-bin `--force` retry.

Compound Engineering personas are now included in the published CLI
bundle, with complete source-to-staged coverage for all persona
definitions and a clear startup error if the bundled assets are missing
or empty.

The PostgreSQL statement visible in the report was validated by the
existing real-Postgres schema reapply test. Its actual `caused by`
detail was truncated, so this PR deliberately makes no speculative
database change.

## Validation

- Dashboard updater tests: 22 passed
- CLI updater tests: 16 passed
- CE persona installer tests: 7 passed
- Published bundle persona assertion: passed against every source
persona
- CLI and CE plugin typechecks: passed
- Changed production/config lint and strict changeset validation: passed
- Real PostgreSQL schema reapply integration test: passed

---

[![Compound
Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Windows CLI and dashboard updates now allow up to five minutes for
installation and restore Compound Engineering agent personas during npm
installs.
* Update failures now surface clearer, terminal timeout guidance (while
preserving specific network connection diagnostics) and avoid misleading
“deprecated”/generic timeout text.
* Persona assets are reliably included in plugin builds and bunded
persona installation now errors clearly when definitions are missing or
empty.
* **Tests**
* Expanded update and bundling coverage for the new 5-minute timeout and
error-handling scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-19 12:16:12 -07:00

107 lines
4.4 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
assertPluginLocalAgentsTarget,
installBundledCeAgents,
isPluginLocalAgentsPath,
resolveBundledAgentsRoot,
} from "../agent-installation.js";
describe("compound engineering bundled agent-persona install", () => {
let tmp: string;
beforeEach(() => {
tmp = mkdtempSync(join(tmpdir(), "ce-agent-install-"));
});
afterEach(() => {
rmSync(tmp, { recursive: true, force: true });
});
it("installs every bundled ce-* persona def into the plugin-local target", () => {
const targetRoot = join(tmp, "plugin-local", ".fusion-ce-agents");
const { results } = installBundledCeAgents({ targetRoot });
expect(results.length).toBeGreaterThan(0);
expect(results.every((r) => r.outcome === "installed")).toBe(true);
// Every source def lands on disk.
const sourceDefs = readdirSync(resolveBundledAgentsRoot()).filter((f) => f.endsWith(".md"));
for (const file of sourceDefs) {
expect(existsSync(join(targetRoot, file))).toBe(true);
}
// The reviewer/research personas the CE skills fan out to are present.
for (const id of ["ce-correctness-reviewer", "ce-repo-research-analyst", "ce-pr-comment-resolver"]) {
expect(existsSync(join(targetRoot, `${id}.md`))).toBe(true);
}
});
it("fails loudly when a published package omits all bundled persona defs", () => {
const missingSourceRoot = join(tmp, "missing-agents");
expect(() => installBundledCeAgents({
sourceRoot: missingSourceRoot,
targetRoot: join(tmp, ".fusion-ce-agents"),
})).toThrow(/bundled agent persona source.*missing/i);
});
it("fails loudly when the bundled persona directory is empty", () => {
const emptySourceRoot = join(tmp, "empty-agents");
mkdirSync(emptySourceRoot);
expect(() => installBundledCeAgents({
sourceRoot: emptySourceRoot,
targetRoot: join(tmp, ".fusion-ce-agents"),
})).toThrow(/contains no markdown definitions/i);
});
it("is idempotent when the plugin-local install provenance is current", () => {
const targetRoot = join(tmp, ".fusion-ce-agents");
const first = installBundledCeAgents({ targetRoot });
expect(first.results.every((r) => r.outcome === "installed")).toBe(true);
const sentinelPath = join(targetRoot, "ce-correctness-reviewer.md");
writeFileSync(sentinelPath, "SENTINEL");
const second = installBundledCeAgents({ targetRoot });
expect(second.results.every((r) => r.outcome === "skipped")).toBe(true);
expect(readFileSync(sentinelPath, "utf-8")).toBe("SENTINEL");
});
it("refreshes stale plugin-local agent installs without a current provenance marker", () => {
const targetRoot = join(tmp, ".fusion-ce-agents");
const first = installBundledCeAgents({ targetRoot });
expect(first.results.every((r) => r.outcome === "installed")).toBe(true);
const sentinelPath = join(targetRoot, "ce-correctness-reviewer.md");
writeFileSync(sentinelPath, "SENTINEL");
rmSync(join(targetRoot, ".fusion-ce-upstream-provenance.json"), { force: true });
const second = installBundledCeAgents({ targetRoot });
expect(second.results.every((r) => r.outcome === "refreshed")).toBe(true);
expect(readFileSync(sentinelPath, "utf-8")).not.toBe("SENTINEL");
});
it("refuses to install into a global client agents directory", () => {
expect(() => assertPluginLocalAgentsTarget(join(tmp, ".claude", "agents"))).toThrow(/plugin-local/i);
expect(isPluginLocalAgentsPath(join(tmp, ".claude", "agents"))).toBe(false);
expect(isPluginLocalAgentsPath(join(tmp, ".fusion-ce-agents"))).toBe(true);
});
it("AE: never writes outside the plugin-local target when a global install exists", () => {
const fakeHome = join(tmp, "home");
const globalAgentsDir = join(fakeHome, ".claude", "agents");
mkdirSync(globalAgentsDir, { recursive: true });
const globalDef = join(globalAgentsDir, "ce-correctness-reviewer.md");
writeFileSync(globalDef, "GLOBAL-ORIGINAL");
const beforeMtime = statSync(globalDef).mtimeMs;
installBundledCeAgents({ targetRoot: join(tmp, "plugin-local", ".fusion-ce-agents") });
expect(readFileSync(globalDef, "utf-8")).toBe("GLOBAL-ORIGINAL");
expect(statSync(globalDef).mtimeMs).toBe(beforeMtime);
});
});