Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

.pi/skills/modernize/scripts/audit.test.mjs

Raw
import 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,
	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."],
		],
	);
});

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/,
	);
});

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." }],
		}),
		{
			schemaVersion: 2,
			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." }],
		},
	);
});