Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ Database: ~/.local/share/rtk/history.db

## Module Organization

### Complete Module Map (30 Modules)
### Complete Module Map (31 Modules)

```
┌────────────────────────────────────────────────────────────────────────┐
Expand Down Expand Up @@ -272,6 +272,8 @@ PYTHON ruff_cmd.rs ruff check/format 80%+ ✓
GO go_cmd.rs go test/build/vet 75-90% ✓
golangci_cmd.rs golangci-lint 85% ✓

JAVA/JVM mvn_cmd.rs mvn test 99% ✓

NETWORK wget_cmd.rs wget 85-95% ✓

DEPENDENCIES deps.rs deps 80-90% ✓
Expand All @@ -288,16 +290,17 @@ SHARED utils.rs Helpers N/A ✓
tee.rs Full output recovery N/A ✓
```

**Total: 50 modules** (32 command modules + 18 infrastructure modules)
**Total: 51 modules** (33 command modules + 18 infrastructure modules)

### Module Count Breakdown

- **Command Modules**: 31 (directly exposed to users)
- **Command Modules**: 32 (directly exposed to users)
- **Infrastructure Modules**: 18 (utils, filter, tracking, tee, config, init, gain, etc.)
- **Git Commands**: 7 operations (status, diff, log, add, commit, push, branch/checkout)
- **JS/TS Tooling**: 8 modules (modern frontend/fullstack development)
- **Python Tooling**: 3 modules (ruff, pytest, pip)
- **Go Tooling**: 2 modules (go test/build/vet, golangci-lint)
- **Java/JVM Tooling**: 1 module (mvn test with passthrough for other subcommands)

---

Expand Down Expand Up @@ -385,7 +388,7 @@ Strategy Modules Technique Reduction
│ Live updates │ Final result
└──────────────┘

Used by: wget, pnpm install (strip ANSI escape sequences)
Used by: wget, pnpm install, mvn (strip ANSI escape sequences, download progress)

10. JSON/TEXT DUAL MODE
┌──────────────┐
Expand All @@ -401,7 +404,7 @@ Strategy Modules Technique Reduction
│ Mixed format │ Extract failures Failure details
└──────────────┘

Used by: pytest (text state machine: test_name → PASSED/FAILED)
Used by: pytest (text state machine: test_name → PASSED/FAILED), mvn test (preamble → test section → failures → summary)

12. NDJSON STREAMING
┌──────────────┐
Expand Down Expand Up @@ -1481,6 +1484,6 @@ When implementing a new command, consider:

---

**Last Updated**: 2026-02-22
**Architecture Version**: 2.2
**Last Updated**: 2026-02-24
**Architecture Version**: 2.3
**rtk Version**: 0.22.2
53 changes: 27 additions & 26 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,32 +206,33 @@ rtk gain --history | grep proxy

### Module Responsibilities

| Module | Purpose | Token Strategy |
|--------|---------|----------------|
| git.rs | Git operations | Stat summaries + compact diffs |
| grep_cmd.rs | Code search | Group by file, truncate lines |
| ls.rs | Directory listing | Tree format, aggregate counts |
| read.rs | File reading | Filter-level based stripping |
| runner.rs | Command execution | Stderr only (err), failures only (test) |
| log_cmd.rs | Log parsing | Deduplication with counts |
| json_cmd.rs | JSON inspection | Structure without values |
| lint_cmd.rs | ESLint/Biome linting | Group by rule, file summary (84% reduction) |
| tsc_cmd.rs | TypeScript compiler | Group by file/error code (83% reduction) |
| next_cmd.rs | Next.js build/dev | Route metrics, bundle stats only (87% reduction) |
| prettier_cmd.rs | Format checking | Files needing changes only (70% reduction) |
| playwright_cmd.rs | E2E test results | Failures only, grouped by suite (94% reduction) |
| prisma_cmd.rs | Prisma CLI | Strip ASCII art and verbose output (88% reduction) |
| gh_cmd.rs | GitHub CLI | Compact PR/issue/run views (26-87% reduction) |
| vitest_cmd.rs | Vitest test runner | Failures only with ANSI stripping (99.5% reduction) |
| pnpm_cmd.rs | pnpm package manager | Compact dependency trees (70-90% reduction) |
| ruff_cmd.rs | Ruff linter/formatter | JSON for check, text for format (80%+ reduction) |
| pytest_cmd.rs | Pytest test runner | State machine text parser (90%+ reduction) |
| pip_cmd.rs | pip/uv package manager | JSON parsing, auto-detect uv (70-85% reduction) |
| go_cmd.rs | Go commands | NDJSON for test, text for build/vet (80-90% reduction) |
| golangci_cmd.rs | golangci-lint | JSON parsing, group by rule (85% reduction) |
| tee.rs | Full output recovery | Save raw output to file on failure, print hint for LLM re-read |
| utils.rs | Shared utilities | Package manager detection, common formatting |
| discover/ | Claude Code history analysis | Scan JSONL sessions, classify commands, report missed savings |
| Module | Purpose | Token Strategy |
|--------|---------|-----------------------------------------------------------------|
| git.rs | Git operations | Stat summaries + compact diffs |
| grep_cmd.rs | Code search | Group by file, truncate lines |
| ls.rs | Directory listing | Tree format, aggregate counts |
| read.rs | File reading | Filter-level based stripping |
| runner.rs | Command execution | Stderr only (err), failures only (test) |
| log_cmd.rs | Log parsing | Deduplication with counts |
| json_cmd.rs | JSON inspection | Structure without values |
| lint_cmd.rs | ESLint/Biome linting | Group by rule, file summary (84% reduction) |
| tsc_cmd.rs | TypeScript compiler | Group by file/error code (83% reduction) |
| next_cmd.rs | Next.js build/dev | Route metrics, bundle stats only (87% reduction) |
| prettier_cmd.rs | Format checking | Files needing changes only (70% reduction) |
| playwright_cmd.rs | E2E test results | Failures only, grouped by suite (94% reduction) |
| prisma_cmd.rs | Prisma CLI | Strip ASCII art and verbose output (88% reduction) |
| gh_cmd.rs | GitHub CLI | Compact PR/issue/run views (26-87% reduction) |
| vitest_cmd.rs | Vitest test runner | Failures only with ANSI stripping (99.5% reduction) |
| pnpm_cmd.rs | pnpm package manager | Compact dependency trees (70-90% reduction) |
| ruff_cmd.rs | Ruff linter/formatter | JSON for check, text for format (80%+ reduction) |
| pytest_cmd.rs | Pytest test runner | State machine text parser (90%+ reduction) |
| pip_cmd.rs | pip/uv package manager | JSON parsing, auto-detect uv (70-85% reduction) |
| go_cmd.rs | Go commands | NDJSON for test, text for build/vet (80-90% reduction) |
| golangci_cmd.rs | golangci-lint | JSON parsing, group by rule (85% reduction) |
| mvn_cmd.rs | Maven commands | State machine parser, strip downloads/lifecycle (99% reduction) |
| tee.rs | Full output recovery | Save raw output to file on failure, print hint for LLM re-read |
| utils.rs | Shared utilities | Package manager detection, common formatting |
| discover/ | Claude Code history analysis | Scan JSONL sessions, classify commands, report missed savings |

