feat(RHIDP-14129): add intent-based CLI commands and backstage-cli pass-through - #156
feat(RHIDP-14129): add intent-based CLI commands and backstage-cli pass-through#156yangcao77 wants to merge 10 commits into
Conversation
…tions related will use backstage-cli Signed-off-by: Stephanie <yangcao@redhat.com>
…nto intent-based-cli
Signed-off-by: Stephanie <yangcao@redhat.com>
- Statically import command modules in commands/index.ts instead of using require(), since the backstage-cli bundler only follows static ESM imports/dynamic import() and silently dropped the require()'d files from the packed dist, breaking every command once installed from npm (Cannot find module './backstage-passthrough'). - Fix TS2352 in intent-errors.ts by adding a safe getStderr() helper instead of casting Error directly to Record<string, unknown>. - Restrict the PATH used to resolve backstage-cli via `which` to directories that aren't group/other-writable, addressing the SonarCloud S4036 PATH-search security hotspot in lib/client.ts. - Extract shared runEntityListAction/runRawAction/runSearchAction helpers and a registerPassthroughCommand helper to remove the heavy code duplication SonarCloud flagged across catalog/api/template/ search/docs/backstage-passthrough command files. - Fix pre-existing lint (no-empty, func-names) and prettier issues so the Checks job can get past the linter/prettier steps. Co-authored-by: Cursor <cursoragent@cursor.com>
…ctory Move catalog/api/search/docs/template/backstage-passthrough and their supporting client/format/intent-errors/helpers modules into src/commands/intent-based-actions/, mirroring the existing export-dynamic-plugin/ and package-dynamic-plugins/ layout, with a single registerIntentCommands() entry point. Co-authored-by: Cursor <cursoragent@cursor.com>
SonarCloud S4036 still flagged spawnSync('which', ...) even with a restricted PATH env, since it pattern-matches on shelling out to a path-search utility rather than analyzing the PATH value. Replace it with a direct filesystem walk over PATH entries (skipping group/other-writable directories) and an accessSync executability check, avoiding the flagged pattern entirely.
Co-authored-by: Cursor <cursoragent@cursor.com>
kadel
left a comment
There was a problem hiding this comment.
Two concerns about how backstage-cli is resolved and surfaced.
Resolution: findBackstageCliOnPath walks system PATH looking for a backstage-cli binary, but backstage-cli is not something people typically install as a standalone global binary, so the PATH walk is unlikely to find it. This means the npx -y @backstage/cli fallback is effectively the default path. This fallback silently downloads whatever latest is on npm without user confirmation. rhdh-cli is built against 0.36.3, so the downloaded version could behave differently, and -y suppresses the install prompt. This is a supply chain concern for a CLI meant for production use.
@backstage/cli is already a declared dependency of this project at 0.36.3. Could we resolve the binary from the installed dependency instead of walking PATH or downloading via npx?
Leaking backstage-cli identity: The passthrough commands expose backstage-cli's own output directly. Commander intercepts --help before it reaches backstage-cli, so passthrough commands show empty help with no options. But backstage-cli itself has useful help that's being hidden. Compare:
rhdh-cli auth login --help:
Usage: rhdh-cli auth login [options]
Log in to a Backstage/RHDH instance
Options:
-h, --help display help for command
backstage-cli auth login --help:
Usage:
backstage-cli auth login [flags...]
Flags:
--backend-url <string> Backend base URL
-h, --help Show help
--instance <string> Name for this instance
--no-browser Do not open browser automatically
rhdh-cli actions execute --help:
Usage: rhdh-cli actions execute [options]
Execute an action
Options:
-h, --help display help for command
backstage-cli actions execute --help:
Usage:
backstage-cli actions execute [flags...] <action-id>
Flags:
-h, --help Show help
--instance <string> Name of the instance to use
The rhdh-cli versions hide --backend-url, --no-browser, --instance, and the <action-id> positional argument. Running without --help (e.g., rhdh-cli actions execute with no args) does forward to backstage-cli but then shows backstage-cli branding instead of rhdh-cli.
For human users this is confusing. For AI agents discovering the CLI through --help, it's a blocker since they see no options and can't tell which CLI to use.
|
Thanks for the review! Fixed both: Resolution: |
Signed-off-by: Stephanie <yangcao@redhat.com>
f58172c to
a504d15
Compare
kadel
left a comment
There was a problem hiding this comment.
Do we need the intent-based commands (template, catalog, api, search, docs) in this PR, or should they be a follow-up?
Every intent-based command maps 1:1 to actions execute — for example, rhdh-cli template list is just rhdh-cli actions execute catalog:query-catalog-entities --query '{"kind":"Template"}'. The passthrough layer (auth, actions) already gives users and agents full access to the same functionality.
The intent-based commands add ~1,000 lines with no tests, and one of them (template dry-run) already has a bug where it passes an entity ref as templateYaml instead of actual YAML content. The impact is low — the command just fails with an error, it can't cause any damage — but it shows the risk of shipping this much code without test coverage.
If we want to keep those extra commands they need test coverage
Would it make sense to merge just the passthrough commands (auth, actions, actions sources) first — they're solid and already working — and add the intent-based layer in a follow-up with proper test coverage? The repo already has a Jest setup in src/lib/*.test.ts, and most of the new code (formatting, error handling, entity extraction) is pure functions that are straightforward to test.
Signed-off-by: Stephanie <yangcao@redhat.com>
|
@kadel On whether we need the intent-based commands in this PR: yes, they're the actual point of this story https://redhat.atlassian.net/browse/RHIDP-14129. The goal is that users and agents should never need to know internal action names or the I agree the test coverage is needed, I initially did not add any as I didn't see any tests coverage for all other cmds in this repo. I've add some unit tests as part of the PR, the integration tests I have created it as a QE item. https://redhat.atlassian.net/browse/RHIDP-14254 |
I don't think that for agentic use this matters that much. The original backstage cli commands are well designed for AI use. If the goal for new commands is mainly human usage, then we need to think a little bit harder about how they look like and what arguments they expose. For example expecting humans to type JSON strings in terminal as arguments for CLI command is bad UX. Agents can deal with it, but people can't. Even simple tasks like searching only in Components I have to type JSON something like this would be much better cli experience: In the template execution it can also get quite complicated. More natural CLI experience should be something like this. The errors are currently also not presented in a user-friendly way Another usability problem for human use is that there is no way to easily list what parameters a template requires. The only way to do it is using following command. Which forces people to parse JSON. (without pre-filtering it with command outputWhen testing this I also found bug in in json output it is fine To summarize this: |
Signed-off-by: Stephanie <yangcao@redhat.com>
Signed-off-by: Stephanie <yangcao@redhat.com>
|
|
@kadel so I pushed a new commit for your suggested UX improvement on the input format, so they no longer require raw JSON: here is the summary: Summary1.
|
|
@kadel Re showing the template params and also the user-friendly error, as long as the bug https://redhat.atlassian.net/browse/RHDHBUGS-3698 you created. I would like to use follow up PR to address those issue. here is a analysis from claude Problem A — No easy way to see a template's inputsToday the only way to discover what i.e. fetch the whole entity and hand-parse nested JSON. What to build: a new read-only subcommand, e.g.
Decision needed: command name ( Problem B — Validation errors are an unreadable JSON dump
What to build: parse that payload into a friendly message.
How they connectThey pair naturally: the friendly error in B points the user at the command from A. Build A first so B can reference Effort / risk / sequencing
PR recommendation: clean second PR — also satisfies "split into multiple PRs" point |
|
@kadel PTAL |



https://redhat.atlassian.net/browse/RHIDP-14129
Adds intent-based subcommands and backstage-cli pass-through commands to rhdh-cli
Today, interacting with a running RHDH/Backstage instance from the CLI requires
backstage-cli actions execute <pluginId>:<actionName>with internal action IDs and raw JSON input. This is very bad experience for human operations.This change makes rhdh-cli the single entry point:
All intent-based commands support
--output jsonfor agent consumption and--instance <name>for multi-instance targeting.The local metadata file is still going to use the config file for
backstage-cli, so that existing backstage-cli user can migrate to userhdh-cliwith no extra effortsee recording:
rhdh-cli.mov