@vzn/vx 0.0.354 → 0.0.356
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 +21 -77
- package/package.json +5 -5
- package/src/cache/archive.ts +3 -11
- package/src/cache/cache.ts +2 -2
- package/src/cache/git-inputs.ts +2 -1
- package/src/cache/inputs.ts +3 -6
- package/src/cli/help.ts +2 -1
- package/src/cli/init.ts +1 -1
- package/src/cli/upgrade.ts +2 -3
- package/src/config.ts +3 -2
- package/src/exec/env.ts +0 -16
- package/src/exec/kill-tree.ts +0 -24
- package/src/exec/local-executor.ts +2 -3
- package/src/exec/runner.ts +24 -22
- package/src/exec/sandbox-binds.ts +39 -15
- package/src/exec/sandbox-runtime.ts +43 -4
- package/src/exec/sandbox-violations.ts +92 -15
- package/src/orchestrator/events.ts +8 -3
- package/src/orchestrator/execute-task.ts +14 -1
- package/src/orchestrator/run-lock.ts +1 -31
- package/src/orchestrator/sandbox-request.ts +1 -1
- package/src/util/real-path.ts +2 -5
- package/src/util/which.ts +2 -7
- package/src/workspace/config-cache.ts +15 -0
- package/src/workspace/config-schema.ts +8 -1
- package/src/workspace/migrate-scripts.ts +24 -0
- package/src/workspace/migration.ts +20 -4
- package/src/workspace/package-graph.ts +21 -13
- package/src/workspace/project-loader.ts +61 -38
|
@@ -8,6 +8,7 @@ import { hasEsmExport, unprovidedBareImports } from './config-imports.js'
|
|
|
8
8
|
import {
|
|
9
9
|
configEvalKey,
|
|
10
10
|
configEvalKeyFromClosure,
|
|
11
|
+
configEvalKeyFromIdentities,
|
|
11
12
|
configImports,
|
|
12
13
|
type ConfigEvalStore,
|
|
13
14
|
} from './config-cache.js'
|
|
@@ -297,7 +298,7 @@ export interface LoadProjectConfigOptions {
|
|
|
297
298
|
* order given, so a failure names the first broken file the way a
|
|
298
299
|
* one-by-one load did). A single-path load is the one-element case.
|
|
299
300
|
*/
|
|
300
|
-
const LOAD_WIDTH =
|
|
301
|
+
const LOAD_WIDTH = 128
|
|
301
302
|
|
|
302
303
|
export async function loadProjectConfigs(
|
|
303
304
|
configPaths: readonly string[],
|
|
@@ -323,49 +324,69 @@ export async function loadProjectConfigs(
|
|
|
323
324
|
// the map; a file the batch could not stat has no identity, which makes
|
|
324
325
|
// that config's fast key miss and sends it down the slow path exactly as
|
|
325
326
|
// a throwing per-file `hashFile` did.
|
|
326
|
-
let
|
|
327
|
+
let identities: Map<string, string> | undefined
|
|
327
328
|
if (closures.size > 0 && store?.hashFiles !== undefined) {
|
|
328
329
|
const files = new Set<string>()
|
|
329
330
|
for (const closure of closures.values()) for (const f of closure) files.add(f)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
331
|
+
identities = await store.hashFiles([...files])
|
|
332
|
+
}
|
|
333
|
+
// With the batch in hand a fast key is synchronous: an async key per
|
|
334
|
+
// config, awaiting identities already in the map, was ~5 ms of a
|
|
335
|
+
// 1,000-config warm load. Only a config off the fast path is awaited.
|
|
336
|
+
const fastKeyOf = (configPath: string): string | null => {
|
|
337
|
+
const closure = closures.get(configPath)
|
|
338
|
+
if (closure === undefined || evalCache === undefined || identities === undefined) return null
|
|
339
|
+
return configEvalKeyFromIdentities({
|
|
340
|
+
closure,
|
|
341
|
+
identities,
|
|
342
|
+
workspaceFingerprint: evalCache.workspaceFingerprint,
|
|
343
|
+
})
|
|
344
|
+
}
|
|
345
|
+
const fastHashFile = identities === undefined ? hashFile : undefined
|
|
346
|
+
interface Prepared {
|
|
347
|
+
configPath: string
|
|
348
|
+
bytes: Uint8Array | null
|
|
349
|
+
cacheKey: string | null
|
|
350
|
+
indexed: boolean
|
|
351
|
+
closure?: string[] | undefined
|
|
337
352
|
}
|
|
338
353
|
const prepared = await Promise.all(
|
|
339
|
-
configPaths.map(
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
hashFile: fastHashFile,
|
|
345
|
-
workspaceFingerprint: evalCache.workspaceFingerprint,
|
|
346
|
-
})
|
|
347
|
-
if (fastKey !== null) return { configPath, bytes: null, cacheKey: fastKey, indexed: true }
|
|
348
|
-
}
|
|
349
|
-
const bytes = await Bun.file(configPath).bytes()
|
|
350
|
-
const keyed =
|
|
351
|
-
evalCache === undefined
|
|
352
|
-
? null
|
|
353
|
-
: await configEvalKey({
|
|
354
|
-
configPath,
|
|
355
|
-
bytes,
|
|
356
|
-
workspaceRoot: evalCache.workspaceRoot,
|
|
357
|
-
workspaceFingerprint: evalCache.workspaceFingerprint,
|
|
358
|
-
...slowKeyHash,
|
|
359
|
-
})
|
|
360
|
-
return {
|
|
361
|
-
configPath,
|
|
362
|
-
bytes,
|
|
363
|
-
cacheKey: keyed?.key ?? null,
|
|
364
|
-
indexed: false,
|
|
365
|
-
closure: keyed !== null && keyed.indexable ? keyed.closure : undefined,
|
|
366
|
-
}
|
|
354
|
+
configPaths.map((configPath): Prepared | Promise<Prepared> => {
|
|
355
|
+
const fastKey = fastKeyOf(configPath)
|
|
356
|
+
return fastKey !== null
|
|
357
|
+
? { configPath, bytes: null, cacheKey: fastKey, indexed: true }
|
|
358
|
+
: slowPrepared(configPath)
|
|
367
359
|
}),
|
|
368
360
|
)
|
|
361
|
+
async function slowPrepared(configPath: string): Promise<Prepared> {
|
|
362
|
+
const closure = closures.get(configPath)
|
|
363
|
+
if (closure !== undefined && evalCache !== undefined && fastHashFile !== undefined) {
|
|
364
|
+
const fastKey = await configEvalKeyFromClosure({
|
|
365
|
+
closure,
|
|
366
|
+
hashFile: fastHashFile,
|
|
367
|
+
workspaceFingerprint: evalCache.workspaceFingerprint,
|
|
368
|
+
})
|
|
369
|
+
if (fastKey !== null) return { configPath, bytes: null, cacheKey: fastKey, indexed: true }
|
|
370
|
+
}
|
|
371
|
+
const bytes = await Bun.file(configPath).bytes()
|
|
372
|
+
const keyed =
|
|
373
|
+
evalCache === undefined
|
|
374
|
+
? null
|
|
375
|
+
: await configEvalKey({
|
|
376
|
+
configPath,
|
|
377
|
+
bytes,
|
|
378
|
+
workspaceRoot: evalCache.workspaceRoot,
|
|
379
|
+
workspaceFingerprint: evalCache.workspaceFingerprint,
|
|
380
|
+
...slowKeyHash,
|
|
381
|
+
})
|
|
382
|
+
return {
|
|
383
|
+
configPath,
|
|
384
|
+
bytes,
|
|
385
|
+
cacheKey: keyed?.key ?? null,
|
|
386
|
+
indexed: false,
|
|
387
|
+
closure: keyed !== null && keyed.indexable ? keyed.closure : undefined,
|
|
388
|
+
}
|
|
389
|
+
}
|
|
369
390
|
let hits = new Map<string, string>()
|
|
370
391
|
if (evalCache !== undefined) {
|
|
371
392
|
const keys = prepared.map((p) => p.cacheKey).filter((k): k is string => k !== null)
|
|
@@ -462,7 +483,9 @@ export async function loadProjectConfigs(
|
|
|
462
483
|
try {
|
|
463
484
|
// Loaded LOAD_WIDTH at a time: one import after another put 1,000 cold
|
|
464
485
|
// configs at ~160 ms of imports where 64 at once take ~60 (D-68), and
|
|
465
|
-
//
|
|
486
|
+
// 128 took `load configs` from 432 to 411 ms more; the width bounds the
|
|
487
|
+
// files a module load may hold open, so it stays under macOS's default
|
|
488
|
+
// 256-descriptor limit. A failure
|
|
466
489
|
// stops nothing (the rest are evaluated and stored for the next
|
|
467
490
|
// attempt); the error thrown is the first in order, as the serial
|
|
468
491
|
// loop's was.
|