pi resolves only a fixed set of its own module paths for installed extensions; pi-ai/api/* is not among them. Add a test that keeps runtime imports within that set.
31 lines
1.3 KiB
TypeScript
31 lines
1.3 KiB
TypeScript
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`);
|
|
}
|
|
}
|
|
});
|