euparliamentmonitor 0.8.4

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 (276) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1005 -0
  3. package/SECURITY.md +151 -0
  4. package/package.json +131 -0
  5. package/scripts/constants/committee-indicator-map.d.ts +199 -0
  6. package/scripts/constants/committee-indicator-map.d.ts.map +1 -0
  7. package/scripts/constants/committee-indicator-map.js +1224 -0
  8. package/scripts/constants/committee-indicator-map.js.map +1 -0
  9. package/scripts/constants/config.d.ts +38 -0
  10. package/scripts/constants/config.d.ts.map +1 -0
  11. package/scripts/constants/config.js +66 -0
  12. package/scripts/constants/config.js.map +1 -0
  13. package/scripts/constants/language-articles.d.ts +84 -0
  14. package/scripts/constants/language-articles.d.ts.map +1 -0
  15. package/scripts/constants/language-articles.js +6771 -0
  16. package/scripts/constants/language-articles.js.map +1 -0
  17. package/scripts/constants/language-core.d.ts +38 -0
  18. package/scripts/constants/language-core.d.ts.map +1 -0
  19. package/scripts/constants/language-core.js +90 -0
  20. package/scripts/constants/language-core.js.map +1 -0
  21. package/scripts/constants/language-ui.d.ts +82 -0
  22. package/scripts/constants/language-ui.d.ts.map +1 -0
  23. package/scripts/constants/language-ui.js +889 -0
  24. package/scripts/constants/language-ui.js.map +1 -0
  25. package/scripts/constants/languages.d.ts +14 -0
  26. package/scripts/constants/languages.d.ts.map +1 -0
  27. package/scripts/constants/languages.js +15 -0
  28. package/scripts/constants/languages.js.map +1 -0
  29. package/scripts/generators/analysis-builders.d.ts +266 -0
  30. package/scripts/generators/analysis-builders.d.ts.map +1 -0
  31. package/scripts/generators/analysis-builders.js +2903 -0
  32. package/scripts/generators/analysis-builders.js.map +1 -0
  33. package/scripts/generators/breaking-content.d.ts +45 -0
  34. package/scripts/generators/breaking-content.d.ts.map +1 -0
  35. package/scripts/generators/breaking-content.js +530 -0
  36. package/scripts/generators/breaking-content.js.map +1 -0
  37. package/scripts/generators/committee-helpers.d.ts +54 -0
  38. package/scripts/generators/committee-helpers.d.ts.map +1 -0
  39. package/scripts/generators/committee-helpers.js +154 -0
  40. package/scripts/generators/committee-helpers.js.map +1 -0
  41. package/scripts/generators/dashboard-content.d.ts +95 -0
  42. package/scripts/generators/dashboard-content.d.ts.map +1 -0
  43. package/scripts/generators/dashboard-content.js +630 -0
  44. package/scripts/generators/dashboard-content.js.map +1 -0
  45. package/scripts/generators/deep-analysis-content.d.ts +23 -0
  46. package/scripts/generators/deep-analysis-content.d.ts.map +1 -0
  47. package/scripts/generators/deep-analysis-content.js +831 -0
  48. package/scripts/generators/deep-analysis-content.js.map +1 -0
  49. package/scripts/generators/mindmap-content.d.ts +55 -0
  50. package/scripts/generators/mindmap-content.d.ts.map +1 -0
  51. package/scripts/generators/mindmap-content.js +512 -0
  52. package/scripts/generators/mindmap-content.js.map +1 -0
  53. package/scripts/generators/motions-content.d.ts +50 -0
  54. package/scripts/generators/motions-content.d.ts.map +1 -0
  55. package/scripts/generators/motions-content.js +391 -0
  56. package/scripts/generators/motions-content.js.map +1 -0
  57. package/scripts/generators/news-enhanced.d.ts +14 -0
  58. package/scripts/generators/news-enhanced.d.ts.map +1 -0
  59. package/scripts/generators/news-enhanced.js +169 -0
  60. package/scripts/generators/news-enhanced.js.map +1 -0
  61. package/scripts/generators/news-indexes.d.ts +31 -0
  62. package/scripts/generators/news-indexes.d.ts.map +1 -0
  63. package/scripts/generators/news-indexes.js +410 -0
  64. package/scripts/generators/news-indexes.js.map +1 -0
  65. package/scripts/generators/pipeline/fetch-stage.d.ts +352 -0
  66. package/scripts/generators/pipeline/fetch-stage.d.ts.map +1 -0
  67. package/scripts/generators/pipeline/fetch-stage.js +1522 -0
  68. package/scripts/generators/pipeline/fetch-stage.js.map +1 -0
  69. package/scripts/generators/pipeline/generate-stage.d.ts +43 -0
  70. package/scripts/generators/pipeline/generate-stage.d.ts.map +1 -0
  71. package/scripts/generators/pipeline/generate-stage.js +204 -0
  72. package/scripts/generators/pipeline/generate-stage.js.map +1 -0
  73. package/scripts/generators/pipeline/output-stage.d.ts +48 -0
  74. package/scripts/generators/pipeline/output-stage.d.ts.map +1 -0
  75. package/scripts/generators/pipeline/output-stage.js +145 -0
  76. package/scripts/generators/pipeline/output-stage.js.map +1 -0
  77. package/scripts/generators/pipeline/transform-stage.d.ts +57 -0
  78. package/scripts/generators/pipeline/transform-stage.d.ts.map +1 -0
  79. package/scripts/generators/pipeline/transform-stage.js +111 -0
  80. package/scripts/generators/pipeline/transform-stage.js.map +1 -0
  81. package/scripts/generators/propositions-content.d.ts +29 -0
  82. package/scripts/generators/propositions-content.d.ts.map +1 -0
  83. package/scripts/generators/propositions-content.js +90 -0
  84. package/scripts/generators/propositions-content.js.map +1 -0
  85. package/scripts/generators/sankey-content.d.ts +45 -0
  86. package/scripts/generators/sankey-content.d.ts.map +1 -0
  87. package/scripts/generators/sankey-content.js +227 -0
  88. package/scripts/generators/sankey-content.js.map +1 -0
  89. package/scripts/generators/sitemap.d.ts +66 -0
  90. package/scripts/generators/sitemap.d.ts.map +1 -0
  91. package/scripts/generators/sitemap.js +562 -0
  92. package/scripts/generators/sitemap.js.map +1 -0
  93. package/scripts/generators/strategies/article-strategy.d.ts +146 -0
  94. package/scripts/generators/strategies/article-strategy.d.ts.map +1 -0
  95. package/scripts/generators/strategies/article-strategy.js +4 -0
  96. package/scripts/generators/strategies/article-strategy.js.map +1 -0
  97. package/scripts/generators/strategies/breaking-news-strategy.d.ts +64 -0
  98. package/scripts/generators/strategies/breaking-news-strategy.d.ts.map +1 -0
  99. package/scripts/generators/strategies/breaking-news-strategy.js +246 -0
  100. package/scripts/generators/strategies/breaking-news-strategy.js.map +1 -0
  101. package/scripts/generators/strategies/committee-reports-strategy.d.ts +93 -0
  102. package/scripts/generators/strategies/committee-reports-strategy.d.ts.map +1 -0
  103. package/scripts/generators/strategies/committee-reports-strategy.js +447 -0
  104. package/scripts/generators/strategies/committee-reports-strategy.js.map +1 -0
  105. package/scripts/generators/strategies/month-ahead-strategy.d.ts +60 -0
  106. package/scripts/generators/strategies/month-ahead-strategy.d.ts.map +1 -0
  107. package/scripts/generators/strategies/month-ahead-strategy.js +175 -0
  108. package/scripts/generators/strategies/month-ahead-strategy.js.map +1 -0
  109. package/scripts/generators/strategies/monthly-review-strategy.d.ts +66 -0
  110. package/scripts/generators/strategies/monthly-review-strategy.d.ts.map +1 -0
  111. package/scripts/generators/strategies/monthly-review-strategy.js +204 -0
  112. package/scripts/generators/strategies/monthly-review-strategy.js.map +1 -0
  113. package/scripts/generators/strategies/motions-strategy.d.ts +61 -0
  114. package/scripts/generators/strategies/motions-strategy.d.ts.map +1 -0
  115. package/scripts/generators/strategies/motions-strategy.js +215 -0
  116. package/scripts/generators/strategies/motions-strategy.js.map +1 -0
  117. package/scripts/generators/strategies/propositions-strategy.d.ts +60 -0
  118. package/scripts/generators/strategies/propositions-strategy.d.ts.map +1 -0
  119. package/scripts/generators/strategies/propositions-strategy.js +257 -0
  120. package/scripts/generators/strategies/propositions-strategy.js.map +1 -0
  121. package/scripts/generators/strategies/week-ahead-strategy.d.ts +57 -0
  122. package/scripts/generators/strategies/week-ahead-strategy.d.ts.map +1 -0
  123. package/scripts/generators/strategies/week-ahead-strategy.js +178 -0
  124. package/scripts/generators/strategies/week-ahead-strategy.js.map +1 -0
  125. package/scripts/generators/strategies/weekly-review-strategy.d.ts +63 -0
  126. package/scripts/generators/strategies/weekly-review-strategy.d.ts.map +1 -0
  127. package/scripts/generators/strategies/weekly-review-strategy.js +211 -0
  128. package/scripts/generators/strategies/weekly-review-strategy.js.map +1 -0
  129. package/scripts/generators/swot-content.d.ts +42 -0
  130. package/scripts/generators/swot-content.d.ts.map +1 -0
  131. package/scripts/generators/swot-content.js +366 -0
  132. package/scripts/generators/swot-content.js.map +1 -0
  133. package/scripts/generators/week-ahead-content.d.ts +103 -0
  134. package/scripts/generators/week-ahead-content.d.ts.map +1 -0
  135. package/scripts/generators/week-ahead-content.js +610 -0
  136. package/scripts/generators/week-ahead-content.js.map +1 -0
  137. package/scripts/index.d.ts +40 -0
  138. package/scripts/index.d.ts.map +1 -0
  139. package/scripts/index.js +53 -0
  140. package/scripts/index.js.map +1 -0
  141. package/scripts/mcp/ep-mcp-client.d.ts +471 -0
  142. package/scripts/mcp/ep-mcp-client.d.ts.map +1 -0
  143. package/scripts/mcp/ep-mcp-client.js +734 -0
  144. package/scripts/mcp/ep-mcp-client.js.map +1 -0
  145. package/scripts/mcp/mcp-connection.d.ts +264 -0
  146. package/scripts/mcp/mcp-connection.d.ts.map +1 -0
  147. package/scripts/mcp/mcp-connection.js +790 -0
  148. package/scripts/mcp/mcp-connection.js.map +1 -0
  149. package/scripts/mcp/mcp-health.d.ts +75 -0
  150. package/scripts/mcp/mcp-health.d.ts.map +1 -0
  151. package/scripts/mcp/mcp-health.js +78 -0
  152. package/scripts/mcp/mcp-health.js.map +1 -0
  153. package/scripts/mcp/mcp-retry.d.ts +94 -0
  154. package/scripts/mcp/mcp-retry.d.ts.map +1 -0
  155. package/scripts/mcp/mcp-retry.js +127 -0
  156. package/scripts/mcp/mcp-retry.js.map +1 -0
  157. package/scripts/mcp/wb-mcp-client.d.ts +38 -0
  158. package/scripts/mcp/wb-mcp-client.d.ts.map +1 -0
  159. package/scripts/mcp/wb-mcp-client.js +112 -0
  160. package/scripts/mcp/wb-mcp-client.js.map +1 -0
  161. package/scripts/templates/article-template.d.ts +9 -0
  162. package/scripts/templates/article-template.d.ts.map +1 -0
  163. package/scripts/templates/article-template.js +378 -0
  164. package/scripts/templates/article-template.js.map +1 -0
  165. package/scripts/templates/section-builders.d.ts +28 -0
  166. package/scripts/templates/section-builders.d.ts.map +1 -0
  167. package/scripts/templates/section-builders.js +142 -0
  168. package/scripts/templates/section-builders.js.map +1 -0
  169. package/scripts/types/analysis.d.ts +115 -0
  170. package/scripts/types/analysis.d.ts.map +1 -0
  171. package/scripts/types/analysis.js +4 -0
  172. package/scripts/types/analysis.js.map +1 -0
  173. package/scripts/types/common.d.ts +584 -0
  174. package/scripts/types/common.d.ts.map +1 -0
  175. package/scripts/types/common.js +96 -0
  176. package/scripts/types/common.js.map +1 -0
  177. package/scripts/types/generation.d.ts +104 -0
  178. package/scripts/types/generation.d.ts.map +1 -0
  179. package/scripts/types/generation.js +4 -0
  180. package/scripts/types/generation.js.map +1 -0
  181. package/scripts/types/index.d.ts +24 -0
  182. package/scripts/types/index.d.ts.map +1 -0
  183. package/scripts/types/index.js +16 -0
  184. package/scripts/types/index.js.map +1 -0
  185. package/scripts/types/intelligence.d.ts +129 -0
  186. package/scripts/types/intelligence.d.ts.map +1 -0
  187. package/scripts/types/intelligence.js +4 -0
  188. package/scripts/types/intelligence.js.map +1 -0
  189. package/scripts/types/mcp.d.ts +418 -0
  190. package/scripts/types/mcp.d.ts.map +1 -0
  191. package/scripts/types/mcp.js +4 -0
  192. package/scripts/types/mcp.js.map +1 -0
  193. package/scripts/types/parliament.d.ts +388 -0
  194. package/scripts/types/parliament.d.ts.map +1 -0
  195. package/scripts/types/parliament.js +4 -0
  196. package/scripts/types/parliament.js.map +1 -0
  197. package/scripts/types/quality.d.ts +114 -0
  198. package/scripts/types/quality.d.ts.map +1 -0
  199. package/scripts/types/quality.js +4 -0
  200. package/scripts/types/quality.js.map +1 -0
  201. package/scripts/types/stakeholder.d.ts +88 -0
  202. package/scripts/types/stakeholder.d.ts.map +1 -0
  203. package/scripts/types/stakeholder.js +16 -0
  204. package/scripts/types/stakeholder.js.map +1 -0
  205. package/scripts/types/visualization.d.ts +708 -0
  206. package/scripts/types/visualization.d.ts.map +1 -0
  207. package/scripts/types/visualization.js +4 -0
  208. package/scripts/types/visualization.js.map +1 -0
  209. package/scripts/types/world-bank.d.ts +85 -0
  210. package/scripts/types/world-bank.d.ts.map +1 -0
  211. package/scripts/types/world-bank.js +4 -0
  212. package/scripts/types/world-bank.js.map +1 -0
  213. package/scripts/utils/article-category.d.ts +18 -0
  214. package/scripts/utils/article-category.d.ts.map +1 -0
  215. package/scripts/utils/article-category.js +49 -0
  216. package/scripts/utils/article-category.js.map +1 -0
  217. package/scripts/utils/article-quality-scorer.d.ts +87 -0
  218. package/scripts/utils/article-quality-scorer.d.ts.map +1 -0
  219. package/scripts/utils/article-quality-scorer.js +1048 -0
  220. package/scripts/utils/article-quality-scorer.js.map +1 -0
  221. package/scripts/utils/content-metadata.d.ts +34 -0
  222. package/scripts/utils/content-metadata.d.ts.map +1 -0
  223. package/scripts/utils/content-metadata.js +249 -0
  224. package/scripts/utils/content-metadata.js.map +1 -0
  225. package/scripts/utils/content-validator.d.ts +94 -0
  226. package/scripts/utils/content-validator.d.ts.map +1 -0
  227. package/scripts/utils/content-validator.js +489 -0
  228. package/scripts/utils/content-validator.js.map +1 -0
  229. package/scripts/utils/copy-test-reports.d.ts +9 -0
  230. package/scripts/utils/copy-test-reports.d.ts.map +1 -0
  231. package/scripts/utils/copy-test-reports.js +508 -0
  232. package/scripts/utils/copy-test-reports.js.map +1 -0
  233. package/scripts/utils/file-utils.d.ts +144 -0
  234. package/scripts/utils/file-utils.d.ts.map +1 -0
  235. package/scripts/utils/file-utils.js +374 -0
  236. package/scripts/utils/file-utils.js.map +1 -0
  237. package/scripts/utils/fix-articles.d.ts +27 -0
  238. package/scripts/utils/fix-articles.d.ts.map +1 -0
  239. package/scripts/utils/fix-articles.js +510 -0
  240. package/scripts/utils/fix-articles.js.map +1 -0
  241. package/scripts/utils/generate-docs-index.d.ts +8 -0
  242. package/scripts/utils/generate-docs-index.d.ts.map +1 -0
  243. package/scripts/utils/generate-docs-index.js +275 -0
  244. package/scripts/utils/generate-docs-index.js.map +1 -0
  245. package/scripts/utils/html-sanitize.d.ts +18 -0
  246. package/scripts/utils/html-sanitize.d.ts.map +1 -0
  247. package/scripts/utils/html-sanitize.js +57 -0
  248. package/scripts/utils/html-sanitize.js.map +1 -0
  249. package/scripts/utils/intelligence-analysis.d.ts +173 -0
  250. package/scripts/utils/intelligence-analysis.d.ts.map +1 -0
  251. package/scripts/utils/intelligence-analysis.js +936 -0
  252. package/scripts/utils/intelligence-analysis.js.map +1 -0
  253. package/scripts/utils/intelligence-index.d.ts +126 -0
  254. package/scripts/utils/intelligence-index.d.ts.map +1 -0
  255. package/scripts/utils/intelligence-index.js +731 -0
  256. package/scripts/utils/intelligence-index.js.map +1 -0
  257. package/scripts/utils/metadata-utils.d.ts +14 -0
  258. package/scripts/utils/metadata-utils.d.ts.map +1 -0
  259. package/scripts/utils/metadata-utils.js +18 -0
  260. package/scripts/utils/metadata-utils.js.map +1 -0
  261. package/scripts/utils/news-metadata.d.ts +47 -0
  262. package/scripts/utils/news-metadata.d.ts.map +1 -0
  263. package/scripts/utils/news-metadata.js +259 -0
  264. package/scripts/utils/news-metadata.js.map +1 -0
  265. package/scripts/utils/validate-articles.d.ts +2 -0
  266. package/scripts/utils/validate-articles.d.ts.map +1 -0
  267. package/scripts/utils/validate-articles.js +284 -0
  268. package/scripts/utils/validate-articles.js.map +1 -0
  269. package/scripts/utils/validate-ep-api.d.ts +51 -0
  270. package/scripts/utils/validate-ep-api.d.ts.map +1 -0
  271. package/scripts/utils/validate-ep-api.js +160 -0
  272. package/scripts/utils/validate-ep-api.js.map +1 -0
  273. package/scripts/utils/world-bank-data.d.ts +84 -0
  274. package/scripts/utils/world-bank-data.d.ts.map +1 -0
  275. package/scripts/utils/world-bank-data.js +311 -0
  276. package/scripts/utils/world-bank-data.js.map +1 -0
