-
Notifications
You must be signed in to change notification settings - Fork 3.5k
chore(skills): package Codex plugin upload #2668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ec770b1
eee6eb8
d0156ed
6753ace
e75a91c
c1eb128
046f88d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| #!/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", "hyperframes-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=hyperframes/", | ||
| "--output", | ||
| OUTPUT, | ||
| "HEAD", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Question — |
||
| "--", | ||
| ...PLUGIN_PATHS, | ||
| ], | ||
| { cwd: REPO_ROOT, stdio: "inherit" }, | ||
| ); | ||
|
|
||
| const bytes = statSync(OUTPUT).size; | ||
| if (bytes > MAX_UPLOAD_BYTES) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 Concern — 100 MB guard has no CI enforcement, only manual invocation. The throw fires only when someone runs |
||
| 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).`); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Nit — decimal MB vs binary MiB.
100 * 1_000_000= 100,000,000 bytes (decimal MB). If Codex actually enforces 100 MiB (104,857,600 bytes = binary), this script rejects at ~95.4 MiB, which is a ~4.9 MB conservative margin. If Codex enforces exactly 100 MB (decimal) then the script is precise. Suggest confirming the exact byte value from Codex docs and adding a comment linking the source — a future contributor shouldn't have to re-derive this. — Rames D Jusso