mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-26 02:00:52 +01:00
89 lines
4.0 KiB
TypeScript
89 lines
4.0 KiB
TypeScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { installCommand, resolveNpmInstallRequest } from "../commands/install.js";
|
|
import { uninstallCommand } from "../commands/uninstall.js";
|
|
import { readInstallManifest, resolveInstallStorePaths } from "../install-store.js";
|
|
import { resolveCliVersion } from "../version.js";
|
|
|
|
const ORIGINAL_ENV = { ...process.env };
|
|
|
|
describe("managed install commands", () => {
|
|
let root: string;
|
|
|
|
beforeEach(() => {
|
|
root = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-install-command-"));
|
|
process.env = {
|
|
...ORIGINAL_ENV,
|
|
HOME: path.join(root, "home"),
|
|
PAPERCLIP_HOME: path.join(root, "home", ".paperclip"),
|
|
PATH: "/usr/bin:/bin",
|
|
SHELL: "/bin/bash",
|
|
};
|
|
fs.mkdirSync(process.env.HOME!, { recursive: true });
|
|
vi.spyOn(console, "log").mockImplementation(() => undefined);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
process.env = { ...ORIGINAL_ENV };
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
});
|
|
|
|
it("selects stable, canary, and exact-version npm sources", () => {
|
|
expect(resolveNpmInstallRequest({})).toEqual({ spec: "latest", channel: "latest" });
|
|
expect(resolveNpmInstallRequest({ canary: true })).toEqual({ spec: "canary", channel: "canary" });
|
|
expect(resolveNpmInstallRequest({ version: "2026.720.0" })).toEqual({
|
|
spec: "2026.720.0",
|
|
channel: "pinned",
|
|
});
|
|
expect(() => resolveNpmInstallRequest({ canary: true, version: "1.2.3" })).toThrow();
|
|
expect(() => resolveNpmInstallRequest({ version: "latest" })).toThrow();
|
|
});
|
|
|
|
it("installs through the shim, reports provenance, and uninstalls without deleting user data", async () => {
|
|
const version = "2026.720.0";
|
|
const runCommand = vi.fn(async (file: string, args: string[], _options?: unknown) => {
|
|
if (file === "npm" && args[0] === "view") return { stdout: JSON.stringify(version), stderr: "" };
|
|
if (file === "npm" && args[0] === "install") {
|
|
const prefix = args[args.indexOf("--prefix") + 1];
|
|
const entrypoint = path.join(prefix, "node_modules", "paperclipai", "dist", "index.js");
|
|
fs.mkdirSync(path.dirname(entrypoint), { recursive: true });
|
|
fs.writeFileSync(entrypoint, "#!/usr/bin/env node\n");
|
|
return { stdout: "", stderr: "" };
|
|
}
|
|
if (file === process.execPath && args.at(-1) === "--version") {
|
|
return { stdout: `${version}\n`, stderr: "" };
|
|
}
|
|
throw new Error(`Unexpected command: ${file} ${args.join(" ")}`);
|
|
});
|
|
|
|
await installCommand({}, { runCommand, now: () => new Date("2026-07-22T18:00:00.000Z") });
|
|
|
|
const paths = resolveInstallStorePaths();
|
|
const manifest = readInstallManifest(paths);
|
|
expect(manifest?.version).toBe(version);
|
|
expect(manifest?.channel).toBe("latest");
|
|
expect(fs.realpathSync(paths.currentPath)).toBe(fs.realpathSync(manifest!.payloadPath));
|
|
expect(fs.existsSync(paths.shimPath)).toBe(true);
|
|
const installCall = runCommand.mock.calls.find(
|
|
([file, args]) => file === "npm" && args[0] === "install",
|
|
);
|
|
expect(installCall?.[1]).toContain("--@paperclipai:registry=https://registry.npmjs.org");
|
|
const installOptions = installCall?.[2] as { env?: NodeJS.ProcessEnv } | undefined;
|
|
expect(installOptions?.env?.npm_config_userconfig).toContain(".npmrc-");
|
|
const entrypoint = path.join(manifest!.payloadPath, "node_modules", "paperclipai", "dist", "index.js");
|
|
expect(resolveCliVersion(entrypoint)).toContain(`managed npm latest; payload ${manifest!.payloadPath}`);
|
|
|
|
const userData = path.join(process.env.PAPERCLIP_HOME!, "instances", "default", "keep.txt");
|
|
fs.mkdirSync(path.dirname(userData), { recursive: true });
|
|
fs.writeFileSync(userData, "keep");
|
|
await uninstallCommand();
|
|
|
|
expect(fs.existsSync(paths.cliRoot)).toBe(false);
|
|
expect(fs.existsSync(paths.shimPath)).toBe(false);
|
|
expect(fs.readFileSync(userData, "utf8")).toBe("keep");
|
|
});
|
|
});
|