opencode-agora 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/README.md +86 -255
  2. package/dist/atomic-write.d.ts +10 -0
  3. package/dist/atomic-write.d.ts.map +1 -0
  4. package/dist/atomic-write.js +23 -0
  5. package/dist/atomic-write.js.map +1 -0
  6. package/dist/auth/refresh.d.ts +17 -0
  7. package/dist/auth/refresh.d.ts.map +1 -0
  8. package/dist/auth/refresh.js +50 -0
  9. package/dist/auth/refresh.js.map +1 -0
  10. package/dist/cli/app.d.ts +13 -18
  11. package/dist/cli/app.d.ts.map +1 -1
  12. package/dist/cli/app.js +184 -1187
  13. package/dist/cli/app.js.map +1 -1
  14. package/dist/cli/chat-renderer.d.ts +31 -0
  15. package/dist/cli/chat-renderer.d.ts.map +1 -0
  16. package/dist/cli/chat-renderer.js +275 -0
  17. package/dist/cli/chat-renderer.js.map +1 -0
  18. package/dist/cli/commands/browse.d.ts +4 -0
  19. package/dist/cli/commands/browse.d.ts.map +1 -0
  20. package/dist/cli/commands/browse.js +80 -0
  21. package/dist/cli/commands/browse.js.map +1 -0
  22. package/dist/cli/commands/chat.d.ts +4 -0
  23. package/dist/cli/commands/chat.d.ts.map +1 -0
  24. package/dist/cli/commands/chat.js +125 -0
  25. package/dist/cli/commands/chat.js.map +1 -0
  26. package/dist/cli/commands/community.d.ts +12 -0
  27. package/dist/cli/commands/community.d.ts.map +1 -0
  28. package/dist/cli/commands/community.js +453 -0
  29. package/dist/cli/commands/community.js.map +1 -0
  30. package/dist/cli/commands/export.d.ts +3 -0
  31. package/dist/cli/commands/export.d.ts.map +1 -0
  32. package/dist/cli/commands/export.js +108 -0
  33. package/dist/cli/commands/export.js.map +1 -0
  34. package/dist/cli/commands/init.d.ts +4 -0
  35. package/dist/cli/commands/init.d.ts.map +1 -0
  36. package/dist/cli/commands/init.js +299 -0
  37. package/dist/cli/commands/init.js.map +1 -0
  38. package/dist/cli/commands/learn.d.ts +4 -0
  39. package/dist/cli/commands/learn.d.ts.map +1 -0
  40. package/dist/cli/commands/learn.js +62 -0
  41. package/dist/cli/commands/learn.js.map +1 -0
  42. package/dist/cli/commands/marketplace.d.ts +9 -0
  43. package/dist/cli/commands/marketplace.d.ts.map +1 -0
  44. package/dist/cli/commands/marketplace.js +321 -0
  45. package/dist/cli/commands/marketplace.js.map +1 -0
  46. package/dist/cli/commands/notify.d.ts +3 -0
  47. package/dist/cli/commands/notify.d.ts.map +1 -0
  48. package/dist/cli/commands/notify.js +59 -0
  49. package/dist/cli/commands/notify.js.map +1 -0
  50. package/dist/cli/commands/operations.d.ts +16 -0
  51. package/dist/cli/commands/operations.d.ts.map +1 -0
  52. package/dist/cli/commands/operations.js +1006 -0
  53. package/dist/cli/commands/operations.js.map +1 -0
  54. package/dist/cli/commands/ping.d.ts +3 -0
  55. package/dist/cli/commands/ping.d.ts.map +1 -0
  56. package/dist/cli/commands/ping.js +56 -0
  57. package/dist/cli/commands/ping.js.map +1 -0
  58. package/dist/cli/commands/today.d.ts +3 -0
  59. package/dist/cli/commands/today.d.ts.map +1 -0
  60. package/dist/cli/commands/today.js +142 -0
  61. package/dist/cli/commands/today.js.map +1 -0
  62. package/dist/cli/commands/types.d.ts +5 -0
  63. package/dist/cli/commands/types.d.ts.map +1 -0
  64. package/dist/cli/commands/types.js +2 -0
  65. package/dist/cli/commands/types.js.map +1 -0
  66. package/dist/cli/commands/watch.d.ts +3 -0
  67. package/dist/cli/commands/watch.d.ts.map +1 -0
  68. package/dist/cli/commands/watch.js +41 -0
  69. package/dist/cli/commands/watch.js.map +1 -0
  70. package/dist/cli/commands/welcome.d.ts +3 -0
  71. package/dist/cli/commands/welcome.d.ts.map +1 -0
  72. package/dist/cli/commands/welcome.js +97 -0
  73. package/dist/cli/commands/welcome.js.map +1 -0
  74. package/dist/cli/commands-meta.d.ts +21 -0
  75. package/dist/cli/commands-meta.d.ts.map +1 -0
  76. package/dist/cli/commands-meta.js +828 -0
  77. package/dist/cli/commands-meta.js.map +1 -0
  78. package/dist/cli/completions-gen.d.ts +2 -0
  79. package/dist/cli/completions-gen.d.ts.map +1 -0
  80. package/dist/cli/completions-gen.js +195 -0
  81. package/dist/cli/completions-gen.js.map +1 -0
  82. package/dist/cli/completions.d.ts +18 -0
  83. package/dist/cli/completions.d.ts.map +1 -0
  84. package/dist/cli/completions.js +227 -0
  85. package/dist/cli/completions.js.map +1 -0
  86. package/dist/cli/flags.d.ts +19 -0
  87. package/dist/cli/flags.d.ts.map +1 -0
  88. package/dist/cli/flags.js +91 -0
  89. package/dist/cli/flags.js.map +1 -0
  90. package/dist/cli/format.d.ts +19 -0
  91. package/dist/cli/format.d.ts.map +1 -0
  92. package/dist/cli/format.js +249 -0
  93. package/dist/cli/format.js.map +1 -0
  94. package/dist/cli/helpers.d.ts +95 -0
  95. package/dist/cli/helpers.d.ts.map +1 -0
  96. package/dist/cli/helpers.js +301 -0
  97. package/dist/cli/helpers.js.map +1 -0
  98. package/dist/cli/mcp-server.d.ts +4 -0
  99. package/dist/cli/mcp-server.d.ts.map +1 -0
  100. package/dist/cli/mcp-server.js +277 -0
  101. package/dist/cli/mcp-server.js.map +1 -0
  102. package/dist/cli/menu.d.ts +7 -0
  103. package/dist/cli/menu.d.ts.map +1 -0
  104. package/dist/cli/menu.js +172 -0
  105. package/dist/cli/menu.js.map +1 -0
  106. package/dist/cli/pages/community.d.ts +9 -0
  107. package/dist/cli/pages/community.d.ts.map +1 -0
  108. package/dist/cli/pages/community.js +1094 -0
  109. package/dist/cli/pages/community.js.map +1 -0
  110. package/dist/cli/pages/helpers.d.ts +37 -0
  111. package/dist/cli/pages/helpers.d.ts.map +1 -0
  112. package/dist/cli/pages/helpers.js +98 -0
  113. package/dist/cli/pages/helpers.js.map +1 -0
  114. package/dist/cli/pages/home.d.ts +4 -0
  115. package/dist/cli/pages/home.d.ts.map +1 -0
  116. package/dist/cli/pages/home.js +231 -0
  117. package/dist/cli/pages/home.js.map +1 -0
  118. package/dist/cli/pages/marketplace.d.ts +5 -0
  119. package/dist/cli/pages/marketplace.d.ts.map +1 -0
  120. package/dist/cli/pages/marketplace.js +583 -0
  121. package/dist/cli/pages/marketplace.js.map +1 -0
  122. package/dist/cli/pages/news.d.ts +31 -0
  123. package/dist/cli/pages/news.d.ts.map +1 -0
  124. package/dist/cli/pages/news.js +688 -0
  125. package/dist/cli/pages/news.js.map +1 -0
  126. package/dist/cli/pages/settings.d.ts +3 -0
  127. package/dist/cli/pages/settings.d.ts.map +1 -0
  128. package/dist/cli/pages/settings.js +296 -0
  129. package/dist/cli/pages/settings.js.map +1 -0
  130. package/dist/cli/pages/types.d.ts +67 -0
  131. package/dist/cli/pages/types.d.ts.map +1 -0
  132. package/dist/cli/pages/types.js +2 -0
  133. package/dist/cli/pages/types.js.map +1 -0
  134. package/dist/cli/prompter.d.ts +135 -0
  135. package/dist/cli/prompter.d.ts.map +1 -0
  136. package/dist/cli/prompter.js +710 -0
  137. package/dist/cli/prompter.js.map +1 -0
  138. package/dist/cli/shell.d.ts +23 -0
  139. package/dist/cli/shell.d.ts.map +1 -0
  140. package/dist/cli/shell.js +1106 -0
  141. package/dist/cli/shell.js.map +1 -0
  142. package/dist/cli/tui.d.ts +7 -0
  143. package/dist/cli/tui.d.ts.map +1 -0
  144. package/dist/cli/tui.js +419 -0
  145. package/dist/cli/tui.js.map +1 -0
  146. package/dist/cli.js +1 -1
  147. package/dist/cli.js.map +1 -1
  148. package/dist/commands.d.ts +14 -0
  149. package/dist/commands.d.ts.map +1 -0
  150. package/dist/commands.js +28 -0
  151. package/dist/commands.js.map +1 -0
  152. package/dist/community/client.d.ts +84 -0
  153. package/dist/community/client.d.ts.map +1 -0
  154. package/dist/community/client.js +340 -0
  155. package/dist/community/client.js.map +1 -0
  156. package/dist/community/search.d.ts +25 -0
  157. package/dist/community/search.d.ts.map +1 -0
  158. package/dist/community/search.js +62 -0
  159. package/dist/community/search.js.map +1 -0
  160. package/dist/community/types.d.ts +71 -0
  161. package/dist/community/types.d.ts.map +1 -0
  162. package/dist/community/types.js +11 -0
  163. package/dist/community/types.js.map +1 -0
  164. package/dist/config.d.ts +1 -7
  165. package/dist/config.d.ts.map +1 -1
  166. package/dist/config.js +0 -32
  167. package/dist/config.js.map +1 -1
  168. package/dist/data.d.ts +1 -1
  169. package/dist/data.d.ts.map +1 -1
  170. package/dist/data.js +778 -40
  171. package/dist/data.js.map +1 -1
  172. package/dist/format.d.ts +5 -39
  173. package/dist/format.d.ts.map +1 -1
  174. package/dist/format.js +5 -120
  175. package/dist/format.js.map +1 -1
  176. package/dist/history.d.ts +13 -0
  177. package/dist/history.d.ts.map +1 -0
  178. package/dist/history.js +37 -0
  179. package/dist/history.js.map +1 -0
  180. package/dist/hubs/cache.d.ts +6 -0
  181. package/dist/hubs/cache.d.ts.map +1 -0
  182. package/dist/hubs/cache.js +46 -0
  183. package/dist/hubs/cache.js.map +1 -0
  184. package/dist/hubs/enrichment.d.ts +43 -0
  185. package/dist/hubs/enrichment.d.ts.map +1 -0
  186. package/dist/hubs/enrichment.js +239 -0
  187. package/dist/hubs/enrichment.js.map +1 -0
  188. package/dist/hubs/github.d.ts +12 -0
  189. package/dist/hubs/github.d.ts.map +1 -0
  190. package/dist/hubs/github.js +54 -0
  191. package/dist/hubs/github.js.map +1 -0
  192. package/dist/hubs/huggingface.d.ts +27 -0
  193. package/dist/hubs/huggingface.d.ts.map +1 -0
  194. package/dist/hubs/huggingface.js +88 -0
  195. package/dist/hubs/huggingface.js.map +1 -0
  196. package/dist/hubs/quality.d.ts +26 -0
  197. package/dist/hubs/quality.d.ts.map +1 -0
  198. package/dist/hubs/quality.js +57 -0
  199. package/dist/hubs/quality.js.map +1 -0
  200. package/dist/hubs/types.d.ts +30 -0
  201. package/dist/hubs/types.d.ts.map +1 -0
  202. package/dist/hubs/types.js +2 -0
  203. package/dist/hubs/types.js.map +1 -0
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +188 -224
  206. package/dist/index.js.map +1 -1
  207. package/dist/init.d.ts.map +1 -1
  208. package/dist/init.js +6 -11
  209. package/dist/init.js.map +1 -1
  210. package/dist/live.d.ts +14 -0
  211. package/dist/live.d.ts.map +1 -1
  212. package/dist/live.js +35 -3
  213. package/dist/live.js.map +1 -1
  214. package/dist/marketplace.d.ts +25 -3
  215. package/dist/marketplace.d.ts.map +1 -1
  216. package/dist/marketplace.js +279 -22
  217. package/dist/marketplace.js.map +1 -1
  218. package/dist/news/cache.d.ts +13 -0
  219. package/dist/news/cache.d.ts.map +1 -0
  220. package/dist/news/cache.js +66 -0
  221. package/dist/news/cache.js.map +1 -0
  222. package/dist/news/score.d.ts +4 -0
  223. package/dist/news/score.d.ts.map +1 -0
  224. package/dist/news/score.js +43 -0
  225. package/dist/news/score.js.map +1 -0
  226. package/dist/news/sources/arxiv.d.ts +9 -0
  227. package/dist/news/sources/arxiv.d.ts.map +1 -0
  228. package/dist/news/sources/arxiv.js +107 -0
  229. package/dist/news/sources/arxiv.js.map +1 -0
  230. package/dist/news/sources/github-trending.d.ts +9 -0
  231. package/dist/news/sources/github-trending.d.ts.map +1 -0
  232. package/dist/news/sources/github-trending.js +97 -0
  233. package/dist/news/sources/github-trending.js.map +1 -0
  234. package/dist/news/sources/hn.d.ts +9 -0
  235. package/dist/news/sources/hn.d.ts.map +1 -0
  236. package/dist/news/sources/hn.js +57 -0
  237. package/dist/news/sources/hn.js.map +1 -0
  238. package/dist/news/sources/reddit.d.ts +9 -0
  239. package/dist/news/sources/reddit.d.ts.map +1 -0
  240. package/dist/news/sources/reddit.js +69 -0
  241. package/dist/news/sources/reddit.js.map +1 -0
  242. package/dist/news/sources/rss.d.ts +13 -0
  243. package/dist/news/sources/rss.d.ts.map +1 -0
  244. package/dist/news/sources/rss.js +14 -0
  245. package/dist/news/sources/rss.js.map +1 -0
  246. package/dist/news/types.d.ts +42 -0
  247. package/dist/news/types.d.ts.map +1 -0
  248. package/dist/news/types.js +56 -0
  249. package/dist/news/types.js.map +1 -0
  250. package/dist/preferences.d.ts +14 -0
  251. package/dist/preferences.d.ts.map +1 -0
  252. package/dist/preferences.js +31 -0
  253. package/dist/preferences.js.map +1 -0
  254. package/dist/settings.d.ts +26 -0
  255. package/dist/settings.d.ts.map +1 -0
  256. package/dist/settings.js +251 -0
  257. package/dist/settings.js.map +1 -0
  258. package/dist/state.d.ts +9 -2
  259. package/dist/state.d.ts.map +1 -1
  260. package/dist/state.js +41 -19
  261. package/dist/state.js.map +1 -1
  262. package/dist/transcript.d.ts +28 -0
  263. package/dist/transcript.d.ts.map +1 -0
  264. package/dist/transcript.js +79 -0
  265. package/dist/transcript.js.map +1 -0
  266. package/dist/types.d.ts +19 -1
  267. package/dist/types.d.ts.map +1 -1
  268. package/dist/ui.d.ts +157 -0
  269. package/dist/ui.d.ts.map +1 -0
  270. package/dist/ui.js +296 -0
  271. package/dist/ui.js.map +1 -0
  272. package/package.json +11 -9
  273. package/dist/api.d.ts +0 -72
  274. package/dist/api.d.ts.map +0 -1
  275. package/dist/api.js +0 -109
  276. package/dist/api.js.map +0 -1
  277. package/dist/logger.d.ts +0 -20
  278. package/dist/logger.d.ts.map +0 -1
  279. package/dist/logger.js +0 -59
  280. package/dist/logger.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ import { agoraUserAgent } from '../types.js';