## Performance Constraints

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ rtk pytest # Python tests (failures only, 90% reduction)
rtk pip list # Python packages (auto-detect uv, 70% reduction)
rtk go test # Go tests (NDJSON, 90% reduction)
rtk golangci-lint run # Go linting (JSON, 85% reduction)
rtk mvn test # Maven tests (state machine, 99% reduction)
```

### Data & Analytics
Expand Down Expand Up @@ -282,6 +283,11 @@ rtk go test # NDJSON streaming parser (90% reduction)
rtk go build # Build errors only (80% reduction)
rtk go vet # Vet issues (75% reduction)
rtk golangci-lint run # JSON grouped by rule (85% reduction)

# Maven
rtk mvn test # Strip downloads/lifecycle, failures only (99% reduction)
rtk mvn test -pl module-a # Multi-module with Maven args passthrough
rtk mvn package # Passthrough for non-test subcommands
```

## Examples
Expand Down Expand Up @@ -625,6 +631,7 @@ The hook is included in this repository at `.claude/hooks/rtk-rewrite.sh`. To us
| `pip list/install/outdated` | `rtk pip ...` |
| `go test/build/vet` | `rtk go ...` |
| `golangci-lint run` | `rtk golangci-lint run` |
| `mvn test/package/...` | `rtk mvn ...` |
| `docker ps/images/logs` | `rtk docker ...` |
| `kubectl get/logs` | `rtk kubectl ...` |
| `curl` | `rtk curl` |
Expand Down
6 changes: 6 additions & 0 deletions hooks/rtk-rewrite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ elif echo "$MATCH_CMD" | grep -qE '^go[[:space:]]+vet([[:space:]]|$)'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed 's/^go vet/rtk go vet/')"
elif echo "$MATCH_CMD" | grep -qE '^golangci-lint([[:space:]]|$)'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed 's/^golangci-lint/rtk golangci-lint/')"

# --- Maven tooling ---
elif echo "$MATCH_CMD" | grep -qE '^(\.?/?mvnw?|mvn)[[:space:]]+test([[:space:]]|$)'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed -E 's/^(\.?\/?mvnw?|mvn) test/rtk mvn test/')"
elif echo "$MATCH_CMD" | grep -qE '^(\.?/?mvnw?|mvn)[[:space:]]'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed -E 's/^(\.?\/?mvnw?|mvn) /rtk mvn /')"
fi

# If no rewrite needed, approve as-is
Expand Down
17 changes: 14 additions & 3 deletions scripts/test-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -413,20 +413,31 @@ else
skip "golangci-lint not installed"
fi

# ── 29. Global flags ────────────────────────────────
# ── 29. Maven (conditional) ────────────────────────

section "Maven (conditional)"

if command -v mvn &>/dev/null; then
assert_help "rtk mvn" rtk mvn --help
assert_help "rtk mvn test" rtk mvn test -h
else
skip "maven not installed"
fi

