## 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 --- [](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 -->
107 lines
4.4 KiB
TypeScript
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);
|
|
});
|
|
});
|