@vzn/vx 0.0.54 → 0.0.55

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.54",
3
+ "version": "0.0.55",
4
4
  "description": "An open, extensible monorepo task runner.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,10 +17,10 @@
17
17
  "node": ">=18"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@vzn/vx-linux-x64": "0.0.54",
21
- "@vzn/vx-linux-arm64": "0.0.54",
22
- "@vzn/vx-darwin-x64": "0.0.54",
23
- "@vzn/vx-darwin-arm64": "0.0.54"
20
+ "@vzn/vx-linux-x64": "0.0.55",
21
+ "@vzn/vx-linux-arm64": "0.0.55",
22
+ "@vzn/vx-darwin-x64": "0.0.55",
23
+ "@vzn/vx-darwin-arm64": "0.0.55"
24
24
  },
25
25
  "dependencies": {
26
26
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -635,6 +635,28 @@ function restampModes(trusted: Map<string, string>, workspaceRoot: string): void
635
635
  }
636
636
  }
637
637
 
638
+ /**
639
+ * `true` when the repository's config weakens the stat `git status` judges
640
+ * a file clean by: `core.trustctime` off, or `core.checkStat=minimal`
641
+ * (whole-second mtime and size only). Then a same-size rewrite that restores
642
+ * its mtime — `cp -p`, `tar -x`, a formatter that keeps times — reads clean
643
+ * and would keep its index OID, while the file hasher's own memo still keys
644
+ * on ctime and inode (A-6). Read from the `git var -l` the run already
645
+ * spawns; git's false spellings, the last value winning.
646
+ */
647
+ export function gitStatWeakened(gitVars: string): boolean {
648
+ const vars = gitVarList(gitVars)
649
+ const trustctime = vars.get('core.trustctime')?.trim().toLowerCase()
650
+ const checkStat = vars.get('core.checkstat')?.trim().toLowerCase()
651
+ return (
652
+ trustctime === 'false' ||
653
+ trustctime === 'no' ||
654
+ trustctime === 'off' ||
655
+ trustctime === '0' ||
656
+ checkStat === 'minimal'
657
+ )
658
+ }
659
+
638
660
  /** `true` when git may rewrite bytes for EVERY auto-detected text file. */
639
661
  export function autocrlfConverts(gitVars: string): boolean {
640
662
  const v = gitVarList(gitVars).get('core.autocrlf')?.trim().toLowerCase()
@@ -945,6 +967,9 @@ export async function startGitEnumeration(
945
967
  // Dropping the OID sends these back through the probe, where they correctly
946
968
  // fall out of the input set while unmaterialized.
947
969
  for (const rel of flagged) trusted.delete(rel)
970
+ // Under a weakened stat, `git status` vouches for nothing a same-size,
971
+ // time-keeping rewrite made: every file is hashed from disk instead.
972
+ if (vars !== null && vars.exitCode === 0 && gitStatWeakened(vars.stdout)) trusted.clear()
948
973
  // An index OID is only the file's content hash when git stores the worktree
949
974
  // bytes VERBATIM. Under a clean filter (`text`/`eol`/`ident`/`filter`/`working-tree-encoding`) the blob is a
950
975
  // DIFFERENT sequence of bytes — the LF-normalized form — while the task
@@ -42,6 +42,7 @@ export {
42
42
  gitPathspecs,
43
43
  parseCheckAttrOutput,
44
44
  autocrlfConverts,
45
+ gitStatWeakened,
45
46
  attributeFilesOutsideTree,
46
47
  type GitEnumeration,
47
48
  } from './git-inputs.js'
@@ -17,7 +17,8 @@ import {
17
17
  type ProjectMeta,
18
18
  } from '../workspace/index.js'
19
19
  import type { WorkspaceConfig } from '../config.js'
20
- import { Cache, noteSchemaReset } from '../cache/index.js'
20
+ import { Cache } from '../cache/index.js'
21
+ import { UserError } from '../util/index.js'
21
22
  import {
22
23
  buildPackageGraph,
23
24
  computeWorkspaceFingerprint,
@@ -245,8 +246,15 @@ export async function loadResolvedProjects(
245
246
  const metas = await listProjects(await loadWorkspace(workspaceRoot, reads))
246
247
  const { workspaceConfig, plugins } = await loadWorkspacePlugins(workspaceRoot, warn)
247
248
  const cacheDir = resolveCacheDir(workspaceRoot, workspaceConfig)
248
- const cache = new Cache(cacheDir, { read: true, write: true }, workspaceRoot)
249
- noteSchemaReset(cache, warn)
249
+ // Opened as `vx last` opens it: a reader makes no index where there is
250
+ // none and never resets an earlier schema's (C-5). One it cannot read
251
+ // serves nothing; the configs evaluate live.
252
+ let cache: Cache | undefined
253
+ try {
254
+ cache = Cache.inspect(cacheDir)
255
+ } catch (err) {
256
+ if (!(err instanceof UserError)) throw err
257
+ }
250
258
  try {
251
259
  const loaded = await loadProjects({
252
260
  workspaceRoot,
@@ -257,15 +265,18 @@ export async function loadResolvedProjects(
257
265
  seeds: opts.scope ?? 'all',
258
266
  closure: false,
259
267
  lock: null,
260
- evalCache: {
261
- store: cache,
262
- workspaceRoot,
263
- workspaceFingerprint: await computeWorkspaceFingerprint(workspaceRoot, reads),
264
- },
268
+ evalCache:
269
+ cache === undefined
270
+ ? undefined
271
+ : {
272
+ store: cache,
273
+ workspaceRoot,
274
+ workspaceFingerprint: await computeWorkspaceFingerprint(workspaceRoot, reads),
275
+ },
265
276
  warn,
266
277
  })
267
278
  return loaded.projects
268
279
  } finally {
269
- cache.close()
280
+ cache?.close()
270
281
  }
271
282
  }