Skip to content

feat: add modern JavaScript tooling support (lint, tsc, next, prettier, playwright, prisma)#9

Merged
pszymkowiak merged 4 commits intortk-ai:masterfrom
FlorianBruniaux:feat/modern-js-stack
Jan 29, 2026
Merged

feat: add modern JavaScript tooling support (lint, tsc, next, prettier, playwright, prisma)#9
pszymkowiak merged 4 commits intortk-ai:masterfrom
FlorianBruniaux:feat/modern-js-stack

Conversation

@FlorianBruniaux
Copy link
Collaborator

Summary

Add comprehensive support for modern JavaScript/TypeScript development tooling with 6 new commands optimized for T3 Stack workflows:

  • rtk lint: ESLint/Biome output with grouped rule violations (84% token reduction)
  • rtk tsc: TypeScript compiler errors grouped by file and error code (83% reduction)
  • rtk next: Next.js build output with route/bundle metrics (87% reduction)
  • rtk prettier: Format checker showing only files needing changes (70% reduction)
  • rtk playwright: E2E test results showing failures only (94% reduction)
  • rtk prisma: Prisma CLI without ASCII art (88% reduction)

Key Features

  • Auto-detects package managers (pnpm/yarn/npm/npx)
  • Preserves exit codes for CI/CD compatibility
  • Groups errors by file and error code for quick navigation
  • Strips verbose output while retaining critical information
  • Shared utils.rs module for consistent formatting across commands

Token Reduction Metrics

Validated on production T3 Stack project (methode-aristote/app):

Command Before After Reduction
tsc --noEmit ~3K tokens ~500 tokens 83%
next build ~8K tokens ~1K tokens 87%
prettier --check ~2.5K tokens ~750 tokens 70%
playwright test ~15K tokens ~900 tokens 94%
prisma generate ~2.5K tokens ~300 tokens 88%
lint (eslint) ~5K tokens ~800 tokens 84%

Changes

  • 3 commits with clean separation:

    1. Shared utils module (truncate, strip_ansi, execute_command)
    2. 6 command modules (~2K LOC)
    3. CHANGELOG documentation
  • 9 files changed, 2,203 insertions

  • All new modules follow existing RTK patterns

  • Zero breaking changes to existing commands

  • Clippy-clean for new modules (upstream warnings not touched)

Test Plan

# Build and install
cargo build --release
cargo install --path .

# Test each command
rtk prettier --help
rtk playwright --help
rtk tsc --help
rtk next --help
rtk lint --help
rtk prisma --help

# Verify on real project
cd /path/to/nextjs-project
rtk tsc --noEmit
rtk prettier --check .
rtk next build

🤖 Generated with Claude Code

FlorianBruniaux and others added 3 commits January 29, 2026 11:23
Add utils.rs with common utilities used across modern JavaScript
tooling commands:
- truncate(): Smart string truncation with ellipsis
- strip_ansi(): Remove ANSI escape codes from output
- execute_command(): Centralized command execution with error handling

These utilities enable consistent output formatting and filtering
across multiple command modules.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive support for modern JS/TS development stack:

Commands added:
- rtk lint: ESLint/Biome output with grouped rule violations (84% reduction)
- rtk tsc: TypeScript compiler errors grouped by file (83% reduction)
- rtk next: Next.js build output with route/bundle metrics (87% reduction)
- rtk prettier: Format checker showing only files needing changes (70% reduction)
- rtk playwright: E2E test results showing failures only (94% reduction)
- rtk prisma: Prisma CLI without ASCII art (88% reduction)

Features:
- Auto-detects package managers (pnpm/yarn/npm/npx)
- Preserves exit codes for CI/CD compatibility
- Groups errors by file and error code for quick navigation
- Strips verbose output while retaining critical information

Total: 6 new commands, ~2,000 LOC

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Document the 6 new commands and shared utils module in CHANGELOG.md.
Focuses on token reduction metrics and CI/CD compatibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 29, 2026 10:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds comprehensive support for modern JavaScript/TypeScript development tooling to the rtk (Rust Token Killer) CLI. The PR introduces 6 new commands designed to minimize LLM token consumption by filtering verbose output from popular JavaScript tooling (ESLint, TypeScript, Next.js, Prettier, Playwright, and Prisma).

