@vzn/vx 0.0.380 → 0.0.382
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 +17 -12
- package/src/cache/config-evals.ts +6 -3
- package/src/cache/file-hashes.ts +8 -3
- package/src/cache/output-index.ts +13 -7
- package/src/cache/run-history.ts +11 -4
- package/src/cache/schema.ts +15 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vzn/vx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.382",
|
|
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.382",
|
|
25
|
+
"@vzn/vx-linux-arm64": "0.0.382",
|
|
26
|
+
"@vzn/vx-darwin-x64": "0.0.382",
|
|
27
|
+
"@vzn/vx-darwin-arm64": "0.0.382"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sandbox-runtime": "^0.0.76"
|
package/src/cache/cache.ts
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from 'node:fs'
|
|
39
39
|
import { readdir, rm, stat, unlink, writeFile } from 'node:fs/promises'
|
|
40
40
|
import path from 'node:path'
|
|
41
|
-
import { createTables } from './schema.js'
|
|
41
|
+
import { createTables, lazyStatement } from './schema.js'
|
|
42
42
|
import {
|
|
43
43
|
UserError,
|
|
44
44
|
formatBytes,
|
|
@@ -451,7 +451,6 @@ export class Cache implements CacheLayer {
|
|
|
451
451
|
private readonly upsertStdout: ReturnType<Database['prepare']>
|
|
452
452
|
private readonly deleteStdout: ReturnType<Database['prepare']>
|
|
453
453
|
private readonly entryExists: ReturnType<Database['prepare']>
|
|
454
|
-
private readonly bumpAccessed: ReturnType<Database['prepare']>
|
|
455
454
|
private readonly touched = new Set<string>()
|
|
456
455
|
private readonly insertEntryInput: ReturnType<Database['prepare']>
|
|
457
456
|
/** The per-file (mtime, size) → blob-OID memo behind `hashFile`. */
|
|
@@ -706,8 +705,10 @@ export class Cache implements CacheLayer {
|
|
|
706
705
|
|
|
707
706
|
createTables(this.db)
|
|
708
707
|
|
|
709
|
-
this.deleteEntryRow = this.db
|
|
710
|
-
this.insertEntry =
|
|
708
|
+
this.deleteEntryRow = lazyStatement(this.db, 'DELETE FROM entries WHERE hash = ?')
|
|
709
|
+
this.insertEntry = lazyStatement(
|
|
710
|
+
this.db,
|
|
711
|
+
`
|
|
711
712
|
INSERT INTO entries(hash, project, task, command, exit_code, duration_ms, size_bytes, created_at, accessed_at, cpu_ms, peak_rss_bytes)
|
|
712
713
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
713
714
|
ON CONFLICT(hash) DO UPDATE SET
|
|
@@ -720,25 +721,29 @@ export class Cache implements CacheLayer {
|
|
|
720
721
|
accessed_at = excluded.accessed_at,
|
|
721
722
|
cpu_ms = excluded.cpu_ms,
|
|
722
723
|
peak_rss_bytes = excluded.peak_rss_bytes
|
|
723
|
-
|
|
724
|
-
|
|
724
|
+
`,
|
|
725
|
+
)
|
|
726
|
+
this.upsertStdout = lazyStatement(
|
|
727
|
+
this.db,
|
|
725
728
|
'INSERT INTO entry_stdout(hash, stdout) VALUES (?, ?) ON CONFLICT(hash) DO UPDATE SET stdout = excluded.stdout',
|
|
726
729
|
)
|
|
727
|
-
this.deleteStdout = this.db
|
|
728
|
-
this.selectEntry = this.db
|
|
730
|
+
this.deleteStdout = lazyStatement(this.db, 'DELETE FROM entry_stdout WHERE hash = ?')
|
|
731
|
+
this.selectEntry = lazyStatement(this.db, `${SELECT_ENTRY} WHERE e.hash = ?`)
|
|
729
732
|
// `has` asks only whether the row is there, with no stdout joined. A
|
|
730
733
|
// column off the index, so the table row is still read and a corrupt
|
|
731
734
|
// table refuses here as it does on `get` (`SELECT 1` answers from the
|
|
732
735
|
// index alone).
|
|
733
|
-
this.entryExists = this.db
|
|
734
|
-
this.bumpAccessed = this.db.prepare('UPDATE entries SET accessed_at = ? WHERE hash = ?')
|
|
736
|
+
this.entryExists = lazyStatement(this.db, 'SELECT exit_code FROM entries WHERE hash = ?')
|
|
735
737
|
// INSERT OR IGNORE: re-saving the same hash (idempotent ingest /
|
|
736
738
|
// overlapping concurrent saves) leaves the existing rows untouched —
|
|
737
739
|
// identical inputs derive the identical hash, so the rows are too.
|
|
738
|
-
this.insertEntryInput =
|
|
740
|
+
this.insertEntryInput = lazyStatement(
|
|
741
|
+
this.db,
|
|
742
|
+
`
|
|
739
743
|
INSERT OR IGNORE INTO entry_inputs(entry_hash, kind, name, hash)
|
|
740
744
|
VALUES (?, ?, ?, ?)
|
|
741
|
-
|
|
745
|
+
`,
|
|
746
|
+
)
|
|
742
747
|
// The slices: each owns its statements over this handle and its table(s);
|
|
743
748
|
// the schema above is the one place every table is declared.
|
|
744
749
|
this.files = new FileHashStore(this.db, cacheDir, this.write, repoDir)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// Owns its statements over the store's handle; `Cache` delegates.
|
|
5
5
|
|
|
6
6
|
import type { Database, SQLQueryBindings } from 'bun:sqlite'
|
|
7
|
+
import { lazyStatement } from './schema.js'
|
|
7
8
|
|
|
8
9
|
export class ConfigEvalTable {
|
|
9
10
|
private readonly selectConfigEval: ReturnType<Database['prepare']>
|
|
@@ -18,11 +19,13 @@ export class ConfigEvalTable {
|
|
|
18
19
|
) {
|
|
19
20
|
this.read = policy.read
|
|
20
21
|
this.write = policy.write
|
|
21
|
-
this.selectConfigEval = this.db
|
|
22
|
-
this.insertConfigEval =
|
|
22
|
+
this.selectConfigEval = lazyStatement(this.db, 'SELECT json FROM config_evals WHERE key = ?')
|
|
23
|
+
this.insertConfigEval = lazyStatement(
|
|
24
|
+
this.db,
|
|
23
25
|
'INSERT OR REPLACE INTO config_evals(key, json, created_at) VALUES (?, ?, ?)',
|
|
24
26
|
)
|
|
25
|
-
this.upsertConfigClosure =
|
|
27
|
+
this.upsertConfigClosure = lazyStatement(
|
|
28
|
+
this.db,
|
|
26
29
|
'INSERT INTO config_closures(config_path, files_json, created_at) VALUES (?, ?, ?) ON CONFLICT(config_path) DO UPDATE SET files_json = excluded.files_json, created_at = excluded.created_at',
|
|
27
30
|
)
|
|
28
31
|
}
|
package/src/cache/file-hashes.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// the store's handle; `Cache` delegates.
|
|
8
8
|
|
|
9
9
|
import type { Database } from 'bun:sqlite'
|
|
10
|
+
import { lazyStatement } from './schema.js'
|
|
10
11
|
import { lstatSync, readlinkSync } from 'node:fs'
|
|
11
12
|
import path from 'node:path'
|
|
12
13
|
import { fileIdentity, repoFacts } from './git-inputs.js'
|
|
@@ -35,10 +36,13 @@ export class FileHashStore {
|
|
|
35
36
|
*/
|
|
36
37
|
private readonly repoDir?: string,
|
|
37
38
|
) {
|
|
38
|
-
this.selectFileHash =
|
|
39
|
+
this.selectFileHash = lazyStatement(
|
|
40
|
+
this.db,
|
|
39
41
|
'SELECT mtime_ms, size_bytes, ctime_ms, ino, content_hash FROM file_hashes WHERE path = ?',
|
|
40
42
|
)
|
|
41
|
-
this.upsertFileHash =
|
|
43
|
+
this.upsertFileHash = lazyStatement(
|
|
44
|
+
this.db,
|
|
45
|
+
`
|
|
42
46
|
INSERT INTO file_hashes(path, mtime_ms, size_bytes, ctime_ms, ino, content_hash, seen_at)
|
|
43
47
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
44
48
|
ON CONFLICT(path) DO UPDATE SET
|
|
@@ -48,7 +52,8 @@ export class FileHashStore {
|
|
|
48
52
|
ino = excluded.ino,
|
|
49
53
|
content_hash = excluded.content_hash,
|
|
50
54
|
seen_at = excluded.seen_at
|
|
51
|
-
|
|
55
|
+
`,
|
|
56
|
+
)
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
/**
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
const ABSENT_DIR_MTIME = -1
|
|
10
10
|
|
|
11
11
|
import type { Database, SQLQueryBindings } from 'bun:sqlite'
|
|
12
|
+
import { lazyStatement } from './schema.js'
|
|
12
13
|
import { lstatSync, statSync } from 'node:fs'
|
|
13
14
|
import { lstat, readdir } from 'node:fs/promises'
|
|
14
15
|
import path from 'node:path'
|
|
@@ -42,21 +43,26 @@ export class OutputIndex {
|
|
|
42
43
|
private readonly pendingStamps = new Map<string, Array<[string, number, number]>>()
|
|
43
44
|
|
|
44
45
|
constructor(private readonly db: Database) {
|
|
45
|
-
this.insertOutputFile =
|
|
46
|
+
this.insertOutputFile = lazyStatement(
|
|
47
|
+
this.db,
|
|
48
|
+
`
|
|
46
49
|
INSERT INTO output_files(entry_hash, path, size_bytes, mode, mtime_ms)
|
|
47
50
|
VALUES (?, ?, ?, ?, ?)
|
|
48
51
|
ON CONFLICT(entry_hash, path) DO UPDATE SET
|
|
49
52
|
size_bytes = excluded.size_bytes,
|
|
50
53
|
mode = excluded.mode,
|
|
51
54
|
mtime_ms = excluded.mtime_ms
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
+
`,
|
|
56
|
+
)
|
|
57
|
+
this.deleteOutputFiles = lazyStatement(this.db, 'DELETE FROM output_files WHERE entry_hash = ?')
|
|
58
|
+
this.insertOutputDir = lazyStatement(
|
|
59
|
+
this.db,
|
|
55
60
|
'INSERT INTO output_dirs(entry_hash, path, mtime_ms) VALUES (?, ?, ?)',
|
|
56
61
|
)
|
|
57
|
-
this.deleteOutputDirs = this.db
|
|
58
|
-
this.entryExists = this.db
|
|
59
|
-
this.stampOutputFile =
|
|
62
|
+
this.deleteOutputDirs = lazyStatement(this.db, 'DELETE FROM output_dirs WHERE entry_hash = ?')
|
|
63
|
+
this.entryExists = lazyStatement(this.db, 'SELECT 1 FROM entries WHERE hash = ?')
|
|
64
|
+
this.stampOutputFile = lazyStatement(
|
|
65
|
+
this.db,
|
|
60
66
|
'UPDATE output_files SET ino = ?, ctime_ms = ? WHERE entry_hash = ? AND path = ?',
|
|
61
67
|
)
|
|
62
68
|
}
|
package/src/cache/run-history.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// its statements over the store's handle; `Cache` delegates.
|
|
5
5
|
|
|
6
6
|
import type { Database, SQLQueryBindings } from 'bun:sqlite'
|
|
7
|
+
import { lazyStatement } from './schema.js'
|
|
7
8
|
import type { InvocationRecord, RunRecord } from './layer.js'
|
|
8
9
|
|
|
9
10
|
export class RunHistory {
|
|
@@ -15,7 +16,9 @@ export class RunHistory {
|
|
|
15
16
|
/** The store's salted value digest (L-4). */
|
|
16
17
|
private readonly digestValue: (value: string) => string,
|
|
17
18
|
) {
|
|
18
|
-
this.insertRun =
|
|
19
|
+
this.insertRun = lazyStatement(
|
|
20
|
+
this.db,
|
|
21
|
+
`
|
|
19
22
|
INSERT INTO runs(
|
|
20
23
|
hash, project, task, status, exit_code, duration_ms, forward_args,
|
|
21
24
|
started_at, ended_at,
|
|
@@ -24,8 +27,11 @@ export class RunHistory {
|
|
|
24
27
|
blocked_by, timed_out, sandbox_violations, not_ready
|
|
25
28
|
)
|
|
26
29
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
`,
|
|
31
|
+
)
|
|
32
|
+
this.insertInvocation = lazyStatement(
|
|
33
|
+
this.db,
|
|
34
|
+
`
|
|
29
35
|
INSERT INTO invocations(
|
|
30
36
|
run_id, command, requested_tasks, cache_policy, concurrency, flow,
|
|
31
37
|
started_at, ended_at, total_duration_ms,
|
|
@@ -36,7 +42,8 @@ export class RunHistory {
|
|
|
36
42
|
)
|
|
37
43
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
38
44
|
ON CONFLICT(run_id) DO NOTHING
|
|
39
|
-
|
|
45
|
+
`,
|
|
46
|
+
)
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
recordRun(run: RunRecord): void {
|
package/src/cache/schema.ts
CHANGED
|
@@ -3,7 +3,21 @@
|
|
|
3
3
|
// them lives in the store that owns the table (file-hashes, config-evals,
|
|
4
4
|
// output-index, history) or in cache.ts for `entries` and `entry_inputs`.
|
|
5
5
|
|
|
6
|
-
import type { Database } from 'bun:sqlite'
|
|
6
|
+
import type { Database, SQLQueryBindings } from 'bun:sqlite'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A statement prepared on its first `run` or `get`. A warm run executes few
|
|
10
|
+
* of the index's statements, and preparing every one at the open cost each
|
|
11
|
+
* run ~0.4 ms (2026-10-03).
|
|
12
|
+
*/
|
|
13
|
+
export function lazyStatement(db: Database, sql: string): ReturnType<Database['prepare']> {
|
|
14
|
+
let statement: ReturnType<Database['prepare']> | undefined
|
|
15
|
+
const prepared = (): ReturnType<Database['prepare']> => (statement ??= db.prepare(sql))
|
|
16
|
+
return {
|
|
17
|
+
run: (...params: SQLQueryBindings[]) => prepared().run(...params),
|
|
18
|
+
get: (...params: SQLQueryBindings[]) => prepared().get(...params),
|
|
19
|
+
} as unknown as ReturnType<Database['prepare']>
|
|
20
|
+
}
|
|
7
21
|
|
|
8
22
|
export function createTables(db: Database): void {
|
|
9
23
|
// Cached config evaluations (workspace/config-cache.ts): the validated
|