- A pid file holding "", "-1" or "0" counted as a live holder (kill -0 -1
signals every process and succeeds), locking Chromium out for good. A pid
must be a positive integer; anything else is stale.
- Two setups judging the same lock stale raced on rm -rf + mkdir and the
loser deleted the winner's fresh lock. The stale dir is renamed first
(atomic), so exactly one reclaims.
- A lock dir with no pid file (killed between mkdir and echo) was never
reclaimed; it now expires once older than the install bound.
- _kill_tree needed pgrep; debian-slim and git-bash ship none, so the bound
killed only the wrapper subshell and the installer kept running. Without
pgrep the children are found by walking /proc/*/stat.
- The timeout knob is normalized in one place with one comment; the trap's
exit 130 is the only exit the block may contain.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The relink gate alone left three destructive sites open:
- link_claude_skill_dirs runs BEFORE relink on every ./setup and used
`ln -snf` (Linux replaces a user's real SKILL.md with a symlink into
gstack) or, on Windows, rm -rf + cp followed by a marker that made the
user's directory "ours" on the next flip. It and _install_alias_skill_md
now consult _claude_entry_is_ours first and skip loudly.
- cleanup_prefixed_claude_symlinks kept a bare name-match deletion and a
`*gstack*` substring match. Symlink arms use anchored `gstack/` segment
patterns; the Windows real-file arm proves provenance (marker,
byte-identity with our source, or the full two-line gen-skill-docs banner
within the first 40 lines, never a one-line substring another generator
could emit). cleanup_old_claude_symlinks uses the same banner rule.
- gstack-relink's fast path judged absolute targets before canonicalizing,
so `/x/gstack/../foreign/SKILL.md` counted as ours; dot-segment targets
now canonicalize first. Its banner rule matches setup's.
The `.gstack-owned` marker records the owning payload's realpath. Entries
skipped by setup or relink are listed in the final setup summary.
Chromium bootstrap refinements from the pre-landing review: an INT/TERM
trap kills the installer's process tree; the Windows npm chain no longer
masks an install failure; GSTACK_SKIP_PLAYWRIGHT=1 is reported as a choice
rather than a failure and sends no telemetry; the timeout knob is
normalized (0, 000, non-numeric, or more than nine digits fall back to the
600s default instead of killing on the first poll or never killing).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
setup runs under `set -e`, and the Chromium bootstrap in section 2 sat ahead
of skill registration in section 4 with a bare `bunx playwright install
chromium`, an unbounded download, and an explicit `exit 1` after the
post-install launch probe. On an offline, proxied, or AppArmor-restricted box
the user ended with ZERO skills registered and a re-run that died at the same
line; a wedged download hung setup indefinitely.
Every browser failure now records a reason code in _PW_FAIL_REASON and setup
continues: skipped (GSTACK_SKIP_PLAYWRIGHT=1, #913), chromium-install,
chromium-install-timeout (the download is bounded by the existing
_wait_with_deadline helper, default 600s, env GSTACK_PLAYWRIGHT_INSTALL_TIMEOUT,
process tree killed via _kill_tree), chromium-install-locked (another setup
holds the lock: this one registers skills and re-probes next time instead of
exiting), windows-no-node, windows-node-modules, post-install-launch (with the
GSTACK_CHROMIUM_NO_SANDBOX=1 hint for Ubuntu 24.04's userns policy, #2157).
The daemon font refresh is skipped when Chromium is unavailable. The final
summary names the skills that need the browser (/qa, /qa-only,
/design-review, /browse, make-pdf, /pair-agent) and the fix for the recorded
reason, and logs the reason code (never a path) through gstack-telemetry-log
when telemetry is on.
Tests: static invariants over the anchor-sliced block (no exit, every reason
code, deadline helper, trap chaining, guarded refresh, summary contents) plus
an integration harness that executes the real block with a stubbed probe and
installer: install failure, hang killed at the deadline with the tree kill
recorded, non-numeric knob fallback, live lock (continues, installer not run,
lock preserved), stale lock reclaimed, post-install probe failure, and the
skip flag.
Credit @DavidMiserak (PR #1900) for the best-effort shape; re-implemented on
the current block.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>