2
+ const QUERY_CATEGORIES = ['cs.AI', 'cs.CL', 'cs.SE', 'cs.LG'];
3
+ const MAX_RESULTS = 25;
4
+ export const arxivSource = {
5
+ async fetch(opts) {
6
+ const fetcher = opts.fetcher ?? globalThis.fetch;
7
+ const allItems = [];
8
+ const now = new Date().toISOString();
9
+ const categories = QUERY_CATEGORIES.join('+OR+');
10
+ const url = `https://export.arxiv.org/api/query?search_query=cat:${categories}&sortBy=submittedDate&sortOrder=descending&max_results=${MAX_RESULTS}`;
11
+ try {
12
+ const res = await fetcher(url, {
13
+ signal: opts.signal,
14
+ headers: { 'User-Agent': agoraUserAgent }
15
+ });
16
+ if (!res.ok)
17
+ throw new Error(`arXiv API returned ${res.status}`);
18
+ const xml = await res.text();
19
+ const items = parseArxivAtom(xml, now);
20
+ allItems.push(...items);
21
+ }
22
+ catch (e) {
23
+ if (e instanceof Error && e.name !== 'AbortError')
24
+ throw e;
25
+ }
26
+ return allItems;
27
+ }
28
+ };
29
+ function parseArxivAtom(xml, now) {
30
+ const items = [];
31
+ const entryRegex = /<entry>([\s\S]*?)<\/entry>/gi;
32
+ let match;
33
+ while ((match = entryRegex.exec(xml)) !== null) {
34
+ try {
35
+ const entry = match[1];
36
+ const idMatch = entry.match(/<id>([^<]+)<\/id>/);
37
+ if (!idMatch)
38
+ continue;
39
+ const paperUrl = idMatch[1].trim();
40
+ const paperId = paperUrl.split('/').pop() || paperUrl;
41
+ const titleMatch = entry.match(/<title>([\s\S]*?)<\/title>/);
42
+ const title = titleMatch ? cleanXml(titleMatch[1]) : '';
43
+ const summaryMatch = entry.match(/<summary>([\s\S]*?)<\/summary>/);
44
+ const summary = summaryMatch ? cleanXml(summaryMatch[1]).slice(0, 300) : '';
45
+ const publishedMatch = entry.match(/<published>([^<]+)<\/published>/);
46
+ const published = publishedMatch ? publishedMatch[1].trim() : now;
47
+ const authorRegex = /<author>[\s\S]*?<name>([^<]+)<\/name>[\s\S]*?<\/author>/gi;
48
+ const authors = [];
49
+ let aMatch;
50
+ while ((aMatch = authorRegex.exec(entry)) !== null) {
51
+ authors.push(cleanXml(aMatch[1]));
52
+ }
53
+ const catRegex = /<category[^>]*term="([^"]+)"[^>]*\/>/gi;
54
+ const categories = [];
55
+ let cMatch;
56
+ while ((cMatch = catRegex.exec(entry)) !== null) {
57
+ categories.push(cMatch[1]);
58
+ }
59
+ items.push({
60
+ id: `arxiv:${paperId}`,
61
+ source: 'arxiv',
62
+ title,
63
+ url: `https://arxiv.org/abs/${paperId}`,
64
+ author: authors[0] || 'Unknown',
65
+ publishedAt: published,
66
+ fetchedAt: now,
67
+ engagement: 0,
68
+ tags: extractArxivTags(categories, title, summary),
69
+ summary: summary || undefined
70
+ });
71
+ }
72
+ catch {
73
+ continue;
74
+ }
75
+ }
76
+ return items;
77
+ }
78
+ function extractArxivTags(categories, title, summary) {
79
+ const tags = [];
80
+ const lower = (title + ' ' + summary).toLowerCase();
81
+ for (const cat of categories) {
82
+ tags.push(cat.replace(/\./g, '-').toLowerCase());
83
+ }
84
+ const topicMap = {
85
+ ai: ['artificial intelligence', 'machine learning', 'deep learning'],
86
+ llm: ['language model', 'llm', 'gpt', 'transformer', 'attention'],
87
+ agents: ['agent', 'tool use', 'tool-use', 'function calling'],
88
+ coding: ['code generation', 'program synthesis', 'software engineering'],
89
+ security: ['security', 'safety', 'alignment', 'harmlessness']
90
+ };
91
+ for (const [topic, keywords] of Object.entries(topicMap)) {
92
+ for (const kw of keywords) {
93
+ if (lower.includes(kw)) {
94
+ tags.push(topic);
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ return tags;
100
+ }
101
+ function cleanXml(text) {
102
+ return text
103
+ .replace(/<[^>]*>/g, '')
104
+ .replace(/\s+/g, ' ')
105
+ .trim();
106
+ }
107
+ //# 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":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QACV,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CACzB;AAID,eAAO,MAAM,oBAAoB,EAAE,aAwBlC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { agoraUserAgent } from '../types.js';
2
+ const LANGUAGES = ['typescript', 'python', 'go', 'rust'];
3
+ export const githubTrendingSource = {
4
+ async fetch(opts) {
5
+ const fetcher = opts.fetcher ?? globalThis.fetch;
6
+ const allItems = [];
7
+ const now = new Date().toISOString();
8
+ for (const lang of LANGUAGES) {
9
+ try {
10
+ const url = `https://github.com/trending/${lang}?since=daily`;
11
+ const res = await fetcher(url, {
12
+ signal: opts.signal,
13
+ headers: { 'User-Agent': agoraUserAgent }
14
+ });
15
+ if (!res.ok)
16
+ continue;
17
+ const html = await res.text();
18
+ const items = parseTrendingHtml(html, lang, now);
19
+ allItems.push(...items);
20
+ }
21
+ catch {
22
+ continue;
23
+ }
24
+ }
25
+ return allItems;
26
+ }
27
+ };
28
+ function parseTrendingHtml(html, lang, now) {
29
+ const items = [];
30
+ const articleRegex = /<article[^>]*>([\s\S]*?)<\/article>/gi;
31
+ let match;
32
+ while ((match = articleRegex.exec(html)) !== null) {
33
+ try {
34
+ const article = match[1];
35
+ const repoMatch = article.match(/<h2[^>]*>[\s\S]*?<a[^>]*href="\/([^"]+)"[^>]*>/i);
36
+ if (!repoMatch)
37
+ continue;
38
+ const repoPath = repoMatch[1];
39
+ const descMatch = article.match(/<p[^>]*class="[^"]*col-9[^"]*"[^>]*>([\s\S]*?)<\/p>/i);
40
+ const description = descMatch ? stripHtml(descMatch[1]).trim() : '';
41
+ const starsMatch = article.match(/<span[^>]*class="[^"]*d-inline-block[^"]*float-sm-right[^"]*"[^>]*>([\s\S]*?)<\/span>/i);
42
+ const starsStr = starsMatch ? stripHtml(starsMatch[1]).trim().replace(/,/g, '') : '0';
43
+ const stars = parseInt(starsStr, 10) || 0;
44
+ const forksMatch = article.match(/<a[^>]*href="\/[^"]+\/fork"[^>]*>([\s\S]*?)<\/a>/i);
45
+ const forksStr = forksMatch ? stripHtml(forksMatch[1]).trim().replace(/,/g, '') : '0';
46
+ const forks = parseInt(forksStr, 10) || 0;
47
+ const [owner, repo] = repoPath.split('/');
48
+ const id = `gh:${repoPath.replace('/', '-')}`;
49
+ const engagement = stars + forks;
50
+ items.push({
51
+ id,
52
+ source: 'github-trending',
53
+ title: `${owner}/${repo}`,
54
+ url: `https://github.com/${repoPath}`,
55
+ author: owner,
56
+ publishedAt: now,
57
+ fetchedAt: now,
58
+ engagement,
59
+ tags: extractGithubTags(repoPath, description, lang),
60
+ summary: description || undefined
61
+ });
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ }
67
+ return items;
68
+ }
69
+ function extractGithubTags(repoPath, description, lang) {
70
+ const tags = new Set();
71
+ const lower = (repoPath + ' ' + description).toLowerCase();
72
+ tags.add(lang);
73
+ const topicMap = {
74
+ mcp: ['mcp', 'model-context-protocol', 'modelcontextprotocol'],
75
+ ai: ['ai', 'artificial-intelligence', 'llm', 'machine-learning'],
76
+ agents: ['agent', 'agents', 'autonomous'],
77
+ tools: ['cli', 'tool', 'framework', 'sdk'],
78
+ database: ['database', 'sql', 'nosql', 'postgres', 'redis', 'sqlite'],
79
+ devtools: ['devtools', 'developer-tools', 'github', 'git']
80
+ };
81
+ for (const [topic, keywords] of Object.entries(topicMap)) {
82
+ for (const kw of keywords) {
83
+ if (lower.includes(kw)) {
84
+ tags.add(topic);
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ return Array.from(tags);
90
+ }
91
+ function stripHtml(html) {
92
+ return html
93
+ .replace(/<[^>]*>/g, '')
94
+ .replace(/[\s\n]+/g, ' ')
95
+ .trim();
96
+ }
97
+ //# 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;AAGxD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QACV,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CACzB;AAgBD,eAAO,MAAM,QAAQ,EAAE,aA6BtB,CAAC"}
@@ -0,0 +1,57 @@
1
+ import { agoraUserAgent } from '../types.js';
2
+ export const hnSource = {
3
+ async fetch(opts) {
4
+ const fetcher = opts.fetcher ?? globalThis.fetch;
5
+ const url = 'https://hn.algolia.com/api/v1/search?tags=front_page&numericFilters=points>50&hitsPerPage=30';
6
+ const res = await fetcher(url, {
7
+ signal: opts.signal,
8
+ headers: { 'User-Agent': agoraUserAgent }
9
+ });
10
+ if (!res.ok)
11
+ throw new Error(`HN API returned ${res.status}`);
12
+ const data = (await res.json());
13
+ const now = new Date().toISOString();
14
+ return (data.hits ?? []).map((hit) => {
15
+ const item = {
16
+ id: `hn:${hit.objectID}`,
17
+ source: 'hn',
18
+ title: hit.title ?? '',
19
+ url: hit.url || `https://news.ycombinator.com/item?id=${hit.objectID}`,
20
+ author: hit.author,
21
+ publishedAt: new Date(hit.created_at).toISOString(),
22
+ fetchedAt: now,
23
+ engagement: hit.points ?? 0,
24
+ tags: extractHnTags(hit)
25
+ };
26
+ return item;
27
+ });
28
+ }
29
+ };
30
+ function extractHnTags(hit) {
31
+ const tags = [];
32
+ const title = (hit.title ?? '').toLowerCase();
33
+ const url = (hit.url ?? '').toLowerCase();
34
+ const topicMap = {
35
+ mcp: ['mcp', 'model-context-protocol', 'modelcontextprotocol'],
36
+ ai: ['ai', 'artificial-intelligence'],
37
+ llm: ['llm', 'large-language-model', 'gpt', 'claude', 'gemini'],
38
+ agents: ['agent', 'agents', 'autonomous'],
39
+ coding: ['coding', 'programming', 'software', 'developer'],
40
+ security: ['security', 'vulnerability', 'exploit'],
41
+ devtools: ['devtools', 'developer-tools', 'sdk', 'api']
42
+ };
43
+ for (const [topic, keywords] of Object.entries(topicMap)) {
44
+ for (const kw of keywords) {
45
+ if (title.includes(kw) || url.includes(kw)) {
46
+ tags.push(topic);
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ if ((hit._tags ?? []).includes('show'))
52
+ tags.push('show');
53
+ if ((hit._tags ?? []).includes('ask'))
54
+ tags.push('ask');
55
+ return tags;
56
+ }
57
+ //# sourceMappingURL=hn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hn.js","sourceRoot":"","sources":["../../../src/news/sources/hn.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 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;AAmBxD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QACV,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CACzB;AAID,eAAO,MAAM,YAAY,EAAE,aAuC1B,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { agoraUserAgent } from '../types.js';
2
+ const SUBREDDITS = ['mcp', 'LocalLLaMA', 'programming', 'MachineLearning'];
3
+ export const redditSource = {
4
+ async fetch(opts) {
5
+ const fetcher = opts.fetcher ?? globalThis.fetch;
6
+ const allItems = [];
7
+ const now = new Date().toISOString();
8
+ for (const sub of SUBREDDITS) {
9
+ try {
10
+ const url = `https://www.reddit.com/r/${sub}/hot.json?limit=25`;
11
+ const res = await fetcher(url, {
12
+ signal: opts.signal,
13
+ headers: { 'User-Agent': agoraUserAgent }
14
+ });
15
+ if (!res.ok)
16
+ continue;
17
+ const data = (await res.json());
18
+ const children = data?.data?.children ?? [];
19
+ for (const child of children) {
20
+ const post = child?.data;
21
+ if (!post || post.stickied)
22
+ continue;
23
+ allItems.push({
24
+ id: `reddit:${post.id}`,
25
+ source: 'reddit',
26
+ title: post.title ?? '',
27
+ url: `https://reddit.com${post.permalink}`,
28
+ author: post.author,
29
+ publishedAt: new Date(post.created_utc * 1000).toISOString(),
30
+ fetchedAt: now,
31
+ engagement: post.ups ?? 0,
32
+ tags: extractRedditTags(post, sub),
33
+ summary: post.selftext ? post.selftext.slice(0, 200) : undefined
34
+ });
35
+ }
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ }
41
+ return allItems;
42
+ }
43
+ };
44
+ function extractRedditTags(post, subreddit) {
45
+ const tags = [];
46
+ const title = (post.title ?? '').toLowerCase();
47
+ const linkFlair = (post.link_flair_text ?? '').toLowerCase();
48
+ const subLower = subreddit.toLowerCase();
49
+ tags.push(subLower === 'localllama' ? 'llm' : subLower);
50
+ const topicMap = {
51
+ mcp: ['mcp', 'model-context-protocol'],
52
+ ai: ['ai', 'artificial intelligence'],
53
+ agents: ['agent'],
54
+ coding: ['code', 'programming', 'coding', 'developer'],
55
+ tools: ['tool', 'framework', 'library']
56
+ };
57
+ for (const [topic, keywords] of Object.entries(topicMap)) {
58
+ for (const kw of keywords) {
59
+ if (title.includes(kw) || linkFlair.includes(kw)) {
60
+ tags.push(topic);
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ if (linkFlair)
66
+ tags.push(linkFlair.replace(/[^a-z0-9-]/g, ''));
67
+ return tags;
68
+ }
69
+ //# 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,13 @@
1
+ /**
2
+ * RSS feed adapter — uncomment the export and wire into NEWS_SOURCES
3
+ * (src/news/types.ts) when user-configurable RSS feeds are needed.
4
+ *
5
+ * import type { NewsItem, NewsSource } from '../types.js';
6
+ *
7
+ * export interface SourceAdapter {
8
+ * fetch(opts: { fetcher?: (url: string, init?: RequestInit) => Promise<Response>; signal?: AbortSignal; }): Promise<NewsItem[]>;
9
+ * }
10
+ *
11
+ * export const rssSource: SourceAdapter = { ... };
12
+ */
13
+ //# 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;;;;;;;;;;;GAWG"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * RSS feed adapter — uncomment the export and wire into NEWS_SOURCES
4
+ * (src/news/types.ts) when user-configurable RSS feeds are needed.
5
+ *
6
+ * import type { NewsItem, NewsSource } from '../types.js';
7
+ *
8
+ * export interface SourceAdapter {
9
+ * fetch(opts: { fetcher?: (url: string, init?: RequestInit) => Promise<Response>; signal?: AbortSignal; }): Promise<NewsItem[]>;
10
+ * }
11
+ *
12
+ * export const rssSource: SourceAdapter = { ... };
13
+ */
14
+ //# sourceMappingURL=rss.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rss.js","sourceRoot":"","sources":["../../../src/news/sources/rss.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,42 @@
1
+ export type NewsSource = 'hn' | 'reddit' | 'github-trending' | 'arxiv' | 'rss';
2
+ /** Shared User-Agent for outbound news fetches. Reads the live package.json
3
+ * so the agent string stays in sync with the published version. */
4
+ export declare const agoraUserAgent: string;
5
+ export interface NewsItem {
6
+ id: string;
7
+ source: NewsSource;
8
+ title: string;
9
+ url: string;
10
+ author?: string;
11
+ publishedAt: string;
12
+ fetchedAt: string;
13
+ engagement: number;
14
+ tags: string[];
15
+ summary?: string;
16
+ }
17
+ export interface ScoredNewsItem extends NewsItem {
18
+ score: number;
19
+ scoreBreakdown: {
20
+ recency: number;
21
+ engagement: number;
22
+ topic: number;
23
+ };
24
+ }
25
+ export interface NewsConfig {
26
+ sources: Record<NewsSource, {
27
+ enabled: boolean;
28
+ ttlMinutes: number;
29
+ }>;
30
+ topics: string[];
31
+ weights: {
32
+ recency: number;
33
+ engagement: number;
34
+ topic: number;
35
+ };
36
+ }
37
+ export declare const DEFAULT_NEWS_CONFIG: NewsConfig;
38
+ export declare const NEWS_SOURCE_LABELS: Record<NewsSource, string>;
39
+ export declare function normalizeNewsSource(s: string): NewsSource | undefined;
40
+ export declare function hostFromUrl(url: string): string;
41
+ export declare function slugFromUrl(url: string): string;
42
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/news/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,iBAAiB,GAAG,OAAO,GAAG,KAAK,CAAC;AAM/E;oEACoE;AACpE,eAAO,MAAM,cAAc,QAA+B,CAAC;AAE3D,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,CAarE;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,56 @@
1
+ import { readFileSync } from 'node:fs';
2
+ const { version: AGORA_VERSION } = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
3
+ /** Shared User-Agent for outbound news fetches. Reads the live package.json
4
+ * so the agent string stays in sync with the published version. */
5
+ export const agoraUserAgent = `agora-cli/${AGORA_VERSION}`;
6
+ export const DEFAULT_NEWS_CONFIG = {
7
+ sources: {
8
+ hn: { enabled: true, ttlMinutes: 10 },
9
+ reddit: { enabled: true, ttlMinutes: 15 },
10
+ 'github-trending': { enabled: true, ttlMinutes: 30 },
11
+ arxiv: { enabled: false, ttlMinutes: 60 },
12
+ rss: { enabled: false, ttlMinutes: 60 }
13
+ },
14
+ topics: ['mcp', 'ai', 'agents', 'workflows', 'llm', 'tool-use', 'coding', 'agents', 'security'],
15
+ weights: { recency: 1.0, engagement: 0.6, topic: 0.8 }
16
+ };
17
+ export const NEWS_SOURCE_LABELS = {
18
+ hn: 'Hacker News',
19
+ reddit: 'Reddit',
20
+ 'github-trending': 'GitHub Trending',
21
+ arxiv: 'arXiv',
22
+ rss: 'RSS'
23
+ };
24
+ export function normalizeNewsSource(s) {
25
+ const map = {
26
+ hn: 'hn',
27
+ hackernews: 'hn',
28
+ 'hacker-news': 'hn',
29
+ reddit: 'reddit',
30
+ gh: 'github-trending',
31
+ github: 'github-trending',
32
+ 'github-trending': 'github-trending',
33
+ arxiv: 'arxiv',
34
+ rss: 'rss'
35
+ };
36
+ return map[s.toLowerCase().trim()];
37
+ }
38
+ export function hostFromUrl(url) {
39
+ try {
40
+ const u = new URL(url);
41
+ return u.hostname.replace(/^www\./, '');
42
+ }
43
+ catch {
44
+ return '';
45
+ }
46
+ }
47
+ export function slugFromUrl(url) {
48
+ try {
49
+ const u = new URL(url);
50
+ return u.pathname.replace(/\/$/, '').split('/').filter(Boolean).slice(-2).join('/');
51
+ }
52
+ catch {
53
+ return '';
54
+ }
55
+ }
56
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/news/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,KAAK,CAC3C,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC9C,CAAC;AAEzB;oEACoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,aAAa,EAAE,CAAC;AA0B3D,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;QACR,UAAU,EAAE,IAAI;QAChB,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,QAAQ;QAChB,EAAE,EAAE,iBAAiB;QACrB,MAAM,EAAE,iBAAiB;QACzB,iBAAiB,EAAE,iBAAiB;QACpC,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":"AAIA,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,CAE/E"}
@@ -0,0 +1,31 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { atomicWriteFile } from './atomic-write.js';
3
+ import { join } from 'node:path';
4
+ const DEFAULTS = {
5
+ theme: 'dark',
6
+ verbosity: 'medium',
7
+ defaultNewsSource: 'all',
8
+ defaultNewsCategory: 'all',
9
+ username: '',
10
+ email: '',
11
+ bio: '',
12
+ lastTab: 0
13
+ };
14
+ export function prefsPath(dataDir) {
15
+ return join(dataDir, 'preferences.json');
16
+ }
17
+ export function loadPreferences(dataDir) {
18
+ const path = prefsPath(dataDir);
19
+ if (!existsSync(path))
20
+ return { ...DEFAULTS };
21
+ try {
22
+ return { ...DEFAULTS, ...JSON.parse(readFileSync(path, 'utf8')) };
23
+ }
24
+ catch {
25
+ return { ...DEFAULTS };
26
+ }
27
+ }
28
+ export function writePreferences(dataDir, prefs) {
29
+ atomicWriteFile(prefsPath(dataDir), JSON.stringify(prefs, null, 2));
30
+ }
31
+ //# sourceMappingURL=preferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preferences.js","sourceRoot":"","sources":["../src/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAajC,MAAM,QAAQ,GAAqB;IACjC,KAAK,EAAE,MAAM;IACb,SAAS,EAAE,QAAQ;IACnB,iBAAiB,EAAE,KAAK;IACxB,mBAAmB,EAAE,KAAK;IAC1B,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,GAAG,EAAE,EAAE;IACP,OAAO,EAAE,CAAC;CACX,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9C,IAAI,CAAC;QACH,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,KAAuB;IACvE,eAAe,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface AgoraSettings {
2
+ account: {
3
+ username: string;
4
+ backend: string;
5
+ declared_llm: string;
6
+ };
7
+ display: {
8
+ color: 'auto' | 'truecolor' | 'none';
9
+ banner: boolean;
10
+ };
11
+ news: {
12
+ sources: Record<string, {
13
+ enabled: boolean;
14
+ ttl_minutes: number;
15
+ }>;
16
+ feeds?: string[];
17
+ };
18
+ community: {
19
+ default_board: string;
20
+ collapse_flag_threshold: number;
21
+ };
22
+ }
23
+ export declare const DEFAULT_SETTINGS: AgoraSettings;
24
+ export declare function loadSettings(dataDir: string): AgoraSettings;
25
+ export declare function writeSettings(dataDir: string, settings: AgoraSettings): void;
26
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IACnE,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACnE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IACF,SAAS,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,uBAAuB,EAAE,MAAM,CAAA;KAAE,CAAC;CACvE;AAED,eAAO,MAAM,gBAAgB,EAAE,aAc9B,CAAC;AAIF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAU3D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAE5E"}