fix(app): five UX papercuts in app list / app view discovery - #179
Merged
Conversation
A blind dogfood of the new App-discovery commands surfaced five papercuts:
1. Top-level help hid app-browsing. The `app` group's Short was authoring-only,
so `civitai --help` never advertised `app list` / `app view`. Short is now
"Browse, author, and ship Civitai Apps"; the group Long + the root Examples
surface `civitai app list` / `civitai app view <slug>`.
2. Broken help example. `app list`'s Example used `--category productivity`, an
invalid enum that 400s. Replaced with `--category generation`, and the
--category flag help now lists the valid marketplace categories.
3. `app view` printed `rating:` twice. The content-rating line reused the
`rating:` label; it is now `content:`.
4. Enum flags gave an unhelpful generic 400. The SDK's badRequestDetail now
parses zod's FLATTENED error shape ({formErrors, fieldErrors}) — what the
store endpoint returns — and surfaces the field-specific message (naming the
bad field + constraint), instead of the bare "invalid request parameter
(400)". Additionally, the FIXED enums --kind/--sort are validated
client-side (fast, offline, allowed-values message); --category is left to
the improved 400 handling so its allowlist can't drift from the backend.
5. Empty list gave a bare header. `app list` with zero items now prints a hint
explaining the mod/tester gating (matching the --help wording) + the filters.
Tests: server-400 field-error surfacing (cmd + SDK unit), local enum
validation (no HTTP), content: label / no double rating:, empty-list hint, and
regression guards on the Short/root Examples + the invalid-category example.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Why
A blind dogfood of the new App-discovery commands (
civitai app list/app view, added in #178) surfaced five UX papercuts. This PR fixes all five, with tests.The five papercuts & fixes
1. (biggest) Top-level help hid app-browsing. The
appgroup'sShortwas authoring-only ("Author and ship Civitai Apps"), so a user who wanted to browse the store never learnedapp list/app viewexisted fromcivitai --help.Short→Browse, author, and ship Civitai Apps; the groupLongnow opens with the browse commands.root.go) socivitai --helpsurfacescivitai app list/civitai app view <slug>.2. Broken help example.
app list's Example used--category productivity— not a valid category, returns HTTP 400.--category generation(a real category).--categoryflag help now lists the valid set (generation, games, utility, discovery, moderation, analytics, other), mirroring the backendMARKETPLACE_CATEGORIESenum.3.
app viewprintedrating:twice. Both the star rating and the content rating were labeledrating:(rating: - (0 review(s))thenrating: content g).content:→content: g.4. Enum flags 400'd with an unhelpful generic message. A bad
--kind/--sort/--categoryround-tripped to a bareinvalid request parameter (400).{"error":{"formErrors":[...],"fieldErrors":{"<field>":["<msg>"]}}}, which the SDK'sbadRequestDetaildidn't parse. AddedflattenedZodDetailso a 400 now surfaces the field-specific message (naming the bad field + constraint) — e.g.invalid request parameter (400): category — Invalid enum value. Expected 'generation' | 'games', received 'productivity'. This stays in sync with the backend enum (no client-side drift). fieldErrors is decoded in document order so the reported field is deterministic.--kind(all/onsite/offsite) and--sort(top-rated/popular/newest/name) are validated locally for a fast, offline allowed-values error — no HTTP call.--categoryis deliberately not hardcoded client-side (its allowlist grows as the backend adds categories); it relies on the improved 400 handling above.--limit's existing local validation is unchanged.5. Empty list gave a bare header. For a non-mod user (the common case — the catalog is identity/flag-gated)
app listprinted only the table header, unexplained.--helpgating wording:No apps visible for your account — until the store opens publicly you only see apps if your account is a moderator or app-dev-tester, or nothing matches your filters.+ a login/relax-filters follow-up.Tests
fieldErrors400 → the command prints the field-specific message (cmd-level), plus an SDK unit test onreadErrorfor bothfieldErrorsandformErrors-only bodies.--kind/--sortfails locally (asserts no HTTP call) with the allowed-values message.viewoutput containscontent:and printsrating:exactly once.items→ the hint line is printed (incl. the mod/tester wording).app/root help advertise browsing; thelisthelp Example does not contain--category productivityand does use a valid category + lists the enum.Verification
go build ./... && go vet ./... && go test ./...all green (16 packages ok);gofmt -l pkg/civitai internal/cmdclean. Built the binary and eyeballedapp --help,app list --help, andapp view(showscontent: g, not a secondrating:).🤖 Generated with Claude Code