初始化
This commit is contained in:
1 parent
34474bd5fc
commit
b638b541d0
3008 files changed
+837699
No files matched your search
@@ -0,0 +1,55 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RootDir = Resolve-Path (Join-Path $ScriptDir "..")
|
||||
|
||||
$BackendDir = Join-Path $RootDir "offline-backend-20260512\backend"
|
||||
$FrontendDir = Join-Path $RootDir "frontend-web"
|
||||
$RuntimeDir = Join-Path $RootDir ".runtime"
|
||||
$LogDir = Join-Path $RuntimeDir "logs"
|
||||
$PidDir = Join-Path $RuntimeDir "pids"
|
||||
|
||||
$BackendHost = if ($env:BACKEND_HOST) { $env:BACKEND_HOST } else { "0.0.0.0" }
|
||||
$BackendPort = if ($env:BACKEND_PORT) { $env:BACKEND_PORT } else { "8001" }
|
||||
$FrontendHost = if ($env:FRONTEND_HOST) { $env:FRONTEND_HOST } else { "0.0.0.0" }
|
||||
$FrontendPort = if ($env:FRONTEND_PORT) { $env:FRONTEND_PORT } else { "5174" }
|
||||
|
||||
$HostIp = if ($env:HOST_IP) { $env:HOST_IP } else { "127.0.0.1" }
|
||||
$BackendPublicBaseUrl = if ($env:BACKEND_PUBLIC_BASE_URL) { $env:BACKEND_PUBLIC_BASE_URL } else { "http://${HostIp}:${BackendPort}" }
|
||||
$FrontendPublicBaseUrl = if ($env:FRONTEND_PUBLIC_BASE_URL) { $env:FRONTEND_PUBLIC_BASE_URL } else { "http://${HostIp}:${FrontendPort}" }
|
||||
$GatewayCorsOrigins = if ($env:GATEWAY_CORS_ORIGINS) {
|
||||
$env:GATEWAY_CORS_ORIGINS
|
||||
} else {
|
||||
"http://localhost:${FrontendPort},http://127.0.0.1:${FrontendPort},http://${HostIp}:${FrontendPort},http://localhost:8080,http://127.0.0.1:8080"
|
||||
}
|
||||
|
||||
$BackendPython = Join-Path $BackendDir ".venv\Scripts\python.exe"
|
||||
$BackendVendorDir = if ($env:BACKEND_VENDOR_DIR) { $env:BACKEND_VENDOR_DIR } else { Join-Path $BackendDir ".deer-flow\python-vendor" }
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $LogDir, $PidDir | Out-Null
|
||||
|
||||
function Test-PidRunning {
|
||||
param([string]$PidFile)
|
||||
if (-not (Test-Path -LiteralPath $PidFile)) { return $false }
|
||||
$rawPid = (Get-Content -LiteralPath $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
|
||||
$processId = 0
|
||||
if (-not [int]::TryParse([string]$rawPid, [ref]$processId)) { return $false }
|
||||
return [bool](Get-Process -Id $processId -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
function Stop-ProcessTree {
|
||||
param([int]$ProcessId)
|
||||
$children = Get-CimInstance Win32_Process -Filter "ParentProcessId=$ProcessId" -ErrorAction SilentlyContinue
|
||||
foreach ($child in $children) {
|
||||
Stop-ProcessTree -ProcessId ([int]$child.ProcessId)
|
||||
}
|
||||
$proc = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue
|
||||
if ($proc) {
|
||||
Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function ConvertTo-PSLiteral {
|
||||
param([string]$Value)
|
||||
return "'" + ($Value -replace "'", "''") + "'"
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
BACKEND_DIR="${ROOT_DIR}/offline-backend-20260512/backend"
|
||||
FRONTEND_DIR="${ROOT_DIR}/frontend-web"
|
||||
RUNTIME_DIR="${ROOT_DIR}/.runtime"
|
||||
LOG_DIR="${RUNTIME_DIR}/logs"
|
||||
PID_DIR="${RUNTIME_DIR}/pids"
|
||||
|
||||
BACKEND_HOST="${BACKEND_HOST:-0.0.0.0}"
|
||||
BACKEND_PORT="${BACKEND_PORT:-8001}"
|
||||
FRONTEND_HOST="${FRONTEND_HOST:-0.0.0.0}"
|
||||
FRONTEND_PORT="${FRONTEND_PORT:-5174}"
|
||||
|
||||
detect_host_ip() {
|
||||
if command -v hostname >/dev/null 2>&1; then
|
||||
# `hostname -I` is unsupported on Windows Git Bash; `|| true` keeps the
|
||||
# pipefail-safe fallback (HOST_IP then defaults to 127.0.0.1 below).
|
||||
hostname -I 2>/dev/null | awk '{print $1}' || true
|
||||
fi
|
||||
}
|
||||
|
||||
HOST_IP="${HOST_IP:-$(detect_host_ip)}"
|
||||
HOST_IP="${HOST_IP:-127.0.0.1}"
|
||||
|
||||
BACKEND_PUBLIC_BASE_URL="${BACKEND_PUBLIC_BASE_URL:-http://${HOST_IP}:${BACKEND_PORT}}"
|
||||
FRONTEND_PUBLIC_BASE_URL="${FRONTEND_PUBLIC_BASE_URL:-http://${HOST_IP}:${FRONTEND_PORT}}"
|
||||
|
||||
# The standalone legacy TaskCOP UI runs on Vite :8080 and calls the Gateway
|
||||
# directly through its configured b1ConsumerUrl. Keep its local origins in the
|
||||
# backend CORS allow-list instead of relying on a frontend reverse proxy.
|
||||
GATEWAY_CORS_ORIGINS="${GATEWAY_CORS_ORIGINS:-http://localhost:${FRONTEND_PORT},http://127.0.0.1:${FRONTEND_PORT},http://${HOST_IP}:${FRONTEND_PORT},http://localhost:8080,http://127.0.0.1:8080}"
|
||||
|
||||
mkdir -p "${LOG_DIR}" "${PID_DIR}"
|
||||
|
||||
is_running() {
|
||||
local pid_file="$1"
|
||||
[[ -f "${pid_file}" ]] || return 1
|
||||
|
||||
local pid
|
||||
pid="$(cat "${pid_file}" 2>/dev/null || true)"
|
||||
[[ -n "${pid}" ]] || return 1
|
||||
kill -0 "${pid}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
stop_by_pid_file() {
|
||||
local name="$1"
|
||||
local pid_file="$2"
|
||||
|
||||
if ! [[ -f "${pid_file}" ]]; then
|
||||
echo "${name} is not running (no pid file)."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local pid
|
||||
pid="$(cat "${pid_file}" 2>/dev/null || true)"
|
||||
if [[ -z "${pid}" ]] || ! kill -0 "${pid}" >/dev/null 2>&1; then
|
||||
echo "${name} is not running (stale pid file removed)."
|
||||
rm -f "${pid_file}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Stopping ${name} (pid ${pid})..."
|
||||
# Services are started with setsid, so the pid is also the process group id.
|
||||
# Stop the whole group to avoid leaving Vite/esbuild/uvicorn child processes.
|
||||
kill "-${pid}" >/dev/null 2>&1 || true
|
||||
kill "${pid}" >/dev/null 2>&1 || true
|
||||
|
||||
for _ in {1..30}; do
|
||||
if ! kill -0 "${pid}" >/dev/null 2>&1; then
|
||||
rm -f "${pid_file}"
|
||||
echo "${name} stopped."
|
||||
return 0
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
echo "${name} did not stop gracefully; killing..."
|
||||
kill -9 "-${pid}" >/dev/null 2>&1 || true
|
||||
kill -9 "${pid}" >/dev/null 2>&1 || true
|
||||
rm -f "${pid_file}"
|
||||
echo "${name} stopped."
|
||||
}
|
||||
|
||||
stop_by_pattern() {
|
||||
local name="$1"
|
||||
local pattern="$2"
|
||||
|
||||
if ! command -v pgrep >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local pids
|
||||
pids="$(pgrep -f "${pattern}" || true)"
|
||||
if [[ -z "${pids}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Stopping ${name} processes matching: ${pattern}"
|
||||
while IFS= read -r pid; do
|
||||
[[ -n "${pid}" ]] || continue
|
||||
[[ "${pid}" != "$$" ]] || continue
|
||||
kill "${pid}" >/dev/null 2>&1 || true
|
||||
done <<<"${pids}"
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
param(
|
||||
[ValidateSet("status", "start", "open")]
|
||||
[string]$Action = "status"
|
||||
)
|
||||
|
||||
$InstallRoot = "C:\Program Files (x86)\Intax\mbwsmdmclient"
|
||||
$RelatedServices = @(
|
||||
"mbwsmdmclient",
|
||||
"itxcltserver",
|
||||
"zfmgclient",
|
||||
"zfnetchkclient",
|
||||
"ZFICONTROL",
|
||||
"ZFFTSSERVER"
|
||||
)
|
||||
|
||||
function Show-MbwsStatus {
|
||||
Write-Host "MBWS related directory:" -ForegroundColor Cyan
|
||||
Write-Host " $InstallRoot"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "MBWS related services:" -ForegroundColor Cyan
|
||||
foreach ($name in $RelatedServices) {
|
||||
$svc = Get-Service -Name $name -ErrorAction SilentlyContinue
|
||||
if ($null -eq $svc) {
|
||||
Write-Host (" {0,-16} not found" -f $name) -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host (" {0,-16} {1}" -f $svc.Name, $svc.Status)
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "MBWS related processes:" -ForegroundColor Cyan
|
||||
Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$_.Path -like "C:\Program Files (x86)\Intax\*" -or
|
||||
$_.ProcessName -match "itx|mbws|zf"
|
||||
} |
|
||||
Select-Object ProcessName, Id, Path |
|
||||
Format-Table -AutoSize
|
||||
}
|
||||
|
||||
function Start-MbwsServices {
|
||||
foreach ($name in $RelatedServices) {
|
||||
$svc = Get-Service -Name $name -ErrorAction SilentlyContinue
|
||||
if ($null -eq $svc) {
|
||||
Write-Host "Service not found: $name" -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
|
||||
if ($svc.Status -eq "Running") {
|
||||
Write-Host "Already running: $name" -ForegroundColor Green
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host "Starting: $name" -ForegroundColor Yellow
|
||||
Start-Service -Name $name -ErrorAction Continue
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Show-MbwsStatus
|
||||
}
|
||||
|
||||
switch ($Action) {
|
||||
"status" {
|
||||
Show-MbwsStatus
|
||||
}
|
||||
"start" {
|
||||
Start-MbwsServices
|
||||
}
|
||||
"open" {
|
||||
if (Test-Path -LiteralPath $InstallRoot) {
|
||||
explorer $InstallRoot
|
||||
} else {
|
||||
Write-Error "Directory does not exist: $InstallRoot"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Package frontend node_modules for offline development.
|
||||
# Uses tar -h to dereference pnpm junctions so the archive is self-contained.
|
||||
param(
|
||||
[string]$OutputDir = (Join-Path (Split-Path $PSScriptRoot -Parent) "dist")
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Split-Path $PSScriptRoot -Parent
|
||||
$Frontend = Join-Path $Root "frontend-web"
|
||||
$Archive = Join-Path $OutputDir "frontend-offline-deps.tar.gz"
|
||||
|
||||
if (-not (Test-Path (Join-Path $Frontend "node_modules\.pnpm"))) {
|
||||
throw "frontend-web/node_modules is missing or incomplete. Run 'pnpm install' in frontend-web first."
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
|
||||
if (Test-Path $Archive) { Remove-Item $Archive -Force }
|
||||
|
||||
Write-Host "Packaging frontend dependencies..."
|
||||
Write-Host " Source: $Frontend"
|
||||
Write-Host " Output: $Archive"
|
||||
|
||||
$start = Get-Date
|
||||
tar -czhf $Archive -C $Frontend node_modules package.json pnpm-lock.yaml
|
||||
$elapsed = ((Get-Date) - $start).TotalSeconds
|
||||
$sizeMb = [math]::Round((Get-Item $Archive).Length / 1MB, 2)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Done in ${elapsed}s — ${sizeMb} MB"
|
||||
Write-Host ""
|
||||
Write-Host "Copy to offline machine, then run:"
|
||||
Write-Host " scripts\restore-frontend-offline-deps.ps1 -Archive <path-to-archive>"
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
FRONTEND="${ROOT}/frontend-web"
|
||||
OUTPUT_DIR="${1:-${ROOT}/dist}"
|
||||
ARCHIVE="${OUTPUT_DIR}/frontend-offline-deps.tar.gz"
|
||||
|
||||
if [[ ! -d "${FRONTEND}/node_modules/.pnpm" ]]; then
|
||||
echo "frontend-web/node_modules is missing or incomplete. Run 'pnpm install' in frontend-web first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${OUTPUT_DIR}"
|
||||
rm -f "${ARCHIVE}"
|
||||
|
||||
echo "Packaging frontend dependencies..."
|
||||
echo " Source: ${FRONTEND}"
|
||||
echo " Output: ${ARCHIVE}"
|
||||
|
||||
tar -czhf "${ARCHIVE}" -C "${FRONTEND}" node_modules package.json pnpm-lock.yaml
|
||||
|
||||
SIZE_MB=$(du -m "${ARCHIVE}" | awk '{print $1}')
|
||||
echo ""
|
||||
echo "Done — ${SIZE_MB} MB"
|
||||
echo ""
|
||||
echo "Copy to offline machine, then run:"
|
||||
echo " scripts/restore-frontend-offline-deps.sh <path-to-archive>"
|
||||
@@ -0,0 +1,4 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
& "$PSScriptRoot\stop-all.ps1"
|
||||
& "$PSScriptRoot\start-all.ps1"
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
"${SCRIPT_DIR}/stop-all.sh"
|
||||
"${SCRIPT_DIR}/start-all.sh"
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
"${SCRIPT_DIR}/stop-backend.sh"
|
||||
"${SCRIPT_DIR}/start-backend.sh"
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
"${SCRIPT_DIR}/stop-frontend.sh"
|
||||
"${SCRIPT_DIR}/start-frontend.sh"
|
||||
@@ -0,0 +1,42 @@
|
||||
# Restore frontend node_modules from an offline dependency archive.
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Archive
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Split-Path $PSScriptRoot -Parent
|
||||
$Frontend = Join-Path $Root "frontend-web"
|
||||
|
||||
if (-not (Test-Path $Archive)) {
|
||||
throw "Archive not found: $Archive"
|
||||
}
|
||||
|
||||
Write-Host "Restoring frontend dependencies to $Frontend ..."
|
||||
|
||||
# Back up existing node_modules if present
|
||||
$backup = Join-Path $Frontend "node_modules.bak"
|
||||
if (Test-Path (Join-Path $Frontend "node_modules")) {
|
||||
if (Test-Path $backup) { Remove-Item $backup -Recurse -Force }
|
||||
Rename-Item (Join-Path $Frontend "node_modules") "node_modules.bak"
|
||||
Write-Host " Existing node_modules backed up to node_modules.bak"
|
||||
}
|
||||
|
||||
tar -xzf $Archive -C $Frontend
|
||||
|
||||
# Quick sanity check
|
||||
$required = @(
|
||||
"node_modules\.pnpm",
|
||||
"node_modules\react\package.json",
|
||||
"node_modules\vite\package.json"
|
||||
)
|
||||
foreach ($rel in $required) {
|
||||
if (-not (Test-Path (Join-Path $Frontend $rel))) {
|
||||
throw "Restore incomplete — missing $rel"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Restore complete. You can now run:"
|
||||
Write-Host " cd frontend-web"
|
||||
Write-Host " pnpm dev"
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <path-to-frontend-offline-deps.tar.gz>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCHIVE="$1"
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
FRONTEND="${ROOT}/frontend-web"
|
||||
|
||||
if [[ ! -f "${ARCHIVE}" ]]; then
|
||||
echo "Archive not found: ${ARCHIVE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Restoring frontend dependencies to ${FRONTEND} ..."
|
||||
|
||||
if [[ -d "${FRONTEND}/node_modules" ]]; then
|
||||
rm -rf "${FRONTEND}/node_modules.bak"
|
||||
mv "${FRONTEND}/node_modules" "${FRONTEND}/node_modules.bak"
|
||||
echo " Existing node_modules backed up to node_modules.bak"
|
||||
fi
|
||||
|
||||
tar -xzf "${ARCHIVE}" -C "${FRONTEND}"
|
||||
|
||||
for rel in node_modules/.pnpm node_modules/react/package.json node_modules/vite/package.json; do
|
||||
if [[ ! -e "${FRONTEND}/${rel}" ]]; then
|
||||
echo "Restore incomplete — missing ${rel}" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Restore complete. You can now run:"
|
||||
echo " cd frontend-web"
|
||||
echo " pnpm dev"
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# Installs Docker Engine in an Ubuntu WSL distribution. Run as root.
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
echo "Run this script as root." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. /etc/os-release
|
||||
if [[ "${ID}" != "ubuntu" ]]; then
|
||||
echo "This installer supports Ubuntu only (detected: ${ID})." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl
|
||||
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
|
||||
cat > /etc/apt/sources.list.d/docker.sources <<EOF
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: ${VERSION_CODENAME}
|
||||
Components: stable
|
||||
Architectures: $(dpkg --print-architecture)
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
EOF
|
||||
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
||||
docker-ce \
|
||||
docker-ce-cli \
|
||||
containerd.io \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin
|
||||
|
||||
systemctl enable --now docker
|
||||
docker version --format 'Docker Engine {{.Server.Version}} is ready.'
|
||||
docker compose version
|
||||
@@ -0,0 +1,21 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
& "$PSScriptRoot\start-all.ps1"
|
||||
|
||||
$deadline = (Get-Date).AddSeconds(60)
|
||||
$url = "$FrontendPublicBaseUrl/"
|
||||
Write-Host "Waiting for frontend: $url"
|
||||
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
try {
|
||||
$response = Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 2
|
||||
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 500) {
|
||||
Write-Host "Frontend is ready: $url"
|
||||
exit 0
|
||||
}
|
||||
} catch {
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
}
|
||||
|
||||
throw "Timed out waiting for frontend: $url"
|
||||
@@ -0,0 +1,4 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
& "$PSScriptRoot\start-backend.ps1"
|
||||
& "$PSScriptRoot\start-frontend.ps1"
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
"${SCRIPT_DIR}/start-backend.sh"
|
||||
"${SCRIPT_DIR}/start-frontend.sh"
|
||||
@@ -0,0 +1,42 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
$PidFile = Join-Path $PidDir "backend.pid"
|
||||
$LogFile = Join-Path $LogDir "backend.log"
|
||||
|
||||
if (Test-PidRunning $PidFile) {
|
||||
$existingPid = Get-Content -LiteralPath $PidFile | Select-Object -First 1
|
||||
Write-Host "Backend is already running (pid $existingPid)."
|
||||
Write-Host "URL: $BackendPublicBaseUrl"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $BackendPython)) {
|
||||
throw "Backend Python not found: $BackendPython. Run uv sync in offline-backend-20260512/backend first."
|
||||
}
|
||||
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $BackendVendorDir | Out-Null
|
||||
|
||||
Write-Host "Starting backend..."
|
||||
Write-Host "Log: $LogFile"
|
||||
|
||||
$RunnerFile = Join-Path $RuntimeDir "run-backend.ps1"
|
||||
$runner = @"
|
||||
`$ErrorActionPreference = "Continue"
|
||||
Set-Location -LiteralPath $(ConvertTo-PSLiteral $BackendDir)
|
||||
`$env:GATEWAY_CORS_ORIGINS = $(ConvertTo-PSLiteral $GatewayCorsOrigins)
|
||||
`$env:PYTHONPATH = $(ConvertTo-PSLiteral ".;$BackendVendorDir")
|
||||
if (-not `$env:WEKNORA_ADMIN_PASSWORD) { `$env:WEKNORA_ADMIN_PASSWORD = "1qaz@WSX" }
|
||||
& $(ConvertTo-PSLiteral $BackendPython) -m uvicorn app.gateway.app:app --host $(ConvertTo-PSLiteral $BackendHost) --port $(ConvertTo-PSLiteral $BackendPort) --reload --reload-dir 'app' --reload-dir 'packages' --reload-exclude $(ConvertTo-PSLiteral (Join-Path $BackendDir '.deer-flow')) --reload-exclude $(ConvertTo-PSLiteral $RuntimeDir) *> $(ConvertTo-PSLiteral $LogFile)
|
||||
"@
|
||||
Set-Content -LiteralPath $RunnerFile -Value $runner -Encoding UTF8
|
||||
|
||||
$proc = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"-File", $RunnerFile
|
||||
) -WindowStyle Hidden -PassThru
|
||||
|
||||
Set-Content -LiteralPath $PidFile -Value $proc.Id
|
||||
Write-Host "Backend started (pid $($proc.Id))."
|
||||
Write-Host "URL: $BackendPublicBaseUrl"
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh"
|
||||
|
||||
PID_FILE="${PID_DIR}/backend.pid"
|
||||
LOG_FILE="${LOG_DIR}/backend.log"
|
||||
BACKEND_VENDOR_DIR="${BACKEND_VENDOR_DIR:-${BACKEND_DIR}/.deer-flow/python-vendor}"
|
||||
BACKEND_WHEELHOUSE="${BACKEND_WHEELHOUSE:-${BACKEND_DIR}/wheelhouse}"
|
||||
BACKEND_INSTALL_DEPS="${BACKEND_INSTALL_DEPS:-1}"
|
||||
BACKEND_PIP_PACKAGES="${BACKEND_PIP_PACKAGES:-croniter==6.2.2 langgraph-checkpoint-postgres==3.0.5 psycopg==3.3.3 psycopg-binary==3.3.3 psycopg-pool==3.3.0 orjson==3.11.9 tzdata==2026.2}"
|
||||
|
||||
if is_running "${PID_FILE}"; then
|
||||
echo "Backend is already running (pid $(cat "${PID_FILE}"))."
|
||||
echo "URL: http://${HOST_IP}:${BACKEND_PORT}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f "${PID_FILE}"
|
||||
|
||||
echo "Starting backend..."
|
||||
echo "Log: ${LOG_FILE}"
|
||||
|
||||
mkdir -p "${BACKEND_VENDOR_DIR}"
|
||||
|
||||
if [[ "${BACKEND_INSTALL_DEPS}" != "0" ]]; then
|
||||
if ! (
|
||||
cd "${BACKEND_DIR}" && \
|
||||
PYTHONPATH=".:${BACKEND_VENDOR_DIR}${PYTHONPATH:+:${PYTHONPATH}}" \
|
||||
uv run --no-sync python -c "import croniter; import psycopg; import psycopg_pool; import langgraph.checkpoint.postgres; import langgraph.store.postgres"
|
||||
) >/dev/null 2>&1; then
|
||||
if [[ ! -d "${BACKEND_WHEELHOUSE}" ]]; then
|
||||
echo "ERROR: wheelhouse not found: ${BACKEND_WHEELHOUSE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Installing backend runtime deps into ${BACKEND_VENDOR_DIR}"
|
||||
(
|
||||
cd "${BACKEND_DIR}" && \
|
||||
uv pip install \
|
||||
--target "${BACKEND_VENDOR_DIR}" \
|
||||
--no-deps \
|
||||
--no-index \
|
||||
--find-links "${BACKEND_WHEELHOUSE}" \
|
||||
${BACKEND_PIP_PACKAGES}
|
||||
)
|
||||
fi
|
||||
fi
|
||||
|
||||
# nohup instead of setsid: setsid does not exist on Windows Git Bash.
|
||||
nohup bash -c '
|
||||
cd "$0" || exit 1
|
||||
exec env \
|
||||
GATEWAY_CORS_ORIGINS="$1" \
|
||||
PYTHONPATH=".:$4${PYTHONPATH:+:${PYTHONPATH}}" \
|
||||
uv run uvicorn app.gateway.app:app \
|
||||
--host "$2" \
|
||||
--port "$3" \
|
||||
--reload \
|
||||
--reload-dir "app" \
|
||||
--reload-dir "packages" \
|
||||
--reload-exclude "$0/.deer-flow" \
|
||||
--reload-exclude "$0/.runtime"
|
||||
' "${BACKEND_DIR}" "${GATEWAY_CORS_ORIGINS}" "${BACKEND_HOST}" "${BACKEND_PORT}" "${BACKEND_VENDOR_DIR}" \
|
||||
>"${LOG_FILE}" 2>&1 &
|
||||
|
||||
echo "$!" >"${PID_FILE}"
|
||||
echo "Backend started (pid $(cat "${PID_FILE}"))."
|
||||
echo "URL: http://${HOST_IP}:${BACKEND_PORT}"
|
||||
@@ -0,0 +1,41 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
$PidFile = Join-Path $PidDir "frontend.pid"
|
||||
$LogFile = Join-Path $LogDir "frontend.log"
|
||||
|
||||
if (Test-PidRunning $PidFile) {
|
||||
$existingPid = Get-Content -LiteralPath $PidFile | Select-Object -First 1
|
||||
Write-Host "Frontend is already running (pid $existingPid)."
|
||||
Write-Host "URL: $FrontendPublicBaseUrl"
|
||||
exit 0
|
||||
}
|
||||
|
||||
$NpmCmd = (Get-Command npm.cmd -ErrorAction SilentlyContinue).Source
|
||||
if (-not $NpmCmd) {
|
||||
throw "npm.cmd was not found in PATH. Install Node.js or add npm.cmd to PATH."
|
||||
}
|
||||
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "Starting frontend..."
|
||||
Write-Host "Log: $LogFile"
|
||||
|
||||
$RunnerFile = Join-Path $RuntimeDir "run-frontend.ps1"
|
||||
$runner = @"
|
||||
`$ErrorActionPreference = "Continue"
|
||||
Set-Location -LiteralPath $(ConvertTo-PSLiteral $FrontendDir)
|
||||
`$env:VITE_BACKEND_BASE_URL = $(ConvertTo-PSLiteral $BackendPublicBaseUrl)
|
||||
`$env:VITE_LANGGRAPH_BASE_URL = $(ConvertTo-PSLiteral "$BackendPublicBaseUrl/api")
|
||||
& $(ConvertTo-PSLiteral $NpmCmd) run dev -- --host $(ConvertTo-PSLiteral $FrontendHost) --port $(ConvertTo-PSLiteral $FrontendPort) *> $(ConvertTo-PSLiteral $LogFile)
|
||||
"@
|
||||
Set-Content -LiteralPath $RunnerFile -Value $runner -Encoding UTF8
|
||||
|
||||
$proc = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"-File", $RunnerFile
|
||||
) -WindowStyle Hidden -PassThru
|
||||
|
||||
Set-Content -LiteralPath $PidFile -Value $proc.Id
|
||||
Write-Host "Frontend started (pid $($proc.Id))."
|
||||
Write-Host "URL: $FrontendPublicBaseUrl"
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh"
|
||||
|
||||
PID_FILE="${PID_DIR}/frontend.pid"
|
||||
LOG_FILE="${LOG_DIR}/frontend.log"
|
||||
|
||||
if is_running "${PID_FILE}"; then
|
||||
echo "Frontend is already running (pid $(cat "${PID_FILE}"))."
|
||||
echo "URL: ${FRONTEND_PUBLIC_BASE_URL}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f "${PID_FILE}"
|
||||
|
||||
echo "Starting frontend..."
|
||||
echo "Log: ${LOG_FILE}"
|
||||
|
||||
# nohup instead of setsid: setsid does not exist on Windows Git Bash.
|
||||
nohup bash -c '
|
||||
cd "$0" || exit 1
|
||||
exec env \
|
||||
VITE_BACKEND_BASE_URL="$1" \
|
||||
VITE_LANGGRAPH_BASE_URL="$1/api" \
|
||||
pnpm exec vite \
|
||||
--host "$2" \
|
||||
--port "$3"
|
||||
' "${FRONTEND_DIR}" "${BACKEND_PUBLIC_BASE_URL}" "${FRONTEND_HOST}" "${FRONTEND_PORT}" \
|
||||
>"${LOG_FILE}" 2>&1 &
|
||||
|
||||
echo "$!" >"${PID_FILE}"
|
||||
echo "Frontend started (pid $(cat "${PID_FILE}"))."
|
||||
echo "URL: ${FRONTEND_PUBLIC_BASE_URL}"
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
IMAGE_TAG="${IMAGE_TAG:-deerflow-backend-offline:20260505}"
|
||||
CONTAINER_NAME="${CONTAINER_NAME:-deerflow-backend}"
|
||||
HOST_PORT="${HOST_PORT:-2026}"
|
||||
IMAGE_TAR="${IMAGE_TAR:-${SCRIPT_DIR}/deerflow-backend-offline-image-20260505.tar}"
|
||||
# Default timezone for the container. The offline image is built from a base
|
||||
# layer that ships with UTC, which made scheduled tasks fire at the wrong wall
|
||||
# clock and made log timestamps confusing for ops. ``Asia/Shanghai`` keeps the
|
||||
# scheduler aligned with the operator's expectation; override with TZ=... when
|
||||
# deploying to a different region.
|
||||
CONTAINER_TZ="${CONTAINER_TZ:-${TZ:-Asia/Shanghai}}"
|
||||
|
||||
die() {
|
||||
echo "ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "command not found: $1"
|
||||
}
|
||||
|
||||
require_file() {
|
||||
[ -f "$1" ] || die "required file not found: $1"
|
||||
}
|
||||
|
||||
require_dir() {
|
||||
[ -d "$1" ] || die "required directory not found: $1"
|
||||
}
|
||||
|
||||
require_env_key() {
|
||||
local key="$1"
|
||||
grep -Eq "^[[:space:]]*${key}=" "${SCRIPT_DIR}/.env" || die "required .env key not found: ${key}"
|
||||
}
|
||||
|
||||
require_cmd docker
|
||||
|
||||
if [ ! -f "${SCRIPT_DIR}/.env" ]; then
|
||||
if [ -f "${SCRIPT_DIR}/.env.example" ]; then
|
||||
cp "${SCRIPT_DIR}/.env.example" "${SCRIPT_DIR}/.env"
|
||||
echo "Generated .env from .env.example. Please edit .env and run this script again."
|
||||
exit 1
|
||||
fi
|
||||
die "missing .env"
|
||||
fi
|
||||
|
||||
if [ ! -f "${SCRIPT_DIR}/config.yaml" ]; then
|
||||
if [ -f "${SCRIPT_DIR}/config.yaml.example" ]; then
|
||||
cp "${SCRIPT_DIR}/config.yaml.example" "${SCRIPT_DIR}/config.yaml"
|
||||
echo "Generated config.yaml from config.yaml.example. Please edit model/API settings and run this script again."
|
||||
exit 1
|
||||
fi
|
||||
die "missing config.yaml"
|
||||
fi
|
||||
|
||||
require_env_key "AUTH_JWT_SECRET"
|
||||
require_env_key "SCHEDULED_TASKS_ENABLED"
|
||||
require_env_key "ELEMENT_ENABLED"
|
||||
require_file "${SCRIPT_DIR}/config.yaml"
|
||||
require_file "${SCRIPT_DIR}/extensions_config.json"
|
||||
require_file "${SCRIPT_DIR}/backend/pyproject.toml"
|
||||
require_file "${SCRIPT_DIR}/backend/app/gateway/app.py"
|
||||
require_file "${SCRIPT_DIR}/backend/packages/harness/deerflow/runtime/scheduler/element.py"
|
||||
require_dir "${SCRIPT_DIR}/skills"
|
||||
require_dir "${SCRIPT_DIR}/wheelhouse"
|
||||
# Knowledge base directory, mounted into the container at /mnt/knowledge_base.
|
||||
require_dir "${SCRIPT_DIR}/backend/knowledge/knowledge_base"
|
||||
mkdir -p "${SCRIPT_DIR}/data"
|
||||
|
||||
if ! docker image inspect "${IMAGE_TAG}" >/dev/null 2>&1; then
|
||||
require_file "${IMAGE_TAR}"
|
||||
echo "Loading Docker image from ${IMAGE_TAR}"
|
||||
docker load -i "${IMAGE_TAR}"
|
||||
fi
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | awk -v name="${CONTAINER_NAME}" '$0 == name { found=1 } END { exit(found ? 0 : 1) }'; then
|
||||
echo "Removing existing container ${CONTAINER_NAME}"
|
||||
docker rm -f "${CONTAINER_NAME}" >/dev/null
|
||||
fi
|
||||
|
||||
echo "Starting backend container ${CONTAINER_NAME}"
|
||||
docker run -d \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
--restart unless-stopped \
|
||||
-p "${HOST_PORT}:8001" \
|
||||
--env-file "${SCRIPT_DIR}/.env" \
|
||||
-e TZ="${CONTAINER_TZ}" \
|
||||
-e DEER_FLOW_PROJECT_ROOT=/app \
|
||||
-e DEER_FLOW_HOME=/app/backend/.deer-flow \
|
||||
-e DEER_FLOW_CONFIG_PATH=/app/config.yaml \
|
||||
-e DEER_FLOW_EXTENSIONS_CONFIG_PATH=/app/extensions_config.json \
|
||||
-e DEER_FLOW_SKILLS_PATH=/app/skills \
|
||||
-e UV_LINK_MODE=copy \
|
||||
-v "${SCRIPT_DIR}/backend/app:/app/backend/app" \
|
||||
-v "${SCRIPT_DIR}/backend/packages:/app/backend/packages" \
|
||||
-v "${SCRIPT_DIR}/backend/scripts:/app/backend/scripts" \
|
||||
-v "${SCRIPT_DIR}/backend/pyproject.toml:/app/backend/pyproject.toml:ro" \
|
||||
-v "${SCRIPT_DIR}/backend/uv.lock:/app/backend/uv.lock:ro" \
|
||||
-v "${SCRIPT_DIR}/backend/langgraph.json:/app/backend/langgraph.json:ro" \
|
||||
-v "${SCRIPT_DIR}/config.yaml:/app/config.yaml:ro" \
|
||||
-v "${SCRIPT_DIR}/skill_evolution.json:/app/skill_evolution.json:rw" \
|
||||
-v "${SCRIPT_DIR}/extensions_config.json:/app/extensions_config.json:rw" \
|
||||
-v "${SCRIPT_DIR}/skills:/app/skills:rw" \
|
||||
-v "${SCRIPT_DIR}/wheelhouse:/app/wheelhouse:ro" \
|
||||
-v "${SCRIPT_DIR}/backend/knowledge/knowledge_base:/mnt/knowledge_base:ro" \
|
||||
-v "${SCRIPT_DIR}/data:/app/backend/.deer-flow" \
|
||||
"${IMAGE_TAG}" \
|
||||
sh -c 'cd backend
|
||||
# Apply timezone inside the container. ``TZ`` alone is enough for Python /
|
||||
# uvicorn log timestamps, but linking /etc/localtime keeps C-level tools
|
||||
# (e.g. anything that reads /etc/localtime directly) on the same clock.
|
||||
if [ -n "${TZ:-}" ] && [ -f "/usr/share/zoneinfo/${TZ}" ]; then
|
||||
ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime 2>/dev/null || true
|
||||
echo "${TZ}" > /etc/timezone 2>/dev/null || true
|
||||
fi
|
||||
if [ "${SCHEDULER_INSTALL_DEPS:-1}" != "0" ]; then
|
||||
uv run --no-sync python -c "import croniter" >/dev/null 2>&1 || {
|
||||
PYTHON_BIN="$(uv run --no-sync python -c "import sys; print(sys.executable)")"
|
||||
uv pip install --python "${PYTHON_BIN}" --no-index --find-links /app/wheelhouse ${SCHEDULER_PIP_PACKAGES:-croniter==6.2.2}
|
||||
}
|
||||
fi
|
||||
if [ "${HINDSIGHT_INSTALL_DEPS:-1}" != "0" ]; then
|
||||
uv run --no-sync python -c "import hindsight_client" >/dev/null 2>&1 || {
|
||||
PYTHON_BIN="$(uv run --no-sync python -c "import sys; print(sys.executable)")"
|
||||
uv pip install --python "${PYTHON_BIN}" --no-index --find-links /app/wheelhouse ${HINDSIGHT_INSTALL_DEPS:-hindsight_client==0.6.2}
|
||||
}
|
||||
fi
|
||||
if [ "${PG_CHECKPOINTER_INSTALL_DEPS:-1}" != "0" ]; then
|
||||
uv run --no-sync python -c "import psycopg; import psycopg_pool; import langgraph.checkpoint.postgres; import langgraph.store.postgres" >/dev/null 2>&1 || {
|
||||
PYTHON_BIN="$(uv run --no-sync python -c "import sys; print(sys.executable)")"
|
||||
uv pip install --python "${PYTHON_BIN}" --no-deps --no-index --find-links /app/wheelhouse ${PG_CHECKPOINTER_PIP_PACKAGES:-langgraph-checkpoint-postgres==3.0.5 psycopg==3.3.3 psycopg-binary==3.3.3 psycopg-pool==3.3.0 orjson==3.11.9 tzdata==2026.2}
|
||||
}
|
||||
fi
|
||||
PYTHONPATH=. uv run --no-sync python -m uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001 --workers ${GATEWAY_WORKERS:-8}'
|
||||
|
||||
echo
|
||||
echo "Backend started."
|
||||
echo " URL: http://<server-ip>:${HOST_PORT}"
|
||||
echo " Logs: docker logs -f ${CONTAINER_NAME}"
|
||||
echo " Stop: ./stop_backend.sh"
|
||||
@@ -0,0 +1,18 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
$backendPidFile = Join-Path $PidDir "backend.pid"
|
||||
$frontendPidFile = Join-Path $PidDir "frontend.pid"
|
||||
|
||||
if (Test-PidRunning $backendPidFile) {
|
||||
$pidValue = Get-Content -LiteralPath $backendPidFile | Select-Object -First 1
|
||||
Write-Host "Backend: running (pid $pidValue) $BackendPublicBaseUrl"
|
||||
} else {
|
||||
Write-Host "Backend: stopped"
|
||||
}
|
||||
|
||||
if (Test-PidRunning $frontendPidFile) {
|
||||
$pidValue = Get-Content -LiteralPath $frontendPidFile | Select-Object -First 1
|
||||
Write-Host "Frontend: running (pid $pidValue) $FrontendPublicBaseUrl"
|
||||
} else {
|
||||
Write-Host "Frontend: stopped"
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh"
|
||||
|
||||
print_status() {
|
||||
local name="$1"
|
||||
local pid_file="$2"
|
||||
local url="$3"
|
||||
local pattern="$4"
|
||||
|
||||
if is_running "${pid_file}"; then
|
||||
echo "${name}: running (pid $(cat "${pid_file}"))"
|
||||
echo " ${url}"
|
||||
elif command -v pgrep >/dev/null 2>&1 && pgrep -f "${pattern}" >/dev/null 2>&1; then
|
||||
echo "${name}: running (unmanaged by scripts)"
|
||||
echo " ${url}"
|
||||
else
|
||||
echo "${name}: stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
print_status "Backend" "${PID_DIR}/backend.pid" "http://${HOST_IP}:${BACKEND_PORT}" "${BACKEND_DIR}.*uvicorn app.gateway.app:app.*--port ${BACKEND_PORT}"
|
||||
print_status "Frontend" "${PID_DIR}/frontend.pid" "${FRONTEND_PUBLIC_BASE_URL}" "${FRONTEND_DIR}.*vite.*--port ${FRONTEND_PORT}"
|
||||
echo "Logs: ${LOG_DIR}"
|
||||
@@ -0,0 +1,4 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
& "$PSScriptRoot\stop-frontend.ps1"
|
||||
& "$PSScriptRoot\stop-backend.ps1"
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
"${SCRIPT_DIR}/stop-frontend.sh"
|
||||
"${SCRIPT_DIR}/stop-backend.sh"
|
||||
@@ -0,0 +1,20 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
$PidFile = Join-Path $PidDir "backend.pid"
|
||||
if (-not (Test-Path -LiteralPath $PidFile)) {
|
||||
Write-Host "Backend is not running (no pid file)."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$rawPid = Get-Content -LiteralPath $PidFile | Select-Object -First 1
|
||||
$processId = 0
|
||||
if (-not [int]::TryParse([string]$rawPid, [ref]$processId) -or -not (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Backend is not running (stale pid file removed)."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Stopping backend (pid $processId)..."
|
||||
Stop-ProcessTree -ProcessId $processId
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Backend stopped."
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh"
|
||||
|
||||
stop_by_pid_file "Backend" "${PID_DIR}/backend.pid"
|
||||
stop_by_pattern "Backend" "${BACKEND_DIR}.*uvicorn app.gateway.app:app.*--port ${BACKEND_PORT}"
|
||||
@@ -0,0 +1,20 @@
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
$PidFile = Join-Path $PidDir "frontend.pid"
|
||||
if (-not (Test-Path -LiteralPath $PidFile)) {
|
||||
Write-Host "Frontend is not running (no pid file)."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$rawPid = Get-Content -LiteralPath $PidFile | Select-Object -First 1
|
||||
$processId = 0
|
||||
if (-not [int]::TryParse([string]$rawPid, [ref]$processId) -or -not (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Frontend is not running (stale pid file removed)."
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "Stopping frontend (pid $processId)..."
|
||||
Stop-ProcessTree -ProcessId $processId
|
||||
Remove-Item -LiteralPath $PidFile -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "Frontend stopped."
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh"
|
||||
|
||||
stop_by_pid_file "Frontend" "${PID_DIR}/frontend.pid"
|
||||
stop_by_pattern "Frontend" "${FRONTEND_DIR}.*vite.*--port ${FRONTEND_PORT}"
|
||||
@@ -0,0 +1,54 @@
|
||||
param(
|
||||
[int]$TimeoutSeconds = 90,
|
||||
[switch]$OpenBrowser
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\env.ps1"
|
||||
|
||||
function Wait-HttpReady {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Name,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Url,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[datetime]$Deadline
|
||||
)
|
||||
|
||||
Write-Host "Waiting for ${Name}: $Url"
|
||||
while ((Get-Date) -lt $Deadline) {
|
||||
try {
|
||||
$response = Invoke-WebRequest -UseBasicParsing -Uri $Url -TimeoutSec 2
|
||||
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 500) {
|
||||
Write-Host "$Name is ready: $Url"
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
Start-Sleep -Milliseconds 700
|
||||
}
|
||||
}
|
||||
|
||||
throw "Timed out waiting for ${Name}: $Url"
|
||||
}
|
||||
|
||||
& "$PSScriptRoot\start-all.ps1"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
||||
Wait-HttpReady -Name "backend" -Url "$BackendPublicBaseUrl/api/health" -Deadline $deadline
|
||||
Wait-HttpReady -Name "frontend" -Url "$FrontendPublicBaseUrl/" -Deadline $deadline
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "DeerFlow is ready."
|
||||
Write-Host "Frontend: $FrontendPublicBaseUrl/"
|
||||
Write-Host "Backend: $BackendPublicBaseUrl"
|
||||
Write-Host ""
|
||||
Write-Host "Logs:"
|
||||
Write-Host " Backend: $(Join-Path $LogDir 'backend.log')"
|
||||
Write-Host " Frontend: $(Join-Path $LogDir 'frontend.log')"
|
||||
|
||||
if ($OpenBrowser) {
|
||||
Start-Process "$FrontendPublicBaseUrl/"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user