@vzn/vx 0.0.575 → 0.0.577
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.
|
|
3
|
+
"version": "0.0.577",
|
|
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.
|
|
25
|
-
"@vzn/vx-linux-arm64": "0.0.
|
|
26
|
-
"@vzn/vx-darwin-x64": "0.0.
|
|
27
|
-
"@vzn/vx-darwin-arm64": "0.0.
|
|
24
|
+
"@vzn/vx-linux-x64": "0.0.577",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.577",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.577",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.577"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cli/cache.ts
CHANGED
|
@@ -172,7 +172,11 @@ async function pruneCmd(args: readonly string[]): Promise<number> {
|
|
|
172
172
|
let dir: string
|
|
173
173
|
let storeRoot: string | null = null
|
|
174
174
|
if (parsed.cacheDir !== undefined) dir = await cliCacheDir(root, parsed.cacheDir)
|
|
175
|
-
else
|
|
175
|
+
else {
|
|
176
|
+
const ws = await loadCliWorkspace(root)
|
|
177
|
+
dir = ws.cacheDir
|
|
178
|
+
storeRoot = await ws.storeRoot
|
|
179
|
+
}
|
|
176
180
|
// A workspace that never ran has nothing to prune, and opening the cache
|
|
177
181
|
// to find that out made it: `.vx/cache` with a database and a
|
|
178
182
|
// `.gitignore`, where item 900 had held the dry run to making nothing
|
|
@@ -27,8 +27,8 @@ export interface CliWorkspace {
|
|
|
27
27
|
workspaceConfig: WorkspaceConfig | null
|
|
28
28
|
plugins: readonly VxPlugin[]
|
|
29
29
|
cacheDir: string
|
|
30
|
-
/** The shared store a run opens `cacheDir` with (`resolveStoreRoot`). */
|
|
31
|
-
storeRoot: string | null
|
|
30
|
+
/** The shared store a run opens `cacheDir` with (`resolveStoreRoot`), asked on load. */
|
|
31
|
+
storeRoot: Promise<string | null>
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export const warnToStderr = (message: string): void => {
|
|
@@ -152,7 +152,7 @@ export async function loadCliProjects(
|
|
|
152
152
|
workspaceRoot,
|
|
153
153
|
undefined,
|
|
154
154
|
'open',
|
|
155
|
-
opts.cacheDir === undefined ? ws.storeRoot : null,
|
|
155
|
+
opts.cacheDir === undefined ? await ws.storeRoot : null,
|
|
156
156
|
)
|
|
157
157
|
try {
|
|
158
158
|
const loaded = await loadProjects({
|
|
@@ -155,7 +155,8 @@ async function collectWorkspaceInfo(
|
|
|
155
155
|
? resolveCacheDir(root, workspaceConfig)
|
|
156
156
|
: path.resolve(cwd, opts.cacheDir)
|
|
157
157
|
const metas = await discoverProjects(await loadWorkspace(root, reads), plugins, cacheDir, warn)
|
|
158
|
-
const storeRoot =
|
|
158
|
+
const storeRoot =
|
|
159
|
+
opts.cacheDir === undefined ? await resolveStoreRoot(root, workspaceConfig) : null
|
|
159
160
|
const cache = new Cache(cacheDir, undefined, undefined, undefined, 'inspect', storeRoot)
|
|
160
161
|
let stats
|
|
161
162
|
let orphans
|
|
@@ -224,6 +224,8 @@ export async function prepareRun(options: RunOptions, log: Logger): Promise<Prep
|
|
|
224
224
|
const cacheDir = options.cacheDir
|
|
225
225
|
? path.resolve(options.cwd, options.cacheDir)
|
|
226
226
|
: resolveCacheDir(workspaceRoot, workspaceConfig)
|
|
227
|
+
// Asked now, read when the cache opens: a repository with no remote is
|
|
228
|
+
// named by its root commit, a git spawn the discovery below overlaps.
|
|
227
229
|
const storeRoot = options.cacheDir ? null : resolveStoreRoot(workspaceRoot, workspaceConfig)
|
|
228
230
|
const projectMetas =
|
|
229
231
|
reused !== undefined
|
|
@@ -286,7 +288,7 @@ export async function prepareRun(options: RunOptions, log: Logger): Promise<Prep
|
|
|
286
288
|
workspaceRoot,
|
|
287
289
|
options.artifactCeiling,
|
|
288
290
|
'open',
|
|
289
|
-
storeRoot,
|
|
291
|
+
await storeRoot,
|
|
290
292
|
)
|
|
291
293
|
localCache.assertWritable()
|
|
292
294
|
// Two digests from one read: the config-evaluation cache keys on every
|
package/src/workspace/repo-id.ts
CHANGED
|
@@ -24,10 +24,11 @@ import path from 'node:path'
|
|
|
24
24
|
* first root commit; null for a shallow clone with no remote and outside
|
|
25
25
|
* git: those share nothing.
|
|
26
26
|
*/
|
|
27
|
-
export function repoIdOf(root: string): string | null {
|
|
27
|
+
export async function repoIdOf(root: string): Promise<string | null> {
|
|
28
28
|
const located = locateGitDir(root)
|
|
29
29
|
if (located === null) return null
|
|
30
|
-
const identity =
|
|
30
|
+
const identity =
|
|
31
|
+
(await remoteIdentity(root, located.commonDir)) ?? (await firstCommit(located.commonDir, root))
|
|
31
32
|
if (identity === null) return null
|
|
32
33
|
const rel = path.relative(located.gitRoot, path.resolve(root)).split(path.sep).join('/')
|
|
33
34
|
const key = sha256(`${identity}#${rel}`)
|
|
@@ -108,10 +109,10 @@ function readOwnedFile(p: string): string | null {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
/** The remote's identity from the config file, else from `git remote -v`. */
|
|
111
|
-
function remoteIdentity(root: string, commonDir: string): string | null {
|
|
112
|
+
async function remoteIdentity(root: string, commonDir: string): Promise<string | null> {
|
|
112
113
|
const config = readOwnedFile(path.join(commonDir, 'config'))
|
|
113
114
|
const remotes = config === null ? null : parseGitConfigRemotes(config)
|
|
114
|
-
const urls = remotes ?? remotesFromGit(root)
|
|
115
|
+
const urls = remotes ?? (await remotesFromGit(root))
|
|
115
116
|
const found = new Map<string, string>()
|
|
116
117
|
let first: string | null = null
|
|
117
118
|
for (const [name, url] of urls) {
|
|
@@ -160,8 +161,8 @@ export function parseGitConfigRemotes(contents: string): [string, string][] | nu
|
|
|
160
161
|
return remotes
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
function remotesFromGit(root: string): [string, string][] {
|
|
164
|
-
const out = git(root, ['remote', '-v'])
|
|
164
|
+
async function remotesFromGit(root: string): Promise<[string, string][]> {
|
|
165
|
+
const out = await git(root, ['remote', '-v'])
|
|
165
166
|
if (out === null) return []
|
|
166
167
|
const pairs: [string, string][] = []
|
|
167
168
|
for (const line of out.split('\n')) {
|
|
@@ -183,17 +184,22 @@ export function parseRemoteUrl(url: string): string | null {
|
|
|
183
184
|
return ssh === null ? null : `${ssh[1]}/${ssh[3]}/${ssh[4]}`
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
/**
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
/**
|
|
188
|
+
* The sorted-first root commit, so every clone agrees; null when shallow.
|
|
189
|
+
* Shallow is git's own test, a `shallow` file in the common dir: asking
|
|
190
|
+
* `rev-parse` cost a spawn on every run of a repo with no remote.
|
|
191
|
+
*/
|
|
192
|
+
async function firstCommit(commonDir: string, root: string): Promise<string | null> {
|
|
193
|
+
if (existsSync(path.join(commonDir, 'shallow'))) return null
|
|
194
|
+
const roots = await git(root, ['rev-list', '--max-parents=0', 'HEAD'])
|
|
190
195
|
return roots?.split(/\r?\n/).filter(Boolean).sort()[0] ?? null
|
|
191
196
|
}
|
|
192
197
|
|
|
193
|
-
function git(cwd: string, args: string[]): string | null {
|
|
198
|
+
async function git(cwd: string, args: string[]): Promise<string | null> {
|
|
194
199
|
try {
|
|
195
|
-
const p = Bun.
|
|
196
|
-
|
|
200
|
+
const p = Bun.spawn(['git', ...args], { cwd, stdout: 'pipe', stderr: 'ignore' })
|
|
201
|
+
const [out, code] = await Promise.all([new Response(p.stdout).text(), p.exited])
|
|
202
|
+
return code === 0 ? out : null
|
|
197
203
|
} catch {
|
|
198
204
|
return null
|
|
199
205
|
}
|
|
@@ -385,17 +385,21 @@ export function resolveCacheDir(root: string, config: WorkspaceConfig | null): s
|
|
|
385
385
|
* `VX_CACHE_DIR`): that directory then holds everything, as one
|
|
386
386
|
* workspace's alone. Null with no repository identity or no home.
|
|
387
387
|
*/
|
|
388
|
-
export function resolveStoreRoot(
|
|
388
|
+
export async function resolveStoreRoot(
|
|
389
|
+
root: string,
|
|
390
|
+
config: WorkspaceConfig | null,
|
|
391
|
+
): Promise<string | null> {
|
|
389
392
|
if (config?.cacheDir !== undefined || process.env['VX_CACHE_DIR']) return null
|
|
390
393
|
// HOME first: Bun's homedir() keeps the HOME the process started with (1.4.2).
|
|
391
394
|
const home = process.env['HOME'] || homedir()
|
|
392
395
|
if (!path.isAbsolute(home)) return null
|
|
393
396
|
let id = repoIds.get(root)
|
|
394
397
|
if (id === undefined) repoIds.set(root, (id = repoIdOf(root)))
|
|
395
|
-
|
|
398
|
+
const resolved = await id
|
|
399
|
+
return resolved === null ? null : path.join(home, '.vx', resolved, 'cache')
|
|
396
400
|
}
|
|
397
401
|
|
|
398
|
-
const repoIds = new Map<string, string | null
|
|
402
|
+
const repoIds = new Map<string, Promise<string | null>>()
|
|
399
403
|
|
|
400
404
|
/**
|
|
401
405
|
* Read the workspace's package-glob list, supporting all common
|