@visulima/task-runner 1.0.0-alpha.7 → 1.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +3 -1
  3. package/dist/index.d.ts +3093 -49
  4. package/dist/index.js +29 -19
  5. package/dist/packem_chunks/index.js +5593 -0
  6. package/dist/packem_shared/{Cache-CWaX_c8U.js → Cache-CbhoA268.js} +151 -10
  7. package/dist/packem_shared/{FileAccessTracker-CQ5Ot7Hd.js → FileAccessTracker-D8zIURPU.js} +1 -1
  8. package/dist/packem_shared/{FingerprintManager-CV7U4f4f.js → FingerprintManager-78DjwWQ4.js} +1 -1
  9. package/dist/packem_shared/HttpRemoteCache-BTXUBH7t.js +290 -0
  10. package/dist/packem_shared/INPUT_URI_SCHEMES-DRm76YI5.js +69 -0
  11. package/dist/packem_shared/{IncrementalFileHasher-BRS76-mb.js → IncrementalFileHasher-BBhVK491.js} +1 -1
  12. package/dist/packem_shared/ReapiRemoteCache-vgRxDMmu.js +1012 -0
  13. package/dist/packem_shared/{TaskOrchestrator-rf45vW5c.js → TaskOrchestrator-CdRaQhTO.js} +100 -11
  14. package/dist/packem_shared/{TrackedTaskExecutor-CFPpQfXF.js → TrackedTaskExecutor-CWSMfHAW.js} +2 -2
  15. package/dist/packem_shared/V2_ROOT-DKBLxKo4.js +14 -0
  16. package/dist/packem_shared/actionDigestForTaskHash-BRE-9MT6.js +121 -0
  17. package/dist/packem_shared/archive-CnggHWb-.js +152 -0
  18. package/dist/packem_shared/{buildForwardDependencyMap-DLPgKEto.js → buildForwardDependencyMap-0BJFMMPv.js} +1 -2
  19. package/dist/packem_shared/{collectFiles-ClXHnHhg.js → collectFiles-cc1gokGU.js} +2 -1
  20. package/dist/packem_shared/{computeTaskHash-DYqfrDGq.js → computeTaskHash-DHoBJ_-V.js} +10 -4
  21. package/dist/packem_shared/containsBlob-CwGB0a_q.js +125 -0
  22. package/dist/packem_shared/{createTaskGraph-B7nH0kY_.js → createTaskGraph-Bwl4hwAf.js} +23 -2
  23. package/dist/packem_shared/{defaultTaskRunner-Cp7jCmIl.js → defaultTaskRunner-BaX4ZbFv.js} +58 -15
  24. package/dist/packem_shared/{detectFrameworks-CeFzKE6J.js → detectFrameworks-D7nyTc-o.js} +1 -1
  25. package/dist/packem_shared/{detectScriptShell-CR-xXKA4.js → detectScriptShell-CzxCM9-t.js} +1 -1
  26. package/dist/packem_shared/digestBuffer-CPdI2E1d.js +48 -0
  27. package/dist/packem_shared/{expandArguments-0AwD2BIA.js → expandArguments-Ba-hHYff.js} +2 -1
  28. package/dist/packem_shared/expandTokensInString-Bb7nYehP.js +47 -0
  29. package/dist/packem_shared/{extractPackageName-BllKetnz.js → extractPackageName-CMHjqGj_.js} +2 -3
  30. package/dist/packem_shared/{generateRunSummary-BE1jnQ3H.js → generateRunSummary-Bah7CFay.js} +1 -1
  31. package/dist/packem_shared/getCurrentBranch-DVNikt0P.js +156 -0
  32. package/dist/packem_shared/getMainWorktreeRoot-iBqToQJ4.js +114 -0
  33. package/dist/packem_shared/{parseCommands-D-IgF8Zh.js → parseCommands-DDdIxaH5.js} +8 -3
  34. package/dist/packem_shared/resolveCacheMode-CsmHT_0o.js +21 -0
  35. package/dist/packem_shared/{runConcurrently-CmfC4r-f.js → runConcurrently-BCGQ9fJl.js} +1 -1
  36. package/dist/packem_shared/shell-quote-DWJJbt21.js +3 -0
  37. package/dist/packem_shared/{utils-zO0ZRgtf.js → utils-Bmnj-H2J.js} +4 -1
  38. package/index.js +556 -723
  39. package/package.json +26 -13
  40. package/dist/affected.d.ts +0 -82
  41. package/dist/archive.d.ts +0 -38
  42. package/dist/cache.d.ts +0 -138
  43. package/dist/chrome-trace.d.ts +0 -53
  44. package/dist/command-parser/expand-arguments.d.ts +0 -11
  45. package/dist/command-parser/expand-shortcut.d.ts +0 -15
  46. package/dist/command-parser/expand-wildcard.d.ts +0 -13
  47. package/dist/command-parser/index.d.ts +0 -18
  48. package/dist/command-parser/strip-quotes.d.ts +0 -6
  49. package/dist/concurrent-fallback.d.ts +0 -16
  50. package/dist/concurrent.d.ts +0 -23
  51. package/dist/default-task-runner.d.ts +0 -44
  52. package/dist/detect-shell.d.ts +0 -19
  53. package/dist/file-access-tracker.d.ts +0 -59
  54. package/dist/fingerprint.d.ts +0 -54
  55. package/dist/flow-controllers/index.d.ts +0 -7
  56. package/dist/flow-controllers/input-handler.d.ts +0 -44
  57. package/dist/flow-controllers/log-timings.d.ts +0 -18
  58. package/dist/flow-controllers/restart-process.d.ts +0 -21
  59. package/dist/flow-controllers/teardown.d.ts +0 -22
  60. package/dist/framework-inference.d.ts +0 -35
  61. package/dist/graph-visualizer.d.ts +0 -74
  62. package/dist/incremental-hasher.d.ts +0 -76
  63. package/dist/life-cycle.d.ts +0 -38
  64. package/dist/lockfile-hasher.d.ts +0 -73
  65. package/dist/log-reporter.d.ts +0 -34
  66. package/dist/native-binding.d.ts +0 -106
  67. package/dist/output-resolver.d.ts +0 -20
  68. package/dist/packem_shared/RemoteCache-DSU3lc87.js +0 -219
  69. package/dist/packem_shared/archive-UQHAnZUa.js +0 -102
  70. package/dist/project-constraints.d.ts +0 -9
  71. package/dist/remote-cache.d.ts +0 -100
  72. package/dist/run-summary.d.ts +0 -111
  73. package/dist/task-graph-utils.d.ts +0 -39
  74. package/dist/task-graph.d.ts +0 -22
  75. package/dist/task-hasher.d.ts +0 -104
  76. package/dist/task-orchestrator.d.ts +0 -38
  77. package/dist/task-scheduler.d.ts +0 -41
  78. package/dist/terminal-buffer.d.ts +0 -29
  79. package/dist/tracked-executor.d.ts +0 -46
  80. package/dist/types.d.ts +0 -757
  81. package/dist/utils.d.ts +0 -39
