feat(plugin): plugin management commands (promoted from beta)#426
Draft
feat(plugin): plugin management commands (promoted from beta)#426
Conversation
Implements CLI commands for the full plugin API surface under `cy beta plugin`: - `cy beta plugin list/get/install/uninstall/upgrade/logs` — manage plugin installs (upgrade has alias: update; --version-id required; --config key=val / --config-file) - `cy beta plugin manager list/get/create/accept/reject/delete` — manage plugin managers (PluginManager agents with invite flow: accept/reject pending invites) - `cy beta plugin registry list/get/add/delete` — manage plugin registries - `cy beta plugin registry plugin list/get/create/delete` — plugins within a registry - `cy beta plugin registry plugin version list/get/publish/delete/install/logs/retry` All commands support dual-form completion (name OR numeric ID). Resolvers handle ambiguity: error message lists conflicting IDs and asks for a numeric ID. Also adds: - 19 plugin model files (copied from backend gen/models) - middleware interface + implementation (plugins.go) - cyargs helpers: AddPluginConfigFlags, GetPluginConfig, Complete*/Resolve* for all entities - Makefile: prune generated client dir after swagger codegen, keep only models Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
xescugc
previously approved these changes
Apr 9, 2026
Three plugin commands defined --url inline without going through cyargs. Consolidate into AddURLFlag/GetURL in cyargs/plugins.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ion publish, and pipeline log commands CLI-113: cy beta plugin install now accepts --version-id (optional) to pin a specific plugin version at install time. cy beta plugin registry plugin version publish now accepts --docker-image as a mutually exclusive alternative to --url, allowing Docker image references (scheme-less URIs) to be published without strfmt.URI validation issues. Refactored upgrade.go to use the shared cyargs.AddPluginVersionIDFlag helper. CLI-114: Added cy pipeline builds logs (dump or --watch a build by ID) and cy pipeline job logs (latest build logs, --watch tails future builds with --poll-interval). Both commands reuse the existing buildwatch SSE streaming and formatting infrastructure via a new StreamLogs function with ReadOnly=true and an idle-timeout reader for dump mode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…WithOptions
Migrates 13 key resource command files (list + get) to use the new
cyout.PrintWithOptions helper with curated table column defaults:
- projects: Canonical, Name, Owner.Username (dot-notation)
- apikey: Canonical, Name, LastSeven, LastUsed
- roles: Canonical, Name, Description, Default
- catalogrepositories: Canonical, Name, URL, Branch, StackCount
- configrepositories: Canonical, Name, URL, Branch, Default
- builds: ID, Name, Status, JobName, StartTime
- credentials: Canonical, Name, Type, Path, Keys (Raw field excluded)
- environments: Canonical, Name
- members: Username, Email, GivenName, FamilyName
- pipelines: Name, Status, Paused, Project, Environment, Component (Transform)
- jobs: Name, Paused, PipelineName, CurrentBuildID (Transform)
- teams: Canonical, Name, MemberCount, Roles (Transform, join role names)
- components: Canonical, Name, Description, StackRef, UseCase, Version (Transform)
Also:
- Fixes table printer to handle []interface{} slices (interface unwrapping)
- Removes force-JSON hacks in multi-arg get commands (now typed slices)
- Adds cyout.RegisterModel to all list/get commands for --output completion
- Fixes pre-existing lint issues (misspell, staticcheck, unconvert)
- Updates tests to match new lipgloss table output format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ands - projects get: accept multiple canonicals; loop returns []*models.Project - roles get: accept multiple canonicals via positional args; --role flag keeps precedence - credentials get: accept multiple canonicals when no --canonical/--path flags set - environments get/delete: accept env canonicals as positional args; --env as fallback - components get/delete: accept component canonicals as positional args; --component as fallback - organizations get/delete/list: accept org canonicals as positional args; migrate to cyout - members get/delete: accept numeric member IDs as positional args; --id as fallback All delete commands migrated from factory.GetPrinter+SmartPrint to cyout.Print. Also includes goimports formatting fixes across unrelated files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all remaining factory.GetPrinter + printer.SmartPrint boilerplate with
cyout.PrintWithOptions / cyout.Print across:
- projects, credentials (create/update/delete/list-env)
- teams (all), roles (all)
- environments, components, stacks (non-list/get)
- organizations, configrepositories, catalogrepositories
- apikey, events, members (invite/update/list-invites)
- externalbackends, login, terracost, status, version
- beta/config, beta/plugins (all subcommands)
- pipelines (pause/unpause/diff/update/clear-task-cache/build-trigger/etc.)
Also removes all "if output == 'table' { output = 'json' }" workarounds
(now handled uniformly by the new table printer and cyout).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s non-struct slices - cyout.PrintWithOptions: use cmd.ErrOrStderr() for error output instead of cmd.OutOrStderr(). OutOrStderr falls back to cmd.outWriter which points to stdout in tests that call SetOut — causing error JSON to land on stdout. ErrOrStderr correctly uses the dedicated errWriter set by SetErr. - printer/table: guard headersFromStruct against non-struct values (strings, ints). Returns nil when v.Kind() != Struct; Print() exits early with no output. Fixes panic when deleteProject returns []string of deleted canonicals. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…iption to project list - BorderHeader(false): with HiddenBorder, the header separator renders as a line of spaces causing a blank line. Disabling it removes the gap entirely. - projectTableOptions: add Description column (Canonical, Name, Description, Owner.Username). Component already had Description in its default columns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hidden-border with NormalBorder (all sides off except header separator) to render a dim ─ line between header and data rows. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds 2-space right padding per cell so columns don't run together when column borders are disabled. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLAUDE.md: update command pattern to cyout.PrintWithOptions, add cyout package description, fix Hard Rule 6 - docs/architecture.md: update request lifecycle, add --output system section (grammar, field extraction, shell completion, cyout helper) - docs/adding-a-command.md: update get.go example to use cyout pattern with RegisterModel and PrintWithOptions - changelog: extend positional-args entry to cover environments, components, organizations, members, roles, credentials; add new output-format entry for table=cols/jq=/field extraction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--jq <expr> is sugar for --output jq=<expr>. GetOutput() checks the --jq flag first; if set, it returns "jq="+expr, bypassing --output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sistent default
- Default table uses kubectl-style `─` header separator with `#` row index column
- New `table:border` option enables nushell-style rounded-border grid (╭─┬─╮)
- New `table:noindex` option suppresses the `#` row index column
- On wide terminals, extra struct fields are shown beyond curated defaults;
as terminal narrows, extra columns are dropped first while curated columns survive
- Nested structs render as `{record N fields}` instead of the type name
- Numeric types (int, int32, float32, float64) render as formatted values
- New `cy output set/get/reset` commands persist the default output format
to ~/.config/cycloid-cli/config.yaml
- Priority chain: --jq > --output > CY_OUTPUT > cy output set > "table"
- Delete commands now use Columns: []string{"Canonical"} for clean table output
- Added e2e tests for delete table output and bulk delete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The # index column was purely cosmetic and not usable for filtering or referencing resources, which could mislead users into trying commands like `cy plugin get 0`. https://claude.ai/code/session_01NkqEDktWxTPxXBtjET5iZK
…nics
Audit of the entire output system (table, field, jq printers) uncovered
multiple crash paths when the table printer receives nil pointers, slices
containing nil elements, or unexpected types. These occur in production
when the API returns null objects or partial data.
Fixes:
- Print() now returns early for nil interface and typed nil pointers
- build() guards nil pointer before calling Elem()
- Slice iteration skips nil elements gracefully (empty row)
- expandColumns() nil-safe pointer/interface unwrap loops
- renderValue() handles invalid Value, nil slices, maps, interfaces
- headersFromStruct() guards invalid Value
- entryFromStruct() guards invalid Value
- Maps now render as "{N entries}" instead of "map"
Adds firstNonNilElem() and derefValue() helpers. 18 new test cases
covering every crash path found during audit.
https://claude.ai/code/session_01NkqEDktWxTPxXBtjET5iZK
Replace the broken path where API errors were rendered as table rows. Errors now bypass the output printer entirely and are formatted as a human-readable block on stderr regardless of --output flag. API errors show: - Status code, HTTP method, and request path - Sanitized request body (credentials and secrets redacted to [REDACTED]) - Structured error payload: [Code] message with sub-detail lines - Request-ID from the backend payload (for support/debugging copy-paste) - Fallback to raw response body when no structured payload is available Local errors (missing flags, bad args) show the command invocation hint (command path + set flags) before the Error: summary line. New sanitizeBody() in middleware recursively redacts sensitive JSON keys: ssh_key, password, secret_key, access_key, client_secret, json_key, token, ca_cert, raw, current — covering all credential and auth models. Co-Authored-By: Claude Sonnet 4.6 <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.
Summary
Full `cy plugin` command tree covering the entire plugin API surface. Commands were developed under `cy beta plugin` and are now promoted to top-level — the feature is in production.
Plugin installs (`cy plugin …`)
Plugin managers (`cy plugin manager …`)
Plugin registries (`cy plugin registry …`)
Registry plugins (`cy plugin registry plugin …`)
Plugin versions (`cy plugin registry plugin version …`)
Plugin widgets (`cy plugin widget …`) (new)
Component plugins (`cy plugin component …`) (new)
Component plugin widgets (`cy plugin component widget …`) (new)
Key design decisions
API drift fixed (vs original PR baseline)
Test plan
🤖 Generated with Claude Code