@evomap/evolver-core 2.0.0-beta.1 → 2.0.0-beta.10
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/assets/gep/genes.jsonl +5 -0
- package/dist/algo/candidateAssembly.js +23 -14
- package/dist/algo/capabilityCandidates.d.ts +2 -0
- package/dist/algo/capabilityCandidates.js +5 -0
- package/dist/algo/conversationSniffer.d.ts +18 -0
- package/dist/algo/conversationSniffer.js +149 -0
- package/dist/algo/cycleEngine.d.ts +11 -0
- package/dist/algo/cycleEngine.js +14 -6
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/cycleFailureClassifier.js +13 -5
- package/dist/algo/geneIntake.d.ts +14 -4
- package/dist/algo/geneIntake.js +37 -9
- package/dist/algo/geneSelection.d.ts +18 -1
- package/dist/algo/geneSelection.js +42 -18
- package/dist/algo/index.d.ts +2 -0
- package/dist/algo/index.js +2 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +3 -0
- package/dist/algo/orchestrator.js +14 -2
- package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
- package/dist/assetstore/assetSidecarRecords.js +376 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +75 -0
- package/dist/assetstore/assetStoreHealth.js +277 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +327 -0
- package/dist/assetstore/assetSyncLedger.d.ts +118 -0
- package/dist/assetstore/assetSyncLedger.js +745 -0
- package/dist/assetstore/index.d.ts +5 -1
- package/dist/assetstore/index.js +5 -1
- package/dist/assetstore/localJsonl.d.ts +12 -3
- package/dist/assetstore/localJsonl.js +131 -39
- package/dist/assetstore/pendingSignals.js +3 -1
- package/dist/assetstore/provenance.d.ts +27 -4
- package/dist/assetstore/provenance.js +107 -56
- package/dist/assetstore/provider.d.ts +26 -0
- package/dist/assetstore/provider.js +50 -0
- package/dist/assetstore/reviewFilter.js +5 -2
- package/dist/assetstore/reviewLedger.d.ts +14 -2
- package/dist/assetstore/reviewLedger.js +78 -43
- package/dist/assetstore/seedGenes.d.ts +3 -0
- package/dist/assetstore/seedGenes.js +134 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +11 -1
- package/dist/benchmark/antiGeneImpact.d.ts +16 -0
- package/dist/benchmark/antiGeneImpact.js +34 -0
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +13 -1
- package/dist/benchmark/index.d.ts +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/events/eventArchive.d.ts +65 -0
- package/dist/events/eventArchive.js +343 -0
- package/dist/events/eventStore.js +2 -12
- package/dist/events/ingest.d.ts +1 -1
- package/dist/events/ingest.js +9 -0
- package/dist/events/paths.d.ts +10 -10
- package/dist/events/paths.js +20 -20
- package/dist/events/public.d.ts +3 -1
- package/dist/events/public.js +2 -1
- package/dist/events/retention.d.ts +24 -1
- package/dist/events/retention.js +133 -37
- package/dist/exec/autoExec.d.ts +6 -1
- package/dist/exec/autoExec.js +34 -0
- package/dist/exec/autonomousCycle.d.ts +2 -0
- package/dist/exec/autonomousCycle.js +5 -0
- package/dist/exec/claudeBridge.d.ts +21 -3
- package/dist/exec/claudeBridge.js +413 -26
- package/dist/exec/openPrRegistry.d.ts +8 -2
- package/dist/exec/openPrRegistry.js +32 -22
- package/dist/exec/prompt.js +9 -0
- package/dist/exec/runnerRegistry.d.ts +90 -18
- package/dist/exec/runnerRegistry.js +603 -42
- package/dist/exec/selfPrObfuscation.d.ts +2 -1
- package/dist/exec/selfPrObfuscation.js +19 -6
- package/dist/hub/agentDirectory.d.ts +90 -0
- package/dist/hub/agentDirectory.js +104 -0
- package/dist/hub/bindings.js +23 -3
- package/dist/hub/capability.d.ts +14 -2
- package/dist/hub/fake.d.ts +4 -2
- package/dist/hub/fake.js +3 -2
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/sanitize.js +3 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/issueReporter/index.d.ts +156 -0
- package/dist/issueReporter/index.js +1688 -0
- package/dist/mailbox/catalog.js +3 -0
- package/dist/mailbox/ipcServer.js +2 -2
- package/dist/mailbox/store.d.ts +14 -0
- package/dist/mailbox/store.js +44 -2
- package/dist/material/consumer.js +9 -6
- package/dist/material/index.d.ts +1 -0
- package/dist/material/index.js +1 -0
- package/dist/material/materialArchive.d.ts +81 -0
- package/dist/material/materialArchive.js +466 -0
- package/dist/material/materialStore.d.ts +1 -0
- package/dist/material/materialStore.js +6 -13
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +10 -1
- package/dist/ops/selfUpdate.js +64 -15
- package/dist/personality/schema.d.ts +12 -12
- package/dist/schema/common.d.ts +1 -1
- package/dist/schema/common.js +1 -1
- package/dist/schema/material.d.ts +5 -5
- package/dist/strategy/constraintAblation.d.ts +64 -0
- package/dist/strategy/constraintAblation.js +3074 -0
- package/dist/strategy/index.d.ts +2 -1
- package/dist/strategy/index.js +2 -1
- package/dist/trace/trajectoryExport.js +2 -2
- package/dist/util/fetchPort.d.ts +1 -0
- package/dist/util/fetchPort.js +11 -0
- package/dist/util/fileLock.d.ts +24 -5
- package/dist/util/fileLock.js +288 -72
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/wire/geneHints.d.ts +42 -1
- package/dist/wire/geneHints.js +52 -1
- package/dist/wire/index.d.ts +14 -2
- package/dist/wire/index.js +1 -1
- package/dist/workflow/dsl.d.ts +24 -3
- package/dist/workflow/dsl.js +4 -0
- package/dist/workflow/engine.d.ts +5 -1
- package/dist/workflow/engine.js +3 -0
- package/dist/workflow/index.d.ts +3 -1
- package/dist/workflow/index.js +3 -1
- package/dist/workflow/runtime.d.ts +110 -0
- package/dist/workflow/runtime.js +1298 -0
- package/dist/workflow/stateStore.d.ts +172 -0
- package/dist/workflow/stateStore.js +1044 -0
- package/package.json +6 -1
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
export class CorruptAssetSidecarError extends Error {
|
|
2
|
+
sidecar;
|
|
3
|
+
reason;
|
|
4
|
+
code = 'CORRUPT_ASSET_SIDECAR';
|
|
5
|
+
constructor(sidecar, reason) {
|
|
6
|
+
super(`corrupt asset sidecar: ${sidecar}/${reason}`);
|
|
7
|
+
this.sidecar = sidecar;
|
|
8
|
+
this.reason = reason;
|
|
9
|
+
this.name = 'CorruptAssetSidecarError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function parseSidecarJsonl(raw, parseRecord) {
|
|
13
|
+
const records = [];
|
|
14
|
+
let rows = 0;
|
|
15
|
+
let corruptRows = 0;
|
|
16
|
+
for (const line of raw.split('\n')) {
|
|
17
|
+
if (!line.trim())
|
|
18
|
+
continue;
|
|
19
|
+
rows += 1;
|
|
20
|
+
try {
|
|
21
|
+
const record = parseRecord(JSON.parse(line));
|
|
22
|
+
if (record)
|
|
23
|
+
records.push(record);
|
|
24
|
+
else
|
|
25
|
+
corruptRows += 1;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
corruptRows += 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
records,
|
|
33
|
+
rows,
|
|
34
|
+
validRows: records.length,
|
|
35
|
+
corruptRows,
|
|
36
|
+
unterminated: raw.length > 0 && !raw.endsWith('\n'),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function assertTrustSidecarHealthy(sidecar, parsed) {
|
|
40
|
+
if (parsed.unterminated)
|
|
41
|
+
throw new CorruptAssetSidecarError(sidecar, 'unterminated');
|
|
42
|
+
if (parsed.corruptRows > 0)
|
|
43
|
+
throw new CorruptAssetSidecarError(sidecar, 'invalid_row');
|
|
44
|
+
}
|
|
45
|
+
export function parseProvenanceRecord(value) {
|
|
46
|
+
const record = objectRecord(value);
|
|
47
|
+
if (!record)
|
|
48
|
+
return null;
|
|
49
|
+
const assetId = stringField(record, 'assetId');
|
|
50
|
+
const source = stringField(record, 'source');
|
|
51
|
+
const at = stringField(record, 'at');
|
|
52
|
+
if (!assetId
|
|
53
|
+
|| (source !== 'local' && source !== 'migrated' && source !== 'hub')
|
|
54
|
+
|| typeof record['trusted'] !== 'boolean'
|
|
55
|
+
|| !at
|
|
56
|
+
|| Number.isNaN(Date.parse(at))) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const decision = record['decision'] === 'promoted' || record['decision'] === 'revoked'
|
|
60
|
+
? record['decision']
|
|
61
|
+
: undefined;
|
|
62
|
+
const decidedBy = stringField(record, 'decidedBy');
|
|
63
|
+
const promotedBy = stringField(record, 'promotedBy');
|
|
64
|
+
const reason = stringField(record, 'reason');
|
|
65
|
+
return {
|
|
66
|
+
assetId,
|
|
67
|
+
source,
|
|
68
|
+
trusted: record['trusted'],
|
|
69
|
+
at,
|
|
70
|
+
...(decision ? { decision } : {}),
|
|
71
|
+
...(decidedBy ? { decidedBy } : {}),
|
|
72
|
+
...(promotedBy ? { promotedBy } : {}),
|
|
73
|
+
...(reason ? { reason } : {}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function parseReviewRecord(value) {
|
|
77
|
+
const record = objectRecord(value);
|
|
78
|
+
if (!record)
|
|
79
|
+
return null;
|
|
80
|
+
const assetId = stringField(record, 'assetId');
|
|
81
|
+
const state = stringField(record, 'state');
|
|
82
|
+
const at = stringField(record, 'at');
|
|
83
|
+
if (!assetId
|
|
84
|
+
|| (state !== 'quarantined' && state !== 'approved' && state !== 'rejected')
|
|
85
|
+
|| !at
|
|
86
|
+
|| Number.isNaN(Date.parse(at))) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const by = stringField(record, 'by');
|
|
90
|
+
const reason = stringField(record, 'reason');
|
|
91
|
+
return {
|
|
92
|
+
assetId,
|
|
93
|
+
state,
|
|
94
|
+
at,
|
|
95
|
+
...(by ? { by } : {}),
|
|
96
|
+
...(reason ? { reason } : {}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function parseAssetSyncRecord(value) {
|
|
100
|
+
const record = objectRecord(value);
|
|
101
|
+
if (!record)
|
|
102
|
+
return null;
|
|
103
|
+
const assetId = stringField(record, 'assetId');
|
|
104
|
+
const type = stringField(record, 'type');
|
|
105
|
+
const source = stringField(record, 'source');
|
|
106
|
+
const scope = stringField(record, 'scope');
|
|
107
|
+
const syncedAt = stringField(record, 'syncedAt');
|
|
108
|
+
const remoteAssetId = stringField(record, 'remoteAssetId');
|
|
109
|
+
if (!assetId
|
|
110
|
+
|| (type !== 'Gene' && type !== 'Capsule')
|
|
111
|
+
|| source !== 'hub'
|
|
112
|
+
|| (scope !== 'purchased' && scope !== 'published')
|
|
113
|
+
|| !syncedAt
|
|
114
|
+
|| !remoteAssetId) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const logicalId = stringField(record, 'logicalId');
|
|
118
|
+
const status = stringField(record, 'status');
|
|
119
|
+
const runKey = optionalStrictString(record, 'runKey');
|
|
120
|
+
const inventoryKey = optionalStrictString(record, 'inventoryKey');
|
|
121
|
+
if (runKey === null || inventoryKey === null)
|
|
122
|
+
return null;
|
|
123
|
+
const forced = record['forced'] === true;
|
|
124
|
+
const collisionWithAssetId = stringField(record, 'collisionWithAssetId');
|
|
125
|
+
return {
|
|
126
|
+
assetId,
|
|
127
|
+
type,
|
|
128
|
+
source,
|
|
129
|
+
scope,
|
|
130
|
+
syncedAt,
|
|
131
|
+
remoteAssetId,
|
|
132
|
+
...(runKey ? { runKey } : {}),
|
|
133
|
+
...(inventoryKey ? { inventoryKey } : {}),
|
|
134
|
+
...(logicalId ? { logicalId } : {}),
|
|
135
|
+
...(status ? { status } : {}),
|
|
136
|
+
...(forced ? { forced: true } : {}),
|
|
137
|
+
...(collisionWithAssetId ? { collisionWithAssetId } : {}),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const MAX_INVENTORY_SEGMENTS = 24;
|
|
141
|
+
const MAX_INVENTORY_ITEMS_PER_SEGMENT = 10_000;
|
|
142
|
+
const MAX_INVENTORY_STRING_LENGTH = 4096;
|
|
143
|
+
export const ASSET_SYNC_INVENTORY_MAX_SEGMENT_BYTES = 2 * 1024 * 1024;
|
|
144
|
+
export function parseAssetSyncRunRecord(value) {
|
|
145
|
+
const record = objectRecord(value);
|
|
146
|
+
if (!record || record['recordType'] !== 'run')
|
|
147
|
+
return null;
|
|
148
|
+
const runId = optionalStrictString(record, 'runId');
|
|
149
|
+
const runKey = optionalStrictString(record, 'runKey');
|
|
150
|
+
const state = optionalStrictString(record, 'state');
|
|
151
|
+
const currentTimestamp = optionalStrictString(record, 'syncedAt');
|
|
152
|
+
const legacyTimestamp = optionalStrictString(record, 'at');
|
|
153
|
+
if (!runId
|
|
154
|
+
|| !runKey
|
|
155
|
+
|| state === null
|
|
156
|
+
|| !isRunState(state)
|
|
157
|
+
|| currentTimestamp === null
|
|
158
|
+
|| legacyTimestamp === null
|
|
159
|
+
|| (currentTimestamp && legacyTimestamp && currentTimestamp !== legacyTimestamp)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const syncedAt = currentTimestamp ?? legacyTimestamp;
|
|
163
|
+
if (!syncedAt || Number.isNaN(Date.parse(syncedAt)))
|
|
164
|
+
return null;
|
|
165
|
+
const remoteAssetId = optionalStrictString(record, 'remoteAssetId');
|
|
166
|
+
const outcomeValue = optionalStrictString(record, 'outcome');
|
|
167
|
+
const reason = optionalStrictString(record, 'reason');
|
|
168
|
+
if (remoteAssetId === null || outcomeValue === null || reason === null)
|
|
169
|
+
return null;
|
|
170
|
+
const outcome = isRunOutcome(outcomeValue) ? outcomeValue : undefined;
|
|
171
|
+
if (outcomeValue !== undefined && !outcome)
|
|
172
|
+
return null;
|
|
173
|
+
let plan;
|
|
174
|
+
const rawPlan = record['plan'];
|
|
175
|
+
if (rawPlan !== undefined) {
|
|
176
|
+
if (!Array.isArray(rawPlan) || rawPlan.length === 0)
|
|
177
|
+
return null;
|
|
178
|
+
const normalized = rawPlan.map((entry) => typeof entry === 'string' ? entry.trim() : '');
|
|
179
|
+
if (normalized.some((entry, index) => !entry || entry !== rawPlan[index]))
|
|
180
|
+
return null;
|
|
181
|
+
if (new Set(normalized).size !== normalized.length)
|
|
182
|
+
return null;
|
|
183
|
+
plan = Object.freeze(normalized);
|
|
184
|
+
}
|
|
185
|
+
if (state === 'started' && (remoteAssetId || outcome || reason))
|
|
186
|
+
return null;
|
|
187
|
+
if (state === 'progress') {
|
|
188
|
+
if (!remoteAssetId || !outcome || plan)
|
|
189
|
+
return null;
|
|
190
|
+
if ((outcome === 'failed') !== Boolean(reason))
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
if (state === 'completed' && (remoteAssetId || outcome || reason || plan))
|
|
194
|
+
return null;
|
|
195
|
+
return immutableRunRecord({
|
|
196
|
+
recordType: 'run',
|
|
197
|
+
runId,
|
|
198
|
+
runKey,
|
|
199
|
+
state,
|
|
200
|
+
...(remoteAssetId ? { remoteAssetId } : {}),
|
|
201
|
+
...(outcome ? { outcome } : {}),
|
|
202
|
+
...(reason ? { reason } : {}),
|
|
203
|
+
...(plan ? { plan } : {}),
|
|
204
|
+
syncedAt,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
export function parseAssetSyncInventorySegmentRecord(value) {
|
|
208
|
+
const record = objectRecord(value);
|
|
209
|
+
if (!record || record['recordType'] !== 'inventory_scan')
|
|
210
|
+
return null;
|
|
211
|
+
try {
|
|
212
|
+
if (Buffer.byteLength(JSON.stringify(record), 'utf8') > ASSET_SYNC_INVENTORY_MAX_SEGMENT_BYTES)
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const scanId = strictBoundedString(record['scanId']);
|
|
219
|
+
const inventoryKey = strictBoundedString(record['inventoryKey']);
|
|
220
|
+
const scope = strictBoundedString(record['scope']);
|
|
221
|
+
const syncedAt = strictBoundedString(record['syncedAt']);
|
|
222
|
+
const index = record['index'];
|
|
223
|
+
const inputCursorFingerprints = parseInventoryCursorFingerprints(record['inputCursorFingerprints']);
|
|
224
|
+
const nextCursorFingerprints = parseInventoryCursorFingerprints(record['nextCursorFingerprints']);
|
|
225
|
+
const anonymousBlocked = record['anonymousBlocked'];
|
|
226
|
+
const cursorHeld = record['cursorHeld'];
|
|
227
|
+
const batchId = record['batchId'];
|
|
228
|
+
const batchIndex = record['batchIndex'];
|
|
229
|
+
const batchSize = record['batchSize'];
|
|
230
|
+
const rawItems = record['items'];
|
|
231
|
+
const hasBatchMetadata = batchId !== undefined || batchIndex !== undefined || batchSize !== undefined;
|
|
232
|
+
if (!scanId
|
|
233
|
+
|| !inventoryKey
|
|
234
|
+
|| (scope !== 'purchased' && scope !== 'published' && scope !== 'all')
|
|
235
|
+
|| !syncedAt
|
|
236
|
+
|| Number.isNaN(Date.parse(syncedAt))
|
|
237
|
+
|| !Number.isInteger(index)
|
|
238
|
+
|| index < 0
|
|
239
|
+
|| index >= MAX_INVENTORY_SEGMENTS
|
|
240
|
+
|| !inputCursorFingerprints
|
|
241
|
+
|| !nextCursorFingerprints
|
|
242
|
+
|| !Number.isInteger(anonymousBlocked)
|
|
243
|
+
|| anonymousBlocked < 0
|
|
244
|
+
|| anonymousBlocked > MAX_INVENTORY_ITEMS_PER_SEGMENT
|
|
245
|
+
|| !Array.isArray(rawItems)
|
|
246
|
+
|| rawItems.length > MAX_INVENTORY_ITEMS_PER_SEGMENT
|
|
247
|
+
|| (cursorHeld !== undefined && cursorHeld !== true)
|
|
248
|
+
|| (hasBatchMetadata && (!strictBoundedString(batchId)
|
|
249
|
+
|| !Number.isInteger(batchIndex)
|
|
250
|
+
|| !Number.isInteger(batchSize)
|
|
251
|
+
|| batchSize < 2
|
|
252
|
+
|| batchSize > MAX_INVENTORY_SEGMENTS
|
|
253
|
+
|| batchIndex < 0
|
|
254
|
+
|| batchIndex >= batchSize
|
|
255
|
+
|| index - batchIndex < 0
|
|
256
|
+
|| index + (batchSize - batchIndex) > MAX_INVENTORY_SEGMENTS))) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
if (scope === 'purchased'
|
|
260
|
+
&& (inputCursorFingerprints.published !== null || nextCursorFingerprints.published !== null))
|
|
261
|
+
return null;
|
|
262
|
+
if (cursorHeld === true
|
|
263
|
+
&& (inputCursorFingerprints.purchased !== nextCursorFingerprints.purchased
|
|
264
|
+
|| inputCursorFingerprints.published !== nextCursorFingerprints.published))
|
|
265
|
+
return null;
|
|
266
|
+
if (scope === 'published'
|
|
267
|
+
&& (inputCursorFingerprints.purchased !== null || nextCursorFingerprints.purchased !== null))
|
|
268
|
+
return null;
|
|
269
|
+
if (index === 0
|
|
270
|
+
&& (inputCursorFingerprints.purchased !== null || inputCursorFingerprints.published !== null))
|
|
271
|
+
return null;
|
|
272
|
+
const items = [];
|
|
273
|
+
const seen = new Set();
|
|
274
|
+
for (const rawItem of rawItems) {
|
|
275
|
+
const item = objectRecord(rawItem);
|
|
276
|
+
if (!item)
|
|
277
|
+
return null;
|
|
278
|
+
const remoteAssetId = strictBoundedString(item['remoteAssetId']);
|
|
279
|
+
const outcome = strictBoundedString(item['outcome']);
|
|
280
|
+
if (!remoteAssetId || !isInventoryOutcome(outcome) || seen.has(remoteAssetId))
|
|
281
|
+
return null;
|
|
282
|
+
seen.add(remoteAssetId);
|
|
283
|
+
items.push(Object.freeze({ remoteAssetId, outcome }));
|
|
284
|
+
}
|
|
285
|
+
if (items.length + anonymousBlocked > MAX_INVENTORY_ITEMS_PER_SEGMENT)
|
|
286
|
+
return null;
|
|
287
|
+
return Object.freeze({
|
|
288
|
+
recordType: 'inventory_scan',
|
|
289
|
+
scanId,
|
|
290
|
+
inventoryKey,
|
|
291
|
+
scope,
|
|
292
|
+
index: index,
|
|
293
|
+
inputCursorFingerprints,
|
|
294
|
+
nextCursorFingerprints,
|
|
295
|
+
items: Object.freeze(items),
|
|
296
|
+
anonymousBlocked: anonymousBlocked,
|
|
297
|
+
...(cursorHeld === true ? { cursorHeld: true } : {}),
|
|
298
|
+
...(hasBatchMetadata ? {
|
|
299
|
+
batchId: batchId,
|
|
300
|
+
batchIndex: batchIndex,
|
|
301
|
+
batchSize: batchSize,
|
|
302
|
+
} : {}),
|
|
303
|
+
syncedAt,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
export function parseAssetSyncSidecarRecord(value) {
|
|
307
|
+
const record = objectRecord(value);
|
|
308
|
+
if (!record)
|
|
309
|
+
return null;
|
|
310
|
+
if (record['recordType'] !== undefined) {
|
|
311
|
+
if (record['recordType'] === 'run')
|
|
312
|
+
return parseAssetSyncRunRecord(record);
|
|
313
|
+
if (record['recordType'] === 'inventory_scan')
|
|
314
|
+
return parseAssetSyncInventorySegmentRecord(record);
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return parseAssetSyncRecord(record);
|
|
318
|
+
}
|
|
319
|
+
function parseInventoryCursorFingerprints(value) {
|
|
320
|
+
const record = objectRecord(value);
|
|
321
|
+
if (!record || !Object.hasOwn(record, 'purchased') || !Object.hasOwn(record, 'published'))
|
|
322
|
+
return null;
|
|
323
|
+
const purchased = strictNullableCursorFingerprint(record['purchased']);
|
|
324
|
+
const published = strictNullableCursorFingerprint(record['published']);
|
|
325
|
+
if (purchased === undefined || published === undefined)
|
|
326
|
+
return null;
|
|
327
|
+
return Object.freeze({ purchased, published });
|
|
328
|
+
}
|
|
329
|
+
function strictNullableCursorFingerprint(value) {
|
|
330
|
+
if (value === null)
|
|
331
|
+
return null;
|
|
332
|
+
return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value) ? value : undefined;
|
|
333
|
+
}
|
|
334
|
+
function strictBoundedString(value) {
|
|
335
|
+
return typeof value === 'string'
|
|
336
|
+
&& value.length <= MAX_INVENTORY_STRING_LENGTH
|
|
337
|
+
&& value.trim()
|
|
338
|
+
&& value === value.trim()
|
|
339
|
+
? value
|
|
340
|
+
: undefined;
|
|
341
|
+
}
|
|
342
|
+
function isInventoryOutcome(value) {
|
|
343
|
+
return value === 'imported'
|
|
344
|
+
|| value === 'already_local'
|
|
345
|
+
|| value === 'blocked'
|
|
346
|
+
|| value === 'failed'
|
|
347
|
+
|| value === 'pending';
|
|
348
|
+
}
|
|
349
|
+
function objectRecord(value) {
|
|
350
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
351
|
+
? value
|
|
352
|
+
: null;
|
|
353
|
+
}
|
|
354
|
+
function stringField(value, key) {
|
|
355
|
+
const raw = value[key];
|
|
356
|
+
return typeof raw === 'string' && raw.trim() ? raw.trim() : undefined;
|
|
357
|
+
}
|
|
358
|
+
function optionalStrictString(value, key) {
|
|
359
|
+
const raw = value[key];
|
|
360
|
+
if (raw === undefined)
|
|
361
|
+
return undefined;
|
|
362
|
+
return typeof raw === 'string' && raw.trim() && raw === raw.trim() ? raw : null;
|
|
363
|
+
}
|
|
364
|
+
function immutableRunRecord(record) {
|
|
365
|
+
const plan = record.plan ? Object.freeze([...record.plan]) : undefined;
|
|
366
|
+
return Object.freeze({ ...record, ...(plan ? { plan } : {}) });
|
|
367
|
+
}
|
|
368
|
+
function isRunState(value) {
|
|
369
|
+
return value === 'started' || value === 'progress' || value === 'completed';
|
|
370
|
+
}
|
|
371
|
+
function isRunOutcome(value) {
|
|
372
|
+
return value === 'imported'
|
|
373
|
+
|| value === 'already_local'
|
|
374
|
+
|| value === 'failed'
|
|
375
|
+
|| value === 'remote_missing';
|
|
376
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ReleaseLockReason } from '../util/fileLock.js';
|
|
2
|
+
import { type AssetStoreLockDeps } from './assetStoreStorage.js';
|
|
3
|
+
import { type AssetSidecarKind } from './assetSidecarRecords.js';
|
|
4
|
+
export type { AssetSidecarKind } from './assetSidecarRecords.js';
|
|
5
|
+
export type AssetSidecarRecoveryFailureReason = 'sidecar_missing' | 'sidecar_not_degraded' | 'replacement_missing' | 'replacement_too_large' | 'replacement_invalid_utf8' | 'replacement_invalid' | 'replacement_unterminated' | 'valid_history_missing' | 'corrective_record_required' | 'unsafe_corrective_record' | 'acknowledgement_required' | 'sidecar_too_large' | 'sidecar_changed' | 'replacement_changed' | 'backup_conflict';
|
|
6
|
+
export declare class AssetSidecarRecoveryError extends Error {
|
|
7
|
+
readonly reason: AssetSidecarRecoveryFailureReason;
|
|
8
|
+
readonly code = "ASSET_SIDECAR_RECOVERY_FAILED";
|
|
9
|
+
constructor(reason: AssetSidecarRecoveryFailureReason);
|
|
10
|
+
}
|
|
11
|
+
export interface AssetSidecarRecoveryFileReport {
|
|
12
|
+
rows: number;
|
|
13
|
+
validRows: number;
|
|
14
|
+
corruptRows: number;
|
|
15
|
+
unterminated: boolean;
|
|
16
|
+
digest: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AssetSidecarReplacementReport extends AssetSidecarRecoveryFileReport {
|
|
19
|
+
preservedValidRows: number;
|
|
20
|
+
addedRecords: number;
|
|
21
|
+
correctiveRecords: number;
|
|
22
|
+
}
|
|
23
|
+
export interface AssetSidecarRecoveryReport {
|
|
24
|
+
mode: 'preview' | 'write';
|
|
25
|
+
sidecar: AssetSidecarKind;
|
|
26
|
+
changed: boolean;
|
|
27
|
+
wouldWrite: boolean;
|
|
28
|
+
acknowledgementRequired: boolean;
|
|
29
|
+
current: AssetSidecarRecoveryFileReport;
|
|
30
|
+
replacement: AssetSidecarReplacementReport;
|
|
31
|
+
backupId?: string;
|
|
32
|
+
lockReleaseWarning?: ReleaseLockReason;
|
|
33
|
+
}
|
|
34
|
+
export interface RecoverAssetSidecarOptions {
|
|
35
|
+
baseDir: string;
|
|
36
|
+
sidecar: AssetSidecarKind;
|
|
37
|
+
replacementPath: string;
|
|
38
|
+
write?: boolean;
|
|
39
|
+
acknowledgeCorruptHistory?: boolean;
|
|
40
|
+
maxFileBytes?: number;
|
|
41
|
+
deps?: {
|
|
42
|
+
beforeBackup?: () => void;
|
|
43
|
+
beforeReplace?: () => void;
|
|
44
|
+
lock?: AssetStoreLockDeps;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export declare const DEFAULT_SIDECAR_RECOVERY_MAX_FILE_BYTES: number;
|
|
48
|
+
export declare function recoverAssetSidecar(opts: RecoverAssetSidecarOptions): AssetSidecarRecoveryReport;
|