@vzn/vx 0.0.645 → 0.0.646

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 (71) hide show
  1. package/README.md +10 -28
  2. package/package.json +5 -5
  3. package/schemas/last.json +15 -0
  4. package/skills/vx/SKILL.md +1 -1
  5. package/src/bin.ts +1 -1
  6. package/src/cache/cache.ts +66 -16
  7. package/src/cache/git-inputs.ts +55 -10
  8. package/src/cache/index.ts +4 -0
  9. package/src/cache/inputs.ts +61 -11
  10. package/src/cache/layer.ts +25 -2
  11. package/src/cache/layered-cache.ts +32 -2
  12. package/src/cache/output-index.ts +25 -11
  13. package/src/cache/remote-lane.ts +13 -4
  14. package/src/cache/run-history.ts +13 -6
  15. package/src/cache/schema.ts +19 -2
  16. package/src/cli/core-alias.ts +5 -2
  17. package/src/cli/help.ts +4 -6
  18. package/src/cli/index.ts +0 -12
  19. package/src/cli/init.ts +43 -10
  20. package/src/cli/last.ts +4 -2
  21. package/src/cli/plugin-commands.ts +96 -3
  22. package/src/cli/plugin-templates.ts +1 -1
  23. package/src/cli/run.ts +2 -7
  24. package/src/cli/select.ts +5 -3
  25. package/src/cli/upgrade.ts +4 -5
  26. package/src/exec/executor.ts +112 -9
  27. package/src/exec/index.ts +2 -0
  28. package/src/exec/proc-sample.ts +67 -5
  29. package/src/exec/runner.ts +4 -0
  30. package/src/exec/sandbox-runtime.ts +11 -4
  31. package/src/graph/scheduler.ts +59 -8
  32. package/src/history/history.ts +119 -7
  33. package/src/history/metrics.ts +53 -16
  34. package/src/index.ts +15 -0
  35. package/src/orchestrator/execute-args.ts +3 -0
  36. package/src/orchestrator/execute-task.ts +28 -7
  37. package/src/orchestrator/held-servers.ts +86 -0
  38. package/src/orchestrator/hit-restore.ts +11 -4
  39. package/src/orchestrator/index.ts +17 -1
  40. package/src/orchestrator/local-floor.ts +104 -0
  41. package/src/orchestrator/local-shortcircuit.ts +26 -7
  42. package/src/orchestrator/miss-save.ts +10 -4
  43. package/src/orchestrator/persistent-task.ts +14 -0
  44. package/src/orchestrator/placement.ts +84 -9
  45. package/src/orchestrator/plugin-host.ts +21 -3
  46. package/src/orchestrator/plugin.ts +37 -0
  47. package/src/orchestrator/prepare.ts +11 -3
  48. package/src/orchestrator/run-keys.ts +164 -0
  49. package/src/orchestrator/run-records.ts +6 -0
  50. package/src/orchestrator/run.ts +93 -6
  51. package/src/orchestrator/sandbox-request.ts +9 -3
  52. package/src/orchestrator/task-artifacts.ts +142 -0
  53. package/src/orchestrator/task-hash.ts +11 -1
  54. package/src/orchestrator/task-process.ts +16 -0
  55. package/src/orchestrator/telemetry-host.ts +2 -1
  56. package/src/orchestrator/telemetry.ts +60 -17
  57. package/src/report/forecast.ts +6 -27
  58. package/src/report/framed-output.ts +41 -5
  59. package/src/report/logger.ts +60 -20
  60. package/src/report/status-line.ts +38 -18
  61. package/src/report/summary.ts +61 -7
  62. package/src/settings.ts +7 -0
  63. package/src/util/colors.ts +16 -1
  64. package/src/util/index.ts +1 -0
  65. package/src/util/paths.ts +30 -0
  66. package/src/util/ui.ts +4 -1
  67. package/src/workspace/config-bytecode.ts +276 -0
  68. package/src/workspace/index.ts +0 -1
  69. package/src/workspace/migration.ts +4 -32
  70. package/src/workspace/project-loader.ts +92 -14
  71. package/src/cli/foreign-flags.ts +0 -727
@@ -14,6 +14,7 @@ import {
14
14
  } from './config-eval.js'
15
15
  import { configImports, hasEsmExport, unprovidedBareImports } from './config-imports.js'
16
16
  import { readOnce, unreadable } from './load-reads.js'
