euparliamentmonitor 0.8.41 → 0.8.43
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 +136 -26
- package/SECURITY.md +11 -6
- package/package.json +11 -9
- package/scripts/aggregator/analysis-aggregator.d.ts +168 -0
- package/scripts/aggregator/analysis-aggregator.js +478 -0
- package/scripts/aggregator/article-generator.d.ts +141 -0
- package/scripts/aggregator/article-generator.js +693 -0
- package/scripts/aggregator/article-html.d.ts +90 -0
- package/scripts/aggregator/article-html.js +215 -0
- package/scripts/aggregator/article-metadata.d.ts +186 -0
- package/scripts/aggregator/article-metadata.js +701 -0
- package/scripts/aggregator/artifact-order.d.ts +52 -0
- package/scripts/aggregator/artifact-order.js +148 -0
- package/scripts/aggregator/clean-artifact.d.ts +138 -0
- package/scripts/aggregator/clean-artifact.js +609 -0
- package/scripts/aggregator/markdown-renderer.d.ts +69 -0
- package/scripts/aggregator/markdown-renderer.js +169 -0
- package/scripts/backport-article-seo.js +1037 -0
- package/scripts/constants/language-ui.d.ts +2 -0
- package/scripts/constants/language-ui.js +17 -0
- package/scripts/constants/languages.d.ts +1 -1
- package/scripts/constants/languages.js +1 -1
- package/scripts/generators/political-intelligence-descriptions.d.ts +200 -0
- package/scripts/generators/political-intelligence-descriptions.js +3043 -0
- package/scripts/generators/political-intelligence.d.ts +118 -0
- package/scripts/generators/political-intelligence.js +1260 -0
- package/scripts/generators/sitemap.d.ts +13 -0
- package/scripts/generators/sitemap.js +616 -127
- package/scripts/index.d.ts +18 -65
- package/scripts/index.js +24 -85
- package/scripts/index.old.js +125 -0
- package/scripts/lint-prompts.js +42 -4
- package/scripts/mcp/ep-mcp-client.d.ts +9 -9
- package/scripts/mcp/ep-mcp-client.js +14 -14
- package/scripts/templates/section-builders.js +5 -3
- package/scripts/types/generation.d.ts +13 -0
- package/scripts/types/index.d.ts +1 -2
- package/scripts/types/mcp.d.ts +14 -14
- package/scripts/utils/content-metadata.d.ts +1 -1
- package/scripts/utils/file-utils.d.ts +87 -9
- package/scripts/utils/file-utils.js +176 -15
- package/scripts/generators/analysis-builders.d.ts +0 -12
- package/scripts/generators/analysis-builders.js +0 -14
- package/scripts/generators/breaking-content.d.ts +0 -45
- package/scripts/generators/breaking-content.js +0 -518
- package/scripts/generators/builders/breaking-builders.d.ts +0 -52
- package/scripts/generators/builders/breaking-builders.js +0 -400
- package/scripts/generators/builders/committee-builders.d.ts +0 -47
- package/scripts/generators/builders/committee-builders.js +0 -324
- package/scripts/generators/builders/index.d.ts +0 -13
- package/scripts/generators/builders/index.js +0 -15
- package/scripts/generators/builders/propositions-builders.d.ts +0 -53
- package/scripts/generators/builders/propositions-builders.js +0 -536
- package/scripts/generators/builders/prospective-builders.d.ts +0 -50
- package/scripts/generators/builders/prospective-builders.js +0 -369
- package/scripts/generators/builders/shared-builders.d.ts +0 -155
- package/scripts/generators/builders/shared-builders.js +0 -328
- package/scripts/generators/builders/voting-builders.d.ts +0 -65
- package/scripts/generators/builders/voting-builders.js +0 -565
- package/scripts/generators/committee-helpers.d.ts +0 -54
- package/scripts/generators/committee-helpers.js +0 -154
- package/scripts/generators/dashboard-content.d.ts +0 -95
- package/scripts/generators/dashboard-content.js +0 -631
- package/scripts/generators/deep-analysis-content.d.ts +0 -22
- package/scripts/generators/deep-analysis-content.js +0 -853
- package/scripts/generators/mindmap-content.d.ts +0 -22
- package/scripts/generators/mindmap-content.js +0 -447
- package/scripts/generators/motions-content.d.ts +0 -50
- package/scripts/generators/motions-content.js +0 -391
- package/scripts/generators/news-enhanced.d.ts +0 -50
- package/scripts/generators/news-enhanced.js +0 -545
- package/scripts/generators/pipeline/analysis-stage.d.ts +0 -100
- package/scripts/generators/pipeline/analysis-stage.js +0 -203
- package/scripts/generators/pipeline/fetch-stage.d.ts +0 -370
- package/scripts/generators/pipeline/fetch-stage.js +0 -1726
- package/scripts/generators/pipeline/generate-stage.d.ts +0 -73
- package/scripts/generators/pipeline/generate-stage.js +0 -268
- package/scripts/generators/pipeline/output-stage.d.ts +0 -54
- package/scripts/generators/pipeline/output-stage.js +0 -156
- package/scripts/generators/pipeline/transform-stage.d.ts +0 -57
- package/scripts/generators/pipeline/transform-stage.js +0 -111
- package/scripts/generators/propositions-content.d.ts +0 -29
- package/scripts/generators/propositions-content.js +0 -80
- package/scripts/generators/strategies/article-strategy.d.ts +0 -265
- package/scripts/generators/strategies/article-strategy.js +0 -514
- package/scripts/generators/strategies/breaking-news-strategy.d.ts +0 -64
- package/scripts/generators/strategies/breaking-news-strategy.js +0 -340
- package/scripts/generators/strategies/committee-reports-strategy.d.ts +0 -93
- package/scripts/generators/strategies/committee-reports-strategy.js +0 -470
- package/scripts/generators/strategies/month-ahead-strategy.d.ts +0 -60
- package/scripts/generators/strategies/month-ahead-strategy.js +0 -196
- package/scripts/generators/strategies/monthly-review-strategy.d.ts +0 -66
- package/scripts/generators/strategies/monthly-review-strategy.js +0 -220
- package/scripts/generators/strategies/motions-strategy.d.ts +0 -61
- package/scripts/generators/strategies/motions-strategy.js +0 -235
- package/scripts/generators/strategies/propositions-strategy.d.ts +0 -60
- package/scripts/generators/strategies/propositions-strategy.js +0 -263
- package/scripts/generators/strategies/week-ahead-strategy.d.ts +0 -57
- package/scripts/generators/strategies/week-ahead-strategy.js +0 -196
- package/scripts/generators/strategies/weekly-review-strategy.d.ts +0 -63
- package/scripts/generators/strategies/weekly-review-strategy.js +0 -232
- package/scripts/generators/swot-content.d.ts +0 -18
- package/scripts/generators/swot-content.js +0 -105
- package/scripts/generators/synthesis-summary.d.ts +0 -93
- package/scripts/generators/synthesis-summary.js +0 -364
- package/scripts/generators/week-ahead-content.d.ts +0 -103
- package/scripts/generators/week-ahead-content.js +0 -603
- package/scripts/templates/article-template.d.ts +0 -32
- package/scripts/templates/article-template.js +0 -702
- package/scripts/utils/article-quality-scorer.d.ts +0 -108
- package/scripts/utils/article-quality-scorer.js +0 -1214
- package/scripts/utils/content-validator.d.ts +0 -253
- package/scripts/utils/content-validator.js +0 -1610
- package/scripts/utils/fix-articles.d.ts +0 -27
- package/scripts/utils/fix-articles.js +0 -510
- package/scripts/utils/imf-data.d.ts +0 -216
- package/scripts/utils/imf-data.js +0 -577
- package/scripts/utils/intelligence-analysis.d.ts +0 -223
- package/scripts/utils/intelligence-analysis.js +0 -1229
- package/scripts/utils/political-classification.d.ts +0 -191
- package/scripts/utils/political-classification.js +0 -885
- package/scripts/utils/political-risk-assessment.d.ts +0 -197
- package/scripts/utils/political-risk-assessment.js +0 -980
- package/scripts/utils/political-threat-assessment.d.ts +0 -116
- package/scripts/utils/political-threat-assessment.js +0 -1438
- package/scripts/utils/retrofit-analysis-links.d.ts +0 -14
- package/scripts/utils/retrofit-analysis-links.js +0 -265
- package/scripts/utils/significance-scoring.d.ts +0 -140
- package/scripts/utils/significance-scoring.js +0 -294
- package/scripts/utils/validate-analysis-completeness.d.ts +0 -80
- package/scripts/utils/validate-analysis-completeness.js +0 -882
- package/scripts/utils/validate-articles.d.ts +0 -2
- package/scripts/utils/validate-articles.js +0 -402
- package/scripts/utils/world-bank-data.d.ts +0 -116
- package/scripts/utils/world-bank-data.js +0 -414
package/README.md
CHANGED
|
@@ -131,15 +131,24 @@ import {
|
|
|
131
131
|
|
|
132
132
|
**MCP Server Integration**: The project uses the
|
|
133
133
|
[European-Parliament-MCP-Server](https://github.com/Hack23/European-Parliament-MCP-Server)
|
|
134
|
-
v1.2.
|
|
134
|
+
v1.2.13 for accessing real EU Parliament data via the Model Context Protocol.
|
|
135
135
|
|
|
136
136
|
- **MCP Server Status**: ✅ Fully operational — 60+ EP data tools available
|
|
137
137
|
(feeds, direct lookups, analytical tools, intelligence correlation)
|
|
138
|
-
- **Agentic Workflows**:
|
|
139
|
-
`gh-aw v0.69.3`
|
|
138
|
+
- **Agentic Workflows**: 9 unified gh-aw markdown workflows — 8 article types (`news-<type>.md`, Stages A → B → C → D → E in one session) + `news-translate.md` (14-language flush translation) — compiled with
|
|
139
|
+
`gh-aw v0.69.3` to `.lock.yml` for automated news generation with AI-driven political
|
|
140
140
|
intelligence analysis. See [`.github/workflows/README.md`](.github/workflows/README.md).
|
|
141
|
-
- **Analysis
|
|
142
|
-
|
|
141
|
+
- **Analysis-Artifact-Driven Article Pipeline**: Agents author the full
|
|
142
|
+
Stage-B analysis-artifact set (`analysis/daily/<date>/<slug>-run<NN>/`, 39
|
|
143
|
+
structured templates per run) and commit it; the deterministic aggregator
|
|
144
|
+
(`src/aggregator/**`, invoked via
|
|
145
|
+
`npm run generate-article -- --run <analysis-run-dir>` or
|
|
146
|
+
`npm run generate-article:all` for batch regen) then walks `manifest.json`,
|
|
147
|
+
cleans each artifact, and emits the final Markdown source + HTML with the
|
|
148
|
+
shared site chrome (stacked header + embedded 14-language switcher + TOC
|
|
149
|
+
sidebar + footer stats) and 14-language `<link rel="alternate" hreflang>`
|
|
150
|
+
entries. There is no AI-authored HTML step; article quality is guaranteed
|
|
151
|
+
editorially at the Stage-C completeness review over the artifact markdown.
|
|
143
152
|
See [`analysis/README.md`](analysis/README.md) and
|
|
144
153
|
[`analysis/methodologies/ai-driven-analysis-guide.md`](analysis/methodologies/ai-driven-analysis-guide.md).
|
|
145
154
|
- **Fallback Mode**: News generation can work with reduced data when EP API
|
|
@@ -168,6 +177,13 @@ covering:
|
|
|
168
177
|
- 🤖 **GitHub Actions Integration**: Automated daily news generation
|
|
169
178
|
- 📊 **SEO Optimized**: Proper metadata, structured data, and sitemap generation
|
|
170
179
|
- ✅ **Code Quality**: ESLint, Prettier, and automated quality gates
|
|
180
|
+
- 🌐 **IMF-grade Economic Context**: IMF-primary citations are the
|
|
181
|
+
editorial standard for every policy article — see
|
|
182
|
+
[`analysis/imf/README.md`](analysis/imf/README.md) and
|
|
183
|
+
[`analysis/methodologies/imf-indicator-mapping.md`](analysis/methodologies/imf-indicator-mapping.md).
|
|
184
|
+
World Bank is retained only for non-economic indicators (health,
|
|
185
|
+
education, social, environment, demographics, defence, agriculture,
|
|
186
|
+
innovation, governance).
|
|
171
187
|
|
|
172
188
|
## 🔒 Security Architecture
|
|
173
189
|
|
|
@@ -398,19 +414,17 @@ import {
|
|
|
398
414
|
// MCP Client for EU Parliament data
|
|
399
415
|
EuropeanParliamentMCPClient,
|
|
400
416
|
getEPMCPClient,
|
|
401
|
-
// Intelligence
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
// Article generation
|
|
406
|
-
|
|
407
|
-
|
|
417
|
+
// Intelligence index (cross-article relationships)
|
|
418
|
+
buildIndexFromEntries,
|
|
419
|
+
findRelatedArticles,
|
|
420
|
+
generateCrossReferences,
|
|
421
|
+
// Article generation (aggregator pipeline)
|
|
422
|
+
generateArticle,
|
|
423
|
+
aggregateAnalysisRun,
|
|
424
|
+
renderMarkdown,
|
|
408
425
|
// Multi-language support (14 languages)
|
|
409
426
|
ALL_LANGUAGES,
|
|
410
427
|
LANGUAGE_NAMES,
|
|
411
|
-
// Content validation
|
|
412
|
-
validateArticleContent,
|
|
413
|
-
validateTranslationCompleteness,
|
|
414
428
|
} from 'euparliamentmonitor';
|
|
415
429
|
|
|
416
430
|
// Or import specific modules for tree-shaking
|
|
@@ -459,27 +473,119 @@ without it using placeholder content.
|
|
|
459
473
|
|
|
460
474
|
### Generate News Articles
|
|
461
475
|
|
|
476
|
+
Agentic workflows generate articles automatically. For manual article generation from an analysis run:
|
|
477
|
+
|
|
462
478
|
```bash
|
|
463
|
-
#
|
|
464
|
-
npm run generate-
|
|
479
|
+
# Render one article from a specific analysis run directory
|
|
480
|
+
npm run generate-article -- --run analysis/daily/2025-01-01/breaking
|
|
465
481
|
|
|
466
|
-
#
|
|
467
|
-
|
|
482
|
+
# Regenerate EVERY committed analysis run in one pass (skips runs whose
|
|
483
|
+
# manifest.json has no valid articleType; collision-suffixes same-date /
|
|
484
|
+
# same-type runs with a sanitised runId)
|
|
485
|
+
npm run generate-article:all
|
|
468
486
|
|
|
469
|
-
#
|
|
470
|
-
npm run generate-
|
|
487
|
+
# Only regenerate runs from a given date onward
|
|
488
|
+
npm run generate-article -- --all --since 2026-04-01
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Each invocation writes:
|
|
492
|
+
|
|
493
|
+
- `news/<slug>.en.md` — aggregated Markdown (provenance block + 19-section
|
|
494
|
+
ordered artifact set + Tradecraft References appendix + Analysis Index appendix)
|
|
495
|
+
- `news/<slug>-<lang>.html` — 14 language variants, each wrapped in the
|
|
496
|
+
shared site chrome (stacked header with embedded language switcher,
|
|
497
|
+
article-level Table of Contents sidebar, shared footer with live
|
|
498
|
+
article-count stats)
|
|
499
|
+
|
|
500
|
+
The aggregator lives under `src/aggregator/` — see the
|
|
501
|
+
[aggregator pipeline](ARCHITECTURE.md#aggregator-pipeline) section of the
|
|
502
|
+
architecture doc for the full data flow.
|
|
503
|
+
|
|
504
|
+
#### Editorial-highlight metadata resolver
|
|
505
|
+
|
|
506
|
+
The `<title>` / `<meta description>` / Open Graph / Twitter / JSON-LD
|
|
507
|
+
`NewsArticle` fields for every article are resolved by
|
|
508
|
+
`src/aggregator/article-metadata.ts` through a 5-tier priority ladder:
|
|
509
|
+
|
|
510
|
+
1. **Manifest override** — the Stage-B agent writes one of these keys in
|
|
511
|
+
`manifest.json` when it has an editorial headline:
|
|
512
|
+
|
|
513
|
+
```jsonc
|
|
514
|
+
{
|
|
515
|
+
"articleType": "breaking",
|
|
516
|
+
// String form — applied to all 14 language variants (recommended
|
|
517
|
+
// when only an English headline is available):
|
|
518
|
+
"title": "Banking Union Breakthrough and Anti-Corruption Landmark",
|
|
519
|
+
"description": "The plenary closes a six-year debate and triggers immediate criticism from two national delegations about implementation timelines.",
|
|
520
|
+
// OR per-language form when translations already exist:
|
|
521
|
+
"title": { "en": "…", "sv": "…", "de": "…" },
|
|
522
|
+
"description": { "en": "…", "sv": "…" }
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
2. **First artefact H1** — the aggregator walks the manifest's ordered
|
|
527
|
+
artefact list (`intelligence/synthesis-summary.md`,
|
|
528
|
+
`executive-summary.md`, `breaking-news-analysis.md`, …) and promotes
|
|
529
|
+
the first non-generic `# …` heading.
|
|
530
|
+
3. **Aggregated-markdown H1** — any non-generic top-level heading in the
|
|
531
|
+
rendered Markdown.
|
|
532
|
+
4. **First strong prose paragraph** — with a tightened leak filter that
|
|
533
|
+
blocks mermaid `%%{init}` blocks, `title …` directives, emoji-banner
|
|
534
|
+
metadata, and `Analysis Date:` / `Classification:` / `Run:` / `Window:`
|
|
535
|
+
/ `Purpose:` / `BLUF (ICD-203):` style rows.
|
|
536
|
+
5. **Localized template** — `*_TITLES(date)` from
|
|
537
|
+
`src/constants/language-articles.ts` — last resort when no editorial
|
|
538
|
+
content exists at all.
|
|
539
|
+
|
|
540
|
+
Downstream generators (`news-indexes.ts`, `sitemap.ts`, political-intelligence
|
|
541
|
+
cards, RSS) call `extractArticleMeta()` in `src/utils/file-utils.ts`, which
|
|
542
|
+
reads the `<head><title>` value (with the ` — EU Parliament Monitor`
|
|
543
|
+
suffix stripped) as the primary title, so the resolver's output
|
|
544
|
+
propagates everywhere without separate code changes in each generator.
|
|
545
|
+
|
|
546
|
+
#### Backport SEO metadata into existing articles
|
|
547
|
+
|
|
548
|
+
`scripts/backport-article-seo.js` rewrites `<title>`, the meta
|
|
549
|
+
description, Open Graph, Twitter, and JSON-LD `headline`/`description`
|
|
550
|
+
for every already-rendered `news/*-<lang>.html` file by extracting the
|
|
551
|
+
first editorial H1 and first strong prose paragraph from the article
|
|
552
|
+
body itself. The rewrite is idempotent — re-running over a backported
|
|
553
|
+
file is a byte-identical no-op — and the article body is never
|
|
554
|
+
modified.
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
# Preview the change-set (dry-run is the default; prints a per-article-
|
|
558
|
+
# type summary and up to 12 sample before/after diffs):
|
|
559
|
+
node scripts/backport-article-seo.js
|
|
471
560
|
|
|
472
|
-
#
|
|
473
|
-
|
|
561
|
+
# Write changes:
|
|
562
|
+
node scripts/backport-article-seo.js --apply
|
|
563
|
+
|
|
564
|
+
# Scope to a subset of article types:
|
|
565
|
+
node scripts/backport-article-seo.js --apply --only breaking,motions
|
|
566
|
+
|
|
567
|
+
# Use a non-default news directory:
|
|
568
|
+
node scripts/backport-article-seo.js --apply --dir news
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
After backporting, regenerate the downstream surfaces that depend on
|
|
572
|
+
article metadata:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
node scripts/generators/news-indexes.js # 14 language index pages
|
|
576
|
+
node scripts/generators/sitemap.js # 14 sitemap HTMLs + sitemap.xml + rss.xml
|
|
474
577
|
```
|
|
475
578
|
|
|
476
579
|
### Generate Indexes and Sitemap
|
|
477
580
|
|
|
478
581
|
```bash
|
|
479
|
-
# Generate
|
|
582
|
+
# Generate per-run news index pages (consumed by the aggregator's
|
|
583
|
+
# transparency footer and political-intelligence.html)
|
|
480
584
|
npm run generate-news-indexes
|
|
481
585
|
|
|
482
|
-
# Generate sitemap.xml
|
|
586
|
+
# Generate sitemap.xml, sitemap_<lang>.html, and political-intelligence_<lang>.html
|
|
587
|
+
# (14 language-specific sitemap pages + 14 language-specific Political Intelligence
|
|
588
|
+
# pages that index every methodology, template, and daily analysis run)
|
|
483
589
|
npm run generate-sitemap
|
|
484
590
|
```
|
|
485
591
|
|
|
@@ -523,7 +629,11 @@ euparliamentmonitor/
|
|
|
523
629
|
├── index-{lang}.html # Language-specific index pages
|
|
524
630
|
├── typedoc.json # TypeDoc configuration
|
|
525
631
|
├── tsconfig.json # TypeScript configuration
|
|
526
|
-
├── sitemap.xml # SEO sitemap
|
|
632
|
+
├── sitemap.xml # SEO sitemap with hreflang alternates
|
|
633
|
+
├── sitemap.html # Human-readable sitemap (English)
|
|
634
|
+
├── sitemap_{lang}.html # Per-language human-readable sitemaps
|
|
635
|
+
├── political-intelligence.html # Index of every methodology + template + daily analysis run
|
|
636
|
+
├── political-intelligence_{lang}.html # Localized political-intelligence pages
|
|
527
637
|
└── package.json # Project dependencies
|
|
528
638
|
```
|
|
529
639
|
|
package/SECURITY.md
CHANGED
|
@@ -88,15 +88,20 @@ See [SECURITY_ARCHITECTURE.md - Security Testing](SECURITY_ARCHITECTURE.md#-secu
|
|
|
88
88
|
### Scope
|
|
89
89
|
|
|
90
90
|
**In Scope**:
|
|
91
|
-
- News generation scripts (scripts
|
|
91
|
+
- News generation scripts (`scripts/`)
|
|
92
|
+
- Analysis-artifact aggregator (`src/aggregator/**` — `artifact-order.ts`, `clean-artifact.ts`, `analysis-aggregator.ts`, `markdown-renderer.ts`, `article-html.ts`, `article-generator.ts` CLI)
|
|
93
|
+
- HTML sanitiser (`src/utils/html-sanitize.ts`) and the `markdown-it` render pipeline with plugins (`markdown-it-anchor`, `markdown-it-footnote`, `markdown-it-attrs`, `markdown-it-deflist`)
|
|
94
|
+
- MCP clients (`src/mcp/**` — European Parliament, IMF, World Bank)
|
|
95
|
+
- Committed analysis artifacts under `analysis/daily/**` (as attack surface for aggregator rendering)
|
|
96
|
+
- Vendored client-side diagram renderer (`js/mermaid.esm.min.mjs`) and its CSP `script-src 'self'` constraint
|
|
92
97
|
- HTML templates and output
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
- Dependencies and supply chain
|
|
98
|
+
- GitHub Actions workflows and gh-aw agentic workflows (`.github/workflows/news-*.md`)
|
|
99
|
+
- AWS S3 + CloudFront deployment pipeline (`deploy-s3.yml`)
|
|
100
|
+
- Dependencies and supply chain (OpenSSF Scorecard + SLSA L3 provenance)
|
|
96
101
|
|
|
97
102
|
**Out of Scope**:
|
|
98
|
-
- Third-party services (GitHub, European Parliament APIs)
|
|
99
|
-
- Infrastructure (GitHub Pages hosting)
|
|
103
|
+
- Third-party services (GitHub, European Parliament APIs, IMF SDMX REST, World Bank MCP)
|
|
104
|
+
- Infrastructure (AWS account-level, GitHub Pages hosting as fallback)
|
|
100
105
|
- Client-side browser vulnerabilities (not controlled by this project)
|
|
101
106
|
|
|
102
107
|
### Recognition and Anonymity
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "euparliamentmonitor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.43",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "European Parliament Intelligence Platform - Monitor political activity with systematic transparency",
|
|
6
6
|
"main": "scripts/index.js",
|
|
@@ -60,15 +60,11 @@
|
|
|
60
60
|
"build": "tsc",
|
|
61
61
|
"build:check": "tsc --noEmit",
|
|
62
62
|
"build:check-tests": "tsc --project tsconfig.test.json --noEmit",
|
|
63
|
-
"copy-vendor": "mkdir -p js/vendor && cp node_modules/chart.js/dist/chart.umd.min.js js/vendor/ && cp node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js js/vendor/ && cp node_modules/d3/dist/d3.min.js js/vendor/",
|
|
64
|
-
"generate-
|
|
63
|
+
"copy-vendor": "mkdir -p js/vendor && cp node_modules/chart.js/dist/chart.umd.min.js js/vendor/ && cp node_modules/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js js/vendor/ && cp node_modules/d3/dist/d3.min.js js/vendor/ && (test -f node_modules/mermaid/dist/mermaid.esm.min.mjs && cp node_modules/mermaid/dist/mermaid.esm.min.mjs js/vendor/ || echo 'mermaid vendor asset not installed; skipping')",
|
|
64
|
+
"generate-article": "node scripts/aggregator/article-generator.js",
|
|
65
|
+
"generate-article:all": "node scripts/aggregator/article-generator.js --all",
|
|
65
66
|
"generate-news-indexes": "node scripts/generators/news-indexes.js",
|
|
66
67
|
"generate-sitemap": "node scripts/generators/sitemap.js",
|
|
67
|
-
"fix-articles": "npx tsx src/utils/fix-articles.ts",
|
|
68
|
-
"retrofit-analysis": "npx tsx src/utils/retrofit-analysis-links.ts",
|
|
69
|
-
"validate-articles": "npx tsx src/utils/validate-articles.ts",
|
|
70
|
-
"validate-articles:strict": "npx tsx src/utils/validate-articles.ts --strict",
|
|
71
|
-
"validate-analysis": "npx tsx src/utils/validate-analysis-completeness.ts",
|
|
72
68
|
"validate-ep-api": "npx tsx src/utils/validate-ep-api.ts",
|
|
73
69
|
"lint:prompts": "node scripts/lint-prompts.js",
|
|
74
70
|
"htmlhint": "sh -c 'htmlhint *.html; set -- news/*.html; if [ -e \"$1\" ]; then htmlhint \"$@\"; else echo \"No news/*.html files to lint\"; fi'",
|
|
@@ -141,6 +137,7 @@
|
|
|
141
137
|
"@eslint/js": "10.0.1",
|
|
142
138
|
"@playwright/test": "1.59.1",
|
|
143
139
|
"@types/d3": "7.4.3",
|
|
140
|
+
"@types/markdown-it": "^14.1.2",
|
|
144
141
|
"@types/node": "25.6.0",
|
|
145
142
|
"@types/papaparse": "5.5.2",
|
|
146
143
|
"@typescript-eslint/eslint-plugin": "8.59.0",
|
|
@@ -172,7 +169,12 @@
|
|
|
172
169
|
"node": ">=25"
|
|
173
170
|
},
|
|
174
171
|
"dependencies": {
|
|
175
|
-
"european-parliament-mcp-server": "1.2.
|
|
172
|
+
"european-parliament-mcp-server": "1.2.13",
|
|
173
|
+
"markdown-it": "^14.1.1",
|
|
174
|
+
"markdown-it-anchor": "^9.2.0",
|
|
175
|
+
"markdown-it-attrs": "^4.3.1",
|
|
176
|
+
"markdown-it-deflist": "^3.0.0",
|
|
177
|
+
"markdown-it-footnote": "^4.0.0"
|
|
176
178
|
},
|
|
177
179
|
"optionalDependencies": {
|
|
178
180
|
"worldbank-mcp": "1.0.1"
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { type ArtifactSection } from './artifact-order.js';
|
|
2
|
+
/** Raw manifest shape as committed by the analysis pipeline. */
|
|
3
|
+
export interface AnalysisManifest {
|
|
4
|
+
readonly articleType: string;
|
|
5
|
+
readonly runId?: string;
|
|
6
|
+
readonly date?: string;
|
|
7
|
+
readonly analysisDir?: string;
|
|
8
|
+
readonly files?: ManifestFiles;
|
|
9
|
+
readonly history?: readonly ManifestHistoryEntry[];
|
|
10
|
+
}
|
|
11
|
+
/** `manifest.files` can be nested category → paths or flat path → description. */
|
|
12
|
+
export type ManifestFiles = Record<string, readonly string[] | Record<string, string>>;
|
|
13
|
+
/** One entry in `manifest.history[]`; only fields we read are typed. */
|
|
14
|
+
export interface ManifestHistoryEntry {
|
|
15
|
+
readonly stage?: string;
|
|
16
|
+
readonly completedAt?: string;
|
|
17
|
+
readonly startedAt?: string;
|
|
18
|
+
readonly finishedAt?: string;
|
|
19
|
+
readonly runId?: string;
|
|
20
|
+
readonly gateResult?: string;
|
|
21
|
+
readonly summary?: string;
|
|
22
|
+
readonly filesWritten?: readonly string[];
|
|
23
|
+
}
|
|
24
|
+
/** Result of {@link aggregateAnalysisRun}. */
|
|
25
|
+
export interface AggregatedRun {
|
|
26
|
+
/** Final Markdown document (provenance + sections + appendices). */
|
|
27
|
+
readonly markdown: string;
|
|
28
|
+
/** Repo-relative path of the run dir (e.g. `analysis/daily/2026-01-15/breaking-run1`). */
|
|
29
|
+
readonly runDirRelPath: string;
|
|
30
|
+
/** Article type slug from the manifest. */
|
|
31
|
+
readonly articleType: string;
|
|
32
|
+
/** ISO date string of the run (YYYY-MM-DD). */
|
|
33
|
+
readonly date: string;
|
|
34
|
+
/** List of every artifact included, in the order they appear. */
|
|
35
|
+
readonly includedArtifacts: readonly IncludedArtifact[];
|
|
36
|
+
/** Latest resolved gate result read from `manifest.history[]`. */
|
|
37
|
+
readonly gateResult: string;
|
|
38
|
+
/**
|
|
39
|
+
* Ordered list of top-level (H2) sections that were actually emitted into
|
|
40
|
+
* the aggregate — used by the HTML renderer to build the article
|
|
41
|
+
* table-of-contents sidebar. Includes canonical sections, the
|
|
42
|
+
* supplementary-intelligence bucket, the tradecraft-references appendix,
|
|
43
|
+
* and the analysis-index appendix, in document order.
|
|
44
|
+
*/
|
|
45
|
+
readonly sectionToc: readonly TocSection[];
|
|
46
|
+
}
|
|
47
|
+
/** One entry in the article-level table of contents (H2 level). */
|
|
48
|
+
export interface TocSection {
|
|
49
|
+
/** Fragment identifier — matches the `id="…"` on the rendered H2. */
|
|
50
|
+
readonly id: string;
|
|
51
|
+
/** Display title shown in the sidebar nav. */
|
|
52
|
+
readonly title: string;
|
|
53
|
+
}
|
|
54
|
+
/** Metadata for one artifact included in the aggregate. */
|
|
55
|
+
export interface IncludedArtifact {
|
|
56
|
+
/** Path relative to the run dir. */
|
|
57
|
+
readonly runRelPath: string;
|
|
58
|
+
/** Path relative to the repo root. */
|
|
59
|
+
readonly repoRelPath: string;
|
|
60
|
+
/** Id of the section this artifact belongs to. */
|
|
61
|
+
readonly sectionId: string;
|
|
62
|
+
}
|
|
63
|
+
/** Options for {@link aggregateAnalysisRun}. */
|
|
64
|
+
export interface AggregateOptions {
|
|
65
|
+
/** Absolute path to the analysis run directory. */
|
|
66
|
+
readonly runDir: string;
|
|
67
|
+
/** Absolute path to the repo root (used to build repo-relative paths). */
|
|
68
|
+
readonly repoRoot: string;
|
|
69
|
+
/**
|
|
70
|
+
* Optional: all methodology files and template files that should be
|
|
71
|
+
* listed in the tradecraft appendix. If omitted, the aggregator
|
|
72
|
+
* discovers them under `analysis/methodologies/*.md` +
|
|
73
|
+
* `analysis/templates/*.md`.
|
|
74
|
+
*/
|
|
75
|
+
readonly tradecraftFiles?: readonly string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Normalise `manifest.files` into a flat list of `runRelPath` strings.
|
|
79
|
+
*
|
|
80
|
+
* @param files - Manifest `files` section (nested or flat)
|
|
81
|
+
* @returns De-duplicated list of run-relative artifact paths
|
|
82
|
+
*/
|
|
83
|
+
export declare function flattenManifestFiles(files: ManifestFiles | undefined): string[];
|
|
84
|
+
/**
|
|
85
|
+
* Pick the latest non-PENDING gateResult from `manifest.history[]`, falling
|
|
86
|
+
* back to `PENDING` if none is recorded. Mirrors the behaviour of
|
|
87
|
+
* {@link readLatestResolvedGateResult} in `src/utils/file-utils.ts` but
|
|
88
|
+
* operates on an in-memory manifest.
|
|
89
|
+
*
|
|
90
|
+
* @param manifest - Parsed manifest object
|
|
91
|
+
* @returns The latest non-PENDING gate result, or `"PENDING"` when none found
|
|
92
|
+
*/
|
|
93
|
+
export declare function latestGateResult(manifest: AnalysisManifest): string;
|
|
94
|
+
/**
|
|
95
|
+
* Expand an `artifacts` entry from {@link ArtifactSection} into a list of
|
|
96
|
+
* concrete artifact paths. Exact paths are kept as-is; directory prefixes
|
|
97
|
+
* ending in `/` expand to every remaining `.md` under that directory
|
|
98
|
+
* (lexical order), excluding files already claimed by higher-priority
|
|
99
|
+
* sections.
|
|
100
|
+
*
|
|
101
|
+
* @param section - Canonical section descriptor from {@link ARTIFACT_SECTIONS}
|
|
102
|
+
* @param available - Set of every known artifact path (run-relative)
|
|
103
|
+
* @param consumed - Mutable set of paths already claimed by earlier sections
|
|
104
|
+
* @returns Ordered list of artifact paths that belong to this section
|
|
105
|
+
*/
|
|
106
|
+
export declare function expandSectionArtifacts(section: ArtifactSection, available: Set<string>, consumed: Set<string>): string[];
|
|
107
|
+
/**
|
|
108
|
+
* Discover tradecraft files (methodologies + templates) under a repo root.
|
|
109
|
+
* Returned paths are repo-relative with POSIX separators and sorted
|
|
110
|
+
* lexically.
|
|
111
|
+
*
|
|
112
|
+
* @param repoRoot - Absolute path of the repo root
|
|
113
|
+
* @returns Sorted list of `analysis/methodologies/*.md` + `analysis/templates/*.md`
|
|
114
|
+
*/
|
|
115
|
+
export declare function discoverTradecraftFiles(repoRoot: string): string[];
|
|
116
|
+
/**
|
|
117
|
+
* Render the provenance block shown at the very top of the aggregated
|
|
118
|
+
* document. Shows run metadata, gate result, and a direct link to the
|
|
119
|
+
* manifest on GitHub so the reader can audit the full artifact set.
|
|
120
|
+
*
|
|
121
|
+
* @param params - Provenance metadata for the aggregated run
|
|
122
|
+
* @param params.articleType - Article type slug (e.g. `breaking`)
|
|
123
|
+
* @param params.date - ISO date of the run (`YYYY-MM-DD`)
|
|
124
|
+
* @param params.runId - Stable identifier for the run
|
|
125
|
+
* @param params.gateResult - Latest non-PENDING gate result
|
|
126
|
+
* @param params.runDirRelPath - Repo-relative path of the run directory
|
|
127
|
+
* @param params.manifestRelPath - Repo-relative path of `manifest.json`
|
|
128
|
+
* @returns Markdown blockquote ready to be concatenated into the aggregate
|
|
129
|
+
*/
|
|
130
|
+
export declare function renderProvenanceBlock(params: {
|
|
131
|
+
articleType: string;
|
|
132
|
+
date: string;
|
|
133
|
+
runId: string;
|
|
134
|
+
gateResult: string;
|
|
135
|
+
runDirRelPath: string;
|
|
136
|
+
manifestRelPath: string;
|
|
137
|
+
}): string;
|
|
138
|
+
/**
|
|
139
|
+
* Render the tradecraft-references appendix — one bullet per
|
|
140
|
+
* methodology/template file with a GitHub blob link.
|
|
141
|
+
*
|
|
142
|
+
* @param files - Repo-relative paths under `analysis/methodologies/` and
|
|
143
|
+
* `analysis/templates/`
|
|
144
|
+
* @returns Markdown block with two subsections (methodologies, templates)
|
|
145
|
+
*/
|
|
146
|
+
export declare function renderTradecraftAppendix(files: readonly string[]): string;
|
|
147
|
+
/**
|
|
148
|
+
* Render the analysis-index appendix — a compact table of every included
|
|
149
|
+
* artifact and its section, plus a direct link to the manifest.
|
|
150
|
+
*
|
|
151
|
+
* @param included - Artifacts that contributed to the aggregated document
|
|
152
|
+
* @param manifestRelPath - Repo-relative path of `manifest.json`
|
|
153
|
+
* @returns Markdown block with the index table
|
|
154
|
+
*/
|
|
155
|
+
export declare function renderAnalysisIndex(included: readonly IncludedArtifact[], manifestRelPath: string): string;
|
|
156
|
+
/**
|
|
157
|
+
* Read, clean, and concatenate every artifact declared by the run's manifest
|
|
158
|
+
* (with discovery fallback when manifest.files is missing), returning a
|
|
159
|
+
* single aggregated Markdown document.
|
|
160
|
+
*
|
|
161
|
+
* The function is deterministic: given the same inputs it produces the
|
|
162
|
+
* same output byte-for-byte.
|
|
163
|
+
*
|
|
164
|
+
* @param options - Aggregation options (run dir, repo root, tradecraft files)
|
|
165
|
+
* @returns {@link AggregatedRun} describing the rendered document
|
|
166
|
+
*/
|
|
167
|
+
export declare function aggregateAnalysisRun(options: AggregateOptions): AggregatedRun;
|
|
168
|
+
//# sourceMappingURL=analysis-aggregator.d.ts.map
|