euparliamentmonitor 0.9.2 → 0.9.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.
- package/package.json +3 -3
- package/scripts/aggregator/analysis-aggregator.d.ts +11 -0
- package/scripts/aggregator/analysis-aggregator.js +25 -6
- package/scripts/aggregator/article-generator.js +7 -1
- package/scripts/aggregator/article-html.d.ts +44 -2
- package/scripts/aggregator/article-html.js +631 -6
- package/scripts/aggregator/reader-intelligence-guide.d.ts +23 -2
- package/scripts/aggregator/reader-intelligence-guide.js +344 -9
- package/scripts/mcp/fetch-proxy-server.d.ts +1 -13
- package/scripts/mcp/fetch-proxy-server.js +148 -32
- package/scripts/mcp/imf-mcp-client.d.ts +68 -19
- package/scripts/mcp/imf-mcp-client.js +471 -100
- package/scripts/types/imf.d.ts +3 -3
|
@@ -22,17 +22,38 @@ export declare const READER_GUIDE_COL_NEED_LABELS: LanguageMap;
|
|
|
22
22
|
export declare const READER_GUIDE_COL_VALUE_LABELS: LanguageMap;
|
|
23
23
|
/** Table header: "Source artifact" */
|
|
24
24
|
export declare const READER_GUIDE_COL_SOURCE_LABELS: LanguageMap;
|
|
25
|
+
/**
|
|
26
|
+
* Look up the visual icon for a known article section.
|
|
27
|
+
*
|
|
28
|
+
* Exposed so the article-level Table-of-Contents (`buildArticleToc`)
|
|
29
|
+
* can render the same emoji that the Reader Intelligence Guide uses
|
|
30
|
+
* for each section, keeping the two navigation surfaces visually
|
|
31
|
+
* consistent. Unknown section IDs (e.g. ad-hoc `supplementary-…` or
|
|
32
|
+
* appendix anchors) fall back to a generic 📎 paperclip.
|
|
33
|
+
*
|
|
34
|
+
* @param sectionId - Anchor id of the section (e.g. `section-risk`)
|
|
35
|
+
* @returns Single emoji glyph used as a `guide-icon`
|
|
36
|
+
*/
|
|
37
|
+
export declare function getReaderGuideSectionIcon(sectionId: string): string;
|
|
25
38
|
/**
|
|
26
39
|
* Build a translated Reader Intelligence Guide as an HTML section.
|
|
27
40
|
* Emits exactly one component with `data-component="reader-intelligence-guide"`
|
|
28
41
|
* for de-duplication detection by E2E tests.
|
|
29
42
|
*
|
|
43
|
+
* The guide renders one row per emitted article section that has a
|
|
44
|
+
* curated reader-need translation (see {@link READER_GUIDE_ROWS}). The
|
|
45
|
+
* `included` list is no longer surfaced — the previous "source artifact"
|
|
46
|
+
* column duplicated the per-section navigation that the Analysis Index
|
|
47
|
+
* appendix already presents, and clutters the headline reader lens. The
|
|
48
|
+
* parameter is kept on the signature for backward compatibility with
|
|
49
|
+
* callers that may pre-compute the run manifest.
|
|
50
|
+
*
|
|
30
51
|
* @param lang - Target language code
|
|
31
52
|
* @param sections - Emitted section TOC entries, in document order
|
|
32
|
-
* @param
|
|
53
|
+
* @param _included - (Unused) Included artifacts; kept for API stability
|
|
33
54
|
* @returns HTML fragment for the guide, or empty string if no rows match
|
|
34
55
|
*/
|
|
35
|
-
export declare function buildReaderIntelligenceGuideHtml(lang: LanguageCode, sections: readonly TocSection[],
|
|
56
|
+
export declare function buildReaderIntelligenceGuideHtml(lang: LanguageCode, sections: readonly TocSection[], _included?: readonly IncludedArtifact[]): string;
|
|
36
57
|
/**
|
|
37
58
|
* Strip an AI-authored Reader Intelligence Guide section from rendered HTML.
|
|
38
59
|
* Looks for H2 headings with id="reader-intelligence-guide" and removes
|
|
@@ -363,6 +363,312 @@ const READER_GUIDE_ROWS = {
|
|
|
363
363
|
zh: '政策、机构、联盟、沟通和执行风险登记册',
|
|
364
364
|
},
|
|
365
365
|
},
|
|
366
|
+
'section-actors-forces': {
|
|
367
|
+
need: {
|
|
368
|
+
en: 'Actors & forces',
|
|
369
|
+
sv: 'Aktörer & krafter',
|
|
370
|
+
da: 'Aktører & kræfter',
|
|
371
|
+
no: 'Aktører & krefter',
|
|
372
|
+
fi: 'Toimijat & voimat',
|
|
373
|
+
de: 'Akteure & Kräfte',
|
|
374
|
+
fr: 'Acteurs & forces',
|
|
375
|
+
es: 'Actores & fuerzas',
|
|
376
|
+
nl: 'Actoren & krachten',
|
|
377
|
+
ar: 'الفاعلون والقوى',
|
|
378
|
+
he: 'שחקנים וכוחות',
|
|
379
|
+
ja: 'アクターと力学',
|
|
380
|
+
ko: '행위자 & 세력',
|
|
381
|
+
zh: '行动者与力量',
|
|
382
|
+
},
|
|
383
|
+
value: {
|
|
384
|
+
en: 'who is driving the story, what political forces line up behind them, and which institutional levers they can pull',
|
|
385
|
+
sv: 'vem som driver händelsen, vilka politiska krafter står bakom och vilka institutionella spakar de kan dra',
|
|
386
|
+
da: 'hvem der driver historien, hvilke politiske kræfter står bag, og hvilke institutionelle håndtag de kan trække',
|
|
387
|
+
no: 'hvem som driver saken, hvilke politiske krefter står bak, og hvilke institusjonelle spaker de kan trekke',
|
|
388
|
+
fi: 'kuka ohjaa tarinaa, mitkä poliittiset voimat ovat takana ja mitä institutionaalisia vipuja he voivat käyttää',
|
|
389
|
+
de: 'wer die Geschichte vorantreibt, welche politischen Kräfte dahinterstehen und welche institutionellen Hebel sie ziehen können',
|
|
390
|
+
fr: "qui pilote l'histoire, quelles forces politiques sont alignées derrière, et quels leviers institutionnels ils peuvent actionner",
|
|
391
|
+
es: 'quién impulsa la historia, qué fuerzas políticas están detrás y qué palancas institucionales pueden accionar',
|
|
392
|
+
nl: 'wie het verhaal aandrijft, welke politieke krachten erachter staan en welke institutionele hefbomen ze kunnen overhalen',
|
|
393
|
+
ar: 'من يقود القصة، وما القوى السياسية المصطفة خلفه، وأي روافع مؤسسية يمكنهم تحريكها',
|
|
394
|
+
he: 'מי מניע את הסיפור, אילו כוחות פוליטיים מאחוריו, ואילו מנופים מוסדיים הם יכולים להפעיל',
|
|
395
|
+
ja: 'ストーリーを動かしているのは誰か、その背後にある政治的勢力、そして彼らが引ける制度的レバー',
|
|
396
|
+
ko: '누가 이야기를 주도하는지, 그 뒤에 어떤 정치적 세력이 있는지, 그리고 어떤 제도적 지렛대를 당길 수 있는지',
|
|
397
|
+
zh: '谁在推动故事、哪些政治力量在其背后、以及他们可以拉动哪些制度杠杆',
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
'section-threat': {
|
|
401
|
+
need: {
|
|
402
|
+
en: 'Threat landscape',
|
|
403
|
+
sv: 'Hotlandskap',
|
|
404
|
+
da: 'Trussellandskab',
|
|
405
|
+
no: 'Trussellandskap',
|
|
406
|
+
fi: 'Uhkamaisema',
|
|
407
|
+
de: 'Bedrohungslandschaft',
|
|
408
|
+
fr: 'Paysage des menaces',
|
|
409
|
+
es: 'Panorama de amenazas',
|
|
410
|
+
nl: 'Dreigingslandschap',
|
|
411
|
+
ar: 'مشهد التهديدات',
|
|
412
|
+
he: 'נוף האיומים',
|
|
413
|
+
ja: '脅威ランドスケープ',
|
|
414
|
+
ko: '위협 환경',
|
|
415
|
+
zh: '威胁态势',
|
|
416
|
+
},
|
|
417
|
+
value: {
|
|
418
|
+
en: 'hostile actors, attack vectors, consequence trees, and the legislative-disruption pathways the article tracks',
|
|
419
|
+
sv: 'fientliga aktörer, attackvektorer, konsekvensträd och de lagstiftningsstörningsvägar artikeln spårar',
|
|
420
|
+
da: 'fjendtlige aktører, angrebsvektorer, konsekvenstræer og de lovgivningsforstyrrelsesveje artiklen følger',
|
|
421
|
+
no: 'fiendtlige aktører, angrepsvektorer, konsekvenstrær og lovgivningsforstyrrelsesveiene artikkelen sporer',
|
|
422
|
+
fi: 'vihamieliset toimijat, hyökkäysvektorit, seurauspuut ja lainsäädännön häiriöpolut, joita artikkeli seuraa',
|
|
423
|
+
de: 'feindliche Akteure, Angriffsvektoren, Konsequenzbäume und die Gesetzgebungsstörungspfade, die der Artikel verfolgt',
|
|
424
|
+
fr: "acteurs hostiles, vecteurs d'attaque, arbres de conséquences et voies de perturbation législative que l'article suit",
|
|
425
|
+
es: 'actores hostiles, vectores de ataque, árboles de consecuencias y las vías de disrupción legislativa que sigue el artículo',
|
|
426
|
+
nl: 'vijandige actoren, aanvalsvectoren, gevolgenbomen en de wetgevingsverstoringspaden die het artikel volgt',
|
|
427
|
+
ar: 'الجهات المعادية وناقلات الهجوم وأشجار العواقب ومسارات التعطيل التشريعي التي يتتبعها المقال',
|
|
428
|
+
he: 'שחקנים עוינים, ווקטורי תקיפה, עצי השלכה ונתיבי שיבוש החקיקה שהמאמר עוקב אחריהם',
|
|
429
|
+
ja: '敵対的アクター、攻撃ベクトル、結果ツリー、および記事が追跡する立法阻害経路',
|
|
430
|
+
ko: '적대적 행위자, 공격 벡터, 결과 트리, 그리고 기사가 추적하는 입법 교란 경로',
|
|
431
|
+
zh: '敌对行为者、攻击向量、后果树以及文章追踪的立法干扰路径',
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
'section-forward-projection': {
|
|
435
|
+
need: {
|
|
436
|
+
en: 'What to watch',
|
|
437
|
+
sv: 'Vad att bevaka',
|
|
438
|
+
da: 'Hvad man skal følge',
|
|
439
|
+
no: 'Hva å følge med på',
|
|
440
|
+
fi: 'Mitä seurata',
|
|
441
|
+
de: 'Was zu beobachten ist',
|
|
442
|
+
fr: 'À surveiller',
|
|
443
|
+
es: 'Qué vigilar',
|
|
444
|
+
nl: 'Wat te volgen',
|
|
445
|
+
ar: 'ما يجب مراقبته',
|
|
446
|
+
he: 'מה לעקוב אחריו',
|
|
447
|
+
ja: '注目ポイント',
|
|
448
|
+
ko: '주목할 사항',
|
|
449
|
+
zh: '关注要点',
|
|
450
|
+
},
|
|
451
|
+
value: {
|
|
452
|
+
en: 'dated trigger events, parliamentary-calendar dependencies, and the legislative-pipeline forecast',
|
|
453
|
+
sv: 'daterade triggers, beroenden i parlamentskalendern och prognosen för lagstiftningspipelinen',
|
|
454
|
+
da: 'daterede triggers, parlamentskalender-afhængigheder og prognosen for lovgivningspipelinen',
|
|
455
|
+
no: 'daterte triggers, parlamentskalender-avhengigheter og prognosen for lovgivningspipelinen',
|
|
456
|
+
fi: 'päivätyt laukaisimet, parlamentin kalenterin riippuvuudet ja lainsäädäntöputken ennuste',
|
|
457
|
+
de: 'datierte Auslöseereignisse, Abhängigkeiten vom Parlamentskalender und die Prognose der Gesetzgebungspipeline',
|
|
458
|
+
fr: 'événements déclencheurs datés, dépendances du calendrier parlementaire et prévision du pipeline législatif',
|
|
459
|
+
es: 'eventos desencadenantes fechados, dependencias del calendario parlamentario y previsión del pipeline legislativo',
|
|
460
|
+
nl: 'gedateerde triggergebeurtenissen, afhankelijkheden van de parlementaire agenda en de voorspelling van de wetgevingspijplijn',
|
|
461
|
+
ar: 'أحداث محفزة مؤرخة، تبعيات الجدول البرلماني، وتوقعات خط الأنابيب التشريعي',
|
|
462
|
+
he: 'אירועי טריגר מתוארכים, תלויות לוח הפרלמנט ותחזית צינור החקיקה',
|
|
463
|
+
ja: '日付付きのトリガーイベント、議会カレンダーの依存関係、立法パイプラインの予測',
|
|
464
|
+
ko: '날짜가 지정된 트리거 이벤트, 의회 일정 의존성, 입법 파이프라인 예측',
|
|
465
|
+
zh: '标注日期的触发事件、议会日历依赖关系以及立法流程预测',
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
'section-electoral-arc': {
|
|
469
|
+
need: {
|
|
470
|
+
en: 'Electoral arc & mandate',
|
|
471
|
+
sv: 'Valbåge & mandat',
|
|
472
|
+
da: 'Valgbue & mandat',
|
|
473
|
+
no: 'Valgbue & mandat',
|
|
474
|
+
fi: 'Vaalikaari & mandaatti',
|
|
475
|
+
de: 'Wahlbogen & Mandat',
|
|
476
|
+
fr: 'Arc électoral & mandat',
|
|
477
|
+
es: 'Arco electoral & mandato',
|
|
478
|
+
nl: 'Verkiezingsboog & mandaat',
|
|
479
|
+
ar: 'القوس الانتخابي والتفويض',
|
|
480
|
+
he: 'קשת בחירות ומנדט',
|
|
481
|
+
ja: '選挙アークとマンデート',
|
|
482
|
+
ko: '선거 아크 & 위임',
|
|
483
|
+
zh: '选举弧线与任期',
|
|
484
|
+
},
|
|
485
|
+
value: {
|
|
486
|
+
en: 'where in the term the story sits, mandate-fulfilment scoring, seat projection, and the presidency-trio context',
|
|
487
|
+
sv: 'var i mandatperioden händelsen befinner sig, mandatuppfyllelsescoring, mandatprojektion och ordförandetrio-kontexten',
|
|
488
|
+
da: 'hvor i valgperioden historien ligger, mandatopfyldelsesscoring, mandatprojektion og formandstrio-konteksten',
|
|
489
|
+
no: 'hvor i valgperioden saken ligger, mandatoppfyllelsesscoring, mandatprojeksjon og formannskapstrio-konteksten',
|
|
490
|
+
fi: 'mihin kohtaan kautta tarina sijoittuu, mandaatin täyttymisen pisteytys, paikkaennuste ja puheenjohtajatrion konteksti',
|
|
491
|
+
de: 'wo im Mandat die Geschichte liegt, Mandatserfüllungs-Scoring, Sitzprojektion und Präsidentschaftstrio-Kontext',
|
|
492
|
+
fr: "où en est l'histoire dans le mandat, notation de l'exécution du mandat, projection des sièges et contexte du trio présidentiel",
|
|
493
|
+
es: 'dónde se sitúa la historia en el mandato, puntuación de cumplimiento del mandato, proyección de escaños y contexto del trío presidencial',
|
|
494
|
+
nl: 'waar het verhaal zich in het mandaat bevindt, scoring mandaatuitvoering, zetelprojectie en context van de voorzittersdrieluik',
|
|
495
|
+
ar: 'موقع القصة في الولاية، تقييم تنفيذ التفويض، توقعات المقاعد، وسياق الترويكا الرئاسية',
|
|
496
|
+
he: 'איפה בכהונה הסיפור ממוקם, ניקוד מילוי המנדט, תחזית מושבים, והקשר של שלישיית הנשיאות',
|
|
497
|
+
ja: '物語が任期のどこに位置するか、マンデート遂行スコア、議席予測、議長トリオの文脈',
|
|
498
|
+
ko: '이야기가 임기의 어디에 위치하는지, 위임 이행 점수, 의석 예측, 의장 트리오 맥락',
|
|
499
|
+
zh: '故事在任期中所处的位置、任期履行评分、席位预测以及主席三人组的背景',
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
'section-pestle-context': {
|
|
503
|
+
need: {
|
|
504
|
+
en: 'PESTLE & structural context',
|
|
505
|
+
sv: 'PESTLE & strukturell kontext',
|
|
506
|
+
da: 'PESTLE & strukturel kontekst',
|
|
507
|
+
no: 'PESTLE & strukturell kontekst',
|
|
508
|
+
fi: 'PESTLE & rakenteellinen konteksti',
|
|
509
|
+
de: 'PESTLE & struktureller Kontext',
|
|
510
|
+
fr: 'PESTLE & contexte structurel',
|
|
511
|
+
es: 'PESTLE & contexto estructural',
|
|
512
|
+
nl: 'PESTLE & structurele context',
|
|
513
|
+
ar: 'PESTLE والسياق الهيكلي',
|
|
514
|
+
he: 'PESTLE והקשר מבני',
|
|
515
|
+
ja: 'PESTLEと構造的コンテキスト',
|
|
516
|
+
ko: 'PESTLE & 구조적 맥락',
|
|
517
|
+
zh: 'PESTLE与结构性背景',
|
|
518
|
+
},
|
|
519
|
+
value: {
|
|
520
|
+
en: 'political, economic, social, technological, legal, and environmental forces plus the historical baseline',
|
|
521
|
+
sv: 'politiska, ekonomiska, sociala, tekniska, juridiska och miljömässiga krafter samt historisk baslinje',
|
|
522
|
+
da: 'politiske, økonomiske, sociale, teknologiske, juridiske og miljømæssige kræfter samt historisk baseline',
|
|
523
|
+
no: 'politiske, økonomiske, sosiale, teknologiske, juridiske og miljømessige krefter pluss historisk grunnlinje',
|
|
524
|
+
fi: 'poliittiset, taloudelliset, sosiaaliset, teknologiset, juridiset ja ympäristötekijät sekä historiallinen lähtötaso',
|
|
525
|
+
de: 'politische, wirtschaftliche, soziale, technologische, rechtliche und Umweltkräfte plus historische Baseline',
|
|
526
|
+
fr: 'forces politiques, économiques, sociales, technologiques, juridiques et environnementales plus la base historique',
|
|
527
|
+
es: 'fuerzas políticas, económicas, sociales, tecnológicas, legales y ambientales más la línea base histórica',
|
|
528
|
+
nl: 'politieke, economische, sociale, technologische, juridische en milieukrachten plus de historische basislijn',
|
|
529
|
+
ar: 'القوى السياسية والاقتصادية والاجتماعية والتكنولوجية والقانونية والبيئية بالإضافة إلى الأساس التاريخي',
|
|
530
|
+
he: 'כוחות פוליטיים, כלכליים, חברתיים, טכנולוגיים, משפטיים וסביבתיים בתוספת קו הבסיס ההיסטורי',
|
|
531
|
+
ja: '政治・経済・社会・技術・法律・環境の各要因と歴史的ベースライン',
|
|
532
|
+
ko: '정치, 경제, 사회, 기술, 법률, 환경 요인과 역사적 기준선',
|
|
533
|
+
zh: '政治、经济、社会、技术、法律和环境力量加上历史基准',
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
'section-continuity': {
|
|
537
|
+
need: {
|
|
538
|
+
en: 'Cross-run continuity',
|
|
539
|
+
sv: 'Kontinuitet mellan körningar',
|
|
540
|
+
da: 'Kryds-kørsels-kontinuitet',
|
|
541
|
+
no: 'Kontinuitet mellom kjøringer',
|
|
542
|
+
fi: 'Ajojen välinen jatkuvuus',
|
|
543
|
+
de: 'Laufübergreifende Kontinuität',
|
|
544
|
+
fr: 'Continuité inter-exécutions',
|
|
545
|
+
es: 'Continuidad entre ejecuciones',
|
|
546
|
+
nl: 'Continuïteit tussen runs',
|
|
547
|
+
ar: 'استمرارية عبر التشغيلات',
|
|
548
|
+
he: 'רציפות בין הרצות',
|
|
549
|
+
ja: 'クロスラン継続性',
|
|
550
|
+
ko: '교차 실행 연속성',
|
|
551
|
+
zh: '跨运行连续性',
|
|
552
|
+
},
|
|
553
|
+
value: {
|
|
554
|
+
en: 'how this run links to prior sessions, what changed, and how confidence shifted between runs',
|
|
555
|
+
sv: 'hur denna körning kopplar till tidigare sessioner, vad som förändrats och hur förtroendet skiftat mellan körningar',
|
|
556
|
+
da: 'hvordan denne kørsel forbinder til tidligere sessioner, hvad der er ændret, og hvordan tilliden har skiftet mellem kørsler',
|
|
557
|
+
no: 'hvordan denne kjøringen kobler til tidligere økter, hva som er endret, og hvordan tilliten har skiftet mellom kjøringer',
|
|
558
|
+
fi: 'miten tämä ajo kytkeytyy aiempiin istuntoihin, mikä on muuttunut ja miten luottamus on siirtynyt ajojen välillä',
|
|
559
|
+
de: 'wie dieser Lauf mit früheren Sitzungen verknüpft ist, was sich geändert hat und wie sich das Vertrauen zwischen Läufen verschoben hat',
|
|
560
|
+
fr: "comment cette exécution se relie aux sessions précédentes, ce qui a changé, et comment la confiance s'est déplacée entre les exécutions",
|
|
561
|
+
es: 'cómo se vincula esta ejecución con sesiones anteriores, qué cambió y cómo se desplazó la confianza entre ejecuciones',
|
|
562
|
+
nl: 'hoe deze run aansluit op eerdere sessies, wat er is veranderd en hoe het vertrouwen tussen runs is verschoven',
|
|
563
|
+
ar: 'كيفية ارتباط هذا التشغيل بالجلسات السابقة، وما الذي تغير، وكيف تحولت الثقة بين عمليات التشغيل',
|
|
564
|
+
he: 'כיצד הרצה זו מתקשרת להפעלות קודמות, מה השתנה, וכיצד הביטחון השתנה בין הרצות',
|
|
565
|
+
ja: 'この実行が以前のセッションとどう繋がるか、何が変わったか、実行間で信頼性がどう変動したか',
|
|
566
|
+
ko: '이 실행이 이전 세션과 어떻게 연결되는지, 무엇이 변경되었는지, 실행 간에 신뢰도가 어떻게 변화했는지',
|
|
567
|
+
zh: '本次运行如何与先前会话关联、变化了什么以及置信度在运行之间如何变化',
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
'section-extended-intel': {
|
|
571
|
+
need: {
|
|
572
|
+
en: 'Extended intelligence',
|
|
573
|
+
sv: 'Utökad underrättelse',
|
|
574
|
+
da: 'Udvidet efterretning',
|
|
575
|
+
no: 'Utvidet etterretning',
|
|
576
|
+
fi: 'Laajennettu tiedustelu',
|
|
577
|
+
de: 'Erweiterte Aufklärung',
|
|
578
|
+
fr: 'Renseignement étendu',
|
|
579
|
+
es: 'Inteligencia ampliada',
|
|
580
|
+
nl: 'Uitgebreide inlichtingen',
|
|
581
|
+
ar: 'استخبارات موسعة',
|
|
582
|
+
he: 'מודיעין מורחב',
|
|
583
|
+
ja: '拡張インテリジェンス',
|
|
584
|
+
ko: '확장 인텔리전스',
|
|
585
|
+
zh: '扩展情报',
|
|
586
|
+
},
|
|
587
|
+
value: {
|
|
588
|
+
en: "devil's-advocate critique, comparative international parallels, historical precedents, and media-framing analysis",
|
|
589
|
+
sv: 'djävulens-advokat-kritik, jämförande internationella paralleller, historiska prejudikat och mediaframing-analys',
|
|
590
|
+
da: 'djævlens-advokat-kritik, sammenlignende internationale paralleller, historiske præcedenser og medieframing-analyse',
|
|
591
|
+
no: 'djevelens advokat-kritikk, sammenlignende internasjonale paralleller, historiske presedenser og mediaframing-analyse',
|
|
592
|
+
fi: 'paholaisen asianajaja -kritiikki, kansainväliset vertailut, historialliset ennakkotapaukset ja media-analyysi',
|
|
593
|
+
de: 'Devil-Advocate-Kritik, vergleichende internationale Parallelen, historische Präzedenzfälle und Medien-Framing-Analyse',
|
|
594
|
+
fr: "critique de l'avocat du diable, parallèles internationaux comparatifs, précédents historiques et analyse du cadrage médiatique",
|
|
595
|
+
es: 'crítica de abogado del diablo, paralelismos internacionales comparativos, precedentes históricos y análisis de encuadre mediático',
|
|
596
|
+
nl: 'devils-advocate-kritiek, vergelijkende internationale parallellen, historische precedenten en media-framinganalyse',
|
|
597
|
+
ar: 'نقد محامي الشيطان، توازيات دولية مقارنة، سوابق تاريخية، وتحليل التأطير الإعلامي',
|
|
598
|
+
he: 'ביקורת פרקליט השטן, מקבילות בינלאומיות השוואתיות, תקדימים היסטוריים וניתוח מסגור תקשורתי',
|
|
599
|
+
ja: '悪魔の代弁者批評、比較国際パラレル、歴史的先例、メディアフレーミング分析',
|
|
600
|
+
ko: '악마의 변호인 비판, 비교 국제 평행 사례, 역사적 선례, 미디어 프레이밍 분석',
|
|
601
|
+
zh: '魔鬼代言人批评、比较国际平行案例、历史先例和媒体框架分析',
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
'section-mcp-reliability': {
|
|
605
|
+
need: {
|
|
606
|
+
en: 'MCP data reliability',
|
|
607
|
+
sv: 'MCP-datatillförlitlighet',
|
|
608
|
+
da: 'MCP-datapålidelighed',
|
|
609
|
+
no: 'MCP-datapålitelighet',
|
|
610
|
+
fi: 'MCP-datan luotettavuus',
|
|
611
|
+
de: 'MCP-Datenzuverlässigkeit',
|
|
612
|
+
fr: 'Fiabilité des données MCP',
|
|
613
|
+
es: 'Fiabilidad de datos MCP',
|
|
614
|
+
nl: 'Betrouwbaarheid MCP-gegevens',
|
|
615
|
+
ar: 'موثوقية بيانات MCP',
|
|
616
|
+
he: 'אמינות נתוני MCP',
|
|
617
|
+
ja: 'MCPデータ信頼性',
|
|
618
|
+
ko: 'MCP 데이터 신뢰성',
|
|
619
|
+
zh: 'MCP数据可靠性',
|
|
620
|
+
},
|
|
621
|
+
value: {
|
|
622
|
+
en: 'which feeds were healthy, which were degraded, and how the data limitations bound the conclusions',
|
|
623
|
+
sv: 'vilka flöden var friska, vilka var degraderade och hur databegränsningar binder slutsatserna',
|
|
624
|
+
da: 'hvilke feeds var sunde, hvilke var forringede, og hvordan databegrænsningerne binder konklusionerne',
|
|
625
|
+
no: 'hvilke feeds var sunne, hvilke var degradert, og hvordan databegrensninger binder konklusjonene',
|
|
626
|
+
fi: 'mitkä syötteet olivat terveitä, mitkä huonontuneita ja miten datarajoitukset rajaavat johtopäätöksiä',
|
|
627
|
+
de: 'welche Feeds gesund waren, welche degradiert, und wie die Datengrenzen die Schlussfolgerungen binden',
|
|
628
|
+
fr: 'quels flux étaient sains, lesquels étaient dégradés et comment les limites de données contraignent les conclusions',
|
|
629
|
+
es: 'qué fuentes estaban sanas, cuáles degradadas y cómo las limitaciones de datos restringen las conclusiones',
|
|
630
|
+
nl: 'welke feeds gezond waren, welke gedegradeerd, en hoe databeperkingen de conclusies inperken',
|
|
631
|
+
ar: 'أي الموجزات كانت صحية، وأيها متدهورة، وكيف تقيد قيود البيانات الاستنتاجات',
|
|
632
|
+
he: 'אילו פידים היו תקינים, אילו היו פגומים, וכיצד מגבלות הנתונים תוחמות את המסקנות',
|
|
633
|
+
ja: 'どのフィードが健全だったか、どれが劣化していたか、そしてデータの制約が結論をどう制限するか',
|
|
634
|
+
ko: '어떤 피드가 건강했고, 어떤 피드가 저하되었으며, 데이터 제약이 결론을 어떻게 제한하는지',
|
|
635
|
+
zh: '哪些数据源健康、哪些已降级,以及数据限制如何约束结论',
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
'section-quality-reflection': {
|
|
639
|
+
need: {
|
|
640
|
+
en: 'Analytical quality & reflection',
|
|
641
|
+
sv: 'Analytisk kvalitet & reflektion',
|
|
642
|
+
da: 'Analytisk kvalitet & refleksion',
|
|
643
|
+
no: 'Analytisk kvalitet & refleksjon',
|
|
644
|
+
fi: 'Analyyttinen laatu & pohdinta',
|
|
645
|
+
de: 'Analytische Qualität & Reflexion',
|
|
646
|
+
fr: 'Qualité analytique & réflexion',
|
|
647
|
+
es: 'Calidad analítica & reflexión',
|
|
648
|
+
nl: 'Analytische kwaliteit & reflectie',
|
|
649
|
+
ar: 'الجودة التحليلية والتأمل',
|
|
650
|
+
he: 'איכות אנליטית ורפלקציה',
|
|
651
|
+
ja: '分析品質と内省',
|
|
652
|
+
ko: '분석 품질 & 성찰',
|
|
653
|
+
zh: '分析质量与反思',
|
|
654
|
+
},
|
|
655
|
+
value: {
|
|
656
|
+
en: 'self-assessment scores, methodology audit, structured-analytic-techniques used, and known limitations',
|
|
657
|
+
sv: 'självvärderingspoäng, metodologirevision, strukturerade analystekniker som använts och kända begränsningar',
|
|
658
|
+
da: 'selvevalueringsresultater, metoderevision, anvendte strukturerede analyseteknikker og kendte begrænsninger',
|
|
659
|
+
no: 'selvvurderingsskår, metoderevisjon, brukte strukturerte analyseteknikker og kjente begrensninger',
|
|
660
|
+
fi: 'itsearviointipisteet, metodologian auditointi, käytetyt strukturoidut analyysitekniikat ja tunnetut rajoitukset',
|
|
661
|
+
de: 'Selbsteinschätzungs-Scores, Methodologie-Audit, eingesetzte strukturierte Analysetechniken und bekannte Einschränkungen',
|
|
662
|
+
fr: "scores d'auto-évaluation, audit méthodologique, techniques analytiques structurées utilisées et limitations connues",
|
|
663
|
+
es: 'puntuaciones de autoevaluación, auditoría metodológica, técnicas analíticas estructuradas utilizadas y limitaciones conocidas',
|
|
664
|
+
nl: 'zelfevaluatiescores, methodologie-audit, gebruikte gestructureerde analytische technieken en bekende beperkingen',
|
|
665
|
+
ar: 'درجات التقييم الذاتي، تدقيق المنهجية، تقنيات التحليل المنظمة المستخدمة، والقيود المعروفة',
|
|
666
|
+
he: 'ציוני הערכה עצמית, ביקורת מתודולוגית, טכניקות אנליטיות מובנות שנעשה בהן שימוש ומגבלות ידועות',
|
|
667
|
+
ja: '自己評価スコア、方法論監査、使用された構造化分析技法、および既知の制約',
|
|
668
|
+
ko: '자가 평가 점수, 방법론 감사, 사용된 구조화된 분석 기법 및 알려진 한계',
|
|
669
|
+
zh: '自我评估分数、方法论审计、使用的结构化分析技术和已知限制',
|
|
670
|
+
},
|
|
671
|
+
},
|
|
366
672
|
};
|
|
367
673
|
/* ─── Section icons ─────────────────────────────────────────────── */
|
|
368
674
|
/** Visual icons for each reader guide section to improve scannability. */
|
|
@@ -370,24 +676,56 @@ const SECTION_ICONS = {
|
|
|
370
676
|
'section-executive-brief': '📋',
|
|
371
677
|
'section-synthesis': '🔗',
|
|
372
678
|
'section-significance': '⚖️',
|
|
679
|
+
'section-actors-forces': '🎭',
|
|
373
680
|
'section-coalitions-voting': '🤝',
|
|
374
681
|
'section-stakeholder-map': '👥',
|
|
375
682
|
'section-economic-context': '💶',
|
|
376
|
-
'section-scenarios': '🔮',
|
|
377
683
|
'section-risk': '⚠️',
|
|
684
|
+
'section-threat': '🛡️',
|
|
685
|
+
'section-scenarios': '🔮',
|
|
686
|
+
'section-forward-projection': '🔭',
|
|
687
|
+
'section-electoral-arc': '🗳️',
|
|
688
|
+
'section-pestle-context': '🌍',
|
|
689
|
+
'section-continuity': '🔁',
|
|
690
|
+
'section-extended-intel': '🧠',
|
|
691
|
+
'section-mcp-reliability': '📡',
|
|
692
|
+
'section-quality-reflection': '🪞',
|
|
378
693
|
};
|
|
694
|
+
/**
|
|
695
|
+
* Look up the visual icon for a known article section.
|
|
696
|
+
*
|
|
697
|
+
* Exposed so the article-level Table-of-Contents (`buildArticleToc`)
|
|
698
|
+
* can render the same emoji that the Reader Intelligence Guide uses
|
|
699
|
+
* for each section, keeping the two navigation surfaces visually
|
|
700
|
+
* consistent. Unknown section IDs (e.g. ad-hoc `supplementary-…` or
|
|
701
|
+
* appendix anchors) fall back to a generic 📎 paperclip.
|
|
702
|
+
*
|
|
703
|
+
* @param sectionId - Anchor id of the section (e.g. `section-risk`)
|
|
704
|
+
* @returns Single emoji glyph used as a `guide-icon`
|
|
705
|
+
*/
|
|
706
|
+
export function getReaderGuideSectionIcon(sectionId) {
|
|
707
|
+
return SECTION_ICONS[sectionId] ?? '📎';
|
|
708
|
+
}
|
|
379
709
|
/* ─── HTML builder ───────────────────────────────────────────────── */
|
|
380
710
|
/**
|
|
381
711
|
* Build a translated Reader Intelligence Guide as an HTML section.
|
|
382
712
|
* Emits exactly one component with `data-component="reader-intelligence-guide"`
|
|
383
713
|
* for de-duplication detection by E2E tests.
|
|
384
714
|
*
|
|
715
|
+
* The guide renders one row per emitted article section that has a
|
|
716
|
+
* curated reader-need translation (see {@link READER_GUIDE_ROWS}). The
|
|
717
|
+
* `included` list is no longer surfaced — the previous "source artifact"
|
|
718
|
+
* column duplicated the per-section navigation that the Analysis Index
|
|
719
|
+
* appendix already presents, and clutters the headline reader lens. The
|
|
720
|
+
* parameter is kept on the signature for backward compatibility with
|
|
721
|
+
* callers that may pre-compute the run manifest.
|
|
722
|
+
*
|
|
385
723
|
* @param lang - Target language code
|
|
386
724
|
* @param sections - Emitted section TOC entries, in document order
|
|
387
|
-
* @param
|
|
725
|
+
* @param _included - (Unused) Included artifacts; kept for API stability
|
|
388
726
|
* @returns HTML fragment for the guide, or empty string if no rows match
|
|
389
727
|
*/
|
|
390
|
-
export function buildReaderIntelligenceGuideHtml(lang, sections,
|
|
728
|
+
export function buildReaderIntelligenceGuideHtml(lang, sections, _included = []) {
|
|
391
729
|
const dir = getTextDirection(lang);
|
|
392
730
|
const rows = [];
|
|
393
731
|
for (const section of sections) {
|
|
@@ -396,10 +734,8 @@ export function buildReaderIntelligenceGuideHtml(lang, sections, included) {
|
|
|
396
734
|
continue;
|
|
397
735
|
const need = getLocalizedString(rowData.need, lang);
|
|
398
736
|
const value = getLocalizedString(rowData.value, lang);
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
const sectionIcon = SECTION_ICONS[section.id] ?? '📎';
|
|
402
|
-
rows.push(`<tr><td><span class="guide-icon" aria-hidden="true">${sectionIcon}</span> <a href="#${escapeHTML(section.id)}">${escapeHTML(need)}</a></td><td>${escapeHTML(value)}</td><td>${sourceLabel}</td></tr>`);
|
|
737
|
+
const sectionIcon = getReaderGuideSectionIcon(section.id);
|
|
738
|
+
rows.push(`<tr><td><span class="guide-icon" aria-hidden="true">${sectionIcon}</span> <a href="#${escapeHTML(section.id)}">${escapeHTML(need)}</a></td><td>${escapeHTML(value)}</td></tr>`);
|
|
403
739
|
}
|
|
404
740
|
if (rows.length === 0)
|
|
405
741
|
return '';
|
|
@@ -407,14 +743,13 @@ export function buildReaderIntelligenceGuideHtml(lang, sections, included) {
|
|
|
407
743
|
const intro = getLocalizedString(READER_GUIDE_INTRO_LABELS, lang);
|
|
408
744
|
const colNeed = getLocalizedString(READER_GUIDE_COL_NEED_LABELS, lang);
|
|
409
745
|
const colValue = getLocalizedString(READER_GUIDE_COL_VALUE_LABELS, lang);
|
|
410
|
-
const colSource = getLocalizedString(READER_GUIDE_COL_SOURCE_LABELS, lang);
|
|
411
746
|
return `<section id="${READER_GUIDE_SECTION_ID}" data-component="reader-intelligence-guide" aria-label="${escapeHTML(title)}"${dir === 'rtl' ? ' dir="rtl"' : ''}>
|
|
412
747
|
<h2 id="${READER_GUIDE_SECTION_ID}-heading"><span class="guide-icon" aria-hidden="true">🧭</span> ${escapeHTML(title)}</h2>
|
|
413
748
|
<p class="reader-guide-intro">${escapeHTML(intro)}</p>
|
|
414
749
|
<div class="table-scroll" role="region" tabindex="0" aria-labelledby="${READER_GUIDE_SECTION_ID}-heading">
|
|
415
750
|
<table class="reader-guide-table">
|
|
416
751
|
<caption class="sr-only">${escapeHTML(title)}</caption>
|
|
417
|
-
<thead><tr><th scope="col">${escapeHTML(colNeed)}</th><th scope="col">${escapeHTML(colValue)}</th
|
|
752
|
+
<thead><tr><th scope="col">${escapeHTML(colNeed)}</th><th scope="col">${escapeHTML(colValue)}</th></tr></thead>
|
|
418
753
|
<tbody>
|
|
419
754
|
${rows.join('\n')}
|
|
420
755
|
</tbody>
|
|
@@ -32,7 +32,7 @@ export interface McpToolResult {
|
|
|
32
32
|
/**
|
|
33
33
|
* Returns `true` when `url` is allowed by the IMF-only fetch-proxy policy.
|
|
34
34
|
*
|
|
35
|
-
* Allowed: `https://
|
|
35
|
+
* Allowed: `https://api.imf.org/external/sdmx/3.0/...` (SDMX 2.1 rejected).
|
|
36
36
|
*
|
|
37
37
|
* @param url - Raw URL string to validate.
|
|
38
38
|
* @returns Whether the URL is permitted.
|
|
@@ -63,18 +63,6 @@ export declare function handleInitialize(id: number | string | null): JsonRpcSuc
|
|
|
63
63
|
* @returns JSON-RPC success with the tool descriptor array.
|
|
64
64
|
*/
|
|
65
65
|
export declare function handleToolsList(id: number | string | null): JsonRpcSuccess;
|
|
66
|
-
/**
|
|
67
|
-
* Execute the `fetch_url` tool call.
|
|
68
|
-
*
|
|
69
|
-
* Only URLs matching the IMF SDMX 3.0 allowlist are permitted. Non-matching
|
|
70
|
-
* or malformed URLs receive a JSON-RPC error response; HTTP errors and network
|
|
71
|
-
* failures also surface as errors.
|
|
72
|
-
*
|
|
73
|
-
* @param id - Request id to echo.
|
|
74
|
-
* @param url - URL to fetch.
|
|
75
|
-
* @param fetchImpl - Injectable `fetch` implementation (defaults to global).
|
|
76
|
-
* @returns JSON-RPC success or error.
|
|
77
|
-
*/
|
|
78
66
|
export declare function handleFetchUrl(id: number | string | null, url: string | undefined, fetchImpl?: typeof fetch): Promise<JsonRpcSuccess | JsonRpcError>;
|
|
79
67
|
/**
|
|
80
68
|
* Run the fetch-proxy MCP server, reading JSON-RPC messages from `input` and
|