openclaw-github-trending 1.0.0

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +480 -0
  3. package/dist/channels/email.d.ts +61 -0
  4. package/dist/channels/email.d.ts.map +1 -0
  5. package/dist/channels/email.js +599 -0
  6. package/dist/channels/email.js.map +1 -0
  7. package/dist/channels/feishu.d.ts +50 -0
  8. package/dist/channels/feishu.d.ts.map +1 -0
  9. package/dist/channels/feishu.js +322 -0
  10. package/dist/channels/feishu.js.map +1 -0
  11. package/dist/channels/types.d.ts +66 -0
  12. package/dist/channels/types.d.ts.map +1 -0
  13. package/dist/channels/types.js +12 -0
  14. package/dist/channels/types.js.map +1 -0
  15. package/dist/cli.d.ts +2 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/core/config.d.ts +83 -0
  19. package/dist/core/config.d.ts.map +1 -0
  20. package/dist/core/config.js +145 -0
  21. package/dist/core/config.js.map +1 -0
  22. package/dist/core/fetcher.d.ts +43 -0
  23. package/dist/core/fetcher.d.ts.map +1 -0
  24. package/dist/core/fetcher.js +306 -0
  25. package/dist/core/fetcher.js.map +1 -0
  26. package/dist/core/file-storage.d.ts +62 -0
  27. package/dist/core/file-storage.d.ts.map +1 -0
  28. package/dist/core/file-storage.js +253 -0
  29. package/dist/core/file-storage.js.map +1 -0
  30. package/dist/core/history.d.ts +71 -0
  31. package/dist/core/history.d.ts.map +1 -0
  32. package/dist/core/history.js +133 -0
  33. package/dist/core/history.js.map +1 -0
  34. package/dist/core/summarizer.d.ts +64 -0
  35. package/dist/core/summarizer.d.ts.map +1 -0
  36. package/dist/core/summarizer.js +324 -0
  37. package/dist/core/summarizer.js.map +1 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +668 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/models/config.d.ts +93 -0
  43. package/dist/models/config.d.ts.map +1 -0
  44. package/dist/models/config.js +3 -0
  45. package/dist/models/config.js.map +1 -0
  46. package/dist/models/history.d.ts +6 -0
  47. package/dist/models/history.d.ts.map +1 -0
  48. package/dist/models/history.js +7 -0
  49. package/dist/models/history.js.map +1 -0
  50. package/dist/models/repository.d.ts +28 -0
  51. package/dist/models/repository.d.ts.map +1 -0
  52. package/dist/models/repository.js +3 -0
  53. package/dist/models/repository.js.map +1 -0
  54. package/dist/models/service.types.d.ts +87 -0
  55. package/dist/models/service.types.d.ts.map +1 -0
  56. package/dist/models/service.types.js +3 -0
  57. package/dist/models/service.types.js.map +1 -0
  58. package/dist/services/trending.service.d.ts +29 -0
  59. package/dist/services/trending.service.d.ts.map +1 -0
  60. package/dist/services/trending.service.js +306 -0
  61. package/dist/services/trending.service.js.map +1 -0
  62. package/dist/tool.d.ts +47 -0
  63. package/dist/tool.d.ts.map +1 -0
  64. package/dist/tool.js +314 -0
  65. package/dist/tool.js.map +1 -0
  66. package/dist/utils/logger.d.ts +77 -0
  67. package/dist/utils/logger.d.ts.map +1 -0
  68. package/dist/utils/logger.js +214 -0
  69. package/dist/utils/logger.js.map +1 -0
  70. package/dist/utils/markdown.d.ts +9 -0
  71. package/dist/utils/markdown.d.ts.map +1 -0
  72. package/dist/utils/markdown.js +40 -0
  73. package/dist/utils/markdown.js.map +1 -0
  74. package/openclaw.plugin.json +152 -0
  75. package/package.json +78 -0
