From 0dec8c116aff3f95f3885f0defd195ec57cbda87 Mon Sep 17 00:00:00 2001 From: Ray Bell Date: Sat, 6 Jun 2026 23:17:55 -0400 Subject: [PATCH 1/2] add powershell statusline --- examples/statusline/statusline.ps1 | 186 +++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 examples/statusline/statusline.ps1 diff --git a/examples/statusline/statusline.ps1 b/examples/statusline/statusline.ps1 new file mode 100644 index 000000000..dd820b365 --- /dev/null +++ b/examples/statusline/statusline.ps1 @@ -0,0 +1,186 @@ +# PowerShell status line script for Antigravity CLI +# Replicates the official statusline.sh example in PowerShell + +# Ensure standard output encoding is UTF-8 so Unicode characters display correctly +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + +# --- ANSI Helpers (Standard 16-color palette only) --- +$esc = [char]27 +$R = "$esc[0m" # Reset +$B = "$esc[1m" # Bold +$D = "$esc[2m" # Dim +$I = "$esc[3m" # Italic + +# Foreground accents +$FG_BLACK = "$esc[30m" +$FG_RED = "$esc[31m" +$FG_GREEN = "$esc[32m" +$FG_YELLOW = "$esc[33m" +$FG_BLUE = "$esc[34m" +$FG_MAGENTA = "$esc[35m" +$FG_CYAN = "$esc[36m" +$FG_WHITE = "$esc[37m" + +$FG_GRAY = "$esc[90m" +$FG_BRIGHT_RED = "$esc[91m" +$FG_BRIGHT_GREEN = "$esc[92m" +$FG_BRIGHT_YELLOW = "$esc[93m" +$FG_BRIGHT_BLUE = "$esc[94m" +$FG_BRIGHT_MAGENTA = "$esc[95m" +$FG_BRIGHT_CYAN = "$esc[96m" +$FG_BRIGHT_WHITE = "$esc[97m" + +$NUM_COLOR = "${FG_BRIGHT_WHITE}${B}" + +# --- Unicode Icons and Symbols --- +$readyIcon = [char]::ConvertFromUtf32(0x25cf) # โ— +$thinkingIcon = [char]::ConvertFromUtf32(0x23f3) # โณ +$workingIcon = [char]::ConvertFromUtf32(0x2699) # โš™ +$toolIcon = [char]::ConvertFromUtf32(0x1f527) # ๐Ÿ”ง +$diamondIcon = [char]::ConvertFromUtf32(0x25c6) # โ—† +$fullBlock = [char]::ConvertFromUtf32(0x2588) # โ–ˆ +$darkShade = [char]::ConvertFromUtf32(0x2593) # โ–“ +$medShade = [char]::ConvertFromUtf32(0x2592) # โ–’ +$lightShade = [char]::ConvertFromUtf32(0x2591) # โ–‘ +$middleDot = [char]::ConvertFromUtf32(0xb7) # ยท +$boxH = [char]::ConvertFromUtf32(0x2500) # โ”€ +$boxV = [char]::ConvertFromUtf32(0x2502) # โ”‚ +$boxTR = [char]::ConvertFromUtf32(0x256d) # โ•ญ +$boxBR = [char]::ConvertFromUtf32(0x2570) # โ•ฐ + +# Default values +$state = "idle" +$usedPct = 0.0 +$vcsBranch = "" +$vcsDirty = $false +$sandbox = $false +$artifacts = 0 +$subagentsCount = 0 +$bgTasks = 0 +$model = "" +$cols = 80 + +# --- Parse JSON from stdin --- +try { + $jsonString = [System.Console]::In.ReadToEnd() + if ($jsonString) { + $data = ConvertFrom-Json $jsonString + if ($data) { + if ($data.agent_state) { $state = $data.agent_state } + if ($data.context_window -and $data.context_window.used_percentage -ne $null) { + $usedPct = [double]$data.context_window.used_percentage + } + if ($data.vcs) { + if ($data.vcs.branch) { $vcsBranch = $data.vcs.branch } + if ($data.vcs.dirty -ne $null) { $vcsDirty = [bool]$data.vcs.dirty } + } + if ($data.sandbox -and $data.sandbox.enabled -ne $null) { $sandbox = [bool]$data.sandbox.enabled } + if ($data.artifact_count -ne $null) { $artifacts = [int]$data.artifact_count } + if ($data.subagents) { + if ($data.subagents -is [array]) { + $subagentsCount = $data.subagents.Length + } else { + $subagentsCount = 1 + } + } + if ($data.task_count -ne $null) { $bgTasks = [int]$data.task_count } + if ($data.model -and $data.model.display_name) { $model = $data.model.display_name } + if ($data.terminal_width -ne $null) { $cols = [int]$data.terminal_width } + } + } +} catch { + # Fallback to defaults if parsing fails +} + +# --- State Indicator --- +switch ($state) { + "idle" { $S = "${FG_BRIGHT_GREEN}${B}${readyIcon} READY${R}" } + "thinking" { $S = "${FG_BRIGHT_YELLOW}${B}${thinkingIcon} THINKING${R}" } + "working" { $S = "${FG_BRIGHT_CYAN}${B}${workingIcon} WORKING${R}" } + "tool_use" { $S = "${FG_BRIGHT_MAGENTA}${B}${toolIcon} TOOL${R}" } + default { $S = "${FG_WHITE}${B}${readyIcon} $($state.ToUpper())${R}" } +} + +# --- VCS Branch --- +$V = "" +if ($vcsBranch) { + if ($vcsDirty) { + $V = "${FG_GRAY} ${diamondIcon} ${FG_BRIGHT_RED}${vcsBranch}${FG_BRIGHT_YELLOW}*${R}" + } else { + $V = "${FG_GRAY} ${diamondIcon} ${FG_BRIGHT_BLUE}${vcsBranch}${R}" + } +} + +# --- Model --- +$M = "" +if ($model) { + $M = "${FG_GRAY} ${diamondIcon} ${FG_BRIGHT_MAGENTA}${I}${model}${R}" +} + +# --- Sandbox Badge --- +if ($sandbox) { + $SB = "${FG_GRAY}sandbox ${FG_BRIGHT_GREEN}${B}ON${R}" +} else { + $SB = "${FG_GRAY}sandbox off${R}" +} + +# --- Context Bar --- +$pctFmt = $usedPct.ToString("F1", [System.Globalization.CultureInfo]::InvariantCulture) +$pctInt = [int][Math]::Floor($usedPct) + +$barLen = 15 +$filled = [int][Math]::Floor($pctInt * $barLen / 100) +$remainder = ($pctInt * $barLen) % 100 + +if ($pctInt -ge 90) { + $barColor = $FG_BRIGHT_RED +} elseif ($pctInt -ge 60) { + $barColor = $FG_BRIGHT_YELLOW +} else { + $barColor = $FG_BRIGHT_WHITE +} + +$BAR = "" +for ($i = 0; $i -lt $barLen; $i++) { + if ($i -lt $filled) { + $BAR += $fullBlock + } elseif ($i -eq $filled) { + if ($remainder -ge 75) { + $BAR += $darkShade + } elseif ($remainder -ge 50) { + $BAR += $medShade + } elseif ($remainder -ge 25) { + $BAR += $lightShade + } else { + $BAR += $middleDot + } + } else { + $BAR += $middleDot + } +} + +# --- Stats --- +$CTX = "${FG_GRAY}ctx ${barColor}${BAR} ${NUM_COLOR}${pctFmt}%${R}" +$ART_FMT = "${FG_GRAY}artifacts ${NUM_COLOR}${artifacts}${R}" +$SUB_FMT = "${FG_GRAY}subagents ${NUM_COLOR}${subagentsCount}${R}" +$BG_FMT = "${FG_GRAY}tasks ${NUM_COLOR}${bgTasks}${R}" + +# Separator +$DOT = "${FG_GRAY} ${middleDot} ${R}" + +# --- Output --- +$LINE1 = "${S}${M}${V}" +$LINE2 = " ${CTX}${DOT}${ART_FMT}${DOT}${SUB_FMT}${DOT}${BG_FMT}${DOT}${SB}" + +if ($cols -ge 120) { + # Wide: single line + Write-Output "${LINE1}${FG_GRAY} ${boxV} ${R}${LINE2}" +} elseif ($cols -ge 80) { + # Medium: two-line layout with border + Write-Output "${FG_GRAY}${boxTR}${boxH}${R} ${LINE1}" + Write-Output "${FG_GRAY}${boxBR}${boxH}${R}${LINE2}" +} else { + # Narrow: compact two-line, minimal chrome + Write-Output "${S}${M}" + Write-Output "${CTX}${DOT}${BG_FMT}" +} From 43c7378911d327c1c6d5c0c2ccc5a928860849a3 Mon Sep 17 00:00:00 2001 From: raybell-md Date: Sun, 7 Jun 2026 00:18:15 -0400 Subject: [PATCH 2/2] Detect sandbox mode via session log in statusline example `agy --sandbox` enables the terminal sandbox but does not populate .sandbox.enabled in the statusLine payload (it stays false as of 1.0.6), so the example's sandbox badge always reads "off" under --sandbox. The flag is not exported to the statusLine process's environment, and the process is reparented to init, so neither env nor the parent command line can be inspected. The only reliable signal is the session log line "--sandbox: enabling terminal sandbox for this session", which cli.log symlinks to. Keep .sandbox.enabled as the primary source and fall back to grepping the session log, so the badge self-corrects once the payload field is fixed upstream (see #321). --- examples/statusline/statusline.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/statusline/statusline.sh b/examples/statusline/statusline.sh index 390fea1ee..4df35089a 100755 --- a/examples/statusline/statusline.sh +++ b/examples/statusline/statusline.sh @@ -87,6 +87,22 @@ if [ -n "$MODEL" ]; then M="${FG_GRAY} โ•ฑ ${FG_BRIGHT_MAGENTA}${I}${MODEL}${R}" fi +# โ”€โ”€โ”€ Sandbox State (workaround for unpopulated payload field) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# As of agy 1.0.6, `agy --sandbox` enables the terminal sandbox but does NOT set +# .sandbox.enabled in the statusLine payload (it stays false), so the badge below +# would always read "off". The flag is also not exported to this process's env, +# and the process is reparented to init, so neither env nor the parent command +# line can be inspected. The only reliable signal is the session log, which +# cli.log symlinks to ("--sandbox: enabling terminal sandbox for this session"). +# .sandbox.enabled remains the primary source, so this self-corrects once the +# payload field is populated upstream. See issue #321. +if [ "$SANDBOX" != "true" ]; then + SANDBOX_LOG="$HOME/.gemini/antigravity-cli/cli.log" + if [ -r "$SANDBOX_LOG" ] && grep -q 'enabling terminal sandbox' "$SANDBOX_LOG" 2>/dev/null; then + SANDBOX="true" + fi +fi + # โ”€โ”€โ”€ Sandbox Badge โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ if [ "$SANDBOX" = "true" ]; then SB="${FG_GRAY}sandbox ${FG_BRIGHT_GREEN}${B}ON${R}"