From 2f528229f2302509d75dafc311028127ec58c9ef Mon Sep 17 00:00:00 2001 From: AetherForge Date: Sun, 31 May 2026 02:32:24 -0700 Subject: [PATCH] Improve portable USB pack and credentials-based tunnel launcher. Expand pack-usb.bat to sync LAUNCH.bat, cloudflare assets, and data dirs while preserving operator state; align usb/LAUNCH.bat with credentials.json tunnel flow instead of a baked token. --- pack-usb.bat | 119 +++++++++++++++++++++++++++++++---------------- usb/LAUNCH.bat | 124 ++++++++++++++++++++++++++++++------------------- 2 files changed, 156 insertions(+), 87 deletions(-) diff --git a/pack-usb.bat b/pack-usb.bat index f45f6bf..75f8819 100644 --- a/pack-usb.bat +++ b/pack-usb.bat @@ -3,17 +3,15 @@ setlocal EnableExtensions EnableDelayedExpansion title AetherForge — Pack USB cd /d "%~dp0" set "ROOT=%CD%" -set "USB=%ROOT%\USB" +set "USB=%ROOT%\usb" echo. echo ================================================================ echo AetherForge — Pack Portable USB echo ================================================================ echo. -echo This script builds AetherForge.exe and assembles everything -echo needed to run the Control Deck from a USB drive. -echo. -echo Output folder: %USB%\ +echo Assembles a self-contained copy in: %USB%\ +echo Copy that entire folder to a USB drive — nothing else needed. echo. :: ---------------------------------------------------------------- @@ -32,11 +30,13 @@ if errorlevel 1 ( set "SKIP_FRONTEND=1" ) +if not exist "%USB%" mkdir "%USB%" + :: ---------------------------------------------------------------- -:: 1. Build the frontend (if npm available) +:: 1. Build the frontend when npm is available :: ---------------------------------------------------------------- if not defined SKIP_FRONTEND ( - echo [1/4] Building frontend... + echo [1/7] Building frontend... cd "%ROOT%\server\web" call npm install --silent call npm run build @@ -47,15 +47,15 @@ if not defined SKIP_FRONTEND ( exit /b 1 ) cd "%ROOT%" - echo [1/4] Frontend built. + echo [1/7] Frontend built. ) else ( - echo [1/4] Skipped (npm not found). + echo [1/7] Skipped - npm not found. ) :: ---------------------------------------------------------------- -:: 2. Build AetherForge.exe for the current machine (amd64 windows) +:: 2. Build AetherForge.exe for Windows amd64 :: ---------------------------------------------------------------- -echo [2/4] Compiling AetherForge.exe... +echo [2/7] Compiling AetherForge.exe... cd "%ROOT%\server" set "CGO_ENABLED=0" set "GOOS=windows" @@ -68,64 +68,105 @@ if errorlevel 1 ( exit /b 1 ) cd "%ROOT%" -echo [2/4] AetherForge.exe -> USB\AetherForge.exe +echo [2/7] AetherForge.exe ready. :: ---------------------------------------------------------------- -:: 3. Copy webroot +:: 3. Copy webroot - dashboard UI :: ---------------------------------------------------------------- -echo [3/4] Copying webroot... +echo [3/7] Copying webroot... +if exist "%USB%\webroot" rd /s /q "%USB%\webroot" if exist "%ROOT%\server\webroot" ( - if exist "%USB%\webroot" rd /s /q "%USB%\webroot" xcopy /e /i /q "%ROOT%\server\webroot" "%USB%\webroot" >nul - echo [3/4] webroot copied. ) else if exist "%ROOT%\server\web\dist" ( - if exist "%USB%\webroot" rd /s /q "%USB%\webroot" xcopy /e /i /q "%ROOT%\server\web\dist" "%USB%\webroot" >nul - echo [3/4] webroot copied from web\dist. ) else ( - echo [3/4] WARNING: No webroot found. Run 'npm run build' in server\web\ first. + echo ERROR: No webroot found. Run npm run build in server\web first. + pause + exit /b 1 ) +echo [3/7] webroot copied. :: ---------------------------------------------------------------- -:: 4. Copy source trees (needed for Forge to compile agents on the USB) +:: 4. Copy agent and fusion source - Forge needs these at runtime :: ---------------------------------------------------------------- -echo [4/4] Copying agent + fusion source... - +echo [4/7] Copying agent + fusion source... if exist "%USB%\agent" rd /s /q "%USB%\agent" if exist "%USB%\fusion" rd /s /q "%USB%\fusion" - -:: Copy agent source, excluding test results and build outputs xcopy /e /i /q /EXCLUDE:"%ROOT%\usb_pack_exclude.txt" "%ROOT%\agent" "%USB%\agent" >nul xcopy /e /i /q /EXCLUDE:"%ROOT%\usb_pack_exclude.txt" "%ROOT%\fusion" "%USB%\fusion" >nul -echo [4/4] Source trees copied. +echo [4/7] Source trees copied. :: ---------------------------------------------------------------- -:: 5. Ensure data directories exist on USB +:: 5. Launcher + docs (always sync from project root) :: ---------------------------------------------------------------- -if not exist "%USB%\data\builds" mkdir "%USB%\data\builds" -if not exist "%USB%\data\logs" mkdir "%USB%\data\logs" -if not exist "%USB%\data\blueprints" mkdir "%USB%\data\blueprints" -if not exist "%USB%\data\preps" mkdir "%USB%\data\preps" +echo [5/7] Syncing LAUNCH.bat, README, cloudflare... +copy /y "%ROOT%\LAUNCH.bat" "%USB%\LAUNCH.bat" >nul +if not exist "%USB%\README.txt" ( + if exist "%ROOT%\usb\README.txt" copy /y "%ROOT%\usb\README.txt" "%USB%\README.txt" >nul +) +:: run.bat is a project-root marker used by some tooling +echo @echo off > "%USB%\run.bat" +echo rem AetherForge portable root marker >> "%USB%\run.bat" + +if not exist "%USB%\cloudflare" mkdir "%USB%\cloudflare" +if exist "%ROOT%\usb\cloudflare\SETUP.txt" ( + copy /y "%ROOT%\usb\cloudflare\SETUP.txt" "%USB%\cloudflare\SETUP.txt" >nul +) +if exist "%ROOT%\cloudflared-windows-amd64.msi" ( + copy /y "%ROOT%\cloudflared-windows-amd64.msi" "%USB%\cloudflare\cloudflared-windows-amd64.msi" >nul + echo [5/7] cloudflared MSI bundled. +) else if exist "%ROOT%\usb\cloudflare\cloudflared-windows-amd64.msi" ( + echo [5/7] cloudflared MSI already in usb\cloudflare\ +) else ( + echo [5/7] WARNING: No cloudflared MSI found. Tunnel auto-install skipped. +) +:: Preserve existing credentials.json if present (never overwrite operator tunnel) +if not exist "%USB%\cloudflare\credentials.json" ( + if exist "%ROOT%\usb\cloudflare\credentials.json" ( + copy /y "%ROOT%\usb\cloudflare\credentials.json" "%USB%\cloudflare\credentials.json" >nul + ) +) +echo [5/7] Launcher synced. :: ---------------------------------------------------------------- -:: 6. Summary +:: 6. Remove stale nested server mirror (not needed for portable) +:: ---------------------------------------------------------------- +echo [6/7] Cleaning stale artifacts... +if exist "%USB%\server" rd /s /q "%USB%\server" +echo [6/7] Done. + +:: ---------------------------------------------------------------- +:: 7. Ensure data directories exist - preserve existing config and db +:: ---------------------------------------------------------------- +echo [7/7] Ensuring data directories... +if not exist "%USB%\data" mkdir "%USB%\data" +if not exist "%USB%\data\builds" mkdir "%USB%\data\builds" +if not exist "%USB%\data\logs" mkdir "%USB%\data\logs" +if not exist "%USB%\data\blueprints" mkdir "%USB%\data\blueprints" +if not exist "%USB%\data\preps" mkdir "%USB%\data\preps" +if not exist "%USB%\data\spread-kits" mkdir "%USB%\data\spread-kits" +if not exist "%USB%\data\uploads" mkdir "%USB%\data\uploads" +if not exist "%USB%\data\cloudflare" mkdir "%USB%\data\cloudflare" +echo [7/7] data\ ready - existing config and db preserved. + +:: ---------------------------------------------------------------- +:: Summary :: ---------------------------------------------------------------- echo. echo ================================================================ echo USB pack complete! echo. -echo Contents of %USB%\: +echo Folder: %USB%\ +echo. dir /b "%USB%" echo. echo To use: -echo 1. Copy the entire USB\ folder to a USB drive (or another PC) -echo 2. Double-click LAUNCH.bat -echo 3. Open http://localhost:8989 in a browser +echo 1. Copy the entire usb\ folder to your USB drive +echo 2. Double-click LAUNCH.bat on any Windows PC +echo 3. Open http://localhost:8989 echo. -echo Toolchain note: -echo If Go is not installed on the target PC, LAUNCH.bat will -echo download it automatically on first run and save it to -echo USB\toolchain\ for future use. +echo Your data\ and toolchain\ folders are preserved across repacks. +echo First launch without Go: LAUNCH.bat downloads toolchain\go\ once. echo ================================================================ echo. diff --git a/usb/LAUNCH.bat b/usb/LAUNCH.bat index 927bceb..00283ca 100644 --- a/usb/LAUNCH.bat +++ b/usb/LAUNCH.bat @@ -123,81 +123,108 @@ if not exist "%ROOT%\data\spread-kits" mkdir "%ROOT%\data\spread-kits" if not exist "%ROOT%\data\uploads" mkdir "%ROOT%\data\uploads" if not exist "%ROOT%\data\blueprints" mkdir "%ROOT%\data\blueprints" if not exist "%ROOT%\data\preps" mkdir "%ROOT%\data\preps" +if not exist "%ROOT%\data\cloudflare" mkdir "%ROOT%\data\cloudflare" :: ---------------------------------------------------------------- -:: 5. Cloudflare Tunnel — install MSI, register service with token +:: 5. Cloudflare Tunnel — auto-install, configure, start :: ---------------------------------------------------------------- -set "CF_MSI=%ROOT%\cloudflare\cloudflared-windows-amd64.msi" -set "CF_TOKEN=eyJhIjoiODk1NDc5YWIzNTQwZGFhNmQ2MWFlNzAyYTUxNjQ0NzUiLCJ0IjoiYWFhYzYzMTctMzgyYS00OTM3LTgxY2YtYjM2ZjVkNjZjYTU4IiwicyI6Ik1XRXlaV0FqTlRndE5XTTRPUzAwT0RCa0xXRTNaR010WkdRNU56UTJZMlJoTmpNMiJ9" +set "CF_DIR=%ROOT%\cloudflare" +set "CF_CREDS_BUNDLE=%CF_DIR%\credentials.json" +set "CF_MSI=%CF_DIR%\cloudflared-windows-amd64.msi" set "CF_HOSTNAME=killa.thetempleofdoom.com" +set "CF_DATA=%ROOT%\data\cloudflare" +set "SERVER_PORT=8989" set "CF_BIN=" +set "CF_TUNNEL_ID=" set "CF_READY=0" -:: Step A — locate cloudflared binary (system PATH or default install paths) +:: Check credentials exist and are real (not the placeholder) +if not exist "%CF_CREDS_BUNDLE%" goto cf_no_creds +powershell -NoProfile -Command "exit ([string](Get-Content '%CF_CREDS_BUNDLE%') | ConvertFrom-Json | Select-Object -ExpandProperty TunnelID) -eq ''" >nul 2>nul +if errorlevel 1 goto cf_no_creds + +:: Parse tunnel ID from credentials JSON +for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "(Get-Content '%CF_CREDS_BUNDLE%' | ConvertFrom-Json).TunnelID" 2^>nul`) do set "CF_TUNNEL_ID=%%i" +if "!CF_TUNNEL_ID!"=="" goto cf_no_creds +echo [CF] Tunnel ID: !CF_TUNNEL_ID! + +:: Stage credentials into data\cloudflare\ (idempotent) +set "CF_CREDS_LOCAL=%CF_DATA%\!CF_TUNNEL_ID!.json" +if not exist "!CF_CREDS_LOCAL!" ( + copy "%CF_CREDS_BUNDLE%" "!CF_CREDS_LOCAL!" >nul + echo [CF] Credentials staged to data\cloudflare\ +) + +:: Always regenerate config.yml with current absolute paths +:: (handles drive-letter changes when USB is moved) +set "CF_CONFIG=%CF_DATA%\config.yml" +powershell -NoProfile -Command "$cfg='%CF_DATA%\config.yml'; $creds='!CF_CREDS_LOCAL!'; $port='%SERVER_PORT%'; $host='%CF_HOSTNAME%'; $id='!CF_TUNNEL_ID!'; Set-Content -Path $cfg -Value @('tunnel: ' + $id, 'credentials-file: ' + $creds, '', 'ingress:', ' - hostname: ' + $host, ' service: http://127.0.0.1:' + $port, ' - service: http_status:404')" >nul 2>nul +echo [CF] Config written for !CF_HOSTNAME! -^> 127.0.0.1:%SERVER_PORT% + +:: ---- Locate or install cloudflared ---- where cloudflared >nul 2>nul if not errorlevel 1 ( set "CF_BIN=cloudflared" - goto cf_check_service + goto cf_have_bin ) if exist "%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" ( set "CF_BIN=%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" - goto cf_check_service + goto cf_have_bin ) if exist "%ProgramFiles(x86)%\cloudflare\cloudflared\cloudflared.exe" ( set "CF_BIN=%ProgramFiles(x86)%\cloudflare\cloudflared\cloudflared.exe" - goto cf_check_service + goto cf_have_bin ) -:: Step B — cloudflared not found, install from bundled MSI -if not exist "%CF_MSI%" ( - echo [CF] WARNING: cloudflared not found and no MSI bundled. Skipping tunnel. +:: Not found — install from bundled MSI +if exist "%CF_MSI%" ( + echo [CF] cloudflared not found. Installing from bundled MSI... + msiexec /i "%CF_MSI%" /quiet /norestart /l*v "%CF_DATA%\cf-install.log" + echo [CF] MSI install launched - waiting... + ping -n 8 127.0.0.1 >nul + if exist "%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" ( + set "CF_BIN=%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" + echo [CF] cloudflared installed successfully. + goto cf_have_bin + ) + where cloudflared >nul 2>nul + if not errorlevel 1 ( + set "CF_BIN=cloudflared" + echo [CF] cloudflared installed successfully. + goto cf_have_bin + ) + echo [CF] WARNING: MSI completed but cloudflared not found in PATH. + echo [CF] Try re-running LAUNCH.bat after a reboot. + goto cf_done +) else ( + echo [CF] WARNING: cloudflared not installed and no MSI bundled. goto cf_done ) -echo [CF] Installing cloudflared from bundled MSI... -msiexec /i "%CF_MSI%" /quiet /norestart -echo [CF] Waiting for MSI to complete... -ping -n 10 127.0.0.1 >nul -:: Re-locate after install -where cloudflared >nul 2>nul -if not errorlevel 1 ( set "CF_BIN=cloudflared" & goto cf_check_service ) -if exist "%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" ( - set "CF_BIN=%ProgramFiles%\cloudflare\cloudflared\cloudflared.exe" - goto cf_check_service -) -echo [CF] WARNING: MSI installed but cloudflared still not found. Try running as Administrator. -goto cf_done - -:cf_check_service +:cf_have_bin echo [CF] Binary: !CF_BIN! -:: Step C — register tunnel as Windows service if not already installed -sc query cloudflared >nul 2>nul +:: Check if cloudflared tunnel already running (same process = skip) +tasklist 2>nul | findstr /I "cloudflared" >nul 2>nul if not errorlevel 1 ( - echo [CF] Tunnel service already registered. - goto cf_start_service -) -echo [CF] Registering tunnel service with token... -"!CF_BIN!" service install %CF_TOKEN% -if errorlevel 1 ( - echo [CF] WARNING: service install failed. Run LAUNCH.bat as Administrator once. - goto cf_done -) -echo [CF] Tunnel service registered. -ping -n 3 127.0.0.1 >nul - -:cf_start_service -:: Step D — start the service if not already running -sc query cloudflared | findstr /I "RUNNING" >nul 2>nul -if not errorlevel 1 ( - echo [CF] Tunnel already running. + echo [CF] Tunnel already running on this machine. + echo [CF] https://!CF_HOSTNAME! set "CF_READY=1" goto cf_done ) -net start cloudflared >nul 2>nul -ping -n 4 127.0.0.1 >nul -echo [CF] Tunnel live: https://%CF_HOSTNAME% + +:: Start cloudflared tunnel in background +echo [CF] Starting Cloudflare tunnel... +start "" /B "!CF_BIN!" tunnel --config "!CF_CONFIG!" run +ping -n 5 127.0.0.1 >nul +echo [CF] Tunnel live: https://!CF_HOSTNAME! set "CF_READY=1" +goto cf_done + +:cf_no_creds +echo [CF] No valid credentials.json in cloudflare\ +echo [CF] See cloudflare\SETUP.txt to configure your tunnel once. +echo [CF] Running in LAN-only mode this session. :cf_done @@ -244,7 +271,8 @@ if "!EC!"=="0" ( echo If port %SERVER_PORT% is in use, close other AetherForge windows and retry. ) -:: Cloudflare tunnel runs as a Windows service — leave it up between sessions +:: On exit, also stop the cloudflared tunnel +taskkill /F /IM cloudflared.exe >nul 2>nul echo. pause