Skip to content
Open
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
4 changes: 2 additions & 2 deletions .antigravity-plugin/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
{
"type": "command",
"command": "scripts\\run-powershell.cmd hooks\\ensure-monk-agent.ps1",
"timeout": 10
"timeout": 20
},
{
"type": "command",
"command": "./hooks/ensure-monk-agent.sh",
"timeout": 10
"timeout": 20
}
]
},
Expand Down
3 changes: 2 additions & 1 deletion .antigravity-plugin/hooks/ensure-monk-agent.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ if ($Process) {
# the health endpoint never responds, report an attempted start with a pointer
# to the logs instead of a false "has been started".
if ($Process -and -not $Process.HasExited) {
for ($i = 0; $i -lt 10; $i++) {
$ReadyDeadline = [DateTime]::UtcNow.AddSeconds(10)
while ([DateTime]::UtcNow -lt $ReadyDeadline) {
Start-Sleep -Seconds 1
if ($Process.HasExited) { break }
if (Test-AgentRunning) {
Expand Down
5 changes: 2 additions & 3 deletions .antigravity-plugin/hooks/ensure-monk-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ printf '%s\n' "$agent_pid" >"$pid_file"
# Wait briefly for the agent to become reachable. If the process exits early or
# the health endpoint never responds, report an attempted start with a pointer
# to the logs instead of a false "has been started".
i=0
while [ "$i" -lt 10 ]; do
ready_deadline=$(( $(date +%s) + 10 ))
while [ "$(date +%s)" -lt "$ready_deadline" ]; do
sleep 1
if ! kill -0 "$agent_pid" 2>/dev/null; then
break
Expand All @@ -113,7 +113,6 @@ while [ "$i" -lt 10 ]; do
emit_inject_steps "monk-agent was not running and has been started. It may take a few seconds to initialize — use monk.install.status or monk.runtime.status to check readiness before issuing Monk operations."
exit 0
fi
i=$((i + 1))
done

emit_inject_steps "monk-agent was started but did not become ready within 10 seconds. Check monk.install.status or monk.runtime.status for details, or the launcher logs under $log_dir."
108 changes: 108 additions & 0 deletions tests/antigravity-ensure-hook-timeout-budget.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
$ErrorActionPreference = "Stop"

$Repo = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
$Root = Join-Path ([IO.Path]::GetTempPath()) ("monk-antigravity-timeout-" + [guid]::NewGuid().ToString("N"))
$AgentPath = Join-Path $Root "fake-agent.exe"
$AgentSource = Join-Path $Root "fake-agent.cs"
$EmptyInput = Join-Path $Root "stdin.txt"
$StdoutPath = Join-Path $Root "hook.stdout.json"
$StderrPath = Join-Path $Root "hook.stderr.log"
$MonkHome = Join-Path $Root "monk-home"
$PidFile = Join-Path $MonkHome "agent\launcher\run\monk-agent.pid"
$EnvironmentNames = @(
"MONK_AGENT_PATH",
"MONK_AGENT_HOME",
"MONK_AGENT_PORT",
"MONK_DISABLE_ANALYTICS"
)
$OriginalEnvironment = @{}

foreach ($Name in $EnvironmentNames) {
$OriginalEnvironment[$Name] = [Environment]::GetEnvironmentVariable($Name, "Process")
}

try {
New-Item -ItemType Directory -Force -Path $Root | Out-Null
New-Item -ItemType File -Force -Path $EmptyInput | Out-Null

@"
using System;
using System.Threading;
class Program { static void Main(string[] args) { Thread.Sleep(TimeSpan.FromSeconds(60)); } }
"@ | Set-Content $AgentSource

$Csc = Join-Path $env:WINDIR "Microsoft.NET\Framework64\v4.0.30319\csc.exe"
if (-not (Test-Path $Csc)) {
$Csc = Get-ChildItem "$env:WINDIR\Microsoft.NET\Framework64" -Filter csc.exe -Recurse |
Select-Object -First 1 -ExpandProperty FullName
}
if (-not $Csc) {
throw "csc.exe not found; cannot build the fake never-ready agent"
}

& $Csc /nologo /out:$AgentPath $AgentSource | Out-Null
if (-not (Test-Path $AgentPath)) {
throw "failed to compile fake-agent.exe"
}

$Hooks = Get-Content -Raw (Join-Path $Repo ".antigravity-plugin\hooks.json") | ConvertFrom-Json
$HostTimeoutSeconds = [int]$Hooks.'ensure-monk-agent'.PreInvocation[0].timeout
$HookPath = Join-Path $Repo ".antigravity-plugin\hooks\ensure-monk-agent.ps1"

$env:MONK_AGENT_PATH = $AgentPath
$env:MONK_AGENT_HOME = $MonkHome
$env:MONK_AGENT_PORT = "57420"
$env:MONK_DISABLE_ANALYTICS = "1"

# Force the native PowerShell hook and make each readiness probe consume its
# full two-second budget without touching the network.
$ChildCommand = @"
`$ProgressPreference = 'SilentlyContinue'
`$env:Path = `$PSHOME
function global:Invoke-WebRequest {
Start-Sleep -Seconds 2
throw 'fixture: companion unavailable'
}
& '$HookPath'
"@
$EncodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($ChildCommand))

$HookProcess = Start-Process `
-FilePath (Get-Process -Id $PID).Path `
-ArgumentList @("-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", $EncodedCommand) `
-WindowStyle Hidden `
-RedirectStandardInput $EmptyInput `
-RedirectStandardOutput $StdoutPath `
-RedirectStandardError $StderrPath `
-PassThru

$Finished = $HookProcess.WaitForExit($HostTimeoutSeconds * 1000)
if (-not $Finished) {
Stop-Process -Id $HookProcess.Id -Force -ErrorAction SilentlyContinue
throw "Antigravity's declared $HostTimeoutSeconds-second timeout kills the native hook before it emits readiness JSON"
}
$HookProcess.WaitForExit()
$HookProcess.Refresh()

$Stdout = Get-Content -Raw $StdoutPath -ErrorAction SilentlyContinue
$Stderr = Get-Content -Raw $StderrPath -ErrorAction SilentlyContinue
if ($HookProcess.ExitCode -is [int] -and $HookProcess.ExitCode -ne 0) {
throw "native ensure hook exited $($HookProcess.ExitCode): $Stderr"
}
if ($Stdout -notmatch "did not become ready") {
throw "native ensure hook completed without the expected readiness diagnostic: $Stdout"
}

Write-Host "PASS: native Antigravity cold-start hook completes within its declared timeout"
} finally {
if (Test-Path $PidFile) {
$AgentPid = Get-Content $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1
if ($AgentPid) {
Stop-Process -Id $AgentPid -Force -ErrorAction SilentlyContinue
}
}
foreach ($Name in $EnvironmentNames) {
[Environment]::SetEnvironmentVariable($Name, $OriginalEnvironment[$Name], "Process")
}
Remove-Item -Recurse -Force $Root -ErrorAction SilentlyContinue
}
75 changes: 75 additions & 0 deletions tests/antigravity-ensure-hook-timeout-budget.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
hook="$repo_root/.antigravity-plugin/hooks/ensure-monk-agent.sh"
hooks_json="$repo_root/.antigravity-plugin/hooks.json"

tmp="$(mktemp -d)"
agent_pid=""
cleanup() {
if [ -f "$tmp/home/.monk/agent/launcher/run/monk-agent.pid" ]; then
agent_pid="$(cat "$tmp/home/.monk/agent/launcher/run/monk-agent.pid" 2>/dev/null || true)"
fi
if [ -n "$agent_pid" ]; then
kill "$agent_pid" 2>/dev/null || true
fi
rm -rf "$tmp"
}
trap cleanup EXIT

mkdir -p "$tmp/bin" "$tmp/home"

# Keep the launched process alive while making every readiness probe use its
# full two-second request budget. This exposes the difference between retry
# count and elapsed wall-clock time without using the network or monk-agent.
cat >"$tmp/monk-agent" <<'EOF'
#!/usr/bin/env sh
exec sleep 60
EOF
chmod +x "$tmp/monk-agent"

cat >"$tmp/bin/curl" <<'EOF'
#!/usr/bin/env sh
sleep 2
exit 1
EOF
chmod +x "$tmp/bin/curl"

configured_timeout="$(sed -n 's/.*"timeout"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$hooks_json" | head -n 1)"
if [ -z "$configured_timeout" ]; then
echo "fixture assumption failed: could not read Antigravity ensure hook timeout" >&2
exit 2
fi

set +e
PATH="$tmp/bin:$PATH" \
HOME="$tmp/home" \
MONK_AGENT_PATH="$tmp/monk-agent" \
MONK_AGENT_HOME="$tmp/home/.monk" \
timeout "${configured_timeout}s" sh "$hook" </dev/null >"$tmp/stdout" 2>"$tmp/stderr"
status=$?
set -e

if [ "$status" -eq 124 ]; then
if [ -s "$tmp/stdout" ]; then
echo "unexpected stdout before the host timeout:" >&2
cat "$tmp/stdout" >&2
fi
echo "FAIL: Antigravity's declared ${configured_timeout}-second timeout kills the cold-start hook before it emits readiness JSON" >&2
exit 1
fi

if [ "$status" -ne 0 ]; then
echo "FAIL: ensure hook exited with status $status" >&2
cat "$tmp/stderr" >&2
exit 1
fi

if ! grep -q 'did not become ready' "$tmp/stdout"; then
echo "FAIL: ensure hook completed without the expected readiness diagnostic" >&2
cat "$tmp/stdout" >&2
exit 1
fi

echo "PASS: Antigravity cold-start hook completes within its declared timeout"