Files
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

267 lines
9.7 KiB
TypeScript

import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { describe, expect, it } from "vitest";
import { ToolPackCache } from "../src/cache.js";
import type { ToolPackConfig } from "../src/config.js";
import { prepareResourceTree } from "../src/win/resources.js";
import type { WinPaths } from "../src/win/types.js";
const RESOURCE_TREE_CACHE_TEST_TIMEOUT_MS = 15_000;
async function writeFakeOpenCodeCompanion(
source: string,
content = "#!/bin/sh\nexit 0\n",
): Promise<string> {
const companion = join(dirname(source), "libexec", "opencode", "opencode");
await mkdir(dirname(companion), { recursive: true });
await writeFile(companion, content, "utf8");
await chmod(companion, 0o755);
return companion;
}
async function createWorkspaceFixture(workspaceRoot: string): Promise<void> {
await mkdir(join(workspaceRoot, "skills", "sample"), { recursive: true });
await mkdir(join(workspaceRoot, "design-templates", "orbit-general"), {
recursive: true,
});
await mkdir(join(workspaceRoot, "design-systems", "sample"), {
recursive: true,
});
await mkdir(join(workspaceRoot, "craft", "sample"), { recursive: true });
await mkdir(join(workspaceRoot, "plugins", "_official", "sample"), {
recursive: true,
});
await writeFile(
join(workspaceRoot, "plugins", "_official", "sample", "open-design.json"),
"{\"id\":\"sample\"}\n",
"utf8",
);
await mkdir(join(workspaceRoot, "plugins", "registry", "community"), {
recursive: true,
});
await writeFile(
join(workspaceRoot, "plugins", "registry", "community", "open-design-marketplace.json"),
"{\"plugins\":[]}\n",
"utf8",
);
await mkdir(join(workspaceRoot, "assets", "frames"), { recursive: true });
await mkdir(join(workspaceRoot, "assets", "community-pets", "sample"), {
recursive: true,
});
await mkdir(join(workspaceRoot, "prompt-templates", "image"), {
recursive: true,
});
await mkdir(join(workspaceRoot, "data", "plugin-previews"), {
recursive: true,
});
await writeFile(
join(workspaceRoot, "data", "plugin-previews", "manifest.json"),
"{\"previews\":{}}\n",
"utf8",
);
await mkdir(join(workspaceRoot, "plugins", "registry", "official"), {
recursive: true,
});
}
describe("prepareResourceTree", () => {
it("invalidates the Windows resource tree cache when design templates change", async () => {
const root = await mkdtemp(join(tmpdir(), "open-design-win-resources-"));
const workspaceRoot = join(root, "workspace");
const resourceRoot = join(root, "materialized", "open-design");
const cache = new ToolPackCache(join(root, "cache"));
const config = { workspaceRoot } as ToolPackConfig;
const paths = { resourceRoot } as WinPaths;
const templatePath = join(
workspaceRoot,
"design-templates",
"orbit-general",
"SKILL.md",
);
const materializedTemplatePath = join(
resourceRoot,
"design-templates",
"orbit-general",
"SKILL.md",
);
try {
await createWorkspaceFixture(workspaceRoot);
await writeFile(templatePath, "version one\n", "utf8");
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedTemplatePath, "utf8")).resolves.toBe(
"version one\n",
);
await writeFile(templatePath, "version two\n", "utf8");
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedTemplatePath, "utf8")).resolves.toBe(
"version two\n",
);
expect(cache.report().entries.map((entry) => entry.status)).toEqual([
"miss",
"miss",
]);
} finally {
await rm(root, { force: true, recursive: true });
}
}, RESOURCE_TREE_CACHE_TEST_TIMEOUT_MS);
it("invalidates the Windows resource tree cache when the plugin-preview manifest changes", async () => {
const root = await mkdtemp(join(tmpdir(), "open-design-win-previews-"));
const workspaceRoot = join(root, "workspace");
const resourceRoot = join(root, "materialized", "open-design");
const cache = new ToolPackCache(join(root, "cache"));
const config = { workspaceRoot } as ToolPackConfig;
const paths = { resourceRoot } as WinPaths;
const manifestPath = join(
workspaceRoot,
"data",
"plugin-previews",
"manifest.json",
);
const materializedManifestPath = join(
resourceRoot,
"data",
"plugin-previews",
"manifest.json",
);
try {
await createWorkspaceFixture(workspaceRoot);
await writeFile(manifestPath, "{\"previews\":{\"a\":1}}\n", "utf8");
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedManifestPath, "utf8")).resolves.toBe(
"{\"previews\":{\"a\":1}}\n",
);
await writeFile(manifestPath, "{\"previews\":{\"a\":2}}\n", "utf8");
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedManifestPath, "utf8")).resolves.toBe(
"{\"previews\":{\"a\":2}}\n",
);
expect(cache.report().entries.map((entry) => entry.status)).toEqual([
"miss",
"miss",
]);
} finally {
await rm(root, { force: true, recursive: true });
}
}, RESOURCE_TREE_CACHE_TEST_TIMEOUT_MS);
it("copies a configured Vela CLI binary into the Windows resource tree", async () => {
const root = await mkdtemp(join(tmpdir(), "open-design-win-vela-"));
const workspaceRoot = join(root, "workspace");
const resourceRoot = join(root, "materialized", "open-design");
const source = join(root, "source", "vela.exe");
const cache = new ToolPackCache(join(root, "cache"));
const config = { workspaceRoot } as ToolPackConfig;
const paths = { resourceRoot } as WinPaths;
const originalVelaBin = process.env.OPEN_DESIGN_VELA_CLI_BIN;
try {
await createWorkspaceFixture(workspaceRoot);
await mkdir(join(root, "source"), { recursive: true });
await writeFile(source, "fake vela exe\n", "utf8");
await writeFakeOpenCodeCompanion(source, "fake opencode\n");
process.env.OPEN_DESIGN_VELA_CLI_BIN = source;
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(join(resourceRoot, "bin", "vela.exe"), "utf8")).resolves.toBe(
"fake vela exe\n",
);
await expect(
readFile(join(resourceRoot, "bin", "libexec", "opencode", "opencode"), "utf8"),
).resolves.toBe("fake opencode\n");
} finally {
if (originalVelaBin == null) delete process.env.OPEN_DESIGN_VELA_CLI_BIN;
else process.env.OPEN_DESIGN_VELA_CLI_BIN = originalVelaBin;
await rm(root, { force: true, recursive: true });
}
});
it("fails strict Windows resource preparation when configured Vela CLI is missing", async () => {
const root = await mkdtemp(join(tmpdir(), "open-design-win-vela-strict-"));
const workspaceRoot = join(root, "workspace");
const resourceRoot = join(root, "materialized", "open-design");
const cache = new ToolPackCache(join(root, "cache"));
const config = {
workspaceRoot,
requireVelaCli: true,
} as ToolPackConfig;
const paths = { resourceRoot } as WinPaths;
const originalVelaBin = process.env.OPEN_DESIGN_VELA_CLI_BIN;
try {
await createWorkspaceFixture(workspaceRoot);
process.env.OPEN_DESIGN_VELA_CLI_BIN = join(root, "missing", "vela.exe");
await expect(
prepareResourceTree(config, paths, cache, { materialize: true }),
).rejects.toThrow();
} finally {
if (originalVelaBin == null) delete process.env.OPEN_DESIGN_VELA_CLI_BIN;
else process.env.OPEN_DESIGN_VELA_CLI_BIN = originalVelaBin;
await rm(root, { force: true, recursive: true });
}
});
it("invalidates the Windows resource tree cache when the Vela companion changes", async () => {
const root = await mkdtemp(join(tmpdir(), "open-design-win-vela-companion-"));
const workspaceRoot = join(root, "workspace");
const resourceRoot = join(root, "materialized", "open-design");
const source = join(root, "source", "vela.exe");
const cache = new ToolPackCache(join(root, "cache"));
const config = { workspaceRoot } as ToolPackConfig;
const paths = { resourceRoot } as WinPaths;
const originalVelaBin = process.env.OPEN_DESIGN_VELA_CLI_BIN;
const materializedCompanion = join(
resourceRoot,
"bin",
"libexec",
"opencode",
"opencode",
);
try {
await createWorkspaceFixture(workspaceRoot);
await mkdir(join(root, "source"), { recursive: true });
await writeFile(source, "fake vela exe\n", "utf8");
const sourceCompanion = await writeFakeOpenCodeCompanion(source, "companion one\n");
process.env.OPEN_DESIGN_VELA_CLI_BIN = source;
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedCompanion, "utf8")).resolves.toBe(
"companion one\n",
);
await writeFile(sourceCompanion, "companion two\n", "utf8");
await prepareResourceTree(config, paths, cache, { materialize: true });
await expect(readFile(materializedCompanion, "utf8")).resolves.toBe(
"companion two\n",
);
expect(cache.report().entries.map((entry) => entry.status)).toEqual([
"miss",
"miss",
]);
} finally {
if (originalVelaBin == null) delete process.env.OPEN_DESIGN_VELA_CLI_BIN;
else process.env.OPEN_DESIGN_VELA_CLI_BIN = originalVelaBin;
await rm(root, { force: true, recursive: true });
}
}, RESOURCE_TREE_CACHE_TEST_TIMEOUT_MS);
});