clanker-agent/packages/coding-agent/test/package-command-paths.test.ts
Harivansh Rathi 536241053c refactor: finish companion rename migration
Complete the remaining pi-to-companion rename across companion-os, web, vm-orchestrator, docker, and archived fixtures.

Verification:
- semantic rg sweeps for Pi/piConfig/getPi/.pi runtime references
- npm run check in apps/companion-os (fails in this worktree: biome not found)

Co-authored-by: Codex <noreply@openai.com>
2026-03-10 07:39:32 -05:00

137 lines
4.6 KiB
TypeScript

import { mkdirSync, readFileSync, realpathSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ENV_AGENT_DIR } from "../src/config.js";
import { main } from "../src/main.js";
describe("package commands", () => {
let tempDir: string;
let agentDir: string;
let projectDir: string;
let packageDir: string;
let originalCwd: string;
let originalAgentDir: string | undefined;
let originalExitCode: typeof process.exitCode;
beforeEach(() => {
tempDir = join(
tmpdir(),
`companion-package-commands-${Date.now()}-${Math.random().toString(36).slice(2)}`,
);
agentDir = join(tempDir, "agent");
projectDir = join(tempDir, "project");
packageDir = join(tempDir, "local-package");
mkdirSync(agentDir, { recursive: true });
mkdirSync(projectDir, { recursive: true });
mkdirSync(packageDir, { recursive: true });
originalCwd = process.cwd();
originalAgentDir = process.env[ENV_AGENT_DIR];
originalExitCode = process.exitCode;
process.exitCode = undefined;
process.env[ENV_AGENT_DIR] = agentDir;
process.chdir(projectDir);
});
afterEach(() => {
process.chdir(originalCwd);
process.exitCode = originalExitCode;
if (originalAgentDir === undefined) {
delete process.env[ENV_AGENT_DIR];
} else {
process.env[ENV_AGENT_DIR] = originalAgentDir;
}
rmSync(tempDir, { recursive: true, force: true });
});
it("should persist global relative local package paths relative to settings.json", async () => {
const relativePkgDir = join(projectDir, "packages", "local-package");
mkdirSync(relativePkgDir, { recursive: true });
await main(["install", "./packages/local-package"]);
const settingsPath = join(agentDir, "settings.json");
const settings = JSON.parse(readFileSync(settingsPath, "utf-8")) as {
packages?: string[];
};
expect(settings.packages?.length).toBe(1);
const stored = settings.packages?.[0] ?? "";
const resolvedFromSettings = realpathSync(join(agentDir, stored));
expect(resolvedFromSettings).toBe(realpathSync(relativePkgDir));
});
it("should remove local packages using a path with a trailing slash", async () => {
await main(["install", `${packageDir}/`]);
const settingsPath = join(agentDir, "settings.json");
const installedSettings = JSON.parse(
readFileSync(settingsPath, "utf-8"),
) as { packages?: string[] };
expect(installedSettings.packages?.length).toBe(1);
await main(["remove", `${packageDir}/`]);
const removedSettings = JSON.parse(readFileSync(settingsPath, "utf-8")) as {
packages?: string[];
};
expect(removedSettings.packages ?? []).toHaveLength(0);
});
it("shows install subcommand help", async () => {
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
try {
await expect(main(["install", "--help"])).resolves.toBeUndefined();
const stdout = logSpy.mock.calls
.map(([message]) => String(message))
.join("\n");
expect(stdout).toContain("Usage:");
expect(stdout).toContain("companion install <source> [-l]");
expect(errorSpy).not.toHaveBeenCalled();
expect(process.exitCode).toBeUndefined();
} finally {
logSpy.mockRestore();
errorSpy.mockRestore();
}
});
it("shows a friendly error for unknown install options", async () => {
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
try {
await expect(main(["install", "--unknown"])).resolves.toBeUndefined();
const stderr = errorSpy.mock.calls
.map(([message]) => String(message))
.join("\n");
expect(stderr).toContain('Unknown option --unknown for "install".');
expect(stderr).toContain(
'Use "companion --help" or "companion install <source> [-l]".',
);
expect(process.exitCode).toBe(1);
} finally {
errorSpy.mockRestore();
}
});
it("shows a friendly error for missing install source", async () => {
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
try {
await expect(main(["install"])).resolves.toBeUndefined();
const stderr = errorSpy.mock.calls
.map(([message]) => String(message))
.join("\n");
expect(stderr).toContain("Missing install source.");
expect(stderr).toContain("Usage: companion install <source> [-l]");
expect(stderr).not.toContain("at ");
expect(process.exitCode).toBe(1);
} finally {
errorSpy.mockRestore();
}
});
});