linkpress 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -6,6 +6,11 @@
6
6
  <strong>Turn your Slack links into a personal tech magazine</strong>
7
7
  </p>
8
8
 
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/linkpress"><img src="https://img.shields.io/npm/v/linkpress.svg" alt="npm version"></a>
11
+ <img src="https://img.shields.io/github/license/mindori/linkpress" alt="license">
12
+ </p>
13
+
9
14
  <p align="center">
10
15
  <img src="assets/serve.gif" alt="LinkPress Demo" width="800">
11
16
  </p>
@@ -62,8 +67,18 @@ linkpress source add slack
62
67
  <img src="assets/add.gif" alt="Connect Slack" width="800">
63
68
  </p>
64
69
 
70
+ > **⚠️ Important:** When the browser opens, **DO NOT open in the Slack desktop app**.
71
+ > You must click **"Use Slack in your browser"** to continue.
72
+ > The automatic token extraction only works in the browser, not in the desktop app.
73
+
74
+ > **📝 Note:** We recommend the **Automatic** method (default). If automatic extraction fails,
75
+ > you can select **Manual** mode and paste tokens from your browser's DevTools.
76
+ > The CLI will guide you through the process.
77
+
65
78
  Select the channels you want to watch. LinkPress will collect all shared links from these channels.
66
79
 
80
+ > **💡 Tip:** Just press Enter without selecting anything — your **Saved Messages (DM to self)** is pre-selected by default. This is the easiest way to curate links: just forward interesting articles to yourself in Slack!
81
+
67
82
 
68
83
  ## Step 2: Sync Links
69
84
 
package/dist/ai.d.ts CHANGED
@@ -1,31 +1,6 @@
1
- import type { AIProvider } from './types.js';
2
- export interface ArticleSummary {
3
- headline: string;
4
- tldr: string;
5
- keyPoints: string[];
6
- whyItMatters: string;
7
- keyQuote?: string;
8
- tags: string[];
9
- difficulty: 'beginner' | 'intermediate' | 'advanced';
10
- }
11
- export type ContentType = 'article' | 'announcement' | 'discussion' | 'reference' | 'social' | 'media' | 'internal' | 'other';
12
- export type TechnicalDepth = 'none' | 'shallow' | 'moderate' | 'deep' | 'expert' | 'unknown';
13
- export type Actionability = 'none' | 'awareness' | 'applicable' | 'reference';
14
- export interface ContentClassification {
15
- contentType: ContentType;
16
- technicalDepth: TechnicalDepth;
17
- actionability: Actionability;
18
- shouldCollect: boolean;
19
- reasoning: string;
20
- }
21
- export interface ModelInfo {
22
- id: string;
23
- name: string;
24
- }
25
- export declare const FALLBACK_MODELS: Record<AIProvider, ModelInfo[]>;
26
- export declare function fetchModels(provider: AIProvider, apiKey: string): Promise<ModelInfo[]>;
27
- export declare function serializeSummary(summary: ArticleSummary): string;
28
- export declare function parseSummary(summaryStr: string | undefined): ArticleSummary | null;
1
+ import { serializeSummary, parseSummary, fetchModels, FALLBACK_MODELS, type ArticleSummary, type ContentClassification, type ModelInfo } from '@linkpress/core';
2
+ export { serializeSummary, parseSummary, fetchModels, FALLBACK_MODELS };
3
+ export type { ArticleSummary, ContentClassification, ModelInfo };
29
4
  export declare function summarizeArticle(title: string, content: string, url: string): Promise<ArticleSummary>;
30
5
  export declare function classifyContent(messageText: string, url: string, title: string, description: string): Promise<ContentClassification>;
31
6
  //# sourceMappingURL=ai.d.ts.map
package/dist/ai.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;CACtD;AAED,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAC9H,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC7F,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAE9E,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,CAmB3D,CAAC;AAEF,wBAAsB,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAgB5F;AAiED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEhE;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,IAAI,CAyBlF;AA0ED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAmDzB;AAkED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,qBAAqB,CAAC,CA8ChC"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,CAAC;AAYjE,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAEzB;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,qBAAqB,CAAC,CAEhC"}
package/dist/ai.js CHANGED
@@ -1,428 +1,19 @@
1
- import Anthropic from '@anthropic-ai/sdk';
2
- import { GoogleGenerativeAI } from '@google/generative-ai';
3
- import OpenAI from 'openai';
1
+ import { summarizeArticle as coreSummarize, classifyContent as coreClassify, serializeSummary, parseSummary, fetchModels, FALLBACK_MODELS, } from '@linkpress/core';
4
2
  import { loadConfig } from './config.js';
