@cleocode/core 2026.10.10 → 2026.10.11
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/dist/build-provenance.json +2 -2
- package/dist/cloud/nexus-cloud-conflicts.d.ts +8 -3
- package/dist/cloud/nexus-cloud-conflicts.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-conflicts.js +21 -5
- package/dist/cloud/nexus-cloud-conflicts.js.map +1 -1
- package/dist/cloud/nexus-cloud-journal-activity.d.ts +15 -1
- package/dist/cloud/nexus-cloud-journal-activity.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-journal-activity.js +8 -2
- package/dist/cloud/nexus-cloud-journal-activity.js.map +1 -1
- package/dist/cloud/nexus-cloud-status.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-status.js +6 -2
- package/dist/cloud/nexus-cloud-status.js.map +1 -1
- package/dist/cloud/nexus-vault.d.ts.map +1 -1
- package/dist/cloud/nexus-vault.js +52 -8
- package/dist/cloud/nexus-vault.js.map +1 -1
- package/dist/cloud/secret-seal.d.ts +31 -0
- package/dist/cloud/secret-seal.d.ts.map +1 -1
- package/dist/cloud/secret-seal.js +82 -4
- package/dist/cloud/secret-seal.js.map +1 -1
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/internal.js.map +1 -1
- package/dist/memory/decision-cross-link.d.ts +5 -2
- package/dist/memory/decision-cross-link.d.ts.map +1 -1
- package/dist/memory/decision-cross-link.js +5 -2
- package/dist/memory/decision-cross-link.js.map +1 -1
- package/dist/memory/decisions.d.ts.map +1 -1
- package/dist/memory/decisions.js +13 -5
- package/dist/memory/decisions.js.map +1 -1
- package/dist/resources/admission-ledger.d.ts +7 -0
- package/dist/resources/admission-ledger.d.ts.map +1 -1
- package/dist/resources/admission-ledger.js +53 -9
- package/dist/resources/admission-ledger.js.map +1 -1
- package/dist/store/migration-runner.d.ts +17 -0
- package/dist/store/migration-runner.d.ts.map +1 -1
- package/dist/store/migration-runner.js +53 -0
- package/dist/store/migration-runner.js.map +1 -1
- package/dist/store/migration-safety.d.ts +406 -0
- package/dist/store/migration-safety.d.ts.map +1 -0
- package/dist/store/migration-safety.js +587 -0
- package/dist/store/migration-safety.js.map +1 -0
- package/dist/store/portable-bundle.d.ts +8 -0
- package/dist/store/portable-bundle.d.ts.map +1 -1
- package/dist/store/portable-bundle.js +5 -0
- package/dist/store/portable-bundle.js.map +1 -1
- package/dist/store/sync/conflicts.d.ts +37 -0
- package/dist/store/sync/conflicts.d.ts.map +1 -1
- package/dist/store/sync/conflicts.js +88 -0
- package/dist/store/sync/conflicts.js.map +1 -1
- package/dist/store/sync/merge/engine.d.ts.map +1 -1
- package/dist/store/sync/merge/engine.js +18 -0
- package/dist/store/sync/merge/engine.js.map +1 -1
- package/dist/store/sync/merge/rules.d.ts +2 -1
- package/dist/store/sync/merge/rules.d.ts.map +1 -1
- package/dist/store/sync/merge/rules.js +9 -2
- package/dist/store/sync/merge/rules.js.map +1 -1
- package/dist/store/sync/merge/types.d.ts +7 -0
- package/dist/store/sync/merge/types.d.ts.map +1 -1
- package/dist/store/sync/reconcile-copy.d.ts +8 -0
- package/dist/store/sync/reconcile-copy.d.ts.map +1 -1
- package/dist/store/sync/reconcile-copy.js +1 -1
- package/dist/store/sync/reconcile-copy.js.map +1 -1
- package/dist/store/sync/sealer.d.ts +5 -1
- package/dist/store/sync/sealer.d.ts.map +1 -1
- package/dist/store/sync/sealer.js +35 -3
- package/dist/store/sync/sealer.js.map +1 -1
- package/dist/store/vault-manifest.d.ts +72 -0
- package/dist/store/vault-manifest.d.ts.map +1 -1
- package/dist/store/vault-manifest.js +134 -0
- package/dist/store/vault-manifest.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +7 -1
- package/dist/tasks/complete.js.map +1 -1
- package/package.json +13 -13
- package/templates/git-hooks/commit-msg +7 -2
- package/templates/git-hooks/legacy-hashes.json +3 -1
- package/templates/git-hooks/pre-push +9 -3
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The migration safety harness (T13448, saga T13339 / epic T13340).
|
|
3
|
+
*
|
|
4
|
+
* Every store move in the CleoDocs re-architecture (the T13360 migration, the
|
|
5
|
+
* T13361/T13362 legacy retirements) wraps its steps in this harness so a
|
|
6
|
+
* migration can never destroy or corrupt an existing project's store without
|
|
7
|
+
* a verified recovery path. Each registered step executes inside a fixed
|
|
8
|
+
* bracket:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Pre-step backup** — a `VACUUM INTO` snapshot of the whole project
|
|
11
|
+
* store via {@link planMigrationSnapshot} + {@link writeMigrationSnapshot}
|
|
12
|
+
* (the same primitives the twin-collapse repairs use, T12535). The
|
|
13
|
+
* snapshot is registered as a `migration` system backup
|
|
14
|
+
* (`.cleo/backups/sqlite/cleo.db.<backupId>` plus its `<backupId>.meta.json`
|
|
15
|
+
* sidecar), so `cleo backup list` shows it and the per-type rotation
|
|
16
|
+
* applies. The sidecar is the step's **backup receipt**; its timestamp
|
|
17
|
+
* feeds the destructive-step guard. Runs OUTSIDE the transaction
|
|
18
|
+
* (`VACUUM INTO` requires it).
|
|
19
|
+
* 2. **`BEGIN IMMEDIATE`** (T13609) — single-writer exclusion for the whole
|
|
20
|
+
* bracket: a concurrent writer can neither interleave between the
|
|
21
|
+
* fingerprints, the run and the verify (masking or forging count/hash
|
|
22
|
+
* results) nor be silently discarded by a later restore.
|
|
23
|
+
* 3. **Run** — the step's `run(ctx)` executes inside the transaction.
|
|
24
|
+
* Table-rebuild recipes use `PRAGMA defer_foreign_keys = ON` (enforced
|
|
25
|
+
* at COMMIT), never `PRAGMA foreign_keys = OFF` (a no-op in a
|
|
26
|
+
* transaction).
|
|
27
|
+
* 4. **Verify** — machine-readable checks: per-table row counts before/after
|
|
28
|
+
* (matching, or explained by the step's declared `expectedDelta`),
|
|
29
|
+
* content-hash spot checks (an order-independent multiset hash over the
|
|
30
|
+
* table's rows, sampled to `sampleSize` rowids when the table is larger),
|
|
31
|
+
* and `PRAGMA foreign_key_check` (must return zero rows).
|
|
32
|
+
* 5. **Commit or roll back** (T13609) — only a fully verified step is
|
|
33
|
+
* COMMITted; a refused, failed or throwing step is ROLLBACKed, so a
|
|
34
|
+
* failed step is never visible in the live store. The restore path
|
|
35
|
+
* remains the backstop for a commit that is later found bad.
|
|
36
|
+
* 6. **Report** — a JSON-serializable {@link MigrationStepReport} per step
|
|
37
|
+
* (including the `transaction` outcome); a failed verification **halts**
|
|
38
|
+
* the runner and names the failed step. {@link rollbackMigrationStep}
|
|
39
|
+
* consumes exactly the report's backup receipt and before-fingerprints.
|
|
40
|
+
*
|
|
41
|
+
* **Destructive guard** — a step declared `destructive: true` refuses to run
|
|
42
|
+
* unless the harness options pass `force: true` AND the step's backup receipt
|
|
43
|
+
* is younger than the step start (which the harness itself guarantees by
|
|
44
|
+
* taking the snapshot first; a failed or skipped backup therefore refuses the
|
|
45
|
+
* step by construction).
|
|
46
|
+
*
|
|
47
|
+
* **Rollback** — {@link rollbackMigrationStep} restores the step's snapshot
|
|
48
|
+
* through {@link restoreStoreSnapshot} (the programmatic core of
|
|
49
|
+
* `cleo restore backup`, T13240: verified copy, live-writer refusal, the
|
|
50
|
+
* replaced store kept as a pinned `pre-restore-*` backup) and then re-proves
|
|
51
|
+
* the restored store against the pre-step fingerprints (counts and content
|
|
52
|
+
* hashes must match exactly).
|
|
53
|
+
*
|
|
54
|
+
* All store access here is read-only verification SQL plus the `VACUUM INTO`
|
|
55
|
+
* snapshot primitive; steps own their own writes and route them through the
|
|
56
|
+
* canonical accessors (gates 28/38).
|
|
57
|
+
*
|
|
58
|
+
* @module
|
|
59
|
+
* @task T13448
|
|
60
|
+
*/
|
|
61
|
+
import { createHash } from 'node:crypto';
|
|
62
|
+
import { ExitCode } from '@cleocode/contracts/exit-codes.js';
|
|
63
|
+
import { CleoError } from '../errors.js';
|
|
64
|
+
import { getLogger } from '../logger.js';
|
|
65
|
+
import { readBackupSidecar } from './backup-sidecar.js';
|
|
66
|
+
import { resolveDualScopeDbPath } from './dual-scope-db.js';
|
|
67
|
+
import { openCleoDbSnapshot } from './open-cleo-db.js';
|
|
68
|
+
import { planMigrationSnapshot, writeMigrationSnapshot } from './pre-repair-snapshot.js';
|
|
69
|
+
import { restoreStoreSnapshot } from './restore-store.js';
|
|
70
|
+
/** Default number of rows content-hash spot-checked per oversized table. */
|
|
71
|
+
export const DEFAULT_VERIFICATION_SAMPLE_SIZE = 200;
|
|
72
|
+
/**
|
|
73
|
+
* Quote one SQLite identifier (table name) for interpolation.
|
|
74
|
+
*/
|
|
75
|
+
function quoteIdent(name) {
|
|
76
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Error message helper — `Error.message` when available, String otherwise.
|
|
80
|
+
*/
|
|
81
|
+
function messageOf(err) {
|
|
82
|
+
return err instanceof Error ? err.message : String(err);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Deterministic, unambiguous serialization of one node:sqlite value for
|
|
86
|
+
* hashing: every value kind gets a tag (`N` null, `n` number, `i` bigint,
|
|
87
|
+
* `s` length-prefixed string, `b` hex blob), so distinct value kinds can
|
|
88
|
+
* never collide.
|
|
89
|
+
*/
|
|
90
|
+
function encodeValue(value) {
|
|
91
|
+
if (value === null || value === undefined)
|
|
92
|
+
return 'N';
|
|
93
|
+
if (typeof value === 'number')
|
|
94
|
+
return `n:${value}`;
|
|
95
|
+
if (typeof value === 'bigint')
|
|
96
|
+
return `i:${value.toString()}`;
|
|
97
|
+
if (typeof value === 'string')
|
|
98
|
+
return `s:${value.length}:${value}`;
|
|
99
|
+
if (value instanceof Uint8Array)
|
|
100
|
+
return `b:${value.length}:${Buffer.from(value).toString('hex')}`;
|
|
101
|
+
return `x:${String(value)}`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* SHA-256 digest of one result row: sorted column names plus tagged values,
|
|
105
|
+
* so it is independent of the row's key order and of physical row order.
|
|
106
|
+
*/
|
|
107
|
+
function rowDigest(row) {
|
|
108
|
+
const hash = createHash('sha256');
|
|
109
|
+
for (const key of Object.keys(row).sort()) {
|
|
110
|
+
hash.update(encodeValue(key));
|
|
111
|
+
hash.update('=');
|
|
112
|
+
hash.update(encodeValue(row[key]));
|
|
113
|
+
hash.update(';');
|
|
114
|
+
}
|
|
115
|
+
return hash.digest('hex');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Combine per-row digests into one table hash: sort the digests and hash the
|
|
119
|
+
* list, making the fingerprint an order-independent multiset hash (a carried
|
|
120
|
+
* table survives a rowid-shuffling rebuild unchanged).
|
|
121
|
+
*/
|
|
122
|
+
function combineDigests(digests) {
|
|
123
|
+
const hash = createHash('sha256');
|
|
124
|
+
for (const digest of [...digests].sort()) {
|
|
125
|
+
hash.update(digest);
|
|
126
|
+
hash.update('\n');
|
|
127
|
+
}
|
|
128
|
+
return hash.digest('hex');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Pick `n` evenly-spaced entries from an already-sorted list (indexes
|
|
132
|
+
* `floor(i * len / n)`), de-duplicated. Deterministic: the same sorted input
|
|
133
|
+
* yields the same sample every time.
|
|
134
|
+
*/
|
|
135
|
+
function evenlySpaced(sorted, n) {
|
|
136
|
+
if (sorted.length <= n)
|
|
137
|
+
return [...sorted];
|
|
138
|
+
const out = [];
|
|
139
|
+
for (let i = 0; i < n; i++) {
|
|
140
|
+
const item = sorted[Math.floor((i * sorted.length) / n)];
|
|
141
|
+
if (item !== undefined && (out.length === 0 || out[out.length - 1] !== item)) {
|
|
142
|
+
out.push(item);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Capture an order-independent content fingerprint of one table.
|
|
149
|
+
*
|
|
150
|
+
* Tables with at most `sampleSize` rows (and `WITHOUT ROWID` tables, which
|
|
151
|
+
* have no rowid to sample) are hashed in full; larger rowid tables are
|
|
152
|
+
* spot-checked on `sampleSize` evenly-spaced rowids. Reads only.
|
|
153
|
+
*
|
|
154
|
+
* @param db - Live native handle.
|
|
155
|
+
* @param table - Table name.
|
|
156
|
+
* @param sampleSize - Full-scan cutoff / sample size (default 200).
|
|
157
|
+
* @returns The fingerprint.
|
|
158
|
+
* @task T13448
|
|
159
|
+
*/
|
|
160
|
+
export function fingerprintTable(db, table, sampleSize = DEFAULT_VERIFICATION_SAMPLE_SIZE) {
|
|
161
|
+
const quoted = quoteIdent(table);
|
|
162
|
+
const count = Number(db.prepare(`SELECT COUNT(*) AS n FROM ${quoted}`).get().n);
|
|
163
|
+
if (count === 0) {
|
|
164
|
+
return { table, count: 0, hash: combineDigests([]), full: true, sampledRowids: [] };
|
|
165
|
+
}
|
|
166
|
+
let rowids = null;
|
|
167
|
+
try {
|
|
168
|
+
rowids = db.prepare(`SELECT rowid AS r FROM ${quoted} ORDER BY rowid`).all().map((row) => row.r);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
rowids = null; // WITHOUT ROWID table: no rowid to sample
|
|
172
|
+
}
|
|
173
|
+
let sample;
|
|
174
|
+
let full;
|
|
175
|
+
if (rowids === null) {
|
|
176
|
+
sample = null;
|
|
177
|
+
full = true;
|
|
178
|
+
}
|
|
179
|
+
else if (count <= sampleSize) {
|
|
180
|
+
sample = rowids;
|
|
181
|
+
full = true;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
sample = evenlySpaced(rowids, sampleSize);
|
|
185
|
+
full = false;
|
|
186
|
+
}
|
|
187
|
+
const digests = [];
|
|
188
|
+
if (sample !== null) {
|
|
189
|
+
const stmt = db.prepare(`SELECT * FROM ${quoted} WHERE rowid = ?`);
|
|
190
|
+
// Real stores carry integers beyond 2^53 (e.g. HLC timestamps); without
|
|
191
|
+
// big-int reads node:sqlite throws converting them to number.
|
|
192
|
+
stmt.setReadBigInts(true);
|
|
193
|
+
for (const rowid of sample) {
|
|
194
|
+
const row = stmt.get(rowid);
|
|
195
|
+
if (row !== undefined)
|
|
196
|
+
digests.push(rowDigest(row));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const rowsStmt = db.prepare(`SELECT * FROM ${quoted}`);
|
|
201
|
+
rowsStmt.setReadBigInts(true);
|
|
202
|
+
const rows = rowsStmt.all();
|
|
203
|
+
for (const row of rows)
|
|
204
|
+
digests.push(rowDigest(row));
|
|
205
|
+
}
|
|
206
|
+
return { table, count, hash: combineDigests(digests), full, sampledRowids: sample ?? [] };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Run `PRAGMA foreign_key_check` and return the violation count. Zero is the
|
|
210
|
+
* only passing value; the pragma reports independently of the
|
|
211
|
+
* `foreign_keys` switch, so a migration that toggles FK enforcement mid-step
|
|
212
|
+
* is still checked. Read-only.
|
|
213
|
+
*
|
|
214
|
+
* @param db - Live native handle.
|
|
215
|
+
* @returns Number of FK violations.
|
|
216
|
+
* @task T13448
|
|
217
|
+
*/
|
|
218
|
+
export function countForeignKeyViolations(db) {
|
|
219
|
+
return db.prepare('PRAGMA foreign_key_check').all().length;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* List user tables (everything except `sqlite_*` internals) in name order.
|
|
223
|
+
* Read-only.
|
|
224
|
+
*/
|
|
225
|
+
function listUserTables(db) {
|
|
226
|
+
return db
|
|
227
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
|
|
228
|
+
.all().map((row) => row.name);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Error text meaning "this table needs a loadable SQLite extension that this
|
|
232
|
+
* connection does not have" (e.g. `vec0` virtual tables without sqlite-vec).
|
|
233
|
+
* Only this read error may skip verification — such tables are
|
|
234
|
+
* content-addressed caches, never the source of truth; anything else stays
|
|
235
|
+
* fail-closed.
|
|
236
|
+
*/
|
|
237
|
+
const NO_SUCH_MODULE = /no such module/i;
|
|
238
|
+
/**
|
|
239
|
+
* Capture the pre- or post-step fingerprint set for the tables in scope.
|
|
240
|
+
* Extension-backed unreadable tables (see {@link NO_SUCH_MODULE}) are
|
|
241
|
+
* returned as skipped, not fatal.
|
|
242
|
+
*/
|
|
243
|
+
function captureFingerprints(db, tables, sampleSize) {
|
|
244
|
+
const names = tables ?? listUserTables(db);
|
|
245
|
+
const fingerprints = [];
|
|
246
|
+
const skipped = [];
|
|
247
|
+
for (const table of names) {
|
|
248
|
+
try {
|
|
249
|
+
fingerprints.push(fingerprintTable(db, table, sampleSize));
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
if (NO_SUCH_MODULE.test(messageOf(err))) {
|
|
253
|
+
skipped.push({ table, reason: messageOf(err) });
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { fingerprints, skipped };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Run migration steps inside the backup → BEGIN IMMEDIATE → migrate → verify
|
|
263
|
+
* → COMMIT/ROLLBACK → report bracket (T13448, T13609). Each step's writes are
|
|
264
|
+
* atomic and write-exclusive: a refused, failed or throwing step is rolled
|
|
265
|
+
* back and never becomes visible in the live store, and no concurrent writer
|
|
266
|
+
* can interleave between the before-fingerprints, the run and the verify.
|
|
267
|
+
* Never throws for verification failures, refusals, or step errors: those are
|
|
268
|
+
* reported and halt the run (AC1, AC4). Throws only for invalid invocation
|
|
269
|
+
* (no steps).
|
|
270
|
+
*
|
|
271
|
+
* @param steps - The registered steps, in execution order.
|
|
272
|
+
* @param opts - The store handle, project, force flag and hooks.
|
|
273
|
+
* @returns The machine-readable run report. On `halted`/`refused`, the last
|
|
274
|
+
* step report carries the backup receipt and before-fingerprints needed by
|
|
275
|
+
* {@link rollbackMigrationStep} (the backstop for a commit later found bad).
|
|
276
|
+
* @task T13448
|
|
277
|
+
* @task T13609 — transactional bracket; failed steps are never visible
|
|
278
|
+
*/
|
|
279
|
+
export async function runMigrationSteps(steps, opts) {
|
|
280
|
+
if (steps.length === 0) {
|
|
281
|
+
// @sync-invariant none:input-shape nothing was asked of the store
|
|
282
|
+
throw new CleoError(ExitCode.INVALID_INPUT, 'runMigrationSteps: at least one step is required');
|
|
283
|
+
}
|
|
284
|
+
const dbPath = opts.dbPath ?? resolveDualScopeDbPath('project', opts.projectRoot);
|
|
285
|
+
const sampleSize = opts.sampleSize ?? DEFAULT_VERIFICATION_SAMPLE_SIZE;
|
|
286
|
+
const logger = getLogger('migration-safety');
|
|
287
|
+
const reports = [];
|
|
288
|
+
for (const step of steps) {
|
|
289
|
+
const startedAt = new Date();
|
|
290
|
+
const stepStartMs = startedAt.getTime();
|
|
291
|
+
const clockStart = Date.now();
|
|
292
|
+
const spec = step.verify ?? {};
|
|
293
|
+
const skipHash = new Set(spec.skipHash ?? []);
|
|
294
|
+
const stepSampleSize = spec.sampleSize ?? sampleSize;
|
|
295
|
+
const failures = [];
|
|
296
|
+
let backup = null;
|
|
297
|
+
let runError = null;
|
|
298
|
+
let status = 'completed';
|
|
299
|
+
const verifications = [];
|
|
300
|
+
let beforeTables = [];
|
|
301
|
+
let unreadableTables = [];
|
|
302
|
+
let addedTables = [];
|
|
303
|
+
let removedTables = [];
|
|
304
|
+
let fkViolations = 0;
|
|
305
|
+
let transaction = 'none';
|
|
306
|
+
// 1. Pre-step VACUUM INTO backup, registered as a migration system
|
|
307
|
+
// backup whose sidecar is this step's receipt (T12535 machinery).
|
|
308
|
+
// Runs OUTSIDE the transaction — VACUUM INTO requires it.
|
|
309
|
+
try {
|
|
310
|
+
const plan = planMigrationSnapshot(opts.db, dbPath);
|
|
311
|
+
const snapshotPath = writeMigrationSnapshot(opts.db, plan, `migration step: ${step.name}${step.description ? ` — ${step.description}` : ''} (T13448)`);
|
|
312
|
+
const receipt = readBackupSidecar(snapshotPath, 'migration');
|
|
313
|
+
backup = {
|
|
314
|
+
backupId: plan.backupId,
|
|
315
|
+
snapshotPath,
|
|
316
|
+
timestamp: receipt?.timestamp ?? new Date().toISOString(),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
status = 'failed';
|
|
321
|
+
runError = `pre-step backup failed: ${messageOf(err)}`;
|
|
322
|
+
}
|
|
323
|
+
// 2. BEGIN IMMEDIATE (T13609): single-writer exclusion for the whole
|
|
324
|
+
// fingerprint → run → verify bracket, so a concurrent writer can
|
|
325
|
+
// neither interleave (masking or forging count/hash results) nor be
|
|
326
|
+
// silently discarded by a later restore. Writers wait on
|
|
327
|
+
// busy_timeout, then fail with SQLITE_BUSY.
|
|
328
|
+
if (status === 'completed') {
|
|
329
|
+
try {
|
|
330
|
+
opts.db.exec('BEGIN IMMEDIATE');
|
|
331
|
+
transaction = 'rolled-back'; // until COMMIT proves otherwise
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
status = 'failed';
|
|
335
|
+
runError = `BEGIN IMMEDIATE failed: ${messageOf(err)}`;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// 3. Destructive guard: refuse without force AND a receipt younger than
|
|
339
|
+
// the step start (AC: owner directive 2026-10-10). Inside the lock,
|
|
340
|
+
// before any fingerprint work.
|
|
341
|
+
if (status === 'completed' && step.destructive === true) {
|
|
342
|
+
const receiptFresh = backup !== null && Date.parse(backup.timestamp) >= stepStartMs;
|
|
343
|
+
if (opts.force !== true || !receiptFresh) {
|
|
344
|
+
status = 'refused';
|
|
345
|
+
failures.push('destructive step refused: requires force AND a backup receipt younger than the step start');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// 4. Before-fingerprints, inside the lock (T13609): the store they will
|
|
349
|
+
// be compared against cannot move underneath the bracket.
|
|
350
|
+
if (status === 'completed') {
|
|
351
|
+
try {
|
|
352
|
+
const captured = captureFingerprints(opts.db, spec.tables, stepSampleSize);
|
|
353
|
+
beforeTables = captured.fingerprints;
|
|
354
|
+
unreadableTables = captured.skipped;
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
status = 'failed';
|
|
358
|
+
runError = `before-fingerprint capture failed: ${messageOf(err)}`;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// 5. Run the step, inside the transaction.
|
|
362
|
+
if (status === 'completed') {
|
|
363
|
+
const log = (message) => {
|
|
364
|
+
logger.info({ step: step.name }, message);
|
|
365
|
+
};
|
|
366
|
+
try {
|
|
367
|
+
await step.run({ db: opts.db, projectRoot: opts.projectRoot, dbPath, log });
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
status = 'failed';
|
|
371
|
+
runError = messageOf(err);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// 6. Verify: counts (or declared deltas), content-hash spot checks, FK.
|
|
375
|
+
if (status === 'completed') {
|
|
376
|
+
try {
|
|
377
|
+
fkViolations = countForeignKeyViolations(opts.db);
|
|
378
|
+
const beforeNames = new Set(beforeTables.map((fp) => fp.table));
|
|
379
|
+
const afterNames = new Set(listUserTables(opts.db));
|
|
380
|
+
addedTables = [...afterNames].filter((name) => !beforeNames.has(name));
|
|
381
|
+
removedTables = [...beforeNames].filter((name) => !afterNames.has(name));
|
|
382
|
+
// A table skipped before the step (unreadable, e.g. a vec0 virtual
|
|
383
|
+
// table without its extension) must still EXIST afterwards: removal
|
|
384
|
+
// of a skipped table is invisible to the count/hash checks, so a
|
|
385
|
+
// step that drops one on this connection would go undetected.
|
|
386
|
+
for (const skipped of unreadableTables) {
|
|
387
|
+
if (!afterNames.has(skipped.table)) {
|
|
388
|
+
failures.push(`table ${skipped.table} was unreadable before the step (${skipped.reason}) and is missing after it`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const before of beforeTables) {
|
|
392
|
+
const expectedDelta = spec.expectedDelta?.[before.table] ?? 0;
|
|
393
|
+
if (!afterNames.has(before.table)) {
|
|
394
|
+
failures.push(`table ${before.table} was removed by the step`);
|
|
395
|
+
verifications.push({
|
|
396
|
+
table: before.table,
|
|
397
|
+
before,
|
|
398
|
+
after: null,
|
|
399
|
+
expectedDelta,
|
|
400
|
+
countOk: false,
|
|
401
|
+
hashOk: null,
|
|
402
|
+
});
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const after = fingerprintTable(opts.db, before.table, stepSampleSize);
|
|
406
|
+
const countOk = after.count === before.count + expectedDelta;
|
|
407
|
+
// A non-zero declared delta legitimately reshapes the table: the
|
|
408
|
+
// count is the contract there, the hash check applies to carried
|
|
409
|
+
// (zero-delta, not skip-listed) tables.
|
|
410
|
+
const hashChecked = expectedDelta === 0 && !skipHash.has(before.table);
|
|
411
|
+
const hashOk = hashChecked ? after.hash === before.hash : null;
|
|
412
|
+
if (!countOk) {
|
|
413
|
+
failures.push(`table ${before.table}: row count ${after.count} != ${before.count} + ${expectedDelta} (expected delta not explained)`);
|
|
414
|
+
}
|
|
415
|
+
if (hashOk === false) {
|
|
416
|
+
failures.push(`table ${before.table}: content hash changed (carried-table spot check failed)`);
|
|
417
|
+
}
|
|
418
|
+
verifications.push({
|
|
419
|
+
table: before.table,
|
|
420
|
+
before,
|
|
421
|
+
after,
|
|
422
|
+
expectedDelta,
|
|
423
|
+
countOk,
|
|
424
|
+
hashOk,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
if (removedTables.length > 0) {
|
|
428
|
+
failures.push(`tables removed by the step: ${removedTables.join(', ')}`);
|
|
429
|
+
}
|
|
430
|
+
// Guard for the blind spot: a table skipped in the before-capture
|
|
431
|
+
// (extension-backed, e.g. vec0 without sqlite-vec loaded) never made
|
|
432
|
+
// it into beforeTables, so the loop above cannot notice the step
|
|
433
|
+
// dropping it. Its absence afterwards is only explainable by the
|
|
434
|
+
// step — fail closed.
|
|
435
|
+
for (const unreadable of unreadableTables) {
|
|
436
|
+
if (!afterNames.has(unreadable.table)) {
|
|
437
|
+
failures.push(`table ${unreadable.table} was removed by the step (skipped before: ${unreadable.reason})`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (fkViolations > 0) {
|
|
441
|
+
failures.push(`PRAGMA foreign_key_check returned ${fkViolations} violation(s) after the step`);
|
|
442
|
+
}
|
|
443
|
+
if (failures.length > 0)
|
|
444
|
+
status = 'failed';
|
|
445
|
+
}
|
|
446
|
+
catch (err) {
|
|
447
|
+
status = 'failed';
|
|
448
|
+
runError = `verification failed: ${messageOf(err)}`;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// 7. Commit only a fully verified step; roll everything else back, so a
|
|
452
|
+
// failed step is never visible in the live store (T13609 AC1/AC3). A
|
|
453
|
+
// COMMIT error (e.g. a deferred foreign-key violation surfacing at
|
|
454
|
+
// commit time) rolls back too.
|
|
455
|
+
if (transaction === 'rolled-back') {
|
|
456
|
+
if (status === 'completed') {
|
|
457
|
+
try {
|
|
458
|
+
opts.db.exec('COMMIT');
|
|
459
|
+
transaction = 'committed';
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
try {
|
|
463
|
+
opts.db.exec('ROLLBACK');
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// best effort — the transaction may already be closed
|
|
467
|
+
}
|
|
468
|
+
status = 'failed';
|
|
469
|
+
if (runError === null)
|
|
470
|
+
runError = `COMMIT failed: ${messageOf(err)}`;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
try {
|
|
475
|
+
opts.db.exec('ROLLBACK');
|
|
476
|
+
}
|
|
477
|
+
catch {
|
|
478
|
+
// best effort — the step may have closed the transaction itself
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const report = {
|
|
483
|
+
step: step.name,
|
|
484
|
+
destructive: step.destructive === true,
|
|
485
|
+
status,
|
|
486
|
+
startedAt: startedAt.toISOString(),
|
|
487
|
+
durationMs: Date.now() - clockStart,
|
|
488
|
+
backup,
|
|
489
|
+
tables: verifications,
|
|
490
|
+
addedTables,
|
|
491
|
+
removedTables,
|
|
492
|
+
foreignKeyViolations: fkViolations,
|
|
493
|
+
unreadableTables,
|
|
494
|
+
transaction,
|
|
495
|
+
failures,
|
|
496
|
+
runError,
|
|
497
|
+
};
|
|
498
|
+
reports.push(report);
|
|
499
|
+
opts.onStepReport?.(report);
|
|
500
|
+
if (status === 'completed') {
|
|
501
|
+
logger.info({ step: step.name, backupId: backup?.backupId ?? null, tables: verifications.length }, 'migration step verified and committed (T13448)');
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
logger.warn({ step: step.name, status, failures, runError, transaction }, 'migration step failed; transaction rolled back, store unchanged, restore path ready (T13448/T13609)');
|
|
505
|
+
return {
|
|
506
|
+
status: status === 'refused' ? 'refused' : 'halted',
|
|
507
|
+
steps: reports,
|
|
508
|
+
haltedStep: step.name,
|
|
509
|
+
failure: failures[0] ?? runError ?? 'step failed',
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return { status: 'completed', steps: reports, haltedStep: null, failure: null };
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Roll back one migration step: restore its pre-step snapshot through the
|
|
517
|
+
* programmatic core of `cleo restore backup` ({@link restoreStoreSnapshot} —
|
|
518
|
+
* verified copy, quiescence/live-writer refusal, the replaced store kept as
|
|
519
|
+
* a pinned `pre-restore-*` backup), then re-prove the restored store against
|
|
520
|
+
* the step's pre-step fingerprints. This is the tested rollback path of AC3.
|
|
521
|
+
*
|
|
522
|
+
* Note: the restore closes every in-process handle on the store (T13240
|
|
523
|
+
* quiescence) — discard any native handle captured before calling this and
|
|
524
|
+
* re-open through the chokepoint afterwards.
|
|
525
|
+
*
|
|
526
|
+
* @param params - The step, its backup receipt and its before-fingerprints.
|
|
527
|
+
* @returns The rollback report; `verified` is the assertion surface.
|
|
528
|
+
* @task T13448
|
|
529
|
+
*/
|
|
530
|
+
export async function rollbackMigrationStep(params) {
|
|
531
|
+
const sampleSize = params.sampleSize ?? DEFAULT_VERIFICATION_SAMPLE_SIZE;
|
|
532
|
+
const result = await restoreStoreSnapshot({
|
|
533
|
+
projectRoot: params.projectRoot,
|
|
534
|
+
cwd: params.cwd,
|
|
535
|
+
snapshot: params.backup.snapshotPath,
|
|
536
|
+
...(params.confirmOwnerStore !== undefined
|
|
537
|
+
? { confirmOwnerStore: params.confirmOwnerStore }
|
|
538
|
+
: {}),
|
|
539
|
+
});
|
|
540
|
+
const failures = [];
|
|
541
|
+
const tables = [];
|
|
542
|
+
if (!result.restored) {
|
|
543
|
+
failures.push('restoreStoreSnapshot did not place the snapshot');
|
|
544
|
+
}
|
|
545
|
+
const restored = openCleoDbSnapshot(result.target, { readOnly: true });
|
|
546
|
+
try {
|
|
547
|
+
for (const expected of params.before) {
|
|
548
|
+
let actual = null;
|
|
549
|
+
let skipped = null;
|
|
550
|
+
try {
|
|
551
|
+
actual = fingerprintTable(restored.db, expected.table, sampleSize);
|
|
552
|
+
}
|
|
553
|
+
catch (err) {
|
|
554
|
+
if (NO_SUCH_MODULE.test(messageOf(err))) {
|
|
555
|
+
// Extension-backed cache table (e.g. vec0 without sqlite-vec on
|
|
556
|
+
// this read-only connection): nothing to compare, cannot fail.
|
|
557
|
+
skipped = messageOf(err);
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
actual = null; // table absent from (or unreadable in) the restored store
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const countOk = skipped !== null || (actual !== null && actual.count === expected.count);
|
|
564
|
+
const hashOk = skipped !== null || (actual !== null && actual.hash === expected.hash);
|
|
565
|
+
if (skipped === null && !countOk) {
|
|
566
|
+
failures.push(`rollback verify: ${expected.table} row count ${actual?.count ?? 'unreadable'} != pre-step ${expected.count}`);
|
|
567
|
+
}
|
|
568
|
+
if (skipped === null && !hashOk) {
|
|
569
|
+
failures.push(`rollback verify: ${expected.table} content hash differs from the pre-step snapshot`);
|
|
570
|
+
}
|
|
571
|
+
tables.push({ table: expected.table, expected, actual, countOk, hashOk, skipped });
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
finally {
|
|
575
|
+
restored.close();
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
step: params.step,
|
|
579
|
+
restored: result.restored,
|
|
580
|
+
verified: failures.length === 0,
|
|
581
|
+
undo: result.undo,
|
|
582
|
+
keptBackupId: result.kept?.backupId ?? null,
|
|
583
|
+
tables,
|
|
584
|
+
failures,
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
//# sourceMappingURL=migration-safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-safety.js","sourceRoot":"","sources":["../../src/store/migration-safety.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAgP1D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,GAAY;IAC7B,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,EAAE,CAAC;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;IAC9D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;IACnE,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,KAAK,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAClG,OAAO,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,GAA4B;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,OAA0B;IAChD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACzC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAI,MAAoB,EAAE,CAAS;IACtD,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAgB,EAChB,KAAa,EACb,aAAqB,gCAAgC;IAErD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CACjB,EAAE,CAAC,OAAO,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAC7E,CAAC;IACF,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;IACtF,CAAC;IACD,IAAI,MAAM,GAAkC,IAAI,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,GACJ,EAAE,CAAC,OAAO,CAAC,0BAA0B,MAAM,iBAAiB,CAAC,CAAC,GAAG,EAGlE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,IAAI,CAAC,CAAC,0CAA0C;IAC3D,CAAC;IACD,IAAI,MAAqC,CAAC;IAC1C,IAAI,IAAa,CAAC;IAClB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,GAAG,IAAI,CAAC;QACd,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;SAAM,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,GAAG,MAAM,CAAC;QAChB,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC1C,IAAI,GAAG,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,iBAAiB,MAAM,kBAAkB,CAAC,CAAC;QACnE,wEAAwE;QACxE,8DAA8D;QAC9D,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAwC,CAAC;YACnE,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAC;QACvD,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAoC,CAAC;QAC9D,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;AAC5F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CAAC,EAAgB;IACxD,OAAO,EAAE,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,EAAgB;IACtC,OACE,EAAE;SACC,OAAO,CACN,gGAAgG,CACjG;SACA,GAAG,EACP,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC;;;;GAIG;AACH,SAAS,mBAAmB,CAC1B,EAAgB,EAChB,MAAqC,EACrC,UAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAuB,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACxC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChD,SAAS;YACX,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA+B,EAC/B,IAA6B;IAE7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,kEAAkE;QAClE,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,kDAAkD,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,sBAAsB,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClF,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,gCAAgC,CAAC;IACvE,MAAM,MAAM,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAC7C,MAAM,OAAO,GAA0B,EAAE,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC;QACrD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,MAAM,GAA6B,IAAI,CAAC;QAC5C,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,MAAM,GAAwB,WAAW,CAAC;QAC9C,MAAM,aAAa,GAAwB,EAAE,CAAC;QAC9C,IAAI,YAAY,GAAuB,EAAE,CAAC;QAC1C,IAAI,gBAAgB,GAAsB,EAAE,CAAC;QAC7C,IAAI,WAAW,GAAa,EAAE,CAAC;QAC/B,IAAI,aAAa,GAAa,EAAE,CAAC;QACjC,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,WAAW,GAAuC,MAAM,CAAC;QAE7D,mEAAmE;QACnE,qEAAqE;QACrE,6DAA6D;QAC7D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YACpD,MAAM,YAAY,GAAG,sBAAsB,CACzC,IAAI,CAAC,EAAE,EACP,IAAI,EACJ,mBAAmB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,CAC3F,CAAC;YACF,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;YAC7D,MAAM,GAAG;gBACP,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,YAAY;gBACZ,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aAC1D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,QAAQ,CAAC;YAClB,QAAQ,GAAG,2BAA2B,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACzD,CAAC;QAED,qEAAqE;QACrE,oEAAoE;QACpE,uEAAuE;QACvE,4DAA4D;QAC5D,+CAA+C;QAC/C,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAChC,WAAW,GAAG,aAAa,CAAC,CAAC,gCAAgC;YAC/D,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,QAAQ,CAAC;gBAClB,QAAQ,GAAG,2BAA2B,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACzD,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,kCAAkC;QAClC,IAAI,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YACxD,MAAM,YAAY,GAAG,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,WAAW,CAAC;YACpF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACzC,MAAM,GAAG,SAAS,CAAC;gBACnB,QAAQ,CAAC,IAAI,CACX,2FAA2F,CAC5F,CAAC;YACJ,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,6DAA6D;QAC7D,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;gBAC3E,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;gBACrC,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC;YACtC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,QAAQ,CAAC;gBAClB,QAAQ,GAAG,sCAAsC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACpE,CAAC;QACH,CAAC;QAED,2CAA2C;QAC3C,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,CAAC,OAAe,EAAQ,EAAE;gBACpC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;YAC5C,CAAC,CAAC;YACF,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YAC9E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,QAAQ,CAAC;gBAClB,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,YAAY,GAAG,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;gBAChE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpD,WAAW,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBACvE,aAAa,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBACzE,mEAAmE;gBACnE,oEAAoE;gBACpE,iEAAiE;gBACjE,8DAA8D;gBAC9D,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;oBACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBACnC,QAAQ,CAAC,IAAI,CACX,SAAS,OAAO,CAAC,KAAK,oCAAoC,OAAO,CAAC,MAAM,2BAA2B,CACpG,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;oBAClC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC9D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;wBAClC,QAAQ,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,KAAK,0BAA0B,CAAC,CAAC;wBAC/D,aAAa,CAAC,IAAI,CAAC;4BACjB,KAAK,EAAE,MAAM,CAAC,KAAK;4BACnB,MAAM;4BACN,KAAK,EAAE,IAAI;4BACX,aAAa;4BACb,OAAO,EAAE,KAAK;4BACd,MAAM,EAAE,IAAI;yBACb,CAAC,CAAC;wBACH,SAAS;oBACX,CAAC;oBACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;oBACtE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,GAAG,aAAa,CAAC;oBAC7D,iEAAiE;oBACjE,iEAAiE;oBACjE,wCAAwC;oBACxC,MAAM,WAAW,GAAG,aAAa,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACvE,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,QAAQ,CAAC,IAAI,CACX,SAAS,MAAM,CAAC,KAAK,eAAe,KAAK,CAAC,KAAK,OAAO,MAAM,CAAC,KAAK,MAAM,aAAa,iCAAiC,CACvH,CAAC;oBACJ,CAAC;oBACD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;wBACrB,QAAQ,CAAC,IAAI,CACX,SAAS,MAAM,CAAC,KAAK,0DAA0D,CAChF,CAAC;oBACJ,CAAC;oBACD,aAAa,CAAC,IAAI,CAAC;wBACjB,KAAK,EAAE,MAAM,CAAC,KAAK;wBACnB,MAAM;wBACN,KAAK;wBACL,aAAa;wBACb,OAAO;wBACP,MAAM;qBACP,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,QAAQ,CAAC,IAAI,CAAC,+BAA+B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC3E,CAAC;gBACD,kEAAkE;gBAClE,qEAAqE;gBACrE,iEAAiE;gBACjE,iEAAiE;gBACjE,sBAAsB;gBACtB,KAAK,MAAM,UAAU,IAAI,gBAAgB,EAAE,CAAC;oBAC1C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtC,QAAQ,CAAC,IAAI,CACX,SAAS,UAAU,CAAC,KAAK,6CAA6C,UAAU,CAAC,MAAM,GAAG,CAC3F,CAAC;oBACJ,CAAC;gBACH,CAAC;gBACD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;oBACrB,QAAQ,CAAC,IAAI,CACX,qCAAqC,YAAY,8BAA8B,CAChF,CAAC;gBACJ,CAAC;gBACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;oBAAE,MAAM,GAAG,QAAQ,CAAC;YAC7C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,GAAG,QAAQ,CAAC;gBAClB,QAAQ,GAAG,wBAAwB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACtD,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,sEAAsE;QACtE,kCAAkC;QAClC,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;YAClC,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;gBAC3B,IAAI,CAAC;oBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACvB,WAAW,GAAG,WAAW,CAAC;gBAC5B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,IAAI,CAAC;wBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAC3B,CAAC;oBAAC,MAAM,CAAC;wBACP,sDAAsD;oBACxD,CAAC;oBACD,MAAM,GAAG,QAAQ,CAAC;oBAClB,IAAI,QAAQ,KAAK,IAAI;wBAAE,QAAQ,GAAG,kBAAkB,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC;oBACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBAAC,MAAM,CAAC;oBACP,gEAAgE;gBAClE,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAwB;YAClC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW,KAAK,IAAI;YACtC,MAAM;YACN,SAAS,EAAE,SAAS,CAAC,WAAW,EAAE;YAClC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU;YACnC,MAAM;YACN,MAAM,EAAE,aAAa;YACrB,WAAW;YACX,aAAa;YACb,oBAAoB,EAAE,YAAY;YAClC,gBAAgB;YAChB,WAAW;YACX,QAAQ;YACR,QAAQ;SACT,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,EACrF,gDAAgD,CACjD,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,EAC5D,qGAAqG,CACtG,CAAC;YACF,OAAO;gBACL,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;gBACnD,KAAK,EAAE,OAAO;gBACd,UAAU,EAAE,IAAI,CAAC,IAAI;gBACrB,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,IAAI,aAAa;aAClD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAClF,CAAC;AA6DD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAA+B;IAE/B,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,gCAAgC,CAAC;IACzE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;QACxC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY;QACpC,GAAG,CAAC,MAAM,CAAC,iBAAiB,KAAK,SAAS;YACxC,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE;YACjD,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,MAAM,GAA4B,IAAI,CAAC;YAC3C,IAAI,OAAO,GAAkB,IAAI,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACrE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBACxC,gEAAgE;oBAChE,+DAA+D;oBAC/D,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC3B,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,IAAI,CAAC,CAAC,0DAA0D;gBAC3E,CAAC;YACH,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC;YACzF,MAAM,MAAM,GAAG,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC;YACtF,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjC,QAAQ,CAAC,IAAI,CACX,oBAAoB,QAAQ,CAAC,KAAK,cAAc,MAAM,EAAE,KAAK,IAAI,YAAY,gBAAgB,QAAQ,CAAC,KAAK,EAAE,CAC9G,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,QAAQ,CAAC,IAAI,CACX,oBAAoB,QAAQ,CAAC,KAAK,kDAAkD,CACrF,CAAC;YACJ,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,IAAI,IAAI;QAC3C,MAAM;QACN,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
*/
|
|
34
34
|
import type { PortableBundleManifest, PortableBundleScope, PortableDatabaseEntry, PortableExportResult, PortableImportResult, PortableSectionBase, PortableSkippedProject, PortableUnmigratedLegacyReport } from '@cleocode/contracts';
|
|
35
35
|
import { type SectionRules } from './portable-bundle-scan.js';
|
|
36
|
+
import { type SealedCredentialCell } from './vault-manifest.js';
|
|
36
37
|
/** Symbolic error codes raised by the portable bundle export/import. */
|
|
37
38
|
export type PortableBundleErrorCode = 'E_PRIMARY_STORE_MISSING' | 'E_PRIMARY_STORE_UNREADABLE' | 'E_NO_PROJECT' | 'E_REGISTRY_UNREADABLE' | 'E_PASSPHRASE_REQUIRED' | 'E_BUNDLE_DECRYPT' | 'E_BUNDLE_FORMAT' | 'E_BUNDLE_INTEGRITY' | 'E_DATA_EXISTS' | 'E_TARGET_AMBIGUOUS' | 'E_RESTORE_MISMATCH' | 'E_REDACTION_FAILED' | 'E_PROJECT_STORE_UNAVAILABLE';
|
|
38
39
|
/**
|
|
@@ -117,6 +118,13 @@ export interface ExportPortableBundleInput {
|
|
|
117
118
|
* cloud vault leaves tracked files to git (T13019). Project scope only.
|
|
118
119
|
*/
|
|
119
120
|
gitTrackedFiles?: ReadonlySet<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Seal the primary store snapshot's credential cells before they are
|
|
123
|
+
* cleared; the sealed cells are written to the snapshot's
|
|
124
|
+
* sealed-credentials table (`vault-manifest.ts`). The cloud vault seals under the
|
|
125
|
+
* account key, so a joining device gets usable credentials (T13530).
|
|
126
|
+
*/
|
|
127
|
+
sealCredentials?: (snapshotPath: string) => Promise<readonly SealedCredentialCell[]>;
|
|
120
128
|
}
|
|
121
129
|
/** A registered project row read from the global registry snapshot. */
|
|
122
130
|
interface RegistryRow {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portable-bundle.d.ts","sourceRoot":"","sources":["../../src/store/portable-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAQH,OAAO,KAAK,EAGV,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EAEpB,oBAAoB,EAEpB,mBAAmB,EACnB,sBAAsB,EAEtB,8BAA8B,EAC/B,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAaL,KAAK,YAAY,EAIlB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"portable-bundle.d.ts","sourceRoot":"","sources":["../../src/store/portable-bundle.ts"],"names":[],"mappings":"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"}
|