import test from "node:test"; import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { existsSync, readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const pkg = JSON.parse(readFileSync(resolve(packageRoot, "package.json"), "utf8")); function getPackedPaths() { const output = execFileSync("npm", ["pack", "--dry-run", "--json"], { cwd: packageRoot, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 30_000, }); const [packResult] = JSON.parse(output) as Array<{ files: Array<{ path: string }> }>; return packResult.files.map((file) => file.path); } test("package.json exposes pi-subagents as a standalone pi package", () => { assert.equal(pkg.name, "pi-subagents"); assert.equal(pkg.type, "module"); assert.ok(Array.isArray(pkg.keywords)); assert.ok(pkg.keywords.includes("pi-package")); assert.deepEqual(pkg.pi, { extensions: ["./index.ts"], prompts: ["./prompts/*.md"], }); assert.equal(pkg.peerDependencies["@mariozechner/pi-ai"], "*"); assert.equal(pkg.peerDependencies["@mariozechner/pi-coding-agent"], "*"); assert.equal(pkg.peerDependencies["@mariozechner/pi-tui"], "*"); assert.equal(pkg.peerDependencies["@sinclair/typebox"], "*"); assert.deepEqual(pkg.dependencies ?? {}, {}); assert.equal(pkg.bundledDependencies, undefined); assert.deepEqual(pkg.files, ["index.ts", "src", "prompts"]); assert.ok(existsSync(resolve(packageRoot, "index.ts"))); assert.ok(existsSync(resolve(packageRoot, "src/wrapper/cli.mjs"))); assert.ok(existsSync(resolve(packageRoot, "prompts/implement.md"))); assert.ok(existsSync(resolve(packageRoot, "prompts/implement-and-review.md"))); assert.ok(existsSync(resolve(packageRoot, "prompts/scout-and-plan.md"))); }); test("README documents local install, git install, and tmux PATH requirement", () => { const readme = readFileSync(resolve(packageRoot, "README.md"), "utf8"); assert.match(readme, /pi install \/absolute\/path\/to\/subagents/); assert.match(readme, /pi install https:\/\/gitea\.rwiesner\.com\/pi\/pi-subagents/); assert.match(readme, /generic subagent/i); assert.doesNotMatch(readme, /specialized built-in roles/i); assert.doesNotMatch(readme, /markdown agent discovery/i); assert.match(readme, /tmux.*PATH/i); }); test("npm pack includes runtime package assets", () => { const packedPaths = getPackedPaths(); assert.ok(packedPaths.includes("index.ts")); assert.ok(packedPaths.includes("prompts/implement.md")); assert.ok(packedPaths.includes("prompts/implement-and-review.md")); assert.ok(packedPaths.includes("prompts/scout-and-plan.md")); assert.ok(packedPaths.includes("src/wrapper/cli.mjs")); assert.deepEqual(packedPaths.filter((p) => p.endsWith(".test.ts")), []); });