@skillrecordings/cli 0.10.2 → 0.11.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.
package/bin/skill.mjs CHANGED
@@ -1,8 +1,3 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- // Load secrets via 1Password/age encryption before importing CLI
4
- // This sets DATABASE_URL and other env vars from encrypted .env.encrypted
5
- await import('../dist/preload.js')
6
-
7
- // Now import the main CLI with secrets available
8
3
  await import('../dist/index.js')
package/bin/skill.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env bun
2
- import '../preload'
3
2
  import '../src/index'
@@ -0,0 +1,198 @@
1
+ import {
2
+ init_esm_shims
3
+ } from "./chunk-WFANXVQG.js";
4
+
5
+ // ../core/src/faq/filters.ts
6
+ init_esm_shims();
7
+ var NOISE_SENDER_DOMAINS = [
8
+ // Transcription services
9
+ "castingwords.com",
10
+ // Email/Marketing services
11
+ "postmarkapp.com",
12
+ "convertkit.com",
13
+ "kit.com",
14
+ "kit-mail6.com",
15
+ "convertkit-mail4.com",
16
+ "mailgun.org",
17
+ "sendgrid.net",
18
+ // Cloud services
19
+ "algolia.com",
20
+ "cloudinary.com",
21
+ "mux.com",
22
+ "aws.amazon.com",
23
+ "amazonaws.com",
24
+ "vercel.com",
25
+ // Google services
26
+ "google.com",
27
+ "google.co.uk",
28
+ "googlemail.com",
29
+ // Payment/Billing
30
+ "stripe.com",
31
+ "paddle.com",
32
+ // Training/Enterprise platforms
33
+ "placedelaformation.com",
34
+ "allwyn-lotterysolutions.com",
35
+ "atlassian.net",
36
+ // Email routing/filtering
37
+ "mixmax.com",
38
+ // Security/DMARC
39
+ "dmarc.postmarkapp.com",
40
+ "postmarkdmarc.com",
41
+ "activecampaign.com"
42
+ ];
43
+ var AUTO_REPLY_PATTERNS = [
44
+ // Chinese auto-replies
45
+ /这是.*自动回复/,
46
+ /[你您]好.*我已收到您的邮件/,
47
+ /我已收到您的邮件/,
48
+ /您的邮件我已经收到/,
49
+ /我最近正在休假中/,
50
+ // English auto-replies
51
+ /vacation.*auto.*reply/i,
52
+ /out of office/i,
53
+ /automatic reply/i,
54
+ /auto-reply/i,
55
+ // Calendar notifications
56
+ /has accepted this invitation/i,
57
+ /has declined this invitation/i,
58
+ /invitation from google calendar/i,
59
+ // Email routing tools
60
+ /uses Mixmax to route/i,
61
+ /keeping their inbox clear/i,
62
+ // Service desk auto-responses
63
+ /just confirming that we got your request/i,
64
+ /reply above this line/i,
65
+ // Unsubscribe confirmations
66
+ /you have been unsubscribed/i,
67
+ /successfully unsubscribed/i
68
+ ];
69
+ var SPAM_PATTERNS = [
70
+ // Influencer outreach (Head AI)
71
+ /reaching out from Head/i,
72
+ /AI-powered influencer/i,
73
+ /Partnerships at Head Creator/i,
74
+ // Generic cold outreach - broad patterns
75
+ /collaboration/i,
76
+ // Catches: collab, collaboration, collaborations, etc.
77
+ /partnership/i,
78
+ // Catches: partner, partnership, partnerships, etc.
79
+ /sponsored/i,
80
+ // Sponsored content requests
81
+ /affiliate/i,
82
+ // Affiliate program requests
83
+ // Generic cold outreach - specific patterns
84
+ /I hope this email finds you well.*My name is/i,
85
+ /I'd like to discuss/i,
86
+ /brand collab/i,
87
+ /creator partnership/i,
88
+ // SEO spam
89
+ /increase your organic traffic/i,
90
+ /boost your SEO/i,
91
+ /backlink opportunity/i
92
+ ];
93
+ var LESSON_COMMENT_PATTERN = /^.*writes:[\s\S]*---\s*lesson:/i;
94
+ var SERVICE_NOTIFICATION_PATTERNS = [
95
+ // Transcription services
96
+ /We've just finished your transcription/i,
97
+ /We just finished up transcribing order/i,
98
+ // DMARC/Email reports
99
+ /emails were sent using.*between/i,
100
+ /DMARC Compliance/i,
101
+ /DMARC aligned/i,
102
+ /dmarc.postmarkapp.com/i,
103
+ // Usage reports
104
+ /Weekly report.*Plan usage/i,
105
+ /Usage Report/i,
106
+ /monthly invoice is available/i,
107
+ // Payment notifications
108
+ /Your payment was successful/i,
109
+ /We received your payment/i,
110
+ // Security notifications
111
+ /new sign-in.*device/i,
112
+ /unrecognized device/i,
113
+ /We found some security gaps/i,
114
+ // Google Workspace
115
+ /Google Workspace.*invoice/i,
116
+ /Google Analytics.*tips/i,
117
+ /Dear Administrator/i
118
+ ];
119
+ function isNoiseSenderDomain(email) {
120
+ const domain = email.split("@")[1]?.toLowerCase() ?? "";
121
+ return NOISE_SENDER_DOMAINS.some(
122
+ (noiseDomain) => domain === noiseDomain || domain.endsWith(`.${noiseDomain}`)
123
+ );
124
+ }
125
+ function isAutoReply(text) {
126
+ return AUTO_REPLY_PATTERNS.some((pattern) => pattern.test(text));
127
+ }
128
+ function isSpam(text) {
129
+ return SPAM_PATTERNS.some((pattern) => pattern.test(text));
130
+ }
131
+ function isLessonComment(text) {
132
+ return LESSON_COMMENT_PATTERN.test(text);
133
+ }
134
+ function isServiceNotification(text) {
135
+ return SERVICE_NOTIFICATION_PATTERNS.some((pattern) => pattern.test(text));
136
+ }
137
+ function shouldFilter(text, senderEmail) {
138
+ if (senderEmail && isNoiseSenderDomain(senderEmail)) {
139
+ return { filtered: true, reason: "sender_domain" };
140
+ }
141
+ if (isLessonComment(text)) {
142
+ return { filtered: true, reason: "lesson_comment" };
143
+ }
144
+ if (isAutoReply(text)) {
145
+ return { filtered: true, reason: "auto_reply" };
146
+ }
147
+ if (isSpam(text)) {
148
+ return { filtered: true, reason: "spam" };
149
+ }
150
+ if (isServiceNotification(text)) {
151
+ return { filtered: true, reason: "service_notification" };
152
+ }
153
+ return { filtered: false };
154
+ }
155
+ function createFilterStats() {
156
+ return {
157
+ total: 0,
158
+ filtered: 0,
159
+ passed: 0,
160
+ byReason: {}
161
+ };
162
+ }
163
+ function updateFilterStats(stats, result) {
164
+ stats.total++;
165
+ if (result.filtered) {
166
+ stats.filtered++;
167
+ if (result.reason) {
168
+ stats.byReason[result.reason] = (stats.byReason[result.reason] ?? 0) + 1;
169
+ }
170
+ } else {
171
+ stats.passed++;
172
+ }
173
+ }
174
+ function formatFilterStats(stats) {
175
+ const lines = [
176
+ `\u{1F4CA} Filter Statistics:`,
177
+ ` Total processed: ${stats.total}`,
178
+ ` Filtered out: ${stats.filtered} (${(stats.filtered / stats.total * 100).toFixed(1)}%)`,
179
+ ` Passed: ${stats.passed} (${(stats.passed / stats.total * 100).toFixed(1)}%)`
180
+ ];
181
+ if (Object.keys(stats.byReason).length > 0) {
182
+ lines.push(` By reason:`);
183
+ for (const [reason, count] of Object.entries(stats.byReason).sort(
184
+ (a, b) => b[1] - a[1]
185
+ )) {
186
+ lines.push(` - ${reason}: ${count}`);
187
+ }
188
+ }
189
+ return lines.join("\n");
190
+ }
191
+
192
+ export {
193
+ shouldFilter,
194
+ createFilterStats,
195
+ updateFilterStats,
196
+ formatFilterStats
197
+ };
198
+ //# sourceMappingURL=chunk-5ACOI6Z3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/src/faq/filters.ts"],"sourcesContent":["/**\n * FAQ Preprocessing Filters\n *\n * Filters to remove noise before clustering. These patterns were identified\n * by auditing Phase 0 cluster quality (see docs/cluster-quality-diagnosis.md).\n *\n * Issue: #110\n *\n * @module faq/filters\n */\n\n/**\n * Sender domains that should be filtered out before clustering.\n * These are service providers, not customer support requests.\n */\nexport const NOISE_SENDER_DOMAINS = [\n // Transcription services\n 'castingwords.com',\n\n // Email/Marketing services\n 'postmarkapp.com',\n 'convertkit.com',\n 'kit.com',\n 'kit-mail6.com',\n 'convertkit-mail4.com',\n 'mailgun.org',\n 'sendgrid.net',\n\n // Cloud services\n 'algolia.com',\n 'cloudinary.com',\n 'mux.com',\n 'aws.amazon.com',\n 'amazonaws.com',\n 'vercel.com',\n\n // Google services\n 'google.com',\n 'google.co.uk',\n 'googlemail.com',\n\n // Payment/Billing\n 'stripe.com',\n 'paddle.com',\n\n // Training/Enterprise platforms\n 'placedelaformation.com',\n 'allwyn-lotterysolutions.com',\n 'atlassian.net',\n\n // Email routing/filtering\n 'mixmax.com',\n\n // Security/DMARC\n 'dmarc.postmarkapp.com',\n 'postmarkdmarc.com',\n 'activecampaign.com',\n] as const\n\n/**\n * Auto-reply patterns that indicate noise, not real support requests.\n */\nexport const AUTO_REPLY_PATTERNS = [\n // Chinese auto-replies\n /这是.*自动回复/,\n /[你您]好.*我已收到您的邮件/,\n /我已收到您的邮件/,\n /您的邮件我已经收到/,\n /我最近正在休假中/,\n\n // English auto-replies\n /vacation.*auto.*reply/i,\n /out of office/i,\n /automatic reply/i,\n /auto-reply/i,\n\n // Calendar notifications\n /has accepted this invitation/i,\n /has declined this invitation/i,\n /invitation from google calendar/i,\n\n // Email routing tools\n /uses Mixmax to route/i,\n /keeping their inbox clear/i,\n\n // Service desk auto-responses\n /just confirming that we got your request/i,\n /reply above this line/i,\n\n // Unsubscribe confirmations\n /you have been unsubscribed/i,\n /successfully unsubscribed/i,\n] as const\n\n/**\n * Spam/outreach patterns - cold emails to support addresses\n */\nexport const SPAM_PATTERNS = [\n // Influencer outreach (Head AI)\n /reaching out from Head/i,\n /AI-powered influencer/i,\n /Partnerships at Head Creator/i,\n\n // Generic cold outreach - broad patterns\n /collaboration/i, // Catches: collab, collaboration, collaborations, etc.\n /partnership/i, // Catches: partner, partnership, partnerships, etc.\n /sponsored/i, // Sponsored content requests\n /affiliate/i, // Affiliate program requests\n\n // Generic cold outreach - specific patterns\n /I hope this email finds you well.*My name is/i,\n /I'd like to discuss/i,\n /brand collab/i,\n /creator partnership/i,\n\n // SEO spam\n /increase your organic traffic/i,\n /boost your SEO/i,\n /backlink opportunity/i,\n] as const\n\n/**\n * Lesson comment pattern - these are egghead lesson comments, not support\n */\nexport const LESSON_COMMENT_PATTERN = /^.*writes:[\\s\\S]*---\\s*lesson:/i\n\n/**\n * Service notification patterns - automated emails from service providers\n */\nexport const SERVICE_NOTIFICATION_PATTERNS = [\n // Transcription services\n /We've just finished your transcription/i,\n /We just finished up transcribing order/i,\n\n // DMARC/Email reports\n /emails were sent using.*between/i,\n /DMARC Compliance/i,\n /DMARC aligned/i,\n /dmarc.postmarkapp.com/i,\n\n // Usage reports\n /Weekly report.*Plan usage/i,\n /Usage Report/i,\n /monthly invoice is available/i,\n\n // Payment notifications\n /Your payment was successful/i,\n /We received your payment/i,\n\n // Security notifications\n /new sign-in.*device/i,\n /unrecognized device/i,\n /We found some security gaps/i,\n\n // Google Workspace\n /Google Workspace.*invoice/i,\n /Google Analytics.*tips/i,\n /Dear Administrator/i,\n] as const\n\n/**\n * Marketing reply indicators - replies to outbound marketing emails\n */\nexport const MARKETING_REPLY_PATTERNS = [\n // Price objection replies (from TotalTypeScript campaigns)\n /What's holding you back from buying/i,\n /Total TypeScript Core Volume Pre-Release/i,\n /workshop.*discount.*limited time/i,\n] as const\n\n/**\n * Check if a message should be filtered based on sender domain.\n */\nexport function isNoiseSenderDomain(email: string): boolean {\n const domain = email.split('@')[1]?.toLowerCase() ?? ''\n return NOISE_SENDER_DOMAINS.some(\n (noiseDomain) =>\n domain === noiseDomain || domain.endsWith(`.${noiseDomain}`)\n )\n}\n\n/**\n * Check if a message matches any auto-reply pattern.\n */\nexport function isAutoReply(text: string): boolean {\n return AUTO_REPLY_PATTERNS.some((pattern) => pattern.test(text))\n}\n\n/**\n * Check if a message matches any spam/outreach pattern.\n */\nexport function isSpam(text: string): boolean {\n return SPAM_PATTERNS.some((pattern) => pattern.test(text))\n}\n\n/**\n * Check if a message is an egghead lesson comment.\n */\nexport function isLessonComment(text: string): boolean {\n return LESSON_COMMENT_PATTERN.test(text)\n}\n\n/**\n * Check if a message is a service notification.\n */\nexport function isServiceNotification(text: string): boolean {\n return SERVICE_NOTIFICATION_PATTERNS.some((pattern) => pattern.test(text))\n}\n\n/**\n * Check if a message is a reply to a marketing email.\n * These are detected by checking if the quoted/forwarded content matches marketing patterns.\n */\nexport function isMarketingReply(text: string): boolean {\n return MARKETING_REPLY_PATTERNS.some((pattern) => pattern.test(text))\n}\n\n/**\n * Filter result with reason for transparency/debugging.\n */\nexport interface FilterResult {\n /** Whether the message should be filtered */\n filtered: boolean\n /** Reason for filtering (if filtered) */\n reason?:\n | 'sender_domain'\n | 'auto_reply'\n | 'spam'\n | 'lesson_comment'\n | 'service_notification'\n | 'marketing_reply'\n}\n\n/**\n * Check if a message should be filtered before clustering.\n *\n * @param text - Message text\n * @param senderEmail - Sender email address\n * @returns FilterResult with filtered status and reason\n */\nexport function shouldFilter(text: string, senderEmail?: string): FilterResult {\n // Check sender domain first (cheapest check)\n if (senderEmail && isNoiseSenderDomain(senderEmail)) {\n return { filtered: true, reason: 'sender_domain' }\n }\n\n // Check lesson comment pattern\n if (isLessonComment(text)) {\n return { filtered: true, reason: 'lesson_comment' }\n }\n\n // Check auto-reply patterns\n if (isAutoReply(text)) {\n return { filtered: true, reason: 'auto_reply' }\n }\n\n // Check spam patterns\n if (isSpam(text)) {\n return { filtered: true, reason: 'spam' }\n }\n\n // Check service notification patterns\n if (isServiceNotification(text)) {\n return { filtered: true, reason: 'service_notification' }\n }\n\n // Don't filter marketing replies by default - they might still be useful\n // for understanding customer objections, just not for FAQ extraction\n // Uncomment to enable:\n // if (isMarketingReply(text)) {\n // return { filtered: true, reason: 'marketing_reply' }\n // }\n\n return { filtered: false }\n}\n\n/**\n * Filter statistics for logging/monitoring.\n */\nexport interface FilterStats {\n total: number\n filtered: number\n passed: number\n byReason: Record<string, number>\n}\n\n/**\n * Create empty filter stats.\n */\nexport function createFilterStats(): FilterStats {\n return {\n total: 0,\n filtered: 0,\n passed: 0,\n byReason: {},\n }\n}\n\n/**\n * Update filter stats with a result.\n */\nexport function updateFilterStats(\n stats: FilterStats,\n result: FilterResult\n): void {\n stats.total++\n if (result.filtered) {\n stats.filtered++\n if (result.reason) {\n stats.byReason[result.reason] = (stats.byReason[result.reason] ?? 0) + 1\n }\n } else {\n stats.passed++\n }\n}\n\n/**\n * Format filter stats for display.\n */\nexport function formatFilterStats(stats: FilterStats): string {\n const lines = [\n `📊 Filter Statistics:`,\n ` Total processed: ${stats.total}`,\n ` Filtered out: ${stats.filtered} (${((stats.filtered / stats.total) * 100).toFixed(1)}%)`,\n ` Passed: ${stats.passed} (${((stats.passed / stats.total) * 100).toFixed(1)}%)`,\n ]\n\n if (Object.keys(stats.byReason).length > 0) {\n lines.push(` By reason:`)\n for (const [reason, count] of Object.entries(stats.byReason).sort(\n (a, b) => b[1] - a[1]\n )) {\n lines.push(` - ${reason}: ${count}`)\n }\n }\n\n return lines.join('\\n')\n}\n"],"mappings":";;;;;AAAA;AAeO,IAAM,uBAAuB;AAAA;AAAA,EAElC;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,sBAAsB;AAAA;AAAA,EAEjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AACF;AAKO,IAAM,gBAAgB;AAAA;AAAA,EAE3B;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,yBAAyB;AAK/B,IAAM,gCAAgC;AAAA;AAAA,EAE3C;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;AAeO,SAAS,oBAAoB,OAAwB;AAC1D,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AACrD,SAAO,qBAAqB;AAAA,IAC1B,CAAC,gBACC,WAAW,eAAe,OAAO,SAAS,IAAI,WAAW,EAAE;AAAA,EAC/D;AACF;AAKO,SAAS,YAAY,MAAuB;AACjD,SAAO,oBAAoB,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AACjE;AAKO,SAAS,OAAO,MAAuB;AAC5C,SAAO,cAAc,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AAC3D;AAKO,SAAS,gBAAgB,MAAuB;AACrD,SAAO,uBAAuB,KAAK,IAAI;AACzC;AAKO,SAAS,sBAAsB,MAAuB;AAC3D,SAAO,8BAA8B,KAAK,CAAC,YAAY,QAAQ,KAAK,IAAI,CAAC;AAC3E;AAiCO,SAAS,aAAa,MAAc,aAAoC;AAE7E,MAAI,eAAe,oBAAoB,WAAW,GAAG;AACnD,WAAO,EAAE,UAAU,MAAM,QAAQ,gBAAgB;AAAA,EACnD;AAGA,MAAI,gBAAgB,IAAI,GAAG;AACzB,WAAO,EAAE,UAAU,MAAM,QAAQ,iBAAiB;AAAA,EACpD;AAGA,MAAI,YAAY,IAAI,GAAG;AACrB,WAAO,EAAE,UAAU,MAAM,QAAQ,aAAa;AAAA,EAChD;AAGA,MAAI,OAAO,IAAI,GAAG;AAChB,WAAO,EAAE,UAAU,MAAM,QAAQ,OAAO;AAAA,EAC1C;AAGA,MAAI,sBAAsB,IAAI,GAAG;AAC/B,WAAO,EAAE,UAAU,MAAM,QAAQ,uBAAuB;AAAA,EAC1D;AASA,SAAO,EAAE,UAAU,MAAM;AAC3B;AAeO,SAAS,oBAAiC;AAC/C,SAAO;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU,CAAC;AAAA,EACb;AACF;AAKO,SAAS,kBACd,OACA,QACM;AACN,QAAM;AACN,MAAI,OAAO,UAAU;AACnB,UAAM;AACN,QAAI,OAAO,QAAQ;AACjB,YAAM,SAAS,OAAO,MAAM,KAAK,MAAM,SAAS,OAAO,MAAM,KAAK,KAAK;AAAA,IACzE;AAAA,EACF,OAAO;AACL,UAAM;AAAA,EACR;AACF;AAKO,SAAS,kBAAkB,OAA4B;AAC5D,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,uBAAuB,MAAM,KAAK;AAAA,IAClC,uBAAuB,MAAM,QAAQ,MAAO,MAAM,WAAW,MAAM,QAAS,KAAK,QAAQ,CAAC,CAAC;AAAA,IAC3F,uBAAuB,MAAM,MAAM,MAAO,MAAM,SAAS,MAAM,QAAS,KAAK,QAAQ,CAAC,CAAC;AAAA,EACzF;AAEA,MAAI,OAAO,KAAK,MAAM,QAAQ,EAAE,SAAS,GAAG;AAC1C,UAAM,KAAK,eAAe;AAC1B,eAAW,CAAC,QAAQ,KAAK,KAAK,OAAO,QAAQ,MAAM,QAAQ,EAAE;AAAA,MAC3D,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;AAAA,IACtB,GAAG;AACD,YAAM,KAAK,UAAU,MAAM,KAAK,KAAK,EAAE;AAAA,IACzC;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}