@apexops/kernel 0.10.0-next.4 → 0.11.0-next.0
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 +28 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/directory-lock.d.ts +118 -0
- package/dist/directory-lock.d.ts.map +1 -0
- package/dist/directory-lock.js +587 -0
- package/dist/directory-lock.js.map +1 -0
- package/dist/files.d.ts +63 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +158 -2
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/object-store.js +2 -2
- package/dist/object-store.js.map +1 -1
- package/dist/project-store.d.ts +2 -1
- package/dist/project-store.d.ts.map +1 -1
- package/dist/project-store.js +1 -0
- package/dist/project-store.js.map +1 -1
- package/dist/repeat-files.d.ts +66 -0
- package/dist/repeat-files.d.ts.map +1 -0
- package/dist/repeat-files.js +214 -0
- package/dist/repeat-files.js.map +1 -0
- package/dist/repeat-guard.d.ts +197 -0
- package/dist/repeat-guard.d.ts.map +1 -0
- package/dist/repeat-guard.js +462 -0
- package/dist/repeat-guard.js.map +1 -0
- package/dist/review-capture.d.ts +170 -0
- package/dist/review-capture.d.ts.map +1 -0
- package/dist/review-capture.js +570 -0
- package/dist/review-capture.js.map +1 -0
- package/dist/run-repository.d.ts +52 -2
- package/dist/run-repository.d.ts.map +1 -1
- package/dist/run-repository.js +198 -52
- package/dist/run-repository.js.map +1 -1
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +24 -2
- package/dist/tasks.js.map +1 -1
- package/dist/test/files.test.d.ts +2 -0
- package/dist/test/files.test.d.ts.map +1 -0
- package/dist/test/files.test.js +140 -0
- package/dist/test/files.test.js.map +1 -0
- package/dist/test/policies.test.js +1 -1
- package/dist/test/policies.test.js.map +1 -1
- package/dist/test/repeat-guard.test.d.ts +2 -0
- package/dist/test/repeat-guard.test.d.ts.map +1 -0
- package/dist/test/repeat-guard.test.js +1106 -0
- package/dist/test/repeat-guard.test.js.map +1 -0
- package/dist/test/review-capture.test.d.ts +2 -0
- package/dist/test/review-capture.test.d.ts.map +1 -0
- package/dist/test/review-capture.test.js +291 -0
- package/dist/test/review-capture.test.js.map +1 -0
- package/dist/test/run-repository.test.js +451 -7
- package/dist/test/run-repository.test.js.map +1 -1
- package/dist/test/workflow.test.js +32 -1
- package/dist/test/workflow.test.js.map +1 -1
- package/dist/test/writer-transfer.test.js +6 -1
- package/dist/test/writer-transfer.test.js.map +1 -1
- package/dist/validator-registry.d.ts.map +1 -1
- package/dist/validator-registry.js +10 -1
- package/dist/validator-registry.js.map +1 -1
- package/dist/workflow-validator-ownership.d.ts.map +1 -1
- package/dist/workflow-validator-ownership.js +2 -1
- package/dist/workflow-validator-ownership.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, readdir, writeFile } from "node:fs/promises";
|
|
4
|
+
import { hostname, tmpdir } from "node:os";
|
|
5
|
+
import { syncBuiltinESMExports } from "node:module";
|
|
6
|
+
import { join, resolve } from "node:path";
|
|
5
7
|
import test from "node:test";
|
|
6
|
-
import { ProjectStore, RunRepository } from "../index.js";
|
|
8
|
+
import { ProjectStore, RunMutationBusyError, RunRepository, RunWriterConflictError } from "../index.js";
|
|
7
9
|
test("run repository CAS permits one mutation and rejects a racing stale hash", async () => {
|
|
8
10
|
const root = await mkdtemp(join(tmpdir(), "apex-run-repository-"));
|
|
9
11
|
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
10
|
-
await store.initializeProject({
|
|
12
|
+
await store.initializeProject({
|
|
13
|
+
projectId: "demo",
|
|
14
|
+
displayName: "Demo",
|
|
15
|
+
defaultIacTool: "bicep",
|
|
16
|
+
riskOwner: "partner",
|
|
17
|
+
});
|
|
11
18
|
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
12
19
|
const repository = new RunRepository(store.runDirectory("demo", "run-1"));
|
|
13
20
|
const expectedRunHash = await repository.hash();
|
|
@@ -30,10 +37,107 @@ test("run repository CAS permits one mutation and rejects a racing stale hash",
|
|
|
30
37
|
assert.equal((await repository.read()).ownerEpoch, 2);
|
|
31
38
|
assert.equal((await repository.journal.replay()).length, 1);
|
|
32
39
|
});
|
|
40
|
+
test("run repository never exposes partial lock metadata under contention", async () => {
|
|
41
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-lock-contention-"));
|
|
42
|
+
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
43
|
+
await store.initializeProject({
|
|
44
|
+
projectId: "demo",
|
|
45
|
+
displayName: "Demo",
|
|
46
|
+
defaultIacTool: "bicep",
|
|
47
|
+
riskOwner: "partner",
|
|
48
|
+
});
|
|
49
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
50
|
+
const repository = new RunRepository(store.runDirectory("demo", "run-1"));
|
|
51
|
+
const results = await Promise.allSettled(Array.from({ length: 64 }, () => repository.read()));
|
|
52
|
+
assert.ok(results.some(({ status }) => status === "fulfilled"));
|
|
53
|
+
for (const result of results) {
|
|
54
|
+
if (result.status === "rejected")
|
|
55
|
+
assert.match(String(result.reason), /Run mutation is already in progress/u);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
test("run repository reclaims an expired dead-owner generation into a permanent tombstone", async () => {
|
|
59
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-stale-lock-"));
|
|
60
|
+
const now = new Date("2026-01-01T00:00:00.000Z");
|
|
61
|
+
const store = new ProjectStore(root, () => now, () => "run-1");
|
|
62
|
+
await store.initializeProject({
|
|
63
|
+
projectId: "demo",
|
|
64
|
+
displayName: "Demo",
|
|
65
|
+
defaultIacTool: "bicep",
|
|
66
|
+
riskOwner: "partner",
|
|
67
|
+
});
|
|
68
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
69
|
+
const directory = store.runDirectory("demo", "run-1");
|
|
70
|
+
const lockPath = join(directory, ".run-mutation.lock");
|
|
71
|
+
await mkdir(lockPath);
|
|
72
|
+
await writeFile(join(lockPath, "metadata.json"), JSON.stringify({
|
|
73
|
+
token: "expired-lock",
|
|
74
|
+
pid: 2_147_483_647,
|
|
75
|
+
host: hostname(),
|
|
76
|
+
createdAt: "2025-12-31T23:58:00.000Z",
|
|
77
|
+
expiresAt: "2025-12-31T23:59:00.000Z",
|
|
78
|
+
}));
|
|
79
|
+
const repository = new RunRepository(directory, { clock: () => now, lockTtlMs: 30_000 });
|
|
80
|
+
const results = await Promise.allSettled(Array.from({ length: 64 }, () => repository.read()));
|
|
81
|
+
assert.ok(results.some(({ status }) => status === "fulfilled"));
|
|
82
|
+
for (const result of results) {
|
|
83
|
+
if (result.status === "fulfilled")
|
|
84
|
+
assert.equal(result.value.projectId, "demo");
|
|
85
|
+
else
|
|
86
|
+
assert.match(String(result.reason), /Run mutation is already in progress/u);
|
|
87
|
+
}
|
|
88
|
+
await assert.rejects(readFile(lockPath), (error) => error.code === "ENOENT");
|
|
89
|
+
// Released generations are deleted; only the reclaimed dead-owner generation stays as a permanent tombstone.
|
|
90
|
+
const tombstones = await readdir(join(directory, ".run-mutation.retired"));
|
|
91
|
+
assert.equal(tombstones.length, 1);
|
|
92
|
+
assert.equal(JSON.parse(await readFile(join(directory, ".run-mutation.retired", tombstones[0], "metadata.json"), "utf8")).token, "expired-lock");
|
|
93
|
+
});
|
|
94
|
+
test("run repository never reclaims an expired lock owned by a live local process", async () => {
|
|
95
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-live-lock-"));
|
|
96
|
+
const now = new Date("2026-01-01T00:00:00.000Z");
|
|
97
|
+
const store = new ProjectStore(root, () => now, () => "run-1");
|
|
98
|
+
await store.initializeProject({
|
|
99
|
+
projectId: "demo",
|
|
100
|
+
displayName: "Demo",
|
|
101
|
+
defaultIacTool: "bicep",
|
|
102
|
+
riskOwner: "partner",
|
|
103
|
+
});
|
|
104
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
105
|
+
const directory = store.runDirectory("demo", "run-1");
|
|
106
|
+
const lockPath = join(directory, ".run-mutation.lock");
|
|
107
|
+
await mkdir(lockPath);
|
|
108
|
+
await writeFile(join(lockPath, "metadata.json"), JSON.stringify({
|
|
109
|
+
token: "live-lock",
|
|
110
|
+
pid: process.pid,
|
|
111
|
+
host: hostname(),
|
|
112
|
+
createdAt: "2025-12-31T23:58:00.000Z",
|
|
113
|
+
expiresAt: "2025-12-31T23:59:00.000Z",
|
|
114
|
+
}));
|
|
115
|
+
await assert.rejects(new RunRepository(directory, { clock: () => now }).read(), /Run mutation is already in progress/u);
|
|
116
|
+
assert.equal(JSON.parse(await readFile(join(lockPath, "metadata.json"), "utf8")).token, "live-lock");
|
|
117
|
+
});
|
|
118
|
+
test("run repository rejects missing metadata in a stable lock generation", async () => {
|
|
119
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-invalid-lock-"));
|
|
120
|
+
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
121
|
+
await store.initializeProject({
|
|
122
|
+
projectId: "demo",
|
|
123
|
+
displayName: "Demo",
|
|
124
|
+
defaultIacTool: "bicep",
|
|
125
|
+
riskOwner: "partner",
|
|
126
|
+
});
|
|
127
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
128
|
+
const directory = store.runDirectory("demo", "run-1");
|
|
129
|
+
await mkdir(join(directory, ".run-mutation.lock"));
|
|
130
|
+
await assert.rejects(new RunRepository(directory).read(), /Run mutation lock metadata is unreadable/u);
|
|
131
|
+
});
|
|
33
132
|
test("run repository rejects a mutation when the validated journal head changed", async () => {
|
|
34
133
|
const root = await mkdtemp(join(tmpdir(), "apex-run-journal-cas-"));
|
|
35
134
|
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
36
|
-
await store.initializeProject({
|
|
135
|
+
await store.initializeProject({
|
|
136
|
+
projectId: "demo",
|
|
137
|
+
displayName: "Demo",
|
|
138
|
+
defaultIacTool: "bicep",
|
|
139
|
+
riskOwner: "partner",
|
|
140
|
+
});
|
|
37
141
|
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
38
142
|
const repository = new RunRepository(store.runDirectory("demo", "run-1"));
|
|
39
143
|
const validatedHead = await repository.journal.head();
|
|
@@ -67,7 +171,12 @@ for (const stage of ["intent", "journal", "run", "cleanup"]) {
|
|
|
67
171
|
test(`run repository recovers a crash after ${stage}`, async () => {
|
|
68
172
|
const root = await mkdtemp(join(tmpdir(), "apex-run-recovery-"));
|
|
69
173
|
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
70
|
-
await store.initializeProject({
|
|
174
|
+
await store.initializeProject({
|
|
175
|
+
projectId: "demo",
|
|
176
|
+
displayName: "Demo",
|
|
177
|
+
defaultIacTool: "bicep",
|
|
178
|
+
riskOwner: "partner",
|
|
179
|
+
});
|
|
71
180
|
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
72
181
|
const directory = store.runDirectory("demo", "run-1");
|
|
73
182
|
const repository = new RunRepository(directory, {
|
|
@@ -97,4 +206,339 @@ for (const stage of ["intent", "journal", "run", "cleanup"]) {
|
|
|
97
206
|
assert.equal(events.length, committed ? 1 : 0);
|
|
98
207
|
});
|
|
99
208
|
}
|
|
209
|
+
async function writerLeaseFixture(now) {
|
|
210
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-writer-lease-"));
|
|
211
|
+
const store = new ProjectStore(root, () => now.value, () => "run-1");
|
|
212
|
+
await store.initializeProject({
|
|
213
|
+
projectId: "demo",
|
|
214
|
+
displayName: "Demo",
|
|
215
|
+
defaultIacTool: "bicep",
|
|
216
|
+
riskOwner: "partner",
|
|
217
|
+
});
|
|
218
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
219
|
+
const directory = store.runDirectory("demo", "run-1");
|
|
220
|
+
return { directory, repository: new RunRepository(directory, { clock: () => now.value, writerLeaseTtlMs: 1_000 }) };
|
|
221
|
+
}
|
|
222
|
+
test("run writer lease acquires, renews, rejects a second writer, and releases", async () => {
|
|
223
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
224
|
+
const { repository } = await writerLeaseFixture(now);
|
|
225
|
+
const owner = { workspacePath: "/workspace/main", sessionId: "session-a" };
|
|
226
|
+
const other = { workspacePath: "/workspace/worktree", sessionId: "session-b" };
|
|
227
|
+
const initial = await repository.acquireWriterLease(owner);
|
|
228
|
+
assert.equal(initial.workspacePath, resolve(owner.workspacePath));
|
|
229
|
+
assert.equal(initial.createdAt, "2026-01-01T00:00:00.000Z");
|
|
230
|
+
assert.equal(initial.expiresAt, "2026-01-01T00:00:01.000Z");
|
|
231
|
+
now.value = new Date("2026-01-01T00:00:00.500Z");
|
|
232
|
+
const renewed = await repository.acquireWriterLease(owner);
|
|
233
|
+
assert.equal(renewed.createdAt, initial.createdAt);
|
|
234
|
+
assert.equal(renewed.expiresAt, "2026-01-01T00:00:01.500Z");
|
|
235
|
+
await assert.rejects(repository.acquireWriterLease(other), (error) => error instanceof RunWriterConflictError &&
|
|
236
|
+
error.code === "APEX_WRITER_CONFLICT" &&
|
|
237
|
+
error.ownerWorktree === resolve(owner.workspacePath));
|
|
238
|
+
await assert.rejects(repository.releaseWriterLease(other), RunWriterConflictError);
|
|
239
|
+
assert.equal(await repository.releaseWriterLease(owner), true);
|
|
240
|
+
assert.equal(await repository.releaseWriterLease(owner), false);
|
|
241
|
+
});
|
|
242
|
+
test("run writer lease expires and can be taken over by another worktree", async () => {
|
|
243
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
244
|
+
const { repository } = await writerLeaseFixture(now);
|
|
245
|
+
await repository.acquireWriterLease({ workspacePath: "/workspace/main", sessionId: "session-a" });
|
|
246
|
+
now.value = new Date("2026-01-01T00:00:01.001Z");
|
|
247
|
+
const takeover = await repository.acquireWriterLease({
|
|
248
|
+
workspacePath: "/workspace/worktree",
|
|
249
|
+
sessionId: "session-b",
|
|
250
|
+
});
|
|
251
|
+
assert.equal(takeover.workspacePath, resolve("/workspace/worktree"));
|
|
252
|
+
assert.equal(takeover.createdAt, "2026-01-01T00:00:01.001Z");
|
|
253
|
+
});
|
|
254
|
+
test("run writer lease publication remains readable under contention", async () => {
|
|
255
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
256
|
+
const { directory, repository } = await writerLeaseFixture(now);
|
|
257
|
+
const attempts = await Promise.allSettled(Array.from({ length: 32 }, (_, index) => repository.acquireWriterLease({
|
|
258
|
+
workspacePath: index % 2 === 0 ? "/workspace/main" : "/workspace/worktree",
|
|
259
|
+
sessionId: `session-${index}`,
|
|
260
|
+
})));
|
|
261
|
+
const owners = new Set(attempts.flatMap((attempt) => (attempt.status === "fulfilled" ? [attempt.value.workspacePath] : [])));
|
|
262
|
+
assert.equal(owners.size, 1, "an unexpired lease must never change workspace under contention");
|
|
263
|
+
for (const attempt of attempts) {
|
|
264
|
+
if (attempt.status === "rejected") {
|
|
265
|
+
assert.ok(attempt.reason instanceof RunWriterConflictError, String(attempt.reason));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const lease = JSON.parse(await readFile(join(directory, ".run-writer-lease.json"), "utf8"));
|
|
269
|
+
assert.equal(lease.workspacePath, [...owners][0]);
|
|
270
|
+
assert.equal(typeof lease.expiresAt, "string");
|
|
271
|
+
});
|
|
272
|
+
test("run writer lease renewal waits out a slow mutation lock holder instead of failing", async () => {
|
|
273
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
274
|
+
const { directory, repository } = await writerLeaseFixture(now);
|
|
275
|
+
const owner = { workspacePath: "/workspace/main", sessionId: "session-a" };
|
|
276
|
+
await repository.acquireWriterLease(owner);
|
|
277
|
+
let entered;
|
|
278
|
+
const holding = new Promise((done) => (entered = done));
|
|
279
|
+
// Hold the run mutation lock longer than the former 500 ms writer-lease wait budget, as a slow Windows lock
|
|
280
|
+
// cycle (or a queue of same-workspace renewals) does under contention.
|
|
281
|
+
const holder = new RunRepository(directory, {
|
|
282
|
+
clock: () => now.value,
|
|
283
|
+
writerLeaseTtlMs: 1_000,
|
|
284
|
+
faultInjector: async (stage) => {
|
|
285
|
+
if (stage !== "intent")
|
|
286
|
+
return;
|
|
287
|
+
entered();
|
|
288
|
+
await new Promise((done) => setTimeout(done, 1_200));
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
const mutation = holder.mutate({
|
|
292
|
+
expectedRunHash: await holder.hash(),
|
|
293
|
+
event: {
|
|
294
|
+
eventId: "event-slow-holder",
|
|
295
|
+
projectId: "demo",
|
|
296
|
+
runId: "run-1",
|
|
297
|
+
type: "owner-changed",
|
|
298
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
299
|
+
ownerEpoch: 2,
|
|
300
|
+
payload: {},
|
|
301
|
+
},
|
|
302
|
+
update: (run) => ({ ...run, ownerEpoch: 2 }),
|
|
303
|
+
});
|
|
304
|
+
await holding;
|
|
305
|
+
let released = false;
|
|
306
|
+
void mutation.then(() => (released = true), () => (released = true));
|
|
307
|
+
await assert.rejects(repository.acquireWriterLease({ workspacePath: "/workspace/worktree", sessionId: "session-b" }), RunWriterConflictError);
|
|
308
|
+
assert.equal(released, false, "another worktree must fail fast with a typed conflict while the lock is held");
|
|
309
|
+
now.value = new Date("2026-01-01T00:00:00.500Z");
|
|
310
|
+
const renewed = await repository.acquireWriterLease(owner);
|
|
311
|
+
assert.equal(renewed.workspacePath, resolve(owner.workspacePath));
|
|
312
|
+
assert.equal(renewed.expiresAt, "2026-01-01T00:00:01.500Z");
|
|
313
|
+
await mutation;
|
|
314
|
+
});
|
|
315
|
+
async function withRunDirectoryMkdirFailure(directory, code, action) {
|
|
316
|
+
const promises = fs.promises;
|
|
317
|
+
const original = promises.mkdir;
|
|
318
|
+
let failures = 1;
|
|
319
|
+
promises.mkdir = (async (path, options) => {
|
|
320
|
+
if (failures > 0 && resolve(String(path)) === resolve(directory)) {
|
|
321
|
+
failures -= 1;
|
|
322
|
+
throw Object.assign(new Error(`${code}: injected`), { code });
|
|
323
|
+
}
|
|
324
|
+
return await original(path, options);
|
|
325
|
+
});
|
|
326
|
+
syncBuiltinESMExports();
|
|
327
|
+
try {
|
|
328
|
+
return await action();
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
promises.mkdir = original;
|
|
332
|
+
syncBuiltinESMExports();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
test("a competing worktree gets a typed writer conflict for a transient Windows sharing violation", async () => {
|
|
336
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
337
|
+
const { directory, repository } = await writerLeaseFixture(now);
|
|
338
|
+
const owner = { workspacePath: "/workspace/main", sessionId: "session-a" };
|
|
339
|
+
const competitor = { workspacePath: "/workspace/worktree", sessionId: "session-b" };
|
|
340
|
+
await repository.acquireWriterLease(owner);
|
|
341
|
+
const windows = new RunRepository(directory, { clock: () => now.value, writerLeaseTtlMs: 1_000, platform: "win32" });
|
|
342
|
+
for (const code of ["EPERM", "EACCES", "EBUSY"]) {
|
|
343
|
+
await assert.rejects(withRunDirectoryMkdirFailure(directory, code, () => windows.acquireWriterLease(competitor)), (error) => error instanceof RunWriterConflictError &&
|
|
344
|
+
error.code === "APEX_WRITER_CONFLICT" &&
|
|
345
|
+
error.ownerWorktree === resolve(owner.workspacePath) &&
|
|
346
|
+
error.cause.code === code);
|
|
347
|
+
}
|
|
348
|
+
// The same transient failure is not masked when no other worktree holds the lease or off Windows.
|
|
349
|
+
await assert.rejects(withRunDirectoryMkdirFailure(directory, "EPERM", () => windows.acquireWriterLease(owner)), { code: "EPERM" });
|
|
350
|
+
const linux = new RunRepository(directory, { clock: () => now.value, writerLeaseTtlMs: 1_000, platform: "linux" });
|
|
351
|
+
await assert.rejects(withRunDirectoryMkdirFailure(directory, "EPERM", () => linux.acquireWriterLease(competitor)), { code: "EPERM" });
|
|
352
|
+
await assert.rejects(withRunDirectoryMkdirFailure(directory, "ENOSPC", () => windows.acquireWriterLease(competitor)), { code: "ENOSPC" });
|
|
353
|
+
assert.equal((await windows.acquireWriterLease(owner)).workspacePath, resolve(owner.workspacePath));
|
|
354
|
+
});
|
|
355
|
+
test("a busy run mutation lock is reported as a conflict only when another worktree holds the lease", async () => {
|
|
356
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
357
|
+
const { directory } = await writerLeaseFixture(now);
|
|
358
|
+
const lockPath = join(directory, ".run-mutation.lock");
|
|
359
|
+
await mkdir(lockPath);
|
|
360
|
+
await writeFile(join(lockPath, "metadata.json"), JSON.stringify({
|
|
361
|
+
token: "live-lock",
|
|
362
|
+
pid: process.pid,
|
|
363
|
+
host: hostname(),
|
|
364
|
+
createdAt: "2025-12-31T23:59:59.000Z",
|
|
365
|
+
expiresAt: "2026-01-01T00:00:30.000Z",
|
|
366
|
+
}));
|
|
367
|
+
const repository = new RunRepository(directory, {
|
|
368
|
+
clock: () => now.value,
|
|
369
|
+
writerLeaseTtlMs: 1_000,
|
|
370
|
+
writerLeaseLockWaitMs: 50,
|
|
371
|
+
});
|
|
372
|
+
await assert.rejects(repository.acquireWriterLease({ workspacePath: "/workspace/worktree", sessionId: "session-b" }), RunMutationBusyError);
|
|
373
|
+
await writeFile(join(directory, ".run-writer-lease.json"), JSON.stringify({
|
|
374
|
+
version: 1,
|
|
375
|
+
workspacePath: resolve("/workspace/main"),
|
|
376
|
+
host: hostname(),
|
|
377
|
+
pid: process.pid,
|
|
378
|
+
sessionId: "session-a",
|
|
379
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
380
|
+
expiresAt: "2026-01-01T00:00:01.000Z",
|
|
381
|
+
}));
|
|
382
|
+
await assert.rejects(repository.acquireWriterLease({ workspacePath: "/workspace/worktree", sessionId: "session-b" }), RunWriterConflictError);
|
|
383
|
+
await assert.rejects(repository.acquireWriterLease({ workspacePath: "/workspace/main", sessionId: "session-a" }), RunMutationBusyError);
|
|
384
|
+
});
|
|
385
|
+
async function lockEntries(directory) {
|
|
386
|
+
const top = (await readdir(directory)).filter((name) => name.startsWith(".run-mutation"));
|
|
387
|
+
const retired = await readdir(join(directory, ".run-mutation.retired")).catch((error) => {
|
|
388
|
+
if (error.code === "ENOENT")
|
|
389
|
+
return [];
|
|
390
|
+
throw error;
|
|
391
|
+
});
|
|
392
|
+
return { top, retired };
|
|
393
|
+
}
|
|
394
|
+
async function mutateOnce(repository, eventId, expectedRunHash) {
|
|
395
|
+
return repository.mutate({
|
|
396
|
+
expectedRunHash: expectedRunHash ?? (await repository.hash()),
|
|
397
|
+
event: {
|
|
398
|
+
eventId,
|
|
399
|
+
projectId: "demo",
|
|
400
|
+
runId: "run-1",
|
|
401
|
+
type: "owner-changed",
|
|
402
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
403
|
+
ownerEpoch: 1,
|
|
404
|
+
payload: { eventId },
|
|
405
|
+
},
|
|
406
|
+
update: (run) => run,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
async function withReleasedLockRemovalFailure(code, failures, action) {
|
|
410
|
+
const promises = fs.promises;
|
|
411
|
+
const original = promises.rm;
|
|
412
|
+
let remaining = failures;
|
|
413
|
+
let injected = 0;
|
|
414
|
+
promises.rm = (async (path, options) => {
|
|
415
|
+
if (remaining > 0 && /[\\/]released-[^\\/]+$/u.test(String(path))) {
|
|
416
|
+
remaining -= 1;
|
|
417
|
+
injected += 1;
|
|
418
|
+
throw Object.assign(new Error(`${code}: injected`), { code });
|
|
419
|
+
}
|
|
420
|
+
return await original(path, options);
|
|
421
|
+
});
|
|
422
|
+
syncBuiltinESMExports();
|
|
423
|
+
try {
|
|
424
|
+
return { result: await action(), injected };
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
promises.rm = original;
|
|
428
|
+
syncBuiltinESMExports();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
test("repeated run mutations leave a bounded number of lock entries", async () => {
|
|
432
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
433
|
+
const { directory } = await writerLeaseFixture(now);
|
|
434
|
+
const repository = new RunRepository(directory, { clock: () => now.value, platform: "linux" });
|
|
435
|
+
const windows = new RunRepository(directory, { clock: () => now.value, platform: "win32" });
|
|
436
|
+
for (let index = 0; index < 25; index += 1) {
|
|
437
|
+
await mutateOnce(index % 2 === 0 ? repository : windows, `event-${index}`);
|
|
438
|
+
await repository.read();
|
|
439
|
+
assert.deepEqual(await lockEntries(directory), { top: [".run-mutation.retired"], retired: [] });
|
|
440
|
+
}
|
|
441
|
+
assert.equal((await repository.journal.replay()).length, 25);
|
|
442
|
+
});
|
|
443
|
+
test("two repositories contending on one run keep CAS semantics and leave no released generations", async () => {
|
|
444
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
445
|
+
const { directory } = await writerLeaseFixture(now);
|
|
446
|
+
const left = new RunRepository(directory, { clock: () => now.value });
|
|
447
|
+
const right = new RunRepository(directory, { clock: () => now.value });
|
|
448
|
+
let fulfilled = 0;
|
|
449
|
+
for (let round = 0; round < 10; round += 1) {
|
|
450
|
+
const results = await Promise.allSettled([
|
|
451
|
+
mutateOnce(left, `left-${round}`),
|
|
452
|
+
mutateOnce(right, `right-${round}`),
|
|
453
|
+
left.read(),
|
|
454
|
+
right.read(),
|
|
455
|
+
]);
|
|
456
|
+
for (const [index, result] of results.entries()) {
|
|
457
|
+
if (result.status === "rejected")
|
|
458
|
+
assert.match(String(result.reason), /Run mutation is already in progress|Stale run hash/u);
|
|
459
|
+
else if (index < 2)
|
|
460
|
+
fulfilled += 1;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Contention may reject every racing call in a round; uncontended calls from both repositories still succeed.
|
|
464
|
+
await mutateOnce(left, "left-final");
|
|
465
|
+
await mutateOnce(right, "right-final");
|
|
466
|
+
assert.equal((await left.journal.replay()).length, fulfilled + 2);
|
|
467
|
+
assert.deepEqual(await lockEntries(directory), { top: [".run-mutation.retired"], retired: [] });
|
|
468
|
+
});
|
|
469
|
+
test("a failed released-lock cleanup never fails the mutation and is swept by the next one", async () => {
|
|
470
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
471
|
+
const { directory } = await writerLeaseFixture(now);
|
|
472
|
+
const linux = new RunRepository(directory, { clock: () => now.value, platform: "linux" });
|
|
473
|
+
const windows = new RunRepository(directory, { clock: () => now.value, platform: "win32" });
|
|
474
|
+
let sequence = 0;
|
|
475
|
+
const expectLeftover = async (repository, code, failures, injected) => {
|
|
476
|
+
const expectedRunHash = await repository.hash();
|
|
477
|
+
const outcome = await withReleasedLockRemovalFailure(code, failures, () => mutateOnce(repository, `event-${(sequence += 1)}`, expectedRunHash));
|
|
478
|
+
assert.equal(outcome.injected, injected);
|
|
479
|
+
const { retired } = await lockEntries(directory);
|
|
480
|
+
assert.equal(retired.length, 1);
|
|
481
|
+
assert.match(retired[0], /^released-/u);
|
|
482
|
+
await mutateOnce(linux, `event-${(sequence += 1)}`);
|
|
483
|
+
assert.deepEqual(await lockEntries(directory), { top: [".run-mutation.retired"], retired: [] });
|
|
484
|
+
};
|
|
485
|
+
// Off Windows a removal failure is not retried; the next mutation's sweep removes the leftover.
|
|
486
|
+
await expectLeftover(linux, "EPERM", 1, 1);
|
|
487
|
+
// A non-transient failure is not retried on Windows either.
|
|
488
|
+
await expectLeftover(windows, "EIO", 1, 1);
|
|
489
|
+
// Persistent Windows sharing violations exhaust the bounded retry and are left for the next sweep.
|
|
490
|
+
await expectLeftover(windows, "EBUSY", 100, 5);
|
|
491
|
+
// Brief Windows sharing violations are retried within the same release.
|
|
492
|
+
for (const code of ["EPERM", "EACCES", "EBUSY", "ENOTEMPTY"]) {
|
|
493
|
+
const expectedRunHash = await windows.hash();
|
|
494
|
+
const outcome = await withReleasedLockRemovalFailure(code, 2, () => mutateOnce(windows, `event-${(sequence += 1)}`, expectedRunHash));
|
|
495
|
+
assert.equal(outcome.injected, 2);
|
|
496
|
+
assert.deepEqual(await lockEntries(directory), { top: [".run-mutation.retired"], retired: [] });
|
|
497
|
+
}
|
|
498
|
+
assert.equal((await linux.journal.replay()).length, sequence);
|
|
499
|
+
});
|
|
500
|
+
test("a delayed stale-lock contender cannot retire a replacement generation", async () => {
|
|
501
|
+
const now = { value: new Date("2026-01-01T00:00:00.000Z") };
|
|
502
|
+
const { directory, repository } = await writerLeaseFixture(now);
|
|
503
|
+
const lockPath = join(directory, ".run-mutation.lock");
|
|
504
|
+
const deadPid = 2_147_483_647;
|
|
505
|
+
await mkdir(lockPath);
|
|
506
|
+
await writeFile(join(lockPath, "metadata.json"), JSON.stringify({
|
|
507
|
+
token: "expired-lock",
|
|
508
|
+
pid: deadPid,
|
|
509
|
+
host: hostname(),
|
|
510
|
+
createdAt: "2025-12-31T23:58:00.000Z",
|
|
511
|
+
expiresAt: "2025-12-31T23:59:00.000Z",
|
|
512
|
+
}));
|
|
513
|
+
const originalKill = process.kill;
|
|
514
|
+
let swapped = false;
|
|
515
|
+
// Between the contender's snapshot and its liveness check, the old owner releases (without a tombstone) and exits,
|
|
516
|
+
// and another process publishes a replacement generation.
|
|
517
|
+
process.kill = ((pid, signal) => {
|
|
518
|
+
if (pid !== deadPid)
|
|
519
|
+
return originalKill.call(process, pid, signal);
|
|
520
|
+
if (!swapped) {
|
|
521
|
+
swapped = true;
|
|
522
|
+
fs.rmSync(lockPath, { recursive: true });
|
|
523
|
+
fs.mkdirSync(lockPath);
|
|
524
|
+
fs.writeFileSync(join(lockPath, "metadata.json"), JSON.stringify({
|
|
525
|
+
token: "replacement",
|
|
526
|
+
pid: process.pid,
|
|
527
|
+
host: hostname(),
|
|
528
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
529
|
+
expiresAt: "2026-01-01T00:00:30.000Z",
|
|
530
|
+
}));
|
|
531
|
+
}
|
|
532
|
+
throw Object.assign(new Error("ESRCH: injected"), { code: "ESRCH" });
|
|
533
|
+
});
|
|
534
|
+
try {
|
|
535
|
+
await assert.rejects(repository.read(), RunMutationBusyError);
|
|
536
|
+
}
|
|
537
|
+
finally {
|
|
538
|
+
process.kill = originalKill;
|
|
539
|
+
}
|
|
540
|
+
assert.equal(swapped, true);
|
|
541
|
+
assert.equal(JSON.parse(await readFile(join(lockPath, "metadata.json"), "utf8")).token, "replacement");
|
|
542
|
+
assert.deepEqual((await lockEntries(directory)).retired, []);
|
|
543
|
+
});
|
|
100
544
|
//# sourceMappingURL=run-repository.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-repository.test.js","sourceRoot":"","sources":["../../src/test/run-repository.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1D,IAAI,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;IACzF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC;IACnG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,EAAE,CACnC,UAAU,CAAC,MAAM,CAAC;QAChB,eAAe;QACf,KAAK,EAAE;YACL,OAAO;YACP,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,OAAO,EAAE;SACrB;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IACL,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACjF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;IAC3F,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC;IACnG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;QAC9B,OAAO,EAAE,oBAAoB;QAC7B,SAAS,EAAE,MAAM;QACjB,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,oBAAoB;QAC1B,SAAS,EAAE,0BAA0B;QACrC,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,aAAa;QAC3B,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;KACxD,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,UAAU,CAAC,IAAI,EAAE;QACxC,mBAAmB,EAAE,aAAa;QAClC,KAAK,EAAE;YACL,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;SACrB;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG;KACrB,CAAC,EACF,oBAAoB,CACrB,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,KAAK,MAAM,KAAK,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAU,EAAE,CAAC;IACrE,IAAI,CAAC,yCAAyC,KAAK,EAAE,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;QACF,MAAM,KAAK,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC;QACnG,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE;YAC9C,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,OAAO,KAAK,KAAK;oBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;YAC3D,CAAC;SACF,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,MAAM,CAAC;YAChB,eAAe,EAAE,MAAM,UAAU,CAAC,IAAI,EAAE;YACxC,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS,KAAK,EAAE;gBACzB,SAAS,EAAE,MAAM;gBACjB,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,eAAe;gBACrB,SAAS,EAAE,0BAA0B;gBACrC,UAAU,EAAE,CAAC;gBACb,OAAO,EAAE,EAAE,KAAK,EAAE;aACnB;YACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;SAC7C,CAAC,EACF,IAAI,MAAM,CAAC,SAAS,KAAK,EAAE,CAAC,CAC7B,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,KAAK,KAAK,QAAQ,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"run-repository.test.js","sourceRoot":"","sources":["../../src/test/run-repository.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAExG,IAAI,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;IACzF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,EAAE,CACnC,UAAU,CAAC,MAAM,CAAC;QAChB,eAAe;QACf,KAAK,EAAE;YACL,OAAO;YACP,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,OAAO,EAAE;SACrB;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IACL,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACjF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;IACrF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9F,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC;IAChE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;YAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,sCAAsC,CAAC,CAAC;IAChH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;IACrG,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,GAAG,EACT,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACvD,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtB,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,cAAc;QACrB,GAAG,EAAE,aAAa;QAClB,IAAI,EAAE,QAAQ,EAAE;QAChB,SAAS,EAAE,0BAA0B;QACrC,SAAS,EAAE,0BAA0B;KACtC,CAAC,CACH,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACzF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9F,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC;IAChE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;YAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;;YAC3E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,sCAAsC,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAc,EAAE,EAAE,CAAE,KAA+B,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACjH,6GAA6G;IAC7G,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CACV,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,EAAE,UAAU,CAAC,CAAC,CAAE,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EACnH,cAAc,CACf,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;IAC7F,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,GAAG,EACT,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACvD,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtB,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,WAAW;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,IAAI,EAAE,QAAQ,EAAE;QAChB,SAAS,EAAE,0BAA0B;QACrC,SAAS,EAAE,0BAA0B;KACtC,CAAC,CACH,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAClB,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,EACzD,sCAAsC,CACvC,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AACvG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;IACrF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAC;IACnD,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,2CAA2C,CAAC,CAAC;AACzG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;IAC3F,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1E,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;QAC9B,OAAO,EAAE,oBAAoB;QAC7B,SAAS,EAAE,MAAM;QACjB,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,oBAAoB;QAC1B,SAAS,EAAE,0BAA0B;QACrC,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,aAAa;QAC3B,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;KACxD,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,MAAM,CAAC;QAChB,eAAe,EAAE,MAAM,UAAU,CAAC,IAAI,EAAE;QACxC,mBAAmB,EAAE,aAAa;QAClC,KAAK,EAAE;YACL,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;SACrB;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG;KACrB,CAAC,EACF,oBAAoB,CACrB,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,KAAK,MAAM,KAAK,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAU,EAAE,CAAC;IACrE,IAAI,CAAC,yCAAyC,KAAK,EAAE,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAC1C,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;QACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;YAC5B,SAAS,EAAE,MAAM;YACjB,WAAW,EAAE,MAAM;YACnB,cAAc,EAAE,OAAO;YACvB,SAAS,EAAE,SAAS;SACrB,CAAC,CAAC;QACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE;YAC9C,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,OAAO,KAAK,KAAK;oBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;YAC3D,CAAC;SACF,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,MAAM,CAAC;YAChB,eAAe,EAAE,MAAM,UAAU,CAAC,IAAI,EAAE;YACxC,KAAK,EAAE;gBACL,OAAO,EAAE,SAAS,KAAK,EAAE;gBACzB,SAAS,EAAE,MAAM;gBACjB,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,eAAe;gBACrB,SAAS,EAAE,0BAA0B;gBACrC,UAAU,EAAE,CAAC;gBACb,OAAO,EAAE,EAAE,KAAK,EAAE;aACnB;YACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;SAC7C,CAAC,EACF,IAAI,MAAM,CAAC,SAAS,KAAK,EAAE,CAAC,CAC7B,CAAC;QACF,MAAM,SAAS,GAAG,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,SAAS,GAAG,KAAK,KAAK,QAAQ,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,GAAoB;IACpD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,IAAI,EACJ,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EACf,GAAG,EAAE,CAAC,OAAO,CACd,CAAC;IACF,MAAM,KAAK,CAAC,iBAAiB,CAAC;QAC5B,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,MAAM;QACnB,cAAc,EAAE,OAAO;QACvB,SAAS,EAAE,SAAS;KACrB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7G,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AACtH,CAAC;AAED,IAAI,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;IAC1F,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC3E,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC/E,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;IAE5D,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;IAC5D,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EACpC,CAAC,KAAc,EAAE,EAAE,CACjB,KAAK,YAAY,sBAAsB;QACvC,KAAK,CAAC,IAAI,KAAK,sBAAsB;QACrC,KAAK,CAAC,aAAa,KAAK,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CACvD,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACnF,MAAM,CAAC,KAAK,CAAC,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;IACpF,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,UAAU,CAAC,kBAAkB,CAAC,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;IAClG,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC;QACnD,aAAa,EAAE,qBAAqB;QACpC,SAAS,EAAE,WAAW;KACvB,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;IAChF,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CACvC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CACtC,UAAU,CAAC,kBAAkB,CAAC;QAC5B,aAAa,EAAE,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,qBAAqB;QAC1E,SAAS,EAAE,WAAW,KAAK,EAAE;KAC9B,CAAC,CACH,CACF,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACrG,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,iEAAiE,CAAC,CAAC;IAChG,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,YAAY,sBAAsB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,EAAE,MAAM,CAAC,CAGzF,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;IACnG,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC3E,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,OAAoB,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,4GAA4G;IAC5G,uEAAuE;IACvE,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE;QAC1C,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK;QACtB,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YAC7B,IAAI,KAAK,KAAK,QAAQ;gBAAE,OAAO;YAC/B,OAAO,EAAE,CAAC;YACV,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC;KACF,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,eAAe,EAAE,MAAM,MAAM,CAAC,IAAI,EAAE;QACpC,KAAK,EAAE;YACL,OAAO,EAAE,mBAAmB;YAC5B,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE;SACZ;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;IACH,MAAM,OAAO,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,QAAQ,CAAC,IAAI,CAChB,GAAG,EAAE,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EACvB,GAAG,EAAE,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CACxB,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,kBAAkB,CAAC,EAAE,aAAa,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAC/F,sBAAsB,CACvB,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,8EAA8E,CAAC,CAAC;IAC9G,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;IAC5D,MAAM,QAAQ,CAAC;AACjB,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,4BAA4B,CAAI,SAAiB,EAAE,IAAY,EAAE,MAAwB;IACtG,MAAM,QAAQ,GAAG,EAAE,CAAC,QAA0D,CAAC;IAC/E,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC;IAChC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,QAAQ,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,IAAiB,EAAE,OAAiC,EAAE,EAAE;QAC/E,IAAI,QAAQ,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACjE,QAAQ,IAAI,CAAC,CAAC;YACd,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,CAAoB,CAAC;IACtB,qBAAqB,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,EAAE,CAAC;IACxB,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC;QAC1B,qBAAqB,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,IAAI,CAAC,6FAA6F,EAAE,KAAK,IAAI,EAAE;IAC7G,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC3E,MAAM,UAAU,GAAG,EAAE,aAAa,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IACpF,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACrH,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;QAChD,MAAM,MAAM,CAAC,OAAO,CAClB,4BAA4B,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,EAC3F,CAAC,KAAc,EAAE,EAAE,CACjB,KAAK,YAAY,sBAAsB;YACvC,KAAK,CAAC,IAAI,KAAK,sBAAsB;YACrC,KAAK,CAAC,aAAa,KAAK,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC;YACnD,KAAK,CAAC,KAA+B,CAAC,IAAI,KAAK,IAAI,CACvD,CAAC;IACJ,CAAC;IACD,kGAAkG;IAClG,MAAM,MAAM,CAAC,OAAO,CAClB,4BAA4B,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EACzF,EAAE,IAAI,EAAE,OAAO,EAAE,CAClB,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACnH,MAAM,MAAM,CAAC,OAAO,CAClB,4BAA4B,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,EAC5F,EAAE,IAAI,EAAE,OAAO,EAAE,CAClB,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAClB,4BAA4B,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,EAC/F,EAAE,IAAI,EAAE,QAAQ,EAAE,CACnB,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;AACtG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+FAA+F,EAAE,KAAK,IAAI,EAAE;IAC/G,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACvD,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtB,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,WAAW;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,IAAI,EAAE,QAAQ,EAAE;QAChB,SAAS,EAAE,0BAA0B;QACrC,SAAS,EAAE,0BAA0B;KACtC,CAAC,CACH,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE;QAC9C,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK;QACtB,gBAAgB,EAAE,KAAK;QACvB,qBAAqB,EAAE,EAAE;KAC1B,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,kBAAkB,CAAC,EAAE,aAAa,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAC/F,oBAAoB,CACrB,CAAC;IACF,MAAM,SAAS,CACb,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,EACzC,IAAI,CAAC,SAAS,CAAC;QACb,OAAO,EAAE,CAAC;QACV,aAAa,EAAE,OAAO,CAAC,iBAAiB,CAAC;QACzC,IAAI,EAAE,QAAQ,EAAE;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,SAAS,EAAE,WAAW;QACtB,SAAS,EAAE,0BAA0B;QACrC,SAAS,EAAE,0BAA0B;KACtC,CAAC,CACH,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,kBAAkB,CAAC,EAAE,aAAa,EAAE,qBAAqB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAC/F,sBAAsB,CACvB,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAClB,UAAU,CAAC,kBAAkB,CAAC,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAC3F,oBAAoB,CACrB,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,WAAW,CAAC,SAAiB;IAC1C,MAAM,GAAG,GAAG,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1F,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC/F,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAClE,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,UAAyB,EAAE,OAAe,EAAE,eAAwB;IAC5F,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,eAAe,EAAE,eAAe,IAAI,CAAC,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QAC7D,KAAK,EAAE;YACL,OAAO;YACP,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,0BAA0B;YACrC,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,OAAO,EAAE;SACrB;QACD,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG;KACrB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,8BAA8B,CAC3C,IAAY,EACZ,QAAgB,EAChB,MAAwB;IAExB,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAoD,CAAC;IACzE,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC7B,IAAI,SAAS,GAAG,QAAQ,CAAC;IACzB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,QAAQ,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,IAAiB,EAAE,OAAsB,EAAE,EAAE;QACjE,IAAI,SAAS,GAAG,CAAC,IAAI,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAClE,SAAS,IAAI,CAAC,CAAC;YACf,QAAQ,IAAI,CAAC,CAAC;YACd,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,CAAoB,CAAC;IACtB,qBAAqB,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC;IAC9C,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC;QACvB,qBAAqB,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,IAAI,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;IAC/E,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5F,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,UAAU,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;QAC3E,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6FAA6F,EAAE,KAAK,IAAI,EAAE;IAC7G,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACvE,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YACvC,UAAU,CAAC,IAAI,EAAE,QAAQ,KAAK,EAAE,CAAC;YACjC,UAAU,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,EAAE;YACX,KAAK,CAAC,IAAI,EAAE;SACb,CAAC,CAAC;QACH,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;gBAC9B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,qDAAqD,CAAC,CAAC;iBACxF,IAAI,KAAK,GAAG,CAAC;gBAAE,SAAS,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,8GAA8G;IAC9G,MAAM,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrC,MAAM,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;IAClE,MAAM,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAClG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACtG,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1F,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5F,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,cAAc,GAAG,KAAK,EAAE,UAAyB,EAAE,IAAY,EAAE,QAAgB,EAAE,QAAgB,EAAE,EAAE;QAC3G,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CACxE,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,CACpE,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACzC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAE,EAAE,aAAa,CAAC,CAAC;QACzC,MAAM,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAClG,CAAC,CAAC;IACF,gGAAgG;IAChG,MAAM,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3C,4DAA4D;IAC5D,MAAM,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3C,mGAAmG;IACnG,MAAM,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IAC/C,wEAAwE;IACxE,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CACjE,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,CACjE,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;IACvF,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC;IAC5D,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,aAAa,CAAC;IAC9B,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtB,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,cAAc;QACrB,GAAG,EAAE,OAAO;QACZ,IAAI,EAAE,QAAQ,EAAE;QAChB,SAAS,EAAE,0BAA0B;QACrC,SAAS,EAAE,0BAA0B;KACtC,CAAC,CACH,CAAC;IACF,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAClC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,mHAAmH;IACnH,0DAA0D;IAC1D,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,GAAW,EAAE,MAAwB,EAAE,EAAE;QACxD,IAAI,GAAG,KAAK,OAAO;YAAE,OAAO,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,IAAI,CAAC;YACf,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACvB,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAC/B,IAAI,CAAC,SAAS,CAAC;gBACb,KAAK,EAAE,aAAa;gBACpB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,IAAI,EAAE,QAAQ,EAAE;gBAChB,SAAS,EAAE,0BAA0B;gBACrC,SAAS,EAAE,0BAA0B;aACtC,CAAC,CACH,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACvE,CAAC,CAAwB,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAChE,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC;IAC9B,CAAC;IACD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACvG,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC"}
|
|
@@ -10,7 +10,12 @@ test("project store creates deterministic project and run layouts with four clos
|
|
|
10
10
|
const root = await mkdtemp(join(tmpdir(), "apex-project-"));
|
|
11
11
|
const clock = () => new Date("2026-01-01T00:00:00.000Z");
|
|
12
12
|
const store = new ProjectStore(root, clock, () => "run-fixed");
|
|
13
|
-
await store.initializeProject({
|
|
13
|
+
await store.initializeProject({
|
|
14
|
+
projectId: "demo",
|
|
15
|
+
displayName: "Demo",
|
|
16
|
+
defaultIacTool: "bicep",
|
|
17
|
+
riskOwner: "partner",
|
|
18
|
+
});
|
|
14
19
|
const run = await store.createRun("demo", {
|
|
15
20
|
environment: "dev",
|
|
16
21
|
targetScope: "/subscriptions/test",
|
|
@@ -67,6 +72,20 @@ test("kernel validates freeform, single-select, and multi-select answers", () =>
|
|
|
67
72
|
{ questionId: "features", value: ["logs", "backup"] },
|
|
68
73
|
]);
|
|
69
74
|
assert.throws(() => validateInputAnswers(questions, [{ questionId: "name", value: "one" }]), /exactly one answer/u);
|
|
75
|
+
assert.deepEqual(validateInputAnswers([...questions, { id: "scale", prompt: "Scale?", optional: true }], [
|
|
76
|
+
{ questionId: "features", value: ["backup", "logs"] },
|
|
77
|
+
{ questionId: "name", value: "demo" },
|
|
78
|
+
{ questionId: "region", value: "sweden" },
|
|
79
|
+
]), [
|
|
80
|
+
{ questionId: "name", value: "demo" },
|
|
81
|
+
{ questionId: "region", value: "sweden" },
|
|
82
|
+
{ questionId: "features", value: ["logs", "backup"] },
|
|
83
|
+
]);
|
|
84
|
+
assert.throws(() => validateInputAnswers(questions, [
|
|
85
|
+
{ questionId: "name", value: "demo" },
|
|
86
|
+
{ questionId: "region", value: "sweden" },
|
|
87
|
+
{ questionId: "features", value: ["logs", "backup", "logs"] },
|
|
88
|
+
]), /Answer repeats an option: features/u);
|
|
70
89
|
assert.throws(() => validateInputAnswers(questions, [
|
|
71
90
|
{ questionId: "name", value: "one" },
|
|
72
91
|
{ questionId: "name", value: "two" },
|
|
@@ -90,6 +109,8 @@ test("kernel validates freeform, single-select, and multi-select answers", () =>
|
|
|
90
109
|
for (const value of ["", " ", "none", "N/A", ["logs", " "]]) {
|
|
91
110
|
assert.throws(() => validateInputAnswers([{ id: "answer", prompt: "Answer?", ...(Array.isArray(value) ? { multiSelect: true } : {}) }], [{ questionId: "answer", value }]), /explicitly provided or deferred/u);
|
|
92
111
|
}
|
|
112
|
+
assert.deepEqual(validateInputAnswers([{ id: "prohibited-services", prompt: "List prohibited services, or use 'none'." }], [{ questionId: "prohibited-services", value: "none" }]), [{ questionId: "prohibited-services", value: "No Azure services are prohibited." }]);
|
|
113
|
+
assert.deepEqual(validateInputAnswers([{ id: "environment-overrides", prompt: "State overrides, or use 'none'." }], [{ questionId: "environment-overrides", value: "none" }]), [{ questionId: "environment-overrides", value: "No environment-specific service or sizing overrides." }]);
|
|
93
114
|
assert.deepEqual(validateInputAnswers([{ id: "answer", prompt: "Answer?" }], [{ questionId: "answer", value: "unknown" }]), [{ questionId: "answer", value: "unknown" }]);
|
|
94
115
|
assert.deepEqual(validateInputAnswers([
|
|
95
116
|
{
|
|
@@ -101,6 +122,16 @@ test("kernel validates freeform, single-select, and multi-select answers", () =>
|
|
|
101
122
|
},
|
|
102
123
|
], [{ questionId: "compliance", value: { kind: "compliance", scopes: ["pci-dss", "gdpr"] } }]), [{ questionId: "compliance", value: { kind: "compliance", scopes: ["gdpr", "pci-dss"] } }]);
|
|
103
124
|
});
|
|
125
|
+
test("validator registry names the allowed values of a failed literal union", () => {
|
|
126
|
+
const registry = new ValidatorRegistry();
|
|
127
|
+
registry.register("status", Type.Object({
|
|
128
|
+
status: Type.Union([Type.Literal("aligned"), Type.Literal("concern")]),
|
|
129
|
+
shape: Type.Union([Type.String(), Type.Integer()]),
|
|
130
|
+
}, { additionalProperties: false }));
|
|
131
|
+
const { issues } = registry.validate("status", { status: "partial", shape: false });
|
|
132
|
+
assert.deepEqual(issues.find(({ path }) => path === "/status"), { path: "/status", message: 'Expected one of: "aligned", "concern"' });
|
|
133
|
+
assert.equal(issues.find(({ path }) => path === "/shape")?.message, "Expected union value");
|
|
134
|
+
});
|
|
104
135
|
test("validator registry caches pure results by content and never caches freshness or authorization", () => {
|
|
105
136
|
const schema = Type.Object({ value: Type.Integer() }, { additionalProperties: false });
|
|
106
137
|
const registry = new ValidatorRegistry();
|