euparliamentmonitor 0.8.43 → 0.8.44
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 +1 -1
- package/scripts/aggregator/analysis-aggregator.d.ts +9 -0
- package/scripts/aggregator/analysis-aggregator.js +23 -3
- package/scripts/aggregator/article-generator.d.ts +6 -0
- package/scripts/aggregator/article-generator.js +23 -4
- package/scripts/aggregator/article-html.d.ts +5 -0
- package/scripts/aggregator/article-html.js +5 -0
- package/scripts/aggregator/clean-artifact.d.ts +24 -0
- package/scripts/aggregator/clean-artifact.js +60 -0
- package/scripts/mcp/imf-mcp-client.d.ts +20 -10
- package/scripts/mcp/imf-mcp-client.js +9 -3
- package/scripts/types/imf.d.ts +23 -13
package/package.json
CHANGED
|
@@ -165,4 +165,13 @@ export declare function renderAnalysisIndex(included: readonly IncludedArtifact[
|
|
|
165
165
|
* @returns {@link AggregatedRun} describing the rendered document
|
|
166
166
|
*/
|
|
167
167
|
export declare function aggregateAnalysisRun(options: AggregateOptions): AggregatedRun;
|
|
168
|
+
/**
|
|
169
|
+
* Extract a `YYYY-MM-DD` date from a path like
|
|
170
|
+
* `analysis/daily/2026-01-15/run`. Falls back to the epoch date when no
|
|
171
|
+
* ISO date is embedded in the path.
|
|
172
|
+
*
|
|
173
|
+
* @param runDirRelPath - Repo-relative path of the run directory
|
|
174
|
+
* @returns ISO date string in `YYYY-MM-DD` form
|
|
175
|
+
*/
|
|
176
|
+
export declare function guessDateFromRunDir(runDirRelPath: string): string;
|
|
168
177
|
//# sourceMappingURL=analysis-aggregator.d.ts.map
|
|
@@ -119,6 +119,24 @@ export function discoverTradecraftFiles(repoRoot) {
|
|
|
119
119
|
}
|
|
120
120
|
return result.sort();
|
|
121
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Return `true` when a `.md` filename should be excluded from the run
|
|
124
|
+
* artifact set. Keeps the walk closure under the cognitive-complexity limit.
|
|
125
|
+
*
|
|
126
|
+
* Excluded names:
|
|
127
|
+
* - `article.md` and translated variants (`article.sv.md`, etc.) — these are
|
|
128
|
+
* outputs of the aggregator, not inputs.
|
|
129
|
+
* - `README.md` (case-insensitive) — required for the analysis gate but not
|
|
130
|
+
* relevant to the published article.
|
|
131
|
+
*
|
|
132
|
+
* @param name - Bare filename (no directory prefix)
|
|
133
|
+
* @returns `true` when the file should be skipped
|
|
134
|
+
*/
|
|
135
|
+
function isExcludedArtifact(name) {
|
|
136
|
+
if (name.toLowerCase() === 'readme.md')
|
|
137
|
+
return true;
|
|
138
|
+
return name.startsWith('article.') && name.endsWith('.md');
|
|
139
|
+
}
|
|
122
140
|
/**
|
|
123
141
|
* Walk the run directory and return every `.md` file as a run-relative
|
|
124
142
|
* POSIX path, excluding files under `data/` (raw MCP payloads, not meant
|
|
@@ -137,11 +155,13 @@ function collectRunArtifacts(runDir) {
|
|
|
137
155
|
const full = path.join(dir, entry.name);
|
|
138
156
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
139
157
|
if (entry.isDirectory()) {
|
|
140
|
-
|
|
158
|
+
// Skip raw payloads, legacy run snapshots, and Pass-1 work-in-progress
|
|
159
|
+
// snapshots so they are not rendered as supplementary artifacts.
|
|
160
|
+
if (entry.name === 'data' || entry.name === 'runs' || entry.name === 'pass1')
|
|
141
161
|
continue;
|
|
142
162
|
walk(full, rel);
|
|
143
163
|
}
|
|
144
|
-
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
164
|
+
else if (entry.isFile() && entry.name.endsWith('.md') && !isExcludedArtifact(entry.name)) {
|
|
145
165
|
result.push(rel);
|
|
146
166
|
}
|
|
147
167
|
}
|
|
@@ -471,7 +491,7 @@ export function aggregateAnalysisRun(options) {
|
|
|
471
491
|
* @param runDirRelPath - Repo-relative path of the run directory
|
|
472
492
|
* @returns ISO date string in `YYYY-MM-DD` form
|
|
473
493
|
*/
|
|
474
|
-
function guessDateFromRunDir(runDirRelPath) {
|
|
494
|
+
export function guessDateFromRunDir(runDirRelPath) {
|
|
475
495
|
const match = /(\d{4}-\d{2}-\d{2})/.exec(runDirRelPath);
|
|
476
496
|
return match ? (match[1] ?? '1970-01-01') : '1970-01-01';
|
|
477
497
|
}
|
|
@@ -38,6 +38,12 @@ export interface CliOptions {
|
|
|
38
38
|
export interface GenerateResult {
|
|
39
39
|
/** Repo-relative path of the English source Markdown that was written. */
|
|
40
40
|
readonly sourceMarkdownRelPath: string;
|
|
41
|
+
/**
|
|
42
|
+
* Repo-relative path of the `article.md` written directly into the
|
|
43
|
+
* analysis run directory — canonical Markdown source that lives alongside
|
|
44
|
+
* the artifacts that produced it (riksdagsmonitor pattern).
|
|
45
|
+
*/
|
|
46
|
+
readonly runArticleMdRelPath: string;
|
|
41
47
|
/** Filenames written under `outDir`, relative to `outDir`. */
|
|
42
48
|
readonly writtenFiles: readonly string[];
|
|
43
49
|
/** Metadata from {@link aggregateAnalysisRun}. */
|
|
@@ -310,6 +310,7 @@ function writeLanguageVariant(lang, slug, aggregated, englishHtml, chromeOptions
|
|
|
310
310
|
sourceMarkdownRelPath: chromeOptions.sourceMarkdownRelPath,
|
|
311
311
|
toc: aggregated.sectionToc,
|
|
312
312
|
articleCount: chromeOptions.articleCount,
|
|
313
|
+
isBasedOn: aggregated.includedArtifacts.map((a) => `https://github.com/Hack23/euparliamentmonitor/blob/main/${a.repoRelPath}`),
|
|
313
314
|
});
|
|
314
315
|
const filename = getArticleFilename(slug, lang);
|
|
315
316
|
fs.writeFileSync(path.join(opts.outDir, filename), html, 'utf8');
|
|
@@ -396,18 +397,31 @@ export function generateArticle(opts, runSuffix, articleCountOverride) {
|
|
|
396
397
|
const effectiveMetadata = opts.title || opts.description
|
|
397
398
|
? applyCliOverrides(resolvedMetadata, opts.title, opts.description)
|
|
398
399
|
: resolvedMetadata;
|
|
399
|
-
// Write
|
|
400
|
+
// Write article.md INTO the analysis run directory — canonical Markdown
|
|
401
|
+
// source that lives alongside the artifacts that produced it.
|
|
402
|
+
// This mirrors the riksdagsmonitor pattern where `article.md` is committed
|
|
403
|
+
// inside `analysis/daily/<date>/<type>/` so every run has a browsable,
|
|
404
|
+
// version-controlled Markdown source in its own directory.
|
|
405
|
+
const runArticleMdAbs = path.join(opts.runDir, 'article.md');
|
|
406
|
+
fs.writeFileSync(runArticleMdAbs, aggregated.markdown, 'utf8');
|
|
407
|
+
const runArticleMdRelPath = path
|
|
408
|
+
.relative(opts.repoRoot, runArticleMdAbs)
|
|
409
|
+
.split(path.sep)
|
|
410
|
+
.join('/');
|
|
411
|
+
// Also write source Markdown under <outDir>/<slug>.en.md for search
|
|
412
|
+
// indexing and backwards compatibility with existing news-index scripts.
|
|
400
413
|
ensureDir(opts.outDir);
|
|
401
414
|
const sourceMdFilename = `${slug}.en.md`;
|
|
402
415
|
const sourceMdAbs = path.join(opts.outDir, sourceMdFilename);
|
|
403
416
|
fs.writeFileSync(sourceMdAbs, aggregated.markdown, 'utf8');
|
|
404
|
-
const sourceMdRelPath = path.relative(opts.repoRoot, sourceMdAbs).split(path.sep).join('/');
|
|
405
417
|
const written = [sourceMdFilename];
|
|
406
418
|
if (!opts.markdownOnly) {
|
|
407
419
|
const rendered = renderMarkdown(aggregated.markdown);
|
|
408
420
|
const chromeOptions = {
|
|
409
421
|
metadata: effectiveMetadata,
|
|
410
|
-
|
|
422
|
+
// Point the "View source Markdown" link at the canonical run-directory
|
|
423
|
+
// article.md so readers can trace the HTML back to the analysis tree.
|
|
424
|
+
sourceMarkdownRelPath: runArticleMdRelPath,
|
|
411
425
|
articleCount: articleCountOverride ?? countPublishedArticles(opts.repoRoot),
|
|
412
426
|
};
|
|
413
427
|
for (const lang of opts.langs) {
|
|
@@ -415,7 +429,12 @@ export function generateArticle(opts, runSuffix, articleCountOverride) {
|
|
|
415
429
|
written.push(filename);
|
|
416
430
|
}
|
|
417
431
|
}
|
|
418
|
-
return {
|
|
432
|
+
return {
|
|
433
|
+
sourceMarkdownRelPath: runArticleMdRelPath,
|
|
434
|
+
runArticleMdRelPath,
|
|
435
|
+
writtenFiles: written,
|
|
436
|
+
aggregated,
|
|
437
|
+
};
|
|
419
438
|
}
|
|
420
439
|
/**
|
|
421
440
|
* Walk `analysis/daily/` recursively and return every subdirectory that
|
|
@@ -44,6 +44,11 @@ export interface WrapArticleOptions {
|
|
|
44
44
|
* the line is omitted.
|
|
45
45
|
*/
|
|
46
46
|
readonly articleCount?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Optional: URLs of source artifacts included in the aggregated article.
|
|
49
|
+
* Emitted as `isBasedOn` in the JSON-LD `NewsArticle` schema for provenance.
|
|
50
|
+
*/
|
|
51
|
+
readonly isBasedOn?: readonly string[];
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
54
|
* Build the canonical filename for an article in a given language. English
|
|
@@ -134,6 +134,11 @@ export function wrapArticleHtml(options) {
|
|
|
134
134
|
name: 'EU Parliament Monitor',
|
|
135
135
|
url: BASE_URL,
|
|
136
136
|
},
|
|
137
|
+
...(options.isBasedOn && options.isBasedOn.length > 0
|
|
138
|
+
? {
|
|
139
|
+
isBasedOn: options.isBasedOn.map((url) => ({ '@type': 'CreativeWork', url })),
|
|
140
|
+
}
|
|
141
|
+
: {}),
|
|
137
142
|
};
|
|
138
143
|
const jsonLdString = JSON.stringify(jsonLd).replace(/</g, '\\u003c');
|
|
139
144
|
const pageTitle = `${options.title} — ${siteTitle}`;
|
|
@@ -35,6 +35,8 @@ export interface CleanArtifactResult {
|
|
|
35
35
|
readonly strippedH1s: number;
|
|
36
36
|
/** Banner/metadata lines removed. */
|
|
37
37
|
readonly strippedBannerLines: number;
|
|
38
|
+
/** Operational metadata preamble lines removed (e.g. **Run:** / **Window:** blocks). */
|
|
39
|
+
readonly strippedMetaLines: number;
|
|
38
40
|
/** Mermaid blocks deduplicated as a reference to a previous occurrence. */
|
|
39
41
|
readonly dedupedMermaidBlocks: number;
|
|
40
42
|
}
|
|
@@ -126,6 +128,28 @@ export declare function dedupMermaid(md: string, seen: Set<string>): {
|
|
|
126
128
|
md: string;
|
|
127
129
|
deduped: number;
|
|
128
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Strip the operational metadata preamble that agent pipelines prepend to
|
|
133
|
+
* artifacts. These are lines of the form `**Run:** …`, `**Window:** …`,
|
|
134
|
+
* `**Methodology:** …`, etc., followed optionally by a standalone `---`
|
|
135
|
+
* horizontal rule. They are agent-operational metadata that should not appear
|
|
136
|
+
* in the published article.
|
|
137
|
+
*
|
|
138
|
+
* Algorithm:
|
|
139
|
+
* 1. Skip leading blank lines (they don't count as metadata).
|
|
140
|
+
* 2. If the first non-blank line does NOT match the metadata pattern, return
|
|
141
|
+
* the document unchanged (`lines: 0`).
|
|
142
|
+
* 3. Otherwise consume all metadata lines and interspersed blank lines.
|
|
143
|
+
* 4. If the next non-blank line is a standalone `---`, consume that too.
|
|
144
|
+
* 5. Return the stripped Markdown and the count of lines removed.
|
|
145
|
+
*
|
|
146
|
+
* @param md - Markdown source (after banner/heading passes)
|
|
147
|
+
* @returns `{ md, lines }` — stripped Markdown and number of lines removed
|
|
148
|
+
*/
|
|
149
|
+
export declare function stripArtifactMetadataPreamble(md: string): {
|
|
150
|
+
md: string;
|
|
151
|
+
lines: number;
|
|
152
|
+
};
|
|
129
153
|
/**
|
|
130
154
|
* Apply all cleanup passes and return the normalised Markdown plus
|
|
131
155
|
* simple counters for telemetry/tests.
|
|
@@ -578,6 +578,63 @@ function hashString(input) {
|
|
|
578
578
|
}
|
|
579
579
|
return (h >>> 0).toString(16).padStart(8, '0');
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Pattern matching an operational metadata line at the start of an artifact.
|
|
583
|
+
* Examples: `**Run:** breaking-run-123`, `**Window:** 2026-04-24 00:00Z — 05:49Z`.
|
|
584
|
+
* The pattern requires the line to start with `**<Word>**` followed by a colon
|
|
585
|
+
* or whitespace so ordinary bold prose is not mistakenly treated as metadata.
|
|
586
|
+
*/
|
|
587
|
+
const METADATA_LINE_PATTERN = /^\*\*[A-Za-z][^*\n]*\*\*[:\s]/;
|
|
588
|
+
/**
|
|
589
|
+
* Strip the operational metadata preamble that agent pipelines prepend to
|
|
590
|
+
* artifacts. These are lines of the form `**Run:** …`, `**Window:** …`,
|
|
591
|
+
* `**Methodology:** …`, etc., followed optionally by a standalone `---`
|
|
592
|
+
* horizontal rule. They are agent-operational metadata that should not appear
|
|
593
|
+
* in the published article.
|
|
594
|
+
*
|
|
595
|
+
* Algorithm:
|
|
596
|
+
* 1. Skip leading blank lines (they don't count as metadata).
|
|
597
|
+
* 2. If the first non-blank line does NOT match the metadata pattern, return
|
|
598
|
+
* the document unchanged (`lines: 0`).
|
|
599
|
+
* 3. Otherwise consume all metadata lines and interspersed blank lines.
|
|
600
|
+
* 4. If the next non-blank line is a standalone `---`, consume that too.
|
|
601
|
+
* 5. Return the stripped Markdown and the count of lines removed.
|
|
602
|
+
*
|
|
603
|
+
* @param md - Markdown source (after banner/heading passes)
|
|
604
|
+
* @returns `{ md, lines }` — stripped Markdown and number of lines removed
|
|
605
|
+
*/
|
|
606
|
+
export function stripArtifactMetadataPreamble(md) {
|
|
607
|
+
const lines = md.split('\n');
|
|
608
|
+
let i = 0;
|
|
609
|
+
// Skip purely blank lines at the very head
|
|
610
|
+
while (i < lines.length && (lines[i] ?? '').trim() === '')
|
|
611
|
+
i++;
|
|
612
|
+
// If the first real line is not a metadata line, return unchanged
|
|
613
|
+
if (i >= lines.length || !METADATA_LINE_PATTERN.test(lines[i] ?? '')) {
|
|
614
|
+
return { md, lines: 0 };
|
|
615
|
+
}
|
|
616
|
+
// Consume the metadata block (metadata lines + interspersed blank lines)
|
|
617
|
+
let metaEnd = i;
|
|
618
|
+
while (metaEnd < lines.length) {
|
|
619
|
+
const line = lines[metaEnd] ?? '';
|
|
620
|
+
if (METADATA_LINE_PATTERN.test(line) || line.trim() === '') {
|
|
621
|
+
metaEnd++;
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// If the next non-blank line is a standalone HR, absorb it
|
|
628
|
+
let scanAhead = metaEnd;
|
|
629
|
+
while (scanAhead < lines.length && (lines[scanAhead] ?? '').trim() === '')
|
|
630
|
+
scanAhead++;
|
|
631
|
+
if (scanAhead < lines.length && /^\s*---\s*$/.test(lines[scanAhead] ?? '')) {
|
|
632
|
+
metaEnd = scanAhead + 1;
|
|
633
|
+
}
|
|
634
|
+
const removed = metaEnd;
|
|
635
|
+
const stripped = lines.slice(removed).join('\n').replace(/^\n+/, '');
|
|
636
|
+
return { md: stripped, lines: removed };
|
|
637
|
+
}
|
|
581
638
|
/**
|
|
582
639
|
* Apply all cleanup passes and return the normalised Markdown plus
|
|
583
640
|
* simple counters for telemetry/tests.
|
|
@@ -594,6 +651,8 @@ export function cleanArtifact(source, options) {
|
|
|
594
651
|
md = mdAfterBanners;
|
|
595
652
|
const { md: mdAfterHeadings, h1Count } = demoteHeadings(md);
|
|
596
653
|
md = mdAfterHeadings;
|
|
654
|
+
const { md: mdAfterMeta, lines: strippedMetaLines } = stripArtifactMetadataPreamble(md);
|
|
655
|
+
md = mdAfterMeta;
|
|
597
656
|
md = rewriteLinks(md, options.artifactRelPath);
|
|
598
657
|
const { md: mdAfterMermaid, deduped } = dedupMermaid(md, seen);
|
|
599
658
|
md = mdAfterMermaid;
|
|
@@ -603,6 +662,7 @@ export function cleanArtifact(source, options) {
|
|
|
603
662
|
markdown: md,
|
|
604
663
|
strippedH1s: h1Count,
|
|
605
664
|
strippedBannerLines,
|
|
665
|
+
strippedMetaLines,
|
|
606
666
|
dedupedMermaidBlocks: deduped,
|
|
607
667
|
};
|
|
608
668
|
}
|
|
@@ -9,21 +9,25 @@
|
|
|
9
9
|
* because the upstream project is a Python git-URL package (not npm) and
|
|
10
10
|
* could not be pinned to an integrity hash per the ISMS Secure Development
|
|
11
11
|
* Policy §7. This module replaces the Python transport with a direct,
|
|
12
|
-
* typed HTTP client
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* typed HTTP client. The public API (`IMFMCPClient`, five tool methods,
|
|
13
|
+
* `MCPToolResult`-shaped envelope) is stable across the migration. The
|
|
14
|
+
* earlier companion module `src/utils/imf-data.ts` (SDMX-JSON parser,
|
|
15
|
+
* indicator/country maps, HTML builders) was purged in the April-2026
|
|
16
|
+
* aggregator-pipeline migration — callers now consume the raw SDMX-JSON
|
|
17
|
+
* envelope returned by {@link IMFMCPClient.fetchData} directly.
|
|
15
18
|
*
|
|
16
19
|
* ## Public API (unchanged from the MCP-backed iteration)
|
|
17
20
|
*
|
|
18
21
|
* - {@link IMFMCPClient} — class with semantic wrappers for five "tools".
|
|
19
22
|
* - {@link IMF_MCP_TOOLS} — stable virtual tool-name list used by the
|
|
20
|
-
*
|
|
23
|
+
* Stage-C editorial fingerprint and the workflow probe. Drift-guarded
|
|
24
|
+
* by `test/integration/mcp/imf-mcp.test.js`.
|
|
21
25
|
* - {@link getIMFMCPClient} / {@link closeIMFMCPClient} — singleton lifecycle.
|
|
22
26
|
*
|
|
23
27
|
* The return envelope of every method is {@link MCPToolResult}
|
|
24
|
-
* (`{ content: [{ type: "text", text: "<json>" }] }`)
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* (`{ content: [{ type: "text", text: "<json>" }] }`). The `text` payload
|
|
29
|
+
* is the raw SDMX-JSON document returned by the IMF REST endpoint;
|
|
30
|
+
* downstream code parses it with any standard SDMX-JSON reader.
|
|
27
31
|
*
|
|
28
32
|
* ## Transport
|
|
29
33
|
*
|
|
@@ -50,7 +54,11 @@ import type { MCPToolResult, MCPClientOptions } from '../types/index.js';
|
|
|
50
54
|
* longer talks to an MCP server, but the tool-name list is preserved so
|
|
51
55
|
* it continues to serve as:
|
|
52
56
|
*
|
|
53
|
-
* 1. The
|
|
57
|
+
* 1. The Stage-C editorial fingerprint source for "IMF is cited" (see
|
|
58
|
+
* `analysis/imf/indicator-catalog.md §6` — the earlier runtime
|
|
59
|
+
* fingerprint table `IMF_STRONG_FINGERPRINTS` in
|
|
60
|
+
* `src/utils/content-validator.ts` was purged in the April-2026
|
|
61
|
+
* aggregator-pipeline migration).
|
|
54
62
|
* 2. The workflow probe's heartbeat identifiers.
|
|
55
63
|
* 3. A drift guard against method additions: if a new helper method lands
|
|
56
64
|
* here, `test/integration/mcp/imf-mcp.test.js` fails unless the list
|
|
@@ -169,8 +177,10 @@ export declare class IMFMCPClient {
|
|
|
169
177
|
* Fetch a time-series slice from an IMF dataflow as SDMX-JSON.
|
|
170
178
|
*
|
|
171
179
|
* Virtual tool: `imf-fetch-data`. The response is already in SDMX-JSON
|
|
172
|
-
* format
|
|
173
|
-
*
|
|
180
|
+
* format; callers read the series under `data.dataSets[0].series`
|
|
181
|
+
* using any standard SDMX-JSON reader. (The earlier helper
|
|
182
|
+
* `parseSDMXJSON` in `src/utils/imf-data.ts` was purged in the
|
|
183
|
+
* April-2026 aggregator-pipeline migration.)
|
|
174
184
|
*
|
|
175
185
|
* @param options - Fetch parameters.
|
|
176
186
|
* @param options.databaseId - IMF dataflow ID (`"WEO"`, `"IFS"`, ...).
|
|
@@ -14,7 +14,11 @@ const IMF_FALLBACK = {
|
|
|
14
14
|
* longer talks to an MCP server, but the tool-name list is preserved so
|
|
15
15
|
* it continues to serve as:
|
|
16
16
|
*
|
|
17
|
-
* 1. The
|
|
17
|
+
* 1. The Stage-C editorial fingerprint source for "IMF is cited" (see
|
|
18
|
+
* `analysis/imf/indicator-catalog.md §6` — the earlier runtime
|
|
19
|
+
* fingerprint table `IMF_STRONG_FINGERPRINTS` in
|
|
20
|
+
* `src/utils/content-validator.ts` was purged in the April-2026
|
|
21
|
+
* aggregator-pipeline migration).
|
|
18
22
|
* 2. The workflow probe's heartbeat identifiers.
|
|
19
23
|
* 3. A drift guard against method additions: if a new helper method lands
|
|
20
24
|
* here, `test/integration/mcp/imf-mcp.test.js` fails unless the list
|
|
@@ -375,8 +379,10 @@ export class IMFMCPClient {
|
|
|
375
379
|
* Fetch a time-series slice from an IMF dataflow as SDMX-JSON.
|
|
376
380
|
*
|
|
377
381
|
* Virtual tool: `imf-fetch-data`. The response is already in SDMX-JSON
|
|
378
|
-
* format
|
|
379
|
-
*
|
|
382
|
+
* format; callers read the series under `data.dataSets[0].series`
|
|
383
|
+
* using any standard SDMX-JSON reader. (The earlier helper
|
|
384
|
+
* `parseSDMXJSON` in `src/utils/imf-data.ts` was purged in the
|
|
385
|
+
* April-2026 aggregator-pipeline migration.)
|
|
380
386
|
*
|
|
381
387
|
* @param options - Fetch parameters.
|
|
382
388
|
* @param options.databaseId - IMF dataflow ID (`"WEO"`, `"IFS"`, ...).
|
package/scripts/types/imf.d.ts
CHANGED
|
@@ -22,12 +22,15 @@
|
|
|
22
22
|
* `c-cf/imf-data-mcp` MCP server. That transport was replaced with a
|
|
23
23
|
* native TypeScript HTTP client so the stack remains npm-pure and
|
|
24
24
|
* pinned per ISMS §7. The `IMF_MCP_TOOLS` identifier list is retained
|
|
25
|
-
* as a stable "virtual tool" surface for the
|
|
26
|
-
* fingerprint and
|
|
25
|
+
* as a stable "virtual tool" surface for the Stage-C editorial
|
|
26
|
+
* fingerprint (see `analysis/imf/indicator-catalog.md §6`) and the
|
|
27
|
+
* workflow probe. The earlier companion module `src/utils/imf-data.ts`
|
|
28
|
+
* (parsers, indicator/country maps, HTML builders) was purged in the
|
|
29
|
+
* April-2026 aggregator-pipeline migration.
|
|
27
30
|
*
|
|
28
31
|
* @see {@link https://dataservices.imf.org/REST/SDMX_3.0 | IMF SDMX 3.0 REST API}
|
|
29
|
-
* @see
|
|
30
|
-
* IMF indicator mapping enforced
|
|
32
|
+
* @see {@link https://github.com/Hack23/euparliamentmonitor/blob/main/analysis/methodologies/imf-indicator-mapping.md | IMF Indicator Mapping methodology} for the committee →
|
|
33
|
+
* IMF indicator mapping enforced at Stage-C editorial review.
|
|
31
34
|
*/
|
|
32
35
|
import type { MCPClientOptions } from './mcp.js';
|
|
33
36
|
/**
|
|
@@ -144,11 +147,17 @@ export interface IMFForecastPoint {
|
|
|
144
147
|
/**
|
|
145
148
|
* Curated set of IMF indicator keys used across the EU Parliament Monitor.
|
|
146
149
|
*
|
|
147
|
-
* These map onto specific IMF database + SDMX dimension codes
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
150
|
+
* These map onto specific IMF database + SDMX dimension codes. The key
|
|
151
|
+
* names are chosen to parallel the World Bank `PolicyRelevantIndicators`
|
|
152
|
+
* keys where an equivalent series exists, so article generators and
|
|
153
|
+
* templates can migrate incrementally.
|
|
154
|
+
*
|
|
155
|
+
* The earlier runtime constant `IMF_POLICY_INDICATORS` in
|
|
156
|
+
* `src/utils/imf-data.ts` was purged in the April-2026
|
|
157
|
+
* aggregator-pipeline migration.
|
|
158
|
+
*
|
|
159
|
+
* @see {@link https://github.com/Hack23/euparliamentmonitor/blob/main/analysis/imf/indicator-catalog.md#2-policy-domain--imf-indicator-mapping | IMF indicator catalog §2}
|
|
160
|
+
* @see {@link https://github.com/Hack23/euparliamentmonitor/blob/main/analysis/methodologies/imf-indicator-mapping.md | IMF per-committee indicator mapping}
|
|
152
161
|
*/
|
|
153
162
|
export type IMFMacroIndicatorKey = 'gdp' | 'gdpGrowth' | 'gdpPerCapita' | 'inflation' | 'unemployment' | 'population' | 'currentAccount' | 'exportsGdp' | 'govDebt' | 'primaryBalance' | 'structuralBalance' | 'fdiInflow' | 'realEffectiveExchangeRate' | 'policyRate';
|
|
154
163
|
/**
|
|
@@ -212,10 +221,11 @@ export interface IMFEconomicContext {
|
|
|
212
221
|
/**
|
|
213
222
|
* Canonical IMF "virtual tool" names used by the native TypeScript
|
|
214
223
|
* client. These identifiers are preserved from the earlier MCP-backed
|
|
215
|
-
* iteration so the
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
224
|
+
* iteration so the Stage-C editorial fingerprint list (see
|
|
225
|
+
* `analysis/imf/indicator-catalog.md §6`) and the workflow probe
|
|
226
|
+
* (`scripts/imf-mcp-probe.sh`) remain stable across the transport
|
|
227
|
+
* swap. Each name maps to a semantic method on {@link IMFMCPClient}
|
|
228
|
+
* rather than to a remote MCP tool call.
|
|
219
229
|
*/
|
|
220
230
|
export type IMFMCPToolName = 'imf-list-databases' | 'imf-search-databases' | 'imf-get-parameter-defs' | 'imf-get-parameter-codes' | 'imf-fetch-data';
|
|
221
231
|
//# sourceMappingURL=imf.d.ts.map
|