# ── 30. Global flags ────────────────────────────────

section "Global flags"

assert_ok "rtk -u ls ." rtk -u ls .
assert_ok "rtk --skip-env npm --help" rtk --skip-env npm --help

# ── 30. CcEconomics ─────────────────────────────────
# ── 31. CcEconomics ─────────────────────────────────

section "CcEconomics"

assert_ok "rtk cc-economics" rtk cc-economics

# ── 31. Learn ───────────────────────────────────────
# ── 32. Learn ───────────────────────────────────────

section "Learn"

Expand Down
47 changes: 47 additions & 0 deletions src/discover/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const PATTERNS: &[&str] = &[
r"^kubectl\s+(get|logs)",
r"^curl\s+",
r"^wget\s+",
r"^(?:\.?/?mvnw?|mvn)\s+(test|compile|package|install|clean|verify)",
];

const RULES: &[RtkRule] = &[
Expand Down Expand Up @@ -225,6 +226,13 @@ const RULES: &[RtkRule] = &[
subcmd_savings: &[],
subcmd_status: &[],
},
RtkRule {
rtk_cmd: "rtk mvn",
category: "Build",
savings_pct: 99.0,
subcmd_savings: &[("test", 99.0)],
subcmd_status: &[],
},
];

/// Commands to ignore (shell builtins, trivial, already rtk).
Expand Down Expand Up @@ -699,6 +707,45 @@ mod tests {
}
}

#[test]
fn test_classify_mvn_test() {
assert_eq!(
classify_command("mvn test"),
Classification::Supported {
rtk_equivalent: "rtk mvn",
category: "Build",
estimated_savings_pct: 99.0,
status: RtkStatus::Existing,
}
);
}

#[test]
fn test_classify_mvnw_test() {
assert_eq!(
classify_command("./mvnw test -pl module-a"),
Classification::Supported {
rtk_equivalent: "rtk mvn",
category: "Build",
estimated_savings_pct: 99.0,
status: RtkStatus::Existing,
}
);
}

#[test]
fn test_classify_mvn_package() {
assert_eq!(
classify_command("mvn package -DskipTests"),
Classification::Supported {
rtk_equivalent: "rtk mvn",
category: "Build",
estimated_savings_pct: 99.0,
status: RtkStatus::Existing,
}
);
}

#[test]
fn test_split_chain_and() {
assert_eq!(split_command_chain("a && b"), vec!["a", "b"]);
Expand Down
60 changes: 60 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod lint_cmd;
mod local_llm;
mod log_cmd;
mod ls;
mod mvn_cmd;
mod next_cmd;
mod npm_cmd;
mod parser;
Expand Down Expand Up @@ -522,6 +523,12 @@ enum Commands {
command: GoCommands,
},

/// Maven commands with compact output
Mvn {
#[command(subcommand)]
command: MvnCommands,
},

/// golangci-lint with compact output
#[command(name = "golangci-lint")]
GolangciLint {
Expand Down Expand Up @@ -852,6 +859,19 @@ enum GoCommands {
Other(Vec<OsString>),
}

#[derive(Subcommand)]
enum MvnCommands {
/// Run tests with compact output (99% token reduction)
Test {
/// Additional mvn test arguments (e.g., -pl module-a, -Dtest=FooTest)
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
/// Passthrough: runs any unsupported mvn subcommand directly
#[command(external_subcommand)]
Other(Vec<OsString>),
}

fn main() -> Result<()> {
let cli = Cli::parse();

Expand Down Expand Up @@ -1423,6 +1443,15 @@ fn main() -> Result<()> {
}
},

Commands::Mvn { command } => match command {
MvnCommands::Test { args } => {
mvn_cmd::run_test(&args, cli.verbose)?;
}
MvnCommands::Other(args) => {
mvn_cmd::run_other(&args, cli.verbose)?;
}
},

Commands::GolangciLint { args } => {
golangci_cmd::run(&args, cli.verbose)?;
}
Expand Down Expand Up @@ -1546,4 +1575,35 @@ mod tests {
_ => panic!("Expected Git Commit command"),
}
}

#[test]
fn test_mvn_test_parsing() {
let cli = Cli::try_parse_from(["rtk", "mvn", "test", "-pl", "module-a", "-Dtest=FooTest"])
.unwrap();
match cli.command {
Commands::Mvn {
command: MvnCommands::Test { args },
} => {
assert_eq!(args, vec!["-pl", "module-a", "-Dtest=FooTest"]);
}
_ => panic!("Expected Mvn Test command"),
}
}

#[test]
fn test_mvn_passthrough() {
let cli = Cli::try_parse_from(["rtk", "mvn", "package", "-DskipTests"]).unwrap();
match cli.command {
Commands::Mvn {
command: MvnCommands::Other(args),
} => {
let strs: Vec<String> = args
.iter()
.map(|a| a.to_string_lossy().into_owned())
.collect();
assert_eq!(strs, vec!["package", "-DskipTests"]);
}
_ => panic!("Expected Mvn Other command"),
}
}
}
Loading