启动网页服务时不再监视文件,并加上控制台脚本用来查询、启停和看日志。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+166
@@ -0,0 +1,166 @@
|
||||
# Start and stop the local writing-agent web server. File watch stays off.
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("query", "start", "stop", "restart", "status", "log")]
|
||||
[string]$Action
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
$Root = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Port = 23337
|
||||
$Log = Join-Path $env:USERPROFILE ".writing-agent\logs\runtime.log"
|
||||
|
||||
function Get-ListenerPid {
|
||||
$lines = netstat -ano -p tcp | Select-String ":$Port\s" | Select-String "LISTENING"
|
||||
foreach ($line in $lines) {
|
||||
if ("$line" -match '\sLISTENING\s+(\d+)\s*$') {
|
||||
return [int]$Matches[1]
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-ProcessById([int]$ProcessId) {
|
||||
Get-CimInstance Win32_Process -Filter "ProcessId=$ProcessId" -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
function Test-ServerCommand([string]$CommandLine) {
|
||||
if (-not $CommandLine) { return $false }
|
||||
if ($CommandLine -match 'Cursor|cursor-agent') { return $false }
|
||||
return $CommandLine -match 'src[\\/]+server[\\/]+web-server|web:watch|tsx(\.cmd)?\s+watch|npm(\.cmd)?\s+run\s+web'
|
||||
}
|
||||
|
||||
function Get-ChainText([int]$ProcessId) {
|
||||
$parts = New-Object System.Collections.Generic.List[string]
|
||||
$current = $ProcessId
|
||||
for ($i = 0; $i -lt 10; $i++) {
|
||||
$proc = Get-ProcessById $current
|
||||
if (-not $proc) { break }
|
||||
$cmd = [string]$proc.CommandLine
|
||||
$parts.Add($cmd)
|
||||
if ($cmd -match 'Cursor|cursor-agent') { break }
|
||||
$parent = [int]$proc.ParentProcessId
|
||||
if ($parent -le 0 -or $parent -eq $current) { break }
|
||||
$current = $parent
|
||||
}
|
||||
return ($parts -join "`n")
|
||||
}
|
||||
|
||||
function Get-ProtectedPids {
|
||||
$protected = New-Object 'System.Collections.Generic.HashSet[int]'
|
||||
$current = $PID
|
||||
for ($i = 0; $i -lt 8; $i++) {
|
||||
if ($current -le 0 -or -not $protected.Add($current)) { break }
|
||||
$proc = Get-ProcessById $current
|
||||
if (-not $proc) { break }
|
||||
$parent = [int]$proc.ParentProcessId
|
||||
if ($parent -le 0 -or $parent -eq $current) { break }
|
||||
$current = $parent
|
||||
}
|
||||
return $protected
|
||||
}
|
||||
|
||||
function Test-ForeignConsole([string]$CommandLine) {
|
||||
if (-not $CommandLine) { return $false }
|
||||
return $CommandLine -match 'tunnel\.ps1|ops-menu|srv\.bat|console\.bat'
|
||||
}
|
||||
|
||||
function Get-StopRoot([int]$ProcessId, $Protected) {
|
||||
$current = $ProcessId
|
||||
$root = $ProcessId
|
||||
$matched = $false
|
||||
for ($i = 0; $i -lt 10; $i++) {
|
||||
if ($Protected.Contains($current)) { break }
|
||||
$proc = Get-ProcessById $current
|
||||
if (-not $proc) { break }
|
||||
$cmd = [string]$proc.CommandLine
|
||||
if ($cmd -match 'Cursor|cursor-agent') { break }
|
||||
if (Test-ForeignConsole $cmd) { break }
|
||||
if (Test-ServerCommand $cmd) {
|
||||
$root = $current
|
||||
$matched = $true
|
||||
}
|
||||
$parent = [int]$proc.ParentProcessId
|
||||
if ($parent -le 0 -or $parent -eq $current) { break }
|
||||
$current = $parent
|
||||
}
|
||||
if (-not $matched) { return $null }
|
||||
if ($Protected.Contains($root)) { return $null }
|
||||
return $root
|
||||
}
|
||||
|
||||
function Stop-Server {
|
||||
$listener = Get-ListenerPid
|
||||
if (-not $listener) {
|
||||
Write-Output "down"
|
||||
return
|
||||
}
|
||||
$root = Get-StopRoot $listener (Get-ProtectedPids)
|
||||
if (-not $root) {
|
||||
throw "Port $Port is in use by another process (pid $listener)."
|
||||
}
|
||||
& taskkill.exe /F /T /PID $root | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "taskkill failed ($LASTEXITCODE)" }
|
||||
Start-Sleep -Seconds 1
|
||||
if (Get-ListenerPid) { throw "Port $Port is still in use." }
|
||||
Write-Output "stopped"
|
||||
}
|
||||
|
||||
function Get-Mode {
|
||||
$listener = Get-ListenerPid
|
||||
if (-not $listener) { return "down" }
|
||||
$chain = Get-ChainText $listener
|
||||
if ($chain -notmatch 'web-server|npm(\.cmd)?\s+run\s+web') { return "other" }
|
||||
if ($chain -match 'web:watch|tsx(\.cmd)?\s+watch') { return "watch" }
|
||||
return "web"
|
||||
}
|
||||
|
||||
function Start-Server {
|
||||
$mode = Get-Mode
|
||||
if ($mode -eq "other") {
|
||||
throw "Port $Port is in use by another process (pid $(Get-ListenerPid))."
|
||||
}
|
||||
if ($mode -eq "watch") { Stop-Server | Out-Null }
|
||||
if ($mode -eq "web") {
|
||||
Write-Output "already"
|
||||
return
|
||||
}
|
||||
$npm = "D:\tool\node\npm.cmd"
|
||||
$found = Get-Command npm.cmd -ErrorAction SilentlyContinue
|
||||
if ($found) { $npm = $found.Source }
|
||||
if (-not (Test-Path $npm)) { throw "npm.cmd not found" }
|
||||
Start-Process -FilePath "cmd.exe" -ArgumentList "/c", "`"$npm`" run web" -WorkingDirectory $Root -WindowStyle Hidden | Out-Null
|
||||
$deadline = (Get-Date).AddSeconds(40)
|
||||
do {
|
||||
Start-Sleep -Seconds 1
|
||||
$listener = Get-ListenerPid
|
||||
if ($listener) {
|
||||
$chain = Get-ChainText $listener
|
||||
if ($chain -notmatch 'ssh\.exe') {
|
||||
Write-Output "started"
|
||||
return
|
||||
}
|
||||
}
|
||||
} while ((Get-Date) -lt $deadline)
|
||||
throw "Server did not listen on $Port."
|
||||
}
|
||||
|
||||
switch ($Action) {
|
||||
"query" { Write-Output (Get-Mode) }
|
||||
"start" { Start-Server }
|
||||
"stop" { Stop-Server }
|
||||
"restart" {
|
||||
Stop-Server | Out-Null
|
||||
Start-Server
|
||||
}
|
||||
"status" {
|
||||
Write-Output ("mode=" + (Get-Mode))
|
||||
Push-Location $Root
|
||||
try { git status -sb } finally { Pop-Location }
|
||||
}
|
||||
"log" {
|
||||
if (-not (Test-Path $Log)) { Write-Output "no log: $Log"; break }
|
||||
Get-Content -Path $Log -Tail 40
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user