euparliamentmonitor 0.9.19 → 0.9.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +4 -3
- package/scripts/aggregator/editorial-brief-resolver.d.ts +38 -0
- package/scripts/aggregator/editorial-brief-resolver.js +32 -0
- package/scripts/aggregator/generator/render-one.js +35 -0
- package/scripts/aggregator/html/localize-body.d.ts +32 -0
- package/scripts/aggregator/html/localize-body.js +69 -0
- package/scripts/aggregator/html/shell.d.ts +10 -0
- package/scripts/aggregator/html/shell.js +11 -1
- package/scripts/aggregator/markdown-renderer.d.ts +23 -24
- package/scripts/aggregator/markdown-renderer.js +39 -25
- package/scripts/aggregator/metadata/artifact-highlight.d.ts +15 -22
- package/scripts/aggregator/metadata/artifact-highlight.js +14 -230
- package/scripts/aggregator/metadata/artifact-walker.d.ts +34 -0
- package/scripts/aggregator/metadata/artifact-walker.js +177 -0
- package/scripts/aggregator/metadata/editorial-highlight.d.ts +15 -0
- package/scripts/aggregator/metadata/editorial-highlight.js +53 -0
- package/scripts/aggregator/metadata/priority-finding-highlight.js +7 -2
- package/scripts/aggregator/metadata/resolve-helpers.js +9 -3
- package/scripts/aggregator/metadata/text-utils.js +7 -0
- package/scripts/aggregator/metadata/translated-sibling.d.ts +23 -0
- package/scripts/aggregator/metadata/translated-sibling.js +39 -0
- package/scripts/aggregator/reader-guide/builder.js +3 -1
- package/scripts/aggregator/reader-guide/labels.d.ts +7 -0
- package/scripts/aggregator/reader-guide/labels.js +22 -0
- package/scripts/aggregator/reader-intelligence-guide.d.ts +1 -1
- package/scripts/aggregator/reader-intelligence-guide.js +1 -1
- package/scripts/aggregator/seo-entity-extractor.d.ts +45 -0
- package/scripts/aggregator/seo-entity-extractor.js +211 -0
- package/scripts/constants/articles/breaking-strings-central.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-central.js +105 -0
- package/scripts/constants/articles/breaking-strings-east.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-east.js +203 -0
- package/scripts/constants/articles/breaking-strings-nordic.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-nordic.js +252 -0
- package/scripts/constants/articles/breaking-strings-west.d.ts +8 -0
- package/scripts/constants/articles/breaking-strings-west.js +154 -0
- package/scripts/constants/articles/breaking.d.ts +0 -1
- package/scripts/constants/articles/breaking.js +9 -6
- package/scripts/constants/articles/dashboard/ar.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ar.js +71 -0
- package/scripts/constants/articles/dashboard/da.d.ts +8 -0
- package/scripts/constants/articles/dashboard/da.js +71 -0
- package/scripts/constants/articles/dashboard/de.d.ts +8 -0
- package/scripts/constants/articles/dashboard/de.js +71 -0
- package/scripts/constants/articles/dashboard/en.d.ts +8 -0
- package/scripts/constants/articles/dashboard/en.js +71 -0
- package/scripts/constants/articles/dashboard/es.d.ts +8 -0
- package/scripts/constants/articles/dashboard/es.js +71 -0
- package/scripts/constants/articles/dashboard/fi.d.ts +8 -0
- package/scripts/constants/articles/dashboard/fi.js +71 -0
- package/scripts/constants/articles/dashboard/fr.d.ts +8 -0
- package/scripts/constants/articles/dashboard/fr.js +71 -0
- package/scripts/constants/articles/dashboard/he.d.ts +8 -0
- package/scripts/constants/articles/dashboard/he.js +71 -0
- package/scripts/constants/articles/dashboard/index.d.ts +7 -0
- package/scripts/constants/articles/dashboard/index.js +33 -0
- package/scripts/constants/articles/dashboard/ja.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ja.js +71 -0
- package/scripts/constants/articles/dashboard/ko.d.ts +8 -0
- package/scripts/constants/articles/dashboard/ko.js +71 -0
- package/scripts/constants/articles/dashboard/nl.d.ts +8 -0
- package/scripts/constants/articles/dashboard/nl.js +71 -0
- package/scripts/constants/articles/dashboard/no.d.ts +8 -0
- package/scripts/constants/articles/dashboard/no.js +71 -0
- package/scripts/constants/articles/dashboard/sv.d.ts +8 -0
- package/scripts/constants/articles/dashboard/sv.js +71 -0
- package/scripts/constants/articles/dashboard/zh.d.ts +8 -0
- package/scripts/constants/articles/dashboard/zh.js +71 -0
- package/scripts/constants/articles/dashboard.d.ts +7 -2
- package/scripts/constants/articles/dashboard.js +4 -8
- package/scripts/constants/articles/deep-analysis/ar.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ar.js +75 -0
- package/scripts/constants/articles/deep-analysis/da.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/da.js +75 -0
- package/scripts/constants/articles/deep-analysis/de.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/de.js +75 -0
- package/scripts/constants/articles/deep-analysis/en.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/en.js +75 -0
- package/scripts/constants/articles/deep-analysis/es.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/es.js +75 -0
- package/scripts/constants/articles/deep-analysis/fi.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/fi.js +75 -0
- package/scripts/constants/articles/deep-analysis/fr.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/fr.js +75 -0
- package/scripts/constants/articles/deep-analysis/he.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/he.js +75 -0
- package/scripts/constants/articles/deep-analysis/index.d.ts +7 -0
- package/scripts/constants/articles/deep-analysis/index.js +33 -0
- package/scripts/constants/articles/deep-analysis/ja.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ja.js +75 -0
- package/scripts/constants/articles/deep-analysis/ko.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/ko.js +75 -0
- package/scripts/constants/articles/deep-analysis/nl.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/nl.js +75 -0
- package/scripts/constants/articles/deep-analysis/no.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/no.js +75 -0
- package/scripts/constants/articles/deep-analysis/sv.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/sv.js +75 -0
- package/scripts/constants/articles/deep-analysis/zh.d.ts +8 -0
- package/scripts/constants/articles/deep-analysis/zh.js +75 -0
- package/scripts/constants/articles/deep-analysis.d.ts +4 -3
- package/scripts/constants/articles/deep-analysis.js +3 -7
- package/scripts/constants/articles/localized-keywords-central.d.ts +8 -0
- package/scripts/constants/articles/localized-keywords-central.js +118 -0
- package/scripts/constants/articles/localized-keywords-nordic.d.ts +8 -0
- package/scripts/constants/articles/localized-keywords-nordic.js +303 -0
- package/scripts/constants/articles/localized-keywords.js +4 -2
- package/scripts/constants/articles/swot-builder-central.d.ts +8 -0
- package/scripts/constants/articles/swot-builder-central.js +90 -0
- package/scripts/constants/articles/swot-builder-nordic.d.ts +8 -0
- package/scripts/constants/articles/swot-builder-nordic.js +216 -0
- package/scripts/constants/articles/swot.js +4 -2
- package/scripts/constants/articles/week-ahead-eu.d.ts +12 -0
- package/scripts/constants/articles/week-ahead-eu.js +278 -0
- package/scripts/constants/articles/week-ahead-global.d.ts +12 -0
- package/scripts/constants/articles/week-ahead-global.js +278 -0
- package/scripts/constants/articles/week-ahead.d.ts +4 -7
- package/scripts/constants/articles/week-ahead.js +11 -535
- package/scripts/constants/world-bank/category-map-analysis.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-analysis.js +204 -0
- package/scripts/constants/world-bank/category-map-legislative.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-legislative.js +130 -0
- package/scripts/constants/world-bank/category-map-periodic.d.ts +9 -0
- package/scripts/constants/world-bank/category-map-periodic.js +176 -0
- package/scripts/constants/world-bank/category-map.d.ts +3 -26
- package/scripts/constants/world-bank/category-map.js +8 -501
- package/scripts/discover-untranslated-briefs.js +123 -4
- package/scripts/generators/news-indexes/per-language.js +21 -7
- package/scripts/generators/political-intelligence/html.js +39 -8
- package/scripts/generators/sitemap/html.js +25 -7
- package/scripts/mcp/ep/client.d.ts +0 -1
- package/scripts/mcp/ep/client.js +0 -65
- package/scripts/mcp/ep/error-classifier.d.ts +2 -2
- package/scripts/mcp/ep/error-classifier.js +2 -2
- package/scripts/mcp/ep/tools-list.d.ts +13 -0
- package/scripts/mcp/ep/tools-list.js +79 -0
- package/scripts/mcp/ep-mcp-client.d.ts +1 -0
- package/scripts/mcp/ep-mcp-client.js +1 -0
- package/scripts/mcp/imf/client.d.ts +3 -64
- package/scripts/mcp/imf/client.js +18 -207
- package/scripts/mcp/imf/http-transport.d.ts +92 -0
- package/scripts/mcp/imf/http-transport.js +232 -0
- package/scripts/mcp/transport/connection.d.ts +25 -53
- package/scripts/mcp/transport/connection.js +90 -250
- package/scripts/mcp/transport/process.d.ts +62 -0
- package/scripts/mcp/transport/process.js +147 -0
- package/scripts/mcp/transport/reconnect.d.ts +73 -0
- package/scripts/mcp/transport/reconnect.js +96 -0
- package/scripts/validate-brief-translations.js +122 -6
- package/scripts/constants/articles/breaking-strings-eu.d.ts +0 -7
- package/scripts/constants/articles/breaking-strings-global.d.ts +0 -7
- package/scripts/constants/articles/dashboard-builder-eu.d.ts +0 -7
- package/scripts/constants/articles/dashboard-builder-global.d.ts +0 -7
- package/scripts/constants/articles/deep-analysis-strings-eu.d.ts +0 -7
- package/scripts/constants/articles/deep-analysis-strings-global.d.ts +0 -7
- package/scripts/constants/articles/localized-keywords-eu.d.ts +0 -7
- package/scripts/constants/articles/swot-builder-eu.d.ts +0 -7
|
@@ -60,6 +60,16 @@
|
|
|
60
60
|
* # flagged largeSource:true and the agent
|
|
61
61
|
* # switches to a 2-phase skeleton-then-edit
|
|
62
62
|
* # translation strategy (see news-translate.md)
|
|
63
|
+
* [--target-brief <id>] # optional operator override: when set, the
|
|
64
|
+
* # queue contains ONLY this brief regardless
|
|
65
|
+
* # of mode / max-briefs / max-age-days.
|
|
66
|
+
* # Accepted forms:
|
|
67
|
+
* # YYYY-MM-DD/<slug>
|
|
68
|
+
* # YYYY-MM-DD/<slug>/extended
|
|
69
|
+
* # analysis/daily/YYYY-MM-DD/<slug>/executive-brief.md
|
|
70
|
+
* # analysis/daily/YYYY-MM-DD/<slug>/extended/executive-brief.md
|
|
71
|
+
* # Used by operator-dispatched runs that need
|
|
72
|
+
* # to (re)translate one specific brief.
|
|
63
73
|
* [--output <path>] # default stdout
|
|
64
74
|
* [--include-extended] # also scan extended/executive-brief.md
|
|
65
75
|
*
|
|
@@ -144,6 +154,75 @@ export const DISCOVERY_MODES = Object.freeze([
|
|
|
144
154
|
'newest-first',
|
|
145
155
|
]);
|
|
146
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Parse a `--target-brief` operator override into a `{ date, slug, isExtended }`
|
|
159
|
+
* triple. Accepts four equivalent operator-friendly forms so the same input
|
|
160
|
+
* works whether the operator copies a path out of the repo, a date/slug pair
|
|
161
|
+
* out of the discovery JSON, or types the canonical short form by hand:
|
|
162
|
+
*
|
|
163
|
+
* 1. `YYYY-MM-DD/<slug>` — short form
|
|
164
|
+
* 2. `YYYY-MM-DD/<slug>/extended` — extended legacy path
|
|
165
|
+
* 3. `analysis/daily/YYYY-MM-DD/<slug>/executive-brief.md` — full repo path
|
|
166
|
+
* 4. `analysis/daily/YYYY-MM-DD/<slug>/extended/executive-brief.md`
|
|
167
|
+
*
|
|
168
|
+
* Validation is intentionally strict (whitelisted character classes, fixed date
|
|
169
|
+
* format, slug character class) — the value flows from a workflow_dispatch
|
|
170
|
+
* string input into a filesystem lookup, so a permissive parser would be a
|
|
171
|
+
* directory-traversal foothold.
|
|
172
|
+
*
|
|
173
|
+
* Throws on any malformed spec; never returns null (callers must check for
|
|
174
|
+
* empty input BEFORE calling this helper).
|
|
175
|
+
*
|
|
176
|
+
* @param {string} spec — already-trimmed, non-empty operator input
|
|
177
|
+
* @returns {{ date: string, slug: string, isExtended: boolean }}
|
|
178
|
+
*/
|
|
179
|
+
export function parseTargetBriefSpec(spec) {
|
|
180
|
+
// Strip leading "analysis/daily/" prefix and trailing "/executive-brief.md"
|
|
181
|
+
// so all four accepted forms collapse to "<date>/<slug>" or
|
|
182
|
+
// "<date>/<slug>/extended".
|
|
183
|
+
let core = spec;
|
|
184
|
+
if (core.startsWith('analysis/daily/')) {
|
|
185
|
+
core = core.slice('analysis/daily/'.length);
|
|
186
|
+
}
|
|
187
|
+
if (core.endsWith('/executive-brief.md')) {
|
|
188
|
+
core = core.slice(0, -'/executive-brief.md'.length);
|
|
189
|
+
}
|
|
190
|
+
// Reject any path-traversal or absolute-path attempts up-front.
|
|
191
|
+
if (
|
|
192
|
+
core.startsWith('/') ||
|
|
193
|
+
core.includes('..') ||
|
|
194
|
+
core.includes('\\') ||
|
|
195
|
+
core.includes('\0')
|
|
196
|
+
) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`--target-brief: refusing path-traversal or absolute path in "${spec}"`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
const parts = core.split('/');
|
|
202
|
+
let isExtended = false;
|
|
203
|
+
if (parts.length === 3 && parts[2] === 'extended') {
|
|
204
|
+
isExtended = true;
|
|
205
|
+
} else if (parts.length !== 2) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`--target-brief: expected "YYYY-MM-DD/<slug>" or "YYYY-MM-DD/<slug>/extended" (got "${spec}")`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
const [date, slug] = parts;
|
|
211
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`--target-brief: date "${date}" is not in YYYY-MM-DD format (from "${spec}")`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
// Slug character class matches the existing on-disk convention used by
|
|
217
|
+
// src/config/article-horizons.ts (lowercase, digits, dashes).
|
|
218
|
+
if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(slug)) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`--target-brief: slug "${slug}" must match [a-z0-9][a-z0-9-]{0,63} (from "${spec}")`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
return { date, slug, isExtended };
|
|
224
|
+
}
|
|
225
|
+
|
|
147
226
|
/**
|
|
148
227
|
* Parse CLI argv into an options object. Exported for unit tests.
|
|
149
228
|
* @param {string[]} argv
|
|
@@ -158,6 +237,7 @@ export function parseArgs(argv) {
|
|
|
158
237
|
mode: 'fresh-then-backlog',
|
|
159
238
|
runNumber: 0,
|
|
160
239
|
maxSourceLines: DEFAULT_MAX_SOURCE_LINES,
|
|
240
|
+
targetBrief: null,
|
|
161
241
|
};
|
|
162
242
|
for (let i = 0; i < argv.length; i += 1) {
|
|
163
243
|
const arg = argv[i];
|
|
@@ -193,6 +273,21 @@ export function parseArgs(argv) {
|
|
|
193
273
|
opts.maxSourceLines = Number.parseInt(argv[i + 1], 10);
|
|
194
274
|
i += 1;
|
|
195
275
|
break;
|
|
276
|
+
case '--target-brief': {
|
|
277
|
+
const raw = argv[i + 1];
|
|
278
|
+
i += 1;
|
|
279
|
+
// Normalize and validate. Empty / whitespace-only / the literal
|
|
280
|
+
// string "none" is treated as "no override" so the workflow can
|
|
281
|
+
// wire `TARGET_BRIEF: ${{ inputs.target_brief }}` without having
|
|
282
|
+
// to special-case the empty-default case in bash.
|
|
283
|
+
const trimmed = typeof raw === 'string' ? raw.trim() : '';
|
|
284
|
+
if (trimmed === '' || trimmed === 'none') {
|
|
285
|
+
opts.targetBrief = null;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
opts.targetBrief = parseTargetBriefSpec(trimmed);
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
196
291
|
case '--help':
|
|
197
292
|
case '-h':
|
|
198
293
|
printHelp();
|
|
@@ -232,7 +327,8 @@ function printHelp() {
|
|
|
232
327
|
process.stdout.write(
|
|
233
328
|
'Usage: discover-untranslated-briefs.js [--repo-root <path>] ' +
|
|
234
329
|
'[--max-briefs <n>] [--max-age-days <n>] [--mode <name>] ' +
|
|
235
|
-
'[--run-number <n>] [--max-source-lines <n>] [--
|
|
330
|
+
'[--run-number <n>] [--max-source-lines <n>] [--target-brief <YYYY-MM-DD/slug>] ' +
|
|
331
|
+
'[--output <path>] [--include-extended]\n',
|
|
236
332
|
);
|
|
237
333
|
}
|
|
238
334
|
|
|
@@ -402,9 +498,15 @@ export function countFixedTokens(absPath) {
|
|
|
402
498
|
* Build the prioritised queue. See module docstring for ordering rules.
|
|
403
499
|
*
|
|
404
500
|
* @param {ReturnType<typeof findExecutiveBriefSources>} sources
|
|
405
|
-
* @param {number | {
|
|
501
|
+
* @param {number | {
|
|
502
|
+
* maxBriefs: number,
|
|
503
|
+
* mode?: string,
|
|
504
|
+
* runNumber?: number,
|
|
505
|
+
* maxSourceLines?: number,
|
|
506
|
+
* targetBrief?: { date: string, slug: string, isExtended: boolean } | null,
|
|
507
|
+
* }} options
|
|
406
508
|
* Numeric form retained for backward compatibility — equivalent to
|
|
407
|
-
* `{ maxBriefs, mode: 'fresh-then-backlog', runNumber: 0, maxSourceLines: DEFAULT_MAX_SOURCE_LINES }`.
|
|
509
|
+
* `{ maxBriefs, mode: 'fresh-then-backlog', runNumber: 0, maxSourceLines: DEFAULT_MAX_SOURCE_LINES, targetBrief: null }`.
|
|
408
510
|
*/
|
|
409
511
|
export function buildQueue(sources, options) {
|
|
410
512
|
const opts =
|
|
@@ -414,6 +516,7 @@ export function buildQueue(sources, options) {
|
|
|
414
516
|
mode: 'fresh-then-backlog',
|
|
415
517
|
runNumber: 0,
|
|
416
518
|
maxSourceLines: DEFAULT_MAX_SOURCE_LINES,
|
|
519
|
+
targetBrief: null,
|
|
417
520
|
}
|
|
418
521
|
: {
|
|
419
522
|
maxBriefs: options.maxBriefs,
|
|
@@ -422,6 +525,7 @@ export function buildQueue(sources, options) {
|
|
|
422
525
|
maxSourceLines: Number.isFinite(options.maxSourceLines)
|
|
423
526
|
? options.maxSourceLines
|
|
424
527
|
: DEFAULT_MAX_SOURCE_LINES,
|
|
528
|
+
targetBrief: options.targetBrief || null,
|
|
425
529
|
};
|
|
426
530
|
if (!DISCOVERY_MODES.includes(opts.mode)) {
|
|
427
531
|
throw new Error(
|
|
@@ -493,7 +597,20 @@ export function buildQueue(sources, options) {
|
|
|
493
597
|
};
|
|
494
598
|
|
|
495
599
|
let queue;
|
|
496
|
-
if (opts.
|
|
600
|
+
if (opts.targetBrief) {
|
|
601
|
+
// Operator override: ignore mode / maxBriefs / parity and queue exactly
|
|
602
|
+
// the one brief the operator asked for, IF it has any missing languages.
|
|
603
|
+
// If the targeted brief is fully translated (no gaps), the queue is
|
|
604
|
+
// empty — the workflow's downstream validator handles the empty-queue
|
|
605
|
+
// case gracefully (skip with no work to do).
|
|
606
|
+
const tb = opts.targetBrief;
|
|
607
|
+
queue = withGaps.filter(
|
|
608
|
+
(entry) =>
|
|
609
|
+
entry.date === tb.date &&
|
|
610
|
+
entry.slug === tb.slug &&
|
|
611
|
+
entry.isExtended === tb.isExtended,
|
|
612
|
+
);
|
|
613
|
+
} else if (opts.mode === 'newest-first') {
|
|
497
614
|
queue = [...withGaps].sort(newestFirst).slice(0, opts.maxBriefs);
|
|
498
615
|
} else if (opts.mode === 'backlog-only') {
|
|
499
616
|
queue = [...withGaps].sort(oldestFirstFinishPartial).slice(0, opts.maxBriefs);
|
|
@@ -577,6 +694,7 @@ export function main(argv) {
|
|
|
577
694
|
mode: opts.mode,
|
|
578
695
|
runNumber: opts.runNumber,
|
|
579
696
|
maxSourceLines: opts.maxSourceLines,
|
|
697
|
+
targetBrief: opts.targetBrief,
|
|
580
698
|
});
|
|
581
699
|
const payload = {
|
|
582
700
|
generatedAt: new Date().toISOString(),
|
|
@@ -587,6 +705,7 @@ export function main(argv) {
|
|
|
587
705
|
mode: opts.mode,
|
|
588
706
|
runNumber: opts.runNumber,
|
|
589
707
|
maxSourceLines: opts.maxSourceLines,
|
|
708
|
+
targetBrief: opts.targetBrief,
|
|
590
709
|
},
|
|
591
710
|
totals,
|
|
592
711
|
queue,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* the monolithic `news-indexes.ts` so the HTML/SEO surface can be
|
|
9
9
|
* regression-tested independently of discovery and write logic.
|
|
10
10
|
*/
|
|
11
|
-
import { APP_VERSION, BUILD_SHORT, BASE_URL } from '../../constants/config.js';
|
|
11
|
+
import { APP_VERSION, BUILD_SHORT, BUILD_TIME, BASE_URL } from '../../constants/config.js';
|
|
12
12
|
import { getNewsIndexSeo } from '../seo-copy.js';
|
|
13
13
|
import { buildHeadFreshnessTags } from '../../constants/build-info-meta.js';
|
|
14
14
|
import { ALL_LANGUAGES, LANGUAGE_NAMES, LANGUAGE_FLAGS, PAGE_TITLES, PAGE_DESCRIPTIONS, SECTION_HEADINGS, NO_ARTICLES_MESSAGES, SKIP_LINK_TEXTS, AI_SECTION_CONTENT, FILTER_LABELS, ARTICLE_TYPE_LABELS, HEADER_SUBTITLE_LABELS, getLocalizedString, getTextDirection, } from '../../constants/languages.js';
|
|
@@ -186,6 +186,8 @@ export function generateIndexHTML(lang, articles, metaMap = new Map()) {
|
|
|
186
186
|
inLanguage: lang,
|
|
187
187
|
isPartOf: { '@type': 'WebSite', name: SITE_NAME, url: BASE_URL },
|
|
188
188
|
publisher: { '@id': `${BASE_URL}/#organization` },
|
|
189
|
+
datePublished: BUILD_TIME,
|
|
190
|
+
dateModified: BUILD_TIME,
|
|
189
191
|
breadcrumb: {
|
|
190
192
|
'@type': 'BreadcrumbList',
|
|
191
193
|
itemListElement: [
|
|
@@ -201,12 +203,24 @@ export function generateIndexHTML(lang, articles, metaMap = new Map()) {
|
|
|
201
203
|
mainEntity: {
|
|
202
204
|
'@type': 'ItemList',
|
|
203
205
|
numberOfItems: Math.min(articles.length, 50),
|
|
204
|
-
itemListElement: articles.slice(0, 50).map((a, idx) =>
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
206
|
+
itemListElement: articles.slice(0, 50).map((a, idx) => {
|
|
207
|
+
const url = `${BASE_URL}/news/${a.filename}`;
|
|
208
|
+
const headline = metaMap.get(a.filename)?.title ?? formatSlug(a.slug);
|
|
209
|
+
return {
|
|
210
|
+
'@type': 'ListItem',
|
|
211
|
+
position: idx + 1,
|
|
212
|
+
url,
|
|
213
|
+
item: {
|
|
214
|
+
'@type': 'NewsArticle',
|
|
215
|
+
'@id': url,
|
|
216
|
+
url,
|
|
217
|
+
headline,
|
|
218
|
+
name: headline,
|
|
219
|
+
datePublished: a.date,
|
|
220
|
+
inLanguage: a.lang,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}),
|
|
210
224
|
},
|
|
211
225
|
}).replace(/</g, '\\u003c');
|
|
212
226
|
const faqJsonLd = JSON.stringify({
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* link points at GitHub blob/tree URLs so readers can audit the raw
|
|
13
13
|
* tradecraft behind every published article.
|
|
14
14
|
*/
|
|
15
|
-
import { BASE_URL, BUILD_SHORT, THEME_TOGGLE_SCRIPT } from '../../constants/config.js';
|
|
15
|
+
import { BASE_URL, BUILD_SHORT, BUILD_TIME, THEME_TOGGLE_SCRIPT } from '../../constants/config.js';
|
|
16
16
|
import { buildHeadFreshnessTags } from '../../constants/build-info-meta.js';
|
|
17
17
|
import { ALL_LANGUAGES, LANGUAGE_FLAGS, LANGUAGE_NAMES, PAGE_TITLES, SKIP_LINK_TEXTS, getLocalizedString, getTextDirection, } from '../../constants/languages.js';
|
|
18
18
|
import { buildOgLocaleTags, ORG_SAME_AS, buildTwitterAttributionTags, } from '../../constants/seo/index.js';
|
|
@@ -263,6 +263,7 @@ export function generatePoliticalIntelligenceHTML(lang, data) {
|
|
|
263
263
|
height: 192,
|
|
264
264
|
},
|
|
265
265
|
};
|
|
266
|
+
const publisherRef = { '@id': `${BASE_URL}/#organization` };
|
|
266
267
|
const jsonLd = {
|
|
267
268
|
'@context': SCHEMA_ORG,
|
|
268
269
|
'@type': 'CollectionPage',
|
|
@@ -270,13 +271,15 @@ export function generatePoliticalIntelligenceHTML(lang, data) {
|
|
|
270
271
|
url: canonicalUrl,
|
|
271
272
|
description: copy.intro,
|
|
272
273
|
inLanguage: safeLang,
|
|
273
|
-
author:
|
|
274
|
-
publisher,
|
|
274
|
+
author: publisherRef,
|
|
275
|
+
publisher: publisherRef,
|
|
276
|
+
datePublished: BUILD_TIME,
|
|
277
|
+
dateModified: BUILD_TIME,
|
|
275
278
|
isPartOf: {
|
|
276
279
|
'@type': 'WebSite',
|
|
277
280
|
name: SITE_NAME,
|
|
278
281
|
url: BASE_URL,
|
|
279
|
-
publisher,
|
|
282
|
+
publisher: publisherRef,
|
|
280
283
|
},
|
|
281
284
|
breadcrumb: {
|
|
282
285
|
'@type': 'BreadcrumbList',
|
|
@@ -299,25 +302,53 @@ export function generatePoliticalIntelligenceHTML(lang, data) {
|
|
|
299
302
|
'@type': 'ListItem',
|
|
300
303
|
position: 1,
|
|
301
304
|
name: copy.methodologiesHeading,
|
|
302
|
-
|
|
305
|
+
url: `${canonicalUrl}#pi-methodologies`,
|
|
306
|
+
item: {
|
|
307
|
+
'@type': 'WebPageElement',
|
|
308
|
+
'@id': `${canonicalUrl}#pi-methodologies`,
|
|
309
|
+
url: `${canonicalUrl}#pi-methodologies`,
|
|
310
|
+
name: copy.methodologiesHeading,
|
|
311
|
+
inLanguage: safeLang,
|
|
312
|
+
},
|
|
303
313
|
},
|
|
304
314
|
{
|
|
305
315
|
'@type': 'ListItem',
|
|
306
316
|
position: 2,
|
|
307
317
|
name: copy.templatesHeading,
|
|
308
|
-
|
|
318
|
+
url: `${canonicalUrl}#pi-templates`,
|
|
319
|
+
item: {
|
|
320
|
+
'@type': 'WebPageElement',
|
|
321
|
+
'@id': `${canonicalUrl}#pi-templates`,
|
|
322
|
+
url: `${canonicalUrl}#pi-templates`,
|
|
323
|
+
name: copy.templatesHeading,
|
|
324
|
+
inLanguage: safeLang,
|
|
325
|
+
},
|
|
309
326
|
},
|
|
310
327
|
{
|
|
311
328
|
'@type': 'ListItem',
|
|
312
329
|
position: 3,
|
|
313
330
|
name: copy.referenceHeading,
|
|
314
|
-
|
|
331
|
+
url: `${canonicalUrl}#pi-reference`,
|
|
332
|
+
item: {
|
|
333
|
+
'@type': 'WebPageElement',
|
|
334
|
+
'@id': `${canonicalUrl}#pi-reference`,
|
|
335
|
+
url: `${canonicalUrl}#pi-reference`,
|
|
336
|
+
name: copy.referenceHeading,
|
|
337
|
+
inLanguage: safeLang,
|
|
338
|
+
},
|
|
315
339
|
},
|
|
316
340
|
{
|
|
317
341
|
'@type': 'ListItem',
|
|
318
342
|
position: 4,
|
|
319
343
|
name: copy.dailyHeading,
|
|
320
|
-
|
|
344
|
+
url: `${canonicalUrl}#pi-daily`,
|
|
345
|
+
item: {
|
|
346
|
+
'@type': 'WebPageElement',
|
|
347
|
+
'@id': `${canonicalUrl}#pi-daily`,
|
|
348
|
+
url: `${canonicalUrl}#pi-daily`,
|
|
349
|
+
name: copy.dailyHeading,
|
|
350
|
+
inLanguage: safeLang,
|
|
351
|
+
},
|
|
321
352
|
},
|
|
322
353
|
],
|
|
323
354
|
},
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* `test/unit/sitemap-byte-equality.test.js` (compares against the
|
|
20
20
|
* golden snapshots taken from `npm run prebuild`).
|
|
21
21
|
*/
|
|
22
|
-
import { BASE_URL, BUILD_SHORT, THEME_TOGGLE_SCRIPT } from '../../constants/config.js';
|
|
22
|
+
import { BASE_URL, BUILD_SHORT, BUILD_TIME, THEME_TOGGLE_SCRIPT } from '../../constants/config.js';
|
|
23
23
|
import { buildHeadFreshnessTags } from '../../constants/build-info-meta.js';
|
|
24
24
|
import { getSitemapSeo } from '../seo-copy.js';
|
|
25
25
|
import { ALL_LANGUAGES, LANGUAGE_NAMES, LANGUAGE_FLAGS, PAGE_TITLES, PAGE_DESCRIPTIONS, SKIP_LINK_TEXTS, getLocalizedString, getTextDirection, } from '../../constants/languages.js';
|
|
@@ -192,6 +192,8 @@ ${items}
|
|
|
192
192
|
url: BASE_URL,
|
|
193
193
|
},
|
|
194
194
|
publisher: { '@id': `${BASE_URL}/#organization` },
|
|
195
|
+
datePublished: BUILD_TIME,
|
|
196
|
+
dateModified: BUILD_TIME,
|
|
195
197
|
breadcrumb: {
|
|
196
198
|
'@type': 'BreadcrumbList',
|
|
197
199
|
itemListElement: [
|
|
@@ -213,12 +215,28 @@ ${items}
|
|
|
213
215
|
'@type': 'ItemList',
|
|
214
216
|
numberOfItems: Math.min(articleInfos.length, 50),
|
|
215
217
|
name: sections.news,
|
|
216
|
-
itemListElement: articleInfos.slice(0, 50).map((info, idx) =>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
218
|
+
itemListElement: articleInfos.slice(0, 50).map((info, idx) => {
|
|
219
|
+
const url = `${BASE_URL}/news/${info.filename}`;
|
|
220
|
+
// Extract per-article language from filename suffix (e.g. `…-foo-en.html` → `en`).
|
|
221
|
+
// Mirrors the canonical `<slug>-<lang>.html` convention enforced by
|
|
222
|
+
// `ARTICLE_FILENAME_PATTERN` / `getArticleFilename()`.
|
|
223
|
+
const langMatch = /-([a-z]{2})\.html$/.exec(info.filename);
|
|
224
|
+
const articleLang = langMatch ? langMatch[1] : lang;
|
|
225
|
+
return {
|
|
226
|
+
'@type': 'ListItem',
|
|
227
|
+
position: idx + 1,
|
|
228
|
+
url,
|
|
229
|
+
item: {
|
|
230
|
+
'@type': 'NewsArticle',
|
|
231
|
+
'@id': url,
|
|
232
|
+
url,
|
|
233
|
+
headline: info.title,
|
|
234
|
+
name: info.title,
|
|
235
|
+
datePublished: info.date,
|
|
236
|
+
inLanguage: articleLang,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}),
|
|
222
240
|
},
|
|
223
241
|
};
|
|
224
242
|
const jsonLdString = JSON.stringify(jsonLd).replace(/</g, '\\u003c');
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { MCPConnection } from '../mcp-connection.js';
|
|
11
11
|
import type { MCPClientOptions, MCPToolResult } from '../../types/index.js';
|
|
12
|
-
export declare const EP_MCP_TOOLS: readonly string[];
|
|
13
12
|
export declare class EuropeanParliamentMCPClient extends MCPConnection {
|
|
14
13
|
/** Tracks tools that returned fallback data in the current session */
|
|
15
14
|
protected readonly _failedTools: Map<string, string>;
|
package/scripts/mcp/ep/client.js
CHANGED
|
@@ -13,71 +13,6 @@ import { MCPConnection } from '../mcp-connection.js';
|
|
|
13
13
|
import { classifyToolError, isFeedUnavailable } from './error-classifier.js';
|
|
14
14
|
import { FEED_UNAVAILABLE_REASON } from './fallbacks.js';
|
|
15
15
|
import { TOOL_RELIABILITY_TIMEOUT_MS, TOOL_RELIABILITY_TIMEOUT_RETRIES } from './reliability.js';
|
|
16
|
-
export const EP_MCP_TOOLS = [
|
|
17
|
-
'analyze_coalition_dynamics',
|
|
18
|
-
'analyze_committee_activity',
|
|
19
|
-
'analyze_country_delegation',
|
|
20
|
-
'analyze_legislative_effectiveness',
|
|
21
|
-
'analyze_voting_patterns',
|
|
22
|
-
'assess_mep_influence',
|
|
23
|
-
'comparative_intelligence',
|
|
24
|
-
'compare_political_groups',
|
|
25
|
-
'correlate_intelligence',
|
|
26
|
-
'detect_voting_anomalies',
|
|
27
|
-
'early_warning_system',
|
|
28
|
-
'generate_political_landscape',
|
|
29
|
-
'generate_report',
|
|
30
|
-
'get_adopted_texts',
|
|
31
|
-
'get_adopted_texts_feed',
|
|
32
|
-
'get_all_generated_stats',
|
|
33
|
-
'get_committee_documents',
|
|
34
|
-
'get_committee_documents_feed',
|
|
35
|
-
'get_committee_info',
|
|
36
|
-
'get_controlled_vocabularies',
|
|
37
|
-
'get_controlled_vocabularies_feed',
|
|
38
|
-
'get_corporate_bodies_feed',
|
|
39
|
-
'get_current_meps',
|
|
40
|
-
'get_documents_feed',
|
|
41
|
-
'get_events',
|
|
42
|
-
'get_events_feed',
|
|
43
|
-
'get_external_documents',
|
|
44
|
-
'get_external_documents_feed',
|
|
45
|
-
'get_homonym_meps',
|
|
46
|
-
'get_incoming_meps',
|
|
47
|
-
'get_latest_votes',
|
|
48
|
-
'get_meeting_activities',
|
|
49
|
-
'get_meeting_decisions',
|
|
50
|
-
'get_meeting_foreseen_activities',
|
|
51
|
-
'get_meeting_plenary_session_document_items',
|
|
52
|
-
'get_meeting_plenary_session_documents',
|
|
53
|
-
'get_mep_declarations',
|
|
54
|
-
'get_mep_declarations_feed',
|
|
55
|
-
'get_mep_details',
|
|
56
|
-
'get_meps',
|
|
57
|
-
'get_meps_feed',
|
|
58
|
-
'get_outgoing_meps',
|
|
59
|
-
'get_parliamentary_questions',
|
|
60
|
-
'get_parliamentary_questions_feed',
|
|
61
|
-
'get_plenary_documents',
|
|
62
|
-
'get_plenary_documents_feed',
|
|
63
|
-
'get_plenary_session_document_items',
|
|
64
|
-
'get_plenary_session_documents',
|
|
65
|
-
'get_plenary_session_documents_feed',
|
|
66
|
-
'get_plenary_sessions',
|
|
67
|
-
'get_procedure_event_by_id',
|
|
68
|
-
'get_procedure_events',
|
|
69
|
-
'get_procedures',
|
|
70
|
-
'get_procedures_feed',
|
|
71
|
-
'get_server_health',
|
|
72
|
-
'get_speeches',
|
|
73
|
-
'get_voting_records',
|
|
74
|
-
'monitor_legislative_pipeline',
|
|
75
|
-
'network_analysis',
|
|
76
|
-
'search_documents',
|
|
77
|
-
'sentiment_tracker',
|
|
78
|
-
'track_legislation',
|
|
79
|
-
'track_mep_attendance',
|
|
80
|
-
];
|
|
81
16
|
export class EuropeanParliamentMCPClient extends MCPConnection {
|
|
82
17
|
/** Tracks tools that returned fallback data in the current session */
|
|
83
18
|
_failedTools = new Map();
|
|
@@ -6,7 +6,7 @@ import type { MCPToolResult } from '../../types/index.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* Classify an error message into a diagnostic error category.
|
|
8
8
|
*
|
|
9
|
-
* Maps EP MCP Server v1.3.
|
|
9
|
+
* Maps EP MCP Server v1.3.10 structured error codes and generic HTTP/network
|
|
10
10
|
* errors into one of six broad categories used for logging and retry decisions:
|
|
11
11
|
*
|
|
12
12
|
* Returned categories (priority order):
|
|
@@ -26,7 +26,7 @@ export declare function classifyToolError(message: string): string;
|
|
|
26
26
|
* covering the two shapes historically emitted by the EP MCP server.
|
|
27
27
|
*
|
|
28
28
|
* 1. **Uniform envelope** (all feeds as of
|
|
29
|
-
* `european-parliament-mcp-server@1.3.
|
|
29
|
+
* `european-parliament-mcp-server@1.3.10`) —
|
|
30
30
|
* `{status:"unavailable", items:[], generatedAt:"..."}` established by
|
|
31
31
|
* Hack23/European-Parliament-MCP-Server#301 and extended to
|
|
32
32
|
* `get_events_feed`/`get_procedures_feed` by
|
|
@@ -4,7 +4,7 @@ import { _parseResultPayload } from './parse.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Classify an error message into a diagnostic error category.
|
|
6
6
|
*
|
|
7
|
-
* Maps EP MCP Server v1.3.
|
|
7
|
+
* Maps EP MCP Server v1.3.10 structured error codes and generic HTTP/network
|
|
8
8
|
* errors into one of six broad categories used for logging and retry decisions:
|
|
9
9
|
*
|
|
10
10
|
* Returned categories (priority order):
|
|
@@ -55,7 +55,7 @@ export function classifyToolError(message) {
|
|
|
55
55
|
* covering the two shapes historically emitted by the EP MCP server.
|
|
56
56
|
*
|
|
57
57
|
* 1. **Uniform envelope** (all feeds as of
|
|
58
|
-
* `european-parliament-mcp-server@1.3.
|
|
58
|
+
* `european-parliament-mcp-server@1.3.10`) —
|
|
59
59
|
* `{status:"unavailable", items:[], generatedAt:"..."}` established by
|
|
60
60
|
* Hack23/European-Parliament-MCP-Server#301 and extended to
|
|
61
61
|
* `get_events_feed`/`get_procedures_feed` by
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module MCP/ep/tools-list
|
|
3
|
+
* @description Canonical list of European Parliament MCP tool identifiers.
|
|
4
|
+
* Used for drift-guard validation, probe tooling, and barrel re-exports.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from `client.ts` to keep individual file sizes under 400 LOC.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Canonical list of every tool exposed by the European Parliament MCP server.
|
|
10
|
+
* Drift-guarded by `test/integration/mcp/ep-mcp.test.js`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const EP_MCP_TOOLS: readonly string[];
|
|
13
|
+
//# sourceMappingURL=tools-list.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* @module MCP/ep/tools-list
|
|
5
|
+
* @description Canonical list of European Parliament MCP tool identifiers.
|
|
6
|
+
* Used for drift-guard validation, probe tooling, and barrel re-exports.
|
|
7
|
+
*
|
|
8
|
+
* Extracted from `client.ts` to keep individual file sizes under 400 LOC.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Canonical list of every tool exposed by the European Parliament MCP server.
|
|
12
|
+
* Drift-guarded by `test/integration/mcp/ep-mcp.test.js`.
|
|
13
|
+
*/
|
|
14
|
+
export const EP_MCP_TOOLS = [
|
|
15
|
+
'analyze_coalition_dynamics',
|
|
16
|
+
'analyze_committee_activity',
|
|
17
|
+
'analyze_country_delegation',
|
|
18
|
+
'analyze_legislative_effectiveness',
|
|
19
|
+
'analyze_voting_patterns',
|
|
20
|
+
'assess_mep_influence',
|
|
21
|
+
'comparative_intelligence',
|
|
22
|
+
'compare_political_groups',
|
|
23
|
+
'correlate_intelligence',
|
|
24
|
+
'detect_voting_anomalies',
|
|
25
|
+
'early_warning_system',
|
|
26
|
+
'generate_political_landscape',
|
|
27
|
+
'generate_report',
|
|
28
|
+
'get_adopted_texts',
|
|
29
|
+
'get_adopted_texts_feed',
|
|
30
|
+
'get_all_generated_stats',
|
|
31
|
+
'get_committee_documents',
|
|
32
|
+
'get_committee_documents_feed',
|
|
33
|
+
'get_committee_info',
|
|
34
|
+
'get_controlled_vocabularies',
|
|
35
|
+
'get_controlled_vocabularies_feed',
|
|
36
|
+
'get_corporate_bodies_feed',
|
|
37
|
+
'get_current_meps',
|
|
38
|
+
'get_documents_feed',
|
|
39
|
+
'get_events',
|
|
40
|
+
'get_events_feed',
|
|
41
|
+
'get_external_documents',
|
|
42
|
+
'get_external_documents_feed',
|
|
43
|
+
'get_homonym_meps',
|
|
44
|
+
'get_incoming_meps',
|
|
45
|
+
'get_latest_votes',
|
|
46
|
+
'get_meeting_activities',
|
|
47
|
+
'get_meeting_decisions',
|
|
48
|
+
'get_meeting_foreseen_activities',
|
|
49
|
+
'get_meeting_plenary_session_document_items',
|
|
50
|
+
'get_meeting_plenary_session_documents',
|
|
51
|
+
'get_mep_declarations',
|
|
52
|
+
'get_mep_declarations_feed',
|
|
53
|
+
'get_mep_details',
|
|
54
|
+
'get_meps',
|
|
55
|
+
'get_meps_feed',
|
|
56
|
+
'get_outgoing_meps',
|
|
57
|
+
'get_parliamentary_questions',
|
|
58
|
+
'get_parliamentary_questions_feed',
|
|
59
|
+
'get_plenary_documents',
|
|
60
|
+
'get_plenary_documents_feed',
|
|
61
|
+
'get_plenary_session_document_items',
|
|
62
|
+
'get_plenary_session_documents',
|
|
63
|
+
'get_plenary_session_documents_feed',
|
|
64
|
+
'get_plenary_sessions',
|
|
65
|
+
'get_procedure_event_by_id',
|
|
66
|
+
'get_procedure_events',
|
|
67
|
+
'get_procedures',
|
|
68
|
+
'get_procedures_feed',
|
|
69
|
+
'get_server_health',
|
|
70
|
+
'get_speeches',
|
|
71
|
+
'get_voting_records',
|
|
72
|
+
'monitor_legislative_pipeline',
|
|
73
|
+
'network_analysis',
|
|
74
|
+
'search_documents',
|
|
75
|
+
'sentiment_tracker',
|
|
76
|
+
'track_legislation',
|
|
77
|
+
'track_mep_attendance',
|
|
78
|
+
];
|
|
79
|
+
//# sourceMappingURL=tools-list.js.map
|
|
@@ -15,6 +15,7 @@ export * from './ep/error-classifier.js';
|
|
|
15
15
|
export * from './ep/staleness.js';
|
|
16
16
|
export * from './ep/reliability.js';
|
|
17
17
|
export * from './ep/election-calendar.js';
|
|
18
|
+
export * from './ep/tools-list.js';
|
|
18
19
|
export * from './ep/client.js';
|
|
19
20
|
import './ep/tools-data.js';
|
|
20
21
|
import './ep/tools-procedures.js';
|
|
@@ -17,6 +17,7 @@ export * from './ep/error-classifier.js';
|
|
|
17
17
|
export * from './ep/staleness.js';
|
|
18
18
|
export * from './ep/reliability.js';
|
|
19
19
|
export * from './ep/election-calendar.js';
|
|
20
|
+
export * from './ep/tools-list.js';
|
|
20
21
|
export * from './ep/client.js';
|
|
21
22
|
// Side-effect mixin imports (augment EuropeanParliamentMCPClient prototype)
|
|
22
23
|
import './ep/tools-data.js';
|