Skip to content

Commit 5968038

Browse files
authored
Merge pull request #14 from CamonZ/multiple-scope-commands
Remove describe command and restructure CLI with CodeCommand grouping
2 parents 3331917 + dae34aa commit 5968038

45 files changed

Lines changed: 252 additions & 1141 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ cargo test -p code_search # Test CLI layer only
1414
cargo test <test_name> # Run a single test by name
1515
cargo nextest run # Alternative test runner (faster)
1616
cargo run -p code_search -- --help # Show CLI help
17-
cargo run -p code_search -- describe # Show detailed command documentation
1817
```
1918

2019
## Workspace Structure

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ All commands support three output formats via `--format` or `-o`:
8282

8383
## Commands
8484

85-
Use `code_search describe` to see detailed documentation, or `code_search describe <command>` for specific command help.
85+
Use `code_search <command> --help` for detailed help on any command.
8686

8787
### Query Commands
8888

@@ -139,10 +139,9 @@ Use `code_search describe` to see detailed documentation, or `code_search descri
139139
|---------|-------|-------------|
140140
| `setup` | `setup [--install-skills] [--install-hooks] [--force]` | Create database schema, install templates and/or git hooks |
141141
| `import` | `import --file <FILE>` | Import call graph JSON |
142-
| `describe` | `describe [COMMANDS...]` | Show detailed command documentation |
143142

144143
**Setup flags:**
145-
- `--install-skills`: Install skill and agent templates to `.claude/` (34 skills + 1 agent)
144+
- `--install-skills`: Install skill and agent templates to `.claude/` (28 skills + 1 agent)
146145
- `--install-hooks`: Install post-commit git hook for automatic incremental updates
147146
- `--mix-env <ENV>`: Mix environment for git hook (used with `--install-hooks`, default: dev)
148147
- `--force`: Overwrite existing template/hook files (preserves by default)
@@ -207,7 +206,7 @@ code_search setup --install-skills --force
207206
```
208207

209208
This installs:
210-
- **34 skill templates** documenting each command with examples
209+
- **28 skill templates** documenting each command with examples
211210
- **1 Haiku-powered agent** for fast, cost-efficient codebase exploration
212211

213212
### Git Hooks for Automatic Updates
@@ -260,7 +259,7 @@ After installation:
260259
├── accepts/ # Type search skills
261260
├── browse-module/ # Module exploration
262261
├── code-search-explorer/ # Quick reference docs
263-
├── ... (30 other command skills)
262+
├── ... (24 other command skills)
264263
└── workflows/ # Common workflow guides
265264
```
266265

