Files
openclaw-control-plane/sync/sync-agent.ps1
wangzhendong b5acead1e1 Add polling sync communication layer
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 11:11:18 +08:00

135 lines
3.1 KiB
PowerShell

param(
[int]$IntervalSeconds = 30,
[switch]$Once
)
$ErrorActionPreference = "Stop"
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$StateDir = Join-Path $RepoRoot ".sync-state"
$ErrorFile = Join-Path $StateDir "sync-error-pc.md"
$AllowedPaths = @(
"AGENT_BOARD.md",
"README.md",
".cursor/rules",
"handoff",
"evidence",
"rollback",
"tasks",
"sync",
".gitignore"
)
function Ensure-StateDir {
if (-not (Test-Path $StateDir)) {
New-Item -ItemType Directory -Path $StateDir | Out-Null
}
}
function Write-SyncError {
param([string]$Message)
Ensure-StateDir
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss zzz"
@"
# PC Sync Error
- Time: $timestamp
- Repository: $RepoRoot
- Message: $Message
Manual action required. Do not continue automatic sync until the repository is clean.
"@ | Set-Content -Path $ErrorFile -Encoding UTF8
}
function Invoke-Git {
param([string[]]$GitArgs)
& git @GitArgs
if ($LASTEXITCODE -ne 0) {
throw "git $($GitArgs -join ' ') failed with exit code $LASTEXITCODE"
}
}
function Get-AllowedChanges {
$changes = & git -C $RepoRoot status --porcelain
if ($LASTEXITCODE -ne 0) {
throw "git status failed with exit code $LASTEXITCODE"
}
return $changes | Where-Object {
$line = $_
if ([string]::IsNullOrWhiteSpace($line)) {
return $false
}
$path = $line.Substring(3).Trim()
foreach ($allowed in $AllowedPaths) {
if ($path -eq $allowed -or $path.StartsWith("$allowed/") -or $path.StartsWith("$allowed\")) {
return $true
}
}
return $false
}
}
function Test-ConflictMarkers {
$conflicts = & git -C $RepoRoot diff --name-only --diff-filter=U
if ($LASTEXITCODE -ne 0) {
throw "git diff conflict check failed with exit code $LASTEXITCODE"
}
return -not [string]::IsNullOrWhiteSpace(($conflicts -join ""))
}
function Sync-Once {
Set-Location $RepoRoot
Ensure-StateDir
Invoke-Git @("pull", "--rebase", "--autostash")
if (Test-ConflictMarkers) {
throw "merge or rebase conflicts detected"
}
$allowedChanges = @(Get-AllowedChanges)
if ($allowedChanges.Count -eq 0) {
return
}
foreach ($path in $AllowedPaths) {
if (Test-Path (Join-Path $RepoRoot $path)) {
Invoke-Git @("add", "--", $path)
}
}
$staged = & git -C $RepoRoot diff --cached --name-only
if ($LASTEXITCODE -ne 0) {
throw "git diff --cached failed with exit code $LASTEXITCODE"
}
if ([string]::IsNullOrWhiteSpace(($staged -join ""))) {
return
}
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Invoke-Git @("commit", "-m", "Sync agent state from PC at $timestamp")
Invoke-Git @("push")
}
do {
try {
Sync-Once
if (Test-Path $ErrorFile) {
Remove-Item $ErrorFile -Force
}
}
catch {
Write-SyncError $_.Exception.Message
Write-Error $_
break
}
if ($Once) {
break
}
Start-Sleep -Seconds $IntervalSeconds
} while ($true)