@vzn/vx 0.0.644 → 0.0.645
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/LICENSE +1 -1
- package/README.md +15 -23
- package/package.json +5 -5
- package/schemas/init.json +5 -0
- package/src/cache/archive.ts +12 -76
- package/src/cache/cache.ts +6 -26
- package/src/cache/index.ts +1 -2
- package/src/cache/layer.ts +5 -6
- package/src/cache/layered-cache.ts +106 -42
- package/src/cache/plugin-cache.ts +9 -14
- package/src/cache/remote-lane.ts +47 -18
- package/src/cache/scoped-cache.ts +3 -80
- package/src/cli/help.ts +4 -4
- package/src/cli/init.ts +121 -20
- package/src/cli/plan-format.ts +6 -2
- package/src/cli/plugin-commands.ts +3 -4
- package/src/cli/plugin-templates.ts +1 -1
- package/src/cli/run.ts +0 -1
- package/src/cli/upgrade.ts +1 -1
- package/src/config.ts +2 -4
- package/src/index.ts +1 -1
- package/src/orchestrator/affected-tasks.ts +0 -18
- package/src/orchestrator/index.ts +1 -0
- package/src/orchestrator/options.ts +0 -8
- package/src/orchestrator/plan.ts +7 -1
- package/src/orchestrator/plugin-host.ts +2 -5
- package/src/orchestrator/plugin.ts +11 -7
- package/src/orchestrator/prepare.ts +4 -47
- package/src/orchestrator/run-context.ts +39 -1
- package/src/orchestrator/run.ts +2 -0
- package/src/orchestrator/task-hash.ts +1 -3
- package/src/report/summary.ts +14 -2
- package/src/settings.ts +1 -7
- package/src/workspace/affected.ts +0 -39
- package/src/workspace/index.ts +0 -1
|
@@ -553,6 +553,44 @@ export function localBranchScope(
|
|
|
553
553
|
return branchCacheScope(repo, name)
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
+
/**
|
|
557
|
+
* The refs a remote reads, in order (2026-10-20): the run's own branch,
|
|
558
|
+
* then the branch it merges into, then the default branch, each once. On
|
|
559
|
+
* CI from its env (a GitHub pull request's head branch, a merge queue's
|
|
560
|
+
* queue ref, a GitLab pipeline's ref), else from git: the checked-out
|
|
561
|
+
* branch, then the default (`origin/HEAD`). A remote plugin keys or scopes
|
|
562
|
+
* its entries by them (`scope` on turboCache/nxCache); core keys nothing
|
|
563
|
+
* by them.
|
|
564
|
+
*/
|
|
565
|
+
export function cacheRefs(
|
|
566
|
+
workspaceRoot: string,
|
|
567
|
+
baseBranch: string | undefined,
|
|
568
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
569
|
+
): string[] {
|
|
570
|
+
const set = (v: string | undefined): string | undefined =>
|
|
571
|
+
v !== undefined && v.trim() !== '' ? v.trim() : undefined
|
|
572
|
+
const head = (b: string | undefined) => (b === undefined ? undefined : `refs/heads/${b}`)
|
|
573
|
+
let own: string | undefined
|
|
574
|
+
let base: string | undefined
|
|
575
|
+
if (env['GITHUB_ACTIONS'] === 'true') {
|
|
576
|
+
own = head(set(env['GITHUB_HEAD_REF'])) ?? set(env['GITHUB_REF'])
|
|
577
|
+
base = head(set(env['GITHUB_BASE_REF']))
|
|
578
|
+
const queue = /^refs\/heads\/gh-readonly-queue\/(.+)\/pr-\d+-[0-9a-f]+$/.exec(own ?? '')
|
|
579
|
+
if (queue !== null) base = head(queue[1])
|
|
580
|
+
} else if (env['GITLAB_CI'] === 'true') {
|
|
581
|
+
const tag = set(env['CI_COMMIT_TAG'])
|
|
582
|
+
own = tag !== undefined ? `refs/tags/${tag}` : head(set(env['CI_COMMIT_REF_NAME']))
|
|
583
|
+
base = head(set(env['CI_MERGE_REQUEST_TARGET_BRANCH_NAME']))
|
|
584
|
+
} else {
|
|
585
|
+
own = head(
|
|
586
|
+
(readHeadDirect(workspaceRoot) ?? captureGitContext(workspaceRoot, null, env)).branch ??
|
|
587
|
+
undefined,
|
|
588
|
+
)
|
|
589
|
+
}
|
|
590
|
+
const trunk = head(baseBranch ?? captureDefaultBranch(env, workspaceRoot) ?? undefined)
|
|
591
|
+
return [...new Set([own, base, trunk].filter((r): r is string => r !== undefined))]
|
|
592
|
+
}
|
|
593
|
+
|
|
556
594
|
/**
|
|
557
595
|
* The repository's path on its host (`owner/repo`; a GitLab subgroup's
|
|
558
596
|
* `group/sub/repo` whole, as `gitlab()` names it); undefined for a local path.
|
|
@@ -591,7 +629,7 @@ function gitConfigSections(workspaceRoot: string): Map<string, Map<string, strin
|
|
|
591
629
|
* The run's cache scope (owner, 2026-10-17): `VX_CACHE_SCOPE` (empty: none),
|
|
592
630
|
* else a plugin's (`setBranch`, `github()` on Actions; null: the plugin
|
|
593
631
|
* named the run trusted), else, with a cache plugin to share it, the
|
|
594
|
-
* branch's from git. Undefined:
|
|
632
|
+
* branch's from git. Undefined: no scope. It keys plugin entries only.
|
|
595
633
|
*/
|
|
596
634
|
export function resolveCacheScope(
|
|
597
635
|
workspaceRoot: string,
|
package/src/orchestrator/run.ts
CHANGED
|
@@ -810,6 +810,8 @@ async function runOnBus(
|
|
|
810
810
|
localWrite: policy.localWrite,
|
|
811
811
|
remote: remoteCacheEnabled && (policy.remoteRead || policy.remoteWrite),
|
|
812
812
|
traffic: prepared.localCache.traffic,
|
|
813
|
+
downloads: prepared.localCache.downloads,
|
|
814
|
+
uploads: prepared.localCache.uploads,
|
|
813
815
|
notDownloaded: () => deferredOutputs.pending().length,
|
|
814
816
|
},
|
|
815
817
|
concurrency,
|
|
@@ -97,9 +97,7 @@ export interface ComputeHashArgs {
|
|
|
97
97
|
*/
|
|
98
98
|
export async function computeTaskHash(args: ComputeHashArgs): Promise<string> {
|
|
99
99
|
if (isKeyless(args.node.config)) return keylessHash(args.node.id)
|
|
100
|
-
|
|
101
|
-
args.cache.noteKey?.(args.node.id, key)
|
|
102
|
-
return key
|
|
100
|
+
return taskHash(args)
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
async function taskHash(args: ComputeHashArgs): Promise<string> {
|
package/src/report/summary.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { isGroupTask } from '../graph/index.js'
|
|
|
10
10
|
import {
|
|
11
11
|
barWidth,
|
|
12
12
|
ERROR,
|
|
13
|
+
formatBytes,
|
|
13
14
|
formatElapsed,
|
|
14
15
|
gradientRule,
|
|
15
16
|
paint,
|
|
@@ -203,6 +204,9 @@ export interface RunContext {
|
|
|
203
204
|
readonly inFlight: number
|
|
204
205
|
readonly keys: ReadonlyMap<string, { uploading: number; failures: readonly string[] }>
|
|
205
206
|
}
|
|
207
|
+
/** Bytes the run's remote hits pulled, and its landed uploads pushed (live refs). */
|
|
208
|
+
downloads?: { readonly bytes: number }
|
|
209
|
+
uploads?: { readonly bytes: number }
|
|
206
210
|
/** Tasks whose outputs are still in the remote store. */
|
|
207
211
|
notDownloaded: () => number
|
|
208
212
|
}
|
|
@@ -335,9 +339,17 @@ export function formatSummarySection(
|
|
|
335
339
|
]
|
|
336
340
|
// The layer words are dim; only the counts carry colour (M, 2026-10-15).
|
|
337
341
|
if (local.length > 0) cacheParts.push(`${dim('local')} ${local.join(' ')}`)
|
|
342
|
+
// Each transfer count is followed by its bytes, dim: what the
|
|
343
|
+
// remote moved is the cost a hit or an upload paid.
|
|
344
|
+
const sized = (count: number, glyph: string, bytes: number | undefined): string[] =>
|
|
345
|
+
count === 0
|
|
346
|
+
? []
|
|
347
|
+
: bytes === undefined || bytes === 0
|
|
348
|
+
? n(count, glyph, REMOTE)
|
|
349
|
+
: [...n(count, glyph, REMOTE), dim(formatBytes(bytes))]
|
|
338
350
|
const remote = [
|
|
339
|
-
...
|
|
340
|
-
...
|
|
351
|
+
...sized(b.restoredRemote, '\u2193', layers.downloads?.bytes),
|
|
352
|
+
...sized(b.uploaded, '\u2191', layers.uploads?.bytes),
|
|
341
353
|
...n(b.remoteFailed, '\u2717', ERROR),
|
|
342
354
|
...n(b.uploading, '\u21e1', ACCENT),
|
|
343
355
|
]
|
package/src/settings.ts
CHANGED
|
@@ -127,7 +127,7 @@ export const SETTINGS: readonly Setting[] = [
|
|
|
127
127
|
path: 'cache.scope',
|
|
128
128
|
kind: { type: 'string' },
|
|
129
129
|
default: "the branch's, `<owner>/<repo>:<branch>`, with a remote cache off `baseBranch`",
|
|
130
|
-
doc: "
|
|
130
|
+
doc: "The branch scope plugin entries are keyed under (`'vznjs/vx:feat-x'`); task keys never carry it. Empty: no scope.",
|
|
131
131
|
config: false,
|
|
132
132
|
},
|
|
133
133
|
{
|
|
@@ -192,12 +192,6 @@ export const SETTINGS: readonly Setting[] = [
|
|
|
192
192
|
default: 'true',
|
|
193
193
|
doc: 'Keep a larger entry as its plain files, which a hit copies or clones out; off, as one `.tar.zst`.',
|
|
194
194
|
},
|
|
195
|
-
{
|
|
196
|
-
path: 'cache.store.verify',
|
|
197
|
-
kind: { type: 'enum', values: ['stat', 'hash', 'none'] },
|
|
198
|
-
default: 'stat',
|
|
199
|
-
doc: "What a hit on plain files checks first: each file's size and mtime, every byte, or nothing.",
|
|
200
|
-
},
|
|
201
195
|
{
|
|
202
196
|
path: 'cache.upload.failures',
|
|
203
197
|
kind: { type: 'enum', values: ['ci', 'local', 'always'] },
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
gitSpawnRefusal,
|
|
15
15
|
isExecutableMissing,
|
|
16
16
|
isInstalledPath,
|
|
17
|
-
isUserError,
|
|
18
17
|
notAWorkTree,
|
|
19
18
|
relPosix,
|
|
20
19
|
UserError,
|
|
@@ -741,44 +740,6 @@ function noHistoryRefusal(workspaceRoot: string): UserError | undefined {
|
|
|
741
740
|
return undefined
|
|
742
741
|
}
|
|
743
742
|
|
|
744
|
-
/**
|
|
745
|
-
* What a branch changed, for which of its tasks read its cache scope
|
|
746
|
-
* (owner, 2026-10-17): from `base` (a plugin's: a pull request's base
|
|
747
|
-
* commit), else from the merge base with the base branch. No base, or
|
|
748
|
-
* one git cannot resolve (a CI checkout at `fetch-depth: 1`), is no
|
|
749
|
-
* change: every task reads the default key, which costs hits, never
|
|
750
|
-
* correctness, since a key must still match.
|
|
751
|
-
*/
|
|
752
|
-
export async function branchChanges(
|
|
753
|
-
workspaceRoot: string,
|
|
754
|
-
base: string | undefined,
|
|
755
|
-
baseBranch: string | undefined,
|
|
756
|
-
projects: Promise<readonly ProjectMeta[]>,
|
|
757
|
-
/** The run's own enumeration, so the diff walks nothing a second time. */
|
|
758
|
-
walked: Pick<AffectedArgs, 'untracked' | 'links'> = {},
|
|
759
|
-
): Promise<AffectedChanges> {
|
|
760
|
-
const none: AffectedChanges = {
|
|
761
|
-
projects: new Set(),
|
|
762
|
-
changed: [],
|
|
763
|
-
paths: new Map(),
|
|
764
|
-
whole: new Set(),
|
|
765
|
-
}
|
|
766
|
-
const since = base ?? (await baseBranchRef(workspaceRoot, baseBranch))?.ref
|
|
767
|
-
if (since === undefined) return none
|
|
768
|
-
try {
|
|
769
|
-
return await affectedChanges({
|
|
770
|
-
workspaceRoot,
|
|
771
|
-
since,
|
|
772
|
-
projects,
|
|
773
|
-
configImports: false,
|
|
774
|
-
...walked,
|
|
775
|
-
})
|
|
776
|
-
} catch (err) {
|
|
777
|
-
if (!isUserError(err)) throw err
|
|
778
|
-
return none
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
|
|
782
743
|
/**
|
|
783
744
|
* The base branch as a ref: `origin/<name>`, else the local branch (a
|
|
784
745
|
* clone with no remote), and whether HEAD is on it. The name is the
|