Skip to content
Merged
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
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ ff-rdp wait --text "Success" --wait-timeout 10000
# Wait for a JavaScript expression to become truthy
ff-rdp wait --eval "document.readyState === 'complete'"

# Plain sleep, no condition or Firefox connection needed (--time is a legacy alias)
ff-rdp wait --sleep-ms 2000

# List cookies
ff-rdp cookies

Expand Down Expand Up @@ -380,6 +383,17 @@ ff-rdp --no-daemon eval "1+1"
whether that owner process is still alive and, if so, keeps the profile
regardless of age. This is a positive "still in use" signal that closes the
gap where a fully-idle-but-running Firefox could look stale by mtime alone.
- A marker naming a **dead** PID is reclaimed by the very next `launch`
immediately, without waiting out the age threshold — a dead owner is
definitive proof of abandonment, not just "old enough to guess at" (iter-142;
fixes an observed 62 profiles / 2.7 GB accumulating in a single day, all
younger than the old 7-day gate).
- Every `ff-rdp launch` also sweeps `~/.ff-rdp/` housekeeping files: stale
per-port spawn locks, the legacy port-less `daemon.spawn.lock` name, and
`daemon.<port>.throttle.json` state files whose recorded daemon PID is no
longer alive (iter-142). Previously this only ran on the rare
daemon-autostart path, so a session that reused an already-running daemon
never triggered it at all.
- `ff-rdp profiles list` / `ff-rdp profiles prune` inspect and reclaim the
profile directory explicitly; `ff-rdp doctor` warns when the profile store
grows past 100 entries or 1 GiB. `profiles prune --all` skips the age gate
Expand Down
45 changes: 37 additions & 8 deletions crates/ff-rdp-cli/src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,9 +493,16 @@ scope and `const`/`let` declarations never leak across calls. The
Top-level `await` works (iter-132): `ff-rdp eval 'await Promise.resolve(41) + 1'`
resolves to 42. Scripts containing `await` are transparently wrapped in an
async IIFE before evaluation — no `--async` flag or extra syntax needed. A
single-expression script (no top-level `;`) auto-returns its value; a
multi-statement script needs an explicit `return` to surface a value (it
still runs either way — no SyntaxError).
single-expression script auto-returns its value. A multi-statement script
(statements separated by `;` OR by a plain newline — iter-142 fixed
ASI-separated scripts being misclassified and leaking the wrapper into a
SyntaxError) also auto-returns its value if the LAST statement is a bare
expression, e.g. `let x = await foo(); x + 1` returns `x + 1` — every
earlier statement still runs unwrapped, so an explicit `return` earlier in
the script keeps working. Only when the last statement is not a bare
expression (a declaration, a control-flow construct) does the script need
its own explicit `return` to surface a value (it still runs either way — no
SyntaxError).

Output: {\"results\": <value>, \"total\": 1, \"meta\": {...}}

Expand Down Expand Up @@ -742,16 +749,24 @@ other. On success, the output gains {\"match_count\": N, \"chosen_index\": N}.

Output: {\"results\": {\"typed\": true, \"tag\": \"INPUT\", \"value\": \"...\"}, \"total\": 1, \"meta\": {...}}")]
Type(TypeArgs),
/// Wait for a condition to become true (polls every 100ms).
/// Exactly one of --selector, --text, --eval, or --ref must be specified.
#[command(long_about = "Wait for a condition to become true (polls every 100ms).
/// Wait for a condition to become true (polls every 100ms), or sleep for a fixed duration.
/// Exactly one of --selector, --text, --eval, --ref, or --sleep-ms must be specified.
#[command(
long_about = "Wait for a condition to become true (polls every 100ms), or sleep for a fixed duration.

Exactly one of --selector, --text, --eval, or --ref must be specified.
Exactly one of --selector, --text, --eval, --ref, or --sleep-ms must be specified.

Use --ref <id> to wait for an element identified by its ARIA-tree ref ID
(daemon mode only). Equivalent to --selector but uses a stable ref handle.

Output: {\"results\": {\"matched\": true, \"elapsed_ms\": N, \"condition\": \"selector|text|eval\"}, \"total\": 1, \"meta\": {...}}")]
Use --sleep-ms <N> for a plain delay with no condition and no Firefox
connection at all — e.g. `ff-rdp wait --sleep-ms 2000`. Prefer a real
condition (--selector/--text/--eval/--ref) whenever one exists; a fixed
sleep is always a guess about how long something takes. --timeout-ms does
not apply to --sleep-ms, which always runs for exactly its own duration.

Output: {\"results\": {\"matched\": true, \"elapsed_ms\": N, \"condition\": \"selector|text|eval|sleep\"}, \"total\": 1, \"meta\": {...}}"
)]
Wait(WaitArgs),
/// List cookies via the Firefox StorageActor (includes httpOnly, secure, sameSite, etc.)
#[command(
Expand Down Expand Up @@ -1695,8 +1710,22 @@ pub struct WaitArgs {
/// ARIA-tree ref ID from a previous dom/snapshot call (daemon mode only, e.g. 'e3')
#[arg(long = "ref", value_name = "REF_ID", group = "condition")]
pub ref_id: Option<String>,
/// Plain sleep for this many milliseconds — no condition, no Firefox
/// connection, just a delay. For when you need to pace commands rather
/// than wait for a specific page state (use --selector/--text/--eval/--ref
/// instead whenever a real condition exists — a fixed sleep is always a
/// guess). The legacy spelling `--time` is also accepted as a hidden
/// alias (iter-142: this was the flag dogfooders reached for first).
#[arg(
long = "sleep-ms",
alias = "time",
value_name = "MS",
group = "condition"
)]
pub sleep_ms: Option<u64>,
/// Timeout in milliseconds before giving up (canonical flag — use this one).
/// The legacy spelling `--wait-timeout` is also accepted as a hidden alias.
/// Not used by --sleep-ms, which always runs for exactly its own duration.
#[arg(long = "timeout-ms", alias = "wait-timeout", default_value_t = 5000)]
pub wait_timeout: u64,
}
Expand Down
Loading
Loading