memkin 0.4.1 → 0.4.3

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 (135) hide show
  1. package/dist/apply/candidate-selection.d.ts +60 -0
  2. package/dist/apply/candidate-selection.d.ts.map +1 -0
  3. package/dist/apply/candidate-selection.js +159 -0
  4. package/dist/apply/candidate-selection.js.map +1 -0
  5. package/dist/apply/cutover.d.ts +45 -0
  6. package/dist/apply/cutover.d.ts.map +1 -0
  7. package/dist/apply/cutover.js +85 -0
  8. package/dist/apply/cutover.js.map +1 -0
  9. package/dist/apply/engine.d.ts +34 -0
  10. package/dist/apply/engine.d.ts.map +1 -0
  11. package/dist/apply/engine.js +255 -0
  12. package/dist/apply/engine.js.map +1 -0
  13. package/dist/apply/ids.d.ts +9 -0
  14. package/dist/apply/ids.d.ts.map +1 -0
  15. package/dist/apply/ids.js +0 -0
  16. package/dist/apply/ids.js.map +1 -0
  17. package/dist/apply/page-content.d.ts +14 -0
  18. package/dist/apply/page-content.d.ts.map +1 -0
  19. package/dist/apply/page-content.js +0 -0
  20. package/dist/apply/page-content.js.map +1 -0
  21. package/dist/apply/rematerialize.d.ts +13 -0
  22. package/dist/apply/rematerialize.d.ts.map +1 -0
  23. package/dist/apply/rematerialize.js +150 -0
  24. package/dist/apply/rematerialize.js.map +1 -0
  25. package/dist/apply/rollback.d.ts +20 -0
  26. package/dist/apply/rollback.d.ts.map +1 -0
  27. package/dist/apply/rollback.js +117 -0
  28. package/dist/apply/rollback.js.map +1 -0
  29. package/dist/apply/shadow-runner.d.ts +47 -0
  30. package/dist/apply/shadow-runner.d.ts.map +1 -0
  31. package/dist/apply/shadow-runner.js +84 -0
  32. package/dist/apply/shadow-runner.js.map +1 -0
  33. package/dist/apply/types.d.ts +51 -0
  34. package/dist/apply/types.d.ts.map +1 -0
  35. package/dist/apply/types.js +13 -0
  36. package/dist/apply/types.js.map +1 -0
  37. package/dist/cli.js +5 -0
  38. package/dist/cli.js.map +1 -1
  39. package/dist/consolidator/consolidator.d.ts +21 -2
  40. package/dist/consolidator/consolidator.d.ts.map +1 -1
  41. package/dist/consolidator/consolidator.js +16 -1
  42. package/dist/consolidator/consolidator.js.map +1 -1
  43. package/dist/core/config.d.ts +42 -0
  44. package/dist/core/config.d.ts.map +1 -1
  45. package/dist/core/config.js +25 -0
  46. package/dist/core/config.js.map +1 -1
  47. package/dist/core/pipeline.d.ts +26 -1
  48. package/dist/core/pipeline.d.ts.map +1 -1
  49. package/dist/core/pipeline.js +26 -0
  50. package/dist/core/pipeline.js.map +1 -1
  51. package/dist/core/schemas.d.ts +16 -16
  52. package/dist/daemon/serve-runtime.d.ts +1 -1
  53. package/dist/daemon/serve-runtime.d.ts.map +1 -1
  54. package/dist/daemon/serve-runtime.js +26 -1
  55. package/dist/daemon/serve-runtime.js.map +1 -1
  56. package/dist/distiller/authority-matrix.d.ts +22 -0
  57. package/dist/distiller/authority-matrix.d.ts.map +1 -0
  58. package/dist/distiller/authority-matrix.js +29 -0
  59. package/dist/distiller/authority-matrix.js.map +1 -0
  60. package/dist/distiller/contract.d.ts +1427 -0
  61. package/dist/distiller/contract.d.ts.map +1 -0
  62. package/dist/distiller/contract.js +166 -0
  63. package/dist/distiller/contract.js.map +1 -0
  64. package/dist/distiller/index.d.ts +83 -0
  65. package/dist/distiller/index.d.ts.map +1 -0
  66. package/dist/distiller/index.js +226 -0
  67. package/dist/distiller/index.js.map +1 -0
  68. package/dist/distiller/map-reduce.d.ts +81 -0
  69. package/dist/distiller/map-reduce.d.ts.map +1 -0
  70. package/dist/distiller/map-reduce.js +92 -0
  71. package/dist/distiller/map-reduce.js.map +1 -0
  72. package/dist/distiller/msg-id.d.ts +55 -0
  73. package/dist/distiller/msg-id.d.ts.map +1 -0
  74. package/dist/distiller/msg-id.js +91 -0
  75. package/dist/distiller/msg-id.js.map +1 -0
  76. package/dist/distiller/payload-privacy.d.ts +18 -0
  77. package/dist/distiller/payload-privacy.d.ts.map +1 -0
  78. package/dist/distiller/payload-privacy.js +51 -0
  79. package/dist/distiller/payload-privacy.js.map +1 -0
  80. package/dist/distiller/prompt.d.ts +28 -0
  81. package/dist/distiller/prompt.d.ts.map +1 -0
  82. package/dist/distiller/prompt.js +69 -0
  83. package/dist/distiller/prompt.js.map +1 -0
  84. package/dist/distiller/raw-privacy.d.ts +55 -0
  85. package/dist/distiller/raw-privacy.d.ts.map +1 -0
  86. package/dist/distiller/raw-privacy.js +123 -0
  87. package/dist/distiller/raw-privacy.js.map +1 -0
  88. package/dist/distiller/segmenter.d.ts +40 -0
  89. package/dist/distiller/segmenter.d.ts.map +1 -0
  90. package/dist/distiller/segmenter.js +75 -0
  91. package/dist/distiller/segmenter.js.map +1 -0
  92. package/dist/embedded-assets.generated.d.ts.map +1 -1
  93. package/dist/embedded-assets.generated.js +5 -4
  94. package/dist/embedded-assets.generated.js.map +1 -1
  95. package/dist/eval/golden.d.ts +12 -12
  96. package/dist/server/api.d.ts.map +1 -1
  97. package/dist/server/api.js +6 -1
  98. package/dist/server/api.js.map +1 -1
  99. package/dist/setup/generate-config.d.ts.map +1 -1
  100. package/dist/setup/generate-config.js +3 -0
  101. package/dist/setup/generate-config.js.map +1 -1
  102. package/dist/setup/validate-config.d.ts +2 -1
  103. package/dist/setup/validate-config.d.ts.map +1 -1
  104. package/dist/setup/validate-config.js.map +1 -1
  105. package/dist/store/agent-sessions.d.ts.map +1 -1
  106. package/dist/store/agent-sessions.js +3 -1
  107. package/dist/store/agent-sessions.js.map +1 -1
  108. package/dist/store/distilled-payload.d.ts +50 -0
  109. package/dist/store/distilled-payload.d.ts.map +1 -0
  110. package/dist/store/distilled-payload.js +117 -0
  111. package/dist/store/distilled-payload.js.map +1 -0
  112. package/dist/store/engine-factory.d.ts.map +1 -1
  113. package/dist/store/engine-factory.js +8 -1
  114. package/dist/store/engine-factory.js.map +1 -1
  115. package/dist/store/migrations/index.d.ts.map +1 -1
  116. package/dist/store/migrations/index.js +139 -0
  117. package/dist/store/migrations/index.js.map +1 -1
  118. package/dist/store/search.d.ts.map +1 -1
  119. package/dist/store/search.js +15 -8
  120. package/dist/store/search.js.map +1 -1
  121. package/dist/store/source-filter.d.ts +19 -0
  122. package/dist/store/source-filter.d.ts.map +1 -0
  123. package/dist/store/source-filter.js +44 -0
  124. package/dist/store/source-filter.js.map +1 -0
  125. package/dist/store/timeline.d.ts.map +1 -1
  126. package/dist/store/timeline.js +15 -8
  127. package/dist/store/timeline.js.map +1 -1
  128. package/dist/synth/scope.d.ts.map +1 -1
  129. package/dist/synth/scope.js +10 -4
  130. package/dist/synth/scope.js.map +1 -1
  131. package/package.json +3 -2
  132. package/web/dist/assets/index-Cie2dVF3.js +5167 -0
  133. package/web/dist/assets/index-diZtO98v.css +2 -0
  134. package/web/dist/assets/newsreader-T5L87s1n.woff2 +0 -0
  135. package/web/dist/index.html +19 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Sequential map-reduce distillation (spec §5.1).
