euparliamentmonitor 0.8.40 โ 0.8.42
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 +23 -5
- package/package.json +6 -5
- 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/news-enhanced.js +81 -40
- package/scripts/generators/pipeline/analysis-stage.d.ts +89 -0
- package/scripts/generators/pipeline/analysis-stage.js +259 -30
- package/scripts/generators/pipeline/fetch-stage.d.ts +1 -1
- package/scripts/generators/pipeline/fetch-stage.js +6 -6
- package/scripts/generators/political-intelligence-descriptions.d.ts +139 -0
- package/scripts/generators/political-intelligence-descriptions.js +2068 -0
- package/scripts/generators/political-intelligence.d.ts +118 -0
- package/scripts/generators/political-intelligence.js +1146 -0
- package/scripts/generators/sitemap.d.ts +13 -0
- package/scripts/generators/sitemap.js +616 -127
- package/scripts/index.d.ts +1 -1
- package/scripts/index.js +1 -1
- package/scripts/lint-prompts.js +218 -0
- package/scripts/mcp/ep-mcp-client.d.ts +20 -8
- package/scripts/mcp/ep-mcp-client.js +88 -13
- package/scripts/templates/section-builders.js +5 -3
- package/scripts/types/mcp.d.ts +14 -14
- package/scripts/utils/content-validator.d.ts +19 -3
- package/scripts/utils/content-validator.js +19 -3
- package/scripts/utils/file-utils.d.ts +54 -0
- package/scripts/utils/file-utils.js +86 -0
- package/scripts/utils/fix-articles.js +7 -57
- package/scripts/utils/world-bank-data.d.ts +67 -2
- package/scripts/utils/world-bank-data.js +105 -2
package/README.md
CHANGED
|
@@ -115,6 +115,13 @@ import {
|
|
|
115
115
|
- [๐ API Documentation](https://euparliamentmonitor.com/docs/api/index.html) - TypeDoc-generated API reference
|
|
116
116
|
- [๐ Test Coverage](https://euparliamentmonitor.com/docs/coverage/index.html) - Interactive coverage report
|
|
117
117
|
|
|
118
|
+
**๐ค Agentic Pipeline:**
|
|
119
|
+
- [Agent Catalog](.github/agents/README.md) โ custom Copilot agents (analysis producers / consumers / gh-aw infrastructure)
|
|
120
|
+
- [Skills Library](.github/skills/README.md) โ shared skills (security, compliance, intelligence, gh-aw)
|
|
121
|
+
- [Prompt Library](.github/prompts/README.md) โ 10-file bounded-context prompt set (`00`โ`09`) + `npm run lint:prompts` drift-guard
|
|
122
|
+
- [Workflows](.github/workflows/README.md) + [WORKFLOWS.md](WORKFLOWS.md) โ 10 `news-*.md` agentic workflows + CI workflows
|
|
123
|
+
- [Analysis Chain](analysis/README.md) โ 5-stage pipeline (Data โ Analysis โ Completeness Gate โ Article โ Single PR), methodologies, 39 templates, quality thresholds
|
|
124
|
+
|
|
118
125
|
**๐ ISMS Compliance:**
|
|
119
126
|
- [๐ก๏ธ Hack23 ISMS Framework](https://github.com/Hack23/ISMS-PUBLIC) - Information Security Management System
|
|
120
127
|
- [๐ Secure Development Policy](https://github.com/Hack23/ISMS-PUBLIC/blob/main/Secure_Development_Policy.md) - Development standards
|
|
@@ -124,12 +131,17 @@ import {
|
|
|
124
131
|
|
|
125
132
|
**MCP Server Integration**: The project uses the
|
|
126
133
|
[European-Parliament-MCP-Server](https://github.com/Hack23/European-Parliament-MCP-Server)
|
|
127
|
-
v1.2.
|
|
134
|
+
v1.2.13 for accessing real EU Parliament data via the Model Context Protocol.
|
|
128
135
|
|
|
129
136
|
- **MCP Server Status**: โ
Fully operational โ 60+ EP data tools available
|
|
130
137
|
(feeds, direct lookups, analytical tools, intelligence correlation)
|
|
131
|
-
- **Agentic Workflows**:
|
|
132
|
-
generation with AI-driven political
|
|
138
|
+
- **Agentic Workflows**: 18 gh-aw markdown workflows โ 8 split-pair article types (`news-<type>-analysis.md` + `news-<type>-article.md`) + `news-article-generator.md` + `news-translate.md` (compiled with
|
|
139
|
+
`gh-aw v0.69.3`) for automated news generation with AI-driven political
|
|
140
|
+
intelligence analysis. See [`.github/workflows/README.md`](.github/workflows/README.md).
|
|
141
|
+
- **Analysis Chain**: 5-stage pipeline (Data โ Analysis โ Completeness Gate โ
|
|
142
|
+
Article โ Single PR) producing 39 structured analysis templates per run.
|
|
143
|
+
See [`analysis/README.md`](analysis/README.md) and
|
|
144
|
+
[`analysis/methodologies/ai-driven-analysis-guide.md`](analysis/methodologies/ai-driven-analysis-guide.md).
|
|
133
145
|
- **Fallback Mode**: News generation can work with reduced data when EP API
|
|
134
146
|
endpoints are temporarily unavailable
|
|
135
147
|
- **Environment Variable**: Set `USE_EP_MCP=false` to disable MCP client
|
|
@@ -467,7 +479,9 @@ npm run generate-news -- --types=week-ahead --languages=all
|
|
|
467
479
|
# Generate language-specific index pages
|
|
468
480
|
npm run generate-news-indexes
|
|
469
481
|
|
|
470
|
-
# Generate sitemap.xml
|
|
482
|
+
# Generate sitemap.xml, sitemap_<lang>.html, and political-intelligence_<lang>.html
|
|
483
|
+
# (14 language-specific sitemap pages + 14 language-specific Political Intelligence
|
|
484
|
+
# pages that index every methodology, template, and daily analysis run)
|
|
471
485
|
npm run generate-sitemap
|
|
472
486
|
```
|
|
473
487
|
|
|
@@ -511,7 +525,11 @@ euparliamentmonitor/
|
|
|
511
525
|
โโโ index-{lang}.html # Language-specific index pages
|
|
512
526
|
โโโ typedoc.json # TypeDoc configuration
|
|
513
527
|
โโโ tsconfig.json # TypeScript configuration
|
|
514
|
-
โโโ sitemap.xml # SEO sitemap
|
|
528
|
+
โโโ sitemap.xml # SEO sitemap with hreflang alternates
|
|
529
|
+
โโโ sitemap.html # Human-readable sitemap (English)
|
|
530
|
+
โโโ sitemap_{lang}.html # Per-language human-readable sitemaps
|
|
531
|
+
โโโ political-intelligence.html # Index of every methodology + template + daily analysis run
|
|
532
|
+
โโโ political-intelligence_{lang}.html # Localized political-intelligence pages
|
|
515
533
|
โโโ package.json # Project dependencies
|
|
516
534
|
```
|
|
517
535
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "euparliamentmonitor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.42",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "European Parliament Intelligence Platform - Monitor political activity with systematic transparency",
|
|
6
6
|
"main": "scripts/index.js",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"validate-articles:strict": "npx tsx src/utils/validate-articles.ts --strict",
|
|
71
71
|
"validate-analysis": "npx tsx src/utils/validate-analysis-completeness.ts",
|
|
72
72
|
"validate-ep-api": "npx tsx src/utils/validate-ep-api.ts",
|
|
73
|
+
"lint:prompts": "node scripts/lint-prompts.js",
|
|
73
74
|
"htmlhint": "sh -c 'htmlhint *.html; set -- news/*.html; if [ -e \"$1\" ]; then htmlhint \"$@\"; else echo \"No news/*.html files to lint\"; fi'",
|
|
74
75
|
"serve": "python3 -m http.server 8080",
|
|
75
76
|
"test": "vitest run",
|
|
@@ -144,8 +145,8 @@
|
|
|
144
145
|
"@types/papaparse": "5.5.2",
|
|
145
146
|
"@typescript-eslint/eslint-plugin": "8.59.0",
|
|
146
147
|
"@typescript-eslint/parser": "8.59.0",
|
|
147
|
-
"@vitest/coverage-v8": "4.1.
|
|
148
|
-
"@vitest/ui": "4.1.
|
|
148
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
149
|
+
"@vitest/ui": "4.1.5",
|
|
149
150
|
"chart.js": "4.5.1",
|
|
150
151
|
"chartjs-plugin-annotation": "3.1.0",
|
|
151
152
|
"d3": "7.9.0",
|
|
@@ -165,13 +166,13 @@
|
|
|
165
166
|
"tsx": "4.21.0",
|
|
166
167
|
"typedoc": "0.28.19",
|
|
167
168
|
"typescript": "6.0.3",
|
|
168
|
-
"vitest": "4.1.
|
|
169
|
+
"vitest": "4.1.5"
|
|
169
170
|
},
|
|
170
171
|
"engines": {
|
|
171
172
|
"node": ">=25"
|
|
172
173
|
},
|
|
173
174
|
"dependencies": {
|
|
174
|
-
"european-parliament-mcp-server": "1.2.
|
|
175
|
+
"european-parliament-mcp-server": "1.2.13"
|
|
175
176
|
},
|
|
176
177
|
"optionalDependencies": {
|
|
177
178
|
"worldbank-mcp": "1.0.1"
|
|
@@ -191,4 +191,6 @@ export declare const FOOTER_DISCLAIMER_LABELS: LanguageMap;
|
|
|
191
191
|
export declare const FOOTER_REPORT_ISSUES_LABELS: LanguageMap;
|
|
192
192
|
/** Localized "{count} articles available" stats text used in footer About section */
|
|
193
193
|
export declare const FOOTER_ARTICLES_AVAILABLE_LABELS: LanguageMap;
|
|
194
|
+
/** Localized "Political Intelligence" link label used in footer Quick Links section */
|
|
195
|
+
export declare const FOOTER_POLITICAL_INTELLIGENCE_LABELS: LanguageMap;
|
|
194
196
|
//# sourceMappingURL=language-ui.d.ts.map
|
|
@@ -1849,4 +1849,21 @@ export const FOOTER_ARTICLES_AVAILABLE_LABELS = {
|
|
|
1849
1849
|
ko: '{count}๊ฐ ๊ธฐ์ฌ ์ด์ฉ ๊ฐ๋ฅ',
|
|
1850
1850
|
zh: '{count}็ฏๆ็ซ ๅฏ็จ',
|
|
1851
1851
|
};
|
|
1852
|
+
/** Localized "Political Intelligence" link label used in footer Quick Links section */
|
|
1853
|
+
export const FOOTER_POLITICAL_INTELLIGENCE_LABELS = {
|
|
1854
|
+
en: 'Political Intelligence',
|
|
1855
|
+
sv: 'Politisk underrรคttelse',
|
|
1856
|
+
da: 'Politisk efterretning',
|
|
1857
|
+
no: 'Politisk etterretning',
|
|
1858
|
+
fi: 'Poliittinen tiedustelu',
|
|
1859
|
+
de: 'Politische Aufklรคrung',
|
|
1860
|
+
fr: 'Intelligence politique',
|
|
1861
|
+
es: 'Inteligencia polรญtica',
|
|
1862
|
+
nl: 'Politieke intelligentie',
|
|
1863
|
+
ar: 'ุงูุงุณุชุฎุจุงุฑุงุช ุงูุณูุงุณูุฉ',
|
|
1864
|
+
he: 'ืืืืืขืื ืคืืืืื',
|
|
1865
|
+
ja: 'ๆฟๆฒปใคใณใใชใธใงใณใน',
|
|
1866
|
+
ko: '์ ์น ์ ๋ณด',
|
|
1867
|
+
zh: 'ๆฟๆฒปๆ
ๆฅ',
|
|
1868
|
+
};
|
|
1852
1869
|
//# sourceMappingURL=language-ui.js.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - **language-articles** โ Article-type title generators and body-text strings
|
|
9
9
|
*/
|
|
10
10
|
export { ALL_LANGUAGES, LANGUAGE_PRESETS, LANGUAGE_FLAGS, LANGUAGE_NAMES, getLocalizedString, isSupportedLanguage, getTextDirection, } from './language-core.js';
|
|
11
|
-
export { PAGE_TITLES, PAGE_DESCRIPTIONS, SECTION_HEADINGS, NO_ARTICLES_MESSAGES, SKIP_LINK_TEXTS, ARTICLE_TYPE_LABELS, READ_TIME_LABELS, BACK_TO_NEWS_LABELS, ARTICLE_NAV_LABELS, RELATED_ARTICLES_NAV_LABELS, BREADCRUMB_HOME_LABELS, BREADCRUMB_NEWS_LABELS, TIMELINE_HEADINGS, COMPARISON_BEFORE_LABELS, COMPARISON_AFTER_LABELS, KEY_FIGURES_HEADINGS, AI_SECTION_CONTENT, FILTER_LABELS, SOURCES_HEADING_LABELS, HEADER_SUBTITLE_LABELS, THEME_TOGGLE_LABELS, FOOTER_ABOUT_HEADING_LABELS, FOOTER_ABOUT_TEXT_LABELS, FOOTER_QUICK_LINKS_LABELS, FOOTER_BUILT_BY_LABELS, FOOTER_LANGUAGES_LABELS, FOOTER_HOME_LABELS, FOOTER_SITEMAP_LABELS, FOOTER_RSS_LABELS, FOOTER_GITHUB_REPO_LABELS, FOOTER_LICENSE_LABELS, FOOTER_EUROPARL_LABELS, FOOTER_LINKEDIN_LABELS, FOOTER_SECURITY_POLICY_LABELS, FOOTER_CONTACT_LABELS, FOOTER_DISCLAIMER_LABELS, FOOTER_REPORT_ISSUES_LABELS, FOOTER_ARTICLES_AVAILABLE_LABELS, TOC_ARIA_LABELS, RELATED_ANALYSIS_LABELS, ANALYSIS_TRANSPARENCY_LABELS, ANALYSIS_SUMMARY_LABELS, METHODOLOGY_LABELS, TRANSPARENCY_DISCLOSURE_LABELS, CLASSIFICATION_ANALYSIS_LABELS, THREAT_ASSESSMENT_LABELS, RISK_SCORING_LABELS, DEEP_ANALYSIS_LABELS, VIEW_SOURCE_LABELS, OPEN_SOURCE_NOTE_LABELS, AI_ANALYSIS_GUIDE_LABELS, SWOT_FRAMEWORK_LABELS, RISK_METHODOLOGY_LABELS, THREAT_FRAMEWORK_LABELS, CLASSIFICATION_GUIDE_LABELS, STYLE_GUIDE_LABELS, SIGNIFICANCE_CLASSIFICATION_LABELS, ACTOR_MAPPING_LABELS, FORCES_ANALYSIS_LABELS, IMPACT_MATRIX_LABELS, POLITICAL_THREAT_LANDSCAPE_LABELS, ACTOR_THREAT_PROFILING_LABELS, CONSEQUENCE_TREES_LABELS, LEGISLATIVE_DISRUPTION_LABELS, RISK_MATRIX_LABELS, QUANTITATIVE_SWOT_LABELS, POLITICAL_CAPITAL_RISK_LABELS, LEGISLATIVE_VELOCITY_RISK_LABELS, AGENT_RISK_WORKFLOW_LABELS, STAKEHOLDER_IMPACT_LABELS, COALITION_DYNAMICS_LABELS, VOTING_PATTERNS_LABELS, CROSS_SESSION_INTELLIGENCE_LABELS, SYNTHESIS_SUMMARY_LABELS, DOCUMENT_ANALYSIS_LABELS, SIGNIFICANCE_SCORING_LABELS, } from './language-ui.js';
|
|
11
|
+
export { PAGE_TITLES, PAGE_DESCRIPTIONS, SECTION_HEADINGS, NO_ARTICLES_MESSAGES, SKIP_LINK_TEXTS, ARTICLE_TYPE_LABELS, READ_TIME_LABELS, BACK_TO_NEWS_LABELS, ARTICLE_NAV_LABELS, RELATED_ARTICLES_NAV_LABELS, BREADCRUMB_HOME_LABELS, BREADCRUMB_NEWS_LABELS, TIMELINE_HEADINGS, COMPARISON_BEFORE_LABELS, COMPARISON_AFTER_LABELS, KEY_FIGURES_HEADINGS, AI_SECTION_CONTENT, FILTER_LABELS, SOURCES_HEADING_LABELS, HEADER_SUBTITLE_LABELS, THEME_TOGGLE_LABELS, FOOTER_ABOUT_HEADING_LABELS, FOOTER_ABOUT_TEXT_LABELS, FOOTER_QUICK_LINKS_LABELS, FOOTER_BUILT_BY_LABELS, FOOTER_LANGUAGES_LABELS, FOOTER_HOME_LABELS, FOOTER_SITEMAP_LABELS, FOOTER_RSS_LABELS, FOOTER_GITHUB_REPO_LABELS, FOOTER_LICENSE_LABELS, FOOTER_EUROPARL_LABELS, FOOTER_LINKEDIN_LABELS, FOOTER_SECURITY_POLICY_LABELS, FOOTER_CONTACT_LABELS, FOOTER_DISCLAIMER_LABELS, FOOTER_REPORT_ISSUES_LABELS, FOOTER_ARTICLES_AVAILABLE_LABELS, FOOTER_POLITICAL_INTELLIGENCE_LABELS, TOC_ARIA_LABELS, RELATED_ANALYSIS_LABELS, ANALYSIS_TRANSPARENCY_LABELS, ANALYSIS_SUMMARY_LABELS, METHODOLOGY_LABELS, TRANSPARENCY_DISCLOSURE_LABELS, CLASSIFICATION_ANALYSIS_LABELS, THREAT_ASSESSMENT_LABELS, RISK_SCORING_LABELS, DEEP_ANALYSIS_LABELS, VIEW_SOURCE_LABELS, OPEN_SOURCE_NOTE_LABELS, AI_ANALYSIS_GUIDE_LABELS, SWOT_FRAMEWORK_LABELS, RISK_METHODOLOGY_LABELS, THREAT_FRAMEWORK_LABELS, CLASSIFICATION_GUIDE_LABELS, STYLE_GUIDE_LABELS, SIGNIFICANCE_CLASSIFICATION_LABELS, ACTOR_MAPPING_LABELS, FORCES_ANALYSIS_LABELS, IMPACT_MATRIX_LABELS, POLITICAL_THREAT_LANDSCAPE_LABELS, ACTOR_THREAT_PROFILING_LABELS, CONSEQUENCE_TREES_LABELS, LEGISLATIVE_DISRUPTION_LABELS, RISK_MATRIX_LABELS, QUANTITATIVE_SWOT_LABELS, POLITICAL_CAPITAL_RISK_LABELS, LEGISLATIVE_VELOCITY_RISK_LABELS, AGENT_RISK_WORKFLOW_LABELS, STAKEHOLDER_IMPACT_LABELS, COALITION_DYNAMICS_LABELS, VOTING_PATTERNS_LABELS, CROSS_SESSION_INTELLIGENCE_LABELS, SYNTHESIS_SUMMARY_LABELS, DOCUMENT_ANALYSIS_LABELS, SIGNIFICANCE_SCORING_LABELS, } from './language-ui.js';
|
|
12
12
|
export type { AISection, RelationshipLabels, RelatedAnalysisStrings } from './language-ui.js';
|
|
13
13
|
export { WEEK_AHEAD_TITLES, MONTH_AHEAD_TITLES, WEEKLY_REVIEW_TITLES, MONTHLY_REVIEW_TITLES, MOTIONS_TITLES, BREAKING_NEWS_TITLES, COMMITTEE_REPORTS_TITLES, PROPOSITIONS_TITLES, PROPOSITIONS_STRINGS, EDITORIAL_STRINGS, MOTIONS_STRINGS, WEEK_AHEAD_STRINGS, WEEK_AHEAD_STAKEHOLDER_STRINGS, BREAKING_STRINGS, DEEP_ANALYSIS_STRINGS, COMMITTEE_ANALYSIS_CONTENT_STRINGS, SWOT_STRINGS, DASHBOARD_STRINGS, SWOT_BUILDER_STRINGS, DASHBOARD_BUILDER_STRINGS, LOCALIZED_KEYWORDS, MONTH_IN_REVIEW_STRINGS, ANALYSIS_QUALITY_LABELS, ANALYSIS_INSIGHTS_HEADING, } from './language-articles.js';
|
|
14
14
|
//# sourceMappingURL=languages.d.ts.map
|
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
* - **language-articles** โ Article-type title generators and body-text strings
|
|
11
11
|
*/
|
|
12
12
|
export { ALL_LANGUAGES, LANGUAGE_PRESETS, LANGUAGE_FLAGS, LANGUAGE_NAMES, getLocalizedString, isSupportedLanguage, getTextDirection, } from './language-core.js';
|
|
13
|
-
export { PAGE_TITLES, PAGE_DESCRIPTIONS, SECTION_HEADINGS, NO_ARTICLES_MESSAGES, SKIP_LINK_TEXTS, ARTICLE_TYPE_LABELS, READ_TIME_LABELS, BACK_TO_NEWS_LABELS, ARTICLE_NAV_LABELS, RELATED_ARTICLES_NAV_LABELS, BREADCRUMB_HOME_LABELS, BREADCRUMB_NEWS_LABELS, TIMELINE_HEADINGS, COMPARISON_BEFORE_LABELS, COMPARISON_AFTER_LABELS, KEY_FIGURES_HEADINGS, AI_SECTION_CONTENT, FILTER_LABELS, SOURCES_HEADING_LABELS, HEADER_SUBTITLE_LABELS, THEME_TOGGLE_LABELS, FOOTER_ABOUT_HEADING_LABELS, FOOTER_ABOUT_TEXT_LABELS, FOOTER_QUICK_LINKS_LABELS, FOOTER_BUILT_BY_LABELS, FOOTER_LANGUAGES_LABELS, FOOTER_HOME_LABELS, FOOTER_SITEMAP_LABELS, FOOTER_RSS_LABELS, FOOTER_GITHUB_REPO_LABELS, FOOTER_LICENSE_LABELS, FOOTER_EUROPARL_LABELS, FOOTER_LINKEDIN_LABELS, FOOTER_SECURITY_POLICY_LABELS, FOOTER_CONTACT_LABELS, FOOTER_DISCLAIMER_LABELS, FOOTER_REPORT_ISSUES_LABELS, FOOTER_ARTICLES_AVAILABLE_LABELS, TOC_ARIA_LABELS, RELATED_ANALYSIS_LABELS, ANALYSIS_TRANSPARENCY_LABELS, ANALYSIS_SUMMARY_LABELS, METHODOLOGY_LABELS, TRANSPARENCY_DISCLOSURE_LABELS, CLASSIFICATION_ANALYSIS_LABELS, THREAT_ASSESSMENT_LABELS, RISK_SCORING_LABELS, DEEP_ANALYSIS_LABELS, VIEW_SOURCE_LABELS, OPEN_SOURCE_NOTE_LABELS, AI_ANALYSIS_GUIDE_LABELS, SWOT_FRAMEWORK_LABELS, RISK_METHODOLOGY_LABELS, THREAT_FRAMEWORK_LABELS, CLASSIFICATION_GUIDE_LABELS, STYLE_GUIDE_LABELS, SIGNIFICANCE_CLASSIFICATION_LABELS, ACTOR_MAPPING_LABELS, FORCES_ANALYSIS_LABELS, IMPACT_MATRIX_LABELS, POLITICAL_THREAT_LANDSCAPE_LABELS, ACTOR_THREAT_PROFILING_LABELS, CONSEQUENCE_TREES_LABELS, LEGISLATIVE_DISRUPTION_LABELS, RISK_MATRIX_LABELS, QUANTITATIVE_SWOT_LABELS, POLITICAL_CAPITAL_RISK_LABELS, LEGISLATIVE_VELOCITY_RISK_LABELS, AGENT_RISK_WORKFLOW_LABELS, STAKEHOLDER_IMPACT_LABELS, COALITION_DYNAMICS_LABELS, VOTING_PATTERNS_LABELS, CROSS_SESSION_INTELLIGENCE_LABELS, SYNTHESIS_SUMMARY_LABELS, DOCUMENT_ANALYSIS_LABELS, SIGNIFICANCE_SCORING_LABELS, } from './language-ui.js';
|
|
13
|
+
export { PAGE_TITLES, PAGE_DESCRIPTIONS, SECTION_HEADINGS, NO_ARTICLES_MESSAGES, SKIP_LINK_TEXTS, ARTICLE_TYPE_LABELS, READ_TIME_LABELS, BACK_TO_NEWS_LABELS, ARTICLE_NAV_LABELS, RELATED_ARTICLES_NAV_LABELS, BREADCRUMB_HOME_LABELS, BREADCRUMB_NEWS_LABELS, TIMELINE_HEADINGS, COMPARISON_BEFORE_LABELS, COMPARISON_AFTER_LABELS, KEY_FIGURES_HEADINGS, AI_SECTION_CONTENT, FILTER_LABELS, SOURCES_HEADING_LABELS, HEADER_SUBTITLE_LABELS, THEME_TOGGLE_LABELS, FOOTER_ABOUT_HEADING_LABELS, FOOTER_ABOUT_TEXT_LABELS, FOOTER_QUICK_LINKS_LABELS, FOOTER_BUILT_BY_LABELS, FOOTER_LANGUAGES_LABELS, FOOTER_HOME_LABELS, FOOTER_SITEMAP_LABELS, FOOTER_RSS_LABELS, FOOTER_GITHUB_REPO_LABELS, FOOTER_LICENSE_LABELS, FOOTER_EUROPARL_LABELS, FOOTER_LINKEDIN_LABELS, FOOTER_SECURITY_POLICY_LABELS, FOOTER_CONTACT_LABELS, FOOTER_DISCLAIMER_LABELS, FOOTER_REPORT_ISSUES_LABELS, FOOTER_ARTICLES_AVAILABLE_LABELS, FOOTER_POLITICAL_INTELLIGENCE_LABELS, TOC_ARIA_LABELS, RELATED_ANALYSIS_LABELS, ANALYSIS_TRANSPARENCY_LABELS, ANALYSIS_SUMMARY_LABELS, METHODOLOGY_LABELS, TRANSPARENCY_DISCLOSURE_LABELS, CLASSIFICATION_ANALYSIS_LABELS, THREAT_ASSESSMENT_LABELS, RISK_SCORING_LABELS, DEEP_ANALYSIS_LABELS, VIEW_SOURCE_LABELS, OPEN_SOURCE_NOTE_LABELS, AI_ANALYSIS_GUIDE_LABELS, SWOT_FRAMEWORK_LABELS, RISK_METHODOLOGY_LABELS, THREAT_FRAMEWORK_LABELS, CLASSIFICATION_GUIDE_LABELS, STYLE_GUIDE_LABELS, SIGNIFICANCE_CLASSIFICATION_LABELS, ACTOR_MAPPING_LABELS, FORCES_ANALYSIS_LABELS, IMPACT_MATRIX_LABELS, POLITICAL_THREAT_LANDSCAPE_LABELS, ACTOR_THREAT_PROFILING_LABELS, CONSEQUENCE_TREES_LABELS, LEGISLATIVE_DISRUPTION_LABELS, RISK_MATRIX_LABELS, QUANTITATIVE_SWOT_LABELS, POLITICAL_CAPITAL_RISK_LABELS, LEGISLATIVE_VELOCITY_RISK_LABELS, AGENT_RISK_WORKFLOW_LABELS, STAKEHOLDER_IMPACT_LABELS, COALITION_DYNAMICS_LABELS, VOTING_PATTERNS_LABELS, CROSS_SESSION_INTELLIGENCE_LABELS, SYNTHESIS_SUMMARY_LABELS, DOCUMENT_ANALYSIS_LABELS, SIGNIFICANCE_SCORING_LABELS, } from './language-ui.js';
|
|
14
14
|
export { WEEK_AHEAD_TITLES, MONTH_AHEAD_TITLES, WEEKLY_REVIEW_TITLES, MONTHLY_REVIEW_TITLES, MOTIONS_TITLES, BREAKING_NEWS_TITLES, COMMITTEE_REPORTS_TITLES, PROPOSITIONS_TITLES, PROPOSITIONS_STRINGS, EDITORIAL_STRINGS, MOTIONS_STRINGS, WEEK_AHEAD_STRINGS, WEEK_AHEAD_STAKEHOLDER_STRINGS, BREAKING_STRINGS, DEEP_ANALYSIS_STRINGS, COMMITTEE_ANALYSIS_CONTENT_STRINGS, SWOT_STRINGS, DASHBOARD_STRINGS, SWOT_BUILDER_STRINGS, DASHBOARD_BUILDER_STRINGS, LOCALIZED_KEYWORDS, MONTH_IN_REVIEW_STRINGS, ANALYSIS_QUALITY_LABELS, ANALYSIS_INSIGHTS_HEADING, } from './language-articles.js';
|
|
15
15
|
//# sourceMappingURL=languages.js.map
|
|
@@ -49,7 +49,7 @@ import { ensureDirectoryExists } from '../utils/file-utils.js';
|
|
|
49
49
|
import { initializeMCPClient, fetchEPFeedData } from './pipeline/fetch-stage.js';
|
|
50
50
|
import { createStrategyRegistry, generateArticleForStrategy, setAIMetadata, } from './pipeline/generate-stage.js';
|
|
51
51
|
import { writeGenerationMetadata } from './pipeline/output-stage.js';
|
|
52
|
-
import { runAnalysisStage, ALL_ANALYSIS_METHODS, VALID_ANALYSIS_METHODS, hasSubstantiveData, deriveArticleTypeSlug, } from './pipeline/analysis-stage.js';
|
|
52
|
+
import { runAnalysisStage, ALL_ANALYSIS_METHODS, VALID_ANALYSIS_METHODS, hasSubstantiveData, deriveArticleTypeSlug, isResolvedAnalysisDir, } from './pipeline/analysis-stage.js';
|
|
53
53
|
import { discoverAnalysisFileEntries } from '../utils/file-utils.js';
|
|
54
54
|
// โโโ Content-module imports (bounded contexts) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
55
55
|
import { parsePlenarySessions, parseEPEvents, parseCommitteeMeetings, parseLegislativeDocuments, parseLegislativePipeline, parseParliamentaryQuestions, buildWeekAheadContent, buildKeywords, PLACEHOLDER_EVENTS, buildWhatToWatchSection, buildStakeholderImpactMatrix, computeWeekPoliticalTemperature, } from './week-ahead-content.js';
|
|
@@ -208,6 +208,56 @@ function parseAnalysisMethods() {
|
|
|
208
208
|
}
|
|
209
209
|
return methods;
|
|
210
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetch EP feed data (month-level timeframe for month-level article types,
|
|
213
|
+
* one-week otherwise), populate `fetchedData` with the result, and enforce
|
|
214
|
+
* the "substantive data required" check.
|
|
215
|
+
*
|
|
216
|
+
* Extracted from {@link maybeRunAnalysis} to keep that function's cognitive
|
|
217
|
+
* complexity under the repo's SonarJS limit. Mutates `fetchedData` in place
|
|
218
|
+
* and throws when no substantive EP data is available.
|
|
219
|
+
*
|
|
220
|
+
* @param fetchedData - Target record to populate (mutated)
|
|
221
|
+
* @param client - Connected MCP client or null
|
|
222
|
+
* @param articleTypes - Requested article types (drives timeframe selection)
|
|
223
|
+
*/
|
|
224
|
+
async function fetchAndValidateEPData(fetchedData, client, articleTypes) {
|
|
225
|
+
const MONTH_LEVEL_TYPES = ['month-ahead', 'month-in-review', 'committee-reports', 'motions'];
|
|
226
|
+
const needsMonthData = articleTypes
|
|
227
|
+
.map((t) => t.trim())
|
|
228
|
+
.some((t) => MONTH_LEVEL_TYPES.includes(t));
|
|
229
|
+
const feedTimeframe = needsMonthData ? 'one-month' : 'one-week';
|
|
230
|
+
// fetchEPFeedData handles a null client gracefully (returns undefined) and
|
|
231
|
+
// also loads from EP_FEED_DATA_FILE when set, so we call it unconditionally.
|
|
232
|
+
const feedData = await fetchEPFeedData(client, feedTimeframe);
|
|
233
|
+
if (feedData) {
|
|
234
|
+
fetchedData['events'] = feedData.events ?? [];
|
|
235
|
+
fetchedData['documents'] = feedData.documents ?? [];
|
|
236
|
+
fetchedData['adoptedTexts'] = feedData.adoptedTexts ?? [];
|
|
237
|
+
fetchedData['procedures'] = feedData.procedures ?? [];
|
|
238
|
+
fetchedData['mepUpdates'] = feedData.mepUpdates ?? [];
|
|
239
|
+
fetchedData['plenaryDocuments'] = feedData.plenaryDocuments ?? [];
|
|
240
|
+
fetchedData['committeeDocuments'] = feedData.committeeDocuments ?? [];
|
|
241
|
+
fetchedData['plenarySessionDocuments'] = feedData.plenarySessionDocuments ?? [];
|
|
242
|
+
fetchedData['externalDocuments'] = feedData.externalDocuments ?? [];
|
|
243
|
+
fetchedData['questions'] = feedData.questions ?? [];
|
|
244
|
+
fetchedData['declarations'] = feedData.declarations ?? [];
|
|
245
|
+
fetchedData['corporateBodies'] = feedData.corporateBodies ?? [];
|
|
246
|
+
}
|
|
247
|
+
if (!fetchedData['events']) {
|
|
248
|
+
// No MCP or feed-data file available โ populate empty arrays so builders don't fail
|
|
249
|
+
fetchedData['events'] = [];
|
|
250
|
+
fetchedData['sessions'] = [];
|
|
251
|
+
fetchedData['documents'] = [];
|
|
252
|
+
}
|
|
253
|
+
// Agentic workflows must not proceed with empty data โ analysis on empty
|
|
254
|
+
// data produces hollow output that should never feed article generation.
|
|
255
|
+
if (!hasSubstantiveData(fetchedData)) {
|
|
256
|
+
throw new Error('โ Analysis aborted: no substantive EP data was fetched. ' +
|
|
257
|
+
'MCP data fetch must succeed before analysis can run. ' +
|
|
258
|
+
'Check MCP connection, feed data file, or EP API availability.');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
211
261
|
/**
|
|
212
262
|
* Run the analysis discovery stage (Fetch โ Discover) before article generation.
|
|
213
263
|
*
|
|
@@ -248,16 +298,24 @@ async function maybeRunAnalysis(date, client) {
|
|
|
248
298
|
console.log(` Output dir: ${analysisDirBase}/${date}`);
|
|
249
299
|
console.log(` Methods: ${enabledMethods.length} enabled`);
|
|
250
300
|
console.log('');
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
301
|
+
// Detect whether `--analysis-dir` already points at a fully-resolved
|
|
302
|
+
// per-run analysis directory (agentic workflows pre-populate
|
|
303
|
+
// `analysis/daily/<date>/<slug>-run<N>` with AI-authored artifacts and
|
|
304
|
+
// pass it verbatim). When so, honour the path as-is; otherwise treat it
|
|
305
|
+
// as a base and compose `<base>/<date>/<slug>` below.
|
|
306
|
+
const analysisDirIsResolved = isResolvedAnalysisDir(analysisDirBase);
|
|
307
|
+
if (analysisDirIsResolved) {
|
|
308
|
+
console.log(` Analysis dir treated as pre-resolved run directory`);
|
|
309
|
+
}
|
|
310
|
+
// Short-circuit for `--analysis-only` wrap-up on a pre-resolved dir:
|
|
311
|
+
// the agent has already completed Stage A (data collection) and Stage B
|
|
312
|
+
// (artifact authoring); runAnalysisStage with outputDirIsResolved=true
|
|
313
|
+
// performs pure filesystem discovery and does not need EP data. Skip
|
|
314
|
+
// the expensive fetchEPFeedData call โ a slow one-month feed pull here
|
|
315
|
+
// can hang the pipeline wrap-up long enough for the safeoutputs MCP
|
|
316
|
+
// session to expire, which then blocks PR creation (see failed run
|
|
317
|
+
// #24802174815 for the cascade).
|
|
318
|
+
const skipDataFetch = analysisOnlyArg && analysisDirIsResolved;
|
|
261
319
|
// Always initialise voting-derived keys (`patterns`, `votingRecords`) to
|
|
262
320
|
// empty arrays so coalition/voting/cross-session analyses never receive
|
|
263
321
|
// undefined. These feeds are not yet exposed by fetchEPFeedData, so they
|
|
@@ -267,37 +325,19 @@ async function maybeRunAnalysis(date, client) {
|
|
|
267
325
|
patterns: [],
|
|
268
326
|
votingRecords: [],
|
|
269
327
|
};
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
fetchedData['documents'] = feedData.documents ?? [];
|
|
274
|
-
fetchedData['adoptedTexts'] = feedData.adoptedTexts ?? [];
|
|
275
|
-
fetchedData['procedures'] = feedData.procedures ?? [];
|
|
276
|
-
fetchedData['mepUpdates'] = feedData.mepUpdates ?? [];
|
|
277
|
-
fetchedData['plenaryDocuments'] = feedData.plenaryDocuments ?? [];
|
|
278
|
-
fetchedData['committeeDocuments'] = feedData.committeeDocuments ?? [];
|
|
279
|
-
fetchedData['plenarySessionDocuments'] = feedData.plenarySessionDocuments ?? [];
|
|
280
|
-
fetchedData['externalDocuments'] = feedData.externalDocuments ?? [];
|
|
281
|
-
fetchedData['questions'] = feedData.questions ?? [];
|
|
282
|
-
fetchedData['declarations'] = feedData.declarations ?? [];
|
|
283
|
-
fetchedData['corporateBodies'] = feedData.corporateBodies ?? [];
|
|
284
|
-
}
|
|
285
|
-
if (!fetchedData['events']) {
|
|
286
|
-
// No MCP or feed-data file available โ populate empty arrays so builders don't fail
|
|
328
|
+
if (skipDataFetch) {
|
|
329
|
+
console.log(` Skipping EP data fetch โ --analysis-only wrap-up on pre-resolved dir (agent owns Stage A/B)`);
|
|
330
|
+
// Populate empty arrays so downstream builders don't trip on undefined.
|
|
287
331
|
fetchedData['events'] = [];
|
|
288
332
|
fetchedData['sessions'] = [];
|
|
289
333
|
fetchedData['documents'] = [];
|
|
290
334
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
// data produces hollow output that should never feed article generation.
|
|
294
|
-
if (!hasSubstantiveData(fetchedData)) {
|
|
295
|
-
const msg = 'โ Analysis aborted: no substantive EP data was fetched. ' +
|
|
296
|
-
'MCP data fetch must succeed before analysis can run. ' +
|
|
297
|
-
'Check MCP connection, feed data file, or EP API availability.';
|
|
298
|
-
throw new Error(msg);
|
|
335
|
+
else {
|
|
336
|
+
await fetchAndValidateEPData(fetchedData, client, articleTypes);
|
|
299
337
|
}
|
|
300
|
-
const validArticleTypes =
|
|
338
|
+
const validArticleTypes = articleTypes
|
|
339
|
+
.map((t) => t.trim())
|
|
340
|
+
.filter((t) => VALID_ARTICLE_CATEGORIES.includes(t));
|
|
301
341
|
// Derive a slug from the article types to scope analysis output per workflow,
|
|
302
342
|
// preventing merge conflicts when multiple workflows run on the same date.
|
|
303
343
|
// When a run ID is provided (e.g. GITHUB_RUN_NUMBER), append it to the slug
|
|
@@ -308,8 +348,8 @@ async function maybeRunAnalysis(date, client) {
|
|
|
308
348
|
console.log(` Article type slug: ${slug}`);
|
|
309
349
|
if (runId)
|
|
310
350
|
console.log(` Run ID: ${runId}`);
|
|
311
|
-
//
|
|
312
|
-
//
|
|
351
|
+
// Require data only when we actually fetched it. The pre-resolved
|
|
352
|
+
// --analysis-only wrap-up path performs discovery-only and needs no data.
|
|
313
353
|
const ctx = await runAnalysisStage(fetchedData, {
|
|
314
354
|
articleTypes: validArticleTypes,
|
|
315
355
|
date,
|
|
@@ -318,7 +358,8 @@ async function maybeRunAnalysis(date, client) {
|
|
|
318
358
|
enabledMethods,
|
|
319
359
|
skipCompleted: true,
|
|
320
360
|
verbose: analysisVerboseArg,
|
|
321
|
-
requireData:
|
|
361
|
+
requireData: !skipDataFetch,
|
|
362
|
+
outputDirIsResolved: analysisDirIsResolved,
|
|
322
363
|
});
|
|
323
364
|
const totalMethods = ctx.manifest.methods.length;
|
|
324
365
|
const completedCount = ctx.manifest.methods.filter((method) => method.status === 'completed').length;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ArticleCategory } from '../../types/index.js';
|
|
2
2
|
import type { ConfidenceLevel } from '../../types/index.js';
|
|
3
|
+
import { type AnalysisManifestHistoryEntry } from '../../utils/file-utils.js';
|
|
3
4
|
/**
|
|
4
5
|
* Union type of all recognised analysis method identifiers.
|
|
5
6
|
*/
|
|
@@ -34,7 +35,44 @@ export interface AnalysisStageOptions {
|
|
|
34
35
|
* Retained for backward compatibility with agentic workflow invocations.
|
|
35
36
|
*/
|
|
36
37
|
readonly requireData?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* When true, treat {@link AnalysisStageOptions.outputDir} as a fully
|
|
40
|
+
* resolved analysis directory and skip the `<outputDir>/<date>/<slug>`
|
|
41
|
+
* composition.
|
|
42
|
+
*
|
|
43
|
+
* This supports agentic workflows that pre-populate a per-run directory
|
|
44
|
+
* (e.g. `analysis/daily/<date>/<slug>-run<N>`) with AI-authored artifacts
|
|
45
|
+
* and then invoke `news-enhanced.ts --analysis-dir=<that dir>` for the
|
|
46
|
+
* discovery + article-generation phase.
|
|
47
|
+
*/
|
|
48
|
+
readonly outputDirIsResolved?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Optional stable run identifier used to record a history entry in the
|
|
51
|
+
* manifest when `outputDirIsResolved` is true. Enables repeated analysis
|
|
52
|
+
* runs against the same `analysis/daily/${DATE}/${TYPE}/` folder to
|
|
53
|
+
* accumulate an audit trail via `manifest.json.history[]` instead of
|
|
54
|
+
* triggering the `-2` suffix. When unset, a UUID-based run id is used.
|
|
55
|
+
*/
|
|
56
|
+
readonly runId?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Optional Stage-C gate result recorded in the manifest history entry
|
|
59
|
+
* written after discovery. Defaults to `'PENDING'` โ the Stage-C
|
|
60
|
+
* validator or the caller updates this later.
|
|
61
|
+
*/
|
|
62
|
+
readonly gateResult?: AnalysisManifestHistoryEntry['gateResult'];
|
|
37
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Detect whether `candidate` looks like a pre-populated, fully-resolved
|
|
66
|
+
* analysis run directory.
|
|
67
|
+
*
|
|
68
|
+
* Returns `true` when the directory exists AND either contains a
|
|
69
|
+
* `manifest.json` from a prior run or at least one of the canonical
|
|
70
|
+
* analysis subdirectories in {@link RESOLVED_ANALYSIS_SUBDIRS}.
|
|
71
|
+
*
|
|
72
|
+
* @param candidate - Directory path to inspect.
|
|
73
|
+
* @returns `true` when the directory is a resolved analysis run dir.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isResolvedAnalysisDir(candidate: string): boolean;
|
|
38
76
|
/** Status record written into the manifest for each method */
|
|
39
77
|
export interface AnalysisMethodStatus {
|
|
40
78
|
readonly method: AnalysisMethod;
|
|
@@ -44,15 +82,60 @@ export interface AnalysisMethodStatus {
|
|
|
44
82
|
readonly duration: number;
|
|
45
83
|
readonly summary: string;
|
|
46
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* `manifest.files.*` structure โ artifact paths grouped by subdirectory.
|
|
87
|
+
*
|
|
88
|
+
* Mirrors the shape consumed by
|
|
89
|
+
* `src/utils/validate-analysis-completeness.ts:extractListedPaths` (nested
|
|
90
|
+
* `{ category: string[] }` variant). Each key is the first path segment of
|
|
91
|
+
* an artifact's relative path (e.g. `intelligence`, `classification`,
|
|
92
|
+
* `risk-scoring`), and the value is the list of relative paths under that
|
|
93
|
+
* subdir.
|
|
94
|
+
*
|
|
95
|
+
* Hyphenated keys (e.g. `risk-scoring`, `threat-assessment`) match the
|
|
96
|
+
* canonical on-disk subdirectory names defined in
|
|
97
|
+
* `scripts/resolve-analysis-dir.sh` and `DISCOVERY_SUBDIRS` /
|
|
98
|
+
* `RESOLVED_ANALYSIS_SUBDIRS`. They must be quoted in TypeScript because
|
|
99
|
+
* `-` is not a valid identifier character.
|
|
100
|
+
*/
|
|
101
|
+
export interface AnalysisManifestFiles {
|
|
102
|
+
readonly classification?: readonly string[];
|
|
103
|
+
readonly 'risk-scoring'?: readonly string[];
|
|
104
|
+
readonly 'threat-assessment'?: readonly string[];
|
|
105
|
+
readonly intelligence?: readonly string[];
|
|
106
|
+
readonly documents?: readonly string[];
|
|
107
|
+
readonly existing?: readonly string[];
|
|
108
|
+
readonly data?: readonly string[];
|
|
109
|
+
readonly runs?: readonly string[];
|
|
110
|
+
readonly [key: string]: readonly string[] | undefined;
|
|
111
|
+
}
|
|
47
112
|
/** Metadata record written to manifest.json for each analysis run */
|
|
48
113
|
export interface AnalysisManifest {
|
|
49
114
|
readonly runId: string;
|
|
50
115
|
readonly date: string;
|
|
116
|
+
/**
|
|
117
|
+
* Top-level article-type slug (e.g. `committee-reports`, `breaking`).
|
|
118
|
+
*
|
|
119
|
+
* Required by the Stage-C completeness gate (see
|
|
120
|
+
* `03-analysis-completeness-gate.md` ยง2 item 8 and
|
|
121
|
+
* `src/utils/validate-analysis-completeness.ts:loadManifest`). Kept in
|
|
122
|
+
* addition to the legacy `articleTypeSlug` field for backward compatibility.
|
|
123
|
+
*/
|
|
124
|
+
readonly articleType?: string | undefined;
|
|
51
125
|
readonly articleTypeSlug?: string | undefined;
|
|
52
126
|
readonly startTime: string;
|
|
53
127
|
readonly endTime: string;
|
|
54
128
|
readonly articleTypes: readonly ArticleCategory[];
|
|
55
129
|
readonly methods: readonly AnalysisMethodStatus[];
|
|
130
|
+
/**
|
|
131
|
+
* Artifact paths grouped by subdirectory (e.g.
|
|
132
|
+
* `{ intelligence: ['intelligence/pestle-analysis.md', ...] }`).
|
|
133
|
+
*
|
|
134
|
+
* Required by the Stage-C completeness gate โ see
|
|
135
|
+
* `src/utils/validate-analysis-completeness.ts:loadManifest` which rejects
|
|
136
|
+
* any manifest without a top-level `files` object.
|
|
137
|
+
*/
|
|
138
|
+
readonly files?: AnalysisManifestFiles;
|
|
56
139
|
readonly overallConfidence: ConfidenceLevel;
|
|
57
140
|
readonly dataSourcesUsed: readonly string[];
|
|
58
141
|
readonly documentsAnalyzed?: number;
|
|
@@ -92,6 +175,12 @@ export declare function deriveArticleTypeSlug(articleTypes: readonly (ArticleCat
|
|
|
92
175
|
* (if one doesn't already exist) so downstream consumers that check for
|
|
93
176
|
* the manifest continue to work.
|
|
94
177
|
*
|
|
178
|
+
* When `options.outputDirIsResolved` is true, `outputDir` is honoured
|
|
179
|
+
* verbatim and the uniqueness-suffix step is bypassed โ agentic workflows
|
|
180
|
+
* pre-populate `analysis/daily/<date>/<slug>-run<N>/` with `manifest.json`
|
|
181
|
+
* plus artifacts during Stage B, and discovery must consume that exact
|
|
182
|
+
* path rather than being redirected to a `-2` suffix.
|
|
183
|
+
*
|
|
95
184
|
* @param fetchedData - Raw EP data (used only for the requireData check)
|
|
96
185
|
* @param options - Analysis stage configuration
|
|
97
186
|
* @returns Analysis context with discovered methods
|