feat(FN-2135): merge fusion/fn-2135
This commit is contained in:
@@ -436,15 +436,36 @@ name: Archive CEO
|
||||
expect(pkg.agents[0]?.name).toBe("Archive CEO");
|
||||
});
|
||||
|
||||
it("throws AgentCompaniesParseError for a corrupt .tar.gz file", async () => {
|
||||
it("throws descriptive error when tar extraction fails", async () => {
|
||||
const root = createTempDir();
|
||||
const archivePath = join(root, "corrupt.tgz");
|
||||
writeTextFile(archivePath, "not a real gzip archive");
|
||||
writeFileSync(archivePath, Buffer.from("not-a-real-gzip"));
|
||||
|
||||
await expect(parseCompanyArchive(archivePath)).rejects.toBeInstanceOf(AgentCompaniesParseError);
|
||||
await expect(parseCompanyArchive(archivePath)).rejects.toThrow(
|
||||
"Failed to parse Agent Companies archive",
|
||||
);
|
||||
await expect(parseCompanyArchive(archivePath)).rejects.toMatchObject({
|
||||
name: "AgentCompaniesParseError",
|
||||
message: expect.stringContaining("Failed to parse Agent Companies archive"),
|
||||
});
|
||||
});
|
||||
|
||||
it("parses a .tar.gz archive with nested directory structure", async () => {
|
||||
const root = createTempDir();
|
||||
const topLevelDir = join(root, "outer-layer");
|
||||
const packageDir = join(topLevelDir, "company-package");
|
||||
|
||||
writeTextFile(join(packageDir, "COMPANY.md"), `---
|
||||
name: Nested Archive Company
|
||||
schema: agentcompanies/v1
|
||||
---`);
|
||||
writeTextFile(join(packageDir, "agents", "ceo", "AGENTS.md"), `---
|
||||
name: Nested Archive CEO
|
||||
---`);
|
||||
|
||||
const archivePath = join(root, "nested-company.tgz");
|
||||
execSync(`tar czf ${JSON.stringify(archivePath)} -C ${JSON.stringify(root)} outer-layer`);
|
||||
|
||||
const pkg = await parseCompanyArchive(archivePath);
|
||||
expect(pkg.company?.name).toBe("Nested Archive Company");
|
||||
expect(pkg.agents[0]?.name).toBe("Nested Archive CEO");
|
||||
});
|
||||
|
||||
it("throws AgentCompaniesParseError for a non-existent .tar.gz file", async () => {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
@@ -24,14 +23,6 @@ import type {
|
||||
} from "./agent-companies-types.js";
|
||||
import type { AgentCapability, AgentCreateInput } from "./types.js";
|
||||
|
||||
type TarExtractOptions = {
|
||||
file: string;
|
||||
cwd: string;
|
||||
};
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
let optionalTarExtract: ((options: TarExtractOptions) => Promise<void>) | null | undefined;
|
||||
|
||||
export class AgentCompaniesParseError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
@@ -482,42 +473,19 @@ function resolveExtractionRoot(tempDir: string): string {
|
||||
}
|
||||
|
||||
if (directories.length === 1) {
|
||||
return join(tempDir, directories[0].name);
|
||||
return resolveExtractionRoot(join(tempDir, directories[0].name));
|
||||
}
|
||||
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
function getOptionalTarExtract(): ((options: TarExtractOptions) => Promise<void>) | null {
|
||||
if (optionalTarExtract !== undefined) {
|
||||
return optionalTarExtract;
|
||||
}
|
||||
|
||||
try {
|
||||
const candidate = require("tar") as {
|
||||
x?: (options: TarExtractOptions) => Promise<void>;
|
||||
};
|
||||
optionalTarExtract = typeof candidate.x === "function" ? candidate.x : null;
|
||||
} catch {
|
||||
optionalTarExtract = null;
|
||||
}
|
||||
|
||||
return optionalTarExtract;
|
||||
}
|
||||
|
||||
async function extractTarArchive(archivePath: string, outputDir: string): Promise<void> {
|
||||
const tarExtract = getOptionalTarExtract();
|
||||
if (tarExtract) {
|
||||
await tarExtract({ file: archivePath, cwd: outputDir });
|
||||
return;
|
||||
}
|
||||
|
||||
const [{ execFile }, { promisify }] = await Promise.all([
|
||||
import("node:child_process"),
|
||||
import("node:util"),
|
||||
]);
|
||||
const execFileAsync = promisify(execFile);
|
||||
await execFileAsync("tar", ["-xzf", archivePath, "-C", outputDir]);
|
||||
await execFileAsync("tar", ["xzf", archivePath, "-C", outputDir]);
|
||||
}
|
||||
|
||||
export async function parseCompanyArchive(archivePath: string): Promise<AgentCompaniesPackage> {
|
||||
|
||||
Reference in New Issue
Block a user