Summary
Every dcd live subcommand (start, status, install, exec, stop) prints the generic "Live Session Commands" menu after its own output. The menu is the parent liveCommand.run() body leaking into successful subcommand invocations.
Reproduction
$ dcd live status --session bouncy-green-hawk --api-url https://api.dev.devicecloud.dev
Live Session
────────────────────────────────────────────────
Session: bouncy-green-hawk
Platform: android
Status: RUNNING
Created: 6/16/2026, 10:57:30 AM
Live Session Commands <-- spurious, should not be here
────────────────────────────────────────────────
start Start a new live device session
install Install a binary on the device
exec Execute Maestro YAML commands
stop Stop a live session
status Get session status
Run dcd live <command> --help for details
Same trailing menu appears after live start and live install (verified on dev).
Root cause
citty's runCommand does not early-return after dispatching to a subcommand — after running the matched subcommand it falls through and also invokes the parent command's run if one is defined:
// node_modules/citty/dist/index.mjs (runCommand)
if (subCommand) { await runCommand(subCommand, {...}); }
...
if (typeof cmd.run === "function") { result = await cmd.run(context); } // parent run still fires
liveCommand (src/commands/live.ts) defines both subCommands and a run() that prints the menu, so the menu prints on every subcommand. The top-level main command is unaffected because it has no run.
Suggested fix
Have liveCommand.run() only print the menu when no subcommand was matched — e.g. detect whether the first positional in rawArgs/ctx.args._ is one of the subcommand names and return early otherwise. (Alternatively restructure so the menu lives in a default sub-command.)
Side note (low priority)
dcd live exec wraps server errors as Failed to execute test failed: <message> — the doubled "test failed" reads awkwardly (e.g. Failed to execute test failed: Session not ready (HTTP 425)). Worth tidying the error-prefix wording while in this area.
Found during a full feature sweep of v5.0.0 against the dev environment.
Summary
Every
dcd livesubcommand (start,status,install,exec,stop) prints the generic "Live Session Commands" menu after its own output. The menu is the parentliveCommand.run()body leaking into successful subcommand invocations.Reproduction
Same trailing menu appears after
live startandlive install(verified on dev).Root cause
citty's
runCommanddoes not early-return after dispatching to a subcommand — after running the matched subcommand it falls through and also invokes the parent command'srunif one is defined:liveCommand(src/commands/live.ts) defines bothsubCommandsand arun()that prints the menu, so the menu prints on every subcommand. The top-levelmaincommand is unaffected because it has norun.Suggested fix
Have
liveCommand.run()only print the menu when no subcommand was matched — e.g. detect whether the first positional inrawArgs/ctx.args._is one of the subcommand names and return early otherwise. (Alternatively restructure so the menu lives in a default sub-command.)Side note (low priority)
dcd live execwraps server errors asFailed to execute test failed: <message>— the doubled "test failed" reads awkwardly (e.g.Failed to execute test failed: Session not ready (HTTP 425)). Worth tidying the error-prefix wording while in this area.Found during a full feature sweep of v5.0.0 against the dev environment.