Files
pi/scripts/create-source-archive.sh
Armin Ronacher caf6dfe731 feat(tui): Simplify clipboard handling (#9163)
Replace the external clipboard dependency with small macOS, Windows,
and X11 helpers and integrate them into coding-agent.

Run native clipboard operations on worker threads and make command
fallbacks asynchronous. Preserve incremental X11 transfers, legacy text
encodings, native image formats, and existing Wayland and platform tools.

Include native prebuilds with ARM64 page alignment, packaging updates,
and regression coverage.
2026-09-05 23:52:32 +02:00

163 lines
5.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Create the deterministic source archive uploaded with GitHub releases.
#
# Usage:
# npm run hydrate:model-data
# ./scripts/create-source-archive.sh --version <version> --ref <git-ref> --out <archive.tar.gz>
set -euo pipefail
version=""
source_ref="HEAD"
output=""
invocation_dir="$PWD"
usage() {
echo "Usage: $0 --version <version> [--ref <git-ref>] --out <archive.tar.gz>"
}
require_value() {
if [[ $# -lt 2 || -z "$2" ]]; then
echo "$1 requires a value" >&2
usage >&2
exit 1
fi
}
while [[ $# -gt 0 ]]; do
case "$1" in
--version)
require_value "$@"
version="$2"
shift 2
;;
--ref)
require_value "$@"
source_ref="$2"
shift 2
;;
--out)
require_value "$@"
output="$2"
shift 2
;;
--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
if [[ -z "$version" || -z "$output" ]]; then
usage >&2
exit 1
fi
if [[ ! "$version" =~ ^[0-9A-Za-z][0-9A-Za-z._-]*$ ]]; then
echo "Invalid version: $version" >&2
exit 1
fi
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
cd "$repo_root"
commit="$(git rev-parse --verify --end-of-options "${source_ref}^{commit}")"
package_version="$(git show "${commit}:packages/coding-agent/package.json" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).version')"
if [[ "$package_version" != "$version" ]]; then
echo "Version ${version} does not match package version ${package_version} at ${source_ref}" >&2
exit 1
fi
if [[ "$output" != /* ]]; then
output="$invocation_dir/$output"
fi
mkdir -p "$(dirname "$output")"
output="$(cd "$(dirname "$output")" && pwd)/$(basename "$output")"
model_data_dir="packages/ai/src/providers/data"
if [[ ! -f "${model_data_dir}/.manifest.json" ]]; then
echo "Generated model data is missing. Run npm run hydrate:model-data first." >&2
exit 1
fi
shopt -s nullglob
model_data_files=("${model_data_dir}/.manifest.json" "${model_data_dir}"/*.json)
shopt -u nullglob
if [[ ${#model_data_files[@]} -eq 1 ]]; then
echo "Generated model data is missing from ${model_data_dir}" >&2
exit 1
fi
temporary_archive="$(mktemp "${output}.tmp.XXXXXX")"
temporary_index="$(mktemp "${output}.index.XXXXXX")"
manifest="$(mktemp "${output}.manifest.XXXXXX")"
validation_root="$(mktemp -d "${output}.validation.XXXXXX")"
rm -f "$temporary_index"
trap 'rm -f "$temporary_archive" "$temporary_index" "$manifest"; rm -rf "$validation_root"' EXIT
# Add the ignored release model-data snapshot to a temporary index based on the
# release commit. Archiving the resulting tree keeps the source artifact
# deterministic for the same commit and generated model data.
GIT_INDEX_FILE="$temporary_index" git read-tree "$commit"
GIT_INDEX_FILE="$temporary_index" git add -f -- "${model_data_files[@]}"
archive_tree="$(GIT_INDEX_FILE="$temporary_index" git write-tree)"
archive_mtime="$(git show -s --format=%ct "$commit")"
archive_root="pi-${version}"
git archive --format=tar --prefix="${archive_root}/" --mtime="@${archive_mtime}" "$archive_tree" \
| gzip -n -9 > "$temporary_archive"
tar -tzf "$temporary_archive" > "$manifest"
required_paths=(
"package.json"
"package-lock.json"
"scripts/build-binaries.sh"
"packages/ai/src/models.generated.ts"
"packages/ai/src/image-models.generated.ts"
"packages/ai/src/providers/data/.manifest.json"
"packages/tui/native/napi.h"
"packages/tui/native/clipboard.h"
"packages/tui/native/darwin/src/darwin-platform.m"
"packages/tui/native/darwin/prebuilds/darwin-arm64/darwin-platform.node"
"packages/tui/native/darwin/prebuilds/darwin-x64/darwin-platform.node"
"packages/tui/native/linux/build.sh"
"packages/tui/native/linux/src/linux-platform-x11.c"
"packages/tui/native/linux/prebuilds/linux-arm64/linux-platform-x11.node"
"packages/tui/native/linux/prebuilds/linux-x64/linux-platform-x11.node"
"packages/tui/native/win32/src/win32-platform.c"
"packages/tui/native/win32/prebuilds/win32-arm64/win32-platform.node"
"packages/tui/native/win32/prebuilds/win32-x64/win32-platform.node"
"packages/coding-agent/package.json"
"packages/coding-agent/src/utils/image-resize-worker.ts"
"packages/coding-agent/src/core/export-html/template.css"
)
for path in "${required_paths[@]}"; do
if ! grep -Fxq "${archive_root}/${path}" "$manifest"; then
echo "Source archive is missing required path: $path" >&2
exit 1
fi
done
if ! awk -v prefix="${archive_root}/" 'index($0, prefix) != 1 { exit 1 }' "$manifest"; then
echo "Source archive contains a path outside ${archive_root}/" >&2
exit 1
fi
if grep -Eq '(^|/)node_modules/|(^|/)packages/coding-agent/binaries/' "$manifest"; then
echo "Source archive contains generated dependencies or binaries" >&2
exit 1
fi
tar -xzf "$temporary_archive" -C "$validation_root"
node "${validation_root}/${archive_root}/packages/ai/scripts/check-model-data.ts"
mv "$temporary_archive" "$output"
trap 'rm -f "$temporary_index" "$manifest"; rm -rf "$validation_root"' EXIT
printf '%s\n' "$output"