Changes:

  • Added shared utils.rs module with common text processing utilities (truncate, strip_ansi, execute_command)
  • Implemented 6 new command modules for JavaScript tooling with token reduction ranging from 70-94%
  • Updated main.rs to register new commands and CLI structure

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/utils.rs Shared utilities for ANSI stripping, text truncation, and command execution
src/tsc_cmd.rs TypeScript compiler output filtering with error grouping by file and code
src/prisma_cmd.rs Prisma CLI wrapper supporting generate, migrate (dev/status/deploy), and db push
src/prettier_cmd.rs Prettier format checker showing only files needing changes
src/playwright_cmd.rs Playwright E2E test output showing only failures and slow tests
src/next_cmd.rs Next.js build output filtering with route/bundle metrics
src/lint_cmd.rs ESLint/linter output with grouped rule violations
src/main.rs CLI command registration and routing for new commands
CHANGELOG.md Documentation of changes and token reduction metrics

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +14
pub fn run(args: &[String], verbose: u8) -> Result<()> {
// Try tsc directly first, fallback to npx if not found
let tsc_exists = Command::new("which")
.arg("tsc")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the which command is not cross-platform compatible. The which command doesn't exist on Windows systems by default (it's where on Windows). Consider using std::env::var("PATH") and checking for executable existence manually, or use a cross-platform approach. This same issue exists in tsc_cmd.rs, prettier_cmd.rs, playwright_cmd.rs, prisma_cmd.rs, next_cmd.rs, and lint_cmd.rs.

