Skip to content

Statusline: timeout 1 git status never runs on macOS, so the git share of the startup estimate is always zero #2136

Description

@hjbrandt

Version

LifeOS 7.40.4 (latest release, 2026-08-14) — component LIFEOS/LIFEOS_StatusLine.sh; repro run against main @ 5e2f2e8, which carries the same file.

What is broken

The startup context estimate asks git how large the working tree's status block will be, and bounds that call with timeout 1. macOS ships no timeout(1) — it is a GNU coreutils program, absent from a stock install and from the Xcode command line tools. On a Mac the command therefore fails before git runs, its error is discarded by the 2>/dev/null already on the line, and the empty output falls through wc -c as 0. Two things follow. The git contribution to the pre-first-API context estimate is always zero whatever the state of the working tree, so STARTUP LOAD under-reports by about a token per three and a half bytes of git status --porcelain output. And the bound itself does not exist on macOS: on a repository where git status is genuinely slow there is nothing stopping it from stalling the render, which is the case the timeout was presumably written for. The branch is reached on the pre-first-API ticks only, gated at :400 by [ "$context_pct" = "0" ] && [ "$total_input" -eq 0 ], so the wrong figure is the one shown while a session is starting up. The same file already branches on platform for stat at :209-211, so it knows it runs on both and this looks like an oversight rather than a GNU-only choice.

Where (file:line)

LifeOS/install/LIFEOS/LIFEOS_StatusLine.sh:447 (writer; consumer is :448, timeout appears nowhere else in the file)

Repro on a clean tree

# macOS, stock PATH, no GNU coreutils. Nothing here reads $HOME or the installed
# LifeOS, so the numbers do not depend on how your install is configured.

git clone https://github.com/danielmiessler/LifeOS.git /tmp/lifeos-clean
sed -n '447p' /tmp/lifeos-clean/LifeOS/install/LIFEOS/LIFEOS_StatusLine.sh

# A throwaway repo with a known amount of status output:
R=$(mktemp -d); cd "$R"; git init -q .
for i in $(seq 1 60); do echo "content $i" > "file-$i.txt"; done

echo "timeout on PATH: $(command -v timeout || echo NONE)"

# Line 447, character for character as it appears in the clean tree:
v=$(timeout 1 git -C "$R" status --porcelain 2>/dev/null | wc -c | tr -d ' ')
echo "_git_bytes=$v"

# What git actually reports for the same tree, and what :448 would have added:
b=$(git -C "$R" status --porcelain | wc -c | tr -d ' ')
echo "git status --porcelain bytes: $b"
echo "tokens :448 should add: $(( b * 10 / 35 ))"

Negative control

Run on unpatched main @ 5e2f2e8, macOS 27.0, /bin/bash 3.2.57, stock PATH:

timeout on PATH: NONE
_git_bytes=0
git status --porcelain bytes: 891
tokens :448 should add: 254

The line reports zero bytes of git status for a tree that has 891 bytes of it, so line 448 adds 0 tokens where it should add 254. A three-file tree gives the same _git_bytes=0 against 26 real bytes, so the result is zero independent of the tree rather than a rounding artefact. Running the whole unpatched script against that same 60-file repo with a startup payload (used_percentage: 0, total_input_tokens: 0) and reading startup_tokens back out of /tmp/pai-startup-estimate-<session_id>.sh gives a figure that is 254 lower than the same script with a working _git_bytes; the absolute total there depends on the reader's own install, the 254 does not.

Suggested fix

Built and run against the clean tree, not a sketch. Use the wrapper when one exists and run bare when neither does, so the value survives either way:

if command -v timeout >/dev/null 2>&1; then _TIMEOUT=(timeout 1)
elif command -v gtimeout >/dev/null 2>&1; then _TIMEOUT=(gtimeout 1)
else _TIMEOUT=(); fi
_git_bytes=$("${_TIMEOUT[@]}" git -C "$current_dir" status --porcelain 2>/dev/null | wc -c | tr -d ' ')

Verified end to end on main @ 5e2f2e8, macOS 27.0, /bin/bash 3.2.57: two copies of the file differing only in that line, the same 60-file dirty repo as current_dir, the startup payload above. startup_tokens reads 61129 unpatched and 61383 with the guard — a difference of exactly 254, the contribution the line is supposed to make. The empty-array expansion is safe here: the file sets only set -o pipefail at :8, not set -u.

What this does not do is give macOS the bound itself. It restores the value and keeps the timeout wherever one exists; a genuinely portable bound means backgrounding git and polling, which is more machinery than this line probably deserves. Happy to send it as a PR if that is useful.

Worth noting for the other direction: on Linux, where timeout exists, this line runs a real git status --porcelain on every startup tick that macOS silently skips.

Before submitting

  • I searched open and closed issues for this defect.
  • The repro runs against a clean tree of the version above, not against my modified install.
  • I removed personal data from the pasted output — real names, absolute home paths, tokens, my own content.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions