Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .agents/skills/ok-script-pr-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ description: 处理 ok-script-toolkit 主仓及 JetBrains 子仓的 PR 审阅意
`6` 仍需等待(`-Once` 不是超时)、`4` PR 关闭而停止等待、`11` head 变化且本轮数据丢弃、`2` 错误。
等待须在用户能从 Codex 侧边查看输出的终端会话后台运行,复用已有进程;不要默认隐藏
Start-Process,也不要为等待另建定时任务、heartbeat 或 automation,除非用户明确要求安排。
终端中的等待截止时间和下一次额度查询时间跟随电脑当前时区,显示完整日期、UTC 偏移与剩余时长;
等待已停止时也显示建议的查询时间。它不是审阅预计完成时间。JSON 的 ISO 时间格式保持不变。
本机账本默认在 `%LOCALAPPDATA%\ok-script-pr-review\coderabbit-triggers`,按仓库、PR 与 head 记录
触发,写入先于发送;`-StateDir` 可改位置。修改脚本后运行 `test-coderabbit-helpers.ps1` 与
`test-coderabbit-wait-mock.ps1`、`test-review-threads-mock.ps1`(Windows PowerShell 5.1 与 PowerShell 7 都应通过)。含非 ASCII
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ function Get-CrNow {
return [datetimeoffset]::UtcNow
}

# Human-readable times follow the computer's current timezone; protocol timestamps stay in UTC.
function Format-CrDisplayTime {
param([datetimeoffset]$Time, [TimeZoneInfo]$TimeZone = [TimeZoneInfo]::Local)
return [TimeZoneInfo]::ConvertTime($Time, $TimeZone).ToString('yyyy-MM-dd HH:mm:ss zzz', [Globalization.CultureInfo]::InvariantCulture)
}

