feat(cli): schema-aware sticky flag splitting and structured unknown-flag recovery (#272)
* chore: update coverage badge [skip ci] * chore: update coverage badge [skip ci] * chore: update coverage badge [skip ci] * chore: update coverage badge [skip ci] * chore: update coverage badge [skip ci] * 1.0.19 changelog * stick opt * fix(cli): utf-8 safe sticky suffix guard + changelog (#272) SuffixLooksLikeValue used to read suffix[0] (a single byte) for both the uuid format branch and the fallback "is the first rune a letter?" check. For multi-byte UTF-8 leading runes — common in dws because value text is often Chinese — this picked up only the first byte (0xE0..0xF4 lead), which is not a letter and not a hex digit, so the function silently returned true and let glued tokens like --name<CJK> get split into --name <CJK>... This switches both branches to utf8.DecodeRuneInString and adds a utf8.RuneError guard so invalid UTF-8 input is rejected too. Also locks down the new behaviour in CHANGELOG ## [Unreleased]: - Changed: schema-aware sticky flag splitting - Added: available_flags field on unknown-flag errors Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
16 files changed
+982
-82
No files matched your search
+25
-10
@@ -79,6 +79,12 @@ func RunPreParse(root *cobra.Command, engine *Engine) {
|
||||
|
||||
// FlagInfoFromCommand extracts FlagInfo entries from a Cobra
|
||||
// command's registered flags (both local and inherited).
|
||||
//
|
||||
// JSON Schema "format" and "enum" hints injected via pflag
|
||||
// annotations (x-cli-format / x-cli-enum, see
|
||||
// internal/compat/dynamic_commands.go) are surfaced on FlagInfo
|
||||
// so PreParse handlers can validate sticky-split candidates against
|
||||
// the actual schema, not just the pflag type.
|
||||
func FlagInfoFromCommand(cmd *cobra.Command) []FlagInfo {
|
||||
if cmd == nil {
|
||||
return nil
|
||||
@@ -92,11 +98,7 @@ func FlagInfoFromCommand(cmd *cobra.Command) []FlagInfo {
|
||||
return
|
||||
}
|
||||
seen[f.Name] = true
|
||||
infos = append(infos, FlagInfo{
|
||||
Name: f.Name,
|
||||
PropertyName: f.Name,
|
||||
Type: f.Value.Type(),
|
||||
})
|
||||
infos = append(infos, flagInfoFromPflag(f))
|
||||
})
|
||||
|
||||
cmd.InheritedFlags().VisitAll(func(f *pflag.Flag) {
|
||||
@@ -104,12 +106,25 @@ func FlagInfoFromCommand(cmd *cobra.Command) []FlagInfo {
|
||||
return
|
||||
}
|
||||
seen[f.Name] = true
|
||||
infos = append(infos, FlagInfo{
|
||||
Name: f.Name,
|
||||
PropertyName: f.Name,
|
||||
Type: f.Value.Type(),
|
||||
})
|
||||
infos = append(infos, flagInfoFromPflag(f))
|
||||
})
|
||||
|
||||
return infos
|
||||
}
|
||||
|
||||
// flagInfoFromPflag builds a FlagInfo from a pflag.Flag, copying
|
||||
// schema metadata stashed in the flag's annotations map.
|
||||
func flagInfoFromPflag(f *pflag.Flag) FlagInfo {
|
||||
fi := FlagInfo{
|
||||
Name: f.Name,
|
||||
PropertyName: f.Name,
|
||||
Type: f.Value.Type(),
|
||||
}
|
||||
if v := f.Annotations["x-cli-format"]; len(v) > 0 {
|
||||
fi.Format = v[0]
|
||||
}
|
||||
if v := f.Annotations["x-cli-enum"]; len(v) > 0 {
|
||||
fi.Enum = append([]string{}, v...)
|
||||
}
|
||||
return fi
|
||||
}
|
||||
Reference in new issue
Block a user