diff --git a/Cargo.lock b/Cargo.lock
index 3d25e15816..6e05e1956f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1902,7 +1902,7 @@ dependencies = [
 [[package]]
 name = "fspy"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "bstr",
@@ -1937,7 +1937,7 @@ dependencies = [
 [[package]]
 name = "fspy_detours_sys"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "cc",
  "winapi",
@@ -1946,7 +1946,7 @@ dependencies = [
 [[package]]
 name = "fspy_preload_unix"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "bstr",
@@ -1961,7 +1961,7 @@ dependencies = [
 [[package]]
 name = "fspy_preload_windows"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "constcat",
  "fspy_detours_sys",
@@ -1977,7 +1977,7 @@ dependencies = [
 [[package]]
 name = "fspy_seccomp_unotify"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "futures-util",
  "libc",
@@ -1994,18 +1994,18 @@ dependencies = [
 [[package]]
 name = "fspy_shared"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "bitflags 2.11.0",
  "bstr",
  "bumpalo",
  "bytemuck",
  "native_str",
- "os_str_bytes",
  "shared_memory",
  "thiserror 2.0.18",
  "tracing",
  "uuid",
+ "vite_path",
  "winapi",
  "wincode",
 ]
@@ -2013,7 +2013,7 @@ dependencies = [
 [[package]]
 name = "fspy_shared_unix"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "base64 0.22.1",
@@ -2506,7 +2506,7 @@ dependencies = [
  "libc",
  "percent-encoding",
  "pin-project-lite",
- "socket2 0.6.3",
+ "socket2 0.5.10",
  "system-configuration",
  "tokio",
  "tower-service",
@@ -3162,7 +3162,7 @@ dependencies = [
 [[package]]
 name = "materialized_artifact"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "tempfile",
 ]
@@ -3170,7 +3170,7 @@ dependencies = [
 [[package]]
 name = "materialized_artifact_build"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "xxhash-rust",
 ]
@@ -3384,7 +3384,7 @@ dependencies = [
 [[package]]
 name = "native_str"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "bumpalo",
  "bytemuck",
@@ -4853,7 +4853,7 @@ dependencies = [
 [[package]]
 name = "pty_terminal_test_client"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 
 [[package]]
 name = "quote"
@@ -7588,10 +7588,10 @@ dependencies = [
 [[package]]
 name = "vite_glob"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
+ "globset",
  "thiserror 2.0.18",
- "vite_path",
  "wax 0.7.0",
 ]
 
@@ -7635,7 +7635,7 @@ dependencies = [
 [[package]]
 name = "vite_graph_ser"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "petgraph 0.8.3",
  "serde",
@@ -7734,9 +7734,10 @@ dependencies = [
 [[package]]
 name = "vite_path"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "diff-struct",
+ "os_str_bytes",
  "path-clean",
  "ref-cast",
  "serde",
@@ -7765,7 +7766,7 @@ dependencies = [
 [[package]]
 name = "vite_powershell"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "vite_path",
  "which",
@@ -7774,7 +7775,7 @@ dependencies = [
 [[package]]
 name = "vite_select"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "crossterm",
@@ -7826,7 +7827,7 @@ dependencies = [
 [[package]]
 name = "vite_shell"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "brush-parser 0.4.0",
  "diff-struct",
@@ -7853,7 +7854,7 @@ dependencies = [
 [[package]]
 name = "vite_str"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "compact_str",
  "diff-struct",
@@ -7864,7 +7865,7 @@ dependencies = [
 [[package]]
 name = "vite_task"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anstream",
  "anyhow",
@@ -7874,6 +7875,8 @@ dependencies = [
  "derive_more",
  "fspy",
  "futures-util",
+ "materialized_artifact",
+ "materialized_artifact_build",
  "nix 0.31.2",
  "once_cell",
  "owo-colors",
@@ -7892,11 +7895,15 @@ dependencies = [
  "tracing",
  "twox-hash",
  "uuid",
+ "vite_glob",
  "vite_path",
  "vite_select",
  "vite_str",
+ "vite_task_client_napi",
  "vite_task_graph",
+ "vite_task_ipc_shared",
  "vite_task_plan",
+ "vite_task_server",
  "vite_workspace",
  "wax 0.7.0",
  "winapi",
@@ -7904,10 +7911,35 @@ dependencies = [
  "zstd",
 ]
 
+[[package]]
+name = "vite_task_client"
+version = "0.0.0"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
+dependencies = [
+ "native_str",
+ "rustc-hash",
+ "vite_path",
+ "vite_task_ipc_shared",
+ "winapi",
+ "wincode",
+]
+
+[[package]]
+name = "vite_task_client_napi"
+version = "0.1.0"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
+dependencies = [
+ "napi",
+ "napi-build",
+ "napi-derive",
+ "vite_str",
+ "vite_task_client",
+]
+
 [[package]]
 name = "vite_task_graph"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -7926,10 +7958,20 @@ dependencies = [
  "wincode",
 ]
 
+[[package]]
+name = "vite_task_ipc_shared"
+version = "0.0.0"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
+dependencies = [
+ "native_str",
+ "rustc-hash",
+ "wincode",
+]
+
 [[package]]
 name = "vite_task_plan"
 version = "0.1.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -7954,6 +7996,26 @@ dependencies = [
  "wincode",
 ]
 
+[[package]]
+name = "vite_task_server"
+version = "0.0.0"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
+dependencies = [
+ "futures",
+ "native_str",
+ "rustc-hash",
+ "tempfile",
+ "thiserror 2.0.18",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "uuid",
+ "vite_glob",
+ "vite_path",
+ "vite_task_ipc_shared",
+ "wincode",
+]
+
 [[package]]
 name = "vite_trampoline"
 version = "0.0.0"
@@ -7961,7 +8023,7 @@ version = "0.0.0"
 [[package]]
 name = "vite_workspace"
 version = "0.0.0"
-source = "git+https://github.com/voidzero-dev/vite-task.git?rev=5833b374c6edb05c2f2f8e133ff8c796b378472a#5833b374c6edb05c2f2f8e133ff8c796b378472a"
+source = "git+https://github.com/voidzero-dev/vite-task.git?rev=82ec12b2956c81f55e40749f65c062ab368a09e7#82ec12b2956c81f55e40749f65c062ab368a09e7"
 dependencies = [
  "clap",
  "petgraph 0.8.3",
diff --git a/Cargo.toml b/Cargo.toml
index 821eb36ca4..8e7b4c7a6f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -193,7 +193,7 @@ dunce = "1.0.5"
 fast-glob = "1.0.0"
 flate2 = { version = "=1.1.9", features = ["zlib-rs"] }
 form_urlencoded = "1.2.1"
-fspy = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
+fspy = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
 futures = "0.3.31"
 futures-util = "0.3.31"
 glob = "0.3.2"
@@ -303,11 +303,11 @@ vite_pm_cli = { path = "crates/vite_pm_cli" }
 vite_setup = { path = "crates/vite_setup" }
 vite_shared = { path = "crates/vite_shared" }
 vite_static_config = { path = "crates/vite_static_config" }
-vite_path = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
-vite_powershell = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
-vite_str = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
-vite_task = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
-vite_workspace = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "5833b374c6edb05c2f2f8e133ff8c796b378472a" }
+vite_path = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
+vite_powershell = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
+vite_str = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
+vite_task = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
+vite_workspace = { git = "https://github.com/voidzero-dev/vite-task.git", rev = "82ec12b2956c81f55e40749f65c062ab368a09e7" }
 walkdir = "2.5.0"
 wax = "0.6.0"
 which = "8.0.0"
diff --git a/docs/config/run.md b/docs/config/run.md
index f4d7b6417d..b7075c8faf 100644
--- a/docs/config/run.md
+++ b/docs/config/run.md
@@ -167,8 +167,8 @@ Environment variables included in the cache fingerprint. When any listed variabl
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  compile: {
+    command: 'webpack --mode production',
     env: ['NODE_ENV'],
   },
 }
@@ -190,8 +190,8 @@ Environment variables passed to the task process but **not** included in the cac
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  deploy: {
+    command: 'node scripts/deploy-preview.mjs',
     untrackedEnv: ['CI', 'GITHUB_ACTIONS'],
   },
 }
@@ -215,8 +215,8 @@ Vite Task automatically detects which files are used by a command (see [Automati
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  typecheck: {
+    command: 'tsc -p tsconfig.json',
     // Use `{ auto: true }` to use automatic fingerprinting (default).
     input: [{ auto: true }, '!**/*.tsbuildinfo', '!dist/**'],
   },
@@ -227,8 +227,8 @@ tasks: {
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  typecheck: {
+    command: 'tsc -p tsconfig.json',
     input: ['src/**/*.ts', 'vite.config.ts'],
   },
 }
@@ -238,8 +238,8 @@ tasks: {
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  docs: {
+    command: 'node scripts/build-docs.mjs',
     input: [
       { auto: true },
       { pattern: 'shared-config/**', base: 'workspace' },
@@ -270,26 +270,50 @@ String glob patterns are resolved relative to the package directory by default.
 
 ### `output`
 
-- **Type:** `Array<string | { pattern: string, base: "workspace" | "package" }>`
-- **Default:** `[]` (nothing is archived)
+- **Type:** `Array<string | { auto: boolean } | { pattern: string, base: "workspace" | "package" }>`
+- **Default:** `[{ auto: true }]` (auto-inferred)
+
+Files the task produces. By default, Vite Task automatically detects files written by the command, archives them after a successful run, and restores them on a cache hit so you don't have to rebuild them.
 
-Files the task produces. They get archived after a successful run and restored on a cache hit, so you don't have to rebuild them. Leave it empty (or omit it) and nothing is archived.
+**Exclude files** from automatic output tracking:
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  assets: {
+    command: 'node scripts/generate-assets.mjs',
+    output: [{ auto: true }, '!dist/cache/**'],
+  },
+}
+```
+
+**Specify explicit output files** only without automatic tracking:
+
+```ts [vite.config.ts]
+tasks: {
+  assets: {
+    command: 'node scripts/generate-assets.mjs',
     output: ['dist/**', '!dist/cache/**'],
   },
 }
 ```
 
+**Disable output restoration** entirely and cache only terminal output:
+
+```ts [vite.config.ts]
+tasks: {
+  report: {
+    command: 'node scripts/generate-report.mjs',
+    output: [],
+  },
+}
+```
+
 If a task writes outside its own package, use the object form with `base: "workspace"`:
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
+  assets: {
+    command: 'node scripts/generate-assets.mjs',
     output: [
       'dist/**',
       { pattern: 'shared-artifacts/**', base: 'workspace' },
diff --git a/docs/guide/cache.md b/docs/guide/cache.md
index fd034e0249..1f5bf896eb 100644
--- a/docs/guide/cache.md
+++ b/docs/guide/cache.md
@@ -10,21 +10,20 @@ When a task runs successfully (exit code 0), its terminal output (stdout/stderr)
 2. **Environment variables:** did any [fingerprinted env vars](/config/run#env) change?
 3. **Input files:** did any file that the command reads change?
 
-If everything matches, the cached output is replayed instantly, and the command does not run.
+If everything matches, the cached terminal output is replayed instantly, written files are restored, and the command does not run.
 
 ::: info
-By default, only terminal output is cached and replayed. To cache files produced by a task, configure [`output`](/config/run#output) globs. Matching files are archived after a successful run and restored on a cache hit.
+By default, Vite Task automatically tracks files produced by a task, archives them after a successful run, and restores them on a cache hit. Use [`output`](/config/run#output) to limit, exclude, or disable file restoration.
 :::
 
 ```ts [vite.config.ts]
 tasks: {
-  build: {
-    command: 'vp build',
-    output: ['dist/**'],
-  },
+  build: 'vp build',
 }
 ```
 
+`vp build` works with zero cache config: Vite Task infers both the files read by the build and the files written by the build.
+
 When a cache miss occurs, Vite Task tells you exactly why:
 
 ```
diff --git a/packages/cli/binding/src/cli/resolver.rs b/packages/cli/binding/src/cli/resolver.rs
index 0b6d05a4d9..c98ebddb1c 100644
--- a/packages/cli/binding/src/cli/resolver.rs
+++ b/packages/cli/binding/src/cli/resolver.rs
@@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
 use vite_path::AbsolutePath;
 use vite_str::Str;
 use vite_task::config::user::{
-    AutoInput, EnabledCacheConfig, GlobWithBase, InputBase, UserCacheConfig, UserInputEntry,
+    AutoTracking, EnabledCacheConfig, GlobWithBase, InputBase, UserCacheConfig, UserInputEntry,
 };
 
 use super::{
@@ -171,10 +171,16 @@ impl SubcommandResolver {
                         .chain(iter::once(Str::from("build")))
                         .chain(args.into_iter().map(Str::from))
                         .collect(),
+                    // No synthetic cache config: vite reports its inputs/outputs/
+                    // envs to the runner via `@voidzero-dev/vite-task-client`.
+                    // All fields `None` keep caching enabled with auto input and
+                    // auto output inference (the latter drives output restoration);
+                    // vite's `ignoreInput`/`ignoreOutput`/`getEnv`/`getEnvs` refine
+                    // the fingerprint at runtime.
                     cache_config: UserCacheConfig::with_config(EnabledCacheConfig {
-                        env: Some(Box::new([Str::from("VITE_*")])),
+                        env: None,
                         untracked_env: None,
-                        input: Some(build_pack_cache_inputs()),
+                        input: None,
                         output: None,
                     }),
                     envs: merge_resolved_envs_with_version(envs, resolved.envs),
@@ -201,7 +207,7 @@ impl SubcommandResolver {
                         env: None,
                         untracked_env: None,
                         input: Some(vec![
-                            UserInputEntry::Auto(AutoInput { auto: true }),
+                            UserInputEntry::Auto(AutoTracking { auto: true }),
                             exclude_glob("!node_modules/.vite-temp/**", InputBase::Package),
                             exclude_glob(
                                 "!node_modules/.vite/vitest/**/results.json",
@@ -313,7 +319,7 @@ fn exclude_glob(pattern: &str, base: InputBase) -> UserInputEntry {
 /// by a runner-aware approach that automatically excludes task output directories.
 fn build_pack_cache_inputs() -> Vec<UserInputEntry> {
     vec![
-        UserInputEntry::Auto(AutoInput { auto: true }),
+        UserInputEntry::Auto(AutoTracking { auto: true }),
         exclude_glob("!node_modules/.vite-temp/**", InputBase::Workspace),
         exclude_glob("!node_modules/.vite-temp/**", InputBase::Package),
         exclude_glob("!dist/**", InputBase::Package),
@@ -327,7 +333,7 @@ fn build_pack_cache_inputs() -> Vec<UserInputEntry> {
 /// - `.vite/task-cache`: task runner state files that change after each run
 pub(super) fn check_cache_inputs() -> Vec<UserInputEntry> {
     vec![
-        UserInputEntry::Auto(AutoInput { auto: true }),
+        UserInputEntry::Auto(AutoTracking { auto: true }),
         exclude_glob("!node_modules/.vite-temp/**", InputBase::Workspace),
         exclude_glob("!node_modules/.vite-temp/**", InputBase::Package),
         exclude_glob("!node_modules/.vite/task-cache/**", InputBase::Workspace),
diff --git a/packages/cli/snap-tests/build-vite-env/snap.txt b/packages/cli/snap-tests/build-vite-env/snap.txt
index ff5a11ea04..54e5eb28ea 100644
--- a/packages/cli/snap-tests/build-vite-env/snap.txt
+++ b/packages/cli/snap-tests/build-vite-env/snap.txt
@@ -25,7 +25,7 @@ dist/assets/index-Dra_-aT4.js  <variable> kB │ gzip: <variable> kB
 vp run: cache hit, <variable>ms saved.
 
 > VITE_MY_VAR=2 vp run build # env changed, should miss cache
-$ vp build ○ cache miss: envs changed, executing
+$ vp build ○ cache miss: env 'VITE_MY_VAR' changed, executing
 vite v<semver> building client environment for production...
 transforming...✓ <variable> modules transformed.
 rendering chunks...
diff --git a/packages/cli/snap-tests/plain-terminal-ui-nested/snap.txt b/packages/cli/snap-tests/plain-terminal-ui-nested/snap.txt
index afafa585f9..ffa975a06b 100644
--- a/packages/cli/snap-tests/plain-terminal-ui-nested/snap.txt
+++ b/packages/cli/snap-tests/plain-terminal-ui-nested/snap.txt
@@ -8,17 +8,17 @@ Found 0 warnings and 0 errors.
 Finished in <variable>ms on 3 files with <variable> rules using <variable> threads.
 
 ---
-vp run: 0/2 cache hit (0%). root-package#hello (and 1 more) not cached because they modified their inputs. (Run `vp run --last-details` for full details)
+vp run: 0/2 cache hit (0%). (Run `vp run --last-details` for full details)
 
 > echo 'console.log(123)' > a.ts
 > vp run hello # report cache status from the inner runner
-$ vp lint ./src
+$ vp lint ./src ◉ cache hit, replaying
 Found 0 warnings and 0 errors.
 Finished in <variable>ms on 1 file with <variable> rules using <variable> threads.
 
-$ vp lint
+$ vp lint ○ cache miss: 'a.ts' modified, executing
 Found 0 warnings and 0 errors.
 Finished in <variable>ms on 3 files with <variable> rules using <variable> threads.
 
 ---
-vp run: 0/2 cache hit (0%). root-package#hello (and 1 more) not cached because they modified their inputs. (Run `vp run --last-details` for full details)
+vp run: 1/2 cache hit (50%), <variable>ms saved. (Run `vp run --last-details` for full details)
diff --git a/packages/cli/snap-tests/plain-terminal-ui/snap.txt b/packages/cli/snap-tests/plain-terminal-ui/snap.txt
index 931e6e0d1e..e183790eff 100644
--- a/packages/cli/snap-tests/plain-terminal-ui/snap.txt
+++ b/packages/cli/snap-tests/plain-terminal-ui/snap.txt
@@ -11,17 +11,17 @@ input_content 1
 vp run: cache hit, <variable>ms saved.
 
 > FOO=2 vp run hello # env changed
-$ node hello.mjs ○ cache miss: envs changed, executing
+$ node hello.mjs ○ cache miss: env 'FOO' changed, executing
 input_content 2
 
 
 > FOO=2 BAR=1 vp run hello # env added
-$ node hello.mjs ○ cache miss: envs changed, executing
+$ node hello.mjs ○ cache miss: env 'BAR' changed, executing
 input_content 2
 
 
 > vp run hello # env removed
-$ node hello.mjs ○ cache miss: envs changed, executing
+$ node hello.mjs ○ cache miss: envs 'BAR', 'FOO' changed, executing
 input_content undefined
 
 
diff --git a/packages/cli/snap-tests/vp-build-auto-output-restoration/index.html b/packages/cli/snap-tests/vp-build-auto-output-restoration/index.html
new file mode 100644
index 0000000000..7febab8c7e
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-output-restoration/index.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+  <body>
+    <script type="module">
+      console.log('hello');
+    </script>
+  </body>
+</html>
diff --git a/packages/cli/snap-tests/vp-build-auto-output-restoration/package.json b/packages/cli/snap-tests/vp-build-auto-output-restoration/package.json
new file mode 100644
index 0000000000..c73c0c479a
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-output-restoration/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "vp-build-auto-output-restoration-test",
+  "private": true
+}
diff --git a/packages/cli/snap-tests/vp-build-auto-output-restoration/snap.txt b/packages/cli/snap-tests/vp-build-auto-output-restoration/snap.txt
new file mode 100644
index 0000000000..d1137efcc4
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-output-restoration/snap.txt
@@ -0,0 +1,13 @@
+> vp run build # first build populates the cache
+> ls dist # build output exists
+assets
+index.html
+
+> rm -rf dist # remove the build output
+> vp run build 2>&1 | grep 'cache hit' # rebuild hits cache
+$ vp build ◉ cache hit, replaying
+vp run: cache hit, <variable>ms saved.
+
+> ls dist # dist auto-restored on cache hit (no synthetic output config)
+assets
+index.html
diff --git a/packages/cli/snap-tests/vp-build-auto-output-restoration/steps.json b/packages/cli/snap-tests/vp-build-auto-output-restoration/steps.json
new file mode 100644
index 0000000000..78a6f469b5
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-output-restoration/steps.json
@@ -0,0 +1,12 @@
+{
+  "commands": [
+    {
+      "command": "vp run build # first build populates the cache",
+      "ignoreOutput": true
+    },
+    "ls dist # build output exists",
+    "rm -rf dist # remove the build output",
+    "vp run build 2>&1 | grep 'cache hit' # rebuild hits cache",
+    "ls dist # dist auto-restored on cache hit (no synthetic output config)"
+  ]
+}
diff --git a/packages/cli/snap-tests/vp-build-auto-output-restoration/vite.config.ts b/packages/cli/snap-tests/vp-build-auto-output-restoration/vite.config.ts
new file mode 100644
index 0000000000..1f066d0132
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-output-restoration/vite.config.ts
@@ -0,0 +1,9 @@
+export default {
+  run: {
+    tasks: {
+      build: {
+        command: 'vp build',
+      },
+    },
+  },
+};
diff --git a/packages/cli/snap-tests/vp-build-auto-tracked-env/index.html b/packages/cli/snap-tests/vp-build-auto-tracked-env/index.html
new file mode 100644
index 0000000000..7febab8c7e
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-tracked-env/index.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+  <body>
+    <script type="module">
+      console.log('hello');
+    </script>
+  </body>
+</html>
diff --git a/packages/cli/snap-tests/vp-build-auto-tracked-env/package.json b/packages/cli/snap-tests/vp-build-auto-tracked-env/package.json
new file mode 100644
index 0000000000..aaab903777
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-tracked-env/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "vp-build-auto-tracked-env-test",
+  "private": true
+}
diff --git a/packages/cli/snap-tests/vp-build-auto-tracked-env/snap.txt b/packages/cli/snap-tests/vp-build-auto-tracked-env/snap.txt
new file mode 100644
index 0000000000..6b69e65233
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-tracked-env/snap.txt
@@ -0,0 +1,37 @@
+> VITE_GREETING=hello vp run build # first build
+$ vp build
+vite v<semver> building client environment for production...
+transforming...✓ <variable> modules transformed.
+rendering chunks...
+computing gzip size...
+dist/index.html                <variable> kB │ gzip: <variable> kB
+dist/assets/index-Dra_-aT4.js  <variable> kB │ gzip: <variable> kB
+
+✓ built in <variable>ms
+
+
+> VITE_GREETING=hello vp run build # same env, cache hit
+$ vp build ◉ cache hit, replaying
+vite v<semver> building client environment for production...
+transforming...✓ <variable> modules transformed.
+rendering chunks...
+computing gzip size...
+dist/index.html                <variable> kB │ gzip: <variable> kB
+dist/assets/index-Dra_-aT4.js  <variable> kB │ gzip: <variable> kB
+
+✓ built in <variable>ms
+
+---
+vp run: cache hit, <variable>ms saved.
+
+> VITE_GREETING=world vp run build # VITE_ env changed, cache miss (tracked via vite-task-client)
+$ vp build ○ cache miss: env 'VITE_GREETING' changed, executing
+vite v<semver> building client environment for production...
+transforming...✓ <variable> modules transformed.
+rendering chunks...
+computing gzip size...
+dist/index.html                <variable> kB │ gzip: <variable> kB
+dist/assets/index-Dra_-aT4.js  <variable> kB │ gzip: <variable> kB
+
+✓ built in <variable>ms
+
diff --git a/packages/cli/snap-tests/vp-build-auto-tracked-env/steps.json b/packages/cli/snap-tests/vp-build-auto-tracked-env/steps.json
new file mode 100644
index 0000000000..57c9586df6
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-tracked-env/steps.json
@@ -0,0 +1,7 @@
+{
+  "commands": [
+    "VITE_GREETING=hello vp run build # first build",
+    "VITE_GREETING=hello vp run build # same env, cache hit",
+    "VITE_GREETING=world vp run build # VITE_ env changed, cache miss (tracked via vite-task-client)"
+  ]
+}
diff --git a/packages/cli/snap-tests/vp-build-auto-tracked-env/vite.config.ts b/packages/cli/snap-tests/vp-build-auto-tracked-env/vite.config.ts
new file mode 100644
index 0000000000..1f066d0132
--- /dev/null
+++ b/packages/cli/snap-tests/vp-build-auto-tracked-env/vite.config.ts
@@ -0,0 +1,9 @@
+export default {
+  run: {
+    tasks: {
+      build: {
+        command: 'vp build',
+      },
+    },
+  },
+};
diff --git a/packages/cli/src/run-config.ts b/packages/cli/src/run-config.ts
index 3a8477c6e8..280b9adc17 100644
--- a/packages/cli/src/run-config.ts
+++ b/packages/cli/src/run-config.ts
@@ -1,18 +1,18 @@
 // This file is auto-generated by `cargo test`. Do not edit manually.
 
-export type AutoInput = { 
+export type AutoTracking = {
 /**
- * Automatically track which files the task reads
+ * Enable automatic file tracking for this input or output list.
  */
 auto: boolean, };
 
 export type Command = string | Array<string>;
 
-export type GlobWithBase = { 
+export type GlobWithBase = {
 /**
  * The glob pattern (positive or negative starting with `!`)
  */
-pattern: string, 
+pattern: string,
 /**
  * The base directory for resolving the pattern
  */
@@ -20,31 +20,31 @@ base: InputBase, };
 
 export type InputBase = "package" | "workspace";
 
-export type Task = { 
+export type Task = {
 /**
  * Command to run, or an array of commands to run in order.
  */
-command: Command, 
+command: Command,
 /**
  * The working directory for the task, relative to the package root (not workspace root).
  */
-cwd?: string, 
+cwd?: string,
 /**
  * Dependencies of this task. Use `package-name#task-name` to refer to tasks in other packages.
  */
-dependsOn?: Array<string>, } & ({ 
+dependsOn?: Array<string>, } & ({
 /**
  * Whether to cache the task
  */
-cache?: true, 
+cache?: true,
 /**
  * Environment variable names to be fingerprinted and passed to the task.
  */
-env?: Array<string>, 
+env?: Array<string>,
 /**
  * Environment variable names to be passed to the task without fingerprinting.
  */
-untrackedEnv?: Array<string>, 
+untrackedEnv?: Array<string>,
 /**
  * Files to include in the cache fingerprint.
  *
@@ -55,16 +55,18 @@ untrackedEnv?: Array<string>,
  * - `{auto: true}` enables automatic file tracking
  * - Negative patterns (e.g. `"!dist/**"`) exclude matched files
  */
-input?: Array<string | GlobWithBase | AutoInput>, 
+input?: Array<string | GlobWithBase | AutoTracking>,
 /**
- * Output files to archive after a successful run and restore on cache hit.
+ * Output files to archive and restore on cache hit.
  *
- * - Omitted or `[]` (empty): no output archiving (default)
+ * - Omitted: automatically tracks which files the task writes
+ * - `[]` (empty): disables output restoration entirely
  * - Glob patterns (e.g. `"dist/**"`) select specific output files, relative to the package directory
  * - `{pattern: "...", base: "workspace" | "package"}` specifies a glob with an explicit base directory
+ * - `{auto: true}` enables automatic output tracking
  * - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files
  */
-output?: Array<string | GlobWithBase>, } | { 
+output?: Array<string | GlobWithBase | AutoTracking>, } | {
 /**
  * Whether to cache the task
  */
@@ -72,7 +74,7 @@ cache: false, });
 
 export type TaskDefinition = Task | Command;
 
-export type UserGlobalCacheConfig = boolean | { 
+export type UserGlobalCacheConfig = boolean | {
 /**
  * Enable caching for package.json scripts not defined in the `tasks` map.
  *
@@ -81,7 +83,7 @@ export type UserGlobalCacheConfig = boolean | {
  *
  * Default: `false`
  */
-scripts?: boolean, 
+scripts?: boolean,
 /**
  * Global cache kill switch for task entries.
  *
@@ -93,18 +95,18 @@ scripts?: boolean,
  */
 tasks?: boolean, };
 
-export type RunConfig = { 
+export type RunConfig = {
 /**
  * Root-level cache configuration.
  *
  * This option can only be set in the workspace root's config file.
  * Setting it in a package's config will result in an error.
  */
-cache?: UserGlobalCacheConfig, 
+cache?: UserGlobalCacheConfig,
 /**
  * Task definitions: full task objects, command strings, or command string arrays.
  */
-tasks?: { [key in string]: TaskDefinition }, 
+tasks?: { [key in string]: TaskDefinition },
 /**
  * Whether to automatically run `preX`/`postX` package.json scripts as
  * lifecycle hooks when script `X` is executed.
@@ -115,4 +117,4 @@ tasks?: { [key in string]: TaskDefinition },
  * This option can only be set in the workspace root's config file.
  * Setting it in a package's config will result in an error.
  */
-enablePrePostScripts?: boolean, };
\ No newline at end of file
+enablePrePostScripts?: boolean, };
diff --git a/packages/core/build.ts b/packages/core/build.ts
index c44383c9c9..c8a7df2e40 100644
--- a/packages/core/build.ts
+++ b/packages/core/build.ts
@@ -315,9 +315,27 @@ async function buildVite() {
     if (!existsSync(dir)) {
       await mkdir(dir, { recursive: true });
     }
-    const rewrittenFile = rewriteModuleSpecifiers(file, srcDtsFile, {
+    let rewrittenFile = rewriteModuleSpecifiers(file, srcDtsFile, {
       rules: [...createViteRewriteRules(pkgJson.name), ...createRolldownRewriteRules(pkgJson.name)],
     });
+    // Upstream bug (vitejs/vite#21863, commit cc39e5540): `node/index.ts`
+    // re-exports `KnownQueryTypeMap` from `#types/importGlob`, but the type is
+    // declared there without `export`. Bundling vite's types into a downstream
+    // project then fails with `[MISSING_EXPORT]`. Add the missing `export` here
+    // until it is fixed upstream (drop this once vite exports it).
+    if (relativePath === '/importGlob.d.ts') {
+      const knownQueryTypeMapPattern = /^type KnownQueryTypeMap\b/m;
+      if (!knownQueryTypeMapPattern.test(rewrittenFile)) {
+        throw new Error(
+          'Expected vite types/importGlob.d.ts to declare non-exported KnownQueryTypeMap. ' +
+            'Upstream may have fixed vitejs/vite#21863; remove the KnownQueryTypeMap export workaround from packages/core/build.ts.',
+        );
+      }
+      rewrittenFile = rewrittenFile.replace(
+        knownQueryTypeMapPattern,
+        'export type KnownQueryTypeMap',
+      );
+    }
     await writeFile(dstFilePath, rewrittenFile);
   }
 
diff --git a/packages/core/package.json b/packages/core/package.json
index ef8e3999f8..ac97ef0ed2 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -136,7 +136,7 @@
     "@tsdown/css": "0.22.2",
     "@tsdown/exe": "0.22.2",
     "@types/node": "^20.19.0 || >=22.12.0",
-    "@vitejs/devtools": "^0.1.18",
+    "@vitejs/devtools": "^0.3.0",
     "esbuild": "^0.27.0 || ^0.28.0",
     "jiti": ">=1.21.0",
     "less": "^4.0.0",
diff --git a/packages/tools/.upstream-versions.json b/packages/tools/.upstream-versions.json
index 835469e37e..e623f98ce5 100644
--- a/packages/tools/.upstream-versions.json
+++ b/packages/tools/.upstream-versions.json
@@ -7,6 +7,6 @@
   "vite": {
     "repo": "https://github.com/vitejs/vite.git",
     "branch": "main",
-    "hash": "f94df87ff03b40b65e29bacdc04cc18c7bccaa4a"
+    "hash": "c13a37b53ec673e5a9053355fce3b9c4528fd917"
   }
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dad6388546..af44d98cc6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1291,6 +1291,9 @@ importers:
       '@vitest/utils':
         specifier: 4.1.7
         version: 4.1.7
+      '@voidzero-dev/vite-task-client':
+        specifier: ^0.1.1
+        version: 0.1.1
       artichokie:
         specifier: ^0.4.3
         version: 0.4.3
@@ -1319,8 +1322,8 @@ importers:
         specifier: ^13.0.0
         version: 13.0.0(patch_hash=49330a663821151418e003e822a82a6a61d2f0f8a6e3cab00c1c94815a112889)
       es-module-lexer:
-        specifier: ^1.7.0
-        version: 1.7.0
+        specifier: ^2.0.0
+        version: 2.0.0
       esbuild:
         specifier: ^0.28.0
         version: 0.28.0
@@ -4993,6 +4996,10 @@ packages:
   '@vitest/utils@4.1.8':
     resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==}
 
+  '@voidzero-dev/vite-task-client@0.1.1':
+    resolution: {integrity: sha512-9zGnSzvzUOKNoMf4zxaDeAyerkvnsXBRWfbTkwhwHsVJFug3j48Et8kr+ulHf3KRdcLr07Np+xDuCvHYVK1k7w==}
+    engines: {node: '>=18'}
+
   '@vue-macros/common@3.1.2':
     resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==}
     engines: {node: '>=20.19.0'}
@@ -12069,6 +12076,8 @@ snapshots:
       convert-source-map: 2.0.0
       tinyrainbow: 3.1.0
 
+  '@voidzero-dev/vite-task-client@0.1.1': {}
+
   '@vue-macros/common@3.1.2(vue@3.5.35(typescript@6.0.2))':
     dependencies:
       '@vue/compiler-sfc': 3.5.35
