Created
September 9, 2025 16:38
-
-
Save seabass011/93afecf79b4003e4a9ac1f0d45ce355e to your computer and use it in GitHub Desktop.
Nova Demo C - Advanced CI with iteration limits
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Nova CI-Rescue — CI Mode & Iteration Demo (Beautiful, presenter-ready) | |
| # Focus: CI flow, branch safety, iteration limits, and clear status reporting | |
| set -Eeuo pipefail | |
| # Unset any existing GitHub tokens to ensure we use our hardcoded PAT | |
| unset GH_TOKEN | |
| unset GITHUB_TOKEN | |
| # GitHub PAT for joinnova-ci organization demos | |
| export GITHUB_TOKEN="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" | |
| export GH_TOKEN="$GITHUB_TOKEN" | |
| ######################################## | |
| # Args & Defaults | |
| ######################################## | |
| VERBOSE=false | |
| FORCE_YES=false | |
| CI_CMD="pytest -q" | |
| MAX_ITERS="3" | |
| TIMEOUT_SEC="600" | |
| for arg in "$@"; do | |
| case $arg in | |
| -y|--yes) | |
| FORCE_YES=true | |
| shift | |
| ;; | |
| -v|--verbose) | |
| VERBOSE=true | |
| shift | |
| ;; | |
| --ci=*) | |
| CI_CMD="${arg#*=}" | |
| shift | |
| ;; | |
| --max-iters=*) | |
| MAX_ITERS="${arg#*=}" | |
| shift | |
| ;; | |
| --timeout=*) | |
| TIMEOUT_SEC="${arg#*=}" | |
| shift | |
| ;; | |
| -h|--help) | |
| echo "Usage: $0 [OPTIONS]" | |
| echo "" | |
| echo "Options:" | |
| echo " -y, --yes Non-interactive mode" | |
| echo " -v, --verbose Show detailed Nova output" | |
| echo " --ci=\"<cmd>\" Test command (default: pytest -q)" | |
| echo " --max-iters=<N> Iteration cap (default: 3)" | |
| echo " --timeout=<seconds> Max runtime in seconds (default: 600)" | |
| echo " -h, --help Show this help" | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Unknown option: $arg" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| ######################################## | |
| # Terminal Intelligence & Visuals | |
| ######################################## | |
| detect_terminal() { | |
| TERM_WIDTH=$(tput cols 2>/dev/null || echo 80) | |
| TERM_HEIGHT=$(tput lines 2>/dev/null || echo 24) | |
| CAN_UTF8=false | |
| if echo -e '\u2713' | grep -q '✓' 2>/dev/null; then CAN_UTF8=true; fi | |
| } | |
| setup_visuals() { | |
| BOLD=$'\033[1m'; DIM=$'\033[2m'; UNDERLINE=$'\033[4m'; ITALIC=$'\033[3m'; NC=$'\033[0m' | |
| RED=$'\033[0;31m'; GREEN=$'\033[0;32m'; YELLOW=$'\033[1;33m'; BLUE=$'\033[0;34m'; CYAN=$'\033[0;36m'; PURPLE=$'\033[0;35m'; WHITE=$'\033[0;37m' | |
| if [ "$CAN_UTF8" = true ]; then CHECK="✓"; CROSS="✗"; BULLET="•"; SPARKLE="✨"; ROCKET="🚀"; PACKAGE="📦"; BRAIN="🧠"; SHIELD="🛡️"; LOOP="🔁"; else CHECK="[OK]"; CROSS="[X]"; BULLET="*"; SPARKLE="*"; ROCKET=">"; PACKAGE="[]"; BRAIN="AI"; SHIELD="[]"; LOOP="(loop)"; fi | |
| } | |
| hr() { printf '%*s\n' "${TERM_WIDTH}" '' | tr ' ' '─'; } | |
| thr() { printf '%*s\n' "${TERM_WIDTH}" '' | tr ' ' '━'; } | |
| banner() { | |
| clear || true | |
| echo | |
| echo | |
| thr | |
| echo "Nova CI-Rescue — CI Mode & Iteration" | |
| echo "Software that fixes software" | |
| thr | |
| echo | |
| } | |
| step() { | |
| local n="$1"; local t="$2"; local msg="$3"; local icon="${4:-$PACKAGE}" | |
| echo | |
| echo "Step ${n}/${t} │ ${icon} ${msg}" | |
| hr | |
| } | |
| ok() { echo -e "${GREEN}✓${NC} $1"; } | |
| warn() { echo -e "${YELLOW}⚠${NC} $1"; } | |
| err() { echo -e "${RED}✗${NC} $1"; } | |
| info() { echo -e "${CYAN}ℹ${NC} $1"; } | |
| ask_yes() { | |
| local prompt="$1"; local default="${2:-Y}"; local yn="[Y/n]"; [ "$default" = "N" ] && yn="[y/N]" | |
| if [ "$FORCE_YES" = true ]; then return 0; fi | |
| printf "%s %s " "$prompt" "$yn"; read -r REPLY; REPLY="${REPLY:-$default}"; [[ "$REPLY" =~ ^[Yy]$ ]] | |
| } | |
| preview_file() { | |
| local file="$1"; local label="$2" | |
| echo | |
| echo -e "${BOLD}${file}${NC} ${DIM}${label}${NC}" | |
| echo -e "${DIM}$(hr)${NC}" | |
| [ -f "$file" ] && nl -ba "$file" | head -15 | sed 's/^/ /' | |
| echo | |
| } | |
| ######################################## | |
| # Core Demo Flow | |
| ######################################## | |
| run_demo() { | |
| detect_terminal; setup_visuals; banner | |
| echo -e "${BOLD}What you'll see in under 2 minutes:${NC}" | |
| echo -e " ${BULLET} ${BOLD}CI Mode${NC}: tests fail → Nova auto-fix runs" | |
| echo -e " ${BULLET} ${BOLD}Branch Safety${NC}: fixes on ${ITALIC}nova/fix/*${NC}" | |
| echo -e " ${BULLET} ${BOLD}Iteration Limits${NC}: --max-iters ${MAX_ITERS}, timeouts ${TIMEOUT_SEC}s" | |
| echo -e " ${BULLET} ${BOLD}Safety Limits${NC}: ≤5 files, ≤40 LOC" | |
| echo | |
| if ! ask_yes "Ready to begin?" "Y"; then | |
| echo -e "${DIM}Come back when you're ready.${NC}" | |
| exit 0 | |
| fi | |
| # Step 1: Workspace | |
| step 1 6 "Create isolated workspace" "$PACKAGE" | |
| DEMO_DIR="/tmp/nova-ci-iter-$(date +%s)" | |
| rm -rf "$DEMO_DIR" 2>/dev/null || true | |
| mkdir -p "$DEMO_DIR" | |
| cd "$DEMO_DIR" | |
| ok "Workspace: $DEMO_DIR" | |
| # Step 2: Python env | |
| step 2 6 "Set up Python environment" "$PACKAGE" | |
| python3 -m venv .venv | |
| source .venv/bin/activate | |
| python3 -m pip install --upgrade pip >/dev/null 2>&1 | |
| ok "Virtualenv ready" | |
| # Step 3: Install Nova | |
| step 3 6 "Install Nova CI-Rescue" "$ROCKET" | |
| info "Installing from Cloudsmith mirror + PyPI" | |
| python3 -m pip install --quiet \ | |
| nova-ci-rescue pytest pytest-json-report openai requests \ | |
| --index-url "https://dl.cloudsmith.io/9rqxsQdhFkYzaXqm/nova/nova-ci-rescue/python/simple/" \ | |
| --extra-index-url "https://pypi.org/simple/" \ | |
| 2>&1 | grep -v "Requirement already satisfied" || true | |
| version=$(nova --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "latest") | |
| ok "Nova ${version} installed" | |
| # Step 4: Create demo project | |
| step 4 6 "Set up demo project" "$BRAIN" | |
| # Check for GitHub integration | |
| SKIP_GITHUB=false | |
| if ! command -v gh &> /dev/null; then | |
| warn "GitHub CLI not found. Running local demo only." | |
| info "To enable GitHub integration, install from: https://cli.github.com" | |
| SKIP_GITHUB=true | |
| else | |
| # Unset any existing GitHub tokens to avoid conflicts | |
| unset GITHUB_TOKEN | |
| unset GH_TOKEN | |
| # Check for PAT | |
| if [ -z "${CHAPTER_ONE_PAT:-}" ]; then | |
| err "GitHub Personal Access Token required" | |
| echo | |
| echo "The demo PATs have expired. Please create your own:" | |
| echo | |
| echo " 1. Go to: ${BOLD}https://github.com/settings/tokens/new${NC}" | |
| echo " 2. Give it a name (e.g., 'Nova Demo')" | |
| echo " 3. Select scopes:" | |
| echo " ${CHECK} repo (all)" | |
| echo " ${CHECK} workflow" | |
| echo " 4. Click 'Generate token' and copy it" | |
| echo " 5. Run: ${BOLD}export CHAPTER_ONE_PAT='your-token-here'${NC}" | |
| echo " 6. Then run this demo again" | |
| echo | |
| echo "Note: GitHub PATs expire and need to be regenerated periodically." | |
| exit 1 | |
| else | |
| # Test the provided PAT | |
| if ! GH_TOKEN="$CHAPTER_ONE_PAT" gh api user &>/dev/null; then | |
| err "Provided PAT is invalid or expired" | |
| echo | |
| # Get more details about why it failed | |
| ERROR_MSG=$(GH_TOKEN="$CHAPTER_ONE_PAT" gh api user 2>&1 | grep -o '"message":"[^"]*"' | cut -d'"' -f4) | |
| echo "GitHub API error: $ERROR_MSG" | |
| echo | |
| echo "Please check your CHAPTER_ONE_PAT environment variable" | |
| echo "You may need to create a new token at: https://github.com/settings/tokens/new" | |
| exit 1 | |
| fi | |
| ok "Using provided CHAPTER_ONE_PAT" | |
| fi | |
| fi | |
| # Create project directory | |
| if [ "$SKIP_GITHUB" = false ]; then | |
| # Create GitHub repo | |
| REPO_NAME="nova-demo-ci-$(date +%s)" | |
| info "Creating GitHub repository: $REPO_NAME" | |
| GH_TOKEN="$CHAPTER_ONE_PAT" gh repo create "$REPO_NAME" --public --clone --description "Nova CI Demo - Automated test fixing" 2>&1 | grep -v "Cloning into" || true | |
| cd "$REPO_NAME" | |
| else | |
| # Create local directory | |
| REPO_NAME="nova-demo-local" | |
| mkdir -p "$REPO_NAME" | |
| cd "$REPO_NAME" | |
| git init | |
| git config user.email "demo@joinnova.com" | |
| git config user.name "Nova Demo" | |
| ok "Local demo repository created" | |
| fi | |
| # Copy demo files | |
| info "Setting up broken calculator demo..." | |
| cat > calculator.py << 'EOF' | |
| """ | |
| Broken Calculator - Nova CI-Rescue Demo | |
| ======================================== | |
| This calculator has bugs in EVERY function! | |
| Perfect for demonstrating Nova CI-Rescue's ability to fix multiple issues. | |
| Each function has a deliberate bug that causes incorrect results. | |
| The tests will expose these bugs, and Nova will fix them automatically. | |
| """ | |
| def add(a, b): | |
| """Add two numbers together.""" | |
| return a + b + 1 | |
| def subtract(a, b): | |
| """Subtract b from a.""" | |
| return a + b | |
| def multiply(a, b): | |
| """Multiply two numbers.""" | |
| return a + b | |
| EOF | |
| cat > test_calculator.py << 'EOF' | |
| """ | |
| Test suite for calculator.py | |
| ============================ | |
| These tests will reveal the bugs in each calculator function. | |
| Nova CI-Rescue will automatically fix the failing tests. | |
| """ | |
| import pytest | |
| from calculator import ( | |
| add, subtract, multiply, divide, power, | |
| modulo, absolute, square_root, factorial, max_of_two | |
| ) | |
| class TestCalculator: | |
| """Test cases for the calculator functions.""" | |
| def test_addition(self): | |
| """Test the add function.""" | |
| assert add(2, 3) == 5 | |
| assert add(-1, 1) == 0 | |
| assert add(0, 0) == 0 | |
| assert add(100, 200) == 300 | |
| def test_subtraction(self): | |
| """Test the subtract function.""" | |
| assert subtract(10, 3) == 7 | |
| assert subtract(0, 5) == -5 | |
| assert subtract(-5, -3) == -2 | |
| assert subtract(100, 100) == 0 | |
| def test_multiplication(self): | |
| """Test the multiply function.""" | |
| assert multiply(3, 4) == 12 | |
| assert multiply(-2, 3) == -6 | |
| assert multiply(0, 100) == 0 | |
| assert multiply(7, 8) == 56 | |
| EOF | |
| # Create GitHub workflow | |
| mkdir -p .github/workflows | |
| cat > .github/workflows/nova-ci.yml << 'EOF' | |
| name: Nova CI-Rescue | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v3 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.x' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install pytest pytest-json-report openai requests | |
| pip install nova-ci-rescue --index-url https://dl.cloudsmith.io/9rqxsQdhFkYzaXqm/nova/nova-ci-rescue/python/simple/ --extra-index-url https://pypi.org/simple/ | |
| - name: Run tests | |
| id: test | |
| run: | | |
| pytest test_calculator.py -v || echo "Tests failed as expected" | |
| - name: Nova Auto-Fix | |
| if: failure() | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Set git config | |
| git config --global user.email "nova-ci@joinnova.com" | |
| git config --global user.name "Nova CI Bot" | |
| # Run Nova with safety limits | |
| nova fix --max-iters 3 --timeout 600 --ci "pytest test_calculator.py" | |
| # Create PR if changes made | |
| if [ -n "$(git status --porcelain)" ]; then | |
| BRANCH="nova-fix/$(date +%Y%m%d_%H%M%S)" | |
| git checkout -b "$BRANCH" | |
| git add -A | |
| git commit -m "Nova CI: Auto-fix failing tests" | |
| git push origin "$BRANCH" | |
| gh pr create \ | |
| --title "Nova CI: Auto-fix failing tests" \ | |
| --body "This PR was automatically generated by Nova CI-Rescue to fix failing tests." \ | |
| --base main | |
| fi | |
| EOF | |
| # Initial commit | |
| git add -A | |
| git commit -m "Initial commit with broken calculator" | |
| if [ "$SKIP_GITHUB" = false ]; then | |
| # Set GitHub secret | |
| info "Setting up GitHub secrets..." | |
| GH_TOKEN="$CHAPTER_ONE_PAT" gh secret set OPENAI_API_KEY --body "$OPENAI_API_KEY" || true | |
| # Push to trigger CI | |
| git push -u origin main | |
| ok "Repository created: https://github.com/$(gh repo view --json nameWithOwner -q .nameWithOwner)" | |
| else | |
| ok "Local repository ready" | |
| fi | |
| # Preview | |
| preview_file "calculator.py" "(broken implementation)" | |
| # Step 5: Run Nova fix | |
| if [ "$SKIP_GITHUB" = false ]; then | |
| step 5 6 "Monitor CI pipeline" "$SHIELD" | |
| # Get the workflow run URL | |
| REPO_URL="https://github.com/$(gh repo view --json nameWithOwner -q .nameWithOwner)" | |
| echo -e "${DIM}Repository:${NC} $REPO_URL" | |
| echo -e "${DIM}Actions:${NC} $REPO_URL/actions" | |
| echo | |
| info "Waiting for CI workflow to start..." | |
| # Wait for workflow to start | |
| sleep 5 | |
| # Get the latest run | |
| RUN_ID=$(GH_TOKEN="$CHAPTER_ONE_PAT" gh run list --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "") | |
| if [ -n "$RUN_ID" ]; then | |
| RUN_URL="$REPO_URL/actions/runs/$RUN_ID" | |
| ok "CI workflow started: $RUN_URL" | |
| echo | |
| # Monitor the run | |
| info "Monitoring CI run (this may take 1-2 minutes)..." | |
| echo -e "${DIM}Nova will automatically fix the failing tests...${NC}" | |
| echo | |
| # Poll for status | |
| MAX_WAIT=180 # 3 minutes | |
| ELAPSED=0 | |
| while [ $ELAPSED -lt $MAX_WAIT ]; do | |
| STATUS=$(GH_TOKEN="$CHAPTER_ONE_PAT" gh run view $RUN_ID --json status --jq '.status' 2>/dev/null || echo "") | |
| CONCLUSION=$(GH_TOKEN="$CHAPTER_ONE_PAT" gh run view $RUN_ID --json conclusion --jq '.conclusion' 2>/dev/null || echo "") | |
| if [ "$STATUS" = "completed" ]; then | |
| if [ "$CONCLUSION" = "success" ]; then | |
| ok "CI run completed successfully!" | |
| else | |
| warn "CI run completed with status: $CONCLUSION" | |
| fi | |
| break | |
| fi | |
| # Show progress | |
| printf "." | |
| sleep 5 | |
| ELAPSED=$((ELAPSED + 5)) | |
| done | |
| echo | |
| echo | |
| # Check for PR created by Nova | |
| info "Checking for Nova-generated PR..." | |
| sleep 3 | |
| PR_NUMBER=$(GH_TOKEN="$CHAPTER_ONE_PAT" gh pr list --state open --json number,title --jq '.[] | select(.title | contains("Nova")) | .number' | head -1) | |
| if [ -n "$PR_NUMBER" ]; then | |
| PR_URL="$REPO_URL/pull/$PR_NUMBER" | |
| ok "Nova created PR #$PR_NUMBER: $PR_URL" | |
| echo | |
| # Show PR details | |
| echo -e "${BOLD}Pull Request Summary:${NC}" | |
| GH_TOKEN="$CHAPTER_ONE_PAT" gh pr view $PR_NUMBER --json title,body,additions,deletions,changedFiles --jq ' | |
| "Title: \(.title)\n" + | |
| "Files changed: \(.changedFiles)\n" + | |
| "Lines added: +\(.additions)\n" + | |
| "Lines deleted: -\(.deletions)" | |
| ' | sed 's/^/ /' | |
| echo | |
| # Show the diff | |
| echo -e "${BOLD}Changes made by Nova:${NC}" | |
| GH_TOKEN="$CHAPTER_ONE_PAT" gh pr diff $PR_NUMBER --color always | head -50 | |
| else | |
| warn "No PR found yet. Check $REPO_URL/pulls" | |
| fi | |
| else | |
| warn "Could not detect CI run. Check manually at: $REPO_URL/actions" | |
| fi | |
| else | |
| step 5 6 "Run Nova CI Mode locally" "$SHIELD" | |
| # Run tests to show failures | |
| info "Running tests to identify failures..." | |
| export PYTHONPATH="." | |
| set +e | |
| python3 -m pytest test_calculator.py -v --tb=short --no-header | \ | |
| sed -e 's/FAILED/\x1b[31mFAILED\x1b[0m/g' -e 's/PASSED/\x1b[32mPASSED\x1b[0m/g' | |
| initial_rc=$? | |
| set -e | |
| echo | |
| echo -e "${BOLD}${RED}${CROSS} Tests failing${NC} - Nova will now fix them" | |
| echo | |
| # API key setup | |
| if [ -z "${OPENAI_API_KEY:-}" ]; then | |
| [ -f "$HOME/.nova.env" ] && source "$HOME/.nova.env" || true | |
| if [ -z "${OPENAI_API_KEY:-}" ]; then | |
| if [ "$FORCE_YES" = true ]; then | |
| err "OPENAI_API_KEY required in environment" | |
| exit 1 | |
| fi | |
| printf "${BOLD}Enter OPENAI_API_KEY:${NC} " | |
| read -rs OPENAI_API_KEY | |
| echo | |
| export OPENAI_API_KEY | |
| fi | |
| fi | |
| # Run Nova fix | |
| echo -e "${DIM}Options:${NC} --ci=\"$CI_CMD\" --max-iters=${MAX_ITERS} --timeout=${TIMEOUT_SEC}s (Safety: ≤5 files, ≤40 LOC)" | |
| echo | |
| export NOVA_CI_CMD="$CI_CMD" | |
| if [ "$VERBOSE" = true ]; then | |
| nova fix --max-iters "$MAX_ITERS" --timeout "$TIMEOUT_SEC" | |
| else | |
| echo -e "${DIM}Running Nova...${NC}" | |
| echo -e "${DIM}This may take 30-60 seconds...${NC}" | |
| echo | |
| # Capture Nova output to show progress | |
| local nova_output=$(nova fix --max-iters "$MAX_ITERS" --timeout "$TIMEOUT_SEC" 2>&1) | |
| local nova_result=$? | |
| # Show filtered output | |
| echo "$nova_output" | grep -E "(Running tests|Test results|Fixing|Fixed|Iteration|All tests|PASSED|FAILED|Error:|Failed to|Successfully|Analyzing|Creating|Applying)" | sed 's/^/ /' | |
| # If Nova failed or produced no output, show full output | |
| if [ $nova_result -ne 0 ] || [ -z "$(echo "$nova_output" | grep -E "(Running tests|Fixing|Fixed)")" ]; then | |
| echo | |
| print_warning "Showing full Nova output:" | |
| echo "$nova_output" | sed 's/^/ /' | |
| fi | |
| fi | |
| # Show results | |
| echo | |
| info "Verifying fixes..." | |
| set +e | |
| python3 -m pytest test_calculator.py -v --tb=no --no-header | sed -e 's/PASSED/\x1b[32mPASSED\x1b[0m/g' -e 's/FAILED/\x1b[31mFAILED\x1b[0m/g' | |
| final_rc=$? | |
| set -e | |
| if [ $final_rc -eq 0 ]; then | |
| ok "ALL TESTS PASS — Nova fixed the suite!" | |
| echo | |
| echo -e "${BOLD}Changes made:${NC}" | |
| git --no-pager diff --stat || true | |
| echo | |
| echo -e "${BOLD}Branch:${NC}" | |
| git branch --show-current | sed 's/^/ ➜ /' | |
| else | |
| warn "Some tests still failing — check iteration limits" | |
| fi | |
| fi | |
| # Step 6: Summary | |
| step 6 6 "Summary" "$SPARKLE" | |
| echo -e "${BOLD}What we demonstrated:${NC}" | |
| echo " ${CHECK} Real GitHub repository with failing tests" | |
| echo " ${CHECK} GitHub Actions CI pipeline" | |
| echo " ${CHECK} Nova automatically fixing tests in CI" | |
| echo " ${CHECK} Pull Request created by Nova" | |
| echo " ${CHECK} Safety limits enforced (≤5 files, ≤40 LOC)" | |
| echo | |
| thr | |
| echo -e "${BOLD}${PURPLE} Key Safety Points${NC}" | |
| hr | |
| echo " ${CHECK} Branch isolation: nova/fix/* (never commits to main)" | |
| echo " ${CHECK} Human review: PR flow for all changes" | |
| echo " ${CHECK} Safety limits: ≤5 files, ≤40 LOC per change" | |
| echo " ${CHECK} Iteration cap: --max-iters ${MAX_ITERS} prevents infinite loops" | |
| echo " ${CHECK} Timeout protection: ${TIMEOUT_SEC}s max runtime" | |
| echo | |
| if [ "$SKIP_GITHUB" = false ]; then | |
| echo -e "${DIM}Repository:${NC} ${BOLD}$REPO_URL${NC}" | |
| echo -e "${DIM}GitHub Actions:${NC} ${BOLD}$REPO_URL/actions${NC}" | |
| echo -e "${DIM}Pull Requests:${NC} ${BOLD}$REPO_URL/pulls${NC}" | |
| else | |
| echo -e "${DIM}Demo workspace:${NC} ${BOLD}$DEMO_DIR/$REPO_NAME${NC}" | |
| fi | |
| echo | |
| echo -e "${DIM}To use Nova in your CI:${NC}" | |
| echo " 1. Add the workflow file to .github/workflows/" | |
| echo " 2. Set OPENAI_API_KEY as a repository secret" | |
| echo " 3. Push failing tests and watch Nova fix them!" | |
| } | |
| ######################################## | |
| # Entry Point | |
| ######################################## | |
| for c in python3 git; do | |
| command -v "$c" >/dev/null 2>&1 || { echo "Error: $c is required." >&2; exit 1; } | |
| done | |
| # Cleanup function | |
| cleanup() { | |
| local exit_code=$? | |
| if [ $exit_code -ne 0 ]; then | |
| echo | |
| echo -e "${YELLOW}Demo interrupted or failed${NC}" | |
| fi | |
| # Deactivate virtual environment if active | |
| if [ -n "${VIRTUAL_ENV:-}" ]; then | |
| deactivate 2>/dev/null || true | |
| fi | |
| echo -e "${DIM}Thank you for trying Nova CI-Rescue${NC}" | |
| exit $exit_code | |
| } | |
| # Set trap for cleanup | |
| trap cleanup EXIT INT TERM | |
| # Run the demo | |
| run_demo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment