#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: HYPERTWIST_REMOTE_WINDOWS_PASSWORD=... \ scripts/run-hypertwist-remote-exact-source-browser-package-refresh.sh Options: --worktree-root Optional Windows worktree root. Defaults to C:\HyperTwist_worktrees\phase10validate. --report-stamp Optional suffix used for the browser automation report and package archive. Defaults to the current UTC date. --fallback-worktree-root Optional fallback Windows worktree root to use if the primary refresh fails. Useful when the maintained worktree is temporarily locked by another Windows-side process. --browser-filter Optional Unreal automation filter. Defaults to HyperTwist.Browser. --browser-report-name Optional explicit browser automation report name. Defaults to Browser-ExactSource-. --package-archive-dir Optional Windows archive directory for the higher-dimensional package run. Defaults to _packaged_phase6c_higherdim_refresh_. --sync-file Optional repo-relative file to sync into the remote Windows worktree before validation. May be repeated. --skip-build Skip the remote Unreal editor build step. --skip-browser-automation Skip the HyperTwist.Browser automation refresh. --skip-package Skip the higher-dimensional package refresh. --skip-browser-report-pull Skip pulling the browser automation index.json back into docs/generated. --skip-package-report-pull Skip pulling the higher-dimensional package validation report back into docs/generated. --skip-summary-refresh Skip re-rendering website/src/shared/generated/windows-package-validation-summary.json. --skip-exact-source-support-sync Skip syncing the bounded exact-source browser/package support files that the fallback Windows validation root needs for truthful browser/package refreshes. --dry-run Print the wrapper invocations without executing them. Environment: HYPERTWIST_REMOTE_WINDOWS_PASSWORD Required by the underlying remote wrappers. HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT Optional default for --worktree-root. HYPERTWIST_REMOTE_WINDOWS_FALLBACK_WORKTREE_ROOT Optional default for --fallback-worktree-root. HYPERTWIST_REMOTE_WINDOWS_SKIP_EXACT_SOURCE_SUPPORT_SYNC Optional default for --skip-exact-source-support-sync. EOF } ps_single_quote() { printf "'%s'" "${1//\'/\'\'}" } run_or_print() { if [[ "$dry_run" == "true" ]]; then printf '%q ' "$@" printf '\n' return 0 fi "$@" } worktree_root="${HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT:-C:\\HyperTwist_worktrees\\phase10validate}" fallback_worktree_root="${HYPERTWIST_REMOTE_WINDOWS_FALLBACK_WORKTREE_ROOT:-}" report_stamp="$(date -u '+%Y%m%d')" browser_filter="HyperTwist.Browser" browser_report_name="" package_archive_dir="" sync_files=() skip_build="false" skip_browser_automation="false" skip_package="false" skip_browser_report_pull="false" skip_package_report_pull="false" skip_summary_refresh="false" skip_exact_source_support_sync="${HYPERTWIST_REMOTE_WINDOWS_SKIP_EXACT_SOURCE_SUPPORT_SYNC:-false}" dry_run="false" while [[ $# -gt 0 ]]; do case "$1" in --worktree-root) worktree_root="${2:-}" shift 2 ;; --report-stamp) report_stamp="${2:-}" shift 2 ;; --fallback-worktree-root) fallback_worktree_root="${2:-}" shift 2 ;; --browser-filter) browser_filter="${2:-}" shift 2 ;; --browser-report-name) browser_report_name="${2:-}" shift 2 ;; --package-archive-dir) package_archive_dir="${2:-}" shift 2 ;; --sync-file) sync_files+=("${2:-}") shift 2 ;; --skip-build) skip_build="true" shift ;; --skip-browser-automation) skip_browser_automation="true" shift ;; --skip-package) skip_package="true" shift ;; --skip-browser-report-pull) skip_browser_report_pull="true" shift ;; --skip-package-report-pull) skip_package_report_pull="true" shift ;; --skip-summary-refresh) skip_summary_refresh="true" shift ;; --skip-exact-source-support-sync) skip_exact_source_support_sync="true" shift ;; --dry-run) dry_run="true" shift ;; -h|--help) usage exit 0 ;; *) usage >&2 exit 1 ;; esac done if [[ -z "$browser_report_name" ]]; then browser_report_name="Browser-ExactSource-${report_stamp}" fi if [[ -z "$package_archive_dir" ]]; then package_archive_dir="${worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}" fi script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "${script_dir}/.." && pwd)" remote_ps_wrapper="${script_dir}/run-hypertwist-remote-windows-powershell.sh" remote_build_wrapper="${script_dir}/run-hypertwist-remote-unreal-build.sh" remote_automation_wrapper="${script_dir}/run-hypertwist-remote-unreal-automation.sh" remote_sync_wrapper="${script_dir}/run-hypertwist-remote-windows-file-sync.sh" remote_pull_wrapper="${script_dir}/run-hypertwist-remote-windows-file-pull.sh" summary_refresh_script="${script_dir}/render-hypertwist-web-package-validation-summary.mjs" for required_wrapper in \ "$remote_ps_wrapper" \ "$remote_build_wrapper" \ "$remote_automation_wrapper" \ "$remote_sync_wrapper" \ "$remote_pull_wrapper" do if [[ ! -x "$required_wrapper" ]]; then echo "Expected executable wrapper at $required_wrapper" >&2 exit 1 fi done if [[ ! -f "$summary_refresh_script" ]]; then echo "Expected summary refresh script at $summary_refresh_script" >&2 exit 1 fi if [[ -z "${HYPERTWIST_REMOTE_WINDOWS_PASSWORD:-}" ]]; then echo "Set HYPERTWIST_REMOTE_WINDOWS_PASSWORD before running this refresh." >&2 exit 1 fi host_probe_command="Write-Output ('USER=' + [System.Security.Principal.WindowsIdentity]::GetCurrent().Name); Write-Output ('HOST=' + \$env:COMPUTERNAME)" browser_report_local_path="docs/generated/browser_automation/${browser_report_name}/index.json" package_report_local_path="docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json" exact_source_support_files=( "Content/Browser/index.html" "Content/Browser/src/browser-runtime-bootstrap.js" "Content/Browser/src/browser-spatial-runtime-fallback.js" "Content/Browser/src/runtime/shell.ts" "scripts/Invoke-HyperTwistHigherDimensionalPackage.ps1" "scripts/Launch-HyperTwistHigherDimensionalPackage.ps1" "docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_map_manifest.json" "UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp" "UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryInternal.h" "UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachPolicies.cpp" "UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachWorkflow.cpp" "UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibraryCoachSummaries.cpp" ) effective_sync_files=() add_effective_sync_file() { local candidate="$1" local existing for existing in "${effective_sync_files[@]}"; do if [[ "$existing" == "$candidate" ]]; then return 0 fi done effective_sync_files+=("$candidate") } if [[ "$skip_exact_source_support_sync" != "true" ]]; then for sync_file in "${exact_source_support_files[@]}"; do add_effective_sync_file "$sync_file" done fi for sync_file in "${sync_files[@]}"; do add_effective_sync_file "$sync_file" done run_refresh_for_root() { local current_worktree_root="$1" local current_validation_report_path="${current_worktree_root}\\docs\\generated\\higher_dimensional_training_maps\\phase6c_dedicated_family_package_validation_report.json" local browser_report_remote_path="${current_worktree_root}\\UnrealHyperTwist\\Saved\\AutomationReports\\${browser_report_name}\\index.json" local package_report_remote_path="$current_validation_report_path" local current_package_script_path="${current_worktree_root}\\scripts\\Invoke-HyperTwistHigherDimensionalPackage.ps1" local current_package_archive_dir="$package_archive_dir" local current_game_target_receipt_path="${current_worktree_root}\\UnrealHyperTwist\\Binaries\\Win64\\UnrealHyperTwist.target" local package_skip_build_clause="" local pre_package_editor_build_ps_bool='$false' local pre_package_editor_build_result='not-run' local step_exit=0 if [[ "$current_worktree_root" != "$worktree_root" && "$package_archive_dir" == "${worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}" ]]; then current_package_archive_dir="${current_worktree_root}_packaged_phase6c_higherdim_refresh_${report_stamp}" fi echo "Re-proving remote Windows lane through ${current_worktree_root}." if run_or_print "$remote_ps_wrapper" --command "$host_probe_command"; then : else step_exit="$?" return "$step_exit" fi if [[ ${#effective_sync_files[@]} -gt 0 ]]; then echo "Syncing ${#effective_sync_files[@]} repo-relative exact-source support file(s) into ${current_worktree_root}." local sync_command=("$remote_sync_wrapper") local sync_file for sync_file in "${effective_sync_files[@]}"; do sync_command+=(--file "$sync_file") done sync_command+=(--remote-root "$current_worktree_root") if run_or_print "${sync_command[@]}"; then : else step_exit="$?" return "$step_exit" fi fi if [[ "$skip_build" != "true" ]]; then echo "Running remote Unreal editor build." if run_or_print "$remote_build_wrapper" --worktree-root "$current_worktree_root"; then pre_package_editor_build_ps_bool='$true' pre_package_editor_build_result='passed' : else step_exit="$?" return "$step_exit" fi fi if [[ "$skip_browser_automation" != "true" ]]; then echo "Running remote browser automation refresh (~10-20s once the editor lane is warm)." if run_or_print \ env HYPERTWIST_REMOTE_WINDOWS_WORKTREE_ROOT="$current_worktree_root" \ "$remote_automation_wrapper" \ --filter "$browser_filter" \ --report-name "$browser_report_name" then : else step_exit="$?" return "$step_exit" fi fi if [[ "$skip_package" != "true" ]]; then echo "Running remote higher-dimensional package refresh (~1-3m on the maintained lane)." if [[ "$dry_run" == "true" ]]; then echo "Dry run: package helper would auto-detect whether ${current_game_target_receipt_path} exists before deciding on -SkipBuild." else local package_skip_build_probe_output if package_skip_build_probe_output="$( "$remote_ps_wrapper" --command "\$GameTargetReceiptPath = $(ps_single_quote "$current_game_target_receipt_path"); Write-Output ('PACKAGE_SKIP_BUILD=' + (Test-Path -LiteralPath \$GameTargetReceiptPath).ToString().ToLowerInvariant())" \ | tr -d '\r' )"; then : else step_exit="$?" return "$step_exit" fi if printf '%s\n' "$package_skip_build_probe_output" | grep -Fq 'PACKAGE_SKIP_BUILD=true'; then package_skip_build_clause=" -SkipBuild" echo "Package helper will reuse the existing Win64 game target receipt." else echo "Package helper will rebuild the Win64 game target because the packaged-game receipt is absent." fi fi local package_command package_command="$( cat <&2 run_refresh_for_root "$fallback_worktree_root" active_worktree_root="$fallback_worktree_root" else exit "$primary_exit" fi fi echo "Remote exact-source browser/package refresh complete through ${active_worktree_root}."