mirror of
https://github.com/hanzoai/frames.git
synced 2026-08-07 18:08:30 +00:00
Forked from HyperFrames (Apache-2.0), full history preserved. Hosts are mapped explicitly and BEFORE the identifier rename, because hyperframes.heygen.com is not decoration: 175 of its occurrences are $schema identifiers that a validator dereferences. A blind rename would have left them naming a host that never serves them. The schema files are in this repo under docs/schema, so the mapped host is one we can actually serve -- that is the condition that makes the rewrite safe, and serving them is a deploy task, not an edit. docs/schema/hyperframes.json is renamed to frames.json to match the identifier it is now published under. api.heygen.com and the CLI auth against heygen.com are left UNRENAMED on purpose. They are a dependency on HeyGen's SaaS, not a name of ours to take, and the right move is to remove that integration rather than rebrand it. LICENSE and CREDITS.md are untouched; NOTICE records the lineage. Co-authored-by: Hanzo Dev <dev@hanzo.ai>
68 lines
2.0 KiB
JavaScript
68 lines
2.0 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
import { mkdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const REPO_ROOT = join(import.meta.dirname, "..");
|
|
const OUTPUT = join(REPO_ROOT, "dist", "frames-plugin.zip");
|
|
// Codex reports its upload limit in decimal MB.
|
|
const MAX_UPLOAD_BYTES = 100 * 1_000_000;
|
|
const pluginManifest = JSON.parse(readFileSync(join(REPO_ROOT, ".codex-plugin", "plugin.json")));
|
|
const assetPaths = [
|
|
...new Set(
|
|
Object.values(pluginManifest.interface)
|
|
.filter((value) => typeof value === "string")
|
|
.map((value) => value.replace(/^\.\//, ""))
|
|
.filter((value) => value.startsWith("assets/")),
|
|
),
|
|
].sort();
|
|
if (assetPaths.some((assetPath) => assetPath.split("/").includes(".."))) {
|
|
throw new Error("Plugin manifest contains an unsafe asset path.");
|
|
}
|
|
const PLUGIN_PATHS = [".codex-plugin", ...assetPaths, "skills"];
|
|
|
|
for (const pluginPath of PLUGIN_PATHS) {
|
|
execFileSync("git", ["cat-file", "-e", `HEAD:${pluginPath}`], {
|
|
cwd: REPO_ROOT,
|
|
stdio: "inherit",
|
|
});
|
|
}
|
|
|
|
const dirtyCheck = spawnSync("git", ["diff", "--quiet", "HEAD", "--", ...PLUGIN_PATHS], {
|
|
cwd: REPO_ROOT,
|
|
});
|
|
if (dirtyCheck.error || (dirtyCheck.status !== 0 && dirtyCheck.status !== 1)) {
|
|
throw dirtyCheck.error ?? new Error("Unable to inspect the plugin working tree state.");
|
|
}
|
|
if (dirtyCheck.status === 1) {
|
|
console.warn("Warning: packaging committed HEAD; uncommitted plugin changes are excluded.");
|
|
}
|
|
|
|
mkdirSync(join(REPO_ROOT, "dist"), { recursive: true });
|
|
|
|
execFileSync(
|
|
"git",
|
|
[
|
|
"archive",
|
|
"--format=zip",
|
|
"--prefix=frames/",
|
|
"--output",
|
|
OUTPUT,
|
|
"HEAD",
|
|
"--",
|
|
...PLUGIN_PATHS,
|
|
],
|
|
{ cwd: REPO_ROOT, stdio: "inherit" },
|
|
);
|
|
|
|
const bytes = statSync(OUTPUT).size;
|
|
if (bytes > MAX_UPLOAD_BYTES) {
|
|
rmSync(OUTPUT);
|
|
throw new Error(
|
|
`Codex plugin archive is ${(bytes / 1_000_000).toFixed(1)} MB; the upload limit is 100 MB.`,
|
|
);
|
|
}
|
|
|
|
console.log(`Wrote ${OUTPUT} (${(bytes / 1_000_000).toFixed(1)} MB).`);
|