mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 01:27:09 +01:00
Share the launcher cleanup traversal with rolling replacement. Make stopped controller directories removable without following dependency symlinks, then delete the entire predecessor home. Cover immutable bundles and external symlink protection with real filesystem tests. Co-Authored-By: Paperclip <noreply@paperclip.ing>
30 lines
1.6 KiB
TypeScript
30 lines
1.6 KiB
TypeScript
import { chmod, lstat, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { expect, it } from "vitest";
|
|
import { makeDirectoryTreeRemovable } from "./directory-cleanup.js";
|
|
|
|
it("removes a retired home with immutable bundles without changing linked dependencies", async () => {
|
|
const root = await mkdtemp(path.join(tmpdir(), "paperclip-retired-home-"));
|
|
const home = path.join(root, "controller"), external = path.join(root, "external");
|
|
const bundle = path.join(home, "runtime-context-assets/bundles/digest");
|
|
try {
|
|
await mkdir(bundle, { recursive: true }); await mkdir(external);
|
|
await writeFile(path.join(bundle, "SKILL.md"), "immutable skill");
|
|
await writeFile(path.join(external, "keep"), "dependency");
|
|
await chmod(bundle, 0o555); await chmod(external, 0o555);
|
|
await symlink(external, path.join(home, "node_modules"));
|
|
await makeDirectoryTreeRemovable(home);
|
|
await rm(home, { recursive: true });
|
|
await expect(lstat(home)).rejects.toMatchObject({ code: "ENOENT" });
|
|
expect((await lstat(external)).mode & 0o777).toBe(0o555);
|
|
expect(await readFile(path.join(external, "keep"), "utf8")).toBe("dependency");
|
|
const link = path.join(root, "not-an-owned-home");
|
|
await symlink(external, link);
|
|
await expect(makeDirectoryTreeRemovable(link)).rejects.toThrow("not a symlink");
|
|
expect((await lstat(external)).mode & 0o777).toBe(0o555);
|
|
} finally {
|
|
await makeDirectoryTreeRemovable(root); await rm(root, { recursive: true });
|
|
}
|
|
});
|