diff --git a/README.md b/README.md index 64cd91b5..908234fe 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,20 @@ -## 🧐 What is The Director? +## 📚 Table of Contents +- [🧐 What is The Director?](#what-is-the-director) +- [⭐️ Key Features](#key-features) +- [😎 Agent Examples](#agent-examples) +- [⚙️ Architecture Overview](#architecture-overview) +- [🧠 Reasoning Engine](#reasoning-engine) +- [🏃 Getting Started](#getting-started) +- [🚀 Running the Application](#running-the-application) +- [📘 Creating a New Agent](#creating-a-new-agent) +- [📖 Documentation](#documentation) +- [🤝 Contributing](#contributing) + + +## 🧐 What is The Director? Think of Director as ChatGPT for videos. It is a framework to build video agents that can reason through complex video tasks like search, editing, compilation, generation etc & instantly stream the results. @@ -72,6 +85,7 @@ https://github.com/user-attachments/assets/33e0e7b4-9eb2-4a26-8274-f96c2c1c3a48
+ ## ⭐️ Key Features ### 🤖 20+ pre-built video agents that you can customize to * Summarize videos in seconds. @@ -95,12 +109,14 @@ Easily add new agents and tools to your workflow. Whether you want to run it loc
+ ## 😎 Agent Examples 1. Highlight Creator: [link](https://www.youtube.com/watch?v=Dncn_0RWrro&list=PLhxAMFLSSK039xl1UgcZmoFLnb-qNRYQw&index=11) 2. Text to Movie: [link](https://www.youtube.com/watch?v=QpnRxuEBDCc&list=PLhxAMFLSSK039xl1UgcZmoFLnb-qNRYQw&index=2) 3. Video Search: [link](https://www.youtube.com/watch?v=kCiCI2KCnC8&list=PLhxAMFLSSK039xl1UgcZmoFLnb-qNRYQw&index=4) + ## ⚙️ Architecture Overview Director's architecture brings together: @@ -111,7 +127,8 @@ Director's architecture brings together: ![Director architecture](https://github.com/user-attachments/assets/9afb2783-66db-4899-9308-03cbd12e74d7) -## 🧠 **Reasoning Engine** + +## 🧠 Reasoning Engine At the heart of The Director is its **Reasoning Engine**, a powerful core that drives intelligent decision-making and dynamic workflows. It acts as the brain behind the agents, enabling them to process commands, interact with data, and deliver meaningful outputs. @@ -135,67 +152,91 @@ For a closer look, check out the detailed architecture diagram below: + ## 🏃 Getting Started ### Prerequisites -- Python 3.9 or higher -- Node.js 22.8.0 or higher -- npm +- **Python 3.9 or higher** +- **Node.js 22.8.0 or higher** +- **npm** ### Installation **1. Clone the repository:** -``` bash +```bash git clone https://github.com/video-db/Director.git cd Director ``` **2. Run the setup script:** +**For Mac/Linux:** ```bash ./setup.sh ``` +**For Windows:** +```cmd +setup.bat +``` + > This script will: -> - Install Node.js 22.8.0 using nvm +> - Install Node.js 22.8.0 using nvm (Mac/Linux) +> - Verify Python 3.9+ and Node.js 22.8.0+ are installed (Windows) > - Install Python and pip -> - Set up virtual environments for both frontend and backend. - - +> - Set up virtual environments for both frontend and backend **3. Configure the environment variables:** Edit the `.env` files to add your API keys and other configuration options. -### Supported platforms: -- Mac -- Linux -- Windows (WSL) +Get your free VideoDB API key from [console.videodb.io](https://console.videodb.io/) -## 💬 Running the Application +### Supported Platforms +- ✅ **Mac** +- ✅ **Linux** +- ✅ **Windows** (native) +- ✅ **Windows (WSL)** -To start both the backend and frontend servers: +--- + + +## 🚀 Running the Application +**For Mac/Linux:** + +To start both the backend and frontend servers: ```bash make run ``` - Backend: `http://127.0.0.1:8000` - - Frontend: `http://127.0.0.1:8080` -For specific tasks: - +**For specific tasks:** - Backend only: `make run-be` - - Frontend only: `make run-fe` +**For Windows:** + +To start both servers: +```cmd +start-all.bat +``` + +This will open two windows (backend and frontend). The application will be available at: +- Backend: `http://127.0.0.1:8000` +- Frontend: `http://127.0.0.1:8080` +**For specific tasks:** +- Backend only: `start-backend.bat` +- Frontend only: `start-frontend.bat` - +--- + ## 📘 Creating a New Agent > Checkout hosted documentation at https://docs.director.videodb.io @@ -234,6 +275,7 @@ Duplicate `sample_agent.py` in `Director/backend/director/agents/` and rename it Remember to consider creating reusable tools if your agent's functionality could be shared across multiple agents. + ## 📖 Documentation > Checkout hosted documentation at https://docs.director.videodb.io ### Serve Locally @@ -253,6 +295,7 @@ mkdocs build + ## 🤝 Contributing We welcome integrations from projects that can make video workflows easy and increase capabilities of the projects. Please check issues and discussions for details. diff --git a/setup.bat b/setup.bat new file mode 100644 index 00000000..80cb6279 --- /dev/null +++ b/setup.bat @@ -0,0 +1,265 @@ +@echo off +setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +echo. +echo === Director Setup (Windows) === +echo. + +:: Locate Python +set "PY_CMD=" +where py >nul 2>nul && set "PY_CMD=py -3" +if "%PY_CMD%"=="" ( + where python >nul 2>nul && set "PY_CMD=python" +) +if "%PY_CMD%"=="" ( + echo [ERROR] Python 3.9+ not found. Install it from https://www.python.org/downloads/ + goto :fail +) +for /f "tokens=2" %%v in ('%PY_CMD% --version 2^>^&1') do set "PY_VER=%%v" +echo [OK] Python %PY_VER% + +:: Locate Node.js and npm +where node >nul 2>nul || ( + echo [ERROR] Node.js not found. Install it from https://nodejs.org/ + goto :fail +) +for /f "tokens=*" %%v in ('node --version 2^>^&1') do set "NODE_VER=%%v" +set "NODE_VER_CLEAN=%NODE_VER%" +if /i "%NODE_VER_CLEAN:~0,1%"=="v" set "NODE_VER_CLEAN=%NODE_VER_CLEAN:~1%" +set "NODE_MAJ=" +set "NODE_MIN=" +set "NODE_PATCH=" +for /f "tokens=1-3 delims=." %%a in ("%NODE_VER_CLEAN%") do ( + set "NODE_MAJ=%%a" + set "NODE_MIN=%%b" + set "NODE_PATCH=%%c" +) +if "%NODE_MAJ%"=="" set "NODE_MAJ=0" +if "%NODE_MIN%"=="" set "NODE_MIN=0" +if "%NODE_PATCH%"=="" set "NODE_PATCH=0" +for /f "tokens=1 delims=-" %%p in ("%NODE_MAJ%") do set "NODE_MAJ=%%p" +for /f "tokens=1 delims=-" %%p in ("%NODE_MIN%") do set "NODE_MIN=%%p" +for /f "tokens=1 delims=-" %%p in ("%NODE_PATCH%") do set "NODE_PATCH=%%p" + +set /a NODE_REQUIRED=22*10000 + 8*100 + 0 >nul 2>&1 +set /a NODE_VALUE=%NODE_MAJ%*10000 + %NODE_MIN%*100 + %NODE_PATCH% >nul 2>&1 +if %NODE_VALUE% LSS %NODE_REQUIRED% ( + echo [ERROR] Node.js 22.8.0 or higher required. Detected %NODE_VER%. + goto :fail +) +echo [OK] Node.js %NODE_VER% + +where npm >nul 2>nul || ( + echo [ERROR] npm not found. Reinstall Node.js from https://nodejs.org/ + goto :fail +) +for /f "tokens=*" %%v in ('npm --version 2^>^&1') do set "NPM_VER=%%v" +echo [OK] npm %NPM_VER% + +echo. +echo Setting up backend... +pushd backend || goto :fail + +if not exist venv ( + echo Creating virtual environment... + %PY_CMD% -m venv venv || goto :fail_backend +) + +call venv\Scripts\activate.bat || goto :fail_backend + +echo Installing backend requirements... +pip install --upgrade pip setuptools wheel >nul 2>&1 +pip install -r requirements.txt || goto :fail_backend +if exist requirements-dev.txt ( + pip install -r requirements-dev.txt || goto :fail_backend +) + +pip check >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Backend dependencies are inconsistent. Resolve pip errors above. + goto :fail_backend +) + +if not exist .env ( + if exist .env.sample ( + copy /y .env.sample .env >nul + echo DB_TYPE=sqlite >> .env + ) else ( + ( + echo VIDEO_DB_API_KEY= + echo. + echo # Database + echo DB_TYPE=sqlite + )> .env + ) +) +call :set_env_value ".env" "DB_TYPE" "sqlite" + +echo Initializing SQLite database... +set SQLITE_DB_PATH=director.db +%PY_CMD% director\db\sqlite\initialize.py >nul 2>&1 + +call venv\Scripts\deactivate.bat >nul 2>&1 +popd +echo [OK] Backend ready + +echo. +echo Setting up frontend... +pushd frontend || goto :fail + +call :ensure_patch_package +if errorlevel 1 goto :fail_frontend + +echo Installing frontend dependencies... +set "NPM_LOCK_PRESENT=" +if exist package-lock.json set "NPM_LOCK_PRESENT=1" + +if defined NPM_LOCK_PRESENT ( + echo Running npm ci ^(clean install^)... + call npm ci >nul 2>&1 + if errorlevel 1 ( + echo [WARN] npm ci failed. Retrying with npm install... + call npm install || goto :fail_frontend + ) +) else ( + echo Running npm install... + call npm install || goto :fail_frontend +) + +set "FRONTEND_READY=" +for %%R in (1 2) do ( + if not defined FRONTEND_READY ( + if exist node_modules\.bin\vite.cmd set "FRONTEND_READY=1" + ) + if not defined FRONTEND_READY ( + if exist node_modules\.bin\vite.ps1 set "FRONTEND_READY=1" + ) + if not defined FRONTEND_READY ( + if exist node_modules\vite\package.json set "FRONTEND_READY=1" + ) + + if not defined FRONTEND_READY ( + if %%R==1 ( + echo [WARN] Frontend dependencies incomplete. Cleaning node_modules and reinstalling... + if exist node_modules rmdir /s /q node_modules + if defined NPM_LOCK_PRESENT ( + call npm ci || goto :fail_frontend + ) else ( + call npm install || goto :fail_frontend + ) + ) + ) +) + +:frontend_verified +if not defined FRONTEND_READY ( + echo [ERROR] Unable to verify frontend dependencies. + goto :fail_frontend +) + +set "VITE_VERSION=" +for /f "usebackq tokens=* delims=" %%v in (`node -p "require('./node_modules/vite/package.json').version" 2^>^&1`) do ( + set "VITE_VERSION=%%v" + goto :vite_version_ready +) +:vite_version_ready + +if not exist .env ( + ( + echo VITE_APP_BACKEND_URL=http://127.0.0.1:8000 + echo VITE_PORT=8080 + echo VITE_OPEN_BROWSER=true + )> .env +) + +if defined VITE_VERSION ( + echo [OK] Frontend ready ^(Vite !VITE_VERSION!^) +) else ( + echo [OK] Frontend ready +) + +echo. +echo Setup complete. +echo Update backend\.env with your VIDEO_DB_API_KEY before running. +echo Use start-all.bat to launch both services. +echo For individual control: start-backend.bat or start-frontend.bat +echo. +exit /b 0 + +:set_env_value +setlocal ENABLEDELAYEDEXPANSION +set "ENV_FILE=%~1" +set "ENV_KEY=%~2" +set "ENV_VALUE=%~3" + +if not exist "%ENV_FILE%" ( + >"%ENV_FILE%" echo %ENV_KEY%=%ENV_VALUE% + endlocal & exit /b 0 +) + +set "TEMP_FILE=%ENV_FILE%.tmp" +set "VAR_WRITTEN=" +( + for /f "usebackq delims=" %%L in ("%ENV_FILE%") do ( + set "LINE=%%L" + set "WRITE_LINE=1" + for /f "tokens=1* delims==" %%K in ("!LINE!") do ( + set "KEY=%%K" + if /i "!KEY!"=="%ENV_KEY%" ( + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + set "VAR_WRITTEN=1" + ) + set "WRITE_LINE=" + ) + ) + if defined WRITE_LINE ( + echo !LINE! + ) + ) + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + ) +) >"%TEMP_FILE%" +move /Y "%TEMP_FILE%" "%ENV_FILE%" >nul +endlocal & exit /b 0 + +:ensure_patch_package +set "PATCH_PACKAGE_READY=" +where patch-package >nul 2>&1 && set "PATCH_PACKAGE_READY=1" +if not defined PATCH_PACKAGE_READY ( + if exist node_modules\.bin\patch-package.cmd set "PATCH_PACKAGE_READY=1" +) +if not defined PATCH_PACKAGE_READY ( + if exist node_modules\.bin\patch-package.ps1 set "PATCH_PACKAGE_READY=1" +) + +if not defined PATCH_PACKAGE_READY ( + echo Ensuring patch-package is available for npm lifecycle scripts... + npm install -g patch-package >nul 2>&1 + if errorlevel 1 ( + echo [ERROR] Unable to install patch-package globally. Run "npm install -g patch-package" manually and retry. + exit /b 1 + ) + where patch-package >nul 2>&1 && set "PATCH_PACKAGE_READY=1" + if not defined PATCH_PACKAGE_READY ( + echo [ERROR] patch-package is still unavailable after installation. Confirm your npm global bin directory is on PATH and retry. + exit /b 1 + ) +) + +exit /b 0 + +:fail_frontend +popd +goto :fail + +:fail_backend +popd + +:fail +echo. +echo Setup failed. Review the messages above. +pause +exit /b 1 + diff --git a/start-all.bat b/start-all.bat new file mode 100644 index 00000000..122b83f7 --- /dev/null +++ b/start-all.bat @@ -0,0 +1,26 @@ +@echo off +setlocal + +cd /d "%~dp0" || exit /b 1 + +if not exist "backend\venv\Scripts\activate.bat" ( + echo Backend not initialized. Run setup.bat first. + exit /b 1 +) + +if not exist "frontend\node_modules\" ( + echo Frontend dependencies will be installed on first launch. +) + +set "LAUNCH_DIR=%CD%" +echo Launching backend window... +start "" cmd /k call "%LAUNCH_DIR%\start-backend.bat" +echo Backend window launched. +timeout /t 2 /nobreak >nul +echo Launching frontend window... +start "" cmd /k call "%LAUNCH_DIR%\start-frontend.bat" +echo Frontend window launched. + +echo Backend: http://127.0.0.1:8000 +echo Frontend: http://127.0.0.1:8080 +echo Close the backend and frontend windows to stop the services. diff --git a/start-backend.bat b/start-backend.bat new file mode 100644 index 00000000..58dc8873 --- /dev/null +++ b/start-backend.bat @@ -0,0 +1,93 @@ +@echo off +setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +cd /d "%~dp0backend" || exit /b 1 + +if not exist "venv\Scripts\activate.bat" ( + echo Backend not initialized. Run setup.bat first. + exit /b 1 +) + +call :ensure_backend_env +if errorlevel 1 exit /b 1 + +echo Backend: http://127.0.0.1:8000 (Ctrl+C to stop) +call venv\Scripts\activate.bat +set "DB_TYPE=sqlite" +set SQLITE_DB_PATH=director.db +pip check >nul 2>&1 +if errorlevel 1 ( + echo Backend dependencies incomplete. Reinstalling requirements... + pip install --upgrade pip setuptools wheel >nul 2>&1 + pip install -r requirements.txt || goto :deps_fail + if exist requirements-dev.txt ( + pip install -r requirements-dev.txt || goto :deps_fail + ) + pip check || goto :deps_fail +) +python director\db\sqlite\initialize.py >nul 2>&1 +if errorlevel 1 ( + echo SQLite initialization failed. + exit /b 1 +) +python director\entrypoint\api\server.py +exit /b %errorlevel% + +:ensure_backend_env +set "ENV_FILE=.env" +if not exist "%ENV_FILE%" ( + if exist .env.sample ( + copy /y .env.sample .env >nul + ) else ( + ( + echo VIDEO_DB_API_KEY= + echo. + echo # Database + )> "%ENV_FILE%" + ) +) + +call :set_env_value "%ENV_FILE%" "DB_TYPE" "sqlite" +exit /b %errorlevel% + +:set_env_value +setlocal ENABLEDELAYEDEXPANSION +set "ENV_FILE=%~1" +set "ENV_KEY=%~2" +set "ENV_VALUE=%~3" + +if not exist "%ENV_FILE%" ( + >"%ENV_FILE%" echo %ENV_KEY%=%ENV_VALUE% + endlocal & exit /b 0 +) + +set "TEMP_FILE=%ENV_FILE%.tmp" +set "VAR_WRITTEN=" +( + for /f "usebackq delims=" %%L in ("%ENV_FILE%") do ( + set "LINE=%%L" + set "WRITE_LINE=1" + for /f "tokens=1* delims==" %%K in ("!LINE!") do ( + set "KEY=%%K" + if /i "!KEY!"=="%ENV_KEY%" ( + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + set "VAR_WRITTEN=1" + ) + set "WRITE_LINE=" + ) + ) + if defined WRITE_LINE ( + echo !LINE! + ) + ) + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + ) +) >"%TEMP_FILE%" +move /Y "%TEMP_FILE%" "%ENV_FILE%" >nul +endlocal & exit /b 0 + +:deps_fail +echo Failed to reinstall backend dependencies. Review the messages above. +exit /b 1 diff --git a/start-frontend.bat b/start-frontend.bat new file mode 100644 index 00000000..030f8a85 --- /dev/null +++ b/start-frontend.bat @@ -0,0 +1,220 @@ +@echo off +setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +cd /d "%~dp0frontend" || exit /b 1 + +where npm >nul 2>&1 || ( + echo npm not found. Install Node.js from https://nodejs.org/ and rerun setup.bat. + exit /b 1 +) + +call :ensure_frontend_deps +if errorlevel 1 goto :deps_fail + +call :configure_frontend_runtime +if errorlevel 1 goto :deps_fail + +set "VITE_VERSION=" +for /f "usebackq tokens=* delims=" %%v in (`node -p "require('./node_modules/vite/package.json').version" 2^>^&1`) do ( + set "VITE_VERSION=%%v" + goto :have_vite_version +) +:have_vite_version +if defined VITE_VERSION ( + echo Frontend dependencies ready ^(Vite !VITE_VERSION!^). +) else ( + echo Frontend dependencies ready. +) + +if not defined VITE_PORT set "VITE_PORT=8080" +if not defined VITE_BIND_HOST set "VITE_BIND_HOST=0.0.0.0" + +if /i "%VITE_BIND_HOST%"=="0.0.0.0" ( + echo Frontend: http://127.0.0.1:%VITE_PORT% ^(Ctrl+C to stop^) +) else ( + echo Frontend: http://%VITE_BIND_HOST%:%VITE_PORT% ^(Ctrl+C to stop^) +) + +call npm run dev -- --host %VITE_BIND_HOST% --port %VITE_PORT% +exit /b %errorlevel% + +:deps_fail +echo Failed to prepare frontend dependencies. Run setup.bat and review the output. +exit /b 1 + +:ensure_frontend_deps +if not exist package.json ( + echo Frontend source missing. Run setup.bat first. + exit /b 1 +) + +call :ensure_patch_package +if errorlevel 1 exit /b 1 + +if exist node_modules\vite\package.json ( + if exist node_modules\.bin\vite.cmd goto :deps_ok + if exist node_modules\.bin\vite.ps1 goto :deps_ok +) + +if exist node_modules ( + echo Detected incomplete frontend installation. Cleaning node_modules... + rmdir /s /q node_modules +) + +if exist package-lock.json ( + echo Installing frontend dependencies with npm ci... + call npm ci || exit /b 1 +) else ( + echo Installing frontend dependencies with npm install... + call npm install || exit /b 1 +) + +if not exist node_modules\vite\package.json exit /b 1 +if not exist node_modules\.bin\vite.cmd ( + if not exist node_modules\.bin\vite.ps1 exit /b 1 +) + +:deps_ok +exit /b 0 + +:configure_frontend_runtime +set "ENV_FILE=.env" +if not exist "%ENV_FILE%" ( + if exist .env.sample ( + copy /y .env.sample .env >nul + ) else ( + ( + echo VITE_APP_BACKEND_URL=http://127.0.0.1:8000 + echo VITE_PORT=8080 + echo VITE_OPEN_BROWSER=true + )> "%ENV_FILE%" + ) +) + +set "REQUESTED_PORT=" +if exist "%ENV_FILE%" ( + for /f "tokens=2 delims==" %%P in ('findstr /R "^VITE_PORT=" "%ENV_FILE%"') do ( + set "REQUESTED_PORT=%%P" + ) +) +if defined REQUESTED_PORT ( + for /f "tokens=1" %%Q in ("!REQUESTED_PORT!") do set "REQUESTED_PORT=%%Q" +) else ( + set "REQUESTED_PORT=8080" +) +set "ORIGINAL_PORT=%REQUESTED_PORT%" + +set "PORT_CANDIDATES=%REQUESTED_PORT% 8080 5173 8081 8000 3000 3001 9000 5500" +call :find_available_port %PORT_CANDIDATES% +if errorlevel 1 ( + echo Unable to find an available port for the frontend dev server. + exit /b 1 +) + +set "VITE_PORT=%RESOLVED_PORT%" +set "VITE_BIND_HOST=%RESOLVED_HOST%" +if not defined VITE_BIND_HOST set "VITE_BIND_HOST=0.0.0.0" + +call :set_env_value "%ENV_FILE%" "VITE_PORT" "%VITE_PORT%" + +if /i "%VITE_BIND_HOST%"=="127.0.0.1" ( + echo Binding dev server to loopback because listening on 0.0.0.0 was blocked. +) +if "%VITE_PORT%" NEQ "%ORIGINAL_PORT%" ( + echo Using port %VITE_PORT% for the dev server ^(requested %ORIGINAL_PORT% was unavailable^). +) + +exit /b 0 + +:find_available_port +set "RESOLVED_PORT=" +set "RESOLVED_HOST=" +for %%P in (%*) do ( + if not defined RESOLVED_PORT ( + call :probe_port %%P + if not errorlevel 1 ( + set "RESOLVED_PORT=%%P" + set "RESOLVED_HOST=!PROBED_HOST!" + ) + ) +) +if not defined RESOLVED_PORT exit /b 1 +exit /b 0 + +:probe_port +set "PROBED_HOST=" +powershell -NoProfile -Command "try { $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Any,%~1); $listener.Start(); $listener.Stop(); exit 0 } catch { try { $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback,%~1); $listener.Start(); $listener.Stop(); exit 2 } catch { exit 1 } }" >nul 2>&1 +set "PS_EXIT=%ERRORLEVEL%" +if "%PS_EXIT%"=="0" ( + set "PROBED_HOST=0.0.0.0" + exit /b 0 +) +if "%PS_EXIT%"=="2" ( + set "PROBED_HOST=127.0.0.1" + exit /b 0 +) +exit /b 1 + +:set_env_value +setlocal ENABLEDELAYEDEXPANSION +set "ENV_FILE=%~1" +set "ENV_KEY=%~2" +set "ENV_VALUE=%~3" + +if not exist "%ENV_FILE%" ( + >"%ENV_FILE%" echo %ENV_KEY%=%ENV_VALUE% + endlocal & exit /b 0 +) + +set "TEMP_FILE=%ENV_FILE%.tmp" +set "VAR_WRITTEN=" +( + for /f "usebackq delims=" %%L in ("%ENV_FILE%") do ( + set "LINE=%%L" + set "WRITE_LINE=1" + for /f "tokens=1* delims==" %%K in ("!LINE!") do ( + set "KEY=%%K" + if /i "!KEY!"=="%ENV_KEY%" ( + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + set "VAR_WRITTEN=1" + ) + set "WRITE_LINE=" + ) + ) + if defined WRITE_LINE ( + echo !LINE! + ) + ) + if not defined VAR_WRITTEN ( + echo %ENV_KEY%=%ENV_VALUE% + ) +) >"%TEMP_FILE%" +move /Y "%TEMP_FILE%" "%ENV_FILE%" >nul +endlocal & exit /b 0 + +:ensure_patch_package +set "PATCH_PACKAGE_READY=" +where patch-package >nul 2>&1 && set "PATCH_PACKAGE_READY=1" +if not defined PATCH_PACKAGE_READY ( + if exist node_modules\.bin\patch-package.cmd set "PATCH_PACKAGE_READY=1" +) +if not defined PATCH_PACKAGE_READY ( + if exist node_modules\.bin\patch-package.ps1 set "PATCH_PACKAGE_READY=1" +) + +if not defined PATCH_PACKAGE_READY ( + echo Ensuring patch-package is available for npm lifecycle scripts... + npm install -g patch-package >nul 2>&1 + if errorlevel 1 ( + echo Failed to install patch-package globally. Run "npm install -g patch-package" manually and rerun the script. + exit /b 1 + ) + where patch-package >nul 2>&1 && set "PATCH_PACKAGE_READY=1" + if not defined PATCH_PACKAGE_READY ( + echo patch-package is still unavailable after installation. Ensure your npm global bin directory is on PATH and rerun the script. + exit /b 1 + ) +) + +exit /b 0