Skip to content
Merged
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
21 changes: 19 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ on:
workflow_dispatch:
pull_request:
types: [opened, synchronize]
paths-ignore:
- '**/*.md'
push:
branches:
- main
Expand All @@ -25,7 +23,25 @@ defaults:
shell: bash

jobs:
detect-changes:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
code-changed: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
code:
- '!**/*.md'

test:
needs: detect-changes
if: needs.detect-changes.outputs.code-changed == 'true'
name: Test
strategy:
fail-fast: false
Expand Down Expand Up @@ -132,6 +148,7 @@ jobs:

done:
runs-on: ubuntu-latest
if: always()
needs:
- test
- fmt
Expand Down
182 changes: 55 additions & 127 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# CLAUDE.md

## Project Overview

A monorepo task runner (like nx/turbo) with intelligent caching and dependency resolution.

## Build Commands
# Vite Task

A monorepo task runner (like Nx/Turbo) with intelligent caching and dependency resolution, distributed as the `vp run` command in [Vite+](https://github.com/voidzero-dev/vite-plus).

## Repository Structure

- `crates/vite_task` — Task execution engine with caching and session management
- `crates/vite_task_bin` — Internal dev CLI binary (`vt`) and task synthesizer
- `crates/vite_task_graph` — Task dependency graph construction and config loading
- `crates/vite_task_plan` — Execution planning (resolves env vars, working dirs, commands)
- `crates/vite_workspace` — Workspace detection and package dependency graph
- `crates/fspy*` — File system access tracing (9 crates: supervisor, preload libs, platform backends)
- `crates/pty_terminal*` — Cross-platform headless terminal emulator (3 crates)
- `crates/vite_path` — Type-safe absolute/relative path system
- `crates/vite_str` — Stack-allocated compact string type
- `crates/vite_glob` — Glob pattern matching
- `crates/vite_shell` — Shell command parsing
- `crates/vite_select` — Interactive fuzzy selection UI
- `crates/vite_tui` — Terminal UI components (WIP, unfinished)
- `crates/vite_graph_ser` — Graph serialization utilities
- `crates/subprocess_test` — Subprocess testing framework
- `packages/tools` — Node.js test utilities (print, json-edit, check-tty, etc.)
- `docs/` — Documentation (inputs configuration guide)

## Development Commands

```bash
just init # Install build tools and dependencies
Expand All @@ -30,96 +48,37 @@ INSTA_UPDATE=always cargo test # Update snapshots

Integration tests (e2e, plan, fspy) require `pnpm install` in `packages/tools` first. You don't need `pnpm install` in test fixture directories.

Test fixtures and snapshots:
### Test Fixtures

- **Plan**: `crates/vite_task_plan/tests/plan_snapshots/fixtures/` - quicker, sufficient for testing behaviour before actual execution:
- task graph
- resolved configurations
- resolved program paths, cwd, and env vars
- **E2E**: `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` - needed for testing execution and beyond: caching, output styling
- **Plan**: `crates/vite_task_plan/tests/plan_snapshots/fixtures/` — quicker, sufficient for testing task graph, resolved configs, program paths, cwd, and env vars
- **E2E**: `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` — needed for testing execution, caching, output styling

### Cross-Platform Testing

**CRITICAL**: This project must work on both Unix (macOS/Linux) and Windows. For any cross-platform features:

1. **No Platform Skipping**: Skipping tests on either platform is **UNACCEPTABLE**
- Use `#[cfg(unix)]` and `#[cfg(windows)]` for platform-specific code within tests
- Both platforms must execute the test and verify the feature works correctly
- If a feature can't work on a platform, it shouldn't be added
**CRITICAL**: This project must work on both Unix (macOS/Linux) and Windows. Skipping tests on either platform is **UNACCEPTABLE**.

2. **Windows Cross-Testing from macOS**:
`cargo xtest` cross-compiles the test binary and runs it on a real remote Windows environment (not emulation). The filesystem is bridged so the test can access local fixture files.
```bash
cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p <package> --test <test>
- Use `#[cfg(unix)]` and `#[cfg(windows)]` for platform-specific code within tests
- Both platforms must execute the test and verify the feature works correctly
- Use cross-platform libraries for common operations (e.g., `terminal_size` for terminal dimensions)

# Examples:
cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p pty_terminal --test terminal
cargo xtest --builder cargo-xwin --target aarch64-pc-windows-msvc -p pty_terminal --test terminal -- resize_terminal
```
## Architecture

3. **Cross-Platform Test Design Patterns**:
- Use conditional compilation for platform-specific setup/assertions
- Use cross-platform libraries for common operations (e.g., `terminal_size` for terminal dimensions)
- Verify platform-specific behavior works as expected:
- **Unix**: SIGWINCH signals, ioctl, /dev/null, etc.
- **Windows**: ConPTY, GetConsoleScreenBufferInfo, NUL, etc.
### Task Execution Pipeline

4. **Example**: The `pty_terminal::resize_terminal` test demonstrates proper cross-platform testing:
- Unix: Installs SIGWINCH handler to verify signal delivery
- Windows: Acknowledges synchronous ConPTY resize behavior
- Both: Query terminal size using cross-platform `terminal_size` crate
- Both: Verify resize actually works and returns correct dimensions

## CLI Usage

```bash
# Run a task defined in vite-task.json
vt run <task> # run task in current package
vt run <package>#<task> # run task in specific package
vt run <task> -r # run task in all packages (recursive)
vt run <task> -t # run task in current package + transitive deps
vt run <task> -- --extra --args # pass extra args to the task command
vt run # interactive task selector (fuzzy search)

# Built-in commands (run tools from node_modules/.bin)
vt test [args...] # run vitest
vt lint [args...] # run oxlint

# Cache management
vt cache clean # remove the cache database

# Package selection flags
-r, --recursive # select all packages in the workspace
-t, --transitive # select current package + transitive deps
-w, --workspace-root # select the workspace root package
-F, --filter <pattern> # pnpm-style filter (repeatable, see below)

# Run flags
--ignore-depends-on # skip explicit dependsOn dependencies
-v, --verbose # show full detailed summary after execution
--cache # force caching on for all tasks and scripts
--no-cache # force caching off for all tasks and scripts
--last-details # show detailed summary of the last run

# Filter patterns (pnpm-style)
-F <name> # select by package name
-F '@scope/*' # select by glob pattern
-F ./<dir> # select packages under a directory
-F '<pattern>...' # select package and its dependencies
-F '...<pattern>' # select package and its dependents
-F '!<pattern>' # exclude packages matching pattern
```
CLI (vite_task_bin) → Task Graph (vite_task_graph) → Plan (vite_task_plan) → Execution (vite_task)
↑ ↓
vite_workspace fspy (file tracing)
```

## Key Architecture
### Task Dependencies

- **vite_task** - Main task runner with caching and session management
- **vite_task_bin** - CLI binary (`vt` command) and task synthesizer
- **vite_task_graph** - Task dependency graph construction and config loading
- **vite_task_plan** - Execution planning (resolves env vars, working dirs, commands)
- **vite_workspace** - Workspace detection and package dependency graph
- **fspy** - File system access tracking for precise cache invalidation
1. **Explicit**: Defined via `dependsOn` in `vite-task.json` (skip with `--ignore-depends-on`)
2. **Topological**: Based on package.json dependencies
- With `-r/--recursive`: runs task across all packages in dependency order
- With `-t/--transitive`: runs task in current package and its dependencies

## Task Configuration
### Task Configuration

Tasks are defined in `vite-task.json`:

Expand All @@ -140,37 +99,11 @@ Tasks are defined in `vite-task.json`:
}
```

- `cache` (root): workspace-wide cache toggle. Default: `{ "scripts": false, "tasks": true }`
- `command`: shell command to run (required)
- `cwd`: working directory relative to the package root
- `dependsOn`: explicit task dependencies (`taskName` or `package#task`)
- `cache` (task): enable/disable caching for this task (default: `true`)
- `env`: env var names to fingerprint and pass to the task
- `untrackedEnv`: env var names to pass without fingerprinting
- `input`: files for cache fingerprinting (globs, `{ "auto": true }`, negation patterns)

## Task Dependencies

1. **Explicit**: Defined via `dependsOn` in `vite-task.json` (skip with `--ignore-depends-on`)
2. **Topological**: Based on package.json dependencies
- With `-r/--recursive`: runs task across all packages in dependency order
- With `-t/--transitive`: runs task in current package and its dependencies

## Cross-Platform Linting

After major changes (especially to `fspy*` or platform-specific crates), run cross-platform clippy before pushing:

```bash
just lint # native (host platform)
just lint-linux # Linux via cargo-zigbuild
just lint-windows # Windows via cargo-xwin
```

## Code Constraints

### Required Patterns

These patterns are enforced by `.clippy.toml`:
Enforced by `.clippy.toml`:

| Instead of | Use |
| ----------------------------------- | ---------------------------------------- |
Expand All @@ -181,28 +114,23 @@ These patterns are enforced by `.clippy.toml`:
| `std::env::current_dir` | `vite_path::current_dir` |
| `.to_lowercase()`/`.to_uppercase()` | `cow_utils` methods |

### Path Type System

- Use `AbsolutePath` for internal data flow; only convert to `RelativePath` when saving to cache
- Use methods like `strip_prefix`/`join` from `vite_path` instead of converting to std paths
- Only convert to std paths when interfacing with std library functions
- Add necessary methods in `vite_path` instead of falling back to std path types