Suggested change
pub fn run(args: &[String], verbose: u8) -> Result<()> {
// Try tsc directly first, fallback to npx if not found
let tsc_exists = Command::new("which")
.arg("tsc")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
fn command_exists(cmd: &str) -> bool {
if let Some(paths) = std::env::var_os("PATH") {
for path in std::env::split_paths(&paths) {
let mut candidate = path.clone();
candidate.push(cmd);
if candidate.is_file() {
return true;
}
#[cfg(windows)]
{
let mut candidate_exe = path.clone();
candidate_exe.push(format!("{cmd}.exe"));
if candidate_exe.is_file() {
return true;
}
}
}
}
false
}
pub fn run(args: &[String], verbose: u8) -> Result<()> {
// Try tsc directly first, fallback to npx if not found
let tsc_exists = command_exists("tsc");

Copilot uses AI. Check for mistakes.
Comment on lines +94 to +96
// TODO: Use duration in detailed reports (token-efficient summary doesn't need it)
#[allow(dead_code)]
duration: Option<f64>,
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO comment should be removed or converted to an actual implementation plan if the feature is needed. If the duration field is not needed for token-efficient summaries as stated, consider removing it entirely rather than keeping it with #[allow(dead_code)].

Suggested change
// TODO: Use duration in detailed reports (token-efficient summary doesn't need it)
#[allow(dead_code)]
duration: Option<f64>,

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +43
cmd.arg("build");

for arg in args {
cmd.arg(arg);
}

if verbose > 0 {
let tool = if next_exists { "next" } else { "npx next" };
eprintln!("Running: {} build", tool);
}

let output = cmd.output().context("Failed to run next build (try: npm install -g next)")?;
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let raw = format!("{}\n{}", stdout, stderr);

let filtered = filter_next_build(&raw);

println!("{}", filtered);

tracking::track("next build", "rtk next build", &raw, &filtered);
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The run function always adds "build" as the first argument to the next command. This means the command can only run next build and not other Next.js commands like next dev, next start, or next lint. The CLI in main.rs is defined as Next command but only supports build. Either rename the command to NextBuild or accept a subcommand argument to support other Next.js commands.

Suggested change
cmd.arg("build");
for arg in args {
cmd.arg(arg);
}
if verbose > 0 {
let tool = if next_exists { "next" } else { "npx next" };
eprintln!("Running: {} build", tool);
}
let output = cmd.output().context("Failed to run next build (try: npm install -g next)")?;
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let raw = format!("{}\n{}", stdout, stderr);
let filtered = filter_next_build(&raw);
println!("{}", filtered);
tracking::track("next build", "rtk next build", &raw, &filtered);
// Determine subcommand (default to "build" if none is provided)
let (subcommand, remaining_args) = if !args.is_empty() && !args[0].starts_with('-') {
(args[0].as_str(), &args[1..])
} else {
("build", args)
};
cmd.arg(subcommand);
for arg in remaining_args {
cmd.arg(arg);
}
if verbose > 0 {
let tool = if next_exists { "next" } else { "npx next" };
eprintln!("Running: {} {}", tool, subcommand);
}
let output = cmd
.output()
.context("Failed to run next (try: npm install -g next)")?;
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let raw = format!("{}\n{}", stdout, stderr);
let filtered = if subcommand == "build" {
filter_next_build(&raw)
} else {
// For non-build subcommands, do not apply build-specific filtering.
raw.clone()
};
println!("{}", filtered);
let event = format!("next {}", subcommand);
let label = format!("rtk next {}", subcommand);
tracking::track(&event, &label, &raw, &filtered);

Copilot uses AI. Check for mistakes.

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("prisma generate failed: {}", stderr);
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Prisma commands use anyhow::bail! to handle failures, which means they return errors through the Result type instead of preserving the original exit codes like other commands (tsc, prettier, playwright, next). This creates inconsistent behavior - Prisma commands will exit with code 1 regardless of the actual Prisma CLI exit code, while other commands preserve exit codes for CI/CD compatibility. Consider using std::process::exit(output.status.code().unwrap_or(1)) to be consistent with other commands.

Suggested change
anyhow::bail!("prisma generate failed: {}", stderr);
eprintln!("prisma generate failed: {}", stderr);
std::process::exit(output.status.code().unwrap_or(1));

Copilot uses AI. Check for mistakes.

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
anyhow::bail!("prisma migrate failed: {}", stderr);
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Prisma migrate commands use anyhow::bail! to handle failures, which means they return errors through the Result type instead of preserving the original exit codes like other commands. This creates inconsistent behavior - Prisma commands will exit with code 1 regardless of the actual Prisma CLI exit code. Consider using std::process::exit(output.status.code().unwrap_or(1)) to be consistent with other commands.

Suggested change
anyhow::bail!("prisma migrate failed: {}", stderr);
let exit_code = output.status.code().unwrap_or(1);
eprintln!("prisma migrate failed with exit code {}: {}", exit_code, stderr);
std::process::exit(exit_code);

Copilot uses AI. Check for mistakes.
Comment on lines +102 to +103
// EXCEPTION: Static regex patterns, validated at compile time
// Unwrap is safe here - panic indicates programming error caught during development
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the comment explains that unwrap is safe for compile-time validated regex patterns, this comment is unnecessarily verbose. The lazy_static pattern with Regex::new().unwrap() is a well-established Rust idiom. The comment can be simplified or removed since this pattern is already used elsewhere in the codebase (e.g., in utils.rs and other commands) without explanation.

Suggested change
// EXCEPTION: Static regex patterns, validated at compile time
// Unwrap is safe here - panic indicates programming error caught during development
// Static regex patterns used with lazy_static and Regex::new().unwrap()

Copilot uses AI. Check for mistakes.
&raw,
&filtered,
);

Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lint command does not preserve the exit code from eslint, unlike other commands (tsc, prettier, playwright, next). ESLint typically returns exit code 1 when lint errors are found, and this should be propagated for CI/CD compatibility. The function should call std::process::exit(output.status.code().unwrap_or(1)) if the linter failed, similar to how other commands handle this.

Suggested change
if !output.status.success() {
std::process::exit(output.status.code().unwrap_or(1));
}

Copilot uses AI. Check for mistakes.
// If max_len is too small, just return "..."
"...".to_string()
} else {
format!("{}...", &s[..max_len - 3])
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The string slicing operation &s[..max_len - 3] can panic if s contains multi-byte UTF-8 characters and the slice boundary falls in the middle of a character. Consider using s.char_indices() to find safe boundary points or s.chars().take(max_len - 3).collect() to handle UTF-8 strings safely.

Suggested change
format!("{}...", &s[..max_len - 3])
let prefix: String = s.chars().take(max_len - 3).collect();
format!("{}...", prefix)

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +38
/// Supprime les codes ANSI d'une chaîne (couleurs, styles).
///
/// # Arguments
/// * `text` - Texte contenant potentiellement des codes ANSI
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for the strip_ansi function is written in French, which is inconsistent with the rest of the codebase. All other documentation in the project appears to be in English. The documentation should be translated to English for consistency and broader accessibility.

Suggested change
/// Supprime les codes ANSI d'une chaîne (couleurs, styles).
///
/// # Arguments
/// * `text` - Texte contenant potentiellement des codes ANSI
/// Removes ANSI codes from a string (colors, styles).
///
/// # Arguments
/// * `text` - Text that may contain ANSI codes

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +57
/// Exécute une commande et retourne stdout/stderr nettoyés.
///
/// # Arguments
/// * `cmd` - Commande à exécuter (ex: "eslint")
/// * `args` - Arguments de la commande
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for the execute_command function is written in French, which is inconsistent with the rest of the codebase. All other documentation in the project appears to be in English. The documentation should be translated to English for consistency and broader accessibility.

Suggested change
/// Exécute une commande et retourne stdout/stderr nettoyés.
///
/// # Arguments
/// * `cmd` - Commande à exécuter (ex: "eslint")
/// * `args` - Arguments de la commande
/// Executes a command and returns cleaned stdout/stderr.
///
/// # Arguments
/// * `cmd` - Command to execute (e.g. "eslint")
/// * `args` - Arguments to pass to the command

Copilot uses AI. Check for mistakes.
FlorianBruniaux added a commit to FlorianBruniaux/rtk that referenced this pull request Jan 29, 2026
Add utils.rs with common utilities used by gh_cmd.rs:
- truncate(): Smart string truncation with ellipsis
- strip_ansi(): Remove ANSI escape codes from output
- execute_command(): Centralized command execution

Note: This module is shared with the Modern JS Stack commands
from PR rtk-ai#9, ensuring consistent formatting across all commands.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add benchmarks for the 6 new commands in scripts/benchmark.sh:
- tsc: TypeScript compiler error grouping
- prettier: Format checker with file filtering
- lint: ESLint/Biome grouped violations
- next: Next.js build metrics extraction
- playwright: E2E test failure filtering
- prisma: Prisma CLI without ASCII art

All benchmarks are conditional (skip if tools not available or
not applicable to current project). Tests only run on projects
with package.json and relevant configuration files.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Copy link
Collaborator

@pszymkowiak pszymkowiak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@pszymkowiak pszymkowiak merged commit 88c0174 into rtk-ai:master Jan 29, 2026
1 check failed
FlorianBruniaux added a commit to FlorianBruniaux/rtk that referenced this pull request Jan 29, 2026
- Add utils.rs as Key Architectural Component
- Expand Module Responsibilities table (7→17 modules)
- Document PR rtk-ai#9 in Fork-Specific Features section
- Include token reduction metrics for all new commands
pszymkowiak added a commit that referenced this pull request Jan 29, 2026
feat: add GitHub CLI integration (depends on #9)
FlorianBruniaux added a commit to FlorianBruniaux/rtk that referenced this pull request Jan 30, 2026
Updates documentation to reflect all features added in recent PRs:

**Version Updates**
- Update installation commands to v0.3.1 (DEB/RPM packages)

**New Sections**
- Add Global Flags section (-u/--ultra-compact, -v/--verbose)
- Add JavaScript/TypeScript Stack section (10 new commands)

**New Commands Documented**
- Files: `rtk smart` (heuristic code summary)
- Commands: `rtk gh` (GitHub CLI), `rtk wget`, `rtk config`
- Data: `rtk gain --quota` and `--tier` flags
- Containers: `rtk kubectl services`
- JS/TS Stack: lint, tsc, next, prettier, vitest, playwright, prisma

**Features Coverage**
This update documents functionality from:
- PR rtk-ai#5: Git argument parsing improvements
- PR rtk-ai#6: pnpm support
- PR rtk-ai#9: Modern JavaScript/TypeScript stack support
- PR rtk-ai#10: GitHub CLI integration
- PR rtk-ai#11: Quota analysis features
- PR rtk-ai#14: Additional command improvements

All commands documented are available in v0.3.1.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
FlorianBruniaux added a commit to FlorianBruniaux/rtk that referenced this pull request Jan 30, 2026
Updates documentation to reflect all features added in recent PRs:

**Version Updates**
- Update installation commands to v0.3.1 (DEB/RPM packages)

**New Sections**
- Add Global Flags section (-u/--ultra-compact, -v/--verbose)
- Add JavaScript/TypeScript Stack section (10 new commands)

**New Commands Documented**
- Files: `rtk smart` (heuristic code summary)
- Commands: `rtk gh` (GitHub CLI), `rtk wget`, `rtk config`
- Data: `rtk gain --quota` and `--tier` flags
- Containers: `rtk kubectl services`
- JS/TS Stack: lint, tsc, next, prettier, vitest, playwright, prisma

**Features Coverage**
This update documents functionality from:
- PR rtk-ai#5: Git argument parsing improvements
- PR rtk-ai#6: pnpm support
- PR rtk-ai#9: Modern JavaScript/TypeScript stack support
- PR rtk-ai#10: GitHub CLI integration
- PR rtk-ai#11: Quota analysis features
- PR rtk-ai#14: Additional command improvements

All commands documented are available in v0.3.1.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
ahundt pushed a commit to ahundt/rtk that referenced this pull request Feb 23, 2026
feat: add modern JavaScript tooling support (lint, tsc, next, prettier, playwright, prisma)
ahundt pushed a commit to ahundt/rtk that referenced this pull request Feb 23, 2026
- Add utils.rs as Key Architectural Component
- Expand Module Responsibilities table (7→17 modules)
- Document PR rtk-ai#9 in Fork-Specific Features section
- Include token reduction metrics for all new commands
ahundt pushed a commit to ahundt/rtk that referenced this pull request Feb 23, 2026
feat: add GitHub CLI integration (depends on rtk-ai#9)
ahundt pushed a commit to ahundt/rtk that referenced this pull request Feb 23, 2026
Updates documentation to reflect all features added in recent PRs:

**Version Updates**
- Update installation commands to v0.3.1 (DEB/RPM packages)

**New Sections**
- Add Global Flags section (-u/--ultra-compact, -v/--verbose)
- Add JavaScript/TypeScript Stack section (10 new commands)

**New Commands Documented**
- Files: `rtk smart` (heuristic code summary)
- Commands: `rtk gh` (GitHub CLI), `rtk wget`, `rtk config`
- Data: `rtk gain --quota` and `--tier` flags
- Containers: `rtk kubectl services`
- JS/TS Stack: lint, tsc, next, prettier, vitest, playwright, prisma

**Features Coverage**
This update documents functionality from:
- PR rtk-ai#5: Git argument parsing improvements
- PR rtk-ai#6: pnpm support
- PR rtk-ai#9: Modern JavaScript/TypeScript stack support
- PR rtk-ai#10: GitHub CLI integration
- PR rtk-ai#11: Quota analysis features
- PR rtk-ai#14: Additional command improvements

All commands documented are available in v0.3.1.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
navidemad added a commit to navidemad/rtk that referenced this pull request Mar 1, 2026
- Change run_rails_filtered to accept impl Fn instead of fn pointer,
  enabling closures that capture local state (issue rtk-ai#9)
- Refactor run_routes to use run_rails_filtered with closure capturing
  has_grep flag (~40 lines removed)
- Refactor run_generate to use run_rails_filtered with closure capturing
  generator_type/generator_name (~30 lines removed)
- Replace double MOUNTED_ENGINES iteration (.any + .find) with single
  .find() call (issue rtk-ai#10)
- Replace BTreeMap with HashMap for namespaces in filter_rails_routes
  since data is re-sorted by count anyway (issue rtk-ai#12)
- Remove redundant !t.is_empty() check since t.len() > 1 implies
  non-empty (issue rtk-ai#13)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants