feat(FN-2135): merge fusion/fn-2135

This commit is contained in:
gsxdsm
2026-04-19 04:37:38 -07:00
parent a10e4c2dfe
commit bde0370d03
2 changed files with 29 additions and 40 deletions

View File

@@ -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 () => {

View File

@@ -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> {