repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
.pi/skills/modernize/scripts/audit.test.mjs
Rawimport assert from "node:assert/strict";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import test from "node:test";
import { checkedSpawn } from "./audit.bench.mjs";
import {
assertLatest,
collectPackageVersions,
compareVersions,
createReport,
extractCandidates,
extractCapabilities,
parseChangelog,
resolvePiInstallation,
} from "./audit.mjs";
const changelog = `# Changelog
## [2.0.0] - 2026-07-13
### Added
- Added harmless sparkle output.
### Changed
- Renamed \`oldCall()\` to \`newCall()\`.
### Fixed
- Removed the obsolete \`legacyOption\` request field.
- Fixed ordinary rendering noise.
## [1.5.0] - 2026-07-01
### Breaking Changes
- Replace \`alpha()\` with \`beta()\`.
## [1.0.0] - 2026-06-01
### Added
- Initial release.
`;
test("parses release sections newest first", () => {
assert.deepEqual(
parseChangelog(changelog).map(({ version }) => version),
["2.0.0", "1.5.0", "1.0.0"],
);
});
test("extracts migration sections and keyword bullets in the version interval", () => {
assert.deepEqual(
extractCandidates(changelog, {
afterVersion: "1.5.0",
throughVersion: "2.0.0",
}).map(({ section, text }) => [section, text]),
[
["Changed", "Renamed `oldCall()` to `newCall()`."],
["Fixed", "Removed the obsolete `legacyOption` request field."],
],
);
});
const capabilitiesChangelog = `# Changelog
## [1.2.0]
### Added
- Added a future capability.
## [1.1.0]
### New Features
- Program status reporting through OSC 7501: working, blocked, done, or failed.
### Added
- Added \`+name\` and \`-name\` entries to \`--tools\`.
### Changed
- Status reports never contain prompts or model output; desktop notifications remain separate.
### Fixed
- Fixed ordinary rendering noise.
## [1.0.4]
### Fixed
- Fixed system prompt rules naming hidden tools; \`BuildSystemPromptOptions\` gains \`hiddenTools\`.
## [1.0.2]
### Added
- Added \`samplingParamsByThinkingLevel\`.
## [1.0.1]
### Added
- Added an older capability.
`;
test("collects native features and Fixed API additions without migration keywords", () => {
const capabilities = extractCapabilities(capabilitiesChangelog, {
afterVersion: "1.0.2",
throughVersion: "1.1.0",
});
assert.deepEqual(
capabilities.map(({ section }) => section),
["New Features", "Added", "Changed", "Fixed", "Fixed", "Added"],
);
for (const shape of [
"OSC 7501",
"+name",
"hiddenTools",
"samplingParamsByThinkingLevel",
])
assert.ok(
capabilities.some(({ text }) => text.includes(shape)),
shape,
);
assert.ok(
capabilities.some(({ text }) => text.includes("ordinary rendering noise")),
);
});
test("includes the repository-resolved release but excludes older and future capabilities", () => {
const capabilities = extractCapabilities(capabilitiesChangelog, {
afterVersion: "1.0.2",
throughVersion: "1.1.0",
});
assert.deepEqual(
[...new Set(capabilities.map(({ version }) => version))],
["1.1.0", "1.0.4", "1.0.2"],
);
assert.deepEqual(
extractCapabilities(capabilitiesChangelog, {
afterVersion: "1.1.0",
throughVersion: "1.1.0",
}).map(({ section }) => section),
["New Features", "Added", "Changed", "Fixed"],
);
});
test("keeps partial-replacement evidence despite observable behavior differences", () => {
const capabilities = extractCapabilities(capabilitiesChangelog, {
afterVersion: "1.0.2",
throughVersion: "1.1.0",
});
assert.ok(
capabilities.some(({ text }) =>
text.includes("desktop notifications remain separate"),
),
);
});
test("rejects changelogs without release sections", () => {
assert.throws(() => parseChangelog("# Changelog\n\nNothing yet."), /release/);
});
test("compares semantic versions numerically", () => {
assert.equal(compareVersions("0.80.10", "0.80.6"), 1);
assert.equal(compareVersions("0.80.6", "0.80.6"), 0);
assert.equal(compareVersions("0.79.9", "0.80.1"), -1);
});
test("fails when installed Pi is not latest", () => {
assert.doesNotThrow(() => assertLatest("0.80.6", "0.80.6"));
assert.throws(() => assertLatest("0.80.5", "0.80.6"), /not latest/);
});
test("resolves the installed Pi package from launcher and CLI paths", (context) => {
const directory = mkdtempSync(path.join(tmpdir(), "pi-modernize-"));
context.after(() => rmSync(directory, { recursive: true, force: true }));
const packageRoot = path.join(
directory,
"node_modules",
"@earendil-works",
"pi-coding-agent",
);
const cli = path.join(packageRoot, "dist", "cli.js");
const changelog = path.join(packageRoot, "CHANGELOG.md");
const launcher = path.join(directory, "pi.CMD");
mkdirSync(path.dirname(cli), { recursive: true });
writeFileSync(
path.join(packageRoot, "package.json"),
JSON.stringify({
name: "@earendil-works/pi-coding-agent",
version: "0.85.0",
bin: { pi: "dist/cli.js" },
}),
);
writeFileSync(cli, "");
writeFileSync(changelog, "");
writeFileSync(launcher, "");
const expected = { cli, changelog, version: "0.85.0" };
assert.deepEqual(resolvePiInstallation(launcher, ""), expected);
assert.deepEqual(resolvePiInstallation(cli, ""), expected);
});
test("fails when no installed Pi package is near the launcher", (context) => {
const directory = mkdtempSync(path.join(tmpdir(), "pi-modernize-"));
context.after(() => rmSync(directory, { recursive: true, force: true }));
const launcher = path.join(directory, "pi");
writeFileSync(launcher, "");
assert.throws(
() => resolvePiInstallation(launcher, ""),
/installed @earendil-works\/pi-coding-agent package not found/,
);
});
function managedInstallation(context) {
const directory = mkdtempSync(path.join(tmpdir(), "pi-modernize-"));
context.after(() => rmSync(directory, { recursive: true, force: true }));
const installRoot = path.join(directory, "install");
const launcher = path.join(directory, "bin", "pi.CMD");
const packageRoot = path.join(
installRoot,
"releases",
"0.85.0",
"node_modules",
"@earendil-works",
"pi-coding-agent",
);
const cli = path.join(packageRoot, "dist", "cli.js");
const changelog = path.join(packageRoot, "CHANGELOG.md");
mkdirSync(path.dirname(launcher), { recursive: true });
mkdirSync(path.dirname(cli), { recursive: true });
writeFileSync(launcher, "");
writeFileSync(path.join(installRoot, "current-version"), "0.85.0\n");
writeFileSync(
path.join(packageRoot, "package.json"),
JSON.stringify({
name: "@earendil-works/pi-coding-agent",
version: "0.85.0",
bin: { pi: "dist/cli.js" },
}),
);
writeFileSync(cli, "");
writeFileSync(changelog, "");
return {
installRoot,
launcher,
packageRoot,
expected: { cli, changelog, version: "0.85.0" },
};
}
test("resolves the selected managed release from the launcher layout", (context) => {
const { launcher, expected } = managedInstallation(context);
assert.deepEqual(resolvePiInstallation(launcher, ""), expected);
});
test("explicit managed root takes precedence over executable proximity", (context) => {
const { installRoot, expected } = managedInstallation(context);
assert.deepEqual(
resolvePiInstallation(process.execPath, installRoot),
expected,
);
});
test("rejects invalid managed version pointers without falling back", (context) => {
const { installRoot, launcher } = managedInstallation(context);
for (const version of ["", ".", "..", "../outside", "a/b", "a\\b"]) {
writeFileSync(path.join(installRoot, "current-version"), version);
assert.throws(
() => resolvePiInstallation(launcher, installRoot),
/version file is invalid/,
);
}
});
test("fails for missing managed pointers and releases", (context) => {
const { installRoot, launcher } = managedInstallation(context);
writeFileSync(path.join(installRoot, "current-version"), "0.86.0");
assert.throws(
() => resolvePiInstallation(launcher, installRoot),
/package not found in managed release/,
);
rmSync(path.join(installRoot, "current-version"));
assert.throws(() => resolvePiInstallation(launcher, installRoot), /ENOENT/);
});
test("rejects managed release metadata mismatching the pointer", (context) => {
const { installRoot, launcher, packageRoot } = managedInstallation(context);
writeFileSync(
path.join(packageRoot, "package.json"),
JSON.stringify({
name: "@earendil-works/pi-coding-agent",
version: "0.84.0",
}),
);
assert.throws(
() => resolvePiInstallation(launcher, installRoot),
/does not match package version/,
);
});
test("reports inherited-stdio child failures by exit code", () => {
assert.throws(
() =>
checkedSpawn(process.execPath, ["-e", "process.exit(7)"], {
stdio: "inherit",
}),
/exited with code 7/,
);
});
test("collects resolved earendil Pi package versions", () => {
assert.deepEqual(
collectPackageVersions({
packages: {
"node_modules/@earendil-works/pi-ai": { version: "0.80.4" },
"extensions/x/node_modules/@earendil-works/pi-ai": {
version: "0.80.4",
},
"node_modules/@earendil-works/pi-coding-agent": {
version: "0.80.6",
},
"node_modules/@earendil-works/pi-coding-agent/node_modules/partial-json":
{
version: "0.1.7",
},
"node_modules/vitest": { version: "4.1.9" },
},
}),
[
{ name: "@earendil-works/pi-ai", version: "0.80.4" },
{ name: "@earendil-works/pi-coding-agent", version: "0.80.6" },
],
);
});
test("reports only evidence needed before tool-driven inspection", () => {
assert.deepEqual(
createReport({
piVersion: "2.0.0",
candidatesAfterVersion: "1.5.0",
localChangelogPath: "/pi/CHANGELOG.md",
remoteChangelogUrl: "https://example.test/CHANGELOG.md",
candidates: [{ version: "2.0.0", text: "Replace alpha." }],
capabilities: [{ version: "1.5.0", text: "Added native status." }],
}),
{
schemaVersion: 3,
status: "ok",
piVersion: "2.0.0",
candidatesAfterVersion: "1.5.0",
changelogs: {
installed: "/pi/CHANGELOG.md",
remote: "https://example.test/CHANGELOG.md",
},
candidates: [{ version: "2.0.0", text: "Replace alpha." }],
capabilities: [{ version: "1.5.0", text: "Added native status." }],
},
);
});