linkpress 0.1.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/dist/ai.d.ts +31 -0
  4. package/dist/ai.d.ts.map +1 -0
  5. package/dist/ai.js +428 -0
  6. package/dist/ai.js.map +1 -0
  7. package/dist/commands/add.d.ts +3 -0
  8. package/dist/commands/add.d.ts.map +1 -0
  9. package/dist/commands/add.js +38 -0
  10. package/dist/commands/add.js.map +1 -0
  11. package/dist/commands/clear.d.ts +3 -0
  12. package/dist/commands/clear.d.ts.map +1 -0
  13. package/dist/commands/clear.js +25 -0
  14. package/dist/commands/clear.js.map +1 -0
  15. package/dist/commands/generate.d.ts +3 -0
  16. package/dist/commands/generate.d.ts.map +1 -0
  17. package/dist/commands/generate.js +38 -0
  18. package/dist/commands/generate.js.map +1 -0
  19. package/dist/commands/index.d.ts +9 -0
  20. package/dist/commands/index.d.ts.map +1 -0
  21. package/dist/commands/index.js +9 -0
  22. package/dist/commands/index.js.map +1 -0
  23. package/dist/commands/init.d.ts +3 -0
  24. package/dist/commands/init.d.ts.map +1 -0
  25. package/dist/commands/init.js +129 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/list.d.ts +3 -0
  28. package/dist/commands/list.d.ts.map +1 -0
  29. package/dist/commands/list.js +33 -0
  30. package/dist/commands/list.js.map +1 -0
  31. package/dist/commands/serve.d.ts +3 -0
  32. package/dist/commands/serve.d.ts.map +1 -0
  33. package/dist/commands/serve.js +122 -0
  34. package/dist/commands/serve.js.map +1 -0
  35. package/dist/commands/source.d.ts +3 -0
  36. package/dist/commands/source.d.ts.map +1 -0
  37. package/dist/commands/source.js +48 -0
  38. package/dist/commands/source.js.map +1 -0
  39. package/dist/commands/sync.d.ts +3 -0
  40. package/dist/commands/sync.d.ts.map +1 -0
  41. package/dist/commands/sync.js +24 -0
  42. package/dist/commands/sync.js.map +1 -0
  43. package/dist/config.d.ts +8 -0
  44. package/dist/config.d.ts.map +1 -0
  45. package/dist/config.js +47 -0
  46. package/dist/config.js.map +1 -0
  47. package/dist/db.d.ts +14 -0
  48. package/dist/db.d.ts.map +1 -0
  49. package/dist/db.js +140 -0
  50. package/dist/db.js.map +1 -0
  51. package/dist/i18n.d.ts +4 -0
  52. package/dist/i18n.d.ts.map +1 -0
  53. package/dist/i18n.js +139 -0
  54. package/dist/i18n.js.map +1 -0
  55. package/dist/index.d.ts +3 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +17 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/magazine.d.ts +6 -0
  60. package/dist/magazine.d.ts.map +1 -0
  61. package/dist/magazine.js +1751 -0
  62. package/dist/magazine.js.map +1 -0
  63. package/dist/process.d.ts +16 -0
  64. package/dist/process.d.ts.map +1 -0
  65. package/dist/process.js +77 -0
  66. package/dist/process.js.map +1 -0
  67. package/dist/scraper.d.ts +11 -0
  68. package/dist/scraper.d.ts.map +1 -0
  69. package/dist/scraper.js +159 -0
  70. package/dist/scraper.js.map +1 -0
  71. package/dist/slack/auth.d.ts +6 -0
  72. package/dist/slack/auth.d.ts.map +1 -0
  73. package/dist/slack/auth.js +373 -0
  74. package/dist/slack/auth.js.map +1 -0
  75. package/dist/slack/browser-auth.d.ts +6 -0
  76. package/dist/slack/browser-auth.d.ts.map +1 -0
  77. package/dist/slack/browser-auth.js +236 -0
  78. package/dist/slack/browser-auth.js.map +1 -0
  79. package/dist/slack/client.d.ts +45 -0
  80. package/dist/slack/client.d.ts.map +1 -0
  81. package/dist/slack/client.js +98 -0
  82. package/dist/slack/client.js.map +1 -0
  83. package/dist/slack/index.d.ts +6 -0
  84. package/dist/slack/index.d.ts.map +1 -0
  85. package/dist/slack/index.js +4 -0
  86. package/dist/slack/index.js.map +1 -0
  87. package/dist/slack/sync.d.ts +12 -0
  88. package/dist/slack/sync.d.ts.map +1 -0
  89. package/dist/slack/sync.js +182 -0
  90. package/dist/slack/sync.js.map +1 -0
  91. package/dist/types.d.ts +64 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +2 -0
  94. package/dist/types.js.map +1 -0
  95. package/dist/utils.d.ts +3 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +15 -0
  98. package/dist/utils.js.map +1 -0
  99. package/package.json +71 -0
