opencode-agora 0.3.0 → 0.4.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 (168) hide show
  1. package/README.md +217 -52
  2. package/dist/cli/app.d.ts +3 -0
  3. package/dist/cli/app.d.ts.map +1 -1
  4. package/dist/cli/app.js +1053 -183
  5. package/dist/cli/app.js.map +1 -1
  6. package/dist/cli/chat-renderer.d.ts +31 -0
  7. package/dist/cli/chat-renderer.d.ts.map +1 -0
  8. package/dist/cli/chat-renderer.js +275 -0
  9. package/dist/cli/chat-renderer.js.map +1 -0
  10. package/dist/cli/commands-meta.d.ts +21 -0
  11. package/dist/cli/commands-meta.d.ts.map +1 -0
  12. package/dist/cli/commands-meta.js +600 -0
  13. package/dist/cli/commands-meta.js.map +1 -0
  14. package/dist/cli/completions.d.ts +18 -0
  15. package/dist/cli/completions.d.ts.map +1 -0
  16. package/dist/cli/completions.js +190 -0
  17. package/dist/cli/completions.js.map +1 -0
  18. package/dist/cli/mcp-server.d.ts +4 -0
  19. package/dist/cli/mcp-server.d.ts.map +1 -0
  20. package/dist/cli/mcp-server.js +277 -0
  21. package/dist/cli/mcp-server.js.map +1 -0
  22. package/dist/cli/menu.d.ts +7 -0
  23. package/dist/cli/menu.d.ts.map +1 -0
  24. package/dist/cli/menu.js +164 -0
  25. package/dist/cli/menu.js.map +1 -0
  26. package/dist/cli/pages/community.d.ts +3 -0
  27. package/dist/cli/pages/community.d.ts.map +1 -0
  28. package/dist/cli/pages/community.js +276 -0
  29. package/dist/cli/pages/community.js.map +1 -0
  30. package/dist/cli/pages/helpers.d.ts +32 -0
  31. package/dist/cli/pages/helpers.d.ts.map +1 -0
  32. package/dist/cli/pages/helpers.js +67 -0
  33. package/dist/cli/pages/helpers.js.map +1 -0
  34. package/dist/cli/pages/home.d.ts +3 -0
  35. package/dist/cli/pages/home.d.ts.map +1 -0
  36. package/dist/cli/pages/home.js +148 -0
  37. package/dist/cli/pages/home.js.map +1 -0
  38. package/dist/cli/pages/marketplace.d.ts +3 -0
  39. package/dist/cli/pages/marketplace.d.ts.map +1 -0
  40. package/dist/cli/pages/marketplace.js +179 -0
  41. package/dist/cli/pages/marketplace.js.map +1 -0
  42. package/dist/cli/pages/news.d.ts +3 -0
  43. package/dist/cli/pages/news.d.ts.map +1 -0
  44. package/dist/cli/pages/news.js +561 -0
  45. package/dist/cli/pages/news.js.map +1 -0
  46. package/dist/cli/pages/settings.d.ts +3 -0
  47. package/dist/cli/pages/settings.d.ts.map +1 -0
  48. package/dist/cli/pages/settings.js +166 -0
  49. package/dist/cli/pages/settings.js.map +1 -0
  50. package/dist/cli/pages/types.d.ts +67 -0
  51. package/dist/cli/pages/types.d.ts.map +1 -0
  52. package/dist/cli/pages/types.js +2 -0
  53. package/dist/cli/pages/types.js.map +1 -0
  54. package/dist/cli/prompter.d.ts +135 -0
  55. package/dist/cli/prompter.d.ts.map +1 -0
  56. package/dist/cli/prompter.js +675 -0
  57. package/dist/cli/prompter.js.map +1 -0
  58. package/dist/cli/shell.d.ts +23 -0
  59. package/dist/cli/shell.d.ts.map +1 -0
  60. package/dist/cli/shell.js +819 -0
  61. package/dist/cli/shell.js.map +1 -0
  62. package/dist/cli/tui.d.ts +7 -0
  63. package/dist/cli/tui.d.ts.map +1 -0
  64. package/dist/cli/tui.js +373 -0
  65. package/dist/cli/tui.js.map +1 -0
  66. package/dist/cli.js +1 -1
  67. package/dist/cli.js.map +1 -1
  68. package/dist/commands.d.ts +14 -0
  69. package/dist/commands.d.ts.map +1 -0
  70. package/dist/commands.js +28 -0
  71. package/dist/commands.js.map +1 -0
  72. package/dist/community/client.d.ts +47 -0
  73. package/dist/community/client.d.ts.map +1 -0
  74. package/dist/community/client.js +245 -0
  75. package/dist/community/client.js.map +1 -0
  76. package/dist/community/types.d.ts +50 -0
  77. package/dist/community/types.d.ts.map +1 -0
  78. package/dist/community/types.js +11 -0
  79. package/dist/community/types.js.map +1 -0
  80. package/dist/config.d.ts +1 -3
  81. package/dist/config.d.ts.map +1 -1
  82. package/dist/config.js +0 -17
  83. package/dist/config.js.map +1 -1
  84. package/dist/data.d.ts +1 -1
  85. package/dist/data.d.ts.map +1 -1
  86. package/dist/data.js +667 -3
  87. package/dist/data.js.map +1 -1
  88. package/dist/format.d.ts +5 -39
  89. package/dist/format.d.ts.map +1 -1
  90. package/dist/format.js +5 -120
  91. package/dist/format.js.map +1 -1
  92. package/dist/history.d.ts +13 -0
  93. package/dist/history.d.ts.map +1 -0
  94. package/dist/history.js +37 -0
  95. package/dist/history.js.map +1 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +114 -234
  98. package/dist/index.js.map +1 -1
  99. package/dist/init.d.ts.map +1 -1
  100. package/dist/init.js +4 -9
  101. package/dist/init.js.map +1 -1
  102. package/dist/live.d.ts +4 -0
  103. package/dist/live.d.ts.map +1 -1
  104. package/dist/live.js +11 -3
  105. package/dist/live.js.map +1 -1
  106. package/dist/marketplace.d.ts +9 -0
  107. package/dist/marketplace.d.ts.map +1 -1
  108. package/dist/marketplace.js +105 -15
  109. package/dist/marketplace.js.map +1 -1
  110. package/dist/news/cache.d.ts +13 -0
  111. package/dist/news/cache.d.ts.map +1 -0
  112. package/dist/news/cache.js +65 -0
  113. package/dist/news/cache.js.map +1 -0
  114. package/dist/news/score.d.ts +4 -0
  115. package/dist/news/score.d.ts.map +1 -0
  116. package/dist/news/score.js +43 -0
  117. package/dist/news/score.js.map +1 -0
  118. package/dist/news/sources/arxiv.d.ts +9 -0
  119. package/dist/news/sources/arxiv.d.ts.map +1 -0
  120. package/dist/news/sources/arxiv.js +103 -0
  121. package/dist/news/sources/arxiv.js.map +1 -0
  122. package/dist/news/sources/github-trending.d.ts +9 -0
  123. package/dist/news/sources/github-trending.d.ts.map +1 -0
  124. package/dist/news/sources/github-trending.js +93 -0
  125. package/dist/news/sources/github-trending.js.map +1 -0
  126. package/dist/news/sources/hn.d.ts +9 -0
  127. package/dist/news/sources/hn.d.ts.map +1 -0
  128. package/dist/news/sources/hn.js +53 -0
  129. package/dist/news/sources/hn.js.map +1 -0
  130. package/dist/news/sources/reddit.d.ts +9 -0
  131. package/dist/news/sources/reddit.d.ts.map +1 -0
  132. package/dist/news/sources/reddit.js +68 -0
  133. package/dist/news/sources/reddit.js.map +1 -0
  134. package/dist/news/sources/rss.d.ts +14 -0
  135. package/dist/news/sources/rss.d.ts.map +1 -0
  136. package/dist/news/sources/rss.js +102 -0
  137. package/dist/news/sources/rss.js.map +1 -0
  138. package/dist/news/types.d.ts +39 -0
  139. package/dist/news/types.d.ts.map +1 -0
  140. package/dist/news/types.js +47 -0
  141. package/dist/news/types.js.map +1 -0
  142. package/dist/preferences.d.ts +14 -0
  143. package/dist/preferences.d.ts.map +1 -0
  144. package/dist/preferences.js +31 -0
  145. package/dist/preferences.js.map +1 -0
  146. package/dist/settings.d.ts +26 -0
  147. package/dist/settings.d.ts.map +1 -0
  148. package/dist/settings.js +257 -0
  149. package/dist/settings.js.map +1 -0
  150. package/dist/transcript.d.ts +28 -0
  151. package/dist/transcript.d.ts.map +1 -0
  152. package/dist/transcript.js +79 -0
  153. package/dist/transcript.js.map +1 -0
  154. package/dist/types.d.ts +6 -1
  155. package/dist/types.d.ts.map +1 -1
  156. package/dist/ui.d.ts +157 -0
  157. package/dist/ui.d.ts.map +1 -0
  158. package/dist/ui.js +296 -0
  159. package/dist/ui.js.map +1 -0
  160. package/package.json +11 -9
  161. package/dist/api.d.ts +0 -72
  162. package/dist/api.d.ts.map +0 -1
  163. package/dist/api.js +0 -109
  164. package/dist/api.js.map +0 -1
  165. package/dist/logger.d.ts +0 -20
  166. package/dist/logger.d.ts.map +0 -1
  167. package/dist/logger.js +0 -59
  168. package/dist/logger.js.map +0 -1
