Skip to content

feat: smart settle detection for CLI --snap#4

Open
404khai wants to merge 1 commit into
antiwork:mainfrom
404khai:feat/wait-for-settle
Open

feat: smart settle detection for CLI --snap#4
404khai wants to merge 1 commit into
antiwork:mainfrom
404khai:feat/wait-for-settle

Conversation

@404khai

@404khai 404khai commented Jul 4, 2026

Copy link
Copy Markdown

Summary

CLI --snap previously relied on a blind --wait sleep after navigation finished. That fails for dashboards, charts, and SPAs that keep rendering after didFinish — the screenshot captures a loading skeleton instead of the final page.

This adds --wait-for with three settle modes:

Mode What it waits for
load document.readyState === 'complete' (HTML + subresources)
network-idle No fetch/XHR activity for 500 ms (injected tracker at document start)
selector:CSS Polls until document.querySelector matches

--wait still adds extra seconds after the condition is met (use --wait 0 to skip). Existing behavior is unchanged when --wait-for is omitted.

# Before: blind sleep, chart still loading
chromeless dashboard.com --snap chart.png --wait 0.5

# After: waits until chart element appears
chromeless dashboard.com --snap chart.png --wait-for selector:.chart-ready --wait 0

Test Plan

Built with ./build.sh on macOS 26 (arm64, 2x Retina):

  • ./Chromeless.app/Contents/MacOS/Chromeless --help lists --wait-for modes
  • tests/fixtures/chart.html with --wait 0.5 → 9 KB PNG (loading skeleton)
  • Same fixture with --wait-for selector:.chart-ready --wait 0 → 42 KB PNG (rendered chart)
  • https://example.com --wait-for load --wait 0 → snapshot succeeds
  • Backward compat: --snap without --wait-for still uses blind --wait (default 1 s)
  • --wait-for times out after 30 s (exit code 4)
BIN="./Chromeless.app/Contents/MacOS/Chromeless"
FIXTURE="$(pwd)/tests/fixtures/chart.html"

# 1. Verify --help lists --wait-for modes
$BIN --help | grep -A5 wait-for

# 2. Blind wait capture (loading skeleton expected)
$BIN "file://$FIXTURE" \
  --snap /tmp/chart-blind.png \
  --size 400x300 \
  --wait 0.5 && \
  ls -lh /tmp/chart-blind.png

# 3. Selector-based wait capture (rendered chart expected)
$BIN "file://$FIXTURE" \
  --snap /tmp/chart-selector.png \
  --size 400x300 \
  --wait-for selector:.chart-ready \
  --wait 0 && \
  ls -lh /tmp/chart-selector.png

# 4. Wait for page load on external URL
$BIN https://example.com \
  --snap /tmp/example.png \
  --size 800x600 \
  --wait-for load \
  --wait 0 && \
  ls -lh /tmp/example.png

# 5. Backward compatibility check (default blind wait)
$BIN https://example.com \
  --snap /tmp/legacy.png \
  --size 800x600 && \
  ls -lh /tmp/legacy.png

# 6. Timeout behavior check (should exit with code 4)
$BIN "file://$FIXTURE" \
  --snap /tmp/timeout.png \
  --wait-for selector:.never-exists \
  --wait 0

echo "exit: $?"

Replace blind --wait sleeps with deterministic readiness checks (load,
network-idle, selector) so dashboard and SPA screenshots capture fully
rendered content instead of loading skeletons.

Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds smarter readiness waits for CLI snapshots.

  • New --wait-for modes for load, network idle, and selector readiness.
  • Snapshot flow now polls readiness before applying the extra --wait delay.
  • README examples and a delayed chart fixture were added.

Confidence Score: 4/5

The snapshot readiness path needs fixes before merging.

  • Network-idle can report ready before large fetch bodies finish.
  • The global snapshot watchdog can fire before slow navigations reach the snap flow.
  • The selector mode and README changes look straightforward.

main.swift

Important Files Changed

Filename Overview
main.swift Adds settle-mode parsing, readiness polling, network-idle tracking, and updated snapshot timeout behavior.
README.md Documents the new snapshot readiness modes and examples.
tests/fixtures/chart.html Adds a delayed chart fixture for selector-based readiness.

Reviews (1): Last reviewed commit: "feat: add --wait-for settle detection fo..." | Re-trigger Greptile

Comment thread main.swift
Comment thread main.swift
Comment on lines +873 to +879
let snapTimeout: TimeInterval = {
guard let snap = launchOptions.snap else { return 30 }
switch snap.settle {
case .sleep: return snap.wait + 15
default: return 30 + snap.wait + 5
}
}()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Watchdog Starts Before Navigation

This timeout is scheduled from application launch, while runSnapJob only starts after webView(_:didFinish:). With the default --snap path, a page that takes more than about 15 seconds to finish loading now exits with chromeless: --snap timed out before the snapshot wait even starts, even though the previous 30-second watchdog still allowed that navigation.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant