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
22 changes: 13 additions & 9 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 @@ -260,6 +260,7 @@ JS/TS STACK lint_cmd.rs lint 84% ✓
prisma_cmd.rs prisma 88% ✓
vitest_cmd.rs vitest 99.5% ✓
pnpm_cmd.rs pnpm 70-90% ✓
yarn_cmd.rs yarn test 90% ✓

CONTAINERS container.rs podman, docker 60-80% ✓

Expand Down Expand Up @@ -288,14 +289,14 @@ 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)
- **JS/TS Tooling**: 9 modules (modern frontend/fullstack development)
- **Python Tooling**: 3 modules (ruff, pytest, pip)
- **Go Tooling**: 2 modules (go test/build/vet, golangci-lint)

Expand Down Expand Up @@ -369,7 +370,7 @@ Strategy Modules Technique Reduction
│ Mixed │ Hide passing " • test_auth"
└──────────────┘

Used by: vitest, playwright, runner (test mode)
Used by: vitest, yarn test, playwright, runner (test mode)

8. TREE COMPRESSION
┌──────────────┐
Expand Down Expand Up @@ -401,7 +402,8 @@ 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),
yarn test (Jest: state machine PASS/FAIL → summary; Vitest: regex summary)

12. NDJSON STREAMING
┌──────────────┐
Expand Down Expand Up @@ -752,7 +754,7 @@ let mut cmd = if is_pnpm {
Command::new("npx").arg("--no-install").arg("--").arg("eslint")
};

Affects: lint, tsc, next, prettier, playwright, prisma, vitest, pnpm
Affects: lint, tsc, next, prettier, playwright, prisma, vitest, pnpm, yarn
```

**Why This Matters**:
Expand Down Expand Up @@ -1016,7 +1018,9 @@ Modules with Exit Code Preservation:
• lint_cmd.rs (linter failures)
• tsc_cmd.rs (TypeScript errors)
• vitest_cmd.rs (test failures)
• yarn_cmd.rs (test failures)
• playwright_cmd.rs (E2E test failures)
• yarn_cmd.rs (test failures)
```

---
Expand Down Expand Up @@ -1481,6 +1485,6 @@ When implementing a new command, consider:

---

