#2171

fill/type consume option-shaped text as flags, even after an end-of-options marker

Openrotemb-wondopened 10d ago

Problem

fill and type cannot reliably accept literal text that looks like a CLI option. Quoting the text does not help: it reaches the CLI as one argv entry, then the CLI consumes it as a flag. The usual -- end-of-options convention does not protect it either.

This matters for agents and wrappers passing arbitrary user text to a form. A command can return success while inserting different text or clearing the field.

Reproduced with the official v0.39.1 macOS arm64 binary and Chrome. The same parser paths are present on current main at 5ee8691339a5a002e4d7454eec95250253bc7419.

Reproduction

Chrome must already be installed. Run this in Bash with agent-browser on PATH. It creates an isolated session and closes it on exit.

export AGENT_BROWSER_SOCKET_DIR="$(mktemp -d /tmp/ab-literal.XXXXXX)"
trap 'agent-browser --session literal-repro close >/dev/null 2>&1' EXIT

agent-browser --session literal-repro open 'data:text/html,<input id="field" value="seed">'

agent-browser --session literal-repro fill '#field' '--json'
agent-browser --session literal-repro --json get value '#field'
# Actual data.value: ""
# Expected data.value: "--json"

agent-browser --session literal-repro fill '#field' seed
agent-browser --session literal-repro type '#field' -- '--clear'
agent-browser --session literal-repro --json get value '#field'
# Actual data.value: "--"
# Expected with a literal end-of-options boundary: "seed--clear"

type '#field' '--clear' without the terminator is a legitimate request to clear; the bug is the lack of a way to pass that same string as literal text, including after --.

Root cause

The global parsing / clean_args path in cli/src/flags.rs removes recognized flags even when they occupy the text argument. Separately, the type branch in cli/src/commands.rs scans the remaining arguments for --clear and --delay without an end-of-options state.

The global and command-specific parsers both need to respect a literal-data boundary. Merely shell-quoting or fixing one parsing stage is insufficient.

Workaround (verified)

For literal replacement text, use JSON-stdin batch mode with fill:

printf '%s
' '[["fill","#field","--json"],["get","value","#field"]]' |
  agent-browser --session literal-repro batch --json

This preserves --json as the field value. I also verified --clear, --delay, and --help. Batch type still runs its command-specific option parser, so this workaround deliberately uses fill; it is not a workaround for every append/keystroke use case.

Proposed fix

Either:

  1. Implement an end-of-options boundary honored by both global and command-specific parsing, preserving everything after it as data; or
  2. Add an explicit opaque text input channel, such as --text-base64 or a structured stdin field, and decode only inside the command parser.

Our embedded integration uses --text-base64 for fill and type: validate Base64 and UTF-8, then put the decoded string directly into the daemon's value / text field without rescanning it for flags. That keeps existing type --clear / --delay behavior while giving integrations an unambiguous literal path. This is a proposed implementation direction, not a claim that upstream already supports the flag.

Validation and regression coverage

The reproductions and batch workaround above were run against the released binary. Current main was inspected, not built. Useful regression cases:

  • Option-shaped text: --json, --help, --clear, --delay, --profile, --config, and --.
  • Empty text, Unicode, leading/trailing whitespace, and embedded newlines.
  • Existing actual flag behavior remains supported.
  • A literal input path stays literal through CLI, batch, and MCP delegation.

Related: #1432 added parsing of real type --clear / --delay options; this report concerns passing those strings as data. #136 concerns shell expansion of $$, which is a different mechanism.

Activity

0

No activity yet.