diff --git a/scripts/run/run b/scripts/run/run new file mode 100755 index 00000000..98a63899 --- /dev/null +++ b/scripts/run/run @@ -0,0 +1,199 @@ +#!/usr/bin/env bash +# Magic Civilization — Task Runner +# Usage: ./run [args...] +# +# Naming convention: `` for global actions; `:` for subcommands. +# Examples: lint / lint:rust, build / build:wasm, install:osx, smoke:linux. + +set -uo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Source all run modules +for _script in "$REPO_ROOT/scripts/run/"*.sh; do + source "$_script" +done +unset _script + +usage() { + echo -e "${BLUE}Magic Civilization${NC} — Task Runner" + echo "" + echo "Usage: ./run [args...]" + echo "" + echo -e "${YELLOW}Development${NC}" + echo " play Launch the game locally" + echo " editor Open Godot editor" + echo " guide Start guide dev server (port 5800)" + echo " lint Lint all (GDScript + Rust + TypeScript)" + echo " lint:gd GDScript only (gdlint + gdformat --check)" + echo " lint:rust Rust only (fmt --check + clippy + machete)" + echo " lint:ts TypeScript only (ESLint + tsc typecheck)" + echo " format Format all (GDScript + Rust + TypeScript)" + echo " format:gd GDScript only (gdformat)" + echo " format:rust Rust only (cargo fmt)" + echo " format:ts TypeScript only (ESLint --fix)" + echo " typecheck pnpm -r typecheck (all TS packages)" + echo " validate Validate game data JSON files against schemas" + echo " test Run GUT + Rust (nextest if available) + vitest" + echo " test:golden Cross-language golden-vector parity (Rust + WASM + GDExt)" + echo " coverage Coverage reports (cargo llvm-cov + pnpm test:coverage)" + echo " verify Full pipeline: schemas + build + tests + lint + docs + LOC cap" + echo " screenshot [name] [scene] [delay] Capture screenshot" + echo " autoplay [seed] Run single seeded auto_play game + report (opt-in)" + echo " autoplay-batch [count] Run N seeded games + aggregate report (opt-in)" + echo "" + echo -e "${YELLOW}Build${NC}" + echo " build Build WASM + GDExtension" + echo " build:wasm Build WASM only (src/simulator → pkg/)" + echo " build:gdext Build GDExtension only (src/simulator → src/game/addons/)" + echo "" + echo -e "${YELLOW}Export${NC}" + echo " export [version] Export all platforms (parallel)" + echo " export:macos [version] Export macOS only" + echo " export:linux [version] Export Linux only" + echo " export:windows [version] Export Windows only" + echo " export:android [version] Export Android APK" + echo " export:ios [version] Export iOS Xcode project" + echo "" + echo -e "${YELLOW}Install (deploy + launch on target)${NC}" + echo " install:osx [version] [--dev] Export + install .app on \$OSX_HOST (default: plum)" + echo " install:linux [version] [--dev] Export + install binary on \$LINUX_HOST" + echo " install:iphone [version] [--dev] Export + xcodebuild + devicectl install via \$OSX_HOST" + echo " install:android [version] [--dev] Export + adb install on connected Android device" + echo "" + echo -e "${YELLOW}Remote control${NC}" + echo " start:osx Launch installed app on \$OSX_HOST" + echo " start:linux Launch installed binary on \$LINUX_HOST" + echo " start:ios Launch app on connected iPhone (via \$OSX_HOST)" + echo " stop:osx Kill running app on \$OSX_HOST" + echo " stop:linux Kill running binary on \$LINUX_HOST" + echo " smoke:osx Full smoke test (macOS — export → ship → launch → screenshot)" + echo " smoke:linux [boot-secs] Full smoke test (Linux — default 20s boot wait)" + echo "" + echo -e "${YELLOW}Tools${NC}" + echo " tools:spritegen Sprite generation pipeline" + echo " setup Install/verify all dev dependencies (auto-detects OS)" +} + +# ── Install args parser (shared by install:* targets) ──────────────── +# Separates --dev from positional args; echoes them as +# "DEV_MODE|pos1 pos2 ..." for callers to split. +_parse_install_args() { + local dev_flag="" + local pos=() + for arg in "$@"; do + case "$arg" in + --dev) dev_flag="--dev" ;; + *) pos+=("$arg") ;; + esac + done + echo "$dev_flag|${pos[*]}" +} + +_dispatch_install() { + local target="$1"; shift + local parsed dev_flag pos_args + parsed="$(_parse_install_args "$@")" + dev_flag="${parsed%%|*}" + pos_args="${parsed#*|}" + # shellcheck disable=SC2086 + case "$target" in + osx) cmd_install_osx $dev_flag $pos_args ;; + linux) cmd_install_linux $dev_flag $pos_args ;; + iphone) cmd_install_ios iphone $dev_flag $pos_args ;; + sim) cmd_install_ios sim $dev_flag $pos_args ;; + android) cmd_install_android $dev_flag $pos_args ;; + *) echo -e "${RED}Unknown install target: $target${NC}"; echo "Available: osx, linux, iphone, android"; return 1 ;; + esac +} + +COMMAND="${1:-}" +shift 2>/dev/null || true + +case "$COMMAND" in + # ── Development ────────────────────────────────────────────────── + play) cmd_play "$@" ;; + editor) cmd_editor "$@" ;; + guide) cmd_guide "$@" ;; + lint) cmd_lint "$@" ;; + lint:gd) cmd_lint_gd "$@" ;; + lint:rust) cmd_lint_rust "$@" ;; + lint:ts) cmd_lint_ts "$@" ;; + format) cmd_format "$@" ;; + format:gd) cmd_format_gd "$@" ;; + format:rust) cmd_format_rust "$@" ;; + format:ts) cmd_format_ts "$@" ;; + typecheck) cmd_typecheck "$@" ;; + validate) cmd_validate "$@" ;; + test) cmd_test "$@" ;; + test:golden) cmd_test_golden "$@" ;; + coverage) cmd_coverage "$@" ;; + verify) cmd_verify "$@" ;; + screenshot) cmd_screenshot "$@" ;; + autoplay) cmd_autoplay "$@" ;; + autoplay-batch) cmd_autoplay_batch "$@" ;; + + # ── Build ──────────────────────────────────────────────────────── + build) cmd_build "$@" ;; + build:wasm) cmd_build_wasm "$@" ;; + build:gdext) cmd_build_gdext "$@" ;; + + # ── Export ─────────────────────────────────────────────────────── + export) cmd_export "$@" ;; + export:windows) cmd_export_single windows "$@" ;; + export:macos) cmd_export_single macos "$@" ;; + export:linux) cmd_export_single linux "$@" ;; + export:android) cmd_export_single android "$@" ;; + export:ios) cmd_export_single ios "$@" ;; + + # ── Install (colon form — canonical) ──────────────────────────── + install:osx|install:macos) _dispatch_install osx "$@" ;; + install:linux) _dispatch_install linux "$@" ;; + install:iphone|install:ios) _dispatch_install iphone "$@" ;; + install:sim) _dispatch_install sim "$@" ;; + install:android) _dispatch_install android "$@" ;; + + # ── Start / Stop / Smoke (colon form — canonical) ─────────────── + start:osx|start:macos) cmd_start_osx "$@" ;; + start:linux) cmd_start_linux "$@" ;; + start:ios|start:iphone) cmd_start_ios "$@" ;; + stop:osx|stop:macos) cmd_stop_osx "$@" ;; + stop:linux) cmd_stop_linux "$@" ;; + smoke:osx|smoke:macos) cmd_smoke_osx "$@" ;; + smoke:linux) cmd_smoke_linux "$@" ;; + + # ── Tools (colon form — canonical) ────────────────────────────── + tools:spritegen) cmd_tools_spritegen "$@" ;; + + # ── Legacy space-form aliases (for muscle memory — undocumented) + # install|start|stop|smoke|tools all accept a positional subtarget. + install) + TARGET=""; POS=() + for arg in "$@"; do + case "$arg" in + --dev) POS+=("$arg") ;; + osx|macos|linux|iphone|ios|sim|android) TARGET="$arg" ;; + *) POS+=("$arg") ;; + esac + done + [ -n "$TARGET" ] || { echo -e "${RED}install requires a target (use install:)${NC}"; exit 1; } + _dispatch_install "${TARGET/macos/osx}" "${POS[@]+"${POS[@]}"}" + ;; + start|stop|smoke) + VERB="$COMMAND" + TARGET="${1:-}"; shift 2>/dev/null || true + [ -n "$TARGET" ] || { echo -e "${RED}$VERB requires a target (use $VERB:)${NC}"; exit 1; } + # Recurse using canonical colon form + exec "$0" "$VERB:$TARGET" "$@" + ;; + tools) + SUB="${1:-}"; shift 2>/dev/null || true + [ -n "$SUB" ] || { echo -e "${RED}tools requires a subcommand (use tools:)${NC}"; exit 1; } + exec "$0" "tools:$SUB" "$@" + ;; + + # ── Misc ───────────────────────────────────────────────────────── + setup) cmd_setup "$@" ;; + help|--help|-h|"") usage ;; + *) echo -e "${RED}Unknown command: $COMMAND${NC}"; echo ""; usage; exit 1 ;; +esac