@@ -0,0 +1,103 @@
1
+ const QUERY_CATEGORIES = ['cs.AI', 'cs.CL', 'cs.SE', 'cs.LG'];
2
+ const MAX_RESULTS = 25;
3
+ export const arxivSource = {
4
+ async fetch(opts) {
5
+ const fetcher = opts.fetcher ?? globalThis.fetch;
6
+ const allItems = [];
7
+ const now = new Date().toISOString();
8
+ const categories = QUERY_CATEGORIES.join('+OR+');
9
+ const url = `http://export.arxiv.org/api/query?search_query=cat:${categories}&sortBy=submittedDate&sortOrder=descending&max_results=${MAX_RESULTS}`;
10
+ try {
11
+ const res = await fetcher(url, {
12
+ signal: opts.signal,
13
+ headers: { 'User-Agent': 'agora-cli/0.5.0' },
14
+ });
15
+ if (!res.ok)
16
+ throw new Error(`arXiv API returned ${res.status}`);
17
+ const xml = await res.text();
18
+ const items = parseArxivAtom(xml, now);
19
+ allItems.push(...items);
20
+ }
21
+ catch (e) {
22
+ if (e instanceof Error && e.name !== 'AbortError')
23
+ throw e;
24
+ }
25
+ return allItems;
26
+ },
27
+ };
28
+ function parseArxivAtom(xml, now) {
29
+ const items = [];
30
+ const entryRegex = /<entry>([\s\S]*?)<\/entry>/gi;
31
+ let match;
32
+ while ((match = entryRegex.exec(xml)) !== null) {
33
+ try {
34
+ const entry = match[1];
35
+ const idMatch = entry.match(/<id>([^<]+)<\/id>/);
36
+ if (!idMatch)
37
+ continue;
38
+ const paperUrl = idMatch[1].trim();
39
+ const paperId = paperUrl.split('/').pop() || paperUrl;
40
+ const titleMatch = entry.match(/<title>([\s\S]*?)<\/title>/);
41
+ const title = titleMatch ? cleanXml(titleMatch[1]) : '';
42
+ const summaryMatch = entry.match(/<summary>([\s\S]*?)<\/summary>/);
43
+ const summary = summaryMatch ? cleanXml(summaryMatch[1]).slice(0, 300) : '';
44
+ const publishedMatch = entry.match(/<published>([^<]+)<\/published>/);
45
+ const published = publishedMatch ? publishedMatch[1].trim() : now;
46
+ const authorRegex = /<author>[\s\S]*?<name>([^<]+)<\/name>[\s\S]*?<\/author>/gi;
47
+ const authors = [];
48
+ let aMatch;
49
+ while ((aMatch = authorRegex.exec(entry)) !== null) {
50
+ authors.push(cleanXml(aMatch[1]));
51
+ }
52
+ const catRegex = /<category[^>]*term="([^"]+)"[^>]*\/>/gi;
53
+ const categories = [];
54
+ let cMatch;
55
+ while ((cMatch = catRegex.exec(entry)) !== null) {
56
+ categories.push(cMatch[1]);
57
+ }
58
+ items.push({
59
+ id: `arxiv:${paperId}`,
60
+ source: 'arxiv',
61
+ title,
62
+ url: `https://arxiv.org/abs/${paperId}`,
63
+ author: authors[0] || 'Unknown',
64
+ publishedAt: published,
65
+ fetchedAt: now,
66
+ engagement: 0,
67
+ tags: extractArxivTags(categories, title, summary),
68
+ summary: summary || undefined,
69
+ });
70
+ }
71
+ catch {
72
+ continue;
73
+ }
74
+ }
75
+ return items;
76
+ }
77
+ function extractArxivTags(categories, title, summary) {
78
+ const tags = [];
79
+ const lower = (title + ' ' + summary).toLowerCase();
80
+ for (const cat of categories) {
81
+ tags.push(cat.replace(/\./g, '-').toLowerCase());
82
+ }
83
+ const topicMap = {
84
+ ai: ['artificial intelligence', 'machine learning', 'deep learning'],
85
+ llm: ['language model', 'llm', 'gpt', 'transformer', 'attention'],
86
+ agents: ['agent', 'tool use', 'tool-use', 'function calling'],
87
+ coding: ['code generation', 'program synthesis', 'software engineering'],
88
+ security: ['security', 'safety', 'alignment', 'harmlessness'],
89
+ };
90
+ for (const [topic, keywords] of Object.entries(topicMap)) {
91
+ for (const kw of keywords) {
92
+ if (lower.includes(kw)) {
93
+ tags.push(topic);
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ return tags;
99
+ }
100
+ function cleanXml(text) {
101
+ return text.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
102
+ }
103
+ //# sourceMappingURL=arxiv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arxiv.js","sourceRoot":"","sources":["../../../src/news/sources/arxiv.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { NewsItem } from '../types.js';
2
+ export interface SourceAdapter {
3
+ fetch(opts: {
4
+ fetcher?: (url: string, init?: RequestInit) => Promise<Response>;
5
+ signal?: AbortSignal;
6
+ }): Promise<NewsItem[]>;
7
+ }
8
+ export declare const githubTrendingSource: SourceAdapter;
9
+ //# sourceMappingURL=github-trending.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-trending.d.ts","sourceRoot":"","sources":["../../../src/news/sources/github-trending.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC9H;AAID,eAAO,MAAM,oBAAoB,EAAE,aAwBlC,CAAC"}
@@ -0,0 +1,93 @@
1
+ const LANGUAGES = ['typescript', 'python', 'go', 'rust'];
2
+ export const githubTrendingSource = {
3
+ async fetch(opts) {
4
+ const fetcher = opts.fetcher ?? globalThis.fetch;
5
+ const allItems = [];
6
+ const now = new Date().toISOString();
7
+ for (const lang of LANGUAGES) {
8
+ try {
9
+ const url = `https://github.com/trending/${lang}?since=daily`;
10
+ const res = await fetcher(url, {
11
+ signal: opts.signal,
12
+ headers: { 'User-Agent': 'agora-cli/0.5.0' },
13
+ });
14
+ if (!res.ok)
15
+ continue;
16
+ const html = await res.text();
17
+ const items = parseTrendingHtml(html, lang, now);
18
+ allItems.push(...items);
19
+ }
20
+ catch {
21
+ continue;
22
+ }
23
+ }
24
+ return allItems;
25
+ },
26
+ };
27
+ function parseTrendingHtml(html, lang, now) {
28
+ const items = [];
29
+ const articleRegex = /<article[^>]*>([\s\S]*?)<\/article>/gi;
30
+ let match;
31
+ while ((match = articleRegex.exec(html)) !== null) {
32
+ try {
33
+ const article = match[1];
34
+ const repoMatch = article.match(/<h2[^>]*>[\s\S]*?<a[^>]*href="\/([^"]+)"[^>]*>/i);
35
+ if (!repoMatch)
36
+ continue;
37
+ const repoPath = repoMatch[1];
38
+ const descMatch = article.match(/<p[^>]*class="[^"]*col-9[^"]*"[^>]*>([\s\S]*?)<\/p>/i);
39
+ const description = descMatch ? stripHtml(descMatch[1]).trim() : '';
40
+ const starsMatch = article.match(/<span[^>]*class="[^"]*d-inline-block[^"]*float-sm-right[^"]*"[^>]*>([\s\S]*?)<\/span>/i);
41
+ const starsStr = starsMatch ? stripHtml(starsMatch[1]).trim().replace(/,/g, '') : '0';
42
+ const stars = parseInt(starsStr, 10) || 0;
43
+ const forksMatch = article.match(/<a[^>]*href="\/[^"]+\/fork"[^>]*>([\s\S]*?)<\/a>/i);
44
+ const forksStr = forksMatch ? stripHtml(forksMatch[1]).trim().replace(/,/g, '') : '0';
45
+ const forks = parseInt(forksStr, 10) || 0;
46
+ const [owner, repo] = repoPath.split('/');
47
+ const id = `gh:${repoPath.replace('/', '-')}`;
48
+ const engagement = stars + forks;
49
+ items.push({
50
+ id,
51
+ source: 'github-trending',
52
+ title: `${owner}/${repo}`,
53
+ url: `https://github.com/${repoPath}`,
54
+ author: owner,
55
+ publishedAt: now,
56
+ fetchedAt: now,
57
+ engagement,
58
+ tags: extractGithubTags(repoPath, description, lang),
59
+ summary: description || undefined,
60
+ });
61
+ }
62
+ catch {
63
+ continue;
64
+ }
65
+ }
66
+ return items;
67
+ }
68
+ function extractGithubTags(repoPath, description, lang) {
69
+ const tags = new Set();
70
+ const lower = (repoPath + ' ' + description).toLowerCase();
71
+ tags.add(lang);
72
+ const topicMap = {
73
+ mcp: ['mcp', 'model-context-protocol', 'modelcontextprotocol'],
74
+ ai: ['ai', 'artificial-intelligence', 'llm', 'machine-learning'],
75
+ agents: ['agent', 'agents', 'autonomous'],
76
+ tools: ['cli', 'tool', 'framework', 'sdk'],
77
+ database: ['database', 'sql', 'nosql', 'postgres', 'redis', 'sqlite'],
78
+ devtools: ['devtools', 'developer-tools', 'github', 'git'],
79
+ };
80
+ for (const [topic, keywords] of Object.entries(topicMap)) {
81
+ for (const kw of keywords) {
82
+ if (lower.includes(kw)) {
83
+ tags.add(topic);
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ return Array.from(tags);
89
+ }
90
+ function stripHtml(html) {
91
+ return html.replace(/<[^>]*>/g, '').replace(/[\s\n]+/g, ' ').trim();
92
+ }
93
+ //# sourceMappingURL=github-trending.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-trending.js","sourceRoot":"","sources":["../../../src/news/sources/github-trending.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { NewsItem } from '../types.js';
2
+ export interface SourceAdapter {
3
+ fetch(opts: {
4
+ fetcher?: (url: string, init?: RequestInit) => Promise<Response>;
5
+ signal?: AbortSignal;
6
+ }): Promise<NewsItem[]>;
7
+ }
8
+ export declare const hnSource: SourceAdapter;
9
+ //# sourceMappingURL=hn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hn.d.ts","sourceRoot":"","sources":["../../../src/news/sources/hn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC9H;AAED,eAAO,MAAM,QAAQ,EAAE,aA0BtB,CAAC"}
@@ -0,0 +1,53 @@
1
+ export const hnSource = {
2
+ async fetch(opts) {
3
+ const fetcher = opts.fetcher ?? globalThis.fetch;
4
+ const url = 'https://hn.algolia.com/api/v1/search?tags=front_page&numericFilters=points>50&hitsPerPage=30';
5
+ const res = await fetcher(url, { signal: opts.signal });
6
+ if (!res.ok)
7
+ throw new Error(`HN API returned ${res.status}`);
8
+ const data = (await res.json());
9
+ const now = new Date().toISOString();
10
+ return (data.hits ?? []).map((hit) => {
11
+ const item = {
12
+ id: `hn:${hit.objectID}`,
13
+ source: 'hn',
14
+ title: hit.title ?? '',
15
+ url: hit.url || `https://news.ycombinator.com/item?id=${hit.objectID}`,
16
+ author: hit.author,
17
+ publishedAt: new Date(hit.created_at).toISOString(),
18
+ fetchedAt: now,
19
+ engagement: hit.points ?? 0,
20
+ tags: extractHnTags(hit),
21
+ };
22
+ return item;
23
+ });
24
+ },
25
+ };
26
+ function extractHnTags(hit) {
27
+ const tags = [];
28
+ const title = (hit.title ?? '').toLowerCase();
29
+ const url = (hit.url ?? '').toLowerCase();
30
+ const topicMap = {
31
+ mcp: ['mcp', 'model-context-protocol', 'modelcontextprotocol'],
32
+ ai: ['ai', 'artificial-intelligence'],
33
+ llm: ['llm', 'large-language-model', 'gpt', 'claude', 'gemini'],
34
+ agents: ['agent', 'agents', 'autonomous'],
35
+ coding: ['coding', 'programming', 'software', 'developer'],
36
+ security: ['security', 'vulnerability', 'exploit'],
37
+ devtools: ['devtools', 'developer-tools', 'sdk', 'api'],
38
+ };
39
+ for (const [topic, keywords] of Object.entries(topicMap)) {
40
+ for (const kw of keywords) {
41
+ if (title.includes(kw) || url.includes(kw)) {
42
+ tags.push(topic);
43
+ break;
44
+ }
45
+ }
46
+ }
47
+ if ((hit._tags ?? []).includes('show'))
48
+ tags.push('show');
49
+ if ((hit._tags ?? []).includes('ask'))
50
+ tags.push('ask');
51
+ return tags;
52
+ }
53
+ //# sourceMappingURL=hn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hn.js","sourceRoot":"","sources":["../../../src/news/sources/hn.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,KAAK,CAAC,KAAK,CAAC,IAAI;QACd,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC;QACjD,MAAM,GAAG,GACP,8FAA8F,CAAC;QAEjG,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAQ,CAAC;QAEvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE;YACxC,MAAM,IAAI,GAAa;gBACrB,EAAE,EAAE,MAAM,GAAG,CAAC,QAAQ,EAAE;gBACxB,MAAM,EAAE,IAAkB;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE;gBACtB,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,wCAAwC,GAAG,CAAC,QAAQ,EAAE;gBACtE,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,WAAW,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;gBACnD,SAAS,EAAE,GAAG;gBACd,UAAU,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC;gBAC3B,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC;aACzB,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,SAAS,aAAa,CAAC,GAAQ;IAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAE1C,MAAM,QAAQ,GAA6B;QACzC,GAAG,EAAE,CAAC,KAAK,EAAE,wBAAwB,EAAE,sBAAsB,CAAC;QAC9D,EAAE,EAAE,CAAC,IAAI,EAAE,yBAAyB,CAAC;QACrC,GAAG,EAAE,CAAC,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC;QAC/D,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC;QACzC,MAAM,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,CAAC;QAC1D,QAAQ,EAAE,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,CAAC;QAClD,QAAQ,EAAE,CAAC,UAAU,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,CAAC;KACxD,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAExD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { NewsItem } from '../types.js';
2
+ export interface SourceAdapter {
3
+ fetch(opts: {
4
+ fetcher?: (url: string, init?: RequestInit) => Promise<Response>;
5
+ signal?: AbortSignal;
6
+ }): Promise<NewsItem[]>;
7
+ }
8
+ export declare const redditSource: SourceAdapter;
9
+ //# sourceMappingURL=reddit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit.d.ts","sourceRoot":"","sources":["../../../src/news/sources/reddit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC9H;AAID,eAAO,MAAM,YAAY,EAAE,aAuC1B,CAAC"}
@@ -0,0 +1,68 @@
1
+ const SUBREDDITS = ['mcp', 'LocalLLaMA', 'programming', 'MachineLearning'];
2
+ export const redditSource = {
3
+ async fetch(opts) {
4
+ const fetcher = opts.fetcher ?? globalThis.fetch;
5
+ const allItems = [];
6
+ const now = new Date().toISOString();
7
+ for (const sub of SUBREDDITS) {
8
+ try {
9
+ const url = `https://www.reddit.com/r/${sub}/hot.json?limit=25`;
10
+ const res = await fetcher(url, {
11
+ signal: opts.signal,
12
+ headers: { 'User-Agent': 'agora-cli/0.5.0' },
13
+ });
14
+ if (!res.ok)
15
+ continue;
16
+ const data = (await res.json());
17
+ const children = data?.data?.children ?? [];
18
+ for (const child of children) {
19
+ const post = child?.data;
20
+ if (!post || post.stickied)
21
+ continue;
22
+ allItems.push({
23
+ id: `reddit:${post.id}`,
24
+ source: 'reddit',
25
+ title: post.title ?? '',
26
+ url: `https://reddit.com${post.permalink}`,
27
+ author: post.author,
28
+ publishedAt: new Date(post.created_utc * 1000).toISOString(),
29
+ fetchedAt: now,
30
+ engagement: post.ups ?? 0,
31
+ tags: extractRedditTags(post, sub),
32
+ summary: post.selftext ? post.selftext.slice(0, 200) : undefined,
33
+ });
34
+ }
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ }
40
+ return allItems;
41
+ },
42
+ };
43
+ function extractRedditTags(post, subreddit) {
44
+ const tags = [];
45
+ const title = (post.title ?? '').toLowerCase();
46
+ const linkFlair = (post.link_flair_text ?? '').toLowerCase();
47
+ const subLower = subreddit.toLowerCase();
48
+ tags.push(subLower === 'localllama' ? 'llm' : subLower);
49
+ const topicMap = {
50
+ mcp: ['mcp', 'model-context-protocol'],
51
+ ai: ['ai', 'artificial intelligence'],
52
+ agents: ['agent'],
53
+ coding: ['code', 'programming', 'coding', 'developer'],
54
+ tools: ['tool', 'framework', 'library'],
55
+ };
56
+ for (const [topic, keywords] of Object.entries(topicMap)) {
57
+ for (const kw of keywords) {
58
+ if (title.includes(kw) || linkFlair.includes(kw)) {
59
+ tags.push(topic);
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ if (linkFlair)
65
+ tags.push(linkFlair.replace(/[^a-z0-9-]/g, ''));
66
+ return tags;
67
+ }
68
+ //# sourceMappingURL=reddit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit.js","sourceRoot":"","sources":["../../../src/news/sources/reddit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { NewsItem } from '../types.js';
2
+ export interface SourceAdapter {
3
+ fetch(opts: {
4
+ fetcher?: (url: string, init?: RequestInit) => Promise<Response>;
5
+ signal?: AbortSignal;
6
+ }): Promise<NewsItem[]>;
7
+ }
8
+ /**
9
+ * RSS feed adapter.
10
+ * Reads user-defined RSS feeds from settings. For each configured URL,
11
+ * fetches the feed XML and parses basic RSS 2.0 / Atom entries.
12
+ */
13
+ export declare const rssSource: SourceAdapter;
14
+ //# sourceMappingURL=rss.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.d.ts","sourceRoot":"","sources":["../../../src/news/sources/rss.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC9H;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,aAqDvB,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * RSS feed adapter.
3
+ * Reads user-defined RSS feeds from settings. For each configured URL,
4
+ * fetches the feed XML and parses basic RSS 2.0 / Atom entries.
5
+ */
6
+ export const rssSource = {
7
+ async fetch(opts) {
8
+ const fetcher = opts.fetcher ?? globalThis.fetch;
9
+ const now = new Date().toISOString();
10
+ const items = [];
11
+ const feedUrls = await getConfiguredFeeds();
12
+ for (const feedUrl of feedUrls) {
13
+ try {
14
+ const res = await fetcher(feedUrl, {
15
+ signal: opts.signal,
16
+ headers: { 'User-Agent': 'agora-cli/0.5.0' },
17
+ });
18
+ if (!res.ok)
19
+ continue;
20
+ const xml = await res.text();
21
+ const entryRegex = /<item>([\s\S]*?)<\/item>/gi;
22
+ let match;
23
+ while ((match = entryRegex.exec(xml)) !== null) {
24
+ const entry = match[1];
25
+ const title = extractXmlTag(entry, 'title');
26
+ const link = extractXmlTag(entry, 'link');
27
+ const pubDate = extractXmlTag(entry, 'pubDate');
28
+ const description = extractXmlTag(entry, 'description');
29
+ const creator = extractXmlTag(entry, 'dc:creator');
30
+ if (!title || !link)
31
+ continue;
32
+ const published = pubDate
33
+ ? new Date(pubDate).toISOString()
34
+ : now;
35
+ items.push({
36
+ id: `rss:${Buffer.from(link).toString('base64').slice(0, 32)}`,
37
+ source: 'rss',
38
+ title,
39
+ url: link,
40
+ author: creator || undefined,
41
+ publishedAt: published,
42
+ fetchedAt: now,
43
+ engagement: 0,
44
+ tags: ['rss', ...extractRssTags(title, description || '')],
45
+ summary: description ? stripHtml(description).slice(0, 200) : undefined,
46
+ });
47
+ }
48
+ }
49
+ catch {
50
+ continue;
51
+ }
52
+ }
53
+ return items;
54
+ },
55
+ };
56
+ async function getConfiguredFeeds() {
57
+ try {
58
+ const { loadSettings } = await import('../../settings.js');
59
+ const dataDir = process.env.AGORA_DATA_DIR || joinHome('.config', 'agora');
60
+ const settings = loadSettings(dataDir);
61
+ if (settings.news?.feeds && Array.isArray(settings.news.feeds)) {
62
+ return settings.news.feeds.filter(Boolean);
63
+ }
64
+ }
65
+ catch {
66
+ // settings not available
67
+ }
68
+ return [];
69
+ }
70
+ function extractXmlTag(xml, tag) {
71
+ const regex = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`, 'i');
72
+ const match = regex.exec(xml);
73
+ return match ? match[1].trim() : null;
74
+ }
75
+ function extractRssTags(title, description) {
76
+ const tags = [];
77
+ const lower = (title + ' ' + description).toLowerCase();
78
+ const topicMap = {
79
+ mcp: ['mcp', 'model-context-protocol'],
80
+ ai: ['ai', 'artificial intelligence'],
81
+ llm: ['llm', 'language model', 'gpt', 'claude'],
82
+ coding: ['coding', 'programming', 'software'],
83
+ devtools: ['devtools', 'developer tools'],
84
+ };
85
+ for (const [topic, keywords] of Object.entries(topicMap)) {
86
+ for (const kw of keywords) {
87
+ if (lower.includes(kw)) {
88
+ tags.push(topic);
89
+ break;
90
+ }
91
+ }
92
+ }
93
+ return tags;
94
+ }
95
+ function stripHtml(html) {
96
+ return html.replace(/<[^>]*>/g, '').replace(/[\s\n]+/g, ' ').trim();
97
+ }
98
+ function joinHome(...parts) {
99
+ const home = process.env.HOME || process.env.USERPROFILE || '';
100
+ return parts.length ? `${home}/${parts.join('/')}` : home;
101
+ }
102
+ //# sourceMappingURL=rss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.js","sourceRoot":"","sources":["../../../src/news/sources/rss.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export type NewsSource = 'hn' | 'reddit' | 'github-trending' | 'arxiv' | 'rss';
2
+ export interface NewsItem {
3
+ id: string;
4
+ source: NewsSource;
5
+ title: string;
6
+ url: string;
7
+ author?: string;
8
+ publishedAt: string;
9
+ fetchedAt: string;
10
+ engagement: number;
11
+ tags: string[];
12
+ summary?: string;
13
+ }
14
+ export interface ScoredNewsItem extends NewsItem {
15
+ score: number;
16
+ scoreBreakdown: {
17
+ recency: number;
18
+ engagement: number;
19
+ topic: number;
20
+ };
21
+ }
22
+ export interface NewsConfig {
23
+ sources: Record<NewsSource, {
24
+ enabled: boolean;
25
+ ttlMinutes: number;
26
+ }>;
27
+ topics: string[];
28
+ weights: {
29
+ recency: number;
30
+ engagement: number;
31
+ topic: number;
32
+ };
33
+ }
34
+ export declare const DEFAULT_NEWS_CONFIG: NewsConfig;
35
+ export declare const NEWS_SOURCE_LABELS: Record<NewsSource, string>;
36
+ export declare function normalizeNewsSource(s: string): NewsSource | undefined;
37
+ export declare function hostFromUrl(url: string): string;
38
+ export declare function slugFromUrl(url: string): string;
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/news/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,iBAAiB,GAAG,OAAO,GAAG,KAAK,CAAC;AAE/E,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACjE;AAED,eAAO,MAAM,mBAAmB,EAAE,UAUjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAMzD,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CASrE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO/C"}
@@ -0,0 +1,47 @@
1
+ export const DEFAULT_NEWS_CONFIG = {
2
+ sources: {
3
+ hn: { enabled: true, ttlMinutes: 10 },
4
+ reddit: { enabled: true, ttlMinutes: 15 },
5
+ 'github-trending': { enabled: true, ttlMinutes: 30 },
6
+ arxiv: { enabled: false, ttlMinutes: 60 },
7
+ rss: { enabled: false, ttlMinutes: 60 },
8
+ },
9
+ topics: ['mcp', 'ai', 'agents', 'workflows', 'llm', 'tool-use', 'coding', 'agents', 'security'],
10
+ weights: { recency: 1.0, engagement: 0.6, topic: 0.8 },
11
+ };
12
+ export const NEWS_SOURCE_LABELS = {
13
+ hn: 'Hacker News',
14
+ reddit: 'Reddit',
15
+ 'github-trending': 'GitHub Trending',
16
+ arxiv: 'arXiv',
17
+ rss: 'RSS',
18
+ };
19
+ export function normalizeNewsSource(s) {
20
+ const map = {
21
+ hn: 'hn', hackernews: 'hn', 'hacker-news': 'hn',
22
+ reddit: 'reddit',
23
+ gh: 'github-trending', github: 'github-trending', 'github-trending': 'github-trending',
24
+ arxiv: 'arxiv',
25
+ rss: 'rss',
26
+ };
27
+ return map[s.toLowerCase().trim()];
28
+ }
29
+ export function hostFromUrl(url) {
30
+ try {
31
+ const u = new URL(url);
32
+ return u.hostname.replace(/^www\./, '');
33
+ }
34
+ catch {
35
+ return '';
36
+ }
37
+ }
38
+ export function slugFromUrl(url) {
39
+ try {
40
+ const u = new URL(url);
41
+ return u.pathname.replace(/\/$/, '').split('/').filter(Boolean).slice(-2).join('/');
42
+ }
43
+ catch {
44
+ return '';
45
+ }
46
+ }
47
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/news/types.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,OAAO,EAAE;QACP,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QACrC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QACzC,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QACpD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE;QACzC,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE;KACxC;IACD,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC/F,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;CACvD,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAA+B;IAC5D,EAAE,EAAE,aAAa;IACjB,MAAM,EAAE,QAAQ;IAChB,iBAAiB,EAAE,iBAAiB;IACpC,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;CACX,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,CAAS;IAC3C,MAAM,GAAG,GAA+B;QACtC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI;QAC/C,MAAM,EAAE,QAAQ;QAChB,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB;QACtF,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,KAAK;KACX,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface LocalPreferences {
2
+ theme: 'dark' | 'light' | 'auto';
3
+ verbosity: 'verbose' | 'medium' | 'quiet';
4
+ defaultNewsSource: string;
5
+ defaultNewsCategory: string;
6
+ username: string;
7
+ email: string;
8
+ bio: string;
9
+ lastTab: number;
10
+ }
11
+ export declare function prefsPath(dataDir: string): string;
12
+ export declare function loadPreferences(dataDir: string): LocalPreferences;
13
+ export declare function writePreferences(dataDir: string, prefs: LocalPreferences): void;
14
+ //# sourceMappingURL=preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACjC,SAAS,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC1C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAQjE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAG/E"}