cli: let flags be written anywhere on the line - #11
Merged
Conversation
dwshell dispatched on os.Args[1], so a flag could only follow its subcommand. `dwshell --config x list` did not complain — it took "list" for a machine name and tried to connect to it, which is worse than an error, and `dwshell --json list` failed with a puzzling "flag provided but not defined". Arguments are now partitioned into flags and positionals before anything is dispatched, so the command is the first positional wherever it sits. `dwshell list --account a@b` and `dwshell --account a@b list` are the same command, and the same holds inside `account <verb>` and for the shell shortcut. Telling a flag's value from a positional needs to know which flags consume a following token, and that registry is the hazard: a value flag missing from it makes dwshell take the value for a command name and quietly do the wrong thing. So a test walks the package's own source with go/ast and holds the registry to the flags actually registered, in both directions. It earned its place immediately, catching two stale entries I had added from memory, and it found a real gap: --user was absent, harmless only because login is dispatched by name. Everything after a bare -- is positional, so an agent or path beginning with a dash can still be passed. Verified live: the reported case, both orders of every flag, a flag between two positionals, the shell shortcut with the flag on either side, the explicit `shell <name>` form for a machine named like a command, help, version, -- and an unknown flag still failing loudly. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01MvidAFW9a2r4hTgHPW9ywG
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.
Replaces #10, which GitHub closed automatically when its base branch was deleted on merge. Same work, retargeted to
mainand integrated with everything that landed since.Answers "can't flags be position-independent?" — yes, everywhere, not just before the subcommand.
What was wrong
dwshell dispatched on
os.Args[1], so a flag could only follow its subcommand. The failure mode was not an error:The first is the bad one: it did not complain, it quietly did something else.
What it does now
Arguments are partitioned into flags and positionals before anything is dispatched, so the command is the first positional wherever it sits — at the top level and inside both
account <verb>andagent <verb>. Everything after a bare--is positional, so an agent or path starting with a dash can still be passed.The hazard, and the guard
Telling a flag's value from a positional requires knowing which flags consume a following token, and that registry is the risk: a value flag missing from it makes dwshell take the value for a command name and quietly do the wrong thing.
TestValueFlagsMatchesTheFlagsActuallyRegisteredwalks the package's own source withgo/astand holds the registry to what is actually registered, in both directions. It has already earned its place three times:--userwas missing, harmless only becauseloginis dispatched by name;--descriptionand--group, the agent flags, which would otherwise have been silently wrong.Integration with agent management
Merging the two feature branches needed real work, not just conflict resolution:
--accountadded to everyagentsubcommand, and threaded throughagentSessionextractPositionalandconfirmhelpers, defined independently on both branches, reduced to onecmdAgentManagestill dispatched onargs[0], sodwshell agent --account … group …answeredunknown agent subcommand "--account". Caught by live testing after the build was already green — the same fixcmdAccounthad.Verification
Live, against a copy of a real configuration, with all four features together:
--account … agent create … --jsonagent --account … group … <bad group>agent rm … --yes --account …--account … GHE -c "uname -s"Linux--json list,list --jsonshell listfor a machine named like a command--,help,version, unknown flaggofmt,go vet,go test -race ./...green.🤖 Generated with Claude Code
https://claude.ai/code/session_01MvidAFW9a2r4hTgHPW9ywG