@vzn/vx 0.0.512 → 0.0.513

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx",
3
- "version": "0.0.512",
3
+ "version": "0.0.513",
4
4
  "description": "The fastest task runner and build cache for JavaScript monorepos.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -21,10 +21,10 @@
21
21
  "node": ">=18"
22
22
  },
23
23
  "optionalDependencies": {
24
- "@vzn/vx-linux-x64": "0.0.512",
25
- "@vzn/vx-linux-arm64": "0.0.512",
26
- "@vzn/vx-darwin-x64": "0.0.512",
27
- "@vzn/vx-darwin-arm64": "0.0.512"
24
+ "@vzn/vx-linux-x64": "0.0.513",
25
+ "@vzn/vx-linux-arm64": "0.0.513",
26
+ "@vzn/vx-darwin-x64": "0.0.513",
27
+ "@vzn/vx-darwin-arm64": "0.0.513"
28
28
  },
29
29
  "dependencies": {
30
30
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
package/src/exec/env.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
1
2
  import path from 'node:path'
2
3
 
3
4
  // Build the environment exposed to a task.
@@ -91,3 +92,55 @@ export function buildIsolatedEnv(opts: BuildEnvOptions): NodeJS.ProcessEnv {
91
92
 
92
93
  return out
93
94
  }
95
+
96
+ /**
97
+ * `npm_execpath`, as the workspace's package manager sets it for a script.
98
+ * A tool that runs other scripts reads it to call the same manager back
99
+ * (npm-run-all's `run-s`, `run-p`) and falls back to `npm` without it:
100
+ * solidjs/solid's `npm-run-all -nl build:*` needed a global npm under vx,
101
+ * where `pnpm run build` passed (owner, 2026-10-06). It names a binary on
102
+ * this machine, so it is not in the key, as PATH is not.
103
+ */
104
+ export const PM_EXEC_ENV = 'npm_execpath'
105
+
106
+ const MANAGERS = ['pnpm', 'yarn', 'bun', 'npm'] as const
107
+ const LOCKFILES: ReadonlyArray<readonly [string, (typeof MANAGERS)[number]]> = [
108
+ ['pnpm-lock.yaml', 'pnpm'],
109
+ ['yarn.lock', 'yarn'],
110
+ ['bun.lock', 'bun'],
111
+ ['bun.lockb', 'bun'],
112
+ ['package-lock.json', 'npm'],
113
+ ]
114
+
115
+ const managerPaths = new Map<string, string | null>()
116
+
117
+ /**
118
+ * The executable of the workspace's package manager: the root
119
+ * package.json's `packageManager`, else its lockfile, found on the root's
120
+ * `node_modules/.bin` and PATH. Learned once per root; null when the root
121
+ * names none or this machine has none.
122
+ */
123
+ export function packageManagerPath(root: string): string | null {
124
+ const known = managerPaths.get(root)
125
+ if (known !== undefined) return known
126
+ let name: string | undefined
127
+ try {
128
+ const field = (
129
+ JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8')) as {
130
+ packageManager?: unknown
131
+ }
132
+ ).packageManager
133
+ if (typeof field === 'string') name = MANAGERS.find((m) => field.startsWith(`${m}@`))
134
+ } catch {}
135
+ name ??= LOCKFILES.find(([f]) => existsSync(path.join(root, f)))?.[1]
136
+ const found =
137
+ name === undefined
138
+ ? null
139
+ : Bun.which(name, {
140
+ PATH: [path.join(root, 'node_modules', '.bin'), process.env['PATH'] ?? ''].join(
141
+ path.delimiter,
142
+ ),
143
+ })
144
+ managerPaths.set(root, found)
145
+ return found
146
+ }
package/src/exec/index.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  // Module contract. Cross-module imports must come through here; see
2
2
  // docs/design/module-isolation-2026-06.md and tests/module-boundaries.test.ts.
3
3
 
4
- export { buildIsolatedEnv, VX_RUN_TASK_ENV, VX_RUN_WORKSPACE_ENV } from './env.js'
4
+ export {
5
+ buildIsolatedEnv,
6
+ packageManagerPath,
7
+ PM_EXEC_ENV,
8
+ VX_RUN_TASK_ENV,
9
+ VX_RUN_WORKSPACE_ENV,
10
+ } from './env.js'
5
11
  export {
6
12
  runCommand,
7
13
  runPersistent,
@@ -17,6 +17,8 @@ import {
17
17
  } from '../cache/index.js'
18
18
  import {
19
19
  buildIsolatedEnv,
20
+ packageManagerPath,
21
+ PM_EXEC_ENV,
20
22
  VX_RUN_TASK_ENV,
21
23
  VX_RUN_WORKSPACE_ENV,
22
24
  runPersistent,
@@ -1411,6 +1413,11 @@ function taskEnv(node: TaskNode, step: ExecConfig, workspaceRoot: string): NodeJ
1411
1413
  })
1412
1414
  env[VX_RUN_WORKSPACE_ENV] = workspaceRoot
1413
1415
  env[VX_RUN_TASK_ENV] = node.id
1416
+ // A task's own passThrough or define wins.
1417
+ if (env[PM_EXEC_ENV] === undefined) {
1418
+ const manager = packageManagerPath(workspaceRoot)
1419
+ if (manager !== null) env[PM_EXEC_ENV] = manager
1420
+ }
1414
1421
  return env
1415
1422
  }
1416
1423