mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 09:21:16 +00:00
Add the environments reference to the skill and install it with setup: record against a disposable instance, sign in through the UI, write with request steps and read each write back, check coverage, re-record by withheld reason and export the bundle. Route it from SKILL.md, name agent environments in the skill description, and document the request step, the export tool and recording writes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
723 lines
26 KiB
TypeScript
723 lines
26 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import {
|
|
access,
|
|
chmod,
|
|
copyFile,
|
|
lstat,
|
|
mkdir,
|
|
readFile,
|
|
readdir,
|
|
rename,
|
|
rm,
|
|
stat,
|
|
symlink,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { constants as fsConstants } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
import {
|
|
canonicalSkillNeedsInstall,
|
|
existingSkillDestinations,
|
|
installCanonicalSkill,
|
|
readInstalledSkillIdentity,
|
|
skillDestinations,
|
|
type SkillInstallFileOperations,
|
|
} from "../../../src/application/SetupSkill.js";
|
|
import {
|
|
runDoctor,
|
|
systemDoctorHost,
|
|
} from "../../../src/application/Doctor.js";
|
|
import { createDoctorHostFixture } from "../../../src/application/Doctor.fixture.js";
|
|
import { TOOL_CONTRACTS } from "../../../src/contracts/toolContracts.js";
|
|
import { PRODUCT_IDENTITY } from "../../../src/identity.js";
|
|
import { SkillFilePublication } from "../../../src/application/SkillFilePublication.js";
|
|
import { z } from "zod";
|
|
import { skillReferenceIssues } from "../../../scripts/lib/docs-facts.mjs";
|
|
|
|
const expectPermissionMode = async (
|
|
path: string,
|
|
expected: number,
|
|
): Promise<void> => {
|
|
if (process.platform === "win32") return;
|
|
expect((await stat(path)).mode & 0o777).toBe(expected);
|
|
};
|
|
|
|
describe("skill recovery backup selection", () => {
|
|
it("reuses a verified existing backup without copying it again", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-matching-backup-");
|
|
const [destination] = skillDestinations(home, []);
|
|
if (destination === undefined) throw new Error("Missing shared skill root");
|
|
const manifest = join(destination.path, "SKILL.md");
|
|
const current = "currently installed instructions\n";
|
|
await mkdir(dirname(manifest), { recursive: true });
|
|
await writeFile(manifest, current);
|
|
await writeFile(`${manifest}.rea.backup`, current);
|
|
const result = await installCanonicalSkill(home, [], {}, process.platform, {
|
|
mkdir: async (path) =>
|
|
mkdir(path, { recursive: true }).then(() => undefined),
|
|
backup: async () => {
|
|
throw new Error("A matching backup must not be copied again");
|
|
},
|
|
prepare: SkillFilePublication.prepare,
|
|
});
|
|
|
|
expect(result).toEqual({ ok: true, value: "installed" });
|
|
expect(await readFile(`${manifest}.rea.backup`, "utf8")).toBe(current);
|
|
expect(await canonicalSkillNeedsInstall(home, [])).toBe(false);
|
|
});
|
|
|
|
it("advertises a current recovery snapshot when the first backup is historical", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-historical-backup-");
|
|
const [destination] = skillDestinations(home, []);
|
|
if (destination === undefined) throw new Error("Missing shared skill root");
|
|
const manifest = join(destination.path, "SKILL.md");
|
|
const current = "currently installed instructions V2\n";
|
|
const oldSnapshot = "historical instructions V0\n";
|
|
await mkdir(dirname(manifest), { recursive: true });
|
|
await writeFile(manifest, current);
|
|
await writeFile(`${manifest}.rea.backup`, oldSnapshot);
|
|
const operations: SkillInstallFileOperations = {
|
|
mkdir: async (path) =>
|
|
mkdir(path, { recursive: true }).then(() => undefined),
|
|
backup: async (source, target) =>
|
|
copyFile(source, target, fsConstants.COPYFILE_EXCL),
|
|
prepare: async (...args) => {
|
|
const publication = await SkillFilePublication.prepare(...args);
|
|
if (publication.path === manifest) {
|
|
const publish = publication.publish.bind(publication);
|
|
vi.spyOn(publication, "publish").mockImplementation(async () => {
|
|
await publish();
|
|
throw new Error("injected failure after publication");
|
|
});
|
|
vi.spyOn(publication, "restore").mockRejectedValue(
|
|
new Error("injected rollback failure"),
|
|
);
|
|
}
|
|
return publication;
|
|
},
|
|
};
|
|
|
|
const result = await installCanonicalSkill(
|
|
home,
|
|
[],
|
|
{},
|
|
process.platform,
|
|
operations,
|
|
);
|
|
|
|
if (result.ok) throw new Error("Expected the injected write failure");
|
|
expect(result.error.rollbackFailures).toEqual([
|
|
{ path: manifest, reason: "injected rollback failure" },
|
|
]);
|
|
const recovery = result.error.recoveryBackupPaths.find((path) =>
|
|
path.startsWith(`${manifest}.rea.backup.`),
|
|
);
|
|
expect(recovery).toBeDefined();
|
|
expect(await readFile(recovery!, "utf8")).toBe(current);
|
|
expect(await readFile(`${manifest}.rea.backup`, "utf8")).toBe(oldSnapshot);
|
|
});
|
|
});
|
|
|
|
describe("skill recovery byte preservation", () => {
|
|
it("backs up and restores the exact bytes of invalid UTF-8 before replacing a skill", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-damaged-bytes-");
|
|
const [destination] = skillDestinations(home, []);
|
|
if (destination === undefined) throw new Error("Missing shared skill root");
|
|
const manifest = join(destination.path, "SKILL.md");
|
|
const original = Buffer.from([0x63, 0x61, 0x66, 0xe9, 0xff, 0x0a]);
|
|
const firstBackup = `${manifest}.rea.backup`;
|
|
const recovery = `${firstBackup}.${createHash("sha256").update(original).digest("hex")}.recovery`;
|
|
await mkdir(dirname(manifest), { recursive: true });
|
|
await writeFile(manifest, original);
|
|
await writeFile(firstBackup, "historical instructions V0\n");
|
|
const result = await installCanonicalSkill(home, [], {}, process.platform, {
|
|
mkdir: async (path) =>
|
|
mkdir(path, { recursive: true }).then(() => undefined),
|
|
backup: async (source, target) =>
|
|
copyFile(source, target, fsConstants.COPYFILE_EXCL),
|
|
prepare: async (...args) => {
|
|
const publication = await SkillFilePublication.prepare(...args);
|
|
if (publication.path === manifest) {
|
|
const publish = publication.publish.bind(publication);
|
|
vi.spyOn(publication, "publish").mockImplementation(async () => {
|
|
await publish();
|
|
throw new Error("injected failure after publication");
|
|
});
|
|
}
|
|
return publication;
|
|
},
|
|
});
|
|
if (result.ok) throw new Error("Expected the injected write failure");
|
|
expect(result.error.recoveryBackupPaths).toContain(recovery);
|
|
expect(await readFile(recovery)).toEqual(original);
|
|
expect(await readFile(manifest)).toEqual(original);
|
|
expect(result.error.rollbackFailures).toEqual([]);
|
|
expect(await readFile(firstBackup, "utf8")).toBe(
|
|
"historical instructions V0\n",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("skill directory admission", () => {
|
|
it("excludes a linked references directory from update maintenance", async () => {
|
|
const directory = await createTestTempDirectory(
|
|
"rea-skill-linked-maintenance-",
|
|
);
|
|
const installed = await installCanonicalSkill(directory, ["claude_code"]);
|
|
expect(installed.ok).toBe(true);
|
|
const [selected] = skillDestinations(directory, ["claude_code"]);
|
|
if (selected === undefined) throw new Error("Missing skill destination");
|
|
const references = join(selected.path, "references");
|
|
const retained = join(directory, "retained-references");
|
|
await rename(references, retained);
|
|
await symlink(
|
|
retained,
|
|
references,
|
|
process.platform === "win32" ? "junction" : "dir",
|
|
);
|
|
expect(await existingSkillDestinations(directory)).toEqual({
|
|
destinations: [],
|
|
issues: [],
|
|
});
|
|
expect((await lstat(references)).isSymbolicLink()).toBe(true);
|
|
await access(join(retained, "native-and-artifacts.md"));
|
|
});
|
|
|
|
it
|
|
.skipIf(process.platform === "win32" || process.getuid?.() === 0)
|
|
.each(["aligned", "stale", "missing"] as const)(
|
|
"reports every unreadable reference with a %s manifest",
|
|
async (manifestState) => {
|
|
const directory = await createTestTempDirectory(
|
|
"rea-skill-unreadable-reference-",
|
|
);
|
|
expect((await installCanonicalSkill(directory, ["claude_code"])).ok).toBe(
|
|
true,
|
|
);
|
|
const [selected] = skillDestinations(directory, ["claude_code"]);
|
|
if (selected === undefined) throw new Error("Missing skill destination");
|
|
const manifest = join(selected.path, "SKILL.md");
|
|
if (manifestState === "stale")
|
|
await writeFile(manifest, "\nlocal changes\n", { flag: "a" });
|
|
if (manifestState === "missing") await rm(manifest);
|
|
const references = [
|
|
"references/connection-and-recovery.md",
|
|
"references/evidence-workflows.md",
|
|
].map((relative) => join(selected.path, relative));
|
|
for (const reference of references) await chmod(reference, 0o000);
|
|
try {
|
|
const identity = await readInstalledSkillIdentity(directory, [
|
|
"claude_code",
|
|
]);
|
|
const issues = references.map((path) =>
|
|
expect.objectContaining({
|
|
path,
|
|
kind: "unreadable",
|
|
detail: expect.stringContaining("EACCES"),
|
|
}),
|
|
);
|
|
expect(identity).toMatchObject({
|
|
canonical: false,
|
|
version:
|
|
manifestState === "missing" ? null : PRODUCT_IDENTITY.skillVersion,
|
|
issues,
|
|
});
|
|
const report = await runDoctor(
|
|
undefined,
|
|
createDoctorHostFixture({
|
|
installedSkillIdentity: () => Promise.resolve(identity),
|
|
}),
|
|
);
|
|
expect(report.identity?.skill).toMatchObject({
|
|
state: "unknown",
|
|
issues,
|
|
remediation: expect.stringContaining("evidence-workflows.md"),
|
|
});
|
|
} finally {
|
|
for (const reference of references) await chmod(reference, 0o600);
|
|
}
|
|
},
|
|
);
|
|
|
|
it.each(["root", "references"] as const)(
|
|
"refuses a linked skill %s before changing any selected destination",
|
|
async (linkedDirectory) => {
|
|
const home = await createTestTempDirectory("rea-skill-linked-root-");
|
|
const destinations = skillDestinations(home, ["shared", "claude_code"]);
|
|
const selected = destinations.find(
|
|
({ client }) => client === "claude_code",
|
|
);
|
|
if (selected === undefined)
|
|
throw new Error("Missing Claude Code skill root");
|
|
const managed = join(home, "user-managed");
|
|
await mkdir(managed);
|
|
const original = "user-owned instructions\n";
|
|
await writeFile(join(managed, "SKILL.md"), original);
|
|
const linked =
|
|
linkedDirectory === "root"
|
|
? selected.path
|
|
: join(selected.path, "references");
|
|
await mkdir(dirname(linked), { recursive: true });
|
|
await symlink(
|
|
managed,
|
|
linked,
|
|
process.platform === "win32" ? "junction" : "dir",
|
|
);
|
|
|
|
const result = await installCanonicalSkill(home, [
|
|
"shared",
|
|
"claude_code",
|
|
]);
|
|
if (result.ok) throw new Error("Expected linked directory refusal");
|
|
expect(result.error.stage).toBe("prepare");
|
|
expect(result.error.path).toBe(linked);
|
|
expect(result.error.reason).toContain("symbolic link");
|
|
expect(result.error.rollbackFailures).toEqual([]);
|
|
expect((await lstat(linked)).isSymbolicLink()).toBe(true);
|
|
expect(await readFile(join(managed, "SKILL.md"), "utf8")).toBe(original);
|
|
expect(await readdir(managed)).toEqual(["SKILL.md"]);
|
|
const shared = destinations.find(({ client }) => client === "shared");
|
|
if (shared === undefined) throw new Error("Missing shared skill root");
|
|
await expect(access(shared.path)).rejects.toMatchObject({
|
|
code: "ENOENT",
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
describe("canonical skill transaction", () => {
|
|
it("does not roll back files when backup preparation fails", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-backup-failure-");
|
|
const root = join(home, ".agents/skills/reverse-engineer-anything");
|
|
const manifest = join(root, "SKILL.md");
|
|
const connection = join(root, "references/connection-and-recovery.md");
|
|
const original = "operator-owned manifest bytes\n";
|
|
const secondOriginal = "operator-owned reference bytes\n";
|
|
await mkdir(dirname(connection), { recursive: true });
|
|
await writeFile(manifest, original, { mode: 0o640 });
|
|
await writeFile(connection, secondOriginal, { mode: 0o644 });
|
|
const writes: string[] = [];
|
|
let backups = 0;
|
|
const operations: SkillInstallFileOperations = {
|
|
mkdir: async (path) => {
|
|
await mkdir(path, { recursive: true });
|
|
},
|
|
backup: async (source, target) => {
|
|
backups += 1;
|
|
if (backups === 2) throw new Error("injected backup failure");
|
|
await copyFile(source, target, fsConstants.COPYFILE_EXCL);
|
|
},
|
|
prepare: async (...args) => {
|
|
writes.push(args[0]);
|
|
return SkillFilePublication.prepare(...args);
|
|
},
|
|
};
|
|
|
|
const result = await installCanonicalSkill(
|
|
home,
|
|
[],
|
|
{},
|
|
process.platform,
|
|
operations,
|
|
);
|
|
|
|
if (result.ok) throw new Error("Expected backup failure");
|
|
expect(result.error.stage).toBe("backup");
|
|
expect(result.error.rollbackFailures).toEqual([]);
|
|
expect(writes).toEqual([]);
|
|
expect(await readFile(manifest, "utf8")).toBe(original);
|
|
expect(await readFile(connection, "utf8")).toBe(secondOriginal);
|
|
expect(await readFile(`${manifest}.rea.backup`, "utf8")).toBe(original);
|
|
await expect(
|
|
readFile(`${connection}.rea.backup`, "utf8"),
|
|
).rejects.toMatchObject({
|
|
code: "ENOENT",
|
|
});
|
|
await expectPermissionMode(manifest, 0o640);
|
|
await expectPermissionMode(connection, 0o644);
|
|
});
|
|
|
|
it("rolls back attempted writes independently and preserves original modes", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-rollback-failure-");
|
|
const [destination] = skillDestinations(home, []);
|
|
if (destination === undefined) throw new Error("Missing shared skill root");
|
|
const root = destination.path;
|
|
const manifest = join(root, "SKILL.md");
|
|
const connection = join(root, "references/connection-and-recovery.md");
|
|
const native = join(root, "references/native-and-artifacts.md");
|
|
await mkdir(dirname(native), { recursive: true });
|
|
await writeFile(manifest, "old manifest\n", { mode: 0o640 });
|
|
await writeFile(connection, "old connection\n", { mode: 0o644 });
|
|
await writeFile(native, "old native\n", { mode: 0o600 });
|
|
const operations: SkillInstallFileOperations = {
|
|
mkdir: async (path) => {
|
|
await mkdir(path, { recursive: true });
|
|
},
|
|
backup: async (source, target) =>
|
|
copyFile(source, target, fsConstants.COPYFILE_EXCL),
|
|
prepare: async (...args) => {
|
|
const publication = await SkillFilePublication.prepare(...args);
|
|
if (publication.path === native) {
|
|
const publish = publication.publish.bind(publication);
|
|
vi.spyOn(publication, "publish").mockImplementation(async () => {
|
|
await publish();
|
|
throw new Error("injected ambiguous publication failure");
|
|
});
|
|
vi.spyOn(publication, "restore").mockRejectedValue(
|
|
new Error("injected rollback failure"),
|
|
);
|
|
}
|
|
return publication;
|
|
},
|
|
};
|
|
|
|
const result = await installCanonicalSkill(
|
|
home,
|
|
[],
|
|
{},
|
|
process.platform,
|
|
operations,
|
|
);
|
|
|
|
if (result.ok) throw new Error("Expected write failure");
|
|
expect(result.error.stage).toBe("write");
|
|
expect(result.error.path).toBe(native);
|
|
expect(result.error.rollbackFailures).toEqual([
|
|
{ path: native, reason: "injected rollback failure" },
|
|
]);
|
|
expect(result.error.recoveryBackupPaths).toEqual([
|
|
`${manifest}.rea.backup`,
|
|
`${connection}.rea.backup`,
|
|
`${native}.rea.backup`,
|
|
]);
|
|
expect(result.error.message).toContain(
|
|
`${native} (injected rollback failure)`,
|
|
);
|
|
expect(await readFile(manifest, "utf8")).toBe("old manifest\n");
|
|
expect(await readFile(connection, "utf8")).toBe("old connection\n");
|
|
await expectPermissionMode(manifest, 0o640);
|
|
await expectPermissionMode(connection, 0o644);
|
|
expect(await readFile(native, "utf8")).not.toBe("old native\n");
|
|
expect(await readFile(`${native}.rea.backup`, "utf8")).toBe("old native\n");
|
|
expect(result.error.message).toContain(
|
|
`Existing-file backups remain at ${manifest}.rea.backup`,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("canonical skill discovery", () => {
|
|
it.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
|
"preserves an unreadable existing skill instead of treating it as absent",
|
|
async () => {
|
|
const home = await createTestTempDirectory("rea-skill-unreadable-");
|
|
const destination = join(
|
|
home,
|
|
".agents/skills/reverse-engineer-anything/SKILL.md",
|
|
);
|
|
const original = "existing private skill bytes\n";
|
|
await mkdir(dirname(destination), { recursive: true });
|
|
await writeFile(destination, original, { mode: 0o200 });
|
|
try {
|
|
await chmod(destination, 0o200);
|
|
const result = await installCanonicalSkill(home);
|
|
if (result.ok) throw new Error("Expected unreadable skill failure");
|
|
expect(result.error.stage).toBe("prepare");
|
|
} finally {
|
|
await chmod(destination, 0o600);
|
|
}
|
|
expect(await readFile(destination, "utf8")).toBe(original);
|
|
await expect(
|
|
readFile(`${destination}.rea.backup`, "utf8"),
|
|
).rejects.toMatchObject({
|
|
code: "ENOENT",
|
|
});
|
|
},
|
|
);
|
|
|
|
it("installs only the selected Claude Code personal skill", async () => {
|
|
const home = await createTestTempDirectory("rea-claude-skill-");
|
|
const configDirectory = join(home, "claude-config");
|
|
const skillsDirectory = join(configDirectory, "skills");
|
|
const claudeSkill = join(
|
|
skillsDirectory,
|
|
"reverse-engineer-anything/SKILL.md",
|
|
);
|
|
await mkdir(configDirectory, { recursive: true });
|
|
await writeFile(
|
|
join(configDirectory, ".claude.json"),
|
|
JSON.stringify({
|
|
mcpServers: {
|
|
rea: {
|
|
command: "npx",
|
|
args: ["-y", PRODUCT_IDENTITY.registrationPackageSpecifier, "mcp"],
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
const host = systemDoctorHost({
|
|
environment: {
|
|
HOME: home,
|
|
USERPROFILE: home,
|
|
CLAUDE_CONFIG_DIR: configDirectory,
|
|
},
|
|
});
|
|
|
|
expect(
|
|
await canonicalSkillNeedsInstall(home, ["claude_code"], {
|
|
CLAUDE_CONFIG_DIR: dirname(skillsDirectory),
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
await installCanonicalSkill(home, ["claude_code"], {
|
|
CLAUDE_CONFIG_DIR: dirname(skillsDirectory),
|
|
}),
|
|
).toMatchObject({ ok: true, value: "installed" });
|
|
expect(
|
|
await canonicalSkillNeedsInstall(home, ["claude_code"], {
|
|
CLAUDE_CONFIG_DIR: dirname(skillsDirectory),
|
|
}),
|
|
).toBe(false);
|
|
await expect(access(claudeSkill)).resolves.toBeUndefined();
|
|
await expect(
|
|
access(join(home, ".agents/skills/reverse-engineer-anything")),
|
|
).rejects.toMatchObject({ code: "ENOENT" });
|
|
expect(
|
|
(
|
|
await runDoctor(undefined, host, {
|
|
clients: ["claude_code"],
|
|
skill: true,
|
|
})
|
|
).identity?.skill.state,
|
|
).toBe("aligned");
|
|
});
|
|
|
|
it("checks selected skill locations for independent drift", async () => {
|
|
const home = await createTestTempDirectory("rea-mixed-skill-");
|
|
const sharedSkill = join(
|
|
home,
|
|
".agents/skills/reverse-engineer-anything/SKILL.md",
|
|
);
|
|
const claudeSkills = join(home, ".claude", "skills");
|
|
const claudeSkill = join(
|
|
claudeSkills,
|
|
"reverse-engineer-anything/SKILL.md",
|
|
);
|
|
const host = systemDoctorHost({
|
|
environment: { HOME: home, USERPROFILE: home },
|
|
});
|
|
const doctorScope = { clients: ["claude_code", "codex"], skill: true };
|
|
|
|
expect(
|
|
await installCanonicalSkill(home, ["claude_code", "codex"]),
|
|
).toMatchObject({ ok: true, value: "installed" });
|
|
await rm(sharedSkill);
|
|
expect(
|
|
(await runDoctor(undefined, host, doctorScope)).identity?.skill.state,
|
|
).toBe("stale");
|
|
expect(
|
|
await installCanonicalSkill(home, ["claude_code", "codex"]),
|
|
).toMatchObject({ ok: true, value: "installed" });
|
|
for (const skill of [sharedSkill, claudeSkill]) {
|
|
await writeFile(skill, "selected copy changed\n");
|
|
expect(
|
|
(await runDoctor(undefined, host, doctorScope)).identity?.skill.state,
|
|
).toBe("stale");
|
|
expect(
|
|
await installCanonicalSkill(home, ["claude_code", "codex"]),
|
|
).toMatchObject({ ok: true, value: "installed" });
|
|
expect(
|
|
(await runDoctor(undefined, host, doctorScope)).identity?.skill.state,
|
|
).toBe("aligned");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("canonical skill transaction", () => {
|
|
it("backs up and upgrades a stale managed skill without touching siblings", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-test-");
|
|
const destination = join(
|
|
home,
|
|
".agents/skills/reverse-engineer-anything/SKILL.md",
|
|
);
|
|
const sibling = join(home, ".agents/skills/unrelated/SKILL.md");
|
|
const nativeGuide = join(
|
|
dirname(destination),
|
|
"references/native-and-artifacts.md",
|
|
);
|
|
await mkdir(dirname(destination), { recursive: true });
|
|
await mkdir(dirname(nativeGuide), { recursive: true });
|
|
await mkdir(dirname(sibling), { recursive: true });
|
|
await writeFile(destination, "stale managed skill\n", { mode: 0o640 });
|
|
await writeFile(nativeGuide, "stale filesystem-write permission grant\n");
|
|
await writeFile(sibling, "unrelated skill\n");
|
|
|
|
expect(await canonicalSkillNeedsInstall(home)).toBe(true);
|
|
expect(await installCanonicalSkill(home)).toMatchObject({
|
|
ok: true,
|
|
value: "installed",
|
|
});
|
|
expect(await readFile(`${destination}.rea.backup`, "utf8")).toBe(
|
|
"stale managed skill\n",
|
|
);
|
|
const installedSkill = await readFile(destination, "utf8");
|
|
expect(installedSkill).toBe(
|
|
await readFile(
|
|
new URL(
|
|
"../../../skills/reverse-engineer-anything/SKILL.md",
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
),
|
|
);
|
|
expect(installedSkill).toContain(
|
|
`version: "${PRODUCT_IDENTITY.skillVersion}"`,
|
|
);
|
|
await expectPermissionMode(destination, 0o640);
|
|
expect(await readFile(`${nativeGuide}.rea.backup`, "utf8")).toBe(
|
|
"stale filesystem-write permission grant\n",
|
|
);
|
|
for (const reference of [
|
|
"connection-and-recovery.md",
|
|
"native-and-artifacts.md",
|
|
"javascript-applications.md",
|
|
"android-applications.md",
|
|
"runtime-observation.md",
|
|
"evidence-workflows.md",
|
|
]) {
|
|
const installed = await readFile(
|
|
join(dirname(destination), "references", reference),
|
|
"utf8",
|
|
);
|
|
expect(installed).toBe(
|
|
await readFile(
|
|
new URL(
|
|
`../../../skills/reverse-engineer-anything/references/${reference}`,
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
),
|
|
);
|
|
expect(installed).not.toMatch(
|
|
/filesystem-write permission grant|native_mount_approved|only with explicit approval|Obtain the per-call/u,
|
|
);
|
|
}
|
|
expect(installedSkill).toContain(
|
|
"use normal repository tools and do not run REA",
|
|
);
|
|
expect(installedSkill).toContain(
|
|
`tool_count: ${String(TOOL_CONTRACTS.length)}`,
|
|
);
|
|
expect(await readFile(sibling, "utf8")).toBe("unrelated skill\n");
|
|
expect(
|
|
await readFile(
|
|
join(
|
|
home,
|
|
".agents/skills/reverse-engineer-anything/references/javascript-applications.md",
|
|
),
|
|
"utf8",
|
|
),
|
|
).toContain("analyze_javascript_application");
|
|
expect(await canonicalSkillNeedsInstall(home)).toBe(false);
|
|
expect(await installCanonicalSkill(home)).toMatchObject({
|
|
ok: true,
|
|
value: "unchanged",
|
|
});
|
|
expect(await skillReferenceIssues(dirname(destination))).toEqual([]);
|
|
});
|
|
|
|
it("binds portable conformance to the generated skill bytes that setup installs", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-commitment-");
|
|
expect(await installCanonicalSkill(home)).toMatchObject({
|
|
ok: true,
|
|
value: "installed",
|
|
});
|
|
const paths = [
|
|
"SKILL.md",
|
|
"references/android-applications.md",
|
|
"references/connection-and-recovery.md",
|
|
"references/environments.md",
|
|
"references/evidence-workflows.md",
|
|
"references/javascript-applications.md",
|
|
"references/native-and-artifacts.md",
|
|
"references/runtime-observation.md",
|
|
];
|
|
const records = await Promise.all(
|
|
paths.map(async (path) => {
|
|
const bytes = await readFile(
|
|
join(home, ".agents/skills/reverse-engineer-anything", path),
|
|
);
|
|
return `${path}\0${createHash("sha256").update(bytes).digest("hex")}\n`;
|
|
}),
|
|
);
|
|
const manifest = z
|
|
.object({
|
|
skill_digests: z.array(
|
|
z.object({ skill_id: z.string(), sha256: z.string() }),
|
|
),
|
|
})
|
|
.parse(
|
|
JSON.parse(
|
|
await readFile(
|
|
"docs/verification/managed-conformance-manifest.json",
|
|
"utf8",
|
|
),
|
|
),
|
|
);
|
|
expect(manifest.skill_digests).toContainEqual({
|
|
skill_id: "reverse-engineer-anything",
|
|
sha256: createHash("sha256").update(records.join("")).digest("hex"),
|
|
});
|
|
});
|
|
});
|
|
|
|
it("doctor verifies installed instructions and references even when metadata is current", async () => {
|
|
const home = await createTestTempDirectory("rea-skill-doctor-");
|
|
const destination = join(
|
|
home,
|
|
".agents/skills/reverse-engineer-anything/SKILL.md",
|
|
);
|
|
const reference = join(
|
|
dirname(destination),
|
|
"references/evidence-workflows.md",
|
|
);
|
|
const system = systemDoctorHost({
|
|
environment: { HOME: home, USERPROFILE: home },
|
|
});
|
|
const host = createDoctorHostFixture({
|
|
installedSkillIdentity: (registrations) =>
|
|
system.installedSkillIdentity?.(registrations) ??
|
|
Promise.resolve(undefined),
|
|
});
|
|
expect((await runDoctor(undefined, host)).identity?.skill.state).toBe(
|
|
"missing",
|
|
);
|
|
expect(await installCanonicalSkill(home)).toMatchObject({
|
|
ok: true,
|
|
value: "installed",
|
|
});
|
|
expect((await runDoctor(undefined, host)).identity?.skill).toMatchObject({
|
|
state: "aligned",
|
|
});
|
|
for (const [path, remove] of [
|
|
[destination, false],
|
|
[reference, false],
|
|
[reference, true],
|
|
] as const) {
|
|
if (remove) await rm(path);
|
|
else await writeFile(path, "Locally changed instructions.\n");
|
|
expect((await runDoctor(undefined, host)).identity?.skill.state).toBe(
|
|
"stale",
|
|
);
|
|
expect(await installCanonicalSkill(home)).toMatchObject({
|
|
ok: true,
|
|
value: "installed",
|
|
});
|
|
expect((await runDoctor(undefined, host)).identity?.skill.state).toBe(
|
|
"aligned",
|
|
);
|
|
}
|
|
});
|