import assert from "node:assert/strict"; import { readdirSync, readFileSync } from "node:fs"; import { test } from "node:test"; // Installed packages get no copy of pi in node_modules (pi is a peer // dependency). pi maps only these specifiers to its own modules when loading // an extension; see "Available Imports" in pi's docs/extensions.md. const HOST_PROVIDED = new Set([ "@earendil-works/pi-coding-agent", "@earendil-works/pi-agent-core", "@earendil-works/pi-tui", "@earendil-works/pi-ai", "@earendil-works/pi-ai/compat", "@earendil-works/pi-ai/models", "@earendil-works/pi-ai/oauth", "@earendil-works/pi-ai/providers/all", "typebox", "typebox/compile", "typebox/value", ]); test("runtime source imports only modules that pi provides to extensions", () => { const sourceDir = new URL("../src/", import.meta.url); for (const file of readdirSync(sourceDir).filter((name) => name.endsWith(".ts"))) { const source = readFileSync(new URL(file, sourceDir), "utf8"); for (const [, specifier] of source.matchAll(/^\s*import\s[^;]*?from\s+"([^"]+)"/gms)) { if (specifier.startsWith(".") || specifier.startsWith("node:")) continue; assert.ok(HOST_PROVIDED.has(specifier), `src/${file} imports "${specifier}", which pi does not provide to installed extensions`); } } });