Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d233c38
Port packages/tools Node.js bins to single Rust binary (vtt)
claude Mar 23, 2026
dcec3c4
Fix formatting, duration redaction for nanoseconds, and snapshot rege…
claude Mar 23, 2026
ed5b606
Strip ", <duration> saved" from cache hit summaries for stable snapshots
claude Mar 23, 2026
2c7360a
Fix Windows path redaction for verbatim (\\?\) prefix paths
claude Mar 23, 2026
b6780ab
Fix Windows redaction for Debug-format paths with escaped backslashes
claude Mar 23, 2026
b3a15f5
Collapse double forward slashes from Windows backslash normalization
claude Mar 23, 2026
8761ade
Fix Windows Debug-format path redaction and musl summary formatting
claude Mar 23, 2026
983c89c
Fix Windows Debug-format path redaction in plan test error strings
claude Mar 23, 2026
872af4b
ci: switch tests to --release to measure build+test time impact
claude Mar 24, 2026
72d1ff1
Revert --release tests; optimize insta/similar in dev profile instead
claude Mar 24, 2026
3f6c130
Revert insta/similar opt-level — compilation overhead outweighs gains
claude Mar 24, 2026
af92bc3
Disable debug info in test profile
claude Mar 24, 2026
ebfb5f1
update
branchseer Mar 24, 2026
bb14537
Rename `json-edit` to `json-patch` using the `json-patch` crate (RFC …
branchseer Mar 24, 2026
f99ac17
Resolve vt and vtt runtime paths using compile-time manifest diffing
branchseer Mar 24, 2026
19c3b1f
Make vite_task_tools a library crate with vtt binary in vite_task_bin
branchseer Mar 24, 2026
5b08a47
Disable test/doctest harness for vite_task_tools lib target
branchseer Mar 24, 2026
def26ec
ci: split test step into separate build and run steps
branchseer Mar 24, 2026
d931535
Remove json-patch command; use replace-file-content instead
branchseer Mar 24, 2026
3f992f7
Simplify Args to Task/Tool; remove execute_synthetic and Lint/Test/En…
branchseer Mar 25, 2026
8d7574f
refactor: remove oxfmt dependency from TS type generation
branchseer Mar 23, 2026
e089b46
Port barrier.js to vtt barrier subcommand for concurrent-execution tests
branchseer Mar 26, 2026
dce84cf
Fix CI failures: remove unused deps, fix clippy, add missing test fix…
branchseer Mar 26, 2026
f5e0680
Fix rustdoc HTML tags and regenerate run-config.ts
branchseer Mar 26, 2026
a91e8b7
Replace sleep polling in vtt barrier with notify filesystem watching
branchseer Mar 26, 2026
e22d0d8
simplify daemonize: close stdout/stderr directly instead of dup2 to /…
branchseer Mar 27, 2026
74600ff
remove #[cfg(unix)] gate from daemonize close: libc::close works on W…
branchseer Mar 27, 2026
c5a4fc0
vtt barrier: start watcher before count_matches; use thread::park for…
branchseer Mar 27, 2026
115e378
refactor(vtt): use clap for argument parsing
branchseer Mar 27, 2026
6eeee4f
Revert "refactor(vtt): use clap for argument parsing"
branchseer Mar 27, 2026
b56dd79
refactor(vite_task_bin): make Args private; parse Command directly in…
branchseer Mar 27, 2026
35fc361
remove irrelevant tests
branchseer Mar 27, 2026
3b79e71
refactor(e2e): read CARGO_BIN_EXE_vt/vtt at runtime; remove resolve_r…
branchseer Mar 27, 2026
fe0a395
refactor(plan_snapshots): replace runtime bin resolution with fake-bi…
branchseer Mar 27, 2026
ef424f9
chore(fake-bin): use vtt.cmd instead of vtt.exe; add README
branchseer Mar 27, 2026
1dae6d4
revert: remove redact_error_string; restore inline two-liner from main
branchseer Mar 27, 2026
bbbbac5
fix: remove stale doc comment; add expect for PathBuf in redact.rs; r…
branchseer Mar 27, 2026
cb1e42d
remove packages/tools scripts ported to vtt; update README
branchseer Mar 27, 2026
ebad439
fix(packages/tools): correct README
branchseer Mar 27, 2026
8783407
refactor(vtt): split subcommands into separate files; fix pnpm lockfile
branchseer Mar 27, 2026
b348acc
chore: remove unused pathdiff from workspace dependencies
branchseer Mar 27, 2026
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
20 changes: 17 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,20 @@ jobs:
# Must run after setup-node so correct native binaries are installed
- run: pnpm install

- run: cargo test --target ${{ matrix.target }}
- name: Build tests
run: cargo test --no-run --target ${{ matrix.target }}
if: ${{ matrix.os != 'ubuntu-latest' }}

- run: cargo-zigbuild test --target x86_64-unknown-linux-gnu.2.17
- name: Build tests
run: cargo-zigbuild test --no-run --target x86_64-unknown-linux-gnu.2.17
if: ${{ matrix.os == 'ubuntu-latest' }}

- name: Run tests
run: cargo test --target ${{ matrix.target }}
if: ${{ matrix.os != 'ubuntu-latest' }}

- name: Run tests
run: cargo-zigbuild test --target x86_64-unknown-linux-gnu.2.17
if: ${{ matrix.os == 'ubuntu-latest' }}

test-musl:
Expand Down Expand Up @@ -175,7 +185,11 @@ jobs:
corepack enable
pnpm install

- run: cargo test
- name: Build tests
run: cargo test --no-run

- name: Run tests
run: cargo test

fmt:
name: Format and Check Deps
Expand Down
87 changes: 78 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ os_str_bytes = "7.1.1"
ouroboros = "0.18.5"
owo-colors = { version = "4.1.0", features = ["supports-colors"] }
passfd = { git = "https://github.com/polachok/passfd", rev = "d55881752c16aced1a49a75f9c428d38d3767213", default-features = false }
notify = "8.0.0"
path-clean = "1.0.1"
pathdiff = "0.2.3"
petgraph = "0.8.2"
phf = { version = "0.11.3", features = ["macros"] }
portable-pty = "0.9.0"
Expand Down Expand Up @@ -167,6 +167,9 @@ ignored = [
# and we don't rely on it for debugging that much.
debug = false

[profile.test]
debug = false

[profile.release]
# Configurations explicitly listed here for clarity.
# Using the best options for performance.
Expand Down
8 changes: 6 additions & 2 deletions crates/vite_task_bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ rust-version.workspace = true
name = "vt"
path = "src/main.rs"

[[bin]]
name = "vtt"
path = "src/vtt/main.rs"

[dependencies]
anyhow = { workspace = true }
libc = { workspace = true }
notify = { workspace = true }
async-trait = { workspace = true }
clap = { workspace = true, features = ["derive"] }
jsonc-parser = { workspace = true }
rustc-hash = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }
vite_path = { workspace = true }
Expand All @@ -27,7 +32,6 @@ which = { workspace = true }
cow-utils = { workspace = true }
cp_r = { workspace = true }
insta = { workspace = true, features = ["glob", "json", "redactions", "filters", "ron"] }
pathdiff = { workspace = true }
pty_terminal = { workspace = true }
pty_terminal_test = { workspace = true }
regex = { workspace = true }
Expand Down
77 changes: 22 additions & 55 deletions crates/vite_task_bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::{
};

use clap::Parser;
use rustc_hash::FxHashMap;
use vite_path::AbsolutePath;
use vite_str::Str;
use vite_task::{
Expand Down Expand Up @@ -47,44 +46,25 @@ pub fn find_executable(
Ok(executable_path.into_os_string().into())
}

/// Create a synthetic plan request for running a tool from `node_modules/.bin`.
/// Internal argument parser for `vt`/`vp` commands that appear inside task scripts.
///
/// # Errors
///
/// Returns an error if the executable cannot be found.
fn synthesize_node_modules_bin_task(
executable_name: &str,
args: &[Str],
envs: &Arc<FxHashMap<Arc<OsStr>, Arc<OsStr>>>,
cwd: &Arc<AbsolutePath>,
) -> anyhow::Result<SyntheticPlanRequest> {
Ok(SyntheticPlanRequest {
program: find_executable(get_path_env(envs), cwd, executable_name)?,
args: args.into(),
cache_config: UserCacheConfig::with_config(EnabledCacheConfig {
env: None,
untracked_env: None,
input: None,
}),
envs: Arc::clone(envs),
})
}

/// [`CommandHandler`] uses this to parse the command line when it intercepts a `vt` or `vp`
/// invocation during script execution. It extends [`Command`] with a `tool` subcommand that
/// forwards to the `vtt` test-utility binary — a subcommand that only makes sense within
/// script execution and is therefore not exposed on the top-level `vt` CLI entry point.
#[derive(Debug, Parser)]
#[command(name = "vt", version)]
pub enum Args {
Lint {
enum Args {
/// Forward arguments to the `vtt` test-utility binary.
///
/// Resolves `vtt` via `node_modules/.bin` lookup (same as any other script executable),
/// then synthesizes a cached invocation with the given arguments. The `--` separator,
/// if present, is stripped before forwarding.
Tool {
#[clap(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<Str>,
},
Test {
#[clap(trailing_var_arg = true, allow_hyphen_values = true)]
args: Vec<Str>,
},
EnvTest {
name: Str,
value: Str,
},
/// Any other `vt` subcommand, delegated to the standard [`Command`] parser.
#[command(flatten)]
Task(Command),
}
Expand All @@ -109,30 +89,17 @@ impl vite_task::CommandHandler for CommandHandler {
std::iter::once(command.program.as_str()).chain(command.args.iter().map(Str::as_str)),
)?;
match args {
Args::Lint { args } => Ok(HandledCommand::Synthesized(
synthesize_node_modules_bin_task("oxlint", &args, &command.envs, &command.cwd)?,
)),
Args::Test { args } => Ok(HandledCommand::Synthesized(
synthesize_node_modules_bin_task("vitest", &args, &command.envs, &command.cwd)?,
)),
Args::EnvTest { name, value } => {
let mut envs = FxHashMap::clone(&command.envs);
envs.insert(
Arc::from(OsStr::new(name.as_str())),
Arc::from(OsStr::new(value.as_str())),
);

Args::Tool { args } => {
let program = find_executable(get_path_env(&command.envs), &command.cwd, "vtt")?;
Ok(HandledCommand::Synthesized(SyntheticPlanRequest {
program: find_executable(get_path_env(&envs), &command.cwd, "print-env")?,
args: [name.clone()].into(),
cache_config: UserCacheConfig::with_config({
EnabledCacheConfig {
env: None,
untracked_env: Some(vec![name]),
input: None,
}
program,
args: args.into_iter().filter(|a| a.as_str() != "--").collect(),
cache_config: UserCacheConfig::with_config(EnabledCacheConfig {
env: None,
untracked_env: None,
input: None,
}),
envs: Arc::new(envs),
envs: Arc::clone(&command.envs),
}))
}
Args::Task(parsed) => Ok(HandledCommand::ViteTaskCommand(parsed)),
Expand Down
53 changes: 6 additions & 47 deletions crates/vite_task_bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,18 @@
use std::{process::ExitCode, sync::Arc};
use std::process::ExitCode;

use clap::Parser;
use vite_str::Str;
use vite_task::{
EnabledCacheConfig, ExitStatus, Session, UserCacheConfig, get_path_env,
plan_request::SyntheticPlanRequest,
};
use vite_task_bin::{Args, OwnedSessionConfig, find_executable};
use clap::Parser as _;
use vite_task::{Command, ExitStatus, Session};
use vite_task_bin::OwnedSessionConfig;

#[tokio::main]
async fn main() -> anyhow::Result<ExitCode> {
#[expect(clippy::large_futures, reason = "top-level await in main, no alternative")]
let exit_status = run().await?;
Ok(exit_status.0.into())
}

async fn run() -> anyhow::Result<ExitStatus> {
let args = Args::parse();
let args = Command::parse();
let mut owned_config = OwnedSessionConfig::default();
let session = Session::init(owned_config.as_config())?;
match args {
Args::Task(parsed) => session.main(parsed).await,
args => {
// If env FOO is set, run `print-env FOO` via Session::exec before proceeding.
// In vite-plus, Session::exec is used for auto-install.
let envs = session.envs();
if envs.contains_key(std::ffi::OsStr::new("FOO")) {
let program = find_executable(get_path_env(envs), session.cwd(), "print-env")?;
let request = SyntheticPlanRequest {
program,
args: [Str::from("FOO")].into(),
cache_config: UserCacheConfig::with_config({
EnabledCacheConfig {
env: Some(Box::from([Str::from("FOO")])),
untracked_env: None,
input: None,
}
}),
envs: Arc::clone(envs),
};
let cache_key: Arc<[Str]> = Arc::from([Str::from("print-env-foo")]);
#[expect(
clippy::large_futures,
reason = "execute_synthetic produces a large future"
)]
let status = session.execute_synthetic(request, cache_key, true).await?;
if status != ExitStatus::SUCCESS {
return Ok(status);
}
}
#[expect(clippy::print_stdout, reason = "CLI binary output for non-task commands")]
{
println!("{args:?}");
}
Ok(ExitStatus::SUCCESS)
}
}
session.main(args).await
}
Loading
Loading