feat: Refactor service management scripts to use a unified dev script

- Added package.json to manage development scripts.
- Updated restart-services.ps1 to call the new dev script for starting services.
- Refactored start-admin.ps1, start-backend.ps1, start-frontend.ps1, and start-mcp.ps1 to utilize the dev script for starting respective services.
- Enhanced stop-services.ps1 to improve process termination logic by matching command patterns.
This commit is contained in:
2026-03-29 21:36:13 +08:00
parent 84f82c2a7e
commit 92a85eef20
137 changed files with 14181 additions and 2691 deletions

246
dev.ps1
View File

@@ -1,73 +1,231 @@
param(
[ValidateSet("frontend", "backend", "admin", "mcp")]
[string]$Only,
[switch]$Spawn,
[switch]$WithMcp,
[switch]$Install,
[string]$DatabaseUrl = "postgres://postgres:postgres%402025%21@10.0.0.2:5432/termi-api_development",
[string]$McpApiKey = "termi-mcp-local-dev-key",
[string]$McpBackendApiBase = "http://127.0.0.1:5150/api",
[int]$McpPort = 5151,
[switch]$FrontendOnly,
[switch]$BackendOnly,
[switch]$AdminOnly,
[switch]$McpOnly,
[switch]$WithMcp,
[string]$DatabaseUrl = "postgres://postgres:postgres%402025%21@10.0.0.2:5432/termi-api_development"
[switch]$McpOnly
)
$ErrorActionPreference = "Stop"
$repoRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$frontendScript = Join-Path $repoRoot "start-frontend.ps1"
$backendScript = Join-Path $repoRoot "start-backend.ps1"
$adminScript = Join-Path $repoRoot "start-admin.ps1"
$mcpScript = Join-Path $repoRoot "start-mcp.ps1"
$devScriptPath = $MyInvocation.MyCommand.Path
$serviceOrder = @("frontend", "admin", "backend")
if (@($FrontendOnly, $BackendOnly, $AdminOnly, $McpOnly).Where({ $_ }).Count -gt 1) {
throw "Use only one of -FrontendOnly, -BackendOnly, -AdminOnly, or -McpOnly."
function Resolve-TargetService {
if ($Only) {
return $Only
}
$legacyTargets = @(
@{ Enabled = $FrontendOnly; Name = "frontend" }
@{ Enabled = $BackendOnly; Name = "backend" }
@{ Enabled = $AdminOnly; Name = "admin" }
@{ Enabled = $McpOnly; Name = "mcp" }
) | Where-Object { $_.Enabled }
if ($legacyTargets.Count -gt 1) {
throw "Use only one of -Only, -FrontendOnly, -BackendOnly, -AdminOnly, or -McpOnly."
}
if ($legacyTargets.Count -eq 1) {
return $legacyTargets[0].Name
}
return $null
}
if ($FrontendOnly) {
& $frontendScript
exit $LASTEXITCODE
function Invoke-RepoCommand {
param(
[string]$Name,
[string]$WorkingDirectory,
[scriptblock]$Run,
[switch]$UsesNode
)
if (-not (Test-Path $WorkingDirectory)) {
throw "$Name directory not found: $WorkingDirectory"
}
Push-Location $WorkingDirectory
try {
if ($UsesNode -and ($Install -or -not (Test-Path (Join-Path $WorkingDirectory "node_modules")))) {
Write-Host "[$Name] Installing dependencies..." -ForegroundColor Cyan
npm install
if ($LASTEXITCODE -ne 0) {
throw "npm install failed for $Name"
}
}
& $Run
if ($LASTEXITCODE -ne 0) {
throw "$Name failed to start"
}
}
finally {
Pop-Location
}
}
if ($BackendOnly) {
& $backendScript -DatabaseUrl $DatabaseUrl
exit $LASTEXITCODE
function Start-Frontend {
Invoke-RepoCommand `
-Name "frontend" `
-WorkingDirectory (Join-Path $repoRoot "frontend") `
-UsesNode `
-Run {
Write-Host "[frontend] Starting Astro dev server..." -ForegroundColor Green
npm run dev
}
}
if ($AdminOnly) {
& $adminScript
exit $LASTEXITCODE
function Start-Admin {
Invoke-RepoCommand `
-Name "admin" `
-WorkingDirectory (Join-Path $repoRoot "admin") `
-UsesNode `
-Run {
Write-Host "[admin] Starting Vite admin workspace..." -ForegroundColor Green
npm run dev
}
}
if ($McpOnly) {
& $mcpScript
exit $LASTEXITCODE
function Start-Backend {
Invoke-RepoCommand `
-Name "backend" `
-WorkingDirectory (Join-Path $repoRoot "backend") `
-Run {
$env:DATABASE_URL = $DatabaseUrl
Write-Host "[backend] DATABASE_URL set to $DatabaseUrl" -ForegroundColor Cyan
Write-Host "[backend] Starting Loco.rs server..." -ForegroundColor Green
cargo loco start 2>&1
}
}
$services = if ($WithMcp) { "frontend, admin, backend, and MCP" } else { "frontend, admin, and backend" }
Write-Host "[monorepo] Starting $services in separate PowerShell windows..." -ForegroundColor Cyan
function Start-Mcp {
Invoke-RepoCommand `
-Name "mcp" `
-WorkingDirectory (Join-Path $repoRoot "mcp-server") `
-UsesNode `
-Run {
$env:TERMI_MCP_API_KEY = $McpApiKey
$env:TERMI_BACKEND_API_BASE = $McpBackendApiBase
$env:TERMI_MCP_PORT = "$McpPort"
Start-Process powershell -ArgumentList @(
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-File", $frontendScript
)
Write-Host "[mcp] Backend API base set to $McpBackendApiBase" -ForegroundColor Cyan
Write-Host "[mcp] Starting MCP server on port $McpPort..." -ForegroundColor Green
npm run start
}
}
Start-Process powershell -ArgumentList @(
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-File", $backendScript,
"-DatabaseUrl", $DatabaseUrl
)
function Invoke-Service {
param([string]$Name)
Start-Process powershell -ArgumentList @(
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-File", $adminScript
)
switch ($Name) {
"frontend" { Start-Frontend; return }
"admin" { Start-Admin; return }
"backend" { Start-Backend; return }
"mcp" { Start-Mcp; return }
default { throw "Unsupported service: $Name" }
}
}
if ($WithMcp) {
Start-Process powershell -ArgumentList @(
function Get-ServiceLaunchArguments {
param([string]$Name)
$arguments = @(
"powershell",
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-File", $mcpScript
"-File", $devScriptPath,
"-Only", $Name
)
if ($Install -and $Name -ne "backend") {
$arguments += "-Install"
}
if ($Name -eq "backend") {
$arguments += @("-DatabaseUrl", $DatabaseUrl)
}
if ($Name -eq "mcp") {
$arguments += @(
"-McpApiKey", $McpApiKey,
"-McpBackendApiBase", $McpBackendApiBase,
"-McpPort", $McpPort
)
}
return $arguments
}
$servicesStarted = if ($WithMcp) { "Frontend, admin, backend, and MCP windows started." } else { "Frontend, admin, and backend windows started." }
Write-Host "[monorepo] $servicesStarted" -ForegroundColor Green
function Start-ServiceWindow {
param([string]$Name)
$arguments = Get-ServiceLaunchArguments -Name $Name
Start-Process powershell -ArgumentList $arguments[1..($arguments.Length - 1)]
}
function Start-ServiceHost {
param([string[]]$Services)
$wt = Get-Command wt.exe -ErrorAction SilentlyContinue
if (-not $wt) {
Write-Warning "[dev] Windows Terminal (wt.exe) not found. Falling back to separate PowerShell windows."
foreach ($service in $Services) {
Start-ServiceWindow $service
}
return
}
$wtArguments = @("-w", "0")
$isFirst = $true
foreach ($service in $Services) {
if (-not $isFirst) {
$wtArguments += ";"
}
$wtArguments += @(
"new-tab",
"--title", "termi:$service"
)
$wtArguments += Get-ServiceLaunchArguments -Name $service
$isFirst = $false
}
Start-Process -FilePath $wt.Source -ArgumentList $wtArguments
}
$targetService = Resolve-TargetService
if ($targetService -and -not $Spawn) {
Invoke-Service $targetService
exit $LASTEXITCODE
}
$servicesToStart = [System.Collections.Generic.List[string]]::new()
if ($targetService) {
[void]$servicesToStart.Add($targetService)
}
else {
$serviceOrder | ForEach-Object { [void]$servicesToStart.Add($_) }
if ($WithMcp) {
[void]$servicesToStart.Add("mcp")
}
}
$serviceLabel = ($servicesToStart -join ", ")
Write-Host "[dev] Starting $serviceLabel in one Windows Terminal window..." -ForegroundColor Cyan
Start-ServiceHost -Services $servicesToStart
Write-Host "[dev] Ready. Use .\\stop-services.ps1 to stop everything." -ForegroundColor Green