17
+ import { buildCompiled, loadCompiled, loadedModules } from './config-bytecode.js'
17
18
 
18
19
  // The validator lives in config-schema.ts; re-exported so a reader that
19
20
  // reaches the loader for it (the tests do) keeps working.
@@ -142,6 +143,8 @@ async function loadDefaultExport(
142
143
  configPath: string,
143
144
  kind: string,
144
145
  bytes: Uint8Array,
146
+ /** The workspace root, where the load may run the config's bytecode bundle (config-bytecode.ts). */
147
+ compiledRoot?: string,
145
148
  ): Promise<unknown> {
146
149
  refuseUnprovidedImports(bytes, configPath, kind)
147
150
  // No random bust for `vx lock`: a project config reaches this import
@@ -166,9 +169,17 @@ async function loadDefaultExport(
166
169
  holdSource(hash, source)
167
170
  }
168
171
  let ns: { default?: unknown }
172
+ let compiled: { default?: unknown } | null | undefined
173
+ let loaded: Set<string> | undefined
169
174
  const unguard = guardExit()
170
175
  let deadline: ReturnType<typeof setTimeout> | undefined
171
176
  try {
177
+ // A bundle that throws is evaluated from source below, so the error
178
+ // the user sees is the source's.
179
+ compiled =
180
+ literal || compiledRoot === undefined ? null : tryCompiled(compiledRoot, configPath, bytes)
181
+ if (compiled) return defaultOf(compiled, kind, configPath)
182
+ if (compiled === undefined) loaded = loadedModules(compiledRoot!)
172
183
  // The worker's budget, here too: a top-level await that never settled
173
184
  // while a timer kept the loop alive hung `vx run` for good, silently
174
185
  // (D-66).
@@ -198,11 +209,32 @@ async function loadDefaultExport(
198
209
  unguard()
199
210
  if (source !== null) releaseSource(hash)
200
211
  }
212
+ const mod = defaultOf(ns, kind, configPath)
213
+ if (compiledRoot !== undefined && loaded !== undefined) {
214
+ await buildCompiled(compiledRoot, configPath, bytes, loaded, ns)
215
+ }
216
+ return mod
217
+ }
218
+
219
+ function defaultOf(ns: { default?: unknown }, kind: string, configPath: string): unknown {
201
220
  const mod = ns?.default
202
221
  assertDefaultObject(mod, kind, configPath)
203
222
  return mod
204
223
  }
205
224
 
225
+ /** The bundle's namespace; `undefined` to build one after this load, `null` when none can serve. */
226
+ function tryCompiled(
227
+ root: string,
228
+ configPath: string,
229
+ bytes: Uint8Array,
230
+ ): { default?: unknown } | null | undefined {
231
+ try {
232
+ return loadCompiled(root, configPath, bytes)
233
+ } catch {
234
+ return null
235
+ }
236
+ }
237
+
206
238
  /**
207
239
  * A config's `process.exit` ended vx mid-load: `exit(0)` was a green run
208
240
  * that ran nothing and printed nothing (D-65). While any config evaluates
@@ -509,12 +541,53 @@ export async function loadProjectConfigs(configPaths: readonly string[]): Promis
509
541
  let redirectHolders = 0
510
542
  let undoRedirect = (): void => {}
511
543
  /**
512
- * Bun's own `Console`, taken at load: the console a round finds may be a
513
- * constructed one (a plugin's verb may install its own), which has no `Console`.
514
- * The global's, not `node:console`'s: the playground bundles this module
515
- * for the browser, where that specifier is a stub.
544
+ * Bun's own console, taken at load: the console a round finds may be a
545
+ * constructed one (a plugin's verb may install its own), which has no
546
+ * `Console`. The global's, not `node:console`'s: the playground bundles
547
+ * this module for the browser, where that specifier is a stub.
516
548
  */
517
- const BunConsole = (globalThis.console as { Console?: typeof console.Console }).Console
549
+ const bunConsole = globalThis.console as typeof console & { Console?: typeof console.Console }
550
+ let stderrConsole: typeof console | undefined
551
+ const BUILT_ON_READ: ReadonlySet<PropertyKey> = new Set(['Console', '_stdout', '_stderr'])
552
+
553
+ /**
554
+ * A console that writes to stderr, built on the first call: reading
555
+ * `Console` loads `node:console`, ~4 ms of a warm run, and the workspace
556
+ * config each run loads in a redirect seldom prints.
557
+ */
558
+ function redirectedConsole(): typeof console {
559
+ const real = (): Record<PropertyKey, (...a: unknown[]) => unknown> =>
560
+ (stderrConsole ??= Object.assign(new bunConsole.Console!(process.stderr, process.stderr), {
561
+ // Bun's console adds `write`, which a constructed Console lacks.
562
+ write: (...data: string[]) => {
563
+ const text = data.join('')
564
+ process.stderr.write(text)
565
+ return text.length
566
+ },
567
+ })) as unknown as Record<PropertyKey, (...a: unknown[]) => unknown>
568
+ const facade = {}
569
+ for (const key of [...Reflect.ownKeys(bunConsole), 'write']) {
570
+ // Read through the real one when read: even their descriptors build a
571
+ // module or a stream (~17 ms together, Bun 1.4.2).
572
+ if (BUILT_ON_READ.has(key)) {
573
+ Object.defineProperty(facade, key, { get: () => real()[key], configurable: true })
574
+ continue
575
+ }
576
+ const own = Object.getOwnPropertyDescriptor(bunConsole, key)
577
+ Object.defineProperty(
578
+ facade,
579
+ key,
580
+ own === undefined || typeof own.value === 'function'
581
+ ? {
582
+ value: (...args: unknown[]) => real()[key]!(...args),
583
+ writable: true,
584
+ configurable: true,
585
+ }
586
+ : own,
587
+ )
588
+ }
589
+ return facade as typeof console
590
+ }
518
591
 
519
592
  function stdoutToStderr(): () => void {
520
593
  if (redirectHolders++ === 0) undoRedirect = installRedirect()
@@ -540,14 +613,7 @@ function installRedirect(): () => void {
540
613
  ;(Bun.stdout as { writer: typeof Bun.stdout.writer }).writer = ((
541
614
  ...args: Parameters<typeof Bun.stderr.writer>
542
615
  ) => Bun.stderr.writer(...args)) as typeof Bun.stdout.writer
543
- // Bun's console adds `write`, which a constructed Console lacks.
544
- globalThis.console = Object.assign(new BunConsole!(process.stderr, process.stderr), {
545
- write: (...data: string[]) => {
546
- const text = data.join('')
547
- process.stderr.write(text)
548
- return text.length
549
- },
550
- })
616
+ globalThis.console = redirectedConsole()
551
617
  return () => {
552
618
  if (ownWrite === undefined) delete (out as { write?: unknown }).write
553
619
  else Object.defineProperty(out, 'write', ownWrite)
@@ -622,12 +688,14 @@ interface BuiltinSnapshot {
622
688
  */
623
689
  const BUN_MEMBERS_VX_READS: readonly PropertyKey[] = [
624
690
  'Archive',
691
+ 'BuildMetafile',
625
692
  'BunFile',
626
693
  'CryptoHasher',
627
694
  'Glob',
628
695
  'JSONC',
629
696
  'Subprocess',
630
697
  'Transpiler',
698
+ 'build',
631
699
  'color',
632
700
  'deepEquals',
633
701
  'env',
@@ -637,9 +705,11 @@ const BUN_MEMBERS_VX_READS: readonly PropertyKey[] = [
637
705
  'inspect',
638
706
  'main',
639
707
  'nanoseconds',
708
+ 'pathToFileURL',
640
709
  'plugin',
641
710
  'randomUUIDv7',
642
711
  'resolveSync',
712
+ 'revision',
643
713
  'secrets',
644
714
  'serve',
645
715
  'sleep',
@@ -959,7 +1029,15 @@ export async function loadWorkspaceConfig(root: string): Promise<WorkspaceConfig
959
1029
  const umask = currentUmask()
960
1030
  let mod: WorkspaceConfig
961
1031
  try {
962
- mod = (await loadDefaultExport(configPath, 'Workspace', bytes)) as WorkspaceConfig
1032
+ mod = (await loadDefaultExport(
1033
+ configPath,
1034
+ 'Workspace',
1035
+ bytes,
1036
+ // Every load, not only the first: a repeat load (the run after the
1037
+ // CLI's selection pass) must get the same plugin instances, and a
1038
+ // required bundle is the cached module.
1039
+ path.resolve(root),
1040
+ )) as WorkspaceConfig
963
1041
  } finally {
964
1042
  const changed = [
965
1043
  ...restoreBuiltins(builtins),