feat(cmd): add repo-scoped commands — raid <repo> <command>#62
feat(cmd): add repo-scoped commands — raid <repo> <command>#62
raid <repo> <command>#62Conversation
Each repository that defines commands in its raid.yaml is now registered as a Cobra subcommand of root. Users can run `raid backend test` to explicitly target the backend repo's "test" command, even when a profile-level command has the same name. - lib: add GetRepos() and ExecuteRepoCommand(repo, cmd, args) - raid: expose GetRepos() and ExecuteRepoCommand() in the facade - cmd: add registerRepoCommands() wired into executeRoot(); repos with names that conflict with built-in or user commands are skipped with a warning - docs: README, docsite (custom commands, repo-config, command reference, examples) - version: bump to 0.7.4-beta Closes #21
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #62 +/- ##
==========================================
+ Coverage 92.49% 92.68% +0.19%
==========================================
Files 32 32
Lines 2438 2503 +65
==========================================
+ Hits 2255 2320 +65
Misses 114 114
Partials 69 69 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds repo-scoped CLI command namespaces (raid <repo> <command>) so users can run a command from a specific repository’s raid.yaml even when a profile-level command has the same name (closes #21).
Changes:
- Added
GetRepos()andExecuteRepoCommand()to the internal lib + facade layer. - Registered repo namespaces and their commands as Cobra subcommands (
raid <repo> <command>), including conflict handling. - Updated docs and added tests covering repo discovery, command execution, and CLI registration behavior.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/resources/app.properties | Bumps version to 0.7.4-beta. |
| src/raid/raid.go | Adds facade wrappers for repo listing + repo-scoped command execution. |
| src/internal/lib/command.go | Implements GetRepos() and ExecuteRepoCommand() in core command runner. |
| src/internal/lib/command_test.go | Adds unit tests for repo listing and repo-scoped command execution. |
| src/cmd/raid.go | Registers repo namespaces + repo commands into Cobra command tree. |
| src/cmd/raid_test.go | Adds CLI registration tests for repo-scoped commands and conflict handling. |
| site/docs/usage/custom.mdx | Documents repo-scoped command syntax and updates reserved-name constraints. |
| site/docs/references/commands.mdx | Adds repo-scoped syntax and examples; updates reserved-name list. |
| site/docs/features/repo-config.mdx | Updates repo command precedence explanation and reserved-name list. |
| site/docs/examples/custom-commands.mdx | Adds explicit repo-scoped command examples. |
| README.md | Documents raid <repo> <command> usage and examples. |
| startedAt := RecordRecentStart(found.Name) | ||
| err := runCommand(found) | ||
| RecordRecentEnd(found.Name, err, startedAt) |
There was a problem hiding this comment.
ExecuteRepoCommand records recent runs under found.Name only. If a repo-scoped command shares the same name as a profile-level command (the motivating case for this feature), the recent history / raid context output becomes ambiguous. Consider recording a namespaced identifier (e.g., " " or ":") for RecordRecentStart/End in the repo-scoped path so history clearly identifies which command actually ran.
| startedAt := RecordRecentStart(found.Name) | |
| err := runCommand(found) | |
| RecordRecentEnd(found.Name, err, startedAt) | |
| recentName := fmt.Sprintf("%s:%s", repoName, found.Name) | |
| startedAt := RecordRecentStart(recentName) | |
| err := runCommand(found) | |
| RecordRecentEnd(recentName, err, startedAt) |
| ## Constraints | ||
|
|
||
| Custom command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`. | ||
| Custom command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`, `context`. |
There was a problem hiding this comment.
The docs say built-in names are limited to profile, install, env, doctor, context, but the CLI also reserves help, version, and completion (see reservedNames in src/cmd/raid.go). Please update this list (or rephrase to avoid an exhaustive enumeration) so the documentation matches actual behavior.
| Custom command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`, `context`. | |
| Custom command names cannot shadow reserved built-in CLI names, such as `profile`, `install`, `env`, `doctor`, `context`, `help`, `version`, and `completion`. |
| Custom commands are defined in `commands` sections of the profile or in individual repository `raid.yaml` files. Run `raid --help` to see all available commands. | ||
|
|
||
| Custom command names cannot shadow built-in names (`profile`, `install`, `env`, `doctor`). | ||
| Custom command names cannot shadow built-in names (`profile`, `install`, `env`, `doctor`, `context`). |
There was a problem hiding this comment.
This reserved-name list is incomplete: the CLI also prevents custom commands from using help, version, and completion (see reservedNames in src/cmd/raid.go). Update the list (or reword to indicate the list is non-exhaustive) so users don’t accidentally pick a disallowed name.
| Custom command names cannot shadow built-in names (`profile`, `install`, `env`, `doctor`, `context`). | |
| Custom command names cannot shadow built-in or reserved names (`profile`, `install`, `env`, `doctor`, `context`, `help`, `version`, `completion`). |
| raid api api-dev # explicitly run the api repo's "api-dev" command | ||
| ``` | ||
|
|
||
| Command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`, `context`. |
There was a problem hiding this comment.
This built-in name list should match what the CLI actually reserves. reservedNames in src/cmd/raid.go also includes help, version, and completion, so custom commands using those names will be rejected even though they aren’t listed here. Please update or clarify the wording.
| Command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`, `context`. | |
| Command names cannot shadow built-in names: `profile`, `install`, `env`, `doctor`, `context`, `help`, `version`, `completion`. |
- Record repo-scoped commands with namespaced identifier (repo:cmd) in recent history so `raid context` output is unambiguous when a repo command shares a name with a profile command - Update reserved-name lists in 3 doc pages to include all 8 reserved names (was missing help, version, completion) - Add facade tests for GetRepos() and ExecuteRepoCommand() to close the codecov patch gap
Summary
Adds the ability to explicitly run a command defined in a specific repository's
raid.yaml, even when a profile-level command has the same name.Each repository that defines commands now appears as a subcommand in
raid --help. The existing flatraid <command>behavior is fully preserved — this is purely additive.Closes #21
Changes
Core (
src/internal/lib/command.go)GetRepos()— returns the repositories in the active profile (parallel toGetCommands())ExecuteRepoCommand(repoName, cmdName, args)— looks up a command in a specific repo and runs it (same session/args/recording flow asExecuteCommand)Facade (
src/raid/raid.go)GetRepos()andExecuteRepoCommand()wrappersCLI (
src/cmd/raid.go)registerRepoCommands(root, repos)— registers each repo as a Cobra subcommand with its commands as sub-subcommandsexecuteRoot()afterregisterUserCommands()WithMutationLock(matching the existing user command pattern)Docs
README.md— newraid <repo> <command>sectionsite/docs/usage/custom.mdx— "Repo-scoped commands" sectionsite/docs/features/repo-config.mdx— updated Commands sectionsite/docs/references/commands.mdx— added repo-scoped syntaxsite/docs/examples/custom-commands.mdx— addedraid api migrateexampleTest plan
TestGetRepos_nilContext,TestGetRepos_withReposTestExecuteRepoCommand_success,_repoNotFound,_cmdNotFound,_taskFailure,_setsArgs,_nilContextTestRegisterRepoCommands_appearsInHelp,_repoSubcommands,_reservedNameSkipped,_conflictWithUserCommand,_noCommandsSkipped,_multipleRepos,_emptyRepos,_runEgo test ./...— all passinggo vet ./...— cleannpm run buildinsite/— docsite builds with no broken links0.7.4-betaGenerated by Claude Code