@postalsys/email-content 0.0.1

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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/analyze.d.ts +91 -0
  5. package/dist/analyze.d.ts.map +1 -0
  6. package/dist/analyze.js +274 -0
  7. package/dist/analyze.js.map +1 -0
  8. package/dist/annotate/client.d.ts +64 -0
  9. package/dist/annotate/client.d.ts.map +1 -0
  10. package/dist/annotate/client.js +139 -0
  11. package/dist/annotate/client.js.map +1 -0
  12. package/dist/annotate/llm.d.ts +46 -0
  13. package/dist/annotate/llm.d.ts.map +1 -0
  14. package/dist/annotate/llm.js +107 -0
  15. package/dist/annotate/llm.js.map +1 -0
  16. package/dist/annotate/prompt.d.ts +38 -0
  17. package/dist/annotate/prompt.d.ts.map +1 -0
  18. package/dist/annotate/prompt.js +165 -0
  19. package/dist/annotate/prompt.js.map +1 -0
  20. package/dist/annotate/store.d.ts +43 -0
  21. package/dist/annotate/store.d.ts.map +1 -0
  22. package/dist/annotate/store.js +46 -0
  23. package/dist/annotate/store.js.map +1 -0
  24. package/dist/canonical/html.d.ts +33 -0
  25. package/dist/canonical/html.d.ts.map +1 -0
  26. package/dist/canonical/html.js +156 -0
  27. package/dist/canonical/html.js.map +1 -0
  28. package/dist/canonical/text.d.ts +75 -0
  29. package/dist/canonical/text.d.ts.map +1 -0
  30. package/dist/canonical/text.js +217 -0
  31. package/dist/canonical/text.js.map +1 -0
  32. package/dist/classify/confidence.d.ts +38 -0
  33. package/dist/classify/confidence.d.ts.map +1 -0
  34. package/dist/classify/confidence.js +59 -0
  35. package/dist/classify/confidence.js.map +1 -0
  36. package/dist/classify/reconcile.d.ts +52 -0
  37. package/dist/classify/reconcile.d.ts.map +1 -0
  38. package/dist/classify/reconcile.js +100 -0
  39. package/dist/classify/reconcile.js.map +1 -0
  40. package/dist/classify/rules.d.ts +51 -0
  41. package/dist/classify/rules.d.ts.map +1 -0
  42. package/dist/classify/rules.js +648 -0
  43. package/dist/classify/rules.js.map +1 -0
  44. package/dist/cli/annotate.d.ts +23 -0
  45. package/dist/cli/annotate.d.ts.map +1 -0
  46. package/dist/cli/annotate.js +328 -0
  47. package/dist/cli/annotate.js.map +1 -0
  48. package/dist/cli/args.d.ts +17 -0
  49. package/dist/cli/args.d.ts.map +1 -0
  50. package/dist/cli/args.js +72 -0
  51. package/dist/cli/args.js.map +1 -0
  52. package/dist/cli/benchmark.d.ts +13 -0
  53. package/dist/cli/benchmark.d.ts.map +1 -0
  54. package/dist/cli/benchmark.js +172 -0
  55. package/dist/cli/benchmark.js.map +1 -0
  56. package/dist/cli/corpus.d.ts +9 -0
  57. package/dist/cli/corpus.d.ts.map +1 -0
  58. package/dist/cli/corpus.js +152 -0
  59. package/dist/cli/corpus.js.map +1 -0
  60. package/dist/cli/disagreements.d.ts +14 -0
  61. package/dist/cli/disagreements.d.ts.map +1 -0
  62. package/dist/cli/disagreements.js +133 -0
  63. package/dist/cli/disagreements.js.map +1 -0
  64. package/dist/cli/evaluate.d.ts +15 -0
  65. package/dist/cli/evaluate.d.ts.map +1 -0
  66. package/dist/cli/evaluate.js +215 -0
  67. package/dist/cli/evaluate.js.map +1 -0
  68. package/dist/cli/extract.d.ts +10 -0
  69. package/dist/cli/extract.d.ts.map +1 -0
  70. package/dist/cli/extract.js +139 -0
  71. package/dist/cli/extract.js.map +1 -0
  72. package/dist/cli/main.d.ts +9 -0
  73. package/dist/cli/main.d.ts.map +1 -0
  74. package/dist/cli/main.js +147 -0
  75. package/dist/cli/main.js.map +1 -0
  76. package/dist/corpus/analyze.d.ts +66 -0
  77. package/dist/corpus/analyze.d.ts.map +1 -0
  78. package/dist/corpus/analyze.js +214 -0
  79. package/dist/corpus/analyze.js.map +1 -0
  80. package/dist/corpus/migrations/index.d.ts +14 -0
  81. package/dist/corpus/migrations/index.d.ts.map +1 -0
  82. package/dist/corpus/migrations/index.js +158 -0
  83. package/dist/corpus/migrations/index.js.map +1 -0
  84. package/dist/corpus/sample.d.ts +66 -0
  85. package/dist/corpus/sample.d.ts.map +1 -0
  86. package/dist/corpus/sample.js +98 -0
  87. package/dist/corpus/sample.js.map +1 -0
  88. package/dist/corpus/scanner.d.ts +79 -0
  89. package/dist/corpus/scanner.d.ts.map +1 -0
  90. package/dist/corpus/scanner.js +256 -0
  91. package/dist/corpus/scanner.js.map +1 -0
  92. package/dist/corpus/stats.d.ts +76 -0
  93. package/dist/corpus/stats.d.ts.map +1 -0
  94. package/dist/corpus/stats.js +240 -0
  95. package/dist/corpus/stats.js.map +1 -0
  96. package/dist/corpus/store.d.ts +67 -0
  97. package/dist/corpus/store.d.ts.map +1 -0
  98. package/dist/corpus/store.js +196 -0
  99. package/dist/corpus/store.js.map +1 -0
  100. package/dist/corpus/thread-index.d.ts +31 -0
  101. package/dist/corpus/thread-index.d.ts.map +1 -0
  102. package/dist/corpus/thread-index.js +182 -0
  103. package/dist/corpus/thread-index.js.map +1 -0
  104. package/dist/corpus/worker.d.ts +21 -0
  105. package/dist/corpus/worker.d.ts.map +1 -0
  106. package/dist/corpus/worker.js +74 -0
  107. package/dist/corpus/worker.js.map +1 -0
  108. package/dist/detect/client.d.ts +28 -0
  109. package/dist/detect/client.d.ts.map +1 -0
  110. package/dist/detect/client.js +121 -0
  111. package/dist/detect/client.js.map +1 -0
  112. package/dist/detect/disclaimer.d.ts +12 -0
  113. package/dist/detect/disclaimer.d.ts.map +1 -0
  114. package/dist/detect/disclaimer.js +28 -0
  115. package/dist/detect/disclaimer.js.map +1 -0
  116. package/dist/detect/forward-header.d.ts +10 -0
  117. package/dist/detect/forward-header.d.ts.map +1 -0
  118. package/dist/detect/forward-header.js +35 -0
  119. package/dist/detect/forward-header.js.map +1 -0
  120. package/dist/detect/patterns/disclaimers.json +113 -0
  121. package/dist/detect/patterns/forward-headers.json +40 -0
  122. package/dist/detect/patterns/html-clients.json +157 -0
  123. package/dist/detect/patterns/quoted-headers.json +41 -0
  124. package/dist/detect/patterns/reply-headers.json +139 -0
  125. package/dist/detect/patterns/signatures.json +58 -0
  126. package/dist/detect/patterns.d.ts +43 -0
  127. package/dist/detect/patterns.d.ts.map +1 -0
  128. package/dist/detect/patterns.js +125 -0
  129. package/dist/detect/patterns.js.map +1 -0
  130. package/dist/detect/reply-header.d.ts +44 -0
  131. package/dist/detect/reply-header.d.ts.map +1 -0
  132. package/dist/detect/reply-header.js +134 -0
  133. package/dist/detect/reply-header.js.map +1 -0
  134. package/dist/detect/signature.d.ts +28 -0
  135. package/dist/detect/signature.d.ts.map +1 -0
  136. package/dist/detect/signature.js +77 -0
  137. package/dist/detect/signature.js.map +1 -0
  138. package/dist/detect/traffic.d.ts +26 -0
  139. package/dist/detect/traffic.d.ts.map +1 -0
  140. package/dist/detect/traffic.js +98 -0
  141. package/dist/detect/traffic.js.map +1 -0
  142. package/dist/eval/metrics.d.ts +87 -0
  143. package/dist/eval/metrics.d.ts.map +1 -0
  144. package/dist/eval/metrics.js +185 -0
  145. package/dist/eval/metrics.js.map +1 -0
  146. package/dist/index.d.ts +54 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +163 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/match/history.d.ts +62 -0
  151. package/dist/match/history.d.ts.map +1 -0
  152. package/dist/match/history.js +128 -0
  153. package/dist/match/history.js.map +1 -0
  154. package/dist/match/normalize.d.ts +33 -0
  155. package/dist/match/normalize.d.ts.map +1 -0
  156. package/dist/match/normalize.js +63 -0
  157. package/dist/match/normalize.js.map +1 -0
  158. package/dist/match/shingle.d.ts +44 -0
  159. package/dist/match/shingle.d.ts.map +1 -0
  160. package/dist/match/shingle.js +78 -0
  161. package/dist/match/shingle.js.map +1 -0
  162. package/dist/mime/charset.d.ts +33 -0
  163. package/dist/mime/charset.d.ts.map +1 -0
  164. package/dist/mime/charset.js +118 -0
  165. package/dist/mime/charset.js.map +1 -0
  166. package/dist/mime/headers.d.ts +32 -0
  167. package/dist/mime/headers.d.ts.map +1 -0
  168. package/dist/mime/headers.js +127 -0
  169. package/dist/mime/headers.js.map +1 -0
  170. package/dist/mime/model.d.ts +111 -0
  171. package/dist/mime/model.d.ts.map +1 -0
  172. package/dist/mime/model.js +17 -0
  173. package/dist/mime/model.js.map +1 -0
  174. package/dist/mime/parse.d.ts +27 -0
  175. package/dist/mime/parse.d.ts.map +1 -0
  176. package/dist/mime/parse.js +343 -0
  177. package/dist/mime/parse.js.map +1 -0
  178. package/dist/segment/features.d.ts +29 -0
  179. package/dist/segment/features.d.ts.map +1 -0
  180. package/dist/segment/features.js +102 -0
  181. package/dist/segment/features.js.map +1 -0
  182. package/dist/segment/html-blocks.d.ts +28 -0
  183. package/dist/segment/html-blocks.d.ts.map +1 -0
  184. package/dist/segment/html-blocks.js +596 -0
  185. package/dist/segment/html-blocks.js.map +1 -0
  186. package/dist/segment/text-blocks.d.ts +30 -0
  187. package/dist/segment/text-blocks.d.ts.map +1 -0
  188. package/dist/segment/text-blocks.js +204 -0
  189. package/dist/segment/text-blocks.js.map +1 -0
  190. package/dist/segment/types.d.ts +88 -0
  191. package/dist/segment/types.d.ts.map +1 -0
  192. package/dist/segment/types.js +11 -0
  193. package/dist/segment/types.js.map +1 -0
  194. package/dist/types.d.ts +85 -0
  195. package/dist/types.d.ts.map +1 -0
  196. package/dist/types.js +17 -0
  197. package/dist/types.js.map +1 -0
  198. package/dist/util/hash.d.ts +49 -0
  199. package/dist/util/hash.d.ts.map +1 -0
  200. package/dist/util/hash.js +0 -0
  201. package/dist/util/hash.js.map +1 -0
  202. package/dist/util/lang.d.ts +25 -0
  203. package/dist/util/lang.d.ts.map +1 -0
  204. package/dist/util/lang.js +135 -0
  205. package/dist/util/lang.js.map +1 -0
  206. package/dist/util/worker-pool.d.ts +51 -0
  207. package/dist/util/worker-pool.d.ts.map +1 -0
  208. package/dist/util/worker-pool.js +155 -0
  209. package/dist/util/worker-pool.js.map +1 -0
  210. package/package.json +74 -0
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * `email-content evaluate` subcommand.
4
+ *
5
+ * Scores the current extractor against a stored reference set. The reference is re-scored from
6
+ * scratch every run, rather than reusing the baseline verdict captured at annotation time, so that
7
+ * a change to the rules is actually measured instead of being compared against its own past
8
+ * output.
9
+ *
10
+ * The reference here is LLM produced. It is treated as a reference, not as truth: two capable
11
+ * models agree with each other on about 80 percent of blocks, so a number in the high nineties
12
+ * would indicate a measurement problem, not a solved task.
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.evaluateCommand = evaluateCommand;
19
+ const node_fs_1 = __importDefault(require("node:fs"));
20
+ const node_path_1 = __importDefault(require("node:path"));
21
+ const index_1 = require("../index");
22
+ const store_1 = require("../corpus/store");
23
+ const thread_index_1 = require("../corpus/thread-index");
24
+ const metrics_1 = require("../eval/metrics");
25
+ const parse_1 = require("../mime/parse");
26
+ const types_1 = require("../types");
27
+ const args_1 = require("./args");
28
+ function pct(value) {
29
+ return `${(100 * value).toFixed(1)}%`;
30
+ }
31
+ function renderReport(report, title) {
32
+ const out = [];
33
+ out.push(title);
34
+ out.push(` messages ${report.messages}, blocks ${report.blocks}, exact label agreement ${pct(report.exactAgreement)}`);
35
+ out.push('');
36
+ out.push('CONTENT RETENTION (the headline numbers)');
37
+ const r = report.retention;
38
+ out.push(` new content characters retained ${pct(r.newContentCharRecall)} (${r.newContentCharsRetained} of ${r.newContentChars})`);
39
+ out.push(` new content blocks retained ${pct(r.newContentBlockRecall)} (${r.newContentBlocksRetained} of ${r.newContentBlocks})`);
40
+ out.push(` hidden content genuinely history ${pct(r.hiddenPrecision)} (${r.hiddenCharsGenuinelyHistory} of ${r.hiddenChars})`);
41
+ out.push(` history still visible ${pct(r.historyStillVisibleShare)} (${r.historyCharsStillVisible} of ${r.historyChars})`);
42
+ out.push('');
43
+ out.push('PER LABEL');
44
+ out.push(' label support predicted precision recall f1');
45
+ for (const metric of report.perLabel) {
46
+ if (!metric.support && !metric.predicted) {
47
+ continue;
48
+ }
49
+ out.push(` ${metric.label.padEnd(18)} ${String(metric.support).padStart(7)} ${String(metric.predicted).padStart(10)} ` +
50
+ `${pct(metric.precision).padStart(10)} ${pct(metric.recall).padStart(7)} ${pct(metric.f1).padStart(7)}`);
51
+ }
52
+ out.push('');
53
+ out.push('CONFUSION (rows: reference, columns: predicted)');
54
+ const present = types_1.LABELS.filter(label => report.perLabel.find(metric => metric.label === label && (metric.support || metric.predicted)));
55
+ out.push(` ${' '.repeat(18)}${present.map(label => label.slice(0, 8).padStart(9)).join('')}`);
56
+ for (const reference of present) {
57
+ const cells = present.map(predicted => String(report.confusion.get(`${reference}|${predicted}`) ?? 0).padStart(9)).join('');
58
+ out.push(` ${reference.padEnd(18)}${cells}`);
59
+ }
60
+ out.push('');
61
+ out.push('CATASTROPHIC ERRORS (counted per message, never averaged)');
62
+ const c = report.catastrophic;
63
+ const line = (label, value) => ` ${label.padEnd(42)} ${String(value).padStart(5)} ${pct(value / Math.max(1, c.messages))}`;
64
+ out.push(line('all new content removed', c.allNewContentRemoved));
65
+ out.push(line('inline answer removed', c.inlineAnswerRemoved));
66
+ out.push(line('inline context removed', c.inlineContextRemoved));
67
+ out.push(line('forwarded content discarded', c.forwardedDiscarded));
68
+ out.push(line('only a footer retained', c.onlyFooterRetained));
69
+ out.push(line('empty extraction from non empty message', c.emptyExtraction));
70
+ out.push(line('mostly unknown content hidden', c.unknownHidden));
71
+ out.push('');
72
+ if (report.byGroup.length > 1) {
73
+ out.push('BY GROUP');
74
+ out.push(' group blocks agreement new content retained');
75
+ for (const group of report.byGroup.slice(0, 15)) {
76
+ out.push(` ${group.group.padEnd(24)} ${String(group.blocks).padStart(6)} ${pct(group.agreement).padStart(10)} ${pct(group.newContentCharRecall).padStart(21)}`);
77
+ }
78
+ out.push('');
79
+ }
80
+ return out.join('\n');
81
+ }
82
+ async function evaluateCommand(args) {
83
+ const dbPath = (0, args_1.flagString)(args, 'db', 'data/corpus.sqlite');
84
+ if (!node_fs_1.default.existsSync(dbPath)) {
85
+ process.stderr.write(`no corpus database at ${dbPath}\n`);
86
+ return 2;
87
+ }
88
+ const model = (0, args_1.flagString)(args, 'model', 'gpt-5.6-sol');
89
+ const useHistory = (0, args_1.flagBool)(args, 'history', false);
90
+ const groupBy = (0, args_1.flagString)(args, 'group-by', 'client');
91
+ const limit = (0, args_1.flagNumber)(args, 'limit', 0);
92
+ const store = new store_1.CorpusStore(dbPath);
93
+ const root = store.queryOne('SELECT root FROM runs ORDER BY id DESC LIMIT 1')?.root;
94
+ if (!root) {
95
+ process.stderr.write('no completed scan run found\n');
96
+ store.close();
97
+ return 2;
98
+ }
99
+ // Latest annotation per (path, block) for the chosen model, so re-annotated messages do not
100
+ // count twice.
101
+ const reference = store.query(`SELECT a.path, a.block_index, a.label, a.char_count, m.client, m.lang, m.reply_style
102
+ FROM annotations a
103
+ JOIN annotation_runs r ON r.id = a.run_id
104
+ JOIN messages m ON m.path = a.path
105
+ WHERE r.model = ? AND a.source = 'llm'
106
+ AND a.id = (SELECT MAX(a2.id) FROM annotations a2
107
+ JOIN annotation_runs r2 ON r2.id = a2.run_id
108
+ WHERE a2.path = a.path AND a2.block_index = a.block_index AND r2.model = r.model)
109
+ ORDER BY a.path, a.block_index`, model);
110
+ if (!reference.length) {
111
+ process.stderr.write(`no annotations found for model ${model}. Run "annotate" first.\n`);
112
+ store.close();
113
+ return 2;
114
+ }
115
+ const byPath = new Map();
116
+ for (const row of reference) {
117
+ const list = byPath.get(row.path);
118
+ if (list) {
119
+ list.push(row);
120
+ }
121
+ else {
122
+ byPath.set(row.path, [row]);
123
+ }
124
+ }
125
+ const paths = [...byPath.keys()].slice(0, limit || undefined);
126
+ const resolver = useHistory ? (0, thread_index_1.corpusThreadResolver)(store, root) : null;
127
+ process.stderr.write(`evaluating ${paths.length} messages against ${model}${useHistory ? ', with thread history' : ''}\n`);
128
+ const rows = [];
129
+ let failures = 0;
130
+ let withHistory = 0;
131
+ for (const relPath of paths) {
132
+ const references = byPath.get(relPath);
133
+ let raw;
134
+ try {
135
+ raw = node_fs_1.default.readFileSync(node_path_1.default.join(root, relPath));
136
+ }
137
+ catch {
138
+ failures++;
139
+ continue;
140
+ }
141
+ let historyDocuments;
142
+ if (resolver) {
143
+ try {
144
+ const message = await (0, parse_1.parseMessage)(raw);
145
+ historyDocuments = await resolver.resolve(message.headers);
146
+ if (historyDocuments.length) {
147
+ withHistory++;
148
+ }
149
+ }
150
+ catch {
151
+ historyDocuments = undefined;
152
+ }
153
+ }
154
+ let result;
155
+ try {
156
+ result = await (0, index_1.extract)(raw, historyDocuments ? { historyDocuments } : {});
157
+ }
158
+ catch {
159
+ failures++;
160
+ continue;
161
+ }
162
+ // Map every reference block to the prediction covering it. Segments merge adjacent blocks,
163
+ // so a block is matched by its index falling inside a segment's block range.
164
+ const predictions = new Map();
165
+ for (const segment of [...result.segments, ...result.hiddenSegments]) {
166
+ predictions.set(segment.source.blockIndex, { label: segment.type, hidden: segment.visibility === 'hide' });
167
+ }
168
+ // Segments start at a block index and run to the next one, so fill forward.
169
+ const ordered = [...predictions.keys()].sort((a, b) => a - b);
170
+ const lookup = (index) => {
171
+ let best = null;
172
+ for (const start of ordered) {
173
+ if (start <= index) {
174
+ best = start;
175
+ }
176
+ else {
177
+ break;
178
+ }
179
+ }
180
+ return best === null ? null : (predictions.get(best) ?? null);
181
+ };
182
+ const first = references[0];
183
+ const group = groupBy === 'lang' ? (first?.lang ?? 'unknown') : groupBy === 'reply-style' ? (first?.reply_style ?? 'unknown') : (first?.client ?? 'unknown');
184
+ for (const item of references) {
185
+ const prediction = lookup(item.block_index);
186
+ rows.push({
187
+ path: relPath,
188
+ blockIndex: item.block_index,
189
+ charCount: item.char_count,
190
+ reference: item.label,
191
+ // A block with no covering segment was dropped as empty, which is equivalent to
192
+ // being shown as nothing. Treat it as UNKNOWN and visible rather than silently
193
+ // excluding it from the score.
194
+ predicted: prediction?.label ?? 'UNKNOWN',
195
+ hidden: prediction?.hidden ?? false,
196
+ group
197
+ });
198
+ }
199
+ }
200
+ store.close();
201
+ if (failures) {
202
+ process.stderr.write(`${failures} message(s) could not be evaluated\n`);
203
+ }
204
+ if (resolver) {
205
+ process.stderr.write(`thread history available for ${withHistory} of ${paths.length} messages\n`);
206
+ }
207
+ const report = (0, metrics_1.evaluate)(rows);
208
+ if ((0, args_1.flagBool)(args, 'json', false)) {
209
+ process.stdout.write(`${JSON.stringify({ ...report, confusion: Object.fromEntries(report.confusion) }, null, 2)}\n`);
210
+ return 0;
211
+ }
212
+ process.stdout.write(`${renderReport(report, `EVALUATION vs ${model}${useHistory ? ' (with history)' : ' (no history)'}`)}\n`);
213
+ return 0;
214
+ }
215
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/cli/evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `email-content extract` subcommand.
3
+ *
4
+ * Human readable output shows the classification, the confidence and the reasons, so that a
5
+ * surprising decision can be understood without a debugger. Message content is printed here, which
6
+ * is fine and necessary: the operator asked for this specific message.
7
+ */
8
+ import { type ParsedArgs } from './args';
9
+ export declare function extractCommand(args: ParsedArgs): Promise<number>;
10
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/cli/extract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAA4C,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAqBnF,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiFtE"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * `email-content extract` subcommand.
4
+ *
5
+ * Human readable output shows the classification, the confidence and the reasons, so that a
6
+ * surprising decision can be understood without a debugger. Message content is printed here, which
7
+ * is fine and necessary: the operator asked for this specific message.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.extractCommand = extractCommand;
47
+ const node_fs_1 = __importDefault(require("node:fs"));
48
+ const index_1 = require("../index");
49
+ const args_1 = require("./args");
50
+ const LABEL_WIDTH = 18;
51
+ function truncate(text, limit) {
52
+ const collapsed = text.replace(/\s+/g, ' ').trim();
53
+ return collapsed.length > limit ? `${collapsed.slice(0, limit - 1)}…` : collapsed;
54
+ }
55
+ function renderSegment(segment, index, full) {
56
+ const head = `${String(index).padStart(2)}. ${segment.type.padEnd(LABEL_WIDTH)} ${segment.confidence.toFixed(2)} ${segment.visibility.padEnd(8)} part ${segment.source.mimePart} [${segment.source.start}..${segment.source.end}]`;
57
+ const reasons = ` reasons: ${segment.reasons.join(', ') || 'none'}`;
58
+ const body = full
59
+ ? segment.text
60
+ .split('\n')
61
+ .map(line => ` | ${line}`)
62
+ .join('\n')
63
+ : ` | ${truncate(segment.text, 100)}`;
64
+ return `${head}\n${reasons}\n${body}`;
65
+ }
66
+ async function extractCommand(args) {
67
+ const file = args.positional[0];
68
+ if (!file) {
69
+ process.stderr.write('usage: email-content extract <message.eml> [--json] [--explain] [--full]\n');
70
+ return 2;
71
+ }
72
+ if (!node_fs_1.default.existsSync(file)) {
73
+ process.stderr.write(`file not found: ${file}\n`);
74
+ return 2;
75
+ }
76
+ const explain = (0, args_1.flagBool)(args, 'explain', false);
77
+ const raw = node_fs_1.default.readFileSync(file);
78
+ // Stage 5 evidence, when the caller can point at earlier messages. Either a corpus database,
79
+ // which resolves the thread by Message-ID, or a folder of .eml files to index.
80
+ let historyDocuments = [];
81
+ const historySource = (0, args_1.flagOptionalString)(args, 'history');
82
+ if (historySource) {
83
+ const { parseMessage } = await Promise.resolve().then(() => __importStar(require('../mime/parse')));
84
+ const message = await parseMessage(raw);
85
+ const isDatabase = /\.sqlite$/i.test(historySource);
86
+ if (isDatabase) {
87
+ const { CorpusStore } = await Promise.resolve().then(() => __importStar(require('../corpus/store')));
88
+ const { corpusThreadResolver } = await Promise.resolve().then(() => __importStar(require('../corpus/thread-index')));
89
+ const store = new CorpusStore(historySource);
90
+ const root = store.queryOne('SELECT root FROM runs ORDER BY id DESC LIMIT 1')?.root;
91
+ if (root) {
92
+ historyDocuments = await corpusThreadResolver(store, root).resolve(message.headers);
93
+ }
94
+ store.close();
95
+ }
96
+ else {
97
+ const { folderThreadResolver } = await Promise.resolve().then(() => __importStar(require('../corpus/thread-index')));
98
+ historyDocuments = await folderThreadResolver(historySource).resolve(message.headers);
99
+ }
100
+ process.stderr.write(`history: resolved ${historyDocuments.length} earlier message(s)\n`);
101
+ }
102
+ const result = await (0, index_1.extract)(raw, {
103
+ explain,
104
+ historyDocuments,
105
+ parse: { maxTextPartBytes: (0, args_1.flagNumber)(args, 'max-text-kb', 1024) * 1024 }
106
+ });
107
+ if ((0, args_1.flagBool)(args, 'json', false)) {
108
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
109
+ return 0;
110
+ }
111
+ const full = (0, args_1.flagBool)(args, 'full', false);
112
+ const out = [];
113
+ out.push(`primary representation: ${result.primaryRepresentation}`);
114
+ out.push(`overall confidence: ${result.overallConfidence.toFixed(3)}`);
115
+ out.push(`history used: ${result.historyUsed}`);
116
+ if (result.warnings.length) {
117
+ out.push(`warnings: ${result.warnings.map(warning => warning.code).join(', ')}`);
118
+ }
119
+ out.push('');
120
+ out.push(`VISIBLE (${result.segments.length})`);
121
+ result.segments.forEach((segment, index) => out.push(renderSegment(segment, index, full)));
122
+ if (result.hiddenSegments.length) {
123
+ out.push('', `HIDDEN (${result.hiddenSegments.length}, retained and recoverable)`);
124
+ result.hiddenSegments.forEach((segment, index) => out.push(renderSegment(segment, index, full)));
125
+ }
126
+ if (explain && result.diagnostics) {
127
+ out.push('', `DIAGNOSTICS structure=${result.diagnostics.structure} part=${result.diagnostics.primaryPart}`);
128
+ for (const block of result.diagnostics.blocks) {
129
+ const evidence = block.evidence.map(item => `${item.id}@${item.strength}`).join(' ') || 'none';
130
+ out.push(` #${String(block.index).padStart(2)} ${block.kind.padEnd(20)} -> ${block.label.padEnd(LABEL_WIDTH)} ${block.confidence.toFixed(2)}`);
131
+ out.push(` evidence: ${evidence}`);
132
+ out.push(` reasons: ${block.reasons.join(', ')}`);
133
+ out.push(` text: ${truncate(block.preview, 100)}`);
134
+ }
135
+ }
136
+ process.stdout.write(`${out.join('\n')}\n`);
137
+ return 0;
138
+ }
139
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/cli/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * email-content command line entry point.
4
+ *
5
+ * Commands are dispatched lazily so that, for example, `extract` does not pay for loading the
6
+ * corpus database layer.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * email-content command line entry point.
5
+ *
6
+ * Commands are dispatched lazily so that, for example, `extract` does not pay for loading the
7
+ * corpus database layer.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ const types_1 = require("../types");
44
+ const args_1 = require("./args");
45
+ const USAGE = `email-content <command> [options]
46
+
47
+ Commands:
48
+ corpus scan <folder> Scan a folder of .eml files into the corpus database
49
+ --db <path> Database path (default data/corpus.sqlite)
50
+ --sample <n> Deterministic sample of n files instead of the whole corpus
51
+ --seed <string> Sampling seed (default "default")
52
+ --concurrency <n> Worker threads (default: cores minus two)
53
+ --no-resume Re-process files already recorded
54
+ --max-file-mb <n> Skip files larger than this (default 32)
55
+ --timeout <ms> Per file timeout (default 30000)
56
+
57
+ corpus stats Print aggregate statistics
58
+ --db <path> Database path
59
+ --json Emit JSON instead of Markdown
60
+ --out <path> Write the Markdown report to a file
61
+
62
+ corpus threads Summarise in-corpus thread parent resolution
63
+
64
+ extract <message.eml> Classify one message into segments
65
+ --json Emit the full structured result
66
+ --explain Show per block evidence, features and reasons
67
+ --full Print complete segment text instead of a preview
68
+ --history <path> Corpus .sqlite or folder of .eml files, to resolve thread history
69
+
70
+ benchmark Measure throughput and catastrophic error rates
71
+ --db <path> Corpus database
72
+ --sample <n> Messages to run (default 2000)
73
+ --traffic <class> human, ticketing, mailing-list, bulk, all (default human)
74
+ --replies false Include non replies
75
+
76
+ annotate Label blocks with an LLM instead of a human (sends content to OpenAI)
77
+ --model <id> Model id (default gpt-5.6-sol)
78
+ --sample <n> Messages to annotate (default 25)
79
+ --concurrency <n> Parallel requests (default 4)
80
+ --traffic <class> Traffic class to sample from (default human)
81
+ --seed <string> Deterministic selection seed
82
+ --dry-run Count blocks and cost without calling the API
83
+ --no-resume Re-annotate messages already done by this model
84
+
85
+ disagreements Review blocks where annotator and baseline disagree (prints content)
86
+ --direction <d> expensive, cheap, footers, all (default expensive)
87
+ --limit <n> Rows to show (default 20)
88
+ --run <id> Restrict to one annotation run
89
+
90
+ evaluate Score the extractor against an annotated reference set
91
+ --model <id> Reference annotations from this model (default gpt-5.6-sol)
92
+ --history Resolve thread history from the corpus while evaluating
93
+ --group-by <field> client, lang or reply-style (default client)
94
+ --json Emit the full report as JSON
95
+
96
+ version Print version information
97
+
98
+ Privacy: no command prints message bodies, subjects or addresses.
99
+ `;
100
+ async function main(argv) {
101
+ const args = (0, args_1.parseArgs)(argv);
102
+ const command = args.positional[0];
103
+ switch (command) {
104
+ case 'corpus': {
105
+ const { corpusCommand } = await Promise.resolve().then(() => __importStar(require('./corpus')));
106
+ return corpusCommand(args.positional[1], { ...args, positional: args.positional.slice(2) });
107
+ }
108
+ case 'extract': {
109
+ const { extractCommand } = await Promise.resolve().then(() => __importStar(require('./extract')));
110
+ return extractCommand({ ...args, positional: args.positional.slice(1) });
111
+ }
112
+ case 'benchmark': {
113
+ const { benchmarkCommand } = await Promise.resolve().then(() => __importStar(require('./benchmark')));
114
+ return benchmarkCommand({ ...args, positional: args.positional.slice(1) });
115
+ }
116
+ case 'annotate': {
117
+ const { annotateCommand } = await Promise.resolve().then(() => __importStar(require('./annotate')));
118
+ return annotateCommand({ ...args, positional: args.positional.slice(1) });
119
+ }
120
+ case 'disagreements': {
121
+ const { disagreementsCommand } = await Promise.resolve().then(() => __importStar(require('./disagreements')));
122
+ return disagreementsCommand({ ...args, positional: args.positional.slice(1) });
123
+ }
124
+ case 'evaluate': {
125
+ const { evaluateCommand } = await Promise.resolve().then(() => __importStar(require('./evaluate')));
126
+ return evaluateCommand({ ...args, positional: args.positional.slice(1) });
127
+ }
128
+ case 'version':
129
+ process.stdout.write(`extractor ${types_1.EXTRACTOR_VERSION}, processing ${types_1.PROCESSING_VERSION}, node ${process.version}\n`);
130
+ return 0;
131
+ case 'help':
132
+ case undefined:
133
+ process.stdout.write(USAGE);
134
+ return command === undefined ? 2 : 0;
135
+ default:
136
+ process.stderr.write(`unknown command: ${command}\n\n${USAGE}`);
137
+ return 2;
138
+ }
139
+ }
140
+ main(process.argv.slice(2)).then(code => {
141
+ process.exitCode = code;
142
+ }, (err) => {
143
+ const message = err instanceof Error ? err.message : String(err);
144
+ process.stderr.write(`error: ${message}\n`);
145
+ process.exitCode = 1;
146
+ });
147
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Corpus feature extraction.
3
+ *
4
+ * Turns a parsed message into the flat, privacy safe record stored in the corpus database. The hard
5
+ * rule here is that nothing derived from body text, subjects or addresses may leave this function
6
+ * in readable form. Subjects and addresses become salted hashes, sender domains are kept because
7
+ * they are needed for stratification, and body text is reduced to counts, ratios and a SimHash.
8
+ */
9
+ import { type ReplyStyle } from '../canonical/text';
10
+ import { type ClientId } from '../detect/client';
11
+ import { type TrafficClass } from '../detect/traffic';
12
+ import { type ParsedMessage } from '../mime/model';
13
+ import { type LanguageCode } from '../util/lang';
14
+ export type BodyKind = 'both' | 'plain-only' | 'html-only' | 'none';
15
+ export interface MessageRecord {
16
+ messageId: string | null;
17
+ inReplyTo: string | null;
18
+ referencesCount: number;
19
+ referencesRoot: string | null;
20
+ dateMs: number | null;
21
+ fromDomain: string | null;
22
+ fromHash: string | null;
23
+ subjectHash: string | null;
24
+ subjectPrefix: 'reply' | 'forward' | 'plain' | 'none';
25
+ subjectLength: number;
26
+ structure: string;
27
+ bodyKind: BodyKind;
28
+ charsets: string;
29
+ encodings: string;
30
+ partCount: number;
31
+ attachmentCount: number;
32
+ hasRfc822: boolean;
33
+ textChars: number;
34
+ htmlChars: number;
35
+ flowed: boolean;
36
+ client: ClientId;
37
+ clientSource: string;
38
+ traffic: TrafficClass;
39
+ trafficSignals: string;
40
+ isReply: boolean;
41
+ isForward: boolean;
42
+ quoteDepthMax: number;
43
+ quotedRatio: number;
44
+ replyStyle: ReplyStyle | 'unknown';
45
+ /** Detector ids that fired, comma separated. Ids only, never matched text. */
46
+ markers: string;
47
+ htmlHints: string;
48
+ blockquoteCount: number;
49
+ tableCount: number;
50
+ hasImage: boolean;
51
+ suspectMalformedHtml: boolean;
52
+ lang: LanguageCode;
53
+ langScore: number;
54
+ bodySimhash: string;
55
+ warnings: string;
56
+ /** True when plain and HTML disagree about whether the message contains quoted history. */
57
+ quoteMarkingDisagrees: boolean;
58
+ }
59
+ /**
60
+ * Build the corpus record for one parsed message.
61
+ *
62
+ * @param message parsed MIME structure
63
+ * @param salt per database salt for the privacy preserving hashes
64
+ */
65
+ export declare function analyzeMessage(message: ParsedMessage, salt: string): MessageRecord;
66
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/corpus/analyze.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,MAAM,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,QAAQ,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,qBAAqB,EAAE,OAAO,CAAC;CAClC;AAoHD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CA6FlF"}