@@ -0,0 +1,215 @@
1
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { ArticleCategory } from '../../types/index.js';
4
+ import { MOTIONS_TITLES, getLocalizedString } from '../../constants/languages.js';
5
+ import { fetchMotionsData, fetchEPFeedData } from '../pipeline/fetch-stage.js';
6
+ import { generateMotionsContent, buildPoliticalAlignmentSection, buildAdoptedTextsSection, PLACEHOLDER_MARKER, } from '../motions-content.js';
7
+ import { buildDeepAnalysisSection } from '../deep-analysis-content.js';
8
+ import { buildVotingAnalysis, buildVotingSwot, buildVotingDashboard, buildVotingMindmap, } from '../analysis-builders.js';
9
+ import { buildSwotSection } from '../swot-content.js';
10
+ import { buildDashboardSection } from '../dashboard-content.js';
11
+ import { buildIntelligenceMindmapSection } from '../mindmap-content.js';
12
+ import { pl } from '../../utils/metadata-utils.js';
13
+ /** Base keywords shared by all Motions articles */
14
+ const MOTIONS_BASE_KEYWORDS = [
15
+ 'European Parliament',
16
+ 'motions',
17
+ 'voting records',
18
+ 'party cohesion',
19
+ 'parliamentary questions',
20
+ ];
21
+ /**
22
+ * Extract content-aware keywords from motions data.
23
+ *
24
+ * Adds voting record titles, anomaly descriptions, question topics,
25
+ * and adopted text titles to the base keyword set.
26
+ *
27
+ * @param data - Motions article data payload
28
+ * @returns Deduplicated keyword array
29
+ */
30
+ function buildMotionsKeywords(data) {
31
+ const keywords = [...MOTIONS_BASE_KEYWORDS];
32
+ for (const r of data.votingRecords.slice(0, 5)) {
33
+ if (r.title)
34
+ keywords.push(r.title.slice(0, 60));
35
+ }
36
+ for (const a of data.anomalies.slice(0, 3)) {
37
+ if (a.type)
38
+ keywords.push(a.type);
39
+ }
40
+ for (const q of data.questions.slice(0, 3)) {
41
+ if (q.topic)
42
+ keywords.push(q.topic);
43
+ }
44
+ if (data.feedData?.adoptedTexts) {
45
+ for (const text of data.feedData.adoptedTexts.slice(0, 3)) {
46
+ if (text.title)
47
+ keywords.push(text.title.slice(0, 60));
48
+ }
49
+ }
50
+ return [...new Set(keywords)];
51
+ }
52
+ /**
53
+ * Build a content-aware description from motions data.
54
+ * Summarises voting record count, anomaly count, and key vote highlights.
55
+ *
56
+ * @param data - Motions article data payload
57
+ * @returns SEO-friendly description (≤ 200 chars)
58
+ */
59
+ function buildMotionsDescription(data) {
60
+ const parts = [];
61
+ if (data.votingRecords.length > 0)
62
+ parts.push(`${pl(data.votingRecords.length, 'vote', 'votes')} analysed`);
63
+ if (data.anomalies.length > 0)
64
+ parts.push(`${pl(data.anomalies.length, 'anomaly', 'anomalies')} detected`);
65
+ if (data.questions.length > 0)
66
+ parts.push(pl(data.questions.length, 'parliamentary question', 'parliamentary questions'));
67
+ const adoptedCount = data.feedData?.adoptedTexts?.length ?? 0;
68
+ if (adoptedCount > 0)
69
+ parts.push(pl(adoptedCount, 'adopted text', 'adopted texts'));
70
+ if (parts.length === 0) {
71
+ return `European Parliament plenary votes and resolutions from ${data.dateFromStr} to ${data.date}.`;
72
+ }
73
+ const highlight = data.votingRecords[0]?.title ?? '';
74
+ const base = `EP voting analysis: ${parts.join(', ')}`;
75
+ if (highlight) {
76
+ const full = `${base}. Key vote: ${highlight}`;
77
+ return full.length > 200 ? full.slice(0, 197) + '...' : full;
78
+ }
79
+ return base.length > 200 ? base.slice(0, 197) + '...' : base;
80
+ }
81
+ /**
82
+ * Build a content-aware title suffix from motions data counts.
83
+ *
84
+ * @param data - Motions article data payload
85
+ * @returns Short suffix for the title, or empty string
86
+ */
87
+ function buildMotionsTitleSuffix(data) {
88
+ const parts = [];
89
+ if (data.votingRecords.length > 0) {
90
+ parts.push(pl(data.votingRecords.length, 'Vote', 'Votes'));
91
+ }
92
+ if (data.anomalies.length > 0) {
93
+ parts.push(pl(data.anomalies.length, 'Anomaly', 'Anomalies'));
94
+ }
95
+ const adoptedCount = data.feedData?.adoptedTexts?.length ?? 0;
96
+ if (adoptedCount > 0) {
97
+ parts.push(pl(adoptedCount, 'Adopted Text', 'Adopted Texts'));
98
+ }
99
+ return parts.join(', ');
100
+ }
101
+ /** Number of days to look back when fetching motions data */
102
+ const MOTIONS_LOOKBACK_DAYS = 30;
103
+ // ─── Strategy implementation ──────────────────────────────────────────────────
104
+ /**
105
+ * Article strategy for {@link ArticleCategory.MOTIONS}.
106
+ * Aggregates voting data over a rolling 30-day window and surfaces
107
+ * patterns, anomalies and parliamentary questions.
108
+ */
109
+ export class MotionsStrategy {
110
+ type = ArticleCategory.MOTIONS;
111
+ requiredMCPTools = [
112
+ 'get_voting_records',
113
+ 'analyze_voting_patterns',
114
+ 'detect_voting_anomalies',
115
+ 'get_parliamentary_questions',
116
+ 'get_adopted_texts_feed',
117
+ 'get_parliamentary_questions_feed',
118
+ ];
119
+ /**
120
+ * Fetch all motions data for the last 30 days.
121
+ *
122
+ * @param client - MCP client or null
123
+ * @param date - ISO 8601 publication date (end of the look-back window)
124
+ * @returns Populated motions data payload
125
+ */
126
+ async fetchData(client, date) {
127
+ const dateFrom = new Date(`${date}T00:00:00Z`);
128
+ dateFrom.setUTCDate(dateFrom.getUTCDate() - MOTIONS_LOOKBACK_DAYS);
129
+ const dateFromParts = dateFrom.toISOString().split('T');
130
+ if (!dateFromParts[0]) {
131
+ throw new Error('Invalid date format generated for motions look-back window');
132
+ }
133
+ const dateFromStr = dateFromParts[0];
134
+ // Fetch voting data and EP feed data in parallel
135
+ const feedDateRange = { start: dateFromStr, end: date };
136
+ const [motionsDataResult, feedData] = await Promise.all([
137
+ fetchMotionsData(client, dateFromStr, date),
138
+ fetchEPFeedData(client, 'one-month', feedDateRange),
139
+ ]);
140
+ const { votingRecords, votingPatterns, anomalies, questions } = motionsDataResult;
141
+ return {
142
+ date,
143
+ dateFromStr,
144
+ votingRecords,
145
+ votingPatterns,
146
+ anomalies,
147
+ questions,
148
+ feedData,
149
+ };
150
+ }
151
+ /**
152
+ * Build the motions HTML body for the specified language.
153
+ *
154
+ * @param data - Motions data payload
155
+ * @param lang - Target language code used for editorial strings
156
+ * @returns Article HTML body
157
+ */
158
+ buildContent(data, lang) {
159
+ const base = generateMotionsContent(data.dateFromStr, data.date, [...data.votingRecords], [...data.votingPatterns], [...data.anomalies], [...data.questions], lang);
160
+ const adoptedTextsSection = data.feedData?.adoptedTexts
161
+ ? buildAdoptedTextsSection(data.feedData.adoptedTexts, lang)
162
+ : '';
163
+ const alignmentSection = buildPoliticalAlignmentSection([...data.votingRecords], [], lang);
164
+ const analysis = buildVotingAnalysis(data.dateFromStr, data.date, data.votingRecords, data.votingPatterns, data.anomalies, data.questions);
165
+ const deepSection = buildDeepAnalysisSection(analysis, lang, 'en');
166
+ const mindmapData = buildVotingMindmap(data.votingRecords, data.votingPatterns, data.anomalies, lang);
167
+ const mindmapSection = buildIntelligenceMindmapSection(mindmapData, lang);
168
+ const swotData = buildVotingSwot(data.votingRecords, data.votingPatterns, data.anomalies, lang);
169
+ const swotSection = buildSwotSection(swotData, lang);
170
+ const hasRealVotingData = data.votingRecords.some((r) => r.result !== PLACEHOLDER_MARKER);
171
+ const dashboardData = hasRealVotingData
172
+ ? buildVotingDashboard(data.votingRecords, data.votingPatterns, data.anomalies, lang)
173
+ : null;
174
+ const dashboardSection = buildDashboardSection(dashboardData, lang);
175
+ // Inject at the explicit <!-- /article-content --> marker so the section
176
+ // stays inside the .article-content styling scope. The marker is always
177
+ // emitted by generateMotionsContent as the last child of that wrapper and
178
+ // is removed from the final HTML during this replacement.
179
+ const injection = adoptedTextsSection +
180
+ (alignmentSection || '') +
181
+ deepSection +
182
+ mindmapSection +
183
+ swotSection +
184
+ dashboardSection;
185
+ if (injection) {
186
+ return base.replace('<!-- /article-content -->', `${injection}\n`);
187
+ }
188
+ return base.replace('<!-- /article-content -->', '');
189
+ }
190
+ /**
191
+ * Return language-specific metadata for the motions article.
192
+ *
193
+ * @param data - Motions data payload
194
+ * @param lang - Target language code
195
+ * @returns Localised metadata
196
+ */
197
+ getMetadata(data, lang) {
198
+ const titleFn = getLocalizedString(MOTIONS_TITLES, lang);
199
+ const { title: baseTitle, subtitle: baseSubtitle } = titleFn(data.date);
200
+ const suffix = lang === 'en' ? buildMotionsTitleSuffix(data) : '';
201
+ const title = suffix ? `${baseTitle} — ${suffix}` : baseTitle;
202
+ const description = lang === 'en' ? buildMotionsDescription(data) : '';
203
+ const subtitle = description || baseSubtitle;
204
+ return {
205
+ title,
206
+ subtitle,
207
+ keywords: buildMotionsKeywords(data),
208
+ category: ArticleCategory.MOTIONS,
209
+ sources: [],
210
+ };
211
+ }
212
+ }
213
+ /** Singleton instance for use by the strategy registry */
214
+ export const motionsStrategy = new MotionsStrategy();
215
+ //# sourceMappingURL=motions-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motions-strategy.js","sourceRoot":"","sources":["../../../src/generators/strategies/motions-strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @module Generators/Strategies/PropositionsStrategy
3
+ * @description Article strategy for the Propositions article type.
4
+ * Fetches legislative proposals and active pipeline data from MCP, then
5
+ * renders a language-specific legislative overview article.
6
+ */
7
+ import type { EuropeanParliamentMCPClient } from '../../mcp/ep-mcp-client.js';
8
+ import { ArticleCategory } from '../../types/index.js';
9
+ import type { LanguageCode, EPFeedData } from '../../types/index.js';
10
+ import type { PipelineData } from '../propositions-content.js';
11
+ import type { ArticleStrategy, ArticleData, ArticleMetadata } from './article-strategy.js';
12
+ /** Data fetched and pre-processed by {@link PropositionsStrategy} */
13
+ export interface PropositionsArticleData extends ArticleData {
14
+ /** Pre-sanitised HTML for the legislative procedures list section */
15
+ readonly proposalsHtml: string;
16
+ /** Pre-sanitised HTML for the recently adopted texts section */
17
+ readonly adoptedTextsHtml: string;
18
+ /** Active legislative pipeline data (null when MCP unavailable) */
19
+ readonly pipelineData: PipelineData | null;
20
+ /** Pre-sanitised HTML for the tracked procedure section */
21
+ readonly procedureHtml: string;
22
+ /** EP feed data for enrichment (when available) */
23
+ readonly feedData?: EPFeedData | undefined;
24
+ }
25
+ /**
26
+ * Article strategy for {@link ArticleCategory.PROPOSITIONS}.
27
+ * Fetches legislative proposals, active pipeline status, and procedure detail
28
+ * then renders a language-specific article.
29
+ */
30
+ export declare class PropositionsStrategy implements ArticleStrategy<PropositionsArticleData> {
31
+ readonly type = ArticleCategory.PROPOSITIONS;
32
+ readonly requiredMCPTools: readonly ["search_documents", "monitor_legislative_pipeline", "track_legislation", "get_procedures_feed", "get_adopted_texts_feed"];
33
+ /**
34
+ * Fetch legislative proposals and pipeline data in parallel.
35
+ *
36
+ * @param client - MCP client or null
37
+ * @param date - ISO 8601 publication date
38
+ * @returns Populated propositions data payload
39
+ */
40
+ fetchData(client: EuropeanParliamentMCPClient | null, date: string): Promise<PropositionsArticleData>;
41
+ /**
42
+ * Build the propositions HTML body using language-specific strings.
43
+ *
44
+ * @param data - Propositions data payload
45
+ * @param lang - Target language code
46
+ * @returns Article HTML body
47
+ */
48
+ buildContent(data: PropositionsArticleData, lang: LanguageCode): string;
49
+ /**
50
+ * Return language-specific metadata for the propositions article.
51
+ *
52
+ * @param data - Propositions data payload
53
+ * @param lang - Target language code
54
+ * @returns Localised metadata
55
+ */
56
+ getMetadata(data: PropositionsArticleData, lang: LanguageCode): ArticleMetadata;
57
+ }
58
+ /** Singleton instance for use by the strategy registry */
59
+ export declare const propositionsStrategy: PropositionsStrategy;
60
+ //# sourceMappingURL=propositions-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propositions-strategy.d.ts","sourceRoot":"","sources":["../../../src/generators/strategies/propositions-strategy.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAyBrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AA2I3F,qEAAqE;AACrE,MAAM,WAAW,uBAAwB,SAAQ,WAAW;IAC1D,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3C,2DAA2D;IAC3D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC5C;AAID;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,eAAe,CAAC,uBAAuB,CAAC;IACnF,QAAQ,CAAC,IAAI,gCAAgC;IAE7C,QAAQ,CAAC,gBAAgB,sIAMd;IAEX;;;;;;OAMG;IACG,SAAS,CACb,MAAM,EAAE,2BAA2B,GAAG,IAAI,EAC1C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,uBAAuB,CAAC;IAsDnC;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAoCvE;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,YAAY,GAAG,eAAe;CAehF;AAED,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,sBAA6B,CAAC"}
@@ -0,0 +1,257 @@
1
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { ArticleCategory } from '../../types/index.js';
4
+ import { escapeHTML } from '../../utils/file-utils.js';
5
+ import { PROPOSITIONS_TITLES, PROPOSITIONS_STRINGS, getLocalizedString, } from '../../constants/languages.js';
6
+ import { computeRollingDateRange, fetchProposalsFromMCP, fetchPipelineFromMCP, fetchProcedureStatusFromMCP, fetchEPFeedData, } from '../pipeline/fetch-stage.js';
7
+ import { buildPropositionsContent } from '../propositions-content.js';
8
+ import { buildDeepAnalysisSection } from '../deep-analysis-content.js';
9
+ import { buildPropositionsAnalysis, buildPropositionsSwot, buildPropositionsDashboard, buildPropositionsMindmap, } from '../analysis-builders.js';
10
+ import { buildSwotSection } from '../swot-content.js';
11
+ import { buildDashboardSection } from '../dashboard-content.js';
12
+ import { buildIntelligenceMindmapSection } from '../mindmap-content.js';
13
+ import { pl } from '../../utils/metadata-utils.js';
14
+ /** Base keywords shared by all Propositions articles */
15
+ const PROPOSITIONS_BASE_KEYWORDS = [
16
+ 'European Parliament',
17
+ 'legislation',
18
+ 'proposals',
19
+ 'procedure',
20
+ 'OLP',
21
+ ];
22
+ /**
23
+ * Extract content-aware keywords from propositions data and feed.
24
+ *
25
+ * Adds procedure titles, adopted text titles, and pipeline health
26
+ * indicators to the base keyword set.
27
+ *
28
+ * @param data - Propositions article data payload
29
+ * @returns Deduplicated keyword array
30
+ */
31
+ function buildPropositionsKeywords(data) {
32
+ const keywords = [...PROPOSITIONS_BASE_KEYWORDS];
33
+ if (data.feedData?.procedures) {
34
+ for (const proc of data.feedData.procedures.slice(0, 5)) {
35
+ if (proc.title)
36
+ keywords.push(proc.title.slice(0, 60));
37
+ }
38
+ }
39
+ if (data.feedData?.adoptedTexts) {
40
+ for (const text of data.feedData.adoptedTexts.slice(0, 3)) {
41
+ if (text.title)
42
+ keywords.push(text.title.slice(0, 60));
43
+ }
44
+ }
45
+ if (data.pipelineData) {
46
+ keywords.push('legislative pipeline');
47
+ if (data.pipelineData.healthScore >= 0.8)
48
+ keywords.push('healthy pipeline');
49
+ }
50
+ return [...new Set(keywords)];
51
+ }
52
+ /**
53
+ * Build a content-aware description from propositions data.
54
+ * Summarises pipeline health, procedure counts, and adopted text counts.
55
+ *
56
+ * @param data - Propositions article data payload
57
+ * @returns SEO-friendly description (≤ 200 chars)
58
+ */
59
+ function buildPropositionsDescription(data) {
60
+ const parts = [];
61
+ const procCount = data.feedData?.procedures?.length ?? 0;
62
+ const adoptedCount = data.feedData?.adoptedTexts?.length ?? 0;
63
+ // Count proposals by the number of proposal-card divs in the HTML
64
+ const proposalMatches = data.proposalsHtml.match(/proposal-card/gu);
65
+ const proposalCount = proposalMatches ? proposalMatches.length : 0;
66
+ if (proposalCount > 0)
67
+ parts.push(`${proposalCount} active proposals`);
68
+ if (procCount > 0)
69
+ parts.push(`${procCount} procedures tracked`);
70
+ if (adoptedCount > 0)
71
+ parts.push(`${adoptedCount} recently adopted texts`);
72
+ if (data.pipelineData) {
73
+ const healthPct = Math.round(data.pipelineData.healthScore * 100);
74
+ parts.push(`pipeline health ${healthPct}%`);
75
+ }
76
+ if (parts.length === 0) {
77
+ return 'Recent legislative proposals, procedure tracking, and pipeline status in the European Parliament';
78
+ }
79
+ const desc = `EP legislative tracker: ${parts.join(', ')}.`;
80
+ return desc.length > 200 ? desc.slice(0, 197) + '...' : desc;
81
+ }
82
+ /**
83
+ * Build a content-aware title suffix from propositions data.
84
+ *
85
+ * @param data - Propositions article data payload
86
+ * @returns Short suffix for the title, or empty string
87
+ */
88
+ function buildPropositionsTitleSuffix(data) {
89
+ const parts = [];
90
+ const procCount = data.feedData?.procedures?.length ?? 0;
91
+ const adoptedCount = data.feedData?.adoptedTexts?.length ?? 0;
92
+ if (procCount > 0)
93
+ parts.push(pl(procCount, 'Procedure', 'Procedures'));
94
+ if (adoptedCount > 0)
95
+ parts.push(pl(adoptedCount, 'Adopted Text', 'Adopted Texts'));
96
+ if (data.pipelineData && parts.length === 0) {
97
+ const healthPct = Math.round(data.pipelineData.healthScore * 100);
98
+ parts.push(`Pipeline ${healthPct}%`);
99
+ }
100
+ return parts.join(', ');
101
+ }
102
+ /**
103
+ * Build procedures and adopted-texts HTML separately from EP feed data when
104
+ * search_documents returns empty. Uses procedures and adopted texts from the
105
+ * feed as fallback content, rendering each as a distinct section.
106
+ *
107
+ * @param feedData - EP feed data containing procedures and adopted texts
108
+ * @returns Pre-sanitized HTML for procedures and adopted texts sections separately
109
+ */
110
+ function buildProceduresAndAdoptedTextsFromFeed(feedData) {
111
+ const procedureItems = [];
112
+ const adoptedTextItems = [];
113
+ for (const proc of feedData.procedures.slice(0, 8)) {
114
+ procedureItems.push(`
115
+ <div class="proposal-card">
116
+ <h3>${escapeHTML(proc.title || proc.id)}</h3>
117
+ <div class="proposal-meta">
118
+ <span class="proposal-id">${escapeHTML(proc.identifier ?? proc.id)}</span>
119
+ ${proc.date ? `<span class="proposal-date">${escapeHTML(proc.date)}</span>` : ''}
120
+ ${proc.stage ? `<span class="proposal-status">${escapeHTML(proc.stage)}</span>` : ''}
121
+ </div>
122
+ </div>`);
123
+ }
124
+ for (const text of feedData.adoptedTexts.slice(0, 8)) {
125
+ adoptedTextItems.push(`
126
+ <div class="proposal-card">
127
+ <h3>${escapeHTML(text.title || text.id)}</h3>
128
+ <div class="proposal-meta">
129
+ <span class="proposal-id">${escapeHTML(text.identifier ?? text.id)}</span>
130
+ ${text.date ? `<span class="proposal-date">${escapeHTML(text.date)}</span>` : ''}
131
+ </div>
132
+ </div>`);
133
+ }
134
+ return {
135
+ proceduresHtml: procedureItems.join('\n'),
136
+ adoptedTextsHtml: adoptedTextItems.join('\n'),
137
+ };
138
+ }
139
+ // ─── Strategy implementation ──────────────────────────────────────────────────
140
+ /**
141
+ * Article strategy for {@link ArticleCategory.PROPOSITIONS}.
142
+ * Fetches legislative proposals, active pipeline status, and procedure detail
143
+ * then renders a language-specific article.
144
+ */
145
+ export class PropositionsStrategy {
146
+ type = ArticleCategory.PROPOSITIONS;
147
+ requiredMCPTools = [
148
+ 'search_documents',
149
+ 'monitor_legislative_pipeline',
150
+ 'track_legislation',
151
+ 'get_procedures_feed',
152
+ 'get_adopted_texts_feed',
153
+ ];
154
+ /**
155
+ * Fetch legislative proposals and pipeline data in parallel.
156
+ *
157
+ * @param client - MCP client or null
158
+ * @param date - ISO 8601 publication date
159
+ * @returns Populated propositions data payload
160
+ */
161
+ async fetchData(client, date) {
162
+ const feedDateRange = computeRollingDateRange(date, 7, 'propositions feed window');
163
+ if (client) {
164
+ console.log(' 📡 Fetching legislative data from MCP server...');
165
+ }
166
+ // Fetch proposals, pipeline, and EP feed data in parallel
167
+ const [proposalsResult, pipelineResult, feedData] = await Promise.allSettled([
168
+ fetchProposalsFromMCP(client),
169
+ fetchPipelineFromMCP(client),
170
+ fetchEPFeedData(client, 'one-week', feedDateRange),
171
+ ]);
172
+ const { html: proposalsHtml, firstProcedureId } = proposalsResult.status === 'fulfilled'
173
+ ? proposalsResult.value
174
+ : { html: '', firstProcedureId: '' };
175
+ const pipelineData = pipelineResult.status === 'fulfilled' ? pipelineResult.value : null;
176
+ const feedResult = feedData.status === 'fulfilled' ? feedData.value : undefined;
177
+ const procedureHtml = await fetchProcedureStatusFromMCP(client, firstProcedureId);
178
+ // When search_documents returns empty but feed data has procedures/adopted texts,
179
+ // build proposals HTML from the feed data as fallback
180
+ let finalProposalsHtml = proposalsHtml;
181
+ let finalAdoptedTextsHtml = '';
182
+ if (!finalProposalsHtml && feedResult) {
183
+ const hasFeedItems = feedResult.procedures.length > 0 || feedResult.adoptedTexts.length > 0;
184
+ if (hasFeedItems) {
185
+ console.log(` 📰 Building procedures/adopted-texts from feed data: ${feedResult.procedures.length} procedures, ${feedResult.adoptedTexts.length} adopted texts`);
186
+ const feedHtml = buildProceduresAndAdoptedTextsFromFeed(feedResult);
187
+ finalProposalsHtml = feedHtml.proceduresHtml;
188
+ finalAdoptedTextsHtml = feedHtml.adoptedTextsHtml;
189
+ }
190
+ }
191
+ if (!finalProposalsHtml && !finalAdoptedTextsHtml) {
192
+ console.log(' ℹ️ No proposals from MCP — pipeline article will be data-free');
193
+ }
194
+ return {
195
+ date,
196
+ proposalsHtml: finalProposalsHtml,
197
+ adoptedTextsHtml: finalAdoptedTextsHtml,
198
+ pipelineData,
199
+ procedureHtml,
200
+ feedData: feedResult,
201
+ };
202
+ }
203
+ /**
204
+ * Build the propositions HTML body using language-specific strings.
205
+ *
206
+ * @param data - Propositions data payload
207
+ * @param lang - Target language code
208
+ * @returns Article HTML body
209
+ */
210
+ buildContent(data, lang) {
211
+ const strings = getLocalizedString(PROPOSITIONS_STRINGS, lang);
212
+ const base = buildPropositionsContent(data.proposalsHtml, data.adoptedTextsHtml, data.pipelineData, data.procedureHtml, strings, lang);
213
+ const analysis = buildPropositionsAnalysis(data.proposalsHtml, data.pipelineData, data.date, lang, data.adoptedTextsHtml);
214
+ const deepSection = buildDeepAnalysisSection(analysis, lang, 'en');
215
+ const mindmapData = buildPropositionsMindmap(data.pipelineData, lang);
216
+ const mindmapSection = buildIntelligenceMindmapSection(mindmapData, lang);
217
+ const swotData = buildPropositionsSwot(data.pipelineData, lang);
218
+ const swotSection = buildSwotSection(swotData, lang);
219
+ const dashboardData = buildPropositionsDashboard(data.pipelineData, lang);
220
+ const dashboardSection = buildDashboardSection(dashboardData, lang);
221
+ const injection = deepSection + mindmapSection + swotSection + dashboardSection;
222
+ // Inject before the closing </div> of .article-content
223
+ if (injection) {
224
+ const closingTag = '</div>';
225
+ const lastIdx = base.lastIndexOf(closingTag);
226
+ if (lastIdx !== -1) {
227
+ return base.slice(0, lastIdx) + injection + '\n' + base.slice(lastIdx);
228
+ }
229
+ }
230
+ return base;
231
+ }
232
+ /**
233
+ * Return language-specific metadata for the propositions article.
234
+ *
235
+ * @param data - Propositions data payload
236
+ * @param lang - Target language code
237
+ * @returns Localised metadata
238
+ */
239
+ getMetadata(data, lang) {
240
+ const titleFn = getLocalizedString(PROPOSITIONS_TITLES, lang);
241
+ const { title: baseTitle, subtitle: baseSubtitle } = titleFn();
242
+ const suffix = lang === 'en' ? buildPropositionsTitleSuffix(data) : '';
243
+ const title = suffix ? `${baseTitle} — ${suffix}` : baseTitle;
244
+ const helperSubtitle = lang === 'en' ? buildPropositionsDescription(data) : '';
245
+ const subtitle = helperSubtitle || baseSubtitle;
246
+ return {
247
+ title,
248
+ subtitle,
249
+ keywords: buildPropositionsKeywords(data),
250
+ category: ArticleCategory.PROPOSITIONS,
251
+ sources: [],
252
+ };
253
+ }
254
+ }
255
+ /** Singleton instance for use by the strategy registry */
256
+ export const propositionsStrategy = new PropositionsStrategy();
257
+ //# sourceMappingURL=propositions-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propositions-strategy.js","sourceRoot":"","sources":["../../../src/generators/strategies/propositions-strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @module Generators/Strategies/WeekAheadStrategy
3
+ * @description Article strategy for the Week Ahead article type.
4
+ * Fetches plenary sessions, committee meetings, documents, pipeline and
5
+ * parliamentary questions then renders a forward-looking HTML article.
6
+ */
7
+ import type { EuropeanParliamentMCPClient } from '../../mcp/ep-mcp-client.js';
8
+ import { ArticleCategory } from '../../types/index.js';
9
+ import type { LanguageCode, DateRange, WeekAheadData, EPFeedData } from '../../types/index.js';
10
+ import type { ArticleStrategy, ArticleData, ArticleMetadata } from './article-strategy.js';
11
+ /** Data fetched and pre-processed by {@link WeekAheadStrategy} */
12
+ export interface WeekAheadArticleData extends ArticleData {
13
+ /** Week-ahead date range */
14
+ readonly dateRange: DateRange;
15
+ /** Aggregated week-ahead domain data */
16
+ readonly weekData: WeekAheadData;
17
+ /** SEO keywords derived from the week-ahead data */
18
+ readonly keywords: readonly string[];
19
+ /** EP feed data for enrichment (when available) */
20
+ readonly feedData?: EPFeedData | undefined;
21
+ }
22
+ /**
23
+ * Article strategy for {@link ArticleCategory.WEEK_AHEAD}.
24
+ * Fetches plenary, committee, document, pipeline and question data then builds
25
+ * a forward-looking preview of the upcoming parliamentary week.
26
+ */
27
+ export declare class WeekAheadStrategy implements ArticleStrategy<WeekAheadArticleData> {
28
+ readonly type = ArticleCategory.WEEK_AHEAD;
29
+ readonly requiredMCPTools: readonly ["get_plenary_sessions", "get_committee_info", "search_documents", "monitor_legislative_pipeline", "get_parliamentary_questions", "get_events", "get_events_feed", "get_plenary_documents_feed", "get_adopted_texts_feed"];
30
+ /**
31
+ * Fetch week-ahead data from MCP.
32
+ *
33
+ * @param client - MCP client or null
34
+ * @param date - ISO 8601 publication date
35
+ * @returns Populated week-ahead data payload
36
+ */
37
+ fetchData(client: EuropeanParliamentMCPClient | null, date: string): Promise<WeekAheadArticleData>;
38
+ /**
39
+ * Build the week-ahead HTML body for the specified language.
40
+ *
41
+ * @param data - Week-ahead data payload
42
+ * @param lang - Target language code used for editorial strings
43
+ * @returns Article HTML body
44
+ */
45
+ buildContent(data: WeekAheadArticleData, lang: LanguageCode): string;
46
+ /**
47
+ * Return language-specific metadata for the week-ahead article.
48
+ *
49
+ * @param data - Week-ahead data payload
50
+ * @param lang - Target language code
51
+ * @returns Localised metadata
52
+ */
53
+ getMetadata(data: WeekAheadArticleData, lang: LanguageCode): ArticleMetadata;
54
+ }
55
+ /** Singleton instance for use by the strategy registry */
56
+ export declare const weekAheadStrategy: WeekAheadStrategy;
57
+ //# sourceMappingURL=week-ahead-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"week-ahead-strategy.d.ts","sourceRoot":"","sources":["../../../src/generators/strategies/week-ahead-strategy.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAkB/F,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK3F,kEAAkE;AAClE,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC5C;AAuFD;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,eAAe,CAAC,oBAAoB,CAAC;IAC7E,QAAQ,CAAC,IAAI,8BAA8B;IAE3C,QAAQ,CAAC,gBAAgB,sOAUd;IAEX;;;;;;OAMG;IACG,SAAS,CACb,MAAM,EAAE,2BAA2B,GAAG,IAAI,EAC1C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,oBAAoB,CAAC;IAoBhC;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM;IAsBpE;;;;;;OAMG;IACH,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,YAAY,GAAG,eAAe;CAoB7E;AAED,0DAA0D;AAC1D,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}