rtk-ai/rtk

feat(registry): rewrite-layer normalization for pnpm --filter

Open

#513 opened on Mar 11, 2026

View on GitHub
 (1 comment) (0 reactions) (0 assignees)Rust (2,914 forks)batch import
area:clieffort-mediumenhancementhelp wantedpriority:medium

Repository metrics

Stars
 (48,085 stars)
PR merge metrics
 (Avg merge 11d 1h) (45 merged PRs in 30d)

Description

Part of #512 — pnpm workspace filter support.

Phase 1: src/discover/registry.rs

1a. Add PNPM_FILTER_RE to the existing lazy_static! block

static ref PNPM_FILTER_RE: Regex = Regex::new(
    r"^pnpm\s+(?:--filter|-F)\s+(\S+)\s+(.+)$"
).unwrap();

1b. Add strip_pnpm_workspace_flag()

fn strip_pnpm_workspace_flag(cmd: &str) -> Option<(&str, &str)> {
    PNPM_FILTER_RE.captures(cmd).and_then(|caps| {
        let m1 = caps.get(1)?;
        let m2 = caps.get(2)?;
        Some((&cmd[m1.start()..m1.end()], &cmd[m2.start()..m2.end()]))
    })
}

1c. Add inject_pnpm_filter()

fn inject_pnpm_filter(rtk_cmd: &str, workspace: &str) -> String {
    let mut parts = rtk_cmd.splitn(3, ' ');
    let rtk = parts.next().unwrap_or("rtk");
    let cmd = parts.next().unwrap_or("");
    match parts.next() {
        Some(rest) => format!("{} {} --pnpm-filter {} {}", rtk, cmd, workspace, rest),
        None => format!("{} {} --pnpm-filter {}", rtk, cmd, workspace),
    }
}

1d. Extract rewrite_core() from rewrite_segment()

Extract the classify+rule-match+prefix-replace logic into a standalone fn that operates on pre-cleaned commands (no env prefix). This avoids recursive rewrite_segment() calls that would re-trigger env prefix stripping, head -N special cases, etc.

1e. Update rewrite_segment()

New structure: env_prefix strip → head check → RTK_DISABLED check → pnpm filter strip → rewrite_core() → re-add env_prefix

if let Some((workspace, inner_cmd)) = strip_pnpm_workspace_flag(cmd_clean) {
    if let Some(rewritten) = rewrite_core(inner_cmd, excluded) {
        return Some(format!("{}{}", env_prefix, inject_pnpm_filter(&rewritten, workspace)));
    }
    let pnpm_cmd = format!("pnpm {}", inner_cmd);
    if let Some(rewritten) = rewrite_core(&pnpm_cmd, excluded) {
        return Some(format!("{}{}", env_prefix, inject_pnpm_filter(&rewritten, workspace)));
    }
    return None;
}

1f. Update classify_command() for rtk discover

After env prefix strip, before RegexSet check:

if let Some((_workspace, inner_cmd)) = strip_pnpm_workspace_flag(cmd_clean) {
    let inner_class = classify_command(inner_cmd);
    if matches!(inner_class, Classification::Supported { .. }) {
        return inner_class;
    }
    let pnpm_cmd = format!("pnpm {}", inner_cmd);
    return classify_command(&pnpm_cmd);
}

Recursion is safe: inner_cmd won't start with pnpm --filter.

Tests to add

rewrite_command("pnpm --filter web prettier --check .", &[])  →  "rtk prettier --pnpm-filter web --check ."
rewrite_command("pnpm -F web tsc --noEmit", &[])              →  "rtk tsc --pnpm-filter web --noEmit"
rewrite_command("pnpm --filter web vitest run", &[])          →  "rtk vitest --pnpm-filter web run"
rewrite_command("pnpm --filter web list", &[])                →  "rtk pnpm --pnpm-filter web list"
rewrite_command("pnpm --filter @scope/pkg lint", &[])         →  "rtk lint --pnpm-filter @scope/pkg"
rewrite_command("sudo pnpm --filter web prettier", &[])       →  "sudo rtk prettier --pnpm-filter web"
rewrite_command("pnpm list", &[])                             →  "rtk pnpm list"  (unchanged)
rewrite_command("pnpm --filter web unknown-cmd", &[])         →  None
classify_command("pnpm --filter web prettier")                →  Supported
classify_command("pnpm --filter web list")                    →  Supported

Contributor guide