@@ -0,0 +1,599 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.EmailChannel = void 0;
40
+ const markdown = __importStar(require("../utils/markdown"));
41
+ const nodemailer_1 = __importDefault(require("nodemailer"));
42
+ const logger_1 = require("../utils/logger");
43
+ const logger = logger_1.Logger.get('EmailChannel');
44
+ /**
45
+ * Email Channel for pushing GitHub trending repositories via email
46
+ */
47
+ class EmailChannel {
48
+ /**
49
+ * Create an email channel instance
50
+ * @param config Email configuration
51
+ */
52
+ constructor(config) {
53
+ this.config = config;
54
+ }
55
+ /**
56
+ * Generate HTML email content from repositories
57
+ * @param newRepositories Array of new repositories to display
58
+ * @param seenRepositories Array of seen repositories to display
59
+ * @param since Time period for trending (daily, weekly, monthly)
60
+ * @returns HTML string for the email
61
+ */
62
+ static generateHTML(newRepositories, seenRepositories, since = 'monthly') {
63
+ const currentDate = new Date();
64
+ const dateStr = currentDate.toLocaleDateString('zh-CN', {
65
+ year: 'numeric',
66
+ month: 'long',
67
+ day: 'numeric',
68
+ weekday: 'long'
69
+ });
70
+ // 根据 since 参数确定时间范围描述
71
+ const sinceTextMap = {
72
+ daily: '今日',
73
+ weekly: '本周',
74
+ monthly: '本月'
75
+ };
76
+ const sinceText = sinceTextMap[since];
77
+ const NEW_REPOS_TITLE = '新上榜项目';
78
+ const SEEN_REPOS_TITLE = '持续霸榜项目';
79
+ // Email styles using 靛蓝色系 (indigo/blue color scheme)
80
+ // 使用 CSS 变量提高可维护性
81
+ const styles = `
82
+ :root {
83
+ --primary-color: #4A6FA5;
84
+ --primary-light: #5B8CB3;
85
+ --text-dark: #333;
86
+ --text-medium: #666;
87
+ --text-light: #888;
88
+ --bg-light: #f5f7fa;
89
+ --bg-card: #f9fafb;
90
+ --border-color: #e1e4e8;
91
+ --ai-bg: #f0f4ff;
92
+ --ai-border: #4A6FA5;
93
+ --ai-title-color: #2c5282;
94
+ --new-section-bg: #fff5f5;
95
+ --seen-section-bg: #f0f9ff;
96
+ }
97
+
98
+ body {
99
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
100
+ background-color: var(--bg-light);
101
+ margin: 0;
102
+ padding: 0;
103
+ }
104
+
105
+ .container {
106
+ max-width: 800px;
107
+ margin: 20px auto;
108
+ padding: 0 20px;
109
+ background-color: #ffffff;
110
+ border-radius: 8px;
111
+ overflow: hidden;
112
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
113
+ }
114
+
115
+ .header {
116
+ background: linear-gradient(135deg, #4A6FA5 0%, #5B8CB3 100%);
117
+ color: white;
118
+ padding: 40px 40px;
119
+ text-align: center;
120
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
121
+ }
122
+
123
+ .header h1 {
124
+ margin: 0;
125
+ font-size: 32px;
126
+ font-weight: 700;
127
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
128
+ letter-spacing: 1px;
129
+ }
130
+
131
+ .header .date {
132
+ margin-top: 12px;
133
+ font-size: 15px;
134
+ opacity: 0.95;
135
+ font-weight: 500;
136
+ }
137
+
138
+ .content {
139
+ padding: 30px 40px;
140
+ }
141
+
142
+ .section {
143
+ margin-bottom: 30px;
144
+ padding: 0;
145
+ border-radius: 12px;
146
+ background-color: #ffffff;
147
+ border: 1px solid var(--border-color);
148
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
149
+ overflow: hidden;
150
+ }
151
+
152
+ .section-new {
153
+ border-top: 3px solid #e53e3e;
154
+ }
155
+
156
+ .section-seen {
157
+ border-top: 3px solid #3182ce;
158
+ }
159
+
160
+ .section-title {
161
+ font-size: 20px;
162
+ font-weight: 700;
163
+ padding: 20px 25px 15px;
164
+ margin: 0;
165
+ background-color: #fafafa;
166
+ border-bottom: 1px solid var(--border-color);
167
+ }
168
+
169
+ .section-new .section-title {
170
+ color: #e53e3e;
171
+ }
172
+
173
+ .section-seen .section-title {
174
+ color: #3182ce;
175
+ }
176
+
177
+ .section-title::before {
178
+ margin-right: 8px;
179
+ }
180
+
181
+ .section-new .section-title::before {
182
+ content: "🔥";
183
+ }
184
+
185
+ .section-seen .section-title::before {
186
+ content: "⭐";
187
+ }
188
+
189
+ .section-content {
190
+ padding: 20px 25px;
191
+ }
192
+
193
+ .section-new .section-title {
194
+ color: #e53e3e;
195
+ border-bottom: 2px solid #e53e3e;
196
+ }
197
+
198
+ .section-seen .section-title {
199
+ color: #3182ce;
200
+ border-bottom: 2px solid #3182ce;
201
+ }
202
+
203
+ .repo-card {
204
+ background-color: #ffffff;
205
+ border: 1px solid var(--border-color);
206
+ border-radius: 8px;
207
+ padding: 20px;
208
+ margin-bottom: 20px;
209
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
210
+ transition: box-shadow 0.2s;
211
+ }
212
+
213
+ .repo-card:hover {
214
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
215
+ }
216
+
217
+ .repo-card:last-child {
218
+ margin-bottom: 0;
219
+ }
220
+
221
+ .repo-header {
222
+ margin-bottom: 12px;
223
+ display: flex;
224
+ align-items: baseline;
225
+ gap: 12px;
226
+ }
227
+
228
+ .repo-number {
229
+ font-size: 18px;
230
+ font-weight: 700;
231
+ color: var(--primary-color);
232
+ min-width: 32px;
233
+ }
234
+
235
+ .repo-name {
236
+ font-size: 17px;
237
+ font-weight: 600;
238
+ color: var(--primary-color);
239
+ text-decoration: none;
240
+ transition: color 0.2s;
241
+ }
242
+
243
+ .repo-name:hover {
244
+ text-decoration: underline;
245
+ color: #3d5a80;
246
+ }
247
+
248
+ .repo-meta {
249
+ font-size: 12px;
250
+ color: var(--text-medium);
251
+ margin-top: 5px;
252
+ }
253
+
254
+ .repo-lang {
255
+ display: inline-block;
256
+ padding: 2px 8px;
257
+ border-radius: 3px;
258
+ font-size: 11px;
259
+ font-weight: 600;
260
+ margin-left: 10px;
261
+ color: white;
262
+ }
263
+
264
+ .repo-desc {
265
+ font-size: 14px;
266
+ color: var(--text-dark);
267
+ line-height: 1.6;
268
+ margin: 10px 0;
269
+ }
270
+
271
+ .repo-ai-summary {
272
+ background-color: var(--ai-bg);
273
+ border-left: 4px solid var(--ai-border);
274
+ padding: 12px;
275
+ margin: 10px 0;
276
+ border-radius: 4px;
277
+ font-size: 13px;
278
+ line-height: 1.6;
279
+ color: var(--text-dark);
280
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
281
+ }
282
+
283
+ .repo-ai-summary-title {
284
+ font-weight: 600;
285
+ color: var(--ai-title-color);
286
+ margin-bottom: 6px;
287
+ font-size: 13px;
288
+ }
289
+
290
+ .repo-simple-summary {
291
+ color: var(--text-medium);
292
+ font-size: 13px;
293
+ margin: 8px 0;
294
+ padding-left: 12px;
295
+ border-left: 3px solid var(--text-light);
296
+ }
297
+
298
+ .repo-footer {
299
+ font-size: 12px;
300
+ color: var(--text-light);
301
+ margin-top: 10px;
302
+ }
303
+
304
+ .star-icon {
305
+ color: #f1c40f;
306
+ margin-right: 4px;
307
+ }
308
+
309
+ .fork-icon {
310
+ color: #e74c3c;
311
+ margin-left: 15px;
312
+ margin-right: 4px;
313
+ }
314
+
315
+ .no-repos {
316
+ text-align: center;
317
+ padding: 40px;
318
+ color: var(--text-light);
319
+ font-size: 14px;
320
+ }
321
+
322
+ .footer {
323
+ background-color: var(--bg-light);
324
+ padding: 20px 40px;
325
+ text-align: center;
326
+ font-size: 12px;
327
+ color: var(--text-light);
328
+ border-top: 1px solid var(--border-color);
329
+ }
330
+
331
+ .link {
332
+ color: var(--primary-color);
333
+ text-decoration: none;
334
+ }
335
+
336
+ /* 响应式设计 */
337
+ @media (max-width: 600px) {
338
+ .container {
339
+ margin: 0;
340
+ padding: 0;
341
+ border-radius: 0;
342
+ }
343
+
344
+ .header {
345
+ padding: 20px;
346
+ }
347
+
348
+ .header h1 {
349
+ font-size: 24px;
350
+ }
351
+
352
+ .content {
353
+ padding: 20px;
354
+ }
355
+
356
+ .section {
357
+ padding: 15px;
358
+ }
359
+
360
+ .repo-card {
361
+ padding: 12px;
362
+ }
363
+
364
+ .repo-name {
365
+ font-size: 15px;
366
+ }
367
+
368
+ .repo-desc {
369
+ font-size: 13px;
370
+ }
371
+
372
+ .repo-ai-summary {
373
+ padding: 10px;
374
+ font-size: 12px;
375
+ }
376
+ }
377
+ `;
378
+ // Build new repositories section HTML
379
+ const buildReposHTML = (repos, titleText, isNew) => {
380
+ // 问题3:当项目数为0时不显示该模块
381
+ if (repos.length === 0) {
382
+ return '';
383
+ }
384
+ const reposHTML = repos
385
+ .map((repo, index) => {
386
+ const formattedStars = EmailChannel.formatNumberWithK(repo.stars);
387
+ const formattedForks = repo.forks
388
+ ? `<span class="fork-icon" aria-hidden="true">⚡</span>${EmailChannel.formatNumberWithK(repo.forks)}`
389
+ : '';
390
+ const languageBadge = repo.language
391
+ ? `<span class="repo-lang" style="background-color: ${EmailChannel.getLanguageColor(repo.language)}">${repo.language}</span>`
392
+ : '';
393
+ // 新上榜项目:显示详细项目介绍
394
+ // 持续霸榜项目:显示简化介绍(一句话)
395
+ const aiSummaryHTML = isNew
396
+ ? (repo.ai_summary
397
+ ? `<div class="repo-ai-summary" role="complementary" aria-label="项目介绍">
398
+ <div class="repo-ai-summary-title"><span aria-hidden="true">🤖</span> 项目介绍</div>
399
+ ${markdown.markdownToHTML(repo.ai_summary)}
400
+ </div>`
401
+ : '')
402
+ : (repo.ai_summary
403
+ ? `<div class="repo-simple-summary">${markdown.markdownToHTML(repo.ai_summary.split('。')[0] + '。')}</div>`
404
+ : '');
405
+ const repoNumber = index + 1;
406
+ return `
407
+ <article class="repo-card" aria-label="${repo.full_name} 项目详情">
408
+ <div class="repo-header">
409
+ <span class="repo-number">${repoNumber}.</span>
410
+ <a href="${repo.url}" class="repo-name" target="_blank" rel="noopener noreferrer" aria-label="访问 ${repo.full_name} 仓库">
411
+ ${repo.full_name}
412
+ </a>
413
+ </div>
414
+ <div class="repo-meta">
415
+ <span class="star-icon" aria-hidden="true">★</span><span aria-label="${repo.stars} stars">${formattedStars}</span>${formattedForks}${languageBadge}
416
+ </div>
417
+ ${aiSummaryHTML}
418
+ </article>
419
+ `;
420
+ })
421
+ .join('');
422
+ return `
423
+ <section class="section ${isNew ? 'section-new' : 'section-seen'}" aria-label="${titleText}">
424
+ <h2 class="section-title">${titleText}</h2>
425
+ <div class="section-content">
426
+ ${reposHTML}
427
+ </div>
428
+ </section>
429
+ `;
430
+ };
431
+ const newReposHTML = buildReposHTML(newRepositories, '新上榜项目', true);
432
+ const seenReposHTML = buildReposHTML(seenRepositories, '持续霸榜项目', false);
433
+ // If no repositories, show message
434
+ const contentHTML = newRepositories.length === 0 && seenRepositories.length === 0
435
+ ? `
436
+ <main class="content">
437
+ <div class="no-repos" role="status">📌 暂无 trending 项目</div>
438
+ </main>
439
+ `
440
+ : `
441
+ <main class="content">
442
+ ${newReposHTML}
443
+ ${seenReposHTML}
444
+ </main>
445
+ `;
446
+ return `
447
+ <!DOCTYPE html>
448
+ <html lang="zh-CN">
449
+ <head>
450
+ <meta charset="UTF-8">
451
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
452
+ <title>GitHub 热榜推送</title>
453
+ <style>${styles}</style>
454
+ </head>
455
+ <body>
456
+ <div class="container" role="main">
457
+ <header class="header">
458
+ <h1>GitHub ${sinceText}热榜推送</h1>
459
+ <time class="date" datetime="${currentDate.toISOString()}">${dateStr}</time>
460
+ </header>
461
+ ${contentHTML}
462
+ <footer class="footer">
463
+ <p>本邮件由 GitHub 热榜机器人自动生成</p>
464
+ <p><a href="https://github.com/indigos" class="link" aria-label="访问 GitHub Trending 主页">GitHub Trending</a></p>
465
+ </footer>
466
+ </div>
467
+ </body>
468
+ </html>
469
+ `;
470
+ }
471
+ /**
472
+ * Format number with 'k' suffix for thousands
473
+ * @param num Number to format
474
+ * @returns Formatted string
475
+ */
476
+ static formatNumberWithK(num) {
477
+ if (num >= 1000) {
478
+ return (num / 1000).toFixed(1) + 'k';
479
+ }
480
+ return num.toString();
481
+ }
482
+ /**
483
+ * Get background color based on programming language
484
+ * @param language Programming language
485
+ * @returns Color code
486
+ */
487
+ static getLanguageColor(language) {
488
+ const colors = {
489
+ JavaScript: '#f1e05a',
490
+ TypeScript: '#3178c6',
491
+ Python: '#3572A5',
492
+ Ruby: '#701516',
493
+ Java: '#b07219',
494
+ Go: '#00ADD8',
495
+ Rust: '#dea584',
496
+ Swift: '#ffac45',
497
+ C: '#555555',
498
+ 'C++': '#f34b7d',
499
+ 'C#': '#178600',
500
+ PHP: '#8993bd',
501
+ HTML: '#e34c26',
502
+ CSS: '#563d7c',
503
+ Shell: '#89e051',
504
+ SQL: '#e38c00',
505
+ Kotlin: '#A97BFF',
506
+ Dart: '#00B4AB'
507
+ };
508
+ return colors[language] || '#666666';
509
+ }
510
+ /**
511
+ * Send email with repositories
512
+ * @param config Email configuration
513
+ * @param newRepositories Array of new repositories
514
+ * @param seenRepositories Array of seen repositories
515
+ * @param since Time period for trending (daily, weekly, monthly)
516
+ * @returns Push result
517
+ */
518
+ static async send(config, newRepositories, seenRepositories, since = 'monthly') {
519
+ logger.info('Starting email send', {
520
+ since,
521
+ newCount: newRepositories.length,
522
+ seenCount: seenRepositories.length,
523
+ from: config.from,
524
+ to: config.to,
525
+ subject: config.subject,
526
+ smtpHost: config.smtp.host,
527
+ smtpPort: config.smtp.port
528
+ });
529
+ try {
530
+ logger.debug('Creating SMTP transport...');
531
+ const startTime = Date.now();
532
+ // Create transport with SMTP configuration
533
+ const transport = nodemailer_1.default.createTransport({
534
+ host: config.smtp.host,
535
+ port: config.smtp.port,
536
+ secure: config.smtp.secure,
537
+ auth: {
538
+ user: config.smtp.auth.user,
539
+ pass: config.smtp.auth.pass
540
+ },
541
+ logger: false,
542
+ debug: false
543
+ });
544
+ const transportCreateTime = Date.now();
545
+ logger.info('SMTP transport created', {
546
+ durationMs: transportCreateTime - startTime
547
+ });
548
+ // Verify SMTP connection
549
+ logger.debug('Verifying SMTP connection...');
550
+ const verified = await transport.verify();
551
+ const verifyDuration = Date.now() - transportCreateTime;
552
+ logger.info('SMTP connection verified', {
553
+ verified,
554
+ durationMs: verifyDuration
555
+ });
556
+ // Generate HTML content
557
+ logger.debug('Generating HTML content...');
558
+ const html = EmailChannel.generateHTML(newRepositories, seenRepositories, since);
559
+ logger.info('HTML content generated', {
560
+ htmlSize: html.length
561
+ });
562
+ // Send email
563
+ logger.info('Sending email...');
564
+ const sendStartTime = Date.now();
565
+ const info = await transport.sendMail({
566
+ from: config.from,
567
+ to: config.to,
568
+ subject: config.subject,
569
+ html: html
570
+ });
571
+ const sendDuration = Date.now() - sendStartTime;
572
+ logger.success('Email sent successfully', {
573
+ messageId: info.messageId,
574
+ accepted: info.accepted,
575
+ rejected: info.rejected,
576
+ pending: info.pending,
577
+ durationMs: sendDuration
578
+ });
579
+ return {
580
+ success: true,
581
+ messageId: info.messageId,
582
+ error: undefined
583
+ };
584
+ }
585
+ catch (error) {
586
+ logger.error('Email send failed', {
587
+ error: error instanceof Error ? error.message : 'Unknown error',
588
+ stack: error instanceof Error ? error.stack : undefined
589
+ });
590
+ return {
591
+ success: false,
592
+ error: error instanceof Error ? error.message : 'Unknown error'
593
+ };
594
+ }
595
+ }
596
+ }
597
+ exports.EmailChannel = EmailChannel;
598
+ exports.default = EmailChannel;
599
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/channels/email.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { RepositoryInfo } from '../models/repository';
2
+ import { PushResult } from './types';
3
+ /**
4
+ * Feishu Channel for pushing GitHub trending repositories
5
+ */
6
+ export declare class FeishuChannel {
7
+ /**
8
+ * Build Feishu card message
9
+ * @param newRepositories Array of new repositories to display
10
+ * @param seenRepositories Array of seen repositories to display
11
+ * @param since Time period for trending
12
+ * @returns Feishu card object
13
+ */
14
+ static buildCard(newRepositories: RepositoryInfo[], seenRepositories: RepositoryInfo[], since?: 'daily' | 'weekly' | 'monthly'): any;
15
+ /**
16
+ * Build a single repository card element
17
+ * @param repo Repository information
18
+ * @param index Index of repository
19
+ * @param isNew Whether this is a new repository
20
+ * @returns Feishu card element array
21
+ */
22
+ static buildRepoElement(repo: RepositoryInfo, index: number, isNew: boolean): any[];
23
+ /**
24
+ * Get emoji icon for programming language
25
+ * @param language Programming language
26
+ * @returns Emoji icon
27
+ */
28
+ static getLanguageEmoji(language: string): string;
29
+ /**
30
+ * Get background color based on programming language
31
+ * @param language Programming language
32
+ * @returns Color code
33
+ */
34
+ static getLanguageColor(language: string): string;
35
+ /**
36
+ * Format number with 'k' suffix for thousands
37
+ * @param num Number to format
38
+ * @returns Formatted string
39
+ */
40
+ static formatNumberWithK(num: number): string;
41
+ /**
42
+ * Push repositories to Feishu webhook
43
+ * @param newRepositories Array of new repositories
44
+ * @param seenRepositories Array of seen repositories
45
+ * @returns Push result
46
+ */
47
+ static push(webhookUrl: string, newRepositories: RepositoryInfo[], seenRepositories: RepositoryInfo[], since?: 'daily' | 'weekly' | 'monthly'): Promise<PushResult>;
48
+ }
49
+ export default FeishuChannel;
50
+ //# sourceMappingURL=feishu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKrC;;GAEG;AACH,qBAAa,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,CACd,eAAe,EAAE,cAAc,EAAE,EACjC,gBAAgB,EAAE,cAAc,EAAE,EAClC,KAAK,GAAE,OAAO,GAAG,QAAQ,GAAG,SAAqB,GAChD,GAAG;IAsGN;;;;;;OAMG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,GAAG,EAAE;IA2CnF;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoCjD;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoCjD;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAO7C;;;;;OAKG;WACU,IAAI,CACf,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,cAAc,EAAE,EACjC,gBAAgB,EAAE,cAAc,EAAE,EAClC,KAAK,GAAE,OAAO,GAAG,QAAQ,GAAG,SAAqB,GAChD,OAAO,CAAC,UAAU,CAAC;CA4EvB;AAED,eAAe,aAAa,CAAC"}