### Cross-Platform Requirements

**All code must work on both Unix and Windows without platform skipping:**
All code must work on both Unix and Windows without platform skipping:

- Use `#[cfg(unix)]` / `#[cfg(windows)]` for platform-specific implementations
- Always test on both platforms (use `cargo xtest` for Windows cross-compilation)
- Platform differences should be handled gracefully, not skipped
- Document platform-specific behavior in code comments

## Path Type System

- **Type Safety**: All paths use typed `vite_path` instead of `std::path`
- **Absolute Paths**: `vite_path::AbsolutePath` / `AbsolutePathBuf`
- **Relative Paths**: `vite_path::RelativePath` / `RelativePathBuf`

- **Usage Guidelines**:
- Use `AbsolutePath` for internal data flow; only convert to `RelativePath` when saving to cache
- Use methods like `strip_prefix`/`join` from `vite_path` instead of converting to std paths
- Only convert to std paths when interfacing with std library functions
- Add necessary methods in `vite_path` instead of falling back to std path types
- After major changes to `fspy*` or platform-specific crates, run `just lint-linux` and `just lint-windows`

## Quick Reference

- **Task Format**: `package#task` (e.g., `app#build`, `@test/utils#lint`)
- **Config File**: `vite-task.json` in each package
- **Rust Edition**: 2024, MSRV 1.88.0
101 changes: 101 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Contributing to Vite Task

## Prerequisites

