@vzn/vx-migrate 0.0.646 → 0.0.648

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.
@@ -1,4 +1,4 @@
1
- import type { ArtifactInfo, RemoteCacheLayer } from '@vzn/vx'
1
+ import { type ArtifactInfo, type RemoteCacheLayer, UserError } from '@vzn/vx'
2
2
 
3
3
  /**
4
4
  * How a remote keeps branches apart (2026-10-20). `'header'`: plain keys,
@@ -10,9 +10,10 @@ import type { ArtifactInfo, RemoteCacheLayer } from '@vzn/vx'
10
10
  */
11
11
  export type RemoteScope = 'header' | 'key'
12
12
 
13
- export function remoteScope(name: string, scope: unknown): RemoteScope {
13
+ /** `factory`: the option's owner as a workspace calls it, `turboCache`. */
14
+ export function remoteScope(factory: string, scope: unknown): RemoteScope {
14
15
  if (scope === undefined || scope === 'header' || scope === 'key') return scope ?? 'header'
15
- throw new Error(`vx/${name}: scope must be 'header' or 'key', got ${JSON.stringify(scope)}`)
16
+ throw new UserError(`${factory}(): scope must be 'header' or 'key', got ${JSON.stringify(scope)}`)
16
17
  }
17
18
 
18
19
  /** A server caps the read header at this many refs (the server rules), so vx never sends more. */
@@ -57,6 +58,7 @@ export function keyedByRef(inner: RemoteCacheLayer, allRefs: readonly string[]):
57
58
  return {
58
59
  ...(inner.endpoint !== undefined ? { endpoint: inner.endpoint } : {}),
59
60
  ...(inner.open !== undefined ? { open: (ctx) => inner.open!(ctx) } : {}),
61
+ ...(inner.lend !== undefined ? { lend: () => inner.lend!() } : {}),
60
62
  has: firstHeld,
61
63
  ...(hasMany !== undefined
62
64
  ? {
@@ -9,7 +9,8 @@ import { existsSync } from 'node:fs'
9
9
  import path from 'node:path'
10
10
  import { type GeneratedProject, type GeneratedTask, UserError } from '@vzn/vx'
11
11
  import type { PackageMeta } from '../packages.js'
12
- import { minimatchToVx, withoutTakenBack } from '../glob-grammar.js'
12
+ import { refuseTaskNames } from '../plugin-gaps.js'
13
+ import { hasGluedGlobstar, minimatchToVx, withoutTakenBack } from '../glob-grammar.js'
13
14
  import { packageScripts, relPosix } from '../paths.js'
14
15
  import { scriptCommand, yarnPnp } from '../script-command.js'
15
16
  import {
@@ -70,9 +71,11 @@ function viteConfigFile(dir: string): string | null {
70
71
 
71
72
  // Bun's resolver reads `\` as a separator, even in a file: URL, so a config
72
73
  // under `a\b` was looked for under `a/b`. Resolved here, the path stays as
73
- // written; the file is read from it.
74
- const LITERAL_QUERY = /\?vx-literal$/
74
+ // written; the file is read from it, found by its number: Bun 1.4.4 hands
75
+ // onLoad the path with `\` made `/`.
76
+ const LITERAL_QUERY = /\?vx-literal=(\d+)$/
75
77
  let servingLiteral = false
78
+ const literals: string[] = []
76
79
 
77
80
  function importAsWritten(file: string): Promise<{ default?: unknown }> {
78
81
  if (!file.includes('\\')) return import(file)
@@ -86,7 +89,7 @@ function importAsWritten(file: string): Promise<{ default?: unknown }> {
86
89
  namespace: 'file',
87
90
  }))
88
91
  build.onLoad({ filter: LITERAL_QUERY }, async (args) => {
89
- const at = args.path.replace(LITERAL_QUERY, '')
92
+ const at = literals[Number(LITERAL_QUERY.exec(args.path)![1])]!
90
93
  return {
91
94
  contents: await Bun.file(at).text(),
92
95
  loader: /\.[cm]?ts$/.test(at) ? 'ts' : 'js',
@@ -95,7 +98,7 @@ function importAsWritten(file: string): Promise<{ default?: unknown }> {
95
98
  },
96
99
  })
97
100
  }
98
- return import(`${file}?vx-literal`)
101
+ return import(`${file}?vx-literal=${literals.push(file) - 1}`)
99
102
  }
100
103
 
101
104
  /**
@@ -384,6 +387,7 @@ export async function mapViteTaskWorkspace(
384
387
  `workspace dependencies spell (${n} task${n === 1 ? '' : 's'}) — add any other a task reads to ` +
385
388
  'inputs.env and exec.env.passThrough',
386
389
  )
390
+ refuseTaskNames(projects, 'task')
387
391
  return { projects, notes }
388
392
  }
389
393
 
@@ -551,7 +555,8 @@ function globs(
551
555
  } else continue
552
556
  const neg = pattern.startsWith('!')
553
557
  const raw = neg ? pattern.slice(1) : pattern
554
- const wax = minimatchToVx(raw, neg)
558
+ // wax refuses a glued `**` (`src/**.ts`), and so does core.
559
+ const wax = hasGluedGlobstar(raw) ? null : minimatchToVx(raw, neg)
555
560
  if (wax === null) {
556
561
  todos.push(
557
562
  `${kind} ${JSON.stringify(pattern)}: glob syntax vx cannot take — ` +
@@ -1,5 +1,5 @@
1
1
  // The plugins a migrated workspace declares, from what the repo shows
2
- // (owner, 2026-10-06: "install and migrate fully … use the plugins"). Each
2
+ // (2026-10-06: "install and migrate fully … use the plugins"). Each
3
3
  // is inert where it does not apply, so declaring one costs a run nothing,
4
4
  // and each is installed beside vx at vx-migrate's own version (plugins
5
5
  // pin their core peer to the release they shipped with).
@@ -23,9 +23,12 @@ export function workspacePlugins(root: string, runner?: 'turbo' | 'nx'): Workspa
23
23
  out.push({ pkg: '@vzn/vx-migrate', factory: REMOTE_CACHE[runner] })
24
24
  const lock = lockfilePlugin(root)
25
25
  if (lock !== undefined) out.push({ pkg: '@vzn/vx-lockfile', factory: lock.factory })
26
- out.push({ pkg: '@vzn/vx-schedule-history', factory: 'scheduleHistoryPlugin' })
26
+ out.push({ pkg: '@vzn/vx-history', factory: 'vxHistory' })
27
27
  if (existsSync(path.join(root, '.github', 'workflows')))
28
28
  out.push({ pkg: '@vzn/vx-ci', factory: 'github' })
29
+ // A remote cache on CI reads the refs only these name (2026-10-25).
30
+ if (existsSync(path.join(root, '.gitlab-ci.yml')))
31
+ out.push({ pkg: '@vzn/vx-ci', factory: 'gitlab' })
29
32
  return out
30
33
  }
31
34