@vzn/vx 0.0.18 → 0.0.22
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.
- package/LICENSE +1 -1
- package/README.md +107 -70
- package/package.json +10 -20
- package/src/bin.ts +64 -5
- package/src/cache/archive.ts +279 -28
- package/src/cache/cache.ts +952 -1584
- package/src/cache/chained-cache.ts +14 -10
- package/src/cache/config-evals.ts +112 -0
- package/src/cache/file-hashes.ts +290 -0
- package/src/cache/git-inputs.ts +966 -0
- package/src/cache/index.ts +23 -7
- package/src/cache/inputs.ts +553 -739
- package/src/cache/key-fold.ts +232 -0
- package/src/cache/layer.ts +674 -0
- package/src/cache/layered-cache.ts +211 -49
- package/src/cache/output-index.ts +323 -0
- package/src/cache/policy.ts +84 -0
- package/src/cache/run-history.ts +152 -0
- package/src/cache/zstd.ts +183 -0
- package/src/cli/cache.ts +88 -30
- package/src/cli/completions.ts +104 -0
- package/src/cli/core-alias.ts +25 -0
- package/src/cli/format.ts +4 -15
- package/src/cli/help.ts +76 -38
- package/src/cli/index.ts +82 -17
- package/src/cli/info.ts +162 -91
- package/src/cli/init.ts +87 -0
- package/src/cli/last.ts +130 -23
- package/src/cli/lock.ts +36 -18
- package/src/cli/plan-format.ts +18 -7
- package/src/cli/plugin-commands.ts +34 -12
- package/src/cli/run.ts +138 -313
- package/src/cli/select.ts +342 -0
- package/src/cli/show.ts +151 -71
- package/src/cli/upgrade.ts +136 -15
- package/src/cli/watch.ts +1175 -116
- package/src/cli/why.ts +51 -29
- package/src/cli/workspace-config.ts +138 -0
- package/src/config.ts +183 -126
- package/src/exec/env.ts +11 -0
- package/src/exec/executor.ts +62 -31
- package/src/exec/index.ts +16 -2
- package/src/exec/kill-tree.ts +281 -0
- package/src/exec/local-executor.ts +41 -0
- package/src/exec/runner.ts +361 -77
- package/src/exec/sandbox-binds.ts +211 -0
- package/src/exec/sandbox-paths.ts +70 -0
- package/src/exec/sandbox-runtime.ts +1152 -415
- package/src/exec/sandbox-violations.ts +293 -0
- package/src/graph/dependency-spec.ts +14 -14
- package/src/graph/index.ts +6 -4
- package/src/graph/priorities.ts +130 -0
- package/src/graph/scheduler.ts +332 -329
- package/src/graph/task-graph.ts +552 -188
- package/src/index.ts +111 -102
- package/src/orchestrator/admission.ts +161 -0
- package/src/orchestrator/colors.ts +8 -3
- package/src/orchestrator/deferred-outputs.ts +25 -7
- package/src/orchestrator/doctor.ts +363 -0
- package/src/orchestrator/events.ts +111 -8
- package/src/orchestrator/excluded-keys.ts +155 -0
- package/src/orchestrator/execute-task.ts +450 -565
- package/src/orchestrator/failure-mode.ts +169 -28
- package/src/orchestrator/failure-recap.ts +121 -0
- package/src/orchestrator/fingerprint-watch.ts +89 -0
- package/src/orchestrator/framed-output.ts +121 -49
- package/src/orchestrator/history.ts +123 -104
- package/src/orchestrator/hit-restore.ts +285 -0
- package/src/orchestrator/index.ts +42 -5
- package/src/orchestrator/keyed-projects.ts +89 -0
- package/src/orchestrator/local-shortcircuit.ts +83 -23
- package/src/orchestrator/lockfile-claim.ts +401 -0
- package/src/orchestrator/logger.ts +128 -41
- package/src/orchestrator/metrics.ts +201 -72
- package/src/orchestrator/miss-save.ts +232 -0
- package/src/orchestrator/options.ts +63 -34
- package/src/orchestrator/persistent.ts +99 -0
- package/src/orchestrator/placement.ts +212 -0
- package/src/orchestrator/plan.ts +24 -11
- package/src/orchestrator/plugin-host.ts +200 -49
- package/src/orchestrator/plugin.ts +190 -14
- package/src/orchestrator/prepare.ts +168 -137
- package/src/orchestrator/projects.ts +270 -0
- package/src/orchestrator/remote-prefetch.ts +22 -2
- package/src/orchestrator/run-artifacts.ts +34 -3
- package/src/orchestrator/run-context.ts +20 -5
- package/src/orchestrator/run-lock.ts +349 -0
- package/src/orchestrator/run-records.ts +132 -0
- package/src/orchestrator/run-report.ts +6 -4
- package/src/orchestrator/run.ts +467 -611
- package/src/orchestrator/sandbox-request.ts +569 -0
- package/src/orchestrator/save-lane.ts +44 -0
- package/src/orchestrator/shell-verdict.ts +117 -0
- package/src/orchestrator/signals.ts +167 -0
- package/src/orchestrator/stable-keys.ts +259 -10
- package/src/orchestrator/status-line.ts +35 -2
- package/src/orchestrator/summary.ts +115 -25
- package/src/orchestrator/task-hash.ts +103 -21
- package/src/orchestrator/task-log-buffer.ts +15 -18
- package/src/orchestrator/telemetry-host.ts +27 -8
- package/src/orchestrator/telemetry.ts +71 -44
- package/src/orchestrator/upstream.ts +91 -45
- package/src/util/bun-version.ts +43 -0
- package/src/util/cgroup.ts +160 -0
- package/src/util/edit-distance.ts +49 -0
- package/src/util/errors.ts +86 -0
- package/src/util/hash.ts +10 -1
- package/src/util/index.ts +42 -5
- package/src/util/paths.ts +168 -5
- package/src/util/procfs.ts +20 -0
- package/src/util/settle.ts +23 -2
- package/src/util/size.ts +33 -0
- package/src/util/task-id.ts +20 -0
- package/src/util/timing.ts +11 -1
- package/src/util/verbs.ts +39 -0
- package/src/util/which.ts +48 -0
- package/src/workspace/affected.ts +368 -60
- package/src/workspace/config-cache.ts +271 -32
- package/src/workspace/config-eval.ts +60 -16
- package/src/workspace/config-imports.ts +131 -9
- package/src/workspace/config-schema.ts +1033 -0
- package/src/workspace/filter.ts +69 -17
- package/src/workspace/fingerprint.ts +59 -7
- package/src/workspace/index.ts +37 -3
- package/src/workspace/json-data.ts +90 -0
- package/src/workspace/load-reads.ts +32 -0
- package/src/workspace/lockfile.ts +41 -14
- package/src/workspace/migrate-scripts.ts +187 -0
- package/src/workspace/migration.ts +353 -0
- package/src/workspace/package-graph.ts +239 -31
- package/src/workspace/project-loader.ts +295 -815
- package/src/workspace/workspace.ts +266 -31
- package/plugins/local-cache/index.ts +0 -2
- package/plugins/local-executor/index.ts +0 -2
- package/plugins/schedule-history/index.ts +0 -2
- package/src/cache/cas-backend.ts +0 -115
- package/src/cache/digest.ts +0 -32
- package/src/cli/migrate-emit.ts +0 -21
- package/src/cli/migrate-nx.ts +0 -473
- package/src/cli/migrate-scripts.ts +0 -127
- package/src/cli/migrate-turbo.ts +0 -401
- package/src/cli/migrate.ts +0 -305
- package/src/cli/prune.ts +0 -291
- package/src/orchestrator/missing-plugin.ts +0 -9
- package/src/orchestrator/resources.ts +0 -45
- package/src/orchestrator/verify.ts +0 -174
- package/src/plugins/local-cache/index.ts +0 -11
- package/src/plugins/local-executor/index.ts +0 -45
- package/src/plugins/schedule-history/index.ts +0 -109
|
@@ -19,17 +19,125 @@
|
|
|
19
19
|
// - RELATIVE specifiers only. A bare specifier is a package; it moves when
|
|
20
20
|
// the lockfile moves, which the workspace fingerprint already covers.
|
|
21
21
|
// - Descend only through files owned by NO project. A config reaching into
|
|
22
|
-
// another project (
|
|
23
|
-
//
|
|
24
|
-
// would drag substantially all of
|
|
25
|
-
// containment channel already selects the project that
|
|
22
|
+
// another project (say a site's `vx.config.ts` importing
|
|
23
|
+
// `../core/src/index.ts`) records that edge and STOPS there — following
|
|
24
|
+
// it would drag substantially all of that project's `src/` into the
|
|
25
|
+
// closure, and the containment channel already selects the project that
|
|
26
|
+
// owns it.
|
|
26
27
|
|
|
28
|
+
import { existsSync } from 'node:fs'
|
|
27
29
|
import { realpath } from 'node:fs/promises'
|
|
30
|
+
import { builtinModules } from 'node:module'
|
|
28
31
|
import path from 'node:path'
|
|
29
32
|
import type { ProjectMeta } from './workspace.js'
|
|
30
33
|
|
|
34
|
+
const BUILTINS = new Set(builtinModules)
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* One transpiler per loader, made on first use: constructing one costs
|
|
38
|
+
* 42 µs against 12 µs for the scan itself (measured 2026-09-16), and a
|
|
39
|
+
* fresh one per config put 1000 cold evaluations 130 ms behind.
|
|
40
|
+
*/
|
|
41
|
+
const transpilers: Partial<Record<'ts' | 'js', Bun.Transpiler>> = {}
|
|
42
|
+
function scanner(loader: 'ts' | 'js'): Bun.Transpiler {
|
|
43
|
+
return (transpilers[loader] ??= new Bun.Transpiler({ loader }))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Whether Bun's own parser finds an ESM `export` in `source` — the one
|
|
48
|
+
* syntax that makes Bun evaluate a file as a module whatever else it says.
|
|
49
|
+
* Without one, a file that touches `module`, `exports`, `require`, `this`
|
|
50
|
+
* or `__dirname` at the top level is CommonJS to Bun. False on source the
|
|
51
|
+
* parser refuses: the evaluation names that error.
|
|
52
|
+
*/
|
|
53
|
+
export function hasEsmExport(source: string, loader: 'ts' | 'js'): boolean {
|
|
54
|
+
try {
|
|
55
|
+
return scanner(loader).scan(source).exports.length > 0
|
|
56
|
+
} catch {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The package a bare specifier names: `@scope/name` or the first segment. */
|
|
62
|
+
function packageOf(spec: string): string {
|
|
63
|
+
const parts = spec.split('/')
|
|
64
|
+
return spec.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0]!
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const SPECIFIER =
|
|
68
|
+
/\b(?:from|import)\s*\(?\s*["']([^"'./][^"']*)["']|\brequire\s*\(\s*["']([^"'./][^"']*)["']/g
|
|
69
|
+
|
|
70
|
+
/** Whether a specifier is one the walk would have to look up at all. */
|
|
71
|
+
function needsLookup(spec: string): boolean {
|
|
72
|
+
if (spec.includes(':') || BUILTINS.has(spec)) return false
|
|
73
|
+
return !(spec === '@vzn/vx' || spec.startsWith('@vzn/vx/'))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A textual pass before the transpiler's: its scan costs ~50 µs per config
|
|
78
|
+
* in situ (1000 cold evaluations: 50 ms, measured 2026-09-16), and most
|
|
79
|
+
* configs import `@vzn/vx` and nothing else. Every static specifier is a
|
|
80
|
+
* quoted string after `from`, `import` or `require(`; a candidate found
|
|
81
|
+
* here is checked exactly by the scan (a comment or a type-only import is
|
|
82
|
+
* the scan's to drop), and a source with no candidate skips it.
|
|
83
|
+
*/
|
|
84
|
+
function hasBareCandidate(source: string): boolean {
|
|
85
|
+
SPECIFIER.lastIndex = 0
|
|
86
|
+
for (let m = SPECIFIER.exec(source); m !== null; m = SPECIFIER.exec(source)) {
|
|
87
|
+
if (needsLookup(m[1] ?? m[2] ?? '')) return true
|
|
88
|
+
}
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The bare specifiers of `source` that no `node_modules/<package>` above
|
|
94
|
+
* `fromDir` provides — the imports Bun would AUTO-INSTALL from the npm
|
|
95
|
+
* registry rather than fail, when no `node_modules` exists anywhere above
|
|
96
|
+
* (measured 2026-09-16: sixteen registry connections and 150 ms before
|
|
97
|
+
* "cannot find"; with one present, 0 and 1 ms). A config is evaluated in
|
|
98
|
+
* the user's process with the user's network: a fresh clone before its
|
|
99
|
+
* install, or a typo, must be a refusal, never a download. Builtins
|
|
100
|
+
* (`node:fs`, `fs`, `bun:sqlite`) and `@vzn/vx` (served by the core alias
|
|
101
|
+
* inside the compiled binary) are never in the list; relative and absolute
|
|
102
|
+
* specifiers resolve by path and are the loader's to refuse.
|
|
103
|
+
*/
|
|
104
|
+
export function unprovidedBareImports(
|
|
105
|
+
source: string,
|
|
106
|
+
fromDir: string,
|
|
107
|
+
loader: 'ts' | 'js',
|
|
108
|
+
): string[] {
|
|
109
|
+
if (!hasBareCandidate(source)) return []
|
|
110
|
+
let specifiers: string[]
|
|
111
|
+
try {
|
|
112
|
+
specifiers = scanner(loader)
|
|
113
|
+
.scanImports(source)
|
|
114
|
+
.map((i) => i.path)
|
|
115
|
+
} catch {
|
|
116
|
+
return [] // unparseable: the evaluation names the syntax error
|
|
117
|
+
}
|
|
118
|
+
const out: string[] = []
|
|
119
|
+
for (const spec of specifiers) {
|
|
120
|
+
if (spec.startsWith('.') || spec.startsWith('/') || !needsLookup(spec)) continue
|
|
121
|
+
const pkg = packageOf(spec)
|
|
122
|
+
let dir = path.resolve(fromDir)
|
|
123
|
+
let provided = false
|
|
124
|
+
for (;;) {
|
|
125
|
+
if (existsSync(path.join(dir, 'node_modules', pkg))) {
|
|
126
|
+
provided = true
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
const up = path.dirname(dir)
|
|
130
|
+
if (up === dir) break
|
|
131
|
+
dir = up
|
|
132
|
+
}
|
|
133
|
+
if (!provided && !out.includes(spec)) out.push(spec)
|
|
134
|
+
}
|
|
135
|
+
return out
|
|
136
|
+
}
|
|
137
|
+
|
|
31
138
|
/**
|
|
32
|
-
* Absolute resolved targets of the RELATIVE specifiers in `source
|
|
139
|
+
* Absolute resolved targets of the RELATIVE specifiers in `source`; one that
|
|
140
|
+
* does not resolve contributes the paths it names.
|
|
33
141
|
*
|
|
34
142
|
* Paths come back realpath'd, because `Bun.resolveSync` realpaths them — see
|
|
35
143
|
* the caller, which realpaths everything it compares against for exactly that
|
|
@@ -39,7 +147,9 @@ import type { ProjectMeta } from './workspace.js'
|
|
|
39
147
|
function scanLocalImports(source: string, fromDir: string, loader: 'ts' | 'js'): string[] {
|
|
40
148
|
let specifiers: string[]
|
|
41
149
|
try {
|
|
42
|
-
specifiers =
|
|
150
|
+
specifiers = scanner(loader)
|
|
151
|
+
.scanImports(source)
|
|
152
|
+
.map((i) => i.path)
|
|
43
153
|
} catch {
|
|
44
154
|
return [] // unparseable source contributes no edges
|
|
45
155
|
}
|
|
@@ -49,9 +159,18 @@ function scanLocalImports(source: string, fromDir: string, loader: 'ts' | 'js'):
|
|
|
49
159
|
try {
|
|
50
160
|
out.push(Bun.resolveSync(spec, fromDir))
|
|
51
161
|
} catch {
|
|
52
|
-
// Unresolvable
|
|
53
|
-
//
|
|
54
|
-
//
|
|
162
|
+
// Unresolvable: most often the change itself deleted or renamed the
|
|
163
|
+
// target, and the config that imports it is exactly the project the
|
|
164
|
+
// change broke. The edge is the path the specifier names (and, bare
|
|
165
|
+
// of an extension, the files Bun would have tried), so the deleted
|
|
166
|
+
// path in the diff still reaches its importer (item 958). Selection
|
|
167
|
+
// may widen; it is never hashed.
|
|
168
|
+
const named = path.resolve(fromDir, spec)
|
|
169
|
+
out.push(named)
|
|
170
|
+
if (path.extname(spec) === '') {
|
|
171
|
+
for (const ext of RESOLVED_EXTENSIONS)
|
|
172
|
+
out.push(named + ext, path.join(named, 'index' + ext))
|
|
173
|
+
}
|
|
55
174
|
}
|
|
56
175
|
}
|
|
57
176
|
return out
|
|
@@ -91,6 +210,9 @@ async function realDirIndex(projects: readonly ProjectMeta[]): Promise<Map<strin
|
|
|
91
210
|
|
|
92
211
|
const TS_EXT = new Set(['.ts', '.mts', '.cts'])
|
|
93
212
|
|
|
213
|
+
/** The extensions Bun tries for a specifier that names none. */
|
|
214
|
+
const RESOLVED_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json']
|
|
215
|
+
|
|
94
216
|
/** The deepest project containing `file`, or undefined when none does. */
|
|
95
217
|
function ownerOf(file: string, dirToName: ReadonlyMap<string, string>): string | undefined {
|
|
96
218
|
let dir = path.dirname(file)
|