function Wait-CrSeconds {
param([double]$Seconds)
if ($Seconds -le 0) { return }
Expand Down
12 changes: 12 additions & 0 deletions .agents/skills/ok-script-pr-review/test-coderabbit-helpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ function Assert-Equal {
if ($Actual -ne $Expected) { throw "$Message -> got '$Actual', expected '$Expected'" }
}

# ---- display timezone: follow the host, including date rollover and fractional offsets ----
$displayInstant = [datetimeoffset]'2026-10-08T18:04:05Z'
foreach ($case in @(
@{ Minutes = 0; Want = '2026-10-08 18:04:05 +00:00' },
@{ Minutes = 480; Want = '2026-10-09 02:04:05 +08:00' },
@{ Minutes = -300; Want = '2026-10-08 13:04:05 -05:00' },
@{ Minutes = 330; Want = '2026-10-08 23:34:05 +05:30' })) {
$zone = [TimeZoneInfo]::CreateCustomTimeZone("test-$($case.Minutes)", [TimeSpan]::FromMinutes($case.Minutes), 'test', 'test')
Assert-Equal (Format-CrDisplayTime $displayInstant $zone) $case.Want 'display uses the requested timezone'
}
Assert-Equal (Format-CrDisplayTime $displayInstant) ($displayInstant.ToLocalTime().ToString('yyyy-MM-dd HH:mm:ss zzz', [Globalization.CultureInfo]::InvariantCulture)) 'default display follows host timezone'

# ---- quota replies: a countdown is unavailable; only an explicit positive reply is available ----
$plan = '<!-- This is an auto-generated reply by CodeRabbit -->' + "`n" +
'Your [plan](https://docs.coderabbit.ai/management/plans#fair-usage-limits-policy) includes PR reviews subject to [rate limits](https://docs.coderabbit.ai/management/plans#rate-limits).'
Expand Down
24 changes: 22 additions & 2 deletions .agents/skills/ok-script-pr-review/test-coderabbit-wait-mock.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ function Invoke-Wait([hashtable]$Extra = @{}) {
function Invoke-Quota([hashtable]$Extra = @{}) {
$params = @{ Repo = $repo; PrNumber = $pr; ExpectedHead = $global:W.head; PollSeconds = 10; ReplyTimeoutSeconds = 60 }
foreach ($key in $Extra.Keys) { $params[$key] = $Extra[$key] }
$lines = @(& $quotaScript @params 6>$null)
return [pscustomobject]@{ exit = $LASTEXITCODE; result = ([string]$lines[-1] | ConvertFrom-Json) }
$lines = @(& $quotaScript @params 6>&1)
return [pscustomobject]@{ exit = $LASTEXITCODE; result = ([string]$lines[-1] | ConvertFrom-Json); log = ($lines | ForEach-Object { "$_" }) -join "`n" }
}
function Test-Case([string]$Name, [scriptblock]$Body) {
try { & $Body; $script:passed++; Write-Output "ok $Name" }
Expand All @@ -151,6 +151,26 @@ function Reply-OnProbe([string[]]$Replies) {
}
}

Test-Case 'quota wait displays local date, offset and time remaining' {
New-World
Reply-OnProbe @('More reviews will be available in 2 minutes.', 'Reviews are available now.')
$r = Invoke-Quota @{ MaxWaitSeconds = 300 }
$expected = $t0.AddSeconds(150).ToLocalTime().ToString('yyyy-MM-dd HH:mm:ss zzz', [Globalization.CultureInfo]::InvariantCulture)
Assert-True ($r.log.Contains("next query at $expected (local time; in 00:02:30)")) 'next query must use the local timezone with a countdown'
Assert-True ($r.log.Contains('review completion time is unknown')) 'do not present quota recheck as review completion'
Assert-True ($r.result.state -eq 'AVAILABLE' -and (Get-Now) -eq $t0.AddSeconds(150)) 'display formatting must not change retry scheduling'
}

Test-Case 'stopped quota wait still displays suggested local retry time' {
New-World
Reply-OnProbe @('More reviews will be available in 2 minutes.')
$r = Invoke-Quota @{ MaxWaitSeconds = 60 }
$expected = $t0.AddSeconds(150).ToLocalTime().ToString('yyyy-MM-dd HH:mm:ss zzz', [Globalization.CultureInfo]::InvariantCulture)
Assert-True ($r.log.Contains("suggested next query at $expected (local time; in 00:02:30); this wait has stopped")) 'stopped wait must give a readable retry time'
Assert-True ($r.result.nextCheckAt -eq $t0.AddSeconds(150).ToString('o')) 'JSON timestamp must keep its protocol format'
Assert-True ($r.result.state -eq 'UNAVAILABLE' -and (Get-Now) -eq $t0) 'stopped wait must not keep sleeping'
}

Test-Case 'covered head ends REVIEWED without any write' {
New-World
Add-Status $headA 'success' 'Review completed'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function Wait-WithSessionCheck {

try {
$deadline = (Get-CrNow).AddSeconds($MaxWaitSeconds)
Write-Host "[rate-limit] waiting deadline: $(Format-CrDisplayTime $deadline) (local time; maximum wait $MaxWaitSeconds seconds; not a review completion estimate)"
for ($probeCount = 1; $probeCount -le $MaxProbes; $probeCount++) {
$stop = Test-Session
if ($stop) { Complete-RateLimit $stop @{ actualHead = $script:ActualHead } }
Expand Down Expand Up @@ -90,8 +91,13 @@ try {
$delay = if ($null -ne $suggested) { $suggested + $RecheckBufferSeconds } else { $DefaultRecheckSeconds }
$nextCheck = (Get-CrNow).AddSeconds([Math]::Max(1, $delay))
$detail = @{ probeId = $probe.id; replyId = $reply.comment.id; reply = Get-CrPlainText $reply.comment.body; nextCheckAt = $nextCheck.ToString('o') }
if ($nextCheck -gt $deadline -or $probeCount -eq $MaxProbes) { Complete-RateLimit 'UNAVAILABLE' $detail }
Write-Host "[rate-limit] unavailable; next query at $($nextCheck.ToString('u')) (a countdown is not proof of quota)"
$remaining = [TimeSpan]::FromSeconds([Math]::Max(0, [Math]::Ceiling(($nextCheck - (Get-CrNow)).TotalSeconds)))
$nextQuery = "$(Format-CrDisplayTime $nextCheck) (local time; in $($remaining.ToString('c')))"
if ($nextCheck -gt $deadline -or $probeCount -eq $MaxProbes) {
Write-Host "[rate-limit] unavailable; suggested next query at $nextQuery; this wait has stopped (review completion time is unknown)"
Complete-RateLimit 'UNAVAILABLE' $detail
}
Write-Host "[rate-limit] unavailable; next query at $nextQuery (a countdown is not proof of quota; review completion time is unknown)"
$stop = Wait-WithSessionCheck $nextCheck
if ($stop) { Complete-RateLimit $stop @{ actualHead = $script:ActualHead } }
}
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/ok-script-pr-review/wait-coderabbit.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ try {
$arrival = $null
$unconfirmedSince = $null
$restart = $false
Write-Host "[wait] session for $Repo#$PrNumber head=$head"
Write-Host "[wait] session for $Repo#$PrNumber head=$head; waiting deadline: $(Format-CrDisplayTime $globalDeadline) (local time; maximum wait $TimeoutSeconds seconds; not a review completion estimate)"

while (-not $restart) {
if ((Get-CrNow) -ge $globalDeadline) { Complete-Wait 'TIMEOUT' $head -Extra @{ detail = 'overall timeout' } }
Expand Down
1 change: 1 addition & 0 deletions .agents/skills/ok-script-pr-review/wait-review-threads.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ try {
}
$started = Get-CrNow
$deadline = $started.AddSeconds($TimeoutSeconds)
if (-not $Once) { Write-Host "[threads] waiting deadline: $(Format-CrDisplayTime $deadline) (local time; maximum wait $TimeoutSeconds seconds; not a review completion estimate)" }
$pr = Get-CrPr $Repo $PrNumber
if (-not $ExpectedHead) { $ExpectedHead = $pr.head }
$polls = 0
Expand Down
Loading