cli/src/commands/accepts/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ use crate::output::{OutputFormat, Outputable};
1313
#[derive(Args, Debug)]
1414
#[command(after_help = "\
1515
Examples:
16-
code_search accepts \"User.t\" # Find functions accepting User.t
17-
code_search accepts \"map()\" # Find functions accepting maps
18-
code_search accepts \"User.t\" MyApp # Filter to module MyApp
19-
code_search accepts -r \"list\\(.*\\)\" # Regex pattern matching
16+
code_search code accepts \"User.t\" # Find functions accepting User.t
17+
code_search code accepts \"map()\" # Find functions accepting maps
18+
code_search code accepts \"User.t\" MyApp # Filter to module MyApp
19+
code_search code accepts -r \"list\\(.*\\)\" # Regex pattern matching
2020
")]
2121
pub struct AcceptsCmd {
2222
/// Type pattern to search for in input types

cli/src/commands/boundaries/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use crate::output::{OutputFormat, Outputable};
1717
#[derive(Args, Debug)]
1818
#[command(after_help = "\
1919
Examples:
20-
code_search boundaries # Find all boundary modules
21-
code_search boundaries MyApp.Web # Filter to MyApp.Web namespace
22-
code_search boundaries --min-incoming 5 # With minimum 5 incoming calls
23-
code_search boundaries --min-ratio 2.0 # With minimum 2.0 ratio
24-
code_search boundaries -l 20 # Show top 20 boundary modules
20+
code_search code boundaries # Find all boundary modules
21+
code_search code boundaries MyApp.Web # Filter to MyApp.Web namespace
22+
code_search code boundaries --min-incoming 5 # With minimum 5 incoming calls
23+
code_search code boundaries --min-ratio 2.0 # With minimum 2.0 ratio
24+
code_search code boundaries -l 20 # Show top 20 boundary modules
2525
")]
2626
pub struct BoundariesCmd {
2727
/// Module filter pattern (substring match by default, regex with --regex)

cli/src/commands/browse_module/cli_tests.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod tests {
1414
// Positional argument test - browse-module requires a module or file argument
1515
#[test]
1616
fn test_requires_module_or_file() {
17-
let result = Args::try_parse_from(["code_search", "browse-module"]);
17+
let result = Args::try_parse_from(["code_search", "code", "browse-module"]);
1818
assert!(result.is_err(), "Should require module_or_file positional argument");
1919
}
2020

@@ -86,14 +86,15 @@ mod tests {
8686
fn test_kind_filter(#[case] kind_str: &str, #[case] expected: DefinitionKind) {
8787
let args = Args::try_parse_from([
8888
"code_search",
89+
"code",
8990
"browse-module",
9091
"MyApp.Accounts",
9192
"--kind",
9293
kind_str,
9394
])
9495
.expect("Failed to parse args");
9596

96-
if let crate::commands::Command::BrowseModule(cmd) = args.command {
97+
if let crate::commands::Command::Code(crate::commands::CodeCommand::BrowseModule(cmd)) = args.command {
9798
assert!(cmd.kind.is_some());
9899
assert!(matches!(cmd.kind.unwrap(), k if std::mem::discriminant(&k) == std::mem::discriminant(&expected)));
99100
} else {
@@ -103,10 +104,10 @@ mod tests {
103104

104105
#[test]
105106
fn test_kind_filter_default_is_none() {
106-
let args = Args::try_parse_from(["code_search", "browse-module", "MyApp.Accounts"])
107+
let args = Args::try_parse_from(["code_search", "code", "browse-module", "MyApp.Accounts"])
107108
.expect("Failed to parse args");
108109

109-
if let crate::commands::Command::BrowseModule(cmd) = args.command {
110+
if let crate::commands::Command::Code(crate::commands::CodeCommand::BrowseModule(cmd)) = args.command {
110111
assert!(cmd.kind.is_none());
111112
} else {
112113
panic!("Expected BrowseModule command");

cli/src/commands/calls_from/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use crate::output::{OutputFormat, Outputable};
1616
#[derive(Args, Debug)]
1717
#[command(after_help = "\
1818
Examples:
19-
code_search calls-from MyApp.Accounts # All calls from module
20-
code_search calls-from MyApp.Accounts get_user # Calls from specific function
21-
code_search calls-from MyApp.Accounts get_user 1 # With specific arity")]
19+
code_search code calls-from MyApp.Accounts # All calls from module
20+
code_search code calls-from MyApp.Accounts get_user # Calls from specific function
21+
code_search code calls-from MyApp.Accounts get_user 1 # With specific arity")]
2222
pub struct CallsFromCmd {
2323
/// Module name (exact match or pattern with --regex)
2424
pub module: String,

cli/src/commands/calls_to/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ use crate::output::{OutputFormat, Outputable};
1616
#[derive(Args, Debug)]
1717
#[command(after_help = "\
1818
Examples:
19-
code_search calls-to MyApp.Repo # All callers of module
20-
code_search calls-to MyApp.Repo get # Callers of specific function
21-
code_search calls-to MyApp.Repo get 2 # With specific arity
22-
code_search calls-to MyApp.Accounts get_user # Find all call sites")]
19+
code_search code calls-to MyApp.Repo # All callers of module
20+
code_search code calls-to MyApp.Repo get # Callers of specific function
21+
code_search code calls-to MyApp.Repo get 2 # With specific arity
22+
code_search code calls-to MyApp.Accounts get_user # Find all call sites")]
2323
pub struct CallsToCmd {
2424
/// Module name (exact match or pattern with --regex)
2525
pub module: String,

cli/src/commands/clusters/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ use crate::output::{OutputFormat, Outputable};
1616
#[derive(Args, Debug)]
1717
#[command(after_help = "\
1818
Examples:
19-
code_search clusters # Show all namespace clusters
20-
code_search clusters MyApp.Core # Filter to MyApp.Core namespace
21-
code_search clusters --depth 2 # Cluster at depth 2 (e.g., MyApp.Accounts)
22-
code_search clusters --depth 3 # Cluster at depth 3 (e.g., MyApp.Accounts.Auth)
23-
code_search clusters --show-dependencies # Include cross-namespace call counts
19+
code_search code clusters # Show all namespace clusters
20+
code_search code clusters MyApp.Core # Filter to MyApp.Core namespace
21+
code_search code clusters --depth 2 # Cluster at depth 2 (e.g., MyApp.Accounts)
22+
code_search code clusters --depth 3 # Cluster at depth 3 (e.g., MyApp.Accounts.Auth)
23+
code_search code clusters --show-dependencies # Include cross-namespace call counts
2424
")]
2525
pub struct ClustersCmd {
2626
/// Module filter pattern (substring match by default, regex with --regex)

cli/src/commands/code.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! Code analysis subcommands.
2+
3+
use clap::Subcommand;
4+
use enum_dispatch::enum_dispatch;
5+
6+
use super::{
7+
AcceptsCmd, BoundariesCmd, BrowseModuleCmd, CallsFromCmd, CallsToCmd, ClustersCmd,
8+
ComplexityCmd, CyclesCmd, DependedByCmd, DependsOnCmd, DuplicatesCmd, FunctionCmd,
9+
GodModulesCmd, HotspotsCmd, ImportCmd, LargeFunctionsCmd, LocationCmd, ManyClausesCmd,
10+
PathCmd, ReturnsCmd, ReverseTraceCmd, SearchCmd, StructUsageCmd, TraceCmd, UnusedCmd,
11+
};
12+
13+
#[derive(Subcommand, Debug)]
14+
#[enum_dispatch(CommandRunner)]
15+
pub enum CodeCommand {
16+
/// Import a call graph JSON file into the database
17+
Import(ImportCmd),
18+
/// Browse all definitions in a module or file
19+
BrowseModule(BrowseModuleCmd),
20+
/// Search for modules or functions by name pattern
21+
Search(SearchCmd),
22+
/// Find where a function is defined (file:line_start:line_end)
23+
Location(LocationCmd),
24+
/// Show what a module/function calls (outgoing edges)
25+
CallsFrom(CallsFromCmd),
26+
/// Show what calls a module/function (incoming edges)
27+
CallsTo(CallsToCmd),
28+
/// Analyze module connectivity using namespace-based clustering
29+
Clusters(ClustersCmd),
30+
/// Display complexity metrics for functions
31+
Complexity(ComplexityCmd),
32+
/// Detect circular dependencies between modules
33+
Cycles(CyclesCmd),
34+
/// Show function signature (args, return type)
35+
Function(FunctionCmd),
36+
/// Trace call chains from a starting function (forward traversal)
37+
Trace(TraceCmd),
38+
/// Trace call chains backwards - who calls the callers of a target
39+
ReverseTrace(ReverseTraceCmd),
40+
/// Find a call path between two functions
41+
Path(PathCmd),
42+
/// Find functions accepting a specific type pattern
43+
Accepts(AcceptsCmd),
44+
/// Find functions returning a specific type pattern
45+
Returns(ReturnsCmd),
46+
/// Find functions that accept or return a specific type pattern
47+
StructUsage(StructUsageCmd),
48+
/// Show what modules a given module depends on (outgoing module dependencies)
49+
DependsOn(DependsOnCmd),
50+
/// Show what modules depend on a given module (incoming module dependencies)
51+
DependedBy(DependedByCmd),
52+
/// Find functions that are never called
53+
Unused(UnusedCmd),
54+
/// Find functions with identical or near-identical implementations
55+
Duplicates(DuplicatesCmd),
56+
/// Find functions with the most incoming/outgoing calls
57+
Hotspots(HotspotsCmd),
58+
/// Find boundary modules - modules with high fan-in but low fan-out
59+
Boundaries(BoundariesCmd),
60+
/// Find god modules - modules with high function count and high connectivity
61+
GodModules(GodModulesCmd),
62+
/// Find large functions that may need refactoring
63+
LargeFunctions(LargeFunctionsCmd),
64+
/// Find functions with many pattern-matched heads
65+
ManyClauses(ManyClausesCmd),
66+
}

cli/src/commands/complexity/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ use crate::output::{OutputFormat, Outputable};
2424
#[derive(Args, Debug)]
2525
#[command(after_help = "\
2626
Examples:
27-
code_search complexity # Show all functions with complexity >= 1
28-
code_search complexity MyApp.Accounts # Filter to MyApp.Accounts module
29-
code_search complexity --min 10 # Show functions with complexity >= 10
30-
code_search complexity --min-depth 3 # Show functions with nesting depth >= 3
31-
code_search complexity --exclude-generated # Exclude macro-generated functions
32-
code_search complexity -l 20 # Show top 20 most complex functions
27+
code_search code complexity # Show all functions with complexity >= 1
28+
code_search code complexity MyApp.Accounts # Filter to MyApp.Accounts module
29+
code_search code complexity --min 10 # Show functions with complexity >= 10
30+
code_search code complexity --min-depth 3 # Show functions with nesting depth >= 3
31+
code_search code complexity --exclude-generated # Exclude macro-generated functions
32+
code_search code complexity -l 20 # Show top 20 most complex functions
3333
")]
3434
pub struct ComplexityCmd {
3535
/// Module filter pattern (substring match by default, regex with --regex)

0 commit comments

Comments
 (0)