5
- export const FALLBACK_MODELS = {
6
- anthropic: [
7
- { id: 'claude-sonnet-4-5-20250929', name: 'Claude Sonnet 4.5' },
8
- { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5' },
9
- { id: 'claude-opus-4-5-20251101', name: 'Claude Opus 4.5' },
10
- ],
11
- openai: [
12
- { id: 'gpt-4.1-mini', name: 'GPT-4.1 Mini' },
13
- { id: 'gpt-4.1-nano', name: 'GPT-4.1 Nano' },
14
- { id: 'gpt-4.1', name: 'GPT-4.1' },
15
- { id: 'gpt-4o-mini', name: 'GPT-4o Mini' },
16
- { id: 'gpt-4o', name: 'GPT-4o' },
17
- ],
18
- gemini: [
19
- { id: 'gemini-3-flash-preview', name: 'Gemini 3 Flash' },
20
- { id: 'gemini-3-pro-preview', name: 'Gemini 3 Pro' },
21
- { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash' },
22
- { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro' },
23
- ],
24
- };
25
- export async function fetchModels(provider, apiKey) {
26
- try {
27
- switch (provider) {
28
- case 'anthropic':
29
- return await fetchAnthropicModels(apiKey);
30
- case 'openai':
31
- return await fetchOpenAIModels(apiKey);
32
- case 'gemini':
33
- return await fetchGeminiModels(apiKey);
34
- default:
35
- return [];
36
- }
37
- }
38
- catch (error) {
39
- console.error('Failed to fetch models:', error instanceof Error ? error.message : error);
40
- return [];
41
- }
42
- }
43
- async function fetchAnthropicModels(apiKey) {
44
- const response = await fetch('https://api.anthropic.com/v1/models', {
45
- headers: {
46
- 'x-api-key': apiKey,
47
- 'anthropic-version': '2023-06-01',
48
- },
49
- });
50
- if (!response.ok)
51
- throw new Error(`HTTP ${response.status}`);
52
- const data = await response.json();
53
- return data.data
54
- .filter(m => m.id.includes('claude') && !m.id.includes('instant'))
55
- .map(m => ({ id: m.id, name: m.display_name || m.id }));
56
- }
57
- async function fetchOpenAIModels(apiKey) {
58
- const response = await fetch('https://api.openai.com/v1/models', {
59
- headers: {
60
- 'Authorization': `Bearer ${apiKey}`,
61
- },
62
- });
63
- if (!response.ok)
64
- throw new Error(`HTTP ${response.status}`);
65
- const data = await response.json();
66
- const validPrefixes = ['gpt-4', 'gpt-5', 'o1', 'o3', 'o4'];
67
- const excludePatterns = ['realtime', 'audio', 'vision', 'instruct', 'turbo', 'preview'];
68
- return data.data
69
- .filter(m => {
70
- const id = m.id.toLowerCase();
71
- const hasValidPrefix = validPrefixes.some(p => id.startsWith(p));
72
- const hasExcluded = excludePatterns.some(p => id.includes(p));
73
- return hasValidPrefix && !hasExcluded;
74
- })
75
- .map(m => ({ id: m.id, name: m.id }))
76
- .sort((a, b) => b.id.localeCompare(a.id));
77
- }
78
- async function fetchGeminiModels(apiKey) {
79
- const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`);
80
- if (!response.ok)
81
- throw new Error(`HTTP ${response.status}`);
82
- const data = await response.json();
83
- return data.models
84
- .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
85
- .filter(m => m.name.includes('gemini'))
86
- .map(m => ({
87
- id: m.name.replace('models/', ''),
88
- name: m.displayName || m.name.replace('models/', ''),
89
- }))
90
- .sort((a, b) => {
91
- const aVersion = a.id.match(/\d+(\.\d+)?/)?.[0] || '0';
92
- const bVersion = b.id.match(/\d+(\.\d+)?/)?.[0] || '0';
93
- return parseFloat(bVersion) - parseFloat(aVersion);
94
- });
95
- }
96
- export function serializeSummary(summary) {
97
- return JSON.stringify(summary);
98
- }
99
- export function parseSummary(summaryStr) {
100
- if (!summaryStr)
101
- return null;
102
- try {
103
- const parsed = JSON.parse(summaryStr);
104
- if (parsed.headline && parsed.tldr) {
105
- return parsed;
106
- }
107
- return {
108
- headline: parsed.hook || summaryStr,
109
- tldr: parsed.summary || summaryStr,
110
- keyPoints: [],
111
- whyItMatters: '',
112
- tags: parsed.tags || [],
113
- difficulty: parsed.difficulty || 'intermediate',
114
- };
115
- }
116
- catch {
117
- return {
118
- headline: summaryStr,
119
- tldr: summaryStr,
120
- keyPoints: [],
121
- whyItMatters: '',
122
- tags: [],
123
- difficulty: 'intermediate',
124
- };
125
- }
126
- }
127
- function buildPrompt(title, content, url, language) {
128
- const koreanRule = language === '한국어'
129
- ? '\n6. KOREAN ONLY: Use formal polite speech (존댓말/합쇼체) consistently. End sentences with -습니다, -입니다, -됩니다. NEVER use casual speech (반말).'
130
- : '';
131
- return `You are a SENIOR TECH JOURNALIST at a prestigious developer magazine.
132
- Your job is to create compelling, newspaper-style briefings that developers actually want to read.
133
-
134
- ---
135
-
136
- INPUT:
137
- - Title: ${title}
138
- - URL: ${url}
139
- - Content: ${content.substring(0, 6000)}
140
-
141
- ---
142
-
143
- TASK: Create a briefing in JSON format.
144
-
145
- {
146
- "headline": "Catchy, newspaper-style headline (max 15 words)",
147
- "tldr": "One-sentence summary for busy readers",
148
- "keyPoints": [
149
- "First key point (one sentence)",
150
- "Second key point (one sentence)",
151
- "Third key point (one sentence)"
152
- ],
153
- "whyItMatters": "Why this matters to developers/readers (1-2 sentences)",
154
- "keyQuote": "Most impactful quote from the article (if any, otherwise empty string)",
155
- "tags": ["tag1", "tag2", "tag3"],
156
- "difficulty": "beginner|intermediate|advanced"
157
- }
158
-
159
- ---
160
-
161
- CRITICAL RULES:
162
- 1. WRITE EVERYTHING IN ${language}. This is NOT optional. The output MUST be in ${language}.
163
- 2. Headline should be ATTENTION-GRABBING but accurate—no clickbait lies.
164
- 3. Key points should be ACTIONABLE insights, not just descriptions.
165
- 4. Tags: use technical topics (frontend, backend, ai, devops, database, security, career, etc.)
166
- 5. Difficulty: beginner (anyone can understand), intermediate (some experience needed), advanced (experts only)${koreanRule}
167
-
168
- OUTPUT: JSON only, no explanation outside JSON.`;
169
- }
170
- async function callAnthropic(apiKey, model, prompt) {
171
- const client = new Anthropic({ apiKey });
172
- const response = await client.messages.create({
173
- model,
174
- max_tokens: 800,
175
- messages: [{ role: 'user', content: prompt }],
176
- });
177
- return response.content[0].type === 'text' ? response.content[0].text : '';
178
- }
179
- async function callOpenAI(apiKey, model, prompt) {
180
- const client = new OpenAI({ apiKey });
181
- const response = await client.chat.completions.create({
182
- model,
183
- max_tokens: 800,
184
- messages: [{ role: 'user', content: prompt }],
185
- });
186
- return response.choices[0]?.message?.content || '';
187
- }
188
- async function callGemini(apiKey, model, prompt) {
189
- const genAI = new GoogleGenerativeAI(apiKey);
190
- const geminiModel = genAI.getGenerativeModel({ model });
191
- const result = await geminiModel.generateContent(prompt);
192
- return result.response.text();
193
- }
194
- export async function summarizeArticle(title, content, url) {
3
+ export { serializeSummary, parseSummary, fetchModels, FALLBACK_MODELS };
4
+ function getAIConfig() {
195
5
  const config = loadConfig();
196
- if (!config.ai.apiKey) {
197
- return getDefaultSummary(title, url);
198
- }
199
- const provider = config.ai.provider;
200
- const model = config.ai.model;
201
- const language = config.ai.language || 'English';
202
- const prompt = buildPrompt(title, content, url, language);
203
- try {
204
- let text = '';
205
- switch (provider) {
206
- case 'anthropic':
207
- text = await callAnthropic(config.ai.apiKey, model, prompt);
208
- break;
209
- case 'openai':
210
- text = await callOpenAI(config.ai.apiKey, model, prompt);
211
- break;
212
- case 'gemini':
213
- text = await callGemini(config.ai.apiKey, model, prompt);
214
- break;
215
- default:
216
- return getDefaultSummary(title, url);
217
- }
218
- const jsonMatch = text.match(/\{[\s\S]*\}/);
219
- if (!jsonMatch) {
220
- return getDefaultSummary(title, url);
221
- }
222
- const parsed = JSON.parse(jsonMatch[0]);
223
- return {
224
- headline: parsed.headline || title,
225
- tldr: parsed.tldr || '',
226
- keyPoints: Array.isArray(parsed.keyPoints) ? parsed.keyPoints.slice(0, 3) : [],
227
- whyItMatters: parsed.whyItMatters || '',
228
- keyQuote: parsed.keyQuote || '',
229
- tags: Array.isArray(parsed.tags) ? parsed.tags.slice(0, 5) : [],
230
- difficulty: ['beginner', 'intermediate', 'advanced'].includes(parsed.difficulty)
231
- ? parsed.difficulty
232
- : 'intermediate',
233
- };
234
- }
235
- catch (error) {
236
- console.error('AI summarization failed:', error instanceof Error ? error.message : String(error));
237
- return getDefaultSummary(title, url);
238
- }
239
- }
240
- function buildClassificationPrompt(messageText, url, title, description) {
241
- return `You filter links for a tech newsletter. DEFAULT ACTION: COLLECT.
242
-
243
- INPUT:
244
- - URL: ${url}
245
- - Context: ${messageText || '(none)'}
246
- - Title: ${title || '(none)'}
247
- - Description: ${description || '(none)'}
248
-
249
- ---
250
-
251
- EXCLUDE ONLY these specific categories:
252
-
253
- 1. INTERNAL TOOLS (workspace/productivity apps, not public content):
254
- - Google Docs/Sheets/Slides/Drive (docs.google.com, drive.google.com, share.google)
255
- - Notion workspace pages (notion.so with private content)
256
- - Figma files (figma.com)
257
- - Jira/Confluence (atlassian.net)
258
- - Canva designs (canva.com/design)
259
- - Slack permalinks
260
-
261
- 2. VIDEO/AUDIO (reading-focused newsletter):
262
- - YouTube (youtube.com, youtu.be)
263
- - Vimeo, Twitch, podcasts
264
-
265
- 3. TWITTER/X ONLY (not scrapable):
266
- - x.com, twitter.com
267
- - NOTE: LinkedIn is NOT excluded. LinkedIn posts ARE scrapable.
268
-
269
- 4. AUTH/TRANSACTIONAL pages:
270
- - Login pages, confirmation tokens, password resets
271
- - URLs with "confirm", "token=", "verify", "unsubscribe"
272
-
273
- 5. OBVIOUS NON-CONTENT:
274
- - Image files (.png, .jpg, .gif direct links)
275
- - File downloads (.zip, .pdf direct links)
276
-
277
- ---
278
-
279
- ALWAYS COLLECT (even without metadata):
280
-
281
- - GitHub repos/gists (github.com, gist.github.com) - developers share code there
282
- - LinkedIn posts (linkedin.com) - professionals share knowledge, IS scrapable
283
- - Blog platforms (medium.com, dev.to, substack.com, brunch.co.kr, velog.io, tistory.com)
284
- - Tech news (news.hada.io, news.ycombinator.com, techcrunch.com)
285
- - Any unknown domain - might be interesting, we'll scrape and find out
286
- - Product/tool pages - developers share useful tools
287
-
288
- ---
289
-
290
- CRITICAL: Missing metadata (no title/description) is NOT a reason to exclude.
291
- We will scrape the content later. If someone shared it, it's probably worth checking.
292
-
293
- OUTPUT (JSON only):
294
- {
295
- "content_type": "article|social|reference|internal|media|other",
296
- "technical_depth": "shallow|moderate|deep|unknown",
297
- "should_collect": true|false,
298
- "reasoning": "Brief reason"
299
- }
300
-
301
- When uncertain, set should_collect: true.`;
302
- }
303
- export async function classifyContent(messageText, url, title, description) {
304
- const config = loadConfig();
305
- if (!config.ai.apiKey) {
306
- return getDefaultClassification(url);
307
- }
308
- const provider = config.ai.provider;
309
- const model = config.ai.model;
310
- const prompt = buildClassificationPrompt(messageText, url, title, description);
311
- try {
312
- let text = '';
313
- switch (provider) {
314
- case 'anthropic':
315
- text = await callAnthropic(config.ai.apiKey, model, prompt);
316
- break;
317
- case 'openai':
318
- text = await callOpenAI(config.ai.apiKey, model, prompt);
319
- break;
320
- case 'gemini':
321
- text = await callGemini(config.ai.apiKey, model, prompt);
322
- break;
323
- default:
324
- return getDefaultClassification(url);
325
- }
326
- const jsonMatch = text.match(/\{[\s\S]*\}/);
327
- if (!jsonMatch) {
328
- return getDefaultClassification(url);
329
- }
330
- const parsed = JSON.parse(jsonMatch[0]);
331
- return {
332
- contentType: parsed.content_type,
333
- technicalDepth: parsed.technical_depth,
334
- actionability: parsed.actionability || 'awareness',
335
- shouldCollect: parsed.should_collect === true,
336
- reasoning: parsed.reasoning || '',
337
- };
338
- }
339
- catch (error) {
340
- console.error('AI classification failed:', error instanceof Error ? error.message : String(error));
341
- return getDefaultClassification(url);
342
- }
343
- }
344
- function getDefaultClassification(url) {
345
- const urlLower = url.toLowerCase();
346
- const internalPatterns = [
347
- 'docs.google.com', 'drive.google.com', 'share.google',
348
- 'sheets.google.com', 'slides.google.com',
349
- 'notion.so', 'figma.com', 'canva.com/design',
350
- 'atlassian.net', 'jira', 'confluence',
351
- 'slack.com/archives',
352
- ];
353
- if (internalPatterns.some(p => urlLower.includes(p))) {
354
- return {
355
- contentType: 'internal',
356
- technicalDepth: 'none',
357
- actionability: 'none',
358
- shouldCollect: false,
359
- reasoning: 'Internal workspace tool',
360
- };
361
- }
362
- if (urlLower.includes('youtube.com') || urlLower.includes('youtu.be') || urlLower.includes('vimeo.com')) {
363
- return {
364
- contentType: 'media',
365
- technicalDepth: 'moderate',
366
- actionability: 'awareness',
367
- shouldCollect: false,
368
- reasoning: 'Video content excluded',
369
- };
370
- }
371
- if (urlLower.includes('x.com') || urlLower.includes('twitter.com')) {
372
- return {
373
- contentType: 'social',
374
- technicalDepth: 'unknown',
375
- actionability: 'awareness',
376
- shouldCollect: false,
377
- reasoning: 'Twitter/X excluded - not scrapable',
378
- };
379
- }
380
- if (urlLower.includes('/confirm') || urlLower.includes('token=') || urlLower.includes('/verify') || urlLower.includes('/unsubscribe')) {
381
- return {
382
- contentType: 'other',
383
- technicalDepth: 'none',
384
- actionability: 'none',
385
- shouldCollect: false,
386
- reasoning: 'Auth/transactional page',
387
- };
388
- }
389
6
  return {
390
- contentType: 'article',
391
- technicalDepth: 'shallow',
392
- actionability: 'awareness',
393
- shouldCollect: true,
394
- reasoning: 'Default: collect and scrape',
7
+ provider: config.ai.provider,
8
+ apiKey: config.ai.apiKey || '',
9
+ model: config.ai.model,
10
+ language: config.ai.language,
395
11
  };
396
12
  }
397
- function getDefaultSummary(title, url) {
398
- let hostname = '';
399
- try {
400
- hostname = new URL(url).hostname.replace('www.', '');
401
- }
402
- catch {
403
- hostname = 'unknown';
404
- }
405
- const tags = [];
406
- const urlLower = url.toLowerCase();
407
- if (urlLower.includes('github.com'))
408
- tags.push('github');
409
- if (urlLower.includes('medium.com'))
410
- tags.push('blog');
411
- if (urlLower.includes('dev.to'))
412
- tags.push('blog');
413
- if (urlLower.includes('youtube.com') || urlLower.includes('youtu.be'))
414
- tags.push('video');
415
- if (urlLower.includes('linkedin.com'))
416
- tags.push('linkedin');
417
- if (urlLower.includes('news.hada.io'))
418
- tags.push('news');
419
- return {
420
- headline: title || `Article from ${hostname}`,
421
- tldr: title || `Content from ${hostname}`,
422
- keyPoints: [],
423
- whyItMatters: '',
424
- tags,
425
- difficulty: 'intermediate',
426
- };
13
+ export async function summarizeArticle(title, content, url) {
14
+ return coreSummarize(title, content, url, getAIConfig());
15
+ }
16
+ export async function classifyContent(messageText, url, title, description) {
17
+ return coreClassify(messageText, url, title, description, getAIConfig());
427
18
  }
428
19
  //# sourceMappingURL=ai.js.map
package/dist/ai.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,IAAI,aAAa,EACjC,eAAe,IAAI,YAAY,EAC/B,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,eAAe,GAKhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;AAGxE,SAAS,WAAW;IAClB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ;QAC5B,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK;QACtB,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,OAAe,EACf,GAAW;IAEX,OAAO,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,GAAW,EACX,KAAa,EACb,WAAmB;IAEnB,OAAO,YAAY,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;AAC3E,CAAC"}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { initCommand, addCommand, listCommand, sourceCommand, syncCommand, gener
4
4
  program
5
5
  .name('linkpress')
6
6
  .description('Turn your Slack links into a personal tech magazine')
7
- .version('0.1.0');
7
+ .version('0.2.0');
8
8
  program.addCommand(initCommand);
9
9
  program.addCommand(addCommand);
10
10
  program.addCommand(listCommand);
package/dist/scraper.d.ts CHANGED
@@ -1,11 +1,3 @@
1
- export interface ScrapedContent {
2
- title: string;
3
- description: string;
4
- content: string;
5
- siteName?: string;
6
- image?: string;
7
- sourceLabel?: string;
8
- }
9
- export declare function scrapeUrl(url: string): Promise<ScrapedContent>;
10
- export declare function estimateReadingTime(content: string): number;
1
+ export { scrapeUrl, type ScrapedContent } from '@linkpress/core';
2
+ export { estimateReadingTime } from '@linkpress/core';
11
3
  //# sourceMappingURL=scraper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scraper.d.ts","sourceRoot":"","sources":["../src/scraper.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAwBpE;AA2JD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D"}
1
+ {"version":3,"file":"scraper.d.ts","sourceRoot":"","sources":["../src/scraper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/scraper.js CHANGED
@@ -1,159 +1,3 @@
1
- import * as cheerio from 'cheerio';
2
- export async function scrapeUrl(url) {
3
- try {
4
- const response = await fetch(url, {
5
- headers: {
6
- 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
7
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
8
- 'Accept-Language': 'en-US,en;q=0.9,ko;q=0.8',
9
- },
10
- redirect: 'follow',
11
- signal: AbortSignal.timeout(15000),
12
- });
13
- if (!response.ok) {
14
- throw new Error(`HTTP ${response.status}`);
15
- }
16
- const html = await response.text();
17
- return parseHtml(html, url);
18
- }
19
- catch (error) {
20
- if (error instanceof Error) {
21
- throw new Error(`Failed to scrape ${url}: ${error.message}`);
22
- }
23
- throw error;
24
- }
25
- }
26
- function parseHtml(html, url) {
27
- const $ = cheerio.load(html);
28
- $('script, style, nav, footer, header, aside, .ads, .advertisement, .sidebar').remove();
29
- const title = $('meta[property="og:title"]').attr('content') ||
30
- $('meta[name="twitter:title"]').attr('content') ||
31
- $('title').text() ||
32
- '';
33
- const description = $('meta[property="og:description"]').attr('content') ||
34
- $('meta[name="description"]').attr('content') ||
35
- $('meta[name="twitter:description"]').attr('content') ||
36
- '';
37
- const siteName = $('meta[property="og:site_name"]').attr('content') ||
38
- new URL(url).hostname.replace('www.', '');
39
- const image = extractImage($, url);
40
- const sourceLabel = detectSourceLabel(url);
41
- let content = '';
42
- const articleSelectors = [
43
- 'article',
44
- '[role="main"]',
45
- 'main',
46
- '.post-content',
47
- '.article-content',
48
- '.entry-content',
49
- '.content',
50
- '#content',
51
- ];
52
- for (const selector of articleSelectors) {
53
- const element = $(selector);
54
- if (element.length > 0) {
55
- content = element.text();
56
- break;
57
- }
58
- }
59
- if (!content) {
60
- content = $('body').text();
61
- }
62
- content = content
63
- .replace(/\s+/g, ' ')
64
- .replace(/\n\s*\n/g, '\n')
65
- .trim()
66
- .substring(0, 10000);
67
- return {
68
- title: title.trim(),
69
- description: description.trim(),
70
- content,
71
- siteName,
72
- image,
73
- sourceLabel,
74
- };
75
- }
76
- function extractImage($, url) {
77
- const ogImage = $('meta[property="og:image"]').attr('content');
78
- if (ogImage) {
79
- return resolveUrl(ogImage, url);
80
- }
81
- const twitterImage = $('meta[name="twitter:image"]').attr('content');
82
- if (twitterImage) {
83
- return resolveUrl(twitterImage, url);
84
- }
85
- const articleSelectors = ['article', '[role="main"]', 'main', '.post-content', '.article-content'];
86
- for (const selector of articleSelectors) {
87
- const img = $(`${selector} img`).first();
88
- const src = img.attr('src') || img.attr('data-src');
89
- if (src && !isIconOrLogo(src)) {
90
- return resolveUrl(src, url);
91
- }
92
- }
93
- return undefined;
94
- }
95
- function resolveUrl(imgUrl, baseUrl) {
96
- if (imgUrl.startsWith('http://') || imgUrl.startsWith('https://')) {
97
- return imgUrl;
98
- }
99
- if (imgUrl.startsWith('//')) {
100
- return 'https:' + imgUrl;
101
- }
102
- try {
103
- return new URL(imgUrl, baseUrl).href;
104
- }
105
- catch {
106
- return imgUrl;
107
- }
108
- }
109
- function isIconOrLogo(src) {
110
- const lower = src.toLowerCase();
111
- return lower.includes('logo') ||
112
- lower.includes('icon') ||
113
- lower.includes('avatar') ||
114
- lower.includes('favicon') ||
115
- lower.includes('badge') ||
116
- lower.endsWith('.svg') ||
117
- lower.includes('1x1') ||
118
- lower.includes('pixel');
119
- }
120
- function detectSourceLabel(url) {
121
- const hostname = new URL(url).hostname.toLowerCase();
122
- const labelMap = {
123
- 'medium.com': 'Blog',
124
- 'dev.to': 'Blog',
125
- 'hashnode.dev': 'Blog',
126
- 'velog.io': 'Blog',
127
- 'tistory.com': 'Blog',
128
- 'brunch.co.kr': 'Blog',
129
- 'substack.com': 'Newsletter',
130
- 'github.com': 'GitHub',
131
- 'github.io': 'Blog',
132
- 'linkedin.com': 'LinkedIn',
133
- 'twitter.com': 'Twitter',
134
- 'x.com': 'Twitter',
135
- 'reddit.com': 'Reddit',
136
- 'news.ycombinator.com': 'HackerNews',
137
- 'stackoverflow.com': 'StackOverflow',
138
- 'youtube.com': 'YouTube',
139
- 'youtu.be': 'YouTube',
140
- 'notion.so': 'Notion',
141
- 'notion.site': 'Notion',
142
- 'news.hada.io': 'News',
143
- };
144
- for (const [domain, label] of Object.entries(labelMap)) {
145
- if (hostname.includes(domain)) {
146
- return label;
147
- }
148
- }
149
- if (hostname.includes('blog') || url.includes('/blog/')) {
150
- return 'Blog';
151
- }
152
- return 'Article';
153
- }
154
- export function estimateReadingTime(content) {
155
- const wordsPerMinute = 200;
156
- const wordCount = content.split(/\s+/).length;
157
- return Math.max(1, Math.ceil(wordCount / wordsPerMinute));
158
- }
1
+ export { scrapeUrl } from '@linkpress/core';
2
+ export { estimateReadingTime } from '@linkpress/core';
159
3
  //# sourceMappingURL=scraper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scraper.js","sourceRoot":"","sources":["../src/scraper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scraper.js","sourceRoot":"","sources":["../src/scraper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1,45 +1,2 @@
1
- export interface SlackAuthConfig {
2
- token: string;
3
- cookie: string;
4
- }
5
- export interface SlackUser {
6
- id: string;
7
- name: string;
8
- realName: string;
9
- team: string;
10
- }
11
- export interface SlackConversation {
12
- id: string;
13
- name: string;
14
- isPrivate: boolean;
15
- isIm: boolean;
16
- isMpim: boolean;
17
- user?: string;
18
- }
19
- export interface SlackMessage {
20
- ts: string;
21
- text: string;
22
- user?: string;
23
- type: string;
24
- }
25
- export declare class SlackClient {
26
- private token;
27
- private cookie;
28
- private baseUrl;
29
- constructor(auth: SlackAuthConfig);
30
- private request;
31
- testAuth(): Promise<SlackUser>;
32
- getConversations(): Promise<SlackConversation[]>;
33
- getUserInfo(userId: string): Promise<{
34
- id: string;
35
- name: string;
36
- realName: string;
37
- }>;
38
- getConversationHistory(channelId: string, options?: {
39
- limit?: number;
40
- oldest?: string;
41
- latest?: string;
42
- }): Promise<SlackMessage[]>;
43
- generateSourceId(): string;
44
- }
1
+ export { SlackClient, type SlackAuthConfig, type SlackUser, type SlackConversation, type SlackMessage, } from '@linkpress/core';
45
2
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/slack/client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA2B;gBAE9B,IAAI,EAAE,eAAe;YAKnB,OAAO;IAsBf,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAU9B,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IA4ChD,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAYpF,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GACjE,OAAO,CAAC,YAAY,EAAE,CAAC;IA6B1B,gBAAgB,IAAI,MAAM;CAG3B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/slack/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,iBAAiB,CAAC"}
@@ -1,98 +1,2 @@
1
- import crypto from 'crypto';
2
- export class SlackClient {
3
- token;
4
- cookie;
5
- baseUrl = 'https://slack.com/api';
6
- constructor(auth) {
7
- this.token = auth.token;
8
- this.cookie = auth.cookie;
9
- }
10
- async request(method, params = {}) {
11
- const url = new URL(`${this.baseUrl}/${method}`);
12
- const response = await fetch(url, {
13
- method: 'POST',
14
- headers: {
15
- 'Authorization': `Bearer ${this.token}`,
16
- 'Cookie': `d=${this.cookie}`,
17
- 'Content-Type': 'application/x-www-form-urlencoded',
18
- },
19
- body: new URLSearchParams(params).toString(),
20
- });
21
- const data = await response.json();
22
- if (!data.ok) {
23
- throw new Error(`Slack API error: ${data.error || 'Unknown error'}`);
24
- }
25
- return data;
26
- }
27
- async testAuth() {
28
- const response = await this.request('auth.test');
29
- return {
30
- id: response.user_id,
31
- name: response.user,
32
- realName: response.user,
33
- team: response.team,
34
- };
35
- }
36
- async getConversations() {
37
- const conversations = [];
38
- let cursor;
39
- do {
40
- const params = {
41
- types: 'public_channel,private_channel,mpim,im',
42
- limit: '200',
43
- exclude_archived: 'true',
44
- };
45
- if (cursor) {
46
- params.cursor = cursor;
47
- }
48
- const response = await this.request('conversations.list', params);
49
- for (const channel of response.channels) {
50
- conversations.push({
51
- id: channel.id,
52
- name: channel.name || channel.id,
53
- isPrivate: channel.is_private,
54
- isIm: channel.is_im,
55
- isMpim: channel.is_mpim,
56
- user: channel.user,
57
- });
58
- }
59
- cursor = response.response_metadata?.next_cursor;
60
- } while (cursor);
61
- return conversations;
62
- }
63
- async getUserInfo(userId) {
64
- const response = await this.request('users.info', { user: userId });
65
- return {
66
- id: response.user.id,
67
- name: response.user.name,
68
- realName: response.user.real_name,
69
- };
70
- }
71
- async getConversationHistory(channelId, options = {}) {
72
- const messages = [];
73
- let cursor;
74
- let fetched = 0;
75
- const limit = options.limit || 100;
76
- do {
77
- const params = {
78
- channel: channelId,
79
- limit: Math.min(limit - fetched, 200).toString(),
80
- };
81
- if (cursor)
82
- params.cursor = cursor;
83
- if (options.oldest)
84
- params.oldest = options.oldest;
85
- if (options.latest)
86
- params.latest = options.latest;
87
- const response = await this.request('conversations.history', params);
88
- messages.push(...response.messages);
89
- fetched += response.messages.length;
90
- cursor = response.response_metadata?.next_cursor;
91
- } while (cursor && fetched < limit);
92
- return messages;
93
- }
94
- generateSourceId() {
95
- return crypto.randomUUID();
96
- }
97
- }
1
+ export { SlackClient, } from '@linkpress/core';
98
2
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/slack/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/slack/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAKZ,MAAM,iBAAiB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/slack/sync.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAgG1C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA0H7H"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/slack/sync.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA0G7H"}
@@ -1,85 +1,11 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
3
  import crypto from 'crypto';
4
- import { SlackClient } from './client.js';
4
+ import { SlackClient, extractLinksFromMessages } from '@linkpress/core';
5
5
  import { loadConfig } from '../config.js';
6
6
  import { insertArticle, articleExists } from '../db.js';
7
7
  import { classifyContent } from '../ai.js';
8
8
  import { t } from '../i18n.js';
9
- const URL_REGEX = /https?:\/\/[^\s<>|]+/g;
10
- const SLACK_URL_REGEX = /<(https?:\/\/[^|>]+)(?:\|[^>]*)?>​/g;
11
- const IGNORED_DOMAINS = [
12
- 'slack.com',
13
- 'slack-edge.com',
14
- 'slack-imgs.com',
15
- 'giphy.com',
16
- 'tenor.com',
17
- 'emoji.slack-edge.com',
18
- ];
19
- function extractUrls(text) {
20
- const urls = new Set();
21
- const slackMatches = text.matchAll(/<(https?:\/\/[^|>]+)(?:\|[^>]*)?>/g);
22
- for (const match of slackMatches) {
23
- urls.add(match[1]);
24
- }
25
- const plainMatches = text.matchAll(URL_REGEX);
26
- for (const match of plainMatches) {
27
- let url = match[0];
28
- url = url.replace(/[.,;:!?)]+$/, '');
29
- urls.add(url);
30
- }
31
- return Array.from(urls).filter(url => {
32
- try {
33
- const parsed = new URL(url);
34
- return !IGNORED_DOMAINS.some(domain => parsed.hostname.includes(domain));
35
- }
36
- catch {
37
- return false;
38
- }
39
- });
40
- }
41
- function isArticleUrl(url) {
42
- try {
43
- const parsed = new URL(url);
44
- const path = parsed.pathname.toLowerCase();
45
- const nonArticlePatterns = [
46
- /\.(png|jpg|jpeg|gif|webp|svg|ico|pdf|zip|tar|gz)$/i,
47
- /^\/?(favicon|robots\.txt|sitemap)/i,
48
- ];
49
- for (const pattern of nonArticlePatterns) {
50
- if (pattern.test(path)) {
51
- return false;
52
- }
53
- }
54
- const articleDomains = [
55
- 'medium.com',
56
- 'dev.to',
57
- 'hashnode.dev',
58
- 'substack.com',
59
- 'github.com',
60
- 'twitter.com',
61
- 'x.com',
62
- 'linkedin.com',
63
- 'youtube.com',
64
- 'youtu.be',
65
- 'notion.so',
66
- 'notion.site',
67
- 'velog.io',
68
- 'tistory.com',
69
- 'brunch.co.kr',
70
- ];
71
- if (articleDomains.some(d => parsed.hostname.includes(d))) {
72
- return true;
73
- }
74
- if (path.length > 10 || path.includes('/blog') || path.includes('/post') || path.includes('/article')) {
75
- return true;
76
- }
77
- return true;
78
- }
79
- catch {
80
- return false;
81
- }
82
- }
83
9
  export async function syncSlackSources(config, options = {}) {
84
10
  const cfg = config || loadConfig();
85
11
  const { silent = false } = options;
@@ -104,21 +30,7 @@ export async function syncSlackSources(config, options = {}) {
104
30
  const spinner = silent ? null : ora(t('sync.fetching', { channel: channel.name })).start();
105
31
  try {
106
32
  const messages = await client.getConversationHistory(channel.id, { limit: 200 });
107
- const extractedLinks = [];
108
- for (const message of messages) {
109
- if (message.text) {
110
- const urls = extractUrls(message.text);
111
- for (const url of urls.filter(isArticleUrl)) {
112
- extractedLinks.push({ url, messageText: message.text });
113
- }
114
- }
115
- }
116
- const uniqueLinks = extractedLinks.reduce((acc, link) => {
117
- if (!acc.some(l => l.url === link.url)) {
118
- acc.push(link);
119
- }
120
- return acc;
121
- }, []);
33
+ const uniqueLinks = extractLinksFromMessages(messages);
122
34
  totalUrls += uniqueLinks.length;
123
35
  let channelNew = 0;
124
36
  let channelSkipped = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/slack/sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/slack/sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAc/B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAsC,EAAE,UAAuB,EAAE;IACtG,MAAM,GAAG,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAExC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC/D,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAE/E,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;YAE3F,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;gBACjF,MAAM,WAAW,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;gBAEvD,SAAS,IAAI,WAAW,CAAC,MAAM,CAAC;gBAEhC,IAAI,UAAU,GAAG,CAAC,CAAC;gBACnB,IAAI,cAAc,GAAG,CAAC,CAAC;gBACvB,IAAI,eAAe,GAAG,CAAC,CAAC;gBAExB,IAAI,SAAS,GAAG,CAAC,CAAC;gBAElB,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;oBAC/B,SAAS,EAAE,CAAC;oBACZ,IAAI,OAAO,EAAE,CAAC;wBACZ,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,kBAAkB,EAAE;4BACnC,OAAO,EAAE,OAAO,CAAC,IAAI;4BACrB,OAAO,EAAE,SAAS;4BAClB,KAAK,EAAE,WAAW,CAAC,MAAM;yBAC1B,CAAC,CAAC;oBACL,CAAC;oBACD,IAAI,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC5B,cAAc,EAAE,CAAC;wBACjB,OAAO,EAAE,CAAC;wBACV,SAAS;oBACX,CAAC;oBAED,MAAM,cAAc,GAAG,MAAM,eAAe,CAC1C,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,GAAG,EACR,EAAE,EACF,EAAE,CACH,CAAC;oBAEF,IAAI,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC;wBAClC,eAAe,EAAE,CAAC;wBAClB,QAAQ,EAAE,CAAC;wBACX,IAAI,CAAC,MAAM,EAAE,CAAC;4BACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;4BAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,cAAc,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;wBACjE,CAAC;wBACD,SAAS;oBACX,CAAC;oBAED,MAAM,OAAO,GAAY;wBACvB,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;wBACvB,GAAG,EAAE,IAAI,CAAC,GAAG;wBACb,KAAK,EAAE,IAAI,CAAC,GAAG;wBACf,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE,OAAO;wBACnB,QAAQ,EAAE,OAAO,CAAC,EAAE;wBACpB,SAAS,EAAE,IAAI,IAAI,EAAE;qBACtB,CAAC;oBAEF,aAAa,CAAC,OAAO,CAAC,CAAC;oBACvB,UAAU,EAAE,CAAC;oBACb,WAAW,EAAE,CAAC;gBAChB,CAAC;gBAED,OAAO,EAAE,OAAO,CACd,CAAC,CAAC,oBAAoB,EAAE;oBACtB,OAAO,EAAE,OAAO,CAAC,IAAI;oBACrB,KAAK,EAAE,WAAW,CAAC,MAAM;oBACzB,GAAG,EAAE,UAAU;oBACf,QAAQ,EAAE,cAAc;oBACxB,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CACH,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,oBAAoB,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAClE,IAAI,KAAK,YAAY,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;oBACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC9D,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,42 +1,10 @@
1
- export interface Article {
2
- id: string;
3
- url: string;
4
- title: string;
5
- description?: string;
6
- content?: string;
7
- summary?: string;
8
- tags: string[];
9
- difficulty?: 'beginner' | 'intermediate' | 'advanced';
10
- readingTimeMinutes?: number;
11
- image?: string;
12
- sourceLabel?: string;
13
- sourceType: 'slack' | 'manual' | 'import';
14
- sourceId?: string;
15
- createdAt: Date;
16
- processedAt?: Date;
17
- readAt?: Date;
18
- }
19
- export interface SlackSource {
20
- id: string;
21
- workspace: string;
22
- token: string;
23
- cookie: string;
24
- channels: SlackChannel[];
25
- addedAt: Date;
26
- }
27
- export interface SlackChannel {
28
- id: string;
29
- name: string;
30
- isPrivate: boolean;
31
- isSelfDM: boolean;
32
- }
33
- export type AIProvider = 'anthropic' | 'openai' | 'gemini';
1
+ export type { Article, AIProvider, SlackSource, SlackChannel, SlackAuthConfig, SlackUser, SlackConversation, SlackMessage, ExtractedLink, ScrapedContent, ArticleSummary, ContentClassification, ModelInfo, AIConfig, } from '@linkpress/core';
34
2
  export interface Config {
35
3
  sources: {
36
- slack?: SlackSource[];
4
+ slack?: import('@linkpress/core').SlackSource[];
37
5
  };
38
6
  ai: {
39
- provider: AIProvider;
7
+ provider: import('@linkpress/core').AIProvider;
40
8
  apiKey?: string;
41
9
  model: string;
42
10
  language: string;
@@ -50,7 +18,7 @@ export interface Magazine {
50
18
  id: string;
51
19
  title: string;
52
20
  generatedAt: Date;
53
- articles: Article[];
21
+ articles: import('@linkpress/core').Article[];
54
22
  period: {
55
23
  from: Date;
56
24
  to: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,CAAC,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,MAAM,CAAC,EAAE,IAAI,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,IAAI,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;KACvB,CAAC;IACF,EAAE,EAAE;QACF,QAAQ,EAAE,UAAU,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;KACtC,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,IAAI,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE;QACN,IAAI,EAAE,IAAI,CAAC;QACX,EAAE,EAAE,IAAI,CAAC;KACV,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;CACb"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE;QACP,KAAK,CAAC,EAAE,OAAO,iBAAiB,EAAE,WAAW,EAAE,CAAC;KACjD,CAAC;IACF,EAAE,EAAE;QACF,QAAQ,EAAE,OAAO,iBAAiB,EAAE,UAAU,CAAC;QAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;KACtC,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,IAAI,CAAC;IAClB,QAAQ,EAAE,OAAO,iBAAiB,EAAE,OAAO,EAAE,CAAC;IAC9C,MAAM,EAAE;QACN,IAAI,EAAE,IAAI,CAAC;QACX,EAAE,EAAE,IAAI,CAAC;KACV,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;CACb"}
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- export declare function truncate(str: string, maxLength: number): string;
2
- export declare function isValidUrl(str: string): boolean;
1
+ export { truncate, isValidUrl } from '@linkpress/core';
3
2
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/utils.js CHANGED
@@ -1,15 +1,2 @@
1
- export function truncate(str, maxLength) {
2
- if (str.length <= maxLength)
3
- return str;
4
- return str.substring(0, maxLength - 3) + '...';
5
- }
6
- export function isValidUrl(str) {
7
- try {
8
- new URL(str);
9
- return true;
10
- }
11
- catch {
12
- return false;
13
- }
14
- }
1
+ export { truncate, isValidUrl } from '@linkpress/core';
15
2
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,SAAiB;IACrD,IAAI,GAAG,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,GAAG,CAAC;IACxC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACb,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linkpress",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Turn your Slack links into a personal tech magazine with AI-powered summaries",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -43,17 +43,13 @@
43
43
  "url": "https://github.com/mindori/linkpress/issues"
44
44
  },
45
45
  "dependencies": {
46
- "@anthropic-ai/sdk": "^0.39.0",
47
- "@google/generative-ai": "^0.24.1",
46
+ "@linkpress/core": "^0.1.0",
48
47
  "better-sqlite3": "^11.7.0",
49
48
  "chalk": "^5.3.0",
50
- "cheerio": "^1.0.0",
51
49
  "commander": "^12.1.0",
52
50
  "express": "^4.21.2",
53
51
  "inquirer": "^12.3.2",
54
- "node-fetch": "^3.3.2",
55
52
  "open": "^10.1.0",
56
- "openai": "^6.16.0",
57
53
  "ora": "^8.1.1",
58
54
  "playwright": "^1.57.0",
59
55
  "yaml": "^2.7.0"