@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.
Files changed (53) hide show
  1. package/README.md +4 -0
  2. package/bin/INDEX.md +6 -4
  3. package/bin/tacitt.cjs +1 -0
  4. package/dist/{agent-setup-DdfF3zch.mjs → agent-setup-B12VbvN_.mjs} +2 -2
  5. package/dist/agent-setup-worker.mjs +5 -5
  6. package/dist/cli.mjs +28 -28
  7. package/dist/codex-title-worker.mjs +2 -2
  8. package/dist/configured-preview-worker.mjs +5 -5
  9. package/dist/configured-session-worker.mjs +23 -25
  10. package/dist/{frame-Bq2zRh-i.mjs → frame-B3He21G8.mjs} +1 -1
  11. package/dist/{heap-CV8Eca8V.mjs → heap-Blrat--4.mjs} +260 -23
  12. package/dist/inspection-worker.mjs +4 -4
  13. package/dist/{job-BKsifhyv.mjs → job-CBuIMTQ0.mjs} +24 -9
  14. package/dist/{locate-Cx52Zqxv.mjs → locate-D-ZaHpI0.mjs} +5 -0
  15. package/dist/{model-C1UXkHh9.mjs → model-DR9odhWP.mjs} +1 -1
  16. package/dist/operation-executor.mjs +3 -3
  17. package/dist/preview-worker.mjs +1 -1
  18. package/dist/privacy-validator.mjs +28 -8
  19. package/dist/{query-AMZerUh8.mjs → query-BYDcNKy2.mjs} +1614 -679
  20. package/dist/{run-CaPktPhH.mjs → run-DQ9xyKSt.mjs} +4 -4
  21. package/dist/session-process.mjs +20 -0
  22. package/dist/{src-wZx_v0Ih.mjs → src-CKQlTA2Z.mjs} +4 -4
  23. package/dist/{src-DlVbGB32.mjs → src-DeNJ8vOD.mjs} +465 -107
  24. package/dist/{src-D1iONla3.mjs → src-Do-qzuMn.mjs} +377 -130
  25. package/dist/store-database-worker.mjs +1 -1
  26. package/dist/web/assets/index-BgDdPL1c.js +172 -0
  27. package/dist/web/index.html +2 -1
  28. package/package.json +2 -1
  29. package/skills/INDEX.md +6 -4
  30. package/skills/tacitt/INDEX.md +7 -6
  31. package/skills/tacitt/SKILL.md +5 -5
  32. package/skills/tacitt/references/INDEX.md +14 -11
  33. package/skills/tacitt/references/b-method.md +4 -4
  34. package/skills/tacitt/references/bootstrap.md +17 -3
  35. package/skills/tacitt/references/classification.md +1 -1
  36. package/skills/tacitt/references/commands.md +24 -6
  37. package/skills/tacitt/references/journey.md +4 -4
  38. package/skills/tacitt/references/parallel-review.md +13 -7
  39. package/skills/tacitt/references/send.md +7 -3
  40. package/skills/tacitt/scripts/INDEX.md +40 -37
  41. package/skills/tacitt/scripts/answer.mjs +19 -1
  42. package/skills/tacitt/scripts/journey-card-consolidation.mjs +1 -1
  43. package/skills/tacitt/scripts/journey-classification-tasks.mjs +28 -8
  44. package/skills/tacitt/scripts/journey-panel-host.d.mts +2 -0
  45. package/skills/tacitt/scripts/journey-panel-host.mjs +25 -2
  46. package/skills/tacitt/scripts/journey-scan-timing.d.mts +4 -0
  47. package/skills/tacitt/scripts/journey-scan-timing.mjs +12 -0
  48. package/skills/tacitt/scripts/journey-state.mjs +11 -0
  49. package/skills/tacitt/scripts/journey-tasks.mjs +12 -5
  50. package/skills/tacitt/scripts/journey.mjs +10 -2
  51. package/skills/tacitt/scripts/privacy-validator.mjs +28 -7
  52. package/skills/tacitt/scripts/review.mjs +399 -99
  53. 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-Cx52Zqxv.mjs";
2
- import { t as createZstdFrameCheck } from "./frame-Bq2zRh-i.mjs";
3
- import { Jr as agentSourceSchema, L as sourceIdentityEvidence, Pn as resolveSourceSelection, R as withSourceEvidence, _i as sourceChangePolicy, jt as metadataProcessingVersion, nr as bContainment, or as bWordBounded, ot as classifyAgentSetup, qr as agentSourcePathSegment, rr as bExceptionRanges, st as defaultAgentSetupInclusion, wi as staticCatalogRef, yi as approvedTreatmentSchema, z as agentSetupKey } from "./src-D1iONla3.mjs";
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(text, entries, bundleId, expectedPathHash, summary) {
1878
- const manifest = record$1(strictJson(text, manifestLimitBytes, manifestNodeLimit));
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(text) : null;
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$1 = (pointer, subject) => `${subject}:${pointer}`;
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$1(pointer, subject);
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$1(field.pointer, field.subject);
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$1(field.pointer, field.subject))?.kind !== "string")) fail("ARTIFACT_INVALID_ARCHIVE");
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(text) {
2647
- const manifest = record$1(parseConfiguredManifest(text));
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: string(manifest["bundleId"]),
2653
- counts: parseCounts(manifest["counts"]),
2654
- sessions: array(manifest["sessions"], (value) => {
2655
- const session = record$1(value);
2656
- const harness = session["harness"];
2657
- if (harness !== "claude" && harness !== "codex") return fail("ARTIFACT_INVALID_MANIFEST");
2658
- return {
2659
- sessionId: string(session["id"]),
2660
- scopeOrdinal: 0,
2661
- harness,
2662
- nativeSessionId: nullableString(session["sourceSessionId"]),
2663
- treatmentId: string(session["treatmentId"]),
2664
- sources: array(session["parts"], parseConfiguredPart).map((part, sourceOrdinal) => ({
2665
- sourceId: part.sourceId,
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 manifestText = "";
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(text, entries, manifest.bundleId, manifest.sourceWorkspaces.length === 1 ? manifest.sourceWorkspaces[0]?.pathHash ?? null : null, workspaceSummary(text));
5595
- manifestText = text;
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
- manifestText,
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) for (const item of piece.items) {
7371
- const coordinates = (range) => sourceOffsets ? {
7372
- start: (sourceOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(piece.source.slice(0, range.start)),
7373
- end: (sourceOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(piece.source.slice(0, range.end))
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 inputRange = coordinates(item.inputRange);
7376
- const start = outputOffsets ? (outputOffsets.get(piece.node) ?? fail("ARTIFACT_PROCESSING_MISMATCH")) + encodedLength(piece.changed.slice(0, item.outputRange.start)) : item.outputRange.start;
7377
- const { span, ...applied } = item;
7378
- const transcript = {
7379
- ...applied,
7380
- pointer,
7381
- inputSha256,
7382
- outputSha256,
7383
- inputRange,
7384
- outputRange: {
7385
- start,
7386
- end: start + item.replacement.length
7387
- },
7388
- context: context(inputRange)
7389
- };
7390
- transcripts.push({
7391
- ...transcript,
7392
- contributors: reconstructedContributors({
7393
- row,
7394
- field: piece.field,
7395
- span,
7396
- transcript,
7397
- coordinates,
7398
- context
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
- for (const { term, category, bounded: whole } of hide.terms) {
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 raw = familySpans(field.text, family, signal);
7629
- const carrier = raw.length || field.text.includes("\\") ? familyCarrierSpans(field, (value) => familySpans(value, family, signal), signal) : void 0;
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) await removeStoppedSpools(slot.task.spoolPaths);
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 file = await sessionFile();
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
- let offset = 0;
15487
- while (offset < bytes.byteLength) {
15488
- const result = await file.write(bytes, offset, bytes.byteLength - offset, size + offset);
15489
- if (!result.bytesWritten) fail("ARTIFACT_IO_FAILED");
15490
- offset += result.bytesWritten;
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
- await cleanup.run(() => file.close());
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
- /** Each yielded spool stays open until the caller advances or closes this iterator. */
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
- const identity = identities.find((item) => item.archiveSessionId === session.id) ?? fail("ARTIFACT_IDENTITY_MISMATCH");
15522
- const workspace = verified.manifest.sourceWorkspaces.find((item) => item.id === session.workspaceId) ?? fail("ARTIFACT_INVALID_MANIFEST");
15523
- const entry = archive.entries.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
15524
- const description = descriptions.get(workspace.metadataPath) ?? fail("ARTIFACT_INVALID_ARCHIVE");
15525
- const text = await readMetadata(entry, signal);
15526
- if (Buffer.byteLength(text) !== description.byteLength || createHash("sha256").update(text).digest("hex") !== description.sha256) fail("ARTIFACT_INVALID_ARCHIVE");
15527
- const { version: _, ...facts } = validateConfiguredSourceMetadata(strictJson(text, metadataLimitBytes), workspace);
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: facts,
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 sink = fileWriter(file, signal, (bytes) => {
15613
+ const limit = (bytes) => {
15543
15614
  if (bytes > 5 * 1024 ** 3) fail("ARTIFACT_ARCHIVE_LIMIT");
15544
15615
  size = bytes;
15545
- }, false);
15546
- const zip = new ZipWriter(sink.writable, {
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, new FileReader(prepared.file, expected.byteLength, 262144, true, signal), { signal });
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
- await partCleanup.run(() => prepared.file.close());
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
- export { removeNamedTemporarySpools as $, renderJobDigest as A, parallelismLimits as B, readOriginalSearchFields as C, prepareCollectionProduction as D, checkReusableBundle as E, SessionWorkerError as F, processJourneyMetadataFields as G, privateJourneyDirectory as H, sessionWorkerFailure as I, listAgentSetup as J, staticMaskCategory as K, privateCollectionDirectory as L, readCollectionIndex as M, parseCollectionWorkspaceSummary as N, captureLogicalJourneySources as O, createSharedSessionPool as P, createTemporary as Q, defaultParallelism as R, readPrivateReviewPayload as S, createCollectionArtifacts as T, readLogicalJourneyFinalMasks as U, writeLogicalJourneyOutput as V, readConfiguredOutputInfo as W, createInspectionProcessor as X, createConfiguredPreviewStream as Y, decodeZstd as Z, processJourneyMetadata as _, scanReviewFields as a, restrictToOwner as at, writeLogicalJourneyBase as b, readSessionScanRecords as c, windowsAclCodes as ct, verifyOutputShard as d, createCleanup as et, writeOutputShard as f, readCapturedOriginalRows as g, captureConfiguredSessionJob as h, buildWorkScanBatches as i, openPrivateFile as it, runConfiguredSessionJob as j, capturedJourneyScope as k, scanPreparedSession as l, openConfiguredUpload as m, verifyPreparedSessionSources as n, exclusiveLock as nt, createWorkPieces as o, windowsOwnerOnly as ot, configuredSessionUploads as p, readWorkspacePair as q, prepareSessionScans as r, makePrivateDirectory as rt, readSessionScanFields as s, isWindowsAclFailure as st, preparedScanConfiguration as t, safeError as tt, runConfiguredScanJob as u, readStaticSessionMasks as v, readConfiguredSearchFields as w, writePrivateReviewPayload as x, staticSessionJobs as y, gitSeedsProvider as z };
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 };