Something went wrong. Try again.
fork of prime agent with changes i want but are not upstreamable probqbly (and some fixes)
Something went wrong. Try again.
3.8 kB · 116 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117import { chmodSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";import { join } from "node:path";import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const toolState = vi.hoisted(() => ({ toolsDir: `/tmp/prime-agent-tools-manager-${process.pid}`, platform: "linux", architecture: "x64", extractZip: async (_source: string, _options: { dir: string }): Promise<void> => {},}));
vi.mock("../src/config.js", () => ({ APP_NAME: "prime-agent", getBinDir: () => toolState.toolsDir,}));
vi.mock("os", () => ({ arch: () => toolState.architecture, platform: () => toolState.platform,}));
vi.mock("extract-zip", () => ({ default: (source: string, options: { dir: string }) => toolState.extractZip(source, options),}));
import { clearResolvedToolPaths, ensureToolWithStatus, getToolPath } from "../src/utils/tools-manager.js";
const originalPath = process.env.PATH;const pathDir = join(toolState.toolsDir, "path");
function writeExecutable(filePath: string, exitCode = 0): void { writeFileSync(filePath, `#!/bin/sh\nexit ${exitCode}\n`, "utf8"); chmodSync(filePath, 0o755);}
describe("tools manager", () => { beforeEach(() => { clearResolvedToolPaths(); rmSync(toolState.toolsDir, { recursive: true, force: true }); mkdirSync(pathDir, { recursive: true }); process.env.PATH = pathDir; delete process.env.PI_OFFLINE; toolState.platform = "linux"; toolState.architecture = "x64"; toolState.extractZip = async () => {}; });
afterEach(() => { vi.unstubAllGlobals(); if (originalPath === undefined) delete process.env.PATH; else process.env.PATH = originalPath; rmSync(toolState.toolsDir, { recursive: true, force: true }); });
it("accepts managed and PATH tools only when their version check succeeds", () => { const managedPath = join(toolState.toolsDir, "rg"); writeExecutable(managedPath); expect(getToolPath("rg")).toBe(managedPath);
clearResolvedToolPaths(); writeExecutable(managedPath, 1); const pathBinary = join(pathDir, "rg"); writeExecutable(pathBinary); expect(getToolPath("rg")).toBe("rg");
clearResolvedToolPaths(); writeExecutable(pathBinary, 1); expect(getToolPath("rg")).toBeNull(); });
it("reuses a resolved path until cleared and never caches a miss", () => { const managedPath = join(toolState.toolsDir, "rg"); writeExecutable(managedPath); expect(getToolPath("rg")).toBe(managedPath);
writeExecutable(managedPath, 1); expect(getToolPath("rg")).toBe(managedPath);
clearResolvedToolPaths(); expect(getToolPath("rg")).toBeNull();
writeExecutable(managedPath); expect(getToolPath("rg")).toBe(managedPath); });
it.each([ ["reports a downloaded binary that passes its version check", 0, { status: "available" }, true], [ "removes a downloaded binary that fails its version check", 1, { status: "unavailable", reason: "download_failed" }, false, ], ])("%s", async (_label, extractedExitCode, expected, kept) => { toolState.platform = "win32"; // A stale binary from an earlier run must not short-circuit the download. writeExecutable(join(toolState.toolsDir, "rg.exe"), 1); const fetchMock = vi .fn() .mockResolvedValueOnce( new Response(JSON.stringify({ tag_name: "15.1.0" }), { status: 200, headers: { "Content-Type": "application/json" }, }), ) .mockResolvedValueOnce(new Response(new Uint8Array([1]), { status: 200 })); vi.stubGlobal("fetch", fetchMock); toolState.extractZip = async (_source, options) => { writeExecutable(join(options.dir, "rg.exe"), extractedExitCode); };
await expect(ensureToolWithStatus("rg")).resolves.toMatchObject(expected); expect(fetchMock).toHaveBeenCalledTimes(2); expect(existsSync(join(toolState.toolsDir, "rg.exe"))).toBe(kept); });});