- [Rust](https://rustup.rs/) (see [rust-toolchain.toml](rust-toolchain.toml) for the required version)
- [Node.js](https://nodejs.org/) (^20.19.0 || >=22.12.0)
- [pnpm](https://pnpm.io/) (10.x)
- [just](https://just.systems/) — task runner for build commands
- [cargo-binstall](https://github.com/cargo-bins/cargo-binstall) — for installing Rust tools

## Initial Setup

```bash
just init
```

This installs all required Rust tools (`cargo-insta`, `typos-cli`, `cargo-shear`, `dprint`, `taplo-cli`) and bootstraps the Node.js tooling.

## Development Workflow

Officially, Vite Task is distributed as part of Vite+ and invoked via `vp run`. The `vt` binary (`vite_task_bin` crate) is an internal development CLI for working on this repo in pure Rust without building the full Vite+ stack. Use `cargo run --bin vt` to build and run locally during development. Don't reference `vt` in user-facing documentation — it's not a public interface.

| | `vp run` (Vite+) | `vt run` (this repo) |
| ------------ | -------------------------------------------- | -------------------- |
| Purpose | End-user CLI | Internal dev/testing |
| Config | `vite.config.ts` (`run` block) | `vite-task.json` |
| Distribution | Bundled in Vite+ | `cargo run --bin vt` |
| Scope | Full toolchain (dev, build, test, lint, ...) | Task runner only |

```bash
just ready # Full quality check: typos, fmt, check, test, lint, doc
just fmt # Format code (cargo fmt + cargo shear + dprint)
just check # Check compilation with all features
just test # Run all tests
just lint # Clippy linting
just doc # Generate documentation
```

### Running Specific Tests

```bash
cargo test # All tests
cargo test -p vite_task_bin --test e2e_snapshots # E2E snapshot tests
cargo test -p vite_task_plan --test plan_snapshots # Plan snapshot tests
cargo test --test e2e_snapshots -- stdin # Filter by test name
INSTA_UPDATE=always cargo test # Update snapshots
```

Integration tests (e2e, plan, fspy) require `pnpm install` in `packages/tools` first. You don't need `pnpm install` in test fixture directories.

### Test Fixtures

- **Plan snapshots** — `crates/vite_task_plan/tests/plan_snapshots/fixtures/` — quicker, sufficient for testing task graph, resolved configs, program paths, cwd, and env vars
- **E2E snapshots** — `crates/vite_task_bin/tests/e2e_snapshots/fixtures/` — needed for testing actual execution, caching behavior, and output styling

See individual crate READMEs for crate-specific testing details.

## Cross-Platform Development

This project must work on macOS, Linux, and Windows. Skipping tests on any platform is not acceptable.

- Use `#[cfg(unix)]` / `#[cfg(windows)]` for platform-specific code
- Use cross-platform libraries where possible (e.g., `terminal_size` instead of raw ioctl/ConPTY)

### Cross-Platform Linting

After changes to `fspy*` or platform-specific crates, run cross-platform clippy:

```bash
just lint # Native (host platform)
just lint-linux # Linux via cargo-zigbuild
just lint-windows # Windows via cargo-xwin
```

## Code Conventions

### Required Patterns

These are enforced by `.clippy.toml`:

| Instead of | Use |
| ------------------------------------- | ------------------------------------------ |
| `HashMap` / `HashSet` | `FxHashMap` / `FxHashSet` from rustc-hash |
| `std::path::Path` / `PathBuf` | `vite_path::AbsolutePath` / `RelativePath` |
| `std::format!` | `vite_str::format!` |
| `String` (for small strings) | `vite_str::Str` |
| `std::env::current_dir` | `vite_path::current_dir` |
| `.to_lowercase()` / `.to_uppercase()` | `cow_utils` methods |

### Path Type System

All paths use `vite_path` for type safety:

- **`AbsolutePath` / `AbsolutePathBuf`** — for internal data flow
- **`RelativePath` / `RelativePathBuf`** — for cache storage and display

Use `vite_path` methods (`strip_prefix`, `join`, etc.) instead of converting to `std::path`. Only convert to std paths when interfacing with std library functions. Add necessary methods to `vite_path` rather than falling back.

## macOS Performance Tip

Add your terminal app to the approved "Developer Tools" in System Settings > Privacy & Security. Your Rust builds will be ~30% faster.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
# Vite Task

Monorepo task runner with intelligent caching and dependency-aware scheduling, powering [`vp run`](https://github.com/voidzero-dev/vite-plus) in [Vite+](https://viteplus.dev).

## Getting Started

Install [Vite+](https://viteplus.dev), then run tasks from your workspace. See the [documentation](https://viteplus.dev/guide/run) for full usage.

```bash
vp run build # run a task in the current package
vp run build -r # run across all packages in dependency order
vp run @my/app#build -t # run in a package and its transitive dependencies
vp run --cache build # run with caching enabled
```

## License

[MIT](LICENSE)

Copyright (c) 2026-present [VoidZero Inc.](https://voidzero.dev/)
Loading