@vzn/vx 0.0.541 → 0.0.543
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 +5 -5
- package/src/cache/cache.ts +9 -6
- package/src/cli/cache.ts +20 -6
- package/src/cli/why.ts +27 -8
- package/src/orchestrator/doctor.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.543",
|
|
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.543",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.543",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.543",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.543"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cache/cache.ts
CHANGED
|
@@ -636,7 +636,8 @@ export class Cache implements CacheLayer {
|
|
|
636
636
|
* and the store's own schema is `store_meta.schema` (`matchStoreSchema`). Or
|
|
637
637
|
* `null` for an index that holds its entries itself (a `cacheDir`).
|
|
638
638
|
* Undefined follows the layout the index records: a reading verb, a
|
|
639
|
-
* plugin's handle.
|
|
639
|
+
* plugin's handle. An `'inspect'` open reads it only where the index
|
|
640
|
+
* records none (deleted, or never written beside a run's store).
|
|
640
641
|
*/
|
|
641
642
|
storeRoot?: string | null,
|
|
642
643
|
) {
|
|
@@ -802,11 +803,13 @@ export class Cache implements CacheLayer {
|
|
|
802
803
|
)?.value,
|
|
803
804
|
)
|
|
804
805
|
let storeDir =
|
|
805
|
-
mode === 'inspect'
|
|
806
|
-
? recorded
|
|
807
|
-
: storeRoot ===
|
|
808
|
-
?
|
|
809
|
-
: storeRoot
|
|
806
|
+
mode === 'inspect'
|
|
807
|
+
? (recorded ?? (typeof storeRoot === 'string' ? storeRoot : undefined))
|
|
808
|
+
: storeRoot === undefined
|
|
809
|
+
? recorded
|
|
810
|
+
: storeRoot === null
|
|
811
|
+
? undefined
|
|
812
|
+
: storeRoot
|
|
810
813
|
if (storeDir !== undefined && mode === 'open' && this.writeBlocked === null) {
|
|
811
814
|
const blocked = storeBlocked(storeDir, typeof storeRoot === 'string' ? storeRoot : null)
|
|
812
815
|
if (blocked !== null) {
|
package/src/cli/cache.ts
CHANGED
|
@@ -4,7 +4,12 @@ import { flagHint, refusedWord, seeHelp } from './help.js'
|
|
|
4
4
|
import { nearest, parseDuration, parseSize } from '../util/index.js'
|
|
5
5
|
import { acquireRunLock } from '../orchestrator/index.js'
|
|
6
6
|
import { findWorkspaceRoot } from '../workspace/index.js'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
cliCacheDir,
|
|
9
|
+
loadCliWorkspace,
|
|
10
|
+
parseCacheDirFlag,
|
|
11
|
+
warnToStderr,
|
|
12
|
+
} from './workspace-config.js'
|
|
8
13
|
import { formatBytes } from './format.js'
|
|
9
14
|
|
|
10
15
|
// parseSize moved to `util` (the orchestrator's resource resolver needs it
|
|
@@ -90,7 +95,7 @@ export function parsePruneArgs(args: readonly string[]): PruneArgs {
|
|
|
90
95
|
// the deliberate way to do it.
|
|
91
96
|
if (ms === 0) {
|
|
92
97
|
return {
|
|
93
|
-
error: `--older-than 0 would evict every entry — delete the cache
|
|
98
|
+
error: `--older-than 0 would evict every entry — to clear the cache, delete the cache store \`vx info\` names`,
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
out.olderThanMs = Date.now() - ms
|
|
@@ -103,7 +108,7 @@ export function parsePruneArgs(args: readonly string[]): PruneArgs {
|
|
|
103
108
|
if (bytes === null) return { error: `invalid size: ${v} (e.g. 500M, 1G)` }
|
|
104
109
|
if (bytes === 0) {
|
|
105
110
|
return {
|
|
106
|
-
error: `--max-size 0 would evict every entry — delete the cache
|
|
111
|
+
error: `--max-size 0 would evict every entry — to clear the cache, delete the cache store \`vx info\` names`,
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
// A bare number is bytes to `parseSize` (a computed size needs that),
|
|
@@ -161,14 +166,20 @@ async function pruneCmd(args: readonly string[]): Promise<number> {
|
|
|
161
166
|
// operate on the same directory or prune silently no-ops against the
|
|
162
167
|
// wrong path.
|
|
163
168
|
// A dry run only reads: it never resets the index (item 896).
|
|
164
|
-
|
|
169
|
+
// The store `vx run` keeps entries in (`~/.vx/<id>/cache`): with the
|
|
170
|
+
// index deleted, a prune followed nothing and said 0 while every entry
|
|
171
|
+
// stayed restorable (X-17).
|
|
172
|
+
let dir: string
|
|
173
|
+
let storeRoot: string | null = null
|
|
174
|
+
if (parsed.cacheDir !== undefined) dir = await cliCacheDir(root, parsed.cacheDir)
|
|
175
|
+
else ({ cacheDir: dir, storeRoot } = await loadCliWorkspace(root))
|
|
165
176
|
// A workspace that never ran has nothing to prune, and opening the cache
|
|
166
177
|
// to find that out made it: `.vx/cache` with a database and a
|
|
167
178
|
// `.gitignore`, where item 900 had held the dry run to making nothing
|
|
168
179
|
// (and a read-only checkout was refused as unwritable instead).
|
|
169
180
|
const dry = parsed.dryRun === true
|
|
170
181
|
const json = parsed.format === 'json'
|
|
171
|
-
if (!existsSync(dir)) {
|
|
182
|
+
if (!existsSync(dir) && (storeRoot === null || !existsSync(storeRoot))) {
|
|
172
183
|
printPruned({ evicted: 0, bytesFreed: 0, orphans: 0, orphanBytes: 0 }, dry, json)
|
|
173
184
|
return 0
|
|
174
185
|
}
|
|
@@ -182,7 +193,10 @@ async function pruneCmd(args: readonly string[]): Promise<number> {
|
|
|
182
193
|
return 0
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
|
-
const cache =
|
|
196
|
+
const cache =
|
|
197
|
+
parsed.dryRun === true
|
|
198
|
+
? new Cache(dir, undefined, undefined, undefined, 'inspect', storeRoot)
|
|
199
|
+
: new Cache(dir, undefined, root, undefined, 'open', storeRoot)
|
|
186
200
|
// A prune deletes rows and artifacts; a cache this user cannot write is
|
|
187
201
|
// refused up front with the directory named, as a run refuses it, rather
|
|
188
202
|
// than dying in the first DELETE with SQLite's "readonly database" and a
|
package/src/cli/why.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from '../orchestrator/index.js'
|
|
19
19
|
import { MASKED, nearMatches, printable, UserError } from '../util/index.js'
|
|
20
20
|
import { findWorkspaceRoot } from '../workspace/index.js'
|
|
21
|
+
import { findCwdProject } from './select.js'
|
|
21
22
|
import { cliCacheDir, parseCacheDirFlag } from './workspace-config.js'
|
|
22
23
|
|
|
23
24
|
interface WhyArgs {
|
|
@@ -127,9 +128,14 @@ function suggest(query: string, ids: readonly string[]): string {
|
|
|
127
128
|
/**
|
|
128
129
|
* Resolve a positional target to a full `project#task` id against the runs
|
|
129
130
|
* table. A `pkg#task` form is used as-is; a bare task name matches every
|
|
130
|
-
* project that ran it — unique → resolved, several →
|
|
131
|
+
* project that ran it — unique → resolved, several → the project the cwd
|
|
132
|
+
* sits in, as `vx run build` there picks (X-18), else an error listing them.
|
|
131
133
|
*/
|
|
132
|
-
function resolveTarget(
|
|
134
|
+
async function resolveTarget(
|
|
135
|
+
cache: Cache,
|
|
136
|
+
target: string,
|
|
137
|
+
cwdProject: () => Promise<string | null>,
|
|
138
|
+
): Promise<string> {
|
|
133
139
|
const db = cache.dbHandle()
|
|
134
140
|
if (target.includes('#')) {
|
|
135
141
|
// An exact id needs one row, and its newest is where a scan from the
|
|
@@ -151,6 +157,8 @@ function resolveTarget(cache: Cache, target: string): string {
|
|
|
151
157
|
const matches = ids.filter((id) => id.endsWith(`#${target}`))
|
|
152
158
|
if (matches.length === 1) return matches[0]!
|
|
153
159
|
if (matches.length > 1) {
|
|
160
|
+
const here = await cwdProject()
|
|
161
|
+
if (here !== null && matches.includes(`${here}#${target}`)) return `${here}#${target}`
|
|
154
162
|
throw new UserError(
|
|
155
163
|
`vx why: "${target}" ran in ${matches.length} projects — pick one:\n` +
|
|
156
164
|
matches.map((m) => ` ${m}`).join('\n'),
|
|
@@ -187,11 +195,19 @@ export async function whyCmd(args: readonly string[]): Promise<number> {
|
|
|
187
195
|
const cache = Cache.inspect(await cliCacheDir(root, parsed.cacheDir))
|
|
188
196
|
try {
|
|
189
197
|
const db = cache.dbHandle()
|
|
190
|
-
const taskId = resolveTarget(cache, await rootSpelled(root, parsed.target))
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
const taskId = await resolveTarget(cache, await rootSpelled(root, parsed.target), () =>
|
|
199
|
+
findCwdProject(process.cwd()),
|
|
200
|
+
)
|
|
201
|
+
let runId: string | null
|
|
202
|
+
if (parsed.runId !== undefined) {
|
|
203
|
+
runId = resolveRunId(db, parsed.runId, 'vx why')
|
|
204
|
+
// An unknown id read as a known run missing the task (X-18).
|
|
205
|
+
if (runId === null) {
|
|
206
|
+
throw new UserError(
|
|
207
|
+
`vx why: no recorded run ${parsed.runId} (vx last --list shows recent runs)`,
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
} else runId = latestRunId(db, taskId)
|
|
195
211
|
|
|
196
212
|
if (runId === null) {
|
|
197
213
|
// Runs exist (resolveTarget passed) but predate run ids — fall back to
|
|
@@ -245,7 +261,10 @@ export async function whyCmd(args: readonly string[]): Promise<number> {
|
|
|
245
261
|
// The key moved and the diff says by what: the verdict names it, so
|
|
246
262
|
// an env-only change reads as one line, not "inputs differ" above a
|
|
247
263
|
// table to scan.
|
|
248
|
-
|
|
264
|
+
// The config component is kind and name `config`: it read "config config".
|
|
265
|
+
const moved = diff.entries.map((e) =>
|
|
266
|
+
e.name === e.kind ? e.kind : `${e.kind} ${printable(e.name)}`,
|
|
267
|
+
)
|
|
249
268
|
lines.push(
|
|
250
269
|
` verdict ${
|
|
251
270
|
why.hashChanged === true && moved.length > 0
|
|
@@ -153,7 +153,7 @@ async function collectWorkspaceInfo(
|
|
|
153
153
|
: path.resolve(cwd, opts.cacheDir)
|
|
154
154
|
const metas = await discoverProjects(await loadWorkspace(root, reads), plugins, cacheDir, warn)
|
|
155
155
|
const storeRoot = opts.cacheDir === undefined ? resolveStoreRoot(root, workspaceConfig) : null
|
|
156
|
-
const cache = Cache
|
|
156
|
+
const cache = new Cache(cacheDir, undefined, undefined, undefined, 'inspect', storeRoot)
|
|
157
157
|
let stats
|
|
158
158
|
let orphans
|
|
159
159
|
let flaky: FlakyTask[]
|