初始化询价智能体新仓:同步本地工程并排除密钥与 .env。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# 将测试部署从 C:\ytd-test 迁移到 E:\wwwroot,并启动智能体 HTTP 8910。
|
||||
# 禁止:改动 C:\yutongda、现网 8080/8810/8813、现网指针。
|
||||
# 副作用:停测口 8910;复制到 E:\wwwroot;改 ai.conf root;重建 venv;起 agent。
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Src = "C:\ytd-test"
|
||||
$Dst = "E:\wwwroot"
|
||||
$Python = "C:\yutongda\tools\Python312\python.exe"
|
||||
$NginxConf = "C:\nginx-1.18.0\myconf\ai.conf"
|
||||
$Stamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
$ReleaseId = "scaffold-agent-20260912-152641"
|
||||
$AgentHome = Join-Path $Dst "releases\$ReleaseId\agent"
|
||||
|
||||
function Write-Step([string]$m) { Write-Output "=== $m ===" }
|
||||
|
||||
if (-not (Test-Path $Src)) { throw "missing source $Src" }
|
||||
if (-not (Test-Path $Dst)) { throw "missing destination $Dst" }
|
||||
if (-not (Test-Path $Python)) { throw "missing python $Python" }
|
||||
|
||||
# 目标非空则备份其下内容到旁路,避免覆盖未知文件
|
||||
$existing = @(Get-ChildItem $Dst -Force -ErrorAction SilentlyContinue)
|
||||
if ($existing.Count -gt 0) {
|
||||
$bak = "E:\wwwroot.bak-before-migrate-$Stamp"
|
||||
Write-Step "backup existing wwwroot -> $bak"
|
||||
New-Item -ItemType Directory -Force -Path $bak | Out-Null
|
||||
robocopy $Dst $bak /E /NFL /NDL /NJH /NJS /nc /ns /np | Out-Null
|
||||
}
|
||||
|
||||
Write-Step "stop listeners on 8910 (test agent only)"
|
||||
Get-NetTCPConnection -LocalPort 8910 -State Listen -ErrorAction SilentlyContinue |
|
||||
Select-Object -ExpandProperty OwningProcess -Unique |
|
||||
ForEach-Object {
|
||||
Write-Output "STOP_PID=$_"
|
||||
Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
# 停掉可能残留的 run-agent-http.cmd 外壳
|
||||
Get-CimInstance Win32_Process -Filter "Name='cmd.exe'" -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.CommandLine -and ($_.CommandLine -like '*run-agent-http*' -or $_.CommandLine -like '*ytd-test*agent*') } |
|
||||
ForEach-Object {
|
||||
Write-Output "STOP_CMD_PID=$($_.ProcessId)"
|
||||
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
Write-Step "robocopy $Src -> $Dst"
|
||||
$rc = (Start-Process -FilePath robocopy.exe -ArgumentList @($Src, $Dst, '/E', '/COPY:DAT', '/R:2', '/W:2', '/NFL', '/NDL', '/NJH', '/NJS', '/nc', '/ns', '/np') -Wait -PassThru).ExitCode
|
||||
# robocopy 0-7 成功
|
||||
if ($rc -ge 8) { throw "robocopy failed code=$rc" }
|
||||
Write-Output "ROBOCOPY_CODE=$rc"
|
||||
|
||||
if (-not (Test-Path (Join-Path $AgentHome "agent\http_app.py"))) {
|
||||
throw "agent http_app.py missing under $AgentHome"
|
||||
}
|
||||
|
||||
Write-Step "rewrite ops paths to E:\\wwwroot"
|
||||
$runCmd = @"
|
||||
@echo off
|
||||
cd /d "$AgentHome"
|
||||
set YTD_ENV=test
|
||||
set AGENT_HTTP_PORT=8910
|
||||
:loop
|
||||
"$AgentHome\.venv\Scripts\python.exe" -m agent.http_app >> "$Dst\logs\agent-http.out.log" 2>> "$Dst\logs\agent-http.err.log"
|
||||
echo agent exited, restart in 3s >> "$Dst\logs\agent-http.err.log"
|
||||
timeout /t 3 /nobreak >nul
|
||||
goto loop
|
||||
"@
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $Dst "ops"), (Join-Path $Dst "logs") | Out-Null
|
||||
Set-Content -Path (Join-Path $Dst "ops\run-agent-http.cmd") -Value $runCmd -Encoding ASCII
|
||||
|
||||
$pointer = @{
|
||||
releaseId = $ReleaseId
|
||||
releaseRoot = (Join-Path $Dst "releases\$ReleaseId")
|
||||
agentHome = $AgentHome
|
||||
root = $Dst
|
||||
migratedFrom = $Src
|
||||
updatedAt = (Get-Date).ToString("o")
|
||||
pid = 0
|
||||
} | ConvertTo-Json
|
||||
Set-Content -Path (Join-Path $Dst "ops\active-release.json") -Value $pointer -Encoding UTF8
|
||||
|
||||
Write-Step "recreate venv at new path (avoid broken VIRTUAL_ENV)"
|
||||
$venvDir = Join-Path $AgentHome ".venv"
|
||||
if (Test-Path $venvDir) {
|
||||
Rename-Item $venvDir ".venv.bak-$Stamp"
|
||||
}
|
||||
& $Python -m venv $venvDir
|
||||
if ($LASTEXITCODE -ne 0) { throw "venv create failed" }
|
||||
$pip = Join-Path $venvDir "Scripts\pip.exe"
|
||||
$req = Join-Path $AgentHome "requirements.txt"
|
||||
& $pip install --default-timeout=180 -i https://pypi.tuna.tsinghua.edu.cn/simple -r $req
|
||||
if ($LASTEXITCODE -ne 0) { throw "pip install failed" }
|
||||
|
||||
# 保证 .env 在 agent 工作目录
|
||||
$rootEnv = Join-Path $Dst ".env"
|
||||
$agentEnv = Join-Path $AgentHome ".env"
|
||||
if ((Test-Path $rootEnv) -and -not (Test-Path $agentEnv)) {
|
||||
Copy-Item $rootEnv $agentEnv -Force
|
||||
}
|
||||
if (Test-Path $rootEnv) {
|
||||
Copy-Item $rootEnv (Join-Path $Dst "releases\$ReleaseId\.env") -Force
|
||||
}
|
||||
|
||||
Write-Step "backup+patch nginx root"
|
||||
Copy-Item $NginxConf "$NginxConf.bak-before-wwwroot-$Stamp" -Force
|
||||
$confText = Get-Content $NginxConf -Raw -Encoding UTF8
|
||||
$confText2 = $confText -replace 'root\s+C:/ytd-test/admin/dist;', 'root E:/wwwroot/admin/dist;'
|
||||
$confText2 = $confText2 -replace 'root\s+C:\\ytd-test\\admin\\dist;', 'root E:/wwwroot/admin/dist;'
|
||||
if ($confText2 -notmatch 'root E:/wwwroot/admin/dist;') {
|
||||
throw "failed to patch nginx root; current conf may use unexpected path"
|
||||
}
|
||||
Set-Content -Path $NginxConf -Value $confText2 -Encoding UTF8
|
||||
Select-String -Path $NginxConf -Pattern '^\s*root ' | ForEach-Object { $_.Line.Trim() }
|
||||
|
||||
Write-Step "restart Nginx1.18"
|
||||
try {
|
||||
Restart-Service Nginx1.18 -Force -ErrorAction Stop
|
||||
Write-Output "NGINX_RESTARTED"
|
||||
} catch {
|
||||
Write-Output "NGINX_SERVICE_FAIL=$_"
|
||||
if (Test-Path 'C:\yutongda\bounce_nginx.ps1') {
|
||||
& 'C:\yutongda\bounce_nginx.ps1'
|
||||
Write-Output "NGINX_BOUNCE"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Step "start agent from E:\\wwwroot"
|
||||
# 用 WMI 脱离子进程,避免 SSH 会话结束被杀
|
||||
$cmdPath = Join-Path $Dst "ops\run-agent-http.cmd"
|
||||
$wmi = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{
|
||||
CommandLine = "cmd.exe /c `"$cmdPath`""
|
||||
}
|
||||
Write-Output "WMI_Return=$($wmi.ReturnValue) ProcessId=$($wmi.ProcessId)"
|
||||
Start-Sleep -Seconds 6
|
||||
|
||||
$healthOk = $false
|
||||
try {
|
||||
$h = Invoke-WebRequest -Uri "http://127.0.0.1:8910/health" -UseBasicParsing -TimeoutSec 8
|
||||
Write-Output "HEALTH=$($h.StatusCode) $($h.Content)"
|
||||
$healthOk = ($h.StatusCode -eq 200)
|
||||
} catch {
|
||||
Write-Output "HEALTH_FAIL=$_"
|
||||
if (Test-Path (Join-Path $Dst "logs\agent-http.err.log")) {
|
||||
Write-Output "---- err.log tail ----"
|
||||
Get-Content (Join-Path $Dst "logs\agent-http.err.log") -Tail 40
|
||||
}
|
||||
}
|
||||
|
||||
$listen = Get-NetTCPConnection -LocalPort 8910 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($listen) {
|
||||
$pointerObj = Get-Content (Join-Path $Dst "ops\active-release.json") -Raw | ConvertFrom-Json
|
||||
$pointerObj.pid = $listen.OwningProcess
|
||||
$pointerObj | ConvertTo-Json | Set-Content (Join-Path $Dst "ops\active-release.json") -Encoding UTF8
|
||||
Write-Output "LISTEN_PID=$($listen.OwningProcess)"
|
||||
}
|
||||
|
||||
Write-Step "retire old C:\\ytd-test pointer (rename, keep files)"
|
||||
if ($healthOk) {
|
||||
$retire = "C:\ytd-test.migrated-to-E-wwwroot-$Stamp"
|
||||
if (Test-Path $Src) {
|
||||
Rename-Item -Path $Src -NewName (Split-Path $retire -Leaf)
|
||||
Write-Output "OLD_RENAMED=$retire"
|
||||
}
|
||||
} else {
|
||||
Write-Output "KEEP_OLD_SRC because health failed"
|
||||
}
|
||||
|
||||
Write-Step "smoke local https"
|
||||
cmd /c "curl.exe -sk -H `"Host: ai.ytd-scm.com`" https://127.0.0.1/agent/health"
|
||||
Write-Output ""
|
||||
cmd /c "curl.exe -sk -o NUL -w root:%{http_code} -H `"Host: ai.ytd-scm.com`" https://127.0.0.1/"
|
||||
Write-Output ""
|
||||
Write-Output "MIGRATE_DONE healthOk=$healthOk"
|
||||
Reference in New Issue
Block a user