@@ -0,0 +1,45 @@
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
+ }
45
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,98 @@
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
+ }
98
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/slack/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AA8B5B,MAAM,OAAO,WAAW;IACd,KAAK,CAAS;IACd,MAAM,CAAS;IACf,OAAO,GAAG,uBAAuB,CAAC;IAE1C,YAAY,IAAqB;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,SAAiC,EAAE;QAC1E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE,CAAC,CAAC;QAEjD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;gBACvC,QAAQ,EAAE,KAAK,IAAI,CAAC,MAAM,EAAE;gBAC5B,cAAc,EAAE,mCAAmC;aACpD;YACD,IAAI,EAAE,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;SAC7C,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAyC,CAAC;QAE1E,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAkD,WAAW,CAAC,CAAC;QAClG,OAAO;YACL,EAAE,EAAE,QAAQ,CAAC,OAAO;YACpB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,aAAa,GAAwB,EAAE,CAAC;QAC9C,IAAI,MAA0B,CAAC;QAE/B,GAAG,CAAC;YACF,MAAM,MAAM,GAA2B;gBACrC,KAAK,EAAE,wCAAwC;gBAC/C,KAAK,EAAE,KAAK;gBACZ,gBAAgB,EAAE,MAAM;aACzB,CAAC;YAEF,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACzB,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAUhC,oBAAoB,EAAE,MAAM,CAAC,CAAC;YAEjC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACxC,aAAa,CAAC,IAAI,CAAC;oBACjB,EAAE,EAAE,OAAO,CAAC,EAAE;oBACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE;oBAChC,SAAS,EAAE,OAAO,CAAC,UAAU;oBAC7B,IAAI,EAAE,OAAO,CAAC,KAAK;oBACnB,MAAM,EAAE,OAAO,CAAC,OAAO;oBACvB,IAAI,EAAE,OAAO,CAAC,IAAI;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,GAAG,QAAQ,CAAC,iBAAiB,EAAE,WAAW,CAAC;QACnD,CAAC,QAAQ,MAAM,EAAE;QAEjB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAc;QAC9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAEhC,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAEnC,OAAO;YACL,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE;YACpB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI;YACxB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS;SAClC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,sBAAsB,CAC1B,SAAiB,EACjB,UAAgE,EAAE;QAElE,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,IAAI,MAA0B,CAAC;QAC/B,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;QAEnC,GAAG,CAAC;YACF,MAAM,MAAM,GAA2B;gBACrC,OAAO,EAAE,SAAS;gBAClB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,OAAO,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;aACjD,CAAC;YAEF,IAAI,MAAM;gBAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YACnC,IAAI,OAAO,CAAC,MAAM;gBAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YACnD,IAAI,OAAO,CAAC,MAAM;gBAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAGhC,uBAAuB,EAAE,MAAM,CAAC,CAAC;YAEpC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YACpC,MAAM,GAAG,QAAQ,CAAC,iBAAiB,EAAE,WAAW,CAAC;QACnD,CAAC,QAAQ,MAAM,IAAI,OAAO,GAAG,KAAK,EAAE;QAEpC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gBAAgB;QACd,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export { SlackClient } from './client.js';
2
+ export type { SlackAuthConfig, SlackUser, SlackConversation, SlackMessage } from './client.js';
3
+ export { addSlackSource, listSlackSources, removeSlackSource, addChannelToSource, removeChannelFromSource } from './auth.js';
4
+ export { syncSlackSources } from './sync.js';
5
+ export type { SyncResult } from './sync.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/slack/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { SlackClient } from './client.js';
2
+ export { addSlackSource, listSlackSources, removeSlackSource, addChannelToSource, removeChannelFromSource } from './auth.js';
3
+ export { syncSlackSources } from './sync.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/slack/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAC7H,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { loadConfig } from '../config.js';
2
+ export interface SyncResult {
3
+ total: number;
4
+ newArticles: number;
5
+ skipped: number;
6
+ filtered: number;
7
+ }
8
+ export interface SyncOptions {
9
+ silent?: boolean;
10
+ }
11
+ export declare function syncSlackSources(config?: ReturnType<typeof loadConfig>, options?: SyncOptions): Promise<SyncResult>;
12
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,182 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import crypto from 'crypto';
4
+ import { SlackClient } from './client.js';
5
+ import { loadConfig } from '../config.js';
6
+ import { insertArticle, articleExists } from '../db.js';
7
+ import { classifyContent } from '../ai.js';
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
+ export async function syncSlackSources(config, options = {}) {
84
+ const cfg = config || loadConfig();
85
+ const { silent = false } = options;
86
+ const sources = cfg.sources.slack || [];
87
+ if (sources.length === 0) {
88
+ if (!silent) {
89
+ console.log(chalk.yellow(`\n${t('sync.noSources')}`));
90
+ console.log(chalk.dim(t('sync.noSourcesHint')));
91
+ }
92
+ return { total: 0, newArticles: 0, skipped: 0, filtered: 0 };
93
+ }
94
+ let totalUrls = 0;
95
+ let newArticles = 0;
96
+ let skipped = 0;
97
+ let filtered = 0;
98
+ for (const source of sources) {
99
+ if (!silent) {
100
+ console.log(chalk.bold(`\n📡 ${t('sync.syncing', { workspace: source.workspace })}`));
101
+ }
102
+ const client = new SlackClient({ token: source.token, cookie: source.cookie });
103
+ for (const channel of source.channels) {
104
+ const spinner = silent ? null : ora(t('sync.fetching', { channel: channel.name })).start();
105
+ try {
106
+ 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
+ }, []);
122
+ totalUrls += uniqueLinks.length;
123
+ let channelNew = 0;
124
+ let channelSkipped = 0;
125
+ let channelFiltered = 0;
126
+ let processed = 0;
127
+ for (const link of uniqueLinks) {
128
+ processed++;
129
+ if (spinner) {
130
+ spinner.text = t('sync.classifying', {
131
+ channel: channel.name,
132
+ current: processed,
133
+ total: uniqueLinks.length
134
+ });
135
+ }
136
+ if (articleExists(link.url)) {
137
+ channelSkipped++;
138
+ skipped++;
139
+ continue;
140
+ }
141
+ const classification = await classifyContent(link.messageText, link.url, '', '');
142
+ if (!classification.shouldCollect) {
143
+ channelFiltered++;
144
+ filtered++;
145
+ if (!silent) {
146
+ console.log(chalk.dim(` ✗ ${link.url}`));
147
+ console.log(chalk.dim(` → ${classification.reasoning}`));
148
+ }
149
+ continue;
150
+ }
151
+ const article = {
152
+ id: crypto.randomUUID(),
153
+ url: link.url,
154
+ title: link.url,
155
+ tags: [],
156
+ sourceType: 'slack',
157
+ sourceId: channel.id,
158
+ createdAt: new Date(),
159
+ };
160
+ insertArticle(article);
161
+ channelNew++;
162
+ newArticles++;
163
+ }
164
+ spinner?.succeed(t('sync.channelResult', {
165
+ channel: channel.name,
166
+ total: uniqueLinks.length,
167
+ new: channelNew,
168
+ existing: channelSkipped,
169
+ filtered: channelFiltered,
170
+ }));
171
+ }
172
+ catch (error) {
173
+ spinner?.fail(t('sync.channelFailed', { channel: channel.name }));
174
+ if (error instanceof Error && !silent) {
175
+ console.log(chalk.dim(` Error: ${error.message}`));
176
+ }
177
+ }
178
+ }
179
+ }
180
+ return { total: totalUrls, newArticles, skipped, filtered };
181
+ }
182
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/slack/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
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';
34
+ export interface Config {
35
+ sources: {
36
+ slack?: SlackSource[];
37
+ };
38
+ ai: {
39
+ provider: AIProvider;
40
+ apiKey?: string;
41
+ model: string;
42
+ language: string;
43
+ };
44
+ output: {
45
+ directory: string;
46
+ format: 'html' | 'markdown' | 'both';
47
+ };
48
+ }
49
+ export interface Magazine {
50
+ id: string;
51
+ title: string;
52
+ generatedAt: Date;
53
+ articles: Article[];
54
+ period: {
55
+ from: Date;
56
+ to: Date;
57
+ };
58
+ }
59
+ export interface CommandContext {
60
+ configDir: string;
61
+ config: Config;
62
+ db: unknown;
63
+ }
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export declare function truncate(str: string, maxLength: number): string;
2
+ export declare function isValidUrl(str: string): boolean;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +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"}
package/dist/utils.js ADDED
@@ -0,0 +1,15 @@
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
+ }
15
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +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"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "linkpress",
3
+ "version": "0.1.0",
4
+ "description": "Turn your Slack links into a personal tech magazine with AI-powered summaries",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "linkpress": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "start": "node dist/index.js",
17
+ "lint": "eslint src --ext .ts",
18
+ "typecheck": "tsc --noEmit",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "slack",
23
+ "newsletter",
24
+ "magazine",
25
+ "cli",
26
+ "ai",
27
+ "curation",
28
+ "linkpress",
29
+ "tech",
30
+ "summary",
31
+ "claude",
32
+ "openai",
33
+ "gemini"
34
+ ],
35
+ "author": "realmindori@gmail.com",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/mindori/linkpress"
40
+ },
41
+ "homepage": "https://github.com/mindori/linkpress#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/mindori/linkpress/issues"
44
+ },
45
+ "dependencies": {
46
+ "@anthropic-ai/sdk": "^0.39.0",
47
+ "@google/generative-ai": "^0.24.1",
48
+ "better-sqlite3": "^11.7.0",
49
+ "chalk": "^5.3.0",
50
+ "cheerio": "^1.0.0",
51
+ "commander": "^12.1.0",
52
+ "express": "^4.21.2",
53
+ "inquirer": "^12.3.2",
54
+ "node-fetch": "^3.3.2",
55
+ "open": "^10.1.0",
56
+ "openai": "^6.16.0",
57
+ "ora": "^8.1.1",
58
+ "playwright": "^1.57.0",
59
+ "yaml": "^2.7.0"
60
+ },
61
+ "devDependencies": {
62
+ "@types/better-sqlite3": "^7.6.12",
63
+ "@types/express": "^5.0.0",
64
+ "@types/inquirer": "^9.0.7",
65
+ "@types/node": "^22.10.7",
66
+ "typescript": "^5.7.3"
67
+ },
68
+ "engines": {
69
+ "node": ">=18.0.0"
70
+ }
71
+ }