@gitroll/tacitt-cli 0.6.11 → 0.6.12
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 +4 -0
- package/bin/INDEX.md +6 -4
- package/bin/tacitt.cjs +1 -0
- package/dist/{agent-setup-DdfF3zch.mjs → agent-setup-B12VbvN_.mjs} +2 -2
- package/dist/agent-setup-worker.mjs +5 -5
- package/dist/cli.mjs +28 -28
- package/dist/codex-title-worker.mjs +2 -2
- package/dist/configured-preview-worker.mjs +5 -5
- package/dist/configured-session-worker.mjs +23 -25
- package/dist/{frame-Bq2zRh-i.mjs → frame-B3He21G8.mjs} +1 -1
- package/dist/{heap-CV8Eca8V.mjs → heap-Blrat--4.mjs} +260 -23
- package/dist/inspection-worker.mjs +4 -4
- package/dist/{job-BKsifhyv.mjs → job-CBuIMTQ0.mjs} +24 -9
- package/dist/{locate-Cx52Zqxv.mjs → locate-D-ZaHpI0.mjs} +5 -0
- package/dist/{model-C1UXkHh9.mjs → model-DR9odhWP.mjs} +1 -1
- package/dist/operation-executor.mjs +3 -3
- package/dist/preview-worker.mjs +1 -1
- package/dist/privacy-validator.mjs +28 -8
- package/dist/{query-AMZerUh8.mjs → query-BYDcNKy2.mjs} +1614 -679
- package/dist/{run-CaPktPhH.mjs → run-DQ9xyKSt.mjs} +4 -4
- package/dist/session-process.mjs +20 -0
- package/dist/{src-wZx_v0Ih.mjs → src-CKQlTA2Z.mjs} +4 -4
- package/dist/{src-DlVbGB32.mjs → src-DeNJ8vOD.mjs} +465 -107
- package/dist/{src-D1iONla3.mjs → src-Do-qzuMn.mjs} +377 -130
- package/dist/store-database-worker.mjs +1 -1
- package/dist/web/assets/index-BgDdPL1c.js +172 -0
- package/dist/web/index.html +2 -1
- package/package.json +2 -1
- package/skills/INDEX.md +6 -4
- package/skills/tacitt/INDEX.md +7 -6
- package/skills/tacitt/SKILL.md +5 -5
- package/skills/tacitt/references/INDEX.md +14 -11
- package/skills/tacitt/references/b-method.md +4 -4
- package/skills/tacitt/references/bootstrap.md +17 -3
- package/skills/tacitt/references/classification.md +1 -1
- package/skills/tacitt/references/commands.md +24 -6
- package/skills/tacitt/references/journey.md +4 -4
- package/skills/tacitt/references/parallel-review.md +13 -7
- package/skills/tacitt/references/send.md +7 -3
- package/skills/tacitt/scripts/INDEX.md +40 -37
- package/skills/tacitt/scripts/answer.mjs +19 -1
- package/skills/tacitt/scripts/journey-card-consolidation.mjs +1 -1
- package/skills/tacitt/scripts/journey-classification-tasks.mjs +28 -8
- package/skills/tacitt/scripts/journey-panel-host.d.mts +2 -0
- package/skills/tacitt/scripts/journey-panel-host.mjs +25 -2
- package/skills/tacitt/scripts/journey-scan-timing.d.mts +4 -0
- package/skills/tacitt/scripts/journey-scan-timing.mjs +12 -0
- package/skills/tacitt/scripts/journey-state.mjs +11 -0
- package/skills/tacitt/scripts/journey-tasks.mjs +12 -5
- package/skills/tacitt/scripts/journey.mjs +10 -2
- package/skills/tacitt/scripts/privacy-validator.mjs +28 -7
- package/skills/tacitt/scripts/review.mjs +399 -99
- package/dist/web/assets/index-CYl7eDUu.js +0 -172
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $n as buildPlan, An as createDetectionSummary, Bn as cleanupImplementationVersion, C as createBAnalysisUnits, Cn as reviewRoles, Dn as bindInspection, En as createSessionPreparation, Gn as nativeField, Hn as nativeParserVersion, In as createReplacementKey, Jn as transformRecords, Kn as nativeItems, Ln as sessionNonce, Mn as walkNativeFields, N as bDuplicateShift, Rn as projectNativeRecord, Sn as mainReviewRole, Tn as renderNative, U as bDigest, Un as redactionImplementationVersion, Vn as entityDictionaryVersion, W as codePointLength, Xn as retainedMainTextNodes, Yn as frameRecords, Zn as validateProfile, ar as detectStatic, bn as processNativeRecord, br as processingSite, c as reviewDigest, cn as reviewFamilies, cr as jsonSpans, er as validatePlan, fn as sourceSnapshotId, gr as ProcessingError, hr as defaultDetectionLimits, in as safeCode, ir as resolveLimits, j as bBindingCap, lr as agentContextLocation, nn as ApplicationError, nr as defaultLimits, qn as nativeText, rr as recordPointerLimits, sn as familySelected, u as textDigest, un as sourceKey, ur as createEntityMatcher, vn as nativeSourceIdentitySchema, vr as fail$1, wn as createSentenceContext, xn as projectNativeReviewInput, xr as siteFields, yn as withMandatoryCustomTerms, yr as isProcessingCode, zn as parseNativeRecord } from "./locate-
|
|
2
|
-
import { t as createZstdFrameCheck } from "./frame-
|
|
3
|
-
import {
|
|
1
|
+
import { $n as buildPlan, An as createDetectionSummary, Bn as cleanupImplementationVersion, C as createBAnalysisUnits, Cn as reviewRoles, Dn as bindInspection, En as createSessionPreparation, Gn as nativeField, Hn as nativeParserVersion, In as createReplacementKey, Jn as transformRecords, Kn as nativeItems, Ln as sessionNonce, Mn as walkNativeFields, N as bDuplicateShift, Rn as projectNativeRecord, Sn as mainReviewRole, Tn as renderNative, U as bDigest, Un as redactionImplementationVersion, Vn as entityDictionaryVersion, W as codePointLength, Xn as retainedMainTextNodes, Yn as frameRecords, Zn as validateProfile, ar as detectStatic, bn as processNativeRecord, br as processingSite, c as reviewDigest, cn as reviewFamilies, cr as jsonSpans, er as validatePlan, fn as sourceSnapshotId, gr as ProcessingError, hr as defaultDetectionLimits, in as safeCode, ir as resolveLimits, j as bBindingCap, lr as agentContextLocation, nn as ApplicationError, nr as defaultLimits, qn as nativeText, rr as recordPointerLimits, sn as familySelected, u as textDigest, un as sourceKey, ur as createEntityMatcher, vn as nativeSourceIdentitySchema, vr as fail$1, wn as createSentenceContext, xn as projectNativeReviewInput, xr as siteFields, yn as withMandatoryCustomTerms, yr as isProcessingCode, zn as parseNativeRecord } from "./locate-D-ZaHpI0.mjs";
|
|
2
|
+
import { t as createZstdFrameCheck } from "./frame-B3He21G8.mjs";
|
|
3
|
+
import { L as sourceIdentityEvidence, Mn as resolveSourceSelection, Ni as approvedTreatmentSchema, Qr as metadataProcessingVersion, R as withSourceEvidence, Ri as staticCatalogRef, ai as agentSourcePathSegment, ar as bWordBounded, ji as sourceChangePolicy, nr as bExceptionRanges, oi as agentSourceSchema, ot as classifyAgentSetup, st as defaultAgentSetupInclusion, tr as bContainment, z as agentSetupKey } from "./src-Do-qzuMn.mjs";
|
|
4
4
|
import { constants } from "node:fs";
|
|
5
5
|
import { link, lstat, mkdir, open, readFile, readdir, realpath, rm, rmdir, stat, unlink } from "node:fs/promises";
|
|
6
6
|
import { execFile, fork, spawn } from "node:child_process";
|
|
@@ -11,7 +11,7 @@ import { Readable } from "node:stream";
|
|
|
11
11
|
import { TextDecoder as TextDecoder$1, isDeepStrictEqual, promisify } from "node:util";
|
|
12
12
|
import { createHash, createHmac, randomUUID } from "node:crypto";
|
|
13
13
|
import { setImmediate } from "node:timers/promises";
|
|
14
|
-
import { ERR_UNSUPPORTED_FORMAT, Reader, TextReader, ZipReader, ZipWriter, configure } from "@zip.js/zip.js/index-native.js";
|
|
14
|
+
import { ERR_UNSUPPORTED_FORMAT, Reader, TextReader, Uint8ArrayReader, ZipReader, ZipWriter, configure } from "@zip.js/zip.js/index-native.js";
|
|
15
15
|
import "node:perf_hooks";
|
|
16
16
|
import { availableParallelism, platform, tmpdir, totalmem } from "node:os";
|
|
17
17
|
import { pipeline } from "node:stream/promises";
|
|
@@ -1874,11 +1874,11 @@ function description(value) {
|
|
|
1874
1874
|
sha256
|
|
1875
1875
|
};
|
|
1876
1876
|
}
|
|
1877
|
-
function checkWorkspaceManifest(
|
|
1878
|
-
const manifest = record$1(strictJson(
|
|
1877
|
+
function checkWorkspaceManifest(source, entries, bundleId, expectedPathHash, summary) {
|
|
1878
|
+
const manifest = record$1(typeof source === "string" ? strictJson(source, manifestLimitBytes, manifestNodeLimit) : source);
|
|
1879
1879
|
const treatment = manifest["contentTreatment"];
|
|
1880
1880
|
const configured = treatment === "configured";
|
|
1881
|
-
const configuredManifest = configured ? parseConfiguredManifest(
|
|
1881
|
+
const configuredManifest = typeof source !== "string" ? source : configured ? parseConfiguredManifest(source) : null;
|
|
1882
1882
|
if (configuredManifest) validateConfiguredManifest(configuredManifest);
|
|
1883
1883
|
const sourceWorkspaces = configuredManifest?.sourceWorkspaces ?? [record$1(manifest["workspace"])];
|
|
1884
1884
|
const workspaceIds = new Set(sourceWorkspaces.map((workspace) => string(workspace["id"])));
|
|
@@ -2443,7 +2443,7 @@ function parseAuditRow(value, sourceId, sourceSha256, ordinal) {
|
|
|
2443
2443
|
diagnostics
|
|
2444
2444
|
};
|
|
2445
2445
|
}
|
|
2446
|
-
const location$
|
|
2446
|
+
const location$2 = (pointer, subject) => `${subject}:${pointer}`;
|
|
2447
2447
|
const child = (pointer, key) => `${pointer}/${String(key).replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
2448
2448
|
function outputLocations(text, signal) {
|
|
2449
2449
|
let root;
|
|
@@ -2462,7 +2462,7 @@ function outputLocations(text, signal) {
|
|
|
2462
2462
|
let bytes = 0;
|
|
2463
2463
|
function visit(node, pointer, subject) {
|
|
2464
2464
|
checkAbort(signal);
|
|
2465
|
-
const key = location$
|
|
2465
|
+
const key = location$2(pointer, subject);
|
|
2466
2466
|
bytes += Buffer.byteLength(key);
|
|
2467
2467
|
if (bytes > maximumBytes) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2468
2468
|
locations.set(key, node);
|
|
@@ -2491,7 +2491,7 @@ function verifyCompanion(row, outputText, signal) {
|
|
|
2491
2491
|
if (!field.fieldId.startsWith(`${row.recordId}-f`) || match === null || Number(match[1]) >= maximumEntries || match[2] !== void 0 && Number(match[2]) >= maximumEntries || fields.has(field.fieldId)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2492
2492
|
if (match?.[2] === void 0 && match?.[3] === void 0) originals.add(Number(match?.[1]));
|
|
2493
2493
|
if (field.pointer !== null) {
|
|
2494
|
-
const key = location$
|
|
2494
|
+
const key = location$2(field.pointer, field.subject);
|
|
2495
2495
|
if (!locations.has(key) || referenced.has(key)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2496
2496
|
referenced.add(key);
|
|
2497
2497
|
}
|
|
@@ -2505,7 +2505,7 @@ function verifyCompanion(row, outputText, signal) {
|
|
|
2505
2505
|
if (marker === null) continue;
|
|
2506
2506
|
const baseId = field.fieldId.replace(/-s\d+$|-k$/u, "");
|
|
2507
2507
|
const base = fields.get(baseId);
|
|
2508
|
-
if (!sampled.has(baseId) || base === void 0 || field.subject !== "value" || (base.pointer === null ? field.pointer !== null : field.pointer !== (marker[2] === "k" ? child(base.pointer, "skeleton") : child(child(base.pointer, "segments"), marker[1] ?? "")) || locations.get(location$
|
|
2508
|
+
if (!sampled.has(baseId) || base === void 0 || field.subject !== "value" || (base.pointer === null ? field.pointer !== null : field.pointer !== (marker[2] === "k" ? child(base.pointer, "skeleton") : child(child(base.pointer, "segments"), marker[1] ?? "")) || locations.get(location$2(field.pointer, field.subject))?.kind !== "string")) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
2509
2509
|
}
|
|
2510
2510
|
const synthetic = sampleLocations(row.bodies, fields, locations);
|
|
2511
2511
|
for (const key of locations.keys()) if (!referenced.has(key) && !synthetic.has(key)) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
@@ -2643,37 +2643,31 @@ async function verifyConfiguredPart(part, entries, descriptions, signal) {
|
|
|
2643
2643
|
//#endregion
|
|
2644
2644
|
//#region packages/artifact/src/read/configured/workspace.ts
|
|
2645
2645
|
/** Public primary facts are parsed independently; no source file is opened. */
|
|
2646
|
-
function workspaceSummary(
|
|
2647
|
-
const manifest =
|
|
2648
|
-
if (manifest["contentTreatment"] !== "configured" || manifest["formatVersion"] !== 5 || manifest["companionVersion"] !== 3) return fail("ARTIFACT_INVALID_MANIFEST");
|
|
2646
|
+
function workspaceSummary(input) {
|
|
2647
|
+
const manifest = typeof input === "string" ? parseConfiguredManifest(input) : input;
|
|
2649
2648
|
return {
|
|
2650
2649
|
format: "sess-pilot-workspace-summary",
|
|
2651
2650
|
formatVersion: 1,
|
|
2652
|
-
bundleId:
|
|
2653
|
-
counts:
|
|
2654
|
-
sessions:
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
sourceOrdinal,
|
|
2667
|
-
native: part.native
|
|
2668
|
-
}))
|
|
2669
|
-
};
|
|
2670
|
-
})
|
|
2651
|
+
bundleId: manifest.bundleId,
|
|
2652
|
+
counts: manifest.counts,
|
|
2653
|
+
sessions: manifest.sessions.map((session) => ({
|
|
2654
|
+
sessionId: session.id,
|
|
2655
|
+
scopeOrdinal: 0,
|
|
2656
|
+
harness: session.harness,
|
|
2657
|
+
nativeSessionId: session.sourceSessionId,
|
|
2658
|
+
treatmentId: session.treatmentId,
|
|
2659
|
+
sources: session.parts.map((part, sourceOrdinal) => ({
|
|
2660
|
+
sourceId: part.sourceId,
|
|
2661
|
+
sourceOrdinal,
|
|
2662
|
+
native: part.native
|
|
2663
|
+
}))
|
|
2664
|
+
}))
|
|
2671
2665
|
};
|
|
2672
2666
|
}
|
|
2673
2667
|
/** Validate exact primary coverage and metadata before either native-data consumer runs. */
|
|
2674
2668
|
async function readPrimaryMetadata(primaryEntries, primaryText, signal, only) {
|
|
2675
|
-
const summary = workspaceSummary(primaryText);
|
|
2676
2669
|
const manifest = parseConfiguredManifest(primaryText);
|
|
2670
|
+
const summary = workspaceSummary(manifest);
|
|
2677
2671
|
checkWorkspaceManifest(primaryText, primaryEntries, summary.bundleId, manifest.sourceWorkspaces.length === 1 ? manifest.sourceWorkspaces[0]?.pathHash ?? null : null, summary);
|
|
2678
2672
|
for (const description of manifest.entries) {
|
|
2679
2673
|
checkAbort(signal);
|
|
@@ -5588,17 +5582,20 @@ function matchFrozenOutput(input, checked) {
|
|
|
5588
5582
|
if (input.sha256 !== checked.sha256 || input.archiveBytes !== checked.archiveBytes) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
5589
5583
|
}
|
|
5590
5584
|
async function checkFrozenOutput(input, signal) {
|
|
5591
|
-
let
|
|
5585
|
+
let verified;
|
|
5592
5586
|
const checked = await checkWrittenArchive(input.path, input.identity, void 0, (text, entries) => {
|
|
5593
5587
|
const manifest = parseConfiguredManifest(text);
|
|
5594
|
-
checkWorkspaceManifest(
|
|
5595
|
-
|
|
5588
|
+
checkWorkspaceManifest(manifest, entries, manifest.bundleId, manifest.sourceWorkspaces.length === 1 ? manifest.sourceWorkspaces[0]?.pathHash ?? null : null, workspaceSummary(manifest));
|
|
5589
|
+
verified = {
|
|
5590
|
+
manifestText: text,
|
|
5591
|
+
manifest
|
|
5592
|
+
};
|
|
5596
5593
|
}, signal);
|
|
5597
5594
|
matchFrozenOutput(input, checked);
|
|
5595
|
+
if (!verified) return fail("ARTIFACT_INVALID_MANIFEST");
|
|
5598
5596
|
return {
|
|
5599
5597
|
checked,
|
|
5600
|
-
|
|
5601
|
-
manifest: parseConfiguredManifest(manifestText)
|
|
5598
|
+
...verified
|
|
5602
5599
|
};
|
|
5603
5600
|
}
|
|
5604
5601
|
/** Hold the exact verified descriptor; every entry is separately hashed before use. */
|
|
@@ -7294,6 +7291,24 @@ function stringOffsets(root, changes) {
|
|
|
7294
7291
|
return offsets;
|
|
7295
7292
|
}
|
|
7296
7293
|
const encodedLength = (text) => JSON.stringify(text).length - 2;
|
|
7294
|
+
/** Absolute JSON string-content coordinates. Fixed-size checkpoints bound both the work
|
|
7295
|
+
* per lookup and retained memory, including out-of-order overlapping contributor ranges. */
|
|
7296
|
+
function encodedOffset(text, base) {
|
|
7297
|
+
const stride = 1024;
|
|
7298
|
+
const offsets = [base];
|
|
7299
|
+
const boundary = (block) => {
|
|
7300
|
+
const at = block * stride;
|
|
7301
|
+
return scalarBoundary(text, at) ? at : at - 1;
|
|
7302
|
+
};
|
|
7303
|
+
return (position) => {
|
|
7304
|
+
const block = Math.floor(position / stride);
|
|
7305
|
+
while (offsets.length <= block) {
|
|
7306
|
+
const next = offsets.length;
|
|
7307
|
+
offsets.push((offsets[next - 1] ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(text.slice(boundary(next - 1), boundary(next))));
|
|
7308
|
+
}
|
|
7309
|
+
return (offsets[block] ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(text.slice(boundary(block), position));
|
|
7310
|
+
};
|
|
7311
|
+
}
|
|
7297
7312
|
/** Restore verified untouched scalar lexemes without round-tripping through JS numbers. */
|
|
7298
7313
|
function restoreLiterals(root, literals) {
|
|
7299
7314
|
const raw = literals.get(root.id);
|
|
@@ -7367,37 +7382,42 @@ function renderReviewRow(row, before, edits, markers, signal) {
|
|
|
7367
7382
|
const changed = inner ? renderNative(inner, innerChanges, reviewLimits, signal).text : pieces[0]?.changed ?? fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
7368
7383
|
const sourceOffsets = inner ? stringOffsets(inner, /* @__PURE__ */ new Map()) : void 0, outputOffsets = inner ? stringOffsets(inner, innerChanges) : void 0;
|
|
7369
7384
|
const inputSha256 = hash$4(sourceText), outputSha256 = hash$4(changed), context = createSentenceContext(sourceText);
|
|
7370
|
-
for (const piece of pieces)
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7385
|
+
for (const piece of pieces) {
|
|
7386
|
+
if (!piece.items.length) continue;
|
|
7387
|
+
const inputOffset = sourceOffsets && encodedOffset(piece.source, sourceOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH"));
|
|
7388
|
+
const outputOffset = outputOffsets && encodedOffset(piece.changed, outputOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH"));
|
|
7389
|
+
const coordinates = (range) => inputOffset ? {
|
|
7390
|
+
start: inputOffset(range.start),
|
|
7391
|
+
end: inputOffset(range.end)
|
|
7374
7392
|
} : range;
|
|
7375
|
-
const
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7393
|
+
for (const item of piece.items) {
|
|
7394
|
+
const inputRange = coordinates(item.inputRange);
|
|
7395
|
+
const start = outputOffset ? outputOffset(item.outputRange.start) : item.outputRange.start;
|
|
7396
|
+
const { span, ...applied } = item;
|
|
7397
|
+
const transcript = {
|
|
7398
|
+
...applied,
|
|
7399
|
+
pointer,
|
|
7400
|
+
inputSha256,
|
|
7401
|
+
outputSha256,
|
|
7402
|
+
inputRange,
|
|
7403
|
+
outputRange: {
|
|
7404
|
+
start,
|
|
7405
|
+
end: start + item.replacement.length
|
|
7406
|
+
},
|
|
7407
|
+
context: context(inputRange)
|
|
7408
|
+
};
|
|
7409
|
+
transcripts.push({
|
|
7410
|
+
...transcript,
|
|
7411
|
+
contributors: reconstructedContributors({
|
|
7412
|
+
row,
|
|
7413
|
+
field: piece.field,
|
|
7414
|
+
span,
|
|
7415
|
+
transcript,
|
|
7416
|
+
coordinates,
|
|
7417
|
+
context
|
|
7418
|
+
})
|
|
7419
|
+
});
|
|
7420
|
+
}
|
|
7401
7421
|
}
|
|
7402
7422
|
if (nativeContainer && changed === sourceText) {
|
|
7403
7423
|
if (nativeContainerText(target, signal) !== sourceText) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
@@ -7513,10 +7533,12 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7513
7533
|
if (!family) {
|
|
7514
7534
|
const categories = /* @__PURE__ */ new Map();
|
|
7515
7535
|
const bounded = /* @__PURE__ */ new Set();
|
|
7516
|
-
|
|
7536
|
+
const toolResultEscapes = /* @__PURE__ */ new Set();
|
|
7537
|
+
for (const { term, category, bounded: whole, toolResultEscapes: escaped } of hide.terms) {
|
|
7517
7538
|
if (categories.has(term)) mismatch("duplicate-term");
|
|
7518
7539
|
categories.set(term, maskCategory(category));
|
|
7519
7540
|
if (whole) bounded.add(term);
|
|
7541
|
+
if (escaped) toolResultEscapes.add(term);
|
|
7520
7542
|
}
|
|
7521
7543
|
family = {
|
|
7522
7544
|
matcher: createEntityMatcher([...categories.keys()].map((value) => ({
|
|
@@ -7525,6 +7547,7 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7525
7547
|
}))),
|
|
7526
7548
|
categories,
|
|
7527
7549
|
bounded,
|
|
7550
|
+
toolResultEscapes,
|
|
7528
7551
|
excepted: bExceptionRanges(hide.exceptions ?? [])
|
|
7529
7552
|
};
|
|
7530
7553
|
shared.set(key, family);
|
|
@@ -7535,7 +7558,7 @@ function indexFamilyHides(manifest, hides = []) {
|
|
|
7535
7558
|
return parts;
|
|
7536
7559
|
}
|
|
7537
7560
|
/** Disjoint literal hits outside existing markers; overlaps join under the highest category. */
|
|
7538
|
-
function familySpans(text, family, signal) {
|
|
7561
|
+
function familySpans(text, family, signal, toolResult) {
|
|
7539
7562
|
const markers = [...text.matchAll(markerPattern)].map((match) => ({
|
|
7540
7563
|
start: match.index,
|
|
7541
7564
|
end: match.index + match[0].length
|
|
@@ -7551,7 +7574,7 @@ function familySpans(text, family, signal) {
|
|
|
7551
7574
|
}
|
|
7552
7575
|
return (markers[low]?.start ?? Infinity) < range.end;
|
|
7553
7576
|
};
|
|
7554
|
-
const hits = family.matcher.find(text, signal, 2e6).filter(({ range, entity }) => !marked(range) && (!family.bounded.has(entity.value) || bWordBounded(text, range.start, range.end)) && !excepted(range)).map(({ range, entity }) => ({
|
|
7577
|
+
const hits = family.matcher.find(text, signal, 2e6).filter(({ range, entity }) => !marked(range) && (!family.bounded.has(entity.value) || bWordBounded(text, range.start, range.end, toolResult && family.toolResultEscapes.has(entity.value))) && !excepted(range)).map(({ range, entity }) => ({
|
|
7555
7578
|
...range,
|
|
7556
7579
|
category: family.categories.get(entity.value) ?? mismatch("unknown-term")
|
|
7557
7580
|
})).sort((left, right) => left.start - right.start || right.end - left.end);
|
|
@@ -7625,8 +7648,10 @@ function maskFamilyFields(text, root, annotations, family, markers, signal, onAp
|
|
|
7625
7648
|
if (skip(field)) continue;
|
|
7626
7649
|
if (field.text.includes(markers.prefix)) mismatch("marker-prefix");
|
|
7627
7650
|
if (field.subject !== "value" || field.scalarKind !== "string" || field.field.protection || !bodies.has(field.nodeId) && structural(field.field.name)) continue;
|
|
7628
|
-
const
|
|
7629
|
-
const
|
|
7651
|
+
const toolResult = field.origin.carrier === "tool-result";
|
|
7652
|
+
const find = (value) => familySpans(value, family, signal, toolResult);
|
|
7653
|
+
const raw = find(field.text);
|
|
7654
|
+
const carrier = raw.length || field.text.includes("\\") ? familyCarrierSpans(field, find, signal) : void 0;
|
|
7630
7655
|
const spans = (carrier ?? raw).sort((left, right) => left.start - right.start);
|
|
7631
7656
|
if (!spans.length) continue;
|
|
7632
7657
|
const changed = maskOutputField({
|
|
@@ -9844,7 +9869,16 @@ function createSessionWorkerPool(url, size, heapMb = workerHeapMb) {
|
|
|
9844
9869
|
stopping = Promise.all(slots.map(async (slot) => {
|
|
9845
9870
|
try {
|
|
9846
9871
|
await slot.process.close();
|
|
9847
|
-
if (slot.task)
|
|
9872
|
+
if (slot.task) {
|
|
9873
|
+
if (requestKind(slot.task) === "journey-base") {
|
|
9874
|
+
await removeNamedTemporarySpools(slot.task.spoolPaths);
|
|
9875
|
+
for (const path of slot.task.spoolPaths) try {
|
|
9876
|
+
await unlink(path);
|
|
9877
|
+
} catch (error) {
|
|
9878
|
+
if (filesystemCode(error) !== "ENOENT") throw error;
|
|
9879
|
+
}
|
|
9880
|
+
} else await removeStoppedSpools(slot.task.spoolPaths);
|
|
9881
|
+
}
|
|
9848
9882
|
} finally {
|
|
9849
9883
|
slot.task?.reject(blame(slot));
|
|
9850
9884
|
slot.task = void 0;
|
|
@@ -9885,6 +9919,10 @@ function createSessionWorkerPool(url, size, heapMb = workerHeapMb) {
|
|
|
9885
9919
|
}
|
|
9886
9920
|
task.spoolPaths.add(message.path);
|
|
9887
9921
|
task.onSpool?.(message.path);
|
|
9922
|
+
if (!closed) slot.process.send({
|
|
9923
|
+
kind: "spool-owned",
|
|
9924
|
+
path: message.path
|
|
9925
|
+
});
|
|
9888
9926
|
} else if (message.kind === "result") {
|
|
9889
9927
|
const requestedKind = requestKind(task);
|
|
9890
9928
|
if ((requestedKind === "render" || requestedKind === "capture" || requestedKind === "scan" || requestedKind === "journey-output" || requestedKind === "journey-output-shard" || requestedKind === "journey-output-verify" || requestedKind === "journey-base") && message.result.kind !== requestedKind) {
|
|
@@ -15473,7 +15511,7 @@ async function sessionFileFacts(file, size, signal) {
|
|
|
15473
15511
|
/** Verify bounded final redacted bytes before starting a second ZIP codec. */
|
|
15474
15512
|
async function sessionPart(entry, expected, signal) {
|
|
15475
15513
|
if (expected.byteLength > 268435456 || entry.uncompressedSize !== expected.byteLength) fail("ARTIFACT_PART_LIMIT");
|
|
15476
|
-
const
|
|
15514
|
+
const scratch = expected.byteLength <= 65536 ? { bytes: new Uint8Array(expected.byteLength) } : { file: await sessionFile() };
|
|
15477
15515
|
let size = 0;
|
|
15478
15516
|
const digest = createHash("sha256");
|
|
15479
15517
|
let crc = 0;
|
|
@@ -15483,11 +15521,14 @@ async function sessionPart(entry, expected, signal) {
|
|
|
15483
15521
|
if (size + bytes.byteLength > expected.byteLength) fail("ARTIFACT_PART_LIMIT");
|
|
15484
15522
|
digest.update(bytes);
|
|
15485
15523
|
crc = crc32(bytes, crc);
|
|
15486
|
-
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15524
|
+
if (scratch.bytes) scratch.bytes.set(bytes, size);
|
|
15525
|
+
else {
|
|
15526
|
+
let offset = 0;
|
|
15527
|
+
while (offset < bytes.byteLength) {
|
|
15528
|
+
const { bytesWritten } = await scratch.file.write(bytes, offset, bytes.byteLength - offset, size + offset);
|
|
15529
|
+
if (!bytesWritten) fail("ARTIFACT_IO_FAILED");
|
|
15530
|
+
offset += bytesWritten;
|
|
15531
|
+
}
|
|
15491
15532
|
}
|
|
15492
15533
|
size += bytes.byteLength;
|
|
15493
15534
|
} }), {
|
|
@@ -15495,55 +15536,93 @@ async function sessionPart(entry, expected, signal) {
|
|
|
15495
15536
|
checkSignature: true
|
|
15496
15537
|
});
|
|
15497
15538
|
if (size !== expected.byteLength || digest.digest("hex") !== expected.sha256) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15539
|
+
const reader = scratch.bytes ? new Uint8ArrayReader(scratch.bytes) : new FileReader(scratch.file, size, 262144, true, signal);
|
|
15498
15540
|
return {
|
|
15499
|
-
file,
|
|
15541
|
+
file: scratch.file,
|
|
15542
|
+
reader,
|
|
15500
15543
|
crc32: crc
|
|
15501
15544
|
};
|
|
15502
15545
|
} catch (error) {
|
|
15503
15546
|
const cleanup = createCleanup();
|
|
15504
15547
|
cleanup.failed(error);
|
|
15505
|
-
|
|
15548
|
+
const { file } = scratch;
|
|
15549
|
+
if (file) await cleanup.run(() => file.close());
|
|
15506
15550
|
throw error;
|
|
15507
15551
|
}
|
|
15508
15552
|
}
|
|
15509
15553
|
//#endregion
|
|
15510
15554
|
//#region packages/artifact/src/configured/output/sessions.ts
|
|
15511
|
-
|
|
15512
|
-
async function* configuredSessionUploads(input, identities, signal) {
|
|
15555
|
+
async function* configuredSessionUploads(input, identities, signal, mode = "upload", omitted = /* @__PURE__ */ new Set(), checkMinimumBytes) {
|
|
15513
15556
|
const verified = await checkFrozenOutput(input, signal);
|
|
15514
15557
|
const archive = await openCheckedOutput(input, verified.checked, signal);
|
|
15515
15558
|
const cleanup = createCleanup();
|
|
15516
15559
|
try {
|
|
15517
15560
|
if (archive.manifestText !== verified.manifestText) fail("ARTIFACT_PROCESSING_MISMATCH");
|
|
15518
15561
|
const descriptions = new Map(verified.manifest.entries.map((entry) => [entry.entryPath, entry]));
|
|
15562
|
+
const byId = new Map(identities.map((identity) => [identity.archiveSessionId, identity]));
|
|
15563
|
+
if (byId.size !== identities.length) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15564
|
+
if (checkMinimumBytes) {
|
|
15565
|
+
const measured = /* @__PURE__ */ new Set();
|
|
15566
|
+
let bytes = 0;
|
|
15567
|
+
for (const session of verified.manifest.sessions) {
|
|
15568
|
+
if (omitted.has(session.id)) continue;
|
|
15569
|
+
if (!byId.has(session.id)) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15570
|
+
for (const part of session.parts) {
|
|
15571
|
+
const entry = descriptions.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15572
|
+
if (measured.has(entry.sha256)) continue;
|
|
15573
|
+
measured.add(entry.sha256);
|
|
15574
|
+
bytes += entry.byteLength;
|
|
15575
|
+
}
|
|
15576
|
+
}
|
|
15577
|
+
checkMinimumBytes(bytes);
|
|
15578
|
+
}
|
|
15579
|
+
const workspaces = new Map(verified.manifest.sourceWorkspaces.map((workspace) => [workspace.id, workspace]));
|
|
15580
|
+
const workspaceFacts = /* @__PURE__ */ new Map();
|
|
15519
15581
|
for (const session of verified.manifest.sessions) {
|
|
15520
15582
|
signal.throwIfAborted();
|
|
15521
|
-
|
|
15522
|
-
const
|
|
15523
|
-
const
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15583
|
+
if (omitted.has(session.id)) continue;
|
|
15584
|
+
const identity = byId.get(session.id) ?? fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15585
|
+
const workspace = workspaces.get(session.workspaceId) ?? fail("ARTIFACT_INVALID_MANIFEST");
|
|
15586
|
+
let facts = workspaceFacts.get(workspace.id);
|
|
15587
|
+
if (!facts) {
|
|
15588
|
+
const entry = archive.entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15589
|
+
const description = descriptions.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15590
|
+
const text = await readMetadata(entry, signal);
|
|
15591
|
+
if (Buffer.byteLength(text) !== description.byteLength || createHash("sha256").update(text).digest("hex") !== description.sha256) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15592
|
+
const { version: _, ...validated } = validateConfiguredSourceMetadata(strictJson(text, metadataLimitBytes), workspace);
|
|
15593
|
+
facts = validated;
|
|
15594
|
+
workspaceFacts.set(workspace.id, facts);
|
|
15595
|
+
}
|
|
15528
15596
|
const native = session.parts[0]?.native;
|
|
15529
15597
|
const nativeSessionId = native?.sessionId ?? session.sourceSessionId;
|
|
15530
15598
|
if (!nativeSessionId?.trim() && !identity.relativePath) fail("ARTIFACT_IDENTITY_MISMATCH");
|
|
15531
15599
|
const metadata = {
|
|
15532
|
-
workspace:
|
|
15600
|
+
workspace: {
|
|
15601
|
+
...facts,
|
|
15602
|
+
remoteHashes: [...facts.remoteHashes]
|
|
15603
|
+
},
|
|
15533
15604
|
sourceSessionId: nativeSessionId,
|
|
15534
15605
|
harness: session.harness,
|
|
15535
15606
|
lastAt: identity.lastAt,
|
|
15536
15607
|
parts: []
|
|
15537
15608
|
};
|
|
15538
|
-
const file = await sessionFile();
|
|
15609
|
+
const file = mode === "upload" ? await sessionFile() : null;
|
|
15539
15610
|
const sessionCleanup = createCleanup();
|
|
15540
15611
|
try {
|
|
15541
15612
|
let size = 0;
|
|
15542
|
-
const
|
|
15613
|
+
const limit = (bytes) => {
|
|
15543
15614
|
if (bytes > 5 * 1024 ** 3) fail("ARTIFACT_ARCHIVE_LIMIT");
|
|
15544
15615
|
size = bytes;
|
|
15545
|
-
}
|
|
15546
|
-
const
|
|
15616
|
+
};
|
|
15617
|
+
const digest = createHash("sha256");
|
|
15618
|
+
let checksum = 0;
|
|
15619
|
+
const writable = file ? fileWriter(file, signal, limit, false).writable : new WritableStream({ write(bytes) {
|
|
15620
|
+
signal.throwIfAborted();
|
|
15621
|
+
limit(size + bytes.byteLength);
|
|
15622
|
+
digest.update(bytes);
|
|
15623
|
+
checksum = crc32(bytes, checksum);
|
|
15624
|
+
} });
|
|
15625
|
+
const zip = new ZipWriter(writable, {
|
|
15547
15626
|
useWebWorkers: false,
|
|
15548
15627
|
useCompressionStream: true,
|
|
15549
15628
|
bufferedWrite: false,
|
|
@@ -15559,24 +15638,30 @@ async function* configuredSessionUploads(input, identities, signal) {
|
|
|
15559
15638
|
const partCleanup = createCleanup();
|
|
15560
15639
|
try {
|
|
15561
15640
|
const path = `p${String(index + 1).padStart(6, "0")}.jsonl`;
|
|
15562
|
-
await zip.add(path,
|
|
15641
|
+
await zip.add(path, prepared.reader, { signal });
|
|
15563
15642
|
metadata.parts.push({
|
|
15564
15643
|
path,
|
|
15565
15644
|
byteLength: expected.byteLength,
|
|
15566
15645
|
sha256: expected.sha256,
|
|
15567
|
-
crc32: prepared.crc32
|
|
15646
|
+
crc32: prepared.crc32,
|
|
15647
|
+
native: part.native
|
|
15568
15648
|
});
|
|
15569
15649
|
} catch (error) {
|
|
15570
15650
|
partCleanup.failed(error);
|
|
15571
15651
|
throw error;
|
|
15572
15652
|
} finally {
|
|
15573
|
-
|
|
15653
|
+
const { file } = prepared;
|
|
15654
|
+
if (file) await partCleanup.run(() => file.close());
|
|
15574
15655
|
}
|
|
15575
15656
|
}
|
|
15576
15657
|
await zip.close();
|
|
15577
15658
|
if (zip.warnings?.length) fail("ARTIFACT_INVALID_ARCHIVE");
|
|
15578
15659
|
if (size > 5 * 1024 ** 3) fail("ARTIFACT_ARCHIVE_LIMIT");
|
|
15579
|
-
const content = await sessionFileFacts(file, size, signal)
|
|
15660
|
+
const content = file ? await sessionFileFacts(file, size, signal) : {
|
|
15661
|
+
byteLength: size,
|
|
15662
|
+
sha256: digest.digest("hex"),
|
|
15663
|
+
crc32: checksum
|
|
15664
|
+
};
|
|
15580
15665
|
await archive.fence();
|
|
15581
15666
|
yield {
|
|
15582
15667
|
...content,
|
|
@@ -15586,13 +15671,13 @@ async function* configuredSessionUploads(input, identities, signal) {
|
|
|
15586
15671
|
relativePath: identity.relativePath,
|
|
15587
15672
|
harness: session.harness,
|
|
15588
15673
|
lastAt: identity.lastAt,
|
|
15589
|
-
stream: () => new FileReader(file, size, 262144, true, signal).createReadable()
|
|
15674
|
+
...file ? { stream: () => new FileReader(file, size, 262144, true, signal).createReadable() } : {}
|
|
15590
15675
|
};
|
|
15591
15676
|
} catch (error) {
|
|
15592
15677
|
sessionCleanup.failed(error);
|
|
15593
15678
|
throw error;
|
|
15594
15679
|
} finally {
|
|
15595
|
-
await sessionCleanup.run(() => file.close());
|
|
15680
|
+
if (file) await sessionCleanup.run(() => file.close());
|
|
15596
15681
|
}
|
|
15597
15682
|
}
|
|
15598
15683
|
} catch (error) {
|
|
@@ -16361,7 +16446,7 @@ const maxChunks = 8e4;
|
|
|
16361
16446
|
function batchLoad(body) {
|
|
16362
16447
|
return Math.max(body.chunks.length / maxChunks, (body.duplicates?.length ?? 0) / maxChunks, Buffer.byteLength(JSON.stringify(body)) / maxTransportBytes);
|
|
16363
16448
|
}
|
|
16364
|
-
function location(context, fieldId, part) {
|
|
16449
|
+
function location$1(context, fieldId, part) {
|
|
16365
16450
|
const source = context.locations.get(fieldId);
|
|
16366
16451
|
if (!source) throw new ApplicationError("CORRUPTED_STATE");
|
|
16367
16452
|
const native = reviewSource(source);
|
|
@@ -16400,7 +16485,7 @@ function reviewBatchBody(context, unit, ordinal) {
|
|
|
16400
16485
|
};
|
|
16401
16486
|
const chunks = unit.fragments.map((part) => ({
|
|
16402
16487
|
id: chunkId(part.fieldId, part),
|
|
16403
|
-
...location(context, part.fieldId, part),
|
|
16488
|
+
...location$1(context, part.fieldId, part),
|
|
16404
16489
|
core: part.core,
|
|
16405
16490
|
offset: part.utf16Start,
|
|
16406
16491
|
text: part.text,
|
|
@@ -16420,7 +16505,7 @@ function reviewBatchBody(context, unit, ordinal) {
|
|
|
16420
16505
|
utf16Start: part.utf16Start + shift.utf16,
|
|
16421
16506
|
utf16End: part.utf16End + shift.utf16
|
|
16422
16507
|
};
|
|
16423
|
-
const { displayMasks, ...own } = location(context, duplicate.fieldId, copy);
|
|
16508
|
+
const { displayMasks, ...own } = location$1(context, duplicate.fieldId, copy);
|
|
16424
16509
|
const hash = fieldHash(duplicate.fieldId);
|
|
16425
16510
|
return {
|
|
16426
16511
|
id: chunkId(duplicate.fieldId, copy),
|
|
@@ -17011,4 +17096,277 @@ async function verifyPreparedSessionSources(prepared, input, signal) {
|
|
|
17011
17096
|
}
|
|
17012
17097
|
}
|
|
17013
17098
|
//#endregion
|
|
17014
|
-
|
|
17099
|
+
//#region packages/artifact/src/configured/output/session-mask-equivalence.ts
|
|
17100
|
+
const exactMarker = new RegExp("^(?:" + replacementMarkerPattern.source + ")$", "u");
|
|
17101
|
+
function sessionMaskProof(row) {
|
|
17102
|
+
const lineage = row.contributors.map((item) => {
|
|
17103
|
+
const { inputRange, context } = item.kind === "static" ? item.source.mask : item.source;
|
|
17104
|
+
const quote = context.text.slice(inputRange.start - context.start, inputRange.end - context.start);
|
|
17105
|
+
const basis = item.kind === "static" ? [
|
|
17106
|
+
item.source.sourceRecordIndex,
|
|
17107
|
+
item.source.mask.originalPointer,
|
|
17108
|
+
item.source.mask.sourceRange,
|
|
17109
|
+
item.source.mask.inputSha256,
|
|
17110
|
+
item.source.mask.stepId,
|
|
17111
|
+
item.source.mask.node.id,
|
|
17112
|
+
item.source.mask.node.version,
|
|
17113
|
+
item.source.mask.ruleId
|
|
17114
|
+
] : [item.source.pointer];
|
|
17115
|
+
return JSON.stringify([
|
|
17116
|
+
item.kind,
|
|
17117
|
+
item.category,
|
|
17118
|
+
basis,
|
|
17119
|
+
inputRange.start,
|
|
17120
|
+
inputRange.end,
|
|
17121
|
+
quote
|
|
17122
|
+
]);
|
|
17123
|
+
}).sort();
|
|
17124
|
+
const first = row.contributors[0];
|
|
17125
|
+
return {
|
|
17126
|
+
pointer: row.pointer,
|
|
17127
|
+
subject: row.subject,
|
|
17128
|
+
start: row.outputRange.start,
|
|
17129
|
+
end: row.outputRange.end,
|
|
17130
|
+
replacement: row.replacement,
|
|
17131
|
+
lineage: createHash("sha256").update(JSON.stringify([row.category, lineage])).digest("hex"),
|
|
17132
|
+
mayRename: row.subject === "value" && exactMarker.test(row.replacement) && row.contributors.length === 1 && first?.kind === "static" && first.source.sourceRecordIndex !== null && first.source.mask.sourceRange !== null && first.source.mask.originalPointer !== null && first.source.mask.outputPointer === row.pointer && first.source.mask.subject === row.subject && first.source.mask.replacement === row.replacement
|
|
17133
|
+
};
|
|
17134
|
+
}
|
|
17135
|
+
const location = (mask) => JSON.stringify([
|
|
17136
|
+
mask.pointer,
|
|
17137
|
+
mask.subject,
|
|
17138
|
+
mask.start,
|
|
17139
|
+
mask.end
|
|
17140
|
+
]);
|
|
17141
|
+
/** Both ledgers have already been independently joined to their own frozen output by the verifier. */
|
|
17142
|
+
function compareSessionRows(leftText, rightText, leftMasks, rightMasks) {
|
|
17143
|
+
if (leftMasks.length !== rightMasks.length) return null;
|
|
17144
|
+
const rightByLocation = new Map(rightMasks.map((mask) => [location(mask), mask]));
|
|
17145
|
+
if (rightByLocation.size !== rightMasks.length) return null;
|
|
17146
|
+
const changes = /* @__PURE__ */ new Map();
|
|
17147
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
17148
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
17149
|
+
for (const left of leftMasks) {
|
|
17150
|
+
const key = location(left);
|
|
17151
|
+
const right = rightByLocation.get(key);
|
|
17152
|
+
if (!right || left.lineage !== right.lineage) return null;
|
|
17153
|
+
rightByLocation.delete(key);
|
|
17154
|
+
if (left.replacement === right.replacement) continue;
|
|
17155
|
+
if (!left.mayRename || !right.mayRename || left.start < 0 || left.end - left.start !== left.replacement.length || right.replacement.length !== left.replacement.length) return null;
|
|
17156
|
+
const prior = aliases.get(left.replacement);
|
|
17157
|
+
const inverse = reverse.get(right.replacement);
|
|
17158
|
+
if (prior !== void 0 && prior !== right.replacement || inverse !== void 0 && inverse !== left.replacement) return null;
|
|
17159
|
+
aliases.set(left.replacement, right.replacement);
|
|
17160
|
+
reverse.set(right.replacement, left.replacement);
|
|
17161
|
+
const masks = changes.get(left.pointer) ?? [];
|
|
17162
|
+
masks.push(left);
|
|
17163
|
+
changes.set(left.pointer, masks);
|
|
17164
|
+
}
|
|
17165
|
+
if (!aliases.size) return leftText === rightText ? { aliases: [] } : null;
|
|
17166
|
+
const limits = {
|
|
17167
|
+
...defaultLimits,
|
|
17168
|
+
maxRecordBytes: maximumRecordBytes
|
|
17169
|
+
};
|
|
17170
|
+
let tree;
|
|
17171
|
+
try {
|
|
17172
|
+
tree = parseNativeRecord(leftText, limits, new AbortController().signal);
|
|
17173
|
+
} catch {
|
|
17174
|
+
return null;
|
|
17175
|
+
}
|
|
17176
|
+
const changedCount = [...changes.values()].reduce((sum, field) => sum + field.length, 0);
|
|
17177
|
+
function authenticOccurrences(root, destination) {
|
|
17178
|
+
let used = 0;
|
|
17179
|
+
const markers = destination ? reverse : aliases;
|
|
17180
|
+
function check(node, pointer) {
|
|
17181
|
+
if (node.kind === "array") return node.items.every((item, i) => check(item, pointer + "/" + i));
|
|
17182
|
+
if (node.kind === "object") return node.properties.every(({ key, value }) => {
|
|
17183
|
+
for (const found of key.value.matchAll(replacementMarkerPattern)) if (markers.has(found[0])) return false;
|
|
17184
|
+
return check(value, pointer + "/" + key.value.replaceAll("~", "~0").replaceAll("/", "~1"));
|
|
17185
|
+
});
|
|
17186
|
+
if (node.kind !== "string") return true;
|
|
17187
|
+
const expected = new Map((changes.get(pointer) ?? []).map((mask) => [mask.start, mask]));
|
|
17188
|
+
for (const found of node.value.matchAll(replacementMarkerPattern)) {
|
|
17189
|
+
if (!markers.has(found[0])) continue;
|
|
17190
|
+
const mask = expected.get(found.index);
|
|
17191
|
+
if (!mask || (destination ? aliases.get(mask.replacement) : mask.replacement) !== found[0]) return false;
|
|
17192
|
+
expected.delete(found.index);
|
|
17193
|
+
used++;
|
|
17194
|
+
}
|
|
17195
|
+
return expected.size === 0;
|
|
17196
|
+
}
|
|
17197
|
+
return check(root, "") && used === changedCount;
|
|
17198
|
+
}
|
|
17199
|
+
if (!authenticOccurrences(tree, false)) return null;
|
|
17200
|
+
for (const winner of aliases.values()) if (aliases.has(winner)) return null;
|
|
17201
|
+
let replaced = 0;
|
|
17202
|
+
const renamed = leftText.replace(replacementMarkerPattern, (marker) => {
|
|
17203
|
+
const mapped = aliases.get(marker);
|
|
17204
|
+
if (!mapped) return marker;
|
|
17205
|
+
replaced++;
|
|
17206
|
+
return mapped;
|
|
17207
|
+
});
|
|
17208
|
+
if (changedCount !== replaced || renamed !== rightText) return null;
|
|
17209
|
+
try {
|
|
17210
|
+
if (!authenticOccurrences(parseNativeRecord(rightText, limits, new AbortController().signal), true)) return null;
|
|
17211
|
+
} catch {
|
|
17212
|
+
return null;
|
|
17213
|
+
}
|
|
17214
|
+
return { aliases: [...aliases] };
|
|
17215
|
+
}
|
|
17216
|
+
//#endregion
|
|
17217
|
+
//#region packages/artifact/src/configured/output/session-source-prefix.ts
|
|
17218
|
+
/**
|
|
17219
|
+
* Both parts come from the verified frozen primary. The caller locates longerSource through
|
|
17220
|
+
* its base source binding. A copied log may have a different path or inode from its ancestor.
|
|
17221
|
+
*/
|
|
17222
|
+
async function sessionSourcePrefix(short, long, longerSource, signal) {
|
|
17223
|
+
checkAbort(signal);
|
|
17224
|
+
if (!short.native.sessionId?.trim() || !["main", "worker"].includes(short.native.role) || !isDeepStrictEqual(short.native, long.native) || short.source.representation !== long.source.representation || short.source.byteLength > long.source.byteLength || short.recordCount > long.recordCount || short.retainedRecordCount > long.retainedRecordCount) return false;
|
|
17225
|
+
if (short.source.byteLength === long.source.byteLength) return short.source.sha256 === long.source.sha256 && short.recordCount === long.recordCount;
|
|
17226
|
+
if (long.source.representation !== "jsonl" || !longerSource || longerSource.representation !== "jsonl" || longerSource.snapshot.size !== long.source.byteLength || short.source.byteLength === 0 || short.recordCount === long.recordCount) return false;
|
|
17227
|
+
try {
|
|
17228
|
+
checkNativeEvidence(longerSource, long.native);
|
|
17229
|
+
const input = await openConfiguredSource(longerSource, signal, void 0, "stable-prefix");
|
|
17230
|
+
try {
|
|
17231
|
+
const prefix = createHash("sha256");
|
|
17232
|
+
let remaining = short.source.byteLength;
|
|
17233
|
+
let endsAtRecord = false;
|
|
17234
|
+
for await (const chunk of input.chunks) {
|
|
17235
|
+
const take = Math.min(remaining, chunk.byteLength);
|
|
17236
|
+
if (take === 0) continue;
|
|
17237
|
+
prefix.update(chunk.subarray(0, take));
|
|
17238
|
+
remaining -= take;
|
|
17239
|
+
if (remaining === 0) endsAtRecord = chunk[take - 1] === 10;
|
|
17240
|
+
}
|
|
17241
|
+
const full = await input.finish();
|
|
17242
|
+
return remaining === 0 && endsAtRecord && prefix.digest("hex") === short.source.sha256 && full.sha256 === long.source.sha256 && full.byteLength === long.source.byteLength;
|
|
17243
|
+
} finally {
|
|
17244
|
+
await input.close();
|
|
17245
|
+
}
|
|
17246
|
+
} catch (error) {
|
|
17247
|
+
checkAbort(signal);
|
|
17248
|
+
if ([
|
|
17249
|
+
"ARTIFACT_SOURCE_CHANGED",
|
|
17250
|
+
"ARTIFACT_SOURCE_MISSING",
|
|
17251
|
+
"ARTIFACT_SOURCE_UNSAFE",
|
|
17252
|
+
"ARTIFACT_SOURCE_UNREADABLE",
|
|
17253
|
+
"ARTIFACT_SOURCE_TRUNCATED"
|
|
17254
|
+
].includes(safeError(error).message)) return false;
|
|
17255
|
+
throw error;
|
|
17256
|
+
}
|
|
17257
|
+
}
|
|
17258
|
+
//#endregion
|
|
17259
|
+
//#region packages/artifact/src/configured/output/session-extension.ts
|
|
17260
|
+
/** Choose an entire already-approved variant. No edited or reconstructed bytes enter transport. */
|
|
17261
|
+
async function sessionExtensions(input, signal) {
|
|
17262
|
+
const verified = await checkFrozenOutput(input.primary, signal);
|
|
17263
|
+
const { manifest } = verified;
|
|
17264
|
+
const sessions = new Map(manifest.sessions.map((session) => [session.id, session]));
|
|
17265
|
+
const groups = input.groups.map((group) => group.map((id) => sessions.get(id) ?? fail("ARTIFACT_IDENTITY_MISMATCH")));
|
|
17266
|
+
const paths = new Set(groups.flat().flatMap((session) => session.parts.map((part) => part.dataPath)));
|
|
17267
|
+
const masks = /* @__PURE__ */ new Map();
|
|
17268
|
+
for await (const row of readLogicalJourneyFinalMasks({
|
|
17269
|
+
ledger: input.ledger,
|
|
17270
|
+
primary: input.primary
|
|
17271
|
+
}, signal, paths)) {
|
|
17272
|
+
const entry = masks.get(row.entryPath) ?? /* @__PURE__ */ new Map();
|
|
17273
|
+
if (!masks.has(row.entryPath)) masks.set(row.entryPath, entry);
|
|
17274
|
+
const list = entry.get(row.recordIndex) ?? [];
|
|
17275
|
+
list.push(sessionMaskProof(row));
|
|
17276
|
+
entry.set(row.recordIndex, list);
|
|
17277
|
+
}
|
|
17278
|
+
const archive = await openCheckedOutput(input.primary, verified.checked, signal);
|
|
17279
|
+
const omitted = /* @__PURE__ */ new Set();
|
|
17280
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
17281
|
+
try {
|
|
17282
|
+
for (const group of groups) {
|
|
17283
|
+
const score = (s) => s.parts.reduce((sum, p) => sum + p.retainedRecordCount, 0);
|
|
17284
|
+
const sorted = group.toSorted((a, b) => score(b) - score(a) || Date.parse(input.lastAt(b.id)) - Date.parse(input.lastAt(a.id)) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
17285
|
+
const winner = sorted[0];
|
|
17286
|
+
if (!winner) continue;
|
|
17287
|
+
for (const shorter of sorted.slice(1)) {
|
|
17288
|
+
if (shorter.workspaceId !== winner.workspaceId || shorter.harness !== winner.harness || shorter.treatmentId !== winner.treatmentId || shorter.sourceSessionId !== winner.sourceSessionId || shorter.parts.length !== winner.parts.length || Date.parse(input.lastAt(shorter.id)) > Date.parse(input.lastAt(winner.id))) return null;
|
|
17289
|
+
for (const [index, part] of shorter.parts.entries()) {
|
|
17290
|
+
const long = winner.parts[index];
|
|
17291
|
+
if (!long || part.retainedRecordCount > long.retainedRecordCount || !await sessionSourcePrefix(part, long, input.sourceFor(winner.id, long.sourceId), signal)) return null;
|
|
17292
|
+
if (!await compareParts(archive, manifest, part, long, masks, aliases, signal)) return null;
|
|
17293
|
+
}
|
|
17294
|
+
omitted.add(shorter.id);
|
|
17295
|
+
}
|
|
17296
|
+
}
|
|
17297
|
+
for (const value of aliases.values()) if (aliases.has(value)) return null;
|
|
17298
|
+
await archive.fence();
|
|
17299
|
+
return {
|
|
17300
|
+
omitted,
|
|
17301
|
+
retired: new Set(aliases.keys())
|
|
17302
|
+
};
|
|
17303
|
+
} finally {
|
|
17304
|
+
await archive.close();
|
|
17305
|
+
}
|
|
17306
|
+
}
|
|
17307
|
+
async function compareParts(archive, manifest, short, long, masks, aliases, signal) {
|
|
17308
|
+
const cleanup = createCleanup();
|
|
17309
|
+
const spools = [];
|
|
17310
|
+
try {
|
|
17311
|
+
for (const part of [short, long]) {
|
|
17312
|
+
const entry = archive.entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17313
|
+
const expected = manifest.entries.find((d) => d.entryPath === part.dataPath) ?? fail("ARTIFACT_INVALID_MANIFEST");
|
|
17314
|
+
spools.push(await spoolFacts(entry, expected, signal));
|
|
17315
|
+
}
|
|
17316
|
+
const [a, b] = spools;
|
|
17317
|
+
if (!a || !b) return fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17318
|
+
let count = 0;
|
|
17319
|
+
for await (const row of a.lines) {
|
|
17320
|
+
const match = await b.lines.next();
|
|
17321
|
+
if (match.done) return false;
|
|
17322
|
+
const proof = compareSessionRows(row, match.value, masks.get(short.dataPath)?.get(count) ?? [], masks.get(long.dataPath)?.get(count) ?? []);
|
|
17323
|
+
if (!proof) return false;
|
|
17324
|
+
for (const [old, chosen] of proof.aliases) {
|
|
17325
|
+
if (aliases.has(old) && aliases.get(old) !== chosen) return false;
|
|
17326
|
+
aliases.set(old, chosen);
|
|
17327
|
+
}
|
|
17328
|
+
count++;
|
|
17329
|
+
}
|
|
17330
|
+
if (count !== short.retainedRecordCount) return false;
|
|
17331
|
+
for await (const _ of b.lines) count++;
|
|
17332
|
+
return count === long.retainedRecordCount;
|
|
17333
|
+
} catch (error) {
|
|
17334
|
+
cleanup.failed(error);
|
|
17335
|
+
throw error;
|
|
17336
|
+
} finally {
|
|
17337
|
+
await cleanup.run(...spools.flatMap((s) => [() => s.lines.return(void 0), () => s.close()]));
|
|
17338
|
+
}
|
|
17339
|
+
}
|
|
17340
|
+
/** Matches complete decoded marker spellings, including Unicode escape spellings in native JSON. */
|
|
17341
|
+
function refersToRetiredMarker(text, retired) {
|
|
17342
|
+
let candidate = text;
|
|
17343
|
+
for (let depth = 0; /\\u[\da-f]{4}/iu.test(candidate); depth++) {
|
|
17344
|
+
if (depth >= 8) return true;
|
|
17345
|
+
candidate = candidate.replace(/\\+u([\da-f]{4})/giu, (_, digits) => String.fromCharCode(Number.parseInt(digits, 16)));
|
|
17346
|
+
}
|
|
17347
|
+
for (const match of candidate.matchAll(replacementMarkerPattern)) if (retired.has(match[0])) return true;
|
|
17348
|
+
return false;
|
|
17349
|
+
}
|
|
17350
|
+
/** Search all kept uploaded fields of a confirmed Work before retiring an alias in another session. */
|
|
17351
|
+
async function hasRetiredSessionMarker(primary, omitted, retired, signal) {
|
|
17352
|
+
if (!retired.size) return false;
|
|
17353
|
+
const verified = await checkFrozenOutput(primary, signal);
|
|
17354
|
+
const archive = await openCheckedOutput(primary, verified.checked, signal);
|
|
17355
|
+
try {
|
|
17356
|
+
const entries = new Map(verified.manifest.entries.map((entry) => [entry.entryPath, entry]));
|
|
17357
|
+
for (const workspace of verified.manifest.sourceWorkspaces) if (refersToRetiredMarker(await readOutputJson(archive.entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE"), entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE"), signal), retired)) return true;
|
|
17358
|
+
for (const session of verified.manifest.sessions) {
|
|
17359
|
+
if (omitted.has(session.id)) continue;
|
|
17360
|
+
for (const part of session.parts) {
|
|
17361
|
+
const entry = archive.entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17362
|
+
const expected = entries.get(part.dataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
|
|
17363
|
+
for await (const row of entryLines(entry, expected, signal)) if (refersToRetiredMarker(row, retired)) return true;
|
|
17364
|
+
}
|
|
17365
|
+
}
|
|
17366
|
+
return false;
|
|
17367
|
+
} finally {
|
|
17368
|
+
await archive.close();
|
|
17369
|
+
}
|
|
17370
|
+
}
|
|
17371
|
+
//#endregion
|
|
17372
|
+
export { decodeZstd as $, captureLogicalJourneySources as A, defaultParallelism as B, writePrivateReviewPayload as C, createCollectionArtifacts as D, readConfiguredSearchFields as E, parseCollectionWorkspaceSummary as F, readLogicalJourneyFinalMasks as G, parallelismLimits as H, createSharedSessionPool as I, staticMaskCategory as J, readConfiguredOutputInfo as K, SessionWorkerError as L, renderJobDigest as M, runConfiguredSessionJob as N, checkReusableBundle as O, readCollectionIndex as P, createInspectionProcessor as Q, sessionWorkerFailure as R, writeLogicalJourneyBase as S, readOriginalSearchFields as T, writeLogicalJourneyOutput as U, gitSeedsProvider as V, privateJourneyDirectory as W, listAgentSetup as X, readWorkspacePair as Y, createConfiguredPreviewStream as Z, captureConfiguredSessionJob as _, prepareSessionScans as a, makePrivateDirectory as at, readStaticSessionMasks as b, createWorkPieces as c, windowsOwnerOnly as ct, scanPreparedSession as d, createTemporary as et, runConfiguredScanJob as f, openConfiguredUpload as g, configuredSessionUploads as h, verifyPreparedSessionSources as i, exclusiveLock as it, capturedJourneyScope as j, prepareCollectionProduction as k, readSessionScanFields as l, isWindowsAclFailure as lt, writeOutputShard as m, sessionExtensions as n, createCleanup as nt, buildWorkScanBatches as o, openPrivateFile as ot, verifyOutputShard as p, processJourneyMetadataFields as q, preparedScanConfiguration as r, safeError as rt, scanReviewFields as s, restrictToOwner as st, hasRetiredSessionMarker as t, removeNamedTemporarySpools as tt, readSessionScanRecords as u, windowsAclCodes as ut, readCapturedOriginalRows as v, readPrivateReviewPayload as w, staticSessionJobs as x, processJourneyMetadata as y, privateCollectionDirectory as z };
|