major improvements

This commit is contained in:
KingKDot
2026-06-12 09:14:49 -05:00
parent a2634a7454
commit b6672ee375
47 changed files with 1498 additions and 231 deletions
+54
View File
@@ -0,0 +1,54 @@
@echo off
setlocal EnableDelayedExpansion
REM Build BackstageCapture DLL for Windows x64 using MSBuild (vcxproj).
REM Run from VS Developer Command Prompt, or let the script detect VS.
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "PROJ=%ROOT%BackstageCapture\BackstageCapture.vcxproj"
set "OUT_DIR=%ROOT%Overlord-Server\dist-clients"
set CONFIG=Release
set PLATFORM=x64
REM Locate MSBuild via vswhere if not already on PATH
where msbuild.exe >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo msbuild.exe not found, searching for Visual Studio ...
set "FOUND_VS="
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do (
set "MSBUILD_PATH=%%i"
set "FOUND_VS=1"
)
if not defined FOUND_VS (
echo ERROR: Visual Studio with MSBuild not found.
exit /b 1
)
echo Found MSBuild at: !MSBUILD_PATH!
)
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
echo Building BackstageCapture.vcxproj [%CONFIG%^|%PLATFORM%] ...
if defined MSBUILD_PATH (
"!MSBUILD_PATH!" "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal
) else (
msbuild.exe "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal
)
if %ERRORLEVEL% neq 0 goto :error
if not exist "%OUT_DIR%\BackstageCapture.x64.dll" (
echo ERROR: DLL not found in output directory.
goto :error
)
echo.
echo Built: %OUT_DIR%\BackstageCapture.x64.dll
dir "%OUT_DIR%\BackstageCapture.x64.dll"
echo Done.
exit /b 0
:error
echo.
echo BUILD FAILED
exit /b 1
+248
View File
@@ -0,0 +1,248 @@
#!/usr/bin/env bash
# Build BackstageCapture DLL for Windows x64 using MinGW cross-compiler (C++).
# Run from the repository root or from Docker.
#
# BackstageCapture hooks IDXGISwapChain::Present to capture frames from the GPU
# process. It uses MinHook for hooking and ReflectiveLoader for injection.
#
# Requirements:
# - x86_64-w64-mingw32-g++ (C++ mode needed for COM vtable calls / __uuidof)
# - MinHook source under BackstageCapture/Minhook/
#
# If MinHook source is not available, you can pre-build the DLL with MSVC
# on Windows using scripts\build-backstage-capture-dll.bat and place the output at:
# Overlord-Server/dist-clients/BackstageCapture.x64.dll
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
cd "$ROOT"
# C++ compiler for COM / __uuidof support
CXX="${CXX:-x86_64-w64-mingw32-g++}"
CC="${CC:-x86_64-w64-mingw32-gcc}"
SRC_DIR="${HVNC_CAPTURE_SRC_DIR:-BackstageCapture/src}"
OUT_DIR="${HVNC_CAPTURE_OUT_DIR:-Overlord-Server/dist-clients}"
DLL_NAME="BackstageCapture.x64.dll"
MINHOOK_REPO="${MINHOOK_REPO:-https://github.com/TsudaKageyu/minhook.git}"
MINHOOK_REF="${MINHOOK_REF:-master}"
HVNC_FETCH_MINHOOK="${HVNC_FETCH_MINHOOK:-1}"
MINHOOK_STATIC_DIR="${MINHOOK_STATIC_DIR:-BackstageCapture/Minhook}"
mkdir -p "$OUT_DIR"
MINHOOK_DIR="$SRC_DIR/minhook"
stage_minhook_tree() {
local source_root="$1"
local include_root="${2:-$1}"
mkdir -p "$MINHOOK_DIR/hde"
cp -f "$source_root/buffer.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/buffer.h" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/hook.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/trampoline.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/trampoline.h" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/hde/hde64.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde32.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/pstdint.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/table64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/table32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
mkdir -p "$SRC_DIR/include"
if [ -f "$source_root/MinHook.h" ]; then
cp -f "$source_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
cp -f "$source_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
elif [ -f "$include_root/MinHook.h" ]; then
cp -f "$include_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
cp -f "$include_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
fi
}
stage_minhook_from_static_dir() {
local candidate_src=""
local candidate_include=""
for dir in "$MINHOOK_STATIC_DIR" "BackstageCapture/Minhook" "BackstageCapture/minhook"; do
if [ -f "$dir/hook.c" ] && [ -f "$dir/hde/hde64.c" ]; then
candidate_src="$dir"
candidate_include="$dir"
break
fi
if [ -f "$dir/src/hook.c" ] && [ -f "$dir/src/hde/hde64.c" ]; then
candidate_src="$dir/src"
if [ -f "$dir/include/MinHook.h" ]; then
candidate_include="$dir/include"
else
candidate_include="$dir/src"
fi
break
fi
done
if [ -n "$candidate_src" ]; then
echo "Using static MinHook source from $candidate_src"
stage_minhook_tree "$candidate_src" "$candidate_include"
return 0
fi
return 1
}
# Verify C++ cross-compiler is available
if ! command -v "$CXX" >/dev/null 2>&1; then
echo "ERROR: C++ cross compiler not found: $CXX"
echo "Install mingw-w64 (x86_64-w64-mingw32-g++) in your build image/environment."
exit 1
fi
fetch_minhook() {
if [ "$HVNC_FETCH_MINHOOK" != "1" ]; then
return 1
fi
if ! command -v git >/dev/null 2>&1; then
echo "WARNING: git is not available; cannot auto-fetch MinHook."
return 1
fi
echo "MinHook source not found; fetching from $MINHOOK_REPO ($MINHOOK_REF) ..."
local tmpdir
tmpdir="$(mktemp -d)"
if ! git clone --depth 1 --branch "$MINHOOK_REF" "$MINHOOK_REPO" "$tmpdir/minhook"; then
rm -rf "$tmpdir"
echo "WARNING: Failed to fetch MinHook source."
return 1
fi
stage_minhook_tree "$tmpdir/minhook/src" "$tmpdir/minhook/include"
cp -f "$tmpdir/minhook/include/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
mkdir -p "$SRC_DIR/include"
cp -f "$tmpdir/minhook/include/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
rm -rf "$tmpdir"
[ -f "$MINHOOK_DIR/hook.c" ]
}
# --- Stage MinHook source ---
if [ ! -d "$MINHOOK_DIR" ]; then
if ! stage_minhook_from_static_dir && ! fetch_minhook; then
echo "WARNING: MinHook source not found at $MINHOOK_DIR"
echo "Attempting to use pre-compiled libMinHook.x64.lib ..."
echo "(This may fail with MinGW. Build with MSVC on Windows instead.)"
MINHOOK_OBJS=""
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
fi
if [ -d "$MINHOOK_DIR" ]; then
if [ ! -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$MINHOOK_DIR/MinHook.c" ]; then
stage_minhook_from_static_dir || fetch_minhook || true
fi
fi
if [ -d "$MINHOOK_DIR" ] && { [ -f "$MINHOOK_DIR/hook.c" ] || [ -f "$MINHOOK_DIR/MinHook.c" ]; }; then
echo "Building MinHook from source ..."
MINHOOK_OBJS=""
MINHOOK_LIB=""
MINHOOK_INC="-I$MINHOOK_DIR -I$MINHOOK_DIR/hde"
if [ -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$SRC_DIR/include/MinHook.h" ]; then
mkdir -p "$SRC_DIR/include"
if [ -f "$MINHOOK_DIR/MinHook.h" ]; then
cp -f "$MINHOOK_DIR/MinHook.h" "$SRC_DIR/include/MinHook.h"
elif [ -f "$MINHOOK_DIR/include/MinHook.h" ]; then
cp -f "$MINHOOK_DIR/include/MinHook.h" "$SRC_DIR/include/MinHook.h"
fi
fi
# MinHook is pure C — compile with gcc
for src in "$MINHOOK_DIR"/buffer.c "$MINHOOK_DIR"/trampoline.c \
"$MINHOOK_DIR"/hde/hde64.c "$MINHOOK_DIR"/hde/hde32.c \
"$MINHOOK_DIR"/hook.c "$MINHOOK_DIR"/MinHook.c; do
if [ -f "$src" ]; then
obj="${src%.c}.o"
"$CC" -c -O2 -DWIN64 -D_WIN64 -fno-stack-protector -fno-asynchronous-unwind-tables $MINHOOK_INC -o "$obj" "$src"
MINHOOK_OBJS="$MINHOOK_OBJS $obj"
fi
done
if [ -z "${MINHOOK_OBJS// }" ]; then
echo "WARNING: No MinHook objects were built, falling back to pre-compiled libMinHook.x64.lib"
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
else
MINHOOK_OBJS=""
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
# --- Compile BackstageCapture sources ---
# DXGICapture.c is compiled as C++ for COM vtable calls and __uuidof
CXXFLAGS="-O2 -DWIN64 -D_WIN64 -DNDEBUG -D_WINDOWS -D_USRDLL"
CXXFLAGS="$CXXFLAGS -DBackstageCapture_EXPORTS -DWIN_X64"
CXXFLAGS="$CXXFLAGS -DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR"
CXXFLAGS="$CXXFLAGS -DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN"
CXXFLAGS="$CXXFLAGS -fno-stack-protector"
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti"
CXXFLAGS="$CXXFLAGS -I$SRC_DIR"
if [ -n "${MINHOOK_INC:-}" ]; then
CXXFLAGS="$CXXFLAGS $MINHOOK_INC"
fi
# C flags for ReflectiveLoader (pure C, no C++)
# Keep -fno-asynchronous-unwind-tables only for the loader shellcode
LOADER_CFLAGS="-O2 -DWIN64 -D_WIN64 -DNDEBUG -D_WINDOWS -D_USRDLL"
LOADER_CFLAGS="$LOADER_CFLAGS -DBackstageCapture_EXPORTS -DWIN_X64"
LOADER_CFLAGS="$LOADER_CFLAGS -DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR"
LOADER_CFLAGS="$LOADER_CFLAGS -DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN"
LOADER_CFLAGS="$LOADER_CFLAGS -fno-stack-protector"
LOADER_CFLAGS="$LOADER_CFLAGS -fno-asynchronous-unwind-tables"
LOADER_CFLAGS="$LOADER_CFLAGS -I$SRC_DIR"
if [ -n "${MINHOOK_INC:-}" ]; then
LOADER_CFLAGS="$LOADER_CFLAGS $MINHOOK_INC"
fi
echo "Compiling ReflectiveLoader.c ..."
"$CC" -c $LOADER_CFLAGS -o "$SRC_DIR/ReflectiveLoader.o" "$SRC_DIR/ReflectiveLoader.c"
echo "Compiling ReflectiveDll.c (C++) ..."
"$CXX" -c $CXXFLAGS -include "$SRC_DIR/seh_compat.h" -o "$SRC_DIR/ReflectiveDll.o" "$SRC_DIR/ReflectiveDll.c"
echo "Compiling DXGICapture.c (C++) ..."
"$CXX" -c $CXXFLAGS -include "$SRC_DIR/seh_compat.h" -o "$SRC_DIR/DXGICapture.o" "$SRC_DIR/DXGICapture.c"
echo "Linking $DLL_NAME ..."
LINK_OBJS="$SRC_DIR/ReflectiveLoader.o $SRC_DIR/ReflectiveDll.o $SRC_DIR/DXGICapture.o"
if [ -n "${MINHOOK_OBJS:-}" ]; then
LINK_OBJS="$LINK_OBJS $MINHOOK_OBJS"
fi
LINK_LIBS="-lkernel32 -luser32 -ladvapi32 -ld3d11 -ldxgi"
if [ -n "${MINHOOK_LIB:-}" ] && [ -f "${MINHOOK_LIB}" ]; then
LINK_LIBS="$LINK_LIBS $MINHOOK_LIB"
fi
"$CXX" -shared -o "$OUT_DIR/$DLL_NAME" $LINK_OBJS $LINK_LIBS \
-Wl,--entry,DllMain \
-Wl,--disable-runtime-pseudo-reloc \
-fno-stack-protector \
-fno-exceptions -fno-rtti \
-static-libgcc -static-libstdc++ \
-s
echo "Built: $OUT_DIR/$DLL_NAME"
ls -la "$OUT_DIR/$DLL_NAME"
# Clean up object files
rm -f "$SRC_DIR"/*.o
if [ -d "$MINHOOK_DIR" ]; then
find "$MINHOOK_DIR" -name '*.o' -delete
fi
echo "Done."
+54
View File
@@ -0,0 +1,54 @@
@echo off
setlocal EnableDelayedExpansion
REM Build BackstageInjection DLL for Windows x64 using MSBuild (vcxproj).
REM Run from VS Developer Command Prompt, or let the script detect VS.
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "PROJ=%ROOT%BackstageInjection\BackstageInjection.vcxproj"
set "OUT_DIR=%ROOT%Overlord-Server\dist-clients"
set CONFIG=Release
set PLATFORM=x64
REM Locate MSBuild via vswhere if not already on PATH
where msbuild.exe >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo msbuild.exe not found, searching for Visual Studio ...
set "FOUND_VS="
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do (
set "MSBUILD_PATH=%%i"
set "FOUND_VS=1"
)
if not defined FOUND_VS (
echo ERROR: Visual Studio with MSBuild not found.
exit /b 1
)
echo Found MSBuild at: !MSBUILD_PATH!
)
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
echo Building BackstageInjection.vcxproj [%CONFIG%^|%PLATFORM%] ...
if defined MSBUILD_PATH (
"!MSBUILD_PATH!" "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal
) else (
msbuild.exe "%PROJ%" /p:Configuration=%CONFIG% /p:Platform=%PLATFORM% /p:OutDir="%OUT_DIR%\\" /m /nologo /v:minimal
)
if %ERRORLEVEL% neq 0 goto :error
if not exist "%OUT_DIR%\BackstageInjection.x64.dll" (
echo ERROR: DLL not found in output directory.
goto :error
)
echo.
echo Built: %OUT_DIR%\BackstageInjection.x64.dll
dir "%OUT_DIR%\BackstageInjection.x64.dll"
echo Done.
exit /b 0
:error
echo.
echo BUILD FAILED
exit /b 1
+234
View File
@@ -0,0 +1,234 @@
#!/usr/bin/env bash
# Build BackstageInjection DLL for Windows x64 using MinGW cross-compiler.
# Run from the repository root or from Docker.
#
# Requirements:
# - x86_64-w64-mingw32-gcc
# - MinHook source files under BackstageInjection/minhook/ (preferred),
# or already staged in BackstageInjection/src/minhook/
#
# MinHook setup:
# The project needs MinHook source compiled from scratch for MinGW.
# 1) Clone https://github.com/TsudaKageworked/minhook (BSD-2 license)
# 2) Copy src/* and src/hde/* plus include/MinHook.h into
# BackstageInjection/minhook/
# 3) Run this script.
#
# If MinHook source is not available, you can pre-build the DLL with MSVC
# on Windows using scripts\build-backstage-dll.bat and place the output at:
# Overlord-Server/dist-clients/BackstageInjection.x64.dll
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
cd "$ROOT"
CC="${CC:-x86_64-w64-mingw32-gcc}"
SRC_DIR="${HVNC_SRC_DIR:-BackstageInjection/src}"
OUT_DIR="${HVNC_OUT_DIR:-Overlord-Server/dist-clients}"
DLL_NAME="BackstageInjection.x64.dll"
MINHOOK_REPO="${MINHOOK_REPO:-https://github.com/TsudaKageyu/minhook.git}"
MINHOOK_REF="${MINHOOK_REF:-master}"
HVNC_FETCH_MINHOOK="${HVNC_FETCH_MINHOOK:-1}"
MINHOOK_STATIC_DIR="${MINHOOK_STATIC_DIR:-BackstageInjection/Minhook}"
mkdir -p "$OUT_DIR"
MINHOOK_DIR="$SRC_DIR/minhook"
stage_minhook_tree() {
local source_root="$1"
local include_root="${2:-$1}"
mkdir -p "$MINHOOK_DIR/hde"
cp -f "$source_root/buffer.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/buffer.h" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/hook.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/trampoline.c" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/trampoline.h" "$MINHOOK_DIR/" 2>/dev/null || true
cp -f "$source_root/hde/hde64.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde32.c" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/hde32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/pstdint.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/table64.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
cp -f "$source_root/hde/table32.h" "$MINHOOK_DIR/hde/" 2>/dev/null || true
mkdir -p "$SRC_DIR/include"
if [ -f "$source_root/MinHook.h" ]; then
cp -f "$source_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
cp -f "$source_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
elif [ -f "$include_root/MinHook.h" ]; then
cp -f "$include_root/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
cp -f "$include_root/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
fi
}
stage_minhook_from_static_dir() {
local candidate_src=""
local candidate_include=""
for dir in "$MINHOOK_STATIC_DIR" "BackstageInjection/Minhook" "BackstageInjection/minhook"; do
if [ -f "$dir/hook.c" ] && [ -f "$dir/hde/hde64.c" ]; then
candidate_src="$dir"
candidate_include="$dir"
break
fi
if [ -f "$dir/src/hook.c" ] && [ -f "$dir/src/hde/hde64.c" ]; then
candidate_src="$dir/src"
if [ -f "$dir/include/MinHook.h" ]; then
candidate_include="$dir/include"
else
candidate_include="$dir/src"
fi
break
fi
done
if [ -n "$candidate_src" ]; then
echo "Using static MinHook source from $candidate_src"
stage_minhook_tree "$candidate_src" "$candidate_include"
return 0
fi
return 1
}
if ! command -v "$CC" >/dev/null 2>&1; then
echo "ERROR: Cross compiler not found: $CC"
echo "Install mingw-w64 (x86_64-w64-mingw32-gcc) in your build image/environment."
exit 1
fi
fetch_minhook() {
if [ "$HVNC_FETCH_MINHOOK" != "1" ]; then
return 1
fi
if ! command -v git >/dev/null 2>&1; then
echo "WARNING: git is not available; cannot auto-fetch MinHook."
return 1
fi
echo "MinHook source not found; fetching from $MINHOOK_REPO ($MINHOOK_REF) ..."
local tmpdir
tmpdir="$(mktemp -d)"
if ! git clone --depth 1 --branch "$MINHOOK_REF" "$MINHOOK_REPO" "$tmpdir/minhook"; then
rm -rf "$tmpdir"
echo "WARNING: Failed to fetch MinHook source."
return 1
fi
stage_minhook_tree "$tmpdir/minhook/src" "$tmpdir/minhook/include"
cp -f "$tmpdir/minhook/include/MinHook.h" "$MINHOOK_DIR/MinHook.h" 2>/dev/null || true
mkdir -p "$SRC_DIR/include"
cp -f "$tmpdir/minhook/include/MinHook.h" "$SRC_DIR/include/MinHook.h" 2>/dev/null || true
rm -rf "$tmpdir"
[ -f "$MINHOOK_DIR/hook.c" ]
}
if [ ! -d "$MINHOOK_DIR" ]; then
if ! stage_minhook_from_static_dir && ! fetch_minhook; then
echo "WARNING: MinHook source not found at $MINHOOK_DIR"
echo "Attempting to use pre-compiled libMinHook.x64.lib ..."
echo "(This may fail with MinGW. Build with MSVC on Windows instead.)"
MINHOOK_OBJS=""
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
fi
if [ -d "$MINHOOK_DIR" ]; then
if [ ! -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$MINHOOK_DIR/MinHook.c" ]; then
# Some trees have the folder but not the expected source files.
stage_minhook_from_static_dir || fetch_minhook || true
fi
fi
if [ -d "$MINHOOK_DIR" ] && { [ -f "$MINHOOK_DIR/hook.c" ] || [ -f "$MINHOOK_DIR/MinHook.c" ]; }; then
echo "Building MinHook from source ..."
MINHOOK_OBJS=""
MINHOOK_LIB=""
MINHOOK_INC="-I$MINHOOK_DIR -I$MINHOOK_DIR/hde"
if [ -f "$MINHOOK_DIR/hook.c" ] && [ ! -f "$SRC_DIR/include/MinHook.h" ]; then
mkdir -p "$SRC_DIR/include"
if [ -f "$MINHOOK_DIR/MinHook.h" ]; then
cp -f "$MINHOOK_DIR/MinHook.h" "$SRC_DIR/include/MinHook.h"
elif [ -f "$MINHOOK_DIR/include/MinHook.h" ]; then
cp -f "$MINHOOK_DIR/include/MinHook.h" "$SRC_DIR/include/MinHook.h"
fi
fi
for src in "$MINHOOK_DIR"/buffer.c "$MINHOOK_DIR"/trampoline.c \
"$MINHOOK_DIR"/hde/hde64.c "$MINHOOK_DIR"/hde/hde32.c \
"$MINHOOK_DIR"/hook.c "$MINHOOK_DIR"/MinHook.c; do
if [ -f "$src" ]; then
obj="${src%.c}.o"
"$CC" -c -O2 -DWIN64 -D_WIN64 -fno-stack-protector -fno-asynchronous-unwind-tables $MINHOOK_INC -o "$obj" "$src"
MINHOOK_OBJS="$MINHOOK_OBJS $obj"
fi
done
if [ -z "${MINHOOK_OBJS// }" ]; then
echo "WARNING: No MinHook objects were built, falling back to pre-compiled libMinHook.x64.lib"
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
else
MINHOOK_OBJS=""
MINHOOK_LIB="$SRC_DIR/libMinHook.x64.lib"
MINHOOK_INC=""
fi
CFLAGS="-O2 -DWIN64 -D_WIN64 -DNDEBUG -D_WINDOWS -D_USRDLL"
CFLAGS="$CFLAGS -DBackstageInjection_EXPORTS -DWIN_X64"
CFLAGS="$CFLAGS -DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR"
CFLAGS="$CFLAGS -DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN"
CFLAGS="$CFLAGS -fno-stack-protector"
CFLAGS="$CFLAGS -I$SRC_DIR"
if [ -n "${MINHOOK_INC:-}" ]; then
CFLAGS="$CFLAGS $MINHOOK_INC"
fi
# ReflectiveLoader is position-independent shellcode: strip .eh_frame but keep .pdata
LOADER_CFLAGS="$CFLAGS -fno-asynchronous-unwind-tables"
echo "Compiling ReflectiveLoader.c ..."
"$CC" -c $LOADER_CFLAGS -o "$SRC_DIR/ReflectiveLoader.o" "$SRC_DIR/ReflectiveLoader.c"
echo "Compiling ReflectiveDll.c ..."
"$CC" -c $CFLAGS -o "$SRC_DIR/ReflectiveDll.o" "$SRC_DIR/ReflectiveDll.c"
echo "Compiling NtApiHooks.c ..."
"$CC" -c $CFLAGS -include "$SRC_DIR/seh_compat.h" -o "$SRC_DIR/NtApiHooks.o" "$SRC_DIR/NtApiHooks.c"
echo "Linking $DLL_NAME ..."
LINK_OBJS="$SRC_DIR/ReflectiveLoader.o $SRC_DIR/ReflectiveDll.o $SRC_DIR/NtApiHooks.o"
if [ -n "${MINHOOK_OBJS:-}" ]; then
LINK_OBJS="$LINK_OBJS $MINHOOK_OBJS"
fi
LINK_LIBS="-lkernel32 -luser32 -ladvapi32 -lntdll"
if [ -n "${MINHOOK_LIB:-}" ] && [ -f "${MINHOOK_LIB}" ]; then
LINK_LIBS="$LINK_LIBS $MINHOOK_LIB"
fi
"$CC" -shared -o "$OUT_DIR/$DLL_NAME" $LINK_OBJS $LINK_LIBS \
-Wl,--entry,DllMain \
-Wl,--disable-runtime-pseudo-reloc \
-fno-stack-protector \
-s
echo "Built: $OUT_DIR/$DLL_NAME"
ls -la "$OUT_DIR/$DLL_NAME"
# Clean up object files
rm -f "$SRC_DIR"/*.o
if [ -d "$MINHOOK_DIR" ]; then
find "$MINHOOK_DIR" -name '*.o' -delete
fi
echo "Done."
+238
View File
@@ -0,0 +1,238 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "CLIENT_DIR=%ROOT%Overlord-Client"
set "OUT_DIR=%ROOT%dist-clients"
if not defined ENABLE_PERSISTENCE set ENABLE_PERSISTENCE=false
if not defined OBFUSCATE set OBFUSCATE=false
if not defined HIDE_CONSOLE set HIDE_CONSOLE=false
if not defined NO_PRINTING set NO_PRINTING=false
set "GARBLE_FLAGS="
REM Build LDFLAGS with all custom settings
set "LDFLAGS=-s -w"
set "BUILD_TAGS="
if "%NO_PRINTING%"=="true" (
echo Building with printing disabled
set "BUILD_TAGS=-tags noprint"
)
if "%ENABLE_PERSISTENCE%"=="true" (
echo Building with persistence enabled
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/config.DefaultPersistence=true"
)
if not "%STARTUP_NAME%"=="" (
echo Building with custom startup name: %STARTUP_NAME%
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/persistence.DefaultStartupName=%STARTUP_NAME%"
)
if not "%SERVER_URL%"=="" (
echo Building with custom server URL: %SERVER_URL%
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/config.DefaultServerURL=%SERVER_URL%"
)
if not "%CLIENT_ID%"=="" (
echo Building with custom client ID: %CLIENT_ID%
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/config.DefaultID=%CLIENT_ID%"
)
if not "%CLIENT_COUNTRY%"=="" (
echo Building with custom country: %CLIENT_COUNTRY%
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/config.DefaultCountry=%CLIENT_COUNTRY%"
)
if "%OVERLORD_AGENT_TOKEN%"=="" (
set "SAVE_JSON=%APPDATA%\Overlord\save.json"
if exist "%SAVE_JSON%" (
for /f "usebackq delims=" %%I in (`powershell -NoProfile -Command "$p='%SAVE_JSON%'; try { $j = Get-Content -Raw -LiteralPath $p | ConvertFrom-Json; $t = $j.auth.agentToken; if ($t) { [Console]::Write($t) } } catch {}"`) do set "OVERLORD_AGENT_TOKEN=%%I"
)
)
if not "%OVERLORD_AGENT_TOKEN%"=="" (
echo Embedding agent token from environment/save.json
set "LDFLAGS=%LDFLAGS% -X overlord-client/cmd/agent/config.DefaultAgentToken=%OVERLORD_AGENT_TOKEN%"
)
echo LDFLAGS: %LDFLAGS%
set "WIN_LDFLAGS="
if "%HIDE_CONSOLE%"=="true" (
echo Windows console hidden (GUI subsystem)
set "WIN_LDFLAGS=-H=windowsgui"
)
set "BUILD_CMD=go build"
if "%OBFUSCATE%"=="true" (
where garble >nul 2>&1
if errorlevel 1 (
echo garble not found. Install with: go install mvdan.cc/garble@latest
exit /b 1
)
echo Obfuscation enabled (garble)
set "BUILD_CMD=garble build %GARBLE_FLAGS%"
)
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
pushd "%CLIENT_DIR%"
echo == Building agent for windows amd64 ==
set GOOS=windows
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS% %WIN_LDFLAGS%" -o "%OUT_DIR%\agent-windows-amd64.exe" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for windows x86 ==
set GOOS=windows
set GOARCH=386
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS% %WIN_LDFLAGS%" -o "%OUT_DIR%\agent-windows-386.exe" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for windows arm64 ==
set GOOS=windows
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS% %WIN_LDFLAGS%" -o "%OUT_DIR%\agent-windows-arm64.exe" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for linux amd64 ==
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-linux-amd64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for linux arm64 ==
set GOOS=linux
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-linux-arm64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for linux arm (armv7) ==
set GOOS=linux
set GOARCH=arm
set GOARM=7
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-linux-armv7" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for darwin arm64 ==
set GOOS=darwin
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-darwin-arm64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for darwin amd64 ==
set GOOS=darwin
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-darwin-amd64" ./cmd/agent
if errorlevel 1 goto :err
echo WARNING: BSD targets are severely untested and will probably not work right.
echo == Building agent for freebsd amd64 ==
set GOOS=freebsd
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-freebsd-amd64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for freebsd arm64 ==
set GOOS=freebsd
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-freebsd-arm64" ./cmd/agent
if errorlevel 1 goto :err
echo WARNING: Android targets are severely untested and will probably not work right.
echo == Building agent for android arm64 ==
set GOOS=android
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-android-arm64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for android amd64 ==
set GOOS=android
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-android-amd64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for android arm (armv7) ==
set GOOS=android
set GOARCH=arm
set GOARM=7
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-android-armv7" ./cmd/agent
if errorlevel 1 goto :err
set GOARM=
echo WARNING: iOS targets are experimental (POC). Most features will be stubbed.
echo == Building agent for ios arm64 ==
set GOOS=darwin
set GOARCH=arm64
set CGO_ENABLED=0
if "%NO_PRINTING%"=="true" (
%BUILD_CMD% -tags "ios_target noprint" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-arm64" ./cmd/agent
) else (
%BUILD_CMD% -tags "ios_target" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-arm64" ./cmd/agent
)
if errorlevel 1 goto :err
echo == Building agent for ios amd64 (simulator) ==
set GOOS=darwin
set GOARCH=amd64
set CGO_ENABLED=0
if "%NO_PRINTING%"=="true" (
%BUILD_CMD% -tags "ios_target noprint" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-amd64" ./cmd/agent
) else (
%BUILD_CMD% -tags "ios_target" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-amd64" ./cmd/agent
)
set GOOS=darwin
set GOARCH=amd64
set CGO_ENABLED=0
if "%NO_PRINTING%"=="true" (
%BUILD_CMD% -tags "ios_target noprint" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-amd64" ./cmd/agent
) else (
%BUILD_CMD% -tags "ios_target" -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-ios-amd64" ./cmd/agent
)
if errorlevel 1 goto :err
echo == Building agent for openbsd amd64 ==
set GOOS=openbsd
set GOARCH=amd64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-openbsd-amd64" ./cmd/agent
if errorlevel 1 goto :err
echo == Building agent for openbsd arm64 ==
set GOOS=openbsd
set GOARCH=arm64
set CGO_ENABLED=0
%BUILD_CMD% %BUILD_TAGS% -ldflags="%LDFLAGS%" -o "%OUT_DIR%\agent-openbsd-arm64" ./cmd/agent
if errorlevel 1 goto :err
echo Builds complete. Outputs in %OUT_DIR%
goto :eof
:err
echo Build failed. See errors above.
popd >nul 2>&1
endlocal
exit /b 1
:eof
popd
endlocal
+32
View File
@@ -0,0 +1,32 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
echo === Building Overlord Desktop (Tauri) ===
pushd "%ROOT%Overlord-Desktop"
where bun >nul 2>&1
if errorlevel 1 (
echo error: bun is required ^(https://bun.sh^)
goto :err
)
where cargo >nul 2>&1
if errorlevel 1 (
echo error: rust toolchain is required ^(https://rustup.rs^)
goto :err
)
call bun install || goto :err
call bun run vendor || goto :err
call bun run build:win || goto :err
echo === Done — bundle output: Overlord-Desktop\src-tauri\target\release\bundle\ ===
popd
pause
endlocal
exit /b 0
:err
popd >nul 2>&1
endlocal
exit /b 1
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
echo "=== Building Overlord Desktop (Tauri) ==="
cd "$ROOT/Overlord-Desktop"
if ! command -v bun >/dev/null 2>&1; then
echo "error: bun is required (https://bun.sh)" >&2
exit 1
fi
if ! command -v cargo >/dev/null 2>&1; then
echo "error: rust toolchain is required (https://rustup.rs)" >&2
exit 1
fi
bun install
bun run vendor
case "$(uname -s)" in
Linux*) bun run build:linux ;;
Darwin*) bun run build:mac ;;
MINGW*|MSYS*|CYGWIN*) bun run build:win ;;
*) bun run build ;;
esac
echo "=== Done — bundle output: Overlord-Desktop/src-tauri/target/release/bundle/ ==="
+139
View File
@@ -0,0 +1,139 @@
@echo off
setlocal EnableExtensions
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "SERVER_SRC=%ROOT%Overlord-Server"
set "CLIENT_SRC=%ROOT%Overlord-Client"
set "RELEASE_DIR=%ROOT%release"
if not exist "%SERVER_SRC%\package.json" (
echo [error] Overlord-Server not found at: %SERVER_SRC%
exit /b 1
)
if not exist "%CLIENT_SRC%\go.mod" (
echo [error] Overlord-Client not found at: %CLIENT_SRC%
exit /b 1
)
where bun >nul 2>&1
if errorlevel 1 (
echo [error] bun was not found in PATH.
exit /b 1
)
where go >nul 2>&1
if errorlevel 1 (
echo [error] go was not found in PATH.
exit /b 1
)
echo [1/10] Building server bundle and web assets...
pushd "%SERVER_SRC%"
call bun install
if errorlevel 1 goto :err
call bun run build
if errorlevel 1 goto :err
echo [2/10] Compiling Windows production executable...
call bun run build:prod:win
if errorlevel 1 goto :err
echo [3/10] Compiling Linux production executable...
call bun run build:prod:linux
if errorlevel 1 goto :err
popd
echo [4/10] Skipping prebuilt client binaries ^(prod package exports client source only^)
echo [5/10] Preparing release folder...
if exist "%RELEASE_DIR%" rmdir /s /q "%RELEASE_DIR%"
mkdir "%RELEASE_DIR%"
if errorlevel 1 goto :err
echo [6/10] Copying compiled server executables...
copy /Y "%SERVER_SRC%\dist\overlord-server.exe" "%RELEASE_DIR%\overlord-server.exe" >nul
if errorlevel 1 goto :err
copy /Y "%SERVER_SRC%\dist\overlord-server-linux-x64" "%RELEASE_DIR%\overlord-server-linux-x64" >nul
if errorlevel 1 goto :err
echo [6b/10] Copying sharp native module for runtime resolution...
if exist "%SERVER_SRC%\node_modules\sharp" (
robocopy "%SERVER_SRC%\node_modules\sharp" "%RELEASE_DIR%\node_modules\sharp" /E >nul
if errorlevel 8 goto :robocopy_err
)
if exist "%SERVER_SRC%\node_modules\@img" (
robocopy "%SERVER_SRC%\node_modules\@img" "%RELEASE_DIR%\node_modules\@img" /E >nul
if errorlevel 8 goto :robocopy_err
)
echo [7/10] Exporting Overlord-Client source for runtime builds...
robocopy "%CLIENT_SRC%" "%RELEASE_DIR%\Overlord-Client" /E /XD build .git .vscode >nul
if errorlevel 8 goto :robocopy_err
echo [8/10] Copying required public web assets...
robocopy "%SERVER_SRC%\public" "%RELEASE_DIR%\public" /E >nul
if errorlevel 8 goto :robocopy_err
echo [9/10] Minifying public JS, CSS, and HTML assets...
pushd "%SERVER_SRC%"
call bun run scripts/minify-public.ts --dir "%RELEASE_DIR%\public"
if errorlevel 1 goto :err
popd
echo [10/10] Creating runner scripts...
(
echo @echo off
echo setlocal
echo set "ROOT=%%~dp0"
echo if not defined HOST set HOST=0.0.0.0
echo if not defined PORT set PORT=5173
echo if not defined LOG_LEVEL set LOG_LEVEL=info
echo if not defined NODE_ENV set NODE_ENV=production
echo if not defined OVERLORD_ROOT set OVERLORD_ROOT=%%ROOT%%
echo pushd "%%ROOT%%"
echo call "%%ROOT%%overlord-server.exe"
echo popd
echo endlocal
) > "%RELEASE_DIR%\start-prod-release.bat"
> "%RELEASE_DIR%\start-prod-release.sh" echo #!/usr/bin/env bash
>> "%RELEASE_DIR%\start-prod-release.sh" echo set -euo pipefail
>> "%RELEASE_DIR%\start-prod-release.sh" echo ROOT="${0%%/*}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo [ "$ROOT" = "$0" ] ^&^& ROOT="."
>> "%RELEASE_DIR%\start-prod-release.sh" echo cd "$ROOT"
>> "%RELEASE_DIR%\start-prod-release.sh" echo ROOT="$PWD"
>> "%RELEASE_DIR%\start-prod-release.sh" echo export HOST="${HOST:-0.0.0.0}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo export PORT="${PORT:-5173}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo export LOG_LEVEL="${LOG_LEVEL:-info}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo export NODE_ENV="${NODE_ENV:-production}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo export OVERLORD_ROOT="${OVERLORD_ROOT:-$ROOT}"
>> "%RELEASE_DIR%\start-prod-release.sh" echo chmod +x "$ROOT/overlord-server-linux-x64" ^|^| true
>> "%RELEASE_DIR%\start-prod-release.sh" echo "$ROOT/overlord-server-linux-x64"
echo.
echo [ok] Production package created:
echo %RELEASE_DIR%
echo [ok] Compiled server executables:
echo %RELEASE_DIR%\overlord-server.exe
echo %RELEASE_DIR%\overlord-server-linux-x64
echo [ok] Web assets:
echo %RELEASE_DIR%\public
echo.
echo Run this from the package folder:
echo start-prod-release.bat
echo Or on Linux:
echo chmod +x start-prod-release.sh overlord-server-linux-x64 ^&^& ./start-prod-release.sh
endlocal
exit /b 0
:robocopy_err
echo [error] Copy operation failed ^(robocopy exit code %errorlevel%^)
popd >nul 2>&1
endlocal
exit /b 1
:err
popd >nul 2>&1
echo [error] Build/package failed.
endlocal
exit /b 1
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
SERVER_SRC="$ROOT/Overlord-Server"
CLIENT_SRC="$ROOT/Overlord-Client"
DIST_CLIENTS_SRC="$ROOT/dist-clients"
RELEASE_DIR="$ROOT/release/prod-package"
if [[ ! -f "$SERVER_SRC/package.json" ]]; then
echo "[error] Overlord-Server not found at: $SERVER_SRC" >&2
exit 1
fi
if [[ ! -f "$CLIENT_SRC/go.mod" ]]; then
echo "[error] Overlord-Client not found at: $CLIENT_SRC" >&2
exit 1
fi
if ! command -v bun >/dev/null 2>&1; then
echo "[error] bun was not found in PATH." >&2
exit 1
fi
if ! command -v go >/dev/null 2>&1; then
echo "[error] go was not found in PATH." >&2
exit 1
fi
copy_tree_excluding() {
local src="$1"
local dst="$2"
shift 2
mkdir -p "$dst"
if command -v rsync >/dev/null 2>&1; then
local excludes=()
for pattern in "$@"; do
excludes+=(--exclude "$pattern")
done
rsync -a --delete "${excludes[@]}" "$src/" "$dst/"
else
local tar_excludes=()
for pattern in "$@"; do
tar_excludes+=("--exclude=$pattern")
done
(cd "$src" && tar "${tar_excludes[@]}" -cf - .) | (cd "$dst" && tar -xf -)
fi
}
echo "[1/5] Building server bundle..."
pushd "$SERVER_SRC" >/dev/null
bun install
bun run build:css
bun run build
popd >/dev/null
echo "[2/5] Skipping prebuilt client binaries (prod package exports client source only)"
echo "[3/5] Preparing release folder..."
rm -rf "$RELEASE_DIR"
mkdir -p "$RELEASE_DIR"
echo "[4/5] Exporting Overlord-Server..."
copy_tree_excluding "$SERVER_SRC" "$RELEASE_DIR/Overlord-Server" "node_modules" ".git" ".vscode"
echo "[5/5] Exporting Overlord-Client source for runtime builds..."
copy_tree_excluding "$CLIENT_SRC" "$RELEASE_DIR/Overlord-Client" "build" ".git" ".vscode"
if [[ -d "$DIST_CLIENTS_SRC" ]]; then
echo "[extra] Copying prebuilt dist-clients..."
mkdir -p "$RELEASE_DIR/dist-clients"
cp -a "$DIST_CLIENTS_SRC/." "$RELEASE_DIR/dist-clients/"
fi
cat > "$RELEASE_DIR/start-prod-release.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT/Overlord-Server"
export HOST="${HOST:-0.0.0.0}"
export PORT="${PORT:-5173}"
export LOG_LEVEL="${LOG_LEVEL:-info}"
export NODE_ENV="${NODE_ENV:-production}"
bun install
bun run build:css && bun run vendor
bun run minify
bun run src/index.ts
EOF
chmod +x "$RELEASE_DIR/start-prod-release.sh"
echo
echo "[ok] Production package created:"
echo " $RELEASE_DIR"
echo
echo "Run this from the package folder:"
echo " ./start-prod-release.sh"
+117
View File
@@ -0,0 +1,117 @@
@echo off
REM Generate self-signed TLS certificates for Overlord (Windows)
REM Requires OpenSSL to be installed and in PATH
setlocal EnableDelayedExpansion
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "CERT_DIR=%ROOT%certs"
set DAYS=3650
set COUNTRY=US
set STATE=State
set CITY=City
set ORG=Overlord
set ORG_UNIT=IT
if "%~1"=="" (
set COMMON_NAME=localhost
) else (
set COMMON_NAME=%~1
)
echo =========================================
echo Generating TLS Certificates for Overlord
echo =========================================
echo Common Name: %COMMON_NAME%
echo Certificate Directory: %CERT_DIR%
echo Validity: %DAYS% days
echo.
REM Check if OpenSSL is available
where openssl >nul 2>nul
if %ERRORLEVEL% neq 0 (
echo ERROR: OpenSSL is not installed or not in PATH
echo.
echo Please install OpenSSL from:
echo - https://slproweb.com/products/Win32OpenSSL.html
echo - Or use Chocolatey: choco install openssl
echo - Or use Git Bash which includes OpenSSL
exit /b 1
)
REM Create certs directory if it doesn't exist
if not exist "%CERT_DIR%" mkdir "%CERT_DIR%"
REM Generate private key
echo [1/3] Generating private key...
openssl genrsa -out "%CERT_DIR%\server.key" 2048
REM Generate certificate signing request
echo [2/3] Generating certificate signing request...
openssl req -new -key "%CERT_DIR%\server.key" -out "%CERT_DIR%\server.csr" -subj "/C=%COUNTRY%/ST=%STATE%/L=%CITY%/O=%ORG%/OU=%ORG_UNIT%/CN=%COMMON_NAME%"
REM Generate self-signed certificate with SAN
echo [3/3] Generating self-signed certificate...
(
echo [req]
echo default_bits = 2048
echo prompt = no
echo default_md = sha256
echo distinguished_name = dn
echo req_extensions = req_ext
echo.
echo [dn]
echo C=%COUNTRY%
echo ST=%STATE%
echo L=%CITY%
echo O=%ORG%
echo OU=%ORG_UNIT%
echo CN=%COMMON_NAME%
echo.
echo [req_ext]
echo subjectAltName = @alt_names
echo.
echo [alt_names]
echo DNS.1 = %COMMON_NAME%
echo DNS.2 = localhost
echo DNS.3 = *.local
echo IP.1 = 127.0.0.1
echo IP.2 = ::1
) > "%CERT_DIR%\san.cnf"
if not "%~2"=="" (
echo IP.3 = %~2>> "%CERT_DIR%\san.cnf"
echo Added IP: %~2
)
openssl x509 -req -in "%CERT_DIR%\server.csr" -signkey "%CERT_DIR%\server.key" -out "%CERT_DIR%\server.crt" -days %DAYS% -sha256 -extfile "%CERT_DIR%\san.cnf" -extensions req_ext
REM Clean up
del "%CERT_DIR%\server.csr"
del "%CERT_DIR%\san.cnf"
echo.
echo =========================================
echo ✓ Certificates generated successfully!
echo =========================================
echo Certificate: %CERT_DIR%\server.crt
echo Private Key: %CERT_DIR%\server.key
echo.
echo To use these certificates:
echo 1. Set environment variable: set OVERLORD_TLS=true
echo 2. Optionally set custom paths:
echo set OVERLORD_TLS_CERT=%CERT_DIR%\server.crt
echo set OVERLORD_TLS_KEY=%CERT_DIR%\server.key
echo.
echo ⚠️ NOTE: Self-signed certificates require clients to:
echo - Skip certificate verification (insecure), OR
echo - Trust the server.crt certificate manually
echo.
echo For production, use proper certificates from:
echo - Let's Encrypt (free, automated)
echo - Your organization's certificate authority
echo =========================================
endlocal
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
# Generate self-signed TLS certificates for Overlord
# For production, use proper certificates from Let's Encrypt or your CA
set -e
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
CERT_DIR="$ROOT/certs"
DAYS=3650 # 10 years
COUNTRY="US"
STATE="State"
CITY="City"
ORG="Overlord"
ORG_UNIT="IT"
COMMON_NAME="${1:-localhost}"
echo "========================================="
echo "Generating TLS Certificates for Overlord"
echo "========================================="
echo "Common Name: $COMMON_NAME"
echo "Certificate Directory: $CERT_DIR"
echo "Validity: $DAYS days"
echo ""
# Create certs directory if it doesn't exist
mkdir -p "$CERT_DIR"
# Generate private key
echo "[1/3] Generating private key..."
openssl genrsa -out "$CERT_DIR/server.key" 2048
# Generate certificate signing request (CSR)
echo "[2/3] Generating certificate signing request..."
openssl req -new \
-key "$CERT_DIR/server.key" \
-out "$CERT_DIR/server.csr" \
-subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORG/OU=$ORG_UNIT/CN=$COMMON_NAME"
# Generate self-signed certificate with SAN (Subject Alternative Names)
echo "[3/3] Generating self-signed certificate..."
cat > "$CERT_DIR/san.cnf" << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[dn]
C=$COUNTRY
ST=$STATE
L=$CITY
O=$ORG
OU=$ORG_UNIT
CN=$COMMON_NAME
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = $COMMON_NAME
DNS.2 = localhost
DNS.3 = *.local
IP.1 = 127.0.0.1
IP.2 = ::1
EOF
# Add additional IP if provided as second argument
if [ -n "$2" ]; then
echo "IP.3 = $2" >> "$CERT_DIR/san.cnf"
echo "Added IP: $2"
fi
openssl x509 -req \
-in "$CERT_DIR/server.csr" \
-signkey "$CERT_DIR/server.key" \
-out "$CERT_DIR/server.crt" \
-days $DAYS \
-sha256 \
-extfile "$CERT_DIR/san.cnf" \
-extensions req_ext
# Clean up CSR and config
rm "$CERT_DIR/server.csr" "$CERT_DIR/san.cnf"
# Set permissions
chmod 600 "$CERT_DIR/server.key"
chmod 644 "$CERT_DIR/server.crt"
echo ""
echo "========================================="
echo "✓ Certificates generated successfully!"
echo "========================================="
echo "Certificate: $CERT_DIR/server.crt"
echo "Private Key: $CERT_DIR/server.key"
echo ""
echo "To use these certificates:"
echo " 1. Set environment variable: OVERLORD_TLS=true"
echo " 2. Optionally set custom paths:"
echo " OVERLORD_TLS_CERT=$CERT_DIR/server.crt"
echo " OVERLORD_TLS_KEY=$CERT_DIR/server.key"
echo ""
echo "⚠️ NOTE: Self-signed certificates require clients to:"
echo " - Skip certificate verification (insecure), OR"
echo " - Trust the server.crt certificate manually"
echo ""
echo "For production, use proper certificates from:"
echo " - Let's Encrypt (free, automated)"
echo " - Your organization's certificate authority"
echo "========================================="
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env bash
set -eu
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
CLIENT_DIR="$ROOT/Overlord-Client"
DIST_DIR="$ROOT/dist-clients"
GO_BIN="${GO_BIN:-go}"
GO_TAGS=()
if [ "${NO_PRINTING:-false}" = "true" ]; then
echo "[client] printing disabled via build tags"
GO_TAGS+=("-tags" "noprint")
fi
# detect platform
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
Darwin) PLATFORM="mac";;
Linux) PLATFORM="linux";;
FreeBSD) PLATFORM="freebsd";;
OpenBSD) PLATFORM="openbsd";;
*) PLATFORM="unknown";;
esac
echo "[client] platform detected: $OS ($PLATFORM) arch: $ARCH"
# determine expected dist binary name
BIN_NAME=""
if [ "$PLATFORM" = "mac" ]; then
if [ "$ARCH" = "x86_64" ]; then
BIN_NAME="agent-darwin-amd64"
else
BIN_NAME="agent-darwin-arm64"
fi
elif [ "$PLATFORM" = "linux" ]; then
BIN_NAME="agent-linux-amd64"
elif [ "$PLATFORM" = "freebsd" ]; then
if [ "$ARCH" = "x86_64" ]; then
BIN_NAME="agent-freebsd-amd64"
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
BIN_NAME="agent-freebsd-arm64"
fi
elif [ "$PLATFORM" = "openbsd" ]; then
if [ "$ARCH" = "x86_64" ]; then
BIN_NAME="agent-openbsd-amd64"
elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
BIN_NAME="agent-openbsd-arm64"
fi
fi
if [ "$PLATFORM" != "mac" ] && [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then
echo "[client] found prebuilt client binary: $DIST_DIR/$BIN_NAME"
echo "[client] starting prebuilt agent"
OVERLORD_SERVER="wss://localhost:5173" \
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
OVERLORD_MODE="dev" \
"${DIST_DIR:?}/$BIN_NAME"
exit 0
fi
if [ "$PLATFORM" = "mac" ]; then
echo "[client] macOS dev mode uses a rebuilt stable binary"
else
echo "[client] no suitable prebuilt client binary found in $DIST_DIR; falling back to 'go run'"
fi
cd "$CLIENT_DIR"
if ! command -v "$GO_BIN" >/dev/null 2>&1; then
echo "[client] go not found. Set GO_BIN to your Go binary (>=1.21) or install Go." >&2
exit 1
fi
GO_VER=$($GO_BIN env GOVERSION 2>/dev/null || true)
GO_MINOR=$(echo "$GO_VER" | sed -E 's/^go[0-9]+\.([0-9]+).*/\1/')
if [ -z "$GO_MINOR" ]; then
echo "[client] unable to determine Go version (got '$GO_VER')." >&2
exit 1
fi
if [ "$GO_MINOR" -lt 21 ]; then
echo "[client] Go >=1.21 required (found $GO_VER). Install a newer Go or point GO_BIN to one." >&2
exit 1
fi
echo "[client] using go at: $(command -v $GO_BIN) ($GO_VER)"
echo "[client] go mod tidy..."
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
"$GO_BIN" mod tidy
if [ "$PLATFORM" = "mac" ] && [ -n "$BIN_NAME" ]; then
mkdir -p "$DIST_DIR"
DEV_BIN="$DIST_DIR/$BIN_NAME"
echo "[client] building stable macOS dev binary at $DEV_BIN"
if [ "${#GO_TAGS[@]}" -gt 0 ]; then
GOINSECURE="*" \
GOPROXY="https://proxy.golang.org,direct" \
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
"$GO_BIN" build "${GO_TAGS[@]}" -o "$DEV_BIN" ./cmd/agent
else
GOINSECURE="*" \
GOPROXY="https://proxy.golang.org,direct" \
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
"$GO_BIN" build -o "$DEV_BIN" ./cmd/agent
fi
echo "[client] starting stable macOS dev binary"
OVERLORD_SERVER="wss://localhost:5173" \
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
OVERLORD_MODE="dev" \
exec "$DEV_BIN"
fi
echo "[client] starting agent via 'go run'"
if [ "${#GO_TAGS[@]}" -gt 0 ]; then
OVERLORD_SERVER="wss://localhost:5173" \
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
OVERLORD_MODE="dev" \
GOINSECURE="*" \
GOPROXY="https://proxy.golang.org,direct" \
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
"$GO_BIN" run "${GO_TAGS[@]}" ./cmd/agent
else
OVERLORD_SERVER="wss://localhost:5173" \
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
OVERLORD_MODE="dev" \
GOINSECURE="*" \
GOPROXY="https://proxy.golang.org,direct" \
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
"$GO_BIN" run ./cmd/agent
fi
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -eu
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
SERVER_DIR="$ROOT/Overlord-Server"
BUN_BIN="${BUN_BIN:-bun}"
# detect platform
OS="$(uname -s)"
case "$OS" in
Darwin) PLATFORM="mac";;
Linux) PLATFORM="linux";;
*) PLATFORM="unknown";;
esac
echo "[server] platform detected: $OS ($PLATFORM)"
cd "$SERVER_DIR"
if ! command -v "$BUN_BIN" >/dev/null 2>&1; then
echo "[server] bun not found. Set BUN_BIN to your bun binary or install bun for this environment." >&2
exit 1
fi
echo "[server] using bun at: $(command -v $BUN_BIN)"
echo "[server] bun install..."
"$BUN_BIN" install
echo "[server] building Tailwind CSS..."
"$BUN_BIN" run build:css
echo "[server] building vendor assets..."
"$BUN_BIN" run vendor
echo "[server] starting bun dev (foreground)"
# Use exec so the script process is replaced by the bun process. This keeps the
# bun process as a child of the dispatcher so the dispatcher can kill it.
export OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only"
exec "$BUN_BIN" run dev
+36
View File
@@ -0,0 +1,36 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
if not defined NO_PRINTING set NO_PRINTING=false
echo === Ensuring server deps (Bun) ===
pushd "%ROOT%Overlord-Server"
echo [server] bun install...
call bun install
popd
echo === Ensuring client dependencies (Go) ===
pushd "%ROOT%Overlord-Client"
if exist go.mod (
echo [client] go mod tidy...
go mod tidy
)
popd
echo === Launching windows ===
rem Bind server to all interfaces for remote access
set HOST=0.0.0.0
set PORT=5173
set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only
set OVERLORD_DISABLE_AGENT_AUTH=true
set LOG_LEVEL=debug
start "Overlord-Server" cmd /k "cd /d ""%ROOT%Overlord-Server"" && set OVERLORD_DISABLE_AGENT_AUTH=true && set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only && set LOG_LEVEL=debug && set NODE_ENV=development && bun install && bun run start"
timeout /t 3 /nobreak >nul
start "Overlord-Client" cmd /k "cd /d ""%ROOT%Overlord-Client"" && set OVERLORD_SERVER=wss://localhost:5173 && set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only && set OVERLORD_TLS_INSECURE_SKIP_VERIFY=true && set OVERLORD_MODE=dev && set OVERLORD_CAPTURE_METRICS=true && set GOINSECURE=* && set GOSUMDB=off && set GOPROXY=https://proxy.golang.org,direct && go mod tidy && go run ./cmd/agent"
echo Done. Terminals stay open (/k) for logs.
endlocal
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "$0")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
SERVER_SCRIPT="$SCRIPT_DIR/start-dev-server.sh"
CLIENT_SCRIPT="$SCRIPT_DIR/start-dev-client.sh"
quote() {
printf "%q" "$1"
}
pause_for_error() {
local exit_code=$?
if [ "$exit_code" -ne 0 ]; then
echo
echo "[start-dev] failed with exit code $exit_code"
echo "Press any key to close this window."
read -r -n 1 _ || true
fi
exit "$exit_code"
}
trap pause_for_error EXIT
if [ "$(uname -s)" != "Darwin" ]; then
echo "[start-dev] start-dev.command is intended for macOS."
echo "[start-dev] Use ./scripts/start-dev.sh on this platform."
exit 1
fi
if ! command -v osascript >/dev/null 2>&1; then
echo "[start-dev] osascript was not found. Use ./scripts/start-dev.sh from a terminal instead."
exit 1
fi
if [ ! -f "$SERVER_SCRIPT" ]; then
echo "[start-dev] missing $SERVER_SCRIPT" >&2
exit 1
fi
if [ ! -f "$CLIENT_SCRIPT" ]; then
echo "[start-dev] missing $CLIENT_SCRIPT" >&2
exit 1
fi
ROOT_Q="$(quote "$ROOT")"
SERVER_SCRIPT_Q="$(quote "$SERVER_SCRIPT")"
CLIENT_SCRIPT_Q="$(quote "$CLIENT_SCRIPT")"
NO_PRINTING_Q="$(quote "${NO_PRINTING:-false}")"
SERVER_CMD="cd $ROOT_Q && HOST=0.0.0.0 PORT=5173 OVERLORD_DISABLE_AGENT_AUTH=true OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only LOG_LEVEL=debug NODE_ENV=development /bin/bash $SERVER_SCRIPT_Q"
CLIENT_CMD="sleep 3; cd $ROOT_Q && NO_PRINTING=$NO_PRINTING_Q /bin/bash $CLIENT_SCRIPT_Q"
open_terminal() {
local title="$1"
local command="$2"
osascript - "$title" "$command" <<'APPLESCRIPT'
on run argv
set windowTitle to item 1 of argv
set shellCommand to item 2 of argv
tell application "Terminal"
activate
do script shellCommand
delay 0.2
set custom title of selected tab of front window to windowTitle
end tell
end run
APPLESCRIPT
}
echo "=== Launching Overlord dev terminals ==="
echo "[start-dev] root: $ROOT"
echo "[start-dev] opening server window..."
open_terminal "Overlord-Server" "$SERVER_CMD"
echo "[start-dev] opening client window..."
open_terminal "Overlord-Client" "$CLIENT_CMD"
echo
echo "Done. Server and client logs are running in separate Terminal windows."
echo "Close those Terminal windows or press Ctrl+C inside them to stop dev processes."
+74
View File
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
set -eu
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
# Dispatcher script kept for backwards compatibility.
# Usage:
# ./start-dev.sh # start server (background) and client (foreground)
# ./start-dev.sh server # start only server
# ./start-dev.sh client # start only client
SERVER_SCRIPT="$SCRIPT_DIR/start-dev-server.sh"
CLIENT_SCRIPT="$SCRIPT_DIR/start-dev-client.sh"
if [ "$#" -eq 0 ]; then
# start server in background, then client in foreground (original behavior)
echo "[start-dev] starting server (background) and client (foreground)"
if [ -x "$SERVER_SCRIPT" ]; then
"$SERVER_SCRIPT" &
SERVER_PID=$!
echo "[start-dev] server started (pid $SERVER_PID)"
else
echo "[start-dev] $SERVER_SCRIPT not found or not executable. Run \"chmod +x $SERVER_SCRIPT\" or run the scripts directly." >&2
exit 1
fi
# Ensure we kill the server child if this script exits or receives a signal.
cleanup() {
echo "[start-dev] cleaning up"
if [ -n "${SERVER_PID:-}" ] && kill -0 "$SERVER_PID" >/dev/null 2>&1; then
echo "[start-dev] killing server (pid $SERVER_PID)"
kill "$SERVER_PID" 2>/dev/null || true
sleep 1
if kill -0 "$SERVER_PID" >/dev/null 2>&1; then
echo "[start-dev] server did not exit; force killing"
kill -9 "$SERVER_PID" 2>/dev/null || true
fi
fi
}
trap cleanup INT TERM EXIT
if [ -x "$CLIENT_SCRIPT" ]; then
# run client in foreground; when it exits the trap will run and kill server
"$CLIENT_SCRIPT"
else
echo "[start-dev] $CLIENT_SCRIPT not found or not executable. Run \"chmod +x $CLIENT_SCRIPT\" or run the scripts directly." >&2
exit 1
fi
# explicit exit so the EXIT trap runs
exit 0
fi
case "$1" in
server)
if [ -x "$SERVER_SCRIPT" ]; then
exec "$SERVER_SCRIPT"
else
echo "[start-dev] $SERVER_SCRIPT not found or not executable." >&2
exit 1
fi
;;
client)
if [ -x "$CLIENT_SCRIPT" ]; then
exec "$CLIENT_SCRIPT"
else
echo "[start-dev] $CLIENT_SCRIPT not found or not executable." >&2
exit 1
fi
;;
*)
echo "Usage: $0 [server|client]"
exit 1
;;
esac
+209
View File
@@ -0,0 +1,209 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
set "MODE=%~1"
REM Tuned production launcher for small VPS targets.
REM Usage:
REM scripts\start-prod-tuned.bat
REM scripts\start-prod-tuned.bat loadtest
REM scripts\start-prod-tuned.bat loadtest-baseline
REM scripts\start-prod-tuned.bat loadtest-profile
REM
REM Optional env overrides before running:
REM PORT=5173
REM HOST=0.0.0.0
REM OVERLORD_AGENT_TOKEN=change-me
REM OVERLORD_USER=admin
REM OVERLORD_PASS=change-me
REM OVERLORD_TLS_OFFLOAD=false
REM OVERLORD_HEARTBEAT_INTERVAL_MS=30000
REM OVERLORD_HEARTBEAT_SWEEP_TICK_MS=1000
REM OVERLORD_CLIENT_DB_SYNC_MS=15000
REM OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=100
REM OVERLORD_EVENT_LOOP_SAMPLE_MS=100
REM OVERLORD_EVENT_LOOP_HISTORY_SECONDS=60
REM OVERLORD_DASHBOARD_DEBOUNCE_MS=1000
REM OVERLORD_DASHBOARD_EVENT_FLUSH_MS=1000
REM OVERLORD_DASHBOARD_EVENT_INLINE_LIMIT=20
REM OVERLORD_OFFLINE_BATCH_SIZE=250
REM OVERLORD_OFFLINE_BATCH_DELAY_MS=25
REM OVERLORD_LOAD_TEST_PROFILE=realistic
REM OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB=true
REM OVERLORD_THUMBNAILS_DASHBOARD_ENABLED=false
REM MAX_WS_MESSAGE_BYTES_CLIENT=8388608
REM MAX_WS_MESSAGE_BYTES_VIEWER=1048576
if not defined HOST set HOST=0.0.0.0
if not defined PORT set PORT=5173
if not defined LOG_LEVEL set LOG_LEVEL=info
if not defined NODE_ENV set NODE_ENV=production
REM Small-host connection tuning. These are conservative for ~250 mostly-idle
REM agents on a 2 vCPU / 2 GB host.
if not defined OVERLORD_HEARTBEAT_INTERVAL_MS set OVERLORD_HEARTBEAT_INTERVAL_MS=30000
if not defined OVERLORD_HEARTBEAT_SWEEP_TICK_MS set OVERLORD_HEARTBEAT_SWEEP_TICK_MS=1000
if not defined OVERLORD_CLIENT_DB_SYNC_MS set OVERLORD_CLIENT_DB_SYNC_MS=15000
if not defined OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE set OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=100
if not defined OVERLORD_EVENT_LOOP_SAMPLE_MS set OVERLORD_EVENT_LOOP_SAMPLE_MS=100
if not defined OVERLORD_EVENT_LOOP_HISTORY_SECONDS set OVERLORD_EVENT_LOOP_HISTORY_SECONDS=60
if not defined OVERLORD_DASHBOARD_DEBOUNCE_MS set OVERLORD_DASHBOARD_DEBOUNCE_MS=1000
if not defined OVERLORD_DASHBOARD_EVENT_FLUSH_MS set OVERLORD_DASHBOARD_EVENT_FLUSH_MS=1000
if not defined OVERLORD_DASHBOARD_EVENT_INLINE_LIMIT set OVERLORD_DASHBOARD_EVENT_INLINE_LIMIT=20
if not defined OVERLORD_OFFLINE_BATCH_SIZE set OVERLORD_OFFLINE_BATCH_SIZE=250
if not defined OVERLORD_OFFLINE_BATCH_DELAY_MS set OVERLORD_OFFLINE_BATCH_DELAY_MS=25
if not defined OVERLORD_STALE_MS set OVERLORD_STALE_MS=120000
if not defined OVERLORD_DISCONNECT_TIMEOUT_MS set OVERLORD_DISCONNECT_TIMEOUT_MS=10000
if not defined PRUNE_BATCH set PRUNE_BATCH=250
if not defined MAX_WS_MESSAGE_BYTES_CLIENT set MAX_WS_MESSAGE_BYTES_CLIENT=8388608
if not defined MAX_WS_MESSAGE_BYTES_VIEWER set MAX_WS_MESSAGE_BYTES_VIEWER=1048576
if not defined OVERLORD_WS_UPGRADE_RATE_WINDOW_MS set OVERLORD_WS_UPGRADE_RATE_WINDOW_MS=10000
set OVERLORD_PROFILE_SOURCE_MODE=false
REM Keep proxy trust disabled unless the deploy explicitly opts into it.
if not defined OVERLORD_TLS_OFFLOAD set OVERLORD_TLS_OFFLOAD=false
if not defined OVERLORD_TRUST_PROXY set OVERLORD_TRUST_PROXY=false
if not defined OVERLORD_TRUST_PROXY_HEADERS set OVERLORD_TRUST_PROXY_HEADERS=false
if not defined OVERLORD_AUTH_COOKIE_SECURE set OVERLORD_AUTH_COOKIE_SECURE=auto
if /I "%MODE%"=="loadtest" (
if not defined OVERLORD_AGENT_TOKEN (
echo [error] loadtest mode requires OVERLORD_AGENT_TOKEN to be set.
echo Example:
echo set OVERLORD_AGENT_TOKEN=some-long-random-token
echo scripts\start-prod-tuned.bat loadtest
endlocal
exit /b 1
)
set OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS=true
if not defined OVERLORD_LOAD_TEST_PROFILE set OVERLORD_LOAD_TEST_PROFILE=realistic
if not defined OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS set OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS=false
if not defined OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB set OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB=true
if "%OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE%"=="100" set OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=500
if not defined OVERLORD_WS_UPGRADE_RATE_MAX set OVERLORD_WS_UPGRADE_RATE_MAX=2000
if not defined OVERLORD_THUMBNAILS_DASHBOARD_ENABLED set OVERLORD_THUMBNAILS_DASHBOARD_ENABLED=false
) else if /I "%MODE%"=="loadtest-profile" (
if not defined OVERLORD_AGENT_TOKEN (
echo [error] loadtest-profile mode requires OVERLORD_AGENT_TOKEN to be set.
echo Example:
echo set OVERLORD_AGENT_TOKEN=some-long-random-token
echo scripts\start-prod-tuned.bat loadtest-profile
endlocal
exit /b 1
)
set OVERLORD_PROFILE_SOURCE_MODE=true
set OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS=true
if not defined OVERLORD_LOAD_TEST_PROFILE set OVERLORD_LOAD_TEST_PROFILE=realistic
if not defined OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS set OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS=false
if not defined OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB set OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB=true
if "%OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE%"=="100" set OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=500
if not defined OVERLORD_WS_UPGRADE_RATE_MAX set OVERLORD_WS_UPGRADE_RATE_MAX=2000
if not defined OVERLORD_THUMBNAILS_DASHBOARD_ENABLED set OVERLORD_THUMBNAILS_DASHBOARD_ENABLED=false
) else if /I "%MODE%"=="loadtest-baseline" (
if not defined OVERLORD_AGENT_TOKEN (
echo [error] loadtest-baseline mode requires OVERLORD_AGENT_TOKEN to be set.
echo Example:
echo set OVERLORD_AGENT_TOKEN=some-long-random-token
echo scripts\start-prod-tuned.bat loadtest-baseline
endlocal
exit /b 1
)
set OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS=true
if not defined OVERLORD_LOAD_TEST_PROFILE set OVERLORD_LOAD_TEST_PROFILE=baseline
if not defined OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS set OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS=true
if not defined OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB set OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB=true
if "%OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE%"=="100" set OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=500
if not defined OVERLORD_WS_UPGRADE_RATE_MAX set OVERLORD_WS_UPGRADE_RATE_MAX=2000
if not defined OVERLORD_THUMBNAILS_DASHBOARD_ENABLED set OVERLORD_THUMBNAILS_DASHBOARD_ENABLED=false
) else (
set OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS=false
if not defined OVERLORD_WS_UPGRADE_RATE_MAX set OVERLORD_WS_UPGRADE_RATE_MAX=30
)
echo === Overlord tuned production server ===
echo HOST=%HOST%
echo PORT=%PORT%
echo NODE_ENV=%NODE_ENV%
echo LOG_LEVEL=%LOG_LEVEL%
echo OVERLORD_HEARTBEAT_INTERVAL_MS=%OVERLORD_HEARTBEAT_INTERVAL_MS%
echo OVERLORD_HEARTBEAT_SWEEP_TICK_MS=%OVERLORD_HEARTBEAT_SWEEP_TICK_MS%
echo OVERLORD_CLIENT_DB_SYNC_MS=%OVERLORD_CLIENT_DB_SYNC_MS%
echo OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE=%OVERLORD_CLIENT_DB_SYNC_BATCH_SIZE%
echo OVERLORD_EVENT_LOOP_SAMPLE_MS=%OVERLORD_EVENT_LOOP_SAMPLE_MS%
echo OVERLORD_EVENT_LOOP_HISTORY_SECONDS=%OVERLORD_EVENT_LOOP_HISTORY_SECONDS%
echo OVERLORD_DASHBOARD_DEBOUNCE_MS=%OVERLORD_DASHBOARD_DEBOUNCE_MS%
echo OVERLORD_DASHBOARD_EVENT_FLUSH_MS=%OVERLORD_DASHBOARD_EVENT_FLUSH_MS%
echo OVERLORD_DASHBOARD_EVENT_INLINE_LIMIT=%OVERLORD_DASHBOARD_EVENT_INLINE_LIMIT%
echo OVERLORD_OFFLINE_BATCH_SIZE=%OVERLORD_OFFLINE_BATCH_SIZE%
echo OVERLORD_OFFLINE_BATCH_DELAY_MS=%OVERLORD_OFFLINE_BATCH_DELAY_MS%
echo MAX_WS_MESSAGE_BYTES_CLIENT=%MAX_WS_MESSAGE_BYTES_CLIENT%
echo MAX_WS_MESSAGE_BYTES_VIEWER=%MAX_WS_MESSAGE_BYTES_VIEWER%
echo OVERLORD_WS_UPGRADE_RATE_MAX=%OVERLORD_WS_UPGRADE_RATE_MAX%
echo OVERLORD_WS_UPGRADE_RATE_WINDOW_MS=%OVERLORD_WS_UPGRADE_RATE_WINDOW_MS%
echo OVERLORD_TLS_OFFLOAD=%OVERLORD_TLS_OFFLOAD%
echo OVERLORD_TRUST_PROXY=%OVERLORD_TRUST_PROXY%
echo OVERLORD_TRUST_PROXY_HEADERS=%OVERLORD_TRUST_PROXY_HEADERS%
echo OVERLORD_AUTH_COOKIE_SECURE=%OVERLORD_AUTH_COOKIE_SECURE%
echo OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS=%OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS%
echo OVERLORD_LOAD_TEST_PROFILE=%OVERLORD_LOAD_TEST_PROFILE%
echo OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS=%OVERLORD_LOAD_TEST_SKIP_SIDE_EFFECTS%
echo OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB=%OVERLORD_LOAD_TEST_DEFER_SYNTHETIC_DB%
echo OVERLORD_THUMBNAILS_DASHBOARD_ENABLED=%OVERLORD_THUMBNAILS_DASHBOARD_ENABLED%
echo OVERLORD_PROFILE_SOURCE_MODE=%OVERLORD_PROFILE_SOURCE_MODE%
echo.
if /I "%OVERLORD_LOAD_TEST_ALLOW_UNSIGNED_AGENTS%"=="true" (
echo [warning] Synthetic unsigned load-test agents are enabled.
echo [warning] Do not use this mode for public production traffic.
echo.
)
pushd "%ROOT%Overlord-Server"
echo [build] installing deps...
call bun install
if errorlevel 1 goto :err
if /I "%OVERLORD_PROFILE_SOURCE_MODE%"=="true" (
echo [build] building server assets for source-profile mode...
call bun run build:css
if errorlevel 1 goto :err
call bun run vendor
if errorlevel 1 goto :err
) else (
echo [build] building server assets and bundle...
call bun run build
if errorlevel 1 goto :err
)
if /I "%OVERLORD_PROFILE_SOURCE_MODE%"=="true" (
echo [build] skipping compiled executable so profiler keeps source function names.
) else (
echo [build] compiling Windows production executable...
call bun run build:prod:win
if errorlevel 1 goto :err
)
echo [build] copying Overlord-Client source for runtime builds...
robocopy "%ROOT%Overlord-Client" "%ROOT%Overlord-Server\dist\Overlord-Client" /E /XD build .git .vscode /NFL /NDL /NJH /NJS >nul
if errorlevel 8 goto :err
set "OVERLORD_ROOT=%ROOT%Overlord-Server"
if /I "%OVERLORD_PROFILE_SOURCE_MODE%"=="true" (
echo [server] starting source-profile server with Bun...
call bun src/index.ts
) else (
echo [server] starting compiled production server...
call "%ROOT%Overlord-Server\dist\overlord-server.exe"
)
popd
echo Server stopped.
endlocal
exit /b 0
:err
popd >nul 2>&1
echo [error] Production start failed.
endlocal
exit /b 1
+61
View File
@@ -0,0 +1,61 @@
@echo off
setlocal
set "SCRIPT_DIR=%~dp0"
for %%I in ("%SCRIPT_DIR%..") do set "ROOT=%%~fI\"
REM Simple production launcher for Overlord server.
REM Builds the Tailwind CSS and server bundle, then runs the compiled executable.
REM Env overrides you can set before running:
REM PORT=5173
REM HOST=0.0.0.0
REM OVERLORD_USER=admin
REM OVERLORD_PASS=admin
REM LOG_LEVEL=info
REM NODE_ENV=production
if not defined HOST set HOST=0.0.0.0
if not defined PORT set PORT=5173
if not defined LOG_LEVEL set LOG_LEVEL=info
if not defined NODE_ENV set NODE_ENV=production
pushd "%ROOT%Overlord-Server"
echo [build] installing deps (bun install)...
call bun install
if errorlevel 1 goto :err
echo [build] building Tailwind CSS...
call bun run build:css
if errorlevel 1 goto :err
echo [build] building server bundle...
call bun run build
if errorlevel 1 goto :err
echo [build] compiling Windows production executable...
call bun run build:prod:win
if errorlevel 1 goto :err
echo [build] copying Overlord-Client source for runtime builds...
robocopy "%ROOT%Overlord-Client" "%ROOT%Overlord-Server\dist\Overlord-Client" /E /XD build .git .vscode /NFL /NDL /NJH /NJS >nul
REM robocopy exit codes 0-7 are success
if errorlevel 8 goto :err
if defined PORT (
echo [server] starting on port %PORT%...
) else (
echo [server] starting on default port...
)
echo [server] running compiled executable...
set "OVERLORD_ROOT=%ROOT%Overlord-Server"
call "%ROOT%Overlord-Server\dist\overlord-server.exe"
popd
echo Server stopped.
endlocal
exit /b 0
:err
popd >nul 2>&1
echo [error] Build failed.
endlocal
exit /b 1
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
SERVER_DIR="$ROOT/Overlord-Server"
BUN_BIN="${BUN_BIN:-bun}"
cd "$SERVER_DIR"
if ! command -v "$BUN_BIN" >/dev/null 2>&1; then
echo "[server] bun not found. Set BUN_BIN to your bun binary or install bun for this environment." >&2
exit 1
fi
echo "[server] using bun at: $(command -v $BUN_BIN)"
echo "[build] bun install..."
"$BUN_BIN" install
echo "[build] building Tailwind CSS..."
"$BUN_BIN" run build:css
echo "[build] building server bundle..."
"$BUN_BIN" run build
echo "[build] compiling Linux production executable..."
"$BUN_BIN" run build:prod:linux
echo "[build] copying Overlord-Client source for runtime builds..."
mkdir -p "$SERVER_DIR/dist/Overlord-Client"
rsync -a --exclude='build' --exclude='.git' --exclude='.vscode' "$ROOT/Overlord-Client/" "$SERVER_DIR/dist/Overlord-Client/" 2>/dev/null \
|| {
rm -rf "$SERVER_DIR/dist/Overlord-Client"
cp -a "$ROOT/Overlord-Client" "$SERVER_DIR/dist/Overlord-Client"
rm -rf "$SERVER_DIR/dist/Overlord-Client/build" "$SERVER_DIR/dist/Overlord-Client/.git" "$SERVER_DIR/dist/Overlord-Client/.vscode"
}
echo "[server] starting compiled executable..."
PORT="${PORT:-5173}" \
HOST="${HOST:-0.0.0.0}" \
OVERLORD_USER="${OVERLORD_USER:-admin}" \
OVERLORD_PASS="${OVERLORD_PASS:-admin}" \
LOG_LEVEL="${LOG_LEVEL:-info}" \
NODE_ENV="${NODE_ENV:-production}" \
OVERLORD_ROOT="$SERVER_DIR" \
"$SERVER_DIR/dist/overlord-server-linux-x64"