- add dist freshness guard to deploy flow - preserve message source provenance for IPC injection - harden Codex usage fallback and workspace package manager detection - document owner branch return protocol
114 lines
3.4 KiB
Bash
Executable File
114 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# check-dist-fresh.sh — verify compiled dist/ outputs are at least as new as their
|
|
# corresponding src/ .ts sources. Use this as a restart-precondition / CI guard so
|
|
# we never ship stale compiled artifacts again (see 2026-04-23 reviewer infinite-loop
|
|
# incident caused by a patched src/bundled-cli-path.ts with a stale dist/).
|
|
#
|
|
# Usage:
|
|
# scripts/check-dist-fresh.sh # checks default packages (root + agent-runner)
|
|
# scripts/check-dist-fresh.sh DIR [DIR ...] # each DIR must contain src/ and dist/
|
|
#
|
|
# Exit codes:
|
|
# 0 — all dist/ files up-to-date
|
|
# 1 — at least one dist/ file missing or older than its src/ sibling
|
|
# 2 — usage / environment error
|
|
#
|
|
# Rules per package:
|
|
# - For every foo.ts under src/ (excluding *.test.ts, *.d.ts, __tests__/*):
|
|
# require dist/foo.js to exist AND have mtime >= src/foo.ts
|
|
# - Missing dist/foo.js is a hard error (build never ran for that file).
|
|
#
|
|
set -euo pipefail
|
|
|
|
# Resolve repo root from this script's location so the script works from any cwd.
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
if [ "$#" -gt 0 ]; then
|
|
PACKAGES=("$@")
|
|
else
|
|
PACKAGES=(
|
|
"${REPO_ROOT}"
|
|
"${REPO_ROOT}/runners/agent-runner"
|
|
"${REPO_ROOT}/runners/codex-runner"
|
|
"${REPO_ROOT}/runners/shared"
|
|
)
|
|
fi
|
|
|
|
fail=0
|
|
checked=0
|
|
|
|
# Use mtime in nanoseconds (GNU stat) for precision. Fallback to seconds if %Y only.
|
|
_mtime() {
|
|
# $1: path
|
|
local t
|
|
t="$(stat -c '%Y' "$1" 2>/dev/null || true)"
|
|
if [ -z "$t" ]; then
|
|
# BSD stat fallback (macOS)
|
|
t="$(stat -f '%m' "$1" 2>/dev/null || true)"
|
|
fi
|
|
echo "${t:-0}"
|
|
}
|
|
|
|
check_package() {
|
|
local pkg="$1"
|
|
local src_dir="${pkg}/src"
|
|
local dist_dir="${pkg}/dist"
|
|
|
|
if [ ! -d "$src_dir" ]; then
|
|
echo "skip: ${pkg} (no src/)" >&2
|
|
return 0
|
|
fi
|
|
if [ ! -d "$dist_dir" ]; then
|
|
echo "FAIL: ${pkg} — dist/ does not exist (run build)" >&2
|
|
fail=1
|
|
return 0
|
|
fi
|
|
|
|
local ts dist_file src_mtime dist_mtime
|
|
# Loop over every .ts file under src/, skipping tests & type declarations.
|
|
while IFS= read -r -d '' ts; do
|
|
local rel="${ts#${src_dir}/}"
|
|
dist_file="${dist_dir}/${rel%.ts}.js"
|
|
checked=$((checked + 1))
|
|
|
|
if [ ! -f "$dist_file" ]; then
|
|
echo "FAIL: missing dist file: ${dist_file} (src: ${ts})" >&2
|
|
fail=1
|
|
continue
|
|
fi
|
|
|
|
src_mtime="$(_mtime "$ts")"
|
|
dist_mtime="$(_mtime "$dist_file")"
|
|
|
|
if [ "$dist_mtime" -lt "$src_mtime" ]; then
|
|
echo "FAIL: stale dist: ${dist_file}" >&2
|
|
echo " src mtime=${src_mtime} ($(date -d "@${src_mtime}" '+%F %T' 2>/dev/null || true)) ${ts}" >&2
|
|
echo " dist mtime=${dist_mtime} ($(date -d "@${dist_mtime}" '+%F %T' 2>/dev/null || true))" >&2
|
|
fail=1
|
|
fi
|
|
done < <(find "$src_dir" -type f -name '*.ts' \
|
|
! -name '*.test.ts' \
|
|
! -name '*.d.ts' \
|
|
! -path '*/__tests__/*' \
|
|
-print0)
|
|
}
|
|
|
|
for pkg in "${PACKAGES[@]}"; do
|
|
if [ ! -d "$pkg" ]; then
|
|
echo "skip: ${pkg} (directory not found)" >&2
|
|
continue
|
|
fi
|
|
check_package "$pkg"
|
|
done
|
|
|
|
if [ "$fail" -ne 0 ]; then
|
|
echo "" >&2
|
|
echo "dist freshness check FAILED (checked ${checked} source files)" >&2
|
|
echo "Run: bun run build:all (or the package's build script)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "dist freshness OK (checked ${checked} source files across ${#PACKAGES[@]} package(s))"
|
|
exit 0
|