3
+ *
4
+ * MAP (sequential, not parallel): each segment is distilled in order; the prompt
5
+ * for segment N carries forward segment N-1's `carry_forward` (in-progress topics
6
+ * / undecided items) so `overturned` can be filled reliably. Session counts are
7
+ * low, so sequential cost is acceptable.
8
+ *
9
+ * Intermediate per-segment schema:
10
+ * { seg_no, summary, tentative_signals[], overturned[], carry_forward }
11
+ *
12
+ * REDUCE: merges the tentative signals into a final payload. The reduce prompt
13
+ * carries the explicit rule "conclusions appearing in any `overturned` must not
14
+ * enter the final signals". We additionally post-filter overturned topics
15
+ * programmatically so a model slip cannot leak a retracted conclusion back in.
16
+ *
17
+ * The final payload is only structurally validated here (parsePayload). Evidence
18
+ * bounds + reference.url locatability (msg-id.ts) and second-pass privacy run in
19
+ * the orchestrator, which has the full transcript.
20
+ */
21
+ import { z } from "zod";
22
+ import { DistilledPayloadSchema, parsePayload, slugifyTopic, } from "./contract.js";
23
+ import { getMapPrompt, getReducePrompt } from "./prompt.js";
24
+ // Intermediate map output. tentative_signals / overturned stay loose (z.unknown /
25
+ // partial) because a segment view is provisional — only the reduced payload is
26
+ // held to the strict contract.
27
+ export const OverturnedSchema = z.object({
28
+ topic: z.string().min(1),
29
+ reason: z.string().optional(),
30
+ });
31
+ export const SegmentSummarySchema = z.object({
32
+ seg_no: z.number(),
33
+ summary: z.string(),
34
+ tentative_signals: z.array(z.record(z.unknown())),
35
+ overturned: z.array(OverturnedSchema),
36
+ carry_forward: z.string(),
37
+ });
38
+ function renderSegment(seg) {
39
+ return seg.messages
40
+ .map((m) => {
41
+ const cont = m.continued ? " (continued)" : "";
42
+ return `[${m.msgId}${cont}] ${m.role}: ${m.content}`;
43
+ })
44
+ .join("\n");
45
+ }
46
+ /**
47
+ * Run sequential map over segments then a single reduce.
48
+ * `criteria` is the judgment-declaration prompt fragment (spec §5 / §11 task 2.9);
49
+ * callers inject the embedded distill criteria.
50
+ */
51
+ export async function mapReduceDistill(segments, provider, criteria) {
52
+ const summaries = [];
53
+ let carry = "";
54
+ for (const seg of segments) {
55
+ const prompt = getMapPrompt({
56
+ criteria,
57
+ segmentText: renderSegment(seg),
58
+ segNo: seg.segNo,
59
+ carryForward: carry,
60
+ });
61
+ const raw = await provider.chat([
62
+ { role: "system", content: "You are a session distiller. Reply with JSON only." },
63
+ { role: "user", content: prompt },
64
+ ], { responseFormat: "json" });
65
+ const parsed = SegmentSummarySchema.parse(JSON.parse(raw));
66
+ summaries.push(parsed);
67
+ carry = parsed.carry_forward;
68
+ }
69
+ const overturnedTopics = summaries.flatMap((s) => s.overturned.map((o) => o.topic));
70
+ const overturnedSlugs = new Set(overturnedTopics.map(slugifyTopic));
71
+ const reducePrompt = getReducePrompt({
72
+ criteria,
73
+ segmentSummaries: summaries,
74
+ overturnedTopics,
75
+ });
76
+ const reduceRaw = await provider.chat([
77
+ { role: "system", content: "You are a session distiller. Reply with JSON only." },
78
+ { role: "user", content: reducePrompt },
79
+ ], { responseFormat: "json" });
80
+ const reduceParsed = DistilledPayloadSchema.parse(JSON.parse(reduceRaw));
81
+ // Belt-and-suspenders: strip any signal whose topic was overturned, even if the
82
+ // reducer wrongly re-included it.
83
+ const filtered = {
84
+ signals: reduceParsed.signals.filter((s) => !overturnedSlugs.has(slugifyTopic(s.topic))),
85
+ };
86
+ const finalRes = parsePayload(filtered);
87
+ if (!finalRes.ok) {
88
+ throw new Error(`reduced payload failed validation: ${finalRes.error.message}`);
89
+ }
90
+ return { payload: finalRes.payload, overturnedTopics, segmentSummaries: summaries };
91
+ }
92
+ //# sourceMappingURL=map-reduce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-reduce.js","sourceRoot":"","sources":["../../src/distiller/map-reduce.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Programmatic msg_id assignment + evidence validation (spec §5.2).
3
+ *
4
+ * The pipeline — not the model — assigns each transcript message a sequential
5
+ * `msg_id` (`msg-1`, `msg-2`, …). Oversized messages get sub-segment ids with a
6
+ * dotted suffix (`msg-42.1`, `msg-42.2`; see segmenter.ts). The model may only
7
+ * cite these given ids, and the validation layer here rejects any evidence range
8
+ * that falls outside the assigned set — killing line-number / id hallucination.
9
+ *
10
+ * It also enforces the spec §5 rule that `reference.url` must be locatable inside
11
+ * the text of its own evidence range: we pull the evidence text and check the url
12
+ * appears as a substring, so the model cannot conjure a url out of thin air.
13
+ *
14
+ * Ordering note: ranges are resolved by INDEX into the ordered message list, not
15
+ * by parsing the numeric id. This makes plain ids and dotted sub-segment ids
16
+ * (`msg-42.1`) order uniformly without a bespoke comparator.
17
+ */
18
+ import type { DistilledSignal } from "./contract.js";
19
+ export type MessageRole = "user" | "assistant";
20
+ export interface RawInputMessage {
21
+ role: MessageRole;
22
+ content: string;
23
+ }
24
+ export interface ParsedMessage {
25
+ msgId: string;
26
+ role: MessageRole;
27
+ content: string;
28
+ }
29
+ /** Assign sequential `msg-N` ids to messages in order. */
30
+ export declare function assignMsgIds(messages: RawInputMessage[]): ParsedMessage[];
31
+ interface EvidenceRange {
32
+ start: string;
33
+ end: string;
34
+ }
35
+ /**
36
+ * Concatenate the text of every message in [start, end] (inclusive), resolved by
37
+ * index. Throws if either bound is unknown or the range is inverted — callers
38
+ * that want a boolean should go through validateEvidence.
39
+ */
40
+ export declare function collectEvidenceText(parsed: ParsedMessage[], range: EvidenceRange): string;
41
+ export type ValidateEvidenceResult = {
42
+ ok: true;
43
+ } | {
44
+ ok: false;
45
+ errors: string[];
46
+ };
47
+ /**
48
+ * Validate every signal's evidence against the assigned msg_id set:
49
+ * - both bounds must reference an assigned id;
50
+ * - the range must not be inverted;
51
+ * - for `reference` signals, the url must appear in the evidence text.
52
+ */
53
+ export declare function validateEvidence(signals: DistilledSignal[], parsed: ParsedMessage[]): ValidateEvidenceResult;
54
+ export {};
55
+ //# sourceMappingURL=msg-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msg-id.d.ts","sourceRoot":"","sources":["../../src/distiller/msg-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,aAAa,EAAE,CAMzE;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAMD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAUzF;AAED,MAAM,MAAM,sBAAsB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEpF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EAAE,EAC1B,MAAM,EAAE,aAAa,EAAE,GACtB,sBAAsB,CAwCxB"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Programmatic msg_id assignment + evidence validation (spec §5.2).
3
+ *
4
+ * The pipeline — not the model — assigns each transcript message a sequential
5
+ * `msg_id` (`msg-1`, `msg-2`, …). Oversized messages get sub-segment ids with a
6
+ * dotted suffix (`msg-42.1`, `msg-42.2`; see segmenter.ts). The model may only
7
+ * cite these given ids, and the validation layer here rejects any evidence range
8
+ * that falls outside the assigned set — killing line-number / id hallucination.
9
+ *
10
+ * It also enforces the spec §5 rule that `reference.url` must be locatable inside
11
+ * the text of its own evidence range: we pull the evidence text and check the url
12
+ * appears as a substring, so the model cannot conjure a url out of thin air.
13
+ *
14
+ * Ordering note: ranges are resolved by INDEX into the ordered message list, not
15
+ * by parsing the numeric id. This makes plain ids and dotted sub-segment ids
16
+ * (`msg-42.1`) order uniformly without a bespoke comparator.
17
+ */
18
+ /** Assign sequential `msg-N` ids to messages in order. */
19
+ export function assignMsgIds(messages) {
20
+ return messages.map((m, i) => ({
21
+ msgId: `msg-${i + 1}`,
22
+ role: m.role,
23
+ content: m.content,
24
+ }));
25
+ }
26
+ function indexOfMsgId(parsed, msgId) {
27
+ return parsed.findIndex((m) => m.msgId === msgId);
28
+ }
29
+ /**
30
+ * Concatenate the text of every message in [start, end] (inclusive), resolved by
31
+ * index. Throws if either bound is unknown or the range is inverted — callers
32
+ * that want a boolean should go through validateEvidence.
33
+ */
34
+ export function collectEvidenceText(parsed, range) {
35
+ const s = indexOfMsgId(parsed, range.start);
36
+ const e = indexOfMsgId(parsed, range.end);
37
+ if (s < 0)
38
+ throw new Error(`unknown evidence start id: ${range.start}`);
39
+ if (e < 0)
40
+ throw new Error(`unknown evidence end id: ${range.end}`);
41
+ if (s > e)
42
+ throw new Error(`inverted evidence range: ${range.start}..${range.end}`);
43
+ return parsed
44
+ .slice(s, e + 1)
45
+ .map((m) => m.content)
46
+ .join("\n");
47
+ }
48
+ /**
49
+ * Validate every signal's evidence against the assigned msg_id set:
50
+ * - both bounds must reference an assigned id;
51
+ * - the range must not be inverted;
52
+ * - for `reference` signals, the url must appear in the evidence text.
53
+ */
54
+ export function validateEvidence(signals, parsed) {
55
+ const errors = [];
56
+ for (const sig of signals) {
57
+ for (const range of sig.evidence) {
58
+ const s = indexOfMsgId(parsed, range.start);
59
+ const e = indexOfMsgId(parsed, range.end);
60
+ if (s < 0) {
61
+ errors.push(`signal "${sig.topic}": evidence start "${range.start}" is out of bounds`);
62
+ continue;
63
+ }
64
+ if (e < 0) {
65
+ errors.push(`signal "${sig.topic}": evidence end "${range.end}" is out of bounds`);
66
+ continue;
67
+ }
68
+ if (s > e) {
69
+ errors.push(`signal "${sig.topic}": inverted evidence range ${range.start}..${range.end}`);
70
+ }
71
+ }
72
+ if (sig.type === "reference") {
73
+ const found = sig.evidence.some((range) => {
74
+ const s = indexOfMsgId(parsed, range.start);
75
+ const e = indexOfMsgId(parsed, range.end);
76
+ if (s < 0 || e < 0 || s > e)
77
+ return false;
78
+ const text = parsed
79
+ .slice(s, e + 1)
80
+ .map((m) => m.content)
81
+ .join("\n");
82
+ return text.includes(sig.url);
83
+ });
84
+ if (!found) {
85
+ errors.push(`signal "${sig.topic}": reference.url "${sig.url}" not found in its evidence text (possible hallucination)`);
86
+ }
87
+ }
88
+ }
89
+ return errors.length === 0 ? { ok: true } : { ok: false, errors };
90
+ }
91
+ //# sourceMappingURL=msg-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msg-id.js","sourceRoot":"","sources":["../../src/distiller/msg-id.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Second-pass privacy over the structured distilled payload (spec §4.3).
3
+ *
4
+ * The first pass (RawMessagePrivacyProcessor) redacts raw message text before
5
+ * the LLM sees it; this second pass runs right before the payload is written to
6
+ * the outbox, catching sensitive strings the model might have reproduced or
7
+ * synthesized in its OUTPUT (e.g. reassembling a phone number from context).
8
+ *
9
+ * Field policy mirrors PrivacyProcessor (privacy.ts): free-text narrative fields
10
+ * are redacted; structural fields (type, authority, status, evidence, dates,
11
+ * enums), entity NAMES (aligned with Entity.name never being redacted) and
12
+ * reference urls (the url is the core field, checked against evidence) are left
13
+ * intact.
14
+ */
15
+ import type { PrivacyConfig } from "../core/config.js";
16
+ import type { DistilledPayload } from "./contract.js";
17
+ export declare function redactPayload(payload: DistilledPayload, config: PrivacyConfig): DistilledPayload;
18
+ //# sourceMappingURL=payload-privacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-privacy.d.ts","sourceRoot":"","sources":["../../src/distiller/payload-privacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,eAAe,CAAC;AAGvE,wBAAgB,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,aAAa,GAAG,gBAAgB,CAoChG"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Second-pass privacy over the structured distilled payload (spec §4.3).
3
+ *
4
+ * The first pass (RawMessagePrivacyProcessor) redacts raw message text before
5
+ * the LLM sees it; this second pass runs right before the payload is written to
6
+ * the outbox, catching sensitive strings the model might have reproduced or
7
+ * synthesized in its OUTPUT (e.g. reassembling a phone number from context).
8
+ *
9
+ * Field policy mirrors PrivacyProcessor (privacy.ts): free-text narrative fields
10
+ * are redacted; structural fields (type, authority, status, evidence, dates,
11
+ * enums), entity NAMES (aligned with Entity.name never being redacted) and
12
+ * reference urls (the url is the core field, checked against evidence) are left
13
+ * intact.
14
+ */
15
+ import { RawMessagePrivacyProcessor } from "./raw-privacy.js";
16
+ export function redactPayload(payload, config) {
17
+ if (!config.enabled)
18
+ return payload;
19
+ // Force irreversible for the structured pass: the reversible restoration map
20
+ // is only kept for raw message text keyed by msg_id (first pass); structured
21
+ // output redactions are not reversible (nothing to anchor them to).
22
+ const proc = new RawMessagePrivacyProcessor({ ...config, mode: "irreversible" });
23
+ const r = (text) => proc.redactString(text);
24
+ const rOpt = (text) => (text === undefined ? undefined : r(text));
25
+ const redactSignal = (sig) => {
26
+ const common = {
27
+ topic: r(sig.topic),
28
+ what: r(sig.what),
29
+ why: rOpt(sig.why),
30
+ project: sig.project,
31
+ entities: sig.entities,
32
+ authority: sig.authority,
33
+ supersedes_topic: rOpt(sig.supersedes_topic),
34
+ evidence: sig.evidence,
35
+ persistence_reason: r(sig.persistence_reason),
36
+ };
37
+ switch (sig.type) {
38
+ case "task":
39
+ return { ...sig, ...common, owner: rOpt(sig.owner) };
40
+ case "reference":
41
+ return { ...sig, ...common, trigger: rOpt(sig.trigger) };
42
+ case "preference":
43
+ return { ...sig, ...common, subject: r(sig.subject) };
44
+ default:
45
+ // decision / knowledge / discovery carry no extra free-text fields.
46
+ return { ...sig, ...common };
47
+ }
48
+ };
49
+ return { signals: payload.signals.map(redactSignal) };
50
+ }
51
+ //# sourceMappingURL=payload-privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-privacy.js","sourceRoot":"","sources":["../../src/distiller/payload-privacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,MAAM,UAAU,aAAa,CAAC,OAAyB,EAAE,MAAqB;IAC5E,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC;IAEpC,6EAA6E;IAC7E,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,IAAI,GAAG,IAAI,0BAA0B,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;IACjF,MAAM,CAAC,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,CAAC,IAAwB,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtF,MAAM,YAAY,GAAG,CAAC,GAAoB,EAAmB,EAAE;QAC7D,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;YACnB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAClB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAC5C,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,kBAAkB,EAAE,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC;SAC9C,CAAC;QACF,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,MAAM;gBACT,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,KAAK,WAAW;gBACd,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,KAAK,YAAY;gBACf,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACxD;gBACE,oEAAoE;gBACpE,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;AACxD,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Distillation prompt assembly (spec §5, §5.1, §11 task 2.9).
3
+ *
4
+ * The judgment-declaration criteria live in an embedded markdown prompt
5
+ * (`src/extractors/prompts/distill.md`, inlined by gen:assets into PROMPTS).
6
+ * This module wraps that criteria into the concrete map + reduce prompts, with
7
+ * carry-forward and overturned instructions threaded in.
8
+ *
9
+ * Keeping prompt text out of map-reduce.ts lets the criteria be iterated
10
+ * (PR-1 eval loop) without touching orchestration logic.
11
+ */
12
+ import type { SegmentSummary } from "./map-reduce.js";
13
+ /** Load the embedded distill criteria; falls back to a terse built-in if absent. */
14
+ export declare function getDistillCriteria(): string;
15
+ export interface MapPromptInput {
16
+ criteria?: string;
17
+ segmentText: string;
18
+ segNo: number;
19
+ carryForward: string;
20
+ }
21
+ export declare function getMapPrompt(input: MapPromptInput): string;
22
+ export interface ReducePromptInput {
23
+ criteria?: string;
24
+ segmentSummaries: SegmentSummary[];
25
+ overturnedTopics: string[];
26
+ }
27
+ export declare function getReducePrompt(input: ReducePromptInput): string;
28
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/distiller/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,oFAAoF;AACpF,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAQD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAwB1D;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,cAAc,EAAE,CAAC;IACnC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAuBhE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Distillation prompt assembly (spec §5, §5.1, §11 task 2.9).
3
+ *
4
+ * The judgment-declaration criteria live in an embedded markdown prompt
5
+ * (`src/extractors/prompts/distill.md`, inlined by gen:assets into PROMPTS).
6
+ * This module wraps that criteria into the concrete map + reduce prompts, with
7
+ * carry-forward and overturned instructions threaded in.
8
+ *
9
+ * Keeping prompt text out of map-reduce.ts lets the criteria be iterated
10
+ * (PR-1 eval loop) without touching orchestration logic.
11
+ */
12
+ import { PROMPTS } from "../embedded-assets.generated.js";
13
+ /** Load the embedded distill criteria; falls back to a terse built-in if absent. */
14
+ export function getDistillCriteria() {
15
+ return PROMPTS["distill.md"] ?? FALLBACK_CRITERIA;
16
+ }
17
+ const FALLBACK_CRITERIA = `You are distilling an agent session for a future retriever 30 days from now.
18
+ Record only what a colleague would need to reconstruct WHY things are the way they
19
+ are. Distinguish: the user deciding (user_confirmed) vs. you proposing
20
+ (assistant_proposed) vs. a claim proven by a tool result (assistant_claimed).
21
+ Skip transient debugging chatter and unconfirmed proposals.`;
22
+ export function getMapPrompt(input) {
23
+ const criteria = input.criteria ?? getDistillCriteria();
24
+ const carrySection = input.carryForward.trim().length > 0
25
+ ? `\n## Carried forward from the previous segment\n\n${input.carryForward}\n`
26
+ : "";
27
+ return `${criteria}
28
+
29
+ ## Segment ${input.segNo}
30
+ ${carrySection}
31
+ ## Messages
32
+
33
+ ${input.segmentText}
34
+
35
+ ## Instructions
36
+
37
+ Distill THIS segment only. Output ONLY JSON of shape:
38
+ {
39
+ "seg_no": ${input.segNo},
40
+ "summary": "<one-paragraph gist of this segment>",
41
+ "tentative_signals": [ /* candidate signals per the contract */ ],
42
+ "overturned": [ { "topic": "<a topic from earlier that is now retracted>", "reason": "..." } ],
43
+ "carry_forward": "<in-progress topics / undecided items to hand to the next segment>"
44
+ }`;
45
+ }
46
+ export function getReducePrompt(input) {
47
+ const criteria = input.criteria ?? getDistillCriteria();
48
+ const summariesJson = JSON.stringify(input.segmentSummaries, null, 2);
49
+ const overturnedList = input.overturnedTopics.length > 0
50
+ ? input.overturnedTopics.map((t) => `- ${t}`).join("\n")
51
+ : "(none)";
52
+ return `${criteria}
53
+
54
+ ## Segment summaries
55
+
56
+ ${summariesJson}
57
+
58
+ ## Overturned topics (MUST NOT appear in the final signals)
59
+
60
+ ${overturnedList}
61
+
62
+ ## Instructions
63
+
64
+ Merge the tentative signals across all segments into the final session payload.
65
+ RULE: any conclusion that appears in the overturned list above MUST NOT enter the
66
+ final signals. Deduplicate: no two final signals may share the same (type, topic).
67
+ Output ONLY JSON of shape { "signals": [ ...signals per the contract... ] }.`;
68
+ }
69
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/distiller/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAG1D,oFAAoF;AACpF,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC,YAAY,CAAC,IAAI,iBAAiB,CAAC;AACpD,CAAC;AAED,MAAM,iBAAiB,GAAG;;;;4DAIkC,CAAC;AAS7D,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,kBAAkB,EAAE,CAAC;IACxD,MAAM,YAAY,GAChB,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAClC,CAAC,CAAC,qDAAqD,KAAK,CAAC,YAAY,IAAI;QAC7E,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,GAAG,QAAQ;;aAEP,KAAK,CAAC,KAAK;EACtB,YAAY;;;EAGZ,KAAK,CAAC,WAAW;;;;;;cAML,KAAK,CAAC,KAAK;;;;;EAKvB,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,kBAAkB,EAAE,CAAC;IACxD,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,MAAM,cAAc,GAClB,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACxD,CAAC,CAAC,QAAQ,CAAC;IACf,OAAO,GAAG,QAAQ;;;;EAIlB,aAAa;;;;EAIb,cAAc;;;;;;;6EAO6D,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * RawMessagePrivacyProcessor — pre-LLM redaction (spec §4.3, first pass).
3
+ *
4
+ * The legacy block pipeline sends raw messages to the LLM and only redacts the
5
+ * structured ExtractionResult afterwards (privacy.ts / PrivacyProcessor) — so
6
+ * the model sees un-redacted originals. For the distiller we fix that ordering:
7
+ * this processor redacts raw message TEXT before it is ever handed to the LLM
8
+ * (every map/reduce segment input goes through it first).
9
+ *
10
+ * It reuses the exact PrivacyConfig rules and patterns as PrivacyProcessor, but
11
+ * operates on plain strings keyed by msg_id (not on ExtractionResult). In
12
+ * reversible mode the restoration map is grouped by msg_id (spec §4.3) so an
13
+ * authorized reader can recover the original text for a cited evidence range.
14
+ */
15
+ import type { PrivacyConfig } from "../core/config.js";
16
+ import type { ParsedMessage } from "./msg-id.js";
17
+ /** A single reversible redaction: what was replaced, with what, and where. */
18
+ export interface RawRedactionEntry {
19
+ original: string;
20
+ replacement: string;
21
+ /** Character offset in the redacted string (post-substitution). */
22
+ position: number;
23
+ }
24
+ /** Restoration map: msg_id → the redactions applied to that message. */
25
+ export type RestorationMap = Record<string, RawRedactionEntry[]>;
26
+ export interface RedactMessagesResult {
27
+ messages: ParsedMessage[];
28
+ restorationMap: RestorationMap;
29
+ }
30
+ export declare class RawMessagePrivacyProcessor {
31
+ private readonly config;
32
+ constructor(config: PrivacyConfig);
33
+ private patterns;
34
+ private escapeRegex;
35
+ /**
36
+ * Redact one message's text. Returns the redacted string and (in reversible
37
+ * mode) the ordered redaction entries.
38
+ */
39
+ private redactText;
40
+ /**
41
+ * Redact a single free-text string (no restoration tracking exposed).
42
+ * Used by the second-pass payload privacy (payload-privacy.ts).
43
+ */
44
+ redactString(text: string): string;
45
+ /** Redact every message's text before it is sent to the LLM. */
46
+ redactMessages(messages: ParsedMessage[]): RedactMessagesResult;
47
+ /**
48
+ * Reverse redaction for a single message's (redacted) text using its
49
+ * msg_id-keyed entries. Applies entries in forward order (they were recorded
50
+ * against post-substitution offsets in reverse, so left-to-right restore is
51
+ * position-stable because each restore preserves earlier offsets).
52
+ */
53
+ restore(msgId: string, redactedText: string, map: RestorationMap): string;
54
+ }
55
+ //# sourceMappingURL=raw-privacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-privacy.d.ts","sourceRoot":"","sources":["../../src/distiller/raw-privacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,8EAA8E;AAC9E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAEjE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC;CAChC;AAQD,qBAAa,0BAA0B;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAGlD,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,WAAW;IAInB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAsClB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAKlC,gEAAgE;IAChE,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,oBAAoB;IAe/D;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,MAAM;CAc1E"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * RawMessagePrivacyProcessor — pre-LLM redaction (spec §4.3, first pass).
3
+ *
4
+ * The legacy block pipeline sends raw messages to the LLM and only redacts the
5
+ * structured ExtractionResult afterwards (privacy.ts / PrivacyProcessor) — so
6
+ * the model sees un-redacted originals. For the distiller we fix that ordering:
7
+ * this processor redacts raw message TEXT before it is ever handed to the LLM
8
+ * (every map/reduce segment input goes through it first).
9
+ *
10
+ * It reuses the exact PrivacyConfig rules and patterns as PrivacyProcessor, but
11
+ * operates on plain strings keyed by msg_id (not on ExtractionResult). In
12
+ * reversible mode the restoration map is grouped by msg_id (spec §4.3) so an
13
+ * authorized reader can recover the original text for a cited evidence range.
14
+ */
15
+ export class RawMessagePrivacyProcessor {
16
+ config;
17
+ constructor(config) {
18
+ this.config = config;
19
+ }
20
+ // Patterns mirror PrivacyProcessor (privacy.ts) — same PrivacyConfig rules.
21
+ patterns() {
22
+ return [
23
+ { regex: /1[3-9]\d{9}/g, replacement: "[REDACTED_PHONE]", enabled: this.config.redact_phone },
24
+ { regex: /\d{17}[\dXx]/g, replacement: "[REDACTED_ID]", enabled: this.config.redact_id_card },
25
+ {
26
+ regex: /\d{16,19}/g,
27
+ replacement: "[REDACTED_CARD]",
28
+ enabled: this.config.redact_bank_card,
29
+ },
30
+ // L2 IP address — always on in PrivacyProcessor.
31
+ { regex: /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g, replacement: "[REDACTED_IP]", enabled: true },
32
+ ];
33
+ }
34
+ escapeRegex(str) {
35
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
36
+ }
37
+ /**
38
+ * Redact one message's text. Returns the redacted string and (in reversible
39
+ * mode) the ordered redaction entries.
40
+ */
41
+ redactText(text) {
42
+ const entries = [];
43
+ let result = text;
44
+ const applyPattern = (regex, replacement) => {
45
+ const matches = [];
46
+ const source = result;
47
+ let m;
48
+ // biome-ignore lint/suspicious/noAssignInExpressions: standard regex.exec loop
49
+ while ((m = regex.exec(source)) !== null) {
50
+ matches.push({ original: m[0], position: m.index });
51
+ }
52
+ regex.lastIndex = 0;
53
+ // Apply in reverse to keep positions valid.
54
+ for (let i = matches.length - 1; i >= 0; i--) {
55
+ const mm = matches[i];
56
+ result =
57
+ result.slice(0, mm.position) +
58
+ replacement +
59
+ result.slice(mm.position + mm.original.length);
60
+ if (this.config.mode === "reversible") {
61
+ entries.push({ original: mm.original, replacement, position: mm.position });
62
+ }
63
+ }
64
+ };
65
+ for (const p of this.patterns()) {
66
+ if (p.enabled)
67
+ applyPattern(p.regex, p.replacement);
68
+ }
69
+ // L3 blocked words (case-insensitive).
70
+ for (const word of this.config.blocked_words) {
71
+ const regex = new RegExp(`\\b${this.escapeRegex(word)}\\b`, "gi");
72
+ applyPattern(regex, this.config.replacement);
73
+ }
74
+ return { text: result, entries };
75
+ }
76
+ /**
77
+ * Redact a single free-text string (no restoration tracking exposed).
78
+ * Used by the second-pass payload privacy (payload-privacy.ts).
79
+ */
80
+ redactString(text) {
81
+ if (!this.config.enabled)
82
+ return text;
83
+ return this.redactText(text).text;
84
+ }
85
+ /** Redact every message's text before it is sent to the LLM. */
86
+ redactMessages(messages) {
87
+ if (!this.config.enabled) {
88
+ return { messages, restorationMap: {} };
89
+ }
90
+ const restorationMap = {};
91
+ const redacted = messages.map((msg) => {
92
+ const { text, entries } = this.redactText(msg.content);
93
+ if (this.config.mode === "reversible" && entries.length > 0) {
94
+ restorationMap[msg.msgId] = entries;
95
+ }
96
+ return { ...msg, content: text };
97
+ });
98
+ return { messages: redacted, restorationMap };
99
+ }
100
+ /**
101
+ * Reverse redaction for a single message's (redacted) text using its
102
+ * msg_id-keyed entries. Applies entries in forward order (they were recorded
103
+ * against post-substitution offsets in reverse, so left-to-right restore is
104
+ * position-stable because each restore preserves earlier offsets).
105
+ */
106
+ restore(msgId, redactedText, map) {
107
+ const entries = map[msgId];
108
+ if (!entries || entries.length === 0)
109
+ return redactedText;
110
+ // Restore from rightmost to leftmost so earlier offsets stay valid.
111
+ const sorted = [...entries].sort((a, b) => b.position - a.position);
112
+ let result = redactedText;
113
+ for (const e of sorted) {
114
+ const at = result.indexOf(e.replacement, e.position);
115
+ const idx = at >= 0 ? at : result.indexOf(e.replacement);
116
+ if (idx < 0)
117
+ continue;
118
+ result = result.slice(0, idx) + e.original + result.slice(idx + e.replacement.length);
119
+ }
120
+ return result;
121
+ }
122
+ }
123
+ //# sourceMappingURL=raw-privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-privacy.js","sourceRoot":"","sources":["../../src/distiller/raw-privacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA2BH,MAAM,OAAO,0BAA0B;IACR;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,4EAA4E;IACpE,QAAQ;QACd,OAAO;YACL,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;YAC7F,EAAE,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;YAC7F;gBACE,KAAK,EAAE,YAAY;gBACnB,WAAW,EAAE,iBAAiB;gBAC9B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;aACtC;YACD,iDAAiD;YACjD,EAAE,KAAK,EAAE,qCAAqC,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;SAC9F,CAAC;IACJ,CAAC;IAEO,WAAW,CAAC,GAAW;QAC7B,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAED;;;OAGG;IACK,UAAU,CAAC,IAAY;QAC7B,MAAM,OAAO,GAAwB,EAAE,CAAC;QACxC,IAAI,MAAM,GAAG,IAAI,CAAC;QAElB,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,WAAmB,EAAE,EAAE;YAC1D,MAAM,OAAO,GAAkD,EAAE,CAAC;YAClE,MAAM,MAAM,GAAG,MAAM,CAAC;YACtB,IAAI,CAAyB,CAAC;YAC9B,+EAA+E;YAC/E,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC;YACD,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;YACpB,4CAA4C;YAC5C,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM;oBACJ,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC;wBAC5B,WAAW;wBACX,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACjD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACtC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC9E,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAChC,IAAI,CAAC,CAAC,OAAO;gBAAE,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;QACtD,CAAC;QACD,uCAAuC;QACvC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAClE,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,gEAAgE;IAChE,cAAc,CAAC,QAAyB;QACtC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;QAC1C,CAAC;QACD,MAAM,cAAc,GAAmB,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5D,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;YACtC,CAAC;YACD,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,KAAa,EAAE,YAAoB,EAAE,GAAmB;QAC9D,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC;QAC1D,oEAAoE;QACpE,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QACpE,IAAI,MAAM,GAAG,YAAY,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACrD,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC;gBAAE,SAAS;YACtB,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}