@vzn/vx 0.0.636 → 0.0.638
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/README.md +39 -11
- package/docs/caching.md +246 -213
- package/docs/cli.md +791 -705
- package/docs/execution.md +68 -76
- package/docs/features.md +47 -42
- package/docs/patterns.md +26 -25
- package/docs/schema.md +392 -205
- package/docs/security.md +76 -39
- package/launcher.sh +43 -0
- package/package.json +5 -5
- package/schemas/cache.json +41 -19
- package/schemas/info.json +23 -11
- package/schemas/last.json +48 -2
- package/schemas/lock.json +1 -1
- package/schemas/plan.json +4 -4
- package/schemas/show.json +5 -3
- package/schemas/why.json +15 -1
- package/skills/vx/SKILL.md +28 -13
- package/src/bin.ts +30 -9
- package/src/cache/archive.ts +11 -0
- package/src/cache/cache.ts +124 -53
- package/src/cache/chained-cache.ts +4 -0
- package/src/cache/git-inputs.ts +277 -63
- package/src/cache/index.ts +15 -1
- package/src/cache/inputs.ts +102 -36
- package/src/cache/key-fold.ts +8 -7
- package/src/cache/layer.ts +15 -18
- package/src/cache/layered-cache.ts +20 -102
- package/src/cache/plugin-cache.ts +248 -0
- package/src/cache/policy.ts +32 -27
- package/src/cache/run-history.ts +104 -14
- package/src/cache/run-store.ts +77 -0
- package/src/cache/schema.ts +58 -31
- package/src/cache/scoped-cache.ts +237 -0
- package/src/cli/cache.ts +173 -34
- package/src/cli/completions.ts +11 -7
- package/src/cli/core-alias.ts +1 -1
- package/src/cli/foreign-flags.ts +13 -12
- package/src/cli/help.ts +110 -70
- package/src/cli/index.ts +67 -24
- package/src/cli/info.ts +43 -27
- package/src/cli/init.ts +115 -407
- package/src/cli/last.ts +157 -9
- package/src/cli/lock.ts +356 -122
- package/src/cli/plan-format.ts +7 -5
- package/src/cli/plugin-commands.ts +81 -14
- package/src/cli/plugin-templates.ts +11 -11
- package/src/cli/run.ts +116 -160
- package/src/cli/select.ts +50 -47
- package/src/cli/show.ts +83 -59
- package/src/cli/task-verb.ts +6 -13
- package/src/cli/upgrade.ts +415 -149
- package/src/cli/watch-cycle.ts +9 -2
- package/src/cli/watch-filter.ts +39 -61
- package/src/cli/watch-fs.ts +29 -16
- package/src/cli/watch-judge.ts +18 -4
- package/src/cli/watch-set.ts +16 -42
- package/src/cli/watch.ts +227 -230
- package/src/cli/why.ts +38 -18
- package/src/cli/workspace-config.ts +33 -70
- package/src/config.ts +169 -70
- package/src/exec/env.ts +1 -31
- package/src/exec/executor.ts +1 -5
- package/src/exec/kill-tree.ts +2 -1
- package/src/exec/sandbox-runtime.ts +12 -1
- package/src/exec/sandbox-violations.ts +9 -1
- package/src/graph/dependency-spec.ts +1 -1
- package/src/graph/index.ts +1 -0
- package/src/graph/priorities.ts +1 -1
- package/src/graph/scheduler.ts +27 -7
- package/src/graph/task-graph.ts +76 -24
- package/src/handoff.ts +169 -0
- package/src/index.ts +35 -58
- package/src/orchestrator/affected-tasks.ts +15 -8
- package/src/orchestrator/command-windows.ts +44 -0
- package/src/orchestrator/deferred-outputs.ts +12 -10
- package/src/orchestrator/doctor.ts +98 -110
- package/src/orchestrator/download-policy.ts +3 -3
- package/src/orchestrator/events.ts +19 -3
- package/src/orchestrator/excluded-keys.ts +0 -2
- package/src/orchestrator/execute-task.ts +147 -69
- package/src/orchestrator/failure-mode.ts +19 -10
- package/src/orchestrator/fingerprint-watch.ts +18 -15
- package/src/orchestrator/forecast.ts +10 -2
- package/src/orchestrator/framed-output.ts +9 -5
- package/src/orchestrator/graph-stage.ts +5 -5
- package/src/orchestrator/history.ts +126 -30
- package/src/orchestrator/hit-restore.ts +15 -3
- package/src/orchestrator/index.ts +20 -5
- package/src/orchestrator/local-shortcircuit.ts +2 -1
- package/src/orchestrator/lockfile-claim.ts +79 -20
- package/src/orchestrator/logger.ts +80 -41
- package/src/orchestrator/metrics.ts +78 -9
- package/src/orchestrator/miss-save.ts +3 -0
- package/src/orchestrator/options.ts +42 -29
- package/src/orchestrator/output-host.ts +72 -0
- package/src/orchestrator/plan.ts +6 -8
- package/src/orchestrator/plugin-host.ts +100 -66
- package/src/orchestrator/plugin.ts +173 -67
- package/src/orchestrator/prepare.ts +163 -78
- package/src/orchestrator/projects.ts +105 -99
- package/src/orchestrator/remote-prefetch.ts +11 -6
- package/src/orchestrator/run-context.ts +25 -6
- package/src/orchestrator/run-failures.ts +17 -8
- package/src/orchestrator/run-lock.ts +1 -1
- package/src/orchestrator/run-records.ts +1 -1
- package/src/orchestrator/run-report.ts +9 -9
- package/src/orchestrator/run-settings.ts +48 -0
- package/src/orchestrator/run.ts +244 -119
- package/src/orchestrator/sandbox-fix.ts +39 -20
- package/src/orchestrator/sandbox-request.ts +84 -13
- package/src/orchestrator/signals.ts +1 -1
- package/src/orchestrator/stable-keys.ts +13 -11
- package/src/orchestrator/status-line.ts +49 -7
- package/src/orchestrator/summary.ts +115 -106
- package/src/orchestrator/task-hash.ts +12 -83
- package/src/orchestrator/telemetry.ts +4 -4
- package/src/settings.ts +428 -0
- package/src/{orchestrator → util}/colors.ts +5 -0
- package/src/util/config-frame.ts +31 -2
- package/src/util/errors.ts +33 -1
- package/src/util/essential-env.ts +31 -0
- package/src/util/hide-env.ts +107 -0
- package/src/util/index.ts +16 -3
- package/src/util/paths.ts +10 -0
- package/src/util/refusal-notice.ts +111 -0
- package/src/util/report.ts +31 -0
- package/src/util/settle.ts +49 -30
- package/src/util/size.ts +23 -4
- package/src/util/timing.ts +3 -2
- package/src/util/ui.ts +186 -0
- package/src/util/ulid.ts +1 -1
- package/src/util/verbs.ts +0 -15
- package/src/workspace/affected.ts +84 -232
- package/src/workspace/config-eval.ts +15 -20
- package/src/workspace/config-imports.ts +78 -3
- package/src/workspace/config-schema.ts +209 -268
- package/src/workspace/dependency-rules.ts +65 -0
- package/src/workspace/filter.ts +2 -2
- package/src/workspace/fingerprint.ts +11 -121
- package/src/workspace/index.ts +20 -27
- package/src/workspace/load-reads.ts +4 -4
- package/src/workspace/lockfile.ts +96 -140
- package/src/workspace/migration.ts +307 -215
- package/src/workspace/package-graph.ts +30 -216
- package/src/workspace/project-loader.ts +80 -285
- package/src/workspace/repo-id.ts +2 -1
- package/src/workspace/workspace.ts +363 -831
- package/src/cache/config-evals.ts +0 -130
- package/src/workspace/config-cache.ts +0 -661
- package/src/workspace/migrate-scripts.ts +0 -1121
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { DependencyRule } from '../config.js'
|
|
2
|
+
import { refusal } from '../util/index.js'
|
|
3
|
+
import { compileNameGlob } from './filter.js'
|
|
4
|
+
import type { PackageGraph } from './package-graph.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `run.rules.dependencies`, held to each project's direct workspace
|
|
8
|
+
* dependencies (`PackageGraph.directDeps`: the manifest's and the
|
|
9
|
+
* cross-project `dependsOn` edges). A rule constrains the projects its
|
|
10
|
+
* `from` selects: each dependency must match an `allow` selector when
|
|
11
|
+
* `allow` is given, and no `deny` one. Every rule that selects a project
|
|
12
|
+
* applies, so a deny beats any allow. Checked by `vx lock` only (owner,
|
|
13
|
+
* 2026-10-13); every broken edge is named in one refusal.
|
|
14
|
+
*/
|
|
15
|
+
export function checkDependencyRules(
|
|
16
|
+
rules: readonly DependencyRule[],
|
|
17
|
+
projects: readonly string[],
|
|
18
|
+
tags: ReadonlyMap<string, readonly string[]>,
|
|
19
|
+
graph: PackageGraph,
|
|
20
|
+
): void {
|
|
21
|
+
if (rules.length === 0) return
|
|
22
|
+
const compiled = rules.map((r) => ({
|
|
23
|
+
from: selector(r.from),
|
|
24
|
+
allow: r.allow?.map(selector),
|
|
25
|
+
deny: r.deny?.map(selector),
|
|
26
|
+
}))
|
|
27
|
+
const broken: string[] = []
|
|
28
|
+
for (const name of projects) {
|
|
29
|
+
const own = tags.get(name) ?? []
|
|
30
|
+
for (const [i, rule] of compiled.entries()) {
|
|
31
|
+
if (!rule.from(name, own)) continue
|
|
32
|
+
for (const dep of graph.directDeps(name)) {
|
|
33
|
+
const theirs = tags.get(dep) ?? []
|
|
34
|
+
const denied = rule.deny?.some((s) => s(dep, theirs)) === true
|
|
35
|
+
if (denied || (rule.allow !== undefined && !rule.allow.some((s) => s(dep, theirs))))
|
|
36
|
+
broken.push(
|
|
37
|
+
`${name} depends on ${dep}, which run.rules.dependencies[${i}] (from '${rules[i]!.from}') ${denied ? 'denies' : 'does not allow'}`,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (broken.length === 0) return
|
|
43
|
+
const headline = `${broken.length === 1 ? '1 dependency breaks' : `${broken.length} dependencies break`} run.rules.dependencies`
|
|
44
|
+
throw refusal(
|
|
45
|
+
{
|
|
46
|
+
headline,
|
|
47
|
+
what: broken,
|
|
48
|
+
fix: "drop the dependency, or change the project's tags or the rule",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
code: 'VX_E_DEPENDENCY_RULE',
|
|
52
|
+
message: `${headline}:\n${broken.map((b) => ` ${b}`).join('\n')}\nDrop the dependency, or change the project's tags or the rule.`,
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** `tag:<glob>` matches a project carrying a matching tag; anything else, its name. */
|
|
58
|
+
function selector(s: string): (name: string, tags: readonly string[]) => boolean {
|
|
59
|
+
if (s.startsWith('tag:')) {
|
|
60
|
+
const re = compileNameGlob(s.slice(4))
|
|
61
|
+
return (_, tags) => tags.some((t) => re.test(t))
|
|
62
|
+
}
|
|
63
|
+
const re = compileNameGlob(s)
|
|
64
|
+
return (name) => re.test(name)
|
|
65
|
+
}
|
package/src/workspace/filter.ts
CHANGED
|
@@ -131,8 +131,8 @@ export function parseFilter(raw: string, workspaceRoot: string): ParsedFilter {
|
|
|
131
131
|
if (s === '') throw new UserError(`filter "${raw}" names no project`)
|
|
132
132
|
|
|
133
133
|
// `//` is Turbo's name for the root package (`--filter=//`, `//...`,
|
|
134
|
-
// `!//`, probed on 2.8.17)
|
|
135
|
-
//
|
|
134
|
+
// `!//`, probed on 2.8.17), and vx's for the root project unless
|
|
135
|
+
// something names it, so `//` is its directory, and only a project
|
|
136
136
|
// there: read as `.`, it would select every project when the root is
|
|
137
137
|
// none.
|
|
138
138
|
if (s === '//') {
|
|
@@ -1,129 +1,23 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { xxh3 } from '../util/index.js'
|
|
3
2
|
import { type LoadReads, readOnce } from './load-reads.js'
|
|
4
3
|
|
|
5
|
-
// Every package-manager lockfile we know about, plus the workspace
|
|
6
|
-
// definition files. Whichever ones exist get folded into the
|
|
7
|
-
// fingerprint; missing ones are skipped. Hashed in declaration order
|
|
8
|
-
// for determinism — adding a new entry here changes the fingerprint
|
|
9
|
-
// for projects that have that file present, which is fine: that's the
|
|
10
|
-
// whole point of bumping CACHE_VERSION when the fingerprint surface
|
|
11
|
-
// expands.
|
|
12
|
-
// Exported so `--affected` can consult the SAME list. A change to any of
|
|
13
|
-
// these re-keys every task in the workspace, so selection has to widen to
|
|
14
|
-
// match — two copies of this list would silently drift into a run that
|
|
15
|
-
// rebuilds everything while selecting nothing.
|
|
16
|
-
export const WORKSPACE_FINGERPRINT_FILES = [
|
|
17
|
-
// Lockfiles
|
|
18
|
-
'pnpm-lock.yaml',
|
|
19
|
-
'package-lock.json',
|
|
20
|
-
'npm-shrinkwrap.json',
|
|
21
|
-
'yarn.lock',
|
|
22
|
-
'bun.lock',
|
|
23
|
-
'bun.lockb',
|
|
24
|
-
// Workspace definition (pnpm); package.json is hashed per-project
|
|
25
|
-
// via projectPackageJsonHash, not here.
|
|
26
|
-
'pnpm-workspace.yaml',
|
|
27
|
-
// Yarn 4 catalogs: yarn.lock records a `catalog:` dependency as that
|
|
28
|
-
// literal, so a catalog flip to a range the file already resolves
|
|
29
|
-
// leaves it byte-identical while the workspace's install moves
|
|
30
|
-
// (turborepo#12635). pnpm's catalogs live in pnpm-workspace.yaml, and
|
|
31
|
-
// its lockfile records each importer's resolved version besides.
|
|
32
|
-
'.yarnrc.yml',
|
|
33
|
-
// Install settings no lockfile records: bun's `linker = "isolated"` and
|
|
34
|
-
// pnpm's `node-linker` / hoisting lay `node_modules` out anew under a
|
|
35
|
-
// byte-identical lockfile, and a build that imported an undeclared
|
|
36
|
-
// hoisted package kept its green hit where it now fails (D-7).
|
|
37
|
-
'.npmrc',
|
|
38
|
-
'bunfig.toml',
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
// DELIBERATELY ABSENT: `vx.workspace.{ts,mts,js,mjs,cts,cjs}`. Everything it can
|
|
42
|
-
// declare — `concurrency`, `cacheDir`, `timeout`, and the
|
|
43
|
-
// plugin list — is placement, storage or observability, never what a
|
|
44
|
-
// command produces; core's three seams may change WHERE a task runs, not
|
|
45
|
-
// WHAT it runs (architecture principle #3). Folding it in would also do
|
|
46
|
-
// active harm: a laptop declaring only the local plugins and a CI runner
|
|
47
|
-
// declaring `reapi()` would compute different fingerprints and share not
|
|
48
|
-
// one cache entry — the same split the rejected `NODE_OPTIONS` non-goal
|
|
49
|
-
// describes. A per-task input that genuinely varies belongs in
|
|
50
|
-
// `cache.inputs`, which is the surface built for it.
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* One hash for the workspace as a whole, derived from whichever
|
|
54
|
-
* lockfile + workspace-definition files exist at the root. Folded
|
|
55
|
-
* into every task's cache key so any lockfile bump (`pnpm update`,
|
|
56
|
-
* `npm install`, `bun install`, …) or a workspace-shape change
|
|
57
|
-
* invalidates every cached entry. Coarse but correct.
|
|
58
|
-
*/
|
|
59
|
-
export async function computeWorkspaceFingerprint(
|
|
60
|
-
workspaceRoot: string,
|
|
61
|
-
reads?: LoadReads,
|
|
62
|
-
): Promise<string> {
|
|
63
|
-
return (await computeWorkspaceFingerprints(workspaceRoot, NONE, reads)).all
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const NONE: ReadonlySet<string> = new Set()
|
|
67
|
-
|
|
68
|
-
export interface WorkspaceFingerprints {
|
|
69
|
-
/** Every file folded — what the config-evaluation cache keys on. */
|
|
70
|
-
readonly all: string
|
|
71
|
-
/**
|
|
72
|
-
* The same fold minus the files a plugin claims (`VxPlugin.fingerprint`)
|
|
73
|
-
* — what every task key folds. Identical to `all` with nothing claimed.
|
|
74
|
-
*/
|
|
75
|
-
readonly unclaimed: string
|
|
76
|
-
/**
|
|
77
|
-
* The bytes folded, by file name — what a mid-run check compares against
|
|
78
|
-
* when a task may have rewritten one (orchestrator/fingerprint-watch.ts).
|
|
79
|
-
* Already in memory for the fold; kept, not copied.
|
|
80
|
-
*/
|
|
81
|
-
readonly files: ReadonlyMap<string, Uint8Array>
|
|
82
|
-
}
|
|
83
|
-
|
|
84
4
|
/**
|
|
85
|
-
*
|
|
86
|
-
* `
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* re-key the workspace when the file appeared.
|
|
5
|
+
* The bytes of each named root file that exists: the files the plugins
|
|
6
|
+
* claim (`VxPlugin.fingerprint`), read once at run start so a task that
|
|
7
|
+
* rewrites one is caught (orchestrator/fingerprint-watch.ts). Core folds
|
|
8
|
+
* none of them into a key; the claimant does.
|
|
90
9
|
*/
|
|
91
|
-
export async function
|
|
10
|
+
export async function readClaimedFiles(
|
|
92
11
|
workspaceRoot: string,
|
|
93
|
-
|
|
12
|
+
names: Iterable<string>,
|
|
94
13
|
reads?: LoadReads,
|
|
95
|
-
): Promise<
|
|
96
|
-
let all = 0n
|
|
97
|
-
let unclaimed = 0n
|
|
14
|
+
): Promise<ReadonlyMap<string, Uint8Array>> {
|
|
98
15
|
const files = new Map<string, Uint8Array>()
|
|
99
|
-
for (const f of
|
|
16
|
+
for (const f of names) {
|
|
100
17
|
const bytes = await readOnce(reads, path.join(workspaceRoot, f))
|
|
101
|
-
if (bytes
|
|
102
|
-
files.set(f, bytes)
|
|
103
|
-
all = xxh3(`${f}\0`, all)
|
|
104
|
-
all = xxh3(bytes, all)
|
|
105
|
-
if (claimed.has(f)) continue
|
|
106
|
-
unclaimed = xxh3(`${f}\0`, unclaimed)
|
|
107
|
-
unclaimed = xxh3(bytes, unclaimed)
|
|
18
|
+
if (bytes !== null) files.set(f, bytes)
|
|
108
19
|
}
|
|
109
|
-
|
|
110
|
-
// left the lockfile byte-identical and every key unmoved while the
|
|
111
|
-
// install applied the new one (item 1014, where only `bun()`'s claim
|
|
112
|
-
// learned it). Each file it names folds here; a claimed bun.lock's
|
|
113
|
-
// plugin folds them itself.
|
|
114
|
-
const bunLock = files.get('bun.lock')
|
|
115
|
-
if (bunLock !== undefined) {
|
|
116
|
-
for (const rel of bunPatchFiles(bunLock)) {
|
|
117
|
-
const bytes = await readOnce(reads, path.join(workspaceRoot, rel))
|
|
118
|
-
const mark = `patch\0${rel}\0${bytes === null ? 'gone' : 'present'}`
|
|
119
|
-
all = xxh3(mark, all)
|
|
120
|
-
if (bytes !== null) all = xxh3(bytes, all)
|
|
121
|
-
if (claimed.has('bun.lock')) continue
|
|
122
|
-
unclaimed = xxh3(mark, unclaimed)
|
|
123
|
-
if (bytes !== null) unclaimed = xxh3(bytes, unclaimed)
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return { all: hex(all), unclaimed: hex(unclaimed), files }
|
|
20
|
+
return files
|
|
127
21
|
}
|
|
128
22
|
|
|
129
23
|
const PATCHED = new TextEncoder().encode('"patchedDependencies"')
|
|
@@ -132,7 +26,7 @@ const PATCHED = new TextEncoder().encode('"patchedDependencies"')
|
|
|
132
26
|
* The workspace-relative patch files a `bun.lock` names, sorted; none
|
|
133
27
|
* outside the workspace. A lockfile without the key is not parsed (the
|
|
134
28
|
* common case costs one byte search), and one that will not parse names
|
|
135
|
-
* none
|
|
29
|
+
* none.
|
|
136
30
|
*/
|
|
137
31
|
export function bunPatchFiles(bytes: Uint8Array): string[] {
|
|
138
32
|
if (Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).indexOf(PATCHED) < 0) return []
|
|
@@ -153,7 +47,3 @@ export function bunPatchFiles(bytes: Uint8Array): string[] {
|
|
|
153
47
|
}
|
|
154
48
|
return [...out].sort()
|
|
155
49
|
}
|
|
156
|
-
|
|
157
|
-
function hex(h: bigint): string {
|
|
158
|
-
return h.toString(16).padStart(16, '0')
|
|
159
|
-
}
|
package/src/workspace/index.ts
CHANGED
|
@@ -10,24 +10,23 @@ export {
|
|
|
10
10
|
refIsHead,
|
|
11
11
|
} from './affected.js'
|
|
12
12
|
export { applyFilters, parseFilter } from './filter.js'
|
|
13
|
-
export {
|
|
14
|
-
|
|
15
|
-
computeWorkspaceFingerprints,
|
|
16
|
-
WORKSPACE_FINGERPRINT_FILES,
|
|
17
|
-
type WorkspaceFingerprints,
|
|
18
|
-
} from './fingerprint.js'
|
|
13
|
+
export { readClaimedFiles } from './fingerprint.js'
|
|
14
|
+
export { checkDependencyRules } from './dependency-rules.js'
|
|
19
15
|
export { computeNestedProjectDirs } from './nested-dirs.js'
|
|
20
16
|
export { buildPackageGraph, type PackageGraph } from './package-graph.js'
|
|
21
17
|
export {
|
|
22
18
|
frozenProjectConfigs,
|
|
23
19
|
LOCKFILE_NAME,
|
|
24
20
|
LOCKFILE_VERSION,
|
|
21
|
+
LOCK_INVALID,
|
|
22
|
+
lockEntryBroken,
|
|
25
23
|
lockfilePath,
|
|
26
|
-
|
|
24
|
+
lockKey,
|
|
25
|
+
NO_LOCK,
|
|
27
26
|
readLockfile,
|
|
28
27
|
writeLockfile,
|
|
29
28
|
type Lockfile,
|
|
30
|
-
type
|
|
29
|
+
type LockedProject,
|
|
31
30
|
} from './lockfile.js'
|
|
32
31
|
export {
|
|
33
32
|
loadProjectConfig,
|
|
@@ -40,47 +39,41 @@ export {
|
|
|
40
39
|
cacheScopeError,
|
|
41
40
|
inputStabilityEnv,
|
|
42
41
|
isCacheScope,
|
|
42
|
+
taskNameProblem,
|
|
43
43
|
validateProjectConfig,
|
|
44
44
|
validateWorkspace,
|
|
45
45
|
} from './config-schema.js'
|
|
46
|
-
export
|
|
47
|
-
export {
|
|
48
|
-
blobOidOf,
|
|
49
|
-
configEvalKey,
|
|
50
|
-
configEvalKeyFromClosure,
|
|
51
|
-
configImports,
|
|
52
|
-
type ConfigEvalStore,
|
|
53
|
-
} from './config-cache.js'
|
|
46
|
+
export { configImports } from './config-imports.js'
|
|
54
47
|
export {
|
|
48
|
+
checkProjectNames,
|
|
55
49
|
findWorkspaceRoot,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
unreachedPackages,
|
|
62
|
-
memberBaseDirs,
|
|
50
|
+
findProjectConfigs,
|
|
51
|
+
discoveredProject,
|
|
52
|
+
linkDiscoveredEdges,
|
|
53
|
+
lockedProjects,
|
|
54
|
+
pathName,
|
|
63
55
|
PROJECT_CONFIG_FILENAMES,
|
|
64
56
|
resolveCacheDir,
|
|
65
57
|
resolveStoreRoot,
|
|
58
|
+
ROOT_NAME,
|
|
59
|
+
type ConfigDir,
|
|
66
60
|
type ProjectEntry,
|
|
67
61
|
type ProjectMeta,
|
|
68
|
-
type Workspace,
|
|
69
62
|
} from './workspace.js'
|
|
70
63
|
export type { LoadReads } from './load-reads.js'
|
|
71
|
-
// The migration seam (see migration.ts)
|
|
64
|
+
// The migration seam (see migration.ts).
|
|
72
65
|
export {
|
|
73
66
|
applyMigration,
|
|
74
67
|
foldScriptHooks,
|
|
75
|
-
PERSISTENT_TASK_NAMES,
|
|
76
68
|
PERSISTENT_TODO,
|
|
77
69
|
pruneOrphanPersistentNotes,
|
|
78
70
|
quoteTsLiteral,
|
|
79
71
|
type ApplyMigrationArgs,
|
|
80
72
|
type MigrationFormat,
|
|
73
|
+
type MigrationMember,
|
|
81
74
|
type GeneratedProject,
|
|
82
75
|
type GeneratedTask,
|
|
83
76
|
type MigrationPlan,
|
|
84
77
|
type RawExpr,
|
|
78
|
+
vxInvocation,
|
|
85
79
|
} from './migration.js'
|
|
86
|
-
export { delegatedScript, migrateScripts } from './migrate-scripts.js'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// A load reads each root file once. Finding the root reads its manifest,
|
|
2
|
-
// listing the package globs read it again and the
|
|
3
|
-
//
|
|
2
|
+
// listing the package globs read it again, and the claimed root files are
|
|
3
|
+
// read for the run (`readClaimedFiles`). Every such read goes through a `LoadReads` the load owns, so
|
|
4
4
|
// a file costs one probe and one read per load however many stages ask for
|
|
5
5
|
// it. The map lives exactly as long as the load: a `vx watch` cycle is a
|
|
6
6
|
// new load and reads fresh bytes.
|
|
@@ -14,8 +14,8 @@ export type LoadReads = Map<string, Promise<Uint8Array | null>>
|
|
|
14
14
|
* `file`'s bytes, read at most once per `reads`; null when there is no file
|
|
15
15
|
* there (`Bun.file(<dir>).exists()` is false, so a directory is none).
|
|
16
16
|
*
|
|
17
|
-
* The probe stays ahead of the read: most names asked about are absent
|
|
18
|
-
*
|
|
17
|
+
* The probe stays ahead of the read: most names asked about are absent
|
|
18
|
+
* (three of the four workspace config names, a manager's settings files),
|
|
19
19
|
* and a failed read costs 90–200 µs building its error where `exists()`
|
|
20
20
|
* answers in 15–40 µs (measured 2026-09-24) — so one stat per present file
|
|
21
21
|
* is cheaper than letting the open answer both questions.
|