vouchington-tooling 0.11.0 → 0.11.2
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/README.md +17 -0
- package/dist/agent-blackboard/snapshot-cleanup-receipt.mjs +2 -0
- package/dist/agent-blackboard/snapshot-cleanup-resume.d.mts +1 -1
- package/dist/agent-blackboard/snapshot-cleanup-resume.mjs +3 -6
- package/dist/agent-harness-config/apply.d.mts +4 -0
- package/dist/agent-harness-config/apply.mjs +72 -0
- package/dist/agent-harness-config/cli.d.mts +10 -0
- package/dist/agent-harness-config/cli.mjs +100 -0
- package/dist/agent-harness-config/index.d.mts +4 -0
- package/dist/agent-harness-config/index.mjs +3 -0
- package/dist/agent-harness-config/merge-json.d.mts +5 -0
- package/dist/agent-harness-config/merge-json.mjs +62 -0
- package/dist/agent-harness-config/merge-toml.d.mts +6 -0
- package/dist/agent-harness-config/merge-toml.mjs +132 -0
- package/dist/agent-harness-config/paths.d.mts +3 -0
- package/dist/agent-harness-config/paths.mjs +117 -0
- package/dist/agent-harness-config/policy.d.mts +14 -0
- package/dist/agent-harness-config/policy.mjs +51 -0
- package/dist/agent-harness-config/prerequisites.d.mts +2 -0
- package/dist/agent-harness-config/prerequisites.mjs +67 -0
- package/dist/agent-harness-config/toml-value.d.mts +6 -0
- package/dist/agent-harness-config/toml-value.mjs +69 -0
- package/dist/agent-harness-config/types.d.mts +88 -0
- package/dist/agent-harness-config/types.mjs +1 -0
- package/dist/browser-session-runner/watchdog.mjs +1 -0
- package/dist/cli/index.mjs +9 -6
- package/dist/cli/parse.d.mts +3 -0
- package/dist/cli/parse.mjs +2 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +5 -0
- package/dist/gha-artifacts-cleanup/classify.mjs +1 -0
- package/dist/gha-post-review/claude-token.mjs +2 -0
- package/dist/gha-post-review/github.mjs +1 -0
- package/dist/gha-post-review/post.mjs +7 -1
- package/dist/gha-pr-checkpoint/codec.mjs +1 -0
- package/dist/gha-review-payload/diff.mjs +1 -0
- package/dist/gha-review-payload/payload.mjs +2 -0
- package/dist/gha-workspace-policy/shared.mjs +1 -0
- package/dist/http-link-pagination/index.mjs +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/pnpm-deploy/normalize.mjs +1 -0
- package/dist/pnpm-install/install-operations.d.mts +2 -1
- package/dist/pnpm-install/install-operations.mjs +16 -4
- package/dist/pnpm-install/metadata.d.mts +3 -3
- package/dist/pnpm-install/metadata.mjs +10 -24
- package/dist/pnpm-install/pending-builds.d.mts +6 -14
- package/dist/pnpm-install/pending-builds.mjs +23 -91
- package/dist/pnpm-install/pnpm-install-fake-pnpm.test-helpers.mjs +15 -1
- package/dist/pnpm-install/runner.mjs +27 -59
- package/dist/pnpm-install/transition.d.mts +2 -7
- package/dist/pnpm-install/transition.mjs +3 -11
- package/dist/runner-port-policy/index.mjs +2 -0
- package/dist/session-friction/log.mjs +1 -0
- package/dist/skill-discovery/manifest.mjs +2 -0
- package/dist/sql-ast/constraint-do-block.mjs +1 -0
- package/dist/sql-ast/drop-index.mjs +2 -0
- package/dist/vitest-blob-manifest/reports-cli.mjs +2 -0
- package/docs/agent-harness-config.md +134 -0
- package/package.json +8 -1
- package/dist/cli/commands/post-review.d.mts +0 -1
- package/dist/cli/commands/post-review.mjs +0 -4
- package/dist/cli/commands/stage-review-payload.d.mts +0 -1
- package/dist/cli/commands/stage-review-payload.mjs +0 -4
- package/dist/cli/commands/swift-semantic-equal.d.mts +0 -1
- package/dist/cli/commands/swift-semantic-equal.mjs +0 -4
|
@@ -47,7 +47,7 @@ function runtimePlatformIdentity() {
|
|
|
47
47
|
platform: process.platform,
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
export async function
|
|
50
|
+
export async function persistentMetadataFingerprintV5(runCapture) {
|
|
51
51
|
const workspaces = (await listWorkspaces(runCapture)).toSorted((left, right) => left.path.localeCompare(right.path));
|
|
52
52
|
const pnpmVersion = await runCapture(['--version']);
|
|
53
53
|
if (pnpmVersion.code !== 0)
|
|
@@ -73,16 +73,14 @@ export async function persistentMetadataFingerprintV4(runCapture) {
|
|
|
73
73
|
function validStamp(value) {
|
|
74
74
|
if (typeof value !== 'object' || value === null)
|
|
75
75
|
return false;
|
|
76
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish the candidate stamp type before complete field validation
|
|
76
77
|
const stamp = value;
|
|
77
|
-
return (stamp.version ===
|
|
78
|
+
return (stamp.version === 5 &&
|
|
78
79
|
typeof stamp.lastInvocationInstallScripts === 'boolean' &&
|
|
79
|
-
typeof stamp.
|
|
80
|
+
typeof stamp.scriptsEnabledInstallVerified === 'boolean' &&
|
|
80
81
|
typeof stamp.provenance === 'object' &&
|
|
81
82
|
stamp.provenance !== null &&
|
|
82
|
-
componentNames.every((name) => typeof stamp.provenance?.[name] === 'string')
|
|
83
|
-
(stamp.pendingDependencyBuilds === undefined ||
|
|
84
|
-
(Array.isArray(stamp.pendingDependencyBuilds) &&
|
|
85
|
-
stamp.pendingDependencyBuilds.every((id) => typeof id === 'string'))));
|
|
83
|
+
componentNames.every((name) => typeof stamp.provenance?.[name] === 'string'));
|
|
86
84
|
}
|
|
87
85
|
async function readPersistentMetadataState() {
|
|
88
86
|
try {
|
|
@@ -97,11 +95,7 @@ async function readPersistentMetadataState() {
|
|
|
97
95
|
: { kind: 'unsafe' };
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
|
-
async function
|
|
101
|
-
const state = await readPersistentMetadataState();
|
|
102
|
-
return state.kind === 'stamp' ? state.stamp : undefined;
|
|
103
|
-
}
|
|
104
|
-
export async function persistentMetadataStatusV4(provenance) {
|
|
98
|
+
export async function persistentMetadataStatusV5(provenance) {
|
|
105
99
|
const state = await readPersistentMetadataState();
|
|
106
100
|
if (state.kind === 'missing')
|
|
107
101
|
return { kind: 'absent' };
|
|
@@ -114,23 +108,15 @@ export async function persistentMetadataStatusV4(provenance) {
|
|
|
114
108
|
: {
|
|
115
109
|
kind: 'matching',
|
|
116
110
|
lastInvocationInstallScripts: stamp.lastInvocationInstallScripts,
|
|
117
|
-
|
|
118
|
-
scriptsEnabledInstallSucceeded: stamp.scriptsEnabledInstallSucceeded,
|
|
111
|
+
scriptsEnabledInstallVerified: stamp.scriptsEnabledInstallVerified,
|
|
119
112
|
};
|
|
120
113
|
}
|
|
121
|
-
export async function
|
|
122
|
-
const existing = await readPersistentMetadataStamp();
|
|
123
|
-
const existingMatches = existing && componentNames.every((name) => existing.provenance[name] === provenance[name]);
|
|
114
|
+
export async function writePersistentMetadataStampV5(provenance, installScripts, scriptsEnabledInstallVerified) {
|
|
124
115
|
const stamp = {
|
|
125
116
|
lastInvocationInstallScripts: installScripts,
|
|
126
|
-
pendingDependencyBuilds: (pendingDependencyBuilds ??
|
|
127
|
-
(existingMatches ? existing.pendingDependencyBuilds : undefined) ??
|
|
128
|
-
[]).toSorted(),
|
|
129
117
|
provenance,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Boolean(existingMatches && existing.scriptsEnabledInstallSucceeded)),
|
|
133
|
-
version: 4,
|
|
118
|
+
scriptsEnabledInstallVerified,
|
|
119
|
+
version: 5,
|
|
134
120
|
};
|
|
135
121
|
const stampPath = persistentMetadataStampPath();
|
|
136
122
|
const directory = path.dirname(stampPath);
|
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
export type
|
|
2
|
-
kind: '
|
|
3
|
-
ids: Set<string>;
|
|
1
|
+
export type PendingBuildState = {
|
|
2
|
+
kind: 'clear';
|
|
4
3
|
} | {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type PendingBuildDelta = {
|
|
8
|
-
kind: 'unknown';
|
|
4
|
+
ids: string[];
|
|
5
|
+
kind: 'pending';
|
|
9
6
|
} | {
|
|
10
|
-
kind: '
|
|
11
|
-
dependencyIds: string[];
|
|
12
|
-
workspaceIds: string[];
|
|
7
|
+
kind: 'unknown';
|
|
13
8
|
};
|
|
14
|
-
export declare function pendingBuilds(): Promise<
|
|
9
|
+
export declare function pendingBuilds(): Promise<PendingBuildState>;
|
|
15
10
|
export declare function buildLedgersAllowNativeRepair(): Promise<boolean>;
|
|
16
|
-
export declare function validDependencyBuildIds(ids: [string, ...string[]]): Promise<[string, ...string[]] | undefined>;
|
|
17
|
-
export declare function clearPendingDependencyBuilds(ids: string[]): Promise<boolean>;
|
|
18
|
-
export declare function pendingBuildDelta(before: PendingBuilds, after: PendingBuilds): Promise<PendingBuildDelta>;
|
|
@@ -1,104 +1,36 @@
|
|
|
1
|
-
import { readFile
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { parse
|
|
4
|
-
|
|
5
|
-
try {
|
|
6
|
-
const value = parse(await readFile(path.join(process.cwd(), 'node_modules', '.modules.yaml'), 'utf8'));
|
|
7
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
8
|
-
return { kind: 'unknown' };
|
|
9
|
-
const pending = value.pendingBuilds ?? [];
|
|
10
|
-
if (!Array.isArray(pending) || !pending.every((id) => typeof id === 'string'))
|
|
11
|
-
return { kind: 'unknown' };
|
|
12
|
-
return { kind: 'known', ids: new Set(pending) };
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return { kind: 'unknown' };
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export async function buildLedgersAllowNativeRepair() {
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
async function buildLedgers() {
|
|
19
5
|
try {
|
|
20
6
|
const value = parse(await readFile(path.join(process.cwd(), 'node_modules', '.modules.yaml'), 'utf8'));
|
|
21
7
|
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
22
|
-
return false;
|
|
23
|
-
const record = value;
|
|
24
|
-
const ignored = record.ignoredBuilds;
|
|
25
|
-
const pending = record.pendingBuilds ?? [];
|
|
26
|
-
return (Array.isArray(ignored) &&
|
|
27
|
-
ignored.length === 0 &&
|
|
28
|
-
Array.isArray(pending) &&
|
|
29
|
-
pending.length === 0);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
async function lockfileDependencyIds() {
|
|
36
|
-
try {
|
|
37
|
-
const lockfile = parse(await readFile(path.join(process.cwd(), 'pnpm-lock.yaml'), 'utf8'));
|
|
38
|
-
if (typeof lockfile !== 'object' || lockfile === null || !('packages' in lockfile))
|
|
39
8
|
return undefined;
|
|
40
|
-
const
|
|
41
|
-
|
|
9
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- validate the parsed YAML object before reading its fields
|
|
10
|
+
const record = value;
|
|
11
|
+
const ignored = Object.hasOwn(record, 'ignoredBuilds') ? record.ignoredBuilds : undefined;
|
|
12
|
+
const pending = Object.hasOwn(record, 'pendingBuilds') ? record.pendingBuilds : [];
|
|
13
|
+
if ((ignored !== undefined &&
|
|
14
|
+
(!Array.isArray(ignored) || !ignored.every((id) => typeof id === 'string'))) ||
|
|
15
|
+
!Array.isArray(pending) ||
|
|
16
|
+
!pending.every((id) => typeof id === 'string'))
|
|
42
17
|
return undefined;
|
|
43
|
-
return
|
|
18
|
+
return {
|
|
19
|
+
ignoredBuilds: ignored,
|
|
20
|
+
pendingBuilds: pending.length === 0 ? { kind: 'clear' } : { ids: pending.toSorted(), kind: 'pending' },
|
|
21
|
+
};
|
|
44
22
|
}
|
|
45
23
|
catch {
|
|
46
24
|
return undefined;
|
|
47
25
|
}
|
|
48
26
|
}
|
|
49
|
-
export async function
|
|
50
|
-
|
|
51
|
-
if (!packages || !ids.every((id) => packages.has(id)))
|
|
52
|
-
return undefined;
|
|
53
|
-
const [first, ...remaining] = ids.toSorted();
|
|
54
|
-
return [first, ...remaining];
|
|
55
|
-
}
|
|
56
|
-
export async function clearPendingDependencyBuilds(ids) {
|
|
57
|
-
const filename = path.join(process.cwd(), 'node_modules', '.modules.yaml');
|
|
58
|
-
try {
|
|
59
|
-
const value = parse(await readFile(filename, 'utf8'));
|
|
60
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
61
|
-
return false;
|
|
62
|
-
const record = value;
|
|
63
|
-
if (!Array.isArray(record.pendingBuilds) ||
|
|
64
|
-
!record.pendingBuilds.every((id) => typeof id === 'string'))
|
|
65
|
-
return false;
|
|
66
|
-
const ignored = record.ignoredBuilds ?? [];
|
|
67
|
-
if (!Array.isArray(ignored) ||
|
|
68
|
-
!ignored.every((id) => typeof id === 'string') ||
|
|
69
|
-
ids.some((id) => ignored.includes(id)))
|
|
70
|
-
return false;
|
|
71
|
-
record.pendingBuilds = record.pendingBuilds.filter((id) => !ids.includes(id));
|
|
72
|
-
const temporary = `${filename}.${process.pid}.tmp`;
|
|
73
|
-
try {
|
|
74
|
-
await writeFile(temporary, stringify(record));
|
|
75
|
-
await rename(temporary, filename);
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
await rm(temporary, { force: true });
|
|
79
|
-
}
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
27
|
+
export async function pendingBuilds() {
|
|
28
|
+
return (await buildLedgers())?.pendingBuilds ?? { kind: 'unknown' };
|
|
85
29
|
}
|
|
86
|
-
export async function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const dependencyIds = [];
|
|
93
|
-
const workspaceIds = [];
|
|
94
|
-
for (const id of after.ids) {
|
|
95
|
-
if (before.ids.has(id))
|
|
96
|
-
continue;
|
|
97
|
-
(packages.has(id) ? dependencyIds : workspaceIds).push(id);
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
kind: 'known',
|
|
101
|
-
dependencyIds: dependencyIds.toSorted(),
|
|
102
|
-
workspaceIds: workspaceIds.toSorted(),
|
|
103
|
-
};
|
|
30
|
+
export async function buildLedgersAllowNativeRepair() {
|
|
31
|
+
const ledgers = await buildLedgers();
|
|
32
|
+
return (ledgers !== undefined &&
|
|
33
|
+
ledgers.ignoredBuilds !== undefined &&
|
|
34
|
+
ledgers.ignoredBuilds.length === 0 &&
|
|
35
|
+
ledgers.pendingBuilds.kind === 'clear');
|
|
104
36
|
}
|
|
@@ -29,18 +29,32 @@ if [ "\${PNPM_FAIL_RELEASE_AGE_CALL:-0}" = "$calls" ]; then
|
|
|
29
29
|
exit 1
|
|
30
30
|
fi
|
|
31
31
|
if [ -n "\${PNPM_SLEEP_SECONDS:-}" ]; then sleep "$PNPM_SLEEP_SECONDS"; fi
|
|
32
|
-
if [
|
|
32
|
+
if [ "\${PNPM_INVALID_PENDING_BUILDS:-0}" = 1 ]; then
|
|
33
|
+
mkdir -p "$PNPM_NODE_MODULES"
|
|
34
|
+
printf 'pendingBuilds: invalid\n' > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
35
|
+
elif [ -n "\${PNPM_PENDING_BUILDS:-}" ]; then
|
|
33
36
|
mkdir -p "$PNPM_NODE_MODULES"
|
|
34
37
|
printf 'pendingBuilds: [%s]\\n' "$PNPM_PENDING_BUILDS" > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
38
|
+
elif [ ! -f "$PNPM_NODE_MODULES/.modules.yaml" ]; then
|
|
39
|
+
mkdir -p "$PNPM_NODE_MODULES"
|
|
40
|
+
printf 'pendingBuilds: []\\n' > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
35
41
|
fi
|
|
36
42
|
case " $* " in
|
|
37
43
|
*' rebuild '*)
|
|
44
|
+
if [ "\${PNPM_REPAIR_NATIVE_ON_REBUILD:-0}" = 1 ]; then
|
|
45
|
+
cp "$PNPM_NATIVE_REPLACEMENT" "$PNPM_NATIVE_ADDON"
|
|
46
|
+
fi
|
|
38
47
|
if [ "\${PNPM_REBUILD_INVALID_LEDGER:-0}" = 1 ]; then
|
|
39
48
|
printf 'pendingBuilds: invalid\n' > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
49
|
+
else
|
|
50
|
+
printf 'pendingBuilds: []\n' > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
40
51
|
fi
|
|
41
52
|
if [ "\${PNPM_REBUILD_BREAK_LINK:-0}" = 1 ]; then rm -f "$PNPM_DEPENDENCY_LINK"; fi
|
|
42
53
|
;;
|
|
43
54
|
*' --force '*)
|
|
55
|
+
if [ -z "\${PNPM_PENDING_BUILDS:-}" ]; then
|
|
56
|
+
printf 'pendingBuilds: []\n' > "$PNPM_NODE_MODULES/.modules.yaml"
|
|
57
|
+
fi
|
|
44
58
|
if [ "\${PNPM_DELETE_NATIVE:-0}" = 1 ]; then
|
|
45
59
|
rm -f "$PNPM_NATIVE_ADDON"
|
|
46
60
|
elif [ "\${PNPM_REPAIR_NATIVE:-0}" = 1 ]; then
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { persistentDependencyTreeIsCold,
|
|
1
|
+
import { persistentDependencyTreeIsCold, persistentMetadataFingerprintV5, persistentMetadataStatusV5, writePersistentMetadataStampV5, } from './metadata.mjs';
|
|
2
2
|
import { runPnpm } from './exec.mjs';
|
|
3
3
|
import { mismatchedNativeBinaries } from './native-health.mjs';
|
|
4
4
|
// oxfmt-ignore
|
|
5
|
-
import {
|
|
5
|
+
import { pendingBuilds } from './pending-builds.mjs';
|
|
6
6
|
// oxfmt-ignore
|
|
7
|
-
import { install, reconcileOrFail, repairIsolatedNativeMismatch, withScriptPolicy } from './install-operations.mjs';
|
|
7
|
+
import { finalizePendingBuilds, install, reconcileOrFail, repairIsolatedNativeMismatch, withScriptPolicy } from './install-operations.mjs';
|
|
8
8
|
// oxfmt-ignore
|
|
9
9
|
import { baseInstallArgs, findWorkspaceLinkMismatches, logWorkspaceLinkMismatches } from './support.mjs';
|
|
10
10
|
import { persistentInstallTransition, persistentProvenanceDiagnostic } from './transition.mjs';
|
|
@@ -14,33 +14,30 @@ async function persistent(options) {
|
|
|
14
14
|
if (options.ephemeralWorkspaces.trim())
|
|
15
15
|
fail('ephemeral-workspaces is only valid for ephemeral runners');
|
|
16
16
|
const runCapture = (args) => runPnpm(args, options, true);
|
|
17
|
-
const fingerprint = await
|
|
18
|
-
const provenance = await
|
|
17
|
+
const fingerprint = await persistentMetadataFingerprintV5(runCapture);
|
|
18
|
+
const provenance = await persistentMetadataStatusV5(fingerprint);
|
|
19
|
+
const pendingBefore = await pendingBuilds();
|
|
19
20
|
const mismatchedNatives = await mismatchedNativeBinaries();
|
|
20
21
|
const nativesMatch = mismatchedNatives.length === 0;
|
|
21
22
|
const repairedNativeMismatch = !nativesMatch &&
|
|
22
23
|
provenance.kind === 'matching' &&
|
|
23
24
|
(await repairIsolatedNativeMismatch(options, runCapture, mismatchedNatives));
|
|
24
25
|
if (repairedNativeMismatch) {
|
|
26
|
+
const pendingAfterRepair = await finalizePendingBuilds(options, runCapture, 'native health reconciliation');
|
|
25
27
|
console.warn('persistent optional native binaries do not match this runtime; reconciled');
|
|
26
28
|
console.warn(persistentProvenanceDiagnostic(provenance, options.installScripts, nativesMatch, {
|
|
27
29
|
action: 'reconcile',
|
|
28
30
|
reason: 'native-health-mismatch',
|
|
29
31
|
}));
|
|
30
|
-
await
|
|
32
|
+
await writePersistentMetadataStampV5(fingerprint, options.installScripts, options.installScripts || persistentStampRemainsVerified(provenance, pendingAfterRepair));
|
|
31
33
|
return 'persistent native health reconciled';
|
|
32
34
|
}
|
|
33
35
|
const provisionalTransition = persistentInstallTransition(provenance, options.installScripts);
|
|
34
|
-
|
|
35
|
-
?
|
|
36
|
-
:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (!ids)
|
|
40
|
-
transition = { action: 'upgrade-scripts', reason: 'invalid-pending-dependency-builds' };
|
|
41
|
-
else
|
|
42
|
-
transition = { ...transition, pendingDependencyBuilds: ids };
|
|
43
|
-
}
|
|
36
|
+
const transition = !nativesMatch
|
|
37
|
+
? { action: 'reconcile', reason: 'native-health-mismatch' }
|
|
38
|
+
: provenance.kind !== 'matching' || pendingBefore.kind === 'clear'
|
|
39
|
+
? provisionalTransition
|
|
40
|
+
: { action: 'reconcile', reason: 'pending-build-ledger-unverified' };
|
|
44
41
|
const provenanceOk = provenance.kind === 'matching' && transition.action !== 'reconcile' && nativesMatch;
|
|
45
42
|
const cold = !provenanceOk && (await persistentDependencyTreeIsCold());
|
|
46
43
|
if (!provenanceOk && !cold) {
|
|
@@ -51,54 +48,19 @@ async function persistent(options) {
|
|
|
51
48
|
console.warn(provenance.kind === 'matching' && !nativesMatch
|
|
52
49
|
? 'persistent optional native binaries do not match this runtime; reconciling'
|
|
53
50
|
: 'persistent dependency metadata provenance is missing or changed; reconciling');
|
|
54
|
-
await reconcileOrFail(options
|
|
55
|
-
await
|
|
51
|
+
await reconcileOrFail(options);
|
|
52
|
+
const pendingAfterReconcile = await finalizePendingBuilds(options, runCapture, 'persistent reconciliation');
|
|
53
|
+
await writePersistentMetadataStampV5(fingerprint, options.installScripts, options.installScripts || persistentStampRemainsVerified(provenance, pendingAfterReconcile));
|
|
56
54
|
return 'persistent metadata reconciled';
|
|
57
55
|
}
|
|
58
56
|
if (provenance.kind === 'absent')
|
|
59
57
|
console.warn('persistent dependency tree is absent; installing cold');
|
|
60
|
-
|
|
61
|
-
await install(withScriptPolicy([...baseInstallArgs], transition.action.startsWith('upgrade-') ? false : options.installScripts), options, 'ordinary persistent install');
|
|
58
|
+
await install(withScriptPolicy([...baseInstallArgs], options.installScripts), options, 'ordinary persistent install');
|
|
62
59
|
const stale = await findWorkspaceLinkMismatches(runCapture);
|
|
63
60
|
if (stale.length === 0) {
|
|
64
|
-
|
|
65
|
-
const pendingDependencyBuilds = transition.action === 'upgrade-dependencies'
|
|
66
|
-
? transition.pendingDependencyBuilds
|
|
67
|
-
: undefined;
|
|
68
|
-
const rebuild = pendingDependencyBuilds === undefined
|
|
69
|
-
? ['rebuild', '--pending', '--recursive']
|
|
70
|
-
: ['rebuild', '--recursive', '--', ...pendingDependencyBuilds];
|
|
71
|
-
await install(rebuild, options, 'pending scripts rebuild');
|
|
72
|
-
const rebuiltStale = await findWorkspaceLinkMismatches(runCapture);
|
|
73
|
-
if (rebuiltStale.length > 0) {
|
|
74
|
-
logWorkspaceLinkMismatches(rebuiltStale);
|
|
75
|
-
await reconcileOrFail(options, runCapture);
|
|
76
|
-
console.warn(persistentProvenanceDiagnostic(provenance, options.installScripts, nativesMatch, {
|
|
77
|
-
action: 'reconcile',
|
|
78
|
-
reason: 'workspace-links-stale-after-rebuild',
|
|
79
|
-
}));
|
|
80
|
-
await writePersistentMetadataStampV4(fingerprint, options.installScripts, true, []);
|
|
81
|
-
return 'persistent reconciled';
|
|
82
|
-
}
|
|
83
|
-
if (pendingDependencyBuilds !== undefined &&
|
|
84
|
-
!(await clearPendingDependencyBuilds(pendingDependencyBuilds)))
|
|
85
|
-
fail('dependency rebuild completed but pending build ledger could not be updated safely');
|
|
86
|
-
}
|
|
61
|
+
const pendingAfterInstall = await finalizePendingBuilds(options, runCapture, 'persistent install');
|
|
87
62
|
console.warn(persistentProvenanceDiagnostic(provenance, options.installScripts, nativesMatch, transition));
|
|
88
|
-
|
|
89
|
-
const delta = pendingBefore && pendingAfter
|
|
90
|
-
? await pendingBuildDelta(pendingBefore, pendingAfter)
|
|
91
|
-
: undefined;
|
|
92
|
-
const unsafePending = delta?.kind === 'unknown' || Boolean(delta?.workspaceIds.length);
|
|
93
|
-
const pendingDependencyBuilds = transition.action.startsWith('upgrade-') || unsafePending
|
|
94
|
-
? []
|
|
95
|
-
: [
|
|
96
|
-
...new Set([
|
|
97
|
-
...(provenance.kind === 'matching' ? provenance.pendingDependencyBuilds : []),
|
|
98
|
-
...(delta?.kind === 'known' ? delta.dependencyIds : []),
|
|
99
|
-
]),
|
|
100
|
-
].toSorted();
|
|
101
|
-
await writePersistentMetadataStampV4(fingerprint, options.installScripts, unsafePending, pendingDependencyBuilds);
|
|
63
|
+
await writePersistentMetadataStampV5(fingerprint, options.installScripts, options.installScripts || persistentStampRemainsVerified(provenance, pendingAfterInstall));
|
|
102
64
|
return provenance.kind === 'absent' ? 'persistent cold' : 'persistent ordinary';
|
|
103
65
|
}
|
|
104
66
|
logWorkspaceLinkMismatches(stale);
|
|
@@ -106,10 +68,16 @@ async function persistent(options) {
|
|
|
106
68
|
action: 'reconcile',
|
|
107
69
|
reason: 'workspace-links-stale',
|
|
108
70
|
}));
|
|
109
|
-
await reconcileOrFail(options
|
|
110
|
-
await
|
|
71
|
+
await reconcileOrFail(options);
|
|
72
|
+
const pendingAfterReconcile = await finalizePendingBuilds(options, runCapture, 'persistent reconciliation');
|
|
73
|
+
await writePersistentMetadataStampV5(fingerprint, options.installScripts, options.installScripts || persistentStampRemainsVerified(provenance, pendingAfterReconcile));
|
|
111
74
|
return 'persistent reconciled';
|
|
112
75
|
}
|
|
76
|
+
function persistentStampRemainsVerified(provenance, pending) {
|
|
77
|
+
return (provenance.kind === 'matching' &&
|
|
78
|
+
provenance.scriptsEnabledInstallVerified &&
|
|
79
|
+
pending.kind === 'clear');
|
|
80
|
+
}
|
|
113
81
|
function isUnbracedPathClosureSelector(selector) {
|
|
114
82
|
return /^\.{0,2}\//.test(selector) && selector.endsWith('...') && !selector.startsWith('{');
|
|
115
83
|
}
|
|
@@ -6,17 +6,12 @@ export type ProvenanceStatus = {
|
|
|
6
6
|
} | {
|
|
7
7
|
kind: 'matching';
|
|
8
8
|
lastInvocationInstallScripts: boolean;
|
|
9
|
-
|
|
10
|
-
scriptsEnabledInstallSucceeded: boolean;
|
|
9
|
+
scriptsEnabledInstallVerified: boolean;
|
|
11
10
|
} | {
|
|
12
11
|
kind: 'unsafe';
|
|
13
12
|
};
|
|
14
13
|
export type PersistentInstallTransition = {
|
|
15
|
-
action: 'ordinary' | 'reconcile'
|
|
16
|
-
reason: string;
|
|
17
|
-
} | {
|
|
18
|
-
action: 'upgrade-dependencies';
|
|
19
|
-
pendingDependencyBuilds: [string, ...string[]];
|
|
14
|
+
action: 'ordinary' | 'reconcile';
|
|
20
15
|
reason: string;
|
|
21
16
|
};
|
|
22
17
|
export declare function persistentInstallTransition(provenance: ProvenanceStatus, installScripts: boolean): PersistentInstallTransition;
|
|
@@ -2,15 +2,8 @@
|
|
|
2
2
|
// evidence that this structural tree has already completed a scripts-enabled install.
|
|
3
3
|
export function persistentInstallTransition(provenance, installScripts) {
|
|
4
4
|
if (provenance.kind === 'matching') {
|
|
5
|
-
if (installScripts && !provenance.
|
|
6
|
-
return { action: '
|
|
7
|
-
const [firstPendingDependencyBuild, ...remainingPendingDependencyBuilds] = provenance.pendingDependencyBuilds;
|
|
8
|
-
if (installScripts && firstPendingDependencyBuild !== undefined)
|
|
9
|
-
return {
|
|
10
|
-
action: 'upgrade-dependencies',
|
|
11
|
-
pendingDependencyBuilds: [firstPendingDependencyBuild, ...remainingPendingDependencyBuilds],
|
|
12
|
-
reason: 'pending-dependency-rebuild',
|
|
13
|
-
};
|
|
5
|
+
if (installScripts && !provenance.scriptsEnabledInstallVerified)
|
|
6
|
+
return { action: 'reconcile', reason: 'scripts-enabled-install-unverified' };
|
|
14
7
|
return { action: 'ordinary', reason: 'matching-structural-provenance' };
|
|
15
8
|
}
|
|
16
9
|
if (provenance.kind === 'absent')
|
|
@@ -26,9 +19,8 @@ export function persistentProvenanceDiagnostic(provenance, installScripts, nativ
|
|
|
26
19
|
changedComponents: provenance.kind === 'changed' ? provenance.components : [],
|
|
27
20
|
event: 'pnpm-install-persistent-provenance',
|
|
28
21
|
installScripts,
|
|
29
|
-
|
|
22
|
+
scriptsEnabledInstallVerified: provenance.kind === 'matching' ? provenance.scriptsEnabledInstallVerified : false,
|
|
30
23
|
lastInvocationInstallScripts: provenance.kind === 'matching' ? provenance.lastInvocationInstallScripts : null,
|
|
31
|
-
pendingDependencyBuildCount: provenance.kind === 'matching' ? provenance.pendingDependencyBuilds.length : 0,
|
|
32
24
|
nativeBinariesMatchRuntime,
|
|
33
25
|
reason: transition.reason,
|
|
34
26
|
state: provenance.kind,
|
|
@@ -33,6 +33,7 @@ export function validateRunnerPortPolicy(parsedPolicy, policyUrl) {
|
|
|
33
33
|
if (typeof parsedPolicy !== 'object' || parsedPolicy === null || Array.isArray(parsedPolicy)) {
|
|
34
34
|
throwInvalidPolicy(policyUrl);
|
|
35
35
|
}
|
|
36
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish a record view after validating the untrusted policy object
|
|
36
37
|
const policy = parsedPolicy;
|
|
37
38
|
const requiredKeys = [
|
|
38
39
|
'reservedPortStart',
|
|
@@ -45,6 +46,7 @@ export function validateRunnerPortPolicy(parsedPolicy, policyUrl) {
|
|
|
45
46
|
requiredKeys.some((key) => !Number.isInteger(policy[key]))) {
|
|
46
47
|
throwInvalidPolicy(policyUrl);
|
|
47
48
|
}
|
|
49
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- retain the validated policy type after the complete key and value checks
|
|
48
50
|
const validatedPolicy = policy;
|
|
49
51
|
const { reservedPortStart: start, reservedPortEnd: end, portsPerRunner, minimumRunnerSlot, maximumRunnerSlot, } = validatedPolicy;
|
|
50
52
|
if (start < 1 ||
|
|
@@ -30,6 +30,7 @@ function logPath(sessionId, directory) {
|
|
|
30
30
|
function validEvent(value) {
|
|
31
31
|
if (!value || typeof value !== 'object')
|
|
32
32
|
return false;
|
|
33
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish a record view after the runtime object check
|
|
33
34
|
const record = value;
|
|
34
35
|
return ((record.kind === 'sandbox-escalation' || record.kind === 'sandbox-failure') &&
|
|
35
36
|
isSafeAuditText(record.timestamp) &&
|
|
@@ -71,12 +71,14 @@ async function validateManifestEntries(root, entries) {
|
|
|
71
71
|
function isManifest(value) {
|
|
72
72
|
if (value === null || typeof value !== 'object')
|
|
73
73
|
return false;
|
|
74
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish the candidate schema type after the runtime object check
|
|
74
75
|
const manifest = value;
|
|
75
76
|
return manifest.version === 1 && Array.isArray(manifest.skills) && manifest.skills.every(isEntry);
|
|
76
77
|
}
|
|
77
78
|
function isEntry(value) {
|
|
78
79
|
if (value === null || typeof value !== 'object')
|
|
79
80
|
return false;
|
|
81
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish the candidate schema type after the runtime object check
|
|
80
82
|
const entry = value;
|
|
81
83
|
return ([entry.name, entry.plugin, entry.pluginVersion, entry.path].every((field) => typeof field === 'string' && field.length > 0) &&
|
|
82
84
|
(entry.prerequisites === undefined ||
|
|
@@ -33,6 +33,7 @@ export function processAlterTableStmt(statement, baseOffset, result, trackConstr
|
|
|
33
33
|
if (!constraint)
|
|
34
34
|
continue;
|
|
35
35
|
if (constraint.contype === 'CONSTR_FOREIGN') {
|
|
36
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- isolate the generated AST type escape at the foreign-key adapter boundary
|
|
36
37
|
const constraintRecord = constraint;
|
|
37
38
|
result.foreignKeys.push(foreignKeyFromConstraint(constraintRecord, tableName, fkAttrNames(constraintRecord), baseOffset));
|
|
38
39
|
}
|
|
@@ -9,6 +9,7 @@ export function extractDropIndexMetadata(content) {
|
|
|
9
9
|
if (!node || !('DropStmt' in node) || node.DropStmt.removeType !== 'OBJECT_INDEX')
|
|
10
10
|
continue;
|
|
11
11
|
for (const object of node.DropStmt.objects ?? []) {
|
|
12
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish an unknown boundary before runtime shape validation
|
|
12
13
|
const objectValue = object;
|
|
13
14
|
const items = isRecord(objectValue) && isRecord(objectValue['List'])
|
|
14
15
|
? objectValue['List']['items']
|
|
@@ -16,6 +17,7 @@ export function extractDropIndexMetadata(content) {
|
|
|
16
17
|
if (!Array.isArray(items))
|
|
17
18
|
continue;
|
|
18
19
|
const names = items.flatMap((item) => {
|
|
20
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish an unknown boundary before runtime shape validation
|
|
19
21
|
const itemValue = item;
|
|
20
22
|
const value = isRecord(itemValue) && isRecord(itemValue['String'])
|
|
21
23
|
? itemValue['String']['sval']
|
|
@@ -11,6 +11,7 @@ function parseContext(raw, attempt) {
|
|
|
11
11
|
const parsed = JSON.parse(raw);
|
|
12
12
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
13
13
|
throw new Error('Vitest report expectation context must be an object');
|
|
14
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- establish a record view after validating the untrusted JSON object
|
|
14
15
|
const context = parsed;
|
|
15
16
|
if (Object.keys(context).toSorted().join('\0') !== ['attempt', 'suites', 'version'].join('\0') ||
|
|
16
17
|
context.version !== 'vitest-report-expectations:v2' ||
|
|
@@ -26,6 +27,7 @@ function parseContext(raw, attempt) {
|
|
|
26
27
|
Number(expectation.minimumAttempt) < 1 ||
|
|
27
28
|
Number(expectation.minimumAttempt) > attempt))
|
|
28
29
|
throw new Error('Vitest report expectation context has an invalid schema');
|
|
30
|
+
// oxlint-disable-next-line no-mistakes/ts-no-const-aliases -- retain the validated expectation type after the complete schema check
|
|
29
31
|
const typed = context;
|
|
30
32
|
const suites = typed.suites.map((expectation) => expectation.suite);
|
|
31
33
|
if (new Set(suites).size !== suites.length || suites.join('\0') !== suites.toSorted().join('\0'))
|