Skip to content

fix(cli): accept parent options placed after lazy subcommands (#55563 regression 1) [AI-assisted]#94431

Merged
steipete merged 2 commits into
openclaw:mainfrom
ml12580:fix/vuln-55563
Jul 7, 2026
Merged

fix(cli): accept parent options placed after lazy subcommands (#55563 regression 1) [AI-assisted]#94431
steipete merged 2 commits into
openclaw:mainfrom
ml12580:fix/vuln-55563

Conversation

@ml12580

@ml12580 ml12580 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

[AI-assisted] Original contribution by @ml12580; maintainer rewrite and validation by @steipete.

What Problem This Solves

OpenClaw v2026.3.24 enabled Commander's positional-option mode. That made this previously shipped and documented invocation fail during lazy command reparse:

openclaw browser tabs --browser-profile remote
error: unknown option '--browser-profile'

--browser-profile belongs to the browser parent, but the second parse happens only after tabs has replaced its lazy placeholder. Positional mode then treats the trailing flag as a tabs option. This is Regression 1 of #55563 and breaks existing WSL2/remote-CDP troubleshooting commands. Regression 2 in that issue (doctor --fix gateway cycling) is separate and intentionally untouched.

Why This Change Was Made

The contributor patch established the right normalization point. I rewrote it around one invariant: after the real lazy subtree loads, restore parent-option placement only when the selected child path does not own the same flag.

The final parser:

  • walks the real Commander hierarchy and consumes ancestor option values, so command-looking values do not confuse path selection;
  • moves only options owned by the lazy parent;
  • preserves collisions on the selected child, including browser extension pair --json and cookie --url;
  • ignores collisions that exist only on an unselected sibling;
  • preserves aliases, option values, missing required values, and the -- terminator.

Simply disabling positional options on browser was rejected: Commander 15 would make the parent steal colliding leaf flags. That would fix the reported command by breaking currently valid child behavior.

User Impact

Both supported orderings work again:

openclaw browser --browser-profile remote tabs
openclaw browser tabs --browser-profile remote

The same repair applies to nested lazy commands such as browser tab new --browser-profile remote. Existing child-option ownership remains unchanged. No config, protocol, auth, network, or migration surface changes.

Evidence

Dependency contract checked directly against Commander 15.0.0 source and types: positional parent options after a subcommand are intentionally disabled, and disabling positional mode would restore parent capture at the cost of child collisions.

Blacksmith Testbox provider/id: blacksmith-testbox / tbx_01kwxpxmb3x1g1prnaa9cs4230.

  • pnpm test src/cli/program/action-reparse.test.ts src/cli/program/register.subclis.test.ts — 32 passed.
  • pnpm test extensions/browser/src/cli/browser-cli.lazy.test.ts extensions/browser/src/cli/browser-cli-extension.test.ts extensions/browser/src/cli/browser-cli-state.option-collisions.test.ts — 26 passed.
  • pnpm check:changed -- CHANGELOG.md src/cli/program/action-reparse.ts src/cli/program/action-reparse.test.ts extensions/browser/src/cli/browser-cli.lazy.test.ts — passed all selected type, lint, docs, and repository guards before the release-owned changelog line was removed by the landing guard.
  • pnpm build — passed, including CLI bootstrap/import guards, runtime postbuild, plugin assets, and Control UI build.
  • Black-box built-CLI contract — 7/7 clauses passed: both parent-option orders were observably identical; nested order worked; selected-child collision, sibling collision, terminator, and missing-value behavior were preserved.
  • Fresh structured autoreview — clean, no accepted/actionable findings.

Release-note context and contributor credit are retained here. Root CHANGELOG.md is release-owned, so the native landing guard correctly kept it out of this normal PR.

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: M proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 18, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. labels Jun 19, 2026
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 1, 2026, 5:40 PM ET / 21:40 UTC.

Summary
The branch adds a shared lazy-reparse helper that hoists parent or ancestor Commander options placed after lazy subcommands, with focused helper, action-reparse, and browser lazy tests.

PR surface: Source +212, Tests +296. Total +508 across 5 files.

Reproducibility: yes. Source inspection shows docs still publish the after-subcommand browser-profile order, --browser-profile remains a browser parent option, and current lazy reparse has no parent-option hoist; the PR body also includes before/after terminal and focused test output.

Review metrics: 2 noteworthy metrics.

  • Shared parser entry point: 1 lazy-reparse entry point changed. The normalization runs through the shared lazy-command reparse path, so compatibility review should cover sibling lazy commands, not only browser tabs.
  • Current fallback guardrail: 1 fallback path and 2 tests to preserve. Current main protects nested lazy command fallback reconstruction, and the PR conflict must not discard that guardrail.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #55563
Summary: This PR is the focused candidate fix for the browser parent-option/lazy-subcommand regression in the canonical composite issue; the doctor/gateway half remains separate.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Rebase or resolve conflicts while preserving current main's full nested fallback reconstruction and tests.
  • Run focused parser/browser lazy tests after the resolution.
  • Confirm GitHub reports the refreshed head as mergeable before maintainer review.

Risk before merge

  • [P2] GitHub reports the PR as conflicting, and the PR head's action-reparse fallback still rebuilds only the leaf command; conflict resolution must keep current main's full nested command-path fallback and rawArgs-missing tests.
  • [P1] The hoist runs in the shared lazy-reparse path, so parser compatibility review needs to cover lazy command groups beyond the browser tabs example before merge.

Maintainer options:

  1. Preserve current fallback while rebasing (recommended)
    Resolve the conflict by keeping current main's full nested command-path fallback and rawArgs-missing tests while adding the parent-option hoist.
  2. Pause for parser ownership review
    If maintainers want a broader decision on shared lazy argv normalization, pause this PR until the CLI owner boundary is settled.

Next step before merge

  • [P2] The open PR has a real fix candidate but is currently conflicting; the next action is author or maintainer conflict resolution plus shared parser compatibility review.

Security
Cleared: The diff changes CLI parser helpers and tests only, with no dependency, workflow, secret, install, or publishing surface changes.

Review findings

  • [P2] Preserve nested fallback argv paths — src/cli/program/action-reparse.ts:14-16
Review details

Best possible solution:

Rebase or resolve conflicts by layering the parent-option hoist onto current main's full nested fallback reconstruction, then land with focused parser and browser lazy regression coverage.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows docs still publish the after-subcommand browser-profile order, --browser-profile remains a browser parent option, and current lazy reparse has no parent-option hoist; the PR body also includes before/after terminal and focused test output.

Is this the best way to solve the issue?

No at the current head. The reparse layer is the right place for the fix and the missing-value edge case is now covered, but the branch must preserve current-main nested fallback reconstruction before it is the best mergeable solution.

Full review comments:

  • [P2] Preserve nested fallback argv paths — src/cli/program/action-reparse.ts:14-16
    Current main reconstructs the full nested command path when Commander rawArgs is unavailable, but this PR head still falls back to only the leaf command name. Keep getCommandPathFromRoot and the rawArgs-missing tests while adding the hoist, or nested lazy commands can reparse as the wrong root command after conflict resolution.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against eb417fa206e6.

Label changes

Label justifications:

  • P2: This is a normal-priority documented CLI regression fix with limited blast radius, but the PR still needs conflict-safe parser repair before merge.
  • merge-risk: 🚨 compatibility: The PR changes shared lazy CLI parsing and currently conflicts with current-main fallback behavior that protects nested lazy command reparsing.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes after-fix real CLI terminal output plus before/after focused test output for this non-visual parser behavior.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix real CLI terminal output plus before/after focused test output for this non-visual parser behavior.
Evidence reviewed

PR surface:

Source +212, Tests +296. Total +508 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 2 214 2 +212
Tests 3 300 4 +296
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 514 6 +508

What I checked:

Likely related people:

  • Pandah97: Authored the merged lazy-reparse usage-error fix that changed src/cli/program/action-reparse.ts shortly before this PR and is directly adjacent to the conflict. (role: recent lazy-reparse contributor; confidence: high; commits: a4b8ead21d25, 68e234f9e24a; files: src/cli/program/action-reparse.ts, src/cli/program/action-reparse.test.ts)
  • vincentkoc: Authored follow-up nested lazy reparse tests in the merged related PR, including coverage this PR must preserve during conflict resolution. (role: adjacent test contributor; confidence: high; commits: 4b42087ed437, b2199b090838, 68e234f9e24a; files: src/cli/program/action-reparse.test.ts)
  • ooiuuii: Authored the closest sibling fix for accepting trailing root --log-level after subcommands, which is the parser-normalization pattern this PR extends. (role: adjacent CLI option-normalization contributor; confidence: medium; commits: b6d3aa57190a, 042ebb4f75f3; files: src/cli/argv.ts, src/cli/argv.test.ts)
  • gumadeiras: Authored the merged descriptor-backed lazy root command registration work, the broader CLI lazy-loading surface this PR extends. (role: lazy CLI registration feature contributor; confidence: medium; commits: 1b892ee02a28, 9b4f26e70af0; files: src/cli/program/register-command-groups.ts, src/cli/program/register-lazy-command.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-24T07:10:04.504Z sha 83bf422 :: found issues before merge. :: [P2] Preserve the full nested fallback path

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jun 20, 2026
@ml12580

ml12580 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Pushed commit 83bf422 addressing the P2 finding ("Preserve missing parent option errors" at src/cli/program/helpers.ts:172): a bare parent value option with no following value is no longer hoisted alone, so Commander's missing-value error is preserved instead of the next token being swallowed as the option value. Added 3 helpers.test.ts + 2 browser-cli.lazy.test.ts regression cases for the missing-value paths; focused lazy CLI tests, oxlint on touched files, and git diff --check all pass. PR body updated with the missing-value after-fix evidence.

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@steipete steipete self-assigned this Jul 7, 2026
@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Maintainer verification complete; thanks @ml12580 for the original fix and reproduction.

What changed in the maintainer rewrite:

  • reduced the original 514-line patch to a focused 3-file parser/test change;
  • normalized at the existing lazy reparse boundary;
  • preserved options owned by the selected child command while ignoring collisions on unselected siblings;
  • handled ancestor option values, nested commands, aliases, missing values, and -- without browser-specific production literals.

How I tested it:

  • Blacksmith Testbox tbx_01kwxpxmb3x1g1prnaa9cs4230: 32 core lazy-reparse tests passed.
  • Same Testbox: 26 browser lazy/extension/collision tests passed.
  • pnpm check:changed for the touched surface passed strict types, lint, docs, import-cycle, and repository guards.
  • Full pnpm build passed, including CLI bootstrap/import guards and runtime postbuild.
  • Built-CLI black-box contract passed 7/7 clauses: parent-before and parent-after orders produced the same result; nested ordering worked; selected-child collision, sibling collision, --, and missing-value behavior were preserved.
  • Fresh structured autoreview: clean, no actionable findings.
  • Exact PR head abb859ee23f9ec6300a49a3be5709f183df0438d: full CI passed in run https://github.com/openclaw/openclaw/actions/runs/28852795527.

The tempting one-line enablePositionalOptions(false) change was directly rejected because Commander 15 makes the parent steal valid leaf flags such as browser extension pair --json and cookie --url. The final change restores the shipped syntax without that functionality regression.

@steipete
steipete merged commit c1f9087 into openclaw:main Jul 7, 2026
106 of 107 checks passed
@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 8, 2026
…aw#55563 regression 1) [AI-assisted] (openclaw#94431)

* fix(cli): restore lazy parent option ordering

Co-authored-by: ml12580 <[email protected]>

* chore: defer release-owned changelog entry

---------

Co-authored-by: Peter Steinberger <[email protected]>
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…aw#55563 regression 1) [AI-assisted] (openclaw#94431)

* fix(cli): restore lazy parent option ordering

Co-authored-by: ml12580 <[email protected]>

* chore: defer release-owned changelog entry

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: M status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants