@gitroll/tacitt-cli 0.6.10 → 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 (63) hide show
  1. package/README.md +47 -4
  2. package/bin/INDEX.md +6 -4
  3. package/bin/tacitt.cjs +1 -0
  4. package/dist/{agent-setup-LPd8WEsN.mjs → agent-setup-B12VbvN_.mjs} +2 -2
  5. package/dist/agent-setup-worker.mjs +5 -5
  6. package/dist/cli.mjs +39 -25
  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 +27 -27
  10. package/dist/{frame-ByT1xayJ.mjs → frame-B3He21G8.mjs} +1 -1
  11. package/dist/{heap-CM298Yu0.mjs → heap-Blrat--4.mjs} +469 -30
  12. package/dist/inspection-worker.mjs +4 -4
  13. package/dist/{job-BHIwElNF.mjs → job-CBuIMTQ0.mjs} +57 -22
  14. package/dist/{locate-Cwv6WH8n.mjs → locate-D-ZaHpI0.mjs} +184 -18
  15. package/dist/{model-zvn5GUJ9.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 +49 -2
  19. package/dist/{query-By41gaKm.mjs → query-BYDcNKy2.mjs} +1869 -716
  20. package/dist/{run-ZQx7p4Rw.mjs → run-DQ9xyKSt.mjs} +4 -4
  21. package/dist/session-process.mjs +20 -0
  22. package/dist/{src-D_DfY--2.mjs → src-CKQlTA2Z.mjs} +297 -207
  23. package/dist/{src-3jvMvSQn.mjs → src-DeNJ8vOD.mjs} +535 -140
  24. package/dist/{src-BqtdFVq7.mjs → src-Do-qzuMn.mjs} +2329 -1786
  25. package/dist/store-database-worker.mjs +1 -1
  26. package/dist/web/assets/index-BgDdPL1c.js +172 -0
  27. package/dist/web/assets/index-DzOozqms.css +1 -0
  28. package/dist/web/index.html +3 -2
  29. package/package.json +2 -1
  30. package/skills/INDEX.md +6 -4
  31. package/skills/tacitt/INDEX.md +7 -6
  32. package/skills/tacitt/SKILL.md +11 -11
  33. package/skills/tacitt/references/INDEX.md +14 -11
  34. package/skills/tacitt/references/b-method.md +4 -4
  35. package/skills/tacitt/references/bootstrap.md +19 -5
  36. package/skills/tacitt/references/classification.md +4 -4
  37. package/skills/tacitt/references/commands.md +51 -34
  38. package/skills/tacitt/references/journey.md +7 -7
  39. package/skills/tacitt/references/parallel-review.md +35 -35
  40. package/skills/tacitt/references/send.md +15 -6
  41. package/skills/tacitt/scripts/INDEX.md +40 -37
  42. package/skills/tacitt/scripts/answer.mjs +91 -15
  43. package/skills/tacitt/scripts/journey-card-consolidation.mjs +1 -1
  44. package/skills/tacitt/scripts/journey-classification-metadata.mjs +75 -26
  45. package/skills/tacitt/scripts/journey-classification-progress.mjs +1 -2
  46. package/skills/tacitt/scripts/journey-classification-tasks.mjs +28 -8
  47. package/skills/tacitt/scripts/journey-classification.mjs +6 -1
  48. package/skills/tacitt/scripts/journey-consolidation.mjs +1 -0
  49. package/skills/tacitt/scripts/journey-panel-host.d.mts +2 -0
  50. package/skills/tacitt/scripts/journey-panel-host.mjs +25 -2
  51. package/skills/tacitt/scripts/journey-scan-timing.d.mts +5 -0
  52. package/skills/tacitt/scripts/journey-scan-timing.mjs +31 -4
  53. package/skills/tacitt/scripts/journey-state.d.mts +9 -1
  54. package/skills/tacitt/scripts/journey-state.mjs +95 -8
  55. package/skills/tacitt/scripts/journey-tasks.d.mts +1 -0
  56. package/skills/tacitt/scripts/journey-tasks.mjs +24 -9
  57. package/skills/tacitt/scripts/journey.d.mts +44 -31
  58. package/skills/tacitt/scripts/journey.mjs +34 -7
  59. package/skills/tacitt/scripts/privacy-validator.mjs +188 -11
  60. package/skills/tacitt/scripts/review.d.mts +7 -6
  61. package/skills/tacitt/scripts/review.mjs +922 -205
  62. package/dist/web/assets/index-B14e6_-z.js +0 -174
  63. package/dist/web/assets/index-CYJBq1px.css +0 -1
@@ -21,12 +21,52 @@ const knownCodes = {
21
21
  function isProcessingCode(value) {
22
22
  return Object.prototype.hasOwnProperty.call(knownCodes, value);
23
23
  }
24
+ const sitePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+){0,7}$/;
25
+ const harnessPattern = /^[a-z]{1,16}$/;
26
+ const versionPattern = /^\d{1,6}(?:\.\d{1,6}){1,3}(?:-[0-9A-Za-z.]{1,24})?$/;
27
+ /** The validated site fields of `value`; anything that does not match its pattern is dropped. */
28
+ function siteFields(value) {
29
+ if (typeof value !== "object" || value === null) return void 0;
30
+ const site = Reflect.get(value, "site");
31
+ if (typeof site !== "string" || !sitePattern.test(site)) return void 0;
32
+ const harness = Reflect.get(value, "harness");
33
+ const harnessVersion = Reflect.get(value, "harnessVersion");
34
+ return {
35
+ site,
36
+ ...typeof harness === "string" && harnessPattern.test(harness) ? { harness } : {},
37
+ ...typeof harnessVersion === "string" && versionPattern.test(harnessVersion) ? { harnessVersion } : {}
38
+ };
39
+ }
40
+ /** The version string a harness record declares, when it has the shape of a version. */
41
+ function declaredVersion(value) {
42
+ return value !== void 0 && versionPattern.test(value) ? value : void 0;
43
+ }
44
+ /**
45
+ * The outermost named site in an error's cause chain (and aggregate members), if any. Depth first:
46
+ * a wide aggregate of wrapped refusals must not spend the visit budget before the first named one.
47
+ */
48
+ function processingSite(error) {
49
+ const stack = [error];
50
+ for (let visited = 0; visited < 32 && stack.length; visited++) {
51
+ const current = stack.pop();
52
+ if (!(current instanceof Error)) continue;
53
+ const found = siteFields(current);
54
+ if (found) return found;
55
+ if (current instanceof AggregateError) stack.push(...current.errors.slice(0, 16).reverse());
56
+ if (current.cause !== void 0) stack.push(current.cause);
57
+ }
58
+ }
24
59
  var ProcessingError = class extends Error {
25
60
  code;
61
+ site;
62
+ harness;
63
+ harnessVersion;
26
64
  constructor(code, options) {
27
65
  super(code, options);
28
66
  this.name = "ProcessingError";
29
67
  this.code = code;
68
+ const named = siteFields(options);
69
+ if (named) Object.assign(this, named);
30
70
  }
31
71
  };
32
72
  function fail(code, options) {
@@ -138,6 +178,10 @@ const credentialNames = Object.freeze([
138
178
  "auth_token",
139
179
  "session_token",
140
180
  "authorization",
181
+ "authorization_code",
182
+ "oauth_code",
183
+ "密碼",
184
+ "密码",
141
185
  "proxy_authorization",
142
186
  "x_api_key",
143
187
  "private_key",
@@ -423,13 +467,13 @@ function assignments(input, output) {
423
467
  }
424
468
  if (input.field.kind === "key") return;
425
469
  const consumed = headers(input, output);
426
- if (!/[:=]|--/u.test(input.text)) return;
470
+ if (!/[:=:]|--/u.test(input.text)) return;
427
471
  if (!mayContainCredentialName(input.text)) return;
428
- const expression = /(?:(?<![\p{L}\p{N}_/?&#-])(\\?["']?)([\p{L}\p{N}_-]{1,64})\1([ \t]*)[:=]([ \t]*)|(?<![\p{L}\p{N}_-])--([\p{L}\p{N}_-]{1,64})([ \t]+)(?![ \t-]))/giu;
472
+ const expression = /(?:(?<![\p{L}\p{N}_/?&#-])(\\?["']?)((?:oauth[ \t]+)?authorization[ \t]+code|oauth[ \t]+code|[\p{L}\p{N}_-]{1,64})\1([ \t]*)[:=:]([ \t]*)|(?<![\p{L}\p{N}_-])--([\p{L}\p{N}_-]{1,64})([ \t]+)(?![ \t-]))/giu;
429
473
  let match;
430
474
  let headerIndex = 0;
431
475
  while ((match = expression.exec(input.text)) !== null) {
432
- const label = normalizeCredentialName(match[2] ?? match[5] ?? "");
476
+ const label = normalizeCredentialName((match[2] ?? match[5] ?? "").replace(/[ \t]+/gu, "_"));
433
477
  if (!credentialName(label)) continue;
434
478
  while ((consumed[headerIndex]?.end ?? Infinity) <= match.index) headerIndex += 1;
435
479
  const header = consumed[headerIndex];
@@ -2564,10 +2608,10 @@ function urlActions(locator, input, result) {
2564
2608
  actions: [action]
2565
2609
  });
2566
2610
  }
2567
- const inspect = (range, key, query = false) => {
2611
+ const inspect = (range, key, query = false, oauthResponse = false) => {
2568
2612
  if (range.start >= range.end) return;
2569
2613
  const raw = input.text.slice(range.start, range.end);
2570
- const credential = key !== void 0 && credentialName(key);
2614
+ const credential = key !== void 0 && (credentialName(key) || oauthResponse && key === "code");
2571
2615
  if (!withinLimit({
2572
2616
  raw,
2573
2617
  range
@@ -2614,6 +2658,8 @@ function urlActions(locator, input, result) {
2614
2658
  const end = hash < 0 ? locator.raw.length : hash;
2615
2659
  const question = locator.raw.indexOf("?", pathEnd);
2616
2660
  if (question >= 0 && question < end) {
2661
+ const keys = new URLSearchParams(locator.raw.slice(question + 1, end));
2662
+ const oauthResponse = (locator.scheme === "http" || locator.scheme === "https") && keys.has("code") && (keys.has("state") || keys.has("session_state") || /(?:^|\/)(?:oauth2?|callback|oauth2?[_-]callback)(?:\/|$)/iu.test(locator.raw.slice(suffix, pathEnd)));
2617
2663
  start = question + 1;
2618
2664
  for (let index = start; index <= end; index++) {
2619
2665
  if (index !== end && locator.raw[index] !== "&") continue;
@@ -2623,7 +2669,7 @@ function urlActions(locator, input, result) {
2623
2669
  if (key !== null) inspect({
2624
2670
  start: offset + equals + 1,
2625
2671
  end: offset + index
2626
- }, key, true);
2672
+ }, key, true, oauthResponse);
2627
2673
  } else inspect({
2628
2674
  start: offset + start,
2629
2675
  end: offset + index
@@ -4794,7 +4840,7 @@ function createRegistry(options, limits) {
4794
4840
  const required = /* @__PURE__ */ new Map();
4795
4841
  for (const step of steps) {
4796
4842
  const registration = nodes.get(refKey(step.node));
4797
- if (!registration) return fail("PROCESSING_UNSUPPORTED");
4843
+ if (!registration) return fail("PROCESSING_UNSUPPORTED", { site: "registry-node-missing" });
4798
4844
  const configured = registration.configure(step.options);
4799
4845
  if (refKey(configured.ref) !== refKey(step.node) || typeof configured.process !== "function" || !Array.isArray(configured.requires) || !Array.isArray(configured.ruleIds) || configured.ruleIds.length > 256 || configured.ruleIds.some((id) => typeof id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(id)) || new Set(configured.ruleIds).size !== configured.ruleIds.length) return fail("PROCESSING_INVALID_PLAN");
4800
4846
  const checked = buildPlan([], configured.requires.map((ref) => ({
@@ -4802,7 +4848,7 @@ function createRegistry(options, limits) {
4802
4848
  version: ref.version
4803
4849
  })));
4804
4850
  for (const ref of checked.analyses) {
4805
- if (!analyses.has(refKey(ref))) return fail("PROCESSING_UNSUPPORTED");
4851
+ if (!analyses.has(refKey(ref))) return fail("PROCESSING_UNSUPPORTED", { site: "registry-analysis-missing" });
4806
4852
  required.set(refKey(ref), ref);
4807
4853
  }
4808
4854
  Object.freeze(configured);
@@ -4821,7 +4867,7 @@ function createRegistry(options, limits) {
4821
4867
  }
4822
4868
  const plan = buildPlan(steps, [...required.values()]);
4823
4869
  const parsers = plan.analyses.map((ref) => {
4824
- return analyses.get(refKey(ref)) ?? fail("PROCESSING_UNSUPPORTED");
4870
+ return analyses.get(refKey(ref)) ?? fail("PROCESSING_UNSUPPORTED", { site: "registry-parser-missing" });
4825
4871
  });
4826
4872
  return Object.freeze({
4827
4873
  plan,
@@ -5176,7 +5222,7 @@ function validateSelection(root, selection, options) {
5176
5222
  if (edit?.mode.kind === "empty" && node.kind === "literal") fail("PROCESSING_INVALID_PROPOSAL");
5177
5223
  if (edit?.replacementOrigin !== void 0 && node.kind !== "string") fail("PROCESSING_INVALID_PROPOSAL");
5178
5224
  if (edit?.replacementSourceRanges !== void 0) {
5179
- if (node.kind !== "string" || edit.replacementOrigin !== "user-message" || !edit.replacementSourceRanges.length) fail("PROCESSING_INVALID_PROPOSAL");
5225
+ if (node.kind !== "string" || edit.replacementOrigin !== "user-message" && !(edit.role === "main-text" && edit.mode.kind === "remove" && edit.replacement !== void 0) || !edit.replacementTargetRanges || !edit.replacementSourceRanges.length) fail("PROCESSING_INVALID_PROPOSAL");
5180
5226
  let end = 0;
5181
5227
  for (const range of edit.replacementSourceRanges) {
5182
5228
  if (!Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < end || range.end <= range.start || range.end > node.value.length) fail("PROCESSING_INVALID_PROPOSAL");
@@ -5917,7 +5963,7 @@ function projectNativeRecord(root, selection, options) {
5917
5963
  if (Buffer.byteLength(edit.replacement) > options.limits.maxOutputBytes) fail("PROCESSING_LIMIT");
5918
5964
  }
5919
5965
  if (edit?.mode.kind === "head-tail") {
5920
- if (node.kind !== "string") fail("PROCESSING_UNSUPPORTED");
5966
+ if (node.kind !== "string") fail("PROCESSING_UNSUPPORTED", { site: "retention-window-not-string" });
5921
5967
  const { segments } = selectOriginalWindows(options.sampleTexts?.get(node.id) ?? node.value, edit.mode);
5922
5968
  const rendered = JSON.stringify({
5923
5969
  kind: "text-sample",
@@ -6306,7 +6352,7 @@ function staticRegistration(category) {
6306
6352
  if (seen.has(action.targetId)) continue;
6307
6353
  seen.add(action.targetId);
6308
6354
  if (action.range.start < end) {
6309
- if (action.range.end > end) fail("PROCESSING_UNSUPPORTED");
6355
+ if (action.range.end > end) fail("PROCESSING_UNSUPPORTED", { site: "static-action-overlap" });
6310
6356
  continue;
6311
6357
  }
6312
6358
  const view = context.view(action.targetId);
@@ -7146,7 +7192,7 @@ function createDetectionSummary() {
7146
7192
  }
7147
7193
  //#endregion
7148
7194
  //#region packages/processing/src/inspection/versions.ts
7149
- const currentDetectorVersion = `static-catalog-11`;
7195
+ const currentDetectorVersion = `static-catalog-12`;
7150
7196
  /** Before-redaction inspection; cleanup and redaction have independent lifetimes. */
7151
7197
  const inspectionSemanticVersions = Object.freeze({
7152
7198
  implementation: originalInspectionVersion,
@@ -7733,7 +7779,7 @@ function collectNativeReviewInput(request, originals, options, scope = "output")
7733
7779
  const originalSource = source ?? sources.get(field.fieldId.replace(/-k$/u, ""));
7734
7780
  if (!originalSource) fail("PROCESSING_INVALID_RECORD");
7735
7781
  const edit = edits.get(originalSource.nodeId);
7736
- if (scope === "main-prose" && edit?.replacementOrigin === "user-message") {
7782
+ if (scope === "main-prose" && (edit?.replacementOrigin === "user-message" || edit?.replacementSourceRanges)) {
7737
7783
  if (!edit.replacementSourceRanges?.length) fail("PROCESSING_INVALID_RECORD");
7738
7784
  for (const [index, range] of edit.replacementSourceRanges.entries()) {
7739
7785
  const text = originalSource.text.slice(range.start, range.end);
@@ -8492,8 +8538,10 @@ const safeCodes = /* @__PURE__ */ new Set([
8492
8538
  "SESSION_UPLOAD_EXHAUSTED",
8493
8539
  "SESSION_TRANSPORT_UNAVAILABLE",
8494
8540
  "SEND_SCOPE_BUSY",
8541
+ "HOST_REPLACEMENT_PENDING",
8495
8542
  "SEND_REPLACE_REFUSED",
8496
8543
  "SESSION_CONTENT_CONFLICT",
8544
+ "WORK_SESSION_CAPACITY_EXCEEDED",
8497
8545
  "SESSION_MOVE_ACCESS_REQUIRED",
8498
8546
  "SESSION_MOVE_ACCESS_HELD",
8499
8547
  "SEND_SCOPE_INVALIDATED",
@@ -8506,6 +8554,8 @@ const safeCodes = /* @__PURE__ */ new Set([
8506
8554
  "SENSITIVE_TERMS_CHANGED",
8507
8555
  "ACCOUNT_NOT_CONFIGURED",
8508
8556
  "ACCOUNT_SIGNED_OUT",
8557
+ "ACCOUNT_ACCESS_UNAVAILABLE",
8558
+ "JOURNEY_SIGN_IN_REQUIRED",
8509
8559
  "ACCOUNT_PROFILE_UNAVAILABLE",
8510
8560
  "PASSPORT_ADDRESS_TAKEN",
8511
8561
  "PASSPORT_ADDRESS_RESERVED",
@@ -8574,6 +8624,8 @@ const safeCodes = /* @__PURE__ */ new Set([
8574
8624
  "OPERATION_BUSY",
8575
8625
  "OPERATION_CONFLICT",
8576
8626
  "OPERATION_FAILED",
8627
+ "WORK_METADATA_INCOMPLETE",
8628
+ "PACKAGING_FAILED",
8577
8629
  "PACKAGING_BUSY",
8578
8630
  "PROCESSING_PLAN_UNAVAILABLE",
8579
8631
  "PROCESSING_PLAN_MISMATCH",
@@ -8988,6 +9040,24 @@ const termEvidenceSchema = z.object({
8988
9040
  rationale: termAssessmentSchema.shape.rationale,
8989
9041
  stance: termAssessmentSchema.shape.stance
8990
9042
  }).strict().refine((evidence) => evidence.end > evidence.start);
9043
+ const namedBatch = z.object({
9044
+ journeyId: id$1,
9045
+ batchId: id$1,
9046
+ batchDigest: digest$3
9047
+ }).strict();
9048
+ const emptyReviewCorrectionSchema = z.discriminatedUnion("kind", [namedBatch.extend({ kind: z.literal("inspect") }).strict(), namedBatch.extend({
9049
+ kind: z.literal("apply"),
9050
+ expectedPackId: id$1,
9051
+ idempotencyKey: id$1
9052
+ }).strict()]);
9053
+ const emptyReviewCorrectionResultSchema = z.object({
9054
+ status: z.enum([
9055
+ "eligible",
9056
+ "reopened",
9057
+ "replayed"
9058
+ ]),
9059
+ packId: id$1
9060
+ }).strict();
8991
9061
  /** One pack of read units and the values found in them (`review.terms`). */
8992
9062
  const reviewTermsInputSchema = z.object({
8993
9063
  journeyId: id$1,
@@ -8998,6 +9068,10 @@ const reviewTermsInputSchema = z.object({
8998
9068
  units: z.array(z.object({
8999
9069
  batchId: id$1,
9000
9070
  batchDigest: digest$3,
9071
+ coverage: z.object({
9072
+ attemptId: id$1,
9073
+ receipts: z.array(digest$3).min(1).max(8e4)
9074
+ }).strict().optional(),
9001
9075
  /** Legacy unit summary in stored packs; accepted and never read (ADR 0178). */
9002
9076
  summary: z.string().trim().min(1).refine((value) => Buffer.byteLength(value) <= 1024).optional(),
9003
9077
  exclude: z.string().trim().refine((value) => codePoints(value) >= 1 && codePoints(value) <= 500).nullable()
@@ -9433,6 +9507,13 @@ const journeyArtifactSchema = z.object({
9433
9507
  archiveBytes: count$1
9434
9508
  }).strict()
9435
9509
  }).strict();
9510
+ /** A closed reader attempt that left named units without a coverage receipt. */
9511
+ const reviewInterruptionSchema = z.object({
9512
+ inputRevision: count$1.min(1),
9513
+ packId: journeyIdSchema,
9514
+ reason: z.enum(["reader-refused", "retry-exhausted"]),
9515
+ batchIds: z.array(journeyIdSchema).min(1).max(1e4).refine((ids) => new Set(ids).size === ids.length)
9516
+ }).strict();
9436
9517
  const journeyWorkSchema = z.object({
9437
9518
  id: journeyIdSchema,
9438
9519
  title: label,
@@ -9524,6 +9605,7 @@ const journeyWorkSchema = z.object({
9524
9605
  /** Images the Work's sessions leave out (D7); absent when a session receipt predates it. */
9525
9606
  imagesOmitted: count$1.optional()
9526
9607
  }).strict().optional(),
9608
+ reviewInterruptions: z.array(reviewInterruptionSchema).optional(),
9527
9609
  totalBatches: count$1,
9528
9610
  completedBatches: count$1,
9529
9611
  groupIds: z.array(journeyIdSchema),
@@ -9547,7 +9629,12 @@ const journeyWorkSchema = z.object({
9547
9629
  const journeyConsentSchema = z.object({
9548
9630
  provider: label,
9549
9631
  allowedAt: z.iso.datetime(),
9550
- source: z.enum(["conversation", "panel"])
9632
+ source: z.enum(["conversation", "panel"]),
9633
+ /**
9634
+ * The account signed in when consent was recorded (ADR 0276 D8). Absent in a build with no
9635
+ * sign-in client and in a journey started before this version (Q11 a, Q13 a).
9636
+ */
9637
+ subject: z.string().min(1).max(128).optional()
9551
9638
  }).strict();
9552
9639
  const journeyExceptionSchema = z.object({
9553
9640
  id: journeyIdSchema,
@@ -9561,6 +9648,7 @@ const journeyExceptionSchema = z.object({
9561
9648
  }).strict();
9562
9649
  const nativeJourneySchema = z.object({
9563
9650
  formatVersion: z.literal(10),
9651
+ outputVersion: z.number().int().positive().optional(),
9564
9652
  classificationRevision: count$1.nullable(),
9565
9653
  privacy: journeyPrivacySchema,
9566
9654
  delegation: journeyDelegationSchema.nullable(),
@@ -9618,8 +9706,29 @@ const nativeJourneySchema = z.object({
9618
9706
  /** Sessions whose last activity lies in this period (ADR 0206); absent means all. */
9619
9707
  period: sessionPeriodSchema.optional(),
9620
9708
  /** The Passport address and links chosen in this Journey (ADR 0246); absent means none yet. */
9621
- profile: journeyProfileSchema.optional()
9709
+ profile: journeyProfileSchema.optional(),
9710
+ /**
9711
+ * The last account read that re-seeded every Work (ADR 0277 section 5). Only scope
9712
+ * confirmation and Retry set `read`; late classification records only a failure. Absent in a
9713
+ * journey of an earlier version, which reads as not `read`.
9714
+ */
9715
+ accountRead: z.object({
9716
+ status: z.enum([
9717
+ "read",
9718
+ "signed-out",
9719
+ "unavailable"
9720
+ ]),
9721
+ subject: z.string().min(1).max(128).optional(),
9722
+ at: z.iso.datetime()
9723
+ }).strict().optional()
9622
9724
  }).strict();
9725
+ /**
9726
+ * Consent with no subject: a journey started before sign-in was required, or in a build with no
9727
+ * sign-in client. It finishes under the rules it started with (ADR 0276 Q13 a, Q11 a).
9728
+ */
9729
+ function consentedWithoutAccount(state) {
9730
+ return state.consent !== null && state.consent.subject === void 0;
9731
+ }
9623
9732
  //#endregion
9624
9733
  //#region packages/application/src/journey/b/model.ts
9625
9734
  const bMethod = "sesspilot-b-v2";
@@ -10737,6 +10846,63 @@ function compileBFindings(batch, evidence) {
10737
10846
  return findings;
10738
10847
  }
10739
10848
  //#endregion
10849
+ //#region packages/application/src/journey/terms/read-pages.ts
10850
+ /** Leave ample space for tool framing, JSON escaping and the final receipt on each read. */
10851
+ const pageBytes = 6e3;
10852
+ /** Each receipt binds the delivered text, its position, the frozen batch and its assignment. */
10853
+ function reviewReadPages(batch, attemptId) {
10854
+ const pages = [];
10855
+ let text = "";
10856
+ function flush() {
10857
+ if (!text) return;
10858
+ const receipt = createHash("sha256").update(JSON.stringify([
10859
+ "scan-read-v1",
10860
+ attemptId,
10861
+ batch.id,
10862
+ batch.digest,
10863
+ pages.length,
10864
+ text
10865
+ ])).digest("hex");
10866
+ pages.push({
10867
+ text,
10868
+ receipt
10869
+ });
10870
+ text = "";
10871
+ }
10872
+ for (const chunk of batch.chunks) {
10873
+ if (!chunk.text.length) throw new Error("EMPTY_REVIEW_PAGE");
10874
+ let offset = 0;
10875
+ while (offset < chunk.text.length) {
10876
+ const header = "\nCHUNK " + chunk.id + " " + (chunk.core ? "review" : "context") + " " + chunk.role + " UTF16_START " + offset + "\n";
10877
+ const available = pageBytes - Buffer.byteLength(text + header);
10878
+ if (available < 4) {
10879
+ if (!text) throw new Error("INVALID_REVIEW_PAGE_HEADER");
10880
+ flush();
10881
+ continue;
10882
+ }
10883
+ let end = offset;
10884
+ let bytes = 0;
10885
+ while (end < chunk.text.length) {
10886
+ const point = chunk.text.codePointAt(end);
10887
+ if (point === void 0) throw new Error("INVALID_REVIEW_PAGE_RANGE");
10888
+ const size = point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
10889
+ if (bytes + size > available) break;
10890
+ end += point >= 65536 ? 2 : 1;
10891
+ bytes += size;
10892
+ }
10893
+ text += header + chunk.text.slice(offset, end);
10894
+ offset = end;
10895
+ if (offset < chunk.text.length) flush();
10896
+ }
10897
+ }
10898
+ flush();
10899
+ return pages;
10900
+ }
10901
+ function matchesReadReceipts(batch, attemptId, receipts) {
10902
+ const pages = reviewReadPages(batch, attemptId);
10903
+ return pages.length > 0 && pages.length === receipts.length && pages.every((page, i) => page.receipt === receipts[i]);
10904
+ }
10905
+ //#endregion
10740
10906
  //#region packages/application/src/journey/terms/locate.ts
10741
10907
  /** NFC core text of each analysed field, contiguous core chunks joined, with its Work. */
10742
10908
  function coreTexts(batches) {
@@ -10787,7 +10953,7 @@ function locateTerms(batches, terms) {
10787
10953
  }];
10788
10954
  }));
10789
10955
  for (const { type, value, index } of unique.values()) {
10790
- if (admitCustomTerm(value)?.value !== value || !texts.some((item) => item.text.includes(value))) {
10956
+ if (value.includes("█") || admitCustomTerm(value)?.value !== value || !texts.some((item) => item.text.includes(value))) {
10791
10957
  unlocated++;
10792
10958
  unlocatedIndices.push(index);
10793
10959
  continue;
@@ -10811,4 +10977,4 @@ function locateTerms(batches, terms) {
10811
10977
  };
10812
10978
  }
10813
10979
  //#endregion
10814
- export { bCountSchema as $, detectStatic as $n, safeField as $t, bDuplicateMirror as A, createReplacementKey as An, journeyTermSchema as At, bEvidenceReader as B, nativeItems as Bn, sessionPeriodSchema as Bt, validateBUnit as C, inspectionSemanticVersions as Cn, cardsSubmitSchema as Ct, uncoveredBObligations as D, createStaticProcessor as Dn, privacyResolveSchema as Dt, bLiterals as E, walkNativeFields as En, packageConfirmActionSchema as Et, bClassificationKey as F, entityDictionaryVersion as Fn, termTypeInfo as Ft, subtractBRanges as G, validateProfile as Gn, ownerProfileSchema as Gt, codePointLength as H, transformRecords as Hn, journeyProfileAddressActionSchema as Ht, bIssue as I, nativeParserVersion as In, termTypeSchema as It, bRetainedGroupSchema as J, validatePlan as Jn, respondProfileLinks as Jt, utf16Offset as K, orderProfile as Kn, passportAddressSchema as Kt, bOverlaps as L, redactionImplementationVersion as Ln, termTypes as Lt, bLegacyBindings as M, projectNativeRecord as Mn, reviewTermsResultSchema as Mt, bUnitFragments as N, parseNativeRecord as Nn, termAssessmentSchema as Nt, indexBRanges as O, staticDefaults as On, privacyTermKey as Ot, bAdoptedObligations as P, cleanupImplementationVersion as Pn, termOverrideValueSchema as Pt, bAnchorSchema as Q, resolveLimits as Qn, safeCode as Qt, unownedBObligations as R, nativeBoolean as Rn, deselectOutsidePeriod as Rt, validateBFields as S, currentDetectorVersion as Sn, cardsConfirmActionSchema as St, bLiteralTerms as T, gapReasons as Tn, emptyJourneyPrivacy as Tt, codePointSlice as U, frameRecords as Un, journeyProfileLinksActionSchema as Ut, bDigest as V, nativeText as Vn, emptyJourneyProfile as Vt, createCodePointIndex as W, retainedMainTextNodes as Wn, mergeOwnerProfile as Wt, bSessionDecisionSchema as X, defaultLimits as Xn, ApplicationError as Xt, bReviewSubmissionSchema as Y, copyData as Yn, classificationTitleMaskSchema as Yt, bTermSchema as Z, recordPointerLimits as Zn, UnfinishedJourneyError as Zt, semanticFindingSchema as _, reviewRoles as _n, hideConfirmSchema as _t, reviewChunkSchema as a, observeSource as an, admitCustomTerm as ar, journeyExceptionSchema as at, validateBReview as b, createSessionPreparation as bn, journeyConfigurationSchema as bt, textDigest as c, inventorySchema as cn, scalarBefore as cr, journeyPreferenceScopeSchema as ct, reviewAlignmentAudit as d, workspaceSchema as dn, fail as dr, nativeJourneySchema as dt, familyNeedsReview as en, isStaticCategory as er, bIdSchema as et, reviewAlignmentAuditSchema as f, nativeSourceIdentitySchema as fn, isProcessingCode as fr, journeyGuidanceSchema as ft, validateReviewAlignment as g, mainReviewRole as gn, journeyWorkSuggestionSchema as gt, reviewFindingsDigest as h, projectNativeReviewInput as hn, journeyDescribeSchema as ht, reviewBatchSchema as i, sourceKey as in, createEntityMatcher as ir, journeyDigestSchema as it, bDuplicateShift as j, sessionNonce as jn, reviewTermsInputSchema as jt, bBindingCap as k, staticOptions as kn, privacyTermSchema as kt, validateReview as l, sessionSchema as ln, defaultDetectionLimits as lr, journeyProjectTypeSchema as lt, reviewAlignmentSchema as m, processNativeRecord as mn, delegatedDecisionSchema as mt, compileBFindings as n, reviewFamilies as nn, jsonSpans as nr, journeyAccessSchema as nt, reviewDigest as o, sourceSnapshotId as on, admitGitName as or, journeyIdSchema as ot, reviewAlignmentInputSchema as p, withMandatoryCustomTerms as pn, journeyInstructionInputSchema as pt, bRepresentationSchema as q, buildPlan as qn, profileHasChoices as qt, reviewBatchChunks as r, sourceGraph as rn, agentContextLocation as rr, journeyChoiceSchema as rt, reviewSubmitSchema as s, fileIdentitySchema as sn, scalarAfter as sr, journeyKindSchema as st, locateTerms as t, familySelected as tn, staticCategories as tr, bMethod as tt, findingReferenceKey as u, sourcePartSchema as un, ProcessingError as ur, journeyWorkTypeSchema as ut, bContextEvidence as v, createSentenceContext as vn, hidePlanInputSchema as vt, bLiteralAdmitted as w, createDetectionSummary as wn, decisionCardInputSchema as wt, createBAnalysisUnits as x, bindInspection as xn, cardAnswerActionSchema as xt, validateBClassification as y, renderNative as yn, hidePlanResourceSchema as yt, bAnchorKey as z, nativeField as zn, filterInventoryByPeriod as zt };
10980
+ export { bTermSchema as $, buildPlan as $n, profileHasChoices as $t, indexBRanges as A, createDetectionSummary as An, packageConfirmActionSchema as At, unownedBObligations as B, cleanupImplementationVersion as Bn, termOverrideValueSchema as Bt, createBAnalysisUnits as C, reviewRoles as Cn, hidePlanResourceSchema as Ct, bLiteralTerms as D, bindInspection as Dn, cardsSubmitSchema as Dt, bLiteralAdmitted as E, createSessionPreparation as En, cardsConfirmActionSchema as Et, bUnitFragments as F, staticOptions as Fn, emptyReviewCorrectionSchema as Ft, codePointSlice as G, nativeField as Gn, filterInventoryByPeriod as Gt, bEvidenceReader as H, nativeParserVersion as Hn, termTypeSchema as Ht, bAdoptedObligations as I, createReplacementKey as In, journeyTermSchema as It, utf16Offset as J, transformRecords as Jn, journeyProfileAddressActionSchema as Jt, createCodePointIndex as K, nativeItems as Kn, sessionPeriodSchema as Kt, bClassificationKey as L, sessionNonce as Ln, reviewTermsInputSchema as Lt, bDuplicateMirror as M, walkNativeFields as Mn, privacyTermKey as Mt, bDuplicateShift as N, createStaticProcessor as Nn, privacyTermSchema as Nt, bLiterals as O, currentDetectorVersion as On, decisionCardInputSchema as Ot, bLegacyBindings as P, staticDefaults as Pn, emptyReviewCorrectionResultSchema as Pt, bSessionDecisionSchema as Q, orderProfile as Qn, passportAddressSchema as Qt, bIssue as R, projectNativeRecord as Rn, reviewTermsResultSchema as Rt, validateBReview as S, mainReviewRole as Sn, hidePlanInputSchema as St, validateBUnit as T, renderNative as Tn, cardAnswerActionSchema as Tt, bDigest as U, redactionImplementationVersion as Un, termTypes as Ut, bAnchorKey as V, entityDictionaryVersion as Vn, termTypeInfo as Vt, codePointLength as W, nativeBoolean as Wn, deselectOutsidePeriod as Wt, bRetainedGroupSchema as X, retainedMainTextNodes as Xn, mergeOwnerProfile as Xt, bRepresentationSchema as Y, frameRecords as Yn, journeyProfileLinksActionSchema as Yt, bReviewSubmissionSchema as Z, validateProfile as Zn, ownerProfileSchema as Zt, reviewFindingsDigest as _, workspaceSchema as _n, declaredVersion as _r, journeyInstructionInputSchema as _t, reviewBatchChunks as a, safeField as an, detectStatic as ar, journeyAccessSchema as at, bContextEvidence as b, processNativeRecord as bn, processingSite as br, journeyWorkSuggestionSchema as bt, reviewDigest as c, reviewFamilies as cn, jsonSpans as cr, journeyExceptionSchema as ct, validateReview as d, observeSource as dn, admitCustomTerm as dr, journeyPreferenceScopeSchema as dt, respondProfileLinks as en, validatePlan as er, bAnchorSchema as et, findingReferenceKey as f, sourceSnapshotId as fn, admitGitName as fr, journeyProjectTypeSchema as ft, reviewAlignmentSchema as g, sourcePartSchema as gn, ProcessingError as gr, journeyGuidanceSchema as gt, reviewAlignmentInputSchema as h, sessionSchema as hn, defaultDetectionLimits as hr, reviewInterruptionSchema as ht, compileBFindings as i, safeCode as in, resolveLimits as ir, consentedWithoutAccount as it, bBindingCap as j, gapReasons as jn, privacyResolveSchema as jt, uncoveredBObligations as k, inspectionSemanticVersions as kn, emptyJourneyPrivacy as kt, reviewSubmitSchema as l, sourceGraph as ln, agentContextLocation as lr, journeyIdSchema as lt, reviewAlignmentAuditSchema as m, inventorySchema as mn, scalarBefore as mr, nativeJourneySchema as mt, matchesReadReceipts as n, ApplicationError as nn, defaultLimits as nr, bIdSchema as nt, reviewBatchSchema as o, familyNeedsReview as on, isStaticCategory as or, journeyChoiceSchema as ot, reviewAlignmentAudit as p, fileIdentitySchema as pn, scalarAfter as pr, journeyWorkTypeSchema as pt, subtractBRanges as q, nativeText as qn, emptyJourneyProfile as qt, reviewReadPages as r, UnfinishedJourneyError as rn, recordPointerLimits as rr, bMethod as rt, reviewChunkSchema as s, familySelected as sn, staticCategories as sr, journeyDigestSchema as st, locateTerms as t, classificationTitleMaskSchema as tn, copyData as tr, bCountSchema as tt, textDigest as u, sourceKey as un, createEntityMatcher as ur, journeyKindSchema as ut, validateReviewAlignment as v, nativeSourceIdentitySchema as vn, fail as vr, delegatedDecisionSchema as vt, validateBFields as w, createSentenceContext as wn, journeyConfigurationSchema as wt, validateBClassification as x, projectNativeReviewInput as xn, siteFields as xr, hideConfirmSchema as xt, semanticFindingSchema as y, withMandatoryCustomTerms as yn, isProcessingCode as yr, journeyDescribeSchema as yt, bOverlaps as z, parseNativeRecord as zn, termAssessmentSchema as zt };
@@ -1,4 +1,4 @@
1
- import "./src-BqtdFVq7.mjs";
1
+ import "./src-Do-qzuMn.mjs";
2
2
  //#region packages/harnesses/src/discovery/model.ts
3
3
  const discoveryBounds = {
4
4
  entries: 1e5,
@@ -1,6 +1,6 @@
1
- import { _ as longCommands, c as executorRequestSchema, h as parseOptions, i as invoke, n as readOperation, o as createRuntime, r as waitOperation, y as startupFailure } from "./query-By41gaKm.mjs";
2
- import { $t as safeField, Qt as safeCode, Xt as ApplicationError } from "./locate-Cwv6WH8n.mjs";
3
- import "./src-BqtdFVq7.mjs";
1
+ import { c as executorRequestSchema, g as longCommands, i as invoke, m as parseOptions, n as readOperation, o as createRuntime, r as waitOperation, v as startupFailure } from "./query-BYDcNKy2.mjs";
2
+ import { an as safeField, in as safeCode, nn as ApplicationError } from "./locate-D-ZaHpI0.mjs";
3
+ import "./src-Do-qzuMn.mjs";
4
4
  import { z } from "zod";
5
5
  import { setTimeout } from "node:timers/promises";
6
6
  //#region apps/cli/src/operation/executor.ts
@@ -1,4 +1,4 @@
1
- import { n as assertPreviewHeap, o as previewInputSchema, t as runPreview } from "./run-ZQx7p4Rw.mjs";
1
+ import { n as assertPreviewHeap, o as previewInputSchema, t as runPreview } from "./run-DQ9xyKSt.mjs";
2
2
  import { parentPort, workerData } from "node:worker_threads";
3
3
  //#region packages/harnesses/src/preview/worker/index.ts
4
4
  function notify(message) {
@@ -1,6 +1,53 @@
1
- import { Dt as privacyResolveSchema, Ot as privacyTermKey, t as locateTerms, wt as decisionCardInputSchema } from "./locate-Cwv6WH8n.mjs";
1
+ import { Mt as privacyTermKey, Ot as decisionCardInputSchema, jt as privacyResolveSchema, r as reviewReadPages, t as locateTerms } from "./locate-D-ZaHpI0.mjs";
2
2
  import { z } from "zod";
3
3
  //#region apps/cli/src/skill-install/privacy-validator.ts
4
+ const sourceReferenceSchema = z.object({
5
+ chunkId: z.uuid(),
6
+ start: z.number().int(),
7
+ end: z.number().int()
8
+ }).strict();
9
+ /** Resolve sensitive spans locally against the projected, assigned core text. */
10
+ function resolvePrivacySources(raw, batches) {
11
+ if (!Array.isArray(raw)) throw new Error("INVALID_FINDING");
12
+ if (!raw.some((term) => typeof term === "object" && term !== null && "source" in term)) return raw;
13
+ const chunks = new Map(batches.flatMap(({ chunks }) => chunks.map((chunk) => [chunk.id, chunk])));
14
+ const diagnostics = [];
15
+ let invalidCount = 0;
16
+ const resolved = raw.map((term, index) => {
17
+ if (typeof term !== "object" || term === null || !("source" in term)) return term;
18
+ const invalid = (reason) => {
19
+ invalidCount++;
20
+ if (diagnostics.length < 32) diagnostics.push(`draft.terms[${index}].source: ${reason}`);
21
+ };
22
+ const reference = sourceReferenceSchema.safeParse(term.source);
23
+ if (!reference.success || "value" in term) return invalid("use only a chunkId and integer start/end offsets for the source");
24
+ const { chunkId, start, end } = reference.data;
25
+ const chunk = chunks.get(chunkId);
26
+ if (!chunk?.core) return invalid("select an assigned core chunk");
27
+ if (start < 0 || end <= start || end > chunk.text.length) return invalid("check chunk-relative UTF-16 bounds");
28
+ if (end - start > 8e3) return invalid("span exceeds the length limit");
29
+ if (chunk.displayMasks?.some((range) => range.start < end && start < range.end)) return invalid("span intersects masked text");
30
+ const value = chunk.text.slice(start, end);
31
+ if (!value.isWellFormed()) {
32
+ if ((chunk.text.codePointAt(start - 1) ?? 0) > 65535 || (chunk.text.codePointAt(end - 1) ?? 0) > 65535) return invalid("offset splits a UTF-16 surrogate pair");
33
+ return invalid("span contains invalid UTF-16");
34
+ }
35
+ if (value.includes("█")) return invalid("span intersects masked text");
36
+ if (!value.trim()) return invalid("span contains only whitespace");
37
+ if (Array.from(value).length > 4e3) return invalid("span exceeds the length limit");
38
+ const { source: _source, ...rest } = term;
39
+ return {
40
+ ...rest,
41
+ value
42
+ };
43
+ });
44
+ if (invalidCount) {
45
+ const remaining = invalidCount - diagnostics.length;
46
+ if (remaining) diagnostics.push(`${remaining} additional invalid source references`);
47
+ throw new Error("INVALID_REVIEW_SPAN", { cause: diagnostics });
48
+ }
49
+ return resolved;
50
+ }
4
51
  const suppliedTerms = z.array(z.object({
5
52
  key: z.string(),
6
53
  type: z.string(),
@@ -43,4 +90,4 @@ function validateStageAnswer(input, answer) {
43
90
  }
44
91
  }
45
92
  //#endregion
46
- export { locateTerms, validateStageAnswer };
93
+ export { locateTerms, resolvePrivacySources, reviewReadPages, validateStageAnswer };