@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
package/src/cli/why.ts
CHANGED
|
@@ -5,20 +5,25 @@
|
|
|
5
5
|
// names the exact cache-key components that differ. Read-only over cache.db —
|
|
6
6
|
// no config evaluation, no re-hash.
|
|
7
7
|
|
|
8
|
-
import { Cache } from '../cache/index.js'
|
|
8
|
+
import { Cache, noteSchemaReset } from '../cache/index.js'
|
|
9
|
+
import { seeHelp } from './help.js'
|
|
9
10
|
import { splitTaskId } from '../graph/index.js'
|
|
10
11
|
import {
|
|
11
12
|
cacheKeyDiff,
|
|
12
13
|
explainCacheKeyQuery as explainCacheKey,
|
|
14
|
+
latestRunId,
|
|
13
15
|
whyDidThisRerunQuery as whyDidThisRerun,
|
|
14
16
|
} from '../orchestrator/index.js'
|
|
15
|
-
import { UserError } from '../util/index.js'
|
|
16
|
-
import { findWorkspaceRoot
|
|
17
|
+
import { nearMatches, UserError } from '../util/index.js'
|
|
18
|
+
import { findWorkspaceRoot } from '../workspace/index.js'
|
|
19
|
+
import { cliCacheDir, parseCacheDirFlag, warnToStderr } from './workspace-config.js'
|
|
17
20
|
|
|
18
21
|
interface WhyArgs {
|
|
19
22
|
target?: string
|
|
20
23
|
runId?: string
|
|
21
24
|
format: 'pretty' | 'json'
|
|
25
|
+
/** `--cache-dir`: read the history a run with the same flag wrote. */
|
|
26
|
+
cacheDir?: string
|
|
22
27
|
error?: string
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -51,20 +56,37 @@ export function parseWhyArgs(args: readonly string[]): WhyArgs {
|
|
|
51
56
|
out.format = fv
|
|
52
57
|
continue
|
|
53
58
|
}
|
|
54
|
-
|
|
59
|
+
const cd = parseCacheDirFlag(args, i)
|
|
60
|
+
if (cd !== null) {
|
|
61
|
+
if ('error' in cd) return { ...out, error: cd.error }
|
|
62
|
+
out.cacheDir = cd.cacheDir
|
|
63
|
+
i = cd.next
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
if (a.startsWith('-')) return { ...out, error: `unknown flag: ${a}${seeHelp('why')}` }
|
|
55
67
|
if (out.target !== undefined) return { ...out, error: `unexpected argument: ${a}` }
|
|
56
68
|
out.target = a
|
|
57
69
|
}
|
|
58
70
|
return out
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
/**
|
|
74
|
+
* A bare query is a TASK name, so it is matched against the task half of
|
|
75
|
+
* every recorded id (the same rule `vx run` hints with) and the hint is
|
|
76
|
+
* the runnable `project#task`; an anchored query is matched whole.
|
|
77
|
+
*/
|
|
78
|
+
function suggest(query: string, ids: readonly string[]): string {
|
|
79
|
+
let hits: string[]
|
|
80
|
+
if (query.includes('#')) {
|
|
81
|
+
hits = nearMatches(query, ids)
|
|
82
|
+
} else {
|
|
83
|
+
const byTask = new Map<string, string[]>()
|
|
84
|
+
for (const id of ids) {
|
|
85
|
+
const task = splitTaskId(id)[1]
|
|
86
|
+
byTask.set(task, [...(byTask.get(task) ?? []), id])
|
|
87
|
+
}
|
|
88
|
+
hits = nearMatches(query, byTask.keys()).flatMap((t) => byTask.get(t) ?? [])
|
|
89
|
+
}
|
|
68
90
|
return hits.length > 0 ? ` — did you mean ${hits.slice(0, 3).join(', ')}?` : ''
|
|
69
91
|
}
|
|
70
92
|
|
|
@@ -75,12 +97,21 @@ function suggest(query: string, candidates: readonly string[]): string {
|
|
|
75
97
|
*/
|
|
76
98
|
function resolveTarget(cache: Cache, target: string): string {
|
|
77
99
|
const db = cache.dbHandle()
|
|
100
|
+
if (target.includes('#')) {
|
|
101
|
+
// An exact id needs one row, and its newest is where a scan from the
|
|
102
|
+
// top of the table finds it first — the full DISTINCT walk below is for
|
|
103
|
+
// the error's suggestions and the bare-name form only.
|
|
104
|
+
const [project, task] = splitTaskId(target)
|
|
105
|
+
const hit = db
|
|
106
|
+
.query('SELECT 1 FROM runs WHERE project = ? AND task = ? ORDER BY id DESC LIMIT 1')
|
|
107
|
+
.get(project, task)
|
|
108
|
+
if (hit !== null) return target
|
|
109
|
+
}
|
|
78
110
|
const pairs = db
|
|
79
111
|
.query('SELECT DISTINCT project, task FROM runs ORDER BY project, task')
|
|
80
112
|
.all() as Array<{ project: string; task: string }>
|
|
81
113
|
const ids = pairs.map((p) => `${p.project}#${p.task}`)
|
|
82
114
|
if (target.includes('#')) {
|
|
83
|
-
if (ids.includes(target)) return target
|
|
84
115
|
throw new UserError(`vx why: no recorded runs for "${target}"${suggest(target, ids)}`)
|
|
85
116
|
}
|
|
86
117
|
const matches = ids.filter((id) => id.endsWith(`#${target}`))
|
|
@@ -94,19 +125,6 @@ function resolveTarget(cache: Cache, target: string): string {
|
|
|
94
125
|
throw new UserError(`vx why: no recorded runs for task "${target}"${suggest(target, ids)}`)
|
|
95
126
|
}
|
|
96
127
|
|
|
97
|
-
/** The latest recorded run of a task (run_id may be NULL on very old rows). */
|
|
98
|
-
function latestRunId(cache: Cache, taskId: string): string | null {
|
|
99
|
-
const [project, task] = splitTaskId(taskId)
|
|
100
|
-
const row = cache
|
|
101
|
-
.dbHandle()
|
|
102
|
-
.query(
|
|
103
|
-
`SELECT run_id AS runId FROM runs WHERE project = ? AND task = ?
|
|
104
|
-
ORDER BY started_at DESC LIMIT 1`,
|
|
105
|
-
)
|
|
106
|
-
.get(project, task) as { runId: string | null } | undefined
|
|
107
|
-
return row?.runId ?? null
|
|
108
|
-
}
|
|
109
|
-
|
|
110
128
|
const fmtWhen = (ms: number): string => new Date(ms).toISOString()
|
|
111
129
|
|
|
112
130
|
export async function whyCmd(args: readonly string[]): Promise<number> {
|
|
@@ -117,12 +135,12 @@ export async function whyCmd(args: readonly string[]): Promise<number> {
|
|
|
117
135
|
}
|
|
118
136
|
|
|
119
137
|
const root = await findWorkspaceRoot(process.cwd())
|
|
120
|
-
const
|
|
121
|
-
|
|
138
|
+
const cache = Cache.inspect(await cliCacheDir(root, parsed.cacheDir))
|
|
139
|
+
noteSchemaReset(cache, warnToStderr)
|
|
122
140
|
try {
|
|
123
141
|
const db = cache.dbHandle()
|
|
124
142
|
const taskId = resolveTarget(cache, parsed.target)
|
|
125
|
-
const runId = parsed.runId ?? latestRunId(cache, taskId)
|
|
143
|
+
const runId = parsed.runId ?? latestRunId(cache.dbHandle(), taskId)
|
|
126
144
|
|
|
127
145
|
if (runId === null) {
|
|
128
146
|
// Runs exist (resolveTarget passed) but predate run ids — fall back to
|
|
@@ -155,9 +173,13 @@ export async function whyCmd(args: readonly string[]): Promise<number> {
|
|
|
155
173
|
const lines: string[] = []
|
|
156
174
|
const t = why.thisRun!
|
|
157
175
|
lines.push(`${taskId} — run ${runId}`)
|
|
176
|
+
// A hit's status (`cache-hit`, `cache-hit-remote`) already names it and
|
|
177
|
+
// its tier; only an executed run needs the word. A skipped task never
|
|
178
|
+
// ran and has no key: it read `skipped · executed · key ` (item 898).
|
|
179
|
+
const ran = t.cacheHit === false && t.status !== 'skipped'
|
|
158
180
|
lines.push(
|
|
159
181
|
` this run ${fmtWhen(t.startedAt)} · ${t.status}` +
|
|
160
|
-
`${
|
|
182
|
+
`${ran ? ' · executed' : ''}${t.hash === '' ? ' · no key' : ` · key ${t.hash}`}`,
|
|
161
183
|
)
|
|
162
184
|
if (why.previousRun == null) {
|
|
163
185
|
lines.push(' previous (none — first recorded run of this task)')
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// The workspace as every verb must see it: the config with the plugin
|
|
2
|
+
// `config` stage applied, and the cache dir derived from THAT. The stage
|
|
3
|
+
// is documented to shape `cacheDir`; a verb that read the file raw opened
|
|
4
|
+
// a directory the run never used — `vx last` found no runs, `vx cache
|
|
5
|
+
// prune` pruned nothing, `vx watch` ignored the wrong path.
|
|
6
|
+
|
|
7
|
+
import { existsSync } from 'node:fs'
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
import type { WorkspaceConfig } from '../config.js'
|
|
10
|
+
import { UserError } from '../util/index.js'
|
|
11
|
+
import { Cache, noteSchemaReset } from '../cache/index.js'
|
|
12
|
+
import { loadProjects, loadWorkspacePlugins } from '../orchestrator/index.js'
|
|
13
|
+
import type { VxPlugin } from '../orchestrator/index.js'
|
|
14
|
+
import {
|
|
15
|
+
buildPackageGraph,
|
|
16
|
+
computeWorkspaceFingerprint,
|
|
17
|
+
FROZEN_WITHOUT_LOCK,
|
|
18
|
+
type ProjectEntry,
|
|
19
|
+
type ProjectMeta,
|
|
20
|
+
readLockfile,
|
|
21
|
+
resolveCacheDir,
|
|
22
|
+
} from '../workspace/index.js'
|
|
23
|
+
|
|
24
|
+
export interface CliWorkspace {
|
|
25
|
+
workspaceConfig: WorkspaceConfig | null
|
|
26
|
+
plugins: readonly VxPlugin[]
|
|
27
|
+
cacheDir: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const warnToStderr = (message: string): void => {
|
|
31
|
+
process.stderr.write(`${message}\n`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function loadCliWorkspace(workspaceRoot: string): Promise<CliWorkspace> {
|
|
35
|
+
const { workspaceConfig, plugins } = await loadWorkspacePlugins(workspaceRoot, warnToStderr)
|
|
36
|
+
return { workspaceConfig, plugins, cacheDir: resolveCacheDir(workspaceRoot, workspaceConfig) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* `--cache-dir <path>` / `--cache-dir=<path>` for a verb that reads the
|
|
41
|
+
* cache a run wrote — `why`, `last`, `info`, `cache prune`. Same rules as
|
|
42
|
+
* `vx run`'s: a value is required, and the space form refuses a value
|
|
43
|
+
* that looks like a flag (an unquoted empty shell variable would otherwise
|
|
44
|
+
* swallow the next flag as the path). Returns null when `args[i]` is not
|
|
45
|
+
* this flag; `next` is the index of the last argv slot consumed.
|
|
46
|
+
*/
|
|
47
|
+
export function parseCacheDirFlag(
|
|
48
|
+
args: readonly string[],
|
|
49
|
+
i: number,
|
|
50
|
+
): { cacheDir: string; next: number } | { error: string } | null {
|
|
51
|
+
const a = args[i]!
|
|
52
|
+
if (a !== '--cache-dir' && !a.startsWith('--cache-dir=')) return null
|
|
53
|
+
const v = a === '--cache-dir' ? args[i + 1] : a.slice('--cache-dir='.length)
|
|
54
|
+
if (v === undefined || v === '') return { error: '--cache-dir requires a path' }
|
|
55
|
+
if (a === '--cache-dir' && v.startsWith('-')) {
|
|
56
|
+
return { error: `--cache-dir requires a path, got flag: ${v}` }
|
|
57
|
+
}
|
|
58
|
+
return { cacheDir: v, next: a === '--cache-dir' ? i + 1 : i }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A reading verb's `--cache-dir`, resolved against the working directory.
|
|
63
|
+
* Named explicitly, a directory that is not there is a typo to report, not
|
|
64
|
+
* an empty cache to read (item 900).
|
|
65
|
+
*/
|
|
66
|
+
export function namedCacheDir(override: string): string {
|
|
67
|
+
const dir = path.resolve(process.cwd(), override)
|
|
68
|
+
if (!existsSync(dir)) throw new UserError(`--cache-dir ${override}: no such directory (${dir})`)
|
|
69
|
+
return dir
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The cache directory a reading verb opens: `--cache-dir` resolved against
|
|
74
|
+
* cwd exactly as `vx run` resolves it (prepare.ts), else the workspace's —
|
|
75
|
+
* so `vx run --cache-dir X` and `vx last --cache-dir X` read one history.
|
|
76
|
+
*/
|
|
77
|
+
export async function cliCacheDir(
|
|
78
|
+
workspaceRoot: string,
|
|
79
|
+
override: string | undefined,
|
|
80
|
+
): Promise<string> {
|
|
81
|
+
if (override !== undefined) return namedCacheDir(override)
|
|
82
|
+
return (await loadCliWorkspace(workspaceRoot)).cacheDir
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The run flags a verb's staged load must honour to see what the run sees. */
|
|
86
|
+
export interface CliLoadOptions {
|
|
87
|
+
/** `--cache-dir`: where the cached evaluations live. */
|
|
88
|
+
cacheDir?: string
|
|
89
|
+
/** `--frozen`: configs come from `vx-lock.json`, not evaluation. */
|
|
90
|
+
frozen?: boolean
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The run path's project-config load (`loadProjects`) for a verb that only
|
|
95
|
+
* reads: the plugin `project` stage applies, and the local cache opens only
|
|
96
|
+
* to serve cached evaluations — a pure config costs a stat, not an
|
|
97
|
+
* evaluation. `scope` is every project or a list of names; no closure, no
|
|
98
|
+
* lock (a verb reads live, as a default run does).
|
|
99
|
+
*/
|
|
100
|
+
export async function loadCliProjects(
|
|
101
|
+
workspaceRoot: string,
|
|
102
|
+
metas: readonly ProjectMeta[],
|
|
103
|
+
scope: 'all' | readonly string[] = 'all',
|
|
104
|
+
opts: CliLoadOptions = {},
|
|
105
|
+
): Promise<Map<string, ProjectEntry>> {
|
|
106
|
+
const ws = await loadCliWorkspace(workspaceRoot)
|
|
107
|
+
const { plugins } = ws
|
|
108
|
+
// The cached evaluations live where the run's do: a verb given
|
|
109
|
+
// `--cache-dir` must not open (and create) the workspace's default one.
|
|
110
|
+
const cacheDir = opts.cacheDir ?? ws.cacheDir
|
|
111
|
+
// A frozen run reads its configs from the lock; what it SELECTS must be
|
|
112
|
+
// decided from the same configs, or an env-dependent `workspaceFiles`
|
|
113
|
+
// glob could select live what the run then treats otherwise.
|
|
114
|
+
const lock = opts.frozen === true ? await readLockfile(workspaceRoot) : null
|
|
115
|
+
if (opts.frozen === true && lock === null) throw new UserError(FROZEN_WITHOUT_LOCK)
|
|
116
|
+
const cache = new Cache(cacheDir, { read: true, write: true }, workspaceRoot)
|
|
117
|
+
noteSchemaReset(cache, warnToStderr)
|
|
118
|
+
try {
|
|
119
|
+
const loaded = await loadProjects({
|
|
120
|
+
workspaceRoot,
|
|
121
|
+
cacheDir,
|
|
122
|
+
plugins,
|
|
123
|
+
projectMetas: metas,
|
|
124
|
+
packageGraph: buildPackageGraph([...metas]),
|
|
125
|
+
seeds: scope,
|
|
126
|
+
closure: false,
|
|
127
|
+
lock,
|
|
128
|
+
evalCache: {
|
|
129
|
+
store: cache,
|
|
130
|
+
workspaceFingerprint: await computeWorkspaceFingerprint(workspaceRoot),
|
|
131
|
+
},
|
|
132
|
+
warn: warnToStderr,
|
|
133
|
+
})
|
|
134
|
+
return loaded.projects
|
|
135
|
+
} finally {
|
|
136
|
+
cache.close()
|
|
137
|
+
}
|
|
138
|
+
}
|