mirror of
https://github.com/obra/superpowers.git
synced 2026-07-02 23:49:05 +08:00
Default Codex portal package to zip
This commit is contained in:
committed by
Jesse Vincent
parent
6770bfbcc5
commit
8e19a0c3e6
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Package the Superpowers Codex plugin as a rootless .tar.gz for portal upload.
|
||||
# Package the Superpowers Codex plugin as a rootless archive for portal upload.
|
||||
#
|
||||
# The Codex portal artifact differs from the old openai/plugins sync flow:
|
||||
# it is a standalone archive, but it still needs the OpenAI-owned
|
||||
@@ -14,6 +14,7 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
REF="HEAD"
|
||||
OUTPUT=""
|
||||
FORMAT=""
|
||||
METADATA_SOURCE=""
|
||||
ALLOW_DIRTY=0
|
||||
KEEP_STAGE=0
|
||||
@@ -25,18 +26,21 @@ Usage:
|
||||
|
||||
Options:
|
||||
--output PATH Write archive to PATH.
|
||||
Default: ../_tmp/sup-codex-packaging/superpowers-VERSION.tar.gz
|
||||
--metadata-source PATH Prior official package directory or .tar.gz used to
|
||||
Default: ../_tmp/sup-codex-packaging/superpowers-VERSION.zip
|
||||
--format FORMAT Archive format: zip or tar.gz. Default: zip.
|
||||
If --output ends in .zip, .tar.gz, or .tgz, that
|
||||
extension is used when --format is omitted.
|
||||
--metadata-source PATH Prior official package directory, .zip, or .tar.gz used to
|
||||
seed skills/*/agents/openai.yaml.
|
||||
Default: ../_tmp/sup-codex-packaging/superpowers,
|
||||
falling back to ../_tmp/sup-codex-packaging/superpowers.tar.gz
|
||||
falling back to superpowers.zip, then superpowers.tar.gz
|
||||
--ref REF Git ref to package. Default: HEAD.
|
||||
--allow-dirty Permit a dirty working tree. The archive still uses --ref.
|
||||
--keep-stage Print and keep the temporary staging directory.
|
||||
-h, --help Show this help.
|
||||
|
||||
The archive is rootless: .codex-plugin/, assets/, skills/, README.md, LICENSE,
|
||||
and CODE_OF_CONDUCT.md sit at the tar root. Source-only repo files, hooks, tests,
|
||||
and CODE_OF_CONDUCT.md sit at the archive root. Source-only repo files, hooks, tests,
|
||||
docs, and other harness manifests are intentionally not shipped.
|
||||
EOF
|
||||
}
|
||||
@@ -53,6 +57,21 @@ while [[ $# -gt 0 ]]; do
|
||||
OUTPUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--format)
|
||||
[[ $# -ge 2 ]] || die "--format requires a value"
|
||||
case "$2" in
|
||||
zip)
|
||||
FORMAT="zip"
|
||||
;;
|
||||
tar.gz|tgz)
|
||||
FORMAT="tar.gz"
|
||||
;;
|
||||
*)
|
||||
die "--format must be zip or tar.gz"
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
--metadata-source)
|
||||
[[ $# -ge 2 ]] || die "--metadata-source requires a path"
|
||||
METADATA_SOURCE="$2"
|
||||
@@ -83,11 +102,43 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
infer_format_from_output() {
|
||||
local output_path="$1"
|
||||
|
||||
case "$output_path" in
|
||||
*.tar.gz|*.tgz)
|
||||
printf '%s\n' "tar.gz"
|
||||
;;
|
||||
*.zip)
|
||||
printf '%s\n' "zip"
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ -z "$FORMAT" ]]; then
|
||||
FORMAT="$(infer_format_from_output "$OUTPUT" || true)"
|
||||
if [[ -z "$FORMAT" ]]; then
|
||||
FORMAT="zip"
|
||||
fi
|
||||
else
|
||||
output_format="$(infer_format_from_output "$OUTPUT" || true)"
|
||||
if [[ -n "$output_format" && "$output_format" != "$FORMAT" ]]; then
|
||||
die "--output extension does not match --format $FORMAT: $OUTPUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
command -v git >/dev/null || die "git not found in PATH"
|
||||
command -v jq >/dev/null || die "jq not found in PATH"
|
||||
command -v tar >/dev/null || die "tar not found in PATH"
|
||||
command -v gzip >/dev/null || die "gzip not found in PATH"
|
||||
command -v shasum >/dev/null || die "shasum not found in PATH"
|
||||
if [[ "$FORMAT" == "zip" ]]; then
|
||||
command -v zip >/dev/null || die "zip not found in PATH"
|
||||
command -v unzip >/dev/null || die "unzip not found in PATH"
|
||||
fi
|
||||
|
||||
[[ -d "$REPO_ROOT/.git" ]] || die "repo root is not a git checkout: $REPO_ROOT"
|
||||
git -C "$REPO_ROOT" rev-parse --verify "$REF^{commit}" >/dev/null ||
|
||||
@@ -105,17 +156,19 @@ fi
|
||||
if [[ -z "$METADATA_SOURCE" ]]; then
|
||||
if [[ -d "$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers" ]]; then
|
||||
METADATA_SOURCE="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers"
|
||||
elif [[ -f "$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers.zip" ]]; then
|
||||
METADATA_SOURCE="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers.zip"
|
||||
elif [[ -f "$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers.tar.gz" ]]; then
|
||||
METADATA_SOURCE="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers.tar.gz"
|
||||
else
|
||||
die "no metadata source found; pass --metadata-source <prior package dir or tar.gz>"
|
||||
die "no metadata source found; pass --metadata-source <prior package dir, zip, or tar.gz>"
|
||||
fi
|
||||
fi
|
||||
|
||||
WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/superpowers-codex-package.XXXXXX")"
|
||||
STAGE="$WORK_DIR/payload"
|
||||
METADATA_WORK="$WORK_DIR/metadata"
|
||||
TAR_LIST="$WORK_DIR/tar-list"
|
||||
ARCHIVE_LIST="$WORK_DIR/archive-list"
|
||||
|
||||
cleanup() {
|
||||
if [[ "$KEEP_STAGE" -eq 1 ]]; then
|
||||
@@ -158,8 +211,13 @@ prepare_metadata_root() {
|
||||
tar -xzf "$source" -C "$METADATA_WORK"
|
||||
root="$METADATA_WORK"
|
||||
;;
|
||||
*.zip)
|
||||
command -v unzip >/dev/null || die "unzip not found in PATH"
|
||||
unzip -q "$source" -d "$METADATA_WORK"
|
||||
root="$METADATA_WORK"
|
||||
;;
|
||||
*)
|
||||
die "metadata source must be a directory or .tar.gz: $source"
|
||||
die "metadata source must be a directory, .zip, or .tar.gz: $source"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
@@ -189,7 +247,14 @@ if jq -e 'has("hooks")' "$STAGE/.codex-plugin/plugin.json" >/dev/null; then
|
||||
fi
|
||||
|
||||
if [[ -z "$OUTPUT" ]]; then
|
||||
OUTPUT="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers-$VERSION.tar.gz"
|
||||
case "$FORMAT" in
|
||||
zip)
|
||||
OUTPUT="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers-$VERSION.zip"
|
||||
;;
|
||||
tar.gz)
|
||||
OUTPUT="$REPO_ROOT/../_tmp/sup-codex-packaging/superpowers-$VERSION.tar.gz"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
OUTPUT="$(cd "$(dirname "$OUTPUT")" && pwd)/$(basename "$OUTPUT")"
|
||||
@@ -218,27 +283,51 @@ metadata_count="$(find "$STAGE/skills" -path '*/agents/openai.yaml' -type f | wc
|
||||
[[ "$skill_count" == "$metadata_count" ]] ||
|
||||
die "metadata count mismatch: $metadata_count metadata files for $skill_count skills"
|
||||
|
||||
# Match the prior official archive's deterministic tar entry metadata.
|
||||
TZ=UTC find "$STAGE" -exec touch -t 197001010000 {} +
|
||||
|
||||
(
|
||||
cd "$STAGE"
|
||||
{
|
||||
find . -mindepth 1 -type d | sed 's#^\./##' | LC_ALL=C sort
|
||||
find . -mindepth 1 -type f | sed 's#^\./##' | LC_ALL=C sort
|
||||
} >"$TAR_LIST"
|
||||
|
||||
rm -f "$OUTPUT"
|
||||
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar --uid 0 --gid 0 --uname '' --gname '' -T "$TAR_LIST" |
|
||||
gzip -9n >"$OUTPUT"
|
||||
} >"$ARCHIVE_LIST"
|
||||
)
|
||||
|
||||
case "$FORMAT" in
|
||||
zip)
|
||||
# ZIP cannot represent dates earlier than 1980.
|
||||
TZ=UTC find "$STAGE" -exec touch -t 198001010000 {} +
|
||||
(
|
||||
cd "$STAGE"
|
||||
rm -f "$OUTPUT"
|
||||
COPYFILE_DISABLE=1 zip -X -q - -@ <"$ARCHIVE_LIST" >"$OUTPUT"
|
||||
)
|
||||
;;
|
||||
tar.gz)
|
||||
# Match the prior official archive's deterministic tar entry metadata.
|
||||
TZ=UTC find "$STAGE" -exec touch -t 197001010000 {} +
|
||||
(
|
||||
cd "$STAGE"
|
||||
rm -f "$OUTPUT"
|
||||
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar --uid 0 --gid 0 --uname '' --gname '' -T "$ARCHIVE_LIST" |
|
||||
gzip -9n >"$OUTPUT"
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
||||
if command -v xattr >/dev/null 2>&1; then
|
||||
xattr -c "$OUTPUT" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
case "$FORMAT" in
|
||||
zip)
|
||||
archive_paths="$(unzip -Z1 "$OUTPUT" | sed 's#/$##')"
|
||||
;;
|
||||
tar.gz)
|
||||
archive_paths="$(tar -tzf "$OUTPUT")"
|
||||
;;
|
||||
esac
|
||||
|
||||
unexpected_paths="$(
|
||||
tar -tzf "$OUTPUT" |
|
||||
printf '%s\n' "$archive_paths" |
|
||||
grep -E '(^superpowers/|^\.agents/|^hooks/|package\.json$|^\.git|^\.pytest_cache|^\.ruff_cache|^scripts/|^tests/|^docs/|^evals/|^lib/|^\.claude|^\.cursor|^\.kimi|^\.opencode|^\.pi|^AGENTS\.md$|^CLAUDE\.md$|^GEMINI\.md$|^RELEASE-NOTES\.md$|^CHANGELOG\.md$)' || true
|
||||
)"
|
||||
if [[ -n "$unexpected_paths" ]]; then
|
||||
@@ -246,10 +335,11 @@ if [[ -n "$unexpected_paths" ]]; then
|
||||
die "archive contains source-only paths"
|
||||
fi
|
||||
|
||||
entry_count="$(tar -tzf "$OUTPUT" | wc -l | tr -d ' ')"
|
||||
entry_count="$(printf '%s\n' "$archive_paths" | wc -l | tr -d ' ')"
|
||||
checksum="$(shasum -a 256 "$OUTPUT" | awk '{print $1}')"
|
||||
|
||||
echo "Archive: $OUTPUT"
|
||||
echo "Format: $FORMAT"
|
||||
echo "Version: $VERSION"
|
||||
echo "Entries: $entry_count"
|
||||
echo "Skills: $skill_count"
|
||||
|
||||
Reference in New Issue
Block a user