**Last Updated**: 2026-02-22
**Architecture Version**: 2.2
**Last Updated**: 2026-02-27
**Architecture Version**: 2.3
**rtk Version**: 0.22.2
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ rtk gain --history | grep proxy
| 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) |
| yarn_cmd.rs | Yarn test runner | State machine Jest parser (90% 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 |
Expand Down
10 changes: 10 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 yarn test # Yarn (Vitest only) tests (failures only, 90% reduction)
```

### Data & Analytics
Expand Down Expand Up @@ -267,6 +268,13 @@ rtk prisma migrate dev --name x # Migration summary
rtk prisma db-push # Schema push summary
```

### Yarn
```bash
rtk yarn test # Jest test output, failures only (90% reduction)
rtk yarn test --coverage # With extra args passed through
rtk yarn install # Passthrough for non-test subcommands
```

### Python & Go Stack
```bash
# Python
Expand Down Expand Up @@ -625,6 +633,8 @@ 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` |
| `yarn test` | `rtk yarn test` |
| `yarn <subcommand>` | `rtk yarn <subcommand>` |
| `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 @@ -194,6 +194,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/')"

# --- Yarn tooling ---
elif echo "$MATCH_CMD" | grep -qE '^yarn[[:space:]]+test([[:space:]]|$)'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed 's/^yarn test/rtk yarn test/')"
elif echo "$MATCH_CMD" | grep -qE '^yarn[[:space:]]'; then
REWRITTEN="${ENV_PREFIX}$(echo "$CMD_BODY" | sed 's/^yarn /rtk yarn /')"
fi

# If no rewrite needed, approve as-is
Expand Down
13 changes: 12 additions & 1 deletion scripts/test-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,18 @@ else
skip "golangci-lint not installed"
fi

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

section "Yarn (conditional)"

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

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

section "Global flags"

Expand Down
34 changes: 34 additions & 0 deletions src/discover/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const PATTERNS: &[&str] = &[
r"^curl\s+",
r"^wget\s+",
r"^(python3?\s+-m\s+)?mypy(\s|$)",
r"^yarn\s+(test|install|add|remove|build|start|dev)",
];

const RULES: &[RtkRule] = &[
Expand Down Expand Up @@ -226,6 +227,13 @@ const RULES: &[RtkRule] = &[
subcmd_savings: &[],
subcmd_status: &[],
},
RtkRule {
rtk_cmd: "rtk yarn",
category: "Tests",
savings_pct: 90.0,
subcmd_savings: &[("test", 90.0)],
subcmd_status: &[],
},
RtkRule {
rtk_cmd: "rtk mypy",
category: "Build",
Expand Down Expand Up @@ -791,4 +799,30 @@ mod tests {
}
);
}

#[test]
fn test_classify_yarn_test() {
assert_eq!(
classify_command("yarn test"),
Classification::Supported {
rtk_equivalent: "rtk yarn",
category: "Tests",
estimated_savings_pct: 90.0,
status: RtkStatus::Existing,
}
);
}

#[test]
fn test_classify_yarn_test_with_args() {
assert_eq!(
classify_command("yarn test --coverage"),
Classification::Supported {
rtk_equivalent: "rtk yarn",
category: "Tests",
estimated_savings_pct: 90.0,
status: RtkStatus::Existing,
}
);
}
}
56 changes: 56 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ mod utils;
mod vitest_cmd;
mod wc_cmd;
mod wget_cmd;
mod yarn_cmd;

use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -548,6 +549,12 @@ enum Commands {
#[arg(short, long, default_value = "7")]
since: u64,
},

/// Yarn commands with compact output
Yarn {
#[command(subcommand)]
command: YarnCommands,
},
}

#[derive(Subcommand)]
Expand Down Expand Up @@ -863,6 +870,19 @@ enum GoCommands {
Other(Vec<OsString>),
}

#[derive(Subcommand)]
enum YarnCommands {
/// Run tests with compact output (90% token reduction)
Test {
/// Additional yarn test arguments
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<String>,
},
/// Passthrough: runs any unsupported yarn subcommand directly
#[command(external_subcommand)]
Other(Vec<OsString>),
}

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

Expand Down Expand Up @@ -1448,6 +1468,15 @@ fn main() -> Result<()> {
hook_audit_cmd::run(since, cli.verbose)?;
}

Commands::Yarn { command } => match command {
YarnCommands::Test { args } => {
yarn_cmd::run_test(&args, cli.verbose)?;
}
YarnCommands::Other(args) => {
yarn_cmd::run_other(&args, cli.verbose)?;
}
},

Commands::Proxy { args } => {
use std::process::Command;

Expand Down Expand Up @@ -1563,4 +1592,31 @@ mod tests {
_ => panic!("Expected Git Commit command"),
}
}

#[test]
fn test_yarn_test_parsing() {
let cli =
Cli::try_parse_from(["rtk", "yarn", "test", "--coverage", "--watchAll=false"]).unwrap();
match cli.command {
Commands::Yarn {
command: YarnCommands::Test { args },
} => {
assert_eq!(args, vec!["--coverage", "--watchAll=false"]);
}
_ => panic!("Expected Yarn Test command"),
}
}

#[test]
fn test_yarn_passthrough() {
let cli = Cli::try_parse_from(["rtk", "yarn", "install"]).unwrap();
match cli.command {
Commands::Yarn {
command: YarnCommands::Other(args),
} => {
assert_eq!(args[0], "install");
}
_ => panic!("Expected Yarn Other command"),
}
}
}
Loading