package/dist/index.d.ts CHANGED
@@ -1,49 +1,3093 @@
1
- export type { AffectedOptions, AffectedResult } from "./affected.d.ts";
2
- export { buildForwardDependencyMap, buildReverseDependencyMap, expandAffected, filterAffectedTasks, getAffectedProjects, getChangedFiles } from "./affected.d.ts";
3
- export type { CachedResult, CacheOptions } from "./cache.d.ts";
4
- export { Cache, DEFAULT_CACHE_DIRECTORY_NAME, formatCacheSize, parseCacheSize } from "./cache.d.ts";
5
- export type { ChromeTraceEvent } from "./chrome-trace.d.ts";
6
- export { toChromeTrace, writeChromeTrace } from "./chrome-trace.d.ts";
7
- export type { ParseCommandsOptions } from "./command-parser/index.d.ts";
8
- export { expandArguments, expandShortcut, expandWildcard, parseCommands, stripQuotes } from "./command-parser/index.d.ts";
9
- export { runConcurrently } from "./concurrent.d.ts";
10
- export { runConcurrentFallback } from "./concurrent-fallback.d.ts";
11
- export { defaultTaskRunner } from "./default-task-runner.d.ts";
12
- export { detectScriptShell } from "./detect-shell.d.ts";
13
- export type { FileAccess, TrackingResult } from "./file-access-tracker.d.ts";
14
- export { FileAccessTracker, generatePreloadScript } from "./file-access-tracker.d.ts";
15
- export type { CacheMissReason, TaskFingerprint } from "./fingerprint.d.ts";
16
- export { FingerprintManager } from "./fingerprint.d.ts";
17
- export type { InputHandlerOptions, RestartOptions, TeardownOptions } from "./flow-controllers/index.d.ts";
18
- export { createInputHandler, formatTimingTable, logTimings, runTeardown, withRestart } from "./flow-controllers/index.d.ts";
19
- export type { DetectedFramework } from "./framework-inference.d.ts";
20
- export { detectFrameworks, getFrameworkEnvVariables, inferFrameworkEnvPatterns } from "./framework-inference.d.ts";
21
- export type { GraphFormat, GraphJson, GraphVisualizerOptions } from "./graph-visualizer.d.ts";
22
- export { projectGraphToDot, toGraphAscii, toGraphHtml, toGraphJson, toGraphvizDot } from "./graph-visualizer.d.ts";
23
- export type { FileSnapshot, IncrementalHasherOptions } from "./incremental-hasher.d.ts";
24
- export { IncrementalFileHasher } from "./incremental-hasher.d.ts";
25
- export { CompositeLifeCycle, ConsoleLifeCycle, EmptyLifeCycle } from "./life-cycle.d.ts";
26
- export type { PackageLockfileHash, ResolvedDependency } from "./lockfile-hasher.d.ts";
27
- export { extractPackageName, LockfileHasher, parseNpmLockfile, parsePnpmLockfile, parseYarnLockfile } from "./lockfile-hasher.d.ts";
28
- export type { LogMode } from "./log-reporter.d.ts";
29
- export { createLogReporter, LogReporter } from "./log-reporter.d.ts";
30
- export { isNativeAvailable, loadNativeBindings } from "./native-binding.d.ts";
31
- export { resolveOutputs } from "./output-resolver.d.ts";
32
- export { enforceProjectConstraints } from "./project-constraints.d.ts";
33
- export type { RemoteCacheCompression, RemoteCacheOptions, RemoteCacheSigning } from "./remote-cache.d.ts";
34
- export { RemoteCache } from "./remote-cache.d.ts";
35
- export type { RunSummary, TaskSummary } from "./run-summary.d.ts";
36
- export { generateRunSummary, getLastRunSummaryPath, readLastRunSummary, writeLastRunSummary, writeRunSummary } from "./run-summary.d.ts";
37
- export { createTaskGraph, getTaskId, parseTaskId } from "./task-graph.d.ts";
38
- export { findCycle, findCycles, getDependentTasks, getLeafTasks, getTransitiveDependencies, makeAcyclic, reverseTaskGraph, walkTaskGraph, } from "./task-graph-utils.d.ts";
39
- export type { TaskHasher, TaskHasherOptions } from "./task-hasher.d.ts";
40
- export { computeTaskHash, InProcessTaskHasher } from "./task-hasher.d.ts";
41
- export type { TaskOrchestratorOptions } from "./task-orchestrator.d.ts";
42
- export { TaskOrchestrator } from "./task-orchestrator.d.ts";
43
- export type { PartitionOptions } from "./task-scheduler.d.ts";
44
- export { parsePartition, TaskScheduler } from "./task-scheduler.d.ts";
45
- export { TerminalBuffer } from "./terminal-buffer.d.ts";
46
- export type { TrackedExecutionResult } from "./tracked-executor.d.ts";
47
- export { TrackedTaskExecutor } from "./tracked-executor.d.ts";
48
- export type { AffectedScope, ConcurrentCloseEvent, ConcurrentCommandConfig, ConcurrentCommandInput, ConcurrentRunnerOptions, ConcurrentRunResult, ConstraintsConfig, ConstraintViolation, DependencyKindRules, DependencyType, EnvironmentInput, ExternalDependencyInput, FileSetBase, FileSetInput, FileSetPattern, InputDefinition, LifeCycleInterface, NamedInputs, OutputSpec, ProcessEvent, ProjectConfiguration, ProjectGraph, ProjectGraphDependency, ProjectGraphProjectNode, RuntimeInput, TagRelationships, TargetConfiguration, TargetDependencyConfig, Task, TaskExecutionOptions, TaskExecutor, TaskGraph, TaskHashDetails, TaskPriority, TaskResult, TaskResults, TaskRunnerContext, TaskRunnerOptions, TasksRunner, TaskStatus, TaskTarget, TypeBoundaries, WorkspaceConfiguration, } from "./types.d.ts";
49
- export { collectFiles, createFailureResult, hashFile, hashStrings, readPackageDeps, resolveTaskCwd, sortObjectKeys, uniqueId } from "./utils.d.ts";
1
+ import { Readable, Writable } from 'node:stream';
2
+ /**
3
+ * Represents a file access recorded during task execution.
4
+ *
5
+ * Write-intent accesses (`"write"`) are emitted when a task opens a file
6
+ * with `O_WRONLY`/`O_RDWR`/`O_CREAT`/`O_TRUNC` flags (strace) or calls
7
+ * `writeFile`/`appendFile`/`unlink`/`rename` (preload script).
8
+ * The orchestrator uses the overlap of reads and writes to the same
9
+ * workspace path to detect self-modifying tasks and skip caching.
10
+ */
11
+ interface FileAccess {
12
+ /** The absolute path of the file */
13
+ path: string;
14
+ /** The type of access */
15
+ type: "missing" | "read" | "readdir" | "stat" | "write";
16
+ }
17
+ /**
18
+ * Result of tracking file accesses during a command execution.
19
+ */
20
+ interface TrackingResult {
21
+ /** All file accesses recorded */
22
+ accesses: FileAccess[];
23
+ /** The command exit code */
24
+ code: number;
25
+ /** The command stdout + stderr output */
26
+ output: string;
27
+ }
28
+ /**
29
+ * Tracks which files a child process accesses during execution.
30
+ *
31
+ * Uses `strace` on Linux to intercept syscalls (open, openat, stat, lstat, access, getdents).
32
+ * Falls back to no tracking on unsupported platforms.
33
+ */
34
+ declare class FileAccessTracker {
35
+ #private;
36
+ constructor(workspaceRoot: string, excludePatterns?: RegExp[]);
37
+ /**
38
+ * Returns true if file access tracking is supported on the current platform.
39
+ */
40
+ isSupported(): boolean;
41
+ /**
42
+ * Runs a command and tracks all file system accesses.
43
+ * On unsupported platforms, runs the command without tracking.
44
+ */
45
+ track(command: string, options?: {
46
+ cwd?: string;
47
+ env?: Record<string, string | undefined>;
48
+ }): Promise<TrackingResult>;
49
+ /**
50
+ * Kills all active child processes. Called on abort/signal to prevent orphans.
51
+ */
52
+ killAll(): void;
53
+ }
54
+ /**
55
+ * Generates a preload script that can be used with NODE_OPTIONS to
56
+ * track file accesses in Node.js child processes.
57
+ *
58
+ * This is an alternative to strace that works cross-platform for Node.js processes.
59
+ */
60
+ declare const generatePreloadScript: (outputPath: string) => string;
61
+ /**
62
+ * Represents a stored fingerprint for a task execution.
63
+ */
64
+ interface TaskFingerprint {
65
+ /** Hash of the command arguments */
66
+ commandHash: string;
67
+ /** Directory listings recorded during execution (path -> sorted entries) */
68
+ directoryListings: Record<string, string[]>;
69
+ /** Hashes of fingerprinted environment variables */
70
+ envHashes: Record<string, string>;
71
+ /** Content hashes of files that were read during execution */
72
+ fileHashes: Record<string, string>;
73
+ /** Paths of files that were probed but didn't exist (ENOENT) */
74
+ missingFiles: string[];
75
+ /**
76
+ * Workspace-relative paths that were both read **and** written
77
+ * during execution. Populated when the tracker emits
78
+ * {@link FileAccess} entries with `"write"` type. The orchestrator
79
+ * uses a non-empty value here to skip caching a self-modifying
80
+ * task, whose fingerprint would otherwise capture post-write state
81
+ * and trigger false cache hits.
82
+ */
83
+ modifiedInputs?: string[];
84
+ }
85
+ /**
86
+ * Describes why a cache miss occurred.
87
+ */
88
+ interface CacheMissReason {
89
+ currentHash?: string;
90
+ detail: string;
91
+ previousHash?: string;
92
+ type: "file-changed" | "file-created" | "file-deleted" | "directory-changed" | "env-changed" | "args-changed" | "no-fingerprint";
93
+ }
94
+ /**
95
+ * Manages task fingerprints for auto-detection caching.
96
+ *
97
+ * Records which files a task accesses during execution, stores content
98
+ * hashes, and on subsequent runs checks if any accessed file has changed.
99
+ */
100
+ declare class FingerprintManager {
101
+ #private;
102
+ constructor(workspaceRoot: string);
103
+ createFingerprint(accesses: FileAccess[], command: string, args: Record<string, unknown>, envVariables: Record<string, string | undefined>, envPatterns?: string[], untrackedEnvVariables?: string[]): Promise<TaskFingerprint>;
104
+ /**
105
+ * Validates a stored fingerprint against the current state.
106
+ * Returns null if valid (cache hit), or an array of reasons (cache miss).
107
+ *
108
+ * Does NOT use the file hash cache — validation must see current disk state.
109
+ */
110
+ validate(fingerprint: TaskFingerprint): Promise<CacheMissReason[] | undefined>;
111
+ validateCommand(fingerprint: TaskFingerprint, command: string, args: Record<string, unknown>): CacheMissReason | undefined;
112
+ formatMissReasons(reasons: CacheMissReason[]): string;
113
+ }
114
+ /**
115
+ * Content-Addressable Storage digest. Mirrors REAPI's `Digest` message:
116
+ * a content hash and the size in bytes of the addressed blob.
117
+ *
118
+ * The hash is the lowercase hex sha256 of the blob's raw bytes. Size is
119
+ * the byte length of those bytes. Together they uniquely identify a CAS
120
+ * entry across HTTP and gRPC (REAPI) backends.
121
+ */
122
+ interface CasDigest {
123
+ /** Lowercase hex sha256 of the blob bytes. */
124
+ hash: string;
125
+ /** Size of the blob bytes, in bytes. */
126
+ sizeBytes: number;
127
+ }
128
+ /**
129
+ * Result of executing a single Action. Mirrors REAPI's `ActionResult`
130
+ * shape, with a vis-specific `fingerprint` extension for auto-fingerprint
131
+ * mode. Persisted as JSON locally; serialized as a protobuf over gRPC.
132
+ *
133
+ * Output paths are workspace-relative.
134
+ */
135
+ interface ActionResult {
136
+ /** Process exit code from the cached run. */
137
+ exitCode: number;
138
+ /** Optional vis-specific fingerprint (auto-fingerprint mode). */
139
+ fingerprint?: TaskFingerprint;
140
+ /**
141
+ * Per-output-directory entries. The `treeDigest` points to a CAS
142
+ * blob that is itself a serialized REAPI `Tree` message describing
143
+ * the directory hierarchy and its file digests.
144
+ */
145
+ outputDirectories: ReadonlyArray<{
146
+ path: string;
147
+ treeDigest: CasDigest;
148
+ }>;
149
+ /** Per-output-file entries. Workspace-relative paths. */
150
+ outputFiles: ReadonlyArray<{
151
+ digest: CasDigest;
152
+ isExecutable: boolean;
153
+ path: string;
154
+ }>;
155
+ /**
156
+ * CAS digest of the captured stdout/stderr stream. Optional because
157
+ * tasks with no output emit nothing. Most tasks emit at least
158
+ * "Done in Xs", so dedup across tasks is real.
159
+ */
160
+ stdoutDigest?: CasDigest;
161
+ }
162
+ /**
163
+ * Lazy handle for a CAS blob. Backends call `open()` only when they're
164
+ * ready to stream the bytes — keeps memory flat for multi-hundred-MB
165
+ * artifacts and avoids buffering blobs the server reports as already
166
+ * present (REAPI `FindMissingBlobs`).
167
+ */
168
+ interface BlobSource {
169
+ digest: CasDigest;
170
+ open: () => Promise<NodeJS.ReadableStream>;
171
+ }
172
+ /**
173
+ * Canonical cache-mode enum, replacing the original `read` / `write`
174
+ * boolean pair. One flag, three values, no implicit env-detection.
175
+ *
176
+ * - `"read"`: Pull cache hits, never push. Default for local dev when
177
+ * developers shouldn't poison the shared cache.
178
+ * - `"write"`: Push results, never read. Useful for refill / warm-up
179
+ * jobs that should always re-execute and re-upload.
180
+ * - `"readwrite"`: Both. Default for CI.
181
+ */
182
+ type CacheMode = "read" | "readwrite" | "write";
183
+ /**
184
+ * Compression algorithm used for artifact tarballs on the wire.
185
+ *
186
+ * - `"gzip"` (default): tar+gzip, matches Turborepo's protocol format
187
+ * and stays interop-safe with existing remote cache servers.
188
+ * - `"brotli"`: tar + Node brotli (BROTLI_MODE_TEXT, quality 4) — a
189
+ * solid ratio/speed trade-off for source-tree tarballs. Both upload
190
+ * and download sides must agree; switching invalidates existing
191
+ * remote entries (they will simply re-populate on next run).
192
+ *
193
+ * HTTP-only — REAPI servers negotiate compression via the
194
+ * `Capabilities` RPC + `grpc-encoding` metadata on the wire.
195
+ */
196
+ type RemoteCacheCompression = "brotli" | "gzip";
197
+ /**
198
+ * HMAC signing configuration for the HTTP backend.
199
+ *
200
+ * When set, every upload carries an `X-Artifact-Signature` header
201
+ * containing the HMAC-SHA256 digest of `hash | body`. On download,
202
+ * the client recomputes the HMAC and rejects any artifact whose
203
+ * signature doesn't match (constant-time comparison). REAPI servers
204
+ * do not consume this — REAPI integrity rides on sha256
205
+ * content-addressing instead.
206
+ */
207
+ interface RemoteCacheSigning {
208
+ /** Shared secret. Must be at least 16 characters. */
209
+ secret: string;
210
+ /**
211
+ * Reject downloads whose signature doesn't match or is missing.
212
+ * Set to `true` once every upload on your server is signed.
213
+ * @default false
214
+ */
215
+ verifyOnDownload?: boolean;
216
+ }
217
+ /**
218
+ * Canonical remote-cache configuration consumed by
219
+ * `createRemoteCacheBackend`. Both `HttpRemoteCache` and
220
+ * `ReapiRemoteCache` accept this shape directly — backend-specific
221
+ * fields (e.g. `signing`, `compression` for HTTP; `bearerToken`,
222
+ * `instanceName` for REAPI) are read by the corresponding constructor
223
+ * and ignored by the other.
224
+ *
225
+ * Living in `backends/types.ts` rather than each backend file keeps a
226
+ * single source of truth for `TaskRunnerOptions.remoteCache` and the
227
+ * `vis-config` typed surface.
228
+ */
229
+ interface RemoteCacheOptions {
230
+ /**
231
+ * Opt out of the REAPI safety check that refuses to send a bearer
232
+ * token over cleartext gRPC. Required only when the connection
233
+ * terminates inside a trusted boundary (loopback dev cache, mesh
234
+ * mTLS sidecar that strips/re-encrypts on the next hop). Default
235
+ * `false` — production callers should reach for `grpcs://` first.
236
+ *
237
+ * REAPI-only.
238
+ */
239
+ allowInsecureBearer?: boolean;
240
+ /**
241
+ * Wire-protocol selector. `"http"` is the Turborepo-compatible
242
+ * single-tarball cache; `"reapi"` switches to the Bazel Remote
243
+ * Execution API gRPC client, unlocking `bazel-remote`,
244
+ * BuildBuddy, BuildBarn, EngFlow as drop-in backends.
245
+ * @default "http"
246
+ */
247
+ backend?: "http" | "reapi";
248
+ /**
249
+ * Bearer token sent in REAPI's `authorization: Bearer {token}`
250
+ * gRPC metadata header. REAPI-only — HTTP backend uses `token`.
251
+ */
252
+ bearerToken?: string;
253
+ /** HTTP-only: tarball compression on the wire. @default "gzip" */
254
+ compression?: RemoteCacheCompression;
255
+ /**
256
+ * REAPI-only `instance_name` for multi-tenant servers (a single
257
+ * gRPC endpoint can host multiple logical caches keyed on the
258
+ * `instance_name` prefix).
259
+ */
260
+ instanceName?: string;
261
+ /**
262
+ * Local CAS root used by the per-blob {@link RemoteCacheBackend}
263
+ * methods. The HTTP wire format is still single-tarball; on
264
+ * retrieve the bridge extracts blobs into this root so a follow-up
265
+ * `fetchBlob` is just a local read.
266
+ */
267
+ localCasRoot?: string;
268
+ /**
269
+ * Canonical cache mode flag.
270
+ *
271
+ * - `"read"`: Pull cache hits, never push. Sensible default for
272
+ * local dev so a developer doesn't poison the shared cache while
273
+ * their workspace is dirty.
274
+ * - `"write"`: Push results, never read. Useful for refill /
275
+ * warm-up jobs that should always re-execute and re-upload.
276
+ * - `"readwrite"`: Both. Default for CI.
277
+ * @default "readwrite"
278
+ */
279
+ mode?: CacheMode;
280
+ /**
281
+ * Called when a fire-and-forget upload fails. Uploads are
282
+ * non-blocking, so without this hook errors are silently dropped.
283
+ * Provide it to log or report upload failures.
284
+ */
285
+ onUploadError?: (hash: string, error: unknown) => void;
286
+ /** HTTP-only: HMAC-SHA256 signing for upload integrity. */
287
+ signing?: RemoteCacheSigning;
288
+ /** Team / namespace for cache isolation. */
289
+ teamId?: string;
290
+ /** Per-call request timeout in milliseconds. @default 30000 */
291
+ timeout?: number;
292
+ /**
293
+ * HTTP authentication token sent as `Authorization: Bearer …`.
294
+ * For REAPI, use `bearerToken` instead — same wire mechanic, but
295
+ * a separate field so REAPI's cleartext-bearer guard can distinguish
296
+ * "user explicitly opted into a gRPC token" from "user set HTTP
297
+ * auth and accidentally selected the REAPI backend".
298
+ */
299
+ token?: string;
300
+ /**
301
+ * Cache server URL.
302
+ *
303
+ * - HTTP: `https://cache.example.com`
304
+ * - REAPI: `grpcs://host:port` (TLS, recommended) or `grpc://host:port`
305
+ * (cleartext — bearer tokens are refused unless `allowInsecureBearer`).
306
+ */
307
+ url: string;
308
+ }
309
+ /**
310
+ * Pluggable backend boundary for the remote cache. Implementations:
311
+ * - `HttpRemoteCache`: Turborepo wire-protocol-compatible HTTP cache.
312
+ * Bridges the single-tarball protocol to per-blob semantics by
313
+ * synthesizing an `ActionResult` from the extracted tarball contents.
314
+ * - `ReapiRemoteCache`: Bazel Remote Execution API gRPC client.
315
+ * Speaks `ActionCache` + `ContentAddressableStorage` services
316
+ * natively, unlocking bazel-remote / BuildBuddy / BuildBarn / EngFlow.
317
+ */
318
+ interface RemoteCacheBackend {
319
+ /**
320
+ * Release any persistent resources held by the backend (gRPC
321
+ * channels, HTTP keep-alive agents). Safe to call multiple times
322
+ * and safe to call when no work has been issued. Implementations
323
+ * must not throw — close failures are best-effort.
324
+ */
325
+ close: () => Promise<void>;
326
+ /**
327
+ * HEAD-equivalent existence check. REAPI: `GetActionResult` with
328
+ * `inline_*` fields disabled. HTTP: `HEAD /v8/artifacts/{hash}`.
329
+ */
330
+ containsAction: (actionDigest: CasDigest) => Promise<boolean>;
331
+ /**
332
+ * Stream a single CAS blob to disk. Returns `true` on success.
333
+ * Used to materialize output files referenced by an `ActionResult`.
334
+ */
335
+ fetchBlob: (digest: CasDigest, destinationPath: string) => Promise<boolean>;
336
+ /**
337
+ * Look up an Action's cached result. Resolves to `null` on miss.
338
+ * Implementations are responsible for fetching any CAS blobs the
339
+ * caller needs to materialize the outputs (or returning enough
340
+ * metadata for the caller to fetch them via `fetchBlob`).
341
+ */
342
+ retrieveAction: (actionDigest: CasDigest) => Promise<ActionResult | null>;
343
+ /**
344
+ * Persist an `ActionResult` and any blobs it references. Backends
345
+ * must enforce blobs-before-AC ordering on the wire so a partial
346
+ * failure cannot leave a cached result pointing at missing bytes.
347
+ */
348
+ storeAction: (actionDigest: CasDigest, result: ActionResult, blobs: ReadonlyArray<BlobSource>) => Promise<boolean>;
349
+ }
350
+ /**
351
+ * A predicate clause that can match a single value, a list of values
352
+ * (any-of), or — for env vars only — a `{ name, equals?, exists? }`
353
+ * triplet. `not.*` mirrors of every clause provide a negative form
354
+ * without having to wrap the whole `when` in a compound expression.
355
+ *
356
+ * Examples:
357
+ * `os: "linux"` — runs only on linux
358
+ * `os: ["linux", "darwin"]` — runs on linux or macOS
359
+ * `not.os: "windows"` — runs everywhere except windows
360
+ * `env: "CI"` — runs only when `process.env.CI` is truthy
361
+ * `env: { name: "NODE_ENV", equals: "production" }`
362
+ * `branch: ["main", "alpha"]`
363
+ * `ci: true` — runs only inside CI
364
+ */
365
+ interface WhenCondition {
366
+ /** Match against the current git branch (HEAD). */
367
+ branch?: string | string[];
368
+ /**
369
+ * Run only when invoked inside CI when `true`, only outside CI
370
+ * when `false`. Detects CI via the `CI` env var (the convention
371
+ * GitHub Actions, GitLab, CircleCI, Jenkins, etc. all share).
372
+ */
373
+ ci?: boolean;
374
+ /**
375
+ * Match against environment variables. A bare string asserts the
376
+ * variable is set and non-empty; the object form lets you match
377
+ * an exact value or just assert presence/absence.
378
+ */
379
+ env?: EnvMatcher | EnvMatcher[];
380
+ /** Negative mirrors. A task runs only when *all* `not.*` clauses fail. */
381
+ not?: {
382
+ branch?: string | string[];
383
+ ci?: boolean;
384
+ env?: EnvMatcher | EnvMatcher[];
385
+ os?: NodePlatform | NodePlatform[];
386
+ };
387
+ /**
388
+ * Match `process.platform` (`"linux" | "darwin" | "win32" | "freebsd"
389
+ * | "openbsd" | "sunos" | "aix"`). Pass `"windows"` as an alias for
390
+ * `"win32"` — easier to remember and matches what people type.
391
+ */
392
+ os?: NodePlatform | NodePlatform[];
393
+ }
394
+ /**
395
+ * An environment-variable match. The string form is shorthand for
396
+ * `{ name, exists: true }` (set + non-empty). The object form
397
+ * supports either presence assertions or exact-value matching.
398
+ */
399
+ type EnvMatcher = string | {
400
+ /** Match this exact value. Mutually exclusive with `exists`. */
401
+ equals?: string;
402
+ /** Assert the variable is set & non-empty (`true`) or unset/empty (`false`). */
403
+ exists?: boolean;
404
+ /** Variable name. */
405
+ name: string;
406
+ };
407
+ /** Aliased platform list — `"windows"` is sugar for Node's `"win32"`. */
408
+ type NodePlatform = "aix" | "darwin" | "freebsd" | "linux" | "openbsd" | "sunos" | "windows" | "win32";
409
+ /**
410
+ * Inputs for {@link evaluateWhen}. Pulled into a struct so tests can
411
+ * inject deterministic values and CLIs can reuse the same env/branch
412
+ * lookup across many task evaluations.
413
+ */
414
+ interface WhenContext {
415
+ /** Current git branch. Pass an empty string when not in a repo. */
416
+ branch?: string;
417
+ /** Whether we're inside CI. Defaults to `process.env.CI` truthy check. */
418
+ ci?: boolean;
419
+ /** Environment variables to match against. Defaults to `process.env`. */
420
+ env?: Record<string, string | undefined>;
421
+ /** Platform string. Defaults to `process.platform`. */
422
+ platform?: NodePlatform;
423
+ }
424
+ declare const getCurrentBranch: (cwd: string) => string;
425
+ /** Test-only escape hatch — clears every cached branch result. */
426
+ declare const resetBranchCache: () => void;
427
+ /**
428
+ * Evaluates a {@link WhenCondition} against the supplied context (or the
429
+ * live process state when omitted). Returns `true` when the task should
430
+ * run, `false` when every positive clause matches and every `not.*`
431
+ * clause is also satisfied.
432
+ *
433
+ * Semantics:
434
+ * - All positive clauses must match (AND).
435
+ * - All `not.*` clauses must not match (AND).
436
+ * - Within a single clause, an array means any-of (OR).
437
+ * - An empty/undefined `when` always returns `true`.
438
+ */
439
+ declare const evaluateWhen: (when: WhenCondition | undefined, context?: WhenContext) => boolean;
440
+ /**
441
+ * Returns a short human-readable explanation of why a `when` clause
442
+ * skipped a task. Used by lifecycle handlers to print diagnostics.
443
+ * Returns an empty string when the condition evaluates to true.
444
+ */
445
+ declare const explainWhen: (when: WhenCondition | undefined, context?: WhenContext) => string;
446
+ /**
447
+ * Represents a target that a task executes against.
448
+ */
449
+ interface TaskTarget {
450
+ /** Optional configuration name */
451
+ configuration?: string;
452
+ /** The project name */
453
+ project: string;
454
+ /** The target name (e.g., "build", "test", "lint") */
455
+ target: string;
456
+ }
457
+ /**
458
+ * Represents a single task to be executed.
459
+ */
460
+ /**
461
+ * Scheduling priority hint. The scheduler picks higher-priority tasks
462
+ * out of the ready-queue first; ties fall through to the graph-derived
463
+ * signals (dependent count, project depth).
464
+ *
465
+ * Use `"high"` for long-running leaves you want to kick off early
466
+ * (integration tests, e2e suites) so their wall-clock overlaps with
467
+ * the main build phase. Use `"low"` for work you don't mind deferring
468
+ * (linters, coverage uploads) when faster tasks contend for slots.
469
+ */
470
+ type TaskPriority = "high" | "low" | "normal";
471
+ /**
472
+ * A single entry in a task's `outputs` list.
473
+ *
474
+ * - `string` — a literal path *or* a glob pattern relative to the
475
+ * workspace root. Prefix with `!` to exclude files the positive
476
+ * patterns would otherwise include (e.g. `"!dist/cache/**"`).
477
+ * - `{ auto: true }` — use whatever files the task actually wrote
478
+ * during execution (resolved from the file-access tracker). Lets
479
+ * authors who don't know their exact output layout cache results
480
+ * without listing every path. Silently behaves as "no outputs" when
481
+ * tracking isn't active for this task.
482
+ */
483
+ type OutputSpec = string | {
484
+ auto: true;
485
+ };
486
+ interface Task {
487
+ /**
488
+ * When `true`, this task runs after the main task graph completes
489
+ * — even if upstream tasks failed or the run was interrupted.
490
+ * Used for cleanup, teardown, or notification tasks. Carried over
491
+ * from {@link TargetConfiguration.always} at task graph creation.
492
+ */
493
+ always?: boolean;
494
+ /** Whether this task is eligible for caching */
495
+ cache?: boolean;
496
+ /**
497
+ * When `false`, exit-0 runs whose output matched any
498
+ * {@link Task.warningPattern} are NOT written to the cache. Defaults
499
+ * to `true` — warnings are recorded on the result but don't suppress
500
+ * caching, matching the rushstack#1402 / Theme P expectation that a
501
+ * succeeded-with-warnings build is still incremental on the next run.
502
+ *
503
+ * Carried over from {@link TargetConfiguration.cacheOnWarning}.
504
+ */
505
+ cacheOnWarning?: boolean;
506
+ /**
507
+ * Per-task overrides for cache restore fidelity. Carried over
508
+ * from {@link TargetConfiguration.cacheRestore}. When absent, the
509
+ * runner uses faithful defaults (mtime + mode preserved).
510
+ */
511
+ cacheRestore?: CacheRestoreOptions;
512
+ /** Hash of the task inputs for caching */
513
+ hash?: string;
514
+ /** Detailed hash information */
515
+ hashDetails?: TaskHashDetails;
516
+ /** Unique identifier for the task, typically "project:target:configuration" */
517
+ id: string;
518
+ /**
519
+ * Output patterns this task produces. Each entry is either a
520
+ * literal path, a glob (`"dist/**"`), a negative glob
521
+ * (`"!dist/cache/**"`), or `{ auto: true }` to pick up whatever
522
+ * files the task wrote during execution.
523
+ */
524
+ outputs: OutputSpec[];
525
+ /** Overrides/extra options passed to the task */
526
+ overrides: Record<string, unknown>;
527
+ /** Whether this task supports parallel execution */
528
+ parallelism?: boolean;
529
+ /**
530
+ * Explicit scheduling priority. Outranks the scheduler's
531
+ * graph-derived heuristics. Defaults to `"normal"` when absent.
532
+ */
533
+ priority?: TaskPriority;
534
+ /** The project root directory */
535
+ projectRoot?: string;
536
+ /** The target this task executes */
537
+ target: TaskTarget;
538
+ /**
539
+ * Regex strings (JavaScript flavor, anchored as the user writes them)
540
+ * that classify a successful task's terminal output as "succeeded
541
+ * with warnings". When any pattern matches, {@link TaskResult.hadWarnings}
542
+ * is set on the result. Combined with {@link Task.cacheOnWarning} this
543
+ * controls whether the run still seeds the cache.
544
+ *
545
+ * Carried over from {@link TargetConfiguration.warningPattern}.
546
+ */
547
+ warningPattern?: string[];
548
+ /**
549
+ * Predicate that gates execution. Evaluated by the orchestrator
550
+ * just before the task is launched; tasks whose `when` returns
551
+ * `false` are marked `"skipped"` without ever invoking the
552
+ * executor. Carried over from {@link TargetConfiguration.when}.
553
+ */
554
+ when?: WhenCondition;
555
+ }
556
+ /**
557
+ * Represents detailed hash information for a task.
558
+ */
559
+ interface TaskHashDetails {
560
+ /** The command hash */
561
+ command: string;
562
+ /** Hash of implicit dependencies */
563
+ implicitDeps?: Record<string, string>;
564
+ /** Hashes of input files */
565
+ nodes: Record<string, string>;
566
+ /** Hash of runtime values */
567
+ runtime?: Record<string, string>;
568
+ }
569
+ /**
570
+ * Represents a directed acyclic graph of tasks.
571
+ */
572
+ interface TaskGraph {
573
+ /** Dependencies for each task */
574
+ dependencies: Record<string, string[]>;
575
+ /** Top-level tasks that no other task depends on (the final outputs to run) */
576
+ roots: string[];
577
+ /** All tasks in the graph, keyed by task ID */
578
+ tasks: Record<string, Task>;
579
+ }
580
+ /**
581
+ * Possible states of a task after execution.
582
+ */
583
+ type TaskStatus = "success" | "failure" | "skipped" | "local-cache" | "local-cache-kept-existing" | "remote-cache";
584
+ /**
585
+ * Result of executing a task.
586
+ */
587
+ interface TaskResult {
588
+ /** The exit code, if applicable */
589
+ code?: number;
590
+ /**
591
+ * Set when auto-fingerprint tracking was attempted for this task but
592
+ * returned zero workspace accesses — usually a static binary on
593
+ * macOS/Windows, where the Node preload can't attach. Caching is
594
+ * skipped to avoid persisting an empty fingerprint that would
595
+ * produce false cache hits on every subsequent run.
596
+ */
597
+ emptyFingerprint?: boolean;
598
+ /** The end time of the task */
599
+ endTime?: number;
600
+ /**
601
+ * Set when the task exited 0 and at least one configured
602
+ * {@link Task.warningPattern} matched the terminal output. Surfaced
603
+ * to lifecycle reporters and the run summary so users can see that
604
+ * a "green" build still emitted warnings, and gates the optional
605
+ * `cacheOnWarning: false` cache-suppression path.
606
+ */
607
+ hadWarnings?: boolean;
608
+ /**
609
+ * Set when the task modified one or more of its own tracked input
610
+ * files during execution. Caching is skipped in this case — the
611
+ * fingerprint captured before the run would mismatch the post-run
612
+ * contents and produce false cache hits on subsequent runs.
613
+ */
614
+ selfModified?: boolean;
615
+ /** The start time of the task */
616
+ startTime?: number;
617
+ status: TaskStatus;
618
+ task: Task;
619
+ /** The terminal output produced during execution */
620
+ terminalOutput?: string;
621
+ }
622
+ /**
623
+ * Map of task results, keyed by task ID.
624
+ */
625
+ type TaskResults = Map<string, TaskResult>;
626
+ /**
627
+ * Configuration for a project in the workspace.
628
+ */
629
+ interface ProjectConfiguration {
630
+ /** Implicit dependencies on other projects */
631
+ implicitDependencies?: string[];
632
+ /**
633
+ * Project layer in the dependency hierarchy. Used by
634
+ * `enforceLayerRelationships` to ensure projects only depend on
635
+ * projects at the same or lower layer.
636
+ *
637
+ * Hierarchy (lowest → highest):
638
+ * `configuration < library < scaffolding < tool < automation < application`
639
+ */
640
+ layer?: "application" | "automation" | "configuration" | "library" | "scaffolding" | "tool";
641
+ /** The project type */
642
+ projectType?: "library" | "application";
643
+ /** The root directory of the project, relative to workspace root */
644
+ root: string;
645
+ /** The source root directory */
646
+ sourceRoot?: string;
647
+ /** Tags for filtering */
648
+ tags?: string[];
649
+ /** Named targets and their configurations */
650
+ targets?: Record<string, TargetConfiguration>;
651
+ }
652
+ /**
653
+ * Per-target controls over how the cache rehydrates outputs.
654
+ *
655
+ * Both default to `true` — faithful restoration is the contract:
656
+ * cached outputs come back with the same mtime and mode bits the
657
+ * task originally produced. Override only when downstream tooling
658
+ * needs the opposite (e.g. a bundler that uses "newer than source"
659
+ * heuristics, or a CI step that compares mtimes against a deploy
660
+ * artifact).
661
+ */
662
+ interface CacheRestoreOptions {
663
+ /**
664
+ * Restore each file's modification time from the captured tar
665
+ * header (second precision). When `false`, restored files take
666
+ * the current wall-clock time, matching the legacy behaviour.
667
+ */
668
+ preserveMtime?: boolean;
669
+ /**
670
+ * Restore each file's POSIX mode bits (rwx triplets, low 12
671
+ * bits). When `false`, restored files take the process umask.
672
+ * Only meaningful on POSIX hosts; Windows ignores tar mode.
673
+ */
674
+ preservePerms?: boolean;
675
+ }
676
+ /**
677
+ * Configuration for a target within a project.
678
+ */
679
+ interface TargetConfiguration {
680
+ /**
681
+ * When `true`, this target runs after the main task graph
682
+ * completes — even if upstream tasks failed. Useful for cleanup,
683
+ * teardown, notifications, or anything that should fire
684
+ * regardless of build outcome. Always-tasks are not part of the
685
+ * normal dependency graph and never block other tasks.
686
+ */
687
+ always?: boolean;
688
+ /** Whether this target is cacheable */
689
+ cache?: boolean;
690
+ /**
691
+ * When `false`, exit-0 runs whose terminal output matched any
692
+ * {@link TargetConfiguration.warningPattern} are not seeded into the
693
+ * cache. Defaults to `true` — warnings are surfaced on the result
694
+ * (`hadWarnings: true`) but caching still happens, matching the
695
+ * "succeeded with warnings is incremental" behaviour rush, lage and
696
+ * wireit users have repeatedly asked for.
697
+ */
698
+ cacheOnWarning?: boolean;
699
+ /**
700
+ * Fine-grained controls over how cached outputs are rehydrated.
701
+ * See {@link CacheRestoreOptions}. Both fields default to `true`
702
+ * (faithful restore); flip individually when downstream tooling
703
+ * needs the legacy "now"-stamped behaviour.
704
+ */
705
+ cacheRestore?: CacheRestoreOptions;
706
+ /** The command to run (alternative to executor) */
707
+ command?: string;
708
+ /** Named configurations (e.g., "production", "development") */
709
+ configurations?: Record<string, Record<string, unknown>>;
710
+ /** Other targets this target depends on */
711
+ dependsOn?: (string | TargetDependencyConfig)[];
712
+ /** The executor/command to run */
713
+ executor?: string;
714
+ /** Input patterns for cache invalidation */
715
+ inputs?: (string | InputDefinition)[];
716
+ /** Options passed to the executor */
717
+ options?: Record<string, unknown>;
718
+ /** Output patterns produced by this target */
719
+ outputs?: string[];
720
+ /** Whether this target supports parallel execution */
721
+ parallelism?: boolean;
722
+ /**
723
+ * Regex source string(s) that mark a successful task as having
724
+ * emitted warnings. The orchestrator scans the task's combined
725
+ * terminal output after a 0-exit and, on first match, sets
726
+ * `hadWarnings` on the result. Combine with `cacheOnWarning: false`
727
+ * to skip caching for warning-tainted runs. Both bare strings and
728
+ * arrays are accepted; arrays are tested in order.
729
+ *
730
+ * ```ts
731
+ * warningPattern: ["\\bwarning\\b", "TS\\d{4}"]
732
+ * ```
733
+ */
734
+ warningPattern?: string | string[];
735
+ /**
736
+ * Predicate that gates execution. When the condition evaluates
737
+ * to `false` for the current environment, the task is skipped
738
+ * (marked `"skipped"`, not failed). Combine with `os`, `env`,
739
+ * `branch`, and `ci` clauses for granular control:
740
+ *
741
+ * ```ts
742
+ * when: { os: "linux", ci: true, env: "DEPLOY_TOKEN" }
743
+ * ```
744
+ */
745
+ when?: WhenCondition;
746
+ }
747
+ /**
748
+ * Defines a dependency on another target.
749
+ */
750
+ interface TargetDependencyConfig {
751
+ /** Whether this is a dependency on the same project */
752
+ dependencies?: boolean;
753
+ /** Params to pass through */
754
+ params?: "forward" | "ignore";
755
+ /** The project name (if different from the current project) */
756
+ projects?: string | string[];
757
+ /** The target name */
758
+ target: string;
759
+ }
760
+ /**
761
+ * Defines an input for cache invalidation.
762
+ */
763
+ type InputDefinition = FileSetInput | RuntimeInput | EnvironmentInput | ExternalDependencyInput;
764
+ /**
765
+ * Controls how a glob pattern is anchored.
766
+ * - "package" (default): pattern is resolved relative to the project root
767
+ * - "workspace": pattern is resolved relative to the workspace root
768
+ */
769
+ type FileSetBase = "package" | "workspace";
770
+ /**
771
+ * An input based on file patterns.
772
+ *
773
+ * `fileset` may be a bare glob string (package-root relative) or an object
774
+ * form `{ pattern, base }` to anchor explicitly to the workspace root.
775
+ * Negation (`!` prefix) works in both forms.
776
+ */
777
+ interface FileSetInput {
778
+ fileset: FileSetPattern | string;
779
+ }
780
+ /**
781
+ * Object form of a fileset pattern, for anchoring to the workspace root.
782
+ */
783
+ interface FileSetPattern {
784
+ /** Anchor for the pattern. */
785
+ base: FileSetBase;
786
+ /** Glob pattern (may start with `!` for negation). */
787
+ pattern: string;
788
+ }
789
+ /**
790
+ * An input based on a runtime command.
791
+ */
792
+ interface RuntimeInput {
793
+ runtime: string;
794
+ }
795
+ /**
796
+ * An input based on environment variables.
797
+ */
798
+ interface EnvironmentInput {
799
+ env: string;
800
+ }
801
+ /**
802
+ * An input based on external dependency versions.
803
+ */
804
+ interface ExternalDependencyInput {
805
+ externalDependencies: string[];
806
+ }
807
+ /**
808
+ * Defines tag-based dependency rules.
809
+ * Each key is a tag name. The value is the list of tags that a dependency
810
+ * must have at least one of, when the source project has that tag.
811
+ *
812
+ * Example: `{ "frontend": ["shared", "frontend"] }` means a project tagged
813
+ * "frontend" can only depend on projects tagged "shared" or "frontend".
814
+ */
815
+ type TagRelationships = Record<string, string[]>;
816
+ /**
817
+ * Defines project-type-based dependency rules.
818
+ */
819
+ interface TypeBoundaries {
820
+ /**
821
+ * Custom rules mapping project types to allowed dependency types.
822
+ * Example: `{ "application": ["library"] }` means applications can only
823
+ * depend on libraries.
824
+ */
825
+ allowedDependencyTypes?: Record<string, string[]>;
826
+ /**
827
+ * When true, no project may depend on an "application" type project.
828
+ * Applications are typically deployment targets, not libraries.
829
+ * @default true
830
+ */
831
+ enforceApplicationBoundary?: boolean;
832
+ }
833
+ /**
834
+ * Rules based on the dependency kind (dependencies vs devDependencies vs peerDependencies).
835
+ */
836
+ interface DependencyKindRules {
837
+ /**
838
+ * When true, a "library" project must not have workspace-internal devDependencies
839
+ * on other libraries that are also in its production dependencies.
840
+ * Prevents publishing libraries that silently rely on dev-only workspace packages.
841
+ * @default false
842
+ */
843
+ noDevDependencyOnProductionDep?: boolean;
844
+ /**
845
+ * When true, production `dependencies` must not point to "application" type projects.
846
+ * devDependencies on applications are allowed (e.g., for testing).
847
+ * @default false
848
+ */
849
+ noProductionDependencyOnApplication?: boolean;
850
+ }
851
+ /**
852
+ * Configuration for project constraint enforcement.
853
+ */
854
+ interface ConstraintsConfig {
855
+ /** Rules based on the dependency kind (static vs devDependency vs peerDependency) */
856
+ dependencyKindRules?: DependencyKindRules;
857
+ /**
858
+ * When true, projects can only depend on projects at the same or
859
+ * lower layer in the hierarchy:
860
+ *
861
+ * configuration < library < scaffolding < tool < automation < application
862
+ *
863
+ * Projects without an explicit `layer` are unconstrained.
864
+ * @default false
865
+ */
866
+ enforceLayerRelationships?: boolean;
867
+ /** Tag-based dependency rules */
868
+ tagRelationships?: TagRelationships;
869
+ /** Project-type-based dependency rules */
870
+ typeBoundaries?: TypeBoundaries;
871
+ }
872
+ /**
873
+ * A single constraint violation detected in the project graph.
874
+ */
875
+ interface ConstraintViolation {
876
+ /** The project being depended on */
877
+ dependencyProject: string;
878
+ /** Human-readable description of the violation */
879
+ message: string;
880
+ /** The type of rule that was violated */
881
+ rule: "dependency-kind" | "layer-relationship" | "tag-relationship" | "type-boundary";
882
+ /** The project that has the invalid dependency */
883
+ sourceProject: string;
884
+ }
885
+ /**
886
+ * Controls how far to traverse the dependency graph in a given direction.
887
+ * - "none": Don't traverse — only directly changed projects are included.
888
+ * - "direct": Include only immediate neighbors (one hop).
889
+ * - "deep": Include all transitive neighbors (full chain).
890
+ */
891
+ type AffectedScope = "deep" | "direct" | "none";
892
+ /**
893
+ * Workspace configuration containing all project configurations.
894
+ */
895
+ interface WorkspaceConfiguration {
896
+ /** All projects in the workspace, keyed by project name */
897
+ projects: Record<string, ProjectConfiguration>;
898
+ }
899
+ /**
900
+ * The kind of dependency relationship between projects.
901
+ * - "static": Production dependency (from `dependencies` in package.json)
902
+ * - "dynamic": Dynamically resolved dependency (e.g., lazy imports)
903
+ * - "implicit": Declared via `implicitDependencies` in project config
904
+ * - "devDependency": Development-only dependency (from `devDependencies`)
905
+ * - "peerDependency": Peer dependency (from `peerDependencies`)
906
+ */
907
+ type DependencyType = "devDependency" | "dynamic" | "implicit" | "peerDependency" | "static";
908
+ /**
909
+ * A dependency relationship in the project graph.
910
+ */
911
+ interface ProjectGraphDependency {
912
+ /** The source project */
913
+ source: string;
914
+ /** The target project */
915
+ target: string;
916
+ /** The type of dependency */
917
+ type: DependencyType;
918
+ }
919
+ /**
920
+ * A node in the project graph.
921
+ */
922
+ interface ProjectGraphProjectNode {
923
+ /** The project configuration */
924
+ data: ProjectConfiguration;
925
+ /** The project name */
926
+ name: string;
927
+ /** The type of project */
928
+ type: "library" | "application";
929
+ }
930
+ /**
931
+ * The project graph represents the dependency relationships between projects.
932
+ */
933
+ interface ProjectGraph {
934
+ /** All dependency relationships */
935
+ dependencies: Record<string, ProjectGraphDependency[]>;
936
+ /** All project nodes, keyed by project name */
937
+ nodes: Record<string, ProjectGraphProjectNode>;
938
+ }
939
+ /**
940
+ * Named input definitions that can be referenced by name.
941
+ */
942
+ interface NamedInputs {
943
+ [name: string]: (string | InputDefinition)[];
944
+ }
945
+ /**
946
+ * Configuration for the task runner.
947
+ */
948
+ interface TaskRunnerOptions {
949
+ /**
950
+ * Scan each task's resolved command text for `$VAR`/`${VAR}`
951
+ * references and automatically fingerprint those env vars. Catches
952
+ * tasks like `curl ${VERCEL_URL}/api` where the user forgot to
953
+ * declare the reference in `envVars`/`globalEnv`.
954
+ * @default false
955
+ */
956
+ autoEnvVars?: boolean;
957
+ /**
958
+ * Enable auto-fingerprinting mode (Vite Task-style).
959
+ * When enabled, the task runner automatically tracks which files
960
+ * a task accesses during execution and uses that for cache invalidation
961
+ * instead of requiring manual input configuration.
962
+ *
963
+ * Falls back to explicit inputs (Nx-style) when file tracking
964
+ * is not supported on the current platform.
965
+ * @default false
966
+ */
967
+ autoFingerprint?: boolean;
968
+ /**
969
+ * Whether to show cache miss diagnostics (why a cache miss occurred).
970
+ * @default false
971
+ */
972
+ cacheDiagnostics?: boolean;
973
+ /** Directory for storing cache */
974
+ cacheDirectory?: string;
975
+ /**
976
+ * Dry-run mode: compute hashes and check cache but don't execute tasks.
977
+ * Useful for debugging cache hits/misses.
978
+ * @default false
979
+ */
980
+ dryRun?: boolean;
981
+ /** Custom environment variables to include in hash */
982
+ envVars?: string[];
983
+ /**
984
+ * Environment variable patterns to include in auto-fingerprint.
985
+ * Supports wildcard patterns like "VITE_*".
986
+ * Only used when autoFingerprint is enabled.
987
+ */
988
+ fingerprintEnvPatterns?: string[];
989
+ /**
990
+ * Enable framework environment variable inference.
991
+ * When true, automatically detects common frontend frameworks and includes
992
+ * their public env var prefixes in the task hash:
993
+ * - Next.js: NEXT_PUBLIC_*
994
+ * - Vite: VITE_*
995
+ * - Create React App: REACT_APP_*
996
+ * - Gatsby: GATSBY_*
997
+ * - Nuxt: NUXT_PUBLIC_*
998
+ * - Expo: EXPO_PUBLIC_*
999
+ *
1000
+ * Matches Turborepo's framework inference behavior.
1001
+ * @default false
1002
+ */
1003
+ frameworkInference?: boolean;
1004
+ /**
1005
+ * Global environment variables that invalidate ALL task hashes.
1006
+ * Matches Turborepo's `globalEnv`.
1007
+ */
1008
+ globalEnv?: string[];
1009
+ /**
1010
+ * Global input files that invalidate ALL task hashes when changed.
1011
+ * These are workspace-root-relative paths.
1012
+ *
1013
+ * Default: ["package-lock.json", "pnpm-lock.yaml", "yarn.lock",
1014
+ * "tsconfig.base.json", ".env"]
1015
+ *
1016
+ * When any global input changes, every task's hash changes,
1017
+ * forcing a full rebuild. This matches Turborepo's `globalDependencies`.
1018
+ */
1019
+ globalInputs?: string[];
1020
+ /**
1021
+ * When `true`, file hashes are cached in a persistent mtime+size
1022
+ * indexed snapshot under `node_modules/.cache/task-runner/`. On
1023
+ * subsequent runs, unchanged files skip content re-reads — cuts
1024
+ * cold-cache fingerprint time dramatically on large workspaces.
1025
+ *
1026
+ * Changed or new files still get full content hashing. Safe to
1027
+ * leave on by default; overhead when nothing matches is a single
1028
+ * `stat` call per file.
1029
+ * @default false
1030
+ */
1031
+ incrementalFileHashing?: boolean;
1032
+ /** Maximum age of cache entries in milliseconds */
1033
+ maxCacheAge?: number;
1034
+ /** Maximum cache size (e.g., "1GB") */
1035
+ maxCacheSize?: string;
1036
+ /** Named inputs for cache invalidation */
1037
+ namedInputs?: NamedInputs;
1038
+ /**
1039
+ * When `true`, the cache directory is partitioned by a hash of
1040
+ * the resolved `globalEnv` values. Changing a globalEnv var moves
1041
+ * cache writes into a new namespace; rolling it back reuses the
1042
+ * old namespace and its hits. Without this option, any globalEnv
1043
+ * change silently busts every cached entry.
1044
+ *
1045
+ * Keep disabled when globalEnv is stable across runs — the extra
1046
+ * path depth offers no value, and misconfigured namespaces can
1047
+ * hide stale hits.
1048
+ * @default false
1049
+ */
1050
+ namespaceByGlobalEnv?: boolean;
1051
+ /** Maximum number of parallel tasks */
1052
+ parallel?: number | boolean;
1053
+ /**
1054
+ * Remote cache configuration.
1055
+ * When configured, the task runner checks the remote cache after a
1056
+ * local miss and uploads results after execution. See
1057
+ * {@link RemoteCacheOptions} for the full HTTP and REAPI surface.
1058
+ */
1059
+ remoteCache?: RemoteCacheOptions;
1060
+ /** Whether to skip cache reads */
1061
+ skipNxCache?: boolean;
1062
+ /**
1063
+ * Enable smart lockfile hashing.
1064
+ * Instead of hashing the entire lockfile (which busts ALL caches),
1065
+ * only hash the resolved versions of each package's actual dependencies.
1066
+ * This matches Turborepo's smart lockfile hashing behavior.
1067
+ * @default false
1068
+ */
1069
+ smartLockfileHashing?: boolean;
1070
+ /**
1071
+ * Generate a detailed JSON run summary after execution.
1072
+ * When true, writes a summary file to `.task-runner/runs/` containing
1073
+ * all task inputs, outputs, hashes, timings, and cache status.
1074
+ *
1075
+ * Useful for debugging cache misses and comparing runs.
1076
+ * Matches Turborepo's `--summarize` flag.
1077
+ * @default false
1078
+ */
1079
+ summarize?: boolean;
1080
+ /** Target-specific default configurations */
1081
+ targetDefaults?: Record<string, Partial<TargetConfiguration>>;
1082
+ /**
1083
+ * Environment variables that should be passed to tasks but NOT
1084
+ * included in the cache fingerprint. Useful for CI-specific vars.
1085
+ * Only used when autoFingerprint is enabled.
1086
+ */
1087
+ untrackedEnvVars?: string[];
1088
+ }
1089
+ /**
1090
+ * Options for executing a task.
1091
+ */
1092
+ interface TaskExecutionOptions {
1093
+ /** Whether to capture output */
1094
+ captureOutput?: boolean;
1095
+ /** The working directory */
1096
+ cwd?: string;
1097
+ /** Environment variables */
1098
+ env?: Record<string, string>;
1099
+ /** Stream output as it arrives */
1100
+ streamOutput?: boolean;
1101
+ }
1102
+ /**
1103
+ * A task executor function.
1104
+ */
1105
+ type TaskExecutor = (task: Task, options: TaskExecutionOptions) => Promise<{
1106
+ code: number;
1107
+ terminalOutput: string;
1108
+ }>;
1109
+ /**
1110
+ * The function type for a task runner.
1111
+ */
1112
+ type TasksRunner = (tasks: Task[], options: TaskRunnerOptions, context: TaskRunnerContext) => Promise<TaskResults>;
1113
+ /**
1114
+ * Context provided to the task runner.
1115
+ */
1116
+ interface TaskRunnerContext {
1117
+ /** Lifecycle hooks */
1118
+ lifeCycle: LifeCycleInterface;
1119
+ /** The project graph */
1120
+ projectGraph: ProjectGraph;
1121
+ /** The task executor */
1122
+ taskExecutor: TaskExecutor;
1123
+ /** The task graph */
1124
+ taskGraph: TaskGraph;
1125
+ /** The workspace root directory */
1126
+ workspaceRoot: string;
1127
+ }
1128
+ /**
1129
+ * Input for a concurrent command -- either a string or a config object.
1130
+ */
1131
+ type ConcurrentCommandInput = string | {
1132
+ command: string;
1133
+ cwd?: string;
1134
+ env?: Record<string, string>;
1135
+ name?: string; /** Initial PTY dimensions (only used when stdin is "pty"). */
1136
+ ptySize?: {
1137
+ cols: number;
1138
+ rows: number;
1139
+ };
1140
+ stdin?: "inherit" | "null" | "pipe" | "pty";
1141
+ };
1142
+ /**
1143
+ * Configuration for a single command to run concurrently.
1144
+ */
1145
+ interface ConcurrentCommandConfig {
1146
+ /** The command string to execute (passed to shell). */
1147
+ command: string;
1148
+ /** Working directory for the command. */
1149
+ cwd?: string;
1150
+ /** Additional environment variables merged with process env. */
1151
+ env?: Record<string, string>;
1152
+ /** Human-readable name for this command (used in prefixes/logs). */
1153
+ name?: string;
1154
+ /**
1155
+ * Initial PTY dimensions. Only used when stdin is "pty".
1156
+ * Defaults to 80x24 if not specified.
1157
+ */
1158
+ ptySize?: {
1159
+ cols: number;
1160
+ rows: number;
1161
+ };
1162
+ /** Whether to use shell execution (default: true). */
1163
+ shell?: boolean;
1164
+ /**
1165
+ * Stdin mode for the child process.
1166
+ * - "null" (default): stdin closed, child cannot read input
1167
+ * - "pipe": stdin is piped, can be written to programmatically
1168
+ * - "inherit": child inherits parent's stdin (for interactive commands like vite dev)
1169
+ * - "pty": child runs inside a pseudo-terminal (isatty() returns true, enables interactive prompts)
1170
+ */
1171
+ stdin?: "inherit" | "null" | "pipe" | "pty";
1172
+ }
1173
+ /**
1174
+ * Options controlling the concurrent runner behavior.
1175
+ */
1176
+ interface ConcurrentRunnerOptions {
1177
+ /** Conditions under which to kill other processes: "success", "failure". */
1178
+ killOthers?: ("failure" | "success")[];
1179
+ /** Signal to send when killing processes (default: "SIGTERM"). */
1180
+ killSignal?: string;
1181
+ /** Milliseconds to wait after kill signal before sending SIGKILL (default: 5000). */
1182
+ killTimeout?: number;
1183
+ /** Maximum number of processes to run simultaneously. 0 = unlimited. */
1184
+ maxProcesses?: number;
1185
+ /** Callback for real-time process events. */
1186
+ onEvent?: (event: ProcessEvent) => void;
1187
+ /** Restart options for failed commands. */
1188
+ restart?: {
1189
+ /** Delay between restarts in ms. "exponential" for 2^attempt * 1000ms. */
1190
+ delay?: number | "exponential";
1191
+ /** Maximum restart attempts per command. 0 = no restarts. -1 = infinite. */
1192
+ tries: number;
1193
+ };
1194
+ /**
1195
+ * Custom shell path for command execution.
1196
+ * Overrides the platform default (/bin/sh on Unix, cmd.exe on Windows).
1197
+ * Automatically detected from npm's `script-shell` config if not set.
1198
+ */
1199
+ shellPath?: string;
1200
+ /** Success condition: "first", "last", "all", or "command-&lt;name|index>". */
1201
+ successCondition?: string;
1202
+ /** Commands to run sequentially after all processes complete. */
1203
+ teardown?: string[];
1204
+ /** Working directory for teardown commands. */
1205
+ teardownCwd?: string;
1206
+ /** Print a timing summary table after completion. Default: false. */
1207
+ timings?: boolean;
1208
+ }
1209
+ /**
1210
+ * An event emitted during concurrent execution.
1211
+ */
1212
+ interface ProcessEvent {
1213
+ /** Command name (for close events). */
1214
+ commandName?: string;
1215
+ /** Duration in milliseconds (for close events). */
1216
+ durationMs?: number;
1217
+ /** Exit code (for close events). */
1218
+ exitCode?: number;
1219
+ /** Index of the command that produced this event. */
1220
+ index: number;
1221
+ /** Kill the child process/PTY. Only present on "started" events. */
1222
+ kill?: (signal?: string) => void;
1223
+ /** Whether the process was killed (for close events). */
1224
+ killed?: boolean;
1225
+ /** Event type: "stdout", "stderr", "close", "error", "started". */
1226
+ kind: "close" | "error" | "started" | "stderr" | "stdout";
1227
+ /** Error message (for error events). */
1228
+ message?: string;
1229
+ /** Resize the child's PTY. Only present on "started" events with stdin "pty". */
1230
+ resize?: (cols: number, rows: number) => void;
1231
+ /** Text content (for stdout/stderr events). */
1232
+ text?: string;
1233
+ /** Write data to the child's stdin (pipe) or PTY. Only present on "started" events. */
1234
+ write?: (data: string) => void;
1235
+ }
1236
+ /**
1237
+ * Result of a close event for a single command.
1238
+ */
1239
+ interface ConcurrentCloseEvent {
1240
+ /** The command string that was executed. */
1241
+ command: string;
1242
+ /** Duration in milliseconds. */
1243
+ durationMs: number;
1244
+ /** Exit code. -1 if killed by signal. */
1245
+ exitCode: number;
1246
+ /** Index of the command. */
1247
+ index: number;
1248
+ /** Whether the process was forcefully killed. */
1249
+ killed: boolean;
1250
+ /** The command name (if provided). */
1251
+ name?: string;
1252
+ }
1253
+ /**
1254
+ * Overall result of a concurrent run.
1255
+ */
1256
+ interface ConcurrentRunResult {
1257
+ /** Close events for all commands, in completion order. */
1258
+ closeEvents: ConcurrentCloseEvent[];
1259
+ /** Whether the run succeeded according to the success condition. */
1260
+ success: boolean;
1261
+ }
1262
+ /**
1263
+ * Interface for lifecycle event handlers.
1264
+ */
1265
+ interface LifeCycleInterface {
1266
+ endCommand?: () => void;
1267
+ endTasks?: (taskResults: TaskResult[]) => void;
1268
+ /**
1269
+ * Called when a running task emits data on stderr, in the order the
1270
+ * data arrives. Executors that support streaming output (`vis run`'s
1271
+ * concurrent executor) forward chunks here verbatim. Executors that
1272
+ * only buffer full output (e.g. the simple test executor) skip this
1273
+ * hook — rely on `printTaskTerminalOutput` for the final dump.
1274
+ *
1275
+ * Handlers should be non-blocking; the orchestrator doesn't await.
1276
+ */
1277
+ onTaskStderr?: (task: Task, chunk: string) => void;
1278
+ /**
1279
+ * Called when a running task emits data on stdout, in the order the
1280
+ * data arrives. See {@link LifeCycleInterface.onTaskStderr} for
1281
+ * semantics — same contract, different stream.
1282
+ */
1283
+ onTaskStdout?: (task: Task, chunk: string) => void;
1284
+ /** Called when a cache miss occurs with diagnostic information */
1285
+ printCacheMiss?: (task: Task, reasons: string) => void;
1286
+ /**
1287
+ * Called when caching was skipped because auto-fingerprint tracking
1288
+ * came back empty — a signal that the tracker (strace or Node
1289
+ * preload) couldn't observe the task's file access, typically
1290
+ * because it's a static binary on a platform without strace.
1291
+ * `reason` is a short human-readable diagnostic.
1292
+ */
1293
+ printEmptyFingerprintWarning?: (task: Task, reason: string) => void;
1294
+ /**
1295
+ * Called when caching is skipped because the task modified one or
1296
+ * more of its own tracked inputs. `modifiedFiles` lists the
1297
+ * workspace-relative paths that changed between pre- and
1298
+ * post-execution hashes.
1299
+ */
1300
+ printSelfModifyingSkip?: (task: Task, modifiedFiles: string[]) => void;
1301
+ printTaskTerminalOutput?: (task: Task, status: TaskStatus, terminalOutput: string) => void;
1302
+ /**
1303
+ * Called when a task is skipped because its `when` clause did not
1304
+ * match the current environment. `reason` is a short
1305
+ * human-readable diagnostic produced by {@link import("./when-condition").explainWhen}.
1306
+ *
1307
+ * Co-fires with `printTaskTerminalOutput` (status `"skipped"`,
1308
+ * output `"Skipped: [reason]"`). Pick one to render — implementing
1309
+ * both will double-report the skip.
1310
+ */
1311
+ printWhenSkip?: (task: Task, reason: string) => void;
1312
+ scheduleTask?: (task: Task) => void;
1313
+ startCommand?: () => void;
1314
+ startTasks?: (tasks: Task[]) => void;
1315
+ }
1316
+ /**
1317
+ * Options for determining affected projects.
1318
+ */
1319
+ interface AffectedOptions {
1320
+ /** The base ref to compare against (default: "main") */
1321
+ base?: string;
1322
+ /**
1323
+ * Control how far downstream (dependents of changed projects) to include.
1324
+ * @default "deep"
1325
+ */
1326
+ downstream?: AffectedScope;
1327
+ /** The head ref to compare (default: "HEAD") */
1328
+ head?: string;
1329
+ /** Project graph for dependency resolution */
1330
+ projectGraph: ProjectGraph;
1331
+ /** All project configurations keyed by name */
1332
+ projects: Record<string, ProjectConfiguration>;
1333
+ /**
1334
+ * Control how far upstream (dependencies of changed projects) to include.
1335
+ * @default "none"
1336
+ */
1337
+ upstream?: AffectedScope;
1338
+ /** The workspace root directory */
1339
+ workspaceRoot: string;
1340
+ }
1341
+ /**
1342
+ * Result of affected detection.
1343
+ */
1344
+ interface AffectedResult {
1345
+ /** All affected projects (union of changed, downstream, and upstream) */
1346
+ affectedProjects: string[];
1347
+ /** Files that changed between base and head */
1348
+ changedFiles: string[];
1349
+ /** Projects that were directly changed */
1350
+ changedProjects: string[];
1351
+ /** Projects affected because they depend on changed projects */
1352
+ downstreamProjects: string[];
1353
+ /** Projects that changed projects depend on */
1354
+ upstreamProjects: string[];
1355
+ }
1356
+ /**
1357
+ * Builds a map from each project to the set of projects that depend on it (reverse/downstream).
1358
+ */
1359
+ declare const buildReverseDependencyMap: (projectGraph: ProjectGraph) => Map<string, Set<string>>;
1360
+ /**
1361
+ * Builds a map from each project to the set of projects it depends on (forward/upstream).
1362
+ */
1363
+ declare const buildForwardDependencyMap: (projectGraph: ProjectGraph) => Map<string, Set<string>>;
1364
+ /**
1365
+ * Expands a set of changed projects based on upstream/downstream scope settings.
1366
+ * Returns a new set containing all affected projects.
1367
+ */
1368
+ declare const expandAffected: (changedProjects: Set<string>, projectGraph: ProjectGraph, options: {
1369
+ downstream: AffectedScope;
1370
+ upstream: AffectedScope;
1371
+ }) => {
1372
+ affected: Set<string>;
1373
+ downstream: Set<string>;
1374
+ upstream: Set<string>;
1375
+ };
1376
+ /**
1377
+ * Gets the list of files changed between two git refs.
1378
+ * Uses execFile with argument arrays to prevent command injection.
1379
+ */
1380
+ declare const getChangedFiles: (workspaceRoot: string, base: string, head: string) => Promise<string[]>;
1381
+ /**
1382
+ * Determines which projects are affected by changes between two git refs.
1383
+ *
1384
+ * Uses `git diff` to find changed files, maps them to projects based on
1385
+ * project roots, then walks the project dependency graph to find all
1386
+ * transitively affected projects.
1387
+ *
1388
+ * This is the same strategy used by `nx affected` and `turbo run --filter=[base...]`.
1389
+ */
1390
+ declare const getAffectedProjects: (options: AffectedOptions) => Promise<AffectedResult>;
1391
+ /**
1392
+ * Filters tasks to only include those that are affected by changes.
1393
+ */
1394
+ declare const filterAffectedTasks: (taskIds: string[], affectedProjects: Set<string>) => string[];
1395
+ /**
1396
+ * Resolves the canonical {@link CacheMode}. `mode` defaults to
1397
+ * `"readwrite"` when unset — the safe choice for CI and the most
1398
+ * common config in dev. Kept as a separate helper so vis-side code
1399
+ * (CLI flag merge, doctor probes) can reuse the resolution rule.
1400
+ */
1401
+ declare const resolveCacheMode: (options: {
1402
+ mode?: CacheMode;
1403
+ }) => CacheMode;
1404
+ /**
1405
+ * Construct the configured remote cache backend. Selects between the
1406
+ * Turborepo-compatible HTTP client and the Bazel REAPI gRPC client
1407
+ * via `options.backend`.
1408
+ */
1409
+ declare const createRemoteCacheBackend: (options: RemoteCacheOptions) => RemoteCacheBackend;
1410
+ /**
1411
+ * Derive a stable {@link CasDigest} from the orchestrator's task hash
1412
+ * (xxh3-128, 32 hex chars). REAPI servers reject non-sha256 digests on
1413
+ * the wire, so we sha256 a namespaced key. The HTTP backend uses the
1414
+ * resulting digest as the artifact URL component.
1415
+ *
1416
+ * `sizeBytes` is set to `0` because this digest identifies an *action*
1417
+ * (an `ActionResult` keyed in the AC), not a stored CAS blob. REAPI
1418
+ * `Digest` size_bytes only carries meaning for blobs in the CAS — for
1419
+ * action keys it's ignored by the server. Setting it to the byte
1420
+ * length of the prehash key would be semantically wrong: the server
1421
+ * would believe a blob of that exact length exists at this hash, and
1422
+ * a downstream `BatchReadBlobs` against this digest would mismatch.
1423
+ */
1424
+ declare const actionDigestForTaskHash: (taskHash: string) => CasDigest;
1425
+ /**
1426
+ * Probe whether a cached entry exists on the remote backend, keyed by
1427
+ * the orchestrator's task hash. Resolves `false` on any wire failure —
1428
+ * the orchestrator treats existence checks as best-effort.
1429
+ */
1430
+ declare const containsByTaskHash: (backend: RemoteCacheBackend, taskHash: string) => Promise<boolean>;
1431
+ /**
1432
+ * Download the cached entry for `taskHash` and extract it into
1433
+ * `{localCacheDirectory}/{taskHash}/`. Returns `true` only when the
1434
+ * directory has been fully populated; partial-extract failures clean
1435
+ * up after themselves so the local cache never observes a half-populated
1436
+ * entry.
1437
+ */
1438
+ declare const retrieveByTaskHash: (backend: RemoteCacheBackend, taskHash: string, localCacheDirectory: string) => Promise<boolean>;
1439
+ /**
1440
+ * Tar `{localCacheDirectory}/{taskHash}/` and upload as a single CAS
1441
+ * blob via {@link RemoteCacheBackend.storeAction}. Skips the upload
1442
+ * unless `.commit` is present so we never publish a half-written entry.
1443
+ *
1444
+ * The lazy {@link BlobSource.open} returns a fresh `createReadStream`
1445
+ * each call so REAPI's `FindMissingBlobs` → `BatchUpdateBlobs` →
1446
+ * fallback `Write` flow can re-read the file as many times as it needs
1447
+ * to without requiring the bridge to buffer the bytes in memory.
1448
+ *
1449
+ * Bridge-local failures (`createTarGz`, `digestFile`) are surfaced
1450
+ * through `onUploadError` when provided, then swallowed so the
1451
+ * fire-and-forget call site stays non-throwing. A missing `.commit`
1452
+ * marker is *not* an error — it's the normal "skip this upload" path.
1453
+ */
1454
+ declare const storeByTaskHash: (backend: RemoteCacheBackend, taskHash: string, localCacheDirectory: string, onUploadError?: (hash: string, error: unknown) => void) => Promise<boolean>;
1455
+ /**
1456
+ * HTTP-based remote cache compatible with the Turborepo remote cache protocol.
1457
+ *
1458
+ * Protocol:
1459
+ * - GET /v8/artifacts/{hash}?teamId={team} -> retrieve cached artifact (gzipped tar)
1460
+ * - PUT /v8/artifacts/{hash}?teamId={team} -> store artifact
1461
+ * - POST /v8/artifacts/events -> analytics (optional)
1462
+ *
1463
+ * Authentication via `Authorization: Bearer {token}` header.
1464
+ *
1465
+ * The cache entry is a gzipped tarball containing the cache directory contents
1466
+ * (code, terminalOutput, fingerprint.json, outputs/, .commit).
1467
+ */
1468
+ declare class HttpRemoteCache implements RemoteCacheBackend {
1469
+ #private;
1470
+ constructor(options: RemoteCacheOptions);
1471
+ /**
1472
+ * No-op. The HTTP backend uses Node's global `fetch`, which has no
1473
+ * persistent connection to release. Implemented to satisfy the
1474
+ * {@link RemoteCacheBackend.close} contract uniformly.
1475
+ */
1476
+ close(): Promise<void>;
1477
+ /**
1478
+ * {@link RemoteCacheBackend.containsAction}: HEAD on the artifact URL.
1479
+ * Resolves `false` on any wire failure — existence checks are best
1480
+ * effort and never block the caller.
1481
+ */
1482
+ containsAction(actionDigest: CasDigest): Promise<boolean>;
1483
+ /**
1484
+ * {@link RemoteCacheBackend.fetchBlob}: streams a blob out of the
1485
+ * local CAS that was hydrated by a previous {@link retrieveAction}
1486
+ * call. The HTTP wire ships one tarball per action, so per-blob
1487
+ * fetches are local-only — there's no remote endpoint to call.
1488
+ */
1489
+ fetchBlob(digest: CasDigest, destinationPath: string): Promise<boolean>;
1490
+ /**
1491
+ * {@link RemoteCacheBackend.retrieveAction}: GETs the artifact at
1492
+ * `/v8/artifacts/{actionDigest.hash}`, ingests the response bytes
1493
+ * as a single CAS blob in the local store, and synthesises an
1494
+ * {@link ActionResult} that points at that blob. Resolves to `null`
1495
+ * on a 404 / signature mismatch / missing local CAS root.
1496
+ */
1497
+ retrieveAction(actionDigest: CasDigest): Promise<ActionResult | null>;
1498
+ /**
1499
+ * {@link RemoteCacheBackend.storeAction}: takes the single blob
1500
+ * referenced by `result.outputFiles[0]`, streams its bytes as the
1501
+ * PUT body, and signs the body when a signing secret is configured.
1502
+ * Per-digest in-flight dedup means parallel writers racing on the
1503
+ * same action upload exactly once.
1504
+ */
1505
+ storeAction(actionDigest: CasDigest, result: ActionResult, blobs: ReadonlyArray<BlobSource>): Promise<boolean>;
1506
+ }
1507
+ /**
1508
+ * REAPI-specific options accepted by {@link ReapiRemoteCache}. A type
1509
+ * alias rather than its own interface so callers can hand the same
1510
+ * object to the backend factory or to the constructor directly without
1511
+ * rewriting field names. HTTP-only fields (`signing`, `compression`)
1512
+ * are silently ignored here.
1513
+ */
1514
+ type ReapiRemoteCacheOptions = RemoteCacheOptions;
1515
+ /**
1516
+ * Bazel REAPI gRPC backend. Implements {@link RemoteCacheBackend} over
1517
+ * `ContentAddressableStorage` + `ActionCache` + `Capabilities` +
1518
+ * `google.bytestream.ByteStream`. Battle-tested REAPI servers
1519
+ * (`bazel-remote`, BuildBuddy, BuildBarn, EngFlow) become drop-in
1520
+ * backends with no per-server adapter.
1521
+ *
1522
+ * Wire flow:
1523
+ * - retrieveAction → GetActionResult → fetchBlob (BatchReadBlobs|Read)
1524
+ * - storeAction → FindMissingBlobs → BatchUpdateBlobs|Write → UpdateActionResult
1525
+ */
1526
+ declare class ReapiRemoteCache implements RemoteCacheBackend {
1527
+ #private;
1528
+ constructor(options: ReapiRemoteCacheOptions);
1529
+ /**
1530
+ * Close all gRPC channels held by this backend. Idempotent — safe
1531
+ * to call multiple times, and safe to call before any RPC was
1532
+ * issued. If `#getClients` is currently in flight we await its
1533
+ * resolution so the underlying channels are observable to close.
1534
+ */
1535
+ close(): Promise<void>;
1536
+ /**
1537
+ * Diagnostic probe — fetches the server's `Capabilities` RPC response
1538
+ * (or the cached value, if a previous call already negotiated). Used
1539
+ * by `vis cache doctor` to surface what the server advertises without
1540
+ * forcing the operator to issue a real CAS RPC.
1541
+ *
1542
+ * Bypasses the read/write mode gate intentionally: a probe must work
1543
+ * even on a cache configured `mode: "write"` so the operator can
1544
+ * verify the connection regardless of how the runner uses it.
1545
+ */
1546
+ probeCapabilities(): Promise<{
1547
+ digestFunctions: ReadonlyArray<string>;
1548
+ maxBatchTotalSizeBytes: number;
1549
+ }>;
1550
+ containsAction(actionDigest: CasDigest): Promise<boolean>;
1551
+ fetchBlob(digest: CasDigest, destinationPath: string): Promise<boolean>;
1552
+ retrieveAction(actionDigest: CasDigest): Promise<ActionResult | null>;
1553
+ storeAction(actionDigest: CasDigest, result: ActionResult, blobs: ReadonlyArray<BlobSource>): Promise<boolean>;
1554
+ }
1555
+ /**
1556
+ * Per-call control over restore fidelity. Both default to `true` —
1557
+ * the cache's job is to recreate exactly what was captured, and any
1558
+ * deviation is opt-in. Callers (e.g. vis target config) can flip
1559
+ * either off when downstream tooling needs a "fresh" mtime/mode.
1560
+ */
1561
+ interface ExtractOptions {
1562
+ preserveMtime?: boolean;
1563
+ preservePerms?: boolean;
1564
+ }
1565
+ /**
1566
+ * Represents a cached task result.
1567
+ */
1568
+ interface CachedResult {
1569
+ /** The exit code of the original task execution */
1570
+ code: number;
1571
+ /** The auto-fingerprint data, if auto-fingerprinting was used */
1572
+ fingerprint?: TaskFingerprint;
1573
+ /** The hash that was used as the cache key */
1574
+ hash: string;
1575
+ /** The terminal output of the original task execution */
1576
+ terminalOutput: string;
1577
+ }
1578
+ /**
1579
+ * Options for creating a Cache instance.
1580
+ */
1581
+ interface CacheOptions {
1582
+ /** The cache directory (defaults to `{workspaceRoot}/.task-runner-cache`) */
1583
+ cacheDirectory?: string;
1584
+ /**
1585
+ * Optional isolation namespace appended to the cache directory
1586
+ * as `&lt;cacheDir>/ns/&lt;namespace>`. When the caller derives the
1587
+ * namespace from the resolved global-env fingerprint, flipping an
1588
+ * env var sends writes into a new namespace while keeping the old
1589
+ * namespace intact — rolling the env back restores the old hits.
1590
+ *
1591
+ * Filesystem-safe segment; callers are responsible for sanitising
1592
+ * (slashes/colons would break path resolution).
1593
+ */
1594
+ cacheNamespace?: string;
1595
+ /** Maximum age of cache entries in milliseconds (default: 7 days) */
1596
+ maxCacheAge?: number;
1597
+ /** Maximum cache size (e.g., "500MB", "1GB") */
1598
+ maxCacheSize?: string;
1599
+ /** The workspace root directory */
1600
+ workspaceRoot: string;
1601
+ }
1602
+ /**
1603
+ * Directory name (relative to `workspaceRoot`) where the task runner writes
1604
+ * its cache by default. Exported so callers that manage the cache from the
1605
+ * outside — e.g. a CLI `cache clean` command — can reach the same default
1606
+ * without hard-coding the literal.
1607
+ */
1608
+ declare const DEFAULT_CACHE_DIRECTORY_NAME = ".task-runner-cache";
1609
+ /**
1610
+ * Parses a human-readable cache size string into bytes.
1611
+ * Delegates to @visulima/humanizer's parseBytes with base-2 (1024) multipliers.
1612
+ */
1613
+ declare const parseCacheSize: (sizeString: string) => number;
1614
+ /**
1615
+ * Formats a byte count into a human-readable string.
1616
+ * Delegates to @visulima/humanizer's formatBytes with base-2 (1024) multipliers.
1617
+ */
1618
+ declare const formatCacheSize: (bytes: number) => string;
1619
+ /**
1620
+ * Local file-based cache for task results.
1621
+ *
1622
+ * Cache structure:
1623
+ * ```
1624
+ * .task-runner-cache/
1625
+ * &lt;hash&gt;/
1626
+ * outputs/ (Archived build outputs)
1627
+ * code (Exit code)
1628
+ * terminalOutput (Captured terminal output)
1629
+ * fingerprint.json (Auto-fingerprint data, optional)
1630
+ * .commit (Marker indicating complete cache entry)
1631
+ * .task-index.json (Task ID -> hash mapping for auto-fingerprint)
1632
+ * ```
1633
+ *
1634
+ * Atomicity: Cache entries are written to a temporary directory first,
1635
+ * then renamed into place. The `.commit` marker ensures readers only
1636
+ * see complete entries.
1637
+ */
1638
+ declare class Cache {
1639
+ #private;
1640
+ constructor(options: CacheOptions);
1641
+ /**
1642
+ * Gets the cache directory path.
1643
+ */
1644
+ get cacheDirectory(): string;
1645
+ /**
1646
+ * Root for v2 CAS-shaped reads/writes. Backend implementations
1647
+ * (HTTP today, REAPI gRPC next) take this path so they can
1648
+ * hydrate fetched blobs into the same CAS the local cache reads
1649
+ * from. Equal to {@link cacheDirectory} — `v2/` lives under that.
1650
+ */
1651
+ get casRoot(): string;
1652
+ /**
1653
+ * Read a v2 {@link ActionResult} by action digest. Resolves to
1654
+ * `null` on miss. The orchestrator is expected to follow up with
1655
+ * {@link materializeOutputs} to place the referenced blobs into
1656
+ * the workspace.
1657
+ */
1658
+ getActionResult(actionDigest: CasDigest): Promise<ActionResult | null>;
1659
+ /**
1660
+ * Look up an action digest by the legacy task hash. Returns
1661
+ * `null` when the bridge file isn't present — caller falls
1662
+ * through to the legacy `&lt;hash>/` layout (or executes the task).
1663
+ */
1664
+ resolveActionDigestForTaskHash(taskHash: string): Promise<string | null>;
1665
+ /**
1666
+ * Persist a v2 entry: writes the AC JSON, copies referenced
1667
+ * blobs into the CAS via the lazy {@link BlobSource} handles,
1668
+ * and binds the task hash → action digest redirect last so a
1669
+ * partial failure can't surface a half-written entry.
1670
+ */
1671
+ putActionResult(taskHash: string, actionDigest: CasDigest, result: ActionResult, blobs: ReadonlyArray<BlobSource>): Promise<void>;
1672
+ /**
1673
+ * Materialize an action's outputs into the workspace. Streams
1674
+ * each referenced blob from the local CAS to its workspace path.
1675
+ * Returns `false` when any blob is missing — caller treats that
1676
+ * as a cache miss and re-executes.
1677
+ */
1678
+ materializeOutputs(result: ActionResult, workspaceRoot: string): Promise<boolean>;
1679
+ /**
1680
+ * Retrieves a cached result for the given task hash.
1681
+ * Returns undefined if no valid cache entry exists.
1682
+ */
1683
+ get(hash: string): Promise<CachedResult | undefined>;
1684
+ /**
1685
+ * Stores a task result in the cache.
1686
+ *
1687
+ * Uses atomic write: builds the entry in a temporary directory,
1688
+ * then renames into place to avoid partial reads by concurrent processes.
1689
+ *
1690
+ * `outputs` accepts the richer `OutputSpec[]` shape — glob
1691
+ * patterns, negative globs, and `{ auto: true }` entries. Pass
1692
+ * `autoWrites` alongside `{ auto: true }` so the resolver knows
1693
+ * which files the task actually wrote; otherwise auto entries
1694
+ * contribute nothing.
1695
+ */
1696
+ put(hash: string, terminalOutput: string, outputs: OutputSpec[], code: number, fingerprint?: TaskFingerprint, autoWrites?: ReadonlyArray<string>): Promise<void>;
1697
+ /**
1698
+ * Restores cached outputs from the compressed `outputs.tar.br`
1699
+ * archive. Returns `true` either when the archive was extracted
1700
+ * successfully OR when the entry simply has no outputs to restore.
1701
+ *
1702
+ * The restore flow stages into a temp directory, then swaps each
1703
+ * top-level entry into place (see {@link restoreOutputsCompressed})
1704
+ * so a mid-restore failure never destroys the user's working tree.
1705
+ * The `outputs` parameter is no longer consulted at restore time —
1706
+ * the archive is authoritative, and top-level entries in the
1707
+ * extracted staging become the set of swap roots. Still accepted
1708
+ * for backward compat.
1709
+ */
1710
+ restoreOutputs(hash: string, _outputs?: OutputSpec[], options?: ExtractOptions): Promise<boolean>;
1711
+ /**
1712
+ * Retrieves the most recent cached result for a task by its ID.
1713
+ * Used in auto-fingerprint mode where the hash is derived from
1714
+ * tracked file accesses rather than computed upfront.
1715
+ */
1716
+ getByTaskId(taskId: string): Promise<CachedResult | undefined>;
1717
+ /**
1718
+ * Stores the mapping from task ID to cache hash.
1719
+ * Uses a write queue to serialize concurrent writes and prevent lost updates.
1720
+ * Each write is atomic (temp file + rename).
1721
+ */
1722
+ setTaskIndex(taskId: string, hash: string): Promise<void>;
1723
+ /**
1724
+ * Removes old cache entries that exceed the maximum age,
1725
+ * and enforces the maximum cache size by evicting oldest entries.
1726
+ */
1727
+ removeOldEntries(): Promise<void>;
1728
+ /**
1729
+ * Clears the entire cache.
1730
+ */
1731
+ clear(): Promise<void>;
1732
+ }
1733
+ /**
1734
+ * Compute the sha256 digest of a buffer's bytes. Lowercase hex, matching
1735
+ * REAPI's `Digest.hash` format. Used for synchronous payloads (small
1736
+ * AC metadata, action proto bytes) where streaming isn't worth it.
1737
+ */
1738
+ declare const digestBuffer: (bytes: Buffer) => CasDigest;
1739
+ /**
1740
+ * Compute the sha256 digest of a file's contents by streaming. Avoids
1741
+ * loading multi-hundred-MB outputs into memory. Returns `undefined`
1742
+ * when the file can't be opened (caller decides whether that's fatal).
1743
+ */
1744
+ declare const digestFile: (filePath: string) => Promise<CasDigest | undefined>;
1745
+ /**
1746
+ * v2 layout root inside the cache directory. Coexists with the legacy
1747
+ * `&lt;cacheDir>/&lt;hash>/` entries until the migration window closes.
1748
+ */
1749
+ declare const V2_ROOT = "v2";
1750
+ /**
1751
+ * Sub-roots under `v2/`. CAS holds raw blob bytes, AC holds JSON
1752
+ * `ActionResult` entries, the task-hash index bridges xxh3 task hashes
1753
+ * to sha256 action digests, tmp stages atomic renames.
1754
+ */
1755
+ declare const V2_CAS = "cas";
1756
+ declare const V2_AC = "ac";
1757
+ declare const V2_INDEX = "task-hash-index";
1758
+ declare const V2_TMP = "tmp";
1759
+ /**
1760
+ * Resolve the on-disk path for a CAS blob. `&lt;root>/v2/cas/&lt;aa>/&lt;hash>`.
1761
+ */
1762
+ declare const casBlobPath: (root: string, hash: string) => string;
1763
+ /**
1764
+ * Resolve the on-disk path for an Action Cache entry. AC entries are
1765
+ * JSON, suffix kept off-disk to match REAPI semantics (the action
1766
+ * digest is the file name).
1767
+ */
1768
+ declare const acEntryPath: (root: string, actionHash: string) => string;
1769
+ /**
1770
+ * Resolve the path for the task-hash → action-digest redirect. 64-byte
1771
+ * file containing the action digest hex; lets `Cache.get(taskHash)`
1772
+ * jump to the AC entry without recomputing the action proto.
1773
+ */
1774
+ declare const taskHashIndexPath: (root: string, taskHash: string) => string;
1775
+ /**
1776
+ * Returns `true` if the CAS blob already exists on disk for the given
1777
+ * digest. Caller uses this for `FindMissingBlobs`-style elision and to
1778
+ * avoid re-uploading bytes the local cache already holds.
1779
+ */
1780
+ declare const containsBlob: (root: string, digest: CasDigest) => Promise<boolean>;
1781
+ /**
1782
+ * Stream a CAS blob from a source path into the store. The blob is
1783
+ * staged under `v2/tmp/` and renamed into `v2/cas/&lt;aa>/&lt;digest>` after
1784
+ * the bytes land. Idempotent: a concurrent writer racing on the same
1785
+ * digest results in two POSIX renames over byte-identical content,
1786
+ * which is atomic per POSIX. On Windows we treat `EEXIST` as success.
1787
+ *
1788
+ * `digest.hash` is trusted — the caller is responsible for computing
1789
+ * the sha256 of the source file first. Re-hashing here would double
1790
+ * the IO on every put.
1791
+ */
1792
+ declare const putBlobFromFile: (root: string, digest: CasDigest, sourcePath: string) => Promise<void>;
1793
+ /**
1794
+ * Same as {@link putBlobFromFile} but for in-memory bytes. Used for
1795
+ * tiny payloads (the AC entry's stdout digest, tree protos) where
1796
+ * streaming would be more code than it's worth.
1797
+ */
1798
+ declare const putBlobFromBytes: (root: string, digest: CasDigest, bytes: Buffer) => Promise<void>;
1799
+ /**
1800
+ * Materialize a CAS blob to a destination path. Streams; safe for
1801
+ * large outputs. Returns `false` if the blob isn't in the local store.
1802
+ */
1803
+ declare const fetchBlobToFile: (root: string, digest: CasDigest, destinationPath: string) => Promise<boolean>;
1804
+ /**
1805
+ * Verify a blob's bytes match its expected digest. Used during legacy
1806
+ * → v2 migration where we trust nothing — sha256 every staged file
1807
+ * before the rename so a bit-flipped legacy artifact doesn't poison
1808
+ * the new CAS.
1809
+ */
1810
+ declare const verifyBlob: (filePath: string, expected: CasDigest) => Promise<boolean>;
1811
+ /**
1812
+ * Bump mtime/atime on a blob. Drives mark-and-sweep GC: the sweeper
1813
+ * evicts blobs whose mtime is older than `maxCacheAge` AND not
1814
+ * referenced by any AC entry. Touching on hit means LRU tracks real
1815
+ * usage rather than write-time.
1816
+ */
1817
+ declare const touchBlob: (root: string, digest: CasDigest) => Promise<void>;
1818
+ /**
1819
+ * Summary of a single task execution.
1820
+ */
1821
+ interface TaskSummary {
1822
+ /** Whether the task was cacheable */
1823
+ cacheable: boolean;
1824
+ /** Cache status */
1825
+ cacheStatus: "HIT" | "MISS" | "REMOTE_HIT" | "SKIPPED";
1826
+ /** Dependencies on other tasks */
1827
+ dependencies: string[];
1828
+ /** Duration in milliseconds */
1829
+ duration: number | undefined;
1830
+ /** End time (ISO 8601) */
1831
+ endTime: string | undefined;
1832
+ /** Exit code */
1833
+ exitCode: number | undefined;
1834
+ /** The computed cache hash */
1835
+ hash: string | undefined;
1836
+ /** Detailed hash information */
1837
+ hashDetails: TaskHashDetails | undefined;
1838
+ /** The task's declared outputs (glob patterns, literals, or `{ auto: true }`). */
1839
+ outputs: OutputSpec[];
1840
+ /** Start time (ISO 8601) */
1841
+ startTime: string | undefined;
1842
+ /** The task target */
1843
+ target: {
1844
+ configuration?: string;
1845
+ project: string;
1846
+ target: string;
1847
+ };
1848
+ /** The task ID (e.g., "app:build") */
1849
+ taskId: string;
1850
+ }
1851
+ /**
1852
+ * Complete summary of a task runner execution.
1853
+ */
1854
+ interface RunSummary {
1855
+ /** Total duration in milliseconds */
1856
+ duration: number;
1857
+ /** Run end time (ISO 8601) */
1858
+ endTime: string;
1859
+ /** Environment info */
1860
+ environment: {
1861
+ /** Architecture */
1862
+ arch: string;
1863
+ /** Node.js version */
1864
+ nodeVersion: string;
1865
+ /** Platform */
1866
+ platform: string;
1867
+ };
1868
+ /** Unique run ID */
1869
+ id: string;
1870
+ /** Run start time (ISO 8601) */
1871
+ startTime: string;
1872
+ /** Overall execution statistics */
1873
+ stats: {
1874
+ /** Number of cached tasks (local + remote) */
1875
+ cached: number;
1876
+ /** Number of failed tasks */
1877
+ failed: number;
1878
+ /** Number of skipped tasks */
1879
+ skipped: number;
1880
+ /** Number of successful tasks */
1881
+ succeeded: number;
1882
+ /** Total number of tasks */
1883
+ total: number;
1884
+ };
1885
+ /** The task graph used for this run */
1886
+ taskGraph: {
1887
+ dependencies: Record<string, string[]>;
1888
+ roots: string[];
1889
+ };
1890
+ /** Summary of each task */
1891
+ tasks: TaskSummary[];
1892
+ }
1893
+ /**
1894
+ * Generates a run summary from task results.
1895
+ */
1896
+ declare const generateRunSummary: (results: TaskResults, taskGraph: TaskGraph, startTime: number) => RunSummary;
1897
+ /**
1898
+ * Writes the run summary to a JSON file in the `.task-runner/runs/` directory.
1899
+ * @param summary The run summary to write
1900
+ * @param workspaceRoot The workspace root directory
1901
+ * @returns The path to the written summary file
1902
+ */
1903
+ declare const writeRunSummary: (summary: RunSummary, workspaceRoot: string) => Promise<string>;
1904
+ /**
1905
+ * Path where the most-recent run summary is persisted.
1906
+ * Consumers (e.g. CLIs exposing `--last-details`) read this file
1907
+ * to replay or render the previous run without re-executing.
1908
+ */
1909
+ declare const getLastRunSummaryPath: (workspaceRoot: string) => string;
1910
+ /**
1911
+ * Persists `summary` as the most-recent run summary at
1912
+ * `.task-runner/last-summary.json`, overwriting any previous entry.
1913
+ *
1914
+ * This is the companion to {@link readLastRunSummary} and powers
1915
+ * CLI surfaces that display "last run" details without re-running tasks.
1916
+ * @returns The path to the written summary file
1917
+ */
1918
+ declare const writeLastRunSummary: (summary: RunSummary, workspaceRoot: string) => Promise<string>;
1919
+ /**
1920
+ * Reads the most-recent run summary written by {@link writeLastRunSummary}.
1921
+ * Returns `undefined` when no previous run has been recorded or the file
1922
+ * cannot be parsed — callers should render an informational message
1923
+ * instead of treating this as an error.
1924
+ */
1925
+ declare const readLastRunSummary: (workspaceRoot: string) => Promise<RunSummary | undefined>;
1926
+ /**
1927
+ * A single event in the Chrome Tracing JSON format. Chrome's
1928
+ * chrome://tracing viewer and Perfetto both accept an array of these.
1929
+ *
1930
+ * Fields track the subset we actually emit:
1931
+ * - `ph: "X"` — "complete" span (has duration)
1932
+ * - `ph: "s"` / `ph: "f"` — flow start / finish (connects two spans)
1933
+ *
1934
+ * See the Chrome Trace Event Format spec on docs.google.com
1935
+ * (document id: 1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU)
1936
+ * for the full specification.
1937
+ */
1938
+ interface ChromeTraceEvent {
1939
+ args?: Record<string, unknown>;
1940
+ /** Event category — grouped in the viewer's search/filter UI. */
1941
+ cat: string;
1942
+ /** Duration in microseconds — only set for `ph: "X"` events. */
1943
+ dur?: number;
1944
+ /** Flow ID — used to draw an arrow from flow-start to flow-finish. */
1945
+ id?: number;
1946
+ /** Human label shown on the timeline. */
1947
+ name: string;
1948
+ /**
1949
+ * Event phase:
1950
+ * - `"X"` — complete (span with duration)
1951
+ * - `"s"` — flow start
1952
+ * - `"f"` — flow finish
1953
+ * - `"M"` — metadata
1954
+ */
1955
+ ph: "f" | "M" | "s" | "X";
1956
+ pid: number;
1957
+ tid: number;
1958
+ /** Timestamp in microseconds. */
1959
+ ts: number;
1960
+ }
1961
+ /**
1962
+ * Converts a {@link RunSummary} into a Chrome Tracing event list that
1963
+ * renders as a gantt chart in chrome://tracing or Perfetto.
1964
+ *
1965
+ * Each task becomes a `"X"` span; dependency edges become flow arrows
1966
+ * from the dependency's finish to the dependent task's start.
1967
+ * Parallel tasks are assigned synthetic `tid` values (lane 0, 1, 2, …)
1968
+ * based on the smallest free lane at the task's start time, so the
1969
+ * timeline clearly shows concurrency without requiring real thread IDs.
1970
+ */
1971
+ declare const toChromeTrace: (summary: RunSummary) => ChromeTraceEvent[];
1972
+ /**
1973
+ * Writes a Chrome Tracing JSON file at `outputPath`. Consumers (e.g.
1974
+ * a CLI `--profile out.json` flag) call this after the run completes
1975
+ * with a RunSummary produced by the task orchestrator.
1976
+ */
1977
+ declare const writeChromeTrace: (summary: RunSummary, outputPath: string) => Promise<void>;
1978
+ /**
1979
+ * Context for token interpolation.
1980
+ *
1981
+ * Currently the only first-class token group is `affected` (and its alias
1982
+ * `changed_files`). Pass `affected.files` (workspace-relative paths) and
1983
+ * the renderer will substitute it into command strings such as
1984
+ * `eslint ${affected.files}` or `prettier ${changed_files | flag '--file'}`.
1985
+ *
1986
+ * Optional `projectRoot` makes paths relative to a single project root,
1987
+ * stripping the leading prefix and the immediately following `/`. Files
1988
+ * outside the root are dropped — token interpolation only emits paths
1989
+ * the task can actually act on.
1990
+ */
1991
+ interface TokenContext {
1992
+ /** Affected/changed files, relative to workspace root. */
1993
+ affectedFiles?: string[];
1994
+ /**
1995
+ * When set, paths are rewritten relative to this project root and
1996
+ * files outside the root are filtered out.
1997
+ */
1998
+ projectRoot?: string;
1999
+ }
2000
+ /**
2001
+ * Expands token references in a single command string.
2002
+ *
2003
+ * Supported tokens:
2004
+ * `${affected.files}` — space-joined, shell-quoted paths
2005
+ * `${changed_files}` — alias of `affected.files`
2006
+ * `${affected.files | flag '--file'}` — `--file path1 --file path2 ...`
2007
+ *
2008
+ * Unknown tokens are left in place — they may be environment-variable
2009
+ * references the shell will expand at runtime, and silently dropping
2010
+ * them would mask bugs in user commands.
2011
+ *
2012
+ * Escape with a leading backslash (`\${affected.files}`) to emit the
2013
+ * literal token without expansion. Note: the regex consumes at most
2014
+ * one leading backslash, so `\\${...}` collapses to `\${...}` rather
2015
+ * than producing a literal backslash followed by the literal token.
2016
+ * Use a different surrounding quoting scheme if you need a real
2017
+ * backslash adjacent to a token.
2018
+ */
2019
+ declare const expandTokensInString: (command: string, context: TokenContext) => string;
2020
+ /**
2021
+ * Pipeline-friendly variant of {@link expandTokensInString} that takes
2022
+ * and returns a `ConcurrentCommandConfig`. Plays the same role as
2023
+ * {@link import("./expand-arguments").expandArguments} so it can slot
2024
+ * into {@link import("./index").parseCommands} as a normal step.
2025
+ */
2026
+ declare const expandTokens: (config: ConcurrentCommandConfig, context: TokenContext) => ConcurrentCommandConfig;
2027
+ /**
2028
+ * Expands argument placeholders in command strings.
2029
+ *
2030
+ * Placeholders:
2031
+ * {1}, {2}, ... -> specific positional argument
2032
+ * {@} -> all arguments, individually quoted
2033
+ * {*} -> all arguments as a single quoted string
2034
+ * \{1} -> literal {1} (escaped)
2035
+ */
2036
+ declare const expandArguments: (config: ConcurrentCommandConfig, additionalArguments: string[]) => ConcurrentCommandConfig;
2037
+ /**
2038
+ * Expands package manager shortcuts into full commands.
2039
+ *
2040
+ * This parser transforms shorthand notation into proper package manager
2041
+ * invocations. No user input is involved -- command strings originate
2042
+ * from the calling code which reads package.json scripts.
2043
+ *
2044
+ * Examples:
2045
+ * npm:build -> npm run build
2046
+ * pnpm:test -> pnpm run test
2047
+ * node:script -> node --run script
2048
+ * deno:task -> deno task task
2049
+ */
2050
+ declare const expandShortcut: (config: ConcurrentCommandConfig) => ConcurrentCommandConfig;
2051
+ /**
2052
+ * Expands wildcard patterns in package manager "run" commands.
2053
+ *
2054
+ * Reads scripts from package.json and matches against the wildcard pattern.
2055
+ * Returns one ConcurrentCommandConfig per matching script.
2056
+ *
2057
+ * Example: "npm run watch-*" with scripts { "watch-js": "...", "watch-css": "..." }
2058
+ * -> ["npm run watch-js", "npm run watch-css"]
2059
+ *
2060
+ * No user input is involved -- patterns come from the calling code.
2061
+ */
2062
+ declare const expandWildcard: (config: ConcurrentCommandConfig) => ConcurrentCommandConfig | ConcurrentCommandConfig[];
2063
+ /**
2064
+ * Removes surrounding quotes from a command string.
2065
+ * Handles both single and double quotes.
2066
+ */
2067
+ declare const stripQuotes: (config: ConcurrentCommandConfig) => ConcurrentCommandConfig;
2068
+ interface ParseCommandsOptions {
2069
+ /** Additional arguments for placeholder expansion ({1}, {@}, {*}). */
2070
+ additionalArguments?: string[];
2071
+ /**
2072
+ * Token interpolation context. When supplied, `${affected.files}`
2073
+ * and `${changed_files | flag '--file'}` references in command
2074
+ * strings are expanded before argument placeholder substitution.
2075
+ */
2076
+ tokens?: TokenContext;
2077
+ }
2078
+ /**
2079
+ * Parse and expand command inputs through the full pipeline:
2080
+ * 1. Normalize string inputs to config objects
2081
+ * 2. Strip surrounding quotes
2082
+ * 3. Expand package manager shortcuts (npm:build -> npm run build)
2083
+ * 4. Expand wildcard patterns (npm run watch-* -> multiple commands)
2084
+ * 5. Expand token references (${affected.files}, ${changed_files | flag '...'})
2085
+ * 6. Expand argument placeholders ({1}, {@}, {*})
2086
+ */
2087
+ declare const parseCommands: (inputs: ConcurrentCommandInput[], options?: ParseCommandsOptions) => ConcurrentCommandConfig[];
2088
+ /**
2089
+ * Run commands concurrently with output streaming and process management.
2090
+ *
2091
+ * Automatically uses the native Rust addon for performance when available,
2092
+ * falling back to a pure JavaScript implementation.
2093
+ *
2094
+ * Supports flow controllers:
2095
+ * - `restart`: retry failed commands with configurable delay/backoff
2096
+ * - `teardown`: run cleanup commands after all processes complete
2097
+ * - `timings`: print a timing summary table
2098
+ * @param commands Array of command strings or config objects
2099
+ * @param options Runner options (maxProcesses, killOthers, restart, teardown, etc.)
2100
+ * @returns Promise resolving to the run result with close events and success status
2101
+ */
2102
+ declare const runConcurrently: (commands: ConcurrentCommandInput[], options?: ConcurrentRunnerOptions) => Promise<ConcurrentRunResult>;
2103
+ /**
2104
+ * Run commands concurrently using pure JavaScript (child_process.spawn).
2105
+ * This is the fallback when the native Rust addon is unavailable.
2106
+ */
2107
+ declare const runConcurrentFallback: (commands: ConcurrentCommandConfig[], options: ConcurrentRunnerOptions) => Promise<ConcurrentRunResult>;
2108
+ /**
2109
+ * The default task runner implementation.
2110
+ *
2111
+ * Runs tasks with caching, scheduling, and lifecycle support.
2112
+ * Supports two caching modes:
2113
+ *
2114
+ * 1. **Nx-style** (default): Explicit input declarations with upfront hash computation.
2115
+ * 2. **Auto-fingerprint** (Vite Task-style): Set `autoFingerprint: true` to automatically
2116
+ * track file accesses and use them for cache invalidation.
2117
+ * @example
2118
+ * ```ts
2119
+ * import { defaultTaskRunner } from "@visulima/task-runner";
2120
+ *
2121
+ * // Nx-style (explicit inputs)
2122
+ * const results = await defaultTaskRunner(tasks, options, context);
2123
+ *
2124
+ * // Vite Task-style (auto-fingerprinting)
2125
+ * const results = await defaultTaskRunner(tasks, {
2126
+ * ...options,
2127
+ * autoFingerprint: true,
2128
+ * fingerprintEnvPatterns: ["VITE_*", "NODE_ENV"],
2129
+ * cacheDiagnostics: true,
2130
+ * }, context);
2131
+ *
2132
+ * // With remote cache
2133
+ * const results = await defaultTaskRunner(tasks, {
2134
+ * ...options,
2135
+ * remoteCache: {
2136
+ * url: "https://cache.example.com",
2137
+ * token: process.env.CACHE_TOKEN,
2138
+ * teamId: "my-team",
2139
+ * },
2140
+ * }, context);
2141
+ *
2142
+ * // Dry-run (inspect hashes without executing)
2143
+ * const results = await defaultTaskRunner(tasks, {
2144
+ * ...options,
2145
+ * dryRun: true,
2146
+ * }, context);
2147
+ * ```
2148
+ */
2149
+ declare const defaultTaskRunner: (_tasks: Task[], options: TaskRunnerOptions, context: TaskRunnerContext) => Promise<TaskResults>;
2150
+ /**
2151
+ * Detect the npm script-shell configuration.
2152
+ *
2153
+ * Returns the shell path if configured, or undefined to use platform defaults.
2154
+ * The result is cached after the first call.
2155
+ */
2156
+ declare const detectScriptShell: () => string | undefined;
2157
+ interface InputHandlerOptions {
2158
+ /** Default command index to route unprefixed input to. Default: 0. */
2159
+ defaultTarget?: number;
2160
+ /** Stream to read input from. Default: process.stdin. */
2161
+ inputStream?: Readable;
2162
+ /** Whether to pause the input stream when all processes finish. Default: true. */
2163
+ pauseOnFinish?: boolean;
2164
+ }
2165
+ interface CommandStdin {
2166
+ index: number;
2167
+ name?: string;
2168
+ stdin: Writable;
2169
+ }
2170
+ /**
2171
+ * Creates an input handler that routes stdin to child processes.
2172
+ * @param commands Map of command index/name to their stdin streams
2173
+ * @param options Input handler configuration
2174
+ * @returns cleanup function to call when done
2175
+ */
2176
+ declare const createInputHandler: (commands: CommandStdin[], options?: InputHandlerOptions) => (() => void);
2177
+ /**
2178
+ * Generate a timing summary table string from close events.
2179
+ * @param closeEvents Close events from the concurrent run (in completion order)
2180
+ * @returns Formatted table string
2181
+ */
2182
+ declare const formatTimingTable: (closeEvents: ConcurrentCloseEvent[]) => string;
2183
+ /**
2184
+ * Print timing summary to a writable stream.
2185
+ * @param closeEvents Close events from the concurrent run
2186
+ * @param output Output stream (default: process.stdout)
2187
+ */
2188
+ declare const logTimings: (closeEvents: ConcurrentCloseEvent[], output?: NodeJS.WritableStream) => void;
2189
+ interface RestartOptions {
2190
+ /** Delay between restarts in milliseconds. "exponential" for 2^attempt * 1000ms. */
2191
+ delay: number | "exponential";
2192
+ /** Maximum number of restart attempts per command. 0 = no restarts. -1 = infinite. */
2193
+ tries: number;
2194
+ }
2195
+ /**
2196
+ * Wraps a runner function to add restart-on-failure behavior.
2197
+ * @param runFn The underlying runner function (runConcurrently or runConcurrentFallback)
2198
+ * @param commands The original command configs
2199
+ * @param options Runner options
2200
+ * @param restartOptions Restart-specific options
2201
+ */
2202
+ declare const withRestart: (runFunction: (commands: ConcurrentCommandConfig[], options: ConcurrentRunnerOptions) => Promise<ConcurrentRunResult>, commands: ConcurrentCommandConfig[], options: ConcurrentRunnerOptions, restartOptions: RestartOptions) => Promise<ConcurrentRunResult>;
2203
+ interface TeardownOptions {
2204
+ /** Commands to run in sequence after all processes complete. */
2205
+ commands: string[];
2206
+ /** Working directory for teardown commands. */
2207
+ cwd?: string;
2208
+ }
2209
+ /**
2210
+ * Run teardown commands sequentially.
2211
+ * Each command runs in the shell with inherited stdio.
2212
+ * If a command fails, subsequent commands are still attempted.
2213
+ * @returns Array of exit codes for each teardown command
2214
+ */
2215
+ declare const runTeardown: (options: TeardownOptions) => Promise<number[]>;
2216
+ /**
2217
+ * Detected framework information.
2218
+ */
2219
+ interface DetectedFramework {
2220
+ /** The env var prefix(es) that should be included in task hashes */
2221
+ envPrefixes: string[];
2222
+ /** The framework name */
2223
+ name: string;
2224
+ }
2225
+ /**
2226
+ * Detects frameworks used in a project by inspecting its package.json dependencies.
2227
+ * @param packageJsonPath Absolute path to the package.json file
2228
+ * @returns Array of detected frameworks with their env prefixes
2229
+ */
2230
+ declare const detectFrameworks: (packageJsonPath: string) => Promise<DetectedFramework[]>;
2231
+ /**
2232
+ * Detects frameworks across all projects in a workspace and returns
2233
+ * the env var patterns that should be included in task hashes.
2234
+ * @param workspaceRoot The workspace root directory
2235
+ * @param projects Map of project name to project configuration with root paths
2236
+ * @returns Array of env var wildcard patterns (e.g., ["NEXT_PUBLIC_*", "VITE_*"])
2237
+ */
2238
+ declare const inferFrameworkEnvPatterns: (workspaceRoot: string, projects: Record<string, {
2239
+ root: string;
2240
+ }>) => Promise<string[]>;
2241
+ /**
2242
+ * For a specific project, detects frameworks and returns the matching
2243
+ * env vars from the current environment.
2244
+ * @param packageJsonPath Absolute path to the project's package.json
2245
+ * @param env The current environment variables
2246
+ * @returns Map of env var name to value for matching framework env vars
2247
+ */
2248
+ declare const getFrameworkEnvVariables: (packageJsonPath: string, env?: Record<string, string | undefined>) => Promise<Record<string, string>>;
2249
+ /**
2250
+ * Graph visualization output formats.
2251
+ */
2252
+ type GraphFormat = "dot" | "json" | "html" | "ascii";
2253
+ /**
2254
+ * Options for graph visualization.
2255
+ */
2256
+ interface GraphVisualizerOptions {
2257
+ /** Show only affected/filtered tasks (highlight subset) */
2258
+ focusedTasks?: string[];
2259
+ /** Group tasks by project (default: true) */
2260
+ groupByProject?: boolean;
2261
+ /** Show task status colors (requires results) */
2262
+ taskStatuses?: Map<string, "success" | "failure" | "skipped" | "local-cache" | "local-cache-kept-existing" | "remote-cache" | "running" | "pending">;
2263
+ }
2264
+ /**
2265
+ * Exports a task graph in DOT format for Graphviz rendering.
2266
+ * @example
2267
+ * ```ts
2268
+ * const dot = toGraphvizDot(taskGraph);
2269
+ * // Render: dot -Tsvg -o graph.svg <<< "$dot"
2270
+ * ```
2271
+ */
2272
+ declare const toGraphvizDot: (taskGraph: TaskGraph, options?: GraphVisualizerOptions) => string;
2273
+ /**
2274
+ * Exports the task graph as a JSON object suitable for visualization tools.
2275
+ */
2276
+ interface GraphJson {
2277
+ edges: {
2278
+ source: string;
2279
+ target: string;
2280
+ }[];
2281
+ nodes: {
2282
+ configuration?: string;
2283
+ id: string;
2284
+ project: string;
2285
+ status?: string;
2286
+ target: string;
2287
+ }[];
2288
+ roots: string[];
2289
+ }
2290
+ declare const toGraphJson: (taskGraph: TaskGraph, taskStatuses?: Map<string, string>) => {
2291
+ edges: GraphJson["edges"];
2292
+ nodes: GraphJson["nodes"];
2293
+ roots: string[];
2294
+ };
2295
+ /**
2296
+ * Generates a self-contained HTML file with an interactive task graph visualization.
2297
+ * Uses a simple force-directed layout with SVG rendering (no external dependencies).
2298
+ */
2299
+ declare const toGraphHtml: (taskGraph: TaskGraph, options?: GraphVisualizerOptions) => string;
2300
+ /**
2301
+ * Renders the task graph as ASCII art for terminal display.
2302
+ * @example
2303
+ * ```
2304
+ * Task Graph (6 tasks, 5 dependencies)
2305
+ *
2306
+ * app:build
2307
+ * ├── lib-a:build
2308
+ * │ └── lib-core:build
2309
+ * └── lib-b:build
2310
+ * └── lib-core:build (*)
2311
+ *
2312
+ * (*) = already shown above
2313
+ * ```
2314
+ */
2315
+ declare const toGraphAscii: (taskGraph: TaskGraph, options?: GraphVisualizerOptions) => string;
2316
+ /**
2317
+ * Exports a project graph in DOT format.
2318
+ */
2319
+ declare const projectGraphToDot: (projectGraph: ProjectGraph) => string;
2320
+ /**
2321
+ * Incremental file hasher that only re-hashes files that have changed
2322
+ * since the last run, based on mtime comparison.
2323
+ *
2324
+ * This is the key performance optimization used by Nx's daemon and
2325
+ * Turborepo's daemon — on subsequent runs, only files whose mtime
2326
+ * changed need to be re-read and re-hashed.
2327
+ *
2328
+ * The snapshot (path → { mtime, hash }) is kept in memory and can
2329
+ * optionally be persisted to disk for cross-process reuse.
2330
+ */
2331
+ interface FileSnapshot {
2332
+ /** xxh3-128 hash of file contents */
2333
+ hash: string;
2334
+ /** Last modification time in milliseconds */
2335
+ mtimeMs: number;
2336
+ /** File size in bytes (fast pre-check) */
2337
+ size: number;
2338
+ }
2339
+ interface IncrementalHasherOptions {
2340
+ /** Directories to skip (default: node_modules, .git, dist, coverage, .cache) */
2341
+ ignoredDirs?: Set<string>;
2342
+ /** File to persist the snapshot to (for cross-run reuse) */
2343
+ snapshotPath?: string;
2344
+ workspaceRoot: string;
2345
+ }
2346
+ declare class IncrementalFileHasher {
2347
+ #private;
2348
+ constructor(options: IncrementalHasherOptions);
2349
+ /**
2350
+ * Loads the snapshot from disk if available.
2351
+ * Called automatically on first use.
2352
+ */
2353
+ load(): Promise<void>;
2354
+ /**
2355
+ * Persists the current snapshot to disk for cross-run reuse.
2356
+ */
2357
+ save(): Promise<void>;
2358
+ /**
2359
+ * Incrementally hashes all files in a directory.
2360
+ *
2361
+ * Only files whose mtime or size changed since the last snapshot
2362
+ * are re-read and re-hashed. Unchanged files reuse the cached hash.
2363
+ *
2364
+ * Returns a map of relative paths → hashes.
2365
+ */
2366
+ hashDirectory(directoryPath: string): Promise<Record<string, string>>;
2367
+ /**
2368
+ * Returns how many files are in the snapshot (for diagnostics).
2369
+ */
2370
+ get snapshotSize(): number;
2371
+ /**
2372
+ * Clears the in-memory snapshot.
2373
+ */
2374
+ clear(): void;
2375
+ /**
2376
+ * Looks up the cached hash for `absolutePath` when its mtime and
2377
+ * size match the snapshot; returns `undefined` otherwise. Callers
2378
+ * that already have a `stat` result (e.g. `InProcessTaskHasher`)
2379
+ * skip an extra syscall by passing it through directly.
2380
+ *
2381
+ * The snapshot is considered loaded on first call — lazy-load is
2382
+ * synchronous-friendly here because the caller already performed
2383
+ * an async `stat` before calling this method.
2384
+ */
2385
+ getSnapshotHash(absolutePath: string, mtimeMs: number, size: number): string | undefined;
2386
+ /**
2387
+ * Writes a fresh snapshot entry after the caller has computed the
2388
+ * hash. Pairs with {@link IncrementalFileHasher.getSnapshotHash}
2389
+ * — after a miss, the caller hashes the file and records the
2390
+ * result here so the next run can reuse it.
2391
+ */
2392
+ recordSnapshot(absolutePath: string, hash: string, mtimeMs: number, size: number): void;
2393
+ }
2394
+ /**
2395
+ * Combines multiple lifecycle handlers into one.
2396
+ * Each event is forwarded to all registered handlers.
2397
+ */
2398
+ declare class CompositeLifeCycle implements LifeCycleInterface {
2399
+ #private;
2400
+ constructor(lifeCycles: LifeCycleInterface[]);
2401
+ startCommand(): void;
2402
+ endCommand(): void;
2403
+ scheduleTask(task: Task): void;
2404
+ startTasks(tasks: Task[]): void;
2405
+ endTasks(taskResults: TaskResult[]): void;
2406
+ printTaskTerminalOutput(task: Task, status: TaskStatus, terminalOutput: string): void;
2407
+ printCacheMiss(task: Task, reasons: string): void;
2408
+ onTaskStdout(task: Task, chunk: string): void;
2409
+ onTaskStderr(task: Task, chunk: string): void;
2410
+ }
2411
+ /**
2412
+ * A lifecycle handler that logs task progress to the console.
2413
+ */
2414
+ declare class ConsoleLifeCycle implements LifeCycleInterface {
2415
+ #private;
2416
+ constructor(verbose?: boolean);
2417
+ startCommand(): void;
2418
+ endCommand(): void;
2419
+ scheduleTask(task: Task): void;
2420
+ startTasks(tasks: Task[]): void;
2421
+ endTasks(taskResults: TaskResult[]): void;
2422
+ printTaskTerminalOutput(_task: Task, _status: TaskStatus, terminalOutput: string): void;
2423
+ printCacheMiss(task: Task, reasons: string): void;
2424
+ }
2425
+ /**
2426
+ * A no-op lifecycle handler. Useful as a default.
2427
+ */
2428
+ declare class EmptyLifeCycle implements LifeCycleInterface {}
2429
+ /**
2430
+ * Resolved dependency entry from a lockfile.
2431
+ */
2432
+ interface ResolvedDependency {
2433
+ /** The package name */
2434
+ name: string;
2435
+ /** The resolved version */
2436
+ version: string;
2437
+ }
2438
+ /**
2439
+ * Result of parsing a lockfile for a specific package.
2440
+ */
2441
+ interface PackageLockfileHash {
2442
+ /** The resolved dependencies that were included in the hash */
2443
+ dependencies: ResolvedDependency[];
2444
+ /** Hash of the resolved dependencies relevant to this package */
2445
+ hash: string;
2446
+ }
2447
+ /**
2448
+ * Extracts a package name from a node_modules path.
2449
+ * E.g., "node_modules/@scope/name" -> "@scope/name",
2450
+ * "node_modules/name" -> "name",
2451
+ * "node_modules/.package-lock.json" -> undefined.
2452
+ */
2453
+ declare const extractPackageName: (path: string) => string | undefined;
2454
+ /**
2455
+ * Parses package-lock.json (npm v2/v3 format) to extract resolved versions.
2456
+ * The v2/v3 format uses a flat "packages" map with paths like "node_modules/pkg-name".
2457
+ */
2458
+ declare const parseNpmLockfile: (content: string) => Map<string, string>;
2459
+ /**
2460
+ * Parses pnpm-lock.yaml to extract resolved versions.
2461
+ * Uses a lightweight regex-based parser to avoid a YAML dependency.
2462
+ */
2463
+ declare const parsePnpmLockfile: (content: string) => Map<string, string>;
2464
+ /**
2465
+ * Parses yarn.lock to extract resolved versions.
2466
+ * Works with both Yarn Classic (v1) and Berry (v2+) formats.
2467
+ */
2468
+ declare const parseYarnLockfile: (content: string) => Map<string, string>;
2469
+ /**
2470
+ * Smart lockfile hasher that only hashes the resolved versions
2471
+ * of a package's actual dependencies, not the entire lockfile.
2472
+ *
2473
+ * This matches Turborepo's smart lockfile hashing behavior:
2474
+ * changing the lockfile only busts cache for affected packages.
2475
+ *
2476
+ * Supports:
2477
+ * - package-lock.json (npm v2/v3)
2478
+ * - pnpm-lock.yaml (pnpm)
2479
+ * - yarn.lock (Yarn Classic + Berry)
2480
+ */
2481
+ declare class LockfileHasher {
2482
+ #private;
2483
+ constructor(workspaceRoot: string);
2484
+ /**
2485
+ * Computes a hash based only on the resolved dependency versions
2486
+ * relevant to a specific package.
2487
+ * @param packageJsonPath Path to the package.json (relative to workspace root)
2488
+ * @returns Hash of the relevant lockfile entries, or undefined if no lockfile found
2489
+ */
2490
+ hashForPackage(packageJsonPath: string): Promise<PackageLockfileHash | undefined>;
2491
+ /**
2492
+ * Returns the type of lockfile detected, or undefined if none found.
2493
+ */
2494
+ get lockfileType(): "npm" | "pnpm" | "yarn" | undefined;
2495
+ /**
2496
+ * Clears the cached lockfile data.
2497
+ */
2498
+ clearCache(): void;
2499
+ }
2500
+ /**
2501
+ * Output formatting mode for task terminal output.
2502
+ *
2503
+ * - `interleaved` **(default)**: emit each task's buffered output as-is
2504
+ * — lines from parallel tasks may intermix when streamed live.
2505
+ * - `labeled`: prefix every line with `[project#target]` so parallel
2506
+ * tasks remain distinguishable.
2507
+ * - `grouped`: buffer each task's output and print it as a single block
2508
+ * bracketed by `── project#target ──` header and blank-line footer.
2509
+ *
2510
+ * Matches the three modes exposed by vite-task's `--log` flag.
2511
+ */
2512
+ type LogMode = "grouped" | "interleaved" | "labeled";
2513
+ /**
2514
+ * A lifecycle handler that renders task terminal output per {@link LogMode}.
2515
+ *
2516
+ * Operates on the buffered `printTaskTerminalOutput` signal the orchestrator
2517
+ * emits at task-completion. Line-by-line streaming is the consumer's
2518
+ * responsibility — a streaming reporter can wrap this one and emit buffered
2519
+ * output at the end of each task regardless of streaming choices.
2520
+ */
2521
+ declare class LogReporter implements LifeCycleInterface {
2522
+ #private;
2523
+ constructor(mode: LogMode, write?: (chunk: string) => void);
2524
+ printTaskTerminalOutput(task: Task, _status: TaskStatus, terminalOutput: string): void;
2525
+ endTasks(_taskResults: TaskResult[]): void;
2526
+ }
2527
+ /**
2528
+ * Convenience factory matching vite-task's `createLogReporter(mode)` surface.
2529
+ * Consumers that already compose their own lifecycle handlers can instantiate
2530
+ * {@link LogReporter} directly.
2531
+ */
2532
+ declare const createLogReporter: (mode: LogMode, write?: (chunk: string) => void) => LogReporter;
2533
+ interface NativeFileHash {
2534
+ hash: string;
2535
+ path: string;
2536
+ }
2537
+ interface NativeTaskHashDetails {
2538
+ command: string;
2539
+ implicit_deps?: string[][];
2540
+ nodes: string[][];
2541
+ runtime?: string[][];
2542
+ }
2543
+ interface NativeTaskGraph {
2544
+ edges: string[][];
2545
+ task_ids: string[];
2546
+ }
2547
+ interface NativeCycleResult {
2548
+ cycle: string[];
2549
+ has_cycle: boolean;
2550
+ }
2551
+ interface NativeConcurrentCommandConfig {
2552
+ command: string;
2553
+ cwd?: string;
2554
+ env?: Record<string, string>;
2555
+ name?: string;
2556
+ shell?: boolean;
2557
+ stdin?: string;
2558
+ }
2559
+ interface NativeConcurrentRunnerOptions {
2560
+ killOthers?: string[];
2561
+ killSignal?: string;
2562
+ killTimeout?: number;
2563
+ maxProcesses?: number;
2564
+ shellPath?: string;
2565
+ successCondition?: string;
2566
+ }
2567
+ interface NativeProcessEvent {
2568
+ commandName?: string;
2569
+ durationMs?: number;
2570
+ exitCode?: number;
2571
+ index: number;
2572
+ killed?: boolean;
2573
+ kind: string;
2574
+ message?: string;
2575
+ text?: string;
2576
+ }
2577
+ interface NativeConcurrentCloseEvent {
2578
+ command: string;
2579
+ durationMs: number;
2580
+ exitCode: number;
2581
+ index: number;
2582
+ killed: boolean;
2583
+ name?: string;
2584
+ }
2585
+ interface NativeConcurrentRunResult {
2586
+ closeEvents: NativeConcurrentCloseEvent[];
2587
+ success: boolean;
2588
+ }
2589
+ interface NativeBindings {
2590
+ collectFiles: (directory: string) => string[];
2591
+ computeTaskHash: (details: NativeTaskHashDetails) => string;
2592
+ findAllCycles: (graph: NativeTaskGraph) => string[][];
2593
+ findBackEdges: (graph: NativeTaskGraph) => string[][];
2594
+ findCycle: (graph: NativeTaskGraph) => NativeCycleResult;
2595
+ getDependentTasks: (graph: NativeTaskGraph, taskId: string) => string[];
2596
+ getMainWorktreeRoot: (workspaceRoot: string) => string | undefined | null;
2597
+ getTransitiveDeps: (graph: NativeTaskGraph, taskId: string) => string[];
2598
+ hashCommand: (project: string, target: string, configuration: string | undefined, overridesJson: string) => string;
2599
+ hashEnvVar: (name: string, value: string) => string;
2600
+ hashFile: (filePath: string) => string;
2601
+ hashFilesBatch: (filePaths: string[], workspaceRoot: string) => NativeFileHash[];
2602
+ hashFilesInDirectory: (directory: string, workspaceRoot: string) => NativeFileHash[];
2603
+ hashString: (input: string) => string;
2604
+ hashStrings: (inputs: string[]) => string;
2605
+ isLinkedWorktree: (workspaceRoot: string) => boolean;
2606
+ resetWorktreeCache: () => void;
2607
+ runConcurrent: (commands: NativeConcurrentCommandConfig[], options: NativeConcurrentRunnerOptions, onEvent: (event: NativeProcessEvent) => void) => Promise<NativeConcurrentRunResult>;
2608
+ runConcurrentBatch: (commands: NativeConcurrentCommandConfig[], options: NativeConcurrentRunnerOptions) => Promise<NativeConcurrentRunResult>;
2609
+ topologicalSort: (graph: NativeTaskGraph) => string[];
2610
+ }
2611
+ /**
2612
+ * Attempts to load the native addon. Returns undefined if unavailable.
2613
+ * The result is cached after the first attempt.
2614
+ *
2615
+ * napi v3 outputs the .node file to the package root as
2616
+ * `task-runner-native.&lt;platform>.node`. The napi-generated index.js
2617
+ * handles platform detection automatically.
2618
+ *
2619
+ * Uses createRequire because the napi-generated index.js is CJS.
2620
+ */
2621
+ declare const loadNativeBindings: () => NativeBindings | undefined;
2622
+ /**
2623
+ * Returns true if the native addon is loaded and available.
2624
+ */
2625
+ declare const isNativeAvailable: () => boolean;
2626
+ /**
2627
+ * Expands a task's `OutputSpec[]` into the concrete file list to
2628
+ * archive:
2629
+ *
2630
+ * - literal paths → kept as-is (the archiver recursively copies
2631
+ * directories, so `"dist"` captures its whole tree);
2632
+ * - positive globs → expanded via `fs.glob`, filtered to files only;
2633
+ * - negatives (`!pattern`) → applied to the combined result;
2634
+ * - `{ auto: true }` → pulls in `autoWrites` entries that fall inside
2635
+ * the workspace.
2636
+ *
2637
+ * Returns deduped, sorted workspace-relative paths so archives are
2638
+ * byte-reproducible across invocations.
2639
+ *
2640
+ * Silent degradation: missing literal paths, empty glob matches, and
2641
+ * `{ auto: true }` without tracked writes all contribute nothing
2642
+ * rather than throwing.
2643
+ */
2644
+ declare const resolveOutputs: (workspaceRoot: string, outputs: OutputSpec[] | undefined, autoWrites?: ReadonlyArray<string>) => Promise<string[]>;
2645
+ /**
2646
+ * URI schemes recognized by {@link parseInputUri}. Each maps to one of the
2647
+ * existing structured `InputDefinition` shapes — the URI form is a sugar
2648
+ * over the object form so the same hash semantics apply unchanged.
2649
+ *
2650
+ * - `file://&lt;path>` and `glob://&lt;pattern>` → {@link FileSetInput}
2651
+ * (both produce a fileset; the split is purely documentary so a reader
2652
+ * can tell at a glance whether the author meant a single path or a glob).
2653
+ * - `env://&lt;NAME>` → {@link EnvironmentInput}.
2654
+ * - `func://&lt;command>` → {@link RuntimeInput} (runtime command output).
2655
+ * - `dep://&lt;a,b,c>` → {@link ExternalDependencyInput} (comma-separated names).
2656
+ *
2657
+ * `{projectRoot}` and `{workspaceRoot}` tokens are honored inside `file://`
2658
+ * and `glob://` bodies, matching the bare-string form. Negation works for
2659
+ * filesets only (`!file://...`, `!glob://...`); attempting to negate the
2660
+ * other schemes throws because there is no semantic for "not this env var".
2661
+ */
2662
+ declare const INPUT_URI_SCHEMES: readonly ["file", "glob", "env", "func", "dep"];
2663
+ type InputUriScheme = (typeof INPUT_URI_SCHEMES)[number];
2664
+ /**
2665
+ * Thrown when a string carries a URI-shaped prefix but the scheme is
2666
+ * unrecognized or the body violates a scheme-specific constraint
2667
+ * (e.g. negating a non-fileset scheme).
2668
+ *
2669
+ * Surfaces as a config-load error rather than degrading silently into a
2670
+ * fileset glob — silent fallback would let typos like `gob://**` mask
2671
+ * cache-correctness bugs that only show up at hash-divergence time.
2672
+ */
2673
+ declare class InvalidInputUriError extends Error {
2674
+ constructor(message: string);
2675
+ }
2676
+ /**
2677
+ * Parses a URI-prefixed input string into its structured `InputDefinition`.
2678
+ * Returns `undefined` for strings that don't carry a URI scheme — callers
2679
+ * fall back to existing handling (named-input lookup, bare globs).
2680
+ */
2681
+ declare const parseInputUri: (input: string) => InputDefinition | undefined;
2682
+ /**
2683
+ * Cheap predicate used by callers that only need to know whether a string
2684
+ * looks like a URI — saves them re-parsing when they want to short-circuit
2685
+ * other handling (e.g. file-group lookup) before delegating to
2686
+ * {@link parseInputUri} downstream.
2687
+ */
2688
+ declare const looksLikeInputUri: (input: string) => boolean;
2689
+ /**
2690
+ * Enforces project dependency constraints on a project graph.
2691
+ * @param projectGraph The workspace project graph to validate.
2692
+ * @param constraints The constraint rules to enforce.
2693
+ * @returns Array of violations found. Empty means all constraints pass.
2694
+ */
2695
+ declare const enforceProjectConstraints: (projectGraph: ProjectGraph, constraints: ConstraintsConfig) => ConstraintViolation[];
2696
+ interface CreateTaskGraphOptions {
2697
+ /** The project graph */
2698
+ projectGraph: ProjectGraph;
2699
+ /** Target default configurations */
2700
+ targetDefaults?: Record<string, Partial<TargetConfiguration>>;
2701
+ /** The workspace configuration */
2702
+ workspace: WorkspaceConfiguration;
2703
+ }
2704
+ /**
2705
+ * Creates a unique task ID from a target.
2706
+ */
2707
+ declare const getTaskId: (target: TaskTarget) => string;
2708
+ /**
2709
+ * Parses a task ID into its component parts.
2710
+ */
2711
+ declare const parseTaskId: (taskId: string) => TaskTarget;
2712
+ /**
2713
+ * Creates a task graph from a list of tasks, resolving all dependencies.
2714
+ */
2715
+ declare const createTaskGraph: (initialTasks: Task[], options: CreateTaskGraphOptions) => TaskGraph;
2716
+ /**
2717
+ * Finds a single cycle in the task graph, if one exists.
2718
+ * Returns the cycle as an array of task IDs, or null if no cycle exists.
2719
+ */
2720
+ declare const findCycle: (taskGraph: TaskGraph) => string[] | undefined;
2721
+ /**
2722
+ * Finds all cycles in the task graph.
2723
+ */
2724
+ declare const findCycles: (taskGraph: TaskGraph) => string[][];
2725
+ /**
2726
+ * Walks the task graph in topological order (dependencies before dependents),
2727
+ * calling the callback for each task.
2728
+ *
2729
+ * Note: If the graph contains cycles, tasks involved in cycles will not be visited.
2730
+ * Use `findCycle` to detect cycles before walking if complete traversal is required.
2731
+ */
2732
+ declare const walkTaskGraph: (taskGraph: TaskGraph, callback: (taskId: string) => void) => void;
2733
+ /**
2734
+ * Returns a reversed copy of the task graph (edges point in the opposite direction).
2735
+ */
2736
+ declare const reverseTaskGraph: (taskGraph: TaskGraph) => TaskGraph;
2737
+ /**
2738
+ * Returns the leaf tasks (tasks with no dependencies of their own).
2739
+ */
2740
+ declare const getLeafTasks: (taskGraph: TaskGraph) => string[];
2741
+ /**
2742
+ * Removes edges that form cycles, making the graph acyclic.
2743
+ * Returns a new task graph without the cycle-forming edges.
2744
+ */
2745
+ declare const makeAcyclic: (taskGraph: TaskGraph) => TaskGraph;
2746
+ /**
2747
+ * Gets all tasks that depend on the given task (directly or transitively).
2748
+ */
2749
+ declare const getDependentTasks: (taskGraph: TaskGraph, taskId: string) => string[];
2750
+ /**
2751
+ * Gets all tasks that the given task depends on (directly or transitively).
2752
+ */
2753
+ declare const getTransitiveDependencies: (taskGraph: TaskGraph, taskId: string) => string[];
2754
+ /**
2755
+ * Interface for task hashers.
2756
+ */
2757
+ interface TaskHasher {
2758
+ hashTask: (task: Task) => Promise<TaskHashDetails>;
2759
+ /**
2760
+ * Rehashes a single file bypassing any in-memory cache. Optional to keep
2761
+ * external/custom hashers backward compatible; the orchestrator skips
2762
+ * self-modifying-task detection when the implementation is absent.
2763
+ */
2764
+ rehashFile?: (filePath: string) => Promise<string | undefined>;
2765
+ }
2766
+ /**
2767
+ * Options for creating an InProcessTaskHasher.
2768
+ */
2769
+ interface TaskHasherOptions {
2770
+ /**
2771
+ * When true, scan each task's resolved command for `$VAR`/`${VAR}`
2772
+ * references and auto-fingerprint them. Catches the common case of
2773
+ * a script reading `$VERCEL_URL` or `${NEXT_PUBLIC_API}` without
2774
+ * the user remembering to declare it in `envVars`/`globalEnv`.
2775
+ * @default false
2776
+ */
2777
+ autoEnvVars?: boolean;
2778
+ /** Additional environment variables to include in hash */
2779
+ envVars?: string[];
2780
+ /**
2781
+ * Enable framework environment variable inference.
2782
+ * When true, auto-detects frameworks and includes their public
2783
+ * env var prefixes in the task hash.
2784
+ * @default false
2785
+ */
2786
+ frameworkInference?: boolean;
2787
+ /**
2788
+ * Global environment variables that invalidate all task hashes.
2789
+ */
2790
+ globalEnv?: string[];
2791
+ /**
2792
+ * Global input files that invalidate all task hashes when changed.
2793
+ * These are workspace-root-relative paths (e.g., "pnpm-lock.yaml").
2794
+ */
2795
+ globalInputs?: string[];
2796
+ /**
2797
+ * Optional persistent mtime/size-indexed file snapshot. When set,
2798
+ * `#hashFile` consults the snapshot first and only re-reads file
2799
+ * contents when the file's mtime or size has changed since the
2800
+ * previous run. Cuts cold-cache fingerprint time dramatically on
2801
+ * large workspaces where most source files don't change run-to-run.
2802
+ *
2803
+ * The caller is responsible for `load()`ing the snapshot before
2804
+ * using the hasher and `save()`ing it after the run completes.
2805
+ */
2806
+ incrementalHasher?: IncrementalFileHasher;
2807
+ /** Named input definitions */
2808
+ namedInputs?: NamedInputs;
2809
+ /** Project configurations keyed by project name */
2810
+ projects: Record<string, ProjectConfiguration>;
2811
+ /**
2812
+ * Enable smart lockfile hashing.
2813
+ * When true, instead of hashing the entire lockfile, only the resolved
2814
+ * versions of a package's actual dependencies are hashed.
2815
+ * This means changing the lockfile only busts cache for affected packages.
2816
+ *
2817
+ * Matches Turborepo's smart lockfile hashing behavior.
2818
+ * @default false
2819
+ */
2820
+ smartLockfileHashing?: boolean;
2821
+ /** Target default configurations */
2822
+ targetDefaults?: Record<string, Partial<TargetConfiguration>>;
2823
+ /** The workspace root directory */
2824
+ workspaceRoot: string;
2825
+ }
2826
+ /**
2827
+ * Computes hashes for tasks based on their inputs.
2828
+ * Used to determine if a cached result can be reused.
2829
+ */
2830
+ declare class InProcessTaskHasher implements TaskHasher {
2831
+ #private;
2832
+ constructor(options: TaskHasherOptions);
2833
+ hashTask(task: Task): Promise<TaskHashDetails>;
2834
+ clearCache(): void;
2835
+ /**
2836
+ * Reads `filePath` fresh and returns its content hash, bypassing the
2837
+ * in-memory cache used during the initial `hashTask` pass.
2838
+ *
2839
+ * Used to detect tasks that modify their own tracked inputs: compare
2840
+ * a pre-execution hash (from `task.hashDetails.nodes`) against the
2841
+ * post-execution result of this method.
2842
+ * @param filePath Absolute path to the file.
2843
+ * @returns The fresh xxh3 hash, or `undefined` if the file cannot be read.
2844
+ */
2845
+ rehashFile(filePath: string): Promise<string | undefined>;
2846
+ }
2847
+ /**
2848
+ * Computes the final hash for a task from its hash details.
2849
+ * Uses native Rust xxh3-128 when available, otherwise pure TS xxh3-ts.
2850
+ * Both produce identical xxh3-128 hashes, ensuring cache compatibility
2851
+ * regardless of whether the native addon is loaded.
2852
+ */
2853
+ declare const computeTaskHash: (hashDetails: TaskHashDetails) => string;
2854
+ /**
2855
+ * Options for partitioning tasks across CI runners.
2856
+ */
2857
+ interface PartitionOptions {
2858
+ /** 1-based partition index (e.g., 1 for the first partition) */
2859
+ index: number;
2860
+ /** Total number of partitions */
2861
+ total: number;
2862
+ }
2863
+ /**
2864
+ * Parses a partition string like "1/4" into PartitionOptions.
2865
+ * Also supports the VIS_PARTITION environment variable as fallback.
2866
+ */
2867
+ declare const parsePartition: (value?: string) => PartitionOptions | undefined;
2868
+ /**
2869
+ * Manages the scheduling order of tasks based on dependencies,
2870
+ * parallelism constraints, and estimated execution times.
2871
+ */
2872
+ declare class TaskScheduler {
2873
+ #private;
2874
+ /**
2875
+ * Partitions a list of tasks for distributed CI execution.
2876
+ * Tasks are sorted by ID for deterministic distribution, then split
2877
+ * using ceiling division so partitions differ by at most one task.
2878
+ * @param tasks The full list of tasks to partition
2879
+ * @param partition The partition configuration (1-based index and total)
2880
+ * @returns The subset of tasks assigned to this partition
2881
+ */
2882
+ static partitionTasks(tasks: Task[], partition: PartitionOptions): Task[];
2883
+ constructor(taskGraph: TaskGraph, projectGraph: ProjectGraph, maxParallel?: number);
2884
+ /**
2885
+ * Returns the next batch of tasks that are ready to execute.
2886
+ */
2887
+ getNextBatch(): Task[];
2888
+ startTask(taskId: string): void;
2889
+ completeTask(taskId: string): void;
2890
+ isComplete(): boolean;
2891
+ get remainingCount(): number;
2892
+ get runningCount(): number;
2893
+ }
2894
+ /**
2895
+ * Options for the TaskOrchestrator.
2896
+ */
2897
+ interface TaskOrchestratorOptions {
2898
+ /**
2899
+ * Tasks marked `always: true` to run after the main task graph
2900
+ * completes. Run sequentially, in declaration order, even if the
2901
+ * main run failed or was aborted (SIGINT skips them — that's an
2902
+ * explicit user request to stop). Skipped if their `when` clause
2903
+ * doesn't match.
2904
+ */
2905
+ alwaysTasks?: Task[];
2906
+ autoFingerprint?: boolean;
2907
+ cache: Cache;
2908
+ cacheDiagnostics?: boolean;
2909
+ captureOutput?: boolean;
2910
+ dryRun?: boolean;
2911
+ fingerprintEnvPatterns?: string[];
2912
+ lifeCycle: LifeCycleInterface;
2913
+ /**
2914
+ * Surfaces bridge-local upload pipeline failures (tar / digest)
2915
+ * for fire-and-forget remote-cache writes. Wire-level errors are
2916
+ * already reported by the backend's own `onUploadError`; this
2917
+ * fills the gap for steps the backend never sees.
2918
+ */
2919
+ onRemoteUploadError?: (hash: string, error: unknown) => void;
2920
+ remoteCache?: RemoteCacheBackend;
2921
+ resolveCommand?: (task: Task) => string | undefined;
2922
+ scheduler: TaskScheduler;
2923
+ skipCache?: boolean;
2924
+ summarize?: boolean;
2925
+ taskExecutor: TaskExecutor;
2926
+ taskGraph?: TaskGraph;
2927
+ taskHasher: TaskHasher;
2928
+ untrackedEnvVars?: string[];
2929
+ /**
2930
+ * Context used to evaluate per-task `when` conditions. Defaults
2931
+ * to the live process state — `process.env`, `process.platform`,
2932
+ * git branch read from `workspaceRoot`. Override in tests.
2933
+ */
2934
+ whenContext?: WhenContext;
2935
+ workspaceRoot: string;
2936
+ }
2937
+ /**
2938
+ * Orchestrates the execution of tasks, handling caching,
2939
+ * scheduling, and lifecycle events.
2940
+ */
2941
+ declare class TaskOrchestrator {
2942
+ #private;
2943
+ constructor(options: TaskOrchestratorOptions);
2944
+ run(): Promise<TaskResults>;
2945
+ }
2946
+ /**
2947
+ * Minimal virtual terminal buffer that processes ANSI escape sequences
2948
+ * for cursor movement and line erasure. This allows PTY output from
2949
+ * interactive tools (inquirer, etc.) to render correctly by updating
2950
+ * lines in place rather than always appending.
2951
+ *
2952
+ * Supported sequences:
2953
+ * - \r carriage return (cursor to column 0)
2954
+ * - \n line feed (new line)
2955
+ * - \x1b[nA cursor up n lines
2956
+ * - \x1b[nB cursor down n lines
2957
+ * - \x1b[nC cursor forward n columns
2958
+ * - \x1b[nD cursor back n columns
2959
+ * - \x1b[nG cursor to column n
2960
+ * - \x1b[r;cH cursor position
2961
+ * - \x1b[K erase from cursor to end of line (0K, 1K, 2K)
2962
+ * - \x1b[J erase from cursor to end of display (0J, 1J, 2J)
2963
+ * - \x1b[...m SGR (colors/styles) — passed through into output
2964
+ */
2965
+ declare class TerminalBuffer {
2966
+ #private;
2967
+ constructor(maxBytes?: number);
2968
+ /**
2969
+ * Process raw PTY output data.
2970
+ */
2971
+ write(data: string): void;
2972
+ /** Get the current buffer content as a string. */
2973
+ toString(): string;
2974
+ }
2975
+ /**
2976
+ * Result of a tracked task execution.
2977
+ */
2978
+ interface TrackedExecutionResult {
2979
+ /** File accesses recorded during execution */
2980
+ accesses: FileAccess[];
2981
+ /** The command exit code */
2982
+ code: number;
2983
+ /** The command stdout + stderr output */
2984
+ terminalOutput: string;
2985
+ }
2986
+ /**
2987
+ * A task executor that tracks file accesses during command execution.
2988
+ *
2989
+ * Tracking strategies (in priority order):
2990
+ * 1. **Linux**: strace-based syscall interception (most complete)
2991
+ * 2. **macOS/Windows**: Node.js preload script that patches `fs` module
2992
+ * (works for Node.js processes, not native binaries)
2993
+ * 3. **Fallback**: No tracking (accesses array will be empty)
2994
+ */
2995
+ declare class TrackedTaskExecutor {
2996
+ #private;
2997
+ constructor(workspaceRoot: string);
2998
+ /**
2999
+ * Returns true if file access tracking is supported on the current platform.
3000
+ * strace tracking (Linux) or preload script (any Node.js process).
3001
+ */
3002
+ get isTrackingSupported(): boolean;
3003
+ /**
3004
+ * Returns true if the platform supports full syscall-level tracking (strace).
3005
+ */
3006
+ get isStraceSupported(): boolean;
3007
+ /**
3008
+ * Executes a task command and tracks all file system accesses.
3009
+ *
3010
+ * On Linux, uses strace for comprehensive tracking.
3011
+ * On other platforms, uses a Node.js preload script (for Node processes).
3012
+ */
3013
+ execute(task: Task, options: TaskExecutionOptions, command: string): Promise<TrackedExecutionResult>;
3014
+ /**
3015
+ * Kills all active child processes. Called on abort/signal to prevent orphans.
3016
+ */
3017
+ killAll(): void;
3018
+ }
3019
+ /**
3020
+ * Hashes a file's content using xxh3-128.
3021
+ * Returns undefined if the file cannot be read.
3022
+ */
3023
+ declare const hashFile: (filePath: string) => Promise<string | undefined>;
3024
+ /**
3025
+ * Hashes one or more string values using xxh3-128.
3026
+ */
3027
+ declare const hashStrings: (...values: string[]) => string;
3028
+ /**
3029
+ * Sorts an object's keys for deterministic serialization.
3030
+ */
3031
+ declare const sortObjectKeys: (object: Record<string, unknown>) => Record<string, unknown>;
3032
+ /**
3033
+ * Recursively collects all file paths in a directory,
3034
+ * skipping directories in the ignored set.
3035
+ *
3036
+ * Tracks visited real paths to prevent infinite loops from symlink cycles.
3037
+ */
3038
+ declare const collectFiles: (directory: string, ignoredDirectories: Set<string>, visitedRealPaths?: Set<string>) => Promise<string[]>;
3039
+ /**
3040
+ * Resolves the working directory for a task.
3041
+ */
3042
+ declare const resolveTaskCwd: (workspaceRoot: string, task: Task) => string;
3043
+ /**
3044
+ * Creates a failure TaskResult from an error.
3045
+ */
3046
+ declare const createFailureResult: (task: Task, error: unknown, startTime: number) => TaskResult;
3047
+ declare const readPackageDeps: (packageJsonPath: string, options?: {
3048
+ optional?: boolean;
3049
+ peer?: boolean;
3050
+ }) => Promise<Set<string> | undefined>;
3051
+ /**
3052
+ * Generates a unique ID for temporary files/directories using
3053
+ * `crypto.randomUUID()`. Used for staging-path names that briefly
3054
+ * coexist on disk during atomic writes — collisions would clobber a
3055
+ * concurrent writer's staging directory, so the extra entropy over
3056
+ * `Date.now() + Math.random()` is worth the cycles. UUID v4 from
3057
+ * Node's crypto module is itself uniformly random, making this
3058
+ * cheaper than the previous string concat.
3059
+ */
3060
+ declare const uniqueId: () => string;
3061
+ /**
3062
+ * Returns the absolute path to the *main* git worktree root when
3063
+ * `workspaceRoot` is a linked worktree, or `undefined` for primary
3064
+ * checkouts and non-git directories.
3065
+ *
3066
+ * Result is memoized for the lifetime of the process — worktree topology
3067
+ * does not change at runtime, so the second call is a hash lookup.
3068
+ *
3069
+ * Detection logic:
3070
+ * 1. If `{workspaceRoot}/.git` is a *directory*, this is a primary checkout
3071
+ * (or vanilla repo). Returns `undefined`.
3072
+ * 2. If `{workspaceRoot}/.git` is a *file* (gitlink), resolves to the parent
3073
+ * of `git rev-parse --git-common-dir` — that is the main worktree root.
3074
+ * 3. On any error (missing git binary, shallow CI checkout, etc.), returns
3075
+ * `undefined` so the caller falls back to the workspace-local cache.
3076
+ * @param workspaceRoot Absolute path to the candidate workspace root.
3077
+ * @returns The main worktree root, or `undefined` if not a linked worktree.
3078
+ */
3079
+ declare const getMainWorktreeRoot: (workspaceRoot: string) => string | undefined;
3080
+ /**
3081
+ * Returns `true` when `{workspaceRoot}/.git` is a regular file (the gitlink
3082
+ * pointer used by `git worktree add`), `false` otherwise. Cheap pre-flight
3083
+ * before invoking `git rev-parse`.
3084
+ * @param workspaceRoot Absolute path to the candidate workspace root.
3085
+ */
3086
+ declare const isLinkedWorktree: (workspaceRoot: string) => boolean;
3087
+ /**
3088
+ * Clears the in-process detection cache. Tests must call this between
3089
+ * scenarios because the cache key is the canonicalized workspace path —
3090
+ * recreating a fixture at the same path would otherwise leak stale results.
3091
+ */
3092
+ declare const resetWorktreeCache: () => void;
3093
+ export { type ActionResult, type AffectedOptions, type AffectedResult, type AffectedScope, type BlobSource, Cache, type CacheMissReason, type CacheMode, type CacheOptions, type CacheRestoreOptions, type CachedResult, type CasDigest, type ChromeTraceEvent, CompositeLifeCycle, type ConcurrentCloseEvent, type ConcurrentCommandConfig, type ConcurrentCommandInput, type ConcurrentRunResult, type ConcurrentRunnerOptions, ConsoleLifeCycle, type ConstraintViolation, type ConstraintsConfig, DEFAULT_CACHE_DIRECTORY_NAME, type DependencyKindRules, type DependencyType, type DetectedFramework, EmptyLifeCycle, type EnvMatcher, type EnvironmentInput, type ExternalDependencyInput, type FileAccess, FileAccessTracker, type FileSetBase, type FileSetInput, type FileSetPattern, type FileSnapshot, FingerprintManager, type GraphFormat, type GraphJson, type GraphVisualizerOptions, HttpRemoteCache, INPUT_URI_SCHEMES, InProcessTaskHasher, IncrementalFileHasher, type IncrementalHasherOptions, type InputDefinition, type InputHandlerOptions, type InputUriScheme, InvalidInputUriError, type LifeCycleInterface, LockfileHasher, type LogMode, LogReporter, type NamedInputs, type NodePlatform, type OutputSpec, type PackageLockfileHash, type ParseCommandsOptions, type PartitionOptions, type ProcessEvent, type ProjectConfiguration, type ProjectGraph, type ProjectGraphDependency, type ProjectGraphProjectNode, ReapiRemoteCache, type ReapiRemoteCacheOptions, type RemoteCacheBackend, type RemoteCacheCompression, type RemoteCacheOptions, type RemoteCacheSigning, type ResolvedDependency, type RestartOptions, type RunSummary, type RuntimeInput, type TagRelationships, type TargetConfiguration, type TargetDependencyConfig, type Task, type TaskExecutionOptions, type TaskExecutor, type TaskFingerprint, type TaskGraph, type TaskHashDetails, type TaskHasher, type TaskHasherOptions, TaskOrchestrator, type TaskOrchestratorOptions, type TaskPriority, type TaskResult, type TaskResults, type TaskRunnerContext, type TaskRunnerOptions, TaskScheduler, type TaskStatus, type TaskSummary, type TaskTarget, type TasksRunner, type TeardownOptions, TerminalBuffer, type TokenContext, type TrackedExecutionResult, TrackedTaskExecutor, type TrackingResult, type TypeBoundaries, V2_AC, V2_CAS, V2_INDEX, V2_ROOT, V2_TMP, type WhenCondition, type WhenContext, type WorkspaceConfiguration, acEntryPath, actionDigestForTaskHash, buildForwardDependencyMap, buildReverseDependencyMap, casBlobPath, collectFiles, computeTaskHash, containsBlob, containsByTaskHash, createFailureResult, createInputHandler, createLogReporter, createRemoteCacheBackend, createTaskGraph, defaultTaskRunner, detectFrameworks, detectScriptShell, digestBuffer, digestFile, enforceProjectConstraints, evaluateWhen, expandAffected, expandArguments, expandShortcut, expandTokens, expandTokensInString, expandWildcard, explainWhen, extractPackageName, fetchBlobToFile, filterAffectedTasks, findCycle, findCycles, formatCacheSize, formatTimingTable, generatePreloadScript, generateRunSummary, getAffectedProjects, getChangedFiles, getCurrentBranch, getDependentTasks, getFrameworkEnvVariables, getLastRunSummaryPath, getLeafTasks, getMainWorktreeRoot, getTaskId, getTransitiveDependencies, hashFile, hashStrings, inferFrameworkEnvPatterns, isLinkedWorktree, isNativeAvailable, loadNativeBindings, logTimings, looksLikeInputUri, makeAcyclic, parseCacheSize, parseCommands, parseInputUri, parseNpmLockfile, parsePartition, parsePnpmLockfile, parseTaskId, parseYarnLockfile, projectGraphToDot, putBlobFromBytes, putBlobFromFile, readLastRunSummary, readPackageDeps, resetBranchCache, resetWorktreeCache, resolveCacheMode, resolveOutputs, resolveTaskCwd, retrieveByTaskHash, reverseTaskGraph, runConcurrentFallback, runConcurrently, runTeardown, sortObjectKeys, storeByTaskHash, stripQuotes, taskHashIndexPath, toChromeTrace, toGraphAscii, toGraphHtml, toGraphJson, toGraphvizDot, touchBlob, uniqueId, verifyBlob, walkTaskGraph, withRestart, writeChromeTrace, writeLastRunSummary, writeRunSummary };