Repository navigation
Phase 3 follow-up: realm picker + pickable-option help annotations - #785
Merged
Merged
Conversation
Completes the last two Phase 3 items of the interactive-commands plan. Realm picker: after successful auth, a command whose realm argument was left at its default offers a dropdown of the target system's realms -- only when prompting is allowed, the command declares a realm argument, the user did not name one (provenance captured pre-auth, since frodo-lib maps the __default__realm__ sentinel to the deployment type's realm during auth), and the system has more than one realm. Everything else is a no-op; escape keeps the default. The picker and `frodo realm list` share a memoized readRealmsCached() in RealmOps so the realms endpoint is fetched once per invocation (keeps Polly's order-matched e2e replay intact and halves latency). Help annotations: FrodoStubHelp renders "(pick from <kind>)" on options with a registered entity picker, so interactive users can see which options will offer a live dropdown. 25 client_cli help snapshots updated (annotation-only diffs). Layering: the active-command registry lives in zero-import ActiveActionCommandState (PromptGateState pattern) and the picker machinery is lazy-imported behind canPrompt(), so AuthenticateOps stays loadable in tests that mock frodo-lib wholesale. Co-Authored-By: Claude Code <noreply@anthropic.com>
The Phase 1b bare-stub sub-command picker replaces commander's parseOptions wholesale, so `frodo -v` and `frodo -h` (and the -hh/-hhh help levels) on a TTY showed the picker instead of their own output -- the interception never reached the option events that make commander print and exit. `frodo --no-prompt` was likewise swallowed, defeating the flag's meaning before any leaf preAction could honor it. The interception now falls through to commander's own parse whenever unknown argv carries one of those tokens (BARE_PICKER_BLOCKING_OPTION_ TOKENS); pass-down options (--verbose, --debug, ...) keep the picker and re-parse in the picked sub-command's context as designed. Regression tests: test/unit/bare-stub-root-flags.pty.test.js via the ShellPty PTY harness with a new allowPrompting opt-in (blanks FRODO_TEST explicitly -- the driver merges the runner's environment under the scenario env, so an omitted key would leak the runner's value). Verified to fail against the pre-fix build and pass against the fixed one. Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 follow-up: realm picker + pickable-option help annotations
Completes the last two Phase 3 items from the interactive-commands plan (builds on #784).
Realm picker
After a successful login, a command whose realm argument was left at its default offers a dropdown of the target system's realms — but only when it makes sense to:
canPrompt()— never inFRODO_TEST/CI or non-TTY runs),[realm]positional argument,FRODO_REALM), andEvery other path is a no-op, so non-interactive behavior is byte-identical to before. Escape declines the offer and keeps the deployment-type default (unlike entity pickers, there is no "wrong" continuation to protect — the default is a valid choice). A failed realm listing is swallowed and the default kept.
The two subtle parts:
__default__realm__sentinel to the deployment type's realm (alpha//) during_getTokens, so after auth a user choice and a mapped default are indistinguishable.noteRealmProvenance()therefore runs in the resolution pass before auth; the picker consults it post-auth.frodo realm listnow share a memoizedreadRealmsCached()inRealmOps— without it, the picker's extra read broke Polly's order-matched replay in existing e2e recordings (they hold one entry for the endpoint) and doubled latency.Wiring is global: the
getTokenswrapper fires the pick for every command; commands that bypass the resolution pass (login/conn stub actions) naturally never see it.Help annotation for pickable options
FrodoStubHelpnow renders(pick from <kind>)on options with a registered entity picker, e.g.:so interactive users can see which options will offer a live dropdown before running the command. The 25 affected client_cli help snapshots are updated (annotation-only diffs, verified).
Layering note
The picker's post-auth hook needs the active command, but
ops/importingcli/ResolveInteractiveInputsdirectly would drag the resolution pass'sgraph (the frodo-lib-importing interactive prompts) into tests that mock
frodo-lib wholesale. The active-command registry therefore lives in its own
zero-import module (
ActiveActionCommandState, same split asPromptGateState), and the picker machinery is lazy-imported in thegetTokenswrapper behindcanPrompt()— non-interactive sessions neverload it.
Tests
RealmPickers.test.ts(new): pins the non-interactive preservation contract — underFRODO_TEST=1, without a realm argument, with a user-specified realm, or without provenance noted,resolveRealmPickis a strict no-op (no read, no write).🤖 Generated with Claude Code