@vzn/vx 0.0.540 → 0.0.542

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.540",
3
+ "version": "0.0.542",
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.540",
25
- "@vzn/vx-linux-arm64": "0.0.540",
26
- "@vzn/vx-darwin-x64": "0.0.540",
27
- "@vzn/vx-darwin-arm64": "0.0.540"
24
+ "@vzn/vx-linux-x64": "0.0.542",
25
+ "@vzn/vx-linux-arm64": "0.0.542",
26
+ "@vzn/vx-darwin-x64": "0.0.542",
27
+ "@vzn/vx-darwin-arm64": "0.0.542"
28
28
  },
29
29
  "dependencies": {
30
30
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -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' || storeRoot === undefined
806
- ? recorded
807
- : storeRoot === null
808
- ? undefined
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 { cliCacheDir, parseCacheDirFlag, warnToStderr } from './workspace-config.js'
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 directory instead`,
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 directory instead`,
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
- const dir = await cliCacheDir(root, parsed.cacheDir)
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 = parsed.dryRun === true ? Cache.inspect(dir) : new Cache(dir)
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/select.ts CHANGED
@@ -356,6 +356,14 @@ export async function resolveFilters(
356
356
  if (unmatched.length === 0 && emptyWalks.length > 0) {
357
357
  return { error: `no projects selected: ${emptyWalks.join('; ')}` }
358
358
  }
359
+ // Every pattern matched and an exclusion took them all back: "no
360
+ // projects matched filter(s): one, !one" read as a typo of `one`.
361
+ const negations = parsed.filter((f) => f.negate).map((f) => f.raw)
362
+ if (unmatched.length === 0 && negations.length > 0) {
363
+ return {
364
+ error: `no projects selected: ${negations.join(', ')} excluded every project the other filters matched`,
365
+ }
366
+ }
359
367
  // One line, not a warning per pattern and then an error saying the same:
360
368
  // the patterns are in the error, and the nearest project name is the
361
369
  // hint a typo needs.
@@ -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.inspect(cacheDir)
156
+ const cache = new Cache(cacheDir, undefined, undefined, undefined, 'inspect', storeRoot)
157
157
  let stats
158
158
  let orphans
159
159
  let flaky: FlakyTask[]